/// <summary> /// Lays out all parameters of the method. /// </summary> private void LayoutParameters() { var parameters = new List <Operand>(); int offset = 0; if (MethodCompiler.Method.HasThis || MethodCompiler.Method.HasExplicitThis) { ++offset; } for (int i = 0; i < MethodCompiler.Method.Signature.Parameters.Count + offset; ++i) { var parameter = MethodCompiler.GetParameterOperand(i); parameters.Add(parameter); } int returnSize = 0; if (TypeLayout.IsCompoundType(MethodCompiler.Method.Signature.ReturnType)) { returnSize = TypeLayout.GetTypeSize(MethodCompiler.Method.Signature.ReturnType); } int size = LayoutVariables(parameters, CallingConvention, CallingConvention.OffsetOfFirstParameter + returnSize, false); MethodCompiler.StackLayout.StackParameterSize = size; MethodCompiler.TypeLayout.SetMethodParameterStackSize(MethodCompiler.Method, size); }
/// <summary> /// Adds PHI functions for all ref/out parameters of the method being compiled. /// </summary> private void AddPhiFunctionsForOutParameters() { Dictionary <StackOperand, StackOperand> liveIn = null; // Retrieve the well known epilogue block BasicBlock epilogue = FindBlock(Int32.MaxValue); Debug.Assert(epilogue != null, "Method doesn't have epilogue block?"); Context ctxEpilogue = new Context(InstructionSet, epilogue); ctxEpilogue.GotoLast(); // Iterate all parameter definitions foreach (RuntimeParameter rp in MethodCompiler.Method.Parameters) { // Retrieve the stack operand for the parameter StackOperand paramOp = (StackOperand)MethodCompiler.GetParameterOperand(rp.Position - 1); // Only add a PHI if the runtime parameter is out or ref... if (rp.IsOut || (paramOp.Type is RefSigType || paramOp.Type is PtrSigType)) { ctxEpilogue.AppendInstruction(IR.Instruction.PhiInstruction, paramOp); if (liveIn == null) { liveIn = new Dictionary <StackOperand, StackOperand> (); } liveIn.Add(paramOp, paramOp); } } // Save the in versions to force a merge later if (liveIn != null) { _liveness[epilogue.Sequence] = liveIn; } }
/// <summary> /// Performs stage specific processing on the compiler context. /// </summary> public void Run() { _dominanceProvider = (IDominanceProvider)MethodCompiler.GetPreviousStage(typeof(IDominanceProvider)); Debug.Assert(_dominanceProvider != null, "SSA Conversion requires a dominance provider."); if (_dominanceProvider == null) { throw new InvalidOperationException("SSA Conversion requires a dominance provider."); } // Allocate space for live outs _liveness = new IDictionary <StackOperand, StackOperand> [BasicBlocks.Count]; // Retrieve the dominance frontier Blocks _dominanceFrontierBlocks = _dominanceProvider.GetDominanceFrontier(); // Add ref/out parameters to the epilogue block to have uses there... AddPhiFunctionsForOutParameters(); // Transformation worklist Queue <WorkItem> workList = new Queue <WorkItem> (); /* Move parameter operands into the dictionary as version 0, * because they are live at entry and maybe referenced. Anyways, an * assignment to a parameter is also SSA related. */ IDictionary <StackOperand, StackOperand> liveIn = new Dictionary <StackOperand, StackOperand> (s_comparer); int i = 0; if (MethodCompiler.Method.Signature.HasThis) { StackOperand param = (StackOperand)MethodCompiler.GetParameterOperand(0); liveIn.Add(param, param); i++; } for (int j = 0; j < MethodCompiler.Method.Parameters.Count; j++) { StackOperand param = (StackOperand)MethodCompiler.GetParameterOperand(i + j); liveIn.Add(param, param); } // Start with the very first block workList.Enqueue(new WorkItem(BasicBlocks[0], null, liveIn)); // Iterate until the worklist is empty while (workList.Count != 0) { // Remove the block From the queue WorkItem workItem = workList.Dequeue(); // Transform the block BasicBlock block = workItem.block; bool schedule = TransformToSsaForm(new Context(InstructionSet, block), workItem.caller, workItem.liveIn, out liveIn); _liveness[block.Sequence] = liveIn; if (schedule) { // Add all branch targets to the work list foreach (BasicBlock next in block.NextBlocks) { // Only follow backward branches, if we've redefined a variable // this may force us to reinsert a PHI function in a block we // already have completed processing on. workList.Enqueue(new WorkItem(next, block, liveIn)); } } } }