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.*; 26 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*; 27 28 import com.oracle.graal.api.code.*; 29 import com.oracle.graal.api.meta.*; 30 import com.oracle.graal.asm.ptx.*; 31 import com.oracle.graal.graph.*; 32 import com.oracle.graal.lir.*; 33 import com.oracle.graal.lir.LIRInstruction.Def; 34 import com.oracle.graal.lir.LIRInstruction.Opcode; 35 import com.oracle.graal.lir.LIRInstruction.Use; 36 import com.oracle.graal.lir.asm.*; 37 38 // @formatter:off 39 public enum PTXArithmetic { 40 IADD, ISUB, IMUL, IDIV, IDIVREM, IREM, IUDIV, IUREM, IAND, IOR, IXOR, ISHL, ISHR, IUSHR, 41 LADD, LSUB, LMUL, LDIV, LDIVREM, LREM, LUDIV, LUREM, LAND, LOR, LXOR, LSHL, LSHR, LUSHR, 42 FADD, FSUB, FMUL, FDIV, FREM, FAND, FOR, FXOR, 43 DADD, DSUB, DMUL, DDIV, DREM, DAND, DOR, DXOR, 44 INEG, LNEG, FNEG, DNEG, 45 I2L, L2I, I2B, I2C, I2S, 46 F2D, D2F, 47 I2F, I2D, F2I, D2I, 48 L2F, L2D, F2L, D2L, 49 MOV_I2F, MOV_L2D, MOV_F2I, MOV_D2L; 50 51 52 /** 53 * Unary operation with separate source and destination operand. 54 */ 55 public static class Unary2Op extends PTXLIRInstruction { 56 @Opcode private final PTXArithmetic opcode; 57 @Def({REG}) protected AllocatableValue result; 58 @Use({REG, STACK}) protected AllocatableValue x; 59 60 public Unary2Op(PTXArithmetic opcode, AllocatableValue result, AllocatableValue x) { 61 this.opcode = opcode; 62 this.result = result; 63 this.x = x; 64 } 65 66 @Override 67 public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { 68 PTXMove.move(tasm, masm, result, x); 69 emit(tasm, masm, opcode, result, x, null); 70 } 71 } 72 73 /** 74 * Unary operation with single operand for source and destination. 75 */ 76 public static class Unary1Op extends PTXLIRInstruction { 77 @Opcode private final PTXArithmetic opcode; 78 @Def({REG, HINT}) protected AllocatableValue result; 79 @Use({REG, STACK}) protected AllocatableValue x; 80 81 public Unary1Op(PTXArithmetic opcode, AllocatableValue result, AllocatableValue x) { 82 this.opcode = opcode; 83 this.result = result; 84 this.x = x; 85 } 86 87 @Override 88 public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { 89 emit(tasm, masm, opcode, result); 90 } 91 } 92 93 public static class Op1Reg extends PTXLIRInstruction { 94 @Opcode private final PTXArithmetic opcode; 95 @Def({REG, HINT}) protected Value result; 96 @Use({REG}) protected Value x; 97 98 public Op1Reg(PTXArithmetic opcode, Value result, Value x) { 99 this.opcode = opcode; 100 this.result = result; 101 this.x = x; 102 } 103 104 @Override 105 public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { 106 emit(tasm, masm, opcode, result, x, null); 107 } 108 } 109 110 public static class Op1Stack extends PTXLIRInstruction { 111 @Opcode private final PTXArithmetic opcode; 112 @Def({REG, HINT}) protected Value result; 113 @Use({REG, STACK, CONST}) protected Value x; 114 115 public Op1Stack(PTXArithmetic opcode, Value result, Value x) { 116 this.opcode = opcode; 117 this.result = result; 118 this.x = x; 119 } 120 121 @Override 122 public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { 123 emit(tasm, masm, opcode, result, x, null); 124 } 125 } 126 127 public static class Op2Stack extends PTXLIRInstruction { 128 @Opcode private final PTXArithmetic opcode; 129 @Def({REG, HINT}) protected Value result; 130 @Use({REG, STACK, CONST}) protected Value x; 131 @Alive({REG, STACK, CONST}) protected Value y; 132 133 public Op2Stack(PTXArithmetic opcode, Value result, Value x, Value y) { 134 this.opcode = opcode; 135 this.result = result; 136 this.x = x; 137 this.y = y; 138 } 139 140 @Override 141 public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { 142 emit(tasm, masm, opcode, result, x, y, null); 143 } 144 145 @Override 146 public void verify() { 147 super.verify(); 148 verifyKind(opcode, result, x, y); 149 } 150 } 151 152 public static class Op2Reg extends PTXLIRInstruction { 153 @Opcode private final PTXArithmetic opcode; 154 @Def({REG, HINT}) protected Value result; 155 @Use({REG, STACK, CONST}) protected Value x; 156 @Alive({REG, CONST}) protected Value y; 157 158 public Op2Reg(PTXArithmetic opcode, Value result, Value x, Value y) { 159 this.opcode = opcode; 160 this.result = result; 161 this.x = x; 162 this.y = y; 163 } 164 165 @Override 166 public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { 167 emit(tasm, masm, opcode, result, x, y, null); 168 } 169 170 @Override 171 public void verify() { 172 super.verify(); 173 verifyKind(opcode, result, x, y); 174 } 175 } 176 177 public static class Op2RegCommutative extends PTXLIRInstruction { 178 @Opcode private final PTXArithmetic opcode; 179 @Def({REG, HINT}) protected Value result; 180 @Use({REG, STACK, CONST}) protected Value x; 181 @Use({REG, CONST}) protected Value y; 182 183 public Op2RegCommutative(PTXArithmetic opcode, Value result, Value x, Value y) { 184 this.opcode = opcode; 185 this.result = result; 186 this.x = x; 187 this.y = y; 188 } 189 190 @Override 191 public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { 192 if (sameRegister(result, y)) { 193 emit(tasm, masm, opcode, result, x, null); 194 } else { 195 PTXMove.move(tasm, masm, result, x); 196 emit(tasm, masm, opcode, result, y, null); 197 } 198 } 199 200 @Override 201 protected void verify() { 202 super.verify(); 203 verifyKind(opcode, result, x, y); 204 } 205 } 206 207 public static class ShiftOp extends PTXLIRInstruction { 208 @Opcode private final PTXArithmetic opcode; 209 @Def({REG, HINT}) protected Value result; 210 @Use({REG, STACK, CONST}) protected Value x; 211 @Alive({REG, CONST}) protected Value y; 212 213 public ShiftOp(PTXArithmetic opcode, Value result, Value x, Value y) { 214 this.opcode = opcode; 215 this.result = result; 216 this.x = x; 217 this.y = y; 218 } 219 220 @Override 221 public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { 222 emit(tasm, masm, opcode, result, x, y, null); 223 } 224 225 @Override 226 public void verify() { 227 super.verify(); 228 verifyKind(opcode, result, x, x); 229 assert y.getKind().getStackKind() == Kind.Int; 230 } 231 } 232 233 public static class DivOp extends PTXLIRInstruction { 234 @Opcode private final PTXArithmetic opcode; 235 @Def protected Value result; 236 @Use protected Value x; 237 @Alive protected Value y; 238 @State protected LIRFrameState state; 239 240 public DivOp(PTXArithmetic opcode, Value result, Value x, Value y, LIRFrameState state) { 241 this.opcode = opcode; 242 this.result = result; 243 this.x = x; 244 this.y = y; 245 this.state = state; 246 } 247 248 @Override 249 public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) { 250 emit(tasm, masm, opcode, result, y, state); 251 } 252 253 @Override 254 protected void verify() { 255 super.verify(); 256 verifyKind(opcode, result, x, y); 257 } 258 } 259 260 protected static void emit(TargetMethodAssembler tasm, PTXAssembler masm, PTXArithmetic opcode, Value result) { 261 switch (opcode) { 262 case L2I: masm.cvt_s32_s64(asLongReg(result), asIntReg(result)); break; 263 case I2C: masm.cvt_b16_s32(asIntReg(result), asIntReg(result)); break; 264 default: 265 throw GraalInternalError.shouldNotReachHere("missing: " + opcode); 266 } 267 } 268 269 public static void emit(TargetMethodAssembler tasm, PTXAssembler masm, PTXArithmetic opcode, Value dst, Value src, LIRFrameState info) { 270 int exceptionOffset = -1; 271 if (isRegister(src)) { 272 Register a = asIntReg(src); 273 Register d = asIntReg(dst); 274 switch (opcode) { 275 case INEG: masm.neg_s32(d, a); break; 276 case FNEG: masm.neg_f32(d, a); break; 277 case DNEG: masm.neg_f64(d, a); break; 278 case I2L: masm.cvt_s64_s32(d, a); break; 279 case I2C: masm.cvt_b16_s32(d, a); break; 280 case I2B: masm.cvt_s8_s32(d, a); break; 281 case I2F: masm.cvt_f32_s32(d, a); break; 282 case I2D: masm.cvt_f64_s32(d, a); break; 283 case F2I: masm.cvt_s32_f32(d, a); break; 284 case F2L: masm.cvt_s64_f32(d, a); break; 285 case F2D: masm.cvt_f64_f32(d, a); break; 286 case D2I: masm.cvt_s32_f64(d, a); break; 287 case D2L: masm.cvt_s64_f64(d, a); break; 288 case D2F: masm.cvt_f32_f64(d, a); break; 289 default: 290 throw GraalInternalError.shouldNotReachHere("missing: " + opcode); 291 } 292 } else if (isConstant(src)) { 293 switch (opcode) { 294 case ISUB: masm.sub_s32(asIntReg(dst), asIntReg(dst), tasm.asIntConst(src)); break; 295 case IAND: masm.and_b32(asIntReg(dst), asIntReg(dst), tasm.asIntConst(src)); break; 296 default: throw GraalInternalError.shouldNotReachHere(); 297 } 298 } else { 299 switch (opcode) { 300 default: throw GraalInternalError.shouldNotReachHere(); 301 } 302 } 303 304 if (info != null) { 305 assert exceptionOffset != -1; 306 tasm.recordImplicitException(exceptionOffset, info); 307 } 308 } 309 310 public static void emit(TargetMethodAssembler tasm, PTXAssembler masm, PTXArithmetic opcode, Value dst, Value src1, Value src2, LIRFrameState info) { 311 int exceptionOffset = -1; 312 if (isConstant(src1)) { 313 switch (opcode) { 314 case ISUB: masm.sub_s32(asIntReg(dst), tasm.asIntConst(src1), asIntReg(src2)); break; 315 case IAND: masm.and_b32(asIntReg(dst), asIntReg(src2), tasm.asIntConst(src1)); break; 316 case IDIV: masm.div_s32(asIntReg(dst), tasm.asIntConst(src1), asIntReg(src2)); break; 317 case FSUB: masm.sub_f32(asFloatReg(dst), tasm.asFloatConst(src1), asFloatReg(src2)); break; 318 case FDIV: masm.div_f32(asFloatReg(dst), tasm.asFloatConst(src1), asFloatReg(src2)); break; 319 case DSUB: masm.sub_f64(asDoubleReg(dst), tasm.asDoubleConst(src1), asDoubleReg(src2)); break; 320 case DDIV: masm.div_f64(asDoubleReg(dst), tasm.asDoubleConst(src1), asDoubleReg(src2)); break; 321 default: 322 throw GraalInternalError.shouldNotReachHere(); 323 } 324 } else if (isConstant(src2)) { 325 switch (opcode) { 326 case IADD: masm.add_s32(asIntReg(dst), asIntReg(src1), tasm.asIntConst(src2)); break; 327 case ISUB: masm.sub_s32(asIntReg(dst), asIntReg(src1), tasm.asIntConst(src2)); break; 328 case IMUL: masm.mul_s32(asIntReg(dst), asIntReg(src1), tasm.asIntConst(src2)); break; 329 case IAND: masm.and_b32(asIntReg(dst), asIntReg(src1), tasm.asIntConst(src2)); break; 330 case ISHL: masm.shl_s32(asIntReg(dst), asIntReg(src1), tasm.asIntConst(src2)); break; 331 case ISHR: masm.shr_s32(asIntReg(dst), asIntReg(src1), tasm.asIntConst(src2)); break; 332 case IUSHR: masm.shr_u32(asIntReg(dst), asIntReg(src1), tasm.asIntConst(src2)); break; 333 case IXOR: masm.xor_b32(asIntReg(dst), asIntReg(src1), tasm.asIntConst(src2)); break; 334 case LXOR: masm.xor_b64(asLongReg(dst), asLongReg(src1), tasm.asLongConst(src2)); break; 335 case LUSHR: masm.shr_u64(asLongReg(dst), asLongReg(src1), tasm.asLongConst(src2)); break; 336 case FADD: masm.add_f32(asFloatReg(dst), asFloatReg(src1), tasm.asFloatConst(src2)); break; 337 case FMUL: masm.mul_f32(asFloatReg(dst), asFloatReg(src1), tasm.asFloatConst(src2)); break; 338 case FDIV: masm.div_f32(asFloatReg(dst), asFloatReg(src1), tasm.asFloatConst(src2)); break; 339 case DADD: masm.add_f64(asDoubleReg(dst), asDoubleReg(src1), tasm.asDoubleConst(src2)); break; 340 case DMUL: masm.mul_f64(asDoubleReg(dst), asDoubleReg(src1), tasm.asDoubleConst(src2)); break; 341 case DDIV: masm.div_f64(asDoubleReg(dst), asDoubleReg(src1), tasm.asDoubleConst(src2)); break; 342 default: 343 throw GraalInternalError.shouldNotReachHere(); 344 } 345 } else { 346 switch (opcode) { 347 case IADD: masm.add_s32(asIntReg(dst), asIntReg(src1), asIntReg(src2)); break; 348 case ISUB: masm.sub_s32(asIntReg(dst), asIntReg(src1), asIntReg(src2)); break; 349 case IMUL: masm.mul_s32(asIntReg(dst), asIntReg(src1), asIntReg(src2)); break; 350 case IDIV: masm.div_s32(asIntReg(dst), asIntReg(src1), asIntReg(src2)); break; 351 case IAND: masm.and_b32(asIntReg(dst), asIntReg(src1), asIntReg(src2)); break; 352 case IOR: masm.or_b32 (asIntReg(dst), asIntReg(src1), asIntReg(src2)); break; 353 case IXOR: masm.xor_b32(asIntReg(dst), asIntReg(src1), asIntReg(src2)); break; 354 case ISHL: masm.shl_s32(asIntReg(dst), asIntReg(src1), asIntReg(src2)); break; 355 case ISHR: masm.shr_s32(asIntReg(dst), asIntReg(src1), asIntReg(src2)); break; 356 case IUSHR: masm.shr_u32(asIntReg(dst), asIntReg(src1), asIntReg(src2)); break; 357 case IREM: masm.rem_s32(asIntReg(dst), asIntReg(src1), asIntReg(src2)); break; 358 case LADD: masm.add_s64(asLongReg(dst), asLongReg(src1), asLongReg(src2)); break; 359 case LSUB: masm.sub_s64(asLongReg(dst), asLongReg(src1), asLongReg(src2)); break; 360 case LMUL: masm.mul_s64(asLongReg(dst), asLongReg(src1), asLongReg(src2)); break; 361 case LDIV: masm.div_s64(asLongReg(dst), asLongReg(src1), asLongReg(src2)); break; 362 case LAND: masm.and_b64(asLongReg(dst), asLongReg(src1), asLongReg(src2)); break; 363 case LOR: masm.or_b64 (asLongReg(dst), asLongReg(src1), asLongReg(src2)); break; 364 case LXOR: masm.xor_b64(asLongReg(dst), asLongReg(src1), asLongReg(src2)); break; 365 case LSHL: masm.shl_s64(asLongReg(dst), asLongReg(src1), asLongReg(src2)); break; 366 case LSHR: masm.shr_s64(asLongReg(dst), asLongReg(src1), asLongReg(src2)); break; 367 case LUSHR: masm.shr_u64(asLongReg(dst), asLongReg(src1), asLongReg(src2)); break; 368 case LREM: masm.rem_s64(asLongReg(dst), asLongReg(src1), asLongReg(src2)); break; 369 case FADD: masm.add_f32(asFloatReg(dst), asFloatReg(src1), asFloatReg(src2)); break; 370 case FSUB: masm.sub_f32(asFloatReg(dst), asFloatReg(src1), asFloatReg(src2)); break; 371 case FMUL: masm.mul_f32(asFloatReg(dst), asFloatReg(src1), asFloatReg(src2)); break; 372 case FDIV: masm.div_f32(asFloatReg(dst), asFloatReg(src1), asFloatReg(src2)); break; 373 case FREM: masm.div_f32(asFloatReg(dst), asFloatReg(src1), asFloatReg(src2)); break; 374 case DADD: masm.add_f64(asDoubleReg(dst), asDoubleReg(src1), asDoubleReg(src2)); break; 375 case DSUB: masm.sub_f64(asDoubleReg(dst), asDoubleReg(src1), asDoubleReg(src2)); break; 376 case DMUL: masm.mul_f64(asDoubleReg(dst), asDoubleReg(src1), asDoubleReg(src2)); break; 377 case DDIV: masm.div_f64(asDoubleReg(dst), asDoubleReg(src1), asDoubleReg(src2)); break; 378 case DREM: masm.div_f64(asDoubleReg(dst), asDoubleReg(src1), asDoubleReg(src2)); break; 379 default: 380 throw GraalInternalError.shouldNotReachHere("missing: " + opcode); 381 } 382 } 383 384 if (info != null) { 385 assert exceptionOffset != -1; 386 tasm.recordImplicitException(exceptionOffset, info); 387 } 388 } 389 390 private static void verifyKind(PTXArithmetic opcode, Value result, Value x, Value y) { 391 assert (opcode.name().startsWith("I") && result.getKind() == Kind.Int && x.getKind().getStackKind() == Kind.Int && y.getKind().getStackKind() == Kind.Int) 392 || (opcode.name().startsWith("L") && result.getKind() == Kind.Long && x.getKind() == Kind.Long && y.getKind() == Kind.Long) 393 || (opcode.name().startsWith("F") && result.getKind() == Kind.Float && x.getKind() == Kind.Float && y.getKind() == Kind.Float) 394 || (opcode.name().startsWith("D") && result.getKind() == Kind.Double && x.getKind() == Kind.Double && y.getKind() == Kind.Double); 395 } 396 }