예제 #1
0
        private void EmitBinaryOperatorExpression(BoundBinaryOperator expression, bool used)
        {
            var operatorKind = expression.OperatorKind;

            if (operatorKind.EmitsAsCheckedInstruction())
            {
                EmitBinaryOperator(expression);
            }
            else
            {
                // if operator does not have side-effects itself and is not short-circuiting
                // we can simply emit side-effects from the first operand and then from the second one
                if (!used && !operatorKind.IsLogical() && !OperatorHasSideEffects(operatorKind))
                {
                    EmitExpression(expression.Left, false);
                    EmitExpression(expression.Right, false);
                    return;
                }

                if (IsConditional(operatorKind))
                {
                    EmitBinaryCondOperator(expression, true);
                }
                else
                {
                    EmitBinaryOperator(expression);
                }
            }

            EmitPopIfUnused(used);
        }
        private BoundNode RewriteStringConcatenation(BoundBinaryOperator node)
        {
            // UNDONE: We need to make this more sophisticated. For example, we should
            // UNDONE: be rewriting (M() + "A") + ("B" + N()) as 
            // UNDONE: String.Concat(M(), "AB", N()).
            // UNDONE: We have many overloads of String.Concat to choose from: that
            // UNDONE: take one, two, three, four strings, that take params arrays
            // UNDONE: in strings and objects, and so on. See the native compiler
            // UNDONE: string rewriter for details.
            // UNDONE: For now, just to get this going let's do it the easy way;
            // UNDONE: we'll just generate calls to String.Concat(string, string)
            // UNDONE: or String.Concat(object, object) as appropriate.

            Debug.Assert(node != null);
            Debug.Assert(node.ConstantValueOpt == null);

            SpecialMember member = (node.OperatorKind == BinaryOperatorKind.StringConcatenation) ?
                SpecialMember.System_String__ConcatStringString :
                SpecialMember.System_String__ConcatObjectObject;

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

            // UNDONE: Handle the bizarre error case where we don't have the expected string concat methods.
            Debug.Assert(method != null);

            return Visit(BoundCall.SynthesizedCall(null, method, node.Left, node.Right));
        }
 private BoundNode RewriteDelegateOperation(BoundBinaryOperator node, SpecialMember member)
 {
     Debug.Assert(node != null);
     var method = (MethodSymbol)this.compilation.Assembly.GetSpecialTypeMember(member);
     // UNDONE: Handle the bizarre error case where we don't have the expected methods.
     Debug.Assert(method != null);
     BoundExpression call = BoundCall.SynthesizedCall(null, method, node.Left, node.Right);
     BoundExpression result = method.ReturnType.SpecialType == SpecialType.System_Delegate ?
         BoundConversion.SynthesizedConversion(call, ConversionKind.ExplicitReference, node.Type) :
         call;
     return Visit(result);
 }
        private BoundNode RewriteStringEquality(BoundBinaryOperator node, SpecialMember member)
        {
            Debug.Assert(node != null);
            Debug.Assert(node.ConstantValueOpt == null);

            if (node.Left.ConstantValue == ConstantValue.Null || node.Right.ConstantValue == ConstantValue.Null)
            {
                return base.VisitBinaryOperator(node);
            }

            var method = (MethodSymbol)this.compilation.Assembly.GetSpecialTypeMember(member);
            Debug.Assert(method != null);

            return Visit(BoundCall.SynthesizedCall(null, method, node.Left, node.Right));
        }
        public override BoundNode VisitBinaryOperator(BoundBinaryOperator node)
        {
            Debug.Assert(node != null);

            BoundExpression left = (BoundExpression)this.Visit(node.Left);
            BoundExpression right = (BoundExpression)this.Visit(node.Right);

            if (node.Type.SpecialType == SpecialType.System_Decimal)
            {
                return RewriteDecimalArithmeticBinaryOperator(node.OperatorKind, node.Syntax, left, right);
            }
            else if (node.Left.Type.SpecialType == SpecialType.System_Decimal && node.Left.Type.SpecialType == SpecialType.System_Decimal)
            {
                return RewriteDecimalComparisonOperator(node.OperatorKind, node.Syntax, left, right);
            }

            return node.Update(node.OperatorKind, left, right, node.ConstantValueOpt, node.MethodOpt, node.ResultKind, node.Type);
        }
예제 #6
0
        private void EmitShortCircuitingOperator(
            BoundBinaryOperator condition,
            bool sense,
            bool stopSense,
            bool stopValue
            )
        {
            // we generate:
            //
            // gotoif (a == stopSense) fallThrough
            // b == sense
            // goto labEnd
            // fallThrough:
            // stopValue
            // labEnd:
            //                 AND       OR
            //            +-  ------    -----
            // stopSense  |   !sense    sense
            // stopValue  |     0         1

            object lazyFallThrough = null;

            EmitCondBranch(condition.Left, ref lazyFallThrough, stopSense);
            EmitCondExpr(condition.Right, sense);

            // if fall-through was not initialized, no-one is going to take that branch
            // and we are done with Right on stack
            if (lazyFallThrough == null)
            {
                return;
            }

            var labEnd = new object();

            _builder.EmitBranch(ILOpCode.Br, labEnd);

            // if we get to fallThrough, we should not have Right on stack. Adjust for that.
            _builder.AdjustStack(-1);

            _builder.MarkLabel(lazyFallThrough);
            _builder.EmitBoolConstant(stopValue);
            _builder.MarkLabel(labEnd);
        }
예제 #7
0
        private void EmitBinaryCheckedOperatorInstruction(BoundBinaryOperator expression)
        {
            var unsigned = IsUnsignedBinaryOperator(expression);

            switch (expression.OperatorKind.Operator())
            {
            case BinaryOperatorKind.Multiplication:
                if (unsigned)
                {
                    _builder.EmitOpCode(ILOpCode.Mul_ovf_un);
                }
                else
                {
                    _builder.EmitOpCode(ILOpCode.Mul_ovf);
                }
                break;

            case BinaryOperatorKind.Addition:
                if (unsigned)
                {
                    _builder.EmitOpCode(ILOpCode.Add_ovf_un);
                }
                else
                {
                    _builder.EmitOpCode(ILOpCode.Add_ovf);
                }
                break;

            case BinaryOperatorKind.Subtraction:
                if (unsigned)
                {
                    _builder.EmitOpCode(ILOpCode.Sub_ovf_un);
                }
                else
                {
                    _builder.EmitOpCode(ILOpCode.Sub_ovf);
                }
                break;

            default:
                throw ExceptionUtilities.UnexpectedValue(expression.OperatorKind.Operator());
            }
        }
예제 #8
0
        protected override BoundStatement RewriteForStatement(BoundForStatement node)
        {
            // for <var> = <lower> to <upper>
            //      <body>
            //
            // ---->
            //
            // {
            //      var <var> = <lower>
            //      while (<var> <= <upper>)
            //      {
            //          <body>
            //          <var> = <var> + 1
            //      }
            // }

            var variableDeclaration   = new BoundVeriableDeclaration(node.Variable, node.LowerBound);
            var variableExpression    = new BoundVariableExpression(node.Variable);
            var upperBoundSybmle      = new VariableSymble("upperBound", true, typeof(int));
            var upperBoundDeclaration = new BoundVeriableDeclaration(upperBoundSybmle, node.UpperBound);
            var condition             = new BoundBinaryExpression(
                variableExpression,
                BoundBinaryOperator.Bind(SyntaxKind.LessOrEqualToken, typeof(int), typeof(int)),
                new BoundVariableExpression(upperBoundSybmle)
                );
            var increment = new BoundExpressionStatemnet(
                new BoundAssignmentExpression(
                    node.Variable,
                    new BoundBinaryExpression(
                        variableExpression,
                        BoundBinaryOperator.Bind(SyntaxKind.PlusToken, typeof(int), typeof(int)),
                        new BoundLiteralExpression(1)
                        )
                    )
                );
            var whileBody      = new BoundBlockStatemnet(ImmutableArray.Create <BoundStatement>(node.Body, increment));
            var whileStatement = new BoundWhileStatement(condition, whileBody);
            var result         = new BoundBlockStatemnet(ImmutableArray.Create <BoundStatement>(
                                                             variableDeclaration, upperBoundDeclaration, whileStatement));

            return(RewriteStatement(result));
        }
예제 #9
0
    private BoundExpression BindBinaryExpression(BinaryExpressionSyntax syntax)
    {
        var boundLeft  = this.BindExpression(syntax.Left);
        var boundRight = this.BindExpression(syntax.Right);

        if (boundLeft.Type == TypeSymbol.Error || boundRight.Type == TypeSymbol.Error)
        {
            return(new BoundErrorExpression(syntax));
        }

        var boundOperator = BoundBinaryOperator.Bind(syntax.OperatorToken.Kind, boundLeft.Type, boundRight.Type);

        if (boundOperator == null)
        {
            this.Diagnostics.ReportUndefinedBinaryOperator(syntax.OperatorToken.Location, syntax.OperatorToken.Text, boundLeft.Type, boundRight.Type);
            return(new BoundErrorExpression(syntax));
        }

        return(new BoundBinaryExpression(syntax, boundLeft, boundOperator, boundRight));
    }
예제 #10
0
        private static bool IsUnsignedBinaryOperator(BoundBinaryOperator op)
        {
            BinaryOperatorKind opKind = op.OperatorKind;
            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);
            }
        }
예제 #11
0
        protected override BoundStatement RewriteForStatement(BoundForStatement node)
        {
            // for <var> = <lower> to <upper>
            //  <body>
            // is rewritten to
            //  {
            //    var <Var> = <lower>
            //  while ()
            //
            var variableDeclaration = new BoundVariableDeclaration(node.Variable, node.LowerBound);
            var variableExpression  = new BoundVariableExpression(node.Variable);

            var condition = new BoundBinaryExpression(
                variableExpression,
                BoundBinaryOperator.Bind(SyntaxKind.LessOrEqualsToken, typeof(int), typeof(int)),
                node.UpperBound);

            var increment = new BoundExpressionStatement(
                new BoundAssignmentExpression(
                    node.Variable,
                    new BoundBinaryExpression(
                        variableExpression,
                        BoundBinaryOperator.Bind(
                            SyntaxKind.PlusToken,
                            typeof(int),
                            typeof(int)),
                        new BoundLiteralExpression(1)
                        )
                    )
                );

            var whileBlock = new BoundBlockStatement(ImmutableArray.Create <BoundStatement>(node.Body, increment));

            var whileStatement = new BoundWhileStatement(condition, whileBlock);

            var result = new BoundBlockStatement(ImmutableArray.Create <BoundStatement>(variableDeclaration, whileStatement));

            return(RewriteStatement(result));
        }
예제 #12
0
        protected override BoundStatement RewriteForStatement(BoundForStatement node)
        {
            BoundVariableDeclaration variableDeclaration      = new BoundVariableDeclaration(node.Variable, node.LowerBound);
            BoundVariableExpression  variableExpression       = new BoundVariableExpression(node.Variable);
            VariableSymbol           upperVariableSymbol      = new LocalVariableSymbol("upperBound", true, TypeSymbol.Int);
            BoundVariableDeclaration upperVariableDeclaration = new BoundVariableDeclaration(upperVariableSymbol, node.UpperBound);

            BoundBinaryExpression condition = new BoundBinaryExpression(
                variableExpression,
                BoundBinaryOperator.Bind(SyntaxKind.LessOrEqualsToken, TypeSymbol.Int, TypeSymbol.Int),
                new BoundVariableExpression(upperVariableSymbol)
                );
            BoundLabelStatement      continueLabelStatement = new BoundLabelStatement(node.ContinueLabel);
            BoundExpressionStatement increment = new BoundExpressionStatement(
                new BoundAssignmentExpression(
                    node.Variable,
                    new BoundBinaryExpression(
                        variableExpression,
                        BoundBinaryOperator.Bind(SyntaxKind.PlusToken, TypeSymbol.Int, TypeSymbol.Int),
                        new BoundLiteralExpression(1)
                        )
                    )
                );

            BoundBlockStatement whileBody = new BoundBlockStatement(ImmutableArray.Create <BoundStatement>(
                                                                        node.Body,
                                                                        continueLabelStatement,
                                                                        increment
                                                                        ));
            BoundWhileStatement whileStatement = new BoundWhileStatement(condition, whileBody, node.BreakLabel, GenerateLabel());

            BoundBlockStatement result = new BoundBlockStatement(ImmutableArray.Create <BoundStatement>(
                                                                     variableDeclaration,
                                                                     upperVariableDeclaration,
                                                                     whileStatement
                                                                     ));

            return(RewriteStatement(result));
        }
