1 /*
2  * Copyright (c) 2015, 2018, 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 package org.graalvm.compiler.lir.amd64;
26 
27 import static jdk.vm.ci.code.ValueUtil.asRegister;
28 import static jdk.vm.ci.code.ValueUtil.isRegister;
29 import static jdk.vm.ci.code.ValueUtil.isStackSlot;
30 import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize.DWORD;
31 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.COMPOSITE;
32 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
33 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
34 
35 import org.graalvm.compiler.asm.amd64.AMD64Address;
36 import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic;
37 import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MIOp;
38 import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MROp;
39 import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp;
40 import org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize;
41 import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
42 import org.graalvm.compiler.core.common.NumUtil;
43 import org.graalvm.compiler.lir.LIRFrameState;
44 import org.graalvm.compiler.lir.LIRInstructionClass;
45 import org.graalvm.compiler.lir.Opcode;
46 import org.graalvm.compiler.lir.StandardOp.ImplicitNullCheck;
47 import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
48 
49 import jdk.vm.ci.code.site.DataSectionReference;
50 import jdk.vm.ci.meta.AllocatableValue;
51 import jdk.vm.ci.meta.Constant;
52 import jdk.vm.ci.meta.VMConstant;
53 import jdk.vm.ci.meta.Value;
54 
55 /**
56  * AMD64 LIR instructions that have two input operands, but no output operand.
57  */
58 public class AMD64BinaryConsumer {
59 
60     /**
61      * Instruction that has two {@link AllocatableValue} operands.
62      */
63     public static class Op extends AMD64LIRInstruction {
64         public static final LIRInstructionClass<Op> TYPE = LIRInstructionClass.create(Op.class);
65 
66         @Opcode private final AMD64RMOp opcode;
67         private final OperandSize size;
68 
69         @Use({REG}) protected AllocatableValue x;
70         @Use({REG, STACK}) protected AllocatableValue y;
71 
Op(AMD64RMOp opcode, OperandSize size, AllocatableValue x, AllocatableValue y)72         public Op(AMD64RMOp opcode, OperandSize size, AllocatableValue x, AllocatableValue y) {
73             super(TYPE);
74             this.opcode = opcode;
75             this.size = size;
76 
77             this.x = x;
78             this.y = y;
79         }
80 
81         @Override
emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm)82         public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
83             if (isRegister(y)) {
84                 opcode.emit(masm, size, asRegister(x), asRegister(y));
85             } else {
86                 assert isStackSlot(y);
87                 opcode.emit(masm, size, asRegister(x), (AMD64Address) crb.asAddress(y));
88             }
89         }
90     }
91 
92     /**
93      * Instruction that has one {@link AllocatableValue} operand and one 32-bit immediate operand.
94      */
95     public static class ConstOp extends AMD64LIRInstruction {
96         public static final LIRInstructionClass<ConstOp> TYPE = LIRInstructionClass.create(ConstOp.class);
97 
98         @Opcode private final AMD64MIOp opcode;
99         private final OperandSize size;
100 
101         @Use({REG, STACK}) protected AllocatableValue x;
102         private final int y;
103 
ConstOp(AMD64BinaryArithmetic opcode, OperandSize size, AllocatableValue x, int y)104         public ConstOp(AMD64BinaryArithmetic opcode, OperandSize size, AllocatableValue x, int y) {
105             this(opcode.getMIOpcode(size, NumUtil.isByte(y)), size, x, y);
106         }
107 
ConstOp(AMD64MIOp opcode, OperandSize size, AllocatableValue x, int y)108         public ConstOp(AMD64MIOp opcode, OperandSize size, AllocatableValue x, int y) {
109             this(TYPE, opcode, size, x, y);
110         }
111 
ConstOp(LIRInstructionClass<? extends ConstOp> c, AMD64MIOp opcode, OperandSize size, AllocatableValue x, int y)112         protected ConstOp(LIRInstructionClass<? extends ConstOp> c, AMD64MIOp opcode, OperandSize size, AllocatableValue x, int y) {
113             super(c);
114             this.opcode = opcode;
115             this.size = size;
116 
117             this.x = x;
118             this.y = y;
119         }
120 
121         @Override
emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm)122         public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
123             if (isRegister(x)) {
124                 opcode.emit(masm, size, asRegister(x), y, shouldAnnotate());
125             } else {
126                 assert isStackSlot(x);
127                 opcode.emit(masm, size, (AMD64Address) crb.asAddress(x), y, shouldAnnotate());
128             }
129         }
130 
shouldAnnotate()131         protected boolean shouldAnnotate() {
132             return false;
133         }
134     }
135 
136     /**
137      * Instruction that has one {@link AllocatableValue} operand and one 32-bit immediate operand
138      * that needs to be patched at runtime.
139      */
140     public static class VMConstOp extends ConstOp {
141         public static final LIRInstructionClass<VMConstOp> TYPE = LIRInstructionClass.create(VMConstOp.class);
142 
143         protected final VMConstant c;
144 
VMConstOp(AMD64MIOp opcode, AllocatableValue x, VMConstant c)145         public VMConstOp(AMD64MIOp opcode, AllocatableValue x, VMConstant c) {
146             super(TYPE, opcode, DWORD, x, 0xDEADDEAD);
147             this.c = c;
148         }
149 
150         @Override
emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm)151         public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
152             crb.recordInlineDataInCode(c);
153             super.emitCode(crb, masm);
154         }
155 
156         @Override
shouldAnnotate()157         protected boolean shouldAnnotate() {
158             return true;
159         }
160     }
161 
162     /**
163      * Instruction that has one {@link AllocatableValue} operand and one
164      * {@link DataSectionReference} operand.
165      */
166     public static class DataOp extends AMD64LIRInstruction {
167         public static final LIRInstructionClass<DataOp> TYPE = LIRInstructionClass.create(DataOp.class);
168 
169         @Opcode private final AMD64RMOp opcode;
170         private final OperandSize size;
171 
172         @Use({REG}) protected AllocatableValue x;
173         private final Constant y;
174 
175         private final int alignment;
176 
DataOp(AMD64RMOp opcode, OperandSize size, AllocatableValue x, Constant y)177         public DataOp(AMD64RMOp opcode, OperandSize size, AllocatableValue x, Constant y) {
178             this(opcode, size, x, y, size.getBytes());
179         }
180 
DataOp(AMD64RMOp opcode, OperandSize size, AllocatableValue x, Constant y, int alignment)181         public DataOp(AMD64RMOp opcode, OperandSize size, AllocatableValue x, Constant y, int alignment) {
182             super(TYPE);
183             this.opcode = opcode;
184             this.size = size;
185 
186             this.x = x;
187             this.y = y;
188 
189             this.alignment = alignment;
190         }
191 
192         @Override
emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm)193         public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
194             opcode.emit(masm, size, asRegister(x), (AMD64Address) crb.recordDataReferenceInCode(y, alignment));
195         }
196     }
197 
198     /**
199      * Instruction that has an {@link AllocatableValue} as first input and a
200      * {@link AMD64AddressValue memory} operand as second input.
201      */
202     public static class MemoryRMOp extends AMD64LIRInstruction implements ImplicitNullCheck {
203         public static final LIRInstructionClass<MemoryRMOp> TYPE = LIRInstructionClass.create(MemoryRMOp.class);
204 
205         @Opcode private final AMD64RMOp opcode;
206         private final OperandSize size;
207 
208         @Use({REG}) protected AllocatableValue x;
209         @Use({COMPOSITE}) protected AMD64AddressValue y;
210 
211         @State protected LIRFrameState state;
212 
MemoryRMOp(AMD64RMOp opcode, OperandSize size, AllocatableValue x, AMD64AddressValue y, LIRFrameState state)213         public MemoryRMOp(AMD64RMOp opcode, OperandSize size, AllocatableValue x, AMD64AddressValue y, LIRFrameState state) {
214             super(TYPE);
215             this.opcode = opcode;
216             this.size = size;
217 
218             this.x = x;
219             this.y = y;
220 
221             this.state = state;
222         }
223 
224         @Override
emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm)225         public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
226             if (state != null) {
227                 crb.recordImplicitException(masm.position(), state);
228             }
229             opcode.emit(masm, size, asRegister(x), y.toAddress());
230         }
231 
232         @Override
makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit)233         public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) {
234             if (state == null && y.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) {
235                 state = nullCheckState;
236                 return true;
237             }
238             return false;
239         }
240     }
241 
242     /**
243      * Instruction that has a {@link AMD64AddressValue memory} operand as first input and an
244      * {@link AllocatableValue} as second input.
245      */
246     public static class MemoryMROp extends AMD64LIRInstruction implements ImplicitNullCheck {
247         public static final LIRInstructionClass<MemoryMROp> TYPE = LIRInstructionClass.create(MemoryMROp.class);
248 
249         @Opcode private final AMD64MROp opcode;
250         private final OperandSize size;
251 
252         @Use({COMPOSITE}) protected AMD64AddressValue x;
253         @Use({REG}) protected AllocatableValue y;
254 
255         @State protected LIRFrameState state;
256 
MemoryMROp(AMD64MROp opcode, OperandSize size, AMD64AddressValue x, AllocatableValue y, LIRFrameState state)257         public MemoryMROp(AMD64MROp opcode, OperandSize size, AMD64AddressValue x, AllocatableValue y, LIRFrameState state) {
258             super(TYPE);
259             this.opcode = opcode;
260             this.size = size;
261 
262             this.x = x;
263             this.y = y;
264 
265             this.state = state;
266         }
267 
268         @Override
emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm)269         public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
270             if (state != null) {
271                 crb.recordImplicitException(masm.position(), state);
272             }
273             opcode.emit(masm, size, x.toAddress(), asRegister(y));
274         }
275 
276         @Override
makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit)277         public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) {
278             if (state == null && x.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) {
279                 state = nullCheckState;
280                 return true;
281             }
282             return false;
283         }
284     }
285 
286     /**
287      * Instruction that has one {@link AMD64AddressValue memory} operand and one 32-bit immediate
288      * operand.
289      */
290     public static class MemoryConstOp extends AMD64LIRInstruction implements ImplicitNullCheck {
291         public static final LIRInstructionClass<MemoryConstOp> TYPE = LIRInstructionClass.create(MemoryConstOp.class);
292 
293         @Opcode private final AMD64MIOp opcode;
294         private final OperandSize size;
295 
296         @Use({COMPOSITE}) protected AMD64AddressValue x;
297         private final int y;
298 
299         @State protected LIRFrameState state;
300 
MemoryConstOp(AMD64BinaryArithmetic opcode, OperandSize size, AMD64AddressValue x, int y, LIRFrameState state)301         public MemoryConstOp(AMD64BinaryArithmetic opcode, OperandSize size, AMD64AddressValue x, int y, LIRFrameState state) {
302             this(opcode.getMIOpcode(size, NumUtil.isByte(y)), size, x, y, state);
303         }
304 
MemoryConstOp(AMD64MIOp opcode, OperandSize size, AMD64AddressValue x, int y, LIRFrameState state)305         public MemoryConstOp(AMD64MIOp opcode, OperandSize size, AMD64AddressValue x, int y, LIRFrameState state) {
306             this(TYPE, opcode, size, x, y, state);
307         }
308 
MemoryConstOp(LIRInstructionClass<? extends MemoryConstOp> c, AMD64MIOp opcode, OperandSize size, AMD64AddressValue x, int y, LIRFrameState state)309         protected MemoryConstOp(LIRInstructionClass<? extends MemoryConstOp> c, AMD64MIOp opcode, OperandSize size, AMD64AddressValue x, int y, LIRFrameState state) {
310             super(c);
311             this.opcode = opcode;
312             this.size = size;
313 
314             this.x = x;
315             this.y = y;
316 
317             this.state = state;
318         }
319 
320         @Override
emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm)321         public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
322             if (state != null) {
323                 crb.recordImplicitException(masm.position(), state);
324             }
325             opcode.emit(masm, size, x.toAddress(), y, shouldAnnotate());
326         }
327 
shouldAnnotate()328         protected boolean shouldAnnotate() {
329             return false;
330         }
331 
332         @Override
makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit)333         public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) {
334             if (state == null && x.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) {
335                 state = nullCheckState;
336                 return true;
337             }
338             return false;
339         }
340 
getOpcode()341         public AMD64MIOp getOpcode() {
342             return opcode;
343         }
344     }
345 
346     /**
347      * Instruction that has one {@link AMD64AddressValue memory} operand and one 32-bit immediate
348      * operand that needs to be patched at runtime.
349      */
350     public static class MemoryVMConstOp extends MemoryConstOp {
351         public static final LIRInstructionClass<MemoryVMConstOp> TYPE = LIRInstructionClass.create(MemoryVMConstOp.class);
352 
353         protected final VMConstant c;
354 
MemoryVMConstOp(AMD64MIOp opcode, AMD64AddressValue x, VMConstant c, LIRFrameState state)355         public MemoryVMConstOp(AMD64MIOp opcode, AMD64AddressValue x, VMConstant c, LIRFrameState state) {
356             super(TYPE, opcode, DWORD, x, 0xDEADDEAD, state);
357             this.c = c;
358         }
359 
360         @Override
emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm)361         public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
362             crb.recordInlineDataInCode(c);
363             super.emitCode(crb, masm);
364         }
365 
366         @Override
shouldAnnotate()367         protected boolean shouldAnnotate() {
368             return true;
369         }
370     }
371 }
372