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