1 /*
   2  * Copyright (c) 2009, 2016, 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 
  25 
  26 package org.graalvm.compiler.core.amd64;
  27 
  28 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.ADD;
  29 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.AND;
  30 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.CMP;
  31 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.OR;
  32 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.SUB;
  33 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.XOR;
  34 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MOp.NEG;
  35 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MOp.NOT;
  36 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.BSF;
  37 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.BSR;
  38 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.LZCNT;
  39 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.MOV;
  40 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.MOVSD;
  41 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.MOVSS;
  42 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.MOVSX;
  43 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.MOVSXB;
  44 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.MOVSXD;
  45 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.MOVZX;
  46 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.MOVZXB;
  47 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.POPCNT;
  48 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.TEST;
  49 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.TESTB;
  50 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.TZCNT;
  51 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64Shift.ROL;
  52 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64Shift.ROR;
  53 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64Shift.SAR;
  54 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64Shift.SHL;
  55 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64Shift.SHR;
  56 import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize.BYTE;
  57 import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize.DWORD;
  58 import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize.PD;
  59 import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize.PS;
  60 import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize.QWORD;
  61 import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize.SD;
  62 import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize.SS;
  63 import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize.WORD;
  64 import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
  65 import static org.graalvm.compiler.lir.LIRValueUtil.asConstantValue;
  66 import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant;
  67 import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue;
  68 import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
  69 import static org.graalvm.compiler.lir.amd64.AMD64Arithmetic.DREM;
  70 import static org.graalvm.compiler.lir.amd64.AMD64Arithmetic.FREM;
  71 import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicBinaryOp.BinaryIntrinsicOpcode.POW;
  72 import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp.UnaryIntrinsicOpcode.COS;
  73 import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp.UnaryIntrinsicOpcode.EXP;
  74 import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp.UnaryIntrinsicOpcode.LOG;
  75 import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp.UnaryIntrinsicOpcode.LOG10;
  76 import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp.UnaryIntrinsicOpcode.SIN;
  77 import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp.UnaryIntrinsicOpcode.TAN;
  78 
  79 import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic;
  80 import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MIOp;
  81 import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MOp;
  82 import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MROp;
  83 import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMIOp;
  84 import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp;
  85 import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64Shift;
  86 import org.graalvm.compiler.asm.amd64.AMD64Assembler.SSEOp;
  87 import org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize;
  88 import org.graalvm.compiler.core.common.LIRKind;
  89 import org.graalvm.compiler.core.common.NumUtil;
  90 import org.graalvm.compiler.core.common.calc.FloatConvert;
  91 import org.graalvm.compiler.debug.GraalError;
  92 import org.graalvm.compiler.lir.ConstantValue;
  93 import org.graalvm.compiler.lir.LIRFrameState;
  94 import org.graalvm.compiler.lir.LIRValueUtil;
  95 import org.graalvm.compiler.lir.Variable;
  96 import org.graalvm.compiler.lir.amd64.AMD64AddressValue;
  97 import org.graalvm.compiler.lir.amd64.AMD64Arithmetic.FPDivRemOp;
  98 import org.graalvm.compiler.lir.amd64.AMD64ArithmeticLIRGeneratorTool;
  99 import org.graalvm.compiler.lir.amd64.AMD64Binary;
 100 import org.graalvm.compiler.lir.amd64.AMD64BinaryConsumer;
 101 import org.graalvm.compiler.lir.amd64.AMD64ClearRegisterOp;
 102 import org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicBinaryOp;
 103 import org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp;
 104 import org.graalvm.compiler.lir.amd64.AMD64Move;
 105 import org.graalvm.compiler.lir.amd64.AMD64MulDivOp;
 106 import org.graalvm.compiler.lir.amd64.AMD64ShiftOp;
 107 import org.graalvm.compiler.lir.amd64.AMD64SignExtendOp;
 108 import org.graalvm.compiler.lir.amd64.AMD64Unary;
 109 import org.graalvm.compiler.lir.gen.ArithmeticLIRGenerator;
 110 import org.graalvm.compiler.lir.gen.LIRGenerator;
 111 
 112 import jdk.vm.ci.amd64.AMD64;
 113 import jdk.vm.ci.amd64.AMD64Kind;
 114 import jdk.vm.ci.code.CodeUtil;
 115 import jdk.vm.ci.code.Register;
 116 import jdk.vm.ci.code.RegisterValue;
 117 import jdk.vm.ci.meta.AllocatableValue;
 118 import jdk.vm.ci.meta.Constant;
 119 import jdk.vm.ci.meta.JavaConstant;
 120 import jdk.vm.ci.meta.JavaKind;
 121 import jdk.vm.ci.meta.PlatformKind;
 122 import jdk.vm.ci.meta.VMConstant;
 123 import jdk.vm.ci.meta.Value;
 124 import jdk.vm.ci.meta.ValueKind;
 125 
 126 /**
 127  * This class implements the AMD64 specific portion of the LIR generator.
 128  */
 129 public class AMD64ArithmeticLIRGenerator extends ArithmeticLIRGenerator implements AMD64ArithmeticLIRGeneratorTool {
 130 
 131     private static final RegisterValue RCX_I = AMD64.rcx.asValue(LIRKind.value(AMD64Kind.DWORD));
 132 
 133     public AMD64ArithmeticLIRGenerator(AllocatableValue nullRegisterValue, Maths maths) {
 134         this.nullRegisterValue = nullRegisterValue;
 135         this.maths = maths == null ? new Maths() {
 136         } : maths;
 137     }
 138 
 139     private final AllocatableValue nullRegisterValue;
 140     private final Maths maths;
 141 
 142     /**
 143      * Interface for emitting LIR for selected {@link Math} routines. A {@code null} return value
 144      * for any method in this interface means the caller must emit the LIR itself.
 145      */
 146     public interface Maths {
 147 
 148         @SuppressWarnings("unused")
 149         default Variable emitLog(LIRGenerator gen, Value input, boolean base10) {
 150             return null;
 151         }
 152 
 153         @SuppressWarnings("unused")
 154         default Variable emitCos(LIRGenerator gen, Value input) {
 155             return null;
 156         }
 157 
 158         @SuppressWarnings("unused")
 159         default Variable emitSin(LIRGenerator gen, Value input) {
 160             return null;
 161         }
 162 
 163         @SuppressWarnings("unused")
 164         default Variable emitTan(LIRGenerator gen, Value input) {
 165             return null;
 166         }
 167     }
 168 
 169     @Override
 170     public Variable emitNegate(Value inputVal) {
 171         AllocatableValue input = asAllocatable(inputVal);
 172         Variable result = getLIRGen().newVariable(LIRKind.combine(input));
 173         switch ((AMD64Kind) input.getPlatformKind()) {
 174             case DWORD:
 175                 getLIRGen().append(new AMD64Unary.MOp(NEG, DWORD, result, input));
 176                 break;
 177             case QWORD:
 178                 getLIRGen().append(new AMD64Unary.MOp(NEG, QWORD, result, input));
 179                 break;
 180             case SINGLE:
 181                 getLIRGen().append(new AMD64Binary.DataTwoOp(SSEOp.XOR, PS, result, input, JavaConstant.forFloat(Float.intBitsToFloat(0x80000000)), 16));
 182                 break;
 183             case DOUBLE:
 184                 getLIRGen().append(new AMD64Binary.DataTwoOp(SSEOp.XOR, PD, result, input, JavaConstant.forDouble(Double.longBitsToDouble(0x8000000000000000L)), 16));
 185                 break;
 186             default:
 187                 throw GraalError.shouldNotReachHere(input.getPlatformKind().toString());
 188         }
 189         return result;
 190     }
 191 
 192     @Override
 193     public Variable emitNot(Value inputVal) {
 194         AllocatableValue input = asAllocatable(inputVal);
 195         Variable result = getLIRGen().newVariable(LIRKind.combine(input));
 196         switch ((AMD64Kind) input.getPlatformKind()) {
 197             case DWORD:
 198                 getLIRGen().append(new AMD64Unary.MOp(NOT, DWORD, result, input));
 199                 break;
 200             case QWORD:
 201                 getLIRGen().append(new AMD64Unary.MOp(NOT, QWORD, result, input));
 202                 break;
 203             default:
 204                 throw GraalError.shouldNotReachHere();
 205         }
 206         return result;
 207     }
 208 
 209     private Variable emitBinary(LIRKind resultKind, AMD64BinaryArithmetic op, OperandSize size, boolean commutative, Value a, Value b, boolean setFlags) {
 210         if (isJavaConstant(b)) {
 211             return emitBinaryConst(resultKind, op, size, commutative, asAllocatable(a), asConstantValue(b), setFlags);
 212         } else if (commutative && isJavaConstant(a)) {
 213             return emitBinaryConst(resultKind, op, size, commutative, asAllocatable(b), asConstantValue(a), setFlags);
 214         } else {
 215             return emitBinaryVar(resultKind, op.getRMOpcode(size), size, commutative, asAllocatable(a), asAllocatable(b));
 216         }
 217     }
 218 
 219     private Variable emitBinary(LIRKind resultKind, AMD64RMOp op, OperandSize size, boolean commutative, Value a, Value b) {
 220         if (isJavaConstant(b)) {
 221             return emitBinaryConst(resultKind, op, size, asAllocatable(a), asJavaConstant(b));
 222         } else if (commutative && isJavaConstant(a)) {
 223             return emitBinaryConst(resultKind, op, size, asAllocatable(b), asJavaConstant(a));
 224         } else {
 225             return emitBinaryVar(resultKind, op, size, commutative, asAllocatable(a), asAllocatable(b));
 226         }
 227     }
 228 
 229     private Variable emitBinaryConst(LIRKind resultKind, AMD64BinaryArithmetic op, OperandSize size, boolean commutative, AllocatableValue a, ConstantValue b, boolean setFlags) {
 230         long value = b.getJavaConstant().asLong();
 231         if (NumUtil.isInt(value)) {
 232             Variable result = getLIRGen().newVariable(resultKind);
 233             int constant = (int) value;
 234 
 235             if (!setFlags) {
 236                 AMD64MOp mop = getMOp(op, constant);
 237                 if (mop != null) {
 238                     getLIRGen().append(new AMD64Unary.MOp(mop, size, result, a));
 239                     return result;
 240                 }
 241             }
 242 
 243             getLIRGen().append(new AMD64Binary.ConstOp(op, size, result, a, constant));
 244             return result;
 245         } else {
 246             return emitBinaryVar(resultKind, op.getRMOpcode(size), size, commutative, a, asAllocatable(b));
 247         }
 248     }
 249 
 250     private static AMD64MOp getMOp(AMD64BinaryArithmetic op, int constant) {
 251         if (constant == 1) {
 252             if (op.equals(AMD64BinaryArithmetic.ADD)) {
 253                 return AMD64MOp.INC;
 254             }
 255             if (op.equals(AMD64BinaryArithmetic.SUB)) {
 256                 return AMD64MOp.DEC;
 257             }
 258         } else if (constant == -1) {
 259             if (op.equals(AMD64BinaryArithmetic.ADD)) {
 260                 return AMD64MOp.DEC;
 261             }
 262             if (op.equals(AMD64BinaryArithmetic.SUB)) {
 263                 return AMD64MOp.INC;
 264             }
 265         }
 266         return null;
 267     }
 268 
 269     private Variable emitBinaryConst(LIRKind resultKind, AMD64RMOp op, OperandSize size, AllocatableValue a, JavaConstant b) {
 270         Variable result = getLIRGen().newVariable(resultKind);
 271         getLIRGen().append(new AMD64Binary.DataTwoOp(op, size, result, a, b));
 272         return result;
 273     }
 274 
 275     private Variable emitBinaryVar(LIRKind resultKind, AMD64RMOp op, OperandSize size, boolean commutative, AllocatableValue a, AllocatableValue b) {
 276         Variable result = getLIRGen().newVariable(resultKind);
 277         if (commutative) {
 278             getLIRGen().append(new AMD64Binary.CommutativeTwoOp(op, size, result, a, b));
 279         } else {
 280             getLIRGen().append(new AMD64Binary.TwoOp(op, size, result, a, b));
 281         }
 282         return result;
 283     }
 284 
 285     @Override
 286     protected boolean isNumericInteger(PlatformKind kind) {
 287         return ((AMD64Kind) kind).isInteger();
 288     }
 289 
 290     private Variable emitBaseOffsetLea(LIRKind resultKind, Value base, int offset, OperandSize size) {
 291         Variable result = getLIRGen().newVariable(resultKind);
 292         AMD64AddressValue address = new AMD64AddressValue(resultKind, asAllocatable(base), offset);
 293         getLIRGen().append(new AMD64Move.LeaOp(result, address, size));
 294         return result;
 295     }
 296 
 297     @Override
 298     public Variable emitAdd(LIRKind resultKind, Value a, Value b, boolean setFlags) {
 299         switch ((AMD64Kind) a.getPlatformKind()) {
 300             case DWORD:
 301                 if (isJavaConstant(b) && !setFlags) {
 302                     long displacement = asJavaConstant(b).asLong();
 303                     if (NumUtil.isInt(displacement) && displacement != 1 && displacement != -1) {
 304                         return emitBaseOffsetLea(resultKind, a, (int) displacement, OperandSize.DWORD);
 305                     }
 306                 }
 307                 return emitBinary(resultKind, ADD, DWORD, true, a, b, setFlags);
 308             case QWORD:
 309                 if (isJavaConstant(b) && !setFlags) {
 310                     long displacement = asJavaConstant(b).asLong();
 311                     if (NumUtil.isInt(displacement) && displacement != 1 && displacement != -1) {
 312                         return emitBaseOffsetLea(resultKind, a, (int) displacement, OperandSize.QWORD);
 313                     }
 314                 }
 315                 return emitBinary(resultKind, ADD, QWORD, true, a, b, setFlags);
 316             case SINGLE:
 317                 return emitBinary(resultKind, SSEOp.ADD, SS, true, a, b);
 318             case DOUBLE:
 319                 return emitBinary(resultKind, SSEOp.ADD, SD, true, a, b);
 320             default:
 321                 throw GraalError.shouldNotReachHere();
 322         }
 323     }
 324 
 325     @Override
 326     public Variable emitSub(LIRKind resultKind, Value a, Value b, boolean setFlags) {
 327         switch ((AMD64Kind) a.getPlatformKind()) {
 328             case DWORD:
 329                 return emitBinary(resultKind, SUB, DWORD, false, a, b, setFlags);
 330             case QWORD:
 331                 return emitBinary(resultKind, SUB, QWORD, false, a, b, setFlags);
 332             case SINGLE:
 333                 return emitBinary(resultKind, SSEOp.SUB, SS, false, a, b);
 334             case DOUBLE:
 335                 return emitBinary(resultKind, SSEOp.SUB, SD, false, a, b);
 336             default:
 337                 throw GraalError.shouldNotReachHere();
 338         }
 339     }
 340 
 341     private Variable emitIMULConst(OperandSize size, AllocatableValue a, ConstantValue b) {
 342         long value = b.getJavaConstant().asLong();
 343         if (NumUtil.isInt(value)) {
 344             int imm = (int) value;
 345             AMD64RMIOp op;
 346             if (NumUtil.isByte(imm)) {
 347                 op = AMD64RMIOp.IMUL_SX;
 348             } else {
 349                 op = AMD64RMIOp.IMUL;
 350             }
 351 
 352             Variable ret = getLIRGen().newVariable(LIRKind.combine(a, b));
 353             getLIRGen().append(new AMD64Binary.RMIOp(op, size, ret, a, imm));
 354             return ret;
 355         } else {
 356             return emitBinaryVar(LIRKind.combine(a, b), AMD64RMOp.IMUL, size, true, a, asAllocatable(b));
 357         }
 358     }
 359 
 360     private Variable emitIMUL(OperandSize size, Value a, Value b) {
 361         if (isJavaConstant(b)) {
 362             return emitIMULConst(size, asAllocatable(a), asConstantValue(b));
 363         } else if (isJavaConstant(a)) {
 364             return emitIMULConst(size, asAllocatable(b), asConstantValue(a));
 365         } else {
 366             return emitBinaryVar(LIRKind.combine(a, b), AMD64RMOp.IMUL, size, true, asAllocatable(a), asAllocatable(b));
 367         }
 368     }
 369 
 370     @Override
 371     public Variable emitMul(Value a, Value b, boolean setFlags) {
 372         LIRKind resultKind = LIRKind.combine(a, b);
 373         switch ((AMD64Kind) a.getPlatformKind()) {
 374             case DWORD:
 375                 return emitIMUL(DWORD, a, b);
 376             case QWORD:
 377                 return emitIMUL(QWORD, a, b);
 378             case SINGLE:
 379                 return emitBinary(resultKind, SSEOp.MUL, SS, true, a, b);
 380             case DOUBLE:
 381                 return emitBinary(resultKind, SSEOp.MUL, SD, true, a, b);
 382             default:
 383                 throw GraalError.shouldNotReachHere();
 384         }
 385     }
 386 
 387     private RegisterValue moveToReg(Register reg, Value v) {
 388         RegisterValue ret = reg.asValue(v.getValueKind());
 389         getLIRGen().emitMove(ret, v);
 390         return ret;
 391     }
 392 
 393     private Value emitMulHigh(AMD64MOp opcode, OperandSize size, Value a, Value b) {
 394         AMD64MulDivOp mulHigh = getLIRGen().append(new AMD64MulDivOp(opcode, size, LIRKind.combine(a, b), moveToReg(AMD64.rax, a), asAllocatable(b)));
 395         return getLIRGen().emitMove(mulHigh.getHighResult());
 396     }
 397 
 398     @Override
 399     public Value emitMulHigh(Value a, Value b) {
 400         switch ((AMD64Kind) a.getPlatformKind()) {
 401             case DWORD:
 402                 return emitMulHigh(AMD64MOp.IMUL, DWORD, a, b);
 403             case QWORD:
 404                 return emitMulHigh(AMD64MOp.IMUL, QWORD, a, b);
 405             default:
 406                 throw GraalError.shouldNotReachHere();
 407         }
 408     }
 409 
 410     @Override
 411     public Value emitUMulHigh(Value a, Value b) {
 412         switch ((AMD64Kind) a.getPlatformKind()) {
 413             case DWORD:
 414                 return emitMulHigh(AMD64MOp.MUL, DWORD, a, b);
 415             case QWORD:
 416                 return emitMulHigh(AMD64MOp.MUL, QWORD, a, b);
 417             default:
 418                 throw GraalError.shouldNotReachHere();
 419         }
 420     }
 421 
 422     public Value emitBinaryMemory(AMD64RMOp op, OperandSize size, AllocatableValue a, AMD64AddressValue location, LIRFrameState state) {
 423         Variable result = getLIRGen().newVariable(LIRKind.combine(a));
 424         getLIRGen().append(new AMD64Binary.MemoryTwoOp(op, size, result, a, location, state));
 425         return result;
 426     }
 427 
 428     protected Value emitConvertMemoryOp(PlatformKind kind, AMD64RMOp op, OperandSize size, AMD64AddressValue address, LIRFrameState state) {
 429         Variable result = getLIRGen().newVariable(LIRKind.value(kind));
 430         getLIRGen().append(new AMD64Unary.MemoryOp(op, size, result, address, state));
 431         return result;
 432     }
 433 
 434     protected Value emitZeroExtendMemory(AMD64Kind memoryKind, int resultBits, AMD64AddressValue address, LIRFrameState state) {
 435         // Issue a zero extending load of the proper bit size and set the result to
 436         // the proper kind.
 437         Variable result = getLIRGen().newVariable(LIRKind.value(resultBits <= 32 ? AMD64Kind.DWORD : AMD64Kind.QWORD));
 438         switch (memoryKind) {
 439             case BYTE:
 440                 getLIRGen().append(new AMD64Unary.MemoryOp(MOVZXB, DWORD, result, address, state));
 441                 break;
 442             case WORD:
 443                 getLIRGen().append(new AMD64Unary.MemoryOp(MOVZX, DWORD, result, address, state));
 444                 break;
 445             case DWORD:
 446                 getLIRGen().append(new AMD64Unary.MemoryOp(MOV, DWORD, result, address, state));
 447                 break;
 448             case QWORD:
 449                 getLIRGen().append(new AMD64Unary.MemoryOp(MOV, QWORD, result, address, state));
 450                 break;
 451             default:
 452                 throw GraalError.shouldNotReachHere();
 453         }
 454         return result;
 455     }
 456 
 457     private AMD64MulDivOp emitIDIV(OperandSize size, Value a, Value b, LIRFrameState state) {
 458         LIRKind kind = LIRKind.combine(a, b);
 459 
 460         AMD64SignExtendOp sx = getLIRGen().append(new AMD64SignExtendOp(size, kind, moveToReg(AMD64.rax, a)));
 461         return getLIRGen().append(new AMD64MulDivOp(AMD64MOp.IDIV, size, kind, sx.getHighResult(), sx.getLowResult(), asAllocatable(b), state));
 462     }
 463 
 464     private AMD64MulDivOp emitDIV(OperandSize size, Value a, Value b, LIRFrameState state) {
 465         LIRKind kind = LIRKind.combine(a, b);
 466 
 467         RegisterValue rax = moveToReg(AMD64.rax, a);
 468         RegisterValue rdx = AMD64.rdx.asValue(kind);
 469         getLIRGen().append(new AMD64ClearRegisterOp(size, rdx));
 470         return getLIRGen().append(new AMD64MulDivOp(AMD64MOp.DIV, size, kind, rdx, rax, asAllocatable(b), state));
 471     }
 472 
 473     public Value[] emitSignedDivRem(Value a, Value b, LIRFrameState state) {
 474         AMD64MulDivOp op;
 475         switch ((AMD64Kind) a.getPlatformKind()) {
 476             case DWORD:
 477                 op = emitIDIV(DWORD, a, b, state);
 478                 break;
 479             case QWORD:
 480                 op = emitIDIV(QWORD, a, b, state);
 481                 break;
 482             default:
 483                 throw GraalError.shouldNotReachHere();
 484         }
 485         return new Value[]{getLIRGen().emitMove(op.getQuotient()), getLIRGen().emitMove(op.getRemainder())};
 486     }
 487 
 488     public Value[] emitUnsignedDivRem(Value a, Value b, LIRFrameState state) {
 489         AMD64MulDivOp op;
 490         switch ((AMD64Kind) a.getPlatformKind()) {
 491             case DWORD:
 492                 op = emitDIV(DWORD, a, b, state);
 493                 break;
 494             case QWORD:
 495                 op = emitDIV(QWORD, a, b, state);
 496                 break;
 497             default:
 498                 throw GraalError.shouldNotReachHere();
 499         }
 500         return new Value[]{getLIRGen().emitMove(op.getQuotient()), getLIRGen().emitMove(op.getRemainder())};
 501     }
 502 
 503     @Override
 504     public Value emitDiv(Value a, Value b, LIRFrameState state) {
 505         LIRKind resultKind = LIRKind.combine(a, b);
 506         switch ((AMD64Kind) a.getPlatformKind()) {
 507             case DWORD:
 508                 AMD64MulDivOp op = emitIDIV(DWORD, a, b, state);
 509                 return getLIRGen().emitMove(op.getQuotient());
 510             case QWORD:
 511                 AMD64MulDivOp lop = emitIDIV(QWORD, a, b, state);
 512                 return getLIRGen().emitMove(lop.getQuotient());
 513             case SINGLE:
 514                 return emitBinary(resultKind, SSEOp.DIV, SS, false, a, b);
 515             case DOUBLE:
 516                 return emitBinary(resultKind, SSEOp.DIV, SD, false, a, b);
 517             default:
 518                 throw GraalError.shouldNotReachHere();
 519         }
 520     }
 521 
 522     @Override
 523     public Value emitRem(Value a, Value b, LIRFrameState state) {
 524         switch ((AMD64Kind) a.getPlatformKind()) {
 525             case DWORD:
 526                 AMD64MulDivOp op = emitIDIV(DWORD, a, b, state);
 527                 return getLIRGen().emitMove(op.getRemainder());
 528             case QWORD:
 529                 AMD64MulDivOp lop = emitIDIV(QWORD, a, b, state);
 530                 return getLIRGen().emitMove(lop.getRemainder());
 531             case SINGLE: {
 532                 Variable result = getLIRGen().newVariable(LIRKind.combine(a, b));
 533                 getLIRGen().append(new FPDivRemOp(FREM, result, getLIRGen().load(a), getLIRGen().load(b)));
 534                 return result;
 535             }
 536             case DOUBLE: {
 537                 Variable result = getLIRGen().newVariable(LIRKind.combine(a, b));
 538                 getLIRGen().append(new FPDivRemOp(DREM, result, getLIRGen().load(a), getLIRGen().load(b)));
 539                 return result;
 540             }
 541             default:
 542                 throw GraalError.shouldNotReachHere();
 543         }
 544     }
 545 
 546     @Override
 547     public Variable emitUDiv(Value a, Value b, LIRFrameState state) {
 548         AMD64MulDivOp op;
 549         switch ((AMD64Kind) a.getPlatformKind()) {
 550             case DWORD:
 551                 op = emitDIV(DWORD, a, b, state);
 552                 break;
 553             case QWORD:
 554                 op = emitDIV(QWORD, a, b, state);
 555                 break;
 556             default:
 557                 throw GraalError.shouldNotReachHere();
 558         }
 559         return getLIRGen().emitMove(op.getQuotient());
 560     }
 561 
 562     @Override
 563     public Variable emitURem(Value a, Value b, LIRFrameState state) {
 564         AMD64MulDivOp op;
 565         switch ((AMD64Kind) a.getPlatformKind()) {
 566             case DWORD:
 567                 op = emitDIV(DWORD, a, b, state);
 568                 break;
 569             case QWORD:
 570                 op = emitDIV(QWORD, a, b, state);
 571                 break;
 572             default:
 573                 throw GraalError.shouldNotReachHere();
 574         }
 575         return getLIRGen().emitMove(op.getRemainder());
 576     }
 577 
 578     @Override
 579     public Variable emitAnd(Value a, Value b) {
 580         LIRKind resultKind = LIRKind.combine(a, b);
 581         switch ((AMD64Kind) a.getPlatformKind()) {
 582             case DWORD:
 583                 return emitBinary(resultKind, AND, DWORD, true, a, b, false);
 584             case QWORD:
 585                 return emitBinary(resultKind, AND, QWORD, true, a, b, false);
 586             case SINGLE:
 587                 return emitBinary(resultKind, SSEOp.AND, PS, true, a, b);
 588             case DOUBLE:
 589                 return emitBinary(resultKind, SSEOp.AND, PD, true, a, b);
 590             default:
 591                 throw GraalError.shouldNotReachHere();
 592         }
 593     }
 594 
 595     @Override
 596     public Variable emitOr(Value a, Value b) {
 597         LIRKind resultKind = LIRKind.combine(a, b);
 598         switch ((AMD64Kind) a.getPlatformKind()) {
 599             case DWORD:
 600                 return emitBinary(resultKind, OR, DWORD, true, a, b, false);
 601             case QWORD:
 602                 return emitBinary(resultKind, OR, QWORD, true, a, b, false);
 603             case SINGLE:
 604                 return emitBinary(resultKind, SSEOp.OR, PS, true, a, b);
 605             case DOUBLE:
 606                 return emitBinary(resultKind, SSEOp.OR, PD, true, a, b);
 607             default:
 608                 throw GraalError.shouldNotReachHere();
 609         }
 610     }
 611 
 612     @Override
 613     public Variable emitXor(Value a, Value b) {
 614         LIRKind resultKind = LIRKind.combine(a, b);
 615         switch ((AMD64Kind) a.getPlatformKind()) {
 616             case DWORD:
 617                 return emitBinary(resultKind, XOR, DWORD, true, a, b, false);
 618             case QWORD:
 619                 return emitBinary(resultKind, XOR, QWORD, true, a, b, false);
 620             case SINGLE:
 621                 return emitBinary(resultKind, SSEOp.XOR, PS, true, a, b);
 622             case DOUBLE:
 623                 return emitBinary(resultKind, SSEOp.XOR, PD, true, a, b);
 624             default:
 625                 throw GraalError.shouldNotReachHere();
 626         }
 627     }
 628 
 629     private Variable emitShift(AMD64Shift op, OperandSize size, Value a, Value b) {
 630         Variable result = getLIRGen().newVariable(LIRKind.combine(a, b).changeType(a.getPlatformKind()));
 631         AllocatableValue input = asAllocatable(a);
 632         if (isJavaConstant(b)) {
 633             JavaConstant c = asJavaConstant(b);
 634             if (c.asLong() == 1) {
 635                 getLIRGen().append(new AMD64Unary.MOp(op.m1Op, size, result, input));
 636             } else {
 637                 /*
 638                  * c is implicitly masked to 5 or 6 bits by the CPU, so casting it to (int) is
 639                  * always correct, even without the NumUtil.is32bit() test.
 640                  */
 641                 getLIRGen().append(new AMD64Binary.ConstOp(op.miOp, size, result, input, (int) c.asLong()));
 642             }
 643         } else {
 644             getLIRGen().emitMove(RCX_I, b);
 645             getLIRGen().append(new AMD64ShiftOp(op.mcOp, size, result, input, RCX_I));
 646         }
 647         return result;
 648     }
 649 
 650     @Override
 651     public Variable emitShl(Value a, Value b) {
 652         switch ((AMD64Kind) a.getPlatformKind()) {
 653             case DWORD:
 654                 return emitShift(SHL, DWORD, a, b);
 655             case QWORD:
 656                 return emitShift(SHL, QWORD, a, b);
 657             default:
 658                 throw GraalError.shouldNotReachHere();
 659         }
 660     }
 661 
 662     @Override
 663     public Variable emitShr(Value a, Value b) {
 664         switch ((AMD64Kind) a.getPlatformKind()) {
 665             case DWORD:
 666                 return emitShift(SAR, DWORD, a, b);
 667             case QWORD:
 668                 return emitShift(SAR, QWORD, a, b);
 669             default:
 670                 throw GraalError.shouldNotReachHere();
 671         }
 672     }
 673 
 674     @Override
 675     public Variable emitUShr(Value a, Value b) {
 676         switch ((AMD64Kind) a.getPlatformKind()) {
 677             case DWORD:
 678                 return emitShift(SHR, DWORD, a, b);
 679             case QWORD:
 680                 return emitShift(SHR, QWORD, a, b);
 681             default:
 682                 throw GraalError.shouldNotReachHere();
 683         }
 684     }
 685 
 686     public Variable emitRol(Value a, Value b) {
 687         switch ((AMD64Kind) a.getPlatformKind()) {
 688             case DWORD:
 689                 return emitShift(ROL, DWORD, a, b);
 690             case QWORD:
 691                 return emitShift(ROL, QWORD, a, b);
 692             default:
 693                 throw GraalError.shouldNotReachHere();
 694         }
 695     }
 696 
 697     public Variable emitRor(Value a, Value b) {
 698         switch ((AMD64Kind) a.getPlatformKind()) {
 699             case DWORD:
 700                 return emitShift(ROR, DWORD, a, b);
 701             case QWORD:
 702                 return emitShift(ROR, QWORD, a, b);
 703             default:
 704                 throw GraalError.shouldNotReachHere();
 705         }
 706     }
 707 
 708     private AllocatableValue emitConvertOp(LIRKind kind, AMD64RMOp op, OperandSize size, Value input) {
 709         Variable result = getLIRGen().newVariable(kind);
 710         getLIRGen().append(new AMD64Unary.RMOp(op, size, result, asAllocatable(input)));
 711         return result;
 712     }
 713 
 714     private AllocatableValue emitConvertOp(LIRKind kind, AMD64MROp op, OperandSize size, Value input) {
 715         Variable result = getLIRGen().newVariable(kind);
 716         getLIRGen().append(new AMD64Unary.MROp(op, size, result, asAllocatable(input)));
 717         return result;
 718     }
 719 
 720     @Override
 721     public Value emitReinterpret(LIRKind to, Value inputVal) {
 722         ValueKind<?> from = inputVal.getValueKind();
 723         if (to.equals(from)) {
 724             return inputVal;
 725         }
 726 
 727         AllocatableValue input = asAllocatable(inputVal);
 728         /*
 729          * Conversions between integer to floating point types require moves between CPU and FPU
 730          * registers.
 731          */
 732         AMD64Kind fromKind = (AMD64Kind) from.getPlatformKind();
 733         switch ((AMD64Kind) to.getPlatformKind()) {
 734             case DWORD:
 735                 switch (fromKind) {
 736                     case SINGLE:
 737                         return emitConvertOp(to, AMD64MROp.MOVD, DWORD, input);
 738                 }
 739                 break;
 740             case QWORD:
 741                 switch (fromKind) {
 742                     case DOUBLE:
 743                         return emitConvertOp(to, AMD64MROp.MOVQ, QWORD, input);
 744                 }
 745                 break;
 746             case SINGLE:
 747                 switch (fromKind) {
 748                     case DWORD:
 749                         return emitConvertOp(to, AMD64RMOp.MOVD, DWORD, input);
 750                 }
 751                 break;
 752             case DOUBLE:
 753                 switch (fromKind) {
 754                     case QWORD:
 755                         return emitConvertOp(to, AMD64RMOp.MOVQ, QWORD, input);
 756                 }
 757                 break;
 758         }
 759         throw GraalError.shouldNotReachHere();
 760     }
 761 
 762     @Override
 763     public Value emitFloatConvert(FloatConvert op, Value input) {
 764         switch (op) {
 765             case D2F:
 766                 return emitConvertOp(LIRKind.combine(input).changeType(AMD64Kind.SINGLE), SSEOp.CVTSD2SS, SD, input);
 767             case D2I:
 768                 return emitConvertOp(LIRKind.combine(input).changeType(AMD64Kind.DWORD), SSEOp.CVTTSD2SI, DWORD, input);
 769             case D2L:
 770                 return emitConvertOp(LIRKind.combine(input).changeType(AMD64Kind.QWORD), SSEOp.CVTTSD2SI, QWORD, input);
 771             case F2D:
 772                 return emitConvertOp(LIRKind.combine(input).changeType(AMD64Kind.DOUBLE), SSEOp.CVTSS2SD, SS, input);
 773             case F2I:
 774                 return emitConvertOp(LIRKind.combine(input).changeType(AMD64Kind.DWORD), SSEOp.CVTTSS2SI, DWORD, input);
 775             case F2L:
 776                 return emitConvertOp(LIRKind.combine(input).changeType(AMD64Kind.QWORD), SSEOp.CVTTSS2SI, QWORD, input);
 777             case I2D:
 778                 return emitConvertOp(LIRKind.combine(input).changeType(AMD64Kind.DOUBLE), SSEOp.CVTSI2SD, DWORD, input);
 779             case I2F:
 780                 return emitConvertOp(LIRKind.combine(input).changeType(AMD64Kind.SINGLE), SSEOp.CVTSI2SS, DWORD, input);
 781             case L2D:
 782                 return emitConvertOp(LIRKind.combine(input).changeType(AMD64Kind.DOUBLE), SSEOp.CVTSI2SD, QWORD, input);
 783             case L2F:
 784                 return emitConvertOp(LIRKind.combine(input).changeType(AMD64Kind.SINGLE), SSEOp.CVTSI2SS, QWORD, input);
 785             default:
 786                 throw GraalError.shouldNotReachHere();
 787         }
 788     }
 789 
 790     @Override
 791     public Value emitNarrow(Value inputVal, int bits) {
 792         if (inputVal.getPlatformKind() == AMD64Kind.QWORD && bits <= 32) {
 793             // TODO make it possible to reinterpret Long as Int in LIR without move
 794             return emitConvertOp(LIRKind.combine(inputVal).changeType(AMD64Kind.DWORD), AMD64RMOp.MOV, DWORD, inputVal);
 795         } else {
 796             return inputVal;
 797         }
 798     }
 799 
 800     @Override
 801     public Value emitSignExtend(Value inputVal, int fromBits, int toBits) {
 802         assert fromBits <= toBits && toBits <= 64;
 803         if (fromBits == toBits) {
 804             return inputVal;
 805         } else if (toBits > 32) {
 806             // sign extend to 64 bits
 807             switch (fromBits) {
 808                 case 8:
 809                     return emitConvertOp(LIRKind.combine(inputVal).changeType(AMD64Kind.QWORD), MOVSXB, QWORD, inputVal);
 810                 case 16:
 811                     return emitConvertOp(LIRKind.combine(inputVal).changeType(AMD64Kind.QWORD), MOVSX, QWORD, inputVal);
 812                 case 32:
 813                     return emitConvertOp(LIRKind.combine(inputVal).changeType(AMD64Kind.QWORD), MOVSXD, QWORD, inputVal);
 814                 default:
 815                     throw GraalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
 816             }
 817         } else {
 818             // sign extend to 32 bits (smaller values are internally represented as 32 bit values)
 819             switch (fromBits) {
 820                 case 8:
 821                     return emitConvertOp(LIRKind.combine(inputVal).changeType(AMD64Kind.DWORD), MOVSXB, DWORD, inputVal);
 822                 case 16:
 823                     return emitConvertOp(LIRKind.combine(inputVal).changeType(AMD64Kind.DWORD), MOVSX, DWORD, inputVal);
 824                 case 32:
 825                     return inputVal;
 826                 default:
 827                     throw GraalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
 828             }
 829         }
 830     }
 831 
 832     @Override
 833     public Value emitZeroExtend(Value inputVal, int fromBits, int toBits) {
 834         assert fromBits <= toBits && toBits <= 64;
 835         if (fromBits == toBits) {
 836             return inputVal;
 837         } else if (fromBits > 32) {
 838             assert inputVal.getPlatformKind() == AMD64Kind.QWORD;
 839             Variable result = getLIRGen().newVariable(LIRKind.combine(inputVal));
 840             long mask = CodeUtil.mask(fromBits);
 841             getLIRGen().append(new AMD64Binary.DataTwoOp(AND.getRMOpcode(QWORD), QWORD, result, asAllocatable(inputVal), JavaConstant.forLong(mask)));
 842             return result;
 843         } else {
 844             LIRKind resultKind = LIRKind.combine(inputVal);
 845             if (toBits > 32) {
 846                 resultKind = resultKind.changeType(AMD64Kind.QWORD);
 847             } else {
 848                 resultKind = resultKind.changeType(AMD64Kind.DWORD);
 849             }
 850 
 851             /*
 852              * Always emit DWORD operations, even if the resultKind is Long. On AMD64, all DWORD
 853              * operations implicitly set the upper half of the register to 0, which is what we want
 854              * anyway. Compared to the QWORD oparations, the encoding of the DWORD operations is
 855              * sometimes one byte shorter.
 856              */
 857             switch (fromBits) {
 858                 case 8:
 859                     return emitConvertOp(resultKind, MOVZXB, DWORD, inputVal);
 860                 case 16:
 861                     return emitConvertOp(resultKind, MOVZX, DWORD, inputVal);
 862                 case 32:
 863                     return emitConvertOp(resultKind, MOV, DWORD, inputVal);
 864             }
 865 
 866             // odd bit count, fall back on manual masking
 867             Variable result = getLIRGen().newVariable(resultKind);
 868             JavaConstant mask;
 869             if (toBits > 32) {
 870                 mask = JavaConstant.forLong(CodeUtil.mask(fromBits));
 871             } else {
 872                 mask = JavaConstant.forInt((int) CodeUtil.mask(fromBits));
 873             }
 874             getLIRGen().append(new AMD64Binary.DataTwoOp(AND.getRMOpcode(DWORD), DWORD, result, asAllocatable(inputVal), mask));
 875             return result;
 876         }
 877     }
 878 
 879     @Override
 880     public Variable emitBitCount(Value value) {
 881         Variable result = getLIRGen().newVariable(LIRKind.combine(value).changeType(AMD64Kind.DWORD));
 882         assert ((AMD64Kind) value.getPlatformKind()).isInteger();
 883         if (value.getPlatformKind() == AMD64Kind.QWORD) {
 884             getLIRGen().append(new AMD64Unary.RMOp(POPCNT, QWORD, result, asAllocatable(value)));
 885         } else {
 886             getLIRGen().append(new AMD64Unary.RMOp(POPCNT, DWORD, result, asAllocatable(value)));
 887         }
 888         return result;
 889     }
 890 
 891     @Override
 892     public Variable emitBitScanForward(Value value) {
 893         Variable result = getLIRGen().newVariable(LIRKind.combine(value).changeType(AMD64Kind.DWORD));
 894         getLIRGen().append(new AMD64Unary.RMOp(BSF, QWORD, result, asAllocatable(value)));
 895         return result;
 896     }
 897 
 898     @Override
 899     public Variable emitBitScanReverse(Value value) {
 900         Variable result = getLIRGen().newVariable(LIRKind.combine(value).changeType(AMD64Kind.DWORD));
 901         assert ((AMD64Kind) value.getPlatformKind()).isInteger();
 902         if (value.getPlatformKind() == AMD64Kind.QWORD) {
 903             getLIRGen().append(new AMD64Unary.RMOp(BSR, QWORD, result, asAllocatable(value)));
 904         } else {
 905             getLIRGen().append(new AMD64Unary.RMOp(BSR, DWORD, result, asAllocatable(value)));
 906         }
 907         return result;
 908     }
 909 
 910     @Override
 911     public Value emitCountLeadingZeros(Value value) {
 912         Variable result = getLIRGen().newVariable(LIRKind.combine(value).changeType(AMD64Kind.DWORD));
 913         assert ((AMD64Kind) value.getPlatformKind()).isInteger();
 914         if (value.getPlatformKind() == AMD64Kind.QWORD) {
 915             getLIRGen().append(new AMD64Unary.RMOp(LZCNT, QWORD, result, asAllocatable(value)));
 916         } else {
 917             getLIRGen().append(new AMD64Unary.RMOp(LZCNT, DWORD, result, asAllocatable(value)));
 918         }
 919         return result;
 920     }
 921 
 922     @Override
 923     public Value emitCountTrailingZeros(Value value) {
 924         Variable result = getLIRGen().newVariable(LIRKind.combine(value).changeType(AMD64Kind.DWORD));
 925         assert ((AMD64Kind) value.getPlatformKind()).isInteger();
 926         if (value.getPlatformKind() == AMD64Kind.QWORD) {
 927             getLIRGen().append(new AMD64Unary.RMOp(TZCNT, QWORD, result, asAllocatable(value)));
 928         } else {
 929             getLIRGen().append(new AMD64Unary.RMOp(TZCNT, DWORD, result, asAllocatable(value)));
 930         }
 931         return result;
 932     }
 933 
 934     @Override
 935     public Value emitMathAbs(Value input) {
 936         Variable result = getLIRGen().newVariable(LIRKind.combine(input));
 937         switch ((AMD64Kind) input.getPlatformKind()) {
 938             case SINGLE:
 939                 getLIRGen().append(new AMD64Binary.DataTwoOp(SSEOp.AND, PS, result, asAllocatable(input), JavaConstant.forFloat(Float.intBitsToFloat(0x7FFFFFFF)), 16));
 940                 break;
 941             case DOUBLE:
 942                 getLIRGen().append(new AMD64Binary.DataTwoOp(SSEOp.AND, PD, result, asAllocatable(input), JavaConstant.forDouble(Double.longBitsToDouble(0x7FFFFFFFFFFFFFFFL)), 16));
 943                 break;
 944             default:
 945                 throw GraalError.shouldNotReachHere();
 946         }
 947         return result;
 948     }
 949 
 950     @Override
 951     public Value emitMathSqrt(Value input) {
 952         Variable result = getLIRGen().newVariable(LIRKind.combine(input));
 953         switch ((AMD64Kind) input.getPlatformKind()) {
 954             case SINGLE:
 955                 getLIRGen().append(new AMD64Unary.RMOp(SSEOp.SQRT, SS, result, asAllocatable(input)));
 956                 break;
 957             case DOUBLE:
 958                 getLIRGen().append(new AMD64Unary.RMOp(SSEOp.SQRT, SD, result, asAllocatable(input)));
 959                 break;
 960             default:
 961                 throw GraalError.shouldNotReachHere();
 962         }
 963         return result;
 964     }
 965 
 966     @Override
 967     public Value emitMathLog(Value input, boolean base10) {
 968         LIRGenerator gen = getLIRGen();
 969         Variable result = maths.emitLog(gen, input, base10);
 970         if (result == null) {
 971             result = gen.newVariable(LIRKind.combine(input));
 972             AllocatableValue stackSlot = gen.getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD));
 973             gen.append(new AMD64MathIntrinsicUnaryOp(getAMD64LIRGen(), base10 ? LOG10 : LOG, result, asAllocatable(input), stackSlot));
 974         }
 975         return result;
 976     }
 977 
 978     @Override
 979     public Value emitMathCos(Value input) {
 980         LIRGenerator gen = getLIRGen();
 981         Variable result = maths.emitCos(gen, input);
 982         if (result == null) {
 983             result = gen.newVariable(LIRKind.combine(input));
 984             AllocatableValue stackSlot = gen.getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD));
 985             gen.append(new AMD64MathIntrinsicUnaryOp(getAMD64LIRGen(), COS, result, asAllocatable(input), stackSlot));
 986         }
 987         return result;
 988     }
 989 
 990     @Override
 991     public Value emitMathSin(Value input) {
 992         LIRGenerator gen = getLIRGen();
 993         Variable result = maths.emitSin(gen, input);
 994         if (result == null) {
 995             result = gen.newVariable(LIRKind.combine(input));
 996             AllocatableValue stackSlot = gen.getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD));
 997             gen.append(new AMD64MathIntrinsicUnaryOp(getAMD64LIRGen(), SIN, result, asAllocatable(input), stackSlot));
 998         }
 999         return result;
