Bug Summary

File:build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/llvm/include/llvm/Support/Endian.h
Warning:line 66, column 3
Null pointer passed to 2nd parameter expecting 'nonnull'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name MCPseudoProbe.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/build-llvm -resource-dir /usr/lib/llvm-16/lib/clang/16.0.0 -D _DEBUG -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I lib/MC -I /build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/llvm/lib/MC -I include -I /build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/llvm/include -D _FORTIFY_SOURCE=2 -D NDEBUG -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/x86_64-linux-gnu/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/backward -internal-isystem /usr/lib/llvm-16/lib/clang/16.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/build-llvm=build-llvm -fmacro-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/= -fcoverage-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/build-llvm=build-llvm -fcoverage-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/= -O3 -Wno-unused-command-line-argument -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-class-memaccess -Wno-redundant-move -Wno-pessimizing-move -Wno-noexcept-type -Wno-comment -Wno-misleading-indentation -std=c++17 -fdeprecated-macro -fdebug-compilation-dir=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/build-llvm -fdebug-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/build-llvm=build-llvm -fdebug-prefix-map=/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/= -ferror-limit 19 -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2022-10-03-140002-15933-1 -x c++ /build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/llvm/lib/MC/MCPseudoProbe.cpp

/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/llvm/lib/MC/MCPseudoProbe.cpp

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/Support/Endian.h"
18#include "llvm/Support/LEB128.h"
19#include "llvm/Support/raw_ostream.h"
20#include <limits>
21#include <memory>
22#include <sstream>
23
24#define DEBUG_TYPE"mcpseudoprobe" "mcpseudoprobe"
25
26using namespace llvm;
27using namespace support;
28
29#ifndef NDEBUG
30int MCPseudoProbeTable::DdgPrintIndent = 0;
31#endif
32
33static const MCExpr *buildSymbolDiff(MCObjectStreamer *MCOS, const MCSymbol *A,
34 const MCSymbol *B) {
35 MCContext &Context = MCOS->getContext();
36 MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None;
37 const MCExpr *ARef = MCSymbolRefExpr::create(A, Variant, Context);
38 const MCExpr *BRef = MCSymbolRefExpr::create(B, Variant, Context);
39 const MCExpr *AddrDelta =
40 MCBinaryExpr::create(MCBinaryExpr::Sub, ARef, BRef, Context);
41 return AddrDelta;
42}
43
44void MCPseudoProbe::emit(MCObjectStreamer *MCOS,
45 const MCPseudoProbe *LastProbe) const {
46 // Emit Index
47 MCOS->emitULEB128IntValue(Index);
48 // Emit Type and the flag:
49 // Type (bit 0 to 3), with bit 4 to 6 for attributes.
50 // Flag (bit 7, 0 - code address, 1 - address delta). This indicates whether
51 // the following field is a symbolic code address or an address delta.
52 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", 52, __extension__ __PRETTY_FUNCTION__
))
;
53 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", 54, __extension__ __PRETTY_FUNCTION__
))
54 "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", 54, __extension__ __PRETTY_FUNCTION__
))
;
55 uint8_t PackedType = Type | (Attributes << 4);
56 uint8_t Flag = LastProbe ? ((int8_t)MCPseudoProbeFlag::AddressDelta << 7) : 0;
57 MCOS->emitInt8(Flag | PackedType);
58
59 if (LastProbe) {
60 // Emit the delta between the address label and LastProbe.
61 const MCExpr *AddrDelta =
62 buildSymbolDiff(MCOS, Label, LastProbe->getLabel());
63 int64_t Delta;
64 if (AddrDelta->evaluateAsAbsolute(Delta, MCOS->getAssemblerPtr())) {
65 MCOS->emitSLEB128IntValue(Delta);
66 } else {
67 MCOS->insert(new MCPseudoProbeAddrFragment(AddrDelta));
68 }
69 } else {
70 // Emit label as a symbolic code address.
71 MCOS->emitSymbolValue(
72 Label, MCOS->getContext().getAsmInfo()->getCodePointerSize());
73 }
74
75 LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("mcpseudoprobe")) { { dbgs().indent(MCPseudoProbeTable::DdgPrintIndent
); dbgs() << "Probe: " << Index << "\n"; };
} } while (false)
76 dbgs().indent(MCPseudoProbeTable::DdgPrintIndent);do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("mcpseudoprobe")) { { dbgs().indent(MCPseudoProbeTable::DdgPrintIndent
); dbgs() << "Probe: " << Index << "\n"; };
} } while (false)
77 dbgs() << "Probe: " << Index << "\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("mcpseudoprobe")) { { dbgs().indent(MCPseudoProbeTable::DdgPrintIndent
); dbgs() << "Probe: " << Index << "\n"; };
} } while (false)
78 })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("mcpseudoprobe")) { { dbgs().indent(MCPseudoProbeTable::DdgPrintIndent
); dbgs() << "Probe: " << Index << "\n"; };
} } while (false)
;
79}
80
81void MCPseudoProbeInlineTree::addPseudoProbe(
82 const MCPseudoProbe &Probe, const MCPseudoProbeInlineStack &InlineStack) {
83 // The function should not be called on the root.
84 assert(isRoot() && "Should not be called on root")(static_cast <bool> (isRoot() && "Should not be called on root"
) ? void (0) : __assert_fail ("isRoot() && \"Should not be called on root\""
, "llvm/lib/MC/MCPseudoProbe.cpp", 84, __extension__ __PRETTY_FUNCTION__
))
;
85
86 // When it comes here, the input look like:
87 // Probe: GUID of C, ...
88 // InlineStack: [88, A], [66, B]
89 // which means, Function A inlines function B at call site with a probe id of
90 // 88, and B inlines C at probe 66. The tri-tree expects a tree path like {[0,
91 // A], [88, B], [66, C]} to locate the tree node where the probe should be
92 // added. Note that the edge [0, A] means A is the top-level function we are
93 // emitting probes for.
94
95 // Make a [0, A] edge.
96 // An empty inline stack means the function that the probe originates from
97 // is a top-level function.
98 InlineSite Top;
99 if (InlineStack.empty()) {
100 Top = InlineSite(Probe.getGuid(), 0);
101 } else {
102 Top = InlineSite(std::get<0>(InlineStack.front()), 0);
103 }
104
105 auto *Cur = getOrAddNode(Top);
106
107 // Make interior edges by walking the inline stack. Once it's done, Cur should
108 // point to the node that the probe originates from.
109 if (!InlineStack.empty()) {
110 auto Iter = InlineStack.begin();
111 auto Index = std::get<1>(*Iter);
112 Iter++;
113 for (; Iter != InlineStack.end(); Iter++) {
114 // Make an edge by using the previous probe id and current GUID.
115 Cur = Cur->getOrAddNode(InlineSite(std::get<0>(*Iter), Index));
116 Index = std::get<1>(*Iter);
117 }
118 Cur = Cur->getOrAddNode(InlineSite(Probe.getGuid(), Index));
119 }
120
121 Cur->Probes.push_back(Probe);
122}
123
124void MCPseudoProbeInlineTree::emit(MCObjectStreamer *MCOS,
125 const MCPseudoProbe *&LastProbe) {
126 LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("mcpseudoprobe")) { { dbgs().indent(MCPseudoProbeTable::DdgPrintIndent
); dbgs() << "Group [\n"; MCPseudoProbeTable::DdgPrintIndent
+= 2; }; } } while (false)
127 dbgs().indent(MCPseudoProbeTable::DdgPrintIndent);do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("mcpseudoprobe")) { { dbgs().indent(MCPseudoProbeTable::DdgPrintIndent
); dbgs() << "Group [\n"; MCPseudoProbeTable::DdgPrintIndent
+= 2; }; } } while (false)
128 dbgs() << "Group [\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("mcpseudoprobe")) { { dbgs().indent(MCPseudoProbeTable::DdgPrintIndent
); dbgs() << "Group [\n"; MCPseudoProbeTable::DdgPrintIndent
+= 2; }; } } while (false)
129 MCPseudoProbeTable::DdgPrintIndent += 2;do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("mcpseudoprobe")) { { dbgs().indent(MCPseudoProbeTable::DdgPrintIndent
); dbgs() << "Group [\n"; MCPseudoProbeTable::DdgPrintIndent
+= 2; }; } } while (false)
130 })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("mcpseudoprobe")) { { dbgs().indent(MCPseudoProbeTable::DdgPrintIndent
); dbgs() << "Group [\n"; MCPseudoProbeTable::DdgPrintIndent
+= 2; }; } } while (false)
;
131 // Emit probes grouped by GUID.
132 if (Guid != 0) {
133 LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("mcpseudoprobe")) { { dbgs().indent(MCPseudoProbeTable::DdgPrintIndent
); dbgs() << "GUID: " << Guid << "\n"; }; }
} while (false)
134 dbgs().indent(MCPseudoProbeTable::DdgPrintIndent);do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("mcpseudoprobe")) { { dbgs().indent(MCPseudoProbeTable::DdgPrintIndent
); dbgs() << "GUID: " << Guid << "\n"; }; }
} while (false)
135 dbgs() << "GUID: " << Guid << "\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("mcpseudoprobe")) { { dbgs().indent(MCPseudoProbeTable::DdgPrintIndent
); dbgs() << "GUID: " << Guid << "\n"; }; }
} while (false)
136 })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("mcpseudoprobe")) { { dbgs().indent(MCPseudoProbeTable::DdgPrintIndent
); dbgs() << "GUID: " << Guid << "\n"; }; }
} while (false)
;
137 // Emit Guid
138 MCOS->emitInt64(Guid);
139 // Emit number of probes in this node
140 MCOS->emitULEB128IntValue(Probes.size());
141 // Emit number of direct inlinees
142 MCOS->emitULEB128IntValue(Children.size());
143 // Emit probes in this group
144 for (const auto &Probe : Probes) {
145 Probe.emit(MCOS, LastProbe);
146 LastProbe = &Probe;
147 }
148 } else {
149 assert(Probes.empty() && "Root should not have probes")(static_cast <bool> (Probes.empty() && "Root should not have probes"
) ? void (0) : __assert_fail ("Probes.empty() && \"Root should not have probes\""
, "llvm/lib/MC/MCPseudoProbe.cpp", 149, __extension__ __PRETTY_FUNCTION__
))
;
150 }
151
152 // Emit sorted descendant
153 // InlineSite is unique for each pair,
154 // so there will be no ordering of Inlinee based on MCPseudoProbeInlineTree*
155 std::map<InlineSite, MCPseudoProbeInlineTree *> Inlinees;
156 for (auto &Child : Children)
157 Inlinees[Child.first] = Child.second.get();
158
159 for (const auto &Inlinee : Inlinees) {
160 if (Guid) {
161 // Emit probe index
162 MCOS->emitULEB128IntValue(std::get<1>(Inlinee.first));
163 LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("mcpseudoprobe")) { { dbgs().indent(MCPseudoProbeTable::DdgPrintIndent
); dbgs() << "InlineSite: " << std::get<1>(
Inlinee.first) << "\n"; }; } } while (false)
164 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)
165 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)
166 })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("mcpseudoprobe")) { { dbgs().indent(MCPseudoProbeTable::DdgPrintIndent
); dbgs() << "InlineSite: " << std::get<1>(
Inlinee.first) << "\n"; }; } } while (false)
;
167 }
168 // Emit the group
169 Inlinee.second->emit(MCOS, LastProbe);
170 }
171
172 LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("mcpseudoprobe")) { { MCPseudoProbeTable::DdgPrintIndent -= 2
; dbgs().indent(MCPseudoProbeTable::DdgPrintIndent); dbgs() <<
"]\n"; }; } } while (false)
173 MCPseudoProbeTable::DdgPrintIndent -= 2;do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("mcpseudoprobe")) { { MCPseudoProbeTable::DdgPrintIndent -= 2
; dbgs().indent(MCPseudoProbeTable::DdgPrintIndent); dbgs() <<
"]\n"; }; } } while (false)
174 dbgs().indent(MCPseudoProbeTable::DdgPrintIndent);do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("mcpseudoprobe")) { { MCPseudoProbeTable::DdgPrintIndent -= 2
; dbgs().indent(MCPseudoProbeTable::DdgPrintIndent); dbgs() <<
"]\n"; }; } } while (false)
175 dbgs() << "]\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("mcpseudoprobe")) { { MCPseudoProbeTable::DdgPrintIndent -= 2
; dbgs().indent(MCPseudoProbeTable::DdgPrintIndent); dbgs() <<
"]\n"; }; } } while (false)
176 })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("mcpseudoprobe")) { { MCPseudoProbeTable::DdgPrintIndent -= 2
; dbgs().indent(MCPseudoProbeTable::DdgPrintIndent); dbgs() <<
"]\n"; }; } } while (false)
;
177}
178
179void MCPseudoProbeSection::emit(MCObjectStreamer *MCOS) {
180 MCContext &Ctx = MCOS->getContext();
181
182 for (auto &ProbeSec : MCProbeDivisions) {
183 const MCPseudoProbe *LastProbe = nullptr;
184 if (auto *S =
185 Ctx.getObjectFileInfo()->getPseudoProbeSection(ProbeSec.first)) {
186 // Switch to the .pseudoprobe section or a comdat group.
187 MCOS->switchSection(S);
188 // Emit probes grouped by GUID.
189 ProbeSec.second.emit(MCOS, LastProbe);
190 }
191 }
192}
193
194//
195// This emits the pseudo probe tables.
196//
197void MCPseudoProbeTable::emit(MCObjectStreamer *MCOS) {
198 MCContext &Ctx = MCOS->getContext();
199 auto &ProbeTable = Ctx.getMCPseudoProbeTable();
200
201 // Bail out early so we don't switch to the pseudo_probe section needlessly
202 // and in doing so create an unnecessary (if empty) section.
203 auto &ProbeSections = ProbeTable.getProbeSections();
204 if (ProbeSections.empty())
205 return;
206
207 LLVM_DEBUG(MCPseudoProbeTable::DdgPrintIndent = 0)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("mcpseudoprobe")) { MCPseudoProbeTable::DdgPrintIndent = 0; }
} while (false)
;
208
209 // Put out the probe.
210 ProbeSections.emit(MCOS);
211}
212
213static StringRef getProbeFNameForGUID(const GUIDProbeFunctionMap &GUID2FuncMAP,
214 uint64_t GUID) {
215 auto It = GUID2FuncMAP.find(GUID);
216 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", 217, __extension__ __PRETTY_FUNCTION__
))
217 "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", 217, __extension__ __PRETTY_FUNCTION__
))
;
218 return It->second.FuncName;
219}
220
221void MCPseudoProbeFuncDesc::print(raw_ostream &OS) {
222 OS << "GUID: " << FuncGUID << " Name: " << FuncName << "\n";
223 OS << "Hash: " << FuncHash << "\n";
224}
225
226void MCDecodedPseudoProbe::getInlineContext(
227 SmallVectorImpl<MCPseduoProbeFrameLocation> &ContextStack,
228 const GUIDProbeFunctionMap &GUID2FuncMAP) const {
229 uint32_t Begin = ContextStack.size();
230 MCDecodedPseudoProbeInlineTree *Cur = InlineTree;
231 // It will add the string of each node's inline site during iteration.
232 // Note that it won't include the probe's belonging function(leaf location)
233 while (Cur->hasInlineSite()) {
234 StringRef FuncName = getProbeFNameForGUID(GUID2FuncMAP, Cur->Parent->Guid);
235 ContextStack.emplace_back(
236 MCPseduoProbeFrameLocation(FuncName, std::get<1>(Cur->ISite)));
237 Cur = static_cast<MCDecodedPseudoProbeInlineTree *>(Cur->Parent);
238 }
239 // Make the ContextStack in caller-callee order
240 std::reverse(ContextStack.begin() + Begin, ContextStack.end());
241}
242
243std::string MCDecodedPseudoProbe::getInlineContextStr(
244 const GUIDProbeFunctionMap &GUID2FuncMAP) const {
245 std::ostringstream OContextStr;
246 SmallVector<MCPseduoProbeFrameLocation, 16> ContextStack;
247 getInlineContext(ContextStack, GUID2FuncMAP);
248 for (auto &Cxt : ContextStack) {
249 if (OContextStr.str().size())
250 OContextStr << " @ ";
251 OContextStr << Cxt.first.str() << ":" << Cxt.second;
252 }
253 return OContextStr.str();
254}
255
256static const char *PseudoProbeTypeStr[3] = {"Block", "IndirectCall",
257 "DirectCall"};
258
259void MCDecodedPseudoProbe::print(raw_ostream &OS,
260 const GUIDProbeFunctionMap &GUID2FuncMAP,
261 bool ShowName) const {
262 OS << "FUNC: ";
263 if (ShowName) {
264 StringRef FuncName = getProbeFNameForGUID(GUID2FuncMAP, Guid);
265 OS << FuncName.str() << " ";
266 } else {
267 OS << Guid << " ";
268 }
269 OS << "Index: " << Index << " ";
270 OS << "Type: " << PseudoProbeTypeStr[static_cast<uint8_t>(Type)] << " ";
271 std::string InlineContextStr = getInlineContextStr(GUID2FuncMAP);
272 if (InlineContextStr.size()) {
273 OS << "Inlined: @ ";
274 OS << InlineContextStr;
275 }
276 OS << "\n";
277}
278
279template <typename T> ErrorOr<T> MCPseudoProbeDecoder::readUnencodedNumber() {
280 if (Data + sizeof(T) > End) {
26
Taking false branch
281 return std::error_code();
282 }
283 T Val = endian::readNext<T, little, unaligned>(Data);
27
Calling 'readNext<unsigned char, llvm::support::little, 1UL, unsigned char>'
284 return ErrorOr<T>(Val);
285}
286
287template <typename T> ErrorOr<T> MCPseudoProbeDecoder::readUnsignedNumber() {
288 unsigned NumBytesRead = 0;
289 uint64_t Val = decodeULEB128(Data, &NumBytesRead);
290 if (Val > std::numeric_limits<T>::max() || (Data + NumBytesRead > End)) {
291 return std::error_code();
292 }
293 Data += NumBytesRead;
294 return ErrorOr<T>(static_cast<T>(Val));
295}
296
297template <typename T> ErrorOr<T> MCPseudoProbeDecoder::readSignedNumber() {
298 unsigned NumBytesRead = 0;
299 int64_t Val = decodeSLEB128(Data, &NumBytesRead);
300 if (Val > std::numeric_limits<T>::max() || (Data + NumBytesRead > End)) {
301 return std::error_code();
302 }
303 Data += NumBytesRead;
304 return ErrorOr<T>(static_cast<T>(Val));
305}
306
307ErrorOr<StringRef> MCPseudoProbeDecoder::readString(uint32_t Size) {
308 StringRef Str(reinterpret_cast<const char *>(Data), Size);
309 if (Data + Size > End) {
310 return std::error_code();
311 }
312 Data += Size;
313 return ErrorOr<StringRef>(Str);
314}
315
316bool MCPseudoProbeDecoder::buildGUID2FuncDescMap(const uint8_t *Start,
317 std::size_t Size) {
318 // The pseudo_probe_desc section has a format like:
319 // .section .pseudo_probe_desc,"",@progbits
320 // .quad -5182264717993193164 // GUID
321 // .quad 4294967295 // Hash
322 // .uleb 3 // Name size
323 // .ascii "foo" // Name
324 // .quad -2624081020897602054
325 // .quad 174696971957
326 // .uleb 34
327 // .ascii "main"
328
329 Data = Start;
330 End = Data + Size;
331
332 while (Data < End) {
333 auto ErrorOrGUID = readUnencodedNumber<uint64_t>();
334 if (!ErrorOrGUID)
335 return false;
336
337 auto ErrorOrHash = readUnencodedNumber<uint64_t>();
338 if (!ErrorOrHash)
339 return false;
340
341 auto ErrorOrNameSize = readUnsignedNumber<uint32_t>();
342 if (!ErrorOrNameSize)
343 return false;
344 uint32_t NameSize = std::move(*ErrorOrNameSize);
345
346 auto ErrorOrName = readString(NameSize);
347 if (!ErrorOrName)
348 return false;
349
350 uint64_t GUID = std::move(*ErrorOrGUID);
351 uint64_t Hash = std::move(*ErrorOrHash);
352 StringRef Name = std::move(*ErrorOrName);
353
354 // Initialize PseudoProbeFuncDesc and populate it into GUID2FuncDescMap
355 GUID2FuncDescMap.emplace(GUID, MCPseudoProbeFuncDesc(GUID, Hash, Name));
356 }
357 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", 357, __extension__ __PRETTY_FUNCTION__
))
;
358 return true;
359}
360
361bool MCPseudoProbeDecoder::buildAddress2ProbeMap(
362 MCDecodedPseudoProbeInlineTree *Cur, uint64_t &LastAddr,
363 std::unordered_set<uint64_t> &GuildFilter) {
364 // The pseudo_probe section encodes an inline forest and each tree has a
365 // format like:
366 // FUNCTION BODY (one for each uninlined function present in the text
367 // section)
368 // GUID (uint64)
369 // GUID of the function
370 // NPROBES (ULEB128)
371 // Number of probes originating from this function.
372 // NUM_INLINED_FUNCTIONS (ULEB128)
373 // Number of callees inlined into this function, aka number of
374 // first-level inlinees
375 // PROBE RECORDS
376 // A list of NPROBES entries. Each entry contains:
377 // INDEX (ULEB128)
378 // TYPE (uint4)
379 // 0 - block probe, 1 - indirect call, 2 - direct call
380 // ATTRIBUTE (uint3)
381 // 1 - tail call, 2 - dangling
382 // ADDRESS_TYPE (uint1)
383 // 0 - code address, 1 - address delta
384 // CODE_ADDRESS (uint64 or ULEB128)
385 // code address or address delta, depending on Flag
386 // INLINED FUNCTION RECORDS
387 // A list of NUM_INLINED_FUNCTIONS entries describing each of the
388 // inlined callees. Each record contains:
389 // INLINE SITE
390 // Index of the callsite probe (ULEB128)
391 // FUNCTION BODY
392 // A FUNCTION BODY entry describing the inlined function.
393
394 uint32_t Index = 0;
395 if (Cur == &DummyInlineRoot) {
4
Taking true branch
14
Assuming the condition is false
15
Taking false branch
396 // Use a sequential id for top level inliner.
397 Index = Cur->getChildren().size();
398 } else {
399 // Read inline site for inlinees
400 auto ErrorOrIndex = readUnsignedNumber<uint32_t>();
401 if (!ErrorOrIndex)
16
Taking false branch
402 return false;
403 Index = std::move(*ErrorOrIndex);
404 }
405
406 // Read guid
407 auto ErrorOrCurGuid = readUnencodedNumber<uint64_t>();
408 if (!ErrorOrCurGuid)
5
Taking false branch
17
Taking false branch
409 return false;
410 uint64_t Guid = std::move(*ErrorOrCurGuid);
411
412 // Decide if top-level node should be disgarded.
413 if (Cur == &DummyInlineRoot && !GuildFilter.empty() &&
6
Assuming the condition is false
18
Assuming the condition is false
414 !GuildFilter.count(Guid))
415 Cur = nullptr;
416
417 // If the incoming node is null, all its children nodes should be disgarded.
418 if (Cur
6.1
'Cur' is non-null
18.1
'Cur' is non-null
6.1
'Cur' is non-null
18.1
'Cur' is non-null
) {
7
Taking true branch
19
Taking true branch
419 // Switch/add to a new tree node(inlinee)
420 Cur = Cur->getOrAddNode(std::make_tuple(Guid, Index));
421 Cur->Guid = Guid;
422 }
423
424 // Read number of probes in the current node.
425 auto ErrorOrNodeCount = readUnsignedNumber<uint32_t>();
426 if (!ErrorOrNodeCount)
8
Taking false branch
20
Taking false branch
427 return false;
428 uint32_t NodeCount = std::move(*ErrorOrNodeCount);
429 // Read number of direct inlinees
430 auto ErrorOrCurChildrenToProcess = readUnsignedNumber<uint32_t>();
431 if (!ErrorOrCurChildrenToProcess)
9
Taking false branch
21
Taking false branch
432 return false;
433 // Read all probes in this node
434 for (std::size_t I = 0; I < NodeCount; I++) {
10
Loop condition is false. Execution continues on line 472
22
Assuming 'I' is < 'NodeCount'
23
Loop condition is true. Entering loop body
435 // Read index
436 auto ErrorOrIndex = readUnsignedNumber<uint32_t>();
437 if (!ErrorOrIndex)
24
Taking false branch
438 return false;
439 uint32_t Index = std::move(*ErrorOrIndex);
440 // Read type | flag.
441 auto ErrorOrValue = readUnencodedNumber<uint8_t>();
25
Calling 'MCPseudoProbeDecoder::readUnencodedNumber'
442 if (!ErrorOrValue)
443 return false;
444 uint8_t Value = std::move(*ErrorOrValue);
445 uint8_t Kind = Value & 0xf;
446 uint8_t Attr = (Value & 0x70) >> 4;
447 // Read address
448 uint64_t Addr = 0;
449 if (Value & 0x80) {
450 auto ErrorOrOffset = readSignedNumber<int64_t>();
451 if (!ErrorOrOffset)
452 return false;
453 int64_t Offset = std::move(*ErrorOrOffset);
454 Addr = LastAddr + Offset;
455 } else {
456 auto ErrorOrAddr = readUnencodedNumber<int64_t>();
457 if (!ErrorOrAddr)
458 return false;
459 Addr = std::move(*ErrorOrAddr);
460 }
461
462 if (Cur) {
463 // Populate Address2ProbesMap
464 auto &Probes = Address2ProbesMap[Addr];
465 Probes.emplace_back(Addr, Cur->Guid, Index, PseudoProbeType(Kind), Attr,
466 Cur);
467 Cur->addProbes(&Probes.back());
468 }
469 LastAddr = Addr;
470 }
471
472 uint32_t ChildrenToProcess = std::move(*ErrorOrCurChildrenToProcess);
473 for (uint32_t I = 0; I < ChildrenToProcess; I++) {
11
Assuming 'I' is < 'ChildrenToProcess'
12
Loop condition is true. Entering loop body
474 buildAddress2ProbeMap(Cur, LastAddr, GuildFilter);
13
Calling 'MCPseudoProbeDecoder::buildAddress2ProbeMap'
475 }
476
477 return true;
478}
479
480bool MCPseudoProbeDecoder::buildAddress2ProbeMap(
481 const uint8_t *Start, std::size_t Size,
482 std::unordered_set<uint64_t> &GuildFilter) {
483 Data = Start;
484 End = Data + Size;
485 uint64_t LastAddr = 0;
486 while (Data < End)
2
Loop condition is true. Entering loop body
487 buildAddress2ProbeMap(&DummyInlineRoot, LastAddr, GuildFilter);
3
Calling 'MCPseudoProbeDecoder::buildAddress2ProbeMap'
488 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", 488, __extension__ __PRETTY_FUNCTION__
))
;
489 return true;
490}
491
492bool MCPseudoProbeDecoder::buildAddress2ProbeMap(const uint8_t *Start,
493 std::size_t Size) {
494 std::unordered_set<uint64_t> GuildFilter;
495 return buildAddress2ProbeMap(Start, Size, GuildFilter);
1
Calling 'MCPseudoProbeDecoder::buildAddress2ProbeMap'
496}
497
498void MCPseudoProbeDecoder::printGUID2FuncDescMap(raw_ostream &OS) {
499 OS << "Pseudo Probe Desc:\n";
500 // Make the output deterministic
501 std::map<uint64_t, MCPseudoProbeFuncDesc> OrderedMap(GUID2FuncDescMap.begin(),
502 GUID2FuncDescMap.end());
503 for (auto &I : OrderedMap) {
504 I.second.print(OS);
505 }
506}
507
508void MCPseudoProbeDecoder::printProbeForAddress(raw_ostream &OS,
509 uint64_t Address) {
510 auto It = Address2ProbesMap.find(Address);
511 if (It != Address2ProbesMap.end()) {
512 for (auto &Probe : It->second) {
513 OS << " [Probe]:\t";
514 Probe.print(OS, GUID2FuncDescMap, true);
515 }
516 }
517}
518
519void MCPseudoProbeDecoder::printProbesForAllAddresses(raw_ostream &OS) {
520 std::vector<uint64_t> Addresses;
521 for (auto Entry : Address2ProbesMap)
522 Addresses.push_back(Entry.first);
523 llvm::sort(Addresses);
524 for (auto K : Addresses) {
525 OS << "Address:\t";
526 OS << K;
527 OS << "\n";
528 printProbeForAddress(OS, K);
529 }
530}
531
532const MCDecodedPseudoProbe *
533MCPseudoProbeDecoder::getCallProbeForAddr(uint64_t Address) const {
534 auto It = Address2ProbesMap.find(Address);
535 if (It == Address2ProbesMap.end())
536 return nullptr;
537 const auto &Probes = It->second;
538
539 const MCDecodedPseudoProbe *CallProbe = nullptr;
540 for (const auto &Probe : Probes) {
541 if (Probe.isCall()) {
542 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", 544, __extension__ __PRETTY_FUNCTION__
))
543 "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", 544, __extension__ __PRETTY_FUNCTION__
))
544 "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", 544, __extension__ __PRETTY_FUNCTION__
))
;
545 CallProbe = &Probe;
546 }
547 }
548 return CallProbe;
549}
550
551const MCPseudoProbeFuncDesc *
552MCPseudoProbeDecoder::getFuncDescForGUID(uint64_t GUID) const {
553 auto It = GUID2FuncDescMap.find(GUID);
554 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", 554, __extension__ __PRETTY_FUNCTION__
))
;
555 return &It->second;
556}
557
558void MCPseudoProbeDecoder::getInlineContextForProbe(
559 const MCDecodedPseudoProbe *Probe,
560 SmallVectorImpl<MCPseduoProbeFrameLocation> &InlineContextStack,
561 bool IncludeLeaf) const {
562 Probe->getInlineContext(InlineContextStack, GUID2FuncDescMap);
563 if (!IncludeLeaf)
564 return;
565 // Note that the context from probe doesn't include leaf frame,
566 // hence we need to retrieve and prepend leaf if requested.
567 const auto *FuncDesc = getFuncDescForGUID(Probe->getGuid());
568 InlineContextStack.emplace_back(
569 MCPseduoProbeFrameLocation(FuncDesc->FuncName, Probe->getIndex()));
570}
571
572const MCPseudoProbeFuncDesc *MCPseudoProbeDecoder::getInlinerDescForProbe(
573 const MCDecodedPseudoProbe *Probe) const {
574 MCDecodedPseudoProbeInlineTree *InlinerNode = Probe->getInlineTreeNode();
575 if (!InlinerNode->hasInlineSite())
576 return nullptr;
577 return getFuncDescForGUID(InlinerNode->Parent->Guid);
578}

