xref: /freebsd/contrib/llvm-project/llvm/lib/CodeGen/PseudoProbeInserter.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
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"
2181ad6265SDimitry Andric #include "llvm/IR/Module.h"
22e8d8bef9SDimitry Andric #include "llvm/IR/PseudoProbe.h"
23e8d8bef9SDimitry Andric #include "llvm/InitializePasses.h"
24e8d8bef9SDimitry Andric 
25e8d8bef9SDimitry Andric #define DEBUG_TYPE "pseudo-probe-inserter"
26e8d8bef9SDimitry Andric 
27e8d8bef9SDimitry Andric using namespace llvm;
28e8d8bef9SDimitry Andric 
29e8d8bef9SDimitry Andric namespace {
30e8d8bef9SDimitry Andric class PseudoProbeInserter : public MachineFunctionPass {
31e8d8bef9SDimitry Andric public:
32e8d8bef9SDimitry Andric   static char ID;
33e8d8bef9SDimitry Andric 
PseudoProbeInserter()34e8d8bef9SDimitry Andric   PseudoProbeInserter() : MachineFunctionPass(ID) {
35e8d8bef9SDimitry Andric     initializePseudoProbeInserterPass(*PassRegistry::getPassRegistry());
36e8d8bef9SDimitry Andric   }
37e8d8bef9SDimitry Andric 
getPassName() const38e8d8bef9SDimitry Andric   StringRef getPassName() const override { return "Pseudo Probe Inserter"; }
39e8d8bef9SDimitry Andric 
getAnalysisUsage(AnalysisUsage & AU) const40e8d8bef9SDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override {
41e8d8bef9SDimitry Andric     AU.setPreservesAll();
42e8d8bef9SDimitry Andric     MachineFunctionPass::getAnalysisUsage(AU);
43e8d8bef9SDimitry Andric   }
44e8d8bef9SDimitry Andric 
doInitialization(Module & M)45349cc55cSDimitry Andric   bool doInitialization(Module &M) override {
46349cc55cSDimitry Andric     ShouldRun = M.getNamedMetadata(PseudoProbeDescMetadataName);
47349cc55cSDimitry Andric     return false;
48349cc55cSDimitry Andric   }
49349cc55cSDimitry Andric 
runOnMachineFunction(MachineFunction & MF)50e8d8bef9SDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override {
51349cc55cSDimitry Andric     if (!ShouldRun)
52349cc55cSDimitry Andric       return false;
53e8d8bef9SDimitry Andric     const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
54e8d8bef9SDimitry Andric     bool Changed = false;
55e8d8bef9SDimitry Andric     for (MachineBasicBlock &MBB : MF) {
56fe6060f1SDimitry Andric       MachineInstr *FirstInstr = nullptr;
57e8d8bef9SDimitry Andric       for (MachineInstr &MI : MBB) {
58fe6060f1SDimitry Andric         if (!MI.isPseudo())
59fe6060f1SDimitry Andric           FirstInstr = &MI;
60e8d8bef9SDimitry Andric         if (MI.isCall()) {
61e8d8bef9SDimitry Andric           if (DILocation *DL = MI.getDebugLoc()) {
62e8d8bef9SDimitry Andric             auto Value = DL->getDiscriminator();
63e8d8bef9SDimitry Andric             if (DILocation::isPseudoProbeDiscriminator(Value)) {
64e8d8bef9SDimitry Andric               BuildMI(MBB, MI, DL, TII->get(TargetOpcode::PSEUDO_PROBE))
65e8d8bef9SDimitry Andric                   .addImm(getFuncGUID(MF.getFunction().getParent(), DL))
66e8d8bef9SDimitry Andric                   .addImm(
67e8d8bef9SDimitry Andric                       PseudoProbeDwarfDiscriminator::extractProbeIndex(Value))
68e8d8bef9SDimitry Andric                   .addImm(
69e8d8bef9SDimitry Andric                       PseudoProbeDwarfDiscriminator::extractProbeType(Value))
70e8d8bef9SDimitry Andric                   .addImm(PseudoProbeDwarfDiscriminator::extractProbeAttributes(
71e8d8bef9SDimitry Andric                       Value));
72e8d8bef9SDimitry Andric               Changed = true;
73e8d8bef9SDimitry Andric             }
74e8d8bef9SDimitry Andric           }
75e8d8bef9SDimitry Andric         }
76e8d8bef9SDimitry Andric       }
77fe6060f1SDimitry Andric 
78fe6060f1SDimitry Andric       // Walk the block backwards, move PSEUDO_PROBE before the first real
79fe6060f1SDimitry Andric       // instruction to fix out-of-order probes. There is a problem with probes
80fe6060f1SDimitry Andric       // as the terminator of the block. During the offline counts processing,
81fe6060f1SDimitry Andric       // the samples collected on the first physical instruction following a
82fe6060f1SDimitry Andric       // probe will be counted towards the probe. This logically equals to
83fe6060f1SDimitry Andric       // treating the instruction next to a probe as if it is from the same
84fe6060f1SDimitry Andric       // block of the probe. This is accurate most of the time unless the
85fe6060f1SDimitry Andric       // instruction can be reached from multiple flows, which means it actually
86fe6060f1SDimitry Andric       // starts a new block. Samples collected on such probes may cause
87fe6060f1SDimitry Andric       // imprecision with the counts inference algorithm. Fortunately, if
88fe6060f1SDimitry Andric       // there are still other native instructions preceding the probe we can
89fe6060f1SDimitry Andric       // use them as a place holder to collect samples for the probe.
90fe6060f1SDimitry Andric       if (FirstInstr) {
91fe6060f1SDimitry Andric         auto MII = MBB.rbegin();
92fe6060f1SDimitry Andric         while (MII != MBB.rend()) {
93fe6060f1SDimitry Andric           // Skip all pseudo probes followed by a real instruction since they
94fe6060f1SDimitry Andric           // are not dangling.
95fe6060f1SDimitry Andric           if (!MII->isPseudo())
96fe6060f1SDimitry Andric             break;
97fe6060f1SDimitry Andric           auto Cur = MII++;
98fe6060f1SDimitry Andric           if (Cur->getOpcode() != TargetOpcode::PSEUDO_PROBE)
99fe6060f1SDimitry Andric             continue;
100fe6060f1SDimitry Andric           // Move the dangling probe before FirstInstr.
101fe6060f1SDimitry Andric           auto *ProbeInstr = &*Cur;
102fe6060f1SDimitry Andric           MBB.remove(ProbeInstr);
103fe6060f1SDimitry Andric           MBB.insert(FirstInstr, ProbeInstr);
104fe6060f1SDimitry Andric           Changed = true;
105fe6060f1SDimitry Andric         }
106fe6060f1SDimitry Andric       } else {
107fe6060f1SDimitry Andric         // Probes not surrounded by any real instructions in the same block are
108fe6060f1SDimitry Andric         // called dangling probes. Since there's no good way to pick up a sample
109fe6060f1SDimitry Andric         // collection point for dangling probes at compile time, they are being
110fe6060f1SDimitry Andric         // removed so that the profile correlation tool will not report any
111fe6060f1SDimitry Andric         // samples collected for them and it's up to the counts inference tool
112fe6060f1SDimitry Andric         // to get them a reasonable count.
113fe6060f1SDimitry Andric         SmallVector<MachineInstr *, 4> ToBeRemoved;
114fe6060f1SDimitry Andric         for (MachineInstr &MI : MBB) {
115fe6060f1SDimitry Andric           if (MI.isPseudoProbe())
116fe6060f1SDimitry Andric             ToBeRemoved.push_back(&MI);
117fe6060f1SDimitry Andric         }
118fe6060f1SDimitry Andric 
119fe6060f1SDimitry Andric         for (auto *MI : ToBeRemoved)
120fe6060f1SDimitry Andric           MI->eraseFromParent();
121fe6060f1SDimitry Andric 
122fe6060f1SDimitry Andric         Changed |= !ToBeRemoved.empty();
123fe6060f1SDimitry Andric       }
124e8d8bef9SDimitry Andric     }
125e8d8bef9SDimitry Andric 
126e8d8bef9SDimitry Andric     return Changed;
127e8d8bef9SDimitry Andric   }
128e8d8bef9SDimitry Andric 
129e8d8bef9SDimitry Andric private:
getFuncGUID(Module * M,DILocation * DL)130e8d8bef9SDimitry Andric   uint64_t getFuncGUID(Module *M, DILocation *DL) {
131*06c3fb27SDimitry Andric     auto Name = DL->getSubprogramLinkageName();
132e8d8bef9SDimitry Andric     return Function::getGUID(Name);
133e8d8bef9SDimitry Andric   }
134349cc55cSDimitry Andric 
135349cc55cSDimitry Andric   bool ShouldRun = false;
136e8d8bef9SDimitry Andric };
137e8d8bef9SDimitry Andric } // namespace
138e8d8bef9SDimitry Andric 
139e8d8bef9SDimitry Andric char PseudoProbeInserter::ID = 0;
140e8d8bef9SDimitry Andric INITIALIZE_PASS_BEGIN(PseudoProbeInserter, DEBUG_TYPE,
141e8d8bef9SDimitry Andric                       "Insert pseudo probe annotations for value profiling",
142e8d8bef9SDimitry Andric                       false, false)
INITIALIZE_PASS_DEPENDENCY(TargetPassConfig)143e8d8bef9SDimitry Andric INITIALIZE_PASS_DEPENDENCY(TargetPassConfig)
144e8d8bef9SDimitry Andric INITIALIZE_PASS_END(PseudoProbeInserter, DEBUG_TYPE,
145e8d8bef9SDimitry Andric                     "Insert pseudo probe annotations for value profiling",
146e8d8bef9SDimitry Andric                     false, false)
147e8d8bef9SDimitry Andric 
148e8d8bef9SDimitry Andric FunctionPass *llvm::createPseudoProbeInserter() {
149e8d8bef9SDimitry Andric   return new PseudoProbeInserter();
150e8d8bef9SDimitry Andric }
151