예제 #13
0
        public static BoundConstant?FoldBinary(BoundBinaryOperator op, BoundExpression left, BoundExpression right)
        {
            if (op == BoundBinaryOperator.LogicalAnd)
            {
                if (!(left.Constant is null) && left.Constant.Value is bool b1 && !b1 || !(right.Constant is null) && right.Constant.Value is bool b2 && !b2)
                {
                    return(new BoundConstant(false));
                }
            }


            if (op == BoundBinaryOperator.LogicalAnd)
            {
                if (!(left.Constant is null) && left.Constant.Value is bool b1 && b1 || !(right.Constant is null) && right.Constant.Value is bool b2 && b2)
                {
                    return(new BoundConstant(true));
                }
            }

            if (left.Constant is null || right.Constant is null)
            {
                return(null);
            }

            var leftVal  = left.Constant.Value;
            var rightVal = right.Constant.Value;

            object res;

            switch (op)
            {
            case BoundBinaryOperator.Addition:
            {
                if (leftVal is int i1 && rightVal is int i2)
                {
                    res = i1 + i2;
                }
예제 #14
0
        //NOTE: The result of this should be a boolean on the stack.
        private void EmitBinaryCondOperator(BoundBinaryOperator binOp, bool sense)
        {
            bool andOrSense = sense;
            int opIdx;

            switch (binOp.OperatorKind.OperatorWithLogical())
            {
                case BinaryOperatorKind.LogicalOr:
                    Debug.Assert(binOp.Left.Type.SpecialType == SpecialType.System_Boolean);
                    Debug.Assert(binOp.Right.Type.SpecialType == SpecialType.System_Boolean);

                    // Rewrite (a || b) as ~(~a && ~b)
                    andOrSense = !andOrSense;
                    // Fall through
                    goto case BinaryOperatorKind.LogicalAnd;

                case BinaryOperatorKind.LogicalAnd:
                    Debug.Assert(binOp.Left.Type.SpecialType == SpecialType.System_Boolean);
                    Debug.Assert(binOp.Right.Type.SpecialType == SpecialType.System_Boolean);

                    // ~(a && b) is equivalent to (~a || ~b)
                    if (!andOrSense)
                    {
                        // generate (~a || ~b)
                        EmitShortCircuitingOperator(binOp, sense, sense, true);
                    }
                    else
                    {
                        // generate (a && b)
                        EmitShortCircuitingOperator(binOp, sense, !sense, false);
                    }
                    return;

                case BinaryOperatorKind.And:
                    Debug.Assert(binOp.Left.Type.SpecialType == SpecialType.System_Boolean);
                    Debug.Assert(binOp.Right.Type.SpecialType == SpecialType.System_Boolean);
                    EmitBinaryCondOperatorHelper(ILOpCode.And, binOp.Left, binOp.Right, sense);
                    return;

                case BinaryOperatorKind.Or:
                    Debug.Assert(binOp.Left.Type.SpecialType == SpecialType.System_Boolean);
                    Debug.Assert(binOp.Right.Type.SpecialType == SpecialType.System_Boolean);
                    EmitBinaryCondOperatorHelper(ILOpCode.Or, binOp.Left, binOp.Right, sense);
                    return;

                case BinaryOperatorKind.Xor:
                    Debug.Assert(binOp.Left.Type.SpecialType == SpecialType.System_Boolean);
                    Debug.Assert(binOp.Right.Type.SpecialType == SpecialType.System_Boolean);

                    // Xor is equivalent to not equal.
                    if (sense)
                        EmitBinaryCondOperatorHelper(ILOpCode.Xor, binOp.Left, binOp.Right, true);
                    else
                        EmitBinaryCondOperatorHelper(ILOpCode.Ceq, binOp.Left, binOp.Right, true);
                    return;

                case BinaryOperatorKind.NotEqual:
                    // neq  is emitted as  !eq
                    sense = !sense;
                    goto case BinaryOperatorKind.Equal;

                case BinaryOperatorKind.Equal:

                    var constant = binOp.Left.ConstantValue;
                    var comparand = binOp.Right;

                    if (constant == null)
                    {
                        constant = comparand.ConstantValue;
                        comparand = binOp.Left;
                    }

                    if (constant != null)
                    {
                        if (constant.IsDefaultValue)
                        {
                            if (!constant.IsFloating)
                            {
                                if (sense)
                                {
                                    EmitIsNullOrZero(comparand, constant);
                                }
                                else
                                {
                                    //  obj != null/0   for pointers and integral numerics is emitted as cgt.un
                                    EmitIsNotNullOrZero(comparand, constant);
                                }
                                return;
                            }
                        }
                        else if (constant.IsBoolean)
                        {
                            // treat  "x = True" ==> "x"
                            EmitExpression(comparand, true);
                            EmitIsSense(sense);
                            return;
                        }
                    }

                    EmitBinaryCondOperatorHelper(ILOpCode.Ceq, binOp.Left, binOp.Right, sense);
                    return;

                case BinaryOperatorKind.LessThan:
                    opIdx = 0;
                    break;

                case BinaryOperatorKind.LessThanOrEqual:
                    opIdx = 1;
                    sense = !sense; // lte is emitted as !gt 
                    break;

                case BinaryOperatorKind.GreaterThan:
                    opIdx = 2;
                    break;

                case BinaryOperatorKind.GreaterThanOrEqual:
                    opIdx = 3;
                    sense = !sense; // gte is emitted as !lt 
                    break;

                default:
                    throw ExceptionUtilities.UnexpectedValue(binOp.OperatorKind.OperatorWithLogical());
            }

            if (IsUnsignedBinaryOperator(binOp))
            {
                opIdx += 4;
            }
            else if (IsFloat(binOp.OperatorKind))
            {
                opIdx += 8;
            }

            EmitBinaryCondOperatorHelper(s_compOpCodes[opIdx], binOp.Left, binOp.Right, sense);
            return;
        }
        /// <summary>
        /// The rewrites are as follows:
        /// 
        /// x++
        ///     temp = x
        ///     x = temp + 1
        ///     return temp
        /// x--
        ///     temp = x
        ///     x = temp - 1
        ///     return temp
        /// ++x
        ///     temp = x + 1
        ///     x = temp
        ///     return temp
        /// --x
        ///     temp = x - 1
        ///     x = temp
        ///     return temp
        ///     
        /// In each case, the literal 1 is of the type required by the builtin addition/subtraction operator that
        /// will be used.  The temp is of the same type as x, but the sum/difference may be wider, in which case a
        /// conversion is required.
        /// </summary>
        /// <param name="node">The unary operator expression representing the increment/decrement.</param>
        /// <param name="isPrefix">True for prefix, false for postfix.</param>
        /// <param name="isIncrement">True for increment, false for decrement.</param>
        /// <returns>A bound sequence that uses a temp to acheive the correct side effects and return value.</returns>
        private BoundNode LowerOperator(BoundUnaryOperator node, bool isPrefix, bool isIncrement)
        {
            BoundExpression operand = node.Operand;
            TypeSymbol operandType = operand.Type; //type of the variable being incremented
            Debug.Assert(operandType == node.Type);

            ConstantValue constantOne;
            BinaryOperatorKind binaryOperatorKind;
            MakeConstantAndOperatorKind(node.OperatorKind.OperandTypes(), node, out constantOne, out binaryOperatorKind);
            binaryOperatorKind |= isIncrement ? BinaryOperatorKind.Addition : BinaryOperatorKind.Subtraction;

            Debug.Assert(constantOne != null);
            Debug.Assert(constantOne.SpecialType != SpecialType.None);
            Debug.Assert(binaryOperatorKind.OperandTypes() != 0);

            TypeSymbol constantType = compilation.GetSpecialType(constantOne.SpecialType);
            BoundExpression boundOne = new BoundLiteral(
                syntax: null,
                syntaxTree: null,
                constantValueOpt: constantOne,
                type: constantType);

            LocalSymbol tempSymbol = new TempLocalSymbol(operandType, RefKind.None, containingSymbol);
            BoundExpression boundTemp = new BoundLocal(
                syntax: null,
                syntaxTree: null,
                localSymbol: tempSymbol,
                constantValueOpt: null,
                type: operandType);

            // NOTE: the LHS may have a narrower type than the operator expects, but that
            // doesn't seem to cause any problems.  If a problem does arise, just add an
            // explicit BoundConversion.
            BoundExpression newValue = new BoundBinaryOperator(
                syntax: null,
                syntaxTree: null,
                operatorKind: binaryOperatorKind,
                left: isPrefix ? operand : boundTemp,
                right: boundOne,
                constantValueOpt: null,
                type: constantType);

            if (constantType != operandType)
            {
                newValue = new BoundConversion(
                    syntax: null,
                    syntaxTree: null,
                    operand: newValue,
                    conversionKind: operandType.IsEnumType() ? ConversionKind.ImplicitEnumeration : ConversionKind.ImplicitNumeric,
                    symbolOpt: null,
                    @checked: false,
                    explicitCastInCode: false,
                    constantValueOpt: null,
                    type: operandType);
            }

            ReadOnlyArray<BoundExpression> assignments = ReadOnlyArray<BoundExpression>.CreateFrom(
                new BoundAssignmentOperator(
                    syntax: null,
                    syntaxTree: null,
                    left: boundTemp,
                    right: isPrefix ? newValue : operand,
                    type: operandType),
                new BoundAssignmentOperator(
                    syntax: null,
                    syntaxTree: null,
                    left: operand,
                    right: isPrefix ? boundTemp : newValue,
                    type: operandType));

            return new BoundSequence(
                syntax: node.Syntax,
                syntaxTree: node.SyntaxTree,
                locals: ReadOnlyArray<LocalSymbol>.CreateFrom(tempSymbol),
                sideEffects: assignments,
                value: boundTemp,
                type: operandType);
        }
예제 #16
0
        /// <summary>
        /// Produces opcode for a jump that corresponds to given operation and sense.
        /// Also produces a reverse opcode - opcode for the same condition with inverted sense.
        /// </summary>
        private static ILOpCode CodeForJump(BoundBinaryOperator op, bool sense, out ILOpCode revOpCode)
        {
            int opIdx;

            switch (op.OperatorKind.Operator())
            {
                case BinaryOperatorKind.Equal:
                    revOpCode = !sense ? ILOpCode.Beq : ILOpCode.Bne_un;
                    return sense ? ILOpCode.Beq : ILOpCode.Bne_un;

                case BinaryOperatorKind.NotEqual:
                    revOpCode = !sense ? ILOpCode.Bne_un : ILOpCode.Beq;
                    return sense ? ILOpCode.Bne_un : ILOpCode.Beq;

                case BinaryOperatorKind.LessThan:
                    opIdx = 0;
                    break;

                case BinaryOperatorKind.LessThanOrEqual:
                    opIdx = 1;
                    break;

                case BinaryOperatorKind.GreaterThan:
                    opIdx = 2;
                    break;

                case BinaryOperatorKind.GreaterThanOrEqual:
                    opIdx = 3;
                    break;

                default:
                    throw ExceptionUtilities.UnexpectedValue(op.OperatorKind.Operator());
            }

            if (IsUnsignedBinaryOperator(op))
            {
                opIdx += 2 * IL_OP_CODE_ROW_LENGTH; //unsigned
            }
            else if (IsFloat(op.OperatorKind))
            {
                opIdx += 4 * IL_OP_CODE_ROW_LENGTH;  //float
            }

            int revOpIdx = opIdx;

            if (!sense)
            {
                opIdx += IL_OP_CODE_ROW_LENGTH; //invert op
            }
            else
            {
                revOpIdx += IL_OP_CODE_ROW_LENGTH; //invert rev
            }

            revOpCode = s_condJumpOpCodes[revOpIdx];
            return s_condJumpOpCodes[opIdx];
        }
예제 #17
0
        public override BoundNode VisitBinaryOperator(BoundBinaryOperator node)
        {
            BoundExpression child = node.Left;

            if (child.Kind != BoundKind.BinaryOperator || child.ConstantValue != null)
            {
                return base.VisitBinaryOperator(node);
            }

            // Do not blow the stack due to a deep recursion on the left.
            var stack = ArrayBuilder<BoundBinaryOperator>.GetInstance();
            stack.Push(node);

            BoundBinaryOperator binary = (BoundBinaryOperator)child;

            while (true)
            {
                stack.Push(binary);
                child = binary.Left;

                if (child.Kind != BoundKind.BinaryOperator || child.ConstantValue != null)
                {
                    break;
                }

                binary = (BoundBinaryOperator)child;
            }

            var left = (BoundExpression)this.Visit(child);

            while (true)
            {
                binary = stack.Pop();
                var right = (BoundExpression)this.Visit(binary.Right);
                var type = this.VisitType(binary.Type);
                left = binary.Update(binary.OperatorKind, left, right, binary.ConstantValueOpt, binary.MethodOpt, binary.ResultKind, type);

                if (stack.Count == 0)
                {
                    break;
                }

                _nodeCounter += 1;
            }

            Debug.Assert((object)binary == node);
            stack.Free();

            return left;
        }
예제 #18
0
        public override BoundNode VisitCompoundAssignmentOperator(BoundCompoundAssignmentOperator node)
        {
            if (node.HasErrors)
            {
                return(node);
            }

            // There are five possible cases.
            //
            // Case 1: receiver.Prop += value is transformed into
            // temp = receiver
            // temp.Prop = temp.Prop + value
            // and a later rewriting will turn that into calls to getters and setters.
            //
            // Case 2: collection[i1, i2, i3] += value is transformed into
            // tc = collection
            // t1 = i1
            // t2 = i2
            // t3 = i3
            // tc[t1, t2, t3] = tc[t1, t2, t3] + value
            // and again, a later rewriting will turn that into getters and setters of the indexer.
            //
            // Case 3: local += value (and param += value) needs no temporaries; it simply
            // becomes local = local + value.
            //
            // Case 4: staticField += value needs no temporaries either. However, classInst.field += value becomes
            // temp = classInst
            // temp.field = temp.field + value
            //
            // Case 5: otherwise, it must be structVariable.field += value or array[index] += value. Either way
            // we have a variable on the left. Transform it into:
            // ref temp = ref variable
            // temp = temp + value

            var temps = ArrayBuilder <LocalSymbol> .GetInstance();

            var stores = ArrayBuilder <BoundExpression> .GetInstance();

            // This will be filled in with the LHS that uses temporaries to prevent
            // double-evaluation of side effects.

            BoundExpression transformedLHS = null;

            if (node.Left.Kind == BoundKind.PropertyAccess)
            {
                // We need to stash away the receiver so that it does not get evaluated twice.
                // If the receiver is classified as a value of reference type then we can simply say
                //
                // R temp = receiver
                // temp.prop = temp.prop + rhs
                //
                // But if the receiver is classified as a variable of struct type then we
                // cannot make a copy of the value; we need to make sure that we mutate
                // the original receiver, not the copy.  We have to generate
                //
                // ref R temp = ref receiver
                // temp.prop = temp.prop + rhs
                //
                // The rules of C# (in section 7.17.1) require that if you have receiver.prop
                // as the target of an assignment such that receiver is a value type, it must
                // be classified as a variable. If we've gotten this far in the rewriting,
                // assume that was the case.

                var prop = (BoundPropertyAccess)node.Left;

                // If the property is static then we can just generate prop = prop + value
                if (prop.ReceiverOpt == null)
                {
                    transformedLHS = prop;
                }
                else
                {
                    // Can we ever avoid storing the receiver in a temp? If the receiver is a variable then it
                    // might be modified by the computation of the getter, the value, or the operation.
                    // The receiver cannot be a null constant or constant of value type. It could be a
                    // constant of string type, but there are no mutable properties of a string.
                    // Similarly, there are no mutable properties of a Type object, so the receiver
                    // cannot be a typeof(T) expression. The only situation I can think of where we could
                    // optimize away the temp is if the receiver is a readonly field of reference type,
                    // we are not in a constructor, and the receiver of the *field*, if any, is also idempotent.
                    // It doesn't seem worthwhile to pursue an optimization for this exceedingly rare case.

                    var rewrittenReceiver = (BoundExpression)Visit(prop.ReceiverOpt);
                    var receiverTemp      = TempHelpers.StoreToTemp(rewrittenReceiver, rewrittenReceiver.Type.IsValueType ? RefKind.Ref : RefKind.None, containingSymbol);
                    stores.Add(receiverTemp.Item1);
                    temps.Add(receiverTemp.Item2.LocalSymbol);
                    transformedLHS = new BoundPropertyAccess(prop.Syntax, prop.SyntaxTree, receiverTemp.Item2, prop.PropertySymbol, prop.Type);
                }
            }
            else if (node.Left.Kind == BoundKind.IndexerAccess)
            {
                var             indexer             = (BoundIndexerAccess)node.Left;
                BoundExpression transformedReceiver = null;
                if (indexer.ReceiverOpt != null)
                {
                    var rewrittenReceiver = (BoundExpression)Visit(indexer.ReceiverOpt);
                    var receiverTemp      = TempHelpers.StoreToTemp(rewrittenReceiver, rewrittenReceiver.Type.IsValueType ? RefKind.Ref : RefKind.None, containingSymbol);
                    transformedReceiver = receiverTemp.Item2;
                    stores.Add(receiverTemp.Item1);
                    temps.Add(receiverTemp.Item2.LocalSymbol);
                }

                // UNDONE: Dealing with the arguments is a bit tricky because they can be named out-of-order arguments;
                // UNDONE: we have to preserve both the source-code order of the side effects and the side effects
                // UNDONE: only being executed once.
                // UNDONE:
                // UNDONE: This is a subtly different problem than the problem faced by the conventional call
                // UNDONE: rewriter; with the conventional call rewriter we already know that the side effects
                // UNDONE: will only be executed once because the arguments are only being pushed on the stack once.
                // UNDONE: In a compound equality operator on an indexer the indices are placed on the stack twice.
                // UNDONE: That is to say, if you have:
                // UNDONE:
                // UNDONE: C().M(z : Z(), x : X(), y : Y())
                // UNDONE:
                // UNDONE: then we can rewrite that into
                // UNDONE:
                // UNDONE: tempc = C()
                // UNDONE: tempz = Z()
                // UNDONE: tempc.M(X(), Y(), tempz)
                // UNDONE:
                // UNDONE: See, we can optimize away two of the temporaries, for x and y. But we cannot optimize away any of the
                // UNDONE: temporaries in
                // UNDONE:
                // UNDONE: C().Collection[z : Z(), x : X(), y : Y()] += 1;
                // UNDONE:
                // UNDONE: because we have to ensure not just that Z() happens first, but in additioan that X() and Y() are only
                // UNDONE: called once.  We have to generate this as
                // UNDONE:
                // UNDONE: tempc = C().Collection
                // UNDONE: tempz = Z()
                // UNDONE: tempx = X()
                // UNDONE: tempy = Y()
                // UNDONE: tempc[tempx, tempy, tempz] = tempc[tempx, tempy, tempz] + 1;
                // UNDONE:
                // UNDONE: Fortunately arguments to indexers are never ref or out, so we don't need to worry about that.
                // UNDONE: However, we can still do the optimization where constants are not stored in
                // UNDONE: temporaries; if we have
                // UNDONE:
                // UNDONE: C().Collection[z : 123, y : Y(), x : X()] += 1;
                // UNDONE:
                // UNDONE: Then we can generate that as
                // UNDONE:
                // UNDONE: tempc = C().Collection
                // UNDONE: tempx = X()
                // UNDONE: tempy = Y()
                // UNDONE: tempc[tempx, tempy, 123] = tempc[tempx, tempy, 123] + 1;
                // UNDONE:
                // UNDONE: For now, we'll punt on both problems, as indexers are not implemented yet anyway.
                // UNDONE: We'll just generate one temporary for each argument. This will work, but in the
                // UNDONE: subsequent rewritings will generate more unnecessary temporaries.

                var transformedArguments = ArrayBuilder <BoundExpression> .GetInstance();

                foreach (var argument in indexer.Arguments)
                {
                    var rewrittenArgument = (BoundExpression)Visit(argument);
                    var argumentTemp      = TempHelpers.StoreToTemp(rewrittenArgument, RefKind.None, containingSymbol);
                    transformedArguments.Add(argumentTemp.Item2);
                    stores.Add(argumentTemp.Item1);
                    temps.Add(argumentTemp.Item2.LocalSymbol);
                }

                transformedLHS = new BoundIndexerAccess(indexer.Syntax, indexer.SyntaxTree, transformedArguments.ToReadOnlyAndFree(), transformedReceiver,
                                                        indexer.IndexerSymbol, indexer.Type);
            }
            else if (node.Left.Kind == BoundKind.Local || node.Left.Kind == BoundKind.Parameter)
            {
                // No temporaries are needed. Just generate local = local + value
                transformedLHS = node.Left;
            }
            else if (node.Left.Kind == BoundKind.FieldAccess)
            {
                // * If the field is static then no temporaries are needed.
                // * If the field is not static and the receiver is of reference type then generate t = r; t.f = t.f + value
                // * If the field is not static and the receiver is a variable of value type then we'll fall into the
                //   general variable case below.

                var fieldAccess = (BoundFieldAccess)node.Left;
                if (fieldAccess.ReceiverOpt == null)
                {
                    transformedLHS = fieldAccess;
                }
                else if (!fieldAccess.ReceiverOpt.Type.IsValueType)
                {
                    var rewrittenReceiver = (BoundExpression)Visit(fieldAccess.ReceiverOpt);
                    var receiverTemp      = TempHelpers.StoreToTemp(rewrittenReceiver, RefKind.None, containingSymbol);
                    stores.Add(receiverTemp.Item1);
                    temps.Add(receiverTemp.Item2.LocalSymbol);
                    transformedLHS = new BoundFieldAccess(fieldAccess.Syntax, fieldAccess.SyntaxTree, receiverTemp.Item2, fieldAccess.FieldSymbol, null);
                }
            }

            if (transformedLHS == null)
            {
                // We made no transformation above. Either we have array[index] += value or
                // structVariable.field += value; either way we have a potentially complicated variable-
                // producing expression on the left. Generate
                // ref temp = ref variable; temp = temp + value
                var rewrittenVariable = (BoundExpression)Visit(node.Left);
                var variableTemp      = TempHelpers.StoreToTemp(rewrittenVariable, RefKind.Ref, containingSymbol);
                stores.Add(variableTemp.Item1);
                temps.Add(variableTemp.Item2.LocalSymbol);
                transformedLHS = variableTemp.Item2;
            }

            // OK, we now have the temporary declarations, the temporary stores, and the transformed left hand side.
            // We need to generate
            //
            // xlhs = (FINAL)((LEFT)xlhs op rhs)
            //
            // And then wrap it up with the generated temporaries.
            //
            // (The right hand side has already been converted to the type expected by the operator.)

            BoundExpression opLHS = BoundConversion.SynthesizedConversion(transformedLHS, node.LeftConversion, node.Operator.LeftType);

            Debug.Assert(node.Right.Type == node.Operator.RightType);
            BoundExpression op         = new BoundBinaryOperator(null, null, node.Operator.Kind, opLHS, node.Right, null, node.Operator.ReturnType);
            BoundExpression opFinal    = BoundConversion.SynthesizedConversion(op, node.FinalConversion, node.Left.Type);
            BoundExpression assignment = new BoundAssignmentOperator(null, null, transformedLHS, opFinal, node.Left.Type);

            // OK, at this point we have:
            //
            // * temps evaluating and storing portions of the LHS that must be evaluated only once.
            // * the "transformed" left hand side, rebuilt to use temps where necessary
            // * the assignment "xlhs = (FINAL)((LEFT)xlhs op (RIGHT)rhs)"
            //
            // Notice that we have recursively rewritten the bound nodes that are things stored in
            // the temps, but we might have more rewriting to do on the assignment. There are three
            // conversions in there that might be lowered to method calls, an operator that might
            // be lowered to delegate combine, string concat, and so on, and don't forget, we
            // haven't lowered the right hand side at all! Let's rewrite all these things at once.

            BoundExpression rewrittenAssignment = (BoundExpression)Visit(assignment);

            BoundExpression result = (temps.Count == 0) ?
                                     rewrittenAssignment :
                                     new BoundSequence(null,
                                                       null,
                                                       temps.ToReadOnly(),
                                                       stores.ToReadOnly(),
                                                       rewrittenAssignment,
                                                       rewrittenAssignment.Type);

            temps.Free();
            stores.Free();
            return(result);
        }
예제 #19
0
        private void EmitBinaryOperator(BoundBinaryOperator expression)
        {
            BoundExpression child = expression.Left;

            if (child.Kind != BoundKind.BinaryOperator || child.ConstantValue != null)
            {
                EmitBinaryOperatorSimple(expression);
                return;
            }

            BoundBinaryOperator binary = (BoundBinaryOperator)child;
            var operatorKind = binary.OperatorKind;

            if (!operatorKind.EmitsAsCheckedInstruction() && IsConditional(operatorKind))
            {
                EmitBinaryOperatorSimple(expression);
                return;
            }

            // Do not blow the stack due to a deep recursion on the left.
            var stack = ArrayBuilder<BoundBinaryOperator>.GetInstance();
            stack.Push(expression);

            while (true)
            {
                stack.Push(binary);
                child = binary.Left;

                if (child.Kind != BoundKind.BinaryOperator || child.ConstantValue != null)
                {
                    break;
                }

                binary = (BoundBinaryOperator)child;
                operatorKind = binary.OperatorKind;

                if (!operatorKind.EmitsAsCheckedInstruction() && IsConditional(operatorKind))
                {
                    break;
                }
            }

            EmitExpression(child, true);

            do
            {
                binary = stack.Pop();

                EmitExpression(binary.Right, true);
                bool isChecked = binary.OperatorKind.EmitsAsCheckedInstruction();
                if (isChecked)
                {
                    EmitBinaryCheckedOperatorInstruction(binary);
                }
                else
                {
                    EmitBinaryOperatorInstruction(binary);
                }

                EmitConversionToEnumUnderlyingType(binary, @checked: isChecked);
            }
            while (stack.Count > 0);

            Debug.Assert((object)binary == expression);
            stack.Free();
        }
예제 #20
0
        private void EmitBinaryCheckedOperatorInstruction(BoundBinaryOperator expression)
        {
            var unsigned = IsUnsignedBinaryOperator(expression);

            switch (expression.OperatorKind.Operator())
            {
                case BinaryOperatorKind.Multiplication:
                    if (unsigned)
                    {
                        _builder.EmitOpCode(ILOpCode.Mul_ovf_un);
                    }
                    else
                    {
                        _builder.EmitOpCode(ILOpCode.Mul_ovf);
                    }
                    break;

                case BinaryOperatorKind.Addition:
                    if (unsigned)
                    {
                        _builder.EmitOpCode(ILOpCode.Add_ovf_un);
                    }
                    else
                    {
                        _builder.EmitOpCode(ILOpCode.Add_ovf);
                    }
                    break;

                case BinaryOperatorKind.Subtraction:
                    if (unsigned)
                    {
                        _builder.EmitOpCode(ILOpCode.Sub_ovf_un);
                    }
                    else
                    {
                        _builder.EmitOpCode(ILOpCode.Sub_ovf);
                    }
                    break;

                default:
                    throw ExceptionUtilities.UnexpectedValue(expression.OperatorKind.Operator());
            }
        }
예제 #21
0
파일: lower.cs 프로젝트: HirushaR/Lex
        protected override BoundStatement RewriteForStatement(BoundForStatement node)
        {
            // for <var> = <lower> to <upper> by <incriment>
            //      <body>
            //
            // ---->
            //
            // {
            //      var <var> = <lower>
            //      while (<var> <= <upper>)
            //      {
            //          <body>
            //          continue:
            //          <var> = <var> + 1
            //      }
            // }



            var variableDeclaration = new BoundVeriableDeclaration(node.Variable, node.LowerBound);
            var variableExpression  = new BoundVariableExpression(node.Variable);


            var upperBoundSybmle      = new LocalVariableSymbol("upperBound", true, TypeSymbol.Int);
            var upperBoundDeclaration = new BoundVeriableDeclaration(upperBoundSybmle, node.UpperBound);

            var condition = new BoundBinaryExpression(
                variableExpression,
                BoundBinaryOperator.Bind(SyntaxKind.LessOrEqualToken, TypeSymbol.Int, TypeSymbol.Int),
                new BoundVariableExpression(upperBoundSybmle)
                );

            var Ittertator = node.Itterator;
            var Operator   = SyntaxKind.PlusToken;

            if (Ittertator == null)
            {
                Ittertator = new BoundLiteralExpression(1);
            }
            var continueLabelStatement = new BoundLabelStatement(node.ContinueLabel);
            var increment = new BoundExpressionStatemnet(
                new BoundAssignmentExpression(
                    node.Variable,
                    new BoundBinaryExpression(
                        variableExpression,
                        BoundBinaryOperator.Bind(Operator, TypeSymbol.Int, TypeSymbol.Int),
                        Ittertator
                        )
                    )
                );
            var whileBody = new BoundBlockStatemnet(ImmutableArray.Create <BoundStatement>(
                                                        node.Body,
                                                        continueLabelStatement,
                                                        increment)
                                                    );
            var whileStatement = new BoundWhileStatement(condition, whileBody, node.BodyLabel, node.BreakLabel, GenerateLabel());
            var result         = new BoundBlockStatemnet(ImmutableArray.Create <BoundStatement>(
                                                             variableDeclaration,
                                                             upperBoundDeclaration,
                                                             whileStatement));

            return(RewriteStatement(result));
        }
예제 #22
0
 public BoundBinaryExpression(BoundExpression left, BoundBinaryOperator op, BoundExpression right)
 {
     Left  = left;
     Op    = op;
     Right = right;
 }
예제 #23
0
        /// <summary>
        /// Lower a foreach loop that will enumerate a single-dimensional array.
        ///
        /// A[] a = x;
        /// for (int p = 0; p &lt; a.Length; p = p + 1) {
        ///     V v = (V)a[p];
        ///     // body
        /// }
        /// </summary>
        /// <remarks>
        /// We will follow Dev10 in diverging from the C# 4 spec by ignoring Array's
        /// implementation of IEnumerable and just indexing into its elements.
        ///
        /// NOTE: We're assuming that sequence points have already been generated.
        /// Otherwise, lowering to for-loops would generated spurious ones.
        /// </remarks>
        private BoundStatement RewriteSingleDimensionalArrayForEachStatement(BoundForEachStatement node)
        {
            ForEachStatementSyntax forEachSyntax = (ForEachStatementSyntax)node.Syntax;

            BoundExpression collectionExpression = GetUnconvertedCollectionExpression(node);

            Debug.Assert(collectionExpression.Type.IsArray());

            ArrayTypeSymbol arrayType = (ArrayTypeSymbol)collectionExpression.Type;

            Debug.Assert(arrayType.Rank == 1);

            TypeSymbol intType  = compilation.GetSpecialType(SpecialType.System_Int32);
            TypeSymbol boolType = compilation.GetSpecialType(SpecialType.System_Boolean);

            BoundExpression rewrittenExpression = (BoundExpression)Visit(collectionExpression);
            BoundStatement  rewrittenBody       = (BoundStatement)Visit(node.Body);

            // A[] a
            LocalSymbol arrayVar = new TempLocalSymbol(arrayType, RefKind.None, containingMethod);

            // A[] a = /*node.Expression*/;
            BoundStatement arrayVarDecl = MakeLocalDeclaration(forEachSyntax, arrayVar, rewrittenExpression);

            AddForEachExpressionSequencePoint(forEachSyntax, ref arrayVarDecl);

            // Reference to a.
            BoundLocal boundArrayVar = MakeBoundLocal(forEachSyntax, arrayVar, arrayType);

            // int p
            LocalSymbol positionVar = new TempLocalSymbol(intType, RefKind.None, containingMethod);

            // Reference to p.
            BoundLocal boundPositionVar = MakeBoundLocal(forEachSyntax, positionVar, intType);

            // int p = 0;
            BoundStatement positionVarDecl = MakeLocalDeclaration(forEachSyntax, positionVar,
                                                                  new BoundLiteral(forEachSyntax, ConstantValue.ConstantValueZero.Int32, intType));

            // V v
            LocalSymbol iterationVar     = node.IterationVariable;
            TypeSymbol  iterationVarType = iterationVar.Type;

            // (V)a[p]
            BoundExpression iterationVarInitValue = SynthesizeConversion(
                syntax: forEachSyntax,
                operand: new BoundArrayAccess(
                    syntax: forEachSyntax,
                    expression: boundArrayVar,
                    indices: ReadOnlyArray <BoundExpression> .CreateFrom(boundPositionVar),
                    type: arrayType.ElementType),
                conversion: node.ElementConversion,
                type: iterationVarType);

            // V v = (V)a[p];
            BoundStatement iterationVariableDecl = MakeLocalDeclaration(forEachSyntax, iterationVar, iterationVarInitValue);

            AddForEachIterationVariableSequencePoint(forEachSyntax, ref iterationVariableDecl);

            BoundStatement initializer = new BoundStatementList(forEachSyntax,
                                                                statements: ReadOnlyArray <BoundStatement> .CreateFrom(arrayVarDecl, positionVarDecl));

            // a.Length
            BoundExpression arrayLength = new BoundArrayLength(
                syntax: forEachSyntax,
                expression: boundArrayVar,
                type: intType);

            // p < a.Length
            BoundExpression exitCondition = new BoundBinaryOperator(
                syntax: forEachSyntax,
                operatorKind: BinaryOperatorKind.IntLessThan,
                left: boundPositionVar,
                right: arrayLength,
                constantValueOpt: null,
                methodOpt: null,
                resultKind: LookupResultKind.Viable,
                type: boolType);

            // p = p + 1;
            BoundStatement positionIncrement = MakePositionIncrement(forEachSyntax, boundPositionVar, intType);

            // { V v = (V)a[p]; /* node.Body */ }
            BoundStatement loopBody = new BoundBlock(forEachSyntax,
                                                     localsOpt: ReadOnlyArray <LocalSymbol> .CreateFrom(iterationVar),
                                                     statements: ReadOnlyArray <BoundStatement> .CreateFrom(iterationVariableDecl, rewrittenBody));

            // for (A[] a = /*node.Expression*/, int p = 0; p < a.Length; p = p + 1) {
            //     V v = (V)a[p];
            //     /*node.Body*/
            // }
            BoundStatement result = RewriteForStatement(
                syntax: node.Syntax,
                locals: ReadOnlyArray <LocalSymbol> .CreateFrom(arrayVar, positionVar),
                rewrittenInitializer: initializer,
                rewrittenCondition: exitCondition,
                conditionSyntax: forEachSyntax.InKeyword,
                rewrittenIncrement: positionIncrement,
                rewrittenBody: loopBody,
                breakLabel: node.BreakLabel,
                continueLabel: node.ContinueLabel, hasErrors: node.HasErrors);

            AddForEachKeywordSequencePoint(forEachSyntax, ref result);

            return(result);
        }
예제 #24
0
        internal void Parse(BoundBinaryOperator boundBinaryOperator)
        {
            base.Parse(boundBinaryOperator);
            this.OperatorKind = boundBinaryOperator.OperatorKind;

            // special case for PointerAddition
            if (IsPointerOperation(this.OperatorKind))
            {
                var left = true;
                var boundBinaryOperator2 = FindBinaryOperatorForPointerOperation(boundBinaryOperator.Right);
                if (boundBinaryOperator2 == null)
                {
                    left = false;
                    boundBinaryOperator2 = FindBinaryOperatorForPointerOperation(boundBinaryOperator.Left);
                }

                if (boundBinaryOperator2 != null)
                {
                    if (HasSizeOfOperator(boundBinaryOperator2.Left))
                    {
                        this.Right = Deserialize(boundBinaryOperator2.Right) as Expression;
                    }
                    else if (HasSizeOfOperator(boundBinaryOperator2.Right))
                    {
                        this.Right = Deserialize(boundBinaryOperator2.Left) as Expression;
                    }

                    if (this.Right != null)
                    {
                        this.Left = (left)
                            ? Deserialize(boundBinaryOperator.Left) as Expression
                            : Deserialize(boundBinaryOperator.Right) as Expression;
                        return;
                    }
                }

                // to support <pointer> +/- sizeof()
                if (boundBinaryOperator2 == null && HasSizeOfOperator(boundBinaryOperator.Right))
                {
                    this.Left  = Deserialize(boundBinaryOperator.Left) as Expression;
                    this.Right = new Literal {
                        Value = ConstantValue.Create(1)
                    };
                    return;
                }

                if (boundBinaryOperator2 == null && HasSizeOfOperator(boundBinaryOperator.Left))
                {
                    this.Left = new Literal {
                        Value = ConstantValue.Create(1)
                    };
                    this.Right = Deserialize(boundBinaryOperator.Right) as Expression;
                    return;
                }
            }

            // special case for PointerSubtraction
            if (GetOperatorKind(this.OperatorKind) == BinaryOperatorKind.Division)
            {
                var boundBinaryOperator2 = boundBinaryOperator.Left as BoundBinaryOperator;
                if (boundBinaryOperator2 != null && IsPointerOperation(boundBinaryOperator2.OperatorKind) &&
                    GetOperatorKind(boundBinaryOperator2.OperatorKind) == BinaryOperatorKind.Subtraction)
                {
                    this.Parse(boundBinaryOperator2);
                    return;
                }
            }

            this.Left  = Deserialize(boundBinaryOperator.Left) as Expression;
            this.Right = Deserialize(boundBinaryOperator.Right) as Expression;
        }
        public override BoundNode VisitBinaryOperator(BoundBinaryOperator node)
        {
            if (node.ConstantValueOpt != null)
            {
                return node;
            }

            switch (node.OperatorKind)
            {
                case BinaryOperatorKind.ObjectAndStringConcatenation:
                case BinaryOperatorKind.StringAndObjectConcatenation:
                case BinaryOperatorKind.StringConcatenation:
                    return RewriteStringConcatenation(node);
                case BinaryOperatorKind.StringEqual:
                    return RewriteStringEquality(node, SpecialMember.System_String__op_Equality);
                case BinaryOperatorKind.StringNotEqual:
                    return RewriteStringEquality(node, SpecialMember.System_String__op_Inequality);
                case BinaryOperatorKind.DelegateCombination:
                    return RewriteDelegateOperation(node, SpecialMember.System_Delegate__Combine);
                case BinaryOperatorKind.DelegateRemoval:
                    return RewriteDelegateOperation(node, SpecialMember.System_Delegate__Remove);
                case BinaryOperatorKind.DelegateEqual:
                    return RewriteDelegateOperation(node, SpecialMember.System_Delegate__op_Equality);
                case BinaryOperatorKind.DelegateNotEqual:
                    return RewriteDelegateOperation(node, SpecialMember.System_Delegate__op_Inequality);
            }
            return base.VisitBinaryOperator(node);
        }
예제 #26
0
 public BoundBinaryExpression(BoundExpression left, BoundBinaryOperator @operator, BoundExpression right)
 {
     Left     = left;
     Operator = @operator;
     Right    = right;
 }
예제 #27
0
        private void EmitConversionToEnumUnderlyingType(BoundBinaryOperator expression, bool @checked)
        {
            // If we are doing an enum addition or subtraction and the 
            // underlying type is 8 or 16 bits then we will have done the operation in 32 
            // bits and we need to convert back down to the smaller bit size
            // to [one|zero]extend the value
            // NOTE: we do not need to do this for bitwise operations since they will always 
            //       result in a properly sign-extended result, assuming operands were sign extended
            //
            // If e is a value of enum type E and u is a value of underlying type u then:
            //
            // e + u --> (E)((U)e + u)
            // u + e --> (E)(u + (U)e)
            // e - e --> (U)((U)e - (U)e)
            // e - u --> (E)((U)e - u)
            // e & e --> (E)((U)e & (U)e)
            // e | e --> (E)((U)e | (U)e)
            // e ^ e --> (E)((U)e ^ (U)e)
            //
            // NOTE: (E) is actually emitted as (U) and in last 3 cases is not necessary.
            //
            // Due to a bug, the native compiler allows:
            //
            // u - e --> (E)(u - (U)e)
            //
            // And so Roslyn does as well.

            TypeSymbol enumType;

            switch (expression.OperatorKind.Operator() | expression.OperatorKind.OperandTypes())
            {
                case BinaryOperatorKind.EnumAndUnderlyingAddition:
                case BinaryOperatorKind.EnumSubtraction:
                case BinaryOperatorKind.EnumAndUnderlyingSubtraction:
                    enumType = expression.Left.Type;
                    break;
                case BinaryOperatorKind.EnumAnd:
                case BinaryOperatorKind.EnumOr:
                case BinaryOperatorKind.EnumXor:
                    Debug.Assert(expression.Left.Type == expression.Right.Type);
                    enumType = null;
                    break;
                case BinaryOperatorKind.UnderlyingAndEnumSubtraction:
                case BinaryOperatorKind.UnderlyingAndEnumAddition:
                    enumType = expression.Right.Type;
                    break;
                default:
                    enumType = null;
                    break;
            }

            if ((object)enumType == null)
            {
                return;
            }

            Debug.Assert(enumType.IsEnumType());

            SpecialType type = enumType.GetEnumUnderlyingType().SpecialType;
            switch (type)
            {
                case SpecialType.System_Byte:
                    _builder.EmitNumericConversion(Microsoft.Cci.PrimitiveTypeCode.Int32, Microsoft.Cci.PrimitiveTypeCode.UInt8, @checked);
                    break;
                case SpecialType.System_SByte:
                    _builder.EmitNumericConversion(Microsoft.Cci.PrimitiveTypeCode.Int32, Microsoft.Cci.PrimitiveTypeCode.Int8, @checked);
                    break;
                case SpecialType.System_Int16:
                    _builder.EmitNumericConversion(Microsoft.Cci.PrimitiveTypeCode.Int32, Microsoft.Cci.PrimitiveTypeCode.Int16, @checked);
                    break;
                case SpecialType.System_UInt16:
                    _builder.EmitNumericConversion(Microsoft.Cci.PrimitiveTypeCode.Int32, Microsoft.Cci.PrimitiveTypeCode.UInt16, @checked);
                    break;
            }
        }
예제 #28
0
        //NOTE: The result of this should be a boolean on the stack.
        private void EmitBinaryCondOperator(BoundBinaryOperator binOp, bool sense)
        {
            bool andOrSense = sense;
            int  opIdx;

            switch (binOp.OperatorKind.OperatorWithLogical())
            {
            case BinaryOperatorKind.LogicalOr:
                Debug.Assert(binOp.Left.Type.SpecialType == SpecialType.System_Boolean);
                Debug.Assert(binOp.Right.Type.SpecialType == SpecialType.System_Boolean);

                // Rewrite (a || b) as ~(~a && ~b)
                andOrSense = !andOrSense;
                // Fall through
                goto case BinaryOperatorKind.LogicalAnd;

            case BinaryOperatorKind.LogicalAnd:
                Debug.Assert(binOp.Left.Type.SpecialType == SpecialType.System_Boolean);
                Debug.Assert(binOp.Right.Type.SpecialType == SpecialType.System_Boolean);

                // ~(a && b) is equivalent to (~a || ~b)
                if (!andOrSense)
                {
                    // generate (~a || ~b)
                    EmitShortCircuitingOperator(binOp, sense, sense, true);
                }
                else
                {
                    // generate (a && b)
                    EmitShortCircuitingOperator(binOp, sense, !sense, false);
                }
                return;

            case BinaryOperatorKind.And:
                Debug.Assert(binOp.Left.Type.SpecialType == SpecialType.System_Boolean);
                Debug.Assert(binOp.Right.Type.SpecialType == SpecialType.System_Boolean);
                EmitBinaryCondOperatorHelper(ILOpCode.And, binOp.Left, binOp.Right, sense);
                return;

            case BinaryOperatorKind.Or:
                Debug.Assert(binOp.Left.Type.SpecialType == SpecialType.System_Boolean);
                Debug.Assert(binOp.Right.Type.SpecialType == SpecialType.System_Boolean);
                EmitBinaryCondOperatorHelper(ILOpCode.Or, binOp.Left, binOp.Right, sense);
                return;

            case BinaryOperatorKind.Xor:
                Debug.Assert(binOp.Left.Type.SpecialType == SpecialType.System_Boolean);
                Debug.Assert(binOp.Right.Type.SpecialType == SpecialType.System_Boolean);

                // Xor is equivalent to not equal.
                if (sense)
                {
                    EmitBinaryCondOperatorHelper(ILOpCode.Xor, binOp.Left, binOp.Right, true);
                }
                else
                {
                    EmitBinaryCondOperatorHelper(ILOpCode.Ceq, binOp.Left, binOp.Right, true);
                }
                return;

            case BinaryOperatorKind.NotEqual:
                // neq  is emitted as  !eq
                sense = !sense;
                goto case BinaryOperatorKind.Equal;

            case BinaryOperatorKind.Equal:

                var constant  = binOp.Left.ConstantValue;
                var comparand = binOp.Right;

                if (constant == null)
                {
                    constant  = comparand.ConstantValue;
                    comparand = binOp.Left;
                }

                if (constant != null)
                {
                    if (constant.IsDefaultValue)
                    {
                        if (!constant.IsFloating)
                        {
                            if (sense)
                            {
                                EmitIsNullOrZero(comparand, constant);
                            }
                            else
                            {
                                //  obj != null/0   for pointers and integral numerics is emitted as cgt.un
                                EmitIsNotNullOrZero(comparand, constant);
                            }
                            return;
                        }
                    }
                    else if (constant.IsBoolean)
                    {
                        // treat  "x = True" ==> "x"
                        EmitExpression(comparand, true);
                        EmitIsSense(sense);
                        return;
                    }
                }

                EmitBinaryCondOperatorHelper(ILOpCode.Ceq, binOp.Left, binOp.Right, sense);
                return;

            case BinaryOperatorKind.LessThan:
                opIdx = 0;
                break;

            case BinaryOperatorKind.LessThanOrEqual:
                opIdx = 1;
                sense = !sense;     // lte is emitted as !gt
                break;

            case BinaryOperatorKind.GreaterThan:
                opIdx = 2;
                break;

            case BinaryOperatorKind.GreaterThanOrEqual:
                opIdx = 3;
                sense = !sense;     // gte is emitted as !lt
                break;

            default:
                throw ExceptionUtilities.UnexpectedValue(binOp.OperatorKind.OperatorWithLogical());
            }

            if (IsUnsignedBinaryOperator(binOp))
            {
                opIdx += 4;
            }
            else if (IsFloat(binOp.OperatorKind))
            {
                opIdx += 8;
            }

            EmitBinaryCondOperatorHelper(s_compOpCodes[opIdx], binOp.Left, binOp.Right, sense);
            return;
        }
예제 #29
0
        private DustObject EvaluateBinaryExpression(BoundBinaryExpression binaryExpression)
        {
            DustObject left  = EvaluateExpression(binaryExpression.Left);
            DustObject right = EvaluateExpression(binaryExpression.Right);

            BoundBinaryOperator @operator = binaryExpression.Operator;

            if (@operator.IsInterchangeable && !left.IsAssignableFrom(@operator.LeftType))
            {
                (left, right) = (right, left);
            }

            switch (binaryExpression.Operator.Kind)
            {
            case BinaryOperatorKind.Add:
                return(left.Add(right));

            case BinaryOperatorKind.Subtract:
                return(left.Subtract(right));

            case BinaryOperatorKind.Multiply:
                return(left.Multiply(right));

            case BinaryOperatorKind.Divide:
                return(left.Divide(right));

            /*case BinaryOperatorKind.Modulo:
             * if (left is double || right is double)
             * {
             *  return (double) left % (double) right;
             * }
             *
             * if (left is float || right is float)
             * {
             *  return (float) left % (float) right;
             * }
             *
             * return (int) left % (int) right;
             * case BinaryOperatorKind.Exponentiate:
             * return Convert.ChangeType(Math.Pow(Convert.ToDouble(left), Convert.ToDouble(right)), binaryExpression.Type.ToNativeType());
             * case BinaryOperatorKind.Equal:
             * {
             * if (left is bool leftBoolValue && right is bool rightBoolValue)
             * {
             *  return leftBoolValue == rightBoolValue;
             * }
             *
             * if (left is double || right is double)
             * {
             *  return (double) left == (double) right;
             * }
             *
             * if (left is float || right is float)
             * {
             *  return (float) left == (float) right;
             * }
             *
             * if (left is int || right is int)
             * {
             *  return (int) left == (int) right;
             * }
             *
             * throw new Exception("Equal only implemented for booleans.");
             * }
             * case BinaryOperatorKind.NotEqual:
             * {
             * if (left is bool leftBoolValue && right is bool rightBoolValue)
             * {
             *  return leftBoolValue != rightBoolValue;
             * }
             *
             * if (left is double || right is double)
             * {
             *  return (double) left != (double) right;
             * }
             *
             * if (left is float || right is float)
             * {
             *  return (float) left != (float) right;
             * }
             *
             * if (left is int || right is int)
             * {
             *  return (int) left != (int) right;
             * }
             *
             * throw new Exception("NotEqual only implemented for booleans.");
             * }
             * case BinaryOperatorKind.And:
             * return (bool) left && (bool) right;
             * case BinaryOperatorKind.Or:
             * return (bool) left || (bool) right;
             * case BinaryOperatorKind.GreaterThan:
             * return Convert.ToDouble(left) > Convert.ToDouble(right);
             * case BinaryOperatorKind.GreaterThanEqual:
             * return Convert.ToDouble(left) >= Convert.ToDouble(right);
             * case BinaryOperatorKind.LessThan:
             * return Convert.ToDouble(left) < Convert.ToDouble(right);
             * case BinaryOperatorKind.LessThanEqual:
             * return Convert.ToDouble(left) <= Convert.ToDouble(right);*/
            default:
                return(null);
            }
        }
예제 #30
0
    protected override BoundExpression RewriteForExpression(BoundForExpression node)
    {
        /*
         * convert from for to while
         *
         * for (x <- l to u) expr
         *
         * var x = l
         * while(x < u) {
         *     expr
         *     continue:
         *     x = x + 1
         * }
         */

        var lowerBound = RewriteExpression(node.LowerBound);
        var upperBound = RewriteExpression(node.UpperBound);
        var body       = RewriteExpression(node.Body);

        var declareX = new BoundVariableDeclarationStatement(
            node.Syntax,
            node.Variable,
            lowerBound
            );

        var variableExpression = ValueExpression(node.Syntax, node.Variable);
        var condition          = new BoundBinaryExpression(
            node.Syntax,
            variableExpression,
            BoundBinaryOperator.BindOrThrow(SyntaxKind.LessThanToken, Type.Int, Type.Int),
            upperBound
            );
        var continueLabelStatement = new BoundLabelStatement(node.Syntax, node.ContinueLabel);
        var incrementX             = new BoundExpressionStatement(
            node.Syntax,
            new BoundAssignmentExpression(
                node.Syntax,
                variableExpression,
                new BoundBinaryExpression(
                    node.Syntax,
                    variableExpression,
                    BoundBinaryOperator.BindOrThrow(SyntaxKind.PlusToken, Type.Int, Type.Int),
                    new BoundLiteralExpression(node.Syntax, 1)
                    )
                )
            );
        var whileBody = new BoundBlockExpression(
            node.Syntax,
            ImmutableArray.Create <BoundStatement>(
                new BoundExpressionStatement(body.Syntax, body),
                continueLabelStatement,
                incrementX
                ),
            new BoundUnitExpression(node.Syntax)
            );

        var newBlock = new BoundBlockExpression(
            node.Syntax,
            ImmutableArray.Create <BoundStatement>(declareX),
            new BoundWhileExpression(
                node.Syntax,
                condition,
                whileBody,
                node.BreakLabel,
                new BoundLabel("continue")
                )
            );

        return(RewriteExpression(newBlock));
    }
예제 #31
0
        private static bool IsUnsignedBinaryOperator(BoundBinaryOperator op)
        {
            BinaryOperatorKind opKind = op.OperatorKind;
            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.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;
            }
        }
예제 #32
0
 public BoundBinaryExpression(SyntaxNode syntax, BoundExpression left, BoundBinaryOperator @operator, BoundExpression right)
     : base(syntax) =>
     (this.Left, this.Operator, this.Right, this.ConstantValue) =
예제 #33
0
        /// <summary>
        /// Lower a foreach loop that will enumerate the characters of a string.
        ///
        /// string s = x;
        /// for (int p = 0; p &lt; s.Length; p = p + 1) {
        ///     V v = (V)s.Chars[p];
        ///     // body
        /// }
        /// </summary>
        /// <remarks>
        /// We will follow Dev10 in diverging from the C# 4 spec by ignoring string's
        /// implementation of IEnumerable and just indexing into its characters.
        ///
        /// NOTE: We're assuming that sequence points have already been generated.
        /// Otherwise, lowering to for-loops would generated spurious ones.
        /// </remarks>
        private BoundStatement RewriteStringForEachStatement(BoundForEachStatement node)
        {
            ForEachStatementSyntax forEachSyntax = (ForEachStatementSyntax)node.Syntax;

            BoundExpression collectionExpression = GetUnconvertedCollectionExpression(node);
            TypeSymbol      stringType           = collectionExpression.Type;

            Debug.Assert(stringType.SpecialType == SpecialType.System_String);

            TypeSymbol intType  = compilation.GetSpecialType(SpecialType.System_Int32);
            TypeSymbol boolType = compilation.GetSpecialType(SpecialType.System_Boolean);

            BoundExpression rewrittenExpression = (BoundExpression)Visit(collectionExpression);
            BoundStatement  rewrittenBody       = (BoundStatement)Visit(node.Body);

            // string s;
            LocalSymbol stringVar = new TempLocalSymbol(stringType, RefKind.None, containingMethod);
            // int p;
            LocalSymbol positionVar = new TempLocalSymbol(intType, RefKind.None, containingMethod);

            // Reference to s.
            BoundLocal boundStringVar = MakeBoundLocal(forEachSyntax, stringVar, stringType);

            // Reference to p.
            BoundLocal boundPositionVar = MakeBoundLocal(forEachSyntax, positionVar, intType);

            // string s = /*expr*/;
            BoundStatement stringVarDecl = MakeLocalDeclaration(forEachSyntax, stringVar, rewrittenExpression);

            AddForEachExpressionSequencePoint(forEachSyntax, ref stringVarDecl);

            // int p = 0;
            BoundStatement positionVariableDecl = MakeLocalDeclaration(forEachSyntax, positionVar,
                                                                       new BoundLiteral(forEachSyntax, ConstantValue.ConstantValueZero.Int32, intType));

            // string s = /*node.Expression*/; int p = 0;
            BoundStatement initializer = new BoundStatementList(forEachSyntax,
                                                                statements: ReadOnlyArray <BoundStatement> .CreateFrom(stringVarDecl, positionVariableDecl));

            BoundExpression stringLength = BoundCall.Synthesized(
                syntax: forEachSyntax,
                receiverOpt: boundStringVar,
                method: (MethodSymbol)compilation.GetSpecialTypeMember(SpecialMember.System_String__Length),
                arguments: ReadOnlyArray <BoundExpression> .Empty);

            // p < s.Length
            BoundExpression exitCondition = new BoundBinaryOperator(
                syntax: forEachSyntax,
                operatorKind: BinaryOperatorKind.IntLessThan,
                left: boundPositionVar,
                right: stringLength,
                constantValueOpt: null,
                methodOpt: null,
                resultKind: LookupResultKind.Viable,
                type: boolType);

            // p = p + 1;
            BoundStatement positionIncrement = MakePositionIncrement(forEachSyntax, boundPositionVar, intType);

            LocalSymbol iterationVar     = node.IterationVariable;
            TypeSymbol  iterationVarType = iterationVar.Type;

            Debug.Assert(node.ElementConversion.Exists);

            // (V)s.Chars[p]
            BoundExpression iterationVarInitValue = SynthesizeConversion(
                syntax: forEachSyntax,
                operand: BoundCall.Synthesized(
                    syntax: forEachSyntax,
                    receiverOpt: boundStringVar,
                    method: (MethodSymbol)this.compilation.GetSpecialTypeMember(SpecialMember.System_String__Chars),
                    arguments: ReadOnlyArray <BoundExpression> .CreateFrom(boundPositionVar)),
                conversion: node.ElementConversion,
                type: iterationVarType);

            // V v = (V)s.Chars[p];
            BoundStatement iterationVarDecl = MakeLocalDeclaration(forEachSyntax, iterationVar, iterationVarInitValue);

            AddForEachIterationVariableSequencePoint(forEachSyntax, ref iterationVarDecl);

            // { V v = (V)s.Chars[p]; /*node.Body*/ }
            BoundStatement loopBody = new BoundBlock(forEachSyntax,
                                                     localsOpt: ReadOnlyArray <LocalSymbol> .CreateFrom(iterationVar),
                                                     statements: ReadOnlyArray <BoundStatement> .CreateFrom(iterationVarDecl, rewrittenBody));

            // for (string s = /*node.Expression*/, int p = 0; p < s.Length; p = p + 1) {
            //     V v = (V)s.Chars[p];
            //     /*node.Body*/
            // }
            BoundStatement result = RewriteForStatement(
                syntax: forEachSyntax,
                locals: ReadOnlyArray <LocalSymbol> .CreateFrom(stringVar, positionVar),
                rewrittenInitializer: initializer,
                rewrittenCondition: exitCondition,
                conditionSyntax: forEachSyntax.InKeyword,
                rewrittenIncrement: positionIncrement,
                rewrittenBody: loopBody,
                breakLabel: node.BreakLabel,
                continueLabel: node.ContinueLabel, hasErrors: node.HasErrors);

            AddForEachKeywordSequencePoint(forEachSyntax, ref result);

            return(result);
        }
        public override BoundNode VisitCompoundAssignmentOperator(BoundCompoundAssignmentOperator node)
        {
            if (node.HasErrors)
            {
                return node;
            }

            // There are five possible cases.
            //
            // Case 1: receiver.Prop += value is transformed into
            // temp = receiver
            // temp.Prop = temp.Prop + value
            // and a later rewriting will turn that into calls to getters and setters.
            //
            // Case 2: collection[i1, i2, i3] += value is transformed into
            // tc = collection
            // t1 = i1
            // t2 = i2
            // t3 = i3
            // tc[t1, t2, t3] = tc[t1, t2, t3] + value
            // and again, a later rewriting will turn that into getters and setters of the indexer.
            //
            // Case 3: local += value (and param += value) needs no temporaries; it simply
            // becomes local = local + value.
            //
            // Case 4: staticField += value needs no temporaries either. However, classInst.field += value becomes
            // temp = classInst
            // temp.field = temp.field + value 
            //
            // Case 5: otherwise, it must be structVariable.field += value or array[index] += value. Either way
            // we have a variable on the left. Transform it into:
            // ref temp = ref variable
            // temp = temp + value

            var temps = ArrayBuilder<LocalSymbol>.GetInstance();
            var stores = ArrayBuilder<BoundExpression>.GetInstance();

            // This will be filled in with the LHS that uses temporaries to prevent
            // double-evaluation of side effects.

            BoundExpression transformedLHS = null;

            if (node.Left.Kind == BoundKind.PropertyAccess)
            {
                // We need to stash away the receiver so that it does not get evaluated twice.
                // If the receiver is classified as a value of reference type then we can simply say
                //
                // R temp = receiver
                // temp.prop = temp.prop + rhs
                //
                // But if the receiver is classified as a variable of struct type then we
                // cannot make a copy of the value; we need to make sure that we mutate
                // the original receiver, not the copy.  We have to generate
                //
                // ref R temp = ref receiver
                // temp.prop = temp.prop + rhs
                //
                // The rules of C# (in section 7.17.1) require that if you have receiver.prop 
                // as the target of an assignment such that receiver is a value type, it must
                // be classified as a variable. If we've gotten this far in the rewriting,
                // assume that was the case.

                var prop = (BoundPropertyAccess)node.Left;

                // If the property is static then we can just generate prop = prop + value
                if (prop.ReceiverOpt == null)
                {
                    transformedLHS = prop;
                }
                else
                {
                    // Can we ever avoid storing the receiver in a temp? If the receiver is a variable then it 
                    // might be modified by the computation of the getter, the value, or the operation. 
                    // The receiver cannot be a null constant or constant of value type. It could be a 
                    // constant of string type, but there are no mutable properties of a string.
                    // Similarly, there are no mutable properties of a Type object, so the receiver
                    // cannot be a typeof(T) expression. The only situation I can think of where we could
                    // optimize away the temp is if the receiver is a readonly field of reference type,
                    // we are not in a constructor, and the receiver of the *field*, if any, is also idempotent.
                    // It doesn't seem worthwhile to pursue an optimization for this exceedingly rare case.

                    var rewrittenReceiver = (BoundExpression)Visit(prop.ReceiverOpt);
                    var receiverTemp = TempHelpers.StoreToTemp(rewrittenReceiver, rewrittenReceiver.Type.IsValueType ? RefKind.Ref : RefKind.None, containingSymbol);
                    stores.Add(receiverTemp.Item1);
                    temps.Add(receiverTemp.Item2.LocalSymbol);
                    transformedLHS = new BoundPropertyAccess(prop.Syntax, prop.SyntaxTree, receiverTemp.Item2, prop.PropertySymbol, prop.Type);
                }
            }
            else if (node.Left.Kind == BoundKind.IndexerAccess)
            {
                var indexer = (BoundIndexerAccess)node.Left;
                BoundExpression transformedReceiver = null;
                if (indexer.ReceiverOpt != null)
                {
                    var rewrittenReceiver = (BoundExpression)Visit(indexer.ReceiverOpt);
                    var receiverTemp = TempHelpers.StoreToTemp(rewrittenReceiver, rewrittenReceiver.Type.IsValueType ? RefKind.Ref : RefKind.None, containingSymbol);
                    transformedReceiver = receiverTemp.Item2;
                    stores.Add(receiverTemp.Item1);
                    temps.Add(receiverTemp.Item2.LocalSymbol);
                }

                // UNDONE: Dealing with the arguments is a bit tricky because they can be named out-of-order arguments;
                // UNDONE: we have to preserve both the source-code order of the side effects and the side effects
                // UNDONE: only being executed once.
                // UNDONE:
                // UNDONE: This is a subtly different problem than the problem faced by the conventional call
                // UNDONE: rewriter; with the conventional call rewriter we already know that the side effects
                // UNDONE: will only be executed once because the arguments are only being pushed on the stack once. 
                // UNDONE: In a compound equality operator on an indexer the indices are placed on the stack twice. 
                // UNDONE: That is to say, if you have:
                // UNDONE:
                // UNDONE: C().M(z : Z(), x : X(), y : Y())
                // UNDONE:
                // UNDONE: then we can rewrite that into
                // UNDONE:
                // UNDONE: tempc = C()
                // UNDONE: tempz = Z()
                // UNDONE: tempc.M(X(), Y(), tempz)
                // UNDONE:
                // UNDONE: See, we can optimize away two of the temporaries, for x and y. But we cannot optimize away any of the
                // UNDONE: temporaries in
                // UNDONE:
                // UNDONE: C().Collection[z : Z(), x : X(), y : Y()] += 1;
                // UNDONE:
                // UNDONE: because we have to ensure not just that Z() happens first, but in additioan that X() and Y() are only 
                // UNDONE: called once.  We have to generate this as
                // UNDONE:
                // UNDONE: tempc = C().Collection
                // UNDONE: tempz = Z()
                // UNDONE: tempx = X()
                // UNDONE: tempy = Y()
                // UNDONE: tempc[tempx, tempy, tempz] = tempc[tempx, tempy, tempz] + 1;
                // UNDONE:
                // UNDONE: Fortunately arguments to indexers are never ref or out, so we don't need to worry about that.
                // UNDONE: However, we can still do the optimization where constants are not stored in
                // UNDONE: temporaries; if we have
                // UNDONE: 
                // UNDONE: C().Collection[z : 123, y : Y(), x : X()] += 1;
                // UNDONE:
                // UNDONE: Then we can generate that as
                // UNDONE:
                // UNDONE: tempc = C().Collection
                // UNDONE: tempx = X()
                // UNDONE: tempy = Y()
                // UNDONE: tempc[tempx, tempy, 123] = tempc[tempx, tempy, 123] + 1;
                // UNDONE:
                // UNDONE: For now, we'll punt on both problems, as indexers are not implemented yet anyway.
                // UNDONE: We'll just generate one temporary for each argument. This will work, but in the
                // UNDONE: subsequent rewritings will generate more unnecessary temporaries. 

                var transformedArguments = ArrayBuilder<BoundExpression>.GetInstance();
                foreach (var argument in indexer.Arguments)
                {
                    var rewrittenArgument = (BoundExpression)Visit(argument);
                    var argumentTemp = TempHelpers.StoreToTemp(rewrittenArgument, RefKind.None, containingSymbol);
                    transformedArguments.Add(argumentTemp.Item2);
                    stores.Add(argumentTemp.Item1);
                    temps.Add(argumentTemp.Item2.LocalSymbol);
                }

                transformedLHS = new BoundIndexerAccess(indexer.Syntax, indexer.SyntaxTree, transformedArguments.ToReadOnlyAndFree(), transformedReceiver,
                    indexer.IndexerSymbol, indexer.Type);
            }
            else if (node.Left.Kind == BoundKind.Local || node.Left.Kind == BoundKind.Parameter)
            {
                // No temporaries are needed. Just generate local = local + value
                transformedLHS = node.Left;
            }
            else if (node.Left.Kind == BoundKind.FieldAccess)
            {
                // * If the field is static then no temporaries are needed. 
                // * If the field is not static and the receiver is of reference type then generate t = r; t.f = t.f + value
                // * If the field is not static and the receiver is a variable of value type then we'll fall into the
                //   general variable case below.

                var fieldAccess = (BoundFieldAccess)node.Left;
                if (fieldAccess.ReceiverOpt == null)
                {
                    transformedLHS = fieldAccess;
                }
                else if (!fieldAccess.ReceiverOpt.Type.IsValueType)
                {
                    var rewrittenReceiver = (BoundExpression)Visit(fieldAccess.ReceiverOpt);
                    var receiverTemp = TempHelpers.StoreToTemp(rewrittenReceiver, RefKind.None, containingSymbol);
                    stores.Add(receiverTemp.Item1);
                    temps.Add(receiverTemp.Item2.LocalSymbol);
                    transformedLHS = new BoundFieldAccess(fieldAccess.Syntax, fieldAccess.SyntaxTree, receiverTemp.Item2, fieldAccess.FieldSymbol, null);
                }
            }

            if (transformedLHS == null)
            {
                // We made no transformation above. Either we have array[index] += value or 
                // structVariable.field += value; either way we have a potentially complicated variable-
                // producing expression on the left. Generate
                // ref temp = ref variable; temp = temp + value
                var rewrittenVariable = (BoundExpression)Visit(node.Left);
                var variableTemp = TempHelpers.StoreToTemp(rewrittenVariable, RefKind.Ref, containingSymbol);
                stores.Add(variableTemp.Item1);
                temps.Add(variableTemp.Item2.LocalSymbol);
                transformedLHS = variableTemp.Item2;
            }

            // OK, we now have the temporary declarations, the temporary stores, and the transformed left hand side.
            // We need to generate 
            //
            // xlhs = (FINAL)((LEFT)xlhs op rhs)
            //
            // And then wrap it up with the generated temporaries.
            //
            // (The right hand side has already been converted to the type expected by the operator.)

            BoundExpression opLHS = BoundConversion.SynthesizedConversion(transformedLHS, node.LeftConversion, node.Operator.LeftType);
            Debug.Assert(node.Right.Type == node.Operator.RightType);
            BoundExpression op = new BoundBinaryOperator(null, null, node.Operator.Kind, opLHS, node.Right, null, node.Operator.ReturnType);
            BoundExpression opFinal = BoundConversion.SynthesizedConversion(op, node.FinalConversion, node.Left.Type);
            BoundExpression assignment = new BoundAssignmentOperator(null, null, transformedLHS, opFinal, node.Left.Type);

            // OK, at this point we have:
            //
            // * temps evaluating and storing portions of the LHS that must be evaluated only once.
            // * the "transformed" left hand side, rebuilt to use temps where necessary
            // * the assignment "xlhs = (FINAL)((LEFT)xlhs op (RIGHT)rhs)"
            // 
            // Notice that we have recursively rewritten the bound nodes that are things stored in
            // the temps, but we might have more rewriting to do on the assignment. There are three
            // conversions in there that might be lowered to method calls, an operator that might
            // be lowered to delegate combine, string concat, and so on, and don't forget, we 
            // haven't lowered the right hand side at all! Let's rewrite all these things at once.

            BoundExpression rewrittenAssignment = (BoundExpression)Visit(assignment);

            BoundExpression result = (temps.Count == 0) ?
                rewrittenAssignment :
                new BoundSequence(null,
                    null,
                    temps.ToReadOnly(),
                    stores.ToReadOnly(),
                    rewrittenAssignment,
                    rewrittenAssignment.Type);

            temps.Free();
            stores.Free();
            return result;
        }
예제 #35
0
        private BoundStatement RewriteMultiDimensionalArrayForEachStatement(BoundForEachStatement node)
        {
            ForEachStatementSyntax forEachSyntax = (ForEachStatementSyntax)node.Syntax;

            BoundExpression collectionExpression = GetUnconvertedCollectionExpression(node);

            Debug.Assert(collectionExpression.Type.IsArray());

            ArrayTypeSymbol arrayType = (ArrayTypeSymbol)collectionExpression.Type;

            int rank = arrayType.Rank;

            Debug.Assert(rank > 1);

            TypeSymbol intType  = compilation.GetSpecialType(SpecialType.System_Int32);
            TypeSymbol boolType = compilation.GetSpecialType(SpecialType.System_Boolean);

            BoundExpression rewrittenExpression = (BoundExpression)Visit(collectionExpression);
            BoundStatement  rewrittenBody       = (BoundStatement)Visit(node.Body);

            // A[...] a
            LocalSymbol arrayVar = new TempLocalSymbol(arrayType, RefKind.None, containingMethod);

            // A[...] a = /*node.Expression*/;
            BoundStatement arrayVarDecl = MakeLocalDeclaration(forEachSyntax, arrayVar, rewrittenExpression);

            AddForEachExpressionSequencePoint(forEachSyntax, ref arrayVarDecl);

            // Reference to a.
            BoundLocal boundArrayVar = MakeBoundLocal(forEachSyntax, arrayVar, arrayType);

            // int p_0, p_1, ...
            LocalSymbol[] positionVar      = new LocalSymbol[rank];
            BoundLocal[]  boundPositionVar = new BoundLocal[rank];
            for (int dimension = 0; dimension < rank; dimension++)
            {
                positionVar[dimension]      = new TempLocalSymbol(intType, RefKind.None, containingMethod);
                boundPositionVar[dimension] = MakeBoundLocal(forEachSyntax, positionVar[dimension], intType);
            }

            // V v
            LocalSymbol iterationVar     = node.IterationVariable;
            TypeSymbol  iterationVarType = iterationVar.Type;

            // (V)a[p_0, p_1, ...]
            BoundExpression iterationVarInitValue = SynthesizeConversion(
                syntax: forEachSyntax,
                operand: new BoundArrayAccess(forEachSyntax,
                                              expression: boundArrayVar,
                                              indices: ReadOnlyArray <BoundExpression> .CreateFrom((BoundExpression[])boundPositionVar),
                                              type: arrayType.ElementType),
                conversion: node.ElementConversion,
                type: iterationVarType);

            // V v = (V)a[p_0, p_1, ...];
            BoundStatement iterationVarDecl = MakeLocalDeclaration(forEachSyntax, iterationVar, iterationVarInitValue);

            AddForEachIterationVariableSequencePoint(forEachSyntax, ref iterationVarDecl);

            // { V v = (V)a[p_0, p_1, ...]; /* node.Body */ }
            BoundStatement innermostLoopBody = new BoundBlock(forEachSyntax,
                                                              localsOpt: ReadOnlyArray <LocalSymbol> .CreateFrom(iterationVar),
                                                              statements: ReadOnlyArray <BoundStatement> .CreateFrom(iterationVarDecl, rewrittenBody));

            // Values we'll use every iteration
            MethodSymbol getLowerBoundMethod = (MethodSymbol)this.compilation.GetSpecialTypeMember(SpecialMember.System_Array__GetLowerBound);
            MethodSymbol getUpperBoundMethod = (MethodSymbol)this.compilation.GetSpecialTypeMember(SpecialMember.System_Array__GetUpperBound);

            // work from most-nested to least-nested
            // for (A[...] a = /*node.Expression*/; int p_0 = a.GetLowerBound(0); p_0 <= a.GetUpperBound(0); p_0 = p_0 + 1)
            //     for (int p_1 = a.GetLowerBound(0); p_1 <= a.GetUpperBound(0); p_1 = p_1 + 1)
            //         ...
            //             { V v = (V)a[p_0, p_1, ...]; /* node.Body */ }
            BoundStatement forLoop = null;

            for (int dimension = rank - 1; dimension >= 0; dimension--)
            {
                ReadOnlyArray <BoundExpression> dimensionArgument = ReadOnlyArray <BoundExpression> .CreateFrom(
                    new BoundLiteral(forEachSyntax,
                                     constantValueOpt : ConstantValue.Create(dimension, ConstantValueTypeDiscriminator.Int32),
                                     type : intType));

                // a.GetLowerBound(/*dimension*/)
                BoundExpression currentDimensionLowerBound = BoundCall.Synthesized(forEachSyntax, boundArrayVar, getLowerBoundMethod, dimensionArgument);
                // a.GetUpperBound(/*dimension*/) //CONSIDER: dev10 creates a temp for each dimension's upper bound
                BoundExpression currentDimensionUpperBound = BoundCall.Synthesized(forEachSyntax, boundArrayVar, getUpperBoundMethod, dimensionArgument);

                // int p_/*dimension*/ = a.GetLowerBound(/*dimension*/);
                BoundStatement positionVarDecl = MakeLocalDeclaration(forEachSyntax, positionVar[dimension], currentDimensionLowerBound);

                ReadOnlyArray <LocalSymbol> locals;
                BoundStatement       initializer;
                GeneratedLabelSymbol breakLabel;

                if (dimension == 0)
                {
                    // outermost for-loop
                    locals = ReadOnlyArray <LocalSymbol> .CreateFrom(arrayVar, positionVar[dimension]);

                    initializer = new BoundStatementList(forEachSyntax,
                                                         statements: ReadOnlyArray <BoundStatement> .CreateFrom(arrayVarDecl, positionVarDecl));
                    breakLabel = node.BreakLabel; // i.e. the one that break statements will jump to
                }
                else
                {
                    locals = ReadOnlyArray <LocalSymbol> .CreateFrom(positionVar[dimension]);

                    initializer = positionVarDecl;
                    breakLabel  = new GeneratedLabelSymbol("break"); // Should not affect emitted code since unused
                }

                // p_/*dimension*/ <= a.GetUpperBound(/*dimension*/)  //NB: OrEqual
                BoundExpression exitCondition = new BoundBinaryOperator(
                    syntax: forEachSyntax,
                    operatorKind: BinaryOperatorKind.IntLessThanOrEqual,
                    left: boundPositionVar[dimension],
                    right: currentDimensionUpperBound,
                    constantValueOpt: null,
                    methodOpt: null,
                    resultKind: LookupResultKind.Viable,
                    type: boolType);

                // p_/*dimension*/ = p_/*dimension*/ + 1;
                BoundStatement positionIncrement = MakePositionIncrement(forEachSyntax, boundPositionVar[dimension], intType);

                BoundStatement       body;
                GeneratedLabelSymbol continueLabel;

                if (forLoop == null)
                {
                    // innermost for-loop
                    body          = innermostLoopBody;
                    continueLabel = node.ContinueLabel; //i.e. the one continue statements will actually jump to
                }
                else
                {
                    body          = forLoop;
                    continueLabel = new GeneratedLabelSymbol("continue"); // Should not affect emitted code since unused
                }

                forLoop = RewriteForStatement(
                    node.Syntax,
                    locals,
                    initializer,
                    exitCondition,
                    forEachSyntax.InKeyword,
                    positionIncrement,
                    body,
                    breakLabel,
                    continueLabel,
                    node.HasErrors);
            }

            Debug.Assert(forLoop != null);

            AddForEachExpressionSequencePoint(forEachSyntax, ref forLoop);

            return(forLoop);
        }
예제 #36
0
        private void EmitBinaryCheckedOperatorExpression(BoundBinaryOperator expression, bool used)
        {
            EmitExpression(expression.Left, true);
            EmitExpression(expression.Right, true);

            var unsigned = IsUnsignedBinaryOperator(expression);

            switch (expression.OperatorKind.Operator())
            {
                case BinaryOperatorKind.Multiplication:
                    if (unsigned)
                    {
                        _builder.EmitOpCode(ILOpCode.Mul_ovf_un);
                    }
                    else
                    {
                        _builder.EmitOpCode(ILOpCode.Mul_ovf);
                    }
                    break;

                case BinaryOperatorKind.Addition:
                    if (unsigned)
                    {
                        _builder.EmitOpCode(ILOpCode.Add_ovf_un);
                    }
                    else
                    {
                        _builder.EmitOpCode(ILOpCode.Add_ovf);
                    }
                    break;

                case BinaryOperatorKind.Subtraction:
                    if (unsigned)
                    {
                        _builder.EmitOpCode(ILOpCode.Sub_ovf_un);
                    }
                    else
                    {
                        _builder.EmitOpCode(ILOpCode.Sub_ovf);
                    }
                    break;

                default:
                    throw ExceptionUtilities.UnexpectedValue(expression.OperatorKind.Operator());
            }

            EmitConversionToEnumUnderlyingType(expression, @checked: true);

            EmitPopIfUnused(used);
        }
예제 #37
0
        /// <inheritdoc/>
        protected override BoundStatement RewriteForEllipsisStatement(BoundForEllipsisStatement node)
        {
            // for <var> := <lower> ... <upper>
            //      <body>
            //
            // ---->
            //
            // {
            //     var <var> = <lower>
            //     const upperBound = <upper>
            //     var step = 1
            //     if <var> greaterthan upperBound {
            //          step = -1
            //     }
            //     goto start
            //     body:
            //     <body>
            //     continue:
            //     <var> = <var> + step
            //     start:
            //     gotoTrue ((step > 0 && lower < upper) || (step < 0 && lower > upper)) body
            //     break:
            // }
            var variableDeclaration   = new BoundVariableDeclaration(node.Variable, node.LowerBound);
            var upperBoundSymbol      = new LocalVariableSymbol("upperBound", isReadOnly: true, type: TypeSymbol.Int);
            var upperBoundDeclaration = new BoundVariableDeclaration(upperBoundSymbol, node.UpperBound);
            var stepBoundSymbol       = new LocalVariableSymbol("step", isReadOnly: false, type: TypeSymbol.Int);
            var stepBoundDeclaration  = new BoundVariableDeclaration(
                variable: stepBoundSymbol,
                initializer: new BoundLiteralExpression(1));
            var variableExpression   = new BoundVariableExpression(node.Variable);
            var upperBoundExpression = new BoundVariableExpression(upperBoundSymbol);
            var stepBoundExpression  = new BoundVariableExpression(stepBoundSymbol);
            var ifLowerIsGreaterThanUpperExpression = new BoundBinaryExpression(
                left: variableExpression,
                op: BoundBinaryOperator.Bind(SyntaxKind.GreaterToken, TypeSymbol.Int, TypeSymbol.Int),
                right: upperBoundExpression);
            var stepBoundAssingment = new BoundExpressionStatement(
                expression: new BoundAssignmentExpression(
                    variable: stepBoundSymbol,
                    expression: new BoundLiteralExpression(-1)));
            var ifLowerIsGreaterThanUpperIfStatement = new BoundIfStatement(
                condition: ifLowerIsGreaterThanUpperExpression,
                thenStatement: stepBoundAssingment,
                elseStatement: null);
            var startLabel             = GenerateLabel();
            var gotoStart              = new BoundGotoStatement(startLabel);
            var bodyLabel              = GenerateLabel();
            var bodyLabelStatement     = new BoundLabelStatement(bodyLabel);
            var continueLabelStatement = new BoundLabelStatement(node.ContinueLabel);
            var increment              = new BoundExpressionStatement(
                expression: new BoundAssignmentExpression(
                    variable: node.Variable,
                    expression: new BoundBinaryExpression(
                        left: variableExpression,
                        op: BoundBinaryOperator.Bind(SyntaxKind.PlusToken, TypeSymbol.Int, TypeSymbol.Int),
                        right: stepBoundExpression)));
            var startLabelStatement           = new BoundLabelStatement(startLabel);
            var zeroLiteralExpression         = new BoundLiteralExpression(0);
            var stepGreaterThanZeroExpression = new BoundBinaryExpression(
                left: stepBoundExpression,
                op: BoundBinaryOperator.Bind(SyntaxKind.GreaterToken, TypeSymbol.Int, TypeSymbol.Int),
                right: zeroLiteralExpression);
            var lowerLessThanUpperExpression = new BoundBinaryExpression(
                left: variableExpression,
                op: BoundBinaryOperator.Bind(SyntaxKind.LessToken, TypeSymbol.Int, TypeSymbol.Int),
                right: upperBoundExpression);
            var positiveStepAndLowerLessThanUpper = new BoundBinaryExpression(
                left: stepGreaterThanZeroExpression,
                op: BoundBinaryOperator.Bind(SyntaxKind.AmpersandAmpersandToken, TypeSymbol.Bool, TypeSymbol.Bool),
                right: lowerLessThanUpperExpression);
            var stepLessThanZeroExpression = new BoundBinaryExpression(
                left: stepBoundExpression,
                op: BoundBinaryOperator.Bind(SyntaxKind.LessToken, TypeSymbol.Int, TypeSymbol.Int),
                right: zeroLiteralExpression);
            var lowerGreaterThanUpperExpression = new BoundBinaryExpression(
                left: variableExpression,
                op: BoundBinaryOperator.Bind(SyntaxKind.GreaterToken, TypeSymbol.Int, TypeSymbol.Int),
                right: upperBoundExpression);
            var negativeStepAndLowerGreaterThanUpper = new BoundBinaryExpression(
                left: stepLessThanZeroExpression,
                op: BoundBinaryOperator.Bind(SyntaxKind.AmpersandAmpersandToken, TypeSymbol.Bool, TypeSymbol.Bool),
                right: lowerGreaterThanUpperExpression);
            var condition = new BoundBinaryExpression(
                positiveStepAndLowerLessThanUpper,
                BoundBinaryOperator.Bind(SyntaxKind.PipePipeToken, TypeSymbol.Bool, TypeSymbol.Bool),
                negativeStepAndLowerGreaterThanUpper);
            var gotoTrue            = new BoundConditionalGotoStatement(bodyLabel, condition, jumpIfTrue: true);
            var breakLabelStatement = new BoundLabelStatement(node.BreakLabel);

            var result = new BoundBlockStatement(ImmutableArray.Create <BoundStatement>(
                                                     variableDeclaration,
                                                     upperBoundDeclaration,
                                                     stepBoundDeclaration,
                                                     ifLowerIsGreaterThanUpperIfStatement,
                                                     gotoStart,
                                                     bodyLabelStatement,
                                                     node.Body,
                                                     continueLabelStatement,
                                                     increment,
                                                     startLabelStatement,
                                                     gotoTrue,
                                                     breakLabelStatement));

            return(RewriteStatement(result));
        }
예제 #38
0
        private void EmitBinaryArithOperator(BoundBinaryOperator expression)
        {
            EmitExpression(expression.Left, true);
            EmitExpression(expression.Right, true);

            switch (expression.OperatorKind.Operator())
            {
                case BinaryOperatorKind.Multiplication:
                    _builder.EmitOpCode(ILOpCode.Mul);
                    break;

                case BinaryOperatorKind.Addition:
                    _builder.EmitOpCode(ILOpCode.Add);
                    break;

                case BinaryOperatorKind.Subtraction:
                    _builder.EmitOpCode(ILOpCode.Sub);
                    break;

                case BinaryOperatorKind.Division:
                    if (IsUnsignedBinaryOperator(expression))
                    {
                        _builder.EmitOpCode(ILOpCode.Div_un);
                    }
                    else
                    {
                        _builder.EmitOpCode(ILOpCode.Div);
                    }
                    break;

                case BinaryOperatorKind.Remainder:
                    if (IsUnsignedBinaryOperator(expression))
                    {
                        _builder.EmitOpCode(ILOpCode.Rem_un);
                    }
                    else
                    {
                        _builder.EmitOpCode(ILOpCode.Rem);
                    }
                    break;

                case BinaryOperatorKind.LeftShift:
                    _builder.EmitOpCode(ILOpCode.Shl);
                    break;

                case BinaryOperatorKind.RightShift:
                    if (IsUnsignedBinaryOperator(expression))
                    {
                        _builder.EmitOpCode(ILOpCode.Shr_un);
                    }
                    else
                    {
                        _builder.EmitOpCode(ILOpCode.Shr);
                    }
                    break;

                case BinaryOperatorKind.And:
                    _builder.EmitOpCode(ILOpCode.And);
                    break;

                case BinaryOperatorKind.Xor:
                    _builder.EmitOpCode(ILOpCode.Xor);
                    break;

                case BinaryOperatorKind.Or:
                    _builder.EmitOpCode(ILOpCode.Or);
                    break;

                default:
                    throw ExceptionUtilities.UnexpectedValue(expression.OperatorKind.Operator());
            }

            EmitConversionToEnumUnderlyingType(expression, @checked: false);
        }
예제 #39
0
        private void EmitBinaryArithOperator(BoundBinaryOperator expression)
        {
            EmitExpression(expression.Left, true);
            EmitExpression(expression.Right, true);

            switch (expression.OperatorKind.Operator())
            {
            case BinaryOperatorKind.Multiplication:
                _builder.EmitOpCode(ILOpCode.Mul);
                break;

            case BinaryOperatorKind.Addition:
                _builder.EmitOpCode(ILOpCode.Add);
                break;

            case BinaryOperatorKind.Subtraction:
                _builder.EmitOpCode(ILOpCode.Sub);
                break;

            case BinaryOperatorKind.Division:
                if (IsUnsignedBinaryOperator(expression))
                {
                    _builder.EmitOpCode(ILOpCode.Div_un);
                }
                else
                {
                    _builder.EmitOpCode(ILOpCode.Div);
                }
                break;

            case BinaryOperatorKind.Remainder:
                if (IsUnsignedBinaryOperator(expression))
                {
                    _builder.EmitOpCode(ILOpCode.Rem_un);
                }
                else
                {
                    _builder.EmitOpCode(ILOpCode.Rem);
                }
                break;

            case BinaryOperatorKind.LeftShift:
                _builder.EmitOpCode(ILOpCode.Shl);
                break;

            case BinaryOperatorKind.RightShift:
                if (IsUnsignedBinaryOperator(expression))
                {
                    _builder.EmitOpCode(ILOpCode.Shr_un);
                }
                else
                {
                    _builder.EmitOpCode(ILOpCode.Shr);
                }
                break;

            case BinaryOperatorKind.And:
                _builder.EmitOpCode(ILOpCode.And);
                break;

            case BinaryOperatorKind.Xor:
                _builder.EmitOpCode(ILOpCode.Xor);
                break;

            case BinaryOperatorKind.Or:
                _builder.EmitOpCode(ILOpCode.Or);
                break;

            default:
                throw ExceptionUtilities.UnexpectedValue(expression.OperatorKind.Operator());
            }

            EmitConversionToEnumUnderlyingType(expression, @checked: false);
        }
        /// <summary>
        /// Lower a foreach loop that will enumerate the characters of a string.
        /// 
        /// string s = x;
        /// for (int p = 0; p &lt; s.Length; p = p + 1) {
        ///     V v = (V)s.Chars[p];
        ///     // body
        /// }
        /// </summary>
        /// <remarks>
        /// We will follow Dev10 in diverging from the C# 4 spec by ignoring string's 
        /// implementation of IEnumerable and just indexing into its characters.
        /// 
        /// NOTE: We're assuming that sequence points have already been generated.
        /// Otherwise, lowering to for-loops would generated spurious ones.
        /// </remarks>
        private BoundStatement RewriteStringForEachStatement(BoundForEachStatement node)
        {
            ForEachStatementSyntax forEachSyntax = (ForEachStatementSyntax)node.Syntax;

            BoundExpression collectionExpression = GetUnconvertedCollectionExpression(node);
            TypeSymbol stringType = collectionExpression.Type;
            Debug.Assert(stringType.SpecialType == SpecialType.System_String);

            TypeSymbol intType = compilation.GetSpecialType(SpecialType.System_Int32);
            TypeSymbol boolType = compilation.GetSpecialType(SpecialType.System_Boolean);

            BoundExpression rewrittenExpression = (BoundExpression)Visit(collectionExpression);
            BoundStatement rewrittenBody = (BoundStatement)Visit(node.Body);

            // string s;
            LocalSymbol stringVar = new TempLocalSymbol(stringType, RefKind.None, containingMethod);
            // int p;
            LocalSymbol positionVar = new TempLocalSymbol(intType, RefKind.None, containingMethod);

            // Reference to s.
            BoundLocal boundStringVar = MakeBoundLocal(forEachSyntax, stringVar, stringType);

            // Reference to p.
            BoundLocal boundPositionVar = MakeBoundLocal(forEachSyntax, positionVar, intType);

            // string s = /*expr*/;
            BoundStatement stringVarDecl = MakeLocalDeclaration(forEachSyntax, stringVar, rewrittenExpression);

            AddForEachExpressionSequencePoint(forEachSyntax, ref stringVarDecl);

            // int p = 0;
            BoundStatement positionVariableDecl = MakeLocalDeclaration(forEachSyntax, positionVar, 
                new BoundLiteral(forEachSyntax, ConstantValue.ConstantValueZero.Int32, intType));

            // string s = /*node.Expression*/; int p = 0;
            BoundStatement initializer = new BoundStatementList(forEachSyntax, 
                statements: ReadOnlyArray<BoundStatement>.CreateFrom(stringVarDecl, positionVariableDecl));

            BoundExpression stringLength = BoundCall.Synthesized(
                    syntax: forEachSyntax,
                    receiverOpt: boundStringVar,
                    method: (MethodSymbol)compilation.GetSpecialTypeMember(SpecialMember.System_String__Length),
                    arguments: ReadOnlyArray<BoundExpression>.Empty);

            // p < s.Length
            BoundExpression exitCondition = new BoundBinaryOperator(
                syntax: forEachSyntax, 
                operatorKind: BinaryOperatorKind.IntLessThan,
                left: boundPositionVar,
                right: stringLength,
                constantValueOpt: null, 
                methodOpt: null, 
                resultKind: LookupResultKind.Viable, 
                type: boolType);

            // p = p + 1;
            BoundStatement positionIncrement = MakePositionIncrement(forEachSyntax, boundPositionVar, intType);

            LocalSymbol iterationVar = node.IterationVariable;
            TypeSymbol iterationVarType = iterationVar.Type;
            Debug.Assert(node.ElementConversion.Exists);

            // (V)s.Chars[p]
            BoundExpression iterationVarInitValue = SynthesizeConversion(
                syntax: forEachSyntax,
                operand: BoundCall.Synthesized(
                    syntax: forEachSyntax,
                    receiverOpt: boundStringVar,
                    method: (MethodSymbol)this.compilation.GetSpecialTypeMember(SpecialMember.System_String__Chars),
                    arguments: ReadOnlyArray<BoundExpression>.CreateFrom(boundPositionVar)),
                conversion: node.ElementConversion,
                type: iterationVarType);

            // V v = (V)s.Chars[p];
            BoundStatement iterationVarDecl = MakeLocalDeclaration(forEachSyntax, iterationVar, iterationVarInitValue);

            AddForEachIterationVariableSequencePoint(forEachSyntax, ref iterationVarDecl);

            // { V v = (V)s.Chars[p]; /*node.Body*/ }
            BoundStatement loopBody = new BoundBlock(forEachSyntax,
                localsOpt: ReadOnlyArray<LocalSymbol>.CreateFrom(iterationVar),
                statements: ReadOnlyArray<BoundStatement>.CreateFrom(iterationVarDecl, rewrittenBody));

            // for (string s = /*node.Expression*/, int p = 0; p < s.Length; p = p + 1) {
            //     V v = (V)s.Chars[p];
            //     /*node.Body*/
            // }
            BoundStatement result = RewriteForStatement(
                syntax: forEachSyntax,
                locals: ReadOnlyArray<LocalSymbol>.CreateFrom(stringVar, positionVar),
                rewrittenInitializer: initializer,
                rewrittenCondition: exitCondition,
                conditionSyntax: forEachSyntax.InKeyword,
                rewrittenIncrement: positionIncrement,
                rewrittenBody: loopBody,
                breakLabel: node.BreakLabel,
                continueLabel: node.ContinueLabel, hasErrors: node.HasErrors);

            AddForEachKeywordSequencePoint(forEachSyntax, ref result);

            return result;
        }
예제 #41
0
        private void EmitBinaryOperatorInstruction(BoundBinaryOperator expression)
        {
            switch (expression.OperatorKind.Operator())
            {
            case BinaryOperatorKind.Multiplication:
                _builder.EmitOpCode(ILOpCode.Mul);
                break;

            case BinaryOperatorKind.Addition:
                _builder.EmitOpCode(ILOpCode.Add);
                break;

            case BinaryOperatorKind.Subtraction:
                _builder.EmitOpCode(ILOpCode.Sub);
                break;

            case BinaryOperatorKind.Division:
                if (IsUnsignedBinaryOperator(expression))
                {
                    _builder.EmitOpCode(ILOpCode.Div_un);
                }
                else
                {
                    _builder.EmitOpCode(ILOpCode.Div);
                }
                break;

            case BinaryOperatorKind.Remainder:
                if (IsUnsignedBinaryOperator(expression))
                {
                    _builder.EmitOpCode(ILOpCode.Rem_un);
                }
                else
                {
                    _builder.EmitOpCode(ILOpCode.Rem);
                }
                break;

            case BinaryOperatorKind.LeftShift:
                _builder.EmitOpCode(ILOpCode.Shl);
                break;

            case BinaryOperatorKind.RightShift:
                if (IsUnsignedBinaryOperator(expression))
                {
                    _builder.EmitOpCode(ILOpCode.Shr_un);
                }
                else
                {
                    _builder.EmitOpCode(ILOpCode.Shr);
                }
                break;

            case BinaryOperatorKind.And:
                _builder.EmitOpCode(ILOpCode.And);
                break;

            case BinaryOperatorKind.Xor:
                _builder.EmitOpCode(ILOpCode.Xor);
                break;

            case BinaryOperatorKind.Or:
                _builder.EmitOpCode(ILOpCode.Or);
                break;

            default:
                throw ExceptionUtilities.UnexpectedValue(expression.OperatorKind.Operator());
            }
        }
        /// <summary>
        /// Lower a foreach loop that will enumerate a single-dimensional array.
        /// 
        /// A[] a = x;
        /// for (int p = 0; p &lt; a.Length; p = p + 1) {
        ///     V v = (V)a[p];
        ///     // body
        /// }
        /// </summary>
        /// <remarks>
        /// We will follow Dev10 in diverging from the C# 4 spec by ignoring Array's 
        /// implementation of IEnumerable and just indexing into its elements.
        /// 
        /// NOTE: We're assuming that sequence points have already been generated.
        /// Otherwise, lowering to for-loops would generated spurious ones.
        /// </remarks>
        private BoundStatement RewriteSingleDimensionalArrayForEachStatement(BoundForEachStatement node)
        {
            ForEachStatementSyntax forEachSyntax = (ForEachStatementSyntax)node.Syntax;

            BoundExpression collectionExpression = GetUnconvertedCollectionExpression(node);
            Debug.Assert(collectionExpression.Type.IsArray());

            ArrayTypeSymbol arrayType = (ArrayTypeSymbol)collectionExpression.Type;

            Debug.Assert(arrayType.Rank == 1);

            TypeSymbol intType = compilation.GetSpecialType(SpecialType.System_Int32);
            TypeSymbol boolType = compilation.GetSpecialType(SpecialType.System_Boolean);

            BoundExpression rewrittenExpression = (BoundExpression)Visit(collectionExpression);
            BoundStatement rewrittenBody = (BoundStatement)Visit(node.Body);

            // A[] a
            LocalSymbol arrayVar = new TempLocalSymbol(arrayType, RefKind.None, containingMethod);

            // A[] a = /*node.Expression*/;
            BoundStatement arrayVarDecl = MakeLocalDeclaration(forEachSyntax, arrayVar, rewrittenExpression);

            AddForEachExpressionSequencePoint(forEachSyntax, ref arrayVarDecl);

            // Reference to a.
            BoundLocal boundArrayVar = MakeBoundLocal(forEachSyntax, arrayVar, arrayType);

            // int p
            LocalSymbol positionVar = new TempLocalSymbol(intType, RefKind.None, containingMethod);

            // Reference to p.
            BoundLocal boundPositionVar = MakeBoundLocal(forEachSyntax, positionVar, intType);

            // int p = 0;
            BoundStatement positionVarDecl = MakeLocalDeclaration(forEachSyntax, positionVar, 
                new BoundLiteral(forEachSyntax, ConstantValue.ConstantValueZero.Int32, intType));

            // V v
            LocalSymbol iterationVar = node.IterationVariable;
            TypeSymbol iterationVarType = iterationVar.Type;

            // (V)a[p]
            BoundExpression iterationVarInitValue = SynthesizeConversion(
                syntax: forEachSyntax,
                operand: new BoundArrayAccess(
                    syntax: forEachSyntax,
                    expression: boundArrayVar,
                    indices: ReadOnlyArray<BoundExpression>.CreateFrom(boundPositionVar),
                    type: arrayType.ElementType),
                conversion: node.ElementConversion,
                type: iterationVarType);

            // V v = (V)a[p];
            BoundStatement iterationVariableDecl = MakeLocalDeclaration(forEachSyntax, iterationVar, iterationVarInitValue);

            AddForEachIterationVariableSequencePoint(forEachSyntax, ref iterationVariableDecl);

            BoundStatement initializer = new BoundStatementList(forEachSyntax, 
                        statements: ReadOnlyArray<BoundStatement>.CreateFrom(arrayVarDecl, positionVarDecl));

            // a.Length
            BoundExpression arrayLength = new BoundArrayLength(
                syntax: forEachSyntax,
                expression: boundArrayVar,
                type: intType);

            // p < a.Length
            BoundExpression exitCondition = new BoundBinaryOperator(
                syntax: forEachSyntax, 
                operatorKind: BinaryOperatorKind.IntLessThan,
                left: boundPositionVar,
                right: arrayLength,
                constantValueOpt: null, 
                methodOpt: null, 
                resultKind: LookupResultKind.Viable, 
                type: boolType);

            // p = p + 1;
            BoundStatement positionIncrement = MakePositionIncrement(forEachSyntax, boundPositionVar, intType);

            // { V v = (V)a[p]; /* node.Body */ }
            BoundStatement loopBody = new BoundBlock(forEachSyntax, 
                localsOpt: ReadOnlyArray<LocalSymbol>.CreateFrom(iterationVar),
                statements: ReadOnlyArray<BoundStatement>.CreateFrom(iterationVariableDecl, rewrittenBody));

            // for (A[] a = /*node.Expression*/, int p = 0; p < a.Length; p = p + 1) {
            //     V v = (V)a[p];
            //     /*node.Body*/
            // }
            BoundStatement result = RewriteForStatement(
                syntax: node.Syntax,
                locals: ReadOnlyArray<LocalSymbol>.CreateFrom(arrayVar, positionVar),
                rewrittenInitializer: initializer,
                rewrittenCondition: exitCondition,
                conditionSyntax: forEachSyntax.InKeyword,
                rewrittenIncrement: positionIncrement,
                rewrittenBody: loopBody,
                breakLabel: node.BreakLabel,
                continueLabel: node.ContinueLabel, hasErrors: node.HasErrors);

            AddForEachKeywordSequencePoint(forEachSyntax, ref result);

            return result;
        }
예제 #43
0
        private void EmitConversionToEnumUnderlyingType(BoundBinaryOperator expression, bool @checked)
        {
            // If we are doing an enum addition or subtraction and the
            // underlying type is 8 or 16 bits then we will have done the operation in 32
            // bits and we need to convert back down to the smaller bit size
            // to [one|zero]extend the value
            // NOTE: we do not need to do this for bitwise operations since they will always
            //       result in a properly sign-extended result, assuming operands were sign extended
            //
            // If e is a value of enum type E and u is a value of underlying type u then:
            //
            // e + u --> (E)((U)e + u)
            // u + e --> (E)(u + (U)e)
            // e - e --> (U)((U)e - (U)e)
            // e - u --> (E)((U)e - u)
            // e & e --> (E)((U)e & (U)e)
            // e | e --> (E)((U)e | (U)e)
            // e ^ e --> (E)((U)e ^ (U)e)
            //
            // NOTE: (E) is actually emitted as (U) and in last 3 cases is not necessary.
            //
            // Due to a bug, the native compiler allows:
            //
            // u - e --> (E)(u - (U)e)
            //
            // And so Roslyn does as well.

            TypeSymbol enumType;

            switch (expression.OperatorKind.Operator() | expression.OperatorKind.OperandTypes())
            {
            case BinaryOperatorKind.EnumAndUnderlyingAddition:
            case BinaryOperatorKind.EnumSubtraction:
            case BinaryOperatorKind.EnumAndUnderlyingSubtraction:
                enumType = expression.Left.Type;
                break;

            case BinaryOperatorKind.EnumAnd:
            case BinaryOperatorKind.EnumOr:
            case BinaryOperatorKind.EnumXor:
                Debug.Assert(expression.Left.Type == expression.Right.Type);
                enumType = null;
                break;

            case BinaryOperatorKind.UnderlyingAndEnumSubtraction:
            case BinaryOperatorKind.UnderlyingAndEnumAddition:
                enumType = expression.Right.Type;
                break;

            default:
                enumType = null;
                break;
            }

            if ((object)enumType == null)
            {
                return;
            }

            Debug.Assert(enumType.IsEnumType());

            SpecialType type = enumType.GetEnumUnderlyingType().SpecialType;

            switch (type)
            {
            case SpecialType.System_Byte:
                _builder.EmitNumericConversion(Microsoft.Cci.PrimitiveTypeCode.Int32, Microsoft.Cci.PrimitiveTypeCode.UInt8, @checked);
                break;

            case SpecialType.System_SByte:
                _builder.EmitNumericConversion(Microsoft.Cci.PrimitiveTypeCode.Int32, Microsoft.Cci.PrimitiveTypeCode.Int8, @checked);
                break;

            case SpecialType.System_Int16:
                _builder.EmitNumericConversion(Microsoft.Cci.PrimitiveTypeCode.Int32, Microsoft.Cci.PrimitiveTypeCode.Int16, @checked);
                break;

            case SpecialType.System_UInt16:
                _builder.EmitNumericConversion(Microsoft.Cci.PrimitiveTypeCode.Int32, Microsoft.Cci.PrimitiveTypeCode.UInt16, @checked);
                break;
            }
        }
        private BoundStatement RewriteMultiDimensionalArrayForEachStatement(BoundForEachStatement node)
        {
            ForEachStatementSyntax forEachSyntax = (ForEachStatementSyntax)node.Syntax;

            BoundExpression collectionExpression = GetUnconvertedCollectionExpression(node);
            Debug.Assert(collectionExpression.Type.IsArray());

            ArrayTypeSymbol arrayType = (ArrayTypeSymbol)collectionExpression.Type;

            int rank = arrayType.Rank;
            Debug.Assert(rank > 1);

            TypeSymbol intType = compilation.GetSpecialType(SpecialType.System_Int32);
            TypeSymbol boolType = compilation.GetSpecialType(SpecialType.System_Boolean);

            BoundExpression rewrittenExpression = (BoundExpression)Visit(collectionExpression);
            BoundStatement rewrittenBody = (BoundStatement)Visit(node.Body);

            // A[...] a
            LocalSymbol arrayVar = new TempLocalSymbol(arrayType, RefKind.None, containingMethod);

            // A[...] a = /*node.Expression*/;
            BoundStatement arrayVarDecl = MakeLocalDeclaration(forEachSyntax, arrayVar, rewrittenExpression);

            AddForEachExpressionSequencePoint(forEachSyntax, ref arrayVarDecl);

            // Reference to a.
            BoundLocal boundArrayVar = MakeBoundLocal(forEachSyntax, arrayVar, arrayType);

            // int p_0, p_1, ...
            LocalSymbol[] positionVar = new LocalSymbol[rank];
            BoundLocal[] boundPositionVar = new BoundLocal[rank];
            for (int dimension = 0; dimension < rank; dimension++)
            {
                positionVar[dimension] = new TempLocalSymbol(intType, RefKind.None, containingMethod);
                boundPositionVar[dimension] = MakeBoundLocal(forEachSyntax, positionVar[dimension], intType);
            }

            // V v
            LocalSymbol iterationVar = node.IterationVariable;
            TypeSymbol iterationVarType = iterationVar.Type;

            // (V)a[p_0, p_1, ...]
            BoundExpression iterationVarInitValue = SynthesizeConversion(
                syntax: forEachSyntax,
                operand: new BoundArrayAccess(forEachSyntax, 
                    expression: boundArrayVar,
                    indices: ReadOnlyArray<BoundExpression>.CreateFrom((BoundExpression[])boundPositionVar),
                    type: arrayType.ElementType),
                conversion: node.ElementConversion,
                type: iterationVarType);

            // V v = (V)a[p_0, p_1, ...];
            BoundStatement iterationVarDecl = MakeLocalDeclaration(forEachSyntax, iterationVar, iterationVarInitValue);

            AddForEachIterationVariableSequencePoint(forEachSyntax, ref iterationVarDecl);

            // { V v = (V)a[p_0, p_1, ...]; /* node.Body */ }
            BoundStatement innermostLoopBody = new BoundBlock(forEachSyntax, 
                localsOpt: ReadOnlyArray<LocalSymbol>.CreateFrom(iterationVar),
                statements: ReadOnlyArray<BoundStatement>.CreateFrom(iterationVarDecl, rewrittenBody));

            // Values we'll use every iteration
            MethodSymbol getLowerBoundMethod = (MethodSymbol)this.compilation.GetSpecialTypeMember(SpecialMember.System_Array__GetLowerBound);
            MethodSymbol getUpperBoundMethod = (MethodSymbol)this.compilation.GetSpecialTypeMember(SpecialMember.System_Array__GetUpperBound);

            // work from most-nested to least-nested
            // for (A[...] a = /*node.Expression*/; int p_0 = a.GetLowerBound(0); p_0 <= a.GetUpperBound(0); p_0 = p_0 + 1)
            //     for (int p_1 = a.GetLowerBound(0); p_1 <= a.GetUpperBound(0); p_1 = p_1 + 1)
            //         ...
            //             { V v = (V)a[p_0, p_1, ...]; /* node.Body */ }
            BoundStatement forLoop = null;
            for (int dimension = rank - 1; dimension >= 0; dimension--)
            {
                ReadOnlyArray<BoundExpression> dimensionArgument = ReadOnlyArray<BoundExpression>.CreateFrom(
                    new BoundLiteral(forEachSyntax, 
                        constantValueOpt: ConstantValue.Create(dimension, ConstantValueTypeDiscriminator.Int32),
                        type: intType));

                // a.GetLowerBound(/*dimension*/)
                BoundExpression currentDimensionLowerBound = BoundCall.Synthesized(forEachSyntax, boundArrayVar, getLowerBoundMethod, dimensionArgument);
                // a.GetUpperBound(/*dimension*/) //CONSIDER: dev10 creates a temp for each dimension's upper bound
                BoundExpression currentDimensionUpperBound = BoundCall.Synthesized(forEachSyntax, boundArrayVar, getUpperBoundMethod, dimensionArgument);

                // int p_/*dimension*/ = a.GetLowerBound(/*dimension*/);
                BoundStatement positionVarDecl = MakeLocalDeclaration(forEachSyntax, positionVar[dimension], currentDimensionLowerBound);

                ReadOnlyArray<LocalSymbol> locals;
                BoundStatement initializer;
                GeneratedLabelSymbol breakLabel;

                if (dimension == 0)
                {
                    // outermost for-loop
                    locals = ReadOnlyArray<LocalSymbol>.CreateFrom(arrayVar, positionVar[dimension]);
                    initializer = new BoundStatementList(forEachSyntax, 
                        statements: ReadOnlyArray<BoundStatement>.CreateFrom(arrayVarDecl, positionVarDecl));
                    breakLabel = node.BreakLabel; // i.e. the one that break statements will jump to
                }
                else
                {
                    locals = ReadOnlyArray<LocalSymbol>.CreateFrom(positionVar[dimension]);
                    initializer = positionVarDecl;
                    breakLabel = new GeneratedLabelSymbol("break"); // Should not affect emitted code since unused
                }

                // p_/*dimension*/ <= a.GetUpperBound(/*dimension*/)  //NB: OrEqual
                BoundExpression exitCondition = new BoundBinaryOperator(
                    syntax: forEachSyntax, 
                    operatorKind: BinaryOperatorKind.IntLessThanOrEqual,
                    left: boundPositionVar[dimension],
                    right: currentDimensionUpperBound,
                    constantValueOpt: null, 
                    methodOpt: null, 
                    resultKind: LookupResultKind.Viable, 
                    type: boolType);

                // p_/*dimension*/ = p_/*dimension*/ + 1;
                BoundStatement positionIncrement = MakePositionIncrement(forEachSyntax, boundPositionVar[dimension], intType);

                BoundStatement body;
                GeneratedLabelSymbol continueLabel;

                if(forLoop == null)
                {
                    // innermost for-loop
                    body = innermostLoopBody;
                    continueLabel = node.ContinueLabel; //i.e. the one continue statements will actually jump to
                }
                else
                {
                    body = forLoop;
                    continueLabel = new GeneratedLabelSymbol("continue"); // Should not affect emitted code since unused
                }

                forLoop = RewriteForStatement(
                    node.Syntax,
                    locals,
                    initializer,
                    exitCondition,
                    forEachSyntax.InKeyword,
                    positionIncrement,
                    body,
                    breakLabel,
                    continueLabel,
                    node.HasErrors);
            }

            Debug.Assert(forLoop != null);

            AddForEachExpressionSequencePoint(forEachSyntax, ref forLoop);

            return forLoop;
        }
예제 #45
0
        private void EmitBinaryOperator(BoundBinaryOperator expression)
        {
            BoundExpression child = expression.Left;

            if (child.Kind != BoundKind.BinaryOperator || child.ConstantValue != null)
            {
                EmitBinaryOperatorSimple(expression);
                return;
            }

            BoundBinaryOperator binary = (BoundBinaryOperator)child;
            var operatorKind           = binary.OperatorKind;

            if (!operatorKind.EmitsAsCheckedInstruction() && IsConditional(operatorKind))
            {
                EmitBinaryOperatorSimple(expression);
                return;
            }

            // Do not blow the stack due to a deep recursion on the left.
            var stack = ArrayBuilder <BoundBinaryOperator> .GetInstance();

            stack.Push(expression);

            while (true)
            {
                stack.Push(binary);
                child = binary.Left;

                if (child.Kind != BoundKind.BinaryOperator || child.ConstantValue != null)
                {
                    break;
                }

                binary       = (BoundBinaryOperator)child;
                operatorKind = binary.OperatorKind;

                if (!operatorKind.EmitsAsCheckedInstruction() && IsConditional(operatorKind))
                {
                    break;
                }
            }

            EmitExpression(child, true);

            do
            {
                binary = stack.Pop();

                EmitExpression(binary.Right, true);
                bool isChecked = binary.OperatorKind.EmitsAsCheckedInstruction();
                if (isChecked)
                {
                    EmitBinaryCheckedOperatorInstruction(binary);
                }
                else
                {
                    EmitBinaryOperatorInstruction(binary);
                }

                EmitConversionToEnumUnderlyingType(binary, @checked: isChecked);
            }while (stack.Count > 0);

            Debug.Assert((object)binary == expression);
            stack.Free();
        }
예제 #46
0
        private void EmitBinaryOperatorSimple(BoundBinaryOperator expression)
        {
            EmitExpression(expression.Left, true);
            EmitExpression(expression.Right, true);

            bool isChecked = expression.OperatorKind.EmitsAsCheckedInstruction();
            if (isChecked)
            {
                EmitBinaryCheckedOperatorInstruction(expression);
            }
            else
            {
                EmitBinaryOperatorInstruction(expression);
            }

            EmitConversionToEnumUnderlyingType(expression, @checked: isChecked);
        }
예제 #47
0
        public override BoundNode VisitBinaryOperator(BoundBinaryOperator node)
        {
            BoundExpression child = node.Left;

            if (child.Kind != BoundKind.BinaryOperator || child.ConstantValue != null)
            {
                return VisitBinaryOperatorSimple(node);
            }

            // Do not blow the stack due to a deep recursion on the left.
            var stack = ArrayBuilder<BoundBinaryOperator>.GetInstance();
            stack.Push(node);

            BoundBinaryOperator binary = (BoundBinaryOperator)child;

            while (true)
            {
                stack.Push(binary);
                child = binary.Left;

                if (child.Kind != BoundKind.BinaryOperator || child.ConstantValue != null)
                {
                    break;
                }

                binary = (BoundBinaryOperator)child;
            }

            var prevContext = _context;
            int prevStack = StackDepth();

            var left = (BoundExpression)this.Visit(child);

            while (true)
            {
                binary = stack.Pop();

                var isLogical = (binary.OperatorKind & BinaryOperatorKind.Logical) != 0;

                object cookie = null;
                if (isLogical)
                {
                    cookie = GetStackStateCookie();     // implicit branch here
                    SetStackDepth(prevStack);  // right is evaluated with original stack
                }

                var right = (BoundExpression)this.Visit(binary.Right);

                if (isLogical)
                {
                    EnsureStackState(cookie);   // implicit label here
                }

                var type = this.VisitType(binary.Type);
                left = binary.Update(binary.OperatorKind, left, right, binary.ConstantValueOpt, binary.MethodOpt, binary.ResultKind, type);

                if (stack.Count == 0)
                {
                    break;
                }

                _context = prevContext;
                _counter += 1;
                SetStackDepth(prevStack);
                PushEvalStack(binary, ExprContext.Value);
            }

            Debug.Assert((object)binary == node);
            stack.Free();

            return left;
        }
예제 #48
0
        private void EmitBinaryOperatorInstruction(BoundBinaryOperator expression)
        {
            switch (expression.OperatorKind.Operator())
            {
                case BinaryOperatorKind.Multiplication:
                    _builder.EmitOpCode(ILOpCode.Mul);
                    break;

                case BinaryOperatorKind.Addition:
                    _builder.EmitOpCode(ILOpCode.Add);
                    break;

                case BinaryOperatorKind.Subtraction:
                    _builder.EmitOpCode(ILOpCode.Sub);
                    break;

                case BinaryOperatorKind.Division:
                    if (IsUnsignedBinaryOperator(expression))
                    {
                        _builder.EmitOpCode(ILOpCode.Div_un);
                    }
                    else
                    {
                        _builder.EmitOpCode(ILOpCode.Div);
                    }
                    break;

                case BinaryOperatorKind.Remainder:
                    if (IsUnsignedBinaryOperator(expression))
                    {
                        _builder.EmitOpCode(ILOpCode.Rem_un);
                    }
                    else
                    {
                        _builder.EmitOpCode(ILOpCode.Rem);
                    }
                    break;

                case BinaryOperatorKind.LeftShift:
                    _builder.EmitOpCode(ILOpCode.Shl);
                    break;

                case BinaryOperatorKind.RightShift:
                    if (IsUnsignedBinaryOperator(expression))
                    {
                        _builder.EmitOpCode(ILOpCode.Shr_un);
                    }
                    else
                    {
                        _builder.EmitOpCode(ILOpCode.Shr);
                    }
                    break;

                case BinaryOperatorKind.And:
                    _builder.EmitOpCode(ILOpCode.And);
                    break;

                case BinaryOperatorKind.Xor:
                    _builder.EmitOpCode(ILOpCode.Xor);
                    break;

                case BinaryOperatorKind.Or:
                    _builder.EmitOpCode(ILOpCode.Or);
                    break;

                default:
                    throw ExceptionUtilities.UnexpectedValue(expression.OperatorKind.Operator());
            }
        }
예제 #49
0
        private static BoundExpression TryReduce(BoundBinaryOperator condition, ref bool sense)
        {
            var opKind = condition.OperatorKind.Operator();

            Debug.Assert(opKind == BinaryOperatorKind.Equal ||
                        opKind == BinaryOperatorKind.NotEqual);

            BoundExpression nonConstOp;
            BoundExpression constOp = (condition.Left.ConstantValue != null) ? condition.Left : null;

            if (constOp != null)
            {
                nonConstOp = condition.Right;
            }
            else
            {
                constOp = (condition.Right.ConstantValue != null) ? condition.Right : null;
                if (constOp == null)
                {
                    return null;
                }
                nonConstOp = condition.Left;
            }

            var nonConstType = nonConstOp.Type;
            if (!CanPassToBrfalse(nonConstType))
            {
                return null;
            }

            bool isBool = nonConstType.PrimitiveTypeCode == Microsoft.Cci.PrimitiveTypeCode.Boolean;
            bool isZero = constOp.ConstantValue.IsDefaultValue;

            // bool is special, only it can be compared to true and false...
            if (!isBool && !isZero)
            {
                return null;
            }

            // if comparing to zero, flip the sense
            if (isZero)
            {
                sense = !sense;
            }

            // if comparing != flip the sense
            if (opKind == BinaryOperatorKind.NotEqual)
            {
                sense = !sense;
            }

            return nonConstOp;
        }
예제 #50
0
        private void EmitShortCircuitingOperator(BoundBinaryOperator condition, bool sense, bool stopSense, bool stopValue)
        {
            // we generate:
            //
            // gotoif (a == stopSense) fallThrough
            // b == sense
            // goto labEnd
            // fallThrough:
            // stopValue
            // labEnd:
            //                 AND       OR
            //            +-  ------    -----
            // stopSense  |   !sense    sense
            // stopValue  |     0         1

            object lazyFallThrough = null;

            EmitCondBranch(condition.Left, ref lazyFallThrough, stopSense);
            EmitCondExpr(condition.Right, sense);

            // if fall-through was not initialized, no-one is going to take that branch
            // and we are done with Right on stack
            if (lazyFallThrough == null)
            {
                return;
            }

            var labEnd = new object();
            _builder.EmitBranch(ILOpCode.Br, labEnd);

            // if we get to fallThrough, we should not have Right on stack. Adjust for that.
            _builder.AdjustStack(-1);

            _builder.MarkLabel(lazyFallThrough);
            _builder.EmitBoolConstant(stopValue);
            _builder.MarkLabel(labEnd);
        }
예제 #51
0
        public override BoundNode VisitBinaryOperator(BoundBinaryOperator node)
        {
            var isLogical = (node.OperatorKind & BinaryOperatorKind.Logical) != 0;
            if (isLogical)
            {
                var origStack = StackDepth();
                BoundExpression left = (BoundExpression)this.Visit(node.Left);

                var cookie = GetStackStateCookie();     // implicit branch here

                SetStackDepth(origStack);  // right is evaluated with original stack
                BoundExpression right = (BoundExpression)this.Visit(node.Right);

                EnsureStackState(cookie);   // implicit label here

                return node.Update(node.OperatorKind, left, right, node.ConstantValueOpt, node.MethodOpt, node.ResultKind, node.Type);
            }

            return base.VisitBinaryOperator(node);
        }
예제 #52
0
        /// <summary>
        /// The rewrites are as follows:
        ///
        /// x++
        ///     temp = x
        ///     x = temp + 1
        ///     return temp
        /// x--
        ///     temp = x
        ///     x = temp - 1
        ///     return temp
        /// ++x
        ///     temp = x + 1
        ///     x = temp
        ///     return temp
        /// --x
        ///     temp = x - 1
        ///     x = temp
        ///     return temp
        ///
        /// In each case, the literal 1 is of the type required by the builtin addition/subtraction operator that
        /// will be used.  The temp is of the same type as x, but the sum/difference may be wider, in which case a
        /// conversion is required.
        /// </summary>
        /// <param name="node">The unary operator expression representing the increment/decrement.</param>
        /// <param name="isPrefix">True for prefix, false for postfix.</param>
        /// <param name="isIncrement">True for increment, false for decrement.</param>
        /// <returns>A bound sequence that uses a temp to acheive the correct side effects and return value.</returns>
        private BoundNode LowerOperator(BoundUnaryOperator node, bool isPrefix, bool isIncrement)
        {
            BoundExpression operand     = node.Operand;
            TypeSymbol      operandType = operand.Type; //type of the variable being incremented

            Debug.Assert(operandType == node.Type);

            ConstantValue      constantOne;
            BinaryOperatorKind binaryOperatorKind;

            MakeConstantAndOperatorKind(node.OperatorKind.OperandTypes(), node, out constantOne, out binaryOperatorKind);
            binaryOperatorKind |= isIncrement ? BinaryOperatorKind.Addition : BinaryOperatorKind.Subtraction;

            Debug.Assert(constantOne != null);
            Debug.Assert(constantOne.SpecialType != SpecialType.None);
            Debug.Assert(binaryOperatorKind.OperandTypes() != 0);

            TypeSymbol      constantType = compilation.GetSpecialType(constantOne.SpecialType);
            BoundExpression boundOne     = new BoundLiteral(
                syntax: null,
                syntaxTree: null,
                constantValueOpt: constantOne,
                type: constantType);

            LocalSymbol     tempSymbol = new TempLocalSymbol(operandType, RefKind.None, containingSymbol);
            BoundExpression boundTemp  = new BoundLocal(
                syntax: null,
                syntaxTree: null,
                localSymbol: tempSymbol,
                constantValueOpt: null,
                type: operandType);

            // NOTE: the LHS may have a narrower type than the operator expects, but that
            // doesn't seem to cause any problems.  If a problem does arise, just add an
            // explicit BoundConversion.
            BoundExpression newValue = new BoundBinaryOperator(
                syntax: null,
                syntaxTree: null,
                operatorKind: binaryOperatorKind,
                left: isPrefix ? operand : boundTemp,
                right: boundOne,
                constantValueOpt: null,
                type: constantType);

            if (constantType != operandType)
            {
                newValue = new BoundConversion(
                    syntax: null,
                    syntaxTree: null,
                    operand: newValue,
                    conversionKind: operandType.IsEnumType() ? ConversionKind.ImplicitEnumeration : ConversionKind.ImplicitNumeric,
                    symbolOpt: null,
                    @checked: false,
                    explicitCastInCode: false,
                    constantValueOpt: null,
                    type: operandType);
            }

            ReadOnlyArray <BoundExpression> assignments = ReadOnlyArray <BoundExpression> .CreateFrom(
                new BoundAssignmentOperator(
                    syntax : null,
                    syntaxTree : null,
                    left : boundTemp,
                    right : isPrefix ? newValue : operand,
                    type : operandType),
                new BoundAssignmentOperator(
                    syntax : null,
                    syntaxTree : null,
                    left : operand,
                    right : isPrefix ? boundTemp : newValue,
                    type : operandType));

            return(new BoundSequence(
                       syntax: node.Syntax,
                       syntaxTree: node.SyntaxTree,
                       locals: ReadOnlyArray <LocalSymbol> .CreateFrom(tempSymbol),
                       sideEffects: assignments,
                       value: boundTemp,
                       type: operandType));
        }