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