Skip to content

Commit 9358325

Browse files
authored
Merge pull request #160 from CodaFi/gardening
Gardening
2 parents 917b32e + ce90642 commit 9358325

10 files changed

+609
-531
lines changed

Sources/LLVM/Comdat.swift

Lines changed: 56 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ import cllvm
4242
///
4343
/// var g1 = builder.addGlobal("g1", initializer: IntType.int8.constant(42))
4444
/// g1.comdat = foo
45-
/// var g2 = builder.addGlobal("g1", initializer: IntType.int8.constant(42))
45+
/// var g2 = builder.addGlobal("g2", initializer: IntType.int8.constant(42))
4646
/// g2.comdat = bar
4747
///
4848
/// From the object file perspective, this requires the creation of two sections
@@ -57,66 +57,68 @@ public class Comdat {
5757
}
5858

5959
/// The selection kind for this COMDAT section.
60-
public var selectionKind: ComdatSelectionKind {
61-
get { return ComdatSelectionKind(llvm: LLVMGetComdatSelectionKind(self.llvm)) }
60+
public var selectionKind: Comdat.SelectionKind {
61+
get { return Comdat.SelectionKind(llvm: LLVMGetComdatSelectionKind(self.llvm)) }
6262
set { LLVMSetComdatSelectionKind(self.llvm, newValue.llvm) }
6363
}
6464
}
6565

