Skip to content

Commit a6857c0

Browse files
author
Annie Ren
committed
rocmfp4 refactor
1 parent 46419e5 commit a6857c0

18 files changed

Lines changed: 949 additions & 17 deletions

ggml/src/CMakeLists.txt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,8 +206,6 @@ add_library(ggml-base
206206
ggml-threading.h
207207
ggml-quants.c
208208
ggml-quants.h
209-
../rocmfp4/rocmfp4.c
210-
../rocmfp4/rocmfp4.h
211209
gguf.cpp)
212210

213211
set_target_properties(ggml-base PROPERTIES

ggml/src/ggml-common.h

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,9 @@ typedef sycl::half2 ggml_half2;
112112
#define QI_NVFP4 (QK_NVFP4 / (4 * QR_NVFP4))
113113
#define QR_NVFP4 2
114114

115+
#define QI_ROCMFP4 (QK_ROCMFP4 / (4 * QR_ROCMFP4))
116+
#define QR_ROCMFP4 2
117+
115118
#define QI5_0 (QK5_0 / (4 * QR5_0))
116119
#define QR5_0 2
117120

@@ -226,6 +229,23 @@ typedef struct {
226229
} block_nvfp4;
227230
static_assert(sizeof(block_nvfp4) == sizeof(uint8_t)*(QK_NVFP4/QK_NVFP4_SUB) + QK_NVFP4/2, "wrong nvfp4 block size/padding");
228231

232+
#define QK_ROCMFP4 32
233+
// AMD-tuned compact layout: 16 bytes of packed E2M1-derived 4-bit codes, then
234+
// one unsigned E4M3 scale byte per 16-weight half block.
235+
typedef struct {
236+
uint8_t qs[QK_ROCMFP4/2];
237+
uint8_t e[2];
238+
} block_rocmfp4;
239+
static_assert(sizeof(block_rocmfp4) == QK_ROCMFP4/2 + 2*sizeof(uint8_t), "wrong rocmfp4 block size/padding");
240+
241+
// Speed-focused layout: same 32 packed ROCmFP4 nibbles, but one UE4M3 scale
242+
// for the whole block.
243+
typedef struct {
244+
uint8_t qs[QK_ROCMFP4/2];
245+
uint8_t e;
246+
} block_rocmfp4_fast;
247+
static_assert(sizeof(block_rocmfp4_fast) == QK_ROCMFP4/2 + sizeof(uint8_t), "wrong rocmfp4 fast block size/padding");
248+
229249
#define QK5_0 32
230250
typedef struct {
231251
ggml_half d; // delta
@@ -1136,6 +1156,47 @@ GGML_TABLE_BEGIN(int8_t, kvalues_rocmfp4, 16)
11361156
0, 1, 2, 3, 4, 6, 8, 10, 0, -1, -2, -3, -4, -6, -8, -10,
11371157
GGML_TABLE_END()
11381158

1159+
// ROCmFP4 UE4M3 "half-scale" values for the finite scale bytes 0x00..0x7e (127
1160+
// entries): the subnormal run (byte>>3 == 0, value M*2^-10) followed by 15
1161+
// normal exponent groups (value (8+M)*2^(e-10), e=1..15). This is the single
1162+
// source of truth shared by both materializations of the table: the CPU
1163+
// quantizer scale-search table (ggml-quants.c) and the opt-in GPU
1164+
// constant-memory LUT (ggml-cuda/common.cuh). Each backend stamps its own
1165+
// storage-qualified array from this list so the two can never drift.
1166+
#define GGML_ROCMFP4_SCALE_UE4M3_HALF_LIST \
1167+
(0) * 0x1p-10f, (1) * 0x1p-10f, (2) * 0x1p-10f, (3) * 0x1p-10f, \
1168+
(4) * 0x1p-10f, (5) * 0x1p-10f, (6) * 0x1p-10f, (7) * 0x1p-10f, \
1169+
(8 + 0) * 0x1p-10f, (8 + 1) * 0x1p-10f, (8 + 2) * 0x1p-10f, (8 + 3) * 0x1p-10f, \
1170+
(8 + 4) * 0x1p-10f, (8 + 5) * 0x1p-10f, (8 + 6) * 0x1p-10f, (8 + 7) * 0x1p-10f, \
1171+
(8 + 0) * 0x1p-9f, (8 + 1) * 0x1p-9f, (8 + 2) * 0x1p-9f, (8 + 3) * 0x1p-9f, \
1172+
(8 + 4) * 0x1p-9f, (8 + 5) * 0x1p-9f, (8 + 6) * 0x1p-9f, (8 + 7) * 0x1p-9f, \
1173+
(8 + 0) * 0x1p-8f, (8 + 1) * 0x1p-8f, (8 + 2) * 0x1p-8f, (8 + 3) * 0x1p-8f, \
1174+
(8 + 4) * 0x1p-8f, (8 + 5) * 0x1p-8f, (8 + 6) * 0x1p-8f, (8 + 7) * 0x1p-8f, \
1175+
(8 + 0) * 0x1p-7f, (8 + 1) * 0x1p-7f, (8 + 2) * 0x1p-7f, (8 + 3) * 0x1p-7f, \
1176+
(8 + 4) * 0x1p-7f, (8 + 5) * 0x1p-7f, (8 + 6) * 0x1p-7f, (8 + 7) * 0x1p-7f, \
1177+
(8 + 0) * 0x1p-6f, (8 + 1) * 0x1p-6f, (8 + 2) * 0x1p-6f, (8 + 3) * 0x1p-6f, \
1178+
(8 + 4) * 0x1p-6f, (8 + 5) * 0x1p-6f, (8 + 6) * 0x1p-6f, (8 + 7) * 0x1p-6f, \
1179+
(8 + 0) * 0x1p-5f, (8 + 1) * 0x1p-5f, (8 + 2) * 0x1p-5f, (8 + 3) * 0x1p-5f, \
1180+
(8 + 4) * 0x1p-5f, (8 + 5) * 0x1p-5f, (8 + 6) * 0x1p-5f, (8 + 7) * 0x1p-5f, \
1181+
(8 + 0) * 0x1p-4f, (8 + 1) * 0x1p-4f, (8 + 2) * 0x1p-4f, (8 + 3) * 0x1p-4f, \
1182+
(8 + 4) * 0x1p-4f, (8 + 5) * 0x1p-4f, (8 + 6) * 0x1p-4f, (8 + 7) * 0x1p-4f, \
1183+
(8 + 0) * 0x1p-3f, (8 + 1) * 0x1p-3f, (8 + 2) * 0x1p-3f, (8 + 3) * 0x1p-3f, \
1184+
(8 + 4) * 0x1p-3f, (8 + 5) * 0x1p-3f, (8 + 6) * 0x1p-3f, (8 + 7) * 0x1p-3f, \
1185+
(8 + 0) * 0x1p-2f, (8 + 1) * 0x1p-2f, (8 + 2) * 0x1p-2f, (8 + 3) * 0x1p-2f, \
1186+
(8 + 4) * 0x1p-2f, (8 + 5) * 0x1p-2f, (8 + 6) * 0x1p-2f, (8 + 7) * 0x1p-2f, \
1187+
(8 + 0) * 0x1p-1f, (8 + 1) * 0x1p-1f, (8 + 2) * 0x1p-1f, (8 + 3) * 0x1p-1f, \
1188+
(8 + 4) * 0x1p-1f, (8 + 5) * 0x1p-1f, (8 + 6) * 0x1p-1f, (8 + 7) * 0x1p-1f, \
1189+
(8 + 0) * 0x1p+0f, (8 + 1) * 0x1p+0f, (8 + 2) * 0x1p+0f, (8 + 3) * 0x1p+0f, \
1190+
(8 + 4) * 0x1p+0f, (8 + 5) * 0x1p+0f, (8 + 6) * 0x1p+0f, (8 + 7) * 0x1p+0f, \
1191+
(8 + 0) * 0x1p+1f, (8 + 1) * 0x1p+1f, (8 + 2) * 0x1p+1f, (8 + 3) * 0x1p+1f, \
1192+
(8 + 4) * 0x1p+1f, (8 + 5) * 0x1p+1f, (8 + 6) * 0x1p+1f, (8 + 7) * 0x1p+1f, \
1193+
(8 + 0) * 0x1p+2f, (8 + 1) * 0x1p+2f, (8 + 2) * 0x1p+2f, (8 + 3) * 0x1p+2f, \
1194+
(8 + 4) * 0x1p+2f, (8 + 5) * 0x1p+2f, (8 + 6) * 0x1p+2f, (8 + 7) * 0x1p+2f, \
1195+
(8 + 0) * 0x1p+3f, (8 + 1) * 0x1p+3f, (8 + 2) * 0x1p+3f, (8 + 3) * 0x1p+3f, \
1196+
(8 + 4) * 0x1p+3f, (8 + 5) * 0x1p+3f, (8 + 6) * 0x1p+3f, (8 + 7) * 0x1p+3f, \
1197+
(8 + 0) * 0x1p+4f, (8 + 1) * 0x1p+4f, (8 + 2) * 0x1p+4f, (8 + 3) * 0x1p+4f, \
1198+
(8 + 4) * 0x1p+4f, (8 + 5) * 0x1p+4f, (8 + 6) * 0x1p+4f
1199+
11391200
#define NGRID_IQ1S 2048
11401201
#define IQ1S_DELTA 0.125f
11411202
#define IQ1M_DELTA 0.125f

ggml/src/ggml-cpu/ggml-cpu.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
#include "ops.h"
1515
#include "ggml.h"
1616
#include "common.h"
17-
#include "../../rocmfp4/rocmfp4.h"
1817

1918
#if defined(_MSC_VER) || defined(__MINGW32__)
2019
#include <malloc.h> // using malloc.h with MSC/MINGW

ggml/src/ggml-cpu/quants.c

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,14 @@ void quantize_row_nvfp4(const float * GGML_RESTRICT x, void * GGML_RESTRICT y, i
6262
quantize_row_nvfp4_ref(x, y, k);
6363
}
6464

65+
void rocmfp4_quantize_row_q4_0(const float * GGML_RESTRICT x, void * GGML_RESTRICT y, int64_t k) {
66+
rocmfp4_quantize_row_q4_0_ref(x, (block_rocmfp4 *) y, k);
67+
}
68+
69+
void rocmfp4_quantize_row_q4_0_fast(const float * GGML_RESTRICT x, void * GGML_RESTRICT y, int64_t k) {
70+
rocmfp4_quantize_row_q4_0_fast_ref(x, (block_rocmfp4_fast *) y, k);
71+
}
72+
6573
//
6674
// 2-6 bit quantization in super-blocks
6775
//
@@ -362,6 +370,71 @@ void ggml_vec_dot_nvfp4_q8_0_generic(int n, float * GGML_RESTRICT s, size_t bs,
362370
*s = sumf;
363371
}
364372

373+
// ROCmFP4: Q4_0-layout FP4 (QK_ROCMFP4 == QK8_0), two UE4M3 half-scales per block.
374+
void rocmfp4_vec_dot_q4_0_q8_0(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, size_t bx, const void * GGML_RESTRICT vy, size_t by, int nrc) {
375+
UNUSED(bs);
376+
UNUSED(bx);
377+
UNUSED(by);
378+
assert(nrc == 1);
379+
UNUSED(nrc);
380+
assert(n % QK_ROCMFP4 == 0);
381+
static_assert(QK_ROCMFP4 == QK8_0, "QK_ROCMFP4 and QK8_0 must be the same");
382+
383+
const block_rocmfp4 * GGML_RESTRICT x = vx;
384+
const block_q8_0 * GGML_RESTRICT y = vy;
385+
386+
const int nb = n / QK_ROCMFP4;
387+
float sumf = 0;
388+
389+
for (int ib = 0; ib < nb; ++ib) {
390+
const float d0 = ggml_ue4m3_to_fp32(x[ib].e[0]) * GGML_CPU_FP16_TO_FP32(y[ib].d);
391+
const float d1 = ggml_ue4m3_to_fp32(x[ib].e[1]) * GGML_CPU_FP16_TO_FP32(y[ib].d);
392+
393+
int sumi0 = 0;
394+
int sumi1 = 0;
395+
for (int j = 0; j < QK_ROCMFP4/2; ++j) {
396+
const uint8_t q = x[ib].qs[j];
397+
sumi0 += kvalues_rocmfp4[q & 0x0f] * y[ib].qs[j];
398+
sumi1 += kvalues_rocmfp4[q >> 4] * y[ib].qs[j + QK_ROCMFP4/2];
399+
}
400+
401+
sumf += d0 * (float) sumi0 + d1 * (float) sumi1;
402+
}
403+
404+
*s = sumf;
405+
}
406+
407+
void rocmfp4_vec_dot_q4_0_fast_q8_0(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, size_t bx, const void * GGML_RESTRICT vy, size_t by, int nrc) {
408+
UNUSED(bs);
409+
UNUSED(bx);
410+
UNUSED(by);
411+
assert(nrc == 1);
412+
UNUSED(nrc);
413+
assert(n % QK_ROCMFP4 == 0);
414+
static_assert(QK_ROCMFP4 == QK8_0, "QK_ROCMFP4 and QK8_0 must be the same");
415+
416+
const block_rocmfp4_fast * GGML_RESTRICT x = vx;
417+
const block_q8_0 * GGML_RESTRICT y = vy;
418+
419+
const int nb = n / QK_ROCMFP4;
420+
float sumf = 0;
421+
422+
for (int ib = 0; ib < nb; ++ib) {
423+
const float d = ggml_ue4m3_to_fp32(x[ib].e) * GGML_CPU_FP16_TO_FP32(y[ib].d);
424+
int sumi = 0;
425+
426+
for (int j = 0; j < QK_ROCMFP4/2; ++j) {
427+
const uint8_t q = x[ib].qs[j];
428+
sumi += kvalues_rocmfp4[q & 0x0f] * y[ib].qs[j];
429+
sumi += kvalues_rocmfp4[q >> 4] * y[ib].qs[j + QK_ROCMFP4/2];
430+
}
431+
432+
sumf += d * (float) sumi;
433+
}
434+
435+
*s = sumf;
436+
}
437+
365438
void ggml_vec_dot_q5_0_q8_0_generic(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, size_t bx, const void * GGML_RESTRICT vy, size_t by, int nrc) {
366439
const int qk = QK8_0;
367440
const int nb = n / qk;

ggml/src/ggml-cpu/quants.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ void quantize_row_q8_1(const float * GGML_RESTRICT x, void * GGML_RESTRICT y, in
2424
void quantize_row_mxfp4(const float * GGML_RESTRICT x, void * GGML_RESTRICT y, int64_t k);
2525
void quantize_row_nvfp4(const float * GGML_RESTRICT x, void * GGML_RESTRICT y, int64_t k);
2626

27+
// CPU from_float wrappers; defined in ggml-cpu/quants.c over the _ref quantizers in ggml-quants.c.
28+
GGML_API void rocmfp4_quantize_row_q4_0 (const float * GGML_RESTRICT x, void * GGML_RESTRICT y, int64_t k);
29+
GGML_API void rocmfp4_quantize_row_q4_0_fast(const float * GGML_RESTRICT x, void * GGML_RESTRICT y, int64_t k);
30+
2731
void quantize_row_q2_K(const float * GGML_RESTRICT x, void * GGML_RESTRICT y, int64_t k);
2832
void quantize_row_q3_K(const float * GGML_RESTRICT x, void * GGML_RESTRICT y, int64_t k);
2933
void quantize_row_q4_K(const float * GGML_RESTRICT x, void * GGML_RESTRICT y, int64_t k);
@@ -49,6 +53,9 @@ void ggml_vec_dot_q8_0_q8_0(int n, float * GGML_RESTRICT s, size_t bs, const voi
4953
void ggml_vec_dot_mxfp4_q8_0(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, size_t bx, const void * GGML_RESTRICT vy, size_t by, int nrc);
5054
void ggml_vec_dot_nvfp4_q8_0(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, size_t bx, const void * GGML_RESTRICT vy, size_t by, int nrc);
5155

56+
GGML_API void rocmfp4_vec_dot_q4_0_q8_0 (int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, size_t bx, const void * GGML_RESTRICT vy, size_t by, int nrc);
57+
GGML_API void rocmfp4_vec_dot_q4_0_fast_q8_0(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, size_t bx, const void * GGML_RESTRICT vy, size_t by, int nrc);
58+
5259
void ggml_vec_dot_q2_K_q8_K(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, size_t bx, const void * GGML_RESTRICT vy, size_t by, int nrc);
5360
void ggml_vec_dot_q3_K_q8_K(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, size_t bx, const void * GGML_RESTRICT vy, size_t by, int nrc);
5461
void ggml_vec_dot_q4_K_q8_K(int n, float * GGML_RESTRICT s, size_t bs, const void * GGML_RESTRICT vx, size_t bx, const void * GGML_RESTRICT vy, size_t by, int nrc);

ggml/src/ggml-cuda/common.cuh

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
#endif
2222
#endif
2323
#include "ggml-common.h"
24-
#include "../../rocmfp4/rocmfp4.h"
2524

2625
#include <array>
2726
#include <algorithm>
@@ -867,6 +866,36 @@ static __device__ __forceinline__ float ggml_cuda_ue4m3_to_fp32(uint8_t x) {
867866
#endif // defined(GGML_USE_HIP) && defined(CDNA3) && defined(FP8_AVAILABLE) && HIP_VERSION >= 60200000
868867
}
869868

869+
// ============================================================================
870+
// ROCmFP4 (AMD gfx1151) device scale + FP4 codebook decode helpers.
871+
// GGML_ROCMFP4_USE_SCALE_LUT is an opt-in AMD-specific escape hatch (constant-memory table) kept for profiling.
872+
// ============================================================================
873+
874+
#ifndef GGML_ROCMFP4_USE_SCALE_LUT
875+
#define GGML_ROCMFP4_USE_SCALE_LUT 0
876+
#endif
877+
878+
#if defined(GGML_USE_HIP) && GGML_ROCMFP4_USE_SCALE_LUT
879+
// Values come from the shared GGML_ROCMFP4_SCALE_UE4M3_HALF_LIST in ggml-common.h
880+
// (single source of truth, also used by the CPU quantizer table in ggml-quants.c).
881+
static __device__ __constant__ const float rocmfp4_scale_ue4m3_half_lut[127] = { GGML_ROCMFP4_SCALE_UE4M3_HALF_LIST };
882+
#endif
883+
884+
static __device__ __forceinline__ float rocmfp4_ue4m3_to_fp32_half_finite(uint8_t x) {
885+
#if defined(GGML_USE_HIP) && GGML_ROCMFP4_USE_SCALE_LUT
886+
return x <= 0x7e ? rocmfp4_scale_ue4m3_half_lut[x] : 0.0f; // opt-in fast table
887+
#else
888+
return ggml_cuda_ue4m3_to_fp32(x); // default: shared decoder
889+
#endif
890+
}
891+
892+
static __device__ __forceinline__ int8_t rocmfp4_decode_i8(uint8_t q) {
893+
q &= 0x0f;
894+
const int mag3 = q & 0x07;
895+
const int mag = mag3 <= 4 ? mag3 : 2*mag3 - 4;
896+
return (q & 0x08) ? -mag : mag;
897+
}
898+
870899
static __device__ __forceinline__ uint8_t ggml_cuda_fp32_to_ue4m3(float x) {
871900
#if defined(BLACKWELL_MMA_AVAILABLE) // This is used for NVFP4 subblock scale quantizations only
872901
if (!(x > 0.0f)) {

ggml/src/ggml-cuda/convert.cu

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
#include "convert.cuh"
22
#include "dequantize.cuh"
3-
#include "../../rocmfp4/rocmfp4_hip_scale.cuh"
43

54
#include <cstdint>
65

ggml/src/ggml-cuda/dequantize.cuh

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
#include "common.cuh"
22
#include "convert.cuh"
3-
#include "../../rocmfp4/rocmfp4_hip_scale.cuh"
43

54
static __device__ __forceinline__ void dequantize_q1_0(const void * vx, const int64_t ib, const int iqs, float2 & v){
65
const block_q1_0 * x = (const block_q1_0 *) vx;

0 commit comments

Comments
 (0)