13ca95b02SDimitry Andric //===- LowerEmuTLS.cpp - Add __emutls_[vt].* variables --------------------===//
23ca95b02SDimitry Andric //
33ca95b02SDimitry Andric // The LLVM Compiler Infrastructure
43ca95b02SDimitry Andric //
53ca95b02SDimitry Andric // This file is distributed under the University of Illinois Open Source
63ca95b02SDimitry Andric // License. See LICENSE.TXT for details.
73ca95b02SDimitry Andric //
83ca95b02SDimitry Andric //===----------------------------------------------------------------------===//
93ca95b02SDimitry Andric //
103ca95b02SDimitry Andric // This transformation is required for targets depending on libgcc style
113ca95b02SDimitry Andric // emulated thread local storage variables. For every defined TLS variable xyz,
123ca95b02SDimitry Andric // an __emutls_v.xyz is generated. If there is non-zero initialized value
133ca95b02SDimitry Andric // an __emutls_t.xyz is also generated.
143ca95b02SDimitry Andric //
153ca95b02SDimitry Andric //===----------------------------------------------------------------------===//
163ca95b02SDimitry Andric
173ca95b02SDimitry Andric #include "llvm/ADT/SmallVector.h"
183ca95b02SDimitry Andric #include "llvm/CodeGen/Passes.h"
192cab237bSDimitry Andric #include "llvm/CodeGen/TargetLowering.h"
20d8866befSDimitry Andric #include "llvm/CodeGen/TargetPassConfig.h"
213ca95b02SDimitry Andric #include "llvm/IR/LLVMContext.h"
223ca95b02SDimitry Andric #include "llvm/IR/Module.h"
233ca95b02SDimitry Andric #include "llvm/Pass.h"
243ca95b02SDimitry Andric
253ca95b02SDimitry Andric using namespace llvm;
263ca95b02SDimitry Andric
273ca95b02SDimitry Andric #define DEBUG_TYPE "loweremutls"
283ca95b02SDimitry Andric
293ca95b02SDimitry Andric namespace {
303ca95b02SDimitry Andric
313ca95b02SDimitry Andric class LowerEmuTLS : public ModulePass {
323ca95b02SDimitry Andric public:
333ca95b02SDimitry Andric static char ID; // Pass identification, replacement for typeid
LowerEmuTLS()34d8866befSDimitry Andric LowerEmuTLS() : ModulePass(ID) {
353ca95b02SDimitry Andric initializeLowerEmuTLSPass(*PassRegistry::getPassRegistry());
363ca95b02SDimitry Andric }
37d8866befSDimitry Andric
383ca95b02SDimitry Andric bool runOnModule(Module &M) override;
393ca95b02SDimitry Andric private:
403ca95b02SDimitry Andric bool addEmuTlsVar(Module &M, const GlobalVariable *GV);
copyLinkageVisibility(Module & M,const GlobalVariable * from,GlobalVariable * to)413ca95b02SDimitry Andric static void copyLinkageVisibility(Module &M,
423ca95b02SDimitry Andric const GlobalVariable *from,
433ca95b02SDimitry Andric GlobalVariable *to) {
443ca95b02SDimitry Andric to->setLinkage(from->getLinkage());
453ca95b02SDimitry Andric to->setVisibility(from->getVisibility());
463ca95b02SDimitry Andric if (from->hasComdat()) {
473ca95b02SDimitry Andric to->setComdat(M.getOrInsertComdat(to->getName()));
483ca95b02SDimitry Andric to->getComdat()->setSelectionKind(from->getComdat()->getSelectionKind());
493ca95b02SDimitry Andric }
503ca95b02SDimitry Andric }
513ca95b02SDimitry Andric };
523ca95b02SDimitry Andric }
533ca95b02SDimitry Andric
543ca95b02SDimitry Andric char LowerEmuTLS::ID = 0;
553ca95b02SDimitry Andric
56302affcbSDimitry Andric INITIALIZE_PASS(LowerEmuTLS, DEBUG_TYPE,
57d8866befSDimitry Andric "Add __emutls_[vt]. variables for emultated TLS model", false,
58d8866befSDimitry Andric false)
593ca95b02SDimitry Andric
createLowerEmuTLSPass()60d8866befSDimitry Andric ModulePass *llvm::createLowerEmuTLSPass() { return new LowerEmuTLS(); }
613ca95b02SDimitry Andric
runOnModule(Module & M)623ca95b02SDimitry Andric bool LowerEmuTLS::runOnModule(Module &M) {
633ca95b02SDimitry Andric if (skipModule(M))
643ca95b02SDimitry Andric return false;
653ca95b02SDimitry Andric
66d8866befSDimitry Andric auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();
67d8866befSDimitry Andric if (!TPC)
68d8866befSDimitry Andric return false;
69d8866befSDimitry Andric
70d8866befSDimitry Andric auto &TM = TPC->getTM<TargetMachine>();
71*4ba319b5SDimitry Andric if (!TM.useEmulatedTLS())
723ca95b02SDimitry Andric return false;
733ca95b02SDimitry Andric
743ca95b02SDimitry Andric bool Changed = false;
753ca95b02SDimitry Andric SmallVector<const GlobalVariable*, 8> TlsVars;
763ca95b02SDimitry Andric for (const auto &G : M.globals()) {
773ca95b02SDimitry Andric if (G.isThreadLocal())
783ca95b02SDimitry Andric TlsVars.append({&G});
793ca95b02SDimitry Andric }
803ca95b02SDimitry Andric for (const auto G : TlsVars)
813ca95b02SDimitry Andric Changed |= addEmuTlsVar(M, G);
823ca95b02SDimitry Andric return Changed;
833ca95b02SDimitry Andric }
843ca95b02SDimitry Andric
addEmuTlsVar(Module & M,const GlobalVariable * GV)853ca95b02SDimitry Andric bool LowerEmuTLS::addEmuTlsVar(Module &M, const GlobalVariable *GV) {
863ca95b02SDimitry Andric LLVMContext &C = M.getContext();
873ca95b02SDimitry Andric PointerType *VoidPtrType = Type::getInt8PtrTy(C);
883ca95b02SDimitry Andric
893ca95b02SDimitry Andric std::string EmuTlsVarName = ("__emutls_v." + GV->getName()).str();
903ca95b02SDimitry Andric GlobalVariable *EmuTlsVar = M.getNamedGlobal(EmuTlsVarName);
913ca95b02SDimitry Andric if (EmuTlsVar)
923ca95b02SDimitry Andric return false; // It has been added before.
933ca95b02SDimitry Andric
943ca95b02SDimitry Andric const DataLayout &DL = M.getDataLayout();
953ca95b02SDimitry Andric Constant *NullPtr = ConstantPointerNull::get(VoidPtrType);
963ca95b02SDimitry Andric
973ca95b02SDimitry Andric // Get non-zero initializer from GV's initializer.
983ca95b02SDimitry Andric const Constant *InitValue = nullptr;
993ca95b02SDimitry Andric if (GV->hasInitializer()) {
1003ca95b02SDimitry Andric InitValue = GV->getInitializer();
1013ca95b02SDimitry Andric const ConstantInt *InitIntValue = dyn_cast<ConstantInt>(InitValue);
1023ca95b02SDimitry Andric // When GV's init value is all 0, omit the EmuTlsTmplVar and let
1033ca95b02SDimitry Andric // the emutls library function to reset newly allocated TLS variables.
1043ca95b02SDimitry Andric if (isa<ConstantAggregateZero>(InitValue) ||
1053ca95b02SDimitry Andric (InitIntValue && InitIntValue->isZero()))
1063ca95b02SDimitry Andric InitValue = nullptr;
1073ca95b02SDimitry Andric }
1083ca95b02SDimitry Andric
1093ca95b02SDimitry Andric // Create the __emutls_v. symbol, whose type has 4 fields:
1103ca95b02SDimitry Andric // word size; // size of GV in bytes
1113ca95b02SDimitry Andric // word align; // alignment of GV
1123ca95b02SDimitry Andric // void *ptr; // initialized to 0; set at run time per thread.
1133ca95b02SDimitry Andric // void *templ; // 0 or point to __emutls_t.*
1143ca95b02SDimitry Andric // sizeof(word) should be the same as sizeof(void*) on target.
1153ca95b02SDimitry Andric IntegerType *WordType = DL.getIntPtrType(C);
1163ca95b02SDimitry Andric PointerType *InitPtrType = InitValue ?
1173ca95b02SDimitry Andric PointerType::getUnqual(InitValue->getType()) : VoidPtrType;
1183ca95b02SDimitry Andric Type *ElementTypes[4] = {WordType, WordType, VoidPtrType, InitPtrType};
1193ca95b02SDimitry Andric ArrayRef<Type*> ElementTypeArray(ElementTypes, 4);
1203ca95b02SDimitry Andric StructType *EmuTlsVarType = StructType::create(ElementTypeArray);
1213ca95b02SDimitry Andric EmuTlsVar = cast<GlobalVariable>(
1223ca95b02SDimitry Andric M.getOrInsertGlobal(EmuTlsVarName, EmuTlsVarType));
1233ca95b02SDimitry Andric copyLinkageVisibility(M, GV, EmuTlsVar);
1243ca95b02SDimitry Andric
1253ca95b02SDimitry Andric // Define "__emutls_t.*" and "__emutls_v.*" only if GV is defined.
1263ca95b02SDimitry Andric if (!GV->hasInitializer())
1273ca95b02SDimitry Andric return true;
1283ca95b02SDimitry Andric
1293ca95b02SDimitry Andric Type *GVType = GV->getValueType();
1303ca95b02SDimitry Andric unsigned GVAlignment = GV->getAlignment();
1313ca95b02SDimitry Andric if (!GVAlignment) {
1323ca95b02SDimitry Andric // When LLVM IL declares a variable without alignment, use
1333ca95b02SDimitry Andric // the ABI default alignment for the type.
1343ca95b02SDimitry Andric GVAlignment = DL.getABITypeAlignment(GVType);
1353ca95b02SDimitry Andric }
1363ca95b02SDimitry Andric
1373ca95b02SDimitry Andric // Define "__emutls_t.*" if there is InitValue
1383ca95b02SDimitry Andric GlobalVariable *EmuTlsTmplVar = nullptr;
1393ca95b02SDimitry Andric if (InitValue) {
1403ca95b02SDimitry Andric std::string EmuTlsTmplName = ("__emutls_t." + GV->getName()).str();
1413ca95b02SDimitry Andric EmuTlsTmplVar = dyn_cast_or_null<GlobalVariable>(
1423ca95b02SDimitry Andric M.getOrInsertGlobal(EmuTlsTmplName, GVType));
1433ca95b02SDimitry Andric assert(EmuTlsTmplVar && "Failed to create emualted TLS initializer");
1443ca95b02SDimitry Andric EmuTlsTmplVar->setConstant(true);
1453ca95b02SDimitry Andric EmuTlsTmplVar->setInitializer(const_cast<Constant*>(InitValue));
1463ca95b02SDimitry Andric EmuTlsTmplVar->setAlignment(GVAlignment);
1473ca95b02SDimitry Andric copyLinkageVisibility(M, GV, EmuTlsTmplVar);
1483ca95b02SDimitry Andric }
1493ca95b02SDimitry Andric
1503ca95b02SDimitry Andric // Define "__emutls_v.*" with initializer and alignment.
1513ca95b02SDimitry Andric Constant *ElementValues[4] = {
1523ca95b02SDimitry Andric ConstantInt::get(WordType, DL.getTypeStoreSize(GVType)),
1533ca95b02SDimitry Andric ConstantInt::get(WordType, GVAlignment),
1543ca95b02SDimitry Andric NullPtr, EmuTlsTmplVar ? EmuTlsTmplVar : NullPtr
1553ca95b02SDimitry Andric };
1563ca95b02SDimitry Andric ArrayRef<Constant*> ElementValueArray(ElementValues, 4);
1573ca95b02SDimitry Andric EmuTlsVar->setInitializer(
1583ca95b02SDimitry Andric ConstantStruct::get(EmuTlsVarType, ElementValueArray));
1593ca95b02SDimitry Andric unsigned MaxAlignment = std::max(
1603ca95b02SDimitry Andric DL.getABITypeAlignment(WordType),
1613ca95b02SDimitry Andric DL.getABITypeAlignment(VoidPtrType));
1623ca95b02SDimitry Andric EmuTlsVar->setAlignment(MaxAlignment);
1633ca95b02SDimitry Andric return true;
1643ca95b02SDimitry Andric }
165