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.rop.code;
18
19import com.android.dx.rop.cst.CstInteger;
20import com.android.dx.rop.type.Type;
21
22/**
23 * Implementation of {@link TranslationAdvice} which represents what
24 * the dex format will be able to represent.
25 */
26public final class DexTranslationAdvice
27        implements TranslationAdvice {
28    /** non-null; standard instance of this class */
29    public static final DexTranslationAdvice THE_ONE =
30        new DexTranslationAdvice();
31
32    /** debug advice for disabling invoke-range optimization */
33    public static final DexTranslationAdvice NO_SOURCES_IN_ORDER =
34        new DexTranslationAdvice(true);
35
36    /**
37     * The minimum source width, in register units, for an invoke
38     * instruction that requires its sources to be in order and contiguous.
39     */
40    private static final int MIN_INVOKE_IN_ORDER = 6;
41
42    /** when true: always returns false for requiresSourcesInOrder */
43    private final boolean disableSourcesInOrder;
44
45    /**
46     * This class is not publicly instantiable. Use {@link #THE_ONE}.
47     */
48    private DexTranslationAdvice() {
49        disableSourcesInOrder = false;
50    }
51
52    private DexTranslationAdvice(boolean disableInvokeRange) {
53        this.disableSourcesInOrder = disableInvokeRange;
54    }
55
56    /** {@inheritDoc} */
57    public boolean hasConstantOperation(Rop opcode,
58            RegisterSpec sourceA, RegisterSpec sourceB) {
59        if (sourceA.getType() != Type.INT) {
60            return false;
61        }
62
63        if (! (sourceB.getTypeBearer() instanceof CstInteger)) {
64            return false;
65        }
66
67        CstInteger cst = (CstInteger) sourceB.getTypeBearer();
68
69        // TODO handle rsub
70        switch (opcode.getOpcode()) {
71            // These have 8 and 16 bit cst representations
72            case RegOps.REM:
73            case RegOps.ADD:
74            case RegOps.MUL:
75            case RegOps.DIV:
76            case RegOps.AND:
77            case RegOps.OR:
78            case RegOps.XOR:
79                return cst.fitsIn16Bits();
80            // These only have 8 bit cst reps
81            case RegOps.SHL:
82            case RegOps.SHR:
83            case RegOps.USHR:
84                return cst.fitsIn8Bits();
85            default:
86                return false;
87        }
88    }
89
90    /** {@inheritDoc} */
91    public boolean requiresSourcesInOrder(Rop opcode,
92            RegisterSpecList sources) {
93
94        return !disableSourcesInOrder && opcode.isCallLike()
95                && totalRopWidth(sources) >= MIN_INVOKE_IN_ORDER;
96    }
97
98    /**
99     * Calculates the total rop width of the list of SSA registers
100     *
101     * @param sources non-null; list of SSA registers
102     * @return >= 0 rop-form width in register units
103     */
104    private int totalRopWidth(RegisterSpecList sources) {
105        int sz = sources.size();
106        int total = 0;
107
108        for (int i = 0; i < sz; i++) {
109            total += sources.get(i).getCategory();
110        }
111
112        return total;
113    }
114
115    /** {@inheritDoc} */
116    public int getMaxOptimalRegisterCount() {
117        return 16;
118    }
119}
120