# HG changeset patch # User Roland Schatz # Date 1362412091 -3600 # Node ID 0ae70d44ec9a26a48ac8cc51e0aaca985b75e0f6 # Parent 0dea5ef60303c9f302f2f33a69c892846c1f5cd8 Restructure Op2 in AMD64 backend. diff -r 0dea5ef60303 -r 0ae70d44ec9a graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java --- 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)) { diff -r 0dea5ef60303 -r 0ae70d44ec9a graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java --- 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 diff -r 0dea5ef60303 -r 0ae70d44ec9a graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java --- 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)); } }