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