1//===- MIRYAMLMapping.h - Describes the mapping between MIR and YAML ------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements the mapping between various MIR data structures and
11// their corresponding YAML representation.
12//
13//===----------------------------------------------------------------------===//
14
15#ifndef LLVM_LIB_CODEGEN_MIRYAMLMAPPING_H
16#define LLVM_LIB_CODEGEN_MIRYAMLMAPPING_H
17
18#include "llvm/ADT/StringRef.h"
19#include "llvm/CodeGen/MachineJumpTableInfo.h"
20#include "llvm/Support/YAMLTraits.h"
21#include <vector>
22
23namespace llvm {
24namespace yaml {
25
26/// A wrapper around std::string which contains a source range that's being
27/// set during parsing.
28struct StringValue {
29  std::string Value;
30  SMRange SourceRange;
31
32  StringValue() {}
33  StringValue(std::string Value) : Value(std::move(Value)) {}
34
35  bool operator==(const StringValue &Other) const {
36    return Value == Other.Value;
37  }
38};
39
40template <> struct ScalarTraits<StringValue> {
41  static void output(const StringValue &S, void *, llvm::raw_ostream &OS) {
42    OS << S.Value;
43  }
44
45  static StringRef input(StringRef Scalar, void *Ctx, StringValue &S) {
46    S.Value = Scalar.str();
47    if (const auto *Node =
48            reinterpret_cast<yaml::Input *>(Ctx)->getCurrentNode())
49      S.SourceRange = Node->getSourceRange();
50    return "";
51  }
52
53  static bool mustQuote(StringRef Scalar) { return needsQuotes(Scalar); }
54};
55
56struct FlowStringValue : StringValue {
57  FlowStringValue() {}
58  FlowStringValue(std::string Value) : StringValue(std::move(Value)) {}
59};
60
61template <> struct ScalarTraits<FlowStringValue> {
62  static void output(const FlowStringValue &S, void *, llvm::raw_ostream &OS) {
63    return ScalarTraits<StringValue>::output(S, nullptr, OS);
64  }
65
66  static StringRef input(StringRef Scalar, void *Ctx, FlowStringValue &S) {
67    return ScalarTraits<StringValue>::input(Scalar, Ctx, S);
68  }
69
70  static bool mustQuote(StringRef Scalar) { return needsQuotes(Scalar); }
71};
72
73struct BlockStringValue {
74  StringValue Value;
75  bool operator==(const BlockStringValue &Other) const {
76    return Value == Other.Value;
77  }
78};
79
80template <> struct BlockScalarTraits<BlockStringValue> {
81  static void output(const BlockStringValue &S, void *Ctx, raw_ostream &OS) {
82    return ScalarTraits<StringValue>::output(S.Value, Ctx, OS);
83  }
84
85  static StringRef input(StringRef Scalar, void *Ctx, BlockStringValue &S) {
86    return ScalarTraits<StringValue>::input(Scalar, Ctx, S.Value);
87  }
88};
89
90/// A wrapper around unsigned which contains a source range that's being set
91/// during parsing.
92struct UnsignedValue {
93  unsigned Value;
94  SMRange SourceRange;
95
96  UnsignedValue() : Value(0) {}
97  UnsignedValue(unsigned Value) : Value(Value) {}
98
99  bool operator==(const UnsignedValue &Other) const {
100    return Value == Other.Value;
101  }
102};
103
104template <> struct ScalarTraits<UnsignedValue> {
105  static void output(const UnsignedValue &Value, void *Ctx, raw_ostream &OS) {
106    return ScalarTraits<unsigned>::output(Value.Value, Ctx, OS);
107  }
108
109  static StringRef input(StringRef Scalar, void *Ctx, UnsignedValue &Value) {
110    if (const auto *Node =
111            reinterpret_cast<yaml::Input *>(Ctx)->getCurrentNode())
112      Value.SourceRange = Node->getSourceRange();
113    return ScalarTraits<unsigned>::input(Scalar, Ctx, Value.Value);
114  }
115
116  static bool mustQuote(StringRef Scalar) {
117    return ScalarTraits<unsigned>::mustQuote(Scalar);
118  }
119};
120
121template <> struct ScalarEnumerationTraits<MachineJumpTableInfo::JTEntryKind> {
122  static void enumeration(yaml::IO &IO,
123                          MachineJumpTableInfo::JTEntryKind &EntryKind) {
124    IO.enumCase(EntryKind, "block-address",
125                MachineJumpTableInfo::EK_BlockAddress);
126    IO.enumCase(EntryKind, "gp-rel64-block-address",
127                MachineJumpTableInfo::EK_GPRel64BlockAddress);
128    IO.enumCase(EntryKind, "gp-rel32-block-address",
129                MachineJumpTableInfo::EK_GPRel32BlockAddress);
130    IO.enumCase(EntryKind, "label-difference32",
131                MachineJumpTableInfo::EK_LabelDifference32);
132    IO.enumCase(EntryKind, "inline", MachineJumpTableInfo::EK_Inline);
133    IO.enumCase(EntryKind, "custom32", MachineJumpTableInfo::EK_Custom32);
134  }
135};
136
137} // end namespace yaml
138} // end namespace llvm
139
140LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::StringValue)
141LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::FlowStringValue)
142LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::UnsignedValue)
143
144namespace llvm {
145namespace yaml {
146
147struct VirtualRegisterDefinition {
148  UnsignedValue ID;
149  StringValue Class;
150  StringValue PreferredRegister;
151  // TODO: Serialize the target specific register hints.
152  bool operator==(const VirtualRegisterDefinition &Other) const {
153    return ID == Other.ID && Class == Other.Class &&
154           PreferredRegister == Other.PreferredRegister;
155  }
156};
157
158template <> struct MappingTraits<VirtualRegisterDefinition> {
159  static void mapping(IO &YamlIO, VirtualRegisterDefinition &Reg) {
160    YamlIO.mapRequired("id", Reg.ID);
161    YamlIO.mapRequired("class", Reg.Class);
162    YamlIO.mapOptional("preferred-register", Reg.PreferredRegister,
163                       StringValue()); // Don't print out when it's empty.
164  }
165
166  static const bool flow = true;
167};
168
169struct MachineFunctionLiveIn {
170  StringValue Register;
171  StringValue VirtualRegister;
172  bool operator==(const MachineFunctionLiveIn &Other) const {
173    return Register == Other.Register &&
174           VirtualRegister == Other.VirtualRegister;
175  }
176};
177
178template <> struct MappingTraits<MachineFunctionLiveIn> {
179  static void mapping(IO &YamlIO, MachineFunctionLiveIn &LiveIn) {
180    YamlIO.mapRequired("reg", LiveIn.Register);
181    YamlIO.mapOptional(
182        "virtual-reg", LiveIn.VirtualRegister,
183        StringValue()); // Don't print the virtual register when it's empty.
184  }
185
186  static const bool flow = true;
187};
188
189/// Serializable representation of stack object from the MachineFrameInfo class.
190///
191/// The flags 'isImmutable' and 'isAliased' aren't serialized, as they are
192/// determined by the object's type and frame information flags.
193/// Dead stack objects aren't serialized.
194///
195/// The 'isPreallocated' flag is determined by the local offset.
196struct MachineStackObject {
197  enum ObjectType { DefaultType, SpillSlot, VariableSized };
198  UnsignedValue ID;
199  StringValue Name;
200  // TODO: Serialize unnamed LLVM alloca reference.
201  ObjectType Type = DefaultType;
202  int64_t Offset = 0;
203  uint64_t Size = 0;
204  unsigned Alignment = 0;
205  StringValue CalleeSavedRegister;
206  Optional<int64_t> LocalOffset;
207  StringValue DebugVar;
208  StringValue DebugExpr;
209  StringValue DebugLoc;
210  bool operator==(const MachineStackObject &Other) const {
211    return ID == Other.ID && Name == Other.Name && Type == Other.Type &&
212           Offset == Other.Offset && Size == Other.Size &&
213           Alignment == Other.Alignment &&
214           CalleeSavedRegister == Other.CalleeSavedRegister &&
215           LocalOffset == Other.LocalOffset && DebugVar == Other.DebugVar &&
216           DebugExpr == Other.DebugExpr && DebugLoc == Other.DebugLoc;
217  }
218};
219
220template <> struct ScalarEnumerationTraits<MachineStackObject::ObjectType> {
221  static void enumeration(yaml::IO &IO, MachineStackObject::ObjectType &Type) {
222    IO.enumCase(Type, "default", MachineStackObject::DefaultType);
223    IO.enumCase(Type, "spill-slot", MachineStackObject::SpillSlot);
224    IO.enumCase(Type, "variable-sized", MachineStackObject::VariableSized);
225  }
226};
227
228template <> struct MappingTraits<MachineStackObject> {
229  static void mapping(yaml::IO &YamlIO, MachineStackObject &Object) {
230    YamlIO.mapRequired("id", Object.ID);
231    YamlIO.mapOptional("name", Object.Name,
232                       StringValue()); // Don't print out an empty name.
233    YamlIO.mapOptional(
234        "type", Object.Type,
235        MachineStackObject::DefaultType); // Don't print the default type.
236    YamlIO.mapOptional("offset", Object.Offset, (int64_t)0);
237    if (Object.Type != MachineStackObject::VariableSized)
238      YamlIO.mapRequired("size", Object.Size);
239    YamlIO.mapOptional("alignment", Object.Alignment, (unsigned)0);
240    YamlIO.mapOptional("callee-saved-register", Object.CalleeSavedRegister,
241                       StringValue()); // Don't print it out when it's empty.
242    YamlIO.mapOptional("local-offset", Object.LocalOffset, Optional<int64_t>());
243    YamlIO.mapOptional("di-variable", Object.DebugVar,
244                       StringValue()); // Don't print it out when it's empty.
245    YamlIO.mapOptional("di-expression", Object.DebugExpr,
246                       StringValue()); // Don't print it out when it's empty.
247    YamlIO.mapOptional("di-location", Object.DebugLoc,
248                       StringValue()); // Don't print it out when it's empty.
249  }
250
251  static const bool flow = true;
252};
253
254/// Serializable representation of the fixed stack object from the
255/// MachineFrameInfo class.
256struct FixedMachineStackObject {
257  enum ObjectType { DefaultType, SpillSlot };
258  UnsignedValue ID;
259  ObjectType Type = DefaultType;
260  int64_t Offset = 0;
261  uint64_t Size = 0;
262  unsigned Alignment = 0;
263  bool IsImmutable = false;
264  bool IsAliased = false;
265  StringValue CalleeSavedRegister;
266  bool operator==(const FixedMachineStackObject &Other) const {
267    return ID == Other.ID && Type == Other.Type && Offset == Other.Offset &&
268           Size == Other.Size && Alignment == Other.Alignment &&
269           IsImmutable == Other.IsImmutable && IsAliased == Other.IsAliased &&
270           CalleeSavedRegister == Other.CalleeSavedRegister;
271  }
272};
273
274template <>
275struct ScalarEnumerationTraits<FixedMachineStackObject::ObjectType> {
276  static void enumeration(yaml::IO &IO,
277                          FixedMachineStackObject::ObjectType &Type) {
278    IO.enumCase(Type, "default", FixedMachineStackObject::DefaultType);
279    IO.enumCase(Type, "spill-slot", FixedMachineStackObject::SpillSlot);
280  }
281};
282
283template <> struct MappingTraits<FixedMachineStackObject> {
284  static void mapping(yaml::IO &YamlIO, FixedMachineStackObject &Object) {
285    YamlIO.mapRequired("id", Object.ID);
286    YamlIO.mapOptional(
287        "type", Object.Type,
288        FixedMachineStackObject::DefaultType); // Don't print the default type.
289    YamlIO.mapOptional("offset", Object.Offset, (int64_t)0);
290    YamlIO.mapOptional("size", Object.Size, (uint64_t)0);
291    YamlIO.mapOptional("alignment", Object.Alignment, (unsigned)0);
292    if (Object.Type != FixedMachineStackObject::SpillSlot) {
293      YamlIO.mapOptional("isImmutable", Object.IsImmutable, false);
294      YamlIO.mapOptional("isAliased", Object.IsAliased, false);
295    }
296    YamlIO.mapOptional("callee-saved-register", Object.CalleeSavedRegister,
297                       StringValue()); // Don't print it out when it's empty.
298  }
299
300  static const bool flow = true;
301};
302
303struct MachineConstantPoolValue {
304  UnsignedValue ID;
305  StringValue Value;
306  unsigned Alignment = 0;
307  bool operator==(const MachineConstantPoolValue &Other) const {
308    return ID == Other.ID && Value == Other.Value &&
309           Alignment == Other.Alignment;
310  }
311};
312
313template <> struct MappingTraits<MachineConstantPoolValue> {
314  static void mapping(IO &YamlIO, MachineConstantPoolValue &Constant) {
315    YamlIO.mapRequired("id", Constant.ID);
316    YamlIO.mapOptional("value", Constant.Value, StringValue());
317    YamlIO.mapOptional("alignment", Constant.Alignment, (unsigned)0);
318  }
319};
320
321struct MachineJumpTable {
322  struct Entry {
323    UnsignedValue ID;
324    std::vector<FlowStringValue> Blocks;
325    bool operator==(const Entry &Other) const {
326      return ID == Other.ID && Blocks == Other.Blocks;
327    }
328  };
329
330  MachineJumpTableInfo::JTEntryKind Kind = MachineJumpTableInfo::EK_Custom32;
331  std::vector<Entry> Entries;
332  bool operator==(const MachineJumpTable &Other) const {
333    return Kind == Other.Kind && Entries == Other.Entries;
334  }
335};
336
337template <> struct MappingTraits<MachineJumpTable::Entry> {
338  static void mapping(IO &YamlIO, MachineJumpTable::Entry &Entry) {
339    YamlIO.mapRequired("id", Entry.ID);
340    YamlIO.mapOptional("blocks", Entry.Blocks, std::vector<FlowStringValue>());
341  }
342};
343
344} // end namespace yaml
345} // end namespace llvm
346
347LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::MachineFunctionLiveIn)
348LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::VirtualRegisterDefinition)
349LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::MachineStackObject)
350LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::FixedMachineStackObject)
351LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::MachineConstantPoolValue)
352LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::MachineJumpTable::Entry)
353
354namespace llvm {
355namespace yaml {
356
357template <> struct MappingTraits<MachineJumpTable> {
358  static void mapping(IO &YamlIO, MachineJumpTable &JT) {
359    YamlIO.mapRequired("kind", JT.Kind);
360    YamlIO.mapOptional("entries", JT.Entries,
361                       std::vector<MachineJumpTable::Entry>());
362  }
363};
364
365/// Serializable representation of MachineFrameInfo.
366///
367/// Doesn't serialize attributes like 'StackAlignment', 'IsStackRealignable' and
368/// 'RealignOption' as they are determined by the target and LLVM function
369/// attributes.
370/// It also doesn't serialize attributes like 'NumFixedObject' and
371/// 'HasVarSizedObjects' as they are determined by the frame objects themselves.
372struct MachineFrameInfo {
373  bool IsFrameAddressTaken = false;
374  bool IsReturnAddressTaken = false;
375  bool HasStackMap = false;
376  bool HasPatchPoint = false;
377  uint64_t StackSize = 0;
378  int OffsetAdjustment = 0;
379  unsigned MaxAlignment = 0;
380  bool AdjustsStack = false;
381  bool HasCalls = false;
382  StringValue StackProtector;
383  // TODO: Serialize FunctionContextIdx
384  unsigned MaxCallFrameSize = ~0u; ///< ~0u means: not computed yet.
385  bool HasOpaqueSPAdjustment = false;
386  bool HasVAStart = false;
387  bool HasMustTailInVarArgFunc = false;
388  StringValue SavePoint;
389  StringValue RestorePoint;
390  bool operator==(const MachineFrameInfo &Other) const {
391    return IsFrameAddressTaken == Other.IsFrameAddressTaken &&
392           IsReturnAddressTaken == Other.IsReturnAddressTaken &&
393           HasStackMap == Other.HasStackMap &&
394           HasPatchPoint == Other.HasPatchPoint &&
395           StackSize == Other.StackSize &&
396           OffsetAdjustment == Other.OffsetAdjustment &&
397           MaxAlignment == Other.MaxAlignment &&
398           AdjustsStack == Other.AdjustsStack && HasCalls == Other.HasCalls &&
399           StackProtector == Other.StackProtector &&
400           MaxCallFrameSize == Other.MaxCallFrameSize &&
401           HasOpaqueSPAdjustment == Other.HasOpaqueSPAdjustment &&
402           HasVAStart == Other.HasVAStart &&
403           HasMustTailInVarArgFunc == Other.HasMustTailInVarArgFunc &&
404           SavePoint == Other.SavePoint && RestorePoint == Other.RestorePoint;
405  }
406};
407
408template <> struct MappingTraits<MachineFrameInfo> {
409  static void mapping(IO &YamlIO, MachineFrameInfo &MFI) {
410    YamlIO.mapOptional("isFrameAddressTaken", MFI.IsFrameAddressTaken, false);
411    YamlIO.mapOptional("isReturnAddressTaken", MFI.IsReturnAddressTaken, false);
412    YamlIO.mapOptional("hasStackMap", MFI.HasStackMap, false);
413    YamlIO.mapOptional("hasPatchPoint", MFI.HasPatchPoint, false);
414    YamlIO.mapOptional("stackSize", MFI.StackSize, (uint64_t)0);
415    YamlIO.mapOptional("offsetAdjustment", MFI.OffsetAdjustment, (int)0);
416    YamlIO.mapOptional("maxAlignment", MFI.MaxAlignment, (unsigned)0);
417    YamlIO.mapOptional("adjustsStack", MFI.AdjustsStack, false);
418    YamlIO.mapOptional("hasCalls", MFI.HasCalls, false);
419    YamlIO.mapOptional("stackProtector", MFI.StackProtector,
420                       StringValue()); // Don't print it out when it's empty.
421    YamlIO.mapOptional("maxCallFrameSize", MFI.MaxCallFrameSize, (unsigned)~0);
422    YamlIO.mapOptional("hasOpaqueSPAdjustment", MFI.HasOpaqueSPAdjustment,
423                       false);
424    YamlIO.mapOptional("hasVAStart", MFI.HasVAStart, false);
425    YamlIO.mapOptional("hasMustTailInVarArgFunc", MFI.HasMustTailInVarArgFunc,
426                       false);
427    YamlIO.mapOptional("savePoint", MFI.SavePoint,
428                       StringValue()); // Don't print it out when it's empty.
429    YamlIO.mapOptional("restorePoint", MFI.RestorePoint,
430                       StringValue()); // Don't print it out when it's empty.
431  }
432};
433
434struct MachineFunction {
435  StringRef Name;
436  unsigned Alignment = 0;
437  bool ExposesReturnsTwice = false;
438  // GISel MachineFunctionProperties.
439  bool Legalized = false;
440  bool RegBankSelected = false;
441  bool Selected = false;
442  // Register information
443  bool TracksRegLiveness = false;
444  std::vector<VirtualRegisterDefinition> VirtualRegisters;
445  std::vector<MachineFunctionLiveIn> LiveIns;
446  Optional<std::vector<FlowStringValue>> CalleeSavedRegisters;
447  // TODO: Serialize the various register masks.
448  // Frame information
449  MachineFrameInfo FrameInfo;
450  std::vector<FixedMachineStackObject> FixedStackObjects;
451  std::vector<MachineStackObject> StackObjects;
452  std::vector<MachineConstantPoolValue> Constants; /// Constant pool.
453  MachineJumpTable JumpTableInfo;
454  BlockStringValue Body;
455};
456
457template <> struct MappingTraits<MachineFunction> {
458  static void mapping(IO &YamlIO, MachineFunction &MF) {
459    YamlIO.mapRequired("name", MF.Name);
460    YamlIO.mapOptional("alignment", MF.Alignment, (unsigned)0);
461    YamlIO.mapOptional("exposesReturnsTwice", MF.ExposesReturnsTwice, false);
462    YamlIO.mapOptional("legalized", MF.Legalized, false);
463    YamlIO.mapOptional("regBankSelected", MF.RegBankSelected, false);
464    YamlIO.mapOptional("selected", MF.Selected, false);
465    YamlIO.mapOptional("tracksRegLiveness", MF.TracksRegLiveness, false);
466    YamlIO.mapOptional("registers", MF.VirtualRegisters,
467                       std::vector<VirtualRegisterDefinition>());
468    YamlIO.mapOptional("liveins", MF.LiveIns,
469                       std::vector<MachineFunctionLiveIn>());
470    YamlIO.mapOptional("calleeSavedRegisters", MF.CalleeSavedRegisters,
471                       Optional<std::vector<FlowStringValue>>());
472    YamlIO.mapOptional("frameInfo", MF.FrameInfo, MachineFrameInfo());
473    YamlIO.mapOptional("fixedStack", MF.FixedStackObjects,
474                       std::vector<FixedMachineStackObject>());
475    YamlIO.mapOptional("stack", MF.StackObjects,
476                       std::vector<MachineStackObject>());
477    YamlIO.mapOptional("constants", MF.Constants,
478                       std::vector<MachineConstantPoolValue>());
479    if (!YamlIO.outputting() || !MF.JumpTableInfo.Entries.empty())
480      YamlIO.mapOptional("jumpTable", MF.JumpTableInfo, MachineJumpTable());
481    YamlIO.mapOptional("body", MF.Body, BlockStringValue());
482  }
483};
484
485} // end namespace yaml
486} // end namespace llvm
487
488#endif
489