コード例 #1
0
        private static Function DeclareCopyFunc(BitcodeModule module
                                                , DIFile diFile
                                                , IDebugType <ITypeRef, DIType> voidType
                                                , DIDerivedType constFoo
                                                , DebugPointerType fooPtr
                                                )
        {
            // Since the first parameter is passed by value
            // using the pointer + alloca + memcopy pattern, the actual
            // source, and therefore debug, signature is NOT a pointer.
            // However, that usage would create a signature with two
            // pointers as the arguments, which doesn't match the source
            // To get the correct debug info signature this inserts an
            // explicit DebugType<> that overrides the default behavior
            // to pair the LLVM pointer type with the original source type.
            var copySig = module.Context.CreateFunctionType(module.DIBuilder
                                                            , voidType
                                                            , DebugType.Create(fooPtr, constFoo)
                                                            , fooPtr
                                                            );

            var copyFunc = module.CreateFunction(scope: diFile
                                                 , name: "copy"
                                                 , linkageName: null
                                                 , file: diFile
                                                 , line: 11
                                                 , signature: copySig
                                                 , isLocalToUnit: true
                                                 , isDefinition: true
                                                 , scopeLine: 14
                                                 , debugFlags: DebugInfoFlags.Prototyped
                                                 , isOptimized: false
                                                 ).Linkage(Linkage.Internal)  // static function
                           .AddAttributes(FunctionAttributeIndex.Function, AttributeKind.NoUnwind, AttributeKind.NoInline, AttributeKind.OptimizeNone)
                           .AddAttributes(FunctionAttributeIndex.Function, TargetDependentAttributes);

            TargetDetails.AddABIAttributesForByValueStructure(copyFunc, 0);
            return(copyFunc);
        }
コード例 #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);
                            }
                        }
            }
        }
コード例 #3
0
        private static void CreateCopyFunctionBody(BitcodeModule module
                                                   , DataLayout layout
                                                   , Function copyFunc
                                                   , DIFile diFile
                                                   , ITypeRef foo
                                                   , DebugPointerType fooPtr
                                                   , DIType constFooType
                                                   )
        {
            var diBuilder = module.DIBuilder;

            copyFunc.Parameters[0].Name = "src";
            copyFunc.Parameters[1].Name = "pDst";

            // create block for the function body, only need one for this simple sample
            var blk = copyFunc.AppendBasicBlock("entry");

            // create instruction builder to build the body
            var instBuilder = new InstructionBuilder(blk);

            // create debug info locals for the arguments
            // NOTE: Debug parameter indices are 1 based!
            var paramSrc = diBuilder.CreateArgument(copyFunc.DISubProgram, "src", diFile, 11, constFooType, false, 0, 1);
            var paramDst = diBuilder.CreateArgument(copyFunc.DISubProgram, "pDst", diFile, 12, fooPtr.DIType, false, 0, 2);

            uint ptrAlign = layout.CallFrameAlignmentOf(fooPtr);

            // create Locals
            // NOTE: There's no debug location attached to these instructions.
            //       The debug info will come from the declare intrinsic below.
            var dstAddr = instBuilder.Alloca(fooPtr)
                          .RegisterName("pDst.addr")
                          .Alignment(ptrAlign);

            bool param0ByVal = copyFunc.Attributes[FunctionAttributeIndex.Parameter0].Contains(AttributeKind.ByVal);

            if (param0ByVal)
            {
                diBuilder.InsertDeclare(copyFunc.Parameters[0]
                                        , paramSrc
                                        , new DILocation(module.Context, 11, 43, copyFunc.DISubProgram)
                                        , blk
                                        );
            }

            instBuilder.Store(copyFunc.Parameters[1], dstAddr)
            .Alignment(ptrAlign);

            // insert declare pseudo instruction to attach debug info to the local declarations
            diBuilder.InsertDeclare(dstAddr, paramDst, new DILocation(module.Context, 12, 38, copyFunc.DISubProgram), blk);

            if (!param0ByVal)
            {
                // since the function's LLVM signature uses a pointer, which is copied locally
                // inform the debugger to treat it as the value by dereferencing the pointer
                diBuilder.InsertDeclare(copyFunc.Parameters[0]
                                        , paramSrc
                                        , diBuilder.CreateExpression(ExpressionOp.deref)
                                        , new DILocation(module.Context, 11, 43, copyFunc.DISubProgram)
                                        , blk
                                        );
            }

            var loadedDst = instBuilder.Load(dstAddr)
                            .Alignment(ptrAlign)
                            .SetDebugLocation(15, 6, copyFunc.DISubProgram);

            var dstPtr = instBuilder.BitCast(loadedDst, module.Context.Int8Type.CreatePointerType( ))
                         .SetDebugLocation(15, 13, copyFunc.DISubProgram);

            var srcPtr = instBuilder.BitCast(copyFunc.Parameters[0], module.Context.Int8Type.CreatePointerType( ))
                         .SetDebugLocation(15, 13, copyFunc.DISubProgram);

            uint pointerSize = layout.IntPtrType(module.Context).IntegerBitWidth;

            instBuilder.MemCpy(module
                               , dstPtr
                               , srcPtr
                               , module.Context.CreateConstant(pointerSize, layout.ByteSizeOf(foo), false)
                               , ( int )layout.AbiAlignmentOf(foo)
                               , false
                               ).SetDebugLocation(15, 13, copyFunc.DISubProgram);

            instBuilder.Return( )
            .SetDebugLocation(16, 1, copyFunc.DISubProgram);
        }
