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