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 
26 namespace llvm {
27 namespace yaml {
28 
29 /// A wrapper around std::string which contains a source range that's being
30 /// set during parsing.
31 struct StringValue {
32   std::string Value;
33   SMRange SourceRange;
34 
StringValueStringValue35   StringValue() {}
StringValueStringValue36   StringValue(std::string Value) : Value(std::move(Value)) {}
37 
38   bool operator==(const StringValue &Other) const {
39     return Value == Other.Value;
40   }
41 };
42 
43 template <> 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 
59 struct FlowStringValue : StringValue {
60   FlowStringValue() {}
61   FlowStringValue(std::string Value) : StringValue(Value) {}
62 };
63 
64 template <> 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 
76 struct BlockStringValue {
77   StringValue Value;
78 };
79 
80 template <> 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.
92 struct 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 
104 template <> 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 
121 template <> 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 
140 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::StringValue)
141 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::FlowStringValue)
142 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::UnsignedValue)
143 
144 namespace llvm {
145 namespace yaml {
146 
147 struct VirtualRegisterDefinition {
148   UnsignedValue ID;
149   StringValue Class;
150   StringValue PreferredRegister;
151   // TODO: Serialize the target specific register hints.
152 };
153 
154 template <> 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 
165 struct MachineFunctionLiveIn {
166   StringValue Register;
167   StringValue VirtualRegister;
168 };
169 
170 template <> 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.
188 struct 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 
204 template <> 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 
212 template <> 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.
240 struct 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 
252 template <>
253 struct 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 
261 template <> 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 
281 struct MachineConstantPoolValue {
282   UnsignedValue ID;
283   StringValue Value;
284   unsigned Alignment = 0;
285 };
286 
287 template <> 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 
295 struct 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 
305 template <> 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 
315 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::MachineFunctionLiveIn)
316 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::VirtualRegisterDefinition)
317 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::MachineStackObject)
318 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::FixedMachineStackObject)
319 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::MachineConstantPoolValue)
320 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::MachineJumpTable::Entry)
321 
322 namespace llvm {
323 namespace yaml {
324 
325 template <> 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.
339 struct 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 
359 template <> 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 
383 struct 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 
405 template <> 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