Skip to content

Commit 03a087e

Browse files
[TLE][AMD] Add AMD local pointers lowering
Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent baa2240 commit 03a087e

4 files changed

Lines changed: 90 additions & 10 deletions

File tree

python/test/tle/unit/test_tle_cumsum.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,6 @@ def _is_hcu_backend():
2727
threads_per_warp = get_current_target().warp_size if is_hip() else 32
2828

2929

30-
def _is_amd_hip_backend():
31-
return is_hip() and not FLAGTREE_BACKEND
32-
33-
3430
def _require_cuda():
3531
try:
3632
if _is_enflame_backend():
@@ -280,7 +276,6 @@ def test_tle_cumsum_amdgcn_fastpath_regression_guard():
280276
"Detected predicated ds_write: possible regression to generic path"
281277

282278

283-
@pytest.mark.skipif(_is_amd_hip_backend(), reason="requires AMD local-pointer lowering")
284279
def test_tle_cumsum_helper_preserves_adjacent_sentinel():
285280
block = 512
286281
num_warps = block // threads_per_warp
@@ -302,7 +297,6 @@ def test_tle_cumsum_helper_preserves_adjacent_sentinel():
302297
torch.testing.assert_close(sentinel, expected_sentinel)
303298

304299

305-
@pytest.mark.skipif(_is_amd_hip_backend(), reason="requires AMD local-pointer lowering")
306300
def test_tle_cumsum_scalar_base_addptr_alias_regression():
307301
block = 512
308302
num_warps = block // threads_per_warp
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// Copyright 2025- FlagOS Contributors
2+
//
3+
// Permission is hereby granted, free of charge, to any person obtaining
4+
// a copy of this software and associated documentation files
5+
// (the "Software"), to deal in the Software without restriction,
6+
// including without limitation the rights to use, copy, modify, merge,
7+
// publish, distribute, sublicense, and/or sell copies of the Software,
8+
// and to permit persons to whom the Software is furnished to do so,
9+
// subject to the following conditions:
10+
//
11+
// The above copyright notice and this permission notice shall be
12+
// included in all copies or substantial portions of the Software.
13+
//
14+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15+
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16+
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17+
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18+
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19+
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20+
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21+
22+
// RUN: triton-opt %s -split-input-file --allocate-amdgpu-shared-memory --convert-triton-amdgpu-to-llvm=arch=gfx1201 --convert-builtin-func-to-llvm | FileCheck %s
23+
24+
#blocked = #ttg.blocked<{sizePerThread = [1], threadsPerWarp = [32], warpsPerCTA = [1], order = [0]}>
25+
#shared = #ttg.swizzled_shared<{vec = 1, perPhase = 1, maxPhase = 1, order = [0]}>
26+
#smem = #ttg.shared_memory
27+
28+
module attributes {"ttg.num-ctas" = 1 : i32, "ttg.num-warps" = 1 : i32, ttg.target = "hip:gfx1201", "ttg.threads-per-warp" = 32 : i32} {
29+
// CHECK-LABEL: llvm.func @local_pointers_tensor_index
30+
// The lowered pointers must stay in the shared address space and be reached
31+
// through plain GEPs, with no NVVM op leaking into the AMD path.
32+
// CHECK: llvm.mlir.addressof @global_smem : !llvm.ptr<3>
33+
// CHECK: llvm.getelementptr {{.*}}!llvm.ptr<3>
34+
// CHECK: llvm.load {{.*}}!llvm.ptr<3>
35+
// CHECK: llvm.store {{.*}}!llvm.ptr<3>
36+
// CHECK-NOT: tle.local_pointers
37+
// CHECK-NOT: nvvm.
38+
tt.func public @local_pointers_tensor_index(%idx: tensor<32xi32, #blocked>) {
39+
%buf = ttg.local_alloc : () -> !ttg.memdesc<32xf32, #shared, #smem, mutable>
40+
%ptrs = "tle.local_pointers"(%buf, %idx) : (!ttg.memdesc<32xf32, #shared, #smem, mutable>, tensor<32xi32, #blocked>) -> tensor<32x!tt.ptr<f32, 3>, #blocked>
41+
%val = tt.load %ptrs : tensor<32x!tt.ptr<f32, 3>, #blocked>
42+
tt.store %ptrs, %val : tensor<32x!tt.ptr<f32, 3>, #blocked>
43+
tt.return
44+
}
45+
}
46+
47+
// -----
48+
49+
#blocked = #ttg.blocked<{sizePerThread = [1], threadsPerWarp = [32], warpsPerCTA = [1], order = [0]}>
50+
#shared = #ttg.swizzled_shared<{vec = 1, perPhase = 1, maxPhase = 1, order = [0]}>
51+
#smem = #ttg.shared_memory
52+
53+
module attributes {"ttg.num-ctas" = 1 : i32, "ttg.num-warps" = 1 : i32, ttg.target = "hip:gfx1201", "ttg.threads-per-warp" = 32 : i32} {
54+
// A scalar base pointer broadcast over a tensor of offsets must not be
55+
// rewritten into buffer ops, which can only address global memory.
56+
// CHECK-LABEL: llvm.func @local_pointers_scalar_index
57+
// CHECK: llvm.getelementptr {{.*}}!llvm.ptr<3>
58+
// CHECK-NOT: tle.local_pointers
59+
// CHECK-NOT: amdg.buffer_
60+
tt.func public @local_pointers_scalar_index(%idx: i32) {
61+
%buf = ttg.local_alloc : () -> !ttg.memdesc<32xf32, #shared, #smem, mutable>
62+
%ptr = "tle.local_pointers"(%buf, %idx) : (!ttg.memdesc<32xf32, #shared, #smem, mutable>, i32) -> !tt.ptr<f32, 3>
63+
%splat = tt.splat %ptr : !tt.ptr<f32, 3> -> tensor<32x!tt.ptr<f32, 3>, #blocked>
64+
%offs = tt.make_range {end = 32 : i32, start = 0 : i32} : tensor<32xi32, #blocked>
65+
%ptrs = tt.addptr %splat, %offs : tensor<32x!tt.ptr<f32, 3>, #blocked>, tensor<32xi32, #blocked>
66+
%val = tt.load %ptrs : tensor<32x!tt.ptr<f32, 3>, #blocked>
67+
tt.store %ptrs, %val : tensor<32x!tt.ptr<f32, 3>, #blocked>
68+
tt.return
69+
}
70+
}

third_party/amd/backend/compiler.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
from triton.backends.compiler import BaseBackend, GPUTarget, Language
22
from triton._C.libtriton import ir, passes, llvm, amd
3+
4+
try:
5+
from triton._C.libtriton import tle
6+
except ImportError:
7+
tle = None
38
from triton import knobs
49
from dataclasses import dataclass
510
from typing import Any, Dict, Tuple
@@ -216,6 +221,14 @@ def make_ttgir(mod, metadata, options):
216221
passes.ttgpuir.add_f32_dot_tc(pm, emuTF32)
217222
passes.ttgpuir.add_remove_layout_conversions(pm)
218223
passes.ttgpuir.add_optimize_thread_locality(pm)
224+
if tle is not None:
225+
# Assigns the shared encodings and inserts the barriers that
226+
# tle.local_pointers lowering relies on. The order is load-bearing.
227+
tle.passes.add_early_assign_memory_space(pm)
228+
tle.passes.add_select_encodings(pm)
229+
tle.passes.add_insert_local_pointer_barriers(pm)
230+
tle.passes.add_optimize_local_pointer_loads(pm)
231+
tle.passes.add_optimize_local_pointer_stores(pm)
219232
amd.passes.ttgpuir.add_accelerate_matmul(pm, options.arch, options.matrix_instr_nonkdim, options.kpack)
220233
passes.ttgpuir.add_remove_layout_conversions(pm)
221234
amd.passes.ttgpuir.add_optimize_epilogue(pm)

third_party/amd/lib/TritonAMDGPUToLLVM/TritonGPUToLLVM.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
#ifdef __TLE__
3131
#include "tle/dialect/include/Conversion/TleToLLVM/ExclusiveCumsumOpToLLVM.h"
32+
#include "tle/dialect/include/Conversion/TleToLLVM/LocalPointersOpToLLVM.h"
3233
#include "tle/dialect/include/IR/Dialect.h"
3334
#include "tle/dialect/include/Transforms/PatternTleToLLVM.h"
3435
#endif
@@ -198,13 +199,15 @@ struct ConvertTritonAMDGPUToLLVM
198199
int AMDBenefit = commonBenefit + 1;
199200

200201
#ifdef __TLE__
201-
// Lower the supported tile-level extension (TLE) ops (extract_tile /
202-
// insert_tile / exclusive_cumsum) via the backend-agnostic conversion
203-
// patterns. The dedicated partial conversion rejects unsupported TLE ops
204-
// and accidental NVVM emission.
202+
// Lower the supported tile-level extension (TLE) ops (local_pointers /
203+
// extract_tile / insert_tile / exclusive_cumsum) via the backend-agnostic
204+
// conversion patterns. The dedicated partial conversion rejects
205+
// unsupported TLE ops and accidental NVVM emission.
205206
{
206207
TleLLVMConversionTarget tleTarget(*context);
207208
RewritePatternSet tlePatterns(context);
209+
mlir::triton::tle::populateLocalPointersOpToLLVMPatterns(
210+
typeConverter, targetInfo, tlePatterns, commonBenefit);
208211
mlir::triton::tle::populateExtractTileOpToLLVMPatterns(
209212
typeConverter, tlePatterns, targetInfo, commonBenefit);
210213
mlir::triton::tle::populateInsertTileOpToLLVMPatterns(

0 commit comments

Comments
 (0)