Skip to content

Commit ad873c2

Browse files
committed
Add SSA compiler pipeline and unified backends
1 parent ef4c528 commit ad873c2

27 files changed

Lines changed: 11982 additions & 9 deletions

.gitignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,3 +160,12 @@ cython_debug/
160160
# and can be added to the global gitignore or merged into this file. For a more nuclear
161161
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
162162
#.idea/
163+
164+
# Local/generated compiler validation artifacts.
165+
reports/
166+
outputs/
167+
tmp_*/
168+
remote_*/
169+
remote_scripts/
170+
compiler-skills/
171+
ninetoothed.skill/

docs/design/README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# NineToothed Compiler Design Notes
2+
3+
This directory contains the design documents that should accompany the compiler implementation changes. Keep generated benchmark logs, large backend artifacts, and exploratory reports out of the main repository history.
4+
5+
## Recommended Reading Order
6+
7+
1. `ir_design_zh.md`
8+
- Overall IR motivation, expressiveness, extensibility, and current scope.
9+
2. `ssa_ir_lowering_pipeline_zh.md`
10+
- Source-to-SSA lowering layers and target-annotated SSA flow.
11+
3. `ssa_pass_registry_pipeline_zh.md`
12+
- Pass registry, default pipeline, backend-specific optimization pass organization.
13+
4. `multi_backend_ir.md`
14+
- Earlier multi-backend design context and compatibility notes.
15+
16+
## Repository Boundary
17+
18+
The main `ninetoothed` repository should keep:
19+
20+
- compiler source code under `src/`
21+
- tests under `tests/`
22+
- reusable validation scripts under `scripts/`
23+
- concise design documents under `docs/design/`
24+
25+
Generated reports and backend artifacts should remain local validation output unless a specific report is intentionally selected for a release note or PR discussion.
26+
27+
AI/Codex workflow skills are maintained separately in the `ninetoothed.skill` repository.

docs/design/ir_design_zh.md

Lines changed: 541 additions & 0 deletions
Large diffs are not rendered by default.

