예제 #1
0
		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;
		}
예제 #2
0
		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;
				}
			}
		}
예제 #3
0
		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;
		}
예제 #4
0
		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();
		}
예제 #5
0
		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;
			}
		}
예제 #6
0
			public IRLocalReductionData(IRInstruction pLifeEnds, IRLocal pLocal) { LifeEnds = pLifeEnds; Local = pLocal; }
예제 #7
0
			public IRLocalSSAData(IRLocal pOriginal) { Original = pOriginal; }
예제 #8
0
		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);
		}