Skip to content

Add thread-local storage models #58

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 1 commit into from
Jan 30, 2017
Merged
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
81 changes: 81 additions & 0 deletions Sources/LLVM/Global.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,80 @@
import cllvm
#endif

/// 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.
///
/// Documentation of these models quotes the [Oracle Linker and Libraries
/// Guide](https://docs.oracle.com/cd/E23824_01/html/819-0690/chapter8-20.html).
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.
case generalDynamic
/// This model is an optimization of the General Dynamic 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.
///
/// 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.
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
/// composed of all thread-local storage blocks that are available at process
/// startup, plus a small backup reservation.
///
/// In this model, the thread pointer-relative offset for a given variable `x`
/// is stored in the GOT entry for x.
///
/// This model can reference a limited number of thread-local variables from
/// shared libraries loaded after initial process startup, such as by means of
/// lazy loading, filters, or `dlopen()`. This access is satisfied from a
/// fixed backup reservation. This reservation can only provide storage for
/// uninitialized thread-local data items. For maximum flexibility, shared
/// objects should reference thread-local variables using a dynamic model of
/// thread-local storage.
case initialExec
/// This model can only reference thread-local variables which are part of the
/// thread-local storage block of the dynamic executable. The link-editor
/// 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
/// executable.
case localExec

internal init(llvm: LLVMThreadLocalMode) {
switch llvm {
case LLVMNotThreadLocal: self = .notThreadLocal
case LLVMGeneralDynamicTLSModel: self = .generalDynamic
case LLVMLocalDynamicTLSModel: self = .localDynamic
case LLVMInitialExecTLSModel: self = .initialExec
case LLVMLocalExecTLSModel: self = .localExec
default: fatalError("unknown thread local mode \(llvm)")
}
}

static let modeMapping: [ThreadLocalModel: LLVMThreadLocalMode] = [
.notThreadLocal: LLVMNotThreadLocal,
.generalDynamic: LLVMGeneralDynamicTLSModel,
.localDynamic: LLVMLocalDynamicTLSModel,
.initialExec: LLVMInitialExecTLSModel,
.localExec: LLVMLocalExecTLSModel,
]

/// Retrieves the corresponding `LLVMThreadLocalMode`.
public var llvm: LLVMThreadLocalMode {
return ThreadLocalModel.modeMapping[self]!
}
}

/// A `Global` represents a region of memory allocated at compile time instead
/// of at runtime. A global variable must either have an initializer, or make
/// reference to an external definition that has an initializer.
Expand Down Expand Up @@ -35,6 +109,13 @@ public struct Global: IRGlobal {
set { LLVMSetThreadLocal(asLLVM(), newValue.llvm) }
}

/// Accesses the model of reference for this global variable if it is
/// thread-local.
public var threadLocalMode: ThreadLocalModel {
get { return ThreadLocalModel(llvm: LLVMGetThreadLocalMode(asLLVM())) }
set { LLVMSetThreadLocalMode(asLLVM(), newValue.llvm) }
}

/// Retrieves the previous global in the module, if there is one.
public func previous() -> Global? {
guard let previous = LLVMGetPreviousGlobal(llvm) else { return nil }
Expand Down