private void UpdateUses(Context ctx, IDictionary <StackOperand, StackOperand> liveOut) { int index = 0; foreach (Operand op1 in ctx.Operands) { // Is this a stack operand? StackOperand op = op1 as StackOperand; if (op != null) { StackOperand ssa; // Determine the most recent version Debug.Assert(liveOut.TryGetValue(op, out ssa), "Stack operand not in live variable list."); ssa = liveOut[op]; // Replace the use with the most recent version ctx.SetOperand(index++, ssa); if (TRACING.TraceInfo) { Trace.WriteLine(String.Format("\\tUse {0} has been replaced with {1}", op, ssa)); } } } }
private void RenameStackOperands(Context ctx, IDictionary <StackOperand, StackOperand> liveOut) { int index = 0; // Create new SSA variables for newly defined operands foreach (Operand op1 in ctx.Results) { // Is this a stack operand? StackOperand op = op1 as StackOperand; if (op != null) { StackOperand ssa; if (!liveOut.TryGetValue(op, out ssa)) { ssa = op; } ssa = RedefineOperand(ssa); liveOut[op] = ssa; ctx.SetResult(index++, ssa); if (TRACING.TraceInfo) { Trace.WriteLine(String.Format("\tStore to {0} redefined as {1}", op, ssa)); } } } }
/// <summary> /// Determines whether [contains] [the specified CTX]. /// </summary> /// <param name="ctx">The context.</param> /// <param name="operand">The operand.</param> /// <returns> /// <c>true</c> if [contains] [the specified CTX]; otherwise, <c>false</c>. /// </returns> public static bool Contains(Context ctx, StackOperand operand) { PhiData phiData = ctx.Other as PhiData; if (phiData == null) { return(false); } List <Operand> operands = phiData.Operands as List <Operand>; return(operands.Contains(operand)); }
/// <summary> /// Redefines a <see cref="StackOperand"/> with a new SSA version. /// </summary> /// <param name="cur">The StackOperand to redefine.</param> /// <returns>A new StackOperand.</returns> private StackOperand RedefineOperand(StackOperand cur) { string name = cur.Name; if (cur.Version == 0) { name = String.Format("T_{0}", name); } StackOperand op = MethodCompiler.CreateTemporary(cur.Type) as StackOperand; //StackOperand op = new LocalVariableOperand(cur.Base, name, idx, cur.Type); op.Version = ++_ssaVersion; return(op); }
/// <summary> /// Adds the value. /// </summary> /// <param name="ctx">The context.</param> /// <param name="edge">The edge.</param> /// <param name="op">The op.</param> public static void AddValue(Context ctx, BasicBlock edge, StackOperand op) { PhiData phiData = ctx.Other as PhiData; if (phiData == null) { phiData = new PhiData(); ctx.Other = phiData; } List <BasicBlock> blocks = phiData.Blocks as List <BasicBlock>; Debug.Assert(blocks.Count < 255, @"Maximum number of operands in PHI exceeded."); blocks.Add(edge); phiData.Operands.Add(op); }
private void MergePhiInstructions(BasicBlock block, BasicBlock caller, IDictionary <StackOperand, StackOperand> liveIn) { for (Context ctx = new Context(InstructionSet, block); !ctx.EndOfInstruction; ctx.GotoNext()) { IR.PhiInstruction phi = ctx.Instruction as IR.PhiInstruction; if (phi != null && liveIn.ContainsKey(ctx.Result as StackOperand)) { StackOperand value = liveIn[ctx.Result as StackOperand]; if (!IR.PhiInstruction.Contains(ctx, value) && (ctx.Result as StackOperand).Version != value.Version) { IR.PhiInstruction.AddValue(ctx, caller, value); } } } }
/// <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; } }
void ICallingConvention.GetStackRequirements(StackOperand stackOperand, out int size, out int alignment) { // Special treatment for some stack types // FIXME: Handle the size and alignment requirements of value types _architecture.GetTypeRequirements(stackOperand.Type, out size, out alignment); }
/// <summary> /// Emits an immediate operand. /// </summary> /// <param name="op">The immediate operand to emit.</param> public void EmitImmediate(Operand op) { byte[] imm = null; if (op is LocalVariableOperand) { // Add the displacement StackOperand so = (StackOperand)op; imm = LittleEndianBitConverter.GetBytes(so.Offset.ToInt32()); } else if (op is LabelOperand) { _literals.Add(new Patch((op as LabelOperand).Label, _codeStream.Position)); imm = new byte[4]; } else if (op is MemoryOperand) { // Add the displacement MemoryOperand mo = (MemoryOperand)op; imm = LittleEndianBitConverter.GetBytes(mo.Offset.ToInt32()); } else if (op is ConstantOperand) { // Add the immediate ConstantOperand co = (ConstantOperand)op; switch (op.Type.Type) { case CilElementType.I: try { imm = LittleEndianBitConverter.GetBytes(Convert.ToInt32(co.Value)); } catch (OverflowException) { imm = LittleEndianBitConverter.GetBytes(Convert.ToUInt32(co.Value)); } break; case CilElementType.I1: //imm = LittleEndianBitConverter.GetBytes(Convert.ToSByte(co.Value)); imm = new byte[1] { Convert.ToByte(co.Value) }; break; case CilElementType.I2: imm = LittleEndianBitConverter.GetBytes(Convert.ToInt16(co.Value)); break; case CilElementType.I4: goto case CilElementType.I; case CilElementType.U1: //imm = LittleEndianBitConverter.GetBytes(Convert.ToByte(co.Value)); imm = new byte[1] { Convert.ToByte(co.Value) }; break; case CilElementType.Char: goto case CilElementType.U2; case CilElementType.U2: imm = LittleEndianBitConverter.GetBytes(Convert.ToUInt16(co.Value)); break; case CilElementType.U4: imm = LittleEndianBitConverter.GetBytes(Convert.ToUInt32(co.Value)); break; case CilElementType.I8: imm = LittleEndianBitConverter.GetBytes(Convert.ToInt64(co.Value)); break; case CilElementType.U8: imm = LittleEndianBitConverter.GetBytes(Convert.ToUInt64(co.Value)); break; case CilElementType.R4: imm = LittleEndianBitConverter.GetBytes(Convert.ToSingle(co.Value)); break; case CilElementType.R8: goto default; default: throw new NotSupportedException(); } } else if (op is RegisterOperand) { // Nothing to do... } else { throw new NotImplementedException(); } // Emit the immediate constant to the code if (null != imm) { _codeStream.Write(imm, 0, imm.Length); } }
/// <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)); } } } }