xref: /freebsd/contrib/llvm-project/llvm/lib/Target/SystemZ/SystemZLDCleanup.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===-- SystemZLDCleanup.cpp - Clean up local-dynamic TLS accesses --------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This pass combines multiple accesses to local-dynamic TLS variables so that
100b57cec5SDimitry Andric // the TLS base address for the module is only fetched once per execution path
110b57cec5SDimitry Andric // through the function.
120b57cec5SDimitry Andric //
130b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
140b57cec5SDimitry Andric 
150b57cec5SDimitry Andric #include "SystemZMachineFunctionInfo.h"
160b57cec5SDimitry Andric #include "SystemZTargetMachine.h"
170b57cec5SDimitry Andric #include "llvm/CodeGen/MachineDominators.h"
180b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
190b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
200b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
210b57cec5SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h"
220b57cec5SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h"
230b57cec5SDimitry Andric #include "llvm/Target/TargetMachine.h"
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric using namespace llvm;
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric namespace {
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric class SystemZLDCleanup : public MachineFunctionPass {
300b57cec5SDimitry Andric public:
310b57cec5SDimitry Andric   static char ID;
SystemZLDCleanup()3204eeddc0SDimitry Andric   SystemZLDCleanup() : MachineFunctionPass(ID), TII(nullptr), MF(nullptr) {
3304eeddc0SDimitry Andric     initializeSystemZLDCleanupPass(*PassRegistry::getPassRegistry());
340b57cec5SDimitry Andric   }
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override;
370b57cec5SDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override;
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric private:
400b57cec5SDimitry Andric   bool VisitNode(MachineDomTreeNode *Node, unsigned TLSBaseAddrReg);
410b57cec5SDimitry Andric   MachineInstr *ReplaceTLSCall(MachineInstr *I, unsigned TLSBaseAddrReg);
420b57cec5SDimitry Andric   MachineInstr *SetRegister(MachineInstr *I, unsigned *TLSBaseAddrReg);
430b57cec5SDimitry Andric 
440b57cec5SDimitry Andric   const SystemZInstrInfo *TII;
450b57cec5SDimitry Andric   MachineFunction *MF;
460b57cec5SDimitry Andric };
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric char SystemZLDCleanup::ID = 0;
490b57cec5SDimitry Andric 
500b57cec5SDimitry Andric } // end anonymous namespace
510b57cec5SDimitry Andric 
5204eeddc0SDimitry Andric INITIALIZE_PASS(SystemZLDCleanup, "systemz-ld-cleanup",
5304eeddc0SDimitry Andric                 "SystemZ Local Dynamic TLS Access Clean-up", false, false)
5404eeddc0SDimitry Andric 
createSystemZLDCleanupPass(SystemZTargetMachine & TM)550b57cec5SDimitry Andric FunctionPass *llvm::createSystemZLDCleanupPass(SystemZTargetMachine &TM) {
5604eeddc0SDimitry Andric   return new SystemZLDCleanup();
570b57cec5SDimitry Andric }
580b57cec5SDimitry Andric 
getAnalysisUsage(AnalysisUsage & AU) const590b57cec5SDimitry Andric void SystemZLDCleanup::getAnalysisUsage(AnalysisUsage &AU) const {
600b57cec5SDimitry Andric   AU.setPreservesCFG();
61*0fca6ea1SDimitry Andric   AU.addRequired<MachineDominatorTreeWrapperPass>();
620b57cec5SDimitry Andric   MachineFunctionPass::getAnalysisUsage(AU);
630b57cec5SDimitry Andric }
640b57cec5SDimitry Andric 
runOnMachineFunction(MachineFunction & F)650b57cec5SDimitry Andric bool SystemZLDCleanup::runOnMachineFunction(MachineFunction &F) {
660b57cec5SDimitry Andric   if (skipFunction(F.getFunction()))
670b57cec5SDimitry Andric     return false;
680b57cec5SDimitry Andric 
6981ad6265SDimitry Andric   TII = F.getSubtarget<SystemZSubtarget>().getInstrInfo();
700b57cec5SDimitry Andric   MF = &F;
710b57cec5SDimitry Andric 
720b57cec5SDimitry Andric   SystemZMachineFunctionInfo* MFI = F.getInfo<SystemZMachineFunctionInfo>();
730b57cec5SDimitry Andric   if (MFI->getNumLocalDynamicTLSAccesses() < 2) {
740b57cec5SDimitry Andric     // No point folding accesses if there isn't at least two.
750b57cec5SDimitry Andric     return false;
760b57cec5SDimitry Andric   }
770b57cec5SDimitry Andric 
78*0fca6ea1SDimitry Andric   MachineDominatorTree *DT =
79*0fca6ea1SDimitry Andric       &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
800b57cec5SDimitry Andric   return VisitNode(DT->getRootNode(), 0);
810b57cec5SDimitry Andric }
820b57cec5SDimitry Andric 
830b57cec5SDimitry Andric // Visit the dominator subtree rooted at Node in pre-order.
840b57cec5SDimitry Andric // If TLSBaseAddrReg is non-null, then use that to replace any
850b57cec5SDimitry Andric // TLS_LDCALL instructions. Otherwise, create the register
860b57cec5SDimitry Andric // when the first such instruction is seen, and then use it
870b57cec5SDimitry Andric // as we encounter more instructions.
VisitNode(MachineDomTreeNode * Node,unsigned TLSBaseAddrReg)880b57cec5SDimitry Andric bool SystemZLDCleanup::VisitNode(MachineDomTreeNode *Node,
890b57cec5SDimitry Andric                                  unsigned TLSBaseAddrReg) {
900b57cec5SDimitry Andric   MachineBasicBlock *BB = Node->getBlock();
910b57cec5SDimitry Andric   bool Changed = false;
920b57cec5SDimitry Andric 
930b57cec5SDimitry Andric   // Traverse the current block.
940b57cec5SDimitry Andric   for (auto I = BB->begin(), E = BB->end(); I != E; ++I) {
950b57cec5SDimitry Andric     switch (I->getOpcode()) {
960b57cec5SDimitry Andric       case SystemZ::TLS_LDCALL:
970b57cec5SDimitry Andric         if (TLSBaseAddrReg)
980b57cec5SDimitry Andric           I = ReplaceTLSCall(&*I, TLSBaseAddrReg);
990b57cec5SDimitry Andric         else
1000b57cec5SDimitry Andric           I = SetRegister(&*I, &TLSBaseAddrReg);
1010b57cec5SDimitry Andric         Changed = true;
1020b57cec5SDimitry Andric         break;
1030b57cec5SDimitry Andric       default:
1040b57cec5SDimitry Andric         break;
1050b57cec5SDimitry Andric     }
1060b57cec5SDimitry Andric   }
1070b57cec5SDimitry Andric 
1080b57cec5SDimitry Andric   // Visit the children of this block in the dominator tree.
109bdd1243dSDimitry Andric   for (auto &N : *Node)
110bdd1243dSDimitry Andric     Changed |= VisitNode(N, TLSBaseAddrReg);
1110b57cec5SDimitry Andric 
1120b57cec5SDimitry Andric   return Changed;
1130b57cec5SDimitry Andric }
1140b57cec5SDimitry Andric 
1150b57cec5SDimitry Andric // Replace the TLS_LDCALL instruction I with a copy from TLSBaseAddrReg,
1160b57cec5SDimitry Andric // returning the new instruction.
ReplaceTLSCall(MachineInstr * I,unsigned TLSBaseAddrReg)1170b57cec5SDimitry Andric MachineInstr *SystemZLDCleanup::ReplaceTLSCall(MachineInstr *I,
1180b57cec5SDimitry Andric                                                unsigned TLSBaseAddrReg) {
1190b57cec5SDimitry Andric   // Insert a Copy from TLSBaseAddrReg to R2.
1200b57cec5SDimitry Andric   MachineInstr *Copy = BuildMI(*I->getParent(), I, I->getDebugLoc(),
1210b57cec5SDimitry Andric                                TII->get(TargetOpcode::COPY), SystemZ::R2D)
1220b57cec5SDimitry Andric                                .addReg(TLSBaseAddrReg);
1230b57cec5SDimitry Andric 
1240b57cec5SDimitry Andric   // Erase the TLS_LDCALL instruction.
1250b57cec5SDimitry Andric   I->eraseFromParent();
1260b57cec5SDimitry Andric 
1270b57cec5SDimitry Andric   return Copy;
1280b57cec5SDimitry Andric }
1290b57cec5SDimitry Andric 
1300b57cec5SDimitry Andric // Create a virtual register in *TLSBaseAddrReg, and populate it by
1310b57cec5SDimitry Andric // inserting a copy instruction after I. Returns the new instruction.
SetRegister(MachineInstr * I,unsigned * TLSBaseAddrReg)1320b57cec5SDimitry Andric MachineInstr *SystemZLDCleanup::SetRegister(MachineInstr *I,
1330b57cec5SDimitry Andric                                             unsigned *TLSBaseAddrReg) {
1340b57cec5SDimitry Andric   // Create a virtual register for the TLS base address.
1350b57cec5SDimitry Andric   MachineRegisterInfo &RegInfo = MF->getRegInfo();
1360b57cec5SDimitry Andric   *TLSBaseAddrReg = RegInfo.createVirtualRegister(&SystemZ::GR64BitRegClass);
1370b57cec5SDimitry Andric 
1380b57cec5SDimitry Andric   // Insert a copy from R2 to TLSBaseAddrReg.
1390b57cec5SDimitry Andric   MachineInstr *Next = I->getNextNode();
1400b57cec5SDimitry Andric   MachineInstr *Copy = BuildMI(*I->getParent(), Next, I->getDebugLoc(),
1410b57cec5SDimitry Andric                                TII->get(TargetOpcode::COPY), *TLSBaseAddrReg)
1420b57cec5SDimitry Andric                                .addReg(SystemZ::R2D);
1430b57cec5SDimitry Andric 
1440b57cec5SDimitry Andric   return Copy;
1450b57cec5SDimitry Andric }
1460b57cec5SDimitry Andric 
147