181ad6265SDimitry Andric //===- TLSVariableHoist.cpp -------- Remove Redundant TLS Loads ---------===//
281ad6265SDimitry Andric //
381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
681ad6265SDimitry Andric //
781ad6265SDimitry Andric //===----------------------------------------------------------------------===//
881ad6265SDimitry Andric //
981ad6265SDimitry Andric // This pass identifies/eliminate Redundant TLS Loads if related option is set.
1081ad6265SDimitry Andric // The example: Please refer to the comment at the head of TLSVariableHoist.h.
1181ad6265SDimitry Andric //
1281ad6265SDimitry Andric //===----------------------------------------------------------------------===//
1381ad6265SDimitry Andric
1481ad6265SDimitry Andric #include "llvm/ADT/SmallVector.h"
1581ad6265SDimitry Andric #include "llvm/IR/BasicBlock.h"
1681ad6265SDimitry Andric #include "llvm/IR/Dominators.h"
1781ad6265SDimitry Andric #include "llvm/IR/Function.h"
1881ad6265SDimitry Andric #include "llvm/IR/InstrTypes.h"
1981ad6265SDimitry Andric #include "llvm/IR/Instruction.h"
2081ad6265SDimitry Andric #include "llvm/IR/Instructions.h"
2181ad6265SDimitry Andric #include "llvm/IR/IntrinsicInst.h"
2281ad6265SDimitry Andric #include "llvm/IR/Module.h"
2381ad6265SDimitry Andric #include "llvm/IR/Value.h"
2481ad6265SDimitry Andric #include "llvm/InitializePasses.h"
2581ad6265SDimitry Andric #include "llvm/Pass.h"
2681ad6265SDimitry Andric #include "llvm/Support/Casting.h"
2781ad6265SDimitry Andric #include "llvm/Support/Debug.h"
2881ad6265SDimitry Andric #include "llvm/Support/raw_ostream.h"
2981ad6265SDimitry Andric #include "llvm/Transforms/Scalar.h"
3081ad6265SDimitry Andric #include "llvm/Transforms/Scalar/TLSVariableHoist.h"
3181ad6265SDimitry Andric #include <algorithm>
3281ad6265SDimitry Andric #include <cassert>
3381ad6265SDimitry Andric #include <cstdint>
3481ad6265SDimitry Andric #include <iterator>
3581ad6265SDimitry Andric #include <utility>
3681ad6265SDimitry Andric
3781ad6265SDimitry Andric using namespace llvm;
3881ad6265SDimitry Andric using namespace tlshoist;
3981ad6265SDimitry Andric
4081ad6265SDimitry Andric #define DEBUG_TYPE "tlshoist"
4181ad6265SDimitry Andric
4281ad6265SDimitry Andric static cl::opt<bool> TLSLoadHoist(
4381ad6265SDimitry Andric "tls-load-hoist", cl::init(false), cl::Hidden,
4481ad6265SDimitry Andric cl::desc("hoist the TLS loads in PIC model to eliminate redundant "
4581ad6265SDimitry Andric "TLS address calculation."));
4681ad6265SDimitry Andric
4781ad6265SDimitry Andric namespace {
4881ad6265SDimitry Andric
4981ad6265SDimitry Andric /// The TLS Variable hoist pass.
5081ad6265SDimitry Andric class TLSVariableHoistLegacyPass : public FunctionPass {
5181ad6265SDimitry Andric public:
5281ad6265SDimitry Andric static char ID; // Pass identification, replacement for typeid
5381ad6265SDimitry Andric
TLSVariableHoistLegacyPass()5481ad6265SDimitry Andric TLSVariableHoistLegacyPass() : FunctionPass(ID) {
5581ad6265SDimitry Andric initializeTLSVariableHoistLegacyPassPass(*PassRegistry::getPassRegistry());
5681ad6265SDimitry Andric }
5781ad6265SDimitry Andric
5881ad6265SDimitry Andric bool runOnFunction(Function &Fn) override;
5981ad6265SDimitry Andric
getPassName() const6081ad6265SDimitry Andric StringRef getPassName() const override { return "TLS Variable Hoist"; }
6181ad6265SDimitry Andric
getAnalysisUsage(AnalysisUsage & AU) const6281ad6265SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override {
6381ad6265SDimitry Andric AU.setPreservesCFG();
6481ad6265SDimitry Andric AU.addRequired<DominatorTreeWrapperPass>();
6581ad6265SDimitry Andric AU.addRequired<LoopInfoWrapperPass>();
6681ad6265SDimitry Andric }
6781ad6265SDimitry Andric
6881ad6265SDimitry Andric private:
6981ad6265SDimitry Andric TLSVariableHoistPass Impl;
7081ad6265SDimitry Andric };
7181ad6265SDimitry Andric
7281ad6265SDimitry Andric } // end anonymous namespace
7381ad6265SDimitry Andric
7481ad6265SDimitry Andric char TLSVariableHoistLegacyPass::ID = 0;
7581ad6265SDimitry Andric
7681ad6265SDimitry Andric INITIALIZE_PASS_BEGIN(TLSVariableHoistLegacyPass, "tlshoist",
7781ad6265SDimitry Andric "TLS Variable Hoist", false, false)
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)7881ad6265SDimitry Andric INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
7981ad6265SDimitry Andric INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass)
8081ad6265SDimitry Andric INITIALIZE_PASS_END(TLSVariableHoistLegacyPass, "tlshoist",
8181ad6265SDimitry Andric "TLS Variable Hoist", false, false)
8281ad6265SDimitry Andric
8381ad6265SDimitry Andric FunctionPass *llvm::createTLSVariableHoistPass() {
8481ad6265SDimitry Andric return new TLSVariableHoistLegacyPass();
8581ad6265SDimitry Andric }
8681ad6265SDimitry Andric
8781ad6265SDimitry Andric /// Perform the TLS Variable Hoist optimization for the given function.
runOnFunction(Function & Fn)8881ad6265SDimitry Andric bool TLSVariableHoistLegacyPass::runOnFunction(Function &Fn) {
8981ad6265SDimitry Andric if (skipFunction(Fn))
9081ad6265SDimitry Andric return false;
9181ad6265SDimitry Andric
9281ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "********** Begin TLS Variable Hoist **********\n");
9381ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "********** Function: " << Fn.getName() << '\n');
9481ad6265SDimitry Andric
9581ad6265SDimitry Andric bool MadeChange =
9681ad6265SDimitry Andric Impl.runImpl(Fn, getAnalysis<DominatorTreeWrapperPass>().getDomTree(),
9781ad6265SDimitry Andric getAnalysis<LoopInfoWrapperPass>().getLoopInfo());
9881ad6265SDimitry Andric
9981ad6265SDimitry Andric if (MadeChange) {
10081ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "********** Function after TLS Variable Hoist: "
10181ad6265SDimitry Andric << Fn.getName() << '\n');
10281ad6265SDimitry Andric LLVM_DEBUG(dbgs() << Fn);
10381ad6265SDimitry Andric }
10481ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "********** End TLS Variable Hoist **********\n");
10581ad6265SDimitry Andric
10681ad6265SDimitry Andric return MadeChange;
10781ad6265SDimitry Andric }
10881ad6265SDimitry Andric
collectTLSCandidate(Instruction * Inst)10981ad6265SDimitry Andric void TLSVariableHoistPass::collectTLSCandidate(Instruction *Inst) {
11081ad6265SDimitry Andric // Skip all cast instructions. They are visited indirectly later on.
11181ad6265SDimitry Andric if (Inst->isCast())
11281ad6265SDimitry Andric return;
11381ad6265SDimitry Andric
11481ad6265SDimitry Andric // Scan all operands.
11581ad6265SDimitry Andric for (unsigned Idx = 0, E = Inst->getNumOperands(); Idx != E; ++Idx) {
11681ad6265SDimitry Andric auto *GV = dyn_cast<GlobalVariable>(Inst->getOperand(Idx));
11781ad6265SDimitry Andric if (!GV || !GV->isThreadLocal())
11881ad6265SDimitry Andric continue;
11981ad6265SDimitry Andric
12081ad6265SDimitry Andric // Add Candidate to TLSCandMap (GV --> Candidate).
12181ad6265SDimitry Andric TLSCandMap[GV].addUser(Inst, Idx);
12281ad6265SDimitry Andric }
12381ad6265SDimitry Andric }
12481ad6265SDimitry Andric
collectTLSCandidates(Function & Fn)12581ad6265SDimitry Andric void TLSVariableHoistPass::collectTLSCandidates(Function &Fn) {
12681ad6265SDimitry Andric // First, quickly check if there is TLS Variable.
12781ad6265SDimitry Andric Module *M = Fn.getParent();
12881ad6265SDimitry Andric
12981ad6265SDimitry Andric bool HasTLS = llvm::any_of(
13081ad6265SDimitry Andric M->globals(), [](GlobalVariable &GV) { return GV.isThreadLocal(); });
13181ad6265SDimitry Andric
13281ad6265SDimitry Andric // If non, directly return.
13381ad6265SDimitry Andric if (!HasTLS)
13481ad6265SDimitry Andric return;
13581ad6265SDimitry Andric
13681ad6265SDimitry Andric TLSCandMap.clear();
13781ad6265SDimitry Andric
13881ad6265SDimitry Andric // Then, collect TLS Variable info.
13981ad6265SDimitry Andric for (BasicBlock &BB : Fn) {
14081ad6265SDimitry Andric // Ignore unreachable basic blocks.
14181ad6265SDimitry Andric if (!DT->isReachableFromEntry(&BB))
14281ad6265SDimitry Andric continue;
14381ad6265SDimitry Andric
14481ad6265SDimitry Andric for (Instruction &Inst : BB)
14581ad6265SDimitry Andric collectTLSCandidate(&Inst);
14681ad6265SDimitry Andric }
14781ad6265SDimitry Andric }
14881ad6265SDimitry Andric
oneUseOutsideLoop(tlshoist::TLSCandidate & Cand,LoopInfo * LI)14981ad6265SDimitry Andric static bool oneUseOutsideLoop(tlshoist::TLSCandidate &Cand, LoopInfo *LI) {
15081ad6265SDimitry Andric if (Cand.Users.size() != 1)
15181ad6265SDimitry Andric return false;
15281ad6265SDimitry Andric
15381ad6265SDimitry Andric BasicBlock *BB = Cand.Users[0].Inst->getParent();
15481ad6265SDimitry Andric if (LI->getLoopFor(BB))
15581ad6265SDimitry Andric return false;
15681ad6265SDimitry Andric
15781ad6265SDimitry Andric return true;
15881ad6265SDimitry Andric }
15981ad6265SDimitry Andric
getNearestLoopDomInst(BasicBlock * BB,Loop * L)16081ad6265SDimitry Andric Instruction *TLSVariableHoistPass::getNearestLoopDomInst(BasicBlock *BB,
16181ad6265SDimitry Andric Loop *L) {
16281ad6265SDimitry Andric assert(L && "Unexcepted Loop status!");
16381ad6265SDimitry Andric
16481ad6265SDimitry Andric // Get the outermost loop.
16581ad6265SDimitry Andric while (Loop *Parent = L->getParentLoop())
16681ad6265SDimitry Andric L = Parent;
16781ad6265SDimitry Andric
16881ad6265SDimitry Andric BasicBlock *PreHeader = L->getLoopPreheader();
16981ad6265SDimitry Andric
17081ad6265SDimitry Andric // There is unique predecessor outside the loop.
17181ad6265SDimitry Andric if (PreHeader)
17281ad6265SDimitry Andric return PreHeader->getTerminator();
17381ad6265SDimitry Andric
17481ad6265SDimitry Andric BasicBlock *Header = L->getHeader();
17581ad6265SDimitry Andric BasicBlock *Dom = Header;
17681ad6265SDimitry Andric for (BasicBlock *PredBB : predecessors(Header))
17781ad6265SDimitry Andric Dom = DT->findNearestCommonDominator(Dom, PredBB);
17881ad6265SDimitry Andric
17981ad6265SDimitry Andric assert(Dom && "Not find dominator BB!");
18081ad6265SDimitry Andric Instruction *Term = Dom->getTerminator();
18181ad6265SDimitry Andric
18281ad6265SDimitry Andric return Term;
18381ad6265SDimitry Andric }
18481ad6265SDimitry Andric
getDomInst(Instruction * I1,Instruction * I2)18581ad6265SDimitry Andric Instruction *TLSVariableHoistPass::getDomInst(Instruction *I1,
18681ad6265SDimitry Andric Instruction *I2) {
18781ad6265SDimitry Andric if (!I1)
18881ad6265SDimitry Andric return I2;
189*bdd1243dSDimitry Andric return DT->findNearestCommonDominator(I1, I2);
19081ad6265SDimitry Andric }
19181ad6265SDimitry Andric
findInsertPos(Function & Fn,GlobalVariable * GV,BasicBlock * & PosBB)19281ad6265SDimitry Andric BasicBlock::iterator TLSVariableHoistPass::findInsertPos(Function &Fn,
19381ad6265SDimitry Andric GlobalVariable *GV,
19481ad6265SDimitry Andric BasicBlock *&PosBB) {
19581ad6265SDimitry Andric tlshoist::TLSCandidate &Cand = TLSCandMap[GV];
19681ad6265SDimitry Andric
19781ad6265SDimitry Andric // We should hoist the TLS use out of loop, so choose its nearest instruction
19881ad6265SDimitry Andric // which dominate the loop and the outside loops (if exist).
19981ad6265SDimitry Andric Instruction *LastPos = nullptr;
20081ad6265SDimitry Andric for (auto &User : Cand.Users) {
20181ad6265SDimitry Andric BasicBlock *BB = User.Inst->getParent();
20281ad6265SDimitry Andric Instruction *Pos = User.Inst;
20381ad6265SDimitry Andric if (Loop *L = LI->getLoopFor(BB)) {
20481ad6265SDimitry Andric Pos = getNearestLoopDomInst(BB, L);
20581ad6265SDimitry Andric assert(Pos && "Not find insert position out of loop!");
20681ad6265SDimitry Andric }
20781ad6265SDimitry Andric Pos = getDomInst(LastPos, Pos);
20881ad6265SDimitry Andric LastPos = Pos;
20981ad6265SDimitry Andric }
21081ad6265SDimitry Andric
21181ad6265SDimitry Andric assert(LastPos && "Unexpected insert position!");
21281ad6265SDimitry Andric BasicBlock *Parent = LastPos->getParent();
21381ad6265SDimitry Andric PosBB = Parent;
21481ad6265SDimitry Andric return LastPos->getIterator();
21581ad6265SDimitry Andric }
21681ad6265SDimitry Andric
21781ad6265SDimitry Andric // Generate a bitcast (no type change) to replace the uses of TLS Candidate.
genBitCastInst(Function & Fn,GlobalVariable * GV)21881ad6265SDimitry Andric Instruction *TLSVariableHoistPass::genBitCastInst(Function &Fn,
21981ad6265SDimitry Andric GlobalVariable *GV) {
22081ad6265SDimitry Andric BasicBlock *PosBB = &Fn.getEntryBlock();
22181ad6265SDimitry Andric BasicBlock::iterator Iter = findInsertPos(Fn, GV, PosBB);
22281ad6265SDimitry Andric Type *Ty = GV->getType();
22381ad6265SDimitry Andric auto *CastInst = new BitCastInst(GV, Ty, "tls_bitcast");
224*bdd1243dSDimitry Andric CastInst->insertInto(PosBB, Iter);
22581ad6265SDimitry Andric return CastInst;
22681ad6265SDimitry Andric }
22781ad6265SDimitry Andric
tryReplaceTLSCandidate(Function & Fn,GlobalVariable * GV)22881ad6265SDimitry Andric bool TLSVariableHoistPass::tryReplaceTLSCandidate(Function &Fn,
22981ad6265SDimitry Andric GlobalVariable *GV) {
23081ad6265SDimitry Andric
23181ad6265SDimitry Andric tlshoist::TLSCandidate &Cand = TLSCandMap[GV];
23281ad6265SDimitry Andric
23381ad6265SDimitry Andric // If only used 1 time and not in loops, we no need to replace it.
23481ad6265SDimitry Andric if (oneUseOutsideLoop(Cand, LI))
23581ad6265SDimitry Andric return false;
23681ad6265SDimitry Andric
23781ad6265SDimitry Andric // Generate a bitcast (no type change)
23881ad6265SDimitry Andric auto *CastInst = genBitCastInst(Fn, GV);
23981ad6265SDimitry Andric
24081ad6265SDimitry Andric // to replace the uses of TLS Candidate
24181ad6265SDimitry Andric for (auto &User : Cand.Users)
24281ad6265SDimitry Andric User.Inst->setOperand(User.OpndIdx, CastInst);
24381ad6265SDimitry Andric
24481ad6265SDimitry Andric return true;
24581ad6265SDimitry Andric }
24681ad6265SDimitry Andric
tryReplaceTLSCandidates(Function & Fn)24781ad6265SDimitry Andric bool TLSVariableHoistPass::tryReplaceTLSCandidates(Function &Fn) {
24881ad6265SDimitry Andric if (TLSCandMap.empty())
24981ad6265SDimitry Andric return false;
25081ad6265SDimitry Andric
25181ad6265SDimitry Andric bool Replaced = false;
25281ad6265SDimitry Andric for (auto &GV2Cand : TLSCandMap) {
25381ad6265SDimitry Andric GlobalVariable *GV = GV2Cand.first;
25481ad6265SDimitry Andric Replaced |= tryReplaceTLSCandidate(Fn, GV);
25581ad6265SDimitry Andric }
25681ad6265SDimitry Andric
25781ad6265SDimitry Andric return Replaced;
25881ad6265SDimitry Andric }
25981ad6265SDimitry Andric
26081ad6265SDimitry Andric /// Optimize expensive TLS variables in the given function.
runImpl(Function & Fn,DominatorTree & DT,LoopInfo & LI)26181ad6265SDimitry Andric bool TLSVariableHoistPass::runImpl(Function &Fn, DominatorTree &DT,
26281ad6265SDimitry Andric LoopInfo &LI) {
26381ad6265SDimitry Andric if (Fn.hasOptNone())
26481ad6265SDimitry Andric return false;
26581ad6265SDimitry Andric
26681ad6265SDimitry Andric if (!TLSLoadHoist && !Fn.getAttributes().hasFnAttr("tls-load-hoist"))
26781ad6265SDimitry Andric return false;
26881ad6265SDimitry Andric
26981ad6265SDimitry Andric this->LI = &LI;
27081ad6265SDimitry Andric this->DT = &DT;
27181ad6265SDimitry Andric assert(this->LI && this->DT && "Unexcepted requirement!");
27281ad6265SDimitry Andric
27381ad6265SDimitry Andric // Collect all TLS variable candidates.
27481ad6265SDimitry Andric collectTLSCandidates(Fn);
27581ad6265SDimitry Andric
27681ad6265SDimitry Andric bool MadeChange = tryReplaceTLSCandidates(Fn);
27781ad6265SDimitry Andric
27881ad6265SDimitry Andric return MadeChange;
27981ad6265SDimitry Andric }
28081ad6265SDimitry Andric
run(Function & F,FunctionAnalysisManager & AM)28181ad6265SDimitry Andric PreservedAnalyses TLSVariableHoistPass::run(Function &F,
28281ad6265SDimitry Andric FunctionAnalysisManager &AM) {
28381ad6265SDimitry Andric
28481ad6265SDimitry Andric auto &LI = AM.getResult<LoopAnalysis>(F);
28581ad6265SDimitry Andric auto &DT = AM.getResult<DominatorTreeAnalysis>(F);
28681ad6265SDimitry Andric
28781ad6265SDimitry Andric if (!runImpl(F, DT, LI))
28881ad6265SDimitry Andric return PreservedAnalyses::all();
28981ad6265SDimitry Andric
29081ad6265SDimitry Andric PreservedAnalyses PA;
29181ad6265SDimitry Andric PA.preserveSet<CFGAnalyses>();
29281ad6265SDimitry Andric return PA;
29381ad6265SDimitry Andric }
294