1 /*
2  * Copyright (c) 2009, 2019, 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 jdk.vm.ci.code.ValueUtil.asRegister;
29 import static jdk.vm.ci.code.ValueUtil.isAllocatableValue;
30 import static jdk.vm.ci.code.ValueUtil.isRegister;
31 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.CMP;
32 import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize.DWORD;
33 import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize.PD;
34 import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize.PS;
35 import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize.QWORD;
36 import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
37 import static org.graalvm.compiler.lir.LIRValueUtil.asConstant;
38 import static org.graalvm.compiler.lir.LIRValueUtil.asConstantValue;
39 import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant;
40 import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue;
41 import static org.graalvm.compiler.lir.LIRValueUtil.isIntConstant;
42 import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
43 
44 import java.util.Optional;
45 
46 import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic;
47 import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MIOp;
48 import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp;
49 import org.graalvm.compiler.asm.amd64.AMD64Assembler.ConditionFlag;
50 import org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize;
51 import org.graalvm.compiler.asm.amd64.AMD64Assembler.SSEOp;
52 import org.graalvm.compiler.core.common.LIRKind;
53 import org.graalvm.compiler.core.common.NumUtil;
54 import org.graalvm.compiler.core.common.calc.Condition;
55 import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
56 import org.graalvm.compiler.core.common.spi.LIRKindTool;
57 import org.graalvm.compiler.debug.GraalError;
58 import org.graalvm.compiler.lir.ConstantValue;
59 import org.graalvm.compiler.lir.LIRFrameState;
60 import org.graalvm.compiler.lir.LIRInstruction;
61 import org.graalvm.compiler.lir.LIRValueUtil;
62 import org.graalvm.compiler.lir.LabelRef;
63 import org.graalvm.compiler.lir.StandardOp.JumpOp;
64 import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp;
65 import org.graalvm.compiler.lir.SwitchStrategy;
66 import org.graalvm.compiler.lir.Variable;
67 import org.graalvm.compiler.lir.amd64.AMD64AddressValue;
68 import org.graalvm.compiler.lir.amd64.AMD64ArithmeticLIRGeneratorTool;
69 import org.graalvm.compiler.lir.amd64.AMD64ArrayCompareToOp;
70 import org.graalvm.compiler.lir.amd64.AMD64ArrayEqualsOp;
71 import org.graalvm.compiler.lir.amd64.AMD64ArrayIndexOfOp;
72 import org.graalvm.compiler.lir.amd64.AMD64Binary;
73 import org.graalvm.compiler.lir.amd64.AMD64BinaryConsumer;
74 import org.graalvm.compiler.lir.amd64.AMD64ByteSwapOp;
75 import org.graalvm.compiler.lir.amd64.AMD64Call;
76 import org.graalvm.compiler.lir.amd64.AMD64ControlFlow;
77 import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.BranchOp;
78 import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.CondMoveOp;
79 import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.CondSetOp;
80 import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.FloatBranchOp;
81 import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.FloatCondMoveOp;
82 import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.FloatCondSetOp;
83 import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.ReturnOp;
84 import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.StrategySwitchOp;
85 import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.TableSwitchOp;
86 import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.HashTableSwitchOp;
87 import org.graalvm.compiler.lir.amd64.AMD64LFenceOp;
88 import org.graalvm.compiler.lir.amd64.AMD64Move;
89 import org.graalvm.compiler.lir.amd64.AMD64Move.CompareAndSwapOp;
90 import org.graalvm.compiler.lir.amd64.AMD64Move.MembarOp;
91 import org.graalvm.compiler.lir.amd64.AMD64Move.StackLeaOp;
92 import org.graalvm.compiler.lir.amd64.AMD64PauseOp;
93 import org.graalvm.compiler.lir.amd64.AMD64StringLatin1InflateOp;
94 import org.graalvm.compiler.lir.amd64.AMD64StringUTF16CompressOp;
95 import org.graalvm.compiler.lir.amd64.AMD64ZapRegistersOp;
96 import org.graalvm.compiler.lir.amd64.AMD64ZapStackOp;
97 import org.graalvm.compiler.lir.gen.LIRGenerationResult;
98 import org.graalvm.compiler.lir.gen.LIRGenerator;
99 import org.graalvm.compiler.lir.hashing.Hasher;
100 import org.graalvm.compiler.phases.util.Providers;
101 
102 import jdk.vm.ci.amd64.AMD64;
103 import jdk.vm.ci.amd64.AMD64Kind;
104 import jdk.vm.ci.code.CallingConvention;
105 import jdk.vm.ci.code.Register;
106 import jdk.vm.ci.code.RegisterValue;
107 import jdk.vm.ci.code.StackSlot;
108 import jdk.vm.ci.meta.AllocatableValue;
109 import jdk.vm.ci.meta.JavaConstant;
110 import jdk.vm.ci.meta.JavaKind;
111 import jdk.vm.ci.meta.PlatformKind;
112 import jdk.vm.ci.meta.VMConstant;
113 import jdk.vm.ci.meta.Value;
114 import jdk.vm.ci.meta.ValueKind;
115 
116 /**
117  * This class implements the AMD64 specific portion of the LIR generator.
118  */
119 public abstract class AMD64LIRGenerator extends LIRGenerator {
120 
AMD64LIRGenerator(LIRKindTool lirKindTool, AMD64ArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, Providers providers, LIRGenerationResult lirGenRes)121     public AMD64LIRGenerator(LIRKindTool lirKindTool, AMD64ArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, Providers providers, LIRGenerationResult lirGenRes) {
122         super(lirKindTool, arithmeticLIRGen, moveFactory, providers, lirGenRes);
123     }
124 
125     /**
126      * Checks whether the supplied constant can be used without loading it into a register for store
127      * operations, i.e., on the right hand side of a memory access.
128      *
129      * @param c The constant to check.
130      * @return True if the constant can be used directly, false if the constant needs to be in a
131      *         register.
132      */
canStoreConstant(JavaConstant c)133     protected static final boolean canStoreConstant(JavaConstant c) {
134         // there is no immediate move of 64-bit constants on Intel
135         switch (c.getJavaKind()) {
136             case Long:
137                 return NumUtil.isInt(c.asLong());
138             case Double:
139                 return false;
140             case Object:
141                 return c.isNull();
142             default:
143                 return true;
144         }
145     }
146 
147     @Override
zapValueForKind(PlatformKind kind)148     protected JavaConstant zapValueForKind(PlatformKind kind) {
149         long dead = 0xDEADDEADDEADDEADL;
150         switch ((AMD64Kind) kind) {
151             case BYTE:
152                 return JavaConstant.forByte((byte) dead);
153             case WORD:
154                 return JavaConstant.forShort((short) dead);
155             case DWORD:
156                 return JavaConstant.forInt((int) dead);
157             case QWORD:
158                 return JavaConstant.forLong(dead);
159             case SINGLE:
160                 return JavaConstant.forFloat(Float.intBitsToFloat((int) dead));
161             default:
162                 // we don't support vector types, so just zap with double for all of them
163                 return JavaConstant.forDouble(Double.longBitsToDouble(dead));
164         }
165     }
166 
asAddressValue(Value address)167     public AMD64AddressValue asAddressValue(Value address) {
168         if (address instanceof AMD64AddressValue) {
169             return (AMD64AddressValue) address;
170         } else {
171             if (address instanceof JavaConstant) {
172                 long displacement = ((JavaConstant) address).asLong();
173                 if (NumUtil.isInt(displacement)) {
174                     return new AMD64AddressValue(address.getValueKind(), Value.ILLEGAL, (int) displacement);
175                 }
176             }
177             return new AMD64AddressValue(address.getValueKind(), asAllocatable(address), 0);
178         }
179     }
180 
181     @Override
emitAddress(AllocatableValue stackslot)182     public Variable emitAddress(AllocatableValue stackslot) {
183         Variable result = newVariable(LIRKind.value(target().arch.getWordKind()));
184         append(new StackLeaOp(result, stackslot));
185         return result;
186     }
187 
188     /**
189      * The AMD64 backend only uses DWORD and QWORD values in registers because of a performance
190      * penalty when accessing WORD or BYTE registers. This function converts small integer kinds to
191      * DWORD.
192      */
193     @Override
toRegisterKind(K kind)194     public <K extends ValueKind<K>> K toRegisterKind(K kind) {
195         switch ((AMD64Kind) kind.getPlatformKind()) {
196             case BYTE:
197             case WORD:
198                 return kind.changeType(AMD64Kind.DWORD);
199             default:
200                 return kind;
201         }
202     }
203 
asAllocatable(Value value, ValueKind<?> kind)204     private AllocatableValue asAllocatable(Value value, ValueKind<?> kind) {
205         if (value.getValueKind().equals(kind)) {
206             return asAllocatable(value);
207         } else if (isRegister(value)) {
208             return asRegister(value).asValue(kind);
209         } else if (isConstantValue(value)) {
210             return emitLoadConstant(kind, asConstant(value));
211         } else {
212             Variable variable = newVariable(kind);
213             emitMove(variable, value);
214             return variable;
215         }
216     }
217 
emitCompareAndSwap(boolean isLogic, LIRKind accessKind, Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue)218     private Value emitCompareAndSwap(boolean isLogic, LIRKind accessKind, Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
219         ValueKind<?> kind = newValue.getValueKind();
220         assert kind.equals(expectedValue.getValueKind());
221 
222         AMD64AddressValue addressValue = asAddressValue(address);
223         LIRKind integralAccessKind = accessKind;
224         Value reinterpretedExpectedValue = expectedValue;
225         Value reinterpretedNewValue = newValue;
226         boolean isXmm = ((AMD64Kind) accessKind.getPlatformKind()).isXMM();
227         if (isXmm) {
228             if (accessKind.getPlatformKind().equals(AMD64Kind.SINGLE)) {
229                 integralAccessKind = LIRKind.fromJavaKind(target().arch, JavaKind.Int);
230             } else {
231                 integralAccessKind = LIRKind.fromJavaKind(target().arch, JavaKind.Long);
232             }
233             reinterpretedExpectedValue = arithmeticLIRGen.emitReinterpret(integralAccessKind, expectedValue);
234             reinterpretedNewValue = arithmeticLIRGen.emitReinterpret(integralAccessKind, newValue);
235         }
236         AMD64Kind memKind = (AMD64Kind) integralAccessKind.getPlatformKind();
237         RegisterValue aRes = AMD64.rax.asValue(integralAccessKind);
238         AllocatableValue allocatableNewValue = asAllocatable(reinterpretedNewValue, integralAccessKind);
239         emitMove(aRes, reinterpretedExpectedValue);
240         append(new CompareAndSwapOp(memKind, aRes, addressValue, aRes, allocatableNewValue));
241 
242         if (isLogic) {
243             assert trueValue.getValueKind().equals(falseValue.getValueKind());
244             Variable result = newVariable(trueValue.getValueKind());
245             append(new CondMoveOp(result, Condition.EQ, asAllocatable(trueValue), falseValue));
246             return result;
247         } else {
248             if (isXmm) {
249                 return arithmeticLIRGen.emitReinterpret(accessKind, aRes);
250             } else {
251                 Variable result = newVariable(kind);
252                 emitMove(result, aRes);
253                 return result;
254             }
255         }
256     }
257 
258     @Override
emitLogicCompareAndSwap(LIRKind accessKind, Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue)259     public Variable emitLogicCompareAndSwap(LIRKind accessKind, Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
260         return (Variable) emitCompareAndSwap(true, accessKind, address, expectedValue, newValue, trueValue, falseValue);
261     }
262 
263     @Override
emitValueCompareAndSwap(LIRKind accessKind, Value address, Value expectedValue, Value newValue)264     public Value emitValueCompareAndSwap(LIRKind accessKind, Value address, Value expectedValue, Value newValue) {
265         return emitCompareAndSwap(false, accessKind, address, expectedValue, newValue, null, null);
266     }
267 
emitCompareAndSwapBranch(ValueKind<?> kind, AMD64AddressValue address, Value expectedValue, Value newValue, Condition condition, LabelRef trueLabel, LabelRef falseLabel, double trueLabelProbability)268     public void emitCompareAndSwapBranch(ValueKind<?> kind, AMD64AddressValue address, Value expectedValue, Value newValue, Condition condition, LabelRef trueLabel, LabelRef falseLabel,
269                     double trueLabelProbability) {
270         assert kind.getPlatformKind().getSizeInBytes() <= expectedValue.getValueKind().getPlatformKind().getSizeInBytes();
271         assert kind.getPlatformKind().getSizeInBytes() <= newValue.getValueKind().getPlatformKind().getSizeInBytes();
272         assert condition == Condition.EQ || condition == Condition.NE;
273         AMD64Kind memKind = (AMD64Kind) kind.getPlatformKind();
274         RegisterValue raxValue = AMD64.rax.asValue(kind);
275         emitMove(raxValue, expectedValue);
276         append(new CompareAndSwapOp(memKind, raxValue, address, raxValue, asAllocatable(newValue)));
277         append(new BranchOp(condition, trueLabel, falseLabel, trueLabelProbability));
278     }
279 
280     @Override
emitAtomicReadAndAdd(Value address, ValueKind<?> kind, Value delta)281     public Value emitAtomicReadAndAdd(Value address, ValueKind<?> kind, Value delta) {
282         Variable result = newVariable(kind);
283         AMD64AddressValue addressValue = asAddressValue(address);
284         append(new AMD64Move.AtomicReadAndAddOp((AMD64Kind) kind.getPlatformKind(), result, addressValue, asAllocatable(delta)));
285         return result;
286     }
287 
288     @Override
emitAtomicReadAndWrite(Value address, ValueKind<?> kind, Value newValue)289     public Value emitAtomicReadAndWrite(Value address, ValueKind<?> kind, Value newValue) {
290         Variable result = newVariable(kind);
291         AMD64AddressValue addressValue = asAddressValue(address);
292         append(new AMD64Move.AtomicReadAndWriteOp((AMD64Kind) kind.getPlatformKind(), result, addressValue, asAllocatable(newValue)));
293         return result;
294     }
295 
296     @Override
emitNullCheck(Value address, LIRFrameState state)297     public void emitNullCheck(Value address, LIRFrameState state) {
298         append(new AMD64Move.NullCheckOp(asAddressValue(address), state));
299     }
300 
301     @Override
emitJump(LabelRef label)302     public void emitJump(LabelRef label) {
303         assert label != null;
304         append(new JumpOp(label));
305     }
306 
307     @Override
emitCompareBranch(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueLabel, LabelRef falseLabel, double trueLabelProbability)308     public void emitCompareBranch(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueLabel, LabelRef falseLabel, double trueLabelProbability) {
309         Condition finalCondition = emitCompare(cmpKind, left, right, cond);
310         if (cmpKind == AMD64Kind.SINGLE || cmpKind == AMD64Kind.DOUBLE) {
311             append(new FloatBranchOp(finalCondition, unorderedIsTrue, trueLabel, falseLabel, trueLabelProbability));
312         } else {
313             append(new BranchOp(finalCondition, trueLabel, falseLabel, trueLabelProbability));
314         }
315     }
316 
emitCompareBranchMemory(AMD64Kind cmpKind, Value left, AMD64AddressValue right, LIRFrameState state, Condition cond, boolean unorderedIsTrue, LabelRef trueLabel, LabelRef falseLabel, double trueLabelProbability)317     public void emitCompareBranchMemory(AMD64Kind cmpKind, Value left, AMD64AddressValue right, LIRFrameState state, Condition cond, boolean unorderedIsTrue, LabelRef trueLabel, LabelRef falseLabel,
318                     double trueLabelProbability) {
319         boolean mirrored = emitCompareMemory(cmpKind, left, right, state);
320         Condition finalCondition = mirrored ? cond.mirror() : cond;
321         if (cmpKind.isXMM()) {
322             append(new FloatBranchOp(finalCondition, unorderedIsTrue, trueLabel, falseLabel, trueLabelProbability));
323         } else {
324             append(new BranchOp(finalCondition, trueLabel, falseLabel, trueLabelProbability));
325         }
326     }
327 
328     @Override
emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, LIRKind cmpLIRKind, double overflowProbability)329     public void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, LIRKind cmpLIRKind, double overflowProbability) {
330         append(new BranchOp(ConditionFlag.Overflow, overflow, noOverflow, overflowProbability));
331     }
332 
333     @Override
emitIntegerTestBranch(Value left, Value right, LabelRef trueDestination, LabelRef falseDestination, double trueDestinationProbability)334     public void emitIntegerTestBranch(Value left, Value right, LabelRef trueDestination, LabelRef falseDestination, double trueDestinationProbability) {
335         emitIntegerTest(left, right);
336         append(new BranchOp(Condition.EQ, trueDestination, falseDestination, trueDestinationProbability));
337     }
338 
339     @Override
emitConditionalMove(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue)340     public Variable emitConditionalMove(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue) {
341         boolean isFloatComparison = cmpKind == AMD64Kind.SINGLE || cmpKind == AMD64Kind.DOUBLE;
342 
343         Condition finalCondition = cond;
344         Value finalTrueValue = trueValue;
345         Value finalFalseValue = falseValue;
346         if (isFloatComparison) {
347             // eliminate the parity check in case of a float comparison
348             Value finalLeft = left;
349             Value finalRight = right;
350             if (unorderedIsTrue != AMD64ControlFlow.trueOnUnordered(finalCondition)) {
351                 if (unorderedIsTrue == AMD64ControlFlow.trueOnUnordered(finalCondition.mirror())) {
352                     finalCondition = finalCondition.mirror();
353                     finalLeft = right;
354                     finalRight = left;
355                 } else if (finalCondition != Condition.EQ && finalCondition != Condition.NE) {
356                     // negating EQ and NE does not make any sense as we would need to negate
357                     // unorderedIsTrue as well (otherwise, we would no longer fulfill the Java
358                     // NaN semantics)
359                     assert unorderedIsTrue == AMD64ControlFlow.trueOnUnordered(finalCondition.negate());
360                     finalCondition = finalCondition.negate();
361                     finalTrueValue = falseValue;
362                     finalFalseValue = trueValue;
363                 }
364             }
365             emitRawCompare(cmpKind, finalLeft, finalRight);
366         } else {
367             finalCondition = emitCompare(cmpKind, left, right, cond);
368         }
369 
370         boolean isParityCheckNecessary = isFloatComparison && unorderedIsTrue != AMD64ControlFlow.trueOnUnordered(finalCondition);
371         Variable result = newVariable(finalTrueValue.getValueKind());
372         if (!isParityCheckNecessary && isIntConstant(finalTrueValue, 1) && isIntConstant(finalFalseValue, 0)) {
373             if (isFloatComparison) {
374                 append(new FloatCondSetOp(result, finalCondition));
375             } else {
376                 append(new CondSetOp(result, finalCondition));
377             }
378         } else if (!isParityCheckNecessary && isIntConstant(finalTrueValue, 0) && isIntConstant(finalFalseValue, 1)) {
379             if (isFloatComparison) {
380                 if (unorderedIsTrue == AMD64ControlFlow.trueOnUnordered(finalCondition.negate())) {
381                     append(new FloatCondSetOp(result, finalCondition.negate()));
382                 } else {
383                     append(new FloatCondSetOp(result, finalCondition));
384                     Variable negatedResult = newVariable(result.getValueKind());
385                     append(new AMD64Binary.ConstOp(AMD64BinaryArithmetic.XOR, OperandSize.get(result.getPlatformKind()), negatedResult, result, 1));
386                     result = negatedResult;
387                 }
388             } else {
389                 append(new CondSetOp(result, finalCondition.negate()));
390             }
391         } else if (isFloatComparison) {
392             append(new FloatCondMoveOp(result, finalCondition, unorderedIsTrue, load(finalTrueValue), load(finalFalseValue)));
393         } else {
394             append(new CondMoveOp(result, finalCondition, load(finalTrueValue), loadNonConst(finalFalseValue)));
395         }
396         return result;
397     }
398 
399     @Override
emitIntegerTestMove(Value left, Value right, Value trueValue, Value falseValue)400     public Variable emitIntegerTestMove(Value left, Value right, Value trueValue, Value falseValue) {
401         emitIntegerTest(left, right);
402         Variable result = newVariable(trueValue.getValueKind());
403         append(new CondMoveOp(result, Condition.EQ, load(trueValue), loadNonConst(falseValue)));
404         return result;
405     }
406 
emitIntegerTest(Value a, Value b)407     private void emitIntegerTest(Value a, Value b) {
408         assert ((AMD64Kind) a.getPlatformKind()).isInteger();
409         OperandSize size = a.getPlatformKind() == AMD64Kind.QWORD ? QWORD : DWORD;
410         if (isJavaConstant(b) && NumUtil.is32bit(asJavaConstant(b).asLong())) {
411             append(new AMD64BinaryConsumer.ConstOp(AMD64MIOp.TEST, size, asAllocatable(a), (int) asJavaConstant(b).asLong()));
412         } else if (isJavaConstant(a) && NumUtil.is32bit(asJavaConstant(a).asLong())) {
413             append(new AMD64BinaryConsumer.ConstOp(AMD64MIOp.TEST, size, asAllocatable(b), (int) asJavaConstant(a).asLong()));
414         } else if (isAllocatableValue(b)) {
415             append(new AMD64BinaryConsumer.Op(AMD64RMOp.TEST, size, asAllocatable(b), asAllocatable(a)));
416         } else {
417             append(new AMD64BinaryConsumer.Op(AMD64RMOp.TEST, size, asAllocatable(a), asAllocatable(b)));
418         }
419     }
420 
421     /**
422      * This method emits the compare against memory instruction, and may reorder the operands. It
423      * returns true if it did so.
424      *
425      * @param b the right operand of the comparison
426      * @return true if the left and right operands were switched, false otherwise
427      */
emitCompareMemory(AMD64Kind cmpKind, Value a, AMD64AddressValue b, LIRFrameState state)428     private boolean emitCompareMemory(AMD64Kind cmpKind, Value a, AMD64AddressValue b, LIRFrameState state) {
429         OperandSize size;
430         switch (cmpKind) {
431             case BYTE:
432                 size = OperandSize.BYTE;
433                 break;
434             case WORD:
435                 size = OperandSize.WORD;
436                 break;
437             case DWORD:
438                 size = OperandSize.DWORD;
439                 break;
440             case QWORD:
441                 size = OperandSize.QWORD;
442                 break;
443             case SINGLE:
444                 append(new AMD64BinaryConsumer.MemoryRMOp(SSEOp.UCOMIS, PS, asAllocatable(a), b, state));
445                 return false;
446             case DOUBLE:
447                 append(new AMD64BinaryConsumer.MemoryRMOp(SSEOp.UCOMIS, PD, asAllocatable(a), b, state));
448                 return false;
449             default:
450                 throw GraalError.shouldNotReachHere("unexpected kind: " + cmpKind);
451         }
452 
453         if (isConstantValue(a)) {
454             return emitCompareMemoryConOp(size, asConstantValue(a), b, state);
455         } else {
456             return emitCompareRegMemoryOp(size, asAllocatable(a), b, state);
457         }
458     }
459 
emitCompareMemoryConOp(OperandSize size, ConstantValue a, AMD64AddressValue b, LIRFrameState state)460     protected boolean emitCompareMemoryConOp(OperandSize size, ConstantValue a, AMD64AddressValue b, LIRFrameState state) {
461         if (JavaConstant.isNull(a.getConstant())) {
462             append(new AMD64BinaryConsumer.MemoryConstOp(CMP, size, b, 0, state));
463             return true;
464         } else if (a.getConstant() instanceof VMConstant && size == DWORD) {
465             VMConstant vc = (VMConstant) a.getConstant();
466             append(new AMD64BinaryConsumer.MemoryVMConstOp(CMP.getMIOpcode(size, false), b, vc, state));
467             return true;
468         } else {
469             long value = a.getJavaConstant().asLong();
470             if (NumUtil.is32bit(value)) {
471                 append(new AMD64BinaryConsumer.MemoryConstOp(CMP, size, b, (int) value, state));
472                 return true;
473             } else {
474                 return emitCompareRegMemoryOp(size, asAllocatable(a), b, state);
475             }
476         }
477     }
478 
emitCompareRegMemoryOp(OperandSize size, AllocatableValue a, AMD64AddressValue b, LIRFrameState state)479     private boolean emitCompareRegMemoryOp(OperandSize size, AllocatableValue a, AMD64AddressValue b, LIRFrameState state) {
480         AMD64RMOp op = CMP.getRMOpcode(size);
481         append(new AMD64BinaryConsumer.MemoryRMOp(op, size, a, b, state));
482         return false;
483     }
484 
485     /**
486      * This method emits the compare instruction, and may reorder the operands. It returns true if
487      * it did so.
488      *
489      * @param a the left operand of the comparison
490      * @param b the right operand of the comparison
491      * @param cond the condition of the comparison
492      * @return true if the left and right operands were switched, false otherwise
493      */
emitCompare(PlatformKind cmpKind, Value a, Value b, Condition cond)494     private Condition emitCompare(PlatformKind cmpKind, Value a, Value b, Condition cond) {
495         if (LIRValueUtil.isVariable(b)) {
496             emitRawCompare(cmpKind, b, a);
497             return cond.mirror();
498         } else {
499             emitRawCompare(cmpKind, a, b);
500             return cond;
501         }
502     }
503 
emitRawCompare(PlatformKind cmpKind, Value left, Value right)504     private void emitRawCompare(PlatformKind cmpKind, Value left, Value right) {
505         ((AMD64ArithmeticLIRGeneratorTool) arithmeticLIRGen).emitCompareOp((AMD64Kind) cmpKind, load(left), loadNonConst(right));
506     }
507 
508     @Override
emitMembar(int barriers)509     public void emitMembar(int barriers) {
510         int necessaryBarriers = target().arch.requiredBarriers(barriers);
511         if (target().isMP && necessaryBarriers != 0) {
512             append(new MembarOp(necessaryBarriers));
513         }
514     }
515 
emitCCall(long address, CallingConvention nativeCallingConvention, Value[] args, int numberOfFloatingPointArguments)516     public abstract void emitCCall(long address, CallingConvention nativeCallingConvention, Value[] args, int numberOfFloatingPointArguments);
517 
518     @Override
emitForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info)519     protected void emitForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info) {
520         long maxOffset = linkage.getMaxCallTargetOffset();
521         if (maxOffset != (int) maxOffset && !GeneratePIC.getValue(getResult().getLIR().getOptions())) {
522             append(new AMD64Call.DirectFarForeignCallOp(linkage, result, arguments, temps, info));
523         } else {
524             append(new AMD64Call.DirectNearForeignCallOp(linkage, result, arguments, temps, info));
525         }
526     }
527 
528     @Override
emitByteSwap(Value input)529     public Variable emitByteSwap(Value input) {
530         Variable result = newVariable(LIRKind.combine(input));
531         append(new AMD64ByteSwapOp(result, input));
532         return result;
533     }
534 
535     @Override
emitArrayCompareTo(JavaKind kind1, JavaKind kind2, Value array1, Value array2, Value length1, Value length2)536     public Variable emitArrayCompareTo(JavaKind kind1, JavaKind kind2, Value array1, Value array2, Value length1, Value length2) {
537         LIRKind resultKind = LIRKind.value(AMD64Kind.DWORD);
538         RegisterValue raxRes = AMD64.rax.asValue(resultKind);
539         RegisterValue cnt1 = AMD64.rcx.asValue(length1.getValueKind());
540         RegisterValue cnt2 = AMD64.rdx.asValue(length2.getValueKind());
541         emitMove(cnt1, length1);
542         emitMove(cnt2, length2);
543         append(new AMD64ArrayCompareToOp(this, kind1, kind2, raxRes, array1, array2, cnt1, cnt2));
544         Variable result = newVariable(resultKind);
545         emitMove(result, raxRes);
546         return result;
547     }
548 
549     @Override
emitArrayEquals(JavaKind kind, Value array1, Value array2, Value length, int constantLength, boolean directPointers)550     public Variable emitArrayEquals(JavaKind kind, Value array1, Value array2, Value length, int constantLength, boolean directPointers) {
551         Variable result = newVariable(LIRKind.value(AMD64Kind.DWORD));
552         append(new AMD64ArrayEqualsOp(this, kind, kind, result, array1, array2, asAllocatable(length), constantLength, directPointers, getMaxVectorSize()));
553         return result;
554     }
555 
556     @Override
emitArrayEquals(JavaKind kind1, JavaKind kind2, Value array1, Value array2, Value length, int constantLength, boolean directPointers)557     public Variable emitArrayEquals(JavaKind kind1, JavaKind kind2, Value array1, Value array2, Value length, int constantLength, boolean directPointers) {
558         Variable result = newVariable(LIRKind.value(AMD64Kind.DWORD));
559         append(new AMD64ArrayEqualsOp(this, kind1, kind2, result, array1, array2, asAllocatable(length), constantLength, directPointers, getMaxVectorSize()));
560         return result;
561     }
562 
563     /**
564      * Return a conservative estimate of the page size for use by the String.indexOf intrinsic.
565      */
getVMPageSize()566     protected int getVMPageSize() {
567         return 4096;
568     }
569 
570     /**
571      * Return the maximum size of vector registers used in SSE/AVX instructions.
572      */
getMaxVectorSize()573     protected int getMaxVectorSize() {
574         // default for "unlimited"
575         return -1;
576     }
577 
578     @Override
emitArrayIndexOf(JavaKind kind, boolean findTwoConsecutive, Value arrayPointer, Value arrayLength, Value... searchValues)579     public Variable emitArrayIndexOf(JavaKind kind, boolean findTwoConsecutive, Value arrayPointer, Value arrayLength, Value... searchValues) {
580         Variable result = newVariable(LIRKind.value(AMD64Kind.QWORD));
581         Value[] allocatableSearchValues = new Value[searchValues.length];
582         for (int i = 0; i < searchValues.length; i++) {
583             allocatableSearchValues[i] = asAllocatable(searchValues[i]);
584         }
585         append(new AMD64ArrayIndexOfOp(kind, findTwoConsecutive, getVMPageSize(), getMaxVectorSize(), this, result, asAllocatable(arrayPointer), asAllocatable(arrayLength), allocatableSearchValues));
586         return result;
587     }
588 
589     @Override
emitStringLatin1Inflate(Value src, Value dst, Value len)590     public void emitStringLatin1Inflate(Value src, Value dst, Value len) {
591         RegisterValue rsrc = AMD64.rsi.asValue(src.getValueKind());
592         RegisterValue rdst = AMD64.rdi.asValue(dst.getValueKind());
593         RegisterValue rlen = AMD64.rdx.asValue(len.getValueKind());
594 
595         emitMove(rsrc, src);
596         emitMove(rdst, dst);
597         emitMove(rlen, len);
598 
599         append(new AMD64StringLatin1InflateOp(this, rsrc, rdst, rlen));
600     }
601 
602     @Override
emitStringUTF16Compress(Value src, Value dst, Value len)603     public Variable emitStringUTF16Compress(Value src, Value dst, Value len) {
604         RegisterValue rsrc = AMD64.rsi.asValue(src.getValueKind());
605         RegisterValue rdst = AMD64.rdi.asValue(dst.getValueKind());
606         RegisterValue rlen = AMD64.rdx.asValue(len.getValueKind());
607 
608         emitMove(rsrc, src);
609         emitMove(rdst, dst);
610         emitMove(rlen, len);
611 
612         LIRKind reskind = LIRKind.value(AMD64Kind.DWORD);
613         RegisterValue rres = AMD64.rax.asValue(reskind);
614 
615         append(new AMD64StringUTF16CompressOp(this, rres, rsrc, rdst, rlen));
616 
617         Variable res = newVariable(reskind);
618         emitMove(res, rres);
619         return res;
620     }
621 
622     @Override
emitReturn(JavaKind kind, Value input)623     public void emitReturn(JavaKind kind, Value input) {
624         AllocatableValue operand = Value.ILLEGAL;
625         if (input != null) {
626             operand = resultOperandFor(kind, input.getValueKind());
627             emitMove(operand, input);
628         }
629         append(new ReturnOp(operand));
630     }
631 
createStrategySwitchOp(SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Variable key, AllocatableValue temp)632     protected StrategySwitchOp createStrategySwitchOp(SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Variable key, AllocatableValue temp) {
633         return new StrategySwitchOp(strategy, keyTargets, defaultTarget, key, temp);
634     }
635 
636     @Override
emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget)637     public void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) {
638         // a temp is needed for loading object constants
639         boolean needsTemp = !LIRKind.isValue(key);
640         append(createStrategySwitchOp(strategy, keyTargets, defaultTarget, key, needsTemp ? newVariable(key.getValueKind()) : Value.ILLEGAL));
641     }
642 
643     @Override
emitTableSwitch(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value key)644     protected void emitTableSwitch(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value key) {
645         append(new TableSwitchOp(lowKey, defaultTarget, targets, key, newVariable(LIRKind.value(target().arch.getWordKind())), newVariable(key.getValueKind())));
646     }
647 
648     @Override
hasherFor(JavaConstant[] keyConstants, double minDensity)649     protected Optional<Hasher> hasherFor(JavaConstant[] keyConstants, double minDensity) {
650         return Hasher.forKeys(keyConstants, minDensity);
651     }
652 
653     @Override
emitHashTableSwitch(Hasher hasher, JavaConstant[] keys, LabelRef defaultTarget, LabelRef[] targets, Value value)654     protected void emitHashTableSwitch(Hasher hasher, JavaConstant[] keys, LabelRef defaultTarget, LabelRef[] targets, Value value) {
655         Value index = hasher.hash(value, arithmeticLIRGen);
656         Variable scratch = newVariable(LIRKind.value(target().arch.getWordKind()));
657         Variable entryScratch = newVariable(LIRKind.value(target().arch.getWordKind()));
658         append(new HashTableSwitchOp(keys, defaultTarget, targets, value, index, scratch, entryScratch));
659     }
660 
661     @Override
emitPause()662     public void emitPause() {
663         append(new AMD64PauseOp());
664     }
665 
666     @Override
createZapRegisters(Register[] zappedRegisters, JavaConstant[] zapValues)667     public SaveRegistersOp createZapRegisters(Register[] zappedRegisters, JavaConstant[] zapValues) {
668         return new AMD64ZapRegistersOp(zappedRegisters, zapValues);
669     }
670 
671     @Override
createZapArgumentSpace(StackSlot[] zappedStack, JavaConstant[] zapValues)672     public LIRInstruction createZapArgumentSpace(StackSlot[] zappedStack, JavaConstant[] zapValues) {
673         return new AMD64ZapStackOp(zappedStack, zapValues);
674     }
675 
676     @Override
emitSpeculationFence()677     public void emitSpeculationFence() {
678         append(new AMD64LFenceOp());
679     }
680 }
681