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.TranslationAdvice;
20import com.android.dx.rop.code.RegisterSpecList;
21import com.android.dx.rop.code.Insn;
22import com.android.dx.rop.code.Rop;
23import com.android.dx.rop.code.RegisterSpec;
24import com.android.dx.rop.code.PlainInsn;
25import com.android.dx.rop.code.Rops;
26import com.android.dx.rop.code.RegOps;
27import com.android.dx.rop.cst.CstLiteralBits;
28import com.android.dx.rop.type.TypeBearer;
29
30import java.util.List;
31
32/**
33 * Upgrades insn to their literal (constant-immediate) equivilent if possible.
34 * Also switches IF instructions that compare with a constant zero or null
35 * to be their IF_*Z equivalents.
36 */
37public class LiteralOpUpgrader {
38
39    /** method we're processing */
40    private final SsaMethod ssaMeth;
41
42    /**
43     * Process a method.
44     *
45     * @param ssaMethod {@code non-null;} method to process
46     */
47    public static void process(SsaMethod ssaMethod) {
48        LiteralOpUpgrader dc;
49
50        dc = new LiteralOpUpgrader(ssaMethod);
51
52        dc.run();
53    }
54
55    private LiteralOpUpgrader(SsaMethod ssaMethod) {
56        this.ssaMeth = ssaMethod;
57    }
58
59    /**
60     * Returns true if the register contains an integer 0 or a known-null
61     * object reference
62     *
63     * @param spec non-null spec
64     * @return true for 0 or null type bearers
65     */
66    private static boolean isConstIntZeroOrKnownNull(RegisterSpec spec) {
67        TypeBearer tb = spec.getTypeBearer();
68        if (tb instanceof CstLiteralBits) {
69            CstLiteralBits clb = (CstLiteralBits) tb;
70            return (clb.getLongBits() == 0);
71        }
72        return false;
73    }
74
75    /**
76     * Run the literal op upgrader
77     */
78    private void run() {
79        final TranslationAdvice advice = Optimizer.getAdvice();
80
81        ssaMeth.forEachInsn(new SsaInsn.Visitor() {
82            public void visitMoveInsn(NormalSsaInsn insn) {
83                // do nothing
84            }
85
86            public void visitPhiInsn(PhiInsn insn) {
87                // do nothing
88            }
89
90            public void visitNonMoveInsn(NormalSsaInsn insn) {
91
92                Insn originalRopInsn = insn.getOriginalRopInsn();
93                Rop opcode = originalRopInsn.getOpcode();
94                RegisterSpecList sources = insn.getSources();
95
96                if (sources.size() != 2 ) {
97                    // We're only dealing with two-source insns here.
98                    return;
99                }
100
101                if (opcode.getBranchingness() == Rop.BRANCH_IF) {
102                    /*
103                     * An if instruction can become an if-*z instruction.
104                     */
105                    if (isConstIntZeroOrKnownNull(sources.get(0))) {
106                        replacePlainInsn(insn, sources.withoutFirst(),
107                                RegOps.flippedIfOpcode(opcode.getOpcode()));
108                    } else if (isConstIntZeroOrKnownNull(sources.get(1))) {
109                        replacePlainInsn(insn, sources.withoutLast(),
110                                opcode.getOpcode());
111                    }
112                } else if (advice.hasConstantOperation(
113                        opcode, sources.get(0), sources.get(1))) {
114                    insn.upgradeToLiteral();
115                } else  if (opcode.isCommutative()
116                        && advice.hasConstantOperation(
117                        opcode, sources.get(1), sources.get(0))) {
118                    /*
119                     * An instruction can be commuted to a literal operation
120                     */
121
122                    insn.setNewSources(
123                            RegisterSpecList.make(
124                                    sources.get(1), sources.get(0)));
125
126                    insn.upgradeToLiteral();
127                }
128            }
129        });
130    }
131
132    /**
133     * Replaces an SsaInsn containing a PlainInsn with a new PlainInsn. The
134     * new PlainInsn is contructed with a new RegOp and new sources.
135     *
136     * TODO move this somewhere else.
137     *
138     * @param insn {@code non-null;} an SsaInsn containing a PlainInsn
139     * @param newSources {@code non-null;} new sources list for new insn
140     * @param newOpcode A RegOp from {@link RegOps}
141     */
142    private void replacePlainInsn(NormalSsaInsn insn,
143            RegisterSpecList newSources, int newOpcode) {
144
145        Insn originalRopInsn = insn.getOriginalRopInsn();
146        Rop newRop = Rops.ropFor(newOpcode,
147                insn.getResult(), newSources, null);
148        Insn newRopInsn = new PlainInsn(newRop,
149                originalRopInsn.getPosition(), insn.getResult(),
150                newSources);
151        NormalSsaInsn newInsn
152                = new NormalSsaInsn(newRopInsn, insn.getBlock());
153
154        List<SsaInsn> insns = insn.getBlock().getInsns();
155
156        ssaMeth.onInsnRemoved(insn);
157        insns.set(insns.lastIndexOf(insn), newInsn);
158        ssaMeth.onInsnAdded(newInsn);
159    }
160}
161