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// The MIR serialization library is currently a work in progress. It can't
11// serialize machine functions at this time.
12//
13// This file implements the mapping between various MIR data structures and
14// their corresponding YAML representation.
15//
16//===----------------------------------------------------------------------===//
17
18#ifndef LLVM_LIB_CODEGEN_MIRYAMLMAPPING_H
19#define LLVM_LIB_CODEGEN_MIRYAMLMAPPING_H
20
21#include "llvm/ADT/StringRef.h"
22#include "llvm/CodeGen/MachineJumpTableInfo.h"
23#include "llvm/Support/YAMLTraits.h"
24#include <vector>
25
26namespace llvm {
27namespace yaml {
28
29/// A wrapper around std::string which contains a source range that's being
30/// set during parsing.
31struct StringValue {
32  std::string Value;
33  SMRange SourceRange;
34
35  StringValue() {}
36  StringValue(std::string Value) : Value(std::move(Value)) {}
37
38  bool operator==(const StringValue &Other) const {
39    return Value == Other.Value;
40  }
41};
42
43template <> struct ScalarTraits<StringValue> {
44  static void output(const StringValue &S, void *, llvm::raw_ostream &OS) {
45    OS << S.Value;
46  }
47
48  static StringRef input(StringRef Scalar, void *Ctx, StringValue &S) {
49    S.Value = Scalar.str();
50    if (const auto *Node =
51            reinterpret_cast<yaml::Input *>(Ctx)->getCurrentNode())
52      S.SourceRange = Node->getSourceRange();
53    return "";
54  }
55
56  static bool mustQuote(StringRef Scalar) { return needsQuotes(Scalar); }
57};
58
59struct FlowStringValue : StringValue {
60  FlowStringValue() {}
61  FlowStringValue(std::string Value) : StringValue(Value) {}
62};
63
64template <> struct ScalarTraits<FlowStringValue> {
65  static void output(const FlowStringValue &S, void *, llvm::raw_ostream &OS) {
66    return ScalarTraits<StringValue>::output(S, nullptr, OS);
67  }
68
69  static StringRef input(StringRef Scalar, void *Ctx, FlowStringValue &S) {
70    return ScalarTraits<StringValue>::input(Scalar, Ctx, S);
71  }
72
73  static bool mustQuote(StringRef Scalar) { return needsQuotes(Scalar); }
74};
75
76struct BlockStringValue {
77  StringValue Value;
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};
153
154template <> struct MappingTraits<VirtualRegisterDefinition> {
155  static void mapping(IO &YamlIO, VirtualRegisterDefinition &Reg) {
156    YamlIO.mapRequired("id", Reg.ID);
157    YamlIO.mapRequired("class", Reg.Class);
158    YamlIO.mapOptional("preferred-register", Reg.PreferredRegister,
159                       StringValue()); // Don't print out when it's empty.
160  }
161
162  static const bool flow = true;
163};
164
165struct MachineFunctionLiveIn {
166  StringValue Register;
167  StringValue VirtualRegister;
168};
169
170template <> struct MappingTraits<MachineFunctionLiveIn> {
171  static void mapping(IO &YamlIO, MachineFunctionLiveIn &LiveIn) {
172    YamlIO.mapRequired("reg", LiveIn.Register);
173    YamlIO.mapOptional(
174        "virtual-reg", LiveIn.VirtualRegister,
175        StringValue()); // Don't print the virtual register when it's empty.
176  }
177
178  static const bool flow = true;
179};
180
181/// Serializable representation of stack object from the MachineFrameInfo class.
182///
183/// The flags 'isImmutable' and 'isAliased' aren't serialized, as they are
184/// determined by the object's type and frame information flags.
185/// Dead stack objects aren't serialized.
186///
187/// The 'isPreallocated' flag is determined by the local offset.
188struct MachineStackObject {
189  enum ObjectType { DefaultType, SpillSlot, VariableSized };
190  UnsignedValue ID;
191  StringValue Name;
192  // TODO: Serialize unnamed LLVM alloca reference.
193  ObjectType Type = DefaultType;
194  int64_t Offset = 0;
195  uint64_t Size = 0;
196  unsigned Alignment = 0;
197  StringValue CalleeSavedRegister;
198  Optional<int64_t> LocalOffset;
199  StringValue DebugVar;
200  StringValue DebugExpr;
201  StringValue DebugLoc;
202};
203
204template <> struct ScalarEnumerationTraits<MachineStackObject::ObjectType> {
205  static void enumeration(yaml::IO &IO, MachineStackObject::ObjectType &Type) {
206    IO.enumCase(Type, "default", MachineStackObject::DefaultType);
207    IO.enumCase(Type, "spill-slot", MachineStackObject::SpillSlot);
208    IO.enumCase(Type, "variable-sized", MachineStackObject::VariableSized);
209  }
210};
211
212template <> struct MappingTraits<MachineStackObject> {
213  static void mapping(yaml::IO &YamlIO, MachineStackObject &Object) {
214    YamlIO.mapRequired("id", Object.ID);
215    YamlIO.mapOptional("name", Object.Name,
216                       StringValue()); // Don't print out an empty name.
217    YamlIO.mapOptional(
218        "type", Object.Type,
219        MachineStackObject::DefaultType); // Don't print the default type.
220    YamlIO.mapOptional("offset", Object.Offset);
221    if (Object.Type != MachineStackObject::VariableSized)
222      YamlIO.mapRequired("size", Object.Size);
223    YamlIO.mapOptional("alignment", Object.Alignment);
224    YamlIO.mapOptional("callee-saved-register", Object.CalleeSavedRegister,
225                       StringValue()); // Don't print it out when it's empty.
226    YamlIO.mapOptional("local-offset", Object.LocalOffset);
227    YamlIO.mapOptional("di-variable", Object.DebugVar,
228                       StringValue()); // Don't print it out when it's empty.
229    YamlIO.mapOptional("di-expression", Object.DebugExpr,
230                       StringValue()); // Don't print it out when it's empty.
231    YamlIO.mapOptional("di-location", Object.DebugLoc,
232                       StringValue()); // Don't print it out when it's empty.
233  }
234
235  static const bool flow = true;
236};
237
238/// Serializable representation of the fixed stack object from the
239/// MachineFrameInfo class.
240struct FixedMachineStackObject {
241  enum ObjectType { DefaultType, SpillSlot };
242  UnsignedValue ID;
243  ObjectType Type = DefaultType;
244  int64_t Offset = 0;
245  uint64_t Size = 0;
246  unsigned Alignment = 0;
247  bool IsImmutable = false;
248  bool IsAliased = false;
249  StringValue CalleeSavedRegister;
250};
251
252template <>
253struct ScalarEnumerationTraits<FixedMachineStackObject::ObjectType> {
254  static void enumeration(yaml::IO &IO,
255                          FixedMachineStackObject::ObjectType &Type) {
256    IO.enumCase(Type, "default", FixedMachineStackObject::DefaultType);
257    IO.enumCase(Type, "spill-slot", FixedMachineStackObject::SpillSlot);
258  }
259};
260
261template <> struct MappingTraits<FixedMachineStackObject> {
262  static void mapping(yaml::IO &YamlIO, FixedMachineStackObject &Object) {
263    YamlIO.mapRequired("id", Object.ID);
264    YamlIO.mapOptional(
265        "type", Object.Type,
266        FixedMachineStackObject::DefaultType); // Don't print the default type.
267    YamlIO.mapOptional("offset", Object.Offset);
268    YamlIO.mapOptional("size", Object.Size);
269    YamlIO.mapOptional("alignment", Object.Alignment);
270    if (Object.Type != FixedMachineStackObject::SpillSlot) {
271      YamlIO.mapOptional("isImmutable", Object.IsImmutable);
272      YamlIO.mapOptional("isAliased", Object.IsAliased);
273    }
274    YamlIO.mapOptional("callee-saved-register", Object.CalleeSavedRegister,
275                       StringValue()); // Don't print it out when it's empty.
276  }
277
278  static const bool flow = true;
279};
280
281struct MachineConstantPoolValue {
282  UnsignedValue ID;
283  StringValue Value;
284  unsigned Alignment = 0;
285};
286
287template <> struct MappingTraits<MachineConstantPoolValue> {
288  static void mapping(IO &YamlIO, MachineConstantPoolValue &Constant) {
289    YamlIO.mapRequired("id", Constant.ID);
290    YamlIO.mapOptional("value", Constant.Value);
291    YamlIO.mapOptional("alignment", Constant.Alignment);
292  }
293};
294
295struct MachineJumpTable {
296  struct Entry {
297    UnsignedValue ID;
298    std::vector<FlowStringValue> Blocks;
299  };
300
301  MachineJumpTableInfo::JTEntryKind Kind = MachineJumpTableInfo::EK_Custom32;
302  std::vector<Entry> Entries;
303};
304
305template <> struct MappingTraits<MachineJumpTable::Entry> {
306  static void mapping(IO &YamlIO, MachineJumpTable::Entry &Entry) {
307    YamlIO.mapRequired("id", Entry.ID);
308    YamlIO.mapOptional("blocks", Entry.Blocks);
309  }
310};
311
312} // end namespace yaml
313} // end namespace llvm
314
315LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::MachineFunctionLiveIn)
316LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::VirtualRegisterDefinition)
317LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::MachineStackObject)
318LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::FixedMachineStackObject)
319LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::MachineConstantPoolValue)
320LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::MachineJumpTable::Entry)
321
322namespace llvm {
323namespace yaml {
324
325template <> struct MappingTraits<MachineJumpTable> {
326  static void mapping(IO &YamlIO, MachineJumpTable &JT) {
327    YamlIO.mapRequired("kind", JT.Kind);
328    YamlIO.mapOptional("entries", JT.Entries);
329  }
330};
331
332/// Serializable representation of MachineFrameInfo.
333///
334/// Doesn't serialize attributes like 'StackAlignment', 'IsStackRealignable' and
335/// 'RealignOption' as they are determined by the target and LLVM function
336/// attributes.
337/// It also doesn't serialize attributes like 'NumFixedObject' and
338/// 'HasVarSizedObjects' as they are determined by the frame objects themselves.
339struct MachineFrameInfo {
340  bool IsFrameAddressTaken = false;
341  bool IsReturnAddressTaken = false;
342  bool HasStackMap = false;
343  bool HasPatchPoint = false;
344  uint64_t StackSize = 0;
345  int OffsetAdjustment = 0;
346  unsigned MaxAlignment = 0;
347  bool AdjustsStack = false;
348  bool HasCalls = false;
349  StringValue StackProtector;
350  // TODO: Serialize FunctionContextIdx
351  unsigned MaxCallFrameSize = 0;
352  bool HasOpaqueSPAdjustment = false;
353  bool HasVAStart = false;
354  bool HasMustTailInVarArgFunc = false;
355  StringValue SavePoint;
356  StringValue RestorePoint;
357};
358
359template <> struct MappingTraits<MachineFrameInfo> {
360  static void mapping(IO &YamlIO, MachineFrameInfo &MFI) {
361    YamlIO.mapOptional("isFrameAddressTaken", MFI.IsFrameAddressTaken);
362    YamlIO.mapOptional("isReturnAddressTaken", MFI.IsReturnAddressTaken);
363    YamlIO.mapOptional("hasStackMap", MFI.HasStackMap);
364    YamlIO.mapOptional("hasPatchPoint", MFI.HasPatchPoint);
365    YamlIO.mapOptional("stackSize", MFI.StackSize);
366    YamlIO.mapOptional("offsetAdjustment", MFI.OffsetAdjustment);
367    YamlIO.mapOptional("maxAlignment", MFI.MaxAlignment);
368    YamlIO.mapOptional("adjustsStack", MFI.AdjustsStack);
369    YamlIO.mapOptional("hasCalls", MFI.HasCalls);
370    YamlIO.mapOptional("stackProtector", MFI.StackProtector,
371                       StringValue()); // Don't print it out when it's empty.
372    YamlIO.mapOptional("maxCallFrameSize", MFI.MaxCallFrameSize);
373    YamlIO.mapOptional("hasOpaqueSPAdjustment", MFI.HasOpaqueSPAdjustment);
374    YamlIO.mapOptional("hasVAStart", MFI.HasVAStart);
375    YamlIO.mapOptional("hasMustTailInVarArgFunc", MFI.HasMustTailInVarArgFunc);
376    YamlIO.mapOptional("savePoint", MFI.SavePoint,
377                       StringValue()); // Don't print it out when it's empty.
378    YamlIO.mapOptional("restorePoint", MFI.RestorePoint,
379                       StringValue()); // Don't print it out when it's empty.
380  }
381};
382
383struct MachineFunction {
384  StringRef Name;
385  unsigned Alignment = 0;
386  bool ExposesReturnsTwice = false;
387  bool HasInlineAsm = false;
388  // Register information
389  bool IsSSA = false;
390  bool TracksRegLiveness = false;
391  bool TracksSubRegLiveness = false;
392  std::vector<VirtualRegisterDefinition> VirtualRegisters;
393  std::vector<MachineFunctionLiveIn> LiveIns;
394  Optional<std::vector<FlowStringValue>> CalleeSavedRegisters;
395  // TODO: Serialize the various register masks.
396  // Frame information
397  MachineFrameInfo FrameInfo;
398  std::vector<FixedMachineStackObject> FixedStackObjects;
399  std::vector<MachineStackObject> StackObjects;
400  std::vector<MachineConstantPoolValue> Constants; /// Constant pool.
401  MachineJumpTable JumpTableInfo;
402  BlockStringValue Body;
403};
404
405template <> struct MappingTraits<MachineFunction> {
406  static void mapping(IO &YamlIO, MachineFunction &MF) {
407    YamlIO.mapRequired("name", MF.Name);
408    YamlIO.mapOptional("alignment", MF.Alignment);
409    YamlIO.mapOptional("exposesReturnsTwice", MF.ExposesReturnsTwice);
410    YamlIO.mapOptional("hasInlineAsm", MF.HasInlineAsm);
411    YamlIO.mapOptional("isSSA", MF.IsSSA);
412    YamlIO.mapOptional("tracksRegLiveness", MF.TracksRegLiveness);
413    YamlIO.mapOptional("tracksSubRegLiveness", MF.TracksSubRegLiveness);
414    YamlIO.mapOptional("registers", MF.VirtualRegisters);
415    YamlIO.mapOptional("liveins", MF.LiveIns);
416    YamlIO.mapOptional("calleeSavedRegisters", MF.CalleeSavedRegisters);
417    YamlIO.mapOptional("frameInfo", MF.FrameInfo);
418    YamlIO.mapOptional("fixedStack", MF.FixedStackObjects);
419    YamlIO.mapOptional("stack", MF.StackObjects);
420    YamlIO.mapOptional("constants", MF.Constants);
421    if (!YamlIO.outputting() || !MF.JumpTableInfo.Entries.empty())
422      YamlIO.mapOptional("jumpTable", MF.JumpTableInfo);
423    YamlIO.mapOptional("body", MF.Body);
424  }
425};
426
427} // end namespace yaml
428} // end namespace llvm
429
430#endif
431