补充验证:官方文档《VF循环优化》明确将以下写法作为 VF 尾块处理的正例:
文档位置:docs/zh/guide/算子实践参考/SIMD算子性能优化/矢量计算/VF性能优化/VF循环优化.md
uint16_t tailK = srcK % floatRepSize;
uint16_t hasTail = 0;
hasTail = !!tailK;
for (uint16_t i = 0; i < hasTail; i++) {
// 尾块处理内容
}
我在同一环境中将首个稳定触发点临时改为上述 tailK + !!tailK + for(1) 形式后重新执行 O3 编译,结果仍然是:
OPC_RC=1
Running pass: HiIPUVectorLoopUnrollPass on BlockAttnResUpdatePhase1OneVLVF
bisheng: error: clang frontend command failed with exit code 139
原写法使用比较表达式后转换为 uint16_t,本身也只能生成 0/1;改成文档推荐的 !!tailK 后并未改变崩溃位置。
这说明问题不是 hasTail 未归一化,而是当前 BiSheng 在 O2/O3 下处理官方文档推荐的 VF 运行时 0/1 trip-count 循环时,HiIPUVectorLoopUnrollPass 发生内部崩溃。该范式应当能够正常编译,至少不应导致编译器 SIGSEGV。


您好,感谢您的反馈,SIMD VF 和调用SIMD VF 的代码片段麻烦发一下~


您好,补充说明:触发问题的版本中,hasTail 是在 SIMD VF 内根据运行时参数 dSize 计算的,调用侧不传入 hasTail。
精简后的故障代码结构如下:
__simd_vf__ inline void BlockAttnResUpdatePhase1OneVLVF(
__ubuf__ float *effectiveQuery, uint32_t dSize)
{
constexpr uint32_t VL = 64;
const uint16_t hasTail =
static_cast<uint16_t>(dSize < VL);
uint32_t remainingD = dSize;
Reg::MaskReg dMask =
Reg::UpdateMask<float>(remainingD);
Reg::RegTensor<float> queryReg;
Reg::LoadAlign<float, Reg::LoadDist::DIST_NORM>(
queryReg, effectiveQuery);
for (uint16_t i = 0; i < hasTail; ++i) {
Reg::ShiftLefts(
(Reg::RegTensor<uint32_t> &)queryReg,
(Reg::RegTensor<uint32_t> &)queryReg,
static_cast<int16_t>(0),
dMask);
}
// 后续还有常规 VF 计算,已省略
}
调用 SIMD VF 的代码结构如下,调用侧没有计算或传入 hasTail:
if (dSize <= 64U) {
asc_vf_call<BlockAttnResUpdatePhase1OneVLVF>(
effectiveQueryUbAddr, dSize);
}
在 Ascend950PR_9599、CANN 9.2.0、-O2/-O3 下,该写法稳定崩溃:
Running pass: HiIPUVectorLoopUnrollPass on BlockAttnResUpdatePhase1OneVLVF
bisheng: error: clang frontend command failed with exit code 139
目前验证可通过的规避方式,是在 Scalar 侧计算 hasTail,然后作为参数传给 SIMD VF:
const uint16_t hasTail =
static_cast<uint16_t>(dSize < 64U);
asc_vf_call<BlockAttnResUpdatePhase1OneVLVF>(
effectiveQueryUbAddr, dSize, hasTail);
因此需要特别更正:此前最新代码已经采用 Scalar 侧计算并传参的规避方式,可以正常编译;真正触发崩溃的是在 VF 内根据运行时参数计算 hasTail,再将其用作 0/1 次循环上界。
另外,将相同故障结构改成 __VEC_SCOPE__ 后仍会在提取出的 VF 函数上崩溃:
HiIPUVectorLoopUnrollPass on BlockAttnResUpdatePhase1OneVLVF...extracted
说明问题与 VF 内部生成的运行时 0/1 循环有关,并不局限于 asc_vf_call 调用形式。


您好,该问题已本地复现,近期将会与编译器确认。
感谢您的反馈~


您好,编译器已确认该问题,编译器近期将会修复。


您好,该问题我们已经提交给编译器团队进行根因分析。目前正在跟踪处理中,一旦有明确结论或修复进展,我会第一时间在这里同步给您。


您好,编译器团队已修复该问题,周三会更新CANN包,可参考:
https://gitcode.com/cann/asc-devkit/blob/master/docs/zh/quick_start.md#下载cann包


Thanks for sending an issue! Please fill in the following template to help quickly solve your problem.
Describe the current behavior / 问题描述 (Mandatory / 必填)
在 Ascend950PR_9599 目标上,以 -O2 或 -O3 编译 block_attn_res_update 的 AscendC Kernel 时,BiSheng clang frontend 直接发生 SIGSEGV(exit code 139)。目标文件未生成,随后出现的链接阶段“找不到 .o”只是该前端崩溃的连锁结果。
通过 LLVM pass trace,首个稳定复现的崩溃位置为:
Running pass: HiIPUVectorLoopUnrollPass on BlockAttnResUpdatePhase1OneVLVF
gdb 同样确认 SIGSEGV 发生在 LLVM Function Pass Manager 执行过程中。
该问题与优化级别强相关:
因此问题并非普通语法错误或内存不足,而是 HiIPUVectorLoopUnrollPass 处理 simd_vf 内运行时 0/1 次循环时的编译器崩溃。
Environment / 环境信息 (Mandatory / 必填)
Steps to reproduce the issue / 重现步骤 (Mandatory / 必填)
bash build.sh --pkg --soc=ascend950 --ops=block_attn_res_update -j16 -O3 |& tee compile_info.txtfor (uint16_t loop = 0; loop < hasTail; ++loop) { Reg::ShiftLefts( (Reg::RegTensor<uint32_t> &)queryReg, (Reg::RegTensor<uint32_t> &)queryReg, static_cast<int16_t>(0), dMask); }使用 -O2 或 -O3 编译,BiSheng frontend 以 exit code 139 退出。
在该循环前加入以下指令后,当前函数可通过,崩溃会移动到下一个相同形态的 hasXXX 循环:
#pragma clang loop unroll(disable)for (uint16_t ...; ... < hasXXX; ...)循环加入该 pragma 后,完整 O3 asc_opc 流程通过并正常生成 .o 与 .json。Describe the expected behavior / 预期结果 (Mandatory / 必填)
BiSheng 应在 -O2/-O3 下正确完成该 Kernel 的编译并生成目标文件。即使某种循环形态暂不受优化器支持,也应跳过该优化或给出可诊断的编译错误,不能在编译器内部触发 SIGSEGV。
Related log / screenshot / 日志 / 截图 (Mandatory / 必填)
核心报错:
Pass trace 在崩溃前最后输出:
gdb 结果:收到 SIGSEGV,调用栈位于 LLVM Function Pass Manager。
后续“目标文件不存在/链接失败”是前端未生成 .o 的次生错误,不是根因。
Special notes for this issue/备注 (Optional / 选填)
已验证的临时规避方式:
#pragma clang loop unroll(disable)(局部规避,推荐用于缩小影响范围)。-mllvm -vloop-unroll-disable(全局关闭该循环展开优化)。-O1。补充定位结果:
--cce-simd-vf-fusion=false)无效。