Skip to content

XLU 冲突惩罚表

地址适用于 libtpu-0.0.40-cp314 wheel 中的 libtpu.so(BuildID md5 89edbbe81c5b328a958fe628a9f2207d,781,691,048 字节,未 strip — nm -C 可解析下文所有符号)。.text/.rodata VMA == 文件偏移;.data.rel.ro VMA − 0x200000 == 文件偏移。其他版本会不同。

摘要

XluConflictPenaltyTable 是每个 (op,op) 延迟模型中非 MXU 结构冒险的一半。当两个跨 lane 操作在没有真实数据依赖的情况下,背靠背发射到同一个 XLU 时,第二个操作必须等第一个操作充分排空跨 lane 数据通路后才能进入该通路 — 这是基础操作延迟网格看不到的结构停顿。本表为该停顿定价。它直接对应 MxuLatencyTable 保留矩阵,但粒度粗得多:MXU 模型按资源保存周期数组索引,而 XLU 模型把每个跨 lane 操作折叠为六种 XluInstrType 之一,并索引一个平坦的 int32[from][to][vxpose] 惩罚网格。

熟悉的参照物是 LLVM SubtargetInfo::getWriteProcResBegin 的转发延迟 / read-advance 表:从生产者写到消费者读的一条边携带固定的旁路/冒险周期数,列表调度器把它加到依赖上。XluConflictPenaltyTable 是把这个想法用于一个功能单元,并按操作类别而不是寄存器来索引。两个操作必须在同一个 MXU 实例上(表按每个 MXU 实例建模,因此这里不建模跨实例冲突),第三个索引 vxpose — MXU 实例 id & 3 — 捕获奇/偶 XLU-FIFO 端口不对称性,使惩罚随实例倾斜。

本页记录三件事,并逐字节锚定到二进制:XluInstrType 枚举和 GetXluInstrType opcode 映射;写入器 SetXluConflictPenaltyBetween 与读取器 XluConflictPenaltyBetween 完全共享的表几何(单元地址算术、stored = value + 1 的“已设置”偏置、边界检查);以及从三个构造函数的 Set 调用序列直接转录的 Viperfish、Pufferfish、Ghostlite 每代完整惩罚矩阵。最后给出调度器端消费者 — LatencyTableViperfish::LatencyBetweenInternal 的 XLU 分支,它对 XLU 冒险项做普通 MAX 归约。

重新实现时,契约是:

  • XluInstrType 的 6 值枚举,以及 GetXluInstrType(LloValue*) 的 opcode → 类型映射(包括 vxpose_mode 转置子表)。
  • int32 cell[from][to][vxpose] 几何:cell = base + 72·from + 12·to + 4·vxpose + 8+1 存储偏置;to < 6 / vxpose < 3 边界,from 不检查。
  • 每代安装策略:VF/PF 的传播式 override(自动填充 B16 packed 兄弟项)与 Ghostlite 的非传播式基础 Set(每个单元显式设置)。
  • 三个惩罚矩阵,以及 IsPacked / Packed16Version / IsTranspose 分类器。
  • 高层 XluConflictPenaltyBetween(LloValue*, LloValue*) 的同 MXU 检查 + final-transpose 虚拟旁路,以及收取该单元值的 LatencyBetweenInternal MAX 归约。
