/// <summary> /// /// </summary> /// <param name="context"></param> /// <param name="emitter"></param> protected override void Emit(Context context, MachineCodeEmitter emitter) { OpCode opCode = ComputeOpCode(context.Result, context.Operand1, context.Operand2); if (context.Operand1 is ConstantOperand) { ConstantOperand op = context.Operand1 as ConstantOperand; op = new ConstantOperand(BuiltInSigType.Byte, op.Value); emitter.Emit(opCode, context.Result, op); } else emitter.Emit(opCode, context.Operand1, null); }
/// <summary> /// Emits the specified platform instruction. /// </summary> /// <param name="context">The context.</param> /// <param name="emitter">The emitter.</param> protected override void Emit(Context context, MachineCodeEmitter emitter) { OpCode opCode = ComputeOpCode(context.Result, context.Operand1, context.Operand2); if (context.Operand2 is ConstantOperand) { // TODO/FIXME: Move these two lines into a stage ConstantOperand op = context.Operand2 as ConstantOperand; op = new ConstantOperand(BuiltInSigType.Byte, op.Value); emitter.Emit(opCode, context.Result, context.Operand1, op); } else emitter.Emit(opCode, context.Result, context.Operand1, context.Operand2); }
protected bool IsConstantBetween(ConstantOperand op, int lo, int hi, out int value) { value = 0; switch (op.Type.Type) { case CilElementType.I: try { if (op.Value is Token) { value = ((Token)op.Value).ToInt32(); return value >= lo && value <= hi; } else { value = Convert.ToInt32(op.Value); return value >= lo && value <= hi; } } catch (OverflowException) { return false; } case CilElementType.I1: case CilElementType.I2: case CilElementType.I4: case CilElementType.U1: case CilElementType.Char: case CilElementType.U2: case CilElementType.Ptr: case CilElementType.U4: goto case CilElementType.I; case CilElementType.I8: case CilElementType.U8: case CilElementType.R4: case CilElementType.R8: goto default; case CilElementType.Object: goto case CilElementType.I; default: throw new NotSupportedException(String.Format(@"CilElementType.{0} is not supported.", op.Type.Type)); } }
private static void SplitFromConstantOperand(Operand operand, out Operand operandLow, out Operand operandHigh) { SigType HighType = (operand.Type.Type == CilElementType.I8) ? BuiltInSigType.Int32 : BuiltInSigType.UInt32; ConstantOperand constantOperand = operand as ConstantOperand; if (HighType.Type == CilElementType.I4) { long value = (long)constantOperand.Value; operandLow = new ConstantOperand(BuiltInSigType.UInt32, (uint)(value & 0xFFFFFFFF)); operandHigh = new ConstantOperand(HighType, (int)(value >> 32)); } else { ulong value = (ulong)constantOperand.Value; operandLow = new ConstantOperand(BuiltInSigType.UInt32, (uint)(value & 0xFFFFFFFF)); operandHigh = new ConstantOperand(HighType, (uint)(value >> 32)); } }
/// <summary> /// Expands the unary branch instruction for 64-bits. /// </summary> /// <param name="context">The context.</param> private void ExpandUnaryBranch(Context context) { Debug.Assert(context.Branch.Targets.Length == 2); int target = context.Branch.Targets[0]; Operand op1H, op1L, op2H, op2L; Operand zero = new ConstantOperand(BuiltInSigType.Int32, (int)0); SplitLongOperand(context.Operand1, out op1L, out op1H); SplitLongOperand(zero, out op2L, out op2H); IR.ConditionCode code; switch (((context.Instruction) as CIL.ICILInstruction).OpCode) { // Signed case CIL.OpCode.Brtrue: code = IR.ConditionCode.NotEqual; break; case CIL.OpCode.Brfalse: code = IR.ConditionCode.Equal; break; case CIL.OpCode.Beq_s: code = IR.ConditionCode.Equal; break; case CIL.OpCode.Bge_s: code = IR.ConditionCode.GreaterOrEqual; break; case CIL.OpCode.Bgt_s: code = IR.ConditionCode.GreaterThan; break; case CIL.OpCode.Ble_s: code = IR.ConditionCode.LessOrEqual; break; case CIL.OpCode.Blt_s: code = IR.ConditionCode.LessThan; break; // Unsigned case CIL.OpCode.Bne_un_s: code = IR.ConditionCode.NotEqual; break; case CIL.OpCode.Bge_un_s: code = IR.ConditionCode.UnsignedGreaterOrEqual; break; case CIL.OpCode.Bgt_un_s: code = IR.ConditionCode.UnsignedGreaterThan; break; case CIL.OpCode.Ble_un_s: code = IR.ConditionCode.UnsignedLessOrEqual; break; case CIL.OpCode.Blt_un_s: code = IR.ConditionCode.UnsignedLessThan; break; // Long form signed case CIL.OpCode.Beq: goto case CIL.OpCode.Beq_s; case CIL.OpCode.Bge: goto case CIL.OpCode.Bge_s; case CIL.OpCode.Bgt: goto case CIL.OpCode.Bgt_s; case CIL.OpCode.Ble: goto case CIL.OpCode.Ble_s; case CIL.OpCode.Blt: goto case CIL.OpCode.Blt_s; // Long form unsigned case CIL.OpCode.Bne_un: goto case CIL.OpCode.Bne_un_s; case CIL.OpCode.Bge_un: goto case CIL.OpCode.Bge_un_s; case CIL.OpCode.Bgt_un: goto case CIL.OpCode.Bgt_un_s; case CIL.OpCode.Ble_un: goto case CIL.OpCode.Ble_un_s; case CIL.OpCode.Blt_un: goto case CIL.OpCode.Blt_un_s; default: throw new NotImplementedException(); } //UNUSED: //IR.ConditionCode conditionHigh = GetHighCondition(code); Context[] newBlocks = CreateEmptyBlockContexts(context.Label, 3); Context nextBlock = SplitContext(context, false); context.SetInstruction(Instruction.JmpInstruction, newBlocks[0].BasicBlock); LinkBlocks(context, newBlocks[0]); // Compare high dwords // TODO: //newBlocks[0].AppendInstruction(Instruction.DirectCompareInstruction, op1H, op2H); // Branch if check already gave results newBlocks[0].AppendInstruction(Instruction.BranchInstruction, IR.ConditionCode.Equal, newBlocks[2].BasicBlock); newBlocks[0].AppendInstruction(Instruction.JmpInstruction, newBlocks[1].BasicBlock); LinkBlocks(newBlocks[0], newBlocks[1], newBlocks[2]); newBlocks[1].AppendInstruction(Instruction.BranchInstruction, code, FindBlock(target)); // newBlocks[1].SetBranch(target); newBlocks[1].AppendInstruction(Instruction.JmpInstruction); newBlocks[1].SetBranch(nextBlock.BasicBlock); LinkBlocks(newBlocks[1], FindBlock(target)); LinkBlocks(newBlocks[1], nextBlock); // Compare low dwords // TODO: //newBlocks[2].SetInstruction(Instruction.DirectCompareInstruction, op1L, op2L); // Set the unsigned result... newBlocks[2].AppendInstruction(Instruction.BranchInstruction, code, FindBlock(target)); // newBlocks[1].SetBranch(target); newBlocks[2].AppendInstruction(Instruction.JmpInstruction); newBlocks[2].SetBranch(nextBlock.BasicBlock); LinkBlocks(newBlocks[2], FindBlock(target)); LinkBlocks(newBlocks[2], nextBlock); }
/// <summary> /// Splits the long operand into its high and low parts. /// </summary> /// <param name="operand">The operand to split.</param> /// <param name="operandLow">The low operand.</param> /// <param name="operandHigh">The high operand.</param> /// <exception cref="T:System.ArgumentException"><paramref name="operand"/> is not a ConstantOperand and not a MemoryOperand.</exception> public static void SplitLongOperand(Operand operand, out Operand operandLow, out Operand operandHigh) { if (operand.Type.Type != CilElementType.I8 && operand.Type.Type != CilElementType.U8) { operandLow = operand; operandHigh = new ConstantOperand(BuiltInSigType.Int32, (int)0); return; } Debug.Assert(operand is MemoryOperand || operand is ConstantOperand, @"Long operand not memory or constant."); if (operand is ConstantOperand) SplitFromConstantOperand(operand, out operandLow, out operandHigh); else SplitFromNonConstantOperand(operand, out operandLow, out operandHigh); }
/// <summary> /// Determines if the given constant operand is a large constant. /// </summary> /// <remarks> /// Only constants, which have special types or do not fit into an immediate argument /// are large and are moved to memory. /// </remarks> /// <param name="co">The constant operand to check.</param> /// <returns>True if the constant is large and needs to be moved to a literal.</returns> private static bool IsLargeConstant(ConstantOperand co) { return (Array.IndexOf<CilElementType>(_largeCilTypes, co.Type.Type) != -1); }
/// <summary> /// Visitation function for Ldfld instruction. /// </summary> /// <param name="context">The context.</param> public void Ldfld(Context context) { Operand resultOperand = context.Result; Operand objectOperand = context.Operand1; Operand temp = methodCompiler.CreateVirtualRegister(context.RuntimeField.SignatureType); RuntimeField field = context.RuntimeField; int offset = typeLayout.GetFieldOffset(field); ConstantOperand offsetOperand = new ConstantOperand(BuiltInSigType.IntPtr, offset); IInstruction loadInstruction = IRInstruction.Load; if (MustSignExtendOnLoad(field.SignatureType.Type)) { loadInstruction = IRInstruction.SignExtendedMove; } else if (MustZeroExtendOnLoad(field.SignatureType.Type)) { loadInstruction = IRInstruction.ZeroExtendedMove; } context.SetInstruction(loadInstruction, temp, objectOperand, offsetOperand); context.AppendInstruction(IRInstruction.Move, resultOperand, temp); }
private Operand CalculateArrayElementOffset(Context context, SZArraySigType arraySignatureType, Operand arrayIndexOperand) { int elementSizeInBytes = 0, alignment = 0; architecture.GetTypeRequirements(arraySignatureType.ElementType, out elementSizeInBytes, out alignment); // // The sequence we're emitting is: // // offset = arrayIndexOperand * elementSize // temp = offset + 12 // result = *(arrayOperand * temp) // // The array data starts at offset 12 from the array object itself. The 12 is a hardcoded assumption // of x86, which might change for other platforms. We need to refactor this into some helper classes. // Operand elementOffset = methodCompiler.CreateVirtualRegister(BuiltInSigType.Int32); Operand elementSizeOperand = new ConstantOperand(BuiltInSigType.Int32, elementSizeInBytes); context.AppendInstruction(IRInstruction.MulS, elementOffset, arrayIndexOperand, elementSizeOperand); return elementOffset; }
private Operand LoadArrayBaseAddress(Context context, SZArraySigType arraySignatureType, Operand arrayOperand) { Operand arrayAddress = methodCompiler.CreateVirtualRegister(new PtrSigType(arraySignatureType.ElementType)); Operand fixedOffset = new ConstantOperand(BuiltInSigType.Int32, 12); context.SetInstruction(IRInstruction.AddS, arrayAddress, arrayOperand, fixedOffset); return arrayAddress; }
/// <summary> /// Visitation function for Stfld instruction. /// </summary> /// <param name="context">The context.</param> public void Stfld(Context context) { Operand objectOperand = context.Operand1; Operand valueOperand = context.Operand2; Operand temp = methodCompiler.CreateVirtualRegister(context.RuntimeField.SignatureType); int offset = typeLayout.GetFieldOffset(context.RuntimeField); ConstantOperand offsetOperand = new ConstantOperand(BuiltInSigType.IntPtr, offset); context.SetInstruction(IRInstruction.Move, temp, valueOperand); context.AppendInstruction(IRInstruction.Store, objectOperand, objectOperand, offsetOperand, temp); }
/// <summary> /// Visitation function for Neg instruction. /// </summary> /// <param name="context">The context.</param> public void Neg(Context context) { if (IsUnsigned(context.Operand1)) { ConstantOperand zero = new ConstantOperand(context.Operand1.Type, 0UL); context.SetInstruction(IRInstruction.SubU, context.Result, zero, context.Operand1); } else if (context.Operand1.Type.Type == CilElementType.R4) { ConstantOperand minusOne = new ConstantOperand(context.Operand1.Type, -1.0f); context.SetInstruction(IRInstruction.MulF, context.Result, minusOne, context.Operand1); } else if (context.Operand1.Type.Type == CilElementType.R8) { ConstantOperand minusOne = new ConstantOperand(context.Operand1.Type, -1.0); context.SetInstruction(IRInstruction.MulF, context.Result, minusOne, context.Operand1); } else { ConstantOperand minusOne = new ConstantOperand(context.Operand1.Type, -1L); context.SetInstruction(IRInstruction.MulS, context.Result, minusOne, context.Operand1); } }
/// <summary> /// Visitation function for Ldflda instruction. /// </summary> /// <param name="context">The context.</param> public void Ldflda(Context context) { Operand fieldAddress = context.Result; Operand objectOperand = context.Operand1; int offset = typeLayout.GetFieldOffset(context.RuntimeField); Operand fixedOffset = new ConstantOperand(BuiltInSigType.Int32, offset); context.SetInstruction(IRInstruction.AddU, fieldAddress, objectOperand, fixedOffset); }
/// <summary> /// Decodes the specified instruction. /// </summary> /// <param name="ctx">The context.</param> /// <param name="decoder">The instruction decoder, which holds the code stream.</param> public override void Decode(Context ctx, IInstructionDecoder decoder) { // Decode base classes first base.Decode(ctx, decoder); ConstantOperand constantValueOperand; // Opcode specific handling switch (opcode) { case OpCode.Ldc_i4: { int i = decoder.DecodeInt(); constantValueOperand = new ConstantOperand(BuiltInSigType.Int32, i); } break; case OpCode.Ldc_i4_s: { sbyte sb = decoder.DecodeSByte(); constantValueOperand = new ConstantOperand(BuiltInSigType.Int32, sb); } break; case OpCode.Ldc_i8: { long l = decoder.DecodeLong(); constantValueOperand = new ConstantOperand(BuiltInSigType.Int64, l); } break; case OpCode.Ldc_r4: { float f = decoder.DecodeFloat(); constantValueOperand = new ConstantOperand(BuiltInSigType.Single, f); } break; case OpCode.Ldc_r8: { double d = decoder.DecodeDouble(); constantValueOperand = new ConstantOperand(BuiltInSigType.Double, d); } break; case OpCode.Ldnull: constantValueOperand = ConstantOperand.GetNull(); break; case OpCode.Ldc_i4_0: constantValueOperand = ConstantOperand.FromValue(0); break; case OpCode.Ldc_i4_1: constantValueOperand = ConstantOperand.FromValue(1); break; case OpCode.Ldc_i4_2: constantValueOperand = ConstantOperand.FromValue(2); break; case OpCode.Ldc_i4_3: constantValueOperand = ConstantOperand.FromValue(3); break; case OpCode.Ldc_i4_4: constantValueOperand = ConstantOperand.FromValue(4); break; case OpCode.Ldc_i4_5: constantValueOperand = ConstantOperand.FromValue(5); break; case OpCode.Ldc_i4_6: constantValueOperand = ConstantOperand.FromValue(6); break; case OpCode.Ldc_i4_7: constantValueOperand = ConstantOperand.FromValue(7); break; case OpCode.Ldc_i4_8: constantValueOperand = ConstantOperand.FromValue(8); break; case OpCode.Ldc_i4_m1: constantValueOperand = ConstantOperand.FromValue(-1); break; default: throw new System.NotImplementedException(); } ctx.Operand1 = constantValueOperand; ctx.Result = decoder.Compiler.CreateTemporary(constantValueOperand.Type); }
/// <summary> /// Folds the add signed. /// </summary> /// <param name="context">The context.</param> private void FoldAddSigned(Context context) { if (context.Ignore) return; if (!(context.Instruction is IR.AddSigned)) return; Operand result = context.Result; ConstantOperand op1 = context.Operand1 as ConstantOperand; ConstantOperand op2 = context.Operand2 as ConstantOperand; if (op1 == null || op2 == null) return; if (result.Type.Type != op1.Type.Type || op1.Type.Type != op2.Type.Type) return; ConstantOperand constant = null; switch (result.Type.Type) { case CilElementType.U1: constant = new ConstantOperand(result.Type, (byte)(op1.Value) + (byte)(op2.Value)); break; case CilElementType.I4: constant = new ConstantOperand(result.Type, (int)(op1.Value) + (int)(op2.Value)); break; default: break; } if (constant != null) { AddContextResultToWorkList(context); context.SetInstruction(IRInstruction.Move, context.Result, constant); } }
/// <summary> /// Determines whether the value is zero. /// </summary> /// <param name="cilElementType">Type of the cil element.</param> /// <param name="constantOperand">The constant operand.</param> /// <returns> /// <c>true</c> if the value is zero; otherwise, <c>false</c>. /// </returns> private static bool IsValueZero(Metadata.CilElementType cilElementType, ConstantOperand constantOperand) { switch (cilElementType) { case Metadata.CilElementType.Char: goto case Metadata.CilElementType.U2; case Metadata.CilElementType.U1: return (byte)(constantOperand.Value) == 0; case Metadata.CilElementType.U2: return (ushort)(constantOperand.Value) == 0; case Metadata.CilElementType.U4: return (int)(constantOperand.Value) == 0; case Metadata.CilElementType.I1: return (sbyte)(constantOperand.Value) == 0; case Metadata.CilElementType.I2: return (short)(constantOperand.Value) == 0; case Metadata.CilElementType.I4: return (int)(constantOperand.Value) == 0; case Metadata.CilElementType.R4: return (float)(constantOperand.Value) == 0; case Metadata.CilElementType.R8: return (double)(constantOperand.Value) == 0; case Metadata.CilElementType.I: goto case Metadata.CilElementType.I4; case Metadata.CilElementType.U: goto case Metadata.CilElementType.U4; default: goto case Metadata.CilElementType.I4; } }
/// <summary> /// Visitation function for UnaryBranch instruction. /// </summary> /// <param name="context">The context.</param> public void UnaryBranch(Context context) { IBranch branch = context.Branch; ConditionCode cc; Operand first = context.Operand1; Operand second = new ConstantOperand(BuiltInSigType.Int32, 0UL); CIL.OpCode opcode = ((CIL.ICILInstruction)context.Instruction).OpCode; if (opcode == CIL.OpCode.Brtrue || opcode == CIL.OpCode.Brtrue_s) { cc = ConditionCode.NotEqual; } else if (opcode == CIL.OpCode.Brfalse || opcode == CIL.OpCode.Brfalse_s) { cc = ConditionCode.Equal; } else { throw new NotSupportedException(@"CILTransformationStage.UnaryBranch doesn't support CIL opcode " + opcode); } context.SetInstruction(Instruction.IntegerCompareBranchInstruction, null, first, second); context.ConditionCode = cc; context.SetBranch(branch.Targets[0]); }