1 //===- MIRYamlMapping.h - Describe mapping between MIR and YAML--*- 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 // This file implements the mapping between various MIR data structures and 10 // their corresponding YAML representation. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #ifndef LLVM_CODEGEN_MIRYAMLMAPPING_H 15 #define LLVM_CODEGEN_MIRYAMLMAPPING_H 16 17 #include "llvm/ADT/StringRef.h" 18 #include "llvm/CodeGen/MachineJumpTableInfo.h" 19 #include "llvm/CodeGen/TargetFrameLowering.h" 20 #include "llvm/Support/SMLoc.h" 21 #include "llvm/Support/YAMLTraits.h" 22 #include "llvm/Support/raw_ostream.h" 23 #include <algorithm> 24 #include <cstdint> 25 #include <optional> 26 #include <string> 27 #include <vector> 28 29 namespace llvm { 30 namespace yaml { 31 32 /// A wrapper around std::string which contains a source range that's being 33 /// set during parsing. 34 struct StringValue { 35 std::string Value; 36 SMRange SourceRange; 37 38 StringValue() = default; StringValueStringValue39 StringValue(std::string Value) : Value(std::move(Value)) {} StringValueStringValue40 StringValue(const char Val[]) : Value(Val) {} 41 42 bool operator==(const StringValue &Other) const { 43 return Value == Other.Value; 44 } 45 }; 46 47 template <> struct ScalarTraits<StringValue> { 48 static void output(const StringValue &S, void *, raw_ostream &OS) { 49 OS << S.Value; 50 } 51 52 static StringRef input(StringRef Scalar, void *Ctx, StringValue &S) { 53 S.Value = Scalar.str(); 54 if (const auto *Node = 55 reinterpret_cast<yaml::Input *>(Ctx)->getCurrentNode()) 56 S.SourceRange = Node->getSourceRange(); 57 return ""; 58 } 59 60 static QuotingType mustQuote(StringRef S) { return needsQuotes(S); } 61 }; 62 63 struct FlowStringValue : StringValue { 64 FlowStringValue() = default; 65 FlowStringValue(std::string Value) : StringValue(std::move(Value)) {} 66 }; 67 68 template <> struct ScalarTraits<FlowStringValue> { 69 static void output(const FlowStringValue &S, void *, raw_ostream &OS) { 70 return ScalarTraits<StringValue>::output(S, nullptr, OS); 71 } 72 73 static StringRef input(StringRef Scalar, void *Ctx, FlowStringValue &S) { 74 return ScalarTraits<StringValue>::input(Scalar, Ctx, S); 75 } 76 77 static QuotingType mustQuote(StringRef S) { return needsQuotes(S); } 78 }; 79 80 struct BlockStringValue { 81 StringValue Value; 82 83 bool operator==(const BlockStringValue &Other) const { 84 return Value == Other.Value; 85 } 86 }; 87 88 template <> struct BlockScalarTraits<BlockStringValue> { 89 static void output(const BlockStringValue &S, void *Ctx, raw_ostream &OS) { 90 return ScalarTraits<StringValue>::output(S.Value, Ctx, OS); 91 } 92 93 static StringRef input(StringRef Scalar, void *Ctx, BlockStringValue &S) { 94 return ScalarTraits<StringValue>::input(Scalar, Ctx, S.Value); 95 } 96 }; 97 98 /// A wrapper around unsigned which contains a source range that's being set 99 /// during parsing. 100 struct UnsignedValue { 101 unsigned Value = 0; 102 SMRange SourceRange; 103 104 UnsignedValue() = default; 105 UnsignedValue(unsigned Value) : Value(Value) {} 106 107 bool operator==(const UnsignedValue &Other) const { 108 return Value == Other.Value; 109 } 110 }; 111 112 template <> struct ScalarTraits<UnsignedValue> { 113 static void output(const UnsignedValue &Value, void *Ctx, raw_ostream &OS) { 114 return ScalarTraits<unsigned>::output(Value.Value, Ctx, OS); 115 } 116 117 static StringRef input(StringRef Scalar, void *Ctx, UnsignedValue &Value) { 118 if (const auto *Node = 119 reinterpret_cast<yaml::Input *>(Ctx)->getCurrentNode()) 120 Value.SourceRange = Node->getSourceRange(); 121 return ScalarTraits<unsigned>::input(Scalar, Ctx, Value.Value); 122 } 123 124 static QuotingType mustQuote(StringRef Scalar) { 125 return ScalarTraits<unsigned>::mustQuote(Scalar); 126 } 127 }; 128 129 template <> struct ScalarEnumerationTraits<MachineJumpTableInfo::JTEntryKind> { 130 static void enumeration(yaml::IO &IO, 131 MachineJumpTableInfo::JTEntryKind &EntryKind) { 132 IO.enumCase(EntryKind, "block-address", 133 MachineJumpTableInfo::EK_BlockAddress); 134 IO.enumCase(EntryKind, "gp-rel64-block-address", 135 MachineJumpTableInfo::EK_GPRel64BlockAddress); 136 IO.enumCase(EntryKind, "gp-rel32-block-address", 137 MachineJumpTableInfo::EK_GPRel32BlockAddress); 138 IO.enumCase(EntryKind, "label-difference32", 139 MachineJumpTableInfo::EK_LabelDifference32); 140 IO.enumCase(EntryKind, "inline", MachineJumpTableInfo::EK_Inline); 141 IO.enumCase(EntryKind, "custom32", MachineJumpTableInfo::EK_Custom32); 142 } 143 }; 144 145 template <> struct ScalarTraits<MaybeAlign> { 146 static void output(const MaybeAlign &Alignment, void *, 147 llvm::raw_ostream &out) { 148 out << uint64_t(Alignment ? Alignment->value() : 0U); 149 } 150 static StringRef input(StringRef Scalar, void *, MaybeAlign &Alignment) { 151 unsigned long long n; 152 if (getAsUnsignedInteger(Scalar, 10, n)) 153 return "invalid number"; 154 if (n > 0 && !isPowerOf2_64(n)) 155 return "must be 0 or a power of two"; 156 Alignment = MaybeAlign(n); 157 return StringRef(); 158 } 159 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 160 }; 161 162 template <> struct ScalarTraits<Align> { 163 static void output(const Align &Alignment, void *, llvm::raw_ostream &OS) { 164 OS << Alignment.value(); 165 } 166 static StringRef input(StringRef Scalar, void *, Align &Alignment) { 167 unsigned long long N; 168 if (getAsUnsignedInteger(Scalar, 10, N)) 169 return "invalid number"; 170 if (!isPowerOf2_64(N)) 171 return "must be a power of two"; 172 Alignment = Align(N); 173 return StringRef(); 174 } 175 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 176 }; 177 178 } // end namespace yaml 179 } // end namespace llvm 180 181 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::StringValue) 182 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::FlowStringValue) 183 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::UnsignedValue) 184 185 namespace llvm { 186 namespace yaml { 187 188 struct VirtualRegisterDefinition { 189 UnsignedValue ID; 190 StringValue Class; 191 StringValue PreferredRegister; 192 193 // TODO: Serialize the target specific register hints. 194 195 bool operator==(const VirtualRegisterDefinition &Other) const { 196 return ID == Other.ID && Class == Other.Class && 197 PreferredRegister == Other.PreferredRegister; 198 } 199 }; 200 201 template <> struct MappingTraits<VirtualRegisterDefinition> { 202 static void mapping(IO &YamlIO, VirtualRegisterDefinition &Reg) { 203 YamlIO.mapRequired("id", Reg.ID); 204 YamlIO.mapRequired("class", Reg.Class); 205 YamlIO.mapOptional("preferred-register", Reg.PreferredRegister, 206 StringValue()); // Don't print out when it's empty. 207 } 208 209 static const bool flow = true; 210 }; 211 212 struct MachineFunctionLiveIn { 213 StringValue Register; 214 StringValue VirtualRegister; 215 216 bool operator==(const MachineFunctionLiveIn &Other) const { 217 return Register == Other.Register && 218 VirtualRegister == Other.VirtualRegister; 219 } 220 }; 221 222 template <> struct MappingTraits<MachineFunctionLiveIn> { 223 static void mapping(IO &YamlIO, MachineFunctionLiveIn &LiveIn) { 224 YamlIO.mapRequired("reg", LiveIn.Register); 225 YamlIO.mapOptional( 226 "virtual-reg", LiveIn.VirtualRegister, 227 StringValue()); // Don't print the virtual register when it's empty. 228 } 229 230 static const bool flow = true; 231 }; 232 233 /// Serializable representation of stack object from the MachineFrameInfo class. 234 /// 235 /// The flags 'isImmutable' and 'isAliased' aren't serialized, as they are 236 /// determined by the object's type and frame information flags. 237 /// Dead stack objects aren't serialized. 238 /// 239 /// The 'isPreallocated' flag is determined by the local offset. 240 struct MachineStackObject { 241 enum ObjectType { DefaultType, SpillSlot, VariableSized }; 242 UnsignedValue ID; 243 StringValue Name; 244 // TODO: Serialize unnamed LLVM alloca reference. 245 ObjectType Type = DefaultType; 246 int64_t Offset = 0; 247 uint64_t Size = 0; 248 MaybeAlign Alignment = std::nullopt; 249 TargetStackID::Value StackID; 250 StringValue CalleeSavedRegister; 251 bool CalleeSavedRestored = true; 252 std::optional<int64_t> LocalOffset; 253 StringValue DebugVar; 254 StringValue DebugExpr; 255 StringValue DebugLoc; 256 257 bool operator==(const MachineStackObject &Other) const { 258 return ID == Other.ID && Name == Other.Name && Type == Other.Type && 259 Offset == Other.Offset && Size == Other.Size && 260 Alignment == Other.Alignment && 261 StackID == Other.StackID && 262 CalleeSavedRegister == Other.CalleeSavedRegister && 263 CalleeSavedRestored == Other.CalleeSavedRestored && 264 LocalOffset == Other.LocalOffset && DebugVar == Other.DebugVar && 265 DebugExpr == Other.DebugExpr && DebugLoc == Other.DebugLoc; 266 } 267 }; 268 269 template <> struct ScalarEnumerationTraits<MachineStackObject::ObjectType> { 270 static void enumeration(yaml::IO &IO, MachineStackObject::ObjectType &Type) { 271 IO.enumCase(Type, "default", MachineStackObject::DefaultType); 272 IO.enumCase(Type, "spill-slot", MachineStackObject::SpillSlot); 273 IO.enumCase(Type, "variable-sized", MachineStackObject::VariableSized); 274 } 275 }; 276 277 template <> struct MappingTraits<MachineStackObject> { 278 static void mapping(yaml::IO &YamlIO, MachineStackObject &Object) { 279 YamlIO.mapRequired("id", Object.ID); 280 YamlIO.mapOptional("name", Object.Name, 281 StringValue()); // Don't print out an empty name. 282 YamlIO.mapOptional( 283 "type", Object.Type, 284 MachineStackObject::DefaultType); // Don't print the default type. 285 YamlIO.mapOptional("offset", Object.Offset, (int64_t)0); 286 if (Object.Type != MachineStackObject::VariableSized) 287 YamlIO.mapRequired("size", Object.Size); 288 YamlIO.mapOptional("alignment", Object.Alignment, std::nullopt); 289 YamlIO.mapOptional("stack-id", Object.StackID, TargetStackID::Default); 290 YamlIO.mapOptional("callee-saved-register", Object.CalleeSavedRegister, 291 StringValue()); // Don't print it out when it's empty. 292 YamlIO.mapOptional("callee-saved-restored", Object.CalleeSavedRestored, 293 true); 294 YamlIO.mapOptional("local-offset", Object.LocalOffset, 295 std::optional<int64_t>()); 296 YamlIO.mapOptional("debug-info-variable", Object.DebugVar, 297 StringValue()); // Don't print it out when it's empty. 298 YamlIO.mapOptional("debug-info-expression", Object.DebugExpr, 299 StringValue()); // Don't print it out when it's empty. 300 YamlIO.mapOptional("debug-info-location", Object.DebugLoc, 301 StringValue()); // Don't print it out when it's empty. 302 } 303 304 static const bool flow = true; 305 }; 306 307 /// Serializable representation of the fixed stack object from the 308 /// MachineFrameInfo class. 309 struct FixedMachineStackObject { 310 enum ObjectType { DefaultType, SpillSlot }; 311 UnsignedValue ID; 312 ObjectType Type = DefaultType; 313 int64_t Offset = 0; 314 uint64_t Size = 0; 315 MaybeAlign Alignment = std::nullopt; 316 TargetStackID::Value StackID; 317 bool IsImmutable = false; 318 bool IsAliased = false; 319 StringValue CalleeSavedRegister; 320 bool CalleeSavedRestored = true; 321 StringValue DebugVar; 322 StringValue DebugExpr; 323 StringValue DebugLoc; 324 325 bool operator==(const FixedMachineStackObject &Other) const { 326 return ID == Other.ID && Type == Other.Type && Offset == Other.Offset && 327 Size == Other.Size && Alignment == Other.Alignment && 328 StackID == Other.StackID && 329 IsImmutable == Other.IsImmutable && IsAliased == Other.IsAliased && 330 CalleeSavedRegister == Other.CalleeSavedRegister && 331 CalleeSavedRestored == Other.CalleeSavedRestored && 332 DebugVar == Other.DebugVar && DebugExpr == Other.DebugExpr 333 && DebugLoc == Other.DebugLoc; 334 } 335 }; 336 337 template <> 338 struct ScalarEnumerationTraits<FixedMachineStackObject::ObjectType> { 339 static void enumeration(yaml::IO &IO, 340 FixedMachineStackObject::ObjectType &Type) { 341 IO.enumCase(Type, "default", FixedMachineStackObject::DefaultType); 342 IO.enumCase(Type, "spill-slot", FixedMachineStackObject::SpillSlot); 343 } 344 }; 345 346 template <> 347 struct ScalarEnumerationTraits<TargetStackID::Value> { 348 static void enumeration(yaml::IO &IO, TargetStackID::Value &ID) { 349 IO.enumCase(ID, "default", TargetStackID::Default); 350 IO.enumCase(ID, "sgpr-spill", TargetStackID::SGPRSpill); 351 IO.enumCase(ID, "scalable-vector", TargetStackID::ScalableVector); 352 IO.enumCase(ID, "wasm-local", TargetStackID::WasmLocal); 353 IO.enumCase(ID, "noalloc", TargetStackID::NoAlloc); 354 } 355 }; 356 357 template <> struct MappingTraits<FixedMachineStackObject> { 358 static void mapping(yaml::IO &YamlIO, FixedMachineStackObject &Object) { 359 YamlIO.mapRequired("id", Object.ID); 360 YamlIO.mapOptional( 361 "type", Object.Type, 362 FixedMachineStackObject::DefaultType); // Don't print the default type. 363 YamlIO.mapOptional("offset", Object.Offset, (int64_t)0); 364 YamlIO.mapOptional("size", Object.Size, (uint64_t)0); 365 YamlIO.mapOptional("alignment", Object.Alignment, std::nullopt); 366 YamlIO.mapOptional("stack-id", Object.StackID, TargetStackID::Default); 367 if (Object.Type != FixedMachineStackObject::SpillSlot) { 368 YamlIO.mapOptional("isImmutable", Object.IsImmutable, false); 369 YamlIO.mapOptional("isAliased", Object.IsAliased, false); 370 } 371 YamlIO.mapOptional("callee-saved-register", Object.CalleeSavedRegister, 372 StringValue()); // Don't print it out when it's empty. 373 YamlIO.mapOptional("callee-saved-restored", Object.CalleeSavedRestored, 374 true); 375 YamlIO.mapOptional("debug-info-variable", Object.DebugVar, 376 StringValue()); // Don't print it out when it's empty. 377 YamlIO.mapOptional("debug-info-expression", Object.DebugExpr, 378 StringValue()); // Don't print it out when it's empty. 379 YamlIO.mapOptional("debug-info-location", Object.DebugLoc, 380 StringValue()); // Don't print it out when it's empty. 381 } 382 383 static const bool flow = true; 384 }; 385 386 /// A serializaable representation of a reference to a stack object or fixed 387 /// stack object. 388 struct FrameIndex { 389 // The frame index as printed. This is always a positive number, even for 390 // fixed objects. To obtain the real index, 391 // MachineFrameInfo::getObjectIndexBegin has to be added. 392 int FI; 393 bool IsFixed; 394 SMRange SourceRange; 395 396 FrameIndex() = default; 397 FrameIndex(int FI, const llvm::MachineFrameInfo &MFI); 398 399 Expected<int> getFI(const llvm::MachineFrameInfo &MFI) const; 400 }; 401 402 template <> struct ScalarTraits<FrameIndex> { 403 static void output(const FrameIndex &FI, void *, raw_ostream &OS) { 404 MachineOperand::printStackObjectReference(OS, FI.FI, FI.IsFixed, ""); 405 } 406 407 static StringRef input(StringRef Scalar, void *Ctx, FrameIndex &FI) { 408 FI.IsFixed = false; 409 StringRef Num; 410 if (Scalar.startswith("%stack.")) { 411 Num = Scalar.substr(7); 412 } else if (Scalar.startswith("%fixed-stack.")) { 413 Num = Scalar.substr(13); 414 FI.IsFixed = true; 415 } else { 416 return "Invalid frame index, needs to start with %stack. or " 417 "%fixed-stack."; 418 } 419 if (Num.consumeInteger(10, FI.FI)) 420 return "Invalid frame index, not a valid number"; 421 422 if (const auto *Node = 423 reinterpret_cast<yaml::Input *>(Ctx)->getCurrentNode()) 424 FI.SourceRange = Node->getSourceRange(); 425 return StringRef(); 426 } 427 428 static QuotingType mustQuote(StringRef S) { return needsQuotes(S); } 429 }; 430 431 /// Serializable representation of CallSiteInfo. 432 struct CallSiteInfo { 433 // Representation of call argument and register which is used to 434 // transfer it. 435 struct ArgRegPair { 436 StringValue Reg; 437 uint16_t ArgNo; 438 439 bool operator==(const ArgRegPair &Other) const { 440 return Reg == Other.Reg && ArgNo == Other.ArgNo; 441 } 442 }; 443 444 /// Identifies call instruction location in machine function. 445 struct MachineInstrLoc { 446 unsigned BlockNum; 447 unsigned Offset; 448 449 bool operator==(const MachineInstrLoc &Other) const { 450 return BlockNum == Other.BlockNum && Offset == Other.Offset; 451 } 452 }; 453 454 MachineInstrLoc CallLocation; 455 std::vector<ArgRegPair> ArgForwardingRegs; 456 457 bool operator==(const CallSiteInfo &Other) const { 458 return CallLocation.BlockNum == Other.CallLocation.BlockNum && 459 CallLocation.Offset == Other.CallLocation.Offset; 460 } 461 }; 462 463 template <> struct MappingTraits<CallSiteInfo::ArgRegPair> { 464 static void mapping(IO &YamlIO, CallSiteInfo::ArgRegPair &ArgReg) { 465 YamlIO.mapRequired("arg", ArgReg.ArgNo); 466 YamlIO.mapRequired("reg", ArgReg.Reg); 467 } 468 469 static const bool flow = true; 470 }; 471 } 472 } 473 474 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::CallSiteInfo::ArgRegPair) 475 476 namespace llvm { 477 namespace yaml { 478 479 template <> struct MappingTraits<CallSiteInfo> { 480 static void mapping(IO &YamlIO, CallSiteInfo &CSInfo) { 481 YamlIO.mapRequired("bb", CSInfo.CallLocation.BlockNum); 482 YamlIO.mapRequired("offset", CSInfo.CallLocation.Offset); 483 YamlIO.mapOptional("fwdArgRegs", CSInfo.ArgForwardingRegs, 484 std::vector<CallSiteInfo::ArgRegPair>()); 485 } 486 487 static const bool flow = true; 488 }; 489 490 /// Serializable representation of debug value substitutions. 491 struct DebugValueSubstitution { 492 unsigned SrcInst; 493 unsigned SrcOp; 494 unsigned DstInst; 495 unsigned DstOp; 496 unsigned Subreg; 497 498 bool operator==(const DebugValueSubstitution &Other) const { 499 return std::tie(SrcInst, SrcOp, DstInst, DstOp) == 500 std::tie(Other.SrcInst, Other.SrcOp, Other.DstInst, Other.DstOp); 501 } 502 }; 503 504 template <> struct MappingTraits<DebugValueSubstitution> { 505 static void mapping(IO &YamlIO, DebugValueSubstitution &Sub) { 506 YamlIO.mapRequired("srcinst", Sub.SrcInst); 507 YamlIO.mapRequired("srcop", Sub.SrcOp); 508 YamlIO.mapRequired("dstinst", Sub.DstInst); 509 YamlIO.mapRequired("dstop", Sub.DstOp); 510 YamlIO.mapRequired("subreg", Sub.Subreg); 511 } 512 513 static const bool flow = true; 514 }; 515 } // namespace yaml 516 } // namespace llvm 517 518 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::DebugValueSubstitution) 519 520 namespace llvm { 521 namespace yaml { 522 struct MachineConstantPoolValue { 523 UnsignedValue ID; 524 StringValue Value; 525 MaybeAlign Alignment = std::nullopt; 526 bool IsTargetSpecific = false; 527 528 bool operator==(const MachineConstantPoolValue &Other) const { 529 return ID == Other.ID && Value == Other.Value && 530 Alignment == Other.Alignment && 531 IsTargetSpecific == Other.IsTargetSpecific; 532 } 533 }; 534 535 template <> struct MappingTraits<MachineConstantPoolValue> { 536 static void mapping(IO &YamlIO, MachineConstantPoolValue &Constant) { 537 YamlIO.mapRequired("id", Constant.ID); 538 YamlIO.mapOptional("value", Constant.Value, StringValue()); 539 YamlIO.mapOptional("alignment", Constant.Alignment, std::nullopt); 540 YamlIO.mapOptional("isTargetSpecific", Constant.IsTargetSpecific, false); 541 } 542 }; 543 544 struct MachineJumpTable { 545 struct Entry { 546 UnsignedValue ID; 547 std::vector<FlowStringValue> Blocks; 548 549 bool operator==(const Entry &Other) const { 550 return ID == Other.ID && Blocks == Other.Blocks; 551 } 552 }; 553 554 MachineJumpTableInfo::JTEntryKind Kind = MachineJumpTableInfo::EK_Custom32; 555 std::vector<Entry> Entries; 556 557 bool operator==(const MachineJumpTable &Other) const { 558 return Kind == Other.Kind && Entries == Other.Entries; 559 } 560 }; 561 562 template <> struct MappingTraits<MachineJumpTable::Entry> { 563 static void mapping(IO &YamlIO, MachineJumpTable::Entry &Entry) { 564 YamlIO.mapRequired("id", Entry.ID); 565 YamlIO.mapOptional("blocks", Entry.Blocks, std::vector<FlowStringValue>()); 566 } 567 }; 568 569 } // end namespace yaml 570 } // end namespace llvm 571 572 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::MachineFunctionLiveIn) 573 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::VirtualRegisterDefinition) 574 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::MachineStackObject) 575 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::FixedMachineStackObject) 576 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::CallSiteInfo) 577 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::MachineConstantPoolValue) 578 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::MachineJumpTable::Entry) 579 580 namespace llvm { 581 namespace yaml { 582 583 template <> struct MappingTraits<MachineJumpTable> { 584 static void mapping(IO &YamlIO, MachineJumpTable &JT) { 585 YamlIO.mapRequired("kind", JT.Kind); 586 YamlIO.mapOptional("entries", JT.Entries, 587 std::vector<MachineJumpTable::Entry>()); 588 } 589 }; 590 591 /// Serializable representation of MachineFrameInfo. 592 /// 593 /// Doesn't serialize attributes like 'StackAlignment', 'IsStackRealignable' and 594 /// 'RealignOption' as they are determined by the target and LLVM function 595 /// attributes. 596 /// It also doesn't serialize attributes like 'NumFixedObject' and 597 /// 'HasVarSizedObjects' as they are determined by the frame objects themselves. 598 struct MachineFrameInfo { 599 bool IsFrameAddressTaken = false; 600 bool IsReturnAddressTaken = false; 601 bool HasStackMap = false; 602 bool HasPatchPoint = false; 603 uint64_t StackSize = 0; 604 int OffsetAdjustment = 0; 605 unsigned MaxAlignment = 0; 606 bool AdjustsStack = false; 607 bool HasCalls = false; 608 StringValue StackProtector; 609 StringValue FunctionContext; 610 unsigned MaxCallFrameSize = ~0u; ///< ~0u means: not computed yet. 611 unsigned CVBytesOfCalleeSavedRegisters = 0; 612 bool HasOpaqueSPAdjustment = false; 613 bool HasVAStart = false; 614 bool HasMustTailInVarArgFunc = false; 615 bool HasTailCall = false; 616 unsigned LocalFrameSize = 0; 617 StringValue SavePoint; 618 StringValue RestorePoint; 619 620 bool operator==(const MachineFrameInfo &Other) const { 621 return IsFrameAddressTaken == Other.IsFrameAddressTaken && 622 IsReturnAddressTaken == Other.IsReturnAddressTaken && 623 HasStackMap == Other.HasStackMap && 624 HasPatchPoint == Other.HasPatchPoint && 625 StackSize == Other.StackSize && 626 OffsetAdjustment == Other.OffsetAdjustment && 627 MaxAlignment == Other.MaxAlignment && 628 AdjustsStack == Other.AdjustsStack && HasCalls == Other.HasCalls && 629 StackProtector == Other.StackProtector && 630 FunctionContext == Other.FunctionContext && 631 MaxCallFrameSize == Other.MaxCallFrameSize && 632 CVBytesOfCalleeSavedRegisters == 633 Other.CVBytesOfCalleeSavedRegisters && 634 HasOpaqueSPAdjustment == Other.HasOpaqueSPAdjustment && 635 HasVAStart == Other.HasVAStart && 636 HasMustTailInVarArgFunc == Other.HasMustTailInVarArgFunc && 637 HasTailCall == Other.HasTailCall && 638 LocalFrameSize == Other.LocalFrameSize && 639 SavePoint == Other.SavePoint && RestorePoint == Other.RestorePoint; 640 } 641 }; 642 643 template <> struct MappingTraits<MachineFrameInfo> { 644 static void mapping(IO &YamlIO, MachineFrameInfo &MFI) { 645 YamlIO.mapOptional("isFrameAddressTaken", MFI.IsFrameAddressTaken, false); 646 YamlIO.mapOptional("isReturnAddressTaken", MFI.IsReturnAddressTaken, false); 647 YamlIO.mapOptional("hasStackMap", MFI.HasStackMap, false); 648 YamlIO.mapOptional("hasPatchPoint", MFI.HasPatchPoint, false); 649 YamlIO.mapOptional("stackSize", MFI.StackSize, (uint64_t)0); 650 YamlIO.mapOptional("offsetAdjustment", MFI.OffsetAdjustment, (int)0); 651 YamlIO.mapOptional("maxAlignment", MFI.MaxAlignment, (unsigned)0); 652 YamlIO.mapOptional("adjustsStack", MFI.AdjustsStack, false); 653 YamlIO.mapOptional("hasCalls", MFI.HasCalls, false); 654 YamlIO.mapOptional("stackProtector", MFI.StackProtector, 655 StringValue()); // Don't print it out when it's empty. 656 YamlIO.mapOptional("functionContext", MFI.FunctionContext, 657 StringValue()); // Don't print it out when it's empty. 658 YamlIO.mapOptional("maxCallFrameSize", MFI.MaxCallFrameSize, (unsigned)~0); 659 YamlIO.mapOptional("cvBytesOfCalleeSavedRegisters", 660 MFI.CVBytesOfCalleeSavedRegisters, 0U); 661 YamlIO.mapOptional("hasOpaqueSPAdjustment", MFI.HasOpaqueSPAdjustment, 662 false); 663 YamlIO.mapOptional("hasVAStart", MFI.HasVAStart, false); 664 YamlIO.mapOptional("hasMustTailInVarArgFunc", MFI.HasMustTailInVarArgFunc, 665 false); 666 YamlIO.mapOptional("hasTailCall", MFI.HasTailCall, false); 667 YamlIO.mapOptional("localFrameSize", MFI.LocalFrameSize, (unsigned)0); 668 YamlIO.mapOptional("savePoint", MFI.SavePoint, 669 StringValue()); // Don't print it out when it's empty. 670 YamlIO.mapOptional("restorePoint", MFI.RestorePoint, 671 StringValue()); // Don't print it out when it's empty. 672 } 673 }; 674 675 /// Targets should override this in a way that mirrors the implementation of 676 /// llvm::MachineFunctionInfo. 677 struct MachineFunctionInfo { 678 virtual ~MachineFunctionInfo() = default; 679 virtual void mappingImpl(IO &YamlIO) {} 680 }; 681 682 template <> struct MappingTraits<std::unique_ptr<MachineFunctionInfo>> { 683 static void mapping(IO &YamlIO, std::unique_ptr<MachineFunctionInfo> &MFI) { 684 if (MFI) 685 MFI->mappingImpl(YamlIO); 686 } 687 }; 688 689 struct MachineFunction { 690 StringRef Name; 691 MaybeAlign Alignment = std::nullopt; 692 bool ExposesReturnsTwice = false; 693 // GISel MachineFunctionProperties. 694 bool Legalized = false; 695 bool RegBankSelected = false; 696 bool Selected = false; 697 bool FailedISel = false; 698 // Register information 699 bool TracksRegLiveness = false; 700 bool HasWinCFI = false; 701 702 bool CallsEHReturn = false; 703 bool CallsUnwindInit = false; 704 bool HasEHCatchret = false; 705 bool HasEHScopes = false; 706 bool HasEHFunclets = false; 707 708 bool FailsVerification = false; 709 bool TracksDebugUserValues = false; 710 bool UseDebugInstrRef = false; 711 std::vector<VirtualRegisterDefinition> VirtualRegisters; 712 std::vector<MachineFunctionLiveIn> LiveIns; 713 std::optional<std::vector<FlowStringValue>> CalleeSavedRegisters; 714 // TODO: Serialize the various register masks. 715 // Frame information 716 MachineFrameInfo FrameInfo; 717 std::vector<FixedMachineStackObject> FixedStackObjects; 718 std::vector<MachineStackObject> StackObjects; 719 std::vector<MachineConstantPoolValue> Constants; /// Constant pool. 720 std::unique_ptr<MachineFunctionInfo> MachineFuncInfo; 721 std::vector<CallSiteInfo> CallSitesInfo; 722 std::vector<DebugValueSubstitution> DebugValueSubstitutions; 723 MachineJumpTable JumpTableInfo; 724 std::vector<StringValue> MachineMetadataNodes; 725 BlockStringValue Body; 726 }; 727 728 template <> struct MappingTraits<MachineFunction> { 729 static void mapping(IO &YamlIO, MachineFunction &MF) { 730 YamlIO.mapRequired("name", MF.Name); 731 YamlIO.mapOptional("alignment", MF.Alignment, std::nullopt); 732 YamlIO.mapOptional("exposesReturnsTwice", MF.ExposesReturnsTwice, false); 733 YamlIO.mapOptional("legalized", MF.Legalized, false); 734 YamlIO.mapOptional("regBankSelected", MF.RegBankSelected, false); 735 YamlIO.mapOptional("selected", MF.Selected, false); 736 YamlIO.mapOptional("failedISel", MF.FailedISel, false); 737 YamlIO.mapOptional("tracksRegLiveness", MF.TracksRegLiveness, false); 738 YamlIO.mapOptional("hasWinCFI", MF.HasWinCFI, false); 739 740 YamlIO.mapOptional("callsEHReturn", MF.CallsEHReturn, false); 741 YamlIO.mapOptional("callsUnwindInit", MF.CallsUnwindInit, false); 742 YamlIO.mapOptional("hasEHCatchret", MF.HasEHCatchret, false); 743 YamlIO.mapOptional("hasEHScopes", MF.HasEHScopes, false); 744 YamlIO.mapOptional("hasEHFunclets", MF.HasEHFunclets, false); 745 YamlIO.mapOptional("debugInstrRef", MF.UseDebugInstrRef, false); 746 747 YamlIO.mapOptional("failsVerification", MF.FailsVerification, false); 748 YamlIO.mapOptional("tracksDebugUserValues", MF.TracksDebugUserValues, 749 false); 750 YamlIO.mapOptional("registers", MF.VirtualRegisters, 751 std::vector<VirtualRegisterDefinition>()); 752 YamlIO.mapOptional("liveins", MF.LiveIns, 753 std::vector<MachineFunctionLiveIn>()); 754 YamlIO.mapOptional("calleeSavedRegisters", MF.CalleeSavedRegisters, 755 std::optional<std::vector<FlowStringValue>>()); 756 YamlIO.mapOptional("frameInfo", MF.FrameInfo, MachineFrameInfo()); 757 YamlIO.mapOptional("fixedStack", MF.FixedStackObjects, 758 std::vector<FixedMachineStackObject>()); 759 YamlIO.mapOptional("stack", MF.StackObjects, 760 std::vector<MachineStackObject>()); 761 YamlIO.mapOptional("callSites", MF.CallSitesInfo, 762 std::vector<CallSiteInfo>()); 763 YamlIO.mapOptional("debugValueSubstitutions", MF.DebugValueSubstitutions, 764 std::vector<DebugValueSubstitution>()); 765 YamlIO.mapOptional("constants", MF.Constants, 766 std::vector<MachineConstantPoolValue>()); 767 YamlIO.mapOptional("machineFunctionInfo", MF.MachineFuncInfo); 768 if (!YamlIO.outputting() || !MF.JumpTableInfo.Entries.empty()) 769 YamlIO.mapOptional("jumpTable", MF.JumpTableInfo, MachineJumpTable()); 770 if (!YamlIO.outputting() || !MF.MachineMetadataNodes.empty()) 771 YamlIO.mapOptional("machineMetadataNodes", MF.MachineMetadataNodes, 772 std::vector<StringValue>()); 773 YamlIO.mapOptional("body", MF.Body, BlockStringValue()); 774 } 775 }; 776 777 } // end namespace yaml 778 } // end namespace llvm 779 780 #endif // LLVM_CODEGEN_MIRYAMLMAPPING_H 781