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 }