Esempio n. 1
0
            /// <inheritdoc/>
            public override BlockFlow Emit(FlowGraphBuilder graph, ValueTag value)
            {
                var headerBlock = graph.AddBasicBlock("searchtree.header");
                var leftBlock   = graph.AddBasicBlock("searchtree.left");
                var rightBlock  = graph.AddBasicBlock("searchtree.right");

                var valueType = graph.GetValueType(value);

                headerBlock.Flow = SwitchFlow.CreateIfElse(
                    Instruction.CreateRelationalIntrinsic(
                        ArithmeticIntrinsics.Operators.IsGreaterThan,
                        typeEnvironment.Boolean,
                        valueType,
                        value,
                        headerBlock.AppendInstruction(
                            Instruction.CreateConstant(pivot, valueType))),
                    new Branch(rightBlock),
                    new Branch(leftBlock));

                leftBlock.Flow  = leftTree.Emit(graph, value);
                rightBlock.Flow = rightTree.Emit(graph, value);

                return(new JumpFlow(headerBlock));
            }
Esempio n. 2
0
        /// <summary>
        /// Emits instructions that read a character from the input stream.
        /// </summary>
        /// <param name="block">A basic block builder.</param>
        /// <param name="resultType">A control-flow graph builder.</param>
        /// <returns>The character that is read from the input stream.</returns>
        public ValueTag EmitRead(ref BasicBlockBuilder block, IType resultType)
        {
            if (ReadMethod == null)
            {
                // If we didn't find a 'read' method, then we'll just return zero.
                return(block.AppendInstruction(
                           Instruction.CreateConstant(
                               new IntegerConstant(0, resultType.GetIntegerSpecOrNull()),
                               resultType)));
            }

            var returnValue = block.AppendInstruction(
                Instruction.CreateCall(
                    ReadMethod,
                    MethodLookup.Static,
                    EmptyArray <ValueTag> .Value));

            var returnType = returnValue.Instruction.ResultType;

            if (returnType == resultType)
            {
                return(returnValue);
            }
            else if (returnType.IsSignedIntegerType() && !resultType.IsSignedIntegerType())
            {
                // When converting a signed return type to an unsigned result type,
                // we want to map negative values to zero because both represent an
                // end-of-stream marker but a direct conversion won't preserve those
                // semantics.

                // Create a zero constant with the same type as the return type.
                var returnZero = block.AppendInstruction(
                    Instruction.CreateConstant(
                        new IntegerConstant(0, returnType.GetIntegerSpecOrNull()),
                        returnType));

                // Compare the return value to zero.
                var lt = Instruction.CreateRelationalIntrinsic(
                    ArithmeticIntrinsics.Operators.IsLessThan,
                    returnType,
                    returnType,
                    returnValue,
                    returnZero);

                // Create a new basic block so we can set `block`'s flow to a switch.
                var successorBlock = block.Graph.AddBasicBlock();
                var resultParam    = new BlockParameter(resultType);
                successorBlock.AppendParameter(resultParam);

                // Create an additional basic block that converts the return value to
                // the result type if the return value is positive.
                var convBlock = block.Graph.AddBasicBlock();

                // Convert the return value to the result type.
                var convReturnValue = block.AppendInstruction(
                    Instruction.CreateConvertIntrinsic(resultType, returnType, returnValue));

                // Set the conversion block's outgoing flow to jump to the successor block.
                convBlock.Flow = new JumpFlow(successorBlock, new ValueTag[] { convReturnValue });

                // Create a zero constant with the same type as the result type.
                var resultZero = block.AppendInstruction(
                    Instruction.CreateConstant(
                        new IntegerConstant(0, resultType.GetIntegerSpecOrNull()),
                        resultType));

                // Set the outgoing flow.
                block.Flow = SwitchFlow.CreateIfElse(
                    lt,
                    new Branch(successorBlock, new ValueTag[] { resultZero }),
                    new Branch(convBlock));

                // Update the block.
                block = successorBlock;

                // Return the value tag of the result parameter.
                return(resultParam.Tag);
            }
            else
            {
                // Otherwise, just convert the result using a straightforward intrinsic.
                return(block.AppendInstruction(
                           Instruction.CreateConvertIntrinsic(resultType, returnType, returnValue)));
            }
        }
