1 /* 2 * Copyright (c) 2009, 2014, 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.amd64; 25 26 import static com.oracle.graal.api.code.ValueUtil.*; 27 import static com.oracle.graal.lir.amd64.AMD64Arithmetic.*; 28 import static com.oracle.graal.lir.amd64.AMD64BitManipulationOp.IntrinsicOpcode.*; 29 import static com.oracle.graal.lir.amd64.AMD64Compare.*; 30 import static com.oracle.graal.lir.amd64.AMD64MathIntrinsicOp.IntrinsicOpcode.*; 31 32 import com.oracle.graal.amd64.*; 33 import com.oracle.graal.api.code.*; 34 import com.oracle.graal.api.meta.*; 35 import com.oracle.graal.asm.*; 36 import com.oracle.graal.asm.amd64.AMD64Address.Scale; 37 import com.oracle.graal.asm.amd64.AMD64Assembler.ConditionFlag; 38 import com.oracle.graal.compiler.common.*; 39 import com.oracle.graal.compiler.common.calc.*; 40 import com.oracle.graal.compiler.common.spi.*; 41 import com.oracle.graal.lir.*; 42 import com.oracle.graal.lir.StandardOp.JumpOp; 43 import com.oracle.graal.lir.amd64.*; 44 import com.oracle.graal.lir.amd64.AMD64Arithmetic.BinaryCommutative; 45 import com.oracle.graal.lir.amd64.AMD64Arithmetic.BinaryMemory; 46 import com.oracle.graal.lir.amd64.AMD64Arithmetic.BinaryRegConst; 47 import com.oracle.graal.lir.amd64.AMD64Arithmetic.BinaryRegReg; 48 import com.oracle.graal.lir.amd64.AMD64Arithmetic.BinaryRegStack; 49 import com.oracle.graal.lir.amd64.AMD64Arithmetic.BinaryRegStackConst; 50 import com.oracle.graal.lir.amd64.AMD64Arithmetic.DivRemOp; 51 import com.oracle.graal.lir.amd64.AMD64Arithmetic.FPDivRemOp; 52 import com.oracle.graal.lir.amd64.AMD64Arithmetic.MulHighOp; 53 import com.oracle.graal.lir.amd64.AMD64Arithmetic.Unary1Op; 54 import com.oracle.graal.lir.amd64.AMD64Arithmetic.Unary2MemoryOp; 55 import com.oracle.graal.lir.amd64.AMD64Arithmetic.Unary2Op; 56 import com.oracle.graal.lir.amd64.AMD64Arithmetic.Unary2RegOp; 57 import com.oracle.graal.lir.amd64.AMD64Compare.CompareMemoryOp; 58 import com.oracle.graal.lir.amd64.AMD64Compare.CompareOp; 59 import com.oracle.graal.lir.amd64.AMD64ControlFlow.BranchOp; 60 import com.oracle.graal.lir.amd64.AMD64ControlFlow.CondMoveOp; 61 import com.oracle.graal.lir.amd64.AMD64ControlFlow.FloatBranchOp; 62 import com.oracle.graal.lir.amd64.AMD64ControlFlow.FloatCondMoveOp; 63 import com.oracle.graal.lir.amd64.AMD64ControlFlow.ReturnOp; 64 import com.oracle.graal.lir.amd64.AMD64ControlFlow.StrategySwitchOp; 65 import com.oracle.graal.lir.amd64.AMD64ControlFlow.TableSwitchOp; 66 import com.oracle.graal.lir.amd64.AMD64Move.LeaDataOp; 67 import com.oracle.graal.lir.amd64.AMD64Move.LeaOp; 68 import com.oracle.graal.lir.amd64.AMD64Move.MembarOp; 69 import com.oracle.graal.lir.amd64.AMD64Move.MoveFromRegOp; 70 import com.oracle.graal.lir.amd64.AMD64Move.MoveToRegOp; 71 import com.oracle.graal.lir.amd64.AMD64Move.StackLeaOp; 72 import com.oracle.graal.lir.amd64.AMD64Move.ZeroExtendLoadOp; 73 import com.oracle.graal.lir.gen.*; 74 import com.oracle.graal.phases.util.*; 75 76 /** 77 * This class implements the AMD64 specific portion of the LIR generator. 78 */ 79 public abstract class AMD64LIRGenerator extends LIRGenerator { 80 81 private static final RegisterValue RCX_I = AMD64.rcx.asValue(LIRKind.value(Kind.Int)); 82 83 private class AMD64SpillMoveFactory implements LIR.SpillMoveFactory { 84 85 @Override 86 public LIRInstruction createMove(AllocatableValue result, Value input) { 87 return AMD64LIRGenerator.this.createMove(result, input); 88 } 89 } 90 91 public AMD64LIRGenerator(LIRKindTool lirKindTool, Providers providers, CallingConvention cc, LIRGenerationResult lirGenRes) { 92 super(lirKindTool, providers, cc, lirGenRes); 93 lirGenRes.getLIR().setSpillMoveFactory(new AMD64SpillMoveFactory()); 94 } 95 96 @Override 97 public boolean canInlineConstant(JavaConstant c) { 98 switch (c.getKind()) { 99 case Long: 100 return NumUtil.isInt(c.asLong()) && !getCodeCache().needsDataPatch(c); 101 case Object: 102 return c.isNull(); 103 default: 104 return true; 105 } 106 } 107 108 protected AMD64LIRInstruction createMove(AllocatableValue dst, Value src) { 109 if (src instanceof AMD64AddressValue) { 110 return new LeaOp(dst, (AMD64AddressValue) src); 111 } else if (isRegister(src) || isStackSlot(dst)) { 112 return new MoveFromRegOp(dst.getKind(), dst, src); 113 } else { 114 return new MoveToRegOp(dst.getKind(), dst, src); 115 } 116 } 117 118 @Override 119 public void emitMove(AllocatableValue dst, Value src) { 120 append(createMove(dst, src)); 121 } 122 123 public void emitData(AllocatableValue dst, byte[] data) { 124 append(new LeaDataOp(dst, data)); 125 } 126 127 @Override 128 public AMD64AddressValue emitAddress(Value base, long displacement, Value index, int scale) { 129 AllocatableValue baseRegister; 130 long finalDisp = displacement; 131 if (isConstant(base)) { 132 if (asConstant(base).isNull()) { 133 baseRegister = Value.ILLEGAL; 134 } else if (asConstant(base).getKind() != Kind.Object && !getCodeCache().needsDataPatch(asConstant(base))) { 135 finalDisp += asConstant(base).asLong(); 136 baseRegister = Value.ILLEGAL; 137 } else { 138 baseRegister = load(base); 139 } 140 } else { 141 baseRegister = asAllocatable(base); 142 } 143 144 AllocatableValue indexRegister; 145 Scale scaleEnum; 146 if (!index.equals(Value.ILLEGAL) && scale != 0) { 147 scaleEnum = Scale.fromInt(scale); 148 if (isConstant(index)) { 149 finalDisp += asConstant(index).asLong() * scale; 150 indexRegister = Value.ILLEGAL; 151 152 } else if (scaleEnum == null) { 153 /* Scale value that architecture cannot handle, so scale manually. */ 154 Value longIndex = index.getKind() == Kind.Long ? index : emitSignExtend(index, 32, 64); 155 if (CodeUtil.isPowerOf2(scale)) { 156 indexRegister = emitShl(longIndex, JavaConstant.forLong(CodeUtil.log2(scale))); 157 } else { 158 indexRegister = emitMul(longIndex, JavaConstant.forLong(scale)); 159 } 160 scaleEnum = Scale.Times1; 161 162 } else { 163 indexRegister = asAllocatable(index); 164 } 165 } else { 166 indexRegister = Value.ILLEGAL; 167 scaleEnum = Scale.Times1; 168 } 169 170 int displacementInt; 171 if (NumUtil.isInt(finalDisp)) { 172 displacementInt = (int) finalDisp; 173 } else { 174 displacementInt = 0; 175 AllocatableValue displacementRegister = load(JavaConstant.forLong(finalDisp)); 176 if (baseRegister.equals(Value.ILLEGAL)) { 177 baseRegister = displacementRegister; 178 } else if (indexRegister.equals(Value.ILLEGAL)) { 179 indexRegister = displacementRegister; 180 scaleEnum = Scale.Times1; 181 } else { 182 baseRegister = emitAdd(baseRegister, displacementRegister); 183 } 184 } 185 186 LIRKind resultKind = getAddressKind(base, displacement, index); 187 return new AMD64AddressValue(resultKind, baseRegister, indexRegister, scaleEnum, displacementInt); 188 } 189 190 public AMD64AddressValue asAddressValue(Value address) { 191 if (address instanceof AMD64AddressValue) { 192 return (AMD64AddressValue) address; 193 } else { 194 return emitAddress(address, 0, Value.ILLEGAL, 0); 195 } 196 } 197 198 @Override 199 public Variable emitAddress(StackSlot address) { 200 Variable result = newVariable(LIRKind.value(target().wordKind)); 201 append(new StackLeaOp(result, address)); 202 return result; 203 } 204 205 @Override 206 public void emitJump(LabelRef label) { 207 assert label != null; 208 append(new JumpOp(label)); 209 } 210 211 @Override 212 public void emitCompareBranch(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueLabel, LabelRef falseLabel, double trueLabelProbability) { 213 boolean mirrored = emitCompare(cmpKind, left, right); 214 Condition finalCondition = mirrored ? cond.mirror() : cond; 215 if (cmpKind == Kind.Float || cmpKind == Kind.Double) { 216 append(new FloatBranchOp(finalCondition, unorderedIsTrue, trueLabel, falseLabel, trueLabelProbability)); 217 } else { 218 append(new BranchOp(finalCondition, trueLabel, falseLabel, trueLabelProbability)); 219 } 220 } 221 222 public void emitCompareBranchMemory(Kind cmpKind, Value left, AMD64AddressValue right, LIRFrameState state, Condition cond, boolean unorderedIsTrue, LabelRef trueLabel, LabelRef falseLabel, 223 double trueLabelProbability) { 224 boolean mirrored = emitCompareMemory(cmpKind, left, right, state); 225 Condition finalCondition = mirrored ? cond.mirror() : cond; 226 if (cmpKind == Kind.Float || cmpKind == Kind.Double) { 227 append(new FloatBranchOp(finalCondition, unorderedIsTrue, trueLabel, falseLabel, trueLabelProbability)); 228 } else { 229 append(new BranchOp(finalCondition, trueLabel, falseLabel, trueLabelProbability)); 230 } 231 } 232 233 @Override 234 public void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, double overflowProbability) { 235 append(new BranchOp(ConditionFlag.Overflow, overflow, noOverflow, overflowProbability)); 236 } 237 238 @Override 239 public void emitIntegerTestBranch(Value left, Value right, LabelRef trueDestination, LabelRef falseDestination, double trueDestinationProbability) { 240 emitIntegerTest(left, right); 241 append(new BranchOp(Condition.EQ, trueDestination, falseDestination, trueDestinationProbability)); 242 } 243 244 @Override 245 public Variable emitConditionalMove(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue) { 246 boolean mirrored = emitCompare(cmpKind, left, right); 247 Condition finalCondition = mirrored ? cond.mirror() : cond; 248 249 Variable result = newVariable(trueValue.getLIRKind()); 250 if (cmpKind == Kind.Float || cmpKind == Kind.Double) { 251 append(new FloatCondMoveOp(result, finalCondition, unorderedIsTrue, load(trueValue), load(falseValue))); 252 } else { 253 append(new CondMoveOp(result, finalCondition, load(trueValue), loadNonConst(falseValue))); 254 } 255 return result; 256 } 257 258 @Override 259 public Variable emitIntegerTestMove(Value left, Value right, Value trueValue, Value falseValue) { 260 emitIntegerTest(left, right); 261 Variable result = newVariable(trueValue.getLIRKind()); 262 append(new CondMoveOp(result, Condition.EQ, load(trueValue), loadNonConst(falseValue))); 263 return result; 264 } 265 266 private void emitIntegerTest(Value a, Value b) { 267 assert a.getKind().isNumericInteger(); 268 if (LIRValueUtil.isVariable(b)) { 269 append(new AMD64TestOp(load(b), loadNonConst(a))); 270 } else { 271 append(new AMD64TestOp(load(a), loadNonConst(b))); 272 } 273 } 274 275 protected void emitCompareOp(PlatformKind cmpKind, Variable left, Value right) { 276 switch ((Kind) cmpKind) { 277 case Byte: 278 case Boolean: 279 append(new CompareOp(BCMP, left, right)); 280 break; 281 case Short: 282 case Char: 283 append(new CompareOp(SCMP, left, right)); 284 break; 285 case Int: 286 append(new CompareOp(ICMP, left, right)); 287 break; 288 case Long: 289 append(new CompareOp(LCMP, left, right)); 290 break; 291 case Object: 292 append(new CompareOp(ACMP, left, right)); 293 break; 294 case Float: 295 append(new CompareOp(FCMP, left, right)); 296 break; 297 case Double: 298 append(new CompareOp(DCMP, left, right)); 299 break; 300 default: 301 throw GraalInternalError.shouldNotReachHere(); 302 } 303 } 304 305 /** 306 * This method emits the compare against memory instruction, and may reorder the operands. It 307 * returns true if it did so. 308 * 309 * @param b the right operand of the comparison 310 * @return true if the left and right operands were switched, false otherwise 311 */ 312 private boolean emitCompareMemory(Kind cmpKind, Value a, AMD64AddressValue b, LIRFrameState state) { 313 boolean mirrored; 314 if (LIRValueUtil.isVariable(a)) { 315 Variable left = load(a); 316 emitCompareRegMemoryOp(cmpKind, left, b, state); 317 mirrored = false; 318 } else { 319 emitCompareMemoryConOp(cmpKind, b, (JavaConstant) a, state); 320 mirrored = true; 321 } 322 return mirrored; 323 } 324 325 protected void emitCompareMemoryConOp(Kind kind, AMD64AddressValue address, JavaConstant value, LIRFrameState state) { 326 assert kind.getStackKind() == value.getKind().getStackKind(); 327 switch (kind) { 328 case Byte: 329 case Boolean: 330 append(new CompareMemoryOp(BCMP, kind, address, value, state)); 331 break; 332 case Short: 333 case Char: 334 append(new CompareMemoryOp(SCMP, kind, address, value, state)); 335 break; 336 case Int: 337 append(new CompareMemoryOp(ICMP, kind, address, value, state)); 338 break; 339 case Long: 340 append(new CompareMemoryOp(LCMP, kind, address, value, state)); 341 break; 342 case Object: 343 assert value.isNull(); 344 append(new CompareMemoryOp(ACMP, kind, address, value, state)); 345 break; 346 default: 347 throw GraalInternalError.shouldNotReachHere(); 348 } 349 } 350 351 protected void emitCompareRegMemoryOp(Kind kind, Value value, AMD64AddressValue address, LIRFrameState state) { 352 AMD64Compare opcode = null; 353 switch (kind) { 354 case Byte: 355 case Boolean: 356 opcode = BCMP; 357 break; 358 case Short: 359 case Char: 360 opcode = SCMP; 361 break; 362 case Int: 363 opcode = ICMP; 364 break; 365 case Long: 366 opcode = LCMP; 367 break; 368 case Object: 369 opcode = ACMP; 370 break; 371 case Float: 372 opcode = FCMP; 373 break; 374 case Double: 375 opcode = DCMP; 376 break; 377 default: 378 throw GraalInternalError.shouldNotReachHere(); 379 } 380 append(new CompareMemoryOp(opcode, kind, address, value, state)); 381 } 382 383 /** 384 * This method emits the compare instruction, and may reorder the operands. It returns true if 385 * it did so. 386 * 387 * @param a the left operand of the comparison 388 * @param b the right operand of the comparison 389 * @return true if the left and right operands were switched, false otherwise 390 */ 391 private boolean emitCompare(PlatformKind cmpKind, Value a, Value b) { 392 Variable left; 393 Value right; 394 boolean mirrored; 395 if (LIRValueUtil.isVariable(b)) { 396 left = load(b); 397 right = loadNonConst(a); 398 mirrored = true; 399 } else { 400 left = load(a); 401 right = loadNonConst(b); 402 mirrored = false; 403 } 404 emitCompareOp(cmpKind, left, right); 405 return mirrored; 406 } 407 408 @Override 409 public Variable emitNegate(Value inputVal) { 410 AllocatableValue input = asAllocatable(inputVal); 411 Variable result = newVariable(LIRKind.derive(input)); 412 switch (input.getKind()) { 413 case Int: 414 append(new Unary1Op(INEG, result, input)); 415 break; 416 case Long: 417 append(new Unary1Op(LNEG, result, input)); 418 break; 419 case Float: 420 append(new BinaryRegConst(FXOR, result, input, JavaConstant.forFloat(Float.intBitsToFloat(0x80000000)))); 421 break; 422 case Double: 423 append(new BinaryRegConst(DXOR, result, input, JavaConstant.forDouble(Double.longBitsToDouble(0x8000000000000000L)))); 424 break; 425 default: 426 throw GraalInternalError.shouldNotReachHere(); 427 } 428 return result; 429 } 430 431 @Override 432 public Variable emitNot(Value inputVal) { 433 AllocatableValue input = asAllocatable(inputVal); 434 Variable result = newVariable(LIRKind.derive(input)); 435 switch (input.getKind()) { 436 case Int: 437 append(new Unary1Op(INOT, result, input)); 438 break; 439 case Long: 440 append(new Unary1Op(LNOT, result, input)); 441 break; 442 default: 443 throw GraalInternalError.shouldNotReachHere(); 444 } 445 return result; 446 } 447 448 private Variable emitBinary(AMD64Arithmetic op, boolean commutative, Value a, Value b) { 449 if (isConstant(b)) { 450 return emitBinaryConst(op, commutative, asAllocatable(a), asConstant(b)); 451 } else if (commutative && isConstant(a)) { 452 return emitBinaryConst(op, commutative, asAllocatable(b), asConstant(a)); 453 } else { 454 return emitBinaryVar(op, commutative, asAllocatable(a), asAllocatable(b)); 455 } 456 } 457 458 private Variable emitBinaryConst(AMD64Arithmetic op, boolean commutative, AllocatableValue a, JavaConstant b) { 459 switch (op) { 460 case IADD: 461 case LADD: 462 case ISUB: 463 case LSUB: 464 case IAND: 465 case LAND: 466 case IOR: 467 case LOR: 468 case IXOR: 469 case LXOR: 470 if (NumUtil.isInt(b.asLong())) { 471 Variable result = newVariable(LIRKind.derive(a, b)); 472 append(new BinaryRegConst(op, result, a, b)); 473 return result; 474 } 475 break; 476 477 case IMUL: 478 case LMUL: 479 if (NumUtil.isInt(b.asLong())) { 480 Variable result = newVariable(LIRKind.derive(a, b)); 481 append(new BinaryRegStackConst(op, result, a, b)); 482 return result; 483 } 484 break; 485 } 486 487 return emitBinaryVar(op, commutative, a, asAllocatable(b)); 488 } 489 490 private Variable emitBinaryVar(AMD64Arithmetic op, boolean commutative, AllocatableValue a, AllocatableValue b) { 491 Variable result = newVariable(LIRKind.derive(a, b)); 492 if (commutative) { 493 append(new BinaryCommutative(op, result, a, b)); 494 } else { 495 append(new BinaryRegStack(op, result, a, b)); 496 } 497 return result; 498 } 499 500 @Override 501 public Variable emitAdd(Value a, Value b) { 502 switch (a.getKind().getStackKind()) { 503 case Int: 504 return emitBinary(IADD, true, a, b); 505 case Long: 506 return emitBinary(LADD, true, a, b); 507 case Float: 508 return emitBinary(FADD, true, a, b); 509 case Double: 510 return emitBinary(DADD, true, a, b); 511 default: 512 throw GraalInternalError.shouldNotReachHere(); 513 } 514 } 515 516 @Override 517 public Variable emitSub(Value a, Value b) { 518 switch (a.getKind().getStackKind()) { 519 case Int: 520 return emitBinary(ISUB, false, a, b); 521 case Long: 522 return emitBinary(LSUB, false, a, b); 523 case Float: 524 return emitBinary(FSUB, false, a, b); 525 case Double: 526 return emitBinary(DSUB, false, a, b); 527 default: 528 throw GraalInternalError.shouldNotReachHere(); 529 } 530 } 531 532 @Override 533 public Variable emitMul(Value a, Value b) { 534 switch (a.getKind().getStackKind()) { 535 case Int: 536 return emitBinary(IMUL, true, a, b); 537 case Long: 538 return emitBinary(LMUL, true, a, b); 539 case Float: 540 return emitBinary(FMUL, true, a, b); 541 case Double: 542 return emitBinary(DMUL, true, a, b); 543 default: 544 throw GraalInternalError.shouldNotReachHere(); 545 } 546 } 547 548 private Value emitMulHigh(AMD64Arithmetic opcode, Value a, Value b) { 549 MulHighOp mulHigh = new MulHighOp(opcode, LIRKind.derive(a, b), asAllocatable(b)); 550 emitMove(mulHigh.x, a); 551 append(mulHigh); 552 return emitMove(mulHigh.highResult); 553 } 554 555 @Override 556 public Value emitMulHigh(Value a, Value b) { 557 switch (a.getKind().getStackKind()) { 558 case Int: 559 return emitMulHigh(IMUL, a, b); 560 case Long: 561 return emitMulHigh(LMUL, a, b); 562 default: 563 throw GraalInternalError.shouldNotReachHere(); 564 } 565 } 566 567 @Override 568 public Value emitUMulHigh(Value a, Value b) { 569 switch (a.getKind().getStackKind()) { 570 case Int: 571 return emitMulHigh(IUMUL, a, b); 572 case Long: 573 return emitMulHigh(LUMUL, a, b); 574 default: 575 throw GraalInternalError.shouldNotReachHere(); 576 } 577 } 578 579 public Value emitBinaryMemory(AMD64Arithmetic op, Kind kind, AllocatableValue a, AMD64AddressValue location, LIRFrameState state) { 580 Variable result = newVariable(LIRKind.derive(a)); 581 append(new BinaryMemory(op, kind, result, a, location, state)); 582 return result; 583 } 584 585 protected Value emitConvert2MemoryOp(PlatformKind kind, AMD64Arithmetic op, AMD64AddressValue address, LIRFrameState state) { 586 Variable result = newVariable(LIRKind.value(kind)); 587 append(new Unary2MemoryOp(op, result, (Kind) null, address, state)); 588 return result; 589 } 590 591 protected Value emitZeroExtendMemory(Kind memoryKind, int resultBits, AMD64AddressValue address, LIRFrameState state) { 592 // Issue a zero extending load of the proper bit size and set the result to 593 // the proper kind. 594 Variable result = newVariable(LIRKind.value(resultBits == 32 ? Kind.Int : Kind.Long)); 595 append(new ZeroExtendLoadOp(memoryKind, result, address, state)); 596 return result; 597 } 598 599 private DivRemOp emitDivRem(AMD64Arithmetic op, Value a, Value b, LIRFrameState state) { 600 AllocatableValue rax = AMD64.rax.asValue(a.getLIRKind()); 601 emitMove(rax, a); 602 DivRemOp ret = new DivRemOp(op, rax, asAllocatable(b), state); 603 append(ret); 604 return ret; 605 } 606 607 public Value[] emitIntegerDivRem(Value a, Value b, LIRFrameState state) { 608 DivRemOp op; 609 switch (a.getKind().getStackKind()) { 610 case Int: 611 op = emitDivRem(IDIVREM, a, b, state); 612 break; 613 case Long: 614 op = emitDivRem(LDIVREM, a, b, state); 615 break; 616 default: 617 throw GraalInternalError.shouldNotReachHere(); 618 } 619 return new Value[]{emitMove(op.divResult), emitMove(op.remResult)}; 620 } 621 622 @Override 623 public Value emitDiv(Value a, Value b, LIRFrameState state) { 624 switch (a.getKind().getStackKind()) { 625 case Int: 626 DivRemOp op = emitDivRem(IDIV, a, b, state); 627 return emitMove(op.divResult); 628 case Long: 629 DivRemOp lop = emitDivRem(LDIV, a, b, state); 630 return emitMove(lop.divResult); 631 case Float: { 632 Variable result = newVariable(LIRKind.derive(a, b)); 633 append(new BinaryRegStack(FDIV, result, asAllocatable(a), asAllocatable(b))); 634 return result; 635 } 636 case Double: { 637 Variable result = newVariable(LIRKind.derive(a, b)); 638 append(new BinaryRegStack(DDIV, result, asAllocatable(a), asAllocatable(b))); 639 return result; 640 } 641 default: 642 throw GraalInternalError.shouldNotReachHere(); 643 } 644 } 645 646 @Override 647 public Value emitRem(Value a, Value b, LIRFrameState state) { 648 switch (a.getKind().getStackKind()) { 649 case Int: 650 DivRemOp op = emitDivRem(IREM, a, b, state); 651 return emitMove(op.remResult); 652 case Long: 653 DivRemOp lop = emitDivRem(LREM, a, b, state); 654 return emitMove(lop.remResult); 655 case Float: { 656 Variable result = newVariable(LIRKind.derive(a, b)); 657 append(new FPDivRemOp(FREM, result, load(a), load(b))); 658 return result; 659 } 660 case Double: { 661 Variable result = newVariable(LIRKind.derive(a, b)); 662 append(new FPDivRemOp(DREM, result, load(a), load(b))); 663 return result; 664 } 665 default: 666 throw GraalInternalError.shouldNotReachHere(); 667 } 668 } 669 670 @Override 671 public Variable emitUDiv(Value a, Value b, LIRFrameState state) { 672 DivRemOp op; 673 switch (a.getKind().getStackKind()) { 674 case Int: 675 op = emitDivRem(IUDIV, a, b, state); 676 break; 677 case Long: 678 op = emitDivRem(LUDIV, a, b, state); 679 break; 680 default: 681 throw GraalInternalError.shouldNotReachHere(); 682 } 683 return emitMove(op.divResult); 684 } 685 686 @Override 687 public Variable emitURem(Value a, Value b, LIRFrameState state) { 688 DivRemOp op; 689 switch (a.getKind().getStackKind()) { 690 case Int: 691 op = emitDivRem(IUREM, a, b, state); 692 break; 693 case Long: 694 op = emitDivRem(LUREM, a, b, state); 695 break; 696 default: 697 throw GraalInternalError.shouldNotReachHere(); 698 } 699 return emitMove(op.remResult); 700 } 701 702 @Override 703 public Variable emitAnd(Value a, Value b) { 704 switch (a.getKind().getStackKind()) { 705 case Int: 706 return emitBinary(IAND, true, a, b); 707 case Long: 708 return emitBinary(LAND, true, a, b); 709 default: 710 throw GraalInternalError.shouldNotReachHere(); 711 } 712 } 713 714 @Override 715 public Variable emitOr(Value a, Value b) { 716 switch (a.getKind().getStackKind()) { 717 case Int: 718 return emitBinary(IOR, true, a, b); 719 case Long: 720 return emitBinary(LOR, true, a, b); 721 default: 722 throw GraalInternalError.shouldNotReachHere(); 723 } 724 } 725 726 @Override 727 public Variable emitXor(Value a, Value b) { 728 switch (a.getKind().getStackKind()) { 729 case Int: 730 return emitBinary(IXOR, true, a, b); 731 case Long: 732 return emitBinary(LXOR, true, a, b); 733 default: 734 throw GraalInternalError.shouldNotReachHere(); 735 } 736 } 737 738 private Variable emitShift(AMD64Arithmetic op, Value a, Value b) { 739 Variable result = newVariable(LIRKind.derive(a, b).changeType(a.getPlatformKind())); 740 AllocatableValue input = asAllocatable(a); 741 if (isConstant(b)) { 742 append(new BinaryRegConst(op, result, input, asConstant(b))); 743 } else { 744 emitMove(RCX_I, b); 745 append(new BinaryRegReg(op, result, input, RCX_I)); 746 } 747 return result; 748 } 749 750 @Override 751 public Variable emitShl(Value a, Value b) { 752 switch (a.getKind().getStackKind()) { 753 case Int: 754 return emitShift(ISHL, a, b); 755 case Long: 756 return emitShift(LSHL, a, b); 757 default: 758 throw GraalInternalError.shouldNotReachHere(); 759 } 760 } 761 762 @Override 763 public Variable emitShr(Value a, Value b) { 764 switch (a.getKind().getStackKind()) { 765 case Int: 766 return emitShift(ISHR, a, b); 767 case Long: 768 return emitShift(LSHR, a, b); 769 default: 770 throw GraalInternalError.shouldNotReachHere(); 771 } 772 } 773 774 @Override 775 public Variable emitUShr(Value a, Value b) { 776 switch (a.getKind().getStackKind()) { 777 case Int: 778 return emitShift(IUSHR, a, b); 779 case Long: 780 return emitShift(LUSHR, a, b); 781 default: 782 throw GraalInternalError.shouldNotReachHere(); 783 } 784 } 785 786 public Variable emitRol(Value a, Value b) { 787 switch (a.getKind().getStackKind()) { 788 case Int: 789 return emitShift(IROL, a, b); 790 case Long: 791 return emitShift(LROL, a, b); 792 default: 793 throw GraalInternalError.shouldNotReachHere(); 794 } 795 } 796 797 public Variable emitRor(Value a, Value b) { 798 switch (a.getKind().getStackKind()) { 799 case Int: 800 return emitShift(IROR, a, b); 801 case Long: 802 return emitShift(LROR, a, b); 803 default: 804 throw GraalInternalError.shouldNotReachHere(); 805 } 806 } 807 808 private AllocatableValue emitConvert2RegOp(LIRKind kind, AMD64Arithmetic op, AllocatableValue input) { 809 Variable result = newVariable(kind); 810 append(new Unary2RegOp(op, result, input)); 811 return result; 812 } 813 814 private AllocatableValue emitConvert2Op(LIRKind kind, AMD64Arithmetic op, AllocatableValue input) { 815 Variable result = newVariable(kind); 816 append(new Unary2Op(op, result, input)); 817 return result; 818 } 819 820 @Override 821 public Value emitReinterpret(LIRKind to, Value inputVal) { 822 LIRKind from = inputVal.getLIRKind(); 823 if (to.equals(from)) { 824 return inputVal; 825 } 826 827 AllocatableValue input = asAllocatable(inputVal); 828 /* 829 * Conversions between integer to floating point types require moves between CPU and FPU 830 * registers. 831 */ 832 Kind fromKind = (Kind) from.getPlatformKind(); 833 switch ((Kind) to.getPlatformKind()) { 834 case Int: 835 switch (fromKind) { 836 case Float: 837 return emitConvert2Op(to, MOV_F2I, input); 838 } 839 break; 840 case Long: 841 switch (fromKind) { 842 case Double: 843 return emitConvert2Op(to, MOV_D2L, input); 844 } 845 break; 846 case Float: 847 switch (fromKind) { 848 case Int: 849 return emitConvert2Op(to, MOV_I2F, input); 850 } 851 break; 852 case Double: 853 switch (fromKind) { 854 case Long: 855 return emitConvert2Op(to, MOV_L2D, input); 856 } 857 break; 858 } 859 throw GraalInternalError.shouldNotReachHere(); 860 } 861 862 public Value emitFloatConvert(FloatConvert op, Value inputVal) { 863 AllocatableValue input = asAllocatable(inputVal); 864 switch (op) { 865 case D2F: 866 return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Float), D2F, input); 867 case D2I: 868 return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Int), D2I, input); 869 case D2L: 870 return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Long), D2L, input); 871 case F2D: 872 return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Double), F2D, input); 873 case F2I: 874 return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Int), F2I, input); 875 case F2L: 876 return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Long), F2L, input); 877 case I2D: 878 return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Double), I2D, input); 879 case I2F: 880 return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Float), I2F, input); 881 case L2D: 882 return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Double), L2D, input); 883 case L2F: 884 return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Float), L2F, input); 885 default: 886 throw GraalInternalError.shouldNotReachHere(); 887 } 888 } 889 890 @Override 891 public Value emitNarrow(Value inputVal, int bits) { 892 if (inputVal.getKind() == Kind.Long && bits <= 32) { 893 // TODO make it possible to reinterpret Long as Int in LIR without move 894 return emitConvert2RegOp(LIRKind.derive(inputVal).changeType(Kind.Int), L2I, asAllocatable(inputVal)); 895 } else { 896 return inputVal; 897 } 898 } 899 900 @Override 901 public Value emitSignExtend(Value inputVal, int fromBits, int toBits) { 902 assert fromBits <= toBits && toBits <= 64; 903 if (fromBits == toBits) { 904 return inputVal; 905 } else if (toBits > 32) { 906 // sign extend to 64 bits 907 switch (fromBits) { 908 case 8: 909 return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Long), B2L, asAllocatable(inputVal)); 910 case 16: 911 return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Long), S2L, asAllocatable(inputVal)); 912 case 32: 913 return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Long), I2L, asAllocatable(inputVal)); 914 default: 915 throw GraalInternalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)"); 916 } 917 } else { 918 // sign extend to 32 bits (smaller values are internally represented as 32 bit values) 919 switch (fromBits) { 920 case 8: 921 return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Int), B2I, asAllocatable(inputVal)); 922 case 16: 923 return emitConvert2Op(LIRKind.derive(inputVal).changeType(Kind.Int), S2I, asAllocatable(inputVal)); 924 case 32: 925 return inputVal; 926 default: 927 throw GraalInternalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)"); 928 } 929 } 930 } 931 932 @Override 933 public Value emitZeroExtend(Value inputVal, int fromBits, int toBits) { 934 assert fromBits <= toBits && toBits <= 64; 935 if (fromBits == toBits) { 936 return inputVal; 937 } else if (fromBits > 32) { 938 assert inputVal.getKind() == Kind.Long; 939 Variable result = newVariable(LIRKind.derive(inputVal).changeType(Kind.Long)); 940 long mask = CodeUtil.mask(fromBits); 941 append(new BinaryRegConst(AMD64Arithmetic.LAND, result, asAllocatable(inputVal), JavaConstant.forLong(mask))); 942 return result; 943 } else { 944 assert inputVal.getKind().getStackKind() == Kind.Int; 945 Variable result = newVariable(LIRKind.derive(inputVal).changeType(Kind.Int)); 946 int mask = (int) CodeUtil.mask(fromBits); 947 append(new BinaryRegConst(AMD64Arithmetic.IAND, result, asAllocatable(inputVal), JavaConstant.forInt(mask))); 948 if (toBits > 32) { 949 Variable longResult = newVariable(LIRKind.derive(inputVal).changeType(Kind.Long)); 950 emitMove(longResult, result); 951 return longResult; 952 } else { 953 return result; 954 } 955 } 956 } 957 958 @Override 959 public void emitMembar(int barriers) { 960 int necessaryBarriers = target().arch.requiredBarriers(barriers); 961 if (target().isMP && necessaryBarriers != 0) { 962 append(new MembarOp(necessaryBarriers)); 963 } 964 } 965 966 public abstract void emitCCall(long address, CallingConvention nativeCallingConvention, Value[] args, int numberOfFloatingPointArguments); 967 968 @Override 969 protected void emitForeignCall(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info) { 970 long maxOffset = linkage.getMaxCallTargetOffset(); 971 if (maxOffset != (int) maxOffset) { 972 append(new AMD64Call.DirectFarForeignCallOp(linkage, result, arguments, temps, info)); 973 } else { 974 append(new AMD64Call.DirectNearForeignCallOp(linkage, result, arguments, temps, info)); 975 } 976 } 977 978 @Override 979 public Value emitBitCount(Value value) { 980 Variable result = newVariable(LIRKind.derive(value).changeType(Kind.Int)); 981 if (value.getKind().getStackKind() == Kind.Int) { 982 append(new AMD64BitManipulationOp(IPOPCNT, result, asAllocatable(value))); 983 } else { 984 append(new AMD64BitManipulationOp(LPOPCNT, result, asAllocatable(value))); 985 } 986 return result; 987 } 988 989 @Override 990 public Value emitBitScanForward(Value value) { 991 Variable result = newVariable(LIRKind.derive(value).changeType(Kind.Int)); 992 append(new AMD64BitManipulationOp(BSF, result, asAllocatable(value))); 993 return result; 994 } 995 996 @Override 997 public Value emitBitScanReverse(Value value) { 998 Variable result = newVariable(LIRKind.derive(value).changeType(Kind.Int)); 999 if (value.getKind().getStackKind() == Kind.Int) { 1000 append(new AMD64BitManipulationOp(IBSR, result, asAllocatable(value))); 1001 } else { 1002 append(new AMD64BitManipulationOp(LBSR, result, asAllocatable(value))); 1003 } 1004 return result; 1005 } 1006 1007 public Value emitCountLeadingZeros(Value value) { 1008 Variable result = newVariable(LIRKind.derive(value).changeType(Kind.Int)); 1009 if (value.getKind().getStackKind() == Kind.Int) { 1010 append(new AMD64BitManipulationOp(ILZCNT, result, asAllocatable(value))); 1011 } else { 1012 append(new AMD64BitManipulationOp(LLZCNT, result, asAllocatable(value))); 1013 } 1014 return result; 1015 } 1016 1017 public Value emitCountTrailingZeros(Value value) { 1018 Variable result = newVariable(LIRKind.derive(value).changeType(Kind.Int)); 1019 if (value.getKind().getStackKind() == Kind.Int) { 1020 append(new AMD64BitManipulationOp(ITZCNT, result, asAllocatable(value))); 1021 } else { 1022 append(new AMD64BitManipulationOp(LTZCNT, result, asAllocatable(value))); 1023 } 1024 return result; 1025 } 1026 1027 @Override 1028 public Value emitMathAbs(Value input) { 1029 Variable result = newVariable(LIRKind.derive(input)); 1030 switch (input.getKind()) { 1031 case Float: 1032 append(new BinaryRegConst(FAND, result, asAllocatable(input), JavaConstant.forFloat(Float.intBitsToFloat(0x7FFFFFFF)))); 1033 break; 1034 case Double: 1035 append(new BinaryRegConst(DAND, result, asAllocatable(input), JavaConstant.forDouble(Double.longBitsToDouble(0x7FFFFFFFFFFFFFFFL)))); 1036 break; 1037 default: 1038 throw GraalInternalError.shouldNotReachHere(); 1039 } 1040 return result; 1041 } 1042 1043 @Override 1044 public Value emitMathSqrt(Value input) { 1045 Variable result = newVariable(LIRKind.derive(input)); 1046 append(new Unary2Op(SQRT, result, asAllocatable(input))); 1047 return result; 1048 } 1049 1050 @Override 1051 public Value emitMathLog(Value input, boolean base10) { 1052 Variable result = newVariable(LIRKind.derive(input)); 1053 append(new AMD64MathIntrinsicOp(base10 ? LOG10 : LOG, result, asAllocatable(input))); 1054 return result; 1055 } 1056 1057 @Override 1058 public Value emitMathCos(Value input) { 1059 Variable result = newVariable(LIRKind.derive(input)); 1060 append(new AMD64MathIntrinsicOp(COS, result, asAllocatable(input))); 1061 return result; 1062 } 1063 1064 @Override 1065 public Value emitMathSin(Value input) { 1066 Variable result = newVariable(LIRKind.derive(input)); 1067 append(new AMD64MathIntrinsicOp(SIN, result, asAllocatable(input))); 1068 return result; 1069 } 1070 1071 @Override 1072 public Value emitMathTan(Value input) { 1073 Variable result = newVariable(LIRKind.derive(input)); 1074 append(new AMD64MathIntrinsicOp(TAN, result, asAllocatable(input))); 1075 return result; 1076 } 1077 1078 @Override 1079 public Value emitByteSwap(Value input) { 1080 Variable result = newVariable(LIRKind.derive(input)); 1081 append(new AMD64ByteSwapOp(result, input)); 1082 return result; 1083 } 1084 1085 @Override 1086 public Value emitArrayEquals(Kind kind, Value array1, Value array2, Value length) { 1087 Variable result = newVariable(LIRKind.value(Kind.Int)); 1088 append(new AMD64ArrayEqualsOp(this, kind, result, array1, array2, asAllocatable(length))); 1089 return result; 1090 } 1091 1092 @Override 1093 public void emitReturn(Value input) { 1094 AllocatableValue operand = Value.ILLEGAL; 1095 if (input != null) { 1096 operand = resultOperandFor(input.getLIRKind()); 1097 emitMove(operand, input); 1098 } 1099 append(new ReturnOp(operand)); 1100 } 1101 1102 @Override 1103 public void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) { 1104 // a temp is needed for loading object constants 1105 boolean needsTemp = key.getKind() == Kind.Object; 1106 append(new StrategySwitchOp(strategy, keyTargets, defaultTarget, key, needsTemp ? newVariable(key.getLIRKind()) : Value.ILLEGAL)); 1107 } 1108 1109 @Override 1110 protected void emitTableSwitch(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value key) { 1111 append(new TableSwitchOp(lowKey, defaultTarget, targets, key, newVariable(LIRKind.value(target().wordKind)), newVariable(key.getLIRKind()))); 1112 } 1113 1114 }