1 /* 2 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package com.oracle.graal.lir.ptx; 24 25 import static com.oracle.graal.api.code.ValueUtil.asIntReg; 26 import static com.oracle.graal.api.code.ValueUtil.asLongReg; 27 import static com.oracle.graal.api.code.ValueUtil.asObjectReg; 28 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; 29 30 import com.oracle.graal.api.code.Register; 31 import com.oracle.graal.api.code.CompilationResult.JumpTable; 32 import com.oracle.graal.api.meta.Constant; 33 import com.oracle.graal.api.meta.Kind; 34 import com.oracle.graal.api.meta.Value; 35 import com.oracle.graal.asm.Buffer; 36 import com.oracle.graal.asm.Label; 37 import com.oracle.graal.asm.NumUtil; 38 import com.oracle.graal.asm.ptx.AbstractPTXAssembler; 39 import com.oracle.graal.asm.ptx.PTXAssembler; 40 import com.oracle.graal.graph.GraalInternalError; 41 import com.oracle.graal.lir.LabelRef; 42 import com.oracle.graal.lir.StandardOp; 43 import com.oracle.graal.lir.StandardOp.FallThroughOp; 44 import com.oracle.graal.lir.Variable; 45 import com.oracle.graal.lir.asm.TargetMethodAssembler; 46 import com.oracle.graal.nodes.calc.Condition; 47 48 public class PTXControlFlow { 49 50 public static class ReturnOp extends PTXLIRInstruction { 51 52 @Use({REG, ILLEGAL}) protected Value x; 53 54 public ReturnOp(Value x) { 55 this.x = x; 56 } 57 58 @Override 59 public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { 60 if (tasm.frameContext != null) { 61 tasm.frameContext.leave(tasm); 62 } 63 masm.exit(); 64 } 65 } 66 67 public static class BranchOp extends PTXLIRInstruction implements StandardOp.BranchOp { 68 69 protected Condition condition; 70 protected LabelRef destination; 71 72 public BranchOp(Condition condition, LabelRef destination) { 73 this.condition = condition; 74 this.destination = destination; 75 } 76 77 @Override 78 public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { 79 masm.at(); 80 Label l = destination.label(); 81 l.addPatchAt(tasm.asm.codeBuffer.position()); 82 String target = l.isBound() ? "L" + l.toString() : AbstractPTXAssembler.UNBOUND_TARGET; 83 masm.bra(target); 84 } 85 86 @Override 87 public LabelRef destination() { 88 return destination; 89 } 90 91 @Override 92 public void negate(LabelRef newDestination) { 93 destination = newDestination; 94 condition = condition.negate(); 95 } 96 } 97 98 public static class CondMoveOp extends PTXLIRInstruction { 99 @Def({REG, HINT}) protected Value result; 100 @Alive({REG}) protected Value trueValue; 101 @Use({REG, STACK, CONST}) protected Value falseValue; 102 private final Condition condition; 103 104 public CondMoveOp(Variable result, Condition condition, Variable trueValue, Value falseValue) { 105 this.result = result; 106 this.condition = condition; 107 this.trueValue = trueValue; 108 this.falseValue = falseValue; 109 } 110 111 @Override 112 public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { 113 // cmove(tasm, masm, result, false, condition, false, trueValue, falseValue); 114 // see 8.3 Predicated Execution p. 61 of PTX ISA 3.1 115 throw new InternalError("NYI"); 116 } 117 } 118 119 120 public static class FloatCondMoveOp extends PTXLIRInstruction { 121 @Def({REG}) protected Value result; 122 @Alive({REG}) protected Value trueValue; 123 @Alive({REG}) protected Value falseValue; 124 private final Condition condition; 125 private final boolean unorderedIsTrue; 126 127 public FloatCondMoveOp(Variable result, Condition condition, boolean unorderedIsTrue, Variable trueValue, Variable falseValue) { 128 this.result = result; 129 this.condition = condition; 130 this.unorderedIsTrue = unorderedIsTrue; 131 this.trueValue = trueValue; 132 this.falseValue = falseValue; 133 } 134 135 @Override 136 public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { 137 // cmove(tasm, masm, result, true, condition, unorderedIsTrue, trueValue, falseValue); 138 // see 8.3 Predicated Execution p. 61 of PTX ISA 3.1 139 throw new InternalError("NYI"); 140 } 141 } 142 143 public static class SequentialSwitchOp extends PTXLIRInstruction implements FallThroughOp { 144 @Use({CONST}) protected Constant[] keyConstants; 145 private final LabelRef[] keyTargets; 146 private LabelRef defaultTarget; 147 @Alive({REG}) protected Value key; 148 @Temp({REG, ILLEGAL}) protected Value scratch; 149 150 public SequentialSwitchOp(Constant[] keyConstants, LabelRef[] keyTargets, LabelRef defaultTarget, Value key, Value scratch) { 151 assert keyConstants.length == keyTargets.length; 152 this.keyConstants = keyConstants; 153 this.keyTargets = keyTargets; 154 this.defaultTarget = defaultTarget; 155 this.key = key; 156 this.scratch = scratch; 157 } 158 159 @Override 160 public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { 161 if (key.getKind() == Kind.Int) { 162 Register intKey = asIntReg(key); 163 for (int i = 0; i < keyConstants.length; i++) { 164 if (tasm.runtime.needsDataPatch(keyConstants[i])) { 165 tasm.recordDataReferenceInCode(keyConstants[i], 0, true); 166 } 167 long lc = keyConstants[i].asLong(); 168 assert NumUtil.isInt(lc); 169 masm.setp_eq_s32((int)lc, intKey); 170 masm.at(); 171 Label l = keyTargets[i].label(); 172 l.addPatchAt(tasm.asm.codeBuffer.position()); 173 String target = l.isBound() ? "L" + l.toString() : AbstractPTXAssembler.UNBOUND_TARGET; 174 masm.bra(target); 175 } 176 } else if (key.getKind() == Kind.Long) { 177 Register longKey = asLongReg(key); 178 for (int i = 0; i < keyConstants.length; i++) { 179 masm.setp_eq_s64(tasm.asLongConst(keyConstants[i]), longKey); 180 masm.at(); 181 Label l = keyTargets[i].label(); 182 l.addPatchAt(tasm.asm.codeBuffer.position()); 183 String target = l.isBound() ? "L" + l.toString() : AbstractPTXAssembler.UNBOUND_TARGET; 184 masm.bra(target); 185 } 186 } else if (key.getKind() == Kind.Object) { 187 Register intKey = asObjectReg(key); 188 Register temp = asObjectReg(scratch); 189 for (int i = 0; i < keyConstants.length; i++) { 190 PTXMove.move(tasm, masm, temp.asValue(Kind.Object), keyConstants[i]); 191 masm.setp_eq_u32(intKey, temp); 192 masm.at(); 193 masm.bra(keyTargets[i].label().toString()); 194 } 195 } else { 196 throw new GraalInternalError("sequential switch only supported for int, long and object"); 197 } 198 if (defaultTarget != null) { 199 masm.jmp(defaultTarget.label()); 200 } else { 201 // masm.hlt(); 202 } 203 } 204 205 @Override 206 public LabelRef fallThroughTarget() { 207 return defaultTarget; 208 } 209 210 @Override 211 public void setFallThroughTarget(LabelRef target) { 212 defaultTarget = target; 213 } 214 } 215 216 public static class TableSwitchOp extends PTXLIRInstruction { 217 private final int lowKey; 218 private final LabelRef defaultTarget; 219 private final LabelRef[] targets; 220 @Alive protected Value index; 221 @Temp protected Value scratch; 222 223 public TableSwitchOp(final int lowKey, final LabelRef defaultTarget, final LabelRef[] targets, 224 Variable index, Variable scratch) { 225 this.lowKey = lowKey; 226 this.defaultTarget = defaultTarget; 227 this.targets = targets; 228 this.index = index; 229 this.scratch = scratch; 230 } 231 232 @Override 233 public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { 234 tableswitch(tasm, masm, lowKey, defaultTarget, targets, asIntReg(index), asLongReg(scratch)); 235 } 236 } 237 238 private static void tableswitch(TargetMethodAssembler tasm, PTXAssembler masm, int lowKey, 239 LabelRef defaultTarget, LabelRef[] targets, 240 Register value, Register scratch) { 241 Buffer buf = masm.codeBuffer; 242 // Compare index against jump table bounds 243 int highKey = lowKey + targets.length - 1; 244 if (lowKey != 0) { 245 // subtract the low value from the switch value 246 masm.sub_s32(value, value, lowKey); 247 masm.setp_gt_s32(value, highKey - lowKey); 248 } else { 249 masm.setp_gt_s32(value, highKey); 250 } 251 252 // Jump to default target if index is not within the jump table 253 if (defaultTarget != null) { 254 masm.at(); 255 masm.bra(defaultTarget.label().toString()); 256 } 257 258 // address of jump table 259 int tablePos = buf.position(); 260 261 JumpTable jt = new JumpTable(tablePos, lowKey, highKey, 4); 262 tasm.compilationResult.addAnnotation(jt); 263 264 System.err.println("PTX: unimp: tableswitch"); 265 } 266 }