Pass Diff¶

Pass Diff shows how TileLang’s TIR changes as compiler passes run. It captures the IR before and after each pass, computes a unified diff, and writes the result to the terminal, an interactive HTML report, or both.

Use the environment-variable workflow to observe the complete lowering pipeline without modifying a program. Use the Python API when you want to apply and inspect a specific pass sequence.

Observe the Lowering Pipeline¶

Set TILELANG_PASS_DIFF before starting the Python process:

# Print colored diffs while passes run.
TILELANG_PASS_DIFF=terminal python my_script.py

# Write an HTML report.
TILELANG_PASS_DIFF=html python my_script.py

# Print terminal diffs and write an HTML report.
TILELANG_PASS_DIFF=both python my_script.py

TileLang reads this setting when tilelang is imported and installs a process- wide hook around TVM pass execution. Setting the variable after importing TileLang does not enable the hook for that process.

Variable

Accepted values

Default

TILELANG_PASS_DIFF

terminal, html, both; 1, true, yes, and on also select terminal output

0 (disabled)

TILELANG_PASS_DIFF_OUTPUT

Directory for pipeline HTML reports

tmp/pass_diff_output

False-like values (0, false, no, off, or an empty string) disable the hook. An unrecognized nonempty value falls back to terminal output.

HTML reports use a timestamped filename such as pass_diff_20260710_153000.html. The report is refreshed after each pass so a partial result is available even during a long compilation, then finalized at process exit.

Pass Diff HTML report showing TIR before and after a compiler pass

Pass Diff HTML report.¶

The HTML viewer provides side-by-side before and after source, collapsible pass sections, expandable unchanged context, copy controls, light and dark themes, and aggregate insertion and deletion counts.

Note

The pipeline hook wraps tvm.ir.transform.Pass.__call__ for the entire process, so it observes TVM passes outside the immediate tilelang.compile() call as well. Capturing IR and, in HTML mode, rewriting the report after every pass adds debugging overhead. Leave the feature disabled for normal builds and benchmarks.

Compare Selected Passes¶

The pass_diff Python API accepts a PrimFunc or IRModule and applies the provided passes in order:

import tilelang
from tilelang import tvm
from tilelang.utils.pass_diff import pass_diff

steps = pass_diff(
    func,
    [
        ("AnnotateDeviceRegions", tvm.tirx.transform.AnnotateDeviceRegions()),
        ("SplitHostDevice", tvm.tirx.transform.SplitHostDevice()),
        ("ThreadSync", tilelang.transform.ThreadSync("shared")),
    ],
    mode="both",
    context=5,
    html_path="tmp/selected_passes.html",
)

A single unnamed pass is also accepted:

steps = pass_diff(func, tilelang.transform.ThreadSync("shared"))

Parameter

Description

Default

func_or_mod

Starting PrimFunc or IRModule; a PrimFunc is wrapped as main

Required

passes

One pass, a list of passes, or a list of (name, pass) pairs

Required

mode

terminal, html, or both

terminal

context

Unchanged context lines included around each diff hunk

3

html_path

Output file used by html and both modes

pass_diff_report.html

The return value contains one dictionary per pass with these fields:

Field

Meaning

name

Explicit step name, or a name derived from the pass type

before_script

Complete TIR script before the pass

after_script

Complete TIR script after the pass

diff_lines

Unified diff as a list of strings

insertions

Number of added lines

deletions

Number of removed lines

changed

Whether the pass changed the rendered TIR

For example, a test can assert that a transformation introduced an expected intrinsic:

steps = pass_diff(func, tilelang.transform.ThreadSync("shared"))
assert steps[0]["changed"]
assert "tvm_storage_sync" in steps[0]["after_script"]

Do not enable the process-wide TILELANG_PASS_DIFF hook when using the programmatic API unless you intentionally want both layers of reporting. The API invokes each pass normally, so the global hook would capture those same invocations again.

Choosing an Output Mode¶

  • Use terminal for a small number of passes and immediate feedback.

  • Use html when a lowering pipeline produces many changes or you need to compare complete before and after scripts.

  • Use both when iterating interactively but retaining a shareable report.

  • Increase context only for the programmatic API; the process-wide hook uses three context lines.

Pass Diff compares the textual form returned by IRModule.script(). A textual change is useful evidence about a pass, but it does not by itself establish a semantic or performance change.