Component
Verifier / IR semantics (lib/PTO/IR)
Description
提单:vpto_split_cv_module — named module CV split 触发 symbol 重定义
1. 问题来源
- pass:
vpto_split_cv_module (-vpto-split-cv-module)
- 涉及文件:
/home/cplop/code/pto/PTOAS/lib/PTO/Transforms/VPTOSplitCVModule.cpp
- 关键逻辑:
splitCVModule → cloneModuleForKind(source->clone() 两次插入同一 outer)
- 发现途径: 手工复核实锤;框架原先漏检(多顶层 module 稀释 + 设计拒绝误报抢占)
- 确认时间: 2026-09-16
Pass 文件 git commit(提单引用)
在 PTOAS 仓库对 pass 文件取 log:
cd /home/cplop/code/pto/PTOAS
git log -1 --format='%H %s %ci' -- lib/PTO/Transforms/VPTOSplitCVModule.cpp
| 用途 |
commit id |
说明 |
| 当前文件 tip(提单默认) |
f45729d4de88836ab28c5939cb12b60e180fb4de |
style: enforce C++ codecheck rules (2026-08-13) |
| 引入 clone 拆分逻辑 |
0b9088de630cf9db961248e309a2f0917e49c795 |
Support VPTO section split input |
2. 为什么是 bug
合法 sugar 输入:顶层 带 sym_name 的 module,体内同时有 pto.section.vector 与 pto.section.cube,且无 pto.kernel_kind。
Pass 走 CV split:
cloneModuleForKind(module, Vector) / cloneModuleForKind(module, Cube) 各一次
Operation::clone() 复制 inherent sym_name = "top_sym"
- 两个 clone 作为兄弟插入同一 SymbolTable →
redefinition of symbol named 'top_sym'
- pass / verifier 失败(exit ≠ 0)
对照:去掉 @top_sym 的匿名 module,同样 sections,拆分成功。
注意:同一 .pto 文件写两个顶层 module 时,MLIR 会隐式包匿名 outer;此时 clone 的是 outer(无 name),每个 kind 子树各保留一份 @top_sym,不会报重定义——这是框架曾漏检的原因。
3. 实证
|
exit |
现象 |
bug.pto(module @top_sym + CV) |
1 |
redefinition of symbol named 'top_sym' |
control.pto(匿名 + CV) |
0 |
正常拆成 vector/cube 子 module |
| bug 无 pass 基线 |
0 |
输入本身合法 |
bash test/vpto_split_cv_module_bug_cursor/reproduce.sh
# 预期: 差分复现成功(bug: symbol redefinition + control 通过)
4. 修复建议(伪代码)
根因:clone 继承了 outer 的 inherent sym_name,而 CV 子 module 不应再占用 outer 的符号名。
在 cloneModuleForKind 中,clone 之后、builder.insert 之前剥离符号名:
static ModuleOp cloneModuleForKind(ModuleOp source, FunctionKernelKind kind,
OpBuilder &builder) {
auto cloned = cast<ModuleOp>(source->clone());
// FIX: kind 子 module 不得继承 outer 的 sym_name,否则双 clone 兄弟冲突
if (cloned.getSymName())
cloned.setSymName(std::nullopt); // 或项目内等价 API: removeSymName()
cloned->setAttr(FunctionKernelKindAttr::name,
FunctionKernelKindAttr::get(cloned.getContext(), kind));
eraseSectionSplitCandidatesWithoutSectionKind(cloned, kind);
rewriteSectionsForKind(cloned, kind);
builder.insert(cloned);
return cloned;
}
可选加固(splitCVModule 组装 outer 时):
// outer 保留原 module 的 discardable attrs;
// 原 module 的 inherent sym_name 留在「外层 wrapper」上即可,不要拷进 clone。
auto outer = ModuleOp::create(module.getLoc());
// ... setAttrs(outerAttrs without sym) ...
if (needVector) cloneModuleForKind(module, FunctionKernelKind::Vector, builder);
if (needCube) cloneModuleForKind(module, FunctionKernelKind::Cube, builder);
module.getBodyRegion().takeBody(outer.getBodyRegion());
module->setAttrs(outer->getAttrs());
// module 自身的 inherent sym_name 若需保留,勿被 setAttrs 清掉;
// 子 module 已无 sym_name,不会与 wrapper 冲突。
lit:采用本目录 bug.pto;修复后应 exit=0,且子 module 匿名(或显式改名),不再出现 redefinition of symbol。
5. 影响面
- 后果:带符号名的 sugar module 无法完成 CV 拆分,编译失败。
- 触发:frontend / 手工 IR 给顶层 module 起名;匿名路径(lit 常见)不受影响。
- 优先级:Medium-High(正确性;合法输入失败)。
Reproduction (minimal)
bug.pto
module @top_sym attributes {pto.target_arch = "a5"} {
func.func @kernel_fn(%arg0: i32) attributes {pto.kernel} {
pto.section.vector {
pto.sync.set <PIPE_V>, 0
}
pto.section.cube {
pto.sync.set <PIPE_MTE1>, 0
}
return
}
}
control.pto
module attributes {pto.target_arch = "a5"} {
func.func @kernel_fn(%arg0: i32) attributes {pto.kernel} {
pto.section.vector {
pto.sync.set <PIPE_V>, 0
}
pto.section.cube {
pto.sync.set <PIPE_MTE1>, 0
}
return
}
}
reproduce.sh
#!/usr/bin/env bash
# 一键复现: vpto_split_cv_module / vpto_split_cv_module_bug_cursor
set -u
HERE="$(cd "$(dirname "$0")" && pwd)"
REPO=/home/cplop/code/pto/PTOAS
PASS='-vpto-split-cv-module'
BIN="${1:-}"
if [ -z "$BIN" ]; then
for cand in "$REPO/build/tools/pto-test-opt/pto-test-opt" \
"$REPO/build-coverage/tools/pto-test-opt/pto-test-opt"; do
[ -x "$cand" ] && BIN="$cand" && break
done
fi
if [ -z "$BIN" ] || [ ! -x "$BIN" ]; then
echo "[!] 未找到 pto-test-opt" >&2
exit 3
fi
echo "[i] 使用二进制: $BIN"
run_one() {
local name="$1"
"$BIN" $PASS "$HERE/${name}.pto" >"$HERE/${name}.out.pto" 2>"$HERE/${name}.stderr.txt"
echo "$?"
}
ctl=$(run_one control)
bug=$(run_one bug)
echo "[control] exit=$ctl (预期 0)"
echo "[bug] exit=$bug (预期非 0,redefinition of symbol)"
echo "--- bug.stderr ---"
cat "$HERE/bug.stderr.txt"
if [ "$ctl" -eq 0 ] && [ "$bug" -ne 0 ]; then
if grep -q "redefinition of symbol" "$HERE/bug.stderr.txt"; then
echo "[OK] 差分复现成功(bug: symbol redefinition + control 通过)"
exit 1
fi
fi
if [ "$ctl" -eq 0 ] && [ "$bug" -eq 0 ]; then
echo "[OK] 未复现(可能已修复)"
exit 0
fi
echo "[!] 结果异常"
exit 2
Expected behavior
输入合法(带名字的 module @top_sym,里面同时有 cube/vector section),跑 -vpto-split-cv-module 应该成功,拆成两个子 module(一个 vector、一个 cube)
Actual behavior / error logs
pass 把 module clone 了两次,两个子 module 都还叫 @top_sym,SymbolTable 报 redefinition of symbol,opt 失败(exit≠0)。
Git commit
f45729d
Host platform
None
Target Ascend arch (if relevant)
None
PTOAS build level (if relevant)
None
Component
Verifier / IR semantics (lib/PTO/IR)
Description
提单:vpto_split_cv_module — named module CV split 触发 symbol 重定义
1. 问题来源
vpto_split_cv_module(-vpto-split-cv-module)/home/cplop/code/pto/PTOAS/lib/PTO/Transforms/VPTOSplitCVModule.cppsplitCVModule→cloneModuleForKind(source->clone()两次插入同一 outer)Pass 文件 git commit(提单引用)
在 PTOAS 仓库对 pass 文件取 log:
f45729d4de88836ab28c5939cb12b60e180fb4destyle: enforce C++ codecheck rules(2026-08-13)0b9088de630cf9db961248e309a2f0917e49c795Support VPTO section split input2. 为什么是 bug
合法 sugar 输入:顶层 带
sym_name的 module,体内同时有pto.section.vector与pto.section.cube,且无pto.kernel_kind。Pass 走 CV split:
cloneModuleForKind(module, Vector)/cloneModuleForKind(module, Cube)各一次Operation::clone()复制 inherentsym_name = "top_sym"redefinition of symbol named 'top_sym'对照:去掉
@top_sym的匿名 module,同样 sections,拆分成功。3. 实证
bug.pto(module @top_sym+ CV)redefinition of symbol named 'top_sym'control.pto(匿名 + CV)bash test/vpto_split_cv_module_bug_cursor/reproduce.sh # 预期: 差分复现成功(bug: symbol redefinition + control 通过)4. 修复建议(伪代码)
根因:clone 继承了 outer 的 inherent
sym_name,而 CV 子 module 不应再占用 outer 的符号名。在
cloneModuleForKind中,clone 之后、builder.insert之前剥离符号名:可选加固(
splitCVModule组装 outer 时):lit:采用本目录
bug.pto;修复后应 exit=0,且子 module 匿名(或显式改名),不再出现redefinition of symbol。5. 影响面
Reproduction (minimal)
bug.pto module @top_sym attributes {pto.target_arch = "a5"} { func.func @kernel_fn(%arg0: i32) attributes {pto.kernel} { pto.section.vector { pto.sync.set <PIPE_V>, 0 } pto.section.cube { pto.sync.set <PIPE_MTE1>, 0 } return } } control.pto module attributes {pto.target_arch = "a5"} { func.func @kernel_fn(%arg0: i32) attributes {pto.kernel} { pto.section.vector { pto.sync.set <PIPE_V>, 0 } pto.section.cube { pto.sync.set <PIPE_MTE1>, 0 } return } } reproduce.sh #!/usr/bin/env bash # 一键复现: vpto_split_cv_module / vpto_split_cv_module_bug_cursor set -u HERE="$(cd "$(dirname "$0")" && pwd)" REPO=/home/cplop/code/pto/PTOAS PASS='-vpto-split-cv-module' BIN="${1:-}" if [ -z "$BIN" ]; then for cand in "$REPO/build/tools/pto-test-opt/pto-test-opt" \ "$REPO/build-coverage/tools/pto-test-opt/pto-test-opt"; do [ -x "$cand" ] && BIN="$cand" && break done fi if [ -z "$BIN" ] || [ ! -x "$BIN" ]; then echo "[!] 未找到 pto-test-opt" >&2 exit 3 fi echo "[i] 使用二进制: $BIN" run_one() { local name="$1" "$BIN" $PASS "$HERE/${name}.pto" >"$HERE/${name}.out.pto" 2>"$HERE/${name}.stderr.txt" echo "$?" } ctl=$(run_one control) bug=$(run_one bug) echo "[control] exit=$ctl (预期 0)" echo "[bug] exit=$bug (预期非 0,redefinition of symbol)" echo "--- bug.stderr ---" cat "$HERE/bug.stderr.txt" if [ "$ctl" -eq 0 ] && [ "$bug" -ne 0 ]; then if grep -q "redefinition of symbol" "$HERE/bug.stderr.txt"; then echo "[OK] 差分复现成功(bug: symbol redefinition + control 通过)" exit 1 fi fi if [ "$ctl" -eq 0 ] && [ "$bug" -eq 0 ]; then echo "[OK] 未复现(可能已修复)" exit 0 fi echo "[!] 结果异常" exit 2Expected behavior
输入合法(带名字的 module @top_sym,里面同时有 cube/vector section),跑 -vpto-split-cv-module 应该成功,拆成两个子 module(一个 vector、一个 cube)
Actual behavior / error logs
Git commit
f45729d
Host platform
None
Target Ascend arch (if relevant)
None
PTOAS build level (if relevant)
None