MIR: Allow targets to serialize MachineFunctionInfo

This has been a very painful missing feature that has made producing
reduced testcases difficult. In particular the various registers
determined for stack access during function lowering were necessary to
avoid undefined register errors in a large percentage of
cases. Implement a subset of the important fields that need to be
preserved for AMDGPU.

Most of the changes are to support targets parsing register fields and
properly reporting errors. The biggest sort-of bug remaining is for
fields that can be initialized from the IR section will be overwritten
by a default initialized machineFunctionInfo section. Another
remaining bug is the machineFunctionInfo section is still printed even
if empty.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@356215 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/CodeGen/MIRParser/MIParser.h b/include/llvm/CodeGen/MIRParser/MIParser.h
similarity index 98%
rename from lib/CodeGen/MIRParser/MIParser.h
rename to include/llvm/CodeGen/MIRParser/MIParser.h
index dc858a9..4e32a04 100644
--- a/lib/CodeGen/MIRParser/MIParser.h
+++ b/include/llvm/CodeGen/MIRParser/MIParser.h
@@ -164,8 +164,8 @@
   PerTargetMIParsingState &Target;
 
   DenseMap<unsigned, MachineBasicBlock *> MBBSlots;
-  DenseMap<unsigned, VRegInfo*> VRegInfos;
-  StringMap<VRegInfo*> VRegInfosNamed;
+  DenseMap<unsigned, VRegInfo *> VRegInfos;
+  StringMap<VRegInfo *> VRegInfosNamed;
   DenseMap<unsigned, int> FixedStackObjectSlots;
   DenseMap<unsigned, int> StackObjectSlots;
   DenseMap<unsigned, unsigned> ConstantPoolSlots;
diff --git a/include/llvm/CodeGen/MIRYamlMapping.h b/include/llvm/CodeGen/MIRYamlMapping.h
index a0f2b16..13f572f 100644
--- a/include/llvm/CodeGen/MIRYamlMapping.h
+++ b/include/llvm/CodeGen/MIRYamlMapping.h
@@ -36,6 +36,7 @@
 
   StringValue() = default;
   StringValue(std::string Value) : Value(std::move(Value)) {}
+  StringValue(const char Val[]) : Value(Val) {}
 
   bool operator==(const StringValue &Other) const {
     return Value == Other.Value;
@@ -482,6 +483,20 @@
   }
 };
 
+/// Targets should override this in a way that mirrors the implementation of
+/// llvm::MachineFunctionInfo.
+struct MachineFunctionInfo {
+  virtual ~MachineFunctionInfo() {}
+  virtual void mappingImpl(IO &YamlIO) {}
+};
+
+template <> struct MappingTraits<std::unique_ptr<MachineFunctionInfo>> {
+  static void mapping(IO &YamlIO, std::unique_ptr<MachineFunctionInfo> &MFI) {
+    if (MFI)
+      MFI->mappingImpl(YamlIO);
+  }
+};
+
 struct MachineFunction {
   StringRef Name;
   unsigned Alignment = 0;
@@ -503,6 +518,7 @@
   std::vector<FixedMachineStackObject> FixedStackObjects;
   std::vector<MachineStackObject> StackObjects;
   std::vector<MachineConstantPoolValue> Constants; /// Constant pool.
+  std::unique_ptr<MachineFunctionInfo> MachineFuncInfo;
   MachineJumpTable JumpTableInfo;
   BlockStringValue Body;
 };
@@ -531,6 +547,7 @@
                        std::vector<MachineStackObject>());
     YamlIO.mapOptional("constants", MF.Constants,
                        std::vector<MachineConstantPoolValue>());
+    YamlIO.mapOptional("machineFunctionInfo", MF.MachineFuncInfo);
     if (!YamlIO.outputting() || !MF.JumpTableInfo.Entries.empty())
       YamlIO.mapOptional("jumpTable", MF.JumpTableInfo, MachineJumpTable());
     YamlIO.mapOptional("body", MF.Body, BlockStringValue());
diff --git a/include/llvm/CodeGen/MachineModuleInfo.h b/include/llvm/CodeGen/MachineModuleInfo.h
index 9b81dc6..4ff5c7f 100644
--- a/include/llvm/CodeGen/MachineModuleInfo.h
+++ b/include/llvm/CodeGen/MachineModuleInfo.h
@@ -150,6 +150,8 @@
   bool doInitialization(Module &) override;
   bool doFinalization(Module &) override;
 
+  const LLVMTargetMachine &getTarget() const { return TM; }
+
   const MCContext &getContext() const { return Context; }
   MCContext &getContext() { return Context; }
 
diff --git a/include/llvm/Target/TargetMachine.h b/include/llvm/Target/TargetMachine.h
index 7dd9b99..f289c65 100644
--- a/include/llvm/Target/TargetMachine.h
+++ b/include/llvm/Target/TargetMachine.h
@@ -35,6 +35,9 @@
 class MCSymbol;
 class raw_pwrite_stream;
 class PassManagerBuilder;
+struct PerFunctionMIParsingState;
+class SMDiagnostic;
+class SMRange;
 class Target;
 class TargetIntrinsicInfo;
 class TargetIRAnalysis;
@@ -49,6 +52,10 @@
 }
 using legacy::PassManagerBase;
 
+namespace yaml {
+struct MachineFunctionInfo;
+}
+
 //===----------------------------------------------------------------------===//
 ///
 /// Primary interface to the complete machine description for the target
@@ -114,6 +121,27 @@
     return nullptr;
   }
 
+  /// Allocate and return a default initialized instance of the YAML
+  /// representation for the MachineFunctionInfo.
+  virtual yaml::MachineFunctionInfo *createDefaultFuncInfoYAML() const {
+    return nullptr;
+  }
+
+  /// Allocate and initialize an instance of the YAML representation of the
+  /// MachineFunctionInfo.
+  virtual yaml::MachineFunctionInfo *
+  convertFuncInfoToYAML(const MachineFunction &MF) const {
+    return nullptr;
+  }
+
+  /// Parse out the target's MachineFunctionInfo from the YAML reprsentation.
+  virtual bool parseMachineFunctionInfo(const yaml::MachineFunctionInfo &,
+                                        PerFunctionMIParsingState &PFS,
+                                        SMDiagnostic &Error,
+                                        SMRange &SourceRange) const {
+    return false;
+  }
+
   /// This method returns a pointer to the specified type of
   /// TargetSubtargetInfo.  In debug builds, it verifies that the object being
   /// returned is of the correct type.
diff --git a/lib/CodeGen/MIRParser/MIParser.cpp b/lib/CodeGen/MIRParser/MIParser.cpp
index 593ec57..971944b 100644
--- a/lib/CodeGen/MIRParser/MIParser.cpp
+++ b/lib/CodeGen/MIRParser/MIParser.cpp
@@ -10,7 +10,7 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "MIParser.h"
+#include "llvm/CodeGen/MIRParser/MIParser.h"
 #include "MILexer.h"
 #include "llvm/ADT/APInt.h"
 #include "llvm/ADT/APSInt.h"
