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;
		}
Пример #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 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;
		}