Skip to content

EUP 分世代延迟整数

本页所有地址都适用于 libtpu-0.0.40-cp314 wheel 中的 libtpu.so(build-id 89edbbe81c5b328a958fe628a9f2207d)。.text/.rodata VMA == 文件偏移。其他版本会有所不同。

摘要

Extended Unary Pipeline(EUP),也就是 libtpu 的超越函数近似器,是一个很深的、由 FIFO 缓冲的单元:它由某个 bundle 中的一次 push 驱动,并在一个或多个 bundle 之后由一次 pop 排出。调度器用一个整数为 push→pop 依赖边定价:push latency,即 pop 可以落后 push 的最小 bundle 数。这个整数就是编译器的 VALU-correction 软件流水必须隐藏的深度,因此它是整个超越函数成本模型中信息量最高的数字。本页是对所有带有 heap-grid Performance 对象的世代逐字节转录这个整数:构造函数发出的精确 latencies[Instruction] store、它写入的 Instruction ordinal 索引,以及得到的 push→pop 边权重。

较新世代的机制是统一的,相当于 libtpu 版的从 LLVM SchedMachineModel 中读出一个单元格。LatencyTable<Gen>::LatencyBetweenInternal 把 push opcode 解析为分世代的 Performance::Instruction ordinal(Get<Gen>Instruction),然后读取 <Gen>Performance::GetLatency(ordinal) = latencies[ordinal],这是一个扁平的 int32 heap 数组,指针在 Performance[0],元素计数在 Performance[+0x8]。构造函数在先导 memset(_, 0xff, _) 把每个未写槽位设为哨兵之后,用 mov dword ptr [array + Instruction*4], value store 逐元素填充该数组。因此恢复分世代 EUP 延迟就是恢复每个构造函数填充中 EUP-push ordinal 处的值,本页逐条 store 完成这件事。旧的 Jellyfish/Dragonfish 路径使用这个数组;它把边钳制到一个扁平常量(Performance[+0x30] = 4),这里只作为基线记录。

本页按每个 Performance 类组织为一个 ## 单元:Pufferfish TensorCore(variant 0)、Pufferfish BarnaCore(variant 1)、Viperfish、Ghostlite,以及 6acc60406 GhPerf twin;每个单元给出构造函数地址、固定数组基数的 new size、EUP push/pop store 偏移,以及整数。这些构造函数填充的网格(GetResourceUsage occupancy matrix)和 opcode→ordinal 分类器表位于 performance-* 兄弟页面和 slot 页面;本页只记录延迟行。

对于重新实现,其契约是:

  • 分世代 EUP push→pop 边整数:PF 7, VF 6, GL 13 (F32) / 14 (BF16), pop 1,以及它替代的旧式 clamp(Jf/Df 4)。
  • 精确的 latencies[] store:构造函数地址、new size → 数组基数、Instruction ordinal、字节偏移(ordinal*4)和值。
  • EUP push 值在每个 gen 的所有已分类 EUP 函数中统一(每种数据类型一个超越函数延迟),所以成本模型使用单个常量,而不是逐函数表。
  • Pufferfish variant<TensorCore, BarnaCore> 拆分:EUP 边是 TensorCore 数组(7);BarnaCore 是单独的 134-entry 数组,有自己的 6-cycle EUP block。
  • 这条延迟边与 VectorEupReservationCycles(EUP 发射速率)正交,绝不会乘以它。
读取路径<Gen>Performance::GetLatency(instr) = latencies[instr]int32,ptr@Perf[0],count@Perf[+0x8]
边选择器LatencyTable<Gen>::LatencyBetweenInternalGet<Gen>Instruction(push)GetLatency
PF push / pop7(Instr 0x67..0x6c)/ 1(Instr 0x76)— PufferfishPerformance ctor @0x1c8be080
VF push / pop6(Instr 0xcc..0xd2)/ 1(Instr 0x168)— ViperfishPerformance ctor @0x1c8c4840
GL push / pop13 F32(Instr 0x106..0x10f)· 14 BF16(Instr 0x110..0x118)/ 1(Instr 0x1c4)— ctor @0x1c8cbc80
旧式 clampJf/Df push→pop = 4Performance[+0x30],不是逐指令数组)
ReservationVectorEupReservationCycles JF/VF/GL = 1,PF = 2 — 与延迟正交(从不相乘)

