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 }