[llvm-branch-commits] [llvm] [AMDGPU] Add `getLDSAllocGranule` to TargetParser (PR #220051)

Chinmay Deshpande via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Thu Sep 10 13:52:07 PDT 2026


https://github.com/chinmaydd updated https://github.com/llvm/llvm-project/pull/220051

>From cfd2b4d3bcc614a13eea4db2bd4294ae918de003 Mon Sep 17 00:00:00 2001
From: Chinmay Deshpande <chdeshpa at amd.com>
Date: Thu, 10 Sep 2026 14:56:13 -0400
Subject: [PATCH 1/2] [AMDGPU] Model LDS allocation granularity with subtarget
 features

Add numeric LDS allocation granularity features, expose them through the TargetParser feature bitset, and use them in the existing backend query.

Generic targets select the largest covered allocation granularity so their resource calculations remain conservative.

Change-Id: Icdd501d008c9d3cd566bdc8bde4a75d566ecb90a
---
 llvm/lib/Target/AMDGPU/AMDGPU.td              | 26 ++++++-
 llvm/lib/Target/AMDGPU/AMDGPUFeatures.td      | 17 +++++
 llvm/lib/Target/AMDGPU/R600Processors.td      |  6 +-
 .../Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp    | 12 ++--
 llvm/lib/TargetParser/AMDGPUTargetParser.cpp  |  7 +-
 llvm/test/TableGen/AMDGPUTargetDefErrors.td   | 70 +++++++++++++++++++
 .../TargetParser/TargetParserTest.cpp         | 46 ++++++++++++
 .../TableGen/Basic/AMDGPUTargetDefEmitter.cpp | 57 +++++++++++++--
 8 files changed, 223 insertions(+), 18 deletions(-)

diff --git a/llvm/lib/Target/AMDGPU/AMDGPU.td b/llvm/lib/Target/AMDGPU/AMDGPU.td
index 3502e65a3f6e6..8d380fbb6e054 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPU.td
+++ b/llvm/lib/Target/AMDGPU/AMDGPU.td
@@ -1606,7 +1606,8 @@ class GCNSubtargetFeatureGeneration <string Value,
 
 def FeatureSouthernIslands : GCNSubtargetFeatureGeneration<"SOUTHERN_ISLANDS",
     "southern-islands",
-  [FeatureFP64, FeatureAddressableLocalMemorySize32768, FeatureMIMG_R128,
+  [FeatureFP64, FeatureAddressableLocalMemorySize32768,
+  FeatureLDSAllocGranularity256, FeatureMIMG_R128,
   FeatureWavefrontSize64, FeatureSupportsWave64, FeatureSMemTimeInst,
   FeatureMadMacF32Insts,
   FeatureDsSrc2Insts, FeatureLDSBankCount32, FeatureMovrel,
@@ -1624,7 +1625,8 @@ def FeatureSouthernIslands : GCNSubtargetFeatureGeneration<"SOUTHERN_ISLANDS",
 
 def FeatureSeaIslands : GCNSubtargetFeatureGeneration<"SEA_ISLANDS",
     "sea-islands",
-  [FeatureFP64, FeatureAddressableLocalMemorySize65536, FeatureMIMG_R128,
+  [FeatureFP64, FeatureAddressableLocalMemorySize65536,
+  FeatureLDSAllocGranularity512, FeatureMIMG_R128,
   FeatureWavefrontSize64, FeatureSupportsWave64, FeatureFlatAddressSpace,
   FeatureCIInsts, FeatureMovrel, FeatureTrigReducedRange,
   FeatureGFX7GFX8GFX9Insts, FeatureSMemTimeInst, FeatureMadMacF32Insts,
@@ -1644,7 +1646,8 @@ def FeatureSeaIslands : GCNSubtargetFeatureGeneration<"SEA_ISLANDS",
 
 def FeatureVolcanicIslands : GCNSubtargetFeatureGeneration<"VOLCANIC_ISLANDS",
   "volcanic-islands",
-  [FeatureFP64, FeatureAddressableLocalMemorySize65536, FeatureMIMG_R128,
+  [FeatureFP64, FeatureAddressableLocalMemorySize65536,
+   FeatureLDSAllocGranularity512, FeatureMIMG_R128,
    FeatureWavefrontSize64, FeatureSupportsWave64, FeatureFlatAddressSpace,
    FeatureGCN3Encoding, FeatureCIInsts, Feature16BitInsts,
    FeatureSMemRealTime, FeatureVGPRIndexMode, FeatureMovrel,
@@ -1694,6 +1697,7 @@ def FeatureGFX9 : GCNSubtargetFeatureGeneration<"GFX9",
 def FeatureGFX10 : GCNSubtargetFeatureGeneration<"GFX10",
   "gfx10",
   [FeatureFP64, FeatureAddressableLocalMemorySize65536,
+   FeatureLDSAllocGranularity512,
    FeatureHalfAddressablePhysicalLocalMemory, FeatureMIMG_R128,
    FeatureSupportsWave32, FeatureSupportsWave64, FeatureSupportsWGP,
    FeatureFlatAddressSpace,
@@ -1728,6 +1732,7 @@ def FeatureGFX10 : GCNSubtargetFeatureGeneration<"GFX10",
 def FeatureGFX11 : GCNSubtargetFeatureGeneration<"GFX11",
   "gfx11",
   [FeatureFP64, FeatureAddressableLocalMemorySize65536,
+   FeatureLDSAllocGranularity512,
    FeatureHalfAddressablePhysicalLocalMemory, FeatureMIMG_R128,
    FeatureSupportsWave32, FeatureSupportsWave64, FeatureSupportsWGP,
    FeatureFlatAddressSpace, Feature16BitInsts,
@@ -1898,6 +1903,7 @@ def FeatureISAVersion8_1_0 : FeatureSet<
 def FeatureISAVersion9_0_Common : FeatureSet<
   [FeatureGFX9,
    FeatureAddressableLocalMemorySize65536,
+   FeatureLDSAllocGranularity512,
    FeatureLDSBankCount32,
    FeatureImageInsts,
    FeatureMadMacF32Insts]>;
@@ -2047,6 +2053,7 @@ def FeatureISAVersion9_4_Common : FeatureSet<
 def FeatureISAVersion9_5_Common : FeatureSet<
   !listconcat(FeatureISAVersion9_4_Common.Features,
   [FeatureAddressableLocalMemorySize163840,
+   FeatureLDSAllocGranularity1280,
    FeatureLDSBankCount64,
    FeatureFP8Insts,
    FeatureFP8ConversionInsts,
@@ -2069,6 +2076,7 @@ def FeatureISAVersion9_4_2 : FeatureSet<
   !listconcat(FeatureISAVersion9_4_Common.Features,
     [
       FeatureAddressableLocalMemorySize65536,
+      FeatureLDSAllocGranularity512,
       FeatureLDSBankCount32,
       FeatureFP8Insts,
       FeatureFP8ConversionInsts,
@@ -2080,6 +2088,7 @@ def FeatureISAVersion9_4_2 : FeatureSet<
 def FeatureISAVersion9_4_Generic : FeatureSet<
   !listconcat(FeatureISAVersion9_4_Common.Features,
     [FeatureAddressableLocalMemorySize65536,
+     FeatureLDSAllocGranularity1280,
      FeatureLDSBankCount32,
      FeatureRequiresCOV6])>;
 
@@ -2288,6 +2297,7 @@ def FeatureISAVersion12 : FeatureSet<
    FeatureSupportsWave64, FeatureSupportsWGP,
    FeatureBackOffBarrier,
    FeatureAddressableLocalMemorySize65536,
+   FeatureLDSAllocGranularity512,
    FeatureHalfAddressablePhysicalLocalMemory,
    FeatureLDSBankCount32,
    FeatureDLInsts,
@@ -2448,6 +2458,7 @@ def FeatureISAVersion12_50_STRICT : FeatureSet<
   !listconcat(FeatureISAVersion12_50_Common.Features,
   [FeatureGFX1250_STRICT,
    FeatureAddressableLocalMemorySize327680,
+   FeatureLDSAllocGranularity2048,
    FeatureVOP3PX2IncrementsVaVdstTwice,
    FeatureSetregVGPRMSBFixup,
    FeatureCubeInsts,
@@ -2475,6 +2486,7 @@ def FeatureISAVersion12_50_STRICT : FeatureSet<
 def FeatureISAVersion12_50 : FeatureSet<
   !listconcat(FeatureISAVersion12_50_Common.Features,
   [FeatureAddressableLocalMemorySize327680,
+   FeatureLDSAllocGranularity2048,
    FeatureWMMAN16Insts,
    FeatureVOP3PX2IncrementsVaVdstTwice,
    FeatureSetregVGPRMSBFixup,
@@ -2502,6 +2514,7 @@ def FeatureISAVersion12_50 : FeatureSet<
 def FeatureISAVersion12_51 : FeatureSet<
   !listconcat(FeatureISAVersion12_50_Common.Features,
   [FeatureAddressableLocalMemorySize327680,
+   FeatureLDSAllocGranularity2048,
    FeatureWMMAN16Insts,
    FeatureFullRate64Ops,
    FeatureVOP3PX2IncrementsVaVdstTwice,
@@ -2537,6 +2550,7 @@ def FeatureISAVersion12_Generic: FeatureSet<
 def FeatureISAVersion12_5_Generic: FeatureSet<
   !listconcat(FeatureISAVersion12_50_Common.Features,
   [FeatureAddressableLocalMemorySize327680,
+   FeatureLDSAllocGranularity2048,
    FeatureSetregVGPRMSBFixup,
    FeatureRequiresCOV6,
    FeatureGFX125xLowestRateWMMA,
@@ -2551,6 +2565,7 @@ def FeatureISAVersion13 : FeatureSet<
   [FeatureGFX13,
    FeatureGFX1250Insts,
    FeatureAddressableLocalMemorySize196608,
+   FeatureLDSAllocGranularity1024,
    Feature64BitLiterals,
    FeatureLDSBankCount32,
    FeatureDLInsts,
@@ -3237,6 +3252,11 @@ def AMDGPUFrontendVisibleFeatures {
   FeatureSGPRInitBug, FeatureApertureRegs, FeatureGetDoorbellID,
   FeatureAGPRAlloc, Feature1536VGPRs, Feature1024AddressableVGPRs,
   FeatureHalfAddressablePhysicalLocalMemory,
+  FeatureLDSAllocGranularity256,
+  FeatureLDSAllocGranularity512,
+  FeatureLDSAllocGranularity1024,
+  FeatureLDSAllocGranularity1280,
+  FeatureLDSAllocGranularity2048,
   ];
 }
 
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUFeatures.td b/llvm/lib/Target/AMDGPU/AMDGPUFeatures.td
index 1d398830f07c6..fe598b07cb34f 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUFeatures.td
+++ b/llvm/lib/Target/AMDGPU/AMDGPUFeatures.td
@@ -45,6 +45,23 @@ def FeatureAddressableLocalMemorySize163840 : SubtargetFeatureAddressableLocalMe
 def FeatureAddressableLocalMemorySize196608 : SubtargetFeatureAddressableLocalMemorySize<196608>;
 def FeatureAddressableLocalMemorySize327680 : SubtargetFeatureAddressableLocalMemorySize<327680>;
 
+class SubtargetFeatureLDSAllocGranularity <int Granularity> : SubtargetFeature <
+  "lds-alloc-granularity-"#Granularity,
+  "LDSAllocationGranularity",
+  !cast<string>(Granularity),
+  "LDS allocation granularity in bytes."
+> {
+  // SubtargetFeature.Value is string-typed; preserve the numeric value for
+  // TableGen backends.
+  int NumericValue = Granularity;
+}
+
+def FeatureLDSAllocGranularity256 : SubtargetFeatureLDSAllocGranularity<256>;
+def FeatureLDSAllocGranularity512 : SubtargetFeatureLDSAllocGranularity<512>;
+def FeatureLDSAllocGranularity1024 : SubtargetFeatureLDSAllocGranularity<1024>;
+def FeatureLDSAllocGranularity1280 : SubtargetFeatureLDSAllocGranularity<1280>;
+def FeatureLDSAllocGranularity2048 : SubtargetFeatureLDSAllocGranularity<2048>;
+
 // Whether each wavefront size mode is available on the hardware,
 // independent of the active mode.
 def FeatureSupportsWave32 : SubtargetFeature<"supports-wave32",
diff --git a/llvm/lib/Target/AMDGPU/R600Processors.td b/llvm/lib/Target/AMDGPU/R600Processors.td
index 7a5847a493d6f..d465f1b52d556 100644
--- a/llvm/lib/Target/AMDGPU/R600Processors.td
+++ b/llvm/lib/Target/AMDGPU/R600Processors.td
@@ -59,13 +59,15 @@ def FeatureR700 : R600SubtargetFeatureGeneration<"R700", "r700",
 >;
 
 def FeatureEvergreen : R600SubtargetFeatureGeneration<"EVERGREEN", "evergreen",
-  [FeatureFetchLimit16, FeatureAddressableLocalMemorySize32768, FeatureMadMacF32Insts]
+  [FeatureFetchLimit16, FeatureAddressableLocalMemorySize32768,
+   FeatureLDSAllocGranularity256, FeatureMadMacF32Insts]
 >;
 
 def FeatureNorthernIslands : R600SubtargetFeatureGeneration<"NORTHERN_ISLANDS",
   "northern-islands",
   [FeatureFetchLimit16, FeatureWavefrontSize64,
-   FeatureAddressableLocalMemorySize32768, FeatureMadMacF32Insts]
+   FeatureAddressableLocalMemorySize32768, FeatureLDSAllocGranularity256,
+   FeatureMadMacF32Insts]
 >;
 
 //===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp b/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp
index 3a7916b80c37f..912236e7860fa 100644
--- a/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp
+++ b/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp
@@ -3661,17 +3661,17 @@ bool isDPALU_DPP(const MCInstrDesc &OpDesc, const MCInstrInfo &MII,
 }
 
 unsigned getLdsDwGranularity(const MCSubtargetInfo &ST) {
-  if (ST.getFeatureBits().test(FeatureAddressableLocalMemorySize32768))
+  if (ST.getFeatureBits().test(FeatureLDSAllocGranularity256))
     return 64;
-  if (ST.getFeatureBits().test(FeatureAddressableLocalMemorySize65536))
+  if (ST.getFeatureBits().test(FeatureLDSAllocGranularity512))
     return 128;
-  if (ST.getFeatureBits().test(FeatureAddressableLocalMemorySize196608))
+  if (ST.getFeatureBits().test(FeatureLDSAllocGranularity1024))
     return 256;
-  if (ST.getFeatureBits().test(FeatureAddressableLocalMemorySize163840))
+  if (ST.getFeatureBits().test(FeatureLDSAllocGranularity1280))
     return 320;
-  if (ST.getFeatureBits().test(FeatureAddressableLocalMemorySize327680))
+  if (ST.getFeatureBits().test(FeatureLDSAllocGranularity2048))
     return 512;
-  return 64; // In sync with getAddressableLocalMemorySize
+  return 64;
 }
 
 bool isPackedSingleSGPRFP32Inst(unsigned Opc) {
diff --git a/llvm/lib/TargetParser/AMDGPUTargetParser.cpp b/llvm/lib/TargetParser/AMDGPUTargetParser.cpp
index 40775d7c6e132..50e6f882da07f 100644
--- a/llvm/lib/TargetParser/AMDGPUTargetParser.cpp
+++ b/llvm/lib/TargetParser/AMDGPUTargetParser.cpp
@@ -530,7 +530,12 @@ static const AMDGPUFeatureBitset FrontendOnlyFeatures = {
     FEAT_AGPR_ALLOC,
     FEAT_1536_PHYSICAL_VGPRS,
     FEAT_HALF_ADDRESSABLE_PHYSICAL_LOCAL_MEMORY,
-    FEAT_1024_ADDRESSABLE_VGPRS};
+    FEAT_1024_ADDRESSABLE_VGPRS,
+    FEAT_LDS_ALLOC_GRANULARITY_256,
+    FEAT_LDS_ALLOC_GRANULARITY_512,
+    FEAT_LDS_ALLOC_GRANULARITY_1024,
+    FEAT_LDS_ALLOC_GRANULARITY_1280,
+    FEAT_LDS_ALLOC_GRANULARITY_2048};
 
 // Add a GPU's features (minus the frontend-only ones) to \p Features. With \p
 // Overwrite false, existing entries are kept so user -mattr overrides win.
diff --git a/llvm/test/TableGen/AMDGPUTargetDefErrors.td b/llvm/test/TableGen/AMDGPUTargetDefErrors.td
index ce540b5bd5a32..ef4ff95329d3b 100644
--- a/llvm/test/TableGen/AMDGPUTargetDefErrors.td
+++ b/llvm/test/TableGen/AMDGPUTargetDefErrors.td
@@ -19,6 +19,10 @@
 // RUN:   | FileCheck %t/bad-stepping.td -DFILE=%t/bad-stepping.td --implicit-check-not="error:"
 // RUN: not llvm-tblgen -gen-amdgpu-target-def -I %p/../../include %t/generic-feature-superset.td 2>&1 \
 // RUN:   | FileCheck %t/generic-feature-superset.td -DFILE=%t/generic-feature-superset.td --implicit-check-not="error:"
+// RUN: llvm-tblgen -gen-amdgpu-target-def -I %p/../../include %t/generic-lds-granularity-valid.td 2>&1 \
+// RUN:   | FileCheck %t/generic-lds-granularity-valid.td --check-prefix=VALID
+// RUN: not llvm-tblgen -gen-amdgpu-target-def -I %p/../../include %t/generic-lds-granularity-invalid.td 2>&1 \
+// RUN:   | FileCheck %t/generic-lds-granularity-invalid.td -DFILE=%t/generic-lds-granularity-invalid.td --implicit-check-not="error:"
 
 // Verify the validation performed by the -gen-amdgpu-target-def backend.
 
@@ -185,3 +189,69 @@ def : ProcessorModel<"gfx9-generic", NoSchedModel, [FeatureFoo]>,
       AMDGPUGPUInfo<[9, 0, 0]> {
   let CoveredGPUs = [GFX900];
 }
+
+//--- generic-lds-granularity-valid.td
+include "llvm/Target/Target.td"
+def MyTarget : Target;
+class AMDGPUArchFeature<string spelling> { string Spelling = spelling; }
+class AMDGPUGPUInfo<list<int> isa = []> {
+  list<AMDGPUArchFeature> ArchFeatures = [];
+  list<int> IsaVersion = isa;
+  list<Processor> CoveredGPUs = [];
+  bit IsPseudoTarget = false;
+}
+
+class SubtargetFeatureLDSAllocGranularity<int Granularity> : SubtargetFeature<
+  "granule-"#Granularity, "LDSAllocationGranularity",
+  !cast<string>(Granularity), "Granularity"> {
+  int NumericValue = Granularity;
+}
+def FeatureGranuleSmall : SubtargetFeatureLDSAllocGranularity<256>;
+def FeatureGranuleBig : SubtargetFeatureLDSAllocGranularity<512>;
+
+def AMDGPUFrontendVisibleFeatures {
+  list<SubtargetFeature> Features = [FeatureGranuleSmall, FeatureGranuleBig];
+}
+
+def GFX900 : ProcessorModel<"gfx900", NoSchedModel, [FeatureGranuleSmall]>,
+             AMDGPUGPUInfo<[9, 0, 0]>;
+
+// A generic carries the worst-case numeric field, so it keeps the larger
+// granularity while covering a GPU with a smaller one. That is not an error.
+// VALID: GK_GFX9_GENERIC
+def : ProcessorModel<"gfx9-generic", NoSchedModel, [FeatureGranuleBig]>,
+      AMDGPUGPUInfo<[9, 0, 0]> {
+  let CoveredGPUs = [GFX900];
+}
+
+//--- generic-lds-granularity-invalid.td
+include "llvm/Target/Target.td"
+def MyTarget : Target;
+class AMDGPUArchFeature<string spelling> { string Spelling = spelling; }
+class AMDGPUGPUInfo<list<int> isa = []> {
+  list<AMDGPUArchFeature> ArchFeatures = [];
+  list<int> IsaVersion = isa;
+  list<Processor> CoveredGPUs = [];
+  bit IsPseudoTarget = false;
+}
+
+class SubtargetFeatureLDSAllocGranularity<int Granularity> : SubtargetFeature<
+  "granule-"#Granularity, "LDSAllocationGranularity",
+  !cast<string>(Granularity), "Granularity"> {
+  int NumericValue = Granularity;
+}
+def FeatureGranuleSmall : SubtargetFeatureLDSAllocGranularity<256>;
+def FeatureGranuleBig : SubtargetFeatureLDSAllocGranularity<512>;
+
+def AMDGPUFrontendVisibleFeatures {
+  list<SubtargetFeature> Features = [FeatureGranuleSmall, FeatureGranuleBig];
+}
+
+def GFX900 : ProcessorModel<"gfx900", NoSchedModel, [FeatureGranuleBig]>,
+             AMDGPUGPUInfo<[9, 0, 0]>;
+
+// CHECK: [[FILE]]:[[#@LINE+1]]:1: error: generic target 'gfx9-generic' exposes feature 'granule-256' below the 'LDSAllocationGranularity' of covered GPU 'gfx900'
+def : ProcessorModel<"gfx9-generic", NoSchedModel, [FeatureGranuleSmall]>,
+      AMDGPUGPUInfo<[9, 0, 0]> {
+  let CoveredGPUs = [GFX900];
+}
diff --git a/llvm/unittests/TargetParser/TargetParserTest.cpp b/llvm/unittests/TargetParser/TargetParserTest.cpp
index 55e99754a44a9..17ae0b78947b9 100644
--- a/llvm/unittests/TargetParser/TargetParserTest.cpp
+++ b/llvm/unittests/TargetParser/TargetParserTest.cpp
@@ -2824,6 +2824,14 @@ TEST(TargetParserTest, testAMDGPUfillAMDGPUFeatureMap) {
 
   // A capability feature is queried through the bitset only.
   EXPECT_FALSE(HasFeature("gfx1030", "half-addressable-physical-local-memory"));
+
+  // Numeric hardware properties stay out of the target-feature string. Merging
+  // multiple values there would silently select the largest one.
+  EXPECT_FALSE(HasFeature("gfx600", "lds-alloc-granularity-256"));
+  EXPECT_FALSE(HasFeature("gfx900", "lds-alloc-granularity-512"));
+  EXPECT_FALSE(HasFeature("gfx950", "lds-alloc-granularity-1280"));
+  EXPECT_FALSE(HasFeature("gfx1310", "lds-alloc-granularity-1024"));
+  EXPECT_FALSE(HasFeature("gfx1250", "lds-alloc-granularity-2048"));
 }
 
 TEST(TargetParserTest, testAMDGPUgetFeatureBitset) {
@@ -2874,6 +2882,44 @@ TEST(TargetParserTest, testAMDGPUHalfAddressableLDSFeature) {
   EXPECT_FALSE(Has(AMDGPU::GK_GFX1310));
 }
 
+TEST(TargetParserTest, testAMDGPULDSAllocGranularityFeatures) {
+  auto Has = [](AMDGPU::GPUKind AK, AMDGPU::AMDGPUFeature Feature) {
+    return AMDGPU::getFeatureBitset(AK).test(Feature);
+  };
+  auto Count = [&Has](AMDGPU::GPUKind AK) {
+    return Has(AK, AMDGPU::FEAT_LDS_ALLOC_GRANULARITY_256) +
+           Has(AK, AMDGPU::FEAT_LDS_ALLOC_GRANULARITY_512) +
+           Has(AK, AMDGPU::FEAT_LDS_ALLOC_GRANULARITY_1024) +
+           Has(AK, AMDGPU::FEAT_LDS_ALLOC_GRANULARITY_1280) +
+           Has(AK, AMDGPU::FEAT_LDS_ALLOC_GRANULARITY_2048);
+  };
+
+  // Exactly one allocation granularity is set per GPU.
+  EXPECT_EQ(Count(AMDGPU::GK_GFX600), 1);
+  EXPECT_EQ(Count(AMDGPU::GK_GFX900), 1);
+  EXPECT_EQ(Count(AMDGPU::GK_GFX950), 1);
+  EXPECT_EQ(Count(AMDGPU::GK_GFX1310), 1);
+  EXPECT_EQ(Count(AMDGPU::GK_GFX1250), 1);
+  EXPECT_EQ(Count(AMDGPU::GK_GFX9_4_GENERIC), 1);
+
+  // The legacy pseudo-targets do not represent hardware.
+  EXPECT_EQ(Count(AMDGPU::GK_GENERIC), 0);
+  EXPECT_EQ(Count(AMDGPU::GK_GENERIC_HSA), 0);
+
+  EXPECT_TRUE(Has(AMDGPU::GK_GFX600, AMDGPU::FEAT_LDS_ALLOC_GRANULARITY_256));
+  EXPECT_TRUE(Has(AMDGPU::GK_GFX900, AMDGPU::FEAT_LDS_ALLOC_GRANULARITY_512));
+  EXPECT_TRUE(Has(AMDGPU::GK_GFX950, AMDGPU::FEAT_LDS_ALLOC_GRANULARITY_1280));
+  EXPECT_TRUE(Has(AMDGPU::GK_GFX1310, AMDGPU::FEAT_LDS_ALLOC_GRANULARITY_1024));
+  EXPECT_TRUE(Has(AMDGPU::GK_GFX1250, AMDGPU::FEAT_LDS_ALLOC_GRANULARITY_2048));
+
+  // A generic target uses the largest allocation granularity of the GPUs it
+  // covers. gfx9-4-generic therefore uses gfx950's 1280-byte granule.
+  EXPECT_TRUE(
+      Has(AMDGPU::GK_GFX9_4_GENERIC, AMDGPU::FEAT_LDS_ALLOC_GRANULARITY_1280));
+  EXPECT_FALSE(
+      Has(AMDGPU::GK_GFX9_4_GENERIC, AMDGPU::FEAT_LDS_ALLOC_GRANULARITY_512));
+}
+
 TEST(TargetParserTest, testAMDGPUfillValidArchListAMDGCN) {
   SmallVector<StringRef, 0> All;
   AMDGPU::fillValidArchListAMDGCN(All, Triple::NoSubArch);
diff --git a/llvm/utils/TableGen/Basic/AMDGPUTargetDefEmitter.cpp b/llvm/utils/TableGen/Basic/AMDGPUTargetDefEmitter.cpp
index 96f82fb42c27a..782882592f9a3 100644
--- a/llvm/utils/TableGen/Basic/AMDGPUTargetDefEmitter.cpp
+++ b/llvm/utils/TableGen/Basic/AMDGPUTargetDefEmitter.cpp
@@ -466,14 +466,44 @@ collectVisibleFeatures(const Record *GPU,
   return Visible;
 }
 
+// Return the LDS allocation granularity in \p GPU's feature closure. Two
+// features setting different granularities is an error: SubtargetFeature
+// silently takes the larger.
+static int64_t getLDSAllocGranularity(const Record *GPU) {
+  SetVector<const Record *> Closure;
+  collectFeatureClosure(GPU, Closure);
+
+  const Record *Found = nullptr;
+  int64_t Value = 256;
+  for (const Record *F : Closure) {
+    if (F->getValueAsString("FieldName") != "LDSAllocationGranularity")
+      continue;
+
+    int64_t V = F->getValueAsInt("NumericValue");
+    if (Found && V != Value) {
+      PrintFatalError(GPU->getLoc(),
+                      "GPU '" + GPU->getValueAsString("Name") +
+                          "' gets conflicting 'LDSAllocationGranularity' "
+                          "values from '" +
+                          Found->getValueAsString("Name") + "' and '" +
+                          F->getValueAsString("Name") + "'");
+    }
+    Found = F;
+    Value = V;
+  }
+  return Value;
+}
+
 // Make sure a "gfxN-generic" processor doesn't expose a frontend-visible
 // feature missing from any covered processor.
 //
+// LDS allocation granularity is an exception to exact matching. A generic
+// target conservatively uses the largest granularity of the GPUs it covers.
+//
 // FIXME: The check should cover all SubtargetFeatures, not just the
 // frontend-visible ones. It is limited to those because a generic legitimately
-// carries some features a covered GPU lacks (bug/hazard workarounds and
-// worst-case-valued features); those cases need to be marked to opt out of the
-// check, plus min-value handling for numeric features.
+// carries some boolean features a covered GPU lacks (bug and hazard
+// workarounds); those cases need to be marked to opt out of the check.
 static void
 validateGenericFeatures(const Record *GPU,
                         const DenseMap<const Record *, unsigned> &FeatureIdx) {
@@ -488,14 +518,29 @@ validateGenericFeatures(const Record *GPU,
     SetVector<const Record *> MemberFeatures =
         collectVisibleFeatures(Member, FeatureIdx);
     for (const Record *F : GenericFeatures) {
-      if (!MemberFeatures.contains(F)) {
+      if (MemberFeatures.contains(F))
+        continue;
+
+      StringRef FieldName = F->getValueAsString("FieldName");
+      if (FieldName == "LDSAllocationGranularity") {
+        int64_t GenericValue = getLDSAllocGranularity(GPU);
+        int64_t MemberValue = getLDSAllocGranularity(Member);
+        if (GenericValue >= MemberValue)
+          continue;
+
         PrintFatalError(GPU->getLoc(),
                         "generic target '" + GPU->getValueAsString("Name") +
                             "' exposes feature '" +
-                            F->getValueAsString("Name") +
-                            "' not supported by covered GPU '" +
+                            F->getValueAsString("Name") + "' below the '" +
+                            FieldName + "' of covered GPU '" +
                             Member->getValueAsString("Name") + "'");
       }
+
+      PrintFatalError(GPU->getLoc(),
+                      "generic target '" + GPU->getValueAsString("Name") +
+                          "' exposes feature '" + F->getValueAsString("Name") +
+                          "' not supported by covered GPU '" +
+                          Member->getValueAsString("Name") + "'");
     }
   }
 }

>From 856f6a57b81471dcc8143cf01c33c24055728711 Mon Sep 17 00:00:00 2001
From: Chinmay Deshpande <chdeshpa at amd.com>
Date: Thu, 3 Sep 2026 01:36:06 -0400
Subject: [PATCH 2/2] [AMDGPU] Add getLDSAllocGranule to TargetParser

Expose the LDS allocation granule from GPUKind and subarch without an
MCSubtargetInfo. Use the dedicated granularity features and consolidate
backend users on the byte-valued query.

Change-Id: Ic0c9345e7657ec3c6978a646628598cb7608b390
---
 .../llvm/TargetParser/AMDGPUTargetParser.h    |  4 +++
 llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp   |  7 +++--
 llvm/lib/Target/AMDGPU/GCNSubtarget.cpp       |  4 +--
 .../Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp    | 14 ----------
 llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h |  5 ----
 llvm/lib/TargetParser/AMDGPUTargetParser.cpp  | 28 +++++++++++++++++++
 .../TargetParser/TargetParserTest.cpp         | 16 +++++++++++
 7 files changed, 54 insertions(+), 24 deletions(-)

diff --git a/llvm/include/llvm/TargetParser/AMDGPUTargetParser.h b/llvm/include/llvm/TargetParser/AMDGPUTargetParser.h
index c9dcd10421481..edb3aca892e32 100644
--- a/llvm/include/llvm/TargetParser/AMDGPUTargetParser.h
+++ b/llvm/include/llvm/TargetParser/AMDGPUTargetParser.h
@@ -235,6 +235,10 @@ getMaxHWAddressableLocalMemorySize(Triple::SubArchType SubArch);
 LLVM_ABI unsigned getLDSBankCount(GPUKind AK);
 LLVM_ABI unsigned getLDSBankCount(Triple::SubArchType SubArch);
 
+/// \returns LDS allocation granularity in bytes.
+LLVM_ABI unsigned getLDSAllocGranule(GPUKind AK);
+LLVM_ABI unsigned getLDSAllocGranule(Triple::SubArchType SubArch);
+
 /// \returns Number of SIMDs a work-group's waves run on. All four SIMDs of the
 /// functional block in full-SIMD mode, half of them otherwise.
 constexpr unsigned getNumWorkGroupSIMDs(bool FullSIMDMode) {
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp b/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp
index 11c482c83f1e1..b68ab01173721 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp
@@ -1440,7 +1440,8 @@ void AMDGPUAsmPrinter::getSIProgramInfo(SIProgramInfo &ProgInfo,
 
   ProgInfo.LDSSize = MFI->getLDSSize();
 
-  unsigned LDSGranularityBytes = getLdsDwGranularity(STM) * 4;
+  unsigned LDSGranularityBytes =
+      AMDGPU::getLDSAllocGranule(STM.getTargetID().getGPUKind());
   ProgInfo.LDSBlocks =
       alignTo(ProgInfo.LDSSize, LDSGranularityBytes) / LDSGranularityBytes;
 
@@ -1679,8 +1680,8 @@ static void EmitPALMetadataCommon(AMDGPUPALMetadata *MD,
 
   MD->updateHwStageMaximum(
       CC, ".lds_size",
-      (unsigned)(CurrentProgramInfo.LdsSize * getLdsDwGranularity(ST) *
-                 sizeof(uint32_t)));
+      (unsigned)(CurrentProgramInfo.LdsSize *
+                 AMDGPU::getLDSAllocGranule(ST.getTargetID().getGPUKind())));
 }
 
 // This is the equivalent of EmitProgramInfoSI above, but for when the OS type
diff --git a/llvm/lib/Target/AMDGPU/GCNSubtarget.cpp b/llvm/lib/Target/AMDGPU/GCNSubtarget.cpp
index 9443420c3d424..e97f2114098b8 100644
--- a/llvm/lib/Target/AMDGPU/GCNSubtarget.cpp
+++ b/llvm/lib/Target/AMDGPU/GCNSubtarget.cpp
@@ -184,9 +184,9 @@ GCNSubtarget &GCNSubtarget::initializeSubtargetDependencies(const Triple &TT,
   LocalMemorySize = AMDGPU::IsaInfo::getLocalMemorySize(*this);
   AddressableLocalMemorySize =
       AMDGPU::IsaInfo::getAddressableLocalMemorySize(*this);
-  // LDS Allocation Granularity calculated in bytes from dwords
+  // LDS allocation granularity is in bytes.
   LDSAllocationGranularity =
-      AMDGPU::getLdsDwGranularity(*this) * sizeof(uint32_t);
+      AMDGPU::getLDSAllocGranule(getTargetID().getGPUKind());
 
   HasFminFmaxLegacy = getGeneration() < AMDGPUSubtarget::VOLCANIC_ISLANDS;
   HasSMulHi = getGeneration() >= AMDGPUSubtarget::GFX9;
diff --git a/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp b/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp
index 912236e7860fa..0c8cacc0e5985 100644
--- a/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp
+++ b/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp
@@ -3660,20 +3660,6 @@ bool isDPALU_DPP(const MCInstrDesc &OpDesc, const MCInstrInfo &MII,
   return hasAny64BitVGPROperands(OpDesc, MII, ST);
 }
 
-unsigned getLdsDwGranularity(const MCSubtargetInfo &ST) {
-  if (ST.getFeatureBits().test(FeatureLDSAllocGranularity256))
-    return 64;
-  if (ST.getFeatureBits().test(FeatureLDSAllocGranularity512))
-    return 128;
-  if (ST.getFeatureBits().test(FeatureLDSAllocGranularity1024))
-    return 256;
-  if (ST.getFeatureBits().test(FeatureLDSAllocGranularity1280))
-    return 320;
-  if (ST.getFeatureBits().test(FeatureLDSAllocGranularity2048))
-    return 512;
-  return 64;
-}
-
 bool isPackedSingleSGPRFP32Inst(unsigned Opc) {
   switch (Opc) {
   case AMDGPU::V_PK_ADD_F32_gfx1250:
diff --git a/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h b/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h
index 6f875db59917e..d8b882218e72a 100644
--- a/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h
+++ b/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h
@@ -1780,11 +1780,6 @@ getVGPRLoweringOperandTables(const MCInstrDesc &Desc);
 /// \returns true if a memory instruction supports scale_offset modifier.
 bool supportsScaleOffset(const MCInstrInfo &MII, unsigned Opcode);
 
-/// \returns lds block size in terms of dwords. \p
-/// This is used to calculate the lds size encoded for PAL metadata 3.0+ which
-/// must be defined in terms of bytes.
-unsigned getLdsDwGranularity(const MCSubtargetInfo &ST);
-
 class ClusterDimsAttr {
 public:
   enum class Kind { Unknown, NoCluster, VariableDims, FixedDims };
diff --git a/llvm/lib/TargetParser/AMDGPUTargetParser.cpp b/llvm/lib/TargetParser/AMDGPUTargetParser.cpp
index 50e6f882da07f..83febf216d8e2 100644
--- a/llvm/lib/TargetParser/AMDGPUTargetParser.cpp
+++ b/llvm/lib/TargetParser/AMDGPUTargetParser.cpp
@@ -494,6 +494,34 @@ unsigned AMDGPU::getLDSBankCount(Triple::SubArchType SubArch) {
   return getLDSBankCount(getGPUKindFromSubArch(SubArch));
 }
 
+unsigned AMDGPU::getLDSAllocGranule(GPUKind AK) {
+  const AMDGPUFeatureBitset &Features = getFeatureBitset(AK);
+  if (Features.none())
+    return 256;
+  assert((Features.test(FEAT_LDS_ALLOC_GRANULARITY_256) ||
+          Features.test(FEAT_LDS_ALLOC_GRANULARITY_512) ||
+          Features.test(FEAT_LDS_ALLOC_GRANULARITY_1024) ||
+          Features.test(FEAT_LDS_ALLOC_GRANULARITY_1280) ||
+          Features.test(FEAT_LDS_ALLOC_GRANULARITY_2048)) &&
+         "missing LDS allocation granularity feature");
+  if (Features.test(FEAT_LDS_ALLOC_GRANULARITY_256))
+    return 256;
+  if (Features.test(FEAT_LDS_ALLOC_GRANULARITY_512))
+    return 512;
+  if (Features.test(FEAT_LDS_ALLOC_GRANULARITY_1024))
+    return 1024;
+  if (Features.test(FEAT_LDS_ALLOC_GRANULARITY_1280))
+    return 1280;
+  if (Features.test(FEAT_LDS_ALLOC_GRANULARITY_2048))
+    return 2048;
+
+  return 256;
+}
+
+unsigned AMDGPU::getLDSAllocGranule(Triple::SubArchType SubArch) {
+  return getLDSAllocGranule(getGPUKindFromSubArch(SubArch));
+}
+
 unsigned AMDGPU::getMaxWavesPerEU(GPUKind AK) {
   const GPUInfo *Info = getAMDGPUInfo(AK);
   return Info ? Info->MaxWavesPerEU : 10;
diff --git a/llvm/unittests/TargetParser/TargetParserTest.cpp b/llvm/unittests/TargetParser/TargetParserTest.cpp
index 17ae0b78947b9..40c726c6619e3 100644
--- a/llvm/unittests/TargetParser/TargetParserTest.cpp
+++ b/llvm/unittests/TargetParser/TargetParserTest.cpp
@@ -3264,6 +3264,22 @@ TEST(TargetParserTest, testAMDGPUgetMaxHWAddressableLocalMemorySize) {
             327680u);
 }
 
+TEST(TargetParserTest, testAMDGPUgetLDSAllocGranule) {
+  EXPECT_EQ(AMDGPU::getLDSAllocGranule(AMDGPU::GK_GFX600), 256u);
+  EXPECT_EQ(AMDGPU::getLDSAllocGranule(AMDGPU::GK_GFX900), 512u);
+  EXPECT_EQ(AMDGPU::getLDSAllocGranule(AMDGPU::GK_GFX950), 1280u);
+  EXPECT_EQ(AMDGPU::getLDSAllocGranule(AMDGPU::GK_GFX1310), 1024u);
+  EXPECT_EQ(AMDGPU::getLDSAllocGranule(AMDGPU::GK_GFX1250), 2048u);
+  EXPECT_EQ(AMDGPU::getLDSAllocGranule(AMDGPU::GK_GFX9_4_GENERIC), 1280u);
+  EXPECT_EQ(AMDGPU::getLDSAllocGranule(AMDGPU::GK_NONE), 256u);
+
+  EXPECT_EQ(AMDGPU::getLDSAllocGranule(Triple::AMDGPUSubArch600), 256u);
+  EXPECT_EQ(AMDGPU::getLDSAllocGranule(Triple::AMDGPUSubArch900), 512u);
+  EXPECT_EQ(AMDGPU::getLDSAllocGranule(Triple::AMDGPUSubArch950), 1280u);
+  EXPECT_EQ(AMDGPU::getLDSAllocGranule(Triple::AMDGPUSubArch1310), 1024u);
+  EXPECT_EQ(AMDGPU::getLDSAllocGranule(Triple::AMDGPUSubArch1250), 2048u);
+}
+
 TEST(TargetParserTest, testAMDGPUgetNumWorkGroupSIMDs) {
   EXPECT_EQ(AMDGPU::getNumWorkGroupSIMDs(true), 4u);
   EXPECT_EQ(AMDGPU::getNumWorkGroupSIMDs(false), 2u);



More information about the llvm-branch-commits mailing list