diff --git a/lib/CodeGen/MIRParser/MIRParser.cpp b/lib/CodeGen/MIRParser/MIRParser.cpp
index 7a4eb45..3598cbe 100644
--- a/lib/CodeGen/MIRParser/MIRParser.cpp
+++ b/lib/CodeGen/MIRParser/MIRParser.cpp
@@ -12,7 +12,6 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/CodeGen/MIRParser/MIRParser.h"
-#include "MIParser.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/StringMap.h"
@@ -21,6 +20,7 @@
 #include "llvm/AsmParser/SlotMapping.h"
 #include "llvm/CodeGen/GlobalISel/RegisterBank.h"
 #include "llvm/CodeGen/GlobalISel/RegisterBankInfo.h"
+#include "llvm/CodeGen/MIRParser/MIParser.h"
 #include "llvm/CodeGen/MIRYamlMapping.h"
 #include "llvm/CodeGen/MachineConstantPool.h"
 #include "llvm/CodeGen/MachineFrameInfo.h"
@@ -39,6 +39,7 @@
 #include "llvm/Support/SMLoc.h"
 #include "llvm/Support/SourceMgr.h"
 #include "llvm/Support/YAMLTraits.h"
+#include "llvm/Target/TargetMachine.h"
 #include <memory>
 
 using namespace llvm;
@@ -266,6 +267,11 @@
   // Parse the yaml.
   yaml::MachineFunction YamlMF;
   yaml::EmptyContext Ctx;
+
+  const LLVMTargetMachine &TM = MMI.getTarget();
+  YamlMF.MachineFuncInfo = std::unique_ptr<yaml::MachineFunctionInfo>(
+      TM.createDefaultFuncInfoYAML());
+
   yaml::yamlize(In, YamlMF, false, Ctx);
   if (In.error())
     return true;
@@ -407,6 +413,19 @@
   if (setupRegisterInfo(PFS, YamlMF))
     return true;
 
+  if (YamlMF.MachineFuncInfo) {
+    const LLVMTargetMachine &TM = MF.getTarget();
+    // Note this is called after the initial constructor of the
+    // MachineFunctionInfo based on the MachineFunction, which may depend on the
+    // IR.
+
+    SMRange SrcRange;
+    if (TM.parseMachineFunctionInfo(*YamlMF.MachineFuncInfo, PFS, Error,
+                                    SrcRange)) {
+      return error(Error, SrcRange);
+    }
+  }
+
   computeFunctionProperties(MF);
 
   MF.getSubtarget().mirFileLoaded(MF);
diff --git a/lib/CodeGen/MIRPrinter.cpp b/lib/CodeGen/MIRPrinter.cpp
index 5977ba4..86e3f53 100644
--- a/lib/CodeGen/MIRPrinter.cpp
+++ b/lib/CodeGen/MIRPrinter.cpp
@@ -215,6 +215,11 @@
     convert(YamlMF, *ConstantPool);
   if (const auto *JumpTableInfo = MF.getJumpTableInfo())
     convert(MST, YamlMF.JumpTableInfo, *JumpTableInfo);
+
+  const TargetMachine &TM = MF.getTarget();
+  YamlMF.MachineFuncInfo =
+      std::unique_ptr<yaml::MachineFunctionInfo>(TM.convertFuncInfoToYAML(MF));
+
   raw_string_ostream StrOS(YamlMF.Body.Value.Value);
   bool IsNewlineNeeded = false;
   for (const auto &MBB : MF) {
diff --git a/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp b/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp
index dd76390..23ba6ce 100644
--- a/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp
+++ b/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp
@@ -24,11 +24,13 @@
 #include "GCNIterativeScheduler.h"
 #include "GCNSchedStrategy.h"
 #include "R600MachineScheduler.h"
+#include "SIMachineFunctionInfo.h"
 #include "SIMachineScheduler.h"
 #include "llvm/CodeGen/GlobalISel/IRTranslator.h"
 #include "llvm/CodeGen/GlobalISel/InstructionSelect.h"
 #include "llvm/CodeGen/GlobalISel/Legalizer.h"
 #include "llvm/CodeGen/GlobalISel/RegBankSelect.h"
+#include "llvm/CodeGen/MIRParser/MIParser.h"
 #include "llvm/CodeGen/Passes.h"
 #include "llvm/CodeGen/TargetPassConfig.h"
 #include "llvm/IR/Attributes.h"
@@ -930,3 +932,74 @@
 TargetPassConfig *GCNTargetMachine::createPassConfig(PassManagerBase &PM) {
   return new GCNPassConfig(*this, PM);
 }
+
+yaml::MachineFunctionInfo *GCNTargetMachine::createDefaultFuncInfoYAML() const {
+  return new yaml::SIMachineFunctionInfo();
+}
+
+yaml::MachineFunctionInfo *
+GCNTargetMachine::convertFuncInfoToYAML(const MachineFunction &MF) const {
+  const SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
+  return new yaml::SIMachineFunctionInfo(*MFI,
+                                         *MF.getSubtarget().getRegisterInfo());
+}
+
+bool GCNTargetMachine::parseMachineFunctionInfo(
+    const yaml::MachineFunctionInfo &MFI_, PerFunctionMIParsingState &PFS,
+    SMDiagnostic &Error, SMRange &SourceRange) const {
+  const yaml::SIMachineFunctionInfo &YamlMFI =
+      reinterpret_cast<const yaml::SIMachineFunctionInfo &>(MFI_);
+  MachineFunction &MF = PFS.MF;
+  SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
+
+  MFI->initializeBaseYamlFields(YamlMFI);
+
+  auto parseRegister = [&](const yaml::StringValue &RegName, unsigned &RegVal) {
+    if (parseNamedRegisterReference(PFS, RegVal, RegName.Value, Error)) {
+      SourceRange = RegName.SourceRange;
+      return true;
+    }
+
+    return false;
+  };
+
+  auto diagnoseRegisterClass = [&](const yaml::StringValue &RegName) {
+    // Create a diagnostic for a the register string literal.
+    const MemoryBuffer &Buffer =
+        *PFS.SM->getMemoryBuffer(PFS.SM->getMainFileID());
+    Error = SMDiagnostic(*PFS.SM, SMLoc(), Buffer.getBufferIdentifier(), 1,
+                         RegName.Value.size(), SourceMgr::DK_Error,
+                         "incorrect register class for field", RegName.Value,
+                         None, None);
+    SourceRange = RegName.SourceRange;
+    return true;
+  };
+
+  if (parseRegister(YamlMFI.ScratchRSrcReg, MFI->ScratchRSrcReg) ||
+      parseRegister(YamlMFI.ScratchWaveOffsetReg, MFI->ScratchWaveOffsetReg) ||
+      parseRegister(YamlMFI.FrameOffsetReg, MFI->FrameOffsetReg) ||
+      parseRegister(YamlMFI.StackPtrOffsetReg, MFI->StackPtrOffsetReg))
+    return true;
+
+  if (MFI->ScratchRSrcReg != AMDGPU::PRIVATE_RSRC_REG &&
+      !AMDGPU::SReg_128RegClass.contains(MFI->ScratchRSrcReg)) {
+    return diagnoseRegisterClass(YamlMFI.ScratchRSrcReg);
+  }
+
+  if (MFI->ScratchWaveOffsetReg != AMDGPU::SCRATCH_WAVE_OFFSET_REG &&
+      !AMDGPU::SGPR_32RegClass.contains(MFI->ScratchWaveOffsetReg)) {
+    return diagnoseRegisterClass(YamlMFI.ScratchWaveOffsetReg);
+  }
+
+  if (MFI->FrameOffsetReg != AMDGPU::FP_REG &&
+      !AMDGPU::SGPR_32RegClass.contains(MFI->FrameOffsetReg)) {
+    return diagnoseRegisterClass(YamlMFI.FrameOffsetReg);
+  }
+
+  if (MFI->StackPtrOffsetReg != AMDGPU::SP_REG &&
+      !AMDGPU::SGPR_32RegClass.contains(MFI->StackPtrOffsetReg)) {
+    return diagnoseRegisterClass(YamlMFI.StackPtrOffsetReg);
+  }
+
+  return false;
+}
diff --git a/lib/Target/AMDGPU/AMDGPUTargetMachine.h b/lib/Target/AMDGPU/AMDGPUTargetMachine.h
index b8805f0..70fa396 100644
--- a/lib/Target/AMDGPU/AMDGPUTargetMachine.h
+++ b/lib/Target/AMDGPU/AMDGPUTargetMachine.h
@@ -110,6 +110,14 @@
   bool useIPRA() const override {
     return true;
   }
+
+  yaml::MachineFunctionInfo *createDefaultFuncInfoYAML() const override;
+  yaml::MachineFunctionInfo *
+  convertFuncInfoToYAML(const MachineFunction &MF) const override;
+  bool parseMachineFunctionInfo(const yaml::MachineFunctionInfo &,
+                                PerFunctionMIParsingState &PFS,
+                                SMDiagnostic &Error,
+                                SMRange &SourceRange) const override;
 };
 
 } // end namespace llvm
