Skip to content

Commit daadf4f

Browse files
committed
[KernelGen][MThreads] Add arctan_ Moore Threads specialized operator
1 parent 4350421 commit daadf4f

2 files changed

Lines changed: 106 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
@@ -18,6 +18,7 @@
1818
from .amax import amax
1919
from .any import any, any_dim, any_dims
2020
from .arange import arange, arange_start
21+
from .arctan_ import arctan_
2122
from .argmin import argmin
2223
from .batch_norm import batch_norm, batch_norm_backward
2324
from .bucketize import bucketize
@@ -82,6 +83,7 @@
8283
"any_dims",
8384
"arange",
8485
"arange_start",
86+
"arctan_",
8587
"argmin",
8688
"batch_norm",
8789
"batch_norm_backward",
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
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.arctan_ import arctan_ as default_arctan_
22+
from flag_gems.runtime import torch_device_fn
23+
from flag_gems.utils import libentry, tl_extra_shim
24+
25+
logger = logging.getLogger(
26+
f'flag_gems.runtime.backend._mthreads.ops.{__name__.split(".")[-1]}'
27+
)
28+
29+
_atan = tl_extra_shim.atan
30+
31+
_SUPPORTED_DTYPES = {torch.float16, torch.bfloat16, torch.float32}
32+
33+
# Above this many elements, streaming out-of-place beats in-place on S5000
34+
# (working set far exceeds L2; separate write stream avoids read/write aliasing).
35+
HUGE_THRESHOLD = 1 << 27
36+
37+
38+
@libentry()
39+
@triton.jit
40+
def arctan_inplace_kernel(
41+
x_ptr, n_elements, BLOCK_SIZE: tl.constexpr, VEC: tl.constexpr, EVEN: tl.constexpr
42+
):
43+
pid = tl.program_id(0)
44+
base = pid * (BLOCK_SIZE * VEC)
45+
for i in tl.static_range(VEC):
46+
offsets = base + i * BLOCK_SIZE + tl.arange(0, BLOCK_SIZE)
47+
if EVEN:
48+
x = tl.load(x_ptr + offsets)
49+
y = _atan(x.to(tl.float32)).to(x_ptr.dtype.element_ty)
50+
tl.store(x_ptr + offsets, y)
51+
else:
52+
mask = offsets < n_elements
53+
x = tl.load(x_ptr + offsets, mask=mask)
54+
y = _atan(x.to(tl.float32)).to(x_ptr.dtype.element_ty)
55+
tl.store(x_ptr + offsets, y, mask=mask)
56+
57+
58+
@libentry()
59+
@triton.jit
60+
def arctan_oop_kernel(x_ptr, out_ptr, n_elements, BLOCK_SIZE: tl.constexpr):
61+
pid = tl.program_id(0)
62+
offsets = pid * BLOCK_SIZE + tl.arange(0, BLOCK_SIZE)
63+
mask = offsets < n_elements
64+
x = tl.load(x_ptr + offsets, mask=mask, eviction_policy="evict_first")
65+
y = _atan(x.to(tl.float32)).to(x_ptr.dtype.element_ty)
66+
tl.store(out_ptr + offsets, y, mask=mask, eviction_policy="evict_first")
67+
68+
69+
def _use_triton_kernel(x: torch.Tensor) -> bool:
70+
if not isinstance(x, torch.Tensor):
71+
return False
72+
if x.device.type != "musa" or x.dtype not in _SUPPORTED_DTYPES:
73+
return False
74+
if not x.is_contiguous() or x.numel() == 0:
75+
return False
76+
return True
77+
78+
79+
def arctan_(x):
80+
logger.debug("GEMS_MTHREADS ARCTAN_")
81+
if not _use_triton_kernel(x):
82+
return default_arctan_(x)
83+
84+
n = x.numel()
85+
with torch_device_fn.device(x.device):
86+
if n >= HUGE_THRESHOLD:
87+
out = torch.empty_like(x)
88+
grid = (triton.cdiv(n, 2048),)
89+
arctan_oop_kernel[grid](x, out, n, BLOCK_SIZE=2048, num_warps=4)
90+
return out
91+
# dtype-tuned vectorization: fp16 uses wider VEC.
92+
if x.dtype == torch.float16:
93+
vec, block = 4, 1024
94+
else:
95+
vec, block = 2, 1024
96+
grid = (triton.cdiv(n, block * vec),)
97+
even = (n % (block * vec)) == 0
98+
arctan_inplace_kernel[grid](
99+
x, n, BLOCK_SIZE=block, VEC=vec, EVEN=even, num_warps=4
100+
)
101+
return x
102+
103+
104+
__all__ = ["arctan_"]

0 commit comments

Comments
 (0)