package soottocfg.cfg.optimization;
import com.google.common.base.Optional;
import soottocfg.cfg.expression.BinaryExpression;
import soottocfg.cfg.expression.BinaryExpression.BinaryOperator;
import soottocfg.cfg.expression.Expression;
import soottocfg.cfg.expression.IdentifierExpression;
import soottocfg.cfg.expression.IteExpression;
import soottocfg.cfg.expression.TupleAccessExpression;
import soottocfg.cfg.expression.UnaryExpression;
import soottocfg.cfg.expression.UnaryExpression.UnaryOperator;
import soottocfg.cfg.expression.literal.BooleanLiteral;
import soottocfg.cfg.expression.literal.IntegerLiteral;
import soottocfg.cfg.expression.literal.NullLiteral;
import soottocfg.cfg.variable.Variable;
//import soottocfg.cfg.type.ReferenceType;
/**
* Evaluate expressions statically if possible.
* Mostly still TODO. Right now only expressions over boolean literals are handled.
*
* @author rodykers
*
*/
public class ExpressionEvaluator {
public static Expression simplify(Expression e) {
if (e instanceof BinaryExpression) {
return simplify((BinaryExpression) e);
} else if (e instanceof BooleanLiteral) {
return e.deepCopy();
} else if (e instanceof IdentifierExpression) {
return e.deepCopy();
} else if (e instanceof IntegerLiteral) {
return e.deepCopy();
} else if (e instanceof IteExpression) {
return simplify((IteExpression) e);
} else if (e instanceof UnaryExpression) {
return simplify((UnaryExpression) e);
} else if (e instanceof NullLiteral) {
return e.deepCopy();
} else if (e instanceof TupleAccessExpression) {
return e.deepCopy();
} else {
throw new RuntimeException("unexpected expression type: " + e);
}
}
public static Expression simplify(BinaryExpression e) {
Expression left = simplify(e.getLeft());
Expression right = simplify(e.getRight());
if (left instanceof IntegerLiteral && right instanceof IntegerLiteral) {
int res = evalBinop(e.getOp(), ((IntegerLiteral)left).getValue().intValue(), ((IntegerLiteral)right).getValue().intValue());
return new IntegerLiteral(e.getSourceLocation(), res);
} else if (left instanceof BooleanLiteral && right instanceof BooleanLiteral) {
int a = ((BooleanLiteral)left).getValue() ? 1 : 0;
int b = ((BooleanLiteral)right).getValue() ? 1 : 0;
int res = evalBinop(e.getOp(), a, b);
return new BooleanLiteral(e.getSourceLocation(), res==1);
} else if (left instanceof IdentifierExpression && right instanceof IdentifierExpression) {
Variable leftVar = ((IdentifierExpression)left).getVariable();
Variable rightVar = ((IdentifierExpression)right).getVariable();
// for the case a==a and a!=a
if (leftVar.equals(rightVar)) {
if (e.getOp()==BinaryOperator.Eq) {
return BooleanLiteral.trueLiteral();
} else if (e.getOp()==BinaryOperator.Ne) {
return BooleanLiteral.falseLiteral();
}
} else if (leftVar.isUnique() && rightVar.isUnique()) {
//unique variable cannot be equal
if (e.getOp()==BinaryOperator.Eq) {
return BooleanLiteral.falseLiteral();
} else if (e.getOp()==BinaryOperator.Ne) {
return BooleanLiteral.trueLiteral();
}
}
}
return new BinaryExpression(e.getSourceLocation(), e.getOp(),left, right);
}
private static int evalBinop(BinaryOperator op, int a, int b) {
switch (op) {
case And:
return (a==1 && b==1) ? 1 : 0;
case BAnd:
return a & b;
case BOr:
return a | b;
case Div:
return a / b;
case Eq:
return a == b ? 1 : 0;
case Ge:
return a >= b ? 1 : 0;
case Gt:
return a > b ? 1 : 0;
case Implies:
return (a==0|| b==1) ? 1 : 0;
case Le:
return a <= b ? 1 : 0;
case Lt:
return a < b ? 1 : 0;
case Minus:
return a - b;
case Mod:
return a % b;
case Mul:
return a * b;
case Ne:
return a != b ? 1 : 0;
case Or:
return (a==1 || b==1) ? 1 : 0;
case Plus:
return a + b;
case PoLeq:
break;
case Shl:
return a << b;
case Shr:
return a >> b;
case Ushr:
return a >>> b;
case Xor:
return a ^ b;
default:
break;
}
throw new RuntimeException("Not implemented: "+op);
}
public static Expression simplify(IteExpression e) {
Expression cond = simplify(e.getCondition());
Expression thenExpr = simplify(e.getCondition());
Expression elseExpr = simplify(e.getCondition());
if (cond instanceof BooleanLiteral) {
if (((BooleanLiteral)cond).getValue()) {
return thenExpr;
} else {
return elseExpr;
}
}
return new IteExpression(e.getSourceLocation(), cond, thenExpr, elseExpr);
}
public static Expression simplify(UnaryExpression e) {
Expression inner = simplify(e.getExpression());
switch (e.getOp()) {
case LNot:
if (inner instanceof BooleanLiteral) {
if (((BooleanLiteral)inner).getValue()) {
return BooleanLiteral.falseLiteral();
} else {
return BooleanLiteral.trueLiteral();
}
}
break;
case Neg:
if (inner instanceof IntegerLiteral) {
return new IntegerLiteral(e.getSourceLocation(), -1*(((IntegerLiteral)inner).getValue()).intValue());
}
break;
default:
break;
}
return new UnaryExpression(e.getSourceLocation(), e.getOp(), inner);
}
public static Optional<Object> eval(Expression e) {
if (e instanceof BinaryExpression) {
return eval((BinaryExpression) e);
} else if (e instanceof BooleanLiteral) {
return eval((BooleanLiteral) e);
} else if (e instanceof IdentifierExpression) {
return eval((IdentifierExpression) e);
} else if (e instanceof IntegerLiteral) {
return eval((IntegerLiteral) e);
} else if (e instanceof IteExpression) {
return eval((IteExpression) e);
} else if (e instanceof UnaryExpression) {
return eval((UnaryExpression) e);
} else if (e instanceof NullLiteral) {
return eval((NullLiteral) e);
} else if (e instanceof TupleAccessExpression) {
return eval((TupleAccessExpression) e);
} else {
throw new RuntimeException("unexpected expression type: " + e);
}
}
public static Optional<Object> eval(BinaryExpression e) {
Optional<Object> left = eval(e.getLeft());
Optional<Object> right = eval(e.getRight());
switch (e.getOp()) {
case And:
if ( (left.isPresent() && !(Boolean) left.get())
|| (right.isPresent() && !(Boolean) right.get()))
return Optional.of((Object) false);
else if (left.isPresent() && right.isPresent())
return Optional.of((Object) ((Boolean) left.get() && (Boolean) right.get()));
else return Optional.absent();
case Or:
if ( (left.isPresent() && (Boolean) left.get())
|| (right.isPresent() && (Boolean) right.get()))
return Optional.of((Object) true);
else if (left.isPresent() && right.isPresent())
return Optional.of((Object) ((Boolean) left.get() || (Boolean) right.get()));
else return Optional.absent();
case Xor:
if (left.isPresent() && right.isPresent())
return Optional.of((Object) ((Boolean) left.get() ^ (Boolean) right.get()));
else return Optional.absent();
case Implies:
if (left.isPresent() && !(Boolean) left.get())
return Optional.of((Object) true);
else if (left.isPresent() && right.isPresent())
return right;
else return Optional.absent();
case Eq:
if (right.isPresent() && right.get() instanceof NullLiteral) {
// This hack confirms that SatAliasing01 and 02 fail with inlining
// because this class is not implemented.
// ReferenceType rt = (ReferenceType) e.getLeft().getType();
// if (rt.toString().equals("A"))
// return Optional.of(true);
// TODO We need a bit of data flow analysis here...
}
break;
// TODO all other cases
default:
break;
}
return Optional.absent();
}
public static Optional<Object> eval(BooleanLiteral e) {
return Optional.of((Object) e.getValue());
}
public static Optional<Object> eval(UnaryExpression e) {
if (e.getOp() == UnaryOperator.LNot) {
Optional<Object> neg = eval(e.getExpression());
if (neg.isPresent())
return Optional.of((Object) !(Boolean) neg.get());
}
return Optional.absent();
}
public static Optional<Object> eval(IdentifierExpression e) {
return Optional.absent();
}
public static Optional<Object> eval(IntegerLiteral e) {
return Optional.absent();
}
public static Optional<Object> eval(IteExpression ite) {
return Optional.absent();
}
public static Optional<Object> eval(NullLiteral e) {
// not sure what to put in the optional here... using the expression for now
return Optional.of((Object) e);
}
public static Optional<Object> eval(TupleAccessExpression e) {
return Optional.absent();
}
}