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