xla::jellyfish::XluConflictPenaltyTable(嵌入在所属 LatencyTable + 0x18
写入器SetXluConflictPenaltyBetween(from, to, vxpose, value) @ 0x1c8a0140(基础,非传播式)
单元读取器XluConflictPenaltyBetween(from, to, vxpose) @ 0x1c8a0180
值读取器XluConflictPenaltyBetween(LloValue*, LloValue*) @ 0x1c8a01c0
Opcode → 类型GetXluInstrType(LloValue*) @ 0x1c89ff20(转置子表 @ 0xa2dcce0
类型 → 名称XluInstrTypeToString @ 0x1c8a16a0
单元算术int32, cell = base + 72·from + 12·to + 4·vxpose + 8;stored = value + 1
边界to ∈ [0,5] (ud1),vxpose ∈ [0,2] (ud1);from 由调用方保证
VF / PF 安装LatencyTableViperfish::Set… @ 0x1c8a42e0 · LatencyTablePufferfish::Set… @ 0x1c8a17e0(字节相同,传播式)
消费者LatencyTableViperfish::LatencyBetweenInternal @ 0x1c8a4ac0(XLU 分支 — 普通 MAX)
置信度CONFIRMED(按字节锚定),除非某行另有说明

XluInstrType 枚举

目的

冲突模型定价的每个跨 lane 操作都会先归约为六种 XluInstrType 值之一 — “非 MXU 冒险字母表”。这是表的行/列空间;除了跨 lane 的种类元素宽度外,操作的其他信息都会被丢弃。该枚举把 XLU 的工作拆分为跨 lane reducetranspose(三种 packed 宽度),以及合并的 permute/rotate/broadcast 家族。

名称

XluInstrTypeToString @ 0x1c8a16a0 通过内联 strcpy(前五个)或 .rodata 引用(第六个,25 个字符 @ 0x84ddb81)发出每个值的字面名称。字符串长度也会一并写入,因此名称逐字节精确:

valuename宽度 / 家族IsPacked?
0kReduceB3232-bit cross-lane reduceno
1kReduceB1616-bit cross-lane reduceyes
2kTransposeB3232-bit transposeno
3kTransposeB16bf16-packed transposeyes
4kTransposeB88-bit-packed transposeyes
5kPermuteRotateOrBroadcastpermute / rotate / broadcast-laneno

B32/B16/B8 后缀表示元素宽度 packing。三个 packed 变体 {1, 3, 4} 是下文 IsPacked 标记的项;B32(以及 permute)类型未 packed。

GetXluInstrType — opcode → 类型

GetXluInstrType(LloValue*) @ 0x1c89ff20 通过 switchLloOpcodeWORD[value])映射到其 XluInstrType。逐字节如下:

c
int GetXluInstrType(LloValue* v):                        // sub_1C89FF20
    switch (WORD[v]):                                     // LloOpcode
        case 0x8B:  return 5;                             // kVectorSetPermutePattern → permute
        case 0xA6:  // kVectorTranspose
            m = LloInstruction::vxpose_mode(v);           // VxposeMode
            if (m >= 4) return 3;                         // out-of-range → kTransposeB16
            return xpose_subtable[m];                     // .rodata @0xa2dcce0 = {2,3,4,2}
        case 0xA7:  return 3;                             // kVectorTransposeBinary → kTransposeB16
        case 0xF5..0xFC: return 0;                        // cross-lane reduce/index → kReduceB32
        case 0xFD..0x101: return 1;                       // (the B16 reduce band) → kReduceB16
        default:
            if (WORD[v] <= 0x3B && bt(0x0C40000000000000, WORD[v]))
                return 5;                                 // bits {0x36,0x3a,0x3b} → permute/rotate/bcast
            LOG(FATAL) << "Unexpected XLU instruction: " << ToMnemonic(v);   // latency_table.cc:206
```text

`.rodata 0xa2dcce0` 处的转置子表是四个 `int32` `{2, 3, 4, 2}`(`xxd` 已确认):`VxposeMode` 0 → `kTransposeB32`,1 → `kTransposeB16`,2 → `kTransposeB8`,3 → `kTransposeB32`。因此 `kVectorTranspose`(`0xa6`)从其 `vxpose_mode` 解析 packing 宽度;`kVectorTransposeBinary`(`0xa7`)固定为 `kTransposeB16`。reduce 按 opcode 区间拆分:`0xf5..0xfc` → `kReduceB32`,`0xfd..0x101` → `kReduceB16`。permute/rotate/broadcast 组是 opcode `{0x36, 0x3a, 0x3b}`(由 `bt 0x0C40000000000000` 位掩码匹配,bits 0x36/0x3a/0x3b 置位)加上 `0x8b`。

> **注意 —** 这里的 `vxpose_mode` 轴(`GetXluInstrType` 内的*元素宽度*选择器)不同于 `vxpose` 表索引(下文的 *MXU 实例 id* 选择器)。这个名称冲突并不理想;前者是从 transpose 操作读出的 `VxposeMode` 枚举,后者是 `mxu_id & 3`。关于真正的 `VxposeMode` 枚举,见 [Transpose-Reservation Latency](xpose-reservation-latency.md)。

---

## 表几何

### 布局与单元地址

惩罚网格是一个 `int32 cell[from=6][to=6][vxpose=3]` 块,嵌在所属的每代 `LatencyTable` 内 `+0x18` 处(因此 VF/PF override 写入会落在 `LatencyTable+0x20`)。写入器和读取器中的单元地址算术完全相同 — 已确认两次:

```c
// writer  XluConflictPenaltyTable::SetXluConflictPenaltyBetween       sub_1C8A0140
// reader  XluConflictPenaltyTable::XluConflictPenaltyBetween          sub_1C8A0180
int32* cell(base, from, to, vxpose):
    if (to     >= 6) ud1;                 // bounds: to ∈ [0,5]
    if (vxpose >= 3) ud1;                 // bounds: vxpose ∈ [0,2]
    return (int32*)(base + 72*from + 12*to + 4*vxpose + 8);
    // (from is NOT range-checked — the caller guarantees from ∈ [0,5])

from 步幅是 72 = 6·12 字节(一个 [to][vxpose] 平面);to 步幅是 12 = 3·4 字节(一个 vxpose 行);vxpose 步幅是 4 字节(一个 int32);+8 是每块头部跳过。活跃读取区域覆盖 base+8 .. base+8+72·6 = base+0x1b8

高层读取器用 int32 单位表达同一个地址:this[18·from + 3·to + vxpose + 2]18·4 = 723·4 = 122·4 = 8)— 完全相同。

