001/* 002 * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023 024package com.oracle.graal.compiler.amd64; 025 026import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.*; 027import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MOp.*; 028import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp.*; 029import static com.oracle.graal.asm.amd64.AMD64Assembler.AMD64Shift.*; 030import static com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize.*; 031import static com.oracle.graal.lir.amd64.AMD64Arithmetic.*; 032import static com.oracle.graal.lir.amd64.AMD64MathIntrinsicOp.IntrinsicOpcode.*; 033import static jdk.internal.jvmci.code.ValueUtil.*; 034 035import java.util.*; 036 037import jdk.internal.jvmci.amd64.*; 038import jdk.internal.jvmci.code.*; 039import jdk.internal.jvmci.common.*; 040import jdk.internal.jvmci.meta.*; 041 042import com.oracle.graal.asm.*; 043import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic; 044import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MIOp; 045import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MOp; 046import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MROp; 047import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMIOp; 048import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp; 049import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64Shift; 050import com.oracle.graal.asm.amd64.AMD64Assembler.ConditionFlag; 051import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize; 052import com.oracle.graal.asm.amd64.AMD64Assembler.SSEOp; 053import com.oracle.graal.compiler.common.calc.*; 054import com.oracle.graal.compiler.common.spi.*; 055import com.oracle.graal.compiler.common.util.*; 056import com.oracle.graal.lir.*; 057import com.oracle.graal.lir.StandardOp.JumpOp; 058import com.oracle.graal.lir.amd64.*; 059import com.oracle.graal.lir.amd64.AMD64Arithmetic.FPDivRemOp; 060import com.oracle.graal.lir.amd64.AMD64ControlFlow.BranchOp; 061import com.oracle.graal.lir.amd64.AMD64ControlFlow.CondMoveOp; 062import com.oracle.graal.lir.amd64.AMD64ControlFlow.FloatBranchOp; 063import com.oracle.graal.lir.amd64.AMD64ControlFlow.FloatCondMoveOp; 064import com.oracle.graal.lir.amd64.AMD64ControlFlow.ReturnOp; 065import com.oracle.graal.lir.amd64.AMD64ControlFlow.StrategySwitchOp; 066import com.oracle.graal.lir.amd64.AMD64ControlFlow.TableSwitchOp; 067import com.oracle.graal.lir.amd64.AMD64Move.AMD64PushPopStackMove; 068import com.oracle.graal.lir.amd64.AMD64Move.AMD64StackMove; 069import com.oracle.graal.lir.amd64.AMD64Move.CompareAndSwapOp; 070import com.oracle.graal.lir.amd64.AMD64Move.LeaDataOp; 071import com.oracle.graal.lir.amd64.AMD64Move.LeaOp; 072import com.oracle.graal.lir.amd64.AMD64Move.MembarOp; 073import com.oracle.graal.lir.amd64.AMD64Move.MoveFromRegOp; 074import com.oracle.graal.lir.amd64.AMD64Move.MoveToRegOp; 075import com.oracle.graal.lir.amd64.AMD64Move.StackLeaOp; 076import com.oracle.graal.lir.framemap.*; 077import com.oracle.graal.lir.gen.*; 078import com.oracle.graal.phases.util.*; 079 080/** 081 * This class implements the AMD64 specific portion of the LIR generator. 082 */ 083public abstract class AMD64LIRGenerator extends LIRGenerator implements AMD64ArithmeticLIRGenerator { 084 085 private static final RegisterValue RCX_I = AMD64.rcx.asValue(LIRKind.value(Kind.Int)); 086 private AMD64SpillMoveFactory moveFactory; 087 private Map<PlatformKind.Key, RegisterBackupPair> categorized; 088 089 private static class RegisterBackupPair { 090 public final Register register; 091 public final StackSlotValue backupSlot; 092 093 RegisterBackupPair(Register register, StackSlotValue backupSlot) { 094 this.register = register; 095 this.backupSlot = backupSlot; 096 } 097 } 098 099 private class AMD64SpillMoveFactory extends SpillMoveFactoryBase { 100 101 @Override 102 protected LIRInstruction createMoveIntern(AllocatableValue result, Value input) { 103 return AMD64LIRGenerator.this.createMove(result, input); 104 } 105 106 @Override 107 protected LIRInstruction createStackMoveIntern(AllocatableValue result, Value input) { 108 return AMD64LIRGenerator.this.createStackMove(result, input); 109 } 110 111 } 112 113 public AMD64LIRGenerator(LIRKindTool lirKindTool, Providers providers, CallingConvention cc, LIRGenerationResult lirGenRes) { 114 super(lirKindTool, providers, cc, lirGenRes); 115 } 116 117 public SpillMoveFactory getSpillMoveFactory() { 118 if (moveFactory == null) { 119 moveFactory = new AMD64SpillMoveFactory(); 120 } 121 return moveFactory; 122 } 123 124 @Override 125 public boolean canInlineConstant(JavaConstant c) { 126 switch (c.getKind()) { 127 case Long: 128 return NumUtil.isInt(c.asLong()) && !getCodeCache().needsDataPatch(c); 129 case Object: 130 return c.isNull(); 131 default: 132 return true; 133 } 134 } 135 136 /** 137 * Checks whether the supplied constant can be used without loading it into a register for store 138 * operations, i.e., on the right hand side of a memory access. 139 * 140 * @param c The constant to check. 141 * @return True if the constant can be used directly, false if the constant needs to be in a 142 * register. 143 */ 144 protected final boolean canStoreConstant(JavaConstant c) { 145 // there is no immediate move of 64-bit constants on Intel 146 switch (c.getKind()) { 147 case Long: 148 return Util.isInt(c.asLong()) && !getCodeCache().needsDataPatch(c); 149 case Double: 150 return false; 151 case Object: 152 return c.isNull(); 153 default: 154 return true; 155 } 156 } 157 158 protected AMD64LIRInstruction createMove(AllocatableValue dst, Value src) { 159 if (src instanceof AMD64AddressValue) { 160 return new LeaOp(dst, (AMD64AddressValue) src); 161 } else if (isRegister(src) || isStackSlotValue(dst)) { 162 return new MoveFromRegOp(dst.getKind(), dst, src); 163 } else { 164 return new MoveToRegOp(dst.getKind(), dst, src); 165 } 166 } 167 168 protected LIRInstruction createStackMove(AllocatableValue result, Value input) { 169 Kind kind = result.getKind(); 170 OperandSize size; 171 switch (kind) { 172 case Long: 173 case Double: 174 size = QWORD; 175 break; 176 case Short: 177 size = WORD; 178 break; 179 default: 180 RegisterBackupPair backup = getScratchRegister(input.getPlatformKind()); 181 Register scratchRegister = backup.register; 182 StackSlotValue backupSlot = backup.backupSlot; 183 return createStackMove(result, input, scratchRegister, backupSlot); 184 } 185 return new AMD64PushPopStackMove(size, result, input); 186 } 187 188 protected LIRInstruction createStackMove(AllocatableValue result, Value input, Register scratchRegister, StackSlotValue backupSlot) { 189 return new AMD64StackMove(result, input, scratchRegister, backupSlot); 190 } 191 192 protected RegisterBackupPair getScratchRegister(PlatformKind kind) { 193 PlatformKind.Key key = kind.getKey(); 194 if (categorized == null) { 195 categorized = new HashMap<>(); 196 } else if (categorized.containsKey(key)) { 197 return categorized.get(key); 198 } 199 200 FrameMapBuilder frameMapBuilder = getResult().getFrameMapBuilder(); 201 RegisterConfig registerConfig = frameMapBuilder.getRegisterConfig(); 202 203 Register[] availableRegister = registerConfig.filterAllocatableRegisters(kind, registerConfig.getAllocatableRegisters()); 204 assert availableRegister != null && availableRegister.length > 1; 205 Register scratchRegister = availableRegister[0]; 206 207 Architecture arch = frameMapBuilder.getCodeCache().getTarget().arch; 208 LIRKind largestKind = LIRKind.value(arch.getLargestStorableKind(scratchRegister.getRegisterCategory())); 209 VirtualStackSlot backupSlot = frameMapBuilder.allocateSpillSlot(largestKind); 210 211 RegisterBackupPair value = new RegisterBackupPair(scratchRegister, backupSlot); 212 categorized.put(key, value); 213 214 return value; 215 } 216 217 @Override 218 public void emitMove(AllocatableValue dst, Value src) { 219 append(createMove(dst, src)); 220 } 221 222 public void emitData(AllocatableValue dst, byte[] data) { 223 append(new LeaDataOp(dst, data)); 224 } 225 226 public AMD64AddressValue asAddressValue(Value address) { 227 if (address instanceof AMD64AddressValue) { 228 return (AMD64AddressValue) address; 229 } else { 230 if (address instanceof JavaConstant) { 231 long displacement = ((JavaConstant) address).asLong(); 232 if (NumUtil.isInt(displacement)) { 233 return new AMD64AddressValue(address.getLIRKind(), Value.ILLEGAL, (int) displacement); 234 } 235 } 236 return new AMD64AddressValue(address.getLIRKind(), asAllocatable(address), 0); 237 } 238 } 239 240 @Override 241 public Variable emitAddress(StackSlotValue address) { 242 Variable result = newVariable(LIRKind.value(target().wordKind)); 243 append(new StackLeaOp(result, address)); 244 return result; 245 } 246 247 private static LIRKind toStackKind(LIRKind kind) { 248 if (kind.getPlatformKind() instanceof Kind) { 249 Kind stackKind = ((Kind) kind.getPlatformKind()).getStackKind(); 250 return kind.changeType(stackKind); 251 } else { 252 return kind; 253 } 254 } 255 256 @Override 257 public Variable emitLoad(LIRKind kind, Value address, LIRFrameState state) { 258 AMD64AddressValue loadAddress = asAddressValue(address); 259 Variable result = newVariable(toStackKind(kind)); 260 switch ((Kind) kind.getPlatformKind()) { 261 case Boolean: 262 append(new AMD64Unary.MemoryOp(MOVZXB, DWORD, result, loadAddress, state)); 263 break; 264 case Byte: 265 append(new AMD64Unary.MemoryOp(MOVSXB, DWORD, result, loadAddress, state)); 266 break; 267 case Char: 268 append(new AMD64Unary.MemoryOp(MOVZX, DWORD, result, loadAddress, state)); 269 break; 270 case Short: 271 append(new AMD64Unary.MemoryOp(MOVSX, DWORD, result, loadAddress, state)); 272 break; 273 case Int: 274 append(new AMD64Unary.MemoryOp(MOV, DWORD, result, loadAddress, state)); 275 break; 276 case Long: 277 case Object: 278 append(new AMD64Unary.MemoryOp(MOV, QWORD, result, loadAddress, state)); 279 break; 280 case Float: 281 append(new AMD64Unary.MemoryOp(MOVSS, SS, result, loadAddress, state)); 282 break; 283 case Double: 284 append(new AMD64Unary.MemoryOp(MOVSD, SD, result, loadAddress, state)); 285 break; 286 default: 287 throw JVMCIError.shouldNotReachHere(); 288 } 289 return result; 290 } 291 292 protected void emitStoreConst(Kind kind, AMD64AddressValue address, JavaConstant value, LIRFrameState state) { 293 if (value.isNull()) { 294 assert kind == Kind.Int || kind == Kind.Long || kind == Kind.Object; 295 OperandSize size = kind == Kind.Int ? DWORD : QWORD; 296 append(new AMD64BinaryConsumer.MemoryConstOp(AMD64MIOp.MOV, size, address, 0, state)); 297 } else { 298 AMD64MIOp op = AMD64MIOp.MOV; 299 OperandSize size; 300 long imm; 301 302 switch (kind) { 303 case Boolean: 304 case Byte: 305 op = AMD64MIOp.MOVB; 306 size = BYTE; 307 imm = value.asInt(); 308 break; 309 case Char: 310 case Short: 311 size = WORD; 312 imm = value.asInt(); 313 break; 314 case Int: 315 size = DWORD; 316 imm = value.asInt(); 317 break; 318 case Long: 319 size = QWORD; 320 imm = value.asLong(); 321 break; 322 case Float: 323 size = DWORD; 324 imm = Float.floatToRawIntBits(value.asFloat()); 325 break; 326 case Double: 327 size = QWORD; 328 imm = Double.doubleToRawLongBits(value.asDouble()); 329 break; 330 default: 331 throw JVMCIError.shouldNotReachHere("unexpected kind " + kind); 332 } 333 334 if (NumUtil.isInt(imm)) { 335 append(new AMD64BinaryConsumer.MemoryConstOp(op, size, address, (int) imm, state)); 336 } else { 337 emitStore(kind, address, asAllocatable(value), state); 338 } 339 } 340 } 341 342 protected void emitStore(Kind kind, AMD64AddressValue address, AllocatableValue value, LIRFrameState state) { 343 switch (kind) { 344 case Boolean: 345 case Byte: 346 append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOVB, BYTE, address, value, state)); 347 break; 348 case Char: 349 case Short: 350 append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOV, WORD, address, value, state)); 351 break; 352 case Int: 353 append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOV, DWORD, address, value, state)); 354 break; 355 case Long: 356 case Object: 357 append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOV, QWORD, address, value, state)); 358 break; 359 case Float: 360 append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOVSS, SS, address, value, state)); 361 break; 362 case Double: 363 append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOVSD, SD, address, value, state)); 364 break; 365 default: 366 throw JVMCIError.shouldNotReachHere(); 367 } 368 } 369 370 @Override 371 public void emitStore(LIRKind lirKind, Value address, Value input, LIRFrameState state) { 372 AMD64AddressValue storeAddress = asAddressValue(address); 373 Kind kind = (Kind) lirKind.getPlatformKind(); 374 if (isConstant(input)) { 375 emitStoreConst(kind, storeAddress, asConstant(input), state); 376 } else { 377 emitStore(kind, storeAddress, asAllocatable(input), state); 378 } 379 } 380 381 @Override 382 public Variable emitCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) { 383 LIRKind kind = newValue.getLIRKind(); 384 assert kind.equals(expectedValue.getLIRKind()); 385 Kind memKind = (Kind) kind.getPlatformKind(); 386 387 AMD64AddressValue addressValue = asAddressValue(address); 388 RegisterValue raxRes = AMD64.rax.asValue(kind); 389 emitMove(raxRes, expectedValue); 390 append(new CompareAndSwapOp(memKind, raxRes, addressValue, raxRes, asAllocatable(newValue))); 391 392 assert trueValue.getLIRKind().equals(falseValue.getLIRKind()); 393 Variable result = newVariable(trueValue.getLIRKind()); 394 append(new CondMoveOp(result, Condition.EQ, asAllocatable(trueValue), falseValue)); 395 return result; 396 } 397 398 @Override 399 public Value emitAtomicReadAndAdd(Value address, Value delta) { 400 LIRKind kind = delta.getLIRKind(); 401 Kind memKind = (Kind) kind.getPlatformKind(); 402 Variable result = newVariable(kind); 403 AMD64AddressValue addressValue = asAddressValue(address); 404 append(new AMD64Move.AtomicReadAndAddOp(memKind, result, addressValue, asAllocatable(delta))); 405 return result; 406 } 407 408 @Override 409 public Value emitAtomicReadAndWrite(Value address, Value newValue) { 410 LIRKind kind = newValue.getLIRKind(); 411 Kind memKind = (Kind) kind.getPlatformKind(); 412 Variable result = newVariable(kind); 413 AMD64AddressValue addressValue = asAddressValue(address); 414 append(new AMD64Move.AtomicReadAndWriteOp(memKind, result, addressValue, asAllocatable(newValue))); 415 return result; 416 } 417 418 @Override 419 public void emitNullCheck(Value address, LIRFrameState state) { 420 assert address.getKind() == Kind.Object || address.getKind() == Kind.Long : address + " - " + address.getKind() + " not a pointer!"; 421 append(new AMD64Move.NullCheckOp(asAddressValue(address), state)); 422 } 423 424 @Override 425 public void emitJump(LabelRef label) { 426 assert label != null; 427 append(new JumpOp(label)); 428 } 429 430 @Override 431 public void emitCompareBranch(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueLabel, LabelRef falseLabel, double trueLabelProbability) { 432 boolean mirrored = emitCompare(cmpKind, left, right); 433 Condition finalCondition = mirrored ? cond.mirror() : cond; 434 if (cmpKind == Kind.Float || cmpKind == Kind.Double) { 435 append(new FloatBranchOp(finalCondition, unorderedIsTrue, trueLabel, falseLabel, trueLabelProbability)); 436 } else { 437 append(new BranchOp(finalCondition, trueLabel, falseLabel, trueLabelProbability)); 438 } 439 } 440 441 public void emitCompareBranchMemory(Kind cmpKind, Value left, AMD64AddressValue right, LIRFrameState state, Condition cond, boolean unorderedIsTrue, LabelRef trueLabel, LabelRef falseLabel, 442 double trueLabelProbability) { 443 boolean mirrored = emitCompareMemory(cmpKind, left, right, state); 444 Condition finalCondition = mirrored ? cond.mirror() : cond; 445 if (cmpKind == Kind.Float || cmpKind == Kind.Double) { 446 append(new FloatBranchOp(finalCondition, unorderedIsTrue, trueLabel, falseLabel, trueLabelProbability)); 447 } else { 448 append(new BranchOp(finalCondition, trueLabel, falseLabel, trueLabelProbability)); 449 } 450 } 451 452 @Override 453 public void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, LIRKind cmpLIRKind, double overflowProbability) { 454 append(new BranchOp(ConditionFlag.Overflow, overflow, noOverflow, overflowProbability)); 455 } 456 457 @Override 458 public void emitIntegerTestBranch(Value left, Value right, LabelRef trueDestination, LabelRef falseDestination, double trueDestinationProbability) { 459 emitIntegerTest(left, right); 460 append(new BranchOp(Condition.EQ, trueDestination, falseDestination, trueDestinationProbability)); 461 } 462 463 @Override 464 public Variable emitConditionalMove(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue) { 465 boolean mirrored = emitCompare(cmpKind, left, right); 466 Condition finalCondition = mirrored ? cond.mirror() : cond; 467 468 Variable result = newVariable(trueValue.getLIRKind()); 469 if (cmpKind == Kind.Float || cmpKind == Kind.Double) { 470 append(new FloatCondMoveOp(result, finalCondition, unorderedIsTrue, load(trueValue), load(falseValue))); 471 } else { 472 append(new CondMoveOp(result, finalCondition, load(trueValue), loadNonConst(falseValue))); 473 } 474 return result; 475 } 476 477 @Override 478 public Variable emitIntegerTestMove(Value left, Value right, Value trueValue, Value falseValue) { 479 emitIntegerTest(left, right); 480 Variable result = newVariable(trueValue.getLIRKind()); 481 append(new CondMoveOp(result, Condition.EQ, load(trueValue), loadNonConst(falseValue))); 482 return result; 483 } 484 485 private void emitIntegerTest(Value a, Value b) { 486 assert a.getKind().isNumericInteger(); 487 OperandSize size = a.getKind() == Kind.Long ? QWORD : DWORD; 488 if (isConstant(b) && NumUtil.is32bit(asConstant(b).asLong())) { 489 append(new AMD64BinaryConsumer.ConstOp(AMD64MIOp.TEST, size, asAllocatable(a), (int) asConstant(b).asLong())); 490 } else if (isConstant(a) && NumUtil.is32bit(asConstant(a).asLong())) { 491 append(new AMD64BinaryConsumer.ConstOp(AMD64MIOp.TEST, size, asAllocatable(b), (int) asConstant(a).asLong())); 492 } else if (isAllocatableValue(b)) { 493 append(new AMD64BinaryConsumer.Op(AMD64RMOp.TEST, size, asAllocatable(b), asAllocatable(a))); 494 } else { 495 append(new AMD64BinaryConsumer.Op(AMD64RMOp.TEST, size, asAllocatable(a), asAllocatable(b))); 496 } 497 } 498 499 protected void emitCompareOp(PlatformKind cmpKind, Variable left, Value right) { 500 OperandSize size; 501 switch ((Kind) cmpKind) { 502 case Byte: 503 case Boolean: 504 size = BYTE; 505 break; 506 case Short: 507 case Char: 508 size = WORD; 509 break; 510 case Int: 511 size = DWORD; 512 break; 513 case Long: 514 case Object: 515 size = QWORD; 516 break; 517 case Float: 518 append(new AMD64BinaryConsumer.Op(SSEOp.UCOMIS, PS, left, asAllocatable(right))); 519 return; 520 case Double: 521 append(new AMD64BinaryConsumer.Op(SSEOp.UCOMIS, PD, left, asAllocatable(right))); 522 return; 523 default: 524 throw JVMCIError.shouldNotReachHere("unexpected kind: " + cmpKind); 525 } 526 527 if (isConstant(right)) { 528 JavaConstant c = asConstant(right); 529 if (c.isDefaultForKind()) { 530 AMD64RMOp op = size == BYTE ? TESTB : TEST; 531 append(new AMD64BinaryConsumer.Op(op, size, left, left)); 532 return; 533 } else if (NumUtil.is32bit(c.asLong())) { 534 append(new AMD64BinaryConsumer.ConstOp(CMP, size, left, (int) c.asLong())); 535 return; 536 } 537 } 538 539 AMD64RMOp op = CMP.getRMOpcode(size); 540 append(new AMD64BinaryConsumer.Op(op, size, left, asAllocatable(right))); 541 } 542 543 /** 544 * This method emits the compare against memory instruction, and may reorder the operands. It 545 * returns true if it did so. 546 * 547 * @param b the right operand of the comparison 548 * @return true if the left and right operands were switched, false otherwise 549 */ 550 private boolean emitCompareMemory(Kind cmpKind, Value a, AMD64AddressValue b, LIRFrameState state) { 551 OperandSize size; 552 switch (cmpKind) { 553 case Byte: 554 case Boolean: 555 size = BYTE; 556 break; 557 case Short: 558 case Char: 559 size = WORD; 560 break; 561 case Int: 562 size = DWORD; 563 break; 564 case Long: 565 case Object: 566 size = QWORD; 567 break; 568 case Float: 569 append(new AMD64BinaryConsumer.MemoryRMOp(SSEOp.UCOMIS, PS, asAllocatable(a), b, state)); 570 return false; 571 case Double: 572 append(new AMD64BinaryConsumer.MemoryRMOp(SSEOp.UCOMIS, PD, asAllocatable(a), b, state)); 573 return false; 574 default: 575 throw JVMCIError.shouldNotReachHere("unexpected kind: " + cmpKind); 576 } 577 578 if (isConstant(a)) { 579 return emitCompareMemoryConOp(size, asConstant(a), b, state); 580 } else { 581 return emitCompareRegMemoryOp(size, a, b, state); 582 } 583 } 584 585 protected boolean emitCompareMemoryConOp(OperandSize size, JavaConstant a, AMD64AddressValue b, LIRFrameState state) { 586 if (NumUtil.is32bit(a.asLong())) { 587 append(new AMD64BinaryConsumer.MemoryConstOp(CMP, size, b, (int) a.asLong(), state)); 588 return true; 589 } else { 590 return emitCompareRegMemoryOp(size, a, b, state); 591 } 592 } 593 594 private boolean emitCompareRegMemoryOp(OperandSize size, Value a, AMD64AddressValue b, LIRFrameState state) { 595 AMD64RMOp op = CMP.getRMOpcode(size); 596 append(new AMD64BinaryConsumer.MemoryRMOp(op, size, asAllocatable(a), b, state)); 597 return false; 598 } 599 600 /** 601 * This method emits the compare instruction, and may reorder the operands. It returns true if 602 * it did so. 603 * 604 * @param a the left operand of the comparison 605 * @param b the right operand of the comparison 606 * @return true if the left and right operands were switched, false otherwise 607 */ 608 private boolean emitCompare(PlatformKind cmpKind, Value a, Value b) { 609 Variable left; 610 Value right; 611 boolean mirrored; 612 if (LIRValueUtil.isVariable(b)) { 613 left = load(b); 614 right = loadNonConst(a); 615 mirrored = true; 616 } else { 617 left = load(a); 618 right = loadNonConst(b); 619 mirrored = false; 620 } 621 emitCompareOp(cmpKind, left, right); 622 return mirrored; 623 } 624 625 @Override 626 public Variable emitNegate(Value inputVal) { 627 AllocatableValue input = asAllocatable(inputVal); 628 Variable result = newVariable(LIRKind.combine(input)); 629 switch (input.getKind()) { 630 case Int: 631 append(new AMD64Unary.MOp(NEG, DWORD, result, input)); 632 break; 633 case Long: 634 append(new AMD64Unary.MOp(NEG, QWORD, result, input)); 635 break; 636 case Float: 637 append(new AMD64Binary.DataOp(SSEOp.XOR, PS, result, input, JavaConstant.forFloat(Float.intBitsToFloat(0x80000000)), 16)); 638 break; 639 case Double: 640 append(new AMD64Binary.DataOp(SSEOp.XOR, PD, result, input, JavaConstant.forDouble(Double.longBitsToDouble(0x8000000000000000L)), 16)); 641 break; 642 default: 643 throw JVMCIError.shouldNotReachHere(); 644 } 645 return result; 646 } 647 648 @Override 649 public Variable emitNot(Value inputVal) { 650 AllocatableValue input = asAllocatable(inputVal); 651 Variable result = newVariable(LIRKind.combine(input)); 652 switch (input.getKind()) { 653 case Int: 654 append(new AMD64Unary.MOp(NOT, DWORD, result, input)); 655 break; 656 case Long: 657 append(new AMD64Unary.MOp(NOT, QWORD, result, input)); 658 break; 659 default: 660 throw JVMCIError.shouldNotReachHere(); 661 } 662 return result; 663 } 664 665 private Variable emitBinary(LIRKind resultKind, AMD64BinaryArithmetic op, OperandSize size, boolean commutative, Value a, Value b, boolean setFlags) { 666 if (isConstant(b)) { 667 return emitBinaryConst(resultKind, op, size, commutative, asAllocatable(a), asConstant(b), setFlags); 668 } else if (commutative && isConstant(a)) { 669 return emitBinaryConst(resultKind, op, size, commutative, asAllocatable(b), asConstant(a), setFlags); 670 } else { 671 return emitBinaryVar(resultKind, op.getRMOpcode(size), size, commutative, asAllocatable(a), asAllocatable(b)); 672 } 673 } 674 675 private Variable emitBinary(LIRKind resultKind, AMD64RMOp op, OperandSize size, boolean commutative, Value a, Value b) { 676 if (isConstant(b)) { 677 return emitBinaryConst(resultKind, op, size, asAllocatable(a), asConstant(b)); 678 } else if (commutative && isConstant(a)) { 679 return emitBinaryConst(resultKind, op, size, asAllocatable(b), asConstant(a)); 680 } else { 681 return emitBinaryVar(resultKind, op, size, commutative, asAllocatable(a), asAllocatable(b)); 682 } 683 } 684 685 private Variable emitBinaryConst(LIRKind resultKind, AMD64BinaryArithmetic op, OperandSize size, boolean commutative, AllocatableValue a, JavaConstant b, boolean setFlags) { 686 if (NumUtil.isInt(b.asLong())) { 687 Variable result = newVariable(resultKind); 688 int constant = (int) b.asLong(); 689 690 if (!setFlags) { 691 AMD64MOp mop = getMOp(op, constant); 692 if (mop != null) { 693 append(new AMD64Unary.MOp(mop, size, result, a)); 694 return result; 695 } 696 } 697 698 append(new AMD64Binary.ConstOp(op, size, result, a, constant)); 699 return result; 700 } else { 701 return emitBinaryVar(resultKind, op.getRMOpcode(size), size, commutative, a, asAllocatable(b)); 702 } 703 } 704 705 private static AMD64MOp getMOp(AMD64BinaryArithmetic op, int constant) { 706 if (constant == 1) { 707 if (op.equals(AMD64BinaryArithmetic.ADD)) { 708 return AMD64MOp.INC; 709 } 710 if (op.equals(AMD64BinaryArithmetic.SUB)) { 711 return AMD64MOp.DEC; 712 } 713 } else if (constant == -1) { 714 if (op.equals(AMD64BinaryArithmetic.ADD)) { 715 return AMD64MOp.DEC; 716 } 717 if (op.equals(AMD64BinaryArithmetic.SUB)) { 718 return AMD64MOp.INC; 719 } 720 } 721 return null; 722 } 723 724 private Variable emitBinaryConst(LIRKind resultKind, AMD64RMOp op, OperandSize size, AllocatableValue a, JavaConstant b) { 725 Variable result = newVariable(resultKind); 726 append(new AMD64Binary.DataOp(op, size, result, a, b)); 727 return result; 728 } 729 730 private Variable emitBinaryVar(LIRKind resultKind, AMD64RMOp op, OperandSize size, boolean commutative, AllocatableValue a, AllocatableValue b) { 731 Variable result = newVariable(resultKind); 732 if (commutative) { 733 append(new AMD64Binary.CommutativeOp(op, size, result, a, b)); 734 } else { 735 append(new AMD64Binary.Op(op, size, result, a, b)); 736 } 737 return result; 738 } 739 740 @Override 741 public Variable emitAdd(LIRKind resultKind, Value a, Value b, boolean setFlags) { 742 switch (a.getKind().getStackKind()) { 743 case Int: 744 return emitBinary(resultKind, ADD, DWORD, true, a, b, setFlags); 745 case Long: 746 return emitBinary(resultKind, ADD, QWORD, true, a, b, setFlags); 747 case Float: 748 return emitBinary(resultKind, SSEOp.ADD, SS, true, a, b); 749 case Double: 750 return emitBinary(resultKind, SSEOp.ADD, SD, true, a, b); 751 default: 752 throw JVMCIError.shouldNotReachHere(); 753 } 754 } 755 756 @Override 757 public Variable emitSub(LIRKind resultKind, Value a, Value b, boolean setFlags) { 758 switch (a.getKind().getStackKind()) { 759 case Int: 760 return emitBinary(resultKind, SUB, DWORD, false, a, b, setFlags); 761 case Long: 762 return emitBinary(resultKind, SUB, QWORD, false, a, b, setFlags); 763 case Float: 764 return emitBinary(resultKind, SSEOp.SUB, SS, false, a, b); 765 case Double: 766 return emitBinary(resultKind, SSEOp.SUB, SD, false, a, b); 767 default: 768 throw JVMCIError.shouldNotReachHere(); 769 } 770 } 771 772 private Variable emitIMULConst(OperandSize size, AllocatableValue a, JavaConstant b) { 773 if (NumUtil.isInt(b.asLong())) { 774 int imm = (int) b.asLong(); 775 AMD64RMIOp op; 776 if (NumUtil.isByte(imm)) { 777 op = AMD64RMIOp.IMUL_SX; 778 } else { 779 op = AMD64RMIOp.IMUL; 780 } 781 782 Variable ret = newVariable(LIRKind.combine(a, b)); 783 append(new AMD64Binary.RMIOp(op, size, ret, a, imm)); 784 return ret; 785 } else { 786 return emitBinaryVar(LIRKind.combine(a, b), AMD64RMOp.IMUL, size, true, a, asAllocatable(b)); 787 } 788 } 789 790 private Variable emitIMUL(OperandSize size, Value a, Value b) { 791 if (isConstant(b)) { 792 return emitIMULConst(size, asAllocatable(a), asConstant(b)); 793 } else if (isConstant(a)) { 794 return emitIMULConst(size, asAllocatable(b), asConstant(a)); 795 } else { 796 return emitBinaryVar(LIRKind.combine(a, b), AMD64RMOp.IMUL, size, true, asAllocatable(a), asAllocatable(b)); 797 } 798 } 799 800 @Override 801 public Variable emitMul(Value a, Value b, boolean setFlags) { 802 switch (a.getKind().getStackKind()) { 803 case Int: 804 return emitIMUL(DWORD, a, b); 805 case Long: 806 return emitIMUL(QWORD, a, b); 807 case Float: 808 return emitBinary(LIRKind.combine(a, b), SSEOp.MUL, SS, true, a, b); 809 case Double: 810 return emitBinary(LIRKind.combine(a, b), SSEOp.MUL, SD, true, a, b); 811 default: 812 throw JVMCIError.shouldNotReachHere(); 813 } 814 } 815 816 private RegisterValue moveToReg(Register reg, Value v) { 817 RegisterValue ret = reg.asValue(v.getLIRKind()); 818 emitMove(ret, v); 819 return ret; 820 } 821 822 private Value emitMulHigh(AMD64MOp opcode, OperandSize size, Value a, Value b) { 823 AMD64MulDivOp mulHigh = append(new AMD64MulDivOp(opcode, size, LIRKind.combine(a, b), moveToReg(AMD64.rax, a), asAllocatable(b))); 824 return emitMove(mulHigh.getHighResult()); 825 } 826 827 @Override 828 public Value emitMulHigh(Value a, Value b) { 829 switch (a.getKind().getStackKind()) { 830 case Int: 831 return emitMulHigh(AMD64MOp.IMUL, DWORD, a, b); 832 case Long: 833 return emitMulHigh(AMD64MOp.IMUL, QWORD, a, b); 834 default: 835 throw JVMCIError.shouldNotReachHere(); 836 } 837 } 838 839 @Override 840 public Value emitUMulHigh(Value a, Value b) { 841 switch (a.getKind().getStackKind()) { 842 case Int: 843 return emitMulHigh(AMD64MOp.MUL, DWORD, a, b); 844 case Long: 845 return emitMulHigh(AMD64MOp.MUL, QWORD, a, b); 846 default: 847 throw JVMCIError.shouldNotReachHere(); 848 } 849 } 850 851 public Value emitBinaryMemory(AMD64RMOp op, OperandSize size, AllocatableValue a, AMD64AddressValue location, LIRFrameState state) { 852 Variable result = newVariable(LIRKind.combine(a)); 853 append(new AMD64Binary.MemoryOp(op, size, result, a, location, state)); 854 return result; 855 } 856 857 protected Value emitConvertMemoryOp(PlatformKind kind, AMD64RMOp op, OperandSize size, AMD64AddressValue address, LIRFrameState state) { 858 Variable result = newVariable(LIRKind.value(kind)); 859 append(new AMD64Unary.MemoryOp(op, size, result, address, state)); 860 return result; 861 } 862 863 protected Value emitZeroExtendMemory(Kind memoryKind, int resultBits, AMD64AddressValue address, LIRFrameState state) { 864 // Issue a zero extending load of the proper bit size and set the result to 865 // the proper kind. 866 Variable result = newVariable(LIRKind.value(resultBits == 32 ? Kind.Int : Kind.Long)); 867 switch (memoryKind) { 868 case Boolean: 869 case Byte: 870 append(new AMD64Unary.MemoryOp(MOVZXB, DWORD, result, address, state)); 871 break; 872 case Char: 873 case Short: 874 append(new AMD64Unary.MemoryOp(MOVZX, DWORD, result, address, state)); 875 break; 876 case Int: 877 append(new AMD64Unary.MemoryOp(MOV, DWORD, result, address, state)); 878 break; 879 case Long: 880 append(new AMD64Unary.MemoryOp(MOV, QWORD, result, address, state)); 881 break; 882 default: 883 throw JVMCIError.shouldNotReachHere(); 884 } 885 return result; 886 } 887 888 private AMD64MulDivOp emitIDIV(OperandSize size, Value a, Value b, LIRFrameState state) { 889 LIRKind kind = LIRKind.combine(a, b); 890 891 AMD64SignExtendOp sx = append(new AMD64SignExtendOp(size, kind, moveToReg(AMD64.rax, a))); 892 return append(new AMD64MulDivOp(AMD64MOp.IDIV, size, kind, sx.getHighResult(), sx.getLowResult(), asAllocatable(b), state)); 893 } 894 895 private AMD64MulDivOp emitDIV(OperandSize size, Value a, Value b, LIRFrameState state) { 896 LIRKind kind = LIRKind.combine(a, b); 897 898 RegisterValue rax = moveToReg(AMD64.rax, a); 899 RegisterValue rdx = AMD64.rdx.asValue(kind); 900 append(new AMD64ClearRegisterOp(size, rdx)); 901 return append(new AMD64MulDivOp(AMD64MOp.DIV, size, kind, rdx, rax, asAllocatable(b), state)); 902 } 903 904 public Value[] emitIntegerDivRem(Value a, Value b, LIRFrameState state) { 905 AMD64MulDivOp op; 906 switch (a.getKind().getStackKind()) { 907 case Int: 908 op = emitIDIV(DWORD, a, b, state); 909 break; 910 case Long: 911 op = emitIDIV(QWORD, a, b, state); 912 break; 913 default: 914 throw JVMCIError.shouldNotReachHere(); 915 } 916 return new Value[]{emitMove(op.getQuotient()), emitMove(op.getRemainder())}; 917 } 918 919 @Override 920 public Value emitDiv(Value a, Value b, LIRFrameState state) { 921 switch (a.getKind().getStackKind()) { 922 case Int: 923 AMD64MulDivOp op = emitIDIV(DWORD, a, b, state); 924 return emitMove(op.getQuotient()); 925 case Long: 926 AMD64MulDivOp lop = emitIDIV(QWORD, a, b, state); 927 return emitMove(lop.getQuotient()); 928 case Float: 929 return emitBinary(LIRKind.combine(a, b), SSEOp.DIV, SS, false, a, b); 930 case Double: 931 return emitBinary(LIRKind.combine(a, b), SSEOp.DIV, SD, false, a, b); 932 default: 933 throw JVMCIError.shouldNotReachHere(); 934 } 935 } 936 937 @Override 938 public Value emitRem(Value a, Value b, LIRFrameState state) { 939 switch (a.getKind().getStackKind()) { 940 case Int: 941 AMD64MulDivOp op = emitIDIV(DWORD, a, b, state); 942 return emitMove(op.getRemainder()); 943 case Long: 944 AMD64MulDivOp lop = emitIDIV(QWORD, a, b, state); 945 return emitMove(lop.getRemainder()); 946 case Float: { 947 Variable result = newVariable(LIRKind.combine(a, b)); 948 append(new FPDivRemOp(FREM, result, load(a), load(b))); 949 return result; 950 } 951 case Double: { 952 Variable result = newVariable(LIRKind.combine(a, b)); 953 append(new FPDivRemOp(DREM, result, load(a), load(b))); 954 return result; 955 } 956 default: 957 throw JVMCIError.shouldNotReachHere(); 958 } 959 } 960 961 @Override 962 public Variable emitUDiv(Value a, Value b, LIRFrameState state) { 963 AMD64MulDivOp op; 964 switch (a.getKind().getStackKind()) { 965 case Int: 966 op = emitDIV(DWORD, a, b, state); 967 break; 968 case Long: 969 op = emitDIV(QWORD, a, b, state); 970 break; 971 default: 972 throw JVMCIError.shouldNotReachHere(); 973 } 974 return emitMove(op.getQuotient()); 975 } 976 977 @Override 978 public Variable emitURem(Value a, Value b, LIRFrameState state) { 979 AMD64MulDivOp op; 980 switch (a.getKind().getStackKind()) { 981 case Int: 982 op = emitDIV(DWORD, a, b, state); 983 break; 984 case Long: 985 op = emitDIV(QWORD, a, b, state); 986 break; 987 default: 988 throw JVMCIError.shouldNotReachHere(); 989 } 990 return emitMove(op.getRemainder()); 991 } 992 993 @Override 994 public Variable emitAnd(Value a, Value b) { 995 LIRKind resultKind = LIRKind.combine(a, b); 996 switch (a.getKind().getStackKind()) { 997 case Int: 998 return emitBinary(resultKind, AND, DWORD, true, a, b, false); 999 case Long: 1000 return emitBinary(resultKind, AND, QWORD, true, a, b, false); 1001 case Float: 1002 return emitBinary(resultKind, SSEOp.AND, PS, true, a, b); 1003 case Double: 1004 return emitBinary(resultKind, SSEOp.AND, PD, true, a, b); 1005 default: 1006 throw JVMCIError.shouldNotReachHere(); 1007 } 1008 } 1009 1010 @Override 1011 public Variable emitOr(Value a, Value b) { 1012 LIRKind resultKind = LIRKind.combine(a, b); 1013 switch (a.getKind().getStackKind()) { 1014 case Int: 1015 return emitBinary(resultKind, OR, DWORD, true, a, b, false); 1016 case Long: 1017 return emitBinary(resultKind, OR, QWORD, true, a, b, false); 1018 case Float: 1019 return emitBinary(resultKind, SSEOp.OR, PS, true, a, b); 1020 case Double: 1021 return emitBinary(resultKind, SSEOp.OR, PD, true, a, b); 1022 default: 1023 throw JVMCIError.shouldNotReachHere(); 1024 } 1025 } 1026 1027 @Override 1028 public Variable emitXor(Value a, Value b) { 1029 LIRKind resultKind = LIRKind.combine(a, b); 1030 switch (a.getKind().getStackKind()) { 1031 case Int: 1032 return emitBinary(resultKind, XOR, DWORD, true, a, b, false); 1033 case Long: 1034 return emitBinary(resultKind, XOR, QWORD, true, a, b, false); 1035 case Float: 1036 return emitBinary(resultKind, SSEOp.XOR, PS, true, a, b); 1037 case Double: 1038 return emitBinary(resultKind, SSEOp.XOR, PD, true, a, b); 1039 default: 1040 throw JVMCIError.shouldNotReachHere(); 1041 } 1042 } 1043 1044 private Variable emitShift(AMD64Shift op, OperandSize size, Value a, Value b) { 1045 Variable result = newVariable(LIRKind.combine(a, b).changeType(a.getPlatformKind())); 1046 AllocatableValue input = asAllocatable(a); 1047 if (isConstant(b)) { 1048 JavaConstant c = asConstant(b); 1049 if (c.asLong() == 1) { 1050 append(new AMD64Unary.MOp(op.m1Op, size, result, input)); 1051 } else { 1052 /* 1053 * c is implicitly masked to 5 or 6 bits by the CPU, so casting it to (int) is 1054 * always correct, even without the NumUtil.is32bit() test. 1055 */ 1056 append(new AMD64Binary.ConstOp(op.miOp, size, result, input, (int) c.asLong())); 1057 } 1058 } else { 1059 emitMove(RCX_I, b); 1060 append(new AMD64ShiftOp(op.mcOp, size, result, input, RCX_I)); 1061 } 1062 return result; 1063 } 1064 1065 @Override 1066 public Variable emitShl(Value a, Value b) { 1067 switch (a.getKind().getStackKind()) { 1068 case Int: 1069 return emitShift(SHL, DWORD, a, b); 1070 case Long: 1071 return emitShift(SHL, QWORD, a, b); 1072 default: 1073 throw JVMCIError.shouldNotReachHere(); 1074 } 1075 } 1076 1077 @Override 1078 public Variable emitShr(Value a, Value b) { 1079 switch (a.getKind().getStackKind()) { 1080 case Int: 1081 return emitShift(SAR, DWORD, a, b); 1082 case Long: 1083 return emitShift(SAR, QWORD, a, b); 1084 default: 1085 throw JVMCIError.shouldNotReachHere(); 1086 } 1087 } 1088 1089 @Override 1090 public Variable emitUShr(Value a, Value b) { 1091 switch (a.getKind().getStackKind()) { 1092 case Int: 1093 return emitShift(SHR, DWORD, a, b); 1094 case Long: 1095 return emitShift(SHR, QWORD, a, b); 1096 default: 1097 throw JVMCIError.shouldNotReachHere(); 1098 } 1099 } 1100 1101 public Variable emitRol(Value a, Value b) { 1102 switch (a.getKind().getStackKind()) { 1103 case Int: 1104 return emitShift(ROL, DWORD, a, b); 1105 case Long: 1106 return emitShift(ROL, QWORD, a, b); 1107 default: 1108 throw JVMCIError.shouldNotReachHere(); 1109 } 1110 } 1111 1112 public Variable emitRor(Value a, Value b) { 1113 switch (a.getKind().getStackKind()) { 1114 case Int: 1115 return emitShift(ROR, DWORD, a, b); 1116 case Long: 1117 return emitShift(ROR, QWORD, a, b); 1118 default: 1119 throw JVMCIError.shouldNotReachHere(); 1120 } 1121 } 1122 1123 private AllocatableValue emitConvertOp(LIRKind kind, AMD64RMOp op, OperandSize size, Value input) { 1124 Variable result = newVariable(kind); 1125 append(new AMD64Unary.RMOp(op, size, result, asAllocatable(input))); 1126 return result; 1127 } 1128 1129 private AllocatableValue emitConvertOp(LIRKind kind, AMD64MROp op, OperandSize size, Value input) { 1130 Variable result = newVariable(kind); 1131 append(new AMD64Unary.MROp(op, size, result, asAllocatable(input))); 1132 return result; 1133 } 1134 1135 @Override 1136 public Value emitReinterpret(LIRKind to, Value inputVal) { 1137 LIRKind from = inputVal.getLIRKind(); 1138 if (to.equals(from)) { 1139 return inputVal; 1140 } 1141 1142 AllocatableValue input = asAllocatable(inputVal); 1143 /* 1144 * Conversions between integer to floating point types require moves between CPU and FPU 1145 * registers. 1146 */ 1147 Kind fromKind = (Kind) from.getPlatformKind(); 1148 switch ((Kind) to.getPlatformKind()) { 1149 case Int: 1150 switch (fromKind) { 1151 case Float: 1152 return emitConvertOp(to, AMD64MROp.MOVD, DWORD, input); 1153 } 1154 break; 1155 case Long: 1156 switch (fromKind) { 1157 case Double: 1158 return emitConvertOp(to, AMD64MROp.MOVQ, QWORD, input); 1159 } 1160 break; 1161 case Float: 1162 switch (fromKind) { 1163 case Int: 1164 return emitConvertOp(to, AMD64RMOp.MOVD, DWORD, input); 1165 } 1166 break; 1167 case Double: 1168 switch (fromKind) { 1169 case Long: 1170 return emitConvertOp(to, AMD64RMOp.MOVQ, QWORD, input); 1171 } 1172 break; 1173 } 1174 throw JVMCIError.shouldNotReachHere(); 1175 } 1176 1177 public Value emitFloatConvert(FloatConvert op, Value input) { 1178 switch (op) { 1179 case D2F: 1180 return emitConvertOp(LIRKind.combine(input).changeType(Kind.Float), SSEOp.CVTSD2SS, SD, input); 1181 case D2I: 1182 return emitConvertOp(LIRKind.combine(input).changeType(Kind.Int), SSEOp.CVTTSD2SI, DWORD, input); 1183 case D2L: 1184 return emitConvertOp(LIRKind.combine(input).changeType(Kind.Long), SSEOp.CVTTSD2SI, QWORD, input); 1185 case F2D: 1186 return emitConvertOp(LIRKind.combine(input).changeType(Kind.Double), SSEOp.CVTSS2SD, SS, input); 1187 case F2I: 1188 return emitConvertOp(LIRKind.combine(input).changeType(Kind.Int), SSEOp.CVTTSS2SI, DWORD, input); 1189 case F2L: 1190 return emitConvertOp(LIRKind.combine(input).changeType(Kind.Long), SSEOp.CVTTSS2SI, QWORD, input); 1191 case I2D: 1192 return emitConvertOp(LIRKind.combine(input).changeType(Kind.Double), SSEOp.CVTSI2SD, DWORD, input); 1193 case I2F: 1194 return emitConvertOp(LIRKind.combine(input).changeType(Kind.Float), SSEOp.CVTSI2SS, DWORD, input); 1195 case L2D: 1196 return emitConvertOp(LIRKind.combine(input).changeType(Kind.Double), SSEOp.CVTSI2SD, QWORD, input); 1197 case L2F: 1198 return emitConvertOp(LIRKind.combine(input).changeType(Kind.Float), SSEOp.CVTSI2SS, QWORD, input); 1199 default: 1200 throw JVMCIError.shouldNotReachHere(); 1201 } 1202 } 1203 1204 @Override 1205 public Value emitNarrow(Value inputVal, int bits) { 1206 if (inputVal.getKind() == Kind.Long && bits <= 32) { 1207 // TODO make it possible to reinterpret Long as Int in LIR without move 1208 return emitConvertOp(LIRKind.combine(inputVal).changeType(Kind.Int), AMD64RMOp.MOV, DWORD, inputVal); 1209 } else { 1210 return inputVal; 1211 } 1212 } 1213 1214 @Override 1215 public Value emitSignExtend(Value inputVal, int fromBits, int toBits) { 1216 assert fromBits <= toBits && toBits <= 64; 1217 if (fromBits == toBits) { 1218 return inputVal; 1219 } else if (toBits > 32) { 1220 // sign extend to 64 bits 1221 switch (fromBits) { 1222 case 8: 1223 return emitConvertOp(LIRKind.combine(inputVal).changeType(Kind.Long), MOVSXB, QWORD, inputVal); 1224 case 16: 1225 return emitConvertOp(LIRKind.combine(inputVal).changeType(Kind.Long), MOVSX, QWORD, inputVal); 1226 case 32: 1227 return emitConvertOp(LIRKind.combine(inputVal).changeType(Kind.Long), MOVSXD, QWORD, inputVal); 1228 default: 1229 throw JVMCIError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)"); 1230 } 1231 } else { 1232 // sign extend to 32 bits (smaller values are internally represented as 32 bit values) 1233 switch (fromBits) { 1234 case 8: 1235 return emitConvertOp(LIRKind.combine(inputVal).changeType(Kind.Int), MOVSXB, DWORD, inputVal); 1236 case 16: 1237 return emitConvertOp(LIRKind.combine(inputVal).changeType(Kind.Int), MOVSX, DWORD, inputVal); 1238 case 32: 1239 return inputVal; 1240 default: 1241 throw JVMCIError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)"); 1242 } 1243 } 1244 } 1245 1246 @Override 1247 public Value emitZeroExtend(Value inputVal, int fromBits, int toBits) { 1248 assert fromBits <= toBits && toBits <= 64; 1249 if (fromBits == toBits) { 1250 return inputVal; 1251 } else if (fromBits > 32) { 1252 assert inputVal.getKind() == Kind.Long; 1253 Variable result = newVariable(LIRKind.combine(inputVal).changeType(Kind.Long)); 1254 long mask = CodeUtil.mask(fromBits); 1255 append(new AMD64Binary.DataOp(AND.getRMOpcode(QWORD), QWORD, result, asAllocatable(inputVal), JavaConstant.forLong(mask))); 1256 return result; 1257 } else { 1258 assert inputVal.getKind().getStackKind() == Kind.Int; 1259 1260 LIRKind resultKind = LIRKind.combine(inputVal); 1261 if (toBits > 32) { 1262 resultKind = resultKind.changeType(Kind.Long); 1263 } else { 1264 resultKind = resultKind.changeType(Kind.Int); 1265 } 1266 1267 /* 1268 * Always emit DWORD operations, even if the resultKind is Long. On AMD64, all DWORD 1269 * operations implicitly set the upper half of the register to 0, which is what we want 1270 * anyway. Compared to the QWORD oparations, the encoding of the DWORD operations is 1271 * sometimes one byte shorter. 1272 */ 1273 switch (fromBits) { 1274 case 8: 1275 return emitConvertOp(resultKind, MOVZXB, DWORD, inputVal); 1276 case 16: 1277 return emitConvertOp(resultKind, MOVZX, DWORD, inputVal); 1278 case 32: 1279 return emitConvertOp(resultKind, MOV, DWORD, inputVal); 1280 } 1281 1282 // odd bit count, fall back on manual masking 1283 Variable result = newVariable(resultKind); 1284 JavaConstant mask; 1285 if (toBits > 32) { 1286 mask = JavaConstant.forLong(CodeUtil.mask(fromBits)); 1287 } else { 1288 mask = JavaConstant.forInt((int) CodeUtil.mask(fromBits)); 1289 } 1290 append(new AMD64Binary.DataOp(AND.getRMOpcode(DWORD), DWORD, result, asAllocatable(inputVal), mask)); 1291 return result; 1292 } 1293 } 1294 1295 @Override 1296 public void emitMembar(int barriers) { 1297 int necessaryBarriers = target().arch.requiredBarriers(barriers); 1298 if (target().isMP && necessaryBarriers != 0) { 1299 append(new MembarOp(necessaryBarriers)); 1300 } 1301 } 1302 1303 public abstract void emitCCall(long address, CallingConvention nativeCallingConvention, Value[] args, int numberOfFloatingPointArguments); 1304 1305 @Override 1306 protected void emitForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info) { 1307 long maxOffset = linkage.getMaxCallTargetOffset(); 1308 if (maxOffset != (int) maxOffset) { 1309 append(new AMD64Call.DirectFarForeignCallOp(linkage, result, arguments, temps, info)); 1310 } else { 1311 append(new AMD64Call.DirectNearForeignCallOp(linkage, result, arguments, temps, info)); 1312 } 1313 } 1314 1315 @Override 1316 public Variable emitBitCount(Value value) { 1317 Variable result = newVariable(LIRKind.combine(value).changeType(Kind.Int)); 1318 if (value.getKind().getStackKind() == Kind.Int) { 1319 append(new AMD64Unary.RMOp(POPCNT, DWORD, result, asAllocatable(value))); 1320 } else { 1321 append(new AMD64Unary.RMOp(POPCNT, QWORD, result, asAllocatable(value))); 1322 } 1323 return result; 1324 } 1325 1326 @Override 1327 public Variable emitBitScanForward(Value value) { 1328 Variable result = newVariable(LIRKind.combine(value).changeType(Kind.Int)); 1329 append(new AMD64Unary.RMOp(BSF, QWORD, result, asAllocatable(value))); 1330 return result; 1331 } 1332 1333 @Override 1334 public Variable emitBitScanReverse(Value value) { 1335 Variable result = newVariable(LIRKind.combine(value).changeType(Kind.Int)); 1336 if (value.getKind().getStackKind() == Kind.Int) { 1337 append(new AMD64Unary.RMOp(BSR, DWORD, result, asAllocatable(value))); 1338 } else { 1339 append(new AMD64Unary.RMOp(BSR, QWORD, result, asAllocatable(value))); 1340 } 1341 return result; 1342 } 1343 1344 public Value emitCountLeadingZeros(Value value) { 1345 Variable result = newVariable(LIRKind.combine(value).changeType(Kind.Int)); 1346 if (value.getKind().getStackKind() == Kind.Int) { 1347 append(new AMD64Unary.RMOp(LZCNT, DWORD, result, asAllocatable(value))); 1348 } else { 1349 append(new AMD64Unary.RMOp(LZCNT, QWORD, result, asAllocatable(value))); 1350 } 1351 return result; 1352 } 1353 1354 public Value emitCountTrailingZeros(Value value) { 1355 Variable result = newVariable(LIRKind.combine(value).changeType(Kind.Int)); 1356 if (value.getKind().getStackKind() == Kind.Int) { 1357 append(new AMD64Unary.RMOp(TZCNT, DWORD, result, asAllocatable(value))); 1358 } else { 1359 append(new AMD64Unary.RMOp(TZCNT, QWORD, result, asAllocatable(value))); 1360 } 1361 return result; 1362 } 1363 1364 @Override 1365 public Value emitMathAbs(Value input) { 1366 Variable result = newVariable(LIRKind.combine(input)); 1367 switch (input.getKind()) { 1368 case Float: 1369 append(new AMD64Binary.DataOp(SSEOp.AND, PS, result, asAllocatable(input), JavaConstant.forFloat(Float.intBitsToFloat(0x7FFFFFFF)), 16)); 1370 break; 1371 case Double: 1372 append(new AMD64Binary.DataOp(SSEOp.AND, PD, result, asAllocatable(input), JavaConstant.forDouble(Double.longBitsToDouble(0x7FFFFFFFFFFFFFFFL)), 16)); 1373 break; 1374 default: 1375 throw JVMCIError.shouldNotReachHere(); 1376 } 1377 return result; 1378 } 1379 1380 @Override 1381 public Value emitMathSqrt(Value input) { 1382 Variable result = newVariable(LIRKind.combine(input)); 1383 switch (input.getKind()) { 1384 case Float: 1385 append(new AMD64Unary.RMOp(SSEOp.SQRT, SS, result, asAllocatable(input))); 1386 break; 1387 case Double: 1388 append(new AMD64Unary.RMOp(SSEOp.SQRT, SD, result, asAllocatable(input))); 1389 break; 1390 default: 1391 throw JVMCIError.shouldNotReachHere(); 1392 } 1393 return result; 1394 } 1395 1396 @Override 1397 public Value emitMathLog(Value input, boolean base10) { 1398 Variable result = newVariable(LIRKind.combine(input)); 1399 append(new AMD64MathIntrinsicOp(base10 ? LOG10 : LOG, result, asAllocatable(input))); 1400 return result; 1401 } 1402 1403 @Override 1404 public Value emitMathCos(Value input) { 1405 Variable result = newVariable(LIRKind.combine(input)); 1406 append(new AMD64MathIntrinsicOp(COS, result, asAllocatable(input))); 1407 return result; 1408 } 1409 1410 @Override 1411 public Value emitMathSin(Value input) { 1412 Variable result = newVariable(LIRKind.combine(input)); 1413 append(new AMD64MathIntrinsicOp(SIN, result, asAllocatable(input))); 1414 return result; 1415 } 1416 1417 @Override 1418 public Value emitMathTan(Value input) { 1419 Variable result = newVariable(LIRKind.combine(input)); 1420 append(new AMD64MathIntrinsicOp(TAN, result, asAllocatable(input))); 1421 return result; 1422 } 1423 1424 @Override 1425 public Variable emitByteSwap(Value input) { 1426 Variable result = newVariable(LIRKind.combine(input)); 1427 append(new AMD64ByteSwapOp(result, input)); 1428 return result; 1429 } 1430 1431 @Override 1432 public Variable emitArrayEquals(Kind kind, Value array1, Value array2, Value length) { 1433 Variable result = newVariable(LIRKind.value(Kind.Int)); 1434 append(new AMD64ArrayEqualsOp(this, kind, result, array1, array2, asAllocatable(length))); 1435 return result; 1436 } 1437 1438 @Override 1439 public void emitReturn(Value input) { 1440 AllocatableValue operand = Value.ILLEGAL; 1441 if (input != null) { 1442 operand = resultOperandFor(input.getLIRKind()); 1443 emitMove(operand, input); 1444 } 1445 append(new ReturnOp(operand)); 1446 } 1447 1448 @Override 1449 public void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) { 1450 // a temp is needed for loading object constants 1451 boolean needsTemp = key.getKind() == Kind.Object; 1452 append(new StrategySwitchOp(strategy, keyTargets, defaultTarget, key, needsTemp ? newVariable(key.getLIRKind()) : Value.ILLEGAL)); 1453 } 1454 1455 @Override 1456 protected void emitTableSwitch(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value key) { 1457 append(new TableSwitchOp(lowKey, defaultTarget, targets, key, newVariable(LIRKind.value(target().wordKind)), newVariable(key.getLIRKind()))); 1458 } 1459 1460}