//==- 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