+1 存储偏置

每个 Set 变体都存储 value + 1,读取器返回原始存储字而不相减:

c
void SetXluConflictPenaltyBetween(from, to, vxpose, value):
    *cell(base, from, to, vxpose) = value + 1;            // inc — the +1 "is-set" bias

int XluConflictPenaltyBetween(from, to, vxpose):
    return *cell(base, from, to, vxpose);                 // raw stored word
```text

> **易错点 —** 读取时**不会**减去 `+1`。从未写入的单元保持 `0`(“无条目”的哨兵);显式设置为 `k` 周期惩罚的单元保存 `k+1`,调度器收取的是**存储值** — 因此显式惩罚实际是 `k+1` 周期,而 `0` 周期惩罚(`Set(...,0)`)会存储 `1` 并收取 `1`。若重新实现时存储并返回原始惩罚,每个已设置单元都会少一,并且无法区分“未设置”和“设置为 0”。请存储 `value + 1`;收取存储字。下文所有惩罚表列出的都是**原始 `Set` 参数**;存储/收取值是它 `+ 1`。

### 初始化与活跃步幅

`InitializeConflictLatency` @ `0x1c8a0040` 在构造函数安装单元前将该块清零,但它按 **84 字节(`0x54`)步幅**遍历 **6 个子块**,在每个子块起始处写入 `{1, 1}`(`0x0000000100000001`)头部对,并用清零的 YMM 通过 `vmovups` 清除其余部分。读/写单元算术使用 **72 字节(`0x48`)from 步幅**,不是 84

> **怪异点 —** init 步幅(84)与索引访问步幅(72)每块相差 12 字节。活跃表是 72 字节步幅区域(已在写入器和读取器中确认);每个 init 子块多出的 12 字节是保留/头部 padding,并且写在每个 init 子块起始处的 `{1,1}` 字不会被索引访问器读取。重新实现可完全忽略 84 字节 init 布局,直接清零一个平坦的 `int32[6][6][3]` 加上 `+8` 头部跳过;该差异是 init 例程的产物,不是第二张表。(FUNCTIONAL — 头部字不会被任何已跟踪读取消费。)

---

## 每代安装策略

三个已解码代际用两种不同方式安装单元,这个差异使矩阵大小看起来很不平衡(VF 18 次调用,PF 10 次,GL 56 次)。

### 传播式 override — Viperfish 和 Pufferfish

`LatencyTableViperfish::SetXluConflictPenaltyBetween` @ `0x1c8a42e0` 与 `LatencyTablePufferfish::SetXluConflictPenaltyBetween` @ `0x1c8a17e0` **逐字节相同**(唯一差异是 `LOG(FATAL)` 源字符串 — `latency_table_vf.cc:1119` vs `latency_table_pf.cc:145`)。二者都是*传播式*形式:一次 `Set(from, to, vxpose, value)` 会自动填充 `from` 与 `to` 的 `B16` packed 兄弟项:

```c
void Set_propagating(from, to, vxpose, value):            // VF sub_1C8A42E0 ≡ PF sub_1C8A17E0
    CHECK(!IsPacked(from) && !IsPacked(to));              // override only sets the *unpacked* cell
    if (to >= 6) ud1;  if (vxpose >= 3) ud1;
    v = value + 1;
    *cell(base, from, to, vxpose) = v;                    // [from][to][vxpose]
    to16 = Packed16Version(to);                           // B16 sibling of `to`, if any
    if (to16.present)   *cell(base, from, to16, vxpose) = v;     // [from][B16(to)]
    from16 = Packed16Version(from);                       // B16 sibling of `from`, if any
    if (from16.present):
        vv = v + 8*(from == 3);                           // +8 iff from == kTransposeB16 (dead — see below)
        *cell(base, from16, to, vxpose) = vv;             // [B16(from)][to]
        if (to16.present) *cell(base, from16, to16, vxpose) = vv;  // [B16(from)][B16(to)]

