Ejemplo n.º 1
0
        public static BinaryOperatorKind WithOverflowChecksIfApplicable(this BinaryOperatorKind kind, bool enabled)
        {
            if (enabled)
            {
                // If it's a dynamic binop then make it checked. Let the lowering
                // pass sort out what to do with it.
                if (kind.IsDynamic())
                {
                    return(kind | BinaryOperatorKind.Checked);
                }

                if (kind.IsIntegral())
                {
                    switch (kind.Operator())
                    {
                    case BinaryOperatorKind.Addition:
                    case BinaryOperatorKind.Subtraction:
                    case BinaryOperatorKind.Multiplication:
                    case BinaryOperatorKind.Division:
                        return(kind | BinaryOperatorKind.Checked);
                    }
                }
                return(kind);
            }
            else
            {
                return(kind & ~BinaryOperatorKind.Checked);
            }
        }
Ejemplo n.º 2
0
        private static string GetBinaryOperatorName(BinaryOperatorKind opKind, out bool isChecked, out bool isLifted, out bool requiresLifted)
        {
            isChecked      = opKind.IsChecked();
            isLifted       = opKind.IsLifted();
            requiresLifted = opKind.IsComparison();

            switch (opKind.Operator())
            {
            case BinaryOperatorKind.Addition: return(isChecked ? "AddChecked" : "Add");

            case BinaryOperatorKind.Multiplication: return(isChecked ? "MultiplyChecked" : "Multiply");

            case BinaryOperatorKind.Subtraction: return(isChecked ? "SubtractChecked" : "Subtract");

            case BinaryOperatorKind.Division: return("Divide");

            case BinaryOperatorKind.Remainder: return("Modulo");

            case BinaryOperatorKind.And: return(opKind.IsLogical() ? "AndAlso" : "And");

            case BinaryOperatorKind.Xor: return("ExclusiveOr");

            case BinaryOperatorKind.Or: return(opKind.IsLogical() ? "OrElse" : "Or");

            case BinaryOperatorKind.LeftShift: return("LeftShift");

            case BinaryOperatorKind.RightShift: return("RightShift");

            case BinaryOperatorKind.Equal: return("Equal");

            case BinaryOperatorKind.NotEqual: return("NotEqual");

            case BinaryOperatorKind.LessThan: return("LessThan");

            case BinaryOperatorKind.LessThanOrEqual: return("LessThanOrEqual");

            case BinaryOperatorKind.GreaterThan: return("GreaterThan");

            case BinaryOperatorKind.GreaterThanOrEqual: return("GreaterThanOrEqual");

            default:
                throw ExceptionUtilities.UnexpectedValue(opKind.Operator());
            }
        }
Ejemplo n.º 3
0
        private MethodSymbol GetDecimalIncDecOperator(BinaryOperatorKind oper)
        {
            SpecialMember member;

            switch (oper.Operator())
            {
            case BinaryOperatorKind.Addition: member = SpecialMember.System_Decimal__op_Increment; break;

            case BinaryOperatorKind.Subtraction: member = SpecialMember.System_Decimal__op_Decrement; break;

            default:
                throw ExceptionUtilities.UnexpectedValue(oper.Operator());
            }

            var method = (MethodSymbol)_compilation.Assembly.GetSpecialTypeMember(member);

            Debug.Assert((object)method != null); // Should have been checked during Warnings pass
            return(method);
        }
Ejemplo n.º 4
0
        private static bool OperatorHasSideEffects(BinaryOperatorKind kind)
        {
            switch (kind.Operator())
            {
            case BinaryOperatorKind.Division:
            case BinaryOperatorKind.Remainder:
                return(true);

            default:
                return(kind.IsChecked());
            }
        }
Ejemplo n.º 5
0
 public static bool IsComparison(this BinaryOperatorKind kind)
 {
     switch (kind.Operator())
     {
     case BinaryOperatorKind.Equal:
     case BinaryOperatorKind.NotEqual:
     case BinaryOperatorKind.GreaterThan:
     case BinaryOperatorKind.GreaterThanOrEqual:
     case BinaryOperatorKind.LessThan:
     case BinaryOperatorKind.LessThanOrEqual:
         return(true);
     }
     return(false);
 }
Ejemplo n.º 6
0
        internal BinaryOperatorSignature GetSignature(BinaryOperatorKind kind)
        {
            var left = LeftType(kind);

            switch (kind.Operator())
            {
            case BinaryOperatorKind.Multiplication:
            case BinaryOperatorKind.Division:
            case BinaryOperatorKind.Subtraction:
                return(new BinaryOperatorSignature(kind, left, left, left));

            case BinaryOperatorKind.Addition:
                return(new BinaryOperatorSignature(kind, LeftType(kind), RightType(kind), ReturnType(kind)));
            }
            return(new BinaryOperatorSignature(kind, LeftType(kind), RightType(kind), ReturnType(kind)));
        }
Ejemplo n.º 7
0
        public static bool EmitsAsCheckedInstruction(this BinaryOperatorKind kind)
        {
            if (!kind.IsChecked())
            {
                return(false);
            }

            switch (kind.Operator())
            {
            case BinaryOperatorKind.Addition:
            case BinaryOperatorKind.Subtraction:
            case BinaryOperatorKind.Multiplication:
                return(true);
            }

            return(false);
        }
Ejemplo n.º 8
0
        private MethodSymbol GetDecimalIncDecOperator(BinaryOperatorKind oper)
        {
            SpecialMember member;

            switch (oper.Operator())
            {
            case BinaryOperatorKind.Addition: member = SpecialMember.System_Decimal__op_Increment; break;

            case BinaryOperatorKind.Subtraction: member = SpecialMember.System_Decimal__op_Decrement; break;

            default:
                Debug.Assert(false);     // Cannot reach here
                return(null);
            }

            var method = (MethodSymbol)this.compilation.Assembly.GetSpecialTypeMember(member);

            Debug.Assert((object)method != null); // Should have been checked during Warnings pass
            return(method);
        }
Ejemplo n.º 9
0
        internal BinaryOperatorSignature GetSignature(BinaryOperatorKind kind)
        {
            var left = LeftType(kind);

            switch (kind.Operator())
            {
            case BinaryOperatorKind.Multiplication:
            case BinaryOperatorKind.Division:
            case BinaryOperatorKind.Subtraction:
            case BinaryOperatorKind.Remainder:
            case BinaryOperatorKind.And:
            case BinaryOperatorKind.Or:
            case BinaryOperatorKind.Xor:
                return(new BinaryOperatorSignature(kind, left, left, left));

            case BinaryOperatorKind.Addition:
                return(new BinaryOperatorSignature(kind, LeftType(kind), RightType(kind), ReturnType(kind)));

            case BinaryOperatorKind.LeftShift:

            case BinaryOperatorKind.RightShift:
                TypeSymbol returnType = Compilation.GetSpecialType(SpecialType.System_Int32);

                if (kind.IsLifted())
                {
                    returnType = Compilation.GetSpecialType(SpecialType.System_Nullable_T).Construct(returnType);
                }

                return(new BinaryOperatorSignature(kind, left, returnType, left));

            case BinaryOperatorKind.Equal:
            case BinaryOperatorKind.NotEqual:
            case BinaryOperatorKind.GreaterThan:
            case BinaryOperatorKind.LessThan:
            case BinaryOperatorKind.GreaterThanOrEqual:
            case BinaryOperatorKind.LessThanOrEqual:
                return(new BinaryOperatorSignature(kind, left, left, Compilation.GetSpecialType(SpecialType.System_Boolean)));
            }
            return(new BinaryOperatorSignature(kind, LeftType(kind), RightType(kind), ReturnType(kind)));
        }
Ejemplo n.º 10
0
 public static BinaryOperatorKind WithOverflowChecksIfApplicable(this BinaryOperatorKind kind, bool enabled)
 {
     if (enabled)
     {
         if (kind.IsIntegral())
         {
             switch (kind.Operator())
             {
             case BinaryOperatorKind.Addition:
             case BinaryOperatorKind.Subtraction:
             case BinaryOperatorKind.Multiplication:
             case BinaryOperatorKind.Division:
                 return(kind | BinaryOperatorKind.Checked);
             }
         }
         return(kind);
     }
     else
     {
         return(kind & ~BinaryOperatorKind.Checked);
     }
 }
