File: | build/source/llvm/include/llvm/Support/Endian.h |
Warning: | line 66, column 3 Null pointer passed to 2nd parameter expecting 'nonnull' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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/ADT/STLExtras.h" | ||||||||
11 | #include "llvm/MC/MCAsmInfo.h" | ||||||||
12 | #include "llvm/MC/MCContext.h" | ||||||||
13 | #include "llvm/MC/MCExpr.h" | ||||||||
14 | #include "llvm/MC/MCFragment.h" | ||||||||
15 | #include "llvm/MC/MCObjectFileInfo.h" | ||||||||
16 | #include "llvm/MC/MCObjectStreamer.h" | ||||||||
17 | #include "llvm/MC/MCSymbol.h" | ||||||||
18 | #include "llvm/Support/Endian.h" | ||||||||
19 | #include "llvm/Support/LEB128.h" | ||||||||
20 | #include "llvm/Support/MD5.h" | ||||||||
21 | #include "llvm/Support/raw_ostream.h" | ||||||||
22 | #include <algorithm> | ||||||||
23 | #include <cassert> | ||||||||
24 | #include <limits> | ||||||||
25 | #include <memory> | ||||||||
26 | #include <sstream> | ||||||||
27 | #include <vector> | ||||||||
28 | |||||||||
29 | #define DEBUG_TYPE"mcpseudoprobe" "mcpseudoprobe" | ||||||||
30 | |||||||||
31 | using namespace llvm; | ||||||||
32 | using namespace support; | ||||||||
33 | |||||||||
34 | #ifndef NDEBUG | ||||||||
35 | int MCPseudoProbeTable::DdgPrintIndent = 0; | ||||||||
36 | #endif | ||||||||
37 | |||||||||
38 | static const MCExpr *buildSymbolDiff(MCObjectStreamer *MCOS, const MCSymbol *A, | ||||||||
39 | const MCSymbol *B) { | ||||||||
40 | MCContext &Context = MCOS->getContext(); | ||||||||
41 | MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None; | ||||||||
42 | const MCExpr *ARef = MCSymbolRefExpr::create(A, Variant, Context); | ||||||||
43 | const MCExpr *BRef = MCSymbolRefExpr::create(B, Variant, Context); | ||||||||
44 | const MCExpr *AddrDelta = | ||||||||
45 | MCBinaryExpr::create(MCBinaryExpr::Sub, ARef, BRef, Context); | ||||||||
46 | return AddrDelta; | ||||||||
47 | } | ||||||||
48 | |||||||||
49 | void MCPseudoProbe::emit(MCObjectStreamer *MCOS, | ||||||||
50 | const MCPseudoProbe *LastProbe) const { | ||||||||
51 | bool IsSentinel = isSentinelProbe(getAttributes()); | ||||||||
52 | assert((LastProbe || IsSentinel) &&(static_cast <bool> ((LastProbe || IsSentinel) && "Last probe should not be null for non-sentinel probes") ? void (0) : __assert_fail ("(LastProbe || IsSentinel) && \"Last probe should not be null for non-sentinel probes\"" , "llvm/lib/MC/MCPseudoProbe.cpp", 53, __extension__ __PRETTY_FUNCTION__ )) | ||||||||
53 | "Last probe should not be null for non-sentinel probes")(static_cast <bool> ((LastProbe || IsSentinel) && "Last probe should not be null for non-sentinel probes") ? void (0) : __assert_fail ("(LastProbe || IsSentinel) && \"Last probe should not be null for non-sentinel probes\"" , "llvm/lib/MC/MCPseudoProbe.cpp", 53, __extension__ __PRETTY_FUNCTION__ )); | ||||||||
54 | |||||||||
55 | // Emit Index | ||||||||
56 | MCOS->emitULEB128IntValue(Index); | ||||||||
57 | // Emit Type and the flag: | ||||||||
58 | // Type (bit 0 to 3), with bit 4 to 6 for attributes. | ||||||||
59 | // Flag (bit 7, 0 - code address, 1 - address delta). This indicates whether | ||||||||
60 | // the following field is a symbolic code address or an address delta. | ||||||||
61 | assert(Type <= 0xF && "Probe type too big to encode, exceeding 15")(static_cast <bool> (Type <= 0xF && "Probe type too big to encode, exceeding 15" ) ? void (0) : __assert_fail ("Type <= 0xF && \"Probe type too big to encode, exceeding 15\"" , "llvm/lib/MC/MCPseudoProbe.cpp", 61, __extension__ __PRETTY_FUNCTION__ )); | ||||||||
62 | assert(Attributes <= 0x7 &&(static_cast <bool> (Attributes <= 0x7 && "Probe attributes too big to encode, exceeding 7" ) ? void (0) : __assert_fail ("Attributes <= 0x7 && \"Probe attributes too big to encode, exceeding 7\"" , "llvm/lib/MC/MCPseudoProbe.cpp", 63, __extension__ __PRETTY_FUNCTION__ )) | ||||||||
63 | "Probe attributes too big to encode, exceeding 7")(static_cast <bool> (Attributes <= 0x7 && "Probe attributes too big to encode, exceeding 7" ) ? void (0) : __assert_fail ("Attributes <= 0x7 && \"Probe attributes too big to encode, exceeding 7\"" , "llvm/lib/MC/MCPseudoProbe.cpp", 63, __extension__ __PRETTY_FUNCTION__ )); | ||||||||
64 | uint8_t PackedType = Type | (Attributes << 4); | ||||||||
65 | uint8_t Flag = | ||||||||
66 | !IsSentinel ? ((int8_t)MCPseudoProbeFlag::AddressDelta << 7) : 0; | ||||||||
67 | MCOS->emitInt8(Flag | PackedType); | ||||||||
68 | |||||||||
69 | if (!IsSentinel) { | ||||||||
70 | // Emit the delta between the address label and LastProbe. | ||||||||
71 | const MCExpr *AddrDelta = | ||||||||
72 | buildSymbolDiff(MCOS, Label, LastProbe->getLabel()); | ||||||||
73 | int64_t Delta; | ||||||||
74 | if (AddrDelta->evaluateAsAbsolute(Delta, MCOS->getAssemblerPtr())) { | ||||||||
75 | MCOS->emitSLEB128IntValue(Delta); | ||||||||
76 | } else { | ||||||||
77 | MCOS->insert(new MCPseudoProbeAddrFragment(AddrDelta)); | ||||||||
78 | } | ||||||||
79 | } else { | ||||||||
80 | // Emit the GUID of the split function that the sentinel probe represents. | ||||||||
81 | MCOS->emitInt64(Guid); | ||||||||
82 | } | ||||||||
83 | |||||||||
84 | LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("mcpseudoprobe")) { { dbgs().indent(MCPseudoProbeTable::DdgPrintIndent ); dbgs() << "Probe: " << Index << "\n"; }; } } while (false) | ||||||||
85 | dbgs().indent(MCPseudoProbeTable::DdgPrintIndent);do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("mcpseudoprobe")) { { dbgs().indent(MCPseudoProbeTable::DdgPrintIndent ); dbgs() << "Probe: " << Index << "\n"; }; } } while (false) | ||||||||
86 | dbgs() << "Probe: " << Index << "\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("mcpseudoprobe")) { { dbgs().indent(MCPseudoProbeTable::DdgPrintIndent ); dbgs() << "Probe: " << Index << "\n"; }; } } while (false) | ||||||||
87 | })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("mcpseudoprobe")) { { dbgs().indent(MCPseudoProbeTable::DdgPrintIndent ); dbgs() << "Probe: " << Index << "\n"; }; } } while (false); | ||||||||
88 | } | ||||||||
89 | |||||||||
90 | void MCPseudoProbeInlineTree::addPseudoProbe( | ||||||||
91 | const MCPseudoProbe &Probe, const MCPseudoProbeInlineStack &InlineStack) { | ||||||||
92 | // The function should not be called on the root. | ||||||||
93 | assert(isRoot() && "Should only be called on root")(static_cast <bool> (isRoot() && "Should only be called on root" ) ? void (0) : __assert_fail ("isRoot() && \"Should only be called on root\"" , "llvm/lib/MC/MCPseudoProbe.cpp", 93, __extension__ __PRETTY_FUNCTION__ )); | ||||||||
94 | |||||||||
95 | // When it comes here, the input look like: | ||||||||
96 | // Probe: GUID of C, ... | ||||||||
97 | // InlineStack: [88, A], [66, B] | ||||||||
98 | // which means, Function A inlines function B at call site with a probe id of | ||||||||
99 | // 88, and B inlines C at probe 66. The tri-tree expects a tree path like {[0, | ||||||||
100 | // A], [88, B], [66, C]} to locate the tree node where the probe should be | ||||||||
101 | // added. Note that the edge [0, A] means A is the top-level function we are | ||||||||
102 | // emitting probes for. | ||||||||
103 | |||||||||
104 | // Make a [0, A] edge. | ||||||||
105 | // An empty inline stack means the function that the probe originates from | ||||||||
106 | // is a top-level function. | ||||||||
107 | InlineSite Top; | ||||||||
108 | if (InlineStack.empty()) { | ||||||||
109 | Top = InlineSite(Probe.getGuid(), 0); | ||||||||
110 | } else { | ||||||||
111 | Top = InlineSite(std::get<0>(InlineStack.front()), 0); | ||||||||
112 | } | ||||||||
113 | |||||||||
114 | auto *Cur = getOrAddNode(Top); | ||||||||
115 | |||||||||
116 | // Make interior edges by walking the inline stack. Once it's done, Cur should | ||||||||
117 | // point to the node that the probe originates from. | ||||||||
118 | if (!InlineStack.empty()) { | ||||||||
119 | auto Iter = InlineStack.begin(); | ||||||||
120 | auto Index = std::get<1>(*Iter); | ||||||||
121 | Iter++; | ||||||||
122 | for (; Iter != InlineStack.end(); Iter++) { | ||||||||
123 | // Make an edge by using the previous probe id and current GUID. | ||||||||
124 | Cur = Cur->getOrAddNode(InlineSite(std::get<0>(*Iter), Index)); | ||||||||
125 | Index = std::get<1>(*Iter); | ||||||||
126 | } | ||||||||
127 | Cur = Cur->getOrAddNode(InlineSite(Probe.getGuid(), Index)); | ||||||||
128 | } | ||||||||
129 | |||||||||
130 | Cur->Probes.push_back(Probe); | ||||||||
131 | } | ||||||||
132 | |||||||||
133 | void MCPseudoProbeInlineTree::emit(MCObjectStreamer *MCOS, | ||||||||
134 | const MCPseudoProbe *&LastProbe) { | ||||||||
135 | LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("mcpseudoprobe")) { { dbgs().indent(MCPseudoProbeTable::DdgPrintIndent ); dbgs() << "Group [\n"; MCPseudoProbeTable::DdgPrintIndent += 2; }; } } while (false) | ||||||||
136 | dbgs().indent(MCPseudoProbeTable::DdgPrintIndent);do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("mcpseudoprobe")) { { dbgs().indent(MCPseudoProbeTable::DdgPrintIndent ); dbgs() << "Group [\n"; MCPseudoProbeTable::DdgPrintIndent += 2; }; } } while (false) | ||||||||
137 | dbgs() << "Group [\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("mcpseudoprobe")) { { dbgs().indent(MCPseudoProbeTable::DdgPrintIndent ); dbgs() << "Group [\n"; MCPseudoProbeTable::DdgPrintIndent += 2; }; } } while (false) | ||||||||
138 | MCPseudoProbeTable::DdgPrintIndent += 2;do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("mcpseudoprobe")) { { dbgs().indent(MCPseudoProbeTable::DdgPrintIndent ); dbgs() << "Group [\n"; MCPseudoProbeTable::DdgPrintIndent += 2; }; } } while (false) | ||||||||
139 | })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("mcpseudoprobe")) { { dbgs().indent(MCPseudoProbeTable::DdgPrintIndent ); dbgs() << "Group [\n"; MCPseudoProbeTable::DdgPrintIndent += 2; }; } } while (false); | ||||||||
140 | assert(!isRoot() && "Root should be handled seperately")(static_cast <bool> (!isRoot() && "Root should be handled seperately" ) ? void (0) : __assert_fail ("!isRoot() && \"Root should be handled seperately\"" , "llvm/lib/MC/MCPseudoProbe.cpp", 140, __extension__ __PRETTY_FUNCTION__ )); | ||||||||
141 | |||||||||
142 | // Emit probes grouped by GUID. | ||||||||
143 | LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("mcpseudoprobe")) { { dbgs().indent(MCPseudoProbeTable::DdgPrintIndent ); dbgs() << "GUID: " << Guid << "\n"; }; } } while (false) | ||||||||
144 | dbgs().indent(MCPseudoProbeTable::DdgPrintIndent);do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("mcpseudoprobe")) { { dbgs().indent(MCPseudoProbeTable::DdgPrintIndent ); dbgs() << "GUID: " << Guid << "\n"; }; } } while (false) | ||||||||
145 | dbgs() << "GUID: " << Guid << "\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("mcpseudoprobe")) { { dbgs().indent(MCPseudoProbeTable::DdgPrintIndent ); dbgs() << "GUID: " << Guid << "\n"; }; } } while (false) | ||||||||
146 | })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("mcpseudoprobe")) { { dbgs().indent(MCPseudoProbeTable::DdgPrintIndent ); dbgs() << "GUID: " << Guid << "\n"; }; } } while (false); | ||||||||
147 | // Emit Guid | ||||||||
148 | MCOS->emitInt64(Guid); | ||||||||
149 | // Emit number of probes in this node, including a sentinel probe for | ||||||||
150 | // top-level functions if needed. | ||||||||
151 | bool NeedSentinel = false; | ||||||||
152 | if (Parent->isRoot()) { | ||||||||
153 | assert(isSentinelProbe(LastProbe->getAttributes()) &&(static_cast <bool> (isSentinelProbe(LastProbe->getAttributes ()) && "Starting probe of a top-level function should be a sentinel probe" ) ? void (0) : __assert_fail ("isSentinelProbe(LastProbe->getAttributes()) && \"Starting probe of a top-level function should be a sentinel probe\"" , "llvm/lib/MC/MCPseudoProbe.cpp", 154, __extension__ __PRETTY_FUNCTION__ )) | ||||||||
154 | "Starting probe of a top-level function should be a sentinel probe")(static_cast <bool> (isSentinelProbe(LastProbe->getAttributes ()) && "Starting probe of a top-level function should be a sentinel probe" ) ? void (0) : __assert_fail ("isSentinelProbe(LastProbe->getAttributes()) && \"Starting probe of a top-level function should be a sentinel probe\"" , "llvm/lib/MC/MCPseudoProbe.cpp", 154, __extension__ __PRETTY_FUNCTION__ )); | ||||||||
155 | // The main body of a split function doesn't need a sentinel probe. | ||||||||
156 | if (LastProbe->getGuid() != Guid) | ||||||||
157 | NeedSentinel = true; | ||||||||
158 | } | ||||||||
159 | |||||||||
160 | MCOS->emitULEB128IntValue(Probes.size() + NeedSentinel); | ||||||||
161 | // Emit number of direct inlinees | ||||||||
162 | MCOS->emitULEB128IntValue(Children.size()); | ||||||||
163 | // Emit sentinel probe for top-level functions | ||||||||
164 | if (NeedSentinel) | ||||||||
165 | LastProbe->emit(MCOS, nullptr); | ||||||||
166 | |||||||||
167 | // Emit probes in this group | ||||||||
168 | for (const auto &Probe : Probes) { | ||||||||
169 | Probe.emit(MCOS, LastProbe); | ||||||||
170 | LastProbe = &Probe; | ||||||||
171 | } | ||||||||
172 | |||||||||
173 | // Emit sorted descendant. InlineSite is unique for each pair, so there will | ||||||||
174 | // be no ordering of Inlinee based on MCPseudoProbeInlineTree* | ||||||||
175 | using InlineeType = std::pair<InlineSite, MCPseudoProbeInlineTree *>; | ||||||||
176 | auto Comparer = [](const InlineeType &A, const InlineeType &B) { | ||||||||
177 | return A.first < B.first; | ||||||||
178 | }; | ||||||||
179 | std::vector<InlineeType> Inlinees; | ||||||||
180 | for (const auto &Child : Children) | ||||||||
181 | Inlinees.emplace_back(Child.first, Child.second.get()); | ||||||||
182 | std::sort(Inlinees.begin(), Inlinees.end(), Comparer); | ||||||||
183 | |||||||||
184 | for (const auto &Inlinee : Inlinees) { | ||||||||
185 | // Emit probe index | ||||||||
186 | MCOS->emitULEB128IntValue(std::get<1>(Inlinee.first)); | ||||||||
187 | LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("mcpseudoprobe")) { { dbgs().indent(MCPseudoProbeTable::DdgPrintIndent ); dbgs() << "InlineSite: " << std::get<1>( Inlinee.first) << "\n"; }; } } while (false) | ||||||||
188 | dbgs().indent(MCPseudoProbeTable::DdgPrintIndent);do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("mcpseudoprobe")) { { dbgs().indent(MCPseudoProbeTable::DdgPrintIndent ); dbgs() << "InlineSite: " << std::get<1>( Inlinee.first) << "\n"; }; } } while (false) | ||||||||
189 | dbgs() << "InlineSite: " << std::get<1>(Inlinee.first) << "\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("mcpseudoprobe")) { { dbgs().indent(MCPseudoProbeTable::DdgPrintIndent ); dbgs() << "InlineSite: " << std::get<1>( Inlinee.first) << "\n"; }; } } while (false) | ||||||||
190 | })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("mcpseudoprobe")) { { dbgs().indent(MCPseudoProbeTable::DdgPrintIndent ); dbgs() << "InlineSite: " << std::get<1>( Inlinee.first) << "\n"; }; } } while (false); | ||||||||
191 | // Emit the group | ||||||||
192 | Inlinee.second->emit(MCOS, LastProbe); | ||||||||
193 | } | ||||||||
194 | |||||||||
195 | LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("mcpseudoprobe")) { { MCPseudoProbeTable::DdgPrintIndent -= 2 ; dbgs().indent(MCPseudoProbeTable::DdgPrintIndent); dbgs() << "]\n"; }; } } while (false) | ||||||||
196 | MCPseudoProbeTable::DdgPrintIndent -= 2;do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("mcpseudoprobe")) { { MCPseudoProbeTable::DdgPrintIndent -= 2 ; dbgs().indent(MCPseudoProbeTable::DdgPrintIndent); dbgs() << "]\n"; }; } } while (false) | ||||||||
197 | dbgs().indent(MCPseudoProbeTable::DdgPrintIndent);do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("mcpseudoprobe")) { { MCPseudoProbeTable::DdgPrintIndent -= 2 ; dbgs().indent(MCPseudoProbeTable::DdgPrintIndent); dbgs() << "]\n"; }; } } while (false) | ||||||||
198 | dbgs() << "]\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("mcpseudoprobe")) { { MCPseudoProbeTable::DdgPrintIndent -= 2 ; dbgs().indent(MCPseudoProbeTable::DdgPrintIndent); dbgs() << "]\n"; }; } } while (false) | ||||||||
199 | })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("mcpseudoprobe")) { { MCPseudoProbeTable::DdgPrintIndent -= 2 ; dbgs().indent(MCPseudoProbeTable::DdgPrintIndent); dbgs() << "]\n"; }; } } while (false); | ||||||||
200 | } | ||||||||
201 | |||||||||
202 | void MCPseudoProbeSections::emit(MCObjectStreamer *MCOS) { | ||||||||
203 | MCContext &Ctx = MCOS->getContext(); | ||||||||
204 | for (auto &ProbeSec : MCProbeDivisions) { | ||||||||
205 | const auto *FuncSym = ProbeSec.first; | ||||||||
206 | const auto &Root = ProbeSec.second; | ||||||||
207 | if (auto *S = Ctx.getObjectFileInfo()->getPseudoProbeSection( | ||||||||
208 | FuncSym->getSection())) { | ||||||||
209 | // Switch to the .pseudoprobe section or a comdat group. | ||||||||
210 | MCOS->switchSection(S); | ||||||||
211 | // Emit probes grouped by GUID. | ||||||||
212 | // Emit sorted descendant. InlineSite is unique for each pair, so there | ||||||||
213 | // will be no ordering of Inlinee based on MCPseudoProbeInlineTree* | ||||||||
214 | using InlineeType = std::pair<InlineSite, MCPseudoProbeInlineTree *>; | ||||||||
215 | auto Comparer = [](const InlineeType &A, const InlineeType &B) { | ||||||||
216 | return A.first < B.first; | ||||||||
217 | }; | ||||||||
218 | std::vector<InlineeType> Inlinees; | ||||||||
219 | for (const auto &Child : Root.getChildren()) | ||||||||
220 | Inlinees.emplace_back(Child.first, Child.second.get()); | ||||||||
221 | std::sort(Inlinees.begin(), Inlinees.end(), Comparer); | ||||||||
222 | |||||||||
223 | for (const auto &Inlinee : Inlinees) { | ||||||||
224 | // Emit the group guarded by a sentinel probe. | ||||||||
225 | MCPseudoProbe SentinelProbe(const_cast<MCSymbol *>(FuncSym), | ||||||||
226 | MD5Hash(FuncSym->getName()), | ||||||||
227 | (uint32_t)PseudoProbeReservedId::Invalid, | ||||||||
228 | (uint32_t)PseudoProbeType::Block, | ||||||||
229 | (uint32_t)PseudoProbeAttributes::Sentinel); | ||||||||
230 | const MCPseudoProbe *Probe = &SentinelProbe; | ||||||||
231 | Inlinee.second->emit(MCOS, Probe); | ||||||||
232 | } | ||||||||
233 | } | ||||||||
234 | } | ||||||||
235 | } | ||||||||
236 | |||||||||
237 | // | ||||||||
238 | // This emits the pseudo probe tables. | ||||||||
239 | // | ||||||||
240 | void MCPseudoProbeTable::emit(MCObjectStreamer *MCOS) { | ||||||||
241 | MCContext &Ctx = MCOS->getContext(); | ||||||||
242 | auto &ProbeTable = Ctx.getMCPseudoProbeTable(); | ||||||||
243 | |||||||||
244 | // Bail out early so we don't switch to the pseudo_probe section needlessly | ||||||||
245 | // and in doing so create an unnecessary (if empty) section. | ||||||||
246 | auto &ProbeSections = ProbeTable.getProbeSections(); | ||||||||
247 | if (ProbeSections.empty()) | ||||||||
248 | return; | ||||||||
249 | |||||||||
250 | LLVM_DEBUG(MCPseudoProbeTable::DdgPrintIndent = 0)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("mcpseudoprobe")) { MCPseudoProbeTable::DdgPrintIndent = 0; } } while (false); | ||||||||
251 | |||||||||
252 | // Put out the probe. | ||||||||
253 | ProbeSections.emit(MCOS); | ||||||||
254 | } | ||||||||
255 | |||||||||
256 | static StringRef getProbeFNameForGUID(const GUIDProbeFunctionMap &GUID2FuncMAP, | ||||||||
257 | uint64_t GUID) { | ||||||||
258 | auto It = GUID2FuncMAP.find(GUID); | ||||||||
259 | assert(It != GUID2FuncMAP.end() &&(static_cast <bool> (It != GUID2FuncMAP.end() && "Probe function must exist for a valid GUID") ? void (0) : __assert_fail ("It != GUID2FuncMAP.end() && \"Probe function must exist for a valid GUID\"" , "llvm/lib/MC/MCPseudoProbe.cpp", 260, __extension__ __PRETTY_FUNCTION__ )) | ||||||||
260 | "Probe function must exist for a valid GUID")(static_cast <bool> (It != GUID2FuncMAP.end() && "Probe function must exist for a valid GUID") ? void (0) : __assert_fail ("It != GUID2FuncMAP.end() && \"Probe function must exist for a valid GUID\"" , "llvm/lib/MC/MCPseudoProbe.cpp", 260, __extension__ __PRETTY_FUNCTION__ )); | ||||||||
261 | return It->second.FuncName; | ||||||||
262 | } | ||||||||
263 | |||||||||
264 | void MCPseudoProbeFuncDesc::print(raw_ostream &OS) { | ||||||||
265 | OS << "GUID: " << FuncGUID << " Name: " << FuncName << "\n"; | ||||||||
266 | OS << "Hash: " << FuncHash << "\n"; | ||||||||
267 | } | ||||||||
268 | |||||||||
269 | void MCDecodedPseudoProbe::getInlineContext( | ||||||||
270 | SmallVectorImpl<MCPseduoProbeFrameLocation> &ContextStack, | ||||||||
271 | const GUIDProbeFunctionMap &GUID2FuncMAP) const { | ||||||||
272 | uint32_t Begin = ContextStack.size(); | ||||||||
273 | MCDecodedPseudoProbeInlineTree *Cur = InlineTree; | ||||||||
274 | // It will add the string of each node's inline site during iteration. | ||||||||
275 | // Note that it won't include the probe's belonging function(leaf location) | ||||||||
276 | while (Cur->hasInlineSite()) { | ||||||||
277 | StringRef FuncName = getProbeFNameForGUID(GUID2FuncMAP, Cur->Parent->Guid); | ||||||||
278 | ContextStack.emplace_back( | ||||||||
279 | MCPseduoProbeFrameLocation(FuncName, std::get<1>(Cur->ISite))); | ||||||||
280 | Cur = static_cast<MCDecodedPseudoProbeInlineTree *>(Cur->Parent); | ||||||||
281 | } | ||||||||
282 | // Make the ContextStack in caller-callee order | ||||||||
283 | std::reverse(ContextStack.begin() + Begin, ContextStack.end()); | ||||||||
284 | } | ||||||||
285 | |||||||||
286 | std::string MCDecodedPseudoProbe::getInlineContextStr( | ||||||||
287 | const GUIDProbeFunctionMap &GUID2FuncMAP) const { | ||||||||
288 | std::ostringstream OContextStr; | ||||||||
289 | SmallVector<MCPseduoProbeFrameLocation, 16> ContextStack; | ||||||||
290 | getInlineContext(ContextStack, GUID2FuncMAP); | ||||||||
291 | for (auto &Cxt : ContextStack) { | ||||||||
292 | if (OContextStr.str().size()) | ||||||||
293 | OContextStr << " @ "; | ||||||||
294 | OContextStr << Cxt.first.str() << ":" << Cxt.second; | ||||||||
295 | } | ||||||||
296 | return OContextStr.str(); | ||||||||
297 | } | ||||||||
298 | |||||||||
299 | static const char *PseudoProbeTypeStr[3] = {"Block", "IndirectCall", | ||||||||
300 | "DirectCall"}; | ||||||||
301 | |||||||||
302 | void MCDecodedPseudoProbe::print(raw_ostream &OS, | ||||||||
303 | const GUIDProbeFunctionMap &GUID2FuncMAP, | ||||||||
304 | bool ShowName) const { | ||||||||
305 | OS << "FUNC: "; | ||||||||
306 | if (ShowName) { | ||||||||
307 | StringRef FuncName = getProbeFNameForGUID(GUID2FuncMAP, Guid); | ||||||||
308 | OS << FuncName.str() << " "; | ||||||||
309 | } else { | ||||||||
310 | OS << Guid << " "; | ||||||||
311 | } | ||||||||
312 | OS << "Index: " << Index << " "; | ||||||||
313 | OS << "Type: " << PseudoProbeTypeStr[static_cast<uint8_t>(Type)] << " "; | ||||||||
314 | std::string InlineContextStr = getInlineContextStr(GUID2FuncMAP); | ||||||||
315 | if (InlineContextStr.size()) { | ||||||||
316 | OS << "Inlined: @ "; | ||||||||
317 | OS << InlineContextStr; | ||||||||
318 | } | ||||||||
319 | OS << "\n"; | ||||||||
320 | } | ||||||||
321 | |||||||||
322 | template <typename T> ErrorOr<T> MCPseudoProbeDecoder::readUnencodedNumber() { | ||||||||
323 | if (Data + sizeof(T) > End) { | ||||||||
324 | return std::error_code(); | ||||||||
325 | } | ||||||||
326 | T Val = endian::readNext<T, little, unaligned>(Data); | ||||||||
327 | return ErrorOr<T>(Val); | ||||||||
328 | } | ||||||||
329 | |||||||||
330 | template <typename T> ErrorOr<T> MCPseudoProbeDecoder::readUnsignedNumber() { | ||||||||
331 | unsigned NumBytesRead = 0; | ||||||||
332 | uint64_t Val = decodeULEB128(Data, &NumBytesRead); | ||||||||
333 | if (Val > std::numeric_limits<T>::max() || (Data + NumBytesRead > End)) { | ||||||||
334 | return std::error_code(); | ||||||||
335 | } | ||||||||
336 | Data += NumBytesRead; | ||||||||
337 | return ErrorOr<T>(static_cast<T>(Val)); | ||||||||
338 | } | ||||||||
339 | |||||||||
340 | template <typename T> ErrorOr<T> MCPseudoProbeDecoder::readSignedNumber() { | ||||||||
341 | unsigned NumBytesRead = 0; | ||||||||
342 | int64_t Val = decodeSLEB128(Data, &NumBytesRead); | ||||||||
343 | if (Val > std::numeric_limits<T>::max() || (Data + NumBytesRead > End)) { | ||||||||
344 | return std::error_code(); | ||||||||
345 | } | ||||||||
346 | Data += NumBytesRead; | ||||||||
347 | return ErrorOr<T>(static_cast<T>(Val)); | ||||||||
348 | } | ||||||||
349 | |||||||||
350 | ErrorOr<StringRef> MCPseudoProbeDecoder::readString(uint32_t Size) { | ||||||||
351 | StringRef Str(reinterpret_cast<const char *>(Data), Size); | ||||||||
352 | if (Data + Size > End) { | ||||||||
353 | return std::error_code(); | ||||||||
354 | } | ||||||||
355 | Data += Size; | ||||||||
356 | return ErrorOr<StringRef>(Str); | ||||||||
357 | } | ||||||||
358 | |||||||||
359 | bool MCPseudoProbeDecoder::buildGUID2FuncDescMap(const uint8_t *Start, | ||||||||
360 | std::size_t Size) { | ||||||||
361 | // The pseudo_probe_desc section has a format like: | ||||||||
362 | // .section .pseudo_probe_desc,"",@progbits | ||||||||
363 | // .quad -5182264717993193164 // GUID | ||||||||
364 | // .quad 4294967295 // Hash | ||||||||
365 | // .uleb 3 // Name size | ||||||||
366 | // .ascii "foo" // Name | ||||||||
367 | // .quad -2624081020897602054 | ||||||||
368 | // .quad 174696971957 | ||||||||
369 | // .uleb 34 | ||||||||
370 | // .ascii "main" | ||||||||
371 | |||||||||
372 | Data = Start; | ||||||||
373 | End = Data + Size; | ||||||||
374 | |||||||||
375 | while (Data < End) { | ||||||||
376 | auto ErrorOrGUID = readUnencodedNumber<uint64_t>(); | ||||||||
377 | if (!ErrorOrGUID) | ||||||||
378 | return false; | ||||||||
379 | |||||||||
380 | auto ErrorOrHash = readUnencodedNumber<uint64_t>(); | ||||||||
381 | if (!ErrorOrHash) | ||||||||
382 | return false; | ||||||||
383 | |||||||||
384 | auto ErrorOrNameSize = readUnsignedNumber<uint32_t>(); | ||||||||
385 | if (!ErrorOrNameSize) | ||||||||
386 | return false; | ||||||||
387 | uint32_t NameSize = std::move(*ErrorOrNameSize); | ||||||||
388 | |||||||||
389 | auto ErrorOrName = readString(NameSize); | ||||||||
390 | if (!ErrorOrName) | ||||||||
391 | return false; | ||||||||
392 | |||||||||
393 | uint64_t GUID = std::move(*ErrorOrGUID); | ||||||||
394 | uint64_t Hash = std::move(*ErrorOrHash); | ||||||||
395 | StringRef Name = std::move(*ErrorOrName); | ||||||||
396 | |||||||||
397 | // Initialize PseudoProbeFuncDesc and populate it into GUID2FuncDescMap | ||||||||
398 | GUID2FuncDescMap.emplace(GUID, MCPseudoProbeFuncDesc(GUID, Hash, Name)); | ||||||||
399 | } | ||||||||
400 | assert(Data == End && "Have unprocessed data in pseudo_probe_desc section")(static_cast <bool> (Data == End && "Have unprocessed data in pseudo_probe_desc section" ) ? void (0) : __assert_fail ("Data == End && \"Have unprocessed data in pseudo_probe_desc section\"" , "llvm/lib/MC/MCPseudoProbe.cpp", 400, __extension__ __PRETTY_FUNCTION__ )); | ||||||||
401 | return true; | ||||||||
402 | } | ||||||||
403 | |||||||||
404 | bool MCPseudoProbeDecoder::buildAddress2ProbeMap( | ||||||||
405 | MCDecodedPseudoProbeInlineTree *Cur, uint64_t &LastAddr, | ||||||||
406 | const Uint64Set &GuidFilter, const Uint64Map &FuncStartAddrs) { | ||||||||
407 | // The pseudo_probe section encodes an inline forest and each tree has a | ||||||||
408 | // format defined in MCPseudoProbe.h | ||||||||
409 | |||||||||
410 | uint32_t Index = 0; | ||||||||
411 | bool IsTopLevelFunc = Cur == &DummyInlineRoot; | ||||||||
412 | if (IsTopLevelFunc
| ||||||||
413 | // Use a sequential id for top level inliner. | ||||||||
414 | Index = Cur->getChildren().size(); | ||||||||
415 | } else { | ||||||||
416 | // Read inline site for inlinees | ||||||||
417 | auto ErrorOrIndex = readUnsignedNumber<uint32_t>(); | ||||||||
418 | if (!ErrorOrIndex) | ||||||||
419 | return false; | ||||||||
420 | Index = std::move(*ErrorOrIndex); | ||||||||
421 | } | ||||||||
422 | |||||||||
423 | // Read guid | ||||||||
424 | auto ErrorOrCurGuid = readUnencodedNumber<uint64_t>(); | ||||||||
425 | if (!ErrorOrCurGuid) | ||||||||
426 | return false; | ||||||||
427 | uint64_t Guid = std::move(*ErrorOrCurGuid); | ||||||||
428 | |||||||||
429 | // Decide if top-level node should be disgarded. | ||||||||
430 | if (IsTopLevelFunc
| ||||||||
431 | Cur = nullptr; | ||||||||
432 | |||||||||
433 | // If the incoming node is null, all its children nodes should be disgarded. | ||||||||
434 | if (Cur
| ||||||||
435 | // Switch/add to a new tree node(inlinee) | ||||||||
436 | Cur = Cur->getOrAddNode(std::make_tuple(Guid, Index)); | ||||||||
437 | Cur->Guid = Guid; | ||||||||
438 | if (IsTopLevelFunc
| ||||||||
439 | if (auto V = FuncStartAddrs.lookup(Guid)) | ||||||||
440 | LastAddr = V; | ||||||||
441 | } | ||||||||
442 | } | ||||||||
443 | |||||||||
444 | // Read number of probes in the current node. | ||||||||
445 | auto ErrorOrNodeCount = readUnsignedNumber<uint32_t>(); | ||||||||
446 | if (!ErrorOrNodeCount) | ||||||||
447 | return false; | ||||||||
448 | uint32_t NodeCount = std::move(*ErrorOrNodeCount); | ||||||||
449 | // Read number of direct inlinees | ||||||||
450 | auto ErrorOrCurChildrenToProcess = readUnsignedNumber<uint32_t>(); | ||||||||
451 | if (!ErrorOrCurChildrenToProcess) | ||||||||
452 | return false; | ||||||||
453 | // Read all probes in this node | ||||||||
454 | for (std::size_t I = 0; I < NodeCount; I++) { | ||||||||
455 | // Read index | ||||||||
456 | auto ErrorOrIndex = readUnsignedNumber<uint32_t>(); | ||||||||
457 | if (!ErrorOrIndex) | ||||||||
458 | return false; | ||||||||
459 | uint32_t Index = std::move(*ErrorOrIndex); | ||||||||
460 | // Read type | flag. | ||||||||
461 | auto ErrorOrValue = readUnencodedNumber<uint8_t>(); | ||||||||
462 | if (!ErrorOrValue) | ||||||||
463 | return false; | ||||||||
464 | uint8_t Value = std::move(*ErrorOrValue); | ||||||||
465 | uint8_t Kind = Value & 0xf; | ||||||||
466 | uint8_t Attr = (Value & 0x70) >> 4; | ||||||||
467 | // Read address | ||||||||
468 | uint64_t Addr = 0; | ||||||||
469 | if (Value & 0x80) { | ||||||||
470 | auto ErrorOrOffset = readSignedNumber<int64_t>(); | ||||||||
471 | if (!ErrorOrOffset) | ||||||||
472 | return false; | ||||||||
473 | int64_t Offset = std::move(*ErrorOrOffset); | ||||||||
474 | Addr = LastAddr + Offset; | ||||||||
475 | } else { | ||||||||
476 | auto ErrorOrAddr = readUnencodedNumber<int64_t>(); | ||||||||
477 | if (!ErrorOrAddr) | ||||||||
478 | return false; | ||||||||
479 | Addr = std::move(*ErrorOrAddr); | ||||||||
480 | if (isSentinelProbe(Attr)) { | ||||||||
481 | // For sentinel probe, the addr field actually stores the GUID of the | ||||||||
482 | // split function. Convert it to the real address. | ||||||||
483 | if (auto V = FuncStartAddrs.lookup(Addr)) | ||||||||
484 | Addr = V; | ||||||||
485 | } else { | ||||||||
486 | // For now we assume all probe encoding should be either based on | ||||||||
487 | // leading probe address or function start address. | ||||||||
488 | // The scheme is for downwards compatibility. | ||||||||
489 | // TODO: retire this scheme once compatibility is no longer an issue. | ||||||||
490 | EncodingIsAddrBased = true; | ||||||||
491 | } | ||||||||
492 | } | ||||||||
493 | |||||||||
494 | if (Cur && !isSentinelProbe(Attr)) { | ||||||||
495 | // Populate Address2ProbesMap | ||||||||
496 | auto &Probes = Address2ProbesMap[Addr]; | ||||||||
497 | Probes.emplace_back(Addr, Cur->Guid, Index, PseudoProbeType(Kind), Attr, | ||||||||
498 | Cur); | ||||||||
499 | Cur->addProbes(&Probes.back()); | ||||||||
500 | } | ||||||||
501 | LastAddr = Addr; | ||||||||
502 | } | ||||||||
503 | |||||||||
504 | uint32_t ChildrenToProcess = std::move(*ErrorOrCurChildrenToProcess); | ||||||||
505 | for (uint32_t I = 0; I < ChildrenToProcess; I++) { | ||||||||
506 | buildAddress2ProbeMap(Cur, LastAddr, GuidFilter, FuncStartAddrs); | ||||||||
507 | } | ||||||||
508 | |||||||||
509 | return true; | ||||||||
510 | } | ||||||||
511 | |||||||||
512 | bool MCPseudoProbeDecoder::buildAddress2ProbeMap( | ||||||||
513 | const uint8_t *Start, std::size_t Size, const Uint64Set &GuidFilter, | ||||||||
514 | const Uint64Map &FuncStartAddrs) { | ||||||||
515 | Data = Start; | ||||||||
516 | End = Data + Size; | ||||||||
517 | uint64_t LastAddr = 0; | ||||||||
518 | while (Data < End) | ||||||||
| |||||||||
519 | buildAddress2ProbeMap(&DummyInlineRoot, LastAddr, GuidFilter, | ||||||||
520 | FuncStartAddrs); | ||||||||
521 | assert(Data == End && "Have unprocessed data in pseudo_probe section")(static_cast <bool> (Data == End && "Have unprocessed data in pseudo_probe section" ) ? void (0) : __assert_fail ("Data == End && \"Have unprocessed data in pseudo_probe section\"" , "llvm/lib/MC/MCPseudoProbe.cpp", 521, __extension__ __PRETTY_FUNCTION__ )); | ||||||||
522 | return true; | ||||||||
523 | } | ||||||||
524 | |||||||||
525 | void MCPseudoProbeDecoder::printGUID2FuncDescMap(raw_ostream &OS) { | ||||||||
526 | OS << "Pseudo Probe Desc:\n"; | ||||||||
527 | // Make the output deterministic | ||||||||
528 | std::map<uint64_t, MCPseudoProbeFuncDesc> OrderedMap(GUID2FuncDescMap.begin(), | ||||||||
529 | GUID2FuncDescMap.end()); | ||||||||
530 | for (auto &I : OrderedMap) { | ||||||||
531 | I.second.print(OS); | ||||||||
532 | } | ||||||||
533 | } | ||||||||
534 | |||||||||
535 | void MCPseudoProbeDecoder::printProbeForAddress(raw_ostream &OS, | ||||||||
536 | uint64_t Address) { | ||||||||
537 | auto It = Address2ProbesMap.find(Address); | ||||||||
538 | if (It != Address2ProbesMap.end()) { | ||||||||
539 | for (auto &Probe : It->second) { | ||||||||
540 | OS << " [Probe]:\t"; | ||||||||
541 | Probe.print(OS, GUID2FuncDescMap, true); | ||||||||
542 | } | ||||||||
543 | } | ||||||||
544 | } | ||||||||
545 | |||||||||
546 | void MCPseudoProbeDecoder::printProbesForAllAddresses(raw_ostream &OS) { | ||||||||
547 | std::vector<uint64_t> Addresses; | ||||||||
548 | for (auto Entry : Address2ProbesMap) | ||||||||
549 | Addresses.push_back(Entry.first); | ||||||||
550 | llvm::sort(Addresses); | ||||||||
551 | for (auto K : Addresses) { | ||||||||
552 | OS << "Address:\t"; | ||||||||
553 | OS << K; | ||||||||
554 | OS << "\n"; | ||||||||
555 | printProbeForAddress(OS, K); | ||||||||
556 | } | ||||||||
557 | } | ||||||||
558 | |||||||||
559 | const MCDecodedPseudoProbe * | ||||||||
560 | MCPseudoProbeDecoder::getCallProbeForAddr(uint64_t Address) const { | ||||||||
561 | auto It = Address2ProbesMap.find(Address); | ||||||||
562 | if (It == Address2ProbesMap.end()) | ||||||||
563 | return nullptr; | ||||||||
564 | const auto &Probes = It->second; | ||||||||
565 | |||||||||
566 | const MCDecodedPseudoProbe *CallProbe = nullptr; | ||||||||
567 | for (const auto &Probe : Probes) { | ||||||||
568 | if (Probe.isCall()) { | ||||||||
569 | assert(!CallProbe &&(static_cast <bool> (!CallProbe && "There should be only one call probe corresponding to address " "which is a callsite.") ? void (0) : __assert_fail ("!CallProbe && \"There should be only one call probe corresponding to address \" \"which is a callsite.\"" , "llvm/lib/MC/MCPseudoProbe.cpp", 571, __extension__ __PRETTY_FUNCTION__ )) | ||||||||
570 | "There should be only one call probe corresponding to address "(static_cast <bool> (!CallProbe && "There should be only one call probe corresponding to address " "which is a callsite.") ? void (0) : __assert_fail ("!CallProbe && \"There should be only one call probe corresponding to address \" \"which is a callsite.\"" , "llvm/lib/MC/MCPseudoProbe.cpp", 571, __extension__ __PRETTY_FUNCTION__ )) | ||||||||
571 | "which is a callsite.")(static_cast <bool> (!CallProbe && "There should be only one call probe corresponding to address " "which is a callsite.") ? void (0) : __assert_fail ("!CallProbe && \"There should be only one call probe corresponding to address \" \"which is a callsite.\"" , "llvm/lib/MC/MCPseudoProbe.cpp", 571, __extension__ __PRETTY_FUNCTION__ )); | ||||||||
572 | CallProbe = &Probe; | ||||||||
573 | } | ||||||||
574 | } | ||||||||
575 | return CallProbe; | ||||||||
576 | } | ||||||||
577 | |||||||||
578 | const MCPseudoProbeFuncDesc * | ||||||||
579 | MCPseudoProbeDecoder::getFuncDescForGUID(uint64_t GUID) const { | ||||||||
580 | auto It = GUID2FuncDescMap.find(GUID); | ||||||||
581 | assert(It != GUID2FuncDescMap.end() && "Function descriptor doesn't exist")(static_cast <bool> (It != GUID2FuncDescMap.end() && "Function descriptor doesn't exist") ? void (0) : __assert_fail ("It != GUID2FuncDescMap.end() && \"Function descriptor doesn't exist\"" , "llvm/lib/MC/MCPseudoProbe.cpp", 581, __extension__ __PRETTY_FUNCTION__ )); | ||||||||
582 | return &It->second; | ||||||||
583 | } | ||||||||
584 | |||||||||
585 | void MCPseudoProbeDecoder::getInlineContextForProbe( | ||||||||
586 | const MCDecodedPseudoProbe *Probe, | ||||||||
587 | SmallVectorImpl<MCPseduoProbeFrameLocation> &InlineContextStack, | ||||||||
588 | bool IncludeLeaf) const { | ||||||||
589 | Probe->getInlineContext(InlineContextStack, GUID2FuncDescMap); | ||||||||
590 | if (!IncludeLeaf) | ||||||||
591 | return; | ||||||||
592 | // Note that the context from probe doesn't include leaf frame, | ||||||||
593 | // hence we need to retrieve and prepend leaf if requested. | ||||||||
594 | const auto *FuncDesc = getFuncDescForGUID(Probe->getGuid()); | ||||||||
595 | InlineContextStack.emplace_back( | ||||||||
596 | MCPseduoProbeFrameLocation(FuncDesc->FuncName, Probe->getIndex())); | ||||||||
597 | } | ||||||||
598 | |||||||||
599 | const MCPseudoProbeFuncDesc *MCPseudoProbeDecoder::getInlinerDescForProbe( | ||||||||
600 | const MCDecodedPseudoProbe *Probe) const { | ||||||||
601 | MCDecodedPseudoProbeInlineTree *InlinerNode = Probe->getInlineTreeNode(); | ||||||||
602 | if (!InlinerNode->hasInlineSite()) | ||||||||
603 | return nullptr; | ||||||||
604 | return getFuncDescForGUID(InlinerNode->Parent->Guid); | ||||||||
605 | } |
1 | //===- Endian.h - Utilities for IO with endian specific data ----*- C++ -*-===// | |||
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 | // This file declares generic functions to read and write endian specific data. | |||
10 | // | |||
11 | //===----------------------------------------------------------------------===// | |||
12 | ||||
13 | #ifndef LLVM_SUPPORT_ENDIAN_H | |||
14 | #define LLVM_SUPPORT_ENDIAN_H | |||
15 | ||||
16 | #include "llvm/Support/Compiler.h" | |||
17 | #include "llvm/Support/SwapByteOrder.h" | |||
18 | #include <cassert> | |||
19 | #include <cstddef> | |||
20 | #include <cstdint> | |||
21 | #include <cstring> | |||
22 | #include <type_traits> | |||
23 | ||||
24 | namespace llvm { | |||
25 | namespace support { | |||
26 | ||||
27 | enum endianness {big, little, native}; | |||
28 | ||||
29 | // These are named values for common alignments. | |||
30 | enum {aligned = 0, unaligned = 1}; | |||
31 | ||||
32 | namespace detail { | |||
33 | ||||
34 | /// ::value is either alignment, or alignof(T) if alignment is 0. | |||
35 | template<class T, int alignment> | |||
36 | struct PickAlignment { | |||
37 | enum { value = alignment == 0 ? alignof(T) : alignment }; | |||
38 | }; | |||
39 | ||||
40 | } // end namespace detail | |||
41 | ||||
42 | namespace endian { | |||
43 | ||||
44 | constexpr endianness system_endianness() { | |||
45 | return sys::IsBigEndianHost ? big : little; | |||
46 | } | |||
47 | ||||
48 | template <typename value_type> | |||
49 | inline value_type byte_swap(value_type value, endianness endian) { | |||
50 | if ((endian != native) && (endian != system_endianness())) | |||
51 | sys::swapByteOrder(value); | |||
52 | return value; | |||
53 | } | |||
54 | ||||
55 | /// Swap the bytes of value to match the given endianness. | |||
56 | template<typename value_type, endianness endian> | |||
57 | inline value_type byte_swap(value_type value) { | |||
58 | return byte_swap(value, endian); | |||
59 | } | |||
60 | ||||
61 | /// Read a value of a particular endianness from memory. | |||
62 | template <typename value_type, std::size_t alignment> | |||
63 | inline value_type read(const void *memory, endianness endian) { | |||
64 | value_type ret; | |||
65 | ||||
66 | memcpy(&ret, | |||
| ||||
67 | LLVM_ASSUME_ALIGNED(__builtin_assume_aligned(memory, (detail::PickAlignment<value_type , alignment>::value)) | |||
68 | memory, (detail::PickAlignment<value_type, alignment>::value))__builtin_assume_aligned(memory, (detail::PickAlignment<value_type , alignment>::value)), | |||
69 | sizeof(value_type)); | |||
70 | return byte_swap<value_type>(ret, endian); | |||
71 | } | |||
72 | ||||
73 | template<typename value_type, | |||
74 | endianness endian, | |||
75 | std::size_t alignment> | |||
76 | inline value_type read(const void *memory) { | |||
77 | return read<value_type, alignment>(memory, endian); | |||
78 | } | |||
79 | ||||
80 | /// Read a value of a particular endianness from a buffer, and increment the | |||
81 | /// buffer past that value. | |||
82 | template <typename value_type, std::size_t alignment, typename CharT> | |||
83 | inline value_type readNext(const CharT *&memory, endianness endian) { | |||
84 | value_type ret = read<value_type, alignment>(memory, endian); | |||
85 | memory += sizeof(value_type); | |||
86 | return ret; | |||
87 | } | |||
88 | ||||
89 | template<typename value_type, endianness endian, std::size_t alignment, | |||
90 | typename CharT> | |||
91 | inline value_type readNext(const CharT *&memory) { | |||
92 | return readNext<value_type, alignment, CharT>(memory, endian); | |||
93 | } | |||
94 | ||||
95 | /// Write a value to memory with a particular endianness. | |||
96 | template <typename value_type, std::size_t alignment> | |||
97 | inline void write(void *memory, value_type value, endianness endian) { | |||
98 | value = byte_swap<value_type>(value, endian); | |||
99 | memcpy(LLVM_ASSUME_ALIGNED(__builtin_assume_aligned(memory, (detail::PickAlignment<value_type , alignment>::value)) | |||
100 | memory, (detail::PickAlignment<value_type, alignment>::value))__builtin_assume_aligned(memory, (detail::PickAlignment<value_type , alignment>::value)), | |||
101 | &value, sizeof(value_type)); | |||
102 | } | |||
103 | ||||
104 | template<typename value_type, | |||
105 | endianness endian, | |||
106 | std::size_t alignment> | |||
107 | inline void write(void *memory, value_type value) { | |||
108 | write<value_type, alignment>(memory, value, endian); | |||
109 | } | |||
110 | ||||
111 | template <typename value_type> | |||
112 | using make_unsigned_t = std::make_unsigned_t<value_type>; | |||
113 | ||||
114 | /// Read a value of a particular endianness from memory, for a location | |||
115 | /// that starts at the given bit offset within the first byte. | |||
116 | template <typename value_type, endianness endian, std::size_t alignment> | |||
117 | inline value_type readAtBitAlignment(const void *memory, uint64_t startBit) { | |||
118 | assert(startBit < 8)(static_cast <bool> (startBit < 8) ? void (0) : __assert_fail ("startBit < 8", "llvm/include/llvm/Support/Endian.h", 118 , __extension__ __PRETTY_FUNCTION__)); | |||
119 | if (startBit == 0) | |||
120 | return read<value_type, endian, alignment>(memory); | |||
121 | else { | |||
122 | // Read two values and compose the result from them. | |||
123 | value_type val[2]; | |||
124 | memcpy(&val[0], | |||
125 | LLVM_ASSUME_ALIGNED(__builtin_assume_aligned(memory, (detail::PickAlignment<value_type , alignment>::value)) | |||
126 | memory, (detail::PickAlignment<value_type, alignment>::value))__builtin_assume_aligned(memory, (detail::PickAlignment<value_type , alignment>::value)), | |||
127 | sizeof(value_type) * 2); | |||
128 | val[0] = byte_swap<value_type, endian>(val[0]); | |||
129 | val[1] = byte_swap<value_type, endian>(val[1]); | |||
130 | ||||
131 | // Shift bits from the lower value into place. | |||
132 | make_unsigned_t<value_type> lowerVal = val[0] >> startBit; | |||
133 | // Mask off upper bits after right shift in case of signed type. | |||
134 | make_unsigned_t<value_type> numBitsFirstVal = | |||
135 | (sizeof(value_type) * 8) - startBit; | |||
136 | lowerVal &= ((make_unsigned_t<value_type>)1 << numBitsFirstVal) - 1; | |||
137 | ||||
138 | // Get the bits from the upper value. | |||
139 | make_unsigned_t<value_type> upperVal = | |||
140 | val[1] & (((make_unsigned_t<value_type>)1 << startBit) - 1); | |||
141 | // Shift them in to place. | |||
142 | upperVal <<= numBitsFirstVal; | |||
143 | ||||
144 | return lowerVal | upperVal; | |||
145 | } | |||
146 | } | |||
147 | ||||
148 | /// Write a value to memory with a particular endianness, for a location | |||
149 | /// that starts at the given bit offset within the first byte. | |||
150 | template <typename value_type, endianness endian, std::size_t alignment> | |||
151 | inline void writeAtBitAlignment(void *memory, value_type value, | |||
152 | uint64_t startBit) { | |||
153 | assert(startBit < 8)(static_cast <bool> (startBit < 8) ? void (0) : __assert_fail ("startBit < 8", "llvm/include/llvm/Support/Endian.h", 153 , __extension__ __PRETTY_FUNCTION__)); | |||
154 | if (startBit == 0) | |||
155 | write<value_type, endian, alignment>(memory, value); | |||
156 | else { | |||
157 | // Read two values and shift the result into them. | |||
158 | value_type val[2]; | |||
159 | memcpy(&val[0], | |||
160 | LLVM_ASSUME_ALIGNED(__builtin_assume_aligned(memory, (detail::PickAlignment<value_type , alignment>::value)) | |||
161 | memory, (detail::PickAlignment<value_type, alignment>::value))__builtin_assume_aligned(memory, (detail::PickAlignment<value_type , alignment>::value)), | |||
162 | sizeof(value_type) * 2); | |||
163 | val[0] = byte_swap<value_type, endian>(val[0]); | |||
164 | val[1] = byte_swap<value_type, endian>(val[1]); | |||
165 | ||||
166 | // Mask off any existing bits in the upper part of the lower value that | |||
167 | // we want to replace. | |||
168 | val[0] &= ((make_unsigned_t<value_type>)1 << startBit) - 1; | |||
169 | make_unsigned_t<value_type> numBitsFirstVal = | |||
170 | (sizeof(value_type) * 8) - startBit; | |||
171 | make_unsigned_t<value_type> lowerVal = value; | |||
172 | if (startBit > 0) { | |||
173 | // Mask off the upper bits in the new value that are not going to go into | |||
174 | // the lower value. This avoids a left shift of a negative value, which | |||
175 | // is undefined behavior. | |||
176 | lowerVal &= (((make_unsigned_t<value_type>)1 << numBitsFirstVal) - 1); | |||
177 | // Now shift the new bits into place | |||
178 | lowerVal <<= startBit; | |||
179 | } | |||
180 | val[0] |= lowerVal; | |||
181 | ||||
182 | // Mask off any existing bits in the lower part of the upper value that | |||
183 | // we want to replace. | |||
184 | val[1] &= ~(((make_unsigned_t<value_type>)1 << startBit) - 1); | |||
185 | // Next shift the bits that go into the upper value into position. | |||
186 | make_unsigned_t<value_type> upperVal = value >> numBitsFirstVal; | |||
187 | // Mask off upper bits after right shift in case of signed type. | |||
188 | upperVal &= ((make_unsigned_t<value_type>)1 << startBit) - 1; | |||
189 | val[1] |= upperVal; | |||
190 | ||||
191 | // Finally, rewrite values. | |||
192 | val[0] = byte_swap<value_type, endian>(val[0]); | |||
193 | val[1] = byte_swap<value_type, endian>(val[1]); | |||
194 | memcpy(LLVM_ASSUME_ALIGNED(__builtin_assume_aligned(memory, (detail::PickAlignment<value_type , alignment>::value)) | |||
195 | memory, (detail::PickAlignment<value_type, alignment>::value))__builtin_assume_aligned(memory, (detail::PickAlignment<value_type , alignment>::value)), | |||
196 | &val[0], sizeof(value_type) * 2); | |||
197 | } | |||
198 | } | |||
199 | ||||
200 | } // end namespace endian | |||
201 | ||||
202 | namespace detail { | |||
203 | ||||
204 | template <typename ValueType, endianness Endian, std::size_t Alignment, | |||
205 | std::size_t ALIGN = PickAlignment<ValueType, Alignment>::value> | |||
206 | struct packed_endian_specific_integral { | |||
207 | using value_type = ValueType; | |||
208 | static constexpr endianness endian = Endian; | |||
209 | static constexpr std::size_t alignment = Alignment; | |||
210 | ||||
211 | packed_endian_specific_integral() = default; | |||
212 | ||||
213 | explicit packed_endian_specific_integral(value_type val) { *this = val; } | |||
214 | ||||
215 | operator value_type() const { | |||
216 | return endian::read<value_type, endian, alignment>( | |||
217 | (const void*)Value.buffer); | |||
218 | } | |||
219 | ||||
220 | void operator=(value_type newValue) { | |||
221 | endian::write<value_type, endian, alignment>( | |||
222 | (void*)Value.buffer, newValue); | |||
223 | } | |||
224 | ||||
225 | packed_endian_specific_integral &operator+=(value_type newValue) { | |||
226 | *this = *this + newValue; | |||
227 | return *this; | |||
228 | } | |||
229 | ||||
230 | packed_endian_specific_integral &operator-=(value_type newValue) { | |||
231 | *this = *this - newValue; | |||
232 | return *this; | |||
233 | } | |||
234 | ||||
235 | packed_endian_specific_integral &operator|=(value_type newValue) { | |||
236 | *this = *this | newValue; | |||
237 | return *this; | |||
238 | } | |||
239 | ||||
240 | packed_endian_specific_integral &operator&=(value_type newValue) { | |||
241 | *this = *this & newValue; | |||
242 | return *this; | |||
243 | } | |||
244 | ||||
245 | private: | |||
246 | struct { | |||
247 | alignas(ALIGN) char buffer[sizeof(value_type)]; | |||
248 | } Value; | |||
249 | ||||
250 | public: | |||
251 | struct ref { | |||
252 | explicit ref(void *Ptr) : Ptr(Ptr) {} | |||
253 | ||||
254 | operator value_type() const { | |||
255 | return endian::read<value_type, endian, alignment>(Ptr); | |||
256 | } | |||
257 | ||||
258 | void operator=(value_type NewValue) { | |||
259 | endian::write<value_type, endian, alignment>(Ptr, NewValue); | |||
260 | } | |||
261 | ||||
262 | private: | |||
263 | void *Ptr; | |||
264 | }; | |||
265 | }; | |||
266 | ||||
267 | } // end namespace detail | |||
268 | ||||
269 | using ulittle16_t = | |||
270 | detail::packed_endian_specific_integral<uint16_t, little, unaligned>; | |||
271 | using ulittle32_t = | |||
272 | detail::packed_endian_specific_integral<uint32_t, little, unaligned>; | |||
273 | using ulittle64_t = | |||
274 | detail::packed_endian_specific_integral<uint64_t, little, unaligned>; | |||
275 | ||||
276 | using little16_t = | |||
277 | detail::packed_endian_specific_integral<int16_t, little, unaligned>; | |||
278 | using little32_t = | |||
279 | detail::packed_endian_specific_integral<int32_t, little, unaligned>; | |||
280 | using little64_t = | |||
281 | detail::packed_endian_specific_integral<int64_t, little, unaligned>; | |||
282 | ||||
283 | using aligned_ulittle16_t = | |||
284 | detail::packed_endian_specific_integral<uint16_t, little, aligned>; | |||
285 | using aligned_ulittle32_t = | |||
286 | detail::packed_endian_specific_integral<uint32_t, little, aligned>; | |||
287 | using aligned_ulittle64_t = | |||
288 | detail::packed_endian_specific_integral<uint64_t, little, aligned>; | |||
289 | ||||
290 | using aligned_little16_t = | |||
291 | detail::packed_endian_specific_integral<int16_t, little, aligned>; | |||
292 | using aligned_little32_t = | |||
293 | detail::packed_endian_specific_integral<int32_t, little, aligned>; | |||
294 | using aligned_little64_t = | |||
295 | detail::packed_endian_specific_integral<int64_t, little, aligned>; | |||
296 | ||||
297 | using ubig16_t = | |||
298 | detail::packed_endian_specific_integral<uint16_t, big, unaligned>; | |||
299 | using ubig32_t = | |||
300 | detail::packed_endian_specific_integral<uint32_t, big, unaligned>; | |||
301 | using ubig64_t = | |||
302 | detail::packed_endian_specific_integral<uint64_t, big, unaligned>; | |||
303 | ||||
304 | using big16_t = | |||
305 | detail::packed_endian_specific_integral<int16_t, big, unaligned>; | |||
306 | using big32_t = | |||
307 | detail::packed_endian_specific_integral<int32_t, big, unaligned>; | |||
308 | using big64_t = | |||
309 | detail::packed_endian_specific_integral<int64_t, big, unaligned>; | |||
310 | ||||
311 | using aligned_ubig16_t = | |||
312 | detail::packed_endian_specific_integral<uint16_t, big, aligned>; | |||
313 | using aligned_ubig32_t = | |||
314 | detail::packed_endian_specific_integral<uint32_t, big, aligned>; | |||
315 | using aligned_ubig64_t = | |||
316 | detail::packed_endian_specific_integral<uint64_t, big, aligned>; | |||
317 | ||||
318 | using aligned_big16_t = | |||
319 | detail::packed_endian_specific_integral<int16_t, big, aligned>; | |||
320 | using aligned_big32_t = | |||
321 | detail::packed_endian_specific_integral<int32_t, big, aligned>; | |||
322 | using aligned_big64_t = | |||
323 | detail::packed_endian_specific_integral<int64_t, big, aligned>; | |||
324 | ||||
325 | using unaligned_uint16_t = | |||
326 | detail::packed_endian_specific_integral<uint16_t, native, unaligned>; | |||
327 | using unaligned_uint32_t = | |||
328 | detail::packed_endian_specific_integral<uint32_t, native, unaligned>; | |||
329 | using unaligned_uint64_t = | |||
330 | detail::packed_endian_specific_integral<uint64_t, native, unaligned>; | |||
331 | ||||
332 | using unaligned_int16_t = | |||
333 | detail::packed_endian_specific_integral<int16_t, native, unaligned>; | |||
334 | using unaligned_int32_t = | |||
335 | detail::packed_endian_specific_integral<int32_t, native, unaligned>; | |||
336 | using unaligned_int64_t = | |||
337 | detail::packed_endian_specific_integral<int64_t, native, unaligned>; | |||
338 | ||||
339 | template <typename T> | |||
340 | using little_t = detail::packed_endian_specific_integral<T, little, unaligned>; | |||
341 | template <typename T> | |||
342 | using big_t = detail::packed_endian_specific_integral<T, big, unaligned>; | |||
343 | ||||
344 | template <typename T> | |||
345 | using aligned_little_t = | |||
346 | detail::packed_endian_specific_integral<T, little, aligned>; | |||
347 | template <typename T> | |||
348 | using aligned_big_t = detail::packed_endian_specific_integral<T, big, aligned>; | |||
349 | ||||
350 | namespace endian { | |||
351 | ||||
352 | template <typename T> inline T read(const void *P, endianness E) { | |||
353 | return read<T, unaligned>(P, E); | |||
354 | } | |||
355 | ||||
356 | template <typename T, endianness E> inline T read(const void *P) { | |||
357 | return *(const detail::packed_endian_specific_integral<T, E, unaligned> *)P; | |||
358 | } | |||
359 | ||||
360 | inline uint16_t read16(const void *P, endianness E) { | |||
361 | return read<uint16_t>(P, E); | |||
362 | } | |||
363 | inline uint32_t read32(const void *P, endianness E) { | |||
364 | return read<uint32_t>(P, E); | |||
365 | } | |||
366 | inline uint64_t read64(const void *P, endianness E) { | |||
367 | return read<uint64_t>(P, E); | |||
368 | } | |||
369 | ||||
370 | template <endianness E> inline uint16_t read16(const void *P) { | |||
371 | return read<uint16_t, E>(P); | |||
372 | } | |||
373 | template <endianness E> inline uint32_t read32(const void *P) { | |||
374 | return read<uint32_t, E>(P); | |||
375 | } | |||
376 | template <endianness E> inline uint64_t read64(const void *P) { | |||
377 | return read<uint64_t, E>(P); | |||
378 | } | |||
379 | ||||
380 | inline uint16_t read16le(const void *P) { return read16<little>(P); } | |||
381 | inline uint32_t read32le(const void *P) { return read32<little>(P); } | |||
382 | inline uint64_t read64le(const void *P) { return read64<little>(P); } | |||
383 | inline uint16_t read16be(const void *P) { return read16<big>(P); } | |||
384 | inline uint32_t read32be(const void *P) { return read32<big>(P); } | |||
385 | inline uint64_t read64be(const void *P) { return read64<big>(P); } | |||
386 | ||||
387 | template <typename T> inline void write(void *P, T V, endianness E) { | |||
388 | write<T, unaligned>(P, V, E); | |||
389 | } | |||
390 | ||||
391 | template <typename T, endianness E> inline void write(void *P, T V) { | |||
392 | *(detail::packed_endian_specific_integral<T, E, unaligned> *)P = V; | |||
393 | } | |||
394 | ||||
395 | inline void write16(void *P, uint16_t V, endianness E) { | |||
396 | write<uint16_t>(P, V, E); | |||
397 | } | |||
398 | inline void write32(void *P, uint32_t V, endianness E) { | |||
399 | write<uint32_t>(P, V, E); | |||
400 | } | |||
401 | inline void write64(void *P, uint64_t V, endianness E) { | |||
402 | write<uint64_t>(P, V, E); | |||
403 | } | |||
404 | ||||
405 | template <endianness E> inline void write16(void *P, uint16_t V) { | |||
406 | write<uint16_t, E>(P, V); | |||
407 | } | |||
408 | template <endianness E> inline void write32(void *P, uint32_t V) { | |||
409 | write<uint32_t, E>(P, V); | |||
410 | } | |||
411 | template <endianness E> inline void write64(void *P, uint64_t V) { | |||
412 | write<uint64_t, E>(P, V); | |||
413 | } | |||
414 | ||||
415 | inline void write16le(void *P, uint16_t V) { write16<little>(P, V); } | |||
416 | inline void write32le(void *P, uint32_t V) { write32<little>(P, V); } | |||
417 | inline void write64le(void *P, uint64_t V) { write64<little>(P, V); } | |||
418 | inline void write16be(void *P, uint16_t V) { write16<big>(P, V); } | |||
419 | inline void write32be(void *P, uint32_t V) { write32<big>(P, V); } | |||
420 | inline void write64be(void *P, uint64_t V) { write64<big>(P, V); } | |||
421 | ||||
422 | } // end namespace endian | |||
423 | ||||
424 | } // end namespace support | |||
425 | } // end namespace llvm | |||
426 | ||||
427 | #endif // LLVM_SUPPORT_ENDIAN_H |