aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/llvm16/include/llvm/Transforms/Scalar/TLSVariableHoist.h
blob: 51c2995f6451f9abab828b5da8d6f05c1922d8a7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#pragma once

#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif

//==- TLSVariableHoist.h ------ Remove Redundant TLS Loads -------*- C++ -*-==//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This pass identifies/eliminates Redundant TLS Loads if related option is set.
// For example:
// static __thread int x;
// int g();
// int f(int c) {
//   int *px = &x;
//   while (c--)
//     *px += g();
//   return *px;
// }
//
// will generate Redundant TLS Loads by compiling it with
// clang++ -fPIC -ftls-model=global-dynamic -O2 -S
//
// .LBB0_2:                                # %while.body
//                                         # =>This Inner Loop Header: Depth=1
//         callq   _Z1gv@PLT
//         movl    %eax, %ebp
//         leaq    _ZL1x@TLSLD(%rip), %rdi
//         callq   __tls_get_addr@PLT
//         addl    _ZL1x@DTPOFF(%rax), %ebp
//         movl    %ebp, _ZL1x@DTPOFF(%rax)
//         addl    $-1, %ebx
//         jne     .LBB0_2
//         jmp     .LBB0_3
// .LBB0_4:                                # %entry.while.end_crit_edge
//         leaq    _ZL1x@TLSLD(%rip), %rdi
//         callq   __tls_get_addr@PLT
//         movl    _ZL1x@DTPOFF(%rax), %ebp
//
// The Redundant TLS Loads will hurt the performance, especially in loops.
// So we try to eliminate/move them if required by customers, let it be:
//
// # %bb.0:                                # %entry
//         ...
//         movl    %edi, %ebx
//         leaq    _ZL1x@TLSLD(%rip), %rdi
//         callq   __tls_get_addr@PLT
//         leaq    _ZL1x@DTPOFF(%rax), %r14
//         testl   %ebx, %ebx
//         je      .LBB0_1
// .LBB0_2:                                # %while.body
//                                         # =>This Inner Loop Header: Depth=1
//         callq   _Z1gv@PLT
//         addl    (%r14), %eax
//         movl    %eax, (%r14)
//         addl    $-1, %ebx
//         jne     .LBB0_2
//         jmp     .LBB0_3
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_TRANSFORMS_SCALAR_TLSVARIABLEHOIST_H
#define LLVM_TRANSFORMS_SCALAR_TLSVARIABLEHOIST_H

#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/IR/PassManager.h"

namespace llvm {

class BasicBlock;
class DominatorTree;
class Function;
class GlobalVariable;
class Instruction;

/// A private "module" namespace for types and utilities used by
/// TLSVariableHoist. These are implementation details and should
/// not be used by clients.
namespace tlshoist {

/// Keeps track of the user of a TLS variable and the operand index
/// where the variable is used.
struct TLSUser {
  Instruction *Inst;
  unsigned OpndIdx;

  TLSUser(Instruction *Inst, unsigned Idx) : Inst(Inst), OpndIdx(Idx) {}
};

/// Keeps track of a TLS variable candidate and its users.
struct TLSCandidate {
  SmallVector<TLSUser, 8> Users;

  /// Add the user to the use list and update the cost.
  void addUser(Instruction *Inst, unsigned Idx) {
    Users.push_back(TLSUser(Inst, Idx));
  }
};

} // end namespace tlshoist

class TLSVariableHoistPass : public PassInfoMixin<TLSVariableHoistPass> {
public:
  PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);

  // Glue for old PM.
  bool runImpl(Function &F, DominatorTree &DT, LoopInfo &LI);

private:
  DominatorTree *DT;
  LoopInfo *LI;

  /// Keeps track of TLS variable candidates found in the function.
  using TLSCandMapType = MapVector<GlobalVariable *, tlshoist::TLSCandidate>;
  TLSCandMapType TLSCandMap;

  void collectTLSCandidates(Function &Fn);
  void collectTLSCandidate(Instruction *Inst);
  Instruction *getNearestLoopDomInst(BasicBlock *BB, Loop *L);
  Instruction *getDomInst(Instruction *I1, Instruction *I2);
  BasicBlock::iterator findInsertPos(Function &Fn, GlobalVariable *GV,
                                     BasicBlock *&PosBB);
  Instruction *genBitCastInst(Function &Fn, GlobalVariable *GV);
  bool tryReplaceTLSCandidates(Function &Fn);
  bool tryReplaceTLSCandidate(Function &Fn, GlobalVariable *GV);
};

} // end namespace llvm

#endif // LLVM_TRANSFORMS_SCALAR_TLSVARIABLEHOIST_H

#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif