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.hsail;
  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.meta.*;
  29 import com.oracle.graal.asm.hsail.*;
  30 import com.oracle.graal.graph.*;
  31 import com.oracle.graal.lir.*;
  32 import com.oracle.graal.lir.asm.CompilationResultBuilder;
  33 
  34 /**
  35  * Defines arithmetic instruction nodes.
  36  */
  37 public enum HSAILArithmetic {
  38     ABS,
  39     CALL,
  40     CEIL,
  41     FDIV,
  42     FLOOR,
  43     FREM,
  44     DADD,
  45     DDIV,
  46     DMUL,
  47     DNEG,
  48     DREM,
  49     DSUB,
  50     FADD,
  51     FMUL,
  52     FNEG,
  53     FSUB,
  54     IADD,
  55     IAND,
  56     ICARRY,
  57     IDIV,
  58     IMAX,
  59     IMIN,
  60     IMUL,
  61     INEG,
  62     INOT,
  63     IOR,
  64     IREM,
  65     ISHL,
  66     ISHR,
  67     ISUB,
  68     IUADD,
  69     IUCARRY,
  70     IUDIV,
  71     IUMAX,
  72     IUMIN,
  73     IUMUL,
  74     IUREM,
  75     IUSHR,
  76     IUSUB,
  77     IXOR,
  78     LADD,
  79     LAND,
  80     LCARRY,
  81     LDIV,
  82     LMAX,
  83     LMIN,
  84     LMUL,
  85     LNEG,
  86     LNOT,
  87     LOR,
  88     LREM,
  89     LSHL,
  90     LSHR,
  91     LSUB,
  92     LUADD,
  93     LUCARRY,
  94     LUDIV,
  95     LUMAX,
  96     LUMIN,
  97     LUMUL,
  98     LUREM,
  99     LUSHR,
 100     LUSUB,
 101     LXOR,
 102     OADD,
 103     RINT,
 104     SQRT,
 105     UNDEF;
 106 
 107     public static class ConvertOp extends HSAILLIRInstruction {
 108         private final Kind from;
 109         private final Kind to;
 110         @Def({REG}) protected AllocatableValue result;
 111         @Use({REG, STACK}) protected AllocatableValue x;
 112 
 113         public ConvertOp(AllocatableValue result, AllocatableValue x, Kind to, Kind from) {
 114             this.from = from;
 115             this.to = to;
 116             this.result = result;
 117             this.x = x;
 118         }
 119 
 120         @Override
 121         public void emitCode(CompilationResultBuilder crb, HSAILAssembler masm) {
 122             masm.emitConvert(result, x, to, from);
 123         }
 124     }
 125 
 126     public static class Op1Stack extends HSAILLIRInstruction {
 127         @Opcode private final HSAILArithmetic opcode;
 128         @Def({REG, HINT}) protected Value result;
 129         @Use({REG, STACK, CONST}) protected Value x;
 130 
 131         public Op1Stack(HSAILArithmetic opcode, Value result, Value x) {
 132             this.opcode = opcode;
 133             this.result = result;
 134             this.x = x;
 135         }
 136 
 137         @Override
 138         public void emitCode(CompilationResultBuilder crb, HSAILAssembler masm) {
 139             emit(crb, masm, opcode, result, x, null);
 140         }
 141     }
 142 
 143     public static class Op2Stack extends HSAILLIRInstruction {
 144         @Opcode private final HSAILArithmetic opcode;
 145         @Def({REG, HINT}) protected Value result;
 146         @Use({REG, CONST}) protected Value x;
 147         @Alive({REG, CONST}) protected Value y;
 148 
 149         public Op2Stack(HSAILArithmetic opcode, Value result, Value x, Value y) {
 150             this.opcode = opcode;
 151             this.result = result;
 152             this.x = x;
 153             this.y = y;
 154         }
 155 
 156         @Override
 157         public void emitCode(CompilationResultBuilder crb, HSAILAssembler masm) {
 158             emit(crb, masm, opcode, result, x, y, null);
 159         }
 160 
 161         @Override
 162         public void verify() {
 163             super.verify();
 164             verifyKind(opcode, result, x, y);
 165         }
 166     }
 167 
 168     public static class Op1Reg extends HSAILLIRInstruction {
 169         @Opcode private final HSAILArithmetic opcode;
 170         @Def({REG, HINT}) protected Value result;
 171         @Use({REG}) protected Value x;
 172 
 173         public Op1Reg(HSAILArithmetic opcode, Value result, Value x) {
 174             this.opcode = opcode;
 175             this.result = result;
 176             this.x = x;
 177         }
 178 
 179         @Override
 180         public void emitCode(CompilationResultBuilder crb, HSAILAssembler masm) {
 181             emit(crb, masm, opcode, result, x, null);
 182         }
 183     }
 184 
 185     public static class Op2Reg extends HSAILLIRInstruction {
 186         @Opcode private final HSAILArithmetic opcode;
 187         @Def({REG, HINT}) protected Value result;
 188         @Use({REG, STACK, CONST}) protected Value x;
 189         @Alive({REG, CONST}) protected Value y;
 190 
 191         public Op2Reg(HSAILArithmetic opcode, Value result, Value x, Value y) {
 192             this.opcode = opcode;
 193             this.result = result;
 194             this.x = x;
 195             this.y = y;
 196         }
 197 
 198         @Override
 199         public void emitCode(CompilationResultBuilder crb, HSAILAssembler masm) {
 200             emit(crb, masm, opcode, result, x, y, null);
 201         }
 202 
 203         @Override
 204         public void verify() {
 205             super.verify();
 206             verifyKind(opcode, result, x, y);
 207         }
 208     }
 209 
 210     public static class Op2RegCommutative extends HSAILLIRInstruction {
 211         @Opcode private final HSAILArithmetic opcode;
 212         @Def({REG, HINT}) protected Value result;
 213         @Use({REG, STACK, CONST}) protected Value x;
 214         @Use({REG, CONST}) protected Value y;
 215 
 216         public Op2RegCommutative(HSAILArithmetic opcode, Value result, Value x, Value y) {
 217             this.opcode = opcode;
 218             this.result = result;
 219             this.x = x;
 220             this.y = y;
 221         }
 222 
 223         @Override
 224         public void emitCode(CompilationResultBuilder crb, HSAILAssembler masm) {
 225             throw GraalInternalError.shouldNotReachHere();
 226         }
 227 
 228         @Override
 229         protected void verify() {
 230             super.verify();
 231             verifyKind(opcode, result, x, y);
 232         }
 233     }
 234 
 235     public static class ShiftOp extends HSAILLIRInstruction {
 236         @Opcode private final HSAILArithmetic opcode;
 237         @Def({REG, HINT}) protected Value result;
 238         @Use({REG, STACK, CONST}) protected Value x;
 239         @Alive({REG, CONST}) protected Value y;
 240 
 241         public ShiftOp(HSAILArithmetic opcode, Value result, Value x, Value y) {
 242             this.opcode = opcode;
 243             this.result = result;
 244             this.x = x;
 245             this.y = y;
 246         }
 247 
 248         @Override
 249         public void emitCode(CompilationResultBuilder crb, HSAILAssembler masm) {
 250             emit(crb, masm, opcode, result, x, y, null);
 251         }
 252 
 253         @Override
 254         public void verify() {
 255             super.verify();
 256             verifyKind(opcode, result, x, x);
 257             assert y.getKind().getStackKind() == Kind.Int;
 258         }
 259     }
 260 
 261     public static class DivOp extends HSAILLIRInstruction {
 262         @Opcode private final HSAILArithmetic opcode;
 263         @Def protected Value result;
 264         @Use protected Value x;
 265         @Alive protected Value y;
 266         @State protected LIRFrameState state;
 267 
 268         public DivOp(HSAILArithmetic opcode, Value result, Value x, Value y, LIRFrameState state) {
 269             this.opcode = opcode;
 270             this.result = result;
 271             this.x = x;
 272             this.y = y;
 273             this.state = state;
 274         }
 275 
 276         @Override
 277         public void emitCode(CompilationResultBuilder crb, HSAILAssembler masm) {
 278             emit(crb, masm, opcode, result, y, state);
 279         }
 280 
 281         @Override
 282         protected void verify() {
 283             super.verify();
 284             verifyKind(opcode, result, x, y);
 285         }
 286     }
 287 
 288     @SuppressWarnings("unused")
 289     protected static void emit(CompilationResultBuilder crb, HSAILAssembler masm, HSAILArithmetic opcode, Value result) {
 290         switch (opcode) {
 291             default:
 292                 throw GraalInternalError.shouldNotReachHere();
 293         }
 294     }
 295 
 296     /**
 297      * Emit the HSAIL code for an arithmetic operation taking one input parameter.
 298      * 
 299      * @param crb the CompilationResultBuilder
 300      * @param masm the HSAIL assembler
 301      * @param opcode the opcode of the arithmetic operation
 302      * @param dst the destination
 303      * @param src the source parameter
 304      * @param info structure that stores the LIRFrameState. Used for exception handling.
 305      */
 306 
 307     public static void emit(CompilationResultBuilder crb, HSAILAssembler masm, HSAILArithmetic opcode, Value dst, Value src, LIRFrameState info) {
 308         int exceptionOffset = -1;
 309         if (isRegister(src)) {
 310             switch (opcode) {
 311                 case ABS:
 312                     masm.emit("abs", dst, src);
 313                     break;
 314                 case CEIL:
 315                     masm.emit("ceil", dst, src);
 316                     break;
 317                 case FLOOR:
 318                     masm.emit("floor", dst, src);
 319                     break;
 320                 case RINT:
 321                     masm.emit("rint", dst, src);
 322                     break;
 323                 case SQRT:
 324                     masm.emit("sqrt", dst, src);
 325                     break;
 326                 case UNDEF:
 327                     masm.undefined("undefined node");
 328                     break;
 329                 case CALL:
 330                     masm.undefined("undefined node CALL");
 331                     break;
 332                 case INOT:
 333                 case LNOT:
 334                     masm.emitForceBitwise("not", dst, src);
 335                     break;
 336                 case INEG:
 337                 case LNEG:
 338                 case FNEG:
 339                 case DNEG:
 340                     masm.emit("neg", dst, src);
 341                     break;
 342                 default:
 343                     throw GraalInternalError.shouldNotReachHere();
 344             }
 345         } else {
 346             throw GraalInternalError.shouldNotReachHere();
 347         }
 348         if (info != null) {
 349             assert exceptionOffset != -1;
 350             crb.recordImplicitException(exceptionOffset, info);
 351         }
 352     }
 353 
 354     public static void emit(CompilationResultBuilder crb, HSAILAssembler masm, HSAILArithmetic opcode, Value dst, Value src1, Value src2, LIRFrameState info) {
 355         /**
 356          * First check if one of src1 or src2 is an AddressValue. If it is, convert the address to a
 357          * register using an lda instruction. We can just reuse the eventual dst register for this.
 358          */
 359         if (src1 instanceof HSAILAddressValue) {
 360             assert (!(src2 instanceof HSAILAddressValue));
 361             masm.emitLda(dst, ((HSAILAddressValue) src1).toAddress());
 362             emit(crb, masm, opcode, dst, dst, src2, info);
 363             return;
 364         } else if (src2 instanceof HSAILAddressValue) {
 365             assert (!(src1 instanceof HSAILAddressValue));
 366             masm.emitLda(dst, ((HSAILAddressValue) src2).toAddress());
 367             emit(crb, masm, opcode, dst, src1, dst, info);
 368             return;
 369         }
 370         int exceptionOffset = -1;
 371         switch (opcode) {
 372             case IADD:
 373             case LADD:
 374             case DADD:
 375             case FADD:
 376             case OADD:
 377                 masm.emit("add", dst, src1, src2);
 378                 break;
 379             case ISUB:
 380             case LSUB:
 381             case DSUB:
 382             case FSUB:
 383                 masm.emit("sub", dst, src1, src2);
 384                 break;
 385             case IMUL:
 386             case LMUL:
 387             case FMUL:
 388             case DMUL:
 389             case LUMUL:
 390                 masm.emit("mul", dst, src1, src2);
 391                 break;
 392             case IDIV:
 393             case LDIV:
 394             case FDIV:
 395             case DDIV:
 396                 masm.emit("div", dst, src1, src2);
 397                 break;
 398             case IMAX:
 399             case LMAX:
 400                 masm.emit("max", dst, src1, src2);
 401                 break;
 402             case IMIN:
 403             case LMIN:
 404                 masm.emit("min", dst, src1, src2);
 405                 break;
 406             case ISHL:
 407             case LSHL:
 408                 masm.emit("shl", dst, src1, src2);
 409                 break;
 410             case ISHR:
 411             case LSHR:
 412                 masm.emit("shr", dst, src1, src2);
 413                 break;
 414             case IUSHR:
 415             case LUSHR:
 416                 masm.emitForceUnsigned("shr", dst, src1, src2);
 417                 break;
 418             case IAND:
 419             case LAND:
 420                 masm.emitForceBitwise("and", dst, src1, src2);
 421                 break;
 422             case IXOR:
 423             case LXOR:
 424                 masm.emitForceBitwise("xor", dst, src1, src2);
 425                 break;
 426             case IOR:
 427             case LOR:
 428                 masm.emitForceBitwise("or", dst, src1, src2);
 429                 break;
 430             case IREM:
 431             case LREM:
 432                 masm.emit("rem", dst, src1, src2);
 433                 break;
 434             default:
 435                 throw GraalInternalError.shouldNotReachHere();
 436         }
 437         if (info != null) {
 438             assert exceptionOffset != -1;
 439             crb.recordImplicitException(exceptionOffset, info);
 440         }
 441     }
 442 
 443     private static void verifyKind(HSAILArithmetic opcode, Value result, Value x, Value y) {
 444         assert (opcode.name().startsWith("I") && result.getKind() == Kind.Int && x.getKind().getStackKind() == Kind.Int && y.getKind().getStackKind() == Kind.Int) ||
 445                         (opcode.name().startsWith("L") && result.getKind() == Kind.Long && x.getKind() == Kind.Long && y.getKind() == Kind.Long) ||
 446                         (opcode.name().startsWith("LU") && result.getKind() == Kind.Long && x.getKind() == Kind.Long && y.getKind() == Kind.Int) ||
 447                         (opcode.name().startsWith("F") && result.getKind() == Kind.Float && x.getKind() == Kind.Float && y.getKind() == Kind.Float) ||
 448                         (opcode.name().startsWith("D") && result.getKind() == Kind.Double && x.getKind() == Kind.Double && y.getKind() == Kind.Double) ||
 449                         (opcode.name().startsWith("O") && result.getKind() == Kind.Object && x.getKind() == Kind.Object && (y.getKind() == Kind.Int || y.getKind() == Kind.Long));
 450     }
 451 }