public IRLocal Clone(IRMethod newMethod) { IRLocal local = new IRLocal(this.Assembly); local.ParentMethod = newMethod; local.mType = this.Type; local.Index = newMethod.Locals.Count; if (SSAData != null) local.SSAData = SSAData.Clone(); return local; }
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 int AddLinearizedLocal(Stack<IRStackObject> pStack, IRType pType) { IRLocal local = null; if (!LinearizedStackLocalLookup.TryGetValue(new Tuple<int, IRType>(pStack.Count, pType), out local)) { local = new IRLocal(Assembly); local.ParentMethod = this; local.Type = pType; local.Index = Locals.Count; Locals.Add(local); LinearizedStackLocalLookup[new Tuple<int, IRType>(pStack.Count, pType)] = local; } return local.Index; }
public void LeaveSSA() { IRControlFlowGraph cfg = IRControlFlowGraph.Build(this); if (cfg == null) return; IRLocal newLocal = null; IRLocal[] reductionTargets = Locals.ToArray(); // Reduce Phi source locations Instructions.ImmediateRetargetModifiedInstructions = false; for (int instructionIndex = 0; instructionIndex < Instructions.Count; ++instructionIndex) { IRInstruction instruction = Instructions[instructionIndex]; if (instruction.Sources.Count == 1 && instruction.Sources[0].Type == IRLinearizedLocationType.Phi) { instruction.Sources[0].Phi.SourceLocations.ForEach(l => reductionTargets[l.Local.LocalIndex] = Locals[instruction.Destination.Local.LocalIndex]); Instructions[instructionIndex] = new IRNopInstruction(); } } Instructions.ImmediateRetargetModifiedInstructions = true; Instructions.FixModifiedTargetInstructions(); foreach (IRInstruction instruction in Instructions) { if (instruction.Destination != null) instruction.Destination.RetargetLocals(reductionTargets); foreach (IRLinearizedLocation sourceLocation in instruction.Sources) sourceLocation.RetargetLocals(reductionTargets); } // Recalculate local lifespans CalculateLocalSSALifespans(cfg); // Find and sort all locals that are alive List<IRLocal> sortedLocals = Locals.FindAll(l => !l.SSAData.IsDead); if (sortedLocals.Count > 0) { sortedLocals.Sort((l1, l2) => { int beginCompare = l1.SSAData.LifeBegins.IRIndex.CompareTo(l2.SSAData.LifeBegins.IRIndex); if (beginCompare != 0) return beginCompare; return l1.SSAData.LifeEnds.IRIndex.CompareTo(l2.SSAData.LifeEnds.IRIndex); }); // Build an array of targets for locals to be // retargeted to for reductions based on lifetime // analysis Dictionary<IRType, List<IRLocal.IRLocalReductionData>> reductionMap = new Dictionary<IRType, List<IRLocal.IRLocalReductionData>>(); List<IRLocal.IRLocalReductionData> reductionTerminations = null; reductionTargets = new IRLocal[Locals.Count]; IRLocal local = null; bool reused = false; int startOfReducedLocals = Locals.Count; for (int sortedIndex = 0; sortedIndex < sortedLocals.Count; ++sortedIndex) { local = sortedLocals[sortedIndex]; reused = false; if (!reductionMap.TryGetValue(local.Type, out reductionTerminations)) { newLocal = new IRLocal(Assembly); newLocal.ParentMethod = this; newLocal.Type = local.Type; newLocal.Index = Locals.Count; Locals.Add(newLocal); reductionTerminations = new List<IRLocal.IRLocalReductionData>(); reductionTerminations.Add(new IRLocal.IRLocalReductionData(local.SSAData.LifeEnds, newLocal)); reductionTargets[local.Index] = newLocal; reductionMap.Add(local.Type, reductionTerminations); } else { for (int terminationIndex = 0; terminationIndex < reductionTerminations.Count; ++terminationIndex) { if (reductionTerminations[terminationIndex].LifeEnds.IRIndex < local.SSAData.LifeBegins.IRIndex) { reductionTerminations[terminationIndex].LifeEnds = local.SSAData.LifeEnds; reductionTargets[local.Index] = reductionTerminations[terminationIndex].Local; reused = true; break; } } if (!reused) { newLocal = new IRLocal(Assembly); newLocal.ParentMethod = this; newLocal.Type = local.Type; newLocal.Index = Locals.Count; Locals.Add(newLocal); reductionTerminations.Add(new IRLocal.IRLocalReductionData(local.SSAData.LifeEnds, newLocal)); reductionTargets[local.Index] = newLocal; } } } // Now we can retarget all the old locals foreach (IRInstruction instruction in Instructions) { if (instruction.Destination != null) instruction.Destination.RetargetLocals(reductionTargets); instruction.Sources.ForEach(l => l.RetargetLocals(reductionTargets)); } reductionTargets = new IRLocal[Locals.Count]; for (int reducedIndex = startOfReducedLocals; reducedIndex < reductionTargets.Length; ++reducedIndex) reductionTargets[reducedIndex] = Locals[reducedIndex]; Locals.RemoveRange(0, startOfReducedLocals); for (int localIndex = 0; localIndex < Locals.Count; ++localIndex) Locals[localIndex].Index = localIndex; foreach (IRInstruction instruction in Instructions) { if (instruction.Destination != null) instruction.Destination.RetargetLocals(reductionTargets); instruction.Sources.ForEach(l => l.RetargetLocals(reductionTargets)); } } else Locals.Clear(); LayoutLocals(); }
public void RetargetLocals(IRLocal[] pCurrentIterations) { switch (Type) { case IRLinearizedLocationType.Local: Local.LocalIndex = pCurrentIterations[Local.LocalIndex].Index; break; case IRLinearizedLocationType.LocalAddress: LocalAddress.LocalIndex = pCurrentIterations[LocalAddress.LocalIndex].Index; break; case IRLinearizedLocationType.ArrayElement: ArrayElement.ArrayLocation.RetargetLocals(pCurrentIterations); ArrayElement.IndexLocation.RetargetLocals(pCurrentIterations); break; case IRLinearizedLocationType.ArrayElementAddress: ArrayElementAddress.ArrayLocation.RetargetLocals(pCurrentIterations); ArrayElementAddress.IndexLocation.RetargetLocals(pCurrentIterations); break; case IRLinearizedLocationType.ArrayLength: ArrayLength.ArrayLocation.RetargetLocals(pCurrentIterations); break; case IRLinearizedLocationType.Field: Field.FieldLocation.RetargetLocals(pCurrentIterations); break; case IRLinearizedLocationType.FieldAddress: FieldAddress.FieldLocation.RetargetLocals(pCurrentIterations); break; case IRLinearizedLocationType.Indirect: Indirect.AddressLocation.RetargetLocals(pCurrentIterations); break; case IRLinearizedLocationType.FunctionAddress: if (FunctionAddress.InstanceLocation != null) FunctionAddress.InstanceLocation.RetargetLocals(pCurrentIterations); break; case IRLinearizedLocationType.Phi: Phi.SourceLocations.ForEach(l => l.RetargetLocals(pCurrentIterations)); break; default: break; } }
public IRLocalReductionData(IRInstruction pLifeEnds, IRLocal pLocal) { LifeEnds = pLifeEnds; Local = pLocal; }
public IRLocalSSAData(IRLocal pOriginal) { Original = pOriginal; }
internal void LoadStage1() { Console.WriteLine("========== Stage 1: {0,-45} ==========", File.ReferenceName); Types = new List<IRType>(File.TypeDefTable.Length); Fields = new List<IRField>(File.FieldTable.Length); Methods = new List<IRMethod>(File.MethodDefTable.Length); foreach (TypeDefData typeDefData in File.TypeDefTable) Types.Add(new IRType(this)); foreach (FieldData fieldData in File.FieldTable) Fields.Add(new IRField(this)); foreach (MethodDefData methodDefData in File.MethodDefTable) { IRMethod method = new IRMethod(this); Methods.Add(method); var mGenParams = new List<GenericParamData>(methodDefData.GenericParamList); for (int i = 0; i < mGenParams.Count; i++) { method.GenericParameters.Add(IRType.GetMVarPlaceholder(mGenParams[i].Number)); } } for (int typeIndex = 0; typeIndex < Types.Count; ++typeIndex) { IRType type = Types[typeIndex]; TypeDefData typeDefData = File.TypeDefTable[typeIndex]; type.Namespace = typeDefData.TypeNamespace; type.Name = typeDefData.TypeName; type.Flags = typeDefData.Flags; var genParams = new List<GenericParamData>(typeDefData.GenericParamList); for (int i = 0; i < genParams.Count; i++) { type.GenericParameters.Add(IRType.GetVarPlaceholder(genParams[i].Number)); } foreach (FieldData fieldData in typeDefData.FieldList) { IRField field = Fields[fieldData.TableIndex]; field.Name = fieldData.Name; field.Flags = fieldData.Flags; field.ParentType = type; type.Fields.Add(field); } foreach (MethodDefData methodDefData in typeDefData.MethodList) { IRMethod method = Methods[methodDefData.TableIndex]; method.Name = methodDefData.Name; method.Flags = methodDefData.Flags; method.ImplFlags = methodDefData.ImplFlags; method.ParentType = type; type.Methods.Add(method); foreach (ParamData paramData in methodDefData.ParamList) { IRParameter parameter = new IRParameter(this); parameter.ParentMethod = method; method.Parameters.Add(parameter); } if (methodDefData.Body != null && methodDefData.Body.ExpandedLocalVarSignature != null) { method.MaximumStackDepth = methodDefData.Body.MaxStack; foreach (SigLocalVar sigLocalVar in methodDefData.Body.ExpandedLocalVarSignature.LocalVars) { IRLocal local = new IRLocal(this); local.ParentMethod = method; local.Index = method.Locals.Count; method.Locals.Add(local); } } } } for (int typeIndex = 0; typeIndex < Types.Count; ++typeIndex) { IRType type = Types[typeIndex]; TypeDefData typeDefData = File.TypeDefTable[typeIndex]; foreach (TypeDefData nestedTypeDefData in typeDefData.NestedClassList) { IRType nestedType = Types[nestedTypeDefData.TableIndex]; //nestedType.Namespace = type.Namespace + "." + type.Name; nestedType.NestedInsideOfType = type; type.NestedTypes.Add(nestedType); } } if (CORLibrary) AppDomain.CacheCOR(this); else if (RuntimeLibrary) AppDomain.CacheRuntime(this); }