合并受阻
变更摘要
此 PR 修复了 triton_experimental 后端 codegen 与 launcher 层的三个正确性 bug:标量 Grid1D kernel 的 grid race 导致 in-place 操作结果随机;int64 pointwise kernel 因 downcast 指针缺少 .to(tl.int32) 转换而读到截断/垃圾值;以及 triton_tensor_ndim() 中 _linearize_applied 守卫导致 pre-linearize 阶段 tensor rank 计数偏低引发 rank mismatch。修改涉及 codegen/triton.py(新增 _npu_fixup_in_out_downcast() 后处理、移除 rank 计数守卫)和 npu_triton_heuristics.py(拓宽标量 Grid1D 判定条件、修复 in_out_ptr 临时 buffer 初始化)。
主要改动
-
拓宽标量 Grid1D 判据(
npu_triton_heuristics.py):将is_unsplit_scalar_reduction改为is_scalar_grid1d,判据从仅覆盖含R0_BLOCK的标量归约扩展到所有npu_num_x_nodes == 0的 Grid1D kernel,并用ncfg.codegen_linearize门控防止非 linearize 模式下将真实 1D pointwise kernel 错误钳位为单 program,从而消除标量 pointwise in-place 操作的 48 路 read-modify-write 竞态 -
新增
_npu_fixup_in_out_downcast()后处理(codegen/triton.py):在NPUTritonKernel.codegen_kernel()返回src前调用该函数,扫描所有来自downcast_args中*i64/i64指针且缺少.to(...)的tl.load()调用,自动追加.to(tl.int32),修复 upstream triton compiler 遗漏的in_ptr与in_out_ptrdowncast 转换 -
修复
in_out_ptr临时 buffer 初始化(npu_triton_heuristics.py):在_wrap_launcher_with_downcast()中,对in_out_ptr类别的 downcast 输出参数将torch.empty_like()改为a.to(dst_dtype),确保 kernel 读取路径获得正确的 downcast 后当前值,而非未初始化垃圾值 -
移除
_linearize_applied守卫(codegen/triton.py):在triton_tensor_ndim()中去掉getattr(self, '_linearize_applied', False)条件,仅保留triton_codegen_linearize门控,使 pre-linearize 阶段也能正确统计 tensor 维度(通过tree_node_mapping为空时同一过滤逻辑自然数出全部非 scalar x-node),修复因数 range-tree 数而非 node 数导致的 rank mismatch


✅ 跳过 docs ci 检查,没有需要检查的文档文件


| 阶段 | 任务名 | 状态 | 详情 |
|---|---|---|---|
| 编译构建 | Build_X86 | ✅ COMPLETED | >>> |
| Build_ARM | ✅ COMPLETED | >>> | |
| Build_X86_torchair | ⚪ IGNORED | >>> | |
| Build_ARM_torchair | ⚪ IGNORED | >>> | |
| patch_test | ⚪ IGNORED | >>> | |
| Build_X86_213 | ✅ COMPLETED | >>> | |
| Build_ARM_213 | ✅ COMPLETED | >>> | |
| 恶意代码检查 | Antipoison | ✅ COMPLETED | >>> |
| 编码安全与规范检查 | codecheck_pre-commit | ✅ COMPLETED | >>> |
| check_error | ✅ COMPLETED | >>> | |
| lintrunner | ✅ COMPLETED | >>> | |
| 开源片段检查 | SCA | ✅ COMPLETED | >>> |
| 开发者测试 | UT_ARM_A3_Part_01 | ⚪ IGNORED | >>> |
| UT_ARM_A3_Part_02 | ⚪ IGNORED | >>> | |
| UT_ARM_A2_Part_01 | ✅ COMPLETED | >>> | |
| UT_ARM_A2_Part_02 | ⚪ IGNORED | >>> | |
| UT_ARM_A2_Part_03 | ⚪ IGNORED | >>> | |
| UT_inductor_Part_01 | ⚪ IGNORED | >>> | |
| UT_inductor_Part_02 | ⚪ IGNORED | >>> | |
| UT_inductor_Part_03 | ⚪ IGNORED | >>> | |
| UT_inductor_Part_04 | ⚪ IGNORED | >>> | |
| UT_DIST_ARM_Part_01 | ⚪ IGNORED | >>> | |
| UT_DIST_ARM_Part_02 | ⚪ IGNORED | >>> | |
| UT_DIST_ARM_Part_03 | ⚪ IGNORED | >>> | |
| UT_DIST_ARM_Part_04 | ⚪ IGNORED | >>> | |
| UT_ARM_A2_Select_Part_01 | ⚪ IGNORED | >>> | |
| UT_ARM_A2_Select_Part_02 | ⚪ IGNORED | >>> | |
| UT_inductor_Part_213 | ✅ COMPLETED | >>> | |
| 流水线 | PR-pipeline_pytorch | ✅ COMPLETED | >>> |
- compile、compile_inductor、compile_torchair : 运行流水线
- retry : 重试流水线所有失败子任务
- retry <任务名> : 仅重试指定失败子任务
- stop : 停止流水线


