Skip to content

Commit f7db21e

Browse files
authored
Reduce redundant FlyDSL numeric wrappers (#448)
1 parent a759efe commit f7db21e

4 files changed

Lines changed: 65 additions & 77 deletions

File tree

kernels/blockscale_preshuffle_gemm.py

Lines changed: 44 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@
1818
from flydsl._mlir import ir
1919

2020
from flydsl.expr import arith, gpu, buffer_ops, vector, rocdl
21-
from flydsl.expr.arith import ArithValue
22-
from flydsl.expr.typing import T
21+
from flydsl.expr.typing import T, Vector as Vec
2322

2423

2524
from kernels.mfma_preshuffle_pipeline import (
@@ -124,6 +123,9 @@ def compile_blockscale_preshuffle_gemm(
124123
def _out_elem_type():
125124
return T.bf16 if is_bf16_out else T.f16
126125

126+
def _out_elem_dtype():
127+
return fx.BFloat16 if is_bf16_out else fx.Float16
128+
127129
epilog_tag = "cshuffle" if use_cshuffle_epilog else "direct"
128130

129131
module_name = (
@@ -168,10 +170,9 @@ def kernel_gemm(
168170
i32_m: fx.Int32,
169171
i32_n: fx.Int32,
170172
):
171-
c_m = arith.index_cast(T.index, i32_m)
172-
c_n = arith.index_cast(T.index, i32_n)
173+
c_n = fx.Index(i32_n)
173174

174-
acc_init = arith.constant_vector(0.0, T.f32x4)
175+
acc_init = fx.full(4, 0.0, fx.Float32)
175176

176177
# ---- B layout (compile-time since N, K are known) ----
177178
n0_val = N // 16
@@ -189,7 +190,7 @@ def kernel_gemm(
189190
stride_lds = fx.make_stride(tile_k, 1)
190191
layout_lds = fx.make_layout(shape_lds, stride_lds)
191192

192-
k_blocks16 = arith.index(tile_k_bytes // 16)
193+
k_blocks16 = tile_k_bytes // 16
193194

194195
tx = gpu.thread_id("x")
195196
bx = gpu.block_id("x")
@@ -215,14 +216,14 @@ def kernel_gemm(
215216
lds_out = None
216217

217218
# ---- Buffer resources (explicit num_records_bytes for correct OOB on M tail) ----
218-
rt_M = arith.index_cast(T.index, i32_m)
219-
rt_N = arith.index_cast(T.index, i32_n)
220-
a_nbytes = rt_M * fx.Index(K) # fp8: 1 byte/elem
219+
rt_M = fx.Index(i32_m)
220+
rt_N = fx.Index(i32_n)
221+
a_nbytes = rt_M * K # fp8: 1 byte/elem
221222
a_rsrc = buffer_ops.create_buffer_resource(arg_a, max_size=False, num_records_bytes=a_nbytes)
222223
out_elem_bytes = 2 # bf16/fp16
223-
c_nbytes = rt_M * rt_N * fx.Index(out_elem_bytes)
224+
c_nbytes = rt_M * rt_N * out_elem_bytes
224225
c_rsrc = buffer_ops.create_buffer_resource(arg_c, max_size=False, num_records_bytes=c_nbytes)
225-
sa_nbytes = arith.index(K // 128) * rt_M * fx.Index(4) # [scale_k, M] f32
226+
sa_nbytes = (K // 128) * rt_M * 4 # [scale_k, M] f32
226227
scale_a_rsrc = buffer_ops.create_buffer_resource(arg_scale_a, max_size=False, num_records_bytes=sa_nbytes)
227228

228229
b_rsrc = buffer_ops.create_buffer_resource(arg_b, max_size=True)
@@ -268,7 +269,7 @@ def load_b_pack(base_k, ki_step, ni):
268269
)
269270

270271
c64_b = 64
271-
_lds_k_dim_c = fx.Index(tile_k)
272+
_lds_k_dim_c = tile_k
272273

273274
def load_b_packs_k64(base_k, ku: int, ni: int):
274275
base_k_bytes = base_k
@@ -282,9 +283,9 @@ def load_b_packs_k64(base_k, ku: int, ni: int):
282283
elem_type=T.f8, vec_elems=16, elem_bytes=elem_bytes,
283284
offset_in_bytes=True,
284285
)
285-
b_i64x2 = vector.bitcast(T.i64x2, b16)
286-
b0_i64 = vector.extract(b_i64x2, static_position=[0], dynamic_position=[])
287-
b1_i64 = vector.extract(b_i64x2, static_position=[1], dynamic_position=[])
286+
b_i64x2 = Vec(b16).bitcast(fx.Int64)
287+
b0_i64 = b_i64x2[0]
288+
b1_i64 = b_i64x2[1]
288289
return b0_i64, b1_i64
289290

290291
def load_b_tile(base_k):
@@ -307,9 +308,9 @@ def lds_load_16b(curr_row_a_lds, col_base, lds_buffer):
307308

308309
def lds_load_packs_k64(curr_row_a_lds, col_base, lds_buffer):
309310
loaded_a16 = lds_load_16b(curr_row_a_lds, col_base, lds_buffer)
310-
a_i64x2 = vector.bitcast(T.i64x2, loaded_a16)
311-
a0_i64 = vector.extract(a_i64x2, static_position=[0], dynamic_position=[])
312-
a1_i64 = vector.extract(a_i64x2, static_position=[1], dynamic_position=[])
311+
a_i64x2 = Vec(loaded_a16).bitcast(fx.Int64)
312+
a0_i64 = a_i64x2[0]
313+
a1_i64 = a_i64x2[1]
313314
return a0_i64, a1_i64
314315

315316
# ── A global→reg load ─────────────────────────────────────────────
@@ -318,8 +319,7 @@ def lds_load_packs_k64(curr_row_a_lds, col_base, lds_buffer):
318319
(tile_m, tile_k_dwords), (tile_k_dwords, 1)
319320
)
320321
chunk_i32_a = a_load_bytes // 4
321-
c_chunk_a = fx.Index(chunk_i32_a)
322-
tx_i32_base = tx * c_chunk_a
322+
tx_i32_base = tx * chunk_i32_a
323323

324324
def load_a(idx_i32, a_load_bytes_v):
325325
if const_expr(a_load_bytes_v == 16):
@@ -348,12 +348,12 @@ def load_a_tile(base_k_div4, a_load_bytes_v, tx_i32_base_v, chunk_i32_a_v):
348348
idx_i32 = row_a_global * _k_div4_factor + (base_k_div4 + col_a_local_i32)
349349
a_vec = load_a(idx_i32, a_load_bytes_v)
350350
if const_expr(a_load_bytes_v == 16):
351-
parts.append(vector.bitcast(T.i32x4, a_vec))
351+
parts.append(Vec(a_vec).bitcast(fx.Int32))
352352
else:
353353
parts.append(a_vec)
354354
return parts
355355

356-
c4_bytes = fx.Index(4) # bytes per dword (always 4, used for LDS byte addressing)
356+
c4_bytes = 4 # bytes per dword (always 4, used for LDS byte addressing)
357357

358358
def store_a_tile_to_lds(vec_a_parts, lds_buffer, a_load_bytes_v, tx_i32_base_v, chunk_i32_a_v):
359359
for i in range_constexpr(num_a_loads):
@@ -365,7 +365,7 @@ def store_a_tile_to_lds(vec_a_parts, lds_buffer, a_load_bytes_v, tx_i32_base_v,
365365
layout_lds=layout_lds,
366366
row_local=row_a_local, col_local_i32=col_a_local_i32,
367367
tx_c4=c4_bytes, k_blocks16=k_blocks16,
368-
lds_base=fx.Index(0),
368+
lds_base=0,
369369
vec_part_i32x4=vec_a_parts[i], elem_bytes=elem_bytes,
370370
)
371371
elif const_expr(a_load_bytes_v == 8):
@@ -375,7 +375,7 @@ def store_a_tile_to_lds(vec_a_parts, lds_buffer, a_load_bytes_v, tx_i32_base_v,
375375
layout_lds=layout_lds,
376376
row_local=row_a_local, col_local_i32=col_a_local_i32,
377377
tx_c4=c4_bytes, k_blocks16=k_blocks16,
378-
lds_base=fx.Index(0),
378+
lds_base=0,
379379
vec_part_i32x2=vec_a_parts[i],
380380
)
381381

@@ -402,20 +402,20 @@ def dma_a_tile_to_lds(base_k_div4, lds_buffer):
402402
col_a_local_sw = swizzle_xor16(row_a_local, col_a_local_i32 * c4_bytes, k_blocks16)
403403
row_a_global = bx_m + row_a_local
404404
global_byte_idx = row_a_global * k_bytes_factor + (base_k_div4 * c4_bytes + col_a_local_sw)
405-
global_offset = arith.index_cast(T.i32, global_byte_idx)
405+
global_offset = fx.Int32(global_byte_idx)
406406

407407
if const_expr(i == 0):
408408
lds_addr = memref_dialect.extract_aligned_pointer_as_index(lds_buffer) + wave_id * 64 * dma_bytes
409-
lds_ptr_i64_lane0 = rocdl.readfirstlane(T.i64, arith.index_cast(T.i64, lds_addr))
409+
lds_ptr_i64_lane0 = rocdl.readfirstlane(T.i64, fx.Int64(lds_addr))
410410
else:
411411
lds_ptr_i64_lane0 += total_threads * dma_bytes
412412
lds_ptr_type = ir.Type.parse("!llvm.ptr<3>")
413413
lds_ptr = llvm.inttoptr(lds_ptr_type, lds_ptr_i64_lane0)
414414

415-
size_i32 = arith.constant(dma_bytes, type=T.i32)
416-
soffset = arith.constant(0, type=T.i32)
417-
offset_imm = arith.constant(0, type=T.i32)
418-
aux = arith.constant(1, type=T.i32)
415+
size_i32 = fx.Int32(dma_bytes)
416+
soffset = fx.Int32(0)
417+
offset_imm = fx.Int32(0)
418+
aux = fx.Int32(1)
419419

420420
rocdl.raw_ptr_buffer_load_lds(
421421
a_rsrc,
@@ -447,11 +447,8 @@ def _mfma_fn_placeholder(*args, **kwargs):
447447
mfma_fn = _mfma_fn_placeholder
448448

449449
if const_expr(_is_gfx950):
450-
c0_i64 = arith.constant(0, type=T.i64)
451-
452450
def pack_i64x4_to_i32x8(x0, x1, x2, x3):
453-
v4 = vector.from_elements(T.vec(4, T.i64), [x0, x1, x2, x3])
454-
return vector.bitcast(T.vec(8, T.i32), v4)
451+
return Vec.from_elements([x0, x1, x2, x3], fx.Int64).bitcast(fx.Int32)
455452
else:
456453
mfma_fn = rocdl.mfma_f32_16x16x32_fp8_fp8
457454

@@ -479,17 +476,17 @@ def load_scales_for_tile(k_base):
479476
sa_base_offset = kb * c_M
480477
s_a_vecs = []
481478
for mi in range_constexpr(m_repeat):
482-
row_base_m = bx_m + arith.index(mi * 16)
479+
row_base_m = bx_m + mi * 16
483480
row_g_base = row_base_m + row_off_base
484481
sa_idx = sa_base_offset + row_g_base
485482
s_a_vec = buffer_ops.buffer_load(
486483
scale_a_rsrc, sa_idx, vec_width=4, dtype=T.f32
487484
)
488-
s_a_vecs.append(vector.bitcast(T.f32x4, s_a_vec))
485+
s_a_vecs.append(Vec(s_a_vec).bitcast(fx.Float32))
489486

490487
s_b_vals = []
491488
for ni in range_constexpr(num_acc_n):
492-
col_base_ni = by_n + n_tile_base + arith.index(ni * 16)
489+
col_base_ni = by_n + n_tile_base + ni * 16
493490
n_block = col_base_ni // c_128
494491
sb_idx = n_block * c_scale_k + kb
495492
s_b_val = buffer_ops.buffer_load(
@@ -499,7 +496,7 @@ def load_scales_for_tile(k_base):
499496

500497
s_b_vecs = []
501498
for ni in range_constexpr(num_acc_n):
502-
s_b_vecs.append(vector.broadcast(T.f32x4, s_b_vals[ni]))
499+
s_b_vecs.append(Vec.filled(4, fx.Float32(s_b_vals[ni]), fx.Float32))
503500

504501
combined_scales = []
505502
for mi in range_constexpr(m_repeat):
@@ -611,28 +608,23 @@ def write_row_to_lds(
611608
col_local = col_base_local + (ni * 16)
612609
acc_idx = mi * num_acc_n + ni
613610
acc = final_accs[acc_idx]
614-
val = vector.extract(
615-
acc, static_position=[ii], dynamic_position=[]
616-
)
617-
v_out = arith.trunc_f(_out_elem_type(), val)
611+
val = Vec(acc)[ii]
612+
v_out = val.to(_out_elem_dtype())
618613
lds_idx = row_base_lds + col_local
619-
v1 = vector.from_elements(vec1_out, [v_out])
614+
v1 = Vec.from_elements([v_out], _out_elem_dtype())
620615
vector.store(v1, lds_out, [lds_idx], alignment=2)
621616

622617
def store_pair(*, row_local, row, row_ctx, col_pair0, col_g0, frag):
623618
idx_out = row * c_n + col_g0
624619
byte_off = idx_out * 2
625620
e_vec = 4 if (int(tile_n) % (32 * 4)) == 0 else 2
626621
if const_expr(e_vec == 4):
627-
frag_i32x2 = vector.bitcast(T.vec(2, T.i32), frag)
622+
frag_i32x2 = Vec(frag).bitcast(fx.Int32)
628623
buffer_ops.buffer_store(
629624
frag_i32x2, c_rsrc, byte_off, offset_is_bytes=True
630625
)
631626
else:
632-
frag_i32x1 = vector.bitcast(T.vec(1, T.i32), frag)
633-
frag_i32 = vector.extract(
634-
frag_i32x1, static_position=[0], dynamic_position=[]
635-
)
627+
frag_i32 = Vec(frag).bitcast(fx.Int32)[0]
636628
buffer_ops.buffer_store(
637629
frag_i32, c_rsrc, byte_off, offset_is_bytes=True
638630
)
@@ -660,10 +652,8 @@ def body_row(*, mi, ii, row_in_tile, row):
660652
for ni in range_constexpr(num_acc_n):
661653
acc_idx = mi * num_acc_n + ni
662654
acc = final_accs[acc_idx]
663-
val = vector.extract(
664-
acc, static_position=[ii], dynamic_position=[]
665-
)
666-
val_out = arith.trunc_f(_out_elem_type(), val)
655+
val = Vec(acc)[ii]
656+
val_out = val.to(_out_elem_dtype())
667657
idx_out = idx_base + (ni * 16)
668658
buffer_ops.buffer_store(val_out, c_rsrc, idx_out)
669659

@@ -784,7 +774,7 @@ def _load_a_to_lds(base_k, lds_buffer, a_load_bytes_v, tx_i32_base_v, chunk_i32_
784774
gpu.barrier()
785775
a0_prefetch_pong = prefetch_a0_pack(lds_a_pong)
786776

787-
last_k = arith.index(K - tile_k)
777+
last_k = K - tile_k
788778
final_accs = compute_tile_blockscale(
789779
global_accs, b_tile_pong, lds_a_pong, scales_pong,
790780
a0_prefetch=a0_prefetch_pong,
@@ -826,8 +816,7 @@ def _load_a_to_lds(base_k, lds_buffer, a_load_bytes_v, tx_i32_base_v, chunk_i32_
826816
gpu.barrier()
827817
a0_prefetch_pong = prefetch_a0_pack(lds_a_pong)
828818

829-
last_k = arith.index(K - tile_k)
830-
second_last_k = arith.index(K - tile_k * 2)
819+
last_k = K - tile_k
831820

832821
_load_a_to_lds(last_k, lds_a_ping, a_load_bytes, tx_i32_base, chunk_i32_a)
833822
b_tile_ping = prefetch_b_tile(last_k)

kernels/fused_rope_cache_kernel.py

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
import flydsl.expr as fx
4141
from flydsl.expr import arith, buffer_ops, const_expr, range_constexpr, vector
4242
from flydsl.expr.arith import ArithValue
43-
from flydsl.expr.typing import T
43+
from flydsl.expr.typing import T, Vector as Vec
4444
from kernels.kernels_common import get_warp_size
4545

4646
# WARP_SIZE is 32 on RDNA (wave32: gfx10xx/gfx11xx/gfx12xx) and 64 on CDNA (wave64: gfx9xx).
@@ -124,6 +124,7 @@ def fused_qk_rope_reshape_and_cache(
124124
tid = fx.thread_idx.x
125125

126126
elem_type = T.bf16 if dtype_str == "bf16" else T.f16
127+
elem_dtype = fx.BFloat16 if dtype_str == "bf16" else fx.Float16
127128

128129
# --- Layout API setup ---
129130
copy_atom = fx.make_copy_atom(fx.rocdl.BufferCopy(copy_bits), elem_bits)
@@ -168,18 +169,18 @@ def ds_bpermute_pair(vec_val, pair_byte_addr):
168169
# Truncate back to i16, bitcast to elem_type, reconstruct vector<1xelem_type>
169170
peer_i16 = ArithValue(peer_i32).trunci(T.i16)
170171
peer_elem = ArithValue(peer_i16).bitcast(elem_type)
171-
return vector.from_elements(T.vec(1, elem_type), [peer_elem])
172+
return Vec.from_elements([peer_elem], elem_dtype)
172173
else:
173174
# VEC_WIDTH>=2: VEC_WIDTH bf16/f16 elements → n_i32 x i32, one ds_bpermute per chunk.
174175
# VEC_WIDTH=2 → n_i32=1 (32 bits); VEC_WIDTH=4 → n_i32=2 (64 bits), etc.
175176
n_i32 = VEC_WIDTH // 2
176-
v_i32 = vector.bitcast(T.vec(n_i32, T.i32), vec_val)
177+
v_i32 = Vec(vec_val).bitcast(fx.Int32)
177178
peer_chunks = []
178179
for ci in range_constexpr(n_i32):
179-
chunk = vector.extract(v_i32, static_position=[ci], dynamic_position=[])
180+
chunk = v_i32[ci]
180181
peer_chunks.append(fx.rocdl.ds_bpermute(T.i32, pair_byte_addr, chunk))
181-
peer_v_i32 = vector.from_elements(T.vec(n_i32, T.i32), peer_chunks)
182-
return vector.bitcast(T.vec(VEC_WIDTH, elem_type), peer_v_i32)
182+
peer_v_i32 = Vec.from_elements(peer_chunks, fx.Int32)
183+
return peer_v_i32.bitcast(elem_dtype)
183184

184185
if tid < vecs_per_head:
185186
# --- Load position (scalar i32) ---
@@ -288,11 +289,13 @@ def ds_bpermute_pair(vec_val, pair_byte_addr):
288289

289290
k_scaled = []
290291
v_scaled = []
292+
k_rot_vec = Vec(k_rot_e.ir_value())
293+
v_vec = Vec(v_e)
291294
for i in range_constexpr(VEC_WIDTH):
292295
# Always use vector.extract; works for VEC_WIDTH=1 (vector<1xbf16>)
293296
# and VEC_WIDTH>1 equally.
294-
ke = ArithValue(vector.extract(k_rot_e.ir_value(), static_position=[i], dynamic_position=[])).extf(T.f32) * k_rcp
295-
ve = ArithValue(vector.extract(v_e, static_position=[i], dynamic_position=[])).extf(T.f32) * v_rcp
297+
ke = k_rot_vec[i].to(fx.Float32) * k_rcp
298+
ve = v_vec[i].to(fx.Float32) * v_rcp
296299
k_scaled.append(ke)
297300
v_scaled.append(ve)
298301

@@ -417,7 +420,7 @@ def pack_fp8(vals):
417420
+ pid_b * x_size
418421
+ sub_o
419422
)
420-
k_elem = vector.extract(k_rot_e.ir_value(), static_position=[vi], dynamic_position=[])
423+
k_elem = Vec(k_rot_e.ir_value())[vi]
421424
buffer_ops.buffer_store(k_elem, kc_rsrc, kc_nf_off)
422425

423426
for vi in range_constexpr(VEC_WIDTH):
@@ -428,7 +431,7 @@ def pack_fp8(vals):
428431
+ d_idx * block_size
429432
+ pid_b
430433
)
431-
v_elem = vector.extract(v_e, static_position=[vi], dynamic_position=[])
434+
v_elem = Vec(v_e)[vi]
432435
buffer_ops.buffer_store(v_elem, vc_rsrc, vc_nf_off)
433436

434437
def _mark_token_layout_dynamic(tensor):

kernels/gemm_fp8fp4_gfx1250.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1243,10 +1243,10 @@ def _l2_prefetch(k_base):
12431243
desc_as_init = make_desc_as(stages_as_mem[0], split_k_base)
12441244
desc_bs_init = make_desc_bs(stages_bs_mem[0], split_k_base)
12451245

1246-
adv_a_i32 = tile_k // PACK_FACTOR_A
1247-
adv_b_i32 = packed_tile_k_b * 16
1248-
adv_as_i32 = tile_k // SCALE_BLOCK * wmma_m_rep
1249-
adv_bs_i32 = tile_k // SCALE_BLOCK * b_scale_load_rep
1246+
adv_a_i32 = fx.Int32(tile_k // PACK_FACTOR_A)
1247+
adv_b_i32 = fx.Int32(packed_tile_k_b * 16)
1248+
adv_as_i32 = fx.Int32(tile_k // SCALE_BLOCK * wmma_m_rep)
1249+
adv_bs_i32 = fx.Int32(tile_k // SCALE_BLOCK * b_scale_load_rep)
12501250

12511251
pred_const = fx.Int32(1)
12521252

kernels/silu_and_mul_fq.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
from flydsl.expr import arith, buffer_ops, const_expr, range_constexpr, rocdl, vector
4545
from flydsl.expr import math as fx_math
4646
from flydsl.expr.arith import ArithValue
47-
from flydsl.expr.typing import T
47+
from flydsl.expr.typing import T, Vector as Vec
4848
from kernels.kernels_common import get_warp_size
4949

5050
BLOCK_THREADS = 256
@@ -356,18 +356,14 @@ def _f32_to_e2m1(qx_f32):
356356
else:
357357
# quant_mode == "none": write bf16 out directly.
358358
# out row stride = inter_dim * 2 bytes.
359-
act_f32_vec = vector.from_elements(vec_f32_ty, act_vals)
360-
act_f32_av = ArithValue(act_f32_vec)
361-
act_bf16_vec = act_f32_av.truncf(T.vec(VEC, T.bf16))
359+
act_bf16_vec = Vec.from_elements(act_vals, fx.Float32).to(fx.BFloat16)
362360
# Write as packed i32 (VEC/2 dwords).
363361
vec_dw = VEC // 2 # each dword = 2 bf16 elems
364362
if const_expr(vec_dw >= 1):
365-
act_i32 = vector.bitcast(T.vec(vec_dw, T.i32), act_bf16_vec)
363+
act_i32 = act_bf16_vec.bitcast(fx.Int32)
366364
bf16_byte_off = in_row * (inter_dim * 2) + col0 * 2
367365
if const_expr(vec_dw == 1):
368-
store_val = vector.extract(
369-
act_i32, static_position=[0], dynamic_position=[]
370-
)
366+
store_val = act_i32[0]
371367
buffer_ops.buffer_store(
372368
store_val,
373369
out_rsrc,

0 commit comments

Comments
 (0)