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;
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;
}
};
+/// 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;
std::vector<FixedMachineStackObject> FixedStackObjects;
std::vector<MachineStackObject> StackObjects;
std::vector<MachineConstantPoolValue> Constants; /// Constant pool.
+ std::unique_ptr<MachineFunctionInfo> MachineFuncInfo;
MachineJumpTable JumpTableInfo;
BlockStringValue Body;
};
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());
bool doInitialization(Module &) override;
bool doFinalization(Module &) override;
+ const LLVMTargetMachine &getTarget() const { return TM; }
+
const MCContext &getContext() const { return Context; }
MCContext &getContext() { return Context; }
class MCSymbol;
class raw_pwrite_stream;
class PassManagerBuilder;
+struct PerFunctionMIParsingState;
+class SMDiagnostic;
+class SMRange;
class Target;
class TargetIntrinsicInfo;
class TargetIRAnalysis;
}
using legacy::PassManagerBase;
+namespace yaml {
+struct MachineFunctionInfo;
+}
+
//===----------------------------------------------------------------------===//
///
/// Primary interface to the complete machine description for the target
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.
//
//===----------------------------------------------------------------------===//
-#include "MIParser.h"
+#include "llvm/CodeGen/MIRParser/MIParser.h"
#include "MILexer.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/APSInt.h"
//===----------------------------------------------------------------------===//
#include "llvm/CodeGen/MIRParser/MIRParser.h"
-#include "MIParser.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringMap.h"
#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"
#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;
// 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;
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);
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) {
#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"
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;
+}
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
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
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);
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;
+}
#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"
}
};
+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
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()) ?
name: basic_insert_dcache_wb
tracksRegLiveness: false
+machineFunctionInfo:
+ isEntryFunction: true
body: |
bb.0:
name: explicit_flush_after
tracksRegLiveness: false
+machineFunctionInfo:
+ isEntryFunction: true
body: |
bb.0:
name: explicit_flush_before
tracksRegLiveness: false
+machineFunctionInfo:
+ isEntryFunction: true
body: |
bb.0:
# CHECK-NEXT: S_ENDPGM 0
name: no_scalar_store
tracksRegLiveness: false
+machineFunctionInfo:
+ isEntryFunction: true
body: |
bb.0:
name: multi_block_store
tracksRegLiveness: false
+machineFunctionInfo:
+ isEntryFunction: true
body: |
bb.0:
name: one_block_store
tracksRegLiveness: false
+machineFunctionInfo:
+ isEntryFunction: true
body: |
bb.0:
name: si_return
tracksRegLiveness: false
+machineFunctionInfo:
+ isEntryFunction: true
body: |
bb.0:
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
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 }
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
# 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
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
---
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' }
--- /dev/null
+# 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
+
+...
--- /dev/null
+# 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
+...
--- /dev/null
+# 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
+...
--- /dev/null
+; 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" }
--- /dev/null
+# 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
+...
--- /dev/null
+# 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
+...
--- /dev/null
+# 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
+...
--- /dev/null
+# 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
+...
--- /dev/null
+# 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
+...
--- /dev/null
+# 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
+...
--- /dev/null
+# 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
+...
--- /dev/null
+# 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
+...