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
29namespace llvm {
30namespace yaml {
31
32/// A wrapper around std::string which contains a source range that's being
33/// set during parsing.
34struct 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
47template <> 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
63struct FlowStringValue : StringValue {
64 FlowStringValue() = default;
65 FlowStringValue(std::string Value) : StringValue(std::move(Value)) {}
66};
67
68template <> 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
80struct BlockStringValue {
81 StringValue Value;
82
83 bool operator==(const BlockStringValue &Other) const {
84 return Value == Other.Value;
85 }
86};
87
88template <> struct BlockScalarTraits<BlockStringValue> {
89 static void output(const BlockStringValue &S, void *Ctx, raw_ostream &OS) {
90 return ScalarTraits<StringValue>::output(S: S.Value, Ctx, OS);
91 }
92
93 static StringRef input(StringRef Scalar, void *Ctx, BlockStringValue &S) {
94 return ScalarTraits<StringValue>::input(Scalar, Ctx, S&: S.Value);
95 }
96};
97
98/// A wrapper around unsigned which contains a source range that's being set
99/// during parsing.
100struct 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
112template <> 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
129template <> struct ScalarEnumerationTraits<MachineJumpTableInfo::JTEntryKind> {
130 static void enumeration(yaml::IO &IO,
131 MachineJumpTableInfo::JTEntryKind &EntryKind) {
132 IO.enumCase(Val&: EntryKind, Str: "block-address",
133 ConstVal: MachineJumpTableInfo::EK_BlockAddress);
134 IO.enumCase(Val&: EntryKind, Str: "gp-rel64-block-address",
135 ConstVal: MachineJumpTableInfo::EK_GPRel64BlockAddress);
136 IO.enumCase(Val&: EntryKind, Str: "gp-rel32-block-address",
137 ConstVal: MachineJumpTableInfo::EK_GPRel32BlockAddress);
138 IO.enumCase(Val&: EntryKind, Str: "label-difference32",
139 ConstVal: MachineJumpTableInfo::EK_LabelDifference32);
140 IO.enumCase(Val&: EntryKind, Str: "label-difference64",
141 ConstVal: MachineJumpTableInfo::EK_LabelDifference64);
142 IO.enumCase(Val&: EntryKind, Str: "inline", ConstVal: MachineJumpTableInfo::EK_Inline);
143 IO.enumCase(Val&: EntryKind, Str: "custom32", ConstVal: MachineJumpTableInfo::EK_Custom32);
144 }
145};
146
147template <> 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(Str: Scalar, Radix: 10, Result&: n))
155 return "invalid number";
156 if (n > 0 && !isPowerOf2_64(Value: 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
164template <> 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(Str: Scalar, Radix: 10, Result&: N))
171 return "invalid number";
172 if (!isPowerOf2_64(Value: 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
183LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::StringValue)
184LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::FlowStringValue)
185LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::UnsignedValue)
186
187namespace llvm {
188namespace yaml {
189
190struct 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
203template <> struct MappingTraits<VirtualRegisterDefinition> {
204 static void mapping(IO &YamlIO, VirtualRegisterDefinition &Reg) {
205 YamlIO.mapRequired(Key: "id", Val&: Reg.ID);
206 YamlIO.mapRequired(Key: "class", Val&: Reg.Class);
207 YamlIO.mapOptional(Key: "preferred-register", Val&: Reg.PreferredRegister,
208 Default: StringValue()); // Don't print out when it's empty.
209 }
210
211 static const bool flow = true;
212};
213
214struct 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
224template <> struct MappingTraits<MachineFunctionLiveIn> {
225 static void mapping(IO &YamlIO, MachineFunctionLiveIn &LiveIn) {
226 YamlIO.mapRequired(Key: "reg", Val&: LiveIn.Register);
227 YamlIO.mapOptional(
228 Key: "virtual-reg", Val&: LiveIn.VirtualRegister,
229 Default: 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.
242struct 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
271template <> struct ScalarEnumerationTraits<MachineStackObject::ObjectType> {
272 static void enumeration(yaml::IO &IO, MachineStackObject::ObjectType &Type) {
273 IO.enumCase(Val&: Type, Str: "default", ConstVal: MachineStackObject::DefaultType);
274 IO.enumCase(Val&: Type, Str: "spill-slot", ConstVal: MachineStackObject::SpillSlot);
275 IO.enumCase(Val&: Type, Str: "variable-sized", ConstVal: MachineStackObject::VariableSized);
276 }
277};
278
279template <> struct MappingTraits<MachineStackObject> {
280 static void mapping(yaml::IO &YamlIO, MachineStackObject &Object) {
281 YamlIO.mapRequired(Key: "id", Val&: Object.ID);
282 YamlIO.mapOptional(Key: "name", Val&: Object.Name,
283 Default: StringValue()); // Don't print out an empty name.
284 YamlIO.mapOptional(
285 Key: "type", Val&: Object.Type,
286 Default: MachineStackObject::DefaultType); // Don't print the default type.
287 YamlIO.mapOptional(Key: "offset", Val&: Object.Offset, Default: (int64_t)0);
288 if (Object.Type != MachineStackObject::VariableSized)
289 YamlIO.mapRequired(Key: "size", Val&: Object.Size);
290 YamlIO.mapOptional(Key: "alignment", Val&: Object.Alignment, Default: std::nullopt);
291 YamlIO.mapOptional(Key: "stack-id", Val&: Object.StackID, Default: TargetStackID::Default);
292 YamlIO.mapOptional(Key: "callee-saved-register", Val&: Object.CalleeSavedRegister,
293 Default: StringValue()); // Don't print it out when it's empty.
294 YamlIO.mapOptional(Key: "callee-saved-restored", Val&: Object.CalleeSavedRestored,
295 Default: true);
296 YamlIO.mapOptional(Key: "local-offset", Val&: Object.LocalOffset,
297 Default: std::optional<int64_t>());
298 YamlIO.mapOptional(Key: "debug-info-variable", Val&: Object.DebugVar,
299 Default: StringValue()); // Don't print it out when it's empty.
300 YamlIO.mapOptional(Key: "debug-info-expression", Val&: Object.DebugExpr,
301 Default: StringValue()); // Don't print it out when it's empty.
302 YamlIO.mapOptional(Key: "debug-info-location", Val&: Object.DebugLoc,
303 Default: 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.
311struct 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
323template <> struct MappingTraits<EntryValueObject> {
324 static void mapping(yaml::IO &YamlIO, EntryValueObject &Object) {
325 YamlIO.mapRequired(Key: "entry-value-register", Val&: Object.EntryValueRegister);
326 YamlIO.mapRequired(Key: "debug-info-variable", Val&: Object.DebugVar);
327 YamlIO.mapRequired(Key: "debug-info-expression", Val&: Object.DebugExpr);
328 YamlIO.mapRequired(Key: "debug-info-location", Val&: Object.DebugLoc);
329 }
330 static const bool flow = true;
331};
332
333/// Serializable representation of the fixed stack object from the
334/// MachineFrameInfo class.
335struct 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
363template <>
364struct ScalarEnumerationTraits<FixedMachineStackObject::ObjectType> {
365 static void enumeration(yaml::IO &IO,
366 FixedMachineStackObject::ObjectType &Type) {
367 IO.enumCase(Val&: Type, Str: "default", ConstVal: FixedMachineStackObject::DefaultType);
368 IO.enumCase(Val&: Type, Str: "spill-slot", ConstVal: FixedMachineStackObject::SpillSlot);
369 }
370};
371
372template <>
373struct ScalarEnumerationTraits<TargetStackID::Value> {
374 static void enumeration(yaml::IO &IO, TargetStackID::Value &ID) {
375 IO.enumCase(Val&: ID, Str: "default", ConstVal: TargetStackID::Default);
376 IO.enumCase(Val&: ID, Str: "sgpr-spill", ConstVal: TargetStackID::SGPRSpill);
377 IO.enumCase(Val&: ID, Str: "scalable-vector", ConstVal: TargetStackID::ScalableVector);
378 IO.enumCase(Val&: ID, Str: "wasm-local", ConstVal: TargetStackID::WasmLocal);
379 IO.enumCase(Val&: ID, Str: "noalloc", ConstVal: TargetStackID::NoAlloc);
380 }
381};
382
383template <> struct MappingTraits<FixedMachineStackObject> {
384 static void mapping(yaml::IO &YamlIO, FixedMachineStackObject &Object) {
385 YamlIO.mapRequired(Key: "id", Val&: Object.ID);
386 YamlIO.mapOptional(
387 Key: "type", Val&: Object.Type,
388 Default: FixedMachineStackObject::DefaultType); // Don't print the default type.
389 YamlIO.mapOptional(Key: "offset", Val&: Object.Offset, Default: (int64_t)0);
390 YamlIO.mapOptional(Key: "size", Val&: Object.Size, Default: (uint64_t)0);
391 YamlIO.mapOptional(Key: "alignment", Val&: Object.Alignment, Default: std::nullopt);
392 YamlIO.mapOptional(Key: "stack-id", Val&: Object.StackID, Default: TargetStackID::Default);
393 if (Object.Type != FixedMachineStackObject::SpillSlot) {
394 YamlIO.mapOptional(Key: "isImmutable", Val&: Object.IsImmutable, Default: false);
395 YamlIO.mapOptional(Key: "isAliased", Val&: Object.IsAliased, Default: false);
396 }
397 YamlIO.mapOptional(Key: "callee-saved-register", Val&: Object.CalleeSavedRegister,
398 Default: StringValue()); // Don't print it out when it's empty.
399 YamlIO.mapOptional(Key: "callee-saved-restored", Val&: Object.CalleeSavedRestored,
400 Default: true);
401 YamlIO.mapOptional(Key: "debug-info-variable", Val&: Object.DebugVar,
402 Default: StringValue()); // Don't print it out when it's empty.
403 YamlIO.mapOptional(Key: "debug-info-expression", Val&: Object.DebugExpr,
404 Default: StringValue()); // Don't print it out when it's empty.
405 YamlIO.mapOptional(Key: "debug-info-location", Val&: Object.DebugLoc,
406 Default: 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.
414struct 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
428template <> struct ScalarTraits<FrameIndex> {
429 static void output(const FrameIndex &FI, void *, raw_ostream &OS) {
430 MachineOperand::printStackObjectReference(OS, FrameIndex: FI.FI, IsFixed: FI.IsFixed, Name: "");
431 }
432
433 static StringRef input(StringRef Scalar, void *Ctx, FrameIndex &FI) {
434 FI.IsFixed = false;
435 StringRef Num;
436 if (Scalar.starts_with(Prefix: "%stack.")) {
437 Num = Scalar.substr(Start: 7);
438 } else if (Scalar.starts_with(Prefix: "%fixed-stack.")) {
439 Num = Scalar.substr(Start: 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(Radix: 10, Result&: 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.
458struct 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
489template <> struct MappingTraits<CallSiteInfo::ArgRegPair> {
490 static void mapping(IO &YamlIO, CallSiteInfo::ArgRegPair &ArgReg) {
491 YamlIO.mapRequired(Key: "arg", Val&: ArgReg.ArgNo);
492 YamlIO.mapRequired(Key: "reg", Val&: ArgReg.Reg);
493 }
494
495 static const bool flow = true;
496};
497}
498}
499
500LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::CallSiteInfo::ArgRegPair)
501
502namespace llvm {
503namespace yaml {
504
505template <> struct MappingTraits<CallSiteInfo> {
506 static void mapping(IO &YamlIO, CallSiteInfo &CSInfo) {
507 YamlIO.mapRequired(Key: "bb", Val&: CSInfo.CallLocation.BlockNum);
508 YamlIO.mapRequired(Key: "offset", Val&: CSInfo.CallLocation.Offset);
509 YamlIO.mapOptional(Key: "fwdArgRegs", Val&: CSInfo.ArgForwardingRegs,
510 Default: std::vector<CallSiteInfo::ArgRegPair>());
511 }
512
513 static const bool flow = true;
514};
515
516/// Serializable representation of debug value substitutions.
517struct 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(args: SrcInst, args: SrcOp, args: DstInst, args: DstOp) ==
526 std::tie(args: Other.SrcInst, args: Other.SrcOp, args: Other.DstInst, args: Other.DstOp);
527 }
528};
529
530template <> struct MappingTraits<DebugValueSubstitution> {
531 static void mapping(IO &YamlIO, DebugValueSubstitution &Sub) {
532 YamlIO.mapRequired(Key: "srcinst", Val&: Sub.SrcInst);
533 YamlIO.mapRequired(Key: "srcop", Val&: Sub.SrcOp);
534 YamlIO.mapRequired(Key: "dstinst", Val&: Sub.DstInst);
535 YamlIO.mapRequired(Key: "dstop", Val&: Sub.DstOp);
536 YamlIO.mapRequired(Key: "subreg", Val&: Sub.Subreg);
537 }
538
539 static const bool flow = true;
540};
541} // namespace yaml
542} // namespace llvm
543
544LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::DebugValueSubstitution)
545
546namespace llvm {
547namespace yaml {
548struct 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
561template <> struct MappingTraits<MachineConstantPoolValue> {
562 static void mapping(IO &YamlIO, MachineConstantPoolValue &Constant) {
563 YamlIO.mapRequired(Key: "id", Val&: Constant.ID);
564 YamlIO.mapOptional(Key: "value", Val&: Constant.Value, Default: StringValue());
565 YamlIO.mapOptional(Key: "alignment", Val&: Constant.Alignment, Default: std::nullopt);
566 YamlIO.mapOptional(Key: "isTargetSpecific", Val&: Constant.IsTargetSpecific, Default: false);
567 }
568};
569
570struct 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
588template <> struct MappingTraits<MachineJumpTable::Entry> {
589 static void mapping(IO &YamlIO, MachineJumpTable::Entry &Entry) {
590 YamlIO.mapRequired(Key: "id", Val&: Entry.ID);
591 YamlIO.mapOptional(Key: "blocks", Val&: Entry.Blocks, Default: std::vector<FlowStringValue>());
592 }
593};
594
595} // end namespace yaml
596} // end namespace llvm
597
598LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::MachineFunctionLiveIn)
599LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::VirtualRegisterDefinition)
600LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::MachineStackObject)
601LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::EntryValueObject)
602LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::FixedMachineStackObject)
603LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::CallSiteInfo)
604LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::MachineConstantPoolValue)
605LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::MachineJumpTable::Entry)
606
607namespace llvm {
608namespace yaml {
609
610template <> struct MappingTraits<MachineJumpTable> {
611 static void mapping(IO &YamlIO, MachineJumpTable &JT) {
612 YamlIO.mapRequired(Key: "kind", Val&: JT.Kind);
613 YamlIO.mapOptional(Key: "entries", Val&: JT.Entries,
614 Default: 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.
625struct 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 unsigned LocalFrameSize = 0;
644 StringValue SavePoint;
645 StringValue RestorePoint;
646
647 bool operator==(const MachineFrameInfo &Other) const {
648 return IsFrameAddressTaken == Other.IsFrameAddressTaken &&
649 IsReturnAddressTaken == Other.IsReturnAddressTaken &&
650 HasStackMap == Other.HasStackMap &&
651 HasPatchPoint == Other.HasPatchPoint &&
652 StackSize == Other.StackSize &&
653 OffsetAdjustment == Other.OffsetAdjustment &&
654 MaxAlignment == Other.MaxAlignment &&
655 AdjustsStack == Other.AdjustsStack && HasCalls == Other.HasCalls &&
656 StackProtector == Other.StackProtector &&
657 FunctionContext == Other.FunctionContext &&
658 MaxCallFrameSize == Other.MaxCallFrameSize &&
659 CVBytesOfCalleeSavedRegisters ==
660 Other.CVBytesOfCalleeSavedRegisters &&
661 HasOpaqueSPAdjustment == Other.HasOpaqueSPAdjustment &&
662 HasVAStart == Other.HasVAStart &&
663 HasMustTailInVarArgFunc == Other.HasMustTailInVarArgFunc &&
664 HasTailCall == Other.HasTailCall &&
665 LocalFrameSize == Other.LocalFrameSize &&
666 SavePoint == Other.SavePoint && RestorePoint == Other.RestorePoint;
667 }
668};
669
670template <> struct MappingTraits<MachineFrameInfo> {
671 static void mapping(IO &YamlIO, MachineFrameInfo &MFI) {
672 YamlIO.mapOptional(Key: "isFrameAddressTaken", Val&: MFI.IsFrameAddressTaken, Default: false);
673 YamlIO.mapOptional(Key: "isReturnAddressTaken", Val&: MFI.IsReturnAddressTaken, Default: false);
674 YamlIO.mapOptional(Key: "hasStackMap", Val&: MFI.HasStackMap, Default: false);
675 YamlIO.mapOptional(Key: "hasPatchPoint", Val&: MFI.HasPatchPoint, Default: false);
676 YamlIO.mapOptional(Key: "stackSize", Val&: MFI.StackSize, Default: (uint64_t)0);
677 YamlIO.mapOptional(Key: "offsetAdjustment", Val&: MFI.OffsetAdjustment, Default: (int)0);
678 YamlIO.mapOptional(Key: "maxAlignment", Val&: MFI.MaxAlignment, Default: (unsigned)0);
679 YamlIO.mapOptional(Key: "adjustsStack", Val&: MFI.AdjustsStack, Default: false);
680 YamlIO.mapOptional(Key: "hasCalls", Val&: MFI.HasCalls, Default: false);
681 YamlIO.mapOptional(Key: "stackProtector", Val&: MFI.StackProtector,
682 Default: StringValue()); // Don't print it out when it's empty.
683 YamlIO.mapOptional(Key: "functionContext", Val&: MFI.FunctionContext,
684 Default: StringValue()); // Don't print it out when it's empty.
685 YamlIO.mapOptional(Key: "maxCallFrameSize", Val&: MFI.MaxCallFrameSize, Default: (unsigned)~0);
686 YamlIO.mapOptional(Key: "cvBytesOfCalleeSavedRegisters",
687 Val&: MFI.CVBytesOfCalleeSavedRegisters, Default: 0U);
688 YamlIO.mapOptional(Key: "hasOpaqueSPAdjustment", Val&: MFI.HasOpaqueSPAdjustment,
689 Default: false);
690 YamlIO.mapOptional(Key: "hasVAStart", Val&: MFI.HasVAStart, Default: false);
691 YamlIO.mapOptional(Key: "hasMustTailInVarArgFunc", Val&: MFI.HasMustTailInVarArgFunc,
692 Default: false);
693 YamlIO.mapOptional(Key: "hasTailCall", Val&: MFI.HasTailCall, Default: false);
694 YamlIO.mapOptional(Key: "localFrameSize", Val&: MFI.LocalFrameSize, Default: (unsigned)0);
695 YamlIO.mapOptional(Key: "savePoint", Val&: MFI.SavePoint,
696 Default: StringValue()); // Don't print it out when it's empty.
697 YamlIO.mapOptional(Key: "restorePoint", Val&: MFI.RestorePoint,
698 Default: StringValue()); // Don't print it out when it's empty.
699 }
700};
701
702/// Targets should override this in a way that mirrors the implementation of
703/// llvm::MachineFunctionInfo.
704struct MachineFunctionInfo {
705 virtual ~MachineFunctionInfo() = default;
706 virtual void mappingImpl(IO &YamlIO) {}
707};
708
709template <> struct MappingTraits<std::unique_ptr<MachineFunctionInfo>> {
710 static void mapping(IO &YamlIO, std::unique_ptr<MachineFunctionInfo> &MFI) {
711 if (MFI)
712 MFI->mappingImpl(YamlIO);
713 }
714};
715
716struct MachineFunction {
717 StringRef Name;
718 MaybeAlign Alignment = std::nullopt;
719 bool ExposesReturnsTwice = false;
720 // GISel MachineFunctionProperties.
721 bool Legalized = false;
722 bool RegBankSelected = false;
723 bool Selected = false;
724 bool FailedISel = false;
725 // Register information
726 bool TracksRegLiveness = false;
727 bool HasWinCFI = false;
728
729 bool CallsEHReturn = false;
730 bool CallsUnwindInit = false;
731 bool HasEHCatchret = false;
732 bool HasEHScopes = false;
733 bool HasEHFunclets = false;
734 bool IsOutlined = false;
735
736 bool FailsVerification = false;
737 bool TracksDebugUserValues = false;
738 bool UseDebugInstrRef = false;
739 std::vector<VirtualRegisterDefinition> VirtualRegisters;
740 std::vector<MachineFunctionLiveIn> LiveIns;
741 std::optional<std::vector<FlowStringValue>> CalleeSavedRegisters;
742 // TODO: Serialize the various register masks.
743 // Frame information
744 MachineFrameInfo FrameInfo;
745 std::vector<FixedMachineStackObject> FixedStackObjects;
746 std::vector<EntryValueObject> EntryValueObjects;
747 std::vector<MachineStackObject> StackObjects;
748 std::vector<MachineConstantPoolValue> Constants; /// Constant pool.
749 std::unique_ptr<MachineFunctionInfo> MachineFuncInfo;
750 std::vector<CallSiteInfo> CallSitesInfo;
751 std::vector<DebugValueSubstitution> DebugValueSubstitutions;
752 MachineJumpTable JumpTableInfo;
753 std::vector<StringValue> MachineMetadataNodes;
754 BlockStringValue Body;
755};
756
757template <> struct MappingTraits<MachineFunction> {
758 static void mapping(IO &YamlIO, MachineFunction &MF) {
759 YamlIO.mapRequired(Key: "name", Val&: MF.Name);
760 YamlIO.mapOptional(Key: "alignment", Val&: MF.Alignment, Default: std::nullopt);
761 YamlIO.mapOptional(Key: "exposesReturnsTwice", Val&: MF.ExposesReturnsTwice, Default: false);
762 YamlIO.mapOptional(Key: "legalized", Val&: MF.Legalized, Default: false);
763 YamlIO.mapOptional(Key: "regBankSelected", Val&: MF.RegBankSelected, Default: false);
764 YamlIO.mapOptional(Key: "selected", Val&: MF.Selected, Default: false);
765 YamlIO.mapOptional(Key: "failedISel", Val&: MF.FailedISel, Default: false);
766 YamlIO.mapOptional(Key: "tracksRegLiveness", Val&: MF.TracksRegLiveness, Default: false);
767 YamlIO.mapOptional(Key: "hasWinCFI", Val&: MF.HasWinCFI, Default: false);
768
769 YamlIO.mapOptional(Key: "callsEHReturn", Val&: MF.CallsEHReturn, Default: false);
770 YamlIO.mapOptional(Key: "callsUnwindInit", Val&: MF.CallsUnwindInit, Default: false);
771 YamlIO.mapOptional(Key: "hasEHCatchret", Val&: MF.HasEHCatchret, Default: false);
772 YamlIO.mapOptional(Key: "hasEHScopes", Val&: MF.HasEHScopes, Default: false);
773 YamlIO.mapOptional(Key: "hasEHFunclets", Val&: MF.HasEHFunclets, Default: false);
774 YamlIO.mapOptional(Key: "isOutlined", Val&: MF.IsOutlined, Default: false);
775 YamlIO.mapOptional(Key: "debugInstrRef", Val&: MF.UseDebugInstrRef, Default: false);
776
777 YamlIO.mapOptional(Key: "failsVerification", Val&: MF.FailsVerification, Default: false);
778 YamlIO.mapOptional(Key: "tracksDebugUserValues", Val&: MF.TracksDebugUserValues,
779 Default: false);
780 YamlIO.mapOptional(Key: "registers", Val&: MF.VirtualRegisters,
781 Default: std::vector<VirtualRegisterDefinition>());
782 YamlIO.mapOptional(Key: "liveins", Val&: MF.LiveIns,
783 Default: std::vector<MachineFunctionLiveIn>());
784 YamlIO.mapOptional(Key: "calleeSavedRegisters", Val&: MF.CalleeSavedRegisters,
785 Default: std::optional<std::vector<FlowStringValue>>());
786 YamlIO.mapOptional(Key: "frameInfo", Val&: MF.FrameInfo, Default: MachineFrameInfo());
787 YamlIO.mapOptional(Key: "fixedStack", Val&: MF.FixedStackObjects,
788 Default: std::vector<FixedMachineStackObject>());
789 YamlIO.mapOptional(Key: "stack", Val&: MF.StackObjects,
790 Default: std::vector<MachineStackObject>());
791 YamlIO.mapOptional(Key: "entry_values", Val&: MF.EntryValueObjects,
792 Default: std::vector<EntryValueObject>());
793 YamlIO.mapOptional(Key: "callSites", Val&: MF.CallSitesInfo,
794 Default: std::vector<CallSiteInfo>());
795 YamlIO.mapOptional(Key: "debugValueSubstitutions", Val&: MF.DebugValueSubstitutions,
796 Default: std::vector<DebugValueSubstitution>());
797 YamlIO.mapOptional(Key: "constants", Val&: MF.Constants,
798 Default: std::vector<MachineConstantPoolValue>());
799 YamlIO.mapOptional(Key: "machineFunctionInfo", Val&: MF.MachineFuncInfo);
800 if (!YamlIO.outputting() || !MF.JumpTableInfo.Entries.empty())
801 YamlIO.mapOptional(Key: "jumpTable", Val&: MF.JumpTableInfo, Default: MachineJumpTable());
802 if (!YamlIO.outputting() || !MF.MachineMetadataNodes.empty())
803 YamlIO.mapOptional(Key: "machineMetadataNodes", Val&: MF.MachineMetadataNodes,
804 Default: std::vector<StringValue>());
805 YamlIO.mapOptional(Key: "body", Val&: MF.Body, Default: BlockStringValue());
806 }
807};
808
809} // end namespace yaml
810} // end namespace llvm
811
812#endif // LLVM_CODEGEN_MIRYAMLMAPPING_H
813

source code of llvm/include/llvm/CodeGen/MIRYamlMapping.h