/build/llvm-toolchain-snapshot-16~++20221003111214+1fa2019828ca/llvm/include/llvm/Support/Endian.h

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
24namespace llvm {
25namespace support {
26
27enum endianness {big, little, native};
28
29// These are named values for common alignments.
30enum {aligned = 0, unaligned = 1};
31
32namespace detail {
33
34/// ::value is either alignment, or alignof(T) if alignment is 0.
35template<class T, int alignment>
36struct PickAlignment {
37 enum { value = alignment == 0 ? alignof(T) : alignment };
38};
39
40} // end namespace detail
41
42namespace endian {
43
44constexpr endianness system_endianness() {
45 return sys::IsBigEndianHost ? big : little;
46}
47
48template <typename value_type>
49inline 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.
56template<typename value_type, endianness endian>
57inline 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.
62template <typename value_type, std::size_t alignment>
63inline value_type read(const void *memory, endianness endian) {
64 value_type ret;
65
66 memcpy(&ret,
30
Null pointer passed to 2nd parameter expecting 'nonnull'
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
73template<typename value_type,
74 endianness endian,
75 std::size_t alignment>
76inline 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.
82template <typename value_type, std::size_t alignment, typename CharT>
83inline value_type readNext(const CharT *&memory, endianness endian) {
84 value_type ret = read<value_type, alignment>(memory, endian);
29
Calling 'read<unsigned char, 1UL>'
85 memory += sizeof(value_type);
86 return ret;
87}
88
89template<typename value_type, endianness endian, std::size_t alignment,
90 typename CharT>
91inline value_type readNext(const CharT *&memory) {
92 return readNext<value_type, alignment, CharT>(memory, endian);
28
Calling 'readNext<unsigned char, 1UL, unsigned char>'
93}
94
95/// Write a value to memory with a particular endianness.
96template <typename value_type, std::size_t alignment>
97inline 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
104template<typename value_type,
105 endianness endian,
106 std::size_t alignment>
107inline void write(void *memory, value_type value) {
108 write<value_type, alignment>(memory, value, endian);
109}
110
111template <typename value_type>
112using 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.
116template <typename value_type, endianness endian, std::size_t alignment>
117inline 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.
150template <typename value_type, endianness endian, std::size_t alignment>
151inline 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
202namespace detail {
203
204template <typename ValueType, endianness Endian, std::size_t Alignment,
205 std::size_t ALIGN = PickAlignment<ValueType, Alignment>::value>
206struct 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
245private:
246 struct {
247 alignas(ALIGN) char buffer[sizeof(value_type)];
248 } Value;
249
250public:
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
269using ulittle16_t =
270 detail::packed_endian_specific_integral<uint16_t, little, unaligned>;
271using ulittle32_t =
272 detail::packed_endian_specific_integral<uint32_t, little, unaligned>;
273using ulittle64_t =
274 detail::packed_endian_specific_integral<uint64_t, little, unaligned>;
275
276using little16_t =
277 detail::packed_endian_specific_integral<int16_t, little, unaligned>;
278using little32_t =
279 detail::packed_endian_specific_integral<int32_t, little, unaligned>;
280using little64_t =
281 detail::packed_endian_specific_integral<int64_t, little, unaligned>;
282
283using aligned_ulittle16_t =
284 detail::packed_endian_specific_integral<uint16_t, little, aligned>;
285using aligned_ulittle32_t =
286 detail::packed_endian_specific_integral<uint32_t, little, aligned>;
287using aligned_ulittle64_t =
288 detail::packed_endian_specific_integral<uint64_t, little, aligned>;
289
290using aligned_little16_t =
291 detail::packed_endian_specific_integral<int16_t, little, aligned>;
292using aligned_little32_t =
293 detail::packed_endian_specific_integral<int32_t, little, aligned>;
294using aligned_little64_t =
295 detail::packed_endian_specific_integral<int64_t, little, aligned>;
296
297using ubig16_t =
298 detail::packed_endian_specific_integral<uint16_t, big, unaligned>;
299using ubig32_t =
300 detail::packed_endian_specific_integral<uint32_t, big, unaligned>;
301using ubig64_t =
302 detail::packed_endian_specific_integral<uint64_t, big, unaligned>;
303
304using big16_t =
305 detail::packed_endian_specific_integral<int16_t, big, unaligned>;
306using big32_t =
307 detail::packed_endian_specific_integral<int32_t, big, unaligned>;
308using big64_t =
309 detail::packed_endian_specific_integral<int64_t, big, unaligned>;
310
311using aligned_ubig16_t =
312 detail::packed_endian_specific_integral<uint16_t, big, aligned>;
313using aligned_ubig32_t =
314 detail::packed_endian_specific_integral<uint32_t, big, aligned>;
315using aligned_ubig64_t =
316 detail::packed_endian_specific_integral<uint64_t, big, aligned>;
317
318using aligned_big16_t =
319 detail::packed_endian_specific_integral<int16_t, big, aligned>;
320using aligned_big32_t =
321 detail::packed_endian_specific_integral<int32_t, big, aligned>;
322using aligned_big64_t =
323 detail::packed_endian_specific_integral<int64_t, big, aligned>;
324
325using unaligned_uint16_t =
326 detail::packed_endian_specific_integral<uint16_t, native, unaligned>;
327using unaligned_uint32_t =
328 detail::packed_endian_specific_integral<uint32_t, native, unaligned>;
329using unaligned_uint64_t =
330 detail::packed_endian_specific_integral<uint64_t, native, unaligned>;
331
332using unaligned_int16_t =
333 detail::packed_endian_specific_integral<int16_t, native, unaligned>;
334using unaligned_int32_t =
335 detail::packed_endian_specific_integral<int32_t, native, unaligned>;
336using unaligned_int64_t =
337 detail::packed_endian_specific_integral<int64_t, native, unaligned>;
338
339template <typename T>
340using little_t = detail::packed_endian_specific_integral<T, little, unaligned>;
341template <typename T>
342using big_t = detail::packed_endian_specific_integral<T, big, unaligned>;
343
344template <typename T>
345using aligned_little_t =
346 detail::packed_endian_specific_integral<T, little, aligned>;
347template <typename T>
348using aligned_big_t = detail::packed_endian_specific_integral<T, big, aligned>;
349
350namespace endian {
351
352template <typename T> inline T read(const void *P, endianness E) {
353 return read<T, unaligned>(P, E);
354}
355
356template <typename T, endianness E> inline T read(const void *P) {
357 return *(const detail::packed_endian_specific_integral<T, E, unaligned> *)P;
358}
359
360inline uint16_t read16(const void *P, endianness E) {
361 return read<uint16_t>(P, E);
362}
363inline uint32_t read32(const void *P, endianness E) {
364 return read<uint32_t>(P, E);
365}
366inline uint64_t read64(const void *P, endianness E) {
367 return read<uint64_t>(P, E);
368}
369
370template <endianness E> inline uint16_t read16(const void *P) {
371 return read<uint16_t, E>(P);
372}
373template <endianness E> inline uint32_t read32(const void *P) {
374 return read<uint32_t, E>(P);
375}
376template <endianness E> inline uint64_t read64(const void *P) {
377 return read<uint64_t, E>(P);
378}
379
380inline uint16_t read16le(const void *P) { return read16<little>(P); }
381inline uint32_t read32le(const void *P) { return read32<little>(P); }
382inline uint64_t read64le(const void *P) { return read64<little>(P); }
383inline uint16_t read16be(const void *P) { return read16<big>(P); }
384inline uint32_t read32be(const void *P) { return read32<big>(P); }
385inline uint64_t read64be(const void *P) { return read64<big>(P); }
386
387template <typename T> inline void write(void *P, T V, endianness E) {
388 write<T, unaligned>(P, V, E);
389}
390
391template <typename T, endianness E> inline void write(void *P, T V) {
392 *(detail::packed_endian_specific_integral<T, E, unaligned> *)P = V;
393}
394
395inline void write16(void *P, uint16_t V, endianness E) {
396 write<uint16_t>(P, V, E);
397}
398inline void write32(void *P, uint32_t V, endianness E) {
399 write<uint32_t>(P, V, E);
400}
401inline void write64(void *P, uint64_t V, endianness E) {
402 write<uint64_t>(P, V, E);
403}
404
405template <endianness E> inline void write16(void *P, uint16_t V) {
406 write<uint16_t, E>(P, V);
407}
408template <endianness E> inline void write32(void *P, uint32_t V) {
409 write<uint32_t, E>(P, V);
410}
411template <endianness E> inline void write64(void *P, uint64_t V) {
412 write<uint64_t, E>(P, V);
413}
414
415inline void write16le(void *P, uint16_t V) { write16<little>(P, V); }
416inline void write32le(void *P, uint32_t V) { write32<little>(P, V); }
417inline void write64le(void *P, uint64_t V) { write64<little>(P, V); }
418inline void write16be(void *P, uint16_t V) { write16<big>(P, V); }
419inline void write32be(void *P, uint32_t V) { write32<big>(P, V); }
420inline 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