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