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