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;
39   StringValue(std::string Value) : Value(std::move(Value)) {}
40   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 MCRegister variant of
308 /// MachineFunction::VariableDbgInfo.
309 struct EntryValueObject {
310   StringValue EntryValueRegister;
311   StringValue DebugVar;
312   StringValue DebugExpr;
313   StringValue DebugLoc;
314   bool operator==(const EntryValueObject &Other) const {
315     return EntryValueRegister == Other.EntryValueRegister &&
316            DebugVar == Other.DebugVar && DebugExpr == Other.DebugExpr &&
317            DebugLoc == Other.DebugLoc;
318   }
319 };
320 
321 template <> struct MappingTraits<EntryValueObject> {
322   static void mapping(yaml::IO &YamlIO, EntryValueObject &Object) {
323     YamlIO.mapRequired("entry-value-register", Object.EntryValueRegister);
324     YamlIO.mapRequired("debug-info-variable", Object.DebugVar);
325     YamlIO.mapRequired("debug-info-expression", Object.DebugExpr);
326     YamlIO.mapRequired("debug-info-location", Object.DebugLoc);
327   }
328   static const bool flow = true;
329 };
330 
331 /// Serializable representation of the fixed stack object from the
332 /// MachineFrameInfo class.
333 struct FixedMachineStackObject {
334   enum ObjectType { DefaultType, SpillSlot };
335   UnsignedValue ID;
336   ObjectType Type = DefaultType;
337   int64_t Offset = 0;
338   uint64_t Size = 0;
339   MaybeAlign Alignment = std::nullopt;
340   TargetStackID::Value StackID;
341   bool IsImmutable = false;
342   bool IsAliased = false;
343   StringValue CalleeSavedRegister;
344   bool CalleeSavedRestored = true;
345   StringValue DebugVar;
346   StringValue DebugExpr;
347   StringValue DebugLoc;
348 
349   bool operator==(const FixedMachineStackObject &Other) const {
350     return ID == Other.ID && Type == Other.Type && Offset == Other.Offset &&
351            Size == Other.Size && Alignment == Other.Alignment &&
352            StackID == Other.StackID &&
353            IsImmutable == Other.IsImmutable && IsAliased == Other.IsAliased &&
354            CalleeSavedRegister == Other.CalleeSavedRegister &&
355            CalleeSavedRestored == Other.CalleeSavedRestored &&
356            DebugVar == Other.DebugVar && DebugExpr == Other.DebugExpr
357            && DebugLoc == Other.DebugLoc;
358   }
359 };
360 
361 template <>
362 struct ScalarEnumerationTraits<FixedMachineStackObject::ObjectType> {
363   static void enumeration(yaml::IO &IO,
364                           FixedMachineStackObject::ObjectType &Type) {
365     IO.enumCase(Type, "default", FixedMachineStackObject::DefaultType);
366     IO.enumCase(Type, "spill-slot", FixedMachineStackObject::SpillSlot);
367   }
368 };
369 
370 template <>
371 struct ScalarEnumerationTraits<TargetStackID::Value> {
372   static void enumeration(yaml::IO &IO, TargetStackID::Value &ID) {
373     IO.enumCase(ID, "default", TargetStackID::Default);
374     IO.enumCase(ID, "sgpr-spill", TargetStackID::SGPRSpill);
375     IO.enumCase(ID, "scalable-vector", TargetStackID::ScalableVector);
376     IO.enumCase(ID, "wasm-local", TargetStackID::WasmLocal);
377     IO.enumCase(ID, "noalloc", TargetStackID::NoAlloc);
378   }
379 };
380 
381 template <> struct MappingTraits<FixedMachineStackObject> {
382   static void mapping(yaml::IO &YamlIO, FixedMachineStackObject &Object) {
383     YamlIO.mapRequired("id", Object.ID);
384     YamlIO.mapOptional(
385         "type", Object.Type,
386         FixedMachineStackObject::DefaultType); // Don't print the default type.
387     YamlIO.mapOptional("offset", Object.Offset, (int64_t)0);
388     YamlIO.mapOptional("size", Object.Size, (uint64_t)0);
389     YamlIO.mapOptional("alignment", Object.Alignment, std::nullopt);
390     YamlIO.mapOptional("stack-id", Object.StackID, TargetStackID::Default);
391     if (Object.Type != FixedMachineStackObject::SpillSlot) {
392       YamlIO.mapOptional("isImmutable", Object.IsImmutable, false);
393       YamlIO.mapOptional("isAliased", Object.IsAliased, false);
394     }
395     YamlIO.mapOptional("callee-saved-register", Object.CalleeSavedRegister,
396                        StringValue()); // Don't print it out when it's empty.
397     YamlIO.mapOptional("callee-saved-restored", Object.CalleeSavedRestored,
398                      true);
399     YamlIO.mapOptional("debug-info-variable", Object.DebugVar,
400                        StringValue()); // Don't print it out when it's empty.
401     YamlIO.mapOptional("debug-info-expression", Object.DebugExpr,
402                        StringValue()); // Don't print it out when it's empty.
403     YamlIO.mapOptional("debug-info-location", Object.DebugLoc,
404                        StringValue()); // Don't print it out when it's empty.
405   }
406 
407   static const bool flow = true;
408 };
409 
410 /// A serializaable representation of a reference to a stack object or fixed
411 /// stack object.
412 struct FrameIndex {
413   // The frame index as printed. This is always a positive number, even for
414   // fixed objects. To obtain the real index,
415   // MachineFrameInfo::getObjectIndexBegin has to be added.
416   int FI;
417   bool IsFixed;
418   SMRange SourceRange;
419 
420   FrameIndex() = default;
421   FrameIndex(int FI, const llvm::MachineFrameInfo &MFI);
422 
423   Expected<int> getFI(const llvm::MachineFrameInfo &MFI) const;
424 };
425 
426 template <> struct ScalarTraits<FrameIndex> {
427   static void output(const FrameIndex &FI, void *, raw_ostream &OS) {
428     MachineOperand::printStackObjectReference(OS, FI.FI, FI.IsFixed, "");
429   }
430 
431   static StringRef input(StringRef Scalar, void *Ctx, FrameIndex &FI) {
432     FI.IsFixed = false;
433     StringRef Num;
434     if (Scalar.startswith("%stack.")) {
435       Num = Scalar.substr(7);
436     } else if (Scalar.startswith("%fixed-stack.")) {
437       Num = Scalar.substr(13);
438       FI.IsFixed = true;
439     } else {
440       return "Invalid frame index, needs to start with %stack. or "
441              "%fixed-stack.";
442     }
443     if (Num.consumeInteger(10, FI.FI))
444       return "Invalid frame index, not a valid number";
445 
446     if (const auto *Node =
447             reinterpret_cast<yaml::Input *>(Ctx)->getCurrentNode())
448       FI.SourceRange = Node->getSourceRange();
449     return StringRef();
450   }
451 
452   static QuotingType mustQuote(StringRef S) { return needsQuotes(S); }
453 };
454 
455 /// Serializable representation of CallSiteInfo.
456 struct CallSiteInfo {
457   // Representation of call argument and register which is used to
458   // transfer it.
459   struct ArgRegPair {
460     StringValue Reg;
461     uint16_t ArgNo;
462 
463     bool operator==(const ArgRegPair &Other) const {
464       return Reg == Other.Reg && ArgNo == Other.ArgNo;
465     }
466   };
467 
468   /// Identifies call instruction location in machine function.
469   struct MachineInstrLoc {
470     unsigned BlockNum;
471     unsigned Offset;
472 
473     bool operator==(const MachineInstrLoc &Other) const {
474       return BlockNum == Other.BlockNum && Offset == Other.Offset;
475     }
476   };
477 
478   MachineInstrLoc CallLocation;
479   std::vector<ArgRegPair> ArgForwardingRegs;
480 
481   bool operator==(const CallSiteInfo &Other) const {
482     return CallLocation.BlockNum == Other.CallLocation.BlockNum &&
483            CallLocation.Offset == Other.CallLocation.Offset;
484   }
485 };
486 
487 template <> struct MappingTraits<CallSiteInfo::ArgRegPair> {
488   static void mapping(IO &YamlIO, CallSiteInfo::ArgRegPair &ArgReg) {
489     YamlIO.mapRequired("arg", ArgReg.ArgNo);
490     YamlIO.mapRequired("reg", ArgReg.Reg);
491   }
492 
493   static const bool flow = true;
494 };
495 }
496 }
497 
498 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::CallSiteInfo::ArgRegPair)
499 
500 namespace llvm {
501 namespace yaml {
502 
503 template <> struct MappingTraits<CallSiteInfo> {
504   static void mapping(IO &YamlIO, CallSiteInfo &CSInfo) {
505     YamlIO.mapRequired("bb", CSInfo.CallLocation.BlockNum);
506     YamlIO.mapRequired("offset", CSInfo.CallLocation.Offset);
507     YamlIO.mapOptional("fwdArgRegs", CSInfo.ArgForwardingRegs,
508                        std::vector<CallSiteInfo::ArgRegPair>());
509   }
510 
511   static const bool flow = true;
512 };
513 
514 /// Serializable representation of debug value substitutions.
515 struct DebugValueSubstitution {
516   unsigned SrcInst;
517   unsigned SrcOp;
518   unsigned DstInst;
519   unsigned DstOp;
520   unsigned Subreg;
521 
522   bool operator==(const DebugValueSubstitution &Other) const {
523     return std::tie(SrcInst, SrcOp, DstInst, DstOp) ==
524            std::tie(Other.SrcInst, Other.SrcOp, Other.DstInst, Other.DstOp);
525   }
526 };
527 
528 template <> struct MappingTraits<DebugValueSubstitution> {
529   static void mapping(IO &YamlIO, DebugValueSubstitution &Sub) {
530     YamlIO.mapRequired("srcinst", Sub.SrcInst);
531     YamlIO.mapRequired("srcop", Sub.SrcOp);
532     YamlIO.mapRequired("dstinst", Sub.DstInst);
533     YamlIO.mapRequired("dstop", Sub.DstOp);
534     YamlIO.mapRequired("subreg", Sub.Subreg);
535   }
536 
537   static const bool flow = true;
538 };
539 } // namespace yaml
540 } // namespace llvm
541 
542 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::DebugValueSubstitution)
543 
544 namespace llvm {
545 namespace yaml {
546 struct MachineConstantPoolValue {
547   UnsignedValue ID;
548   StringValue Value;
549   MaybeAlign Alignment = std::nullopt;
550   bool IsTargetSpecific = false;
551 
552   bool operator==(const MachineConstantPoolValue &Other) const {
553     return ID == Other.ID && Value == Other.Value &&
554            Alignment == Other.Alignment &&
555            IsTargetSpecific == Other.IsTargetSpecific;
556   }
557 };
558 
559 template <> struct MappingTraits<MachineConstantPoolValue> {
560   static void mapping(IO &YamlIO, MachineConstantPoolValue &Constant) {
561     YamlIO.mapRequired("id", Constant.ID);
562     YamlIO.mapOptional("value", Constant.Value, StringValue());
563     YamlIO.mapOptional("alignment", Constant.Alignment, std::nullopt);
564     YamlIO.mapOptional("isTargetSpecific", Constant.IsTargetSpecific, false);
565   }
566 };
567 
568 struct MachineJumpTable {
569   struct Entry {
570     UnsignedValue ID;
571     std::vector<FlowStringValue> Blocks;
572 
573     bool operator==(const Entry &Other) const {
574       return ID == Other.ID && Blocks == Other.Blocks;
575     }
576   };
577 
578   MachineJumpTableInfo::JTEntryKind Kind = MachineJumpTableInfo::EK_Custom32;
579   std::vector<Entry> Entries;
580 
581   bool operator==(const MachineJumpTable &Other) const {
582     return Kind == Other.Kind && Entries == Other.Entries;
583   }
584 };
585 
586 template <> struct MappingTraits<MachineJumpTable::Entry> {
587   static void mapping(IO &YamlIO, MachineJumpTable::Entry &Entry) {
588     YamlIO.mapRequired("id", Entry.ID);
589     YamlIO.mapOptional("blocks", Entry.Blocks, std::vector<FlowStringValue>());
590   }
591 };
592 
593 } // end namespace yaml
594 } // end namespace llvm
595 
596 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::MachineFunctionLiveIn)
597 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::VirtualRegisterDefinition)
598 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::MachineStackObject)
599 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::EntryValueObject)
600 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::FixedMachineStackObject)
601 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::CallSiteInfo)
602 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::MachineConstantPoolValue)
603 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::MachineJumpTable::Entry)
604 
605 namespace llvm {
606 namespace yaml {
607 
608 template <> struct MappingTraits<MachineJumpTable> {
609   static void mapping(IO &YamlIO, MachineJumpTable &JT) {
610     YamlIO.mapRequired("kind", JT.Kind);
611     YamlIO.mapOptional("entries", JT.Entries,
612                        std::vector<MachineJumpTable::Entry>());
613   }
614 };
615 
616 /// Serializable representation of MachineFrameInfo.
617 ///
618 /// Doesn't serialize attributes like 'StackAlignment', 'IsStackRealignable' and
619 /// 'RealignOption' as they are determined by the target and LLVM function
620 /// attributes.
621 /// It also doesn't serialize attributes like 'NumFixedObject' and
622 /// 'HasVarSizedObjects' as they are determined by the frame objects themselves.
623 struct MachineFrameInfo {
624   bool IsFrameAddressTaken = false;
625   bool IsReturnAddressTaken = false;
626   bool HasStackMap = false;
627   bool HasPatchPoint = false;
628   uint64_t StackSize = 0;
629   int OffsetAdjustment = 0;
630   unsigned MaxAlignment = 0;
631   bool AdjustsStack = false;
632   bool HasCalls = false;
633   StringValue StackProtector;
634   StringValue FunctionContext;
635   unsigned MaxCallFrameSize = ~0u; ///< ~0u means: not computed yet.
636   unsigned CVBytesOfCalleeSavedRegisters = 0;
637   bool HasOpaqueSPAdjustment = false;
638   bool HasVAStart = false;
639   bool HasMustTailInVarArgFunc = false;
640   bool HasTailCall = false;
641   unsigned LocalFrameSize = 0;
642   StringValue SavePoint;
643   StringValue RestorePoint;
644 
645   bool operator==(const MachineFrameInfo &Other) const {
646     return IsFrameAddressTaken == Other.IsFrameAddressTaken &&
647            IsReturnAddressTaken == Other.IsReturnAddressTaken &&
648            HasStackMap == Other.HasStackMap &&
649            HasPatchPoint == Other.HasPatchPoint &&
650            StackSize == Other.StackSize &&
651            OffsetAdjustment == Other.OffsetAdjustment &&
652            MaxAlignment == Other.MaxAlignment &&
653            AdjustsStack == Other.AdjustsStack && HasCalls == Other.HasCalls &&
654            StackProtector == Other.StackProtector &&
655            FunctionContext == Other.FunctionContext &&
656            MaxCallFrameSize == Other.MaxCallFrameSize &&
657            CVBytesOfCalleeSavedRegisters ==
658                Other.CVBytesOfCalleeSavedRegisters &&
659            HasOpaqueSPAdjustment == Other.HasOpaqueSPAdjustment &&
660            HasVAStart == Other.HasVAStart &&
661            HasMustTailInVarArgFunc == Other.HasMustTailInVarArgFunc &&
662            HasTailCall == Other.HasTailCall &&
663            LocalFrameSize == Other.LocalFrameSize &&
664            SavePoint == Other.SavePoint && RestorePoint == Other.RestorePoint;
665   }
666 };
667 
668 template <> struct MappingTraits<MachineFrameInfo> {
669   static void mapping(IO &YamlIO, MachineFrameInfo &MFI) {
670     YamlIO.mapOptional("isFrameAddressTaken", MFI.IsFrameAddressTaken, false);
671     YamlIO.mapOptional("isReturnAddressTaken", MFI.IsReturnAddressTaken, false);
672     YamlIO.mapOptional("hasStackMap", MFI.HasStackMap, false);
673     YamlIO.mapOptional("hasPatchPoint", MFI.HasPatchPoint, false);
674     YamlIO.mapOptional("stackSize", MFI.StackSize, (uint64_t)0);
675     YamlIO.mapOptional("offsetAdjustment", MFI.OffsetAdjustment, (int)0);
676     YamlIO.mapOptional("maxAlignment", MFI.MaxAlignment, (unsigned)0);
677     YamlIO.mapOptional("adjustsStack", MFI.AdjustsStack, false);
678     YamlIO.mapOptional("hasCalls", MFI.HasCalls, false);
679     YamlIO.mapOptional("stackProtector", MFI.StackProtector,
680                        StringValue()); // Don't print it out when it's empty.
681     YamlIO.mapOptional("functionContext", MFI.FunctionContext,
682                        StringValue()); // Don't print it out when it's empty.
683     YamlIO.mapOptional("maxCallFrameSize", MFI.MaxCallFrameSize, (unsigned)~0);
684     YamlIO.mapOptional("cvBytesOfCalleeSavedRegisters",
685                        MFI.CVBytesOfCalleeSavedRegisters, 0U);
686     YamlIO.mapOptional("hasOpaqueSPAdjustment", MFI.HasOpaqueSPAdjustment,
687                        false);
688     YamlIO.mapOptional("hasVAStart", MFI.HasVAStart, false);
689     YamlIO.mapOptional("hasMustTailInVarArgFunc", MFI.HasMustTailInVarArgFunc,
690                        false);
691     YamlIO.mapOptional("hasTailCall", MFI.HasTailCall, false);
692     YamlIO.mapOptional("localFrameSize", MFI.LocalFrameSize, (unsigned)0);
693     YamlIO.mapOptional("savePoint", MFI.SavePoint,
694                        StringValue()); // Don't print it out when it's empty.
695     YamlIO.mapOptional("restorePoint", MFI.RestorePoint,
696                        StringValue()); // Don't print it out when it's empty.
697   }
698 };
699 
700 /// Targets should override this in a way that mirrors the implementation of
701 /// llvm::MachineFunctionInfo.
702 struct MachineFunctionInfo {
703   virtual ~MachineFunctionInfo() = default;
704   virtual void mappingImpl(IO &YamlIO) {}
705 };
706 
707 template <> struct MappingTraits<std::unique_ptr<MachineFunctionInfo>> {
708   static void mapping(IO &YamlIO, std::unique_ptr<MachineFunctionInfo> &MFI) {
709     if (MFI)
710       MFI->mappingImpl(YamlIO);
711   }
712 };
713 
714 struct MachineFunction {
715   StringRef Name;
716   MaybeAlign Alignment = std::nullopt;
717   bool ExposesReturnsTwice = false;
718   // GISel MachineFunctionProperties.
719   bool Legalized = false;
720   bool RegBankSelected = false;
721   bool Selected = false;
722   bool FailedISel = false;
723   // Register information
724   bool TracksRegLiveness = false;
725   bool HasWinCFI = false;
726 
727   bool CallsEHReturn = false;
728   bool CallsUnwindInit = false;
729   bool HasEHCatchret = false;
730   bool HasEHScopes = false;
731   bool HasEHFunclets = false;
732   bool IsOutlined = false;
733 
734   bool FailsVerification = false;
735   bool TracksDebugUserValues = false;
736   bool UseDebugInstrRef = false;
737   std::vector<VirtualRegisterDefinition> VirtualRegisters;
738   std::vector<MachineFunctionLiveIn> LiveIns;
739   std::optional<std::vector<FlowStringValue>> CalleeSavedRegisters;
740   // TODO: Serialize the various register masks.
741   // Frame information
742   MachineFrameInfo FrameInfo;
743   std::vector<FixedMachineStackObject> FixedStackObjects;
744   std::vector<EntryValueObject> EntryValueObjects;
745   std::vector<MachineStackObject> StackObjects;
746   std::vector<MachineConstantPoolValue> Constants; /// Constant pool.
747   std::unique_ptr<MachineFunctionInfo> MachineFuncInfo;
748   std::vector<CallSiteInfo> CallSitesInfo;
749   std::vector<DebugValueSubstitution> DebugValueSubstitutions;
750   MachineJumpTable JumpTableInfo;
751   std::vector<StringValue> MachineMetadataNodes;
752   BlockStringValue Body;
753 };
754 
755 template <> struct MappingTraits<MachineFunction> {
756   static void mapping(IO &YamlIO, MachineFunction &MF) {
757     YamlIO.mapRequired("name", MF.Name);
758     YamlIO.mapOptional("alignment", MF.Alignment, std::nullopt);
759     YamlIO.mapOptional("exposesReturnsTwice", MF.ExposesReturnsTwice, false);
760     YamlIO.mapOptional("legalized", MF.Legalized, false);
761     YamlIO.mapOptional("regBankSelected", MF.RegBankSelected, false);
762     YamlIO.mapOptional("selected", MF.Selected, false);
763     YamlIO.mapOptional("failedISel", MF.FailedISel, false);
764     YamlIO.mapOptional("tracksRegLiveness", MF.TracksRegLiveness, false);
765     YamlIO.mapOptional("hasWinCFI", MF.HasWinCFI, false);
766 
767     YamlIO.mapOptional("callsEHReturn", MF.CallsEHReturn, false);
768     YamlIO.mapOptional("callsUnwindInit", MF.CallsUnwindInit, false);
769     YamlIO.mapOptional("hasEHCatchret", MF.HasEHCatchret, false);
770     YamlIO.mapOptional("hasEHScopes", MF.HasEHScopes, false);
771     YamlIO.mapOptional("hasEHFunclets", MF.HasEHFunclets, false);
772     YamlIO.mapOptional("isOutlined", MF.IsOutlined, false);
773     YamlIO.mapOptional("debugInstrRef", MF.UseDebugInstrRef, false);
774 
775     YamlIO.mapOptional("failsVerification", MF.FailsVerification, false);
776     YamlIO.mapOptional("tracksDebugUserValues", MF.TracksDebugUserValues,
777                        false);
778     YamlIO.mapOptional("registers", MF.VirtualRegisters,
779                        std::vector<VirtualRegisterDefinition>());
780     YamlIO.mapOptional("liveins", MF.LiveIns,
781                        std::vector<MachineFunctionLiveIn>());
782     YamlIO.mapOptional("calleeSavedRegisters", MF.CalleeSavedRegisters,
783                        std::optional<std::vector<FlowStringValue>>());
784     YamlIO.mapOptional("frameInfo", MF.FrameInfo, MachineFrameInfo());
785     YamlIO.mapOptional("fixedStack", MF.FixedStackObjects,
786                        std::vector<FixedMachineStackObject>());
787     YamlIO.mapOptional("stack", MF.StackObjects,
788                        std::vector<MachineStackObject>());
789     YamlIO.mapOptional("entry_values", MF.EntryValueObjects,
790                        std::vector<EntryValueObject>());
791     YamlIO.mapOptional("callSites", MF.CallSitesInfo,
792                        std::vector<CallSiteInfo>());
793     YamlIO.mapOptional("debugValueSubstitutions", MF.DebugValueSubstitutions,
794                        std::vector<DebugValueSubstitution>());
795     YamlIO.mapOptional("constants", MF.Constants,
796                        std::vector<MachineConstantPoolValue>());
797     YamlIO.mapOptional("machineFunctionInfo", MF.MachineFuncInfo);
798     if (!YamlIO.outputting() || !MF.JumpTableInfo.Entries.empty())
799       YamlIO.mapOptional("jumpTable", MF.JumpTableInfo, MachineJumpTable());
800     if (!YamlIO.outputting() || !MF.MachineMetadataNodes.empty())
801       YamlIO.mapOptional("machineMetadataNodes", MF.MachineMetadataNodes,
802                          std::vector<StringValue>());
803     YamlIO.mapOptional("body", MF.Body, BlockStringValue());
804   }
805 };
806 
807 } // end namespace yaml
808 } // end namespace llvm
809 
810 #endif // LLVM_CODEGEN_MIRYAMLMAPPING_H
811