Skip to content

Commit 4918ed6

Browse files
committed
Merge branch 'main' into process-input-refactor
2 parents fd6a35f + 6a32dd9 commit 4918ed6

4 files changed

Lines changed: 52 additions & 7 deletions

File tree

humming/include/humming/datatype/dequant_fused.cuh

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,10 @@ CUDA_INLINE uint2 fused_dequant_single_for_mxfp4<Float8E4M3>(const uint32_t qb,
1717
uint32_t exp_offset_buffer1 = (exp_offset * 0x08080800) + ((0x03020100 << 2) - 0x00000400);
1818
uint32_t exp_offset_buffer2 = (exp_offset * 0x08080808) + (0x07060504 << 2);
1919

20+
uint32_t qb_selectors = qb & 0x77777777;
2021
uint32_t exp_offsets[2] = {
21-
__byte_perm(exp_offset_buffer1, exp_offset_buffer2, qb),
22-
__byte_perm(exp_offset_buffer1, exp_offset_buffer2, qb >> 16)};
22+
prmt(exp_offset_buffer1, exp_offset_buffer2, qb_selectors),
23+
prmt(exp_offset_buffer1, exp_offset_buffer2, qb_selectors >> 16)};
2324

2425
uint32_t res[2] = {
2526
lop3_and_or(qb << 4, 0x80808080, exp_offsets[0]),
@@ -36,13 +37,14 @@ CUDA_INLINE uint2 fused_dequant_single_for_mxfp4<Int8>(const uint32_t qb, const
3637

3738
uint32_t res[2];
3839
uint32_t signs[2] = {qb >> 3, qb >> 7};
40+
uint32_t qb_selectors = qb & 0x77777777;
3941
uint32_t int8s[2] = {
40-
__byte_perm(buffer1, buffer2, qb),
41-
__byte_perm(buffer1, buffer2, qb >> 16)};
42+
prmt(buffer1, buffer2, qb_selectors),
43+
prmt(buffer1, buffer2, qb_selectors >> 16)};
4244

4345
PRAGMA_UNROLL
4446
for (uint32_t i = 0; i < 2; i++) {
45-
uint32_t val = __byte_perm(int8s[0], int8s[1], 0x6420 + 0x1111 * i);
47+
uint32_t val = prmt(int8s[0], int8s[1], 0x6420 + 0x1111 * i);
4648
uint32_t flag = signs[i] & 0x01010101;
4749
uint32_t mask = flag * 0xFF;
4850
res[i] = (val - flag) ^ mask;
@@ -55,7 +57,9 @@ template <class TargetType, uint32_t kCount, bool kUseWgmma>
5557
CUDA_INLINE void fused_dequant_for_mxfp4(const uint32_t *qb_ptrs, uint32_t *res_ptrs, uint32_t *scales_ptr) {
5658
PRAGMA_UNROLL
5759
for (uint32_t i = 0; i < kCount * 2; i++) {
58-
uint32_t exp_offset = reinterpret_cast<uint8_t *>(scales_ptr)[i];
60+
uint32_t scale_word = scales_ptr[i / 4];
61+
uint32_t byte_selector = 1u << (8 * (i % 4));
62+
uint32_t exp_offset = __dp4a(scale_word, byte_selector, 0u);
5963
uint2 res = fused_dequant_single_for_mxfp4<TargetType>(qb_ptrs[i], exp_offset);
6064
res_ptrs[i * 2] = res.x;
6165
res_ptrs[i * 2 + 1] = res.y;

humming/include/humming/utils/ptx/math.cuh

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22

33
#include <humming/utils/base.cuh>
44

5+
CUDA_INLINE uint32_t prmt(uint32_t a, uint32_t b, uint32_t s) {
6+
uint32_t res;
7+
asm volatile("prmt.b32 %0, %1, %2, %3;\n"
8+
: "=r"(res)
9+
: "r"(a), "r"(b), "r"(s));
10+
return res;
11+
};
12+
513
template <uint32_t lut>
614
CUDA_INLINE uint32_t lop3(uint32_t a, uint32_t b, uint32_t c) {
715
uint32_t res;

humming/tune/sm90_policies.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,12 @@ def build_sm90_seed_config(problem: TuningProblem) -> dict:
115115
)
116116
if use_wide_indexed_tile:
117117
warp_shape_n = 64
118-
if layer_config.shape_k <= 512 and layer_config.shape_n >= 2048:
118+
# N=512 spills its accumulator at two-CTA residency from M=48 onward.
119+
if (
120+
layer_config.shape_k <= 512
121+
and layer_config.shape_n >= 2048
122+
and block_shape_m < 48
123+
):
119124
block_shape_n = 512
120125
block_shape_k = 64
121126
else:

tests/test_sm90_heuristics.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,34 @@ def test_mxfp4_a16_indexed_preserves_warp_k_and_fits_grid(
288288
assert config["use_stream_k"] is expected_stream_k
289289

290290

291+
@pytest.mark.parametrize("shape_k", [512, 256])
292+
def test_mxfp4_a16_short_k_limits_wide_n_tile_before_block_m48(shape_k):
293+
layer = _layer(
294+
6144,
295+
shape_k,
296+
num_experts=256,
297+
a_dtype=dtypes.bfloat16,
298+
as_dtype=None,
299+
input_scale_group_size=0,
300+
)
301+
302+
small = Sm90Heuristics.get_config(
303+
layer,
304+
shape_m=6144,
305+
gemm_type=GemmType.INDEXED,
306+
)
307+
large = Sm90Heuristics.get_config(
308+
layer,
309+
shape_m=8192,
310+
gemm_type=GemmType.INDEXED,
311+
)
312+
313+
assert small["block_shape"] == (32, 512, 64)
314+
assert small["num_ctas_per_sm"] == 2
315+
assert large["block_shape"] == (48, 256, 64)
316+
assert large["num_ctas_per_sm"] == 2
317+
318+
291319
def test_nvfp4_a16_uses_narrow_first_wave_only():
292320
layer = _layer(
293321
5376,

0 commit comments

Comments
 (0)