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