/Users/buildslave/jenkins/sharedspace/clang-stage2-coverage-R@2/llvm/lib/CodeGen/LowerEmuTLS.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===- LowerEmuTLS.cpp - Add __emutls_[vt].* variables --------------------===// |
2 | | // |
3 | | // The LLVM Compiler Infrastructure |
4 | | // |
5 | | // This file is distributed under the University of Illinois Open Source |
6 | | // License. See LICENSE.TXT for details. |
7 | | // |
8 | | //===----------------------------------------------------------------------===// |
9 | | // |
10 | | // This transformation is required for targets depending on libgcc style |
11 | | // emulated thread local storage variables. For every defined TLS variable xyz, |
12 | | // an __emutls_v.xyz is generated. If there is non-zero initialized value |
13 | | // an __emutls_t.xyz is also generated. |
14 | | // |
15 | | //===----------------------------------------------------------------------===// |
16 | | |
17 | | #include "llvm/ADT/SmallVector.h" |
18 | | #include "llvm/CodeGen/Passes.h" |
19 | | #include "llvm/CodeGen/TargetPassConfig.h" |
20 | | #include "llvm/IR/LLVMContext.h" |
21 | | #include "llvm/IR/Module.h" |
22 | | #include "llvm/Pass.h" |
23 | | #include "llvm/Target/TargetLowering.h" |
24 | | |
25 | | using namespace llvm; |
26 | | |
27 | | #define DEBUG_TYPE "loweremutls" |
28 | | |
29 | | namespace { |
30 | | |
31 | | class LowerEmuTLS : public ModulePass { |
32 | | public: |
33 | | static char ID; // Pass identification, replacement for typeid |
34 | 48 | LowerEmuTLS() : ModulePass(ID) { |
35 | 48 | initializeLowerEmuTLSPass(*PassRegistry::getPassRegistry()); |
36 | 48 | } |
37 | | |
38 | | bool runOnModule(Module &M) override; |
39 | | private: |
40 | | bool addEmuTlsVar(Module &M, const GlobalVariable *GV); |
41 | | static void copyLinkageVisibility(Module &M, |
42 | | const GlobalVariable *from, |
43 | 238 | GlobalVariable *to) { |
44 | 238 | to->setLinkage(from->getLinkage()); |
45 | 238 | to->setVisibility(from->getVisibility()); |
46 | 238 | if (from->hasComdat()238 ) { |
47 | 3 | to->setComdat(M.getOrInsertComdat(to->getName())); |
48 | 3 | to->getComdat()->setSelectionKind(from->getComdat()->getSelectionKind()); |
49 | 3 | } |
50 | 238 | } |
51 | | }; |
52 | | } |
53 | | |
54 | | char LowerEmuTLS::ID = 0; |
55 | | |
56 | | INITIALIZE_PASS(LowerEmuTLS, DEBUG_TYPE, |
57 | | "Add __emutls_[vt]. variables for emultated TLS model", false, |
58 | | false) |
59 | | |
60 | 48 | ModulePass *llvm::createLowerEmuTLSPass() { return new LowerEmuTLS(); } |
61 | | |
62 | 48 | bool LowerEmuTLS::runOnModule(Module &M) { |
63 | 48 | if (skipModule(M)) |
64 | 0 | return false; |
65 | 48 | |
66 | 48 | auto *TPC = getAnalysisIfAvailable<TargetPassConfig>(); |
67 | 48 | if (!TPC) |
68 | 0 | return false; |
69 | 48 | |
70 | 48 | auto &TM = TPC->getTM<TargetMachine>(); |
71 | 48 | if (!TM.Options.EmulatedTLS) |
72 | 0 | return false; |
73 | 48 | |
74 | 48 | bool Changed = false; |
75 | 48 | SmallVector<const GlobalVariable*, 8> TlsVars; |
76 | 178 | for (const auto &G : M.globals()) { |
77 | 178 | if (G.isThreadLocal()) |
78 | 152 | TlsVars.append({&G}); |
79 | 178 | } |
80 | 48 | for (const auto G : TlsVars) |
81 | 152 | Changed |= addEmuTlsVar(M, G); |
82 | 48 | return Changed; |
83 | 48 | } |
84 | | |
85 | 152 | bool LowerEmuTLS::addEmuTlsVar(Module &M, const GlobalVariable *GV) { |
86 | 152 | LLVMContext &C = M.getContext(); |
87 | 152 | PointerType *VoidPtrType = Type::getInt8PtrTy(C); |
88 | 152 | |
89 | 152 | std::string EmuTlsVarName = ("__emutls_v." + GV->getName()).str(); |
90 | 152 | GlobalVariable *EmuTlsVar = M.getNamedGlobal(EmuTlsVarName); |
91 | 152 | if (EmuTlsVar) |
92 | 0 | return false; // It has been added before. |
93 | 152 | |
94 | 152 | const DataLayout &DL = M.getDataLayout(); |
95 | 152 | Constant *NullPtr = ConstantPointerNull::get(VoidPtrType); |
96 | 152 | |
97 | 152 | // Get non-zero initializer from GV's initializer. |
98 | 152 | const Constant *InitValue = nullptr; |
99 | 152 | if (GV->hasInitializer()152 ) { |
100 | 104 | InitValue = GV->getInitializer(); |
101 | 104 | const ConstantInt *InitIntValue = dyn_cast<ConstantInt>(InitValue); |
102 | 104 | // When GV's init value is all 0, omit the EmuTlsTmplVar and let |
103 | 104 | // the emutls library function to reset newly allocated TLS variables. |
104 | 104 | if (isa<ConstantAggregateZero>(InitValue) || |
105 | 103 | (InitIntValue && 103 InitIntValue->isZero()102 )) |
106 | 18 | InitValue = nullptr; |
107 | 104 | } |
108 | 152 | |
109 | 152 | // Create the __emutls_v. symbol, whose type has 4 fields: |
110 | 152 | // word size; // size of GV in bytes |
111 | 152 | // word align; // alignment of GV |
112 | 152 | // void *ptr; // initialized to 0; set at run time per thread. |
113 | 152 | // void *templ; // 0 or point to __emutls_t.* |
114 | 152 | // sizeof(word) should be the same as sizeof(void*) on target. |
115 | 152 | IntegerType *WordType = DL.getIntPtrType(C); |
116 | 152 | PointerType *InitPtrType = InitValue ? |
117 | 152 | PointerType::getUnqual(InitValue->getType())86 : VoidPtrType66 ; |
118 | 152 | Type *ElementTypes[4] = {WordType, WordType, VoidPtrType, InitPtrType}; |
119 | 152 | ArrayRef<Type*> ElementTypeArray(ElementTypes, 4); |
120 | 152 | StructType *EmuTlsVarType = StructType::create(ElementTypeArray); |
121 | 152 | EmuTlsVar = cast<GlobalVariable>( |
122 | 152 | M.getOrInsertGlobal(EmuTlsVarName, EmuTlsVarType)); |
123 | 152 | copyLinkageVisibility(M, GV, EmuTlsVar); |
124 | 152 | |
125 | 152 | // Define "__emutls_t.*" and "__emutls_v.*" only if GV is defined. |
126 | 152 | if (!GV->hasInitializer()) |
127 | 48 | return true; |
128 | 104 | |
129 | 104 | Type *GVType = GV->getValueType(); |
130 | 104 | unsigned GVAlignment = GV->getAlignment(); |
131 | 104 | if (!GVAlignment104 ) { |
132 | 64 | // When LLVM IL declares a variable without alignment, use |
133 | 64 | // the ABI default alignment for the type. |
134 | 64 | GVAlignment = DL.getABITypeAlignment(GVType); |
135 | 64 | } |
136 | 104 | |
137 | 104 | // Define "__emutls_t.*" if there is InitValue |
138 | 104 | GlobalVariable *EmuTlsTmplVar = nullptr; |
139 | 104 | if (InitValue104 ) { |
140 | 86 | std::string EmuTlsTmplName = ("__emutls_t." + GV->getName()).str(); |
141 | 86 | EmuTlsTmplVar = dyn_cast_or_null<GlobalVariable>( |
142 | 86 | M.getOrInsertGlobal(EmuTlsTmplName, GVType)); |
143 | 86 | assert(EmuTlsTmplVar && "Failed to create emualted TLS initializer"); |
144 | 86 | EmuTlsTmplVar->setConstant(true); |
145 | 86 | EmuTlsTmplVar->setInitializer(const_cast<Constant*>(InitValue)); |
146 | 86 | EmuTlsTmplVar->setAlignment(GVAlignment); |
147 | 86 | copyLinkageVisibility(M, GV, EmuTlsTmplVar); |
148 | 86 | } |
149 | 104 | |
150 | 104 | // Define "__emutls_v.*" with initializer and alignment. |
151 | 104 | Constant *ElementValues[4] = { |
152 | 104 | ConstantInt::get(WordType, DL.getTypeStoreSize(GVType)), |
153 | 104 | ConstantInt::get(WordType, GVAlignment), |
154 | 104 | NullPtr, EmuTlsTmplVar ? EmuTlsTmplVar86 : NullPtr18 |
155 | 152 | }; |
156 | 152 | ArrayRef<Constant*> ElementValueArray(ElementValues, 4); |
157 | 152 | EmuTlsVar->setInitializer( |
158 | 152 | ConstantStruct::get(EmuTlsVarType, ElementValueArray)); |
159 | 152 | unsigned MaxAlignment = std::max( |
160 | 152 | DL.getABITypeAlignment(WordType), |
161 | 152 | DL.getABITypeAlignment(VoidPtrType)); |
162 | 152 | EmuTlsVar->setAlignment(MaxAlignment); |
163 | 152 | return true; |
164 | 152 | } |