diff --git a/lib/Target/AMDGPU/LLVMBuild.txt b/lib/Target/AMDGPU/LLVMBuild.txt
index 2f661af..e18085d 100644
--- a/lib/Target/AMDGPU/LLVMBuild.txt
+++ b/lib/Target/AMDGPU/LLVMBuild.txt
@@ -29,5 +29,5 @@
 type = Library
 name = AMDGPUCodeGen
 parent = AMDGPU
-required_libraries = Analysis AsmPrinter CodeGen Core IPO MC AMDGPUAsmPrinter AMDGPUDesc AMDGPUInfo AMDGPUUtils Scalar SelectionDAG Support Target TransformUtils Vectorize GlobalISel BinaryFormat
+required_libraries = Analysis AsmPrinter CodeGen Core IPO MC AMDGPUAsmPrinter AMDGPUDesc AMDGPUInfo AMDGPUUtils Scalar SelectionDAG Support Target TransformUtils Vectorize GlobalISel BinaryFormat MIRParser
 add_to_library_groups = AMDGPU
diff --git a/lib/Target/AMDGPU/SIISelLowering.cpp b/lib/Target/AMDGPU/SIISelLowering.cpp
index 9205c20..f625331 100644
--- a/lib/Target/AMDGPU/SIISelLowering.cpp
+++ b/lib/Target/AMDGPU/SIISelLowering.cpp
@@ -9607,13 +9607,22 @@
     assert(Info->getStackPtrOffsetReg() != Info->getFrameOffsetReg());
     assert(!TRI->isSubRegister(Info->getScratchRSrcReg(),
                                Info->getStackPtrOffsetReg()));
-    MRI.replaceRegWith(AMDGPU::SP_REG, Info->getStackPtrOffsetReg());
+    if (Info->getStackPtrOffsetReg() != AMDGPU::SP_REG)
+      MRI.replaceRegWith(AMDGPU::SP_REG, Info->getStackPtrOffsetReg());
   }
 
-  MRI.replaceRegWith(AMDGPU::PRIVATE_RSRC_REG, Info->getScratchRSrcReg());
-  MRI.replaceRegWith(AMDGPU::FP_REG, Info->getFrameOffsetReg());
-  MRI.replaceRegWith(AMDGPU::SCRATCH_WAVE_OFFSET_REG,
-                     Info->getScratchWaveOffsetReg());
+  // We need to worry about replacing the default register with itself in case
+  // of MIR testcases missing the MFI.
+  if (Info->getScratchRSrcReg() != AMDGPU::PRIVATE_RSRC_REG)
+    MRI.replaceRegWith(AMDGPU::PRIVATE_RSRC_REG, Info->getScratchRSrcReg());
+
+  if (Info->getFrameOffsetReg() != AMDGPU::FP_REG)
+    MRI.replaceRegWith(AMDGPU::FP_REG, Info->getFrameOffsetReg());
+
+  if (Info->getScratchWaveOffsetReg() != AMDGPU::SCRATCH_WAVE_OFFSET_REG) {
+    MRI.replaceRegWith(AMDGPU::SCRATCH_WAVE_OFFSET_REG,
+                       Info->getScratchWaveOffsetReg());
+  }
 
   Info->limitOccupancy(MF);
 
diff --git a/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp b/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp
index 78e88ab..834f651 100644
--- a/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp
+++ b/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp
@@ -319,3 +319,42 @@
 MCPhysReg SIMachineFunctionInfo::getNextSystemSGPR() const {
   return AMDGPU::SGPR0 + NumUserSGPRs + NumSystemSGPRs;
 }
