1 /*
2  * Copyright (c) 2015, 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 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 
getOpcode()135         public AMD64MIOp getOpcode() {
136             return opcode;
137         }
138     }
139 
140     /**
141      * Instruction that has one {@link AllocatableValue} operand and one 32-bit immediate operand
142      * that needs to be patched at runtime.
143      */
144     public static class VMConstOp extends ConstOp {
145         public static final LIRInstructionClass<VMConstOp> TYPE = LIRInstructionClass.create(VMConstOp.class);
146 
147         protected final VMConstant c;
148 
VMConstOp(AMD64MIOp opcode, AllocatableValue x, VMConstant c)149         public VMConstOp(AMD64MIOp opcode, AllocatableValue x, VMConstant c) {
150             super(TYPE, opcode, DWORD, x, 0xDEADDEAD);
151             this.c = c;
152         }
153 
154         @Override
emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm)155         public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
156             crb.recordInlineDataInCode(c);
157             super.emitCode(crb, masm);
158         }
159 
160         @Override
shouldAnnotate()161         protected boolean shouldAnnotate() {
162             return true;
163         }
164     }
165 
166     /**
167      * Instruction that has one {@link AllocatableValue} operand and one
168      * {@link DataSectionReference} operand.
169      */
170     public static class DataOp extends AMD64LIRInstruction {
171         public static final LIRInstructionClass<DataOp> TYPE = LIRInstructionClass.create(DataOp.class);
172 
173         @Opcode private final AMD64RMOp opcode;
174         private final OperandSize size;
175 
176         @Use({REG}) protected AllocatableValue x;
177         private final Constant y;
178 
179         private final int alignment;
180 
DataOp(AMD64RMOp opcode, OperandSize size, AllocatableValue x, Constant y)181         public DataOp(AMD64RMOp opcode, OperandSize size, AllocatableValue x, Constant y) {
182             this(opcode, size, x, y, size.getBytes());
183         }
184 
DataOp(AMD64RMOp opcode, OperandSize size, AllocatableValue x, Constant y, int alignment)185         public DataOp(AMD64RMOp opcode, OperandSize size, AllocatableValue x, Constant y, int alignment) {
186             super(TYPE);
187             this.opcode = opcode;
188             this.size = size;
189 
190             this.x = x;
191             this.y = y;
192 
193             this.alignment = alignment;
194         }
195 
196         @Override
emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm)197         public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
198             opcode.emit(masm, size, asRegister(x), (AMD64Address) crb.recordDataReferenceInCode(y, alignment));
199         }
200     }
201 
202     /**
203      * Instruction that has an {@link AllocatableValue} as first input and a
204      * {@link AMD64AddressValue memory} operand as second input.
205      */
206     public static class MemoryRMOp extends AMD64LIRInstruction implements ImplicitNullCheck {
207         public static final LIRInstructionClass<MemoryRMOp> TYPE = LIRInstructionClass.create(MemoryRMOp.class);
208 
209         @Opcode private final AMD64RMOp opcode;
210         private final OperandSize size;
211 
212         @Use({REG}) protected AllocatableValue x;
213         @Use({COMPOSITE}) protected AMD64AddressValue y;
214 
215         @State protected LIRFrameState state;
216 
MemoryRMOp(AMD64RMOp opcode, OperandSize size, AllocatableValue x, AMD64AddressValue y, LIRFrameState state)217         public MemoryRMOp(AMD64RMOp opcode, OperandSize size, AllocatableValue x, AMD64AddressValue y, LIRFrameState state) {
218             super(TYPE);
219             this.opcode = opcode;
220             this.size = size;
221 
222             this.x = x;
223             this.y = y;
224 
225             this.state = state;
226         }
227 
228         @Override
emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm)229         public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
230             if (state != null) {
231                 crb.recordImplicitException(masm.position(), state);
232             }
233             opcode.emit(masm, size, asRegister(x), y.toAddress());
234         }
235 
236         @Override
makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit)237         public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) {
238             if (state == null && y.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) {
239                 state = nullCheckState;
240                 return true;
241             }
242             return false;
243         }
244     }
245 
246     /**
247      * Instruction that has a {@link AMD64AddressValue memory} operand as first input and an
248      * {@link AllocatableValue} as second input.
249      */
250     public static class MemoryMROp extends AMD64LIRInstruction implements ImplicitNullCheck {
251         public static final LIRInstructionClass<MemoryMROp> TYPE = LIRInstructionClass.create(MemoryMROp.class);
252 
253         @Opcode private final AMD64MROp opcode;
254         private final OperandSize size;
255 
256         @Use({COMPOSITE}) protected AMD64AddressValue x;
257         @Use({REG}) protected AllocatableValue y;
258 
259         @State protected LIRFrameState state;
260 
MemoryMROp(AMD64MROp opcode, OperandSize size, AMD64AddressValue x, AllocatableValue y, LIRFrameState state)261         public MemoryMROp(AMD64MROp opcode, OperandSize size, AMD64AddressValue x, AllocatableValue y, LIRFrameState state) {
262             super(TYPE);
263             this.opcode = opcode;
264             this.size = size;
265 
266             this.x = x;
267             this.y = y;
268 
269             this.state = state;
270         }
271 
272         @Override
emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm)273         public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
274             if (state != null) {
275                 crb.recordImplicitException(masm.position(), state);
276             }
277             opcode.emit(masm, size, x.toAddress(), asRegister(y));
278         }
279 
280         @Override
makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit)281         public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) {
282             if (state == null && x.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) {
283                 state = nullCheckState;
284                 return true;
285             }
286             return false;
287         }
288     }
289 
290     /**
291      * Instruction that has one {@link AMD64AddressValue memory} operand and one 32-bit immediate
292      * operand.
293      */
294     public static class MemoryConstOp extends AMD64LIRInstruction implements ImplicitNullCheck {
295         public static final LIRInstructionClass<MemoryConstOp> TYPE = LIRInstructionClass.create(MemoryConstOp.class);
296 
297         @Opcode private final AMD64MIOp opcode;
298         private final OperandSize size;
299 
300         @Use({COMPOSITE}) protected AMD64AddressValue x;
301         private final int y;
302 
303         @State protected LIRFrameState state;
304 
MemoryConstOp(AMD64BinaryArithmetic opcode, OperandSize size, AMD64AddressValue x, int y, LIRFrameState state)305         public MemoryConstOp(AMD64BinaryArithmetic opcode, OperandSize size, AMD64AddressValue x, int y, LIRFrameState state) {
306             this(opcode.getMIOpcode(size, NumUtil.isByte(y)), size, x, y, state);
307         }
308 
MemoryConstOp(AMD64MIOp opcode, OperandSize size, AMD64AddressValue x, int y, LIRFrameState state)309         public MemoryConstOp(AMD64MIOp opcode, OperandSize size, AMD64AddressValue x, int y, LIRFrameState state) {
310             this(TYPE, opcode, size, x, y, state);
311         }
312 
MemoryConstOp(LIRInstructionClass<? extends MemoryConstOp> c, AMD64MIOp opcode, OperandSize size, AMD64AddressValue x, int y, LIRFrameState state)313         protected MemoryConstOp(LIRInstructionClass<? extends MemoryConstOp> c, AMD64MIOp opcode, OperandSize size, AMD64AddressValue x, int y, LIRFrameState state) {
314             super(c);
315             this.opcode = opcode;
316             this.size = size;
317 
318             this.x = x;
319             this.y = y;
320 
321             this.state = state;
322         }
323 
324         @Override
emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm)325         public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
326             if (state != null) {
327                 crb.recordImplicitException(masm.position(), state);
328             }
329             opcode.emit(masm, size, x.toAddress(), y, shouldAnnotate());
330         }
331 
shouldAnnotate()332         protected boolean shouldAnnotate() {
333             return false;
334         }
335 
336         @Override
makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit)337         public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) {
338             if (state == null && x.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) {
339                 state = nullCheckState;
340                 return true;
341             }
342             return false;
343         }
344 
getOpcode()345         public AMD64MIOp getOpcode() {
346             return opcode;
347         }
348     }
349 
350     /**
351      * Instruction that has one {@link AMD64AddressValue memory} operand and one 32-bit immediate
352      * operand that needs to be patched at runtime.
353      */
354     public static class MemoryVMConstOp extends MemoryConstOp {
355         public static final LIRInstructionClass<MemoryVMConstOp> TYPE = LIRInstructionClass.create(MemoryVMConstOp.class);
356 
357         protected final VMConstant c;
358 
MemoryVMConstOp(AMD64MIOp opcode, AMD64AddressValue x, VMConstant c, LIRFrameState state)359         public MemoryVMConstOp(AMD64MIOp opcode, AMD64AddressValue x, VMConstant c, LIRFrameState state) {
360             super(TYPE, opcode, DWORD, x, 0xDEADDEAD, state);
361             this.c = c;
362         }
363 
364         @Override
emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm)365         public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
366             crb.recordInlineDataInCode(c);
367             super.emitCode(crb, masm);
368         }
369 
370         @Override
shouldAnnotate()371         protected boolean shouldAnnotate() {
372             return true;
373         }
374     }
375 }
376