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.asm.*;
  34 
  35 // @formatter:off
  36 public enum PTXArithmetic {
  37     IADD, ISUB, IMUL, IDIV, IDIVREM, IREM, IUDIV, IUREM, IAND, IOR, IXOR, ISHL, ISHR, IUSHR,
  38     LADD, LSUB, LMUL, LDIV, LDIVREM, LREM, LUDIV, LUREM, LAND, LOR, LXOR, LSHL, LSHR, LUSHR,
  39     FADD, FSUB, FMUL, FDIV, FAND, FOR, FXOR,
  40     DADD, DSUB, DMUL, DDIV, DAND, DOR, DXOR,
  41     INEG, LNEG,
  42     I2L, L2I, I2B, I2C, I2S,
  43     F2D, D2F,
  44     I2F, I2D, F2I, D2I,
  45     L2F, L2D, F2L, D2L,
  46     MOV_I2F, MOV_L2D, MOV_F2I, MOV_D2L;
  47 
  48 
  49     public static class Op1Reg extends PTXLIRInstruction {
  50         @Opcode private final PTXArithmetic opcode;
  51         @Def({REG, HINT}) protected Value result;
  52         @Use({REG}) protected Value x;
  53 
  54         public Op1Reg(PTXArithmetic opcode, Value result, Value x) {
  55             this.opcode = opcode;
  56             this.result = result;
  57             this.x = x;
  58         }
  59 
  60         @Override
  61         public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) {
  62             emit(tasm, masm, opcode, result, x, null);
  63         }
  64     }
  65 
  66     public static class Op1Stack extends PTXLIRInstruction {
  67         @Opcode private final PTXArithmetic opcode;
  68         @Def({REG, HINT}) protected Value result;
  69         @Use({REG, STACK, CONST}) protected Value x;
  70 
  71         public Op1Stack(PTXArithmetic opcode, Value result, Value x) {
  72             this.opcode = opcode;
  73             this.result = result;
  74             this.x = x;
  75         }
  76 
  77         @Override
  78         public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) {
  79             emit(tasm, masm, opcode, result, x, null);
  80         }
  81     }
  82 
  83     public static class Op2Stack extends PTXLIRInstruction {
  84         @Opcode private final PTXArithmetic opcode;
  85         @Def({REG, HINT}) protected Value result;
  86         @Use({REG, STACK, CONST}) protected Value x;
  87         @Alive({REG, STACK, CONST}) protected Value y;
  88 
  89         public Op2Stack(PTXArithmetic opcode, Value result, Value x, Value y) {
  90             this.opcode = opcode;
  91             this.result = result;
  92             this.x = x;
  93             this.y = y;
  94         }
  95 
  96         @Override
  97         public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) {
  98             emit(tasm, masm, opcode, result, x, y, null);
  99         }
 100 
 101         @Override
 102         public void verify() {
 103             super.verify();
 104             verifyKind(opcode, result, x, y);
 105         }
 106     }
 107 
 108     public static class Op2Reg extends PTXLIRInstruction {
 109         @Opcode private final PTXArithmetic opcode;
 110         @Def({REG, HINT}) protected Value result;
 111         @Use({REG, STACK, CONST}) protected Value x;
 112         @Alive({REG, CONST}) protected Value y;
 113 
 114         public Op2Reg(PTXArithmetic opcode, Value result, Value x, Value y) {
 115             this.opcode = opcode;
 116             this.result = result;
 117             this.x = x;
 118             this.y = y;
 119         }
 120 
 121         @Override
 122         public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) {
 123             emit(tasm, masm, opcode, result, x, y, null);
 124         }
 125 
 126         @Override
 127         public void verify() {
 128             super.verify();
 129             verifyKind(opcode, result, x, y);
 130         }
 131     }
 132 
 133     public static class Op2RegCommutative extends PTXLIRInstruction {
 134         @Opcode private final PTXArithmetic opcode;
 135         @Def({REG, HINT}) protected Value result;
 136         @Use({REG, STACK, CONST}) protected Value x;
 137         @Use({REG, CONST}) protected Value y;
 138 
 139         public Op2RegCommutative(PTXArithmetic opcode, Value result, Value x, Value y) {
 140             this.opcode = opcode;
 141             this.result = result;
 142             this.x = x;
 143             this.y = y;
 144         }
 145 
 146         @Override
 147         public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) {
 148             if (sameRegister(result, y)) {
 149                 emit(tasm, masm, opcode, result, x, null);
 150             } else {
 151                 PTXMove.move(tasm, masm, result, x);
 152                 emit(tasm, masm, opcode, result, y, null);
 153             }
 154         }
 155 
 156         @Override
 157         protected void verify() {
 158             super.verify();
 159             verifyKind(opcode, result, x, y);
 160         }
 161     }
 162 
 163     public static class ShiftOp extends PTXLIRInstruction {
 164         @Opcode private final PTXArithmetic opcode;
 165         @Def({REG, HINT}) protected Value result;
 166         @Use({REG, STACK, CONST}) protected Value x;
 167         @Alive({REG, CONST}) protected Value y;
 168 
 169         public ShiftOp(PTXArithmetic opcode, Value result, Value x, Value y) {
 170             this.opcode = opcode;
 171             this.result = result;
 172             this.x = x;
 173             this.y = y;
 174         }
 175 
 176         @Override
 177         public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) {
 178             emit(tasm, masm, opcode, result, x, y, null);
 179         }
 180 
 181         @Override
 182         public void verify() {
 183             super.verify();
 184             verifyKind(opcode, result, x, x);
 185             assert y.getKind().getStackKind() == Kind.Int;
 186         }
 187     }
 188 
 189     public static class DivOp extends PTXLIRInstruction {
 190         @Opcode private final PTXArithmetic opcode;
 191         @Def protected Value result;
 192         @Use protected Value x;
 193         @Alive protected Value y;
 194         @State protected LIRFrameState state;
 195 
 196         public DivOp(PTXArithmetic opcode, Value result, Value x, Value y, LIRFrameState state) {
 197             this.opcode = opcode;
 198             this.result = result;
 199             this.x = x;
 200             this.y = y;
 201             this.state = state;
 202         }
 203 
 204         @Override
 205         public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) {
 206             emit(tasm, masm, opcode, result, y, state);
 207         }
 208 
 209         @Override
 210         protected void verify() {
 211             super.verify();
 212             verifyKind(opcode, result, x, y);
 213         }
 214     }
 215 
 216 
 217     @SuppressWarnings("unused")
 218     protected static void emit(TargetMethodAssembler tasm, PTXAssembler masm, PTXArithmetic opcode, Value result) {
 219         switch (opcode) {
 220             default:   throw GraalInternalError.shouldNotReachHere();
 221         }
 222     }
 223 
 224     public static void emit(TargetMethodAssembler tasm, PTXAssembler masm, PTXArithmetic opcode, Value dst, Value src, LIRFrameState info) {
 225         int exceptionOffset = -1;
 226         if (isRegister(src)) {
 227             Register a = asIntReg(src);
 228             Register d = asIntReg(dst);
 229             switch (opcode) {
 230                 case INEG: masm.neg_s32(d, a); break;
 231                 default:
 232                     throw GraalInternalError.shouldNotReachHere();
 233             }
 234         } else if (isConstant(src)) {
 235             switch (opcode) {
 236                 case ISUB: masm.sub_s32(asIntReg(dst), asIntReg(dst), tasm.asIntConst(src)); break;
 237                 case IAND: masm.and_b32(asIntReg(dst), asIntReg(dst), tasm.asIntConst(src)); break;
 238                 default:   throw GraalInternalError.shouldNotReachHere();
 239             }
 240         } else {
 241             switch (opcode) {
 242                 default:   throw GraalInternalError.shouldNotReachHere();
 243             }
 244         }
 245 
 246         if (info != null) {
 247             assert exceptionOffset != -1;
 248             tasm.recordImplicitException(exceptionOffset, info);
 249         }
 250     }
 251 
 252     public static void emit(TargetMethodAssembler tasm, PTXAssembler masm, PTXArithmetic opcode, Value dst, Value src1, Value src2, LIRFrameState info) {
 253         int exceptionOffset = -1;
 254         if (isConstant(src1)) {
 255             int      a = tasm.asIntConst(src1);
 256             Register b = asIntReg(src2);
 257             Register d = asIntReg(dst);
 258             switch (opcode) {
 259             case ISUB:  masm.sub_s32(d, a, b); break;
 260             case IAND:  masm.and_b32(d, b, a); break;
 261             default:    throw GraalInternalError.shouldNotReachHere();
 262             }
 263         } else if (isConstant(src2)) {
 264             Register a = asIntReg(src1);
 265             int      b = tasm.asIntConst(src2);
 266             Register d = asIntReg(dst);
 267             switch (opcode) {
 268             case IADD:  masm.add_s32(d, a, b); break;
 269             case IAND:  masm.and_b32(d, a, b); break;
 270             case IUSHR: masm.shr_u32(d, a, b); break;
 271             default:    throw GraalInternalError.shouldNotReachHere();
 272             }
 273         } else {
 274             Register a = asIntReg(src1);
 275             Register b = asIntReg(src2);
 276             Register d = asIntReg(dst);
 277             switch (opcode) {
 278             case IADD:  masm.add_s32(d, a, b); break;
 279             case ISUB:  masm.sub_s32(d, a, b); break;
 280             case IMUL:  masm.mul_s32(d, a, b); break;
 281             default:    throw GraalInternalError.shouldNotReachHere();
 282             }
 283         }
 284 
 285         if (info != null) {
 286             assert exceptionOffset != -1;
 287             tasm.recordImplicitException(exceptionOffset, info);
 288         }
 289     }
 290 
 291     private static void verifyKind(PTXArithmetic opcode, Value result, Value x, Value y) {
 292         assert (opcode.name().startsWith("I") && result.getKind() == Kind.Int && x.getKind().getStackKind() == Kind.Int && y.getKind().getStackKind() == Kind.Int)
 293             || (opcode.name().startsWith("L") && result.getKind() == Kind.Long && x.getKind() == Kind.Long && y.getKind() == Kind.Long)
 294             || (opcode.name().startsWith("F") && result.getKind() == Kind.Float && x.getKind() == Kind.Float && y.getKind() == Kind.Float)
 295             || (opcode.name().startsWith("D") && result.getKind() == Kind.Double && x.getKind() == Kind.Double && y.getKind() == Kind.Double);
 296     }
 297 }