查找及其两个锚点

目的

本页上的每个分世代延迟整数都由一个很小的 accessor 读取,并由一个构造函数写入。钉住两者才使该整数达到可重新实现的级别:accessor 证明 ordinal 如何索引数组,构造函数 store 证明该 ordinal 处的

Accessor

<Gen>Performance::GetLatency 在三个较新 gen 中逐字节一致,是一个带边界检查的 int32 数组 load:

c
int32 GetLatency(Performance* p, u32 instr):   // VF @0x1c8cbc20, PF-TC @0x1c8c3860,
    if (p->count <= instr)                      //   GL @0x1c8d36e0, PF-BC @0x1c8c47e0
        BUG()                                   // p->count is Performance[+0x8]
    return p->latency[instr]                    // p->latency is Performance[0]; int32 stride
```text

所以 EUP push 边是 `latency[Get<Gen>Instruction(push_opcode)]`。分类器 `Get<Gen>Instruction` 把 LLO push opcode(`0x128`..`0x13a`)和 `0x14e` pop 映射到分世代 `Instruction` ordinal;这些 ordinal 就是本页读取的索引。分类器表(VF/PF 密集 jump table,GL 的 258-entry 排序 `(u16,u16)` pair table)已转录在 [slot 页面](../isa/slot-eup-transcendental.md);这里仅关心得到的 ordinal。

### 构造函数 Store

每个 `Performance` 构造函数用 `operator new(size)` 分配延迟数组(所以 `size/4` 是基数),把它 `memset` 为 `0xff`,然后用 `mov dword ptr [array + ordinal*4], value` 覆写槽位。EUP 行是一段连续的同值 store。读取 EUP 延迟就是读取 EUP-push 偏移处的立即数值:

```text
ctor:
  rax = operator new(SIZE)        ; SIZE/4 = Instruction cardinality
  Perf[0]   = rax                 ; latency array pointer
  Perf[+8]  = Perf[+0x10] = COUNT ; element count (== SIZE/4)
  memset(rax, 0xff, SIZE)         ; sentinel = 0xffffffff
  ...
  cmp [Perf+8], ORDINAL ; jbe BUG ; rax = [Perf] ; mov [rax + ORDINAL*4], VALUE

注意 — store 中的字节偏移([rax+0x418],或反编译器十进制中的 [rax+412LL])始终是 ordinal*4。本页全程在同一行给出十六进制偏移和 ordinal,因此重新实现者可以用任一方向交叉核对:0x418 = 0x106*40x19c = 0x67*40x330 = 0xcc*4

怪癖 — 在 PF 上,memset 哨兵(0xff0xffffffff)永远不会到达消费者,因为全部 336 个槽位都会被覆写。在 GL/GF 上,0xff 会保留在未定价行。无论哪种情况,EUP 行都是显式 store,绝不是哨兵;重新实现必须写入它们。


Pufferfish — TensorCore Variant(push 7)

目的

PufferfishPerformanceLatencyTablePufferfish 定价的 variant<PufferfishPerformance, PufferfishBarnaCorePerformance> 中的 TensorCore 分支(variant 0)。每个 EUP opcode 都分类到 variant 0,因此 Pufferfish EUP push→pop 边就是 TensorCore 数组值。

边整数

