Path: blob/main/contrib/llvm-project/llvm/lib/Target/AArch64/AArch64CleanupLocalDynamicTLSPass.cpp
35269 views
//===-- AArch64CleanupLocalDynamicTLSPass.cpp ---------------------*- C++ -*-=//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// Local-dynamic access to thread-local variables proceeds in three stages.9//10// 1. The offset of this Module's thread-local area from TPIDR_EL0 is calculated11// in much the same way as a general-dynamic TLS-descriptor access against12// the special symbol _TLS_MODULE_BASE.13// 2. The variable's offset from _TLS_MODULE_BASE_ is calculated using14// instructions with "dtprel" modifiers.15// 3. These two are added, together with TPIDR_EL0, to obtain the variable's16// true address.17//18// This is only better than general-dynamic access to the variable if two or19// more of the first stage TLS-descriptor calculations can be combined. This20// pass looks through a function and performs such combinations.21//22//===----------------------------------------------------------------------===//23#include "AArch64.h"24#include "AArch64InstrInfo.h"25#include "AArch64MachineFunctionInfo.h"26#include "llvm/CodeGen/MachineDominators.h"27#include "llvm/CodeGen/MachineFunction.h"28#include "llvm/CodeGen/MachineFunctionPass.h"29#include "llvm/CodeGen/MachineInstrBuilder.h"30#include "llvm/CodeGen/MachineRegisterInfo.h"31using namespace llvm;3233#define TLSCLEANUP_PASS_NAME "AArch64 Local Dynamic TLS Access Clean-up"3435namespace {36struct LDTLSCleanup : public MachineFunctionPass {37static char ID;38LDTLSCleanup() : MachineFunctionPass(ID) {39initializeLDTLSCleanupPass(*PassRegistry::getPassRegistry());40}4142bool runOnMachineFunction(MachineFunction &MF) override {43if (skipFunction(MF.getFunction()))44return false;4546AArch64FunctionInfo *AFI = MF.getInfo<AArch64FunctionInfo>();47if (AFI->getNumLocalDynamicTLSAccesses() < 2) {48// No point folding accesses if there isn't at least two.49return false;50}5152MachineDominatorTree *DT =53&getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();54return VisitNode(DT->getRootNode(), 0);55}5657// Visit the dominator subtree rooted at Node in pre-order.58// If TLSBaseAddrReg is non-null, then use that to replace any59// TLS_base_addr instructions. Otherwise, create the register60// when the first such instruction is seen, and then use it61// as we encounter more instructions.62bool VisitNode(MachineDomTreeNode *Node, unsigned TLSBaseAddrReg) {63MachineBasicBlock *BB = Node->getBlock();64bool Changed = false;6566// Traverse the current block.67for (MachineBasicBlock::iterator I = BB->begin(), E = BB->end(); I != E;68++I) {69switch (I->getOpcode()) {70case AArch64::TLSDESC_CALLSEQ:71// Make sure it's a local dynamic access.72if (!I->getOperand(0).isSymbol() ||73strcmp(I->getOperand(0).getSymbolName(), "_TLS_MODULE_BASE_"))74break;7576if (TLSBaseAddrReg)77I = replaceTLSBaseAddrCall(*I, TLSBaseAddrReg);78else79I = setRegister(*I, &TLSBaseAddrReg);80Changed = true;81break;82default:83break;84}85}8687// Visit the children of this block in the dominator tree.88for (MachineDomTreeNode *N : *Node) {89Changed |= VisitNode(N, TLSBaseAddrReg);90}9192return Changed;93}9495// Replace the TLS_base_addr instruction I with a copy from96// TLSBaseAddrReg, returning the new instruction.97MachineInstr *replaceTLSBaseAddrCall(MachineInstr &I,98unsigned TLSBaseAddrReg) {99MachineFunction *MF = I.getParent()->getParent();100const TargetInstrInfo *TII = MF->getSubtarget().getInstrInfo();101102// Insert a Copy from TLSBaseAddrReg to x0, which is where the rest of the103// code sequence assumes the address will be.104MachineInstr *Copy = BuildMI(*I.getParent(), I, I.getDebugLoc(),105TII->get(TargetOpcode::COPY), AArch64::X0)106.addReg(TLSBaseAddrReg);107108// Update the call site info.109if (I.shouldUpdateCallSiteInfo())110I.getMF()->eraseCallSiteInfo(&I);111112// Erase the TLS_base_addr instruction.113I.eraseFromParent();114115return Copy;116}117118// Create a virtual register in *TLSBaseAddrReg, and populate it by119// inserting a copy instruction after I. Returns the new instruction.120MachineInstr *setRegister(MachineInstr &I, unsigned *TLSBaseAddrReg) {121MachineFunction *MF = I.getParent()->getParent();122const TargetInstrInfo *TII = MF->getSubtarget().getInstrInfo();123124// Create a virtual register for the TLS base address.125MachineRegisterInfo &RegInfo = MF->getRegInfo();126*TLSBaseAddrReg = RegInfo.createVirtualRegister(&AArch64::GPR64RegClass);127128// Insert a copy from X0 to TLSBaseAddrReg for later.129MachineInstr *Copy =130BuildMI(*I.getParent(), ++I.getIterator(), I.getDebugLoc(),131TII->get(TargetOpcode::COPY), *TLSBaseAddrReg)132.addReg(AArch64::X0);133134return Copy;135}136137StringRef getPassName() const override { return TLSCLEANUP_PASS_NAME; }138139void getAnalysisUsage(AnalysisUsage &AU) const override {140AU.setPreservesCFG();141AU.addRequired<MachineDominatorTreeWrapperPass>();142MachineFunctionPass::getAnalysisUsage(AU);143}144};145}146147INITIALIZE_PASS(LDTLSCleanup, "aarch64-local-dynamic-tls-cleanup",148TLSCLEANUP_PASS_NAME, false, false)149150char LDTLSCleanup::ID = 0;151FunctionPass *llvm::createAArch64CleanupLocalDynamicTLSPass() {152return new LDTLSCleanup();153}154155156