//===- X86CleanupLocalDynamicTLS.cpp - Cleanup local dynamic TLS access ---===// // // 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 combines multiple accesses to local-dynamic TLS variables so that // the TLS base address for the module is only fetched once per execution path // through the function. // //===----------------------------------------------------------------------===// #include "X86.h" #include "X86InstrInfo.h" #include "X86MachineFunctionInfo.h" #include "X86Subtarget.h" #include "llvm/CodeGen/MachineDominators.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/InitializePasses.h" using namespace llvm; #define DEBUG_TYPE "x86-cleanup-local-dynamic-tls" namespace { class X86CleanupLocalDynamicTLSLegacy : public MachineFunctionPass { public: static char ID; X86CleanupLocalDynamicTLSLegacy() : MachineFunctionPass(ID) {} StringRef getPassName() const override { return "Local Dynamic TLS Access Clean-up"; } bool runOnMachineFunction(MachineFunction &MF) override; void getAnalysisUsage(AnalysisUsage &AU) const override { AU.setPreservesCFG(); AU.addRequired(); MachineFunctionPass::getAnalysisUsage(AU); } }; } // end anonymous namespace char X86CleanupLocalDynamicTLSLegacy::ID = 0; FunctionPass *llvm::createCleanupLocalDynamicTLSLegacyPass() { return new X86CleanupLocalDynamicTLSLegacy(); } // Replace the TLS_base_addr instruction I with a copy from // TLSBaseAddrReg, returning the new instruction. static MachineInstr *ReplaceTLSBaseAddrCall(MachineInstr &I, Register TLSBaseAddrReg) { MachineFunction *MF = I.getParent()->getParent(); const X86Subtarget &STI = MF->getSubtarget(); const bool is64Bit = STI.is64Bit(); const X86InstrInfo *TII = STI.getInstrInfo(); // Insert a Copy from TLSBaseAddrReg to RAX/EAX. MachineInstr *Copy = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII->get(TargetOpcode::COPY), is64Bit ? X86::RAX : X86::EAX) .addReg(TLSBaseAddrReg); // Erase the TLS_base_addr instruction. I.eraseFromParent(); return Copy; } // Create a virtual register in *TLSBaseAddrReg, and populate it by // inserting a copy instruction after I. Returns the new instruction. static MachineInstr *SetRegister(MachineInstr &I, Register *TLSBaseAddrReg) { MachineFunction *MF = I.getParent()->getParent(); const X86Subtarget &STI = MF->getSubtarget(); const bool is64Bit = STI.is64Bit(); const X86InstrInfo *TII = STI.getInstrInfo(); // Create a virtual register for the TLS base address. MachineRegisterInfo &RegInfo = MF->getRegInfo(); *TLSBaseAddrReg = RegInfo.createVirtualRegister(is64Bit ? &X86::GR64RegClass : &X86::GR32RegClass); // Insert a copy from RAX/EAX to TLSBaseAddrReg. MachineInstr *Next = I.getNextNode(); MachineInstr *Copy = BuildMI(*I.getParent(), Next, I.getDebugLoc(), TII->get(TargetOpcode::COPY), *TLSBaseAddrReg) .addReg(is64Bit ? X86::RAX : X86::EAX); return Copy; } // Visit the dominator subtree rooted at Node in pre-order. // If TLSBaseAddrReg is non-null, then use that to replace any // TLS_base_addr instructions. Otherwise, create the register // when the first such instruction is seen, and then use it // as we encounter more instructions. static bool VisitNode(MachineDomTreeNode *Node, Register TLSBaseAddrReg) { MachineBasicBlock *BB = Node->getBlock(); bool Changed = false; // Traverse the current block. for (MachineBasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) { switch (I->getOpcode()) { case X86::TLS_base_addr32: case X86::TLS_base_addr64: if (TLSBaseAddrReg) I = ReplaceTLSBaseAddrCall(*I, TLSBaseAddrReg); else I = SetRegister(*I, &TLSBaseAddrReg); Changed = true; break; default: break; } } // Visit the children of this block in the dominator tree. for (MachineDomTreeNode *I : Node->children()) Changed |= VisitNode(I, TLSBaseAddrReg); return Changed; } static bool cleanupLocalDynamicTLS(MachineDominatorTree &DT) { return VisitNode(DT.getRootNode(), Register()); } static bool shouldSkipLocalDynamicTLS(MachineFunction &MF) { X86MachineFunctionInfo *MFI = MF.getInfo(); if (MFI->getNumLocalDynamicTLSAccesses() < 2) { // No point folding accesses if there isn't at least two. return true; } return false; } bool X86CleanupLocalDynamicTLSLegacy::runOnMachineFunction( MachineFunction &MF) { if (skipFunction(MF.getFunction()) || shouldSkipLocalDynamicTLS(MF)) return false; MachineDominatorTree &DT = getAnalysis().getDomTree(); return cleanupLocalDynamicTLS(DT); } PreservedAnalyses X86CleanupLocalDynamicTLSPass::run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM) { if (shouldSkipLocalDynamicTLS(MF)) return PreservedAnalyses::all(); MachineDominatorTree &DT = MFAM.getResult(MF); return cleanupLocalDynamicTLS(DT) ? getMachineFunctionPassPreservedAnalyses() .preserveSet() : PreservedAnalyses::all(); }