10b57cec5SDimitry Andric //===-- StackMapLivenessAnalysis.cpp - StackMap live Out Analysis ----------===// 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 file implements the StackMap Liveness analysis pass. The pass calculates 100b57cec5SDimitry Andric // the liveness for each basic block in a function and attaches the register 110b57cec5SDimitry Andric // live-out information to a stackmap or patchpoint intrinsic if present. 120b57cec5SDimitry Andric // 130b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 140b57cec5SDimitry Andric 150b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h" 160b57cec5SDimitry Andric #include "llvm/CodeGen/LivePhysRegs.h" 170b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h" 180b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 190b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 200b57cec5SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h" 21480093f4SDimitry Andric #include "llvm/InitializePasses.h" 2281ad6265SDimitry Andric #include "llvm/Pass.h" 230b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h" 240b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 250b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 260b57cec5SDimitry Andric 270b57cec5SDimitry Andric using namespace llvm; 280b57cec5SDimitry Andric 290b57cec5SDimitry Andric #define DEBUG_TYPE "stackmaps" 300b57cec5SDimitry Andric 310b57cec5SDimitry Andric static cl::opt<bool> EnablePatchPointLiveness( 320b57cec5SDimitry Andric "enable-patchpoint-liveness", cl::Hidden, cl::init(true), 330b57cec5SDimitry Andric cl::desc("Enable PatchPoint Liveness Analysis Pass")); 340b57cec5SDimitry Andric 350b57cec5SDimitry Andric STATISTIC(NumStackMapFuncVisited, "Number of functions visited"); 360b57cec5SDimitry Andric STATISTIC(NumStackMapFuncSkipped, "Number of functions skipped"); 370b57cec5SDimitry Andric STATISTIC(NumBBsVisited, "Number of basic blocks visited"); 380b57cec5SDimitry Andric STATISTIC(NumBBsHaveNoStackmap, "Number of basic blocks with no stackmap"); 390b57cec5SDimitry Andric STATISTIC(NumStackMaps, "Number of StackMaps visited"); 400b57cec5SDimitry Andric 410b57cec5SDimitry Andric namespace { 420b57cec5SDimitry Andric /// This pass calculates the liveness information for each basic block in 430b57cec5SDimitry Andric /// a function and attaches the register live-out information to a patchpoint 440b57cec5SDimitry Andric /// intrinsic if present. 450b57cec5SDimitry Andric /// 460b57cec5SDimitry Andric /// This pass can be disabled via the -enable-patchpoint-liveness=false flag. 470b57cec5SDimitry Andric /// The pass skips functions that don't have any patchpoint intrinsics. The 480b57cec5SDimitry Andric /// information provided by this pass is optional and not required by the 490b57cec5SDimitry Andric /// aformentioned intrinsic to function. 500b57cec5SDimitry Andric class StackMapLiveness : public MachineFunctionPass { 5106c3fb27SDimitry Andric const TargetRegisterInfo *TRI = nullptr; 520b57cec5SDimitry Andric LivePhysRegs LiveRegs; 530b57cec5SDimitry Andric 540b57cec5SDimitry Andric public: 550b57cec5SDimitry Andric static char ID; 560b57cec5SDimitry Andric 570b57cec5SDimitry Andric /// Default construct and initialize the pass. 580b57cec5SDimitry Andric StackMapLiveness(); 590b57cec5SDimitry Andric 600b57cec5SDimitry Andric /// Tell the pass manager which passes we depend on and what 610b57cec5SDimitry Andric /// information we preserve. 620b57cec5SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override; 630b57cec5SDimitry Andric 640b57cec5SDimitry Andric MachineFunctionProperties getRequiredProperties() const override { 650b57cec5SDimitry Andric return MachineFunctionProperties().set( 660b57cec5SDimitry Andric MachineFunctionProperties::Property::NoVRegs); 670b57cec5SDimitry Andric } 680b57cec5SDimitry Andric 690b57cec5SDimitry Andric /// Calculate the liveness information for the given machine function. 700b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 710b57cec5SDimitry Andric 720b57cec5SDimitry Andric private: 730b57cec5SDimitry Andric /// Performs the actual liveness calculation for the function. 740b57cec5SDimitry Andric bool calculateLiveness(MachineFunction &MF); 750b57cec5SDimitry Andric 760b57cec5SDimitry Andric /// Add the current register live set to the instruction. 770b57cec5SDimitry Andric void addLiveOutSetToMI(MachineFunction &MF, MachineInstr &MI); 780b57cec5SDimitry Andric 790b57cec5SDimitry Andric /// Create a register mask and initialize it with the registers from 800b57cec5SDimitry Andric /// the register live set. 810b57cec5SDimitry Andric uint32_t *createRegisterMask(MachineFunction &MF) const; 820b57cec5SDimitry Andric }; 830b57cec5SDimitry Andric } // namespace 840b57cec5SDimitry Andric 850b57cec5SDimitry Andric char StackMapLiveness::ID = 0; 860b57cec5SDimitry Andric char &llvm::StackMapLivenessID = StackMapLiveness::ID; 870b57cec5SDimitry Andric INITIALIZE_PASS(StackMapLiveness, "stackmap-liveness", 880b57cec5SDimitry Andric "StackMap Liveness Analysis", false, false) 890b57cec5SDimitry Andric 900b57cec5SDimitry Andric /// Default construct and initialize the pass. 910b57cec5SDimitry Andric StackMapLiveness::StackMapLiveness() : MachineFunctionPass(ID) { 920b57cec5SDimitry Andric initializeStackMapLivenessPass(*PassRegistry::getPassRegistry()); 930b57cec5SDimitry Andric } 940b57cec5SDimitry Andric 950b57cec5SDimitry Andric /// Tell the pass manager which passes we depend on and what information we 960b57cec5SDimitry Andric /// preserve. 970b57cec5SDimitry Andric void StackMapLiveness::getAnalysisUsage(AnalysisUsage &AU) const { 980b57cec5SDimitry Andric // We preserve all information. 990b57cec5SDimitry Andric AU.setPreservesAll(); 1000b57cec5SDimitry Andric AU.setPreservesCFG(); 1010b57cec5SDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 1020b57cec5SDimitry Andric } 1030b57cec5SDimitry Andric 1040b57cec5SDimitry Andric /// Calculate the liveness information for the given machine function. 1050b57cec5SDimitry Andric bool StackMapLiveness::runOnMachineFunction(MachineFunction &MF) { 1060b57cec5SDimitry Andric if (!EnablePatchPointLiveness) 1070b57cec5SDimitry Andric return false; 1080b57cec5SDimitry Andric 1090b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "********** COMPUTING STACKMAP LIVENESS: " 1100b57cec5SDimitry Andric << MF.getName() << " **********\n"); 1110b57cec5SDimitry Andric TRI = MF.getSubtarget().getRegisterInfo(); 1120b57cec5SDimitry Andric ++NumStackMapFuncVisited; 1130b57cec5SDimitry Andric 1140b57cec5SDimitry Andric // Skip this function if there are no patchpoints to process. 1150b57cec5SDimitry Andric if (!MF.getFrameInfo().hasPatchPoint()) { 1160b57cec5SDimitry Andric ++NumStackMapFuncSkipped; 1170b57cec5SDimitry Andric return false; 1180b57cec5SDimitry Andric } 1190b57cec5SDimitry Andric return calculateLiveness(MF); 1200b57cec5SDimitry Andric } 1210b57cec5SDimitry Andric 1220b57cec5SDimitry Andric /// Performs the actual liveness calculation for the function. 1230b57cec5SDimitry Andric bool StackMapLiveness::calculateLiveness(MachineFunction &MF) { 1240b57cec5SDimitry Andric bool HasChanged = false; 1250b57cec5SDimitry Andric // For all basic blocks in the function. 1260b57cec5SDimitry Andric for (auto &MBB : MF) { 1270b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "****** BB " << MBB.getName() << " ******\n"); 1280b57cec5SDimitry Andric LiveRegs.init(*TRI); 129*0fca6ea1SDimitry Andric LiveRegs.addLiveOuts(MBB); 1300b57cec5SDimitry Andric bool HasStackMap = false; 1310b57cec5SDimitry Andric // Reverse iterate over all instructions and add the current live register 1320b57cec5SDimitry Andric // set to an instruction if we encounter a patchpoint instruction. 1330eae32dcSDimitry Andric for (MachineInstr &MI : llvm::reverse(MBB)) { 1340eae32dcSDimitry Andric if (MI.getOpcode() == TargetOpcode::PATCHPOINT) { 1350eae32dcSDimitry Andric addLiveOutSetToMI(MF, MI); 1360b57cec5SDimitry Andric HasChanged = true; 1370b57cec5SDimitry Andric HasStackMap = true; 1380b57cec5SDimitry Andric ++NumStackMaps; 1390b57cec5SDimitry Andric } 1400eae32dcSDimitry Andric LLVM_DEBUG(dbgs() << " " << LiveRegs << " " << MI); 1410eae32dcSDimitry Andric LiveRegs.stepBackward(MI); 1420b57cec5SDimitry Andric } 1430b57cec5SDimitry Andric ++NumBBsVisited; 1440b57cec5SDimitry Andric if (!HasStackMap) 1450b57cec5SDimitry Andric ++NumBBsHaveNoStackmap; 1460b57cec5SDimitry Andric } 1470b57cec5SDimitry Andric return HasChanged; 1480b57cec5SDimitry Andric } 1490b57cec5SDimitry Andric 1500b57cec5SDimitry Andric /// Add the current register live set to the instruction. 1510b57cec5SDimitry Andric void StackMapLiveness::addLiveOutSetToMI(MachineFunction &MF, 1520b57cec5SDimitry Andric MachineInstr &MI) { 1530b57cec5SDimitry Andric uint32_t *Mask = createRegisterMask(MF); 1540b57cec5SDimitry Andric MachineOperand MO = MachineOperand::CreateRegLiveOut(Mask); 1550b57cec5SDimitry Andric MI.addOperand(MF, MO); 1560b57cec5SDimitry Andric } 1570b57cec5SDimitry Andric 1580b57cec5SDimitry Andric /// Create a register mask and initialize it with the registers from the 1590b57cec5SDimitry Andric /// register live set. 1600b57cec5SDimitry Andric uint32_t *StackMapLiveness::createRegisterMask(MachineFunction &MF) const { 1610b57cec5SDimitry Andric // The mask is owned and cleaned up by the Machine Function. 1620b57cec5SDimitry Andric uint32_t *Mask = MF.allocateRegMask(); 1630b57cec5SDimitry Andric for (auto Reg : LiveRegs) 1640b57cec5SDimitry Andric Mask[Reg / 32] |= 1U << (Reg % 32); 1650b57cec5SDimitry Andric 1660b57cec5SDimitry Andric // Give the target a chance to adjust the mask. 1670b57cec5SDimitry Andric TRI->adjustStackMapLiveOutMask(Mask); 1680b57cec5SDimitry Andric 1690b57cec5SDimitry Andric return Mask; 1700b57cec5SDimitry Andric } 171