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