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