package org.jnode.vm.x86.compiler.l2; import org.jnode.assembler.Label; import org.jnode.assembler.x86.X86Assembler; import org.jnode.assembler.x86.X86Constants; import org.jnode.assembler.x86.X86Register; import org.jnode.assembler.x86.X86Register.GPR; import org.jnode.vm.compiler.ir.AddressingMode; import org.jnode.vm.compiler.ir.DoubleConstant; import org.jnode.vm.compiler.ir.FloatConstant; import org.jnode.vm.compiler.ir.Operand; import org.jnode.vm.compiler.ir.RegisterLocation; import org.jnode.vm.compiler.ir.StackLocation; import org.jnode.vm.compiler.ir.Variable; import org.jnode.vm.compiler.ir.quad.BinaryOperation; import org.jnode.vm.compiler.ir.quad.BinaryQuad; /** * User: lsantha * Date: 3/13/15 10:51 PM */ public class FPX86CodeGenerator<T> { protected X86Assembler os; GenericX86CodeGenerator context; public FPX86CodeGenerator(X86Assembler x86Stream, GenericX86CodeGenerator context) { os = x86Stream; this.context = context; } public void generateBinaryOP(BinaryQuad<T> quad) { context.checkLabel(quad.getAddress()); Variable lsh = quad.getLHS(); Operand op1 = quad.getOperand1(); Operand op2 = quad.getOperand2(); BinaryOperation operation = quad.getOperation(); switch (operation) { case FCMPG: loadToFPUStack32(op1, os, context); loadToFPUStack32(op2, os, context); floatCompare(true, lsh, context.getInstrLabel(quad.getAddress())); break; case FCMPL: loadToFPUStack32(op2, os, context); loadToFPUStack32(op1, os, context); floatCompare(false, lsh, context.getInstrLabel(quad.getAddress())); break; case DCMPG: loadToFPUStack64(op1, os, context); loadToFPUStack64(op2, os, context); floatCompare(true, lsh, context.getInstrLabel(quad.getAddress())); break; case DCMPL: loadToFPUStack64(op2, os, context); loadToFPUStack64(op1, os, context); floatCompare(false, lsh, context.getInstrLabel(quad.getAddress())); break; default: throw new IllegalArgumentException("Unsupported operation: " + operation); } } //fpu stack: ... op1, op2 if gt = true //fpu stack: ... op2, op1 if gt = false //result: result 1 if op1 > op2, -1 is op1 < op2, 0 otherwise private void floatCompare(boolean gt, final Variable<T> result, final Label curInstrLabel) { // Clear resultReg GPR resultReg = null; int resultDisp = 0; boolean reg; AddressingMode addressingMode = result.getAddressingMode(); switch (addressingMode) { case REGISTER: reg = true; resultReg = (GPR) ((RegisterLocation) ((Variable) result).getLocation()).getRegister(); break; case STACK: reg = false; resultDisp = ((StackLocation) ((Variable) result).getLocation()).getDisplacement(); break; default: throw new IllegalArgumentException("Illegal addressing mode: " + addressingMode); } if (reg) { os.writeXOR(resultReg, resultReg); } else { os.writeMOV_Const(X86Constants.BITS32, X86Register.EBP, resultDisp, 0); } os.writeFUCOMPP(); os.writeFNSTSW_AX(); os.writeSAHF(); final Label gtLabel = new Label(curInstrLabel + "gt"); final Label ltLabel = new Label(curInstrLabel + "lt"); final Label endLabel = new Label(curInstrLabel + "end"); os.writeJCC(gtLabel, X86Constants.JA); os.writeJCC(ltLabel, X86Constants.JB); os.writeJMP(endLabel); // equal // Greater os.setObjectRef(gtLabel); if (gt) { if (reg) { os.writeDEC(resultReg); } else { os.writeDEC(X86Constants.BITS32, X86Register.EBP, resultDisp); } } else { if (reg) { os.writeINC(resultReg); } else { os.writeINC(X86Constants.BITS32, X86Register.EBP, resultDisp); } } os.writeJMP(endLabel); // Less os.setObjectRef(ltLabel); if (gt) { if (reg) { os.writeINC(resultReg); } else { os.writeINC(X86Constants.BITS32, X86Register.EBP, resultDisp); } } else { if (reg) { os.writeDEC(resultReg); } else { os.writeDEC(X86Constants.BITS32, X86Register.EBP, resultDisp); } } // End os.setObjectRef(endLabel); } //fpu stack: ... op1, op2 if gt = true //fpu stack: ... op2, op1 if gt = false //result: resultReg or resultDisp 1 if op1 > op2, -1 is op1 < op2, 0 otherwise private void floatCompare(boolean gt, final GPR resultReg, int resultDisp, final Label curInstrLabel) { // Clear resultReg if (resultReg == null) { os.writeMOV_Const(X86Constants.BITS32, X86Register.EBP, resultDisp, 0); } else { os.writeXOR(resultReg, resultReg); } os.writeFUCOMPP(); os.writeFNSTSW_AX(); os.writeSAHF(); final Label gtLabel = new Label(curInstrLabel + "gt"); final Label ltLabel = new Label(curInstrLabel + "lt"); final Label endLabel = new Label(curInstrLabel + "end"); os.writeJCC(gtLabel, X86Constants.JA); os.writeJCC(ltLabel, X86Constants.JB); os.writeJMP(endLabel); // equal // Greater os.setObjectRef(gtLabel); if (gt) { if (resultReg == null) { os.writeDEC(X86Constants.BITS32, X86Register.EBP, resultDisp); } else { os.writeDEC(resultReg); } } else { if (resultReg == null) { os.writeINC(X86Constants.BITS32, X86Register.EBP, resultDisp); } else { os.writeINC(resultReg); } } os.writeJMP(endLabel); // Less os.setObjectRef(ltLabel); if (gt) { if (resultReg == null) { os.writeINC(X86Constants.BITS32, X86Register.EBP, resultDisp); } else { os.writeINC(resultReg); } } else { if (resultReg == null) { os.writeDEC(X86Constants.BITS32, X86Register.EBP, resultDisp); } else { os.writeDEC(resultReg); } } // End os.setObjectRef(endLabel); } static <T> void loadToFPUStack32(Operand<T> operand, X86Assembler os, GenericX86CodeGenerator context) { AddressingMode addressingMode = operand.getAddressingMode(); switch (addressingMode) { case CONSTANT: os.writePUSH(((FloatConstant) operand).getIntBits()); os.writeFLD32(X86Register.ESP, 0); os.writeLEA(X86Register.ESP, X86Register.ESP, context.stackFrame.getHelper().SLOTSIZE); break; case REGISTER: os.writePUSH((GPR) ((RegisterLocation) ((Variable) operand).getLocation()).getRegister()); os.writeFLD32(X86Register.ESP, 0); os.writeLEA(X86Register.ESP, X86Register.ESP, context.stackFrame.getHelper().SLOTSIZE); break; case STACK: os.writeFLD32(X86Register.EBP, ((StackLocation) ((Variable) operand).getLocation()).getDisplacement()); break; default: throw new IllegalArgumentException("Illegal addressing mode: " + addressingMode); } } static <T> void loadToFPUStack64(Operand<T> operand, X86Assembler os, GenericX86CodeGenerator context) { AddressingMode addressingMode = operand.getAddressingMode(); switch (addressingMode) { case CONSTANT: DoubleConstant dconst = (DoubleConstant) operand; long value = Double.doubleToRawLongBits(dconst.getValue()); final int v_lsb = (int) (value & 0xFFFFFFFFL); final int v_msb = (int) ((value >>> 32) & 0xFFFFFFFFL); os.writePUSH(v_msb); os.writePUSH(v_lsb); os.writeFLD64(X86Register.ESP, 0); os.writeLEA(X86Register.ESP, X86Register.ESP, 2 * context.stackFrame.getHelper().SLOTSIZE); break; // case REGISTER: // os.writePUSH((GPR) ((RegisterLocation) ((Variable) operand).getLocation()).getRegister()); // os.writeFLD64(X86Register.ESP, 0); // os.writeLEA(X86Register.ESP, X86Register.ESP, context.stackFrame.getHelper().SLOTSIZE); // break; case STACK: int displacement = ((StackLocation) ((Variable) operand).getLocation()).getDisplacement(); displacement -= context.stackFrame.getHelper().SLOTSIZE; //todo OK - follow this os.writeFLD64(X86Register.EBP, displacement); break; default: throw new IllegalArgumentException("Illegal addressing mode: " + addressingMode); } } }