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.Insn;
20 import com.android.dx.rop.code.LocalItem;
21 import com.android.dx.rop.code.RegOps;
22 import com.android.dx.rop.code.RegisterSpec;
23 import com.android.dx.rop.code.RegisterSpecList;
24 import com.android.dx.rop.code.Rop;
27 * A "normal" (non-phi) instruction in SSA form. Always wraps a rop insn.
29 public final class NormalSsaInsn extends SsaInsn implements Cloneable {
30 /** {@code non-null;} rop insn that we're wrapping */
34 * Creates an instance.
36 * @param insn Rop insn to wrap
37 * @param block block that contains this insn
39 NormalSsaInsn(final Insn insn, final SsaBasicBlock block) {
40 super(insn.getResult(), block);
46 public final void mapSourceRegisters(RegisterMapper mapper) {
47 RegisterSpecList oldSources = insn.getSources();
48 RegisterSpecList newSources = mapper.map(oldSources);
50 if (newSources != oldSources) {
51 insn = insn.withNewRegisters(getResult(), newSources);
52 getBlock().getParent().onSourcesChanged(this, oldSources);
57 * Changes one of the insn's sources. New source should be of same type
60 * @param index {@code >=0;} index of source to change
61 * @param newSpec spec for new source
63 public final void changeOneSource(int index, RegisterSpec newSpec) {
64 RegisterSpecList origSources = insn.getSources();
65 int sz = origSources.size();
66 RegisterSpecList newSources = new RegisterSpecList(sz);
68 for (int i = 0; i < sz; i++) {
69 newSources.set(i, i == index ? newSpec : origSources.get(i));
72 newSources.setImmutable();
74 RegisterSpec origSpec = origSources.get(index);
75 if (origSpec.getReg() != newSpec.getReg()) {
77 * If the register remains unchanged, we're only changing
78 * the type or local var name so don't update use list
80 getBlock().getParent().onSourceChanged(this, origSpec, newSpec);
83 insn = insn.withNewRegisters(getResult(), newSources);
87 * Changes the source list of the insn. New source list should be the
88 * same size and consist of sources of identical types.
90 * @param newSources non-null new sources list.
92 public final void setNewSources (RegisterSpecList newSources) {
93 RegisterSpecList origSources = insn.getSources();
95 if (origSources.size() != newSources.size()) {
96 throw new RuntimeException("Sources counts don't match");
99 insn = insn.withNewRegisters(getResult(), newSources);
104 public NormalSsaInsn clone() {
105 return (NormalSsaInsn) super.clone();
109 * Like rop.Insn.getSources().
111 * @return {@code null-ok;} sources list
114 public RegisterSpecList getSources() {
115 return insn.getSources();
119 public String toHuman() {
120 return toRopInsn().toHuman();
125 public Insn toRopInsn() {
126 return insn.withNewRegisters(getResult(), insn.getSources());
130 * @return the Rop opcode for this insn
133 public Rop getOpcode() {
134 return insn.getOpcode();
139 public Insn getOriginalRopInsn() {
145 public RegisterSpec getLocalAssignment() {
146 RegisterSpec assignment;
148 if (insn.getOpcode().getOpcode() == RegOps.MARK_LOCAL) {
149 assignment = insn.getSources().get(0);
151 assignment = getResult();
154 if (assignment == null) {
158 LocalItem local = assignment.getLocalItem();
168 * Upgrades this insn to a version that represents the constant source
169 * literally. If the upgrade is not possible, this does nothing.
171 * @see Insn#withSourceLiteral
173 public void upgradeToLiteral() {
174 RegisterSpecList oldSources = insn.getSources();
176 insn = insn.withSourceLiteral();
177 getBlock().getParent().onSourcesChanged(this, oldSources);
181 * @return true if this is a move (but not a move-operand) instruction
184 public boolean isNormalMoveInsn() {
185 return insn.getOpcode().getOpcode() == RegOps.MOVE;
190 public boolean isMoveException() {
191 return insn.getOpcode().getOpcode() == RegOps.MOVE_EXCEPTION;
196 public boolean canThrow() {
197 return insn.canThrow();
202 public void accept(Visitor v) {
203 if (isNormalMoveInsn()) {
204 v.visitMoveInsn(this);
206 v.visitNonMoveInsn(this);
212 public boolean isPhiOrMove() {
213 return isNormalMoveInsn();
219 * TODO: Increase the scope of this.
222 public boolean hasSideEffect() {
223 Rop opcode = getOpcode();
225 if (opcode.getBranchingness() != Rop.BRANCH_NONE) {
229 boolean hasLocalSideEffect
230 = Optimizer.getPreserveLocals() && getLocalAssignment() != null;
232 switch (opcode.getOpcode()) {
233 case RegOps.MOVE_RESULT:
236 return hasLocalSideEffect;