/**
* Short circuit binary operations.
*/
@Override
public void endVisit(JBinaryOperation x, Context ctx) {
JBinaryOperator op = x.getOp();
JExpression lhs = x.getLhs();
JExpression rhs = x.getRhs();
// If either parameter is a multiexpression, restructure if possible.
if (isNonEmptyMultiExpression(lhs)) {
// Push the operation inside the multiexpression. This exposes other optimization
// opportunities for latter passes e.g:
//
// (a(), b(), 1) + 2 ==> (a(), b(), 1 + 2) ==> (a(), b(), 3)
//
// There is no need to consider the symmetric case as it requires that all expression in the
// rhs (except the last one) to be side effect free, in which case they will end up being
// removed anyway.
List<JExpression> expressions = ((JMultiExpression) lhs).getExpressions();
JMultiExpression result = new JMultiExpression(lhs.getSourceInfo(),
expressions.subList(0, expressions.size() - 1));
result.addExpressions(new JBinaryOperation(x.getSourceInfo(), x.getType(), x.getOp(),
expressions.get(expressions.size() - 1), rhs));
ctx.replaceMe(result);
return;
}
if (isNonEmptyMultiExpression(rhs) && lhs instanceof JValueLiteral &&
op != JBinaryOperator.AND && op != JBinaryOperator.OR) {
// Push the operation inside the multiexpression if the lhs is a value literal.
// This exposes other optimization opportunities for latter passes e.g:
//
// 2 + (a(), b(), 1) ==> (a(), b(), 2 + 1) ==> (a(), b(), 3)
//
// And exception must be made for || and &&, as these operations might not evaluate the
// rhs due to shortcutting.
List<JExpression> expressions = ((JMultiExpression) rhs).getExpressions();
JMultiExpression result = new JMultiExpression(rhs.getSourceInfo(),
expressions.subList(0, expressions.size() - 1));
result.addExpressions(new JBinaryOperation(x.getSourceInfo(), x.getType(), x.getOp(),
lhs, expressions.get(expressions.size() - 1)));
ctx.replaceMe(result);
return;
}
if ((lhs instanceof JValueLiteral) && (rhs instanceof JValueLiteral)) {
if (evalOpOnLiterals(op, (JValueLiteral) lhs, (JValueLiteral) rhs, ctx)) {
return;
}
}
switch (op) {
case AND:
maybeReplaceMe(x, Simplifier.and(x), ctx);
break;
case OR:
maybeReplaceMe(x, Simplifier.or(x), ctx);
break;
case BIT_XOR:
simplifyXor(lhs, rhs, ctx);
break;
case EQ:
simplifyEq(lhs, rhs, ctx, false);
break;
case NEQ:
simplifyEq(lhs, rhs, ctx, true);
break;
case ADD:
simplifyAdd(lhs, rhs, ctx, x.getType());
break;
case CONCAT:
evalConcat(x.getSourceInfo(), lhs, rhs, ctx);
break;
case SUB:
simplifySub(lhs, rhs, ctx, x.getType());
break;
case MUL:
simplifyMul(lhs, rhs, ctx, x.getType());
break;
case DIV:
simplifyDiv(lhs, rhs, ctx, x.getType());
break;
case SHL:
case SHR:
case SHRU:
if (isLiteralZero(rhs)) {
ctx.replaceMe(lhs);
}
break;
default:
if (op.isAssignment()) {
lvalues.remove(lhs);
}
break;
}
}