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