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