Exemple #1
0
 /// <summary>
 /// Tells if syntactically equivalent instances of a particular intrinsic
 /// are semantically equivalent.
 /// </summary>
 /// <param name="intrinsic">An intrinsic to consider.</param>
 /// <returns>
 /// <c>true</c> if syntactically equivalent instances of
 /// <paramref name="intrinsic"/> are semantically equivalent;
 /// otherwise, <c>false</c>.
 /// </returns>
 private static bool IsCopyableIntrinsic(IntrinsicPrototype intrinsic)
 {
     return(ArithmeticIntrinsics.IsArithmeticIntrinsicPrototype(intrinsic) ||
            ArrayIntrinsics.Namespace.IsIntrinsicPrototype(intrinsic, ArrayIntrinsics.Operators.GetLength) ||
            ArrayIntrinsics.Namespace.IsIntrinsicPrototype(intrinsic, ArrayIntrinsics.Operators.GetElementPointer) ||
            ExceptionIntrinsics.Namespace.IsIntrinsicPrototype(intrinsic, ExceptionIntrinsics.Operators.GetCapturedException));
 }
Exemple #2
0
        /// <summary>
        /// The default constant instruction evaluation function.
        /// </summary>
        /// <param name="prototype">
        /// The prorotype of the instruction to evaluate.
        /// </param>
        /// <param name="arguments">
        /// A list of arguments to the instruction, all of which
        /// must be constants.
        /// </param>
        /// <returns>
        /// <c>null</c> if the instruction cannot be evaluated; otherwise, the constant
        /// to which the instruction evaluates.
        /// </returns>
        public static Constant EvaluateDefault(
            InstructionPrototype prototype,
            IReadOnlyList <Constant> arguments)
        {
            if (prototype is CopyPrototype ||
                prototype is ReinterpretCastPrototype)
            {
                return(arguments[0]);
            }
            else if (prototype is ConstantPrototype)
            {
                var constProto = (ConstantPrototype)prototype;
                if (constProto.Value is DefaultConstant)
                {
                    // Try to specialize 'default' constants.
                    var intSpec = constProto.ResultType.GetIntegerSpecOrNull();
                    if (intSpec != null)
                    {
                        return(new IntegerConstant(0, intSpec));
                    }
                }
                return(constProto.Value);
            }
            else if (prototype is IntrinsicPrototype)
            {
                var intrinsicProto = (IntrinsicPrototype)prototype;

                Constant result;
                if (ArithmeticIntrinsics.IsArithmeticIntrinsicPrototype(intrinsicProto) &&
                    ArithmeticIntrinsics.TryEvaluate(intrinsicProto, arguments, out result))
                {
                    return(result);
                }
            }
            return(null);
        }
 /// <summary>
 /// Looks for an instruction that is semantically
 /// equivalent to a given instruction but minimizes
 /// the number of layers of indirection erected by
 /// copies.
 /// </summary>
 /// <param name="instruction">
 /// The instruction to simplify.
 /// </param>
 /// <param name="graph">
 /// The graph that defines the instruction.
 /// </param>
 /// <returns>
 /// A semantically equivalent instruction.</returns>
 private static Instruction SimplifyInstruction(
     Instruction instruction,
     FlowGraph graph)
 {
     if (instruction.Prototype is CopyPrototype)
     {
         var copyProto = (CopyPrototype)instruction.Prototype;
         var copiedVal = copyProto.GetCopiedValue(instruction);
         if (graph.ContainsInstruction(copiedVal))
         {
             var copiedInsn = graph.GetInstruction(copiedVal).Instruction;
             // Only simplify copies of arithmetic intriniscs and constants.
             // Those are the only instructions we're actually
             // interested in and they don't have any "funny" behavior.
             if (copiedInsn.Prototype is ConstantPrototype ||
                 copiedInsn.Prototype is CopyPrototype ||
                 ArithmeticIntrinsics.IsArithmeticIntrinsicPrototype(copiedInsn.Prototype))
             {
                 return(SimplifyInstruction(copiedInsn, graph));
             }
         }
     }
     return(instruction);
 }
        private static BlockFlow SimplifySwitchFlow(SwitchFlow flow, FlowGraph graph)
        {
            var value = SimplifyInstruction(flow.SwitchValue, graph);

            if (value.Prototype is ConstantPrototype)
            {
                // Turn the switch into a jump.
                var constant         = ((ConstantPrototype)value.Prototype).Value;
                var valuesToBranches = flow.ValueToBranchMap;
                return(new JumpFlow(
                           valuesToBranches.ContainsKey(constant)
                    ? valuesToBranches[constant]
                    : flow.DefaultBranch));
            }
            else if (ArithmeticIntrinsics.IsArithmeticIntrinsicPrototype(value.Prototype))
            {
                var proto         = (IntrinsicPrototype)value.Prototype;
                var intrinsicName = ArithmeticIntrinsics.ParseArithmeticIntrinsicName(proto.Name);
                if (intrinsicName == ArithmeticIntrinsics.Operators.Convert &&
                    proto.ParameterCount == 1 &&
                    flow.IsIntegerSwitch)
                {
                    // We can eliminate instructions that extend integers
                    // by changing the values in the list of cases.
                    var operand     = proto.GetArgumentList(value).Single();
                    var operandType = graph.GetValueType(operand);
                    var convType    = proto.ResultType;
                    var operandSpec = operandType.GetIntegerSpecOrNull();

                    if (operandSpec == null)
                    {
                        // The operand of the conversion intrinsic is not an
                        // integer.
                        return(flow);
                    }

                    var convSpec = convType.GetIntegerSpecOrNull();

                    if (operandSpec.Size > convSpec.Size)
                    {
                        // We can't handle this case. To handle it anyway
                        // would require us to introduce additional cases
                        // and that's costly.
                        return(flow);
                    }

                    var caseList = new List <SwitchCase>();
                    foreach (var switchCase in flow.Cases)
                    {
                        // Retain only those switch cases that have values
                        // that are in the range of the conversion function.
                        var values = ImmutableHashSet.CreateBuilder <Constant>();
                        foreach (var val in switchCase.Values.Cast <IntegerConstant>())
                        {
                            var opVal = val.Cast(operandSpec);
                            if (opVal.Cast(convSpec).Equals(val))
                            {
                                values.Add(opVal);
                            }
                        }
                        if (values.Count > 0)
                        {
                            caseList.Add(new SwitchCase(values.ToImmutableHashSet(), switchCase.Branch));
                        }
                    }
                    return(SimplifySwitchFlow(
                               new SwitchFlow(
                                   Instruction.CreateCopy(
                                       operandType,
                                       operand),
                                   caseList,
                                   flow.DefaultBranch),
                               graph));
                }
                else if (intrinsicName == ArithmeticIntrinsics.Operators.IsEqualTo &&
                         proto.ParameterCount == 2 &&
                         proto.ResultType.IsIntegerType())
                {
                    var      args = proto.GetArgumentList(value);
                    var      lhs  = args[0];
                    var      rhs  = args[1];
                    Constant constant;
                    ValueTag operand;
                    if (TryExtractConstantAndValue(lhs, rhs, graph, out constant, out operand))
                    {
                        // The 'arith.eq' intrinsic always either produces '0' or '1'.
                        // Because of that property, we can safely rewrite switches
                        // like so:
                        //
                        // switch arith.eq(value, constant)
                        //   0 -> zeroBranch
                        //   1 -> oneBranch
                        //   default -> defaultBranch
                        //
                        // -->
                        //
                        // switch value
                        //   constant -> oneBranch ?? defaultBranch
                        //   default -> zeroBranch ?? defaultBranch
                        //
                        var resultSpec = proto.ResultType.GetIntegerSpecOrNull();
                        var zeroVal    = new IntegerConstant(0, resultSpec);
                        var oneVal     = new IntegerConstant(1, resultSpec);

                        var valuesToBranches = flow.ValueToBranchMap;
                        var zeroBranch       = valuesToBranches.ContainsKey(zeroVal)
                            ? valuesToBranches[zeroVal]
                            : flow.DefaultBranch;
                        var oneBranch = valuesToBranches.ContainsKey(oneVal)
                            ? valuesToBranches[oneVal]
                            : flow.DefaultBranch;

                        return(SimplifySwitchFlow(
                                   new SwitchFlow(
                                       Instruction.CreateCopy(
                                           graph.GetValueType(operand),
                                           operand),
                                       new[] { new SwitchCase(ImmutableHashSet.Create(constant), oneBranch) },
                                       zeroBranch),
                                   graph));
                    }
                }
            }
            return(flow);
        }