1*81ad6265SDimitry Andric //==- TLSVariableHoist.h ------ Remove Redundant TLS Loads -------*- C++ -*-==//
2*81ad6265SDimitry Andric //
3*81ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*81ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*81ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*81ad6265SDimitry Andric //
7*81ad6265SDimitry Andric //===----------------------------------------------------------------------===//
8*81ad6265SDimitry Andric //
9*81ad6265SDimitry Andric // This pass identifies/eliminates Redundant TLS Loads if related option is set.
10*81ad6265SDimitry Andric // For example:
11*81ad6265SDimitry Andric // static __thread int x;
12*81ad6265SDimitry Andric // int g();
13*81ad6265SDimitry Andric // int f(int c) {
14*81ad6265SDimitry Andric //   int *px = &x;
15*81ad6265SDimitry Andric //   while (c--)
16*81ad6265SDimitry Andric //     *px += g();
17*81ad6265SDimitry Andric //   return *px;
18*81ad6265SDimitry Andric // }
19*81ad6265SDimitry Andric //
20*81ad6265SDimitry Andric // will generate Redundant TLS Loads by compiling it with
21*81ad6265SDimitry Andric // clang++ -fPIC -ftls-model=global-dynamic -O2 -S
22*81ad6265SDimitry Andric //
23*81ad6265SDimitry Andric // .LBB0_2:                                # %while.body
24*81ad6265SDimitry Andric //                                         # =>This Inner Loop Header: Depth=1
25*81ad6265SDimitry Andric //         callq   _Z1gv@PLT
26*81ad6265SDimitry Andric //         movl    %eax, %ebp
27*81ad6265SDimitry Andric //         leaq    _ZL1x@TLSLD(%rip), %rdi
28*81ad6265SDimitry Andric //         callq   __tls_get_addr@PLT
29*81ad6265SDimitry Andric //         addl    _ZL1x@DTPOFF(%rax), %ebp
30*81ad6265SDimitry Andric //         movl    %ebp, _ZL1x@DTPOFF(%rax)
31*81ad6265SDimitry Andric //         addl    $-1, %ebx
32*81ad6265SDimitry Andric //         jne     .LBB0_2
33*81ad6265SDimitry Andric //         jmp     .LBB0_3
34*81ad6265SDimitry Andric // .LBB0_4:                                # %entry.while.end_crit_edge
35*81ad6265SDimitry Andric //         leaq    _ZL1x@TLSLD(%rip), %rdi
36*81ad6265SDimitry Andric //         callq   __tls_get_addr@PLT
37*81ad6265SDimitry Andric //         movl    _ZL1x@DTPOFF(%rax), %ebp
38*81ad6265SDimitry Andric //
39*81ad6265SDimitry Andric // The Redundant TLS Loads will hurt the performance, especially in loops.
40*81ad6265SDimitry Andric // So we try to eliminate/move them if required by customers, let it be:
41*81ad6265SDimitry Andric //
42*81ad6265SDimitry Andric // # %bb.0:                                # %entry
43*81ad6265SDimitry Andric //         ...
44*81ad6265SDimitry Andric //         movl    %edi, %ebx
45*81ad6265SDimitry Andric //         leaq    _ZL1x@TLSLD(%rip), %rdi
46*81ad6265SDimitry Andric //         callq   __tls_get_addr@PLT
47*81ad6265SDimitry Andric //         leaq    _ZL1x@DTPOFF(%rax), %r14
48*81ad6265SDimitry Andric //         testl   %ebx, %ebx
49*81ad6265SDimitry Andric //         je      .LBB0_1
50*81ad6265SDimitry Andric // .LBB0_2:                                # %while.body
51*81ad6265SDimitry Andric //                                         # =>This Inner Loop Header: Depth=1
52*81ad6265SDimitry Andric //         callq   _Z1gv@PLT
53*81ad6265SDimitry Andric //         addl    (%r14), %eax
54*81ad6265SDimitry Andric //         movl    %eax, (%r14)
55*81ad6265SDimitry Andric //         addl    $-1, %ebx
56*81ad6265SDimitry Andric //         jne     .LBB0_2
57*81ad6265SDimitry Andric //         jmp     .LBB0_3
58*81ad6265SDimitry Andric //
59*81ad6265SDimitry Andric //===----------------------------------------------------------------------===//
60*81ad6265SDimitry Andric 
61*81ad6265SDimitry Andric #ifndef LLVM_TRANSFORMS_SCALAR_TLSVARIABLEHOIST_H
62*81ad6265SDimitry Andric #define LLVM_TRANSFORMS_SCALAR_TLSVARIABLEHOIST_H
63*81ad6265SDimitry Andric 
64*81ad6265SDimitry Andric #include "llvm/ADT/MapVector.h"
65*81ad6265SDimitry Andric #include "llvm/ADT/SmallVector.h"
66*81ad6265SDimitry Andric #include "llvm/Analysis/LoopInfo.h"
67*81ad6265SDimitry Andric #include "llvm/IR/PassManager.h"
68*81ad6265SDimitry Andric 
69*81ad6265SDimitry Andric namespace llvm {
70*81ad6265SDimitry Andric 
71*81ad6265SDimitry Andric class BasicBlock;
72*81ad6265SDimitry Andric class DominatorTree;
73*81ad6265SDimitry Andric class Function;
74*81ad6265SDimitry Andric class GlobalVariable;
75*81ad6265SDimitry Andric class Instruction;
76*81ad6265SDimitry Andric 
77*81ad6265SDimitry Andric /// A private "module" namespace for types and utilities used by
78*81ad6265SDimitry Andric /// TLSVariableHoist. These are implementation details and should
79*81ad6265SDimitry Andric /// not be used by clients.
80*81ad6265SDimitry Andric namespace tlshoist {
81*81ad6265SDimitry Andric 
82*81ad6265SDimitry Andric /// Keeps track of the user of a TLS variable and the operand index
83*81ad6265SDimitry Andric /// where the variable is used.
84*81ad6265SDimitry Andric struct TLSUser {
85*81ad6265SDimitry Andric   Instruction *Inst;
86*81ad6265SDimitry Andric   unsigned OpndIdx;
87*81ad6265SDimitry Andric 
TLSUserTLSUser88*81ad6265SDimitry Andric   TLSUser(Instruction *Inst, unsigned Idx) : Inst(Inst), OpndIdx(Idx) {}
89*81ad6265SDimitry Andric };
90*81ad6265SDimitry Andric 
91*81ad6265SDimitry Andric /// Keeps track of a TLS variable candidate and its users.
92*81ad6265SDimitry Andric struct TLSCandidate {
93*81ad6265SDimitry Andric   SmallVector<TLSUser, 8> Users;
94*81ad6265SDimitry Andric 
95*81ad6265SDimitry Andric   /// Add the user to the use list and update the cost.
addUserTLSCandidate96*81ad6265SDimitry Andric   void addUser(Instruction *Inst, unsigned Idx) {
97*81ad6265SDimitry Andric     Users.push_back(TLSUser(Inst, Idx));
98*81ad6265SDimitry Andric   }
99*81ad6265SDimitry Andric };
100*81ad6265SDimitry Andric 
101*81ad6265SDimitry Andric } // end namespace tlshoist
102*81ad6265SDimitry Andric 
103*81ad6265SDimitry Andric class TLSVariableHoistPass : public PassInfoMixin<TLSVariableHoistPass> {
104*81ad6265SDimitry Andric public:
105*81ad6265SDimitry Andric   PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
106*81ad6265SDimitry Andric 
107*81ad6265SDimitry Andric   // Glue for old PM.
108*81ad6265SDimitry Andric   bool runImpl(Function &F, DominatorTree &DT, LoopInfo &LI);
109*81ad6265SDimitry Andric 
110*81ad6265SDimitry Andric private:
111*81ad6265SDimitry Andric   DominatorTree *DT;
112*81ad6265SDimitry Andric   LoopInfo *LI;
113*81ad6265SDimitry Andric 
114*81ad6265SDimitry Andric   /// Keeps track of TLS variable candidates found in the function.
115*81ad6265SDimitry Andric   using TLSCandMapType = MapVector<GlobalVariable *, tlshoist::TLSCandidate>;
116*81ad6265SDimitry Andric   TLSCandMapType TLSCandMap;
117*81ad6265SDimitry Andric 
118*81ad6265SDimitry Andric   void collectTLSCandidates(Function &Fn);
119*81ad6265SDimitry Andric   void collectTLSCandidate(Instruction *Inst);
120*81ad6265SDimitry Andric   Instruction *getNearestLoopDomInst(BasicBlock *BB, Loop *L);
121*81ad6265SDimitry Andric   Instruction *getDomInst(Instruction *I1, Instruction *I2);
122*81ad6265SDimitry Andric   BasicBlock::iterator findInsertPos(Function &Fn, GlobalVariable *GV,
123*81ad6265SDimitry Andric                                      BasicBlock *&PosBB);
124*81ad6265SDimitry Andric   Instruction *genBitCastInst(Function &Fn, GlobalVariable *GV);
125*81ad6265SDimitry Andric   bool tryReplaceTLSCandidates(Function &Fn);
126*81ad6265SDimitry Andric   bool tryReplaceTLSCandidate(Function &Fn, GlobalVariable *GV);
127*81ad6265SDimitry Andric };
128*81ad6265SDimitry Andric 
129*81ad6265SDimitry Andric } // end namespace llvm
130*81ad6265SDimitry Andric 
131*81ad6265SDimitry Andric #endif // LLVM_TRANSFORMS_SCALAR_TLSVARIABLEHOIST_H
132