角色LLO opcodeInstruction字节偏移
EUP push (rsqrt)0x12c0x670x19c7
EUP push (pow2)0x1290x680x1a07
EUP push (log2)0x12b0x690x1a47
EUP push (tanh)0x1280x6a0x1a87
EUP push (recip)0x12a0x6b0x1ac7
EUP push (pushErf)0x1310x6c0x1b07
EUP pop0x14e0x760x1d81

PufferfishPerformance ctor @0x1c8be080operator new(0x540) = 1344 B = 336 int32Perf[+8] = Perf[+0x10] = 336memset(array, 0xff, 1344)。六个 EUP-push store 是连续的(mov [rax+412LL]=7[rax+432LL]=7,十进制 412 = 0x19c432 = 0x1b0),pop store 是 mov [rax+472LL]=1472 = 0x1d8)。该值在全部六个已分类 F32 EUP 函数中统一为 7

注意 — Pufferfish kVectorSigShftF320x12d)push 落入分类器默认分支,GetPufferfishInstruction 没有为它发出 variant-0 ordinal,这与其他六个 F32 push 不同。按统一 EUP 模式,它的有效边最可能是 7,但 ordinal 未被钉住(推断)。全部六个已分类 PF EUP 函数都是 7。


Pufferfish — BarnaCore Variant(push 6)

目的

Pufferfish 是最后一个带 BarnaCore embedding engine 的世代。LatencyTablePufferfish 在一个 std::variant 中持有两个网格;2-arm __fmatrix LatencyFromInstruction visitor(@0x21c203d0)为旧式 embedding-engine op 选择 variant 1,即 PufferfishBarnaCorePerformance。Variant 1 是一个单独的 134-entry 数组,有自己更低的 EUP block。

Variant Dispatch

variant index 是 GetPufferfishInstruction 返回值的高 16 bit;LatencyTablePufferfish::LatencyBetweenInternal@0x1c8a2aa0)对它移位(shr r14d,0x10)并调用 fmatrix[variant]。两个 dispatch 分支读取 Instruction 的方式不同:

c
dispatch<0>(holder):   // @0x1c8a3140 — TensorCore
    return PufferfishPerformance::GetLatency(holder[0], (u16)*instr)   // 16-bit ordinal

dispatch<1>(holder):   // @0x1c8a3160 — BarnaCore
    return PufferfishBarnaCorePerformance::GetLatency(holder[8], (u8)*instr)  // 8-bit ordinal