1000     }
1001 
1002     @Override
1003     public Value emitMathTan(Value input) {
1004         LIRGenerator gen = getLIRGen();
1005         Variable result = maths.emitTan(gen, input);
1006         if (result == null) {
1007             result = gen.newVariable(LIRKind.combine(input));
1008             AllocatableValue stackSlot = gen.getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD));
1009             gen.append(new AMD64MathIntrinsicUnaryOp(getAMD64LIRGen(), TAN, result, asAllocatable(input), stackSlot));
1010         }
1011         return result;
1012     }
1013 
1014     @Override
1015     public Value emitMathExp(Value input) {
1016         Variable result = getLIRGen().newVariable(LIRKind.combine(input));
1017         AllocatableValue stackSlot = getLIRGen().getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD));
1018         getLIRGen().append(new AMD64MathIntrinsicUnaryOp(getAMD64LIRGen(), EXP, result, asAllocatable(input), stackSlot));
1019         return result;
1020     }
1021 
1022     @Override
1023     public Value emitMathPow(Value input1, Value input2) {
1024         Variable result = getLIRGen().newVariable(LIRKind.combine(input1));
1025         getLIRGen().append(new AMD64MathIntrinsicBinaryOp(getAMD64LIRGen(), POW, result, asAllocatable(input1), asAllocatable(input2)));
1026         return result;
1027     }
1028 
1029     protected AMD64LIRGenerator getAMD64LIRGen() {
1030         return (AMD64LIRGenerator) getLIRGen();
1031     }
1032 
1033     @Override
1034     public Variable emitLoad(LIRKind kind, Value address, LIRFrameState state) {
1035         AMD64AddressValue loadAddress = getAMD64LIRGen().asAddressValue(address);
1036         Variable result = getLIRGen().newVariable(getLIRGen().toRegisterKind(kind));
1037         switch ((AMD64Kind) kind.getPlatformKind()) {
1038             case BYTE:
1039                 getLIRGen().append(new AMD64Unary.MemoryOp(MOVSXB, DWORD, result, loadAddress, state));
1040                 break;
1041             case WORD:
1042                 getLIRGen().append(new AMD64Unary.MemoryOp(MOVSX, DWORD, result, loadAddress, state));
1043                 break;
1044             case DWORD:
1045                 getLIRGen().append(new AMD64Unary.MemoryOp(MOV, DWORD, result, loadAddress, state));
1046                 break;
1047             case QWORD:
1048                 getLIRGen().append(new AMD64Unary.MemoryOp(MOV, QWORD, result, loadAddress, state));
1049                 break;
1050             case SINGLE:
1051                 getLIRGen().append(new AMD64Unary.MemoryOp(MOVSS, SS, result, loadAddress, state));
1052                 break;
1053             case DOUBLE:
1054                 getLIRGen().append(new AMD64Unary.MemoryOp(MOVSD, SD, result, loadAddress, state));
1055                 break;
1056             default:
1057                 throw GraalError.shouldNotReachHere();
1058         }
1059         return result;
1060     }
1061 
1062     protected void emitStoreConst(AMD64Kind kind, AMD64AddressValue address, ConstantValue value, LIRFrameState state) {
1063         Constant c = value.getConstant();
1064         if (JavaConstant.isNull(c)) {
1065             assert kind == AMD64Kind.DWORD || kind == AMD64Kind.QWORD;
1066             OperandSize size = kind == AMD64Kind.DWORD ? DWORD : QWORD;
1067             getLIRGen().append(new AMD64BinaryConsumer.MemoryConstOp(AMD64MIOp.MOV, size, address, 0, state));
1068             return;
1069         } else if (c instanceof VMConstant) {
1070             // only 32-bit constants can be patched
1071             if (kind == AMD64Kind.DWORD) {
1072                 if (getLIRGen().target().inlineObjects || !(c instanceof JavaConstant)) {
1073                     // if c is a JavaConstant, it's an oop, otherwise it's a metaspace constant
1074                     assert !(c instanceof JavaConstant) || ((JavaConstant) c).getJavaKind() == JavaKind.Object;
1075                     getLIRGen().append(new AMD64BinaryConsumer.MemoryVMConstOp(AMD64MIOp.MOV, address, (VMConstant) c, state));
1076                     return;
1077                 }
1078             }
1079         } else {
1080             JavaConstant jc = (JavaConstant) c;
1081             assert jc.getJavaKind().isPrimitive();
1082 
1083             AMD64MIOp op = AMD64MIOp.MOV;
1084             OperandSize size;
1085             long imm;
1086 
1087             switch (kind) {
1088                 case BYTE:
1089                     op = AMD64MIOp.MOVB;
1090                     size = BYTE;
1091                     imm = jc.asInt();
1092                     break;
1093                 case WORD:
1094                     size = WORD;
1095                     imm = jc.asInt();
1096                     break;
1097                 case DWORD:
1098                     size = DWORD;
1099                     imm = jc.asInt();
1100                     break;
1101                 case QWORD:
1102                     size = QWORD;
1103                     imm = jc.asLong();
1104                     break;
1105                 case SINGLE:
1106                     size = DWORD;
1107                     imm = Float.floatToRawIntBits(jc.asFloat());
1108                     break;
1109                 case DOUBLE:
1110                     size = QWORD;
1111                     imm = Double.doubleToRawLongBits(jc.asDouble());
1112                     break;
1113                 default:
1114                     throw GraalError.shouldNotReachHere("unexpected kind " + kind);
1115             }
1116 
1117             if (NumUtil.isInt(imm)) {
1118                 getLIRGen().append(new AMD64BinaryConsumer.MemoryConstOp(op, size, address, (int) imm, state));
1119                 return;
1120             }
1121         }
1122 
1123         // fallback: load, then store
1124         emitStore(kind, address, asAllocatable(value), state);
1125     }
1126 
1127     protected void emitStore(AMD64Kind kind, AMD64AddressValue address, AllocatableValue value, LIRFrameState state) {
1128         switch (kind) {
1129             case BYTE:
1130                 getLIRGen().append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOVB, BYTE, address, value, state));
1131                 break;
1132             case WORD:
1133                 getLIRGen().append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOV, WORD, address, value, state));
1134                 break;
1135             case DWORD:
1136                 getLIRGen().append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOV, DWORD, address, value, state));
1137                 break;
1138             case QWORD:
1139                 getLIRGen().append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOV, QWORD, address, value, state));
1140                 break;
1141             case SINGLE:
1142                 getLIRGen().append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOVSS, SS, address, value, state));
1143                 break;
1144             case DOUBLE:
1145                 getLIRGen().append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOVSD, SD, address, value, state));
1146                 break;
1147             default:
1148                 throw GraalError.shouldNotReachHere();
1149         }
1150     }
1151 
1152     @Override
1153     public void emitStore(ValueKind<?> lirKind, Value address, Value input, LIRFrameState state) {
1154         AMD64AddressValue storeAddress = getAMD64LIRGen().asAddressValue(address);
1155         AMD64Kind kind = (AMD64Kind) lirKind.getPlatformKind();
1156         if (isConstantValue(input)) {
1157             emitStoreConst(kind, storeAddress, asConstantValue(input), state);
1158         } else {
1159             emitStore(kind, storeAddress, asAllocatable(input), state);
1160         }
1161     }
1162 
1163     private boolean mustReplaceNullWithNullRegister(Constant nullConstant) {
1164         /* Uncompressed null pointers only */
1165         return nullRegisterValue != null && JavaConstant.NULL_POINTER.equals(nullConstant);
1166     }
1167 
1168     @Override
1169     public void emitCompareOp(AMD64Kind cmpKind, Variable left, Value right) {
1170         OperandSize size;
1171         switch (cmpKind) {
1172             case BYTE:
1173                 size = BYTE;
1174                 break;
1175             case WORD:
1176                 size = WORD;
1177                 break;
1178             case DWORD:
1179                 size = DWORD;
1180                 break;
1181             case QWORD:
1182                 size = QWORD;
1183                 break;
1184             case SINGLE:
1185                 getLIRGen().append(new AMD64BinaryConsumer.Op(SSEOp.UCOMIS, PS, left, asAllocatable(right)));
1186                 return;
1187             case DOUBLE:
1188                 getLIRGen().append(new AMD64BinaryConsumer.Op(SSEOp.UCOMIS, PD, left, asAllocatable(right)));
1189                 return;
1190             default:
1191                 throw GraalError.shouldNotReachHere("unexpected kind: " + cmpKind);
1192         }
1193 
1194         if (isConstantValue(right)) {
1195             Constant c = LIRValueUtil.asConstant(right);
1196             if (JavaConstant.isNull(c)) {
1197                 if (mustReplaceNullWithNullRegister(c)) {
1198                     getLIRGen().append(new AMD64BinaryConsumer.Op(AMD64RMOp.CMP, size, left, nullRegisterValue));
1199                 } else {
1200                     getLIRGen().append(new AMD64BinaryConsumer.Op(TEST, size, left, left));
1201                 }
1202                 return;
1203             } else if (c instanceof VMConstant) {
1204                 VMConstant vc = (VMConstant) c;
1205                 if (size == DWORD && !GeneratePIC.getValue(getOptions())) {
1206                     getLIRGen().append(new AMD64BinaryConsumer.VMConstOp(CMP.getMIOpcode(DWORD, false), left, vc));
1207                 } else {
1208                     getLIRGen().append(new AMD64BinaryConsumer.DataOp(CMP.getRMOpcode(size), size, left, vc));
1209                 }
1210                 return;
1211             } else if (c instanceof JavaConstant) {
1212                 JavaConstant jc = (JavaConstant) c;
1213                 if (jc.isDefaultForKind()) {
1214                     AMD64RMOp op = size == BYTE ? TESTB : TEST;
1215                     getLIRGen().append(new AMD64BinaryConsumer.Op(op, size, left, left));
1216                     return;
1217                 } else if (NumUtil.is32bit(jc.asLong())) {
1218                     getLIRGen().append(new AMD64BinaryConsumer.ConstOp(CMP, size, left, (int) jc.asLong()));
1219                     return;
1220                 }
1221             }
1222         }
1223 
1224         // fallback: load, then compare
1225         getLIRGen().append(new AMD64BinaryConsumer.Op(CMP.getRMOpcode(size), size, left, asAllocatable(right)));
1226     }
1227 
1228     @Override
1229     public Value emitRound(Value value, RoundingMode mode) {
1230         Variable result = getLIRGen().newVariable(LIRKind.combine(value));
1231         assert ((AMD64Kind) value.getPlatformKind()).isXMM();
1232         if (value.getPlatformKind() == AMD64Kind.SINGLE) {
1233             getLIRGen().append(new AMD64Binary.RMIOp(AMD64RMIOp.ROUNDSS, OperandSize.PD, result, asAllocatable(value), mode.encoding));
1234         } else {
1235             getLIRGen().append(new AMD64Binary.RMIOp(AMD64RMIOp.ROUNDSD, OperandSize.PD, result, asAllocatable(value), mode.encoding));
1236         }
1237         return result;
1238     }
1239 }