Skip to content

[LinxV5] TRegToOffset ICE: unrolled if-select TMOV dest from Tile array (Liveouts sync-up error) #60

Description

@wangyuascend-spec

代码分支 / 版本

本机 checkout(不是远程 default),用于复现 clang ICE:

分支 HEAD (short hash + subject) / 版本说明
SuperNPUBench main f38ee5f Merge pull request #65 from wangyuascend-spec/add-one-level-norm-static
SuperScalarModel main 3e1ebf2f Merge pull request llvm#286 from LinxISA/chore/untrack-local-exec-logs
Linx-TileOP-API 本机 src linx tip c02dae6本 repro 编译用 overlay 6369707(toolchain 默认 pin 分支 linx src:c02dae6 Enforce Group TMATMUL shape contracts。overlay:6369707 Fix TPREFETCH and TSORT bindings(clang++ -resource-dir …/clang_res_6369707)。tip c02dae6 与当前 clang 组合会在 TQUANT %Z 上编不过,故 demo 用 overlay。
llvm-project verify/dev-llvm15_56 b945a5d01323 [handoff] Record Group TMATMUL Issue 18 acceptance。clang++:15.0.4 (linx64v5-musl-local b945a5d01323de2f38989288d0a4c423abff3ad1) Target linx64v5-unknown-linux-musl
linx-toolchain-build main e6a31ef macOS: install GNU tar for the package step
pto-spec main 0b8ce516 arch: add extension first-use profile hook (llvm#101)
  • gfrun mtime:2026-08-20 14:15:51(SuperScalarModel/bin/gfrun;本 issue 是 compile-only ICE,不必跑仿真)
  • TileOP include 来源:linx-toolchain-build/src/Linx-TileOP-APIlinx 分支;demo 实际 -resource-dir 指向 commit 6369707 的头文件树

问题描述与分析

场景抽象

要把 Local tile 数组 当成二分累加 cache:cid = ctz(idx+1) 是运行期整数,需要

TMOV(updateTile[cid], cur)     // 把当前部分和写到第 cid 档

TMOV 要求 src/dst 是同一 C++ Tile 类型且各有独立 Local 描述符。运行期下标 upd[cid] 在 SoftCore 上会断言描述符不一致;于是改成编译期展开:

#pragma unroll
for (j = 0; j < N; ++j)
    if (j == cid) TMOV(upd[j], cur);   // 展开后每条 TMOV 的 dest 是常量槽位

同时还有进位:

#pragma unroll
for (j = 0; j < N; ++j)
    if (j < cid) TADD(cur, cur, upd[j]);

这段会 inline 进带循环的 caller。

期望

N=6(rms_norm_binary 的 cache 档数)应能编过:展开后每条 TMOV/TADD 的 tile 操作数是静态可知的 Local 寄存器。

实际

clang frontend abort(exit 134):

LinxV5TRegToOffset.cpp:1112
Assertion `ResRegOp == CurRegOp && "Liveouts sync-up error!"' failed.
Running pass 'LinxV5 Treg to Offset' on function '@main'

CFG 是 runtime cid 上的 N 路钻石:每个 if (j==cid) / if (j<cid) 写不同 tile 寄存器,join 时 getLiveoutLimits 认为各前驱 live-out 的 Treg 不一致。

同文件改 kN 的边界(同一 compile.sh):

kN 结果
2 编过
3、4 template_asm.hpp TMOV:Match Instruction Error!(另一条 lowering 失败)
5、6 本 ICELiveouts sync-up error

相关(不是本 ICE,但是同一需求)

TMOV(upd[cid], cur)运行期下标、不展开)当前 能编过,但 gfrun -f 立刻:

ASSERTION FAILED: ... srcTile[0]->tileInfo->row == dstTile[0]->tileInfo->row ...
"PTO 0.58 Local TMOV requires matching source/destination descriptors"
ValidateOperandContract  SuperScalarModel/isa/Block.cpp:1099

说明动态 dest 的 TMOV 被编成了描述符不匹配的 TLSU。更理想的修复是:数组槽位有独立、匹配的 Local tileInfo,或前端拒绝无法证明匹配的 TMOV。

kernel 侧 workaround:不用 TMOV,改 TMULS(dst, src, 1.0f) 做同类型拷贝(device 无 TCOPY#ifndef __linx)。

触发背景:SuperNPUBench rms_norm_binary 想把 UpdateCache 从 GM TLOAD/TSTORE 改成本地 tile list。

复现方式

独立 demo(不依赖 rms_norm 本体),本机已跑通 ICE:

SuperNPUBench/Daily/2026-08-20/tmov_select_treg_liveout/
  tmov_select_treg.cpp
  compile.sh
  compile.log
export COMPILER_DIR=/path/to/linx_blockisa_llvm_musl/bin
# TileOP 头用 6369707 overlay(见版本表);或等价 -resource-dir
bash Daily/2026-08-20/tmov_select_treg_liveout/compile.sh

最小源码:

#include <common/pto_tileop.hpp>
#include <cstdint>
using namespace pto;

constexpr int kN = 6;
using TileV = Tile<Location::Vec, float, 1, 128, BLayout::RowMajor, 1, 1>;

inline int cache_id(int64_t idx) {
    return static_cast<int>(
        __builtin_ctzll(static_cast<unsigned long long>(idx + 1)));
}

inline void update_cache(TileV (&upd)[kN], TileV &cur, int64_t &r) {
    const int cid = cache_id(r);
#pragma clang loop unroll(full)
    for (int j = 0; j < kN; ++j) {
        if (j < cid) {
            TADD(cur, cur, upd[j]);
        }
    }
#pragma clang loop unroll(full)
    for (int j = 0; j < kN; ++j) {
        if (j == cid) {
            TMOV(upd[j], cur);
        }
    }
    ++r;
}

int main() {
    TileV upd[kN];
    TileV cur, sum;
    int64_t r = 0;
    for (int i = 0; i < 8; ++i) {
        TEXPANDS(cur, 1.0f);
        update_cache(upd, cur, r);
    }
    TMULS(sum, upd[cache_id(r - 1)], 1.0f);
    float buf[128];
    using gm_t = global_tensor<float, RowMajor<1, 128>>;
    gm_t g(buf);
    TSTORE(g, sum);
}

编译要点(与 one-level Makefile 一致):-c -mlxbc -fenable-matrix -O2 -mllvm -enable-all-vector-as-tilereg=true 以及 LinxV5 HL/dim/simt 那组 -mllvm-D__linx -DENABLE_TENSOR_INSTR-std=c++20。只需 -c,不需要 link / gfrun。

__attribute__((noinline)) 且去掉 TADD 循环、只留 if (j==cid) TMOV 时,本机 N=4 能编过;必须把 TADD 进位 + TMOV 选择一起 inline 进带循环的 caller,且 N≥5,才会打到这条 Treg live-out ICE。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions