/* Soot - a J*va Optimization Framework * Copyright (C) 1997-1999 Raja Vallee-Rai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ package soot.jbco.jimpleTransformations; import java.util.*; import soot.*; import soot.jbco.*; import soot.util.*; import soot.jimple.*; import soot.BodyTransformer; import soot.jbco.util.*; /** * @author Michael Batchelder * * Created on 6-Mar-2006 */ // when shifting, add multiple of 32 or 64 to the shift value, since it will // have no effect // shift negatively to confuse things further? // look into calculating operational cost and limiting to those transforms that // will // not hurt the speed of the program. Empirically: 4 adds/shifts == 1 mult? public class ArithmeticTransformer extends BodyTransformer implements IJbcoTransform { private static int mulPerformed = 0; private static int divPerformed = 0; private static int total = 0; public static String dependancies[] = new String[] {"jtp.jbco_cae2bo"}; public String[] getDependancies() { return dependancies; } public static String name = "jtp.jbco_cae2bo"; public String getName() { return name; } protected void internalTransform(Body b, String phaseName, Map options) { int weight = soot.jbco.Main.getWeight(phaseName, b.getMethod().getSignature()); if (weight == 0) return; PatchingChain units = b.getUnits(); int localCount = 0; Chain locals = b.getLocals(); if (output) out.println("*** Performing Arithmetic Transformation on " + b.getMethod().getSignature()); Iterator it = units.snapshotIterator(); while (it.hasNext()) { Unit u = (Unit) it.next(); if (u instanceof AssignStmt) { AssignStmt as = (AssignStmt) u; Value v = as.getRightOp(); if (v instanceof MulExpr) { total++; MulExpr me = (MulExpr) v; Value op1 = me.getOp1(); Value op = null, op2 = me.getOp2(); NumericConstant nc = null; if (op1 instanceof NumericConstant) { nc = (NumericConstant) op1; op = op2; } else if (op2 instanceof NumericConstant) { nc = (NumericConstant) op2; op = op1; } if (nc != null) { if (output) out.println("Considering: " + as + "\r"); Type opType = op.getType(); int max = opType instanceof IntType ? 32 : opType instanceof LongType ? 64 : 0; if (max != 0) { Object shft_rem[] = checkNumericValue(nc); if (shft_rem[0] != null && ((Integer) shft_rem[0]).intValue() < max && Rand.getInt(10) <= weight) { List<Unit> unitsBuilt = new ArrayList<Unit>(); int rand = Rand.getInt(16); int shift = ((Integer) shft_rem[0]).intValue(); boolean neg = ((Boolean) shft_rem[2]).booleanValue(); if (rand % 2 == 0) { shift += rand * max; } else { shift -= rand * max; } Expr e = null; if (shft_rem[1] != null) { // if there is an additive floating // component Local tmp2 = null, tmp1 = Jimple.v().newLocal( "__tmp_shft_lcl" + localCount++, opType); locals.add(tmp1); // shift the integral portion Unit newU = Jimple.v().newAssignStmt(tmp1, Jimple.v().newShlExpr(op, IntConstant.v(shift))); unitsBuilt.add(newU); units.insertBefore(newU, u); // grab remainder (that not part of the 2^x) double rem = ((Double) shft_rem[1]).doubleValue(); if (rem != 1) { if (rem == ((int) rem) && opType instanceof IntType) nc = IntConstant.v((int) rem); else if (rem == ((long) rem) && opType instanceof LongType) nc = LongConstant.v((long) rem); else nc = DoubleConstant.v(rem); if (nc instanceof DoubleConstant && !(opType instanceof DoubleType)) { tmp2 = Jimple.v().newLocal( "__tmp_shft_lcl" + localCount++, DoubleType.v()); locals.add(tmp2); newU = Jimple.v().newAssignStmt(tmp2, Jimple.v().newCastExpr(op, DoubleType.v())); unitsBuilt.add(newU); units.insertBefore(newU, u); newU = Jimple.v().newAssignStmt(tmp2, Jimple.v().newMulExpr(tmp2, nc)); } else { tmp2 = Jimple.v().newLocal( "__tmp_shft_lcl" + localCount++, nc.getType()); locals.add(tmp2); newU = Jimple.v().newAssignStmt(tmp2, Jimple.v().newMulExpr(op, nc)); } unitsBuilt.add(newU); units.insertBefore(newU, u); } if (tmp2 == null) { e = Jimple.v().newAddExpr(tmp1, op); } else if (tmp2.getType().getClass() != tmp1.getType() .getClass()) { Local tmp3 = Jimple.v().newLocal( "__tmp_shft_lcl" + localCount++, tmp2.getType()); locals.add(tmp3); newU = Jimple.v().newAssignStmt(tmp3, Jimple.v().newCastExpr(tmp1, tmp2.getType())); unitsBuilt.add(newU); units.insertBefore(newU, u); e = Jimple.v().newAddExpr(tmp3, tmp2); } else { e = Jimple.v().newAddExpr(tmp1, tmp2); } } else { e = Jimple.v().newShlExpr(op, IntConstant.v(shift)); } if (e.getType().getClass() != as.getLeftOp().getType() .getClass()) { Local tmp = Jimple.v().newLocal( "__tmp_shft_lcl" + localCount++, e.getType()); locals.add(tmp); Unit newU = Jimple.v().newAssignStmt(tmp, e); unitsBuilt.add(newU); units.insertAfter(newU, u); e = Jimple.v().newCastExpr(tmp, as.getLeftOp().getType()); } as.setRightOp(e); unitsBuilt.add(as); if (neg) { Unit newU = Jimple.v().newAssignStmt(as.getLeftOp(), Jimple.v().newNegExpr(as.getLeftOp())); unitsBuilt.add(newU); units.insertAfter(newU, u); } mulPerformed++; if (output) { System.out.println(" after as: "); Iterator<Unit> ait = unitsBuilt.iterator(); while (ait.hasNext()) { Unit uu = ait.next(); System.out.println("\t" + uu + "\ttype : " + (uu instanceof AssignStmt ? ((AssignStmt) uu) .getLeftOp().getType().toString() : "")); } } } } } } else if (v instanceof DivExpr) { total++; DivExpr de = (DivExpr) v; Value op2 = de.getOp2(); NumericConstant nc = null; if (op2 instanceof NumericConstant) { nc = (NumericConstant) op2; if (nc != null) { Type opType = de.getOp1().getType(); int max = opType instanceof IntType ? 32 : opType instanceof LongType ? 64 : 0; if (max != 0) { Object shft_rem[] = checkNumericValue(nc); if (shft_rem[0] != null && ((Integer) shft_rem[0]).intValue() < max && Rand.getInt(10) <= weight) { List<Unit> unitsBuilt = new ArrayList<Unit>(); int rand = Rand.getInt(16); int shift = ((Integer) shft_rem[0]).intValue(); boolean neg = ((Boolean) shft_rem[2]).booleanValue(); if (Rand.getInt() % 2 == 0) { shift += rand * max; } else { shift -= rand * max; } Expr e = Jimple.v().newShrExpr(de.getOp1(), IntConstant.v(shift)); if (e.getType().getClass() != as.getLeftOp().getType() .getClass()) { Local tmp = Jimple.v().newLocal( "__tmp_shft_lcl" + localCount++, e.getType()); locals.add(tmp); Unit newU = Jimple.v().newAssignStmt(tmp, e); unitsBuilt.add(newU); units.insertAfter(newU, u); e = Jimple.v().newCastExpr(tmp, as.getLeftOp().getType()); } as.setRightOp(e); unitsBuilt.add(as); if (neg) { Unit newU = Jimple.v().newAssignStmt(as.getLeftOp(), Jimple.v().newNegExpr(as.getLeftOp())); unitsBuilt.add(newU); units.insertAfter(newU, u); } divPerformed++; if (output) { System.out.println(" after as: "); Iterator<Unit> ait = unitsBuilt.iterator(); while (ait.hasNext()) { Unit uu = ait.next(); System.out.println("\t" + uu + "\ttype : " + (uu instanceof AssignStmt ? ((AssignStmt) uu) .getLeftOp().getType().toString() : "")); } } } } } } } } } } public void outputSummary() { out.println("Replaced mul/div expressions: " + (divPerformed + mulPerformed)); out.println("Total mul/div expressions: " + total); } private Object[] checkNumericValue(NumericConstant nc) { Double d = null; Object shift[] = new Object[3]; if (nc instanceof IntConstant) { d = new Double(((IntConstant) nc).value); } else if (nc instanceof DoubleConstant) { d = new Double(((DoubleConstant) nc).value); } else if (nc instanceof FloatConstant) { d = new Double(((FloatConstant) nc).value); } else if (nc instanceof LongConstant) { d = new Double(((LongConstant) nc).value); } if (d != null) { shift[2] = new Boolean(d.doubleValue() < 0); double tmp[] = checkShiftValue(d.doubleValue()); if (tmp[0] != 0) { shift[0] = new Integer((int) tmp[0]); if (tmp[1] != 0) shift[1] = new Double(tmp[1]); else shift[1] = null; } else d = null; } if (d == null) { shift[0] = null; shift[1] = null; } return shift; } private double[] checkShiftValue(double val) { double shift[] = new double[2]; if (val == 0 || val == 1 || val == -1) { shift[0] = 0; shift[1] = 0; } else { double shift_dbl = Math.log(val) / Math.log(2); double shift_int = Math.rint(shift_dbl); if (shift_dbl == shift_int) { shift[1] = 0; } else { if (Math.pow(2, shift_int) > val) shift_int--; shift[1] = val - Math.pow(2, shift_int); } shift[0] = shift_int; } return shift; } }