|
2 | 2 | import cllvm
|
3 | 3 | #endif
|
4 | 4 |
|
| 5 | +/// Enumerates the supported models of reference of thread-local variables. |
| 6 | +/// |
| 7 | +/// These models are listed from the most general, but least optimized, to the |
| 8 | +/// fastest, but most restrictive. |
| 9 | +/// |
| 10 | +/// Documentation of these models quotes the [Oracle Linker and Libraries |
| 11 | +/// Guide](https://docs.oracle.com/cd/E23824_01/html/819-0690/chapter8-20.html). |
| 12 | +public enum ThreadLocalModel { |
| 13 | + /// The variable is not thread local and hence has no associated model. |
| 14 | + case notThreadLocal |
| 15 | + /// Allows reference of all thread-local variables, from either a shared |
| 16 | + /// object or a dynamic executable. This model also supports the deferred |
| 17 | + /// allocation of a block of thread-local storage when the block is first |
| 18 | + /// referenced from a specific thread. |
| 19 | + case generalDynamic |
| 20 | + /// This model is an optimization of the General Dynamic model. The compiler |
| 21 | + /// might determine that a variable is bound locally, or protected, within the |
| 22 | + /// object being built. In this case, the compiler instructs the link-editor |
| 23 | + /// to statically bind the dynamic `tlsoffset` and use this model. |
| 24 | + /// |
| 25 | + /// This model provides a performance benefit over the General Dynamic model. |
| 26 | + /// Only one call to `tls_get_addr()` is required per function, to determine |
| 27 | + /// the address of `dtv0,m`. The dynamic thread-local storage offset, bound at |
| 28 | + /// link-edit time, is added to the `dtv0,m` address for each reference. |
| 29 | + case localDynamic |
| 30 | + /// This model can only reference thread-local variables which are available |
| 31 | + /// as part of the initial static thread-local template. This template is |
| 32 | + /// composed of all thread-local storage blocks that are available at process |
| 33 | + /// startup, plus a small backup reservation. |
| 34 | + /// |
| 35 | + /// In this model, the thread pointer-relative offset for a given variable `x` |
| 36 | + /// is stored in the GOT entry for x. |
| 37 | + /// |
| 38 | + /// This model can reference a limited number of thread-local variables from |
| 39 | + /// shared libraries loaded after initial process startup, such as by means of |
| 40 | + /// lazy loading, filters, or `dlopen()`. This access is satisfied from a |
| 41 | + /// fixed backup reservation. This reservation can only provide storage for |
| 42 | + /// uninitialized thread-local data items. For maximum flexibility, shared |
| 43 | + /// objects should reference thread-local variables using a dynamic model of |
| 44 | + /// thread-local storage. |
| 45 | + case initialExec |
| 46 | + /// This model can only reference thread-local variables which are part of the |
| 47 | + /// thread-local storage block of the dynamic executable. The link-editor |
| 48 | + /// calculates the thread pointer-relative offsets statically, without the |
| 49 | + /// need for dynamic relocations, or the extra reference to the GOT. This |
| 50 | + /// model can not be used to reference variables outside of the dynamic |
| 51 | + /// executable. |
| 52 | + case localExec |
| 53 | + |
| 54 | + internal init(llvm: LLVMThreadLocalMode) { |
| 55 | + switch llvm { |
| 56 | + case LLVMNotThreadLocal: self = .notThreadLocal |
| 57 | + case LLVMGeneralDynamicTLSModel: self = .generalDynamic |
| 58 | + case LLVMLocalDynamicTLSModel: self = .localDynamic |
| 59 | + case LLVMInitialExecTLSModel: self = .initialExec |
| 60 | + case LLVMLocalExecTLSModel: self = .localExec |
| 61 | + default: fatalError("unknown thread local mode \(llvm)") |
| 62 | + } |
| 63 | + } |
| 64 | + |
| 65 | + static let modeMapping: [ThreadLocalModel: LLVMThreadLocalMode] = [ |
| 66 | + .notThreadLocal: LLVMNotThreadLocal, |
| 67 | + .generalDynamic: LLVMGeneralDynamicTLSModel, |
| 68 | + .localDynamic: LLVMLocalDynamicTLSModel, |
| 69 | + .initialExec: LLVMInitialExecTLSModel, |
| 70 | + .localExec: LLVMLocalExecTLSModel, |
| 71 | + ] |
| 72 | + |
| 73 | + /// Retrieves the corresponding `LLVMThreadLocalMode`. |
| 74 | + public var llvm: LLVMThreadLocalMode { |
| 75 | + return ThreadLocalModel.modeMapping[self]! |
| 76 | + } |
| 77 | +} |
| 78 | + |
5 | 79 | /// A `Global` represents a region of memory allocated at compile time instead
|
6 | 80 | /// of at runtime. A global variable must either have an initializer, or make
|
7 | 81 | /// reference to an external definition that has an initializer.
|
@@ -35,6 +109,13 @@ public struct Global: IRGlobal {
|
35 | 109 | set { LLVMSetThreadLocal(asLLVM(), newValue.llvm) }
|
36 | 110 | }
|
37 | 111 |
|
| 112 | + /// Accesses the model of reference for this global variable if it is |
| 113 | + /// thread-local. |
| 114 | + public var threadLocalMode: ThreadLocalModel { |
| 115 | + get { return ThreadLocalModel(llvm: LLVMGetThreadLocalMode(asLLVM())) } |
| 116 | + set { LLVMSetThreadLocalMode(asLLVM(), newValue.llvm) } |
| 117 | + } |
| 118 | + |
38 | 119 | /// Retrieves the previous global in the module, if there is one.
|
39 | 120 | public func previous() -> Global? {
|
40 | 121 | guard let previous = LLVMGetPreviousGlobal(llvm) else { return nil }
|
|
0 commit comments