From c170b43195cac88053cc3cd30d4fc3b637b44575 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Mon, 30 Jan 2017 15:37:26 -0500 Subject: [PATCH] Add thread-local storage models MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit LLVM calls the enumeration “TLS Modes” but has defined cases using the namespace “TLS Model”. For the sake of consistency, I have chosen Model. --- Sources/LLVM/Global.swift | 81 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/Sources/LLVM/Global.swift b/Sources/LLVM/Global.swift index 1d0fcd1b..ce858f5a 100644 --- a/Sources/LLVM/Global.swift +++ b/Sources/LLVM/Global.swift @@ -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. @@ -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 }