public void RetargetSource(ref IRLinearizedLocation selfReference, IRLinearizedLocation oldSrc, IRLinearizedLocation newSrc) { if (selfReference == oldSrc) { selfReference = newSrc; return; } switch (this.Type) { case IRLinearizedLocationType.Null: case IRLinearizedLocationType.Local: case IRLinearizedLocationType.LocalAddress: case IRLinearizedLocationType.Parameter: case IRLinearizedLocationType.ParameterAddress: case IRLinearizedLocationType.ConstantI4: case IRLinearizedLocationType.ConstantI8: case IRLinearizedLocationType.ConstantR4: case IRLinearizedLocationType.ConstantR8: case IRLinearizedLocationType.SizeOf: case IRLinearizedLocationType.StaticField: case IRLinearizedLocationType.StaticFieldAddress: case IRLinearizedLocationType.RuntimeHandle: case IRLinearizedLocationType.String: break; case IRLinearizedLocationType.Field: Field.FieldLocation.RetargetSource(ref Field.FieldLocation, oldSrc, newSrc); break; case IRLinearizedLocationType.FieldAddress: FieldAddress.FieldLocation.RetargetSource(ref FieldAddress.FieldLocation, oldSrc, newSrc); break; case IRLinearizedLocationType.Indirect: Indirect.AddressLocation.RetargetSource(ref Indirect.AddressLocation, oldSrc, newSrc); break; case IRLinearizedLocationType.ArrayElement: ArrayElement.ArrayLocation.RetargetSource(ref ArrayElement.ArrayLocation, oldSrc, newSrc); ArrayElement.IndexLocation.RetargetSource(ref ArrayElement.IndexLocation, oldSrc, newSrc); break; case IRLinearizedLocationType.ArrayElementAddress: ArrayElementAddress.ArrayLocation.RetargetSource(ref ArrayElementAddress.ArrayLocation, oldSrc, newSrc); ArrayElementAddress.IndexLocation.RetargetSource(ref ArrayElementAddress.IndexLocation, oldSrc, newSrc); break; case IRLinearizedLocationType.ArrayLength: ArrayLength.ArrayLocation.RetargetSource(ref ArrayLength.ArrayLocation, oldSrc, newSrc); break; case IRLinearizedLocationType.FunctionAddress: if (FunctionAddress.Virtual) FunctionAddress.InstanceLocation.RetargetSource(ref FunctionAddress.InstanceLocation, oldSrc, newSrc); break; case IRLinearizedLocationType.Phi: for (int i = 0; i < Phi.SourceLocations.Count; i++) { var l = Phi.SourceLocations[i]; l.RetargetSource(ref l, oldSrc, newSrc); Phi.SourceLocations[i] = l; } break; default: throw new Exception("Unknown IRLinearizedLocationType!"); } }
public void EnterSSA() { IRControlFlowGraph cfg = IRControlFlowGraph.Build(this); if (cfg == null) return; int originalCount = Locals.Count; bool[] originalAssignments = new bool[originalCount]; int[] originalIterations = new int[originalCount]; IRLocal tempLocal = null; Locals.ForEach(l => l.SSAData = new IRLocal.IRLocalSSAData(l)); // Add new local iterations for each assignment to an original local, and keep // track of final iterations for each node, assigning true to indicate it was // assigned, false means propagated (used later) foreach (IRControlFlowGraphNode node in cfg.Nodes) { node.SSAFinalIterations = new Tuple<IRLocal, bool>[originalCount]; node.SSAPhis = new IRLocal[originalCount]; foreach (IRInstruction instruction in node.Instructions) { if (instruction.Destination == null || instruction.Destination.Type != IRLinearizedLocationType.Local) continue; tempLocal = Locals[instruction.Destination.Local.LocalIndex]; if (!originalAssignments[tempLocal.Index]) { originalAssignments[tempLocal.Index] = true; node.SSAFinalIterations[tempLocal.Index] = new Tuple<IRLocal, bool>(tempLocal, true); continue; } tempLocal = tempLocal.Clone(this); Locals.Add(tempLocal); tempLocal.SSAData.Iteration = ++originalIterations[tempLocal.SSAData.Original.Index]; instruction.Destination.Local.LocalIndex = tempLocal.Index; node.SSAFinalIterations[tempLocal.SSAData.Original.Index] = new Tuple<IRLocal, bool>(tempLocal, true); } } // Any SSAFinalIterations missing from the entry node means the entry node // did not assign to the original local, so they can be filled in with // propagated original locals by, assigning false to indicate propagated for (int index = 0; index < originalCount; ++index) { if (cfg.Nodes[0].SSAFinalIterations[index] == null) cfg.Nodes[0].SSAFinalIterations[index] = new Tuple<IRLocal, bool>(Locals[index], false); } // Any SSAFinalIterations missing from any node means the node did not // assign to the original local, so they can be filled in with propagated // locals using the dominance tree, assigning false to indicate propagated foreach (IRControlFlowGraphNode node in cfg.Nodes) { for (int index = 0; index < originalCount; ++index) { if (node.SSAFinalIterations[index] == null) { IRControlFlowGraphNode treeNode = node.Dominator; while (treeNode.SSAFinalIterations[index] == null) treeNode = treeNode.Dominator; node.SSAFinalIterations[index] = new Tuple<IRLocal, bool>(treeNode.SSAFinalIterations[index].Item1, false); } } } // Now that all final iterations are known, we also know if the final // iteration for a node was assigned or propagated // So now we can create a phi, in the dominance frontiers of nodes which // have assignments to original locals // If the phi is the only assignment in a dominance frontier node, then // the phi destination becomes the final iteration for that node int localsBeforePhis = Locals.Count; BitArray phiInserted = new BitArray(cfg.Nodes.Count, false); BitArray localAssigned = new BitArray(cfg.Nodes.Count, false); HashSet<IRControlFlowGraphNode> unprocessedNodes = new HashSet<IRControlFlowGraphNode>(); HashSet<IRControlFlowGraphNode>.Enumerator unprocessedNodesEnumerator; IRControlFlowGraphNode processingNode = null; for (int originalIndex = 0; originalIndex < originalCount; ++originalIndex) { phiInserted.SetAll(false); localAssigned.SetAll(false); foreach (IRControlFlowGraphNode node in cfg.Nodes) { if (node.SSAFinalIterations[originalIndex].Item2) { localAssigned.Set(node.Index, true); unprocessedNodes.Add(node); } } while (unprocessedNodes.Count > 0) { unprocessedNodesEnumerator = unprocessedNodes.GetEnumerator(); unprocessedNodesEnumerator.MoveNext(); processingNode = unprocessedNodesEnumerator.Current; unprocessedNodes.Remove(processingNode); foreach (IRControlFlowGraphNode frontierNode in processingNode.Frontiers) { if (!phiInserted[frontierNode.Index]) { tempLocal = Locals[originalIndex].Clone(this); Locals.Add(tempLocal); tempLocal.SSAData.Iteration = ++originalIterations[originalIndex]; tempLocal.SSAData.Phi = true; frontierNode.SSAPhis[originalIndex] = tempLocal; if (!frontierNode.SSAFinalIterations[originalIndex].Item2) frontierNode.SSAFinalIterations[originalIndex] = new Tuple<IRLocal, bool>(tempLocal, true); phiInserted.Set(frontierNode.Index, true); if (!localAssigned[frontierNode.Index]) { localAssigned.Set(frontierNode.Index, true); unprocessedNodes.Add(frontierNode); } } } } } // Now we have assignments expanded, phi's created, and we can // determine phi sources from a nodes parents final iterations, // which we will use later // Initial iterations for each original local in a node can now // be found through using the SSAPhi's if available, otherwise // using immediate dominator final iterations, the entry node // cannot have phis, and has no immediate dominator, so we just // copy the original locals (iteration 0) as the currentIterations // So finally, now we can retarget uses of original locals by // keeping track of the current iterations, replacing source uses // with current iterations, and updating the current iterations // when there is local assignments IRLocal[] currentIterations = new IRLocal[originalCount]; foreach (IRControlFlowGraphNode node in cfg.Nodes) { if (node.Index == 0) Locals.CopyTo(0, currentIterations, 0, originalCount); else { for (int index = 0; index < originalCount; ++index) currentIterations[index] = node.SSAPhis[index] ?? node.Dominator.SSAFinalIterations[index].Item1; } foreach (IRInstruction instruction in node.Instructions) { instruction.Sources.ForEach(l => l.RetargetLocals(currentIterations)); if (instruction.Destination != null) { if (instruction.Destination.Type == IRLinearizedLocationType.Local) { tempLocal = Locals[instruction.Destination.Local.LocalIndex]; currentIterations[tempLocal.SSAData.Original.Index] = tempLocal; } else { instruction.Destination.RetargetLocals(currentIterations); } } } } // At this point, most of the requirements set by SSA have been // fulfilled, all we want to do now is insert a move instruction // with a linearized phi source for each phi in the frontiers using // the parent final iterations created earlier, with phi reductions // based on lifetime analysis, so that various optimizations occuring // before leaving SSA can be done much more effectively IRMoveInstruction moveInstruction = null; IRLinearizedLocation location = null; HashSet<int> sourceLocals = new HashSet<int>(); // Used to prevent us from adding the same source twice foreach (IRControlFlowGraphNode node in cfg.Nodes) { for (int originalIndex = originalCount - 1; originalIndex >= 0; --originalIndex) { if (node.SSAPhis[originalIndex] != null) { moveInstruction = new IRMoveInstruction(); moveInstruction.Destination = new IRLinearizedLocation(moveInstruction, IRLinearizedLocationType.Local); moveInstruction.Destination.Local.LocalIndex = node.SSAPhis[originalIndex].Index; location = new IRLinearizedLocation(moveInstruction, IRLinearizedLocationType.Phi); location.Phi.SourceLocations = new List<IRLinearizedLocation>(); foreach (IRControlFlowGraphNode parentNode in node.ParentNodes) { int finalIterationIndex = parentNode.SSAFinalIterations[originalIndex].Item1.Index; if (sourceLocals.Add(finalIterationIndex)) { IRLinearizedLocation phiSourceLocation = new IRLinearizedLocation(moveInstruction, IRLinearizedLocationType.Local); phiSourceLocation.Local.LocalIndex = finalIterationIndex; location.Phi.SourceLocations.Add(phiSourceLocation); } } sourceLocals.Clear(); if (location.Phi.SourceLocations.Count == 1) { location.Type = IRLinearizedLocationType.Local; location.Local.LocalIndex = location.Phi.SourceLocations[0].Local.LocalIndex; location.Phi.SourceLocations = null; } moveInstruction.Sources.Add(location); InsertInstruction(node.Instructions[0].IRIndex, moveInstruction); node.Instructions.Insert(0, moveInstruction); } } } mInstructions.FixInsertedTargetInstructions(); // Analyze local lifespans CalculateLocalSSALifespans(cfg); // Find dead phis that got move instructions inserted, and remove // the unneeded instructions, then fix branch targets again List<IRLocal> deadPhis = mLocals.FindAll(l => l.SSAData.Phi && l.SSAData.LifeBegins == l.SSAData.LifeEnds); IRInstruction onlyInstruction = null; foreach (IRLocal deadPhi in deadPhis) { onlyInstruction = deadPhi.SSAData.LifeBegins; mInstructions.Remove(onlyInstruction); deadPhi.SSAData.LifeBegins = null; deadPhi.SSAData.LifeEnds = null; } mInstructions.FixRemovedTargetInstructions(); // Ensure that SSA lifespan analysis data is unusable, as it was // invalidated by dead phi removal mLocals.ForEach(l => l.SSAData.LifeBegins = l.SSAData.LifeEnds = null); //LayoutLocals(); // Test that we did stuff right, make sure no local is assigned // more than once, though some may never get assigned due to // phi reductions that occur, if an exception is thrown here // it is most likely due to something that caused dead code // but never removed it before entering SSA, or a bug with // branching that removed a valid node and we luckily caught a // duplicate assignment due to unprocessed instructions bool[] assigned = new bool[Locals.Count]; foreach (IRInstruction instruction in Instructions) { if (instruction.Destination != null && instruction.Destination.Type == IRLinearizedLocationType.Local) { if (assigned[instruction.Destination.Local.LocalIndex]) throw new Exception(); assigned[instruction.Destination.Local.LocalIndex] = true; } } }
public IRLinearizedLocation(IRInstruction pParentInstruction, IRLinearizedLocation pLinearizedTarget) { mTempID = sTempID++; ParentInstruction = pParentInstruction; Type = pLinearizedTarget.Type; switch (Type) { case IRLinearizedLocationType.Null: break; case IRLinearizedLocationType.Local: Local = pLinearizedTarget.Local; break; case IRLinearizedLocationType.LocalAddress: LocalAddress = pLinearizedTarget.LocalAddress; break; case IRLinearizedLocationType.Parameter: Parameter = pLinearizedTarget.Parameter; break; case IRLinearizedLocationType.ParameterAddress: ParameterAddress = pLinearizedTarget.ParameterAddress; break; case IRLinearizedLocationType.ConstantI4: ConstantI4 = pLinearizedTarget.ConstantI4; break; case IRLinearizedLocationType.ConstantI8: ConstantI8 = pLinearizedTarget.ConstantI8; break; case IRLinearizedLocationType.ConstantR4: ConstantR4 = pLinearizedTarget.ConstantR4; break; case IRLinearizedLocationType.ConstantR8: ConstantR8 = pLinearizedTarget.ConstantR8; break; case IRLinearizedLocationType.Field: Field = pLinearizedTarget.Field; Field.FieldLocation = pLinearizedTarget.Field.FieldLocation.Clone(pParentInstruction); break; case IRLinearizedLocationType.FieldAddress: FieldAddress = pLinearizedTarget.FieldAddress; FieldAddress.FieldLocation = pLinearizedTarget.FieldAddress.FieldLocation.Clone(pParentInstruction); break; case IRLinearizedLocationType.StaticField: StaticField = pLinearizedTarget.StaticField; break; case IRLinearizedLocationType.StaticFieldAddress: StaticFieldAddress = pLinearizedTarget.StaticFieldAddress; break; case IRLinearizedLocationType.Indirect: Indirect = pLinearizedTarget.Indirect; Indirect.AddressLocation = pLinearizedTarget.Indirect.AddressLocation.Clone(pParentInstruction); break; case IRLinearizedLocationType.SizeOf: SizeOf = pLinearizedTarget.SizeOf; break; case IRLinearizedLocationType.ArrayElement: ArrayElement = pLinearizedTarget.ArrayElement; ArrayElement.ArrayLocation = pLinearizedTarget.ArrayElement.ArrayLocation.Clone(pParentInstruction); ArrayElement.IndexLocation = pLinearizedTarget.ArrayElement.IndexLocation.Clone(pParentInstruction); break; case IRLinearizedLocationType.ArrayElementAddress: ArrayElementAddress = pLinearizedTarget.ArrayElementAddress; ArrayElementAddress.ArrayLocation = pLinearizedTarget.ArrayElementAddress.ArrayLocation.Clone(pParentInstruction); ArrayElementAddress.IndexLocation = pLinearizedTarget.ArrayElementAddress.IndexLocation.Clone(pParentInstruction); break; case IRLinearizedLocationType.ArrayLength: ArrayLength = pLinearizedTarget.ArrayLength; ArrayLength.ArrayLocation = pLinearizedTarget.ArrayLength.ArrayLocation.Clone(pParentInstruction); break; case IRLinearizedLocationType.FunctionAddress: FunctionAddress = pLinearizedTarget.FunctionAddress; if (FunctionAddress.InstanceLocation != null) FunctionAddress.InstanceLocation = pLinearizedTarget.FunctionAddress.InstanceLocation.Clone(pParentInstruction); break; case IRLinearizedLocationType.RuntimeHandle: RuntimeHandle = pLinearizedTarget.RuntimeHandle; break; case IRLinearizedLocationType.String: String = pLinearizedTarget.String; break; case IRLinearizedLocationType.Phi: Phi = pLinearizedTarget.Phi; Phi.SourceLocations = new List<IRLinearizedLocation>(pLinearizedTarget.Phi.SourceLocations.Count); pLinearizedTarget.Phi.SourceLocations.ForEach(l => Phi.SourceLocations.Add(l.Clone(pParentInstruction))); break; default: throw new ArgumentException("Type"); } }