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 }