1e8d8bef9SDimitry Andric //===- PseudoProbeInserter.cpp - Insert annotation for callsite profiling -===// 2e8d8bef9SDimitry Andric // 3e8d8bef9SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4e8d8bef9SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5e8d8bef9SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e8d8bef9SDimitry Andric // 7e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===// 8e8d8bef9SDimitry Andric // 9e8d8bef9SDimitry Andric // This file implements PseudoProbeInserter pass, which inserts pseudo probe 10e8d8bef9SDimitry Andric // annotations for call instructions with a pseudo-probe-specific dwarf 11e8d8bef9SDimitry Andric // discriminator. such discriminator indicates that the call instruction comes 12e8d8bef9SDimitry Andric // with a pseudo probe, and the discriminator value holds information to 13e8d8bef9SDimitry Andric // identify the corresponding counter. 14e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===// 15e8d8bef9SDimitry Andric 16e8d8bef9SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h" 17e8d8bef9SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 18e8d8bef9SDimitry Andric #include "llvm/CodeGen/MachineInstr.h" 19e8d8bef9SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h" 20e8d8bef9SDimitry Andric #include "llvm/IR/DebugInfoMetadata.h" 21e8d8bef9SDimitry Andric #include "llvm/IR/PseudoProbe.h" 22e8d8bef9SDimitry Andric #include "llvm/InitializePasses.h" 23*fe6060f1SDimitry Andric #include "llvm/MC/MCPseudoProbe.h" 24e8d8bef9SDimitry Andric #include "llvm/Target/TargetMachine.h" 25*fe6060f1SDimitry Andric #include <unordered_set> 26e8d8bef9SDimitry Andric 27e8d8bef9SDimitry Andric #define DEBUG_TYPE "pseudo-probe-inserter" 28e8d8bef9SDimitry Andric 29e8d8bef9SDimitry Andric using namespace llvm; 30e8d8bef9SDimitry Andric 31e8d8bef9SDimitry Andric namespace { 32e8d8bef9SDimitry Andric class PseudoProbeInserter : public MachineFunctionPass { 33e8d8bef9SDimitry Andric public: 34e8d8bef9SDimitry Andric static char ID; 35e8d8bef9SDimitry Andric 36e8d8bef9SDimitry Andric PseudoProbeInserter() : MachineFunctionPass(ID) { 37e8d8bef9SDimitry Andric initializePseudoProbeInserterPass(*PassRegistry::getPassRegistry()); 38e8d8bef9SDimitry Andric } 39e8d8bef9SDimitry Andric 40e8d8bef9SDimitry Andric StringRef getPassName() const override { return "Pseudo Probe Inserter"; } 41e8d8bef9SDimitry Andric 42e8d8bef9SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 43e8d8bef9SDimitry Andric AU.setPreservesAll(); 44e8d8bef9SDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 45e8d8bef9SDimitry Andric } 46e8d8bef9SDimitry Andric 47e8d8bef9SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override { 48e8d8bef9SDimitry Andric const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo(); 49e8d8bef9SDimitry Andric bool Changed = false; 50e8d8bef9SDimitry Andric for (MachineBasicBlock &MBB : MF) { 51*fe6060f1SDimitry Andric MachineInstr *FirstInstr = nullptr; 52e8d8bef9SDimitry Andric for (MachineInstr &MI : MBB) { 53*fe6060f1SDimitry Andric if (!MI.isPseudo()) 54*fe6060f1SDimitry Andric FirstInstr = &MI; 55e8d8bef9SDimitry Andric if (MI.isCall()) { 56e8d8bef9SDimitry Andric if (DILocation *DL = MI.getDebugLoc()) { 57e8d8bef9SDimitry Andric auto Value = DL->getDiscriminator(); 58e8d8bef9SDimitry Andric if (DILocation::isPseudoProbeDiscriminator(Value)) { 59e8d8bef9SDimitry Andric BuildMI(MBB, MI, DL, TII->get(TargetOpcode::PSEUDO_PROBE)) 60e8d8bef9SDimitry Andric .addImm(getFuncGUID(MF.getFunction().getParent(), DL)) 61e8d8bef9SDimitry Andric .addImm( 62e8d8bef9SDimitry Andric PseudoProbeDwarfDiscriminator::extractProbeIndex(Value)) 63e8d8bef9SDimitry Andric .addImm( 64e8d8bef9SDimitry Andric PseudoProbeDwarfDiscriminator::extractProbeType(Value)) 65e8d8bef9SDimitry Andric .addImm(PseudoProbeDwarfDiscriminator::extractProbeAttributes( 66e8d8bef9SDimitry Andric Value)); 67e8d8bef9SDimitry Andric Changed = true; 68e8d8bef9SDimitry Andric } 69e8d8bef9SDimitry Andric } 70e8d8bef9SDimitry Andric } 71e8d8bef9SDimitry Andric } 72*fe6060f1SDimitry Andric 73*fe6060f1SDimitry Andric // Walk the block backwards, move PSEUDO_PROBE before the first real 74*fe6060f1SDimitry Andric // instruction to fix out-of-order probes. There is a problem with probes 75*fe6060f1SDimitry Andric // as the terminator of the block. During the offline counts processing, 76*fe6060f1SDimitry Andric // the samples collected on the first physical instruction following a 77*fe6060f1SDimitry Andric // probe will be counted towards the probe. This logically equals to 78*fe6060f1SDimitry Andric // treating the instruction next to a probe as if it is from the same 79*fe6060f1SDimitry Andric // block of the probe. This is accurate most of the time unless the 80*fe6060f1SDimitry Andric // instruction can be reached from multiple flows, which means it actually 81*fe6060f1SDimitry Andric // starts a new block. Samples collected on such probes may cause 82*fe6060f1SDimitry Andric // imprecision with the counts inference algorithm. Fortunately, if 83*fe6060f1SDimitry Andric // there are still other native instructions preceding the probe we can 84*fe6060f1SDimitry Andric // use them as a place holder to collect samples for the probe. 85*fe6060f1SDimitry Andric if (FirstInstr) { 86*fe6060f1SDimitry Andric auto MII = MBB.rbegin(); 87*fe6060f1SDimitry Andric while (MII != MBB.rend()) { 88*fe6060f1SDimitry Andric // Skip all pseudo probes followed by a real instruction since they 89*fe6060f1SDimitry Andric // are not dangling. 90*fe6060f1SDimitry Andric if (!MII->isPseudo()) 91*fe6060f1SDimitry Andric break; 92*fe6060f1SDimitry Andric auto Cur = MII++; 93*fe6060f1SDimitry Andric if (Cur->getOpcode() != TargetOpcode::PSEUDO_PROBE) 94*fe6060f1SDimitry Andric continue; 95*fe6060f1SDimitry Andric // Move the dangling probe before FirstInstr. 96*fe6060f1SDimitry Andric auto *ProbeInstr = &*Cur; 97*fe6060f1SDimitry Andric MBB.remove(ProbeInstr); 98*fe6060f1SDimitry Andric MBB.insert(FirstInstr, ProbeInstr); 99*fe6060f1SDimitry Andric Changed = true; 100*fe6060f1SDimitry Andric } 101*fe6060f1SDimitry Andric } else { 102*fe6060f1SDimitry Andric // Probes not surrounded by any real instructions in the same block are 103*fe6060f1SDimitry Andric // called dangling probes. Since there's no good way to pick up a sample 104*fe6060f1SDimitry Andric // collection point for dangling probes at compile time, they are being 105*fe6060f1SDimitry Andric // removed so that the profile correlation tool will not report any 106*fe6060f1SDimitry Andric // samples collected for them and it's up to the counts inference tool 107*fe6060f1SDimitry Andric // to get them a reasonable count. 108*fe6060f1SDimitry Andric SmallVector<MachineInstr *, 4> ToBeRemoved; 109*fe6060f1SDimitry Andric for (MachineInstr &MI : MBB) { 110*fe6060f1SDimitry Andric if (MI.isPseudoProbe()) 111*fe6060f1SDimitry Andric ToBeRemoved.push_back(&MI); 112*fe6060f1SDimitry Andric } 113*fe6060f1SDimitry Andric 114*fe6060f1SDimitry Andric for (auto *MI : ToBeRemoved) 115*fe6060f1SDimitry Andric MI->eraseFromParent(); 116*fe6060f1SDimitry Andric 117*fe6060f1SDimitry Andric Changed |= !ToBeRemoved.empty(); 118*fe6060f1SDimitry Andric } 119e8d8bef9SDimitry Andric } 120e8d8bef9SDimitry Andric 121e8d8bef9SDimitry Andric return Changed; 122e8d8bef9SDimitry Andric } 123e8d8bef9SDimitry Andric 124e8d8bef9SDimitry Andric private: 125e8d8bef9SDimitry Andric uint64_t getFuncGUID(Module *M, DILocation *DL) { 126e8d8bef9SDimitry Andric auto *SP = DL->getScope()->getSubprogram(); 127e8d8bef9SDimitry Andric auto Name = SP->getLinkageName(); 128e8d8bef9SDimitry Andric if (Name.empty()) 129e8d8bef9SDimitry Andric Name = SP->getName(); 130e8d8bef9SDimitry Andric return Function::getGUID(Name); 131e8d8bef9SDimitry Andric } 132e8d8bef9SDimitry Andric }; 133e8d8bef9SDimitry Andric } // namespace 134e8d8bef9SDimitry Andric 135e8d8bef9SDimitry Andric char PseudoProbeInserter::ID = 0; 136e8d8bef9SDimitry Andric INITIALIZE_PASS_BEGIN(PseudoProbeInserter, DEBUG_TYPE, 137e8d8bef9SDimitry Andric "Insert pseudo probe annotations for value profiling", 138e8d8bef9SDimitry Andric false, false) 139e8d8bef9SDimitry Andric INITIALIZE_PASS_DEPENDENCY(TargetPassConfig) 140e8d8bef9SDimitry Andric INITIALIZE_PASS_END(PseudoProbeInserter, DEBUG_TYPE, 141e8d8bef9SDimitry Andric "Insert pseudo probe annotations for value profiling", 142e8d8bef9SDimitry Andric false, false) 143e8d8bef9SDimitry Andric 144e8d8bef9SDimitry Andric FunctionPass *llvm::createPseudoProbeInserter() { 145e8d8bef9SDimitry Andric return new PseudoProbeInserter(); 146e8d8bef9SDimitry Andric } 147