因此一次 VF/PF 调用最多写入四个单元:基础 unpacked 单元、它的 B16-to 列兄弟、B16-from 行兄弟,以及 B16×B16 角落。CHECK(!IsPacked(...)) 强制 override 只能用 unpacked 参数调用 — packed 单元完全通过传播到达。Packed16VersionkReduceB32 → kReduceB16kTransposeB32 → kTransposeB16,并报告 kPermuteRotateOrBroadcast 没有 B16 版本(因此 permute from/to 不传播)。

怪异点 — 传播值中的 +8*(from == 3) 增量在实践中是死代码from == 3kTransposeB16,会被 IsPacked 标记 — 而开头的 CHECK(!IsPacked(from)) 禁止用 from == 3 调用 override。该增量是防御性代码,在实际安装序列下永远不会触发(VF/PF 只用 from ∈ {0, 2, 5} 调用)。重新实现可以省略它。

非传播式基础 — Ghostlite

LatencyTableGhostlite(ctor @ 0x1c8b0c00)不安装 override:它直接调用基础 XluConflictPenaltyTable::SetXluConflictPenaltyBetween @ 0x1c8a0140,后者只写一个单元且不传播。因此 Ghostlite 会显式设置它想要的每个单元,包括 B16/B8 packed 行列 — 56 次调用覆盖 27 个不同的 (from, to) 对(其中 kReduceB32 → kTransposeB8 这一对设置两次;第二次写入生效)。


惩罚矩阵

下方所有值都是原始 Set 参数(表存储 value + 1;调度器收取存储值)。XluInstrType:0 kReduceB32,1 kReduceB16,2 kTransposeB32,3 kTransposeB16,4 kTransposeB8,5 kPermuteRotateOrBroadcast(缩写为 Perm)。矩阵是有方向的from → to),并按 vxpose = MXU 实例 id & 3 参数化。

Viperfish — LatencyTableViperfish ctor @ 0x1c8a3f20

18 次显式 Set 调用(传播式 override 自动填充 B16 兄弟项)。Viperfish 使用全部三个 vxpose 模式:

fromtovx=0vx=1vx=2
kReduceB32kTransposeB32405740
kReduceB32Perm192423
PermkReduceB32414140
PermkTransposeB32335237
kTransposeB32kReduceB3210588105
kTransposeB32Perm1028297

