"""Native compact-index repair loops; offline packed weight CSR tiles. All repairs use the same outer factors as the dense base, permitting one FP32 accumulator. Residual W storage is only the selected N128/K_B tiles. """ import torch,triton import triton.language as tl from .linear import _pack @triton.jit def gemm(AC,AS,WC,WS,WG,AG,AI,AM,WR,WRS,WI,OFF,Y, M:tl.constexpr,N:tl.constexpr,K:tl.constexpr,MP:tl.constexpr, NA:tl.constexpr,HASW:tl.constexpr,CROSS:tl.constexpr,B:tl.constexpr,BM:tl.constexpr,INTERLEAVE:tl.constexpr,SPLIT_K:tl.constexpr=1,DENSE_W:tl.constexpr=False,WLOC=None,SHARED_BANK:tl.constexpr=False): mi=tl.program_id(0)*BM+tl.arange(0,BM);nb=tl.program_id(1);ni=nb*128+tl.arange(0,128) dk=tl.arange(0,B//2);ds=tl.arange(0,B//16);acc=tl.full((BM,128),0,tl.float32) part=tl.program_id(2) if SPLIT_K==1:begin_k=0;end_k=K//B else:begin_k=part*tl.cdiv(K//B,SPLIT_K);end_k=tl.minimum((part+1)*tl.cdiv(K//B,SPLIT_K),K//B) for kb in range(begin_k,end_k): ai=mi[:,None]*(K//2)+kb*(B//2)+dk[None,:];asi=mi[:,None]*(K//16)+kb*(B//16)+ds[None,:] wi=ni[:,None]*(K//2)+kb*(B//2)+dk[None,:];wsi=ni[:,None]*(K//16)+kb*(B//16)+ds[None,:] a=tl.load(AC+ai,mi[:,None]0): if NA==K//B:selected=True else:selected=tl.load(AM+(tl.program_id(0)*BM//128)*(K//B)+kb) if selected: a=tl.load(AC+MP*(K//2)+ai,mi[:,None]0 and NA=begin_k and kb=begin_k and kb0: selected=tl.load(AM+(tl.program_id(0)*BM//128)*(K//B)+kb) if selected: a=tl.load(AC+MP*(K//2)+ai,mi[:,None]0,self.na==self.k//self.b,self.union) def run_packed(self,x,packed): ac,sc,ag,mp=packed;m=x.shape[0] out=torch.empty((m,self.n),device=x.device,dtype=x.dtype) parts=out if self.split_k==1 else torch.empty((self.split_k,m,self.n),device=x.device,dtype=torch.float32) gemm[(triton.cdiv(m,self.bm),self.n//128,self.split_k)](ac,sc,self.wc,self.ws,self.wg,ag,self.ai,self.am,self.wr,self.wrs,self.wi,self.off,parts,m,self.n,self.k,mp,self.na,self.hasw,self.cross,self.b,self.bm,self.interleave,self.split_k,self.dense_w,WLOC=self.wloc,SHARED_BANK=self.shared_bank,num_warps=self.num_warps,num_stages=self.num_stages) if self.split_k>1: reduce_split_k[(triton.cdiv(m*self.n,512),)](parts,out,self.wg,ag,m*self.n,self.split_k,512,num_warps=4) return out def __call__(self,x): if x.ndim!=2 or x.shape[1]!=self.k or x.shape[0]<=0 or triton.cdiv(x.shape[0],128)!=self.am.shape[0]: raise ValueError("activation shape must match the prepared M128 support and K") if x.dtype!=torch.bfloat16 or x.device!=self.wc.device or not x.is_contiguous(): raise ValueError("expected contiguous BF16 activation on the packed-weight device") return self.run_packed(x,self.pack(x)) @property def residual_weight_bytes(self):return sum(t.numel()*t.element_size() for t in [self.wr,self.wrs,self.wi,self.off]) if self.hasw else 0