docs/design/multi_backend_ir.md

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# NineToothed Multi-Backend IR Design
2+
3+
## Objectives
4+
5+
NineToothed currently exposes a tensor-oriented metaprogramming DSL and lowers it to Triton. The target backend programming languages are now:
6+
7+
- Triton: keep the current production path and use it as the correctness baseline.
8+
- CUDA: add native CUDA source generation while preserving the current AOT CUDA launcher path.
9+
- TileLang: add a TileLang path for tile-level scheduling experiments.
10+
- TVM: add a TensorIR/TVMScript path for a widely used tensor compiler stack.
11+
12+
SGLang is intentionally excluded from this backend list because it is an inference engine, not a kernel programming language target.
13+
14+
## IR Stack
15+
16+
The design should remain multi-level instead of forcing all targets through one flat IR:
17+
18+
- TOM Graph IR: tensor arrangement history, shapes, strides, jagged metadata, dtypes, constexpr values, and symbolic constraints.
19+
- Program IR: loads, stores, pointer/index expressions, masks, arithmetic, dot, reductions, math intrinsics, helper calls, and function boundaries.
20+
- Schedule IR: grid/block decomposition, thread/warp mapping, memory scopes, vectorization, unrolling, pipelining, and target capabilities.
21+
- Target IR: backend-specific syntax, ABI metadata, runtime dispatch metadata, and compiler flags.
22+
23+
## First Implementation Slice
24+
25+
The current implementation slice adds a compact `KernelIR` bridge:
26+
27+
- `TensorTypeIR` records public tensor parameter metadata.
28+
- `LaunchIR` records launch function name, launch args, and grid text.
29+
- `KernelIR` records canonical source, entrypoint, launch metadata, compiler options, and extensible metadata.
30+
- Backend lowerers consume `KernelIR` and return `BackendArtifact`.
31+
32+
This bridge does not replace the Triton generator yet. It creates a stable backend contract while the production Triton path remains untouched.
33+
34+
## Backend Status
35+
36+
| Backend | Current Status | Execution Status |
37+
| --- | --- | --- |
38+
| Triton | Existing production path plus artifact lowerer | Executable |
39+
| CUDA | Emits `.cu` manifest and ABI shell; existing `caller="cuda"` AOT remains the only executable CUDA path | Native source shell is not executable |
40+
| TileLang | Emits TileLang Python module shell and metadata | Not executable |
41+
| TVM | Emits TVMScript module shell and metadata | Not executable |
42+
43+
## API Direction
44+
45+
```python
46+
artifact = ninetoothed.lower(arrangement, application, tensors, backend="triton")
47+
cuda_artifact = ninetoothed.lower(arrangement, application, tensors, backend="cuda")
48+
tilelang_artifact = ninetoothed.lower(arrangement, application, tensors, backend="tilelang")
49+
tvm_artifact = ninetoothed.lower(arrangement, application, tensors, backend="tvm")
50+
```
51+
52+
Existing `make`, `jit`, and `aot` calls should keep working. New backend selection should remain explicit until native CUDA, TileLang, and TVM lowering are feature complete enough to pass the full correctness gates.
53+
54+
## Lowering Roadmap
55+
56+
1. Keep the bridge IR and backend registry in place.
57+
2. Extract TOM Graph IR from `Tensor` arrangement history instead of reflecting only generated source.
58+
3. Split semantic lowering from Triton rendering.
59+
4. Add Program IR statement and expression nodes for loads, stores, masks, arithmetic, dot, reductions, and intrinsics.
60+
5. Re-render Triton from Program IR and prove parity with the existing generator.
61+
6. Implement native CUDA rendering for elementwise, reductions, and matmul-style tiled dot.
62+
7. Implement TileLang rendering for elementwise, reductions, and matmul-style tiled dot.
63+
8. Implement TVM TensorIR rendering for elementwise, reductions, and matmul-style tiled dot.
64+
9. Add target capability descriptions for AscendC, BangC, and similar vendor languages.
65+
66+
## Validation Plan
67+
68+
The acceptance gate is intentionally strict:
69+
70+
- All existing NineToothed tests pass.
71+
- All `ntops` tests pass.
72+
- All runnable `ntops.lab` operators pass.
73+
- Backend artifact audit passes for Triton, CUDA, TileLang, and TVM.
74+
- Executable backend artifacts compile and run.
75+
- Outputs match existing PyTorch/reference checks.
76+
77+
Until CUDA, TileLang, and TVM emit real executable target code, backend compatibility must be reported as incomplete.
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
# 九齿 SSA IR Lowering Pipeline 设计
2+
3+
## 目标
4+
5+
九齿的核心 IR 不应把一个完整算子表示成一个粗粒度节点。前端看到的是 Python/NineToothed 计算过程,IR 应抽象其中的控制流、数据流、访存、规约、矩阵原语和数学函数,然后通过 pass 逐步加入 schedule、memory scope 和后端 intrinsic 信息,最后生成 Triton、CUDA、TileLang、TVM 等后端语言。
6+
7+
因此 canonical IR 的基本单元是:
8+
9+
- `arith.*`:标量/张量表达式。
10+
- `math.*``exp/log/sqrt/rsqrt` 等数学函数。
11+
- `reduce.*``sum/max/min` 等规约。
12+
- `linalg.*``dot/matmul/transpose` 等细粒度线性代数原语。
13+
- `scf.*`:循环、条件、yield 等控制流 region。
14+
- `mem.*`:load/store、memory effect。
15+
- `index.*``shape.*`:形状和索引计算。
16+
17+
`AttentionOpIR``FlashAttentionOpIR` 这类节点只能作为历史兼容层或 pattern 名称出现,不能成为 canonical SSA 的表达粒度。以 `tests/test_attention.py` 中的参考实现为例,canonical SSA 是 `scf.for + linalg.dot + reduce.max/reduce.sum + math.exp2 + select.where + mem.store`,不是一个 attention 节点。
18+
19+
## IR 分层
20+
21+
1. Frontend AST/Tensor Semantics
22+
23+
输入是 NineToothed 的 arrangement/application 或已有结构化 ProgramIR。此阶段只负责理解用户代码与张量元信息。
24+
25+
2. Generic SSA
26+
27+
语义层 IR,保持后端无关。它描述计算发生了什么,不描述 CUDA block、Triton program、TileLang fragment 或 TVM thread binding。
28+
29+
3. Canonical SSA
30+
31+
通过 `ssa.canonicalize` 规范化 opcode、metadata 和 region 结构,为后续分析 pass 提供稳定输入。
32+
33+
4. Analyzed SSA
34+
35+
`ssa.analyze_effects` 统计 store、reduction、loop、dot、online-softmax-shape 等事实。这里仍不做后端决策。
36+
37+
5. Scheduled SSA
38+
39+
`ssa.select_schedule` 根据后端和分析事实加入 schedule annotation,例如 elementwise grid、parallel reduction、blocked linalg、online-softmax-dot。此阶段开始出现 tile size、vector width、threads、num_warps/num_stages 等策略,但仍保持为 IR metadata。
40+
41+
6. Target-Annotated SSA
42+
43+
`ssa.lower_memory_scopes``ssa.lower_backend_intrinsics` 将抽象 schedule 映射到目标后端:
44+
45+
- Triton:`tl.program_id``tl.load/tl.store``tl.dot`、Triton tensor/register 表达。
46+
- CUDA:`blockIdx/threadIdx`、thread-local register、`__shared__``__expf/expf`、后续 `mma.sync` 候选。
47+
- TileLang:`T.Kernel``T.get_thread_binding``local.fragment/shared/global``T.gemm/T.dot` 候选。
48+
- TVM:`T.thread_binding``T.alloc_buffer(scope="local/shared")`、tensorize intrinsic 候选。
49+
50+
7. Backend Source
51+
52+
后端 emitter 读取 target-annotated SSA 和历史 ProgramIR 信息,生成目标语言源码。当前 CUDA/TileLang/TVM 的结构化算子 emitter 已能接收带 pass trace 的 SSA;Triton 普通算子仍可复用历史 Triton source path,但同样生成 SSA 审计信息。
53+
54+
## 可表达性
55+
56+
SSA 的表达能力来自三个方面:
57+
58+
- 数据流:每个 operation 显式列出 operands/results,支持 CSE、DCE、fusion、layout rewrite。
59+
- 控制流:`scf.for/scf.if` 通过 region 表达循环和条件,loop-carried state 通过 block args 和 `scf.yield` 表示,能覆盖 online softmax、rowwise normalize、scan-like 更新。
60+
- memory effect:`mem.store` 与 future `mem.load/alloc` 明确建模 side effect,便于在 schedule pass 中决定 coalescing、shared memory staging、local scratch placement。
61+
62+
这足以覆盖当前已验证的:
63+
64+
- elementwise/fill/copy。
65+
- 1D reduction、axis reduction、rowwise softmax/layernorm 类融合。
66+
- transpose、matmul。
67+
- `tests/test_attention.py` 形式的 flash attention reference lowering。
68+
69+
## 可扩展性
70+
71+
新增后端时不需要改前端 IR,只需增加:
72+
73+
1. 目标 backend enum/registry。
74+
2. backend-specific schedule policy。
75+
3. memory scope mapping。
76+
4. intrinsic mapping。
77+
5. source emitter。
78+
79+
新增优化 pass 时应满足:
80+
81+
- 输入输出仍是 SSAProgramIR。
82+
- pass 只处理细粒度 opcode,不按完整算子名改写。
83+
- 若识别 pattern,也只能作为 schedule 选择依据,而不是替换成粗粒度语义节点。
84+
85+
## 当前实现状态
86+
87+
已新增 `ninetoothed.ssa_passes`
88+
89+
```text
90+
ssa.canonicalize
91+
ssa.analyze_effects
92+
ssa.select_schedule
93+
ssa.lower_memory_scopes
94+
ssa.lower_backend_intrinsics
95+
```
96+
97+
公共 `ninetoothed.lowering.lower` 和直接 `ninetoothed.backends.lower(KernelIR, backend=...)` 都会运行该 pipeline。`BackendArtifact.metadata` 会带出:
98+
99+
- `ssa_pass_trace`
100+
- `ssa_schedule`
101+
- `ssa_metadata`
102+
- `kernel_metadata`
103+
104+
## 后续优化方向
105+
106+
- Triton 普通算子 emitter 从历史 source passthrough 逐步迁移到 SSA source emission。
107+
- CUDA matmul/attention 引入 shared memory tile、warp-level reduction、`mma.sync` tensorization pass。
108+
- TileLang 引入 `T.gemm`/block fragment schedule,而不是 correctness-first scalar loops。
109+
- TVM 引入 schedule rule/tensorize rule,生成标准 host wrapper 的环境兼容路径。
110+
- 为 pass 增加 cost model/autotune metadata,并把测得性能反馈回 schedule selection。
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
# 九齿 SSA Pass 注册器与优化遍执行流程
2+
3+
本文档描述当前九齿 SSA lowering 中的标准编译器式 pass 执行逻辑。目标是把优化遍从固定函数调用整理为可注册、可分类、可配置、可自动选择的 pipeline,为后续更多优化和自动调优留出接口。
4+
5+
## 设计目标
6+
7+
1. Pass 粒度保持在 SSA 计算、访存、控制和 schedule annotation 层,不引入 `AttentionOpIR` 之类粗粒度算子节点。
8+
2. 优化遍按硬件无关和硬件相关分层执行。
9+
3. 硬件相关优化可以按后端拆分,例如 `ssa.triton.optimize_schedule``ssa.cuda.optimize_schedule`
10+
4. 默认 pipeline 可以覆盖当前 Triton/CUDA/TileLang/TVM 后端。
11+
5. 用户或 autotune 系统可以通过 declarative spec 替换 pass 序列和 pass 参数。
12+
13+
## Pass 分类
14+
15+
当前 pass registry 中的分类如下:
16+
17+
| 分类 | 作用 | 当前 pass |
18+
| --- | --- | --- |
19+
| `hardware_independent` | 不依赖后端,负责规范化和语义分析 | `ssa.canonicalize``ssa.analyze_effects` |
20+
| `hardware_dependent` | 依赖后端能力,但多个后端共享同一 pass 框架 | `ssa.select_schedule``ssa.lower_memory_scopes``ssa.lower_backend_intrinsics` |
21+
| `backend_specific` | 后端专属优化策略 | `ssa.triton.optimize_schedule``ssa.cuda.optimize_schedule``ssa.tilelang.optimize_schedule``ssa.tvm.optimize_schedule` |
22+
23+
默认 pipeline 形态为:
24+
25+
```text
26+
ssa.canonicalize
27+
-> ssa.analyze_effects
28+
-> ssa.select_schedule
29+
-> ssa.<backend>.optimize_schedule
30+
-> ssa.lower_memory_scopes
31+
-> ssa.lower_backend_intrinsics
32+
```
33+
34+
## 执行流程
35+
36+
编译入口在 backend lowering 前调用 `lower_ssa_for_backend`。整体流程为:
37+
38+
1. 如果 `KernelIR` 只有 `ProgramIR`,先转换为 generic `SSAProgramIR`
39+
2. 根据目标后端、`compiler_options``kernel_metadata` 和显式参数选择 pipeline。
40+
3. 通过 `SSAPassRegistry` 把 pass 名称解析为 descriptor 和 pass 实例。
41+
4. 逐个执行 pass,并在 SSA metadata 中记录:
42+
- `pass_trace`
43+
- `pipeline_selection`
44+
- `schedule`
45+
- `optimization`
46+
- `memory_scope`
47+
- `backend_intrinsics`
48+
5. 后端代码生成器读取这些 metadata 和 operation annotation,生成目标代码。
49+
50+
## 注册器接口
51+
52+
核心对象:
53+
54+
```python
55+
from ninetoothed.ssa_passes import (
56+
DEFAULT_SSA_PASS_REGISTRY,
57+
registered_ssa_passes,
58+
)
59+
```
60+
61+
查询 pass:
62+
63+
```python
64+
registered_ssa_passes(category="hardware_independent")
65+
registered_ssa_passes(category="backend_specific", backend="triton")
66+
```
67+
68+
新增 pass 的基本方式:
69+
70+
```python
71+
from ninetoothed.ssa_passes import SSAPass, BACKEND_SPECIFIC
72+
from ninetoothed.backends.base import BackendName
73+
74+
75+
class MyTritonPass(SSAPass):
76+
name = "ssa.triton.my_pass"
77+
category = BACKEND_SPECIFIC
78+
phase = "optimization"
79+
supported_backends = (BackendName.TRITON,)
80+
81+
def run(self, program, context):
82+
return program
83+
84+
85+
DEFAULT_SSA_PASS_REGISTRY.register(MyTritonPass)
86+
```
87+
88+
## 自定义 Pipeline
89+
90+
可以直接传入 `SSAPipelineSpec`
91+
92+
```python
93+
from ninetoothed.ssa_passes import SSAPipelineSpec, lower_ssa_for_backend
94+
95+
spec = SSAPipelineSpec(
96+
passes=(
97+
"ssa.canonicalize",
98+
"ssa.analyze_effects",
99+
"ssa.select_schedule",
100+
"ssa.triton.optimize_schedule",
101+
"ssa.lower_memory_scopes",
102+
"ssa.lower_backend_intrinsics",
103+
),
104+
mode="custom",
105+
pass_options={
106+
"ssa.triton.optimize_schedule": {
107+
"tile": {"block_m": 64, "block_n": 32, "block_k": 32},
108+
"num_warps": 4,
109+
}
110+
},
111+
)
112+
113+
target_ssa = lower_ssa_for_backend(generic_ssa, backend="triton", pass_pipeline=spec)
114+
```
115+
116+
也可以通过 `KernelIR.compiler_options``KernelIR.metadata` 传入:
117+
118+
```python
119+
compiler_options={
120+
"ssa_pass_pipeline": {
121+
"mode": "custom",
122+
"passes": (...),
123+
"pass_options": {...},
124+
}
125+
}
126+
```
127+
128+
## 自动调优入口
129+
130+
当前提供 policy-based autotune 入口:
131+
132+
```python
133+
target_ssa = lower_ssa_for_backend(generic_ssa, backend="triton", autotune=True)
134+
```
135+
136+
它会根据 SSA opcodes、program kind、目标后端选择候选 pipeline,并把选择结果记录到:
137+
138+
```python
139+
target_ssa.metadata["pipeline_selection"]
140+
```
141+
142+
当前 autotune 还不是运行时测量型,而是静态策略型。它已经具备三个关键扩展点:
143+
144+
1. `candidate_pipelines`:记录候选 pass 序列。
145+
2. `pass_options`:记录候选配置,例如 tile、num_warps、num_stages。
146+
3. `reason`:记录选择原因,便于报告和调试。
147+
148+
后续可以在这个接口上接入真实运行时 benchmark:
149+
150+
1. 生成多个 `SSAPipelineSpec`
151+
2. 对每个 spec 生成后端代码并运行 microbenchmark。
152+
3. 缓存 shape/operator/backend 对应的最优 spec。
153+
4. 以后遇到同类算子直接复用缓存 spec。
154+
155+
## 当前后端消费情况
156+
157+
Triton backend 已经实际消费 `optimization` metadata:
158+
159+
- elementwise/fill/copy:读取 `block_size`,使用更大的 coalesced vector block。
160+
- matmul:读取 tile、num_warps、num_stages、input_precision、小问题阈值。
161+
- 小矩阵使用 micro-kernel,中大矩阵使用二维 block + `tl.dot`
162+
163+
CUDA/TileLang/TVM 目前也能收到后端专属 optimize pass 产生的 metadata,后续可以逐步把更多 schedule 决策接入各自代码生成器。
164+
165+
## 正确性约束
166+
167+
- pass registry 只控制 SSA pass 执行,不改变前端语义。
168+
- backend-specific pass 只能添加或转换细粒度 SSA annotation,不允许把整个算子包成粗粒度节点。
169+
- 所有 pass 执行结果都必须可序列化进 SSA metadata,便于审计、报告和自动调优缓存。

0 commit comments

Comments
 (0)