[llvm] [AMDGPU] Move EU and Wave Queries into TargetParser (PR #215681)
Chinmay Deshpande via llvm-commits
llvm-commits at lists.llvm.org
Tue Aug 11 14:56:42 PDT 2026
https://github.com/chinmaydd created https://github.com/llvm/llvm-project/pull/215681
This also updates the APIs to use the terms `halfSIMD` and `fullSIMD`. General terminology is up for a debate.
Supersedes: https://github.com/llvm/llvm-project/pull/211312
>From 28f47d05ea2137ef1277b4213d6ca2e0343df864 Mon Sep 17 00:00:00 2001
From: Chinmay Deshpande <chdeshpa at amd.com>
Date: Tue, 11 Aug 2026 17:33:44 -0400
Subject: [PATCH] [AMDGPU] Move EU and Wave Queries into TargetParser
Change-Id: I32b24e6fd7c676d7ca99bdcaa7f9baf351ff4f7f
---
.../llvm/TargetParser/AMDGPUTargetParser.h | 13 ++++
llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp | 2 +-
llvm/lib/Target/AMDGPU/AMDGPUSubtarget.cpp | 9 +--
llvm/lib/Target/AMDGPU/AMDGPUSubtarget.h | 10 +--
llvm/lib/Target/AMDGPU/AMDGPUTargetParser.td | 11 +++
llvm/lib/Target/AMDGPU/GCNProcessors.td | 71 +++++++++++++++++++
llvm/lib/Target/AMDGPU/GCNSubtarget.cpp | 6 +-
llvm/lib/Target/AMDGPU/SIInsertWaitcnts.cpp | 3 +-
.../Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp | 50 ++++---------
llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h | 8 ---
llvm/lib/TargetParser/AMDGPUTargetParser.cpp | 24 +++++++
llvm/test/TableGen/AMDGPUTargetDefErrors.td | 18 +++++
.../llvm-calc-occupancy.cpp | 12 ++--
.../TargetParser/TargetParserTest.cpp | 37 ++++++++++
.../TableGen/Basic/AMDGPUTargetDefEmitter.cpp | 5 +-
15 files changed, 213 insertions(+), 66 deletions(-)
diff --git a/llvm/include/llvm/TargetParser/AMDGPUTargetParser.h b/llvm/include/llvm/TargetParser/AMDGPUTargetParser.h
index f8e283db55fec..e610fbe020803 100644
--- a/llvm/include/llvm/TargetParser/AMDGPUTargetParser.h
+++ b/llvm/include/llvm/TargetParser/AMDGPUTargetParser.h
@@ -194,6 +194,19 @@ LLVM_ABI unsigned getAddressableNumSGPRs(Triple::SubArchType SubArch);
LLVM_ABI unsigned getSGPRAllocGranule(GPUKind AK);
LLVM_ABI unsigned getSGPRAllocGranule(Triple::SubArchType SubArch);
+/// \returns Number of SIMDs (execution units) a work-group's waves run on. In
+/// full-SIMD mode that is every SIMD of the functional block; otherwise the
+/// work-group is confined to half of them. Hardware that cannot split the
+/// block reports the same count either way.
+LLVM_ABI unsigned getWorkGroupSIMDs(GPUKind AK, bool FullSIMDMode);
+LLVM_ABI unsigned getWorkGroupSIMDs(Triple::SubArchType SubArch,
+ bool FullSIMDMode);
+
+/// \returns Maximum number of waves per execution unit without any kind of
+/// limitation.
+LLVM_ABI unsigned getMaxWavesPerEU(GPUKind AK);
+LLVM_ABI unsigned getMaxWavesPerEU(Triple::SubArchType SubArch);
+
/// Fills Features map with default values for given target GPU.
/// \p Features contains overriding target features and this function returns
/// default target features with entries overridden by \p Features.
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp b/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp
index 3d337a466a75e..4a6fcb70c62e4 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp
@@ -419,7 +419,7 @@ const AMDGPUMCExpr *createOccupancy(unsigned InitOcc, const MCExpr *NumSGPRs,
const MCExpr *NumVGPRs,
unsigned DynamicVGPRBlockSize,
const GCNSubtarget &STM, MCContext &Ctx) {
- unsigned MaxWaves = IsaInfo::getMaxWavesPerEU(STM);
+ unsigned MaxWaves = STM.getMaxWavesPerEU();
unsigned Granule = IsaInfo::getVGPRAllocGranule(STM, DynamicVGPRBlockSize);
unsigned TargetTotalNumVGPRs = IsaInfo::getTotalNumVGPRs(STM);
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUSubtarget.cpp b/llvm/lib/Target/AMDGPU/AMDGPUSubtarget.cpp
index 87515d22ed422..97ca03955acda 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUSubtarget.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUSubtarget.cpp
@@ -44,7 +44,7 @@ AMDGPUSubtarget::getMaxLocalMemSizeWithWaveCount(unsigned NWaves,
std::max(1u, (WorkGroupSize + WaveSize - 1) / WaveSize);
const unsigned WorkGroupsPerCU =
- std::max(1u, (NWaves * getEUsPerCU()) / WavesPerWorkgroup);
+ std::max(1u, (NWaves * getWorkGroupSIMDs()) / WavesPerWorkgroup);
return getLocalMemorySize() / WorkGroupsPerCU;
}
@@ -88,7 +88,7 @@ std::pair<unsigned, unsigned> AMDGPUSubtarget::getOccupancyWithWorkGroupSizes(
if (MinWavesPerCU >= MaxWavesPerCU) {
std::swap(MinWavesPerCU, MaxWavesPerCU);
} else {
- const unsigned WaveSlotsPerCU = WavesPerEU * getEUsPerCU();
+ const unsigned WaveSlotsPerCU = WavesPerEU * getWorkGroupSIMDs();
// Look for a potential smaller group size than the maximum which decreases
// the concurrent number of waves on the CU for the same number of
@@ -128,8 +128,9 @@ std::pair<unsigned, unsigned> AMDGPUSubtarget::getOccupancyWithWorkGroupSizes(
// Return the minimum/maximum number of waves on any EU, assuming that all
// wavefronts are spread across all EUs as evenly as possible.
- return {std::clamp(MinWavesPerCU / getEUsPerCU(), 1U, WavesPerEU),
- std::clamp(divideCeil(MaxWavesPerCU, getEUsPerCU()), 1U, WavesPerEU)};
+ return {std::clamp(MinWavesPerCU / getWorkGroupSIMDs(), 1U, WavesPerEU),
+ std::clamp(divideCeil(MaxWavesPerCU, getWorkGroupSIMDs()), 1U,
+ WavesPerEU)};
}
std::pair<unsigned, unsigned> AMDGPUSubtarget::getOccupancyWithWorkGroupSizes(
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUSubtarget.h b/llvm/lib/Target/AMDGPU/AMDGPUSubtarget.h
index 71a8f064ffa11..e135531f2b935 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUSubtarget.h
+++ b/llvm/lib/Target/AMDGPU/AMDGPUSubtarget.h
@@ -54,7 +54,7 @@ class AMDGPUSubtarget {
bool HasSMulHi = false;
bool HasFminFmaxLegacy = true;
- unsigned EUsPerCU = 4;
+ unsigned WorkGroupSIMDs = 4;
unsigned MaxWavesPerEU = 10;
unsigned LocalMemorySize = 0;
unsigned AddressableLocalMemorySize = 0;
@@ -237,10 +237,10 @@ class AMDGPUSubtarget {
return AddressableLocalMemorySize;
}
- /// Number of SIMDs/EUs (execution units) per "CU" ("compute unit"), where the
- /// "CU" is the unit onto which workgroups are mapped. This takes WGP mode vs.
- /// CU mode into account.
- unsigned getEUsPerCU() const { return EUsPerCU; }
+ /// Number of SIMDs (execution units) a work-group's waves run on: all four
+ /// of the block's SIMDs in full-SIMD mode, two when the work-group is
+ /// confined to half of them.
+ unsigned getWorkGroupSIMDs() const { return WorkGroupSIMDs; }
Align getAlignmentForImplicitArgPtr() const {
return isAmdHsaOS() ? Align(8) : Align(4);
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUTargetParser.td b/llvm/lib/Target/AMDGPU/AMDGPUTargetParser.td
index e6ea319017436..8454ee392c5bc 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUTargetParser.td
+++ b/llvm/lib/Target/AMDGPU/AMDGPUTargetParser.td
@@ -47,6 +47,17 @@ class AMDGPUGPUInfo<list<int> isa = []> {
// A pseudo target ("generic"/"generic-hsa") that represents no
// hardware.
bit IsPseudoTarget = false;
+
+ // Maximum number of waves an execution unit can hold, ignoring any resource
+ // limit.
+ int MaxWavesPerEU = 10;
+
+ // Number of execution units (SIMDs) whose waves a workgroup must share: the
+ // full set of SIMDs of the functional block, and the count when a workgroup
+ // is restricted to half of them. Hardware that cannot split the block has
+ // the same count for both.
+ int FullSIMDs = 4;
+ int HalfSIMDs = 4;
}
// An R600 processor that is also a canonical TargetParser GPU.
diff --git a/llvm/lib/Target/AMDGPU/GCNProcessors.td b/llvm/lib/Target/AMDGPU/GCNProcessors.td
index 47dc1f182c7b4..bc93a957039b6 100644
--- a/llvm/lib/Target/AMDGPU/GCNProcessors.td
+++ b/llvm/lib/Target/AMDGPU/GCNProcessors.td
@@ -171,6 +171,7 @@ def GFX909 : AMDGPUProcessorModel<"gfx909", SIQuarterSpeedModel,
def GFX90A : AMDGPUProcessorModel<"gfx90a", SIDPFullSpeedModel,
FeatureISAVersion9_0_A.Features, [9, 0, 0xa]> {
let ArchFeatures = ArchFeaturesW64XnackSramEcc;
+ let MaxWavesPerEU = 8;
}
def GFX90C : AMDGPUProcessorModel<"gfx90c", SIQuarterSpeedModel,
@@ -181,11 +182,13 @@ def GFX90C : AMDGPUProcessorModel<"gfx90c", SIQuarterSpeedModel,
def GFX942 : AMDGPUProcessorModel<"gfx942", SIDPGFX942FullSpeedModel,
FeatureISAVersion9_4_2.Features, [9, 4, 2]> {
let ArchFeatures = ArchFeaturesW64XnackSramEcc;
+ let MaxWavesPerEU = 8;
}
def GFX950 : AMDGPUProcessorModel<"gfx950", SIDPGFX950FullSpeedModel,
FeatureISAVersion9_5_0.Features, [9, 5, 0]> {
let ArchFeatures = ArchFeaturesW64XnackSramEcc;
+ let MaxWavesPerEU = 8;
}
def GFX9_GENERIC : AMDGPUProcessorModel<"gfx9-generic", SIQuarterSpeedModel,
@@ -198,6 +201,7 @@ def GFX9_4_GENERIC : AMDGPUProcessorModel<"gfx9-4-generic", SIDPGFX942FullSpeedM
FeatureISAVersion9_4_Generic.Features, [9, 4, 0]> {
let ArchFeatures = ArchFeaturesW64XnackSramEcc;
let CoveredGPUs = [GFX942, GFX950];
+ let MaxWavesPerEU = 8;
}
//===----------------------------------------------------------------------===//
@@ -207,68 +211,94 @@ def GFX9_4_GENERIC : AMDGPUProcessorModel<"gfx9-4-generic", SIDPGFX942FullSpeedM
def GFX1010 : AMDGPUProcessorModel<"gfx1010", GFX10SpeedModel,
FeatureISAVersion10_1_0.Features, [10, 1, 0]> {
let ArchFeatures = ArchFeaturesW32XnackWgp;
+ let MaxWavesPerEU = 20;
+ let HalfSIMDs = 2;
}
def GFX1011 : AMDGPUProcessorModel<"gfx1011", GFX10SpeedModel,
FeatureISAVersion10_1_1.Features, [10, 1, 1]> {
let ArchFeatures = ArchFeaturesW32XnackWgp;
+ let MaxWavesPerEU = 20;
+ let HalfSIMDs = 2;
}
def GFX1012 : AMDGPUProcessorModel<"gfx1012", GFX10SpeedModel,
FeatureISAVersion10_1_2.Features, [10, 1, 2]> {
let ArchFeatures = ArchFeaturesW32XnackWgp;
+ let MaxWavesPerEU = 20;
+ let HalfSIMDs = 2;
}
def GFX1013 : AMDGPUProcessorModel<"gfx1013", GFX10SpeedModel,
FeatureISAVersion10_1_3.Features, [10, 1, 3]> {
let ArchFeatures = ArchFeaturesW32XnackWgp;
+ let MaxWavesPerEU = 20;
+ let HalfSIMDs = 2;
}
def GFX1030 : AMDGPUProcessorModel<"gfx1030", GFX10SpeedModel,
FeatureISAVersion10_3_0.Features, [10, 3, 0]> {
let ArchFeatures = ArchFeaturesW32Wgp;
+ let MaxWavesPerEU = 16;
+ let HalfSIMDs = 2;
}
def GFX1031 : AMDGPUProcessorModel<"gfx1031", GFX10SpeedModel,
FeatureISAVersion10_3_0.Features, [10, 3, 1]> {
let ArchFeatures = ArchFeaturesW32Wgp;
+ let MaxWavesPerEU = 16;
+ let HalfSIMDs = 2;
}
def GFX1032 : AMDGPUProcessorModel<"gfx1032", GFX10SpeedModel,
FeatureISAVersion10_3_0.Features, [10, 3, 2]> {
let ArchFeatures = ArchFeaturesW32Wgp;
+ let MaxWavesPerEU = 16;
+ let HalfSIMDs = 2;
}
def GFX1033 : AMDGPUProcessorModel<"gfx1033", GFX10SpeedModel,
FeatureISAVersion10_3_0.Features, [10, 3, 3]> {
let ArchFeatures = ArchFeaturesW32Wgp;
+ let MaxWavesPerEU = 16;
+ let HalfSIMDs = 2;
}
def GFX1034 : AMDGPUProcessorModel<"gfx1034", GFX10SpeedModel,
FeatureISAVersion10_3_0.Features, [10, 3, 4]> {
let ArchFeatures = ArchFeaturesW32Wgp;
+ let MaxWavesPerEU = 16;
+ let HalfSIMDs = 2;
}
def GFX1035 : AMDGPUProcessorModel<"gfx1035", GFX10SpeedModel,
FeatureISAVersion10_3_0.Features, [10, 3, 5]> {
let ArchFeatures = ArchFeaturesW32Wgp;
+ let MaxWavesPerEU = 16;
+ let HalfSIMDs = 2;
}
def GFX1036 : AMDGPUProcessorModel<"gfx1036", GFX10SpeedModel,
FeatureISAVersion10_3_0.Features, [10, 3, 6]> {
let ArchFeatures = ArchFeaturesW32Wgp;
+ let MaxWavesPerEU = 16;
+ let HalfSIMDs = 2;
}
def GFX10_1_GENERIC : AMDGPUProcessorModel<"gfx10-1-generic", GFX10SpeedModel,
FeatureISAVersion10_1_Generic.Features, [10, 1, 0]> {
let ArchFeatures = ArchFeaturesW32XnackWgp;
let CoveredGPUs = [GFX1010, GFX1011, GFX1012, GFX1013];
+ let MaxWavesPerEU = 20;
+ let HalfSIMDs = 2;
}
def GFX10_3_GENERIC : AMDGPUProcessorModel<"gfx10-3-generic", GFX10SpeedModel,
FeatureISAVersion10_3_Generic.Features, [10, 3, 0]> {
let ArchFeatures = ArchFeaturesW32Wgp;
let CoveredGPUs = [GFX1030, GFX1031, GFX1032, GFX1033, GFX1034, GFX1035, GFX1036];
+ let MaxWavesPerEU = 16;
+ let HalfSIMDs = 2;
}
//===----------------------------------------------------------------------===//
@@ -278,61 +308,85 @@ def GFX10_3_GENERIC : AMDGPUProcessorModel<"gfx10-3-generic", GFX10SpeedModel,
def GFX1100 : AMDGPUProcessorModel<"gfx1100", GFX11SpeedModel,
FeatureISAVersion11_0_0.Features, [11, 0, 0]> {
let ArchFeatures = ArchFeaturesW32Wgp;
+ let MaxWavesPerEU = 16;
+ let HalfSIMDs = 2;
}
def GFX1101 : AMDGPUProcessorModel<"gfx1101", GFX11SpeedModel,
FeatureISAVersion11_0_1.Features, [11, 0, 1]> {
let ArchFeatures = ArchFeaturesW32Wgp;
+ let MaxWavesPerEU = 16;
+ let HalfSIMDs = 2;
}
def GFX1102 : AMDGPUProcessorModel<"gfx1102", GFX11SpeedModel,
FeatureISAVersion11_0_2.Features, [11, 0, 2]> {
let ArchFeatures = ArchFeaturesW32Wgp;
+ let MaxWavesPerEU = 16;
+ let HalfSIMDs = 2;
}
def GFX1103 : AMDGPUProcessorModel<"gfx1103", GFX11SpeedModel,
FeatureISAVersion11_0_3.Features, [11, 0, 3]> {
let ArchFeatures = ArchFeaturesW32Wgp;
+ let MaxWavesPerEU = 16;
+ let HalfSIMDs = 2;
}
def GFX1150 : AMDGPUProcessorModel<"gfx1150", GFX11SpeedModel,
FeatureISAVersion11_5_0.Features, [11, 5, 0]> {
let ArchFeatures = ArchFeaturesW32Wgp;
+ let MaxWavesPerEU = 16;
+ let HalfSIMDs = 2;
}
def GFX1151 : AMDGPUProcessorModel<"gfx1151", GFX11SpeedModel,
FeatureISAVersion11_5_1.Features, [11, 5, 1]> {
let ArchFeatures = ArchFeaturesW32Wgp;
+ let MaxWavesPerEU = 16;
+ let HalfSIMDs = 2;
}
def GFX1152 : AMDGPUProcessorModel<"gfx1152", GFX11SpeedModel,
FeatureISAVersion11_5_2.Features, [11, 5, 2]> {
let ArchFeatures = ArchFeaturesW32Wgp;
+ let MaxWavesPerEU = 16;
+ let HalfSIMDs = 2;
}
def GFX1153 : AMDGPUProcessorModel<"gfx1153", GFX11SpeedModel,
FeatureISAVersion11_5_Common.Features, [11, 5, 3]> {
let ArchFeatures = ArchFeaturesW32Wgp;
+ let MaxWavesPerEU = 16;
+ let HalfSIMDs = 2;
}
def GFX1154 : AMDGPUProcessorModel<"gfx1154", GFX11SpeedModel,
FeatureISAVersion11_5_Common.Features, [11, 5, 4]> {
let ArchFeatures = ArchFeaturesW32Wgp;
+ let MaxWavesPerEU = 16;
+ let HalfSIMDs = 2;
}
def GFX1170 : AMDGPUProcessorModel<"gfx1170", GFX11SpeedModel,
FeatureISAVersion11_7_Common.Features, [11, 7, 0]> {
let ArchFeatures = ArchFeaturesW32Wgp;
+ let MaxWavesPerEU = 16;
+ let HalfSIMDs = 2;
}
def GFX1171 : AMDGPUProcessorModel<"gfx1171", GFX11SpeedModel,
FeatureISAVersion11_7_Common.Features, [11, 7, 1]> {
let ArchFeatures = ArchFeaturesW32Wgp;
+ let MaxWavesPerEU = 16;
+ let HalfSIMDs = 2;
}
def GFX1172 : AMDGPUProcessorModel<"gfx1172", GFX11SpeedModel,
FeatureISAVersion11_7_Common.Features, [11, 7, 2]> {
let ArchFeatures = ArchFeaturesW32Wgp;
+ let MaxWavesPerEU = 16;
+ let HalfSIMDs = 2;
}
def GFX11_GENERIC : AMDGPUProcessorModel<"gfx11-generic", GFX11SpeedModel,
@@ -340,12 +394,16 @@ def GFX11_GENERIC : AMDGPUProcessorModel<"gfx11-generic", GFX11SpeedModel,
let ArchFeatures = ArchFeaturesW32Wgp;
let CoveredGPUs = [GFX1100, GFX1101, GFX1102, GFX1103, GFX1150, GFX1151, GFX1152, GFX1153,
GFX1154];
+ let MaxWavesPerEU = 16;
+ let HalfSIMDs = 2;
}
def GFX11_7_GENERIC : AMDGPUProcessorModel<"gfx11-7-generic", GFX11SpeedModel,
FeatureISAVersion11_7_Generic.Features, [11, 7, 0]> {
let ArchFeatures = ArchFeaturesW32Wgp;
let CoveredGPUs = [GFX1170, GFX1171, GFX1172];
+ let MaxWavesPerEU = 16;
+ let HalfSIMDs = 2;
}
//===----------------------------------------------------------------------===//
@@ -355,33 +413,42 @@ def GFX11_7_GENERIC : AMDGPUProcessorModel<"gfx11-7-generic", GFX11SpeedModel,
def GFX1200 : AMDGPUProcessorModel<"gfx1200", GFX12SpeedModel,
FeatureISAVersion12.Features, [12, 0, 0]> {
let ArchFeatures = ArchFeaturesW32Wgp;
+ let MaxWavesPerEU = 16;
+ let HalfSIMDs = 2;
}
def GFX1201 : AMDGPUProcessorModel<"gfx1201", GFX12SpeedModel,
FeatureISAVersion12.Features, [12, 0, 1]> {
let ArchFeatures = ArchFeaturesW32Wgp;
+ let MaxWavesPerEU = 16;
+ let HalfSIMDs = 2;
}
def GFX12_GENERIC : AMDGPUProcessorModel<"gfx12-generic", GFX12SpeedModel,
FeatureISAVersion12_Generic.Features, [12, 0, 0]> {
let ArchFeatures = ArchFeaturesW32Wgp;
let CoveredGPUs = [GFX1200, GFX1201];
+ let MaxWavesPerEU = 16;
+ let HalfSIMDs = 2;
}
def GFX1250 : AMDGPUProcessorModel<"gfx1250", GFX1250SpeedModel,
FeatureISAVersion12_50.Features, [12, 5, 0]> {
let ArchFeatures = [FEATURE_FAST_FMA_F32, FEATURE_FAST_DENORMAL_F32, FEATURE_WAVE32, FEATURE_XNACK, FEATURE_SRAMECC];
+ let MaxWavesPerEU = 16;
}
def GFX1251 : AMDGPUProcessorModel<"gfx1251", GFX1251SpeedModel,
FeatureISAVersion12_51.Features, [12, 5, 1]> {
let ArchFeatures = [FEATURE_FAST_FMA_F32, FEATURE_FAST_DENORMAL_F32, FEATURE_WAVE32, FEATURE_XNACK, FEATURE_SRAMECC];
+ let MaxWavesPerEU = 16;
}
def GFX12_5_GENERIC : AMDGPUProcessorModel<"gfx12-5-generic", GFX125xGenericSpeedModel,
FeatureISAVersion12_5_Generic.Features, [12, 5, 0]> {
let ArchFeatures = [FEATURE_FAST_FMA_F32, FEATURE_FAST_DENORMAL_F32, FEATURE_WAVE32, FEATURE_XNACK, FEATURE_SRAMECC];
let CoveredGPUs = [GFX1250, GFX1251];
+ let MaxWavesPerEU = 16;
}
//===----------------------------------------------------------------------===//
@@ -391,12 +458,16 @@ def GFX12_5_GENERIC : AMDGPUProcessorModel<"gfx12-5-generic", GFX125xGenericSpee
def GFX1310 : AMDGPUProcessorModel<"gfx1310", GFX12SpeedModel,
FeatureISAVersion13.Features, [13, 1, 0]> {
let ArchFeatures = ArchFeaturesW32Wgp;
+ let MaxWavesPerEU = 16;
+ let HalfSIMDs = 2;
}
def GFX13_GENERIC : AMDGPUProcessorModel<"gfx13-generic", GFX12SpeedModel,
FeatureISAVersion13_Generic.Features, [13, 1, 0]> {
let ArchFeatures = ArchFeaturesW32Wgp;
let CoveredGPUs = [GFX1310];
+ let MaxWavesPerEU = 16;
+ let HalfSIMDs = 2;
}
// The gfx6/gfx7/gfx8 families have no "gfxN-generic" target, so their major
diff --git a/llvm/lib/Target/AMDGPU/GCNSubtarget.cpp b/llvm/lib/Target/AMDGPU/GCNSubtarget.cpp
index 1c0e718bd8d97..08667d3d70e95 100644
--- a/llvm/lib/Target/AMDGPU/GCNSubtarget.cpp
+++ b/llvm/lib/Target/AMDGPU/GCNSubtarget.cpp
@@ -245,8 +245,10 @@ GCNSubtarget::GCNSubtarget(const Triple &TT, StringRef GPU, StringRef FS,
LLVM_DEBUG(dbgs() << "sramecc setting for subtarget: "
<< TargetID.getSramEccSetting() << '\n');
- MaxWavesPerEU = AMDGPU::IsaInfo::getMaxWavesPerEU(*this);
- EUsPerCU = AMDGPU::IsaInfo::getEUsPerCU(*this);
+ MaxWavesPerEU = AMDGPU::getMaxWavesPerEU(TargetID.getGPUKind());
+ // CU mode confines a work-group to half of the block's SIMDs.
+ WorkGroupSIMDs = AMDGPU::getWorkGroupSIMDs(
+ TargetID.getGPUKind(), /*FullSIMDMode=*/!isCuModeEnabled());
TSInfo = std::make_unique<AMDGPUSelectionDAGInfo>();
diff --git a/llvm/lib/Target/AMDGPU/SIInsertWaitcnts.cpp b/llvm/lib/Target/AMDGPU/SIInsertWaitcnts.cpp
index 16743201d9ee3..3a22bc739ba23 100644
--- a/llvm/lib/Target/AMDGPU/SIInsertWaitcnts.cpp
+++ b/llvm/lib/Target/AMDGPU/SIInsertWaitcnts.cpp
@@ -3688,8 +3688,7 @@ bool SIInsertWaitcnts::run() {
(MF.getFrameInfo().hasCalls() ||
ST.getOccupancyWithNumVGPRs(
TRI.getNumUsedPhysRegs(MRI, AMDGPU::VGPR_32RegClass),
- /*IsDynamicVGPR=*/false) <
- AMDGPU::IsaInfo::getMaxWavesPerEU(ST))) {
+ /*IsDynamicVGPR=*/false) < ST.getMaxWavesPerEU())) {
for (auto [MI, Flag] : EndPgmInsts) {
if (Flag) {
if (ST.requiresNopBeforeDeallocVGPRs()) {
diff --git a/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp b/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp
index b2b1e4237367d..bc16aa88c40d4 100644
--- a/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp
+++ b/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp
@@ -1200,32 +1200,15 @@ unsigned getAddressableLocalMemorySize(const MCSubtargetInfo &STI) {
return 32768;
}
-unsigned getEUsPerCU(const MCSubtargetInfo &STI) {
- // "Per CU" really means "per whatever functional block the waves of a
- // workgroup must share".
-
- // GFX12.5 only supports CU mode, which contains four SIMDs.
- if (isGFX1250(STI)) {
- assert(STI.getFeatureBits().test(FeatureCuMode));
- return 4;
- }
-
- // For gfx10 in CU mode the functional block is the CU, which contains
- // two SIMDs.
- if (isGFX10Plus(STI) && STI.getFeatureBits().test(FeatureCuMode))
- return 2;
-
- // Pre-gfx10 a CU contains four SIMDs. For gfx10 in WGP mode the WGP
- // contains two CUs, so a total of four SIMDs.
- return 4;
-}
-
unsigned getMaxWorkGroupsPerCU(const MCSubtargetInfo &STI,
unsigned FlatWorkGroupSize) {
assert(FlatWorkGroupSize != 0);
if (!STI.getTargetTriple().isAMDGCN())
return 8;
- unsigned MaxWaves = getMaxWavesPerEU(STI) * getEUsPerCU(STI);
+ GPUKind Kind = parseArchAMDGCN(STI.getCPU());
+ bool FullSIMDMode = !STI.getFeatureBits().test(FeatureCuMode);
+ unsigned MaxWaves =
+ getMaxWavesPerEU(Kind) * getWorkGroupSIMDs(Kind, FullSIMDMode);
unsigned N = getWavesPerWorkGroup(STI, FlatWorkGroupSize);
if (N == 1) {
// Single-wave workgroups don't consume barrier resources.
@@ -1241,19 +1224,12 @@ unsigned getMaxWorkGroupsPerCU(const MCSubtargetInfo &STI,
unsigned getMinWavesPerEU(const MCSubtargetInfo &STI) { return 1; }
-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;
-}
-
unsigned getWavesPerEUForWorkGroup(const MCSubtargetInfo &STI,
unsigned FlatWorkGroupSize) {
+ GPUKind Kind = parseArchAMDGCN(STI.getCPU());
+ bool FullSIMDMode = !STI.getFeatureBits().test(FeatureCuMode);
return divideCeil(getWavesPerWorkGroup(STI, FlatWorkGroupSize),
- getEUsPerCU(STI));
+ getWorkGroupSIMDs(Kind, FullSIMDMode));
}
unsigned getMinFlatWorkGroupSize(const MCSubtargetInfo &STI) { return 1; }
@@ -1291,10 +1267,10 @@ unsigned getMinNumSGPRs(const MCSubtargetInfo &STI, unsigned WavesPerEU) {
if (Version.Major >= 10)
return 0;
- if (WavesPerEU >= getMaxWavesPerEU(STI))
+ GPUKind Kind = parseArchAMDGCN(STI.getCPU());
+ if (WavesPerEU >= getMaxWavesPerEU(Kind))
return 0;
- GPUKind Kind = parseArchAMDGCN(STI.getCPU());
unsigned MinNumSGPRs =
getSGPRBudgetPerWave(getTotalNumSGPRs(Kind), WavesPerEU + 1,
getSGPRTrapHandlerReserve(STI),
@@ -1444,7 +1420,7 @@ unsigned getNumWavesPerEUWithNumVGPRs(const MCSubtargetInfo &STI,
unsigned DynamicVGPRBlockSize) {
return getNumWavesPerEUWithNumVGPRs(
NumVGPRs, getVGPRAllocGranule(STI, DynamicVGPRBlockSize),
- getMaxWavesPerEU(STI), getTotalNumVGPRs(STI));
+ getMaxWavesPerEU(parseArchAMDGCN(STI.getCPU())), getTotalNumVGPRs(STI));
}
unsigned getNumWavesPerEUWithNumVGPRs(unsigned NumVGPRs, unsigned Granule,
@@ -1467,12 +1443,12 @@ unsigned getOccupancyWithNumSGPRs(unsigned SGPRs, unsigned MaxWaves,
}
unsigned getOccupancyWithNumSGPRs(const MCSubtargetInfo &STI, unsigned SGPRs) {
- unsigned MaxWaves = getMaxWavesPerEU(STI);
+ GPUKind Kind = parseArchAMDGCN(STI.getCPU());
+ unsigned MaxWaves = getMaxWavesPerEU(Kind);
if (!isSGPROccupancyLimited(STI))
return MaxWaves;
- GPUKind Kind = parseArchAMDGCN(STI.getCPU());
return getOccupancyWithNumSGPRs(SGPRs, MaxWaves, getTotalNumSGPRs(Kind),
getSGPRAllocGranule(Kind),
getSGPRTrapHandlerReserve(STI));
@@ -1490,7 +1466,7 @@ unsigned getMinNumVGPRs(const MCSubtargetInfo &STI, unsigned WavesPerEU,
if (DynamicVGPREnabled)
return 0;
- unsigned MaxWavesPerEU = getMaxWavesPerEU(STI);
+ unsigned MaxWavesPerEU = getMaxWavesPerEU(parseArchAMDGCN(STI.getCPU()));
if (WavesPerEU >= MaxWavesPerEU)
return 0;
diff --git a/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h b/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h
index 7d0bdbc661bc1..3e5f8d6cd744d 100644
--- a/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h
+++ b/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h
@@ -183,10 +183,6 @@ unsigned getLocalMemorySize(const MCSubtargetInfo &STI);
/// \p STI.
unsigned getAddressableLocalMemorySize(const MCSubtargetInfo &STI);
-/// \returns Number of execution units per compute unit for given subtarget \p
-/// STI.
-unsigned getEUsPerCU(const MCSubtargetInfo &STI);
-
/// \returns Maximum number of work groups per compute unit for given subtarget
/// \p STI and limited by given \p FlatWorkGroupSize.
unsigned getMaxWorkGroupsPerCU(const MCSubtargetInfo &STI,
@@ -196,10 +192,6 @@ unsigned getMaxWorkGroupsPerCU(const MCSubtargetInfo &STI,
/// STI.
unsigned getMinWavesPerEU(const MCSubtargetInfo &STI);
-/// \returns Maximum number of waves per execution unit for given subtarget \p
-/// STI without any kind of limitation.
-unsigned getMaxWavesPerEU(const MCSubtargetInfo &STI);
-
/// \returns Number of waves per execution unit required to support the given \p
/// FlatWorkGroupSize.
unsigned getWavesPerEUForWorkGroup(const MCSubtargetInfo &STI,
diff --git a/llvm/lib/TargetParser/AMDGPUTargetParser.cpp b/llvm/lib/TargetParser/AMDGPUTargetParser.cpp
index d8abaf7474cd6..45cb2863fa743 100644
--- a/llvm/lib/TargetParser/AMDGPUTargetParser.cpp
+++ b/llvm/lib/TargetParser/AMDGPUTargetParser.cpp
@@ -41,6 +41,9 @@ struct GPUInfo {
AMDGPUFeatureBitset Features;
IsaVersion Version;
StringTable::Offset FamilyName;
+ uint8_t MaxWavesPerEU;
+ uint8_t FullSIMDs;
+ uint8_t HalfSIMDs;
};
// Per-GPU data for the R600 GPUKinds.
@@ -422,6 +425,27 @@ unsigned AMDGPU::getSGPRAllocGranule(Triple::SubArchType SubArch) {
return 8;
}
+unsigned AMDGPU::getWorkGroupSIMDs(GPUKind AK, bool FullSIMDMode) {
+ const GPUInfo *Info = getAMDGPUInfo(AK);
+ if (!Info)
+ return 4;
+ return FullSIMDMode ? Info->FullSIMDs : Info->HalfSIMDs;
+}
+
+unsigned AMDGPU::getWorkGroupSIMDs(Triple::SubArchType SubArch,
+ bool FullSIMDMode) {
+ return getWorkGroupSIMDs(getGPUKindFromSubArch(SubArch), FullSIMDMode);
+}
+
+unsigned AMDGPU::getMaxWavesPerEU(GPUKind AK) {
+ const GPUInfo *Info = getAMDGPUInfo(AK);
+ return Info ? Info->MaxWavesPerEU : 10;
+}
+
+unsigned AMDGPU::getMaxWavesPerEU(Triple::SubArchType SubArch) {
+ return getMaxWavesPerEU(getGPUKindFromSubArch(SubArch));
+}
+
StringRef AMDGPU::getCanonicalArchName(const Triple &T, StringRef Arch) {
assert(T.isAMDGPU());
auto ProcKind = T.isAMDGCN() ? parseArchAMDGCN(Arch) : parseArchR600(Arch);
diff --git a/llvm/test/TableGen/AMDGPUTargetDefErrors.td b/llvm/test/TableGen/AMDGPUTargetDefErrors.td
index 106b168917676..1d94725625665 100644
--- a/llvm/test/TableGen/AMDGPUTargetDefErrors.td
+++ b/llvm/test/TableGen/AMDGPUTargetDefErrors.td
@@ -23,6 +23,9 @@ class AMDGPUGPUInfo<list<int> isa = []> {
list<int> IsaVersion = isa;
list<Processor> CoveredGPUs = [];
bit IsPseudoTarget = false;
+ int MaxWavesPerEU = 10;
+ int FullSIMDs = 4;
+ int HalfSIMDs = 4;
}
def : ProcessorModel<"gfx900", NoSchedModel, []>, AMDGPUGPUInfo<[9, 0, 0]>;
@@ -39,6 +42,9 @@ class AMDGPUGPUInfo<list<int> isa = []> {
list<int> IsaVersion = isa;
list<Processor> CoveredGPUs = [];
bit IsPseudoTarget = false;
+ int MaxWavesPerEU = 10;
+ int FullSIMDs = 4;
+ int HalfSIMDs = 4;
}
def DupA : ProcessorModel<"gfx900", NoSchedModel, []>, AMDGPUGPUInfo<[9, 0, 0]>;
@@ -55,6 +61,9 @@ class AMDGPUGPUInfo<list<int> isa = []> {
list<int> IsaVersion = isa;
list<Processor> CoveredGPUs = [];
bit IsPseudoTarget = false;
+ int MaxWavesPerEU = 10;
+ int FullSIMDs = 4;
+ int HalfSIMDs = 4;
}
def : ProcessorModel<"gfx900", NoSchedModel, []>, AMDGPUGPUInfo<[9, 0, 0]>;
@@ -71,6 +80,9 @@ class AMDGPUGPUInfo<list<int> isa = []> {
list<int> IsaVersion = isa;
list<Processor> CoveredGPUs = [];
bit IsPseudoTarget = false;
+ int MaxWavesPerEU = 10;
+ int FullSIMDs = 4;
+ int HalfSIMDs = 4;
}
// A malformed IsaVersion is reported (not asserted), so this stays a clean
// diagnostic in release builds.
@@ -86,6 +98,9 @@ class AMDGPUGPUInfo<list<int> isa = []> {
list<int> IsaVersion = isa;
list<Processor> CoveredGPUs = [];
bit IsPseudoTarget = false;
+ int MaxWavesPerEU = 10;
+ int FullSIMDs = 4;
+ int HalfSIMDs = 4;
}
// The stepping must fit in a single hex digit so it can be spelled in the
// triple subarch name (e.g. "amdgpu9.0c").
@@ -101,6 +116,9 @@ class AMDGPUGPUInfo<list<int> isa = []> {
list<int> IsaVersion = isa;
list<Processor> CoveredGPUs = [];
bit IsPseudoTarget = false;
+ int MaxWavesPerEU = 10;
+ int FullSIMDs = 4;
+ int HalfSIMDs = 4;
}
def FeatureFoo : SubtargetFeature<"foo", "HasFoo", "true", "Foo">;
diff --git a/llvm/tools/llvm-calc-occupancy/llvm-calc-occupancy.cpp b/llvm/tools/llvm-calc-occupancy/llvm-calc-occupancy.cpp
index ed44d7531640e..5952cfc4fa36a 100644
--- a/llvm/tools/llvm-calc-occupancy/llvm-calc-occupancy.cpp
+++ b/llvm/tools/llvm-calc-occupancy/llvm-calc-occupancy.cpp
@@ -220,8 +220,8 @@ int main(int argc, char **argv) {
// Hardware characteristics.
unsigned WaveSize = AMDGPU::IsaInfo::getWavefrontSize(STI);
- unsigned MaxWaves = AMDGPU::IsaInfo::getMaxWavesPerEU(STI);
- unsigned EUsPerCU = AMDGPU::IsaInfo::getEUsPerCU(STI);
+ unsigned MaxWaves = ST.getMaxWavesPerEU();
+ unsigned WorkGroupSIMDs = ST.getWorkGroupSIMDs();
unsigned LocalMemSize = AMDGPU::IsaInfo::getLocalMemorySize(STI);
unsigned AddrLocalMem = AMDGPU::IsaInfo::getAddressableLocalMemorySize(STI);
unsigned AddrVGPRs =
@@ -264,7 +264,7 @@ int main(int argc, char **argv) {
outs() << format(" %-20s %u\n", "Wavefront size:", WaveSize);
outs() << format(" %-20s %u (waves per SIMD, hardware limit)\n",
"Max waves/EU:", MaxWaves);
- outs() << format(" %-20s %u\n", "EUs (SIMDs) per CU:", EUsPerCU);
+ outs() << format(" %-20s %u\n", "SIMDs per work-group:", WorkGroupSIMDs);
outs() << format(" %-20s %s\n",
"LDS per CU:", formatBytes(LocalMemSize).c_str());
outs() << format(" %-20s %s\n", "Addressable LDS:",
@@ -332,11 +332,11 @@ int main(int argc, char **argv) {
outs() << "\nResult\n";
if (MinOcc == MaxOcc)
outs() << format(" %-20s %u waves/EU (%u waves/CU)\n",
- "Occupancy:", MaxOcc, MaxOcc * EUsPerCU);
+ "Occupancy:", MaxOcc, MaxOcc * WorkGroupSIMDs);
else
outs() << format(" %-20s %u .. %u waves/EU (%u .. %u waves/CU)\n",
- "Occupancy:", MinOcc, MaxOcc, MinOcc * EUsPerCU,
- MaxOcc * EUsPerCU);
+ "Occupancy:", MinOcc, MaxOcc, MinOcc * WorkGroupSIMDs,
+ MaxOcc * WorkGroupSIMDs);
outs() << format(" %-20s %s\n",
"Limited by:", join(LimitedBy, ", ").c_str());
diff --git a/llvm/unittests/TargetParser/TargetParserTest.cpp b/llvm/unittests/TargetParser/TargetParserTest.cpp
index 8939c0e7a162c..aa447bddfad41 100644
--- a/llvm/unittests/TargetParser/TargetParserTest.cpp
+++ b/llvm/unittests/TargetParser/TargetParserTest.cpp
@@ -3027,6 +3027,43 @@ TEST(TargetParserTest, testAMDGPUgetSGPRAllocGranule) {
EXPECT_EQ(AMDGPU::getSGPRAllocGranule(AMDGPU::GK_GFX1030), 106u);
}
+TEST(TargetParserTest, testAMDGPUgetWorkGroupSIMDs) {
+ // The functional block has four SIMDs everywhere. A target that can split it
+ // runs a work-group on two of them outside full-SIMD mode; one that cannot -
+ // pre-GFX10, and GFX10+ targets such as GFX12.5 - runs on four either way.
+ // The second argument is the full-SIMD-mode flag.
+ EXPECT_EQ(AMDGPU::getWorkGroupSIMDs(Triple::AMDGPUSubArch900, true), 4u);
+ EXPECT_EQ(AMDGPU::getWorkGroupSIMDs(Triple::AMDGPUSubArch908, true), 4u);
+ EXPECT_EQ(AMDGPU::getWorkGroupSIMDs(Triple::AMDGPUSubArch942, true), 4u);
+ EXPECT_EQ(AMDGPU::getWorkGroupSIMDs(Triple::AMDGPUSubArch950, true), 4u);
+ EXPECT_EQ(AMDGPU::getWorkGroupSIMDs(Triple::AMDGPUSubArch1030, true), 4u);
+ EXPECT_EQ(AMDGPU::getWorkGroupSIMDs(Triple::AMDGPUSubArch1030, false), 2u);
+ EXPECT_EQ(AMDGPU::getWorkGroupSIMDs(Triple::AMDGPUSubArch1250, false), 4u);
+
+ // The GPUKind overload resolves to the same values.
+ EXPECT_EQ(AMDGPU::getWorkGroupSIMDs(AMDGPU::GK_GFX900, true), 4u);
+ EXPECT_EQ(AMDGPU::getWorkGroupSIMDs(AMDGPU::GK_GFX1030, true), 4u);
+ EXPECT_EQ(AMDGPU::getWorkGroupSIMDs(AMDGPU::GK_GFX1030, false), 2u);
+}
+
+TEST(TargetParserTest, testAMDGPUgetMaxWavesPerEU) {
+ // GFX90A+ -> 8, other pre-GFX10 -> 10, GFX10.1 -> 20, GFX10.3 and every
+ // later generation -> 16.
+ EXPECT_EQ(AMDGPU::getMaxWavesPerEU(Triple::AMDGPUSubArch900), 10u);
+ EXPECT_EQ(AMDGPU::getMaxWavesPerEU(Triple::AMDGPUSubArch908), 10u);
+ EXPECT_EQ(AMDGPU::getMaxWavesPerEU(Triple::AMDGPUSubArch90A), 8u);
+ EXPECT_EQ(AMDGPU::getMaxWavesPerEU(Triple::AMDGPUSubArch942), 8u);
+ EXPECT_EQ(AMDGPU::getMaxWavesPerEU(Triple::AMDGPUSubArch950), 8u);
+ EXPECT_EQ(AMDGPU::getMaxWavesPerEU(Triple::AMDGPUSubArch1010), 20u);
+ EXPECT_EQ(AMDGPU::getMaxWavesPerEU(Triple::AMDGPUSubArch1030), 16u);
+ EXPECT_EQ(AMDGPU::getMaxWavesPerEU(Triple::AMDGPUSubArch1250), 16u);
+
+ // The GPUKind overload resolves to the same values.
+ EXPECT_EQ(AMDGPU::getMaxWavesPerEU(AMDGPU::GK_GFX908), 10u);
+ EXPECT_EQ(AMDGPU::getMaxWavesPerEU(AMDGPU::GK_GFX90A), 8u);
+ EXPECT_EQ(AMDGPU::getMaxWavesPerEU(AMDGPU::GK_GFX1030), 16u);
+}
+
TEST(TargetParserTest, testAMDGPUParseTargetIDString) {
using AMDGPU::TargetID;
using AMDGPU::TargetIDSetting;
diff --git a/llvm/utils/TableGen/Basic/AMDGPUTargetDefEmitter.cpp b/llvm/utils/TableGen/Basic/AMDGPUTargetDefEmitter.cpp
index d077178f98526..34b883042a647 100644
--- a/llvm/utils/TableGen/Basic/AMDGPUTargetDefEmitter.cpp
+++ b/llvm/utils/TableGen/Basic/AMDGPUTargetDefEmitter.cpp
@@ -534,7 +534,10 @@ emitAMDGPUTable(raw_ostream &OS, const RecordKeeper &RK,
emitFeatureBitset(OS, R, FeatureIdx);
OS << ", ";
emitIsaVersion(OS, R, '{', '}');
- OS << ", " << Names.GetOrAddStringOffset(getArchFamily(R)) << "},\n";
+ OS << ", " << Names.GetOrAddStringOffset(getArchFamily(R)) << ", "
+ << R->getValueAsInt("MaxWavesPerEU") << ", "
+ << R->getValueAsInt("FullSIMDs") << ", " << R->getValueAsInt("HalfSIMDs")
+ << "},\n";
}
OS << "};\n"
"#endif // GET_AMDGPU_GPU_TABLE\n\n";
More information about the llvm-commits
mailing list