66-
/// A `ComdatSelectionKind` describes the behavior of the linker when
67-
/// linking COMDAT sections.
68-
public enum ComdatSelectionKind {
69-
/// The linker may choose any COMDAT section with a matching key.
70-
///
71-
/// This selection kind is the most relaxed - any section with the same key
72-
/// but not necessarily identical size or contents can be chosen. Precisely
73-
/// which section is chosen is implementation-defined.
74-
///
75-
/// This selection kind is the default for all newly-inserted sections.
76-
case any
77-
/// The linker may choose any identically-keyed COMDAT section and requires
78-
/// all other referenced data to match its selection's referenced data.
79-
///
80-
/// This selection kind requires that the data in each COMDAT section be
81-
/// identical in length and content. Inclusion of multiple non-identical
82-
/// COMDAT sections with the same key is an error.
83-
///
84-
/// For global objects in LLVM, identical contents is defined to mean that
85-
/// their initializers point to the same global `IRValue`.
86-
case exactMatch
87-
/// The linker chooses the identically-keyed COMDAT section with the largest
88-
/// size, ignoring content.
89-
case largest
90-
/// The COMDAT section with this key is unique.
91-
///
92-
/// This selection requires that no other COMDAT section have the same key
93-
/// as this section, making the choice of selection unambiguous. Inclusion
94-
/// of any other COMDAT section with the same key is an error.
95-
case noDuplicates
96-
/// The linker may choose any identically-keyed COMDAT section and requires
97-
/// all other sections to have the same size as its selection.
98-
case sameSize
66+
extension Comdat {
67+
/// A `Comdat.SelectionKind` describes the behavior of the linker when
68+
/// linking COMDAT sections.
69+
public enum SelectionKind {
70+
/// The linker may choose any COMDAT section with a matching key.
71+
///
72+
/// This selection kind is the most relaxed - any section with the same key
73+
/// but not necessarily identical size or contents can be chosen. Precisely
74+
/// which section is chosen is implementation-defined.
75+
///
76+
/// This selection kind is the default for all newly-inserted sections.
77+
case any
78+
/// The linker may choose any identically-keyed COMDAT section and requires
79+
/// all other referenced data to match its selection's referenced data.
80+
///
81+
/// This selection kind requires that the data in each COMDAT section be
82+
/// identical in length and content. Inclusion of multiple non-identical
83+
/// COMDAT sections with the same key is an error.
84+
///
85+
/// For global objects in LLVM, identical contents is defined to mean that
86+
/// their initializers point to the same global `IRValue`.
87+
case exactMatch
88+
/// The linker chooses the identically-keyed COMDAT section with the largest
89+
/// size, ignoring content.
90+
case largest
91+
/// The COMDAT section with this key is unique.
92+
///
93+
/// This selection requires that no other COMDAT section have the same key
94+
/// as this section, making the choice of selection unambiguous. Inclusion
95+
/// of any other COMDAT section with the same key is an error.
96+
case noDuplicates
97+
/// The linker may choose any identically-keyed COMDAT section and requires
98+
/// all other sections to have the same size as its selection.
99+
case sameSize
99100

100-
internal init(llvm: LLVMComdatSelectionKind) {
101-
switch llvm {
102-
case LLVMAnyComdatSelectionKind: self = .any
103-
case LLVMExactMatchComdatSelectionKind: self = .exactMatch
104-
case LLVMLargestComdatSelectionKind: self = .largest
105-
case LLVMNoDuplicatesComdatSelectionKind: self = .noDuplicates
106-
case LLVMSameSizeComdatSelectionKind: self = .sameSize
107-
default: fatalError("unknown comdat selection kind \(llvm)")
101+
internal init(llvm: LLVMComdatSelectionKind) {
102+
switch llvm {
103+
case LLVMAnyComdatSelectionKind: self = .any
104+
case LLVMExactMatchComdatSelectionKind: self = .exactMatch
105+
case LLVMLargestComdatSelectionKind: self = .largest
106+
case LLVMNoDuplicatesComdatSelectionKind: self = .noDuplicates
107+
case LLVMSameSizeComdatSelectionKind: self = .sameSize
108+
default: fatalError("unknown comdat selection kind \(llvm)")
109+
}
108110
}
109-
}
110111

111-
private static let comdatMapping: [ComdatSelectionKind: LLVMComdatSelectionKind] = [
112-
.any: LLVMAnyComdatSelectionKind,
113-
.exactMatch: LLVMExactMatchComdatSelectionKind,
114-
.largest: LLVMLargestComdatSelectionKind,
115-
.noDuplicates: LLVMNoDuplicatesComdatSelectionKind,
116-
.sameSize: LLVMSameSizeComdatSelectionKind,
117-
]
112+
private static let comdatMapping: [Comdat.SelectionKind: LLVMComdatSelectionKind] = [
113+
.any: LLVMAnyComdatSelectionKind,
114+
.exactMatch: LLVMExactMatchComdatSelectionKind,
115+
.largest: LLVMLargestComdatSelectionKind,
116+
.noDuplicates: LLVMNoDuplicatesComdatSelectionKind,
117+
.sameSize: LLVMSameSizeComdatSelectionKind,
118+
]
118119

119-
fileprivate var llvm: LLVMComdatSelectionKind {
120-
return ComdatSelectionKind.comdatMapping[self]!
120+
fileprivate var llvm: LLVMComdatSelectionKind {
121+
return SelectionKind.comdatMapping[self]!
122+
}
121123
}
122124
}

Sources/LLVM/Global.swift

Lines changed: 49 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,63 @@ import cllvm
55
/// Enumerates the supported models of reference of thread-local variables.
66
///
77
/// These models are listed from the most general, but least optimized, to the
8-
/// fastest, but most restrictive.
8+
/// fastest, but most restrictive in general, as architectural differences
9+
/// play a role in determining the access patterns for thread-local storage.
910
///
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).
11+
/// In general, support for thread-local storage in statically-linked
12+
/// applications is limited: some platforms may not even define the behavior of
13+
/// TLS in such cases. This is usually not an issue as statically-linked code
14+
/// only ever has one TLS block, the offset of the variables within that block
15+
/// is known, and support for additional dynamic loading of code in
16+
/// statically-linked code is limited.
17+
///
18+
/// Computing the thread-specific address of a TLS variable is usually a dynamic
19+
/// process that relies on an ABI-defined function call (usually
20+
/// `__tls_get_addr`) to do the heavy lifting.
21+
///
22+
/// TLS access models fall into two classes: static and dynamic. Regardless of
23+
/// the actual model used, the dynamic linker must process all relocations
24+
/// for thread-local variables whenever the module is loaded. Some models,
25+
/// therefore, provide for a decrease in the overall number of relocations at
26+
/// a cost of restrictions on which modules can access variables.
1227
public enum ThreadLocalModel {
1328
/// The variable is not thread local and hence has no associated model.
1429
case notThreadLocal
1530
/// Allows reference of all thread-local variables, from either a shared
1631
/// object or a dynamic executable. This model also supports the deferred
1732
/// allocation of a block of thread-local storage when the block is first
18-
/// referenced from a specific thread.
33+
/// referenced from a specific thread. Note that the linker is free to
34+
/// optimize accesses using this model to one of the more specific models
35+
/// below which may ultimately defeat lazy allocation of the TLS storagee
36+
/// block.
37+
///
38+
/// The code generated for this model does not assume that any information
39+
/// about the module or variable offsets is known at link-time. Instead, the
40+
/// exact value of these variables is computed by the dynamic linker at
41+
/// runtime and passeed to `__tls_get_addr` in an architecture-specific way.
42+
///
43+
/// If possible, this model should be avoided if one of the more specific
44+
/// models applies out of concern for code size and application startup
45+
/// performance.
1946
case generalDynamic
20-
/// This model is an optimization of the General Dynamic model. The compiler
47+
/// This model is an optimization of the `generalDynamic` model. The compiler
2148
/// 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.
49+
/// object being built. In this case, the compiler instructs the linker
50+
/// to statically bind the dynamic offset of the variable and use this model.
2451
///
2552
/// 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.
53+
/// Only one call to `__tls_get_addr` is required per function, to determine
54+
/// the starting address of the variable within the TLS block for its
55+
/// parent module. Additional accesses can add an offset to this address
56+
/// value for repeated accesses.
57+
///
58+
/// The optimization available over the `generalDynamic` model is defeated if
59+
/// a variable is only ever accessed once, as its access would incur the
60+
/// same `__tls_get_addr` call and the additional overhead of the offset
61+
/// calculation.
62+
///
63+
/// The linker cannot, in general, optimize from the general dynamic model
64+
/// to the local dynamic model.
2965
case localDynamic
3066
/// This model can only reference thread-local variables which are available
3167
/// as part of the initial static thread-local template. This template is
@@ -43,8 +79,10 @@ public enum ThreadLocalModel {
4379
/// objects should reference thread-local variables using a dynamic model of
4480
/// thread-local storage.
4581
case initialExec
82+
/// This model is an optimization of the `localDynamic` model.
83+
///
4684
/// 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
85+
/// thread-local storage block of the dynamic executable. The linker
4886
/// calculates the thread pointer-relative offsets statically, without the
4987
/// need for dynamic relocations, or the extra reference to the GOT. This
5088
/// model can not be used to reference variables outside of the dynamic

0 commit comments

Comments
 (0)