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 
  24 package com.oracle.graal.compiler.hsail;
  25 
  26 import static com.oracle.graal.api.code.ValueUtil.*;
  27 import static com.oracle.graal.lir.hsail.HSAILArithmetic.*;
  28 import static com.oracle.graal.lir.hsail.HSAILBitManipulationOp.IntrinsicOpcode.*;
  29 import static com.oracle.graal.lir.hsail.HSAILCompare.*;
  30 
  31 import com.oracle.graal.api.code.*;
  32 import com.oracle.graal.api.meta.*;
  33 import com.oracle.graal.asm.*;
  34 import com.oracle.graal.compiler.gen.*;
  35 import com.oracle.graal.compiler.target.*;
  36 import com.oracle.graal.debug.*;
  37 import com.oracle.graal.graph.*;
  38 import com.oracle.graal.lir.*;
  39 import com.oracle.graal.lir.StandardOp.JumpOp;
  40 import com.oracle.graal.lir.hsail.*;
  41 import com.oracle.graal.lir.hsail.HSAILArithmetic.Op1Stack;
  42 import com.oracle.graal.lir.hsail.HSAILArithmetic.Op2Reg;
  43 import com.oracle.graal.lir.hsail.HSAILArithmetic.Op2Stack;
  44 import com.oracle.graal.lir.hsail.HSAILArithmetic.ShiftOp;
  45 import com.oracle.graal.lir.hsail.HSAILControlFlow.CompareBranchOp;
  46 import com.oracle.graal.lir.hsail.HSAILControlFlow.CondMoveOp;
  47 import com.oracle.graal.lir.hsail.HSAILControlFlow.FloatCompareBranchOp;
  48 import com.oracle.graal.lir.hsail.HSAILControlFlow.FloatCondMoveOp;
  49 import com.oracle.graal.lir.hsail.HSAILControlFlow.ReturnOp;
  50 import com.oracle.graal.lir.hsail.HSAILMove.LeaOp;
  51 import com.oracle.graal.lir.hsail.HSAILMove.LoadOp;
  52 import com.oracle.graal.lir.hsail.HSAILMove.MoveFromRegOp;
  53 import com.oracle.graal.lir.hsail.HSAILMove.MoveToRegOp;
  54 import com.oracle.graal.lir.hsail.HSAILMove.StoreOp;
  55 import com.oracle.graal.nodes.*;
  56 import com.oracle.graal.nodes.calc.*;
  57 import com.oracle.graal.nodes.java.*;
  58 
  59 /**
  60  * This class implements the HSAIL specific portion of the LIR generator.
  61  */
  62 public class HSAILLIRGenerator extends LIRGenerator {
  63 
  64     public static class HSAILSpillMoveFactory implements LIR.SpillMoveFactory {
  65 
  66         @Override
  67         public LIRInstruction createMove(AllocatableValue dst, Value src) {
  68             if (src instanceof HSAILAddressValue) {
  69                 return new LeaOp(dst, (HSAILAddressValue) src);
  70             } else if (isRegister(src) || isStackSlot(dst)) {
  71                 return new MoveFromRegOp(dst, src);
  72             } else {
  73                 return new MoveToRegOp(dst, src);
  74             }
  75         }
  76     }
  77 
  78     public HSAILLIRGenerator(StructuredGraph graph, CodeCacheProvider runtime, TargetDescription target, FrameMap frameMap, CallingConvention cc, LIR lir) {
  79         super(graph, runtime, target, frameMap, cc, lir);
  80         lir.spillMoveFactory = new HSAILSpillMoveFactory();
  81     }
  82 
  83     @Override
  84     protected void emitNode(ValueNode node) {
  85         if (node instanceof LIRGenLowerable) {
  86             ((LIRGenLowerable) node).generate(this);
  87         } else {
  88             super.emitNode(node);
  89         }
  90     }
  91 
  92     @Override
  93     public boolean canStoreConstant(Constant c) {
  94         // Operand b must be in the .reg state space.
  95         return false;
  96     }
  97 
  98     @Override
  99     public boolean canInlineConstant(Constant c) {
 100         switch (c.getKind()) {
 101             case Long:
 102                 return NumUtil.isInt(c.asLong()) && !runtime.needsDataPatch(c);
 103             case Object:
 104                 return c.isNull();
 105             default:
 106                 return true;
 107         }
 108     }
 109 
 110     @Override
 111     public Variable emitMove(Value input) {
 112         Variable result = newVariable(input.getKind());
 113         emitMove(result, input);
 114         return result;
 115     }
 116 
 117     @Override
 118     public void emitMove(AllocatableValue dst, Value src) {
 119         if (isRegister(src) || isStackSlot(dst)) {
 120             append(new MoveFromRegOp(dst, src));
 121         } else {
 122             append(new MoveToRegOp(dst, src));
 123         }
 124     }
 125 
 126     public HSAILAddressValue emitAddress(Value base, long displacement, Value index, int scale) {
 127         AllocatableValue baseRegister;
 128         long finalDisp = displacement;
 129 
 130         if (isConstant(base)) {
 131             if (asConstant(base).isNull()) {
 132                 baseRegister = Value.ILLEGAL;
 133             } else if (asConstant(base).getKind() != Kind.Object) {
 134                 finalDisp += asConstant(base).asLong();
 135                 baseRegister = Value.ILLEGAL;
 136             } else {
 137                 baseRegister = load(base);
 138             }
 139         } else if (base == Value.ILLEGAL) {
 140             baseRegister = Value.ILLEGAL;
 141         } else {
 142             baseRegister = asAllocatable(base);
 143         }
 144         if (index != Value.ILLEGAL) {
 145             if (isConstant(index)) {
 146                 finalDisp += asConstant(index).asLong() * scale;
 147             } else {
 148                 Value indexRegister;
 149                 Value convertedIndex;
 150                 convertedIndex = this.emitConvert(ConvertNode.Op.I2L, index);
 151                 if (scale != 1) {
 152                     indexRegister = emitUMul(convertedIndex, Constant.forInt(scale));
 153                 } else {
 154                     indexRegister = convertedIndex;
 155                 }
 156                 if (baseRegister == Value.ILLEGAL) {
 157                     baseRegister = asAllocatable(indexRegister);
 158                 } else {
 159                     baseRegister = emitAdd(baseRegister, indexRegister);
 160                 }
 161             }
 162         }
 163         return new HSAILAddressValue(target().wordKind, baseRegister, finalDisp);
 164     }
 165 
 166     private HSAILAddressValue asAddress(Value address) {
 167         if (address instanceof HSAILAddressValue) {
 168             return (HSAILAddressValue) address;
 169         } else {
 170             return emitAddress(address, 0, Value.ILLEGAL, 0);
 171         }
 172     }
 173 
 174     @Override
 175     public Variable emitLoad(Kind kind, Value address, DeoptimizingNode deopting) {
 176         HSAILAddressValue loadAddress = asAddress(address);
 177         Variable result = newVariable(kind);
 178         append(new LoadOp(kind, result, loadAddress, deopting != null ? state(deopting) : null));
 179         return result;
 180     }
 181 
 182     @Override
 183     public void emitStore(Kind kind, Value address, Value inputVal, DeoptimizingNode deopting) {
 184         HSAILAddressValue storeAddress = asAddress(address);
 185         Variable input = load(inputVal);
 186         append(new StoreOp(kind, storeAddress, input, deopting != null ? state(deopting) : null));
 187     }
 188 
 189     @Override
 190     public Variable emitAddress(StackSlot address) {
 191         throw new InternalError("NYI");
 192     }
 193 
 194     @Override
 195     public void emitJump(LabelRef label) {
 196         append(new JumpOp(label));
 197     }
 198 
 199     private static HSAILCompare mapKindToCompareOp(Kind kind) {
 200         switch (kind) {
 201             case Int:
 202                 return ICMP;
 203             case Long:
 204                 return LCMP;
 205             case Float:
 206                 return FCMP;
 207             case Double:
 208                 return DCMP;
 209             case Object:
 210                 return ACMP;
 211             default:
 212                 throw GraalInternalError.shouldNotReachHere("" + kind);
 213         }
 214     }
 215 
 216     @Override
 217     public void emitCompareBranch(Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef label) {
 218         // We don't have top worry about mirroring the condition on HSAIL.
 219         Condition finalCondition = cond;
 220         Variable result = newVariable(left.getKind());
 221         Kind kind = left.getKind().getStackKind();
 222         switch (kind) {
 223             case Int:
 224             case Long:
 225             case Object:
 226                 append(new CompareBranchOp(mapKindToCompareOp(kind), finalCondition, left, right, result, result, label));
 227                 break;
 228             case Float:
 229             case Double:
 230                 append(new FloatCompareBranchOp(mapKindToCompareOp(kind), finalCondition, left, right, result, result, label, unorderedIsTrue));
 231                 break;
 232             default:
 233                 throw GraalInternalError.shouldNotReachHere("" + left.getKind());
 234         }
 235     }
 236 
 237     @Override
 238     public void emitOverflowCheckBranch(LabelRef label, boolean negated) {
 239         throw new InternalError("NYI");
 240     }
 241 
 242     @Override
 243     public void emitIntegerTestBranch(Value left, Value right, boolean negated, LabelRef label) {
 244         throw new InternalError("NYI");
 245     }
 246 
 247     @Override
 248     public Variable emitConditionalMove(Value left, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue) {
 249         Condition finalCondition = cond;
 250         Variable result = newVariable(trueValue.getKind());
 251         Kind kind = left.getKind().getStackKind();
 252         switch (kind) {
 253             case Int:
 254             case Long:
 255             case Object:
 256                 append(new CondMoveOp(mapKindToCompareOp(kind), load(left), load(right), result, finalCondition, load(trueValue), load(falseValue)));
 257                 break;
 258             case Float:
 259             case Double:
 260                 append(new FloatCondMoveOp(mapKindToCompareOp(kind), load(left), load(right), result, finalCondition, unorderedIsTrue, load(trueValue), load(falseValue)));
 261                 break;
 262             default:
 263                 throw GraalInternalError.shouldNotReachHere("missing: " + left.getKind());
 264         }
 265         return result;
 266     }
 267 
 268     @Override
 269     public Variable emitIntegerTestMove(Value left, Value right, Value trueValue, Value falseValue) {
 270         throw new InternalError("NYI");
 271     }
 272 
 273     @Override
 274     public Variable emitNegate(Value input) {
 275         Variable result = newVariable(input.getKind());
 276         switch (input.getKind()) {
 277             case Int:
 278                 append(new Op1Stack(INEG, result, input));
 279                 break;
 280             default:
 281                 throw GraalInternalError.shouldNotReachHere();
 282         }
 283         return result;
 284 
 285     }
 286 
 287     public Variable emitTestAddressAdd(Value a, Value b) {
 288         Variable result = newVariable(a.getKind());
 289         switch (a.getKind()) {
 290             case Int:
 291                 append(new Op2Stack(IADD, result, a, loadNonConst(b)));
 292                 break;
 293             case Long:
 294                 append(new Op2Stack(LADD, result, a, loadNonConst(b)));
 295                 break;
 296             case Float:
 297                 append(new Op2Stack(FADD, result, a, loadNonConst(b)));
 298                 break;
 299             case Double:
 300                 append(new Op2Stack(DADD, result, a, loadNonConst(b)));
 301                 break;
 302             case Object:
 303                 throw GraalInternalError.shouldNotReachHere();
 304             default:
 305                 throw GraalInternalError.shouldNotReachHere();
 306         }
 307 
 308         return result;
 309     }
 310 
 311     @Override
 312     public Variable emitAdd(Value a, Value b) {
 313         Variable result = newVariable(a.getKind());
 314         switch (a.getKind()) {
 315             case Int:
 316                 append(new Op2Stack(IADD, result, a, loadNonConst(b)));
 317                 break;
 318             case Long:
 319                 append(new Op2Stack(LADD, result, a, loadNonConst(b)));
 320                 break;
 321             case Float:
 322                 append(new Op2Stack(FADD, result, a, loadNonConst(b)));
 323                 break;
 324             case Double:
 325                 append(new Op2Stack(DADD, result, a, loadNonConst(b)));
 326                 break;
 327             case Object:
 328                 append(new Op2Stack(OADD, result, a, loadNonConst(b)));
 329                 break;
 330             default:
 331                 throw GraalInternalError.shouldNotReachHere();
 332         }
 333         return result;
 334     }
 335 
 336     @Override
 337     public Variable emitSub(Value a, Value b) {
 338         Variable result = newVariable(a.getKind());
 339         switch (a.getKind()) {
 340             case Int:
 341                 append(new Op2Stack(ISUB, result, a, loadNonConst(b)));
 342                 break;
 343             case Float:
 344                 append(new Op2Stack(FSUB, result, a, loadNonConst(b)));
 345                 break;
 346             case Long:
 347                 append(new Op2Stack(LSUB, result, a, loadNonConst(b)));
 348                 break;
 349             case Double:
 350                 append(new Op2Stack(DSUB, result, a, loadNonConst(b)));
 351                 break;
 352             default:
 353                 throw GraalInternalError.shouldNotReachHere();
 354         }
 355         return result;
 356     }
 357 
 358     @Override
 359     public Variable emitMul(Value a, Value b) {
 360         Variable result = newVariable(a.getKind());
 361         switch (a.getKind()) {
 362             case Int:
 363                 append(new Op2Reg(IMUL, result, a, loadNonConst(b)));
 364                 break;
 365             case Long:
 366                 append(new Op2Reg(LMUL, result, a, loadNonConst(b)));
 367                 break;
 368             case Float:
 369                 append(new Op2Reg(FMUL, result, a, loadNonConst(b)));
 370                 break;
 371             case Double:
 372                 append(new Op2Reg(DMUL, result, a, loadNonConst(b)));
 373                 break;
 374             default:
 375                 throw GraalInternalError.shouldNotReachHere();
 376         }
 377         return result;
 378     }
 379 
 380     public Variable emitUMul(Value a, Value b) {
 381         Variable result = newVariable(a.getKind());
 382         switch (a.getKind()) {
 383             case Int:
 384                 append(new Op2Reg(LUMUL, result, a, loadNonConst(b)));
 385                 break;
 386             case Long:
 387                 append(new Op2Reg(LUMUL, result, a, loadNonConst(b)));
 388                 break;
 389             default:
 390                 throw GraalInternalError.shouldNotReachHere();
 391         }
 392         return result;
 393     }
 394 
 395     @Override
 396     protected boolean peephole(ValueNode valueNode) {
 397         // No peephole optimizations for now.
 398         return false;
 399     }
 400 
 401     @Override
 402     public Value emitDiv(Value a, Value b, DeoptimizingNode deopting) {
 403         Variable result = newVariable(a.getKind());
 404         switch (a.getKind()) {
 405             case Int:
 406                 append(new Op2Stack(IDIV, result, a, loadNonConst(b)));
 407                 break;
 408             case Long:
 409                 append(new Op2Stack(LDIV, result, a, loadNonConst(b)));
 410                 break;
 411             case Float:
 412                 append(new Op2Stack(FDIV, result, a, loadNonConst(b)));
 413                 break;
 414             case Double:
 415                 append(new Op2Stack(DDIV, result, a, loadNonConst(b)));
 416                 break;
 417             default:
 418                 throw GraalInternalError.shouldNotReachHere();
 419         }
 420         return result;
 421 
 422     }
 423 
 424     @Override
 425     public Value emitRem(Value a, Value b, DeoptimizingNode deopting) {
 426         Variable result = newVariable(a.getKind());
 427         switch (a.getKind()) {
 428             case Int:
 429                 append(new Op2Stack(IREM, result, a, loadNonConst(b)));
 430                 break;
 431             case Long:
 432                 append(new Op2Stack(LREM, result, a, loadNonConst(b)));
 433                 break;
 434             case Float:
 435                 append(new Op2Stack(FREM, result, a, loadNonConst(b)));
 436                 break;
 437             case Double:
 438                 append(new Op2Stack(DREM, result, a, loadNonConst(b)));
 439                 break;
 440             default:
 441                 throw GraalInternalError.shouldNotReachHere();
 442         }
 443         return result;
 444     }
 445 
 446     @Override
 447     public Variable emitUDiv(Value a, Value b, DeoptimizingNode deopting) {
 448         throw new InternalError("NYI");
 449     }
 450 
 451     @Override
 452     public Variable emitURem(Value a, Value b, DeoptimizingNode deopting) {
 453         throw new InternalError("NYI");
 454     }
 455 
 456     @Override
 457     public Variable emitAnd(Value a, Value b) {
 458         Variable result = newVariable(a.getKind());
 459         switch (a.getKind()) {
 460             case Int:
 461                 append(new Op2Stack(IAND, result, a, loadNonConst(b)));
 462                 break;
 463             default:
 464                 throw GraalInternalError.shouldNotReachHere();
 465         }
 466         return result;
 467     }
 468 
 469     @Override
 470     public Variable emitOr(Value a, Value b) {
 471         throw new InternalError("NYI");
 472     }
 473 
 474     @Override
 475     public Variable emitXor(Value a, Value b) {
 476         throw new InternalError("NYI");
 477     }
 478 
 479     @Override
 480     public Variable emitShl(Value a, Value b) {
 481         Variable result = newVariable(a.getKind());
 482         switch (a.getKind()) {
 483             case Int:
 484                 append(new ShiftOp(ISHL, result, a, b));
 485                 break;
 486             default:
 487                 GraalInternalError.shouldNotReachHere();
 488         }
 489         return result;
 490     }
 491 
 492     @Override
 493     public Variable emitShr(Value a, Value b) {
 494         throw new InternalError("NYI");
 495     }
 496 
 497     @Override
 498     public Variable emitUShr(Value a, Value b) {
 499         Variable result = newVariable(a.getKind());
 500         switch (a.getKind()) {
 501             case Int:
 502                 append(new ShiftOp(IUSHR, result, a, b));
 503                 break;
 504             default:
 505                 GraalInternalError.shouldNotReachHere();
 506         }
 507         return result;
 508     }
 509 
 510     @Override
 511     public Variable emitConvert(ConvertNode.Op opcode, Value inputVal) {
 512         Variable input = load(inputVal);
 513         Variable result = newVariable(opcode.to);
 514         switch (opcode) {
 515             case I2F:
 516                 append(new Op1Stack(I2F, result, input));
 517                 break;
 518             case I2L:
 519                 append(new Op1Stack(I2L, result, input));
 520                 break;
 521             case I2D:
 522                 append(new Op1Stack(I2D, result, input));
 523                 break;
 524             case D2I:
 525                 append(new Op1Stack(D2I, result, input));
 526                 break;
 527             case L2I:
 528                 append(new Op1Stack(L2I, result, input));
 529                 break;
 530             case F2D:
 531                 append(new Op1Stack(F2D, result, input));
 532                 break;
 533             case D2F:
 534                 append(new Op1Stack(D2F, result, input));
 535                 break;
 536             default:
 537                 throw GraalInternalError.shouldNotReachHere();
 538         }
 539         return result;
 540     }
 541 
 542     @Override
 543     public void emitDeoptimize(DeoptimizationAction action, DeoptimizingNode deopting) {
 544         append(new ReturnOp(Value.ILLEGAL));
 545     }
 546 
 547     @Override
 548     public void emitMembar(int barriers) {
 549         throw new InternalError("NYI");
 550     }
 551 
 552     @Override
 553     protected void emitDirectCall(DirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) {
 554         throw new InternalError("NYI");
 555     }
 556 
 557     @Override
 558     protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) {
 559         throw new InternalError("NYI");
 560     }
 561 
 562     @Override
 563     protected void emitForeignCall(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info) {
 564         throw new InternalError("NYI emitForeignCall");
 565     }
 566 
 567     @Override
 568     public void emitBitCount(Variable result, Value value) {
 569         if (value.getKind().getStackKind() == Kind.Int) {
 570             append(new HSAILBitManipulationOp(IPOPCNT, result, value));
 571         } else {
 572             append(new HSAILBitManipulationOp(LPOPCNT, result, value));
 573         }
 574     }
 575 
 576     @Override
 577     public void emitBitScanForward(Variable result, Value value) {
 578         throw new InternalError("NYI");
 579     }
 580 
 581     @Override
 582     public void emitBitScanReverse(Variable result, Value value) {
 583         throw new InternalError("NYI");
 584     }
 585 
 586     @Override
 587     public void emitMathAbs(Variable result, Variable input) {
 588         throw new InternalError("NYI");
 589     }
 590 
 591     @Override
 592     public void emitMathSqrt(Variable result, Variable input) {
 593         append(new Op1Stack(SQRT, result, input));
 594     }
 595 
 596     @Override
 597     public void emitMathLog(Variable result, Variable input, boolean base10) {
 598         throw new InternalError("NYI");
 599     }
 600 
 601     @Override
 602     public void emitMathCos(Variable result, Variable input) {
 603         throw new InternalError("NYI");
 604     }
 605 
 606     @Override
 607     public void emitMathSin(Variable result, Variable input) {
 608         throw new InternalError("NYI");
 609     }
 610 
 611     @Override
 612     public void emitMathTan(Variable result, Variable input) {
 613         throw new InternalError("NYI");
 614     }
 615 
 616     @Override
 617     public void emitByteSwap(Variable result, Value input) {
 618         throw new InternalError("NYI");
 619     }
 620 
 621     @Override
 622     protected void emitReturn(Value input) {
 623         append(new ReturnOp(input));
 624     }
 625 
 626     @Override
 627     protected void emitSequentialSwitch(Constant[] keyConstants, LabelRef[] keyTargets, LabelRef defaultTarget, Value key) {
 628         throw new InternalError("NYI");
 629     }
 630 
 631     @Override
 632     protected void emitSwitchRanges(int[] lowKeys, int[] highKeys, LabelRef[] targets, LabelRef defaultTarget, Value key) {
 633         throw new InternalError("NYI");
 634     }
 635 
 636     @Override
 637     protected void emitTableSwitch(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value key) {
 638         throw new InternalError("NYI");
 639     }
 640 
 641     @Override
 642     public void visitCompareAndSwap(CompareAndSwapNode node) {
 643         throw new InternalError("NYI");
 644     }
 645 
 646     @Override
 647     public void visitBreakpointNode(BreakpointNode node) {
 648         throw new InternalError("NYI");
 649     }
 650 
 651     @Override
 652     public void visitSafepointNode(SafepointNode i) {
 653         Debug.log("visitSafePointNode unimplemented");
 654     }
 655 
 656     @Override
 657     public void emitUnwind(Value operand) {
 658         throw new InternalError("NYI");
 659     }
 660 
 661     @Override
 662     public void emitNullCheck(ValueNode v, DeoptimizingNode deopting) {
 663         assert v.kind() == Kind.Object;
 664         Variable obj = newVariable(Kind.Object);
 665         emitMove(obj, operand(v));
 666         append(new HSAILMove.NullCheckOp(obj, state(deopting)));
 667     }
 668 
 669     @Override
 670     public void visitInfopointNode(InfopointNode i) {
 671         throw new InternalError("NYI");
 672     }
 673 }