Skip to content

[Feat] Allow print macro call stack in device assert#1616

Merged
LeiWang1999 merged 6 commits intotile-ai:mainfrom
kurisu6912:device-assert
Jan 7, 2026
Merged

[Feat] Allow print macro call stack in device assert#1616
LeiWang1999 merged 6 commits intotile-ai:mainfrom
kurisu6912:device-assert

Conversation

@kurisu6912
Copy link
Collaborator

@kurisu6912 kurisu6912 commented Jan 6, 2026

as title.

Summary by CodeRabbit

  • New Features

    • Option to include or omit stack/location details in device assertion messages for clearer error output.
    • Generated closures now carry per-file, per-line and macro context to improve debugging traces and error locations.
    • Macro-level tracking with APIs to record and retrieve caller file/line/macro context for richer diagnostics.
  • Chores

    • Updated third-party submodule reference.

✏️ Tip: You can customize this high-level summary in your review settings.

@github-actions
Copy link

github-actions bot commented Jan 6, 2026

👋 Hi! Thank you for contributing to the TileLang project.

Please remember to run pre-commit run --all-files in the root directory of the project to ensure your changes are properly linted and formatted. This will help ensure your contribution passes the format check.

We appreciate you taking this step! Our team will review your contribution, and we look forward to your awesome work! 🚀

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 6, 2026

📝 Walkthrough

Walkthrough

Adds per-file/line span tracking and propagation through macros and generated closures (Builder fields and APIs, DSLMutator filename propagation, SpanAttacher injection); modifies device_assert signature to optionally suppress stack info; updates TVM submodule pointer.

Changes

Cohort / File(s) Summary
Submodule update
3rdparty/tvm
Updated TVM submodule ref from dcfe86eb...001022bd... (pointer-only change).
Device assertion / print ops
tilelang/language/print_op.py
Imported Builder, added get_stack_str() helper; signature changed to device_assert(condition, msg="", no_stack_info=False) and branching to include or omit stack/fileline info under CUDA guards.
DSL AST mutation & span injection
tilelang/language/v2/ast.py
DSLMutator.__init__ now accepts filename (uses Path(filename).name); added SpanAttacher AST transformer to inject per-statement __tb.set_fileline(...); updated closure generation to bind/propagate __tb_fl/__tb_fn and use local function name.
Builder fileline & macro stack
tilelang/language/v2/builder.py
Added current_file, current_line, current_macro_name, macro_fileline_stack; implemented set_fileline(...), get_fileline_stack(...), and push/pop of macro fileline frames around macro entry/exit.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Caller as Macro Caller
    participant Builder as Builder
    participant DSL as DSLMutator / SpanAttacher
    participant Closure as Generated Closure
    participant Device as tl (CUDA)

    rect rgb(245,250,255)
    Caller->>Builder: enter macro (file,line,name) / set_fileline
    Builder->>Builder: push (file,line,name) onto macro_fileline_stack
    Builder->>DSL: mutate AST (pass filename)
    DSL->>Closure: inject per-statement __tb.set_fileline(__tb_fl,__tb_fn,...)
    Builder->>Caller: return closure with __tb_fl / __tb_fn bound
    end

    rect rgb(245,255,245)
    Closure->>Device: device_assert(condition, msg, no_stack_info)
    alt no_stack_info == False
        Device->>Device: call device_assert_with_msg(get_stack_str(...))
    else no_stack_info == True
        Device->>Device: call device_assert or device_assert_with_msg(msg) depending on msg
    end
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 I hop through stacks and mark each line,
I tuck file, line, macro into span and sign,
SpanAttacher paints traces where statements run,
Builder stacks the path so each macro's known,
Tiny paws, tidy traces — hop, report, done!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 17.65% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main feature: allowing print macro call stack information to be displayed in device assert, which aligns with the core changes across all modified files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI Agents
In @tilelang/language/print_op.py:
- Around line 127-132: get_stack_str can raise AttributeError when
Builder.current() returns None; modify get_stack_str to first retrieve builder =
Builder.current(), and if builder is None return the original msg (or msg +
newline) without attempting to call get_fileline_stack; otherwise call
builder.get_fileline_stack(stacklevel) and proceed as before—refer to the
get_stack_str function and Builder.current() to locate where to add this None
check and early-return behavior.
🧹 Nitpick comments (3)
tilelang/language/v2/ast.py (1)

582-591: Consider using iterable unpacking for cleaner concatenation.

The static analysis tool suggests using iterable unpacking instead of list concatenation. This is a minor stylistic improvement.

🔎 Suggested refactor
     def visit(self, node: ast.AST):
         node = self.generic_visit(node)
         if isinstance(node, ast.stmt):
