feat: 统一 PTODSL scalar、builtin vector 与 SIMT 接口语义 - #1189
Conversation
848dda5 to
e194ab0
Compare
c481d8b to
abf08ee
Compare
| @@ -1,99 +1,348 @@ | |||
| # 14. Arith (Shared MLIR Dialect) | |||
| # 14. Scalar and Builtin Vector Value Operations | |||
There was a problem hiding this comment.
感谢建议。这个章节内容已经不再是 MLIR arith dialect 的镜像,当前标题是 Scalar and Builtin Vector Value Operations,因此 14-shared-arith.md 确实有些过时。我们倾向将文件重命名为 14-generic-scalar-ops.md,标题同步为 Generic Scalar and Builtin Vector Operations。这里的 generic 表示这些 IR operation 与执行域无关,可统一适用于 scalar/builtin-vector,并在后续按语义 lower;它与 SIMT 专用 operation 相区别。这个命名是否更合适?确认后我们再同步当前文档引用。
| class PTO_BinaryF16F32ScalarOp<string mnemonic> | ||
| : PTO_SimtOp<mnemonic, [Pure, AllTypesMatch<["lhs", "rhs", "result"]>]> { | ||
| : PTO_ScalarOp<mnemonic, [Pure, AllTypesMatch<["lhs", "rhs", "result"]>]> { | ||
| let arguments = (ins |
There was a problem hiding this comment.
[Major] PTO_BinaryF16F32ScalarOp/PTO_FmaOp 的操作数从 PTO_SimtBinaryF16F32ValueType(f16/f32/v2f16)放宽到了 PTO_GenericFloatType(含 bf16/f64/fp8 及任意 rank 向量),但这两个类没有 verifier,而 emitter 仍只支持 f32/f16/v2f16(VPTOLLVMEmitter.cpp 的 pow lowering 对其它元素类型直接 return failure())。结果:pto.pow : f64 或 vector<4xf32> 能通过 verify,直到 VPTO emission 深处才失败。建议收窄 ODS 约束或补 verifier。
| } | ||
|
|
||
| if (inputIsInteger && resultPtrType && | ||
| cast<IntegerType>(inputType).getWidth() != 64) { |
There was a problem hiding this comment.
[Major] 相比被删除的 IntToPtrOp::verify,新 CastPtrOp::verify 丢了两项检查:(1) 结果指针元素类型的 isEmitCSupportedScalarType 校验——现在 i64 -> !pto.ptr<tensor<...>> 等后端不支持的元素类型也能通过 verify;(2) 这里的 isa<IntegerType> 会接受 si64/ui64,而旧 ODS 的 I64 只接受 signless。建议补齐元素类型检查,并把整数侧约束收紧为 signless。
| @@ -28,10 +191,25 @@ def classify_runtime_scalar_type(type_obj): | |||
| return "integer" | |||
| if any(cls.isinstance(type_obj) for cls in (BF16Type, F16Type, F32Type)): | |||
There was a problem hiding this comment.
[Major] classify_runtime_scalar_type 只识别内建 BF16/F16/F32 和少数 !pto.* 浮点类型;而 pto.f8e4m3/pto.f8e5m2 在 _types.py 解析为 MLIR 内建 Float8E4M3FNType/Float8E5M2Type,因此 pto.cast(f32_val, pto.f8e4m3)(标量或向量)会直接抛 TypeError: runtime scalar operators only support index/int/float values——hif8 反而可用。fp8 cast 目前是不通的,与本 PR 的 cast 完备性声明矛盾。
| Location loc = op.getLoc(); | ||
| Type type = op.getResult().getType(); | ||
| if (isa<IndexType>(type)) { | ||
| rewriter.replaceOp(op, op.getValue()); |
There was a problem hiding this comment.
[Major] absi 作用在 index 上被直接替换为操作数本身(恒等)。但本文件前面 negi on index 已实现为 0 - x,即负 index 在该 IR 中可表示,此时恒等替换是静默错码。建议改为 index_cast -> math.absi -> index_cast,或在 AbsIOp::verify 中拒绝 index。
| Value falseValue = | ||
| stripIntegerSignedness(rewriter, loc, op.getFalseValue()); | ||
| Value result = rewriter.create<LLVM::SelectOp>( | ||
| loc, trueValue.getType(), op.getCondition(), trueValue, falseValue); |
There was a problem hiding this comment.
[Minor] broadcast 情形(标量 i1 条件 + 向量值)arith.select 本身就支持,这里却生成了 LLVM::SelectOp:前端阶段 IR 混入 LLVM dialect 后,arith 类 pass(如 VMILegalizeArithSelect)看不到它;且 EmitC 路径 PTOToEmitC 的 conversion target 未声明 LLVM dialect(未知 op 默认合法),llvm.select 会穿过 conversion 直到 C++ 发射阶段才失败。建议改用 arith.select,或在 EmitC 侧补 pattern。
| LowerScalarMathPattern<pto::SqrtOp, math::SqrtOp>, | ||
| LowerBinaryScalarMathPattern<pto::PowOp, math::PowFOp>, | ||
| LowerFmaToMathPattern>(&getContext()); | ||
| if (failed(applyPatternsAndFoldGreedily(getOperation(), |
There was a problem hiding this comment.
[Major] greedy 跑完后没有检查残留 generic op:例如 pto.divi ... unsigned : index 会 notifyMatchFailure 后悄悄留在 IR 里,后续各路径兜底不一致(EmitC 因 addIllegalDialect<pto> 干净报错;VPTO emitter 未把 pto dialect 标为 illegal,残留 op 会漏到 LLVM 翻译阶段才以笼统信息失败)。issue #1175 要求该 pass 结束后不得残留公共 scalar op——建议在 pass 末尾 walk 一次,对不在 documented keep-set(SIMT 硬件转换、packed math 等)内的残留 generic op 显式报错。
| // SoftLib expansion can materialize frontend PTO scalar producers after the | ||
| // shared pre-backend lowering. Legalize those newly-created generic ops | ||
| // before VPTO LLVM emission and its final legality check. | ||
| kernelModulePM.addNestedPass<func::FuncOp>( |
There was a problem hiding this comment.
[Minor] kernelModulePM.nest<ModuleOp>() 本身会递归覆盖嵌套 module 内的 func,这里再 addNestedPass<func::FuncOp> 一次是等幂的重复 greedy;且在 pre-backend 块(3579-3583)该 pass 跑在 VPTOSplitCVModule 之前,child-module 那次 add 实际是死代码。建议删掉或注释说明意图。
| UpdatePTOOpInfoWithPipeline(op, pto::PipelineType::PIPE_S, | ||
| /*skipIfNoMemInfo=*/true); | ||
| } else if (isa<pto::OpPipeInterface>(op)) { | ||
| // --- Case D: 带有 OpPipeInterface 的计算/搬运指令 --- |
There was a problem hiding this comment.
[Minor] scalar load/store 原来走 skipIfNoMemInfo=true 的分支,现在统一走 UpdatePTOOpInfo(skip=false):未跟踪指针的 scalar 访问会生成空依赖的 PIPE_S 节点而不是被丢弃。虽有新增的保守 UpdateIntegerToPtrCastMemInfo 兜底,但建议补一个针对性的 sync 测试,确认这个行为变化符合预期。
| ```mlir | ||
| %sum = pto.addi %lhs, %rhs overflow<nsw, nuw> : i32 | ||
| %fast = pto.addf %flhs, %frhs fastmath<nnan,ninf> : f32 | ||
| %half = pto.ftof %value toward_zero fastmath<nnan> : f32 -> f16 |
There was a problem hiding this comment.
[Major] 示例里的 toward_zero 是 arith.truncf 的拼法;PTO 的实际 assembly 是 round(r/a/f/c/z/o/h)(见 PTO.cpp 的 rounding parser 以及全部 lit 测试中的 round(z)),照抄此示例会得到 parse error。另外下文 247-248 行的 rounding 列表漏了 to_odd/hybrid,也没写 verifier 强制的 scope 规则:非 SIMT ftof 仅在目标更窄时接受 rounding、非 SIMT ftoi/itof 完全拒绝 rounding、to_odd/hybrid 仅 SIMT。
| `pto.trunci` is signedness-independent and may carry explicit overflow | ||
| promises. Equal-width carrier reinterpretation requires no numeric operation. | ||
| - **Cross-category conversion:** The required signedness clause selects signed | ||
| or unsigned integer interpretation. Floating-point to |
There was a problem hiding this comment.
[Major] “Floating-point to integer conversion does not saturate” 与另外两处文档矛盾:用户指南 ptodsl/docs/user_guide/06-scalar-and-pointer-ops.md 说 “always saturating”,mapping 设计文档说 F2I 是 “fixed saturating ISA behavior; PTO verification requires sat”。代码真相是分 scope/形式的:非 SIMT pto.ftoi 降为 arith.fptosi(不饱和);SIMT 硬件转换饱和且 verifySimtConversionControls 强制 sat;而裸的 SIMT pto.ftoi signed 会静默走不饱和的 arith 路径。建议在这里把 scope/形式规则写准确。
| %f32 = arith.constant 2.000000e+00 : f32 | ||
| %bad = pto.convert %f32 round(z) nosat signed : f32 -> i32 | ||
| %bad = pto.ftoi %f32 signed round(z) : f32 -> i32 | ||
| return |
There was a problem hiding this comment.
[Minor] 这个文件原来覆盖的是 SIMT F2I 缺 saturation 的负例,现在被改造成非 SIMT rounding 负例;改造后 verifySimtConversionControls 的失败路径(SIMT F2I 硬件转换缺 sat、非法 rounding/type 组合、缺 signedness、int→int)在全仓零测试覆盖。建议保留本例的同时,补回一个 SIMT scope 内的转换负例。
| - `pto.atomic_cas(ptr, compare, value, *, l2cache="nmfv")` | ||
|
|
||
| Plain scalar memory remains available through `scalar.load(...)` and | ||
| `scalar.store(...)`. |
There was a problem hiding this comment.
[Minor] 本文档其它部分已迁移到新接口,但这里(以及 41/96/129/158 行附近)仍以 scalar.load/scalar.store/scalar.index_cast 作为现行 API 描述;scalar.* 命名空间在本 PR 已不再是公开入口,建议同步更新,或明确标注为历史方案。
There was a problem hiding this comment.
[Minor] 执行域标签不一致:load/store/sqrt/exp/log/pow/fma 已迁到 PTO_ScalarOp(“纯值语义,不影响 SIMT 合法性或 section-kind 推断”),但 ceil/floor/rint/round(PTO_UnaryFloatScalarOp,约 906 行)与 PTO_BinaryFloatScalarOp 仍是 PTO_SimtOp。同类 op 两套标签,建议统一或注明依据。
There was a problem hiding this comment.
[Major] 第 470-476 行附近仍在介绍已删除的 API:“pto.fmin and pto.fmax accept f16, f32, bf16, vector<2xf16>...”——这两个符号在 ptodsl 中已不存在(迁移目标是 pto.min/pto.max);472 行还提到 “explicit convert modes”,convert 也不再是公开接口。另外全文缺少逐名迁移指引(scalar.load/store/cast/index_cast → pto.*、pto.convert(...) → pto.cast(..., rounding=, saturation=)、fmin/fmax → min/max),作为 breaking change 用户没有迁移表可查。
| lhs = arith.IndexCastOp(IndexType.get(), _strip_integer_signedness(lhs)).result | ||
| lhs = _pto_cast(lhs, IndexType.get(), index=True) | ||
| return lhs, rhs, "index" | ||
|
|
There was a problem hiding this comment.
[Major] 下面这个分支里,si32 OP ui32 时 target 取 si32(target_type = lhs_type if lhs_width >= rhs_width else rhs_type),ui32 操作数经同宽 unrealized cast 按位重解释后走 signed 的 divi/remi/cmpi/shr——对大于 INT32_MAX 的无符号值结果是错的(C 的 usual arithmetic conversions 应转 unsigned)。无告警、无报错,静默错码。建议至少文档化该规则,最好对同宽混合 signedness 的 div/rem/cmp/shr 给出诊断。
Unify the scalar and SIMT authoring surface, signless PTO IR contracts, conversion categories, pointer and typed-memory APIs, lowering, tests, and documentation.
62d0f9a to
db6206b
Compare
Fixes #1175
Relates to mouliangyu#583
Summary
统一 PTODSL 中普通 scalar、builtin vector 和 SIMT scalar 的作者接口,并为普通 scalar/builtin-vector value 建立统一的 PTO generic IR 表达。
本 PR 让 DSL 使用统一的
pto.*接口,由 frontend 根据 authored type 和执行上下文选择对应的 PTO IR;普通 PTO IR 使用 signless integer carrier,需要 signedness、rounding、saturation、overflow 或 fast-math 的语义通过 operation attribute 表达。Scope
本 PR 包含:
pto.cast按源类型和目标类型分发为exti、trunci、ftof、ftoi和itof;pto.castptr;pto.load/pto.store;pto-lower-generic-ops,将普通 generic PTO operation lower 到arith、math或 LLVM;Interface Changes
PTODSL
普通 scalar 和 same-shape builtin vector 使用统一作者接口,例如:
DSL 根据 authored type 和执行上下文选择具体 PTO IR operation。普通 scalar/builtin-vector 操作不会自动推断为 SIMT operation。
PTO IR
普通 integer operation 使用 signless
i*类型。需要 signedness 的 operation 通过 attribute 表达,浮点和整数 operation 通过 operation name 区分,例如:exti/trunci/ftof/ftoi/itof是 PTO IR 的分类表达;PTODSL 作者层统一使用pto.cast。Lowering
pto-lower-generic-ops在共享 frontend 阶段处理普通 generic PTO operation;TileLib 或 SoftLib 展开后再次处理新生成的 generic operation。target-specialized、packed ABI、SIMT collective、atomic 和同步 operation 不由该 pass 转换。Compatibility And Migration
pto.load_scalar/pto.store_scalar迁移到pto.load/pto.store;pto.castptr;pto.fmin/pto.fmax迁移到对应的pto.min/pto.max或pto.minimum/pto.maximum;pto.convert不再作为独立的 PTODSL 作者接口;scalar.*作者模块不再作为公开入口;Non-goals
pto.alloc_buffer的迁移;CTRL[48]的自动设置、恢复和跨指令优化;本 PR 只保留 conversion 所需的 saturation/rounding 字段和现有语义,不负责新增通用 CTRL 状态管理。
Validation
已完成:
load_scalar/store_scalar使用迁移验证;git diff --check;