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