Skip to content

Commit 7d2cf3b

Browse files
committed
feat: support gfx1250 on turbo (Part1)
1 parent 573bb39 commit 7d2cf3b

35 files changed

Lines changed: 578 additions & 196 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,4 @@ agent/workspace/
1515
logs/
1616
primus_turbo/_build_info.py
1717
primus_turbo/_version.py
18+
primus_turbo/common/build_config.py

csrc/include/primus_turbo/arch.h

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
namespace primus_turbo {
1212

13-
enum class GPUArch { GFX942, GFX950, UNKNOWN };
13+
enum class GPUArch { GFX942, GFX950, GFX1250, UNKNOWN };
1414

1515
inline GPUArch get_current_arch() {
1616
static GPUArch cached_arch = []() -> GPUArch {
@@ -23,6 +23,8 @@ inline GPUArch get_current_arch() {
2323
return GPUArch::GFX942;
2424
if (prop.major == 9 && prop.minor == 5)
2525
return GPUArch::GFX950;
26+
if (prop.major == 12 && prop.minor == 5)
27+
return GPUArch::GFX1250;
2628
return GPUArch::UNKNOWN;
2729
}();
2830
return cached_arch;
@@ -36,6 +38,22 @@ inline bool is_gfx942() {
3638
return get_current_arch() == GPUArch::GFX942;
3739
}
3840

41+
inline bool is_gfx1250() {
42+
return get_current_arch() == GPUArch::GFX1250;
43+
}
44+
45+
// gfx1250 = 32, gfx942 / gfx950 (and others) = 64.
46+
inline int warp_size() {
47+
if (is_gfx1250()) {
48+
return 32;
49+
} else if (is_gfx950() || is_gfx942()) {
50+
return 64;
51+
} else {
52+
PRIMUS_TURBO_ERROR("Unknown architecture");
53+
return -1;
54+
}
55+
}
56+
3957
inline int32_t get_multi_processor_count(const int32_t device_id) {
4058
int32_t num_cu = 0;
4159
PRIMUS_TURBO_CHECK_HIP(

csrc/include/primus_turbo/device/memory.cuh

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,19 @@ namespace primus_turbo::device {
1616
// ════════════════════════════════════════════════════════════════
1717

1818
template <int CNT> __device__ __forceinline__ void wait_lgkmcnt() {
19+
#if defined(__gfx1250__)
20+
asm volatile("s_wait_dscnt %0" : : "n"(CNT) : "memory");
21+
#else
1922
asm volatile("s_waitcnt lgkmcnt(%0)" : : "n"(CNT) : "memory");
23+
#endif
2024
}
2125

2226
template <int CNT> __device__ __forceinline__ void wait_vmcnt() {
27+
#if defined(__gfx1250__)
28+
asm volatile("s_wait_loadcnt %0" : : "n"(CNT) : "memory");
29+
#else
2330
asm volatile("s_waitcnt vmcnt(%0)" : : "n"(CNT) : "memory");
31+
#endif
2432
}
2533

2634
// ════════════════════════════════════════════════════════════════

csrc/include/primus_turbo/device/reduce.cuh

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,14 @@
77
#include "primus_turbo/common.h"
88
#include "primus_turbo/device/utils.cuh"
99

10+
// gfx12 (gfx1250 / gfx1251, CDNA5) removed the unified `s_waitcnt`; LDS waits use
11+
// the split `s_wait_dscnt` counter instead.
12+
#if defined(__gfx1250__)
13+
#define PRIMUS_TURBO_WAIT_DS_STR "s_wait_dscnt 0"
14+
#else
15+
#define PRIMUS_TURBO_WAIT_DS_STR "s_waitcnt lgkmcnt(0)"
16+
#endif
17+
1018
#define FINAL_MASK 0xffffffffffffffffULL
1119

1220
namespace primus_turbo {
@@ -187,35 +195,31 @@ template <template <class> class Func, typename T> PRIMUS_TURBO_DEVICE T BlockRe
187195
// block memory-op scheduling around this VALU-bound reduction.
188196
PRIMUS_TURBO_DEVICE float ds_swizzle_xor1(float val) {
189197
float result;
190-
asm volatile("ds_swizzle_b32 %0, %1 offset:0x041F\n\t"
191-
"s_waitcnt lgkmcnt(0)"
198+
asm volatile("ds_swizzle_b32 %0, %1 offset:0x041F\n\t" PRIMUS_TURBO_WAIT_DS_STR
192199
: "=v"(result)
193200
: "v"(val));
194201
return result;
195202
}
196203

197204
PRIMUS_TURBO_DEVICE float ds_swizzle_xor2(float val) {
198205
float result;
199-
asm volatile("ds_swizzle_b32 %0, %1 offset:0x081F\n\t"
200-
"s_waitcnt lgkmcnt(0)"
206+
asm volatile("ds_swizzle_b32 %0, %1 offset:0x081F\n\t" PRIMUS_TURBO_WAIT_DS_STR
201207
: "=v"(result)
202208
: "v"(val));
203209
return result;
204210
}
205211

206212
PRIMUS_TURBO_DEVICE float ds_swizzle_xor8(float val) {
207213
float result;
208-
asm volatile("ds_swizzle_b32 %0, %1 offset:0x201F\n\t"
209-
"s_waitcnt lgkmcnt(0)"
214+
asm volatile("ds_swizzle_b32 %0, %1 offset:0x201F\n\t" PRIMUS_TURBO_WAIT_DS_STR
210215
: "=v"(result)
211216
: "v"(val));
212217
return result;
213218
}
214219

215220
PRIMUS_TURBO_DEVICE float ds_swizzle_xor16(float val) {
216221
float result;
217-
asm volatile("ds_swizzle_b32 %0, %1 offset:0x401F\n\t"
218-
"s_waitcnt lgkmcnt(0)"
222+
asm volatile("ds_swizzle_b32 %0, %1 offset:0x401F\n\t" PRIMUS_TURBO_WAIT_DS_STR
219223
: "=v"(result)
220224
: "v"(val));
221225
return result;
@@ -247,36 +251,38 @@ PRIMUS_TURBO_DEVICE float warp_reduce_max_8_dpp(float val) {
247251
// clobber) is what makes the per-row reduction deterministic.
248252

249253
// Step 1: Exchange with thread 4 positions away
250-
asm volatile("ds_swizzle_b32 %0, %1 offset:0x101F\n\t"
251-
"s_waitcnt lgkmcnt(0)"
254+
asm volatile("ds_swizzle_b32 %0, %1 offset:0x101F\n\t" PRIMUS_TURBO_WAIT_DS_STR
252255
: "=v"(tmp)
253256
: "v"(v));
254257
val = fmaxf(val, uint_as_float(tmp));
255258
v = float_as_uint(val);
256259

257260
// Step 2: Exchange with thread 2 positions away
258-
asm volatile("ds_swizzle_b32 %0, %1 offset:0x081F\n\t"
259-
"s_waitcnt lgkmcnt(0)"
261+
asm volatile("ds_swizzle_b32 %0, %1 offset:0x081F\n\t" PRIMUS_TURBO_WAIT_DS_STR
260262
: "=v"(tmp)
261263
: "v"(v));
262264
val = fmaxf(val, uint_as_float(tmp));
263265
v = float_as_uint(val);
264266

265267
// Step 3: Exchange with adjacent thread
266-
asm volatile("ds_swizzle_b32 %0, %1 offset:0x041F\n\t"
267-
"s_waitcnt lgkmcnt(0)"
268+
asm volatile("ds_swizzle_b32 %0, %1 offset:0x041F\n\t" PRIMUS_TURBO_WAIT_DS_STR
268269
: "=v"(tmp)
269270
: "v"(v));
270271
val = fmaxf(val, uint_as_float(tmp));
271272

272273
return val;
273274
}
274275

276+
// Full-wavefront max reduction. ``ds_swizzle`` only exchanges within 32-lane
277+
// groups, so a 64-lane wavefront needs an extra cross-group (lane ^ 32) step
278+
// while a 32-lane wavefront (gfx1250) is already fully reduced after xor16.
275279
PRIMUS_TURBO_DEVICE float warp_reduce_max_64_dpp(float val) {
276280
val = warp_reduce_max_8_dpp(val);
277281
val = fmaxf(val, ds_swizzle_xor8(val));
278282
val = fmaxf(val, ds_swizzle_xor16(val));
279-
val = fmaxf(val, __shfl_xor_sync(FINAL_MASK, val, 32, THREADS_PER_WARP));
283+
if constexpr (THREADS_PER_WARP == 64) {
284+
val = fmaxf(val, __shfl_xor_sync(FINAL_MASK, val, 32, THREADS_PER_WARP));
285+
}
280286
return val;
281287
}
282288

csrc/include/primus_turbo/float8.h

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,17 @@ inline Float8Format current_fp8_format() {
2525
#if PRIMUS_TURBO_DEVICE_COMPILE
2626
return Float8Format::FNUZ; // dummy
2727
#else
28-
static Float8Format fmt = [] { return is_gfx950() ? Float8Format::OCP : Float8Format::FNUZ; }();
28+
static Float8Format fmt = [] { return is_gfx942() ? Float8Format::FNUZ : Float8Format::OCP; }();
2929
return fmt;
3030
#endif
3131
}
3232

3333
PRIMUS_TURBO_HOST_DEVICE bool is_fp8_fnuz() {
3434
#if PRIMUS_TURBO_DEVICE_COMPILE
35-
#if defined(__gfx950__)
36-
return false; // gfx950 OCP
37-
#else
35+
#if defined(__gfx942__)
3836
return true;
37+
#else
38+
return false; // gfx950 OCP
3939
#endif
4040
#else
4141
return current_fp8_format() == Float8Format::FNUZ;
@@ -45,10 +45,10 @@ PRIMUS_TURBO_HOST_DEVICE bool is_fp8_fnuz() {
4545
struct float8_e4m3_t {
4646

4747
#if PRIMUS_TURBO_DEVICE_COMPILE
48-
#if defined(__gfx950__)
49-
using storage_t = __hip_fp8_e4m3; // OCP on gfx950
48+
#if defined(__gfx942__)
49+
using storage_t = __hip_fp8_e4m3_fnuz; // FNUZ on gfx942
5050
#else
51-
using storage_t = __hip_fp8_e4m3_fnuz; // FNUZ on others
51+
using storage_t = __hip_fp8_e4m3; // OCP on others
5252
#endif
5353
storage_t val;
5454
#else // host side – keep both encodings
@@ -180,10 +180,10 @@ static_assert(std::is_trivially_copyable_v<float8_e4m3_t>);
180180
struct float8_e5m2_t {
181181

182182
#if PRIMUS_TURBO_DEVICE_COMPILE
183-
#if defined(__gfx950__)
184-
using storage_t = __hip_fp8_e5m2; // OCP on gfx950
183+
#if defined(__gfx942__)
184+
using storage_t = __hip_fp8_e5m2_fnuz; // FNUZ on gfx942
185185
#else
186-
using storage_t = __hip_fp8_e5m2_fnuz; // FNUZ on others
186+
using storage_t = __hip_fp8_e5m2; // OCP on others
187187
#endif
188188
storage_t val;
189189
#else // host side – keep both encodings
@@ -392,10 +392,10 @@ template <> class numeric_limits<float8_e4m3_t> {
392392

393393
PRIMUS_TURBO_HOST_DEVICE static float8_e4m3_t max() {
394394
#if PRIMUS_TURBO_DEVICE_COMPILE
395-
#if defined(__gfx950__)
396-
return float8_e4m3_t::from_bits(0x7E);
397-
#else
395+
#if defined(__gfx942__)
398396
return float8_e4m3_t::from_bits(0x7F);
397+
#else
398+
return float8_e4m3_t::from_bits(0x7E);
399399
#endif
400400
#else
401401
return primus_turbo::is_fp8_fnuz() ? float8_e4m3_t::from_bits(0x7F)
@@ -414,10 +414,10 @@ template <> class numeric_limits<float8_e4m3_t> {
414414
// FNUZ: 0x80
415415
PRIMUS_TURBO_HOST_DEVICE static float8_e4m3_t quiet_NaN() {
416416
#if PRIMUS_TURBO_DEVICE_COMPILE
417-
#if defined(__gfx950__)
418-
return float8_e4m3_t::from_bits(0x7F);
419-
#else
417+
#if defined(__gfx942__)
420418
return float8_e4m3_t::from_bits(0x80);
419+
#else
420+
return float8_e4m3_t::from_bits(0x7F);
421421
#endif
422422
#else
423423
return primus_turbo::is_fp8_fnuz() ? float8_e4m3_t::from_bits(0x80)
@@ -430,10 +430,10 @@ template <> class numeric_limits<float8_e5m2_t> {
430430
public:
431431
static constexpr bool is_specialized = true;
432432
#if PRIMUS_TURBO_DEVICE_COMPILE
433-
#if defined(__gfx950__)
434-
static constexpr bool has_infinity = true;
435-
#else
433+
#if defined(__gfx942__)
436434
static constexpr bool has_infinity = false;
435+
#else
436+
static constexpr bool has_infinity = true;
437437
#endif
438438
#else
439439
// Host: cannot determine at compile time whether this is OCP or FNUZ.
@@ -448,10 +448,10 @@ template <> class numeric_limits<float8_e5m2_t> {
448448

449449
PRIMUS_TURBO_HOST_DEVICE static float8_e5m2_t max() {
450450
#if PRIMUS_TURBO_DEVICE_COMPILE
451-
#if defined(__gfx950__)
452-
return float8_e5m2_t::from_bits(0x7B);
453-
#else
451+
#if defined(__gfx942__)
454452
return float8_e5m2_t::from_bits(0x7F);
453+
#else
454+
return float8_e5m2_t::from_bits(0x7B);
455455
#endif
456456
#else
457457
return primus_turbo::is_fp8_fnuz() ? float8_e5m2_t::from_bits(0x7F)
@@ -463,10 +463,10 @@ template <> class numeric_limits<float8_e5m2_t> {
463463

464464
PRIMUS_TURBO_HOST_DEVICE static float8_e5m2_t infinity() {
465465
#if PRIMUS_TURBO_DEVICE_COMPILE
466-
#if defined(__gfx950__)
467-
return float8_e5m2_t::from_bits(0x7C);
468-
#else
466+
#if defined(__gfx942__)
469467
return max();
468+
#else
469+
return float8_e5m2_t::from_bits(0x7C);
470470
#endif
471471
#else
472472
return primus_turbo::is_fp8_fnuz() ? max() : float8_e5m2_t::from_bits(0x7C);
@@ -475,10 +475,10 @@ template <> class numeric_limits<float8_e5m2_t> {
475475

476476
PRIMUS_TURBO_HOST_DEVICE static float8_e5m2_t quiet_NaN() {
477477
#if PRIMUS_TURBO_DEVICE_COMPILE
478-
#if defined(__gfx950__)
479-
return float8_e5m2_t::from_bits(0x7D);
480-
#else
478+
#if defined(__gfx942__)
481479
return float8_e5m2_t::from_bits(0x80);
480+
#else
481+
return float8_e5m2_t::from_bits(0x7D);
482482
#endif
483483
#else
484484
return primus_turbo::is_fp8_fnuz() ? float8_e5m2_t::from_bits(0x80)

csrc/include/primus_turbo/gemm.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44

55
#pragma once
66

7+
#ifdef BUILD_CK_BACKEND
78
#include "ck_tile/ops/gemm_quant/pipeline/tile_gemm_quant_traits.hpp"
9+
#endif
810
#include "primus_turbo/dtype.h"
911
#include <cstdint>
1012
#include <hip/hip_runtime.h>
@@ -56,6 +58,7 @@ void hipblaslt_gemm_impl(const void *A, const hipDataType A_type, const int64_t
5658
//==================================================================
5759
// CK GEMM
5860
//==================================================================
61+
#ifdef BUILD_CK_BACKEND
5962

6063
template <typename AType, typename BType, typename CType, typename ACCType = float>
6164
struct CKGemmFP8Params {
@@ -79,9 +82,12 @@ template <typename ADataType, typename BDataType, typename CDataType, typename A
7982
ck_tile::QuantType QuantMode>
8083
void ck_gemm_fp8_impl(const CKGemmFP8Params<ADataType, BDataType, CDataType, AccDataType> &params);
8184

85+
#endif // BUILD_CK_BACKEND
86+
8287
//==================================================================
8388
// Turbo GEMM
8489
//==================================================================
90+
#ifdef BUILD_TURBO_BACKEND
8591

8692
size_t turbo_gemm_mxfp8_workspace_size(int32_t m, int32_t n, int32_t k);
8793

@@ -92,4 +98,6 @@ void turbo_gemm_mxfp8_impl(const AType *a_ptr, const BType *b_ptr,
9298
int32_t n, int32_t k, void *workspace, size_t workspace_size,
9399
hipStream_t stream);
94100

101+
#endif // BUILD_TURBO_BACKEND
102+
95103
} // namespace primus_turbo

csrc/include/primus_turbo/grouped_gemm.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,20 @@
44

55
#pragma once
66

7+
#ifdef BUILD_CK_BACKEND
78
#include "ck_tile/ops/gemm_quant/pipeline/tile_gemm_quant_traits.hpp"
9+
#endif
810
#include <cstdint>
911
#include <hip/hip_runtime.h>
1012

1113
#include "primus_turbo/common.h"
1214

1315
namespace primus_turbo {
1416

17+
#ifdef BUILD_CK_BACKEND
1518
std::int64_t get_ck_grouped_gemm_args_sizes(const int group_num);
1619
std::int64_t get_ck_grouped_gemm_fp8_args_sizes(const int group_num);
20+
#endif
1721

1822
std::int64_t get_hipblaslt_grouped_gemm_workspace_size();
1923

@@ -56,6 +60,7 @@ template <typename AType, typename BType, typename CType> struct GroupedGemmPara
5660
int32_t ws_local_per_xcd = 0;
5761
};
5862

63+
#ifdef BUILD_CK_BACKEND
5964
template <typename AType, typename BType, typename CType>
6065
struct CKGroupedGemmParams : public GroupedGemmParams<AType, BType, CType> {
6166
void *args_ptr = nullptr;
@@ -66,6 +71,7 @@ struct CKGroupedGemmFP8Params : public CKGroupedGemmParams<AType, BType, CType>
6671
const ACCType *aq_ptr = nullptr;
6772
const ACCType *bq_ptr = nullptr;
6873
};
74+
#endif // BUILD_CK_BACKEND
6975

7076
struct HipblasltGroupedGemmParams {
7177
const void *a_ptr = nullptr;
@@ -99,6 +105,7 @@ struct HipblasltGroupedGemmParams {
99105
//==================================================================
100106
// CK Grouped GEMM
101107
//==================================================================
108+
#ifdef BUILD_CK_BACKEND
102109

103110
template <typename ADataType, typename BDataType, typename CDataType, typename AccDataType = float>
104111
void ck_grouped_gemm(const CKGroupedGemmParams<ADataType, BDataType, CDataType> &params);
@@ -116,6 +123,8 @@ template <typename ADataType, typename BDataType, typename CDataType, typename A
116123
void ck_grouped_gemm_fp8_variable_k(
117124
const CKGroupedGemmFP8Params<ADataType, BDataType, CDataType, AccDataType> &params);
118125

126+
#endif // BUILD_CK_BACKEND
127+
119128
//==================================================================
120129
// hipBLASLt Grouped GEMM
121130
//==================================================================

0 commit comments

Comments
 (0)