/// <summary> /// Replaces the intrinsic call site /// </summary> /// <param name="context">The context.</param> /// <param name="typeSystem">The type system.</param> void IIntrinsicPlatformMethod.ReplaceIntrinsicCall(Context context, ITypeSystem typeSystem, IList<RuntimeParameter> parameters) { var result = context.Result; var op1 = context.Operand1; var op2 = context.Operand2; var constant = Operand.CreateConstant(BuiltInSigType.IntPtr, parameters.Count * 4); var eax = Operand.CreateCPURegister(BuiltInSigType.IntPtr, GeneralPurposeRegister.EAX); // FIXME - need access to virtual register allocator var edx = Operand.CreateCPURegister(BuiltInSigType.IntPtr, GeneralPurposeRegister.EDX); // FIXME - need access to virtual register allocator var esp = Operand.CreateCPURegister(BuiltInSigType.IntPtr, GeneralPurposeRegister.ESP); // FIXME - need access to virtual register allocator var ebp = Operand.CreateCPURegister(BuiltInSigType.IntPtr, GeneralPurposeRegister.EBP); // FIXME - need access to virtual register allocator context.SetInstruction(X86.Sub, esp, constant); context.AppendInstruction(X86.Mov, edx, esp); var size = parameters.Count * 4 + 4; foreach (var parameter in parameters) { context.AppendInstruction(X86.Mov, Operand.CreateMemoryAddress(BuiltInSigType.IntPtr, edx, new IntPtr(size - 4)), Operand.CreateMemoryAddress(BuiltInSigType.IntPtr, ebp, new IntPtr(size + 4))); size -= 4; } context.AppendInstruction(X86.Mov, Operand.CreateMemoryAddress(BuiltInSigType.IntPtr, edx, new IntPtr(size - 4)), op1); context.AppendInstruction(X86.Mov, eax, op2); context.AppendInstruction(X86.Call, null, eax); context.AppendInstruction(X86.Add, esp, constant); context.AppendInstruction(X86.Mov, result, Operand.CreateCPURegister(result.Type, GeneralPurposeRegister.EAX)); // FIXME - need access to virtual register allocator }
/// <summary> /// Folds the instruction. /// </summary> /// <param name="context">The context.</param> private void FoldInstruction(Context context) { if (context.Instruction is AddSInstruction) this.FoldAddSInstruction(context); else if (context.Instruction is MulSInstruction) this.FoldMulSInstruction(context); }
/// <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) { // TODO: Remove if (context.Operand1 is MemberOperand) return; if (context.Result is RegisterOperand && context.Operand1 is MemoryOperand) { RegisterOperand result = context.Result as RegisterOperand; MemoryOperand operand = context.Operand1 as MemoryOperand; int displacement = operand.Offset.ToInt32(); if (IsBetween(displacement, 0, 7)) { emitter.EmitTwoRegisterInstructions((byte)(0x0C & displacement), (byte)operand.Base.RegisterCode, (byte)result.Register.RegisterCode); } else if (IsBetween(displacement, -32768, 32767)) { emitter.EmitTwoRegistersAndK16(0x13, (byte)operand.Base.RegisterCode, (byte)result.Register.RegisterCode, (short)displacement); } else throw new OverflowException(); } else throw new Exception("Not supported combination of operands"); }
/// <summary> /// Emits the constant operands. /// </summary> /// <param name="node">The node.</param> protected void EmitFloatingPointConstants(InstructionNode node) { for (int i = 0; i < node.OperandCount; i++) { var operand = node.GetOperand(i); if (operand == null || !operand.IsConstant || !operand.IsR) continue; if (operand.IsUnresolvedConstant) continue; var v1 = AllocateVirtualRegister(operand.Type); var symbol = (operand.IsR4) ? MethodCompiler.Linker.GetConstantSymbol(operand.ConstantSingleFloatingPoint) : MethodCompiler.Linker.GetConstantSymbol(operand.ConstantDoubleFloatingPoint); var s1 = Operand.CreateLabel(operand.Type, symbol.Name); var before = new Context(node).InsertBefore(); if (operand.IsR4) { before.SetInstruction(X86.MovssLoad, InstructionSize.Size32, v1, s1, ConstantZero); } else { before.SetInstruction(X86.MovsdLoad, InstructionSize.Size64, v1, s1, ConstantZero); } node.SetOperand(i, v1); } }
/// <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) { Debug.Assert(context.Result == null); OpCode opCode = ComputeOpCode(null, context.Operand1, context.Operand2); emitter.Emit(opCode, context.Operand1, context.Operand2); }
/// <summary> /// Runs the specified method compiler. /// </summary> void IMethodCompilerStage.Run() { if (methodCompiler.PlugSystem != null) if (methodCompiler.PlugSystem.GetPlugMethod(this.methodCompiler.Method) != null) return; List<StackOperand> locals = CollectLocalVariablesFromIL(); // Iterate and collect locals from all blocks foreach (BasicBlock block in basicBlocks) { CollectLocalVariables(locals, block); } // Sort all found locals OrderVariables(locals, callingConvention); // Now we assign increasing stack offsets to each variable localsSize = LayoutVariables(locals, callingConvention, callingConvention.OffsetOfFirstLocal, 1); // Layout parameters LayoutParameters(methodCompiler); // Create a prologue instruction Context prologueCtx = new Context(instructionSet, FindBlock(-1)).InsertBefore(); prologueCtx.SetInstruction(IR.Instruction.PrologueInstruction); prologueCtx.Label = -1; // Create an epilogue instruction Context epilogueCtx = new Context(instructionSet, FindBlock(Int32.MaxValue)); epilogueCtx.AppendInstruction(IR.Instruction.EpilogueInstruction); epilogueCtx.Label = Int32.MaxValue; }
/// <summary> /// Creates the ISR methods. /// </summary> private void CreateExceptionVector() { RuntimeType runtimeType = typeSystem.GetType(@"Mosa.Kernel.x86.IDT"); if (runtimeType == null) return; RuntimeMethod runtimeMethod = runtimeType.FindMethod(@"ExceptionHandler"); if (runtimeMethod == null) return; SymbolOperand exceptionMethod = SymbolOperand.FromMethod(runtimeMethod); RegisterOperand esp = new RegisterOperand(BuiltInSigType.Int32, GeneralPurposeRegister.ESP); InstructionSet instructionSet = new InstructionSet(100); Context ctx = new Context(instructionSet); // TODO - setup stack for call to the managed exception handler //1. //2. //3. Call the managed exception handler ctx.AppendInstruction(Instruction.CallInstruction, null, exceptionMethod); LinkTimeCodeGenerator.Compile(this.compiler, @"ExceptionVector", instructionSet, typeSystem); }
/// <summary> /// Replaces the intrinsic call site /// </summary> /// <param name="context">The context.</param> /// <param name="typeSystem">The type system.</param> void IIntrinsicPlatformMethod.ReplaceIntrinsicCall(Context context, BaseMethodCompiler methodCompiler) { var zero = Operand.CreateConstant(methodCompiler.TypeSystem.BuiltIn.I4, 0); var MultibootEAX = Operand.CreateUnmanagedSymbolPointer(methodCompiler.TypeSystem, Multiboot0695Stage.MultibootEAX); context.SetInstruction(IRInstruction.Load2, context.Result, MultibootEAX, zero); }
/// <summary> /// Visitation function for <see cref="IX86Visitor.Call"/> instructions. /// </summary> /// <param name="context">The context.</param> public override void Call(Context context) { if (context.Operand1 == null) return; if (!context.Operand1.IsCPURegister) return; var before = context.Previous; while (before.IsEmpty && !before.IsBlockStartInstruction) { before = before.Previous; } if (before == null || before.IsBlockStartInstruction) return; if (!before.Result.IsCPURegister) return; if (context.Operand1.Register != before.Result.Register) return; before.SetInstruction(X86.Call, null, before.Operand1); context.Empty(); }
/// <summary> /// Replaces the intrinsic call site /// </summary> /// <param name="context">The context.</param> /// <param name="typeSystem">The type system.</param> void IIntrinsicPlatformMethod.ReplaceIntrinsicCall(Context context, BaseMethodCompiler methodCompiler) { Debug.Assert(context.Result.IsI4 | context.Result.IsU4); Operand zero = Operand.CreateConstant(methodCompiler.TypeSystem, 0); context.SetInstruction(X86.MovzxLoad, InstructionSize.Size16, context.Result, context.Operand1, zero); }
/// <summary> /// Visitation function for AddFloat. /// </summary> /// <param name="context">The context.</param> void IIRVisitor.AddFloat(Context context) { if (context.Result.IsR4) ReplaceInstructionAndAnyFloatingPointConstant(context, X86.Addss); else ReplaceInstructionAndAnyFloatingPointConstant(context, X86.Addsd); }
/// <summary> /// Replaces the intrinsic call site /// </summary> /// <param name="context">The context.</param> /// <param name="typeSystem">The type system.</param> void IIntrinsicPlatformMethod.ReplaceIntrinsicCall(Context context, BaseMethodCompiler methodCompiler) { Operand methodAddress = context.Operand1; Operand newESP = context.Operand2; context.SetInstruction(X86.Call, null, methodAddress); }
/// <summary> /// Visitation function for <see cref="IX86Visitor.Call"/> instructions. /// </summary> /// <param name="context">The context.</param> void IX86Visitor.Call(Context context) { if (context.Operand1 == null) return; if (!context.Operand1.IsCPURegister) return; var before = context.Previous; while (before.IsEmpty && !before.IsBlockStartInstruction) { before = before.Previous; } if (before == null || before.IsBlockStartInstruction) return; if (!before.Result.IsCPURegister) return; if (context.Operand1.Register != before.Result.Register) return; before.SetInstruction(X86.Call, null, before.Operand1); context.Delete(false); }
/// <summary> /// Replaces the intrinsic call site /// </summary> /// <param name="context">The context.</param> /// <param name="typeSystem">The type system.</param> void IIntrinsicPlatformMethod.ReplaceIntrinsicCall(Context context, BaseMethodCompiler methodCompiler) { var result = context.Result; var dividend = context.Operand1; var divisor = context.Operand2; if (result.IsR8) { var xmm1 = methodCompiler.CreateVirtualRegister(methodCompiler.TypeSystem.BuiltIn.R8); var xmm2 = methodCompiler.CreateVirtualRegister(methodCompiler.TypeSystem.BuiltIn.R8); var xmm3 = methodCompiler.CreateVirtualRegister(methodCompiler.TypeSystem.BuiltIn.R8); var size = InstructionSize.Size64; context.SetInstruction(X86.Divsd, size, xmm1, dividend, divisor); context.AppendInstruction(X86.Roundsd, size, xmm2, xmm1, Operand.CreateConstant(methodCompiler.TypeSystem.BuiltIn.U1, 0x3)); context.AppendInstruction(X86.Mulsd, size, xmm3, divisor, xmm2); context.AppendInstruction(X86.Subsd, size, result, dividend, xmm3); } else { var xmm1 = methodCompiler.CreateVirtualRegister(methodCompiler.TypeSystem.BuiltIn.R4); var xmm2 = methodCompiler.CreateVirtualRegister(methodCompiler.TypeSystem.BuiltIn.R4); var xmm3 = methodCompiler.CreateVirtualRegister(methodCompiler.TypeSystem.BuiltIn.R4); var size = InstructionSize.Size32; context.SetInstruction(X86.Divss, size, xmm1, dividend, divisor); context.AppendInstruction(X86.Roundss, size, xmm2, xmm1, Operand.CreateConstant(methodCompiler.TypeSystem.BuiltIn.U1, 0x3)); context.AppendInstruction(X86.Mulss, size, xmm3, divisor, xmm2); context.AppendInstruction(X86.Subss, size, result, dividend, xmm3); } }
/// <summary> /// Folds the mul S instruction. /// </summary> /// <param name="context">The context.</param> private void FoldMulSInstruction(Context context) { var cA = this.LoadSignedInteger(context.Operand1); var cB = this.LoadSignedInteger(context.Operand2); context.SetInstruction(Instruction.MoveInstruction, context.Result, new ConstantOperand(context.Result.Type, cA * cB)); }
/// <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) { if (context.OperandCount == 0) { // TODO: //emitter.EmitBranch(LabelCall, context.BranchTargets[0]); return; } Operand destinationOperand = context.Operand1; SymbolOperand destinationSymbol = destinationOperand as SymbolOperand; if (destinationSymbol != null) { emitter.Call(destinationSymbol); } else { if (destinationOperand is MemoryOperand) { //RegisterOperand register = destinationOperand as RegisterOperand; //emitter.EmitSingleRegisterInstructions(0x11, (byte)register.Register.RegisterCode); MemoryOperand memory = destinationOperand as MemoryOperand; emitter.EmitRegisterOperandWithK16(0x101, (byte)memory.Base.RegisterCode, (ushort)memory.Offset); } } }
/// <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) { if (context.Result is RegisterOperand && context.Operand1 is ConstantOperand) { RegisterOperand reg = context.Result as RegisterOperand; ConstantOperand op = context.Operand1 as ConstantOperand; int value = 0; if (IsConstantBetween(op, -128, 127, out value)) { emitter.EmitK8immediateAndSingleRegister(0x01, (sbyte)value, (byte)reg.Register.RegisterCode); // mov Rd, Imm (k8) } else if (IsConstantBetween(op, -1048576, 1048575, out value)) { emitter.EmitRegisterOrConditionCodeAndK21(0x03, (byte)reg.Register.RegisterCode, value); // mov Rd, Imm (k21) } else throw new OverflowException(); } else if ((context.Result is RegisterOperand) && (context.Operand1 is RegisterOperand)) { RegisterOperand destination = context.Result as RegisterOperand; RegisterOperand source = context.Operand1 as RegisterOperand; emitter.EmitTwoRegisterInstructions(0x09, (byte)source.Register.RegisterCode, (byte)destination.Register.RegisterCode); // mov Rd, Rs } //else //throw new Exception("Not supported combination of operands"); }
/// <summary> /// Replaces the intrinsic call site /// </summary> /// <param name="context">The context.</param> /// <param name="typeSystem">The type system.</param> void IIntrinsicPlatformMethod.ReplaceIntrinsicCall(Context context, BaseMethodCompiler methodCompiler) { var operand = context.Operand1; if (!operand.IsConstant) { // try to find the constant - a bit of a hack Context ctx = new Context(operand.Definitions[0]); if (ctx.Instruction == IRInstruction.Move && ctx.Operand1.IsConstant) { operand = ctx.Operand1; } } Debug.Assert(operand.IsConstant); int irq = (int)operand.ConstantSignedLongInteger; // Find the method var method = methodCompiler.TypeSystem.DefaultLinkerType.FindMethodByName("InterruptISR" + irq.ToString()); if (method == null) { throw new InvalidCompilerException(); } context.SetInstruction(IRInstruction.Move, context.Result, Operand.CreateSymbolFromMethod(methodCompiler.TypeSystem, method)); }
/// <summary> /// Visitation function for <see cref="IX86Visitor.Cmp"/> instructions. /// </summary> /// <param name="context">The context.</param> public override void Cmp(Context context) { Operand left = context.Operand1; Operand right = context.Operand2; if (left.IsConstant) { Operand ecx = AllocateVirtualRegister(left.Type); Context before = context.InsertBefore(); before.AppendInstruction(X86.Mov, ecx, left); context.Operand1 = ecx; } if (right.IsConstant && (left.IsChar || left.IsShort || left.IsByte)) { Operand edx = AllocateVirtualRegister(TypeSystem.BuiltIn.I4); Context before = context.InsertBefore(); if (left.IsSigned) { before.AppendInstruction(X86.Movsx, edx, left); } else { before.AppendInstruction(X86.Movzx, edx, left); } context.Operand1 = edx; } }
/// <summary> /// Replaces the intrinsic call site /// </summary> /// <param name="context">The context.</param> /// <param name="typeSystem">The type system.</param> void IIntrinsicPlatformMethod.ReplaceIntrinsicCall(Context context, ITypeSystem typeSystem, IList<RuntimeParameter> parameters) { // Retrieve register context //context.SetInstruction(CPUx86.Instruction.MovInstruction, new RegisterOperand(BuiltInSigType.UInt32, GeneralPurposeRegister.EAX), Operand.CreateMemoryAddress(BuiltInSigType.UInt32, GeneralPurposeRegister.ESP, new IntPtr(28))); // Restore registers (Note: EAX and EDX are NOT restored!) //context.AppendInstruction(CPUx86.Instruction.MovInstruction, new RegisterOperand(BuiltInSigType.UInt32, GeneralPurposeRegister.EDX), Operand.CreateMemoryAddress(BuiltInSigType.UInt32, GeneralPurposeRegister.EAX, new IntPtr(28))); //context.AppendInstruction(CPUx86.Instruction.MovInstruction, new RegisterOperand(BuiltInSigType.UInt32, GeneralPurposeRegister.EBX), Operand.CreateMemoryAddress(BuiltInSigType.UInt32, GeneralPurposeRegister.EAX, new IntPtr(4))); //context.AppendInstruction(CPUx86.Instruction.MovInstruction, new RegisterOperand(BuiltInSigType.UInt32, GeneralPurposeRegister.EDI), Operand.CreateMemoryAddress(BuiltInSigType.UInt32, GeneralPurposeRegister.EAX, new IntPtr(20))); //context.AppendInstruction(CPUx86.Instruction.MovInstruction, new RegisterOperand(BuiltInSigType.UInt32, GeneralPurposeRegister.ESI), Operand.CreateMemoryAddress(BuiltInSigType.UInt32, GeneralPurposeRegister.EAX, new IntPtr(16))); //context.AppendInstruction(CPUx86.Instruction.MovInstruction, new RegisterOperand(BuiltInSigType.UInt32, GeneralPurposeRegister.ESP), Operand.CreateMemoryAddress(BuiltInSigType.UInt32, GeneralPurposeRegister.EAX, new IntPtr(32))); //context.AppendInstruction(CPUx86.Instruction.MovInstruction, new RegisterOperand(BuiltInSigType.UInt32, GeneralPurposeRegister.EBP), Operand.CreateMemoryAddress(BuiltInSigType.UInt32, GeneralPurposeRegister.EAX, new IntPtr(24))); //uint ebp, uint esp, int eip Operand edx = Operand.CreateCPURegister(BuiltInSigType.UInt32, GeneralPurposeRegister.EDX); Operand ebp = Operand.CreateCPURegister(BuiltInSigType.UInt32, GeneralPurposeRegister.EBP); Operand esp = Operand.CreateCPURegister(BuiltInSigType.UInt32, GeneralPurposeRegister.ESP); // Restore registers context.SetInstruction(X86.Mov, Operand.CreateCPURegister(BuiltInSigType.UInt32, GeneralPurposeRegister.ESP), context.Operand1); // Jmp to EIP (stored in EDX) context.AppendInstruction(X86.Jmp, null, edx); //context.SetOperand(0, edx); }
/// <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) { if (context.Result is RegisterOperand && context.Operand1 is RegisterOperand && context.Operand2 is RegisterOperand) { RegisterOperand destination = context.Result as RegisterOperand; RegisterOperand firstSource = context.Operand1 as RegisterOperand; RegisterOperand secondSource = context.Operand2 as RegisterOperand; emitter.EmitThreeRegistersUnshifted(0x24, (byte)firstSource.Register.RegisterCode, (byte)secondSource.Register.RegisterCode, (byte)destination.Register.RegisterCode); } else if (context.Result is RegisterOperand && context.Operand1 is RegisterOperand && context.Operand2 is ConstantOperand) { RegisterOperand destination = context.Result as RegisterOperand; RegisterOperand source = context.Operand1 as RegisterOperand; ConstantOperand immediate = context.Operand2 as ConstantOperand; int value = 0; if (IsConstantBetween(immediate, -128, 127, out value)) { emitter.EmitTwoRegisterOperandsWithK8Immediate(0x00, (byte)source.Register.RegisterCode, (byte)destination.Register.RegisterCode, (sbyte)value); } else throw new OverflowException(); } else if (context.Result is RegisterOperand && context.Operand1 is RegisterOperand) { RegisterOperand destination = context.Result as RegisterOperand; RegisterOperand source = context.Operand1 as RegisterOperand; emitter.EmitTwoRegisterInstructions(0x13, (byte)source.Register.RegisterCode, (byte)destination.Register.RegisterCode); } else { throw new Exception("Not supported combination of operands"); } }
/// <summary> /// Replaces the intrinsic call site /// </summary> /// <param name="context">The context.</param> /// <param name="typeSystem">The type system.</param> void IIntrinsicPlatformMethod.ReplaceIntrinsicCall(Context context, BaseMethodCompiler methodCompiler) { var result = context.Result; var address = methodCompiler.CreateVirtualRegister(methodCompiler.TypeSystem.BuiltIn.I4); context.SetInstruction(IRInstruction.Move, address, Operand.CreateUnmanagedSymbolPointer(methodCompiler.TypeSystem, Multiboot0695Stage.MultibootEBX)); context.AppendInstruction(IRInstruction.Move, result, Operand.CreateMemoryAddress(methodCompiler.TypeSystem.BuiltIn.I4, address, 0)); }
/// <summary> /// Replaces the intrinsic call site /// </summary> /// <param name="context">The context.</param> /// <param name="typeSystem">The type system.</param> void IIntrinsicMethod.ReplaceIntrinsicCall(Context context, ITypeSystem typeSystem, IList<RuntimeParameter> parameters) { var result = context.Result; //var op1 = context.Operand1; var op2 = context.Operand2; var eax = new RegisterOperand(BuiltInSigType.IntPtr, GeneralPurposeRegister.EAX); var edx = new RegisterOperand(BuiltInSigType.IntPtr, GeneralPurposeRegister.EDX); var esp = new RegisterOperand(BuiltInSigType.IntPtr, GeneralPurposeRegister.ESP); var ebp = new RegisterOperand(BuiltInSigType.IntPtr, GeneralPurposeRegister.EBP); context.SetInstruction(X86.Sub, esp, new ConstantOperand(BuiltInSigType.IntPtr, parameters.Count * 4)); context.AppendInstruction(X86.Mov, edx, esp); var size = parameters.Count * 4; foreach (var parameter in parameters) { context.AppendInstruction(X86.Mov, new MemoryOperand(BuiltInSigType.IntPtr, edx.Register, new IntPtr(size - 4)), new MemoryOperand(BuiltInSigType.IntPtr, ebp.Register, new IntPtr(size + 8))); size -= 4; } context.AppendInstruction(X86.Mov, eax, op2); context.AppendInstruction(X86.Call, null, new RegisterOperand(BuiltInSigType.IntPtr, GeneralPurposeRegister.EAX)); context.AppendInstruction(X86.Add, esp, new ConstantOperand(BuiltInSigType.IntPtr, parameters.Count * 4)); context.AppendInstruction(X86.Mov,result, new RegisterOperand(result.Type, GeneralPurposeRegister.EAX)); }
/// <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) { if (context.Result.IsRegister && context.Operand1.IsRegister && context.Operand2.IsRegister) { emitter.EmitThreeRegistersUnshifted(0x24, (byte)context.Operand1.Register.RegisterCode, (byte)context.Operand2.Register.RegisterCode, (byte)context.Result.Register.RegisterCode); } else if (context.Result.IsRegister && context.Operand1.IsRegister && context.Operand2.IsConstant) { int value = 0; if (IsConstantBetween(context.Operand2, -128, 127, out value)) { emitter.EmitTwoRegisterOperandsWithK8Immediate(0x00, (byte)context.Operand1.Register.RegisterCode, (byte)context.Result.Register.RegisterCode, (sbyte)value); } else throw new OverflowException(); } else if (context.Result.IsRegister && context.Operand1.IsRegister) { emitter.EmitTwoRegisterInstructions(0x13, (byte)context.Operand1.Register.RegisterCode, (byte)context.Result.Register.RegisterCode); } else { throw new Exception("Not supported combination of operands"); } }
/// <summary> /// Visitation function for <see cref="IX86Visitor.Cmp"/> instructions. /// </summary> /// <param name="context">The context.</param> public void Cmp(Context context) { Operand left = context.Operand1; Operand right = context.Operand2; if (left.IsConstant) { Operand v1 = AllocateVirtualRegister(left.Type); Context before = context.InsertBefore(); before.AppendInstruction(X86.Mov, v1, left); context.Operand1 = v1; } if (right.IsConstant && (left.IsChar || left.IsShort || left.IsByte)) { Operand v2 = AllocateVirtualRegister(TypeSystem.BuiltIn.I4); InstructionSize size = left.IsByte ? InstructionSize.Size8 : InstructionSize.Size16; if (left.IsSigned) { context.InsertBefore().AppendInstruction(X86.Movsx, size, v2, left); } else { context.InsertBefore().AppendInstruction(X86.Movzx, size, v2, left); } context.Operand1 = v2; } }
/// <summary> /// Converts the operand1 to constant. /// </summary> /// <param name="context">The context.</param> internal static void FoldOperand1ToConstant(Context context) { var operand1 = context.Operand1; if (operand1.IsConstant) return; while (!operand1.IsConstant) { if (operand1.Definitions.Count != 1) break; var node = operand1.Definitions[0]; if ((node.Instruction == X86.Mov || node.Instruction == IRInstruction.MoveInteger) && node.Operand1.IsConstant) { operand1 = node.Operand1; continue; } break; } Debug.Assert(operand1.IsConstant); // only constants are supported context.Operand1 = operand1; }
/// <summary> /// Creates the interrupt service routine (ISR) methods. /// </summary> private void CreateInterruptVectors() { RuntimeType runtimeType = typeSystem.GetType(@"Mosa.Kernel.x86.IDT"); if (runtimeType == null) return; RuntimeMethod runtimeMethod = runtimeType.FindMethod(@"ProcessInterrupt"); if (runtimeMethod == null) return; Operand interruptMethod = Operand.CreateSymbolFromMethod(runtimeMethod); Operand esp = Operand.CreateCPURegister(BuiltInSigType.Int32, GeneralPurposeRegister.ESP); for (int i = 0; i <= 255; i++) { InstructionSet instructionSet = new InstructionSet(100); Context ctx = new Context(instructionSet); ctx.AppendInstruction(X86.Cli); if (i <= 7 || i >= 16 | i == 9) // For IRQ 8, 10, 11, 12, 13, 14 the cpu will automatically pushed the error code ctx.AppendInstruction(X86.Push, null, Operand.CreateConstant(BuiltInSigType.SByte, 0x0)); ctx.AppendInstruction(X86.Push, null, Operand.CreateConstant(BuiltInSigType.SByte, (byte)i)); ctx.AppendInstruction(X86.Pushad); ctx.AppendInstruction(X86.Call, null, interruptMethod); ctx.AppendInstruction(X86.Popad); ctx.AppendInstruction(X86.Add, esp, Operand.CreateConstant(BuiltInSigType.Int32, 0x08)); ctx.AppendInstruction(X86.Sti); ctx.AppendInstruction(X86.IRetd); LinkTimeCodeGenerator.Compile(this.compiler, @"InterruptISR" + i.ToString(), instructionSet, typeSystem); } }
/// <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) { if (context.Result.IsRegister && context.Operand1.IsRegister) { emitter.EmitTwoRegisterInstructions(0x03, (byte)context.Operand1.Register.RegisterCode, (byte)context.Result.Register.RegisterCode); // cp.w Rd, Rs } else if (context.Result.IsRegister && context.Operand1.IsConstant) { int value = 0; if (IsConstantBetween(context.Operand1, -32, 31, out value)) { emitter.EmitK6immediateAndSingleRegister((sbyte)value, (byte)context.Result.Register.RegisterCode); // cp.w Rd, imm 6 bits } else if (IsConstantBetween(context.Operand1, -1048576, 1048575, out value)) { emitter.EmitRegisterOrConditionCodeAndK21((byte)0x02, (byte)context.Result.Register.RegisterCode, value); // cp.w Rd, imm 21 bits } else throw new OverflowException(); } else throw new Exception("Not supported combination of operands"); }
/// <summary> /// Visitation function for <see cref="IX86Visitor.Div"/> instructions. /// </summary> /// <param name="context">The context.</param> public void Div(Context context) { if (context.Result.IsCPURegister && context.Result2.IsCPURegister && context.Operand1.IsCPURegister) if (context.Result.Register == GeneralPurposeRegister.EDX && context.Result2.Register == GeneralPurposeRegister.EAX && context.Operand1.Register == GeneralPurposeRegister.EDX && context.Operand2.Register == GeneralPurposeRegister.EAX) return; Operand operand1 = context.Operand1; Operand operand2 = context.Operand2; Operand operand3 = context.Operand3; Operand result = context.Result; Operand result2 = context.Result2; Operand EAX = Operand.CreateCPURegister(TypeSystem.BuiltIn.I4, GeneralPurposeRegister.EAX); Operand EDX = Operand.CreateCPURegister(TypeSystem.BuiltIn.I4, GeneralPurposeRegister.EDX); context.SetInstruction(X86.Mov, EDX, operand1); context.AppendInstruction(X86.Mov, EAX, operand2); if (operand3.IsCPURegister) { context.AppendInstruction2(X86.Div, EDX, EAX, EDX, EAX, operand3); } else { Operand v3 = AllocateVirtualRegister(TypeSystem.BuiltIn.I4); context.AppendInstruction(X86.Mov, v3, operand3); context.AppendInstruction2(X86.Div, EDX, EAX, EDX, EAX, v3); } context.AppendInstruction(X86.Mov, result2, EAX); context.AppendInstruction(X86.Mov, result, EDX); }
/// <summary> /// Visitation function for <see cref="IX86Visitor.Mov"/> instructions. /// </summary> /// <param name="context">The context.</param> public void Mov(Context context) { if (context.Result.IsCPURegister && context.Operand1.IsCPURegister && context.Result.Register == context.Operand1.Register) { context.Empty(); return; } // Mov can not use ESI or EDI registers with 8 or 16 bit memory or register if (context.Operand1.IsCPURegister && (context.Result.IsMemoryAddress || context.Result.IsCPURegister) && (context.Result.IsByte || context.Result.IsShort || context.Result.IsChar || context.Result.IsBoolean) && (context.Operand1.Register == GeneralPurposeRegister.ESI || context.Operand1.Register == GeneralPurposeRegister.EDI)) { Operand source = context.Operand1; Operand dest = context.Result; var replace = (dest.IsMemoryAddress && dest.EffectiveOffsetBase == GeneralPurposeRegister.EAX) ? GeneralPurposeRegister.EBX : GeneralPurposeRegister.EAX; Operand reg = Operand.CreateCPURegister(TypeSystem.BuiltIn.I4, replace); context.SetInstruction2(X86.Xchg, reg, source, source, reg); context.AppendInstruction(X86.Mov, dest, reg); context.AppendInstruction2(X86.Xchg, source, reg, reg, source); } }