diff --git a/Sources/LLVM/DIBuilder.swift b/Sources/LLVM/DIBuilder.swift index 7ac1dcb7..84bf23a5 100644 --- a/Sources/LLVM/DIBuilder.swift +++ b/Sources/LLVM/DIBuilder.swift @@ -2,162 +2,23 @@ import cllvm #endif -/// Source languages known by DWARF. -public enum DWARFSourceLanguage { - case ada83 - - case ada95 - - case c - - case c89 - - case c99 - - case c11 - - case cPlusPlus - - case cPlusPlus03 - - case cPlusPlus11 - - case cPlusPlus14 - - case cobol74 - - case cobol85 - - case fortran77 - - case fortran90 - - case fortran03 - - case fortran08 - - case pascal83 - - case modula2 - - case java - - case fortran95 - - case PLI - - case objC - - case objCPlusPlus - - case UPC - - case D - - case python - - case openCL - - case go - - case modula3 - - case haskell - - case ocaml - - case rust - - case swift - - case julia - - case dylan - - case renderScript - - case BLISS - - // MARK: Vendor Extensions - - case mipsAssembler - - case googleRenderScript - - case borlandDelphi - - - private static let languageMapping: [DWARFSourceLanguage: LLVMDWARFSourceLanguage] = [ - .c: LLVMDWARFSourceLanguageC, .c89: LLVMDWARFSourceLanguageC89, - .c99: LLVMDWARFSourceLanguageC99, .c11: LLVMDWARFSourceLanguageC11, - .ada83: LLVMDWARFSourceLanguageAda83, - .cPlusPlus: LLVMDWARFSourceLanguageC_plus_plus, - .cPlusPlus03: LLVMDWARFSourceLanguageC_plus_plus_03, - .cPlusPlus11: LLVMDWARFSourceLanguageC_plus_plus_11, - .cPlusPlus14: LLVMDWARFSourceLanguageC_plus_plus_14, - .cobol74: LLVMDWARFSourceLanguageCobol74, - .cobol85: LLVMDWARFSourceLanguageCobol85, - .fortran77: LLVMDWARFSourceLanguageFortran77, - .fortran90: LLVMDWARFSourceLanguageFortran90, - .pascal83: LLVMDWARFSourceLanguagePascal83, - .modula2: LLVMDWARFSourceLanguageModula2, - .java: LLVMDWARFSourceLanguageJava, - .ada95: LLVMDWARFSourceLanguageAda95, - .fortran95: LLVMDWARFSourceLanguageFortran95, - .PLI: LLVMDWARFSourceLanguagePLI, - .objC: LLVMDWARFSourceLanguageObjC, - .objCPlusPlus: LLVMDWARFSourceLanguageObjC_plus_plus, - .UPC: LLVMDWARFSourceLanguageUPC, - .D: LLVMDWARFSourceLanguageD, - .python: LLVMDWARFSourceLanguagePython, - .openCL: LLVMDWARFSourceLanguageOpenCL, - .go: LLVMDWARFSourceLanguageGo, - .modula3: LLVMDWARFSourceLanguageModula3, - .haskell: LLVMDWARFSourceLanguageHaskell, - .ocaml: LLVMDWARFSourceLanguageOCaml, - .rust: LLVMDWARFSourceLanguageRust, - .swift: LLVMDWARFSourceLanguageSwift, - .julia: LLVMDWARFSourceLanguageJulia, - .dylan: LLVMDWARFSourceLanguageDylan, - .fortran03: LLVMDWARFSourceLanguageFortran03, - .fortran08: LLVMDWARFSourceLanguageFortran08, - .renderScript: LLVMDWARFSourceLanguageRenderScript, - .BLISS: LLVMDWARFSourceLanguageBLISS, - .mipsAssembler: LLVMDWARFSourceLanguageMips_Assembler, - .googleRenderScript: LLVMDWARFSourceLanguageGOOGLE_RenderScript, - .borlandDelphi: LLVMDWARFSourceLanguageBORLAND_Delphi, - ] - - /// Retrieves the corresponding `LLVMDWARFSourceLanguage`. - public var llvm: LLVMDWARFSourceLanguage { - return DWARFSourceLanguage.languageMapping[self]! - } -} - -/// The amount of debug information to emit. -public enum DWARFEmissionKind { - case none - case full - case lineTablesOnly - - private static let emissionMapping: [DWARFEmissionKind: LLVMDWARFEmissionKind] = [ - .none: LLVMDWARFEmissionNone, .full: LLVMDWARFEmissionFull, - .lineTablesOnly: LLVMDWARFEmissionLineTablesOnly, - ] - - /// Retrieves the corresponding `LLVMDWARFEmissionKind`. - public var llvm: LLVMDWARFEmissionKind { - return DWARFEmissionKind.emissionMapping[self]! - } -} - +/// A `DIBuilder` is a helper object used to generate debugging information in +/// the form of LLVM metadata. A `DIBuilder` is usually paired with an +/// `IRBuilder` to allow for the generation of code and metadata in lock step. public final class DIBuilder { internal let llvm: LLVMDIBuilderRef - /// The module this `IRBuilder` is associated with. + /// The module this `DIBuilder` is associated with. public let module: Module - public init(module: Module, allowUnresolved: Bool = false) { + /// Initializes a new `DIBuilder` object. + /// + /// - Parameters: + /// - module: The parent module. + /// - allowUnresolved: If true, when this DIBuilder is finalized it will + /// collect unresolved nodes attached to the module in + /// order to resolve cycles + public init(module: Module, allowUnresolved: Bool = true) { self.module = module if allowUnresolved { self.llvm = LLVMCreateDIBuilder(module.llvm) @@ -166,6 +27,19 @@ public final class DIBuilder { } } + /// Construct any deferred debug info descriptors. + public func finalize() { + LLVMDIBuilderFinalize(self.llvm) + } + + deinit { + LLVMDisposeDIBuilder(self.llvm) + } +} + +// MARK: Scope Entities + +extension DIBuilder { /// A CompileUnit provides an anchor for all debugging information generated /// during this instance of compilation. /// @@ -174,16 +48,18 @@ public final class DIBuilder { /// - file: The file descriptor for the source file. /// - kind: The kind of debug info to generate. /// - optimized: A flag that indicates whether optimization is enabled or - /// not when compiling the source file. Defaults to `false`. - /// - splitDebugInlining: A flag that indicates whether to emit inline debug - /// information. Defaults to `false`. + /// not when compiling the source file. Defaults to `false`. + /// - splitDebugInlining: If true, minimal debug info in the module is + /// emitted to facilitate online symbolication and stack traces in the + /// absence of .dwo/.dwp files when using Split DWARF. /// - debugInfoForProfiling: A flag that indicates whether to emit extra - /// debug information for profile collection. + /// debug information for profile collection. /// - flags: Command line options that are embedded in debug info for use - /// by third-party tools. + /// by third-party tools. + /// - splitDWARFPath: The path to the split DWARF file. /// - identity: The identity of the tool that is compiling this source file. /// - Returns: A value representing a compilation-unit level scope. - public func createCompileUnit( + public func buildCompileUnit( for language: DWARFSourceLanguage, in file: FileMetadata, kind: DWARFEmissionKind, @@ -191,16 +67,17 @@ public final class DIBuilder { splitDebugInlining: Bool = false, debugInfoForProfiling: Bool = false, flags: [String] = [], - identity: String = "", - splitName: String = "" - ) -> Scope { + runtimeVersion: Int = 0, + splitDWARFPath: String = "", + identity: String = "" + ) -> CompileUnitMetadata { let allFlags = flags.joined(separator: " ") guard let cu = LLVMDIBuilderCreateCompileUnit( self.llvm, language.llvm, file.llvm, identity, identity.count, optimized.llvm, allFlags, allFlags.count, - /*Runtime Version*/0, - splitName, splitName.count, + UInt32(runtimeVersion), + splitDWARFPath, splitDWARFPath.count, kind.llvm, /*DWOId*/0, splitDebugInlining.llvm, @@ -208,22 +85,213 @@ public final class DIBuilder { ) else { fatalError() } - return Scope(llvm: cu) + return CompileUnitMetadata(llvm: cu) } /// Create a file descriptor to hold debugging information for a file. /// + /// Global variables and top level functions would be defined using this + /// context. File descriptors also provide context for source line + /// correspondence. + /// /// - Parameters: /// - name: The name of the file. /// - directory: The directory the file resides in. /// - Returns: A value represending metadata about a given file. - public func createFile(named name: String, in directory: String) -> FileMetadata { - guard let file = LLVMDIBuilderCreateFile(self.llvm, name, name.count, directory, directory.count) else { + public func buildFile( + named name: String, in directory: String + ) -> FileMetadata { + guard let file = LLVMDIBuilderCreateFile( + self.llvm, name, name.count, directory, directory.count) + else { fatalError("Failed to allocate metadata for a file") } return FileMetadata(llvm: file) } + /// Creates a new descriptor for a module with the specified parent scope. + /// + /// - Parameters: + /// - name: Module name. + /// - scope: The parent scope containing this module declaration. + /// - macros: A list of -D macro definitions as they would appear on a + /// command line. + /// - includePath: The path to the module map file. + /// - includeSystemRoot: The Clang system root (value of -isysroot). + public func buildModule( + named name: String, + scope: DIScope, + macros: [String] = [], + includePath: String = "", + includeSystemRoot: String = "" + ) -> ModuleMetadata { + let macros = macros.joined(separator: " ") + guard + let module = LLVMDIBuilderCreateModule( + self.llvm, scope.asMetadata(), name, name.count, + macros, macros.count, includePath, includePath.count, + includeSystemRoot, includeSystemRoot.count) + else { + fatalError("Failed to allocate metadata for a file") + } + return ModuleMetadata(llvm: module) + } + + /// Creates a new descriptor for a namespace with the specified parent scope. + /// + /// - Parameters: + /// - name: NameSpace name. + /// - scope: The parent scope containing this module declaration. + /// - exportsSymbols: Whether or not the namespace exports symbols, e.g. + /// this is true of C++ inline namespaces. + public func buildNameSpace( + named name: String, scope: DIScope, exportsSymbols: Bool + ) -> NameSpaceMetadata { + guard + let nameSpace = LLVMDIBuilderCreateNameSpace( + self.llvm, scope.asMetadata(), name, name.count, exportsSymbols.llvm) + else { + fatalError("Failed to allocate metadata for a file") + } + return NameSpaceMetadata(llvm: nameSpace) + } + + /// Create a new descriptor for the specified subprogram. + /// + /// - Parameters: + /// - name: Function name. + /// - linkageName: Mangled function name. + /// - scope: Function scope. + /// - file: File where this variable is defined. + /// - line: Line number. + /// - scopeLine: Set to the beginning of the scope this starts + /// - type: Function type. + /// - flags: Flags to emit DWARF attributes. + /// - isLocal: True if this function is not externally visible. + /// - isDefinition: True if this is a function definition. + /// - isOptimized: True if optimization is enabled. + public func buildFunction( + named name: String, linkageName: String, + scope: DIScope, file: FileMetadata, line: Int, scopeLine: Int, + type: DISubroutineType, + flags: DIFlags, + isLocal: Bool = true, isDefinition: Bool = true, + isOptimized: Bool = false + ) -> FunctionMetadata { + guard let fn = LLVMDIBuilderCreateFunction( + self.llvm, scope.asMetadata(), + name, name.count, linkageName, linkageName.count, + file.asMetadata(), UInt32(line), + type.asMetadata(), + isLocal.llvm, isDefinition.llvm, UInt32(scopeLine), + flags.llvm, isOptimized.llvm) + else { + fatalError("Failed to allocate metadata for a function") + } + return FunctionMetadata(llvm: fn) + } + + /// Create a descriptor for a lexical block with the specified parent context. + /// + /// - Parameters: + /// - scope: Parent lexical block. + /// - File: Source file. + /// - line: The line in the source file. + /// - column: The column in the source file. + /// + public func buildLexicalBlock( + scope: DIScope, file: FileMetadata, line: Int, column: Int + ) -> LexicalBlockMetadata { + guard let block = LLVMDIBuilderCreateLexicalBlock( + self.llvm, scope.asMetadata(), file.asMetadata(), + UInt32(line), UInt32(column)) + else { + fatalError("Failed to allocate metadata for a lexical block") + } + return LexicalBlockMetadata(llvm: block) + } + + /// Create a descriptor for a lexical block with a new file attached. + /// + /// - Parameters: + /// - scope: Lexical block. + /// - file: Source file. + /// - discriminator: DWARF path discriminator value. + public func buildLexicalBlockFile( + scope: DIScope, file: FileMetadata, discriminator: Int + ) -> LexicalBlockFileMetadata { + guard let block = LLVMDIBuilderCreateLexicalBlockFile( + self.llvm, scope.asMetadata(), file.asMetadata(), UInt32(discriminator)) + else { + fatalError("Failed to allocate metadata for a lexical block file") + } + return LexicalBlockFileMetadata(llvm: block) + } +} + +// MARK: Local Variables + +extension DIBuilder { + /// Create a new descriptor for a local auto variable. + /// + /// - Parameters: + /// - name: Variable name. + /// - scope: The local scope the variable is declared in. + /// - file: File where this variable is defined. + /// - line: Line number. + /// - type: Metadata describing the type of the variable. + /// - alwaysPreserve: If true, this descriptor will survive optimizations. + /// - flags: Flags. + /// - alignment: Variable alignment. + public func buildLocalVariable( + named name: String, + scope: DIScope, file: FileMetadata, line: Int, + type: DIType, alwaysPreserve: Bool = false, + flags: DIFlags = [], alignment: Alignment = .zero + ) -> LocalVariableMetadata { + let radix = UInt32(self.module.dataLayout.intPointerType().width) + guard let variable = LLVMDIBuilderCreateAutoVariable( + self.llvm, scope.asMetadata(), + name, name.count, file.asMetadata(), UInt32(line), + type.asMetadata(), alwaysPreserve.llvm, + flags.llvm, alignment.rawValue * radix) + else { + fatalError("Failed to allocate metadata for a local variable") + } + return LocalVariableMetadata(llvm: variable) + } + + /// Create a new descriptor for a function parameter variable. + /// + /// - Parameters: + /// - name: Variable name. + /// - index: Unique argument number for this variable; starts at 1. + /// - scope: The local scope the variable is declared in. + /// - file: File where this variable is defined. + /// - line: Line number. + /// - type: Metadata describing the type of the variable. + /// - alwaysPreserve: If true, this descriptor will survive optimizations. + /// - flags: Flags. + public func buildParameterVariable( + named name: String, index: Int, + scope: DIScope, file: FileMetadata, line: Int, + type: DIType, alwaysPreserve: Bool = false, + flags: DIFlags = [] + ) -> LocalVariableMetadata { + guard let variable = LLVMDIBuilderCreateParameterVariable( + self.llvm, scope.asMetadata(), name, name.count, + UInt32(index), file.asMetadata(), UInt32(line), + type.asMetadata(), alwaysPreserve.llvm, flags.llvm) + else { + fatalError("Failed to allocate metadata for a parameter variable") + } + return LocalVariableMetadata(llvm: variable) + } +} + +// MARK: Debug Locations + +extension DIBuilder { /// Creates a new debug location that describes a source location. /// /// - Parameters: @@ -234,26 +302,756 @@ public final class DIBuilder { /// - inlinedAt: If this location has been inlined somewhere, the scope in /// which it was inlined. Defaults to `nil`. /// - Returns: A value representing a debug location. - public func createDebugLocation( + public func buildDebugLocation( at location : (line: Int, column: Int), - in scope: Scope, - inlinedAt: Scope? = nil + in scope: DIScope, + inlinedAt: DIScope? = nil ) -> DebugLocation { guard let loc = LLVMDIBuilderCreateDebugLocation( self.module.context.llvm, UInt32(location.line), UInt32(location.column), - scope.llvm, inlinedAt?.llvm - ) else { + scope.asMetadata(), inlinedAt?.asMetadata()) + else { fatalError("Failed to allocate metadata for a debug location") } return DebugLocation(llvm: loc) } +} - /// Construct any deferred debug info descriptors. - public func finalize() { - LLVMDIBuilderFinalize(self.llvm) +extension DIBuilder { + /// Create subroutine type. + /// + /// - Parameters: + /// - file: The file in which the subroutine resides. + /// - parameterTypes: An array of subroutine parameter types. + /// - returnType: The return type of the function, if any. + /// - flags: Flags to emit DWARF attributes. + public func buildSubroutineType( + in file: FileMetadata, + parameterTypes: [DIType], returnType: DIType? = nil, + flags: DIFlags = [] + ) -> DISubroutineType { + // The return type is always the first operand. + var diTypes = [returnType?.asMetadata()] + diTypes.append(contentsOf: parameterTypes.map { + return $0.asMetadata() as Optional + }) + return diTypes.withUnsafeMutableBufferPointer { buf in + guard let ty = LLVMDIBuilderCreateSubroutineType( + self.llvm, file.asMetadata(), + buf.baseAddress!, UInt32(buf.count), + flags.llvm) + else { + fatalError("Failed to allocate metadata") + } + return DISubroutineType(llvm: ty) + } } - deinit { - LLVMDisposeDIBuilder(self.llvm) + /// Create a debugging information entry for an enumeration. + /// + /// - Parameters: + /// - name: Enumeration name. + /// - scope: Scope in which this enumeration is defined. + /// - file: File where this member is defined. + /// - line: Line number. + /// - size: Member size. + /// - alignmemnt: Member alignment. + /// - elements: Enumeration elements. + /// - numElements: Number of enumeration elements. + /// - underlyingType: Underlying type of a C++11/ObjC fixed enum. + public func buildEnumerationType( + named name: String, + scope: DIScope, file: FileMetadata, line: Int, + size: Size, alignment: Alignment, + elements: [DIType], underlyingType: DIType + ) -> DIType { + let radix = UInt32(self.module.dataLayout.intPointerType().width) + var diTypes = elements.map { $0.asMetadata() as Optional } + return diTypes.withUnsafeMutableBufferPointer { buf in + guard let ty = LLVMDIBuilderCreateEnumerationType( + self.llvm, scope.asMetadata(), + name, name.count, file.asMetadata(), UInt32(line), + size.valueInBits(radix: UInt64(radix)), alignment.rawValue * radix, + buf.baseAddress!, UInt32(buf.count), + underlyingType.asMetadata()) + else { + fatalError("Failed to allocate metadata") + } + return DIOpaqueType(llvm: ty) + } + } + + /// Create a debugging information entry for a union. + /// + /// - Parameters: + /// - name: Union name. + /// - scope: Scope in which this union is defined. + /// - file: File where this member is defined. + /// - line: Line number. + /// - size: Member size. + /// - alignment: Member alignment. + /// - flags: Flags to encode member attribute, e.g. private + /// - elements: Union elements. + /// - runtimeVersion: Optional parameter, Objective-C runtime version. + /// - uniqueID: A unique identifier for the union. + public func buildUnionType( + named name: String, + scope: DIScope, file: FileMetadata, line: Int, + size: Size, alignment: Alignment, flags: DIFlags, + elements: [DIType], + runtimeVersion: Int = 0, uniqueID: String = "" + ) -> DIType { + let radix = UInt32(self.module.dataLayout.intPointerType().width) + var diTypes = elements.map { $0.asMetadata() as Optional } + return diTypes.withUnsafeMutableBufferPointer { buf in + guard let ty = LLVMDIBuilderCreateUnionType( + self.llvm, scope.asMetadata(), + name, name.count, file.asMetadata(), UInt32(line), + size.valueInBits(radix: UInt64(radix)), alignment.rawValue * radix, + flags.llvm, buf.baseAddress!, UInt32(buf.count), + UInt32(runtimeVersion), uniqueID, uniqueID.count) + else { + fatalError("Failed to allocate metadata") + } + return DIOpaqueType(llvm: ty) + } + } + + /// Create a debugging information entry for an array. + /// + /// - Parameters: + /// - elementType: Metadata describing the type of the elements. + /// - size: The total size of the array. + /// - alignment: The alignment of the array. + /// - subscripts: A list of ranges of valid subscripts into the array. For + /// unbounded arrays, pass the unchecked range `-1...0`. + public func buildArrayType( + of elementType: DIType, + size: Size, alignment: Alignment, + subscripts: [Range] = [] + ) -> DIType { + let radix = UInt32(self.module.dataLayout.intPointerType().width) + var diSubs = subscripts.map { + LLVMDIBuilderGetOrCreateSubrange(self.llvm, + Int64($0.lowerBound), Int64($0.count)) + } + return diSubs.withUnsafeMutableBufferPointer { buf in + guard let ty = LLVMDIBuilderCreateArrayType( + self.llvm, size.rawValue, alignment.rawValue * radix, + elementType.asMetadata(), + buf.baseAddress!, UInt32(buf.count)) + else { + fatalError("Failed to allocate metadata") + } + return DIOpaqueType(llvm: ty) + } + } + + /// Create a debugging information entry for a vector. + /// + /// - Parameters: + /// - elementType: Metadata describing the type of the elements. + /// - size: The total size of the array. + /// - alignment: The alignment of the array. + /// - subscripts: A list of ranges of valid subscripts into the array. For + /// unbounded arrays, pass the unchecked range `-1...0`. + public func buildVectorType( + of elementType: DIType, + size: Size, alignment: Alignment, + subscripts: [Range] = [] + ) -> DIType { + let radix = UInt32(self.module.dataLayout.intPointerType().width) + var diSubs = subscripts.map { + LLVMDIBuilderGetOrCreateSubrange(self.llvm, + Int64($0.lowerBound), Int64($0.count)) + } + return diSubs.withUnsafeMutableBufferPointer { buf in + guard let ty = LLVMDIBuilderCreateVectorType( + self.llvm, size.rawValue, alignment.rawValue * radix, + elementType.asMetadata(), + buf.baseAddress!, UInt32(buf.count)) + else { + fatalError("Failed to allocate metadata") + } + return DIOpaqueType(llvm: ty) + } + } + + /// Create a debugging information entry for a DWARF unspecified type. + /// + /// Some languages have constructs in which a type may be left unspecified or + /// the absence of a type may be explicitly indicated. For example, C++ + /// permits using the `auto` return type specifier for the return type of a + /// member function declaration. The actual return type is deduced based on + /// the definition of the function, so it may not be known when the function + /// is declared. The language implementation can provide an unspecified type + /// entry with the name `auto` which can be referenced by the return type + /// attribute of a function declaration entry. When the function is later + /// defined, the `subprogram` entry for the definition includes a reference to + /// the actual return type. + /// + /// - Parameter name: The name of the type + public func buildUnspecifiedType(named name: String) -> DIType { + guard let ty = LLVMDIBuilderCreateUnspecifiedType( + self.llvm, name, name.count) + else { + fatalError("Failed to allocate metadata") + } + return DIOpaqueType(llvm: ty) + } + + /// Create a debugging information entry for a basic type. + /// + /// - Parameters: + /// - name: Type name. + /// - encoding: The basic type encoding + /// - size: Size of the type. + public func buildBasicType( + named name: String, encoding: DIAttributeTypeEncoding, size: Size + ) -> DIType { + let radix = UInt64(self.module.dataLayout.intPointerType().width) + guard let ty = LLVMDIBuilderCreateBasicType( + self.llvm, name, name.count, + size.valueInBits(radix: radix), encoding.llvm) + else { + fatalError("Failed to allocate metadata") + } + return DIOpaqueType(llvm: ty) + } + + /// Create a debugging information entry for a pointer. + /// + /// - Parameters: + /// - pointee: Type pointed by this pointer. + /// - size: The size of the pointer value. + /// - alignment: The alignment of the pointer. + /// - addressSpace: DWARF address space. + /// - name: The name of the pointer type. + public func buildPointerType( + pointee: DIType, size: Size, alignment: Alignment = .zero, + addressSpace: UInt32 = 0, name: String = "" + ) -> DIType { + let radix = UInt32(self.module.dataLayout.intPointerType().width) + guard let ty = LLVMDIBuilderCreatePointerType( + self.llvm, pointee.asMetadata(), + size.valueInBits(radix: UInt64(radix)), alignment.rawValue * radix, + addressSpace, name, name.count) + else { + fatalError("Failed to allocate metadata") + } + return DIOpaqueType(llvm: ty) + } + + /// Create a debugging information entry for a struct. + /// + /// - Parameters: + /// - name: Struct name. + /// - scope: Scope in which this struct is defined. + /// - file: File where this member is defined. + /// - line: Line number. + /// - size: The total size of the struct and its members. + /// - alignment: The alignment of the struct. + /// - flags: Flags to encode member attributes. + /// - elements: Struct elements. + /// - vtableHolder: The object containing the vtable for the struct. + /// - runtimeVersion: Optional parameter, Objective-C runtime version. + /// - uniqueId: A unique identifier for the struct. + public func buildStructType( + named name: String, + scope: DIScope, file: FileMetadata, line: Int, + size: Size, alignment: Alignment, flags: DIFlags = [], + baseType: DIType? = nil, elements: [DIType] = [], + vtableHolder: DIType? = nil, runtimeVersion: Int = 0, uniqueID: String = "" + ) -> DIType { + let radix = UInt32(self.module.dataLayout.intPointerType().width) + var diEls = elements.map { $0.asMetadata() as Optional } + return diEls.withUnsafeMutableBufferPointer { buf in + guard let ty = LLVMDIBuilderCreateStructType( + self.llvm, scope.asMetadata(), name, name.count, + file.asMetadata(), UInt32(line), + size.valueInBits(radix: UInt64(radix)), alignment.rawValue * radix, + flags.llvm, + baseType?.asMetadata(), + buf.baseAddress!, UInt32(buf.count), UInt32(runtimeVersion), + vtableHolder?.asMetadata(), uniqueID, uniqueID.count) + else { + fatalError("Failed to allocate metadata") + } + return DIOpaqueType(llvm: ty) + } + } + + /// Create a debugging information entry for a member. + /// + /// - Parameters: + /// - parentType: Parent type. + /// - scope: Member scope. + /// - name: Member name. + /// - file: File where this member is defined. + /// - line: Line number. + /// - size: Member size. + /// - alignment: Member alignment. + /// - offset: Member offset. + /// - flags: Flags to encode member attributes. + public func buildMemberType( + of parentType: DIType, scope: DIScope, name: String, + file: FileMetadata, line: Int, + size: Size, alignment: Alignment, offset: Size, flags: DIFlags = [] + ) -> DIType { + let radix = UInt32(self.module.dataLayout.intPointerType().width) + guard let ty = LLVMDIBuilderCreateMemberType( + self.llvm, scope.asMetadata(), name, name.count, file.asMetadata(), + UInt32(line), + size.valueInBits(radix: UInt64(radix)), alignment.rawValue * radix, + offset.rawValue, + flags.llvm, parentType.asMetadata()) + else { + fatalError("Failed to allocate metadata") + } + return DIOpaqueType(llvm: ty) + } + + /// Create a debugging information entry for a C++ static data member. + /// + /// - Parameters: + /// - parentType: Type of the static member. + /// - scope: Member scope. + /// - name: Member name. + /// - file: File where this member is declared. + /// - line: Line number. + /// - alignment: Member alignment. + /// - flags: Flags to encode member attributes. + /// - initialValue: Constant initializer of the member. + public func buildStaticMemberType( + of parentType: DIType, scope: DIScope, name: String, file: FileMetadata, + line: Int, alignment: Alignment, flags: DIFlags = [], + initialValue: IRConstant? = nil + ) -> DIType { + let radix = UInt32(self.module.dataLayout.intPointerType().width) + guard let ty = LLVMDIBuilderCreateStaticMemberType( + self.llvm, scope.asMetadata(), name, name.count, + file.asMetadata(), UInt32(line), + parentType.asMetadata(), flags.llvm, + initialValue?.asLLVM(), alignment.rawValue * radix) + else { + fatalError("Failed to allocate metadata") + } + return DIOpaqueType(llvm: ty) + } + + /// Create a debugging information entry for a pointer to member. + /// + /// - Parameters: + /// - pointee: Type pointed to by this pointer. + /// - baseType: Type for which this pointer points to members of. + /// - size: Size. + /// - alignment: Alignment. + /// - flags: Flags. + public func buildMemberPointerType( + pointee: DIType, baseType: DIType, + size: Size, alignment: Alignment, + flags: DIFlags = [] + ) -> DIType { + let radix = UInt32(self.module.dataLayout.intPointerType().width) + guard let ty = LLVMDIBuilderCreateMemberPointerType( + self.llvm, pointee.asMetadata(), baseType.asMetadata(), + size.valueInBits(radix: UInt64(radix)), alignment.rawValue * radix, + flags.llvm) + else { + fatalError("Failed to allocate metadata") + } + return DIOpaqueType(llvm: ty) + } + + /// Create a uniqued DIType* clone with FlagObjectPointer and + /// FlagArtificial set. + /// + /// - Parameters: + /// - pointee: The underlying type to which this pointer points. + public func buildObjectPointerType(pointee: DIType) -> DIType { + guard let ty = LLVMDIBuilderCreateObjectPointerType( + self.llvm, pointee.asMetadata()) + else { + fatalError("Failed to allocate metadata") + } + return DIOpaqueType(llvm: ty) + } + + /// Create a debugging information entry for a qualified type, e.g. 'const int'. + /// + /// - Parameters: + /// - tag: Tag identifying type. + /// - type: Base Type. + public func buildQualifiedType(_ tag: DWARFTag, _ type: DIType) -> DIType { + guard let ty = LLVMDIBuilderCreateQualifiedType( + self.llvm, tag.rawValue, type.asMetadata()) + else { + fatalError("Failed to allocate metadata") + } + return DIOpaqueType(llvm: ty) + } + + /// Create a debugging information entry for a c++ style reference or rvalue + /// reference type. + /// + /// - Parameters: + /// - tag: Tag identifying type. + /// - type: Base Type. + public func buildReferenceType(_ tag: DWARFTag, _ type: DIType) -> DIType { + guard let ty = LLVMDIBuilderCreateReferenceType( + self.llvm, tag.rawValue, type.asMetadata()) + else { + fatalError("Failed to allocate metadata") + } + return DIOpaqueType(llvm: ty) + } + + /// Create C++11 nullptr type. + public func buildNullPtrType() -> DIType { + guard let ty = LLVMDIBuilderCreateNullPtrType(self.llvm) else { + fatalError("Failed to allocate metadata") + } + return DIOpaqueType(llvm: ty) + } +} + +extension DIBuilder { + /// Create a debugging information entry for a typedef. + /// + /// - Parameters: + /// - type: Original type. + /// - name: Typedef name. + /// - scope: The surrounding context for the typedef. + /// - file: File where this type is defined. + /// - line: Line number. + public func buildTypedef( + of type: DIType, name: String, scope: DIScope, file: FileMetadata, line: Int + ) -> DIType { + guard let ty = LLVMDIBuilderCreateTypedef( + self.llvm, type.asMetadata(), name, name.count, + file.asMetadata(), UInt32(line), scope.asMetadata()) + else { + fatalError("Failed to allocate metadata") + } + return DIOpaqueType(llvm: ty) + } + + /// Create a debugging information entry to establish inheritance relationship + /// between two types. + /// + /// - Parameters: + /// - derived: Original type. + /// - base: Base type. Ty is inherits from base. + /// - baseOffset: Base offset. + /// - virtualBasePointerOffset: Virtual base pointer offset. + /// - flags: Flags to describe inheritance attribute, e.g. private + public func buildInheritance( + of derived: DIType, to base: DIType, + baseOffset: Size, virtualBasePointerOffset: Size, flags: DIFlags = [] + ) -> DIType { + let radix = UInt64(self.module.dataLayout.intPointerType().width) + guard let ty = LLVMDIBuilderCreateInheritance( + self.llvm, derived.asMetadata(), + base.asMetadata(), + baseOffset.valueInBits(radix: radix), + UInt32(virtualBasePointerOffset.valueInBits(radix: radix)), + flags.llvm) + else { + fatalError("Failed to allocate metadata") + } + return DIOpaqueType(llvm: ty) + } + + /// Create a permanent forward-declared type. + /// + /// - Parameters: + /// - name: Type name. + /// - tag: A unique tag for this type. + /// - scope: Type scope. + /// - file: File where this type is defined. + /// - line: Line number where this type is defined. + /// - size: Member size. + /// - alignment: Member alignment. + /// - runtimeLanguage: Indicates runtime version for languages like + /// Objective-C. + /// - uniqueID: A unique identifier for the type. + public func buildForwardDeclaration( + named name: String, tag: DWARFTag, + scope: DIScope, file: FileMetadata, line: Int, + size: Size, alignment: Alignment, + runtimeLanguage: Int = 0, uniqueID: String = "" + ) -> DIType { + let radix = UInt32(self.module.dataLayout.intPointerType().width) + guard let ty = LLVMDIBuilderCreateForwardDecl( + self.llvm, tag.rawValue, name, name.count, + scope.asMetadata(), file.asMetadata(), UInt32(line), + UInt32(runtimeLanguage), + size.valueInBits(radix: UInt64(radix)), alignment.rawValue * radix, + uniqueID, uniqueID.count) else { + fatalError("Failed to allocate metadata") + } + return DIOpaqueType(llvm: ty) + } + + /// Create a temporary forward-declared type. + /// + /// - Parameters: + /// - name: Type name. + /// - tag: A unique tag for this type. + /// - scope: Type scope. + /// - file: File where this type is defined. + /// - line: Line number where this type is defined. + /// Objective-C. + /// - size: Member size. + /// - alignment: Member alignment. + /// - flags: Flags. + /// - runtimeVersion: Indicates runtime version for languages like + /// - uniqueID: A unique identifier for the type. + public func buildReplaceableCompositeType( + named name: String, tag: DWARFTag, + scope: DIScope, file: FileMetadata, line: Int, + size: Size, alignment: Alignment, flags: DIFlags = [], + runtimeVersion: Int = 0, uniqueID: String = "" + ) -> DIType { + let radix = UInt32(self.module.dataLayout.intPointerType().width) + guard let ty = LLVMDIBuilderCreateReplaceableCompositeType( + self.llvm, tag.rawValue, name, name.count, + scope.asMetadata(), file.asMetadata(), UInt32(line), + UInt32(runtimeVersion), + size.valueInBits(radix: UInt64(radix)), alignment.rawValue * radix, + flags.llvm, + uniqueID, uniqueID.count) + else { + fatalError("Failed to allocate metadata") + } + return DIOpaqueType(llvm: ty) + } + + /// Create a debugging information entry for a bit field member. + /// + /// - Parameters: + /// - name: Member name. + /// - type: Parent type. + /// - scope: Member scope. + /// - file: File where this member is defined. + /// - line: Line number. + /// - size: Member size. + /// - offset: Member offset. + /// - storageOffset: Member storage offset. + /// - flags: Flags to encode member attribute. + public func buildBitFieldMemberType( + named name: String, type: DIType, + scope: DIScope, file: FileMetadata, line: Int, + size: Size, offset: Size, storageOffset: Size, + flags: DIFlags = [] + ) -> DIType { + let radix = UInt64(self.module.dataLayout.intPointerType().width) + guard let ty = LLVMDIBuilderCreateBitFieldMemberType( + self.llvm, scope.asMetadata(), name, name.count, + file.asMetadata(), UInt32(line), + size.valueInBits(radix: radix), offset.valueInBits(radix: radix), + storageOffset.valueInBits(radix: radix), + flags.llvm, type.asMetadata()) + else { + fatalError("Failed to allocate metadata") + } + return DIOpaqueType(llvm: ty) + } + + /// Create a debugging information entry for a class. + /// + /// - name: Class name. + /// - baseType: Debug info of the base class of this type. + /// - scope: Scope in which this class is defined. + /// - file: File where this member is defined. + /// - line: Line number. + /// - size: Member size. + /// - alignment: Member alignment. + /// - offset: Member offset. + /// - flags: Flags to encode member attribute, e.g. private. + /// - elements: Class members. + /// - vtableHolder: Debug info of the base class that contains vtable + /// for this type. This is used in `DW_AT_containing_type`. + /// - uniqueID: A unique identifier for the type. + public func buildClassType( + named name: String, derivedFrom baseType: DIType?, + scope: DIScope, file: FileMetadata, line: Int, + size: Size, alignment: Alignment, offset: Size, flags: DIFlags, + elements: [DIType] = [], + vtableHolder: DIType? = nil, uniqueID: String = "" + ) -> DIType { + let radix = UInt32(self.module.dataLayout.intPointerType().width) + var diEls = elements.map { $0.asMetadata() as Optional } + return diEls.withUnsafeMutableBufferPointer { buf in + guard let ty = LLVMDIBuilderCreateClassType( + self.llvm, scope.asMetadata(), name, name.count, + file.asMetadata(), UInt32(line), + size.valueInBits(radix: UInt64(radix)), alignment.rawValue * radix, + offset.rawValue, flags.llvm, + baseType?.asMetadata(), + buf.baseAddress!, UInt32(buf.count), + vtableHolder?.asMetadata(), nil, uniqueID, uniqueID.count) + else { + fatalError("Failed to allocate metadata") + } + return DIOpaqueType(llvm: ty) + } + } + + /// Create a uniqued DIType* clone with FlagArtificial set. + /// + /// - Parameters: + /// - type: The underlying type. + public func buildArtificialType(_ type: DIType) -> DIType { + guard let ty = LLVMDIBuilderCreateArtificialType( + self.llvm, type.asMetadata()) + else { + fatalError("Failed to allocate metadata") + } + return DIOpaqueType(llvm: ty) + } +} + +// MARK: Imported Entities + +extension DIBuilder { + /// Create a descriptor for an imported module. + /// + /// - Parameters: + /// - context: The scope this module is imported into + /// - namespace: The namespace being imported here. + /// - file: File where the declaration is located. + /// - line: Line number of the declaration. + public func buildImportedModule( + in context: DIScope, namespace: NameSpaceMetadata, + file: FileMetadata, line: Int + ) -> ImportedEntityMetadata { + guard let mod = LLVMDIBuilderCreateImportedModuleFromNamespace( + self.llvm, context.asMetadata(), + namespace.asMetadata(), file.asMetadata(), UInt32(line)) + else { + fatalError("Failed to allocate metadata") + } + return ImportedEntityMetadata(llvm: mod) + } + + /// Create a descriptor for an imported module. + /// + /// - Parameters: + /// - context: The scope this module is imported into. + /// - aliasee: An aliased namespace. + /// - file: File where the declaration is located. + /// - line: Line number of the declaration. + public func buildImportedModule( + in context: DIScope, aliasee: ImportedEntityMetadata, + file: FileMetadata, line: Int + ) -> ImportedEntityMetadata { + guard let mod = LLVMDIBuilderCreateImportedModuleFromNamespace( + self.llvm, context.asMetadata(), aliasee.asMetadata(), + file.asMetadata(), UInt32(line)) + else { + fatalError("Failed to allocate metadata") + } + return ImportedEntityMetadata(llvm: mod) + } + + /// Create a descriptor for an imported module. + /// + /// - Parameters: + /// - context: The scope this module is imported into. + /// - module: The module being imported here + /// - file: File where the declaration is located. + /// - line: Line number of the declaration. + public func buildImportedModule( + in context: DIScope, module: ModuleMetadata, file: FileMetadata, line: Int + ) -> ImportedEntityMetadata { + guard let mod = LLVMDIBuilderCreateImportedModuleFromModule( + self.llvm, context.asMetadata(), module.asMetadata(), + file.asMetadata(), UInt32(line)) + else { + fatalError("Failed to allocate metadata") + } + return ImportedEntityMetadata(llvm: mod) + } + + /// Create a descriptor for an imported function. + /// + /// - Parameters: + /// - context: The scope this module is imported into. + /// - declaration: The declaration (or definition) of a function, type, or + /// variable. + /// - file: File where the declaration is located. + /// - line: Line number of the declaration. + /// - name: The name of the imported declaration. + public func buildImportedDeclaration( + in context: DIScope, declaration: Metadata, + file: FileMetadata, line: Int, name: String = "" + ) -> ImportedEntityMetadata { + guard let mod = LLVMDIBuilderCreateImportedDeclaration( + self.llvm, context.asMetadata(), + declaration.asMetadata(), + file.asMetadata(), UInt32(line), name, name.count) + else { + fatalError("Failed to allocate metadata") + } + return ImportedEntityMetadata(llvm: mod) + } +} + +// MARK: Objective-C + +extension DIBuilder { + /// Create a debugging information entry for Objective-C instance variable. + /// + /// - Parameters: + /// - property: The property associated with this ivar. + /// - name: Member name. + /// - type: Type. + /// - file: File where this member is defined. + /// - line: Line number. + /// - size: Member size. + /// - alignment: Member alignment. + /// - offset: Member offset. + /// - flags: Flags to encode member attributes. + public func buildObjCIVar( + for property: ObjectiveCPropertyMetadata, name: String, type: DIType, + file: FileMetadata, line: Int, + size: Size, alignment: Alignment, offset: Size, flags: DIFlags = [] + ) -> DIType { + let radix = UInt32(self.module.dataLayout.intPointerType().width) + guard let ty = LLVMDIBuilderCreateObjCIVar( + self.llvm, name, name.count, file.asMetadata(), UInt32(line), + size.valueInBits(radix: UInt64(radix)), alignment.rawValue * radix, + offset.rawValue, flags.llvm, type.asMetadata(), property.asMetadata()) + else { + fatalError("Failed to allocate metadata") + } + return DIOpaqueType(llvm: ty) + } + + /// Create a debugging information entry for Objective-C property. + /// + /// - Parameters: + /// - name: Property name. + /// - type: Type. + /// - file: File where this property is defined. + /// - line: Line number. + /// - getter: Name of the Objective C property getter selector. + /// - setter: Name of the Objective C property setter selector. + /// - propertyAttributes: Objective C property attributes. + public func buildObjCProperty( + named name: String, type: DIType, + file: FileMetadata, line: Int, + getter: String, setter: String, + propertyAttributes: ObjectiveCPropertyAttribute + ) -> ObjectiveCPropertyMetadata { + guard let ty = LLVMDIBuilderCreateObjCProperty( + self.llvm, name, name.count, file.asMetadata(), UInt32(line), + getter, getter.count, setter, setter.count, + propertyAttributes.rawValue, type.asMetadata()) + else { + fatalError("Failed to allocate metadata") + } + return ObjectiveCPropertyMetadata(llvm: ty) } } diff --git a/Sources/LLVM/Function.swift b/Sources/LLVM/Function.swift index 2dce2612..1356c42a 100644 --- a/Sources/LLVM/Function.swift +++ b/Sources/LLVM/Function.swift @@ -11,6 +11,14 @@ public class Function: IRGlobal { self.llvm = llvm } + /// Accesses the metadata associated with this function. + /// + /// To build new function metadata, see `DIBuilder.buildFunction`. + public var metadata: FunctionMetadata { + get { return FunctionMetadata(llvm: LLVMGetSubprogram(self.llvm)) } + set { LLVMSetSubprogram(self.llvm, newValue.asMetadata()) } + } + /// Accesses the calling convention for this function. public var callingConvention: CallingConvention { get { return CallingConvention(llvm: LLVMCallConv(rawValue: LLVMGetFunctionCallConv(llvm))) } diff --git a/Sources/LLVM/IRBuilder.swift b/Sources/LLVM/IRBuilder.swift index 21962593..5d4a5b49 100644 --- a/Sources/LLVM/IRBuilder.swift +++ b/Sources/LLVM/IRBuilder.swift @@ -84,6 +84,16 @@ extension IRBuilder { } } +// MARK: Debug Information + +extension IRBuilder { + /// Access location information used by debugging information. + public var currentDebugLocation: DebugLocation { + get { return DebugLocation(llvm: LLVMValueAsMetadata(LLVMGetCurrentDebugLocation(self.llvm))) } + set { LLVMSetCurrentDebugLocation(self.llvm, LLVMMetadataAsValue(self.module.context.llvm, newValue.asMetadata())) } + } +} + // MARK: Convenience Instructions extension IRBuilder { diff --git a/Sources/LLVM/Metadata.swift b/Sources/LLVM/Metadata.swift index ef302948..34f9e448 100644 --- a/Sources/LLVM/Metadata.swift +++ b/Sources/LLVM/Metadata.swift @@ -2,10 +2,134 @@ import cllvm #endif -public protocol Metadata { +public protocol _IRMetadataInitializerHack { + init(llvm: LLVMMetadataRef) +} + +/// The `Metadata` protocol captures those types that represent metadata nodes +/// in LLVM IR. +/// +/// LLVM IR allows metadata to be attached to instructions in the program that +/// can convey extra information about the code to the optimizers and code +/// generator. One example application of metadata is source-level debug +/// information. +/// +/// Metadata does not have a type, and is not a value. If referenced from a call +/// instruction, it uses the metadata type. +/// +/// The idea of LLVM debugging information is to capture how the important +/// pieces of the source-language’s Abstract Syntax Tree map onto LLVM code. +/// LLVM takes a number of positions on the impact of the broader compilation +/// process on debug information: +/// +/// - Debugging information should have very little impact on the rest of the +/// compiler. No transformations, analyses, or code generators should need to +/// be modified because of debugging information. +/// - LLVM optimizations should interact in well-defined and easily described +/// ways with the debugging information. +/// - Because LLVM is designed to support arbitrary programming languages, +/// LLVM-to-LLVM tools should not need to know anything about the semantics +/// of the source-level-language. +/// - Source-level languages are often widely different from one another. LLVM +/// should not put any restrictions of the flavor of the source-language, and +/// the debugging information should work with any language. +/// - With code generator support, it should be possible to use an LLVM compiler +/// to compile a program to native machine code and standard debugging +/// formats. This allows compatibility with traditional machine-code level +/// debuggers, like GDB, DBX, or CodeView. +public protocol Metadata: _IRMetadataInitializerHack { func asMetadata() -> LLVMMetadataRef } +extension Metadata { + /// Replaces all uses of the this metadata with the given metadata. + /// + /// - parameter metadata: The new value to swap in. + public func replaceAllUses(with metadata: Metadata) { + LLVMMetadataReplaceAllUsesWith(self.asMetadata(), metadata.asMetadata()) + } +} + +extension Metadata { + /// Dumps a representation of this metadata to stderr. + public func dump() { + LLVMDumpValue(LLVMMetadataAsValue(LLVMGetGlobalContext(), self.asMetadata())) + } + + public func forceCast(to: DestTy.Type) -> DestTy { + return DestTy(llvm: self.asMetadata()) + } +} + +/// Denotes a scope in which child metadata nodes can be inserted. +public protocol DIScope: Metadata {} + +/// Denotes metadata for a type. +public protocol DIType: DIScope {} + +extension DIType { + /// Retrieves the name of this type. + public var name: String { + var length: Int = 0 + let cstring = LLVMDITypeGetName(self.asMetadata(), &length) + return String(cString: cstring!) + } + + /// Retrieves the size of the type represented by this metadata in bits. + public var sizeInBits: Size { + return Size(LLVMDITypeGetSizeInBits(self.asMetadata())) + } + + /// Retrieves the offset of the type represented by this metadata in bits. + public var offsetInBits: Size { + return Size(LLVMDITypeGetOffsetInBits(self.asMetadata())) + } + + /// Retrieves the alignment of the type represented by this metadata in bits. + public var alignmentInBits: Alignment { + return Alignment(LLVMDITypeGetAlignInBits(self.asMetadata())) + } + + /// Retrieves the line the type represented by this metadata is declared on. + public var line: Int { + return Int(LLVMDITypeGetLine(self.asMetadata())) + } + + /// Retrieves the flags the type represented by this metadata is declared + /// with. + public var flags: DIFlags { + return DIFlags(rawValue: LLVMDITypeGetFlags(self.asMetadata()).rawValue) + } +} + +/// A `DebugLocation` represents a location in source. +public struct DebugLocation: Metadata { + internal let llvm: LLVMMetadataRef + + public func asMetadata() -> LLVMMetadataRef { + return llvm + } + + /// Retrieves the line described by this location. + public var line: Int { + return Int(LLVMDILocationGetLine(self.llvm)) + } + + /// Retrieves the column described by this location. + public var column: Int { + return Int(LLVMDILocationGetColumn(self.llvm)) + } + + /// Retrieves the enclosing scope containing this location. + public var scope: DIScope { + return DIOpaqueType(llvm: LLVMDILocationGetScope(self.llvm)) + } + + public init(llvm: LLVMMetadataRef) { + self.llvm = llvm + } +} + struct AnyMetadata: Metadata { let llvm: LLVMMetadataRef @@ -14,59 +138,200 @@ struct AnyMetadata: Metadata { } } -public struct VariableMetadata: Metadata { +struct DIOpaqueType: DIType { + internal let llvm: LLVMMetadataRef + + public func asMetadata() -> LLVMMetadataRef { + return llvm + } + + public init(llvm: LLVMMetadataRef) { + self.llvm = llvm + } +} + +/// `CompileUnitMetadata` nodes represent a compile unit, the root of a metadata +/// hierarchy for a translation unit. +/// +/// Compile unit descriptors provide the root scope for objects declared in a +/// specific compilation unit. `FileMetadata` descriptors are defined using this +/// scope. +/// +/// These descriptors are collected by a named metadata node `!llvm.dbg.cu`. +/// They keep track of global variables, type information, and imported entities +/// (declarations and namespaces). +public struct CompileUnitMetadata: DIScope { + internal let llvm: LLVMMetadataRef + + public func asMetadata() -> LLVMMetadataRef { + return llvm + } + + public init(llvm: LLVMMetadataRef) { + self.llvm = llvm + } +} + + +/// `FileMetadata` nodes represent files. +/// +/// The file name does not necessarily have to be a proper file path. For +/// example, it can include additional slash-separated path components. +public struct FileMetadata: DIScope { internal let llvm: LLVMMetadataRef public func asMetadata() -> LLVMMetadataRef { return llvm } + + public init(llvm: LLVMMetadataRef) { + self.llvm = llvm + } } -public struct FileMetadata: Metadata { +/// `DIBasicType` nodes represent primitive types, such as `int`, `bool` and +/// `float`. +/// +/// Basic types carry an encoding describing the details of the type to +/// influence how it is presented in debuggers. LLVM currently supports +/// specific DWARF "Attribute Type Encodings" that are enumerated in +/// `DIAttributeTypeEncoding`. +public struct DIBasicType: DIType { internal let llvm: LLVMMetadataRef public func asMetadata() -> LLVMMetadataRef { return llvm } + + public init(llvm: LLVMMetadataRef) { + self.llvm = llvm + } } -public struct Scope: Metadata { +/// `DISubroutineType` nodes represent subroutine types. +/// +/// Subroutine types are meant to mirror their formal declarations in source: +/// arguments are represented in order. The return type is optional and meant +/// to represent the concept of `void` in C-like languages. +public struct DISubroutineType: DIType { internal let llvm: LLVMMetadataRef public func asMetadata() -> LLVMMetadataRef { return llvm } + + public init(llvm: LLVMMetadataRef) { + self.llvm = llvm + } } -public struct Macro: Metadata { +/// `LexicalBlockMetadata` nodes describe nested blocks within a subprogram. The +/// line number and column numbers are used to distinguish two lexical blocks at +/// same depth. +/// +/// Usually lexical blocks are distinct to prevent node merging based on +/// operands. +public struct LexicalBlockMetadata: DIScope { internal let llvm: LLVMMetadataRef public func asMetadata() -> LLVMMetadataRef { return llvm } + + public init(llvm: LLVMMetadataRef) { + self.llvm = llvm + } } -public struct DIModule: Metadata { +/// `LexicalBlockFile` nodes are used to discriminate between sections of a +/// lexical block. The file field can be changed to indicate textual inclusion, +/// or the discriminator field can be used to discriminate between control flow +/// within a single block in the source language. +public struct LexicalBlockFileMetadata: DIScope { internal let llvm: LLVMMetadataRef public func asMetadata() -> LLVMMetadataRef { return llvm } + + public init(llvm: LLVMMetadataRef) { + self.llvm = llvm + } } -public struct DIExpression: Metadata { +/// `LocalVariableMetadata` nodes represent local variables and function +/// parameters in the source language. +public struct LocalVariableMetadata: Metadata { internal let llvm: LLVMMetadataRef public func asMetadata() -> LLVMMetadataRef { return llvm } + + public init(llvm: LLVMMetadataRef) { + self.llvm = llvm + } } +/// `ObjectiveCPropertyMetadata` nodes represent Objective-C property nodes. +public struct ObjectiveCPropertyMetadata: Metadata { + internal let llvm: LLVMMetadataRef -public struct DebugLocation: Metadata { + public func asMetadata() -> LLVMMetadataRef { + return llvm + } + + public init(llvm: LLVMMetadataRef) { + self.llvm = llvm + } +} + +/// `ImportedEntityMetadata` nodes represent entities (such as modules) imported +/// into a compile unit. +public struct ImportedEntityMetadata: DIType { internal let llvm: LLVMMetadataRef public func asMetadata() -> LLVMMetadataRef { return llvm } + + public init(llvm: LLVMMetadataRef) { + self.llvm = llvm + } +} + +public struct FunctionMetadata: DIScope { + internal let llvm: LLVMMetadataRef + + public func asMetadata() -> LLVMMetadataRef { + return llvm + } + + public init(llvm: LLVMMetadataRef) { + self.llvm = llvm + } +} + +public struct ModuleMetadata: DIScope { + internal let llvm: LLVMMetadataRef + + public func asMetadata() -> LLVMMetadataRef { + return llvm + } + + public init(llvm: LLVMMetadataRef) { + self.llvm = llvm + } +} + +public struct NameSpaceMetadata: DIScope { + internal let llvm: LLVMMetadataRef + + public func asMetadata() -> LLVMMetadataRef { + return llvm + } + + public init(llvm: LLVMMetadataRef) { + self.llvm = llvm + } } diff --git a/Sources/LLVM/MetadataAttributes.swift b/Sources/LLVM/MetadataAttributes.swift new file mode 100644 index 00000000..55a03b54 --- /dev/null +++ b/Sources/LLVM/MetadataAttributes.swift @@ -0,0 +1,541 @@ +#if SWIFT_PACKAGE +import cllvm +#endif + +/// Source languages known to DWARF. +public enum DWARFSourceLanguage { + /// ISO Ada:1983 + case ada83 + /// ISO Ada:1995 + case ada95 + /// BLISS + case bliss + /// Non-standardized C, e.g. K&R C. + case c + /// ISO C:1989. + case c89 + /// ISO C:1999. + case c99 + /// ISO C:2011 + case c11 + /// ISO C++90 + case cPlusPlus + /// ISO C++03 + case cPlusPlus03 + /// ISO C++11 + case cPlusPlus11 + /// ISO C++14 + case cPlusPlus14 + /// ISO COBOL:1974 + case cobol74 + /// ISO COBOL:1985 + case cobol85 + /// C + case d + /// Dylan + case dylan + /// ISO FORTRAN:1977 + case fortran77 + /// ISO Fortran:1990 + case fortran90 + /// ISO Fortran:1995 + case fortran95 + /// ISO Fortran:2004 + case fortran03 + /// ISO Fortran:2010 + case fortran08 + /// Go + case go + /// Haskell + case haskell + /// Java + case java + /// Julia + case julia + /// ISO Modula-2:1996 + case modula2 + /// Module-3 + case modula3 + /// Objective-C + case objectiveC + /// Objective-C++ + case objectiveCPlusPlus + /// OCaml + case ocaml + /// OpenCL + case openCL + /// ISO Pascal:1983 + case pascal83 + /// ANSI PL/I:1976 + case pli + /// Python + case python + /// RenderScript Kernel Language + case renderScript + /// Rust + case rust + /// Swift + case swift + /// Unified Parallel C + case upc + + // MARK: Vendor Extensions + + /// MIPS Assembler + case mipsAssembler + /// Google RenderScript Kernel Language + case googleRenderScript + /// Borland Delphi + case borlandDelphi + + + private static let languageMapping: [DWARFSourceLanguage: LLVMDWARFSourceLanguage] = [ + .c: LLVMDWARFSourceLanguageC, .c89: LLVMDWARFSourceLanguageC89, + .c99: LLVMDWARFSourceLanguageC99, .c11: LLVMDWARFSourceLanguageC11, + .ada83: LLVMDWARFSourceLanguageAda83, + .cPlusPlus: LLVMDWARFSourceLanguageC_plus_plus, + .cPlusPlus03: LLVMDWARFSourceLanguageC_plus_plus_03, + .cPlusPlus11: LLVMDWARFSourceLanguageC_plus_plus_11, + .cPlusPlus14: LLVMDWARFSourceLanguageC_plus_plus_14, + .cobol74: LLVMDWARFSourceLanguageCobol74, + .cobol85: LLVMDWARFSourceLanguageCobol85, + .fortran77: LLVMDWARFSourceLanguageFortran77, + .fortran90: LLVMDWARFSourceLanguageFortran90, + .pascal83: LLVMDWARFSourceLanguagePascal83, + .modula2: LLVMDWARFSourceLanguageModula2, + .java: LLVMDWARFSourceLanguageJava, + .ada95: LLVMDWARFSourceLanguageAda95, + .fortran95: LLVMDWARFSourceLanguageFortran95, + .pli: LLVMDWARFSourceLanguagePLI, + .objectiveC: LLVMDWARFSourceLanguageObjC, + .objectiveCPlusPlus: LLVMDWARFSourceLanguageObjC_plus_plus, + .upc: LLVMDWARFSourceLanguageUPC, + .d: LLVMDWARFSourceLanguageD, + .python: LLVMDWARFSourceLanguagePython, + .openCL: LLVMDWARFSourceLanguageOpenCL, + .go: LLVMDWARFSourceLanguageGo, + .modula3: LLVMDWARFSourceLanguageModula3, + .haskell: LLVMDWARFSourceLanguageHaskell, + .ocaml: LLVMDWARFSourceLanguageOCaml, + .rust: LLVMDWARFSourceLanguageRust, + .swift: LLVMDWARFSourceLanguageSwift, + .julia: LLVMDWARFSourceLanguageJulia, + .dylan: LLVMDWARFSourceLanguageDylan, + .fortran03: LLVMDWARFSourceLanguageFortran03, + .fortran08: LLVMDWARFSourceLanguageFortran08, + .renderScript: LLVMDWARFSourceLanguageRenderScript, + .bliss: LLVMDWARFSourceLanguageBLISS, + .mipsAssembler: LLVMDWARFSourceLanguageMips_Assembler, + .googleRenderScript: LLVMDWARFSourceLanguageGOOGLE_RenderScript, + .borlandDelphi: LLVMDWARFSourceLanguageBORLAND_Delphi, + ] + + /// Retrieves the corresponding `LLVMDWARFSourceLanguage`. + internal var llvm: LLVMDWARFSourceLanguage { + return DWARFSourceLanguage.languageMapping[self]! + } +} + +/// Enumerates the supported identifying tags for corresponding DWARF +/// Debugging Information Entries (DIEs) known to LLVM. +public enum DWARFTag: UInt32 { + /// Identifies metadata for an array type. + case arrayType = 0x0001 + /// Identifies metadata for a class type. + case classType = 0x0002 + /// Identifies metadata for an alternate entry point. + case entryPoint = 0x0003 + /// Identifies metadata for an enumeration type. + case enumerationType = 0x0004 + /// Identifies metadata for a formal parameter of a parameter list. + case formalParameter = 0x0005 + /// Identifies metadata for an imported declaration. + case importedDeclaration = 0x0008 + /// Identifies metadata for a label in the source; the + /// target of one or more `go to` statements. + case label = 0x000a + /// Identifies metadata for a lexical block in the source (usually for + /// C-like languages). + case lexicalBlock = 0x000b + /// Identifies metadata for a data member. + case member = 0x000d + /// Identifies metadata for a pointer type. + case pointerType = 0x000f + /// Identifies metadata for a reference type + case referenceType = 0x0010 + /// Identifies metadata for a complete compilation unit. + case compileUnit = 0x0011 + /// Identifies metadata for a string type. + case stringType = 0x0012 + /// Identifies metadata for a structure type. + case structureType = 0x0013 + /// Identifies metadata for a subroutine type. + case subroutineType = 0x0015 + /// Identifies metadata for a typedef declaration. + case typedef = 0x0016 + /// Identifies metadata for a union type. + case unionType = 0x0017 + /// Identifies metadata for an unspecified parameter list. Can also be used + /// to identify vararg parameter lists. + case unspecifiedParameters = 0x0018 + /// Identifies metadata for a variant record. + case variant = 0x0019 + /// Identifies metadata for a Fortran common block. + case commonBlock = 0x001a + /// Identifies metadata for a Fortran common inclusion. + case commonInclusion = 0x001b + /// Identifies metadata for an inheritance clause. + case inheritance = 0x001c + /// Identifies metadata for an inlined subroutine. + case inlinedSubroutine = 0x001d + /// Identifies metadata for a module. + case module = 0x001e + /// Identifies metadata for a pointer to a data member. + case ptrToMemberType = 0x001f + /// Identifies metadata for a set type. + case setType = 0x0020 + /// Identifies metadata for a subrange type describing the + /// dimensions of an array. + case subrangeType = 0x0021 + /// Identifies metadata for Pascal and Modula-2's `with` statements. + case withStmt = 0x0022 + /// Identifies metadata for an access declaration. + case accessDeclaration = 0x0023 + /// Identifies metadata for a a base type: a type that is not defined in terms + /// of metadata for other data types. + case baseType = 0x0024 + /// Identifies metadata for the catch block in a `try-catch` statement. + case catchBlock = 0x0025 + /// Identifies metadata for a constant type. + case constType = 0x0026 + /// Identifies metadata for a constant. + case constant = 0x0027 + /// Identifies metadata for an enumerator. + case enumerator = 0x0028 + /// Identifies metadata for a file. + case fileType = 0x0029 + /// Identifies metadata for a C++ `friend` declaration. + case friend = 0x002a + /// Identifies metadata for a Fortran 90 namelist. + case namelist = 0x002b + /// Identifies metadata for an item in a Fortran 90 namelist. + case namelistItem = 0x002c + /// Identifies metadata for an Ada or Pascal packed type. + case packedType = 0x002d + /// Identifies metadata for a subprogram. + case subprogram = 0x002e + /// Identifies metadata for a template type parameter. + case templateTypeParameter = 0x002f + /// Identifies metadata for a template value parameter. + case templateValueParameter = 0x0030 + /// Identifies metadata for the thrown type from a subroutine. + case thrownType = 0x0031 + /// Identifies metadata for the try block in a `try-catch` statement. + case tryBlock = 0x0032 + /// Identifies metadata for a part of a variant record. + case variantPart = 0x0033 + /// Identifies metadata for a variable. + case variable = 0x0034 + /// Identifies metadata for a volatile-qualified type. + case volatileType = 0x0035 + + // MARK: New in DWARF v3 + + /// Identifies metadata for a DWARF procedure. + case dwarfProcedure = 0x0036 + /// Identifies metadata for a restrict-qualified type. + case restrictType = 0x0037 + /// Identifies metadata for a Java interface type. + case interfaceType = 0x0038 + /// Identifies metadata for a namespace. + case namespace = 0x0039 + /// Identifies metadata for an imported module. + case importedModule = 0x003a + /// Identifies metadata for an unspecified type. + case unspecifiedType = 0x003b + /// Identifies metadata for a portion of an object file. + case partialUnit = 0x003c + /// Identifies metadata for an imported compilation unit. + case importedUnit = 0x003d + /// Identifies metadata for a COBOL "level-88" condition that associates a + /// data item, called the conditional variable, with a set of one or more + /// constant values and/or value ranges. + case condition = 0x003f + /// Identifies metadata for a UPC shared-qualified type. + case sharedType = 0x0040 + + // MARK: New in DWARF v4 + + /// Identifies metadata for a single type. + case typeUnit = 0x0041 + /// Identifies metadata for an rvalue-reference-qualified type. + case rvalueReferenceType = 0x0042 + /// Identifies metadata for a template alias. + case templateAlias = 0x0043 + + // MARK: New in DWARF v5 + + /// Identifies metadata for a Fortran "coarray" - an array whose elements + /// are located in different processes rather than in the memory of one + /// process. + case coarrayType = 0x0044 + /// Identifies metadata for a generic subrange. This is useful for arrays of + /// dynamic size in C and Fortran. + case genericSubrange = 0x0045 + /// Identifies metadata for a dynamic type. + case dynamicType = 0x0046 + /// Identifies metadata for an atomic type. + case atomicType = 0x0047 + /// Identifies metadata for a call site. + case callSite = 0x0048 + /// Identifies metadata for a parameter at a call site. + case callSiteParameter = 0x0049 + /// Identifies metadata for the "skeleton" compilation unit in a split DWARF + /// object file. + case skeletonUnit = 0x004a + /// Identifies metadata for an immutable type. + case immutableType = 0x004b + + // MARK: Vendor extensions + + /// Identifies metadata for a MIPS loop. + case mipsLoop = 0x4081 + /// Identifies metadata for a format label. + case formatLabel = 0x4101 + /// Identifies metadata for a function template. + case functionTemplate = 0x4102 + /// Identifies metadata for a class template. + case classTemplate = 0x4103 + /// Identifies metadata for a template template parameter. + case gnuTemplateTemplateParam = 0x4106 + /// Identifies metadata for a template parameter pack. + case gnuTemplateParameterPack = 0x4107 + /// Identifies metadata for a formal parameter pack. + case gnuFormalParameterPack = 0x4108 + /// Identifies metadata for a call site. + case gnuCallSite = 0x4109 + /// Identifies metadata for a call site parameter. + case gnuCallSiteParameter = 0x410a + /// Identifies metadata for an Objective-C property. + case applyProperty = 0x4200 + /// Identifies metadata for an Borland Delphi property. + case borlandProperty = 0xb000 + /// Identifies metadata for an Borland Delphi property. + case borlandDelphiString = 0xb001 + /// Identifies metadata for an Borland Delphi dynamic array. + case borlandDelphiDynamicArray = 0xb002 + /// Identifies metadata for an Borland Delphi set. + case borlandDelphiSet = 0xb003 + /// Identifies metadata for an Borland Delphi variant. + case borlandDelphiVariant = 0xb004 +} + +/// Enumerates the known attributes that can appear on an Objective-C property. +public struct ObjectiveCPropertyAttribute : OptionSet { + public let rawValue: UInt32 + + public init(rawValue: UInt32) { + self.rawValue = rawValue + } + + /// Indicates a property has `readonly` access. + public static let readonly = ObjectiveCPropertyAttribute(rawValue: 0x01) + /// Indicates a property has a customized getter name. + public static let getter = ObjectiveCPropertyAttribute(rawValue: 0x02) + /// Indicates a property has `assign` ownership. + public static let assign = ObjectiveCPropertyAttribute(rawValue: 0x04) + /// Indicates a property has `readwrite` access. + public static let readwrite = ObjectiveCPropertyAttribute(rawValue: 0x08) + /// Indicates a property has `retain` ownership. + public static let retain = ObjectiveCPropertyAttribute(rawValue: 0x10) + /// Indicates a property has `copy` ownership. + public static let copy = ObjectiveCPropertyAttribute(rawValue: 0x20) + /// Indicates a property has `nonatomic` accessors. + public static let nonatomic = ObjectiveCPropertyAttribute(rawValue: 0x40) + /// Indicates a property has a customized setter name. + public static let setter = ObjectiveCPropertyAttribute(rawValue: 0x80) + /// Indicates a property has `atomic` accessors. + public static let atomic = ObjectiveCPropertyAttribute(rawValue: 0x100) + /// Indicates a property has `weak` ownership. + public static let weak = ObjectiveCPropertyAttribute(rawValue: 0x200) + /// Indicates a property has `strong` ownership. + public static let strong = ObjectiveCPropertyAttribute(rawValue: 0x400) + /// Indicates a property has `unsafe_unretained` ownership. + public static let unsafeUnretained = ObjectiveCPropertyAttribute(rawValue: 0x800) + /// Indicates a property has an explicit nullability annotation. + public static let nullability = ObjectiveCPropertyAttribute(rawValue: 0x1000) + /// Indicates a property is null_resettable. + public static let nullResettable = ObjectiveCPropertyAttribute(rawValue: 0x2000) + /// Indicates a property is a `class` property. + public static let `class` = ObjectiveCPropertyAttribute(rawValue: 0x4000) +} + +/// Describes how a base type is encoded and to be interpreted by a debugger. +public enum DIAttributeTypeEncoding { + /// A linear machine address. + case address + /// A true or false value. + case boolean + /// A complex binary floating-point number. + case complexFloat + /// A binary floating-point number. + case float + /// A signed binary integer. + case signed + /// A signed character. + case signedChar + /// An unsigned binary integer. + case unsigned + /// An unsigned character. + case unsignedChar + /// An imaginary binary floating-point number. + case imaginaryFloat + /// A packed decimal number. + case packedDecimal + /// A numeric string. + case numericString + /// An edited string. + case edited + /// A signed fixed-point scaled integer. + case signedFixed + /// An unsigned fixed-point scaled integer. + case unsignedFixed + /// An IEEE-754R decimal floating-point number. + case decimalFloat + /// An ISO/IEC 10646-1:1993 character. + case utf + /// An ISO/IEC 10646-1:1993 character in UCS-4 format. + case ucs + /// An ISO/IEC 646:1991 character. + case ascii + + private static let encodingMapping: [DIAttributeTypeEncoding: LLVMDWARFTypeEncoding] = [ + .address: 0x01, + .boolean: 0x02, + .complexFloat: 0x03, + .float: 0x04, + .signed: 0x05, + .signedChar: 0x06, + .unsigned: 0x07, + .unsignedChar: 0x08, + .imaginaryFloat: 0x09, + .packedDecimal: 0x0a, + .numericString: 0x0b, + .edited: 0x0c, + .signedFixed: 0x0d, + .unsignedFixed: 0x0e, + .decimalFloat: 0x0f, + .utf: 0x10, + .ucs: 0x11, + .ascii: 0x12, + ] + + internal var llvm: LLVMDWARFTypeEncoding { + return DIAttributeTypeEncoding.encodingMapping[self]! + } +} + +public struct DIFlags : OptionSet { + public let rawValue: LLVMDIFlags.RawValue + + public init(rawValue: LLVMDIFlags.RawValue) { + self.rawValue = rawValue + } + + /// Denotes the `private` visibility attribute. + public static let `private` = DIFlags(rawValue: LLVMDIFlagPrivate.rawValue) + /// Denotes the `protected` visibility attribute. + public static let protected = DIFlags(rawValue: LLVMDIFlagProtected.rawValue) + /// Denotes the `public` visibility attribute. + public static let `public` = DIFlags(rawValue: LLVMDIFlagPublic.rawValue) + /// Denotes a forward declaration. + public static let forwardDeclaration = DIFlags(rawValue: LLVMDIFlagFwdDecl.rawValue) + /// Denotes a block object. + public static let appleBlock = DIFlags(rawValue: LLVMDIFlagAppleBlock.rawValue) + /// Denotes the structure containing a variable captured by reference in a + /// block object. + public static let blockByrefStruct = DIFlags(rawValue: LLVMDIFlagBlockByrefStruct.rawValue) + /// Denotes a virtual function or dynamic dispatch. + public static let virtual = DIFlags(rawValue: LLVMDIFlagVirtual.rawValue) + /// Denotes a compiler-generated declaration that may not appear in source. + public static let artificial = DIFlags(rawValue: LLVMDIFlagArtificial.rawValue) + /// Denotes an `explicit`-annotated declaration. + public static let explicit = DIFlags(rawValue: LLVMDIFlagExplicit.rawValue) + /// Denotes a prototype declaration. + public static let prototyped = DIFlags(rawValue: LLVMDIFlagPrototyped.rawValue) + /// Denotes an Objective-C class whose definition is visible to the compiler. + public static let objectiveCClassComplete = DIFlags(rawValue: LLVMDIFlagObjcClassComplete.rawValue) + /// Denotes a pointer value that is known to point to a C++ or Objective-C + /// object - usually `self` or `this`. + public static let objectPointer = DIFlags(rawValue: LLVMDIFlagObjectPointer.rawValue) + /// Denotes a vector type. + public static let vector = DIFlags(rawValue: LLVMDIFlagVector.rawValue) + /// Denotes a static member. + public static let staticMember = DIFlags(rawValue: LLVMDIFlagStaticMember.rawValue) + /// Denotes an lvalue reference. + public static let lValueReference = DIFlags(rawValue: LLVMDIFlagLValueReference.rawValue) + /// Denotes an rvalue reference. + public static let rValueReference = DIFlags(rawValue: LLVMDIFlagRValueReference.rawValue) + /// Denotes a class type that is part of a single inheritance class hierarchy. + /// This flag is required to be set for CodeView compatibility. + public static let singleInheritance = DIFlags(rawValue: LLVMDIFlagSingleInheritance.rawValue) + /// Denotes a class type that is part of a multiple inheritance class + /// hierarchy. This flag is required to be set for CodeView compatibility. + public static let multipleInheritance = DIFlags(rawValue: LLVMDIFlagMultipleInheritance.rawValue) + /// Denotes a class type whose inheritance involves virtual members. This + /// flag is required to be set for CodeView compatibility. + public static let virtualInheritance = DIFlags(rawValue: LLVMDIFlagVirtualInheritance.rawValue) + /// Denotes a class type that introduces virtual members. This is needed for + /// the MS C++ ABI does not include all virtual methods from non-primary bases + /// in the vtable for the most derived class + public static let introducedVirtual = DIFlags(rawValue: LLVMDIFlagIntroducedVirtual.rawValue) + /// Denotes a bitfield type. + public static let bitField = DIFlags(rawValue: LLVMDIFlagBitField.rawValue) + /// Denotes a `noreturn` function. + public static let noReturn = DIFlags(rawValue: LLVMDIFlagNoReturn.rawValue) + /// Denotes the subprogram for main. + public static let mainSubprogram = DIFlags(rawValue: LLVMDIFlagMainSubprogram.rawValue) + /// Denotes a parameter that is passed by value according to the target's + /// calling convention. + public static let passByValue = DIFlags(rawValue: LLVMDIFlagTypePassByValue.rawValue) + /// Denotes a parameter that is passed by indirect reference according to the + /// target's calling convention. + public static let passByReference = DIFlags(rawValue: LLVMDIFlagTypePassByReference.rawValue) + /// Denotes a "fixed enum" type e.g. a C++ `enum class`. + public static let fixedEnum = DIFlags(rawValue: LLVMDIFlagFixedEnum.rawValue) + /// Denotes a thunk function. + public static let thunk = DIFlags(rawValue: LLVMDIFlagThunk.rawValue) + /// Denotes a class that has a trivial default constructor and is trivially + /// copiable. + public static let trivial = DIFlags(rawValue: LLVMDIFlagTrivial.rawValue) + /// Denotes an indirect virtual base class. + public static let indirectVirtualBase = DIFlags(rawValue: LLVMDIFlagIndirectVirtualBase.rawValue) + /// The mask for `public`, `private`, and `protected` accessibility. + public static let accessibility = DIFlags(rawValue: LLVMDIFlagAccessibility.rawValue) + /// The mask for `singleInheritance`, `multipleInheritance`, + /// and `virtualInheritance`. + public static let pointerToMemberRep = DIFlags(rawValue: LLVMDIFlagPtrToMemberRep.rawValue) + + internal var llvm: LLVMDIFlags { + return LLVMDIFlags(self.rawValue) + } +} + +/// The amount of debug information to emit. +public enum DWARFEmissionKind { + /// No debug information should be emitted. + case none + /// Full debug information should be emitted. + case full + /// Onle line tables should be emitted. + case lineTablesOnly + + private static let emissionMapping: [DWARFEmissionKind: LLVMDWARFEmissionKind] = [ + .none: LLVMDWARFEmissionNone, .full: LLVMDWARFEmissionFull, + .lineTablesOnly: LLVMDWARFEmissionLineTablesOnly, + ] + + internal var llvm: LLVMDWARFEmissionKind { + return DWARFEmissionKind.emissionMapping[self]! + } +} diff --git a/Sources/LLVM/Module.swift b/Sources/LLVM/Module.swift index eb9c65e9..cdea1aa0 100644 --- a/Sources/LLVM/Module.swift +++ b/Sources/LLVM/Module.swift @@ -78,7 +78,6 @@ public final class Module: CustomStringConvertible { llvm = LLVMModuleCreateWithName(name) self.context = Context(llvm: LLVMGetModuleContext(llvm)!) } - self.dataLayout = TargetData(llvm: LLVMGetModuleDataLayout(llvm)) } /// Obtain the target triple for this module. @@ -319,6 +318,18 @@ extension Module { return Comdat(llvm: comdat) } + /// Searches for and retrieves module-level named metadata with the given name + /// in this module. If none is found, one with that name is created and + /// returned. + /// + /// - parameter name: The name of the comdat section to create. + /// + /// - returns: A representation of the newly created metadata with the + /// given name. + public func metadata(named name: String) -> NamedMetadata { + return NamedMetadata(module: self, name: name) + } + /// Build a named global of the given type. /// /// - parameter name: The name of the newly inserted global value. diff --git a/Sources/LLVM/NamedMetadata.swift b/Sources/LLVM/NamedMetadata.swift new file mode 100644 index 00000000..936ea657 --- /dev/null +++ b/Sources/LLVM/NamedMetadata.swift @@ -0,0 +1,42 @@ +#if SWIFT_PACKAGE +import cllvm +#endif + +/// A `NamedMetadata` object represents a module-level metadata value identified +/// by a user-provided name. Named metadata is generated lazily when operands +/// are attached. +public class NamedMetadata { + public let module: Module + public let name: String + + init(module: Module, name: String) { + self.module = module + self.name = name + } + + /// Computes the operands of a named metadata node. + public var operands: [Metadata] { + let count = Int(LLVMGetNamedMetadataNumOperands(self.module.llvm, name)) + let operands = UnsafeMutablePointer.allocate(capacity: count) + LLVMGetNamedMetadataOperands(self.module.llvm, name, operands) + + var ops = [Metadata]() + ops.reserveCapacity(count) + for i in 0..