Optimizer.java revision de75089fb7216d19e9c22cce4dc62a49513477d3
1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.dx.ssa;
18
19import com.android.dx.rop.code.RopMethod;
20import com.android.dx.rop.code.TranslationAdvice;
21import com.android.dx.ssa.back.SsaToRop;
22import com.android.dx.ssa.back.LivenessAnalyzer;
23
24import java.util.EnumSet;
25import java.util.BitSet;
26import java.util.ArrayList;
27
28/**
29 * Runs a method through the SSA form conversion, any optimization algorithms,
30 * and returns it to rop form.
31 */
32public class Optimizer {
33    private static boolean preserveLocals = true;
34
35    private static TranslationAdvice advice;
36
37    /** optional optimizer steps */
38    public enum OptionalStep {
39        MOVE_PARAM_COMBINER,SCCP,LITERAL_UPGRADE,CONST_COLLECTOR
40    }
41
42    /**
43     * @return true if local variable information should be preserved, even
44     * at code size/register size cost
45     */
46    public static boolean getPreserveLocals() {
47        return preserveLocals;
48    }
49
50    /**
51     * @return {@code non-null;} translation advice
52     */
53    public static TranslationAdvice getAdvice() {
54        return advice;
55    }
56
57    /**
58     * Runs optimization algorthims over this method, and returns a new
59     * instance of RopMethod with the changes.
60     *
61     * @param rmeth method to process
62     * @param paramWidth the total width, in register-units, of this method's
63     * parameters
64     * @param isStatic true if this method has no 'this' pointer argument.
65     * @param inPreserveLocals true if local variable info should be preserved,
66     * at the cost of some registers and insns
67     * @param inAdvice {@code non-null;} translation advice
68     * @return optimized method
69     */
70    public static RopMethod optimize(RopMethod rmeth, int paramWidth,
71            boolean isStatic, boolean inPreserveLocals,
72            TranslationAdvice inAdvice) {
73
74        return optimize(rmeth, paramWidth, isStatic, inPreserveLocals, inAdvice,
75                EnumSet.allOf(OptionalStep.class));
76    }
77
78    /**
79     * Runs optimization algorthims over this method, and returns a new
80     * instance of RopMethod with the changes.
81     *
82     * @param rmeth method to process
83     * @param paramWidth the total width, in register-units, of this method's
84     * parameters
85     * @param isStatic true if this method has no 'this' pointer argument.
86     * @param inPreserveLocals true if local variable info should be preserved,
87     * at the cost of some registers and insns
88     * @param inAdvice {@code non-null;} translation advice
89     * @param steps set of optional optimization steps to run
90     * @return optimized method
91     */
92    public static RopMethod optimize(RopMethod rmeth, int paramWidth,
93            boolean isStatic, boolean inPreserveLocals,
94            TranslationAdvice inAdvice, EnumSet<OptionalStep> steps) {
95        SsaMethod ssaMeth = null;
96
97        preserveLocals = inPreserveLocals;
98        advice = inAdvice;
99
100        ssaMeth = SsaConverter.convertToSsaMethod(rmeth, paramWidth, isStatic);
101        runSsaFormSteps(ssaMeth, steps);
102
103        RopMethod resultMeth = SsaToRop.convertToRopMethod(ssaMeth, false);
104
105        if (resultMeth.getBlocks().getRegCount()
106                > advice.getMaxOptimalRegisterCount()) {
107            // Try to see if we can squeeze it under the register count bar
108            resultMeth = optimizeMinimizeRegisters(rmeth, paramWidth, isStatic,
109                    steps);
110        }
111        return resultMeth;
112    }
113
114    /**
115     * Runs the optimizer with a strategy to minimize the number of rop-form
116     * registers used by the end result. Dex bytecode does not have instruction
117     * forms that take register numbers larger than 15 for all instructions.
118     * If we've produced a method that uses more than 16 registers, try again
119     * with a different strategy to see if we can get under the bar. The end
120     * result will be much more efficient.
121     *
122     * @param rmeth method to process
123     * @param paramWidth the total width, in register-units, of this method's
124     * parameters
125     * @param isStatic true if this method has no 'this' pointer argument.
126     * @param steps set of optional optimization steps to run
127     * @return optimized method
128     */
129    private static RopMethod optimizeMinimizeRegisters(RopMethod rmeth,
130            int paramWidth, boolean isStatic,
131            EnumSet<OptionalStep> steps) {
132        SsaMethod ssaMeth;
133        RopMethod resultMeth;
134
135        ssaMeth = SsaConverter.convertToSsaMethod(
136                rmeth, paramWidth, isStatic);
137
138        EnumSet<OptionalStep> newSteps = steps.clone();
139
140        /*
141         * CONST_COLLECTOR trades insns for registers, which is not an
142         * appropriate strategy here.
143         */
144        newSteps.remove(OptionalStep.CONST_COLLECTOR);
145
146        runSsaFormSteps(ssaMeth, newSteps);
147
148        resultMeth = SsaToRop.convertToRopMethod(ssaMeth, true);
149        return resultMeth;
150    }
151
152    private static void runSsaFormSteps(SsaMethod ssaMeth,
153            EnumSet<OptionalStep> steps) {
154        boolean needsDeadCodeRemover = true;
155
156        if (steps.contains(OptionalStep.MOVE_PARAM_COMBINER)) {
157            MoveParamCombiner.process(ssaMeth);
158        }
159
160        if (steps.contains(OptionalStep.SCCP)) {
161            SCCP.process(ssaMeth);
162        }
163
164        if (steps.contains(OptionalStep.LITERAL_UPGRADE)) {
165            LiteralOpUpgrader.process(ssaMeth);
166            DeadCodeRemover.process(ssaMeth);
167            needsDeadCodeRemover = false;
168        }
169
170        if (steps.contains(OptionalStep.CONST_COLLECTOR)) {
171            ConstCollector.process(ssaMeth);
172            DeadCodeRemover.process(ssaMeth);
173            needsDeadCodeRemover = false;
174        }
175
176        // dead code remover must be run before phi type resolver
177        if (needsDeadCodeRemover) {
178            DeadCodeRemover.process(ssaMeth);
179        }
180
181        PhiTypeResolver.process(ssaMeth);
182    }
183
184    public static SsaMethod debugEdgeSplit(RopMethod rmeth, int paramWidth,
185            boolean isStatic, boolean inPreserveLocals,
186            TranslationAdvice inAdvice) {
187
188        preserveLocals = inPreserveLocals;
189        advice = inAdvice;
190
191        return SsaConverter.testEdgeSplit(rmeth, paramWidth, isStatic);
192    }
193
194    public static SsaMethod debugPhiPlacement(RopMethod rmeth, int paramWidth,
195            boolean isStatic, boolean inPreserveLocals,
196            TranslationAdvice inAdvice) {
197
198        preserveLocals = inPreserveLocals;
199        advice = inAdvice;
200
201        return SsaConverter.testPhiPlacement(rmeth, paramWidth, isStatic);
202    }
203
204    public static SsaMethod debugRenaming(RopMethod rmeth, int paramWidth,
205            boolean isStatic, boolean inPreserveLocals,
206            TranslationAdvice inAdvice) {
207
208        preserveLocals = inPreserveLocals;
209        advice = inAdvice;
210
211        return SsaConverter.convertToSsaMethod(rmeth, paramWidth, isStatic);
212    }
213
214    public static SsaMethod debugDeadCodeRemover(RopMethod rmeth,
215            int paramWidth, boolean isStatic, boolean inPreserveLocals,
216            TranslationAdvice inAdvice) {
217
218        SsaMethod ssaMeth;
219
220        preserveLocals = inPreserveLocals;
221        advice = inAdvice;
222
223        ssaMeth = SsaConverter.convertToSsaMethod(rmeth, paramWidth, isStatic);
224        DeadCodeRemover.process(ssaMeth);
225
226        return ssaMeth;
227    }
228
229    public static SsaMethod debugNoRegisterAllocation(RopMethod rmeth,
230            int paramWidth, boolean isStatic, boolean inPreserveLocals,
231            TranslationAdvice inAdvice, EnumSet<OptionalStep> steps) {
232
233        SsaMethod ssaMeth;
234
235        preserveLocals = inPreserveLocals;
236        advice = inAdvice;
237
238        ssaMeth = SsaConverter.convertToSsaMethod(rmeth, paramWidth, isStatic);
239
240        runSsaFormSteps(ssaMeth, steps);
241
242        LivenessAnalyzer.constructInterferenceGraph(ssaMeth);
243
244        return ssaMeth;
245    }
246}
247