public virtual Expression VisitBinaryExpression(BinaryExpression binExp) { // (+ id1 id1) ==> (* id1 2) if (add2ids.Match(binExp)) { Changed = true; return(add2ids.Transform().Accept(this)); } if (binopWithSelf.Match(binExp)) { Changed = true; return(binopWithSelf.Transform(ctx).Accept(this)); } var left = binExp.Left.Accept(this); var right = binExp.Right.Accept(this); Constant cLeft = left as Constant; Constant cRight = right as Constant; if (cLeft != null && BinaryExpression.Commutes(binExp.Operator)) { cRight = cLeft; left = right; right = cLeft; } // (- X 0) ==> X // (+ X 0) ==> X if (cRight != null && cRight.IsIntegerZero && IsAddOrSub(binExp.Operator)) { Changed = true; return(left); } else if (cRight != null && cRight.IsIntegerZero && binExp.Operator == Operator.Or) { Changed = true; return(left); } //$REVIEW: this is evaluation! Shouldn't the be done by the evaluator? if (left == Constant.Invalid || right == Constant.Invalid) { return(Constant.Invalid); } binExp = new BinaryExpression(binExp.Operator, binExp.DataType, left, right); if (constConstBin.Match(binExp)) { Changed = true; return(constConstBin.Transform()); } Identifier idLeft = left as Identifier; Identifier idRight = right as Identifier; // (rel? id1 c) should just pass. if (IsIntComparison(binExp.Operator) && cRight != null && idLeft != null) { return(binExp); } // Floating point expressions with "integer" constants if (IsFloatComparison(binExp.Operator) && IsNonFloatConstant(cRight)) { cRight = ReinterpretAsIeeeFloat(cRight); right = cRight; binExp.Right = cRight; } var binLeft = left as BinaryExpression; var cLeftRight = (binLeft != null) ? binLeft.Right as Constant : null; // (+ (+ e c1) c2) ==> (+ e (+ c1 c2)) // (+ (- e c1) c2) ==> (+ e (- c2 c1)) // (- (+ e c1) c2) ==> (- e (- c2 c1)) // (- (- e c1) c2) ==> (- e (+ c1 c2)) if (binLeft != null && cLeftRight != null && cRight != null && IsAddOrSub(binExp.Operator) && IsAddOrSub(binLeft.Operator) && !cLeftRight.IsReal && !cRight.IsReal) { Changed = true; var binOperator = binExp.Operator; ctx.RemoveIdentifierUse(idLeft); ctx.UseExpression(left); Constant c; if (binLeft.Operator == binOperator) { c = Operator.IAdd.ApplyConstants(cLeftRight, cRight); } else { if (Math.Abs(cRight.ToInt64()) >= Math.Abs(cLeftRight.ToInt64())) { c = Operator.ISub.ApplyConstants(cRight, cLeftRight); } else { binOperator = binOperator == Operator.IAdd ? Operator.ISub : Operator.IAdd; c = Operator.ISub.ApplyConstants(cLeftRight, cRight); } } if (c.IsIntegerZero) { return(binLeft.Left); } return(new BinaryExpression(binOperator, binExp.DataType, binLeft.Left, c)); } // (== (- e c1) c2) => (== e c1+c2) if (binLeft != null && cLeftRight != null && cRight != null && IsIntComparison(binExp.Operator) && IsAddOrSub(binLeft.Operator) && !cLeftRight.IsReal && !cRight.IsReal) { Changed = true; ctx.RemoveIdentifierUse(idLeft); var op = binLeft.Operator == Operator.IAdd ? Operator.ISub : Operator.IAdd; var c = ExpressionSimplifier.SimplifyTwoConstants(op, cLeftRight, cRight); return(new BinaryExpression(binExp.Operator, PrimitiveType.Bool, binLeft.Left, c)); } if (addMici.Match(binExp)) { Changed = true; return(addMici.Transform()); } if (shAdd.Match(binExp)) { Changed = true; return(shAdd.Transform()); } if (shMul.Match(binExp)) { Changed = true; return(shMul.Transform()); } if (shiftShift.Match(binExp)) { Changed = true; return(shiftShift.Transform()); } // No change, just return as is. return(binExp); }
public virtual Expression VisitBinaryExpression(BinaryExpression binExp) { // (+ id1 id1) ==> (* id1 2) if (add2ids.Match(binExp)) { Changed = true; return(add2ids.Transform().Accept(this)); } if (binopWithSelf.Match(binExp)) { Changed = true; return(binopWithSelf.Transform(ctx).Accept(this)); } if (distributedCast.Match(binExp)) { Changed = true; return(distributedCast.Transform(ctx).Accept(this)); } if (distributedSlice.Match(binExp)) { Changed = true; return(distributedSlice.Transform(ctx).Accept(this)); } var left = binExp.Left.Accept(this); var right = binExp.Right.Accept(this); Constant?cLeft = left as Constant; Constant?cRight = right as Constant; if (cLeft != null && BinaryExpression.Commutes(binExp.Operator)) { cRight = cLeft; left = right; right = cLeft; } // (- X 0) ==> X // (+ X 0) ==> X if (cRight != null && cRight.IsIntegerZero && IsAddOrSub(binExp.Operator)) { Changed = true; return(left); } else if (cRight != null && cRight.IsIntegerZero && binExp.Operator == Operator.Or) { Changed = true; return(left); } //$REVIEW: this is evaluation! Shouldn't the be done by the evaluator? if (left == Constant.Invalid || right == Constant.Invalid) { return(Constant.Invalid); } binExp = new BinaryExpression(binExp.Operator, binExp.DataType, left, right); if (constConstBin.Match(binExp)) { Changed = true; return(constConstBin.Transform()); } Identifier?idLeft = left as Identifier; Identifier?idRight = right as Identifier; // (rel? id1 c) should just pass. if (IsIntComparison(binExp.Operator) && cRight != null && idLeft != null) { return(binExp); } // Floating point expressions with "integer" constants if (IsFloatComparison(binExp.Operator) && IsNonFloatConstant(cRight)) { cRight = ReinterpretAsIeeeFloat(cRight !); right = cRight; binExp = new BinaryExpression( binExp.Operator, binExp.DataType, binExp.Left, cRight); } var binLeft = left as BinaryExpression; var cLeftRight = (binLeft != null) ? binLeft.Right as Constant : null; // (+ (+ e c1) c2) ==> (+ e (+ c1 c2)) // (+ (- e c1) c2) ==> (+ e (- c2 c1)) // (- (+ e c1) c2) ==> (- e (- c2 c1)) // (- (- e c1) c2) ==> (- e (+ c1 c2)) if (binLeft != null && cLeftRight != null && cRight != null) { if (IsAddOrSub(binExp.Operator) && IsAddOrSub(binLeft.Operator) && !cLeftRight.IsReal && !cRight.IsReal) { Changed = true; var binOperator = binExp.Operator; Constant c; if (binLeft.Operator == binOperator) { c = Operator.IAdd.ApplyConstants(cLeftRight, cRight); } else { if (Math.Abs(cRight.ToInt64()) >= Math.Abs(cLeftRight.ToInt64())) { c = Operator.ISub.ApplyConstants(cRight, cLeftRight); } else { binOperator = binOperator == Operator.IAdd ? Operator.ISub : Operator.IAdd; c = Operator.ISub.ApplyConstants(cLeftRight, cRight); } } if (c.IsIntegerZero) { return(binLeft.Left); } return(new BinaryExpression(binOperator, binExp.DataType, binLeft.Left, c)); } if (binExp.Operator == Operator.IMul && binLeft.Operator == Operator.IMul) { Changed = true; var c = Operator.IMul.ApplyConstants(cLeftRight, cRight); if (c.IsIntegerZero) { return(c); } else { return(new BinaryExpression(binExp.Operator, binExp.DataType, binLeft.Left, c)); } } } // (rel (- c e) 0 => (rel -c e) => (rel.Negate e c) if (binLeft != null && cRight != null && cRight.IsIntegerZero && IsIntComparison(binExp.Operator) && binLeft.Left is Constant cBinLeft && binLeft.Operator == Operator.ISub) { return(new BinaryExpression( ((ConditionalOperator)binExp.Operator).Negate(), binExp.DataType, binLeft.Right, cBinLeft)); } // (rel (- e c1) c2) => (rel e c1+c2) if (binLeft != null && cLeftRight != null && cRight != null && IsIntComparison(binExp.Operator) && IsAddOrSub(binLeft.Operator) && !cLeftRight.IsReal && !cRight.IsReal) { // (>u (- e c1) c2) => (>u e c1+c2) || (<u e c2) if (binExp.Operator == Operator.Ugt && binLeft.Operator == Operator.ISub && !cRight.IsIntegerZero) { Changed = true; ctx.UseExpression(binLeft.Left); var c = ExpressionSimplifier.SimplifyTwoConstants(Operator.IAdd, cLeftRight, cRight); return(new BinaryExpression(Operator.Cor, PrimitiveType.Bool, new BinaryExpression(binExp.Operator, PrimitiveType.Bool, binLeft.Left, c), new BinaryExpression(Operator.Ult, PrimitiveType.Bool, binLeft.Left, cLeftRight))); } else { Changed = true; ctx.RemoveIdentifierUse(idLeft !); var op = binLeft.Operator == Operator.IAdd ? Operator.ISub : Operator.IAdd; var c = ExpressionSimplifier.SimplifyTwoConstants(op, cLeftRight, cRight); return(new BinaryExpression(binExp.Operator, PrimitiveType.Bool, binLeft.Left, c)); } } // (rel C non-C) => (trans(rel) non-C C) if (constOnLeft.Match(binExp)) { Changed = true; return(constOnLeft.Transform().Accept(this)); } if (addMici.Match(binExp)) { Changed = true; return(addMici.Transform()); } if (shAdd.Match(binExp)) { Changed = true; return(shAdd.Transform()); } if (shMul.Match(binExp)) { Changed = true; return(shMul.Transform()); } if (shiftShift.Match(binExp)) { Changed = true; return(shiftShift.Transform()); } // (-exp == 0) => (exp == 0) if (unaryNegEqZero.Match(binExp)) { Changed = true; return(unaryNegEqZero.Transform()); } if (logicalNotFromBorrow.Match(binExp)) { Changed = true; return(logicalNotFromBorrow.Transform()); } // No change, just return as is. return(binExp); }