コード例 #4
0
        public static void Main(string[] args)
        {
            #region CommandlineArguments
            if (args.Length < 2 || args.Length > 3)
            {
                ShowUsage( );
                return;
            }

            string outputPath = args.Length == 3 ? args[2] : Environment.CurrentDirectory;

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

            srcPath = Path.GetFullPath(srcPath);
            #endregion

            using var libLLVM = InitializeLLVM( );

            #region TargetDetailsSelection
            switch (args[0].ToUpperInvariant( ))
            {
            case "M3":
                TargetDetails = new CortexM3Details(libLLVM);
                break;

            case "X64":
                TargetDetails = new X64Details(libLLVM);
                break;

            default:
                ShowUsage( );
                return;
            }

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

            #region CreatingModule
            using var context     = new Context( );
            using var module      = context.CreateBitcodeModule(moduleName, SourceLanguage.C99, srcPath, VersionIdentString);
            module.SourceFileName = Path.GetFileName(srcPath);
            module.TargetTriple   = TargetDetails.TargetMachine.Triple;
            module.Layout         = TargetDetails.TargetMachine.TargetData;
            Debug.Assert(!(module.DICompileUnit is null), "Expected module with non-null compile unit");

            TargetDependentAttributes = TargetDetails.BuildTargetDependentFunctionAttributes(context);
            #endregion

            var diFile = module.DIBuilder.CreateFile(srcPath);

            #region CreatingBasicTypesWithDebugInfo
            // 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 <ITypeRef, DIType>(module.Context.VoidType, null);
            var i32Array_0_32 = i32.CreateArrayType(module, 0, 32);
            #endregion

            #region CreatingStructureTypes
            // create the LLVM structure type and body with full debug information
            var fooBody = new[]
            {
                new DebugMemberInfo(0, "a", diFile, 3, i32),
                new DebugMemberInfo(1, "b", diFile, 4, f32),
                new DebugMemberInfo(2, "c", diFile, 5, i32Array_0_32),
            };

            var fooType = new DebugStructType(module, "struct.foo", module.DICompileUnit, "foo", diFile, 1, DebugInfoFlags.None, fooBody);
            #endregion

            #region CreatingGlobalsAndMetadata
            // 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 = module.Layout.AbiAlignmentOf(fooType);
            bar.AddDebugInfo(module.DIBuilder.CreateGlobalVariableExpression(module.DICompileUnit, "bar", string.Empty, diFile, 8, fooType.DIType, false, null));

            var baz = module.AddGlobal(fooType, false, Linkage.Common, Constant.NullValueFor(fooType), "baz");
            baz.Alignment = module.Layout.AbiAlignmentOf(fooType);
            baz.AddDebugInfo(module.DIBuilder.CreateGlobalVariableExpression(module.DICompileUnit, "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);
            #endregion

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

            // 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.
            IrFunction doCopyFunc = DeclareDoCopyFunc(module, diFile, voidType);
            IrFunction copyFunc   = DeclareCopyFunc(module, diFile, voidType, constFoo, fooPtr);

            CreateCopyFunctionBody(module, copyFunc, diFile, fooType, fooPtr, constFoo);
            CreateDoCopyFunctionBody(module, 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 compare 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);
                    using 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.
                    using var pm = new ModulePassManager( );
                    pm.AddAlwaysInlinerPass( )
                    .AddAggressiveDCEPass( )
                    .AddArgumentPromotionPass( )
                    .AddBasicAliasAnalysisPass( )
                    .AddBitTrackingDCEPass( )
                    .AddCFGSimplificationPass( )
                    .AddConstantMergePass( )
                    .AddConstantPropagationPass( )
                    .AddFunctionInliningPass( )
                    .AddGlobalOptimizerPass( )
                    .AddInstructionCombiningPass( )
                    .Run(modForOpt);
                }

                // Module is good, so generate the output files
                module.WriteToFile(Path.Combine(outputPath, "test.bc"));
                File.WriteAllText(Path.Combine(outputPath, "test.ll"), module.WriteToString( ));
                TargetDetails.TargetMachine.EmitToFile(module, Path.Combine(outputPath, "test.o"), CodeGenFileType.ObjectFile);
                TargetDetails.TargetMachine.EmitToFile(module, Path.Combine(outputPath, "test.s"), CodeGenFileType.AssemblySource);
                Console.WriteLine("Generated test.bc, test.ll, test.o, and test.s");
            }
        }