```text

BarnaCore 分支把 `Instruction` 作为**字节**(`unsigned __int8 *`)读取,并从 `[holder+8]` 加载 BarnaCore holder(TensorCore 则是 `[holder+0]`),这在 `<1ul>` dispatcher 体中逐字节确认。每个 EUP push opcode 都发出 variant 0,所以 Pufferfish EUP **7;下面的 BarnaCore block 通过 `PufferfishBarnaCoreChannelEmitter` 到达,而不是通过 LLO-level EUP push 到达,并为旧 embedding-engine 超越函数定价。

### 边整数

| 角色 | `Instruction` | 字节偏移 ||
|---|---|---|---|
| BarnaCore EUP/transcendental block | `0x77`..`0x7c`(6 entries) | `0x1dc`..`0x1f0` | 6 |
| `kBarnaCoreScalarSyncDoneRead` | `0x3d` | `0xf4` | 3 |
| `kBarnaCoreVectorStore`(memory op) | `0x85` | `0x214` | 12 |
| no-op / null slot | `0x01` | `0x04` | 0 |

`PufferfishBarnaCorePerformance` ctor `@0x1c8c38c0`:`operator new(0x218)` = 536 B = **134** `int32`;`memset(array, 0xff, 536)`;`Perf[+8] = 134`。EUP block 是六个连续的 `mov [rax+476LL]=6` … `[rax+496LL]=6` store(十进制 `476 = 0x1dc` … `496 = 0x1f0`);VectorStore store 是 `[rax+532LL]=12`(`532 = 0x214`)。134-entry 数组主要由 1-cycle scalar/sync op 组成;恢复出的非默认值为六个 `6`(EUP block)、一个 `12`(VectorStore)、两个 `3`、两个 `4` 和一个 `0`,即旧 embedding-engine 延迟模型。

> **怪癖 —** BarnaCore EUP block 是 **6 cycles,比 TensorCore EUP(7)少一个 cycle**6-entry 宽度与 6-function TensorCore EUP block 形状匹配,而更便宜的 EUP 在结构上也与更小的 134-entry BarnaCore ISA 一致。`0x77..0x7c` 的精确 BarnaCore-`Instruction`→函数名没有钉住,这些 ordinal 通过 channel emitter 到达,而没有 `BarnaCoreInstructionToString`(推断该 block 是 embedding-engine 超越函数)。

---

## Viperfish(push 6

### 目的

`ViperfishPerformance` 是第一个单网格较新 gen,没有 variant,也没有 BarnaCore。`LatencyTableViperfish::LatencyBetweenInternal`(`@0x1c8a4ac0`)直接运行 `GetViperfishInstruction(push)` → `GetLatency`。

### 边整数

| 角色 | LLO opcode | `Instruction` | 字节偏移 ||
|---|---|---|---|---|
| EUP push (rsqrt) | `0x12c` | `0xcc` | `0x330` | 6 |
| EUP push (pow2) | `0x129` | `0xcd` | `0x334` | 6 |
| EUP push (log2) | `0x12b` | `0xce` | `0x338` | 6 |
| EUP push (tanh) | `0x128` | `0xcf` | `0x33c` | 6 |
| EUP push (sigshft) | `0x12d` | `0xd0` | `0x340` | 6 |
| EUP push (recip) | `0x12a` | `0xd1` | `0x344` | 6 |
| EUP push (pushErf) | `0x131` | `0xd2` | `0x348` | 6 |
| EUP pop | `0x14e` | `0x168` | `0x5a0` | 1 |

`ViperfishPerformance` ctor `@0x1c8c4840`:`operator new(0x600)` = 1536 B = **384** `int32`;`Perf[+8] = Perf[+0x10] = 0x180`(384);`memset(array, 0xff, 1536)`。七个 EUP-push store 连续为 `mov dword ptr [rax+0x330],6` … `[rax+0x348],6`(`@0x1c8c5d4a`..`@0x1c8c5dec`),pop store 是 `mov dword ptr [rax+0x5a0],1`(`@0x1c8cadff`)。Viperfish 分类**全部七个** F32 EUP push(包括 `sigshft`,不同于 PF),且值统一为 6

> **注意 —** Viperfish 的 `SupportsBf16AluInstructions` 为 FALSE,因此晚期 decomposer 会把 BF16 超越函数加宽为 F32 push;BF16 EUP opcode(`0x132`..`0x13a`)落入分类器默认分支,没有单独的 BF16 延迟槽。因此 VF 只有*一个* EUP 延迟(6),而 Ghostlite 会拆分它。

---

## Ghostlite(push 13 F32 / 14 BF16)

### 目的

`GhostlitePerformance` 是生产 V5e/V6e 级表。Ghostlite 有原生 BF16 ALU(`SupportsBf16AluInstructions` TRUE),所以它的分类器把 **F32 push 和 BF16 push** 都映射到不同延迟槽;它是唯一按数据类型拆分 EUP 延迟的 gen。`LatencyTableGhostlite::LatencyBetweenInternal`(`@0x1c8b22e0`)→ `GetGhostliteInstruction`(排序 `(u16,u16)` pair table `@0x4067dc8`)→ `GetLatency`。

### 完整 9-Transcendental Block

构造函数填充一个连续 F32 run(`Instruction 0x106..0x10f`,全为 13)和一个连续 BF16 run(`0x110..0x118`,全为 14)。**没有逐函数偏差**:`tanh = pow2 = log2 = rsqrt = sigshft = recip = pushErf = sinq = cosq = erf`,在每种数据类型内都相同。成本模型可以把 VALU-correction 窗口定为单个 GL EUP 常量(13/14),而不是逐函数表。

| 函数 | F32 push opc | F32 `Instr` | F32 lat | BF16 push opc | BF16 `Instr` | BF16 lat |
|---|---|---|---|---|---|---|
| rsqrt | `0x12c` | `0x106` | 13 | `0x136` | `0x110` | 14 |
| pow2 (2^x) | `0x129` | `0x107` | 13 | `0x133` | `0x111` | 14 |
| log2 | `0x12b` | `0x108` | 13 | `0x135` | `0x112` | 14 |
| tanh | `0x128` | `0x109` | 13 | `0x132` | `0x113` | 14 |
| sigshft | `0x12d` | `0x10a` | 13 | `0x137` | `0x114` | 14 |
| recip | `0x12a` | `0x10b` | 13 | `0x134` | `0x115` | 14 |
| pushErf | `0x131` | `0x10c` | 13 ||||
| sinq | `0x12e` | `0x10d` | 13 | `0x138` | `0x116` | 14 |
| cosq | `0x12f` | `0x10e` | 13 | `0x139` | `0x117` | 14 |
| erf | `0x130` | `0x10f` | 13 | `0x13a` | `0x118` | 14 |
| **EUP pop** | `0x14e` | `0x1c4` | **1** | (same) | (same) | **1** |

所有行都确定。F32 有 10 个 entry(`0x130 kVectorErfF32` ** `0x131 kVectorPushErf` 都被分类);BF16 有 9 个(没有单独的 push-form erf)。

### 边整数

`GhostlitePerformance` ctor `@0x1c8cbc80`(干净符号 `_ZN3xla9ghostlite20GhostlitePerformanceC1Ev`):`operator new(0x770)` = 1904 B = **476** `int32`;`Perf[+8] = Perf[+0x10] = 0x1dc`(476);`memset(array, 0xff, 1904)`。三段连续 store run:

| Block | Ordinals | 字节偏移 || Store window |
|---|---|---|---|---|
| F32 EUP push (10) | `0x106`..`0x10f` | `0x418`..`0x43c` | `0xd` (13) | `@0x1c8cd80f`..`@0x1c8cd902` |
| BF16 EUP push (9) | `0x110`..`0x118` | `0x440`..`0x460` | `0xe` (14) | `@0x1c8cd91d`..`@0x1c8cd9f5` |
| EUP pop | `0x1c4` | `0x710` | `1` | `@0x1c8d2864` |

> **注意 —** GL F32 EUP 填充是**十个**连续槽位 `0x106..0x10f`,全为 13,包括 `sinq`/`cosq`/`erf` F32(`0x10d..0x10f`),在偏移 `0x418..0x43c` 处逐字节确认;9 个 BF16 槽位 `0x110..0x118` 全为 14。每个 EUP 函数共享一个逐精度延迟,没有逐函数离群值(没有 `erf`/`sigshft` 偏差),因此 GL 不需要逐函数 EUP 延迟表。
>
> **注意 —** BF16 push 多花一个 cycle(14 vs 13)。这是 GL 保留 16-bit lane(`SupportsBf16AluInstructions` TRUE)在延迟层面的体现:GL 支付一个不同的 BF16 EUP 延迟,而 VF/PF 解包到 F32 并支付单个 F32 延迟。[`performance-gl`](performance-gl-ghperf.md) / [`performance-gf`](performance-gf-ghperf.md) 页面上的 192/182212/204 数字是 EUP-*prep* 网格带成本量级,与这个 push→pop 延迟边不同。

---

## 6acc60406 GhPerf Twin(push ~10 F32 / ~11 BF16 — 低)

### 目的

`6acc60406` 线(GF)的 GhPerf 对象由一个不同的构造函数 `sub_1C8D3740` 构建,结构上与 `GhostlitePerformance` 布局相同,但 instruction set 为 465 行(而 GL 为 476)。它的 cycle-table twin `GfcCycleTable` 在 `cycle_table.cc` `FunctionRegistry` 中紧跟 `GlcCycleTable`(ghostlite)之后注册,绑定到 post-ghostlite `TpuVersion`。它填充自己的延迟数组,****共享 GL 的实例,并且 EUP 形状的 block 携带与 GL 不同的整数。

### 边整数

| Block | 字节偏移(与 GL 相同) ||
|---|---|---|
| F32 EUP-shaped run (head, 3 slots) | `0x410`..`0x418` | 2 |
| F32 EUP-shaped run (rest, 9 slots) | `0x41c`..`0x43c` | `0xa` (10) |
| BF16 EUP-shaped run (9 slots) | `0x440`..`0x460` | `0xb` (11) |
| post-BF16 tail | `0x464`..`0x46c` | 1 |
| pop-position slot | `0x710` | 2 |

`sub_1C8D3740`:`operator new(0x744)` = 1860 B = **465** `int32`(比 GL 的 476 少一行);`Perf[+8] = Perf[+0x10] = 0x1d1`(465);`memset(_, 0xff, 0x744)`。延迟填充不同于 GL。`0x410..0x460` 处的 store 逐字节精确且连续:三个 `mov [rax+off],2` 位于 `0x410`/`0x414`/`0x418`(`@0x1c8d5367`..`@0x1c8d539d`),九个 `mov [rax+off],0xa` 位于 `0x41c..0x43c`(`@0x1c8d53b8`..`@0x1c8d5490`),九个 `mov [rax+off],0xb` 位于 `0x440..0x460`(`@0x1c8d54ab`..`@0x1c8d5583`),随后从 `0x464` 开始是 `1`;pop-position slot `0x710` 是 `2`(`@0x1c8d97d1`)。

> **陷阱 —** GF 值在这些偏移处逐字节精确,但本分析**没有追踪** GF opcode→`Instruction` 分类器,而且 F32 EUP 形状 run 并不统一:开头是**三个**值为 2 的槽位(`0x410`/`0x414`/`0x418`),随后九个值为 10 的槽位(`0x41c..0x43c`)。这个拆分打破了 GL 的每数据类型单值形状,证明 GF `Instruction` enum 与 GL 并非 1:1465 vs 476 行会移动映射),所以按偏移类比把 `0x418` 读作 “GF rsqrt” 并不可靠。不要假设 GF EUP push 边按偏移类比就是 10/11。在 GF 分类器被解码之前,这些偏移到 EUP 超越函数的绑定置信度为低;只有 `LatencyTableGhostlite`(一个实例,`@0x1c8b22e0`)被确认会把 *Ghostlite* push→pop 边路由到 `GhostlitePerformance::GetLatency`。

---

## 旧式基线 — Jellyfish / Dragonfish(clamp 4

Pufferfish 之前的家族不使用逐指令延迟数组来表示 EUP 边。`LatencyTableJellyfish::LatencyBetweenInternal`(`@0x1c8a0d60`)在第一个 opcode 是裸 push(`∈ [0x128, 0x13a]`)且第二个是 `0x14e` pop 时,把边钳制到 `this+0x1c`,构造函数从 `Performance[+0x30]` = 4 复制该值。Dragonfish 继承相同 clamp。因此 Jf/Df 上的 EUP push→pop 边是扁平的 **4**,也就是同一个概念(最小 push→pop bundle 间隔)通过单个逐表字段表达,而不是逐 `Instruction` 数组。这是这些 gen 上唯一的 EUP 延迟;数组机制是 Pufferfish 及以后才有的构造。

---

## 分世代汇总表

| Gen | EUP push latency | Pop latency | 机制 | 构造函数 | Push byte anchor |
|---|---|---|---|---|---|
| Jellyfish | 4 | (clamp) | `Performance[+0x30]` = 4 clamp | `LatencyTableJellyfish` | n/a(扁平字段) |
| Dragonfish | 4(继承 Jf) | (clamp) | `PerformanceDf` 保持 `+0x30` = 4 | (inherits) | n/a |
| Pufferfish (TensorCore) | 7 | 1 | `latency[0x67..0x6c]` | `@0x1c8be080` | `[rax+0x19c..0x1b0]=7` |
| Pufferfish (BarnaCore) | 6 | (via channel emitter) | `latency[0x77..0x7c]` | `@0x1c8c38c0` | `[rax+0x1dc..0x1f0]=6` |
| Viperfish | 6 | 1 | `latency[0xcc..0xd2]` | `@0x1c8c4840` | `[rax+0x330..0x348]=6` |
| Ghostlite | 13 (F32) / 14 (BF16) | 1 | `latency[0x106..0x118]` | `@0x1c8cbc80` | `[rax+0x418..0x43c]=0xd` / `[0x440..0x460]=0xe` |
| `6acc60406` (GF, LOW) | ~10 / ~11(仅偏移) | ~2 | `latency[0x410..0x460]` | `sub_1C8D3740` | `[rax+0x41c..0x43c]=0xa` / `[0x440..0x460]=0xb` |

上面每个值都是 *push* 延迟,即 push→pop 依赖图边权重。pop 自身的延迟(PF/VF/GL 上为 1)是排出的 EUP 结果在 pop 之后向下游携带的延迟。

---

## Latency vs Reservation — 不是乘积

EUP push→pop 边由**两个从不同数组读取的独立量**约束;重新实现者如果把它们相乘会得到错误调度:

| Quantity | Bounds | Source | PF | VF | GL (F32/BF16) | JF |
|---|---|---|---|---|---|---|
| push→pop data latency | min bundles push → its drain (pop) | `latency[Get<Gen>Instr(push)]` | 7 | 6 | 13 / 14 | 4 (clamp) |
| pop latency | latency the drained value carries | `latency[pop Instr]` | 1 | 1 | 1 ||
| `VectorEupReservationCycles` | min bundles push → *next* push | Target accessor (vtable `+0x480`) | 2 | 1 | 1 | 1 |

`LatencyTable::LatencyBetween`(`@0x1c89f820`)调用分世代 `LatencyBetweenInternal`(`call [rax+0x18]`),可选地加一个 uniform-random jitter,只对 matres/transpose opcode(`0x82`/`0x84`)特殊处理 MXU floor,并对 EUP push **原样**返回该边。路径上没有任何地方乘以 reservation 字段。分世代 `LatencyBetweenInternal` 主路径(GL general arm、VF wrapper `@0x1c8a4480`)会应用 transpose-latch halving(`latency/2`,带 `(lat & 0x80000001)==1` round-up 修正),由 `LatchModeIsTranspose(operand)` 门控,即 `if (!LatchModeIsTranspose(...)) latency = latency/2 + ...`。EUP push 不是 transpose/latch-mode op,所以 halving 不会应用于它,`latency[Instruction]` 会逐字通过。

`VectorEupReservationCycles` 是正交的 EUP-unit **issue occupancy**:一次 push 后 EUP 资源保持 reserved 的 bundle 数,由逐指令资源模型(`GetResourceUsage` matrix + `SlotTracker` reservation)应用,而不是由延迟边应用。组合方式是 `max(latency-deadline, resource-availability)`,从不是乘积:pop 不会早于 `push_bundle + latency` 放置;连续 push 的间隔不小于 `reservation` 个 bundle。

> **陷阱 —** 延迟边**不会**按 reservation 缩放。Pufferfish 的半速 EUP(reservation 2)约束的是*发射速率*(每 2 个 bundle 一次 push),不是 push→pop 窗口;push 返回未经修改的 `latency[Instruction]`。decomposer 必须填充的 VALU-correction 软件流水深度等于**延迟**(PF 7),与 reservation 无关。PF 上 N 个独立超越函数的链在 EUP 上受限于约 2·(N−1) + 7 个 bundle(受发射速率限制的间隔加最终排出),而不是 7·2

---

## 函数映射

| 函数 | 地址 | 作用 |
|---|---|---|
| `LatencyTable::LatencyBetween` | `0x1c89f820` | dispatcher;原样返回 EUP 边 |
| `LatencyTableJellyfish::LatencyBetweenInternal` | `0x1c8a0d60` | Jf/Df EUP clamp 到 `Performance[+0x30]` = 4 |
| `LatencyTablePufferfish::LatencyBetweenInternal` | `0x1c8a2aa0` | 通过 `shr r14d,0x10` → `fmatrix` 选择 variant |
| `LatencyTableViperfish::LatencyBetweenInternal` | `0x1c8a4ac0` | VF EUP 边经 `GetViperfishInstruction` → `GetLatency` |
| `LatencyTableGhostlite::LatencyBetweenInternal` | `0x1c8b22e0` | GL/GF EUP 边经 `GetGhostliteInstruction` → `GetLatency` |
| `__fmatrix LatencyFromInstruction` visitor | `0x21c203d0` | 2-arm `variant<TensorCore,BarnaCore>` dispatch |
| `dispatch<0ul>` / `dispatch<1ul>` | `0x1c8a3140` / `0x1c8a3160` | TensorCore(u16 ordinal)/ BarnaCore(u8 ordinal) |
| `PufferfishPerformance` ctor | `0x1c8be080` | 填充 TensorCore EUP push = 7,pop = 1 |
| `PufferfishBarnaCorePerformance` ctor | `0x1c8c38c0` | 填充 BarnaCore EUP block = 6,VectorStore = 12 |
| `ViperfishPerformance` ctor | `0x1c8c4840` | 填充 EUP push = 6,pop = 1 |
| `GhostlitePerformance` ctor | `0x1c8cbc80` | 填充 F32 EUP = 13,BF16 = 14,pop = 1 |
| `sub_1C8D3740` (GF GhPerf ctor) | `0x1c8d3740` | 填充 465-row 数组;EUP-shaped block 10/11(绑定为低置信度) |
| `<Gen>Performance::GetLatency` | `0x1c8cbc20` (VF), `0x1c8c3860` (PF-TC), `0x1c8d36e0` (GL), `0x1c8c47e0` (PF-BC) | `latency[Instruction]` heap lookup |
| `GetGhostliteInstruction` | `0x1c8b1740` | 排序 `(u16,u16)` pair table `@0x4067dc8`(258 entries) |

---

## 交叉引用

- [EUP 延迟概览](eup-latency-overview.md) — push→pop 软件流水模型,以及这个整数位于成本模型中的位置
- [Slot — EUP 与超越函数](../isa/slot-eup-transcendental.md) — push/pop 编码、分类器表,以及 latency-vs-reservation 正交性的完整说明
- [Performance: PF](performance-pf.md) — 336-row PF 网格、variant dispatch,以及 EUP push 网格 occupancy
- [Performance: VF](performance-vf.md) — 384-row VF 网格,以及为什么 VF 只通过延迟数组为 EUP push 定价
- [Performance: GL (GhPerf 476×31)](performance-gl-ghperf.md) — 476-row GL 网格和 EUP-prep band 成本量级(192/182
- [Performance: GF (GhPerf 465×31)](performance-gf-ghperf.md) — 由 `sub_1C8D3740` 构建的不同 465-row `6acc60406` GhPerf 实例
- [EUP 修正系数](eup-correction-coeffs.md) — 该延迟窗口隐藏的 Newton/rational refinement 系数
- [Payne-Hanek 范围归约](eup-paynehanek.md) — 与 sinq/cosq EUP push 配对的 trig 1/(2π) 归约