Repository navigation
[Ascend][PTO] Vectorize T.Parallel to PTO VMI: pipeline framework and element-wise support - #4
jimmychou0 wants to merge 3 commits into
Conversation
| from __future__ import annotations | ||
|
|
||
| import ptodsl._allreduce as _allreduce | ||
| try: # mainline ptodsl only; the vmi-track releases have no SIMT allreduce |
There was a problem hiding this comment.
补充说明(更正我上一条回复):这个守卫是必需的,已在 2dbf83d 恢复。依据:本 PR 的验证方法论是 ptoas vmi-v0.1.9(released vmi 轨道,与 PR#1 基线一致),该轨道的 ptodsl 不带 ptodsl._allreduce;而生成的 kernel 源码导入 tilelang.contrib.ptodsl(其 init 顶层 import .simt),无守卫时任何 VMI kernel 会在导入期 ModuleNotFoundError。守卫只影响 vmi 轨道缺失该模块的场景,主线行为不变(238 上主线 ptoas-0.66 + 无守卫版与 vmi-0.1.9 + 守卫版均已实测通过)。若倾向不改此文件,替代方案是把 contrib/ptodsl/init.py 改为 PEP 562 懒加载,VMI 路径就不会被 SIMT 内部依赖连累——可另行提案。
69ec9ae to
33bdb37
Compare
| @@ -0,0 +1,119 @@ | |||
| import tilelang | |||
There was a problem hiding this comment.
这个文件应该不需要上传?可以考虑替换成 PR #2 中的element-wise的example
There was a problem hiding this comment.
同意,已删除(9b5354c8):example_simdvf_vecadd_lower.py 与依赖它的 test_simdvf_vecadd_pto_run.py 一并去掉。element-wise 的设备端覆盖由本 PR 自带的 test_vectorize_parallel_pto_run.py 承担(vecadd 1D/2D、tail mask、cast,auto-schedule 保持开启);PR #2 合入后 t_parallel_st_suite 的 sv1 作为 element-wise 的权威 example。
|
commit 标题和正文信息中存在很多fork仓中(deepseek/wenbo)的pr链接信息,因为这俩都是私仓,带上了现在指向的链接也不对,指向的是tile-ai仓的pr,是否需要带上?我建议是squash commit或rebase重写全部commit message。 |
9b5354c to
977425d
Compare
+1 |
T.vmi的语言前端在这个PR里面是否是必要的?
这个是什么,为什么需要simt的支持?
这部分的AI味过于浓重了,看不懂这个PR到底支持了什么特性 |
|
针对 @WenboCodes 的三个问题,description 已重写(用户视角优先,附 before/after 示例): 1. T.vmi 前端在这个 PR 是否必要? 必要:T.Parallel 自动向量化降低到 tl.vmi.* TIR op,缺 builtin 注册和 pto.vmi.* 发射就无法落地;且向量化测试复用的手写 VMI 用例也依赖前端。这与 roadmap PR-1 的口径一致("T.Parallel 核心向量化(含 VMI 语言面)")。如果 reviewer 更倾向拆分(VMI 前端单独先行一个 PR),当前分支正好按两个 commit 切开,可以无损 rebase 拆分。 2. simt.py 那条不是"SIMT 支持",是一行导入容错:每个生成的 kernel 都会 import tilelang.contrib.ptodsl(codegen 发射的固定头部),该包 init 顶层连带 import simt 子模块,后者 import ptodsl 内部模块 ptodsl._allreduce——vmi 轨道和主线 ≥0.67 的 ptodsl 没有这个模块,无守卫时任何 kernel(包括纯 VMI)在导入期就挂。守卫在 ≤0.66 上零行为变化;缺模块时只有 SIMT allreduce 辅助函数在被调用时报清晰错误。本 PR 其余部分不使用 SIMT。 3. AI 味/看不懂:已把 description 改成"先说用户能写什么"——开头就是一个 T.Parallel(300) 在 SimdVF(lanes=128) 里的完整例子(生成 vload/vmul/vadd/vstore + 44-lane 动态尾掩码),然后列本期支持(1D/2D、整除/非整除、cast)与不支持(控制流/规约/gather,后续 PR)。pass 管线等实现细节降级到后面的 Implementation notes 小节。 |
|
86c4e22 to
d9b8801
Compare
d9b8801 to
96c2345
Compare
…wing casts Extend the T.Parallel element-wise vectorizer beyond add/mul/cast: - Sub and Div binary ops (vsub / vdiv), gated by the full op-level dtype matrix in Verify (per the VMI ISA documentation): vsub matches vadd (i8/i16/i32 + f16/bf16/f32), vdiv admits f16/f32 only. - Unary math: T.abs / T.exp / T.log / T.sqrt lower to vabs / vexp / vln / vsqrt, dtype-gated per the ISA matrix (f16/bf16/f32 for fabs; f16/f32 for exp/log/sqrt). Integer abs lowers to Select at the frontend and is rejected with a pointer to the PR-2 Select support. - f32 -> f16/bf16 narrowing casts (the missing half of the f16/bf16 <-> f32 round trip): rounding=R, NOSAT (IEEE overflow-to-inf). - Runtime lane-uniform float computations (add/sub/mul/div and the unary set) are rejected at Verify via AnalyzeLaneUse (bind env + address analysis); compile-time constants and integer scalars are unaffected. Rebased onto PR PTO-ISA#4 head 96c2345 (which now carries the updated vectorization pipeline commit messages).
…wing casts Extend the T.Parallel element-wise vectorizer beyond add/mul/cast: - Sub and Div binary ops (vsub / vdiv), gated by the full op-level dtype matrix in Verify (per the VMI ISA documentation): vsub matches vadd (i8/i16/i32 + f16/bf16/f32), vdiv admits f16/f32 only. - Unary math: T.abs / T.exp / T.log / T.sqrt lower to vabs / vexp / vln / vsqrt, dtype-gated per the ISA matrix (f16/bf16/f32 for fabs; f16/f32 for exp/log/sqrt). Integer abs lowers to Select at the frontend and is rejected with a pointer to the PR-2 Select support. - f32 -> f16/bf16 narrowing casts (the missing half of the f16/bf16 <-> f32 round trip): rounding=R, NOSAT (IEEE overflow-to-inf). - Runtime lane-uniform float computations (add/sub/mul/div and the unary set) are rejected at Verify via AnalyzeLaneUse (bind env + address analysis); compile-time constants and integer scalars are unaffected. Rebased onto PR PTO-ISA#4 head 96c2345 (which now carries the updated vectorization pipeline commit messages).
Add the T.Parallel -> PTO VMI vectorization pipeline: - Verify -> Legalize -> Vectorize pass pipeline ahead of AscendSimdVFLowerParallel, with pass registration, the Python interface, and routing tests (SIMT and hand-written VMI regions are bypassed inside the passes; control-flow rewriting stays out of scope) - Verify: shared region scan and inverse lane-mapping analysis, the LayoutInference-for-PTO branch, 1D/2D lane mapping, and T.SimdVF(lanes=...) frontend support, with contract tests; lane layouts use Fragment layout objects for the base loop mapping only - Vectorize: chunk loops with dynamic prefix tail masks, remaining state reset per row/column and per sequential unit, dtype/cast codegen, plus element-wise, tail-mask, and FP8 device tests - integration: the shared full-chunk mask is emitted inside the simdvf scope (VPTO rejects pset values crossing the vecscope boundary) Co-authored-by: qukelin <qukelin1991@163.com> Co-authored-by: jimmychou <47636600+jimmychou0@users.noreply.github.com> ## Element-wise ops extension (from the stacked PR) Extend the T.Parallel element-wise vectorizer beyond add/mul/cast: - Sub and Div binary ops (vsub / vdiv), gated by the full op-level dtype matrix in Verify (per the VMI ISA documentation): vsub matches vadd (i8/i16/i32 + f16/bf16/f32), vdiv admits f16/f32 only. - Unary math: T.abs / T.exp / T.log / T.sqrt lower to vabs / vexp / vln / vsqrt, dtype-gated per the ISA matrix (f16/bf16/f32 for fabs; f16/f32 for exp/log/sqrt). Integer abs lowers to Select at the frontend and is rejected with a pointer to the PR-2 Select support. - f32 -> f16/bf16 narrowing casts (the missing half of the f16/bf16 <-> f32 round trip): rounding=R, NOSAT (IEEE overflow-to-inf). - Runtime lane-uniform float computations (add/sub/mul/div and the unary set) are rejected at Verify via AnalyzeLaneUse (bind env + address analysis); compile-time constants and integer scalars are unaffected. Rebased onto PR PTO-ISA#4 head 96c2345 (which now carries the updated vectorization pipeline commit messages).
20cb806 to
cde7e41
Compare
0c189ce to
9b1769a
Compare
Add the VMI (virtual machine instruction) intrinsics and PTO codegen:
- tilelang/ascend/language/vmi.py: the T.vmi.* surface, exposed as T.vmi
through tilelang.ascend.language - vector loads/stores, masks,
arithmetic/bitwise/shift ops, vcvt (incl. packed FP4 sources),
vinterpret_cast, vzip/vunzip, precision-aware vdiv, gather/scatter,
histogram ops, and register allocation helpers
- 54 tl.vmi.* TIR builtins registered in src/op/builtin.{h,cc}
- PTO codegen: pto.vmi.* emission with typed-literal wrapping, FP4
pair expansion, eager vreg allocation for vector local.var, the
signed/unsigned integer type split (pto.si*/pto.ui*), and a clear
AscendC rejection diagnostic; generated kernels import
tilelang.contrib.ptodsl before ptodsl so this build's native
libraries load ahead of the PTODSL MLIR modules
- KernelParam.storage_shape: packed-storage shapes for sub-byte dtypes
Co-authored-by: KurrinQu <qukelin1991@163.com>
Co-authored-by: Jay Zhuang <80731350+learning-chip@users.noreply.github.com>
Co-authored-by: Zhang Zhendong <zhendong404@gmail.com>
Co-authored-by: cj <erhsh_165@126.com>
Add the T.Parallel -> PTO VMI vectorization pipeline: - Verify -> Legalize -> Vectorize pass pipeline ahead of AscendSimdVFLowerParallel, with pass registration, the Python interface, and routing tests (SIMT and hand-written VMI regions are bypassed inside the passes; control-flow rewriting stays out of scope) - Verify: shared region scan and inverse lane-mapping analysis, the LayoutInference-for-PTO branch, 1D/2D lane mapping, and T.SimdVF(lanes=...) frontend support, with contract tests - Vectorize: chunk loops with dynamic prefix tail masks, remaining state reset per row/column and per sequential unit, and dtype/cast codegen for element-wise add/sub/mul/div, unary abs/exp/log/sqrt, and f32 <-> f16/bf16 conversions; runtime lane-uniform float computations are rejected (they would stay scalar inside SIMD_VF) - Device tests: element-wise, tail-mask, and FP8 suites Co-authored-by: qukelin <qukelin1991@163.com> Co-authored-by: jimmychou <47636600+jimmychou0@users.noreply.github.com>
The si32 reducer strategy serves both signed si32 and signless i32 carriers, but created its initial-value constant as signless pto.i32. With TIR signedness now carried into PTODSL, scalar.select mixing an si32 carrier with an i32 constant is rejected by current PTOAS (pto.select integer arms require matching types). Both creation points (_emit_warp_hw_reduce and _emit_cross_warp_reduce) now share _identity_const: the strategy key still selects the constant's numeric value, while its integer type follows the carrier value's own signedness (signed carriers get pto.si32, signless keep pto.i32).
9b1769a to
8d9d2ec
Compare
Background and Goal
Goal: users write scalar-parallel
T.Parallelprograms (element-wise, control flow, reduce) insideT.SimdVF(lanes=L); the compiler vectorizes them into PTO VMI instructions, which PTOAS compiles to run correctly on Ascend 950. The full capability lands in tile-ai mainline over several PRs; each PR submission is a milestone.Division of responsibility:
Roadmap Milestones
Scope of This PR (PR-1)
tl.vmi.*instruction-entry registration and VMI codegen, covering data movement, arithmetic, broadcast and lane index, mask creation, type conversion, etc.; codegen translates eachtl.vmi.*call intopto.vmi.*PTODSL text for PTOAS, which handles mask materialization, register allocation, and optimization.remainingdrives a dynamic prefix mask per chunk.1. Overall Transformation Flow
flowchart LR A["T.Parallel source<br/>inside T.SimdVF(lanes=L)"] -->|"LayoutInference for PTO<br/>layout_inference.cc · parallel.cc"| B["TIR with lane-layout annotation<br/>pto_parallel_loop_layout"] B -->|"Verify (read-only)<br/>verify_parallel_to_pto.cc"| C["TIR passing the input contract"] C -->|"Legalize (normalize)<br/>legalize_parallel_to_pto.cc"| D["Normalized TIR<br/>(framework init only in this PR)"] D -->|"Vectorize (uniform conversion)<br/>vectorize_parallel_to_pto.cc<br/>+ parallel_to_pto_utils.cc"| E["Vectorized TIR<br/>tl.vmi.* calls + chunk loop + mask"] E -->|"PTO codegen<br/>codegen_pto.cc"| F["pto.vmi.* PTODSL text<br/>to PTOAS"]Flow notes:
T.SimdVF(lanes=L)marks the region in the frontend (writing thetl.simdvf_lanesannotation); a kernel built with target=pto enters Verify→Legalize→Vectorize, while anything else takes the originalAscendSimdVFLowerParallelpath, leaving the Ascend compilation path unaffected.tl.vmi.*calls.codegen_pto.cc) translates eachtl.vmi.*call intopto.vmi.*PTODSL text, handed to PTOAS for mask materialization, register allocation, and optimization.2. Modules
2.1 LayoutInference for PTO
Role: pick a lane layout for each Parallel inside a PTO SIMD_VF region and write it back as an IR annotation for Verify/Vectorize to consume.
T.Parallelinside a SIMD_VF region with target=pto →pto_parallel_loop_layoutannotationparallel.ccadds a PTO branch to Parallel's layout candidates (builds a lane layout with vectorize_size=1 whenin_pto_simd_vf);layout_inference.ccrecognizes PTO regions and writes the annotation; the annotation key is independent of SIMT'sparallel_loop_layout, so the two backends never misread each otherMapping for 1D
T.Parallel(E)(VL = lanes):A 2D
T.Parallel(M, N)appears in TIR as two tightly nested Parallels and is recognized as one 2D iteration space; the layout annotation goes only on the outermost For. Only the selected dimension is vectorized; the other stays as an outer serial loop. WithP_N = ceil(N/VL)×VLandP_M = ceil(M/VL)×VL:2.2 Shared Implementation Layer (parallel_to_pto_utils + pto_index_analysis)
Verify and Vectorize must make the same judgments over the same program — whether it is convertible, what each address pattern is, how each cast lowers. These capabilities are implemented once in the shared layer and used by both passes, so the rules and their implementations cannot drift apart.
InvertPtoLaneLayoutPtoInverseMapping(lanes,index_expr, chunk_count, tail_lanes, 2D selection)AnalyzeBufferAccessMemoryAccess(address regularity expressed withElemOffsetand proven equivalent by the arithmetic analyzer over the given value ranges)ScanPtoRegion/DiscoverUnitsSharedAnalyzeLaneUsevci)PlanValueCastIsSupportedElementDType/IsSupportedVectorBinaryOp/FindUnsupportedExprNodepto_index_analysis: Index Substitution and Padding Arithmetic
When the user writes
x = i + 1and then accessesA[x], judging the address regularity ofA[x]requires substitutingxback toi + 1.ResolveIndexAliasesperforms exactly this substitution: it walks Bind definition chains and expands index variables layer by layer until the expression contains only loop variables, constants, and BufferLoads, then hands it to the address-regularity check. Whether an address is continuous or lane-uniform decides which vectorization path applies, and real programs often chain several such indirections.Rules of
ResolveIndexAliases:x1=i+i; x2=x1+x1; …from exploding exponentially);The same file provides
CheckedPtoPadding: an overflow-guarded version of "pad the logical extent up to a multiple of lanes". The lane loop indexes with int32, so an extent beyond int32 is rejected outright.2.3 Verify: Input Contract Checking
Role: read-only checking of the input TIR; accepts forms that Legalize can normalize later; aborts compilation at the first error. Diagnostics carry the
[VerifyParallelToPTO]prefix with a category and a location.Main rejection scenarios, grouped by diagnostic category:
tl.simdvf_lanesannotation; annotation not an Int64 constant; illegal lanes valuetl.vmi.*mixed with a converting Parallel;volatile_scopeattribute; region metadata referencing lane-varying valuespto_parallel_loop_layout; non-invertible layoutVerify and Vectorize share every analysis function from §2.2, so the two passes cannot disagree on the same input.
2.4 Legalize: Normalization
In PR-1 this pass only initializes the pass pipeline framework and rewrites nothing. It is introduced so that PR-2's control-flow support — normalization of IfThenElse/Min/Max→Select, etc. — lands here, keeping Vectorize's input contract unchanged.
2.5 Vectorize: Converting the Whole SIMD_VF Region Uniformly
Core class
VectorizeParallelToPTOImpl. The entryVisitStmt_(const SBlockNode*)finds a PTO SIMD_VF region →ScanPtoRegionscans it → each Parallel loop is inverted byInvertPtoLaneLayout→ converted byConvertUnit→ spliced back byReplaceStmt.ConvertUnit: the Main Flow for One Parallel Loop
flowchart TD M["Input: one Parallel loop + PtoInverseMapping"] --> S1["Reset per-loop state<br/>bind_env / value_map / temp counter"] S1 --> S2{"extent divisible by lanes?"} S2 -->|"divisible"| S3["Reuse the region-wide shared full mask"] S2 -->|"non-divisible"| S4["Create the remaining scalar (init: logical extent)"] S3 --> S5["ConvertBody: statement-by-statement<br/>(via ConvertExpr / ConvertBinary)"] S4 --> S5 S5 --> S6["DeadBindElim local DCE"] S6 --> S7["Assemble the chunk loop (induction variable q):<br/>mask bind → body → remaining update<br/>2D: the non-vectorized dimension re-emitted as an outer serial loop"] S7 --> S8["ReplaceStmt splices over the original Parallel"]Two key decisions:
remainingscalar (initialized to the loop's logical extent, decremented by lanes per chunk), and each chunk binds a dynamic prefix mask viacreate_mask(remaining, L), runs the body, then updates remaining. The mask variable must exist before the body is converted — the vstore and vector ops in the body reference it.After the body is converted, a local DCE (
DeadBindElim) removes leftover bindings that only served address derivation (dead vci/vbrc/vadd/vload chains).ConvertExpr: Expression Conversion Dispatch
AnalyzeBufferAccess, pointer viatl.access_ptr(extent=VL)vloadsload; each textual occurrence binds separately — no cross-access load reusevciPlanValueCast; identity casts pass throughvcvtwith explicit saturate/rounding attributes — backend defaults are never relied onvabs/vexp/vln/vsqrt(with mask)ConvertBinaryEvery intermediate value is materialized through
EmitBindas a named Bind (vload_0,brc_1, …), keeping the output in a stable SSA form.ConvertBinary: the Scalar/Vector 2×2 Dispatch
vbrc, thenvadd/vsub/vmul/vdiv(with mask)vbrc, thenvadd/vsub/vmul/vdiv(with mask)vadd/vsub/vmul/vdivdirectly (with mask)