Ejemplo n.º 11
0
        private static bool IsUnsignedBinaryOperator(BoundBinaryOperator op)
        {
            BinaryOperatorKind opKind = op.OperatorKind;

            Debug.Assert(opKind.Operator() != BinaryOperatorKind.UnsignedRightShift);

            BinaryOperatorKind type = opKind.OperandTypes();

            switch (type)
            {
            case BinaryOperatorKind.Enum:
            case BinaryOperatorKind.EnumAndUnderlying:
                return(IsUnsigned(Binder.GetEnumPromotedType(op.Left.Type.GetEnumUnderlyingType().SpecialType)));

            case BinaryOperatorKind.UnderlyingAndEnum:
                return(IsUnsigned(Binder.GetEnumPromotedType(op.Right.Type.GetEnumUnderlyingType().SpecialType)));

            case BinaryOperatorKind.UInt:
            case BinaryOperatorKind.NUInt:
            case BinaryOperatorKind.ULong:
            case BinaryOperatorKind.ULongAndPointer:
            case BinaryOperatorKind.PointerAndInt:
            case BinaryOperatorKind.PointerAndUInt:
            case BinaryOperatorKind.PointerAndLong:
            case BinaryOperatorKind.PointerAndULong:
            case BinaryOperatorKind.Pointer:
                return(true);

            // Dev10 bases signedness on the first operand (see ILGENREC::genOperatorExpr).
            case BinaryOperatorKind.IntAndPointer:
            case BinaryOperatorKind.LongAndPointer:
            // Dev10 converts the uint to a native int, so it counts as signed.
            case BinaryOperatorKind.UIntAndPointer:
            default:
                return(false);
            }
        }
        private string GetBinaryOperatorName(BinaryOperatorKind opKind, out bool isChecked, out bool isLifted, out bool requiresLifted)
        {
            isChecked = opKind.IsChecked();
            isLifted = opKind.IsLifted();
            requiresLifted = opKind.IsComparison();

            switch (opKind.Operator())
            {
                case BinaryOperatorKind.Addition: return isChecked ? "AddChecked" : "Add";
                case BinaryOperatorKind.Multiplication: return isChecked ? "MultiplyChecked" : "Multiply";
                case BinaryOperatorKind.Subtraction: return isChecked ? "SubtractChecked" : "Subtract";
                case BinaryOperatorKind.Division: return "Divide";
                case BinaryOperatorKind.Remainder: return "Modulo";
                case BinaryOperatorKind.And: return opKind.IsLogical() ? "AndAlso" : "And";
                case BinaryOperatorKind.Xor: return "ExclusiveOr";
                case BinaryOperatorKind.Or: return opKind.IsLogical() ? "OrElse" : "Or";
                case BinaryOperatorKind.LeftShift: return "LeftShift";
                case BinaryOperatorKind.RightShift: return "RightShift";
                case BinaryOperatorKind.Equal: return "Equal";
                case BinaryOperatorKind.NotEqual: return "NotEqual";
                case BinaryOperatorKind.LessThan: return "LessThan";
                case BinaryOperatorKind.LessThanOrEqual: return "LessThanOrEqual";
                case BinaryOperatorKind.GreaterThan: return "GreaterThan";
                case BinaryOperatorKind.GreaterThanOrEqual: return "GreaterThanOrEqual";
                default:
                    throw ExceptionUtilities.UnexpectedValue(opKind.Operator());
            }
        }
Ejemplo n.º 13
0
        /// <summary>
        /// If one of the (unconverted) operands has constant value null and the other has
        /// a null constant value other than null, then they are definitely not equal
        /// and we can give a constant value for either == or !=.  This is a spec violation
        /// that we retain from Dev10.
        /// </summary>
        /// <param name="kind">The operator kind.  Nothing will happen if it is not a lifted equality operator.</param>
        /// <param name="left">The left-hand operand of the operation (possibly wrapped in a conversion).</param>
        /// <param name="right">The right-hand operand of the operation (possibly wrapped in a conversion).</param>
        /// <returns>
        /// If the operator represents lifted equality, then constant value true if both arguments have constant
        /// value null, constant value false if exactly one argument has constant value null, and null otherwise.
        /// If the operator represents lifted inequality, then constant value false if both arguments have constant
        /// value null, constant value true if exactly one argument has constant value null, and null otherwise.
        /// </returns>
        /// <remarks>
        /// SPEC VIOLATION: according to the spec (section 7.19) constant expressions cannot
        /// include implicit nullable conversions or nullable subexpressions.  However, Dev10
        /// specifically folds over lifted == and != (see ExpressionBinder::TryFoldingNullableEquality).
        /// Dev 10 does do compile-time evaluation of simple lifted operators, but it does so
        /// in a rewriting pass (see NullableRewriter) - they are not treated as constant values.
        /// </remarks>
        private static ConstantValue TryFoldingNullableEquality(BinaryOperatorKind kind, BoundExpression left, BoundExpression right)
        {
            if (kind.IsLifted())
            {
                BinaryOperatorKind op = kind.Operator();
                if (op == BinaryOperatorKind.Equal || op == BinaryOperatorKind.NotEqual)
                {
                    if (left.Kind == BoundKind.Conversion && right.Kind == BoundKind.Conversion)
                    {
                        BoundConversion leftConv = (BoundConversion)left;
                        BoundConversion rightConv = (BoundConversion)right;
                        ConstantValue leftConstant = leftConv.Operand.ConstantValue;
                        ConstantValue rightConstant = rightConv.Operand.ConstantValue;

                        if (leftConstant != null && rightConstant != null)
                        {
                            bool leftIsNull = leftConstant.IsNull;
                            bool rightIsNull = rightConstant.IsNull;
                            if (leftIsNull || rightIsNull)
                            {
                                // IMPL CHANGE: Dev10 raises WRN_NubExprIsConstBool in some cases, but that really doesn't
                                // make sense (why warn that a constant has a constant value?).
                                return (leftIsNull == rightIsNull) == (op == BinaryOperatorKind.Equal) ? ConstantValue.True : ConstantValue.False;
                            }
                        }
                    }
                }
            }

            return null;
        }
Ejemplo n.º 14
0
        private ConstantValue FoldEnumBinaryOperator(
            CSharpSyntaxNode syntax,
            BinaryOperatorKind kind,
            BoundExpression left,
            BoundExpression right,
            DiagnosticBag diagnostics)
        {
            Debug.Assert(left != null);
            Debug.Assert(right != null);
            Debug.Assert(kind.IsEnum());
            Debug.Assert(!kind.IsLifted());

            // A built-in binary operation on constant enum operands is evaluated into an operation on 
            // constants of the underlying type U of the enum type E. Comparison operators are lowered as
            // simply computing U<U. All other operators are computed as (E)(U op U) or in the case of 
            // E-E, (U)(U-U).  

            TypeSymbol enumType = GetEnumType(kind, left, right);
            TypeSymbol underlyingType = enumType.GetEnumUnderlyingType();

            BoundExpression newLeftOperand = CreateConversion(left, underlyingType, diagnostics);
            BoundExpression newRightOperand = CreateConversion(right, underlyingType, diagnostics);

            // If the underlying type is byte, sbyte, short, ushort or nullables of those then we'll need
            // to convert it up to int or int? because there are no + - * & | ^ < > <= >= == != operators
            // on byte, sbyte, short or ushort. They all convert to int.

            SpecialType operandSpecialType = GetEnumPromotedType(underlyingType.SpecialType);
            TypeSymbol operandType = (operandSpecialType == underlyingType.SpecialType) ?
                underlyingType :
                GetSpecialType(operandSpecialType, diagnostics, syntax);

            newLeftOperand = CreateConversion(newLeftOperand, operandType, diagnostics);
            newRightOperand = CreateConversion(newRightOperand, operandType, diagnostics);

            BinaryOperatorKind newKind = kind.Operator().WithType(newLeftOperand.Type.SpecialType);

            SpecialType operatorType = SpecialType.None;

            switch (newKind.Operator())
            {
                case BinaryOperatorKind.Addition:
                case BinaryOperatorKind.Subtraction:
                case BinaryOperatorKind.And:
                case BinaryOperatorKind.Or:
                case BinaryOperatorKind.Xor:
                    operatorType = operandType.SpecialType;
                    break;

                case BinaryOperatorKind.LessThan:
                case BinaryOperatorKind.LessThanOrEqual:
                case BinaryOperatorKind.GreaterThan:
                case BinaryOperatorKind.GreaterThanOrEqual:
                case BinaryOperatorKind.Equal:
                case BinaryOperatorKind.NotEqual:
                    operatorType = SpecialType.System_Boolean;
                    break;

                default:
                    throw ExceptionUtilities.UnexpectedValue(newKind.Operator());
            }

            var constantValue = FoldBinaryOperator(syntax, newKind, newLeftOperand, newRightOperand, operatorType, diagnostics);

            if (operatorType != SpecialType.System_Boolean && constantValue != null && !constantValue.IsBad)
            {
                TypeSymbol resultType = kind == BinaryOperatorKind.EnumSubtraction ? underlyingType : enumType;

                // We might need to convert back to the underlying type.
                return FoldConstantNumericConversion(syntax, constantValue, resultType, diagnostics);
            }

            return constantValue;
        }
        private MethodSymbol GetDecimalIncDecOperator(BinaryOperatorKind oper)
        {
            SpecialMember member;
            switch (oper.Operator())
            {
                case BinaryOperatorKind.Addition: member = SpecialMember.System_Decimal__op_Increment; break;
                case BinaryOperatorKind.Subtraction: member = SpecialMember.System_Decimal__op_Decrement; break;
                default:
                    Debug.Assert(false); // Cannot reach here
                    return null;
            }

            var method = (MethodSymbol)this.compilation.Assembly.GetSpecialTypeMember(member);
            Debug.Assert((object)method != null); // Should have been checked during Warnings pass
            return method;
        }
