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