1303231Sdim//===- LowerEmuTLS.cpp - Add __emutls_[vt].* variables --------------------===//
2303231Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6303231Sdim//
7303231Sdim//===----------------------------------------------------------------------===//
8303231Sdim//
9303231Sdim// This transformation is required for targets depending on libgcc style
10303231Sdim// emulated thread local storage variables. For every defined TLS variable xyz,
11303231Sdim// an __emutls_v.xyz is generated. If there is non-zero initialized value
12303231Sdim// an __emutls_t.xyz is also generated.
13303231Sdim//
14303231Sdim//===----------------------------------------------------------------------===//
15303231Sdim
16303231Sdim#include "llvm/ADT/SmallVector.h"
17303231Sdim#include "llvm/CodeGen/Passes.h"
18327952Sdim#include "llvm/CodeGen/TargetLowering.h"
19321369Sdim#include "llvm/CodeGen/TargetPassConfig.h"
20303231Sdim#include "llvm/IR/LLVMContext.h"
21303231Sdim#include "llvm/IR/Module.h"
22360784Sdim#include "llvm/InitializePasses.h"
23303231Sdim#include "llvm/Pass.h"
24303231Sdim
25303231Sdimusing namespace llvm;
26303231Sdim
27303231Sdim#define DEBUG_TYPE "loweremutls"
28303231Sdim
29303231Sdimnamespace {
30303231Sdim
31303231Sdimclass LowerEmuTLS : public ModulePass {
32303231Sdimpublic:
33303231Sdim  static char ID; // Pass identification, replacement for typeid
34321369Sdim  LowerEmuTLS() : ModulePass(ID) {
35303231Sdim    initializeLowerEmuTLSPass(*PassRegistry::getPassRegistry());
36303231Sdim  }
37321369Sdim
38303231Sdim  bool runOnModule(Module &M) override;
39303231Sdimprivate:
40303231Sdim  bool addEmuTlsVar(Module &M, const GlobalVariable *GV);
41303231Sdim  static void copyLinkageVisibility(Module &M,
42303231Sdim                                    const GlobalVariable *from,
43303231Sdim                                    GlobalVariable *to) {
44303231Sdim    to->setLinkage(from->getLinkage());
45303231Sdim    to->setVisibility(from->getVisibility());
46303231Sdim    if (from->hasComdat()) {
47303231Sdim      to->setComdat(M.getOrInsertComdat(to->getName()));
48303231Sdim      to->getComdat()->setSelectionKind(from->getComdat()->getSelectionKind());
49303231Sdim    }
50303231Sdim  }
51303231Sdim};
52303231Sdim}
53303231Sdim
54303231Sdimchar LowerEmuTLS::ID = 0;
55303231Sdim
56321369SdimINITIALIZE_PASS(LowerEmuTLS, DEBUG_TYPE,
57321369Sdim                "Add __emutls_[vt]. variables for emultated TLS model", false,
58321369Sdim                false)
59303231Sdim
60321369SdimModulePass *llvm::createLowerEmuTLSPass() { return new LowerEmuTLS(); }
61303231Sdim
62303231Sdimbool LowerEmuTLS::runOnModule(Module &M) {
63303231Sdim  if (skipModule(M))
64303231Sdim    return false;
65303231Sdim
66321369Sdim  auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();
67321369Sdim  if (!TPC)
68303231Sdim    return false;
69303231Sdim
70321369Sdim  auto &TM = TPC->getTM<TargetMachine>();
71341825Sdim  if (!TM.useEmulatedTLS())
72321369Sdim    return false;
73321369Sdim
74303231Sdim  bool Changed = false;
75303231Sdim  SmallVector<const GlobalVariable*, 8> TlsVars;
76303231Sdim  for (const auto &G : M.globals()) {
77303231Sdim    if (G.isThreadLocal())
78303231Sdim      TlsVars.append({&G});
79303231Sdim  }
80303231Sdim  for (const auto G : TlsVars)
81303231Sdim    Changed |= addEmuTlsVar(M, G);
82303231Sdim  return Changed;
83303231Sdim}
84303231Sdim
85303231Sdimbool LowerEmuTLS::addEmuTlsVar(Module &M, const GlobalVariable *GV) {
86303231Sdim  LLVMContext &C = M.getContext();
87303231Sdim  PointerType *VoidPtrType = Type::getInt8PtrTy(C);
88303231Sdim
89303231Sdim  std::string EmuTlsVarName = ("__emutls_v." + GV->getName()).str();
90303231Sdim  GlobalVariable *EmuTlsVar = M.getNamedGlobal(EmuTlsVarName);
91303231Sdim  if (EmuTlsVar)
92303231Sdim    return false;  // It has been added before.
93303231Sdim
94303231Sdim  const DataLayout &DL = M.getDataLayout();
95303231Sdim  Constant *NullPtr = ConstantPointerNull::get(VoidPtrType);
96303231Sdim
97303231Sdim  // Get non-zero initializer from GV's initializer.
98303231Sdim  const Constant *InitValue = nullptr;
99303231Sdim  if (GV->hasInitializer()) {
100303231Sdim    InitValue = GV->getInitializer();
101303231Sdim    const ConstantInt *InitIntValue = dyn_cast<ConstantInt>(InitValue);
102303231Sdim    // When GV's init value is all 0, omit the EmuTlsTmplVar and let
103303231Sdim    // the emutls library function to reset newly allocated TLS variables.
104303231Sdim    if (isa<ConstantAggregateZero>(InitValue) ||
105303231Sdim        (InitIntValue && InitIntValue->isZero()))
106303231Sdim      InitValue = nullptr;
107303231Sdim  }
108303231Sdim
109303231Sdim  // Create the __emutls_v. symbol, whose type has 4 fields:
110303231Sdim  //     word size;   // size of GV in bytes
111303231Sdim  //     word align;  // alignment of GV
112303231Sdim  //     void *ptr;   // initialized to 0; set at run time per thread.
113303231Sdim  //     void *templ; // 0 or point to __emutls_t.*
114303231Sdim  // sizeof(word) should be the same as sizeof(void*) on target.
115303231Sdim  IntegerType *WordType = DL.getIntPtrType(C);
116303231Sdim  PointerType *InitPtrType = InitValue ?
117303231Sdim      PointerType::getUnqual(InitValue->getType()) : VoidPtrType;
118303231Sdim  Type *ElementTypes[4] = {WordType, WordType, VoidPtrType, InitPtrType};
119303231Sdim  ArrayRef<Type*> ElementTypeArray(ElementTypes, 4);
120303231Sdim  StructType *EmuTlsVarType = StructType::create(ElementTypeArray);
121303231Sdim  EmuTlsVar = cast<GlobalVariable>(
122303231Sdim      M.getOrInsertGlobal(EmuTlsVarName, EmuTlsVarType));
123303231Sdim  copyLinkageVisibility(M, GV, EmuTlsVar);
124303231Sdim
125303231Sdim  // Define "__emutls_t.*" and "__emutls_v.*" only if GV is defined.
126303231Sdim  if (!GV->hasInitializer())
127303231Sdim    return true;
128303231Sdim
129303231Sdim  Type *GVType = GV->getValueType();
130303231Sdim  unsigned GVAlignment = GV->getAlignment();
131303231Sdim  if (!GVAlignment) {
132303231Sdim    // When LLVM IL declares a variable without alignment, use
133303231Sdim    // the ABI default alignment for the type.
134303231Sdim    GVAlignment = DL.getABITypeAlignment(GVType);
135303231Sdim  }
136303231Sdim
137303231Sdim  // Define "__emutls_t.*" if there is InitValue
138303231Sdim  GlobalVariable *EmuTlsTmplVar = nullptr;
139303231Sdim  if (InitValue) {
140303231Sdim    std::string EmuTlsTmplName = ("__emutls_t." + GV->getName()).str();
141303231Sdim    EmuTlsTmplVar = dyn_cast_or_null<GlobalVariable>(
142303231Sdim        M.getOrInsertGlobal(EmuTlsTmplName, GVType));
143303231Sdim    assert(EmuTlsTmplVar && "Failed to create emualted TLS initializer");
144303231Sdim    EmuTlsTmplVar->setConstant(true);
145303231Sdim    EmuTlsTmplVar->setInitializer(const_cast<Constant*>(InitValue));
146360784Sdim    EmuTlsTmplVar->setAlignment(Align(GVAlignment));
147303231Sdim    copyLinkageVisibility(M, GV, EmuTlsTmplVar);
148303231Sdim  }
149303231Sdim
150303231Sdim  // Define "__emutls_v.*" with initializer and alignment.
151303231Sdim  Constant *ElementValues[4] = {
152303231Sdim      ConstantInt::get(WordType, DL.getTypeStoreSize(GVType)),
153303231Sdim      ConstantInt::get(WordType, GVAlignment),
154303231Sdim      NullPtr, EmuTlsTmplVar ? EmuTlsTmplVar : NullPtr
155303231Sdim  };
156303231Sdim  ArrayRef<Constant*> ElementValueArray(ElementValues, 4);
157303231Sdim  EmuTlsVar->setInitializer(
158303231Sdim      ConstantStruct::get(EmuTlsVarType, ElementValueArray));
159360784Sdim  Align MaxAlignment(std::max(DL.getABITypeAlignment(WordType),
160360784Sdim                              DL.getABITypeAlignment(VoidPtrType)));
161303231Sdim  EmuTlsVar->setAlignment(MaxAlignment);
162303231Sdim  return true;
163303231Sdim}
164