blob: 2a1b02b40eebff7ed08910eab27570639908b42a [file] [log] [blame]
//==- 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