Skip to content

Gardening #160

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Nov 6, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 56 additions & 54 deletions Sources/LLVM/Comdat.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ import cllvm
///
/// var g1 = builder.addGlobal("g1", initializer: IntType.int8.constant(42))
/// g1.comdat = foo
/// var g2 = builder.addGlobal("g1", initializer: IntType.int8.constant(42))
/// var g2 = builder.addGlobal("g2", initializer: IntType.int8.constant(42))
/// g2.comdat = bar
///
/// From the object file perspective, this requires the creation of two sections
Expand All @@ -57,66 +57,68 @@ public class Comdat {
}

/// The selection kind for this COMDAT section.
public var selectionKind: ComdatSelectionKind {
get { return ComdatSelectionKind(llvm: LLVMGetComdatSelectionKind(self.llvm)) }
public var selectionKind: Comdat.SelectionKind {
get { return Comdat.SelectionKind(llvm: LLVMGetComdatSelectionKind(self.llvm)) }
set { LLVMSetComdatSelectionKind(self.llvm, newValue.llvm) }
}
}

/// A `ComdatSelectionKind` describes the behavior of the linker when
/// linking COMDAT sections.
public enum ComdatSelectionKind {
/// The linker may choose any COMDAT section with a matching key.
///
/// This selection kind is the most relaxed - any section with the same key
/// but not necessarily identical size or contents can be chosen. Precisely
/// which section is chosen is implementation-defined.
///
/// This selection kind is the default for all newly-inserted sections.
case any
/// The linker may choose any identically-keyed COMDAT section and requires
/// all other referenced data to match its selection's referenced data.
///
/// This selection kind requires that the data in each COMDAT section be
/// identical in length and content. Inclusion of multiple non-identical
/// COMDAT sections with the same key is an error.
///
/// For global objects in LLVM, identical contents is defined to mean that
/// their initializers point to the same global `IRValue`.
case exactMatch
/// The linker chooses the identically-keyed COMDAT section with the largest
/// size, ignoring content.
case largest
/// The COMDAT section with this key is unique.
///
/// This selection requires that no other COMDAT section have the same key
/// as this section, making the choice of selection unambiguous. Inclusion
/// of any other COMDAT section with the same key is an error.
case noDuplicates
/// The linker may choose any identically-keyed COMDAT section and requires
/// all other sections to have the same size as its selection.
case sameSize
extension Comdat {
/// A `Comdat.SelectionKind` describes the behavior of the linker when
/// linking COMDAT sections.
public enum SelectionKind {
/// The linker may choose any COMDAT section with a matching key.
///
/// This selection kind is the most relaxed - any section with the same key
/// but not necessarily identical size or contents can be chosen. Precisely
/// which section is chosen is implementation-defined.
///
/// This selection kind is the default for all newly-inserted sections.
case any
/// The linker may choose any identically-keyed COMDAT section and requires
/// all other referenced data to match its selection's referenced data.
///
/// This selection kind requires that the data in each COMDAT section be
/// identical in length and content. Inclusion of multiple non-identical
/// COMDAT sections with the same key is an error.
///
/// For global objects in LLVM, identical contents is defined to mean that
/// their initializers point to the same global `IRValue`.
case exactMatch
/// The linker chooses the identically-keyed COMDAT section with the largest
/// size, ignoring content.
case largest
/// The COMDAT section with this key is unique.
///
/// This selection requires that no other COMDAT section have the same key
/// as this section, making the choice of selection unambiguous. Inclusion
/// of any other COMDAT section with the same key is an error.
case noDuplicates
/// The linker may choose any identically-keyed COMDAT section and requires
/// all other sections to have the same size as its selection.
case sameSize

internal init(llvm: LLVMComdatSelectionKind) {
switch llvm {
case LLVMAnyComdatSelectionKind: self = .any
case LLVMExactMatchComdatSelectionKind: self = .exactMatch
case LLVMLargestComdatSelectionKind: self = .largest
case LLVMNoDuplicatesComdatSelectionKind: self = .noDuplicates
case LLVMSameSizeComdatSelectionKind: self = .sameSize
default: fatalError("unknown comdat selection kind \(llvm)")
internal init(llvm: LLVMComdatSelectionKind) {
switch llvm {
case LLVMAnyComdatSelectionKind: self = .any
case LLVMExactMatchComdatSelectionKind: self = .exactMatch
case LLVMLargestComdatSelectionKind: self = .largest
case LLVMNoDuplicatesComdatSelectionKind: self = .noDuplicates
case LLVMSameSizeComdatSelectionKind: self = .sameSize
default: fatalError("unknown comdat selection kind \(llvm)")
}
}
}

private static let comdatMapping: [ComdatSelectionKind: LLVMComdatSelectionKind] = [
.any: LLVMAnyComdatSelectionKind,
.exactMatch: LLVMExactMatchComdatSelectionKind,
.largest: LLVMLargestComdatSelectionKind,
.noDuplicates: LLVMNoDuplicatesComdatSelectionKind,
.sameSize: LLVMSameSizeComdatSelectionKind,
]
private static let comdatMapping: [Comdat.SelectionKind: LLVMComdatSelectionKind] = [
.any: LLVMAnyComdatSelectionKind,
.exactMatch: LLVMExactMatchComdatSelectionKind,
.largest: LLVMLargestComdatSelectionKind,
.noDuplicates: LLVMNoDuplicatesComdatSelectionKind,
.sameSize: LLVMSameSizeComdatSelectionKind,
]

fileprivate var llvm: LLVMComdatSelectionKind {
return ComdatSelectionKind.comdatMapping[self]!
fileprivate var llvm: LLVMComdatSelectionKind {
return SelectionKind.comdatMapping[self]!
}
}
}
60 changes: 49 additions & 11 deletions Sources/LLVM/Global.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,63 @@ import cllvm
/// Enumerates the supported models of reference of thread-local variables.
///
/// These models are listed from the most general, but least optimized, to the
/// fastest, but most restrictive.
/// fastest, but most restrictive in general, as architectural differences
/// play a role in determining the access patterns for thread-local storage.
///
/// Documentation of these models quotes the [Oracle Linker and Libraries
/// Guide](https://docs.oracle.com/cd/E23824_01/html/819-0690/chapter8-20.html).
/// In general, support for thread-local storage in statically-linked
/// applications is limited: some platforms may not even define the behavior of
/// TLS in such cases. This is usually not an issue as statically-linked code
/// only ever has one TLS block, the offset of the variables within that block
/// is known, and support for additional dynamic loading of code in
/// statically-linked code is limited.
///
/// Computing the thread-specific address of a TLS variable is usually a dynamic
/// process that relies on an ABI-defined function call (usually
/// `__tls_get_addr`) to do the heavy lifting.
///
/// TLS access models fall into two classes: static and dynamic. Regardless of
/// the actual model used, the dynamic linker must process all relocations
/// for thread-local variables whenever the module is loaded. Some models,
/// therefore, provide for a decrease in the overall number of relocations at
/// a cost of restrictions on which modules can access variables.
public enum ThreadLocalModel {
/// The variable is not thread local and hence has no associated model.
case notThreadLocal
/// Allows reference of all thread-local variables, from either a shared
/// object or a dynamic executable. This model also supports the deferred
/// allocation of a block of thread-local storage when the block is first
/// referenced from a specific thread.
/// referenced from a specific thread. Note that the linker is free to
/// optimize accesses using this model to one of the more specific models
/// below which may ultimately defeat lazy allocation of the TLS storagee
/// block.
///
/// The code generated for this model does not assume that any information
/// about the module or variable offsets is known at link-time. Instead, the
/// exact value of these variables is computed by the dynamic linker at
/// runtime and passeed to `__tls_get_addr` in an architecture-specific way.
///
/// If possible, this model should be avoided if one of the more specific
/// models applies out of concern for code size and application startup
/// performance.
case generalDynamic
/// This model is an optimization of the General Dynamic model. The compiler
/// This model is an optimization of the `generalDynamic` model. The compiler
/// might determine that a variable is bound locally, or protected, within the
/// object being built. In this case, the compiler instructs the link-editor
/// to statically bind the dynamic `tlsoffset` and use this model.
/// object being built. In this case, the compiler instructs the linker
/// to statically bind the dynamic offset of the variable and use this model.
///
/// This model provides a performance benefit over the General Dynamic model.
/// Only one call to `tls_get_addr()` is required per function, to determine
/// the address of `dtv0,m`. The dynamic thread-local storage offset, bound at
/// link-edit time, is added to the `dtv0,m` address for each reference.
/// Only one call to `__tls_get_addr` is required per function, to determine
/// the starting address of the variable within the TLS block for its
/// parent module. Additional accesses can add an offset to this address
/// value for repeated accesses.
///
/// The optimization available over the `generalDynamic` model is defeated if
/// a variable is only ever accessed once, as its access would incur the
/// same `__tls_get_addr` call and the additional overhead of the offset
/// calculation.
///
/// The linker cannot, in general, optimize from the general dynamic model
/// to the local dynamic model.
case localDynamic
/// This model can only reference thread-local variables which are available
/// as part of the initial static thread-local template. This template is
Expand All @@ -43,8 +79,10 @@ public enum ThreadLocalModel {
/// objects should reference thread-local variables using a dynamic model of
/// thread-local storage.
case initialExec
/// This model is an optimization of the `localDynamic` model.
///
/// This model can only reference thread-local variables which are part of the
/// thread-local storage block of the dynamic executable. The link-editor
/// thread-local storage block of the dynamic executable. The linker
/// calculates the thread pointer-relative offsets statically, without the
/// need for dynamic relocations, or the extra reference to the GOT. This
/// model can not be used to reference variables outside of the dynamic
Expand Down
Loading