2 * Copyright (C) 2007 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.dx.ssa;
19 import com.android.dx.rop.code.*;
20 import com.android.dx.rop.type.Type;
21 import com.android.dx.rop.type.TypeBearer;
22 import com.android.dx.util.Hex;
24 import java.util.ArrayList;
25 import java.util.List;
28 * A Phi instruction (magical post-control-flow-merge) instruction
29 * in SSA form. Will be converted to moves in predecessor blocks before
30 * conversion back to ROP form.
32 public final class PhiInsn extends SsaInsn {
34 * result register. The original result register of the phi insn
35 * is needed during the renaming process after the new result
36 * register has already been chosen.
38 private final int ropResultReg;
41 * {@code non-null;} operands of the instruction; built up by
42 * {@link #addPhiOperand}
44 private final ArrayList<Operand> operands = new ArrayList<Operand>();
46 /** {@code null-ok;} source registers; constructed lazily */
47 private RegisterSpecList sources;
50 * Constructs a new phi insn with no operands.
52 * @param resultReg the result reg for this phi insn
53 * @param block block containing this insn.
55 public PhiInsn(RegisterSpec resultReg, SsaBasicBlock block) {
56 super(resultReg, block);
57 ropResultReg = resultReg.getReg();
61 * Makes a phi insn with a void result type.
63 * @param resultReg the result register for this phi insn.
64 * @param block block containing this insn.
66 public PhiInsn(final int resultReg, final SsaBasicBlock block) {
68 * The result type here is bogus: The type depends on the
69 * operand and will be derived later.
71 super(RegisterSpec.make(resultReg, Type.VOID), block);
72 ropResultReg = resultReg;
76 public PhiInsn clone() {
77 throw new UnsupportedOperationException("can't clone phi");
81 * Updates the TypeBearers of all the sources (phi operands) to be
82 * the current TypeBearer of the register-defining instruction's result.
83 * This is used during phi-type resolution.<p>
85 * Note that local association of operands are preserved in this step.
87 * @param ssaMeth method that contains this insn
89 public void updateSourcesToDefinitions(SsaMethod ssaMeth) {
90 for (Operand o : operands) {
92 = ssaMeth.getDefinitionForRegister(
93 o.regSpec.getReg()).getResult();
95 o.regSpec = o.regSpec.withType(def.getType());
102 * Changes the result type. Used during phi type resolution
104 * @param type {@code non-null;} new TypeBearer
105 * @param local {@code null-ok;} new local info, if available
107 public void changeResultType(TypeBearer type, LocalItem local) {
108 setResult(RegisterSpec.makeLocalOptional(
109 getResult().getReg(), type, local));
113 * Gets the original rop-form result reg. This is useful during renaming.
115 * @return the original rop-form result reg
117 public int getRopResultReg() {
122 * Adds an operand to this phi instruction.
124 * @param registerSpec register spec, including type and reg of operand
125 * @param predBlock predecessor block to be associated with this operand
127 public void addPhiOperand(RegisterSpec registerSpec,
128 SsaBasicBlock predBlock) {
129 operands.add(new Operand(registerSpec, predBlock.getIndex(),
130 predBlock.getRopLabel()));
132 // Un-cache sources, in case someone has already called getSources().
137 * Gets the index of the pred block associated with the RegisterSpec
138 * at the particular getSources() index.
140 * @param sourcesIndex index of source in getSources()
141 * @return block index
143 public int predBlockIndexForSourcesIndex(int sourcesIndex) {
144 return operands.get(sourcesIndex).blockIndex;
150 * Always returns null for {@code PhiInsn}s.
153 public Rop getOpcode() {
160 * Always returns null for {@code PhiInsn}s.
163 public Insn getOriginalRopInsn() {
170 * Always returns false for {@code PhiInsn}s.
173 public boolean canThrow() {
178 * Gets sources. Constructed lazily from phi operand data structures and
181 * @return {@code non-null;} sources list
183 public RegisterSpecList getSources() {
184 if (sources != null) {
188 if (operands.size() == 0) {
189 // How'd this happen? A phi insn with no operand?
190 return RegisterSpecList.EMPTY;
193 int szSources = operands.size();
194 sources = new RegisterSpecList(szSources);
196 for (int i = 0; i < szSources; i++) {
197 Operand o = operands.get(i);
199 sources.set(i, o.regSpec);
202 sources.setImmutable();
208 public boolean isRegASource(int reg) {
210 * Avoid creating a sources list in case it has not already been
214 for (Operand o : operands) {
215 if (o.regSpec.getReg() == reg) {
224 * @return true if all operands use the same register
226 public boolean areAllOperandsEqual() {
227 if (operands.size() == 0 ) {
228 // This should never happen.
232 int firstReg = operands.get(0).regSpec.getReg();
233 for (Operand o : operands) {
234 if (firstReg != o.regSpec.getReg()) {
244 public final void mapSourceRegisters(RegisterMapper mapper) {
245 for (Operand o : operands) {
246 RegisterSpec old = o.regSpec;
247 o.regSpec = mapper.map(old);
248 if (old != o.regSpec) {
249 getBlock().getParent().onSourceChanged(this, old, o.regSpec);
256 * Always throws an exeption, since a phi insn may not be
257 * converted back to rop form.
259 * @return always throws exception
262 public Insn toRopInsn() {
263 throw new IllegalArgumentException(
264 "Cannot convert phi insns to rop form");
268 * Returns the list of predecessor blocks associated with all operands
269 * that have {@code reg} as an operand register.
271 * @param reg register to look up
272 * @param ssaMeth method we're operating on
273 * @return list of predecessor blocks, empty if none
275 public List<SsaBasicBlock> predBlocksForReg(int reg, SsaMethod ssaMeth) {
276 ArrayList<SsaBasicBlock> ret = new ArrayList<SsaBasicBlock>();
278 for (Operand o : operands) {
279 if (o.regSpec.getReg() == reg) {
280 ret.add(ssaMeth.getBlocks().get(o.blockIndex));
289 public boolean isPhiOrMove() {
295 public boolean hasSideEffect() {
296 return Optimizer.getPreserveLocals() && getLocalAssignment() != null;
301 public void accept(SsaInsn.Visitor v) {
302 v.visitPhiInsn(this);
306 public String toHuman() {
307 return toHumanWithInline(null);
311 * Returns human-readable string for listing dumps. This method
312 * allows sub-classes to specify extra text.
314 * @param extra {@code null-ok;} the argument to print after the opcode
315 * @return human-readable string for listing dumps
317 protected final String toHumanWithInline(String extra) {
318 StringBuffer sb = new StringBuffer(80);
320 sb.append(SourcePosition.NO_INFO);
329 RegisterSpec result = getResult();
331 if (result == null) {
335 sb.append(result.toHuman());
340 int sz = getSources().size();
344 for (int i = 0; i < sz; i++) {
346 sb.append(sources.get(i).toHuman()
348 + Hex.u2(operands.get(i).ropLabel) + "]");
352 return sb.toString();
356 * A single phi operand, consiting of source register and block index
359 private static class Operand {
360 public RegisterSpec regSpec;
361 public final int blockIndex;
362 public final int ropLabel; // only used for debugging
364 public Operand(RegisterSpec regSpec, int blockIndex, int ropLabel) {
365 this.regSpec = regSpec;
366 this.blockIndex = blockIndex;
367 this.ropLabel = ropLabel;
372 * Visitor interface for instances of this (outer) class.
374 public static interface Visitor {
375 public void visitPhiInsn(PhiInsn insn);