/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.dx.ssa;
import com.android.dx.rop.code.TranslationAdvice;
import com.android.dx.rop.code.RegisterSpecList;
import com.android.dx.rop.code.Insn;
import com.android.dx.rop.code.Rop;
import com.android.dx.rop.code.RegisterSpec;
import com.android.dx.rop.code.PlainInsn;
import com.android.dx.rop.code.Rops;
import com.android.dx.rop.code.RegOps;
import com.android.dx.rop.cst.CstLiteralBits;
import com.android.dx.rop.type.TypeBearer;
import java.util.List;
/**
* Upgrades insn to their literal (constant-immediate) equivilent if possible.
* Also switches IF instructions that compare with a constant zero or null
* to be their IF_*Z equivalents.
*/
public class LiteralOpUpgrader {
/** method we're processing */
private final SsaMethod ssaMeth;
/**
* Process a method.
*
* @param ssaMethod non-null; method to process
*/
public static void process(SsaMethod ssaMethod) {
LiteralOpUpgrader dc;
dc = new LiteralOpUpgrader(ssaMethod);
dc.run();
}
private LiteralOpUpgrader(SsaMethod ssaMethod) {
this.ssaMeth = ssaMethod;
}
/**
* Returns true if the register contains an integer 0 or a known-null
* object reference
*
* @param spec non-null spec
* @return true for 0 or null type bearers
*/
private static boolean isConstIntZeroOrKnownNull(RegisterSpec spec) {
TypeBearer tb = spec.getTypeBearer();
if (tb instanceof CstLiteralBits) {
CstLiteralBits clb = (CstLiteralBits) tb;
return (clb.getLongBits() == 0);
}
return false;
}
/**
* Run the literal op upgrader
*/
private void run() {
final TranslationAdvice advice = Optimizer.getAdvice();
ssaMeth.forEachInsn(new SsaInsn.Visitor() {
public void visitMoveInsn(NormalSsaInsn insn) {
// do nothing
}
public void visitPhiInsn(PhiInsn insn) {
// do nothing
}
public void visitNonMoveInsn(NormalSsaInsn insn) {
Insn originalRopInsn = insn.getOriginalRopInsn();
Rop opcode = originalRopInsn.getOpcode();
RegisterSpecList sources = insn.getSources();
if (sources.size() != 2 ) {
// We're only dealing with two-source insns here.
return;
}
if (opcode.getBranchingness() == Rop.BRANCH_IF) {
/*
* An if instruction can become an if-*z instruction.
*/
if (isConstIntZeroOrKnownNull(sources.get(0))) {
replacePlainInsn(insn, sources.withoutFirst(),
RegOps.flippedIfOpcode(opcode.getOpcode()));
} else if (isConstIntZeroOrKnownNull(sources.get(1))) {
replacePlainInsn(insn, sources.withoutLast(),
opcode.getOpcode());
}
} else if (advice.hasConstantOperation(
opcode, sources.get(0), sources.get(1))) {
insn.upgradeToLiteral();
} else if (opcode.isCommutative()
&& advice.hasConstantOperation(
opcode, sources.get(1), sources.get(0))) {
/*
* An instruction can be commuted to a literal operation
*/
insn.setNewSources(
RegisterSpecList.make(
sources.get(1), sources.get(0)));
insn.upgradeToLiteral();
}
}
});
}
/**
* Replaces an SsaInsn containing a PlainInsn with a new PlainInsn. The
* new PlainInsn is contructed with a new RegOp and new sources.
*
* TODO move this somewhere else.
*
* @param insn non-null; an SsaInsn containing a PlainInsn
* @param newSources non-null; new sources list for new insn
* @param newOpcode A RegOp from {@link RegOps}
*/
private void replacePlainInsn(NormalSsaInsn insn,
RegisterSpecList newSources, int newOpcode) {
Insn originalRopInsn = insn.getOriginalRopInsn();
Rop newRop = Rops.ropFor(newOpcode,
insn.getResult(), newSources, null);
Insn newRopInsn = new PlainInsn(newRop,
originalRopInsn.getPosition(), insn.getResult(),
newSources);
NormalSsaInsn newInsn
= new NormalSsaInsn(newRopInsn, insn.getBlock());
List<SsaInsn> insns = insn.getBlock().getInsns();
ssaMeth.onInsnRemoved(insn);
insns.set(insns.lastIndexOf(insn), newInsn);
ssaMeth.onInsnAdded(newInsn);
}
}
|