181ad6265SDimitry Andric //===- TLSVariableHoist.cpp -------- Remove Redundant TLS Loads ---------===// 281ad6265SDimitry Andric // 381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 681ad6265SDimitry Andric // 781ad6265SDimitry Andric //===----------------------------------------------------------------------===// 881ad6265SDimitry Andric // 981ad6265SDimitry Andric // This pass identifies/eliminate Redundant TLS Loads if related option is set. 1081ad6265SDimitry Andric // The example: Please refer to the comment at the head of TLSVariableHoist.h. 1181ad6265SDimitry Andric // 1281ad6265SDimitry Andric //===----------------------------------------------------------------------===// 1381ad6265SDimitry Andric 1481ad6265SDimitry Andric #include "llvm/ADT/SmallVector.h" 1581ad6265SDimitry Andric #include "llvm/IR/BasicBlock.h" 1681ad6265SDimitry Andric #include "llvm/IR/Dominators.h" 1781ad6265SDimitry Andric #include "llvm/IR/Function.h" 1881ad6265SDimitry Andric #include "llvm/IR/InstrTypes.h" 1981ad6265SDimitry Andric #include "llvm/IR/Instruction.h" 2081ad6265SDimitry Andric #include "llvm/IR/Instructions.h" 2181ad6265SDimitry Andric #include "llvm/IR/IntrinsicInst.h" 2281ad6265SDimitry Andric #include "llvm/IR/Module.h" 2381ad6265SDimitry Andric #include "llvm/IR/Value.h" 2481ad6265SDimitry Andric #include "llvm/InitializePasses.h" 2581ad6265SDimitry Andric #include "llvm/Pass.h" 2681ad6265SDimitry Andric #include "llvm/Support/Casting.h" 2781ad6265SDimitry Andric #include "llvm/Support/Debug.h" 2881ad6265SDimitry Andric #include "llvm/Support/raw_ostream.h" 2981ad6265SDimitry Andric #include "llvm/Transforms/Scalar.h" 3081ad6265SDimitry Andric #include "llvm/Transforms/Scalar/TLSVariableHoist.h" 3181ad6265SDimitry Andric #include <algorithm> 3281ad6265SDimitry Andric #include <cassert> 3381ad6265SDimitry Andric #include <cstdint> 3481ad6265SDimitry Andric #include <iterator> 3581ad6265SDimitry Andric #include <tuple> 3681ad6265SDimitry Andric #include <utility> 3781ad6265SDimitry Andric 3881ad6265SDimitry Andric using namespace llvm; 3981ad6265SDimitry Andric using namespace tlshoist; 4081ad6265SDimitry Andric 4181ad6265SDimitry Andric #define DEBUG_TYPE "tlshoist" 4281ad6265SDimitry Andric 4381ad6265SDimitry Andric static cl::opt<bool> TLSLoadHoist( 4481ad6265SDimitry Andric "tls-load-hoist", cl::init(false), cl::Hidden, 4581ad6265SDimitry Andric cl::desc("hoist the TLS loads in PIC model to eliminate redundant " 4681ad6265SDimitry Andric "TLS address calculation.")); 4781ad6265SDimitry Andric 4881ad6265SDimitry Andric namespace { 4981ad6265SDimitry Andric 5081ad6265SDimitry Andric /// The TLS Variable hoist pass. 5181ad6265SDimitry Andric class TLSVariableHoistLegacyPass : public FunctionPass { 5281ad6265SDimitry Andric public: 5381ad6265SDimitry Andric static char ID; // Pass identification, replacement for typeid 5481ad6265SDimitry Andric 5581ad6265SDimitry Andric TLSVariableHoistLegacyPass() : FunctionPass(ID) { 5681ad6265SDimitry Andric initializeTLSVariableHoistLegacyPassPass(*PassRegistry::getPassRegistry()); 5781ad6265SDimitry Andric } 5881ad6265SDimitry Andric 5981ad6265SDimitry Andric bool runOnFunction(Function &Fn) override; 6081ad6265SDimitry Andric 6181ad6265SDimitry Andric StringRef getPassName() const override { return "TLS Variable Hoist"; } 6281ad6265SDimitry Andric 6381ad6265SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 6481ad6265SDimitry Andric AU.setPreservesCFG(); 6581ad6265SDimitry Andric AU.addRequired<DominatorTreeWrapperPass>(); 6681ad6265SDimitry Andric AU.addRequired<LoopInfoWrapperPass>(); 6781ad6265SDimitry Andric } 6881ad6265SDimitry Andric 6981ad6265SDimitry Andric private: 7081ad6265SDimitry Andric TLSVariableHoistPass Impl; 7181ad6265SDimitry Andric }; 7281ad6265SDimitry Andric 7381ad6265SDimitry Andric } // end anonymous namespace 7481ad6265SDimitry Andric 7581ad6265SDimitry Andric char TLSVariableHoistLegacyPass::ID = 0; 7681ad6265SDimitry Andric 7781ad6265SDimitry Andric INITIALIZE_PASS_BEGIN(TLSVariableHoistLegacyPass, "tlshoist", 7881ad6265SDimitry Andric "TLS Variable Hoist", false, false) 7981ad6265SDimitry Andric INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) 8081ad6265SDimitry Andric INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass) 8181ad6265SDimitry Andric INITIALIZE_PASS_END(TLSVariableHoistLegacyPass, "tlshoist", 8281ad6265SDimitry Andric "TLS Variable Hoist", false, false) 8381ad6265SDimitry Andric 8481ad6265SDimitry Andric FunctionPass *llvm::createTLSVariableHoistPass() { 8581ad6265SDimitry Andric return new TLSVariableHoistLegacyPass(); 8681ad6265SDimitry Andric } 8781ad6265SDimitry Andric 8881ad6265SDimitry Andric /// Perform the TLS Variable Hoist optimization for the given function. 8981ad6265SDimitry Andric bool TLSVariableHoistLegacyPass::runOnFunction(Function &Fn) { 9081ad6265SDimitry Andric if (skipFunction(Fn)) 9181ad6265SDimitry Andric return false; 9281ad6265SDimitry Andric 9381ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "********** Begin TLS Variable Hoist **********\n"); 9481ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "********** Function: " << Fn.getName() << '\n'); 9581ad6265SDimitry Andric 9681ad6265SDimitry Andric bool MadeChange = 9781ad6265SDimitry Andric Impl.runImpl(Fn, getAnalysis<DominatorTreeWrapperPass>().getDomTree(), 9881ad6265SDimitry Andric getAnalysis<LoopInfoWrapperPass>().getLoopInfo()); 9981ad6265SDimitry Andric 10081ad6265SDimitry Andric if (MadeChange) { 10181ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "********** Function after TLS Variable Hoist: " 10281ad6265SDimitry Andric << Fn.getName() << '\n'); 10381ad6265SDimitry Andric LLVM_DEBUG(dbgs() << Fn); 10481ad6265SDimitry Andric } 10581ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "********** End TLS Variable Hoist **********\n"); 10681ad6265SDimitry Andric 10781ad6265SDimitry Andric return MadeChange; 10881ad6265SDimitry Andric } 10981ad6265SDimitry Andric 11081ad6265SDimitry Andric void TLSVariableHoistPass::collectTLSCandidate(Instruction *Inst) { 11181ad6265SDimitry Andric // Skip all cast instructions. They are visited indirectly later on. 11281ad6265SDimitry Andric if (Inst->isCast()) 11381ad6265SDimitry Andric return; 11481ad6265SDimitry Andric 11581ad6265SDimitry Andric // Scan all operands. 11681ad6265SDimitry Andric for (unsigned Idx = 0, E = Inst->getNumOperands(); Idx != E; ++Idx) { 11781ad6265SDimitry Andric auto *GV = dyn_cast<GlobalVariable>(Inst->getOperand(Idx)); 11881ad6265SDimitry Andric if (!GV || !GV->isThreadLocal()) 11981ad6265SDimitry Andric continue; 12081ad6265SDimitry Andric 12181ad6265SDimitry Andric // Add Candidate to TLSCandMap (GV --> Candidate). 12281ad6265SDimitry Andric TLSCandMap[GV].addUser(Inst, Idx); 12381ad6265SDimitry Andric } 12481ad6265SDimitry Andric } 12581ad6265SDimitry Andric 12681ad6265SDimitry Andric void TLSVariableHoistPass::collectTLSCandidates(Function &Fn) { 12781ad6265SDimitry Andric // First, quickly check if there is TLS Variable. 12881ad6265SDimitry Andric Module *M = Fn.getParent(); 12981ad6265SDimitry Andric 13081ad6265SDimitry Andric bool HasTLS = llvm::any_of( 13181ad6265SDimitry Andric M->globals(), [](GlobalVariable &GV) { return GV.isThreadLocal(); }); 13281ad6265SDimitry Andric 13381ad6265SDimitry Andric // If non, directly return. 13481ad6265SDimitry Andric if (!HasTLS) 13581ad6265SDimitry Andric return; 13681ad6265SDimitry Andric 13781ad6265SDimitry Andric TLSCandMap.clear(); 13881ad6265SDimitry Andric 13981ad6265SDimitry Andric // Then, collect TLS Variable info. 14081ad6265SDimitry Andric for (BasicBlock &BB : Fn) { 14181ad6265SDimitry Andric // Ignore unreachable basic blocks. 14281ad6265SDimitry Andric if (!DT->isReachableFromEntry(&BB)) 14381ad6265SDimitry Andric continue; 14481ad6265SDimitry Andric 14581ad6265SDimitry Andric for (Instruction &Inst : BB) 14681ad6265SDimitry Andric collectTLSCandidate(&Inst); 14781ad6265SDimitry Andric } 14881ad6265SDimitry Andric } 14981ad6265SDimitry Andric 15081ad6265SDimitry Andric static bool oneUseOutsideLoop(tlshoist::TLSCandidate &Cand, LoopInfo *LI) { 15181ad6265SDimitry Andric if (Cand.Users.size() != 1) 15281ad6265SDimitry Andric return false; 15381ad6265SDimitry Andric 15481ad6265SDimitry Andric BasicBlock *BB = Cand.Users[0].Inst->getParent(); 15581ad6265SDimitry Andric if (LI->getLoopFor(BB)) 15681ad6265SDimitry Andric return false; 15781ad6265SDimitry Andric 15881ad6265SDimitry Andric return true; 15981ad6265SDimitry Andric } 16081ad6265SDimitry Andric 16181ad6265SDimitry Andric Instruction *TLSVariableHoistPass::getNearestLoopDomInst(BasicBlock *BB, 16281ad6265SDimitry Andric Loop *L) { 16381ad6265SDimitry Andric assert(L && "Unexcepted Loop status!"); 16481ad6265SDimitry Andric 16581ad6265SDimitry Andric // Get the outermost loop. 16681ad6265SDimitry Andric while (Loop *Parent = L->getParentLoop()) 16781ad6265SDimitry Andric L = Parent; 16881ad6265SDimitry Andric 16981ad6265SDimitry Andric BasicBlock *PreHeader = L->getLoopPreheader(); 17081ad6265SDimitry Andric 17181ad6265SDimitry Andric // There is unique predecessor outside the loop. 17281ad6265SDimitry Andric if (PreHeader) 17381ad6265SDimitry Andric return PreHeader->getTerminator(); 17481ad6265SDimitry Andric 17581ad6265SDimitry Andric BasicBlock *Header = L->getHeader(); 17681ad6265SDimitry Andric BasicBlock *Dom = Header; 17781ad6265SDimitry Andric for (BasicBlock *PredBB : predecessors(Header)) 17881ad6265SDimitry Andric Dom = DT->findNearestCommonDominator(Dom, PredBB); 17981ad6265SDimitry Andric 18081ad6265SDimitry Andric assert(Dom && "Not find dominator BB!"); 18181ad6265SDimitry Andric Instruction *Term = Dom->getTerminator(); 18281ad6265SDimitry Andric 18381ad6265SDimitry Andric return Term; 18481ad6265SDimitry Andric } 18581ad6265SDimitry Andric 18681ad6265SDimitry Andric Instruction *TLSVariableHoistPass::getDomInst(Instruction *I1, 18781ad6265SDimitry Andric Instruction *I2) { 18881ad6265SDimitry Andric if (!I1) 18981ad6265SDimitry Andric return I2; 190*bdd1243dSDimitry Andric return DT->findNearestCommonDominator(I1, I2); 19181ad6265SDimitry Andric } 19281ad6265SDimitry Andric 19381ad6265SDimitry Andric BasicBlock::iterator TLSVariableHoistPass::findInsertPos(Function &Fn, 19481ad6265SDimitry Andric GlobalVariable *GV, 19581ad6265SDimitry Andric BasicBlock *&PosBB) { 19681ad6265SDimitry Andric tlshoist::TLSCandidate &Cand = TLSCandMap[GV]; 19781ad6265SDimitry Andric 19881ad6265SDimitry Andric // We should hoist the TLS use out of loop, so choose its nearest instruction 19981ad6265SDimitry Andric // which dominate the loop and the outside loops (if exist). 20081ad6265SDimitry Andric Instruction *LastPos = nullptr; 20181ad6265SDimitry Andric for (auto &User : Cand.Users) { 20281ad6265SDimitry Andric BasicBlock *BB = User.Inst->getParent(); 20381ad6265SDimitry Andric Instruction *Pos = User.Inst; 20481ad6265SDimitry Andric if (Loop *L = LI->getLoopFor(BB)) { 20581ad6265SDimitry Andric Pos = getNearestLoopDomInst(BB, L); 20681ad6265SDimitry Andric assert(Pos && "Not find insert position out of loop!"); 20781ad6265SDimitry Andric } 20881ad6265SDimitry Andric Pos = getDomInst(LastPos, Pos); 20981ad6265SDimitry Andric LastPos = Pos; 21081ad6265SDimitry Andric } 21181ad6265SDimitry Andric 21281ad6265SDimitry Andric assert(LastPos && "Unexpected insert position!"); 21381ad6265SDimitry Andric BasicBlock *Parent = LastPos->getParent(); 21481ad6265SDimitry Andric PosBB = Parent; 21581ad6265SDimitry Andric return LastPos->getIterator(); 21681ad6265SDimitry Andric } 21781ad6265SDimitry Andric 21881ad6265SDimitry Andric // Generate a bitcast (no type change) to replace the uses of TLS Candidate. 21981ad6265SDimitry Andric Instruction *TLSVariableHoistPass::genBitCastInst(Function &Fn, 22081ad6265SDimitry Andric GlobalVariable *GV) { 22181ad6265SDimitry Andric BasicBlock *PosBB = &Fn.getEntryBlock(); 22281ad6265SDimitry Andric BasicBlock::iterator Iter = findInsertPos(Fn, GV, PosBB); 22381ad6265SDimitry Andric Type *Ty = GV->getType(); 22481ad6265SDimitry Andric auto *CastInst = new BitCastInst(GV, Ty, "tls_bitcast"); 225*bdd1243dSDimitry Andric CastInst->insertInto(PosBB, Iter); 22681ad6265SDimitry Andric return CastInst; 22781ad6265SDimitry Andric } 22881ad6265SDimitry Andric 22981ad6265SDimitry Andric bool TLSVariableHoistPass::tryReplaceTLSCandidate(Function &Fn, 23081ad6265SDimitry Andric GlobalVariable *GV) { 23181ad6265SDimitry Andric 23281ad6265SDimitry Andric tlshoist::TLSCandidate &Cand = TLSCandMap[GV]; 23381ad6265SDimitry Andric 23481ad6265SDimitry Andric // If only used 1 time and not in loops, we no need to replace it. 23581ad6265SDimitry Andric if (oneUseOutsideLoop(Cand, LI)) 23681ad6265SDimitry Andric return false; 23781ad6265SDimitry Andric 23881ad6265SDimitry Andric // Generate a bitcast (no type change) 23981ad6265SDimitry Andric auto *CastInst = genBitCastInst(Fn, GV); 24081ad6265SDimitry Andric 24181ad6265SDimitry Andric // to replace the uses of TLS Candidate 24281ad6265SDimitry Andric for (auto &User : Cand.Users) 24381ad6265SDimitry Andric User.Inst->setOperand(User.OpndIdx, CastInst); 24481ad6265SDimitry Andric 24581ad6265SDimitry Andric return true; 24681ad6265SDimitry Andric } 24781ad6265SDimitry Andric 24881ad6265SDimitry Andric bool TLSVariableHoistPass::tryReplaceTLSCandidates(Function &Fn) { 24981ad6265SDimitry Andric if (TLSCandMap.empty()) 25081ad6265SDimitry Andric return false; 25181ad6265SDimitry Andric 25281ad6265SDimitry Andric bool Replaced = false; 25381ad6265SDimitry Andric for (auto &GV2Cand : TLSCandMap) { 25481ad6265SDimitry Andric GlobalVariable *GV = GV2Cand.first; 25581ad6265SDimitry Andric Replaced |= tryReplaceTLSCandidate(Fn, GV); 25681ad6265SDimitry Andric } 25781ad6265SDimitry Andric 25881ad6265SDimitry Andric return Replaced; 25981ad6265SDimitry Andric } 26081ad6265SDimitry Andric 26181ad6265SDimitry Andric /// Optimize expensive TLS variables in the given function. 26281ad6265SDimitry Andric bool TLSVariableHoistPass::runImpl(Function &Fn, DominatorTree &DT, 26381ad6265SDimitry Andric LoopInfo &LI) { 26481ad6265SDimitry Andric if (Fn.hasOptNone()) 26581ad6265SDimitry Andric return false; 26681ad6265SDimitry Andric 26781ad6265SDimitry Andric if (!TLSLoadHoist && !Fn.getAttributes().hasFnAttr("tls-load-hoist")) 26881ad6265SDimitry Andric return false; 26981ad6265SDimitry Andric 27081ad6265SDimitry Andric this->LI = &LI; 27181ad6265SDimitry Andric this->DT = &DT; 27281ad6265SDimitry Andric assert(this->LI && this->DT && "Unexcepted requirement!"); 27381ad6265SDimitry Andric 27481ad6265SDimitry Andric // Collect all TLS variable candidates. 27581ad6265SDimitry Andric collectTLSCandidates(Fn); 27681ad6265SDimitry Andric 27781ad6265SDimitry Andric bool MadeChange = tryReplaceTLSCandidates(Fn); 27881ad6265SDimitry Andric 27981ad6265SDimitry Andric return MadeChange; 28081ad6265SDimitry Andric } 28181ad6265SDimitry Andric 28281ad6265SDimitry Andric PreservedAnalyses TLSVariableHoistPass::run(Function &F, 28381ad6265SDimitry Andric FunctionAnalysisManager &AM) { 28481ad6265SDimitry Andric 28581ad6265SDimitry Andric auto &LI = AM.getResult<LoopAnalysis>(F); 28681ad6265SDimitry Andric auto &DT = AM.getResult<DominatorTreeAnalysis>(F); 28781ad6265SDimitry Andric 28881ad6265SDimitry Andric if (!runImpl(F, DT, LI)) 28981ad6265SDimitry Andric return PreservedAnalyses::all(); 29081ad6265SDimitry Andric 29181ad6265SDimitry Andric PreservedAnalyses PA; 29281ad6265SDimitry Andric PA.preserveSet<CFGAnalyses>(); 29381ad6265SDimitry Andric return PA; 29481ad6265SDimitry Andric } 295