# HG changeset patch # User Morris Meyer # Date 1381082109 14400 # Node ID 1f82cda83ced7536795c46f9fe3f3f06b6a5426b # Parent 1ec42a9f61499a4c4c55a8478483dadedf5ac20d PTX conditional move, switch, if-else diff -r 1ec42a9f6149 -r 1f82cda83ced graal/com.oracle.graal.asm.ptx/src/com/oracle/graal/asm/ptx/PTXAssembler.java --- a/graal/com.oracle.graal.asm.ptx/src/com/oracle/graal/asm/ptx/PTXAssembler.java Sun Oct 06 15:38:20 2013 +0200 +++ b/graal/com.oracle.graal.asm.ptx/src/com/oracle/graal/asm/ptx/PTXAssembler.java Sun Oct 06 13:55:09 2013 -0400 @@ -24,6 +24,7 @@ import static com.oracle.graal.api.code.ValueUtil.*; +import com.oracle.graal.asm.Label; import com.oracle.graal.api.code.Register; import com.oracle.graal.api.code.RegisterConfig; import com.oracle.graal.api.code.TargetDescription; @@ -32,6 +33,7 @@ import com.oracle.graal.api.meta.Value; import com.oracle.graal.nodes.calc.Condition; import com.oracle.graal.graph.GraalInternalError; +import com.oracle.graal.lir.LabelRef; import com.oracle.graal.lir.Variable; public class PTXAssembler extends AbstractPTXAssembler { @@ -511,12 +513,18 @@ // Checkstyle: stop method name check public final void bra(String tgt, int pred) { - System.err.println("BRA: " + tgt + " pred: " + pred); assert pred >= 0; + if (tgt.equals("?")) { + Thread.dumpStack(); + } emitString("@%p" + pred + " " + "bra" + " " + tgt + ";"); } + public final void bra(String target) { + emitString("bra " + target + ";"); + } + public final void bra_uni(String tgt) { emitString("bra.uni" + " " + tgt + ";" + ""); } @@ -534,10 +542,16 @@ public static class Mov extends SingleOperandFormat { + private int predicateRegisterNumber = -1; + public Mov(Variable dst, Value src) { super(dst, src); } + public Mov(Variable dst, Value src, int predicate) { + super(dst, src); + this.predicateRegisterNumber = predicate; + } /* public Mov(Variable dst, AbstractAddress src) { throw GraalInternalError.unimplemented("AbstractAddress Mov"); @@ -545,10 +559,15 @@ */ public void emit(PTXAssembler asm) { - asm.emitString("mov." + super.emit()); + if (predicateRegisterNumber >= 0) { + asm.emitString("@%p" + String.valueOf(predicateRegisterNumber) + + " mov." + super.emit()); + } else { + asm.emitString("mov." + super.emit()); + } } } - + public static class Neg extends SingleOperandFormat { public Neg(Variable dst, Variable src) { @@ -597,6 +616,49 @@ emitString("exit;" + " " + ""); } + public static class Global { + + private Kind kind; + private String name; + private LabelRef[] targets; + + public Global(Value val, String name, LabelRef[] targets) { + this.kind = val.getKind(); + this.name = name; + this.targets = targets; + } + + private String valueForKind(Kind k) { + switch (k.getTypeChar()) { + case 'i': + return "s32"; + case 'j': + return "s64"; + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + + private String emitTargets(PTXAssembler asm, LabelRef[] refs) { + StringBuffer sb = new StringBuffer(); + + for (int i = 0; i < refs.length; i++) { + sb.append(asm.nameOf(refs[i].label())); + if (i < (refs.length -1)) { + sb.append(", "); + } + } + + return sb.toString(); + } + + public void emit(PTXAssembler asm) { + asm.emitString(".global ." + valueForKind(kind) + + " " + name + "[" + targets.length + "] = " + + "{ " + emitTargets(asm, targets) + " };"); + } + } + public static class Param extends SingleOperandFormat { private boolean lastParameter; @@ -824,4 +886,15 @@ public PTXAddress getPlaceholder() { return null; } + + @Override + public void jmp(Label l) { + String str = nameOf(l); + if (l.equals("?")) { + Thread.dumpStack(); + } + bra(str); + } + + } diff -r 1ec42a9f6149 -r 1f82cda83ced graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/ControlPTXTest.java --- a/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/ControlPTXTest.java Sun Oct 06 15:38:20 2013 +0200 +++ b/graal/com.oracle.graal.compiler.ptx.test/src/com/oracle/graal/compiler/ptx/test/ControlPTXTest.java Sun Oct 06 13:55:09 2013 -0400 @@ -42,10 +42,27 @@ } else { printReport("testSwitchDefault1I: no VALUE"); } + ret = (Integer) invoke(compile("testSwitch1I"), 2); + if (ret != null) { + printReport("testSwitch1I: " + ret); + } else { + printReport("testSwitch1I: no VALUE"); + } + ret = (Integer) invoke(compile("testIfElse1I"), 222); + if (ret != null) { + printReport("testIfElse1I: " + ret); + } else { + printReport("testIfElse1I: no VALUE"); + } + ret = (Integer) invoke(compile("testIfElse2I"), 19, 64); + if (ret != null) { + printReport("testIfElse2I: " + (char) ret.intValue()); + } else { + printReport("testIfElse2I: no VALUE"); + } compile("testStatic"); compile("testCall"); - // compile("testSwitch1I"); - // compile("testLookupSwitch1I"); + compile("testLookupSwitch1I"); } public static int testLoop(int n) { @@ -57,6 +74,24 @@ return sum; } + public static int testIfElse1I(int n) { + if (n > 22) { + return 42; + } else { + return -42; + } + } + + public static int testIfElse2I(int c, int y) { + if (c > 19) { + return (int) 'M'; // millenial + } else if (y > 84) { + return (int) 'Y'; // young + } else { + return (int) 'O'; // old + } + } + public static int testSwitchDefault1I(int a) { switch (a) { default: @@ -78,31 +113,31 @@ public static int testLookupSwitch1I(int a) { switch (a) { case 0: - return 1; + return 10; case 1: - return 2; + return 11; case 2: - return 3; + return 12; case 3: - return 1; + return 13; case 4: - return 2; + return 14; case 5: - return 3; + return 15; case 6: - return 1; + return 16; case 7: - return 2; + return 17; case 8: - return 3; + return 18; case 9: - return 1; + return 19; case 10: - return 2; + return 20; case 11: - return 3; + return 21; default: - return -1; + return 42; } } diff -r 1ec42a9f6149 -r 1f82cda83ced graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXBackend.java --- a/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXBackend.java Sun Oct 06 15:38:20 2013 +0200 +++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXBackend.java Sun Oct 06 13:55:09 2013 -0400 @@ -109,8 +109,8 @@ Buffer codeBuffer = tasm.asm.codeBuffer; // Emit initial boiler-plate directives. - codeBuffer.emitString(".version 1.4"); - codeBuffer.emitString(".target sm_10"); + codeBuffer.emitString(".version 2.1"); + codeBuffer.emitString(".target sm_20"); codeBuffer.emitString0(".entry " + name + " ("); codeBuffer.emitString(""); diff -r 1ec42a9f6149 -r 1f82cda83ced graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java --- a/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java Sun Oct 06 15:38:20 2013 +0200 +++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java Sun Oct 06 13:55:09 2013 -0400 @@ -46,6 +46,8 @@ import com.oracle.graal.lir.ptx.PTXArithmetic.Unary2Op; 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.ReturnNoValOp; import com.oracle.graal.lir.ptx.PTXControlFlow.SequentialSwitchOp; @@ -86,7 +88,9 @@ } } - public PTXLIRGenerator(StructuredGraph graph, CodeCacheProvider runtime, TargetDescription target, FrameMap frameMap, CallingConvention cc, LIR lir) { + public PTXLIRGenerator(StructuredGraph graph, CodeCacheProvider runtime, + TargetDescription target, FrameMap frameMap, + CallingConvention cc, LIR lir) { super(graph, runtime, target, frameMap, cc, lir); lir.spillMoveFactory = new PTXSpillMoveFactory(); int callVariables = cc.getArgumentCount() + (cc.getReturn() == Value.ILLEGAL ? 0 : 1); @@ -333,11 +337,79 @@ } @Override - public Variable emitConditionalMove(Value left, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue) { - // TODO: There is no conventional conditional move instruction in PTX. - // So, this method is changed to throw NYI exception. - // To be revisited if this needs to be really implemented. - throw GraalInternalError.unimplemented("PTXLIRGenerator.emitConditionalMove()"); + public Variable emitConditionalMove(Value left, Value right, + Condition cond, boolean unorderedIsTrue, + Value trueValue, Value falseValue) { + + Condition finalCondition = LIRValueUtil.isVariable(right) ? cond.mirror() : cond; + + boolean mirrored; + mirrored = emitCompare(finalCondition, left, right); + + Variable result = newVariable(trueValue.getKind()); + switch (left.getKind().getStackKind()) { + case Int: + case Long: + case Object: + append(new CondMoveOp(result, finalCondition, + load(trueValue), loadNonConst(falseValue), + nextPredRegNum)); + nextPredRegNum++; + break; + case Float: + case Double: + append(new FloatCondMoveOp(result, finalCondition, unorderedIsTrue, + load(trueValue), load(falseValue), + nextPredRegNum)); + nextPredRegNum++; + break; + default: + throw GraalInternalError.shouldNotReachHere("" + 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, nextPredRegNum)); + break; + case Long: + append(new CompareOp(LCMP, cond, left, right, nextPredRegNum)); + break; + case Object: + append(new CompareOp(ACMP, cond, left, right, nextPredRegNum)); + break; + case Float: + append(new CompareOp(FCMP, cond, left, right, nextPredRegNum)); + break; + case Double: + append(new CompareOp(DCMP, cond, left, right, nextPredRegNum)); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + return mirrored; } diff -r 1ec42a9f6149 -r 1f82cda83ced graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXControlFlow.java --- a/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXControlFlow.java Sun Oct 06 15:38:20 2013 +0200 +++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXControlFlow.java Sun Oct 06 13:55:09 2013 -0400 @@ -22,8 +22,10 @@ */ package com.oracle.graal.lir.ptx; +import static com.oracle.graal.api.code.ValueUtil.*; import static com.oracle.graal.asm.ptx.PTXAssembler.*; import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; +import static com.oracle.graal.lir.LIRValueUtil.*; import static com.oracle.graal.nodes.calc.Condition.*; import com.oracle.graal.api.code.CompilationResult.JumpTable; @@ -97,30 +99,31 @@ } } - @SuppressWarnings("unused") public static class CondMoveOp extends PTXLIRInstruction { @Def({REG, HINT}) protected Value result; @Alive({REG}) protected Value trueValue; @Use({REG, STACK, CONST}) protected Value falseValue; private final Condition condition; + private final int predicate; - public CondMoveOp(Variable result, Condition condition, Variable trueValue, Value falseValue) { + public CondMoveOp(Variable result, Condition condition, + Variable trueValue, Value falseValue, + int predicateRegister) { this.result = result; this.condition = condition; this.trueValue = trueValue; this.falseValue = falseValue; + this.predicate = predicateRegister; } @Override public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { - // cmove(tasm, masm, result, false, condition, false, trueValue, falseValue); - // see 8.3 Predicated Execution p. 61 of PTX ISA 3.1 - throw new InternalError("NYI"); + cmove(tasm, masm, result, false, condition, false, + trueValue, falseValue, predicate); } } - @SuppressWarnings("unused") public static class FloatCondMoveOp extends PTXLIRInstruction { @Def({REG}) protected Value result; @@ -128,20 +131,81 @@ @Alive({REG}) protected Value falseValue; private final Condition condition; private final boolean unorderedIsTrue; + private final int predicate; - public FloatCondMoveOp(Variable result, Condition condition, boolean unorderedIsTrue, Variable trueValue, Variable falseValue) { + public FloatCondMoveOp(Variable result, Condition condition, + boolean unorderedIsTrue, + Variable trueValue, Variable falseValue, + int predicateRegister) { this.result = result; this.condition = condition; this.unorderedIsTrue = unorderedIsTrue; this.trueValue = trueValue; this.falseValue = falseValue; + this.predicate = predicateRegister; } @Override public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { - // cmove(tasm, masm, result, true, condition, unorderedIsTrue, trueValue, falseValue); - // see 8.3 Predicated Execution p. 61 of PTX ISA 3.1 - throw new InternalError("NYI"); + cmove(tasm, masm, result, true, condition, unorderedIsTrue, + trueValue, falseValue, predicate); + } + } + + private static void cmove(TargetMethodAssembler tasm, PTXAssembler asm, + Value result, boolean isFloat, Condition condition, + boolean unorderedIsTrue, + Value trueValue, Value falseValue, + int predicateRegister) { + // check that we don't overwrite an input operand before it is used. + assert !result.equals(trueValue); + + PTXMove.move(tasm, asm, result, falseValue); + cmove(tasm, asm, result, condition, trueValue, predicateRegister); + + if (isFloat) { + if (unorderedIsTrue && !trueOnUnordered(condition)) { + // cmove(tasm, masm, result, ConditionFlag.Parity, trueValue); + throw GraalInternalError.unimplemented(); + } else if (!unorderedIsTrue && trueOnUnordered(condition)) { + // cmove(tasm, masm, result, ConditionFlag.Parity, falseValue); + throw GraalInternalError.unimplemented(); + } + } + } + + private static boolean trueOnUnordered(Condition condition) { + switch (condition) { + case NE: + case EQ: + return false; + case LT: + case GE: + return true; + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + + private static void cmove(TargetMethodAssembler tasm, PTXAssembler asm, + Value result, Condition cond, Value other, + int predicateRegister) { + if (isVariable(other)) { + assert !asVariable(other).equals(asVariable(result)) : + "other already overwritten by previous move"; + + switch (other.getKind()) { + case Int: + new Mov(asVariable(result), other, predicateRegister).emit(asm); + break; + case Long: + new Mov(asVariable(result), other, predicateRegister).emit(asm); + break; + default: + throw new InternalError("unhandled: " + other.getKind()); + } + } else { + throw GraalInternalError.shouldNotReachHere("cmove: not register"); } } @@ -155,7 +219,9 @@ // Number of predicate register that would be set by this instruction. protected int predRegNum; - public SequentialSwitchOp(Constant[] keyConstants, LabelRef[] keyTargets, LabelRef defaultTarget, Value key, Value scratch, int predReg) { + public SequentialSwitchOp(Constant[] keyConstants, + LabelRef[] keyTargets, LabelRef defaultTarget, + Value key, Value scratch, int predReg) { assert keyConstants.length == keyTargets.length; this.keyConstants = keyConstants; this.keyTargets = keyTargets; @@ -214,7 +280,9 @@ // Number of predicate register that would be set by this instruction. protected int predRegNum; - public TableSwitchOp(final int lowKey, final LabelRef defaultTarget, final LabelRef[] targets, Variable index, Variable scratch, int predReg) { + public TableSwitchOp(final int lowKey, final LabelRef defaultTarget, + final LabelRef[] targets, + Variable index, Variable scratch, int predReg) { this.lowKey = lowKey; this.defaultTarget = defaultTarget; this.targets = targets; @@ -225,7 +293,8 @@ @Override public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { - tableswitch(tasm, masm, lowKey, defaultTarget, targets, index, scratch, predRegNum); + tableswitch(tasm, masm, lowKey, defaultTarget, targets, + index, scratch, predRegNum); } } @@ -234,7 +303,9 @@ LabelRef defaultTarget, LabelRef[] targets, Value value, Value scratch, int predNum) { Buffer buf = masm.codeBuffer; + // Compare index against jump table bounds + int highKey = lowKey + targets.length - 1; if (lowKey != 0) { // subtract the low value from the switch value @@ -246,15 +317,21 @@ // Jump to default target if index is not within the jump table if (defaultTarget != null) { - masm.bra(defaultTarget.label().toString(), predNum); + masm.bra(masm.nameOf(defaultTarget.label()), predNum); } // address of jump table int tablePos = buf.position(); + JumpTable jt = new JumpTable(tablePos, lowKey, highKey, 4); + String name = "jumptable" + jt.position; + + new Global(value, name, targets).emit(masm); + + // bra(Value, name); + tasm.compilationResult.addAnnotation(jt); - // PTX: unimp: tableswitch extract } }