public override void Run(IRMethod pMethod) { pMethod.Instructions.ImmediateRetargetModifiedInstructions = false; for (int i = 0; i < pMethod.Instructions.Count; i++) { var curInstr = pMethod.Instructions[i]; if (curInstr.Opcode == IROpcode.Call) { var curCall = (IRCallInstruction)curInstr; int retIdx; if (!curCall.Virtual && IsSimpleAccessor(curCall.Target, out retIdx)) { if (curCall.Target.IsStatic) { var newMove = new IRMoveInstruction() { ParentMethod = pMethod, }; newMove.Destination = curCall.Destination.Clone(newMove); var retSrc = curCall.Target.Instructions[retIdx].Sources[0]; newMove.Sources.Add(retSrc.Clone(newMove)); pMethod.Instructions[i] = newMove; } else { var newMove = new IRMoveInstruction() { ParentMethod = pMethod, }; newMove.Destination = curCall.Destination.Clone(newMove); var curSrc = curCall.Sources[0]; var retSrc = curCall.Target.Instructions[retIdx].Sources[0]; var paramSrc = new IRLinearizedLocation(newMove, IRLinearizedLocationType.Parameter) { Parameter = new IRLinearizedLocation.ParameterLocationData() { ParameterIndex = 0, }, }; var nSrc = retSrc.Clone(newMove); nSrc.RetargetSource(ref nSrc, paramSrc, curSrc); newMove.Sources.Add(nSrc); pMethod.Instructions[i] = newMove; } } } } pMethod.Instructions.FixModifiedTargetInstructions(); pMethod.Instructions.ImmediateRetargetModifiedInstructions = true; }
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 override void Transform(IRMethod method) { method.Instructions.ImmediateRetargetModifiedInstructions = false; for (int i = 0; i < method.Instructions.Count; i++) { var curInstr = method.Instructions[i]; if (curInstr.Opcode == IROpcode.InitializeObject) { var initObj = (IRInitializeObjectInstruction)curInstr; var mov = new IRMoveInstruction() { ParentMethod = method, Linearized = true, IRIndex = i, ILOffset = curInstr.ILOffset, }; if (initObj.Type.IsClass || initObj.Type.IsInterface) { mov.Destination = new IRLinearizedLocation(mov, IRLinearizedLocationType.Indirect) { Indirect = new IRLinearizedLocation.IndirectLocationData() { AddressLocation = initObj.Sources[0], Type = method.Assembly.AppDomain.System_Object } }; mov.Sources.Add(new IRLinearizedLocation(mov, IRLinearizedLocationType.Null)); } else if ( initObj.Type == method.Assembly.AppDomain.System_Byte || initObj.Type == method.Assembly.AppDomain.System_SByte || initObj.Type == method.Assembly.AppDomain.System_UInt16 || initObj.Type == method.Assembly.AppDomain.System_Int16 || initObj.Type == method.Assembly.AppDomain.System_Char || initObj.Type == method.Assembly.AppDomain.System_UInt32 || initObj.Type == method.Assembly.AppDomain.System_Int32 ) { mov.Destination = new IRLinearizedLocation(mov, IRLinearizedLocationType.Indirect) { Indirect = new IRLinearizedLocation.IndirectLocationData() { AddressLocation = initObj.Sources[0], Type = initObj.Type } }; mov.Sources.Add(new IRLinearizedLocation(mov, IRLinearizedLocationType.ConstantI4)); } else if ( initObj.Type == method.Assembly.AppDomain.System_UInt64 || initObj.Type == method.Assembly.AppDomain.System_Int64 ) { mov.Destination = new IRLinearizedLocation(mov, IRLinearizedLocationType.Indirect) { Indirect = new IRLinearizedLocation.IndirectLocationData() { AddressLocation = initObj.Sources[0], Type = initObj.Type } }; mov.Sources.Add(new IRLinearizedLocation(mov, IRLinearizedLocationType.ConstantI8)); } else if (initObj.Type == method.Assembly.AppDomain.System_Single) { mov.Destination = new IRLinearizedLocation(mov, IRLinearizedLocationType.Indirect) { Indirect = new IRLinearizedLocation.IndirectLocationData() { AddressLocation = initObj.Sources[0], Type = initObj.Type } }; mov.Sources.Add(new IRLinearizedLocation(mov, IRLinearizedLocationType.ConstantR4)); } else if (initObj.Type == method.Assembly.AppDomain.System_Double) { mov.Destination = new IRLinearizedLocation(mov, IRLinearizedLocationType.Indirect) { Indirect = new IRLinearizedLocation.IndirectLocationData() { AddressLocation = initObj.Sources[0], Type = initObj.Type } }; mov.Sources.Add(new IRLinearizedLocation(mov, IRLinearizedLocationType.ConstantR8)); } else { #warning Still need a way to initialize a structure here. continue; } method.Instructions[i] = mov; } } method.Instructions.FixModifiedTargetInstructions(); method.Instructions.ImmediateRetargetModifiedInstructions = true; }