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
69namespace llvm {
70
71class BasicBlock;
72class DominatorTree;
73class Function;
74class GlobalVariable;
75class 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.
80namespace tlshoist {
81
82/// Keeps track of the user of a TLS variable and the operand index
83/// where the variable is used.
84struct 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.
92struct 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
103class TLSVariableHoistPass : public PassInfoMixin<TLSVariableHoistPass> {
104public:
105  PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
106
107  // Glue for old PM.
108  bool runImpl(Function &F, DominatorTree &DT, LoopInfo &LI);
109
110private:
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