Esempio n. 3
0
            public override BlockFlow Emit(
                FlowGraphBuilder graph,
                ValueTag value)
            {
                // Create the following blocks:
                //
                // bitswitch.entry():
                //   minvalue = const <MinValue>
                //   switchval.adjusted = switchval - minvalue
                //   switchval.unsigned = (uintX)switchval.adjusted
                //   valrange = const <ValueRange>
                //   switch (switchval.unsigned > valrange)
                //     0 -> bitswitch.header()
                //     default -> <defaultBranch>
                //
                // bitswitch.header():
                //   one = const 1
                //   shifted = one << switchval.unsigned
                //   bitmask1 = const <bitmask1>
                //   switch (shifted & bitmask1)
                //     0 -> bitswitch.case2()
                //     default -> <case1Branch>
                //
                // bitswitch.case2():
                //   bitmask2 = const <bitmask2>
                //   switch (shifted & bitmask1)
                //     0 -> bitswitch.case3()
                //     default -> <case2Branch>
                //
                // ...

                var entryBlock  = graph.AddBasicBlock("bitswitch.entry");
                var headerBlock = graph.AddBasicBlock("bitswitch.header");

                var valueType = graph.GetValueType(value);
                var valueSpec = valueType.GetIntegerSpecOrNull();

                var defaultBranch = Flow.DefaultBranch;

                // Subtract the min value from the switch value if necessary.
                if (!MinValue.IsZero)
                {
                    value = entryBlock.AppendInstruction(
                        Instruction.CreateBinaryArithmeticIntrinsic(
                            ArithmeticIntrinsics.Operators.Subtract,
                            false,
                            valueType,
                            value,
                            entryBlock.AppendInstruction(
                                Instruction.CreateConstant(MinValue, valueType),
                                "minvalue")),
                        "switchval.adjusted");
                }

                // Make the switch value unsigned if it wasn't already.
                if (valueSpec.IsSigned)
                {
                    var uintType = TypeEnvironment.MakeUnsignedIntegerType(valueSpec.Size);
                    value = entryBlock.AppendInstruction(
                        Instruction.CreateConvertIntrinsic(
                            false,
                            uintType,
                            valueType,
                            value),
                        "switchval.unsigned");
                    valueType = uintType;
                    valueSpec = uintType.GetIntegerSpecOrNull();
                }

                // Check that the value is within range.
                entryBlock.Flow = SwitchFlow.CreateIfElse(
                    Instruction.CreateRelationalIntrinsic(
                        ArithmeticIntrinsics.Operators.IsGreaterThan,
                        TypeEnvironment.Boolean,
                        valueType,
                        value,
                        entryBlock.AppendInstruction(
                            Instruction.CreateConstant(
                                ValueRange.CastSignedness(false),
                                valueType),
                            "valrange")),
                    defaultBranch,
                    new Branch(headerBlock));

                // Pick an appropriate type for the bitmasks.
                var bitmaskType = valueType;

                if (valueSpec.Size < 32)
                {
                    bitmaskType = TypeEnvironment.UInt32;
                }
                if (ValueRange.IsGreaterThan(new IntegerConstant(valueSpec.Size, ValueRange.Spec)))
                {
                    bitmaskType = TypeEnvironment.UInt64;
                }

                // Set up first part of the header block.
                if (bitmaskType != valueType)
                {
                    valueSpec = bitmaskType.GetIntegerSpecOrNull();
                }

                var zero = headerBlock.AppendInstruction(
                    Instruction.CreateConstant(
                        new IntegerConstant(0, valueSpec),
                        valueType),
                    "zero");

                var one = headerBlock.AppendInstruction(
                    Instruction.CreateConstant(
                        new IntegerConstant(1, valueSpec),
                        valueType),
                    "one");

                value = headerBlock.AppendInstruction(
                    Instruction.CreateArithmeticIntrinsic(
                        ArithmeticIntrinsics.Operators.LeftShift,
                        false,
                        bitmaskType,
                        new[] { bitmaskType, valueType },
                        new[] { one, value }),
                    "shifted");

                valueType = bitmaskType;

                // Start emitting cases.
                var caseBlock = headerBlock;
                var nextCase  = graph.AddBasicBlock("bitswitch.case1");

                for (int i = 0; i < Flow.Cases.Count; i++)
                {
                    // Construct a mask for the case.
                    var switchCase  = Flow.Cases[i];
                    var oneConstant = new IntegerConstant(1, valueSpec);
                    var mask        = new IntegerConstant(0, valueSpec);
                    foreach (var pattern in switchCase.Values)
                    {
                        mask = mask.BitwiseOr(oneConstant.ShiftLeft(((IntegerConstant)pattern).Subtract(MinValue)));
                    }

                    // Switch on the bitwise 'and' of the mask and
                    // the shifted value.
                    caseBlock.Flow = SwitchFlow.CreateIfElse(
                        Instruction.CreateBinaryArithmeticIntrinsic(
                            ArithmeticIntrinsics.Operators.And,
                            false,
                            valueType,
                            value,
                            caseBlock.AppendInstruction(
                                Instruction.CreateConstant(mask, valueType),
                                "bitmask" + i)),
                        switchCase.Branch,
                        new Branch(nextCase));

                    caseBlock = nextCase;
                    nextCase  = graph.AddBasicBlock("bitswitch.case" + (i + 2));
                }

                // Jump to the default branch if nothing matches.
                caseBlock.Flow = new JumpFlow(defaultBranch);

                // Jump to the header block and let it do all of the heavy
                // lifting.
                return(new JumpFlow(entryBlock));
            }