Ejemplo n.º 16
0
 public override string ToString() => $"RelationalDispatch.{Height}({Left} {Operator.Operator()} {Value} {Right})";
Ejemplo n.º 17
0
        private MethodSymbol GetDecimalIncDecOperator(BinaryOperatorKind oper)
        {
            SpecialMember member;
            switch (oper.Operator())
            {
                case BinaryOperatorKind.Addition: member = SpecialMember.System_Decimal__op_Increment; break;
                case BinaryOperatorKind.Subtraction: member = SpecialMember.System_Decimal__op_Decrement; break;
                default:
                    throw ExceptionUtilities.UnexpectedValue(oper.Operator());
            }

            var method = (MethodSymbol)_compilation.Assembly.GetSpecialTypeMember(member);
            Debug.Assert((object)method != null); // Should have been checked during Warnings pass
            return method;
        }
Ejemplo n.º 18
0
 private static bool IsReversed(BinaryOperatorKind op) => op.Operator() switch
 {
Ejemplo n.º 19
0
        private BoundExpression LowerLiftedBuiltInComparisonOperator(
            CSharpSyntaxNode syntax,
            BinaryOperatorKind kind,
            BoundExpression loweredLeft,
            BoundExpression loweredRight)
        {
            // SPEC: For the equality operators == != :
            // SPEC: The lifted operator considers two null values equal and a null value unequal to
            // SPEC: any non-null value. If both operands are non-null the lifted operator unwraps
            // SPEC: the operands and applies the underlying operator to produce the bool result.
            // SPEC:
            // SPEC: For the relational operators < > <= >= :
            // SPEC: The lifted operator produces the value false if one or both operands
            // SPEC: are null. Otherwise the lifted operator unwraps the operands and
            // SPEC: applies the underlying operator to produce the bool result.

            // Note that this means that x == y is true but x <= y is false if both are null.
            // x <= y is not the same as (x < y) || (x == y).

            // Start with some simple optimizations for cases like one side being null.
            BoundExpression optimized = TrivialLiftedComparisonOperatorOptimizations(syntax, kind, loweredLeft, loweredRight, null);
            if (optimized != null)
            {
                return optimized;
            }

            // We rewrite x == y as 
            //
            // tempx = x; 
            // tempy = y;
            // result = tempx.GetValueOrDefault() == tempy.GetValueOrDefault() ? 
            //          tempx.HasValue == tempy.HasValue : 
            //          false;
            //
            // and x != y as
            //
            // tempx = x; 
            // tempy = y;
            // result = tempx.GetValueOrDefault() == tempy.GetValueOrDefault() ? 
            //          tempx.HasValue != tempy.HasValue : 
            //          true;
            //
            // Otherwise, we rewrite x OP y as
            //
            // tempx = x;
            // tempy = y;
            // result = tempx.GetValueOrDefault() OP tempy.GetValueOrDefault() ?
            //          tempx.HasValue & tempy.HasValue :
            //          false;
            //
            // Note that there is no reason to generate "&&" over "&"; the cost of
            // the added code for the conditional branch would be about the same as simply doing 
            // the bitwise & in the first place.
            //
            // We have not yet optimized the case where we have a known-not-null value on one side, 
            // and an unknown value on the other. In those cases we will still generate a temp, but
            // we will not generate the call to the unnecessary nullable ctor or to GetValueOrDefault.
            // Rather, we will generate the value's temp instead of a call to GetValueOrDefault, and generate
            // literal true for HasValue. The tree construction methods we call will use those constants
            // to eliminate unnecessary branches.

            BoundExpression xNonNull = NullableAlwaysHasValue(loweredLeft);
            BoundExpression yNonNull = NullableAlwaysHasValue(loweredRight);

            BoundAssignmentOperator tempAssignmentX;
            BoundLocal boundTempX = _factory.StoreToTemp(xNonNull ?? loweredLeft, out tempAssignmentX);
            BoundAssignmentOperator tempAssignmentY;
            BoundLocal boundTempY = _factory.StoreToTemp(yNonNull ?? loweredRight, out tempAssignmentY);

            BoundExpression callX_GetValueOrDefault = MakeOptimizedGetValueOrDefault(syntax, boundTempX);
            BoundExpression callY_GetValueOrDefault = MakeOptimizedGetValueOrDefault(syntax, boundTempY);
            BoundExpression callX_HasValue = MakeOptimizedHasValue(syntax, boundTempX);
            BoundExpression callY_HasValue = MakeOptimizedHasValue(syntax, boundTempY);

            // tempx.GetValueOrDefault() == tempy.GetValueOrDefault()
            BinaryOperatorKind operatorKind = kind.Operator();
            BinaryOperatorKind conditionOperator = operatorKind == BinaryOperatorKind.NotEqual ?
                BinaryOperatorKind.Equal :
                operatorKind;
            TypeSymbol boolType = _compilation.GetSpecialType(SpecialType.System_Boolean);

            BoundExpression condition = MakeBinaryOperator(
                syntax: syntax,
                operatorKind: conditionOperator.WithType(kind.OperandTypes()),
                loweredLeft: callX_GetValueOrDefault,
                loweredRight: callY_GetValueOrDefault,
                type: boolType,
                method: null);

            BinaryOperatorKind consequenceOperator;
            switch (operatorKind)
            {
                case BinaryOperatorKind.Equal:
                    consequenceOperator = BinaryOperatorKind.BoolEqual;
                    break;
                case BinaryOperatorKind.NotEqual:
                    consequenceOperator = BinaryOperatorKind.BoolNotEqual;
                    break;
                default:
                    consequenceOperator = BinaryOperatorKind.BoolAnd;
                    break;
            }

            // tempx.HasValue == tempy.HasValue
            BoundExpression consequence = MakeBinaryOperator(
                syntax: syntax,
                operatorKind: consequenceOperator,
                loweredLeft: callX_HasValue,
                loweredRight: callY_HasValue,
                type: boolType,
                method: null);

            // false
            BoundExpression alternative = this.MakeBooleanConstant(syntax, operatorKind == BinaryOperatorKind.NotEqual);

            // tempx.GetValueOrDefault() == tempy.GetValueOrDefault() ? 
            //          tempx.HasValue == tempy.HasValue : 
            //          false;
            BoundExpression conditionalExpression = RewriteConditionalOperator(
                syntax: syntax,
                rewrittenCondition: condition,
                rewrittenConsequence: consequence,
                rewrittenAlternative: alternative,
                constantValueOpt: null,
                rewrittenType: boolType);

            // tempx = x; 
            // tempy = y;
            // result = tempx.GetValueOrDefault() == tempy.GetValueOrDefault() ? 
            //          tempx.HasValue == tempy.HasValue : 
            //          false;
            return new BoundSequence(
                syntax: syntax,
                locals: ImmutableArray.Create<LocalSymbol>(boundTempX.LocalSymbol, boundTempY.LocalSymbol),
                sideEffects: ImmutableArray.Create<BoundExpression>(tempAssignmentX, tempAssignmentY),
                value: conditionalExpression,
                type: boolType);
        }
Ejemplo n.º 20
0
        private BoundExpression MakeDynamicLogicalBinaryOperator(
            CSharpSyntaxNode syntax,
            BinaryOperatorKind operatorKind,
            BoundExpression loweredLeft,
            BoundExpression loweredRight,
            MethodSymbol leftTruthOperator,
            TypeSymbol type,
            bool isCompoundAssignment,
            BoundUnaryOperator applyParentUnaryOperator)
        {
            Debug.Assert(operatorKind.Operator() == BinaryOperatorKind.And || operatorKind.Operator() == BinaryOperatorKind.Or);

            // Dynamic logical && and || operators are lowered as follows:
            //   left && right  ->  IsFalse(left) ? left : And(left, right)
            //   left || right  ->  IsTrue(left) ? left : Or(left, right)
            // 
            // Optimization: If the binary AND/OR is directly contained in IsFalse/IsTrue operator (parentUnaryOperator != null)
            // we can avoid calling IsFalse/IsTrue twice on the same object.
            //   IsFalse(left && right)  ->  IsFalse(left) || IsFalse(And(left, right))
            //   IsTrue(left || right)   ->  IsTrue(left) || IsTrue(Or(left, right))

            bool isAnd = operatorKind.Operator() == BinaryOperatorKind.And;

            // Operator to be used to test the left operand:
            var testOperator = isAnd ? UnaryOperatorKind.DynamicFalse : UnaryOperatorKind.DynamicTrue;

            // VisitUnaryOperator ensures we are never called with parentUnaryOperator != null when we can't perform the optimization.
            Debug.Assert(applyParentUnaryOperator == null || applyParentUnaryOperator.OperatorKind == testOperator);

            ConstantValue constantLeft = loweredLeft.ConstantValue ?? UnboxConstant(loweredLeft);
            if (testOperator == UnaryOperatorKind.DynamicFalse && constantLeft == ConstantValue.False ||
                testOperator == UnaryOperatorKind.DynamicTrue && constantLeft == ConstantValue.True)
            {
                Debug.Assert(leftTruthOperator == null);

                if (applyParentUnaryOperator != null)
                {
                    // IsFalse(false && right) -> true
                    // IsTrue(true || right)   -> true
                    return _factory.Literal(true);
                }
                else
                {
                    // false && right  ->  box(false)
                    // true || right   ->  box(true)
                    return MakeConversionNode(loweredLeft, type, @checked: false);
                }
            }

            BoundExpression result;
            var boolean = _compilation.GetSpecialType(SpecialType.System_Boolean);

            // Store left to local if needed. If constant or already local we don't need a temp 
            // since the value of left can't change until right is evaluated.
            BoundAssignmentOperator tempAssignment;
            BoundLocal temp;
            if (constantLeft == null && loweredLeft.Kind != BoundKind.Local && loweredLeft.Kind != BoundKind.Parameter)
            {
                BoundAssignmentOperator assignment;
                var local = _factory.StoreToTemp(loweredLeft, out assignment);
                loweredLeft = local;
                tempAssignment = assignment;
                temp = local;
            }
            else
            {
                tempAssignment = null;
                temp = null;
            }

            var op = _dynamicFactory.MakeDynamicBinaryOperator(operatorKind, loweredLeft, loweredRight, isCompoundAssignment, type).ToExpression();

            // IsFalse(true) or IsTrue(false) are always false:
            bool leftTestIsConstantFalse = testOperator == UnaryOperatorKind.DynamicFalse && constantLeft == ConstantValue.True ||
                                           testOperator == UnaryOperatorKind.DynamicTrue && constantLeft == ConstantValue.False;

            if (applyParentUnaryOperator != null)
            {
                // IsFalse(left && right)  ->  IsFalse(left) || IsFalse(And(left, right))
                // IsTrue(left || right)   ->  IsTrue(left) || IsTrue(Or(left, right))

                result = _dynamicFactory.MakeDynamicUnaryOperator(testOperator, op, boolean).ToExpression();
                if (!leftTestIsConstantFalse)
                {
                    BoundExpression leftTest = MakeTruthTestForDynamicLogicalOperator(syntax, loweredLeft, boolean, leftTruthOperator, negative: isAnd);
                    result = _factory.Binary(BinaryOperatorKind.LogicalOr, boolean, leftTest, result);
                }
            }
            else
            {
                // left && right  ->  IsFalse(left) ? left : And(left, right)
                // left || right  ->  IsTrue(left) ? left : Or(left, right)

                if (leftTestIsConstantFalse)
                {
                    result = op;
                }
                else
                {
                    // We might need to box.
                    BoundExpression leftTest = MakeTruthTestForDynamicLogicalOperator(syntax, loweredLeft, boolean, leftTruthOperator, negative: isAnd);
                    var convertedLeft = MakeConversionNode(loweredLeft, type, @checked: false);
                    result = _factory.Conditional(leftTest, convertedLeft, op, type);
                }
            }

            if (tempAssignment != null)
            {
                return _factory.Sequence(ImmutableArray.Create(temp.LocalSymbol), ImmutableArray.Create<BoundExpression>(tempAssignment), result);
            }

            return result;
        }
Ejemplo n.º 21
0
        private BoundExpression RewritePointerNumericOperator(
            CSharpSyntaxNode syntax,
            BinaryOperatorKind kind,
            BoundExpression loweredLeft,
            BoundExpression loweredRight,
            TypeSymbol returnType,
            bool isPointerElementAccess,
            bool isLeftPointer)
        {
            if (isLeftPointer)
            {
                loweredRight = MakeSizeOfMultiplication(loweredRight, (PointerTypeSymbol)loweredLeft.Type, kind.IsChecked());
            }
            else
            {
                loweredLeft = MakeSizeOfMultiplication(loweredLeft, (PointerTypeSymbol)loweredRight.Type, kind.IsChecked());
            }

            if (isPointerElementAccess)
            {
                Debug.Assert(kind.Operator() == BinaryOperatorKind.Addition);

                // NOTE: This is here to persist a bug in Dev10.  checked(p[n]) should be equivalent to checked(*(p + n)),
                // but Dev10 omits the check on the addition (though it retains the check on the multiplication of n by
                // the size).
                kind = kind & ~BinaryOperatorKind.Checked;
            }

            return new BoundBinaryOperator(
                            syntax,
                            kind,
                            loweredLeft,
                            loweredRight,
                            ConstantValue.NotAvailable,
                            null,
                            LookupResultKind.Viable,
                            returnType);
        }
Ejemplo n.º 22
0
 private static bool OperatorHasSideEffects(BinaryOperatorKind kind)
 {
     switch (kind.Operator())
     {
         case BinaryOperatorKind.Division:
         case BinaryOperatorKind.Remainder:
             return true;
         default:
             return kind.IsChecked();
     }
 }
Ejemplo n.º 23
0
 public static int OperatorIndex(this BinaryOperatorKind kind)
 {
     return(((int)kind.Operator() >> 8) - 16);
 }
Ejemplo n.º 24
0
        private BoundExpression MakeBinaryOperator(
            BoundBinaryOperator oldNode,
            CSharpSyntaxNode syntax,
            BinaryOperatorKind operatorKind,
            BoundExpression loweredLeft,
            BoundExpression loweredRight,
            TypeSymbol type,
            MethodSymbol method,
            bool isPointerElementAccess = false,
            bool isCompoundAssignment = false,
            BoundUnaryOperator applyParentUnaryOperator = null)
        {
            Debug.Assert(oldNode == null || (oldNode.Syntax == syntax));

            if (_inExpressionLambda)
            {
                switch (operatorKind.Operator() | operatorKind.OperandTypes())
                {
                    case BinaryOperatorKind.ObjectAndStringConcatenation:
                    case BinaryOperatorKind.StringAndObjectConcatenation:
                    case BinaryOperatorKind.StringConcatenation:
                        return RewriteStringConcatenation(syntax, operatorKind, loweredLeft, loweredRight, type);
                    case BinaryOperatorKind.DelegateCombination:
                        return RewriteDelegateOperation(syntax, operatorKind, loweredLeft, loweredRight, type, SpecialMember.System_Delegate__Combine);
                    case BinaryOperatorKind.DelegateRemoval:
                        return RewriteDelegateOperation(syntax, operatorKind, loweredLeft, loweredRight, type, SpecialMember.System_Delegate__Remove);
                    case BinaryOperatorKind.DelegateEqual:
                        return RewriteDelegateOperation(syntax, operatorKind, loweredLeft, loweredRight, type, SpecialMember.System_Delegate__op_Equality);
                    case BinaryOperatorKind.DelegateNotEqual:
                        return RewriteDelegateOperation(syntax, operatorKind, loweredLeft, loweredRight, type, SpecialMember.System_Delegate__op_Inequality);
                }
            }
            else
            // try to lower the expression.
            {
                if (operatorKind.IsDynamic())
                {
                    Debug.Assert(!isPointerElementAccess);

                    if (operatorKind.IsLogical())
                    {
                        return MakeDynamicLogicalBinaryOperator(syntax, operatorKind, loweredLeft, loweredRight, method, type, isCompoundAssignment, applyParentUnaryOperator);
                    }
                    else
                    {
                        Debug.Assert((object)method == null);
                        return _dynamicFactory.MakeDynamicBinaryOperator(operatorKind, loweredLeft, loweredRight, isCompoundAssignment, type).ToExpression();
                    }
                }

                if (operatorKind.IsLifted())
                {
                    return RewriteLiftedBinaryOperator(syntax, operatorKind, loweredLeft, loweredRight, type, method);
                }

                if (operatorKind.IsUserDefined())
                {
                    return LowerUserDefinedBinaryOperator(syntax, operatorKind, loweredLeft, loweredRight, type, method);
                }

                switch (operatorKind.OperatorWithLogical() | operatorKind.OperandTypes())
                {
                    case BinaryOperatorKind.NullableNullEqual:
                    case BinaryOperatorKind.NullableNullNotEqual:
                        return RewriteNullableNullEquality(syntax, operatorKind, loweredLeft, loweredRight, type);

                    case BinaryOperatorKind.ObjectAndStringConcatenation:
                    case BinaryOperatorKind.StringAndObjectConcatenation:
                    case BinaryOperatorKind.StringConcatenation:
                        return RewriteStringConcatenation(syntax, operatorKind, loweredLeft, loweredRight, type);

                    case BinaryOperatorKind.StringEqual:
                        return RewriteStringEquality(oldNode, syntax, operatorKind, loweredLeft, loweredRight, type, SpecialMember.System_String__op_Equality);

                    case BinaryOperatorKind.StringNotEqual:
                        return RewriteStringEquality(oldNode, syntax, operatorKind, loweredLeft, loweredRight, type, SpecialMember.System_String__op_Inequality);

                    case BinaryOperatorKind.DelegateCombination:
                        return RewriteDelegateOperation(syntax, operatorKind, loweredLeft, loweredRight, type, SpecialMember.System_Delegate__Combine);

                    case BinaryOperatorKind.DelegateRemoval:
                        return RewriteDelegateOperation(syntax, operatorKind, loweredLeft, loweredRight, type, SpecialMember.System_Delegate__Remove);

                    case BinaryOperatorKind.DelegateEqual:
                        return RewriteDelegateOperation(syntax, operatorKind, loweredLeft, loweredRight, type, SpecialMember.System_Delegate__op_Equality);

                    case BinaryOperatorKind.DelegateNotEqual:
                        return RewriteDelegateOperation(syntax, operatorKind, loweredLeft, loweredRight, type, SpecialMember.System_Delegate__op_Inequality);

                    case BinaryOperatorKind.LogicalBoolAnd:
                        if (loweredRight.ConstantValue == ConstantValue.True) return loweredLeft;
                        if (loweredLeft.ConstantValue == ConstantValue.True) return loweredRight;
                        if (loweredLeft.ConstantValue == ConstantValue.False) return loweredLeft;

                        if (loweredRight.Kind == BoundKind.Local || loweredRight.Kind == BoundKind.Parameter)
                        {
                            operatorKind &= ~BinaryOperatorKind.Logical;
                        }

                        goto default;

                    case BinaryOperatorKind.LogicalBoolOr:
                        if (loweredRight.ConstantValue == ConstantValue.False) return loweredLeft;
                        if (loweredLeft.ConstantValue == ConstantValue.False) return loweredRight;
                        if (loweredLeft.ConstantValue == ConstantValue.True) return loweredLeft;

                        if (loweredRight.Kind == BoundKind.Local || loweredRight.Kind == BoundKind.Parameter)
                        {
                            operatorKind &= ~BinaryOperatorKind.Logical;
                        }

                        goto default;

                    case BinaryOperatorKind.BoolAnd:
                        if (loweredRight.ConstantValue == ConstantValue.True) return loweredLeft;
                        if (loweredLeft.ConstantValue == ConstantValue.True) return loweredRight;
                        goto default;

                    case BinaryOperatorKind.BoolOr:
                        if (loweredRight.ConstantValue == ConstantValue.False) return loweredLeft;
                        if (loweredLeft.ConstantValue == ConstantValue.False) return loweredRight;
                        goto default;

                    case BinaryOperatorKind.BoolEqual:
                        if (loweredLeft.ConstantValue == ConstantValue.True) return loweredRight;
                        if (loweredRight.ConstantValue == ConstantValue.True) return loweredLeft;

                        if (loweredLeft.ConstantValue == ConstantValue.False)
                            return MakeUnaryOperator(UnaryOperatorKind.BoolLogicalNegation, syntax, null, loweredRight, loweredRight.Type);

                        if (loweredRight.ConstantValue == ConstantValue.False)
                            return MakeUnaryOperator(UnaryOperatorKind.BoolLogicalNegation, syntax, null, loweredLeft, loweredLeft.Type);

                        goto default;

                    case BinaryOperatorKind.BoolNotEqual:
                        if (loweredLeft.ConstantValue == ConstantValue.False) return loweredRight;
                        if (loweredRight.ConstantValue == ConstantValue.False) return loweredLeft;

                        if (loweredLeft.ConstantValue == ConstantValue.True)
                            return MakeUnaryOperator(UnaryOperatorKind.BoolLogicalNegation, syntax, null, loweredRight, loweredRight.Type);

                        if (loweredRight.ConstantValue == ConstantValue.True)
                            return MakeUnaryOperator(UnaryOperatorKind.BoolLogicalNegation, syntax, null, loweredLeft, loweredLeft.Type);

                        goto default;

                    case BinaryOperatorKind.BoolXor:
                        if (loweredLeft.ConstantValue == ConstantValue.False) return loweredRight;
                        if (loweredRight.ConstantValue == ConstantValue.False) return loweredLeft;

                        if (loweredLeft.ConstantValue == ConstantValue.True)
                            return MakeUnaryOperator(UnaryOperatorKind.BoolLogicalNegation, syntax, null, loweredRight, loweredRight.Type);

                        if (loweredRight.ConstantValue == ConstantValue.True)
                            return MakeUnaryOperator(UnaryOperatorKind.BoolLogicalNegation, syntax, null, loweredLeft, loweredLeft.Type);

                        goto default;

                    case BinaryOperatorKind.IntLeftShift:
                    case BinaryOperatorKind.UIntLeftShift:
                    case BinaryOperatorKind.IntRightShift:
                    case BinaryOperatorKind.UIntRightShift:
                        return RewriteBuiltInShiftOperation(oldNode, syntax, operatorKind, loweredLeft, loweredRight, type, 0x1F);

                    case BinaryOperatorKind.LongLeftShift:
                    case BinaryOperatorKind.ULongLeftShift:
                    case BinaryOperatorKind.LongRightShift:
                    case BinaryOperatorKind.ULongRightShift:
                        return RewriteBuiltInShiftOperation(oldNode, syntax, operatorKind, loweredLeft, loweredRight, type, 0x3F);

                    case BinaryOperatorKind.DecimalAddition:
                    case BinaryOperatorKind.DecimalSubtraction:
                    case BinaryOperatorKind.DecimalMultiplication:
                    case BinaryOperatorKind.DecimalDivision:
                    case BinaryOperatorKind.DecimalRemainder:
                    case BinaryOperatorKind.DecimalEqual:
                    case BinaryOperatorKind.DecimalNotEqual:
                    case BinaryOperatorKind.DecimalLessThan:
                    case BinaryOperatorKind.DecimalLessThanOrEqual:
                    case BinaryOperatorKind.DecimalGreaterThan:
                    case BinaryOperatorKind.DecimalGreaterThanOrEqual:
                        return RewriteDecimalBinaryOperation(syntax, loweredLeft, loweredRight, operatorKind);

                    case BinaryOperatorKind.PointerAndIntAddition:
                    case BinaryOperatorKind.PointerAndUIntAddition:
                    case BinaryOperatorKind.PointerAndLongAddition:
                    case BinaryOperatorKind.PointerAndULongAddition:
                    case BinaryOperatorKind.PointerAndIntSubtraction:
                    case BinaryOperatorKind.PointerAndUIntSubtraction:
                    case BinaryOperatorKind.PointerAndLongSubtraction:
                    case BinaryOperatorKind.PointerAndULongSubtraction:
                        if (loweredRight.IsDefaultValue())
                        {
                            return loweredLeft;
                        }
                        return RewritePointerNumericOperator(syntax, operatorKind, loweredLeft, loweredRight, type, isPointerElementAccess, isLeftPointer: true);

                    case BinaryOperatorKind.IntAndPointerAddition:
                    case BinaryOperatorKind.UIntAndPointerAddition:
                    case BinaryOperatorKind.LongAndPointerAddition:
                    case BinaryOperatorKind.ULongAndPointerAddition:
                        if (loweredLeft.IsDefaultValue())
                        {
                            return loweredRight;
                        }
                        return RewritePointerNumericOperator(syntax, operatorKind, loweredLeft, loweredRight, type, isPointerElementAccess, isLeftPointer: false);

                    case BinaryOperatorKind.PointerSubtraction:
                        return RewritePointerSubtraction(operatorKind, loweredLeft, loweredRight, type);

                    case BinaryOperatorKind.IntAddition:
                    case BinaryOperatorKind.UIntAddition:
                    case BinaryOperatorKind.LongAddition:
                    case BinaryOperatorKind.ULongAddition:
                        if (loweredLeft.IsDefaultValue())
                        {
                            return loweredRight;
                        }
                        if (loweredRight.IsDefaultValue())
                        {
                            return loweredLeft;
                        }
                        goto default;

                    case BinaryOperatorKind.IntSubtraction:
                    case BinaryOperatorKind.LongSubtraction:
                    case BinaryOperatorKind.UIntSubtraction:
                    case BinaryOperatorKind.ULongSubtraction:
                        if (loweredRight.IsDefaultValue())
                        {
                            return loweredLeft;
                        }
                        goto default;

                    case BinaryOperatorKind.IntMultiplication:
                    case BinaryOperatorKind.LongMultiplication:
                    case BinaryOperatorKind.UIntMultiplication:
                    case BinaryOperatorKind.ULongMultiplication:
                        if (loweredLeft.IsDefaultValue())
                        {
                            return loweredLeft;
                        }
                        if (loweredRight.IsDefaultValue())
                        {
                            return loweredRight;
                        }
                        if (loweredLeft.ConstantValue?.UInt64Value == 1)
                        {
                            return loweredRight;
                        }
                        if (loweredRight.ConstantValue?.UInt64Value == 1)
                        {
                            return loweredLeft;
                        }
                        goto default;

                    case BinaryOperatorKind.IntGreaterThan:
                    case BinaryOperatorKind.IntLessThanOrEqual:
                        if (loweredLeft.Kind == BoundKind.ArrayLength && loweredRight.IsDefaultValue())
                        {
                            //array length is never negative
                            var newOp = operatorKind == BinaryOperatorKind.IntGreaterThan ?
                                                        BinaryOperatorKind.NotEqual :
                                                        BinaryOperatorKind.Equal;

                            operatorKind &= ~BinaryOperatorKind.OpMask;
                            operatorKind |= newOp;
                            loweredLeft = UnconvertArrayLength((BoundArrayLength)loweredLeft);
                        }
                        goto default;

                    case BinaryOperatorKind.IntLessThan:
                    case BinaryOperatorKind.IntGreaterThanOrEqual:
                        if (loweredRight.Kind == BoundKind.ArrayLength && loweredLeft.IsDefaultValue())
                        {
                            //array length is never negative
                            var newOp = operatorKind == BinaryOperatorKind.IntLessThan ?
                                                        BinaryOperatorKind.NotEqual :
                                                        BinaryOperatorKind.Equal;

                            operatorKind &= ~BinaryOperatorKind.OpMask;
                            operatorKind |= newOp;
                            loweredRight = UnconvertArrayLength((BoundArrayLength)loweredRight);
                        }
                        goto default;

                    case BinaryOperatorKind.IntEqual:
                    case BinaryOperatorKind.IntNotEqual:
                        if (loweredLeft.Kind == BoundKind.ArrayLength && loweredRight.IsDefaultValue())
                        {
                            loweredLeft = UnconvertArrayLength((BoundArrayLength)loweredLeft);
                        }
                        else if (loweredRight.Kind == BoundKind.ArrayLength && loweredLeft.IsDefaultValue())
                        {
                            loweredRight = UnconvertArrayLength((BoundArrayLength)loweredRight);
                        }

                        goto default;

                    default:
                        break;
                }
            }

            return (oldNode != null) ?
                oldNode.Update(operatorKind, loweredLeft, loweredRight, oldNode.ConstantValueOpt, oldNode.MethodOpt, oldNode.ResultKind, type) :
                new BoundBinaryOperator(syntax, operatorKind, loweredLeft, loweredRight, null, null, LookupResultKind.Viable, type);
        }
Ejemplo n.º 25
0
        public static bool IsShift(this BinaryOperatorKind kind)
        {
            BinaryOperatorKind type = kind.Operator();

            return(type == BinaryOperatorKind.LeftShift || type == BinaryOperatorKind.RightShift);
        }
Ejemplo n.º 26
0
        private BoundExpression RewriteLiftedBinaryOperator(CSharpSyntaxNode syntax, BinaryOperatorKind operatorKind, BoundExpression loweredLeft, BoundExpression loweredRight, TypeSymbol type, MethodSymbol method)
        {
            var conditionalLeft = loweredLeft as BoundLoweredConditionalAccess;

            // NOTE: we could in theory handle side-effecting loweredRight here too
            //       by including it as a part of whenNull, but there is a concern 
            //       that it can lead to code duplication
            var optimize = conditionalLeft != null &&
                !ReadIsSideeffecting(loweredRight) &&
                (conditionalLeft.WhenNullOpt == null || conditionalLeft.WhenNullOpt.IsDefaultValue());

            if (optimize)
            {
                loweredLeft = conditionalLeft.WhenNotNull;
            }

            var result = operatorKind.IsComparison() ?
                            operatorKind.IsUserDefined() ?
                                LowerLiftedUserDefinedComparisonOperator(syntax, operatorKind, loweredLeft, loweredRight, method) :
                                LowerLiftedBuiltInComparisonOperator(syntax, operatorKind, loweredLeft, loweredRight) :
                            LowerLiftedBinaryArithmeticOperator(syntax, operatorKind, loweredLeft, loweredRight, type, method);

            if (optimize)
            {
                BoundExpression whenNullOpt = null;

                // for all operators null-in means null-out
                // except for the Equal/NotEqual since null == null ==> true
                if (operatorKind.Operator() == BinaryOperatorKind.NotEqual ||
                    operatorKind.Operator() == BinaryOperatorKind.Equal)
                {
                    whenNullOpt = RewriteLiftedBinaryOperator(syntax, operatorKind, _factory.Default(loweredLeft.Type), loweredRight, type, method);
                }

                result = conditionalLeft.Update(
                    conditionalLeft.Receiver,
                    conditionalLeft.HasValueMethodOpt,
                    whenNotNull: result,
                    whenNullOpt: whenNullOpt,
                    id: conditionalLeft.Id,
                    type: result.Type
                );
            }

            return result;
        }
Ejemplo n.º 27
0
        public static ExpressionType ToExpressionType(this BinaryOperatorKind kind, bool isCompoundAssignment)
        {
            if (isCompoundAssignment)
            {
                switch (kind.Operator())
                {
                case BinaryOperatorKind.Multiplication: return(ExpressionType.MultiplyAssign);

                case BinaryOperatorKind.Addition: return(ExpressionType.AddAssign);

                case BinaryOperatorKind.Subtraction: return(ExpressionType.SubtractAssign);

                case BinaryOperatorKind.Division: return(ExpressionType.DivideAssign);

                case BinaryOperatorKind.Remainder: return(ExpressionType.ModuloAssign);

                case BinaryOperatorKind.LeftShift: return(ExpressionType.LeftShiftAssign);

                case BinaryOperatorKind.RightShift: return(ExpressionType.RightShiftAssign);

                case BinaryOperatorKind.And: return(ExpressionType.AndAssign);

                case BinaryOperatorKind.Xor: return(ExpressionType.ExclusiveOrAssign);

                case BinaryOperatorKind.Or: return(ExpressionType.OrAssign);
                }
            }
            else
            {
                switch (kind.Operator())
                {
                case BinaryOperatorKind.Multiplication: return(ExpressionType.Multiply);

                case BinaryOperatorKind.Addition: return(ExpressionType.Add);

                case BinaryOperatorKind.Subtraction: return(ExpressionType.Subtract);

                case BinaryOperatorKind.Division: return(ExpressionType.Divide);

                case BinaryOperatorKind.Remainder: return(ExpressionType.Modulo);

                case BinaryOperatorKind.LeftShift: return(ExpressionType.LeftShift);

                case BinaryOperatorKind.RightShift: return(ExpressionType.RightShift);

                case BinaryOperatorKind.Equal: return(ExpressionType.Equal);

                case BinaryOperatorKind.NotEqual: return(ExpressionType.NotEqual);

                case BinaryOperatorKind.GreaterThan: return(ExpressionType.GreaterThan);

                case BinaryOperatorKind.LessThan: return(ExpressionType.LessThan);

                case BinaryOperatorKind.GreaterThanOrEqual: return(ExpressionType.GreaterThanOrEqual);

                case BinaryOperatorKind.LessThanOrEqual: return(ExpressionType.LessThanOrEqual);

                case BinaryOperatorKind.And: return(ExpressionType.And);

                case BinaryOperatorKind.Xor: return(ExpressionType.ExclusiveOr);

                case BinaryOperatorKind.Or: return(ExpressionType.Or);
                }
            }

            throw ExceptionUtilities.UnexpectedValue(kind.Operator());
        }
Ejemplo n.º 28
0
        private BoundExpression TrivialLiftedComparisonOperatorOptimizations(
            CSharpSyntaxNode syntax,
            BinaryOperatorKind kind,
            BoundExpression left,
            BoundExpression right,
            MethodSymbol method)
        {
            Debug.Assert(left != null);
            Debug.Assert(right != null);

            // Optimization #1: if both sides are null then the result 
            // is either true (for equality) or false (for everything else.)

            bool leftAlwaysNull = NullableNeverHasValue(left);
            bool rightAlwaysNull = NullableNeverHasValue(right);

            TypeSymbol boolType = _compilation.GetSpecialType(SpecialType.System_Boolean);

            if (leftAlwaysNull && rightAlwaysNull)
            {
                return MakeLiteral(syntax, ConstantValue.Create(kind.Operator() == BinaryOperatorKind.Equal), boolType);
            }

            // Optimization #2: If both sides are non-null then we can again eliminate the lifting entirely.

            BoundExpression leftNonNull = NullableAlwaysHasValue(left);
            BoundExpression rightNonNull = NullableAlwaysHasValue(right);

            if (leftNonNull != null && rightNonNull != null)
            {
                return MakeBinaryOperator(
                    syntax: syntax,
                    operatorKind: kind.Unlifted(),
                    loweredLeft: leftNonNull,
                    loweredRight: rightNonNull,
                    type: boolType,
                    method: method);
            }

            // Optimization #3: If one side is null and the other is definitely not, then we generate the side effects
            // of the non-null side and result in true (for not-equals) or false (for everything else.)

            BinaryOperatorKind operatorKind = kind.Operator();

            if (leftAlwaysNull && rightNonNull != null || rightAlwaysNull && leftNonNull != null)
            {
                BoundExpression result = MakeLiteral(syntax, ConstantValue.Create(operatorKind == BinaryOperatorKind.NotEqual), boolType);

                BoundExpression nonNull = leftAlwaysNull ? rightNonNull : leftNonNull;

                if (ReadIsSideeffecting(nonNull))
                {
                    result = new BoundSequence(
                                    syntax: syntax,
                                    locals: ImmutableArray<LocalSymbol>.Empty,
                                    sideEffects: ImmutableArray.Create<BoundExpression>(nonNull),
                                    value: result,
                                    type: boolType);
                }

                return result;
            }

            // Optimization #4: If one side is null and the other is unknown, then we have three cases:
            // #4a: If we have x == null then that becomes !x.HasValue.
            // #4b: If we have x != null then that becomes x.HasValue.
            // #4c: If we have x OP null then that becomes side effects of x, result in false.

            if (leftAlwaysNull || rightAlwaysNull)
            {
                BoundExpression maybeNull = leftAlwaysNull ? right : left;

                if (operatorKind == BinaryOperatorKind.Equal || operatorKind == BinaryOperatorKind.NotEqual)
                {
                    BoundExpression callHasValue = MakeNullableHasValue(syntax, maybeNull);
                    BoundExpression result = operatorKind == BinaryOperatorKind.Equal ?
                        MakeUnaryOperator(UnaryOperatorKind.BoolLogicalNegation, syntax, null, callHasValue, boolType) :
                        callHasValue;
                    return result;
                }
                else
                {
                    BoundExpression falseExpr = MakeBooleanConstant(syntax, operatorKind == BinaryOperatorKind.NotEqual);
                    return _factory.Sequence(maybeNull, falseExpr);
                }
            }

            return null;
        }
        private BoundExpression LowerUserDefinedLogicalOperator(
            CSharpSyntaxNode syntax,
            BinaryOperatorKind operatorKind,
            BoundExpression loweredLeft,
            BoundExpression loweredRight,
            TypeSymbol type,
            MethodSymbol method)
        {
            Debug.Assert((object)method != null);

            // See comments in method IsValidUserDefinedConditionalLogicalOperator for information
            // on some subtle aspects of this lowering.

            // We generate one of:
            //
            // x || y --> temp = x; T.true(temp)  ? temp : T.|(temp, y);
            // x && y --> temp = x; T.false(temp) ? temp : T.&(temp, y);
            //
            // For the ease of naming locals, we'll assume we're doing an &&.

            // TODO: We generate every one of these as "temp = x; T.false(temp) ? temp : T.&(temp, y)" even
            // TODO: when x has no side effects. We can optimize away the temporary if there are no side effects.

            BoundAssignmentOperator tempAssignment;
            var boundTemp = factory.StoreToTemp(loweredLeft, out tempAssignment);

            // T.false(temp)
            var falseOperatorCall = BoundCall.Synthesized(syntax, null, GetTruthOperator(type, negative: operatorKind.Operator() == BinaryOperatorKind.And), boundTemp);

            // T.&(temp, y)

            var andOperatorCall = LowerUserDefinedBinaryOperator(syntax, operatorKind & ~BinaryOperatorKind.Logical, boundTemp, loweredRight, type, method);

            // T.false(temp) ? temp : T.&(temp, y)
            BoundExpression conditionalExpression = RewriteConditionalOperator(
                syntax: syntax,
                rewrittenCondition: falseOperatorCall,
                rewrittenConsequence: boundTemp,
                rewrittenAlternative: andOperatorCall,
                constantValueOpt: null,
                rewrittenType: type);

            // temp = x; T.false(temp) ? temp : T.&(temp, y)
            return new BoundSequence(
                syntax: syntax,
                locals: ImmutableArray.Create(boundTemp.LocalSymbol),
                sideEffects: ImmutableArray.Create<BoundExpression>(tempAssignment),
                value: conditionalExpression,
                type: type);
        }
Ejemplo n.º 30
0
        private BoundExpression LowerLiftedUserDefinedComparisonOperator(
            CSharpSyntaxNode syntax,
            BinaryOperatorKind kind,
            BoundExpression loweredLeft,
            BoundExpression loweredRight,
            MethodSymbol method)
        {
            // If both sides are null, or neither side is null, then we can do some simple optimizations.

            BoundExpression optimized = TrivialLiftedComparisonOperatorOptimizations(syntax, kind, loweredLeft, loweredRight, method);
            if (optimized != null)
            {
                return optimized;
            }

            // Otherwise, the expression
            //
            // x == y 
            //
            // becomes
            //
            // tempX = x;
            // tempY = y;
            // result = tempX.HasValue == tempY.HasValue ? 
            //            (tempX.HasValue ? 
            //              tempX.GetValueOrDefault() == tempY.GetValueOrDefault() : 
            //              true) : 
            //          false;
            //
            //
            // the expression
            //
            // x != y 
            //
            // becomes
            //
            // tempX = x;
            // tempY = y;
            // result = tempX.HasValue == tempY.HasValue ? 
            //            (tempX.HasValue ? 
            //              tempX.GetValueOrDefault() != tempY.GetValueOrDefault() : 
            //              false) : 
            //            true;
            //
            //
            // For the other comparison operators <, <=, >, >=,
            //
            // x OP y 
            //
            // becomes
            //
            // tempX = x;
            // tempY = y;
            // result = tempX.HasValue & tempY.HasValue ? 
            //              tempX.GetValueOrDefault() OP tempY.GetValueOrDefault() : 
            //              false;
            //
            // We have not yet optimized the case where we have a known-not-null value on one side, 
            // and an unknown value on the other. In those cases we will still generate a temp, but
            // we will not generate the call to the unnecessary nullable ctor or to GetValueOrDefault.
            // Rather, we will generate the value's temp instead of a call to GetValueOrDefault, and generate
            // literal true for HasValue. The tree construction methods we call will use those constants
            // to eliminate unnecessary branches.

            BoundExpression xNonNull = NullableAlwaysHasValue(loweredLeft);
            BoundExpression yNonNull = NullableAlwaysHasValue(loweredRight);

            // TODO: (This TODO applies throughout this file, not just to this method.)
            // TODO: We might be storing a constant to this temporary that we could simply inline.
            // TODO: (There are other expressions that can be safely moved around other than constants
            // TODO: as well -- for example a boxing conversion of a constant int to object.)
            // TODO: Build a better temporary-storage management system that decides whether or not
            // TODO: to store a temporary.

            BoundAssignmentOperator tempAssignmentX;
            BoundLocal boundTempX = _factory.StoreToTemp(xNonNull ?? loweredLeft, out tempAssignmentX);
            BoundAssignmentOperator tempAssignmentY;
            BoundLocal boundTempY = _factory.StoreToTemp(yNonNull ?? loweredRight, out tempAssignmentY);

            BoundExpression callX_GetValueOrDefault = MakeOptimizedGetValueOrDefault(syntax, boundTempX);
            BoundExpression callY_GetValueOrDefault = MakeOptimizedGetValueOrDefault(syntax, boundTempY);
            BoundExpression callX_HasValue = MakeOptimizedHasValue(syntax, boundTempX);
            BoundExpression callY_HasValue = MakeOptimizedHasValue(syntax, boundTempY);

            // tempx.HasValue == tempy.HasValue
            BinaryOperatorKind conditionOperator;
            BinaryOperatorKind operatorKind = kind.Operator();
            switch (operatorKind)
            {
                case BinaryOperatorKind.Equal:
                case BinaryOperatorKind.NotEqual:
                    conditionOperator = BinaryOperatorKind.BoolEqual;
                    break;
                default:
                    conditionOperator = BinaryOperatorKind.BoolAnd;
                    break;
            }

            TypeSymbol boolType = _compilation.GetSpecialType(SpecialType.System_Boolean);

            BoundExpression condition = MakeBinaryOperator(
                syntax: syntax,
                operatorKind: conditionOperator,
                loweredLeft: callX_HasValue,
                loweredRight: callY_HasValue,
                type: boolType,
                method: null);

            // tempX.GetValueOrDefault() OP tempY.GetValueOrDefault()
            BoundExpression unliftedOp = MakeBinaryOperator(
                syntax: syntax,
                operatorKind: kind.Unlifted(),
                loweredLeft: callX_GetValueOrDefault,
                loweredRight: callY_GetValueOrDefault,
                type: boolType,
                method: method);

            BoundExpression consequence;
            if (operatorKind == BinaryOperatorKind.Equal || operatorKind == BinaryOperatorKind.NotEqual)
            {
                // tempx.HasValue ? tempX.GetValueOrDefault() == tempY.GetValueOrDefault() : true
                consequence = RewriteConditionalOperator(
                    syntax: syntax,
                    rewrittenCondition: callX_HasValue,
                    rewrittenConsequence: unliftedOp,
                    rewrittenAlternative: MakeLiteral(syntax, ConstantValue.Create(operatorKind == BinaryOperatorKind.Equal), boolType),
                    constantValueOpt: null,
                    rewrittenType: boolType);
            }
            else
            {
                // tempX.GetValueOrDefault() OP tempY.GetValueOrDefault()
                consequence = unliftedOp;
            }

            // false
            BoundExpression alternative = MakeBooleanConstant(syntax, operatorKind == BinaryOperatorKind.NotEqual);

            BoundExpression conditionalExpression = RewriteConditionalOperator(
                syntax: syntax,
                rewrittenCondition: condition,
                rewrittenConsequence: consequence,
                rewrittenAlternative: alternative,
                constantValueOpt: null,
                rewrittenType: boolType);

            return new BoundSequence(
                syntax: syntax,
                locals: ImmutableArray.Create<LocalSymbol>(boundTempX.LocalSymbol, boundTempY.LocalSymbol),
                sideEffects: ImmutableArray.Create<BoundExpression>(tempAssignmentX, tempAssignmentY),
                value: conditionalExpression,
                type: boolType);
        }
Ejemplo n.º 31
0
        internal BinaryOperatorSignature GetSignature(BinaryOperatorKind kind)
        {
            var left = LeftType(kind);
            switch (kind.Operator())
            {
                case BinaryOperatorKind.Multiplication:
                case BinaryOperatorKind.Division:
                case BinaryOperatorKind.Subtraction:
                case BinaryOperatorKind.Remainder:
                case BinaryOperatorKind.And:
                case BinaryOperatorKind.Or:
                case BinaryOperatorKind.Xor:
                    return new BinaryOperatorSignature(kind, left, left, left);
                case BinaryOperatorKind.Addition:
                    return new BinaryOperatorSignature(kind, LeftType(kind), RightType(kind), ReturnType(kind));
                case BinaryOperatorKind.LeftShift:

                case BinaryOperatorKind.RightShift:
                    TypeSymbol returnType = Compilation.GetSpecialType(SpecialType.System_Int32);

                    if (kind.IsLifted())
                    {
                        returnType = Compilation.GetSpecialType(SpecialType.System_Nullable_T).Construct(returnType);
                    }

                    return new BinaryOperatorSignature(kind, left, returnType, left);

                case BinaryOperatorKind.Equal:
                case BinaryOperatorKind.NotEqual:
                case BinaryOperatorKind.GreaterThan:
                case BinaryOperatorKind.LessThan:
                case BinaryOperatorKind.GreaterThanOrEqual:
                case BinaryOperatorKind.LessThanOrEqual:
                    return new BinaryOperatorSignature(kind, left, left, Compilation.GetSpecialType(SpecialType.System_Boolean));
            }
            return new BinaryOperatorSignature(kind, LeftType(kind), RightType(kind), ReturnType(kind));
        }