Exemplo n.º 1
0
        public void AsStringTest( )
        {
            using (var context = new Context( ))
                using (var module = new BitcodeModule(context, TestModuleName))
                {
                    Function testFunc = CreateSimpleVoidNopTestFunction(module, "foo");

                    // verify basics
                    Assert.IsNotNull(testFunc);
                    string txt = module.WriteToString( );
                    Assert.IsFalse(string.IsNullOrWhiteSpace(txt));
                    string expectedText = string.Format(TestModuleTemplate, Environment.NewLine, "test");
                    Assert.AreEqual(expectedText, txt);
                }
        }
Exemplo n.º 2
0
        /// <summary>Creates a test LLVM module with debug information</summary>
        /// <param name="args">ignored</param>
        /// <remarks>
        /// <code language="c" title="Example code generated" source="test.c" />
        /// </remarks>
        public static void Main(string[] args)
        {
            TargetDetails = new CortexM3Details();
            string srcPath = args[0];

            if (!File.Exists(srcPath))
            {
                Console.Error.WriteLine("Src file not found: '{0}'", srcPath);
                return;
            }

            srcPath = Path.GetFullPath(srcPath);

            string moduleName = $"test_{TargetDetails.ShortName}.bc";

            using (StaticState.InitializeLLVM())
            {
                StaticState.RegisterAll( );
                var target = Target.FromTriple(TargetDetails.Triple);
                using (var context = new Context( ))
                    using (var targetMachine = target.CreateTargetMachine(TargetDetails.Triple, TargetDetails.Cpu, TargetDetails.Features, CodeGenOpt.Aggressive, Reloc.Default, CodeModel.Small))
                        using (var module = new BitcodeModule(context, moduleName))
                        {
                            module.SourceFileName     = Path.GetFileName(srcPath);
                            TargetDependentAttributes = TargetDetails.BuildTargetDependentFunctionAttributes(context);
                            var targetData = targetMachine.TargetData;

                            module.TargetTriple = targetMachine.Triple;
                            module.Layout       = targetMachine.TargetData;

                            // create compile unit and file as the top level scope for everything
                            var cu = module.DIBuilder.CreateCompileUnit(SourceLanguage.C99
                                                                        , Path.GetFileName(srcPath)
                                                                        , Path.GetDirectoryName(srcPath)
                                                                        , VersionIdentString
                                                                        , false
                                                                        , string.Empty
                                                                        , 0
                                                                        );
                            var diFile = module.DIBuilder.CreateFile(srcPath);

                            // Create basic types used in this compilation
                            var i32           = new DebugBasicType(module.Context.Int32Type, module, "int", DiTypeKind.Signed);
                            var f32           = new DebugBasicType(module.Context.FloatType, module, "float", DiTypeKind.Float);
                            var voidType      = DebugType.Create(module.Context.VoidType, ( DIType )null);
                            var i32Array_0_32 = i32.CreateArrayType(module, 0, 32);

                            // create the LLVM structure type and body with full debug information
    #pragma warning disable SA1500 // "Warning SA1500  Braces for multi - line statements must not share line" (simple table format)
                            var fooBody = new[]
                            { new DebugMemberInfo {
                                  File = diFile, Line = 3, Name = "a", DebugType = i32, Index = 0
                              }
                              , new DebugMemberInfo {
                                  File = diFile, Line = 4, Name = "b", DebugType = f32, Index = 1
                              }
                              , new DebugMemberInfo {
                                  File = diFile, Line = 5, Name = "c", DebugType = i32Array_0_32, Index = 2
                              } };
    #pragma warning restore
                            var fooType = new DebugStructType(module, "struct.foo", cu, "foo", diFile, 1, DebugInfoFlags.None, fooBody);

                            // add global variables and constants
                            var constArray = ConstantArray.From(i32, 32, module.Context.CreateConstant(3), module.Context.CreateConstant(4));
                            var barValue   = module.Context.CreateNamedConstantStruct(fooType
                                                                                      , module.Context.CreateConstant(1)
                                                                                      , module.Context.CreateConstant(2.0f)
                                                                                      , constArray
                                                                                      );

                            var bar = module.AddGlobal(fooType, false, 0, barValue, "bar");
                            bar.Alignment = targetData.AbiAlignmentOf(fooType);
                            bar.AddDebugInfo(module.DIBuilder.CreateGlobalVariableExpression(cu, "bar", string.Empty, diFile, 8, fooType.DIType, false, null));

                            var baz = module.AddGlobal(fooType, false, Linkage.Common, Constant.NullValueFor(fooType), "baz");
                            baz.Alignment = targetData.AbiAlignmentOf(fooType);
                            baz.AddDebugInfo(module.DIBuilder.CreateGlobalVariableExpression(cu, "baz", string.Empty, diFile, 9, fooType.DIType, false, null));

                            // add module flags and compiler identifiers...
                            // this can technically occur at any point, though placing it here makes
                            // comparing against clang generated files easier
                            AddModuleFlags(module);

                            // create types for function args
                            var constFoo = module.DIBuilder.CreateQualifiedType(fooType.DIType, QualifiedTypeTag.Const);
                            var fooPtr   = new DebugPointerType(fooType, module);

                            // Create the functions
                            // NOTE: The declaration ordering is reversed from that of the sample code file (test.c)
                            //       However, this is what Clang ends up doing for some reason so it is
                            //       replicated here to aid in comparing the generated LL files.
                            Function doCopyFunc = DeclareDoCopyFunc(module, diFile, voidType);
                            Function copyFunc   = DeclareCopyFunc(module, diFile, voidType, constFoo, fooPtr);

                            CreateCopyFunctionBody(module, targetData, copyFunc, diFile, fooType, fooPtr, constFoo);
                            CreateDoCopyFunctionBody(module, targetData, doCopyFunc, fooType, bar, baz, copyFunc);

                            // finalize the debug information
                            // all temporaries must be replaced by now, this resolves any remaining
                            // forward declarations and marks the builder to prevent adding any
                            // nodes that are not completely resolved.
                            module.DIBuilder.Finish( );

                            // verify the module is still good and print any errors found
                            if (!module.Verify(out string msg))
                            {
                                Console.Error.WriteLine("ERROR: {0}", msg);
                            }
                            else
                            {
                                // test optimization works, but don't save it as that makes it harder to do a diff with official clang builds
                                {// force a GC to verify callback delegate for diagnostics is still valid, this is for test only and wouldn't
                                 // normally be done in production code.
                                    GC.Collect(GC.MaxGeneration);
                                    var modForOpt = module.Clone( );

                                    // NOTE:
                                    // The ordering of passes can matter depending on the pass and passes may be added more than once
                                    // the caller has full control of ordering, this is just a sample of effectively randomly picked
                                    // passes and not necessarily a reflection of any particular use case.
                                    var pm = new ModulePassManager( )
                                             .AddAlwaysInlinerPass( )
                                             .AddAggressiveDCEPass( )
                                             .AddArgumentPromotionPass( )
                                             .AddBasicAliasAnalysisPass( )
                                             .AddBitTrackingDCEPass( )
                                             .AddCFGSimplificationPass( )
                                             .AddConstantMergePass( )
                                             .AddConstantPropagationPass( )
                                             .AddFunctionInliningPass( )
                                             .AddGlobalOptimizerPass( )
                                             .AddInstructionCombiningPass( );

                                    pm.Run(modForOpt);
                                }

                                // Module is good, so generate the output files
                                module.WriteToFile("test.bc");
                                File.WriteAllText("test.ll", module.WriteToString( ));
                                targetMachine.EmitToFile(module, "test.o", CodeGenFileType.ObjectFile);
                                targetMachine.EmitToFile(module, "test.s", CodeGenFileType.AssemblySource);
                            }
                        }
            }
        }