changeset 7919:0ae70d44ec9a

Restructure Op2 in AMD64 backend.
author Roland Schatz <roland.schatz@oracle.com>
date Mon, 04 Mar 2013 16:48:11 +0100
parents 0dea5ef60303
children 2e3e4b691835
files graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java
diffstat 3 files changed, 208 insertions(+), 130 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java	Mon Mar 04 10:00:49 2013 +0100
+++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java	Mon Mar 04 16:48:11 2013 +0100
@@ -664,6 +664,13 @@
         emitByte(0xC0 | encode);
     }
 
+    public final void imull(Register dst, AMD64Address src) {
+        prefix(src, dst);
+        emitByte(0x0F);
+        emitByte(0xAF);
+        emitOperandHelper(dst, src);
+    }
+
     public final void imull(Register dst, Register src, int value) {
         int encode = prefixAndEncode(dst.encoding, src.encoding);
         if (isByte(value)) {
@@ -2025,6 +2032,13 @@
         emitByte(0xC0 | encode);
     }
 
+    public final void imulq(Register dst, AMD64Address src) {
+        prefixq(src, dst);
+        emitByte(0x0F);
+        emitByte(0xAF);
+        emitOperandHelper(dst, src);
+    }
+
     public final void imulq(Register dst, Register src, int value) {
         int encode = prefixqAndEncode(dst.encoding, src.encoding);
         if (isByte(value)) {
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Mon Mar 04 10:00:49 2013 +0100
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Mon Mar 04 16:48:11 2013 +0100
@@ -40,14 +40,16 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.JumpOp;
+import com.oracle.graal.lir.amd64.*;
+import com.oracle.graal.lir.amd64.AMD64Arithmetic.BinaryCommutative;
+import com.oracle.graal.lir.amd64.AMD64Arithmetic.BinaryRegConst;
+import com.oracle.graal.lir.amd64.AMD64Arithmetic.BinaryRegReg;
+import com.oracle.graal.lir.amd64.AMD64Arithmetic.BinaryRegStack;
+import com.oracle.graal.lir.amd64.AMD64Arithmetic.BinaryRegStackConst;
 import com.oracle.graal.lir.amd64.AMD64Arithmetic.DivOp;
 import com.oracle.graal.lir.amd64.AMD64Arithmetic.DivRemOp;
-import com.oracle.graal.lir.amd64.AMD64Arithmetic.Op2Reg;
-import com.oracle.graal.lir.amd64.AMD64Arithmetic.Op2Stack;
-import com.oracle.graal.lir.amd64.AMD64Arithmetic.ShiftOp;
 import com.oracle.graal.lir.amd64.AMD64Arithmetic.Unary1Op;
 import com.oracle.graal.lir.amd64.AMD64Arithmetic.Unary2Op;
-import com.oracle.graal.lir.amd64.*;
 import com.oracle.graal.lir.amd64.AMD64Call.DirectCallOp;
 import com.oracle.graal.lir.amd64.AMD64Call.IndirectCallOp;
 import com.oracle.graal.lir.amd64.AMD64Compare.CompareOp;
@@ -365,32 +367,10 @@
                 append(new Unary1Op(LNEG, result, input));
                 break;
             case Float:
-                append(new Op2Reg(FXOR, result, input, Constant.forFloat(Float.intBitsToFloat(0x80000000))));
+                append(new BinaryRegConst(FXOR, result, input, Constant.forFloat(Float.intBitsToFloat(0x80000000))));
                 break;
             case Double:
-                append(new Op2Reg(DXOR, result, input, Constant.forDouble(Double.longBitsToDouble(0x8000000000000000L))));
-                break;
-            default:
-                throw GraalInternalError.shouldNotReachHere();
-        }
-        return result;
-    }
-
-    @Override
-    public Variable emitAdd(Value a, Value b) {
-        Variable result = newVariable(a.getKind());
-        switch (a.getKind()) {
-            case Int:
-                append(new Op2Stack(IADD, result, a, loadNonConst(b)));
-                break;
-            case Long:
-                append(new Op2Stack(LADD, result, a, loadNonConst(b)));
-                break;
-            case Float:
-                append(new Op2Stack(FADD, result, a, loadNonConst(b)));
-                break;
-            case Double:
-                append(new Op2Stack(DADD, result, a, loadNonConst(b)));
+                append(new BinaryRegConst(DXOR, result, input, Constant.forDouble(Double.longBitsToDouble(0x8000000000000000L))));
                 break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
@@ -398,48 +378,104 @@
         return result;
     }
 
-    @Override
-    public Variable emitSub(Value a, Value b) {
-        Variable result = newVariable(a.getKind());
-        switch (a.getKind()) {
-            case Int:
-                append(new Op2Stack(ISUB, result, a, loadNonConst(b)));
+    private Variable emitBinary(AMD64Arithmetic op, boolean commutative, Value a, Value b) {
+        if (isConstant(b)) {
+            return emitBinaryConst(op, commutative, asAllocatable(a), asConstant(b));
+        } else if (commutative && isConstant(a)) {
+            return emitBinaryConst(op, commutative, asAllocatable(b), asConstant(a));
+        } else {
+            return emitBinaryVar(op, commutative, asAllocatable(a), asAllocatable(b));
+        }
+    }
+
+    private Variable emitBinaryConst(AMD64Arithmetic op, boolean commutative, AllocatableValue a, Constant b) {
+        switch (op) {
+            case IADD:
+            case LADD:
+            case ISUB:
+            case LSUB:
+            case IAND:
+            case LAND:
+            case IOR:
+            case LOR:
+            case IXOR:
+            case LXOR:
+                if (NumUtil.isInt(b.asLong())) {
+                    Variable result = newVariable(a.getKind());
+                    append(new BinaryRegConst(op, result, a, b));
+                    return result;
+                }
                 break;
-            case Long:
-                append(new Op2Stack(LSUB, result, a, loadNonConst(b)));
-                break;
-            case Float:
-                append(new Op2Stack(FSUB, result, a, loadNonConst(b)));
+
+            case IMUL:
+            case LMUL:
+                if (NumUtil.isInt(b.asLong())) {
+                    Variable result = newVariable(a.getKind());
+                    append(new BinaryRegStackConst(op, result, a, b));
+                    return result;
+                }
                 break;
-            case Double:
-                append(new Op2Stack(DSUB, result, a, loadNonConst(b)));
-                break;
-            default:
-                throw GraalInternalError.shouldNotReachHere();
+        }
+
+        return emitBinaryVar(op, commutative, a, asAllocatable(b));
+    }
+
+    private Variable emitBinaryVar(AMD64Arithmetic op, boolean commutative, AllocatableValue a, AllocatableValue b) {
+        Variable result = newVariable(a.getKind());
+        if (commutative) {
+            append(new BinaryCommutative(op, result, a, b));
+        } else {
+            append(new BinaryRegStack(op, result, a, b));
         }
         return result;
     }
 
     @Override
-    public Variable emitMul(Value a, Value b) {
-        Variable result = newVariable(a.getKind());
+    public Variable emitAdd(Value a, Value b) {
         switch (a.getKind()) {
             case Int:
-                append(new Op2Reg(IMUL, result, a, loadNonConst(b)));
-                break;
+                return emitBinary(IADD, true, a, b);
             case Long:
-                append(new Op2Reg(LMUL, result, a, loadNonConst(b)));
-                break;
+                return emitBinary(LADD, true, a, b);
             case Float:
-                append(new Op2Stack(FMUL, result, a, loadNonConst(b)));
-                break;
+                return emitBinary(FADD, true, a, b);
             case Double:
-                append(new Op2Stack(DMUL, result, a, loadNonConst(b)));
-                break;
+                return emitBinary(DADD, true, a, b);
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
-        return result;
+    }
+
+    @Override
+    public Variable emitSub(Value a, Value b) {
+        switch (a.getKind()) {
+            case Int:
+                return emitBinary(ISUB, false, a, b);
+            case Long:
+                return emitBinary(LSUB, false, a, b);
+            case Float:
+                return emitBinary(FSUB, false, a, b);
+            case Double:
+                return emitBinary(DSUB, false, a, b);
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
+    @Override
+    public Variable emitMul(Value a, Value b) {
+        switch (a.getKind()) {
+            case Int:
+                return emitBinary(IMUL, true, a, b);
+            case Long:
+                return emitBinary(LMUL, true, a, b);
+            case Float:
+                return emitBinary(FMUL, true, a, b);
+            case Double:
+                return emitBinary(DMUL, true, a, b);
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
     }
 
     @Override
@@ -497,12 +533,12 @@
                 return emitMove(RAX_L);
             case Float: {
                 Variable result = newVariable(a.getKind());
-                append(new Op2Stack(FDIV, result, a, loadNonConst(b)));
+                append(new BinaryRegStack(FDIV, result, asAllocatable(a), asAllocatable(b)));
                 return result;
             }
             case Double: {
                 Variable result = newVariable(a.getKind());
-                append(new Op2Stack(DDIV, result, a, loadNonConst(b)));
+                append(new BinaryRegStack(DDIV, result, asAllocatable(a), asAllocatable(b)));
                 return result;
             }
             default:
@@ -568,107 +604,86 @@
 
     @Override
     public Variable emitAnd(Value a, Value b) {
-        Variable result = newVariable(a.getKind());
         switch (a.getKind()) {
             case Int:
-                append(new Op2Stack(IAND, result, a, loadNonConst(b)));
-                break;
+                return emitBinary(IAND, true, a, b);
             case Long:
-                append(new Op2Stack(LAND, result, a, loadNonConst(b)));
-                break;
+                return emitBinary(LAND, true, a, b);
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
-        return result;
     }
 
     @Override
     public Variable emitOr(Value a, Value b) {
-        Variable result = newVariable(a.getKind());
         switch (a.getKind()) {
             case Int:
-                append(new Op2Stack(IOR, result, a, loadNonConst(b)));
-                break;
+                return emitBinary(IOR, true, a, b);
             case Long:
-                append(new Op2Stack(LOR, result, a, loadNonConst(b)));
-                break;
+                return emitBinary(LOR, true, a, b);
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
-        return result;
     }
 
     @Override
     public Variable emitXor(Value a, Value b) {
-        Variable result = newVariable(a.getKind());
         switch (a.getKind()) {
             case Int:
-                append(new Op2Stack(IXOR, result, a, loadNonConst(b)));
-                break;
+                return emitBinary(IXOR, true, a, b);
             case Long:
-                append(new Op2Stack(LXOR, result, a, loadNonConst(b)));
-                break;
+                return emitBinary(LXOR, true, a, b);
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
+    }
+
+    private Variable emitShift(AMD64Arithmetic op, Value a, Value b) {
+        Variable result = newVariable(a.getKind());
+        AllocatableValue input = asAllocatable(a);
+        if (isConstant(b)) {
+            append(new BinaryRegConst(op, result, input, asConstant(b)));
+        } else {
+            emitMove(RCX_I, b);
+            append(new BinaryRegReg(op, result, input, RCX_I));
+        }
         return result;
     }
 
     @Override
     public Variable emitShl(Value a, Value b) {
-        Variable result = newVariable(a.getKind());
         switch (a.getKind()) {
             case Int:
-                append(new ShiftOp(ISHL, result, a, loadShiftCount(b)));
-                break;
+                return emitShift(ISHL, a, b);
             case Long:
-                append(new ShiftOp(LSHL, result, a, loadShiftCount(b)));
-                break;
+                return emitShift(LSHL, a, b);
             default:
-                GraalInternalError.shouldNotReachHere();
+                throw GraalInternalError.shouldNotReachHere();
         }
-        return result;
     }
 
     @Override
     public Variable emitShr(Value a, Value b) {
-        Variable result = newVariable(a.getKind());
         switch (a.getKind()) {
             case Int:
-                append(new ShiftOp(ISHR, result, a, loadShiftCount(b)));
-                break;
+                return emitShift(ISHR, a, b);
             case Long:
-                append(new ShiftOp(LSHR, result, a, loadShiftCount(b)));
-                break;
+                return emitShift(LSHR, a, b);
             default:
-                GraalInternalError.shouldNotReachHere();
+                throw GraalInternalError.shouldNotReachHere();
         }
-        return result;
     }
 
     @Override
     public Variable emitUShr(Value a, Value b) {
-        Variable result = newVariable(a.getKind());
         switch (a.getKind()) {
             case Int:
-                append(new ShiftOp(IUSHR, result, a, loadShiftCount(b)));
-                break;
+                return emitShift(IUSHR, a, b);
             case Long:
-                append(new ShiftOp(LUSHR, result, a, loadShiftCount(b)));
-                break;
+                return emitShift(LUSHR, a, b);
             default:
-                GraalInternalError.shouldNotReachHere();
+                throw GraalInternalError.shouldNotReachHere();
         }
-        return result;
-    }
-
-    private Value loadShiftCount(Value value) {
-        if (isConstant(value)) {
-            return value;
-        }
-        // Non-constant shift count must be in RCX
-        emitMove(RCX_I, value);
-        return RCX_I;
     }
 
     @Override
@@ -815,7 +830,7 @@
 
     @Override
     public void emitMathAbs(Variable result, Variable input) {
-        append(new Op2Reg(DAND, result, input, Constant.forDouble(Double.longBitsToDouble(0x7FFFFFFFFFFFFFFFL))));
+        append(new BinaryRegConst(DAND, result, input, Constant.forDouble(Double.longBitsToDouble(0x7FFFFFFFFFFFFFFFL))));
     }
 
     @Override
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java	Mon Mar 04 10:00:49 2013 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java	Mon Mar 04 16:48:11 2013 +0100
@@ -49,6 +49,9 @@
     MOV_I2F, MOV_L2D, MOV_F2I, MOV_D2L;
 
 
+    /**
+     * Unary operation with separate source and destination operand. 
+     */
     public static class Unary2Op extends AMD64LIRInstruction {
         @Opcode private final AMD64Arithmetic opcode;
         @Def({REG}) protected AllocatableValue result;
@@ -66,6 +69,9 @@
         }
     }
 
+    /**
+     * Unary operation with single operand for source and destination. 
+     */
     public static class Unary1Op extends AMD64LIRInstruction {
         @Opcode private final AMD64Arithmetic opcode;
         @Def({REG, HINT}) protected AllocatableValue result;
@@ -84,13 +90,17 @@
         }
     }
 
-    public static class Op2Stack extends AMD64LIRInstruction {
+    /**
+     * Binary operation with two operands. The first source operand is combined with the destination.
+     * The second source operand may be a stack slot. 
+     */
+    public static class BinaryRegStack extends AMD64LIRInstruction {
         @Opcode private final AMD64Arithmetic opcode;
-        @Def({REG, HINT}) protected Value result;
-        @Use({REG, STACK, CONST}) protected Value x;
-        @Alive({REG, STACK, CONST}) protected Value y;
+        @Def({REG, HINT}) protected AllocatableValue result;
+        @Use({REG, STACK}) protected AllocatableValue x;
+        @Alive({REG, STACK}) protected AllocatableValue y;
 
-        public Op2Stack(AMD64Arithmetic opcode, Value result, Value x, Value y) {
+        public BinaryRegStack(AMD64Arithmetic opcode, AllocatableValue result, AllocatableValue x, AllocatableValue y) {
             this.opcode = opcode;
             this.result = result;
             this.x = x;
@@ -111,13 +121,17 @@
         }
     }
 
-    public static class Op2Reg extends AMD64LIRInstruction {
+    /**
+     * Binary operation with two operands. The first source operand is combined with the destination.
+     * The second source operand must be a register. 
+     */
+    public static class BinaryRegReg extends AMD64LIRInstruction {
         @Opcode private final AMD64Arithmetic opcode;
-        @Def({REG, HINT}) protected Value result;
-        @Use({REG, STACK, CONST}) protected Value x;
-        @Alive({REG, CONST}) protected Value y;
+        @Def({REG, HINT}) protected AllocatableValue result;
+        @Use({REG, STACK}) protected AllocatableValue x;
+        @Alive({REG}) protected AllocatableValue y;
 
-        public Op2Reg(AMD64Arithmetic opcode, Value result, Value x, Value y) {
+        public BinaryRegReg(AMD64Arithmetic opcode, AllocatableValue result, AllocatableValue x, AllocatableValue y) {
             this.opcode = opcode;
             this.result = result;
             this.x = x;
@@ -138,13 +152,45 @@
         }
     }
 
-    public static class Op2RegCommutative extends AMD64LIRInstruction {
+    /**
+     * Binary operation with single source/destination operand and one constant.
+     */
+    public static class BinaryRegConst extends AMD64LIRInstruction {
         @Opcode private final AMD64Arithmetic opcode;
-        @Def({REG, HINT}) protected Value result;
-        @Use({REG, STACK, CONST}) protected Value x;
-        @Use({REG, CONST}) protected Value y;
+        @Def({REG, HINT}) protected AllocatableValue result;
+        @Use({REG, STACK}) protected AllocatableValue x;
+        @Use({CONST}) protected Constant y;
+
+        public BinaryRegConst(AMD64Arithmetic opcode, AllocatableValue result, AllocatableValue x, Constant y) {
+            this.opcode = opcode;
+            this.result = result;
+            this.x = x;
+            this.y = y;
+        }
+
+        @Override
+        public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
+            AMD64Move.move(tasm, masm, result, x);
+            emit(tasm, masm, opcode, result, y, null);
+        }
 
-        public Op2RegCommutative(AMD64Arithmetic opcode, Value result, Value x, Value y) {
+        @Override
+        public void verify() {
+            super.verify();
+            verifyKind(opcode, result, x, y);
+        }
+    }
+
+    /**
+     * Commutative binary operation with two operands. One of the operands is combined with the result.
+     */
+    public static class BinaryCommutative extends AMD64LIRInstruction {
+        @Opcode private final AMD64Arithmetic opcode;
+        @Def({REG, HINT}) protected AllocatableValue result;
+        @Use({REG, STACK}) protected AllocatableValue x;
+        @Use({REG, STACK}) protected AllocatableValue y;
+
+        public BinaryCommutative(AMD64Arithmetic opcode, AllocatableValue result, AllocatableValue x, AllocatableValue y) {
             this.opcode = opcode;
             this.result = result;
             this.x = x;
@@ -168,13 +214,16 @@
         }
     }
 
-    public static class ShiftOp extends AMD64LIRInstruction {
+    /**
+     * Binary operation with separate source and destination and one constant operand.
+     */
+    public static class BinaryRegStackConst extends AMD64LIRInstruction {
         @Opcode private final AMD64Arithmetic opcode;
-        @Def({REG, HINT}) protected Value result;
-        @Use({REG, STACK, CONST}) protected Value x;
-        @Alive({REG, CONST}) protected Value y;
+        @Def({REG}) protected AllocatableValue result;
+        @Use({REG, STACK}) protected AllocatableValue x;
+        @Use({CONST}) protected Constant y;
 
-        public ShiftOp(AMD64Arithmetic opcode, Value result, Value x, Value y) {
+        public BinaryRegStackConst(AMD64Arithmetic opcode, AllocatableValue result, AllocatableValue x, Constant y) {
             this.opcode = opcode;
             this.result = result;
             this.x = x;
@@ -190,10 +239,7 @@
         @Override
         public void verify() {
             super.verify();
-            assert isConstant(y) || asRegister(y) == AMD64.rcx;
-            assert differentRegisters(result, y) || sameRegister(x, y);
-            verifyKind(opcode, result, x, x);
-            assert y.getKind().getStackKind() == Kind.Int;
+            verifyKind(opcode, result, x, y);
         }
     }
 
@@ -423,11 +469,13 @@
                 case IADD: masm.addl(asIntReg(dst), (AMD64Address) tasm.asIntAddr(src)); break;
                 case ISUB: masm.subl(asIntReg(dst), (AMD64Address) tasm.asIntAddr(src)); break;
                 case IAND: masm.andl(asIntReg(dst), (AMD64Address) tasm.asIntAddr(src)); break;
+                case IMUL: masm.imull(asIntReg(dst), (AMD64Address) tasm.asIntAddr(src)); break;
                 case IOR:  masm.orl(asIntReg(dst),  (AMD64Address) tasm.asIntAddr(src)); break;
                 case IXOR: masm.xorl(asIntReg(dst), (AMD64Address) tasm.asIntAddr(src)); break;
 
                 case LADD: masm.addq(asLongReg(dst), (AMD64Address) tasm.asLongAddr(src)); break;
                 case LSUB: masm.subq(asLongReg(dst), (AMD64Address) tasm.asLongAddr(src)); break;
+                case LMUL: masm.imulq(asIntReg(dst), (AMD64Address) tasm.asIntAddr(src)); break;
                 case LAND: masm.andq(asLongReg(dst), (AMD64Address) tasm.asLongAddr(src)); break;
                 case LOR:  masm.orq(asLongReg(dst),  (AMD64Address) tasm.asLongAddr(src)); break;
                 case LXOR: masm.xorq(asLongReg(dst), (AMD64Address) tasm.asLongAddr(src)); break;
@@ -512,6 +560,7 @@
         assert (opcode.name().startsWith("I") && result.getKind() == Kind.Int && x.getKind().getStackKind() == Kind.Int && y.getKind().getStackKind() == Kind.Int)
             || (opcode.name().startsWith("L") && result.getKind() == Kind.Long && x.getKind() == Kind.Long && y.getKind() == Kind.Long)
             || (opcode.name().startsWith("F") && result.getKind() == Kind.Float && x.getKind() == Kind.Float && y.getKind() == Kind.Float)
-            || (opcode.name().startsWith("D") && result.getKind() == Kind.Double && x.getKind() == Kind.Double && y.getKind() == Kind.Double);
+            || (opcode.name().startsWith("D") && result.getKind() == Kind.Double && x.getKind() == Kind.Double && y.getKind() == Kind.Double)
+            || (opcode.name().matches(".U?SH.") && result.getKind() == x.getKind() && y.getKind() == Kind.Int && (isConstant(y) || asRegister(y) == AMD64.rcx));
     }
 }