1 //===- LowerEmuTLS.cpp - Add __emutls_[vt].* variables --------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This transformation is required for targets depending on libgcc style 10 // emulated thread local storage variables. For every defined TLS variable xyz, 11 // an __emutls_v.xyz is generated. If there is non-zero initialized value 12 // an __emutls_t.xyz is also generated. 13 // 14 //===----------------------------------------------------------------------===// 15 16 #include "llvm/CodeGen/LowerEmuTLS.h" 17 #include "llvm/ADT/SmallVector.h" 18 #include "llvm/Analysis/GlobalsModRef.h" 19 #include "llvm/Analysis/ModuleSummaryAnalysis.h" 20 #include "llvm/Analysis/StackSafetyAnalysis.h" 21 #include "llvm/CodeGen/Passes.h" 22 #include "llvm/CodeGen/TargetPassConfig.h" 23 #include "llvm/IR/Constants.h" 24 #include "llvm/IR/Module.h" 25 #include "llvm/InitializePasses.h" 26 #include "llvm/Pass.h" 27 #include "llvm/Target/TargetMachine.h" 28 29 using namespace llvm; 30 31 #define DEBUG_TYPE "lower-emutls" 32 33 namespace { 34 35 class LowerEmuTLS : public ModulePass { 36 public: 37 static char ID; // Pass identification, replacement for typeid 38 LowerEmuTLS() : ModulePass(ID) { 39 initializeLowerEmuTLSPass(*PassRegistry::getPassRegistry()); 40 } 41 42 bool runOnModule(Module &M) override; 43 }; 44 } 45 46 static bool addEmuTlsVar(Module &M, const GlobalVariable *GV); 47 48 static void copyLinkageVisibility(Module &M, const GlobalVariable *from, 49 GlobalVariable *to) { 50 to->setLinkage(from->getLinkage()); 51 to->setVisibility(from->getVisibility()); 52 to->setDSOLocal(from->isDSOLocal()); 53 if (from->hasComdat()) { 54 to->setComdat(M.getOrInsertComdat(to->getName())); 55 to->getComdat()->setSelectionKind(from->getComdat()->getSelectionKind()); 56 } 57 } 58 59 PreservedAnalyses LowerEmuTLSPass::run(Module &M, ModuleAnalysisManager &MAM) { 60 bool Changed = false; 61 SmallVector<const GlobalVariable *, 8> TlsVars; 62 for (const auto &G : M.globals()) { 63 if (G.isThreadLocal()) 64 TlsVars.push_back(&G); 65 } 66 for (const auto *G : TlsVars) 67 Changed |= addEmuTlsVar(M, G); 68 69 if (!Changed) 70 return PreservedAnalyses::all(); 71 PreservedAnalyses PA = PreservedAnalyses::all(); 72 PA.abandon<GlobalsAA>(); 73 PA.abandon<ModuleSummaryIndexAnalysis>(); 74 PA.abandon<StackSafetyGlobalAnalysis>(); 75 return PA; 76 } 77 78 char LowerEmuTLS::ID = 0; 79 80 INITIALIZE_PASS(LowerEmuTLS, DEBUG_TYPE, 81 "Add __emutls_[vt]. variables for emultated TLS model", false, 82 false) 83 84 ModulePass *llvm::createLowerEmuTLSPass() { return new LowerEmuTLS(); } 85 86 bool LowerEmuTLS::runOnModule(Module &M) { 87 if (skipModule(M)) 88 return false; 89 90 auto *TPC = getAnalysisIfAvailable<TargetPassConfig>(); 91 if (!TPC) 92 return false; 93 94 auto &TM = TPC->getTM<TargetMachine>(); 95 if (!TM.useEmulatedTLS()) 96 return false; 97 98 bool Changed = false; 99 SmallVector<const GlobalVariable*, 8> TlsVars; 100 for (const auto &G : M.globals()) { 101 if (G.isThreadLocal()) 102 TlsVars.append({&G}); 103 } 104 for (const auto *const G : TlsVars) 105 Changed |= addEmuTlsVar(M, G); 106 return Changed; 107 } 108 109 bool addEmuTlsVar(Module &M, const GlobalVariable *GV) { 110 LLVMContext &C = M.getContext(); 111 PointerType *VoidPtrType = PointerType::getUnqual(C); 112 113 std::string EmuTlsVarName = ("__emutls_v." + GV->getName()).str(); 114 GlobalVariable *EmuTlsVar = M.getNamedGlobal(EmuTlsVarName); 115 if (EmuTlsVar) 116 return false; // It has been added before. 117 118 const DataLayout &DL = M.getDataLayout(); 119 Constant *NullPtr = ConstantPointerNull::get(VoidPtrType); 120 121 // Get non-zero initializer from GV's initializer. 122 const Constant *InitValue = nullptr; 123 if (GV->hasInitializer()) { 124 InitValue = GV->getInitializer(); 125 const ConstantInt *InitIntValue = dyn_cast<ConstantInt>(InitValue); 126 // When GV's init value is all 0, omit the EmuTlsTmplVar and let 127 // the emutls library function to reset newly allocated TLS variables. 128 if (isa<ConstantAggregateZero>(InitValue) || 129 (InitIntValue && InitIntValue->isZero())) 130 InitValue = nullptr; 131 } 132 133 // Create the __emutls_v. symbol, whose type has 4 fields: 134 // word size; // size of GV in bytes 135 // word align; // alignment of GV 136 // void *ptr; // initialized to 0; set at run time per thread. 137 // void *templ; // 0 or point to __emutls_t.* 138 // sizeof(word) should be the same as sizeof(void*) on target. 139 IntegerType *WordType = DL.getIntPtrType(C); 140 PointerType *InitPtrType = PointerType::getUnqual(C); 141 Type *ElementTypes[4] = {WordType, WordType, VoidPtrType, InitPtrType}; 142 StructType *EmuTlsVarType = StructType::create(ElementTypes); 143 EmuTlsVar = cast<GlobalVariable>( 144 M.getOrInsertGlobal(EmuTlsVarName, EmuTlsVarType)); 145 copyLinkageVisibility(M, GV, EmuTlsVar); 146 147 // Define "__emutls_t.*" and "__emutls_v.*" only if GV is defined. 148 if (!GV->hasInitializer()) 149 return true; 150 151 Type *GVType = GV->getValueType(); 152 Align GVAlignment = DL.getValueOrABITypeAlignment(GV->getAlign(), GVType); 153 154 // Define "__emutls_t.*" if there is InitValue 155 GlobalVariable *EmuTlsTmplVar = nullptr; 156 if (InitValue) { 157 std::string EmuTlsTmplName = ("__emutls_t." + GV->getName()).str(); 158 EmuTlsTmplVar = dyn_cast_or_null<GlobalVariable>( 159 M.getOrInsertGlobal(EmuTlsTmplName, GVType)); 160 assert(EmuTlsTmplVar && "Failed to create emualted TLS initializer"); 161 EmuTlsTmplVar->setConstant(true); 162 EmuTlsTmplVar->setInitializer(const_cast<Constant*>(InitValue)); 163 EmuTlsTmplVar->setAlignment(GVAlignment); 164 copyLinkageVisibility(M, GV, EmuTlsTmplVar); 165 } 166 167 // Define "__emutls_v.*" with initializer and alignment. 168 Constant *ElementValues[4] = { 169 ConstantInt::get(WordType, DL.getTypeStoreSize(GVType)), 170 ConstantInt::get(WordType, GVAlignment.value()), NullPtr, 171 EmuTlsTmplVar ? EmuTlsTmplVar : NullPtr}; 172 EmuTlsVar->setInitializer(ConstantStruct::get(EmuTlsVarType, ElementValues)); 173 Align MaxAlignment = 174 std::max(DL.getABITypeAlign(WordType), DL.getABITypeAlign(VoidPtrType)); 175 EmuTlsVar->setAlignment(MaxAlignment); 176 return true; 177 } 178