Skip to content

Commit 662e248

Browse files
committed
[KernelGen][MThreads] Add square_ Moore Threads specialized operator
1 parent 4350421 commit 662e248

2 files changed

Lines changed: 100 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
@@ -66,6 +66,7 @@
6666
)
6767
from .resolve_conj import resolve_conj
6868
from .sort import sort, sort_stable
69+
from .square_ import square_
6970
from .tile import tile
7071
from .unique import _unique2
7172
from .w8a8_block_fp8_matmul import w8a8_block_fp8_matmul
@@ -143,6 +144,7 @@
143144
"resolve_conj",
144145
"sort",
145146
"sort_stable",
147+
"square_",
146148
"tile",
147149
"_unique2",
148150
"w8a8_block_fp8_matmul",
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
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.square import square_ as default_square_
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+
32+
@libentry()
33+
@triton.autotune(
34+
configs=[
35+
triton.Config({"BLOCK_SIZE": 256}, num_warps=1, num_stages=1),
36+
triton.Config({"BLOCK_SIZE": 1024}, num_warps=2, num_stages=1),
37+
triton.Config({"BLOCK_SIZE": 2048}, num_warps=2, num_stages=1),
38+
triton.Config({"BLOCK_SIZE": 4096}, num_warps=2, num_stages=1),
39+
],
40+
key=["n_elements"],
41+
# Inplace: autotune reruns the kernel on the same buffer, so restore the
42+
# input between trials to avoid squaring repeatedly in place.
43+
restore_value=["x_ptr"],
44+
)
45+
@triton.jit
46+
def square_kernel_full(x_ptr, n_elements, BLOCK_SIZE: tl.constexpr):
47+
pid = tl.program_id(0)
48+
offsets = pid * BLOCK_SIZE + tl.arange(0, BLOCK_SIZE)
49+
x = tl.load(x_ptr + offsets, eviction_policy="evict_first")
50+
tl.store(x_ptr + offsets, x * x, eviction_policy="evict_first")
51+
52+
53+
@libentry()
54+
@triton.autotune(
55+
configs=[
56+
triton.Config({"BLOCK_SIZE": 256}, num_warps=1, num_stages=1),
57+
triton.Config({"BLOCK_SIZE": 1024}, num_warps=2, num_stages=1),
58+
triton.Config({"BLOCK_SIZE": 2048}, num_warps=2, num_stages=1),
59+
triton.Config({"BLOCK_SIZE": 4096}, num_warps=2, num_stages=1),
60+
],
61+
key=["n_elements"],
62+
# Inplace: autotune reruns the kernel on the same buffer, so restore the
63+
# input between trials to avoid squaring repeatedly in place.
64+
restore_value=["x_ptr"],
65+
)
66+
@triton.jit
67+
def square_kernel_masked(x_ptr, n_elements, BLOCK_SIZE: tl.constexpr):
68+
pid = tl.program_id(0)
69+
offsets = pid * BLOCK_SIZE + tl.arange(0, BLOCK_SIZE)
70+
mask = offsets < n_elements
71+
x = tl.load(x_ptr + offsets, mask=mask, eviction_policy="evict_first")
72+
tl.store(x_ptr + offsets, x * x, mask=mask, eviction_policy="evict_first")
73+
74+
75+
def _use_triton_kernel(x: torch.Tensor) -> bool:
76+
if not isinstance(x, torch.Tensor):
77+
return False
78+
if x.device.type != "musa" or x.dtype not in _SUPPORTED_DTYPES:
79+
return False
80+
if not x.is_contiguous() or x.numel() == 0:
81+
return False
82+
return True
83+
84+
85+
def square_(x: torch.Tensor):
86+
logger.debug("GEMS_MTHREADS SQUARE_")
87+
if not _use_triton_kernel(x):
88+
return default_square_(x)
89+
90+
n = x.numel()
91+
with torch_device_fn.device(x.device):
92+
if n % 4096 == 0:
93+
grid = lambda META: (n // META["BLOCK_SIZE"],)
94+
square_kernel_full[grid](x, n)
95+
else:
96+
grid = lambda META: (triton.cdiv(n, META["BLOCK_SIZE"]),)
97+
square_kernel_masked[grid](x, n)
98+
return x

0 commit comments

Comments
 (0)