-            return quote(f"__tb.set_fileline({self.filename_var}, {node.lineno}, {self.func_name_var})") + [node]
+            return [*quote(f"__tb.set_fileline({self.filename_var}, {node.lineno}, {self.func_name_var})"), node]
         return node
tilelang/language/v2/builder.py (2)

695-697: Consider using iterable unpacking for cleaner concatenation.

Per static analysis suggestion, the list concatenation could use iterable unpacking for consistency with Python best practices.

🔎 Suggested refactor
     def get_fileline_stack(self, stacklevel=1):
-        stack = self.macro_fileline_stack + [(self.current_file, self.current_line, self.current_macro_name)]
+        stack = [*self.macro_fileline_stack, (self.current_file, self.current_line, self.current_macro_name)]
         return stack[: len(stack) - stacklevel + 1]

699-704: Remove commented-out code.

The get_fileline_stack_msg helper is commented out. If it's not needed, it should be removed to keep the codebase clean. If it's intended for future use, consider implementing it properly or tracking it in an issue.

🔎 Suggested removal
-    # def get_fileline_stack_msg(self, stacklevel=1):
-    #     stack = self.get_fileline_stack(stacklevel)
-    #     msg = ''
-    #     for filename, lineno, macro_name in stack:
-    #         msg += f'{filename}:{lineno} {macro_name}\n'
-    #     return msg
-
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9d446f3 and a480402.

📒 Files selected for processing (4)
  • 3rdparty/tvm
  • tilelang/language/print_op.py
  • tilelang/language/v2/ast.py
  • tilelang/language/v2/builder.py
🧰 Additional context used
🧬 Code graph analysis (2)
tilelang/language/v2/builder.py (2)
tilelang/language/kernel.py (1)
  • pop (38-45)
tilelang/language/frame.py (1)
  • pop (36-50)
tilelang/language/print_op.py (1)
tilelang/language/v2/builder.py (5)
  • current (182-184)
  • get_fileline_stack (695-697)
  • macro (197-224)
  • macro (752-788)
  • get (226-227)
🪛 Ruff (0.14.10)
tilelang/language/v2/builder.py

696-696: Consider iterable unpacking instead of concatenation

Replace with iterable unpacking

(RUF005)

tilelang/language/v2/ast.py

590-590: Consider iterable unpacking instead of concatenation

Replace with iterable unpacking

(RUF005)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Test for Python 3.12 with Metal (on macos-latest)
🔇 Additional comments (7)
3rdparty/tvm (1)

1-1: This is a submodule version update for TVM; no action required on the code review side. The tilelang implementation files referenced in the AI summary already exist in the repository and were modified in prior commits supporting this feature. This PR only bumps the TVM submodule reference to enable the "allow device assert print macro call stack" functionality.

Likely an incorrect or invalid review comment.

tilelang/language/v2/ast.py (2)

474-486: LGTM! File/line context injection for debugging.

The changes correctly capture the function name and inject per-statement file/line tracking via SpanAttacher. The generated closure properly initializes __tb_fl and __tb_fn variables that are referenced by the injected set_fileline calls.


648-648: LGTM!

Using Path(filename).name to extract just the base filename is appropriate for stack traces, keeping error messages concise and avoiding exposure of full filesystem paths.

tilelang/language/print_op.py (1)

136-150: LGTM! The no_stack_info parameter provides flexibility.

The implementation correctly:

  • Defaults to including stack info for better debugging
  • Allows users to opt-out with no_stack_info=True when performance is critical
  • Emits a warning about potential slowdown when using messages without stack info
tilelang/language/v2/builder.py (3)

175-179: LGTM! Proper initialization of file/line tracking state.

The new fields are properly initialized with sensible defaults ("<unknown>" for file/macro, 0 for line, empty list for stack).


219-223: Stack management looks correct, but consider exception safety.

The push/pop of macro_fileline_stack is balanced within the context manager. However, if an exception is raised during macro execution (between yield at line 221 and pop() at line 223), the stack won't be popped. This might leave stale entries in the stack.

Since this is primarily for debugging/error messages and exceptions typically unwind the entire builder context anyway, this may be acceptable. Consider if this needs a try/finally for robustness.


690-693: LGTM!

The set_fileline method is a straightforward setter that updates the current file/line/macro context, called before each statement during macro execution.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI Agents
In @tilelang/language/v2/ast.py:
- Around line 479-480: The generated f-strings embedding filename/name in ast.py
(the lines that set __tb_fl and __tb_fn) can break if self.filename or name
contain quotes/backslashes; change the code generation to embed a safely-escaped
Python literal (use repr(self.filename) and repr(name) or an equivalent escaping
helper) instead of raw f"'{...}'" so the produced source is always valid and
safe; update the code that emits "__tb_fl" and "__tb_fn" accordingly
(references: the AST code path that writes __tb_fl = ... and __tb_fn = ...).
- Line 648: The code passes Path(filename).name to DSLMutator which strips
directory context and produces ambiguous filenames in user-visible stack
messages; change the argument so DSLMutator receives a disambiguating path
(e.g., the relative path from the repo root or the absolute path) instead of
just the basename: locate the DSLMutator construction (DSLMutator(nonlocals,
func.__globals__, Path(filename).name)) and replace the third parameter with a
path that preserves directories (for example Path(filename).as_posix() or a
relative path computed from Path.cwd() or the project root) so get_stack_str()
shows a full/relative path like tilelang/language/v2/utils.py rather than just
utils.py.
🧹 Nitpick comments (1)
tilelang/language/v2/ast.py (1)

