xref: /freebsd/contrib/llvm-project/llvm/lib/MC/MCPseudoProbe.cpp (revision f7c32ed617858bcd22f8d1b03199099d50125721)
1 //===- lib/MC/MCPseudoProbe.cpp - Pseudo probe encoding support ----------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "llvm/MC/MCPseudoProbe.h"
10 #include "llvm/MC/MCAsmInfo.h"
11 #include "llvm/MC/MCContext.h"
12 #include "llvm/MC/MCObjectFileInfo.h"
13 #include "llvm/MC/MCObjectStreamer.h"
14 #include "llvm/MC/MCStreamer.h"
15 
16 #define DEBUG_TYPE "mcpseudoprobe"
17 
18 using namespace llvm;
19 
20 #ifndef NDEBUG
21 int MCPseudoProbeTable::DdgPrintIndent = 0;
22 #endif
23 
24 static const MCExpr *buildSymbolDiff(MCObjectStreamer *MCOS, const MCSymbol *A,
25                                      const MCSymbol *B) {
26   MCContext &Context = MCOS->getContext();
27   MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None;
28   const MCExpr *ARef = MCSymbolRefExpr::create(A, Variant, Context);
29   const MCExpr *BRef = MCSymbolRefExpr::create(B, Variant, Context);
30   const MCExpr *AddrDelta =
31       MCBinaryExpr::create(MCBinaryExpr::Sub, ARef, BRef, Context);
32   return AddrDelta;
33 }
34 
35 void MCPseudoProbe::emit(MCObjectStreamer *MCOS,
36                          const MCPseudoProbe *LastProbe) const {
37   // Emit Index
38   MCOS->emitULEB128IntValue(Index);
39   // Emit Type and the flag:
40   // Type (bit 0 to 3), with bit 4 to 6 for attributes.
41   // Flag (bit 7, 0 - code address, 1 - address delta). This indicates whether
42   // the following field is a symbolic code address or an address delta.
43   assert(Type <= 0xF && "Probe type too big to encode, exceeding 15");
44   assert(Attributes <= 0x7 &&
45          "Probe attributes too big to encode, exceeding 7");
46   uint8_t PackedType = Type | (Attributes << 4);
47   uint8_t Flag = LastProbe ? ((int8_t)MCPseudoProbeFlag::AddressDelta << 7) : 0;
48   MCOS->emitInt8(Flag | PackedType);
49 
50   if (LastProbe) {
51     // Emit the delta between the address label and LastProbe.
52     const MCExpr *AddrDelta =
53         buildSymbolDiff(MCOS, Label, LastProbe->getLabel());
54     int64_t Delta;
55     if (AddrDelta->evaluateAsAbsolute(Delta, MCOS->getAssemblerPtr())) {
56       MCOS->emitSLEB128IntValue(Delta);
57     } else {
58       MCOS->insert(new MCPseudoProbeAddrFragment(AddrDelta));
59     }
60   } else {
61     // Emit label as a symbolic code address.
62     MCOS->emitSymbolValue(
63         Label, MCOS->getContext().getAsmInfo()->getCodePointerSize());
64   }
65 
66   LLVM_DEBUG({
67     dbgs().indent(MCPseudoProbeTable::DdgPrintIndent);
68     dbgs() << "Probe: " << Index << "\n";
69   });
70 }
71 
72 MCPseudoProbeInlineTree::~MCPseudoProbeInlineTree() {
73   for (auto &Inlinee : Inlinees)
74     delete Inlinee.second;
75 }
76 
77 MCPseudoProbeInlineTree *
78 MCPseudoProbeInlineTree::getOrAddNode(InlineSite Site) {
79   auto Iter = Inlinees.find(Site);
80   if (Iter == Inlinees.end()) {
81     auto *Node = new MCPseudoProbeInlineTree(std::get<0>(Site));
82     Inlinees[Site] = Node;
83     return Node;
84   } else {
85     return Iter->second;
86   }
87 }
88 
89 void MCPseudoProbeInlineTree::addPseudoProbe(
90     const MCPseudoProbe &Probe, const MCPseudoProbeInlineStack &InlineStack) {
91   // The function should not be called on the root.
92   assert(isRoot() && "Should not be called on root");
93 
94   // When it comes here, the input look like:
95   //    Probe: GUID of C, ...
96   //    InlineStack: [88, A], [66, B]
97   // which means, Function A inlines function B at call site with a probe id of
98   // 88, and B inlines C at probe 66. The tri-tree expects a tree path like {[0,
99   // A], [88, B], [66, C]} to locate the tree node where the probe should be
100   // added. Note that the edge [0, A] means A is the top-level function we are
101   // emitting probes for.
102 
103   // Make a [0, A] edge.
104   // An empty inline stack means the function that the probe originates from
105   // is a top-level function.
106   InlineSite Top;
107   if (InlineStack.empty()) {
108     Top = InlineSite(Probe.getGuid(), 0);
109   } else {
110     Top = InlineSite(std::get<0>(InlineStack.front()), 0);
111   }
112 
113   auto *Cur = getOrAddNode(Top);
114 
115   // Make interior edges by walking the inline stack. Once it's done, Cur should
116   // point to the node that the probe originates from.
117   if (!InlineStack.empty()) {
118     auto Iter = InlineStack.begin();
119     auto Index = std::get<1>(*Iter);
120     Iter++;
121     for (; Iter != InlineStack.end(); Iter++) {
122       // Make an edge by using the previous probe id and current GUID.
123       Cur = Cur->getOrAddNode(InlineSite(std::get<0>(*Iter), Index));
124       Index = std::get<1>(*Iter);
125     }
126     Cur = Cur->getOrAddNode(InlineSite(Probe.getGuid(), Index));
127   }
128 
129   Cur->Probes.push_back(Probe);
130 }
131 
132 void MCPseudoProbeInlineTree::emit(MCObjectStreamer *MCOS,
133                                    const MCPseudoProbe *&LastProbe) {
134   LLVM_DEBUG({
135     dbgs().indent(MCPseudoProbeTable::DdgPrintIndent);
136     dbgs() << "Group [\n";
137     MCPseudoProbeTable::DdgPrintIndent += 2;
138   });
139   // Emit probes grouped by GUID.
140   if (Guid != 0) {
141     LLVM_DEBUG({
142       dbgs().indent(MCPseudoProbeTable::DdgPrintIndent);
143       dbgs() << "GUID: " << Guid << "\n";
144     });
145     // Emit Guid
146     MCOS->emitInt64(Guid);
147     // Emit number of probes in this node
148     MCOS->emitULEB128IntValue(Probes.size());
149     // Emit number of direct inlinees
150     MCOS->emitULEB128IntValue(Inlinees.size());
151     // Emit probes in this group
152     for (const auto &Probe : Probes) {
153       Probe.emit(MCOS, LastProbe);
154       LastProbe = &Probe;
155     }
156   } else {
157     assert(Probes.empty() && "Root should not have probes");
158   }
159 
160   // Emit descendent
161   for (const auto &Inlinee : Inlinees) {
162     if (Guid) {
163       // Emit probe index
164       MCOS->emitULEB128IntValue(std::get<1>(Inlinee.first));
165       LLVM_DEBUG({
166         dbgs().indent(MCPseudoProbeTable::DdgPrintIndent);
167         dbgs() << "InlineSite: " << std::get<1>(Inlinee.first) << "\n";
168       });
169     }
170     // Emit the group
171     Inlinee.second->emit(MCOS, LastProbe);
172   }
173 
174   LLVM_DEBUG({
175     MCPseudoProbeTable::DdgPrintIndent -= 2;
176     dbgs().indent(MCPseudoProbeTable::DdgPrintIndent);
177     dbgs() << "]\n";
178   });
179 }
180 
181 void MCPseudoProbeSection::emit(MCObjectStreamer *MCOS) {
182   MCContext &Ctx = MCOS->getContext();
183 
184   for (auto &ProbeSec : MCProbeDivisions) {
185     const MCPseudoProbe *LastProbe = nullptr;
186     if (auto *S =
187             Ctx.getObjectFileInfo()->getPseudoProbeSection(ProbeSec.first)) {
188       // Switch to the .pseudoprobe section or a comdat group.
189       MCOS->SwitchSection(S);
190       // Emit probes grouped by GUID.
191       ProbeSec.second.emit(MCOS, LastProbe);
192     }
193   }
194 }
195 
196 //
197 // This emits the pseudo probe tables.
198 //
199 void MCPseudoProbeTable::emit(MCObjectStreamer *MCOS) {
200   MCContext &Ctx = MCOS->getContext();
201   auto &ProbeTable = Ctx.getMCPseudoProbeTable();
202 
203   // Bail out early so we don't switch to the pseudo_probe section needlessly
204   // and in doing so create an unnecessary (if empty) section.
205   auto &ProbeSections = ProbeTable.getProbeSections();
206   if (ProbeSections.empty())
207     return;
208 
209   LLVM_DEBUG(MCPseudoProbeTable::DdgPrintIndent = 0);
210 
211   // Put out the probe.
212   ProbeSections.emit(MCOS);
213 }
214