Exemplo n.º 1
0
        /// <summary>
        /// Writes a CIL method body, analyzes it as Flame IR,
        /// emits that as CIL and checks that the outcome matches
        /// what we'd expect.
        /// </summary>
        /// <param name="returnType">
        /// The return type of the method body.
        /// </param>
        /// <param name="parameterTypes">
        /// The parameter types of the method body.
        /// </param>
        /// <param name="localTypes">
        /// The local variable types of the method body.
        /// </param>
        /// <param name="emitBody">
        /// A function that writes the method body.
        /// </param>
        /// <param name="emitOracle">
        /// A function that writes the expected method body.
        /// </param>
        private void RoundtripStaticMethodBody(
            TypeReference returnType,
            IReadOnlyList <TypeReference> parameterTypes,
            IReadOnlyList <TypeReference> localTypes,
            Action <Mono.Cecil.Cil.ILProcessor> emitBody,
            Action <Mono.Cecil.Cil.ILProcessor> emitOracle)
        {
            // Synthesize the expected CIL.
            var expectedCilBody = new Mono.Cecil.Cil.MethodBody(
                CreateStaticMethodDef(returnType, parameterTypes));

            emitOracle(expectedCilBody.GetILProcessor());
            expectedCilBody.Optimize();

            // Format the synthesized CIL.
            RoundtripStaticMethodBody(
                returnType,
                parameterTypes,
                localTypes,
                emitBody,
                FormatMethodBody(expectedCilBody));
        }
Exemplo n.º 2
0
        /// <summary>
        /// Writes a CIL method body, analyzes it as Flame IR,
        /// emits that as CIL and checks that the outcome matches
        /// what we'd expect.
        /// </summary>
        /// <param name="returnType">
        /// The return type of the method body.
        /// </param>
        /// <param name="parameterTypes">
        /// The parameter types of the method body.
        /// </param>
        /// <param name="localTypes">
        /// The local variable types of the method body.
        /// </param>
        /// <param name="emitBody">
        /// A function that writes the method body.
        /// </param>
        /// <param name="oracle">
        /// A printed version of the expected method body.
        /// </param>
        private void RoundtripStaticMethodBody(
            TypeReference returnType,
            IReadOnlyList <TypeReference> parameterTypes,
            IReadOnlyList <TypeReference> localTypes,
            Action <Mono.Cecil.Cil.ILProcessor> emitBody,
            string oracle)
        {
            // Define a method.
            var methodDef = CreateStaticMethodDef(returnType, parameterTypes);

            // Emit the source CIL.
            var cilBody = new Mono.Cecil.Cil.MethodBody(methodDef);

            foreach (var localType in localTypes)
            {
                cilBody.Variables.Add(new Mono.Cecil.Cil.VariableDefinition(localType));
            }

            emitBody(cilBody.GetILProcessor());
            cilBody.Optimize();

            // Analyze it as Flame IR.
            var irBody = ClrMethodBodyAnalyzer.Analyze(
                cilBody,
                new Parameter(TypeHelpers.BoxIfReferenceType(corlib.Resolve(returnType))),
                default(Parameter),
                parameterTypes
                .Select((type, i) => new Parameter(TypeHelpers.BoxIfReferenceType(corlib.Resolve(type)), "param_" + i))
                .ToArray(),
                corlib);

            // Register analyses.
            irBody = new global::Flame.Compiler.MethodBody(
                irBody.ReturnParameter,
                irBody.ThisParameter,
                irBody.Parameters,
                irBody.Implementation
                .WithAnalysis(LazyBlockReachabilityAnalysis.Instance)
                .WithAnalysis(NullabilityAnalysis.Instance)
                .WithAnalysis(new EffectfulInstructionAnalysis())
                .WithAnalysis(PredecessorAnalysis.Instance)
                .WithAnalysis(RelatedValueAnalysis.Instance)
                .WithAnalysis(LivenessAnalysis.Instance)
                .WithAnalysis(InterferenceGraphAnalysis.Instance)
                .WithAnalysis(ValueUseAnalysis.Instance)
                .WithAnalysis(ConservativeInstructionOrderingAnalysis.Instance));

            // Optimize the IR a tiny bit.
            irBody = irBody.WithImplementation(
                irBody.Implementation.Transform(
                    AllocaToRegister.Instance,
                    CopyPropagation.Instance,
                    new ConstantPropagation(),
                    SwitchSimplification.Instance,
                    DeadValueElimination.Instance,
                    InstructionSimplification.Instance,
                    new JumpThreading(true),
                    DeadBlockElimination.Instance,
                    new SwitchLowering(corlib.Resolver.TypeEnvironment),
                    CopyPropagation.Instance,
                    InstructionSimplification.Instance,
                    DeadValueElimination.Instance,
                    InstructionReordering.Instance,
                    new JumpThreading(false)));

            // Turn Flame IR back into CIL.
            var newCilBody = ClrMethodBodyEmitter.Compile(irBody, methodDef, corlib.Resolver.TypeEnvironment);

            // Check that the resulting CIL matches the expected CIL.
            var actual = FormatMethodBody(newCilBody);

            actual = actual.Trim().Replace("\r", "");
            oracle = oracle.Trim().Replace("\r", "");
            if (actual != oracle)
            {
                var encoder     = new EncoderState();
                var encodedImpl = encoder.Encode(irBody.Implementation);

                var actualIr = Les2LanguageService.Value.Print(
                    encodedImpl,
                    options: new LNodePrinterOptions
                {
                    IndentString = new string(' ', 4)
                });

                log.Log(
                    new LogEntry(
                        Severity.Message,
                        "emitted CIL-oracle mismatch",
                        "round-tripped CIL does not match the oracle. CIL emit output:",
                        new Paragraph(new WrapBox(actual, 0, -actual.Length)),
                        DecorationSpan.MakeBold("remark: Flame IR:"),
                        new Paragraph(new WrapBox(actualIr, 0, -actualIr.Length))));
            }
            Assert.AreEqual(oracle, actual);
        }