582-591: Consider using iterable unpacking for cleaner code.

The concatenation quote(...) + [node] works correctly but can be more idiomatically expressed using iterable unpacking.

🔎 Proposed refactor using iterable unpacking
 class SpanAttacher(ast.NodeTransformer):
     def __init__(self, filename_var: str, func_name_var: str):
         self.filename_var = filename_var
         self.func_name_var = func_name_var

     def visit(self, node: ast.AST):
         node = self.generic_visit(node)
         if isinstance(node, ast.stmt) and hasattr(node, 'lineno'):
-            return quote(f"__tb.set_fileline({self.filename_var}, {node.lineno}, {self.func_name_var})") + [node]
+            return [*quote(f"__tb.set_fileline({self.filename_var}, {node.lineno}, {self.func_name_var})"), node]
         return node

Based on static analysis hints from Ruff.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a480402 and 584a1b4.

📒 Files selected for processing (1)
  • tilelang/language/v2/ast.py
🧰 Additional context used
🪛 Ruff (0.14.10)
tilelang/language/v2/ast.py

590-590: Consider iterable unpacking instead of concatenation

Replace with iterable unpacking

(RUF005)

🔇 Additional comments (3)
tilelang/language/v2/ast.py (3)

4-4: LGTM!

The Path import is correctly added to support filename extraction at line 648.


253-253: LGTM!

The filename parameter is correctly added and stored for later use in generating file-level tracking context.

Also applies to: 258-258


475-475: The set_fileline method is already defined in the Builder class (line 690 in tilelang/language/v2/builder.py) with the correct signature: def set_fileline(self, filename: str, lineno: int, name: str). Since Builder extends BaseBuilder, the method is accessible to the generated code at line 475 of ast.py that calls __tb.set_fileline(...) through the SpanAttacher.

Likely an incorrect or invalid review comment.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
tilelang/language/v2/ast.py (1)

582-592: Consider iterable unpacking for cleaner syntax.

The SpanAttacher class correctly instruments statements with span tracking. However, line 590 uses list concatenation where iterable unpacking would be more idiomatic.

🔎 Proposed refactor using iterable unpacking
     def visit(self, node: ast.AST):
         node = self.generic_visit(node)
         if isinstance(node, ast.stmt) and hasattr(node, "lineno"):
-            return quote(f"__tb.set_fileline({self.filename_var}, {node.lineno}, {self.func_name_var})") + [node]
+            return [*quote(f"__tb.set_fileline({self.filename_var}, {node.lineno}, {self.func_name_var})"), node]
         return node

Based on static analysis hints.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 584a1b4 and 801858f.

📒 Files selected for processing (1)
  • tilelang/language/v2/ast.py
🧰 Additional context used
🪛 Ruff (0.14.10)
tilelang/language/v2/ast.py

590-590: Consider iterable unpacking instead of concatenation

Replace with iterable unpacking

(RUF005)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Test for Python 3.12 with Metal (on macos-latest)
  • GitHub Check: Test for Python 3.12 with Nightly-ROCm-7.1 (on self-hosted-amd)
  • GitHub Check: Test for Python 3.12 with CUDA-12.8 (on self-hosted-nvidia)
🔇 Additional comments (3)
tilelang/language/v2/ast.py (3)

4-4: LGTM!

The import additions are appropriate: Path is used for filename handling at line 648, and the ParamSpec compatibility layer follows standard patterns for Python 3.9 support.

Also applies to: 11-13


253-258: LGTM!

The addition of the filename parameter to DSLMutator.__init__ correctly enables per-file tracking for stack traces in device assertions.


474-475: LGTM!

Capturing the function name locally before applying SpanAttacher is correct, as the AST transformation might modify node properties. The SpanAttacher application properly instruments the function body with per-statement span tracking.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
tilelang/language/v2/builder.py (2)

690-692: Consider adding parameter validation and documentation.

The method works correctly for typical usage, but could be more robust:

  1. The stacklevel parameter lacks documentation explaining its behavior (how many frames to trim from the top).
  2. No validation for edge cases (e.g., stacklevel <= 0 or stacklevel > len(stack)).
  3. Static analysis suggests using iterable unpacking instead of list concatenation for better performance.