这些行/列的 B16 兄弟项(kReduceB16kTransposeB16)会在 ctor 时通过传播填充为相同值 — 例如 kReduceB16 → kTransposeB16 携带与 kReduceB32 → kTransposeB32 相同的 40/57/40

Pufferfish — LatencyTablePufferfish ctor @ 0x1c8a1960

10 次显式 Set 调用 — 5 个不同的 (from, to) 对,每个都在 vxpose 0vxpose 1 上以相同值安装(Pufferfish 在两个模式间复制,而不是变化):

fromtovx=0vx=1
kReduceB32kTransposeB325656
PermkTransposeB324646
kReduceB32Perm1717
kTransposeB32Perm9696
kTransposeB32kReduceB328686

注意 — PF ctor(@0x1c8a1960)进行了 10SetXluConflictPenaltyBetween 调用,包括显式的 (2, 0, 1, 86) — 因此 kTransposeB32 → kReduceB32 单元在两个 vxpose 平面上都设置为 86。PF 矩阵在 vxpose 0/1 上完全对称。

Ghostlite — LatencyTableGhostlite ctor @ 0x1c8b0c00

56 次显式基础 Set 调用覆盖 27 个不同的 (from, to) 对(非传播路径直接设置 packed 行/列)。完整矩阵:

fromtovx=0vx=1
kReduceB32kTransposeB324450
kReduceB32kTransposeB164444
kReduceB32kTransposeB83632
kReduceB32Perm2116
kReduceB16kTransposeB324854
kReduceB16kTransposeB164848
kReduceB16Perm2520
kTransposeB32kReduceB324438
kTransposeB32kReduceB164438
kTransposeB32kTransposeB163529
kTransposeB32kTransposeB83929
kTransposeB32Perm4029
kTransposeB16kReduceB321212
kTransposeB16kReduceB161212
kTransposeB16kTransposeB3239
kTransposeB16kTransposeB873
kTransposeB16Perm83
kTransposeB8kReduceB321620
kTransposeB8kReduceB161620
kTransposeB8kTransposeB321525
kTransposeB8kTransposeB161519
kTransposeB8Perm43
PermkReduceB323035
PermkReduceB163035
PermkTransposeB322940
PermkTransposeB162934
PermkTransposeB81718

易错点 — kReduceB32 → kTransposeB8 对在 GL ctor 中安装了两次:先是 (0, 4, 0, 32) / (0, 4, 1, 28),然后是 (0, 4, 0, 36) / (0, 4, 1, 32)。第二次写入生效,因此实时存储值是 36 / 32(原始),不是第一次的 32 / 28。若读者在该单元首次安装处停止,会记录错误惩罚。

数值含义

该矩阵编码 XLU FIFO-push 顺序冒险。重新实现者可以依赖几个模式:

  • 方向很重要。 kTransposeB32 → kReduceB32 是代价最高的边,明显高于其他边(VF 105 周期 — 完整 XLU 排空 — 而反向代价小得多),表示 transpose 后接 reduce 会使跨 lane 排空流水线停顿。PF 对同一方向定价为 86
  • Packing 会降低成本。 最宽的 unpacked B32 → B32 对成本最高;B16/B8 packed 变体逐步降低(GL kTransposeB16 → Perm = 8/3kTransposeB8 → Perm = 4/3)。
  • vxpose 索引会倾斜成本。 在 Viperfish 上,kReduceB32 → kTransposeB3240 / 57 / 40 — 实例 1 比实例 0 和 2 多 +17,体现奇/偶 XLU-FIFO 端口不对称。Ghostlite 同样在 vxpose 0/1 间不同(例如 Perm → kTransposeB32 = 29/40)。Pufferfish vxpose 变化(每个对都在 0/1 上复制)。

值读取器 — XluConflictPenaltyBetween(LloValue*, LloValue*)

XluConflictPenaltyBetween(LloValue* A, LloValue* B) @ 0x1c8a01c0 是调度器用两个指令值调用的形式。它分类二者,强制同 MXU 不变量,然后要么走动态 transpose-reservation 虚拟路径,要么读取静态单元。逐字节如下:

c
int XluConflictPenaltyBetween(LloValue* A, LloValue* B):           // sub_1C8A01C0
    fromType = GetXluInstrType(A);
    toType   = GetXluInstrType(B);
    // both must have a valid MXU/unit id (bit 0x400 of WORD[v+0xb])
    CHECK(A.unit_id().has_value());                                // latency_table.cc:245
    CHECK(B.unit_id().has_value());                                // latency_table.cc:246
    CHECK(A.unit_id() == B.unit_id());                             // latency_table.cc:248 — SAME MXU
    if (LloInstruction::IsFinalTransposeInSequence(A)):
        CHECK(IsTranspose(GetXluInstrType(A)));                    // latency_table.cc:322/328
        m = A.vxpose_mode();
        h = A.GetTransposeHeight();  w = A.GetTransposeWidth();
        return this->vtable[+0x10](m, fromType, toType, A.unit_id()&3, h, w);  // XposeXLUReservationLatency
    vxpose = A.unit_id() & 3;                                      // MXU instance → table index
    if (vxpose == 3) ud1;                                          // instance 3 has no table column
    return cell[fromType][toType][vxpose];
```text

两个关键行为:**同 MXU `CHECK`**(`unit_id()` 是 `WORD[v+0xb]` 的 MXU 实例 bits 8-9,由 bit `0x400` 表示存在)意味着本表只定价*一个 MXU 实例内*的冲突 — 否则触发 `LOG(FATAL)`;**final-transpose 旁路**会把结束一个序列的 transpose 路由到动态的、高度/宽度相关的 `XposeXLUReservationLatency` 虚拟函数(`vtable[+0x10]`),而不是静态单元。该虚拟函数记录在 [Transpose-Reservation Latency](xpose-reservation-latency.md);在 Viperfish(`@0x1c8a4e60`)上它是 `XluConflictPenaltyBetween(fromType, toType, vxpose) + max(0, width − height) + 7` — 即静态单元**加上**数据形状项。

> **易错点 —** `vxpose` 索引是 MXU 实例 id,并且读取器会在实例 **3** 上陷入(`ud1`)。表只有三个 `vxpose` 列,但一个 TensorCore 可能有第 4 个 MXU 实例。冲突模型假设两个冲突操作永远不会同时落在实例 3;落在那里的一对操作会崩溃。(安装序列中没有 instance-3 路径可达 — VF/PF/GL 只填充列 0-2 — 因此这是调用方必须维持的真实不变量,不是死防御代码。)

---

## 调度器如何收取惩罚

冲突单元是 `LatencyTableViperfish::LatencyBetweenInternal` @ `0x1c8a4ac0` 在非真实依赖、非(MXU∧MXU)边上用**普通 MAX** 归约的几个 XLU 冒险项之一 — 与 MXU 结构冒险路径类似。XLU 分支逐字节如下:

```c
long LatencyBetweenInternal(LloValue* A, LloValue* B):              // VF sub_1C8A4AC0 (vtable+0x18)
    if ((WORD[A] - 233) < 4)  return 0;                             // ops 0xe9..0xec: no edge
    base = GetLatency(A);                                           // intrinsic op latency
    true_dep = this->vtable[+0x20](A, B);                           // IsTrueDependencyBetween (vtable+0x20)
    if (!true_dep && LloOpcodeUsesMxu(A) && LloOpcodeUsesMxu(B))
        return MxuLatencyTable::GetLatencyBetween(this+0x1d8, A, B);// not-true-dep ∧ both-MXU → MXU matrix

    // --- the XLU arm (this page) ---
    // true-dependency does NOT early-return; it only suppresses the MXU branch.
    // r seeds at base when true_dep, else at 0 (the not-true-dep, non-both-MXU case).
    r = (true_dep ? base : 0);
    if (HasSetPermutePatternReservation(A, B)):                     // both involve a set-permute push, same MXU
        rsv = GetXluPathReservation(A);                             // XLU-slot occupancy gate
        r = max(base, rsv);
        r = max(r, XluConflictPenaltyBetween(GetXluInstrType(A), GetXluInstrType(B), A.unit_id()&3));
    if (IsFinalTransposeFollowedByResult(A, B)):
        r = max(r, this->vtable[+0x30](A, B, base));                // LatencyBetweenXposeInstrAndResult
    if (ArePushesToSameXluFifo(A, B)):                              // both push the same XLU FIFO, same MXU
        r = max(r, XluConflictPenaltyBetween(A, B));               // the LloValue* form (final-transpose aware)
    if (IsIndexedStoreFollowedByLoad(A, B))  r = max(r, 5);
    if (IsSetIarFollowedByIndexedLoad(A, B)) r = max(r, 8);
    if (WORD[A] == 21 && WORD[B] == 22 && r < 31) r = 30;          // cross-lane-max → max-index fixup
    if (WORD[A] == 25 && WORD[B] == 26 && r < 37) r = 36;          // cross-lane-min → min-index fixup
    return max(r, GetResourceLatency(A, B));

