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.Insn; 20import com.android.dx.rop.code.PlainCstInsn; 21import com.android.dx.rop.code.PlainInsn; 22import com.android.dx.rop.code.RegOps; 23import com.android.dx.rop.code.RegisterSpec; 24import com.android.dx.rop.code.RegisterSpecList; 25import com.android.dx.rop.code.Rop; 26import com.android.dx.rop.code.Rops; 27import com.android.dx.rop.code.TranslationAdvice; 28import com.android.dx.rop.cst.Constant; 29import com.android.dx.rop.cst.CstLiteralBits; 30import com.android.dx.rop.type.Type; 31import com.android.dx.rop.type.TypeBearer; 32import java.util.ArrayList; 33import java.util.List; 34 35/** 36 * Upgrades insn to their literal (constant-immediate) equivalent if possible. 37 * Also switches IF instructions that compare with a constant zero or null 38 * to be their IF_*Z equivalents. 39 */ 40public class LiteralOpUpgrader { 41 42 /** method we're processing */ 43 private final SsaMethod ssaMeth; 44 45 /** 46 * Process a method. 47 * 48 * @param ssaMethod {@code non-null;} method to process 49 */ 50 public static void process(SsaMethod ssaMethod) { 51 LiteralOpUpgrader dc; 52 53 dc = new LiteralOpUpgrader(ssaMethod); 54 55 dc.run(); 56 } 57 58 private LiteralOpUpgrader(SsaMethod ssaMethod) { 59 this.ssaMeth = ssaMethod; 60 } 61 62 /** 63 * Returns true if the register contains an integer 0 or a known-null 64 * object reference 65 * 66 * @param spec non-null spec 67 * @return true for 0 or null type bearers 68 */ 69 private static boolean isConstIntZeroOrKnownNull(RegisterSpec spec) { 70 TypeBearer tb = spec.getTypeBearer(); 71 if (tb instanceof CstLiteralBits) { 72 CstLiteralBits clb = (CstLiteralBits) tb; 73 return (clb.getLongBits() == 0); 74 } 75 return false; 76 } 77 78 /** 79 * Run the literal op upgrader 80 */ 81 private void run() { 82 final TranslationAdvice advice = Optimizer.getAdvice(); 83 84 ssaMeth.forEachInsn(new SsaInsn.Visitor() { 85 @Override 86 public void visitMoveInsn(NormalSsaInsn insn) { 87 // do nothing 88 } 89 90 @Override 91 public void visitPhiInsn(PhiInsn insn) { 92 // do nothing 93 } 94 95 @Override 96 public void visitNonMoveInsn(NormalSsaInsn insn) { 97 98 Insn originalRopInsn = insn.getOriginalRopInsn(); 99 Rop opcode = originalRopInsn.getOpcode(); 100 RegisterSpecList sources = insn.getSources(); 101 102 // Replace insns with constant results with const insns 103 if (tryReplacingWithConstant(insn)) return; 104 105 if (sources.size() != 2 ) { 106 // We're only dealing with two-source insns here. 107 return; 108 } 109 110 if (opcode.getBranchingness() == Rop.BRANCH_IF) { 111 /* 112 * An if instruction can become an if-*z instruction. 113 */ 114 if (isConstIntZeroOrKnownNull(sources.get(0))) { 115 replacePlainInsn(insn, sources.withoutFirst(), 116 RegOps.flippedIfOpcode(opcode.getOpcode()), null); 117 } else if (isConstIntZeroOrKnownNull(sources.get(1))) { 118 replacePlainInsn(insn, sources.withoutLast(), 119 opcode.getOpcode(), null); 120 } 121 } else if (advice.hasConstantOperation( 122 opcode, sources.get(0), sources.get(1))) { 123 insn.upgradeToLiteral(); 124 } else if (opcode.isCommutative() 125 && advice.hasConstantOperation( 126 opcode, sources.get(1), sources.get(0))) { 127 /* 128 * An instruction can be commuted to a literal operation 129 */ 130 131 insn.setNewSources( 132 RegisterSpecList.make( 133 sources.get(1), sources.get(0))); 134 135 insn.upgradeToLiteral(); 136 } 137 } 138 }); 139 } 140 141 /** 142 * Tries to replace an instruction with a const instruction. The given 143 * instruction must have a constant result for it to be replaced. 144 * 145 * @param insn {@code non-null;} instruction to try to replace 146 * @return true if the instruction was replaced 147 */ 148 private boolean tryReplacingWithConstant(NormalSsaInsn insn) { 149 Insn originalRopInsn = insn.getOriginalRopInsn(); 150 Rop opcode = originalRopInsn.getOpcode(); 151 RegisterSpec result = insn.getResult(); 152 153 if (result != null && !ssaMeth.isRegALocal(result) && 154 opcode.getOpcode() != RegOps.CONST) { 155 TypeBearer type = insn.getResult().getTypeBearer(); 156 if (type.isConstant() && type.getBasicType() == Type.BT_INT) { 157 // Replace the instruction with a constant 158 replacePlainInsn(insn, RegisterSpecList.EMPTY, 159 RegOps.CONST, (Constant) type); 160 161 // Remove the source as well if this is a move-result-pseudo 162 if (opcode.getOpcode() == RegOps.MOVE_RESULT_PSEUDO) { 163 int pred = insn.getBlock().getPredecessors().nextSetBit(0); 164 ArrayList<SsaInsn> predInsns = 165 ssaMeth.getBlocks().get(pred).getInsns(); 166 NormalSsaInsn sourceInsn = 167 (NormalSsaInsn) predInsns.get(predInsns.size()-1); 168 replacePlainInsn(sourceInsn, RegisterSpecList.EMPTY, 169 RegOps.GOTO, null); 170 } 171 return true; 172 } 173 } 174 return false; 175 } 176 177 /** 178 * Replaces an SsaInsn containing a PlainInsn with a new PlainInsn. The 179 * new PlainInsn is constructed with a new RegOp and new sources. 180 * 181 * TODO move this somewhere else. 182 * 183 * @param insn {@code non-null;} an SsaInsn containing a PlainInsn 184 * @param newSources {@code non-null;} new sources list for new insn 185 * @param newOpcode A RegOp from {@link RegOps} 186 * @param cst {@code null-ok;} constant for new instruction, if any 187 */ 188 private void replacePlainInsn(NormalSsaInsn insn, 189 RegisterSpecList newSources, int newOpcode, Constant cst) { 190 191 Insn originalRopInsn = insn.getOriginalRopInsn(); 192 Rop newRop = Rops.ropFor(newOpcode, insn.getResult(), newSources, cst); 193 Insn newRopInsn; 194 if (cst == null) { 195 newRopInsn = new PlainInsn(newRop, originalRopInsn.getPosition(), 196 insn.getResult(), newSources); 197 } else { 198 newRopInsn = new PlainCstInsn(newRop, originalRopInsn.getPosition(), 199 insn.getResult(), newSources, cst); 200 } 201 NormalSsaInsn newInsn = new NormalSsaInsn(newRopInsn, insn.getBlock()); 202 203 List<SsaInsn> insns = insn.getBlock().getInsns(); 204 205 ssaMeth.onInsnRemoved(insn); 206 insns.set(insns.lastIndexOf(insn), newInsn); 207 ssaMeth.onInsnAdded(newInsn); 208 } 209} 210