Skip to content

Commit 43ee940

Browse files
authored
[KernelGen][MThreads] Add mish Moore Threads specialized operator (#116)
1 parent 7455d1d commit 43ee940

2 files changed

Lines changed: 116 additions & 0 deletions

File tree

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
)
4040
from .max import max, max_dim
4141
from .min import min, min_dim
42+
from .mish import mish, mish_
4243
from .mode import mode
4344
from .normal import normal_
4445
from .one_hot import one_hot
@@ -109,6 +110,8 @@
109110
"max_dim",
110111
"min",
111112
"min_dim",
113+
"mish",
114+
"mish_",
112115
"mode",
113116
"normal_",
114117
"one_hot",
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
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+
from typing import Tuple
17+
18+
import torch
19+
import triton
20+
import triton.language as tl
21+
22+
from flag_gems.ops.mish import mish as default_mish
23+
from flag_gems.ops.mish import mish_ as default_mish_
24+
from flag_gems.runtime import torch_device_fn
25+
from flag_gems.utils import libentry, tl_extra_shim
26+
27+
logger = logging.getLogger(
28+
f'flag_gems.runtime.backend._mthreads.ops.{__name__.split(".")[-1]}'
29+
)
30+
31+
_SUPPORTED_DTYPES = {torch.float16, torch.bfloat16, torch.float32}
32+
33+
exp = tl_extra_shim.exp
34+
log = tl_extra_shim.log
35+
fast_tanh = tl_extra_shim.fast_tanh
36+
37+
38+
@libentry()
39+
@triton.autotune(
40+
configs=[
41+
triton.Config({"BLOCK_SIZE": 256, "VEC": 4}, num_warps=4, num_stages=1),
42+
triton.Config({"BLOCK_SIZE": 256, "VEC": 2}, num_warps=4, num_stages=1),
43+
triton.Config({"BLOCK_SIZE": 512, "VEC": 2}, num_warps=8, num_stages=1),
44+
triton.Config({"BLOCK_SIZE": 512, "VEC": 4}, num_warps=8, num_stages=1),
45+
triton.Config({"BLOCK_SIZE": 1024, "VEC": 1}, num_warps=4, num_stages=2),
46+
triton.Config({"BLOCK_SIZE": 1024, "VEC": 2}, num_warps=8, num_stages=2),
47+
triton.Config({"BLOCK_SIZE": 2048, "VEC": 4}, num_warps=8, num_stages=2),
48+
triton.Config({"BLOCK_SIZE": 4096, "VEC": 1}, num_warps=8, num_stages=2),
49+
triton.Config({"BLOCK_SIZE": 4096, "VEC": 2}, num_warps=16, num_stages=2),
50+
],
51+
key=["n_elements", "dtype_size"],
52+
)
53+
@triton.jit
54+
def mish_kernel(
55+
x_ptr,
56+
out_ptr,
57+
n_elements,
58+
dtype_size, # used for autotune key
59+
BLOCK_SIZE: tl.constexpr,
60+
VEC: tl.constexpr,
61+
):
62+
pid = tl.program_id(0)
63+
BLOCK_ELEMS: tl.constexpr = BLOCK_SIZE * VEC
64+
offsets = (pid * BLOCK_ELEMS + tl.arange(0, BLOCK_ELEMS)).to(tl.int64)
65+
mask = offsets < n_elements
66+
x = tl.load(x_ptr + offsets, mask=mask)
67+
68+
# mish(x) = x * tanh(softplus(x)) = x * tanh(ln(1 + e^x))
69+
# compute in fp32 (mthreads has no fp64); tails are stable since for
70+
# large |x| mish -> x (pos) or 0 (neg) and tanh saturates accordingly.
71+
x_fp32 = x.to(tl.float32)
72+
out = (x_fp32 * fast_tanh(log(1.0 + exp(x_fp32)))).to(x.dtype)
73+
74+
tl.store(out_ptr + offsets, out, mask=mask)
75+
76+
77+
def _use_triton_kernel(x: torch.Tensor) -> Tuple[bool, int]:
78+
if not isinstance(x, torch.Tensor):
79+
return False, 0
80+
if x.device.type != "musa" or x.dtype not in _SUPPORTED_DTYPES:
81+
return False, 0
82+
if x.numel() == 0 or not x.is_contiguous():
83+
return False, 0
84+
return True, x.element_size()
85+
86+
87+
def _launch_mish(x: torch.Tensor, out: torch.Tensor, dtype_size: int):
88+
x_flat = x.view(-1)
89+
out_flat = out.view(-1)
90+
n_elements = out_flat.numel()
91+
grid = lambda META: (triton.cdiv(n_elements, META["BLOCK_SIZE"] * META["VEC"]),)
92+
with torch_device_fn.device(out.device):
93+
mish_kernel[grid](x_flat, out_flat, n_elements, dtype_size)
94+
return out
95+
96+
97+
def mish(A):
98+
logger.debug("GEMS_MTHREADS MISH")
99+
use_triton, dtype_size = _use_triton_kernel(A)
100+
if not use_triton:
101+
return default_mish(A)
102+
103+
out = torch.empty_like(A)
104+
return _launch_mish(A, out, dtype_size)
105+
106+
107+
def mish_(A):
108+
logger.debug("GEMS_MTHREADS MISH_")
109+
use_triton, dtype_size = _use_triton_kernel(A)
110+
if not use_triton:
111+
return default_mish_(A)
112+
113+
return _launch_mish(A, A, dtype_size)

0 commit comments

Comments
 (0)