Skip to content

Commit 1e93074

Browse files
committed
[KernelGen][MThreads] Add rad2deg_ Moore Threads specialized operator
1 parent b44d2fd commit 1e93074

2 files changed

Lines changed: 104 additions & 0 deletions

File tree

src/flag_gems/runtime/backend/_mthreads/ops/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
from .pad import constant_pad_nd
7070
from .permute_copy import permute_copy
7171
from .prod import prod, prod_dim
72+
from .rad2deg_ import rad2deg_
7273
from .rand import rand
7374
from .rand_like import rand_like
7475
from .randn import randn
@@ -166,6 +167,7 @@
166167
"permute_copy",
167168
"prod",
168169
"prod_dim",
170+
"rad2deg_",
169171
"rand",
170172
"rand_like",
171173
"randn",
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
# Copyright 2026 FlagOS Contributors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import logging
16+
17+
import torch
18+
import triton
19+
import triton.language as tl
20+
21+
from flag_gems.ops.rad2deg import rad2deg_ as default_rad2deg_
22+
from flag_gems.runtime import torch_device_fn
23+
from flag_gems.utils import libentry
24+
25+
logger = logging.getLogger(
26+
f'flag_gems.runtime.backend._mthreads.ops.{__name__.split(".")[-1]}'
27+
)
28+
29+
_SUPPORTED_DTYPES = {torch.float16, torch.bfloat16, torch.float32}
30+
31+
# 180 / pi as used by torch's rad2deg
32+
RAD2DEG = tl.constexpr(57.29577951308232)
33+
34+
# Above this many elements, streaming out-of-place beats in-place on S5000
35+
# (working set far exceeds L2; separate write stream avoids read/write aliasing).
36+
HUGE_THRESHOLD = 1 << 27
37+
38+
39+
@libentry()
40+
@triton.jit
41+
def rad2deg_inplace_kernel(
42+
x_ptr, n_elements, BLOCK_SIZE: tl.constexpr, VEC: tl.constexpr, EVEN: tl.constexpr
43+
):
44+
pid = tl.program_id(0)
45+
base = pid * (BLOCK_SIZE * VEC)
46+
for i in tl.static_range(VEC):
47+
offsets = base + i * BLOCK_SIZE + tl.arange(0, BLOCK_SIZE)
48+
if EVEN:
49+
x = tl.load(x_ptr + offsets)
50+
tl.store(x_ptr + offsets, x * RAD2DEG)
51+
else:
52+
mask = offsets < n_elements
53+
x = tl.load(x_ptr + offsets, mask=mask)
54+
tl.store(x_ptr + offsets, x * RAD2DEG, mask=mask)
55+
56+
57+
@libentry()
58+
@triton.jit
59+
def rad2deg_oop_kernel(x_ptr, out_ptr, n_elements, BLOCK_SIZE: tl.constexpr):
60+
pid = tl.program_id(0)
61+
offsets = pid * BLOCK_SIZE + tl.arange(0, BLOCK_SIZE)
62+
mask = offsets < n_elements
63+
x = tl.load(x_ptr + offsets, mask=mask, eviction_policy="evict_first")
64+
tl.store(out_ptr + offsets, x * RAD2DEG, mask=mask, eviction_policy="evict_first")
65+
66+
67+
def _use_triton_kernel(x: torch.Tensor) -> bool:
68+
if not isinstance(x, torch.Tensor):
69+
return False
70+
if x.device.type != "musa" or x.dtype not in _SUPPORTED_DTYPES:
71+
return False
72+
if not x.is_contiguous() or x.numel() == 0:
73+
return False
74+
return True
75+
76+
77+
def rad2deg_(x):
78+
logger.debug("GEMS_MTHREADS RAD2DEG_")
79+
if not _use_triton_kernel(x):
80+
return default_rad2deg_(x)
81+
82+
n = x.numel()
83+
with torch_device_fn.device(x.device):
84+
if n >= HUGE_THRESHOLD:
85+
out = torch.empty_like(x)
86+
grid = (triton.cdiv(n, 2048),)
87+
rad2deg_oop_kernel[grid](x, out, n, BLOCK_SIZE=2048, num_warps=4)
88+
return out
89+
# dtype-tuned vectorization (matches deg2rad_): fp16 uses wider VEC.
90+
if x.dtype == torch.float16:
91+
vec, block = 4, 1024
92+
else:
93+
vec, block = 2, 1024
94+
grid = (triton.cdiv(n, block * vec),)
95+
even = (n % (block * vec)) == 0
96+
rad2deg_inplace_kernel[grid](
97+
x, n, BLOCK_SIZE=block, VEC=vec, EVEN=even, num_warps=4
98+
)
99+
return x
100+
101+
102+
__all__ = ["rad2deg_"]

0 commit comments

Comments
 (0)