+
+static yaml::StringValue regToString(unsigned Reg,
+                                     const TargetRegisterInfo &TRI) {
+  yaml::StringValue Dest;
+  raw_string_ostream OS(Dest.Value);
+  OS << printReg(Reg, &TRI);
+  return Dest;
+}
+
+yaml::SIMachineFunctionInfo::SIMachineFunctionInfo(
+  const llvm::SIMachineFunctionInfo& MFI,
+  const TargetRegisterInfo &TRI)
+  : ExplicitKernArgSize(MFI.getExplicitKernArgSize()),
+    MaxKernArgAlign(MFI.getMaxKernArgAlign()),
+    LDSSize(MFI.getLDSSize()),
+    IsEntryFunction(MFI.isEntryFunction()),
+    NoSignedZerosFPMath(MFI.hasNoSignedZerosFPMath()),
+    MemoryBound(MFI.isMemoryBound()),
+    WaveLimiter(MFI.needsWaveLimiter()),
+    ScratchRSrcReg(regToString(MFI.getScratchRSrcReg(), TRI)),
+    ScratchWaveOffsetReg(regToString(MFI.getScratchWaveOffsetReg(), TRI)),
+    FrameOffsetReg(regToString(MFI.getFrameOffsetReg(), TRI)),
+    StackPtrOffsetReg(regToString(MFI.getStackPtrOffsetReg(), TRI)) {}
+
+void yaml::SIMachineFunctionInfo::mappingImpl(yaml::IO &YamlIO) {
+  MappingTraits<SIMachineFunctionInfo>::mapping(YamlIO, *this);
+}
+
+bool SIMachineFunctionInfo::initializeBaseYamlFields(
+  const yaml::SIMachineFunctionInfo &YamlMFI) {
+  ExplicitKernArgSize = YamlMFI.ExplicitKernArgSize;
+  MaxKernArgAlign = YamlMFI.MaxKernArgAlign;
+  LDSSize = YamlMFI.LDSSize;
+  IsEntryFunction = YamlMFI.IsEntryFunction;
+  NoSignedZerosFPMath = YamlMFI.NoSignedZerosFPMath;
+  MemoryBound = YamlMFI.MemoryBound;
+  WaveLimiter = YamlMFI.WaveLimiter;
+  return false;
+}
diff --git a/lib/Target/AMDGPU/SIMachineFunctionInfo.h b/lib/Target/AMDGPU/SIMachineFunctionInfo.h
index de84fbb..ce103dc 100644
--- a/lib/Target/AMDGPU/SIMachineFunctionInfo.h
+++ b/lib/Target/AMDGPU/SIMachineFunctionInfo.h
@@ -15,13 +15,14 @@
 
 #include "AMDGPUArgumentUsageInfo.h"
 #include "AMDGPUMachineFunction.h"
+#include "MCTargetDesc/AMDGPUMCTargetDesc.h"
 #include "SIInstrInfo.h"
 #include "SIRegisterInfo.h"
-#include "MCTargetDesc/AMDGPUMCTargetDesc.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/ADT/SmallVector.h"
+#include "llvm/CodeGen/MIRYamlMapping.h"
 #include "llvm/CodeGen/PseudoSourceValue.h"
 #include "llvm/CodeGen/TargetInstrInfo.h"
 #include "llvm/MC/MCRegisterInfo.h"
@@ -78,9 +79,58 @@
   }
 };
 