🔎 Optional improvements
 def get_fileline_stack(self, stacklevel=1):
+    """Get the file/line call stack up to the specified level.
+    
+    Args:
+        stacklevel: Number of frames to include from bottom (1 = all frames).
+    
+    Returns:
+        List of (filename, lineno, macro_name) tuples representing the call stack.
+    """
-    stack = self.macro_fileline_stack + [(self.current_file, self.current_line, self.current_macro_name)]
+    stack = [*self.macro_fileline_stack, (self.current_file, self.current_line, self.current_macro_name)]
     return stack[: len(stack) - stacklevel + 1]

694-699: Consider removing commented-out code.

The commented-out get_fileline_stack_msg method adds maintenance overhead. If this functionality is needed, consider either:

  1. Implementing and documenting it as an active method
  2. Removing it entirely to keep the codebase clean

If it's temporarily kept for reference during development, consider adding a TODO comment explaining when it will be removed or activated.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2de0132 and 16a18b2.

📒 Files selected for processing (1)
  • tilelang/language/v2/builder.py
🧰 Additional context used
🧬 Code graph analysis (1)
tilelang/language/v2/builder.py (2)
tilelang/language/kernel.py (1)
  • pop (38-45)
tilelang/language/frame.py (1)
  • pop (36-50)
🪛 Ruff (0.14.10)
tilelang/language/v2/builder.py

691-691: Consider iterable unpacking instead of concatenation

Replace with iterable unpacking

(RUF005)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Test for Python 3.12 with Metal (on macos-latest)
🔇 Additional comments (4)
tilelang/language/v2/builder.py (4)

176-180: LGTM! Initialization of file/line tracking fields.

The new fields are properly initialized with sensible defaults, and the comment clearly explains the purpose of the stack.


220-220: LGTM! Macro call stack tracking.

The push operation correctly records the caller's file/line/macro context before entering a macro frame. This integrates well with the contextmanager pattern to ensure balanced stack operations.


224-224: LGTM! Stack cleanup on macro exit.

The pop operation properly restores the call stack when exiting a macro frame.


685-688: LGTM! Simple setter for file/line context.

The method correctly updates the current file/line/macro tracking fields.

Removed commented-out method get_fileline_stack_msg from builder.py.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
tilelang/language/v2/builder.py (2)

690-692: Consider adding bounds validation for the stacklevel parameter.

If stacklevel exceeds len(stack), the slicing could return an empty list or unexpectedly truncated results. Consider adding validation to ensure stacklevel is within reasonable bounds (e.g., 1 <= stacklevel <= len(stack)), or document the expected behavior for out-of-range values.

🛡️ Proposed bounds checking
 def get_fileline_stack(self, stacklevel=1):
     stack = self.macro_fileline_stack + [(self.current_file, self.current_line, self.current_macro_name)]
+    if stacklevel < 1:
+        stacklevel = 1
+    if stacklevel > len(stack):
+        stacklevel = len(stack)
     return stack[: len(stack) - stacklevel + 1]

691-691: Consider iterable unpacking for clearer intent.

As suggested by static analysis, you could use iterable unpacking instead of list concatenation for slightly better performance and clarity.

♻️ Proposed refactor using iterable unpacking
-    stack = self.macro_fileline_stack + [(self.current_file, self.current_line, self.current_macro_name)]
+    stack = [*self.macro_fileline_stack, (self.current_file, self.current_line, self.current_macro_name)]
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 16a18b2 and 867661a.

📒 Files selected for processing (1)
  • tilelang/language/v2/builder.py
🧰 Additional context used
🧬 Code graph analysis (1)
tilelang/language/v2/builder.py (2)
tilelang/language/kernel.py (1)
  • pop (38-45)
tilelang/language/frame.py (1)
  • pop (36-50)
🪛 Ruff (0.14.10)
tilelang/language/v2/builder.py

691-691: Consider iterable unpacking instead of concatenation

Replace with iterable unpacking

(RUF005)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Test for Python 3.12 with Metal (on macos-latest)
🔇 Additional comments (3)
tilelang/language/v2/builder.py (3)

176-180: LGTM! Clear initialization of macro call stack tracking fields.

The new fields support tracking file/line/macro context through macro expansion. The default values are appropriate sentinel values, and the comment on line 179 helpfully clarifies that the stack tracks caller context.


220-224: LGTM! Exception-safe push/pop pattern for macro call stack tracking.

The @contextmanager decorator ensures line 224 executes even if exceptions occur within the macro body, maintaining stack consistency. The balanced push before entry (line 220) and pop after exit (line 224) correctly tracks the macro invocation context.


685-688: LGTM! Simple and clear setter for tracking current location context.

@LeiWang1999 LeiWang1999 merged commit aca9218 into tile-ai:main Jan 7, 2026
5 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants