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.OR;
  31 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.SUB;
  32 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.XOR;
  33 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.MOVSX;
  34 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.MOVSXB;
  35 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp.MOVSXD;
  36 import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize.DWORD;
  37 import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize.QWORD;
  38 import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize.SD;
  39 import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize.SS;
  40 
  41 import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MIOp;
  42 import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp;
  43 import org.graalvm.compiler.asm.amd64.AMD64Assembler.SSEOp;
  44 import org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize;
  45 import org.graalvm.compiler.core.common.LIRKind;
  46 import org.graalvm.compiler.core.common.NumUtil;
  47 import org.graalvm.compiler.core.common.calc.CanonicalCondition;
  48 import org.graalvm.compiler.core.common.calc.Condition;
  49 import org.graalvm.compiler.core.gen.NodeLIRBuilder;
  50 import org.graalvm.compiler.core.gen.NodeMatchRules;
  51 import org.graalvm.compiler.core.match.ComplexMatchResult;
  52 import org.graalvm.compiler.core.match.MatchRule;
  53 import org.graalvm.compiler.debug.GraalError;
  54 import org.graalvm.compiler.lir.LIRFrameState;
  55 import org.graalvm.compiler.lir.LIRValueUtil;
  56 import org.graalvm.compiler.lir.LabelRef;
  57 import org.graalvm.compiler.lir.amd64.AMD64AddressValue;
  58 import org.graalvm.compiler.lir.amd64.AMD64BinaryConsumer;
  59 import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.BranchOp;
  60 import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
  61 import org.graalvm.compiler.nodes.ConstantNode;
  62 import org.graalvm.compiler.nodes.DeoptimizingNode;
  63 import org.graalvm.compiler.nodes.IfNode;
  64 import org.graalvm.compiler.nodes.NodeView;
  65 import org.graalvm.compiler.nodes.ValueNode;
  66 import org.graalvm.compiler.nodes.calc.CompareNode;
  67 import org.graalvm.compiler.nodes.calc.FloatConvertNode;
  68 import org.graalvm.compiler.nodes.calc.LeftShiftNode;
  69 import org.graalvm.compiler.nodes.calc.NarrowNode;
  70 import org.graalvm.compiler.nodes.calc.ReinterpretNode;
  71 import org.graalvm.compiler.nodes.calc.SignExtendNode;
  72 import org.graalvm.compiler.nodes.calc.UnsignedRightShiftNode;
  73 import org.graalvm.compiler.nodes.calc.ZeroExtendNode;
  74 import org.graalvm.compiler.nodes.java.LogicCompareAndSwapNode;
  75 import org.graalvm.compiler.nodes.java.ValueCompareAndSwapNode;
  76 import org.graalvm.compiler.nodes.memory.Access;
  77 import org.graalvm.compiler.nodes.memory.LIRLowerableAccess;
  78 import org.graalvm.compiler.nodes.memory.WriteNode;
  79 import org.graalvm.compiler.nodes.util.GraphUtil;
  80 
  81 import jdk.vm.ci.amd64.AMD64Kind;
  82 import jdk.vm.ci.meta.AllocatableValue;
  83 import jdk.vm.ci.meta.JavaConstant;
  84 import jdk.vm.ci.meta.PlatformKind;
  85 import jdk.vm.ci.meta.Value;
  86 import jdk.vm.ci.meta.ValueKind;
  87 
  88 public class AMD64NodeMatchRules extends NodeMatchRules {
  89 
  90     public AMD64NodeMatchRules(LIRGeneratorTool gen) {
  91         super(gen);
  92     }
  93 
  94     protected LIRFrameState getState(Access access) {
  95         if (access instanceof DeoptimizingNode) {
  96             return state((DeoptimizingNode) access);
  97         }
  98         return null;
  99     }
 100 
 101     protected AMD64Kind getMemoryKind(LIRLowerableAccess access) {
 102         return (AMD64Kind) getLirKind(access).getPlatformKind();
 103     }
 104 
 105     protected LIRKind getLirKind(LIRLowerableAccess access) {
 106         return gen.getLIRKind(access.getAccessStamp());
 107     }
 108 
 109     protected OperandSize getMemorySize(LIRLowerableAccess access) {
 110         switch (getMemoryKind(access)) {
 111             case BYTE:
 112                 return OperandSize.BYTE;
 113             case WORD:
 114                 return OperandSize.WORD;
 115             case DWORD:
 116                 return OperandSize.DWORD;
 117             case QWORD:
 118                 return OperandSize.QWORD;
 119             case SINGLE:
 120                 return OperandSize.SS;
 121             case DOUBLE:
 122                 return OperandSize.SD;
 123             default:
 124                 throw GraalError.shouldNotReachHere("unsupported memory access type " + getMemoryKind(access));
 125         }
 126     }
 127 
 128     protected ComplexMatchResult emitCompareBranchMemory(IfNode ifNode, CompareNode compare, ValueNode value, LIRLowerableAccess access) {
 129         Condition cond = compare.condition().asCondition();
 130         AMD64Kind kind = getMemoryKind(access);
 131         boolean matchedAsConstant = false; // For assertion checking
 132 
 133         if (value.isConstant()) {
 134             JavaConstant constant = value.asJavaConstant();
 135             if (constant != null) {
 136                 if (kind == AMD64Kind.QWORD && !constant.getJavaKind().isObject() && !NumUtil.isInt(constant.asLong())) {
 137                     // Only imm32 as long
 138                     return null;
 139                 }
 140                 // A QWORD that can be encoded as int can be embedded as a constant
 141                 matchedAsConstant = kind == AMD64Kind.QWORD && !constant.getJavaKind().isObject() && NumUtil.isInt(constant.asLong());
 142             }
 143             if (kind == AMD64Kind.DWORD) {
 144                 // Any DWORD value should be embeddable as a constant
 145                 matchedAsConstant = true;
 146             }
 147             if (kind.isXMM()) {
 148                 ifNode.getDebug().log("Skipping constant compares for float kinds");
 149                 return null;
 150             }
 151         }
 152         boolean matchedAsConstantFinal = matchedAsConstant;
 153 
 154         /*
 155          * emitCompareBranchMemory expects the memory on the right, so mirror the condition if
 156          * that's not true. It might be mirrored again the actual compare is emitted but that's ok.
 157          */
 158         Condition finalCondition = GraphUtil.unproxify(compare.getX()) == access ? cond.mirror() : cond;
 159         return new ComplexMatchResult() {
 160             @Override
 161             public Value evaluate(NodeLIRBuilder builder) {
 162                 LabelRef trueLabel = getLIRBlock(ifNode.trueSuccessor());
 163                 LabelRef falseLabel = getLIRBlock(ifNode.falseSuccessor());
 164                 boolean unorderedIsTrue = compare.unorderedIsTrue();
 165                 double trueLabelProbability = ifNode.probability(ifNode.trueSuccessor());
 166                 Value other = operand(value);
 167                 /*
 168                  * Check that patterns which were matched as a constant actually end up seeing a
 169                  * constant in the LIR.
 170                  */
 171                 assert !matchedAsConstantFinal || !LIRValueUtil.isVariable(other) : "expected constant value " + value;
 172                 AMD64AddressValue address = (AMD64AddressValue) operand(access.getAddress());
 173                 getLIRGeneratorTool().emitCompareBranchMemory(kind, other, address, getState(access), finalCondition, unorderedIsTrue, trueLabel, falseLabel, trueLabelProbability);
 174                 return null;
 175             }
 176         };
 177     }
 178 
 179     private ComplexMatchResult emitIntegerTestBranchMemory(IfNode x, ValueNode value, LIRLowerableAccess access) {
 180         LabelRef trueLabel = getLIRBlock(x.trueSuccessor());
 181         LabelRef falseLabel = getLIRBlock(x.falseSuccessor());
 182         double trueLabelProbability = x.probability(x.trueSuccessor());
 183         AMD64Kind kind = getMemoryKind(access);
 184         OperandSize size = kind == AMD64Kind.QWORD ? QWORD : DWORD;
 185         if (value.isConstant()) {
 186             JavaConstant constant = value.asJavaConstant();
 187             if (constant != null && kind == AMD64Kind.QWORD && !NumUtil.isInt(constant.asLong())) {
 188                 // Only imm32 as long
 189                 return null;
 190             }
 191             return builder -> {
 192                 AMD64AddressValue address = (AMD64AddressValue) operand(access.getAddress());
 193                 gen.append(new AMD64BinaryConsumer.MemoryConstOp(AMD64MIOp.TEST, size, address, (int) constant.asLong(), getState(access)));
 194                 gen.append(new BranchOp(Condition.EQ, trueLabel, falseLabel, trueLabelProbability));
 195                 return null;
 196             };
 197         } else {
 198             return builder -> {
 199                 AMD64AddressValue address = (AMD64AddressValue) operand(access.getAddress());
 200                 gen.append(new AMD64BinaryConsumer.MemoryRMOp(AMD64RMOp.TEST, size, gen.asAllocatable(operand(value)), address, getState(access)));
 201                 gen.append(new BranchOp(Condition.EQ, trueLabel, falseLabel, trueLabelProbability));
 202                 return null;
 203             };
 204         }
 205     }
 206 
 207     protected ComplexMatchResult emitConvertMemoryOp(PlatformKind kind, AMD64RMOp op, OperandSize size, Access access, ValueKind<?> addressKind) {
 208         return builder -> {
 209             AMD64AddressValue address = (AMD64AddressValue) operand(access.getAddress());
 210             LIRFrameState state = getState(access);
 211             if (addressKind != null) {
 212                 address = address.withKind(addressKind);
 213             }
 214             return getArithmeticLIRGenerator().emitConvertMemoryOp(kind, op, size, address, state);
 215         };
 216     }
 217 
 218     protected ComplexMatchResult emitConvertMemoryOp(PlatformKind kind, AMD64RMOp op, OperandSize size, Access access) {
 219         return emitConvertMemoryOp(kind, op, size, access, null);
 220     }
 221 
 222     private ComplexMatchResult emitSignExtendMemory(Access access, int fromBits, int toBits, ValueKind<?> addressKind) {
 223         assert fromBits <= toBits && toBits <= 64;
 224         AMD64Kind kind = null;
 225         AMD64RMOp op;
 226         OperandSize size;
 227         if (fromBits == toBits) {
 228             return null;
 229         } else if (toBits > 32) {
 230             kind = AMD64Kind.QWORD;
 231             size = OperandSize.QWORD;
 232             // sign extend to 64 bits
 233             switch (fromBits) {
 234                 case 8:
 235                     op = MOVSXB;
 236                     break;
 237                 case 16:
 238                     op = MOVSX;
 239                     break;
 240                 case 32:
 241                     op = MOVSXD;
 242                     break;
 243                 default:
 244                     throw GraalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
 245             }
 246         } else {
 247             kind = AMD64Kind.DWORD;
 248             size = OperandSize.DWORD;
 249             // sign extend to 32 bits (smaller values are internally represented as 32 bit values)
 250             switch (fromBits) {
 251                 case 8:
 252                     op = MOVSXB;
 253                     break;
 254                 case 16:
 255                     op = MOVSX;
 256                     break;
 257                 case 32:
 258                     return null;
 259                 default:
 260                     throw GraalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
 261             }
 262         }
 263         if (kind != null && op != null) {
 264             return emitConvertMemoryOp(kind, op, size, access, addressKind);
 265         }
 266         return null;
 267     }
 268 
 269     private Value emitReinterpretMemory(LIRKind to, Access access) {
 270         AMD64AddressValue address = (AMD64AddressValue) operand(access.getAddress());
 271         LIRFrameState state = getState(access);
 272         return getArithmeticLIRGenerator().emitLoad(to, address, state);
 273     }
 274 
 275     @MatchRule("(If (IntegerTest Read=access value))")
 276     @MatchRule("(If (IntegerTest FloatingRead=access value))")
 277     public ComplexMatchResult integerTestBranchMemory(IfNode root, LIRLowerableAccess access, ValueNode value) {
 278         return emitIntegerTestBranchMemory(root, value, access);
 279     }
 280 
 281     @MatchRule("(If (IntegerEquals=compare value Read=access))")
 282     @MatchRule("(If (IntegerLessThan=compare value Read=access))")
 283     @MatchRule("(If (IntegerBelow=compare value Read=access))")
 284     @MatchRule("(If (IntegerEquals=compare value FloatingRead=access))")
 285     @MatchRule("(If (IntegerLessThan=compare value FloatingRead=access))")
 286     @MatchRule("(If (IntegerBelow=compare value FloatingRead=access))")
 287     @MatchRule("(If (FloatEquals=compare value Read=access))")
 288     @MatchRule("(If (FloatEquals=compare value FloatingRead=access))")
 289     @MatchRule("(If (FloatLessThan=compare value Read=access))")
 290     @MatchRule("(If (FloatLessThan=compare value FloatingRead=access))")
 291     @MatchRule("(If (PointerEquals=compare value Read=access))")
 292     @MatchRule("(If (PointerEquals=compare value FloatingRead=access))")
 293     @MatchRule("(If (ObjectEquals=compare value Read=access))")
 294     @MatchRule("(If (ObjectEquals=compare value FloatingRead=access))")
 295     public ComplexMatchResult ifCompareMemory(IfNode root, CompareNode compare, ValueNode value, LIRLowerableAccess access) {
 296         return emitCompareBranchMemory(root, compare, value, access);
 297     }
 298 
 299     @MatchRule("(If (ObjectEquals=compare value ValueCompareAndSwap=cas))")
 300     @MatchRule("(If (PointerEquals=compare value ValueCompareAndSwap=cas))")
 301     @MatchRule("(If (FloatEquals=compare value ValueCompareAndSwap=cas))")
 302     @MatchRule("(If (IntegerEquals=compare value ValueCompareAndSwap=cas))")
 303     public ComplexMatchResult ifCompareValueCas(IfNode root, CompareNode compare, ValueNode value, ValueCompareAndSwapNode cas) {
 304         assert compare.condition() == CanonicalCondition.EQ;
 305         if (value == cas.getExpectedValue() && cas.usages().count() == 1) {
 306             return builder -> {
 307                 LIRKind kind = getLirKind(cas);
 308                 LabelRef trueLabel = getLIRBlock(root.trueSuccessor());
 309                 LabelRef falseLabel = getLIRBlock(root.falseSuccessor());
 310                 double trueLabelProbability = root.probability(root.trueSuccessor());
 311                 Value expectedValue = operand(cas.getExpectedValue());
 312                 Value newValue = operand(cas.getNewValue());
 313                 AMD64AddressValue address = (AMD64AddressValue) operand(cas.getAddress());
 314                 getLIRGeneratorTool().emitCompareAndSwapBranch(kind, address, expectedValue, newValue, Condition.EQ, trueLabel, falseLabel, trueLabelProbability);
 315                 return null;
 316             };
 317         }
 318         return null;
 319     }
 320 
 321     @MatchRule("(If (ObjectEquals=compare value LogicCompareAndSwap=cas))")
 322     @MatchRule("(If (PointerEquals=compare value LogicCompareAndSwap=cas))")
 323     @MatchRule("(If (FloatEquals=compare value LogicCompareAndSwap=cas))")
 324     @MatchRule("(If (IntegerEquals=compare value LogicCompareAndSwap=cas))")
 325     public ComplexMatchResult ifCompareLogicCas(IfNode root, CompareNode compare, ValueNode value, LogicCompareAndSwapNode cas) {
 326         JavaConstant constant = value.asJavaConstant();
 327         assert compare.condition() == CanonicalCondition.EQ;
 328         if (constant != null && cas.usages().count() == 1) {
 329             long constantValue = constant.asLong();
 330             boolean successIsTrue;
 331             if (constantValue == 0) {
 332                 successIsTrue = false;
 333             } else if (constantValue == 1) {
 334                 successIsTrue = true;
 335             } else {
 336                 return null;
 337             }
 338             return builder -> {
 339                 LIRKind kind = getLirKind(cas);
 340                 LabelRef trueLabel = getLIRBlock(root.trueSuccessor());
 341                 LabelRef falseLabel = getLIRBlock(root.falseSuccessor());
 342                 double trueLabelProbability = root.probability(root.trueSuccessor());
 343                 Value expectedValue = operand(cas.getExpectedValue());
 344                 Value newValue = operand(cas.getNewValue());
 345                 AMD64AddressValue address = (AMD64AddressValue) operand(cas.getAddress());
 346                 Condition condition = successIsTrue ? Condition.EQ : Condition.NE;
 347                 getLIRGeneratorTool().emitCompareAndSwapBranch(kind, address, expectedValue, newValue, condition, trueLabel, falseLabel, trueLabelProbability);
 348                 return null;
 349             };
 350         }
 351         return null;
 352     }
 353 
 354     @MatchRule("(If (ObjectEquals=compare value FloatingRead=access))")
 355     public ComplexMatchResult ifLogicCas(IfNode root, CompareNode compare, ValueNode value, LIRLowerableAccess access) {
 356         return emitCompareBranchMemory(root, compare, value, access);
 357     }
 358 
 359     @MatchRule("(Or (LeftShift=lshift value Constant) (UnsignedRightShift=rshift value Constant))")
 360     public ComplexMatchResult rotateLeftConstant(LeftShiftNode lshift, UnsignedRightShiftNode rshift) {
 361         if ((lshift.getShiftAmountMask() & (lshift.getY().asJavaConstant().asInt() + rshift.getY().asJavaConstant().asInt())) == 0) {
 362             return builder -> getArithmeticLIRGenerator().emitRol(operand(lshift.getX()), operand(lshift.getY()));
 363         }
 364         return null;
 365     }
 366 
 367     @MatchRule("(Or (LeftShift value (Sub Constant=delta shiftAmount)) (UnsignedRightShift value shiftAmount))")
 368     public ComplexMatchResult rotateRightVariable(ValueNode value, ConstantNode delta, ValueNode shiftAmount) {
 369         if (delta.asJavaConstant().asLong() == 0 || delta.asJavaConstant().asLong() == 32) {
 370             return builder -> getArithmeticLIRGenerator().emitRor(operand(value), operand(shiftAmount));
 371         }
 372         return null;
 373     }
 374 
 375     @MatchRule("(Or (LeftShift value shiftAmount) (UnsignedRightShift value (Sub Constant=delta shiftAmount)))")
 376     public ComplexMatchResult rotateLeftVariable(ValueNode value, ValueNode shiftAmount, ConstantNode delta) {
 377         if (delta.asJavaConstant().asLong() == 0 || delta.asJavaConstant().asLong() == 32) {
 378             return builder -> getArithmeticLIRGenerator().emitRol(operand(value), operand(shiftAmount));
 379         }
 380         return null;
 381     }
 382 
 383     private ComplexMatchResult binaryRead(AMD64RMOp op, OperandSize size, ValueNode value, LIRLowerableAccess access) {
 384         return builder -> getArithmeticLIRGenerator().emitBinaryMemory(op, size, getLIRGeneratorTool().asAllocatable(operand(value)), (AMD64AddressValue) operand(access.getAddress()),
 385                         getState(access));
 386     }
 387 
 388     @MatchRule("(Add value Read=access)")
 389     @MatchRule("(Add value FloatingRead=access)")
 390     public ComplexMatchResult addMemory(ValueNode value, LIRLowerableAccess access) {
 391         OperandSize size = getMemorySize(access);
 392         if (size.isXmmType()) {
 393             return binaryRead(SSEOp.ADD, size, value, access);
 394         } else {
 395             return binaryRead(ADD.getRMOpcode(size), size, value, access);
 396         }
 397     }
 398 
 399     @MatchRule("(Sub value Read=access)")
 400     @MatchRule("(Sub value FloatingRead=access)")
 401     public ComplexMatchResult subMemory(ValueNode value, LIRLowerableAccess access) {
 402         OperandSize size = getMemorySize(access);
 403         if (size.isXmmType()) {
 404             return binaryRead(SSEOp.SUB, size, value, access);
 405         } else {
 406             return binaryRead(SUB.getRMOpcode(size), size, value, access);
 407         }
 408     }
 409 
 410     @MatchRule("(Mul value Read=access)")
 411     @MatchRule("(Mul value FloatingRead=access)")
 412     public ComplexMatchResult mulMemory(ValueNode value, LIRLowerableAccess access) {
 413         OperandSize size = getMemorySize(access);
 414         if (size.isXmmType()) {
 415             return binaryRead(SSEOp.MUL, size, value, access);
 416         } else {
 417             return binaryRead(AMD64RMOp.IMUL, size, value, access);
 418         }
 419     }
 420 
 421     @MatchRule("(And value Read=access)")
 422     @MatchRule("(And value FloatingRead=access)")
 423     public ComplexMatchResult andMemory(ValueNode value, LIRLowerableAccess access) {
 424         OperandSize size = getMemorySize(access);
 425         if (size.isXmmType()) {
 426             return null;
 427         } else {
 428             return binaryRead(AND.getRMOpcode(size), size, value, access);
 429         }
 430     }
 431 
 432     @MatchRule("(Or value Read=access)")
 433     @MatchRule("(Or value FloatingRead=access)")
 434     public ComplexMatchResult orMemory(ValueNode value, LIRLowerableAccess access) {
 435         OperandSize size = getMemorySize(access);
 436         if (size.isXmmType()) {
 437             return null;
 438         } else {
 439             return binaryRead(OR.getRMOpcode(size), size, value, access);
 440         }
 441     }
 442 
 443     @MatchRule("(Xor value Read=access)")
 444     @MatchRule("(Xor value FloatingRead=access)")
 445     public ComplexMatchResult xorMemory(ValueNode value, LIRLowerableAccess access) {
 446         OperandSize size = getMemorySize(access);
 447         if (size.isXmmType()) {
 448             return null;
 449         } else {
 450             return binaryRead(XOR.getRMOpcode(size), size, value, access);
 451         }
 452     }
 453 
 454     @MatchRule("(Write object Narrow=narrow)")
 455     public ComplexMatchResult writeNarrow(WriteNode root, NarrowNode narrow) {
 456         return builder -> {
 457             LIRKind writeKind = getLIRGeneratorTool().getLIRKind(root.value().stamp(NodeView.DEFAULT));
 458             getArithmeticLIRGenerator().emitStore(writeKind, operand(root.getAddress()), operand(narrow.getValue()), state(root));
 459             return null;
 460         };
 461     }
 462 
 463     @MatchRule("(SignExtend Read=access)")
 464     @MatchRule("(SignExtend FloatingRead=access)")
 465     public ComplexMatchResult signExtend(SignExtendNode root, LIRLowerableAccess access) {
 466         return emitSignExtendMemory(access, root.getInputBits(), root.getResultBits(), null);
 467     }
 468 
 469     @MatchRule("(ZeroExtend Read=access)")
 470     @MatchRule("(ZeroExtend FloatingRead=access)")
 471     public ComplexMatchResult zeroExtend(ZeroExtendNode root, LIRLowerableAccess access) {
 472         AMD64Kind memoryKind = getMemoryKind(access);
 473         return builder -> getArithmeticLIRGenerator().emitZeroExtendMemory(memoryKind, root.getResultBits(), (AMD64AddressValue) operand(access.getAddress()), getState(access));
 474     }
 475 
 476     @MatchRule("(Narrow Read=access)")
 477     @MatchRule("(Narrow FloatingRead=access)")
 478     public ComplexMatchResult narrowRead(NarrowNode root, LIRLowerableAccess access) {
 479         return new ComplexMatchResult() {
 480             @Override
 481             public Value evaluate(NodeLIRBuilder builder) {
 482                 AMD64AddressValue address = (AMD64AddressValue) operand(access.getAddress());
 483                 LIRKind addressKind = LIRKind.combineDerived(getLIRGeneratorTool().getLIRKind(root.asNode().stamp(NodeView.DEFAULT)),
 484                                 address.getBase(), address.getIndex());
 485                 AMD64AddressValue newAddress = address.withKind(addressKind);
 486                 LIRKind readKind = getLIRGeneratorTool().getLIRKind(root.stamp(NodeView.DEFAULT));
 487                 return getArithmeticLIRGenerator().emitZeroExtendMemory((AMD64Kind) readKind.getPlatformKind(),
 488                                 root.getResultBits(), newAddress, getState(access));
 489             }
 490         };
 491     }
 492 
 493     @MatchRule("(SignExtend (Narrow=narrow Read=access))")
 494     @MatchRule("(SignExtend (Narrow=narrow FloatingRead=access))")
 495     public ComplexMatchResult signExtendNarrowRead(SignExtendNode root, NarrowNode narrow, LIRLowerableAccess access) {
 496         LIRKind kind = getLIRGeneratorTool().getLIRKind(narrow.stamp(NodeView.DEFAULT));
 497         return emitSignExtendMemory(access, narrow.getResultBits(), root.getResultBits(), kind);
 498     }
 499 
 500     @MatchRule("(FloatConvert Read=access)")
 501     @MatchRule("(FloatConvert FloatingRead=access)")
 502     public ComplexMatchResult floatConvert(FloatConvertNode root, LIRLowerableAccess access) {
 503         switch (root.getFloatConvert()) {
 504             case D2F:
 505                 return emitConvertMemoryOp(AMD64Kind.SINGLE, SSEOp.CVTSD2SS, SD, access);
 506             case D2I:
 507                 return emitConvertMemoryOp(AMD64Kind.DWORD, SSEOp.CVTTSD2SI, DWORD, access);
 508             case D2L:
 509                 return emitConvertMemoryOp(AMD64Kind.QWORD, SSEOp.CVTTSD2SI, QWORD, access);
 510             case F2D:
 511                 return emitConvertMemoryOp(AMD64Kind.DOUBLE, SSEOp.CVTSS2SD, SS, access);
 512             case F2I:
 513                 return emitConvertMemoryOp(AMD64Kind.DWORD, SSEOp.CVTTSS2SI, DWORD, access);
 514             case F2L:
 515                 return emitConvertMemoryOp(AMD64Kind.QWORD, SSEOp.CVTTSS2SI, QWORD, access);
 516             case I2D:
 517                 return emitConvertMemoryOp(AMD64Kind.DOUBLE, SSEOp.CVTSI2SD, DWORD, access);
 518             case I2F:
 519                 return emitConvertMemoryOp(AMD64Kind.SINGLE, SSEOp.CVTSI2SS, DWORD, access);
 520             case L2D:
 521                 return emitConvertMemoryOp(AMD64Kind.DOUBLE, SSEOp.CVTSI2SD, QWORD, access);
 522             case L2F:
 523                 return emitConvertMemoryOp(AMD64Kind.SINGLE, SSEOp.CVTSI2SS, QWORD, access);
 524             default:
 525                 throw GraalError.shouldNotReachHere();
 526         }
 527     }
 528 
 529     @MatchRule("(Reinterpret Read=access)")
 530     @MatchRule("(Reinterpret FloatingRead=access)")
 531     public ComplexMatchResult reinterpret(ReinterpretNode root, LIRLowerableAccess access) {
 532         return builder -> {
 533             LIRKind kind = getLIRGeneratorTool().getLIRKind(root.stamp(NodeView.DEFAULT));
 534             return emitReinterpretMemory(kind, access);
 535         };
 536 
 537     }
 538 
 539     @MatchRule("(Write object Reinterpret=reinterpret)")
 540     public ComplexMatchResult writeReinterpret(WriteNode root, ReinterpretNode reinterpret) {
 541         return builder -> {
 542             LIRKind kind = getLIRGeneratorTool().getLIRKind(reinterpret.getValue().stamp(NodeView.DEFAULT));
 543             AllocatableValue value = getLIRGeneratorTool().asAllocatable(operand(reinterpret.getValue()));
 544 
 545             AMD64AddressValue address = (AMD64AddressValue) operand(root.getAddress());
 546             getArithmeticLIRGenerator().emitStore((AMD64Kind) kind.getPlatformKind(), address, value, getState(root));
 547             return null;
 548         };
 549     }
 550 
 551     @Override
 552     public AMD64LIRGenerator getLIRGeneratorTool() {
 553         return (AMD64LIRGenerator) gen;
 554     }
 555 
 556     protected AMD64ArithmeticLIRGenerator getArithmeticLIRGenerator() {
 557         return (AMD64ArithmeticLIRGenerator) getLIRGeneratorTool().getArithmetic();
 558     }
 559 }