@@ -53,47 +53,64 @@ def _can_use_triton_kernel(x: torch.Tensor) -> bool:
5353def _flip_block_kernel (
5454 x_ptr ,
5555 out_ptr ,
56+ shape_ptr ,
57+ strides_ptr ,
58+ flip_mask_ptr ,
5659 inner_size ,
5760 outer_size ,
58- x_outer_stride ,
59- x_inner_stride ,
61+ split : tl .constexpr ,
6062 BLOCK_SIZE : tl .constexpr ,
6163):
62- """Flip kernel for case where innermost dims are NOT flipped .
64+ """Flip kernel with correct multi-dimensional indexing .
6365
6466 Each program processes multiple blocks (grid-stride loop).
6567 Each block has inner_size contiguous elements.
66- The outer index is mapped: output block i -> source block (outer_size - 1 - i) .
68+ The block_id is decoded to multi-dim indices, each dim independently flipped if needed .
6769
6870 Args:
6971 x_ptr: source tensor data pointer
7072 out_ptr: output tensor data pointer
71- inner_size: number of contiguous elements per block (non-flipped trailing dims)
72- outer_size: number of blocks (product of flipped leading dims)
73- x_outer_stride: stride in source between consecutive blocks (positive)
74- x_inner_stride: stride within a source block (should be 1 for contiguous)
73+ shape_ptr: shape of the leading dims [0:split]
74+ strides_ptr: strides of the leading dims [0:split]
75+ flip_mask_ptr: boolean mask indicating which dims to flip [0:split]
76+ inner_size: number of contiguous elements per block (trailing non-flipped dims)
77+ outer_size: number of blocks (product of leading dims)
78+ split: number of leading dimensions
7579 BLOCK_SIZE: tile size for processing inner elements
7680 """
7781 pid = tl .program_id (0 )
7882 num_programs = tl .num_programs (0 )
7983
8084 # Grid-stride loop over outer blocks
8185 for block_id in range (pid , outer_size , num_programs ):
82- # Map output block id to source block id (reverse for flip)
83- src_block_id = outer_size - 1 - block_id
86+ # Decode block_id to multi-dimensional index and compute source offset
87+ # Row-major layout: decode from the last dimension backwards
88+ remaining = block_id
89+ src_offset = 0
90+
91+ for dim in range (split - 1 , - 1 , - 1 ):
92+ dim_size = tl .load (shape_ptr + dim )
93+ dim_stride = tl .load (strides_ptr + dim )
94+ flip_dim = tl .load (flip_mask_ptr + dim )
95+
96+ # Extract index for this dimension (in output layout)
97+ idx = remaining % dim_size
98+ remaining = remaining // dim_size
99+
100+ # Apply flip if needed for this dimension
101+ src_idx = tl .where (flip_dim , dim_size - 1 - idx , idx )
102+
103+ # Accumulate source offset
104+ src_offset += src_idx * dim_stride
84105
85- # Compute base offsets
86- src_base = src_block_id * x_outer_stride
87106 dst_base = block_id * inner_size
88107
89108 # Process inner elements in tiles
90109 offsets = tl .arange (0 , BLOCK_SIZE )
91110 for inner_start in range (0 , inner_size , BLOCK_SIZE ):
92111 idx = inner_start + offsets
93112 mask = idx < inner_size
94- # Read from source (coalesced since x_inner_stride is 1)
95- val = tl .load (x_ptr + src_base + idx * x_inner_stride , mask = mask , other = 0.0 )
96- # Write to output (coalesced, contiguous)
113+ val = tl .load (x_ptr + src_offset + idx , mask = mask , other = 0.0 )
97114 tl .store (
98115 out_ptr + dst_base + idx , val .to (out_ptr .dtype .element_ty ), mask = mask
99116 )
@@ -160,15 +177,17 @@ def flip(x: torch.Tensor, dims) -> torch.Tensor:
160177 for i in range (split , ndim ):
161178 inner_size *= shape [i ]
162179
163- # Outer size = product of leading dims (all flipped)
180+ # Outer size = product of leading dims
164181 outer_size = 1
165182 for i in range (0 , split ):
166183 outer_size *= shape [i ]
167184
168- # x_outer_stride = stride for the innermost flipped dimension
169- # For contiguous tensors, this equals inner_size
170- x_outer_stride = strides [split - 1 ] if split > 0 else inner_size
171- x_inner_stride = 1 # contiguous inner block
185+ # Prepare shape, strides, and flip_mask for leading dims
186+ leading_shape = torch .tensor (shape [:split ], dtype = torch .int32 , device = x .device )
187+ leading_strides = torch .tensor (strides [:split ], dtype = torch .int32 , device = x .device )
188+ leading_flip_mask = torch .tensor (
189+ [i in flip_set for i in range (split )], dtype = torch .bool , device = x .device
190+ )
172191
173192 out = torch .empty_like (x )
174193
@@ -180,9 +199,11 @@ def flip(x: torch.Tensor, dims) -> torch.Tensor:
180199 _flip_block_kernel [grid ](
181200 x ,
182201 out ,
202+ leading_shape ,
203+ leading_strides ,
204+ leading_flip_mask ,
183205 inner_size ,
184206 outer_size ,
185- x_outer_stride ,
186- x_inner_stride ,
207+ split ,
187208 )
188209 return out
0 commit comments