/// <summary> /// Computes the opcode. /// </summary> /// <param name="destination">The destination operand.</param> /// <param name="source">The source operand.</param> /// <param name="third">The third operand.</param> /// <returns></returns> protected override OpCode ComputeOpCode(Operand destination, Operand source, Operand third) { if (source.IsMemoryAddress && third.IsRegister) { if (source.IsByte || third.IsByte) return M_R_8; if (source.IsChar || third.IsChar) return M_R_16; if (source.IsShort || third.IsShort) return M_R_16; return M_R; } if (source.IsRegister && third.IsRegister) return R_R; if (source.IsMemoryAddress && third.IsConstant) return M_C; if (source.IsRegister && third.IsConstant) { if (third.IsByte || source.IsByte) return R_C_8; if (third.IsChar || source.IsChar) return R_C_16; if (third.IsShort || source.IsShort) return R_C_16; return R_C; } throw new ArgumentException(String.Format(@"x86.Test: No opcode for operand types {0} and {1}.", source, third)); }
/// <summary> /// Computes the opcode. /// </summary> /// <param name="size">The size.</param> /// <param name="destination">The destination operand.</param> /// <param name="source">The source operand.</param> /// <returns></returns> /// <exception cref="NotImplementCompilerException"></exception> private OpCode ComputeOpCode(InstructionSize size, Operand destination, Operand source) { Debug.Assert(destination.IsConstant || destination.IsCPURegister); Debug.Assert(size != InstructionSize.None); Debug.Assert(size != InstructionSize.Native); //size = BaseMethodCompilerStage.GetInstructionSize(size, destination); if (destination.IsCPURegister) { if (size == InstructionSize.Size8) return R_8; if (size == InstructionSize.Size16) return R_16; return R_32; } if (destination.IsConstant) { if (size == InstructionSize.Size8) return C_8; if (size == InstructionSize.Size16) return C_16; return C_32; } throw new NotImplementCompilerException(); }
/// <summary> /// Computes the opcode. /// </summary> /// <param name="destination">The destination operand.</param> /// <param name="source">The source operand.</param> /// <param name="third">The third operand.</param> /// <returns></returns> protected override OpCode ComputeOpCode(Operand destination, Operand source, Operand third) { if ((source.IsRegister) && (third.IsRegister)) return opcode; if ((source.IsRegister) && (third.IsMemoryAddress)) return opcode; if ((source.IsRegister) && (third.IsConstant)) return opcode; throw new ArgumentException(@"No opcode for operand type."); }
/// <summary> /// Computes the opcode. /// </summary> /// <param name="destination">The destination operand.</param> /// <param name="source">The source operand.</param> /// <param name="third">The third operand.</param> /// <returns></returns> protected override OpCode ComputeOpCode(Operand destination, Operand source, Operand third) { if (!(destination.IsRegister)) throw new ArgumentException(@"Destination must be RegisterOperand.", @"destination"); if (source.IsConstant) throw new ArgumentException(@"Source must not be ConstantOperand.", @"source"); switch (source.Type.Type) { case CilElementType.Boolean: goto case CilElementType.I1; case CilElementType.U1: goto case CilElementType.I1; case CilElementType.I1: { if ((destination.IsRegister) && (source.IsRegister)) return R_X8; if ((destination.IsRegister) && (source.IsMemoryAddress)) return R_X8; } break; case CilElementType.Char: goto case CilElementType.U2; case CilElementType.U2: goto case CilElementType.I2; case CilElementType.I2: if ((destination.IsRegister) && (source.IsRegister)) return R_X16; if ((destination.IsRegister) && (source.IsMemoryAddress)) return R_X16; break; default: break; } throw new ArgumentException(@"No opcode for operand type. [" + destination.GetType() + ", " + source.GetType() + ")"); }
/// <summary> /// This function emits a constant variable into the read-only data section. /// </summary> /// <param name="op">The operand to emit as a constant.</param> /// <returns>An operand, which represents the reference to the read-only constant.</returns> /// <remarks> /// This function checks if the given operand needs to be moved into the read-only data /// section of the executable. For x86 this concerns only floating point operands, as these /// can't be specified in inline assembly.<para/> /// This function checks if the given operand needs to be moved and rewires the operand, if /// it must be moved. /// </remarks> protected Operand EmitConstant(Operand cop) { if (!cop.IsConstant) return cop; if (!(cop.StackType == StackTypeCode.F || cop.StackType == StackTypeCode.Int64)) return cop; int size, alignment; architecture.GetTypeRequirements(cop.Type, out size, out alignment); string name = String.Format("C_{0}", Guid.NewGuid()); using (Stream stream = methodCompiler.Linker.Allocate(name, SectionKind.ROData, size, alignment)) { using (BinaryWriter writer = new BinaryWriter(stream)) { switch (cop.Type.Type) { case CilElementType.R4: writer.Write((float)cop.Value); break; case CilElementType.R8: writer.Write((double)cop.Value); break; case CilElementType.I8: writer.Write((long)cop.Value); break; case CilElementType.U8: writer.Write((ulong)cop.Value); break; default: throw new NotSupportedException(); } } } // FIXME: Attach the label operand to the linker symbol // FIXME: Rename the operand to SymbolOperand // FIXME: Use the provided name to link return Operand.CreateLabel(cop.Type, name); }
/// <summary> /// Emits the given code. /// </summary> /// <param name="opCode">The op code.</param> /// <param name="dest">The destination operand.</param> /// <param name="src">The source operand.</param> public void Emit(OpCode opCode, Operand dest, Operand src) { // Write the opcode codeStream.Write(opCode.Code, 0, opCode.Code.Length); if (dest == null && src == null) return; byte? sib = null, modRM = null; Operand displacement = null; // Write the mod R/M byte modRM = CalculateModRM(opCode.RegField, dest, src, out sib, out displacement); if (modRM != null) { codeStream.WriteByte(modRM.Value); if (sib.HasValue) codeStream.WriteByte(sib.Value); } // Add displacement to the code if (displacement != null) WriteDisplacement(displacement); // Add immediate bytes if (dest.IsConstant) WriteImmediate(dest); else if (dest.IsSymbol) WriteDisplacement(dest); else if (src != null && src.IsConstant) WriteImmediate(src); else if (src != null && src.IsSymbol) WriteDisplacement(src); }
/// <summary> /// Computes the opcode. /// </summary> /// <param name="destination">The destination operand.</param> /// <param name="source">The source operand.</param> /// <param name="third">The third operand.</param> /// <returns></returns> protected override OpCode ComputeOpCode(Operand destination, Operand source, Operand third) { if (destination.IsCPURegister && third.IsConstant) return R_C; if (destination.IsCPURegister && third.IsCPURegister) return R_R; throw new ArgumentException(@"No opcode for operand type."); }
/// <summary> /// Computes the opcode. /// </summary> /// <param name="destination">The destination operand.</param> /// <param name="source">The source operand.</param> /// <param name="third">The third operand.</param> /// <returns></returns> protected override OpCode ComputeOpCode(Operand destination, Operand source, Operand third) { if (destination.IsRegister) return R_RM; if (destination.IsMemoryAddress) return RM_R; throw new ArgumentException(@"No opcode for operand type. [" + destination.GetType() + ", " + source.GetType() + ")"); }
/// <summary> /// Computes the opcode. /// </summary> /// <param name="destination">The destination operand.</param> /// <param name="source">The source operand.</param> /// <param name="third">The third operand.</param> /// <returns></returns> protected override OpCode ComputeOpCode(Operand destination, Operand source, Operand third) { if (third.IsConstant) return RM_C; else return RM_R; }
/// <summary> /// Computes the opcode. /// </summary> /// <param name="destination">The destination operand.</param> /// <param name="source">The source operand.</param> /// <param name="third">The third operand.</param> /// <returns></returns> protected override OpCode ComputeOpCode(Operand destination, Operand source, Operand third) { if (destination.Register is ControlRegister) return CR_R; if (source.Register is ControlRegister) return R_CR; throw new ArgumentException(@"No opcode for operand type. [" + destination + ", " + source + ")"); }
/// <summary> /// Computes the opcode. /// </summary> /// <param name="destination">The destination operand.</param> /// <param name="source">The source operand.</param> /// <param name="third">The third operand.</param> /// <returns></returns> protected override OpCode ComputeOpCode(Operand destination, Operand source, Operand third) { //if (source.Type.Type == CilElementType.R4) return DIVSS; return opcode; //return DIVSD; }
public static X86Instruction GetMove(Operand Destination, Operand Source) { if (Source.IsR8 && Destination.IsR8) { return X86.Movsd; } else if (Source.IsR4 && Destination.IsR4) { return X86.Movss; } else if (Source.IsR4 && Destination.IsR8) { return X86.Cvtss2sd; } else if (Source.IsR8 && Destination.IsR4) { return X86.Cvtsd2ss; } else if (Source.IsR8 && Destination.IsMemoryAddress) { return X86.Movsd; } else if (Source.IsR4 && Destination.IsMemoryAddress) { return X86.Movss; } else { return X86.Mov; } }
/// <summary> /// Initializes a new instance of the <see cref="BaseMethodCompiler" /> class. /// </summary> /// <param name="compiler">The assembly compiler.</param> /// <param name="method">The method to compile by this instance.</param> /// <param name="basicBlocks">The basic blocks.</param> /// <param name="threadID">The thread identifier.</param> protected BaseMethodCompiler(BaseCompiler compiler, MosaMethod method, BasicBlocks basicBlocks, int threadID) { Compiler = compiler; Method = method; Type = method.DeclaringType; Scheduler = compiler.CompilationScheduler; Architecture = compiler.Architecture; TypeSystem = compiler.TypeSystem; TypeLayout = compiler.TypeLayout; Trace = compiler.CompilerTrace; Linker = compiler.Linker; BasicBlocks = basicBlocks ?? new BasicBlocks(); Pipeline = new CompilerPipeline(); LocalStack = new List<Operand>(); ConstantZero = Operand.CreateConstant(TypeSystem, 0); StackFrame = Operand.CreateCPURegister(TypeSystem.BuiltIn.Pointer, Architecture.StackFrameRegister); Parameters = new Operand[method.Signature.Parameters.Count + (method.HasThis || method.HasExplicitThis ? 1 : 0)]; VirtualRegisters = new VirtualRegisters(Architecture); LocalVariables = emptyOperandList; ThreadID = threadID; DominanceAnalysis = new Dominance(Compiler.CompilerOptions.DominanceAnalysisFactory, BasicBlocks); PluggedMethod = compiler.PlugSystem.GetPlugMethod(Method); stop = false; MethodData = compiler.CompilerData.GetCompilerMethodData(Method); MethodData.Counters.Clear(); EvaluateParameterOperands(); }
public void Emit(OpcodeEncoder opcode, Operand symbolOperand, int symbolOffset) { int pos = (int)codeStream.Position + symbolOffset; Emit(opcode); if (symbolOperand.IsLabel) { linker.Link(LinkType.AbsoluteAddress, PatchType.I4, MethodName, SectionKind.Text, pos, 0, symbolOperand.Name, SectionKind.ROData, 0); } else if (symbolOperand.IsField) { var section = symbolOperand.Field.Data != null ? SectionKind.ROData : SectionKind.BSS; linker.Link(LinkType.AbsoluteAddress, PatchType.I4, MethodName, SectionKind.Text, pos, 0, symbolOperand.Field.FullName, section, (int)symbolOperand.Displacement); } else if (symbolOperand.IsSymbol) { var section = symbolOperand.Method != null ? SectionKind.Text : SectionKind.ROData; var symbol = linker.GetSymbol(symbolOperand.Name, section); if (symbol == null) { symbol = linker.FindSymbol(symbolOperand.Name); } linker.Link(LinkType.AbsoluteAddress, PatchType.I4, MethodName, SectionKind.Text, pos, 0, symbol, 0); } }
/// <summary> /// Computes the opcode. /// </summary> /// <param name="size">The size.</param> /// <param name="destination">The destination operand.</param> /// <param name="source">The source operand.</param> /// <returns></returns> /// <exception cref="System.ArgumentException">@No opcode for operand type. [ + destination + , + source + )</exception> private OpCode ComputeOpCode(InstructionSize size, Operand destination, Operand source) { Debug.Assert(destination.IsMemoryAddress); Debug.Assert(source.IsRegister || source.IsConstant || source.IsSymbol); size = BaseMethodCompilerStage.GetInstructionSize(size, destination); if (source.IsSymbol) return RM_C; if (source.IsConstant) { if (size == InstructionSize.Size8) return RM_C_U8; if (size == InstructionSize.Size16) return M_C_16; return RM_C; } if (source.IsRegister) { if (size == InstructionSize.Size8) return RM_R_U8; if (size == InstructionSize.Size16) return M_R_16; return M_R; } throw new ArgumentException(@"No opcode for operand type. [" + destination + ", " + source + ")"); }
/// <summary> /// Emits the given code. /// </summary> /// <param name="opCode">The op code.</param> /// <param name="dest">The destination operand.</param> /// <param name="src">The source operand.</param> public void Emit(OpCode opCode, Operand dest, Operand src) { // Write the opcode codeStream.Write(opCode.Code, 0, opCode.Code.Length); Debug.Assert(!(dest == null && src == null)); byte? modRM = null; // Write the mod R/M byte modRM = CalculateModRM(opCode.RegField, dest, src); if (modRM != null) { codeStream.WriteByte(modRM.Value); } // Add immediate bytes if (dest.IsConstant) WriteImmediate(dest); else if (dest.IsSymbol) WriteDisplacement(dest); else if (src != null && src.IsResolvedConstant) WriteImmediate(src); else if (src != null && (src.IsSymbol || src.IsStaticField)) WriteDisplacement(src); }
/// <summary> /// Computes the opcode. /// </summary> /// <param name="destination">The destination operand.</param> /// <param name="source">The source operand.</param> /// <param name="third">The third operand.</param> /// <returns></returns> protected override OpCode ComputeOpCode(Operand destination, Operand source, Operand third) { if (IsByte(destination)) return DEC8; if (IsShort(destination) || IsChar(destination)) return DEC16; if (IsInt(destination)) return DEC32; throw new ArgumentException(@"No opcode for operand type."); }
/// <summary> /// Computes the opcode. /// </summary> /// <param name="destination">The destination operand.</param> /// <param name="source">The source operand.</param> /// <param name="third">The third operand.</param> /// <returns></returns> protected override OpCode ComputeOpCode(Operand destination, Operand source, Operand third) { if (destination.IsByte) return INC8; if (destination.IsShort || destination.IsChar) return INC16; if (destination.IsInt) return INC32; throw new ArgumentException(@"No opcode for operand type."); }
/// <summary> /// Computes the opcode. /// </summary> /// <param name="destination">The destination operand.</param> /// <param name="source">The source operand.</param> /// <param name="third">The third operand.</param> /// <returns></returns> protected override OpCode ComputeOpCode(Operand destination, Operand source, Operand third) { if (destination.IsShort && source.IsShort && destination.IsRegister && source.IsRegister) return R_R_16; if (destination.IsRegister && source.IsMemoryAddress) return R_M; if (destination.IsRegister && source.IsRegister) return R_R; if (destination.IsMemoryAddress && source.IsRegister) return M_R; throw new ArgumentException(@"No opcode for operand type."); }
/// <summary> /// Computes the opcode. /// </summary> /// <param name="destination">The destination operand.</param> /// <param name="source">The source operand.</param> /// <param name="third">The third operand.</param> /// <returns></returns> protected override OpCode ComputeOpCode(Operand destination, Operand source, Operand third) { if (destination.IsRegister && destination.Register is SegmentRegister) return SR_R; if (source.IsRegister && source.Register is SegmentRegister) throw new ArgumentException(@"TODO: No opcode for move sourcee segment register"); if (destination.IsRegister && source.IsConstant) return RM_C; if (destination.IsMemoryAddress && source.IsConstant) { if (destination.IsByte || destination.IsBoolean) return RM_C_U8; if (destination.IsChar || destination.IsShort) return M_C_16; return RM_C; } if (destination.IsRegister && source.IsSymbol) return RM_C; if (destination.IsMemoryAddress && source.IsSymbol) return RM_C; if (destination.IsRegister && source.IsRegister) { Debug.Assert(!((source.IsByte || destination.IsByte) && (source.Register == GeneralPurposeRegister.ESI || source.Register == GeneralPurposeRegister.EDI)), source.ToString()); if (source.IsByte || destination.IsByte) return R_M_U8; if (source.IsChar || destination.IsChar || source.IsShort || destination.IsShort) return R_RM_16; return R_RM; } if (destination.IsRegister && source.IsMemoryAddress) { if (destination.IsByte) return R_M_U8; if (destination.IsChar || destination.IsShort) return R_RM_16; return R_RM; } if (destination.IsMemoryAddress && source.IsRegister) { if (destination.IsPointer && !source.IsPointer && destination.Type.ElementType != null) { if (destination.Type.ElementType.IsUI1 || destination.Type.ElementType.IsBoolean) return RM_R_U8; if (destination.Type.ElementType.IsChar || destination.Type.ElementType.IsUI2) return M_R_16; } if (destination.IsByte) return RM_R_U8; if (destination.IsChar || destination.IsShort) return M_R_16; return M_R; } if (destination.IsSymbol && source.IsRegister) { if (destination.IsByte || destination.IsBoolean) return RM_C_U8; if (destination.IsChar || destination.IsShort) return M_C_16; return RM_C; } throw new ArgumentException(@"No opcode for operand type. [" + destination + ", " + source + ")"); }
/// <summary> /// Computes the opcode. /// </summary> /// <param name="destination">The destination operand.</param> /// <param name="source">The source operand.</param> /// <param name="third">The third operand.</param> /// <returns></returns> protected override OpCode ComputeOpCode(Operand destination, Operand source, Operand third) { Debug.Assert(source.IsMemoryAddress); if (source.IsR4) return m32fp; else return m64fp; }
public override void GetStackRequirements(MosaTypeLayout typeLayout, Operand 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(typeLayout, stackOperand.Type, out size, out alignment); if (size < alignment) size = alignment; }
public static OpcodeEncoder AppendConditionalDisplacement(this OpcodeEncoder encoder, Operand displacement, bool include) { if (!include) return encoder; if (Is8BitDisplacement(displacement)) return encoder.AppendByteValue((byte)displacement.ConstantUnsignedInteger); return encoder.AppendIntegerValue(displacement.ConstantUnsignedInteger); }
protected override void Setup() { base.Setup(); ConstantZero = Operand.CreateConstant(MethodCompiler.TypeSystem, 0); visitationDictionary = new Dictionary<BaseInstruction, VisitationDelegate>(); PopulateVisitationDictionary(); }
public static OpcodeEncoder AppendInteger(this OpcodeEncoder encoder, Operand operand, InstructionSize size) { if (size == InstructionSize.Size32) return encoder.AppendIntegerValue(operand.ConstantUnsignedInteger); if (size == InstructionSize.Size8) return encoder.AppendByteValue((byte)operand.ConstantUnsignedInteger); if (size == InstructionSize.Size16) return encoder.AppendShortValue((ushort)operand.ConstantUnsignedInteger); throw new InvalidCompilerException("Instruction size invalid"); }
/// <summary> /// Computes the opcode. /// </summary> /// <param name="destination">The destination operand.</param> /// <param name="source">The source operand.</param> /// <param name="third">The third operand.</param> /// <returns></returns> protected override OpCode ComputeOpCode(Operand destination, Operand source, Operand third) { if ((destination.IsRegister) || (destination.IsMemoryAddress)) { if (IsByte(destination)) return MR_8; if (IsChar(destination)) return MR_16; return MR; } throw new ArgumentException(@"No opcode for operand type."); }
/// <summary> /// Computes the opcode. /// </summary> /// <param name="destination">The destination operand.</param> /// <param name="source">The source operand.</param> /// <param name="third">The third operand.</param> /// <returns></returns> protected override OpCode ComputeOpCode(Operand destination, Operand source, Operand third) { if (destination.IsCPURegister) { if (destination.IsByte) return MR_8; if (destination.IsChar) return MR_16; return MR; } throw new ArgumentException(@"No opcode for operand type."); }
/// <summary> /// Calls the specified target. /// </summary> /// <param name="symbolOperand">The symbol operand.</param> public void Call(Operand symbolOperand) { linker.Link( LinkType.RelativeOffset | LinkType.NativeI4, compiler.Method.ToString(), (int)(codeStream.Position - codeStreamBasePosition), (int)(codeStream.Position - codeStreamBasePosition) + 4, symbolOperand.Name, IntPtr.Zero ); codeStream.Position += 4; }
/// <summary> /// Computes the opcode. /// </summary> /// <param name="destination">The destination operand.</param> /// <param name="source">The source operand.</param> /// <param name="third">The third operand.</param> /// <returns></returns> protected override OpCode ComputeOpCode(Operand destination, Operand source, Operand third) { if (third.IsConstant) return O_C; if (destination.IsRegister) { if (third.IsChar) return R_O_16; else return R_O; } if ((destination.IsMemoryAddress) && (third.IsRegister)) return M_R; throw new ArgumentException(@"No opcode for operand type."); }
/// <summary> /// Computes the opcode. /// </summary> /// <param name="destination">The destination operand.</param> /// <param name="source">The source operand.</param> /// <param name="third">The third operand.</param> /// <returns></returns> protected override OpCode ComputeOpCode(Operand destination, Operand source, Operand third) { if (destination.IsRegister) { if (source.IsMemoryAddress) return R_M; if (source.IsRegister) return R_R; if (source.IsConstant) return R_C; } else if (destination.IsMemoryAddress) { if (source.IsRegister) return M_R; if (source.IsConstant) return M_C; } throw new ArgumentException(@"No opcode for operand type."); }