因此,当两个跨 lane 操作在同一个 MXU 上 push 同一个 XLU FIFO 时,会收取 XLU 冲突惩罚 — 即相邻 permute/reduce/transpose 操作之间的结构冒险成本。它两次进入 MAX:一次通过类型索引单元(在 HasSetPermutePatternReservation 下),一次通过 LloValue* 形式(在 ArePushesToSameXluFifo 下;当生产者结束 transpose 序列时会分派到 final-transpose 虚拟路径)。真实数据依赖IsTrueDependencyBetweenvtable+0x20不会短路 XLU 分支 — 它只抑制 both-MXU 分支,并把运行 MAX r 的初值从 0 改为 base,因此冲突单元仍会被 MAX 折入。both-MXU MXU 矩阵分支只在该边不是真实依赖且两个操作都使用 MXU 时采用。

门控 helper(全部按字节确认):

Helper地址门控
HasSetPermutePatternReservation0x1c89fe00A/B 之一是 kVectorSetPermutePattern0x8b),LloInstructionPushesToXluFifos,同 unit id
ArePushesToSameXluFifo0x1c8a05a0二者都 LloInstructionPushesToXluFifos,同 unit id
IsFinalTransposeFollowedByResult0x1c8a0500A 是 final-in-sequence transpose,且喂给 B 的 result
GetXluPathReservation (VF)0x1c8a3200op 0x8b1(若字段 +0x40 置位则 8);否则 ViperfishPerformance::GetResourceUsage(instr, 14)

注意 — GetXluPathReservation@0x1c8a3200)特殊处理 op 0x8bkVectorSetPermutePattern):它返回 1,或在 +0x40 字段非零时返回 8;其他所有 op 返回 ViperfishPerformance::GetResourceUsage(instr, /*resource=*/14)0x8b 分支还运行一个软 LloCheckForFailure,确认 opcode 是 kVectorSetPermutePattern


交叉引用

  • XLU 操作清单GetXluInstrType 分类的 LLO 跨 lane opcode(0x36/0x3a/0x3b/0x8b/0xa6/0xa7/0xf5..0x101/…),以及在收取该成本前运行的 XLU 操作合并流水线。
  • Transpose-Reservation 延迟XposeXLUReservationLatencyvtable[+0x10])、final-transpose 旁路路由到的动态高度/宽度 transpose 路径,以及 VxposeMode 枚举。
  • XLU Combine / Source-BusComputeCombinablePairs / AssignSourceBus 与独立的 PreXluAssignmentLatencyTableceil(base / xlu_count))优化器边模型 — 不是本表。
  • XLU Reemit CostCyclesAddedByXluOperation,XLU 优化器通过自身延迟表消费的边际延迟函数。
  • MXU 延迟概览 — 本表对应的 MXU 结构冒险同级项(MxuLatencyTable::GetLatencyBetween);LatencyBetweenInternal 的第二个分支。
  • 资源枚举 — 23 槽 ResourceVector,其中 R[2] = Xlu 是该更细 per-(op,op) 冒险所细化的粗周期权重桶。
  • LLO Opcode 枚举GetXluInstrType switch 所用的 LloOpcode 编号。