From 81a1a2c242d86cd10a7b8f0f4ce5366d56c6aa34 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Sat, 17 Feb 2024 20:03:54 -0800 Subject: [PATCH] Rough-and-ready context lifetime management. This is a mostly-mechanical change; careful attention should be paid to make sure it's being done right. --- Sources/LLVM/BasicBlock.swift | 7 +- Sources/LLVM/Context.swift | 48 ++ Sources/LLVM/Module.swift | 646 +++++++++++------- Sources/LLVM/Types/AnyType.swift | 7 +- Sources/LLVM/Types/ArrayType.swift | 22 +- Sources/LLVM/Types/FloatingPointType.swift | 24 +- Sources/LLVM/Types/FunctionType.swift | 24 +- Sources/LLVM/Types/IRType.swift | 18 +- Sources/LLVM/Types/IntegerType.swift | 19 +- Sources/LLVM/Types/PointerType.swift | 14 +- Sources/LLVM/Types/StructType.swift | 54 +- Sources/LLVM/Types/VoidType.swift | 8 +- .../Values/Constants/AggregateConstant.swift | 2 +- Sources/LLVM/Values/Constants/AnyValue.swift | 7 +- .../LLVM/Values/Constants/ArrayConstant.swift | 5 +- Sources/LLVM/Values/Constants/Attribute.swift | 2 +- .../Constants/FloatingPointConstant.swift | 19 +- Sources/LLVM/Values/Constants/Function.swift | 32 +- .../Values/Constants/IntegerConstant.swift | 10 +- Sources/LLVM/Values/Constants/Intrinsic.swift | 7 +- Sources/LLVM/Values/Constants/Parameter.swift | 12 +- Sources/LLVM/Values/Constants/Poison.swift | 8 +- .../Values/Constants/StringConstant.swift | 26 +- .../Values/Constants/StructConstant.swift | 11 +- Sources/LLVM/Values/Constants/Undefined.swift | 8 +- Sources/LLVM/Values/Global.swift | 6 +- Sources/LLVM/Values/GlobalVariable.swift | 7 +- Sources/LLVM/Values/IRValue.swift | 4 +- Sources/LLVM/Values/Instructions/Alloca.swift | 14 +- .../Values/Instructions/Instruction.swift | 7 +- 30 files changed, 717 insertions(+), 361 deletions(-) create mode 100644 Sources/LLVM/Context.swift diff --git a/Sources/LLVM/BasicBlock.swift b/Sources/LLVM/BasicBlock.swift index 771a952..d1c4f59 100644 --- a/Sources/LLVM/BasicBlock.swift +++ b/Sources/LLVM/BasicBlock.swift @@ -1,14 +1,17 @@ import llvmc /// A basic block in LLVM IR. -public struct BasicBlock: Hashable { +public struct BasicBlock: Hashable, Contextual { /// A handle to the LLVM object wrapped by this instance. public let llvm: LLVMBasicBlockRef + public let context: ContextHandle + /// Creates an instance wrapping `llvm`. - internal init(_ llvm: LLVMBasicBlockRef) { + internal init(_ llvm: LLVMBasicBlockRef, in context: ContextHandle) { self.llvm = llvm + self.context = context } } diff --git a/Sources/LLVM/Context.swift b/Sources/LLVM/Context.swift new file mode 100644 index 0000000..d1a799c --- /dev/null +++ b/Sources/LLVM/Context.swift @@ -0,0 +1,48 @@ +import llvmc + +/// Lifetime manager for a raw LLVM context. +public final class ContextHandle { + + /// The raw LLVM context managed by `self`. + let raw: LLVMContextRef + + /// An instance managing c. + init(_ c: LLVMContextRef) { + self.raw = c + } + + deinit { + LLVMContextDispose(raw) + } + +} + +/// A context handle is valueless; all such handles are considered to be equal. +extension ContextHandle: Hashable { + + public static func == (_: ContextHandle, _: ContextHandle) -> Bool { true } + + public func hash(into hasher: inout Hasher) {} + +} + +/// A type whose operations require a particular live LLVMContextRef for validity. +public protocol Contextual { + + /// A handle managing the LLVMContextRef that must remain live for operations on `self` to be + /// valid. + var context: ContextHandle { get } + +} + +extension Contextual { + + /// Invokes `body`, returning its result, with the guarantee that `context` will remain live + /// during the execution of `body`. + func inContext(body: () throws -> R) rethrows -> R { + try withExtendedLifetime(context) { + try body() + } + } + +} diff --git a/Sources/LLVM/Module.swift b/Sources/LLVM/Module.swift index aa26988..b26e266 100644 --- a/Sources/LLVM/Module.swift +++ b/Sources/LLVM/Module.swift @@ -8,21 +8,20 @@ public struct Module { private final class Handles { /// The context owning the contents of the LLVM module. - let context: LLVMContextRef + let context: ContextHandle /// The LLVM module. let module: LLVMModuleRef /// Creates an instance with given properties. - init(context: LLVMContextRef, module: LLVMModuleRef) { - self.context = context + init(context: ContextHandle, module: LLVMModuleRef) { self.module = module + self.context = context } /// Dispose of the managed resources. deinit { LLVMDisposeModule(module) - LLVMContextDispose(context) } } @@ -32,60 +31,115 @@ public struct Module { /// Creates an instance with given `name`. public init(_ name: String) { - let c = LLVMContextCreate()! - let m = LLVMModuleCreateWithNameInContext(name, c)! + let c = ContextHandle(LLVMContextCreate()!) + let m = LLVMModuleCreateWithNameInContext(name, c.raw)! self.handles = .init(context: c, module: m) } + // MARK: Basic type instances + + /// The `void` type. + public private(set) lazy var void: VoidType = .init(in: &self) + + /// The `ptr` type in the default address space. + public private(set) lazy var ptr: PointerType = .init(inAddressSpace: .default, in: &self) + + /// The `half` type. + public private(set) lazy var half: FloatingPointType = .half(in: &self) + + /// The `float` type. + public private(set) lazy var float: FloatingPointType = .float(in: &self) + + /// The `double` type. + public private(set) lazy var double: FloatingPointType = .double(in: &self) + + /// The `fp128` type. + public private(set) lazy var fp128: FloatingPointType = .fp128(in: &self) + + /// The 1-bit integer type. + public private(set) lazy var i1: IntegerType = .init(LLVMInt1TypeInContext(self.context.raw), in: context) + + /// The 8-bit integer type. + public private(set) lazy var i8: IntegerType = .init(LLVMInt8TypeInContext(self.context.raw), in: context) + + /// The 16-bit integer type. + public private(set) lazy var i16: IntegerType = .init(LLVMInt16TypeInContext(self.context.raw), in: context) + + /// The 32-bit integer type. + public private(set) lazy var i32: IntegerType = .init(LLVMInt32TypeInContext(self.context.raw), in: context) + + /// The 64-bit integer type. + public private(set) lazy var i64: IntegerType = .init(LLVMInt64TypeInContext(self.context.raw), in: context) + + /// The 128-bit integer type. + public private(set) lazy var i128: IntegerType = .init(LLVMInt128TypeInContext(self.context.raw), in: context) + +} + +extension Module: Contextual { + + public var context: ContextHandle { handles.context } + +} + +extension Module { + /// A handle to the LLVM object wrapped by this instance. public var llvm: LLVMModuleRef { handles.module } - /// A handle to the LLVM context associated with this module. - internal var context: LLVMContextRef { handles.context } - /// The name of the module. public var name: String { get { - String(from: llvm, readingWith: LLVMGetModuleIdentifier(_:_:)) ?? "" + inContext { String(from: llvm, readingWith: LLVMGetModuleIdentifier(_:_:)) ?? "" } } set { - newValue.withCString({ LLVMSetModuleIdentifier(llvm, $0, newValue.utf8.count) }) + inContext { newValue.withCString({ LLVMSetModuleIdentifier(llvm, $0, newValue.utf8.count) }) } } } /// The data layout of the module. public var layout: DataLayout { get { - let s = LLVMGetDataLayoutStr(llvm) - let h = LLVMCreateTargetData(s) - return .init(h!) + inContext { + let s = LLVMGetDataLayoutStr(llvm) + let h = LLVMCreateTargetData(s) + return .init(h!) + } } set { - LLVMSetDataLayout(llvm, newValue.description) + inContext { + LLVMSetDataLayout(llvm, newValue.description) + } } } /// The target of the module. public var target: Target? { get { - guard let t = LLVMGetTarget(llvm) else { return nil } - return try? Target(triple: .init(cString: t)) + inContext { + guard let t = LLVMGetTarget(llvm) else { return nil } + return try? Target(triple: .init(cString: t)) + } } set { - LLVMSetTarget(llvm, newValue?.triple) + inContext { + LLVMSetTarget(llvm, newValue?.triple) + } } } /// Verifies if the IR in `self` is well formed and throws an error if it isn't. public func verify() throws { - var message: UnsafeMutablePointer? = nil - defer { LLVMDisposeMessage(message) } - let status = withUnsafeMutablePointer(to: &message, { (m) in - LLVMVerifyModule(llvm, LLVMReturnStatusAction, m) - }) - - if status != 0 { - throw LLVMError(.init(cString: message!)) + try inContext { + var message: UnsafeMutablePointer? = nil + defer { LLVMDisposeMessage(message) } + let status = withUnsafeMutablePointer(to: &message, { (m) in + LLVMVerifyModule(llvm, LLVMReturnStatusAction, m) + }) + + if status != 0 { + throw LLVMError(.init(cString: message!)) + } } } @@ -94,30 +148,36 @@ public struct Module { optimization: OptimitzationLevel = .none, for machine: TargetMachine? = nil ) { - let o: SwiftyLLVMPassOptimizationLevel - switch optimization { - case .none: - o = SwiftyLLVMPassOptimizationLevelO0 - case .less: - o = SwiftyLLVMPassOptimizationLevelO1 - case .default: - o = SwiftyLLVMPassOptimizationLevelO2 - case .aggressive: - o = SwiftyLLVMPassOptimizationLevelO3 + inContext { + let o: SwiftyLLVMPassOptimizationLevel + switch optimization { + case .none: + o = SwiftyLLVMPassOptimizationLevelO0 + case .less: + o = SwiftyLLVMPassOptimizationLevelO1 + case .default: + o = SwiftyLLVMPassOptimizationLevelO2 + case .aggressive: + o = SwiftyLLVMPassOptimizationLevelO3 + } + SwiftyLLVMRunDefaultModulePasses(llvm, machine?.llvm, o) } - SwiftyLLVMRunDefaultModulePasses(llvm, machine?.llvm, o) } /// Writes the LLVM bitcode of this module to `filepath`. public func writeBitcode(to filepath: String) throws { - guard LLVMWriteBitcodeToFile(llvm, filepath) == 0 else { - throw LLVMError("write failure") + try inContext { + guard LLVMWriteBitcodeToFile(llvm, filepath) == 0 else { + throw LLVMError("write failure") + } } } /// Returns the LLVM bitcode of this module. public func bitcode() -> MemoryBuffer { - .init(LLVMWriteBitcodeToMemoryBuffer(llvm), owned: true) + inContext { + .init(LLVMWriteBitcodeToMemoryBuffer(llvm), owned: true) + } } /// Compiles this module for given `machine` and writes a result of kind `type` to `filepath`. @@ -126,12 +186,14 @@ public struct Module { for machine:TargetMachine, to filepath: String ) throws { - var error: UnsafeMutablePointer? = nil - LLVMTargetMachineEmitToFile(machine.llvm, llvm, filepath, type.llvm, &error) - - if let e = error { - defer { LLVMDisposeMessage(e) } - throw LLVMError(.init(cString: e)) + try inContext { + var error: UnsafeMutablePointer? = nil + LLVMTargetMachineEmitToFile(machine.llvm, llvm, filepath, type.llvm, &error) + + if let e = error { + defer { LLVMDisposeMessage(e) } + throw LLVMError(.init(cString: e)) + } } } @@ -140,43 +202,53 @@ public struct Module { _ type: CodeGenerationResultType, for machine: TargetMachine ) throws -> MemoryBuffer { - var output: LLVMMemoryBufferRef? = nil - var error: UnsafeMutablePointer? = nil - LLVMTargetMachineEmitToMemoryBuffer(machine.llvm, llvm, type.llvm, &error, &output) + try inContext { + var output: LLVMMemoryBufferRef? = nil + var error: UnsafeMutablePointer? = nil + LLVMTargetMachineEmitToMemoryBuffer(machine.llvm, llvm, type.llvm, &error, &output) - if let e = error { - defer { LLVMDisposeMessage(e) } - throw LLVMError(.init(cString: e)) - } + if let e = error { + defer { LLVMDisposeMessage(e) } + throw LLVMError(.init(cString: e)) + } - return .init(output!, owned: true) + return .init(output!, owned: true) + } } /// Returns the type with given `name`, or `nil` if no such type exists. public func type(named name: String) -> IRType? { - LLVMGetTypeByName2(context, name).map(AnyType.init(_:)) + inContext { + LLVMGetTypeByName2(context.raw, name).map { AnyType($0, in: context) } + } } /// Returns the function with given `name`, or `nil` if no such function exists. public func function(named name: String) -> Function? { - LLVMGetNamedFunction(llvm, name).map(Function.init(_:)) + inContext { + LLVMGetNamedFunction(llvm, name).map{ Function($0, in: context) } + } } /// Returns the global with given `name`, or `nil` if no such global exists. public func global(named name: String) -> GlobalVariable? { - LLVMGetNamedGlobal(llvm, name).map(GlobalVariable.init(_:)) + inContext { + LLVMGetNamedGlobal(llvm, name).map { GlobalVariable($0, in: context) } + } } /// Returns the intrinsic with given `name`, specialized for `parameters`, or `nil` if no such /// intrinsic exists. public mutating func intrinsic(named name: String, for parameters: [IRType] = []) -> Intrinsic? { - let i = name.withCString({ LLVMLookupIntrinsicID($0, name.utf8.count) }) - guard i != 0 else { return nil } - - let h = parameters.withHandles { (p) in - LLVMGetIntrinsicDeclaration(llvm, i, p.baseAddress, parameters.count) + inContext { + let i = name.withCString({ LLVMLookupIntrinsicID($0, name.utf8.count) }) + guard i != 0 else { return nil } + + let h = parameters.withHandles { (p) in + LLVMGetIntrinsicDeclaration(llvm, i, p.baseAddress, parameters.count) + } + return h.map { Intrinsic($0, in: context) } } - return h.map(Intrinsic.init(_:)) } /// Returns the intrinsic with given `name`, specialized for `parameters`, or `nil` if no such @@ -184,7 +256,9 @@ public struct Module { public mutating func intrinsic( named name: Intrinsic.Name, for parameters: [IRType] = [] ) -> Intrinsic? { - intrinsic(named: name.value, for: parameters) + inContext { + intrinsic(named: name.value, for: parameters) + } } /// Creates and returns a global variable with given `name` and `type`. @@ -196,7 +270,9 @@ public struct Module { _ type: IRType, inAddressSpace s: AddressSpace = .default ) -> GlobalVariable { - .init(LLVMAddGlobalInAddressSpace(llvm, type.llvm, name, s.llvm)) + inContext { + .init(LLVMAddGlobalInAddressSpace(llvm, type.llvm, name, s.llvm), in: context) + } } /// Returns a global variable with given `name` and `type`, declaring it if it doesn't exist. @@ -205,28 +281,34 @@ public struct Module { _ type: IRType, inAddressSpace s: AddressSpace = .default ) -> GlobalVariable { - if let g = global(named: name) { - precondition(g.valueType == type) - return g - } else { - return .init(LLVMAddGlobalInAddressSpace(llvm, type.llvm, name, s.llvm)) + inContext { + if let g = global(named: name) { + precondition(g.valueType == type) + return g + } else { + return .init(LLVMAddGlobalInAddressSpace(llvm, type.llvm, name, s.llvm), in: context) + } } } /// Returns a function with given `name` and `type`, declaring it if it doesn't exist. public mutating func declareFunction(_ name: String, _ type: FunctionType) -> Function { - if let f = function(named: name) { - precondition(f.valueType == type) - return f - } else { - return .init(LLVMAddFunction(llvm, name, type.llvm)) + inContext { + if let f = function(named: name) { + precondition(f.valueType == type) + return f + } else { + return .init(LLVMAddFunction(llvm, name, type.llvm), in: context) + } } } /// Adds attribute `a` to `f`. public mutating func addAttribute(_ a: Function.Attribute, to f: Function) { - let i = UInt32(bitPattern: Int32(LLVMAttributeFunctionIndex)) - LLVMAddAttributeAtIndex(f.llvm, i, a.llvm) + inContext { + let i = UInt32(bitPattern: Int32(LLVMAttributeFunctionIndex)) + LLVMAddAttributeAtIndex(f.llvm, i, a.llvm) + } } /// Adds the attribute named `n` to `f` and returns it. @@ -234,14 +316,18 @@ public struct Module { public mutating func addAttribute( named n: Function.AttributeName, to f: Function ) -> Function.Attribute { - let a = Function.Attribute(n, in: &self) - addAttribute(a, to: f) - return a + inContext { + let a = Function.Attribute(n, in: &self) + addAttribute(a, to: f) + return a + } } /// Adds attribute `a` to the return value of `f`. public mutating func addAttribute(_ a: Function.Return.Attribute, to r: Function.Return) { - LLVMAddAttributeAtIndex(r.parent.llvm, 0, a.llvm) + inContext { + LLVMAddAttributeAtIndex(r.parent.llvm, 0, a.llvm) + } } /// Adds the attribute named `n` to the return value of `f` and returns it. @@ -249,15 +335,19 @@ public struct Module { public mutating func addAttribute( named n: Function.Return.AttributeName, to r: Function.Return ) -> Function.Return.Attribute { - let a = Function.Return.Attribute(n, in: &self) - addAttribute(a, to: r) - return a + inContext { + let a = Function.Return.Attribute(n, in: &self) + addAttribute(a, to: r) + return a + } } /// Adds attribute `a` to `p`. public mutating func addAttribute(_ a: Parameter.Attribute, to p: Parameter) { - let i = UInt32(p.index + 1) - LLVMAddAttributeAtIndex(p.parent.llvm, i, a.llvm) + inContext { + let i = UInt32(p.index + 1) + LLVMAddAttributeAtIndex(p.parent.llvm, i, a.llvm) + } } /// Adds the attribute named `n` to `p` and returns it. @@ -265,37 +355,45 @@ public struct Module { public mutating func addAttribute( named n: Parameter.AttributeName, to p: Parameter ) -> Parameter.Attribute { - let a = Parameter.Attribute(n, in: &self) - addAttribute(a, to: p) - return a + inContext { + let a = Parameter.Attribute(n, in: &self) + addAttribute(a, to: p) + return a + } } /// Removes `a` from `f`. public mutating func removeAttribute(_ a: Function.Attribute, from f: Function) { - switch a { - case .targetIndependent(let h): - let k = LLVMGetEnumAttributeKind(h) - let i = UInt32(bitPattern: Int32(LLVMAttributeFunctionIndex)) - LLVMRemoveEnumAttributeAtIndex(f.llvm, i, k) + inContext { + switch a { + case .targetIndependent(let h): + let k = LLVMGetEnumAttributeKind(h) + let i = UInt32(bitPattern: Int32(LLVMAttributeFunctionIndex)) + LLVMRemoveEnumAttributeAtIndex(f.llvm, i, k) + } } } /// Removes `a` from `p`. public mutating func removeAttribute(_ a: Parameter.Attribute, from p: Parameter) { - switch a { - case .targetIndependent(let h): - let k = LLVMGetEnumAttributeKind(h) - let i = UInt32(p.index + 1) - LLVMRemoveEnumAttributeAtIndex(p.parent.llvm, i, k) + inContext { + switch a { + case .targetIndependent(let h): + let k = LLVMGetEnumAttributeKind(h) + let i = UInt32(p.index + 1) + LLVMRemoveEnumAttributeAtIndex(p.parent.llvm, i, k) + } } } /// Removes `a` from `r`. public mutating func removeAttribute(_ a: Function.Return.Attribute, from r: Function.Return) { - switch a { - case .targetIndependent(let h): - let k = LLVMGetEnumAttributeKind(h) - LLVMRemoveEnumAttributeAtIndex(r.parent.llvm, 0, k) + inContext { + switch a { + case .targetIndependent(let h): + let k = LLVMGetEnumAttributeKind(h) + LLVMRemoveEnumAttributeAtIndex(r.parent.llvm, 0, k) + } } } @@ -304,50 +402,66 @@ public struct Module { /// A unique name is generated if `n` is empty or if `f` already contains a block named `n`. @discardableResult public mutating func appendBlock(named n: String = "", to f: Function) -> BasicBlock { - .init(LLVMAppendBasicBlockInContext(context, f.llvm, n)) + inContext { + .init(LLVMAppendBasicBlockInContext(context.raw, f.llvm, n), in: context) + } } /// Returns an insertion pointing before `i`. public func before(_ i: Instruction) -> InsertionPoint { - let h = LLVMCreateBuilderInContext(context)! - LLVMPositionBuilderBefore(h, i.llvm) - return .init(h) + inContext { + let h = LLVMCreateBuilderInContext(context.raw)! + LLVMPositionBuilderBefore(h, i.llvm) + return .init(h) + } } /// Returns an insertion point at the start of `b`. public func startOf(_ b: BasicBlock) -> InsertionPoint { - if let h = LLVMGetFirstInstruction(b.llvm) { - return before(Instruction(h)) - } else { - return endOf(b) + inContext { + if let h = LLVMGetFirstInstruction(b.llvm) { + return before(Instruction(h, in: context)) + } else { + return endOf(b) + } } } /// Returns an insertion point at the end of `b`. public func endOf(_ b: BasicBlock) -> InsertionPoint { - let h = LLVMCreateBuilderInContext(context)! - LLVMPositionBuilderAtEnd(h, b.llvm) - return .init(h) + inContext { + let h = LLVMCreateBuilderInContext(context.raw)! + LLVMPositionBuilderAtEnd(h, b.llvm) + return .init(h) + } } /// Sets the name of `v` to `n`. public mutating func setName(_ n: String, for v: IRValue) { - n.withCString({ LLVMSetValueName2(v.llvm, $0, n.utf8.count) }) + inContext { + n.withCString({ LLVMSetValueName2(v.llvm, $0, n.utf8.count) }) + } } /// Sets the linkage of `g` to `l`. public mutating func setLinkage(_ l: Linkage, for g: Global) { - LLVMSetLinkage(g.llvm, l.llvm) + inContext { + LLVMSetLinkage(g.llvm, l.llvm) + } } /// Configures whether `g` is a global constant. public mutating func setGlobalConstant(_ newValue: Bool, for g: GlobalVariable) { - LLVMSetGlobalConstant(g.llvm, newValue ? 1 : 0) + inContext { + LLVMSetGlobalConstant(g.llvm, newValue ? 1 : 0) + } } /// Configures whether `g` is externally initialized. public mutating func setExternallyInitialized(_ newValue: Bool, for g: GlobalVariable) { - LLVMSetExternallyInitialized(g.llvm, newValue ? 1 : 0) + inContext { + LLVMSetExternallyInitialized(g.llvm, newValue ? 1 : 0) + } } /// Sets the initializer of `g` to `v`. @@ -355,54 +469,20 @@ public struct Module { /// - Precondition: if `g` has type pointer-to-`T`, the `newValue` /// must have type `T`. public mutating func setInitializer(_ newValue: IRValue, for g: GlobalVariable) { - LLVMSetInitializer(g.llvm, newValue.llvm) + inContext { + LLVMSetInitializer(g.llvm, newValue.llvm) + } } /// Sets the preferred alignment of `v` to `a`. /// /// - Requires: `a` is whole power of 2. public mutating func setAlignment(_ a: Int, for v: Alloca) { - LLVMSetAlignment(v.llvm, UInt32(a)) + inContext { + LLVMSetAlignment(v.llvm, UInt32(a)) + } } - // MARK: Basic type instances - - /// The `void` type. - public private(set) lazy var void: VoidType = .init(in: &self) - - /// The `ptr` type in the default address space. - public private(set) lazy var ptr: PointerType = .init(inAddressSpace: .default, in: &self) - - /// The `half` type. - public private(set) lazy var half: FloatingPointType = .half(in: &self) - - /// The `float` type. - public private(set) lazy var float: FloatingPointType = .float(in: &self) - - /// The `double` type. - public private(set) lazy var double: FloatingPointType = .double(in: &self) - - /// The `fp128` type. - public private(set) lazy var fp128: FloatingPointType = .fp128(in: &self) - - /// The 1-bit integer type. - public private(set) lazy var i1: IntegerType = .init(LLVMInt1TypeInContext(context)) - - /// The 8-bit integer type. - public private(set) lazy var i8: IntegerType = .init(LLVMInt8TypeInContext(context)) - - /// The 16-bit integer type. - public private(set) lazy var i16: IntegerType = .init(LLVMInt16TypeInContext(context)) - - /// The 32-bit integer type. - public private(set) lazy var i32: IntegerType = .init(LLVMInt32TypeInContext(context)) - - /// The 64-bit integer type. - public private(set) lazy var i64: IntegerType = .init(LLVMInt64TypeInContext(context)) - - /// The 128-bit integer type. - public private(set) lazy var i128: IntegerType = .init(LLVMInt128TypeInContext(context)) - // MARK: Arithmetics public mutating func insertAdd( @@ -410,13 +490,15 @@ public struct Module { _ lhs: IRValue, _ rhs: IRValue, at p: InsertionPoint ) -> Instruction { - switch overflow { - case .ignore: - return .init(LLVMBuildAdd(p.llvm, lhs.llvm, rhs.llvm, "")) - case .nuw: - return .init(LLVMBuildNUWAdd(p.llvm, lhs.llvm, rhs.llvm, "")) - case .nsw: - return .init(LLVMBuildNSWAdd(p.llvm, lhs.llvm, rhs.llvm, "")) + inContext { + switch overflow { + case .ignore: + return .init(LLVMBuildAdd(p.llvm, lhs.llvm, rhs.llvm, ""), in: context) + case .nuw: + return .init(LLVMBuildNUWAdd(p.llvm, lhs.llvm, rhs.llvm, ""), in: context) + case .nsw: + return .init(LLVMBuildNSWAdd(p.llvm, lhs.llvm, rhs.llvm, ""), in: context) + } } } @@ -424,7 +506,9 @@ public struct Module { _ lhs: IRValue, _ rhs: IRValue, at p: InsertionPoint ) -> Instruction { - .init(LLVMBuildFAdd(p.llvm, lhs.llvm, rhs.llvm, "")) + inContext { + .init(LLVMBuildFAdd(p.llvm, lhs.llvm, rhs.llvm, ""), in: context) + } } public mutating func insertSub( @@ -432,13 +516,15 @@ public struct Module { _ lhs: IRValue, _ rhs: IRValue, at p: InsertionPoint ) -> Instruction { - switch overflow { - case .ignore: - return .init(LLVMBuildSub(p.llvm, lhs.llvm, rhs.llvm, "")) - case .nuw: - return .init(LLVMBuildNUWSub(p.llvm, lhs.llvm, rhs.llvm, "")) - case .nsw: - return .init(LLVMBuildNSWSub(p.llvm, lhs.llvm, rhs.llvm, "")) + inContext { + switch overflow { + case .ignore: + return .init(LLVMBuildSub(p.llvm, lhs.llvm, rhs.llvm, ""), in: context) + case .nuw: + return .init(LLVMBuildNUWSub(p.llvm, lhs.llvm, rhs.llvm, ""), in: context) + case .nsw: + return .init(LLVMBuildNSWSub(p.llvm, lhs.llvm, rhs.llvm, ""), in: context) + } } } @@ -446,7 +532,9 @@ public struct Module { _ lhs: IRValue, _ rhs: IRValue, at p: InsertionPoint ) -> Instruction { - .init(LLVMBuildFSub(p.llvm, lhs.llvm, rhs.llvm, "")) + inContext { + .init(LLVMBuildFSub(p.llvm, lhs.llvm, rhs.llvm, ""), in: context) + } } public mutating func insertMul( @@ -454,13 +542,15 @@ public struct Module { _ lhs: IRValue, _ rhs: IRValue, at p: InsertionPoint ) -> Instruction { - switch overflow { - case .ignore: - return .init(LLVMBuildMul(p.llvm, lhs.llvm, rhs.llvm, "")) - case .nuw: - return .init(LLVMBuildNUWMul(p.llvm, lhs.llvm, rhs.llvm, "")) - case .nsw: - return .init(LLVMBuildNSWMul(p.llvm, lhs.llvm, rhs.llvm, "")) + inContext { + switch overflow { + case .ignore: + return .init(LLVMBuildMul(p.llvm, lhs.llvm, rhs.llvm, ""), in: context) + case .nuw: + return .init(LLVMBuildNUWMul(p.llvm, lhs.llvm, rhs.llvm, ""), in: context) + case .nsw: + return .init(LLVMBuildNSWMul(p.llvm, lhs.llvm, rhs.llvm, ""), in: context) + } } } @@ -468,7 +558,9 @@ public struct Module { _ lhs: IRValue, _ rhs: IRValue, at p: InsertionPoint ) -> Instruction { - .init(LLVMBuildFMul(p.llvm, lhs.llvm, rhs.llvm, "")) + inContext { + .init(LLVMBuildFMul(p.llvm, lhs.llvm, rhs.llvm, ""), in: context) + } } public mutating func insertUnsignedDiv( @@ -476,10 +568,12 @@ public struct Module { _ lhs: IRValue, _ rhs: IRValue, at p: InsertionPoint ) -> Instruction { - if exact { - return .init(LLVMBuildExactUDiv(p.llvm, lhs.llvm, rhs.llvm, "")) - } else { - return .init(LLVMBuildUDiv(p.llvm, lhs.llvm, rhs.llvm, "")) + inContext { + if exact { + return .init(LLVMBuildExactUDiv(p.llvm, lhs.llvm, rhs.llvm, ""), in: context) + } else { + return .init(LLVMBuildUDiv(p.llvm, lhs.llvm, rhs.llvm, ""), in: context) + } } } @@ -488,10 +582,12 @@ public struct Module { _ lhs: IRValue, _ rhs: IRValue, at p: InsertionPoint ) -> Instruction { - if exact { - return .init(LLVMBuildExactSDiv(p.llvm, lhs.llvm, rhs.llvm, "")) - } else { - return .init(LLVMBuildSDiv(p.llvm, lhs.llvm, rhs.llvm, "")) + inContext { + if exact { + return .init(LLVMBuildExactSDiv(p.llvm, lhs.llvm, rhs.llvm, ""), in: context) + } else { + return .init(LLVMBuildSDiv(p.llvm, lhs.llvm, rhs.llvm, ""), in: context) + } } } @@ -499,76 +595,98 @@ public struct Module { _ lhs: IRValue, _ rhs: IRValue, at p: InsertionPoint ) -> Instruction { - .init(LLVMBuildFDiv(p.llvm, lhs.llvm, rhs.llvm, "")) + inContext { + .init(LLVMBuildFDiv(p.llvm, lhs.llvm, rhs.llvm, ""), in: context) + } } public mutating func insertUnsignedRem( _ lhs: IRValue, _ rhs: IRValue, at p: InsertionPoint ) -> Instruction { - .init(LLVMBuildURem(p.llvm, lhs.llvm, rhs.llvm, "")) + inContext { + .init(LLVMBuildURem(p.llvm, lhs.llvm, rhs.llvm, ""), in: context) + } } public mutating func insertSignedRem( _ lhs: IRValue, _ rhs: IRValue, at p: InsertionPoint ) -> Instruction { - .init(LLVMBuildSRem(p.llvm, lhs.llvm, rhs.llvm, "")) + inContext { + .init(LLVMBuildSRem(p.llvm, lhs.llvm, rhs.llvm, ""), in: context) + } } public mutating func insertFRem( _ lhs: IRValue, _ rhs: IRValue, at p: InsertionPoint ) -> Instruction { - .init(LLVMBuildFRem(p.llvm, lhs.llvm, rhs.llvm, "")) + inContext { + .init(LLVMBuildFRem(p.llvm, lhs.llvm, rhs.llvm, ""), in: context) + } } public mutating func insertShl( _ lhs: IRValue, _ rhs: IRValue, at p: InsertionPoint ) -> Instruction { - .init(LLVMBuildShl(p.llvm, lhs.llvm, rhs.llvm, "")) + inContext { + .init(LLVMBuildShl(p.llvm, lhs.llvm, rhs.llvm, ""), in: context) + } } public mutating func insertLShr( _ lhs: IRValue, _ rhs: IRValue, at p: InsertionPoint ) -> Instruction { - .init(LLVMBuildLShr(p.llvm, lhs.llvm, rhs.llvm, "")) + inContext { + .init(LLVMBuildLShr(p.llvm, lhs.llvm, rhs.llvm, ""), in: context) + } } public mutating func insertAShr( _ lhs: IRValue, _ rhs: IRValue, at p: InsertionPoint ) -> Instruction { - .init(LLVMBuildAShr(p.llvm, lhs.llvm, rhs.llvm, "")) + inContext { + .init(LLVMBuildAShr(p.llvm, lhs.llvm, rhs.llvm, ""), in: context) + } } public mutating func insertBitwiseAnd( _ lhs: IRValue, _ rhs: IRValue, at p: InsertionPoint ) -> Instruction { - .init(LLVMBuildAnd(p.llvm, lhs.llvm, rhs.llvm, "")) + inContext { + .init(LLVMBuildAnd(p.llvm, lhs.llvm, rhs.llvm, ""), in: context) + } } public mutating func insertBitwiseOr( _ lhs: IRValue, _ rhs: IRValue, at p: InsertionPoint ) -> Instruction { - .init(LLVMBuildOr(p.llvm, lhs.llvm, rhs.llvm, "")) + inContext { + .init(LLVMBuildOr(p.llvm, lhs.llvm, rhs.llvm, ""), in: context) + } } public mutating func insertBitwiseXor( _ lhs: IRValue, _ rhs: IRValue, at p: InsertionPoint ) -> Instruction { - .init(LLVMBuildXor(p.llvm, lhs.llvm, rhs.llvm, "")) + inContext { + .init(LLVMBuildXor(p.llvm, lhs.llvm, rhs.llvm, ""), in: context) + } } // MARK: Memory public mutating func insertAlloca(_ type: IRType, at p: InsertionPoint) -> Alloca { - .init(LLVMBuildAlloca(p.llvm, type.llvm, "")) + inContext { + .init(LLVMBuildAlloca(p.llvm, type.llvm, ""), in: context) + } } /// Inerts an `alloca` allocating memory on the stack a value of `type`, at the entry of `f`. @@ -584,9 +702,11 @@ public struct Module { indices: [IRValue], at p: InsertionPoint ) -> Instruction { - var i = indices.map({ $0.llvm as Optional }) - let h = LLVMBuildGEP2(p.llvm, baseType.llvm, base.llvm, &i, UInt32(i.count), "")! - return .init(h) + inContext { + var i = indices.map({ $0.llvm as Optional }) + let h = LLVMBuildGEP2(p.llvm, baseType.llvm, base.llvm, &i, UInt32(i.count), "")! + return .init(h, in: context) + } } public mutating func insertGetElementPointerInBounds( @@ -595,9 +715,11 @@ public struct Module { indices: [IRValue], at p: InsertionPoint ) -> Instruction { - var i = indices.map({ $0.llvm as Optional }) - let h = LLVMBuildInBoundsGEP2(p.llvm, baseType.llvm, base.llvm, &i, UInt32(i.count), "")! - return .init(h) + inContext { + var i = indices.map({ $0.llvm as Optional }) + let h = LLVMBuildInBoundsGEP2(p.llvm, baseType.llvm, base.llvm, &i, UInt32(i.count), "")! + return .init(h, in: context) + } } public mutating func insertGetStructElementPointer( @@ -606,27 +728,35 @@ public struct Module { index: Int, at p: InsertionPoint ) -> Instruction { - .init(LLVMBuildStructGEP2(p.llvm, baseType.llvm, base.llvm, UInt32(index), "")) + inContext { + .init(LLVMBuildStructGEP2(p.llvm, baseType.llvm, base.llvm, UInt32(index), ""), in: context) + } } public mutating func insertLoad( _ type: IRType, from source: IRValue, at p: InsertionPoint ) -> Instruction { - .init(LLVMBuildLoad2(p.llvm, type.llvm, source.llvm, "")) + inContext { + .init(LLVMBuildLoad2(p.llvm, type.llvm, source.llvm, ""), in: context) + } } @discardableResult public mutating func insertStore( _ value: IRValue, to location: IRValue, at p: InsertionPoint ) -> Instruction { - .init(LLVMBuildStore(p.llvm, value.llvm, location.llvm)) + inContext { + .init(LLVMBuildStore(p.llvm, value.llvm, location.llvm), in: context) + } } // MARK: Terminators @discardableResult public mutating func insertBr(to destination: BasicBlock, at p: InsertionPoint) -> Instruction { - .init(LLVMBuildBr(p.llvm, destination.llvm)) + inContext { + .init(LLVMBuildBr(p.llvm, destination.llvm), in: context) + } } @discardableResult @@ -634,33 +764,43 @@ public struct Module { if condition: IRValue, then t: BasicBlock, else e: BasicBlock, at p: InsertionPoint ) -> Instruction { - .init(LLVMBuildCondBr(p.llvm, condition.llvm, t.llvm, e.llvm)) + inContext { + .init(LLVMBuildCondBr(p.llvm, condition.llvm, t.llvm, e.llvm), in: context) + } } @discardableResult public mutating func insertSwitch>( on value: IRValue, cases: C, default defaultCase: BasicBlock, at p: InsertionPoint ) -> Instruction { - let s = LLVMBuildSwitch(p.llvm, value.llvm, defaultCase.llvm, UInt32(cases.count)) - for (value, destination) in cases { - LLVMAddCase(s, value.llvm, destination.llvm) + inContext { + let s = LLVMBuildSwitch(p.llvm, value.llvm, defaultCase.llvm, UInt32(cases.count)) + for (value, destination) in cases { + LLVMAddCase(s, value.llvm, destination.llvm) + } + return .init(s!, in: context) } - return .init(s!) } @discardableResult public mutating func insertReturn(at p: InsertionPoint) -> Instruction { - .init(LLVMBuildRetVoid(p.llvm)) + inContext { + .init(LLVMBuildRetVoid(p.llvm), in: context) + } } @discardableResult public mutating func insertReturn(_ value: IRValue, at p: InsertionPoint) -> Instruction { - .init(LLVMBuildRet(p.llvm, value.llvm)) + inContext { + .init(LLVMBuildRet(p.llvm, value.llvm), in: context) + } } @discardableResult public mutating func insertUnreachable(at p: InsertionPoint) -> Instruction { - .init(LLVMBuildUnreachable(p.llvm)) + inContext { + .init(LLVMBuildUnreachable(p.llvm), in: context) + } } // MARK: Aggregate operations @@ -670,7 +810,9 @@ public struct Module { at index: Int, at p: InsertionPoint ) -> Instruction { - .init(LLVMBuildExtractValue(p.llvm, whole.llvm, UInt32(index), "")) + inContext { + .init(LLVMBuildExtractValue(p.llvm, whole.llvm, UInt32(index), ""), in: context) + } } public mutating func insertInsertValue( @@ -679,7 +821,9 @@ public struct Module { into whole: IRValue, at p: InsertionPoint ) -> Instruction { - .init(LLVMBuildInsertValue(p.llvm, whole.llvm, part.llvm, UInt32(index), "")) + inContext { + .init(LLVMBuildInsertValue(p.llvm, whole.llvm, part.llvm, UInt32(index), ""), in: context) + } } // MARK: Conversions @@ -688,50 +832,64 @@ public struct Module { _ source: IRValue, to target: IRType, at p: InsertionPoint ) -> Instruction { - .init(LLVMBuildTrunc(p.llvm, source.llvm, target.llvm, "")) + inContext { + .init(LLVMBuildTrunc(p.llvm, source.llvm, target.llvm, ""), in: context) + } } public mutating func insertSignExtend( _ source: IRValue, to target: IRType, at p: InsertionPoint ) -> Instruction { - .init(LLVMBuildSExt(p.llvm, source.llvm, target.llvm, "")) + inContext { + .init(LLVMBuildSExt(p.llvm, source.llvm, target.llvm, ""), in: context) + } } public mutating func insertZeroExtend( _ source: IRValue, to target: IRType, at p: InsertionPoint ) -> Instruction { - .init(LLVMBuildZExt(p.llvm, source.llvm, target.llvm, "")) + inContext { + .init(LLVMBuildZExt(p.llvm, source.llvm, target.llvm, ""), in: context) + } } public mutating func insertIntToPtr( _ source: IRValue, to target: IRType? = nil, at p: InsertionPoint ) -> Instruction { - let t = target ?? PointerType(in: &self) - return .init(LLVMBuildIntToPtr(p.llvm, source.llvm, t.llvm, "")) + inContext { + let t = target ?? PointerType(in: &self) + return .init(LLVMBuildIntToPtr(p.llvm, source.llvm, t.llvm, ""), in: context) + } } public func insertPtrToInt( _ source: IRValue, to target: IRType, at p: InsertionPoint ) -> Instruction { - .init(LLVMBuildPtrToInt(p.llvm, source.llvm, target.llvm, "")) + inContext { + .init(LLVMBuildPtrToInt(p.llvm, source.llvm, target.llvm, ""), in: context) + } } public mutating func insertFPTrunc( _ source: IRValue, to target: IRType, at p: InsertionPoint ) -> Instruction { - .init(LLVMBuildFPTrunc(p.llvm, source.llvm, target.llvm, "")) + inContext { + .init(LLVMBuildFPTrunc(p.llvm, source.llvm, target.llvm, ""), in: context) + } } public mutating func insertFPExtend( _ source: IRValue, to target: IRType, at p: InsertionPoint ) -> Instruction { - .init(LLVMBuildFPExt(p.llvm, source.llvm, target.llvm, "")) + inContext { + .init(LLVMBuildFPExt(p.llvm, source.llvm, target.llvm, ""), in: context) + } } // MARK: Others @@ -741,7 +899,9 @@ public struct Module { on arguments: [IRValue], at p: InsertionPoint ) -> Instruction { - insertCall(callee, typed: callee.valueType, on: arguments, at: p) + inContext { + insertCall(callee, typed: callee.valueType, on: arguments, at: p) + } } public mutating func insertCall( @@ -750,8 +910,10 @@ public struct Module { on arguments: [IRValue], at p: InsertionPoint ) -> Instruction { - var a = arguments.map({ $0.llvm as Optional }) - return .init(LLVMBuildCall2(p.llvm, calleeType.llvm, callee.llvm, &a, UInt32(a.count), "")) + inContext { + var a = arguments.map({ $0.llvm as Optional }) + return .init(LLVMBuildCall2(p.llvm, calleeType.llvm, callee.llvm, &a, UInt32(a.count), ""), in: context) + } } public mutating func insertIntegerComparison( @@ -759,8 +921,10 @@ public struct Module { _ lhs: IRValue, _ rhs: IRValue, at p: InsertionPoint ) -> Instruction { - precondition(lhs.type == rhs.type) - return .init(LLVMBuildICmp(p.llvm, predicate.llvm, lhs.llvm, rhs.llvm, "")) + inContext { + precondition(lhs.type == rhs.type) + return .init(LLVMBuildICmp(p.llvm, predicate.llvm, lhs.llvm, rhs.llvm, ""), in: context) + } } public mutating func insertFloatingPointComparison( @@ -768,8 +932,10 @@ public struct Module { _ lhs: IRValue, _ rhs: IRValue, at p: InsertionPoint ) -> Instruction { - precondition(lhs.type == rhs.type) - return .init(LLVMBuildFCmp(p.llvm, predicate.llvm, lhs.llvm, rhs.llvm, "")) + inContext { + precondition(lhs.type == rhs.type) + return .init(LLVMBuildFCmp(p.llvm, predicate.llvm, lhs.llvm, rhs.llvm, ""), in: context) + } } } @@ -777,9 +943,11 @@ public struct Module { extension Module: CustomStringConvertible { public var description: String { - guard let s = LLVMPrintModuleToString(llvm) else { return "" } - defer { LLVMDisposeMessage(s) } - return String(cString: s) + inContext { + guard let s = LLVMPrintModuleToString(llvm) else { return "" } + defer { LLVMDisposeMessage(s) } + return String(cString: s) + } } } diff --git a/Sources/LLVM/Types/AnyType.swift b/Sources/LLVM/Types/AnyType.swift index 7304670..5e7e17f 100644 --- a/Sources/LLVM/Types/AnyType.swift +++ b/Sources/LLVM/Types/AnyType.swift @@ -6,9 +6,12 @@ internal struct AnyType: IRType, Hashable { /// A handle to the LLVM object wrapped by this instance. public let llvm: LLVMTypeRef - /// Creates an instance wrapping `llvm`. - internal init(_ llvm: LLVMTypeRef) { + public let context: ContextHandle + + /// Creates an instance wrapping `llvm` in `context`. + internal init(_ llvm: LLVMTypeRef, in context: ContextHandle) { self.llvm = llvm + self.context = context } } diff --git a/Sources/LLVM/Types/ArrayType.swift b/Sources/LLVM/Types/ArrayType.swift index 0c559e3..4ccf276 100644 --- a/Sources/LLVM/Types/ArrayType.swift +++ b/Sources/LLVM/Types/ArrayType.swift @@ -1,37 +1,47 @@ import llvmc /// An array type in LLVM IR. -public struct ArrayType: IRType, Hashable { +public struct ArrayType: IRType, Hashable, Contextual { /// A handle to the LLVM object wrapped by this instance. public let llvm: LLVMTypeRef + public let context: ContextHandle + /// Creates an instance representing arrays of `count` `element`s in `module`. public init(_ count: Int, _ element: IRType, in module: inout Module) { - precondition(LLVMGetTypeContext(element.llvm) == module.context) + context = module.context + precondition(LLVMGetTypeContext(element.llvm) == context.raw) self.llvm = LLVMArrayType(element.llvm, UInt32(count)) } /// Creates an instance with `t`, failing iff `t` isn't a void type. public init?(_ t: IRType) { - if LLVMGetTypeKind(t.llvm) == LLVMArrayTypeKind { + if (t.inContext { LLVMGetTypeKind(t.llvm) }) == LLVMArrayTypeKind { self.llvm = t.llvm + self.context = t.context } else { return nil } } /// The type of an element in instances of this type. - public var element: IRType { AnyType(LLVMGetElementType(llvm)) } + public var element: IRType { + inContext { + AnyType(LLVMGetElementType(llvm), in: context) + } + } /// The number of elements in instances of this type. - public var count: Int { Int(LLVMGetArrayLength(llvm)) } + public var count: Int { inContext { Int(LLVMGetArrayLength(llvm)) } } /// Returns a constant whose LLVM IR type is `self` and whose value is aggregating `elements`. public func constant( contentsOf elements: S, in module: inout Module ) -> ArrayConstant where S.Element == IRValue { - .init(of: self, containing: elements, in: &module) + inContext { + .init(of: self, containing: elements, in: &module) + } } } diff --git a/Sources/LLVM/Types/FloatingPointType.swift b/Sources/LLVM/Types/FloatingPointType.swift index 0cbcb69..bff0801 100644 --- a/Sources/LLVM/Types/FloatingPointType.swift +++ b/Sources/LLVM/Types/FloatingPointType.swift @@ -6,16 +6,20 @@ public struct FloatingPointType: IRType, Hashable { /// A handle to the LLVM object wrapped by this instance. public let llvm: LLVMTypeRef - /// Creates an instance wrapping `llvm`. - private init(_ llvm: LLVMTypeRef) { + public let context: ContextHandle + + /// Creates an instance wrapping `llvm` in `context`. + private init(_ llvm: LLVMTypeRef, in context: ContextHandle) { self.llvm = llvm + self.context = context } /// Creates an instance with `t`, failing iff `t` isn't a floating point type. public init?(_ t: IRType) { - switch LLVMGetTypeKind(t.llvm) { + switch (t.inContext { LLVMGetTypeKind(t.llvm) }) { case LLVMHalfTypeKind, LLVMFloatTypeKind, LLVMDoubleTypeKind, LLVMFP128TypeKind: self.llvm = t.llvm + self.context = t.context default: return nil } @@ -23,22 +27,22 @@ public struct FloatingPointType: IRType, Hashable { /// Returns the type `half` in `module` public static func half(in module: inout Module) -> Self { - .init(LLVMHalfTypeInContext(module.context)) + .init(LLVMHalfTypeInContext(module.context.raw), in: module.context) } /// Returns the type `float` in `module`. public static func float(in module: inout Module) -> Self { - .init(LLVMFloatTypeInContext(module.context)) + .init(LLVMFloatTypeInContext(module.context.raw), in: module.context) } /// Returns the type `double` in `module` public static func double(in module: inout Module) -> Self { - .init(LLVMDoubleTypeInContext(module.context)) + .init(LLVMDoubleTypeInContext(module.context.raw), in: module.context) } /// Returns the type `fp128` in `module` public static func fp128(in module: inout Module) -> Self { - .init(LLVMFP128TypeInContext(module.context)) + .init(LLVMFP128TypeInContext(module.context.raw), in: module.context) } /// Returns a constant whose LLVM IR type is `self` and whose value is `v`. @@ -48,19 +52,19 @@ public struct FloatingPointType: IRType, Hashable { /// Returns a constant whose LLVM IR type is `self` and whose value is `v`. public func constant(_ v: Double) -> FloatingPointConstant { - .init(LLVMConstReal(llvm, v)) + .init(LLVMConstReal(llvm, v), in: context) } /// Returns a constant whose LLVM IR type is `self` and whose value is parsed from `text`. /// /// Zero is returned if `text` is not a valid floating-point value. public func constant(parsing text: String) -> FloatingPointConstant { - .init(text.withCString({ LLVMConstRealOfStringAndSize(llvm, $0, UInt32(text.utf8.count)) })) + .init(text.withCString({ LLVMConstRealOfStringAndSize(llvm, $0, UInt32(text.utf8.count)) }), in: context) } /// The zero value of this type. public var zero: FloatingPointConstant { - .init(LLVMConstNull(llvm)) + .init(LLVMConstNull(llvm), in: context) } } diff --git a/Sources/LLVM/Types/FunctionType.swift b/Sources/LLVM/Types/FunctionType.swift index 0180c0e..5eaf4dd 100644 --- a/Sources/LLVM/Types/FunctionType.swift +++ b/Sources/LLVM/Types/FunctionType.swift @@ -6,34 +6,42 @@ public struct FunctionType: IRType, Hashable { /// A handle to the LLVM object wrapped by this instance. public let llvm: LLVMTypeRef + public let context: ContextHandle + /// Creates an instance with given `parameters` and `returnType` in `module`. /// /// The return type is `void` if `returnType` is passed `nil`. public init(from parameters: [IRType], to returnType: IRType? = nil, in module: inout Module) { + self.context = module.context let r = returnType ?? VoidType(in: &module) - self.llvm = parameters.withHandles { (p) in - LLVMFunctionType(r.llvm, p.baseAddress, UInt32(p.count), 0) + self.llvm = module.inContext { + parameters.withHandles { (p) in + LLVMFunctionType(r.llvm, p.baseAddress, UInt32(p.count), 0) + } } } /// Creates an instance with `t`, failing iff `t` isn't a function type. public init?(_ t: IRType) { - if LLVMGetTypeKind(t.llvm) == LLVMFunctionTypeKind { + if (t.inContext { LLVMGetTypeKind(t.llvm) }) == LLVMFunctionTypeKind { self.llvm = t.llvm + self.context = t.context } else { return nil } } /// The return type of the function. - public var returnType: IRType { AnyType(LLVMGetReturnType(llvm)) } + public var returnType: IRType { AnyType(LLVMGetReturnType(llvm), in: context) } /// The parameters of the function. public var parameters: [IRType] { - let n = LLVMCountParamTypes(llvm) - var handles: [LLVMAttributeRef?] = .init(repeating: nil, count: Int(n)) - LLVMGetParamTypes(llvm, &handles) - return handles.map({ AnyType($0!) as IRType }) + inContext { + let n = LLVMCountParamTypes(llvm) + var handles: [LLVMAttributeRef?] = .init(repeating: nil, count: Int(n)) + LLVMGetParamTypes(llvm, &handles) + return handles.map({ AnyType($0!, in: context) as IRType }) + } } } diff --git a/Sources/LLVM/Types/IRType.swift b/Sources/LLVM/Types/IRType.swift index 215fa90..df5b222 100644 --- a/Sources/LLVM/Types/IRType.swift +++ b/Sources/LLVM/Types/IRType.swift @@ -1,7 +1,7 @@ import llvmc /// The type of a value in LLVM IR. -public protocol IRType: CustomStringConvertible { +public protocol IRType: CustomStringConvertible, Contextual { /// A handle to the LLVM object wrapped by this instance. var llvm: LLVMTypeRef { get } @@ -12,16 +12,22 @@ extension IRType { /// A string representation of the type. public var description: String { - guard let s = LLVMPrintTypeToString(llvm) else { return "" } - defer { LLVMDisposeMessage(s) } - return String(cString: s) + inContext { + guard let s = LLVMPrintTypeToString(llvm) else { return "" } + defer { LLVMDisposeMessage(s) } + return String(cString: s) + } } /// `true` if the size of the type is known. - public var isSized: Bool { LLVMTypeIsSized(llvm) != 0 } + public var isSized: Bool { + inContext { LLVMTypeIsSized(llvm) != 0 } + } /// The `null` instance of this type (e.g., the zero of `i32`). - public var null: IRValue { AnyValue(LLVMConstNull(llvm)) } + public var null: IRValue { + inContext { AnyValue(LLVMConstNull(llvm), in: context) } + } /// Returns `true` iff `lhs` is equal to `rhs`. public static func == (lhs: Self, rhs: R) -> Bool { diff --git a/Sources/LLVM/Types/IntegerType.swift b/Sources/LLVM/Types/IntegerType.swift index 9502f0c..070dc02 100644 --- a/Sources/LLVM/Types/IntegerType.swift +++ b/Sources/LLVM/Types/IntegerType.swift @@ -6,22 +6,27 @@ public struct IntegerType: IRType, Hashable { /// A handle to the LLVM object wrapped by this instance. public let llvm: LLVMTypeRef + public let context: ContextHandle + /// Creates an instance with given `bitWidth` in `module`. /// /// - Requires: `bitWidth` is greater than 0. public init(_ bitWidth: Int, in module: inout Module) { - self.llvm = LLVMIntTypeInContext(module.context, UInt32(bitWidth)) + self.context = module.context + self.llvm = module.inContext { LLVMIntTypeInContext(module.context.raw, UInt32(bitWidth)) } } /// Creates an instance with `t`, failing iff `t` isn't an integer type. public init?(_ t: IRType) { - guard LLVMGetTypeKind(t.llvm) == LLVMIntegerTypeKind else { return nil } + guard (t.inContext { LLVMGetTypeKind(t.llvm) == LLVMIntegerTypeKind }) else { return nil } + self.context = t.context self.llvm = t.llvm } /// Creates an instance wrapping `llvm`. - internal init(_ llvm: LLVMTypeRef) { + internal init(_ llvm: LLVMTypeRef, in context: ContextHandle) { self.llvm = llvm + self.context = context } /// The number of bits in the representation of the type's instances. @@ -38,7 +43,7 @@ public struct IntegerType: IRType, Hashable { /// Returns a constant whose LLVM IR type is `self` and whose value is `v`, truncating or /// sign-extending if needed to fit `self.bitWidth`. public func constant(_ v: T) -> LLVM.IntegerConstant { - .init(LLVMConstInt(llvm, UInt64(truncatingIfNeeded: v), 0)) + .init(LLVMConstInt(llvm, UInt64(truncatingIfNeeded: v), 0), in: context) } /// Returns a constant whose LLVM IR type is `self` and whose value is parsed from `text` with @@ -51,19 +56,19 @@ public struct IntegerType: IRType, Hashable { let h = text.withCString { (s) in LLVMConstIntOfStringAndSize(llvm, s, UInt32(text.utf8.count), UInt8(radix))! } - return .init(h) + return .init(h, in: context) } /// Returns a constant whose LLVM IR type is `self` and whose value's binary presentation is /// `words`, from least to most significant. public func constant>(words: Words) -> IntegerConstant { let w = Array(words) - return .init(LLVMConstIntOfArbitraryPrecision(llvm, UInt32(w.count), w)) + return .init(LLVMConstIntOfArbitraryPrecision(llvm, UInt32(w.count), w), in: context) } /// The zero value of this type. public var zero: IntegerConstant { - .init(LLVMConstNull(llvm)) + .init(LLVMConstNull(llvm), in: context) } } diff --git a/Sources/LLVM/Types/PointerType.swift b/Sources/LLVM/Types/PointerType.swift index d845033..0c54d4b 100644 --- a/Sources/LLVM/Types/PointerType.swift +++ b/Sources/LLVM/Types/PointerType.swift @@ -6,15 +6,19 @@ public struct PointerType: IRType, Hashable { /// A handle to the LLVM object wrapped by this instance. public let llvm: LLVMTypeRef - /// Creates an instance wrapping `llvm`. - private init(_ llvm: LLVMTypeRef) { + public let context: ContextHandle + + /// Creates an instance wrapping `llvm` in `context`. + private init(_ llvm: LLVMTypeRef, in context: ContextHandle) { self.llvm = llvm + self.context = context } /// Creates an instance with `t`, failing iff `t` isn't a pointer type. public init?(_ t: IRType) { - if LLVMGetTypeKind(t.llvm) == LLVMPointerTypeKind { + if (t.inContext { LLVMGetTypeKind(t.llvm) == LLVMPointerTypeKind }) { self.llvm = t.llvm + self.context = t.context } else { return nil } @@ -22,7 +26,9 @@ public struct PointerType: IRType, Hashable { /// Creates an opaque pointer type in address space `s` in `module`. public init(inAddressSpace s: AddressSpace = .default, in module: inout Module) { - self.init(LLVMPointerTypeInContext(module.context, s.llvm)) + self = module.inContext { + .init(LLVMPointerTypeInContext(module.context.raw, s.llvm), in: module.context) + } } /// The address space of the pointer. diff --git a/Sources/LLVM/Types/StructType.swift b/Sources/LLVM/Types/StructType.swift index 3844976..611e2ff 100644 --- a/Sources/LLVM/Types/StructType.swift +++ b/Sources/LLVM/Types/StructType.swift @@ -6,10 +6,15 @@ public struct StructType: IRType, Hashable { /// A handle to the LLVM object wrapped by this instance. public let llvm: LLVMTypeRef + public let context: ContextHandle + /// Creates an instance with given `fields` in `module`, packed iff `packed` is `true`. public init(_ fields: [IRType], packed: Bool = false, in module: inout Module) { - self.llvm = fields.withHandles { (f) in - LLVMStructTypeInContext(module.context, f.baseAddress, UInt32(f.count), packed ? 1 : 0) + context = module.context + self.llvm = module.inContext { + fields.withHandles { (f) in + LLVMStructTypeInContext(module.context.raw, f.baseAddress, UInt32(f.count), packed ? 1 : 0) + } } } @@ -20,16 +25,21 @@ public struct StructType: IRType, Hashable { public init( named name: String, _ fields: [IRType], packed: Bool = false, in module: inout Module ) { - self.llvm = LLVMStructCreateNamed(module.context, name) - fields.withHandles { (f) in - LLVMStructSetBody(self.llvm, f.baseAddress, UInt32(f.count), packed ? 1 : 0) + context = module.context + self.llvm = module.inContext { + let llvm = LLVMStructCreateNamed(module.context.raw, name) + fields.withHandles { (f) in + LLVMStructSetBody(llvm, f.baseAddress, UInt32(f.count), packed ? 1 : 0) + } + return llvm! } } /// Creates an instance with `t`, failing iff `t` isn't a struct type. public init?(_ t: IRType) { - if LLVMGetTypeKind(t.llvm) == LLVMStructTypeKind { + if (t.inContext { LLVMGetTypeKind(t.llvm) }) == LLVMStructTypeKind { self.llvm = t.llvm + self.context = t.context } else { return nil } @@ -37,27 +47,39 @@ public struct StructType: IRType, Hashable { /// The name of the struct. public var name: String? { - guard let s = LLVMGetStructName(llvm) else { return nil } - return String(cString: s) + inContext { + guard let s = LLVMGetStructName(llvm) else { return nil } + return String(cString: s) + } } /// `true` iff the fields of the struct are packed. - public var isPacked: Bool { LLVMIsPackedStruct(llvm) != 0 } + public var isPacked: Bool { + inContext {LLVMIsPackedStruct(llvm) != 0 } + } /// `true` iff the struct is opaque. - public var isOpaque: Bool { LLVMIsOpaqueStruct(llvm) != 0 } + public var isOpaque: Bool { + inContext {LLVMIsOpaqueStruct(llvm) != 0 } + } /// `true` iff the struct is literal. - public var isLiteral: Bool { LLVMIsLiteralStruct(llvm) != 0 } + public var isLiteral: Bool { + inContext {LLVMIsLiteralStruct(llvm) != 0 } + } /// The fields of the struct. - public var fields: Fields { .init(of: self) } + public var fields: Fields { + inContext {.init(of: self) } + } /// Returns a constant whose LLVM IR type is `self` and whose value is aggregating `parts`. public func constant( aggregating elements: S, in module: inout Module ) -> StructConstant where S.Element == IRValue { - .init(of: self, aggregating: elements, in: &module) + inContext { + .init(of: self, aggregating: elements, in: &module) + } } } @@ -81,7 +103,9 @@ extension StructType { /// The number of fields in the collection. public var count: Int { - Int(LLVMCountStructElementTypes(parent.llvm)) + parent.inContext { + Int(LLVMCountStructElementTypes(parent.llvm)) + } } public var startIndex: Int { 0 } @@ -100,7 +124,7 @@ extension StructType { public subscript(position: Int) -> IRType { precondition(position >= 0 && position < count, "index is out of bounds") - return AnyType(LLVMStructGetTypeAtIndex(parent.llvm, UInt32(position))) + return parent.inContext { AnyType(LLVMStructGetTypeAtIndex(parent.llvm, UInt32(position)), in: parent.context) } } } diff --git a/Sources/LLVM/Types/VoidType.swift b/Sources/LLVM/Types/VoidType.swift index b7829ca..e385c3c 100644 --- a/Sources/LLVM/Types/VoidType.swift +++ b/Sources/LLVM/Types/VoidType.swift @@ -6,15 +6,19 @@ public struct VoidType: IRType, Hashable { /// A handle to the LLVM object wrapped by this instance. public let llvm: LLVMTypeRef + public let context: ContextHandle + /// Creates an instance in `module`. public init(in module: inout Module) { - self.llvm = LLVMVoidTypeInContext(module.context) + self.context = module.context + self.llvm = module.inContext { LLVMVoidTypeInContext(module.context.raw) } } /// Creates an instance with `t`, failing iff `t` isn't a void type. public init?(_ t: IRType) { - if LLVMGetTypeKind(t.llvm) == LLVMVoidTypeKind { + if (t.inContext { LLVMGetTypeKind(t.llvm) == LLVMVoidTypeKind }) { self.llvm = t.llvm + self.context = t.context } else { return nil } diff --git a/Sources/LLVM/Values/Constants/AggregateConstant.swift b/Sources/LLVM/Values/Constants/AggregateConstant.swift index ee2eaa5..d4181c5 100644 --- a/Sources/LLVM/Values/Constants/AggregateConstant.swift +++ b/Sources/LLVM/Values/Constants/AggregateConstant.swift @@ -26,7 +26,7 @@ extension AggregateConstant where Index == Int, Element == IRValue { public subscript(position: Int) -> IRValue { precondition(position >= 0 && position < count, "index is out of bounds") - return AnyValue(LLVMGetAggregateElement(llvm, UInt32(position))) + return inContext{ AnyValue(LLVMGetAggregateElement(llvm, UInt32(position)), in: context) } } } diff --git a/Sources/LLVM/Values/Constants/AnyValue.swift b/Sources/LLVM/Values/Constants/AnyValue.swift index cebb53c..63691c1 100644 --- a/Sources/LLVM/Values/Constants/AnyValue.swift +++ b/Sources/LLVM/Values/Constants/AnyValue.swift @@ -6,9 +6,12 @@ internal struct AnyValue: IRValue { /// A handle to the LLVM object wrapped by this instance. public let llvm: LLVMValueRef - /// Creates an instance wrapping `llvm`. - internal init(_ llvm: LLVMValueRef) { + public let context: ContextHandle + + /// Creates an instance wrapping `llvm` in `context`. + internal init(_ llvm: LLVMValueRef, in context: ContextHandle) { self.llvm = llvm + self.context = context } } diff --git a/Sources/LLVM/Values/Constants/ArrayConstant.swift b/Sources/LLVM/Values/Constants/ArrayConstant.swift index 463a734..255d2ee 100644 --- a/Sources/LLVM/Values/Constants/ArrayConstant.swift +++ b/Sources/LLVM/Values/Constants/ArrayConstant.swift @@ -9,6 +9,8 @@ public struct ArrayConstant: Hashable { /// The number of elements in the array. public let count: Int + public let context: ContextHandle + /// Creates a constant array of `type` in `module`, filled with the contents of `elements`. /// /// - Requires: The type of each element in `contents` is `type`. @@ -16,7 +18,8 @@ public struct ArrayConstant: Hashable { of type: IRType, containing elements: S, in module: inout Module ) where S.Element == IRValue { var values = elements.map({ $0.llvm as Optional }) - self.llvm = LLVMConstArray(type.llvm, &values, UInt32(values.count)) + self.llvm = module.inContext { LLVMConstArray(type.llvm, &values, UInt32(values.count)) } + self.context = module.context self.count = values.count } diff --git a/Sources/LLVM/Values/Constants/Attribute.swift b/Sources/LLVM/Values/Constants/Attribute.swift index 13b1ae3..cbe964f 100644 --- a/Sources/LLVM/Values/Constants/Attribute.swift +++ b/Sources/LLVM/Values/Constants/Attribute.swift @@ -40,7 +40,7 @@ public enum Attribute: Hashable { /// Creates a target-independent attribute with given `name` and optional `value` in `module`. public init(_ name: T.AttributeName, _ value: UInt64 = 0, in module: inout Module) { - self = .targetIndependent(llvm: LLVMCreateEnumAttribute(module.context, name.id, value)!) + self = .targetIndependent(llvm: LLVMCreateEnumAttribute(module.context.raw, name.id, value)!) } /// The value of the attribute if it is target-independent. diff --git a/Sources/LLVM/Values/Constants/FloatingPointConstant.swift b/Sources/LLVM/Values/Constants/FloatingPointConstant.swift index 1a17423..4780bc3 100644 --- a/Sources/LLVM/Values/Constants/FloatingPointConstant.swift +++ b/Sources/LLVM/Values/Constants/FloatingPointConstant.swift @@ -1,4 +1,5 @@ import llvmc +import llvmshims /// A constant floating-point number in LLVM IR. public struct FloatingPointConstant: IRValue, Hashable { @@ -6,15 +7,19 @@ public struct FloatingPointConstant: IRValue, Hashable { /// A handle to the LLVM object wrapped by this instance. public let llvm: LLVMValueRef - /// Creates an instance wrapping `llvm`. - internal init(_ llvm: LLVMValueRef) { + public let context: ContextHandle + + /// Creates an instance wrapping `llvm` in `context`. + internal init(_ llvm: LLVMValueRef, in context: ContextHandle) { self.llvm = llvm + self.context = context } /// Creates an instance with `v`, failing iff `v` isn't a constant floating-point number. public init?(_ v: IRValue) { - if let h = LLVMIsAConstantFP(v.llvm) { + if let h = (v.inContext { LLVMIsAConstantFP(v.llvm) }) { self.llvm = h + self.context = v.context } else { return nil } @@ -23,9 +28,11 @@ public struct FloatingPointConstant: IRValue, Hashable { /// A pair `(v, l)` where `v` is the value of this constant and `l` is `true` iff /// precision was lost in the conversion. public var value: (value: Double, lostPrecision: Bool) { - var l: Int32 = 0 - let v = LLVMConstRealGetDouble(llvm, &l) - return (v, l != 0) + inContext { + var l: Int32 = 0 + let v = LLVMConstRealGetDouble(llvm, &l) + return (v, l != 0) + } } } diff --git a/Sources/LLVM/Values/Constants/Function.swift b/Sources/LLVM/Values/Constants/Function.swift index 3e48cee..ae11f48 100644 --- a/Sources/LLVM/Values/Constants/Function.swift +++ b/Sources/LLVM/Values/Constants/Function.swift @@ -6,15 +6,19 @@ public struct Function: Global, Hashable { /// A handle to the LLVM object wrapped by this instance. public let llvm: LLVMValueRef - /// Creates an instance wrapping `llvm`. - internal init(_ llvm: LLVMValueRef) { + public let context: ContextHandle + + /// Creates an instance wrapping `llvm` in `context`. + internal init(_ llvm: LLVMValueRef, in context: ContextHandle) { self.llvm = llvm + self.context = context } /// Creates an instance with `v`, failing iff `v` isn't a function. public init?(_ v: IRValue) { - if let h = LLVMIsAFunction(v.llvm) { + if let h = (v.inContext { LLVMIsAFunction(v.llvm) }) { self.llvm = h + self.context = v.context } else { return nil } @@ -25,21 +29,27 @@ public struct Function: Global, Hashable { /// The basic blocks of the function. public var basicBlocks: [BasicBlock] { - let n = LLVMCountBasicBlocks(llvm) - var handles: [LLVMBasicBlockRef?] = .init(repeating: nil, count: Int(n)) - LLVMGetBasicBlocks(llvm, &handles) - return handles.map({ .init($0!) }) + inContext{ + let n = LLVMCountBasicBlocks(llvm) + var handles: [LLVMBasicBlockRef?] = .init(repeating: nil, count: Int(n)) + LLVMGetBasicBlocks(llvm, &handles) + return handles.map({ .init($0!, in: context) }) + } } /// The the function's entry, if any. public var entry: BasicBlock? { - guard LLVMCountBasicBlocks(llvm) > 0 else { return nil } - return .init(LLVMGetEntryBasicBlock(llvm)) + inContext{ + guard LLVMCountBasicBlocks(llvm) > 0 else { return nil } + return .init(LLVMGetEntryBasicBlock(llvm), in: context) + } } /// Returns `true` iff the IR in `self` is well formed. public func isWellFormed() -> Bool { - LLVMVerifyFunction(llvm, LLVMReturnStatusAction) == 0 + inContext{ + LLVMVerifyFunction(llvm, LLVMReturnStatusAction) == 0 + } } } @@ -103,7 +113,7 @@ extension Function { public subscript(position: Int) -> Parameter { precondition(position >= 0 && position < count, "index is out of bounds") - return .init(LLVMGetParam(parent.llvm, UInt32(position)), position) + return .init(LLVMGetParam(parent.llvm, UInt32(position)), position, in: parent.context) } } diff --git a/Sources/LLVM/Values/Constants/IntegerConstant.swift b/Sources/LLVM/Values/Constants/IntegerConstant.swift index 824fcc3..18ea01b 100644 --- a/Sources/LLVM/Values/Constants/IntegerConstant.swift +++ b/Sources/LLVM/Values/Constants/IntegerConstant.swift @@ -6,15 +6,19 @@ public struct IntegerConstant: IRValue, Hashable { /// A handle to the LLVM object wrapped by this instance. public let llvm: LLVMValueRef - /// Creates an instance wrapping `llvm`. - internal init(_ llvm: LLVMValueRef) { + public let context: ContextHandle + + /// Creates an instance wrapping `llvm` in `context`. + internal init(_ llvm: LLVMValueRef, in context: ContextHandle) { self.llvm = llvm + self.context = context } /// Creates an instance with `v`, failing iff `v` isn't a constant integer value. public init?(_ v: IRValue) { - if let h = LLVMIsAConstantInt(v.llvm) { + if let h = (v.inContext { LLVMIsAConstantInt(v.llvm) }) { self.llvm = h + self.context = v.context } else { return nil } diff --git a/Sources/LLVM/Values/Constants/Intrinsic.swift b/Sources/LLVM/Values/Constants/Intrinsic.swift index a80bbe3..af2ca6d 100644 --- a/Sources/LLVM/Values/Constants/Intrinsic.swift +++ b/Sources/LLVM/Values/Constants/Intrinsic.swift @@ -11,9 +11,12 @@ public struct Intrinsic: Global, Hashable { /// A handle to the LLVM object wrapped by this instance. public let llvm: LLVMValueRef - /// Creates an instance wrapping `llvm`. - internal init(_ llvm: LLVMValueRef) { + public let context: ContextHandle + + /// Creates an instance wrapping `llvm` in `context`. + internal init(_ llvm: LLVMValueRef, in context: ContextHandle) { self.llvm = llvm + self.context = context } /// The intrinsic's identifier. diff --git a/Sources/LLVM/Values/Constants/Parameter.swift b/Sources/LLVM/Values/Constants/Parameter.swift index 1b0c287..5874b98 100644 --- a/Sources/LLVM/Values/Constants/Parameter.swift +++ b/Sources/LLVM/Values/Constants/Parameter.swift @@ -9,24 +9,28 @@ public struct Parameter: IRValue { /// The index of the parameter in its function. public let index: Int + public let context: ContextHandle + /// Creates an instance wrapping `llvm`, which represents the `i`-th parameter of a function. - internal init(_ llvm: LLVMValueRef, _ i: Int) { + internal init(_ llvm: LLVMValueRef, _ i: Int, in context: ContextHandle) { + self.context = context self.llvm = llvm self.index = i } /// Creates an intance with `v`, failing iff `v` is not a parameter. public init?(_ v: IRValue) { - if let h = LLVMIsAArgument(v.llvm) { + if let h = (v.inContext { LLVMIsAArgument(v.llvm) }) { self.llvm = h - self.index = Function(LLVMGetParamParent(h)).parameters.firstIndex(where: { $0.llvm == h })! + self.context = v.context + self.index = Function(LLVMGetParamParent(h), in: v.context).parameters.firstIndex(where: { $0.llvm == h })! } else { return nil } } /// The function containing the parameter. - public var parent: Function { .init(LLVMGetParamParent(llvm)) } + public var parent: Function { inContext { .init(LLVMGetParamParent(llvm), in: context) } } } diff --git a/Sources/LLVM/Values/Constants/Poison.swift b/Sources/LLVM/Values/Constants/Poison.swift index 3e1696c..2e79ac8 100644 --- a/Sources/LLVM/Values/Constants/Poison.swift +++ b/Sources/LLVM/Values/Constants/Poison.swift @@ -6,15 +6,19 @@ public struct Poison: IRValue, Hashable { /// A handle to the LLVM object wrapped by this instance. public let llvm: LLVMValueRef + public let context: ContextHandle + /// Creates the poison value of `t`. public init(of t: IRType) { - self.llvm = LLVMGetPoison(t.llvm) + self.llvm = t.inContext { LLVMGetPoison(t.llvm) } + self.context = t.context } /// Creates an intance with `v`, failing iff `v` is not a poison value. public init?(_ v: IRValue) { - if let h = LLVMIsAPoisonValue(v.llvm) { + if let h = (v.inContext { LLVMIsAPoisonValue(v.llvm) }) { self.llvm = h + self.context = v.context } else { return nil } diff --git a/Sources/LLVM/Values/Constants/StringConstant.swift b/Sources/LLVM/Values/Constants/StringConstant.swift index b0d81ce..8fde94d 100644 --- a/Sources/LLVM/Values/Constants/StringConstant.swift +++ b/Sources/LLVM/Values/Constants/StringConstant.swift @@ -6,18 +6,24 @@ public struct StringConstant: IRValue, Hashable { /// A handle to the LLVM object wrapped by this instance. public let llvm: LLVMValueRef + public let context: ContextHandle + /// Creates an instance with `text` in `module`, appending a null terminator to the string iff /// `nullTerminated` is `true`. public init(_ text: String, nullTerminated: Bool = true, in module: inout Module) { - self.llvm = text.withCString { (s) in - LLVMConstStringInContext(module.context, s, UInt32(text.utf8.count), nullTerminated ? 0 : 1) + self.context = module.context + self.llvm = module.inContext { + text.withCString { (s) in + LLVMConstStringInContext(module.context.raw, s, UInt32(text.utf8.count), nullTerminated ? 0 : 1) + } } } /// Creates an instance with `v`, failing iff `v` is not a constant string value. public init?(_ v: IRValue) { - if LLVMIsAConstantDataSequential(v.llvm) != nil && LLVMIsConstantString(v.llvm) != 0 { + if (v.inContext { LLVMIsAConstantDataSequential(v.llvm) != nil && LLVMIsConstantString(v.llvm) != 0 }) { self.llvm = v.llvm + self.context = v.context } else { return nil } @@ -25,12 +31,14 @@ public struct StringConstant: IRValue, Hashable { /// The value of this constant. public var value: String { - .init(from: llvm) { (h, count) in - // Decrement `count` if the string is null-terminated. - guard let s = LLVMGetAsString(h, count) else { return nil } - if s[count!.pointee - 1] == 0 { count!.pointee -= 1 } - return s - } ?? "" + inContext { + .init(from: llvm) { (h, count) in + // Decrement `count` if the string is null-terminated. + guard let s = LLVMGetAsString(h, count) else { return nil } + if s[count!.pointee - 1] == 0 { count!.pointee -= 1 } + return s + } ?? "" + } } } diff --git a/Sources/LLVM/Values/Constants/StructConstant.swift b/Sources/LLVM/Values/Constants/StructConstant.swift index aa4eb5d..cedd0af 100644 --- a/Sources/LLVM/Values/Constants/StructConstant.swift +++ b/Sources/LLVM/Values/Constants/StructConstant.swift @@ -9,6 +9,8 @@ public struct StructConstant: Hashable { /// The number of elements in the struct. public let count: Int + public let context: ContextHandle + /// Creates a constant struct of `type` in `module` aggregating `elements`. /// /// - Requires: The type of `contents[i]` has the same type as the `i`-th element of `type`. @@ -16,7 +18,8 @@ public struct StructConstant: Hashable { of type: StructType, aggregating elements: S, in module: inout Module ) where S.Element == IRValue { var values = elements.map({ $0.llvm as Optional }) - self.llvm = LLVMConstNamedStruct(type.llvm, &values, UInt32(values.count)) + self.context = type.context + self.llvm = type.inContext { LLVMConstNamedStruct(type.llvm, &values, UInt32(values.count)) } self.count = values.count } @@ -26,8 +29,10 @@ public struct StructConstant: Hashable { aggregating elements: S, packed isPacked: Bool = false, in module: inout Module ) where S.Element == IRValue { var values = elements.map({ $0.llvm as Optional }) - self.llvm = LLVMConstStructInContext( - module.context, &values, UInt32(values.count), isPacked ? 1 : 0) + self.context = module.context + self.llvm = module.inContext { + LLVMConstStructInContext( + module.context.raw, &values, UInt32(values.count), isPacked ? 1 : 0)} self.count = values.count } diff --git a/Sources/LLVM/Values/Constants/Undefined.swift b/Sources/LLVM/Values/Constants/Undefined.swift index b8a4b1e..75ce662 100644 --- a/Sources/LLVM/Values/Constants/Undefined.swift +++ b/Sources/LLVM/Values/Constants/Undefined.swift @@ -6,15 +6,19 @@ public struct Undefined: IRValue, Hashable { /// A handle to the LLVM object wrapped by this instance. public let llvm: LLVMValueRef + public let context: ContextHandle + /// Creates an undefined value of type `t`. public init(of t: IRType) { - self.llvm = LLVMGetUndef(t.llvm) + self.context = t.context + self.llvm = t.inContext { LLVMGetUndef(t.llvm) } } /// Creates an instance with `v`, failing iff `v` is not an undefined value. public init?(_ v: IRValue) { - if let h = LLVMIsAUndefValue(v.llvm) { + if let h = ( v.inContext { LLVMIsAUndefValue(v.llvm) } ) { self.llvm = h + self.context = v.context } else { return nil } diff --git a/Sources/LLVM/Values/Global.swift b/Sources/LLVM/Values/Global.swift index ca5e2b6..4b93384 100644 --- a/Sources/LLVM/Values/Global.swift +++ b/Sources/LLVM/Values/Global.swift @@ -9,12 +9,14 @@ extension Global { /// /// This "value type" of a global differs from its formal type, which is always a pointer type. public var valueType: IRType { - AnyType(LLVMGlobalGetValueType(llvm)) + AnyType(LLVMGlobalGetValueType(llvm), in: context) } /// The linkage of this global. public var linkage: Linkage { - .init(llvm: LLVMGetLinkage(llvm)) + inContext { + .init(llvm: LLVMGetLinkage(llvm)) + } } } diff --git a/Sources/LLVM/Values/GlobalVariable.swift b/Sources/LLVM/Values/GlobalVariable.swift index 29a2353..2095960 100644 --- a/Sources/LLVM/Values/GlobalVariable.swift +++ b/Sources/LLVM/Values/GlobalVariable.swift @@ -6,9 +6,12 @@ public struct GlobalVariable: Global { /// A handle to the LLVM object wrapped by this instance. public let llvm: LLVMValueRef + public let context: ContextHandle + /// Creates an instance wrapping `llvm`. - internal init(_ llvm: LLVMValueRef) { + internal init(_ llvm: LLVMValueRef, in context: ContextHandle) { self.llvm = llvm + self.context = context } /// `true` if this value is constant. @@ -24,6 +27,6 @@ public struct GlobalVariable: Global { public var isExternallyInitialized: Bool { LLVMIsExternallyInitialized(llvm) != 0 } /// The initial value of this global. - public var initializer: IRValue? { LLVMGetInitializer(llvm).map(AnyValue.init(_:)) } + public var initializer: IRValue? { LLVMGetInitializer(llvm).map { AnyValue($0, in: context) } } } diff --git a/Sources/LLVM/Values/IRValue.swift b/Sources/LLVM/Values/IRValue.swift index 851891c..1557952 100644 --- a/Sources/LLVM/Values/IRValue.swift +++ b/Sources/LLVM/Values/IRValue.swift @@ -1,7 +1,7 @@ import llvmc /// A value in LLVM IR. -public protocol IRValue: CustomStringConvertible { +public protocol IRValue: CustomStringConvertible, Contextual { /// A handle to the LLVM object wrapped by this instance. var llvm: LLVMValueRef { get } @@ -18,7 +18,7 @@ extension IRValue { } /// The LLVM IR type of this value. - public var type: IRType { AnyType(LLVMTypeOf(llvm)) } + public var type: IRType { AnyType(LLVMTypeOf(llvm), in: context) } /// The name of this value. public var name: String { String(from: llvm, readingWith: LLVMGetValueName2(_:_:)) ?? "" } diff --git a/Sources/LLVM/Values/Instructions/Alloca.swift b/Sources/LLVM/Values/Instructions/Alloca.swift index 44288ea..b7e3f69 100644 --- a/Sources/LLVM/Values/Instructions/Alloca.swift +++ b/Sources/LLVM/Values/Instructions/Alloca.swift @@ -6,24 +6,28 @@ public struct Alloca: IRValue { /// A handle to the LLVM object wrapped by this instance. public let llvm: LLVMValueRef - /// Creates an instance wrapping `llvm`. - internal init(_ llvm: LLVMValueRef) { + public let context: ContextHandle + + /// Creates an instance wrapping `llvm` in `context`. + internal init(_ llvm: LLVMValueRef, in context: ContextHandle) { self.llvm = llvm + self.context = context } /// Creates an instance with `s`, failing iff `s` isn't an `alloca` public init?(_ s: IRValue) { - if let h = LLVMIsAAllocaInst(s.llvm) { + if let h = (s.inContext { LLVMIsAAllocaInst(s.llvm) }) { self.llvm = h + self.context = s.context } else { return nil } } /// The type of the value allocated by the instruction. - public var allocatedType: IRType { AnyType(LLVMGetAllocatedType(llvm)) } + public var allocatedType: IRType { inContext { AnyType(LLVMGetAllocatedType(llvm), in: context) } } /// The preferred alignment of the allocated memory. - public var alignment: Int { Int(LLVMGetAlignment(llvm)) } + public var alignment: Int { inContext { Int(LLVMGetAlignment(llvm)) } } } diff --git a/Sources/LLVM/Values/Instructions/Instruction.swift b/Sources/LLVM/Values/Instructions/Instruction.swift index c17a79e..5cf921f 100644 --- a/Sources/LLVM/Values/Instructions/Instruction.swift +++ b/Sources/LLVM/Values/Instructions/Instruction.swift @@ -6,9 +6,12 @@ public struct Instruction: IRValue, Hashable { /// A handle to the LLVM object wrapped by this instance. public let llvm: LLVMValueRef - /// Creates an instance wrapping `llvm`. - internal init(_ llvm: LLVMValueRef) { + public let context: ContextHandle + + /// Creates an instance wrapping `llvm` in `context`. + internal init(_ llvm: LLVMValueRef, in context: ContextHandle) { self.llvm = llvm + self.context = context } }