1917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul/*
2917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Copyright (C) 2007 The Android Open Source Project
3917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul *
4917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Licensed under the Apache License, Version 2.0 (the "License");
5917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * you may not use this file except in compliance with the License.
6917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * You may obtain a copy of the License at
7917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul *
8917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul *      http://www.apache.org/licenses/LICENSE-2.0
9917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul *
10917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Unless required by applicable law or agreed to in writing, software
11917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * distributed under the License is distributed on an "AS IS" BASIS,
12917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * See the License for the specific language governing permissions and
14917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * limitations under the License.
15917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */
16917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
17917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulpackage com.android.dexgen.dex.code;
18917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
19917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.code.BasicBlock;
20917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.code.BasicBlockList;
21917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.code.FillArrayDataInsn;
22917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.code.Insn;
23917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.code.LocalVariableInfo;
24917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.code.PlainCstInsn;
25917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.code.PlainInsn;
26917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.code.RegOps;
27917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.code.RegisterSpec;
28917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.code.RegisterSpecList;
29917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.code.RegisterSpecSet;
30917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.code.Rop;
31917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.code.RopMethod;
32917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.code.SourcePosition;
33917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.code.SwitchInsn;
34917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.code.ThrowingCstInsn;
35917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.code.ThrowingInsn;
36917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.cst.Constant;
37917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.cst.CstInteger;
38917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.type.Type;
39917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.util.Bits;
40917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.util.IntList;
41917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
42917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport java.util.ArrayList;
43917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
44917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul/**
45917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Translator from {@link RopMethod} to {@link DalvCode}. The {@link
46917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * #translate} method is the thing to call on this class.
47917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */
48917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulpublic final class RopTranslator {
49917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** {@code non-null;} method to translate */
50917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private final RopMethod method;
51917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
52917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
53917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * how much position info to preserve; one of the static
54917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * constants in {@link PositionList}
55917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
56917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private final int positionInfo;
57917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
58917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** {@code null-ok;} local variable info to use */
59917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private final LocalVariableInfo locals;
60917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
61917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** {@code non-null;} container for all the address objects for the method */
62917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private final BlockAddresses addresses;
63917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
64917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** {@code non-null;} list of output instructions in-progress */
65917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private final OutputCollector output;
66917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
67917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** {@code non-null;} visitor to use during translation */
68917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private final TranslationVisitor translationVisitor;
69917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
70917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** {@code >= 0;} register count for the method */
71917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private final int regCount;
72917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
73917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** {@code null-ok;} block output order; becomes non-null in {@link #pickOrder} */
74917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private int[] order;
75917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
76917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** size, in register units, of all the parameters to this method */
77917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private final int paramSize;
78917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
79917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
80917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * true if the parameters to this method happen to be in proper order
81917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * at the end of the frame (as the optimizer emits them)
82917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
83917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private boolean paramsAreInOrder;
84917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
85917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
86917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Translates a {@link RopMethod}. This may modify the given
87917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * input.
88917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
89917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param method {@code non-null;} the original method
90917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param positionInfo how much position info to preserve; one of the
91917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * static constants in {@link PositionList}
92917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param locals {@code null-ok;} local variable information to use
93917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param paramSize size, in register units, of all the parameters to
94917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * this method
95917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return {@code non-null;} the translated version
96917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
97917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public static DalvCode translate(RopMethod method, int positionInfo,
98917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                                     LocalVariableInfo locals, int paramSize) {
99917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        RopTranslator translator =
100917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            new RopTranslator(method, positionInfo, locals,
101917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    paramSize);
102917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return translator.translateAndGetResult();
103917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
104917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
105917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
106917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Constructs an instance. This method is private. Use {@link #translate}.
107917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
108917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param method {@code non-null;} the original method
109917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param positionInfo how much position info to preserve; one of the
110917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * static constants in {@link PositionList}
111917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param locals {@code null-ok;} local variable information to use
112917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param paramSize size, in register units, of all the parameters to
113917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * this method
114917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
115917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private RopTranslator(RopMethod method, int positionInfo,
116917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                          LocalVariableInfo locals, int paramSize) {
117917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.method = method;
118917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.positionInfo = positionInfo;
119917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.locals = locals;
120917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.addresses = new BlockAddresses(method);
121917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.paramSize = paramSize;
122917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.order = null;
123917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.paramsAreInOrder = calculateParamsAreInOrder(method, paramSize);
124917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
125917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        BasicBlockList blocks = method.getBlocks();
126917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int bsz = blocks.size();
127917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
128917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /*
129917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * Max possible instructions includes three code address
130917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * objects per basic block (to the first and last instruction,
131917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * and just past the end of the block), and the possibility of
132917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * an extra goto at the end of each basic block.
133917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
134917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int maxInsns = (bsz * 3) + blocks.getInstructionCount();
135917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
136917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (locals != null) {
137917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            /*
138917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * If we're tracking locals, then there's could be another
139917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * extra instruction per block (for the locals state at the
140917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * start of the block) as well as one for each interblock
141917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * local introduction.
142917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             */
143917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            maxInsns += bsz + locals.getAssignmentCount();
144917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
145917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
146917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /*
147917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * If params are not in order, we will need register space
148917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * for them before this is all over...
149917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
150917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.regCount = blocks.getRegCount()
151917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                + (paramsAreInOrder ? 0 : this.paramSize);
152917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
153917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.output = new OutputCollector(maxInsns, bsz * 3, regCount);
154917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
155917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (locals != null) {
156917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            this.translationVisitor =
157917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                new LocalVariableAwareTranslationVisitor(output, locals);
158917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        } else {
159917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            this.translationVisitor = new TranslationVisitor(output);
160917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
161917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
162917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
163917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
164917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Checks to see if the move-param instructions that occur in this
165917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * method happen to slot the params in an order at the top of the
166917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * stack frame that matches dalvik's calling conventions. This will
167917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * alway result in "true" for methods that have run through the
168917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * SSA optimizer.
169917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
170917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param paramSize size, in register units, of all the parameters
171917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * to this method
172917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
173917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private static boolean calculateParamsAreInOrder(RopMethod method,
174917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            final int paramSize) {
175917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        final boolean[] paramsAreInOrder = { true };
176917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        final int initialRegCount = method.getBlocks().getRegCount();
177917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
178917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /*
179917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * We almost could just check the first block here, but the
180917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * {@code cf} layer will put in a second move-param in a
181917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * subsequent block in the case of synchronized methods.
182917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
183917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        method.getBlocks().forEachInsn(new Insn.BaseVisitor() {
184917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            public void visitPlainCstInsn(PlainCstInsn insn) {
185917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                if (insn.getOpcode().getOpcode()== RegOps.MOVE_PARAM) {
186917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    int param =
187917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        ((CstInteger) insn.getConstant()).getValue();
188917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
189917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    paramsAreInOrder[0] = paramsAreInOrder[0]
190917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                            && ((initialRegCount - paramSize + param)
191917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                                == insn.getResult().getReg());
192917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
193917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
194917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        });
195917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
196917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return paramsAreInOrder[0];
197917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
198917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
199917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
200917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Does the translation and returns the result.
201917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
202917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return {@code non-null;} the result
203917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
204917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private DalvCode translateAndGetResult() {
205917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        pickOrder();
206917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        outputInstructions();
207917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
208917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        StdCatchBuilder catches =
209917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            new StdCatchBuilder(method, order, addresses);
210917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
211917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return new DalvCode(positionInfo, output.getFinisher(), catches);
212917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
213917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
214917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
215917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Performs initial creation of output instructions based on the
216917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * original blocks.
217917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
218917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private void outputInstructions() {
219917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        BasicBlockList blocks = method.getBlocks();
220917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int[] order = this.order;
221917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int len = order.length;
222917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
223917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        // Process the blocks in output order.
224917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        for (int i = 0; i < len; i++) {
225917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int nextI = i + 1;
226917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int nextLabel = (nextI == order.length) ? -1 : order[nextI];
227917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            outputBlock(blocks.labelToBlock(order[i]), nextLabel);
228917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
229917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
230917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
231917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
232917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Helper for {@link #outputInstructions}, which does the processing
233917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * and output of one block.
234917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
235917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param block {@code non-null;} the block to process and output
236917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param nextLabel {@code >= -1;} the next block that will be processed, or
237917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * {@code -1} if there is no next block
238917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
239917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private void outputBlock(BasicBlock block, int nextLabel) {
240917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        // Append the code address for this block.
241917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        CodeAddress startAddress = addresses.getStart(block);
242917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        output.add(startAddress);
243917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
244917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        // Append the local variable state for the block.
245917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (locals != null) {
246917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            RegisterSpecSet starts = locals.getStarts(block);
247917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            output.add(new LocalSnapshot(startAddress.getPosition(),
248917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                                         starts));
249917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
250917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
251917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /*
252917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * Choose and append an output instruction for each original
253917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * instruction.
254917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
255917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        translationVisitor.setBlock(block, addresses.getLast(block));
256917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        block.getInsns().forEach(translationVisitor);
257917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
258917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        // Insert the block end code address.
259917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        output.add(addresses.getEnd(block));
260917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
261917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        // Set up for end-of-block activities.
262917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
263917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int succ = block.getPrimarySuccessor();
264917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        Insn lastInsn = block.getLastInsn();
265917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
266917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /*
267917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * Check for (and possibly correct for) a non-optimal choice of
268917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * which block will get output next.
269917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
270917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
271917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if ((succ >= 0) && (succ != nextLabel)) {
272917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            /*
273917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * The block has a "primary successor" and that primary
274917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * successor isn't the next block to be output.
275917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             */
276917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            Rop lastRop = lastInsn.getOpcode();
277917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if ((lastRop.getBranchingness() == Rop.BRANCH_IF) &&
278917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    (block.getSecondarySuccessor() == nextLabel)) {
279917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                /*
280917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * The block ends with an "if" of some sort, and its
281917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * secondary successor (the "then") is in fact the
282917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * next block to output. So, reverse the sense of
283917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * the test, so that we can just emit the next block
284917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * without an interstitial goto.
285917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 */
286917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                output.reverseBranch(1, addresses.getStart(succ));
287917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            } else {
288917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                /*
289917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * Our only recourse is to add a goto here to get the
290917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * flow to be correct.
291917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 */
292917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                TargetInsn insn =
293917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    new TargetInsn(Dops.GOTO, lastInsn.getPosition(),
294917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                            RegisterSpecList.EMPTY,
295917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                            addresses.getStart(succ));
296917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                output.add(insn);
297917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
298917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
299917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
300917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
301917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
302917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Picks an order for the blocks by doing "trace" analysis.
303917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
304917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private void pickOrder() {
305917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        BasicBlockList blocks = method.getBlocks();
306917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int sz = blocks.size();
307917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int maxLabel = blocks.getMaxLabel();
308917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int[] workSet = Bits.makeBitSet(maxLabel);
309917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int[] tracebackSet = Bits.makeBitSet(maxLabel);
310917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
311917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        for (int i = 0; i < sz; i++) {
312917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            BasicBlock one = blocks.get(i);
313917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            Bits.set(workSet, one.getLabel());
314917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
315917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
316917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int[] order = new int[sz];
317917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int at = 0;
318917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
319917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /*
320917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * Starting with the designated "first label" (that is, the
321917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * first block of the method), add that label to the order,
322917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * and then pick its first as-yet unordered successor to
323917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * immediately follow it, giving top priority to the primary
324917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * (aka default) successor (if any). Keep following successors
325917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * until the trace runs out of possibilities. Then, continue
326917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * by finding an unordered chain containing the first as-yet
327917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * unordered block, and adding it to the order, and so on.
328917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
329917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        for (int label = method.getFirstLabel();
330917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             label != -1;
331917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             label = Bits.findFirst(workSet, 0)) {
332917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
333917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            /*
334917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * Attempt to trace backward from the chosen block to an
335917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * as-yet unordered predecessor which lists the chosen
336917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * block as its primary successor, and so on, until we
337917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * fail to find such an unordered predecessor. Start the
338917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * trace with that block. Note that the first block in the
339917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * method has no predecessors, so in that case this loop
340917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * will simply terminate with zero iterations and without
341917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * picking a new starter block.
342917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             */
343917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            traceBack:
344917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            for (;;) {
345917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                IntList preds = method.labelToPredecessors(label);
346917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                int psz = preds.size();
347917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
348917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                for (int i = 0; i < psz; i++) {
349917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    int predLabel = preds.get(i);
350917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
351917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    if (Bits.get(tracebackSet, predLabel)) {
352917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        /*
353917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                         * We found a predecessor loop; stop tracing back
354917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                         * from here.
355917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                         */
356917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        break;
357917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    }
358917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
359917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    if (!Bits.get(workSet, predLabel)) {
360917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        // This one's already ordered.
361917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        continue;
362917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    }
363917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
364917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    BasicBlock pred = blocks.labelToBlock(predLabel);
365917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    if (pred.getPrimarySuccessor() == label) {
366917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        // Found one!
367917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        label = predLabel;
368917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        Bits.set(tracebackSet, label);
369917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        continue traceBack;
370917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    }
371917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
372917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
373917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                // Failed to find a better block to start the trace.
374917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                break;
375917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
376917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
377917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            /*
378917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * Trace a path from the chosen block to one of its
379917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * unordered successors (hopefully the primary), and so
380917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * on, until we run out of unordered successors.
381917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             */
382917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            while (label != -1) {
383917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                Bits.clear(workSet, label);
384917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                Bits.clear(tracebackSet, label);
385917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                order[at] = label;
386917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                at++;
387917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
388917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                BasicBlock one = blocks.labelToBlock(label);
389917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                BasicBlock preferredBlock = blocks.preferredSuccessorOf(one);
390917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
391917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                if (preferredBlock == null) {
392917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    break;
393917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
394917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
395917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                int preferred = preferredBlock.getLabel();
396917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                int primary = one.getPrimarySuccessor();
397917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
398917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                if (Bits.get(workSet, preferred)) {
399917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    /*
400917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                     * Order the current block's preferred successor
401917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                     * next, as it has yet to be scheduled.
402917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                     */
403917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    label = preferred;
404917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                } else if ((primary != preferred) && (primary >= 0)
405917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        && Bits.get(workSet, primary)) {
406917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    /*
407917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                     * The primary is available, so use that.
408917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                     */
409917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    label = primary;
410917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                } else {
411917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    /*
412917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                     * There's no obvious candidate, so pick the first
413917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                     * one that's available, if any.
414917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                     */
415917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    IntList successors = one.getSuccessors();
416917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    int ssz = successors.size();
417917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    label = -1;
418917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    for (int i = 0; i < ssz; i++) {
419917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        int candidate = successors.get(i);
420917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        if (Bits.get(workSet, candidate)) {
421917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                            label = candidate;
422917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                            break;
423917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        }
424917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    }
425917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
426917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
427917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
428917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
429917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (at != sz) {
430917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            // There was a duplicate block label.
431917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            throw new RuntimeException("shouldn't happen");
432917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
433917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
434917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        this.order = order;
435917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
436917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
437917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
438917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Gets the complete register list (result and sources) out of a
439917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * given rop instruction. For insns that are commutative, have
440917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * two register sources, and have a source equal to the result,
441917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * place that source first.
442917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
443917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param insn {@code non-null;} instruction in question
444917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return {@code non-null;} the instruction's complete register list
445917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
446917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private static RegisterSpecList getRegs(Insn insn) {
447917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return getRegs(insn, insn.getResult());
448917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
449917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
450917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
451917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Gets the complete register list (result and sources) out of a
452917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * given rop instruction. For insns that are commutative, have
453917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * two register sources, and have a source equal to the result,
454917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * place that source first.
455917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
456917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param insn {@code non-null;} instruction in question
457917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param resultReg {@code null-ok;} the real result to use (ignore the insn's)
458917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return {@code non-null;} the instruction's complete register list
459917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
460917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private static RegisterSpecList getRegs(Insn insn,
461917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            RegisterSpec resultReg) {
462917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        RegisterSpecList regs = insn.getSources();
463917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
464917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (insn.getOpcode().isCommutative()
465917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                && (regs.size() == 2)
466917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                && (resultReg.getReg() == regs.get(1).getReg())) {
467917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
468917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            /*
469917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * For commutative ops which have two register sources,
470917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * if the second source is the same register as the result,
471917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * swap the sources so that an opcode of form 12x can be selected
472917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * instead of one of form 23x
473917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             */
474917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
475917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            regs = RegisterSpecList.make(regs.get(1), regs.get(0));
476917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
477917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
478917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (resultReg == null) {
479917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            return regs;
480917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
481917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
482917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return regs.withFirst(resultReg);
483917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
484917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
485917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
486917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Instruction visitor class for doing the instruction translation per se.
487917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
488917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private class TranslationVisitor implements Insn.Visitor {
489917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /** {@code non-null;} list of output instructions in-progress */
490917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        private final OutputCollector output;
491917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
492917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /** {@code non-null;} basic block being worked on */
493917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        private BasicBlock block;
494917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
495917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /**
496917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * {@code null-ok;} code address for the salient last instruction of the
497917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * block (used before switches and throwing instructions)
498917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
499917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        private CodeAddress lastAddress;
500917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
501917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /**
502917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * Constructs an instance.
503917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         *
504917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @param output {@code non-null;} destination for instruction output
505917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
506917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public TranslationVisitor(OutputCollector output) {
507917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            this.output = output;
508917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
509917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
510917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /**
511917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * Sets the block currently being worked on.
512917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         *
513917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @param block {@code non-null;} the block
514917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @param lastAddress {@code non-null;} code address for the salient
515917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * last instruction of the block
516917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
517917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public void setBlock(BasicBlock block, CodeAddress lastAddress) {
518917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            this.block = block;
519917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            this.lastAddress = lastAddress;
520917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
521917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
522917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /** {@inheritDoc} */
523917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public void visitPlainInsn(PlainInsn insn) {
524917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            Rop rop = insn.getOpcode();
525917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (rop.getOpcode() == RegOps.MARK_LOCAL) {
526917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                /*
527917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * Ignore these. They're dealt with by
528917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * the LocalVariableAwareTranslationVisitor
529917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 */
530917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                return;
531917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
532917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (rop.getOpcode() == RegOps.MOVE_RESULT_PSEUDO) {
533917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                // These get skipped
534917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                return;
535917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
536917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
537917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            SourcePosition pos = insn.getPosition();
538917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            Dop opcode = RopToDop.dopFor(insn);
539917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            DalvInsn di;
540917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
541917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            switch (rop.getBranchingness()) {
542917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                case Rop.BRANCH_NONE:
543917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                case Rop.BRANCH_RETURN:
544917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                case Rop.BRANCH_THROW: {
545917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    di = new SimpleInsn(opcode, pos, getRegs(insn));
546917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    break;
547917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
548917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                case Rop.BRANCH_GOTO: {
549917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    /*
550917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                     * Code in the main translation loop will emit a
551917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                     * goto if necessary (if the branch isn't to the
552917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                     * immediately subsequent block).
553917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                     */
554917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    return;
555917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
556917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                case Rop.BRANCH_IF: {
557917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    int target = block.getSuccessors().get(1);
558917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    di = new TargetInsn(opcode, pos, getRegs(insn),
559917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                                        addresses.getStart(target));
560917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    break;
561917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
562917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                default: {
563917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    throw new RuntimeException("shouldn't happen");
564917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
565917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
566917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
567917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            addOutput(di);
568917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
569917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
570917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /** {@inheritDoc} */
571917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public void visitPlainCstInsn(PlainCstInsn insn) {
572917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            SourcePosition pos = insn.getPosition();
573917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            Dop opcode = RopToDop.dopFor(insn);
574917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            Rop rop = insn.getOpcode();
575917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int ropOpcode = rop.getOpcode();
576917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            DalvInsn di;
577917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
578917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (rop.getBranchingness() != Rop.BRANCH_NONE) {
579917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                throw new RuntimeException("shouldn't happen");
580917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
581917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
582917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (ropOpcode == RegOps.MOVE_PARAM) {
583917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                if (!paramsAreInOrder) {
584917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    /*
585917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                     * Parameters are not in order at the top of the reg space.
586917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                     * We need to add moves.
587917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                     */
588917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
589917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    RegisterSpec dest = insn.getResult();
590917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    int param =
591917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        ((CstInteger) insn.getConstant()).getValue();
592917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    RegisterSpec source =
593917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        RegisterSpec.make(regCount - paramSize + param,
594917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                                dest.getType());
595917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    di = new SimpleInsn(opcode, pos,
596917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                                        RegisterSpecList.make(dest, source));
597917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    addOutput(di);
598917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
599917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            } else {
600917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                // No moves required for the parameters
601917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                RegisterSpecList regs = getRegs(insn);
602917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                di = new CstInsn(opcode, pos, regs, insn.getConstant());
603917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                addOutput(di);
604917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
605917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
606917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
607917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /** {@inheritDoc} */
608917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public void visitSwitchInsn(SwitchInsn insn) {
609917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            SourcePosition pos = insn.getPosition();
610917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            IntList cases = insn.getCases();
611917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            IntList successors = block.getSuccessors();
612917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int casesSz = cases.size();
613917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int succSz = successors.size();
614917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int primarySuccessor = block.getPrimarySuccessor();
615917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
616917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            /*
617917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * Check the assumptions that the number of cases is one
618917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * less than the number of successors and that the last
619917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * successor in the list is the primary (in this case, the
620917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * default). This test is here to guard against forgetting
621917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * to change this code if the way switch instructions are
622917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * constructed also gets changed.
623917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             */
624917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if ((casesSz != (succSz - 1)) ||
625917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                (primarySuccessor != successors.get(casesSz))) {
626917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                throw new RuntimeException("shouldn't happen");
627917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
628917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
629917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            CodeAddress[] switchTargets = new CodeAddress[casesSz];
630917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
631917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            for (int i = 0; i < casesSz; i++) {
632917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                int label = successors.get(i);
633917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                switchTargets[i] = addresses.getStart(label);
634917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
635917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
636917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            CodeAddress dataAddress = new CodeAddress(pos);
637917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            SwitchData dataInsn =
638917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                new SwitchData(pos, lastAddress, cases, switchTargets);
639917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            Dop opcode = dataInsn.isPacked() ?
640917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                Dops.PACKED_SWITCH : Dops.SPARSE_SWITCH;
641917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            TargetInsn switchInsn =
642917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                new TargetInsn(opcode, pos, getRegs(insn), dataAddress);
643917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
644917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            addOutput(lastAddress);
645917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            addOutput(switchInsn);
646917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
647917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            addOutputSuffix(new OddSpacer(pos));
648917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            addOutputSuffix(dataAddress);
649917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            addOutputSuffix(dataInsn);
650917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
651917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
652917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /**
653917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * Looks forward to the current block's primary successor, returning
654917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * the RegisterSpec of the result of the move-result-pseudo at the
655917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * top of that block or null if none.
656917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         *
657917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @return {@code null-ok;} result of move-result-pseudo at the beginning of
658917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * primary successor
659917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
660917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        private RegisterSpec getNextMoveResultPseudo()
661917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        {
662917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int label = block.getPrimarySuccessor();
663917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
664917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (label < 0) {
665917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                return null;
666917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
667917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
668917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            Insn insn
669917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    = method.getBlocks().labelToBlock(label).getInsns().get(0);
670917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
671917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (insn.getOpcode().getOpcode() != RegOps.MOVE_RESULT_PSEUDO) {
672917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                return null;
673917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            } else {
674917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                return insn.getResult();
675917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
676917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
677917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
678917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /** {@inheritDoc} */
679917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public void visitThrowingCstInsn(ThrowingCstInsn insn) {
680917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            SourcePosition pos = insn.getPosition();
681917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            Dop opcode = RopToDop.dopFor(insn);
682917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            Rop rop = insn.getOpcode();
683917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            Constant cst = insn.getConstant();
684917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
685917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (rop.getBranchingness() != Rop.BRANCH_THROW) {
686917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                throw new RuntimeException("shouldn't happen");
687917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
688917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
689917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            addOutput(lastAddress);
690917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
691917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (rop.isCallLike()) {
692917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                RegisterSpecList regs = insn.getSources();
693917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                DalvInsn di = new CstInsn(opcode, pos, regs, cst);
694917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
695917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                addOutput(di);
696917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            } else {
697917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                RegisterSpec realResult = getNextMoveResultPseudo();
698917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
699917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                RegisterSpecList regs = getRegs(insn, realResult);
700917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                DalvInsn di;
701917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
702917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                boolean hasResult = opcode.hasResult()
703917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        || (rop.getOpcode() == RegOps.CHECK_CAST);
704917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
705917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                if (hasResult != (realResult != null)) {
706917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    throw new RuntimeException(
707917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                            "Insn with result/move-result-pseudo mismatch " +
708917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                            insn);
709917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
710917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
711917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                if ((rop.getOpcode() == RegOps.NEW_ARRAY) &&
712917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    (opcode.getOpcode() != DalvOps.NEW_ARRAY)) {
713917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    /*
714917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                     * It's a type-specific new-array-<primitive>, and
715917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                     * so it should be turned into a SimpleInsn (no
716917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                     * constant ref as it's implicit).
717917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                     */
718917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    di = new SimpleInsn(opcode, pos, regs);
719917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                } else {
720917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    /*
721917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                     * This is the general case for constant-bearing
722917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                     * instructions.
723917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                     */
724917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    di = new CstInsn(opcode, pos, regs, cst);
725917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
726917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
727917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                addOutput(di);
728917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
729917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
730917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
731917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /** {@inheritDoc} */
732917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public void visitThrowingInsn(ThrowingInsn insn) {
733917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            SourcePosition pos = insn.getPosition();
734917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            Dop opcode = RopToDop.dopFor(insn);
735917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            Rop rop = insn.getOpcode();
736917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            RegisterSpec realResult;
737917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
738917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (rop.getBranchingness() != Rop.BRANCH_THROW) {
739917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                throw new RuntimeException("shouldn't happen");
740917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
741917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
742917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            realResult = getNextMoveResultPseudo();
743917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
744917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (opcode.hasResult() != (realResult != null)) {
745917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                throw new RuntimeException(
746917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        "Insn with result/move-result-pseudo mismatch" + insn);
747917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
748917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
749917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            addOutput(lastAddress);
750917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
751917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            DalvInsn di = new SimpleInsn(opcode, pos,
752917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    getRegs(insn, realResult));
753917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
754917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            addOutput(di);
755917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
756917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
757917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /** {@inheritDoc} */
758917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public void visitFillArrayDataInsn(FillArrayDataInsn insn) {
759917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            SourcePosition pos = insn.getPosition();
760917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            Constant cst = insn.getConstant();
761917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            ArrayList<Constant> values = insn.getInitValues();
762917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            Rop rop = insn.getOpcode();
763917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
764917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (rop.getBranchingness() != Rop.BRANCH_NONE) {
765917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                throw new RuntimeException("shouldn't happen");
766917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
767917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            CodeAddress dataAddress = new CodeAddress(pos);
768917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            ArrayData dataInsn =
769917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                new ArrayData(pos, lastAddress, values, cst);
770917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
771917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            TargetInsn fillArrayDataInsn =
772917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                new TargetInsn(Dops.FILL_ARRAY_DATA, pos, getRegs(insn),
773917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        dataAddress);
774917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
775917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            addOutput(lastAddress);
776917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            addOutput(fillArrayDataInsn);
777917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
778917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            addOutputSuffix(new OddSpacer(pos));
779917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            addOutputSuffix(dataAddress);
780917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            addOutputSuffix(dataInsn);
781917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
782917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
783917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /**
784917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * Adds to the output.
785917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         *
786917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @param insn {@code non-null;} instruction to add
787917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
788917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        protected void addOutput(DalvInsn insn) {
789917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            output.add(insn);
790917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
791917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
792917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /**
793917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * Adds to the output suffix.
794917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         *
795917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @param insn {@code non-null;} instruction to add
796917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
797917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        protected void addOutputSuffix(DalvInsn insn) {
798917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            output.addSuffix(insn);
799917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
800917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
801917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
802917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
803917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Instruction visitor class for doing instruction translation with
804917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * local variable tracking
805917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
806917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private class LocalVariableAwareTranslationVisitor
807917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            extends TranslationVisitor {
808917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /** {@code non-null;} local variable info */
809917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        private LocalVariableInfo locals;
810917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
811917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /**
812917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * Constructs an instance.
813917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         *
814917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @param output {@code non-null;} destination for instruction output
815917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @param locals {@code non-null;} the local variable info
816917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
817917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public LocalVariableAwareTranslationVisitor(OutputCollector output,
818917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                                                    LocalVariableInfo locals) {
819917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            super(output);
820917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            this.locals = locals;
821917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
822917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
823917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /** {@inheritDoc} */
824917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        @Override
825917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public void visitPlainInsn(PlainInsn insn) {
826917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            super.visitPlainInsn(insn);
827917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            addIntroductionIfNecessary(insn);
828917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
829917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
830917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /** {@inheritDoc} */
831917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        @Override
832917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public void visitPlainCstInsn(PlainCstInsn insn) {
833917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            super.visitPlainCstInsn(insn);
834917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            addIntroductionIfNecessary(insn);
835917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
836917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
837917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /** {@inheritDoc} */
838917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        @Override
839917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public void visitSwitchInsn(SwitchInsn insn) {
840917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            super.visitSwitchInsn(insn);
841917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            addIntroductionIfNecessary(insn);
842917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
843917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
844917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /** {@inheritDoc} */
845917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        @Override
846917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public void visitThrowingCstInsn(ThrowingCstInsn insn) {
847917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            super.visitThrowingCstInsn(insn);
848917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            addIntroductionIfNecessary(insn);
849917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
850917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
851917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /** {@inheritDoc} */
852917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        @Override
853917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public void visitThrowingInsn(ThrowingInsn insn) {
854917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            super.visitThrowingInsn(insn);
855917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            addIntroductionIfNecessary(insn);
856917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
857917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
858917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /**
859917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * Adds a {@link LocalStart} to the output if the given
860917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * instruction in fact introduces a local variable.
861917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         *
862917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @param insn {@code non-null;} instruction in question
863917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
864917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public void addIntroductionIfNecessary(Insn insn) {
865917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            RegisterSpec spec = locals.getAssignment(insn);
866917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
867917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (spec != null) {
868917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                addOutput(new LocalStart(insn.getPosition(), spec));
869917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
870917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
871917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
872917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul}
873