001/*
002 * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023package com.oracle.graal.lir;
024
025import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
026import static com.oracle.graal.lir.LIRValueUtil.*;
027
028import java.util.*;
029
030import com.oracle.graal.asm.*;
031import com.oracle.graal.compiler.common.cfg.*;
032import com.oracle.graal.lir.asm.*;
033import com.oracle.graal.lir.framemap.*;
034
035import jdk.internal.jvmci.code.*;
036import jdk.internal.jvmci.common.*;
037import jdk.internal.jvmci.meta.*;
038
039/**
040 * A collection of machine-independent LIR operations, as well as interfaces to be implemented for
041 * specific kinds or LIR operations.
042 */
043public class StandardOp {
044
045    /**
046     * A block delimiter. Every well formed block must contain exactly one such operation and it
047     * must be the last operation in the block.
048     */
049    public interface BlockEndOp {
050        void setOutgoingValues(Value[] values);
051
052        int getOutgoingSize();
053
054        Value getOutgoingValue(int idx);
055
056        int addOutgoingValues(Value[] values);
057
058        void clearOutgoingValues();
059    }
060
061    public interface NullCheck {
062        Value getCheckedValue();
063
064        LIRFrameState getState();
065    }
066
067    public interface ImplicitNullCheck {
068        boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit);
069    }
070
071    /**
072     * LIR operation that defines the position of a label.
073     */
074    public static final class LabelOp extends LIRInstruction {
075        public static final LIRInstructionClass<LabelOp> TYPE = LIRInstructionClass.create(LabelOp.class);
076
077        /**
078         * In the LIR, every register and variable must be defined before it is used. For method
079         * parameters that are passed in fixed registers, exception objects passed to the exception
080         * handler in a fixed register, or any other use of a fixed register not defined in this
081         * method, an artificial definition is necessary. To avoid spill moves to be inserted
082         * between the label at the beginning of a block an an actual definition in the second
083         * instruction of a block, the registers are defined here in the label.
084         */
085        @Def({REG, STACK}) private Value[] incomingValues;
086        private int size;
087
088        private final Label label;
089        private final boolean align;
090
091        public LabelOp(Label label, boolean align) {
092            super(TYPE);
093            this.label = label;
094            this.align = align;
095            this.incomingValues = Value.NO_VALUES;
096            size = 0;
097        }
098
099        public void setIncomingValues(Value[] values) {
100            assert this.incomingValues.length == 0;
101            assert values != null;
102            this.incomingValues = values;
103            size = values.length;
104        }
105
106        public int getIncomingSize() {
107            return size;
108        }
109
110        public Value getIncomingValue(int idx) {
111            assert checkRange(idx);
112            return incomingValues[idx];
113        }
114
115        public void clearIncomingValues() {
116            incomingValues = Value.NO_VALUES;
117            size = 0;
118        }
119
120        public void addIncomingValues(Value[] values) {
121            int t = size + values.length;
122            if (t >= incomingValues.length) {
123                Value[] newArray = new Value[t];
124                System.arraycopy(incomingValues, 0, newArray, 0, size);
125                incomingValues = newArray;
126            }
127            System.arraycopy(values, 0, incomingValues, size, values.length);
128            size = t;
129        }
130
131        private boolean checkRange(int idx) {
132            return idx < size;
133        }
134
135        @Override
136        public void emitCode(CompilationResultBuilder crb) {
137            if (align) {
138                crb.asm.align(crb.target.wordSize * 2);
139            }
140            crb.asm.bind(label);
141        }
142
143        public Label getLabel() {
144            return label;
145        }
146
147        /**
148         * @return true if this label acts as a PhiIn.
149         */
150        public boolean isPhiIn() {
151            return getIncomingSize() > 0 && isVariable(getIncomingValue(0));
152        }
153    }
154
155    public abstract static class AbstractBlockEndOp extends LIRInstruction implements BlockEndOp {
156        public static final LIRInstructionClass<AbstractBlockEndOp> TYPE = LIRInstructionClass.create(AbstractBlockEndOp.class);
157
158        @Alive({REG, STACK, CONST}) private Value[] outgoingValues;
159        private int size;
160
161        protected AbstractBlockEndOp(LIRInstructionClass<? extends AbstractBlockEndOp> c) {
162            super(c);
163            this.outgoingValues = Value.NO_VALUES;
164            size = 0;
165        }
166
167        public void setOutgoingValues(Value[] values) {
168            assert this.outgoingValues.length == 0;
169            assert values != null;
170            this.outgoingValues = values;
171            size = values.length;
172        }
173
174        public int getOutgoingSize() {
175            return size;
176        }
177
178        public Value getOutgoingValue(int idx) {
179            assert checkRange(idx);
180            return outgoingValues[idx];
181        }
182
183        public void clearOutgoingValues() {
184            outgoingValues = Value.NO_VALUES;
185            size = 0;
186        }
187
188        public int addOutgoingValues(Value[] values) {
189            int t = size + values.length;
190            if (t >= outgoingValues.length) {
191                Value[] newArray = new Value[t];
192                System.arraycopy(outgoingValues, 0, newArray, 0, size);
193                outgoingValues = newArray;
194            }
195            System.arraycopy(values, 0, outgoingValues, size, values.length);
196            size = t;
197            return t;
198        }
199
200        private boolean checkRange(int idx) {
201            return idx < size;
202        }
203    }
204
205    /**
206     * LIR operation that is an unconditional jump to a {@link #destination()}.
207     */
208    public static class JumpOp extends AbstractBlockEndOp {
209        public static final LIRInstructionClass<JumpOp> TYPE = LIRInstructionClass.create(JumpOp.class);
210
211        private final LabelRef destination;
212
213        public JumpOp(LabelRef destination) {
214            this(TYPE, destination);
215        }
216
217        protected JumpOp(LIRInstructionClass<? extends JumpOp> c, LabelRef destination) {
218            super(c);
219            this.destination = destination;
220        }
221
222        @Override
223        public void emitCode(CompilationResultBuilder crb) {
224            if (!crb.isSuccessorEdge(destination)) {
225                crb.asm.jmp(destination.label());
226            }
227        }
228
229        public LabelRef destination() {
230            return destination;
231        }
232    }
233
234    /**
235     * Marker interface for a LIR operation that is a conditional jump.
236     */
237    public interface BranchOp extends BlockEndOp {
238    }
239
240    /**
241     * Marker interface for a LIR operation that moves a value from {@link #getInput()} to
242     * {@link #getResult()}.
243     */
244    public interface MoveOp {
245
246        Value getInput();
247
248        AllocatableValue getResult();
249    }
250
251    /**
252     * An operation that saves registers to the stack. The set of saved registers can be
253     * {@linkplain #remove(Set) pruned} and a mapping from registers to the frame slots in which
254     * they are saved can be {@linkplain #getMap(FrameMap) retrieved}.
255     */
256    public interface SaveRegistersOp {
257
258        /**
259         * Determines if the {@link #remove(Set)} operation is supported for this object.
260         */
261        boolean supportsRemove();
262
263        /**
264         * Prunes {@code doNotSave} from the registers saved by this operation.
265         *
266         * @param doNotSave registers that should not be saved by this operation
267         * @return the number of registers pruned
268         * @throws UnsupportedOperationException if removal is not {@linkplain #supportsRemove()
269         *             supported}
270         */
271        int remove(Set<Register> doNotSave);
272
273        /**
274         * Gets a map from the saved registers saved by this operation to the frame slots in which
275         * they are saved.
276         *
277         * @param frameMap used to {@linkplain FrameMap#offsetForStackSlot(StackSlot) convert} a
278         *            virtual slot to a frame slot index
279         */
280        RegisterSaveLayout getMap(FrameMap frameMap);
281
282    }
283
284    /**
285     * An operation that takes one input and stores it in a stack slot as well as to an ordinary
286     * variable.
287     */
288    public interface StackStoreOp {
289
290        Value getInput();
291
292        AllocatableValue getResult();
293
294        StackSlotValue getStackSlot();
295    }
296
297    /**
298     * A LIR operation that does nothing. If the operation records its position, it can be
299     * subsequently {@linkplain #replace(LIR, LIRInstruction) replaced}.
300     */
301    public static final class NoOp extends LIRInstruction {
302        public static final LIRInstructionClass<NoOp> TYPE = LIRInstructionClass.create(NoOp.class);
303
304        /**
305         * The block in which this instruction is located.
306         */
307        final AbstractBlockBase<?> block;
308
309        /**
310         * The block index of this instruction.
311         */
312        final int index;
313
314        public NoOp(AbstractBlockBase<?> block, int index) {
315            super(TYPE);
316            this.block = block;
317            this.index = index;
318        }
319
320        public void replace(LIR lir, LIRInstruction replacement) {
321            List<LIRInstruction> instructions = lir.getLIRforBlock(block);
322            assert instructions.get(index).equals(this) : String.format("Replacing the wrong instruction: %s instead of %s", instructions.get(index), this);
323            instructions.set(index, replacement);
324        }
325
326        public void remove(LIR lir) {
327            List<LIRInstruction> instructions = lir.getLIRforBlock(block);
328            assert instructions.get(index).equals(this) : String.format("Removing the wrong instruction: %s instead of %s", instructions.get(index), this);
329            instructions.remove(index);
330        }
331
332        @Override
333        public void emitCode(CompilationResultBuilder crb) {
334            if (block != null) {
335                throw new JVMCIError(this + " should have been replaced");
336            }
337        }
338    }
339
340    @Opcode("BLACKHOLE")
341    public static final class BlackholeOp extends LIRInstruction {
342        public static final LIRInstructionClass<BlackholeOp> TYPE = LIRInstructionClass.create(BlackholeOp.class);
343
344        @Use({REG, STACK, CONST}) private Value value;
345
346        public BlackholeOp(Value value) {
347            super(TYPE);
348            this.value = value;
349        }
350
351        @Override
352        public void emitCode(CompilationResultBuilder crb) {
353            // do nothing, just keep value alive until at least here
354        }
355    }
356
357    public static final class StackMove extends LIRInstruction implements MoveOp {
358        public static final LIRInstructionClass<StackMove> TYPE = LIRInstructionClass.create(StackMove.class);
359
360        @Def({STACK, HINT}) protected AllocatableValue result;
361        @Use({STACK}) protected Value input;
362
363        public StackMove(AllocatableValue result, Value input) {
364            super(TYPE);
365            this.result = result;
366            this.input = input;
367        }
368
369        @Override
370        public void emitCode(CompilationResultBuilder crb) {
371            throw new JVMCIError(this + " should have been removed");
372        }
373
374        @Override
375        public Value getInput() {
376            return input;
377        }
378
379        @Override
380        public AllocatableValue getResult() {
381            return result;
382        }
383    }
384
385}