Ejemplo n.º 1
0
        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 (distributedConvert.Match(binExp))
            {
                Changed = true;
                return(distributedConvert.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));
            }
            // (exp >> n) << n => __align(exp, 1<<n)
            var eNew = ShiftRightShiftLeft(binExp);

            if (eNew != null)
            {
                Changed = true;
                return(eNew);
            }

            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;
            }

            //$TODO: operands to binary operations appear to be
            // mismatched in some processors. Change the ctor
            // of BinaryExpression to catch this later.
            var sameBitsize = left.DataType.BitSize == right.DataType.BitSize;

            if (cRight != null)
            {
                // (- X 0) ==> X
                // (+ X 0) ==> X
                if (cRight.IsIntegerZero && IsAddOrSub(binExp.Operator))
                {
                    Changed = true;
                    return(left);
                }
                if (binExp.Operator == Operator.Or)
                {
                    if (cRight.IsIntegerZero)
                    {
                        Changed = true;
                        return(left);
                    }
                    // (| X 0xFFFF...F) ==> 0xFFFF...F
                    if (cRight.IsMaxUnsigned && sameBitsize && !CriticalInstruction.IsCritical(left))
                    {
                        ctx.RemoveExpressionUse(left);
                        Changed = true;
                        return(right);
                    }
                }
                if (binExp.Operator == Operator.And)
                {
                    if (cRight.IsIntegerZero && sameBitsize && !CriticalInstruction.IsCritical(left))
                    {
                        ctx.RemoveExpressionUse(left);
                        Changed = true;
                        return(cRight);
                    }
                    if (cRight.IsMaxUnsigned && sameBitsize)
                    {
                        Changed = true;
                        return(left);
                    }
                }
                if (binExp.Operator == Operator.Xor)
                {
                    if (cRight.IsIntegerZero)
                    {
                        Changed = true;
                        return(left);
                    }
                    if (cRight.IsMaxUnsigned && sameBitsize)
                    {
                        Changed = true;
                        return(new UnaryExpression(Operator.Comp, left.DataType, left).Accept(this));
                    }
                }
            }

            //$REVIEW: this is evaluation! Shouldn't the be done by the evaluator?
            if (left is InvalidConstant || right is InvalidConstant)
            {
                return(InvalidConstant.Create(binExp.DataType));
            }

            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 = ctx.ReinterpretAsFloat(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());
            }

            eNew = ShiftLeftShiftRight(binExp, cRight);
            if (eNew != null)
            {
                Changed = true;
                return(eNew);
            }

            // (-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);
        }
Ejemplo n.º 2
0
        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);
        }