Skip to content

Commit 13eab2b

Browse files
rraminenpraguptaclaudejeffdaily
authored
[release/2.12] [ROCm] Add initial support for gfx1250 (pytorch#188597) (#3421)
## Summary Validation theRock Run: https://github.com/ROCm/TheRock/actions/runs/29045360944 Cherry-pick of upstream [pytorch#188597](pytorch#188597) onto `release/2.12` to add initial ROCm support for **gfx1250 (CDNA5)**. Co-authored-by: @glen-amd ### What this PR enables - Gates gfx1250-specific behavior on ROCm 7.14+ (the support floor), applied consistently across CUDABlas.cpp, ScaledBlas.cpp, CUDAHooks.cpp, and the test helpers. - Adds gfx1250 to the hipBLASLt preferred/supported arch lists and the hipSparseLt support check (ROCm 7.14+). - Extends the scaled GEMM / MX-format paths (block-wise Float8_e8m0fnu, mxfp8, mxfp4) to gfx1250. - Sets the gfx1250 shared-memory limit to 320 KB (vs 160 KB on gfx950), matching on the suffix-stripped arch name. - Adds CDNA2/CDNA3/CDNA5 "or later" arch helpers and updates FP8 / MX GEMM test gating in common_cuda.py. - Builds Composable Kernel (CK) GEMM as a separate ck_gemm library with gfx1250 filtered out of HIP_ARCHITECTURES, so a multi-arch build that includes gfx1250 keeps CK GEMM for the other archs instead of failing to compile for gfx1250 (composable_kernel has no gfx1250 support yet). The filter is removed once CK supports gfx1250. - Extends the gfx942 nontemporal vectorized-load path in MemoryAccess.cuh to gfx1250. - Refactors duplicated arch-check logic in CUDABlas.cpp, ScaledBlas.cpp, and cuSPARSELtOps.cpp per review feedback. - Writes the CublasHandlePool workspace archs in full (gfx942/gfx950/gfx1250). Enabled via the main merge: - Flash attention and memory-efficient attention on gfx1250 via AOTriton 0.12.1b (from pytorch#188242), which this branch merges in. What is not enabled yet: - CK SDPA on gfx1250: composable_kernel has no gfx1250 support; the CK SDPA target auto-filters to gfx942/gfx950. - CK GEMM on gfx1250: filtered out (see above) until composable_kernel supports it. - FP8 grouped GEMM on gfx1250: MSLK builds only gfx942/gfx950. - int4 mm on gfx1250: the tinygemm MFMA kernel needs a WMMA port; the ops return a clear "not supported yet" error and the int4 unit tests skip gfx1250. CI note: - gfx1250 is not added to the ROCm 7.2 (rocm-n) docker image, whose HIP compiler cannot target gfx1250. gfx1250 CI belongs on the nightly ROCm image and is added in a follow-up. Co-authored-by: @glen-amd ## References - Upstream PR: pytorch#188597 - Related AOTriton bump: pytorch#188242 --------- Co-authored-by: Prachi Gupta <prachi.gupta@amd.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Jeff Daily <jeff.daily@amd.com>
1 parent e4d43db commit 13eab2b

15 files changed

Lines changed: 216 additions & 76 deletions

File tree

aten/src/ATen/CMakeLists.txt

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -682,11 +682,33 @@ if(USE_ROCM)
682682
${native_quantized_hip_hip}
683683
${native_transformers_hip_hip} ${native_transformers_src_hip_hip}
684684
)
685+
file(GLOB native_hip_bgemm CONFIGURE_DEPENDS "native/hip/bgemm_kernels/*.hip")
686+
file(GLOB native_hip_ck CONFIGURE_DEPENDS "native/hip/ck*.hip")
685687
if(NOT USE_ROCM_CK_GEMM)
686-
file(GLOB native_hip_bgemm "native/hip/bgemm_kernels/*.hip")
687-
file(GLOB native_hip_ck "native/hip/ck*.hip")
688688
exclude(ATen_HIP_SRCS "${ATen_HIP_SRCS}"
689689
${native_hip_bgemm} ${native_hip_ck})
690+
else()
691+
# composable_kernel has no gfx1250 support yet, so its CK GEMM kernels fail to
692+
# compile for that arch. Build CK GEMM as a separate library with gfx1250
693+
# filtered out of HIP_ARCHITECTURES so every other requested arch still gets
694+
# CK GEMM. Remove this filtering once the CK submodule supports gfx1250.
695+
exclude(ATen_HIP_SRCS "${ATen_HIP_SRCS}"
696+
${native_hip_bgemm} ${native_hip_ck})
697+
set(_ck_gemm_hip_arches ${PYTORCH_ROCM_ARCH})
698+
list(REMOVE_ITEM _ck_gemm_hip_arches "gfx1250")
699+
set_source_files_properties(${native_hip_bgemm} ${native_hip_ck} PROPERTIES LANGUAGE HIP)
700+
add_library(ck_gemm STATIC ${native_hip_bgemm} ${native_hip_ck})
701+
set_target_properties(ck_gemm PROPERTIES
702+
POSITION_INDEPENDENT_CODE ON
703+
HIP_ARCHITECTURES "${_ck_gemm_hip_arches}")
704+
target_compile_options(ck_gemm PRIVATE ${HIP_CXX_FLAGS})
705+
target_include_directories(ck_gemm PRIVATE
706+
${CMAKE_CURRENT_SOURCE_DIR}/hip
707+
${CMAKE_CURRENT_SOURCE_DIR}/../../../third_party/composable_kernel/include
708+
${CMAKE_CURRENT_SOURCE_DIR}/../../../third_party/composable_kernel/library/include
709+
${CMAKE_CURRENT_BINARY_DIR}/composable_kernel)
710+
# Ensure torch_cpu (and its codegen) is built before ck_gemm to avoid race conditions
711+
add_dependencies(ck_gemm torch_cpu)
690712
endif()
691713

