diff --git a/llvm/include/llvm/CodeGen/MIRYamlMapping.h b/llvm/include/llvm/CodeGen/MIRYamlMapping.h --- a/llvm/include/llvm/CodeGen/MIRYamlMapping.h +++ b/llvm/include/llvm/CodeGen/MIRYamlMapping.h @@ -381,6 +381,50 @@ static const bool flow = true; }; +/// A serializaable representation of a reference to a stack object or fixed +/// stack object. +struct FrameIndex { + // The frame index as printed. This is always a positive number, even for + // fixed objects. To obtain the real index, + // MachineFrameInfo::getObjectIndexBegin has to be added. + int FI; + bool IsFixed; + SMRange SourceRange; + + FrameIndex() {} + FrameIndex(int FI, const llvm::MachineFrameInfo &MFI); + + Expected getFI(const llvm::MachineFrameInfo &MFI) const; +}; + +template <> struct ScalarTraits { + static void output(const FrameIndex &FI, void *, raw_ostream &OS) { + MachineOperand::printStackObjectReference(OS, FI.FI, FI.IsFixed, ""); + } + + static StringRef input(StringRef Scalar, void *Ctx, FrameIndex &FI) { + FI.IsFixed = false; + StringRef Num; + if (Scalar.startswith("%stack.")) { + Num = Scalar.substr(7); + } else if (Scalar.startswith("%fixed-stack.")) { + Num = Scalar.substr(13); + FI.IsFixed = true; + } else { + return "Invalid frame index, needs to start with %stack. or " + "%fixed-stack."; + } + if (Num.consumeInteger(10, FI.FI)) + return "Invalid frame index, not a valid number"; + + if (const auto *Node = + reinterpret_cast(Ctx)->getCurrentNode()) + FI.SourceRange = Node->getSourceRange(); + return StringRef(); + } + + static QuotingType mustQuote(StringRef S) { return needsQuotes(S); } +}; /// Serializable representation of CallSiteInfo. struct CallSiteInfo { diff --git a/llvm/lib/CodeGen/CMakeLists.txt b/llvm/lib/CodeGen/CMakeLists.txt --- a/llvm/lib/CodeGen/CMakeLists.txt +++ b/llvm/lib/CodeGen/CMakeLists.txt @@ -108,6 +108,7 @@ MachineStripDebug.cpp MachineTraceMetrics.cpp MachineVerifier.cpp + MIRYamlMapping.cpp ModuloSchedule.cpp MultiHazardRecognizer.cpp PatchableFunction.cpp diff --git a/llvm/lib/CodeGen/MIRYamlMapping.cpp b/llvm/lib/CodeGen/MIRYamlMapping.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/CodeGen/MIRYamlMapping.cpp @@ -0,0 +1,43 @@ +//===- MIRYamlMapping.cpp - Describe mapping between MIR and YAML ---------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the mapping between various MIR data structures and +// their corresponding YAML representation. +// +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/MIRYamlMapping.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/FormatVariadic.h" + +using namespace llvm; +using namespace llvm::yaml; + +FrameIndex::FrameIndex(int FI, const llvm::MachineFrameInfo &MFI) { + IsFixed = MFI.isFixedObjectIndex(FI); + if (IsFixed) + FI -= MFI.getObjectIndexBegin(); + this->FI = FI; +} + +// Returns the value and if the frame index is fixed or not. +Expected FrameIndex::getFI(const llvm::MachineFrameInfo &MFI) const { + int FI = this->FI; + if (IsFixed) { + if (unsigned(FI) >= MFI.getNumFixedObjects()) + return make_error( + formatv("invalid fixed frame index {0}", FI).str(), + inconvertibleErrorCode()); + FI += MFI.getObjectIndexBegin(); + } + if (unsigned(FI + MFI.getNumFixedObjects()) >= MFI.getNumObjects()) + return make_error(formatv("invalid frame index {0}", FI).str(), + inconvertibleErrorCode()); + return FI; +} diff --git a/llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp b/llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp --- a/llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp +++ b/llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp @@ -1237,8 +1237,8 @@ yaml::MachineFunctionInfo * GCNTargetMachine::convertFuncInfoToYAML(const MachineFunction &MF) const { const SIMachineFunctionInfo *MFI = MF.getInfo(); - return new yaml::SIMachineFunctionInfo(*MFI, - *MF.getSubtarget().getRegisterInfo()); + return new yaml::SIMachineFunctionInfo( + *MFI, *MF.getSubtarget().getRegisterInfo(), MF); } bool GCNTargetMachine::parseMachineFunctionInfo( @@ -1249,7 +1249,8 @@ MachineFunction &MF = PFS.MF; SIMachineFunctionInfo *MFI = MF.getInfo(); - MFI->initializeBaseYamlFields(YamlMFI); + if (MFI->initializeBaseYamlFields(YamlMFI, MF, PFS, Error, SourceRange)) + return true; if (MFI->Occupancy == 0) { // Fixup the subtarget dependent default value. diff --git a/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.h b/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.h --- a/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.h +++ b/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.h @@ -289,10 +289,12 @@ Optional ArgInfo; SIMode Mode; + Optional ScavengeFI; SIMachineFunctionInfo() = default; SIMachineFunctionInfo(const llvm::SIMachineFunctionInfo &, - const TargetRegisterInfo &TRI); + const TargetRegisterInfo &TRI, + const llvm::MachineFunction &MF); void mappingImpl(yaml::IO &YamlIO) override; ~SIMachineFunctionInfo() = default; @@ -322,6 +324,7 @@ YamlIO.mapOptional("highBitsOf32BitAddress", MFI.HighBitsOf32BitAddress, 0u); YamlIO.mapOptional("occupancy", MFI.Occupancy, 0); + YamlIO.mapOptional("scavengeFI", MFI.ScavengeFI); } }; @@ -502,7 +505,10 @@ public: SIMachineFunctionInfo(const MachineFunction &MF); - bool initializeBaseYamlFields(const yaml::SIMachineFunctionInfo &YamlMFI); + bool initializeBaseYamlFields(const yaml::SIMachineFunctionInfo &YamlMFI, + const MachineFunction &MF, + PerFunctionMIParsingState &PFS, + SMDiagnostic &Error, SMRange &SourceRange); void reserveWWMRegister(Register Reg, Optional FI) { WWMReservedRegs.insert(std::make_pair(Reg, FI)); @@ -546,6 +552,7 @@ void removeDeadFrameIndices(MachineFrameInfo &MFI); int getScavengeFI(MachineFrameInfo &MFI, const SIRegisterInfo &TRI); + Optional getOptionalScavengeFI() const { return ScavengeFI; } bool hasCalculatedTID() const { return TIDReg != 0; }; Register getTIDReg() const { return TIDReg; }; diff --git a/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp b/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp --- a/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp +++ b/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp @@ -8,6 +8,7 @@ #include "SIMachineFunctionInfo.h" #include "AMDGPUTargetMachine.h" +#include "llvm/CodeGen/MIRParser/MIParser.h" #define MAX_LANES 64 @@ -547,7 +548,8 @@ } yaml::SIMachineFunctionInfo::SIMachineFunctionInfo( - const llvm::SIMachineFunctionInfo &MFI, const TargetRegisterInfo &TRI) + const llvm::SIMachineFunctionInfo &MFI, const TargetRegisterInfo &TRI, + const llvm::MachineFunction &MF) : ExplicitKernArgSize(MFI.getExplicitKernArgSize()), MaxKernArgAlign(MFI.getMaxKernArgAlign()), LDSSize(MFI.getLDSSize()), DynLDSAlign(MFI.getDynLDSAlign()), IsEntryFunction(MFI.isEntryFunction()), @@ -561,6 +563,9 @@ FrameOffsetReg(regToString(MFI.getFrameOffsetReg(), TRI)), StackPtrOffsetReg(regToString(MFI.getStackPtrOffsetReg(), TRI)), ArgInfo(convertArgumentInfo(MFI.getArgInfo(), TRI)), Mode(MFI.getMode()) { + auto SFI = MFI.getOptionalScavengeFI(); + if (SFI) + ScavengeFI = yaml::FrameIndex(*SFI, MF.getFrameInfo()); } void yaml::SIMachineFunctionInfo::mappingImpl(yaml::IO &YamlIO) { @@ -568,7 +573,8 @@ } bool SIMachineFunctionInfo::initializeBaseYamlFields( - const yaml::SIMachineFunctionInfo &YamlMFI) { + const yaml::SIMachineFunctionInfo &YamlMFI, const MachineFunction &MF, + PerFunctionMIParsingState &PFS, SMDiagnostic &Error, SMRange &SourceRange) { ExplicitKernArgSize = YamlMFI.ExplicitKernArgSize; MaxKernArgAlign = assumeAligned(YamlMFI.MaxKernArgAlign); LDSSize = YamlMFI.LDSSize; @@ -581,6 +587,24 @@ WaveLimiter = YamlMFI.WaveLimiter; HasSpilledSGPRs = YamlMFI.HasSpilledSGPRs; HasSpilledVGPRs = YamlMFI.HasSpilledVGPRs; + + if (YamlMFI.ScavengeFI) { + auto FIOrErr = YamlMFI.ScavengeFI->getFI(MF.getFrameInfo()); + if (!FIOrErr) { + // Create a diagnostic for a the frame index. + const MemoryBuffer &Buffer = + *PFS.SM->getMemoryBuffer(PFS.SM->getMainFileID()); + + Error = SMDiagnostic(*PFS.SM, SMLoc(), Buffer.getBufferIdentifier(), 1, 1, + SourceMgr::DK_Error, toString(FIOrErr.takeError()), + "", None, None); + SourceRange = YamlMFI.ScavengeFI->SourceRange; + return true; + } + ScavengeFI = *FIOrErr; + } else { + ScavengeFI = None; + } return false; } diff --git a/llvm/test/CodeGen/MIR/AMDGPU/invalid-frame-index-invalid-fixed-stack.mir b/llvm/test/CodeGen/MIR/AMDGPU/invalid-frame-index-invalid-fixed-stack.mir new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/MIR/AMDGPU/invalid-frame-index-invalid-fixed-stack.mir @@ -0,0 +1,17 @@ +# RUN: not llc -mtriple=amdgcn-amd-amdhsa -run-pass=none -verify-machineinstrs %s -o /dev/null 2>&1 | FileCheck %s + +--- +name: invalid_scavenge_fi +stack: + - { id: 0, name: '', type: spill-slot, offset: 0, size: 16, alignment: 4, stack-id: noalloc } + - { id: 1, name: '', type: spill-slot, offset: 16, size: 16, alignment: 4, stack-id: noalloc } + - { id: 2, name: '', type: spill-slot, offset: 32, size: 16, alignment: 4, stack-id: noalloc } +machineFunctionInfo: + # CHECK: [[@LINE+1]]:17: invalid fixed frame index 2 + scavengeFI: '%fixed-stack.2' + +body: | + bb.0: + S_ENDPGM 0 + +... diff --git a/llvm/test/CodeGen/MIR/AMDGPU/invalid-frame-index-invalid-stack.mir b/llvm/test/CodeGen/MIR/AMDGPU/invalid-frame-index-invalid-stack.mir new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/MIR/AMDGPU/invalid-frame-index-invalid-stack.mir @@ -0,0 +1,17 @@ +# RUN: not llc -mtriple=amdgcn-amd-amdhsa -run-pass=none -verify-machineinstrs %s -o /dev/null 2>&1 | FileCheck %s + +--- +name: invalid_scavenge_fi +fixedStack: + - { id: 0, type: spill-slot, offset: 0, size: 16, alignment: 4, stack-id: noalloc } +stack: + - { id: 0, name: '', type: spill-slot, offset: 0, size: 16, alignment: 4, stack-id: noalloc } +machineFunctionInfo: + # CHECK: [[@LINE+1]]:17: invalid frame index 2 + scavengeFI: '%stack.2' + +body: | + bb.0: + S_ENDPGM 0 + +... diff --git a/llvm/test/CodeGen/MIR/AMDGPU/invalid-frame-index-no-stack.mir b/llvm/test/CodeGen/MIR/AMDGPU/invalid-frame-index-no-stack.mir new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/MIR/AMDGPU/invalid-frame-index-no-stack.mir @@ -0,0 +1,13 @@ +# RUN: not llc -mtriple=amdgcn-amd-amdhsa -run-pass=none -verify-machineinstrs %s -o /dev/null 2>&1 | FileCheck %s + +--- +name: invalid_scavenge_fi +machineFunctionInfo: + # CHECK: [[@LINE+1]]:17: invalid frame index 0 + scavengeFI: '%stack.0' + +body: | + bb.0: + S_ENDPGM 0 + +... diff --git a/llvm/test/CodeGen/MIR/AMDGPU/invalid-frame-index.mir b/llvm/test/CodeGen/MIR/AMDGPU/invalid-frame-index.mir new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/MIR/AMDGPU/invalid-frame-index.mir @@ -0,0 +1,13 @@ +# RUN: not llc -mtriple=amdgcn-amd-amdhsa -run-pass=none -verify-machineinstrs %s -o /dev/null 2>&1 | FileCheck %s + +--- +name: invalid_scavenge_fi +machineFunctionInfo: + # CHECK: [[@LINE+1]]:15: Invalid frame index, needs to start with %stack. or %fixed-stack + scavengeFI: 0 + +body: | + bb.0: + S_ENDPGM 0 + +... diff --git a/llvm/test/CodeGen/MIR/AMDGPU/invalid-frame-index2.mir b/llvm/test/CodeGen/MIR/AMDGPU/invalid-frame-index2.mir new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/MIR/AMDGPU/invalid-frame-index2.mir @@ -0,0 +1,13 @@ +# RUN: not llc -mtriple=amdgcn-amd-amdhsa -run-pass=none -verify-machineinstrs %s -o /dev/null 2>&1 | FileCheck %s + +--- +name: invalid_scavenge_fi +machineFunctionInfo: + # CHECK: [[@LINE+1]]:15: Invalid frame index, not a valid number + scavengeFI: '%stack.abc' + +body: | + bb.0: + S_ENDPGM 0 + +... diff --git a/llvm/test/CodeGen/MIR/AMDGPU/machine-function-info-after-pei.ll b/llvm/test/CodeGen/MIR/AMDGPU/machine-function-info-after-pei.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/MIR/AMDGPU/machine-function-info-after-pei.ll @@ -0,0 +1,50 @@ +; RUN: llc -mtriple=amdgcn-mesa-mesa3d -mcpu=tahiti -amdgpu-spill-sgpr-to-vgpr=0 -stop-after prologepilog -verify-machineinstrs %s -o - | FileCheck -check-prefix=AFTER-PEI %s + +; Test that the ScavengeFI is serialized in the SIMachineFunctionInfo. + +; AFTER-PEI-LABEL: {{^}}name: scavenge_fi +; AFTER-PEI: machineFunctionInfo: +; AFTER-PEI-NEXT: explicitKernArgSize: 12 +; AFTER-PEI-NEXT: maxKernArgAlign: 8 +; AFTER-PEI-NEXT: ldsSize: 0 +; AFTER-PEI-NEXT: dynLDSAlign: 1 +; AFTER-PEI-NEXT: isEntryFunction: true +; AFTER-PEI-NEXT: noSignedZerosFPMath: false +; AFTER-PEI-NEXT: memoryBound: false +; AFTER-PEI-NEXT: waveLimiter: false +; AFTER-PEI-NEXT: hasSpilledSGPRs: true +; AFTER-PEI-NEXT: hasSpilledVGPRs: false +; AFTER-PEI-NEXT: scratchRSrcReg: '$sgpr68_sgpr69_sgpr70_sgpr71' +; AFTER-PEI-NEXT: frameOffsetReg: '$fp_reg' +; AFTER-PEI-NEXT: stackPtrOffsetReg: '$sgpr32' +; AFTER-PEI-NEXT: argumentInfo: +; AFTER-PEI-NEXT: privateSegmentBuffer: { reg: '$sgpr0_sgpr1_sgpr2_sgpr3' } +; AFTER-PEI-NEXT: kernargSegmentPtr: { reg: '$sgpr4_sgpr5' } +; AFTER-PEI-NEXT: workGroupIDX: { reg: '$sgpr6' } +; AFTER-PEI-NEXT: privateSegmentWaveByteOffset: { reg: '$sgpr7' } +; AFTER-PEI-NEXT: workItemIDX: { reg: '$vgpr0' } +; AFTER-PEI-NEXT: mode: +; AFTER-PEI-NEXT: ieee: true +; AFTER-PEI-NEXT: dx10-clamp: true +; AFTER-PEI-NEXT: fp32-input-denormals: true +; AFTER-PEI-NEXT: fp32-output-denormals: true +; AFTER-PEI-NEXT: fp64-fp16-input-denormals: true +; AFTER-PEI-NEXT: fp64-fp16-output-denormals: true +; AFTER-PEI-NEXT: highBitsOf32BitAddress: 0 +; AFTER-PEI-NEXT: occupancy: 5 +; AFTER-PEI-NEXT: scavengeFI: '%fixed-stack.0' +; AFTER-PEI-NEXT: body: +define amdgpu_kernel void @scavenge_fi(i32 addrspace(1)* %out, i32 %in) #0 { + %wide.sgpr0 = call <32 x i32> asm sideeffect "; def $0", "=s" () #0 + %wide.sgpr1 = call <32 x i32> asm sideeffect "; def $0", "=s" () #0 + %wide.sgpr2 = call <32 x i32> asm sideeffect "; def $0", "=s" () #0 + %wide.sgpr3 = call <32 x i32> asm sideeffect "; def $0", "=s" () #0 + + call void asm sideeffect "; use $0", "s"(<32 x i32> %wide.sgpr0) #0 + call void asm sideeffect "; use $0", "s"(<32 x i32> %wide.sgpr1) #0 + call void asm sideeffect "; use $0", "s"(<32 x i32> %wide.sgpr2) #0 + call void asm sideeffect "; use $0", "s"(<32 x i32> %wide.sgpr3) #0 + ret void +} + +attributes #0 = { nounwind } diff --git a/llvm/test/CodeGen/MIR/AMDGPU/machine-function-info-no-ir.mir b/llvm/test/CodeGen/MIR/AMDGPU/machine-function-info-no-ir.mir --- a/llvm/test/CodeGen/MIR/AMDGPU/machine-function-info-no-ir.mir +++ b/llvm/test/CodeGen/MIR/AMDGPU/machine-function-info-no-ir.mir @@ -340,3 +340,18 @@ S_ENDPGM 0 ... + +--- +# ALL-LABEL: name: scavenge_fi +# ALL: scavengeFI: '%stack.0' +name: scavenge_fi +stack: + - { id: 0, name: '', type: spill-slot, offset: 0, size: 4, alignment: 4 } +machineFunctionInfo: + scavengeFI: '%stack.0' + +body: | + bb.0: + S_ENDPGM 0 + +...