diff options
| author | Stanislav Mekhanoshin <Stanislav.Mekhanoshin@amd.com> | 2021-02-17 13:37:46 -0800 |
|---|---|---|
| committer | Stanislav Mekhanoshin <Stanislav.Mekhanoshin@amd.com> | 2021-02-17 16:01:32 -0800 |
| commit | a8d9d50762c42d726274d3f1126ec97ff96e2a22 (patch) | |
| tree | 3ba3e3cfde488e025fa7acfde11ca08b69cc1572 /llvm/lib | |
| parent | 0252e6ead192f7c61e5a02ceea420bee28a2f251 (diff) | |
[AMDGPU] gfx90a support
Differential Revision: https://reviews.llvm.org/D96906
Diffstat (limited to 'llvm/lib')
66 files changed, 3947 insertions, 548 deletions
diff --git a/llvm/lib/Object/ELFObjectFile.cpp b/llvm/lib/Object/ELFObjectFile.cpp index faf614a1a97a..8285e3d9e659 100644 --- a/llvm/lib/Object/ELFObjectFile.cpp +++ b/llvm/lib/Object/ELFObjectFile.cpp @@ -457,6 +457,8 @@ StringRef ELFObjectFileBase::getAMDGPUCPUName() const { return "gfx908"; case ELF::EF_AMDGPU_MACH_AMDGCN_GFX909: return "gfx909"; + case ELF::EF_AMDGPU_MACH_AMDGCN_GFX90A: + return "gfx90a"; case ELF::EF_AMDGPU_MACH_AMDGCN_GFX90C: return "gfx90c"; diff --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp index 1eedc646e820..8267ac9c596d 100644 --- a/llvm/lib/ObjectYAML/ELFYAML.cpp +++ b/llvm/lib/ObjectYAML/ELFYAML.cpp @@ -535,6 +535,7 @@ void ScalarBitSetTraits<ELFYAML::ELF_EF>::bitset(IO &IO, BCaseMask(EF_AMDGPU_MACH_AMDGCN_GFX906, EF_AMDGPU_MACH); BCaseMask(EF_AMDGPU_MACH_AMDGCN_GFX908, EF_AMDGPU_MACH); BCaseMask(EF_AMDGPU_MACH_AMDGCN_GFX909, EF_AMDGPU_MACH); + BCaseMask(EF_AMDGPU_MACH_AMDGCN_GFX90A, EF_AMDGPU_MACH); BCaseMask(EF_AMDGPU_MACH_AMDGCN_GFX90C, EF_AMDGPU_MACH); BCaseMask(EF_AMDGPU_MACH_AMDGCN_GFX1010, EF_AMDGPU_MACH); BCaseMask(EF_AMDGPU_MACH_AMDGCN_GFX1011, EF_AMDGPU_MACH); diff --git a/llvm/lib/Support/TargetParser.cpp b/llvm/lib/Support/TargetParser.cpp index 3ccdc55b305d..abc2f68a60a3 100644 --- a/llvm/lib/Support/TargetParser.cpp +++ b/llvm/lib/Support/TargetParser.cpp @@ -104,6 +104,7 @@ constexpr GPUInfo AMDGCNGPUs[] = { {{"gfx906"}, {"gfx906"}, GK_GFX906, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_XNACK|FEATURE_SRAMECC}, {{"gfx908"}, {"gfx908"}, GK_GFX908, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_XNACK|FEATURE_SRAMECC}, {{"gfx909"}, {"gfx909"}, GK_GFX909, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_XNACK}, + {{"gfx90a"}, {"gfx90a"}, GK_GFX90A, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_XNACK|FEATURE_SRAMECC}, {{"gfx90c"}, {"gfx90c"}, GK_GFX90C, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_XNACK}, {{"gfx1010"}, {"gfx1010"}, GK_GFX1010, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_WAVE32|FEATURE_XNACK}, {{"gfx1011"}, {"gfx1011"}, GK_GFX1011, FEATURE_FAST_FMA_F32|FEATURE_FAST_DENORMAL_F32|FEATURE_WAVE32|FEATURE_XNACK}, @@ -213,6 +214,7 @@ AMDGPU::IsaVersion AMDGPU::getIsaVersion(StringRef GPU) { case GK_GFX906: return {9, 0, 6}; case GK_GFX908: return {9, 0, 8}; case GK_GFX909: return {9, 0, 9}; + case GK_GFX90A: return {9, 0, 10}; case GK_GFX90C: return {9, 0, 12}; case GK_GFX1010: return {10, 1, 0}; case GK_GFX1011: return {10, 1, 1}; diff --git a/llvm/lib/Target/AMDGPU/AMDGPU.td b/llvm/lib/Target/AMDGPU/AMDGPU.td index c352c0097c5c..8cc0d2b4e78b 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPU.td +++ b/llvm/lib/Target/AMDGPU/AMDGPU.td @@ -51,6 +51,12 @@ def HalfRate64Ops : SubtargetFeature<"half-rate-64-ops", "Most fp64 instructions are half rate instead of quarter" >; +def FullRate64Ops : SubtargetFeature<"full-rate-64-ops", + "FullRate64Ops", + "true", + "Most fp64 instructions are full rate" +>; + def FeatureFlatAddressSpace : SubtargetFeature<"flat-address-space", "FlatAddressSpace", "true", @@ -148,6 +154,12 @@ def FeatureXNACK : SubtargetFeature<"xnack", "Enable XNACK support" >; +def FeatureTgSplit : SubtargetFeature<"tgsplit", + "EnableTgSplit", + "true", + "Enable threadgroup split execution" +>; + def FeatureCuMode : SubtargetFeature<"cumode", "EnableCuMode", "true", @@ -272,6 +284,12 @@ def FeatureGFX9Insts : SubtargetFeature<"gfx9-insts", "Additional instructions for GFX9+" >; +def FeatureGFX90AInsts : SubtargetFeature<"gfx90a-insts", + "GFX90AInsts", + "true", + "Additional instructions for GFX90A+" +>; + def FeatureGFX10Insts : SubtargetFeature<"gfx10-insts", "GFX10Insts", "true", @@ -387,6 +405,18 @@ def FeatureDPP8 : SubtargetFeature<"dpp8", "Support DPP8 (Data Parallel Primitives) extension" >; +def Feature64BitDPP : SubtargetFeature<"dpp-64bit", + "Has64BitDPP", + "true", + "Support DPP (Data Parallel Primitives) extension" +>; + +def FeaturePackedFP32Ops : SubtargetFeature<"packed-fp32-ops", + "HasPackedFP32Ops", + "true", + "Support packed fp32 instructions" +>; + def FeatureR128A16 : SubtargetFeature<"r128-a16", "HasR128A16", "true", @@ -411,6 +441,12 @@ def FeatureNSAEncoding : SubtargetFeature<"nsa-encoding", "Support NSA encoding for image instructions" >; +def FeatureExtendedImageInsts : SubtargetFeature<"extended-image-insts", + "HasExtendedImageInsts", + "true", + "Support mips != 0, lod != 0, gather4, and get_lod" +>; + def FeatureGFX10_BEncoding : SubtargetFeature<"gfx10_b-encoding", "GFX10_BEncoding", "true", @@ -659,6 +695,12 @@ def FeatureUnalignedAccessMode : SubtargetFeature<"unaligned-access-mode", " supports it" >; +def FeaturePackedTID : SubtargetFeature<"packed-tid", + "HasPackedTID", + "true", + "Workitem IDs are packed into v0 at kernel launch" +>; + // Dummy feature used to disable assembler instructions. def FeatureDisable : SubtargetFeature<"", "FeatureDisable","true", @@ -675,7 +717,8 @@ def FeatureSouthernIslands : GCNSubtargetFeatureGeneration<"SOUTHERN_ISLANDS", [FeatureFP64, FeatureLocalMemorySize32768, FeatureMIMG_R128, FeatureWavefrontSize64, FeatureSMemTimeInst, FeatureMadMacF32Insts, FeatureDsSrc2Insts, FeatureLDSBankCount32, FeatureMovrel, - FeatureTrigReducedRange] + FeatureTrigReducedRange, FeatureExtendedImageInsts + ] >; def FeatureSeaIslands : GCNSubtargetFeatureGeneration<"SEA_ISLANDS", @@ -684,7 +727,8 @@ def FeatureSeaIslands : GCNSubtargetFeatureGeneration<"SEA_ISLANDS", FeatureWavefrontSize64, FeatureFlatAddressSpace, FeatureCIInsts, FeatureMovrel, FeatureTrigReducedRange, FeatureGFX7GFX8GFX9Insts, FeatureSMemTimeInst, FeatureMadMacF32Insts, - FeatureDsSrc2Insts, FeatureUnalignedBufferAccess] + FeatureDsSrc2Insts, FeatureExtendedImageInsts, FeatureUnalignedBufferAccess + ] >; def FeatureVolcanicIslands : GCNSubtargetFeatureGeneration<"VOLCANIC_ISLANDS", @@ -697,7 +741,9 @@ def FeatureVolcanicIslands : GCNSubtargetFeatureGeneration<"VOLCANIC_ISLANDS", FeatureSDWA, FeatureSDWAOutModsVOPC, FeatureSDWAMac, FeatureDPP, FeatureIntClamp, FeatureTrigReducedRange, FeatureGFX8Insts, FeatureGFX7GFX8GFX9Insts, FeatureSMemTimeInst, FeatureMadMacF32Insts, - FeatureDsSrc2Insts, FeatureFastDenormalF32, FeatureUnalignedBufferAccess] + FeatureDsSrc2Insts, FeatureExtendedImageInsts, FeatureFastDenormalF32, + FeatureUnalignedBufferAccess + ] >; def FeatureGFX9 : GCNSubtargetFeatureGeneration<"GFX9", @@ -712,9 +758,9 @@ def FeatureGFX9 : GCNSubtargetFeatureGeneration<"GFX9", FeatureFlatInstOffsets, FeatureFlatGlobalInsts, FeatureFlatScratchInsts, FeatureAddNoCarryInsts, FeatureGFX8Insts, FeatureGFX7GFX8GFX9Insts, FeatureScalarFlatScratchInsts, FeatureScalarAtomics, FeatureR128A16, - FeatureSMemTimeInst, FeatureMadMacF32Insts, FeatureDsSrc2Insts, - FeatureFastDenormalF32, FeatureUnalignedBufferAccess, FeatureUnalignedDSAccess, - FeatureSupportsXNACK] + FeatureSMemTimeInst, FeatureFastDenormalF32, FeatureSupportsXNACK, + FeatureUnalignedBufferAccess, FeatureUnalignedDSAccess + ] >; def FeatureGFX10 : GCNSubtargetFeatureGeneration<"GFX10", @@ -729,7 +775,7 @@ def FeatureGFX10 : GCNSubtargetFeatureGeneration<"GFX10", FeatureFlatInstOffsets, FeatureFlatGlobalInsts, FeatureFlatScratchInsts, FeatureAddNoCarryInsts, FeatureFmaMixInsts, FeatureGFX8Insts, FeatureNoSdstCMPX, FeatureVscnt, FeatureRegisterBanking, - FeatureVOP3Literal, FeatureDPP8, + FeatureVOP3Literal, FeatureDPP8, FeatureExtendedImageInsts, FeatureNoDataDepHazard, FeaturePkFmacF16Inst, FeatureGFX10A16, FeatureFastDenormalF32, FeatureG16, FeatureUnalignedBufferAccess, FeatureUnalignedDSAccess @@ -816,17 +862,26 @@ def FeatureISAVersion9_0_0 : FeatureSet< [FeatureGFX9, FeatureMadMixInsts, FeatureLDSBankCount32, + FeatureDsSrc2Insts, + FeatureExtendedImageInsts, + FeatureMadMacF32Insts, FeatureImageGather4D16Bug]>; def FeatureISAVersion9_0_2 : FeatureSet< [FeatureGFX9, FeatureMadMixInsts, FeatureLDSBankCount32, + FeatureDsSrc2Insts, + FeatureExtendedImageInsts, + FeatureMadMacF32Insts, FeatureImageGather4D16Bug]>; def FeatureISAVersion9_0_4 : FeatureSet< [FeatureGFX9, FeatureLDSBankCount32, + FeatureDsSrc2Insts, + FeatureExtendedImageInsts, + FeatureMadMacF32Insts, FeatureFmaMixInsts, FeatureImageGather4D16Bug]>; @@ -835,6 +890,9 @@ def FeatureISAVersion9_0_6 : FeatureSet< HalfRate64Ops, FeatureFmaMixInsts, FeatureLDSBankCount32, + FeatureDsSrc2Insts, + FeatureExtendedImageInsts, + FeatureMadMacF32Insts, FeatureDLInsts, FeatureDot1Insts, FeatureDot2Insts, @@ -846,6 +904,9 @@ def FeatureISAVersion9_0_8 : FeatureSet< HalfRate64Ops, FeatureFmaMixInsts, FeatureLDSBankCount32, + FeatureDsSrc2Insts, + FeatureExtendedImageInsts, + FeatureMadMacF32Insts, FeatureDLInsts, FeatureDot1Insts, FeatureDot2Insts, @@ -864,13 +925,40 @@ def FeatureISAVersion9_0_9 : FeatureSet< [FeatureGFX9, FeatureMadMixInsts, FeatureLDSBankCount32, + FeatureDsSrc2Insts, + FeatureExtendedImageInsts, + FeatureMadMacF32Insts, FeatureImageGather4D16Bug]>; +def FeatureISAVersion9_0_A : FeatureSet< + [FeatureGFX9, + FeatureGFX90AInsts, + FeatureFmaMixInsts, + FeatureLDSBankCount32, + FeatureDLInsts, + FeatureDot1Insts, + FeatureDot2Insts, + FeatureDot3Insts, + FeatureDot4Insts, + FeatureDot5Insts, + FeatureDot6Insts, + Feature64BitDPP, + FeaturePackedFP32Ops, + FeatureMAIInsts, + FeaturePkFmacF16Inst, + FeatureAtomicFaddInsts, + FeatureMadMacF32Insts, + FeatureSupportsSRAMECC, + FeaturePackedTID, + FullRate64Ops]>; + def FeatureISAVersion9_0_C : FeatureSet< [FeatureGFX9, FeatureMadMixInsts, FeatureLDSBankCount32, FeatureXNACK, + FeatureDsSrc2Insts, + FeatureExtendedImageInsts, FeatureImageGather4D16Bug]>; // TODO: Organize more features into groups. @@ -1077,6 +1165,14 @@ def isGFX6GFX7GFX8GFX9 : "Subtarget->getGeneration() == AMDGPUSubtarget::GFX9">, AssemblerPredicate<(all_of (not FeatureGFX10Insts))>; +def isGFX6GFX7GFX8GFX9NotGFX90A : + Predicate<"!Subtarget->hasGFX90AInsts() &&" + "(Subtarget->getGeneration() == AMDGPUSubtarget::SOUTHERN_ISLANDS ||" + " Subtarget->getGeneration() == AMDGPUSubtarget::SEA_ISLANDS ||" + " Subtarget->getGeneration() == AMDGPUSubtarget::VOLCANIC_ISLANDS ||" + " Subtarget->getGeneration() == AMDGPUSubtarget::GFX9)">, + AssemblerPredicate<(all_of (not FeatureGFX10Insts), (not FeatureGFX90AInsts))>; + def isGFX7Plus : Predicate<"Subtarget->getGeneration() >= AMDGPUSubtarget::SEA_ISLANDS">, AssemblerPredicate<(all_of FeatureCIInsts)>; @@ -1097,6 +1193,28 @@ def isGFX9Only : Predicate < "Subtarget->getGeneration() == AMDGPUSubtarget::GFX9">, AssemblerPredicate<(all_of FeatureGCN3Encoding, FeatureGFX9Insts)>; +def isGCN3ExcludingGFX90A : + Predicate<"Subtarget->isGCN3Encoding() && !Subtarget->hasGFX90AInsts()">, + AssemblerPredicate<(all_of FeatureGCN3Encoding, (not FeatureGFX90AInsts))>; + +def isGFX90APlus : + Predicate<"Subtarget->hasGFX90AInsts()">, + AssemblerPredicate<(all_of FeatureGFX90AInsts)>; + +def isNotGFX90APlus : + Predicate<"!Subtarget->hasGFX90AInsts()">, + AssemblerPredicate<(all_of (not FeatureGFX90AInsts))>; + +def isGFX8GFX9NotGFX90A : + Predicate<"!Subtarget->hasGFX90AInsts() &&" + "(Subtarget->getGeneration() == AMDGPUSubtarget::VOLCANIC_ISLANDS ||" + " Subtarget->getGeneration() == AMDGPUSubtarget::GFX9)">, + AssemblerPredicate<(all_of FeatureGFX8Insts, FeatureGCN3Encoding, (not FeatureGFX90AInsts))>; + +def isGFX90AOnly : + Predicate<"Subtarget->hasGFX90AInsts()">, + AssemblerPredicate<(all_of FeatureGFX90AInsts)>; + def isGFX8GFX9 : Predicate<"Subtarget->getGeneration() == AMDGPUSubtarget::VOLCANIC_ISLANDS ||" "Subtarget->getGeneration() == AMDGPUSubtarget::GFX9">, @@ -1177,6 +1295,15 @@ def HasDPP : Predicate<"Subtarget->hasDPP()">, def HasDPP8 : Predicate<"Subtarget->hasDPP8()">, AssemblerPredicate<(all_of (not FeatureGCN3Encoding), FeatureGFX10Insts, FeatureDPP8)>; +def Has64BitDPP : Predicate<"Subtarget->has64BitDPP()">, + AssemblerPredicate<(all_of Feature64BitDPP)>; + +def HasPackedFP32Ops : Predicate<"Subtarget->hasPackedFP32Ops()">, + AssemblerPredicate<(all_of FeaturePackedFP32Ops)>; + +def HasExtendedImageInsts : Predicate<"Subtarget->hasExtendedImageInsts()">, + AssemblerPredicate<(all_of FeatureExtendedImageInsts)>; + def HasR128A16 : Predicate<"Subtarget->hasR128A16()">, AssemblerPredicate<(all_of FeatureR128A16)>; diff --git a/llvm/lib/Target/AMDGPU/AMDGPUArgumentUsageInfo.h b/llvm/lib/Target/AMDGPU/AMDGPUArgumentUsageInfo.h index 139ac3bab14c..e9ed45d8cd14 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUArgumentUsageInfo.h +++ b/llvm/lib/Target/AMDGPU/AMDGPUArgumentUsageInfo.h @@ -143,7 +143,8 @@ struct AMDGPUFunctionArgInfo { // Input registers for non-HSA ABI ArgDescriptor ImplicitBufferPtr; - // VGPRs inputs. These are always v0, v1 and v2 for entry functions. + // VGPRs inputs. For entry functions these are either v0, v1 and v2 or packed + // into v0, 10 bits per dimension if packed-tid is set. ArgDescriptor WorkItemIDX; ArgDescriptor WorkItemIDY; ArgDescriptor WorkItemIDZ; diff --git a/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp b/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp index c655e5ec87b7..ed5ed98033a5 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp +++ b/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp @@ -328,11 +328,11 @@ bool AMDGPUAsmPrinter::doFinalization(Module &M) { // causing stale data in caches. Arguably this should be done by the linker, // which is why this isn't done for Mesa. const MCSubtargetInfo &STI = *getGlobalSTI(); - if (AMDGPU::isGFX10Plus(STI) && + if ((AMDGPU::isGFX10Plus(STI) || AMDGPU::isGFX90A(STI)) && (STI.getTargetTriple().getOS() == Triple::AMDHSA || STI.getTargetTriple().getOS() == Triple::AMDPAL)) { OutStreamer->SwitchSection(getObjFileLowering().getTextSection()); - getTargetStreamer()->EmitCodeEnd(); + getTargetStreamer()->EmitCodeEnd(STI); } return AsmPrinter::doFinalization(M); @@ -400,6 +400,7 @@ uint16_t AMDGPUAsmPrinter::getAmdhsaKernelCodeProperties( amdhsa::kernel_descriptor_t AMDGPUAsmPrinter::getAmdhsaKernelDescriptor( const MachineFunction &MF, const SIProgramInfo &PI) const { + const GCNSubtarget &STM = MF.getSubtarget<GCNSubtarget>(); amdhsa::kernel_descriptor_t KernelDescriptor; memset(&KernelDescriptor, 0x0, sizeof(KernelDescriptor)); @@ -413,6 +414,11 @@ amdhsa::kernel_descriptor_t AMDGPUAsmPrinter::getAmdhsaKernelDescriptor( KernelDescriptor.compute_pgm_rsrc2 = PI.ComputePGMRSrc2; KernelDescriptor.kernel_code_properties = getAmdhsaKernelCodeProperties(MF); + assert(STM.hasGFX90AInsts() || CurrentProgramInfo.ComputePGMRSrc3GFX90A == 0); + if (STM.hasGFX90AInsts()) + KernelDescriptor.compute_pgm_rsrc3 = + CurrentProgramInfo.ComputePGMRSrc3GFX90A; + return KernelDescriptor; } @@ -521,6 +527,11 @@ bool AMDGPUAsmPrinter::runOnMachineFunction(MachineFunction &MF) { " NumVGPRsForWavesPerEU: " + Twine(CurrentProgramInfo.NumVGPRsForWavesPerEU), false); + if (STM.hasGFX90AInsts()) + OutStreamer->emitRawComment( + " AccumOffset: " + + Twine((CurrentProgramInfo.AccumOffset + 1) * 4), false); + OutStreamer->emitRawComment( " Occupancy: " + Twine(CurrentProgramInfo.Occupancy), false); @@ -550,6 +561,21 @@ bool AMDGPUAsmPrinter::runOnMachineFunction(MachineFunction &MF) { " COMPUTE_PGM_RSRC2:TIDIG_COMP_CNT: " + Twine(G_00B84C_TIDIG_COMP_CNT(CurrentProgramInfo.ComputePGMRSrc2)), false); + + assert(STM.hasGFX90AInsts() || + CurrentProgramInfo.ComputePGMRSrc3GFX90A == 0); + if (STM.hasGFX90AInsts()) { + OutStreamer->emitRawComment( + " COMPUTE_PGM_RSRC3_GFX90A:ACCUM_OFFSET: " + + Twine((AMDHSA_BITS_GET(CurrentProgramInfo.ComputePGMRSrc3GFX90A, + amdhsa::COMPUTE_PGM_RSRC3_GFX90A_ACCUM_OFFSET))), + false); + OutStreamer->emitRawComment( + " COMPUTE_PGM_RSRC3_GFX90A:TG_SPLIT: " + + Twine((AMDHSA_BITS_GET(CurrentProgramInfo.ComputePGMRSrc3GFX90A, + amdhsa::COMPUTE_PGM_RSRC3_GFX90A_TG_SPLIT))), + false); + } } if (DumpCodeInstEmitter) { @@ -612,6 +638,8 @@ int32_t AMDGPUAsmPrinter::SIFunctionResourceInfo::getTotalNumSGPRs( int32_t AMDGPUAsmPrinter::SIFunctionResourceInfo::getTotalNumVGPRs( const GCNSubtarget &ST) const { + if (ST.hasGFX90AInsts() && NumAGPR) + return alignTo(NumVGPR, 4) + NumAGPR; return std::max(NumVGPR, NumAGPR); } @@ -985,6 +1013,8 @@ void AMDGPUAsmPrinter::getSIProgramInfo(SIProgramInfo &ProgInfo, ProgInfo.NumArchVGPR = Info.NumVGPR; ProgInfo.NumAccVGPR = Info.NumAGPR; ProgInfo.NumVGPR = Info.getTotalNumVGPRs(STM); + ProgInfo.AccumOffset = alignTo(std::max(1, Info.NumVGPR), 4) / 4 - 1; + ProgInfo.TgSplit = STM.isTgSplitEnabled(); ProgInfo.NumSGPR = Info.NumExplicitSGPR; ProgInfo.ScratchSize = Info.PrivateSegmentSize; ProgInfo.VCCUsed = Info.UsesVCC; @@ -1163,6 +1193,15 @@ void AMDGPUAsmPrinter::getSIProgramInfo(SIProgramInfo &ProgInfo, S_00B84C_LDS_SIZE(STM.isAmdHsaOS() ? 0 : ProgInfo.LDSBlocks) | S_00B84C_EXCP_EN(0); + if (STM.hasGFX90AInsts()) { + AMDHSA_BITS_SET(ProgInfo.ComputePGMRSrc3GFX90A, + amdhsa::COMPUTE_PGM_RSRC3_GFX90A_ACCUM_OFFSET, + ProgInfo.AccumOffset); + AMDHSA_BITS_SET(ProgInfo.ComputePGMRSrc3GFX90A, + amdhsa::COMPUTE_PGM_RSRC3_GFX90A_TG_SPLIT, + ProgInfo.TgSplit); + } + ProgInfo.Occupancy = STM.computeOccupancy(MF.getFunction(), ProgInfo.LDSSize, ProgInfo.NumSGPRsForWavesPerEU, ProgInfo.NumVGPRsForWavesPerEU); diff --git a/llvm/lib/Target/AMDGPU/AMDGPUCallingConv.td b/llvm/lib/Target/AMDGPU/AMDGPUCallingConv.td index 02944154924e..f25019b167ca 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUCallingConv.td +++ b/llvm/lib/Target/AMDGPU/AMDGPUCallingConv.td @@ -163,6 +163,10 @@ def CSR_AMDGPU_VGPRs : CalleeSavedRegs< (sequence "VGPR%u", 248, 255)) >; +def CSR_AMDGPU_AGPRs_32_255 : CalleeSavedRegs< + (sequence "AGPR%u", 32, 255) +>; + def CSR_AMDGPU_SGPRs_32_105 : CalleeSavedRegs< (sequence "SGPR%u", 32, 105) >; @@ -172,6 +176,13 @@ def CSR_AMDGPU_AllVGPRs : CalleeSavedRegs< (sequence "VGPR%u", 0, 255) >; +def CSR_AMDGPU_AllAGPRs : CalleeSavedRegs< + (sequence "AGPR%u", 0, 255) +>; +def CSR_AMDGPU_AllVectorRegs : CalleeSavedRegs< + (add CSR_AMDGPU_AllVGPRs, CSR_AMDGPU_AllAGPRs) +>; + // Just to get the regmask, not for calling convention purposes. def CSR_AMDGPU_AllAllocatableSRegs : CalleeSavedRegs< (add (sequence "SGPR%u", 0, 105), VCC_LO, VCC_HI) @@ -181,6 +192,10 @@ def CSR_AMDGPU_HighRegs : CalleeSavedRegs< (add CSR_AMDGPU_VGPRs, CSR_AMDGPU_SGPRs_32_105) >; +def CSR_AMDGPU_HighRegs_With_AGPRs : CalleeSavedRegs< + (add CSR_AMDGPU_HighRegs, CSR_AMDGPU_AGPRs_32_255) +>; + def CSR_AMDGPU_NoRegs : CalleeSavedRegs<(add)>; // Calling convention for leaf functions diff --git a/llvm/lib/Target/AMDGPU/AMDGPUGISel.td b/llvm/lib/Target/AMDGPU/AMDGPUGISel.td index 820aa42c65b7..38f3bb900c84 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUGISel.td +++ b/llvm/lib/Target/AMDGPU/AMDGPUGISel.td @@ -219,6 +219,8 @@ def : GINodeEquiv<G_AMDGPU_BUFFER_ATOMIC_XOR, SIbuffer_atomic_xor>; def : GINodeEquiv<G_AMDGPU_BUFFER_ATOMIC_INC, SIbuffer_atomic_inc>; def : GINodeEquiv<G_AMDGPU_BUFFER_ATOMIC_DEC, SIbuffer_atomic_dec>; def : GINodeEquiv<G_AMDGPU_BUFFER_ATOMIC_FADD, SIbuffer_atomic_fadd>; +def : GINodeEquiv<G_AMDGPU_BUFFER_ATOMIC_FMIN, SIbuffer_atomic_fmin>; +def : GINodeEquiv<G_AMDGPU_BUFFER_ATOMIC_FMAX, SIbuffer_atomic_fmax>; def : GINodeEquiv<G_AMDGPU_BUFFER_ATOMIC_CMPSWAP, SIbuffer_atomic_cmpswap>; def : GINodeEquiv<G_AMDGPU_S_BUFFER_LOAD, SIsbuffer_load>; @@ -338,5 +340,8 @@ def gi_extract_dlc : GICustomOperandRenderer<"renderExtractDLC">, def gi_extract_swz : GICustomOperandRenderer<"renderExtractSWZ">, GISDNodeXFormEquiv<extract_swz>; +def gi_extract_sccb : GICustomOperandRenderer<"renderExtractSCCB">, + GISDNodeXFormEquiv<extract_sccb>; + def gi_frameindex_to_targetframeindex : GICustomOperandRenderer<"renderFrameIndex">, GISDNodeXFormEquiv<frameindex_to_targetframeindex>; diff --git a/llvm/lib/Target/AMDGPU/AMDGPUISelDAGToDAG.cpp b/llvm/lib/Target/AMDGPU/AMDGPUISelDAGToDAG.cpp index 340f4ac6f57a..c03cde0a6d54 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUISelDAGToDAG.cpp +++ b/llvm/lib/Target/AMDGPU/AMDGPUISelDAGToDAG.cpp @@ -189,11 +189,12 @@ private: bool SelectMUBUF(SDValue Addr, SDValue &SRsrc, SDValue &VAddr, SDValue &SOffset, SDValue &Offset, SDValue &Offen, SDValue &Idxen, SDValue &Addr64, SDValue &GLC, SDValue &SLC, - SDValue &TFE, SDValue &DLC, SDValue &SWZ) const; + SDValue &TFE, SDValue &DLC, SDValue &SWZ, + SDValue &SCCB) const; bool SelectMUBUFAddr64(SDValue Addr, SDValue &SRsrc, SDValue &VAddr, SDValue &SOffset, SDValue &Offset, SDValue &GLC, SDValue &SLC, SDValue &TFE, SDValue &DLC, - SDValue &SWZ) const; + SDValue &SWZ, SDValue &SCCB) const; bool SelectMUBUFAddr64(SDValue Addr, SDValue &SRsrc, SDValue &VAddr, SDValue &SOffset, SDValue &Offset, SDValue &SLC) const; @@ -206,7 +207,8 @@ private: bool SelectMUBUFOffset(SDValue Addr, SDValue &SRsrc, SDValue &SOffset, SDValue &Offset, SDValue &GLC, SDValue &SLC, - SDValue &TFE, SDValue &DLC, SDValue &SWZ) const; + SDValue &TFE, SDValue &DLC, SDValue &SWZ, + SDValue &SCCB) const; bool SelectMUBUFOffset(SDValue Addr, SDValue &SRsrc, SDValue &Soffset, SDValue &Offset, SDValue &SLC) const; bool SelectMUBUFOffset(SDValue Addr, SDValue &SRsrc, SDValue &Soffset, @@ -322,6 +324,16 @@ static SDValue stripBitcast(SDValue Val) { // Figure out if this is really an extract of the high 16-bits of a dword. static bool isExtractHiElt(SDValue In, SDValue &Out) { In = stripBitcast(In); + + if (In.getOpcode() == ISD::EXTRACT_VECTOR_ELT) { + if (ConstantSDNode *Idx = dyn_cast<ConstantSDNode>(In.getOperand(1))) { + if (!Idx->isOne()) + return false; + Out = In.getOperand(0); + return true; + } + } + if (In.getOpcode() != ISD::TRUNCATE) return false; @@ -341,6 +353,13 @@ static bool isExtractHiElt(SDValue In, SDValue &Out) { // Look through operations that obscure just looking at the low 16-bits of the // same register. static SDValue stripExtractLoElt(SDValue In) { + if (In.getOpcode() == ISD::EXTRACT_VECTOR_ELT) { + if (ConstantSDNode *Idx = dyn_cast<ConstantSDNode>(In.getOperand(1))) { + if (Idx->isNullValue() && In.getValueSizeInBits() <= 32) + return In.getOperand(0); + } + } + if (In.getOpcode() == ISD::TRUNCATE) { SDValue Src = In.getOperand(0); if (Src.getValueType().getSizeInBits() == 32) @@ -1380,7 +1399,7 @@ bool AMDGPUDAGToDAGISel::SelectMUBUF(SDValue Addr, SDValue &Ptr, SDValue &Idxen, SDValue &Addr64, SDValue &GLC, SDValue &SLC, SDValue &TFE, SDValue &DLC, - SDValue &SWZ) const { + SDValue &SWZ, SDValue &SCCB) const { // Subtarget prefers to use flat instruction // FIXME: This should be a pattern predicate and not reach here if (Subtarget->useFlatForGlobal()) @@ -1395,6 +1414,7 @@ bool AMDGPUDAGToDAGISel::SelectMUBUF(SDValue Addr, SDValue &Ptr, TFE = CurDAG->getTargetConstant(0, DL, MVT::i1); DLC = CurDAG->getTargetConstant(0, DL, MVT::i1); SWZ = CurDAG->getTargetConstant(0, DL, MVT::i1); + SCCB = CurDAG->getTargetConstant(0, DL, MVT::i1); Idxen = CurDAG->getTargetConstant(0, DL, MVT::i1); Offen = CurDAG->getTargetConstant(0, DL, MVT::i1); @@ -1474,7 +1494,8 @@ bool AMDGPUDAGToDAGISel::SelectMUBUFAddr64(SDValue Addr, SDValue &SRsrc, SDValue &VAddr, SDValue &SOffset, SDValue &Offset, SDValue &GLC, SDValue &SLC, SDValue &TFE, - SDValue &DLC, SDValue &SWZ) const { + SDValue &DLC, SDValue &SWZ, + SDValue &SCCB) const { SDValue Ptr, Offen, Idxen, Addr64; // addr64 bit was removed for volcanic islands. @@ -1483,7 +1504,7 @@ bool AMDGPUDAGToDAGISel::SelectMUBUFAddr64(SDValue Addr, SDValue &SRsrc, return false; if (!SelectMUBUF(Addr, Ptr, VAddr, SOffset, Offset, Offen, Idxen, Addr64, - GLC, SLC, TFE, DLC, SWZ)) + GLC, SLC, TFE, DLC, SWZ, SCCB)) return false; ConstantSDNode *C = cast<ConstantSDNode>(Addr64); @@ -1505,9 +1526,9 @@ bool AMDGPUDAGToDAGISel::SelectMUBUFAddr64(SDValue Addr, SDValue &SRsrc, SDValue &Offset, SDValue &SLC) const { SLC = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i1); - SDValue GLC, TFE, DLC, SWZ; + SDValue GLC, TFE, DLC, SWZ, SCCB; - return SelectMUBUFAddr64(Addr, SRsrc, VAddr, SOffset, Offset, GLC, SLC, TFE, DLC, SWZ); + return SelectMUBUFAddr64(Addr, SRsrc, VAddr, SOffset, Offset, GLC, SLC, TFE, DLC, SWZ, SCCB); } static bool isStackPtrRelative(const MachinePointerInfo &PtrInfo) { @@ -1631,13 +1652,13 @@ bool AMDGPUDAGToDAGISel::SelectMUBUFOffset(SDValue Addr, SDValue &SRsrc, SDValue &SOffset, SDValue &Offset, SDValue &GLC, SDValue &SLC, SDValue &TFE, SDValue &DLC, - SDValue &SWZ) const { + SDValue &SWZ, SDValue &SCCB) const { SDValue Ptr, VAddr, Offen, Idxen, Addr64; const SIInstrInfo *TII = static_cast<const SIInstrInfo *>(Subtarget->getInstrInfo()); if (!SelectMUBUF(Addr, Ptr, VAddr, SOffset, Offset, Offen, Idxen, Addr64, - GLC, SLC, TFE, DLC, SWZ)) + GLC, SLC, TFE, DLC, SWZ, SCCB)) return false; if (!cast<ConstantSDNode>(Offen)->getSExtValue() && @@ -1659,16 +1680,16 @@ bool AMDGPUDAGToDAGISel::SelectMUBUFOffset(SDValue Addr, SDValue &SRsrc, bool AMDGPUDAGToDAGISel::SelectMUBUFOffset(SDValue Addr, SDValue &SRsrc, SDValue &Soffset, SDValue &Offset ) const { - SDValue GLC, SLC, TFE, DLC, SWZ; + SDValue GLC, SLC, TFE, DLC, SWZ, SCCB; - return SelectMUBUFOffset(Addr, SRsrc, Soffset, Offset, GLC, SLC, TFE, DLC, SWZ); + return SelectMUBUFOffset(Addr, SRsrc, Soffset, Offset, GLC, SLC, TFE, DLC, SWZ, SCCB); } bool AMDGPUDAGToDAGISel::SelectMUBUFOffset(SDValue Addr, SDValue &SRsrc, SDValue &Soffset, SDValue &Offset, SDValue &SLC) const { - SDValue GLC, TFE, DLC, SWZ; + SDValue GLC, TFE, DLC, SWZ, SCCB; - return SelectMUBUFOffset(Addr, SRsrc, Soffset, Offset, GLC, SLC, TFE, DLC, SWZ); + return SelectMUBUFOffset(Addr, SRsrc, Soffset, Offset, GLC, SLC, TFE, DLC, SWZ, SCCB); } // Find a load or store from corresponding pattern root. @@ -2773,18 +2794,62 @@ bool AMDGPUDAGToDAGISel::SelectVOP3PMods(SDValue In, SDValue &Src, if (isExtractHiElt(Hi, Hi)) Mods |= SISrcMods::OP_SEL_1; + unsigned VecSize = Src.getValueSizeInBits(); Lo = stripExtractLoElt(Lo); Hi = stripExtractLoElt(Hi); + if (Lo.getValueSizeInBits() > VecSize) { + Lo = CurDAG->getTargetExtractSubreg( + (VecSize > 32) ? AMDGPU::sub0_sub1 : AMDGPU::sub0, SDLoc(In), + MVT::getIntegerVT(VecSize), Lo); + } + + if (Hi.getValueSizeInBits() > VecSize) { + Hi = CurDAG->getTargetExtractSubreg( + (VecSize > 32) ? AMDGPU::sub0_sub1 : AMDGPU::sub0, SDLoc(In), + MVT::getIntegerVT(VecSize), Hi); + } + + assert(Lo.getValueSizeInBits() <= VecSize && + Hi.getValueSizeInBits() <= VecSize); + if (Lo == Hi && !isInlineImmediate(Lo.getNode())) { // Really a scalar input. Just select from the low half of the register to // avoid packing. - Src = Lo; + if (VecSize == 32 || VecSize == Lo.getValueSizeInBits()) { + Src = Lo; + } else { + assert(Lo.getValueSizeInBits() == 32 && VecSize == 64); + + SDLoc SL(In); + SDValue Undef = SDValue( + CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, SL, + Lo.getValueType()), 0); + auto RC = Lo->isDivergent() ? AMDGPU::VReg_64RegClassID + : AMDGPU::SReg_64RegClassID; + const SDValue Ops[] = { + CurDAG->getTargetConstant(RC, SL, MVT::i32), + Lo, CurDAG->getTargetConstant(AMDGPU::sub0, SL, MVT::i32), + Undef, CurDAG->getTargetConstant(AMDGPU::sub1, SL, MVT::i32) }; + + Src = SDValue(CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, SL, + Src.getValueType(), Ops), 0); + } SrcMods = CurDAG->getTargetConstant(Mods, SDLoc(In), MVT::i32); return true; } + if (VecSize == 64 && Lo == Hi && isa<ConstantFPSDNode>(Lo)) { + uint64_t Lit = cast<ConstantFPSDNode>(Lo)->getValueAPF() + .bitcastToAPInt().getZExtValue(); + if (AMDGPU::isInlinableLiteral32(Lit, Subtarget->hasInv2PiInlineImm())) { + Src = CurDAG->getTargetConstant(Lit, SDLoc(In), MVT::i64);; + SrcMods = CurDAG->getTargetConstant(Mods, SDLoc(In), MVT::i32); + return true; + } + } + Mods = VecMods; } diff --git a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp index afdca239b0ff..c7abfd5d50d6 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp +++ b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp @@ -4345,6 +4345,8 @@ const char* AMDGPUTargetLowering::getTargetNodeName(unsigned Opcode) const { NODE_NAME_CASE(BUFFER_ATOMIC_CMPSWAP) NODE_NAME_CASE(BUFFER_ATOMIC_CSUB) NODE_NAME_CASE(BUFFER_ATOMIC_FADD) + NODE_NAME_CASE(BUFFER_ATOMIC_FMIN) + NODE_NAME_CASE(BUFFER_ATOMIC_FMAX) case AMDGPUISD::LAST_AMDGPU_ISD_NUMBER: break; } diff --git a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h index ce3618f83130..25b20999e0f8 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h +++ b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h @@ -523,6 +523,8 @@ enum NodeType : unsigned { BUFFER_ATOMIC_CMPSWAP, BUFFER_ATOMIC_CSUB, BUFFER_ATOMIC_FADD, + BUFFER_ATOMIC_FMIN, + BUFFER_ATOMIC_FMAX, LAST_AMDGPU_ISD_NUMBER }; diff --git a/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp b/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp index de92ce0e4dde..1ccef774107b 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp +++ b/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.cpp @@ -1456,7 +1456,7 @@ static bool parseTexFail(uint64_t TexFailCtrl, bool &TFE, bool &LWE, } static bool parseCachePolicy(uint64_t Value, - bool *GLC, bool *SLC, bool *DLC) { + bool *GLC, bool *SLC, bool *DLC, bool *SCC) { if (GLC) { *GLC = (Value & 0x1) ? 1 : 0; Value &= ~(uint64_t)0x1; @@ -1469,6 +1469,10 @@ static bool parseCachePolicy(uint64_t Value, *DLC = (Value & 0x4) ? 1 : 0; Value &= ~(uint64_t)0x4; } + if (SCC) { + *SCC = (Value & 0x10) ? 1 : 0; + Value &= ~(uint64_t)0x10; + } return Value == 0; } @@ -1601,16 +1605,17 @@ bool AMDGPUInstructionSelector::selectImageIntrinsic( bool GLC = false; bool SLC = false; bool DLC = false; + bool SCC = false; if (BaseOpcode->Atomic) { GLC = true; // TODO no-return optimization if (!parseCachePolicy( MI.getOperand(ArgOffset + Intr->CachePolicyIndex).getImm(), nullptr, - &SLC, IsGFX10Plus ? &DLC : nullptr)) + &SLC, IsGFX10Plus ? &DLC : nullptr, &SCC)) return false; } else { if (!parseCachePolicy( MI.getOperand(ArgOffset + Intr->CachePolicyIndex).getImm(), &GLC, - &SLC, IsGFX10Plus ? &DLC : nullptr)) + &SLC, IsGFX10Plus ? &DLC : nullptr, &SCC)) return false; } @@ -1700,6 +1705,8 @@ bool AMDGPUInstructionSelector::selectImageIntrinsic( MIB.addImm(Unorm); if (IsGFX10Plus) MIB.addImm(DLC); + else + MIB.addImm(SCC); MIB.addImm(GLC); MIB.addImm(SLC); @@ -2904,6 +2911,8 @@ bool AMDGPUInstructionSelector::selectG_SHUFFLE_VECTOR( bool AMDGPUInstructionSelector::selectAMDGPU_BUFFER_ATOMIC_FADD( MachineInstr &MI) const { + if (STI.hasGFX90AInsts()) + return selectImpl(MI, *CoverageInfo); MachineBasicBlock *MBB = MI.getParent(); const DebugLoc &DL = MI.getDebugLoc(); @@ -2988,6 +2997,9 @@ bool AMDGPUInstructionSelector::selectAMDGPU_BUFFER_ATOMIC_FADD( bool AMDGPUInstructionSelector::selectGlobalAtomicFaddIntrinsic( MachineInstr &MI) const{ + if (STI.hasGFX90AInsts()) + return selectImpl(MI, *CoverageInfo); + MachineBasicBlock *MBB = MI.getParent(); const DebugLoc &DL = MI.getDebugLoc(); @@ -3013,6 +3025,7 @@ bool AMDGPUInstructionSelector::selectGlobalAtomicFaddIntrinsic( .addReg(Data) .addImm(Addr.second) .addImm(0) // SLC + .addImm(0) // SSCB .cloneMemRefs(MI); MI.eraseFromParent(); @@ -4143,7 +4156,8 @@ AMDGPUInstructionSelector::selectMUBUFAddr64(MachineOperand &Root) const { addZeroImm, // slc addZeroImm, // tfe addZeroImm, // dlc - addZeroImm // swz + addZeroImm, // swz + addZeroImm // scc }}; } @@ -4171,7 +4185,8 @@ AMDGPUInstructionSelector::selectMUBUFOffset(MachineOperand &Root) const { addZeroImm, // slc addZeroImm, // tfe addZeroImm, // dlc - addZeroImm // swz + addZeroImm, // swz + addZeroImm // scc }}; } @@ -4345,6 +4360,13 @@ void AMDGPUInstructionSelector::renderExtractSWZ(MachineInstrBuilder &MIB, MIB.addImm((MI.getOperand(OpIdx).getImm() >> 3) & 1); } +void AMDGPUInstructionSelector::renderExtractSCCB(MachineInstrBuilder &MIB, + const MachineInstr &MI, + int OpIdx) const { + assert(OpIdx >= 0 && "expected to match an immediate operand"); + MIB.addImm((MI.getOperand(OpIdx).getImm() >> 4) & 1); +} + void AMDGPUInstructionSelector::renderFrameIndex(MachineInstrBuilder &MIB, const MachineInstr &MI, int OpIdx) const { diff --git a/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.h b/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.h index ea561deb5f61..b604cadef8fe 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.h +++ b/llvm/lib/Target/AMDGPU/AMDGPUInstructionSelector.h @@ -291,6 +291,9 @@ private: int OpIdx) const; void renderExtractSWZ(MachineInstrBuilder &MIB, const MachineInstr &MI, int OpIdx) const; + void renderExtractSCCB(MachineInstrBuilder &MIB, const MachineInstr &MI, + int OpIdx) const; + void renderFrameIndex(MachineInstrBuilder &MIB, const MachineInstr &MI, int OpIdx) const; diff --git a/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp b/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp index 322ad1798009..931ce9908823 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp +++ b/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp @@ -1287,8 +1287,10 @@ AMDGPULegalizerInfo::AMDGPULegalizerInfo(const GCNSubtarget &ST_, } if (ST.hasLDSFPAtomics()) { - getActionDefinitionsBuilder(G_ATOMICRMW_FADD) + auto &Atomic = getActionDefinitionsBuilder(G_ATOMICRMW_FADD) .legalFor({{S32, LocalPtr}, {S32, RegionPtr}}); + if (ST.hasGFX90AInsts()) + Atomic.legalFor({{S64, LocalPtr}}); } // BUFFER/FLAT_ATOMIC_CMP_SWAP on GCN GPUs needs input marshalling, and output @@ -3903,9 +3905,16 @@ static unsigned getBufferAtomicPseudo(Intrinsic::ID IntrID) { case Intrinsic::amdgcn_raw_buffer_atomic_cmpswap: case Intrinsic::amdgcn_struct_buffer_atomic_cmpswap: return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_CMPSWAP; + case Intrinsic::amdgcn_buffer_atomic_fadd: case Intrinsic::amdgcn_raw_buffer_atomic_fadd: case Intrinsic::amdgcn_struct_buffer_atomic_fadd: return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_FADD; + case Intrinsic::amdgcn_raw_buffer_atomic_fmin: + case Intrinsic::amdgcn_struct_buffer_atomic_fmin: + return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_FMIN; + case Intrinsic::amdgcn_raw_buffer_atomic_fmax: + case Intrinsic::amdgcn_struct_buffer_atomic_fmax: + return AMDGPU::G_AMDGPU_BUFFER_ATOMIC_FMAX; default: llvm_unreachable("unhandled atomic opcode"); } @@ -4815,6 +4824,11 @@ bool AMDGPULegalizerInfo::legalizeIntrinsic(LegalizerHelper &Helper, case Intrinsic::amdgcn_struct_buffer_atomic_fadd: case Intrinsic::amdgcn_raw_buffer_atomic_cmpswap: case Intrinsic::amdgcn_struct_buffer_atomic_cmpswap: + case Intrinsic::amdgcn_buffer_atomic_fadd: + case Intrinsic::amdgcn_raw_buffer_atomic_fmin: + case Intrinsic::amdgcn_struct_buffer_atomic_fmin: + case Intrinsic::amdgcn_raw_buffer_atomic_fmax: + case Intrinsic::amdgcn_struct_buffer_atomic_fmax: return legalizeBufferAtomic(MI, B, IntrID); case Intrinsic::amdgcn_atomic_inc: return legalizeAtomicIncDec(MI, B, true); diff --git a/llvm/lib/Target/AMDGPU/AMDGPURegisterBankInfo.cpp b/llvm/lib/Target/AMDGPU/AMDGPURegisterBankInfo.cpp index bb3d0bf8304a..59279b6819fa 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPURegisterBankInfo.cpp +++ b/llvm/lib/Target/AMDGPU/AMDGPURegisterBankInfo.cpp @@ -1714,6 +1714,15 @@ static unsigned extractDLC(unsigned CachePolicy) { return (CachePolicy >> 2) & 1; } +static unsigned extractSWZ(unsigned CachePolicy) { + return (CachePolicy >> 3) & 1; +} + +static unsigned extractSCCB(unsigned CachePolicy) { + return (CachePolicy >> 4) & 1; +} + + MachineInstr * AMDGPURegisterBankInfo::selectStoreIntrinsic(MachineIRBuilder &B, MachineInstr &MI) const { @@ -1782,6 +1791,8 @@ AMDGPURegisterBankInfo::selectStoreIntrinsic(MachineIRBuilder &B, .addImm(extractSLC(CachePolicy)) .addImm(0) // tfe: FIXME: Remove from inst .addImm(extractDLC(CachePolicy)) + .addImm(extractSWZ(CachePolicy)) + .addImm(extractSCCB(CachePolicy)) .cloneMemRefs(MI); // FIXME: We need a way to report failure from applyMappingImpl. @@ -2839,7 +2850,9 @@ void AMDGPURegisterBankInfo::applyMappingImpl( executeInWaterfallLoop(MI, MRI, {2, 5}); return; } - case AMDGPU::G_AMDGPU_BUFFER_ATOMIC_FADD: { + case AMDGPU::G_AMDGPU_BUFFER_ATOMIC_FADD: + case AMDGPU::G_AMDGPU_BUFFER_ATOMIC_FMIN: + case AMDGPU::G_AMDGPU_BUFFER_ATOMIC_FMAX: { applyDefaultMapping(OpdMapper); executeInWaterfallLoop(MI, MRI, {2, 5}); return; @@ -3807,7 +3820,9 @@ AMDGPURegisterBankInfo::getInstrMapping(const MachineInstr &MI) const { case AMDGPU::G_AMDGPU_BUFFER_ATOMIC_XOR: case AMDGPU::G_AMDGPU_BUFFER_ATOMIC_INC: case AMDGPU::G_AMDGPU_BUFFER_ATOMIC_DEC: - case AMDGPU::G_AMDGPU_BUFFER_ATOMIC_FADD: { + case AMDGPU::G_AMDGPU_BUFFER_ATOMIC_FADD: + case AMDGPU::G_AMDGPU_BUFFER_ATOMIC_FMIN: + case AMDGPU::G_AMDGPU_BUFFER_ATOMIC_FMAX: { // vdata_out OpdsMapping[0] = getVGPROpMapping(MI.getOperand(0).getReg(), MRI, *TRI); @@ -4064,7 +4079,14 @@ AMDGPURegisterBankInfo::getInstrMapping(const MachineInstr &MI) const { case Intrinsic::amdgcn_mfma_i32_32x32x4i8: case Intrinsic::amdgcn_mfma_i32_32x32x8i8: case Intrinsic::amdgcn_mfma_f32_32x32x2bf16: - case Intrinsic::amdgcn_mfma_f32_32x32x4bf16: { + case Intrinsic::amdgcn_mfma_f32_32x32x4bf16: + case Intrinsic::amdgcn_mfma_f32_32x32x4bf16_1k: + case Intrinsic::amdgcn_mfma_f32_16x16x4bf16_1k: + case Intrinsic::amdgcn_mfma_f32_4x4x4bf16_1k: + case Intrinsic::amdgcn_mfma_f32_32x32x8bf16_1k: + case Intrinsic::amdgcn_mfma_f32_16x16x16bf16_1k: + case Intrinsic::amdgcn_mfma_f64_16x16x4f64: + case Intrinsic::amdgcn_mfma_f64_4x4x4f64: { // Default for MAI intrinsics. // srcC can also be an immediate which can be folded later. // FIXME: Should we eventually add an alternative mapping with AGPR src @@ -4138,6 +4160,11 @@ AMDGPURegisterBankInfo::getInstrMapping(const MachineInstr &MI) const { } case Intrinsic::amdgcn_global_atomic_fadd: case Intrinsic::amdgcn_global_atomic_csub: + case Intrinsic::amdgcn_global_atomic_fmin: + case Intrinsic::amdgcn_global_atomic_fmax: + case Intrinsic::amdgcn_flat_atomic_fadd: + case Intrinsic::amdgcn_flat_atomic_fmin: + case Intrinsic::amdgcn_flat_atomic_fmax: return getDefaultMappingAllVGPR(MI); case Intrinsic::amdgcn_ds_ordered_add: case Intrinsic::amdgcn_ds_ordered_swap: { diff --git a/llvm/lib/Target/AMDGPU/AMDGPUSearchableTables.td b/llvm/lib/Target/AMDGPU/AMDGPUSearchableTables.td index e63294b55ea8..afe016731395 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUSearchableTables.td +++ b/llvm/lib/Target/AMDGPU/AMDGPUSearchableTables.td @@ -199,6 +199,12 @@ def : SourceOfDivergence<int_r600_read_tidig_z>; def : SourceOfDivergence<int_amdgcn_atomic_inc>; def : SourceOfDivergence<int_amdgcn_atomic_dec>; def : SourceOfDivergence<int_amdgcn_global_atomic_csub>; +def : SourceOfDivergence<int_amdgcn_global_atomic_fadd>; +def : SourceOfDivergence<int_amdgcn_global_atomic_fmin>; +def : SourceOfDivergence<int_amdgcn_global_atomic_fmax>; +def : SourceOfDivergence<int_amdgcn_flat_atomic_fadd>; +def : SourceOfDivergence<int_amdgcn_flat_atomic_fmin>; +def : SourceOfDivergence<int_amdgcn_flat_atomic_fmax>; def : SourceOfDivergence<int_amdgcn_ds_fadd>; def : SourceOfDivergence<int_amdgcn_ds_fmin>; def : SourceOfDivergence<int_amdgcn_ds_fmax>; @@ -226,6 +232,8 @@ def : SourceOfDivergence<int_amdgcn_raw_buffer_atomic_xor>; def : SourceOfDivergence<int_amdgcn_raw_buffer_atomic_inc>; def : SourceOfDivergence<int_amdgcn_raw_buffer_atomic_dec>; def : SourceOfDivergence<int_amdgcn_raw_buffer_atomic_fadd>; +def : SourceOfDivergence<int_amdgcn_raw_buffer_atomic_fmin>; +def : SourceOfDivergence<int_amdgcn_raw_buffer_atomic_fmax>; def : SourceOfDivergence<int_amdgcn_raw_buffer_atomic_cmpswap>; def : SourceOfDivergence<int_amdgcn_struct_buffer_atomic_swap>; def : SourceOfDivergence<int_amdgcn_struct_buffer_atomic_add>; @@ -240,6 +248,8 @@ def : SourceOfDivergence<int_amdgcn_struct_buffer_atomic_xor>; def : SourceOfDivergence<int_amdgcn_struct_buffer_atomic_inc>; def : SourceOfDivergence<int_amdgcn_struct_buffer_atomic_dec>; def : SourceOfDivergence<int_amdgcn_struct_buffer_atomic_fadd>; +def : SourceOfDivergence<int_amdgcn_struct_buffer_atomic_fmin>; +def : SourceOfDivergence<int_amdgcn_struct_buffer_atomic_fmax>; def : SourceOfDivergence<int_amdgcn_struct_buffer_atomic_cmpswap>; def : SourceOfDivergence<int_amdgcn_buffer_atomic_csub>; def : SourceOfDivergence<int_amdgcn_ps_live>; @@ -275,6 +285,13 @@ def : SourceOfDivergence<int_amdgcn_mfma_i32_32x32x4i8>; def : SourceOfDivergence<int_amdgcn_mfma_i32_32x32x8i8>; def : SourceOfDivergence<int_amdgcn_mfma_f32_32x32x2bf16>; def : SourceOfDivergence<int_amdgcn_mfma_f32_32x32x4bf16>; +def : SourceOfDivergence<int_amdgcn_mfma_f32_32x32x4bf16_1k>; +def : SourceOfDivergence<int_amdgcn_mfma_f32_16x16x4bf16_1k>; +def : SourceOfDivergence<int_amdgcn_mfma_f32_4x4x4bf16_1k>; +def : SourceOfDivergence<int_amdgcn_mfma_f32_32x32x8bf16_1k>; +def : SourceOfDivergence<int_amdgcn_mfma_f32_16x16x16bf16_1k>; +def : SourceOfDivergence<int_amdgcn_mfma_f64_16x16x4f64>; +def : SourceOfDivergence<int_amdgcn_mfma_f64_4x4x4f64>; // The dummy boolean output is divergent from the IR's perspective, // but the mask results are uniform. These produce a divergent and diff --git a/llvm/lib/Target/AMDGPU/AMDGPUSubtarget.cpp b/llvm/lib/Target/AMDGPU/AMDGPUSubtarget.cpp index f1a7d7463676..ec34237b201c 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUSubtarget.cpp +++ b/llvm/lib/Target/AMDGPU/AMDGPUSubtarget.cpp @@ -176,6 +176,7 @@ GCNSubtarget::initializeSubtargetDependencies(const Triple &TT, AMDGPUSubtarget::AMDGPUSubtarget(const Triple &TT) : TargetTriple(TT), + GCN3Encoding(false), Has16BitInsts(false), HasMadMixInsts(false), HasMadMacF32Insts(false), @@ -207,6 +208,7 @@ GCNSubtarget::GCNSubtarget(const Triple &TT, StringRef GPU, StringRef FS, FastFMAF32(false), FastDenormalF32(false), HalfRate64Ops(false), + FullRate64Ops(false), FlatForGlobal(false), AutoWaitcntBeforeBarrier(false), @@ -216,6 +218,7 @@ GCNSubtarget::GCNSubtarget(const Triple &TT, StringRef GPU, StringRef FS, HasApertureRegs(false), SupportsXNACK(false), EnableXNACK(false), + EnableTgSplit(false), EnableCuMode(false), TrapHandler(false), @@ -227,10 +230,10 @@ GCNSubtarget::GCNSubtarget(const Triple &TT, StringRef GPU, StringRef FS, DumpCode(false), FP64(false), - GCN3Encoding(false), CIInsts(false), GFX8Insts(false), GFX9Insts(false), + GFX90AInsts(false), GFX10Insts(false), GFX10_3Insts(false), GFX7GFX8GFX9Insts(false), @@ -249,6 +252,9 @@ GCNSubtarget::GCNSubtarget(const Triple &TT, StringRef GPU, StringRef FS, HasSDWAOutModsVOPC(false), HasDPP(false), HasDPP8(false), + Has64BitDPP(false), + HasPackedFP32Ops(false), + HasExtendedImageInsts(false), HasR128A16(false), HasGFX10A16(false), HasG16(false), @@ -284,6 +290,7 @@ GCNSubtarget::GCNSubtarget(const Triple &TT, StringRef GPU, StringRef FS, HasMFMAInlineLiteralBug(false), UnalignedBufferAccess(false), UnalignedDSAccess(false), + HasPackedTID(false), ScalarizeGlobal(false), @@ -776,6 +783,9 @@ unsigned GCNSubtarget::getMaxNumVGPRs(const MachineFunction &MF) const { unsigned Requested = AMDGPU::getIntegerAttribute( F, "amdgpu-num-vgpr", MaxNumVGPRs); + if (hasGFX90AInsts()) + Requested *= 2; + // Make sure requested value is compatible with values implied by // default/requested minimum/maximum number of waves per execution unit. if (Requested && Requested > getMaxNumVGPRs(WavesPerEU.first)) diff --git a/llvm/lib/Target/AMDGPU/AMDGPUSubtarget.h b/llvm/lib/Target/AMDGPU/AMDGPUSubtarget.h index ba3a8acae551..08576356255f 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUSubtarget.h +++ b/llvm/lib/Target/AMDGPU/AMDGPUSubtarget.h @@ -45,6 +45,7 @@ private: Triple TargetTriple; protected: + bool GCN3Encoding; bool Has16BitInsts; bool HasMadMixInsts; bool HasMadMacF32Insts; @@ -124,6 +125,10 @@ public: return TargetTriple.getArch() == Triple::amdgcn; } + bool isGCN3Encoding() const { + return GCN3Encoding; + } + bool has16BitInsts() const { return Has16BitInsts; } diff --git a/llvm/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.cpp b/llvm/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.cpp index 7b8a79640bb2..360a2c71160b 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.cpp +++ b/llvm/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.cpp @@ -311,7 +311,7 @@ unsigned GCNTTIImpl::getNumberOfRegisters(unsigned RCID) const { } unsigned GCNTTIImpl::getRegisterBitWidth(bool Vector) const { - return 32; + return (Vector && ST->hasPackedFP32Ops()) ? 64 : 32; } unsigned GCNTTIImpl::getMinVectorRegisterBitWidth() const { @@ -321,7 +321,9 @@ unsigned GCNTTIImpl::getMinVectorRegisterBitWidth() const { unsigned GCNTTIImpl::getMaximumVF(unsigned ElemWidth, unsigned Opcode) const { if (Opcode == Instruction::Load || Opcode == Instruction::Store) return 32 * 4 / ElemWidth; - return (ElemWidth == 16 && ST->has16BitInsts()) ? 2 : 1; + return (ElemWidth == 16 && ST->has16BitInsts()) ? 2 + : (ElemWidth == 32 && ST->hasPackedFP32Ops()) ? 2 + : 1; } unsigned GCNTTIImpl::getLoadVectorFactor(unsigned VF, unsigned LoadSize, @@ -628,6 +630,8 @@ int GCNTTIImpl::getArithmeticInstrCost(unsigned Opcode, Type *Ty, LLVM_FALLTHROUGH; case ISD::FADD: case ISD::FSUB: + if (ST->hasPackedFP32Ops() && SLT == MVT::f32) + NElts = (NElts + 1) / 2; if (SLT == MVT::f64) return LT.first * NElts * get64BitInstrCost(CostKind); @@ -779,7 +783,8 @@ int GCNTTIImpl::getIntrinsicInstrCost(const IntrinsicCostAttributes &ICA, if (SLT == MVT::f64) return LT.first * NElts * get64BitInstrCost(CostKind); - if (ST->has16BitInsts() && SLT == MVT::f16) + if ((ST->has16BitInsts() && SLT == MVT::f16) || + (ST->hasPackedFP32Ops() && SLT == MVT::f32)) NElts = (NElts + 1) / 2; // TODO: Get more refined intrinsic costs? @@ -1192,8 +1197,10 @@ void GCNTTIImpl::getPeelingPreferences(Loop *L, ScalarEvolution &SE, } int GCNTTIImpl::get64BitInstrCost(TTI::TargetCostKind CostKind) const { - return ST->hasHalfRate64Ops() ? getHalfRateInstrCost(CostKind) - : getQuarterRateInstrCost(CostKind); + return ST->hasFullRate64Ops() + ? getFullRateInstrCost() + : ST->hasHalfRate64Ops() ? getHalfRateInstrCost(CostKind) + : getQuarterRateInstrCost(CostKind); } R600TTIImpl::R600TTIImpl(const AMDGPUTargetMachine *TM, const Function &F) diff --git a/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp b/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp index dda528ab4b3f..a0616922d317 100644 --- a/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp +++ b/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp @@ -11,6 +11,7 @@ #include "MCTargetDesc/AMDGPUTargetStreamer.h" #include "SIDefines.h" #include "SIInstrInfo.h" +#include "SIRegisterInfo.h" #include "TargetInfo/AMDGPUTargetInfo.h" #include "Utils/AMDGPUAsmUtils.h" #include "Utils/AMDGPUBaseInfo.h" @@ -114,6 +115,7 @@ public: ImmTyOffset0, ImmTyOffset1, ImmTyDLC, + ImmTySCCB, ImmTyGLC, ImmTySLC, ImmTySWZ, @@ -299,6 +301,8 @@ public: return isRegKind() && getReg() == AMDGPU::SGPR_NULL; } + bool isVRegWithInputMods() const; + bool isSDWAOperand(MVT type) const; bool isSDWAFP16Operand() const; bool isSDWAFP32Operand() const; @@ -337,6 +341,7 @@ public: bool isGDS() const { return isImmTy(ImmTyGDS); } bool isLDS() const { return isImmTy(ImmTyLDS); } bool isDLC() const { return isImmTy(ImmTyDLC); } + bool isSCCB() const { return isImmTy(ImmTySCCB); } bool isGLC() const { return isImmTy(ImmTyGLC); } // "GLC_1" is a MatchClass of the GLC_1 operand with the default and forced // value of the GLC operand. @@ -449,6 +454,26 @@ public: return isSSrcF16(); } + bool isSSrcV2FP32() const { + llvm_unreachable("cannot happen"); + return isSSrcF32(); + } + + bool isSCSrcV2FP32() const { + llvm_unreachable("cannot happen"); + return isSCSrcF32(); + } + + bool isSSrcV2INT32() const { + llvm_unreachable("cannot happen"); + return isSSrcB32(); + } + + bool isSCSrcV2INT32() const { + llvm_unreachable("cannot happen"); + return isSCSrcB32(); + } + bool isSSrcOrLdsB32() const { return isRegOrInlineNoMods(AMDGPU::SRegOrLds_32RegClassID, MVT::i32) || isLiteralImm(MVT::i32) || isExpr(); @@ -502,6 +527,22 @@ public: return isVSrcB16() || isLiteralImm(MVT::v2i16); } + bool isVCSrcV2FP32() const { + return isVCSrcF64(); + } + + bool isVSrcV2FP32() const { + return isVSrcF64() || isLiteralImm(MVT::v2f32); + } + + bool isVCSrcV2INT32() const { + return isVCSrcB64(); + } + + bool isVSrcV2INT32() const { + return isVSrcB64() || isLiteralImm(MVT::v2i32); + } + bool isVSrcF32() const { return isVCSrcF32() || isLiteralImm(MVT::f32) || isExpr(); } @@ -542,6 +583,102 @@ public: return isVISrcF16() || isVISrcB32(); } + bool isVISrc_64B64() const { + return isRegOrInlineNoMods(AMDGPU::VReg_64RegClassID, MVT::i64); + } + + bool isVISrc_64F64() const { + return isRegOrInlineNoMods(AMDGPU::VReg_64RegClassID, MVT::f64); + } + + bool isVISrc_64V2FP32() const { + return isRegOrInlineNoMods(AMDGPU::VReg_64RegClassID, MVT::f32); + } + + bool isVISrc_64V2INT32() const { + return isRegOrInlineNoMods(AMDGPU::VReg_64RegClassID, MVT::i32); + } + + bool isVISrc_256B64() const { + return isRegOrInlineNoMods(AMDGPU::VReg_256RegClassID, MVT::i64); + } + + bool isVISrc_256F64() const { + return isRegOrInlineNoMods(AMDGPU::VReg_256RegClassID, MVT::f64); + } + + bool isVISrc_128B16() const { + return isRegOrInlineNoMods(AMDGPU::VReg_128RegClassID, MVT::i16); + } + + bool isVISrc_128V2B16() const { + return isVISrc_128B16(); + } + + bool isVISrc_128B32() const { + return isRegOrInlineNoMods(AMDGPU::VReg_128RegClassID, MVT::i32); + } + + bool isVISrc_128F32() const { + return isRegOrInlineNoMods(AMDGPU::VReg_128RegClassID, MVT::f32); + } + + bool isVISrc_256V2FP32() const { + return isRegOrInlineNoMods(AMDGPU::VReg_256RegClassID, MVT::f32); + } + + bool isVISrc_256V2INT32() const { + return isRegOrInlineNoMods(AMDGPU::VReg_256RegClassID, MVT::i32); + } + + bool isVISrc_512B32() const { + return isRegOrInlineNoMods(AMDGPU::VReg_512RegClassID, MVT::i32); + } + + bool isVISrc_512B16() const { + return isRegOrInlineNoMods(AMDGPU::VReg_512RegClassID, MVT::i16); + } + + bool isVISrc_512V2B16() const { + return isVISrc_512B16(); + } + + bool isVISrc_512F32() const { + return isRegOrInlineNoMods(AMDGPU::VReg_512RegClassID, MVT::f32); + } + + bool isVISrc_512F16() const { + return isRegOrInlineNoMods(AMDGPU::VReg_512RegClassID, MVT::f16); + } + + bool isVISrc_512V2F16() const { + return isVISrc_512F16() || isVISrc_512B32(); + } + + bool isVISrc_1024B32() const { + return isRegOrInlineNoMods(AMDGPU::VReg_1024RegClassID, MVT::i32); + } + + bool isVISrc_1024B16() const { + return isRegOrInlineNoMods(AMDGPU::VReg_1024RegClassID, MVT::i16); + } + + bool isVISrc_1024V2B16() const { + return isVISrc_1024B16(); + } + + bool isVISrc_1024F32() const { + return isRegOrInlineNoMods(AMDGPU::VReg_1024RegClassID, MVT::f32); + } + + bool isVISrc_1024F16() const { + return isRegOrInlineNoMods(AMDGPU::VReg_1024RegClassID, MVT::f16); + } + + bool isVISrc_1024V2F16() const { + return isVISrc_1024F16() || isVISrc_1024B32(); + } + bool isAISrcB32() const { return isRegOrInlineNoMods(AMDGPU::AGPR_32RegClassID, MVT::i32); } @@ -566,6 +703,14 @@ public: return isAISrcF16() || isAISrcB32(); } + bool isAISrc_64B64() const { + return isRegOrInlineNoMods(AMDGPU::AReg_64RegClassID, MVT::i64); + } + + bool isAISrc_64F64() const { + return isRegOrInlineNoMods(AMDGPU::AReg_64RegClassID, MVT::f64); + } + bool isAISrc_128B32() const { return isRegOrInlineNoMods(AMDGPU::AReg_128RegClassID, MVT::i32); } @@ -590,6 +735,22 @@ public: return isAISrc_128F16() || isAISrc_128B32(); } + bool isVISrc_128F16() const { + return isRegOrInlineNoMods(AMDGPU::VReg_128RegClassID, MVT::f16); + } + + bool isVISrc_128V2F16() const { + return isVISrc_128F16() || isVISrc_128B32(); + } + + bool isAISrc_256B64() const { + return isRegOrInlineNoMods(AMDGPU::AReg_256RegClassID, MVT::i64); + } + + bool isAISrc_256F64() const { + return isRegOrInlineNoMods(AMDGPU::AReg_256RegClassID, MVT::f64); + } + bool isAISrc_512B32() const { return isRegOrInlineNoMods(AMDGPU::AReg_512RegClassID, MVT::i32); } @@ -838,6 +999,7 @@ public: case ImmTyOffset0: OS << "Offset0"; break; case ImmTyOffset1: OS << "Offset1"; break; case ImmTyDLC: OS << "DLC"; break; + case ImmTySCCB: OS << "SCCB"; break; case ImmTyGLC: OS << "GLC"; break; case ImmTySLC: OS << "SLC"; break; case ImmTySWZ: OS << "SWZ"; break; @@ -1197,6 +1359,10 @@ public: return AMDGPU::isGFX9(getSTI()); } + bool isGFX90A() const { + return AMDGPU::isGFX90A(getSTI()); + } + bool isGFX9Plus() const { return AMDGPU::isGFX9Plus(getSTI()); } @@ -1384,6 +1550,8 @@ private: bool validateVccOperand(unsigned Reg) const; bool validateVOP3Literal(const MCInst &Inst, const OperandVector &Operands); bool validateMAIAccWrite(const MCInst &Inst, const OperandVector &Operands); + bool validateAGPRLdSt(const MCInst &Inst) const; + bool validateVGPRAlign(const MCInst &Inst) const; bool validateDivScale(const MCInst &Inst); bool validateCoherencyBits(const MCInst &Inst, const OperandVector &Operands, const SMLoc &IDLoc); @@ -1459,6 +1627,7 @@ public: void cvtMtbuf(MCInst &Inst, const OperandVector &Operands); AMDGPUOperand::Ptr defaultDLC() const; + AMDGPUOperand::Ptr defaultSCCB() const; AMDGPUOperand::Ptr defaultGLC() const; AMDGPUOperand::Ptr defaultGLC_1() const; AMDGPUOperand::Ptr defaultSLC() const; @@ -1553,11 +1722,16 @@ static const fltSemantics *getOpFltSemantics(uint8_t OperandType) { case AMDGPU::OPERAND_REG_INLINE_C_FP32: case AMDGPU::OPERAND_REG_INLINE_AC_INT32: case AMDGPU::OPERAND_REG_INLINE_AC_FP32: + case AMDGPU::OPERAND_REG_INLINE_C_V2FP32: + case AMDGPU::OPERAND_REG_IMM_V2FP32: + case AMDGPU::OPERAND_REG_INLINE_C_V2INT32: + case AMDGPU::OPERAND_REG_IMM_V2INT32: return &APFloat::IEEEsingle(); case AMDGPU::OPERAND_REG_IMM_INT64: case AMDGPU::OPERAND_REG_IMM_FP64: case AMDGPU::OPERAND_REG_INLINE_C_INT64: case AMDGPU::OPERAND_REG_INLINE_C_FP64: + case AMDGPU::OPERAND_REG_INLINE_AC_FP64: return &APFloat::IEEEdouble(); case AMDGPU::OPERAND_REG_IMM_INT16: case AMDGPU::OPERAND_REG_IMM_FP16: @@ -1717,7 +1891,8 @@ bool AMDGPUOperand::isLiteralImm(MVT type) const { // literal goes into the lower half and the upper half is zero. We also // require that the literal may be losslesly converted to f16. MVT ExpectedType = (type == MVT::v2f16)? MVT::f16 : - (type == MVT::v2i16)? MVT::i16 : type; + (type == MVT::v2i16)? MVT::i16 : + (type == MVT::v2f32)? MVT::f32 : type; APFloat FPLiteral(APFloat::IEEEdouble(), APInt(64, Imm.Val)); return canLosslesslyConvertToFPType(FPLiteral, ExpectedType); @@ -1727,6 +1902,13 @@ bool AMDGPUOperand::isRegClass(unsigned RCID) const { return isRegKind() && AsmParser->getMRI()->getRegClass(RCID).contains(getReg()); } +bool AMDGPUOperand::isVRegWithInputMods() const { + return isRegClass(AMDGPU::VGPR_32RegClassID) || + // GFX90A allows DPP on 64-bit operands. + (isRegClass(AMDGPU::VReg_64RegClassID) && + AsmParser->getFeatureBits()[AMDGPU::Feature64BitDPP]); +} + bool AMDGPUOperand::isSDWAOperand(MVT type) const { if (AsmParser->isVI()) return isVReg32(); @@ -1808,6 +1990,7 @@ void AMDGPUOperand::addLiteralImmOperand(MCInst &Inst, int64_t Val, bool ApplyMo case AMDGPU::OPERAND_REG_IMM_FP64: case AMDGPU::OPERAND_REG_INLINE_C_INT64: case AMDGPU::OPERAND_REG_INLINE_C_FP64: + case AMDGPU::OPERAND_REG_INLINE_AC_FP64: if (AMDGPU::isInlinableLiteral64(Literal.getZExtValue(), AsmParser->hasInv2PiInlineImm())) { Inst.addOperand(MCOperand::createImm(Literal.getZExtValue())); @@ -1851,7 +2034,11 @@ void AMDGPUOperand::addLiteralImmOperand(MCInst &Inst, int64_t Val, bool ApplyMo case AMDGPU::OPERAND_REG_INLINE_AC_V2INT16: case AMDGPU::OPERAND_REG_INLINE_AC_V2FP16: case AMDGPU::OPERAND_REG_IMM_V2INT16: - case AMDGPU::OPERAND_REG_IMM_V2FP16: { + case AMDGPU::OPERAND_REG_IMM_V2FP16: + case AMDGPU::OPERAND_REG_INLINE_C_V2FP32: + case AMDGPU::OPERAND_REG_IMM_V2FP32: + case AMDGPU::OPERAND_REG_INLINE_C_V2INT32: + case AMDGPU::OPERAND_REG_IMM_V2INT32: { bool lost; APFloat FPLiteral(APFloat::IEEEdouble(), Literal); // Convert literal to single precision @@ -1883,6 +2070,10 @@ void AMDGPUOperand::addLiteralImmOperand(MCInst &Inst, int64_t Val, bool ApplyMo case AMDGPU::OPERAND_REG_INLINE_AC_FP32: case AMDGPU::OPERAND_REG_IMM_V2INT16: case AMDGPU::OPERAND_REG_IMM_V2FP16: + case AMDGPU::OPERAND_REG_IMM_V2FP32: + case AMDGPU::OPERAND_REG_INLINE_C_V2FP32: + case AMDGPU::OPERAND_REG_IMM_V2INT32: + case AMDGPU::OPERAND_REG_INLINE_C_V2INT32: if (isSafeTruncation(Val, 32) && AMDGPU::isInlinableLiteral32(static_cast<int32_t>(Val), AsmParser->hasInv2PiInlineImm())) { @@ -1899,6 +2090,7 @@ void AMDGPUOperand::addLiteralImmOperand(MCInst &Inst, int64_t Val, bool ApplyMo case AMDGPU::OPERAND_REG_IMM_FP64: case AMDGPU::OPERAND_REG_INLINE_C_INT64: case AMDGPU::OPERAND_REG_INLINE_C_FP64: + case AMDGPU::OPERAND_REG_INLINE_AC_FP64: if (AMDGPU::isInlinableLiteral64(Val, AsmParser->hasInv2PiInlineImm())) { Inst.addOperand(MCOperand::createImm(Val)); setImmKindConst(); @@ -3202,7 +3394,7 @@ bool AMDGPUAsmParser::validateMIMGDataSize(const MCInst &Inst) { return true; unsigned VDataSize = AMDGPU::getRegOperandSize(getMRI(), Desc, VDataIdx); - unsigned TFESize = Inst.getOperand(TFEIdx).getImm()? 1 : 0; + unsigned TFESize = (TFEIdx != -1 && Inst.getOperand(TFEIdx).getImm()) ? 1 : 0; unsigned DMask = Inst.getOperand(DMaskIdx).getImm() & 0xf; if (DMask == 0) DMask = 1; @@ -3804,6 +3996,79 @@ bool AMDGPUAsmParser::validateVOP3Literal(const MCInst &Inst, return true; } +// Returns -1 if not a register, 0 if VGPR and 1 if AGPR. +static int IsAGPROperand(const MCInst &Inst, uint16_t NameIdx, + const MCRegisterInfo *MRI) { + int OpIdx = AMDGPU::getNamedOperandIdx(Inst.getOpcode(), NameIdx); + if (OpIdx < 0) + return -1; + + const MCOperand &Op = Inst.getOperand(OpIdx); + if (!Op.isReg()) + return -1; + + unsigned Sub = MRI->getSubReg(Op.getReg(), AMDGPU::sub0); + auto Reg = Sub ? Sub : Op.getReg(); + const MCRegisterClass &AGRP32 = MRI->getRegClass(AMDGPU::AGPR_32RegClassID); + return AGRP32.contains(Reg) ? 1 : 0; +} + +bool AMDGPUAsmParser::validateAGPRLdSt(const MCInst &Inst) const { + uint64_t TSFlags = MII.get(Inst.getOpcode()).TSFlags; + if ((TSFlags & (SIInstrFlags::FLAT | SIInstrFlags::MUBUF | + SIInstrFlags::MTBUF | SIInstrFlags::MIMG | + SIInstrFlags::DS)) == 0) + return true; + + uint16_t DataNameIdx = (TSFlags & SIInstrFlags::DS) ? AMDGPU::OpName::data0 + : AMDGPU::OpName::vdata; + + const MCRegisterInfo *MRI = getMRI(); + int DstAreg = IsAGPROperand(Inst, AMDGPU::OpName::vdst, MRI); + int DataAreg = IsAGPROperand(Inst, DataNameIdx, MRI); + + if ((TSFlags & SIInstrFlags::DS) && DataAreg >= 0) { + int Data2Areg = IsAGPROperand(Inst, AMDGPU::OpName::data1, MRI); + if (Data2Areg >= 0 && Data2Areg != DataAreg) + return false; + } + + auto FB = getFeatureBits(); + if (FB[AMDGPU::FeatureGFX90AInsts]) { + if (DataAreg < 0 || DstAreg < 0) + return true; + return DstAreg == DataAreg; + } + + return DstAreg < 1 && DataAreg < 1; +} + +bool AMDGPUAsmParser::validateVGPRAlign(const MCInst &Inst) const { + auto FB = getFeatureBits(); + if (!FB[AMDGPU::FeatureGFX90AInsts]) + return true; + + const MCRegisterInfo *MRI = getMRI(); + const MCRegisterClass &VGRP32 = MRI->getRegClass(AMDGPU::VGPR_32RegClassID); + const MCRegisterClass &AGRP32 = MRI->getRegClass(AMDGPU::AGPR_32RegClassID); + for (unsigned I = 0, E = Inst.getNumOperands(); I != E; ++I) { + const MCOperand &Op = Inst.getOperand(I); + if (!Op.isReg()) + continue; + + unsigned Sub = MRI->getSubReg(Op.getReg(), AMDGPU::sub0); + if (!Sub) + continue; + + if (VGRP32.contains(Sub) && ((Sub - AMDGPU::VGPR0) & 1)) + return false; + if (AGRP32.contains(Sub) && ((Sub - AMDGPU::AGPR0) & 1)) + return false; + } + + return true; +} + bool AMDGPUAsmParser::validateCoherencyBits(const MCInst &Inst, const OperandVector &Operands, const SMLoc &IDLoc) { @@ -3895,6 +4160,23 @@ bool AMDGPUAsmParser::validateInstruction(const MCInst &Inst, if (!validateMAIAccWrite(Inst, Operands)) { return false; } + if (!validateCoherencyBits(Inst, Operands, IDLoc)) { + return false; + } + + if (!validateAGPRLdSt(Inst)) { + Error(IDLoc, getFeatureBits()[AMDGPU::FeatureGFX90AInsts] + ? "invalid register class: data and dst should be all VGPR or AGPR" + : "invalid register class: agpr loads and stores not supported on this GPU" + ); + return false; + } + if (!validateVGPRAlign(Inst)) { + Error(IDLoc, + "invalid register class: vgpr tuples must be 64 bit aligned"); + return false; + } + if (!validateDivScale(Inst)) { Error(IDLoc, "ABS not allowed in VOP3B instructions"); return false; @@ -4145,6 +4427,7 @@ bool AMDGPUAsmParser::ParseDirectiveAMDHSAKernel() { SMRange VGPRRange; uint64_t NextFreeVGPR = 0; + uint64_t AccumOffset = 0; SMRange SGPRRange; uint64_t NextFreeSGPR = 0; unsigned UserSGPRCount = 0; @@ -4273,6 +4556,10 @@ bool AMDGPUAsmParser::ParseDirectiveAMDHSAKernel() { } else if (ID == ".amdhsa_next_free_sgpr") { SGPRRange = ValRange; NextFreeSGPR = Val; + } else if (ID == ".amdhsa_accum_offset") { + if (!isGFX90A()) + return Error(IDRange.Start, "directive requires gfx90a+", IDRange); + AccumOffset = Val; } else if (ID == ".amdhsa_reserve_vcc") { if (!isUInt<1>(Val)) return OutOfRangeError(ValRange); @@ -4313,6 +4600,11 @@ bool AMDGPUAsmParser::ParseDirectiveAMDHSAKernel() { return Error(IDRange.Start, "directive requires gfx9+", IDRange); PARSE_BITS_ENTRY(KD.compute_pgm_rsrc1, COMPUTE_PGM_RSRC1_FP16_OVFL, Val, ValRange); + } else if (ID == ".amdhsa_tg_split") { + if (!isGFX90A()) + return Error(IDRange.Start, "directive requires gfx90a+", IDRange); + PARSE_BITS_ENTRY(KD.compute_pgm_rsrc3, COMPUTE_PGM_RSRC3_GFX90A_TG_SPLIT, Val, + ValRange); } else if (ID == ".amdhsa_workgroup_processor_mode") { if (IVersion.Major < 10) return Error(IDRange.Start, "directive requires gfx10+", IDRange); @@ -4397,6 +4689,18 @@ bool AMDGPUAsmParser::ParseDirectiveAMDHSAKernel() { AMDHSA_BITS_SET(KD.compute_pgm_rsrc2, COMPUTE_PGM_RSRC2_USER_SGPR_COUNT, UserSGPRCount); + if (isGFX90A()) { + if (Seen.find(".amdhsa_accum_offset") == Seen.end()) + return TokError(".amdhsa_accum_offset directive is required"); + if (AccumOffset < 4 || AccumOffset > 256 || (AccumOffset & 3)) + return TokError("accum_offset should be in range [4..256] in " + "increments of 4"); + if (AccumOffset > alignTo(std::max((uint64_t)1, NextFreeVGPR), 4)) + return TokError("accum_offset exceeds total VGPR allocation"); + AMDHSA_BITS_SET(KD.compute_pgm_rsrc3, COMPUTE_PGM_RSRC3_GFX90A_ACCUM_OFFSET, + (AccumOffset / 4 - 1)); + } + getTargetStreamer().EmitAmdhsaKernelDescriptor( getSTI(), KernelName, KD, NextFreeVGPR, NextFreeSGPR, ReserveVCC, ReserveFlatScr, ReserveXNACK); @@ -5075,6 +5379,8 @@ AMDGPUAsmParser::parseNamedBit(StringRef Name, OperandVector &Operands, Error(S, "dlc modifier is not supported on this GPU"); return MatchOperand_ParseFail; } + if (!isGFX90A() && ImmTy == AMDGPUOperand::ImmTySCCB) + return MatchOperand_ParseFail; if (isGFX9() && ImmTy == AMDGPUOperand::ImmTyA16) ImmTy = AMDGPUOperand::ImmTyR128A16; @@ -6504,6 +6810,10 @@ AMDGPUOperand::Ptr AMDGPUAsmParser::defaultDLC() const { return AMDGPUOperand::CreateImm(this, 0, SMLoc(), AMDGPUOperand::ImmTyDLC); } +AMDGPUOperand::Ptr AMDGPUAsmParser::defaultSCCB() const { + return AMDGPUOperand::CreateImm(this, 0, SMLoc(), AMDGPUOperand::ImmTySCCB); +} + AMDGPUOperand::Ptr AMDGPUAsmParser::defaultGLC() const { return AMDGPUOperand::CreateImm(this, 0, SMLoc(), AMDGPUOperand::ImmTyGLC); } @@ -6586,8 +6896,9 @@ void AMDGPUAsmParser::cvtMubufImpl(MCInst &Inst, addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyTFE); } - if (isGFX10Plus()) - addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyDLC); + addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyDLC); + addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTySWZ); + addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTySCCB); } void AMDGPUAsmParser::cvtMtbuf(MCInst &Inst, const OperandVector &Operands) { @@ -6625,9 +6936,9 @@ void AMDGPUAsmParser::cvtMtbuf(MCInst &Inst, const OperandVector &Operands) { addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyGLC); addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTySLC); addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyTFE); - - if (isGFX10Plus()) - addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyDLC); + addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyDLC); + addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTySWZ); + addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTySCCB); } //===----------------------------------------------------------------------===// @@ -6669,14 +6980,21 @@ void AMDGPUAsmParser::cvtMIMG(MCInst &Inst, const OperandVector &Operands, if (IsGFX10Plus) addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyDim, -1); addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyUNorm); + + if (AMDGPU::getNamedOperandIdx(Inst.getOpcode(), AMDGPU::OpName::sccb) != -1) + addOptionalImmOperand(Inst, Operands, OptionalIdx, + AMDGPUOperand::ImmTySCCB); + if (IsGFX10Plus) addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyDLC); + addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyGLC); addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTySLC); addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyR128A16); + if (AMDGPU::getNamedOperandIdx(Inst.getOpcode(), AMDGPU::OpName::tfe) != -1) + addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyTFE); if (IsGFX10Plus) addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyA16); - addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyTFE); addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyLWE); if (!IsGFX10Plus) addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyDA); @@ -6784,6 +7102,7 @@ static const OptionalOperand AMDGPUOptionalOperandTable[] = { {"offset", AMDGPUOperand::ImmTyOffset, false, nullptr}, {"inst_offset", AMDGPUOperand::ImmTyInstOffset, false, nullptr}, {"dlc", AMDGPUOperand::ImmTyDLC, true, nullptr}, + {"scc", AMDGPUOperand::ImmTySCCB, true, nullptr}, {"glc", AMDGPUOperand::ImmTyGLC, true, nullptr}, {"slc", AMDGPUOperand::ImmTySLC, true, nullptr}, {"swz", AMDGPUOperand::ImmTySWZ, true, nullptr}, @@ -7021,6 +7340,7 @@ void AMDGPUAsmParser::cvtVOP3(MCInst &Inst, const OperandVector &Operands, Opc == AMDGPU::V_MAC_LEGACY_F32_e64_gfx6_gfx7 || Opc == AMDGPU::V_MAC_LEGACY_F32_e64_gfx10 || Opc == AMDGPU::V_MAC_F16_e64_vi || + Opc == AMDGPU::V_FMAC_F64_e64_gfx90a || Opc == AMDGPU::V_FMAC_F32_e64_gfx10 || Opc == AMDGPU::V_FMAC_F32_e64_vi || Opc == AMDGPU::V_FMAC_LEGACY_F32_e64_gfx10 || @@ -7276,6 +7596,15 @@ OperandMatchResultTy AMDGPUAsmParser::parseDPP8(OperandVector &Operands) { bool AMDGPUAsmParser::isSupportedDPPCtrl(StringRef Ctrl, const OperandVector &Operands) { + if (Ctrl == "row_newbcast") + return isGFX90A(); + + // DPP64 is supported for row_newbcast only. + const MCRegisterInfo *MRI = getMRI(); + if (Operands.size() > 2 && Operands[1]->isReg() && + MRI->getSubReg(Operands[1]->getReg(), AMDGPU::sub1)) + return false; + if (Ctrl == "row_share" || Ctrl == "row_xmask") return isGFX10Plus(); @@ -7353,6 +7682,7 @@ AMDGPUAsmParser::parseDPPCtrlSel(StringRef Ctrl) { .Case("row_ror", {DppCtrl::ROW_ROR0, 1, 15}) .Case("row_share", {DppCtrl::ROW_SHARE_FIRST, 0, 15}) .Case("row_xmask", {DppCtrl::ROW_XMASK_FIRST, 0, 15}) + .Case("row_newbcast", {DppCtrl::ROW_NEWBCAST_FIRST, 0, 15}) .Default({-1, 0, 0}); bool Valid; diff --git a/llvm/lib/Target/AMDGPU/BUFInstructions.td b/llvm/lib/Target/AMDGPU/BUFInstructions.td index 4a67630c0809..d56d9b6d2e59 100644 --- a/llvm/lib/Target/AMDGPU/BUFInstructions.td +++ b/llvm/lib/Target/AMDGPU/BUFInstructions.td @@ -7,13 +7,13 @@ //===----------------------------------------------------------------------===// def MUBUFAddr32 : ComplexPattern<i64, 9, "SelectMUBUFAddr32">; -def MUBUFAddr64 : ComplexPattern<i64, 9, "SelectMUBUFAddr64">; +def MUBUFAddr64 : ComplexPattern<i64, 10, "SelectMUBUFAddr64">; def MUBUFAddr64Atomic : ComplexPattern<i64, 5, "SelectMUBUFAddr64">; def MUBUFScratchOffen : ComplexPattern<i64, 4, "SelectMUBUFScratchOffen", [], [SDNPWantParent]>; def MUBUFScratchOffset : ComplexPattern<i64, 3, "SelectMUBUFScratchOffset", [], [SDNPWantParent], 20>; -def MUBUFOffset : ComplexPattern<i64, 8, "SelectMUBUFOffset">; +def MUBUFOffset : ComplexPattern<i64, 9, "SelectMUBUFOffset">; def MUBUFOffsetNoGLC : ComplexPattern<i64, 3, "SelectMUBUFOffset">; def MUBUFOffsetAtomic : ComplexPattern<i64, 4, "SelectMUBUFOffset">; @@ -105,6 +105,8 @@ class MTBUF_Pseudo <string opName, dag outs, dag ins, bits<1> has_slc = 1; bits<1> has_tfe = 1; bits<4> elements = 0; + bits<1> has_sccb = 1; + bits<1> sccb_value = 0; } class MTBUF_Real <MTBUF_Pseudo ps> : @@ -126,7 +128,7 @@ class MTBUF_Real <MTBUF_Pseudo ps> : bits<1> dlc; bits<7> format; bits<8> vaddr; - bits<8> vdata; + bits<10> vdata; bits<7> srsrc; bits<1> slc; bits<1> tfe; @@ -134,25 +136,31 @@ class MTBUF_Real <MTBUF_Pseudo ps> : bits<4> dfmt = format{3-0}; bits<3> nfmt = format{6-4}; + + bits<1> sccb; + // GFX90A+ only: instruction uses AccVGPR for data + // Bit superceedes tfe. + bits<1> acc = !if(ps.has_vdata, vdata{9}, 0); } class getMTBUFInsDA<list<RegisterClass> vdataList, list<RegisterClass> vaddrList=[]> { RegisterClass vdataClass = !if(!empty(vdataList), ?, !head(vdataList)); RegisterClass vaddrClass = !if(!empty(vaddrList), ?, !head(vaddrList)); + RegisterOperand vdata_op = getLdStRegisterOperand<vdataClass>.ret; dag InsNoData = !if(!empty(vaddrList), (ins SReg_128:$srsrc, SCSrc_b32:$soffset, - offset:$offset, FORMAT:$format, GLC:$glc, SLC:$slc, TFE:$tfe, DLC:$dlc, SWZ:$swz), + offset:$offset, FORMAT:$format, GLC:$glc, SLC:$slc, TFE:$tfe, DLC:$dlc, SWZ:$swz, SCCB_0:$sccb), (ins vaddrClass:$vaddr, SReg_128:$srsrc, SCSrc_b32:$soffset, - offset:$offset, FORMAT:$format, GLC:$glc, SLC:$slc, TFE:$tfe, DLC:$dlc, SWZ:$swz) + offset:$offset, FORMAT:$format, GLC:$glc, SLC:$slc, TFE:$tfe, DLC:$dlc, SWZ:$swz, SCCB_0:$sccb) ); dag InsData = !if(!empty(vaddrList), - (ins vdataClass:$vdata, SReg_128:$srsrc, + (ins vdata_op:$vdata, SReg_128:$srsrc, SCSrc_b32:$soffset, offset:$offset, FORMAT:$format, GLC:$glc, - SLC:$slc, TFE:$tfe, DLC:$dlc, SWZ:$swz), - (ins vdataClass:$vdata, vaddrClass:$vaddr, SReg_128:$srsrc, + SLC:$slc, TFE:$tfe, DLC:$dlc, SWZ:$swz, SCCB_0:$sccb), + (ins vdata_op:$vdata, vaddrClass:$vaddr, SReg_128:$srsrc, SCSrc_b32:$soffset, offset:$offset, FORMAT:$format, GLC:$glc, - SLC:$slc, TFE:$tfe, DLC:$dlc, SWZ:$swz) + SLC:$slc, TFE:$tfe, DLC:$dlc, SWZ:$swz, SCCB_0:$sccb) ); dag ret = !if(!empty(vdataList), InsNoData, InsData); } @@ -202,9 +210,9 @@ class MTBUF_Load_Pseudo <string opName, // Workaround bug bz30254 int addrKindCopy = addrKind> : MTBUF_Pseudo<opName, - (outs vdataClass:$vdata), + (outs getLdStRegisterOperand<vdataClass>.ret:$vdata), getMTBUFIns<addrKindCopy>.ret, - " $vdata, " # getMTBUFAsmOps<addrKindCopy>.ret # "$glc$slc$tfe$dlc$swz", + " $vdata, " # getMTBUFAsmOps<addrKindCopy>.ret # "$glc$slc$tfe$dlc$swz$sccb", pattern>, MTBUF_SetupAddr<addrKindCopy> { let PseudoInstr = opName # "_" # getAddrName<addrKindCopy>.ret; @@ -252,7 +260,7 @@ class MTBUF_Store_Pseudo <string opName, : MTBUF_Pseudo<opName, (outs), getMTBUFIns<addrKindCopy, [vdataClassCopy]>.ret, - " $vdata, " # getMTBUFAsmOps<addrKindCopy>.ret # "$glc$slc$tfe$dlc$swz", + " $vdata, " # getMTBUFAsmOps<addrKindCopy>.ret # "$glc$slc$tfe$dlc$swz$sccb", pattern>, MTBUF_SetupAddr<addrKindCopy> { let PseudoInstr = opName # "_" # getAddrName<addrKindCopy>.ret; @@ -341,6 +349,8 @@ class MUBUF_Pseudo <string opName, dag outs, dag ins, bits<1> has_slc = 1; bits<1> has_tfe = 1; bits<4> elements = 0; + bits<1> has_sccb = 1; + bits<1> sccb_value = 0; } class MUBUF_Real <MUBUF_Pseudo ps> : @@ -362,11 +372,16 @@ class MUBUF_Real <MUBUF_Pseudo ps> : bits<1> glc; bits<1> dlc; bits<8> vaddr; - bits<8> vdata; + bits<10> vdata; bits<7> srsrc; bits<1> slc; bits<1> tfe; bits<8> soffset; + + bits<1> sccb; + // GFX90A+ only: instruction uses AccVGPR for data + // Bit superceedes tfe. + bits<1> acc = !if(ps.has_vdata, vdata{9}, 0); } @@ -395,6 +410,8 @@ class MUBUF_Invalidate <string opName, SDPatternOperator node = null_frag> : let has_offset = 0; let has_slc = 0; let has_tfe = 0; + let has_sccb = 0; + let sccb_value = 0; } class getMUBUFInsDA<list<RegisterClass> vdataList, @@ -402,6 +419,7 @@ class getMUBUFInsDA<list<RegisterClass> vdataList, bit isLds = 0> { RegisterClass vdataClass = !if(!empty(vdataList), ?, !head(vdataList)); RegisterClass vaddrClass = !if(!empty(vaddrList), ?, !head(vaddrList)); + RegisterOperand vdata_op = getLdStRegisterOperand<vdataClass>.ret; dag InsNoData = !if(!empty(vaddrList), (ins SReg_128:$srsrc, SCSrc_b32:$soffset, offset:$offset, GLC:$glc, SLC:$slc), @@ -409,14 +427,14 @@ class getMUBUFInsDA<list<RegisterClass> vdataList, offset:$offset, GLC:$glc, SLC:$slc) ); dag InsData = !if(!empty(vaddrList), - (ins vdataClass:$vdata, SReg_128:$srsrc, + (ins vdata_op:$vdata, SReg_128:$srsrc, SCSrc_b32:$soffset, offset:$offset, GLC:$glc, SLC:$slc), - (ins vdataClass:$vdata, vaddrClass:$vaddr, SReg_128:$srsrc, + (ins vdata_op:$vdata, vaddrClass:$vaddr, SReg_128:$srsrc, SCSrc_b32:$soffset, offset:$offset, GLC:$glc, SLC:$slc) ); dag ret = !con( !if(!empty(vdataList), InsNoData, InsData), - !if(isLds, (ins DLC:$dlc, SWZ:$swz), (ins TFE:$tfe, DLC:$dlc,SWZ:$swz)) + !if(isLds, (ins DLC:$dlc, SWZ:$swz, SCCB_0:$sccb), (ins TFE:$tfe, DLC:$dlc, SWZ:$swz, SCCB_0:$sccb)) ); } @@ -482,13 +500,15 @@ class MUBUF_Load_Pseudo <string opName, bit isLds = 0, list<dag> pattern=[], // Workaround bug bz30254 - int addrKindCopy = addrKind> + int addrKindCopy = addrKind, + RegisterClass vdata_rc = getVregSrcForVT<vdata_vt>.ret, + RegisterOperand vdata_op = getLdStRegisterOperand<vdata_rc>.ret> : MUBUF_Pseudo<opName, - (outs getVregSrcForVT<vdata_vt>.ret:$vdata), + (outs vdata_op:$vdata), !con(getMUBUFIns<addrKindCopy, [], isLds>.ret, - !if(HasTiedDest, (ins getVregSrcForVT<vdata_vt>.ret:$vdata_in), (ins))), + !if(HasTiedDest, (ins vdata_op:$vdata_in), (ins))), " $vdata, " # getMUBUFAsmOps<addrKindCopy>.ret # "$glc$slc" # - !if(isLds, " lds", "$tfe") # "$dlc$swz", + !if(isLds, " lds", "$tfe") # "$dlc$swz$sccb", pattern>, MUBUF_SetupAddr<addrKindCopy> { let PseudoInstr = opName # !if(isLds, "_lds", "") # @@ -567,7 +587,7 @@ class MUBUF_Store_Pseudo <string opName, : MUBUF_Pseudo<opName, (outs), getMUBUFIns<addrKindCopy, [getVregSrcForVT<store_vt>.ret]>.ret, - " $vdata, " # getMUBUFAsmOps<addrKindCopy>.ret # "$glc$slc$tfe$dlc$swz", + " $vdata, " # getMUBUFAsmOps<addrKindCopy>.ret # "$glc$slc$tfe$dlc$swz$sccb", pattern>, MUBUF_SetupAddr<addrKindCopy> { let PseudoInstr = opName # "_" # getAddrName<addrKindCopy>.ret; @@ -608,8 +628,8 @@ multiclass MUBUF_Pseudo_Stores<string opName, class MUBUF_Pseudo_Store_Lds<string opName> : MUBUF_Pseudo<opName, (outs), - (ins SReg_128:$srsrc, SCSrc_b32:$soffset, offset:$offset, GLC:$glc, SLC:$slc, SWZ:$swz), - " $srsrc, $soffset$offset lds$glc$slc$swz"> { + (ins SReg_128:$srsrc, SCSrc_b32:$soffset, offset:$offset, GLC:$glc, SLC:$slc, SWZ:$swz, SCCB_0:$sccb), + " $srsrc, $soffset$offset lds$glc$slc$swz$sccb"> { let mayLoad = 0; let mayStore = 1; let maybeAtomic = 1; @@ -626,17 +646,18 @@ class MUBUF_Pseudo_Store_Lds<string opName> class getMUBUFAtomicInsDA<RegisterClass vdataClass, bit vdata_in, list<RegisterClass> vaddrList=[]> { RegisterClass vaddrClass = !if(!empty(vaddrList), ?, !head(vaddrList)); + RegisterOperand vdata_op = getLdStRegisterOperand<vdataClass>.ret; dag ret = !if(vdata_in, !if(!empty(vaddrList), - (ins vdataClass:$vdata_in, + (ins vdata_op:$vdata_in, SReg_128:$srsrc, SCSrc_b32:$soffset, offset:$offset, GLC_1:$glc1, SLC:$slc), - (ins vdataClass:$vdata_in, vaddrClass:$vaddr, + (ins vdata_op:$vdata_in, vaddrClass:$vaddr, SReg_128:$srsrc, SCSrc_b32:$soffset, offset:$offset, GLC_1:$glc1, SLC:$slc) ), !if(!empty(vaddrList), - (ins vdataClass:$vdata, + (ins vdata_op:$vdata, SReg_128:$srsrc, SCSrc_b32:$soffset, offset:$offset, SLC:$slc), - (ins vdataClass:$vdata, vaddrClass:$vaddr, + (ins vdata_op:$vdata, vaddrClass:$vaddr, SReg_128:$srsrc, SCSrc_b32:$soffset, offset:$offset, SLC:$slc) )); } @@ -678,6 +699,7 @@ class MUBUF_Atomic_Pseudo<string opName, let has_glc = 0; let has_dlc = 0; let has_tfe = 0; + let has_sccb = 0; let maybeAtomic = 1; } @@ -696,6 +718,7 @@ class MUBUF_AtomicNoRet_Pseudo<string opName, int addrKind, let PseudoInstr = opName # "_" # getAddrName<addrKindCopy>.ret; let glc_value = 0; let dlc_value = 0; + let sccb_value = 0; let IsAtomicNoRet = 1; let AsmMatchConverter = "cvtMubufAtomic"; } @@ -705,9 +728,10 @@ class MUBUF_AtomicRet_Pseudo<string opName, int addrKind, list<dag> pattern=[], // Workaround bug bz30254 int addrKindCopy = addrKind, - RegisterClass vdataClassCopy = vdataClass> + RegisterClass vdataClassCopy = vdataClass, + RegisterOperand vdata_op = getLdStRegisterOperand<vdataClass>.ret> : MUBUF_Atomic_Pseudo<opName, addrKindCopy, - (outs vdataClassCopy:$vdata), + (outs vdata_op:$vdata), getMUBUFAtomicIns<addrKindCopy, vdataClassCopy, 1>.ret, " $vdata, " # getMUBUFAsmOps<addrKindCopy>.ret # "$glc1$slc", pattern>, @@ -715,6 +739,7 @@ class MUBUF_AtomicRet_Pseudo<string opName, int addrKind, let PseudoInstr = opName # "_rtn_" # getAddrName<addrKindCopy>.ret; let glc_value = 1; let dlc_value = 0; + let sccb_value = 0; let IsAtomicRet = 1; let Constraints = "$vdata = $vdata_in"; let DisableEncoding = "$vdata_in"; @@ -1108,6 +1133,15 @@ defm BUFFER_ATOMIC_ADD_F32 : MUBUF_Pseudo_Atomics_NO_RTN < defm BUFFER_ATOMIC_PK_ADD_F16 : MUBUF_Pseudo_Atomics_NO_RTN < "buffer_atomic_pk_add_f16", VGPR_32, v2f16, atomic_load_fadd_v2f16_global_noret_32 >; + +let OtherPredicates = [isGFX90APlus] in { +defm BUFFER_ATOMIC_ADD_F32 : MUBUF_Pseudo_Atomics_RTN < + "buffer_atomic_add_f32", VGPR_32, f32, atomic_load_fadd_global_32 +>; +defm BUFFER_ATOMIC_PK_ADD_F16 : MUBUF_Pseudo_Atomics_RTN < + "buffer_atomic_pk_add_f16", VGPR_32, v2f16, atomic_load_fadd_v2f16_global_32 +>; +} } // End SubtargetPredicate = HasAtomicFaddInsts //===----------------------------------------------------------------------===// @@ -1156,6 +1190,17 @@ def BUFFER_WBINVL1_VOL : MUBUF_Invalidate <"buffer_wbinvl1_vol", } // End let SubtargetPredicate = isGFX7Plus +let SubtargetPredicate = isGFX90APlus in { + def BUFFER_WBL2 : MUBUF_Invalidate<"buffer_wbl2"> { + } + def BUFFER_INVL2 : MUBUF_Invalidate<"buffer_invl2"> { + } + + defm BUFFER_ATOMIC_ADD_F64 : MUBUF_Pseudo_Atomics<"buffer_atomic_add_f64", VReg_64, f64, int_amdgcn_global_atomic_fadd>; + defm BUFFER_ATOMIC_MIN_F64 : MUBUF_Pseudo_Atomics<"buffer_atomic_min_f64", VReg_64, f64, int_amdgcn_global_atomic_fmin>; + defm BUFFER_ATOMIC_MAX_F64 : MUBUF_Pseudo_Atomics<"buffer_atomic_max_f64", VReg_64, f64, int_amdgcn_global_atomic_fmax>; +} // End SubtargetPredicate = isGFX90APlus + let SubtargetPredicate = isGFX10Plus in { def BUFFER_GL0_INV : MUBUF_Invalidate<"buffer_gl0_inv">; def BUFFER_GL1_INV : MUBUF_Invalidate<"buffer_gl1_inv">; @@ -1178,7 +1223,7 @@ multiclass MUBUF_LoadIntrinsicPat<SDPatternOperator name, ValueType vt, timm:$auxiliary, 0)), (!cast<MUBUF_Pseudo>(opcode # _OFFSET) SReg_128:$rsrc, SCSrc_b32:$soffset, (as_i16timm $offset), (extract_glc $auxiliary), (extract_slc $auxiliary), 0, (extract_dlc $auxiliary), - (extract_swz $auxiliary)) + (extract_swz $auxiliary), (extract_sccb $auxiliary)) >; def : GCNPat< @@ -1186,7 +1231,7 @@ multiclass MUBUF_LoadIntrinsicPat<SDPatternOperator name, ValueType vt, timm:$auxiliary, 0)), (!cast<MUBUF_Pseudo>(opcode # _OFFEN) VGPR_32:$voffset, SReg_128:$rsrc, SCSrc_b32:$soffset, (as_i16timm $offset), (extract_glc $auxiliary), (extract_slc $auxiliary), 0, (extract_dlc $auxiliary), - (extract_swz $auxiliary)) + (extract_swz $auxiliary), (extract_sccb $auxiliary)) >; def : GCNPat< @@ -1194,7 +1239,7 @@ multiclass MUBUF_LoadIntrinsicPat<SDPatternOperator name, ValueType vt, timm:$auxiliary, timm)), (!cast<MUBUF_Pseudo>(opcode # _IDXEN) VGPR_32:$vindex, SReg_128:$rsrc, SCSrc_b32:$soffset, (as_i16timm $offset), (extract_glc $auxiliary), (extract_slc $auxiliary), 0, (extract_dlc $auxiliary), - (extract_swz $auxiliary)) + (extract_swz $auxiliary), (extract_sccb $auxiliary)) >; def : GCNPat< @@ -1204,7 +1249,7 @@ multiclass MUBUF_LoadIntrinsicPat<SDPatternOperator name, ValueType vt, (REG_SEQUENCE VReg_64, VGPR_32:$vindex, sub0, VGPR_32:$voffset, sub1), SReg_128:$rsrc, SCSrc_b32:$soffset, (as_i16timm $offset), (extract_glc $auxiliary), (extract_slc $auxiliary), 0, (extract_dlc $auxiliary), - (extract_swz $auxiliary)) + (extract_swz $auxiliary), (extract_sccb $auxiliary)) >; } @@ -1264,7 +1309,7 @@ multiclass MUBUF_StoreIntrinsicPat<SDPatternOperator name, ValueType vt, timm:$auxiliary, 0), (!cast<MUBUF_Pseudo>(opcode # _OFFSET_exact) getVregSrcForVT<vt>.ret:$vdata, SReg_128:$rsrc, SCSrc_b32:$soffset, (as_i16timm $offset), (extract_glc $auxiliary), (extract_slc $auxiliary), 0, (extract_dlc $auxiliary), - (extract_swz $auxiliary)) + (extract_swz $auxiliary), (extract_sccb $auxiliary)) >; def : GCNPat< @@ -1273,7 +1318,7 @@ multiclass MUBUF_StoreIntrinsicPat<SDPatternOperator name, ValueType vt, (!cast<MUBUF_Pseudo>(opcode # _OFFEN_exact) getVregSrcForVT<vt>.ret:$vdata, VGPR_32:$voffset, SReg_128:$rsrc, SCSrc_b32:$soffset, (as_i16timm $offset), (extract_glc $auxiliary), (extract_slc $auxiliary), 0, (extract_dlc $auxiliary), - (extract_swz $auxiliary)) + (extract_swz $auxiliary), (extract_sccb $auxiliary)) >; def : GCNPat< @@ -1282,7 +1327,7 @@ multiclass MUBUF_StoreIntrinsicPat<SDPatternOperator name, ValueType vt, (!cast<MUBUF_Pseudo>(opcode # _IDXEN_exact) getVregSrcForVT<vt>.ret:$vdata, VGPR_32:$vindex, SReg_128:$rsrc, SCSrc_b32:$soffset, (as_i16timm $offset), (extract_glc $auxiliary), (extract_slc $auxiliary), 0, (extract_dlc $auxiliary), - (extract_swz $auxiliary)) + (extract_swz $auxiliary), (extract_sccb $auxiliary)) >; def : GCNPat< @@ -1293,7 +1338,7 @@ multiclass MUBUF_StoreIntrinsicPat<SDPatternOperator name, ValueType vt, (REG_SEQUENCE VReg_64, VGPR_32:$vindex, sub0, VGPR_32:$voffset, sub1), SReg_128:$rsrc, SCSrc_b32:$soffset, (as_i16timm $offset), (extract_glc $auxiliary), (extract_slc $auxiliary), 0, (extract_dlc $auxiliary), - (extract_swz $auxiliary)) + (extract_swz $auxiliary), (extract_sccb $auxiliary)) >; } @@ -1462,15 +1507,24 @@ defm : BufferAtomicPatterns_NO_RTN<SIbuffer_atomic_fadd, f32, "BUFFER_ATOMIC_ADD defm : BufferAtomicPatterns_NO_RTN<SIbuffer_atomic_fadd, v2f16, "BUFFER_ATOMIC_PK_ADD_F16">; } +let SubtargetPredicate = isGFX90APlus in { + defm : BufferAtomicPatterns<SIbuffer_atomic_fadd, f32, "BUFFER_ATOMIC_ADD_F32">; + defm : BufferAtomicPatterns<SIbuffer_atomic_fadd, v2f16, "BUFFER_ATOMIC_PK_ADD_F16">; + + defm : BufferAtomicPatterns<SIbuffer_atomic_fadd, f64, "BUFFER_ATOMIC_ADD_F64">; + defm : BufferAtomicPatterns<SIbuffer_atomic_fmin, f64, "BUFFER_ATOMIC_MIN_F64">; + defm : BufferAtomicPatterns<SIbuffer_atomic_fmax, f64, "BUFFER_ATOMIC_MAX_F64">; +} // End SubtargetPredicate = isGFX90APlus + def : GCNPat< (SIbuffer_atomic_cmpswap i32:$data, i32:$cmp, v4i32:$rsrc, 0, 0, i32:$soffset, timm:$offset, timm:$cachepolicy, 0), - (EXTRACT_SUBREG + (EXTRACT_SUBREG (i64 (COPY_TO_REGCLASS (BUFFER_ATOMIC_CMPSWAP_OFFSET_RTN (REG_SEQUENCE VReg_64, VGPR_32:$data, sub0, VGPR_32:$cmp, sub1), SReg_128:$rsrc, SCSrc_b32:$soffset, (as_i16timm $offset), - (extract_slc $cachepolicy)), sub0) + (extract_slc $cachepolicy)), VReg_64)), sub0) >; def : GCNPat< @@ -1478,10 +1532,10 @@ def : GCNPat< i32:$data, i32:$cmp, v4i32:$rsrc, i32:$vindex, 0, i32:$soffset, timm:$offset, timm:$cachepolicy, timm), - (EXTRACT_SUBREG + (EXTRACT_SUBREG (i64 (COPY_TO_REGCLASS (BUFFER_ATOMIC_CMPSWAP_IDXEN_RTN (REG_SEQUENCE VReg_64, VGPR_32:$data, sub0, VGPR_32:$cmp, sub1), - VGPR_32:$vindex, SReg_128:$rsrc, SCSrc_b32:$soffset, (as_i16timm $offset), (extract_slc $cachepolicy)), + VGPR_32:$vindex, SReg_128:$rsrc, SCSrc_b32:$soffset, (as_i16timm $offset), (extract_slc $cachepolicy)), VReg_64)), sub0) >; @@ -1490,10 +1544,10 @@ def : GCNPat< i32:$data, i32:$cmp, v4i32:$rsrc, 0, i32:$voffset, i32:$soffset, timm:$offset, timm:$cachepolicy, 0), - (EXTRACT_SUBREG + (EXTRACT_SUBREG (i64 (COPY_TO_REGCLASS (BUFFER_ATOMIC_CMPSWAP_OFFEN_RTN (REG_SEQUENCE VReg_64, VGPR_32:$data, sub0, VGPR_32:$cmp, sub1), - VGPR_32:$voffset, SReg_128:$rsrc, SCSrc_b32:$soffset, (as_i16timm $offset), (extract_slc $cachepolicy)), + VGPR_32:$voffset, SReg_128:$rsrc, SCSrc_b32:$soffset, (as_i16timm $offset), (extract_slc $cachepolicy)), VReg_64)), sub0) >; @@ -1502,11 +1556,11 @@ def : GCNPat< i32:$data, i32:$cmp, v4i32:$rsrc, i32:$vindex, i32:$voffset, i32:$soffset, timm:$offset, timm:$cachepolicy, timm), - (EXTRACT_SUBREG + (EXTRACT_SUBREG (i64 (COPY_TO_REGCLASS (BUFFER_ATOMIC_CMPSWAP_BOTHEN_RTN (REG_SEQUENCE VReg_64, VGPR_32:$data, sub0, VGPR_32:$cmp, sub1), (REG_SEQUENCE VReg_64, VGPR_32:$vindex, sub0, VGPR_32:$voffset, sub1), - SReg_128:$rsrc, SCSrc_b32:$soffset, (as_i16timm $offset), (extract_slc $cachepolicy)), + SReg_128:$rsrc, SCSrc_b32:$soffset, (as_i16timm $offset), (extract_slc $cachepolicy)), VReg_64)), sub0) >; @@ -1522,12 +1576,12 @@ multiclass MUBUFLoad_Atomic_Pattern <MUBUF_Pseudo Instr_ADDR64, MUBUF_Pseudo Ins def : GCNPat < (vt (atomic_ld (MUBUFAddr64 v4i32:$srsrc, i64:$vaddr, i32:$soffset, i16:$offset, i1:$slc))), - (Instr_ADDR64 $vaddr, $srsrc, $soffset, $offset, 0, $slc, 0, 0, 0) + (Instr_ADDR64 $vaddr, $srsrc, $soffset, $offset, 0, $slc, 0, 0, 0, 0) >; def : GCNPat < (vt (atomic_ld (MUBUFOffsetNoGLC v4i32:$rsrc, i32:$soffset, i16:$offset))), - (Instr_OFFSET $rsrc, $soffset, (as_i16imm $offset), 0, 0, 0, 0, 0) + (Instr_OFFSET $rsrc, $soffset, (as_i16imm $offset), 0, 0, 0, 0, 0, 0) >; } @@ -1572,12 +1626,12 @@ multiclass MUBUFScratchLoadPat <MUBUF_Pseudo InstrOffen, def : GCNPat < (vt (ld (MUBUFScratchOffen v4i32:$srsrc, i32:$vaddr, i32:$soffset, u16imm:$offset))), - (InstrOffen $vaddr, $srsrc, $soffset, $offset, 0, 0, 0, 0, 0) + (InstrOffen $vaddr, $srsrc, $soffset, $offset, 0, 0, 0, 0, 0, 0) >; def : GCNPat < (vt (ld (MUBUFScratchOffset v4i32:$srsrc, i32:$soffset, u16imm:$offset))), - (InstrOffset $srsrc, $soffset, $offset, 0, 0, 0, 0, 0) + (InstrOffset $srsrc, $soffset, $offset, 0, 0, 0, 0, 0, 0) >; } @@ -1639,12 +1693,12 @@ multiclass MUBUFStore_Atomic_Pattern <MUBUF_Pseudo Instr_ADDR64, MUBUF_Pseudo In def : GCNPat < (atomic_st (MUBUFAddr64 v4i32:$srsrc, i64:$vaddr, i32:$soffset, i16:$offset, i1:$slc), vt:$val), - (Instr_ADDR64 $val, $vaddr, $srsrc, $soffset, $offset, 0, $slc, 0, 0, 0) + (Instr_ADDR64 $val, $vaddr, $srsrc, $soffset, $offset, 0, $slc, 0, 0, 0, 0) >; def : GCNPat < (atomic_st (MUBUFOffsetNoGLC v4i32:$rsrc, i32:$soffset, i16:$offset), vt:$val), - (Instr_OFFSET $val, $rsrc, $soffset, (as_i16imm $offset), 0, 0, 0, 0, 0) + (Instr_OFFSET $val, $rsrc, $soffset, (as_i16imm $offset), 0, 0, 0, 0, 0, 0) >; } let SubtargetPredicate = isGFX6GFX7 in { @@ -1673,13 +1727,13 @@ multiclass MUBUFScratchStorePat <MUBUF_Pseudo InstrOffen, def : GCNPat < (st vt:$value, (MUBUFScratchOffen v4i32:$srsrc, i32:$vaddr, i32:$soffset, u16imm:$offset)), - (InstrOffen rc:$value, $vaddr, $srsrc, $soffset, $offset, 0, 0, 0, 0, 0) + (InstrOffen rc:$value, $vaddr, $srsrc, $soffset, $offset, 0, 0, 0, 0, 0, 0) >; def : GCNPat < (st vt:$value, (MUBUFScratchOffset v4i32:$srsrc, i32:$soffset, u16imm:$offset)), - (InstrOffset rc:$value, $srsrc, $soffset, $offset, 0, 0, 0, 0, 0) + (InstrOffset rc:$value, $srsrc, $soffset, $offset, 0, 0, 0, 0, 0, 0) >; } @@ -1726,7 +1780,7 @@ multiclass MTBUF_LoadIntrinsicPat<SDPatternOperator name, ValueType vt, (!cast<MTBUF_Pseudo>(opcode # _OFFSET) SReg_128:$rsrc, SCSrc_b32:$soffset, (as_i16timm $offset), (as_i8timm $format), (extract_glc $auxiliary), (extract_slc $auxiliary), 0, (extract_dlc $auxiliary), - (extract_swz $auxiliary)) + (extract_swz $auxiliary), (extract_sccb $auxiliary)) >; def : GCNPat< @@ -1735,7 +1789,7 @@ multiclass MTBUF_LoadIntrinsicPat<SDPatternOperator name, ValueType vt, (!cast<MTBUF_Pseudo>(opcode # _IDXEN) VGPR_32:$vindex, SReg_128:$rsrc, SCSrc_b32:$soffset, (as_i16timm $offset), (as_i8timm $format), (extract_glc $auxiliary), (extract_slc $auxiliary), 0, (extract_dlc $auxiliary), - (extract_swz $auxiliary)) + (extract_swz $auxiliary), (extract_sccb $auxiliary)) >; def : GCNPat< @@ -1744,7 +1798,7 @@ multiclass MTBUF_LoadIntrinsicPat<SDPatternOperator name, ValueType vt, (!cast<MTBUF_Pseudo>(opcode # _OFFEN) VGPR_32:$voffset, SReg_128:$rsrc, SCSrc_b32:$soffset, (as_i16timm $offset), (as_i8timm $format), (extract_glc $auxiliary), (extract_slc $auxiliary), 0, (extract_dlc $auxiliary), - (extract_swz $auxiliary)) + (extract_swz $auxiliary), (extract_sccb $auxiliary)) >; def : GCNPat< @@ -1755,7 +1809,7 @@ multiclass MTBUF_LoadIntrinsicPat<SDPatternOperator name, ValueType vt, SReg_128:$rsrc, SCSrc_b32:$soffset, (as_i16timm $offset), (as_i8timm $format), (extract_glc $auxiliary), (extract_slc $auxiliary), 0, (extract_dlc $auxiliary), - (extract_swz $auxiliary)) + (extract_swz $auxiliary), (extract_sccb $auxiliary)) >; } @@ -1794,7 +1848,7 @@ multiclass MTBUF_StoreIntrinsicPat<SDPatternOperator name, ValueType vt, (!cast<MTBUF_Pseudo>(opcode # _OFFSET_exact) getVregSrcForVT<vt>.ret:$vdata, SReg_128:$rsrc, SCSrc_b32:$soffset, (as_i16timm $offset), (as_i8timm $format), (extract_glc $auxiliary), (extract_slc $auxiliary), 0, (extract_dlc $auxiliary), - (extract_swz $auxiliary)) + (extract_swz $auxiliary), (extract_sccb $auxiliary)) >; def : GCNPat< @@ -1803,7 +1857,7 @@ multiclass MTBUF_StoreIntrinsicPat<SDPatternOperator name, ValueType vt, (!cast<MTBUF_Pseudo>(opcode # _IDXEN_exact) getVregSrcForVT<vt>.ret:$vdata, VGPR_32:$vindex, SReg_128:$rsrc, SCSrc_b32:$soffset, (as_i16timm $offset), (as_i8timm $format), (extract_glc $auxiliary), (extract_slc $auxiliary), 0, (extract_dlc $auxiliary), - (extract_swz $auxiliary)) + (extract_swz $auxiliary), (extract_sccb $auxiliary)) >; def : GCNPat< @@ -1812,7 +1866,7 @@ multiclass MTBUF_StoreIntrinsicPat<SDPatternOperator name, ValueType vt, (!cast<MTBUF_Pseudo>(opcode # _OFFEN_exact) getVregSrcForVT<vt>.ret:$vdata, VGPR_32:$voffset, SReg_128:$rsrc, SCSrc_b32:$soffset, (as_i16timm $offset), (as_i8timm $format), (extract_glc $auxiliary), (extract_slc $auxiliary), 0, (extract_dlc $auxiliary), - (extract_swz $auxiliary)) + (extract_swz $auxiliary), (extract_sccb $auxiliary)) >; def : GCNPat< @@ -1823,7 +1877,7 @@ multiclass MTBUF_StoreIntrinsicPat<SDPatternOperator name, ValueType vt, (REG_SEQUENCE VReg_64, VGPR_32:$vindex, sub0, VGPR_32:$voffset, sub1), SReg_128:$rsrc, SCSrc_b32:$soffset, (as_i16timm $offset), (as_i8timm $format), (extract_glc $auxiliary), (extract_slc $auxiliary), 0, (extract_dlc $auxiliary), - (extract_swz $auxiliary)) + (extract_swz $auxiliary), (extract_sccb $auxiliary)) >; } @@ -1870,7 +1924,7 @@ class Base_MUBUF_Real_gfx6_gfx7_gfx10<bits<7> op, MUBUF_Pseudo ps, int ef> : let Inst{24-18} = op; let Inst{31-26} = 0x38; let Inst{39-32} = !if(ps.has_vaddr, vaddr, ?); - let Inst{47-40} = !if(ps.has_vdata, vdata, ?); + let Inst{47-40} = !if(ps.has_vdata, vdata{7-0}, ?); let Inst{52-48} = !if(ps.has_srsrc, srsrc{6-2}, ?); let Inst{54} = !if(ps.has_slc, slc, ?); let Inst{55} = !if(ps.has_tfe, tfe, ?); @@ -2124,7 +2178,7 @@ class Base_MTBUF_Real_gfx6_gfx7_gfx10<bits<3> op, MTBUF_Pseudo ps, int ef> : let Inst{18-16} = op; let Inst{31-26} = 0x3a; //encoding let Inst{39-32} = !if(ps.has_vaddr, vaddr, ?); - let Inst{47-40} = !if(ps.has_vdata, vdata, ?); + let Inst{47-40} = !if(ps.has_vdata, vdata{7-0}, ?); let Inst{52-48} = !if(ps.has_srsrc, srsrc{6-2}, ?); let Inst{54} = !if(ps.has_slc, slc, ?); let Inst{55} = !if(ps.has_tfe, tfe, ?); @@ -2206,33 +2260,53 @@ defm TBUFFER_STORE_FORMAT_XYZW : MTBUF_Real_AllAddr_gfx6_gfx7_gfx10<0x007>; // GFX8, GFX9 (VI). //===----------------------------------------------------------------------===// -class MUBUF_Real_vi <bits<7> op, MUBUF_Pseudo ps> : +class MUBUF_Real_Base_vi <bits<7> op, MUBUF_Pseudo ps, int Enc> : MUBUF_Real<ps>, Enc64, - SIMCInstr<ps.PseudoInstr, SIEncodingFamily.VI> { - let AssemblerPredicate = isGFX8GFX9; - let DecoderNamespace = "GFX8"; + SIMCInstr<ps.PseudoInstr, Enc> { let Inst{11-0} = !if(ps.has_offset, offset, ?); let Inst{12} = ps.offen; let Inst{13} = ps.idxen; let Inst{14} = !if(ps.has_glc, glc, ps.glc_value); + let Inst{15} = !if(ps.has_sccb, sccb, ps.sccb_value); let Inst{16} = ps.lds; let Inst{17} = !if(ps.has_slc, slc, ?); let Inst{24-18} = op; let Inst{31-26} = 0x38; //encoding let Inst{39-32} = !if(ps.has_vaddr, vaddr, ?); - let Inst{47-40} = !if(ps.has_vdata, vdata, ?); + let Inst{47-40} = !if(ps.has_vdata, vdata{7-0}, ?); let Inst{52-48} = !if(ps.has_srsrc, srsrc{6-2}, ?); - let Inst{55} = !if(ps.has_tfe, tfe, ?); let Inst{63-56} = !if(ps.has_soffset, soffset, ?); } +class MUBUF_Real_vi <bits<7> op, MUBUF_Pseudo ps> : + MUBUF_Real_Base_vi<op, ps, SIEncodingFamily.VI> { + let AssemblerPredicate = isGFX8GFX9NotGFX90A; + let DecoderNamespace = "GFX8"; + + let Inst{55} = !if(ps.has_tfe, tfe, ?); +} + +class MUBUF_Real_gfx90a <bits<7> op, MUBUF_Pseudo ps> : + MUBUF_Real_Base_vi<op, ps, SIEncodingFamily.GFX90A> { + let AssemblerPredicate = isGFX90APlus; + let DecoderNamespace = "GFX90A"; + let AsmString = ps.Mnemonic # !subst("$tfe", "", ps.AsmOperands); + + let Inst{55} = acc; +} + +multiclass MUBUF_Real_vi_gfx90a<bits<7> op, MUBUF_Pseudo ps> { + def _vi : MUBUF_Real_vi<op, ps>; + def _gfx90a : MUBUF_Real_gfx90a<op, ps>; +} + multiclass MUBUF_Real_AllAddr_vi<bits<7> op> { - def _OFFSET_vi : MUBUF_Real_vi <op, !cast<MUBUF_Pseudo>(NAME#"_OFFSET")>; - def _OFFEN_vi : MUBUF_Real_vi <op, !cast<MUBUF_Pseudo>(NAME#"_OFFEN")>; - def _IDXEN_vi : MUBUF_Real_vi <op, !cast<MUBUF_Pseudo>(NAME#"_IDXEN")>; - def _BOTHEN_vi : MUBUF_Real_vi <op, !cast<MUBUF_Pseudo>(NAME#"_BOTHEN")>; + defm _OFFSET : MUBUF_Real_vi_gfx90a <op, !cast<MUBUF_Pseudo>(NAME#"_OFFSET")>; + defm _OFFEN : MUBUF_Real_vi_gfx90a <op, !cast<MUBUF_Pseudo>(NAME#"_OFFEN")>; + defm _IDXEN : MUBUF_Real_vi_gfx90a <op, !cast<MUBUF_Pseudo>(NAME#"_IDXEN")>; + defm _BOTHEN : MUBUF_Real_vi_gfx90a <op, !cast<MUBUF_Pseudo>(NAME#"_BOTHEN")>; } multiclass MUBUF_Real_AllAddr_Lds_vi<bits<7> op> { @@ -2254,6 +2328,24 @@ multiclass MUBUF_Real_AllAddr_Lds_vi<bits<7> op> { MUBUFLdsTable<1, NAME # "_IDXEN_vi">; def _LDS_BOTHEN_vi : MUBUF_Real_vi <op, !cast<MUBUF_Pseudo>(NAME#"_LDS_BOTHEN")>, MUBUFLdsTable<1, NAME # "_BOTHEN_vi">; + + def _OFFSET_gfx90a : MUBUF_Real_gfx90a <op, !cast<MUBUF_Pseudo>(NAME#"_OFFSET")>, + MUBUFLdsTable<0, NAME # "_OFFSET_gfx90a">; + def _OFFEN_gfx90a : MUBUF_Real_gfx90a <op, !cast<MUBUF_Pseudo>(NAME#"_OFFEN")>, + MUBUFLdsTable<0, NAME # "_OFFEN_gfx90a">; + def _IDXEN_gfx90a : MUBUF_Real_gfx90a <op, !cast<MUBUF_Pseudo>(NAME#"_IDXEN")>, + MUBUFLdsTable<0, NAME # "_IDXEN_gfx90a">; + def _BOTHEN_gfx90a : MUBUF_Real_gfx90a <op, !cast<MUBUF_Pseudo>(NAME#"_BOTHEN")>, + MUBUFLdsTable<0, NAME # "_BOTHEN_gfx90a">; + + def _LDS_OFFSET_gfx90a : MUBUF_Real_gfx90a <op, !cast<MUBUF_Pseudo>(NAME#"_LDS_OFFSET")>, + MUBUFLdsTable<1, NAME # "_OFFSET_gfx90a">; + def _LDS_OFFEN_gfx90a : MUBUF_Real_gfx90a <op, !cast<MUBUF_Pseudo>(NAME#"_LDS_OFFEN")>, + MUBUFLdsTable<1, NAME # "_OFFEN_gfx90a">; + def _LDS_IDXEN_gfx90a : MUBUF_Real_gfx90a <op, !cast<MUBUF_Pseudo>(NAME#"_LDS_IDXEN")>, + MUBUFLdsTable<1, NAME # "_IDXEN_gfx90a">; + def _LDS_BOTHEN_gfx90a : MUBUF_Real_gfx90a <op, !cast<MUBUF_Pseudo>(NAME#"_LDS_BOTHEN")>, + MUBUFLdsTable<1, NAME # "_BOTHEN_gfx90a">; } class MUBUF_Real_gfx80 <bits<7> op, MUBUF_Pseudo ps> : @@ -2272,7 +2364,7 @@ class MUBUF_Real_gfx80 <bits<7> op, MUBUF_Pseudo ps> : let Inst{24-18} = op; let Inst{31-26} = 0x38; //encoding let Inst{39-32} = !if(ps.has_vaddr, vaddr, ?); - let Inst{47-40} = !if(ps.has_vdata, vdata, ?); + let Inst{47-40} = !if(ps.has_vdata, vdata{7-0}, ?); let Inst{52-48} = !if(ps.has_srsrc, srsrc{6-2}, ?); let Inst{55} = !if(ps.has_tfe, tfe, ?); let Inst{63-56} = !if(ps.has_soffset, soffset, ?); @@ -2287,10 +2379,10 @@ multiclass MUBUF_Real_AllAddr_gfx80<bits<7> op> { multiclass MUBUF_Real_Atomic_vi<bits<7> op> : MUBUF_Real_AllAddr_vi<op> { - def _OFFSET_RTN_vi : MUBUF_Real_vi <op, !cast<MUBUF_Pseudo>(NAME#"_OFFSET_RTN")>; - def _OFFEN_RTN_vi : MUBUF_Real_vi <op, !cast<MUBUF_Pseudo>(NAME#"_OFFEN_RTN")>; - def _IDXEN_RTN_vi : MUBUF_Real_vi <op, !cast<MUBUF_Pseudo>(NAME#"_IDXEN_RTN")>; - def _BOTHEN_RTN_vi : MUBUF_Real_vi <op, !cast<MUBUF_Pseudo>(NAME#"_BOTHEN_RTN")>; + defm _OFFSET_RTN : MUBUF_Real_vi_gfx90a <op, !cast<MUBUF_Pseudo>(NAME#"_OFFSET_RTN")>; + defm _OFFEN_RTN : MUBUF_Real_vi_gfx90a <op, !cast<MUBUF_Pseudo>(NAME#"_OFFEN_RTN")>; + defm _IDXEN_RTN : MUBUF_Real_vi_gfx90a <op, !cast<MUBUF_Pseudo>(NAME#"_IDXEN_RTN")>; + defm _BOTHEN_RTN : MUBUF_Real_vi_gfx90a <op, !cast<MUBUF_Pseudo>(NAME#"_BOTHEN_RTN")>; } defm BUFFER_LOAD_FORMAT_X : MUBUF_Real_AllAddr_Lds_vi <0x00>; @@ -2376,24 +2468,34 @@ defm BUFFER_ATOMIC_XOR_X2 : MUBUF_Real_Atomic_vi <0x6a>; defm BUFFER_ATOMIC_INC_X2 : MUBUF_Real_Atomic_vi <0x6b>; defm BUFFER_ATOMIC_DEC_X2 : MUBUF_Real_Atomic_vi <0x6c>; -def BUFFER_STORE_LDS_DWORD_vi : MUBUF_Real_vi <0x3d, BUFFER_STORE_LDS_DWORD>; +defm BUFFER_STORE_LDS_DWORD : MUBUF_Real_vi_gfx90a <0x3d, BUFFER_STORE_LDS_DWORD>; +let AssemblerPredicate = isGFX8GFX9 in { def BUFFER_WBINVL1_vi : MUBUF_Real_vi <0x3e, BUFFER_WBINVL1>; def BUFFER_WBINVL1_VOL_vi : MUBUF_Real_vi <0x3f, BUFFER_WBINVL1_VOL>; +} // End AssemblerPredicate = isGFX8GFX9 let SubtargetPredicate = HasAtomicFaddInsts in { -defm BUFFER_ATOMIC_ADD_F32 : MUBUF_Real_AllAddr_vi <0x4d>; -defm BUFFER_ATOMIC_PK_ADD_F16 : MUBUF_Real_AllAddr_vi <0x4e>; +defm BUFFER_ATOMIC_ADD_F32 : MUBUF_Real_Atomic_vi <0x4d>; +defm BUFFER_ATOMIC_PK_ADD_F16 : MUBUF_Real_Atomic_vi <0x4e>; } // End SubtargetPredicate = HasAtomicFaddInsts -class MTBUF_Real_vi <bits<4> op, MTBUF_Pseudo ps> : +let SubtargetPredicate = isGFX90APlus, AssemblerPredicate = isGFX90APlus in { + defm BUFFER_ATOMIC_ADD_F64 : MUBUF_Real_Atomic_vi<0x4f>; + defm BUFFER_ATOMIC_MIN_F64 : MUBUF_Real_Atomic_vi<0x50>; + defm BUFFER_ATOMIC_MAX_F64 : MUBUF_Real_Atomic_vi<0x51>; +} // End SubtargetPredicate = isGFX90APlus, AssemblerPredicate = isGFX90APlus + +def BUFFER_WBL2_gfx90a : MUBUF_Real_gfx90a<0x28, BUFFER_WBL2> { +} +def BUFFER_INVL2_gfx90a : MUBUF_Real_gfx90a<0x29, BUFFER_INVL2>; + +class MTBUF_Real_Base_vi <bits<4> op, MTBUF_Pseudo ps, int Enc> : MTBUF_Real<ps>, Enc64, - SIMCInstr<ps.PseudoInstr, SIEncodingFamily.VI> { - let AssemblerPredicate = isGFX8GFX9; - let DecoderNamespace = "GFX8"; + SIMCInstr<ps.PseudoInstr, Enc> { let Inst{11-0} = !if(ps.has_offset, offset, ?); let Inst{12} = ps.offen; @@ -2404,18 +2506,40 @@ class MTBUF_Real_vi <bits<4> op, MTBUF_Pseudo ps> : let Inst{25-23} = nfmt; let Inst{31-26} = 0x3a; //encoding let Inst{39-32} = !if(ps.has_vaddr, vaddr, ?); - let Inst{47-40} = !if(ps.has_vdata, vdata, ?); + let Inst{47-40} = !if(ps.has_vdata, vdata{7-0}, ?); let Inst{52-48} = !if(ps.has_srsrc, srsrc{6-2}, ?); + let Inst{53} = !if(ps.has_sccb, sccb, ps.sccb_value); let Inst{54} = !if(ps.has_slc, slc, ?); - let Inst{55} = !if(ps.has_tfe, tfe, ?); let Inst{63-56} = !if(ps.has_soffset, soffset, ?); } +class MTBUF_Real_vi <bits<4> op, MTBUF_Pseudo ps> : + MTBUF_Real_Base_vi <op, ps, SIEncodingFamily.VI> { + let AssemblerPredicate = isGFX8GFX9NotGFX90A; + let DecoderNamespace = "GFX8"; + + let Inst{55} = !if(ps.has_tfe, tfe, ?); +} + +class MTBUF_Real_gfx90a <bits<4> op, MTBUF_Pseudo ps> : + MTBUF_Real_Base_vi <op, ps, SIEncodingFamily.GFX90A> { + let AssemblerPredicate = isGFX90APlus; + let DecoderNamespace = "GFX90A"; + let AsmString = ps.Mnemonic # !subst("$tfe", "", ps.AsmOperands); + + let Inst{55} = acc; +} + +multiclass MTBUF_Real_vi_gfx90a<bits<4> op, MTBUF_Pseudo ps> { + def _vi : MTBUF_Real_vi<op, ps>; + def _gfx90a : MTBUF_Real_gfx90a<op, ps>; +} + multiclass MTBUF_Real_AllAddr_vi<bits<4> op> { - def _OFFSET_vi : MTBUF_Real_vi <op, !cast<MTBUF_Pseudo>(NAME#"_OFFSET")>; - def _OFFEN_vi : MTBUF_Real_vi <op, !cast<MTBUF_Pseudo>(NAME#"_OFFEN")>; - def _IDXEN_vi : MTBUF_Real_vi <op, !cast<MTBUF_Pseudo>(NAME#"_IDXEN")>; - def _BOTHEN_vi : MTBUF_Real_vi <op, !cast<MTBUF_Pseudo>(NAME#"_BOTHEN")>; + defm _OFFSET : MTBUF_Real_vi_gfx90a <op, !cast<MTBUF_Pseudo>(NAME#"_OFFSET")>; + defm _OFFEN : MTBUF_Real_vi_gfx90a <op, !cast<MTBUF_Pseudo>(NAME#"_OFFEN")>; + defm _IDXEN : MTBUF_Real_vi_gfx90a <op, !cast<MTBUF_Pseudo>(NAME#"_IDXEN")>; + defm _BOTHEN : MTBUF_Real_vi_gfx90a <op, !cast<MTBUF_Pseudo>(NAME#"_BOTHEN")>; } class MTBUF_Real_gfx80 <bits<4> op, MTBUF_Pseudo ps> : @@ -2434,7 +2558,7 @@ class MTBUF_Real_gfx80 <bits<4> op, MTBUF_Pseudo ps> : let Inst{25-23} = nfmt; let Inst{31-26} = 0x3a; //encoding let Inst{39-32} = !if(ps.has_vaddr, vaddr, ?); - let Inst{47-40} = !if(ps.has_vdata, vdata, ?); + let Inst{47-40} = !if(ps.has_vdata, vdata{7-0}, ?); let Inst{52-48} = !if(ps.has_srsrc, srsrc{6-2}, ?); let Inst{54} = !if(ps.has_slc, slc, ?); let Inst{55} = !if(ps.has_tfe, tfe, ?); diff --git a/llvm/lib/Target/AMDGPU/DSInstructions.td b/llvm/lib/Target/AMDGPU/DSInstructions.td index 9f71017d81df..c856b2a0bbd2 100644 --- a/llvm/lib/Target/AMDGPU/DSInstructions.td +++ b/llvm/lib/Target/AMDGPU/DSInstructions.td @@ -67,17 +67,20 @@ class DS_Real <DS_Pseudo ds> : let AsmMatchConverter = ds.AsmMatchConverter; // encoding fields - bits<8> vdst; + bits<10> vdst; bits<1> gds; bits<8> addr; - bits<8> data0; - bits<8> data1; + bits<10> data0; + bits<10> data1; bits<8> offset0; bits<8> offset1; bits<16> offset; let offset0 = !if(ds.has_offset, offset{7-0}, ?); let offset1 = !if(ds.has_offset, offset{15-8}, ?); + + bits<1> acc = !if(ds.has_vdst, vdst{9}, + !if(!or(ds.has_data0, ds.has_gws_data0), data0{9}, 0)); } @@ -86,7 +89,7 @@ class DS_Real <DS_Pseudo ds> : class DS_0A1D_NORET<string opName, RegisterClass rc = VGPR_32> : DS_Pseudo<opName, (outs), - (ins rc:$data0, offset:$offset, gds:$gds), + (ins getLdStRegisterOperand<rc>.ret:$data0, offset:$offset, gds:$gds), " $data0$offset$gds"> { let has_addr = 0; @@ -97,7 +100,7 @@ class DS_0A1D_NORET<string opName, RegisterClass rc = VGPR_32> class DS_1A1D_NORET<string opName, RegisterClass rc = VGPR_32> : DS_Pseudo<opName, (outs), - (ins VGPR_32:$addr, rc:$data0, offset:$offset, gds:$gds), + (ins VGPR_32:$addr, getLdStRegisterOperand<rc>.ret:$data0, offset:$offset, gds:$gds), " $addr, $data0$offset$gds"> { let has_data1 = 0; @@ -115,10 +118,18 @@ multiclass DS_1A1D_NORET_mc<string opName, RegisterClass rc = VGPR_32> { } } -class DS_1A2D_NORET<string opName, RegisterClass rc = VGPR_32> +multiclass DS_1A1D_NORET_mc_gfx9<string opName, RegisterClass rc = VGPR_32> { + let has_m0_read = 0 in { + def "" : DS_1A1D_NORET<opName, rc>, + AtomicNoRet<opName, 0>; + } +} + +class DS_1A2D_NORET<string opName, RegisterClass rc = VGPR_32, + RegisterOperand data_op = getLdStRegisterOperand<rc>.ret> : DS_Pseudo<opName, (outs), - (ins VGPR_32:$addr, rc:$data0, rc:$data1, offset:$offset, gds:$gds), + (ins VGPR_32:$addr, data_op:$data0, data_op:$data1, offset:$offset, gds:$gds), " $addr, $data0, $data1$offset$gds"> { let has_vdst = 0; @@ -135,10 +146,11 @@ multiclass DS_1A2D_NORET_mc<string opName, RegisterClass rc = VGPR_32> { } } -class DS_1A2D_Off8_NORET <string opName, RegisterClass rc = VGPR_32> +class DS_1A2D_Off8_NORET <string opName, RegisterClass rc = VGPR_32, + RegisterOperand data_op = getLdStRegisterOperand<rc>.ret> : DS_Pseudo<opName, (outs), - (ins VGPR_32:$addr, rc:$data0, rc:$data1, + (ins VGPR_32:$addr, data_op:$data0, data_op:$data1, offset0:$offset0, offset1:$offset1, gds:$gds), " $addr, $data0, $data1$offset0$offset1$gds"> { @@ -155,10 +167,11 @@ multiclass DS_1A2D_Off8_NORET_mc <string opName, RegisterClass rc = VGPR_32> { } } -class DS_1A1D_RET <string opName, RegisterClass rc = VGPR_32> +class DS_1A1D_RET <string opName, RegisterClass rc = VGPR_32, + RegisterOperand data_op = getLdStRegisterOperand<rc>.ret> : DS_Pseudo<opName, - (outs rc:$vdst), - (ins VGPR_32:$addr, rc:$data0, offset:$offset, gds:$gds), + (outs data_op:$vdst), + (ins VGPR_32:$addr, data_op:$data0, offset:$offset, gds:$gds), " $vdst, $addr, $data0$offset$gds"> { let hasPostISelHook = 1; @@ -178,12 +191,23 @@ multiclass DS_1A1D_RET_mc <string opName, RegisterClass rc = VGPR_32, } } +multiclass DS_1A1D_RET_mc_gfx9 <string opName, RegisterClass rc = VGPR_32, + string NoRetOp = ""> { + let has_m0_read = 0 in { + def "" : DS_1A1D_RET<opName, rc>, + AtomicNoRet<!if(!eq(NoRetOp, ""), "", NoRetOp), + !if(!eq(NoRetOp, ""), 0, 1)>; + } +} + class DS_1A2D_RET<string opName, RegisterClass rc = VGPR_32, - RegisterClass src = rc> + RegisterClass src = rc, + RegisterOperand dst_op = getLdStRegisterOperand<rc>.ret, + RegisterOperand src_op = getLdStRegisterOperand<src>.ret> : DS_Pseudo<opName, - (outs rc:$vdst), - (ins VGPR_32:$addr, src:$data0, src:$data1, offset:$offset, gds:$gds), + (outs dst_op:$vdst), + (ins VGPR_32:$addr, src_op:$data0, src_op:$data1, offset:$offset, gds:$gds), " $vdst, $addr, $data0, $data1$offset$gds"> { let hasPostISelHook = 1; @@ -205,10 +229,12 @@ multiclass DS_1A2D_RET_mc<string opName, class DS_1A2D_Off8_RET<string opName, RegisterClass rc = VGPR_32, - RegisterClass src = rc> + RegisterClass src = rc, + RegisterOperand dst_op = getLdStRegisterOperand<rc>.ret, + RegisterOperand src_op = getLdStRegisterOperand<src>.ret> : DS_Pseudo<opName, - (outs rc:$vdst), - (ins VGPR_32:$addr, src:$data0, src:$data1, offset0:$offset0, offset1:$offset1, gds:$gds), + (outs dst_op:$vdst), + (ins VGPR_32:$addr, src_op:$data0, src_op:$data1, offset0:$offset0, offset1:$offset1, gds:$gds), " $vdst, $addr, $data0, $data1$offset0$offset1$gds"> { let has_offset = 0; @@ -228,11 +254,12 @@ multiclass DS_1A2D_Off8_RET_mc<string opName, } -class DS_1A_RET<string opName, RegisterClass rc = VGPR_32, bit HasTiedOutput = 0, Operand ofs = offset> +class DS_1A_RET<string opName, RegisterClass rc = VGPR_32, bit HasTiedOutput = 0, Operand ofs = offset, + RegisterOperand data_op = getLdStRegisterOperand<rc>.ret> : DS_Pseudo<opName, - (outs rc:$vdst), + (outs data_op:$vdst), !if(HasTiedOutput, - (ins VGPR_32:$addr, ofs:$offset, gds:$gds, rc:$vdst_in), + (ins VGPR_32:$addr, ofs:$offset, gds:$gds, data_op:$vdst_in), (ins VGPR_32:$addr, ofs:$offset, gds:$gds)), " $vdst, $addr$offset$gds"> { let Constraints = !if(HasTiedOutput, "$vdst = $vdst_in", ""); @@ -254,7 +281,7 @@ class DS_1A_RET_Tied<string opName, RegisterClass rc = VGPR_32> : class DS_1A_Off8_RET <string opName, RegisterClass rc = VGPR_32> : DS_Pseudo<opName, - (outs rc:$vdst), + (outs getLdStRegisterOperand<rc>.ret:$vdst), (ins VGPR_32:$addr, offset0:$offset0, offset1:$offset1, gds:$gds), " $vdst, $addr$offset0$offset1$gds"> { @@ -273,7 +300,7 @@ multiclass DS_1A_Off8_RET_mc <string opName, RegisterClass rc = VGPR_32> { } class DS_1A_RET_GDS <string opName> : DS_Pseudo<opName, - (outs VGPR_32:$vdst), + (outs getLdStRegisterOperand<VGPR_32>.ret:$vdst), (ins VGPR_32:$addr, offset:$offset), " $vdst, $addr$offset gds"> { @@ -285,7 +312,7 @@ class DS_1A_RET_GDS <string opName> : DS_Pseudo<opName, } class DS_0A_RET <string opName> : DS_Pseudo<opName, - (outs VGPR_32:$vdst), + (outs getLdStRegisterOperand<VGPR_32>.ret:$vdst), (ins offset:$offset, gds:$gds), " $vdst$offset$gds"> { @@ -340,7 +367,8 @@ class DS_GWS_0D <string opName> class DS_GWS_1D <string opName> : DS_GWS<opName, - (ins VGPR_32:$data0, offset:$offset), " $data0$offset gds"> { + (ins getLdStRegisterOperand<VGPR_32>.ret:$data0, offset:$offset), + " $data0$offset gds"> { let has_gws_data0 = 1; let hasSideEffects = 1; @@ -364,10 +392,11 @@ class DS_VOID <string opName> : DS_Pseudo<opName, let has_gds = 0; } -class DS_1A1D_PERMUTE <string opName, SDPatternOperator node = null_frag> +class DS_1A1D_PERMUTE <string opName, SDPatternOperator node = null_frag, + RegisterOperand data_op = getLdStRegisterOperand<VGPR_32>.ret> : DS_Pseudo<opName, - (outs VGPR_32:$vdst), - (ins VGPR_32:$addr, VGPR_32:$data0, offset:$offset), + (outs data_op:$vdst), + (ins VGPR_32:$addr, data_op:$data0, offset:$offset), " $vdst, $addr, $data0$offset", [(set i32:$vdst, (node (DS1Addr1Offset i32:$addr, i16:$offset), i32:$data0))] > { @@ -424,6 +453,11 @@ def DS_WRITE_ADDTID_B32 : DS_0A1D_NORET<"ds_write_addtid_b32">; } // End mayLoad = 0 +let SubtargetPredicate = isGFX90APlus in { + defm DS_ADD_F64 : DS_1A1D_NORET_mc_gfx9<"ds_add_f64", VReg_64>; + defm DS_ADD_RTN_F64 : DS_1A1D_RET_mc_gfx9<"ds_add_rtn_f64 ", VReg_64, "ds_add_f64">; +} // End SubtargetPredicate = isGFX90APlus + defm DS_MSKOR_B32 : DS_1A2D_NORET_mc<"ds_mskor_b32">; defm DS_CMPST_B32 : DS_1A2D_NORET_mc<"ds_cmpst_b32">; defm DS_CMPST_F32 : DS_1A2D_NORET_mc<"ds_cmpst_f32">; @@ -942,6 +976,10 @@ defm : DSAtomicRetPat_mc<DS_MAX_RTN_U64, i64, "atomic_load_umax">; defm : DSAtomicCmpXChg_mc<DS_CMPST_RTN_B64, i64, "atomic_cmp_swap">; +let SubtargetPredicate = isGFX90APlus in { +def : DSAtomicRetPat<DS_ADD_RTN_F64, f64, atomic_load_fadd_local_64>; +} + def : Pat < (SIds_ordered_count i32:$value, i16:$offset), (DS_ORDERED_COUNT $value, (as_i16imm $offset)) @@ -963,10 +1001,10 @@ class Base_DS_Real_gfx6_gfx7_gfx10<bits<8> op, DS_Pseudo ps, int ef> : let Inst{17} = !if(ps.has_gds, gds, ps.gdsValue); let Inst{25-18} = op; let Inst{31-26} = 0x36; - let Inst{39-32} = !if(ps.has_addr, addr, !if(ps.has_gws_data0, data0, 0)); - let Inst{47-40} = !if(ps.has_data0, data0, 0); - let Inst{55-48} = !if(ps.has_data1, data1, 0); - let Inst{63-56} = !if(ps.has_vdst, vdst, 0); + let Inst{39-32} = !if(ps.has_addr, addr, !if(ps.has_gws_data0, data0{7-0}, 0)); + let Inst{47-40} = !if(ps.has_data0, data0{7-0}, 0); + let Inst{55-48} = !if(ps.has_data1, data1{7-0}, 0); + let Inst{63-56} = !if(ps.has_vdst, vdst{7-0}, 0); } //===----------------------------------------------------------------------===// @@ -1181,11 +1219,12 @@ class DS_Real_vi <bits<8> op, DS_Pseudo ds> : let Inst{15-8} = !if(ds.has_offset1, offset1, 0); let Inst{16} = !if(ds.has_gds, gds, ds.gdsValue); let Inst{24-17} = op; + let Inst{25} = acc; let Inst{31-26} = 0x36; // ds prefix - let Inst{39-32} = !if(ds.has_addr, addr, !if(ds.has_gws_data0, data0, 0)); - let Inst{47-40} = !if(ds.has_data0, data0, 0); - let Inst{55-48} = !if(ds.has_data1, data1, 0); - let Inst{63-56} = !if(ds.has_vdst, vdst, 0); + let Inst{39-32} = !if(ds.has_addr, addr, !if(ds.has_gws_data0, data0{7-0}, 0)); + let Inst{47-40} = !if(ds.has_data0, data0{7-0}, 0); + let Inst{55-48} = !if(ds.has_data1, data1{7-0}, 0); + let Inst{63-56} = !if(ds.has_vdst, vdst{7-0}, 0); } def DS_ADD_U32_vi : DS_Real_vi<0x0, DS_ADD_U32>; @@ -1348,3 +1387,8 @@ def DS_WRITE_B96_vi : DS_Real_vi<0xde, DS_WRITE_B96>; def DS_WRITE_B128_vi : DS_Real_vi<0xdf, DS_WRITE_B128>; def DS_READ_B96_vi : DS_Real_vi<0xfe, DS_READ_B96>; def DS_READ_B128_vi : DS_Real_vi<0xff, DS_READ_B128>; + +let SubtargetPredicate = isGFX90APlus in { + def DS_ADD_F64_vi : DS_Real_vi<0x5c, DS_ADD_F64>; + def DS_ADD_RTN_F64_vi : DS_Real_vi<0x7c, DS_ADD_RTN_F64>; +} // End SubtargetPredicate = isGFX90APlus diff --git a/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp b/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp index 8061c6c509e0..4b535f81ecbf 100644 --- a/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp +++ b/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp @@ -123,6 +123,7 @@ DECODE_OPERAND_REG(VReg_96) DECODE_OPERAND_REG(VReg_128) DECODE_OPERAND_REG(VReg_256) DECODE_OPERAND_REG(VReg_512) +DECODE_OPERAND_REG(VReg_1024) DECODE_OPERAND_REG(SReg_32) DECODE_OPERAND_REG(SReg_32_XM0_XEXEC) @@ -135,7 +136,9 @@ DECODE_OPERAND_REG(SReg_256) DECODE_OPERAND_REG(SReg_512) DECODE_OPERAND_REG(AGPR_32) +DECODE_OPERAND_REG(AReg_64) DECODE_OPERAND_REG(AReg_128) +DECODE_OPERAND_REG(AReg_256) DECODE_OPERAND_REG(AReg_512) DECODE_OPERAND_REG(AReg_1024) DECODE_OPERAND_REG(AV_32) @@ -157,6 +160,14 @@ static DecodeStatus decodeOperand_VSrcV216(MCInst &Inst, return addOperand(Inst, DAsm->decodeOperand_VSrcV216(Imm)); } +static DecodeStatus decodeOperand_VSrcV232(MCInst &Inst, + unsigned Imm, + uint64_t Addr, + const void *Decoder) { + auto DAsm = static_cast<const AMDGPUDisassembler*>(Decoder); + return addOperand(Inst, DAsm->decodeOperand_VSrcV232(Imm)); +} + static DecodeStatus decodeOperand_VS_16(MCInst &Inst, unsigned Imm, uint64_t Addr, @@ -173,6 +184,14 @@ static DecodeStatus decodeOperand_VS_32(MCInst &Inst, return addOperand(Inst, DAsm->decodeOperand_VS_32(Imm)); } +static DecodeStatus decodeOperand_AReg_64(MCInst &Inst, + unsigned Imm, + uint64_t Addr, + const void *Decoder) { + auto DAsm = static_cast<const AMDGPUDisassembler*>(Decoder); + return addOperand(Inst, DAsm->decodeSrcOp(AMDGPUDisassembler::OPW64, Imm | 512)); +} + static DecodeStatus decodeOperand_AReg_128(MCInst &Inst, unsigned Imm, uint64_t Addr, @@ -181,6 +200,14 @@ static DecodeStatus decodeOperand_AReg_128(MCInst &Inst, return addOperand(Inst, DAsm->decodeSrcOp(AMDGPUDisassembler::OPW128, Imm | 512)); } +static DecodeStatus decodeOperand_AReg_256(MCInst &Inst, + unsigned Imm, + uint64_t Addr, + const void *Decoder) { + auto DAsm = static_cast<const AMDGPUDisassembler*>(Decoder); + return addOperand(Inst, DAsm->decodeSrcOp(AMDGPUDisassembler::OPW256, Imm | 512)); +} + static DecodeStatus decodeOperand_AReg_512(MCInst &Inst, unsigned Imm, uint64_t Addr, @@ -197,6 +224,127 @@ static DecodeStatus decodeOperand_AReg_1024(MCInst &Inst, return addOperand(Inst, DAsm->decodeSrcOp(AMDGPUDisassembler::OPW1024, Imm | 512)); } +static DecodeStatus decodeOperand_VReg_64(MCInst &Inst, + unsigned Imm, + uint64_t Addr, + const void *Decoder) { + auto DAsm = static_cast<const AMDGPUDisassembler*>(Decoder); + return addOperand(Inst, DAsm->decodeSrcOp(AMDGPUDisassembler::OPW64, Imm)); +} + +static DecodeStatus decodeOperand_VReg_128(MCInst &Inst, + unsigned Imm, + uint64_t Addr, + const void *Decoder) { + auto DAsm = static_cast<const AMDGPUDisassembler*>(Decoder); + return addOperand(Inst, DAsm->decodeSrcOp(AMDGPUDisassembler::OPW128, Imm)); +} + +static DecodeStatus decodeOperand_VReg_256(MCInst &Inst, + unsigned Imm, + uint64_t Addr, + const void *Decoder) { + auto DAsm = static_cast<const AMDGPUDisassembler*>(Decoder); + return addOperand(Inst, DAsm->decodeSrcOp(AMDGPUDisassembler::OPW256, Imm)); +} + +static DecodeStatus decodeOperand_VReg_512(MCInst &Inst, + unsigned Imm, + uint64_t Addr, + const void *Decoder) { + auto DAsm = static_cast<const AMDGPUDisassembler*>(Decoder); + return addOperand(Inst, DAsm->decodeSrcOp(AMDGPUDisassembler::OPW512, Imm)); +} + +static DecodeStatus decodeOperand_VReg_1024(MCInst &Inst, + unsigned Imm, + uint64_t Addr, + const void *Decoder) { + auto DAsm = static_cast<const AMDGPUDisassembler*>(Decoder); + return addOperand(Inst, DAsm->decodeSrcOp(AMDGPUDisassembler::OPW1024, Imm)); +} + +static bool IsAGPROperand(const MCInst &Inst, int OpIdx, + const MCRegisterInfo *MRI) { + if (OpIdx < 0) + return false; + + const MCOperand &Op = Inst.getOperand(OpIdx); + if (!Op.isReg()) + return false; + + unsigned Sub = MRI->getSubReg(Op.getReg(), AMDGPU::sub0); + auto Reg = Sub ? Sub : Op.getReg(); + return Reg >= AMDGPU::AGPR0 && Reg <= AMDGPU::AGPR255; +} + +static DecodeStatus decodeOperand_AVLdSt_Any(MCInst &Inst, + unsigned Imm, + AMDGPUDisassembler::OpWidthTy Opw, + const void *Decoder) { + auto DAsm = static_cast<const AMDGPUDisassembler*>(Decoder); + if (!DAsm->isGFX90A()) { + Imm &= 511; + } else { + // If atomic has both vdata and vdst their register classes are tied. + // The bit is decoded along with the vdst, first operand. We need to + // change register class to AGPR if vdst was AGPR. + // If a DS instruction has both data0 and data1 their register classes + // are also tied. + unsigned Opc = Inst.getOpcode(); + uint64_t TSFlags = DAsm->getMCII()->get(Opc).TSFlags; + uint16_t DataNameIdx = (TSFlags & SIInstrFlags::DS) ? AMDGPU::OpName::data0 + : AMDGPU::OpName::vdata; + const MCRegisterInfo *MRI = DAsm->getContext().getRegisterInfo(); + int DataIdx = AMDGPU::getNamedOperandIdx(Opc, DataNameIdx); + if ((int)Inst.getNumOperands() == DataIdx) { + int DstIdx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::vdst); + if (IsAGPROperand(Inst, DstIdx, MRI)) + Imm |= 512; + } + + if (TSFlags & SIInstrFlags::DS) { + int Data2Idx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::data1); + if ((int)Inst.getNumOperands() == Data2Idx && + IsAGPROperand(Inst, DataIdx, MRI)) + Imm |= 512; + } + } + return addOperand(Inst, DAsm->decodeSrcOp(Opw, Imm | 256)); +} + +static DecodeStatus DecodeAVLdSt_32RegisterClass(MCInst &Inst, + unsigned Imm, + uint64_t Addr, + const void *Decoder) { + return decodeOperand_AVLdSt_Any(Inst, Imm, + AMDGPUDisassembler::OPW32, Decoder); +} + +static DecodeStatus DecodeAVLdSt_64RegisterClass(MCInst &Inst, + unsigned Imm, + uint64_t Addr, + const void *Decoder) { + return decodeOperand_AVLdSt_Any(Inst, Imm, + AMDGPUDisassembler::OPW64, Decoder); +} + +static DecodeStatus DecodeAVLdSt_96RegisterClass(MCInst &Inst, + unsigned Imm, + uint64_t Addr, + const void *Decoder) { + return decodeOperand_AVLdSt_Any(Inst, Imm, + AMDGPUDisassembler::OPW96, Decoder); +} + +static DecodeStatus DecodeAVLdSt_128RegisterClass(MCInst &Inst, + unsigned Imm, + uint64_t Addr, + const void *Decoder) { + return decodeOperand_AVLdSt_Any(Inst, Imm, + AMDGPUDisassembler::OPW128, Decoder); +} + static DecodeStatus decodeOperand_SReg_32(MCInst &Inst, unsigned Imm, uint64_t Addr, @@ -341,6 +489,12 @@ DecodeStatus AMDGPUDisassembler::getInstruction(MCInst &MI, uint64_t &Size, Res = tryDecodeInst(DecoderTableGFX932, MI, DW, Address); if (Res) break; + if (STI.getFeatureBits()[AMDGPU::FeatureGFX90AInsts]) { + Res = tryDecodeInst(DecoderTableGFX90A32, MI, DW, Address); + if (Res) + break; + } + if (STI.getFeatureBits()[AMDGPU::FeatureGFX10_BEncoding]) { Res = tryDecodeInst(DecoderTableGFX10_B32, MI, DW, Address); if (Res) break; @@ -351,6 +505,13 @@ DecodeStatus AMDGPUDisassembler::getInstruction(MCInst &MI, uint64_t &Size, if (Bytes.size() < 4) break; const uint64_t QW = ((uint64_t)eatBytes<uint32_t>(Bytes) << 32) | DW; + + if (STI.getFeatureBits()[AMDGPU::FeatureGFX90AInsts]) { + Res = tryDecodeInst(DecoderTableGFX90A64, MI, QW, Address); + if (Res) + break; + } + Res = tryDecodeInst(DecoderTableGFX864, MI, QW, Address); if (Res) break; @@ -369,6 +530,7 @@ DecodeStatus AMDGPUDisassembler::getInstruction(MCInst &MI, uint64_t &Size, MI.getOpcode() == AMDGPU::V_MAC_LEGACY_F32_e64_gfx6_gfx7 || MI.getOpcode() == AMDGPU::V_MAC_LEGACY_F32_e64_gfx10 || MI.getOpcode() == AMDGPU::V_MAC_F16_e64_vi || + MI.getOpcode() == AMDGPU::V_FMAC_F64_e64_gfx90a || MI.getOpcode() == AMDGPU::V_FMAC_F32_e64_vi || MI.getOpcode() == AMDGPU::V_FMAC_F32_e64_gfx10 || MI.getOpcode() == AMDGPU::V_FMAC_LEGACY_F32_e64_gfx10 || @@ -384,6 +546,44 @@ DecodeStatus AMDGPUDisassembler::getInstruction(MCInst &MI, uint64_t &Size, insertNamedMCOperand(MI, MCOperand::createImm(1), AMDGPU::OpName::glc1); } + if (Res && (MCII->get(MI.getOpcode()).TSFlags & + (SIInstrFlags::MTBUF | SIInstrFlags::MUBUF)) && + (STI.getFeatureBits()[AMDGPU::FeatureGFX90AInsts])) { + // GFX90A lost TFE, its place is occupied by ACC. + int TFEOpIdx = + AMDGPU::getNamedOperandIdx(MI.getOpcode(), AMDGPU::OpName::tfe); + if (TFEOpIdx != -1) { + auto TFEIter = MI.begin(); + std::advance(TFEIter, TFEOpIdx); + MI.insert(TFEIter, MCOperand::createImm(0)); + } + } + + if (Res && (MCII->get(MI.getOpcode()).TSFlags & + (SIInstrFlags::FLAT | + SIInstrFlags::MTBUF | SIInstrFlags::MUBUF))) { + if (!isGFX10()) { + int DLCOpIdx = + AMDGPU::getNamedOperandIdx(MI.getOpcode(), AMDGPU::OpName::dlc); + if (DLCOpIdx != -1) { + auto DLCIter = MI.begin(); + std::advance(DLCIter, DLCOpIdx); + MI.insert(DLCIter, MCOperand::createImm(0)); + } + } + } + + if (Res && (MCII->get(MI.getOpcode()).TSFlags & + (SIInstrFlags::MTBUF | SIInstrFlags::MUBUF))) { + int SWZOpIdx = + AMDGPU::getNamedOperandIdx(MI.getOpcode(), AMDGPU::OpName::swz); + if (SWZOpIdx != -1) { + auto SWZIter = MI.begin(); + std::advance(SWZIter, SWZOpIdx); + MI.insert(SWZIter, MCOperand::createImm(0)); + } + } + if (Res && (MCII->get(MI.getOpcode()).TSFlags & SIInstrFlags::MIMG)) { int VAddr0Idx = AMDGPU::getNamedOperandIdx(MI.getOpcode(), AMDGPU::OpName::vaddr0); @@ -545,7 +745,7 @@ DecodeStatus AMDGPUDisassembler::convertMIMGInst(MCInst &MI) const { DstSize = (DstSize + 1) / 2; } - if (MI.getOperand(TFEIdx).getImm()) + if (TFEIdx != -1 && MI.getOperand(TFEIdx).getImm()) DstSize += 1; if (DstSize == Info->VDataDwords && AddrSize == Info->VAddrDwords) @@ -701,6 +901,10 @@ MCOperand AMDGPUDisassembler::decodeOperand_VSrcV216(unsigned Val) const { return decodeSrcOp(OPWV216, Val); } +MCOperand AMDGPUDisassembler::decodeOperand_VSrcV232(unsigned Val) const { + return decodeSrcOp(OPWV232, Val); +} + MCOperand AMDGPUDisassembler::decodeOperand_VGPR_32(unsigned Val) const { // Some instructions have operand restrictions beyond what the encoding // allows. Some ordinarily VSrc_32 operands are VGPR_32, so clear the extra @@ -718,10 +922,18 @@ MCOperand AMDGPUDisassembler::decodeOperand_AGPR_32(unsigned Val) const { return createRegOperand(AMDGPU::AGPR_32RegClassID, Val & 255); } +MCOperand AMDGPUDisassembler::decodeOperand_AReg_64(unsigned Val) const { + return createRegOperand(AMDGPU::AReg_64RegClassID, Val & 255); +} + MCOperand AMDGPUDisassembler::decodeOperand_AReg_128(unsigned Val) const { return createRegOperand(AMDGPU::AReg_128RegClassID, Val & 255); } +MCOperand AMDGPUDisassembler::decodeOperand_AReg_256(unsigned Val) const { + return createRegOperand(AMDGPU::AReg_256RegClassID, Val & 255); +} + MCOperand AMDGPUDisassembler::decodeOperand_AReg_512(unsigned Val) const { return createRegOperand(AMDGPU::AReg_512RegClassID, Val & 255); } @@ -758,6 +970,10 @@ MCOperand AMDGPUDisassembler::decodeOperand_VReg_512(unsigned Val) const { return createRegOperand(AMDGPU::VReg_512RegClassID, Val); } +MCOperand AMDGPUDisassembler::decodeOperand_VReg_1024(unsigned Val) const { + return createRegOperand(AMDGPU::VReg_1024RegClassID, Val); +} + MCOperand AMDGPUDisassembler::decodeOperand_SReg_32(unsigned Val) const { // table-gen generated disassembler doesn't care about operand types // leaving only registry class so SSrc_32 operand turns into SReg_32 @@ -914,8 +1130,10 @@ MCOperand AMDGPUDisassembler::decodeFPImmed(OpWidthTy Width, unsigned Imm) { case OPW128: // splat constants case OPW512: case OPW1024: + case OPWV232: return MCOperand::createImm(getInlineImmVal32(Imm)); case OPW64: + case OPW256: return MCOperand::createImm(getInlineImmVal64(Imm)); case OPW16: case OPWV216: @@ -935,8 +1153,14 @@ unsigned AMDGPUDisassembler::getVgprClassId(const OpWidthTy Width) const { case OPW16: case OPWV216: return VGPR_32RegClassID; - case OPW64: return VReg_64RegClassID; + case OPW64: + case OPWV232: return VReg_64RegClassID; + case OPW96: return VReg_96RegClassID; case OPW128: return VReg_128RegClassID; + case OPW160: return VReg_160RegClassID; + case OPW256: return VReg_256RegClassID; + case OPW512: return VReg_512RegClassID; + case OPW1024: return VReg_1024RegClassID; } } @@ -950,8 +1174,11 @@ unsigned AMDGPUDisassembler::getAgprClassId(const OpWidthTy Width) const { case OPW16: case OPWV216: return AGPR_32RegClassID; - case OPW64: return AReg_64RegClassID; + case OPW64: + case OPWV232: return AReg_64RegClassID; + case OPW96: return AReg_96RegClassID; case OPW128: return AReg_128RegClassID; + case OPW160: return AReg_160RegClassID; case OPW256: return AReg_256RegClassID; case OPW512: return AReg_512RegClassID; case OPW1024: return AReg_1024RegClassID; @@ -969,8 +1196,11 @@ unsigned AMDGPUDisassembler::getSgprClassId(const OpWidthTy Width) const { case OPW16: case OPWV216: return SGPR_32RegClassID; - case OPW64: return SGPR_64RegClassID; + case OPW64: + case OPWV232: return SGPR_64RegClassID; + case OPW96: return SGPR_96RegClassID; case OPW128: return SGPR_128RegClassID; + case OPW160: return SGPR_160RegClassID; case OPW256: return SGPR_256RegClassID; case OPW512: return SGPR_512RegClassID; } @@ -986,7 +1216,8 @@ unsigned AMDGPUDisassembler::getTtmpClassId(const OpWidthTy Width) const { case OPW16: case OPWV216: return TTMP_32RegClassID; - case OPW64: return TTMP_64RegClassID; + case OPW64: + case OPWV232: return TTMP_64RegClassID; case OPW128: return TTMP_128RegClassID; case OPW256: return TTMP_256RegClassID; case OPW512: return TTMP_512RegClassID; @@ -1040,6 +1271,7 @@ MCOperand AMDGPUDisassembler::decodeSrcOp(const OpWidthTy Width, unsigned Val) c case OPWV216: return decodeSpecialReg32(Val); case OPW64: + case OPWV232: return decodeSpecialReg64(Val); default: llvm_unreachable("unexpected immediate type"); @@ -1209,6 +1441,10 @@ bool AMDGPUDisassembler::isVI() const { bool AMDGPUDisassembler::isGFX9() const { return AMDGPU::isGFX9(STI); } +bool AMDGPUDisassembler::isGFX90A() const { + return STI.getFeatureBits()[AMDGPU::FeatureGFX90AInsts]; +} + bool AMDGPUDisassembler::isGFX9Plus() const { return AMDGPU::isGFX9Plus(STI); } bool AMDGPUDisassembler::isGFX10() const { return AMDGPU::isGFX10(STI); } diff --git a/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.h b/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.h index 714dabbc5184..7c6d3afbe788 100644 --- a/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.h +++ b/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.h @@ -99,12 +99,14 @@ public: MCOperand decodeOperand_VS_128(unsigned Val) const; MCOperand decodeOperand_VSrc16(unsigned Val) const; MCOperand decodeOperand_VSrcV216(unsigned Val) const; + MCOperand decodeOperand_VSrcV232(unsigned Val) const; MCOperand decodeOperand_VReg_64(unsigned Val) const; MCOperand decodeOperand_VReg_96(unsigned Val) const; MCOperand decodeOperand_VReg_128(unsigned Val) const; MCOperand decodeOperand_VReg_256(unsigned Val) const; MCOperand decodeOperand_VReg_512(unsigned Val) const; + MCOperand decodeOperand_VReg_1024(unsigned Val) const; MCOperand decodeOperand_SReg_32(unsigned Val) const; MCOperand decodeOperand_SReg_32_XM0_XEXEC(unsigned Val) const; @@ -117,7 +119,9 @@ public: MCOperand decodeOperand_SReg_512(unsigned Val) const; MCOperand decodeOperand_AGPR_32(unsigned Val) const; + MCOperand decodeOperand_AReg_64(unsigned Val) const; MCOperand decodeOperand_AReg_128(unsigned Val) const; + MCOperand decodeOperand_AReg_256(unsigned Val) const; MCOperand decodeOperand_AReg_512(unsigned Val) const; MCOperand decodeOperand_AReg_1024(unsigned Val) const; MCOperand decodeOperand_AV_32(unsigned Val) const; @@ -126,12 +130,15 @@ public: enum OpWidthTy { OPW32, OPW64, + OPW96, OPW128, + OPW160, OPW256, OPW512, OPW1024, OPW16, OPWV216, + OPWV232, OPW_LAST_, OPW_FIRST_ = OPW32 }; @@ -159,8 +166,11 @@ public: int getTTmpIdx(unsigned Val) const; + const MCInstrInfo *getMCII() const { return MCII.get(); } + bool isVI() const; bool isGFX9() const; + bool isGFX90A() const; bool isGFX9Plus() const; bool isGFX10() const; bool isGFX10Plus() const; diff --git a/llvm/lib/Target/AMDGPU/FLATInstructions.td b/llvm/lib/Target/AMDGPU/FLATInstructions.td index 7a9c36e72d74..ee43d12865ef 100644 --- a/llvm/lib/Target/AMDGPU/FLATInstructions.td +++ b/llvm/lib/Target/AMDGPU/FLATInstructions.td @@ -54,6 +54,8 @@ class FLAT_Pseudo<string opName, dag outs, dag ins, bits<1> glcValue = 0; bits<1> has_dlc = 1; bits<1> dlcValue = 0; + bits<1> has_sccb = 1; + bits<1> sccbValue = 0; let SubtargetPredicate = !if(is_flat_global, HasFlatGlobalInsts, !if(is_flat_scratch, HasFlatScratchInsts, HasFlatAddressSpace)); @@ -88,14 +90,17 @@ class FLAT_Real <bits<7> op, FLAT_Pseudo ps> : // encoding fields bits<8> vaddr; - bits<8> vdata; + bits<10> vdata; bits<7> saddr; - bits<8> vdst; + bits<10> vdst; bits<1> slc; bits<1> glc; bits<1> dlc; + // Only valid on gfx90a+ + bits<1> sccb; + // Only valid on gfx9 bits<1> lds = 0; // XXX - What does this actually do? @@ -106,7 +111,8 @@ class FLAT_Real <bits<7> op, FLAT_Pseudo ps> : // Signed offset. Highest bit ignored for flat and treated as 12-bit // unsigned for flat accesses. bits<13> offset; - bits<1> nv = 0; // XXX - What does this actually do? + // GFX90A+ only: instruction uses AccVGPR for data + bits<1> acc = !if(ps.has_vdst, vdst{9}, !if(ps.has_data, vdata{9}, 0)); // We don't use tfe right now, and it was removed in gfx9. bits<1> tfe = 0; @@ -121,12 +127,12 @@ class FLAT_Real <bits<7> op, FLAT_Pseudo ps> : let Inst{24-18} = op; let Inst{31-26} = 0x37; // Encoding. let Inst{39-32} = !if(ps.has_vaddr, vaddr, ?); - let Inst{47-40} = !if(ps.has_data, vdata, ?); + let Inst{47-40} = !if(ps.has_data, vdata{7-0}, ?); let Inst{54-48} = !if(ps.has_saddr, !if(ps.enabled_saddr, saddr, 0x7f), 0); // 54-48 is reserved. - let Inst{55} = nv; // nv on GFX9+, TFE before. - let Inst{63-56} = !if(ps.has_vdst, vdst, ?); + let Inst{55} = acc; // nv on GFX9+, TFE before. AccVGPR for data on GFX90A. + let Inst{63-56} = !if(ps.has_vdst, vdst{7-0}, ?); } class GlobalSaddrTable <bit is_saddr, string Name = ""> { @@ -139,9 +145,10 @@ class GlobalSaddrTable <bit is_saddr, string Name = ""> { // saddr is 32-bit (which isn't handled here yet). class FLAT_Load_Pseudo <string opName, RegisterClass regClass, bit HasTiedOutput = 0, - bit HasSaddr = 0, bit EnableSaddr = 0> : FLAT_Pseudo< + bit HasSaddr = 0, bit EnableSaddr = 0, + RegisterOperand vdata_op = getLdStRegisterOperand<regClass>.ret> : FLAT_Pseudo< opName, - (outs regClass:$vdst), + (outs vdata_op:$vdst), !con( !con( !if(EnableSaddr, @@ -149,9 +156,9 @@ class FLAT_Load_Pseudo <string opName, RegisterClass regClass, (ins VReg_64:$vaddr)), (ins flat_offset:$offset)), // FIXME: Operands with default values do not work with following non-optional operands. - !if(HasTiedOutput, (ins GLC:$glc, SLC:$slc, DLC:$dlc, regClass:$vdst_in), - (ins GLC_0:$glc, SLC_0:$slc, DLC_0:$dlc))), - " $vdst, $vaddr"#!if(HasSaddr, !if(EnableSaddr, ", $saddr", ", off"), "")#"$offset$glc$slc$dlc"> { + !if(HasTiedOutput, (ins GLC:$glc, SLC:$slc, DLC:$dlc, SCCB:$sccb, vdata_op:$vdst_in), + (ins GLC_0:$glc, SLC_0:$slc, DLC_0:$dlc, SCCB_0:$sccb))), + " $vdst, $vaddr"#!if(HasSaddr, !if(EnableSaddr, ", $saddr", ", off"), "")#"$offset$glc$slc$dlc$sccb"> { let has_data = 0; let mayLoad = 1; let has_saddr = HasSaddr; @@ -169,10 +176,10 @@ class FLAT_Store_Pseudo <string opName, RegisterClass vdataClass, (outs), !con( !if(EnableSaddr, - (ins VGPR_32:$vaddr, vdataClass:$vdata, SReg_64:$saddr), - (ins VReg_64:$vaddr, vdataClass:$vdata)), - (ins flat_offset:$offset, GLC_0:$glc, SLC_0:$slc, DLC_0:$dlc)), - " $vaddr, $vdata"#!if(HasSaddr, !if(EnableSaddr, ", $saddr", ", off"), "")#"$offset$glc$slc$dlc"> { + (ins VGPR_32:$vaddr, getLdStRegisterOperand<vdataClass>.ret:$vdata, SReg_64:$saddr), + (ins VReg_64:$vaddr, getLdStRegisterOperand<vdataClass>.ret:$vdata)), + (ins flat_offset:$offset, GLC_0:$glc, SLC_0:$slc, DLC_0:$dlc, SCCB_0:$sccb)), + " $vaddr, $vdata"#!if(HasSaddr, !if(EnableSaddr, ", $saddr", ", off"), "")#"$offset$glc$slc$dlc$sccb"> { let mayLoad = 0; let mayStore = 1; let has_vdst = 0; @@ -196,9 +203,9 @@ class FLAT_Global_Load_AddTid_Pseudo <string opName, RegisterClass regClass, opName, (outs regClass:$vdst), !con(!if(EnableSaddr, (ins SReg_64:$saddr), (ins)), - (ins flat_offset:$offset, GLC_0:$glc, SLC_0:$slc, DLC_0:$dlc), + (ins flat_offset:$offset, GLC_0:$glc, SLC_0:$slc, DLC_0:$dlc, SCCB_0:$sccb), !if(HasTiedOutput, (ins regClass:$vdst_in), (ins))), - " $vdst, "#!if(EnableSaddr, "$saddr", "off")#"$offset$glc$slc$dlc"> { + " $vdst, "#!if(EnableSaddr, "$saddr", "off")#"$offset$glc$slc$dlc$sccb"> { let is_flat_global = 1; let has_data = 0; let mayLoad = 1; @@ -234,8 +241,8 @@ class FLAT_Global_Store_AddTid_Pseudo <string opName, RegisterClass vdataClass, opName, (outs), !con(!if(EnableSaddr, (ins vdataClass:$vdata, SReg_64:$saddr), (ins vdataClass:$vdata)), - (ins flat_offset:$offset, GLC:$glc, SLC:$slc, DLC:$dlc)), - " $vdata, "#!if(EnableSaddr, "$saddr", "off")#"$offset$glc$slc$dlc"> { + (ins flat_offset:$offset, GLC:$glc, SLC:$slc, DLC:$dlc, SCCB_0:$sccb)), + " $vdata, "#!if(EnableSaddr, "$saddr", "off")#"$offset$glc$slc$dlc$sccb"> { let is_flat_global = 1; let mayLoad = 0; let mayStore = 1; @@ -266,16 +273,16 @@ class FLAT_Scratch_Load_Pseudo <string opName, RegisterClass regClass, bit EnableVaddr = !not(EnableSaddr)> : FLAT_Pseudo< opName, - (outs regClass:$vdst), + (outs getLdStRegisterOperand<regClass>.ret:$vdst), !con( !if(EnableSaddr, (ins SReg_32_XEXEC_HI:$saddr, flat_offset:$offset), !if(EnableVaddr, (ins VGPR_32:$vaddr, flat_offset:$offset), (ins flat_offset:$offset))), - !if(HasTiedOutput, (ins GLC:$glc, SLC:$slc, DLC:$dlc, regClass:$vdst_in), - (ins GLC_0:$glc, SLC_0:$slc, DLC_0:$dlc))), - " $vdst, "#!if(EnableVaddr, "$vaddr, ", "off, ")#!if(EnableSaddr, "$saddr", "off")#"$offset$glc$slc$dlc"> { + !if(HasTiedOutput, (ins GLC:$glc, SLC:$slc, DLC:$dlc, SCCB:$sccb, getLdStRegisterOperand<regClass>.ret:$vdst_in), + (ins GLC_0:$glc, SLC_0:$slc, DLC_0:$dlc, SCCB_0:$sccb))), + " $vdst, "#!if(EnableVaddr, "$vaddr, ", "off, ")#!if(EnableSaddr, "$saddr", "off")#"$offset$glc$slc$dlc$sccb"> { let has_data = 0; let mayLoad = 1; let has_saddr = 1; @@ -289,15 +296,16 @@ class FLAT_Scratch_Load_Pseudo <string opName, RegisterClass regClass, } class FLAT_Scratch_Store_Pseudo <string opName, RegisterClass vdataClass, bit EnableSaddr = 0, - bit EnableVaddr = !not(EnableSaddr)> : FLAT_Pseudo< + bit EnableVaddr = !not(EnableSaddr), + RegisterOperand vdata_op = getLdStRegisterOperand<vdataClass>.ret> : FLAT_Pseudo< opName, (outs), !if(EnableSaddr, - (ins vdataClass:$vdata, SReg_32_XEXEC_HI:$saddr, flat_offset:$offset, GLC_0:$glc, SLC_0:$slc, DLC_0:$dlc), + (ins vdata_op:$vdata, SReg_32_XEXEC_HI:$saddr, flat_offset:$offset, GLC_0:$glc, SLC_0:$slc, DLC_0:$dlc, SCCB_0:$sccb), !if(EnableVaddr, - (ins vdataClass:$vdata, VGPR_32:$vaddr, flat_offset:$offset, GLC_0:$glc, SLC_0:$slc, DLC_0:$dlc), - (ins vdataClass:$vdata, flat_offset:$offset, GLC_0:$glc, SLC_0:$slc, DLC_0:$dlc))), - " "#!if(EnableVaddr, "$vaddr", "off")#", $vdata, "#!if(EnableSaddr, "$saddr", "off")#"$offset$glc$slc$dlc"> { + (ins vdata_op:$vdata, VGPR_32:$vaddr, flat_offset:$offset, GLC_0:$glc, SLC_0:$slc, DLC_0:$dlc, SCCB_0:$sccb), + (ins vdata_op:$vdata, flat_offset:$offset, GLC_0:$glc, SLC_0:$slc, DLC_0:$dlc, SCCB_0:$sccb))), + " "#!if(EnableVaddr, "$vaddr", "off")#", $vdata, "#!if(EnableSaddr, "$saddr", "off")#"$offset$glc$slc$dlc$sccb"> { let mayLoad = 0; let mayStore = 1; let has_vdst = 0; @@ -344,6 +352,8 @@ class FLAT_AtomicNoRet_Pseudo<string opName, dag outs, dag ins, let has_dlc = 0; let dlcValue = 0; let has_vdst = 0; + let has_sccb = 1; + let sccbValue = 0; let maybeAtomic = 1; let IsAtomicNoRet = 1; } @@ -355,6 +365,7 @@ class FLAT_AtomicRet_Pseudo<string opName, dag outs, dag ins, let has_vdst = 1; let glcValue = 1; let dlcValue = 0; + let sccbValue = 0; let IsAtomicNoRet = 0; let IsAtomicRet = 1; let PseudoInstr = NAME # "_RTN"; @@ -367,11 +378,12 @@ multiclass FLAT_Atomic_Pseudo< SDPatternOperator atomic = null_frag, ValueType data_vt = vt, RegisterClass data_rc = vdst_rc, - bit isFP = isFloatType<data_vt>.ret> { + bit isFP = isFloatType<data_vt>.ret, + RegisterOperand data_op = getLdStRegisterOperand<data_rc>.ret> { def "" : FLAT_AtomicNoRet_Pseudo <opName, (outs), - (ins VReg_64:$vaddr, data_rc:$vdata, flat_offset:$offset, SLC_0:$slc), - " $vaddr, $vdata$offset$slc">, + (ins VReg_64:$vaddr, data_op:$vdata, flat_offset:$offset, SLC_0:$slc, SCCB_0:$sccb), + " $vaddr, $vdata$offset$slc$sccb">, GlobalSaddrTable<0, opName>, AtomicNoRet <opName, 0> { let PseudoInstr = NAME; @@ -380,9 +392,9 @@ multiclass FLAT_Atomic_Pseudo< } def _RTN : FLAT_AtomicRet_Pseudo <opName, - (outs vdst_rc:$vdst), - (ins VReg_64:$vaddr, data_rc:$vdata, flat_offset:$offset, GLC_1:$glc1, SLC_0:$slc), - " $vdst, $vaddr, $vdata$offset$glc1$slc", + (outs getLdStRegisterOperand<vdst_rc>.ret:$vdst), + (ins VReg_64:$vaddr, data_op:$vdata, flat_offset:$offset, GLC_1:$glc1, SLC_0:$slc, SCCB_0:$sccb), + " $vdst, $vaddr, $vdata$offset$glc1$slc$sccb", [(set vt:$vdst, (atomic (FLATOffset i64:$vaddr, i16:$offset), data_vt:$vdata))]>, GlobalSaddrTable<0, opName#"_rtn">, @@ -399,12 +411,13 @@ multiclass FLAT_Global_Atomic_Pseudo_NO_RTN< SDPatternOperator atomic = null_frag, ValueType data_vt = vt, RegisterClass data_rc = vdst_rc, - bit isFP = isFloatType<data_vt>.ret> { + bit isFP = isFloatType<data_vt>.ret, + RegisterOperand data_op = getLdStRegisterOperand<data_rc>.ret> { def "" : FLAT_AtomicNoRet_Pseudo <opName, (outs), - (ins VReg_64:$vaddr, data_rc:$vdata, flat_offset:$offset, SLC_0:$slc), - " $vaddr, $vdata, off$offset$slc">, + (ins VReg_64:$vaddr, data_op:$vdata, flat_offset:$offset, SLC_0:$slc, SCCB_0:$sccb), + " $vaddr, $vdata, off$offset$slc$sccb">, GlobalSaddrTable<0, opName>, AtomicNoRet <opName, 0> { let has_saddr = 1; @@ -414,8 +427,8 @@ multiclass FLAT_Global_Atomic_Pseudo_NO_RTN< def _SADDR : FLAT_AtomicNoRet_Pseudo <opName, (outs), - (ins VGPR_32:$vaddr, data_rc:$vdata, SReg_64:$saddr, flat_offset:$offset, SLC_0:$slc), - " $vaddr, $vdata, $saddr$offset$slc">, + (ins VGPR_32:$vaddr, data_op:$vdata, SReg_64:$saddr, flat_offset:$offset, SLC_0:$slc, SCCB_0:$sccb), + " $vaddr, $vdata, $saddr$offset$slc$sccb">, GlobalSaddrTable<1, opName>, AtomicNoRet <opName#"_saddr", 0> { let has_saddr = 1; @@ -432,12 +445,14 @@ multiclass FLAT_Global_Atomic_Pseudo_RTN< SDPatternOperator atomic = null_frag, ValueType data_vt = vt, RegisterClass data_rc = vdst_rc, - bit isFP = isFloatType<data_vt>.ret> { + bit isFP = isFloatType<data_vt>.ret, + RegisterOperand data_op = getLdStRegisterOperand<data_rc>.ret, + RegisterOperand vdst_op = getLdStRegisterOperand<vdst_rc>.ret> { def _RTN : FLAT_AtomicRet_Pseudo <opName, - (outs vdst_rc:$vdst), - (ins VReg_64:$vaddr, data_rc:$vdata, flat_offset:$offset, GLC_1:$glc1, SLC_0:$slc), - " $vdst, $vaddr, $vdata, off$offset$glc1$slc", + (outs vdst_op:$vdst), + (ins VReg_64:$vaddr, data_op:$vdata, flat_offset:$offset, GLC_1:$glc1, SLC_0:$slc, SCCB_0:$sccb), + " $vdst, $vaddr, $vdata, off$offset$glc1$slc$sccb", [(set vt:$vdst, (atomic (FLATOffsetSigned i64:$vaddr, i16:$offset), data_vt:$vdata))]>, GlobalSaddrTable<0, opName#"_rtn">, @@ -447,9 +462,9 @@ multiclass FLAT_Global_Atomic_Pseudo_RTN< } def _SADDR_RTN : FLAT_AtomicRet_Pseudo <opName, - (outs vdst_rc:$vdst), - (ins VGPR_32:$vaddr, data_rc:$vdata, SReg_64:$saddr, flat_offset:$offset, GLC_1:$glc1, SLC_0:$slc), - " $vdst, $vaddr, $vdata, $saddr$offset$glc1$slc">, + (outs vdst_op:$vdst), + (ins VGPR_32:$vaddr, data_op:$vdata, SReg_64:$saddr, flat_offset:$offset, GLC_1:$glc1, SLC_0:$slc, SCCB_0:$sccb), + " $vdst, $vaddr, $vdata, $saddr$offset$glc1$slc$sccb">, GlobalSaddrTable<1, opName#"_rtn">, AtomicNoRet <opName#"_saddr", 1> { let has_saddr = 1; @@ -608,6 +623,15 @@ defm FLAT_ATOMIC_FMAX_X2 : FLAT_Atomic_Pseudo <"flat_atomic_fmax_x2", } // End SubtargetPredicate = isGFX7GFX10 +let SubtargetPredicate = isGFX90APlus in { + defm FLAT_ATOMIC_ADD_F64 : FLAT_Atomic_Pseudo<"flat_atomic_add_f64", VReg_64, f64, int_amdgcn_flat_atomic_fadd>; + defm FLAT_ATOMIC_MIN_F64 : FLAT_Atomic_Pseudo<"flat_atomic_min_f64", VReg_64, f64, int_amdgcn_flat_atomic_fmin>; + defm FLAT_ATOMIC_MAX_F64 : FLAT_Atomic_Pseudo<"flat_atomic_max_f64", VReg_64, f64, int_amdgcn_flat_atomic_fmax>; + defm GLOBAL_ATOMIC_ADD_F64 : FLAT_Global_Atomic_Pseudo<"global_atomic_add_f64", VReg_64, f64, int_amdgcn_global_atomic_fadd>; + defm GLOBAL_ATOMIC_MIN_F64 : FLAT_Global_Atomic_Pseudo<"global_atomic_min_f64", VReg_64, f64, int_amdgcn_global_atomic_fmin>; + defm GLOBAL_ATOMIC_MAX_F64 : FLAT_Global_Atomic_Pseudo<"global_atomic_max_f64", VReg_64, f64, int_amdgcn_global_atomic_fmax>; +} // End SubtargetPredicate = isGFX90APlus + defm GLOBAL_LOAD_UBYTE : FLAT_Global_Load_Pseudo <"global_load_ubyte", VGPR_32>; defm GLOBAL_LOAD_SBYTE : FLAT_Global_Load_Pseudo <"global_load_sbyte", VGPR_32>; defm GLOBAL_LOAD_USHORT : FLAT_Global_Load_Pseudo <"global_load_ushort", VGPR_32>; @@ -780,6 +804,15 @@ let OtherPredicates = [HasAtomicFaddInsts] in { "global_atomic_pk_add_f16", VGPR_32, v2f16 >; } // End OtherPredicates = [HasAtomicFaddInsts] + +let OtherPredicates = [isGFX90APlus] in { + defm GLOBAL_ATOMIC_ADD_F32 : FLAT_Global_Atomic_Pseudo_RTN < + "global_atomic_add_f32", VGPR_32, f32, int_amdgcn_global_atomic_fadd + >; + defm GLOBAL_ATOMIC_PK_ADD_F16 : FLAT_Global_Atomic_Pseudo_RTN < + "global_atomic_pk_add_f16", VGPR_32, v2f16, int_amdgcn_global_atomic_fadd + >; +} // End OtherPredicates = [isGFX90APlus] } // End is_flat_global = 1 //===----------------------------------------------------------------------===// @@ -794,17 +827,17 @@ class FlatLoadPat <FLAT_Pseudo inst, SDPatternOperator node, ValueType vt> : GCN class FlatLoadPat_D16 <FLAT_Pseudo inst, SDPatternOperator node, ValueType vt> : GCNPat < (node (FLATOffset (i64 VReg_64:$vaddr), i16:$offset), vt:$in), - (inst $vaddr, $offset, 0, 0, 0, $in) + (inst $vaddr, $offset, 0, 0, 0, 0, $in) >; class FlatSignedLoadPat_D16 <FLAT_Pseudo inst, SDPatternOperator node, ValueType vt> : GCNPat < (node (FLATOffsetSigned (i64 VReg_64:$vaddr), i16:$offset), vt:$in), - (inst $vaddr, $offset, 0, 0, 0, $in) + (inst $vaddr, $offset, 0, 0, 0, 0, $in) >; class GlobalLoadSaddrPat_D16 <FLAT_Pseudo inst, SDPatternOperator node, ValueType vt> : GCNPat < (vt (node (GlobalSAddr (i64 SReg_64:$saddr), (i32 VGPR_32:$voffset), i16:$offset), vt:$in)), - (inst $saddr, $voffset, $offset, 0, 0, 0, $in) + (inst $saddr, $voffset, $offset, 0, 0, 0, 0, $in) >; class FlatLoadSignedPat <FLAT_Pseudo inst, SDPatternOperator node, ValueType vt> : GCNPat < @@ -895,7 +928,7 @@ class ScratchLoadSignedPat <FLAT_Pseudo inst, SDPatternOperator node, ValueType class ScratchLoadSignedPat_D16 <FLAT_Pseudo inst, SDPatternOperator node, ValueType vt> : GCNPat < (node (ScratchOffset (i32 VGPR_32:$vaddr), i16:$offset), vt:$in), - (inst $vaddr, $offset, 0, 0, 0, $in) + (inst $vaddr, $offset, 0, 0, 0, 0, $in) >; class ScratchStoreSignedPat <FLAT_Pseudo inst, SDPatternOperator node, ValueType vt> : GCNPat < @@ -910,7 +943,7 @@ class ScratchLoadSaddrPat <FLAT_Pseudo inst, SDPatternOperator node, ValueType v class ScratchLoadSaddrPat_D16 <FLAT_Pseudo inst, SDPatternOperator node, ValueType vt> : GCNPat < (vt (node (ScratchSAddr (i32 SGPR_32:$saddr), i16:$offset), vt:$in)), - (inst $saddr, $offset, 0, 0, 0, $in) + (inst $saddr, $offset, 0, 0, 0, 0, $in) >; class ScratchStoreSaddrPat <FLAT_Pseudo inst, SDPatternOperator node, @@ -1205,6 +1238,17 @@ defm : GlobalFLATNoRtnAtomicPats <GLOBAL_ATOMIC_ADD_F32, atomic_load_fadd_glo defm : GlobalFLATNoRtnAtomicPats <GLOBAL_ATOMIC_PK_ADD_F16, atomic_load_fadd_v2f16_global_noret_32, v2f16>; } +let OtherPredicates = [isGFX90APlus] in { +defm : GlobalFLATAtomicPats <"GLOBAL_ATOMIC_ADD_F32", atomic_load_fadd_global_32, f32>; +defm : GlobalFLATAtomicPats <"GLOBAL_ATOMIC_PK_ADD_F16", atomic_load_fadd_v2f16_global_32, v2f16>; +defm : GlobalFLATAtomicPats <"GLOBAL_ATOMIC_ADD_F64", atomic_load_fadd_global_64, f64>; +defm : GlobalFLATAtomicPats <"GLOBAL_ATOMIC_MIN_F64", atomic_load_fmin_global_64, f64>; +defm : GlobalFLATAtomicPats <"GLOBAL_ATOMIC_MAX_F64", atomic_load_fmax_global_64, f64>; +def : FlatSignedAtomicPat <FLAT_ATOMIC_ADD_F64_RTN, atomic_load_fadd_flat_64, f64>; +def : FlatSignedAtomicPat <FLAT_ATOMIC_MIN_F64_RTN, atomic_load_fmin_flat_64, f64>; +def : FlatSignedAtomicPat <FLAT_ATOMIC_MAX_F64_RTN, atomic_load_fmax_flat_64, f64>; +} + } // End OtherPredicates = [HasFlatGlobalInsts], AddedComplexity = 10 let OtherPredicates = [HasFlatScratchInsts, EnableFlatScratch] in { @@ -1345,6 +1389,8 @@ class FLAT_Real_vi <bits<7> op, FLAT_Pseudo ps> : SIMCInstr <ps.PseudoInstr, SIEncodingFamily.VI> { let AssemblerPredicate = isGFX8GFX9; let DecoderNamespace = "GFX8"; + + let Inst{25} = !if(ps.has_sccb, sccb, ps.sccbValue); } multiclass FLAT_Real_AllAddr_vi<bits<7> op> { @@ -1492,6 +1538,14 @@ defm SCRATCH_STORE_DWORDX2 : FLAT_Real_AllAddr_vi <0x1d>; defm SCRATCH_STORE_DWORDX3 : FLAT_Real_AllAddr_vi <0x1e>; defm SCRATCH_STORE_DWORDX4 : FLAT_Real_AllAddr_vi <0x1f>; +let SubtargetPredicate = isGFX90APlus in { + defm FLAT_ATOMIC_ADD_F64 : FLAT_Real_Atomics_vi<0x4f, FLAT_ATOMIC_ADD_F64>; + defm FLAT_ATOMIC_MIN_F64 : FLAT_Real_Atomics_vi<0x50, FLAT_ATOMIC_MIN_F64>; + defm FLAT_ATOMIC_MAX_F64 : FLAT_Real_Atomics_vi<0x51, FLAT_ATOMIC_MAX_F64>; + defm GLOBAL_ATOMIC_ADD_F64 : FLAT_Global_Real_Atomics_vi<0x4f>; + defm GLOBAL_ATOMIC_MIN_F64 : FLAT_Global_Real_Atomics_vi<0x50>; + defm GLOBAL_ATOMIC_MAX_F64 : FLAT_Global_Real_Atomics_vi<0x51>; +} // End SubtargetPredicate = isGFX90APlus //===----------------------------------------------------------------------===// // GFX10. @@ -1701,7 +1755,7 @@ defm SCRATCH_LOAD_SHORT_D16_HI : FLAT_Real_ScratchAllAddr_gfx10<0x025>; let SubtargetPredicate = HasAtomicFaddInsts in { -defm GLOBAL_ATOMIC_ADD_F32 : FLAT_Real_AllAddr_vi <0x04d>; -defm GLOBAL_ATOMIC_PK_ADD_F16 : FLAT_Real_AllAddr_vi <0x04e>; +defm GLOBAL_ATOMIC_ADD_F32 : FLAT_Global_Real_Atomics_vi <0x04d>; +defm GLOBAL_ATOMIC_PK_ADD_F16 : FLAT_Global_Real_Atomics_vi <0x04e>; } // End SubtargetPredicate = HasAtomicFaddInsts diff --git a/llvm/lib/Target/AMDGPU/GCNDPPCombine.cpp b/llvm/lib/Target/AMDGPU/GCNDPPCombine.cpp index e4eacd101ce8..eb2610492480 100644 --- a/llvm/lib/Target/AMDGPU/GCNDPPCombine.cpp +++ b/llvm/lib/Target/AMDGPU/GCNDPPCombine.cpp @@ -137,7 +137,8 @@ MachineOperand *GCNDPPCombine::getOldOpndValue(MachineOperand &OldOpnd) const { case AMDGPU::IMPLICIT_DEF: return nullptr; case AMDGPU::COPY: - case AMDGPU::V_MOV_B32_e32: { + case AMDGPU::V_MOV_B32_e32: + case AMDGPU::V_MOV_B64_PSEUDO: { auto &Op1 = Def->getOperand(1); if (Op1.isImm()) return &Op1; @@ -151,7 +152,8 @@ MachineInstr *GCNDPPCombine::createDPPInst(MachineInstr &OrigMI, MachineInstr &MovMI, RegSubRegPair CombOldVGPR, bool CombBCZ) const { - assert(MovMI.getOpcode() == AMDGPU::V_MOV_B32_dpp); + assert(MovMI.getOpcode() == AMDGPU::V_MOV_B32_dpp || + MovMI.getOpcode() == AMDGPU::V_MOV_B64_DPP_PSEUDO); auto OrigOp = OrigMI.getOpcode(); auto DPPOp = getDPPOp(OrigOp); @@ -174,7 +176,11 @@ MachineInstr *GCNDPPCombine::createDPPInst(MachineInstr &OrigMI, const int OldIdx = AMDGPU::getNamedOperandIdx(DPPOp, AMDGPU::OpName::old); if (OldIdx != -1) { assert(OldIdx == NumOperands); - assert(isOfRegClass(CombOldVGPR, AMDGPU::VGPR_32RegClass, *MRI)); + assert(isOfRegClass( + CombOldVGPR, + *MRI->getRegClass( + TII->getNamedOperand(MovMI, AMDGPU::OpName::vdst)->getReg()), + *MRI)); auto *Def = getVRegSubRegDef(CombOldVGPR, *MRI); DPPInst.addReg(CombOldVGPR.Reg, Def ? 0 : RegState::Undef, CombOldVGPR.SubReg); @@ -325,8 +331,10 @@ MachineInstr *GCNDPPCombine::createDPPInst(MachineInstr &OrigMI, return nullptr; } CombOldVGPR = getRegSubRegPair(*Src1); - if (!isOfRegClass(CombOldVGPR, AMDGPU::VGPR_32RegClass, *MRI)) { - LLVM_DEBUG(dbgs() << " failed: src1 isn't a VGPR32 register\n"); + auto MovDst = TII->getNamedOperand(MovMI, AMDGPU::OpName::vdst); + const TargetRegisterClass *RC = MRI->getRegClass(MovDst->getReg()); + if (!isOfRegClass(CombOldVGPR, *RC, *MRI)) { + LLVM_DEBUG(dbgs() << " failed: src1 has wrong register class\n"); return nullptr; } } @@ -346,7 +354,8 @@ bool GCNDPPCombine::hasNoImmOrEqual(MachineInstr &MI, unsigned OpndName, } bool GCNDPPCombine::combineDPPMov(MachineInstr &MovMI) const { - assert(MovMI.getOpcode() == AMDGPU::V_MOV_B32_dpp); + assert(MovMI.getOpcode() == AMDGPU::V_MOV_B32_dpp || + MovMI.getOpcode() == AMDGPU::V_MOV_B64_DPP_PSEUDO); LLVM_DEBUG(dbgs() << "\nDPP combine: " << MovMI); auto *DstOpnd = TII->getNamedOperand(MovMI, AMDGPU::OpName::vdst); @@ -362,6 +371,17 @@ bool GCNDPPCombine::combineDPPMov(MachineInstr &MovMI) const { return false; } + if (MovMI.getOpcode() == AMDGPU::V_MOV_B64_DPP_PSEUDO) { + auto *DppCtrl = TII->getNamedOperand(MovMI, AMDGPU::OpName::dpp_ctrl); + assert(DppCtrl && DppCtrl->isImm()); + if (!AMDGPU::isLegal64BitDPPControl(DppCtrl->getImm())) { + LLVM_DEBUG(dbgs() << " failed: 64 bit dpp move uses unsupported" + " control value\n"); + // Let it split, then control may become legal. + return false; + } + } + auto *RowMaskOpnd = TII->getNamedOperand(MovMI, AMDGPU::OpName::row_mask); assert(RowMaskOpnd && RowMaskOpnd->isImm()); auto *BankMaskOpnd = TII->getNamedOperand(MovMI, AMDGPU::OpName::bank_mask); @@ -430,8 +450,9 @@ bool GCNDPPCombine::combineDPPMov(MachineInstr &MovMI) const { auto CombOldVGPR = getRegSubRegPair(*OldOpnd); // try to reuse previous old reg if its undefined (IMPLICIT_DEF) if (CombBCZ && OldOpndValue) { // CombOldVGPR should be undef + const TargetRegisterClass *RC = MRI->getRegClass(DPPMovReg); CombOldVGPR = RegSubRegPair( - MRI->createVirtualRegister(&AMDGPU::VGPR_32RegClass)); + MRI->createVirtualRegister(RC)); auto UndefInst = BuildMI(*MovMI.getParent(), MovMI, MovMI.getDebugLoc(), TII->get(AMDGPU::IMPLICIT_DEF), CombOldVGPR.Reg); DPPMIs.push_back(UndefInst.getInstr()); @@ -581,12 +602,17 @@ bool GCNDPPCombine::runOnMachineFunction(MachineFunction &MF) { Changed = true; ++NumDPPMovsCombined; } else if (MI.getOpcode() == AMDGPU::V_MOV_B64_DPP_PSEUDO) { - auto Split = TII->expandMovDPP64(MI); - for (auto M : { Split.first, Split.second }) { - if (combineDPPMov(*M)) - ++NumDPPMovsCombined; + if (ST.has64BitDPP() && combineDPPMov(MI)) { + Changed = true; + ++NumDPPMovsCombined; + } else { + auto Split = TII->expandMovDPP64(MI); + for (auto M : { Split.first, Split.second }) { + if (M && combineDPPMov(*M)) + ++NumDPPMovsCombined; + } + Changed = true; } - Changed = true; } } } diff --git a/llvm/lib/Target/AMDGPU/GCNHazardRecognizer.cpp b/llvm/lib/Target/AMDGPU/GCNHazardRecognizer.cpp index ed1dc77bd545..0482865bd518 100644 --- a/llvm/lib/Target/AMDGPU/GCNHazardRecognizer.cpp +++ b/llvm/lib/Target/AMDGPU/GCNHazardRecognizer.cpp @@ -32,7 +32,7 @@ GCNHazardRecognizer::GCNHazardRecognizer(const MachineFunction &MF) : TRI(TII.getRegisterInfo()), ClauseUses(TRI.getNumRegUnits()), ClauseDefs(TRI.getNumRegUnits()) { - MaxLookAhead = MF.getRegInfo().isPhysRegUsed(AMDGPU::AGPR0) ? 18 : 5; + MaxLookAhead = MF.getRegInfo().isPhysRegUsed(AMDGPU::AGPR0) ? 19 : 5; TSchedModel.init(&ST); } @@ -87,6 +87,25 @@ static bool isSMovRel(unsigned Opcode) { } } +static bool isDGEMM(unsigned Opcode) { + return Opcode == AMDGPU::V_MFMA_F64_4X4X4F64_e64 || + Opcode == AMDGPU::V_MFMA_F64_4X4X4F64_vgprcd_e64 || + Opcode == AMDGPU::V_MFMA_F64_16X16X4F64_e64 || + Opcode == AMDGPU::V_MFMA_F64_16X16X4F64_vgprcd_e64; +} + +static bool isXDL(const GCNSubtarget &ST, const MachineInstr &MI) { + unsigned Opcode = MI.getOpcode(); + + if (!SIInstrInfo::isMAI(MI) || + isDGEMM(Opcode) || + Opcode == AMDGPU::V_ACCVGPR_WRITE_B32_e64 || + Opcode == AMDGPU::V_ACCVGPR_READ_B32_e64) + return false; + + return true; +} + static bool isSendMsgTraceDataOrGDS(const SIInstrInfo &TII, const MachineInstr &MI) { if (TII.isAlwaysGDS(MI.getOpcode())) @@ -165,6 +184,11 @@ GCNHazardRecognizer::getHazardType(SUnit *SU, int Stalls) { if (isRWLane(MI->getOpcode()) && checkRWLaneHazards(MI) > 0) return HazardType; + if ((SIInstrInfo::isVALU(*MI) || SIInstrInfo::isVMEM(*MI) || + SIInstrInfo::isFLAT(*MI) || SIInstrInfo::isDS(*MI) || + SIInstrInfo::isEXP(*MI)) && checkMAIVALUHazards(MI) > 0) + return HazardType; + if (isSGetReg(MI->getOpcode()) && checkGetRegHazards(MI) > 0) return HazardType; @@ -274,6 +298,11 @@ unsigned GCNHazardRecognizer::PreEmitNoopsCommon(MachineInstr *MI) { if (isRWLane(MI->getOpcode())) WaitStates = std::max(WaitStates, checkRWLaneHazards(MI)); + if ((SIInstrInfo::isVALU(*MI) || SIInstrInfo::isVMEM(*MI) || + SIInstrInfo::isFLAT(*MI) || SIInstrInfo::isDS(*MI) || + SIInstrInfo::isEXP(*MI)) && checkMAIVALUHazards(MI) > 0) + WaitStates = std::max(WaitStates, checkMAIVALUHazards(MI)); + if (MI->isInlineAsm()) return std::max(WaitStates, checkInlineAsmHazards(MI)); @@ -603,7 +632,7 @@ int GCNHazardRecognizer::checkVMEMHazards(MachineInstr* VMEM) { const int VmemSgprWaitStates = 5; auto IsHazardDefFn = [this] (MachineInstr *MI) { return TII.isVALU(*MI); }; for (const MachineOperand &Use : VMEM->uses()) { - if (!Use.isReg() || TRI.isVGPR(MF.getRegInfo(), Use.getReg())) + if (!Use.isReg() || TRI.isVectorRegister(MF.getRegInfo(), Use.getReg())) continue; int WaitStatesNeededForUse = @@ -739,7 +768,7 @@ GCNHazardRecognizer::checkVALUHazardsHelper(const MachineOperand &Def, const int VALUWaitStates = 1; int WaitStatesNeeded = 0; - if (!TRI->isVGPR(MRI, Def.getReg())) + if (!TRI->isVectorRegister(MRI, Def.getReg())) return WaitStatesNeeded; Register Reg = Def.getReg(); auto IsHazardFn = [this, Reg, TRI] (MachineInstr *MI) { @@ -1187,6 +1216,10 @@ int GCNHazardRecognizer::checkFPAtomicToDenormModeHazard(MachineInstr *MI) { int GCNHazardRecognizer::checkMAIHazards(MachineInstr *MI) { assert(SIInstrInfo::isMAI(*MI)); + return ST.hasGFX90AInsts() ? checkMAIHazards90A(MI) : checkMAIHazards908(MI); +} + +int GCNHazardRecognizer::checkMAIHazards908(MachineInstr *MI) { int WaitStatesNeeded = 0; unsigned Opc = MI->getOpcode(); @@ -1353,8 +1386,166 @@ int GCNHazardRecognizer::checkMAIHazards(MachineInstr *MI) { return WaitStatesNeeded; } +int GCNHazardRecognizer::checkMAIHazards90A(MachineInstr *MI) { + int WaitStatesNeeded = 0; + unsigned Opc = MI->getOpcode(); + + auto IsMFMAFn = [] (MachineInstr *MI) { + return SIInstrInfo::isMAI(*MI) && + MI->getOpcode() != AMDGPU::V_ACCVGPR_WRITE_B32_e64 && + MI->getOpcode() != AMDGPU::V_ACCVGPR_READ_B32_e64; + }; + + auto IsLegacyVALUFn = [&IsMFMAFn] (MachineInstr *MI) { + return SIInstrInfo::isVALU(*MI) && !IsMFMAFn(MI); + }; + + auto IsLegacyVALUNotDotFn = [&IsMFMAFn] (MachineInstr *MI) { + return SIInstrInfo::isVALU(*MI) && + !IsMFMAFn(MI) && !SIInstrInfo::isDOT(*MI); + }; + + if (!IsMFMAFn(MI)) + return WaitStatesNeeded; + + const int VALUWritesExecWaitStates = 4; + int WaitStatesNeededForUse = VALUWritesExecWaitStates - + getWaitStatesSinceDef(AMDGPU::EXEC, IsLegacyVALUFn, + VALUWritesExecWaitStates); + WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse); + + int SrcCIdx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src2); + + // Loop for both DGEMM and S/HGEMM 2nd instruction. + for (const MachineOperand &Use : MI->explicit_uses()) { + const int LegacyVALUNotDotWritesVGPRWaitStates = 2; + const int SMFMA4x4WritesVGPROverlappedSMFMASrcCWaitStates = 2; + const int SMFMA16x16WritesVGPROverlappedSMFMASrcCWaitStates = 8; + const int SMFMA32x32WritesVGPROverlappedSMFMASrcCWaitStates = 16; + const int SMFMA4x4WritesVGPROverlappedDMFMASrcCWaitStates = 3; + const int SMFMA16x16WritesVGPROverlappedDMFMASrcCWaitStates = 9; + const int SMFMA32x32WritesVGPROverlappedDMFMASrcCWaitStates = 17; + const int DMFMA16x16WritesVGPROverlappedSrcCWaitStates = 9; + const int DMFMA4x4WritesVGPROverlappedSrcCWaitStates = 4; + const int SMFMA4x4WritesVGPROverlappedSrcABWaitStates = 5; + const int SMFMA16x16WritesVGPROverlappedSrcABWaitStates = 11; + const int SMFMA32x32WritesVGPROverlappedSrcABWaitStates = 19; + const int DMFMA4x4WritesVGPROverlappedMFMASrcABWaitStates = 6; + const int DMFMA16x16WritesVGPROverlappedMFMASrcABWaitStates = 11; + const int DMFMA4x4WritesVGPRFullSrcCWaitStates = 4; + const int MaxWaitStates = 19; + + if (!Use.isReg()) + continue; + unsigned Reg = Use.getReg(); + bool FullReg; + MachineInstr *MI1; + + auto IsOverlappedDGEMMorXDLFn = [Reg, &IsMFMAFn, &FullReg, &MI1, this] + (MachineInstr *MI) { + if (!IsMFMAFn(MI)) + return false; + if (!isDGEMM(MI->getOpcode()) && !isXDL(ST, *MI)) + return false; + Register DstReg = MI->getOperand(0).getReg(); + FullReg = (DstReg == Reg); + MI1 = MI; + return TRI.regsOverlap(DstReg, Reg); + }; + + WaitStatesNeededForUse = LegacyVALUNotDotWritesVGPRWaitStates - + getWaitStatesSinceDef(Reg, IsLegacyVALUNotDotFn, MaxWaitStates); + WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse); + + int NumWaitStates = getWaitStatesSinceDef(Reg, IsOverlappedDGEMMorXDLFn, + MaxWaitStates); + if (NumWaitStates == std::numeric_limits<int>::max()) + continue; + + int OpNo = MI->getOperandNo(&Use); + unsigned Opc1 = MI1->getOpcode(); + int NeedWaitStates = 0; + if (OpNo == SrcCIdx) { + if (!isDGEMM(Opc) && isDGEMM(Opc1)) { + NeedWaitStates = 0; + } else if (FullReg) { + if ((Opc == AMDGPU::V_MFMA_F64_4X4X4F64_e64 || + Opc == AMDGPU::V_MFMA_F64_4X4X4F64_vgprcd_e64) && + (Opc1 == AMDGPU::V_MFMA_F64_4X4X4F64_e64 || + Opc1 == AMDGPU::V_MFMA_F64_4X4X4F64_vgprcd_e64)) + NeedWaitStates = DMFMA4x4WritesVGPRFullSrcCWaitStates; + } else { + switch (Opc1) { + case AMDGPU::V_MFMA_F64_16X16X4F64_e64: + case AMDGPU::V_MFMA_F64_16X16X4F64_vgprcd_e64: + if (!isXDL(ST, *MI)) + NeedWaitStates = DMFMA16x16WritesVGPROverlappedSrcCWaitStates; + break; + case AMDGPU::V_MFMA_F64_4X4X4F64_e64: + case AMDGPU::V_MFMA_F64_4X4X4F64_vgprcd_e64: + if (!isXDL(ST, *MI)) + NeedWaitStates = DMFMA4x4WritesVGPROverlappedSrcCWaitStates; + break; + default: + switch (TSchedModel.computeInstrLatency(MI1)) { + case 2: + NeedWaitStates = isDGEMM(Opc) + ? SMFMA4x4WritesVGPROverlappedDMFMASrcCWaitStates + : SMFMA4x4WritesVGPROverlappedSMFMASrcCWaitStates; + break; + case 8: + NeedWaitStates = isDGEMM(Opc) + ? SMFMA16x16WritesVGPROverlappedDMFMASrcCWaitStates + : SMFMA16x16WritesVGPROverlappedSMFMASrcCWaitStates; + break; + case 16: LLVM_FALLTHROUGH; + default: + NeedWaitStates = isDGEMM(Opc) + ? SMFMA32x32WritesVGPROverlappedDMFMASrcCWaitStates + : SMFMA32x32WritesVGPROverlappedSMFMASrcCWaitStates; + } + } + } + } else { + switch (Opc1) { + case AMDGPU::V_MFMA_F64_16X16X4F64_e64: + case AMDGPU::V_MFMA_F64_16X16X4F64_vgprcd_e64: + NeedWaitStates = DMFMA16x16WritesVGPROverlappedMFMASrcABWaitStates; + break; + case AMDGPU::V_MFMA_F64_4X4X4F64_e64: + case AMDGPU::V_MFMA_F64_4X4X4F64_vgprcd_e64: + NeedWaitStates = DMFMA4x4WritesVGPROverlappedMFMASrcABWaitStates; + break; + default: + switch (TSchedModel.computeInstrLatency(MI1)) { + case 2: + NeedWaitStates = SMFMA4x4WritesVGPROverlappedSrcABWaitStates; + break; + case 8: + NeedWaitStates = SMFMA16x16WritesVGPROverlappedSrcABWaitStates; + break; + case 16: LLVM_FALLTHROUGH; + default: + NeedWaitStates = SMFMA32x32WritesVGPROverlappedSrcABWaitStates; + } + } + } + if (WaitStatesNeeded >= NeedWaitStates) + continue; + + WaitStatesNeededForUse = NeedWaitStates - NumWaitStates; + WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse); + + if (WaitStatesNeeded == MaxWaitStates) + break; + } + + return WaitStatesNeeded; +} + int GCNHazardRecognizer::checkMAILdStHazards(MachineInstr *MI) { - if (!ST.hasMAIInsts()) + // On gfx90a+ releveant hazards are checked in checkMAIVALUHazards() + if (!ST.hasMAIInsts() || ST.hasGFX90AInsts()) return 0; int WaitStatesNeeded = 0; @@ -1399,6 +1590,234 @@ int GCNHazardRecognizer::checkMAILdStHazards(MachineInstr *MI) { return WaitStatesNeeded; } +int GCNHazardRecognizer::checkMAIVALUHazards(MachineInstr *MI) { + if (!ST.hasGFX90AInsts()) + return 0; + + auto IsMFMAFn = [] (MachineInstr *MI) -> bool { + return SIInstrInfo::isMAI(*MI) && + MI->getOpcode() != AMDGPU::V_ACCVGPR_WRITE_B32_e64 && + MI->getOpcode() != AMDGPU::V_ACCVGPR_READ_B32_e64; + }; + + auto IsDGEMMFn = [] (MachineInstr *MI) -> bool { + return isDGEMM(MI->getOpcode()); + }; + + // This is checked in checkMAIHazards90A() + if (IsMFMAFn(MI)) + return 0; + + int WaitStatesNeeded = 0; + + bool IsMemOrExport = SIInstrInfo::isVMEM(*MI) || + SIInstrInfo::isFLAT(*MI) || + SIInstrInfo::isDS(*MI) || + SIInstrInfo::isEXP(*MI); + bool IsVALU = SIInstrInfo::isVALU(*MI); + + MachineInstr *MFMA = nullptr; + unsigned Reg; + auto IsDGEMMorXDLWriteFn = [&Reg, &IsMFMAFn, &MFMA, this] (MachineInstr *MI) { + if (!IsMFMAFn(MI) || !TRI.regsOverlap(MI->getOperand(0).getReg(), Reg)) + return false; + if (!isDGEMM(MI->getOpcode()) && !isXDL(ST, *MI)) + return false; + MFMA = MI; + return true; + }; + + MachineInstr *DOT = nullptr; + auto IsDotWriteFn = [&Reg, &DOT, this] (MachineInstr *MI) { + if (!SIInstrInfo::isDOT(*MI) || + !TRI.regsOverlap(MI->getOperand(0).getReg(), Reg)) + return false; + DOT = MI; + return true; + }; + + int SrcCIdx = AMDGPU::getNamedOperandIdx(MI->getOpcode(), + AMDGPU::OpName::src2); + + if (IsMemOrExport || IsVALU) { + const int SMFMA4x4WriteVgprVALUMemExpReadWaitStates = 5; + const int SMFMA16x16WriteVgprVALUMemExpReadWaitStates = 11; + const int SMFMA32x32WriteVgprVALUMemExpReadWaitStates = 19; + const int DMFMA4x4WriteVgprMemExpReadWaitStates = 9; + const int DMFMA16x16WriteVgprMemExpReadWaitStates = 18; + const int DMFMA4x4WriteVgprVALUReadWaitStates = 6; + const int DMFMA16x16WriteVgprVALUReadWaitStates = 11; + const int DotWriteSameDotReadSrcAB = 3; + const int DotWriteDifferentVALURead = 3; + const int MaxWaitStates = 19; + + for (const MachineOperand &Use : MI->explicit_uses()) { + if (!Use.isReg()) + continue; + Reg = Use.getReg(); + + DOT = nullptr; + int WaitStatesSinceDef = getWaitStatesSinceDef(Reg, IsDotWriteFn, + MaxWaitStates); + if (DOT) { + int NeedWaitStates = 0; + if (DOT->getOpcode() == MI->getOpcode()) { + if (&Use - &MI->getOperand(0) != SrcCIdx) + NeedWaitStates = DotWriteSameDotReadSrcAB; + } else { + NeedWaitStates = DotWriteDifferentVALURead; + } + + int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSinceDef; + WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse); + } + + MFMA = nullptr; + WaitStatesSinceDef = getWaitStatesSinceDef(Reg, IsDGEMMorXDLWriteFn, + MaxWaitStates); + if (!MFMA) + continue; + + unsigned HazardDefLatency = TSchedModel.computeInstrLatency(MFMA); + int NeedWaitStates = MaxWaitStates; + switch (HazardDefLatency) { + case 2: + NeedWaitStates = SMFMA4x4WriteVgprVALUMemExpReadWaitStates; + break; + case 4: + assert(isDGEMM(MFMA->getOpcode())); + NeedWaitStates = + IsMemOrExport ? DMFMA4x4WriteVgprMemExpReadWaitStates + : DMFMA4x4WriteVgprVALUReadWaitStates; + break; + case 8: + NeedWaitStates = SMFMA16x16WriteVgprVALUMemExpReadWaitStates; + break; + case 16: LLVM_FALLTHROUGH; + default: + NeedWaitStates = + isDGEMM(MFMA->getOpcode()) + ? IsMemOrExport ? DMFMA16x16WriteVgprMemExpReadWaitStates + : DMFMA16x16WriteVgprVALUReadWaitStates + : SMFMA32x32WriteVgprVALUMemExpReadWaitStates; + break; + } + + int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSinceDef; + WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse); + + if (WaitStatesNeeded == MaxWaitStates) + break; + } + } + + unsigned Opc = MI->getOpcode(); + const int DMFMAToFMA64WaitStates = 2; + if ((Opc == AMDGPU::V_FMA_F64_e64 || + Opc == AMDGPU::V_FMAC_F64_e32 || Opc == AMDGPU::V_FMAC_F64_e64 || + Opc == AMDGPU::V_FMAC_F64_dpp) && + WaitStatesNeeded < DMFMAToFMA64WaitStates) { + int WaitStatesNeededForUse = DMFMAToFMA64WaitStates - + getWaitStatesSince(IsDGEMMFn, DMFMAToFMA64WaitStates); + WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse); + } + + if (!IsVALU && !IsMemOrExport) + return WaitStatesNeeded; + + for (const MachineOperand &Def : MI->defs()) { + const int SMFMA4x4WriteVgprVALUWawWaitStates = 5; + const int SMFMA16x16WriteVgprVALUWawWaitStates = 11; + const int SMFMA32x32WriteVgprVALUWawWaitStates = 19; + const int SMFMA4x4ReadVgprVALUWarWaitStates = 1; + const int SMFMA16x16ReadVgprVALUWarWaitStates = 7; + const int SMFMA32x32ReadVgprVALUWarWaitStates = 15; + const int DMFMA4x4WriteVgprVALUWriteWaitStates = 6; + const int DMFMA16x16WriteVgprVALUWriteWaitStates = 11; + const int DotWriteDifferentVALUWrite = 3; + const int MaxWaitStates = 19; + const int MaxWarWaitStates = 15; + + Reg = Def.getReg(); + + DOT = nullptr; + int WaitStatesSinceDef = getWaitStatesSinceDef(Reg, IsDotWriteFn, + MaxWaitStates); + if (DOT && DOT->getOpcode() != MI->getOpcode()) + WaitStatesNeeded = std::max(WaitStatesNeeded, DotWriteDifferentVALUWrite - + WaitStatesSinceDef); + + MFMA = nullptr; + WaitStatesSinceDef = getWaitStatesSinceDef(Reg, IsDGEMMorXDLWriteFn, + MaxWaitStates); + if (MFMA) { + int NeedWaitStates = MaxWaitStates; + switch (TSchedModel.computeInstrLatency(MFMA)) { + case 2: + NeedWaitStates = SMFMA4x4WriteVgprVALUWawWaitStates; + break; + case 4: + assert(isDGEMM(MFMA->getOpcode())); + NeedWaitStates = DMFMA4x4WriteVgprVALUWriteWaitStates; + break; + case 8: + NeedWaitStates = SMFMA16x16WriteVgprVALUWawWaitStates; + break; + case 16: LLVM_FALLTHROUGH; + default: + NeedWaitStates = isDGEMM(MFMA->getOpcode()) + ? DMFMA16x16WriteVgprVALUWriteWaitStates + : SMFMA32x32WriteVgprVALUWawWaitStates; + break; + } + + int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSinceDef; + WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse); + + if (WaitStatesNeeded == MaxWaitStates) + break; + } + + auto IsSMFMAReadAsCFn = [&Reg, &IsMFMAFn, &MFMA, this] + (MachineInstr *MI) { + if (!IsMFMAFn(MI) || isDGEMM(MI->getOpcode()) || + !MI->readsRegister(Reg, &TRI)) + return false; + + MachineOperand *SrcC = TII.getNamedOperand(*MI, AMDGPU::OpName::src2); + assert(SrcC); + if (!SrcC->isReg() || !TRI.regsOverlap(SrcC->getReg(), Reg)) + return false; + + MFMA = MI; + return true; + }; + + MFMA = nullptr; + int WaitStatesSinceUse = getWaitStatesSince(IsSMFMAReadAsCFn, + MaxWarWaitStates); + if (!MFMA) + continue; + + unsigned HazardDefLatency = TSchedModel.computeInstrLatency(MFMA); + int NeedWaitStates = MaxWaitStates; + switch (HazardDefLatency) { + case 2: NeedWaitStates = SMFMA4x4ReadVgprVALUWarWaitStates; + break; + case 8: NeedWaitStates = SMFMA16x16ReadVgprVALUWarWaitStates; + break; + case 16: LLVM_FALLTHROUGH; + default: NeedWaitStates = SMFMA32x32ReadVgprVALUWarWaitStates; + break; + } + + int WaitStatesNeededForUse = NeedWaitStates - WaitStatesSinceUse; + WaitStatesNeeded = std::max(WaitStatesNeeded, WaitStatesNeededForUse); + } + + return WaitStatesNeeded; +} + bool GCNHazardRecognizer::ShouldPreferAnother(SUnit *SU) { if (!SU->isInstr()) return false; diff --git a/llvm/lib/Target/AMDGPU/GCNHazardRecognizer.h b/llvm/lib/Target/AMDGPU/GCNHazardRecognizer.h index 447ca828ae64..6d61af3ac876 100644 --- a/llvm/lib/Target/AMDGPU/GCNHazardRecognizer.h +++ b/llvm/lib/Target/AMDGPU/GCNHazardRecognizer.h @@ -94,6 +94,9 @@ private: bool fixLdsBranchVmemWARHazard(MachineInstr *MI); int checkMAIHazards(MachineInstr *MI); + int checkMAIHazards908(MachineInstr *MI); + int checkMAIHazards90A(MachineInstr *MI); + int checkMAIVALUHazards(MachineInstr *MI); int checkMAILdStHazards(MachineInstr *MI); public: diff --git a/llvm/lib/Target/AMDGPU/GCNProcessors.td b/llvm/lib/Target/AMDGPU/GCNProcessors.td index 7447ec2db188..888bbbb9d3c1 100644 --- a/llvm/lib/Target/AMDGPU/GCNProcessors.td +++ b/llvm/lib/Target/AMDGPU/GCNProcessors.td @@ -184,6 +184,10 @@ def : ProcessorModel<"gfx909", SIQuarterSpeedModel, FeatureISAVersion9_0_9.Features >; +def : ProcessorModel<"gfx90a", SIDPFullSpeedModel, + FeatureISAVersion9_0_A.Features +>; + def : ProcessorModel<"gfx90c", SIQuarterSpeedModel, FeatureISAVersion9_0_C.Features >; diff --git a/llvm/lib/Target/AMDGPU/GCNRegPressure.cpp b/llvm/lib/Target/AMDGPU/GCNRegPressure.cpp index 55fd2b5eb284..3456f9a6156c 100644 --- a/llvm/lib/Target/AMDGPU/GCNRegPressure.cpp +++ b/llvm/lib/Target/AMDGPU/GCNRegPressure.cpp @@ -125,12 +125,14 @@ bool GCNRegPressure::less(const GCNSubtarget &ST, unsigned MaxOccupancy) const { const auto SGPROcc = std::min(MaxOccupancy, ST.getOccupancyWithNumSGPRs(getSGPRNum())); - const auto VGPROcc = std::min(MaxOccupancy, - ST.getOccupancyWithNumVGPRs(getVGPRNum())); + const auto VGPROcc = + std::min(MaxOccupancy, + ST.getOccupancyWithNumVGPRs(getVGPRNum(ST.hasGFX90AInsts()))); const auto OtherSGPROcc = std::min(MaxOccupancy, ST.getOccupancyWithNumSGPRs(O.getSGPRNum())); - const auto OtherVGPROcc = std::min(MaxOccupancy, - ST.getOccupancyWithNumVGPRs(O.getVGPRNum())); + const auto OtherVGPROcc = + std::min(MaxOccupancy, + ST.getOccupancyWithNumVGPRs(O.getVGPRNum(ST.hasGFX90AInsts()))); const auto Occ = std::min(SGPROcc, VGPROcc); const auto OtherOcc = std::min(OtherSGPROcc, OtherVGPROcc); @@ -161,7 +163,8 @@ bool GCNRegPressure::less(const GCNSubtarget &ST, } } return SGPRImportant ? (getSGPRNum() < O.getSGPRNum()): - (getVGPRNum() < O.getVGPRNum()); + (getVGPRNum(ST.hasGFX90AInsts()) < + O.getVGPRNum(ST.hasGFX90AInsts())); } #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) @@ -169,7 +172,9 @@ LLVM_DUMP_METHOD void GCNRegPressure::print(raw_ostream &OS, const GCNSubtarget *ST) const { OS << "VGPRs: " << Value[VGPR32] << ' '; OS << "AGPRs: " << Value[AGPR32]; - if (ST) OS << "(O" << ST->getOccupancyWithNumVGPRs(getVGPRNum()) << ')'; + if (ST) OS << "(O" + << ST->getOccupancyWithNumVGPRs(getVGPRNum(ST->hasGFX90AInsts())) + << ')'; OS << ", SGPRs: " << getSGPRNum(); if (ST) OS << "(O" << ST->getOccupancyWithNumSGPRs(getSGPRNum()) << ')'; OS << ", LVGPR WT: " << getVGPRTuplesWeight() diff --git a/llvm/lib/Target/AMDGPU/GCNRegPressure.h b/llvm/lib/Target/AMDGPU/GCNRegPressure.h index 8541c7e983f7..257561cb8430 100644 --- a/llvm/lib/Target/AMDGPU/GCNRegPressure.h +++ b/llvm/lib/Target/AMDGPU/GCNRegPressure.h @@ -42,12 +42,19 @@ struct GCNRegPressure { clear(); } - bool empty() const { return getSGPRNum() == 0 && getVGPRNum() == 0; } + bool empty() const { return getSGPRNum() == 0 && getVGPRNum(false) == 0; } void clear() { std::fill(&Value[0], &Value[TOTAL_KINDS], 0); } unsigned getSGPRNum() const { return Value[SGPR32]; } - unsigned getVGPRNum() const { return std::max(Value[VGPR32], Value[AGPR32]); } + unsigned getVGPRNum(bool UnifiedVGPRFile) const { + if (UnifiedVGPRFile) { + return Value[AGPR32] ? alignTo(Value[VGPR32], 4) + Value[AGPR32] + : Value[VGPR32] + Value[AGPR32]; + } + return std::max(Value[VGPR32], Value[AGPR32]); + } + unsigned getAGPRNum() const { return Value[AGPR32]; } unsigned getVGPRTuplesWeight() const { return std::max(Value[VGPR_TUPLE], Value[AGPR_TUPLE]); } @@ -55,7 +62,7 @@ struct GCNRegPressure { unsigned getOccupancy(const GCNSubtarget &ST) const { return std::min(ST.getOccupancyWithNumSGPRs(getSGPRNum()), - ST.getOccupancyWithNumVGPRs(getVGPRNum())); + ST.getOccupancyWithNumVGPRs(getVGPRNum(ST.hasGFX90AInsts()))); } void inc(unsigned Reg, diff --git a/llvm/lib/Target/AMDGPU/GCNSchedStrategy.cpp b/llvm/lib/Target/AMDGPU/GCNSchedStrategy.cpp index 6e2550298dc6..18a534d28b21 100644 --- a/llvm/lib/Target/AMDGPU/GCNSchedStrategy.cpp +++ b/llvm/lib/Target/AMDGPU/GCNSchedStrategy.cpp @@ -335,7 +335,7 @@ void GCNScheduleDAGMILive::schedule() { PressureAfter.print(dbgs())); if (PressureAfter.getSGPRNum() <= S.SGPRCriticalLimit && - PressureAfter.getVGPRNum() <= S.VGPRCriticalLimit) { + PressureAfter.getVGPRNum(ST.hasGFX90AInsts()) <= S.VGPRCriticalLimit) { Pressure[RegionIdx] = PressureAfter; LLVM_DEBUG(dbgs() << "Pressure in desired limits, done.\n"); return; @@ -366,7 +366,8 @@ void GCNScheduleDAGMILive::schedule() { unsigned MaxVGPRs = ST.getMaxNumVGPRs(MF); unsigned MaxSGPRs = ST.getMaxNumSGPRs(MF); - if (PressureAfter.getVGPRNum() > MaxVGPRs || + if (PressureAfter.getVGPRNum(false) > MaxVGPRs || + PressureAfter.getAGPRNum() > MaxVGPRs || PressureAfter.getSGPRNum() > MaxSGPRs) RescheduleRegions[RegionIdx] = true; diff --git a/llvm/lib/Target/AMDGPU/GCNSubtarget.h b/llvm/lib/Target/AMDGPU/GCNSubtarget.h index 7a7178126444..c2f172aa5a5a 100644 --- a/llvm/lib/Target/AMDGPU/GCNSubtarget.h +++ b/llvm/lib/Target/AMDGPU/GCNSubtarget.h @@ -82,6 +82,7 @@ protected: bool FastFMAF32; bool FastDenormalF32; bool HalfRate64Ops; + bool FullRate64Ops; // Dynamically set bits that enable features. bool FlatForGlobal; @@ -95,6 +96,7 @@ protected: // for XNACK. bool EnableXNACK; + bool EnableTgSplit; bool EnableCuMode; bool TrapHandler; @@ -110,10 +112,11 @@ protected: bool FP64; bool FMA; bool MIMG_R128; - bool GCN3Encoding; + bool IsGCN; bool CIInsts; bool GFX8Insts; bool GFX9Insts; + bool GFX90AInsts; bool GFX10Insts; bool GFX10_3Insts; bool GFX7GFX8GFX9Insts; @@ -132,6 +135,9 @@ protected: bool HasSDWAOutModsVOPC; bool HasDPP; bool HasDPP8; + bool Has64BitDPP; + bool HasPackedFP32Ops; + bool HasExtendedImageInsts; bool HasR128A16; bool HasGFX10A16; bool HasG16; @@ -167,10 +173,16 @@ protected: bool ScalarFlatScratchInsts; bool AddNoCarryInsts; bool HasUnpackedD16VMem; + bool R600ALUInst; + bool CaymanISA; + bool CFALUBug; bool LDSMisalignedBug; bool HasMFMAInlineLiteralBug; + bool HasVertexCache; + short TexVTXClauseSize; bool UnalignedBufferAccess; bool UnalignedDSAccess; + bool HasPackedTID; bool ScalarizeGlobal; bool HasVcmpxPermlaneHazard; @@ -295,6 +307,10 @@ public: return HalfRate64Ops; } + bool hasFullRate64Ops() const { + return FullRate64Ops; + } + bool hasAddr64() const { return (getGeneration() < AMDGPUSubtarget::VOLCANIC_ISLANDS); } @@ -510,6 +526,10 @@ public: return TargetID.isXnackOnOrAny(); } + bool isTgSplitEnabled() const { + return EnableTgSplit; + } + bool isCuModeEnabled() const { return EnableCuMode; } @@ -796,6 +816,18 @@ public: return HasDPP8; } + bool has64BitDPP() const { + return Has64BitDPP; + } + + bool hasPackedFP32Ops() const { + return HasPackedFP32Ops; + } + + bool hasExtendedImageInsts() const { + return HasExtendedImageInsts; + } + bool hasR128A16() const { return HasR128A16; } @@ -896,6 +928,10 @@ public: bool hasHardClauses() const { return getGeneration() >= GFX10; } + bool hasGFX90AInsts() const { return GFX90AInsts; } + + bool hasPackedTID() const { return HasPackedTID; } + /// Return the maximum number of waves per SIMD for kernels using \p SGPRs /// SGPRs unsigned getOccupancyWithNumSGPRs(unsigned SGPRs) const; diff --git a/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUInstPrinter.cpp b/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUInstPrinter.cpp index 00bc9b2b65db..4b713ef93d48 100644 --- a/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUInstPrinter.cpp +++ b/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUInstPrinter.cpp @@ -10,6 +10,7 @@ #include "AMDGPUInstPrinter.h" #include "MCTargetDesc/AMDGPUMCTargetDesc.h" #include "SIDefines.h" +#include "SIRegisterInfo.h" #include "Utils/AMDGPUAsmUtils.h" #include "Utils/AMDGPUBaseInfo.h" #include "llvm/MC/MCExpr.h" @@ -207,6 +208,12 @@ void AMDGPUInstPrinter::printDLC(const MCInst *MI, unsigned OpNo, printNamedBit(MI, OpNo, O, "dlc"); } +void AMDGPUInstPrinter::printSCCB(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, raw_ostream &O) { + if (AMDGPU::isGFX90A(STI)) + printNamedBit(MI, OpNo, O, "scc"); +} + void AMDGPUInstPrinter::printGLC(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, raw_ostream &O) { printNamedBit(MI, OpNo, O, "glc"); @@ -601,6 +608,10 @@ void AMDGPUInstPrinter::printOperand(const MCInst *MI, unsigned OpNo, case AMDGPU::OPERAND_REG_INLINE_C_FP32: case AMDGPU::OPERAND_REG_INLINE_AC_INT32: case AMDGPU::OPERAND_REG_INLINE_AC_FP32: + case AMDGPU::OPERAND_REG_IMM_V2INT32: + case AMDGPU::OPERAND_REG_IMM_V2FP32: + case AMDGPU::OPERAND_REG_INLINE_C_V2INT32: + case AMDGPU::OPERAND_REG_INLINE_C_V2FP32: case MCOI::OPERAND_IMMEDIATE: printImmediate32(Op.getImm(), STI, O); break; @@ -608,6 +619,7 @@ void AMDGPUInstPrinter::printOperand(const MCInst *MI, unsigned OpNo, case AMDGPU::OPERAND_REG_IMM_FP64: case AMDGPU::OPERAND_REG_INLINE_C_INT64: case AMDGPU::OPERAND_REG_INLINE_C_FP64: + case AMDGPU::OPERAND_REG_INLINE_AC_FP64: printImmediate64(Op.getImm(), STI, O); break; case AMDGPU::OPERAND_REG_INLINE_C_INT16: @@ -794,7 +806,20 @@ void AMDGPUInstPrinter::printDPPCtrl(const MCInst *MI, unsigned OpNo, using namespace AMDGPU::DPP; unsigned Imm = MI->getOperand(OpNo).getImm(); - if (Imm <= DppCtrl::QUAD_PERM_LAST) { + const MCInstrDesc &Desc = MII.get(MI->getOpcode()); + int DstIdx = AMDGPU::getNamedOperandIdx(MI->getOpcode(), + AMDGPU::OpName::vdst); + int Src0Idx = AMDGPU::getNamedOperandIdx(MI->getOpcode(), + AMDGPU::OpName::src0); + + if (((DstIdx >= 0 && + Desc.OpInfo[DstIdx].RegClass == AMDGPU::VReg_64RegClassID) || + ((Src0Idx >= 0 && + Desc.OpInfo[Src0Idx].RegClass == AMDGPU::VReg_64RegClassID))) && + !AMDGPU::isLegal64BitDPPControl(Imm)) { + O << " /* 64 bit dpp only supports row_newbcast */"; + return; + } else if (Imm <= DppCtrl::QUAD_PERM_LAST) { O << "quad_perm:["; O << formatDec(Imm & 0x3) << ','; O << formatDec((Imm & 0xc) >> 2) << ','; @@ -854,11 +879,15 @@ void AMDGPUInstPrinter::printDPPCtrl(const MCInst *MI, unsigned OpNo, O << "row_bcast:31"; } else if ((Imm >= DppCtrl::ROW_SHARE_FIRST) && (Imm <= DppCtrl::ROW_SHARE_LAST)) { - if (!AMDGPU::isGFX10Plus(STI)) { - O << "/* row_share is not supported on ASICs earlier than GFX10 */"; + if (AMDGPU::isGFX90A(STI)) { + O << " row_newbcast:"; + } else if (AMDGPU::isGFX10Plus(STI)) { + O << "row_share:"; + } else { + O << " /* row_newbcast/row_share is not supported on ASICs earlier " + "than GFX90A/GFX10 */"; return; } - O << "row_share:"; printU4ImmDecOperand(MI, OpNo, O); } else if ((Imm >= DppCtrl::ROW_XMASK_FIRST) && (Imm <= DppCtrl::ROW_XMASK_LAST)) { diff --git a/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUInstPrinter.h b/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUInstPrinter.h index 8d13aa682211..121195fe8e20 100644 --- a/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUInstPrinter.h +++ b/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUInstPrinter.h @@ -70,6 +70,8 @@ private: raw_ostream &O); void printDLC(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, raw_ostream &O); + void printSCCB(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, + raw_ostream &O); void printGLC(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, raw_ostream &O); void printSLC(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, diff --git a/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUTargetStreamer.cpp b/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUTargetStreamer.cpp index f0eb11b70c97..842356008a4c 100644 --- a/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUTargetStreamer.cpp +++ b/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUTargetStreamer.cpp @@ -86,6 +86,7 @@ StringRef AMDGPUTargetStreamer::getArchNameFromElfMach(unsigned ElfMach) { case ELF::EF_AMDGPU_MACH_AMDGCN_GFX906: AK = GK_GFX906; break; case ELF::EF_AMDGPU_MACH_AMDGCN_GFX908: AK = GK_GFX908; break; case ELF::EF_AMDGPU_MACH_AMDGCN_GFX909: AK = GK_GFX909; break; + case ELF::EF_AMDGPU_MACH_AMDGCN_GFX90A: AK = GK_GFX90A; break; case ELF::EF_AMDGPU_MACH_AMDGCN_GFX90C: AK = GK_GFX90C; break; case ELF::EF_AMDGPU_MACH_AMDGCN_GFX1010: AK = GK_GFX1010; break; case ELF::EF_AMDGPU_MACH_AMDGCN_GFX1011: AK = GK_GFX1011; break; @@ -145,6 +146,7 @@ unsigned AMDGPUTargetStreamer::getElfMach(StringRef GPU) { case GK_GFX906: return ELF::EF_AMDGPU_MACH_AMDGCN_GFX906; case GK_GFX908: return ELF::EF_AMDGPU_MACH_AMDGCN_GFX908; case GK_GFX909: return ELF::EF_AMDGPU_MACH_AMDGCN_GFX909; + case GK_GFX90A: return ELF::EF_AMDGPU_MACH_AMDGCN_GFX90A; case GK_GFX90C: return ELF::EF_AMDGPU_MACH_AMDGCN_GFX90C; case GK_GFX1010: return ELF::EF_AMDGPU_MACH_AMDGCN_GFX1010; case GK_GFX1011: return ELF::EF_AMDGPU_MACH_AMDGCN_GFX1011; @@ -258,10 +260,19 @@ bool AMDGPUTargetAsmStreamer::EmitHSAMetadata( return true; } -bool AMDGPUTargetAsmStreamer::EmitCodeEnd() { +bool AMDGPUTargetAsmStreamer::EmitCodeEnd(const MCSubtargetInfo &STI) { const uint32_t Encoded_s_code_end = 0xbf9f0000; - OS << "\t.p2alignl 6, " << Encoded_s_code_end << '\n'; - OS << "\t.fill 48, 4, " << Encoded_s_code_end << '\n'; + const uint32_t Encoded_s_nop = 0xbf800000; + uint32_t Encoded_pad = Encoded_s_code_end; + unsigned FillSize = 48; + + if (AMDGPU::isGFX90A(STI)) { + Encoded_pad = Encoded_s_nop; + FillSize = 256; + } + + OS << "\t.p2alignl 6, " << Encoded_pad << '\n'; + OS << "\t.fill " << FillSize << ", 4, " << Encoded_pad << '\n'; return true; } @@ -331,6 +342,12 @@ void AMDGPUTargetAsmStreamer::EmitAmdhsaKernelDescriptor( OS << "\t\t.amdhsa_next_free_vgpr " << NextVGPR << '\n'; OS << "\t\t.amdhsa_next_free_sgpr " << NextSGPR << '\n'; + if (AMDGPU::isGFX90A(STI)) + OS << "\t\t.amdhsa_accum_offset " << + (AMDHSA_BITS_GET(KD.compute_pgm_rsrc3, + amdhsa::COMPUTE_PGM_RSRC3_GFX90A_ACCUM_OFFSET) + 1) * 4 + << '\n'; + if (!ReserveVCC) OS << "\t\t.amdhsa_reserve_vcc " << ReserveVCC << '\n'; if (IVersion.Major >= 7 && !ReserveFlatScr) @@ -360,6 +377,10 @@ void AMDGPUTargetAsmStreamer::EmitAmdhsaKernelDescriptor( PRINT_FIELD(OS, ".amdhsa_fp16_overflow", KD, compute_pgm_rsrc1, amdhsa::COMPUTE_PGM_RSRC1_FP16_OVFL); + if (AMDGPU::isGFX90A(STI)) + PRINT_FIELD(OS, ".amdhsa_tg_split", KD, + compute_pgm_rsrc3, + amdhsa::COMPUTE_PGM_RSRC3_GFX90A_TG_SPLIT); if (IVersion.Major >= 10) { PRINT_FIELD(OS, ".amdhsa_workgroup_processor_mode", KD, compute_pgm_rsrc1, @@ -616,14 +637,22 @@ bool AMDGPUTargetELFStreamer::EmitHSAMetadata( return true; } -bool AMDGPUTargetELFStreamer::EmitCodeEnd() { +bool AMDGPUTargetELFStreamer::EmitCodeEnd(const MCSubtargetInfo &STI) { const uint32_t Encoded_s_code_end = 0xbf9f0000; + const uint32_t Encoded_s_nop = 0xbf800000; + uint32_t Encoded_pad = Encoded_s_code_end; + unsigned FillSize = 48; + + if (AMDGPU::isGFX90A(STI)) { + Encoded_pad = Encoded_s_nop; + FillSize = 256; + } MCStreamer &OS = getStreamer(); OS.PushSection(); - OS.emitValueToAlignment(64, Encoded_s_code_end, 4); - for (unsigned I = 0; I < 48; ++I) - OS.emitInt32(Encoded_s_code_end); + OS.emitValueToAlignment(64, Encoded_pad, 4); + for (unsigned I = 0; I < FillSize; ++I) + OS.emitInt32(Encoded_pad); OS.PopSection(); return true; } diff --git a/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUTargetStreamer.h b/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUTargetStreamer.h index 4dbb37dca9e8..a29fc94ca523 100644 --- a/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUTargetStreamer.h +++ b/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUTargetStreamer.h @@ -85,7 +85,7 @@ public: virtual bool EmitHSAMetadata(const AMDGPU::HSAMD::Metadata &HSAMetadata) = 0; /// \returns True on success, false on failure. - virtual bool EmitCodeEnd() = 0; + virtual bool EmitCodeEnd(const MCSubtargetInfo &STI) = 0; virtual void EmitAmdhsaKernelDescriptor( const MCSubtargetInfo &STI, StringRef KernelName, @@ -129,7 +129,7 @@ public: bool EmitHSAMetadata(const AMDGPU::HSAMD::Metadata &HSAMetadata) override; /// \returns True on success, false on failure. - bool EmitCodeEnd() override; + bool EmitCodeEnd(const MCSubtargetInfo &STI) override; void EmitAmdhsaKernelDescriptor( const MCSubtargetInfo &STI, StringRef KernelName, @@ -177,7 +177,7 @@ public: bool EmitHSAMetadata(const AMDGPU::HSAMD::Metadata &HSAMetadata) override; /// \returns True on success, false on failure. - bool EmitCodeEnd() override; + bool EmitCodeEnd(const MCSubtargetInfo &STI) override; void EmitAmdhsaKernelDescriptor( const MCSubtargetInfo &STI, StringRef KernelName, diff --git a/llvm/lib/Target/AMDGPU/MCTargetDesc/SIMCCodeEmitter.cpp b/llvm/lib/Target/AMDGPU/MCTargetDesc/SIMCCodeEmitter.cpp index e0ca60bc3023..3fb11487a98d 100644 --- a/llvm/lib/Target/AMDGPU/MCTargetDesc/SIMCCodeEmitter.cpp +++ b/llvm/lib/Target/AMDGPU/MCTargetDesc/SIMCCodeEmitter.cpp @@ -234,12 +234,17 @@ uint32_t SIMCCodeEmitter::getLitEncoding(const MCOperand &MO, case AMDGPU::OPERAND_REG_INLINE_C_FP32: case AMDGPU::OPERAND_REG_INLINE_AC_INT32: case AMDGPU::OPERAND_REG_INLINE_AC_FP32: + case AMDGPU::OPERAND_REG_IMM_V2INT32: + case AMDGPU::OPERAND_REG_IMM_V2FP32: + case AMDGPU::OPERAND_REG_INLINE_C_V2INT32: + case AMDGPU::OPERAND_REG_INLINE_C_V2FP32: return getLit32Encoding(static_cast<uint32_t>(Imm), STI); case AMDGPU::OPERAND_REG_IMM_INT64: case AMDGPU::OPERAND_REG_IMM_FP64: case AMDGPU::OPERAND_REG_INLINE_C_INT64: case AMDGPU::OPERAND_REG_INLINE_C_FP64: + case AMDGPU::OPERAND_REG_INLINE_AC_FP64: return getLit64Encoding(static_cast<uint64_t>(Imm), STI); case AMDGPU::OPERAND_REG_IMM_INT16: diff --git a/llvm/lib/Target/AMDGPU/MIMGInstructions.td b/llvm/lib/Target/AMDGPU/MIMGInstructions.td index 6769b10d9123..404d5d8fa8c6 100644 --- a/llvm/lib/Target/AMDGPU/MIMGInstructions.td +++ b/llvm/lib/Target/AMDGPU/MIMGInstructions.td @@ -11,12 +11,14 @@ // // - MIMGEncGfx6: encoding introduced with gfx6 (obsoleted for atomics in gfx8) // - MIMGEncGfx8: encoding introduced with gfx8 for atomics +// - MIMGEncGfx90a: encoding for gfx90a for atomics // - MIMGEncGfx10Default: gfx10 default (non-NSA) encoding // - MIMGEncGfx10NSA: gfx10 NSA encoding class MIMGEncoding; def MIMGEncGfx6 : MIMGEncoding; def MIMGEncGfx8 : MIMGEncoding; +def MIMGEncGfx90a : MIMGEncoding; def MIMGEncGfx10Default : MIMGEncoding; def MIMGEncGfx10NSA : MIMGEncoding; @@ -207,14 +209,24 @@ class MIMGNSAHelper<int num_addrs> { // Base class of all pre-gfx10 MIMG instructions. class MIMG_gfx6789<bits<8> op, dag outs, string dns = ""> : MIMG<outs, dns>, MIMGe_gfx6789<op> { - let SubtargetPredicate = isGFX6GFX7GFX8GFX9; - let AssemblerPredicate = isGFX6GFX7GFX8GFX9; + let SubtargetPredicate = isGFX6GFX7GFX8GFX9NotGFX90A; + let AssemblerPredicate = isGFX6GFX7GFX8GFX9NotGFX90A; let MIMGEncoding = MIMGEncGfx6; let d16 = !if(BaseOpcode.HasD16, ?, 0); } +class MIMG_gfx90a<bits<8> op, dag outs, string dns = ""> + : MIMG<outs, dns>, MIMGe_gfx90a<op> { + let SubtargetPredicate = isGFX90APlus; + let AssemblerPredicate = isGFX90APlus; + + let MIMGEncoding = MIMGEncGfx90a; + + let d16 = !if(BaseOpcode.HasD16, ?, 0); +} + // Base class of all non-NSA gfx10 MIMG instructions. class MIMG_gfx10<int op, dag outs, string dns = ""> : MIMG<outs, dns>, MIMGe_gfx10<op> { @@ -250,10 +262,23 @@ class MIMG_NoSampler_Helper <mimgopc op, string asm, string dns=""> : MIMG_gfx6789 <op.BASE, (outs dst_rc:$vdata), dns> { let InOperandList = !con((ins addr_rc:$vaddr, SReg_256:$srsrc, - DMask:$dmask, UNorm:$unorm, GLC:$glc, SLC:$slc, + DMask:$dmask, UNorm:$unorm, SCCB_0:$sccb, GLC:$glc, SLC:$slc, R128A16:$r128, TFE:$tfe, LWE:$lwe, DA:$da), !if(BaseOpcode.HasD16, (ins D16:$d16), (ins))); - let AsmString = asm#" $vdata, $vaddr, $srsrc$dmask$unorm$glc$slc$r128$tfe$lwe$da" + let AsmString = asm#" $vdata, $vaddr, $srsrc$dmask$unorm$sccb$glc$slc$r128$tfe$lwe$da" + #!if(BaseOpcode.HasD16, "$d16", ""); +} + +class MIMG_NoSampler_Helper_gfx90a <mimgopc op, string asm, + RegisterClass dst_rc, + RegisterClass addr_rc, + string dns=""> + : MIMG_gfx90a <op.BASE, (outs getLdStRegisterOperand<dst_rc>.ret:$vdata), dns> { + let InOperandList = !con((ins addr_rc:$vaddr, SReg_256:$srsrc, + DMask:$dmask, UNorm:$unorm, SCCB_0:$sccb, GLC:$glc, SLC:$slc, + R128A16:$r128, LWE:$lwe, DA:$da), + !if(BaseOpcode.HasD16, (ins D16:$d16), (ins))); + let AsmString = asm#" $vdata, $vaddr, $srsrc$dmask$unorm$sccb$glc$slc$r128$lwe$da" #!if(BaseOpcode.HasD16, "$d16", ""); } @@ -284,12 +309,16 @@ class MIMG_NoSampler_nsa_gfx10<mimgopc op, string opcode, multiclass MIMG_NoSampler_Src_Helper <mimgopc op, string asm, RegisterClass dst_rc, - bit enableDisasm> { + bit enableDisasm, + bit ExtendedImageInst = 1> { let ssamp = 0 in { let VAddrDwords = 1 in { if op.HAS_BASE then { def _V1 : MIMG_NoSampler_Helper <op, asm, dst_rc, VGPR_32, !if(enableDisasm, "AMDGPU", "")>; + foreach _ = BoolToList<!eq(ExtendedImageInst, 0)>.ret in + def _V1_gfx90a : MIMG_NoSampler_Helper_gfx90a <op, asm, dst_rc, VGPR_32, + !if(enableDisasm, "GFX90A", "")>; def _V1_gfx10 : MIMG_NoSampler_gfx10<op, asm, dst_rc, VGPR_32, !if(enableDisasm, "AMDGPU", "")>; } @@ -298,6 +327,8 @@ multiclass MIMG_NoSampler_Src_Helper <mimgopc op, string asm, let VAddrDwords = 2 in { if op.HAS_BASE then { def _V2 : MIMG_NoSampler_Helper <op, asm, dst_rc, VReg_64>; + foreach _ = BoolToList<!eq(ExtendedImageInst, 0)>.ret in + def _V2_gfx90a : MIMG_NoSampler_Helper_gfx90a <op, asm, dst_rc, VReg_64>; def _V2_gfx10 : MIMG_NoSampler_gfx10<op, asm, dst_rc, VReg_64>; def _V2_nsa_gfx10 : MIMG_NoSampler_nsa_gfx10<op, asm, dst_rc, 2>; } @@ -306,6 +337,8 @@ multiclass MIMG_NoSampler_Src_Helper <mimgopc op, string asm, let VAddrDwords = 3 in { if op.HAS_BASE then { def _V3 : MIMG_NoSampler_Helper <op, asm, dst_rc, VReg_96>; + foreach _ = BoolToList<!eq(ExtendedImageInst, 0)>.ret in + def _V3_gfx90a : MIMG_NoSampler_Helper_gfx90a <op, asm, dst_rc, VReg_96>; def _V3_gfx10 : MIMG_NoSampler_gfx10<op, asm, dst_rc, VReg_96>; def _V3_nsa_gfx10 : MIMG_NoSampler_nsa_gfx10<op, asm, dst_rc, 3>; } @@ -314,6 +347,8 @@ multiclass MIMG_NoSampler_Src_Helper <mimgopc op, string asm, let VAddrDwords = 4 in { if op.HAS_BASE then { def _V4 : MIMG_NoSampler_Helper <op, asm, dst_rc, VReg_128>; + foreach _ = BoolToList<!eq(ExtendedImageInst, 0)>.ret in + def _V4_gfx90a : MIMG_NoSampler_Helper_gfx90a <op, asm, dst_rc, VReg_128>; def _V4_gfx10 : MIMG_NoSampler_gfx10<op, asm, dst_rc, VReg_128>; def _V4_nsa_gfx10 : MIMG_NoSampler_nsa_gfx10<op, asm, dst_rc, 4, !if(enableDisasm, "AMDGPU", "")>; @@ -323,7 +358,8 @@ multiclass MIMG_NoSampler_Src_Helper <mimgopc op, string asm, } multiclass MIMG_NoSampler <mimgopc op, string asm, bit has_d16, bit mip = 0, - bit isResInfo = 0> { + bit isResInfo = 0, + bit msaa = 0> { def "" : MIMGBaseOpcode { let Coordinates = !not(isResInfo); let LodOrClampOrMip = mip; @@ -333,15 +369,15 @@ multiclass MIMG_NoSampler <mimgopc op, string asm, bit has_d16, bit mip = 0, let BaseOpcode = !cast<MIMGBaseOpcode>(NAME), mayLoad = !not(isResInfo) in { let VDataDwords = 1 in - defm _V1 : MIMG_NoSampler_Src_Helper <op, asm, VGPR_32, 1>; + defm _V1 : MIMG_NoSampler_Src_Helper <op, asm, VGPR_32, 1, msaa>; let VDataDwords = 2 in - defm _V2 : MIMG_NoSampler_Src_Helper <op, asm, VReg_64, 0>; + defm _V2 : MIMG_NoSampler_Src_Helper <op, asm, VReg_64, 0, msaa>; let VDataDwords = 3 in - defm _V3 : MIMG_NoSampler_Src_Helper <op, asm, VReg_96, 0>; + defm _V3 : MIMG_NoSampler_Src_Helper <op, asm, VReg_96, 0, msaa>; let VDataDwords = 4 in - defm _V4 : MIMG_NoSampler_Src_Helper <op, asm, VReg_128, 0>; + defm _V4 : MIMG_NoSampler_Src_Helper <op, asm, VReg_128, 0, msaa>; let VDataDwords = 5 in - defm _V5 : MIMG_NoSampler_Src_Helper <op, asm, VReg_160, 0>; + defm _V5 : MIMG_NoSampler_Src_Helper <op, asm, VReg_160, 0, msaa>; } } @@ -351,10 +387,24 @@ class MIMG_Store_Helper <mimgopc op, string asm, string dns = ""> : MIMG_gfx6789<op.BASE, (outs), dns> { let InOperandList = !con((ins data_rc:$vdata, addr_rc:$vaddr, SReg_256:$srsrc, - DMask:$dmask, UNorm:$unorm, GLC:$glc, SLC:$slc, + DMask:$dmask, UNorm:$unorm, SCCB_0:$sccb, GLC:$glc, SLC:$slc, R128A16:$r128, TFE:$tfe, LWE:$lwe, DA:$da), !if(BaseOpcode.HasD16, (ins D16:$d16), (ins))); - let AsmString = asm#" $vdata, $vaddr, $srsrc$dmask$unorm$glc$slc$r128$tfe$lwe$da" + let AsmString = asm#" $vdata, $vaddr, $srsrc$dmask$unorm$sccb$glc$slc$r128$tfe$lwe$da" + #!if(BaseOpcode.HasD16, "$d16", ""); +} + +class MIMG_Store_Helper_gfx90a <mimgopc op, string asm, + RegisterClass data_rc, + RegisterClass addr_rc, + string dns = ""> + : MIMG_gfx90a<op.BASE, (outs), dns> { + let InOperandList = !con((ins getLdStRegisterOperand<data_rc>.ret:$vdata, + addr_rc:$vaddr, SReg_256:$srsrc, + DMask:$dmask, UNorm:$unorm, SCCB_0:$sccb, GLC:$glc, SLC:$slc, + R128A16:$r128, LWE:$lwe, DA:$da), + !if(BaseOpcode.HasD16, (ins D16:$d16), (ins))); + let AsmString = asm#" $vdata, $vaddr, $srsrc$dmask$unorm$sccb$glc$slc$r128$lwe$da" #!if(BaseOpcode.HasD16, "$d16", ""); } @@ -393,6 +443,8 @@ multiclass MIMG_Store_Addr_Helper <mimgopc op, string asm, if op.HAS_BASE then { def _V1 : MIMG_Store_Helper <op, asm, data_rc, VGPR_32, !if(enableDisasm, "AMDGPU", "")>; + def _V1_gfx90a : MIMG_Store_Helper_gfx90a <op, asm, data_rc, VGPR_32, + !if(enableDisasm, "GFX90A", "")>; def _V1_gfx10 : MIMG_Store_gfx10 <op, asm, data_rc, VGPR_32, !if(enableDisasm, "AMDGPU", "")>; } @@ -400,6 +452,7 @@ multiclass MIMG_Store_Addr_Helper <mimgopc op, string asm, let VAddrDwords = 2 in { if op.HAS_BASE then { def _V2 : MIMG_Store_Helper <op, asm, data_rc, VReg_64>; + def _V2_gfx90a : MIMG_Store_Helper_gfx90a <op, asm, data_rc, VReg_64>; def _V2_gfx10 : MIMG_Store_gfx10 <op, asm, data_rc, VReg_64>; def _V2_nsa_gfx10 : MIMG_Store_nsa_gfx10 <op, asm, data_rc, 2>; } @@ -407,6 +460,7 @@ multiclass MIMG_Store_Addr_Helper <mimgopc op, string asm, let VAddrDwords = 3 in { if op.HAS_BASE then { def _V3 : MIMG_Store_Helper <op, asm, data_rc, VReg_96>; + def _V3_gfx90a : MIMG_Store_Helper_gfx90a <op, asm, data_rc, VReg_96>; def _V3_gfx10 : MIMG_Store_gfx10 <op, asm, data_rc, VReg_96>; def _V3_nsa_gfx10 : MIMG_Store_nsa_gfx10 <op, asm, data_rc, 3>; } @@ -414,6 +468,7 @@ multiclass MIMG_Store_Addr_Helper <mimgopc op, string asm, let VAddrDwords = 4 in { if op.HAS_BASE then { def _V4 : MIMG_Store_Helper <op, asm, data_rc, VReg_128>; + def _V4_gfx90a : MIMG_Store_Helper_gfx90a <op, asm, data_rc, VReg_128>; def _V4_gfx10 : MIMG_Store_gfx10 <op, asm, data_rc, VReg_128>; def _V4_nsa_gfx10 : MIMG_Store_nsa_gfx10 <op, asm, data_rc, 4, !if(enableDisasm, "AMDGPU", "")>; @@ -450,9 +505,22 @@ class MIMG_Atomic_gfx6789_base <bits<8> op, string asm, RegisterClass data_rc, let AsmMatchConverter = "cvtMIMGAtomic"; let InOperandList = (ins data_rc:$vdata, addr_rc:$vaddr, SReg_256:$srsrc, - DMask:$dmask, UNorm:$unorm, GLC:$glc, SLC:$slc, + DMask:$dmask, UNorm:$unorm, SCCB_0:$sccb, GLC:$glc, SLC:$slc, R128A16:$r128, TFE:$tfe, LWE:$lwe, DA:$da); - let AsmString = asm#" $vdst, $vaddr, $srsrc$dmask$unorm$glc$slc$r128$tfe$lwe$da"; + let AsmString = asm#" $vdst, $vaddr, $srsrc$dmask$unorm$sccb$glc$slc$r128$tfe$lwe$da"; +} + +class MIMG_Atomic_gfx90a_base <bits<8> op, string asm, RegisterClass data_rc, + RegisterClass addr_rc, string dns=""> + : MIMG_gfx90a <op, (outs getLdStRegisterOperand<data_rc>.ret:$vdst), dns> { + let Constraints = "$vdst = $vdata"; + let AsmMatchConverter = "cvtMIMGAtomic"; + + let InOperandList = (ins getLdStRegisterOperand<data_rc>.ret:$vdata, + addr_rc:$vaddr, SReg_256:$srsrc, + DMask:$dmask, UNorm:$unorm, SCCB_0:$sccb, GLC:$glc, SLC:$slc, + R128A16:$r128, LWE:$lwe, DA:$da); + let AsmString = asm#" $vdst, $vaddr, $srsrc$dmask$unorm$sccb$glc$slc$r128$lwe$da"; } class MIMG_Atomic_si<mimgopc op, string asm, RegisterClass data_rc, @@ -465,10 +533,17 @@ class MIMG_Atomic_si<mimgopc op, string asm, RegisterClass data_rc, class MIMG_Atomic_vi<mimgopc op, string asm, RegisterClass data_rc, RegisterClass addr_rc, bit enableDasm = 0> : MIMG_Atomic_gfx6789_base<op.VI, asm, data_rc, addr_rc, !if(enableDasm, "GFX8", "")> { - let AssemblerPredicate = isGFX8GFX9; + let AssemblerPredicate = isGFX8GFX9NotGFX90A; let MIMGEncoding = MIMGEncGfx8; } +class MIMG_Atomic_gfx90a<mimgopc op, string asm, RegisterClass data_rc, + RegisterClass addr_rc, bit enableDasm = 0> + : MIMG_Atomic_gfx90a_base<op.VI, asm, data_rc, addr_rc, !if(enableDasm, "GFX90A", "")> { + let AssemblerPredicate = isGFX90APlus; + let MIMGEncoding = MIMGEncGfx90a; +} + class MIMG_Atomic_gfx10<mimgopc op, string opcode, RegisterClass DataRC, RegisterClass AddrRC, bit enableDisasm = 0> @@ -512,6 +587,7 @@ multiclass MIMG_Atomic_Addr_Helper_m <mimgopc op, string asm, } if op.HAS_VI then { def _V1_vi : MIMG_Atomic_vi <op, asm, data_rc, VGPR_32, enableDasm>; + def _V1_gfx90a : MIMG_Atomic_gfx90a <op, asm, data_rc, VGPR_32, enableDasm>; } if op.HAS_BASE then { def _V1_gfx10 : MIMG_Atomic_gfx10 <op, asm, data_rc, VGPR_32, enableDasm>; @@ -523,6 +599,7 @@ multiclass MIMG_Atomic_Addr_Helper_m <mimgopc op, string asm, } if op.HAS_VI then { def _V2_vi : MIMG_Atomic_vi <op, asm, data_rc, VReg_64, 0>; + def _V2_gfx90a : MIMG_Atomic_gfx90a <op, asm, data_rc, VReg_64, 0>; } if op.HAS_BASE then { def _V2_gfx10 : MIMG_Atomic_gfx10 <op, asm, data_rc, VReg_64, 0>; @@ -535,6 +612,7 @@ multiclass MIMG_Atomic_Addr_Helper_m <mimgopc op, string asm, } if op.HAS_VI then { def _V3_vi : MIMG_Atomic_vi <op, asm, data_rc, VReg_96, 0>; + def _V3_gfx90a : MIMG_Atomic_gfx90a <op, asm, data_rc, VReg_96, 0>; } if op.HAS_BASE then { def _V3_gfx10 : MIMG_Atomic_gfx10 <op, asm, data_rc, VReg_96, 0>; @@ -542,12 +620,13 @@ multiclass MIMG_Atomic_Addr_Helper_m <mimgopc op, string asm, } } let VAddrDwords = 4 in { - if op.HAS_VI then { - def _V4_vi : MIMG_Atomic_vi <op, asm, data_rc, VReg_128, 0>; - } if op.HAS_SI then { def _V4_si : MIMG_Atomic_si <op, asm, data_rc, VReg_128, 0>; } + if op.HAS_VI then { + def _V4_vi : MIMG_Atomic_vi <op, asm, data_rc, VReg_128, 0>; + def _V4_gfx90a : MIMG_Atomic_gfx90a <op, asm, data_rc, VReg_128, 0>; + } if op.HAS_BASE then { def _V4_gfx10 : MIMG_Atomic_gfx10 <op, asm, data_rc, VReg_128, 0>; def _V4_nsa_gfx10 : MIMG_Atomic_nsa_gfx10 <op, asm, data_rc, 4, enableDasm>; @@ -579,10 +658,21 @@ class MIMG_Sampler_Helper <mimgopc op, string asm, RegisterClass dst_rc, RegisterClass src_rc, string dns=""> : MIMG_gfx6789 <op.BASE, (outs dst_rc:$vdata), dns> { let InOperandList = !con((ins src_rc:$vaddr, SReg_256:$srsrc, SReg_128:$ssamp, - DMask:$dmask, UNorm:$unorm, GLC:$glc, SLC:$slc, + DMask:$dmask, UNorm:$unorm, SCCB_0:$sccb, GLC:$glc, SLC:$slc, R128A16:$r128, TFE:$tfe, LWE:$lwe, DA:$da), !if(BaseOpcode.HasD16, (ins D16:$d16), (ins))); - let AsmString = asm#" $vdata, $vaddr, $srsrc, $ssamp$dmask$unorm$glc$slc$r128$tfe$lwe$da" + let AsmString = asm#" $vdata, $vaddr, $srsrc, $ssamp$dmask$unorm$sccb$glc$slc$r128$tfe$lwe$da" + #!if(BaseOpcode.HasD16, "$d16", ""); +} + +class MIMG_Sampler_gfx90a<mimgopc op, string asm, RegisterClass dst_rc, + RegisterClass src_rc, string dns=""> + : MIMG_gfx90a<op.BASE, (outs getLdStRegisterOperand<dst_rc>.ret:$vdata), dns> { + let InOperandList = !con((ins src_rc:$vaddr, SReg_256:$srsrc, SReg_128:$ssamp, + DMask:$dmask, UNorm:$unorm, SCCB_0:$sccb, GLC:$glc, SLC:$slc, + R128A16:$r128, LWE:$lwe, DA:$da), + !if(BaseOpcode.HasD16, (ins D16:$d16), (ins))); + let AsmString = asm#" $vdata, $vaddr, $srsrc, $ssamp$dmask$unorm$sccb$glc$slc$r128$lwe$da" #!if(BaseOpcode.HasD16, "$d16", ""); } @@ -686,13 +776,18 @@ class MIMG_Sampler_AddrSizes<AMDGPUSampleVariant sample> { multiclass MIMG_Sampler_Src_Helper <mimgopc op, string asm, AMDGPUSampleVariant sample, RegisterClass dst_rc, - bit enableDisasm = 0> { + bit enableDisasm = 0, + bit ExtendedImageInst = 1> { foreach addr = MIMG_Sampler_AddrSizes<sample>.MachineInstrs in { let VAddrDwords = addr.NumWords in { if op.HAS_BASE then { def _V # addr.NumWords : MIMG_Sampler_Helper <op, asm, dst_rc, addr.RegClass, !if(!and(enableDisasm, addr.Disassemble), "AMDGPU", "")>; + foreach _ = BoolToList<!eq(ExtendedImageInst, 0)>.ret in + def _V # addr.NumWords # _gfx90a + : MIMG_Sampler_gfx90a <op, asm, dst_rc, addr.RegClass, + !if(!and(enableDisasm, addr.Disassemble), "GFX90A", "")>; def _V # addr.NumWords # _gfx10 : MIMG_Sampler_gfx10 <op, asm, dst_rc, addr.RegClass, !if(!and(enableDisasm, addr.Disassemble), "AMDGPU", "")>; @@ -721,7 +816,8 @@ class MIMG_Sampler_BaseOpcode<AMDGPUSampleVariant sample> multiclass MIMG_Sampler <mimgopc op, AMDGPUSampleVariant sample, bit wqm = 0, bit isG16 = 0, bit isGetLod = 0, - string asm = "image_sample"#sample.LowerCaseMod#!if(isG16, "_g16", "")> { + string asm = "image_sample"#sample.LowerCaseMod#!if(isG16, "_g16", ""), + bit ExtendedImageInst = !ne(sample.LowerCaseMod, "")> { def "" : MIMG_Sampler_BaseOpcode<sample> { let HasD16 = !not(isGetLod); let G16 = isG16; @@ -730,15 +826,15 @@ multiclass MIMG_Sampler <mimgopc op, AMDGPUSampleVariant sample, bit wqm = 0, let BaseOpcode = !cast<MIMGBaseOpcode>(NAME), WQM = wqm, mayLoad = !not(isGetLod) in { let VDataDwords = 1 in - defm _V1 : MIMG_Sampler_Src_Helper<op, asm, sample, VGPR_32, 1>; + defm _V1 : MIMG_Sampler_Src_Helper<op, asm, sample, VGPR_32, 1, ExtendedImageInst>; let VDataDwords = 2 in - defm _V2 : MIMG_Sampler_Src_Helper<op, asm, sample, VReg_64>; + defm _V2 : MIMG_Sampler_Src_Helper<op, asm, sample, VReg_64, 0, ExtendedImageInst>; let VDataDwords = 3 in - defm _V3 : MIMG_Sampler_Src_Helper<op, asm, sample, VReg_96>; + defm _V3 : MIMG_Sampler_Src_Helper<op, asm, sample, VReg_96, 0, ExtendedImageInst>; let VDataDwords = 4 in - defm _V4 : MIMG_Sampler_Src_Helper<op, asm, sample, VReg_128>; + defm _V4 : MIMG_Sampler_Src_Helper<op, asm, sample, VReg_128, 0, ExtendedImageInst>; let VDataDwords = 5 in - defm _V5 : MIMG_Sampler_Src_Helper<op, asm, sample, VReg_160>; + defm _V5 : MIMG_Sampler_Src_Helper<op, asm, sample, VReg_160, 0, ExtendedImageInst>; } } @@ -848,7 +944,9 @@ defm IMAGE_ATOMIC_DEC : MIMG_Atomic <mimgopc<0x1c>, "image_atomic_dec" defm IMAGE_ATOMIC_FCMPSWAP : MIMG_Atomic <mimgopc<0x1d, MIMG.NOP>, "image_atomic_fcmpswap", 0, 1>; defm IMAGE_ATOMIC_FMIN : MIMG_Atomic <mimgopc<0x1e, MIMG.NOP>, "image_atomic_fmin", 0, 1>; defm IMAGE_ATOMIC_FMAX : MIMG_Atomic <mimgopc<0x1f, MIMG.NOP>, "image_atomic_fmax", 0, 1>; + defm IMAGE_SAMPLE : MIMG_Sampler_WQM <mimgopc<0x20>, AMDGPUSample>; +let OtherPredicates = [HasExtendedImageInsts] in { defm IMAGE_SAMPLE_CL : MIMG_Sampler_WQM <mimgopc<0x21>, AMDGPUSample_cl>; defm IMAGE_SAMPLE_D : MIMG_Sampler <mimgopc<0x22>, AMDGPUSample_d>; defm IMAGE_SAMPLE_D_CL : MIMG_Sampler <mimgopc<0x23>, AMDGPUSample_d_cl>; @@ -932,12 +1030,12 @@ defm IMAGE_SAMPLE_CD_O_G16 : MIMG_Sampler <mimgopc<0xec>, AMDGPUSample_cd_o defm IMAGE_SAMPLE_CD_CL_O_G16 : MIMG_Sampler <mimgopc<0xed>, AMDGPUSample_cd_cl_o, 0, 1>; defm IMAGE_SAMPLE_C_CD_O_G16 : MIMG_Sampler <mimgopc<0xee>, AMDGPUSample_c_cd_o, 0, 1>; defm IMAGE_SAMPLE_C_CD_CL_O_G16 : MIMG_Sampler <mimgopc<0xef>, AMDGPUSample_c_cd_cl_o, 0, 1>; - -//def IMAGE_RSRC256 : MIMG_NoPattern_RSRC256 <"image_rsrc256", mimgopc<0x7e>>; -//def IMAGE_SAMPLER : MIMG_NoPattern_ <"image_sampler", mimgopc<0x7f>>; +} // End OtherPredicates = [HasExtendedImageInsts] +//def IMAGE_RSRC256 : MIMG_NoPattern_RSRC256 <"image_rsrc256", 0x0000007e>; +//def IMAGE_SAMPLER : MIMG_NoPattern_ <"image_sampler", 0x0000007f>; let SubtargetPredicate = HasGFX10_BEncoding in -defm IMAGE_MSAA_LOAD : MIMG_NoSampler <mimgopc<0x80>, "image_msaa_load", 1>; +defm IMAGE_MSAA_LOAD : MIMG_NoSampler <mimgopc<0x80>, "image_msaa_load", 1, 0, 0, 1>; defm IMAGE_BVH_INTERSECT_RAY : MIMG_IntersectRay<mimgopc<0xe6>, "image_bvh_intersect_ray", 11, 0>; defm IMAGE_BVH_INTERSECT_RAY_a16 : MIMG_IntersectRay<mimgopc<0xe6>, "image_bvh_intersect_ray", 8, 1>; diff --git a/llvm/lib/Target/AMDGPU/SIAddIMGInit.cpp b/llvm/lib/Target/AMDGPU/SIAddIMGInit.cpp index 3b753cb66ead..7d3a60a9b20c 100644 --- a/llvm/lib/Target/AMDGPU/SIAddIMGInit.cpp +++ b/llvm/lib/Target/AMDGPU/SIAddIMGInit.cpp @@ -77,7 +77,7 @@ bool SIAddIMGInit::runOnMachineFunction(MachineFunction &MF) { if (!TFE && !LWE) // intersect_ray continue; - unsigned TFEVal = TFE->getImm(); + unsigned TFEVal = TFE ? TFE->getImm() : 0; unsigned LWEVal = LWE->getImm(); unsigned D16Val = D16 ? D16->getImm() : 0; diff --git a/llvm/lib/Target/AMDGPU/SIDefines.h b/llvm/lib/Target/AMDGPU/SIDefines.h index 9b4e1048ab5c..5efea77b1bbd 100644 --- a/llvm/lib/Target/AMDGPU/SIDefines.h +++ b/llvm/lib/Target/AMDGPU/SIDefines.h @@ -142,6 +142,8 @@ namespace AMDGPU { OPERAND_REG_IMM_FP16, OPERAND_REG_IMM_V2FP16, OPERAND_REG_IMM_V2INT16, + OPERAND_REG_IMM_V2INT32, + OPERAND_REG_IMM_V2FP32, /// Operands with register or inline constant OPERAND_REG_INLINE_C_INT16, @@ -150,25 +152,30 @@ namespace AMDGPU { OPERAND_REG_INLINE_C_FP16, OPERAND_REG_INLINE_C_FP32, OPERAND_REG_INLINE_C_FP64, - OPERAND_REG_INLINE_C_V2FP16, OPERAND_REG_INLINE_C_V2INT16, + OPERAND_REG_INLINE_C_V2FP16, + OPERAND_REG_INLINE_C_V2INT32, + OPERAND_REG_INLINE_C_V2FP32, /// Operands with an AccVGPR register or inline constant OPERAND_REG_INLINE_AC_INT16, OPERAND_REG_INLINE_AC_INT32, OPERAND_REG_INLINE_AC_FP16, OPERAND_REG_INLINE_AC_FP32, - OPERAND_REG_INLINE_AC_V2FP16, + OPERAND_REG_INLINE_AC_FP64, OPERAND_REG_INLINE_AC_V2INT16, + OPERAND_REG_INLINE_AC_V2FP16, + OPERAND_REG_INLINE_AC_V2INT32, + OPERAND_REG_INLINE_AC_V2FP32, OPERAND_REG_IMM_FIRST = OPERAND_REG_IMM_INT32, - OPERAND_REG_IMM_LAST = OPERAND_REG_IMM_V2INT16, + OPERAND_REG_IMM_LAST = OPERAND_REG_IMM_V2FP32, OPERAND_REG_INLINE_C_FIRST = OPERAND_REG_INLINE_C_INT16, - OPERAND_REG_INLINE_C_LAST = OPERAND_REG_INLINE_AC_V2INT16, + OPERAND_REG_INLINE_C_LAST = OPERAND_REG_INLINE_AC_V2FP32, OPERAND_REG_INLINE_AC_FIRST = OPERAND_REG_INLINE_AC_INT16, - OPERAND_REG_INLINE_AC_LAST = OPERAND_REG_INLINE_AC_V2INT16, + OPERAND_REG_INLINE_AC_LAST = OPERAND_REG_INLINE_AC_V2FP32, OPERAND_SRC_FIRST = OPERAND_REG_IMM_INT32, OPERAND_SRC_LAST = OPERAND_REG_INLINE_C_LAST, @@ -680,6 +687,8 @@ enum DppCtrl : unsigned { BCAST31 = 0x143, DPP_UNUSED8_FIRST = 0x144, DPP_UNUSED8_LAST = 0x14F, + ROW_NEWBCAST_FIRST= 0x150, + ROW_NEWBCAST_LAST = 0x15F, ROW_SHARE_FIRST = 0x150, ROW_SHARE_LAST = 0x15F, ROW_XMASK_FIRST = 0x160, diff --git a/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp b/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp index d5fa9afded27..a0be4940acf9 100644 --- a/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp +++ b/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp @@ -97,6 +97,9 @@ public: std::pair<const MachineOperand *, int> isOMod(const MachineInstr &MI) const; bool tryFoldOMod(MachineInstr &MI); + bool tryFoldRegSeqence(MachineInstr &MI); + bool tryFoldLCSSAPhi(MachineInstr &MI); + bool tryFoldLoad(MachineInstr &MI); public: SIFoldOperands() : MachineFunctionPass(ID) { @@ -135,6 +138,8 @@ static unsigned macToMad(unsigned Opc) { return AMDGPU::V_FMA_F16_gfx9_e64; case AMDGPU::V_FMAC_LEGACY_F32_e64: return AMDGPU::V_FMA_LEGACY_F32_e64; + case AMDGPU::V_FMAC_F64_e64: + return AMDGPU::V_FMA_F64_e64; } return AMDGPU::INSTRUCTION_LIST_END; } @@ -531,8 +536,10 @@ static bool tryToFoldACImm(const SIInstrInfo *TII, return false; uint8_t OpTy = OpInfo[UseOpIdx].OperandType; - if (OpTy < AMDGPU::OPERAND_REG_INLINE_AC_FIRST || - OpTy > AMDGPU::OPERAND_REG_INLINE_AC_LAST) + if ((OpTy < AMDGPU::OPERAND_REG_INLINE_AC_FIRST || + OpTy > AMDGPU::OPERAND_REG_INLINE_AC_LAST) && + (OpTy < AMDGPU::OPERAND_REG_INLINE_C_FIRST || + OpTy > AMDGPU::OPERAND_REG_INLINE_C_LAST)) return false; if (OpToFold.isImm() && TII->isInlineConstant(OpToFold, OpTy) && @@ -554,6 +561,19 @@ static bool tryToFoldACImm(const SIInstrInfo *TII, return false; MachineRegisterInfo &MRI = UseMI->getParent()->getParent()->getRegInfo(); + + // Maybe it is just a COPY of an immediate itself. + MachineInstr *Def = MRI.getUniqueVRegDef(UseReg); + MachineOperand &UseOp = UseMI->getOperand(UseOpIdx); + if (!UseOp.getSubReg() && Def && TII->isFoldableCopy(*Def)) { + MachineOperand &DefOp = Def->getOperand(1); + if (DefOp.isImm() && TII->isInlineConstant(DefOp, OpTy) && + TII->isOperandLegal(*UseMI, UseOpIdx, &DefOp)) { + UseMI->getOperand(UseOpIdx).ChangeToImmediate(DefOp.getImm()); + return true; + } + } + SmallVector<std::pair<MachineOperand*, unsigned>, 32> Defs; if (!getRegSeqInit(Defs, UseReg, OpTy, TII, MRI)) return false; @@ -825,6 +845,10 @@ void SIFoldOperands::foldOperand( else if (TRI->isVGPR(*MRI, UseMI->getOperand(0).getReg()) && TRI->isAGPR(*MRI, UseMI->getOperand(1).getReg())) UseMI->setDesc(TII->get(AMDGPU::V_ACCVGPR_READ_B32_e64)); + else if (ST->hasGFX90AInsts() && + TRI->isAGPR(*MRI, UseMI->getOperand(0).getReg()) && + TRI->isAGPR(*MRI, UseMI->getOperand(1).getReg())) + UseMI->setDesc(TII->get(AMDGPU::V_ACCVGPR_MOV_B32)); return; } @@ -1502,6 +1526,194 @@ bool SIFoldOperands::tryFoldOMod(MachineInstr &MI) { return true; } +// Try to fold a reg_sequence with vgpr output and agpr inputs into an +// instruction which can take an agpr. So far that means a store. +bool SIFoldOperands::tryFoldRegSeqence(MachineInstr &MI) { + assert(MI.isRegSequence()); + auto Reg = MI.getOperand(0).getReg(); + + if (!ST->hasGFX90AInsts() || !TRI->isVGPR(*MRI, Reg) || + !MRI->hasOneNonDBGUse(Reg)) + return false; + + SmallVector<std::pair<MachineOperand*, unsigned>, 32> Defs; + if (!getRegSeqInit(Defs, Reg, MCOI::OPERAND_REGISTER, TII, *MRI)) + return false; + + for (auto &Def : Defs) { + const auto *Op = Def.first; + if (!Op->isReg()) + return false; + if (TRI->isAGPR(*MRI, Op->getReg())) + continue; + // Maybe this is a COPY from AREG + const MachineInstr *SubDef = MRI->getUniqueVRegDef(Op->getReg()); + if (!SubDef || !SubDef->isCopy() || SubDef->getOperand(1).getSubReg()) + return false; + if (!TRI->isAGPR(*MRI, SubDef->getOperand(1).getReg())) + return false; + } + + MachineOperand *Op = &*MRI->use_nodbg_begin(Reg); + MachineInstr *UseMI = Op->getParent(); + while (UseMI->isCopy() && !Op->getSubReg()) { + Reg = UseMI->getOperand(0).getReg(); + if (!TRI->isVGPR(*MRI, Reg) || !MRI->hasOneNonDBGUse(Reg)) + return false; + Op = &*MRI->use_nodbg_begin(Reg); + UseMI = Op->getParent(); + } + + if (Op->getSubReg()) + return false; + + unsigned OpIdx = Op - &UseMI->getOperand(0); + const MCInstrDesc &InstDesc = UseMI->getDesc(); + const MCOperandInfo &OpInfo = InstDesc.OpInfo[OpIdx]; + switch (OpInfo.RegClass) { + case AMDGPU::AV_32RegClassID: LLVM_FALLTHROUGH; + case AMDGPU::AV_64RegClassID: LLVM_FALLTHROUGH; + case AMDGPU::AV_96RegClassID: LLVM_FALLTHROUGH; + case AMDGPU::AV_128RegClassID: LLVM_FALLTHROUGH; + case AMDGPU::AV_160RegClassID: + break; + default: + return false; + } + + const auto *NewDstRC = TRI->getEquivalentAGPRClass(MRI->getRegClass(Reg)); + auto Dst = MRI->createVirtualRegister(NewDstRC); + auto RS = BuildMI(*MI.getParent(), MI, MI.getDebugLoc(), + TII->get(AMDGPU::REG_SEQUENCE), Dst); + + for (unsigned I = 0; I < Defs.size(); ++I) { + MachineOperand *Def = Defs[I].first; + Def->setIsKill(false); + if (TRI->isAGPR(*MRI, Def->getReg())) { + RS.add(*Def); + } else { // This is a copy + MachineInstr *SubDef = MRI->getUniqueVRegDef(Def->getReg()); + SubDef->getOperand(1).setIsKill(false); + RS.addReg(SubDef->getOperand(1).getReg(), 0, Def->getSubReg()); + } + RS.addImm(Defs[I].second); + } + + Op->setReg(Dst); + if (!TII->isOperandLegal(*UseMI, OpIdx, Op)) { + Op->setReg(Reg); + RS->eraseFromParent(); + return false; + } + + LLVM_DEBUG(dbgs() << "Folded " << *RS << " into " << *UseMI << '\n'); + + return true; +} + +// Try to hoist an AGPR to VGPR copy out of the loop across a LCSSA PHI. +// This should allow folding of an AGPR into a consumer which may support it. +// I.e.: +// +// loop: // loop: +// %1:vreg = COPY %0:areg // exit: +// exit: => // %1:areg = PHI %0:areg, %loop +// %2:vreg = PHI %1:vreg, %loop // %2:vreg = COPY %1:areg +bool SIFoldOperands::tryFoldLCSSAPhi(MachineInstr &PHI) { + assert(PHI.isPHI()); + + if (PHI.getNumExplicitOperands() != 3) // Single input LCSSA PHI + return false; + + Register PhiIn = PHI.getOperand(1).getReg(); + Register PhiOut = PHI.getOperand(0).getReg(); + if (PHI.getOperand(1).getSubReg() || + !TRI->isVGPR(*MRI, PhiIn) || !TRI->isVGPR(*MRI, PhiOut)) + return false; + + // A single use should not matter for correctness, but if it has another use + // inside the loop we may perform copy twice in a worst case. + if (!MRI->hasOneNonDBGUse(PhiIn)) + return false; + + MachineInstr *Copy = MRI->getUniqueVRegDef(PhiIn); + if (!Copy || !Copy->isCopy()) + return false; + + Register CopyIn = Copy->getOperand(1).getReg(); + if (!TRI->isAGPR(*MRI, CopyIn) || Copy->getOperand(1).getSubReg()) + return false; + + const TargetRegisterClass *ARC = MRI->getRegClass(CopyIn); + Register NewReg = MRI->createVirtualRegister(ARC); + PHI.getOperand(1).setReg(CopyIn); + PHI.getOperand(0).setReg(NewReg); + + MachineBasicBlock *MBB = PHI.getParent(); + BuildMI(*MBB, MBB->getFirstNonPHI(), Copy->getDebugLoc(), + TII->get(AMDGPU::COPY), PhiOut) + .addReg(NewReg, RegState::Kill); + Copy->eraseFromParent(); // We know this copy had a single use. + + LLVM_DEBUG(dbgs() << "Folded " << PHI << '\n'); + + return true; +} + +// Attempt to convert VGPR load to an AGPR load. +bool SIFoldOperands::tryFoldLoad(MachineInstr &MI) { + assert(MI.mayLoad()); + if (!ST->hasGFX90AInsts() || !MI.getNumOperands()) + return false; + + MachineOperand &Def = MI.getOperand(0); + if (!Def.isDef()) + return false; + + Register DefReg = Def.getReg(); + + if (DefReg.isPhysical() || !TRI->isVGPR(*MRI, DefReg)) + return false; + + SmallVector<const MachineInstr*, 8> Users; + SmallVector<Register, 8> MoveRegs; + for (const MachineInstr &I : MRI->use_nodbg_instructions(DefReg)) { + Users.push_back(&I); + } + if (Users.empty()) + return false; + + // Check that all uses a copy to an agpr or a reg_sequence producing an agpr. + while (!Users.empty()) { + const MachineInstr *I = Users.pop_back_val(); + if (!I->isCopy() && !I->isRegSequence()) + return false; + Register DstReg = I->getOperand(0).getReg(); + if (TRI->isAGPR(*MRI, DstReg)) + continue; + MoveRegs.push_back(DstReg); + for (const MachineInstr &U : MRI->use_nodbg_instructions(DstReg)) { + Users.push_back(&U); + } + } + + const TargetRegisterClass *RC = MRI->getRegClass(DefReg); + MRI->setRegClass(DefReg, TRI->getEquivalentAGPRClass(RC)); + if (!TII->isOperandLegal(MI, 0, &Def)) { + MRI->setRegClass(DefReg, RC); + return false; + } + + while (!MoveRegs.empty()) { + Register Reg = MoveRegs.pop_back_val(); + MRI->setRegClass(Reg, TRI->getEquivalentAGPRClass(MRI->getRegClass(Reg))); + } + + LLVM_DEBUG(dbgs() << "Folded " << MI << '\n'); + + return true; +} + bool SIFoldOperands::runOnMachineFunction(MachineFunction &MF) { if (skipFunction(MF.getFunction())) return false; @@ -1529,6 +1741,15 @@ bool SIFoldOperands::runOnMachineFunction(MachineFunction &MF) { tryFoldInst(TII, &MI); + if (MI.isRegSequence() && tryFoldRegSeqence(MI)) + continue; + + if (MI.isPHI() && tryFoldLCSSAPhi(MI)) + continue; + + if (MI.mayLoad() && tryFoldLoad(MI)) + continue; + if (!TII->isFoldableCopy(MI)) { // Saw an unknown clobber of m0, so we no longer know what it is. if (CurrentKnownM0Val && MI.modifiesRegister(AMDGPU::M0, TRI)) diff --git a/llvm/lib/Target/AMDGPU/SIFormMemoryClauses.cpp b/llvm/lib/Target/AMDGPU/SIFormMemoryClauses.cpp index b0ec5ac4a5b9..d874aa143f27 100644 --- a/llvm/lib/Target/AMDGPU/SIFormMemoryClauses.cpp +++ b/llvm/lib/Target/AMDGPU/SIFormMemoryClauses.cpp @@ -188,11 +188,24 @@ void SIFormMemoryClauses::forAllLanes(Register Reg, LaneBitmask LaneMask, return MaskA.getHighestLane() > MaskB.getHighestLane(); }); + MCRegister RepReg; + for (MCRegister R : *MRI->getRegClass(Reg)) { + if (!MRI->isReserved(R)) { + RepReg = R; + break; + } + } + if (!RepReg) + llvm_unreachable("Failed to find required allocatable register"); + for (unsigned Idx : CoveringSubregs) { LaneBitmask SubRegMask = TRI->getSubRegIndexLaneMask(Idx); if ((SubRegMask & ~LaneMask).any() || (SubRegMask & LaneMask).none()) continue; + if (MRI->isReserved(TRI->getSubReg(RepReg, Idx))) + continue; + Func(Idx); LaneMask &= ~SubRegMask; if (LaneMask.none()) @@ -261,7 +274,7 @@ bool SIFormMemoryClauses::checkPressure(const MachineInstr &MI, // tracking does not account for the alignment requirements for SGPRs, or the // fragmentation of registers the allocator will need to satisfy. if (Occupancy >= MFI->getMinAllowedOccupancy() && - MaxPressure.getVGPRNum() <= MaxVGPRs / 2 && + MaxPressure.getVGPRNum(ST->hasGFX90AInsts()) <= MaxVGPRs / 2 && MaxPressure.getSGPRNum() <= MaxSGPRs / 2) { LastRecordedOccupancy = Occupancy; return true; diff --git a/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp b/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp index 6548dde08065..8d5f5145e26b 100644 --- a/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp +++ b/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp @@ -138,6 +138,7 @@ static void buildPrologSpill(const GCNSubtarget &ST, LivePhysRegs &LiveRegs, .addImm(0) // glc .addImm(0) // slc .addImm(0) // dlc + .addImm(0) // scc .addMemOperand(MMO); return; } @@ -152,6 +153,7 @@ static void buildPrologSpill(const GCNSubtarget &ST, LivePhysRegs &LiveRegs, .addImm(0) // tfe .addImm(0) // dlc .addImm(0) // swz + .addImm(0) // scc .addMemOperand(MMO); return; } @@ -181,6 +183,7 @@ static void buildPrologSpill(const GCNSubtarget &ST, LivePhysRegs &LiveRegs, .addImm(0) // glc .addImm(0) // slc .addImm(0) // dlc + .addImm(0) // scc .addMemOperand(MMO); if (!HasOffsetReg) { @@ -207,6 +210,7 @@ static void buildPrologSpill(const GCNSubtarget &ST, LivePhysRegs &LiveRegs, .addImm(0) // tfe .addImm(0) // dlc .addImm(0) // swz + .addImm(0) // scc .addMemOperand(MMO); } else { // No free register, use stack pointer and restore afterwards. @@ -224,6 +228,7 @@ static void buildPrologSpill(const GCNSubtarget &ST, LivePhysRegs &LiveRegs, .addImm(0) // tfe .addImm(0) // dlc .addImm(0) // swz + .addImm(0) // scc .addMemOperand(MMO); BuildMI(MBB, I, DebugLoc(), TII->get(AMDGPU::S_SUB_U32), SPReg) @@ -257,6 +262,7 @@ static void buildEpilogReload(const GCNSubtarget &ST, LivePhysRegs &LiveRegs, .addImm(0) // glc .addImm(0) // slc .addImm(0) // dlc + .addImm(0) // scc .addMemOperand(MMO); return; } @@ -275,6 +281,7 @@ static void buildEpilogReload(const GCNSubtarget &ST, LivePhysRegs &LiveRegs, .addImm(0) // glc .addImm(0) // slc .addImm(0) // dlc + .addImm(0) // scc .addMemOperand(MMO); return; } @@ -290,6 +297,7 @@ static void buildEpilogReload(const GCNSubtarget &ST, LivePhysRegs &LiveRegs, .addImm(0) // tfe .addImm(0) // dlc .addImm(0) // swz + .addImm(0) // scc .addMemOperand(MMO); return; } @@ -313,6 +321,7 @@ static void buildEpilogReload(const GCNSubtarget &ST, LivePhysRegs &LiveRegs, .addImm(0) // tfe .addImm(0) // dlc .addImm(0) // swz + .addImm(0) // scc .addMemOperand(MMO); } @@ -1311,7 +1320,13 @@ void SIFrameLowering::determineCalleeSaves(MachineFunction &MF, const SIRegisterInfo *TRI = ST.getRegisterInfo(); // Ignore the SGPRs the default implementation found. - SavedVGPRs.clearBitsNotInMask(TRI->getAllVGPRRegMask()); + SavedVGPRs.clearBitsNotInMask(TRI->getAllVectorRegMask()); + + // Do not save AGPRs prior to GFX90A because there was no easy way to do so. + // In gfx908 there was do AGPR loads and stores and thus spilling also + // require a temporary VGPR. + if (!ST.hasGFX90AInsts()) + SavedVGPRs.clearBitsInMask(TRI->getAllAGPRRegMask()); // hasFP only knows about stack objects that already exist. We're now // determining the stack slots that will be created, so we have to predict @@ -1366,7 +1381,7 @@ void SIFrameLowering::determineCalleeSavesSGPR(MachineFunction &MF, SavedRegs.reset(MFI->getStackPtrOffsetReg()); const BitVector AllSavedRegs = SavedRegs; - SavedRegs.clearBitsInMask(TRI->getAllVGPRRegMask()); + SavedRegs.clearBitsInMask(TRI->getAllVectorRegMask()); // If clearing VGPRs changed the mask, we will have some CSR VGPR spills. const bool HaveAnyCSRVGPR = SavedRegs != AllSavedRegs; diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp index ca2b50509bcd..c36ed0902d2f 100644 --- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp +++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp @@ -718,6 +718,19 @@ SITargetLowering::SITargetLowering(const TargetMachine &TM, setOperationAction(ISD::FEXP, MVT::v2f16, Custom); setOperationAction(ISD::SELECT, MVT::v4i16, Custom); setOperationAction(ISD::SELECT, MVT::v4f16, Custom); + + if (Subtarget->hasPackedFP32Ops()) { + setOperationAction(ISD::FADD, MVT::v2f32, Legal); + setOperationAction(ISD::FMUL, MVT::v2f32, Legal); + setOperationAction(ISD::FMA, MVT::v2f32, Legal); + setOperationAction(ISD::FNEG, MVT::v2f32, Legal); + + for (MVT VT : { MVT::v4f32, MVT::v8f32, MVT::v16f32, MVT::v32f32 }) { + setOperationAction(ISD::FADD, VT, Custom); + setOperationAction(ISD::FMUL, VT, Custom); + setOperationAction(ISD::FMA, VT, Custom); + } + } } setOperationAction(ISD::FNEG, MVT::v4f16, Custom); @@ -1128,17 +1141,6 @@ bool SITargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info, MachineMemOperand::MOVolatile; return true; } - case Intrinsic::amdgcn_global_atomic_fadd: { - Info.opc = ISD::INTRINSIC_W_CHAIN; - Info.memVT = MVT::getVT(CI.getType()); - Info.ptrVal = CI.getOperand(0); - Info.align.reset(); - Info.flags = MachineMemOperand::MOLoad | - MachineMemOperand::MOStore | - MachineMemOperand::MODereferenceable | - MachineMemOperand::MOVolatile; - return true; - } case Intrinsic::amdgcn_image_bvh_intersect_ray: { SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>(); Info.opc = ISD::INTRINSIC_W_CHAIN; @@ -1150,6 +1152,22 @@ bool SITargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info, MachineMemOperand::MODereferenceable; return true; } + case Intrinsic::amdgcn_global_atomic_fadd: + case Intrinsic::amdgcn_global_atomic_fmin: + case Intrinsic::amdgcn_global_atomic_fmax: + case Intrinsic::amdgcn_flat_atomic_fadd: + case Intrinsic::amdgcn_flat_atomic_fmin: + case Intrinsic::amdgcn_flat_atomic_fmax: { + Info.opc = ISD::INTRINSIC_W_CHAIN; + Info.memVT = MVT::getVT(CI.getType()); + Info.ptrVal = CI.getOperand(0); + Info.align.reset(); + Info.flags = MachineMemOperand::MOLoad | + MachineMemOperand::MOStore | + MachineMemOperand::MODereferenceable | + MachineMemOperand::MOVolatile; + return true; + } case Intrinsic::amdgcn_ds_gws_init: case Intrinsic::amdgcn_ds_gws_barrier: case Intrinsic::amdgcn_ds_gws_sema_v: @@ -1191,6 +1209,9 @@ bool SITargetLowering::getAddrModeArguments(IntrinsicInst *II, case Intrinsic::amdgcn_ds_fmin: case Intrinsic::amdgcn_ds_fmax: case Intrinsic::amdgcn_global_atomic_fadd: + case Intrinsic::amdgcn_flat_atomic_fadd: + case Intrinsic::amdgcn_flat_atomic_fmin: + case Intrinsic::amdgcn_flat_atomic_fmax: case Intrinsic::amdgcn_global_atomic_csub: { Value *Ptr = II->getArgOperand(0); AccessTy = II->getType(); @@ -1799,23 +1820,37 @@ void SITargetLowering::allocateSpecialEntryInputVGPRs(CCState &CCInfo, MRI.setType(MF.addLiveIn(Reg, &AMDGPU::VGPR_32RegClass), S32); CCInfo.AllocateReg(Reg); - Info.setWorkItemIDX(ArgDescriptor::createRegister(Reg)); + unsigned Mask = (Subtarget->hasPackedTID() && + Info.hasWorkItemIDY()) ? 0x3ff : ~0u; + Info.setWorkItemIDX(ArgDescriptor::createRegister(Reg, Mask)); } if (Info.hasWorkItemIDY()) { - Register Reg = AMDGPU::VGPR1; - MRI.setType(MF.addLiveIn(Reg, &AMDGPU::VGPR_32RegClass), S32); + assert(Info.hasWorkItemIDX()); + if (Subtarget->hasPackedTID()) { + Info.setWorkItemIDY(ArgDescriptor::createRegister(AMDGPU::VGPR0, + 0x3ff << 10)); + } else { + unsigned Reg = AMDGPU::VGPR1; + MRI.setType(MF.addLiveIn(Reg, &AMDGPU::VGPR_32RegClass), S32); - CCInfo.AllocateReg(Reg); - Info.setWorkItemIDY(ArgDescriptor::createRegister(Reg)); + CCInfo.AllocateReg(Reg); + Info.setWorkItemIDY(ArgDescriptor::createRegister(Reg)); + } } if (Info.hasWorkItemIDZ()) { - Register Reg = AMDGPU::VGPR2; - MRI.setType(MF.addLiveIn(Reg, &AMDGPU::VGPR_32RegClass), S32); + assert(Info.hasWorkItemIDX() && Info.hasWorkItemIDY()); + if (Subtarget->hasPackedTID()) { + Info.setWorkItemIDZ(ArgDescriptor::createRegister(AMDGPU::VGPR0, + 0x3ff << 20)); + } else { + unsigned Reg = AMDGPU::VGPR2; + MRI.setType(MF.addLiveIn(Reg, &AMDGPU::VGPR_32RegClass), S32); - CCInfo.AllocateReg(Reg); - Info.setWorkItemIDZ(ArgDescriptor::createRegister(Reg)); + CCInfo.AllocateReg(Reg); + Info.setWorkItemIDZ(ArgDescriptor::createRegister(Reg)); + } } } @@ -4380,7 +4415,8 @@ SDValue SITargetLowering::splitBinaryVectorOp(SDValue Op, SelectionDAG &DAG) const { unsigned Opc = Op.getOpcode(); EVT VT = Op.getValueType(); - assert(VT == MVT::v4i16 || VT == MVT::v4f16); + assert(VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4f32 || + VT == MVT::v8f32 || VT == MVT::v16f32 || VT == MVT::v32f32); SDValue Lo0, Hi0; std::tie(Lo0, Hi0) = DAG.SplitVectorOperand(Op.getNode(), 0); @@ -4401,7 +4437,8 @@ SDValue SITargetLowering::splitTernaryVectorOp(SDValue Op, SelectionDAG &DAG) const { unsigned Opc = Op.getOpcode(); EVT VT = Op.getValueType(); - assert(VT == MVT::v4i16 || VT == MVT::v4f16); + assert(VT == MVT::v4i16 || VT == MVT::v4f16 || VT == MVT::v4f32 || + VT == MVT::v8f32 || VT == MVT::v16f32 || VT == MVT::v32f32); SDValue Lo0, Hi0; std::tie(Lo0, Hi0) = DAG.SplitVectorOperand(Op.getNode(), 0); @@ -6168,6 +6205,8 @@ SDValue SITargetLowering::lowerImage(SDValue Op, if (IsGFX10Plus) Ops.push_back(DAG.getTargetConstant(DimInfo->Encoding, DL, MVT::i32)); Ops.push_back(Unorm); + if (!IsGFX10Plus) + Ops.push_back(DAG.getTargetConstant(0, SDLoc(), MVT::i1)); if (IsGFX10Plus) Ops.push_back(DLC); Ops.push_back(GLC); @@ -6176,8 +6215,12 @@ SDValue SITargetLowering::lowerImage(SDValue Op, ST->hasFeature(AMDGPU::FeatureR128A16) ? True : False); if (IsGFX10Plus) Ops.push_back(IsA16 ? True : False); - Ops.push_back(TFE); - Ops.push_back(LWE); + if (!Subtarget->hasGFX90AInsts()) { + Ops.push_back(TFE); //tfe + } else if (cast<ConstantSDNode>(TFE)->getZExtValue()) { + report_fatal_error("TFE is not supported on this GPU"); + } + Ops.push_back(LWE); // lwe if (!IsGFX10Plus) Ops.push_back(DimInfo->DA ? True : False); if (BaseOpcode->HasD16) @@ -6195,7 +6238,15 @@ SDValue SITargetLowering::lowerImage(SDValue Op, : AMDGPU::MIMGEncGfx10Default, NumVDataDwords, NumVAddrDwords); } else { - if (Subtarget->getGeneration() >= AMDGPUSubtarget::VOLCANIC_ISLANDS) + if (Subtarget->hasGFX90AInsts()) { + Opcode = AMDGPU::getMIMGOpcode(IntrOpcode, AMDGPU::MIMGEncGfx90a, + NumVDataDwords, NumVAddrDwords); + if (Opcode == -1) + report_fatal_error( + "requested image instruction is not supported on this GPU"); + } + if (Opcode == -1 && + Subtarget->getGeneration() >= AMDGPUSubtarget::VOLCANIC_ISLANDS) Opcode = AMDGPU::getMIMGOpcode(IntrOpcode, AMDGPU::MIMGEncGfx8, NumVDataDwords, NumVAddrDwords); if (Opcode == -1) @@ -7062,7 +7113,7 @@ SDValue SITargetLowering::LowerINTRINSIC_W_CHAIN(SDValue Op, Opcode = AMDGPUISD::BUFFER_ATOMIC_XOR; break; case Intrinsic::amdgcn_buffer_atomic_fadd: - if (!Op.getValue(0).use_empty()) { + if (!Op.getValue(0).use_empty() && !Subtarget->hasGFX90AInsts()) { DiagnosticInfoUnsupported NoFpRet(DAG.getMachineFunction().getFunction(), "return versions of fp atomics not supported", @@ -7083,6 +7134,14 @@ SDValue SITargetLowering::LowerINTRINSIC_W_CHAIN(SDValue Op, return lowerRawBufferAtomicIntrin(Op, DAG, AMDGPUISD::BUFFER_ATOMIC_FADD); case Intrinsic::amdgcn_struct_buffer_atomic_fadd: return lowerStructBufferAtomicIntrin(Op, DAG, AMDGPUISD::BUFFER_ATOMIC_FADD); + case Intrinsic::amdgcn_raw_buffer_atomic_fmin: + return lowerRawBufferAtomicIntrin(Op, DAG, AMDGPUISD::BUFFER_ATOMIC_FMIN); + case Intrinsic::amdgcn_struct_buffer_atomic_fmin: + return lowerStructBufferAtomicIntrin(Op, DAG, AMDGPUISD::BUFFER_ATOMIC_FMIN); + case Intrinsic::amdgcn_raw_buffer_atomic_fmax: + return lowerRawBufferAtomicIntrin(Op, DAG, AMDGPUISD::BUFFER_ATOMIC_FMAX); + case Intrinsic::amdgcn_struct_buffer_atomic_fmax: + return lowerStructBufferAtomicIntrin(Op, DAG, AMDGPUISD::BUFFER_ATOMIC_FMAX); case Intrinsic::amdgcn_raw_buffer_atomic_swap: return lowerRawBufferAtomicIntrin(Op, DAG, AMDGPUISD::BUFFER_ATOMIC_SWAP); case Intrinsic::amdgcn_raw_buffer_atomic_add: @@ -7208,27 +7267,6 @@ SDValue SITargetLowering::LowerINTRINSIC_W_CHAIN(SDValue Op, return DAG.getMemIntrinsicNode(AMDGPUISD::BUFFER_ATOMIC_CMPSWAP, DL, Op->getVTList(), Ops, VT, M->getMemOperand()); } - case Intrinsic::amdgcn_global_atomic_fadd: { - if (!Op.getValue(0).use_empty()) { - DiagnosticInfoUnsupported - NoFpRet(DAG.getMachineFunction().getFunction(), - "return versions of fp atomics not supported", - DL.getDebugLoc(), DS_Error); - DAG.getContext()->diagnose(NoFpRet); - return SDValue(); - } - MemSDNode *M = cast<MemSDNode>(Op); - SDValue Ops[] = { - M->getOperand(0), // Chain - M->getOperand(2), // Ptr - M->getOperand(3) // Value - }; - - EVT VT = Op.getOperand(3).getValueType(); - return DAG.getAtomic(ISD::ATOMIC_LOAD_FADD, DL, VT, - DAG.getVTList(VT, MVT::Other), Ops, - M->getMemOperand()); - } case Intrinsic::amdgcn_image_bvh_intersect_ray: { SDLoc DL(Op); MemSDNode *M = cast<MemSDNode>(Op); @@ -7299,7 +7337,55 @@ SDValue SITargetLowering::LowerINTRINSIC_W_CHAIN(SDValue Op, DAG.setNodeMemRefs(NewNode, {MemRef}); return SDValue(NewNode, 0); } + case Intrinsic::amdgcn_global_atomic_fadd: + if (!Op.getValue(0).use_empty() && !Subtarget->hasGFX90AInsts()) { + DiagnosticInfoUnsupported + NoFpRet(DAG.getMachineFunction().getFunction(), + "return versions of fp atomics not supported", + DL.getDebugLoc(), DS_Error); + DAG.getContext()->diagnose(NoFpRet); + return SDValue(); + } + LLVM_FALLTHROUGH; + case Intrinsic::amdgcn_global_atomic_fmin: + case Intrinsic::amdgcn_global_atomic_fmax: + case Intrinsic::amdgcn_flat_atomic_fadd: + case Intrinsic::amdgcn_flat_atomic_fmin: + case Intrinsic::amdgcn_flat_atomic_fmax: { + MemSDNode *M = cast<MemSDNode>(Op); + SDValue Ops[] = { + M->getOperand(0), // Chain + M->getOperand(2), // Ptr + M->getOperand(3) // Value + }; + unsigned Opcode = 0; + switch (IntrID) { + case Intrinsic::amdgcn_global_atomic_fadd: + case Intrinsic::amdgcn_flat_atomic_fadd: { + EVT VT = Op.getOperand(3).getValueType(); + return DAG.getAtomic(ISD::ATOMIC_LOAD_FADD, DL, VT, + DAG.getVTList(VT, MVT::Other), Ops, + M->getMemOperand()); + } + case Intrinsic::amdgcn_global_atomic_fmin: + case Intrinsic::amdgcn_flat_atomic_fmin: { + Opcode = AMDGPUISD::ATOMIC_LOAD_FMIN; + break; + } + case Intrinsic::amdgcn_global_atomic_fmax: + case Intrinsic::amdgcn_flat_atomic_fmax: { + Opcode = AMDGPUISD::ATOMIC_LOAD_FMAX; + break; + } + default: + llvm_unreachable("unhandled atomic opcode"); + } + return DAG.getMemIntrinsicNode(Opcode, SDLoc(Op), + M->getVTList(), Ops, M->getMemoryVT(), + M->getMemOperand()); + } default: + if (const AMDGPU::ImageDimIntrinsicInfo *ImageDimIntr = AMDGPU::getImageDimIntrinsicInfo(IntrID)) return lowerImage(Op, ImageDimIntr, DAG, true); @@ -10813,7 +10899,7 @@ SDNode *SITargetLowering::adjustWritemask(MachineSDNode *&Node, unsigned NewDmask = 0; unsigned TFEIdx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::tfe) - 1; unsigned LWEIdx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::lwe) - 1; - bool UsesTFC = (Node->getConstantOperandVal(TFEIdx) || + bool UsesTFC = ((int(TFEIdx) >= 0 && Node->getConstantOperandVal(TFEIdx)) || Node->getConstantOperandVal(LWEIdx)) ? 1 : 0; unsigned TFCLane = 0; bool HasChain = Node->getNumValues() > 1; @@ -11768,26 +11854,39 @@ SITargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *RMW) const { if (Ty->isHalfTy()) return AtomicExpansionKind::None; - if (!Ty->isFloatTy()) + if (!Ty->isFloatTy() && (!Subtarget->hasGFX90AInsts() || !Ty->isDoubleTy())) return AtomicExpansionKind::CmpXChg; // TODO: Do have these for flat. Older targets also had them for buffers. unsigned AS = RMW->getPointerAddressSpace(); - if (AS == AMDGPUAS::GLOBAL_ADDRESS && Subtarget->hasAtomicFaddInsts()) { + if ((AS == AMDGPUAS::GLOBAL_ADDRESS || AS == AMDGPUAS::FLAT_ADDRESS) && + Subtarget->hasAtomicFaddInsts()) { if (!fpModeMatchesGlobalFPAtomicMode(RMW) || RMW->getFunction()->getFnAttribute("amdgpu-unsafe-fp-atomics") .getValueAsString() != "true") return AtomicExpansionKind::CmpXChg; + if (Subtarget->hasGFX90AInsts()) + return (Ty->isFloatTy() && AS == AMDGPUAS::FLAT_ADDRESS) ? + AtomicExpansionKind::CmpXChg : AtomicExpansionKind::None; + + if (!Subtarget->hasGFX90AInsts() && AS != AMDGPUAS::GLOBAL_ADDRESS) + return AtomicExpansionKind::CmpXChg; + return RMW->use_empty() ? AtomicExpansionKind::None : AtomicExpansionKind::CmpXChg; } // DS FP atomics do repect the denormal mode, but the rounding mode is fixed // to round-to-nearest-even. - return (AS == AMDGPUAS::LOCAL_ADDRESS && Subtarget->hasLDSFPAtomics()) ? - AtomicExpansionKind::None : AtomicExpansionKind::CmpXChg; + // The only exception is DS_ADD_F64 which never flushes regardless of mode. + if (AS == AMDGPUAS::LOCAL_ADDRESS && Subtarget->hasLDSFPAtomics()) { + return (Ty->isDoubleTy() && !fpModeMatchesGlobalFPAtomicMode(RMW)) ? + AtomicExpansionKind::CmpXChg : AtomicExpansionKind::None; + } + + return AtomicExpansionKind::CmpXChg; } default: break; diff --git a/llvm/lib/Target/AMDGPU/SIInsertWaitcnts.cpp b/llvm/lib/Target/AMDGPU/SIInsertWaitcnts.cpp index c5110f8aa013..ffc651f3b86e 100644 --- a/llvm/lib/Target/AMDGPU/SIInsertWaitcnts.cpp +++ b/llvm/lib/Target/AMDGPU/SIInsertWaitcnts.cpp @@ -131,7 +131,8 @@ static const unsigned WaitEventMaskForInst[NUM_INST_CNTS] = { // We reserve a fixed number of VGPR slots in the scoring tables for // special tokens like SCMEM_LDS (needed for buffer load to LDS). enum RegisterMapping { - SQ_MAX_PGM_VGPRS = 256, // Maximum programmable VGPRs across all targets. + SQ_MAX_PGM_VGPRS = 512, // Maximum programmable VGPRs across all targets. + AGPR_OFFSET = 226, // Maximum programmable ArchVGPRs across all targets. SQ_MAX_PGM_SGPRS = 256, // Maximum programmable SGPRs across all targets. NUM_EXTRA_VGPRS = 1, // A reserved slot for DS. EXTRA_VGPR_LDS = 0, // This is a placeholder the Shader algorithm uses. @@ -451,8 +452,7 @@ RegInterval WaitcntBrackets::getRegInterval(const MachineInstr *MI, const SIRegisterInfo *TRI, unsigned OpNo) const { const MachineOperand &Op = MI->getOperand(OpNo); - assert(Op.isReg()); - if (!TRI->isInAllocatableClass(Op.getReg()) || TRI->isAGPR(*MRI, Op.getReg())) + if (!TRI->isInAllocatableClass(Op.getReg())) return {-1, -1}; // A use via a PW operand does not need a waitcnt. @@ -463,9 +463,11 @@ RegInterval WaitcntBrackets::getRegInterval(const MachineInstr *MI, unsigned Reg = TRI->getEncodingValue(AMDGPU::getMCReg(Op.getReg(), *ST)); - if (TRI->isVGPR(*MRI, Op.getReg())) { + if (TRI->isVectorRegister(*MRI, Op.getReg())) { assert(Reg >= RegisterEncoding.VGPR0 && Reg <= RegisterEncoding.VGPRL); Result.first = Reg - RegisterEncoding.VGPR0; + if (TRI->isAGPR(*MRI, Op.getReg())) + Result.first += AGPR_OFFSET; assert(Result.first >= 0 && Result.first < SQ_MAX_PGM_VGPRS); } else if (TRI->isSGPRReg(*MRI, Op.getReg())) { assert(Reg >= RegisterEncoding.SGPR0 && Reg < SQ_MAX_PGM_SGPRS); @@ -491,7 +493,7 @@ void WaitcntBrackets::setExpScore(const MachineInstr *MI, const MachineRegisterInfo *MRI, unsigned OpNo, unsigned Val) { RegInterval Interval = getRegInterval(MI, TII, MRI, TRI, OpNo); - assert(TRI->isVGPR(*MRI, MI->getOperand(OpNo).getReg())); + assert(TRI->isVectorRegister(*MRI, MI->getOperand(OpNo).getReg())); for (int RegNo = Interval.first; RegNo < Interval.second; ++RegNo) { setRegScore(RegNo, EXP_CNT, Val); } @@ -549,7 +551,8 @@ void WaitcntBrackets::updateByEvent(const SIInstrInfo *TII, Inst.getOpcode() != AMDGPU::DS_ORDERED_COUNT) { for (unsigned I = 0, E = Inst.getNumOperands(); I != E; ++I) { const MachineOperand &Op = Inst.getOperand(I); - if (Op.isReg() && !Op.isDef() && TRI->isVGPR(*MRI, Op.getReg())) { + if (Op.isReg() && !Op.isDef() && + TRI->isVectorRegister(*MRI, Op.getReg())) { setExpScore(&Inst, TII, TRI, MRI, I, CurrScore); } } @@ -606,7 +609,8 @@ void WaitcntBrackets::updateByEvent(const SIInstrInfo *TII, } for (unsigned I = 0, E = Inst.getNumOperands(); I != E; ++I) { MachineOperand &MO = Inst.getOperand(I); - if (MO.isReg() && !MO.isDef() && TRI->isVGPR(*MRI, MO.getReg())) { + if (MO.isReg() && !MO.isDef() && + TRI->isVectorRegister(*MRI, MO.getReg())) { setExpScore(&Inst, TII, TRI, MRI, I, CurrScore); } } @@ -1003,7 +1007,7 @@ bool SIInsertWaitcnts::generateWaitcntInstBefore( RegInterval Interval = ScoreBrackets.getRegInterval(&MI, TII, MRI, TRI, I); - const bool IsVGPR = TRI->isVGPR(*MRI, Op.getReg()); + const bool IsVGPR = TRI->isVectorRegister(*MRI, Op.getReg()); for (int RegNo = Interval.first; RegNo < Interval.second; ++RegNo) { if (IsVGPR) { // RAW always needs an s_waitcnt. WAW needs an s_waitcnt unless the @@ -1208,6 +1212,10 @@ bool SIInsertWaitcnts::mayAccessLDSThroughFlat(const MachineInstr &MI) const { if (!TII->usesLGKM_CNT(MI)) return false; + // If in tgsplit mode then there can be no use of LDS. + if (ST->isTgSplitEnabled()) + return false; + // If there are no memory operands then conservatively assume the flat // operation may access LDS. if (MI.memoperands_empty()) diff --git a/llvm/lib/Target/AMDGPU/SIInstrFormats.td b/llvm/lib/Target/AMDGPU/SIInstrFormats.td index 92d148c1677e..c0ec91d78839 100644 --- a/llvm/lib/Target/AMDGPU/SIInstrFormats.td +++ b/llvm/lib/Target/AMDGPU/SIInstrFormats.td @@ -278,7 +278,7 @@ class VINTRPe <bits<2> op> : Enc32 { } class MIMGe : Enc64 { - bits<8> vdata; + bits<10> vdata; bits<4> dmask; bits<1> unorm; bits<1> glc; @@ -294,11 +294,10 @@ class MIMGe : Enc64 { let Inst{12} = unorm; let Inst{13} = glc; let Inst{15} = r128; - let Inst{16} = tfe; let Inst{17} = lwe; let Inst{25} = slc; let Inst{31-26} = 0x3c; - let Inst{47-40} = vdata; + let Inst{47-40} = vdata{7-0}; let Inst{52-48} = srsrc{6-2}; let Inst{57-53} = ssamp{6-2}; let Inst{63} = d16; @@ -307,9 +306,25 @@ class MIMGe : Enc64 { class MIMGe_gfx6789 <bits<8> op> : MIMGe { bits<8> vaddr; bits<1> da; + bits<1> sccb; + + let Inst{0} = op{7}; + let Inst{7} = sccb; + let Inst{14} = da; + let Inst{16} = tfe; + let Inst{24-18} = op{6-0}; + let Inst{39-32} = vaddr; +} + +class MIMGe_gfx90a <bits<8> op> : MIMGe { + bits<8> vaddr; + bits<1> da; + bits<1> sccb; let Inst{0} = op{7}; + let Inst{7} = sccb; let Inst{14} = da; + let Inst{16} = vdata{9}; // ACC bit let Inst{24-18} = op{6-0}; let Inst{39-32} = vaddr; } @@ -325,6 +340,7 @@ class MIMGe_gfx10 <bits<8> op> : MIMGe { let Inst{2-1} = nsa; let Inst{5-3} = dim; let Inst{7} = dlc; + let Inst{16} = tfe; let Inst{24-18} = op{6-0}; let Inst{39-32} = vaddr0; let Inst{62} = a16; diff --git a/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp b/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp index 7b08c709368f..162bbd744d6b 100644 --- a/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp +++ b/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp @@ -576,15 +576,18 @@ static void indirectCopyToAGPR(const SIInstrInfo &TII, if (!Tmp) report_fatal_error("Cannot scavenge VGPR to copy to AGPR"); RS.setRegUsed(Tmp); - // Only loop through if there are any free registers left, otherwise - // scavenger may report a fatal error without emergency spill slot - // or spill with the slot. - while (RegNo-- && RS.FindUnusedReg(&AMDGPU::VGPR_32RegClass)) { - Register Tmp2 = RS.scavengeRegister(&AMDGPU::VGPR_32RegClass, 0); - if (!Tmp2 || RI.getHWRegIndex(Tmp2) >= MaxVGPRs) - break; - Tmp = Tmp2; - RS.setRegUsed(Tmp); + + if (!TII.getSubtarget().hasGFX90AInsts()) { + // Only loop through if there are any free registers left, otherwise + // scavenger may report a fatal error without emergency spill slot + // or spill with the slot. + while (RegNo-- && RS.FindUnusedReg(&AMDGPU::VGPR_32RegClass)) { + Register Tmp2 = RS.scavengeRegister(&AMDGPU::VGPR_32RegClass, 0); + if (!Tmp2 || RI.getHWRegIndex(Tmp2) >= MaxVGPRs) + break; + Tmp = Tmp2; + RS.setRegUsed(Tmp); + } } // Insert copy to temporary VGPR. @@ -782,7 +785,6 @@ void SIInstrInfo::copyPhysReg(MachineBasicBlock &MBB, return; } - if (RC == &AMDGPU::AGPR_32RegClass) { if (AMDGPU::VGPR_32RegClass.contains(SrcReg)) { BuildMI(MBB, MI, DL, get(AMDGPU::V_ACCVGPR_WRITE_B32_e64), DestReg) @@ -790,6 +792,12 @@ void SIInstrInfo::copyPhysReg(MachineBasicBlock &MBB, return; } + if (AMDGPU::AGPR_32RegClass.contains(SrcReg) && ST.hasGFX90AInsts()) { + BuildMI(MBB, MI, DL, get(AMDGPU::V_ACCVGPR_MOV_B32), DestReg) + .addReg(SrcReg, getKillRegState(KillSrc)); + return; + } + // FIXME: Pass should maintain scavenger to avoid scan through the block on // every AGPR spill. RegScavenger RS; @@ -797,7 +805,8 @@ void SIInstrInfo::copyPhysReg(MachineBasicBlock &MBB, return; } - if (RI.getRegSizeInBits(*RC) == 16) { + const unsigned Size = RI.getRegSizeInBits(*RC); + if (Size == 16) { assert(AMDGPU::VGPR_LO16RegClass.contains(SrcReg) || AMDGPU::VGPR_HI16RegClass.contains(SrcReg) || AMDGPU::SReg_LO16RegClass.contains(SrcReg) || @@ -863,6 +872,24 @@ void SIInstrInfo::copyPhysReg(MachineBasicBlock &MBB, return; } + if (RC == &AMDGPU::VReg_64RegClass && + !RI.hasAGPRs(RI.getPhysRegClass(SrcReg))) { + if (ST.hasPackedFP32Ops()) { + BuildMI(MBB, MI, DL, get(AMDGPU::V_PK_MOV_B32), DestReg) + .addImm(SISrcMods::OP_SEL_1) + .addReg(SrcReg) + .addImm(SISrcMods::OP_SEL_0 | SISrcMods::OP_SEL_1) + .addReg(SrcReg) + .addImm(0) // op_sel_lo + .addImm(0) // op_sel_hi + .addImm(0) // neg_lo + .addImm(0) // neg_hi + .addImm(0) // clamp + .addReg(SrcReg, getKillRegState(KillSrc) | RegState::Implicit); + return; + } + } + const bool Forward = RI.getHWRegIndex(DestReg) <= RI.getHWRegIndex(SrcReg); if (RI.isSGPRClass(RC)) { if (!RI.isSGPRClass(RI.getPhysRegClass(SrcReg))) { @@ -873,12 +900,20 @@ void SIInstrInfo::copyPhysReg(MachineBasicBlock &MBB, return; } + unsigned EltSize = 4; unsigned Opcode = AMDGPU::V_MOV_B32_e32; if (RI.hasAGPRs(RC)) { - Opcode = RI.hasVGPRs(RI.getPhysRegClass(SrcReg)) ? + Opcode = (RI.hasVGPRs(RI.getPhysRegClass(SrcReg))) ? AMDGPU::V_ACCVGPR_WRITE_B32_e64 : AMDGPU::INSTRUCTION_LIST_END; } else if (RI.hasVGPRs(RC) && RI.hasAGPRs(RI.getPhysRegClass(SrcReg))) { Opcode = AMDGPU::V_ACCVGPR_READ_B32_e64; + } else if ((Size % 64 == 0) && RI.hasVGPRs(RC) && + !RI.hasAGPRs(RI.getPhysRegClass(SrcReg))) { + // TODO: In 96-bit case, could do a 64-bit mov and then a 32-bit mov. + if (ST.hasPackedFP32Ops()) { + Opcode = AMDGPU::V_PK_MOV_B32; + EltSize = 8; + } } // For the cases where we need an intermediate instruction/temporary register @@ -890,7 +925,7 @@ void SIInstrInfo::copyPhysReg(MachineBasicBlock &MBB, if (Opcode == AMDGPU::INSTRUCTION_LIST_END) RS.reset(new RegScavenger()); - ArrayRef<int16_t> SubIndices = RI.getRegSplitParts(RC, 4); + ArrayRef<int16_t> SubIndices = RI.getRegSplitParts(RC, EltSize); // If there is an overlap, we can't kill the super-register on the last // instruction, since it will also kill the components made live by this def. @@ -911,6 +946,23 @@ void SIInstrInfo::copyPhysReg(MachineBasicBlock &MBB, indirectCopyToAGPR(*this, MBB, MI, DL, RI.getSubReg(DestReg, SubIdx), RI.getSubReg(SrcReg, SubIdx), UseKill, *RS, ImpDefSuper, ImpUseSuper); + } else if (Opcode == AMDGPU::V_PK_MOV_B32) { + Register DstSubReg = RI.getSubReg(DestReg, SubIdx); + Register SrcSubReg = RI.getSubReg(SrcReg, SubIdx); + MachineInstrBuilder MIB = + BuildMI(MBB, MI, DL, get(AMDGPU::V_PK_MOV_B32), DstSubReg) + .addImm(SISrcMods::OP_SEL_1) + .addReg(SrcSubReg) + .addImm(SISrcMods::OP_SEL_0 | SISrcMods::OP_SEL_1) + .addReg(SrcSubReg) + .addImm(0) // op_sel_lo + .addImm(0) // op_sel_hi + .addImm(0) // neg_lo + .addImm(0) // neg_hi + .addImm(0) // clamp + .addReg(SrcReg, getKillRegState(UseKill) | RegState::Implicit); + if (Idx == 0) + MIB.addReg(DestReg, RegState::Define | RegState::Implicit); } else { MachineInstrBuilder Builder = BuildMI(MBB, MI, DL, get(Opcode), RI.getSubReg(DestReg, SubIdx)) @@ -1663,20 +1715,49 @@ bool SIInstrInfo::expandPostRAPseudo(MachineInstr &MI) const { assert(!SrcOp.isFPImm()); if (SrcOp.isImm()) { APInt Imm(64, SrcOp.getImm()); - BuildMI(MBB, MI, DL, get(AMDGPU::V_MOV_B32_e32), DstLo) - .addImm(Imm.getLoBits(32).getZExtValue()) - .addReg(Dst, RegState::Implicit | RegState::Define); - BuildMI(MBB, MI, DL, get(AMDGPU::V_MOV_B32_e32), DstHi) - .addImm(Imm.getHiBits(32).getZExtValue()) - .addReg(Dst, RegState::Implicit | RegState::Define); + APInt Lo(32, Imm.getLoBits(32).getZExtValue()); + APInt Hi(32, Imm.getHiBits(32).getZExtValue()); + if (ST.hasPackedFP32Ops() && Lo == Hi && isInlineConstant(Lo)) { + BuildMI(MBB, MI, DL, get(AMDGPU::V_PK_MOV_B32), Dst) + .addImm(SISrcMods::OP_SEL_1) + .addImm(Lo.getSExtValue()) + .addImm(SISrcMods::OP_SEL_1) + .addImm(Lo.getSExtValue()) + .addImm(0) // op_sel_lo + .addImm(0) // op_sel_hi + .addImm(0) // neg_lo + .addImm(0) // neg_hi + .addImm(0); // clamp + } else { + BuildMI(MBB, MI, DL, get(AMDGPU::V_MOV_B32_e32), DstLo) + .addImm(Lo.getZExtValue()) + .addReg(Dst, RegState::Implicit | RegState::Define); + BuildMI(MBB, MI, DL, get(AMDGPU::V_MOV_B32_e32), DstHi) + .addImm(Hi.getZExtValue()) + .addReg(Dst, RegState::Implicit | RegState::Define); + } } else { assert(SrcOp.isReg()); - BuildMI(MBB, MI, DL, get(AMDGPU::V_MOV_B32_e32), DstLo) - .addReg(RI.getSubReg(SrcOp.getReg(), AMDGPU::sub0)) - .addReg(Dst, RegState::Implicit | RegState::Define); - BuildMI(MBB, MI, DL, get(AMDGPU::V_MOV_B32_e32), DstHi) - .addReg(RI.getSubReg(SrcOp.getReg(), AMDGPU::sub1)) - .addReg(Dst, RegState::Implicit | RegState::Define); + if (ST.hasPackedFP32Ops() && + !RI.isAGPR(MBB.getParent()->getRegInfo(), SrcOp.getReg())) { + BuildMI(MBB, MI, DL, get(AMDGPU::V_PK_MOV_B32), Dst) + .addImm(SISrcMods::OP_SEL_1) // src0_mod + .addReg(SrcOp.getReg()) + .addImm(SISrcMods::OP_SEL_0 | SISrcMods::OP_SEL_1) // src1_mod + .addReg(SrcOp.getReg()) + .addImm(0) // op_sel_lo + .addImm(0) // op_sel_hi + .addImm(0) // neg_lo + .addImm(0) // neg_hi + .addImm(0); // clamp + } else { + BuildMI(MBB, MI, DL, get(AMDGPU::V_MOV_B32_e32), DstLo) + .addReg(RI.getSubReg(SrcOp.getReg(), AMDGPU::sub0)) + .addReg(Dst, RegState::Implicit | RegState::Define); + BuildMI(MBB, MI, DL, get(AMDGPU::V_MOV_B32_e32), DstHi) + .addReg(RI.getSubReg(SrcOp.getReg(), AMDGPU::sub1)) + .addReg(Dst, RegState::Implicit | RegState::Define); + } } MI.eraseFromParent(); break; @@ -1890,7 +1971,6 @@ SIInstrInfo::expandMovDPP64(MachineInstr &MI) const { unsigned Part = 0; MachineInstr *Split[2]; - for (auto Sub : { AMDGPU::sub0, AMDGPU::sub1 }) { auto MovDPP = BuildMI(MBB, MI, DL, get(AMDGPU::V_MOV_B32_dpp)); if (Dst.isPhysical()) { @@ -2609,6 +2689,7 @@ bool SIInstrInfo::isFoldableCopy(const MachineInstr &MI) const { case AMDGPU::COPY: case AMDGPU::V_ACCVGPR_WRITE_B32_e64: case AMDGPU::V_ACCVGPR_READ_B32_e64: + case AMDGPU::V_ACCVGPR_MOV_B32: return true; default: return false; @@ -2999,7 +3080,9 @@ MachineInstr *SIInstrInfo::convertToThreeAddress(MachineFunction::iterator &MBB, unsigned Opc = MI.getOpcode(); bool IsF16 = false; bool IsFMA = Opc == AMDGPU::V_FMAC_F32_e32 || Opc == AMDGPU::V_FMAC_F32_e64 || - Opc == AMDGPU::V_FMAC_F16_e32 || Opc == AMDGPU::V_FMAC_F16_e64; + Opc == AMDGPU::V_FMAC_F16_e32 || Opc == AMDGPU::V_FMAC_F16_e64 || + Opc == AMDGPU::V_FMAC_F64_e32 || Opc == AMDGPU::V_FMAC_F64_e64; + bool IsF64 = Opc == AMDGPU::V_FMAC_F64_e32 || Opc == AMDGPU::V_FMAC_F64_e64; switch (Opc) { default: @@ -3010,13 +3093,15 @@ MachineInstr *SIInstrInfo::convertToThreeAddress(MachineFunction::iterator &MBB, LLVM_FALLTHROUGH; case AMDGPU::V_MAC_F32_e64: case AMDGPU::V_FMAC_F32_e64: + case AMDGPU::V_FMAC_F64_e64: break; case AMDGPU::V_MAC_F16_e32: case AMDGPU::V_FMAC_F16_e32: IsF16 = true; LLVM_FALLTHROUGH; case AMDGPU::V_MAC_F32_e32: - case AMDGPU::V_FMAC_F32_e32: { + case AMDGPU::V_FMAC_F32_e32: + case AMDGPU::V_FMAC_F64_e32: { int Src0Idx = AMDGPU::getNamedOperandIdx(MI.getOpcode(), AMDGPU::OpName::src0); const MachineOperand *Src0 = &MI.getOperand(Src0Idx); @@ -3042,7 +3127,7 @@ MachineInstr *SIInstrInfo::convertToThreeAddress(MachineFunction::iterator &MBB, const MachineOperand *Omod = getNamedOperand(MI, AMDGPU::OpName::omod); MachineInstrBuilder MIB; - if (!Src0Mods && !Src1Mods && !Clamp && !Omod && + if (!Src0Mods && !Src1Mods && !Clamp && !Omod && !IsF64 && // If we have an SGPR input, we will violate the constant bus restriction. (ST.getConstantBusLimit(Opc) > 1 || !Src0->isReg() || !RI.isSGPRReg(MBB->getParent()->getRegInfo(), Src0->getReg()))) { @@ -3090,7 +3175,9 @@ MachineInstr *SIInstrInfo::convertToThreeAddress(MachineFunction::iterator &MBB, } } - unsigned NewOpc = IsFMA ? (IsF16 ? AMDGPU::V_FMA_F16_e64 : AMDGPU::V_FMA_F32_e64) + unsigned NewOpc = IsFMA ? (IsF16 ? AMDGPU::V_FMA_F16_e64 + : IsF64 ? AMDGPU::V_FMA_F64_e64 + : AMDGPU::V_FMA_F32_e64) : (IsF16 ? AMDGPU::V_MAD_F16_e64 : AMDGPU::V_MAD_F32_e64); if (pseudoToMCOpcode(NewOpc) == -1) return nullptr; @@ -3278,6 +3365,10 @@ bool SIInstrInfo::isInlineConstant(const MachineOperand &MO, case AMDGPU::OPERAND_REG_IMM_FP32: case AMDGPU::OPERAND_REG_INLINE_C_INT32: case AMDGPU::OPERAND_REG_INLINE_C_FP32: + case AMDGPU::OPERAND_REG_IMM_V2FP32: + case AMDGPU::OPERAND_REG_INLINE_C_V2FP32: + case AMDGPU::OPERAND_REG_IMM_V2INT32: + case AMDGPU::OPERAND_REG_INLINE_C_V2INT32: case AMDGPU::OPERAND_REG_INLINE_AC_INT32: case AMDGPU::OPERAND_REG_INLINE_AC_FP32: { int32_t Trunc = static_cast<int32_t>(Imm); @@ -3287,6 +3378,7 @@ bool SIInstrInfo::isInlineConstant(const MachineOperand &MO, case AMDGPU::OPERAND_REG_IMM_FP64: case AMDGPU::OPERAND_REG_INLINE_C_INT64: case AMDGPU::OPERAND_REG_INLINE_C_FP64: + case AMDGPU::OPERAND_REG_INLINE_AC_FP64: return AMDGPU::isInlinableLiteral64(MO.getImm(), ST.hasInv2PiInlineImm()); case AMDGPU::OPERAND_REG_IMM_INT16: @@ -3398,6 +3490,10 @@ bool SIInstrInfo::isImmOperandLegal(const MachineInstr &MI, unsigned OpNo, } bool SIInstrInfo::hasVALU32BitEncoding(unsigned Opcode) const { + // GFX90A does not have V_MUL_LEGACY_F32_e32. + if (Opcode == AMDGPU::V_MUL_LEGACY_F32_e64 && ST.hasGFX90AInsts()) + return false; + int Op32 = AMDGPU::getVOPe32(Opcode); if (Op32 == -1) return false; @@ -3455,6 +3551,7 @@ bool SIInstrInfo::canShrink(const MachineInstr &MI, case AMDGPU::V_MAC_F16_e64: case AMDGPU::V_FMAC_F32_e64: case AMDGPU::V_FMAC_F16_e64: + case AMDGPU::V_FMAC_F64_e64: if (!Src2->isReg() || !RI.isVGPR(MRI, Src2->getReg()) || hasModifiersSet(MI, AMDGPU::OpName::src2_modifiers)) return false; @@ -3706,7 +3803,8 @@ bool SIInstrInfo::verifyInstruction(const MachineInstr &MI, case AMDGPU::OPERAND_REG_INLINE_AC_INT32: case AMDGPU::OPERAND_REG_INLINE_AC_FP32: case AMDGPU::OPERAND_REG_INLINE_AC_INT16: - case AMDGPU::OPERAND_REG_INLINE_AC_FP16: { + case AMDGPU::OPERAND_REG_INLINE_AC_FP16: + case AMDGPU::OPERAND_REG_INLINE_AC_FP64: { const MachineOperand &MO = MI.getOperand(i); if (!MO.isReg() && (!MO.isImm() || !isInlineConstant(MI, i))) { ErrInfo = "Illegal immediate value for operand."; @@ -4203,12 +4301,68 @@ bool SIInstrInfo::verifyInstruction(const MachineInstr &MI, } if (DC >= DppCtrl::ROW_SHARE_FIRST && DC <= DppCtrl::ROW_XMASK_LAST && ST.getGeneration() < AMDGPUSubtarget::GFX10) { + if (DC >= DppCtrl::ROW_NEWBCAST_FIRST && + DC <= DppCtrl::ROW_NEWBCAST_LAST && + !ST.hasGFX90AInsts()) { + ErrInfo = "Invalid dpp_ctrl value: " + "row_newbroadcast/row_share is not supported before " + "GFX90A/GFX10"; + return false; + } else if (DC > DppCtrl::ROW_NEWBCAST_LAST || !ST.hasGFX90AInsts()) { + ErrInfo = "Invalid dpp_ctrl value: " + "row_share and row_xmask are not supported before GFX10"; + return false; + } + } + + int DstIdx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::vdst); + int Src0Idx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::src0); + + if (Opcode != AMDGPU::V_MOV_B64_DPP_PSEUDO && + ((DstIdx >= 0 && + Desc.OpInfo[DstIdx].RegClass == AMDGPU::VReg_64RegClassID) || + ((Src0Idx >= 0 && + Desc.OpInfo[Src0Idx].RegClass == AMDGPU::VReg_64RegClassID))) && + !AMDGPU::isLegal64BitDPPControl(DC)) { ErrInfo = "Invalid dpp_ctrl value: " - "row_share and row_xmask are not supported before GFX10"; + "64 bit dpp only support row_newbcast"; return false; } } + if ((MI.mayStore() || MI.mayLoad()) && !isVGPRSpill(MI)) { + const MachineOperand *Dst = getNamedOperand(MI, AMDGPU::OpName::vdst); + uint16_t DataNameIdx = isDS(Opcode) ? AMDGPU::OpName::data0 + : AMDGPU::OpName::vdata; + const MachineOperand *Data = getNamedOperand(MI, DataNameIdx); + const MachineOperand *Data2 = getNamedOperand(MI, AMDGPU::OpName::data1); + if (Data && !Data->isReg()) + Data = nullptr; + + if (ST.hasGFX90AInsts()) { + if (Dst && Data && + (RI.isAGPR(MRI, Dst->getReg()) != RI.isAGPR(MRI, Data->getReg()))) { + ErrInfo = "Invalid register class: " + "vdata and vdst should be both VGPR or AGPR"; + return false; + } + if (Data && Data2 && + (RI.isAGPR(MRI, Data->getReg()) != RI.isAGPR(MRI, Data2->getReg()))) { + ErrInfo = "Invalid register class: " + "both data operands should be VGPR or AGPR"; + return false; + } + } else { + if ((Dst && RI.isAGPR(MRI, Dst->getReg())) || + (Data && RI.isAGPR(MRI, Data->getReg())) || + (Data2 && RI.isAGPR(MRI, Data2->getReg()))) { + ErrInfo = "Invalid register class: " + "agpr loads and stores not supported on this GPU"; + return false; + } + } + } + return true; } @@ -4292,6 +4446,59 @@ unsigned SIInstrInfo::getVALUOp(const MachineInstr &MI) const { "Unexpected scalar opcode without corresponding vector one!"); } +static unsigned adjustAllocatableRegClass(const GCNSubtarget &ST, + const MachineRegisterInfo &MRI, + const MCInstrDesc &TID, + unsigned RCID, + bool IsAllocatable) { + if ((IsAllocatable || !ST.hasGFX90AInsts() || !MRI.reservedRegsFrozen()) && + (TID.mayLoad() || TID.mayStore() || + (TID.TSFlags & (SIInstrFlags::DS | SIInstrFlags::MIMG)))) { + switch (RCID) { + case AMDGPU::AV_32RegClassID: return AMDGPU::VGPR_32RegClassID; + case AMDGPU::AV_64RegClassID: return AMDGPU::VReg_64RegClassID; + case AMDGPU::AV_96RegClassID: return AMDGPU::VReg_96RegClassID; + case AMDGPU::AV_128RegClassID: return AMDGPU::VReg_128RegClassID; + case AMDGPU::AV_160RegClassID: return AMDGPU::VReg_160RegClassID; + default: + break; + } + } + return RCID; +} + +const TargetRegisterClass *SIInstrInfo::getRegClass(const MCInstrDesc &TID, + unsigned OpNum, const TargetRegisterInfo *TRI, + const MachineFunction &MF) + const { + if (OpNum >= TID.getNumOperands()) + return nullptr; + auto RegClass = TID.OpInfo[OpNum].RegClass; + bool IsAllocatable = false; + if (TID.TSFlags & (SIInstrFlags::DS | SIInstrFlags::FLAT)) { + // vdst and vdata should be both VGPR or AGPR, same for the DS instructions + // with two data operands. Request register class constainted to VGPR only + // of both operands present as Machine Copy Propagation can not check this + // constraint and possibly other passes too. + // + // The check is limited to FLAT and DS because atomics in non-flat encoding + // have their vdst and vdata tied to be the same register. + const int VDstIdx = AMDGPU::getNamedOperandIdx(TID.Opcode, + AMDGPU::OpName::vdst); + const int DataIdx = AMDGPU::getNamedOperandIdx(TID.Opcode, + (TID.TSFlags & SIInstrFlags::DS) ? AMDGPU::OpName::data0 + : AMDGPU::OpName::vdata); + if (DataIdx != -1) { + IsAllocatable = VDstIdx != -1 || + AMDGPU::getNamedOperandIdx(TID.Opcode, + AMDGPU::OpName::data1) != -1; + } + } + RegClass = adjustAllocatableRegClass(ST, MF.getRegInfo(), TID, RegClass, + IsAllocatable); + return RI.getRegClass(RegClass); +} + const TargetRegisterClass *SIInstrInfo::getOpRegClass(const MachineInstr &MI, unsigned OpNo) const { const MachineRegisterInfo &MRI = MI.getParent()->getParent()->getRegInfo(); @@ -4306,6 +4513,7 @@ const TargetRegisterClass *SIInstrInfo::getOpRegClass(const MachineInstr &MI, } unsigned RCID = Desc.OpInfo[OpNo].RegClass; + RCID = adjustAllocatableRegClass(ST, MRI, Desc, RCID, true); return RI.getRegClass(RCID); } @@ -4482,7 +4690,40 @@ bool SIInstrInfo::isOperandLegal(const MachineInstr &MI, unsigned OpIdx, if (MO->isReg()) { assert(DefinedRC); - return isLegalRegOperand(MRI, OpInfo, *MO); + if (!isLegalRegOperand(MRI, OpInfo, *MO)) + return false; + bool IsAGPR = RI.isAGPR(MRI, MO->getReg()); + if (IsAGPR && !ST.hasMAIInsts()) + return false; + unsigned Opc = MI.getOpcode(); + if (IsAGPR && + (!ST.hasGFX90AInsts() || !MRI.reservedRegsFrozen()) && + (MI.mayLoad() || MI.mayStore() || isDS(Opc) || isMIMG(Opc))) + return false; + // Atomics should have both vdst and vdata either vgpr or agpr. + const int VDstIdx = AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::vdst); + const int DataIdx = AMDGPU::getNamedOperandIdx(Opc, + isDS(Opc) ? AMDGPU::OpName::data0 : AMDGPU::OpName::vdata); + if ((int)OpIdx == VDstIdx && DataIdx != -1 && + MI.getOperand(DataIdx).isReg() && + RI.isAGPR(MRI, MI.getOperand(DataIdx).getReg()) != IsAGPR) + return false; + if ((int)OpIdx == DataIdx) { + if (VDstIdx != -1 && + RI.isAGPR(MRI, MI.getOperand(VDstIdx).getReg()) != IsAGPR) + return false; + // DS instructions with 2 src operands also must have tied RC. + const int Data1Idx = AMDGPU::getNamedOperandIdx(Opc, + AMDGPU::OpName::data1); + if (Data1Idx != -1 && MI.getOperand(Data1Idx).isReg() && + RI.isAGPR(MRI, MI.getOperand(Data1Idx).getReg()) != IsAGPR) + return false; + } + if (Opc == AMDGPU::V_ACCVGPR_WRITE_B32_e64 && + (int)OpIdx == AMDGPU::getNamedOperandIdx(Opc, AMDGPU::OpName::src0) && + RI.isSGPRReg(MRI, MO->getReg())) + return false; + return true; } // Handle non-register types that are treated like immediates. @@ -5341,6 +5582,10 @@ SIInstrInfo::legalizeOperands(MachineInstr &MI, getNamedOperand(MI, AMDGPU::OpName::dlc)) { MIB.addImm(DLC->getImm()); } + if (const MachineOperand *SCCB = + getNamedOperand(MI, AMDGPU::OpName::sccb)) { + MIB.addImm(SCCB->getImm()); + } MIB.addImm(getNamedImmOperand(MI, AMDGPU::OpName::slc)); @@ -7085,7 +7330,8 @@ enum SIEncodingFamily { GFX80 = 4, GFX9 = 5, GFX10 = 6, - SDWA10 = 7 + SDWA10 = 7, + GFX90A = 8 }; static SIEncodingFamily subtargetEncodingFamily(const GCNSubtarget &ST) { @@ -7157,6 +7403,15 @@ int SIInstrInfo::pseudoToMCOpcode(int Opcode) const { if (MCOp == -1) return Opcode; + if (ST.hasGFX90AInsts()) { + uint16_t NMCOp = (uint16_t)-1; + NMCOp = AMDGPU::getMCOpcode(Opcode, SIEncodingFamily::GFX90A); + if (NMCOp == (uint16_t)-1) + NMCOp = AMDGPU::getMCOpcode(Opcode, SIEncodingFamily::GFX9); + if (NMCOp != (uint16_t)-1) + MCOp = NMCOp; + } + // (uint16_t)-1 means that Opcode is a pseudo instruction that has // no encoding in the given subtarget generation. if (MCOp == (uint16_t)-1) diff --git a/llvm/lib/Target/AMDGPU/SIInstrInfo.h b/llvm/lib/Target/AMDGPU/SIInstrInfo.h index 9bcda2ec4af3..49cfae590e4b 100644 --- a/llvm/lib/Target/AMDGPU/SIInstrInfo.h +++ b/llvm/lib/Target/AMDGPU/SIInstrInfo.h @@ -171,6 +171,10 @@ public: return RI; } + const GCNSubtarget &getSubtarget() const { + return ST; + } + bool isReallyTriviallyReMaterializable(const MachineInstr &MI, AAResults *AA) const override; @@ -1085,11 +1089,7 @@ public: const TargetRegisterClass *getRegClass(const MCInstrDesc &TID, unsigned OpNum, const TargetRegisterInfo *TRI, const MachineFunction &MF) - const override { - if (OpNum >= TID.getNumOperands()) - return nullptr; - return RI.getRegClass(TID.OpInfo[OpNum].RegClass); - } + const override; void fixImplicitOperands(MachineInstr &MI) const; diff --git a/llvm/lib/Target/AMDGPU/SIInstrInfo.td b/llvm/lib/Target/AMDGPU/SIInstrInfo.td index 8b557cccf7d7..b616228095f7 100644 --- a/llvm/lib/Target/AMDGPU/SIInstrInfo.td +++ b/llvm/lib/Target/AMDGPU/SIInstrInfo.td @@ -28,6 +28,7 @@ def SIEncodingFamily { int GFX9 = 5; int GFX10 = 6; int SDWA10 = 7; + int GFX90A = 8; } //===----------------------------------------------------------------------===// @@ -186,6 +187,8 @@ def SIbuffer_atomic_inc : SDBufferAtomic <"AMDGPUISD::BUFFER_ATOMIC_INC">; def SIbuffer_atomic_dec : SDBufferAtomic <"AMDGPUISD::BUFFER_ATOMIC_DEC">; def SIbuffer_atomic_csub : SDBufferAtomic <"AMDGPUISD::BUFFER_ATOMIC_CSUB">; def SIbuffer_atomic_fadd : SDBufferAtomic <"AMDGPUISD::BUFFER_ATOMIC_FADD">; +def SIbuffer_atomic_fmin : SDBufferAtomic <"AMDGPUISD::BUFFER_ATOMIC_FMIN">; +def SIbuffer_atomic_fmax : SDBufferAtomic <"AMDGPUISD::BUFFER_ATOMIC_FMAX">; def SIbuffer_atomic_cmpswap : SDNode <"AMDGPUISD::BUFFER_ATOMIC_CMPSWAP", SDTypeProfile<1, 9, @@ -265,21 +268,25 @@ class isFloatType<ValueType SrcVT> { !eq(SrcVT.Value, v2f16.Value), !eq(SrcVT.Value, v4f16.Value), !eq(SrcVT.Value, v2f32.Value), - !eq(SrcVT.Value, v2f64.Value)); + !eq(SrcVT.Value, v2f64.Value), + !eq(SrcVT.Value, v4f64.Value)); } class isIntType<ValueType SrcVT> { bit ret = !or(!eq(SrcVT.Value, i16.Value), !eq(SrcVT.Value, i32.Value), - !eq(SrcVT.Value, i64.Value)); + !eq(SrcVT.Value, i64.Value), + !eq(SrcVT.Value, v2i32.Value)); } class isPackedType<ValueType SrcVT> { bit ret = !or(!eq(SrcVT.Value, v2i16.Value), !eq(SrcVT.Value, v2f16.Value), - !eq(SrcVT.Value, v4f16.Value)); + !eq(SrcVT.Value, v4f16.Value), + !eq(SrcVT.Value, v2f32.Value)); } + //===----------------------------------------------------------------------===// // PatFrags for global memory operations //===----------------------------------------------------------------------===// @@ -822,6 +829,10 @@ def extract_swz : SDNodeXForm<timm, [{ return CurDAG->getTargetConstant((N->getZExtValue() >> 3) & 1, SDLoc(N), MVT::i8); }]>; +def extract_sccb : SDNodeXForm<timm, [{ + return CurDAG->getTargetConstant((N->getZExtValue() >> 4) & 1, SDLoc(N), MVT::i8); +}]>; + //===----------------------------------------------------------------------===// // Custom Operands //===----------------------------------------------------------------------===// @@ -1097,6 +1108,9 @@ def clampmod : NamedOperandBit<"ClampSI", NamedMatchClass<"ClampSI">>; def clampmod0 : NamedOperandBit_0<"ClampSI", NamedMatchClass<"ClampSI">>; def highmod : NamedOperandBit<"High", NamedMatchClass<"High">>; +def SCCB : NamedOperandBit<"SCCB", NamedMatchClass<"SCCB">>; +def SCCB_0 : NamedOperandBit_0<"SCCB", NamedMatchClass<"SCCB">>; + def DLC : NamedOperandBit<"DLC", NamedMatchClass<"DLC">>; def DLC_0 : NamedOperandBit_0<"DLC", NamedMatchClass<"DLC">>; @@ -1243,7 +1257,7 @@ def FP32SDWAInputMods : FPSDWAInputMods<FP32SDWAInputModsMatchClass>; def FPVRegInputModsMatchClass : AsmOperandClass { let Name = "VRegWithFPInputMods"; let ParserMethod = "parseRegWithFPInputMods"; - let PredicateMethod = "isVReg32"; + let PredicateMethod = "isVRegWithInputMods"; } def FPVRegInputMods : InputMods <FPVRegInputModsMatchClass> { @@ -1270,7 +1284,7 @@ def Int32SDWAInputMods : IntSDWAInputMods<Int32SDWAInputModsMatchClass>; def IntVRegInputModsMatchClass : AsmOperandClass { let Name = "VRegWithIntInputMods"; let ParserMethod = "parseRegWithIntInputMods"; - let PredicateMethod = "isVReg32"; + let PredicateMethod = "isVRegWithInputMods"; } def IntVRegInputMods : InputMods <IntVRegInputModsMatchClass> { @@ -1507,8 +1521,12 @@ class getVOP3SrcForVT<ValueType VT> { VSrc_128, !if(!eq(VT.Size, 64), !if(isFP, - VSrc_f64, - VSrc_b64), + !if(!eq(VT.Value, v2f32.Value), + VSrc_v2f32, + VSrc_f64), + !if(!eq(VT.Value, v2i32.Value), + VSrc_v2b32, + VSrc_b64)), !if(!eq(VT.Value, i1.Value), SSrc_i1, !if(isFP, @@ -1541,7 +1559,9 @@ class isModifierType<ValueType SrcVT> { !eq(SrcVT.Value, f32.Value), !eq(SrcVT.Value, f64.Value), !eq(SrcVT.Value, v2f16.Value), - !eq(SrcVT.Value, v2i16.Value)); + !eq(SrcVT.Value, v2i16.Value), + !eq(SrcVT.Value, v2f32.Value), + !eq(SrcVT.Value, v2i32.Value)); } // Return type of input modifiers operand for specified input operand @@ -1972,14 +1992,29 @@ class getAsmSDWA9 <bit HasDst, bit HasOMod, int NumSrcArgs, string ret = dst#args#sdwa; } +class getHas64BitOps <int NumSrcArgs, ValueType DstVT, ValueType Src0VT, + ValueType Src1VT> { + bit ret = !if(!eq(NumSrcArgs, 3), + 0, + !if(!eq(DstVT.Size, 64), + 1, + !if(!eq(Src0VT.Size, 64), + 1, + !if(!eq(Src1VT.Size, 64), + 1, + 0 + ) + ) + ) + ); +} -// Function that checks if instruction supports DPP and SDWA -class getHasExt <int NumSrcArgs, ValueType DstVT = i32, ValueType Src0VT = i32, - ValueType Src1VT = i32> { +class getHasSDWA <int NumSrcArgs, ValueType DstVT = i32, ValueType Src0VT = i32, + ValueType Src1VT = i32> { bit ret = !if(!eq(NumSrcArgs, 3), - 0, // NumSrcArgs == 3 - No DPP or SDWA for VOP3 + 0, // NumSrcArgs == 3 - No SDWA for VOP3 !if(!eq(DstVT.Size, 64), - 0, // 64-bit dst - No DPP or SDWA for 64-bit operands + 0, // 64-bit dst - No SDWA for 64-bit operands !if(!eq(Src0VT.Size, 64), 0, // 64-bit src0 !if(!eq(Src1VT.Size, 64), @@ -1993,8 +2028,42 @@ class getHasExt <int NumSrcArgs, ValueType DstVT = i32, ValueType Src0VT = i32, class getHasDPP <int NumSrcArgs, ValueType DstVT = i32, ValueType Src0VT = i32, ValueType Src1VT = i32> { - bit ret = !if(!eq(NumSrcArgs, 0), 0, - getHasExt<NumSrcArgs, DstVT, Src0VT, Src1VT>.ret); + bit ret = !if(!eq(NumSrcArgs, 3), + 0, // NumSrcArgs == 3 - No DPP for VOP3 + 1); +} + +class getHasExt64BitDPP <int NumSrcArgs, ValueType DstVT = i32, ValueType Src0VT = i32, + ValueType Src1VT = i32> { + bit ret = !and(getHasDPP<NumSrcArgs, DstVT, Src0VT, Src1VT>.ret, + getHas64BitOps<NumSrcArgs, DstVT, Src0VT, Src1VT>.ret); +} + +// Function that checks if instruction supports DPP and SDWA +class getHasExt <int NumSrcArgs, ValueType DstVT = i32, ValueType Src0VT = i32, + ValueType Src1VT = i32> { + bit ret = !or(getHasDPP<NumSrcArgs, DstVT, Src0VT, Src1VT>.ret, + getHasSDWA<NumSrcArgs, DstVT, Src0VT, Src1VT>.ret); +} + +// Return an AGPR+VGPR operand class for the given VGPR register class. +class getLdStRegisterOperand<RegisterClass RC> { + RegisterOperand ret = + !if(!eq(RC.Size, 32), AVLdSt_32, + !if(!eq(RC.Size, 64), AVLdSt_64, + !if(!eq(RC.Size, 96), AVLdSt_96, + !if(!eq(RC.Size, 128), AVLdSt_128, + !if(!eq(RC.Size, 160), AVLdSt_160, + RegisterOperand<VReg_1> // invalid register + ))))); +} + +class BitOr<bit a, bit b> { + bit ret = !if(a, 1, !if(b, 1, 0)); +} + +class BitAnd<bit a, bit b> { + bit ret = !if(a, !if(b, 1, 0), 0); } def PatGenMode { @@ -2077,8 +2146,9 @@ class VOPProfile <list<ValueType> _ArgVT, bit _EnableF32SrcMods = 0, field bit HasExt = getHasExt<NumSrcArgs, DstVT, Src0VT, Src1VT>.ret; field bit HasExtDPP = getHasDPP<NumSrcArgs, DstVT, Src0VT, Src1VT>.ret; - field bit HasExtSDWA = HasExt; - field bit HasExtSDWA9 = HasExt; + field bit HasExt64BitDPP = getHasExt64BitDPP<NumSrcArgs, DstVT, Src0VT, Src1VT>.ret; + field bit HasExtSDWA = getHasSDWA<NumSrcArgs, DstVT, Src0VT, Src1VT>.ret; + field bit HasExtSDWA9 = HasExtSDWA; field int NeedPatGen = PatGenMode.NoPattern; field bit IsMAI = 0; @@ -2144,6 +2214,7 @@ class VOPProfile <list<ValueType> _ArgVT, bit _EnableF32SrcMods = 0, class VOP_NO_EXT <VOPProfile p> : VOPProfile <p.ArgVT> { let HasExt = 0; let HasExtDPP = 0; + let HasExt64BitDPP = 0; let HasExtSDWA = 0; let HasExtSDWA9 = 0; } @@ -2191,6 +2262,7 @@ def VOP_I32_F64 : VOPProfile <[i32, f64, untyped, untyped]>; def VOP_I32_I32 : VOPProfile <[i32, i32, untyped, untyped]>; def VOP_F16_F32 : VOPProfile <[f16, f32, untyped, untyped]>; def VOP_F32_F16 : VOPProfile <[f32, f16, untyped, untyped]>; +def VOP_I64_I64 : VOPProfile <[i64, i64, untyped, untyped]>; def VOP_F32_F32_F16 : VOPProfile <[f32, f32, f16, untyped]>; def VOP_F32_F32_F32 : VOPProfile <[f32, f32, f32, untyped]>; @@ -2234,6 +2306,16 @@ def VOP_V4I32_I32_I32_V4I32 : VOPProfile <[v4i32, i32, i32, v4i32]>; def VOP_V16I32_I32_I32_V16I32 : VOPProfile <[v16i32, i32, i32, v16i32]>; def VOP_V32I32_I32_I32_V32I32 : VOPProfile <[v32i32, i32, i32, v32i32]>; +def VOP_V4F64_F64_F64_V4F64 : VOPProfile <[v4f64, f64, f64, v4f64]>; +def VOP_V1F64_F64_F64_V1F64 : VOPProfile <[v1f64, f64, f64, v1f64]>; + +def VOP_V2F32_V2F32_V2F32_V2F32 : VOPProfile <[v2f32, v2f32, v2f32, v2f32]>; +def VOP_V2F32_V2F32_V2F32 : VOPProfile <[v2f32, v2f32, v2f32, untyped]>; +def VOP_V2I32_V2I32_V2I32 : VOPProfile <[v2i32, v2i32, v2i32, untyped]>; +def VOP_V4F32_V4I16_V4I16_V4F32 : VOPProfile <[v4f32, v4i16, v4i16, v4f32]>; +def VOP_V16F32_V4I16_V4I16_V16F32 : VOPProfile <[v16f32, v4i16, v4i16, v16f32]>; +def VOP_V32F32_V4I16_V4I16_V32F32 : VOPProfile <[v32f32, v4i16, v4i16, v32f32]>; + class Commutable_REV <string revOp, bit isOrig> { string RevOp = revOp; bit IsOrig = isOrig; @@ -2372,7 +2454,8 @@ def getMCOpcodeGen : InstrMapping { [!cast<string>(SIEncodingFamily.GFX80)], [!cast<string>(SIEncodingFamily.GFX9)], [!cast<string>(SIEncodingFamily.GFX10)], - [!cast<string>(SIEncodingFamily.SDWA10)]]; + [!cast<string>(SIEncodingFamily.SDWA10)], + [!cast<string>(SIEncodingFamily.GFX90A)]]; } // Get equivalent SOPK instruction. diff --git a/llvm/lib/Target/AMDGPU/SIInstructions.td b/llvm/lib/Target/AMDGPU/SIInstructions.td index bdc6b94ca6d6..2482649f58c6 100644 --- a/llvm/lib/Target/AMDGPU/SIInstructions.td +++ b/llvm/lib/Target/AMDGPU/SIInstructions.td @@ -41,18 +41,21 @@ multiclass V_INTERP_P1_F32_m : VINTRP_m < (i32 timm:$attrchan), (i32 timm:$attr), M0))] >; -let OtherPredicates = [has32BankLDS] in { +let OtherPredicates = [has32BankLDS, isNotGFX90APlus] in { defm V_INTERP_P1_F32 : V_INTERP_P1_F32_m; -} // End OtherPredicates = [has32BankLDS] +} // End OtherPredicates = [has32BankLDS, isNotGFX90APlus] -let OtherPredicates = [has16BankLDS], Constraints = "@earlyclobber $vdst", isAsmParserOnly=1 in { +let OtherPredicates = [has16BankLDS, isNotGFX90APlus], + Constraints = "@earlyclobber $vdst", isAsmParserOnly=1 in { defm V_INTERP_P1_F32_16bank : V_INTERP_P1_F32_m; -} // End OtherPredicates = [has32BankLDS], Constraints = "@earlyclobber $vdst", isAsmParserOnly=1 +} // End OtherPredicates = [has32BankLDS, isNotGFX90APlus], + // Constraints = "@earlyclobber $vdst", isAsmParserOnly=1 +let OtherPredicates = [isNotGFX90APlus] in { let DisableEncoding = "$src0", Constraints = "$src0 = $vdst" in { defm V_INTERP_P2_F32 : VINTRP_m < @@ -73,6 +76,8 @@ defm V_INTERP_MOV_F32 : VINTRP_m < [(set f32:$vdst, (int_amdgcn_interp_mov (i32 timm:$vsrc), (i32 timm:$attrchan), (i32 timm:$attr), M0))]>; +} // End OtherPredicates = [isNotGFX90APlus] + } // End Uses = [MODE, M0, EXEC] //===----------------------------------------------------------------------===// @@ -86,11 +91,6 @@ def ATOMIC_FENCE : SPseudoInstSI< let maybeAtomic = 1; } -def VOP_I64_I64_DPP : VOPProfile <[i64, i64, untyped, untyped]> { - let HasExt = 1; - let HasExtDPP = 1; -} - let hasSideEffects = 0, mayLoad = 0, mayStore = 0, Uses = [EXEC] in { // For use in patterns @@ -107,7 +107,7 @@ def V_MOV_B64_PSEUDO : VPseudoInstSI <(outs VReg_64:$vdst), (ins VSrc_b64:$src0)>; // 64-bit vector move with dpp. Expanded post-RA. -def V_MOV_B64_DPP_PSEUDO : VOP_DPP_Pseudo <"v_mov_b64_dpp", VOP_I64_I64_DPP> { +def V_MOV_B64_DPP_PSEUDO : VOP_DPP_Pseudo <"v_mov_b64_dpp", VOP_I64_I64> { let Size = 16; // Requires two 8-byte v_mov_b32_dpp to complete. } @@ -1373,6 +1373,19 @@ def : GCNPat < // sub1) // >; +// COPY_TO_REGCLASS is needed to avoid using SCC from S_XOR_B32 instead +// of the real value. +def : GCNPat < + (fneg (v2f32 SReg_64:$src)), + (v2f32 (REG_SEQUENCE SReg_64, + (f32 (COPY_TO_REGCLASS (S_XOR_B32 (i32 (EXTRACT_SUBREG $src, sub0)), + (i32 (S_MOV_B32 (i32 0x80000000)))), + SReg_32)), sub0, + (f32 (COPY_TO_REGCLASS (S_XOR_B32 (i32 (EXTRACT_SUBREG $src, sub1)), + (i32 (S_MOV_B32 (i32 0x80000000)))), + SReg_32)), sub1)) +>; + } // End let AddedComplexity = 1 def : GCNPat < @@ -1438,6 +1451,15 @@ def : GCNPat < >; def : GCNPat < + (getDivergentFrag<fneg>.ret (v2f32 VReg_64:$src)), + (V_PK_ADD_F32 11 /* OP_SEL_1 | NEG_LO | HEG_HI */, VReg_64:$src, + 11 /* OP_SEL_1 | NEG_LO | HEG_HI */, 0, + 0, 0, 0, 0, 0) +> { + let SubtargetPredicate = HasPackedFP32Ops; +} + +def : GCNPat < (fcopysign f16:$src0, f16:$src1), (V_BFI_B32_e64 (S_MOV_B32 (i32 0x00007fff)), $src0, $src1) >; @@ -1556,9 +1578,16 @@ def : GCNPat < /********** Intrinsic Patterns **********/ /********** ================== **********/ +let OtherPredicates = [isNotGFX90APlus] in // FIXME: Should use _e64 and select source modifiers. def : POW_Common <V_LOG_F32_e32, V_EXP_F32_e32, V_MUL_LEGACY_F32_e32>; +let OtherPredicates = [isGFX90APlus] in +def : GCNPat < + (fpow f32:$src0, f32:$src1), + (V_EXP_F32_e32 (V_MUL_LEGACY_F32_e64 0, f32:$src1, SRCMODS.NONE, (V_LOG_F32_e32 f32:$src0), 0, 0)) +>; + def : GCNPat < (i32 (sext i1:$src0)), (V_CNDMASK_B32_e64 /*src0mod*/(i32 0), /*src0*/(i32 0), @@ -2167,6 +2196,17 @@ def : GCNPat < SRCMODS.NONE, $src2) >; +let SubtargetPredicate = isGFX90APlus in +def : GCNPat < + (fma (f64 (VOP3Mods0 f64:$src0, i32:$src0_modifiers, i1:$clamp, i32:$omod)), + (f64 (VOP3Mods f64:$src1, i32:$src1_modifiers)), + (f64 (VOP3NoMods f64:$src2))), + (V_FMAC_F64_e64 $src0_modifiers, $src0, $src1_modifiers, $src1, + SRCMODS.NONE, $src2, $clamp, $omod) +>; + +// COPY is workaround tablegen bug from multiple outputs +// from S_LSHL_B32's multiple outputs from implicit scc def. def : GCNPat < (v2i16 (build_vector (i16 0), (i16 SReg_32:$src1))), (S_LSHL_B32 SReg_32:$src1, (i16 16)) @@ -2652,6 +2692,8 @@ def G_AMDGPU_BUFFER_ATOMIC_XOR : BufferAtomicGenericInstruction; def G_AMDGPU_BUFFER_ATOMIC_INC : BufferAtomicGenericInstruction; def G_AMDGPU_BUFFER_ATOMIC_DEC : BufferAtomicGenericInstruction; def G_AMDGPU_BUFFER_ATOMIC_FADD : BufferAtomicGenericInstruction; +def G_AMDGPU_BUFFER_ATOMIC_FMIN : BufferAtomicGenericInstruction; +def G_AMDGPU_BUFFER_ATOMIC_FMAX : BufferAtomicGenericInstruction; def G_AMDGPU_BUFFER_ATOMIC_CMPSWAP : AMDGPUGenericInstruction { let OutOperandList = (outs type0:$dst); diff --git a/llvm/lib/Target/AMDGPU/SILoadStoreOptimizer.cpp b/llvm/lib/Target/AMDGPU/SILoadStoreOptimizer.cpp index b959bb3eb9c6..4545994726e5 100644 --- a/llvm/lib/Target/AMDGPU/SILoadStoreOptimizer.cpp +++ b/llvm/lib/Target/AMDGPU/SILoadStoreOptimizer.cpp @@ -107,6 +107,7 @@ class SILoadStoreOptimizer : public MachineFunctionPass { bool GLC; bool SLC; bool DLC; + bool SCCB; // vmem only. bool UseST64; int AddrIdx[MaxAddressRegs]; const MachineOperand *AddrReg[MaxAddressRegs]; @@ -199,6 +200,7 @@ private: const CombineInfo &Paired); const TargetRegisterClass *getTargetRegisterClass(const CombineInfo &CI, const CombineInfo &Paired); + const TargetRegisterClass *getDataRegClass(const MachineInstr &MI) const; bool checkAndPrepareMerge(CombineInfo &CI, CombineInfo &Paired, SmallVectorImpl<MachineInstr *> &InstsToMove); @@ -304,6 +306,16 @@ static unsigned getOpcodeWidth(const MachineInstr &MI, const SIInstrInfo &TII) { return 2; case AMDGPU::S_BUFFER_LOAD_DWORDX4_IMM: return 4; + case AMDGPU::DS_READ_B32: LLVM_FALLTHROUGH; + case AMDGPU::DS_READ_B32_gfx9: LLVM_FALLTHROUGH; + case AMDGPU::DS_WRITE_B32: LLVM_FALLTHROUGH; + case AMDGPU::DS_WRITE_B32_gfx9: + return 1; + case AMDGPU::DS_READ_B64: LLVM_FALLTHROUGH; + case AMDGPU::DS_READ_B64_gfx9: LLVM_FALLTHROUGH; + case AMDGPU::DS_WRITE_B64: LLVM_FALLTHROUGH; + case AMDGPU::DS_WRITE_B64_gfx9: + return 2; default: return 0; } @@ -526,6 +538,9 @@ void SILoadStoreOptimizer::CombineInfo::setMI(MachineBasicBlock::iterator MI, SLC = TII.getNamedOperand(*I, AMDGPU::OpName::slc)->getImm(); } DLC = TII.getNamedOperand(*I, AMDGPU::OpName::dlc)->getImm(); + if (InstClass != S_BUFFER_LOAD_IMM) { + SCCB = TII.getNamedOperand(*I, AMDGPU::OpName::sccb)->getImm(); + } } AddressRegs Regs = getRegs(Opc, TII); @@ -784,7 +799,8 @@ bool SILoadStoreOptimizer::offsetsCanBeCombined(CombineInfo &CI, return (EltOffset0 + CI.Width == EltOffset1 || EltOffset1 + Paired.Width == EltOffset0) && CI.GLC == Paired.GLC && CI.DLC == Paired.DLC && - (CI.InstClass == S_BUFFER_LOAD_IMM || CI.SLC == Paired.SLC); + (CI.InstClass == S_BUFFER_LOAD_IMM || + (CI.SLC == Paired.SLC && CI.SCCB == Paired.SCCB)); } // If the offset in elements doesn't fit in 8-bits, we might be able to use @@ -864,6 +880,26 @@ bool SILoadStoreOptimizer::widthsFit(const GCNSubtarget &STM, } } +const TargetRegisterClass * +SILoadStoreOptimizer::getDataRegClass(const MachineInstr &MI) const { + if (const auto *Dst = TII->getNamedOperand(MI, AMDGPU::OpName::vdst)) { + return TRI->getRegClassForReg(*MRI, Dst->getReg()); + } + if (const auto *Src = TII->getNamedOperand(MI, AMDGPU::OpName::vdata)) { + return TRI->getRegClassForReg(*MRI, Src->getReg()); + } + if (const auto *Src = TII->getNamedOperand(MI, AMDGPU::OpName::data0)) { + return TRI->getRegClassForReg(*MRI, Src->getReg()); + } + if (const auto *Dst = TII->getNamedOperand(MI, AMDGPU::OpName::sdst)) { + return TRI->getRegClassForReg(*MRI, Dst->getReg()); + } + if (const auto *Src = TII->getNamedOperand(MI, AMDGPU::OpName::sdata)) { + return TRI->getRegClassForReg(*MRI, Src->getReg()); + } + return nullptr; +} + /// This function assumes that CI comes before Paired in a basic block. bool SILoadStoreOptimizer::checkAndPrepareMerge( CombineInfo &CI, CombineInfo &Paired, @@ -896,6 +932,9 @@ bool SILoadStoreOptimizer::checkAndPrepareMerge( DenseSet<Register> PhysRegUsesToMove; addDefsUsesToList(*CI.I, RegDefsToMove, PhysRegUsesToMove); + const TargetRegisterClass *DataRC = getDataRegClass(*CI.I); + bool IsAGPR = TRI->hasAGPRs(DataRC); + MachineBasicBlock::iterator E = std::next(Paired.I); MachineBasicBlock::iterator MBBI = std::next(CI.I); MachineBasicBlock::iterator MBBE = CI.I->getParent()->end(); @@ -964,6 +1003,17 @@ bool SILoadStoreOptimizer::checkAndPrepareMerge( continue; if (&*MBBI == &*Paired.I) { + if (TRI->hasAGPRs(getDataRegClass(*MBBI)) != IsAGPR) + return false; + // FIXME: nothing is illegal in a ds_write2 opcode with two AGPR data + // operands. However we are reporting that ds_write2 shall have + // only VGPR data so that machine copy propagation does not + // create an illegal instruction with a VGPR and AGPR sources. + // Consequenctially if we create such instruction the verifier + // will complain. + if (IsAGPR && CI.InstClass == DS_WRITE) + return false; + // We need to go through the list of instructions that we plan to // move and make sure they are all safe to move down past the merged // instruction. @@ -1037,8 +1087,7 @@ SILoadStoreOptimizer::mergeRead2Pair(CombineInfo &CI, CombineInfo &Paired, const MCInstrDesc &Read2Desc = TII->get(Opc); - const TargetRegisterClass *SuperRC = - (CI.EltSize == 4) ? &AMDGPU::VReg_64RegClass : &AMDGPU::VReg_128RegClass; + const TargetRegisterClass *SuperRC = getTargetRegisterClass(CI, Paired); Register DestReg = MRI->createVirtualRegister(SuperRC); DebugLoc DL = CI.I->getDebugLoc(); @@ -1317,6 +1366,7 @@ MachineBasicBlock::iterator SILoadStoreOptimizer::mergeBufferLoadPair( .addImm(0) // tfe .addImm(CI.DLC) // dlc .addImm(0) // swz + .addImm(CI.SCCB) // scc .addMemOperand(combineKnownAdjacentMMOs(*MBB->getParent(), MMOa, MMOb)); std::pair<unsigned, unsigned> SubRegIdx = getSubRegIdxs(CI, Paired); @@ -1384,6 +1434,7 @@ MachineBasicBlock::iterator SILoadStoreOptimizer::mergeTBufferLoadPair( .addImm(0) // tfe .addImm(CI.DLC) // dlc .addImm(0) // swz + .addImm(CI.SCCB) // scc .addMemOperand( combineKnownAdjacentMMOs(*MBB->getParent(), MMOa, MMOb)); @@ -1464,6 +1515,7 @@ MachineBasicBlock::iterator SILoadStoreOptimizer::mergeTBufferStorePair( .addImm(0) // tfe .addImm(CI.DLC) // dlc .addImm(0) // swz + .addImm(CI.SCCB) // scc .addMemOperand( combineKnownAdjacentMMOs(*MBB->getParent(), MMOa, MMOb)); @@ -1559,18 +1611,27 @@ SILoadStoreOptimizer::getTargetRegisterClass(const CombineInfo &CI, case 16: return &AMDGPU::SGPR_512RegClass; } - } else { - switch (CI.Width + Paired.Width) { - default: - return nullptr; - case 2: - return &AMDGPU::VReg_64RegClass; - case 3: - return &AMDGPU::VReg_96RegClass; - case 4: - return &AMDGPU::VReg_128RegClass; - } } + const TargetRegisterClass *RC = nullptr; + + switch (CI.Width + Paired.Width) { + default: + return nullptr; + case 2: + RC = &AMDGPU::VReg_64RegClass; + break; + case 3: + RC = &AMDGPU::VReg_96RegClass; + break; + case 4: + RC = &AMDGPU::VReg_128RegClass; + break; + } + + if (TRI->hasAGPRs(getDataRegClass(*CI.I))) + return TRI->getEquivalentAGPRClass(RC); + + return RC; } MachineBasicBlock::iterator SILoadStoreOptimizer::mergeBufferStorePair( @@ -1624,6 +1685,7 @@ MachineBasicBlock::iterator SILoadStoreOptimizer::mergeBufferStorePair( .addImm(0) // tfe .addImm(CI.DLC) // dlc .addImm(0) // swz + .addImm(CI.SCCB) // scc .addMemOperand(combineKnownAdjacentMMOs(*MBB->getParent(), MMOa, MMOb)); moveInstsAfter(MIB, InstsToMove); diff --git a/llvm/lib/Target/AMDGPU/SIMemoryLegalizer.cpp b/llvm/lib/Target/AMDGPU/SIMemoryLegalizer.cpp index e7158a72fc0e..d4dd5a381a71 100644 --- a/llvm/lib/Target/AMDGPU/SIMemoryLegalizer.cpp +++ b/llvm/lib/Target/AMDGPU/SIMemoryLegalizer.cpp @@ -300,6 +300,20 @@ public: SIAtomicScope Scope, SIAtomicAddrSpace AddrSpace) const = 0; + /// Update \p MI memory store instruction to bypass any caches up to + /// the \p Scope memory scope for address spaces \p + /// AddrSpace. Return true iff the instruction was modified. + virtual bool enableStoreCacheBypass(const MachineBasicBlock::iterator &MI, + SIAtomicScope Scope, + SIAtomicAddrSpace AddrSpace) const = 0; + + /// Update \p MI memory read-modify-write instruction to bypass any caches up + /// to the \p Scope memory scope for address spaces \p AddrSpace. Return true + /// iff the instruction was modified. + virtual bool enableRMWCacheBypass(const MachineBasicBlock::iterator &MI, + SIAtomicScope Scope, + SIAtomicAddrSpace AddrSpace) const = 0; + /// Update \p MI memory instruction of kind \p Op associated with address /// spaces \p AddrSpace to indicate it is volatile and/or nontemporal. Return /// true iff the instruction was modified. @@ -372,6 +386,14 @@ public: SIAtomicScope Scope, SIAtomicAddrSpace AddrSpace) const override; + bool enableStoreCacheBypass(const MachineBasicBlock::iterator &MI, + SIAtomicScope Scope, + SIAtomicAddrSpace AddrSpace) const override; + + bool enableRMWCacheBypass(const MachineBasicBlock::iterator &MI, + SIAtomicScope Scope, + SIAtomicAddrSpace AddrSpace) const override; + bool enableVolatileAndOrNonTemporal(MachineBasicBlock::iterator &MI, SIAtomicAddrSpace AddrSpace, SIMemOp Op, bool IsVolatile, @@ -408,6 +430,55 @@ public: }; +class SIGfx90ACacheControl : public SIGfx7CacheControl { +protected: + + /// Sets SCC bit to "true" if present in \p MI. Returns true if \p MI + /// is modified, false otherwise. + bool enableSCCBit(const MachineBasicBlock::iterator &MI) const { + return enableNamedBit<AMDGPU::OpName::sccb>(MI); + } + +public: + + SIGfx90ACacheControl(const GCNSubtarget &ST) : SIGfx7CacheControl(ST) {}; + + bool enableLoadCacheBypass(const MachineBasicBlock::iterator &MI, + SIAtomicScope Scope, + SIAtomicAddrSpace AddrSpace) const override; + + bool enableStoreCacheBypass(const MachineBasicBlock::iterator &MI, + SIAtomicScope Scope, + SIAtomicAddrSpace AddrSpace) const override; + + bool enableRMWCacheBypass(const MachineBasicBlock::iterator &MI, + SIAtomicScope Scope, + SIAtomicAddrSpace AddrSpace) const override; + + bool enableVolatileAndOrNonTemporal(MachineBasicBlock::iterator &MI, + SIAtomicAddrSpace AddrSpace, SIMemOp Op, + bool IsVolatile, + bool IsNonTemporal) const override; + + bool insertWait(MachineBasicBlock::iterator &MI, + SIAtomicScope Scope, + SIAtomicAddrSpace AddrSpace, + SIMemOp Op, + bool IsCrossAddrSpaceOrdering, + Position Pos) const override; + + bool insertAcquire(MachineBasicBlock::iterator &MI, + SIAtomicScope Scope, + SIAtomicAddrSpace AddrSpace, + Position Pos) const override; + + bool insertRelease(MachineBasicBlock::iterator &MI, + SIAtomicScope Scope, + SIAtomicAddrSpace AddrSpace, + bool IsCrossAddrSpaceOrdering, + Position Pos) const override; +}; + class SIGfx10CacheControl : public SIGfx7CacheControl { protected: @@ -717,6 +788,8 @@ SICacheControl::SICacheControl(const GCNSubtarget &ST) : ST(ST) { /* static */ std::unique_ptr<SICacheControl> SICacheControl::create(const GCNSubtarget &ST) { GCNSubtarget::Generation Generation = ST.getGeneration(); + if (ST.hasGFX90AInsts()) + return std::make_unique<SIGfx90ACacheControl>(ST); if (Generation <= AMDGPUSubtarget::SOUTHERN_ISLANDS) return std::make_unique<SIGfx6CacheControl>(ST); if (Generation < AMDGPUSubtarget::GFX10) @@ -757,6 +830,32 @@ bool SIGfx6CacheControl::enableLoadCacheBypass( return Changed; } +bool SIGfx6CacheControl::enableStoreCacheBypass( + const MachineBasicBlock::iterator &MI, + SIAtomicScope Scope, + SIAtomicAddrSpace AddrSpace) const { + assert(!MI->mayLoad() && MI->mayStore()); + bool Changed = false; + + /// The L1 cache is write through so does not need to be bypassed. There is no + /// bypass control for the L2 cache at the isa level. + + return Changed; +} + +bool SIGfx6CacheControl::enableRMWCacheBypass( + const MachineBasicBlock::iterator &MI, + SIAtomicScope Scope, + SIAtomicAddrSpace AddrSpace) const { + assert(MI->mayLoad() && MI->mayStore()); + bool Changed = false; + + /// The L1 cache is write through so does not need to be bypassed. There is no + /// bypass control for the L2 cache at the isa level. + + return Changed; +} + bool SIGfx6CacheControl::enableVolatileAndOrNonTemporal( MachineBasicBlock::iterator &MI, SIAtomicAddrSpace AddrSpace, SIMemOp Op, bool IsVolatile, bool IsNonTemporal) const { @@ -1000,6 +1099,300 @@ bool SIGfx7CacheControl::insertAcquire(MachineBasicBlock::iterator &MI, return Changed; } +bool SIGfx90ACacheControl::enableLoadCacheBypass( + const MachineBasicBlock::iterator &MI, + SIAtomicScope Scope, + SIAtomicAddrSpace AddrSpace) const { + assert(MI->mayLoad() && !MI->mayStore()); + bool Changed = false; + + if ((AddrSpace & SIAtomicAddrSpace::GLOBAL) != SIAtomicAddrSpace::NONE) { + switch (Scope) { + case SIAtomicScope::SYSTEM: + Changed |= enableSCCBit(MI); + Changed |= enableGLCBit(MI); + break; + case SIAtomicScope::AGENT: + Changed |= enableGLCBit(MI); + break; + case SIAtomicScope::WORKGROUP: + // In threadgroup split mode the waves of a work-group can be executing on + // different CUs. Therefore need to bypass the L1 which is per CU. + // Otherwise in non-threadgroup split mode all waves of a work-group are + // on the same CU, and so the L1 does not need to be bypassed. + if (ST.isTgSplitEnabled()) Changed |= enableGLCBit(MI); + break; + case SIAtomicScope::WAVEFRONT: + case SIAtomicScope::SINGLETHREAD: + // No cache to bypass. + break; + default: + llvm_unreachable("Unsupported synchronization scope"); + } + } + + /// The scratch address space does not need the global memory caches + /// to be bypassed as all memory operations by the same thread are + /// sequentially consistent, and no other thread can access scratch + /// memory. + + /// Other address spaces do not have a cache. + + return Changed; +} + +bool SIGfx90ACacheControl::enableStoreCacheBypass( + const MachineBasicBlock::iterator &MI, + SIAtomicScope Scope, + SIAtomicAddrSpace AddrSpace) const { + assert(!MI->mayLoad() && MI->mayStore()); + bool Changed = false; + + if ((AddrSpace & SIAtomicAddrSpace::GLOBAL) != SIAtomicAddrSpace::NONE) { + switch (Scope) { + case SIAtomicScope::SYSTEM: + Changed |= enableSCCBit(MI); + LLVM_FALLTHROUGH; + case SIAtomicScope::AGENT: + /// Do not set glc for store atomic operations as they implicitly write + /// through the L1 cache. + break; + case SIAtomicScope::WORKGROUP: + case SIAtomicScope::WAVEFRONT: + case SIAtomicScope::SINGLETHREAD: + // No cache to bypass. Store atomics implicitly write through the L1 + // cache. + break; + default: + llvm_unreachable("Unsupported synchronization scope"); + } + } + + /// The scratch address space does not need the global memory caches + /// to be bypassed as all memory operations by the same thread are + /// sequentially consistent, and no other thread can access scratch + /// memory. + + /// Other address spaces do not have a cache. + + return Changed; +} + +bool SIGfx90ACacheControl::enableRMWCacheBypass( + const MachineBasicBlock::iterator &MI, + SIAtomicScope Scope, + SIAtomicAddrSpace AddrSpace) const { + assert(MI->mayLoad() && MI->mayStore()); + bool Changed = false; + + if ((AddrSpace & SIAtomicAddrSpace::GLOBAL) != SIAtomicAddrSpace::NONE) { + switch (Scope) { + case SIAtomicScope::SYSTEM: + Changed |= enableSCCBit(MI); + LLVM_FALLTHROUGH; + case SIAtomicScope::AGENT: + /// Do not set glc for RMW atomic operations as they implicitly bypass + /// the L1 cache, and the glc bit is instead used to indicate if they are + /// return or no-return. + break; + case SIAtomicScope::WORKGROUP: + case SIAtomicScope::WAVEFRONT: + case SIAtomicScope::SINGLETHREAD: + // No cache to bypass. RMW atomics implicitly bypass the L1 cache. + break; + default: + llvm_unreachable("Unsupported synchronization scope"); + } + } + + return Changed; +} + +bool SIGfx90ACacheControl::enableVolatileAndOrNonTemporal( + MachineBasicBlock::iterator &MI, SIAtomicAddrSpace AddrSpace, SIMemOp Op, + bool IsVolatile, bool IsNonTemporal) const { + // Only handle load and store, not atomic read-modify-write insructions. The + // latter use glc to indicate if the atomic returns a result and so must not + // be used for cache control. + assert(MI->mayLoad() ^ MI->mayStore()); + + // Only update load and store, not LLVM IR atomic read-modify-write + // instructions. The latter are always marked as volatile so cannot sensibly + // handle it as do not want to pessimize all atomics. Also they do not support + // the nontemporal attribute. + assert( Op == SIMemOp::LOAD || Op == SIMemOp::STORE); + + bool Changed = false; + + if (IsVolatile) { + if (Op == SIMemOp::LOAD) { + Changed |= enableGLCBit(MI); + } + Changed |= enableSCCBit(MI); + + // Ensure operation has completed at system scope to cause all volatile + // operations to be visible outside the program in a global order. Do not + // request cross address space as only the global address space can be + // observable outside the program, so no need to cause a waitcnt for LDS + // address space operations. + Changed |= insertWait(MI, SIAtomicScope::SYSTEM, AddrSpace, Op, false, + Position::AFTER); + + return Changed; + } + + if (IsNonTemporal) { + // Request L1 MISS_EVICT and L2 STREAM for load and store instructions. + Changed |= enableGLCBit(MI); + Changed |= enableSLCBit(MI); + return Changed; + } + + return Changed; +} + +bool SIGfx90ACacheControl::insertWait(MachineBasicBlock::iterator &MI, + SIAtomicScope Scope, + SIAtomicAddrSpace AddrSpace, + SIMemOp Op, + bool IsCrossAddrSpaceOrdering, + Position Pos) const { + if (ST.isTgSplitEnabled()) { + // In threadgroup split mode the waves of a work-group can be executing on + // different CUs. Therefore need to wait for global or GDS memory operations + // to complete to ensure they are visible to waves in the other CUs. + // Otherwise in non-threadgroup split mode all waves of a work-group are on + // the same CU, so no need to wait for global memory as all waves in the + // work-group access the same the L1, nor wait for GDS as access are ordered + // on a CU. + if (((AddrSpace & (SIAtomicAddrSpace::GLOBAL | SIAtomicAddrSpace::SCRATCH | + SIAtomicAddrSpace::GDS)) != SIAtomicAddrSpace::NONE) && + (Scope == SIAtomicScope::WORKGROUP)) { + // Same as GFX7 using agent scope. + Scope = SIAtomicScope::AGENT; + } + // In threadgroup split mode LDS cannot be allocated so no need to wait for + // LDS memory operations. + AddrSpace &= ~SIAtomicAddrSpace::LDS; + } + return SIGfx7CacheControl::insertWait(MI, Scope, AddrSpace, Op, + IsCrossAddrSpaceOrdering, Pos); +} + +bool SIGfx90ACacheControl::insertAcquire(MachineBasicBlock::iterator &MI, + SIAtomicScope Scope, + SIAtomicAddrSpace AddrSpace, + Position Pos) const { + if (!InsertCacheInv) + return false; + + bool Changed = false; + + MachineBasicBlock &MBB = *MI->getParent(); + DebugLoc DL = MI->getDebugLoc(); + + if (Pos == Position::AFTER) + ++MI; + + if ((AddrSpace & SIAtomicAddrSpace::GLOBAL) != SIAtomicAddrSpace::NONE) { + switch (Scope) { + case SIAtomicScope::SYSTEM: + // Ensures that following loads will not see stale remote VMEM data or + // stale local VMEM data with MTYPE NC. Local VMEM data with MTYPE RW and + // CC will never be stale due to the local memory probes. + BuildMI(MBB, MI, DL, TII->get(AMDGPU::BUFFER_INVL2)); + // Inserting a "S_WAITCNT vmcnt(0)" after is not required because the + // hardware does not reorder memory operations by the same wave with + // respect to a preceding "BUFFER_INVL2". The invalidate is guaranteed to + // remove any cache lines of earlier writes by the same wave and ensures + // later reads by the same wave will refetch the cache lines. + Changed = true; + break; + case SIAtomicScope::AGENT: + // Same as GFX7. + break; + case SIAtomicScope::WORKGROUP: + // In threadgroup split mode the waves of a work-group can be executing on + // different CUs. Therefore need to invalidate the L1 which is per CU. + // Otherwise in non-threadgroup split mode all waves of a work-group are + // on the same CU, and so the L1 does not need to be invalidated. + if (ST.isTgSplitEnabled()) { + // Same as GFX7 using agent scope. + Scope = SIAtomicScope::AGENT; + } + break; + case SIAtomicScope::WAVEFRONT: + case SIAtomicScope::SINGLETHREAD: + // Same as GFX7. + break; + default: + llvm_unreachable("Unsupported synchronization scope"); + } + } + + /// The scratch address space does not need the global memory cache + /// to be flushed as all memory operations by the same thread are + /// sequentially consistent, and no other thread can access scratch + /// memory. + + /// Other address spaces do not have a cache. + + if (Pos == Position::AFTER) + --MI; + + Changed |= SIGfx7CacheControl::insertAcquire(MI, Scope, AddrSpace, Pos); + + return Changed; +} + +bool SIGfx90ACacheControl::insertRelease(MachineBasicBlock::iterator &MI, + SIAtomicScope Scope, + SIAtomicAddrSpace AddrSpace, + bool IsCrossAddrSpaceOrdering, + Position Pos) const { + bool Changed = false; + + MachineBasicBlock &MBB = *MI->getParent(); + DebugLoc DL = MI->getDebugLoc(); + + if (Pos == Position::AFTER) + ++MI; + + if ((AddrSpace & SIAtomicAddrSpace::GLOBAL) != SIAtomicAddrSpace::NONE) { + switch (Scope) { + case SIAtomicScope::SYSTEM: + // Inserting a "S_WAITCNT vmcnt(0)" before is not required because the + // hardware does not reorder memory operations by the same wave with + // respect to a following "BUFFER_WBL2". The "BUFFER_WBL2" is guaranteed + // to initiate writeback of any dirty cache lines of earlier writes by the + // same wave. A "S_WAITCNT vmcnt(0)" is needed after to ensure the + // writeback has completed. + BuildMI(MBB, MI, DL, TII->get(AMDGPU::BUFFER_WBL2)); + // Followed by same as GFX7, which will ensure the necessary "S_WAITCNT + // vmcnt(0)" needed by the "BUFFER_WBL2". + Changed = true; + break; + case SIAtomicScope::AGENT: + case SIAtomicScope::WORKGROUP: + case SIAtomicScope::WAVEFRONT: + case SIAtomicScope::SINGLETHREAD: + // Same as GFX7. + break; + default: + llvm_unreachable("Unsupported synchronization scope"); + } + } + + if (Pos == Position::AFTER) + --MI; + + Changed |= + SIGfx7CacheControl::insertRelease(MI, Scope, AddrSpace, + IsCrossAddrSpaceOrdering, Pos); + + return Changed; +} + bool SIGfx10CacheControl::enableLoadCacheBypass( const MachineBasicBlock::iterator &MI, SIAtomicScope Scope, @@ -1324,6 +1717,13 @@ bool SIMemoryLegalizer::expandStore(const SIMemOpInfo &MOI, bool Changed = false; if (MOI.isAtomic()) { + if (MOI.getOrdering() == AtomicOrdering::Monotonic || + MOI.getOrdering() == AtomicOrdering::Release || + MOI.getOrdering() == AtomicOrdering::SequentiallyConsistent) { + Changed |= CC->enableStoreCacheBypass(MI, MOI.getScope(), + MOI.getOrderingAddrSpace()); + } + if (MOI.getOrdering() == AtomicOrdering::Release || MOI.getOrdering() == AtomicOrdering::SequentiallyConsistent) Changed |= CC->insertRelease(MI, MOI.getScope(), @@ -1392,6 +1792,15 @@ bool SIMemoryLegalizer::expandAtomicCmpxchgOrRmw(const SIMemOpInfo &MOI, bool Changed = false; if (MOI.isAtomic()) { + if (MOI.getOrdering() == AtomicOrdering::Monotonic || + MOI.getOrdering() == AtomicOrdering::Acquire || + MOI.getOrdering() == AtomicOrdering::Release || + MOI.getOrdering() == AtomicOrdering::AcquireRelease || + MOI.getOrdering() == AtomicOrdering::SequentiallyConsistent) { + Changed |= CC->enableRMWCacheBypass(MI, MOI.getScope(), + MOI.getInstrAddrSpace()); + } + if (MOI.getOrdering() == AtomicOrdering::Release || MOI.getOrdering() == AtomicOrdering::AcquireRelease || MOI.getOrdering() == AtomicOrdering::SequentiallyConsistent || diff --git a/llvm/lib/Target/AMDGPU/SIProgramInfo.h b/llvm/lib/Target/AMDGPU/SIProgramInfo.h index 9b72d0829d80..b13afceba20e 100644 --- a/llvm/lib/Target/AMDGPU/SIProgramInfo.h +++ b/llvm/lib/Target/AMDGPU/SIProgramInfo.h @@ -41,10 +41,13 @@ struct SIProgramInfo { uint32_t ScratchBlocks = 0; uint64_t ComputePGMRSrc2 = 0; + uint64_t ComputePGMRSrc3GFX90A = 0; uint32_t NumVGPR = 0; uint32_t NumArchVGPR = 0; uint32_t NumAccVGPR = 0; + uint32_t AccumOffset = 0; + uint32_t TgSplit = 0; uint32_t NumSGPR = 0; uint32_t LDSSize = 0; bool FlatUsed = false; diff --git a/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp b/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp index 44d23ebc4f36..bb2ac725cab9 100644 --- a/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp +++ b/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp @@ -122,7 +122,9 @@ const MCPhysReg *SIRegisterInfo::getCalleeSavedRegs( case CallingConv::Fast: case CallingConv::Cold: case CallingConv::AMDGPU_Gfx: - return CSR_AMDGPU_HighRegs_SaveList; + return MF->getSubtarget<GCNSubtarget>().hasGFX90AInsts() + ? CSR_AMDGPU_HighRegs_With_AGPRs_SaveList + : CSR_AMDGPU_HighRegs_SaveList; default: { // Dummy to not crash RegisterClassInfo. static const MCPhysReg NoCalleeSavedReg = AMDGPU::NoRegister; @@ -143,7 +145,9 @@ const uint32_t *SIRegisterInfo::getCallPreservedMask(const MachineFunction &MF, case CallingConv::Fast: case CallingConv::Cold: case CallingConv::AMDGPU_Gfx: - return CSR_AMDGPU_HighRegs_RegMask; + return MF.getSubtarget<GCNSubtarget>().hasGFX90AInsts() + ? CSR_AMDGPU_HighRegs_With_AGPRs_RegMask + : CSR_AMDGPU_HighRegs_RegMask; default: return nullptr; } @@ -181,6 +185,14 @@ const uint32_t *SIRegisterInfo::getAllVGPRRegMask() const { return CSR_AMDGPU_AllVGPRs_RegMask; } +const uint32_t *SIRegisterInfo::getAllAGPRRegMask() const { + return CSR_AMDGPU_AllAGPRs_RegMask; +} + +const uint32_t *SIRegisterInfo::getAllVectorRegMask() const { + return CSR_AMDGPU_AllVectorRegs_RegMask; +} + const uint32_t *SIRegisterInfo::getAllAllocatableSRegMask() const { return CSR_AMDGPU_AllAllocatableSRegs_RegMask; } @@ -263,6 +275,12 @@ BitVector SIRegisterInfo::getReservedRegs(const MachineFunction &MF) const { } unsigned MaxNumVGPRs = ST.getMaxNumVGPRs(MF); + // TODO: In an entry function without calls and AGPRs used it is possible + // to use the whole register budget for VGPRs. Even more it shall + // be possible to estimate maximum AGPR/VGPR pressure and split + // register file accordingly. + if (ST.hasGFX90AInsts()) + MaxNumVGPRs /= 2; unsigned TotalNumVGPRs = AMDGPU::VGPR_32RegClass.getNumRegs(); for (unsigned i = MaxNumVGPRs; i < TotalNumVGPRs; ++i) { unsigned Reg = AMDGPU::VGPR_32RegClass.getRegister(i); @@ -327,6 +345,13 @@ BitVector SIRegisterInfo::getReservedRegs(const MachineFunction &MF) const { reserveRegisterTuples(Reserved, Reg); } + if (ST.hasGFX90AInsts()) + for (const TargetRegisterClass *RC : this->regclasses()) + if (getRegSizeInBits(*RC) > 32 && hasVectorRegisters(RC)) + for (unsigned Reg : *RC) + if (getEncodingValue(Reg) & 1) + Reserved.set(Reg); + // FIXME: Stop using reserved registers for this. for (MCPhysReg Reg : MFI->getAGPRSpillVGPRs()) reserveRegisterTuples(Reserved, Reg); @@ -730,6 +755,7 @@ static bool buildMUBUFOffsetLoadStore(const GCNSubtarget &ST, .addImm(0) // tfe .addImm(0) // dlc .addImm(0) // swz + .addImm(0) // scc .cloneMemRefs(*MI); const MachineOperand *VDataIn = TII->getNamedOperand(*MI, @@ -798,7 +824,8 @@ void SIRegisterInfo::buildSpillLoadStore(MachineBasicBlock::iterator MI, MCRegister SOffset = ScratchOffsetReg; const TargetRegisterClass *RC = getRegClassForReg(MF->getRegInfo(), ValueReg); - const bool IsAGPR = hasAGPRs(RC); + // On gfx90a+ AGPR is a regular VGPR acceptable for loads and stores. + const bool IsAGPR = !ST.hasGFX90AInsts() && hasAGPRs(RC); const unsigned RegWidth = AMDGPU::getRegBitWidth(RC->getID()) / 8; // Always use 4 byte operations for AGPRs because we need to scavenge @@ -996,6 +1023,7 @@ void SIRegisterInfo::buildSpillLoadStore(MachineBasicBlock::iterator MI, if (!IsFlat) MIB.addImm(0) // dlc .addImm(0); // swz + MIB.addImm(0); // scc MIB.addMemOperand(NewMMO); if (!IsAGPR && NeedSuperRegDef) @@ -2055,6 +2083,13 @@ bool SIRegisterInfo::shouldCoalesce(MachineInstr *MI, unsigned DstSize = getRegSizeInBits(*DstRC); unsigned NewSize = getRegSizeInBits(*NewRC); + // Do not allow coalescing between an odd and an even lanes as it will + // result in misaligned tuple access. + if (ST.hasGFX90AInsts() && !isSGPRClass(NewRC) && + (getChannelFromSubReg(DstSubReg) & 1) != + (getChannelFromSubReg(SubReg) & 1)) + return false; + // Do not increase size of registers beyond dword, we would need to allocate // adjacent registers and constraint regalloc more than needed. diff --git a/llvm/lib/Target/AMDGPU/SIRegisterInfo.h b/llvm/lib/Target/AMDGPU/SIRegisterInfo.h index 963da9b3536b..fedac6ab4fcf 100644 --- a/llvm/lib/Target/AMDGPU/SIRegisterInfo.h +++ b/llvm/lib/Target/AMDGPU/SIRegisterInfo.h @@ -279,6 +279,8 @@ public: LiveIntervals *LIS) const; const uint32_t *getAllVGPRRegMask() const; + const uint32_t *getAllAGPRRegMask() const; + const uint32_t *getAllVectorRegMask() const; const uint32_t *getAllAllocatableSRegMask() const; // \returns number of 32 bit registers covered by a \p LM diff --git a/llvm/lib/Target/AMDGPU/SIRegisterInfo.td b/llvm/lib/Target/AMDGPU/SIRegisterInfo.td index 5163bdab0e8a..816e844be58f 100644 --- a/llvm/lib/Target/AMDGPU/SIRegisterInfo.td +++ b/llvm/lib/Target/AMDGPU/SIRegisterInfo.td @@ -847,21 +847,36 @@ def VS_32 : RegisterClass<"AMDGPU", [i32, f32, i16, f16, v2i16, v2f16], 32, let isAllocatable = 0; } -def VS_64 : RegisterClass<"AMDGPU", [i64, f64], 32, (add VReg_64, SReg_64)> { +def VS_64 : RegisterClass<"AMDGPU", [i64, f64, v2f32], 32, (add VReg_64, SReg_64)> { let isAllocatable = 0; } -def AV_32 : RegisterClass<"AMDGPU", [i32, f32, i16, f16, v2i16, v2f16], 32, +def AV_32 : RegisterClass<"AMDGPU", VGPR_32.RegTypes, 32, (add AGPR_32, VGPR_32)> { let isAllocatable = 0; } -def AV_64 : RegisterClass<"AMDGPU", [i64, f64, v4f16], 32, +def AV_64 : RegisterClass<"AMDGPU", VReg_64.RegTypes, 32, (add AReg_64, VReg_64)> { let isAllocatable = 0; } } // End GeneratePressureSet = 0 +def AV_96 : RegisterClass<"AMDGPU", VReg_96.RegTypes, 32, + (add AReg_96, VReg_96)> { + let isAllocatable = 0; +} + +def AV_128 : RegisterClass<"AMDGPU", VReg_128.RegTypes, 32, + (add AReg_128, VReg_128)> { + let isAllocatable = 0; +} + +def AV_160 : RegisterClass<"AMDGPU", VReg_160.RegTypes, 32, + (add AReg_160, VReg_160)> { + let isAllocatable = 0; +} + //===----------------------------------------------------------------------===// // Register operands //===----------------------------------------------------------------------===// @@ -912,21 +927,38 @@ multiclass SIRegOperand32 <string rc, string MatchName, string opType, } } -multiclass SIRegOperand <string rc, string MatchName, string opType> : - SIRegOperand32<rc, MatchName, opType> { +multiclass SIRegOperand64 <string rc, string MatchName, string opType, + string rc_suffix = "_64", bit Vectors = 1> { let OperandNamespace = "AMDGPU" in { - def _b64 : RegisterOperand<!cast<RegisterClass>(rc#"_64")> { + def _b64 : RegisterOperand<!cast<RegisterClass>(rc#rc_suffix)> { let OperandType = opType#"_INT64"; let ParserMatchClass = RegImmMatcher<MatchName#"B64">; } - def _f64 : RegisterOperand<!cast<RegisterClass>(rc#"_64")> { + def _f64 : RegisterOperand<!cast<RegisterClass>(rc#rc_suffix)> { let OperandType = opType#"_FP64"; let ParserMatchClass = RegImmMatcher<MatchName#"F64">; } + + foreach _ = BoolToList<Vectors>.ret in + def _v2f32 : RegisterOperand<!cast<RegisterClass>(rc#rc_suffix)> { + let OperandType = opType#"_V2FP32"; + let ParserMatchClass = RegImmMatcher<MatchName#"V2FP32">; + let DecoderMethod = "decodeOperand_VSrcV232"; + } + foreach _ = BoolToList<Vectors>.ret in + def _v2b32 : RegisterOperand<!cast<RegisterClass>(rc#rc_suffix)> { + let OperandType = opType#"_V2INT32"; + let ParserMatchClass = RegImmMatcher<MatchName#"V2INT32">; + let DecoderMethod = "decodeOperand_VSrcV232"; + } } } +multiclass SIRegOperand <string rc, string MatchName, string opType> : + SIRegOperand32<rc, MatchName, opType>, + SIRegOperand64<rc, MatchName, opType>; + // FIXME: 64-bit sources can sometimes use 32-bit constants. multiclass RegImmOperand <string rc, string MatchName> : SIRegOperand<rc, MatchName, "OPERAND_REG_IMM">; @@ -938,10 +970,18 @@ multiclass RegInlineOperand32 <string rc, string MatchName, string rc_suffix = "_32"> : SIRegOperand32<rc, MatchName, "OPERAND_REG_INLINE_C", rc_suffix>; +multiclass RegInlineOperand64 <string rc, string MatchName, + string rc_suffix = "_64"> + : SIRegOperand64<rc, MatchName, "OPERAND_REG_INLINE_C", rc_suffix>; + multiclass RegInlineOperandAC <string rc, string MatchName, string rc_suffix = "_32"> : SIRegOperand32<rc, MatchName, "OPERAND_REG_INLINE_AC", rc_suffix>; +multiclass RegInlineOperandAC64 <string rc, string MatchName, + string rc_suffix = "_64"> + : SIRegOperand64<rc, MatchName, "OPERAND_REG_INLINE_AC", rc_suffix, 0>; + //===----------------------------------------------------------------------===// // SSrc_* Operands with an SGPR or a 32-bit immediate //===----------------------------------------------------------------------===// @@ -1001,6 +1041,13 @@ defm VCSrc : RegInlineOperand<"VS", "VCSrc">; //===----------------------------------------------------------------------===// defm VISrc : RegInlineOperand32<"VGPR", "VISrc">; +let DecoderMethod = "decodeOperand_VReg_64" in +defm VISrc_64 : RegInlineOperand64<"VReg", "VISrc_64", "_64">; +defm VISrc_128 : RegInlineOperandAC<"VReg", "VISrc_128", "_128">; +let DecoderMethod = "decodeOperand_VReg_256" in +defm VISrc_256 : RegInlineOperand64<"VReg", "VISrc_256", "_256">; +defm VISrc_512 : RegInlineOperandAC<"VReg", "VISrc_512", "_512">; +defm VISrc_1024 : RegInlineOperandAC<"VReg", "VISrc_1024", "_1024">; //===----------------------------------------------------------------------===// // AVSrc_* Operands with an AGPR or VGPR @@ -1016,6 +1063,31 @@ def AVSrc_64 : RegisterOperand<AV_64> { let EncoderMethod = "getAVOperandEncoding"; } +def AVLdSt_32 : RegisterOperand<AV_32> { + let DecoderMethod = "DecodeAVLdSt_32RegisterClass"; + let EncoderMethod = "getAVOperandEncoding"; +} + +def AVLdSt_64 : RegisterOperand<AV_64> { + let DecoderMethod = "DecodeAVLdSt_64RegisterClass"; + let EncoderMethod = "getAVOperandEncoding"; +} + +def AVLdSt_96 : RegisterOperand<AV_96> { + let DecoderMethod = "DecodeAVLdSt_96RegisterClass"; + let EncoderMethod = "getAVOperandEncoding"; +} + +def AVLdSt_128 : RegisterOperand<AV_128> { + let DecoderMethod = "DecodeAVLdSt_128RegisterClass"; + let EncoderMethod = "getAVOperandEncoding"; +} + +def AVLdSt_160 : RegisterOperand<AV_160> { + let DecoderMethod = "DecodeAVLdSt_160RegisterClass"; + let EncoderMethod = "getAVOperandEncoding"; +} + //===----------------------------------------------------------------------===// // ACSrc_* Operands with an AGPR or an inline constant //===----------------------------------------------------------------------===// @@ -1024,3 +1096,8 @@ defm AISrc : RegInlineOperandAC<"AGPR", "AISrc">; defm AISrc_128 : RegInlineOperandAC<"AReg", "AISrc_128", "_128">; defm AISrc_512 : RegInlineOperandAC<"AReg", "AISrc_512", "_512">; defm AISrc_1024 : RegInlineOperandAC<"AReg", "AISrc_1024", "_1024">; + +let DecoderMethod = "decodeOperand_AReg_64" in +defm AISrc_64 : RegInlineOperandAC64<"AReg", "AISrc_64", "_64">; +let DecoderMethod = "decodeOperand_AReg_256" in +defm AISrc_256 : RegInlineOperandAC64<"AReg", "AISrc_256", "_256">; diff --git a/llvm/lib/Target/AMDGPU/SISchedule.td b/llvm/lib/Target/AMDGPU/SISchedule.td index db4a009e08d7..adb79dd93d25 100644 --- a/llvm/lib/Target/AMDGPU/SISchedule.td +++ b/llvm/lib/Target/AMDGPU/SISchedule.td @@ -54,10 +54,15 @@ def WriteTrans64 : SchedWrite; // Half rate 64-bit instructions. def Write64Bit : SchedWrite; +// Integer multiplications. +def WriteIntMul : SchedWrite; + // mAI multipass instructions. def Write2PassMAI : SchedWrite; def Write8PassMAI : SchedWrite; def Write16PassMAI : SchedWrite; +def Write4PassDGEMM : SchedWrite; +def Write8PassDGEMM : SchedWrite; // FIXME: Should there be a class for instructions which are VALU // instructions and have VALU rates, but write to the SALU (i.e. VOPC @@ -80,6 +85,7 @@ class SISchedMachineModel : SchedMachineModel { def SIFullSpeedModel : SISchedMachineModel; def SIQuarterSpeedModel : SISchedMachineModel; +def SIDPFullSpeedModel : SISchedMachineModel; def GFX10SpeedModel : SISchedMachineModel; // XXX: Are the resource counts correct? @@ -137,11 +143,13 @@ multiclass SICommonWriteRes { def : HWWriteRes<WriteBarrier, [HWBranch], 500>; // XXX: Guessed ??? def : HWVALUWriteRes<Write32Bit, 1>; - def : HWVALUWriteRes<Write64Bit, 2>; def : HWVALUWriteRes<WriteFloatCvt, 4>; def : HWVALUWriteRes<WriteTrans32, 4>; def : HWVALUWriteRes<WriteQuarterRate32, 4>; + def : HWVALUWriteRes<Write4PassDGEMM, 4>; + def : HWVALUWriteRes<Write8PassDGEMM, 16>; + let ResourceCycles = [2] in def : HWWriteRes<Write2PassMAI, [HWXDL], 2>; let ResourceCycles = [8] in @@ -150,7 +158,6 @@ multiclass SICommonWriteRes { def : HWWriteRes<Write16PassMAI, [HWXDL], 16>; def : ReadAdvance<MIVGPRRead, -2>; - def : InstRW<[Write64Bit, MIReadVGPR], (instregex "^V_ACCVGPR_WRITE_B32_e64$")>; // Technically mfma reads can be from 0 to 4 cycles but that does not make // sense to model because its register setup is huge. In particular if we @@ -159,10 +166,6 @@ multiclass SICommonWriteRes { // need to consume 2 or 4 more vgprs to be initialized before the acc // write sequence. Just assume worst case here. def : ReadAdvance<MIMFMARead, -4>; - - def : InstRW<[Write2PassMAI, MIMFMARead], (instregex "^V_MFMA_..._4X4X")>; - def : InstRW<[Write8PassMAI, MIMFMARead], (instregex "^V_MFMA_..._16X16X")>; - def : InstRW<[Write16PassMAI, MIMFMARead], (instregex "^V_MFMA_..._32X32X")>; } def PredIsVGPR32Copy : SchedPredicate<[{TII->isVGPRCopy(*MI) && TII->getOpSize(*MI, 0) <= 32}]>; @@ -176,11 +179,13 @@ let SchedModel = SIFullSpeedModel in { defm : SICommonWriteRes; -def : HWVALUWriteRes<WriteFloatFMA, 1>; -def : HWVALUWriteRes<WriteDouble, 4>; -def : HWVALUWriteRes<WriteDoubleAdd, 2>; -def : HWVALUWriteRes<WriteDoubleCvt, 4>; -def : HWVALUWriteRes<WriteTrans64, 4>; +def : HWVALUWriteRes<Write64Bit, 2>; +def : HWVALUWriteRes<WriteIntMul, 4>; +def : HWVALUWriteRes<WriteFloatFMA, 1>; +def : HWVALUWriteRes<WriteDouble, 4>; +def : HWVALUWriteRes<WriteDoubleAdd, 2>; +def : HWVALUWriteRes<WriteDoubleCvt, 4>; +def : HWVALUWriteRes<WriteTrans64, 4>; def : InstRW<[WriteCopy], (instrs COPY)>; @@ -190,16 +195,44 @@ let SchedModel = SIQuarterSpeedModel in { defm : SICommonWriteRes; -def : HWVALUWriteRes<WriteFloatFMA, 16>; -def : HWVALUWriteRes<WriteDouble, 16>; -def : HWVALUWriteRes<WriteDoubleAdd, 8>; -def : HWVALUWriteRes<WriteDoubleCvt, 4>; -def : HWVALUWriteRes<WriteTrans64, 16>; +def : HWVALUWriteRes<Write64Bit, 2>; +def : HWVALUWriteRes<WriteIntMul, 4>; +def : HWVALUWriteRes<WriteFloatFMA, 16>; +def : HWVALUWriteRes<WriteDouble, 16>; +def : HWVALUWriteRes<WriteDoubleAdd, 8>; +def : HWVALUWriteRes<WriteDoubleCvt, 4>; +def : HWVALUWriteRes<WriteTrans64, 16>; def : InstRW<[WriteCopy], (instrs COPY)>; +def : InstRW<[Write64Bit, MIReadVGPR], (instregex "^V_ACCVGPR_WRITE_B32_e64$")>; +def : InstRW<[Write2PassMAI, MIMFMARead], (instregex "^V_MFMA_..._4X4X")>; +def : InstRW<[Write8PassMAI, MIMFMARead], (instregex "^V_MFMA_..._16X16X")>; +def : InstRW<[Write16PassMAI, MIMFMARead], (instregex "^V_MFMA_..._32X32X")>; } // End SchedModel = SIQuarterSpeedModel +let SchedModel = SIDPFullSpeedModel in { + +defm : SICommonWriteRes; + +def : HWVALUWriteRes<WriteFloatFMA, 1>; +def : HWVALUWriteRes<WriteDouble, 1>; +def : HWVALUWriteRes<WriteDoubleAdd, 1>; +def : HWVALUWriteRes<WriteDoubleCvt, 1>; +def : HWVALUWriteRes<WriteTrans64, 4>; +def : HWVALUWriteRes<WriteIntMul, 1>; +def : HWVALUWriteRes<Write64Bit, 1>; + +def : InstRW<[WriteCopy], (instrs COPY)>; +def : InstRW<[Write64Bit], (instregex "^V_ACCVGPR_WRITE_B32_e64$")>; +def : InstRW<[Write2PassMAI, MIMFMARead], (instregex "^V_MFMA_.32_4X4X")>; +def : InstRW<[Write8PassMAI, MIMFMARead], (instregex "^V_MFMA_.32_16X16X")>; +def : InstRW<[Write16PassMAI, MIMFMARead], (instregex "^V_MFMA_.32_32X32X")>; +def : InstRW<[Write4PassDGEMM, MIMFMARead], (instregex "^V_MFMA_.64_4X4X")>; +def : InstRW<[Write8PassDGEMM, MIMFMARead], (instregex "^V_MFMA_.64_16X16X")>; + +} // End SchedModel = SIDPFullSpeedModel + let SchedModel = GFX10SpeedModel in { // The latency values are 1 / (operations / cycle). @@ -213,6 +246,7 @@ def : HWWriteRes<WriteFloatFMA, [HWVALU, HWRC], 5>; def : HWWriteRes<WriteDouble, [HWVALU, HWRC], 22>; def : HWWriteRes<WriteDoubleAdd, [HWVALU, HWRC], 22>; def : HWWriteRes<WriteDoubleCvt, [HWVALU, HWRC], 22>; +def : HWWriteRes<WriteIntMul, [HWVALU, HWRC], 8>; def : HWWriteRes<WriteTrans64, [HWVALU, HWRC], 24>; def : HWWriteRes<WriteBranch, [HWBranch], 32>; diff --git a/llvm/lib/Target/AMDGPU/SIWholeQuadMode.cpp b/llvm/lib/Target/AMDGPU/SIWholeQuadMode.cpp index 1deef5080318..7c62282012f9 100644 --- a/llvm/lib/Target/AMDGPU/SIWholeQuadMode.cpp +++ b/llvm/lib/Target/AMDGPU/SIWholeQuadMode.cpp @@ -407,6 +407,9 @@ char SIWholeQuadMode::scanInstructions(MachineFunction &MF, char Flags = 0; if (TII->isWQM(Opcode)) { + // If LOD is not supported WQM is not needed. + if (!ST->hasExtendedImageInsts()) + continue; // Sampling instructions don't need to produce results for all pixels // in a quad, they just require all inputs of a quad to have been // computed for derivatives. diff --git a/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp b/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp index 4c1e4dec7ecb..f384719144e5 100644 --- a/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp +++ b/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp @@ -345,7 +345,7 @@ void streamIsaVersion(const MCSubtargetInfo *STI, raw_ostream &Stream) { << "gfx" << Version.Major << Version.Minor - << Version.Stepping; + << hexdigit(Version.Stepping, true); if (hasXNACK(*STI)) Stream << "+xnack"; @@ -402,6 +402,8 @@ unsigned getMinWavesPerEU(const MCSubtargetInfo *STI) { unsigned getMaxWavesPerEU(const MCSubtargetInfo *STI) { // FIXME: Need to take scratch memory into account. + if (isGFX90A(*STI)) + return 8; if (!isGFX10Plus(*STI)) return 10; return hasGFX10_3Insts(*STI) ? 16 : 20; @@ -531,6 +533,9 @@ unsigned getNumSGPRBlocks(const MCSubtargetInfo *STI, unsigned NumSGPRs) { unsigned getVGPRAllocGranule(const MCSubtargetInfo *STI, Optional<bool> EnableWavefrontSize32) { + if (STI->getFeatureBits().test(FeatureGFX90AInsts)) + return 8; + bool IsWave32 = EnableWavefrontSize32 ? *EnableWavefrontSize32 : STI->getFeatureBits().test(FeatureWavefrontSize32); @@ -543,6 +548,8 @@ unsigned getVGPRAllocGranule(const MCSubtargetInfo *STI, unsigned getVGPREncodingGranule(const MCSubtargetInfo *STI, Optional<bool> EnableWavefrontSize32) { + if (STI->getFeatureBits().test(FeatureGFX90AInsts)) + return 8; bool IsWave32 = EnableWavefrontSize32 ? *EnableWavefrontSize32 : @@ -552,12 +559,16 @@ unsigned getVGPREncodingGranule(const MCSubtargetInfo *STI, } unsigned getTotalNumVGPRs(const MCSubtargetInfo *STI) { + if (STI->getFeatureBits().test(FeatureGFX90AInsts)) + return 512; if (!isGFX10Plus(*STI)) return 256; return STI->getFeatureBits().test(FeatureWavefrontSize32) ? 1024 : 512; } unsigned getAddressableNumVGPRs(const MCSubtargetInfo *STI) { + if (STI->getFeatureBits().test(FeatureGFX90AInsts)) + return 512; return 256; } @@ -653,6 +664,11 @@ amdhsa::kernel_descriptor_t getDefaultAmdhsaKernelDescriptor( AMDHSA_BITS_SET(KD.compute_pgm_rsrc1, amdhsa::COMPUTE_PGM_RSRC1_MEM_ORDERED, 1); } + if (AMDGPU::isGFX90A(*STI)) { + AMDHSA_BITS_SET(KD.compute_pgm_rsrc3, + amdhsa::COMPUTE_PGM_RSRC3_GFX90A_TG_SPLIT, + STI->getFeatureBits().test(FeatureTgSplit) ? 1 : 0); + } return KD; } @@ -1267,6 +1283,10 @@ bool hasGFX10_3Insts(const MCSubtargetInfo &STI) { return STI.getFeatureBits()[AMDGPU::FeatureGFX10_3Insts]; } +bool isGFX90A(const MCSubtargetInfo &STI) { + return STI.getFeatureBits()[AMDGPU::FeatureGFX90AInsts]; +} + bool isSGPR(unsigned Reg, const MCRegisterInfo* TRI) { const MCRegisterClass SGPRClass = TRI->getRegClass(AMDGPU::SReg_32RegClassID); const unsigned FirstSubReg = TRI->getSubReg(Reg, AMDGPU::sub0); @@ -1374,6 +1394,9 @@ bool isSISrcFPOperand(const MCInstrDesc &Desc, unsigned OpNo) { case AMDGPU::OPERAND_REG_INLINE_AC_FP16: case AMDGPU::OPERAND_REG_INLINE_AC_V2FP16: case AMDGPU::OPERAND_REG_INLINE_AC_V2INT16: + case AMDGPU::OPERAND_REG_IMM_V2FP32: + case AMDGPU::OPERAND_REG_INLINE_C_V2FP32: + case AMDGPU::OPERAND_REG_INLINE_AC_FP64: return true; default: return false; @@ -1418,16 +1441,19 @@ unsigned getRegBitWidth(unsigned RCID) { case AMDGPU::SReg_96RegClassID: case AMDGPU::VReg_96RegClassID: case AMDGPU::AReg_96RegClassID: + case AMDGPU::AV_96RegClassID: return 96; case AMDGPU::SGPR_128RegClassID: case AMDGPU::SReg_128RegClassID: case AMDGPU::VReg_128RegClassID: case AMDGPU::AReg_128RegClassID: + case AMDGPU::AV_128RegClassID: return 128; case AMDGPU::SGPR_160RegClassID: case AMDGPU::SReg_160RegClassID: case AMDGPU::VReg_160RegClassID: case AMDGPU::AReg_160RegClassID: + case AMDGPU::AV_160RegClassID: return 160; case AMDGPU::SGPR_192RegClassID: case AMDGPU::SReg_192RegClassID: diff --git a/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h b/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h index f9378693cf48..246132ef27ec 100644 --- a/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h +++ b/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h @@ -703,6 +703,7 @@ bool isGFX10Plus(const MCSubtargetInfo &STI); bool isGCN3Encoding(const MCSubtargetInfo &STI); bool isGFX10_BEncoding(const MCSubtargetInfo &STI); bool hasGFX10_3Insts(const MCSubtargetInfo &STI); +bool isGFX90A(const MCSubtargetInfo &STI); /// Is Reg - scalar register bool isSGPR(unsigned Reg, const MCRegisterInfo* TRI); @@ -746,12 +747,17 @@ inline unsigned getOperandSize(const MCOperandInfo &OpInfo) { case AMDGPU::OPERAND_REG_INLINE_C_FP32: case AMDGPU::OPERAND_REG_INLINE_AC_INT32: case AMDGPU::OPERAND_REG_INLINE_AC_FP32: + case AMDGPU::OPERAND_REG_IMM_V2INT32: + case AMDGPU::OPERAND_REG_IMM_V2FP32: + case AMDGPU::OPERAND_REG_INLINE_C_V2INT32: + case AMDGPU::OPERAND_REG_INLINE_C_V2FP32: return 4; case AMDGPU::OPERAND_REG_IMM_INT64: case AMDGPU::OPERAND_REG_IMM_FP64: case AMDGPU::OPERAND_REG_INLINE_C_INT64: case AMDGPU::OPERAND_REG_INLINE_C_FP64: + case AMDGPU::OPERAND_REG_INLINE_AC_FP64: return 8; case AMDGPU::OPERAND_REG_IMM_INT16: @@ -847,6 +853,11 @@ bool splitMUBUFOffset(uint32_t Imm, uint32_t &SOffset, uint32_t &ImmOffset, const GCNSubtarget *Subtarget, Align Alignment = Align(4)); +LLVM_READNONE +inline bool isLegal64BitDPPControl(unsigned DC) { + return DC >= DPP::ROW_NEWBCAST_FIRST && DC <= DPP::ROW_NEWBCAST_LAST; +} + /// \returns true if the intrinsic is divergent bool isIntrinsicSourceOfDivergence(unsigned IntrID); diff --git a/llvm/lib/Target/AMDGPU/VOP1Instructions.td b/llvm/lib/Target/AMDGPU/VOP1Instructions.td index f1e470031982..5ba0723ba24b 100644 --- a/llvm/lib/Target/AMDGPU/VOP1Instructions.td +++ b/llvm/lib/Target/AMDGPU/VOP1Instructions.td @@ -351,12 +351,12 @@ let SubtargetPredicate = isGFX6GFX7 in { VOP1Inst<"v_rsq_legacy_f32", VOP_F32_F32, int_amdgcn_rsq_legacy>; } // End TRANS = 1, SchedRW = [WriteTrans32] - let SchedRW = [WriteDouble] in { + let SchedRW = [WriteTrans64] in { defm V_RCP_CLAMP_F64 : VOP1Inst<"v_rcp_clamp_f64", VOP_F64_F64>; defm V_RSQ_CLAMP_F64 : VOP1Inst<"v_rsq_clamp_f64", VOP_F64_F64, AMDGPUrsq_clamp>; - } // End SchedRW = [WriteDouble] + } // End SchedRW = [WriteTrans64] } // End SubtargetPredicate = isGFX6GFX7 let SubtargetPredicate = isGFX7GFX8GFX9 in { @@ -461,6 +461,18 @@ let SubtargetPredicate = isGFX10Plus in { } // End Uses = [M0] } // End SubtargetPredicate = isGFX10Plus +def VOPProfileAccMov : VOP_NO_EXT<VOP_I32_I32> { + let DstRC = RegisterOperand<AGPR_32>; + let Src0RC32 = RegisterOperand<AGPR_32>; + let Asm32 = " $vdst, $src0"; +} + +def V_ACCVGPR_MOV_B32 : VOP1_Pseudo<"v_accvgpr_mov_b32", VOPProfileAccMov, [], 1> { + let SubtargetPredicate = isGFX90APlus; + let isReMaterializable = 1; + let isAsCheapAsAMove = 1; +} + //===----------------------------------------------------------------------===// // Target-specific instruction encodings. //===----------------------------------------------------------------------===// @@ -823,6 +835,8 @@ defm V_SAT_PK_U8_I16 : VOP1_Real_vi<0x4f>; defm V_CVT_NORM_I16_F16 : VOP1_Real_vi<0x4d>; defm V_CVT_NORM_U16_F16 : VOP1_Real_vi<0x4e>; +defm V_ACCVGPR_MOV_B32 : VOP1Only_Real_vi<0x52>; + // Copy of v_mov_b32 with $vdst as a use operand for use with VGPR // indexing mode. vdst can't be treated as a def for codegen purposes, // and an implicit use and def of the super register should be added. diff --git a/llvm/lib/Target/AMDGPU/VOP2Instructions.td b/llvm/lib/Target/AMDGPU/VOP2Instructions.td index 7a334eaadaed..edcd8595f9e1 100644 --- a/llvm/lib/Target/AMDGPU/VOP2Instructions.td +++ b/llvm/lib/Target/AMDGPU/VOP2Instructions.td @@ -289,28 +289,30 @@ class VOP_MADMK <ValueType vt> : VOPProfile <[vt, vt, vt, vt]> { def VOP_MADMK_F16 : VOP_MADMK <f16>; def VOP_MADMK_F32 : VOP_MADMK <f32>; +class getRegisterOperandForVT<ValueType VT> { + RegisterOperand ret = RegisterOperand<getVregSrcForVT<VT>.ret>; +} + // FIXME: Remove src2_modifiers. It isn't used, so is wasting memory // and processing time but it makes it easier to convert to mad. class VOP_MAC <ValueType vt0, ValueType vt1=vt0> : VOPProfile <[vt0, vt1, vt1, vt0]> { - let Ins32 = (ins Src0RC32:$src0, Src1RC32:$src1, VGPR_32:$src2); - let Ins64 = getIns64<Src0RC64, Src1RC64, RegisterOperand<VGPR_32>, 3, + let Ins32 = (ins Src0RC32:$src0, Src1RC32:$src1, getVregSrcForVT<Src2VT>.ret:$src2); + let Ins64 = getIns64<Src0RC64, Src1RC64, getRegisterOperandForVT<Src2VT>.ret, 3, 0, HasModifiers, HasModifiers, HasOMod, Src0Mod, Src1Mod, Src2Mod>.ret; let InsDPP = (ins Src0ModDPP:$src0_modifiers, Src0DPP:$src0, Src1ModDPP:$src1_modifiers, Src1DPP:$src1, - VGPR_32:$src2, // stub argument + getVregSrcForVT<Src2VT>.ret:$src2, // stub argument dpp_ctrl:$dpp_ctrl, row_mask:$row_mask, bank_mask:$bank_mask, bound_ctrl:$bound_ctrl); let InsDPP16 = !con(InsDPP, (ins FI:$fi)); - let InsDPP8 = (ins Src0ModDPP:$src0_modifiers, Src0DPP:$src0, Src1ModDPP:$src1_modifiers, Src1DPP:$src1, - VGPR_32:$src2, // stub argument + getVregSrcForVT<Src2VT>.ret:$src2, // stub argument dpp8:$dpp8, FI:$fi); - let InsSDWA = (ins Src0ModSDWA:$src0_modifiers, Src0SDWA:$src0, Src1ModSDWA:$src1_modifiers, Src1SDWA:$src1, - VGPR_32:$src2, // stub argument + getVregSrcForVT<Src2VT>.ret:$src2, // stub argument clampmod:$clamp, omod:$omod, dst_sel:$dst_sel, dst_unused:$dst_unused, src0_sel:$src0_sel, src1_sel:$src1_sel); @@ -335,6 +337,8 @@ def VOP_MAC_F16 : VOP_MAC <f16>; def VOP_MAC_F32 : VOP_MAC <f32>; let HasExtDPP = 0 in def VOP_MAC_LEGACY_F32 : VOP_MAC <f32>; +let HasExtSDWA = 0, HasExt64BitDPP = 1 in +def VOP_MAC_F64 : VOP_MAC <f64>; class VOP_DOT_ACC<ValueType vt0, ValueType vt1> : VOP_MAC<vt0, vt1> { let HasClamp = 0; @@ -448,6 +452,7 @@ def VOP_READLANE : VOPProfile<[i32, i32, i32]> { let HasExt = 0; let HasExtDPP = 0; + let HasExt64BitDPP = 0; let HasExtSDWA = 0; let HasExtSDWA9 = 0; } @@ -464,6 +469,7 @@ def VOP_WRITELANE : VOPProfile<[i32, i32, i32, i32]> { let HasExt = 0; let HasExtDPP = 0; + let HasExt64BitDPP = 0; let HasExtSDWA = 0; let HasExtSDWA9 = 0; } @@ -692,6 +698,14 @@ defm V_FMAC_LEGACY_F32 : VOP2Inst <"v_fmac_legacy_f32", VOP_MAC_LEGACY_F32>; } // End SubtargetPredicate = HasFmaLegacy32 +let SubtargetPredicate = isGFX90APlus, + Constraints = "$vdst = $src2", + DisableEncoding="$src2", + isConvertibleToThreeAddress = 1, + isCommutable = 1, + SchedRW = [WriteDoubleAdd] in +defm V_FMAC_F64 : VOP2Inst <"v_fmac_f64", VOP_MAC_F64>; + let Constraints = "$vdst = $src2", DisableEncoding="$src2", isConvertibleToThreeAddress = 1, @@ -1525,6 +1539,7 @@ defm V_CNDMASK_B32 : VOP2_Real_e32e64_vi <0x0>; defm V_ADD_F32 : VOP2_Real_e32e64_vi <0x1>; defm V_SUB_F32 : VOP2_Real_e32e64_vi <0x2>; defm V_SUBREV_F32 : VOP2_Real_e32e64_vi <0x3>; +let AssemblerPredicate = isGCN3ExcludingGFX90A in defm V_MUL_LEGACY_F32 : VOP2_Real_e32e64_vi <0x4>; defm V_MUL_F32 : VOP2_Real_e32e64_vi <0x5>; defm V_MUL_I32_I24 : VOP2_Real_e32e64_vi <0x6>; @@ -1641,6 +1656,40 @@ defm V_XNOR_B32 : VOP2_Real_e32e64_vi <0x3d>; } // End SubtargetPredicate = HasDLInsts +let AssemblerPredicate = isGFX90APlus, DecoderNamespace = "GFX90A" in { + multiclass VOP2_Real_e32_gfx90a <bits<6> op> { + def _e32_gfx90a : + VOP2_Real<!cast<VOP2_Pseudo>(NAME#"_e32"), SIEncodingFamily.GFX90A>, + VOP2e<op{5-0}, !cast<VOP2_Pseudo>(NAME#"_e32").Pfl>; + } + + multiclass VOP2_Real_e64_gfx90a <bits<10> op> { + def _e64_gfx90a : + VOP3_Real<!cast<VOP3_Pseudo>(NAME#"_e64"), SIEncodingFamily.GFX90A>, + VOP3e_vi <op, !cast<VOP3_Pseudo>(NAME#"_e64").Pfl>; + } + + multiclass Base_VOP2_Real_e32e64_gfx90a <bits<6> op> : + VOP2_Real_e32_gfx90a<op>, + VOP2_Real_e64_gfx90a<{0, 1, 0, 0, op{5-0}}>; + + multiclass VOP2_Real_e32e64_gfx90a <bits<6> op> : + Base_VOP2_Real_e32e64_gfx90a<op> { + + foreach _ = BoolToList<!cast<VOP2_Pseudo>(NAME#"_e32").Pfl.HasExtDPP>.ret in + def _dpp_gfx90a : + VOP_DPP_Real<!cast<VOP2_DPP_Pseudo>(NAME#"_dpp"), SIEncodingFamily.GFX90A>, + VOP2_DPPe<op, !cast<VOP2_DPP_Pseudo>(NAME#"_dpp")> { + let DecoderNamespace = "SDWA9"; + } + } +} // End AssemblerPredicate = isGFX90APlus, DecoderNamespace = "GFX90A" + +let SubtargetPredicate = isGFX90APlus in { + defm V_FMAC_F64 : VOP2_Real_e32e64_gfx90a <0x4>; + defm V_MUL_LEGACY_F32 : VOP2_Real_e64_gfx90a <0x2a1>; +} // End SubtargetPredicate = isGFX90APlus + multiclass VOP2_Real_DOT_ACC_gfx9<bits<6> op> : VOP2_Real_e32_vi<op> { def _dpp_vi : VOP2_DPP<op, !cast<VOP2_DPP_Pseudo>(NAME#"_dpp")>; } diff --git a/llvm/lib/Target/AMDGPU/VOP3Instructions.td b/llvm/lib/Target/AMDGPU/VOP3Instructions.td index 42dc995609f0..6fd9ae235b35 100644 --- a/llvm/lib/Target/AMDGPU/VOP3Instructions.td +++ b/llvm/lib/Target/AMDGPU/VOP3Instructions.td @@ -325,12 +325,12 @@ defm V_MIN_F64 : VOP3Inst <"v_min_f64", VOP3_Profile<VOP_F64_F64_F64>, fminnum_l defm V_MAX_F64 : VOP3Inst <"v_max_f64", VOP3_Profile<VOP_F64_F64_F64>, fmaxnum_like, 1>; } // End SchedRW = [WriteDoubleAdd] -let SchedRW = [WriteQuarterRate32] in { +let SchedRW = [WriteIntMul] in { defm V_MUL_LO_U32 : VOP3Inst <"v_mul_lo_u32", VOP3_Profile<VOP_I32_I32_I32>, mul>; defm V_MUL_HI_U32 : VOP3Inst <"v_mul_hi_u32", VOP3_Profile<VOP_I32_I32_I32>, mulhu>; defm V_MUL_LO_I32 : VOP3Inst <"v_mul_lo_i32", VOP3_Profile<VOP_I32_I32_I32>>; defm V_MUL_HI_I32 : VOP3Inst <"v_mul_hi_i32", VOP3_Profile<VOP_I32_I32_I32>, mulhs>; -} // End SchedRW = [WriteQuarterRate32] +} // End SchedRW = [WriteIntMul] let Uses = [MODE, VCC, EXEC] in { // v_div_fmas_f32: @@ -447,10 +447,10 @@ defm V_MQSAD_U32_U8 : VOP3Inst <"v_mqsad_u32_u8", VOP3_Profile<VOP_V4I32_I64_I32 } // End Constraints = "@earlyclobber $vdst", SchedRW = [WriteQuarterRate32] let isCommutable = 1 in { -let SchedRW = [WriteQuarterRate32, WriteSALU] in { +let SchedRW = [WriteIntMul, WriteSALU] in { defm V_MAD_U64_U32 : VOP3Inst <"v_mad_u64_u32", VOP3b_I64_I1_I32_I32_I64>; defm V_MAD_I64_I32 : VOP3Inst <"v_mad_i64_i32", VOP3b_I64_I1_I32_I32_I64>; -} // End SchedRW = [WriteQuarterRate32, WriteSALU] +} // End SchedRW = [WriteIntMul, WriteSALU] } // End isCommutable = 1 } // End SubtargetPredicate = isGFX7Plus @@ -476,6 +476,7 @@ let renamedInGFX9 = 1 in { let FPDPRounding = 1 in { defm V_MAD_F16 : VOP3Inst <"v_mad_f16", VOP3_Profile<VOP_F16_F16_F16_F16>, fmad>; let Uses = [MODE, M0, EXEC] in { + let OtherPredicates = [isNotGFX90APlus] in // For some reason the intrinsic operands are in a different order // from the instruction operands. def V_INTERP_P2_F16 : VOP3Interp <"v_interp_p2_f16", VOP3_INTERP16<[f16, f32, i32, f32]>, @@ -497,24 +498,24 @@ let SubtargetPredicate = isGFX9Only, FPDPRounding = 1 in { let SubtargetPredicate = isGFX9Plus in { defm V_MAD_U16_gfx9 : VOP3Inst <"v_mad_u16_gfx9", VOP3_Profile<VOP_I16_I16_I16_I16, VOP3_OPSEL>>; defm V_MAD_I16_gfx9 : VOP3Inst <"v_mad_i16_gfx9", VOP3_Profile<VOP_I16_I16_I16_I16, VOP3_OPSEL>>; +let OtherPredicates = [isNotGFX90APlus] in def V_INTERP_P2_F16_gfx9 : VOP3Interp <"v_interp_p2_f16_gfx9", VOP3_INTERP16<[f16, f32, i32, f32]>>; } // End SubtargetPredicate = isGFX9Plus -let Uses = [MODE, M0, EXEC], FPDPRounding = 1 in { +// This predicate should only apply to the selection pattern. The +// instruction still exists and should decode on subtargets with +// other bank counts. +let OtherPredicates = [isNotGFX90APlus, has32BankLDS], Uses = [MODE, M0, EXEC], FPDPRounding = 1 in { def V_INTERP_P1LL_F16 : VOP3Interp <"v_interp_p1ll_f16", VOP3_INTERP16<[f32, f32, i32, untyped]>, [(set f32:$vdst, (int_amdgcn_interp_p1_f16 (VOP3Mods f32:$src0, i32:$src0_modifiers), (i32 timm:$attrchan), (i32 timm:$attr), - (i1 timm:$high), M0))]> { - // This predicate should only apply to the selection pattern. The - // instruction still exists and should decode on subtargets with - // other bank counts. - let OtherPredicates = [has32BankLDS]; -} - + (i1 timm:$high), M0))]>; +} // End OtherPredicates = [isNotGFX90APlus, has32BankLDS], Uses = [MODE, M0, EXEC], FPDPRounding = 1 +let OtherPredicates = [isNotGFX90APlus], Uses = [MODE, M0, EXEC], FPDPRounding = 1 in { def V_INTERP_P1LV_F16 : VOP3Interp <"v_interp_p1lv_f16", VOP3_INTERP16<[f32, f32, i32, f16]>>; -} // End Uses = [MODE, M0, EXEC], FPDPRounding = 1 +} // End OtherPredicates = [isNotGFX90APlus], Uses = [MODE, M0, EXEC], FPDPRounding = 1 } // End SubtargetPredicate = Has16BitInsts, isCommutable = 1 @@ -527,11 +528,11 @@ def : GCNPat< ), VGPR_32)), sub1) >; -let SubtargetPredicate = isGFX8Plus, Uses = [MODE, M0, EXEC] in { +let SubtargetPredicate = isGFX8Plus, Uses = [MODE, M0, EXEC], OtherPredicates = [isNotGFX90APlus] in { def V_INTERP_P1_F32_e64 : VOP3Interp <"v_interp_p1_f32", VOP3_INTERP>; def V_INTERP_P2_F32_e64 : VOP3Interp <"v_interp_p2_f32", VOP3_INTERP>; def V_INTERP_MOV_F32_e64 : VOP3Interp <"v_interp_mov_f32", VOP3_INTERP_MOV>; -} // End SubtargetPredicate = isGFX8Plus, Uses = [MODE, M0, EXEC] +} // End SubtargetPredicate = isGFX8Plus, Uses = [MODE, M0, EXEC], OtherPredicates = [isNotGFX90APlus] let Predicates = [Has16BitInsts, isGFX6GFX7GFX8GFX9] in { diff --git a/llvm/lib/Target/AMDGPU/VOP3PInstructions.td b/llvm/lib/Target/AMDGPU/VOP3PInstructions.td index b06addf4c927..073e4dff4578 100644 --- a/llvm/lib/Target/AMDGPU/VOP3PInstructions.td +++ b/llvm/lib/Target/AMDGPU/VOP3PInstructions.td @@ -340,9 +340,16 @@ foreach Type = ["U", "I"] in (!cast<VOP3PInst>("V_DOT8_"#Type#"32_"#Type#4) (i32 8), $src0, (i32 8), $src1, (i32 8), $src2, (i1 0))>; def ADst_32 : VOPDstOperand<AGPR_32>; +def ADst_64 : VOPDstOperand<AReg_64>; def ADst_128 : VOPDstOperand<AReg_128>; +def ADst_256 : VOPDstOperand<AReg_256>; def ADst_512 : VOPDstOperand<AReg_512>; def ADst_1024 : VOPDstOperand<AReg_1024>; +def VDst_64 : VOPDstOperand<VReg_64>; +def VDst_128 : VOPDstOperand<VReg_128>; +def VDst_256 : VOPDstOperand<VReg_256>; +def VDst_512 : VOPDstOperand<VReg_512>; +def VDst_1024 : VOPDstOperand<VReg_1024>; def VOPProfileAccRead : VOP3_Profile<VOP_I32_I32, VOP3_MAI> { let Src0RC64 = ARegSrc_32; @@ -362,6 +369,9 @@ class VOPProfileMAI<VOPProfile P, RegisterOperand _SrcRC, RegisterOperand _DstRC let Src2RC64 = _SrcRC; let HasOpSel = 0; let HasClamp = 0; + let HasIntClamp = 0; + let HasOMod = 0; + let HasModifiers = 0; let Asm64 = " $vdst, $src0, $src1, $src2$cbsz$abid$blgp"; let Ins64 = (ins Src0RC64:$src0, Src1RC64:$src1, Src2RC64:$src2, cbsz:$cbsz, abid:$abid, blgp:$blgp); } @@ -378,6 +388,29 @@ def VOPProfileMAI_F32_V2I16_X32 : VOPProfileMAI<VOP_V32F32_V2I16_V2I16_V32F32, A def VOPProfileMAI_F32_V4F16_X4 : VOPProfileMAI<VOP_V4F32_V4F16_V4F16_V4F32, AISrc_128_b32, ADst_128, AVSrc_64>; def VOPProfileMAI_F32_V4F16_X16 : VOPProfileMAI<VOP_V16F32_V4F16_V4F16_V16F32, AISrc_512_b32, ADst_512, AVSrc_64>; def VOPProfileMAI_F32_V4F16_X32 : VOPProfileMAI<VOP_V32F32_V4F16_V4F16_V32F32, AISrc_1024_b32, ADst_1024, AVSrc_64>; +def VOPProfileMAI_F32_V4I16_X4 : VOPProfileMAI<VOP_V4F32_V4I16_V4I16_V4F32, AISrc_128_b32, ADst_128, AVSrc_64>; +def VOPProfileMAI_F32_V4I16_X16 : VOPProfileMAI<VOP_V16F32_V4I16_V4I16_V16F32, AISrc_512_b32, ADst_512, AVSrc_64>; +def VOPProfileMAI_F32_V4I16_X32 : VOPProfileMAI<VOP_V32F32_V4I16_V4I16_V32F32, AISrc_1024_b32, ADst_1024, AVSrc_64>; +def VOPProfileMAI_F64_16X16X4F64 : VOPProfileMAI<VOP_V4F64_F64_F64_V4F64, AISrc_256_f64, ADst_256, AVSrc_64>; +def VOPProfileMAI_F64_4X4X4F64 : VOPProfileMAI<VOP_F64_F64_F64_F64, AISrc_64_f64, ADst_64, AVSrc_64>; + +def VOPProfileMAI_F32_F32_X4_VCD : VOPProfileMAI<VOP_V4F32_F32_F32_V4F32, VISrc_128_f32, VDst_128>; +def VOPProfileMAI_F32_F32_X16_VCD : VOPProfileMAI<VOP_V16F32_F32_F32_V16F32, VISrc_512_f32, VDst_512>; +def VOPProfileMAI_F32_F32_X32_VCD : VOPProfileMAI<VOP_V32F32_F32_F32_V32F32, VISrc_1024_f32, VDst_1024>; +def VOPProfileMAI_I32_I32_X4_VCD : VOPProfileMAI<VOP_V4I32_I32_I32_V4I32, VISrc_128_b32, VDst_128>; +def VOPProfileMAI_I32_I32_X16_VCD : VOPProfileMAI<VOP_V16I32_I32_I32_V16I32, VISrc_512_b32, VDst_512>; +def VOPProfileMAI_I32_I32_X32_VCD : VOPProfileMAI<VOP_V32I32_I32_I32_V32I32, VISrc_1024_b32, VDst_1024>; +def VOPProfileMAI_F32_V2I16_X4_VCD : VOPProfileMAI<VOP_V4F32_V2I16_V2I16_V4F32, VISrc_128_b32, VDst_128>; +def VOPProfileMAI_F32_V2I16_X16_VCD : VOPProfileMAI<VOP_V16F32_V2I16_V2I16_V16F32, VISrc_512_b32, VDst_512>; +def VOPProfileMAI_F32_V2I16_X32_VCD : VOPProfileMAI<VOP_V32F32_V2I16_V2I16_V32F32, VISrc_1024_b32, VDst_1024>; +def VOPProfileMAI_F32_V4F16_X4_VCD : VOPProfileMAI<VOP_V4F32_V4F16_V4F16_V4F32, VISrc_128_b32, VDst_128, AVSrc_64>; +def VOPProfileMAI_F32_V4F16_X16_VCD : VOPProfileMAI<VOP_V16F32_V4F16_V4F16_V16F32, VISrc_512_b32, VDst_512, AVSrc_64>; +def VOPProfileMAI_F32_V4F16_X32_VCD : VOPProfileMAI<VOP_V32F32_V4F16_V4F16_V32F32, VISrc_1024_b32, VDst_1024, AVSrc_64>; +def VOPProfileMAI_F32_V4I16_X4_VCD : VOPProfileMAI<VOP_V4F32_V4I16_V4I16_V4F32, VISrc_128_b32, VDst_128, AVSrc_64>; +def VOPProfileMAI_F32_V4I16_X16_VCD : VOPProfileMAI<VOP_V16F32_V4I16_V4I16_V16F32, VISrc_512_b32, VDst_512, AVSrc_64>; +def VOPProfileMAI_F32_V4I16_X32_VCD : VOPProfileMAI<VOP_V32F32_V4I16_V4I16_V32F32, VISrc_1024_b32, VDst_1024, AVSrc_64>; +def VOPProfileMAI_F64_16X16X4F64_VCD : VOPProfileMAI<VOP_V4F64_F64_F64_V4F64, VISrc_256_f64, VDst_256, AVSrc_64>; +def VOPProfileMAI_F64_4X4X4F64_VCD : VOPProfileMAI<VOP_F64_F64_F64_F64, VISrc_64_f64, VDst_64, AVSrc_64>; let Predicates = [HasMAIInsts] in { @@ -388,32 +421,57 @@ let isAsCheapAsAMove = 1, isReMaterializable = 1 in { } // End isMoveImm = 1 } // End isAsCheapAsAMove = 1, isReMaterializable = 1 -// FP32 denorm mode is respected, rounding mode is not. Exceptions are not supported. -let isConvergent = 1, mayRaiseFPException = 0, ReadsModeReg = 1 in { -defm V_MFMA_F32_4X4X1F32 : VOP3Inst<"v_mfma_f32_4x4x1f32", VOPProfileMAI_F32_F32_X4, int_amdgcn_mfma_f32_4x4x1f32>; -defm V_MFMA_F32_4X4X4F16 : VOP3Inst<"v_mfma_f32_4x4x4f16", VOPProfileMAI_F32_V4F16_X4, int_amdgcn_mfma_f32_4x4x4f16>; -defm V_MFMA_I32_4X4X4I8 : VOP3Inst<"v_mfma_i32_4x4x4i8", VOPProfileMAI_I32_I32_X4, int_amdgcn_mfma_i32_4x4x4i8>; -defm V_MFMA_F32_4X4X2BF16 : VOP3Inst<"v_mfma_f32_4x4x2bf16", VOPProfileMAI_F32_V2I16_X4, int_amdgcn_mfma_f32_4x4x2bf16>; -defm V_MFMA_F32_16X16X1F32 : VOP3Inst<"v_mfma_f32_16x16x1f32", VOPProfileMAI_F32_F32_X16, int_amdgcn_mfma_f32_16x16x1f32>; -defm V_MFMA_F32_16X16X4F32 : VOP3Inst<"v_mfma_f32_16x16x4f32", VOPProfileMAI_F32_F32_X4, int_amdgcn_mfma_f32_16x16x4f32>; -defm V_MFMA_F32_16X16X4F16 : VOP3Inst<"v_mfma_f32_16x16x4f16", VOPProfileMAI_F32_V4F16_X16, int_amdgcn_mfma_f32_16x16x4f16>; -defm V_MFMA_F32_16X16X16F16 : VOP3Inst<"v_mfma_f32_16x16x16f16", VOPProfileMAI_F32_V4F16_X4, int_amdgcn_mfma_f32_16x16x16f16>; -defm V_MFMA_I32_16X16X4I8 : VOP3Inst<"v_mfma_i32_16x16x4i8", VOPProfileMAI_I32_I32_X16, int_amdgcn_mfma_i32_16x16x4i8>; -defm V_MFMA_I32_16X16X16I8 : VOP3Inst<"v_mfma_i32_16x16x16i8", VOPProfileMAI_I32_I32_X4, int_amdgcn_mfma_i32_16x16x16i8>; -defm V_MFMA_F32_16X16X2BF16 : VOP3Inst<"v_mfma_f32_16x16x2bf16", VOPProfileMAI_F32_V2I16_X16, int_amdgcn_mfma_f32_16x16x2bf16>; -defm V_MFMA_F32_16X16X8BF16 : VOP3Inst<"v_mfma_f32_16x16x8bf16", VOPProfileMAI_F32_V2I16_X4, int_amdgcn_mfma_f32_16x16x8bf16>; -defm V_MFMA_F32_32X32X1F32 : VOP3Inst<"v_mfma_f32_32x32x1f32", VOPProfileMAI_F32_F32_X32, int_amdgcn_mfma_f32_32x32x1f32>; -defm V_MFMA_F32_32X32X2F32 : VOP3Inst<"v_mfma_f32_32x32x2f32", VOPProfileMAI_F32_F32_X16, int_amdgcn_mfma_f32_32x32x2f32>; -defm V_MFMA_F32_32X32X4F16 : VOP3Inst<"v_mfma_f32_32x32x4f16", VOPProfileMAI_F32_V4F16_X32, int_amdgcn_mfma_f32_32x32x4f16>; -defm V_MFMA_F32_32X32X8F16 : VOP3Inst<"v_mfma_f32_32x32x8f16", VOPProfileMAI_F32_V4F16_X16, int_amdgcn_mfma_f32_32x32x8f16>; -defm V_MFMA_I32_32X32X4I8 : VOP3Inst<"v_mfma_i32_32x32x4i8", VOPProfileMAI_I32_I32_X32, int_amdgcn_mfma_i32_32x32x4i8>; -defm V_MFMA_I32_32X32X8I8 : VOP3Inst<"v_mfma_i32_32x32x8i8", VOPProfileMAI_I32_I32_X16, int_amdgcn_mfma_i32_32x32x8i8>; -defm V_MFMA_F32_32X32X2BF16 : VOP3Inst<"v_mfma_f32_32x32x2bf16", VOPProfileMAI_F32_V2I16_X32, int_amdgcn_mfma_f32_32x32x2bf16>; -defm V_MFMA_F32_32X32X4BF16 : VOP3Inst<"v_mfma_f32_32x32x4bf16", VOPProfileMAI_F32_V2I16_X16, int_amdgcn_mfma_f32_32x32x4bf16>; -} // End isConvergent = 1, mayRaiseFPException = 0, ReadsModeReg = 1 +multiclass MAIInst<string OpName, string P, SDPatternOperator node> { + let isConvergent = 1, mayRaiseFPException = 0, ReadsModeReg = 1 in { + // FP32 denorm mode is respected, rounding mode is not. Exceptions are not supported. + defm "" : VOP3Inst<OpName, !cast<VOPProfileMAI>("VOPProfileMAI_" # P), node>; + + let SubtargetPredicate = isGFX90APlus, Mnemonic = OpName in + defm _vgprcd : VOP3Inst<OpName # "_vgprcd", !cast<VOPProfileMAI>("VOPProfileMAI_" # P # "_VCD")>; + } // End isConvergent = 1, mayRaiseFPException = 0, ReadsModeReg = 1 +} + +defm V_MFMA_F32_4X4X1F32 : MAIInst<"v_mfma_f32_4x4x1f32", "F32_F32_X4", int_amdgcn_mfma_f32_4x4x1f32>; +defm V_MFMA_F32_4X4X4F16 : MAIInst<"v_mfma_f32_4x4x4f16", "F32_V4F16_X4", int_amdgcn_mfma_f32_4x4x4f16>; +defm V_MFMA_I32_4X4X4I8 : MAIInst<"v_mfma_i32_4x4x4i8", "I32_I32_X4", int_amdgcn_mfma_i32_4x4x4i8>; +defm V_MFMA_F32_16X16X1F32 : MAIInst<"v_mfma_f32_16x16x1f32", "F32_F32_X16", int_amdgcn_mfma_f32_16x16x1f32>; +defm V_MFMA_F32_16X16X4F32 : MAIInst<"v_mfma_f32_16x16x4f32", "F32_F32_X4", int_amdgcn_mfma_f32_16x16x4f32>; +defm V_MFMA_F32_16X16X4F16 : MAIInst<"v_mfma_f32_16x16x4f16", "F32_V4F16_X16", int_amdgcn_mfma_f32_16x16x4f16>; +defm V_MFMA_F32_16X16X16F16 : MAIInst<"v_mfma_f32_16x16x16f16", "F32_V4F16_X4", int_amdgcn_mfma_f32_16x16x16f16>; +defm V_MFMA_I32_16X16X4I8 : MAIInst<"v_mfma_i32_16x16x4i8", "I32_I32_X16", int_amdgcn_mfma_i32_16x16x4i8>; +defm V_MFMA_F32_32X32X1F32 : MAIInst<"v_mfma_f32_32x32x1f32", "F32_F32_X32", int_amdgcn_mfma_f32_32x32x1f32>; +defm V_MFMA_F32_32X32X2F32 : MAIInst<"v_mfma_f32_32x32x2f32", "F32_F32_X16", int_amdgcn_mfma_f32_32x32x2f32>; +defm V_MFMA_F32_32X32X4F16 : MAIInst<"v_mfma_f32_32x32x4f16", "F32_V4F16_X32", int_amdgcn_mfma_f32_32x32x4f16>; +defm V_MFMA_F32_32X32X8F16 : MAIInst<"v_mfma_f32_32x32x8f16", "F32_V4F16_X16", int_amdgcn_mfma_f32_32x32x8f16>; +defm V_MFMA_I32_32X32X4I8 : MAIInst<"v_mfma_i32_32x32x4i8", "I32_I32_X32", int_amdgcn_mfma_i32_32x32x4i8>; +defm V_MFMA_I32_16X16X16I8 : MAIInst<"v_mfma_i32_16x16x16i8", "I32_I32_X4", int_amdgcn_mfma_i32_16x16x16i8>; +defm V_MFMA_I32_32X32X8I8 : MAIInst<"v_mfma_i32_32x32x8i8", "I32_I32_X16", int_amdgcn_mfma_i32_32x32x8i8>; +defm V_MFMA_F32_4X4X2BF16 : MAIInst<"v_mfma_f32_4x4x2bf16", "F32_V2I16_X4", int_amdgcn_mfma_f32_4x4x2bf16>; +defm V_MFMA_F32_16X16X2BF16 : MAIInst<"v_mfma_f32_16x16x2bf16", "F32_V2I16_X16", int_amdgcn_mfma_f32_16x16x2bf16>; +defm V_MFMA_F32_16X16X8BF16 : MAIInst<"v_mfma_f32_16x16x8bf16", "F32_V2I16_X4", int_amdgcn_mfma_f32_16x16x8bf16>; +defm V_MFMA_F32_32X32X2BF16 : MAIInst<"v_mfma_f32_32x32x2bf16", "F32_V2I16_X32", int_amdgcn_mfma_f32_32x32x2bf16>; +defm V_MFMA_F32_32X32X4BF16 : MAIInst<"v_mfma_f32_32x32x4bf16", "F32_V2I16_X16", int_amdgcn_mfma_f32_32x32x4bf16>; } // End SubtargetPredicate = HasMAIInsts +let Predicates = [isGFX90APlus] in { + defm V_MFMA_F32_32X32X4BF16_1K : MAIInst<"v_mfma_f32_32x32x4bf16_1k", "F32_V4I16_X32", int_amdgcn_mfma_f32_32x32x4bf16_1k>; + defm V_MFMA_F32_16X16X4BF16_1K : MAIInst<"v_mfma_f32_16x16x4bf16_1k", "F32_V4I16_X16", int_amdgcn_mfma_f32_16x16x4bf16_1k>; + defm V_MFMA_F32_4X4X4BF16_1K : MAIInst<"v_mfma_f32_4x4x4bf16_1k", "F32_V4I16_X4", int_amdgcn_mfma_f32_4x4x4bf16_1k>; + defm V_MFMA_F32_32X32X8BF16_1K : MAIInst<"v_mfma_f32_32x32x8bf16_1k", "F32_V4I16_X16", int_amdgcn_mfma_f32_32x32x8bf16_1k>; + defm V_MFMA_F32_16X16X16BF16_1K : MAIInst<"v_mfma_f32_16x16x16bf16_1k", "F32_V4I16_X4", int_amdgcn_mfma_f32_16x16x16bf16_1k>; + + defm V_MFMA_F64_16X16X4F64 : MAIInst<"v_mfma_f64_16x16x4f64", "F64_16X16X4F64", int_amdgcn_mfma_f64_16x16x4f64>; + defm V_MFMA_F64_4X4X4F64 : MAIInst<"v_mfma_f64_4x4x4f64", "F64_4X4X4F64", int_amdgcn_mfma_f64_4x4x4f64>; +} // End Predicates = [isGFX90APlus] + +let SubtargetPredicate = HasPackedFP32Ops, isCommutable = 1 in { + def V_PK_FMA_F32 : VOP3PInst<"v_pk_fma_f32", VOP3_Profile<VOP_V2F32_V2F32_V2F32_V2F32, VOP3_PACKED>, any_fma>; + def V_PK_MUL_F32 : VOP3PInst<"v_pk_mul_f32", VOP3_Profile<VOP_V2F32_V2F32_V2F32, VOP3_PACKED>, any_fmul>; + def V_PK_ADD_F32 : VOP3PInst<"v_pk_add_f32", VOP3_Profile<VOP_V2F32_V2F32_V2F32, VOP3_PACKED>, any_fadd>; + def V_PK_MOV_B32 : VOP3PInst<"v_pk_mov_b32", VOP3_Profile<VOP_V2I32_V2I32_V2I32, VOP3_PACKED>>; +} // End SubtargetPredicate = HasPackedFP32Ops, isCommutable = 1 + def : MnemonicAlias<"v_accvgpr_read", "v_accvgpr_read_b32">; def : MnemonicAlias<"v_accvgpr_write", "v_accvgpr_write_b32">; @@ -435,7 +493,7 @@ multiclass VOP3P_Real_vi<bits<7> op> { multiclass VOP3P_Real_MAI<bits<7> op> { def _vi : VOP3P_Real<!cast<VOP3_Pseudo>(NAME#"_e64"), SIEncodingFamily.VI>, - VOP3Pe_MAI <op, !cast<VOP3_Pseudo>(NAME#"_e64").Pfl> { + VOP3Pe_MAI <op, !cast<VOP3_Pseudo>(NAME#"_e64").Pfl, ?> { let AssemblerPredicate = HasMAIInsts; let DecoderNamespace = "GFX8"; let Inst{14} = ?; // op_sel_hi(2) @@ -444,9 +502,21 @@ multiclass VOP3P_Real_MAI<bits<7> op> { } } -multiclass VOP3P_Real_MFMA<bits<7> op> { +multiclass VOP3P_Real_MFMA_gfx90a<bits<7> op> { + let SubtargetPredicate = isGFX90AOnly, + AssemblerPredicate = isGFX90AOnly, DecoderNamespace = "GFX90A" in { + def _gfx90a_acd : VOP3P_Real<!cast<VOP3_Pseudo>(NAME#"_e64"), SIEncodingFamily.GFX90A>, + VOP3Pe_MAI <op, !cast<VOP3_Pseudo>(NAME#"_e64").Pfl, 1>; + + def _gfx90a_vcd : VOP3P_Real<!cast<VOP3_Pseudo>(NAME # "_vgprcd" # "_e64"), SIEncodingFamily.GFX90A>, + VOP3Pe_MAI <op, !cast<VOP3_Pseudo>(NAME # "_vgprcd" # "_e64").Pfl, 0>; + } // End AssemblerPredicate = isGFX90AOnly, DecoderNamespace = "GFX90A" +} + +multiclass VOP3P_Real_MFMA<bits<7> op> : + VOP3P_Real_MFMA_gfx90a <op> { def _vi : VOP3P_Real<!cast<VOP3_Pseudo>(NAME#"_e64"), SIEncodingFamily.VI>, - VOP3Pe_MAI <op, !cast<VOP3_Pseudo>(NAME#"_e64").Pfl> { + VOP3Pe_MAI <op, !cast<VOP3_Pseudo>(NAME#"_e64").Pfl, ?> { let AssemblerPredicate = HasMAIInsts; let DecoderNamespace = "GFX8"; } @@ -536,6 +606,21 @@ defm V_MFMA_F32_16X16X8BF16 : VOP3P_Real_MFMA <0x6d>; } // End SubtargetPredicate = HasMAIInsts +defm V_MFMA_F32_32X32X4BF16_1K : VOP3P_Real_MFMA_gfx90a <0x63>; +defm V_MFMA_F32_16X16X4BF16_1K : VOP3P_Real_MFMA_gfx90a <0x64>; +defm V_MFMA_F32_4X4X4BF16_1K : VOP3P_Real_MFMA_gfx90a <0x65>; +defm V_MFMA_F32_32X32X8BF16_1K : VOP3P_Real_MFMA_gfx90a <0x66>; +defm V_MFMA_F32_16X16X16BF16_1K : VOP3P_Real_MFMA_gfx90a <0x67>; +defm V_MFMA_F64_16X16X4F64 : VOP3P_Real_MFMA_gfx90a <0x6e>; +defm V_MFMA_F64_4X4X4F64 : VOP3P_Real_MFMA_gfx90a <0x6f>; + +let SubtargetPredicate = HasPackedFP32Ops in { + defm V_PK_FMA_F32 : VOP3P_Real_vi <0x30>; + defm V_PK_MUL_F32 : VOP3P_Real_vi <0x31>; + defm V_PK_ADD_F32 : VOP3P_Real_vi <0x32>; + defm V_PK_MOV_B32 : VOP3P_Real_vi <0x33>; +} // End SubtargetPredicate = HasPackedFP32Ops + //===----------------------------------------------------------------------===// // GFX10. //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/AMDGPU/VOPInstructions.td b/llvm/lib/Target/AMDGPU/VOPInstructions.td index 282c1002d3c9..382b02144612 100644 --- a/llvm/lib/Target/AMDGPU/VOPInstructions.td +++ b/llvm/lib/Target/AMDGPU/VOPInstructions.td @@ -333,7 +333,7 @@ class VOP3Pe <bits<7> op, VOPProfile P> : Enc64 { let Inst{63} = !if(P.HasSrc2Mods, src2_modifiers{0}, 0); // neg (lo) } -class VOP3Pe_MAI <bits<7> op, VOPProfile P> : Enc64 { +class VOP3Pe_MAI <bits<7> op, VOPProfile P, bit acc_cd = 0> : Enc64 { bits<8> vdst; bits<10> src0; bits<10> src1; @@ -341,14 +341,13 @@ class VOP3Pe_MAI <bits<7> op, VOPProfile P> : Enc64 { bits<3> blgp; bits<3> cbsz; bits<4> abid; - bits<1> clamp; let Inst{7-0} = vdst; let Inst{10-8} = !if(P.HasSrc1, cbsz, 0); let Inst{14-11} = !if(P.HasSrc1, abid, 0); - let Inst{15} = !if(P.HasClamp, clamp{0}, 0); + let Inst{15} = acc_cd; let Inst{22-16} = op; let Inst{31-23} = 0x1a7; //encoding @@ -628,8 +627,8 @@ class VOP_DPP_Pseudo <string OpName, VOPProfile P, list<dag> pattern=[]> : string AsmOperands = P.AsmDPP; let AsmMatchConverter = !if(P.HasModifiers, "cvtDPP", ""); - let SubtargetPredicate = HasDPP; - let AssemblerPredicate = HasDPP; + let SubtargetPredicate = !if(P.HasExt64BitDPP, Has64BitDPP, HasDPP); + let AssemblerPredicate = !if(P.HasExt64BitDPP, Has64BitDPP, HasDPP); let AsmVariantName = !if(P.HasExtDPP, AMDGPUAsmVariants.DPP, AMDGPUAsmVariants.Disable); let Constraints = !if(P.NumSrcArgs, P.TieRegDPP # " = $vdst", ""); @@ -683,8 +682,8 @@ class VOP_DPP <string OpName, VOPProfile P, bit IsDPP16, let Size = 8; let AsmMatchConverter = !if(P.HasModifiers, "cvtDPP", ""); - let SubtargetPredicate = HasDPP; - let AssemblerPredicate = HasDPP; + let SubtargetPredicate = !if(P.HasExt64BitDPP, Has64BitDPP, HasDPP); + let AssemblerPredicate = !if(P.HasExt64BitDPP, Has64BitDPP, HasDPP); let AsmVariantName = !if(P.HasExtDPP, AMDGPUAsmVariants.DPP, AMDGPUAsmVariants.Disable); let Constraints = !if(P.NumSrcArgs, P.TieRegDPP # " = $vdst", ""); |
