001/*
002 * Copyright (c) 2009, 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 java.util.*;
026
027import com.oracle.graal.compiler.common.cfg.*;
028import com.oracle.graal.lir.StandardOp.BlockEndOp;
029import com.oracle.graal.lir.StandardOp.LabelOp;
030
031/**
032 * This class implements the overall container for the LIR graph and directs its construction,
033 * optimization, and finalization.
034 */
035public class LIR {
036
037    private final AbstractControlFlowGraph<?> cfg;
038
039    /**
040     * The linear-scan ordered list of blocks.
041     */
042    private final List<? extends AbstractBlockBase<?>> linearScanOrder;
043
044    /**
045     * The order in which the code is emitted.
046     */
047    private final List<? extends AbstractBlockBase<?>> codeEmittingOrder;
048
049    private int firstVariableNumber;
050
051    private int numVariables;
052
053    private final BlockMap<List<LIRInstruction>> lirInstructions;
054
055    private boolean hasArgInCallerFrame;
056
057    /**
058     * Creates a new LIR instance for the specified compilation.
059     */
060    public LIR(AbstractControlFlowGraph<?> cfg, List<? extends AbstractBlockBase<?>> linearScanOrder, List<? extends AbstractBlockBase<?>> codeEmittingOrder) {
061        this.cfg = cfg;
062        this.codeEmittingOrder = codeEmittingOrder;
063        this.linearScanOrder = linearScanOrder;
064        this.lirInstructions = new BlockMap<>(cfg);
065    }
066
067    public AbstractControlFlowGraph<?> getControlFlowGraph() {
068        return cfg;
069    }
070
071    /**
072     * Determines if any instruction in the LIR has debug info associated with it.
073     */
074    public boolean hasDebugInfo() {
075        for (AbstractBlockBase<?> b : linearScanOrder()) {
076            for (LIRInstruction op : getLIRforBlock(b)) {
077                if (op.hasState()) {
078                    return true;
079                }
080            }
081        }
082        return false;
083    }
084
085    public List<LIRInstruction> getLIRforBlock(AbstractBlockBase<?> block) {
086        return lirInstructions.get(block);
087    }
088
089    public void setLIRforBlock(AbstractBlockBase<?> block, List<LIRInstruction> list) {
090        assert getLIRforBlock(block) == null : "lir instruction list should only be initialized once";
091        lirInstructions.put(block, list);
092    }
093
094    /**
095     * Gets the linear scan ordering of blocks as a list.
096     *
097     * @return the blocks in linear scan order
098     */
099    public List<? extends AbstractBlockBase<?>> linearScanOrder() {
100        return linearScanOrder;
101    }
102
103    public List<? extends AbstractBlockBase<?>> codeEmittingOrder() {
104        return codeEmittingOrder;
105    }
106
107    public int numVariables() {
108        return numVariables;
109    }
110
111    public int nextVariable() {
112        return firstVariableNumber + numVariables++;
113    }
114
115    public void setFirstVariableNumber(int num) {
116        firstVariableNumber = num;
117    }
118
119    public void setHasArgInCallerFrame() {
120        hasArgInCallerFrame = true;
121    }
122
123    /**
124     * Determines if any of the parameters to the method are passed via the stack where the
125     * parameters are located in the caller's frame.
126     */
127    public boolean hasArgInCallerFrame() {
128        return hasArgInCallerFrame;
129    }
130
131    /**
132     * Gets the exception edge (if any) originating at a given operation.
133     */
134    public static LabelRef getExceptionEdge(LIRInstruction op) {
135        final LabelRef[] exceptionEdge = {null};
136        op.forEachState(state -> {
137            if (state.exceptionEdge != null) {
138                assert exceptionEdge[0] == null;
139                exceptionEdge[0] = state.exceptionEdge;
140            }
141        });
142        return exceptionEdge[0];
143    }
144
145    /**
146     * The maximum distance an operation with an {@linkplain #getExceptionEdge(LIRInstruction)
147     * exception edge} can be from the last instruction of a LIR block. The value of 3 is based on a
148     * non-void call operation that has an exception edge. Such a call may move the result to
149     * another register and then spill it.
150     * <p>
151     * The rationale for such a constant is to limit the search for an insertion point when adding
152     * move operations at the end of a block. Such moves must be inserted before all control flow
153     * instructions.
154     */
155    public static final int MAX_EXCEPTION_EDGE_OP_DISTANCE_FROM_END = 3;
156
157    public static boolean verifyBlock(LIR lir, AbstractBlockBase<?> block) {
158        List<LIRInstruction> ops = lir.getLIRforBlock(block);
159        if (ops.size() == 0) {
160            return false;
161        }
162        LIRInstruction opWithExceptionEdge = null;
163        int index = 0;
164        int lastIndex = ops.size() - 1;
165        for (LIRInstruction op : ops.subList(0, lastIndex)) {
166            assert !(op instanceof BlockEndOp) : op.getClass();
167            LabelRef exceptionEdge = getExceptionEdge(op);
168            if (exceptionEdge != null) {
169                assert opWithExceptionEdge == null : "multiple ops with an exception edge not allowed";
170                opWithExceptionEdge = op;
171                int distanceFromEnd = lastIndex - index;
172                assert distanceFromEnd <= MAX_EXCEPTION_EDGE_OP_DISTANCE_FROM_END;
173            }
174            index++;
175        }
176        LIRInstruction end = ops.get(lastIndex);
177        assert end instanceof BlockEndOp : end.getClass();
178        return true;
179    }
180
181    public static boolean verifyBlocks(LIR lir, List<? extends AbstractBlockBase<?>> blocks) {
182        for (AbstractBlockBase<?> block : blocks) {
183            for (AbstractBlockBase<?> sux : block.getSuccessors()) {
184                assert blocks.contains(sux) : "missing successor from: " + block + "to: " + sux;
185            }
186            for (AbstractBlockBase<?> pred : block.getPredecessors()) {
187                assert blocks.contains(pred) : "missing predecessor from: " + block + "to: " + pred;
188            }
189            if (!verifyBlock(lir, block)) {
190                return false;
191            }
192        }
193        return true;
194    }
195
196    public void resetLabels() {
197
198        for (AbstractBlockBase<?> block : codeEmittingOrder()) {
199            for (LIRInstruction inst : lirInstructions.get(block)) {
200                if (inst instanceof LabelOp) {
201                    ((LabelOp) inst).getLabel().reset();
202                }
203            }
204        }
205    }
206
207}