SsaInsn.java revision f6c387128427e121477c1b32ad35cdcaa5101ba3
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.*;
20import com.android.dx.util.ToHuman;
21
22/**
23 * An instruction in SSA form
24 */
25public abstract class SsaInsn implements ToHuman, Cloneable {
26
27    protected RegisterSpec result;
28    protected final SsaBasicBlock block;
29
30    /**
31     * Constructs an instance
32     * @param block block containing this insn. Can never change.
33     */
34    protected SsaInsn(final SsaBasicBlock block) {
35        this.block = block;
36    }
37
38    /**
39     * Makes a new SSA insn form a ROP insn
40     *
41     * @param insn non-null; rop insn
42     * @param block non-null; owning block
43     * @return non-null; an appropriately constructed instance
44     */
45    public static SsaInsn makeFromRop(Insn insn, SsaBasicBlock block) {
46        return new NormalSsaInsn(insn, block);
47    }
48
49    /** {@inheritDoc} */
50    @Override
51    public SsaInsn clone() {
52        try {
53            return (SsaInsn)super.clone();
54        } catch (CloneNotSupportedException ex) {
55            throw new RuntimeException ("unexpected", ex);
56        }
57    }
58
59    /**
60     * Like {@link com.android.dx.rop.code.Insn getResult()}.
61     * @return result register
62     */
63    public RegisterSpec getResult() {
64        return result;
65    }
66
67    /**
68     * Like {@link com.android.dx.rop.code.Insn getSources()}.
69     * @return non-null; sources list
70     */
71    abstract public RegisterSpecList getSources();
72
73    /**
74     * Gets the block to which this insn instance belongs.
75     *
76     * @return owning block
77     */
78    public SsaBasicBlock getBlock() {
79        return block;
80    }
81
82    /**
83     * is the specified reg the result reg?
84     * @param reg register to test
85     * @return true if there is a result and it is stored in the specified
86     * register
87     */
88    public boolean isResultReg(int reg) {
89        return result != null && result.getReg() == reg;
90    }
91
92
93    /**
94     * Changes the result register if this insn has a result.
95     * Used during renaming.
96     * @param reg new result register.
97     */
98    public void changeResultReg(int reg) {
99        if (result != null) {
100            result = result.withReg(reg);
101        }
102    }
103
104    /**
105     * Sets the local association for the result of this insn.
106     * This is sometimes updated during the SsaRenamer process.
107     *
108     * @param local null-ok; New debug/local variable info.
109     */
110    public final void setResultLocal(LocalItem local) {
111        LocalItem oldItem = result.getLocalItem();
112
113        if (local != oldItem && (local == null
114                || !local.equals(result.getLocalItem()))) {
115            result = RegisterSpec.makeLocalOptional(
116                    result.getReg(), result.getType(), local);
117        }
118    }
119
120    /**
121     * Map registers after register allocation.
122     *
123     * @param mapper
124     */
125    public final void mapRegisters(RegisterMapper mapper) {
126        RegisterSpec oldResult = result;
127        result = mapper.map(result);
128        block.getParent().updateOneDefinition(this, oldResult);
129        mapSourceRegisters(mapper);
130    }
131
132    /**
133     * Maps only source registers.
134     *
135     * @param mapper new mapping
136     */
137    abstract public void mapSourceRegisters(RegisterMapper mapper);
138
139
140    /**
141     * Returns the Rop opcode for this insn, or null if this is a phi insn
142     *
143     * TODO move this up into NormalSsaInsn
144     *
145     * @return null-ok; Rop opcode if there is one.
146     */
147    abstract public Rop getOpcode();
148
149    /**
150     * Returns the original Rop insn for this insn, or null if this is
151     * a phi insn.
152     *
153     * TODO move this up into NormalSsaInsn
154     *
155     * @return null-ok; Rop insn if there is one.
156     */
157    abstract public Insn getOriginalRopInsn();
158
159    /**
160     * Gets the spec of a local variable assignment that occurs at this
161     * instruction, or null if no local variable assignment occurs. This
162     * may be the result register, or for <code>mark-local</code> insns
163     * it may be the source.
164     *
165     * @return null-ok; a local-associated register spec or null
166     * @see com.android.dx.rop.code.Insn#getLocalAssignment()
167     */
168    public RegisterSpec getLocalAssignment() {
169        if (result != null && result.getLocalItem() != null) {
170            return result;
171        }
172
173        return null;
174    }
175
176    /**
177     * Indicates whether the specified register is amongst the registers
178     * used as sources for this instruction.
179     * @param reg The register in question
180     * @return true if the reg is a source
181     */
182    public boolean isRegASource(int reg) {
183        return null != getSources().specForRegister(reg);
184    }
185
186    /**
187     * Transform back to ROP form.
188     *
189     * TODO move this up into NormalSsaInsn
190     *
191     * @return non-null; a ROP representation of this instruction, with
192     * updated registers.
193     */
194    public abstract Insn toRopInsn();
195
196    /**
197     * @return true if this is a PhiInsn or a normal move insn
198     */
199    public abstract boolean isPhiOrMove();
200
201    /**
202     * Returns true if this insn is considered to have a side effect beyond
203     * that of assigning to the result reg.
204     *
205     * @return true if this insn is considered to have a side effect beyond
206     * that of assigning to the result reg.
207     */
208    public abstract boolean hasSideEffect();
209
210    /**
211     * @return true if this is a move (but not a move-operand or move-exception)
212     * instruction
213     */
214    public boolean isNormalMoveInsn() {
215        return false;
216    }
217
218    /**
219     * @return true if this is a move-exception instruction.
220     * These instructions must immediately follow a preceeding invoke*
221     */
222    public boolean isMoveException() {
223        return false;
224    }
225
226    /**
227     * @return true if this instruction can throw.
228     */
229    abstract public boolean canThrow();
230
231    /**
232     * accepts a visitor
233     * @param v visitor
234     */
235    public abstract void accept(Visitor v);
236
237    /**
238     * Visitor interface for this class.
239     */
240    public static interface Visitor {
241
242        /**
243         * Any non-phi move instruction
244         * @param insn non-null; the instruction to visit
245         */
246        public void visitMoveInsn(NormalSsaInsn insn);
247
248        /**
249         * Any phi insn
250         * @param insn non-null; the instruction to visit
251         */
252        public void visitPhiInsn(PhiInsn insn);
253
254        /**
255         * Any insn that isn't a move or a phi (which is also a move).
256         * @param insn non-null; the instruction to visit
257         */
258        public void visitNonMoveInsn(NormalSsaInsn insn);
259    }
260}
261