1c3101432SXiang1 Zhang //===- TLSVariableHoist.cpp -------- Remove Redundant TLS Loads ---------===//
2c3101432SXiang1 Zhang //
3c3101432SXiang1 Zhang // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4c3101432SXiang1 Zhang // See https://llvm.org/LICENSE.txt for license information.
5c3101432SXiang1 Zhang // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6c3101432SXiang1 Zhang //
7c3101432SXiang1 Zhang //===----------------------------------------------------------------------===//
8c3101432SXiang1 Zhang //
9c3101432SXiang1 Zhang // This pass identifies/eliminate Redundant TLS Loads if related option is set.
10c3101432SXiang1 Zhang // The example: Please refer to the comment at the head of TLSVariableHoist.h.
11c3101432SXiang1 Zhang //
12c3101432SXiang1 Zhang //===----------------------------------------------------------------------===//
13c3101432SXiang1 Zhang 
14c3101432SXiang1 Zhang #include "llvm/ADT/SmallVector.h"
15c3101432SXiang1 Zhang #include "llvm/IR/BasicBlock.h"
16c3101432SXiang1 Zhang #include "llvm/IR/Dominators.h"
17c3101432SXiang1 Zhang #include "llvm/IR/Function.h"
18c3101432SXiang1 Zhang #include "llvm/IR/InstrTypes.h"
19c3101432SXiang1 Zhang #include "llvm/IR/Instruction.h"
20c3101432SXiang1 Zhang #include "llvm/IR/Instructions.h"
21c3101432SXiang1 Zhang #include "llvm/IR/IntrinsicInst.h"
22c3101432SXiang1 Zhang #include "llvm/IR/Module.h"
23c3101432SXiang1 Zhang #include "llvm/IR/Value.h"
24c3101432SXiang1 Zhang #include "llvm/InitializePasses.h"
25c3101432SXiang1 Zhang #include "llvm/Pass.h"
26c3101432SXiang1 Zhang #include "llvm/Support/Casting.h"
27c3101432SXiang1 Zhang #include "llvm/Support/Debug.h"
28c3101432SXiang1 Zhang #include "llvm/Support/raw_ostream.h"
29c3101432SXiang1 Zhang #include "llvm/Transforms/Scalar.h"
30c3101432SXiang1 Zhang #include "llvm/Transforms/Scalar/TLSVariableHoist.h"
31c3101432SXiang1 Zhang #include <algorithm>
32c3101432SXiang1 Zhang #include <cassert>
33c3101432SXiang1 Zhang #include <cstdint>
34c3101432SXiang1 Zhang #include <iterator>
35c3101432SXiang1 Zhang #include <tuple>
36c3101432SXiang1 Zhang #include <utility>
37c3101432SXiang1 Zhang 
38c3101432SXiang1 Zhang using namespace llvm;
39c3101432SXiang1 Zhang using namespace tlshoist;
40c3101432SXiang1 Zhang 
41c3101432SXiang1 Zhang #define DEBUG_TYPE "tlshoist"
42c3101432SXiang1 Zhang 
43a56f2649SXiang1 Zhang static cl::opt<bool> TLSLoadHoist(
44a56f2649SXiang1 Zhang     "tls-load-hoist", cl::init(false), cl::Hidden,
45*f830392bSXiang1 Zhang     cl::desc("hoist the TLS loads in PIC model to eliminate redundant "
46a56f2649SXiang1 Zhang              "TLS address calculation."));
47c3101432SXiang1 Zhang 
48c3101432SXiang1 Zhang namespace {
49c3101432SXiang1 Zhang 
50c3101432SXiang1 Zhang /// The TLS Variable hoist pass.
51c3101432SXiang1 Zhang class TLSVariableHoistLegacyPass : public FunctionPass {
52c3101432SXiang1 Zhang public:
53c3101432SXiang1 Zhang   static char ID; // Pass identification, replacement for typeid
54c3101432SXiang1 Zhang 
TLSVariableHoistLegacyPass()55c3101432SXiang1 Zhang   TLSVariableHoistLegacyPass() : FunctionPass(ID) {
56c3101432SXiang1 Zhang     initializeTLSVariableHoistLegacyPassPass(*PassRegistry::getPassRegistry());
57c3101432SXiang1 Zhang   }
58c3101432SXiang1 Zhang 
59c3101432SXiang1 Zhang   bool runOnFunction(Function &Fn) override;
60c3101432SXiang1 Zhang 
getPassName() const61c3101432SXiang1 Zhang   StringRef getPassName() const override { return "TLS Variable Hoist"; }
62c3101432SXiang1 Zhang 
getAnalysisUsage(AnalysisUsage & AU) const63c3101432SXiang1 Zhang   void getAnalysisUsage(AnalysisUsage &AU) const override {
64c3101432SXiang1 Zhang     AU.setPreservesCFG();
65c3101432SXiang1 Zhang     AU.addRequired<DominatorTreeWrapperPass>();
66c3101432SXiang1 Zhang     AU.addRequired<LoopInfoWrapperPass>();
67c3101432SXiang1 Zhang   }
68c3101432SXiang1 Zhang 
69c3101432SXiang1 Zhang private:
70c3101432SXiang1 Zhang   TLSVariableHoistPass Impl;
71c3101432SXiang1 Zhang };
72c3101432SXiang1 Zhang 
73c3101432SXiang1 Zhang } // end anonymous namespace
74c3101432SXiang1 Zhang 
75c3101432SXiang1 Zhang char TLSVariableHoistLegacyPass::ID = 0;
76c3101432SXiang1 Zhang 
77c3101432SXiang1 Zhang INITIALIZE_PASS_BEGIN(TLSVariableHoistLegacyPass, "tlshoist",
78c3101432SXiang1 Zhang                       "TLS Variable Hoist", false, false)
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)79c3101432SXiang1 Zhang INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
80c3101432SXiang1 Zhang INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass)
81c3101432SXiang1 Zhang INITIALIZE_PASS_END(TLSVariableHoistLegacyPass, "tlshoist",
82c3101432SXiang1 Zhang                     "TLS Variable Hoist", false, false)
83c3101432SXiang1 Zhang 
84c3101432SXiang1 Zhang FunctionPass *llvm::createTLSVariableHoistPass() {
85c3101432SXiang1 Zhang   return new TLSVariableHoistLegacyPass();
86c3101432SXiang1 Zhang }
87c3101432SXiang1 Zhang 
88c3101432SXiang1 Zhang /// Perform the TLS Variable Hoist optimization for the given function.
runOnFunction(Function & Fn)89c3101432SXiang1 Zhang bool TLSVariableHoistLegacyPass::runOnFunction(Function &Fn) {
90c3101432SXiang1 Zhang   if (skipFunction(Fn))
91c3101432SXiang1 Zhang     return false;
92c3101432SXiang1 Zhang 
93c3101432SXiang1 Zhang   LLVM_DEBUG(dbgs() << "********** Begin TLS Variable Hoist **********\n");
94c3101432SXiang1 Zhang   LLVM_DEBUG(dbgs() << "********** Function: " << Fn.getName() << '\n');
95c3101432SXiang1 Zhang 
96c3101432SXiang1 Zhang   bool MadeChange =
97c3101432SXiang1 Zhang       Impl.runImpl(Fn, getAnalysis<DominatorTreeWrapperPass>().getDomTree(),
98c3101432SXiang1 Zhang                    getAnalysis<LoopInfoWrapperPass>().getLoopInfo());
99c3101432SXiang1 Zhang 
100c3101432SXiang1 Zhang   if (MadeChange) {
101c3101432SXiang1 Zhang     LLVM_DEBUG(dbgs() << "********** Function after TLS Variable Hoist: "
102c3101432SXiang1 Zhang                       << Fn.getName() << '\n');
103c3101432SXiang1 Zhang     LLVM_DEBUG(dbgs() << Fn);
104c3101432SXiang1 Zhang   }
105c3101432SXiang1 Zhang   LLVM_DEBUG(dbgs() << "********** End TLS Variable Hoist **********\n");
106c3101432SXiang1 Zhang 
107c3101432SXiang1 Zhang   return MadeChange;
108c3101432SXiang1 Zhang }
109c3101432SXiang1 Zhang 
collectTLSCandidate(Instruction * Inst)110c3101432SXiang1 Zhang void TLSVariableHoistPass::collectTLSCandidate(Instruction *Inst) {
111c3101432SXiang1 Zhang   // Skip all cast instructions. They are visited indirectly later on.
112c3101432SXiang1 Zhang   if (Inst->isCast())
113c3101432SXiang1 Zhang     return;
114c3101432SXiang1 Zhang 
115c3101432SXiang1 Zhang   // Scan all operands.
116c3101432SXiang1 Zhang   for (unsigned Idx = 0, E = Inst->getNumOperands(); Idx != E; ++Idx) {
117c3101432SXiang1 Zhang     auto *GV = dyn_cast<GlobalVariable>(Inst->getOperand(Idx));
118c3101432SXiang1 Zhang     if (!GV || !GV->isThreadLocal())
119c3101432SXiang1 Zhang       continue;
120c3101432SXiang1 Zhang 
121c3101432SXiang1 Zhang     // Add Candidate to TLSCandMap (GV --> Candidate).
122c3101432SXiang1 Zhang     TLSCandMap[GV].addUser(Inst, Idx);
123c3101432SXiang1 Zhang   }
124c3101432SXiang1 Zhang }
125c3101432SXiang1 Zhang 
collectTLSCandidates(Function & Fn)126c3101432SXiang1 Zhang void TLSVariableHoistPass::collectTLSCandidates(Function &Fn) {
127c3101432SXiang1 Zhang   // First, quickly check if there is TLS Variable.
128c3101432SXiang1 Zhang   Module *M = Fn.getParent();
129c3101432SXiang1 Zhang 
130c3101432SXiang1 Zhang   bool HasTLS = llvm::any_of(
131c3101432SXiang1 Zhang       M->globals(), [](GlobalVariable &GV) { return GV.isThreadLocal(); });
132c3101432SXiang1 Zhang 
133c3101432SXiang1 Zhang   // If non, directly return.
134c3101432SXiang1 Zhang   if (!HasTLS)
135c3101432SXiang1 Zhang     return;
136c3101432SXiang1 Zhang 
137c3101432SXiang1 Zhang   TLSCandMap.clear();
138c3101432SXiang1 Zhang 
139c3101432SXiang1 Zhang   // Then, collect TLS Variable info.
140c3101432SXiang1 Zhang   for (BasicBlock &BB : Fn) {
141c3101432SXiang1 Zhang     // Ignore unreachable basic blocks.
142c3101432SXiang1 Zhang     if (!DT->isReachableFromEntry(&BB))
143c3101432SXiang1 Zhang       continue;
144c3101432SXiang1 Zhang 
145c3101432SXiang1 Zhang     for (Instruction &Inst : BB)
146c3101432SXiang1 Zhang       collectTLSCandidate(&Inst);
147c3101432SXiang1 Zhang   }
148c3101432SXiang1 Zhang }
149c3101432SXiang1 Zhang 
oneUseOutsideLoop(tlshoist::TLSCandidate & Cand,LoopInfo * LI)150c3101432SXiang1 Zhang static bool oneUseOutsideLoop(tlshoist::TLSCandidate &Cand, LoopInfo *LI) {
151c3101432SXiang1 Zhang   if (Cand.Users.size() != 1)
152c3101432SXiang1 Zhang     return false;
153c3101432SXiang1 Zhang 
154c3101432SXiang1 Zhang   BasicBlock *BB = Cand.Users[0].Inst->getParent();
155c3101432SXiang1 Zhang   if (LI->getLoopFor(BB))
156c3101432SXiang1 Zhang     return false;
157c3101432SXiang1 Zhang 
158c3101432SXiang1 Zhang   return true;
159c3101432SXiang1 Zhang }
160c3101432SXiang1 Zhang 
getNearestLoopDomInst(BasicBlock * BB,Loop * L)161c3101432SXiang1 Zhang Instruction *TLSVariableHoistPass::getNearestLoopDomInst(BasicBlock *BB,
162c3101432SXiang1 Zhang                                                          Loop *L) {
163c3101432SXiang1 Zhang   assert(L && "Unexcepted Loop status!");
164c3101432SXiang1 Zhang 
165c3101432SXiang1 Zhang   // Get the outermost loop.
166c3101432SXiang1 Zhang   while (Loop *Parent = L->getParentLoop())
167c3101432SXiang1 Zhang     L = Parent;
168c3101432SXiang1 Zhang 
169c3101432SXiang1 Zhang   BasicBlock *PreHeader = L->getLoopPreheader();
170c3101432SXiang1 Zhang 
171c3101432SXiang1 Zhang   // There is unique predecessor outside the loop.
172c3101432SXiang1 Zhang   if (PreHeader)
173c3101432SXiang1 Zhang     return PreHeader->getTerminator();
174c3101432SXiang1 Zhang 
175c3101432SXiang1 Zhang   BasicBlock *Header = L->getHeader();
176c3101432SXiang1 Zhang   BasicBlock *Dom = Header;
177c3101432SXiang1 Zhang   for (BasicBlock *PredBB : predecessors(Header))
178c3101432SXiang1 Zhang     Dom = DT->findNearestCommonDominator(Dom, PredBB);
179c3101432SXiang1 Zhang 
180c3101432SXiang1 Zhang   assert(Dom && "Not find dominator BB!");
181c3101432SXiang1 Zhang   Instruction *Term = Dom->getTerminator();
182c3101432SXiang1 Zhang 
183c3101432SXiang1 Zhang   return Term;
184c3101432SXiang1 Zhang }
185c3101432SXiang1 Zhang 
getDomInst(Instruction * I1,Instruction * I2)186c3101432SXiang1 Zhang Instruction *TLSVariableHoistPass::getDomInst(Instruction *I1,
187c3101432SXiang1 Zhang                                               Instruction *I2) {
188c3101432SXiang1 Zhang   if (!I1)
189c3101432SXiang1 Zhang     return I2;
190c3101432SXiang1 Zhang   if (DT->dominates(I1, I2))
191c3101432SXiang1 Zhang     return I1;
192c3101432SXiang1 Zhang   if (DT->dominates(I2, I1))
193c3101432SXiang1 Zhang     return I2;
194c3101432SXiang1 Zhang 
195c3101432SXiang1 Zhang   // If there is no dominance relation, use common dominator.
196c3101432SXiang1 Zhang   BasicBlock *DomBB =
197c3101432SXiang1 Zhang       DT->findNearestCommonDominator(I1->getParent(), I2->getParent());
198c3101432SXiang1 Zhang 
199c3101432SXiang1 Zhang   Instruction *Dom = DomBB->getTerminator();
200c3101432SXiang1 Zhang   assert(Dom && "Common dominator not found!");
201c3101432SXiang1 Zhang 
202c3101432SXiang1 Zhang   return Dom;
203c3101432SXiang1 Zhang }
204c3101432SXiang1 Zhang 
findInsertPos(Function & Fn,GlobalVariable * GV,BasicBlock * & PosBB)205c3101432SXiang1 Zhang BasicBlock::iterator TLSVariableHoistPass::findInsertPos(Function &Fn,
206c3101432SXiang1 Zhang                                                          GlobalVariable *GV,
207c3101432SXiang1 Zhang                                                          BasicBlock *&PosBB) {
208c3101432SXiang1 Zhang   tlshoist::TLSCandidate &Cand = TLSCandMap[GV];
209c3101432SXiang1 Zhang 
210c3101432SXiang1 Zhang   // We should hoist the TLS use out of loop, so choose its nearest instruction
211c3101432SXiang1 Zhang   // which dominate the loop and the outside loops (if exist).
212c3101432SXiang1 Zhang   Instruction *LastPos = nullptr;
213c3101432SXiang1 Zhang   for (auto &User : Cand.Users) {
214c3101432SXiang1 Zhang     BasicBlock *BB = User.Inst->getParent();
215c3101432SXiang1 Zhang     Instruction *Pos = User.Inst;
216c3101432SXiang1 Zhang     if (Loop *L = LI->getLoopFor(BB)) {
217c3101432SXiang1 Zhang       Pos = getNearestLoopDomInst(BB, L);
218c3101432SXiang1 Zhang       assert(Pos && "Not find insert position out of loop!");
219c3101432SXiang1 Zhang     }
220c3101432SXiang1 Zhang     Pos = getDomInst(LastPos, Pos);
221c3101432SXiang1 Zhang     LastPos = Pos;
222c3101432SXiang1 Zhang   }
223c3101432SXiang1 Zhang 
224c3101432SXiang1 Zhang   assert(LastPos && "Unexpected insert position!");
225c3101432SXiang1 Zhang   BasicBlock *Parent = LastPos->getParent();
226c3101432SXiang1 Zhang   PosBB = Parent;
227c3101432SXiang1 Zhang   return LastPos->getIterator();
228c3101432SXiang1 Zhang }
229c3101432SXiang1 Zhang 
230c3101432SXiang1 Zhang // Generate a bitcast (no type change) to replace the uses of TLS Candidate.
genBitCastInst(Function & Fn,GlobalVariable * GV)231c3101432SXiang1 Zhang Instruction *TLSVariableHoistPass::genBitCastInst(Function &Fn,
232c3101432SXiang1 Zhang                                                   GlobalVariable *GV) {
233c3101432SXiang1 Zhang   BasicBlock *PosBB = &Fn.getEntryBlock();
234c3101432SXiang1 Zhang   BasicBlock::iterator Iter = findInsertPos(Fn, GV, PosBB);
235c3101432SXiang1 Zhang   Type *Ty = GV->getType();
236c3101432SXiang1 Zhang   auto *CastInst = new BitCastInst(GV, Ty, "tls_bitcast");
237c3101432SXiang1 Zhang   PosBB->getInstList().insert(Iter, CastInst);
238c3101432SXiang1 Zhang   return CastInst;
239c3101432SXiang1 Zhang }
240c3101432SXiang1 Zhang 
tryReplaceTLSCandidate(Function & Fn,GlobalVariable * GV)241c3101432SXiang1 Zhang bool TLSVariableHoistPass::tryReplaceTLSCandidate(Function &Fn,
242c3101432SXiang1 Zhang                                                   GlobalVariable *GV) {
243c3101432SXiang1 Zhang 
244c3101432SXiang1 Zhang   tlshoist::TLSCandidate &Cand = TLSCandMap[GV];
245c3101432SXiang1 Zhang 
246c3101432SXiang1 Zhang   // If only used 1 time and not in loops, we no need to replace it.
247c3101432SXiang1 Zhang   if (oneUseOutsideLoop(Cand, LI))
248c3101432SXiang1 Zhang     return false;
249c3101432SXiang1 Zhang 
250c3101432SXiang1 Zhang   // Generate a bitcast (no type change)
251c3101432SXiang1 Zhang   auto *CastInst = genBitCastInst(Fn, GV);
252c3101432SXiang1 Zhang 
253c3101432SXiang1 Zhang   // to replace the uses of TLS Candidate
254c3101432SXiang1 Zhang   for (auto &User : Cand.Users)
255c3101432SXiang1 Zhang     User.Inst->setOperand(User.OpndIdx, CastInst);
256c3101432SXiang1 Zhang 
257c3101432SXiang1 Zhang   return true;
258c3101432SXiang1 Zhang }
259c3101432SXiang1 Zhang 
tryReplaceTLSCandidates(Function & Fn)260c3101432SXiang1 Zhang bool TLSVariableHoistPass::tryReplaceTLSCandidates(Function &Fn) {
261c3101432SXiang1 Zhang   if (TLSCandMap.empty())
262c3101432SXiang1 Zhang     return false;
263c3101432SXiang1 Zhang 
264c3101432SXiang1 Zhang   bool Replaced = false;
265c3101432SXiang1 Zhang   for (auto &GV2Cand : TLSCandMap) {
266c3101432SXiang1 Zhang     GlobalVariable *GV = GV2Cand.first;
267c3101432SXiang1 Zhang     Replaced |= tryReplaceTLSCandidate(Fn, GV);
268c3101432SXiang1 Zhang   }
269c3101432SXiang1 Zhang 
270c3101432SXiang1 Zhang   return Replaced;
271c3101432SXiang1 Zhang }
272c3101432SXiang1 Zhang 
273c3101432SXiang1 Zhang /// Optimize expensive TLS variables in the given function.
runImpl(Function & Fn,DominatorTree & DT,LoopInfo & LI)274c3101432SXiang1 Zhang bool TLSVariableHoistPass::runImpl(Function &Fn, DominatorTree &DT,
275c3101432SXiang1 Zhang                                    LoopInfo &LI) {
276c3101432SXiang1 Zhang   if (Fn.hasOptNone())
277c3101432SXiang1 Zhang     return false;
278c3101432SXiang1 Zhang 
279a56f2649SXiang1 Zhang   if (!TLSLoadHoist && !Fn.getAttributes().hasFnAttr("tls-load-hoist"))
280c3101432SXiang1 Zhang     return false;
281c3101432SXiang1 Zhang 
282c3101432SXiang1 Zhang   this->LI = &LI;
283c3101432SXiang1 Zhang   this->DT = &DT;
284c3101432SXiang1 Zhang   assert(this->LI && this->DT && "Unexcepted requirement!");
285c3101432SXiang1 Zhang 
286c3101432SXiang1 Zhang   // Collect all TLS variable candidates.
287c3101432SXiang1 Zhang   collectTLSCandidates(Fn);
288c3101432SXiang1 Zhang 
289c3101432SXiang1 Zhang   bool MadeChange = tryReplaceTLSCandidates(Fn);
290c3101432SXiang1 Zhang 
291c3101432SXiang1 Zhang   return MadeChange;
292c3101432SXiang1 Zhang }
293c3101432SXiang1 Zhang 
run(Function & F,FunctionAnalysisManager & AM)294c3101432SXiang1 Zhang PreservedAnalyses TLSVariableHoistPass::run(Function &F,
295c3101432SXiang1 Zhang                                             FunctionAnalysisManager &AM) {
296c3101432SXiang1 Zhang 
297c3101432SXiang1 Zhang   auto &LI = AM.getResult<LoopAnalysis>(F);
298c3101432SXiang1 Zhang   auto &DT = AM.getResult<DominatorTreeAnalysis>(F);
299c3101432SXiang1 Zhang 
300c3101432SXiang1 Zhang   if (!runImpl(F, DT, LI))
301c3101432SXiang1 Zhang     return PreservedAnalyses::all();
302c3101432SXiang1 Zhang 
303c3101432SXiang1 Zhang   PreservedAnalyses PA;
304c3101432SXiang1 Zhang   PA.preserveSet<CFGAnalyses>();
305c3101432SXiang1 Zhang   return PA;
306c3101432SXiang1 Zhang }
307