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 | |
29 | namespace llvm { |
30 | namespace yaml { |
31 | |
32 | /// A wrapper around std::string which contains a source range that's being |
33 | /// set during parsing. |
34 | struct 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 | |
47 | template <> 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 | |
63 | struct FlowStringValue : StringValue { |
64 | FlowStringValue() = default; |
65 | FlowStringValue(std::string Value) : StringValue(std::move(Value)) {} |
66 | }; |
67 | |
68 | template <> 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 | |
80 | struct BlockStringValue { |
81 | StringValue Value; |
82 | |
83 | bool operator==(const BlockStringValue &Other) const { |
84 | return Value == Other.Value; |
85 | } |
86 | }; |
87 | |
88 | template <> 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. |
100 | struct 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 | |
112 | template <> 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 | |
129 | template <> 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 | |
147 | template <> 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 | |
164 | template <> 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 | |
183 | LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::StringValue) |
184 | LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::FlowStringValue) |
185 | LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::UnsignedValue) |
186 | |
187 | namespace llvm { |
188 | namespace yaml { |
189 | |
190 | struct 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 | |
203 | template <> 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 | |
214 | struct 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 | |
224 | template <> 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. |
242 | struct 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 | |
271 | template <> 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 | |
279 | template <> 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. |
311 | struct 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 | |
323 | template <> 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. |
335 | struct 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 | |
363 | template <> |
364 | struct 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 | |
372 | template <> |
373 | struct 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 | |
383 | template <> 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. |
414 | struct 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 | |
428 | template <> 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. |
458 | struct 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 | |
489 | template <> 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 | |
500 | LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::CallSiteInfo::ArgRegPair) |
501 | |
502 | namespace llvm { |
503 | namespace yaml { |
504 | |
505 | template <> 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. |
517 | struct 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 | |
530 | template <> 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 | |
544 | LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::DebugValueSubstitution) |
545 | |
546 | namespace llvm { |
547 | namespace yaml { |
548 | struct 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 | |
561 | template <> 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 | |
570 | struct 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 | |
588 | template <> 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 | |
598 | LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::MachineFunctionLiveIn) |
599 | LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::VirtualRegisterDefinition) |
600 | LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::MachineStackObject) |
601 | LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::EntryValueObject) |
602 | LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::FixedMachineStackObject) |
603 | LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::CallSiteInfo) |
604 | LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::MachineConstantPoolValue) |
605 | LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::MachineJumpTable::Entry) |
606 | |
607 | namespace llvm { |
608 | namespace yaml { |
609 | |
610 | template <> 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. |
625 | struct 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 | |
670 | template <> 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. |
704 | struct MachineFunctionInfo { |
705 | virtual ~MachineFunctionInfo() = default; |
706 | virtual void mappingImpl(IO &YamlIO) {} |
707 | }; |
708 | |
709 | template <> 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 | |
716 | struct 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 | |
757 | template <> 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 | |