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!");
			}
		}
示例#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;
				}
			}
		}
		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");
			}
		}