【合入来源】
https://gitcode.com/Ascend/pytorch/issues/4314
【修改方案】
1. 问题现象
linearize 模式下 promoted r-tree 的 codegen 暴露 rank mismatch 与 load mask 不匹配两类问题,叠加
aten.fmod错误 fallback,导致多个 reduction / fill / slice / fmod 用例失败:test_buffer_use_after_remove_dynamic_shapes_npuValueError('Cannot broadcast, rank mismatch: [1,1,1,1], [1,1]')test_slice_mutation3_npuValueError('Cannot broadcast, rank mismatch: [1], [2, 2]')test_fmod_npu(含 dynamic shapes)aten.fmod调用,融合路径精度不达标2. 问题根因
根因 1 — load mask 不匹配
promoted r-tree 内不同
tl.load的 index 只涉及部分 r-node,但代码统一套用combined_mask(所有 r-node mask 的 AND),Triton 在 index 与 mask 秩不一致时拒绝广播。根因 2 —
triton_tensor_ndim()语义混淆原实现返回"每个子节点 1 维",实为迭代空间秩,但下游(
reduction_resize/dense_size_str/ store address)要求的是输出秩。输出秩下每个 r-tree 只贡献 1 个 reduction axis,无论内部被拆成几个子节点。根因 3 —
post_resize与 store address 的秩不一致store address 的秩可能为
iter_ndim(x-tree 有 register 槽位时)或real_ndim(full reduction),但post_resize统一用real_ndim作目标秩,两者不对齐。根因 4 —
constant()形状误配NPUTritonKernelOverrides.constant()用[1]*ndim作 shape,在非 linearize 的 2D pointwise kernel 下(triton_tensor_ndim()返回 1,但[None,:]/[:,None]broadcast 出 2D store address)造成 fill/slice/mutation 场景 rank mismatch。根因 5 —
index_vars_per_node时序问题triton_tensor_ndim()在__init__阶段被调用,但此时index_vars_per_node尚未赋值。根因 6 —
aten.fmod不在 GENERATE_LISTaten.fmod未注册进 triton_experimental 的 GENERATE_LIST,被错误地当作 fallback 处理(externaten.fmod调用),无法走 libdevice 融合 lowering。3. 修改原理
核心思路:输出秩(real_ndim)与迭代空间秩(iter_ndim)分离,store address 秩由上游 codegen 决定、下游
post_resize去适配它。NPUTritonKernel.__init__()super().__init__()前初始化index_vars_per_node/var_ranges_per_nodetriton_tensor_ndim()reduction_resize语义对齐_npu_iter_ndim()(新增)post_resizeiter_ndim/real_ndim_npu_apply_promoted_rtree_linesiter_ndim;_rewrite_reduction_store_shape/_fix_masked_load_ptr保留 upstream 07f4d4ccb2 完整实现_npu_mask_for_load_line()(新增)constant()_npu_build_tree_node_mapping()(从_apply_linearize提取)constant()在 body emit 阶段访问不完整 mapping 的问题_npu_fixup_in_out_downcast()(新增)downcast_args中*i64指针的tmpN = tl.load(ptr + ...)补.to(tl.int32)后处理4. 影响范围
constant()路径、i64 downcast 融合 kernel 受影响_linearize_applied守卫或iter_ndim == real_ndim自然退化lowering_override_list.py:aten.fmod加入 GENERATE_LIST(净变更 +1 行).to(tl.int32);promoted r-tree kernel 的 store/load shape 与 mask 更精确5. 测试验证
新增两个看护测试文件(9 个用例,均 PASSED,dev 6,2026-09-05/07):
test_reduction_fused_pointwise_broadcasttest_partial_reduction_dynamic_shapes/test_std_dynamic_shapes__init__阶段属性可用性test_var_mean_multi_outputtest_fill_scalar_into_slice/test_slice_mutation3/test_slice_mutation_chaintest_fmod_stay_fused/test_fmod_int_stay_fusedlibdevice.fmod融合、无aten.fmodfallback)敏感性验证:在父提交(不含本 PR 修复)上跑,fmod 用例如预期失败(fallback 断言命中);linearize 用例因父提交已含 upstream !45171 部分修复而通过,另 2 个 fmod 用例验证了修复归属本 PR。
回归验证:
test_slice_mutation3×2 +test_fmod×2(pip vs PR 分支 A/B 实测确认)【资料变更】
不涉及
【接口变更】
不涉及
【功能验证】
test/_inductor/test_triton_experimental_fmod.py、test/_inductor/test_triton_experimental_linearize_regressions.py)【CheckList】