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