ProprietaryLegal's picture
PLI Labs public snapshot 2026-10-28 (history squashed)
e1acc15
Raw History Blame Contribute Delete
5.93 kB
"""Original SM86 native-packed W4A16 kernels. No native FP4/FP8 MMA or atomics on results."""
from __future__ import annotations
import triton as tr
import triton.language as tl
@tr.jit
def bf16_decode(code, scale):
# E2M1 magnitude as BF16 fields, then exact exponent adjustment. Integer
# construction also handles scale-0 subnormals; no FTZ multiplication here.
mag = code & 7
exp = tl.where(mag < 2, -1, tl.where(mag < 4, 0, tl.where(mag < 6, 1, 2)))
mant = tl.where((mag == 3) | (mag == 5) | (mag == 7), 64, 0)
biased = exp + scale
normal = (biased << 7) | mant
sub = (128 | mant) >> (1 - biased)
bits = tl.where(biased > 0, normal, sub)
bits = tl.where(biased >= 255, 0x7f80, bits)
bits = tl.where(mag == 0, 0, bits) | ((code & 8) << 12)
bits = tl.where(scale == 255, 0x7fc0, bits)
return bits.to(tl.uint16).to(tl.bfloat16, bitcast=True)
@tr.jit
def decode_kernel(C, S, O, COUNT: tl.constexpr, B: tl.constexpr):
i = tl.program_id(0) * B + tl.arange(0, B)
c = tl.load(C+i, i < COUNT, 0).to(tl.int32)
s = tl.load(S+i, i < COUNT, 127).to(tl.int32)
tl.store(O+i, bf16_decode(c, s), i < COUNT)
@tr.jit
def _weights(W, S, e, k, n, N: tl.constexpr, K: tl.constexpr):
p = tl.load(W + (e * (K//2) + k[:, None]//2) * N + n[None, :],
(k[:, None] < K) & (n[None, :] < N), 0).to(tl.int32)
c = (p >> ((k[:, None] & 1) * 4)) & 15
s = tl.load(S + (e * (K//32) + k[:, None]//32) * N + n[None, :],
(k[:, None] < K) & (n[None, :] < N), 127).to(tl.int32)
return bf16_decode(c, s)
@tr.jit
def linear_kernel(X, IDS, W, S, U, US, O, OU, STATUS,
N: tl.constexpr, K: tl.constexpr, E: tl.constexpr,
TOP: tl.constexpr, PER_SLOT: tl.constexpr,
FUSED: tl.constexpr, MMA: tl.constexpr,
BN: tl.constexpr, BK: tl.constexpr):
route = tl.program_id(1)
expert = tl.load(IDS+route)
valid = (expert >= 0) & (expert < E)
if not valid:
tl.atomic_or(STATUS, 1)
expert = tl.minimum(tl.maximum(expert, 0), E-1)
row = route if PER_SLOT else route // TOP
n = tl.program_id(0)*BN + tl.arange(0, BN)
if MMA:
m = tl.arange(0, 16)
acc = tl.full((16, BN), 0, tl.float32)
if FUSED:
up = tl.full((16, BN), 0, tl.float32)
for start in range(tr.cdiv(K, BK)):
k = start*BK + tl.arange(0, BK)
x = tl.load(X + row*K + k[None, :], (m[:, None] == 0) & (k[None, :] < K), 0)
w = _weights(W, S, expert, k, n, N, K)
acc = tl.dot(x, w, acc, out_dtype=tl.float32)
if FUSED:
u = _weights(U, US, expert, k, n, N, K)
up = tl.dot(x, u, up, out_dtype=tl.float32)
value = tl.sum(tl.where(m[:, None] == 0, acc, 0), axis=0)
if FUSED:
uvalue = tl.sum(tl.where(m[:, None] == 0, up, 0), axis=0)
else:
# One/few row SIMT control: FP32 product/reduction, decoded BF16 values.
# Only BK independent partials persist, rather than the whole matrix.
acc = tl.full((BK, BN), 0, tl.float32)
if FUSED:
up = tl.full((BK, BN), 0, tl.float32)
for start in range(tr.cdiv(K, BK)):
k = start*BK + tl.arange(0, BK)
x = tl.load(X+row*K+k, k < K, 0).to(tl.float32)
w = _weights(W, S, expert, k, n, N, K).to(tl.float32)
acc += x[:, None] * w
if FUSED:
u = _weights(U, US, expert, k, n, N, K).to(tl.float32)
up += x[:, None] * u
value = tl.sum(acc, axis=0)
if FUSED:
uvalue = tl.sum(up, axis=0)
tl.store(O+route*N+n, tl.where(valid, value, float('nan')), n < N)
if FUSED:
tl.store(OU+route*N+n, tl.where(valid, uvalue, float('nan')), n < N)
@tr.jit
def activation_kernel(G, U, R, A, COUNT: tl.constexpr, N: tl.constexpr,
LIMIT: tl.constexpr, B: tl.constexpr):
i = tl.program_id(0)*B + tl.arange(0, B)
# Official linear outputs round to BF16 before clamp/SwiGLU; routing is
# applied before the BF16 down input, not moved through its trained QDQ.
gate = tl.minimum(tl.load(G+i, i < COUNT, 0).to(tl.bfloat16).to(tl.float32), LIMIT)
up = tl.minimum(tl.maximum(tl.load(U+i, i < COUNT, 0).to(tl.bfloat16).to(tl.float32), -LIMIT), LIMIT)
route = tl.load(R+i//N, i < COUNT, 0)
act = gate / (1 + tl.exp(-gate)) * up * route
tl.store(A+i, act.to(tl.bfloat16), i < COUNT)
@tr.jit
def combine_kernel(P, R, O, N: tl.constexpr, TOP: tl.constexpr, B: tl.constexpr):
row = tl.program_id(1)
n = tl.program_id(0)*B + tl.arange(0, B)
total = tl.full((B,), 0, tl.float32)
for slot in tl.static_range(TOP):
weight = tl.load(R+row*TOP+slot)
part = tl.load(P+(row*TOP+slot)*N+n, n < N, 0)
total = total + part * weight
tl.store(O+row*N+n, total, n < N)
@tr.jit
def native_combine_kernel(P, IDS, O, N: tl.constexpr, TOP: tl.constexpr, B: tl.constexpr):
row = tl.program_id(1)
n = tl.program_id(0)*B + tl.arange(0, B)
total = tl.full((B,), 0, tl.float32)
# Official expert-loop order. Stable slot order also handles duplicate IDs
# in diagnostic inputs. TP reduction must already be complete per route.
for order in tl.static_range(TOP):
value = tl.full((B,), 0, tl.float32)
for slot in tl.static_range(TOP):
eid = tl.load(IDS+row*TOP+slot)
rank = tl.full((), 0, tl.int32)
for other in tl.static_range(TOP):
other_id = tl.load(IDS+row*TOP+other)
rank += ((other_id < eid) | ((other_id == eid) & (other < slot))).to(tl.int32)
part = tl.load(P+(row*TOP+slot)*N+n, n < N, 0).to(tl.bfloat16).to(tl.float32)
value = tl.where(rank == order, part, value)
total = total + value
tl.store(O+row*N+n, total, n < N)