Skip to content

Commit f36fd54

Browse files
authored
Merge pull request #58 from CodaFi/modal-logic
Add thread-local storage models
2 parents 39a1daa + c170b43 commit f36fd54

File tree

1 file changed

+81
-0
lines changed

1 file changed

+81
-0
lines changed

Sources/LLVM/Global.swift

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,80 @@
22
import cllvm
33
#endif
44

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+
579
/// A `Global` represents a region of memory allocated at compile time instead
680
/// of at runtime. A global variable must either have an initializer, or make
781
/// reference to an external definition that has an initializer.
@@ -35,6 +109,13 @@ public struct Global: IRGlobal {
35109
set { LLVMSetThreadLocal(asLLVM(), newValue.llvm) }
36110
}
37111

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+
38119
/// Retrieves the previous global in the module, if there is one.
39120
public func previous() -> Global? {
40121
guard let previous = LLVMGetPreviousGlobal(llvm) else { return nil }

0 commit comments

Comments
 (0)