692714
# TODO: Codegen separate files for HIP and use those (s/cuda_generated_sources/hip_generated_sources)

aten/src/ATen/cuda/CUDABlas.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2012,7 +2012,11 @@ void scaled_gemm(
20122012
}
20132013
else if (mat1_scale_dtype == kFloat8_e8m0fnu && mat2_scale_dtype == kFloat8_e8m0fnu) {
20142014
#if ROCM_VERSION >= 70000
2015-
if (at::detail::getCUDAHooks().isGPUArch({"gfx950"})) {
2015+
std::vector<std::string> mx_archs{"gfx950"};
2016+
#if ROCM_VERSION >= 71400
2017+
mx_archs.push_back("gfx1250");
2018+
#endif
2019+
if (at::detail::getCUDAHooks().isGPUArch(mx_archs)) {
20162020
// TODO: add constraints based on hipblaslt internals
20172021
TORCH_CHECK((m % 16 == 0) && (n % 16 == 0) && (k % 128 == 0),
20182022
"M, N must be multiples of 16 and K should be multiple of 128 for MX format. "

aten/src/ATen/cuda/CublasHandlePool.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -165,9 +165,9 @@ size_t parseChosenWorkspaceSize() {
165165
// for extra convenience
166166
val = c10::utils::get_env("ROCBLAS_WORKSPACE_CONFIG");
167167
}
168-
/* 32MiB default, 128MiB for gfx94x/gfx95x */
169-
const bool gfx94_95 = at::detail::getCUDAHooks().isGPUArch({"gfx94", "gfx95"});
170-
const size_t default_size = gfx94_95 ? 1024 * 128 * 1024 : 1024 * 32 * 1024;
168+
/* 32MiB default, 128MiB for gfx942/gfx950/gfx1250 */
169+
const bool gfx942_950_1250 = at::detail::getCUDAHooks().isGPUArch({"gfx942", "gfx950", "gfx1250"});
170+
const size_t default_size = gfx942_950_1250 ? 1024 * 128 * 1024 : 1024 * 32 * 1024;
171171
#else
172172
/* :4096:2:16:8 default, 32MiB for Hopper and Blackwell */
173173
cudaDeviceProp* properties = at::cuda::getCurrentDeviceProperties();

aten/src/ATen/cuda/detail/CUDAHooks.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -557,7 +557,10 @@ const std::vector<std::string>& CUDAHooks::getHipblasltPreferredArchs() const {
557557
"gfx950",
558558
#endif
559559
#if ROCM_VERSION >= 71300
560-
"gfx1100", "gfx1101", "gfx1151"
560+
"gfx1100", "gfx1101", "gfx1151",
561+
#endif
562+
#if ROCM_VERSION >= 71400
563+
"gfx1250",
561564
#endif
562565
};
563566
return archs;
@@ -572,7 +575,7 @@ const std::vector<std::string>& CUDAHooks::getHipblasltSupportedArchs() const {
572575
#if ROCM_VERSION >= 70000
573576
"gfx950", "gfx1150", "gfx1151",
574577
#endif
575-
#if ROCM_VERSION >= 70200
578+
#if ROCM_VERSION >= 71400
576579
"gfx1250"
577580
#endif
578581
};

aten/src/ATen/native/cuda/MemoryAccess.cuh

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -187,28 +187,35 @@ template <int vec_size, typename scalar_t>
187187
__device__ aligned_vector<scalar_t, vec_size> load_vector(const scalar_t *base_ptr, uint32_t offset) {
188188
using vec_t = aligned_vector<scalar_t, vec_size>;
189189
auto *from = reinterpret_cast<const vec_t *>(base_ptr);
190-
#if defined(USE_ROCM) && defined(__gfx942__)
191-
using longx2 = __attribute__((__vector_size__(4*sizeof(int)))) int;
192-
if constexpr (sizeof(vec_t) == sizeof(int)) {
193-
union {
194-
vec_t v;
195-
int i;
196-
} tmpt = { .i = __builtin_nontemporal_load(reinterpret_cast<const int *>(&(from[offset]))) };
197-
return tmpt.v;
198-
}
199-
else if constexpr (sizeof(vec_t) == sizeof(long)) {
200-
union {
201-
vec_t v;
202-
long i;
203-
} tmpt = { .i = __builtin_nontemporal_load(reinterpret_cast<const long *>(&(from[offset]))) };
204-
return tmpt.v;
205-
}
206-
else if constexpr (sizeof(vec_t) == sizeof(longx2)) {
207-
union {
208-
vec_t v;
209-
longx2 i;
210-
} tmpt = { .i = __builtin_nontemporal_load(reinterpret_cast<const longx2 *>(&(from[offset]))) };
211-
return tmpt.v;
190+
#if defined(USE_ROCM)
191+
// NOTE: This nontemporal vectorized load is tuned for gfx942 (CDNA3, Wave64).
192+
// Do NOT extend to gfx1250 (GFX12.5, Wave32) without first validating
193+
// intrinsic codegen and re-benchmarking — the register layout and wave
194+
// width differ. gfx1250 falls through to the generic path below, which
195+
// is correctness-safe.
196+
if(__builtin_amdgcn_processor_is("gfx942")) {
197+
using longx2 = __attribute__((__vector_size__(4*sizeof(int)))) int;
198+
if constexpr (sizeof(vec_t) == sizeof(int)) {
199+
union {
200+
vec_t v;
201+
int i;
202+
} tmpt = { .i = __builtin_nontemporal_load(reinterpret_cast<const int *>(&(from[offset]))) };
203+
return tmpt.v;
204+
}
205+
else if constexpr (sizeof(vec_t) == sizeof(long)) {
206+
union {
207+
vec_t v;
208+
long i;
209+
} tmpt = { .i = __builtin_nontemporal_load(reinterpret_cast<const long *>(&(from[offset]))) };
210+
return tmpt.v;
211+
}
212+
else if constexpr (sizeof(vec_t) == sizeof(longx2)) {
213+
union {
214+
vec_t v;
215+
longx2 i;
216+
} tmpt = { .i = __builtin_nontemporal_load(reinterpret_cast<const longx2 *>(&(from[offset]))) };
217+
return tmpt.v;
218+
}
212219
}
213220
#endif
214221
return from[offset];

aten/src/ATen/native/cuda/ScaledBlas.cpp

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <ATen/cuda/tunable/TunableGemm.h>
1818
#include <ATen/native/Resize.h>
1919
#include <c10/util/MaybeOwned.h>
20+
#include <c10/util/StringUtil.h>
2021
#include <ATen/native/GroupedMMUtils.h>
2122
#include <ATen/native/cuda/RowwiseScaledMM.h>
2223
#include <ATen/native/cuda/ScaledGroupMM.h>
@@ -78,7 +79,10 @@ bool _scaled_mm_allowed_device(bool sm90_only=false, bool sm100_only=false) {
7879
"gfx1200", "gfx1201",
7980
#endif
8081
#if ROCM_VERSION >= 60500
81-
"gfx950"
82+
"gfx950",
83+
#endif
84+
#if ROCM_VERSION >= 71400
85+
"gfx1250",
8286
#endif
8387
};
8488
return at::detail::getCUDAHooks().isGPUArch(archs);
@@ -97,6 +101,19 @@ bool _scaled_mm_allowed_device(bool sm90_only=false, bool sm100_only=false) {
97101
bool _scaled_mm_is_fnuz() {
98102
return at::detail::getCUDAHooks().isGPUArch({"gfx942"});
99103
}
104+
105+
#if ROCM_VERSION >= 70000
106+
static void check_blockwise_e8m0fnu_arch_supported() {
107+
std::vector<std::string> mx_archs{"gfx950"};
108+
#if ROCM_VERSION >= 71400
109+
mx_archs.push_back("gfx1250");
110+
#endif
111+
TORCH_CHECK_NOT_IMPLEMENTED(
112+
at::detail::getCUDAHooks().isGPUArch(mx_archs),
113+
"Block-wise scaling for Float8_e8m0fnu is only supported on ",
114+
c10::Join(",", mx_archs));
115+
}
116+
#endif
100117
#endif
101118

102119
/*
@@ -621,9 +638,8 @@ _scaled_mm_out_cuda(const Tensor& mat1, const Tensor& mat2,
621638
}
622639
else if (scaling_choice_a == ScalingType::BlockWise1x32 && scaling_choice_b == ScalingType::BlockWise1x32) {
623640
#ifdef USE_ROCM
624-
#if ROCM_VERSION >= 70000
625-
TORCH_CHECK_NOT_IMPLEMENTED(at::detail::getCUDAHooks().isGPUArch({"gfx950"}),
626-
"Block-wise scaling for Float8_e8m0fnu is only supported on gfx950");
641+
#if ROCM_VERSION >= 70000
642+
check_blockwise_e8m0fnu_arch_supported();
627643

628644
int packed_factor = 1;
629645
if (mat1.scalar_type() == ScalarType::Float4_e2m1fn_x2) {
@@ -1064,8 +1080,7 @@ _scaled_mxfp8_mxfp8(
10641080

10651081
#ifdef USE_ROCM
10661082
#if ROCM_VERSION >= 70000
1067-
TORCH_CHECK_NOT_IMPLEMENTED(at::detail::getCUDAHooks().isGPUArch({"gfx950"}),
1068-
"Block-wise scaling for Float8_e8m0fnu is only supported on gfx950");
1083+
check_blockwise_e8m0fnu_arch_supported();
10691084

10701085
TORCH_CHECK_VALUE(mat_a.size(0) % 32 == 0 && mat_a.size(1) % 32 == 0 &&
10711086
mat_b.size(0) % 32 == 0 && mat_b.size(1) % 32 == 0,
@@ -1150,8 +1165,7 @@ _scaled_mxfp4_mxfp4(
11501165
auto scaling_choice_b = ScalingType::BlockWise1x32;
11511166

11521167
#if ROCM_VERSION >= 70000
1153-
TORCH_CHECK_NOT_IMPLEMENTED(at::detail::getCUDAHooks().isGPUArch({"gfx950"}),
1154-
"Block-wise scaling for Float8_e8m0fnu is only supported on gfx950");
1168+
check_blockwise_e8m0fnu_arch_supported();
11551169

11561170
TORCH_CHECK_VALUE(mat_a.size(0) % 32 == 0 && mat_a.size(1) % 32 == 0 &&
11571171
mat_b.size(0) % 32 == 0 && mat_b.size(1) % 32 == 0,

aten/src/ATen/native/cuda/int4mm.cu

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,10 @@ static bool isCDNA2orLater(int index) {
146146
return at::detail::getCUDAHooks().isGPUArch({"gfx90a", "gfx942", "gfx950"}, index);
147147
}
148148

149+
static bool isCDNA5orLater(int index) {
150+
return at::detail::getCUDAHooks().isGPUArch({"gfx1250"}, index);
151+
}
152+
149153
#else
150154
constexpr int32_t kWarpSize = 32;
151155
#endif
@@ -1098,6 +1102,11 @@ at::Tensor _weight_int4pack_mm_cuda(
10981102
A.device() == B.device() && A.device() == qScaleAndZeros.device());
10991103

11001104
#if defined(USE_ROCM)
1105+
if (isCDNA5orLater(A.device().index())) {
1106+
TORCH_CHECK(false,
1107+
"_weight_int4pack_mm_cuda is not yet supported on gfx1250. "
1108+
"A WMMA-based implementation is required for gfx1250.");
1109+
}
11011110
if (!isCDNA2orLater(A.device().index())) {
11021111
TORCH_CHECK(false, "_weight_int4pack_mm_cuda is only supported on AMD gpu arch greater than or equal to CDNA2");
11031112
}
@@ -1293,6 +1302,11 @@ at::Tensor _convert_weight_to_int4pack_cuda(
12931302
TORCH_CHECK(innerKTiles == 2 || innerKTiles == 4 || innerKTiles == 8);
12941303

12951304
#if defined(USE_ROCM)
1305+
if (isCDNA5orLater(in.device().index())) {
1306+
TORCH_CHECK(false,
1307+
"_convert_weight_to_int4pack_cuda is not yet supported on gfx1250. "
1308+
"A WMMA-based implementation is required for gfx1250.");
1309+
}
12961310
if (!isCDNA2orLater(in.device().index())) {
12971311
TORCH_CHECK(false, "_convert_weight_to_int4pack_cuda is only supported on AMD gpu arch greater than or equal to CDNA2");
12981312
}

aten/src/ATen/native/sparse/cuda/cuSPARSELtOps.cpp

Lines changed: 39 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
#include <unordered_map>
33
#include <mutex>
44
#include <string_view>
5+
#include <unordered_map>
6+
#include <vector>
7+
#include <c10/util/StringUtil.h>
58
#if AT_CUSPARSELT_ENABLED()
69

710
namespace at::native {
@@ -22,37 +25,51 @@ thread_local bool handle_initialized = false;
2225
c10::once_flag g_hipSparseLtSupportInitFlag;
2326
static bool g_hipSparseLtSupported = false;
2427

28+
static const std::vector<std::string>& hipSparseLtSupportedArchs() {
29+
#if ROCM_VERSION >= 71400
30+
static const std::vector<std::string> archs = {"gfx950", "gfx942", "gfx1250"};
31+
#elif ROCM_VERSION >= 71200
32+
static const std::vector<std::string> archs = {"gfx950", "gfx942"};
33+
#else
34+
static const std::vector<std::string> archs = {};
35+
#endif
36+
return archs;
37+
}
38+
2539
// Initialize the hipSparseLt support status once for the platform
2640
static void initHipSparseLtSupport() {
27-
// Default to not supported
28-
g_hipSparseLtSupported = false;
29-
30-
// Check only the first available device
31-
try {
32-
if (at::cuda::device_count() > 0) {
33-
g_hipSparseLtSupported = at::detail::getCUDAHooks().isGPUArch({"gfx950", "gfx942"}, 0);
34-
}
35-
} catch (const std::exception&) {
36-
// If an exception occurs during device property check, we assume hipSparseLt is not supported
37-
// This could happen due to driver issues, device access problems, or other runtime errors
38-
g_hipSparseLtSupported = false;
39-
TORCH_WARN("Exception occurred while checking hipSparseLt support. Assuming not supported.");
41+
// Default to not supported
42+
g_hipSparseLtSupported = false;
43+
44+
// Check only the first available device
45+
try {
46+
if (at::cuda::device_count() > 0) {
47+
g_hipSparseLtSupported = at::detail::getCUDAHooks().isGPUArch(
48+
hipSparseLtSupportedArchs(), 0);
4049
}
50+
} catch (const std::exception&) {
51+
// If an exception occurs during device property check, we assume
52+
// hipSparseLt is not supported This could happen due to driver issues,
53+
// device access problems, or other runtime errors
54+
g_hipSparseLtSupported = false;
55+
TORCH_WARN(
56+
"Exception occurred while checking hipSparseLt support. Assuming not supported.");
57+
}
4158
}
4259

4360
static bool isHipSparseLtSupported() {
4461
// Initialize support check only once
4562
c10::call_once(g_hipSparseLtSupportInitFlag, initHipSparseLtSupport);
4663

47-
// Return cached result (platform-wide)
48-
if (!g_hipSparseLtSupported) {
49-
TORCH_CHECK(
50-
false,
51-
"hipSparseLt not supported on this device, supported architectures: "
52-
"gfx950, gfx942. "
53-
"required ROCM version: 6.4.0 or later.");
54-
}
55-
return g_hipSparseLtSupported;
64+
// Return cached result (platform-wide)
65+
if (!g_hipSparseLtSupported) {
66+
TORCH_CHECK(
67+
false,
68+
"hipSparseLt not supported on this device. Supported architectures: ",
69+
c10::Join(", ", hipSparseLtSupportedArchs()),
70+
". hipSparseLt on ROCm requires ROCm 7.12 or newer.");
71+
}
72+
return g_hipSparseLtSupported;
5673
}
5774
#endif
5875

caffe2/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1866,6 +1866,10 @@ if(USE_ROCM)
18661866
target_link_libraries(torch_hip PRIVATE ck_sdpa)
18671867
endif()
18681868

1869+
if(TARGET ck_gemm)
1870+
target_link_libraries(torch_hip PRIVATE ck_gemm)
1871+
endif()
1872+
18691873
if(USE_MSLK)
18701874
if(USE_ROCM)
18711875
target_link_libraries(torch_hip PRIVATE mslk)

test/inductor/test_aot_inductor.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
from torch.testing._internal import common_utils
4747
from torch.testing._internal.common_cuda import (
4848
CDNA2OrLater,
49+
CDNA5OrLater,
4950
PLATFORM_SUPPORTS_FLASH_ATTENTION,
5051
PLATFORM_SUPPORTS_FP8,
5152
PLATFORM_SUPPORTS_FP8_GROUPED_GEMM,
@@ -7174,6 +7175,8 @@ def test__weight_int4pack_mm(self, m, n, q_group, num_groups):
71747175
raise unittest.SkipTest("requires GPU")
71757176

71767177
if TEST_WITH_ROCM:
7178+
if CDNA5OrLater():
7179+
self.skipTest("int4 mm not yet implemented for gfx1250 (needs WMMA)")
71777180
if not CDNA2OrLater():
71787181
self.skipTest("_int4_mm is supported only for CDNA2 or later")
71797182

@@ -7211,6 +7214,8 @@ def test__weight_int4pack_mm_with_scales_and_zeros(self, m, n, q_group, num_grou
72117214
raise unittest.SkipTest("requires Intel GPU")
72127215

72137216
if TEST_WITH_ROCM:
7217+
if CDNA5OrLater():
7218+
self.skipTest("int4 mm not yet implemented for gfx1250 (needs WMMA)")
72147219
if not CDNA2OrLater():
72157220
self.skipTest("_int4_mm is supported only for CDNA2 or later")
72167221

0 commit comments

Comments
 (0)