Index: include/llvm/CodeGen/MIRParser/MIParser.h =================================================================== --- include/llvm/CodeGen/MIRParser/MIParser.h +++ include/llvm/CodeGen/MIRParser/MIParser.h @@ -164,8 +164,8 @@ PerTargetMIParsingState &Target; DenseMap MBBSlots; - DenseMap VRegInfos; - StringMap VRegInfosNamed; + DenseMap VRegInfos; + StringMap VRegInfosNamed; DenseMap FixedStackObjectSlots; DenseMap StackObjectSlots; DenseMap ConstantPoolSlots; Index: include/llvm/CodeGen/MIRYamlMapping.h =================================================================== --- include/llvm/CodeGen/MIRYamlMapping.h +++ 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> { + static void mapping(IO &YamlIO, std::unique_ptr &MFI) { + if (MFI) + MFI->mappingImpl(YamlIO); + } +}; + struct MachineFunction { StringRef Name; unsigned Alignment = 0; @@ -503,6 +518,7 @@ std::vector FixedStackObjects; std::vector StackObjects; std::vector Constants; /// Constant pool. + std::unique_ptr MachineFuncInfo; MachineJumpTable JumpTableInfo; BlockStringValue Body; }; @@ -531,6 +547,7 @@ std::vector()); YamlIO.mapOptional("constants", MF.Constants, std::vector()); + YamlIO.mapOptional("machineFunctionInfo", MF.MachineFuncInfo); if (!YamlIO.outputting() || !MF.JumpTableInfo.Entries.empty()) YamlIO.mapOptional("jumpTable", MF.JumpTableInfo, MachineJumpTable()); YamlIO.mapOptional("body", MF.Body, BlockStringValue()); Index: include/llvm/CodeGen/MachineModuleInfo.h =================================================================== --- include/llvm/CodeGen/MachineModuleInfo.h +++ 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; } Index: include/llvm/Target/TargetMachine.h =================================================================== --- include/llvm/Target/TargetMachine.h +++ 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. Index: lib/CodeGen/MIRParser/MIParser.cpp =================================================================== --- lib/CodeGen/MIRParser/MIParser.cpp +++ 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" Index: lib/CodeGen/MIRParser/MIRParser.cpp =================================================================== --- lib/CodeGen/MIRParser/MIRParser.cpp +++ 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 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( + 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); Index: lib/CodeGen/MIRPrinter.cpp =================================================================== --- lib/CodeGen/MIRPrinter.cpp +++ 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(TM.convertFuncInfoToYAML(MF)); + raw_string_ostream StrOS(YamlMF.Body.Value.Value); bool IsNewlineNeeded = false; for (const auto &MBB : MF) { Index: lib/Target/AMDGPU/AMDGPUTargetMachine.h =================================================================== --- lib/Target/AMDGPU/AMDGPUTargetMachine.h +++ 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 Index: lib/Target/AMDGPU/AMDGPUTargetMachine.cpp =================================================================== --- lib/Target/AMDGPU/AMDGPUTargetMachine.cpp +++ 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(); + 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(MFI_); + MachineFunction &MF = PFS.MF; + SIMachineFunctionInfo *MFI = MF.getInfo(); + + 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; +} Index: lib/Target/AMDGPU/LLVMBuild.txt =================================================================== --- lib/Target/AMDGPU/LLVMBuild.txt +++ 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 Index: lib/Target/AMDGPU/SIISelLowering.cpp =================================================================== --- lib/Target/AMDGPU/SIISelLowering.cpp +++ lib/Target/AMDGPU/SIISelLowering.cpp @@ -9623,13 +9623,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); Index: lib/Target/AMDGPU/SIMachineFunctionInfo.h =================================================================== --- lib/Target/AMDGPU/SIMachineFunctionInfo.h +++ 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 { + 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 getSGPRToVGPRSpills(int FrameIndex) const { auto I = SGPRToVGPRSpills.find(FrameIndex); return (I == SGPRToVGPRSpills.end()) ? Index: lib/Target/AMDGPU/SIMachineFunctionInfo.cpp =================================================================== --- lib/Target/AMDGPU/SIMachineFunctionInfo.cpp +++ 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::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; +} Index: test/CodeGen/AMDGPU/scalar-store-cache-flush.mir =================================================================== --- test/CodeGen/AMDGPU/scalar-store-cache-flush.mir +++ 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 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: Index: test/CodeGen/AMDGPU/sgpr-spill-wrong-stack-id.mir =================================================================== --- test/CodeGen/AMDGPU/sgpr-spill-wrong-stack-id.mir +++ test/CodeGen/AMDGPU/sgpr-spill-wrong-stack-id.mir @@ -76,6 +76,10 @@ tracksRegLiveness: true frameInfo: hasCalls: true +machineFunctionInfo: + scratchRSrcReg: $sgpr0_sgpr1_sgpr2_sgpr3 + scratchWaveOffsetReg: $sgpr4 + stackPtrOffsetReg: $sgpr32 body: | bb.0: %0:sreg_32_xm0 = COPY $sgpr5 Index: test/CodeGen/AMDGPU/spill-before-exec.mir =================================================================== --- test/CodeGen/AMDGPU/spill-before-exec.mir +++ 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 } Index: test/CodeGen/AMDGPU/spill-empty-live-interval.mir =================================================================== --- test/CodeGen/AMDGPU/spill-empty-live-interval.mir +++ test/CodeGen/AMDGPU/spill-empty-live-interval.mir @@ -19,6 +19,10 @@ name: expecting_non_empty_interval tracksRegLiveness: true +machineFunctionInfo: + scratchRSrcReg: $sgpr0_sgpr1_sgpr2_sgpr3 + scratchWaveOffsetReg: $sgpr4 + stackPtrOffsetReg: $sgpr32 body: | bb.0: successors: %bb.1 @@ -49,6 +53,10 @@ # CHECK-NEXT: S_NOP 0, implicit %2.sub2 name: rematerialize_empty_interval_has_reference tracksRegLiveness: true +machineFunctionInfo: + scratchRSrcReg: $sgpr0_sgpr1_sgpr2_sgpr3 + scratchWaveOffsetReg: $sgpr4 + stackPtrOffsetReg: $sgpr32 body: | bb.0: successors: %bb.1 Index: test/CodeGen/AMDGPU/stack-slot-color-sgpr-vgpr-spills.mir =================================================================== --- test/CodeGen/AMDGPU/stack-slot-color-sgpr-vgpr-spills.mir +++ test/CodeGen/AMDGPU/stack-slot-color-sgpr-vgpr-spills.mir @@ -17,6 +17,10 @@ name: no_merge_sgpr_vgpr_spill_slot tracksRegLiveness: true +machineFunctionInfo: + scratchRSrcReg: $sgpr0_sgpr1_sgpr2_sgpr3 + scratchWaveOffsetReg: $sgpr4 + stackPtrOffsetReg: $sgpr32 body: | bb.0: %0:vgpr_32 = FLAT_LOAD_DWORD undef $vgpr0_vgpr1, 0, 0, 0, implicit $flat_scr, implicit $exec Index: test/CodeGen/AMDGPU/subreg-split-live-in-error.mir =================================================================== --- test/CodeGen/AMDGPU/subreg-split-live-in-error.mir +++ test/CodeGen/AMDGPU/subreg-split-live-in-error.mir @@ -39,6 +39,10 @@ --- name: _amdgpu_ps_main tracksRegLiveness: true +machineFunctionInfo: + scratchRSrcReg: $sgpr0_sgpr1_sgpr2_sgpr3 + scratchWaveOffsetReg: $sgpr4 + stackPtrOffsetReg: $sgpr32 liveins: - { reg: '$vgpr2', virtual-reg: '%0' } - { reg: '$vgpr3', virtual-reg: '%1' } Index: test/CodeGen/MIR/AMDGPU/machine-function-info-no-ir.mir =================================================================== --- /dev/null +++ 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 + +... + +# 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 + +... + +--- +# 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 + +... + +--- +# 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 + +... + +--- +# 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 + +... Index: test/CodeGen/MIR/AMDGPU/machine-function-info-register-parse-error1.mir =================================================================== --- /dev/null +++ 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 +... Index: test/CodeGen/MIR/AMDGPU/machine-function-info-register-parse-error2.mir =================================================================== --- /dev/null +++ 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 +... Index: test/CodeGen/MIR/AMDGPU/machine-function-info.ll =================================================================== --- /dev/null +++ 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" } Index: test/CodeGen/MIR/AMDGPU/mfi-frame-offset-reg-class.mir =================================================================== --- /dev/null +++ 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 +... Index: test/CodeGen/MIR/AMDGPU/mfi-parse-error-frame-offset-reg.mir =================================================================== --- /dev/null +++ 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 +... Index: test/CodeGen/MIR/AMDGPU/mfi-parse-error-scratch-rsrc-reg.mir =================================================================== --- /dev/null +++ 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 +... Index: test/CodeGen/MIR/AMDGPU/mfi-parse-error-scratch-wave-offset-reg.mir =================================================================== --- /dev/null +++ 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 +... Index: test/CodeGen/MIR/AMDGPU/mfi-parse-error-stack-ptr-offset-reg.mir =================================================================== --- /dev/null +++ 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 +... Index: test/CodeGen/MIR/AMDGPU/mfi-scratch-rsrc-reg-reg-class.mir =================================================================== --- /dev/null +++ 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 +... Index: test/CodeGen/MIR/AMDGPU/mfi-scratch-wave-offset-reg-class.mir =================================================================== --- /dev/null +++ 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 +... Index: test/CodeGen/MIR/AMDGPU/mfi-stack-ptr-offset-reg-class.mir =================================================================== --- /dev/null +++ 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 +...