xref: /freebsd/contrib/llvm-project/llvm/include/llvm/IR/ModuleSummaryIndexYAML.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
1 //===-- llvm/ModuleSummaryIndexYAML.h - YAML I/O for summary ----*- 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 #ifndef LLVM_IR_MODULESUMMARYINDEXYAML_H
10 #define LLVM_IR_MODULESUMMARYINDEXYAML_H
11 
12 #include "llvm/ADT/StringRef.h"
13 #include "llvm/IR/ModuleSummaryIndex.h"
14 #include "llvm/Support/YAMLTraits.h"
15 #include <algorithm>
16 
17 namespace llvm {
18 namespace yaml {
19 
20 template <> struct ScalarEnumerationTraits<TypeTestResolution::Kind> {
21   static void enumeration(IO &io, TypeTestResolution::Kind &value) {
22     io.enumCase(value, "Unknown", TypeTestResolution::Unknown);
23     io.enumCase(value, "Unsat", TypeTestResolution::Unsat);
24     io.enumCase(value, "ByteArray", TypeTestResolution::ByteArray);
25     io.enumCase(value, "Inline", TypeTestResolution::Inline);
26     io.enumCase(value, "Single", TypeTestResolution::Single);
27     io.enumCase(value, "AllOnes", TypeTestResolution::AllOnes);
28   }
29 };
30 
31 template <> struct MappingTraits<TypeTestResolution> {
32   static void mapping(IO &io, TypeTestResolution &res) {
33     io.mapOptional("Kind", res.TheKind);
34     io.mapOptional("SizeM1BitWidth", res.SizeM1BitWidth);
35     io.mapOptional("AlignLog2", res.AlignLog2);
36     io.mapOptional("SizeM1", res.SizeM1);
37     io.mapOptional("BitMask", res.BitMask);
38     io.mapOptional("InlineBits", res.InlineBits);
39   }
40 };
41 
42 template <>
43 struct ScalarEnumerationTraits<WholeProgramDevirtResolution::ByArg::Kind> {
44   static void enumeration(IO &io,
45                           WholeProgramDevirtResolution::ByArg::Kind &value) {
46     io.enumCase(value, "Indir", WholeProgramDevirtResolution::ByArg::Indir);
47     io.enumCase(value, "UniformRetVal",
48                 WholeProgramDevirtResolution::ByArg::UniformRetVal);
49     io.enumCase(value, "UniqueRetVal",
50                 WholeProgramDevirtResolution::ByArg::UniqueRetVal);
51     io.enumCase(value, "VirtualConstProp",
52                 WholeProgramDevirtResolution::ByArg::VirtualConstProp);
53   }
54 };
55 
56 template <> struct MappingTraits<WholeProgramDevirtResolution::ByArg> {
57   static void mapping(IO &io, WholeProgramDevirtResolution::ByArg &res) {
58     io.mapOptional("Kind", res.TheKind);
59     io.mapOptional("Info", res.Info);
60     io.mapOptional("Byte", res.Byte);
61     io.mapOptional("Bit", res.Bit);
62   }
63 };
64 
65 template <>
66 struct CustomMappingTraits<
67     std::map<std::vector<uint64_t>, WholeProgramDevirtResolution::ByArg>> {
68   static void inputOne(
69       IO &io, StringRef Key,
70       std::map<std::vector<uint64_t>, WholeProgramDevirtResolution::ByArg> &V) {
71     std::vector<uint64_t> Args;
72     std::pair<StringRef, StringRef> P = {"", Key};
73     while (!P.second.empty()) {
74       P = P.second.split(',');
75       uint64_t Arg;
76       if (P.first.getAsInteger(0, Arg)) {
77         io.setError("key not an integer");
78         return;
79       }
80       Args.push_back(Arg);
81     }
82     io.mapRequired(Key.str().c_str(), V[Args]);
83   }
84   static void output(
85       IO &io,
86       std::map<std::vector<uint64_t>, WholeProgramDevirtResolution::ByArg> &V) {
87     for (auto &P : V) {
88       std::string Key;
89       for (uint64_t Arg : P.first) {
90         if (!Key.empty())
91           Key += ',';
92         Key += llvm::utostr(Arg);
93       }
94       io.mapRequired(Key.c_str(), P.second);
95     }
96   }
97 };
98 
99 template <> struct ScalarEnumerationTraits<WholeProgramDevirtResolution::Kind> {
100   static void enumeration(IO &io, WholeProgramDevirtResolution::Kind &value) {
101     io.enumCase(value, "Indir", WholeProgramDevirtResolution::Indir);
102     io.enumCase(value, "SingleImpl", WholeProgramDevirtResolution::SingleImpl);
103     io.enumCase(value, "BranchFunnel",
104                 WholeProgramDevirtResolution::BranchFunnel);
105   }
106 };
107 
108 template <> struct MappingTraits<WholeProgramDevirtResolution> {
109   static void mapping(IO &io, WholeProgramDevirtResolution &res) {
110     io.mapOptional("Kind", res.TheKind);
111     io.mapOptional("SingleImplName", res.SingleImplName);
112     io.mapOptional("ResByArg", res.ResByArg);
113   }
114 };
115 
116 template <>
117 struct CustomMappingTraits<std::map<uint64_t, WholeProgramDevirtResolution>> {
118   static void inputOne(IO &io, StringRef Key,
119                        std::map<uint64_t, WholeProgramDevirtResolution> &V) {
120     uint64_t KeyInt;
121     if (Key.getAsInteger(0, KeyInt)) {
122       io.setError("key not an integer");
123       return;
124     }
125     io.mapRequired(Key.str().c_str(), V[KeyInt]);
126   }
127   static void output(IO &io, std::map<uint64_t, WholeProgramDevirtResolution> &V) {
128     for (auto &P : V)
129       io.mapRequired(llvm::utostr(P.first).c_str(), P.second);
130   }
131 };
132 
133 template <> struct MappingTraits<TypeIdSummary> {
134   static void mapping(IO &io, TypeIdSummary& summary) {
135     io.mapOptional("TTRes", summary.TTRes);
136     io.mapOptional("WPDRes", summary.WPDRes);
137   }
138 };
139 
140 struct GlobalValueSummaryYaml {
141   // Commonly used fields
142   unsigned Linkage, Visibility;
143   bool NotEligibleToImport, Live, IsLocal, CanAutoHide;
144   unsigned ImportType;
145   // Fields for AliasSummary
146   std::optional<uint64_t> Aliasee;
147   // Fields for FunctionSummary
148   std::vector<uint64_t> Refs = {};
149   std::vector<uint64_t> TypeTests = {};
150   std::vector<FunctionSummary::VFuncId> TypeTestAssumeVCalls = {};
151   std::vector<FunctionSummary::VFuncId> TypeCheckedLoadVCalls = {};
152   std::vector<FunctionSummary::ConstVCall> TypeTestAssumeConstVCalls = {};
153   std::vector<FunctionSummary::ConstVCall> TypeCheckedLoadConstVCalls = {};
154 };
155 
156 } // End yaml namespace
157 } // End llvm namespace
158 
159 namespace llvm {
160 namespace yaml {
161 
162 template <> struct MappingTraits<FunctionSummary::VFuncId> {
163   static void mapping(IO &io, FunctionSummary::VFuncId& id) {
164     io.mapOptional("GUID", id.GUID);
165     io.mapOptional("Offset", id.Offset);
166   }
167 };
168 
169 template <> struct MappingTraits<FunctionSummary::ConstVCall> {
170   static void mapping(IO &io, FunctionSummary::ConstVCall& id) {
171     io.mapOptional("VFunc", id.VFunc);
172     io.mapOptional("Args", id.Args);
173   }
174 };
175 
176 } // End yaml namespace
177 } // End llvm namespace
178 
179 LLVM_YAML_IS_SEQUENCE_VECTOR(FunctionSummary::VFuncId)
180 LLVM_YAML_IS_SEQUENCE_VECTOR(FunctionSummary::ConstVCall)
181 
182 namespace llvm {
183 namespace yaml {
184 
185 template <> struct MappingTraits<GlobalValueSummaryYaml> {
186   static void mapping(IO &io, GlobalValueSummaryYaml &summary) {
187     io.mapOptional("Linkage", summary.Linkage);
188     io.mapOptional("Visibility", summary.Visibility);
189     io.mapOptional("NotEligibleToImport", summary.NotEligibleToImport);
190     io.mapOptional("Live", summary.Live);
191     io.mapOptional("Local", summary.IsLocal);
192     io.mapOptional("CanAutoHide", summary.CanAutoHide);
193     io.mapOptional("ImportType", summary.ImportType);
194     io.mapOptional("Aliasee", summary.Aliasee);
195     io.mapOptional("Refs", summary.Refs);
196     io.mapOptional("TypeTests", summary.TypeTests);
197     io.mapOptional("TypeTestAssumeVCalls", summary.TypeTestAssumeVCalls);
198     io.mapOptional("TypeCheckedLoadVCalls", summary.TypeCheckedLoadVCalls);
199     io.mapOptional("TypeTestAssumeConstVCalls",
200                    summary.TypeTestAssumeConstVCalls);
201     io.mapOptional("TypeCheckedLoadConstVCalls",
202                    summary.TypeCheckedLoadConstVCalls);
203   }
204 };
205 
206 } // End yaml namespace
207 } // End llvm namespace
208 
209 LLVM_YAML_IS_SEQUENCE_VECTOR(GlobalValueSummaryYaml)
210 
211 namespace llvm {
212 namespace yaml {
213 
214 // FIXME: Add YAML mappings for the rest of the module summary.
215 template <> struct CustomMappingTraits<GlobalValueSummaryMapTy> {
216   static void inputOne(IO &io, StringRef Key, GlobalValueSummaryMapTy &V) {
217     std::vector<GlobalValueSummaryYaml> GVSums;
218     io.mapRequired(Key.str().c_str(), GVSums);
219     uint64_t KeyInt;
220     if (Key.getAsInteger(0, KeyInt)) {
221       io.setError("key not an integer");
222       return;
223     }
224     auto &Elem = V.try_emplace(KeyInt, /*IsAnalysis=*/false).first->second;
225     for (auto &GVSum : GVSums) {
226       GlobalValueSummary::GVFlags GVFlags(
227           static_cast<GlobalValue::LinkageTypes>(GVSum.Linkage),
228           static_cast<GlobalValue::VisibilityTypes>(GVSum.Visibility),
229           GVSum.NotEligibleToImport, GVSum.Live, GVSum.IsLocal,
230           GVSum.CanAutoHide,
231           static_cast<GlobalValueSummary::ImportKind>(GVSum.ImportType));
232       if (GVSum.Aliasee) {
233         auto ASum = std::make_unique<AliasSummary>(GVFlags);
234         V.try_emplace(*GVSum.Aliasee, /*IsAnalysis=*/false);
235         ValueInfo AliaseeVI(/*IsAnalysis=*/false, &*V.find(*GVSum.Aliasee));
236         // Note: Aliasee cannot be filled until all summaries are loaded.
237         // This is done in fixAliaseeLinks() which is called in
238         // MappingTraits<ModuleSummaryIndex>::mapping().
239         ASum->setAliasee(AliaseeVI, /*Aliasee=*/nullptr);
240         Elem.SummaryList.push_back(std::move(ASum));
241         continue;
242       }
243       SmallVector<ValueInfo, 0> Refs;
244       Refs.reserve(GVSum.Refs.size());
245       for (auto &RefGUID : GVSum.Refs) {
246         auto It = V.try_emplace(RefGUID, /*IsAnalysis=*/false).first;
247         Refs.push_back(ValueInfo(/*IsAnalysis=*/false, &*It));
248       }
249       Elem.SummaryList.push_back(std::make_unique<FunctionSummary>(
250           GVFlags, /*NumInsts=*/0, FunctionSummary::FFlags{}, std::move(Refs),
251           SmallVector<FunctionSummary::EdgeTy, 0>{}, std::move(GVSum.TypeTests),
252           std::move(GVSum.TypeTestAssumeVCalls),
253           std::move(GVSum.TypeCheckedLoadVCalls),
254           std::move(GVSum.TypeTestAssumeConstVCalls),
255           std::move(GVSum.TypeCheckedLoadConstVCalls),
256           ArrayRef<FunctionSummary::ParamAccess>{}, ArrayRef<CallsiteInfo>{},
257           ArrayRef<AllocInfo>{}));
258     }
259   }
260   static void output(IO &io, GlobalValueSummaryMapTy &V) {
261     for (auto &P : V) {
262       std::vector<GlobalValueSummaryYaml> GVSums;
263       for (auto &Sum : P.second.SummaryList) {
264         if (auto *FSum = dyn_cast<FunctionSummary>(Sum.get())) {
265           std::vector<uint64_t> Refs;
266           Refs.reserve(FSum->refs().size());
267           for (auto &VI : FSum->refs())
268             Refs.push_back(VI.getGUID());
269           GVSums.push_back(GlobalValueSummaryYaml{
270               FSum->flags().Linkage, FSum->flags().Visibility,
271               static_cast<bool>(FSum->flags().NotEligibleToImport),
272               static_cast<bool>(FSum->flags().Live),
273               static_cast<bool>(FSum->flags().DSOLocal),
274               static_cast<bool>(FSum->flags().CanAutoHide),
275               FSum->flags().ImportType, /*Aliasee=*/std::nullopt, Refs,
276               FSum->type_tests(), FSum->type_test_assume_vcalls(),
277               FSum->type_checked_load_vcalls(),
278               FSum->type_test_assume_const_vcalls(),
279               FSum->type_checked_load_const_vcalls()});
280         } else if (auto *ASum = dyn_cast<AliasSummary>(Sum.get());
281                    ASum && ASum->hasAliasee()) {
282           GVSums.push_back(GlobalValueSummaryYaml{
283               ASum->flags().Linkage, ASum->flags().Visibility,
284               static_cast<bool>(ASum->flags().NotEligibleToImport),
285               static_cast<bool>(ASum->flags().Live),
286               static_cast<bool>(ASum->flags().DSOLocal),
287               static_cast<bool>(ASum->flags().CanAutoHide),
288               ASum->flags().ImportType,
289               /*Aliasee=*/ASum->getAliaseeGUID()});
290         }
291       }
292       if (!GVSums.empty())
293         io.mapRequired(llvm::utostr(P.first).c_str(), GVSums);
294     }
295   }
296   static void fixAliaseeLinks(GlobalValueSummaryMapTy &V) {
297     for (auto &P : V) {
298       for (auto &Sum : P.second.SummaryList) {
299         if (auto *Alias = dyn_cast<AliasSummary>(Sum.get())) {
300           ValueInfo AliaseeVI = Alias->getAliaseeVI();
301           auto AliaseeSL = AliaseeVI.getSummaryList();
302           if (AliaseeSL.empty()) {
303             ValueInfo EmptyVI;
304             Alias->setAliasee(EmptyVI, nullptr);
305           } else
306             Alias->setAliasee(AliaseeVI, AliaseeSL[0].get());
307         }
308       }
309     }
310   }
311 };
312 
313 template <> struct CustomMappingTraits<TypeIdSummaryMapTy> {
314   static void inputOne(IO &io, StringRef Key, TypeIdSummaryMapTy &V) {
315     TypeIdSummary TId;
316     io.mapRequired(Key.str().c_str(), TId);
317     V.insert({GlobalValue::getGUIDAssumingExternalLinkage(Key), {Key, TId}});
318   }
319   static void output(IO &io, TypeIdSummaryMapTy &V) {
320     for (auto &TidIter : V)
321       io.mapRequired(TidIter.second.first.str().c_str(), TidIter.second.second);
322   }
323 };
324 
325 template <> struct MappingTraits<ModuleSummaryIndex> {
326   static void mapping(IO &io, ModuleSummaryIndex& index) {
327     io.mapOptional("GlobalValueMap", index.GlobalValueMap);
328     if (!io.outputting())
329       CustomMappingTraits<GlobalValueSummaryMapTy>::fixAliaseeLinks(
330           index.GlobalValueMap);
331 
332     if (io.outputting()) {
333       io.mapOptional("TypeIdMap", index.TypeIdMap);
334     } else {
335       TypeIdSummaryMapTy TypeIdMap;
336       io.mapOptional("TypeIdMap", TypeIdMap);
337       for (auto &[TypeGUID, TypeIdSummaryMap] : TypeIdMap) {
338         // Save type id references in index and point TypeIdMap to use the
339         // references owned by index.
340         StringRef KeyRef = index.TypeIdSaver.save(TypeIdSummaryMap.first);
341         index.TypeIdMap.insert(
342             {TypeGUID, {KeyRef, std::move(TypeIdSummaryMap.second)}});
343       }
344     }
345 
346     io.mapOptional("WithGlobalValueDeadStripping",
347                    index.WithGlobalValueDeadStripping);
348 
349     if (io.outputting()) {
350       auto CfiFunctionDefs = index.CfiFunctionDefs.symbols();
351       llvm::sort(CfiFunctionDefs);
352       io.mapOptional("CfiFunctionDefs", CfiFunctionDefs);
353       auto CfiFunctionDecls(index.CfiFunctionDecls.symbols());
354       llvm::sort(CfiFunctionDecls);
355       io.mapOptional("CfiFunctionDecls", CfiFunctionDecls);
356     } else {
357       std::vector<std::string> CfiFunctionDefs;
358       io.mapOptional("CfiFunctionDefs", CfiFunctionDefs);
359       index.CfiFunctionDefs = {CfiFunctionDefs.begin(), CfiFunctionDefs.end()};
360       std::vector<std::string> CfiFunctionDecls;
361       io.mapOptional("CfiFunctionDecls", CfiFunctionDecls);
362       index.CfiFunctionDecls = {CfiFunctionDecls.begin(),
363                                 CfiFunctionDecls.end()};
364     }
365   }
366 };
367 
368 } // End yaml namespace
369 } // End llvm namespace
370 
371 #endif
372