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