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