1/*
2 * Copyright (c) 2015, 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 */
23package org.graalvm.compiler.lir.amd64;
24
25import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.COMPOSITE;
26import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT;
27import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
28import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
29import static org.graalvm.compiler.lir.LIRValueUtil.differentRegisters;
30import static org.graalvm.compiler.lir.LIRValueUtil.sameRegister;
31import static jdk.vm.ci.code.ValueUtil.asRegister;
32import static jdk.vm.ci.code.ValueUtil.isRegister;
33import static jdk.vm.ci.code.ValueUtil.isStackSlot;
34
35import org.graalvm.compiler.core.common.NumUtil;
36import org.graalvm.compiler.asm.amd64.AMD64Address;
37import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic;
38import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MIOp;
39import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMIOp;
40import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp;
41import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RRMOp;
42import org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize;
43import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
44import org.graalvm.compiler.lir.LIRFrameState;
45import org.graalvm.compiler.lir.LIRInstructionClass;
46import org.graalvm.compiler.lir.Opcode;
47import org.graalvm.compiler.lir.StandardOp.ImplicitNullCheck;
48import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
49
50import jdk.vm.ci.code.site.DataSectionReference;
51import jdk.vm.ci.meta.AllocatableValue;
52import jdk.vm.ci.meta.JavaConstant;
53import jdk.vm.ci.meta.Value;
54
55/**
56 * AMD64 LIR instructions that have two inputs and one output.
57 */
58public class AMD64Binary {
59
60    /**
61     * Instruction that has two {@link AllocatableValue} operands.
62     */
63    public static class TwoOp extends AMD64LIRInstruction {
64        public static final LIRInstructionClass<TwoOp> TYPE = LIRInstructionClass.create(TwoOp.class);
65
66        @Opcode private final AMD64RMOp opcode;
67        private final OperandSize size;
68
69        @Def({REG, HINT}) protected AllocatableValue result;
70        @Use({REG}) protected AllocatableValue x;
71        /**
72         * This argument must be Alive to ensure that result and y are not assigned to the same
73         * register, which would break the code generation by destroying y too early.
74         */
75        @Alive({REG, STACK}) protected AllocatableValue y;
76
77        public TwoOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AllocatableValue y) {
78            super(TYPE);
79            this.opcode = opcode;
80            this.size = size;
81
82            this.result = result;
83            this.x = x;
84            this.y = y;
85        }
86
87        @Override
88        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
89            AMD64Move.move(crb, masm, result, x);
90            if (isRegister(y)) {
91                opcode.emit(masm, size, asRegister(result), asRegister(y));
92            } else {
93                assert isStackSlot(y);
94                opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(y));
95            }
96        }
97    }
98
99    /**
100     * Instruction that has three {@link AllocatableValue} operands.
101     */
102    public static class ThreeOp extends AMD64LIRInstruction {
103        public static final LIRInstructionClass<ThreeOp> TYPE = LIRInstructionClass.create(ThreeOp.class);
104
105        @Opcode private final AMD64RRMOp opcode;
106        private final OperandSize size;
107
108        @Def({REG}) protected AllocatableValue result;
109        @Use({REG}) protected AllocatableValue x;
110        @Use({REG, STACK}) protected AllocatableValue y;
111
112        public ThreeOp(AMD64RRMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AllocatableValue y) {
113            super(TYPE);
114            this.opcode = opcode;
115            this.size = size;
116
117            this.result = result;
118            this.x = x;
119            this.y = y;
120        }
121
122        @Override
123        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
124            if (isRegister(y)) {
125                opcode.emit(masm, size, asRegister(result), asRegister(x), asRegister(y));
126            } else {
127                assert isStackSlot(y);
128                opcode.emit(masm, size, asRegister(result), asRegister(x), (AMD64Address) crb.asAddress(y));
129            }
130        }
131    }
132
133    /**
134     * Commutative instruction that has two {@link AllocatableValue} operands.
135     */
136    public static class CommutativeTwoOp extends AMD64LIRInstruction {
137        public static final LIRInstructionClass<CommutativeTwoOp> TYPE = LIRInstructionClass.create(CommutativeTwoOp.class);
138
139        @Opcode private final AMD64RMOp opcode;
140        private final OperandSize size;
141
142        @Def({REG, HINT}) protected AllocatableValue result;
143        @Use({REG, STACK}) protected AllocatableValue x;
144        @Use({REG, STACK}) protected AllocatableValue y;
145
146        public CommutativeTwoOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AllocatableValue y) {
147            super(TYPE);
148            this.opcode = opcode;
149            this.size = size;
150
151            this.result = result;
152            this.x = x;
153            this.y = y;
154        }
155
156        @Override
157        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
158            AllocatableValue input;
159            if (sameRegister(result, y)) {
160                input = x;
161            } else {
162                AMD64Move.move(crb, masm, result, x);
163                input = y;
164            }
165
166            if (isRegister(input)) {
167                opcode.emit(masm, size, asRegister(result), asRegister(input));
168            } else {
169                assert isStackSlot(input);
170                opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(input));
171            }
172        }
173    }
174
175    /**
176     * Commutative instruction that has three {@link AllocatableValue} operands.
177     */
178    public static class CommutativeThreeOp extends AMD64LIRInstruction {
179        public static final LIRInstructionClass<CommutativeThreeOp> TYPE = LIRInstructionClass.create(CommutativeThreeOp.class);
180
181        @Opcode private final AMD64RRMOp opcode;
182        private final OperandSize size;
183
184        @Def({REG}) protected AllocatableValue result;
185        @Use({REG}) protected AllocatableValue x;
186        @Use({REG, STACK}) protected AllocatableValue y;
187
188        public CommutativeThreeOp(AMD64RRMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AllocatableValue y) {
189            super(TYPE);
190            this.opcode = opcode;
191            this.size = size;
192
193            this.result = result;
194            this.x = x;
195            this.y = y;
196        }
197
198        @Override
199        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
200            if (isRegister(y)) {
201                opcode.emit(masm, size, asRegister(result), asRegister(x), asRegister(y));
202            } else {
203                assert isStackSlot(y);
204                opcode.emit(masm, size, asRegister(result), asRegister(x), (AMD64Address) crb.asAddress(y));
205            }
206        }
207    }
208
209    /**
210     * Instruction that has one {@link AllocatableValue} operand and one 32-bit immediate operand.
211     */
212    public static class ConstOp extends AMD64LIRInstruction {
213        public static final LIRInstructionClass<ConstOp> TYPE = LIRInstructionClass.create(ConstOp.class);
214
215        @Opcode private final AMD64MIOp opcode;
216        private final OperandSize size;
217
218        @Def({REG, HINT}) protected AllocatableValue result;
219        @Use({REG}) protected AllocatableValue x;
220        private final int y;
221
222        public ConstOp(AMD64BinaryArithmetic opcode, OperandSize size, AllocatableValue result, AllocatableValue x, int y) {
223            this(opcode.getMIOpcode(size, NumUtil.isByte(y)), size, result, x, y);
224        }
225
226        public ConstOp(AMD64MIOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, int y) {
227            super(TYPE);
228            this.opcode = opcode;
229            this.size = size;
230
231            this.result = result;
232            this.x = x;
233            this.y = y;
234        }
235
236        @Override
237        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
238            AMD64Move.move(crb, masm, result, x);
239            opcode.emit(masm, size, asRegister(result), y);
240        }
241    }
242
243    /**
244     * Instruction that has one {@link AllocatableValue} operand and one
245     * {@link DataSectionReference} operand.
246     */
247    public static class DataTwoOp extends AMD64LIRInstruction {
248        public static final LIRInstructionClass<DataTwoOp> TYPE = LIRInstructionClass.create(DataTwoOp.class);
249
250        @Opcode private final AMD64RMOp opcode;
251        private final OperandSize size;
252
253        @Def({REG, HINT}) protected AllocatableValue result;
254        @Use({REG}) protected AllocatableValue x;
255        private final JavaConstant y;
256
257        private final int alignment;
258
259        public DataTwoOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, JavaConstant y) {
260            this(opcode, size, result, x, y, y.getJavaKind().getByteCount());
261        }
262
263        public DataTwoOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, JavaConstant y, int alignment) {
264            super(TYPE);
265            this.opcode = opcode;
266            this.size = size;
267
268            this.result = result;
269            this.x = x;
270            this.y = y;
271
272            this.alignment = alignment;
273        }
274
275        @Override
276        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
277            AMD64Move.move(crb, masm, result, x);
278            opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.recordDataReferenceInCode(y, alignment));
279        }
280    }
281
282    /**
283     * Instruction that has two {@link AllocatableValue} operands and one
284     * {@link DataSectionReference} operand.
285     */
286    public static class DataThreeOp extends AMD64LIRInstruction {
287        public static final LIRInstructionClass<DataThreeOp> TYPE = LIRInstructionClass.create(DataThreeOp.class);
288
289        @Opcode private final AMD64RRMOp opcode;
290        private final OperandSize size;
291
292        @Def({REG}) protected AllocatableValue result;
293        @Use({REG}) protected AllocatableValue x;
294        private final JavaConstant y;
295
296        private final int alignment;
297
298        public DataThreeOp(AMD64RRMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, JavaConstant y) {
299            this(opcode, size, result, x, y, y.getJavaKind().getByteCount());
300        }
301
302        public DataThreeOp(AMD64RRMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, JavaConstant y, int alignment) {
303            super(TYPE);
304            this.opcode = opcode;
305            this.size = size;
306
307            this.result = result;
308            this.x = x;
309            this.y = y;
310
311            this.alignment = alignment;
312        }
313
314        @Override
315        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
316            opcode.emit(masm, size, asRegister(result), asRegister(x), (AMD64Address) crb.recordDataReferenceInCode(y, alignment));
317        }
318    }
319
320    /**
321     * Instruction that has one {@link AllocatableValue} operand and one {@link AMD64AddressValue
322     * memory} operand.
323     */
324    public static class MemoryTwoOp extends AMD64LIRInstruction implements ImplicitNullCheck {
325        public static final LIRInstructionClass<MemoryTwoOp> TYPE = LIRInstructionClass.create(MemoryTwoOp.class);
326
327        @Opcode private final AMD64RMOp opcode;
328        private final OperandSize size;
329
330        @Def({REG, HINT}) protected AllocatableValue result;
331        @Use({REG}) protected AllocatableValue x;
332        @Alive({COMPOSITE}) protected AMD64AddressValue y;
333
334        @State protected LIRFrameState state;
335
336        public MemoryTwoOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AMD64AddressValue y, LIRFrameState state) {
337            super(TYPE);
338            this.opcode = opcode;
339            this.size = size;
340
341            this.result = result;
342            this.x = x;
343            this.y = y;
344
345            this.state = state;
346        }
347
348        @Override
349        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
350            AMD64Move.move(crb, masm, result, x);
351            if (state != null) {
352                crb.recordImplicitException(masm.position(), state);
353            }
354            opcode.emit(masm, size, asRegister(result), y.toAddress());
355        }
356
357        @Override
358        public void verify() {
359            super.verify();
360            assert differentRegisters(result, y) || sameRegister(x, y);
361        }
362
363        @Override
364        public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) {
365            if (state == null && y.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) {
366                state = nullCheckState;
367                return true;
368            }
369            return false;
370        }
371    }
372
373    /**
374     * Instruction that has one {@link AllocatableValue} operand and one {@link AMD64AddressValue
375     * memory} operand.
376     */
377    public static class MemoryThreeOp extends AMD64LIRInstruction implements ImplicitNullCheck {
378        public static final LIRInstructionClass<MemoryThreeOp> TYPE = LIRInstructionClass.create(MemoryThreeOp.class);
379
380        @Opcode private final AMD64RRMOp opcode;
381        private final OperandSize size;
382
383        @Def({REG}) protected AllocatableValue result;
384        @Use({REG}) protected AllocatableValue x;
385        @Use({COMPOSITE}) protected AMD64AddressValue y;
386
387        @State protected LIRFrameState state;
388
389        public MemoryThreeOp(AMD64RRMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AMD64AddressValue y, LIRFrameState state) {
390            super(TYPE);
391            this.opcode = opcode;
392            this.size = size;
393
394            this.result = result;
395            this.x = x;
396            this.y = y;
397
398            this.state = state;
399        }
400
401        @Override
402        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
403            if (state != null) {
404                crb.recordImplicitException(masm.position(), state);
405            }
406            opcode.emit(masm, size, asRegister(result), asRegister(x), y.toAddress());
407        }
408
409        @Override
410        public void verify() {
411            super.verify();
412            assert differentRegisters(result, y) || sameRegister(x, y);
413        }
414
415        @Override
416        public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) {
417            if (state == null && y.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) {
418                state = nullCheckState;
419                return true;
420            }
421            return false;
422        }
423    }
424
425    /**
426     * Instruction with a separate result operand, one {@link AllocatableValue} input and one 32-bit
427     * immediate input.
428     */
429    public static class RMIOp extends AMD64LIRInstruction {
430        public static final LIRInstructionClass<RMIOp> TYPE = LIRInstructionClass.create(RMIOp.class);
431
432        @Opcode private final AMD64RMIOp opcode;
433        private final OperandSize size;
434
435        @Def({REG}) protected AllocatableValue result;
436        @Use({REG, STACK}) protected AllocatableValue x;
437        private final int y;
438
439        public RMIOp(AMD64RMIOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, int y) {
440            super(TYPE);
441            this.opcode = opcode;
442            this.size = size;
443
444            this.result = result;
445            this.x = x;
446            this.y = y;
447        }
448
449        @Override
450        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
451            if (isRegister(x)) {
452                opcode.emit(masm, size, asRegister(result), asRegister(x), y);
453            } else {
454                assert isStackSlot(x);
455                opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(x), y);
456            }
457        }
458    }
459}
460