Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/op/builtin.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ TVM_REGISTER_PASS_CONFIG_OPTION(kDisableVectorize256, Bool);
TVM_REGISTER_PASS_CONFIG_OPTION(kDisableWGMMA, Bool);
TVM_REGISTER_PASS_CONFIG_OPTION(kDisableShuffleElect, Bool);
TVM_REGISTER_PASS_CONFIG_OPTION(kStorageRewriteDetectInplace, Bool);
TVM_REGISTER_PASS_CONFIG_OPTION(kEnableLayoutVisual, Bool);

DataType cuTensorMapType() { return DataType::UInt(8, 128); }

Expand Down
1 change: 1 addition & 0 deletions src/op/builtin.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ static constexpr const char *kDisableWGMMA = "tl.disable_wgmma";
static constexpr const char *kDisableShuffleElect = "tl.disable_shuffle_elect";
static constexpr const char *kStorageRewriteDetectInplace =
"tl.storage_rewrite_detect_inplace";
static constexpr const char *kEnableLayoutVisual = "tl.enable_layout_visual";
/*!
* \brief Whether to disable dynamic tail split
*
Expand Down
1 change: 1 addition & 0 deletions tilelang/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ def _load_tile_lang_lib():
transform, # noqa: F401
language, # noqa: F401
engine, # noqa: F401
tools, # noqa: F401
)
from .autotuner import autotune # noqa: F401
from .transform import PassConfigKey # noqa: F401
Expand Down
4 changes: 4 additions & 0 deletions tilelang/engine/lower.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from tilelang.engine.param import KernelParam, CompiledArtifact
from tilelang.utils.target import determine_target
from tilelang.engine.phase import (
LayoutVisual,
PreLowerSemanticCheck,
LowerAndLegalize,
OptimizeForTarget,
Expand Down Expand Up @@ -249,6 +250,9 @@ def lower(
# Phase 1: Lower and legalize the IR
mod = LowerAndLegalize(mod, target)

# Visualize the layout
LayoutVisual(mod)

# Phase 2: Optimize the IR for the target
mod = OptimizeForTarget(mod, target)

Expand Down
13 changes: 13 additions & 0 deletions tilelang/engine/phase.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,19 @@ def should_force_let_inline(pass_ctx: PassContext | None = None) -> bool:
return bool(pass_ctx and pass_ctx.config.get(tilelang.PassConfigKey.TL_FORCE_LET_INLINE, False))


def should_enable_layout_visual(pass_ctx: PassContext | None = None) -> bool:
if pass_ctx is None:
pass_ctx = tilelang.transform.get_pass_context()
return bool(
pass_ctx and pass_ctx.config.get(tilelang.PassConfigKey.TL_ENABLE_LAYOUT_VISUAL, False))


def LayoutVisual(mod: IRModule) -> None:
"""Apply layout visualization pass if enabled."""
if should_enable_layout_visual():
tilelang.tools.LayoutVisual()(mod)


def PreLowerSemanticCheck(mod: IRModule) -> None:
"""
Check whether the module is valid before lowering. If not, raise a user-friendly error
Expand Down
1 change: 1 addition & 0 deletions tilelang/tools/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
from .plot_layout import plot_layout # noqa: F401
from .Analyzer import *
from .layout_visual import LayoutVisual # noqa: F401
50 changes: 50 additions & 0 deletions tilelang/tools/layout_visual.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import tilelang.language as T
from tvm import tir
from tvm.tir import PyStmtExprVisitor

from tvm.tir.transform import prim_func_pass
from tilelang.tools.plot_layout import plot_layout


def print_layout_format(layout: T.Fragment) -> str:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This only works for fragment layout, I think we should rename it into print_fragment_format and do some type check there.

input_shape = layout.get_input_shape()
output_shape = layout.get_output_shape()
lines = [
f" Shape: {input_shape} -> {output_shape}", f" Thread: {layout.forward_thread}",
f" Index: {layout.forward_index}"
]

return "\n".join(lines)


@tir.functor.visitor
class _LayoutVisualVisitor(PyStmtExprVisitor):

def __init__(self):
super().__init__()
self.layout_found = []
self.processed_layouts = set()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Remove unused layout_found attribute.

The layout_found list is initialized but never used anywhere in the class. Remove it to avoid confusion.

     def __init__(self):
         super().__init__()
-        self.layout_found = []
         self.processed_layouts = set()
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def __init__(self):
super().__init__()
self.layout_found = []
self.processed_layouts = set()
def __init__(self):
super().__init__()
self.processed_layouts = set()
🤖 Prompt for AI Agents
In tilelang/tools/layout_visual.py around lines 23 to 26, the __init__ defines
self.layout_found which is never used; remove that attribute initialization
(delete the self.layout_found = [] line) so only self.processed_layouts = set()
remains, and run tests/lint to ensure no references to layout_found exist
elsewhere.


def visit_block_(self, op: tir.Block) -> None:
if "layout_map" in op.annotations:
layout_map = op.annotations["layout_map"]

for key, layout in layout_map.items():
if isinstance(layout, T.Fragment):
layout_id = str(layout)
if layout_id not in self.processed_layouts:
print(f"{key} layout inference:")
print(print_layout_format(layout))
plot_layout(layout, name=f"{key}_layout")
self.processed_layouts.add(layout_id)

self.visit_stmt(op.body)


def LayoutVisual():

def pass_fn(func: tir.PrimFunc, mod, ctx):
_LayoutVisualVisitor().visit_stmt(func.body)
return func

return prim_func_pass(pass_fn, opt_level=0)
8 changes: 7 additions & 1 deletion tilelang/tools/plot_layout.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import tilelang.language as T


def plot_layout(layout: T.Layout,
def plot_layout(layout: T.Fragment,
save_directory="./tmp",
name: str = "layout",
colormap: str = "RdPu",
Expand Down Expand Up @@ -82,6 +82,12 @@ def plot_layout(layout: T.Layout,
raw_colors = [cmap(i) for i in range(num_threads)]
colors = raw_colors.copy()

# Show the distribution of registers in each thread of a warp.
warp_size = 32
spectral_camp = plt.get_cmap("hsv", warp_size * 6)
for i in range(warp_size):
colors[i] = spectral_camp(i * 6)
Comment on lines +88 to +101

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Guard warp coloring when thread count < warp size

The new warp-aware coloring loop assumes at least 32 threads, but colors is sized to num_threads; when a layout has fewer than 32 threads (common for small tiles), iterating for i in range(warp_size) writes past the end of the list and raises IndexError, so visualization fails before any plots are saved.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


Comment thread
LeiWang1999 marked this conversation as resolved.
# Determine the number of rows and columns in the input shape
nrows, ncols = input_shape
# Adjust figure size to maintain square cells
Expand Down
3 changes: 3 additions & 0 deletions tilelang/transform/pass_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ class PassConfigKey(str, Enum):
TL_FORCE_LET_INLINE = "tl.force_let_inline"
"""Force TileLang to inline let bindings during simplification. Default: False"""

TL_ENABLE_LAYOUT_VISUAL = "tl.enable_layout_visual"
"""Enable layout inference visualization. Default: False"""

TL_STORAGE_REWRITE_DETECT_INPLACE = "tl.storage_rewrite_detect_inplace"
"""Control StorageRewrite inplace detection.

Expand Down
Loading