graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java
Print this page
rev 8661 : Graal PTX enhancements
rev 8662 : [mq]: ptx_switch
rev 8663 : [mq]: ptx_lookup_switch
@@ -26,39 +26,69 @@
import static com.oracle.graal.api.code.ValueUtil.*;
import static com.oracle.graal.lir.ptx.PTXArithmetic.*;
import static com.oracle.graal.lir.ptx.PTXBitManipulationOp.IntrinsicOpcode.*;
import static com.oracle.graal.lir.ptx.PTXCompare.*;
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.asm.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.lir.*;
+import com.oracle.graal.api.code.AllocatableValue;
+import com.oracle.graal.api.code.CodeCacheProvider;
+import com.oracle.graal.api.code.DeoptimizationAction;
+import com.oracle.graal.api.code.RuntimeCallTarget;
+import com.oracle.graal.api.code.StackSlot;
+import com.oracle.graal.api.code.TargetDescription;
+import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
+import com.oracle.graal.api.meta.Constant;
+import com.oracle.graal.api.meta.DeoptimizationReason;
+import com.oracle.graal.api.meta.Kind;
+import com.oracle.graal.api.meta.ResolvedJavaMethod;
+import com.oracle.graal.api.meta.Value;
+import com.oracle.graal.asm.NumUtil;
+import com.oracle.graal.compiler.gen.LIRGenerator;
+import com.oracle.graal.compiler.target.LIRGenLowerable;
+import com.oracle.graal.graph.GraalInternalError;
+import com.oracle.graal.lir.FrameMap;
+import com.oracle.graal.lir.LIR;
+import com.oracle.graal.lir.LIRFrameState;
+import com.oracle.graal.lir.LIRInstruction;
+import com.oracle.graal.lir.LIRValueUtil;
+import com.oracle.graal.lir.LabelRef;
import com.oracle.graal.lir.StandardOp.JumpOp;
-import com.oracle.graal.lir.ptx.*;
+import com.oracle.graal.lir.Variable;
+import com.oracle.graal.lir.ptx.PTXAddressValue;
import com.oracle.graal.lir.ptx.PTXArithmetic.Op1Stack;
import com.oracle.graal.lir.ptx.PTXArithmetic.Op2Reg;
import com.oracle.graal.lir.ptx.PTXArithmetic.Op2Stack;
import com.oracle.graal.lir.ptx.PTXArithmetic.ShiftOp;
+import com.oracle.graal.lir.ptx.PTXBitManipulationOp;
import com.oracle.graal.lir.ptx.PTXCompare.CompareOp;
import com.oracle.graal.lir.ptx.PTXControlFlow.BranchOp;
+import com.oracle.graal.lir.ptx.PTXControlFlow.CondMoveOp;
+import com.oracle.graal.lir.ptx.PTXControlFlow.FloatCondMoveOp;
import com.oracle.graal.lir.ptx.PTXControlFlow.ReturnOp;
+import com.oracle.graal.lir.ptx.PTXControlFlow.SequentialSwitchOp;
+import com.oracle.graal.lir.ptx.PTXControlFlow.TableSwitchOp;
import com.oracle.graal.lir.ptx.PTXMove.LoadOp;
import com.oracle.graal.lir.ptx.PTXMove.MoveFromRegOp;
import com.oracle.graal.lir.ptx.PTXMove.MoveToRegOp;
import com.oracle.graal.lir.ptx.PTXMove.StoreOp;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.BreakpointNode;
+import com.oracle.graal.nodes.DirectCallTargetNode;
+import com.oracle.graal.nodes.IndirectCallTargetNode;
+import com.oracle.graal.nodes.SafepointNode;
+import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.ValueNode;
+import com.oracle.graal.nodes.calc.Condition;
+import com.oracle.graal.nodes.calc.ConvertNode;
+import com.oracle.graal.nodes.java.CompareAndSwapNode;
/**
* This class implements the PTX specific portion of the LIR generator.
*/
public class PTXLIRGenerator extends LIRGenerator {
+ public static final Descriptor ARITHMETIC_FREM = new Descriptor("arithmeticFrem", false, float.class, float.class, float.class);
+ public static final Descriptor ARITHMETIC_DREM = new Descriptor("arithmeticDrem", false, double.class, double.class, double.class);
+
public static class PTXSpillMoveFactory implements LIR.SpillMoveFactory {
@Override
public LIRInstruction createMove(Value result, Value input) {
throw new InternalError("NYI");
@@ -188,15 +218,28 @@
switch (left.getKind().getStackKind()) {
case Int:
append(new CompareOp(ICMP, cond, left, right));
append(new BranchOp(cond, label));
break;
+ case Long:
+ append(new CompareOp(LCMP, cond, left, right));
+ append(new BranchOp(cond, label));
+ break;
+ case Float:
+ append(new CompareOp(FCMP, cond, left, right));
+ append(new BranchOp(cond, label));
+ break;
+ case Double:
+ append(new CompareOp(DCMP, cond, left, right));
+ append(new BranchOp(cond, label));
+ break;
case Object:
append(new CompareOp(ACMP, cond, left, right));
append(new BranchOp(cond, label));
break;
default:
+ System.err.println("missing: " + left.getKind());
throw GraalInternalError.shouldNotReachHere("" + left.getKind());
}
}
@Override
@@ -209,11 +252,71 @@
throw new InternalError("NYI");
}
@Override
public Variable emitConditionalMove(Value left, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue) {
- throw new InternalError("NYI");
+ boolean mirrored = emitCompare(cond, left, right);
+ Condition finalCondition = mirrored ? cond.mirror() : cond;
+
+ Variable result = newVariable(trueValue.getKind());
+ switch (left.getKind().getStackKind()) {
+ case Int:
+ case Long:
+ case Object:
+ append(new CondMoveOp(result, finalCondition, load(trueValue), loadNonConst(falseValue)));
+ break;
+ case Float:
+ case Double:
+ append(new FloatCondMoveOp(result, finalCondition, unorderedIsTrue, load(trueValue), load(falseValue)));
+ break;
+ default:
+ throw GraalInternalError.shouldNotReachHere("missing: " + left.getKind());
+ }
+ return result;
+ }
+
+ /**
+ * This method emits the compare instruction, and may reorder the operands. It returns true if
+ * it did so.
+ *
+ * @param a the left operand of the comparison
+ * @param b the right operand of the comparison
+ * @return true if the left and right operands were switched, false otherwise
+ */
+ private boolean emitCompare(Condition cond, Value a, Value b) {
+ Variable left;
+ Value right;
+ boolean mirrored;
+ if (LIRValueUtil.isVariable(b)) {
+ left = load(b);
+ right = loadNonConst(a);
+ mirrored = true;
+ } else {
+ left = load(a);
+ right = loadNonConst(b);
+ mirrored = false;
+ }
+ switch (left.getKind().getStackKind()) {
+ case Int:
+ append(new CompareOp(ICMP, cond, left, right));
+ break;
+ case Long:
+ append(new CompareOp(LCMP, cond, left, right));
+ break;
+ case Object:
+ append(new CompareOp(ACMP, cond, left, right));
+ break;
+ case Float:
+ append(new CompareOp(FCMP, cond, left, right));
+ break;
+ case Double:
+ append(new CompareOp(DCMP, cond, left, right));
+ break;
+ default:
+ throw GraalInternalError.shouldNotReachHere();
+ }
+ return mirrored;
}
@Override
public Variable emitIntegerTestMove(Value left, Value right, Value trueValue, Value falseValue) {
throw new InternalError("NYI");
@@ -224,10 +327,16 @@
Variable result = newVariable(input.getKind());
switch (input.getKind()) {
case Int:
append(new Op1Stack(INEG, result, input));
break;
+ case Float:
+ append(new Op1Stack(FNEG, result, input));
+ break;
+ case Double:
+ append(new Op1Stack(DNEG, result, input));
+ break;
default:
throw GraalInternalError.shouldNotReachHere();
}
return result;
}
@@ -237,10 +346,19 @@
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)));
+ break;
default:
throw GraalInternalError.shouldNotReachHere();
}
return result;
}
@@ -250,12 +368,21 @@
Variable result = newVariable(a.getKind());
switch (a.getKind()) {
case Int:
append(new Op2Stack(ISUB, result, a, loadNonConst(b)));
break;
+ case Long:
+ append(new Op2Stack(LSUB, result, a, loadNonConst(b)));
+ break;
+ case Float:
+ append(new Op2Stack(FSUB, result, a, loadNonConst(b)));
+ break;
+ case Double:
+ append(new Op2Stack(DSUB, result, a, loadNonConst(b)));
+ break;
default:
- throw GraalInternalError.shouldNotReachHere();
+ throw GraalInternalError.shouldNotReachHere("missing: " + a.getKind());
}
return result;
}
@Override
@@ -263,12 +390,21 @@
Variable result = newVariable(a.getKind());
switch (a.getKind()) {
case Int:
append(new Op2Reg(IMUL, result, a, loadNonConst(b)));
break;
+ case Long:
+ append(new Op2Reg(LMUL, result, a, loadNonConst(b)));
+ break;
+ case Float:
+ append(new Op2Stack(FMUL, result, a, loadNonConst(b)));
+ break;
+ case Double:
+ append(new Op2Stack(DMUL, result, a, loadNonConst(b)));
+ break;
default:
- throw GraalInternalError.shouldNotReachHere();
+ throw GraalInternalError.shouldNotReachHere("missing: " + a.getKind());
}
return result;
}
@Override
@@ -277,16 +413,55 @@
return false;
}
@Override
public Value emitDiv(Value a, Value b) {
- throw new InternalError("NYI");
+ Variable result = newVariable(a.getKind());
+ switch (a.getKind()) {
+ case Int:
+ append(new Op2Reg(IDIV, result, a, loadNonConst(b)));
+ break;
+ case Long:
+ append(new Op2Reg(LDIV, result, a, loadNonConst(b)));
+ break;
+ case Float:
+ append(new Op2Stack(FDIV, result, a, loadNonConst(b)));
+ break;
+ case Double:
+ append(new Op2Stack(DDIV, result, a, loadNonConst(b)));
+ break;
+ default:
+ throw GraalInternalError.shouldNotReachHere("missing: " + a.getKind());
+ }
+ return result;
}
@Override
public Value emitRem(Value a, Value b) {
- throw new InternalError("NYI");
+ Variable result = newVariable(a.getKind());
+ switch (a.getKind()) {
+ case Int:
+ append(new Op2Reg(IREM, result, a, loadNonConst(b)));
+ break;
+ case Long:
+ append(new Op2Reg(LREM, result, a, loadNonConst(b)));
+ break;
+ /*
+ * not correct - these need to call the PTX double-precision remainder() function
+ case Float: {
+ RuntimeCallTarget stub = runtime.lookupRuntimeCall(ARITHMETIC_FREM);
+ return emitCall(stub, stub.getCallingConvention(), false, a, b);
+ }
+ case Double: {
+ RuntimeCallTarget stub = runtime.lookupRuntimeCall(ARITHMETIC_DREM);
+ return emitCall(stub, stub.getCallingConvention(), false, a, b);
+ }
+ */
+ default:
+ throw GraalInternalError.shouldNotReachHere("missing: " + a.getKind());
+ }
+ return result;
}
@Override
public Variable emitUDiv(Value a, Value b) {
throw new InternalError("NYI");
@@ -302,52 +477,172 @@
Variable result = newVariable(a.getKind());
switch (a.getKind()) {
case Int:
append(new Op2Stack(IAND, result, a, loadNonConst(b)));
break;
+ case Long:
+ append(new Op2Stack(LAND, result, a, loadNonConst(b)));
+ break;
+
default:
- throw GraalInternalError.shouldNotReachHere();
+ throw GraalInternalError.shouldNotReachHere("missing: " + a.getKind());
}
return result;
}
@Override
public Variable emitOr(Value a, Value b) {
- throw new InternalError("NYI");
+ Variable result = newVariable(a.getKind());
+ switch (a.getKind()) {
+ case Int:
+ append(new Op2Stack(IOR, result, a, loadNonConst(b)));
+ break;
+ case Long:
+ append(new Op2Stack(LOR, result, a, loadNonConst(b)));
+ break;
+ default:
+ throw GraalInternalError.shouldNotReachHere("missing: " + a.getKind());
+ }
+ return result;
}
@Override
public Variable emitXor(Value a, Value b) {
- throw new InternalError("NYI");
+ Variable result = newVariable(a.getKind());
+ switch (a.getKind()) {
+ case Int:
+ append(new Op2Stack(IXOR, result, a, loadNonConst(b)));
+ break;
+ case Long:
+ append(new Op2Stack(LXOR, result, a, loadNonConst(b)));
+ break;
+ default:
+ throw GraalInternalError.shouldNotReachHere();
+ }
+ return result;
}
@Override
public Variable emitShl(Value a, Value b) {
- throw new InternalError("NYI");
+ Variable result = newVariable(a.getKind());
+ switch (a.getKind()) {
+ case Int:
+ append(new Op2Stack(ISHL, result, a, loadNonConst(b)));
+ break;
+ case Long:
+ append(new Op2Stack(LSHL, result, a, loadNonConst(b)));
+ break;
+ default:
+ throw GraalInternalError.shouldNotReachHere();
+ }
+ return result;
}
@Override
public Variable emitShr(Value a, Value b) {
- throw new InternalError("NYI");
+ Variable result = newVariable(a.getKind());
+ switch (a.getKind()) {
+ case Int:
+ append(new Op2Stack(ISHR, result, a, loadNonConst(b)));
+ break;
+ case Long:
+ append(new Op2Stack(LSHR, result, a, loadNonConst(b)));
+ break;
+ default:
+ 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, b));
break;
+ case Long:
+ append(new ShiftOp(LUSHR, result, a, b));
+ break;
default:
GraalInternalError.shouldNotReachHere();
}
return result;
}
@Override
public Variable emitConvert(ConvertNode.Op opcode, Value inputVal) {
- throw new InternalError("NYI");
+ Variable input = load(inputVal);
+ Variable result = newVariable(opcode.to);
+ switch (opcode) {
+ case I2L:
+ append(new Unary2Op(I2L, result, input));
+ break;
+ case L2I:
+ append(new Unary1Op(L2I, result, input));
+ break;
+ case I2B:
+ append(new Unary2Op(I2B, result, input));
+ break;
+ case I2C:
+ append(new Unary1Op(I2C, result, input));
+ break;
+ case I2S:
+ append(new Unary2Op(I2S, result, input));
+ break;
+ case F2D:
+ append(new Unary2Op(F2D, result, input));
+ break;
+ case D2F:
+ append(new Unary2Op(D2F, result, input));
+ break;
+ case I2F:
+ append(new Unary2Op(I2F, result, input));
+ break;
+ case I2D:
+ append(new Unary2Op(I2D, result, input));
+ break;
+ case F2I:
+ append(new Unary2Op(F2I, result, input));
+ break;
+ case D2I:
+ append(new Unary2Op(D2I, result, input));
+ break;
+ case L2F:
+ append(new Unary2Op(L2F, result, input));
+ break;
+ case L2D:
+ append(new Unary2Op(L2D, result, input));
+ break;
+ case F2L:
+ append(new Unary2Op(F2L, result, input));
+ break;
+ case D2L:
+ append(new Unary2Op(D2L, result, input));
+ break;
+ case MOV_I2F:
+ append(new Unary2Op(MOV_I2F, result, input));
+ break;
+ case MOV_L2D:
+ append(new Unary2Op(MOV_L2D, result, input));
+ break;
+ case MOV_F2I:
+ append(new Unary2Op(MOV_F2I, result, input));
+ break;
+ case MOV_D2L:
+ append(new Unary2Op(MOV_D2L, result, input));
+ break;
+ case UNSIGNED_I2L:
+ // Instructions that move or generate 32-bit register values also set the upper 32
+ // bits of the register to zero.
+ // Consequently, there is no need for a special zero-extension move.
+ emitMove(result, input);
+ break;
+ default:
+ throw GraalInternalError.shouldNotReachHere();
+ }
+ return result;
}
@Override
public void emitDeoptimize(DeoptimizationAction action, DeoptimizationReason reason) {
append(new ReturnOp(Value.ILLEGAL));
@@ -432,21 +727,31 @@
append(new ReturnOp(input));
}
@Override
protected void emitSequentialSwitch(Constant[] keyConstants, LabelRef[] keyTargets, LabelRef defaultTarget, Value key) {
- throw new InternalError("NYI");
+ // Making a copy of the switch value is necessary because jump table destroys the input
+ // value
+ if (key.getKind() == Kind.Int || key.getKind() == Kind.Long) {
+ append(new SequentialSwitchOp(keyConstants, keyTargets, defaultTarget, key, Value.ILLEGAL));
+ } else {
+ assert key.getKind() == Kind.Object : key.getKind();
+ append(new SequentialSwitchOp(keyConstants, keyTargets, defaultTarget, key, newVariable(Kind.Object)));
+ }
}
@Override
protected void emitSwitchRanges(int[] lowKeys, int[] highKeys, LabelRef[] targets, LabelRef defaultTarget, Value key) {
throw new InternalError("NYI");
}
@Override
protected void emitTableSwitch(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value key) {
- throw new InternalError("NYI");
+ // Making a copy of the switch value is necessary because jump table destroys the input
+ // value
+ Variable tmp = emitMove(key);
+ append(new TableSwitchOp(lowKey, defaultTarget, targets, tmp, newVariable(target.wordKind)));
}
@Override
public void visitCompareAndSwap(CompareAndSwapNode node) {
throw new InternalError("NYI");
@@ -457,17 +762,18 @@
throw new InternalError("NYI");
}
@Override
public void visitSafepointNode(SafepointNode i) {
+ // LIRFrameState info = state();
+ // append(new PTXSafepointOp(info, runtime().config, this));
throw new InternalError("NYI");
}
@Override
public void emitUnwind(Value operand) {
- // TODO Auto-generated method stub
-
+ throw new InternalError("NYI");
}
@Override
public void emitNullCheck(ValueNode v) {
throw new InternalError("NYI");