+namespace yaml {
+
+struct SIMachineFunctionInfo final : public yaml::MachineFunctionInfo {
+  uint64_t ExplicitKernArgSize = 0;
+  unsigned MaxKernArgAlign = 0;
+  unsigned LDSSize = 0;
+  bool IsEntryFunction = false;
+  bool NoSignedZerosFPMath = false;
+  bool MemoryBound = false;
+  bool WaveLimiter = false;
+
+  StringValue ScratchRSrcReg = "$private_rsrc_reg";
+  StringValue ScratchWaveOffsetReg = "$scratch_wave_offset_reg";
+  StringValue FrameOffsetReg = "$fp_reg";
+  StringValue StackPtrOffsetReg = "$sp_reg";
+
+  SIMachineFunctionInfo() = default;
+  SIMachineFunctionInfo(const llvm::SIMachineFunctionInfo &,
+                        const TargetRegisterInfo &TRI);
+
+  void mappingImpl(yaml::IO &YamlIO) override;
+  ~SIMachineFunctionInfo() = default;
+};
+
+template <> struct MappingTraits<SIMachineFunctionInfo> {
+  static void mapping(IO &YamlIO, SIMachineFunctionInfo &MFI) {
+    YamlIO.mapOptional("explicitKernArgSize", MFI.ExplicitKernArgSize,
+                       UINT64_C(0));
+    YamlIO.mapOptional("maxKernArgAlign", MFI.MaxKernArgAlign, 0u);
+    YamlIO.mapOptional("ldsSize", MFI.LDSSize, 0u);
+    YamlIO.mapOptional("isEntryFunction", MFI.IsEntryFunction, false);
+    YamlIO.mapOptional("noSignedZerosFPMath", MFI.NoSignedZerosFPMath, false);
+    YamlIO.mapOptional("memoryBound", MFI.MemoryBound, false);
+    YamlIO.mapOptional("waveLimiter", MFI.WaveLimiter, false);
+    YamlIO.mapOptional("scratchRSrcReg", MFI.ScratchRSrcReg,
+                       StringValue("$private_rsrc_reg"));
+    YamlIO.mapOptional("scratchWaveOffsetReg", MFI.ScratchWaveOffsetReg,
+                       StringValue("$scratch_wave_offset_reg"));
+    YamlIO.mapOptional("frameOffsetReg", MFI.FrameOffsetReg,
+                       StringValue("$fp_reg"));
+    YamlIO.mapOptional("stackPtrOffsetReg", MFI.StackPtrOffsetReg,
+                       StringValue("$sp_reg"));
+  }
+};
+
+} // end namespace yaml
+
 /// This class keeps track of the SPI_SP_INPUT_ADDR config register, which
 /// tells the hardware which interpolation parameters to load.
 class SIMachineFunctionInfo final : public AMDGPUMachineFunction {
+  friend class GCNTargetMachine;
+
   unsigned TIDReg = AMDGPU::NoRegister;
 
   // Registers that may be reserved for spilling purposes. These may be the same
@@ -219,6 +269,8 @@
 public:
   SIMachineFunctionInfo(const MachineFunction &MF);
 
+  bool initializeBaseYamlFields(const yaml::SIMachineFunctionInfo &YamlMFI);
+
   ArrayRef<SpilledReg> getSGPRToVGPRSpills(int FrameIndex) const {
     auto I = SGPRToVGPRSpills.find(FrameIndex);
     return (I == SGPRToVGPRSpills.end()) ?
diff --git a/test/CodeGen/AMDGPU/scalar-store-cache-flush.mir b/test/CodeGen/AMDGPU/scalar-store-cache-flush.mir
index 23974fe..1fea21d 100644
--- a/test/CodeGen/AMDGPU/scalar-store-cache-flush.mir
+++ b/test/CodeGen/AMDGPU/scalar-store-cache-flush.mir
@@ -53,6 +53,8 @@
 
 name: basic_insert_dcache_wb
 tracksRegLiveness: false
+machineFunctionInfo:
+  isEntryFunction: true
 
 body: |
   bb.0:
@@ -69,6 +71,8 @@
 
 name: explicit_flush_after
 tracksRegLiveness: false
+machineFunctionInfo:
+  isEntryFunction: true
 
 body: |
   bb.0:
@@ -87,6 +91,8 @@
 
 name: explicit_flush_before
 tracksRegLiveness: false
+machineFunctionInfo:
+  isEntryFunction: true
 
 body: |
   bb.0:
@@ -100,6 +106,8 @@
 # CHECK-NEXT: S_ENDPGM 0
 name: no_scalar_store
 tracksRegLiveness: false
+machineFunctionInfo:
+  isEntryFunction: true
 
 body: |
   bb.0:
@@ -119,6 +127,8 @@
 
 name: multi_block_store
 tracksRegLiveness: false
+machineFunctionInfo:
+  isEntryFunction: true
 
 body: |
   bb.0:
@@ -146,6 +156,8 @@
 
 name: one_block_store
 tracksRegLiveness: false
+machineFunctionInfo:
+  isEntryFunction: true
 
 body: |
   bb.0:
@@ -165,6 +177,8 @@
 
 name: si_return
 tracksRegLiveness: false
+machineFunctionInfo:
+  isEntryFunction: true
 
 body: |
   bb.0:
diff --git a/test/CodeGen/AMDGPU/sgpr-spill-wrong-stack-id.mir b/test/CodeGen/AMDGPU/sgpr-spill-wrong-stack-id.mir
index 9481e98..5943279 100644
--- a/test/CodeGen/AMDGPU/sgpr-spill-wrong-stack-id.mir
+++ b/test/CodeGen/AMDGPU/sgpr-spill-wrong-stack-id.mir
@@ -76,6 +76,11 @@
 tracksRegLiveness: true
 frameInfo:
   hasCalls:        true
+machineFunctionInfo:
+  scratchRSrcReg: $sgpr0_sgpr1_sgpr2_sgpr3
+  scratchWaveOffsetReg: $sgpr4
+  frameOffsetReg: $sgpr5
+  stackPtrOffsetReg: $sgpr32
 body:             |
   bb.0:
     %0:sreg_32_xm0 = COPY $sgpr5
diff --git a/test/CodeGen/AMDGPU/spill-before-exec.mir b/test/CodeGen/AMDGPU/spill-before-exec.mir
index 0726a25..7f0576b7 100644
--- a/test/CodeGen/AMDGPU/spill-before-exec.mir
+++ b/test/CodeGen/AMDGPU/spill-before-exec.mir
@@ -8,6 +8,10 @@
 
 name:            foo
 tracksRegLiveness: true
+machineFunctionInfo:
+  scratchRSrcReg: $sgpr0_sgpr1_sgpr2_sgpr3
+  scratchWaveOffsetReg: $sgpr4
+  stackPtrOffsetReg: $sgpr32
 registers:
   - { id: 0, class: sreg_64 }
   - { id: 1100, class: sreg_128 }
diff --git a/test/CodeGen/AMDGPU/spill-empty-live-interval.mir b/test/CodeGen/AMDGPU/spill-empty-live-interval.mir
index 384042f..c0e63ef 100644
--- a/test/CodeGen/AMDGPU/spill-empty-live-interval.mir
+++ b/test/CodeGen/AMDGPU/spill-empty-live-interval.mir
@@ -19,6 +19,11 @@
 
 name: expecting_non_empty_interval
 tracksRegLiveness: true
+machineFunctionInfo:
+  scratchRSrcReg: $sgpr0_sgpr1_sgpr2_sgpr3
+  scratchWaveOffsetReg: $sgpr4
+  frameOffsetReg: $sgpr5
+  stackPtrOffsetReg: $sgpr32
 body:             |
   bb.0:
     successors: %bb.1
@@ -49,6 +54,11 @@
 # CHECK-NEXT: S_NOP 0, implicit %2.sub2
 name: rematerialize_empty_interval_has_reference
 tracksRegLiveness: true
+machineFunctionInfo:
+  scratchRSrcReg: $sgpr0_sgpr1_sgpr2_sgpr3
+  scratchWaveOffsetReg: $sgpr4
+  frameOffsetReg: $sgpr5
+  stackPtrOffsetReg: $sgpr32
 body:             |
   bb.0:
     successors: %bb.1
diff --git a/test/CodeGen/AMDGPU/stack-slot-color-sgpr-vgpr-spills.mir b/test/CodeGen/AMDGPU/stack-slot-color-sgpr-vgpr-spills.mir
index 559c0d4..9d21d70 100644
--- a/test/CodeGen/AMDGPU/stack-slot-color-sgpr-vgpr-spills.mir
+++ b/test/CodeGen/AMDGPU/stack-slot-color-sgpr-vgpr-spills.mir
@@ -17,9 +17,14 @@
 
 name: no_merge_sgpr_vgpr_spill_slot
 tracksRegLiveness: true
+machineFunctionInfo:
+  scratchRSrcReg: $sgpr0_sgpr1_sgpr2_sgpr3
+  scratchWaveOffsetReg: $sgpr4
+  frameOffsetReg: $sgpr5
+  stackPtrOffsetReg: $sgpr32
 body: |
   bb.0:
-      %0:vgpr_32 = FLAT_LOAD_DWORD undef $vgpr0_vgpr1, 0, 0, 0, implicit $flat_scr, implicit $exec
+    %0:vgpr_32 = FLAT_LOAD_DWORD undef $vgpr0_vgpr1, 0, 0, 0, implicit $flat_scr, implicit $exec
     %2:vgpr_32 = FLAT_LOAD_DWORD undef $vgpr0_vgpr1, 0, 0, 0, implicit $flat_scr, implicit $exec
     S_NOP 0, implicit %0
     %1:sreg_32_xm0_xexec = S_LOAD_DWORD_IMM undef $sgpr0_sgpr1, 0, 0
diff --git a/test/CodeGen/AMDGPU/subreg-split-live-in-error.mir b/test/CodeGen/AMDGPU/subreg-split-live-in-error.mir
index 68f6ec7..3bb2737 100644
--- a/test/CodeGen/AMDGPU/subreg-split-live-in-error.mir
+++ b/test/CodeGen/AMDGPU/subreg-split-live-in-error.mir
@@ -39,6 +39,11 @@
 ---
 name:            _amdgpu_ps_main
 tracksRegLiveness: true
+machineFunctionInfo:
+  scratchRSrcReg: $sgpr0_sgpr1_sgpr2_sgpr3
+  scratchWaveOffsetReg: $sgpr4
+  frameOffsetReg: $sgpr5
+  stackPtrOffsetReg: $sgpr32
 liveins:
   - { reg: '$vgpr2', virtual-reg: '%0' }
   - { reg: '$vgpr3', virtual-reg: '%1' }
diff --git a/test/CodeGen/MIR/AMDGPU/machine-function-info-no-ir.mir b/test/CodeGen/MIR/AMDGPU/machine-function-info-no-ir.mir
new file mode 100644
index 0000000..81c4f8f
--- /dev/null
+++ b/test/CodeGen/MIR/AMDGPU/machine-function-info-no-ir.mir
@@ -0,0 +1,151 @@
+# RUN: llc -mtriple=amdgcn-amd-amdhsa -run-pass=none -verify-machineinstrs %s -o - | FileCheck -check-prefixes=FULL,ALL %s
+# RUN: llc -mtriple=amdgcn-amd-amdhsa -run-pass=none -simplify-mir -verify-machineinstrs %s -o - | FileCheck -check-prefixes=SIMPLE,ALL %s
+
+
+---
+# ALL-LABEL: name: kernel0
+# FULL: machineFunctionInfo:
+# FULL-NEXT: explicitKernArgSize: 128
+# FULL-NEXT: maxKernArgAlign: 64
+# FULL-NEXT: ldsSize: 2048
+# FULL-NEXT: isEntryFunction: true
+# FULL-NEXT: noSignedZerosFPMath: false
+# FULL-NEXT: memoryBound:     true
+# FULL-NEXT: waveLimiter:     true
+# FULL-NEXT: scratchRSrcReg:  '$sgpr8_sgpr9_sgpr10_sgpr11'
+# FULL-NEXT: scratchWaveOffsetReg:  '$sgpr12'
+# FULL-NEXT: frameOffsetReg:  '$sgpr12'
+# FULL-NEXT: stackPtrOffsetReg:  '$sgpr13'
+# FULL-NEXT: body:
+
+# SIMPLE: machineFunctionInfo:
+# SIMPLE-NEXT: explicitKernArgSize: 128
+# SIMPLE-NEXT: maxKernArgAlign: 64
+# SIMPLE-NEXT: ldsSize: 2048
+# SIMPLE-NEXT: isEntryFunction: true
+# SIMPLE-NEXT: memoryBound: true
+# SIMPLE-NEXT: waveLimiter: true
+# SIMPLE-NEXT: scratchRSrcReg: '$sgpr8_sgpr9_sgpr10_sgpr11'
+# SIMPLE-NEXT: scratchWaveOffsetReg:  '$sgpr12'
+# SIMPLE-NEXT: frameOffsetReg:  '$sgpr12'
+# SIMPLE-NEXT: stackPtrOffsetReg:  '$sgpr13'
+# SIMPLE-NEXT: body:
+name: kernel0
+machineFunctionInfo:
+  explicitKernArgSize: 128
+  maxKernArgAlign: 64
+  ldsSize: 2048
+  isEntryFunction: true
+  noSignedZerosFPMath: false
+  memoryBound:     true
+  waveLimiter:     true
+  scratchRSrcReg:  '$sgpr8_sgpr9_sgpr10_sgpr11'
+  scratchWaveOffsetReg:  '$sgpr12'
+  frameOffsetReg: '$sgpr12'
+  stackPtrOffsetReg:  '$sgpr13'
+body:             |
+  bb.0:
+    S_ENDPGM 0
+
+...
+
+# FIXME: Should be able to not print section for simple
+---
+# ALL-LABEL: name: no_mfi
+# FULL: machineFunctionInfo:
+# FULL-NEXT: explicitKernArgSize: 0
+# FULL-NEXT: maxKernArgAlign: 0
+# FULL-NEXT: ldsSize: 0
+# FULL-NEXT: isEntryFunction: false
+# FULL-NEXT: noSignedZerosFPMath: false
+# FULL-NEXT: memoryBound:     false
+# FULL-NEXT: waveLimiter:     false
+# FULL-NEXT: scratchRSrcReg:  '$private_rsrc_reg'
+# FULL-NEXT: scratchWaveOffsetReg:  '$scratch_wave_offset_reg'
+# FULL-NEXT: frameOffsetReg:  '$fp_reg'
+# FULL-NEXT: stackPtrOffsetReg:  '$sp_reg'
+
+# SIMPLE: machineFunctionInfo:
+# SIMPLE-NEXT: body:
+
+name: no_mfi
+body:             |
+  bb.0:
+    S_ENDPGM 0
+
+...
+
+---
+# ALL-LABEL: name: empty_mfi
+# FULL: machineFunctionInfo:
+# FULL-NEXT: explicitKernArgSize: 0
+# FULL-NEXT: maxKernArgAlign: 0
+# FULL-NEXT: ldsSize: 0
+# FULL-NEXT: isEntryFunction: false
+# FULL-NEXT: noSignedZerosFPMath: false
+# FULL-NEXT: memoryBound:     false
+# FULL-NEXT: waveLimiter:     false
+# FULL-NEXT: scratchRSrcReg:  '$private_rsrc_reg'
+# FULL-NEXT: scratchWaveOffsetReg:  '$scratch_wave_offset_reg'
+# FULL-NEXT: frameOffsetReg:  '$fp_reg'
+# FULL-NEXT: stackPtrOffsetReg:  '$sp_reg'
+
+# SIMPLE: machineFunctionInfo:
+# SIMPLE-NEXT: body:
+
+name: empty_mfi
+machineFunctionInfo:
+body:             |
+  bb.0:
+    S_ENDPGM 0
+
+...
+
+---
+# ALL-LABEL: name: empty_mfi_entry_func
+# FULL: machineFunctionInfo:
+# FULL-NEXT: explicitKernArgSize: 0
+# FULL-NEXT: maxKernArgAlign: 0
+# FULL-NEXT: ldsSize: 0
+# FULL-NEXT: isEntryFunction: true
+# FULL-NEXT: noSignedZerosFPMath: false
+# FULL-NEXT: memoryBound:     false
+# FULL-NEXT: waveLimiter:     false
+# FULL-NEXT: scratchRSrcReg:  '$private_rsrc_reg'
+# FULL-NEXT: scratchWaveOffsetReg:  '$scratch_wave_offset_reg'
+# FULL-NEXT: frameOffsetReg:  '$fp_reg'
+# FULL-NEXT: stackPtrOffsetReg:  '$sp_reg'
+
+# SIMPLE: machineFunctionInfo:
+# SIMPLE-NEXT: isEntryFunction: true
+# SIMPLE-NEXT: body:
+
+name: empty_mfi_entry_func
+machineFunctionInfo:
+  isEntryFunction: true
+body:             |
+  bb.0:
+    S_ENDPGM 0
+
+...
+
+---
+# ALL-LABEL: name: default_regs_mfi
+
+# FULL: scratchRSrcReg:  '$private_rsrc_reg'
+# FULL-NEXT: scratchWaveOffsetReg:  '$scratch_wave_offset_reg'
+# FULL-NEXT: frameOffsetReg:  '$fp_reg'
+# FULL-NEXT: stackPtrOffsetReg:  '$sp_reg'
+
+# SIMPLE-NOT: scratchRSrcReg
+# SIMPLE-NOT: scratchWaveOffsetReg
+# SIMPLE-NOT:: stackPtrOffsetReg
+name: default_regs_mfi
+machineFunctionInfo:
+  scratchRSrcReg:  '$private_rsrc_reg'
+
+body:             |
+  bb.0:
+    S_ENDPGM 0
+
+...
diff --git a/test/CodeGen/MIR/AMDGPU/machine-function-info-register-parse-error1.mir b/test/CodeGen/MIR/AMDGPU/machine-function-info-register-parse-error1.mir
new file mode 100644
index 0000000..cfa5323
--- /dev/null
+++ b/test/CodeGen/MIR/AMDGPU/machine-function-info-register-parse-error1.mir
@@ -0,0 +1,12 @@
+# RUN: not llc -march=amdgcn -run-pass none -o /dev/null %s 2>&1 | FileCheck %s
+# CHECK: :7:27: incorrect register class for field
+# CHECK: scratchRSrcReg:  '$noreg'
+---
+name: noreg_rsrc_reg
+machineFunctionInfo:
+  scratchRSrcReg:  '$noreg'
+body:             |
+  bb.0:
+
+    S_ENDPGM
+...
diff --git a/test/CodeGen/MIR/AMDGPU/machine-function-info-register-parse-error2.mir b/test/CodeGen/MIR/AMDGPU/machine-function-info-register-parse-error2.mir
new file mode 100644
index 0000000..f3da77e
--- /dev/null
+++ b/test/CodeGen/MIR/AMDGPU/machine-function-info-register-parse-error2.mir
@@ -0,0 +1,12 @@
+# RUN: not llc -march=amdgcn -run-pass none -o /dev/null %s 2>&1 | FileCheck %s
+# CHECK: :7:21: unknown register name 'not_a_register_name'
+# CHECK: scratchRSrcReg:  '$not_a_register_name'
+---
+name: invalid_rsrc_reg
+machineFunctionInfo:
+  scratchRSrcReg:  '$not_a_register_name'
+body:             |
+  bb.0:
+
+    S_ENDPGM
+...
diff --git a/test/CodeGen/MIR/AMDGPU/machine-function-info.ll b/test/CodeGen/MIR/AMDGPU/machine-function-info.ll
new file mode 100644
index 0000000..d04df7d
--- /dev/null
+++ b/test/CodeGen/MIR/AMDGPU/machine-function-info.ll
@@ -0,0 +1,83 @@
+; RUN: llc -mtriple=amdgcn-mesa-mesa3d -stop-after expand-isel-pseudos -o %t.mir %s
+; RUN: llc -run-pass=none -verify-machineinstrs %t.mir -o - | FileCheck %s
+
+; Test that SIMachineFunctionInfo can be round trip serialized through
+; MIR.
+
+@lds = addrspace(3) global [512 x float] undef, align 4
+
+; CHECK-LABEL: {{^}}name: kernel
+; CHECK: machineFunctionInfo:
+; CHECK-NEXT: explicitKernArgSize: 128
+; CHECK-NEXT: maxKernArgAlign: 64
+; CHECK-NEXT: ldsSize: 2048
+; CHECK-NEXT: isEntryFunction: true
+; CHECK-NEXT: noSignedZerosFPMath: false
+; CHECK-NEXT: memoryBound: false
+; CHECK-NEXT: waveLimiter: false
+; CHECK-NEXT: scratchRSrcReg:  '$sgpr96_sgpr97_sgpr98_sgpr99'
+; CHECK-NEXT: scratchWaveOffsetReg: '$sgpr101'
+; CHECK-NEXT: frameOffsetReg:  '$sgpr101'
+; CHECK-NEXT: stackPtrOffsetReg: '$sp_reg'
+; CHECK-NEXT: body:
+define amdgpu_kernel void @kernel(i32 %arg0, i64 %arg1, <16 x i32> %arg2) {
+  %gep = getelementptr inbounds [512 x float], [512 x float] addrspace(3)* @lds, i32 0, i32 %arg0
+  store float 0.0, float addrspace(3)* %gep, align 4
+  ret void
+}
+
+; CHECK-LABEL: {{^}}name: ps_shader
+; CHECK: machineFunctionInfo:
+; CHECK-NEXT: explicitKernArgSize: 0
+; CHECK-NEXT: maxKernArgAlign: 0
+; CHECK-NEXT: ldsSize: 0
+; CHECK-NEXT: isEntryFunction: true
+; CHECK-NEXT: noSignedZerosFPMath: false
+; CHECK-NEXT: memoryBound: false
+; CHECK-NEXT: waveLimiter: false
+; CHECK-NEXT: scratchRSrcReg:  '$sgpr96_sgpr97_sgpr98_sgpr99'
+; CHECK-NEXT: scratchWaveOffsetReg: '$sgpr101'
+; CHECK-NEXT: frameOffsetReg:  '$sgpr101'
+; CHECK-NEXT: stackPtrOffsetReg: '$sp_reg'
+; CHECK-NEXT: body:
+define amdgpu_ps void @ps_shader(i32 %arg0, i32 inreg %arg1) {
+  ret void
+}
+
+; CHECK-LABEL: {{^}}name: function
+; CHECK: machineFunctionInfo:
+; CHECK-NEXT: explicitKernArgSize: 0
+; CHECK-NEXT: maxKernArgAlign: 0
+; CHECK-NEXT: ldsSize: 0
+; CHECK-NEXT: isEntryFunction: false
+; CHECK-NEXT: noSignedZerosFPMath: false
+; CHECK-NEXT: memoryBound: false
+; CHECK-NEXT: waveLimiter: false
+; CHECK-NEXT: scratchRSrcReg: '$sgpr0_sgpr1_sgpr2_sgpr3'
+; CHECK-NEXT: scratchWaveOffsetReg: '$sgpr4'
+; CHECK-NEXT: frameOffsetReg: '$sgpr5'
+; CHECK-NEXT: stackPtrOffsetReg: '$sgpr32'
+; CHECK-NEXT: body:
+define void @function() {
+  ret void
+}
+
+; CHECK-LABEL: {{^}}name: function_nsz
+; CHECK: machineFunctionInfo:
+; CHECK-NEXT: explicitKernArgSize: 0
+; CHECK-NEXT: maxKernArgAlign: 0
+; CHECK-NEXT: ldsSize: 0
+; CHECK-NEXT: isEntryFunction: false
+; CHECK-NEXT: noSignedZerosFPMath: true
+; CHECK-NEXT: memoryBound: false
+; CHECK-NEXT: waveLimiter: false
+; CHECK-NEXT: scratchRSrcReg: '$sgpr0_sgpr1_sgpr2_sgpr3'
+; CHECK-NEXT: scratchWaveOffsetReg: '$sgpr4'
+; CHECK-NEXT: frameOffsetReg: '$sgpr5'
+; CHECK-NEXT: stackPtrOffsetReg: '$sgpr32'
+; CHECK-NEXT: body:
+define void @function_nsz() #0 {
+  ret void
+}
+
+attributes #0 = { "no-signed-zeros-fp-math" = "true" }
diff --git a/test/CodeGen/MIR/AMDGPU/mfi-frame-offset-reg-class.mir b/test/CodeGen/MIR/AMDGPU/mfi-frame-offset-reg-class.mir
new file mode 100644
index 0000000..c66f6b6
--- /dev/null
+++ b/test/CodeGen/MIR/AMDGPU/mfi-frame-offset-reg-class.mir
@@ -0,0 +1,13 @@
+# RUN: not llc -march=amdgcn -run-pass none -o /dev/null %s 2>&1 | FileCheck %s
+# CHECK: :8:27: incorrect register class for field
+# CHECK: frameOffsetReg:  '$vgpr0'
+
+---
+name: wrong_reg_class_frame_offset_reg
+machineFunctionInfo:
+  frameOffsetReg:  '$vgpr0'
+body:             |
+  bb.0:
+
+    S_ENDPGM
+...
diff --git a/test/CodeGen/MIR/AMDGPU/mfi-parse-error-frame-offset-reg.mir b/test/CodeGen/MIR/AMDGPU/mfi-parse-error-frame-offset-reg.mir
new file mode 100644
index 0000000..723f542
--- /dev/null
+++ b/test/CodeGen/MIR/AMDGPU/mfi-parse-error-frame-offset-reg.mir
@@ -0,0 +1,12 @@
+# RUN: not llc -march=amdgcn -run-pass none -o /dev/null %s 2>&1 | FileCheck %s
+# CHECK: :7:21: expected a named register
+# CHECK: frameOffsetReg:  ''
+---
+name: empty_frame_offset_reg
+machineFunctionInfo:
+  frameOffsetReg:  ''
+body:             |
+  bb.0:
+
+    S_ENDPGM
+...
diff --git a/test/CodeGen/MIR/AMDGPU/mfi-parse-error-scratch-rsrc-reg.mir b/test/CodeGen/MIR/AMDGPU/mfi-parse-error-scratch-rsrc-reg.mir
new file mode 100644
index 0000000..ee047b9
--- /dev/null
+++ b/test/CodeGen/MIR/AMDGPU/mfi-parse-error-scratch-rsrc-reg.mir
@@ -0,0 +1,12 @@
+# RUN: not llc -march=amdgcn -run-pass none -o /dev/null %s 2>&1 | FileCheck %s
+# CHECK: :7:21: expected a named register
+# CHECK: scratchRSrcReg:  ''
+---
+name: empty_scratch_rsrc_reg
+machineFunctionInfo:
+  scratchRSrcReg:  ''
+body:             |
+  bb.0:
+
+    S_ENDPGM
+...
diff --git a/test/CodeGen/MIR/AMDGPU/mfi-parse-error-scratch-wave-offset-reg.mir b/test/CodeGen/MIR/AMDGPU/mfi-parse-error-scratch-wave-offset-reg.mir
new file mode 100644
index 0000000..bbf5808
--- /dev/null
+++ b/test/CodeGen/MIR/AMDGPU/mfi-parse-error-scratch-wave-offset-reg.mir
@@ -0,0 +1,12 @@
+# RUN: not llc -march=amdgcn -run-pass none -o /dev/null %s 2>&1 | FileCheck %s
+# CHECK: :7:27: expected a named register
+# CHECK: scratchWaveOffsetReg:  ''
+---
+name: empty_scratch_wave_offset_reg
+machineFunctionInfo:
+  scratchWaveOffsetReg:  ''
+body:             |
+  bb.0:
+
+    S_ENDPGM
+...
diff --git a/test/CodeGen/MIR/AMDGPU/mfi-parse-error-stack-ptr-offset-reg.mir b/test/CodeGen/MIR/AMDGPU/mfi-parse-error-stack-ptr-offset-reg.mir
new file mode 100644
index 0000000..e8164da
--- /dev/null
+++ b/test/CodeGen/MIR/AMDGPU/mfi-parse-error-stack-ptr-offset-reg.mir
@@ -0,0 +1,12 @@
+# RUN: not llc -march=amdgcn -run-pass none -o /dev/null %s 2>&1 | FileCheck %s
+# CHECK: :7:24: expected a named register
+# CHECK: stackPtrOffsetReg:  ''
+---
+name: empty_stack_ptr_offset_reg
+machineFunctionInfo:
+  stackPtrOffsetReg:  ''
+body:             |
+  bb.0:
+
+    S_ENDPGM
+...
diff --git a/test/CodeGen/MIR/AMDGPU/mfi-scratch-rsrc-reg-reg-class.mir b/test/CodeGen/MIR/AMDGPU/mfi-scratch-rsrc-reg-reg-class.mir
new file mode 100644
index 0000000..ac02af9
--- /dev/null
+++ b/test/CodeGen/MIR/AMDGPU/mfi-scratch-rsrc-reg-reg-class.mir
@@ -0,0 +1,13 @@
+# RUN: not llc -march=amdgcn -run-pass none -o /dev/null %s 2>&1 | FileCheck %s
+# CHECK: :8:45: incorrect register class for field
+# CHECK: scratchRSrcReg:  '$vgpr0_vgpr1_vgpr2_vgpr3'
+
+---
+name: wrong_reg_class_scratch_rsrc_reg
+machineFunctionInfo:
+  scratchRSrcReg:  '$vgpr0_vgpr1_vgpr2_vgpr3'
+body:             |
+  bb.0:
+
+    S_ENDPGM
+...
diff --git a/test/CodeGen/MIR/AMDGPU/mfi-scratch-wave-offset-reg-class.mir b/test/CodeGen/MIR/AMDGPU/mfi-scratch-wave-offset-reg-class.mir
new file mode 100644
index 0000000..8e765ba
--- /dev/null
+++ b/test/CodeGen/MIR/AMDGPU/mfi-scratch-wave-offset-reg-class.mir
@@ -0,0 +1,13 @@
+# RUN: not llc -march=amdgcn -run-pass none -o /dev/null %s 2>&1 | FileCheck %s
+# CHECK: :8:33: incorrect register class for field
+# CHECK: scratchWaveOffsetReg:  '$vgpr0'
+
+---
+name: wrong_reg_class_scratch_wave_offset_reg
+machineFunctionInfo:
+  scratchWaveOffsetReg:  '$vgpr0'
+body:             |
+  bb.0:
+
+    S_ENDPGM
+...
diff --git a/test/CodeGen/MIR/AMDGPU/mfi-stack-ptr-offset-reg-class.mir b/test/CodeGen/MIR/AMDGPU/mfi-stack-ptr-offset-reg-class.mir
new file mode 100644
index 0000000..c15b0c6
--- /dev/null
+++ b/test/CodeGen/MIR/AMDGPU/mfi-stack-ptr-offset-reg-class.mir
@@ -0,0 +1,13 @@
+# RUN: not llc -march=amdgcn -run-pass none -o /dev/null %s 2>&1 | FileCheck %s
+# CHECK: :8:30: incorrect register class for field
+# CHECK: stackPtrOffsetReg:  '$vgpr0'
+
+---
+name: wrong_reg_class_stack_ptr_offset_reg
+machineFunctionInfo:
+  stackPtrOffsetReg:  '$vgpr0'
+body:             |
+  bb.0:
+
+    S_ENDPGM
+...