10b57cec5SDimitry Andric //===- LowerEmuTLS.cpp - Add __emutls_[vt].* variables --------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This transformation is required for targets depending on libgcc style 100b57cec5SDimitry Andric // emulated thread local storage variables. For every defined TLS variable xyz, 110b57cec5SDimitry Andric // an __emutls_v.xyz is generated. If there is non-zero initialized value 120b57cec5SDimitry Andric // an __emutls_t.xyz is also generated. 130b57cec5SDimitry Andric // 140b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 150b57cec5SDimitry Andric 16cb14a3feSDimitry Andric #include "llvm/CodeGen/LowerEmuTLS.h" 170b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 18cb14a3feSDimitry Andric #include "llvm/Analysis/GlobalsModRef.h" 19cb14a3feSDimitry Andric #include "llvm/Analysis/ModuleSummaryAnalysis.h" 20cb14a3feSDimitry Andric #include "llvm/Analysis/StackSafetyAnalysis.h" 210b57cec5SDimitry Andric #include "llvm/CodeGen/Passes.h" 220b57cec5SDimitry Andric #include "llvm/CodeGen/TargetPassConfig.h" 23e8d8bef9SDimitry Andric #include "llvm/IR/Constants.h" 240b57cec5SDimitry Andric #include "llvm/IR/Module.h" 25480093f4SDimitry Andric #include "llvm/InitializePasses.h" 260b57cec5SDimitry Andric #include "llvm/Pass.h" 275ffd83dbSDimitry Andric #include "llvm/Target/TargetMachine.h" 280b57cec5SDimitry Andric 290b57cec5SDimitry Andric using namespace llvm; 300b57cec5SDimitry Andric 31cb14a3feSDimitry Andric #define DEBUG_TYPE "lower-emutls" 320b57cec5SDimitry Andric 330b57cec5SDimitry Andric namespace { 340b57cec5SDimitry Andric 350b57cec5SDimitry Andric class LowerEmuTLS : public ModulePass { 360b57cec5SDimitry Andric public: 370b57cec5SDimitry Andric static char ID; // Pass identification, replacement for typeid 380b57cec5SDimitry Andric LowerEmuTLS() : ModulePass(ID) { 390b57cec5SDimitry Andric initializeLowerEmuTLSPass(*PassRegistry::getPassRegistry()); 400b57cec5SDimitry Andric } 410b57cec5SDimitry Andric 420b57cec5SDimitry Andric bool runOnModule(Module &M) override; 43cb14a3feSDimitry Andric }; 44cb14a3feSDimitry Andric } 45cb14a3feSDimitry Andric 46cb14a3feSDimitry Andric static bool addEmuTlsVar(Module &M, const GlobalVariable *GV); 47cb14a3feSDimitry Andric 48cb14a3feSDimitry Andric static void copyLinkageVisibility(Module &M, const GlobalVariable *from, 490b57cec5SDimitry Andric GlobalVariable *to) { 500b57cec5SDimitry Andric to->setLinkage(from->getLinkage()); 510b57cec5SDimitry Andric to->setVisibility(from->getVisibility()); 52e8d8bef9SDimitry Andric to->setDSOLocal(from->isDSOLocal()); 530b57cec5SDimitry Andric if (from->hasComdat()) { 540b57cec5SDimitry Andric to->setComdat(M.getOrInsertComdat(to->getName())); 550b57cec5SDimitry Andric to->getComdat()->setSelectionKind(from->getComdat()->getSelectionKind()); 560b57cec5SDimitry Andric } 570b57cec5SDimitry Andric } 58cb14a3feSDimitry Andric 59cb14a3feSDimitry Andric PreservedAnalyses LowerEmuTLSPass::run(Module &M, ModuleAnalysisManager &MAM) { 60cb14a3feSDimitry Andric bool Changed = false; 61cb14a3feSDimitry Andric SmallVector<const GlobalVariable *, 8> TlsVars; 62cb14a3feSDimitry Andric for (const auto &G : M.globals()) { 63cb14a3feSDimitry Andric if (G.isThreadLocal()) 64cb14a3feSDimitry Andric TlsVars.push_back(&G); 65cb14a3feSDimitry Andric } 66cb14a3feSDimitry Andric for (const auto *G : TlsVars) 67cb14a3feSDimitry Andric Changed |= addEmuTlsVar(M, G); 68cb14a3feSDimitry Andric 69cb14a3feSDimitry Andric if (!Changed) 70cb14a3feSDimitry Andric return PreservedAnalyses::all(); 71cb14a3feSDimitry Andric PreservedAnalyses PA = PreservedAnalyses::all(); 72cb14a3feSDimitry Andric PA.abandon<GlobalsAA>(); 73cb14a3feSDimitry Andric PA.abandon<ModuleSummaryIndexAnalysis>(); 74cb14a3feSDimitry Andric PA.abandon<StackSafetyGlobalAnalysis>(); 75cb14a3feSDimitry Andric return PA; 760b57cec5SDimitry Andric } 770b57cec5SDimitry Andric 780b57cec5SDimitry Andric char LowerEmuTLS::ID = 0; 790b57cec5SDimitry Andric 800b57cec5SDimitry Andric INITIALIZE_PASS(LowerEmuTLS, DEBUG_TYPE, 810b57cec5SDimitry Andric "Add __emutls_[vt]. variables for emultated TLS model", false, 820b57cec5SDimitry Andric false) 830b57cec5SDimitry Andric 840b57cec5SDimitry Andric ModulePass *llvm::createLowerEmuTLSPass() { return new LowerEmuTLS(); } 850b57cec5SDimitry Andric 860b57cec5SDimitry Andric bool LowerEmuTLS::runOnModule(Module &M) { 870b57cec5SDimitry Andric if (skipModule(M)) 880b57cec5SDimitry Andric return false; 890b57cec5SDimitry Andric 900b57cec5SDimitry Andric auto *TPC = getAnalysisIfAvailable<TargetPassConfig>(); 910b57cec5SDimitry Andric if (!TPC) 920b57cec5SDimitry Andric return false; 930b57cec5SDimitry Andric 940b57cec5SDimitry Andric auto &TM = TPC->getTM<TargetMachine>(); 950b57cec5SDimitry Andric if (!TM.useEmulatedTLS()) 960b57cec5SDimitry Andric return false; 970b57cec5SDimitry Andric 980b57cec5SDimitry Andric bool Changed = false; 990b57cec5SDimitry Andric SmallVector<const GlobalVariable*, 8> TlsVars; 1000b57cec5SDimitry Andric for (const auto &G : M.globals()) { 1010b57cec5SDimitry Andric if (G.isThreadLocal()) 1020b57cec5SDimitry Andric TlsVars.append({&G}); 1030b57cec5SDimitry Andric } 104fcaf7f86SDimitry Andric for (const auto *const G : TlsVars) 1050b57cec5SDimitry Andric Changed |= addEmuTlsVar(M, G); 1060b57cec5SDimitry Andric return Changed; 1070b57cec5SDimitry Andric } 1080b57cec5SDimitry Andric 109cb14a3feSDimitry Andric bool addEmuTlsVar(Module &M, const GlobalVariable *GV) { 1100b57cec5SDimitry Andric LLVMContext &C = M.getContext(); 1115f757f3fSDimitry Andric PointerType *VoidPtrType = PointerType::getUnqual(C); 1120b57cec5SDimitry Andric 1130b57cec5SDimitry Andric std::string EmuTlsVarName = ("__emutls_v." + GV->getName()).str(); 1140b57cec5SDimitry Andric GlobalVariable *EmuTlsVar = M.getNamedGlobal(EmuTlsVarName); 1150b57cec5SDimitry Andric if (EmuTlsVar) 1160b57cec5SDimitry Andric return false; // It has been added before. 1170b57cec5SDimitry Andric 1180b57cec5SDimitry Andric const DataLayout &DL = M.getDataLayout(); 1190b57cec5SDimitry Andric Constant *NullPtr = ConstantPointerNull::get(VoidPtrType); 1200b57cec5SDimitry Andric 1210b57cec5SDimitry Andric // Get non-zero initializer from GV's initializer. 1220b57cec5SDimitry Andric const Constant *InitValue = nullptr; 1230b57cec5SDimitry Andric if (GV->hasInitializer()) { 1240b57cec5SDimitry Andric InitValue = GV->getInitializer(); 1250b57cec5SDimitry Andric const ConstantInt *InitIntValue = dyn_cast<ConstantInt>(InitValue); 1260b57cec5SDimitry Andric // When GV's init value is all 0, omit the EmuTlsTmplVar and let 1270b57cec5SDimitry Andric // the emutls library function to reset newly allocated TLS variables. 1280b57cec5SDimitry Andric if (isa<ConstantAggregateZero>(InitValue) || 1290b57cec5SDimitry Andric (InitIntValue && InitIntValue->isZero())) 1300b57cec5SDimitry Andric InitValue = nullptr; 1310b57cec5SDimitry Andric } 1320b57cec5SDimitry Andric 1330b57cec5SDimitry Andric // Create the __emutls_v. symbol, whose type has 4 fields: 1340b57cec5SDimitry Andric // word size; // size of GV in bytes 1350b57cec5SDimitry Andric // word align; // alignment of GV 1360b57cec5SDimitry Andric // void *ptr; // initialized to 0; set at run time per thread. 1370b57cec5SDimitry Andric // void *templ; // 0 or point to __emutls_t.* 1380b57cec5SDimitry Andric // sizeof(word) should be the same as sizeof(void*) on target. 1390b57cec5SDimitry Andric IntegerType *WordType = DL.getIntPtrType(C); 1405f757f3fSDimitry Andric PointerType *InitPtrType = PointerType::getUnqual(C); 1410b57cec5SDimitry Andric Type *ElementTypes[4] = {WordType, WordType, VoidPtrType, InitPtrType}; 142*0fca6ea1SDimitry Andric StructType *EmuTlsVarType = StructType::create(ElementTypes); 1430b57cec5SDimitry Andric EmuTlsVar = cast<GlobalVariable>( 1440b57cec5SDimitry Andric M.getOrInsertGlobal(EmuTlsVarName, EmuTlsVarType)); 1450b57cec5SDimitry Andric copyLinkageVisibility(M, GV, EmuTlsVar); 1460b57cec5SDimitry Andric 1470b57cec5SDimitry Andric // Define "__emutls_t.*" and "__emutls_v.*" only if GV is defined. 1480b57cec5SDimitry Andric if (!GV->hasInitializer()) 1490b57cec5SDimitry Andric return true; 1500b57cec5SDimitry Andric 1510b57cec5SDimitry Andric Type *GVType = GV->getValueType(); 1525ffd83dbSDimitry Andric Align GVAlignment = DL.getValueOrABITypeAlignment(GV->getAlign(), GVType); 1530b57cec5SDimitry Andric 1540b57cec5SDimitry Andric // Define "__emutls_t.*" if there is InitValue 1550b57cec5SDimitry Andric GlobalVariable *EmuTlsTmplVar = nullptr; 1560b57cec5SDimitry Andric if (InitValue) { 1570b57cec5SDimitry Andric std::string EmuTlsTmplName = ("__emutls_t." + GV->getName()).str(); 1580b57cec5SDimitry Andric EmuTlsTmplVar = dyn_cast_or_null<GlobalVariable>( 1590b57cec5SDimitry Andric M.getOrInsertGlobal(EmuTlsTmplName, GVType)); 1600b57cec5SDimitry Andric assert(EmuTlsTmplVar && "Failed to create emualted TLS initializer"); 1610b57cec5SDimitry Andric EmuTlsTmplVar->setConstant(true); 1620b57cec5SDimitry Andric EmuTlsTmplVar->setInitializer(const_cast<Constant*>(InitValue)); 1635ffd83dbSDimitry Andric EmuTlsTmplVar->setAlignment(GVAlignment); 1640b57cec5SDimitry Andric copyLinkageVisibility(M, GV, EmuTlsTmplVar); 1650b57cec5SDimitry Andric } 1660b57cec5SDimitry Andric 1670b57cec5SDimitry Andric // Define "__emutls_v.*" with initializer and alignment. 1680b57cec5SDimitry Andric Constant *ElementValues[4] = { 1690b57cec5SDimitry Andric ConstantInt::get(WordType, DL.getTypeStoreSize(GVType)), 1705ffd83dbSDimitry Andric ConstantInt::get(WordType, GVAlignment.value()), NullPtr, 1715ffd83dbSDimitry Andric EmuTlsTmplVar ? EmuTlsTmplVar : NullPtr}; 172*0fca6ea1SDimitry Andric EmuTlsVar->setInitializer(ConstantStruct::get(EmuTlsVarType, ElementValues)); 1735ffd83dbSDimitry Andric Align MaxAlignment = 1745ffd83dbSDimitry Andric std::max(DL.getABITypeAlign(WordType), DL.getABITypeAlign(VoidPtrType)); 1750b57cec5SDimitry Andric EmuTlsVar->setAlignment(MaxAlignment); 1760b57cec5SDimitry Andric return true; 1770b57cec5SDimitry Andric } 178