diff --git a/llvm-api/LLVM/Core/Context.swift b/llvm-api/LLVM/Core/Context.swift index 2468a7f..dab1dd5 100644 --- a/llvm-api/LLVM/Core/Context.swift +++ b/llvm-api/LLVM/Core/Context.swift @@ -222,7 +222,7 @@ public final class Context: ContextRef { } } - ///Destroy a context instance. + /// Destroy a context instance. /// /// This should be called for every call to LLVMContextCreate() or memory will be leaked. public func dispose() { diff --git a/llvm-api/LLVM/Core/Modules.swift b/llvm-api/LLVM/Core/Modules.swift index 3212ab8..4aee795 100644 --- a/llvm-api/LLVM/Core/Modules.swift +++ b/llvm-api/LLVM/Core/Modules.swift @@ -9,9 +9,28 @@ public final class Module: ModuleRef { /// Retrieves the underlying LLVM value object. public var moduleRef: LLVMModuleRef { llvm } + /// Inline Asm Dialect public enum InlineAsmDialect { case att case intel + + /// Init inline asm dialect from LLVM + public init(llvm: LLVMInlineAsmDialect) { + switch llvm { + case LLVMInlineAsmDialectATT: self = .att + case LLVMInlineAsmDialectIntel: self = .intel + default: + fatalError("Unknown behavior kind") + } + } + + /// Get LLVM representation + public var llvm: LLVMInlineAsmDialect { + switch self { + case .att: LLVMInlineAsmDialectATT + case .intel: LLVMInlineAsmDialectIntel + } + } } /// Named Metadata Node @@ -105,44 +124,88 @@ public final class Module: ModuleRef { fatalError("Unknown behavior kind") } } + + /// Converts ModuleFlagBehavior to LLVMModuleFlagBehavior + public var moduleFlagBehavior: LLVMModuleFlagBehavior { + switch self { + case .error: + LLVMModuleFlagBehaviorError + case .warning: + LLVMModuleFlagBehaviorWarning + case .require: + LLVMModuleFlagBehaviorRequire + case .override: + LLVMModuleFlagBehaviorOverride + case .append: + LLVMModuleFlagBehaviorAppend + case .appendUnique: + LLVMModuleFlagBehaviorAppendUnique + } + } } class Metadata: MetadataRef { - private let llvm:LLVMMetadataRef - public var metadataRef: LLVMMetadataRef { - llvm } - public init(llvm: LLVMMetadataRef ) { + private let llvm: LLVMMetadataRef + public var metadataRef: LLVMMetadataRef { + llvm + } + + public init(llvm: LLVMMetadataRef) { self.llvm = llvm } } + /// Represents the possible errors that can be thrown while interacting with a + /// `Module` object. + public enum ModuleError: Error, CustomStringConvertible { + /// Thrown when a module does not pass the module verification process. + /// Includes the reason the module did not pass verification. + case didNotPassVerification(String) + /// Thrown when a module cannot be printed at a given path. Provides the + /// erroneous path and a deeper reason why printing to that path failed. + case couldNotPrint(path: String, error: String) + /// Thrown when a module cannot emit bitcode because it contains erroneous + /// declarations. + case couldNotEmitBitCode(path: String) + + public var description: String { + switch self { + case let .didNotPassVerification(message): + "module did not pass verification: \(message)" + case let .couldNotPrint(path, error): + "could not print to file \(path): \(error)" + case let .couldNotEmitBitCode(path): + "could not emit bitcode to file \(path) for an unknown reason" + } + } + } + public class ModuleFlagEntry { private let llvm: OpaquePointer? private let bounds: Int - public init(llvm:OpaquePointer?, bounds: Int) { + public init(llvm: OpaquePointer?, bounds: Int) { self.llvm = llvm self.bounds = bounds } /// Get Metadata flags etries count - public var count: Int { self.bounds } + public var count: Int { bounds } - /// Returns the flag behavior for a module flag entry at a specific index. + /// Returns the flag behavior for a module flag entry at a specific index. public func getFlagBehavior(at index: UInt32) -> ModuleFlagBehavior { let bh = LLVMModuleFlagEntriesGetFlagBehavior(llvm, index) return ModuleFlagBehavior(raw: bh) } - /// Returns the key for a module flag entry at a specific index. + /// Returns the key for a module flag entry at a specific index. public func getKey(at index: UInt32) -> String { - var length: Int = 0 + var length = 0 let keyPointer = LLVMModuleFlagEntriesGetKey(llvm, index, &length) return String(cString: keyPointer!) - } - /// Returns the metadata for a module flag entry at a specific index. + /// Returns the metadata for a module flag entry at a specific index. public func getMetadata(at index: UInt32) -> MetadataRef { let metadata = LLVMModuleFlagEntriesGetMetadata(llvm, index)! return Metadata(llvm: metadata) @@ -150,8 +213,8 @@ public final class Module: ModuleRef { /// Deinitialize this value and dispose of its resources. deinit { - guard let ptr = llvm else { return } - LLVMDisposeModuleFlagsMetadata(ptr) + guard let ptr = llvm else { return } + LLVMDisposeModuleFlagsMetadata(ptr) } } @@ -190,10 +253,10 @@ public final class Module: ModuleRef { /// Get and Set the identifier of a module. public var moduleIdentifier: String { get { - self.getModuleIdentifier + getModuleIdentifier } set { - self.setModuleIdentifier(identifier: newValue) + setModuleIdentifier(identifier: newValue) } } @@ -214,14 +277,14 @@ public final class Module: ModuleRef { /// Get and Set the original source file name of a module to a string Name public var sourceFileName: String { get { - self.getSourceFileName! + getSourceFileName! } set { - self.setSourceFileName(fileName: newValue) + setSourceFileName(fileName: newValue) } } - ///Set the original source file name of a module to a string Name + /// Set the original source file name of a module to a string Name public func setSourceFileName(fileName: String) { fileName.withCString { cString in LLVMSetSourceFileName(llvm, cString, fileName.utf8.count) @@ -230,7 +293,7 @@ public final class Module: ModuleRef { /// Obtain the module's original source file name. public var getSourceFileName: String? { - var length: Int = 0 + var length = 0 guard let cString = LLVMGetSourceFileName(llvm, &length) else { return nil } @@ -252,8 +315,7 @@ public final class Module: ModuleRef { return String(cString: cString) } - - /// Obtain the target triple for a module. + /// Obtain the target triple for a module. func getTargetTriple() -> String { guard let targetTriplePointer = LLVMGetTarget(llvm) else { return "" @@ -268,14 +330,317 @@ public final class Module: ModuleRef { } } - /// Returns the module flags as an array of flag-key-value triples. The caller - /// is responsible for freeing this array by calling - /// `LLVMDisposeModuleFlagsMetadata`. + /// Returns the module flags as an array of flag-key-value triples. The caller + /// is responsible for freeing this array by calling + /// `LLVMDisposeModuleFlagsMetadata`. public func copyModuleFlagsMetadata() -> ModuleFlagEntry? { - var length: Int = 0 - guard let flagsPointer = LLVMCopyModuleFlagsMetadata(llvm, &length) else { return nil } + var length = 0 + guard let flagsPointer = LLVMCopyModuleFlagsMetadata(llvm, &length) else { return nil } + + return ModuleFlagEntry(llvm: flagsPointer, bounds: length) + } + + /// Add a module-level flag to the module-level flags metadata if it doesn't + /// already exist. + func getModuleFlag(key: String) -> MetadataRef { + let keyLen = key.utf8.count + let metadata = key.withCString { keyPtr in + LLVMGetModuleFlag(llvm, keyPtr, keyLen)! + } + return Metadata(llvm: metadata) + } + + /// Add a module-level flag to the module-level flags metadata if it doesn't + /// already exist. + func addModuleFlag(behavior: ModuleFlagBehavior, key: String, value: MetadataRef) { + let keyLen = key.utf8.count + key.withCString { keyPtr in + LLVMAddModuleFlag(llvm, behavior.moduleFlagBehavior, keyPtr, keyLen, value.metadataRef) + } + } + + /// Dump a representation of a module to stderr. + func dump_module() { + LLVMDumpModule(llvm) + } + + /// Print a representation of a module to a file. The ErrorMessage needs to be + /// disposed with `LLVMDisposeMessage`. Returns 0 on success, 1 otherwise. + func printToFile(filename: String) throws { + var errorMessage: UnsafeMutablePointer? + + let result = filename.withCString { filenamePtr in + LLVMPrintModuleToFile(llvm, filenamePtr, &errorMessage) + } - return ModuleFlagEntry(llvm: flagsPointer, bounds: length) + if result != 0, let errorMessage { + defer { LLVMDisposeMessage(errorMessage) } + let errorString = String(cString: errorMessage) + throw ModuleError.couldNotPrint(path: filename, error: errorString) + } + } + + /// Return a string representation of the module. Use + /// `LLVMDisposeMessage` to free the string. + func printToString() -> String { + guard let moduleString = LLVMPrintModuleToString(llvm) else { + return "" + } + defer { LLVMDisposeMessage(moduleString) } + return String(cString: moduleString) + } + + /// ========================== + /// Get inline assembly for a module. + public func getModuleInlineAsm(module _: LLVMModuleRef) -> String { + var length = 0 + let cString = LLVMGetModuleInlineAsm(llvm, &length) + return String(cString: cString!) + } + + /// Set inline assembly for a module. + public func setModuleInlineAsm(asm: String) { + asm.withCString { cString in + LLVMSetModuleInlineAsm2(llvm, cString, asm.utf8.count) + } + } + + /// Append inline assembly to a module. + public func appendModuleInlineAsm(asm: String) { + asm.withCString { cString in + LLVMAppendModuleInlineAsm(llvm, cString, asm.utf8.count) + } + } + + /// Create the specified uniqued inline asm string. + public func getInlineAsm(type: TypeRef, asmString: String, constraints: String, + hasSideEffects: Bool, isAlignStack: Bool, + dialect: InlineAsmDialect, canThrow: Bool) -> ValueRef + { + let inlineAsm = asmString.withCString { asmCString in + constraints.withCString { constraintsCString in + LLVMGetInlineAsm(type.typeRef, asmCString, asmString.utf8.count, constraintsCString, constraints.utf8.count, hasSideEffects.llvm, isAlignStack.llvm, dialect.llvm, canThrow.llvm) + } + } + return Value(llvm: inlineAsm!) + } + + /// Get the template string used for an inline assembly snippet + public func getInlineAsmAsmString(inlineAsmVal: ValueRef) -> String { + var length = 0 + let cString = LLVMGetInlineAsmAsmString(inlineAsmVal.valueRef, &length) + return String(cString: cString!) + } + + /// Get the raw constraint string for an inline assembly snippet + public func getInlineAsmConstraintString(inlineAsmVal: ValueRef) -> String { + var length = 0 + let cString = LLVMGetInlineAsmConstraintString(inlineAsmVal.valueRef, &length) + return String(cString: cString!) + } + + /// Get the dialect used by the inline asm snippet + public func getInlineAsmDialect(inlineAsmVal: ValueRef) -> InlineAsmDialect { + let dialect = LLVMGetInlineAsmDialect(inlineAsmVal.valueRef) + return InlineAsmDialect(llvm: dialect) + } + + /// Get the function type of the inline assembly snippet. The same type that + /// was passed into LLVMGetInlineAsm originally + public func getInlineAsmFunctionType(inlineAsmVal: ValueRef) -> TypeRef { + let typeRef = LLVMGetInlineAsmFunctionType(inlineAsmVal.valueRef) + return Types(llvm: typeRef!) + } + + /// Get if the inline asm snippet has side effects + public func inlineAsmHasSideEffects(inlineAsmVal: ValueRef) -> Bool { + LLVMGetInlineAsmHasSideEffects(inlineAsmVal.valueRef) != 0 + } + + /// Get if the inline asm snippet needs an aligned stack + public func inlineAsmNeedsAlignedStack(inlineAsmVal: ValueRef) -> Bool { + LLVMGetInlineAsmNeedsAlignedStack(inlineAsmVal.valueRef) != 0 + } + + /// Get if the inline asm snippet may unwind the stack + public func inlineAsmCanUnwind(inlineAsmVal: ValueRef) -> Bool { + LLVMGetInlineAsmCanUnwind(inlineAsmVal.valueRef) != 0 + } + + /// Obtain the context to which this module is associated. + public func getModuleContext() -> ContextRef { + let context = LLVMGetModuleContext(llvm) + return Context(llvm: context!) + } + + /// Obtain an iterator to the first NamedMDNode in a Module. + public func getFirstNamedMetadata() -> NamedMetadataNodeRef { + let namedMD = LLVMGetFirstNamedMetadata(llvm) + return NamedMetadataNode(llvm: namedMD!) + } + + /// Obtain an iterator to the last NamedMDNode in a Module. + public func getLastNamedMetadata() -> NamedMetadataNodeRef { + let namedMD = LLVMGetLastNamedMetadata(llvm) + return NamedMetadataNode(llvm: namedMD!) + } + + /// Advance a NamedMDNode iterator to the next NamedMDNode. + /// + /// Returns NULL if the iterator was already at the end and there are no more + /// named metadata nodes. + public func getNextNamedMetadata(namedMDNode: NamedMetadataNodeRef) -> NamedMetadataNodeRef { + let namedMD = LLVMGetNextNamedMetadata(namedMDNode.namedMetadataNodeRef) + return NamedMetadataNode(llvm: namedMD!) + } + + /// Decrement a NamedMDNode iterator to the previous NamedMDNode. + /// + /// Returns NULL if the iterator was already at the beginning and there are + /// no previous named metadata nodes. + public func getPreviousNamedMetadata(namedMDNode: NamedMetadataNodeRef) -> NamedMetadataNodeRef { + let namedMD = LLVMGetPreviousNamedMetadata(namedMDNode.namedMetadataNodeRef) + return NamedMetadataNode(llvm: namedMD!) + } + + /// Retrieve a NamedMDNode with the given name, returning NULL if no such + /// node exists. + public func getNamedMetadata(name: String) -> NamedMetadataNodeRef { + let namedMD = name.withCString { cString in + LLVMGetNamedMetadata(llvm, cString, name.utf8.count) + } + return NamedMetadataNode(llvm: namedMD!) + } + + /// Retrieve a NamedMDNode with the given name, creating a new node if no such + /// node exists. + public func getOrInsertNamedMetadata(name: String) -> NamedMetadataNodeRef { + let namedMD = name.withCString { cString in + LLVMGetOrInsertNamedMetadata(llvm, cString, name.utf8.count) + } + return NamedMetadataNode(llvm: namedMD!) + } + + /// Retrieve the name of a NamedMDNode. + public func getNamedMetadataName(namedMD: NamedMetadataNodeRef) -> String? { + var nameLen = 0 + guard let cString = LLVMGetNamedMetadataName(namedMD.namedMetadataNodeRef, &nameLen) else { + return nil + } + return String(cString: cString) + } + + /// Obtain the number of operands for named metadata in a module. + public func getNamedMetadataNumOperands(name: String) -> UInt32 { + name.withCString { cString in + LLVMGetNamedMetadataNumOperands(llvm, cString) + } + } + + /// Obtain the named metadata operands for a module. + /// + /// The passed LLVMValueRef pointer should refer to an array of + /// LLVMValueRef at least LLVMGetNamedMetadataNumOperands long. This + /// array will be populated with the LLVMValueRef instances. Each + /// instance corresponds to a llvm::MDNode. + public func getNamedMetadataOperands(name: String) -> [ValueRef] { + let numOperands = getNamedMetadataNumOperands(name: name) + var operands = [LLVMValueRef?](repeating: nil, count: Int(numOperands)) + + operands.withUnsafeMutableBufferPointer { buffer in + name.withCString { cString in + LLVMGetNamedMetadataOperands(llvm, cString, buffer.baseAddress) + } + } + + return operands.compactMap { Value(llvm: $0!) } + } + + /// Add an operand to named metadata. + public func addNamedMetadataOperand(name: String, value: ValueRef) { + name.withCString { cString in + LLVMAddNamedMetadataOperand(llvm, cString, value.valueRef) + } + } + + /// Return the directory of the debug location for this value, which must be + /// an llvm Instruction, llvm GlobalVariable, or llvm Function. + public func getDebugLocDirectory(value: ValueRef) -> String? { + var length: UInt32 = 0 + guard let cString = LLVMGetDebugLocDirectory(value.valueRef, &length) else { + return nil + } + return String(cString: cString) + } + + /// Return the filename of the debug location for this value, which must be + /// an llvm Instruction, llvm GlobalVariable, or llvm Function. + public func getDebugLocFilename(value: ValueRef) -> String? { + var length: UInt32 = 0 + guard let cString = LLVMGetDebugLocFilename(value.valueRef, &length) else { + return nil + } + return String(cString: cString) + } + + /// Return the line number of the debug location for this value, which must be + /// an llvm Instruction, llvm GlobalVariable, or llvm Function. + public func getDebugLocLine(value: ValueRef) -> UInt32 { + LLVMGetDebugLocLine(value.valueRef) + } + + /// Return the column number of the debug location for this value, which must be + /// an llvm Instruction. + public func getDebugLocColumn(value: ValueRef) -> UInt32 { + LLVMGetDebugLocColumn(value.valueRef) + } + + /// Add a function to a module under a specified name. + public func addFunction(name: String, functionType: TypeRef) -> ValueRef? { + guard let value = name.withCString({ cString in + LLVMAddFunction(llvm, cString, functionType.typeRef) + }) else { return nil } + return Value(llvm: value) + } + + /// Obtain a Function value from a Module by its name. + /// + /// The returned value corresponds to a llvm::Function value. + public func getNamedFunction(name: String) -> ValueRef? { + guard let value = name.withCString({ cString in + LLVMGetNamedFunction(llvm, cString) + }) else { return nil } + return Value(llvm: value) + } + + /// Obtain an iterator to the first Function in a Module. + public func getFirstFunction() -> ValueRef? { + guard let value = LLVMGetFirstFunction(llvm) else { return nil } + return Value(llvm: value) + } + + /// Obtain an iterator to the last Function in a Module. + public func getLastFunction() -> ValueRef? { + guard let value = LLVMGetLastFunction(llvm) else { return nil } + return Value(llvm: value) + } + + /// Advance a Function iterator to the next Function. + /// + /// Returns NULL if the iterator was already at the end and there are no more + /// functions. + public func getNextFunction(function: ValueRef) -> ValueRef? { + guard let value = LLVMGetNextFunction(function.valueRef) else { return nil } + return Value(llvm: value) + } + + /// Decrement a Function iterator to the previous Function. + /// + /// Returns NULL if the iterator was already at the beginning and there are + /// no previous functions. + public func getPreviousFunction(function: ValueRef) -> ValueRef? { + guard let value = LLVMGetPreviousFunction(function.valueRef) else { return nil } + return Value(llvm: value) } /// Destroy a module instance. diff --git a/llvm-api/LLVM/Core/Types/Types.swift b/llvm-api/LLVM/Core/Types/Types.swift index 1231e6f..514fca7 100644 --- a/llvm-api/LLVM/Core/Types/Types.swift +++ b/llvm-api/LLVM/Core/Types/Types.swift @@ -72,7 +72,7 @@ public protocol ModuleRef { } /// Represents an LLVM Named Metadata Node (NamedMDNodeRef). -public protocol NamedMetadataNodeRef { +public protocol NamedMetadataNodeRef { var namedMetadataNodeRef: LLVMNamedMDNodeRef { get } } diff --git a/llvm-api/LLVM/Core/Values/Constants/Composite.swift b/llvm-api/LLVM/Core/Values/Constants/Composite.swift index 31b5f49..9272095 100644 --- a/llvm-api/LLVM/Core/Values/Constants/Composite.swift +++ b/llvm-api/LLVM/Core/Values/Constants/Composite.swift @@ -27,20 +27,12 @@ public enum CompositeConstant { } /// Get the given constant data sequential as a string. - public static func getString(value: ValueRef) -> (String, UInt) { - var length: UInt = 0 - let lengthPtr = UnsafeMutablePointer.allocate(capacity: 1) - defer { - lengthPtr.deallocate() - } - - if let cStr = LLVMGetAsString(value.valueRef, lengthPtr) { - length = lengthPtr.pointee - let swiftStr = String(cString: cStr) - return (swiftStr, length) - } else { - return ("", 0) + public static func getString(value: ValueRef) -> String? { + var length: size_t = 0 + guard let cString = LLVMGetAsString(value.valueRef, &length) else { + return nil } + return String(cString: cString) } /// Create an anonymous `ConstantStruct` with the specified values.