//===-- StackMapLivenessAnalysis.cpp - StackMap live Out Analysis ----------===// // // 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 file implements the StackMap Liveness analysis pass. The pass calculates // the liveness for each basic block in a function and attaches the register // live-out information to a stackmap or patchpoint intrinsic if present. // //===----------------------------------------------------------------------===// #include "llvm/ADT/Statistic.h" #include "llvm/CodeGen/LivePhysRegs.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/InitializePasses.h" #include "llvm/Pass.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; #define DEBUG_TYPE "stackmaps" static cl::opt EnablePatchPointLiveness( "enable-patchpoint-liveness", cl::Hidden, cl::init(true), cl::desc("Enable PatchPoint Liveness Analysis Pass")); STATISTIC(NumStackMapFuncVisited, "Number of functions visited"); STATISTIC(NumStackMapFuncSkipped, "Number of functions skipped"); STATISTIC(NumBBsVisited, "Number of basic blocks visited"); STATISTIC(NumBBsHaveNoStackmap, "Number of basic blocks with no stackmap"); STATISTIC(NumStackMaps, "Number of StackMaps visited"); namespace { /// This pass calculates the liveness information for each basic block in /// a function and attaches the register live-out information to a patchpoint /// intrinsic if present. /// /// This pass can be disabled via the -enable-patchpoint-liveness=false flag. /// The pass skips functions that don't have any patchpoint intrinsics. The /// information provided by this pass is optional and not required by the /// aformentioned intrinsic to function. class StackMapLiveness : public MachineFunctionPass { const TargetRegisterInfo *TRI; LivePhysRegs LiveRegs; public: static char ID; /// Default construct and initialize the pass. StackMapLiveness(); /// Tell the pass manager which passes we depend on and what /// information we preserve. void getAnalysisUsage(AnalysisUsage &AU) const override; MachineFunctionProperties getRequiredProperties() const override { return MachineFunctionProperties().set( MachineFunctionProperties::Property::NoVRegs); } /// Calculate the liveness information for the given machine function. bool runOnMachineFunction(MachineFunction &MF) override; private: /// Performs the actual liveness calculation for the function. bool calculateLiveness(MachineFunction &MF); /// Add the current register live set to the instruction. void addLiveOutSetToMI(MachineFunction &MF, MachineInstr &MI); /// Create a register mask and initialize it with the registers from /// the register live set. uint32_t *createRegisterMask(MachineFunction &MF) const; }; } // namespace char StackMapLiveness::ID = 0; char &llvm::StackMapLivenessID = StackMapLiveness::ID; INITIALIZE_PASS(StackMapLiveness, "stackmap-liveness", "StackMap Liveness Analysis", false, false) /// Default construct and initialize the pass. StackMapLiveness::StackMapLiveness() : MachineFunctionPass(ID) { initializeStackMapLivenessPass(*PassRegistry::getPassRegistry()); } /// Tell the pass manager which passes we depend on and what information we /// preserve. void StackMapLiveness::getAnalysisUsage(AnalysisUsage &AU) const { // We preserve all information. AU.setPreservesAll(); AU.setPreservesCFG(); MachineFunctionPass::getAnalysisUsage(AU); } /// Calculate the liveness information for the given machine function. bool StackMapLiveness::runOnMachineFunction(MachineFunction &MF) { if (!EnablePatchPointLiveness) return false; LLVM_DEBUG(dbgs() << "********** COMPUTING STACKMAP LIVENESS: " << MF.getName() << " **********\n"); TRI = MF.getSubtarget().getRegisterInfo(); ++NumStackMapFuncVisited; // Skip this function if there are no patchpoints to process. if (!MF.getFrameInfo().hasPatchPoint()) { ++NumStackMapFuncSkipped; return false; } return calculateLiveness(MF); } /// Performs the actual liveness calculation for the function. bool StackMapLiveness::calculateLiveness(MachineFunction &MF) { bool HasChanged = false; // For all basic blocks in the function. for (auto &MBB : MF) { LLVM_DEBUG(dbgs() << "****** BB " << MBB.getName() << " ******\n"); LiveRegs.init(*TRI); // FIXME: This should probably be addLiveOuts(). LiveRegs.addLiveOutsNoPristines(MBB); bool HasStackMap = false; // Reverse iterate over all instructions and add the current live register // set to an instruction if we encounter a patchpoint instruction. for (MachineInstr &MI : llvm::reverse(MBB)) { if (MI.getOpcode() == TargetOpcode::PATCHPOINT) { addLiveOutSetToMI(MF, MI); HasChanged = true; HasStackMap = true; ++NumStackMaps; } LLVM_DEBUG(dbgs() << " " << LiveRegs << " " << MI); LiveRegs.stepBackward(MI); } ++NumBBsVisited; if (!HasStackMap) ++NumBBsHaveNoStackmap; } return HasChanged; } /// Add the current register live set to the instruction. void StackMapLiveness::addLiveOutSetToMI(MachineFunction &MF, MachineInstr &MI) { uint32_t *Mask = createRegisterMask(MF); MachineOperand MO = MachineOperand::CreateRegLiveOut(Mask); MI.addOperand(MF, MO); } /// Create a register mask and initialize it with the registers from the /// register live set. uint32_t *StackMapLiveness::createRegisterMask(MachineFunction &MF) const { // The mask is owned and cleaned up by the Machine Function. uint32_t *Mask = MF.allocateRegMask(); for (auto Reg : LiveRegs) Mask[Reg / 32] |= 1U << (Reg % 32); // Give the target a chance to adjust the mask. TRI->adjustStackMapLiveOutMask(Mask); return Mask; }