1//===----------------------------------------------------------------------===//
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/// \file
10/// This file defines the YAMLIO mappings for the format-agnostic BB address
11/// map YAML types declared in BBAddrMapYAML.h.
12///
13//===----------------------------------------------------------------------===//
14
15#include "llvm/ObjectYAML/BBAddrMapYAML.h"
16#include "llvm/Object/BBAddrMap.h"
17#include "llvm/ObjectYAML/ContiguousBlobAccumulator.h"
18#include "llvm/Support/WithColor.h"
19
20namespace llvm {
21namespace yaml {
22
23void MappingTraits<BBAddrMapYAML::BBAddrMapEntry>::mapping(
24 IO &IO, BBAddrMapYAML::BBAddrMapEntry &E) {
25 assert(IO.getContext() && "The IO context is not initialized");
26 IO.mapRequired(Key: "Version", Val&: E.Version);
27 IO.mapOptional(Key: "Feature", Val&: E.Feature, Default: Hex16(0));
28 IO.mapOptional(Key: "NumBBRanges", Val&: E.NumBBRanges);
29 IO.mapOptional(Key: "BBRanges", Val&: E.BBRanges);
30}
31
32void MappingTraits<BBAddrMapYAML::BBAddrMapEntry::BBRangeEntry>::mapping(
33 IO &IO, BBAddrMapYAML::BBAddrMapEntry::BBRangeEntry &E) {
34 IO.mapOptional(Key: "BaseAddress", Val&: E.BaseAddress, Default: Hex64(0));
35 IO.mapOptional(Key: "NumBlocks", Val&: E.NumBlocks);
36 IO.mapOptional(Key: "BBEntries", Val&: E.BBEntries);
37}
38
39void MappingTraits<BBAddrMapYAML::BBAddrMapEntry::BBEntry>::mapping(
40 IO &IO, BBAddrMapYAML::BBAddrMapEntry::BBEntry &E) {
41 assert(IO.getContext() && "The IO context is not initialized");
42 IO.mapOptional(Key: "ID", Val&: E.ID);
43 IO.mapRequired(Key: "AddressOffset", Val&: E.AddressOffset);
44 IO.mapRequired(Key: "Size", Val&: E.Size);
45 IO.mapRequired(Key: "Metadata", Val&: E.Metadata);
46 IO.mapOptional(Key: "CallsiteEndOffsets", Val&: E.CallsiteEndOffsets);
47 IO.mapOptional(Key: "Hash", Val&: E.Hash);
48}
49
50void MappingTraits<BBAddrMapYAML::PGOAnalysisMapEntry>::mapping(
51 IO &IO, BBAddrMapYAML::PGOAnalysisMapEntry &E) {
52 assert(IO.getContext() && "The IO context is not initialized");
53 IO.mapOptional(Key: "FuncEntryCount", Val&: E.FuncEntryCount);
54 IO.mapOptional(Key: "PGOBBEntries", Val&: E.PGOBBEntries);
55}
56
57void MappingTraits<BBAddrMapYAML::PGOAnalysisMapEntry::PGOBBEntry>::mapping(
58 IO &IO, BBAddrMapYAML::PGOAnalysisMapEntry::PGOBBEntry &E) {
59 assert(IO.getContext() && "The IO context is not initialized");
60 IO.mapOptional(Key: "BBFreq", Val&: E.BBFreq);
61 IO.mapOptional(Key: "PostLinkBBFreq", Val&: E.PostLinkBBFreq);
62 IO.mapOptional(Key: "Successors", Val&: E.Successors);
63}
64
65void MappingTraits<
66 BBAddrMapYAML::PGOAnalysisMapEntry::PGOBBEntry::SuccessorEntry>::
67 mapping(IO &IO,
68 BBAddrMapYAML::PGOAnalysisMapEntry::PGOBBEntry::SuccessorEntry &E) {
69 assert(IO.getContext() && "The IO context is not initialized");
70 IO.mapRequired(Key: "ID", Val&: E.ID);
71 IO.mapRequired(Key: "BrProb", Val&: E.BrProb);
72 IO.mapOptional(Key: "PostLinkBrFreq", Val&: E.PostLinkBrFreq);
73}
74
75} // end namespace yaml
76
77namespace BBAddrMapYAML {
78
79void encodePayload(ArrayRef<BBAddrMapEntry> Entries,
80 const std::vector<PGOAnalysisMapEntry> *PGOAnalyses,
81 yaml::ContiguousBlobAccumulator &CBA,
82 llvm::endianness Endian, unsigned AddressSize) {
83 assert((AddressSize == 4 || AddressSize == 8) && "invalid address size");
84 for (const auto &[Idx, E] : llvm::enumerate(First&: Entries)) {
85 // Write version and feature values.
86 if (E.Version > 5)
87 WithColor::warning() << "unsupported BB address map version: "
88 << static_cast<int>(E.Version)
89 << "; encoding using the most recent version";
90 CBA.write(C: E.Version);
91 if (E.Version < 5)
92 CBA.write(C: static_cast<uint8_t>(E.Feature));
93 else
94 CBA.write<uint16_t>(Val: E.Feature, E: Endian);
95 auto FeatureOrErr = llvm::object::BBAddrMap::Features::decode(Val: E.Feature);
96 if (!FeatureOrErr) {
97 // Invalid feature: warn and skip the entry.
98 WithColor::warning() << toString(E: FeatureOrErr.takeError());
99 continue;
100 }
101 bool MultiBBRangeFeatureEnabled = FeatureOrErr->MultiBBRange;
102 bool MultiBBRange =
103 MultiBBRangeFeatureEnabled ||
104 (E.NumBBRanges.has_value() && E.NumBBRanges.value() != 1) ||
105 (E.BBRanges && E.BBRanges->size() != 1);
106 if (MultiBBRange && !MultiBBRangeFeatureEnabled)
107 WithColor::warning() << "feature value(" << E.Feature
108 << ") does not support multiple BB ranges.";
109 if (MultiBBRange) {
110 // Write the number of basic block ranges, which is overridden by the
111 // 'NumBBRanges' field when specified.
112 uint64_t NumBBRanges =
113 E.NumBBRanges.value_or(u: E.BBRanges ? E.BBRanges->size() : 0);
114 CBA.writeULEB128(Val: NumBBRanges);
115 }
116 if (!E.BBRanges)
117 continue;
118 uint64_t TotalNumBlocks = 0;
119 bool EmitCallsiteEndOffsets =
120 FeatureOrErr->CallsiteEndOffsets || E.hasAnyCallsiteEndOffsets();
121 for (const BBAddrMapEntry::BBRangeEntry &BBR : *E.BBRanges) {
122 // Write the pointer-sized base address of the range.
123 if (AddressSize == 8)
124 CBA.write<uint64_t>(Val: BBR.BaseAddress, E: Endian);
125 else
126 CBA.write<uint32_t>(Val: static_cast<uint32_t>(BBR.BaseAddress), E: Endian);
127 // Write number of BBEntries (number of basic blocks in this basic block
128 // range). This is overridden by the 'NumBlocks' YAML field when
129 // specified.
130 uint64_t NumBlocks =
131 BBR.NumBlocks.value_or(u: BBR.BBEntries ? BBR.BBEntries->size() : 0);
132 CBA.writeULEB128(Val: NumBlocks);
133 // Write all BBEntries in this BBRange.
134 if (!BBR.BBEntries || FeatureOrErr->OmitBBEntries)
135 continue;
136 for (const BBAddrMapEntry::BBEntry &BBE : *BBR.BBEntries) {
137 ++TotalNumBlocks;
138 if (E.Version > 1)
139 CBA.writeULEB128(Val: BBE.ID);
140 CBA.writeULEB128(Val: BBE.AddressOffset);
141 if (EmitCallsiteEndOffsets) {
142 size_t NumCallsiteEndOffsets =
143 BBE.CallsiteEndOffsets ? BBE.CallsiteEndOffsets->size() : 0;
144 CBA.writeULEB128(Val: NumCallsiteEndOffsets);
145 if (BBE.CallsiteEndOffsets) {
146 for (uint32_t Offset : *BBE.CallsiteEndOffsets)
147 CBA.writeULEB128(Val: Offset);
148 }
149 }
150 CBA.writeULEB128(Val: BBE.Size);
151 CBA.writeULEB128(Val: BBE.Metadata);
152 if (FeatureOrErr->BBHash || BBE.Hash.has_value()) {
153 uint64_t Hash =
154 BBE.Hash.has_value() ? BBE.Hash.value() : llvm::yaml::Hex64(0);
155 CBA.write<uint64_t>(Val: Hash, E: Endian);
156 }
157 }
158 }
159 if (!PGOAnalyses)
160 continue;
161 const PGOAnalysisMapEntry &PGOEntry = PGOAnalyses->at(n: Idx);
162
163 if (PGOEntry.FuncEntryCount)
164 CBA.writeULEB128(Val: *PGOEntry.FuncEntryCount);
165
166 if (!PGOEntry.PGOBBEntries)
167 continue;
168
169 const auto &PGOBBEntries = PGOEntry.PGOBBEntries.value();
170 if (TotalNumBlocks != PGOBBEntries.size()) {
171 WithColor::warning() << "PGOBBEntries must be the same length as "
172 "BBEntries in the BB address map.\n"
173 << "Mismatch on function with address: "
174 << E.getFunctionAddress();
175 continue;
176 }
177
178 for (const auto &PGOBBE : PGOBBEntries) {
179 if (PGOBBE.BBFreq)
180 CBA.writeULEB128(Val: *PGOBBE.BBFreq);
181 if (FeatureOrErr->PostLinkCfg || PGOBBE.PostLinkBBFreq.has_value())
182 CBA.writeULEB128(Val: PGOBBE.PostLinkBBFreq.value_or(u: 0));
183 if (PGOBBE.Successors) {
184 CBA.writeULEB128(Val: PGOBBE.Successors->size());
185 for (const auto &[ID, BrProb, PostLinkBrFreq] : *PGOBBE.Successors) {
186 CBA.writeULEB128(Val: ID);
187 CBA.writeULEB128(Val: BrProb);
188 if (FeatureOrErr->PostLinkCfg || PostLinkBrFreq.has_value())
189 CBA.writeULEB128(Val: PostLinkBrFreq.value_or(u: 0));
190 }
191 }
192 }
193 }
194}
195
196} // end namespace BBAddrMapYAML
197} // end namespace llvm
198