157886400SChih-Hung Hsieh //===- LowerEmuTLS.cpp - Add __emutls_[vt].* variables --------------------===//
257886400SChih-Hung Hsieh //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
657886400SChih-Hung Hsieh //
757886400SChih-Hung Hsieh //===----------------------------------------------------------------------===//
857886400SChih-Hung Hsieh //
957886400SChih-Hung Hsieh // This transformation is required for targets depending on libgcc style
1057886400SChih-Hung Hsieh // emulated thread local storage variables. For every defined TLS variable xyz,
1157886400SChih-Hung Hsieh // an __emutls_v.xyz is generated. If there is non-zero initialized value
1257886400SChih-Hung Hsieh // an __emutls_t.xyz is also generated.
1357886400SChih-Hung Hsieh //
1457886400SChih-Hung Hsieh //===----------------------------------------------------------------------===//
1557886400SChih-Hung Hsieh
1657886400SChih-Hung Hsieh #include "llvm/ADT/SmallVector.h"
17c67cf31fSBenjamin Kramer #include "llvm/CodeGen/Passes.h"
188b61764cSFrancis Visoiu Mistrih #include "llvm/CodeGen/TargetPassConfig.h"
1991848b11SSimon Pilgrim #include "llvm/IR/Constants.h"
2057886400SChih-Hung Hsieh #include "llvm/IR/Module.h"
2105da2fe5SReid Kleckner #include "llvm/InitializePasses.h"
2257886400SChih-Hung Hsieh #include "llvm/Pass.h"
23fe0006c8SSimon Pilgrim #include "llvm/Target/TargetMachine.h"
2457886400SChih-Hung Hsieh
2557886400SChih-Hung Hsieh using namespace llvm;
2657886400SChih-Hung Hsieh
2757886400SChih-Hung Hsieh #define DEBUG_TYPE "loweremutls"
2857886400SChih-Hung Hsieh
2957886400SChih-Hung Hsieh namespace {
3057886400SChih-Hung Hsieh
3157886400SChih-Hung Hsieh class LowerEmuTLS : public ModulePass {
3257886400SChih-Hung Hsieh public:
3357886400SChih-Hung Hsieh static char ID; // Pass identification, replacement for typeid
LowerEmuTLS()348b61764cSFrancis Visoiu Mistrih LowerEmuTLS() : ModulePass(ID) {
3557886400SChih-Hung Hsieh initializeLowerEmuTLSPass(*PassRegistry::getPassRegistry());
3657886400SChih-Hung Hsieh }
378b61764cSFrancis Visoiu Mistrih
3857886400SChih-Hung Hsieh bool runOnModule(Module &M) override;
3957886400SChih-Hung Hsieh private:
4057886400SChih-Hung Hsieh bool addEmuTlsVar(Module &M, const GlobalVariable *GV);
copyLinkageVisibility(Module & M,const GlobalVariable * from,GlobalVariable * to)4157886400SChih-Hung Hsieh static void copyLinkageVisibility(Module &M,
4257886400SChih-Hung Hsieh const GlobalVariable *from,
4357886400SChih-Hung Hsieh GlobalVariable *to) {
4457886400SChih-Hung Hsieh to->setLinkage(from->getLinkage());
4557886400SChih-Hung Hsieh to->setVisibility(from->getVisibility());
46f7318395SFangrui Song to->setDSOLocal(from->isDSOLocal());
4757886400SChih-Hung Hsieh if (from->hasComdat()) {
4857886400SChih-Hung Hsieh to->setComdat(M.getOrInsertComdat(to->getName()));
4957886400SChih-Hung Hsieh to->getComdat()->setSelectionKind(from->getComdat()->getSelectionKind());
5057886400SChih-Hung Hsieh }
5157886400SChih-Hung Hsieh }
5257886400SChih-Hung Hsieh };
5357886400SChih-Hung Hsieh }
5457886400SChih-Hung Hsieh
5557886400SChih-Hung Hsieh char LowerEmuTLS::ID = 0;
5657886400SChih-Hung Hsieh
571527baabSMatthias Braun INITIALIZE_PASS(LowerEmuTLS, DEBUG_TYPE,
588b61764cSFrancis Visoiu Mistrih "Add __emutls_[vt]. variables for emultated TLS model", false,
598b61764cSFrancis Visoiu Mistrih false)
6057886400SChih-Hung Hsieh
createLowerEmuTLSPass()618b61764cSFrancis Visoiu Mistrih ModulePass *llvm::createLowerEmuTLSPass() { return new LowerEmuTLS(); }
6257886400SChih-Hung Hsieh
runOnModule(Module & M)6357886400SChih-Hung Hsieh bool LowerEmuTLS::runOnModule(Module &M) {
64aa641a51SAndrew Kaylor if (skipModule(M))
65aa641a51SAndrew Kaylor return false;
66aa641a51SAndrew Kaylor
678b61764cSFrancis Visoiu Mistrih auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();
688b61764cSFrancis Visoiu Mistrih if (!TPC)
698b61764cSFrancis Visoiu Mistrih return false;
708b61764cSFrancis Visoiu Mistrih
718b61764cSFrancis Visoiu Mistrih auto &TM = TPC->getTM<TargetMachine>();
729f9e4681SChih-Hung Hsieh if (!TM.useEmulatedTLS())
7357886400SChih-Hung Hsieh return false;
7457886400SChih-Hung Hsieh
7557886400SChih-Hung Hsieh bool Changed = false;
7657886400SChih-Hung Hsieh SmallVector<const GlobalVariable*, 8> TlsVars;
7757886400SChih-Hung Hsieh for (const auto &G : M.globals()) {
7857886400SChih-Hung Hsieh if (G.isThreadLocal())
7957886400SChih-Hung Hsieh TlsVars.append({&G});
8057886400SChih-Hung Hsieh }
81*9e6d1f4bSKazu Hirata for (const auto *const G : TlsVars)
8257886400SChih-Hung Hsieh Changed |= addEmuTlsVar(M, G);
8357886400SChih-Hung Hsieh return Changed;
8457886400SChih-Hung Hsieh }
8557886400SChih-Hung Hsieh
addEmuTlsVar(Module & M,const GlobalVariable * GV)8657886400SChih-Hung Hsieh bool LowerEmuTLS::addEmuTlsVar(Module &M, const GlobalVariable *GV) {
8757886400SChih-Hung Hsieh LLVMContext &C = M.getContext();
8857886400SChih-Hung Hsieh PointerType *VoidPtrType = Type::getInt8PtrTy(C);
8957886400SChih-Hung Hsieh
9057886400SChih-Hung Hsieh std::string EmuTlsVarName = ("__emutls_v." + GV->getName()).str();
9157886400SChih-Hung Hsieh GlobalVariable *EmuTlsVar = M.getNamedGlobal(EmuTlsVarName);
9257886400SChih-Hung Hsieh if (EmuTlsVar)
9357886400SChih-Hung Hsieh return false; // It has been added before.
9457886400SChih-Hung Hsieh
9557886400SChih-Hung Hsieh const DataLayout &DL = M.getDataLayout();
9657886400SChih-Hung Hsieh Constant *NullPtr = ConstantPointerNull::get(VoidPtrType);
9757886400SChih-Hung Hsieh
9857886400SChih-Hung Hsieh // Get non-zero initializer from GV's initializer.
9957886400SChih-Hung Hsieh const Constant *InitValue = nullptr;
10057886400SChih-Hung Hsieh if (GV->hasInitializer()) {
10157886400SChih-Hung Hsieh InitValue = GV->getInitializer();
10257886400SChih-Hung Hsieh const ConstantInt *InitIntValue = dyn_cast<ConstantInt>(InitValue);
10357886400SChih-Hung Hsieh // When GV's init value is all 0, omit the EmuTlsTmplVar and let
10457886400SChih-Hung Hsieh // the emutls library function to reset newly allocated TLS variables.
10557886400SChih-Hung Hsieh if (isa<ConstantAggregateZero>(InitValue) ||
10657886400SChih-Hung Hsieh (InitIntValue && InitIntValue->isZero()))
10757886400SChih-Hung Hsieh InitValue = nullptr;
10857886400SChih-Hung Hsieh }
10957886400SChih-Hung Hsieh
11057886400SChih-Hung Hsieh // Create the __emutls_v. symbol, whose type has 4 fields:
11157886400SChih-Hung Hsieh // word size; // size of GV in bytes
11257886400SChih-Hung Hsieh // word align; // alignment of GV
11357886400SChih-Hung Hsieh // void *ptr; // initialized to 0; set at run time per thread.
11457886400SChih-Hung Hsieh // void *templ; // 0 or point to __emutls_t.*
11557886400SChih-Hung Hsieh // sizeof(word) should be the same as sizeof(void*) on target.
11657886400SChih-Hung Hsieh IntegerType *WordType = DL.getIntPtrType(C);
11757886400SChih-Hung Hsieh PointerType *InitPtrType = InitValue ?
11857886400SChih-Hung Hsieh PointerType::getUnqual(InitValue->getType()) : VoidPtrType;
11957886400SChih-Hung Hsieh Type *ElementTypes[4] = {WordType, WordType, VoidPtrType, InitPtrType};
12057886400SChih-Hung Hsieh ArrayRef<Type*> ElementTypeArray(ElementTypes, 4);
12157886400SChih-Hung Hsieh StructType *EmuTlsVarType = StructType::create(ElementTypeArray);
12257886400SChih-Hung Hsieh EmuTlsVar = cast<GlobalVariable>(
12357886400SChih-Hung Hsieh M.getOrInsertGlobal(EmuTlsVarName, EmuTlsVarType));
12457886400SChih-Hung Hsieh copyLinkageVisibility(M, GV, EmuTlsVar);
12557886400SChih-Hung Hsieh
12657886400SChih-Hung Hsieh // Define "__emutls_t.*" and "__emutls_v.*" only if GV is defined.
12757886400SChih-Hung Hsieh if (!GV->hasInitializer())
12857886400SChih-Hung Hsieh return true;
12957886400SChih-Hung Hsieh
13057886400SChih-Hung Hsieh Type *GVType = GV->getValueType();
131d3085c25SGuillaume Chatelet Align GVAlignment = DL.getValueOrABITypeAlignment(GV->getAlign(), GVType);
13257886400SChih-Hung Hsieh
13357886400SChih-Hung Hsieh // Define "__emutls_t.*" if there is InitValue
13457886400SChih-Hung Hsieh GlobalVariable *EmuTlsTmplVar = nullptr;
13557886400SChih-Hung Hsieh if (InitValue) {
13657886400SChih-Hung Hsieh std::string EmuTlsTmplName = ("__emutls_t." + GV->getName()).str();
13757886400SChih-Hung Hsieh EmuTlsTmplVar = dyn_cast_or_null<GlobalVariable>(
13857886400SChih-Hung Hsieh M.getOrInsertGlobal(EmuTlsTmplName, GVType));
13957886400SChih-Hung Hsieh assert(EmuTlsTmplVar && "Failed to create emualted TLS initializer");
14057886400SChih-Hung Hsieh EmuTlsTmplVar->setConstant(true);
14157886400SChih-Hung Hsieh EmuTlsTmplVar->setInitializer(const_cast<Constant*>(InitValue));
142d3085c25SGuillaume Chatelet EmuTlsTmplVar->setAlignment(GVAlignment);
14357886400SChih-Hung Hsieh copyLinkageVisibility(M, GV, EmuTlsTmplVar);
14457886400SChih-Hung Hsieh }
14557886400SChih-Hung Hsieh
14657886400SChih-Hung Hsieh // Define "__emutls_v.*" with initializer and alignment.
14757886400SChih-Hung Hsieh Constant *ElementValues[4] = {
14857886400SChih-Hung Hsieh ConstantInt::get(WordType, DL.getTypeStoreSize(GVType)),
149d3085c25SGuillaume Chatelet ConstantInt::get(WordType, GVAlignment.value()), NullPtr,
150d3085c25SGuillaume Chatelet EmuTlsTmplVar ? EmuTlsTmplVar : NullPtr};
15157886400SChih-Hung Hsieh ArrayRef<Constant*> ElementValueArray(ElementValues, 4);
15257886400SChih-Hung Hsieh EmuTlsVar->setInitializer(
15357886400SChih-Hung Hsieh ConstantStruct::get(EmuTlsVarType, ElementValueArray));
154d3085c25SGuillaume Chatelet Align MaxAlignment =
155d3085c25SGuillaume Chatelet std::max(DL.getABITypeAlign(WordType), DL.getABITypeAlign(VoidPtrType));
15657886400SChih-Hung Hsieh EmuTlsVar->setAlignment(MaxAlignment);
15757886400SChih-Hung Hsieh return true;
15857886400SChih-Hung Hsieh }
159