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