xref: /src/contrib/llvm-project/llvm/lib/CodeGen/StackMapLivenessAnalysis.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
15ca98fd9SDimitry Andric //===-- StackMapLivenessAnalysis.cpp - StackMap live Out Analysis ----------===//
25ca98fd9SDimitry Andric //
3e6d15924SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e6d15924SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e6d15924SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65ca98fd9SDimitry Andric //
75ca98fd9SDimitry Andric //===----------------------------------------------------------------------===//
85ca98fd9SDimitry Andric //
95ca98fd9SDimitry Andric // This file implements the StackMap Liveness analysis pass. The pass calculates
105ca98fd9SDimitry Andric // the liveness for each basic block in a function and attaches the register
115ca98fd9SDimitry Andric // live-out information to a stackmap or patchpoint intrinsic if present.
125ca98fd9SDimitry Andric //
135ca98fd9SDimitry Andric //===----------------------------------------------------------------------===//
145ca98fd9SDimitry Andric 
155ca98fd9SDimitry Andric #include "llvm/ADT/Statistic.h"
165a5ac124SDimitry Andric #include "llvm/CodeGen/LivePhysRegs.h"
175ca98fd9SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h"
185ca98fd9SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
195a5ac124SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
20044eb2f6SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h"
21706b4fc4SDimitry Andric #include "llvm/InitializePasses.h"
22145449b1SDimitry Andric #include "llvm/Pass.h"
235ca98fd9SDimitry Andric #include "llvm/Support/CommandLine.h"
245ca98fd9SDimitry Andric #include "llvm/Support/Debug.h"
255a5ac124SDimitry Andric #include "llvm/Support/raw_ostream.h"
265ca98fd9SDimitry Andric 
275ca98fd9SDimitry Andric using namespace llvm;
285ca98fd9SDimitry Andric 
295ca98fd9SDimitry Andric #define DEBUG_TYPE "stackmaps"
305ca98fd9SDimitry Andric 
315a5ac124SDimitry Andric static cl::opt<bool> EnablePatchPointLiveness(
325a5ac124SDimitry Andric     "enable-patchpoint-liveness", cl::Hidden, cl::init(true),
335ca98fd9SDimitry Andric     cl::desc("Enable PatchPoint Liveness Analysis Pass"));
345ca98fd9SDimitry Andric 
355ca98fd9SDimitry Andric STATISTIC(NumStackMapFuncVisited, "Number of functions visited");
365ca98fd9SDimitry Andric STATISTIC(NumStackMapFuncSkipped, "Number of functions skipped");
375ca98fd9SDimitry Andric STATISTIC(NumBBsVisited,          "Number of basic blocks visited");
385ca98fd9SDimitry Andric STATISTIC(NumBBsHaveNoStackmap,   "Number of basic blocks with no stackmap");
395ca98fd9SDimitry Andric STATISTIC(NumStackMaps,           "Number of StackMaps visited");
405ca98fd9SDimitry Andric 
415a5ac124SDimitry Andric namespace {
42eb11fae6SDimitry Andric /// This pass calculates the liveness information for each basic block in
435a5ac124SDimitry Andric /// a function and attaches the register live-out information to a patchpoint
445a5ac124SDimitry Andric /// intrinsic if present.
455a5ac124SDimitry Andric ///
465a5ac124SDimitry Andric /// This pass can be disabled via the -enable-patchpoint-liveness=false flag.
475a5ac124SDimitry Andric /// The pass skips functions that don't have any patchpoint intrinsics. The
485a5ac124SDimitry Andric /// information provided by this pass is optional and not required by the
495a5ac124SDimitry Andric /// aformentioned intrinsic to function.
505a5ac124SDimitry Andric class StackMapLiveness : public MachineFunctionPass {
517fa27ce4SDimitry Andric   const TargetRegisterInfo *TRI = nullptr;
525a5ac124SDimitry Andric   LivePhysRegs LiveRegs;
535a5ac124SDimitry Andric 
545a5ac124SDimitry Andric public:
555a5ac124SDimitry Andric   static char ID;
565a5ac124SDimitry Andric 
57eb11fae6SDimitry Andric   /// Default construct and initialize the pass.
585a5ac124SDimitry Andric   StackMapLiveness();
595a5ac124SDimitry Andric 
60eb11fae6SDimitry Andric   /// Tell the pass manager which passes we depend on and what
615a5ac124SDimitry Andric   /// information we preserve.
625a5ac124SDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override;
635a5ac124SDimitry Andric 
getRequiredProperties() const6401095a5dSDimitry Andric   MachineFunctionProperties getRequiredProperties() const override {
6501095a5dSDimitry Andric     return MachineFunctionProperties().set(
66b915e9e0SDimitry Andric         MachineFunctionProperties::Property::NoVRegs);
6701095a5dSDimitry Andric   }
6801095a5dSDimitry Andric 
69eb11fae6SDimitry Andric   /// Calculate the liveness information for the given machine function.
705a5ac124SDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override;
715a5ac124SDimitry Andric 
725a5ac124SDimitry Andric private:
73eb11fae6SDimitry Andric   /// Performs the actual liveness calculation for the function.
74ee8648bdSDimitry Andric   bool calculateLiveness(MachineFunction &MF);
755a5ac124SDimitry Andric 
76eb11fae6SDimitry Andric   /// Add the current register live set to the instruction.
77ee8648bdSDimitry Andric   void addLiveOutSetToMI(MachineFunction &MF, MachineInstr &MI);
785a5ac124SDimitry Andric 
79eb11fae6SDimitry Andric   /// Create a register mask and initialize it with the registers from
805a5ac124SDimitry Andric   /// the register live set.
81ee8648bdSDimitry Andric   uint32_t *createRegisterMask(MachineFunction &MF) const;
825a5ac124SDimitry Andric };
835a5ac124SDimitry Andric } // namespace
845a5ac124SDimitry Andric 
855ca98fd9SDimitry Andric char StackMapLiveness::ID = 0;
865ca98fd9SDimitry Andric char &llvm::StackMapLivenessID = StackMapLiveness::ID;
875ca98fd9SDimitry Andric INITIALIZE_PASS(StackMapLiveness, "stackmap-liveness",
885ca98fd9SDimitry Andric                 "StackMap Liveness Analysis", false, false)
895ca98fd9SDimitry Andric 
905ca98fd9SDimitry Andric /// Default construct and initialize the pass.
StackMapLiveness()915ca98fd9SDimitry Andric StackMapLiveness::StackMapLiveness() : MachineFunctionPass(ID) {
925ca98fd9SDimitry Andric   initializeStackMapLivenessPass(*PassRegistry::getPassRegistry());
935ca98fd9SDimitry Andric }
945ca98fd9SDimitry Andric 
955ca98fd9SDimitry Andric /// Tell the pass manager which passes we depend on and what information we
965ca98fd9SDimitry Andric /// preserve.
getAnalysisUsage(AnalysisUsage & AU) const975ca98fd9SDimitry Andric void StackMapLiveness::getAnalysisUsage(AnalysisUsage &AU) const {
985ca98fd9SDimitry Andric   // We preserve all information.
995ca98fd9SDimitry Andric   AU.setPreservesAll();
1005ca98fd9SDimitry Andric   AU.setPreservesCFG();
101ee8648bdSDimitry Andric   MachineFunctionPass::getAnalysisUsage(AU);
1025ca98fd9SDimitry Andric }
1035ca98fd9SDimitry Andric 
1045ca98fd9SDimitry Andric /// Calculate the liveness information for the given machine function.
runOnMachineFunction(MachineFunction & MF)1055a5ac124SDimitry Andric bool StackMapLiveness::runOnMachineFunction(MachineFunction &MF) {
1065ca98fd9SDimitry Andric   if (!EnablePatchPointLiveness)
1075ca98fd9SDimitry Andric     return false;
1085ca98fd9SDimitry Andric 
109eb11fae6SDimitry Andric   LLVM_DEBUG(dbgs() << "********** COMPUTING STACKMAP LIVENESS: "
110eb11fae6SDimitry Andric                     << MF.getName() << " **********\n");
1115a5ac124SDimitry Andric   TRI = MF.getSubtarget().getRegisterInfo();
1125ca98fd9SDimitry Andric   ++NumStackMapFuncVisited;
1135ca98fd9SDimitry Andric 
1145ca98fd9SDimitry Andric   // Skip this function if there are no patchpoints to process.
115b915e9e0SDimitry Andric   if (!MF.getFrameInfo().hasPatchPoint()) {
1165ca98fd9SDimitry Andric     ++NumStackMapFuncSkipped;
1175ca98fd9SDimitry Andric     return false;
1185ca98fd9SDimitry Andric   }
119ee8648bdSDimitry Andric   return calculateLiveness(MF);
1205ca98fd9SDimitry Andric }
1215ca98fd9SDimitry Andric 
1225ca98fd9SDimitry Andric /// Performs the actual liveness calculation for the function.
calculateLiveness(MachineFunction & MF)123ee8648bdSDimitry Andric bool StackMapLiveness::calculateLiveness(MachineFunction &MF) {
1245ca98fd9SDimitry Andric   bool HasChanged = false;
1255ca98fd9SDimitry Andric   // For all basic blocks in the function.
126ee8648bdSDimitry Andric   for (auto &MBB : MF) {
127eb11fae6SDimitry Andric     LLVM_DEBUG(dbgs() << "****** BB " << MBB.getName() << " ******\n");
128b915e9e0SDimitry Andric     LiveRegs.init(*TRI);
129ac9a064cSDimitry Andric     LiveRegs.addLiveOuts(MBB);
1305ca98fd9SDimitry Andric     bool HasStackMap = false;
1315ca98fd9SDimitry Andric     // Reverse iterate over all instructions and add the current live register
1325ca98fd9SDimitry Andric     // set to an instruction if we encounter a patchpoint instruction.
13377fc4c14SDimitry Andric     for (MachineInstr &MI : llvm::reverse(MBB)) {
13477fc4c14SDimitry Andric       if (MI.getOpcode() == TargetOpcode::PATCHPOINT) {
13577fc4c14SDimitry Andric         addLiveOutSetToMI(MF, MI);
1365ca98fd9SDimitry Andric         HasChanged = true;
1375ca98fd9SDimitry Andric         HasStackMap = true;
1385ca98fd9SDimitry Andric         ++NumStackMaps;
1395ca98fd9SDimitry Andric       }
14077fc4c14SDimitry Andric       LLVM_DEBUG(dbgs() << "   " << LiveRegs << "   " << MI);
14177fc4c14SDimitry Andric       LiveRegs.stepBackward(MI);
1425ca98fd9SDimitry Andric     }
1435ca98fd9SDimitry Andric     ++NumBBsVisited;
1445ca98fd9SDimitry Andric     if (!HasStackMap)
1455ca98fd9SDimitry Andric       ++NumBBsHaveNoStackmap;
1465ca98fd9SDimitry Andric   }
1475ca98fd9SDimitry Andric   return HasChanged;
1485ca98fd9SDimitry Andric }
1495ca98fd9SDimitry Andric 
1505ca98fd9SDimitry Andric /// Add the current register live set to the instruction.
addLiveOutSetToMI(MachineFunction & MF,MachineInstr & MI)151ee8648bdSDimitry Andric void StackMapLiveness::addLiveOutSetToMI(MachineFunction &MF,
152ee8648bdSDimitry Andric                                          MachineInstr &MI) {
153ee8648bdSDimitry Andric   uint32_t *Mask = createRegisterMask(MF);
1545ca98fd9SDimitry Andric   MachineOperand MO = MachineOperand::CreateRegLiveOut(Mask);
155ee8648bdSDimitry Andric   MI.addOperand(MF, MO);
1565ca98fd9SDimitry Andric }
1575ca98fd9SDimitry Andric 
1585ca98fd9SDimitry Andric /// Create a register mask and initialize it with the registers from the
1595ca98fd9SDimitry Andric /// register live set.
createRegisterMask(MachineFunction & MF) const160ee8648bdSDimitry Andric uint32_t *StackMapLiveness::createRegisterMask(MachineFunction &MF) const {
1615ca98fd9SDimitry Andric   // The mask is owned and cleaned up by the Machine Function.
162eb11fae6SDimitry Andric   uint32_t *Mask = MF.allocateRegMask();
163ee8648bdSDimitry Andric   for (auto Reg : LiveRegs)
164ee8648bdSDimitry Andric     Mask[Reg / 32] |= 1U << (Reg % 32);
16567c32a98SDimitry Andric 
166ee8648bdSDimitry Andric   // Give the target a chance to adjust the mask.
16767c32a98SDimitry Andric   TRI->adjustStackMapLiveOutMask(Mask);
168ee8648bdSDimitry Andric 
1695ca98fd9SDimitry Andric   return Mask;
1705ca98fd9SDimitry Andric }
171