176 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This transformation is required for targets depending on libgcc style10// emulated thread local storage variables. For every defined TLS variable xyz,11// an __emutls_v.xyz is generated. If there is non-zero initialized value12// 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 29using namespace llvm;30 31#define DEBUG_TYPE "lower-emutls"32 33namespace {34 35class LowerEmuTLS : public ModulePass {36public:37 static char ID; // Pass identification, replacement for typeid38 LowerEmuTLS() : ModulePass(ID) {39 initializeLowerEmuTLSPass(*PassRegistry::getPassRegistry());40 }41 42 bool runOnModule(Module &M) override;43};44}45 46static bool addEmuTlsVar(Module &M, const GlobalVariable *GV);47 48static 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 59PreservedAnalyses 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 78char LowerEmuTLS::ID = 0;79 80INITIALIZE_PASS(LowerEmuTLS, DEBUG_TYPE,81 "Add __emutls_[vt]. variables for emultated TLS model", false,82 false)83 84ModulePass *llvm::createLowerEmuTLSPass() { return new LowerEmuTLS(); }85 86bool 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 109bool 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 let127 // 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 bytes135 // word align; // alignment of GV136 // 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 = M.getOrInsertGlobal(EmuTlsVarName, EmuTlsVarType);144 copyLinkageVisibility(M, GV, EmuTlsVar);145 146 // Define "__emutls_t.*" and "__emutls_v.*" only if GV is defined.147 if (!GV->hasInitializer())148 return true;149 150 Type *GVType = GV->getValueType();151 Align GVAlignment = DL.getValueOrABITypeAlignment(GV->getAlign(), GVType);152 153 // Define "__emutls_t.*" if there is InitValue154 GlobalVariable *EmuTlsTmplVar = nullptr;155 if (InitValue) {156 std::string EmuTlsTmplName = ("__emutls_t." + GV->getName()).str();157 EmuTlsTmplVar = M.getOrInsertGlobal(EmuTlsTmplName, GVType);158 assert(EmuTlsTmplVar && "Failed to create emualted TLS initializer");159 EmuTlsTmplVar->setConstant(true);160 EmuTlsTmplVar->setInitializer(const_cast<Constant*>(InitValue));161 EmuTlsTmplVar->setAlignment(GVAlignment);162 copyLinkageVisibility(M, GV, EmuTlsTmplVar);163 }164 165 // Define "__emutls_v.*" with initializer and alignment.166 Constant *ElementValues[4] = {167 ConstantInt::get(WordType, DL.getTypeStoreSize(GVType)),168 ConstantInt::get(WordType, GVAlignment.value()), NullPtr,169 EmuTlsTmplVar ? EmuTlsTmplVar : NullPtr};170 EmuTlsVar->setInitializer(ConstantStruct::get(EmuTlsVarType, ElementValues));171 Align MaxAlignment =172 std::max(DL.getABITypeAlign(WordType), DL.getABITypeAlign(VoidPtrType));173 EmuTlsVar->setAlignment(MaxAlignment);174 return true;175}176