VectorExtended (VEX)
本页中的每个 opcode 值、mask 立即数、字段 shift/width,以及逐代计数,都是从
libtpu-0.0.40-cp314wheel(build-id89edbbe81c5b328a958fe628a9f2207d)里的libtpu.so逐字节读取的 — 来源包括每个 op 的SparseCoreTecVectorExtended<Op>Opcode::Matches()比较立即数、…<Op><Field>Field::GetConcatenatedValue()访问器 shift,以及ConsumeOneTecVexBundleInstruction到FindAndEmitToUnusedPort/EmitVectorSort的分派。地址适用于此构建;其他版本会不同。
摘要
VectorExtended (VEX) 是 64 字节 TEC bundle 的 scan/sort/reduce 槽位 — 即 SparseCore 的跨 lane datapath。VectorAlu 是逐 lane SIMD,VectorLoad/VectorStore 在 TILE_SPMEM 与 VREG 文件之间移动行,而 VEX 是归约引擎:它在一个 bundle 内跨 vector lane 计算 inclusive prefix scan、arg-extremum scan、key+payload sort,或 duplicate-count/uniquify。它是 embedding-reduce 流水线的 stage-3 reduce(gather → load → reduce → drain → scatter-add),也是结果通过共享 VstSource 字段直接馈入 store mux 的那个 op family。
决定性的结构事实是:VEX 是一个统一的操作数框架,只有 opcode 变化。所有 op 共享同一种 bit layout — 三个 V 操作数对(V0/V1/V2,每个都是 Y_VREG + X selector)、一个 SourceOne seed-port selector、一个 Vmask lane predicate,以及一个 VstSource fused-store port — 唯一随 op 变化的字段是 word0x28 bits 16..21 处的 6-bit opcode。op 就是函数;操作数按位置固定。两个 op 打破这个框架:四个 Sort 变体增加 SourceTwo 第二 source(key+payload),而 VectorMoveConstrained(仅 gfc 的 op 52)用三目的 fan-out(VexDest + VresDestOne + VresDestTwo)替换 Vmask。
本页负责三件事:VEX 槽位字段图(op-invariant operand frame,逐字节精确)、embedding-reduce op 名册(连续的 0..52 gfc opcode 空间、dtype/segmented/sort/dedup families,以及逐代 vfc-28 / glc-52 / gfc-53 差异),以及 load/store fusion(VstSource 驱动 VectorStore source mux;VexSource 通过 VexSourcePortEncoding 将一个 V read port 路由到 scan-input mux)。逐端口 read-allocator 主体(FindAndEmitToUnusedPort)归 VEX Operand-Port Binding;scan-input mask 消耗与 ScanOp lowering 归 Scan Datapath。这里链接它们,不重复展开。
对重新实现而言,契约是:
- opcode 是位于
word0x28bits 16..21 的扁平 6-bit function selector (gfc);53 个 op,连续 0..52。opcode = Matches_cmp_immediate >> 16。op 顺序按 family 组织 — 32-bit scans (0..9)、32-bit segmented scans (10..19)、sort/dup/uniquify (20..27)、16-bit/bf16 scans (28..39)、16-bit/bf16 segmented scans (40..51)、VectorMoveConstrained(52)。没有单独的 dtype 或 mode 操作数;两者都烘进 opcode 值里。 - 操作数框架是 op-INVARIANT。 每个 scan/segmented op 都携带相同的
{SourceOne, Vmask, VstSource, V0/V1/V2}layout — 已逐字节确认AddScanS32与MaxScanU32相同。重新实现者解码一个框架,并为所有 50 个 scan op 复用它;只有Sort(+SourceTwo)和VectorMoveConstrained(multi-dest)不同。 - scan 结果通过
VstSource融合 store 路径。VstSource(word0x30 >> 27 & 0x3f) 位于 VectorStore 槽位读取其Source的确切 bit 位置 — 因此 reduce 结果无需中间VectorStore-slot 指令即可直接驱动 store-source mux。 - scan 输入通过一个 V read port 融合 load 路径。
SourceOne(word0x28 >> 13 & 7) 是一个VexSourcePortEncodingselector,用于把 scan 的 carry-in 路由到 VectorLoad 所馈入的V0..V3/VSTread port;归约 identity(0, ±inf)是放入该端口的值,而不是硬连线 code。 - Segmented family 在逐 sample 边界重置 accumulator。 24 个
Segmented*op 与其普通 twin 携带相同框架;segment-id boundary 作为SegmentedScanOp的第二个 SSA operand(operand 1)绑定,并 register-allocated 到一个空闲 V read port。
| 槽位 | VectorExtended (VEX) — 64 字节 TEC bundle 的 TecVectorExtended 槽位 |
| Opcode 字段 | 6-bit @ word0x28 bits 16..21 (gfc);6-bit @ bit 15 (glc) — 见 §The Per-Gen Delta |
| Opcode → mnemonic 来源 | 每个 op 的 SparseCoreTecVectorExtended<Op>Opcode::Matches() 立即数 (>> 16) |
| Op 计数(逐代) | vfc 28 · glc 52 · gfc 53 (Matches symbol 名册);VEX jump table 中 glc 36 个被分派 |
| Op families | AddScan · Min/MaxScan · Min/MaxIndexScan · Segmented* · Sort · DuplicateCount · Uniquify · VectorMoveConstrained |
| 操作数框架 | op-INVARIANT: {SourceOne@13/3, Vmask@5/5} (word0x28) · {VstSource@27/6, V2*} (word0x30) · V0/V1 (word0x38/0x40) |
| Fused store | VstSource @ word0x30 >> 27 & 0x3f == VectorStore Source 位置 |
| Scan-emit 模板 | FindAndEmitToUnusedPort<…VregReadPort, …VectorExtended_<Op>> (scans) · EmitVectorSort<…> (sort) |
| 编排器 | ConsumeOneTecVexBundleInstruction (glc 0x13a15ba0, vfc 0x139a9de0) |
| 置信度 | CONFIRMED(decompile / Matches-immediate 与 accessor-shift 锚定),除非某行或 callout 另有说明 |
NOTE — 本页负责 VEX opcode 名册、op-invariant operand frame,以及 load/store fusion 接缝(
VstSource/SourceOne-VexSource)。 64 字节 bundle layout 在 TEC Engine;read-port allocator 主体在 VEX Operand-Port Binding;ScanOp/SegmentedScanOpMLIR lowering 在 Scan Datapath 和 Segmented Scan;SourceOneseed enum(8 个VexSourcePortEncoding值)在 VectorLoad。这里链接它们,不重复展开。
槽位字段图
目的
VectorExtended 槽位驱动 SparseCore 的 EUP (Extended Unit Pipeline) 跨 lane 归约。它从 VREG read ports 读取最多三个 V 操作数对,运行 opcode 的跨 lane 归约,用 lane Vmask 对结果 gating,并把结果路由到两个方向:到 XRF(Extended Result FIFO,由 VectorResult 槽位 drain)以及 — 通过 VstSource — 到 VectorStore source mux。seed/carry-in 输入由 SourceOne 选择。整个框架固定;只有 6-bit opcode 变化。
字段布局
已用 gfc AddScanS32 字段访问器(SparseCoreTecVectorExtendedAddScanS32<Field>Field::GetConcatenatedValue)逐字节确认,并验证与 MaxScanU32 逐字节相同 — 该框架是 op-invariant。这些字段跨越四个 8 字节 struct word(0x20, 0x28, 0x30, 0x38/0x40)。在反编译访问器中,*((_DWORD*)this + 10) 是 word 0x28 的 4 字节低半部分(10 × 4 = 0x28),*((_QWORD*)this + 6) 是 word 0x30:
VectorExtended slot — op-invariant scan frame (gfc; AddScanS32 reference)
word0x28 bit: 5 10 13 16 22
┌─────────┬─────────┬───────┬─────────┬──────────────┐
│ Vmask │ SrcTwo* │SrcOne │ Opcode │ Predication │
│ 5b @5 │ 3b @10 │ 3b @13│ 6b @16 │ (preg hdr) │
└─────────┴─────────┴───────┴─────────┴──────────────┘
Sort only seed the op
word0x30 bit: 27 50
┌─────────────────────────┬──────────┐
│ VstSource 6b @27 │ V2YVreg │ (V2X straddles word0x30 hi / word0x38)
│ (== VectorStore Source) │ 6b @50 │
└─────────────────────────┴──────────┘
word0x38/0x40: V0YVreg (shld 4: word0x38 hi / word0x40) · V0X @word0x40 bit8
V1YVreg @word0x38 bit23 · V1X @word0x38 bit35
word0x20 bit: 47 53 (VectorMoveConstrained only)
┌───────────┬───────────┐
│ VresDestTwo│VresDestOne│ 6b each — multi-destination fan-out
└───────────┴───────────┘
```text
| Field | Word | Shift | Width | 出现于 | Accessor (gfc) |
|---|---:|---:|---:|---|---|
| `Opcode` | `0x28` | 16 | 6 | 全部 | (Matches predicate, `byte+0x2a & 0x3f`) |
| `SourceOne` | `0x28` | 13 | 3 | 全部(scan seed-port selector) | `…AddScanS32SourceOneField` `0x1eca7c40` |
| `Vmask` | `0x28` | 5 | 5 | 除 `VectorMoveConstrained` 外全部 | `…AddScanS32VmaskField` `0x1eca7d40` |
| `VstSource` | `0x30` | 27 | 6 | 全部(fused store source) | `…AddScanS32VstSourceField` `0x1eca7c60` |
| `V0YVreg` | `0x38`/`0x40` | (shld 4) | 6 | 全部(operand-0 VREG) | `…AddScanS32V0YVregField` `0x1eca7c80` |
| `V1YVreg` | `0x38` | 23 | 6 | 全部(operand-1 VREG) | `…AddScanS32V1YVregField` `0x1eca7cc0` |
| `V2YVreg` | `0x30` | 50 | 6 | 全部(operand-2 VREG) | `…AddScanS32V2YVregField` `0x1eca7d00` |
| `SourceTwo` | `0x28` | 10 | 3 | 仅 `Sort*`(key+payload 第 2 src) | `…SortIntegerAscendingSourceTwoField` `0x1ecaade0` |
| `VexDest` | `0x28` | 10 | **1** | 仅 `VectorMoveConstrained` | `…VectorMoveConstrainedVexDestField` `0x1ecab840` |
| `VresDestOne` | `0x20` | 53 | 6 | 仅 `VectorMoveConstrained` | `…VectorMoveConstrainedVresDestOneField` `0x1ecab860` |
| `VresDestTwo` | `0x20` | 47 | 6 | 仅 `VectorMoveConstrained` | `…VectorMoveConstrainedVresDestTwoField` `0x1ecab880` |
访问器主体精确解码为:
```c
// SparseCoreTecVectorExtendedAddScanS32SourceOneField::GetConcatenatedValue (gfc 0x1eca7c40)
return (uint8_t)HIBYTE(*((uint16_t *)this + 20)) >> 5;
// *((uint16_t*)this+20) is the 16-bit @ byte 0x28; HIBYTE = byte 0x29 (bits 8..15);
// >>5 takes the top 3 bits = bits 13..15 of word0x28 → 3-bit @ bit13 (the seed-port selector).
// …AddScanS32VstSourceField::GetConcatenatedValue (gfc 0x1eca7c60)
return (*((uint64_t *)this + 6) >> 27) & 0x3F; // word0x30 bit27, 6-bit — SAME position as VectorStore Source
// …AddScanS32VmaskField::GetConcatenatedValue (gfc 0x1eca7d40)
return (*((uint32_t *)this + 10) >> 5) & 0x1F; // word0x28 bit5, 5-bit — lane predicate mask
// …AddScanS32V2YVregField::GetConcatenatedValue (gfc 0x1eca7d00)
return (*((uint64_t *)this + 6) >> 50) & 0x3F; // word0x30 bit50, 6-bit — operand-2 VREG
// …AddScanS32V0YVregField::GetConcatenatedValue (gfc 0x1eca7c80)
return (*(__int128 *)((char *)this + 56) >> 60) & 0x3F; // straddles word0x38(byte56)/0x40 — shld 4QUIRK —
VstSource是一个命名VectorStore资源的 VEX 字段。 重新实现者阅读 VEX op 模板时会看到一个 6-bit 字段,其含义是“scan 结果馈入的 store source”,而不是 scan operand。它是两个槽位之间的结构接缝;把它当作普通 VEX operand 会错误建模 fused write-back。见 §The Load/Store Fusion。NOTE —
VexDest是 1-bit 字段,不是 3-bit。VectorMoveConstrained的VexDest字段位于word0x28bit 10;反编译访问器(0x1ecab840)读取(word0x28 >> 10) & 1— 一个 1-bit EUP/XRF destination select。它与Sortops 的 3-bitSourceTwo共享 bit 10,但两者从不同时出现(一个 bundle 是这个 op 或另一个 op)。word0x20bits 53/47 处的 6-bitVresDestOne/VresDestTwo已确认。NOTE —
SourceTwo和VexDest共享word0x28bit 10,但它们属于不同 op,绝不会冲突。 只有Sort*携带SourceTwo(3-bit);只有VectorMoveConstrained携带VexDest(1-bit)。decoder 按 opcode 决定字段提取,因此同一个 bit region 会按 op 解释 — 这与 VectorStore 槽位用于其 mode 字段的同一种 opcode-keyed extraction 规则一致。
Embedding-Reduce Op 名册
opcode-recovery 模型
每个 VEX op-form 都是一个独立 C++ 类型 SparseCoreTecVectorExtended<Op>Opcode,携带一个 Matches() const predicate,用来从 decoded-instruction word 中 mask 出 opcode 字段,并与该 op 的 signature 比较。该字段是 word 0x28 bit 16 处的 6-bit(gfc;mask 0x3f0000),因此 opcode = cmp_immediate >> 16。base op(AddScanS32, 0)用 testb $0x3f, 0x2a(%rdi) 测试(+0x2a 处的 byte 是 word 0x28 的 bits 16..23;mask 0x3f 隔离 6 个 opcode bit,全零 ⇒ op 0)。逐字节精确如下:
// SparseCoreTecVectorExtendedAddScanS32Opcode::Matches (gfc 0x1eca7520)
return (*((uint8_t *)this + 42) & 0x3F) == 0; // byte +0x2a, opcode 0
// …MaxScanU32Opcode::Matches (gfc 0x1eca7560)
return (*((uint32_t *)this + 10) & 0x3F0000) == 0x20000; // 0x20000 >> 16 = 2
// …SortFloatDescendingOpcode::Matches (gfc 0x1eca7b00)
return (*((uint32_t *)this + 10) & 0x3F0000) == 0x170000; // 0x170000 >> 16 = 23
// …VectorMoveConstrainedOpcode::Matches (gfc 0x1eca7ba0)
return (*((uint32_t *)this + 10) & 0x3F0000) == 0x340000; // 0x340000 >> 16 = 52
```text
`*((uint32_t*)this + 10)` 是 word `0x28` 的低半部分。所有 53 个 gfc op `Matches()` 立即数均已枚举并解码;得到的 opcode 集合是**连续 0..52,无空洞,无重复**。
### 完整名册(gfc,53 ops,逐字节确认)
opcode 值决定 family 顺序:先是 32-bit scans,然后是 32-bit segmented,接着是 sort/dedup block,再到 16-bit/bf16 scans 及其 segmented forms,最后是 constrained move。每一行都是逐字节精确的 `Matches` immediate `>> 16`:
| op | mnemonic (`…VectorExtended…`) | family | dtype | reduction |
|---:|---|---|---|---|
| 0 | `AddScanS32` | AddScan | S32 | inclusive prefix sum |
| 1 | `MinScanU32` | MinScan | U32 | prefix min |
| 2 | `MaxScanU32` | MaxScan | U32 | prefix max |
| 3 | `MinIndexScanU32` | MinIndexScan | U32 | prefix arg-min (value + lane idx) |
| 4 | `MaxIndexScanU32` | MaxIndexScan | U32 | prefix arg-max |
| 5 | `AddScanF32` | AddScan | F32 | prefix sum |
| 6 | `MinScanF32` | MinScan | F32 | prefix min |
| 7 | `MaxScanF32` | MaxScan | F32 | prefix max |
| 8 | `MinIndexScanF32` | MinIndexScan | F32 | prefix arg-min |
| 9 | `MaxIndexScanF32` | MaxIndexScan | F32 | prefix arg-max |
| 10..19 | `Segmented{Add,Min,Max,MinIndex,MaxIndex}Scan{U32,F32}` | Segmented | U32/F32 | per-segment-reset scan |
| 20 | `SortIntegerAscending` | Sort | int | key+payload sort ↑ |
| 21 | `SortIntegerDescending` | Sort | int | key+payload sort ↓ |
| 22 | `SortFloatAscending` | Sort | float | key+payload sort ↑ |
| 23 | `SortFloatDescending` | Sort | float | key+payload sort ↓ |
| 24 | `DuplicateCountInteger` | DuplicateCount | int | per-value multiplicity |
| 25 | `DuplicateCountFloat` | DuplicateCount | float | per-value multiplicity |
| 26 | `UniquifyInteger` | Uniquify | int | compact to unique reps |
| 27 | `UniquifyFloat` | Uniquify | float | compact to unique reps |
| 28 | `AddScanS16PartialSumS16` | AddScan | S16→S16 | prefix sum, narrow partial |
| 29 | `AddScanS16PartialSumS32` | AddScan | S16→S32 | prefix sum, widened partial |
| 30..33 | `{Min,Max}{,Index}ScanU16` | scan | U16 | prefix min/max/arg |
| 34 | `AddScanBf16PartialSumBf16` | AddScan | Bf16→Bf16 | prefix sum, narrow partial |
| 35 | `AddScanBf16PartialSumF32` | AddScan | Bf16→F32 | prefix sum, widened partial |
| 36..39 | `{Min,Max}{,Index}ScanBf16` | scan | Bf16 | prefix min/max/arg |
| 40..51 | `Segmented…{S16,Bf16,U16,…}` | Segmented | 16-bit/bf16 | per-segment-reset scan |
| 52 | `VectorMoveConstrained` | move | — | multi-dest EUP/VRES move (gfc-only) |
连续性(0..52,无空洞/重复)已通过完整 `Matches`-immediate 枚举验证。反编译 spot-check 确认了每个 family 的代表行:op 0(`AddScanS32`, `testb 0x3f`)、op 2(`MaxScanU32`, `0x20000`)、op 23(`SortFloatDescending`, `0x170000`)、op 35(`AddScanBf16PartialSumF32`, `0x230000`)、op 46(`SegmentedAddScanBf16PartialSumBf16`, `0x2e0000`)、op 51(`SegmentedMaxIndexScanBf16`, `0x330000`)、op 52(`VectorMoveConstrained`, `0x340000`)。
> **NOTE — opcode *顺序*是 dtype-split 历史,而不是逻辑分组。** 32-bit families 位于最前(原始 v5 集合),sort/dedup block 位于中间(跨代稳定),16-bit/bf16 families 加 `VectorMoveConstrained` 追加在高 opcode — 这与 [VectorStore](vectorstore-slot.md#the-vfgf-generic-to-typed-evolution) 的 dtype-split 模式完全一致,新 dtype 是向上扩展 opcode 空间,而不是重新排序。重新实现者必须按 opcode *值*编码,绝不能按词典名顺序编码。
### op families — 跨 lane 语义
每个 family 都是一种独立的跨 lane 归约。名称 + 操作数框架 + [XRF drain](vector-opcode-enum.md) 模型决定语义;逐周期 lane datapath(systolic scan / bitonic-sort network)在 silicon 中,不在 C++ 中(micro-architecture 为 `HIGH`,op→semantics map 为 `CONFIRMED`)。
```text
VEX cross-lane reduction families
AddScan{S32,F32}, AddScan{S16,Bf16}PartialSum{narrow,wide}
out[i] = SUM(in[0..i]). PartialSum widens a narrow input (S16/Bf16) into a wider
partial (S16/S32 · Bf16/F32) — the precision-preserving embedding-row sum.
SourceOne selects the scan seed / carry-in source bus.
MinScan / MaxScan {U32,F32,U16,Bf16} out[i] = MIN/MAX(in[0..i]).
MinIndexScan / MaxIndexScan {U32,F32,U16,Bf16}
prefix arg-extremum: carries the LANE INDEX of the running min/max (recover WHICH
gathered embedding row was the extremum — top-k / argmax over a window).
Segmented<scan> same reduction, but the running accumulator RESETS at segment boundaries
(the segment-id boundary is operand 1 of SegmentedScanOp; see below).
SortInteger/Float Ascending/Descending key+payload sort: SourceOne=key, SourceTwo=payload
(sort the gathered ids, carry the associated value/row index).
DuplicateCount{Integer,Float} count repeated values (the multiplicity of each id).
Uniquify{Integer,Float} compact duplicate values to unique representatives.
VectorMoveConstrained multi-destination EUP/VRES move (VexDest + VresDest{One,Two}).Segmented family 在逐 sample 边界重置 running accumulator — 这是 multi-lookup / multi-sample embedding sum 所需的逐 segment prefix reduction,其中一个 tile 保存多个 sample 的 gathered rows,每个输出行聚合一个连续 run。Sort/Uniquify/DuplicateCount 三件套是 dedup-lookup 预处理:对 ids 排序,uniquify 使每个 unique row 只 fetched 一次,count duplicates 让 scatter-add 知道 multiplicity(Dedup Multiplicity 路径)。
Load/Store Fusion {#the-loadstore-fusion}
VEX 在归约的两端都接入 load 和 store 槽位。fusion 有两个不同接缝:scan 输出驱动 VectorStore source mux(VstSource),scan 输入从 VectorLoad 填充的一个 V read port 路由而来(SourceOne → VexSource)。
输出接缝 — VstSource 进入 store mux
VstSource 字段(word0x30 >> 27 & 0x3f)位于 VectorStore 槽位读取其 Source 的确切 bit 位置 — 已逐字节确认相同:gfc VEX 访问器 0x1eca7c60 读取 (word0x30 >> 27) & 0x3f,gfc TileSpmemStore Source 访问器(0x1ecca3e0)读取相同的 word0x30 >> 27 & 0x3f。
fused reduce → store (one TEC bundle, no VectorStore round-trip)
VectorExtended slot VectorStore slot
(scan / segmented-scan) (TileSpmemStore…Add{dt})
│ result │
└── VstSource @word0x30>>27 ───┘ Source @word0x30>>27 ◄── SAME bit position
(the scan/reduce output drives the store-source mux directly)
```text
由于 reduce 输出和 store source 占据同一字段,VEX reduction 可以直接驱动 store-source mux:reduced embedding row 无需中间 `VectorStore`-slot 指令即可流向 `TILE_SPMEM`。结果也会通过 XRF → [VectorResult](vector-opcode-enum.md) 路径 drain;两者并不互斥。这就是 embedding-reduce inner loop 比朴素 load-scan-store 序列使用更少 bundle 的原因 — scan *就是* store source。
### 输入接缝 — `SourceOne` 选择一个 V read port(`VexSource`)
`SourceOne`(`word0x28 >> 13 & 7`)**不是 constant-pool index** — 它是一个 3-bit `VexSourcePortEncoding` *selector*,把 scan 的 first/seed input 路由到 V0..V3 VREG read ports 或 `VST` source bus 之一。8 个 encoding(`VST_SOURCE`, `V0_Y_VREG`, `V0_X`, `V1_Y_VREG`, `V1_X`, `V2_Y_VREG`, `V2_X`, `V3_Y_VREG`)由 [VectorLoad §The SourceOne Seed Enum](vectorload-slot.md#the-sourceone-seed-enum) 负责并制表;它们由 `GhostliteProtoUtils::GetVexSourcePortEncoding(VregReadPort)`(gfc `0x1c5ee280`)交叉确认,这是一个 1:1 switch。
归约 identity element(`Add` 为 0,`Min`/`Max` 为 ±inf)是*放入被选端口的值* — 不是硬连线 `SourceOne` code。这就是跨 tile 链接 scan accumulator 的机制:把前一个 partial 写入选定 V port,将 `SourceOne` 设为该端口,然后 scan 带着这个 carry-in 继续。每个 op 的 read-port allocation(每个操作数落在哪个物理 port 上)由 `FindAndEmitToUnusedPort<…VregReadPort, …VectorExtended_<Op>>` 执行,并记录在 [VEX Operand-Port Binding](vex-operand-port.md)。
### Segmented boundary — operand 1,register-allocated
对于 embedding *sum*,scan 是 segmented;逐 sample reset boundary 绑定为 `mlir::sparse_core::SegmentedScanOp` 的**第二个 SSA operand**(operand 0 = data,operand 1 = segment_ids),而普通 `ScanOp` 只有单个 operand。SC isa_emitter 将每个 intrinsic operand register-allocate 到一个空闲 V read port(`FindAndEmitToUnusedPort`),因此 segment-id 会落在任一空闲的 `V0/V1/V2` port 上 — 这是 register-allocated operand,不是固定槽位。完整 lowering(`reduction_op` ∈ {`sum`, `max`, `min`} byte-comparison,`…_seg_scan2xN` vs `…_scan1xN` intrinsic-name operand count)归 [Segmented Scan](segmented-scan.md),并在 [VectorLoad](vectorload-slot.md#the-segmented-scan-boundary-operand) 页面总结。
---
## Scan-Emit 分派
`VectorExtended` **没有独立的 `Consume<Slot>Instruction`** — 不同于 `VectorAlu`/`VectorStore`(每个都有自己的 consumer 和 jump table),VEX 由 TEC VEX orchestrator *inline* 消耗。`ConsumeOneTecVexBundleInstruction`(glc `0x13a15ba0`,vfc `0x139a9de0`)读取 MCInst opcode,索引主 VEX jump table,并将每个 arm 分派到 scan-emit allocator 或 sort emitter:
```text
ConsumeOneTecVexBundleInstruction (glc 0x13a15ba0)
read opcode → main VEX jump table (base 0x106b)
per non-default arm:
GetVectorExtendedSlot + EmitPredicationToSlot<…VectorExtended>
cmp [slot+0x50], <oneof-tag> ── the arm's SparseCoreTecVectorExtended oneof tag
DefaultConstruct<…VectorExtended_<Op>>
GetVectorMask + GetVregno
└─ scan ops → FindAndEmitToUnusedPort<…SparsecoreVregReadPort, …VectorExtended_<Op>>
sort ops → EmitVectorSort<…SparsecoreVectorMask, …VregReadPort, …VectorExtended_Sort{…}>
VresMove (opcode 0x10de) → EmitVectorResultMove ── a VectorResult op, not VEX
default arm → MakeError "Unsupported Vector Extended or Vector Result opcode: $0 : $1"EmitVectorSort 以 {SparsecoreVectorMask, SparsecoreVregReadPort, SparseCoreTecVectorExtended_Sort{Integer,Float}{Ascending,Descending}} 为模板参数 — 已确认出现在反编译中(例如 vfc 0x139d2dc0/0x139d2b80)。FindAndEmitToUnusedPort 在各 engine 中有 111 个按 op 类型化的 …VregReadPort/…VectorExtended_<Op> instantiation。orchestrator 还 inline 承载一个 VectorResult op(VresMove, opcode 0x10de);其余 VectorResult family(EupResult, PopXrf*)由另一个 TEC orchestrator 分派。
GOTCHA — VEX
Matches名册(52/53 ops)大于 glc jump table 分派的集合(36)。 proto/Matchesop family 是完整的逐代 declared set(glc 52,gfc 53),但 glc VEX jump table 只到达其中 36 个(32 个 scan/dedup arm 通过FindAndEmitToUnusedPort+ 4 个Sortarm 通过EmitVectorSort);其余落到MakeError "Unsupported Vector Extended or Vector Result opcode"default。构建 decoder 的重新实现者需要完整Matches名册(这些 opcode 中任何一个都可能出现在 bundle 中并必须解码);构建 emitter 只需要其 lowering 会产生的 reachable set。两个计数衡量的是不同事物 — 不要混淆。reachable-set census 与 jump-table layout 归 code-gen 页面;本页负责Matches名册和字段解码。
逐代差异 {#the-per-gen-delta}
该槽位存在于全部三个 wired generations,具有相同的操作数框架和 orchestrator 结构,但 op 名册和 opcode 字段位置不同。差异与 VectorStore 和 VectorAlu 槽位展示的 dtype-merged → dtype-split ISA 演进相同。
| Quantity | Viperfish (vfc, v5) | Ghostlite (glc, v6e) | 6acc60406 (gfc, TPU7x) |
|---|---|---|---|
VectorExtended op count (Matches symbols) | 28 | 52 | 53 |
| VEX jump table 中分派的 ops | 28 | 36 | (full emitter set) |
| Opcode field | 6-bit @ word0x28 bit 16 | 6-bit @ bit 15 | 6-bit @ bit 16 |
| dtype naming | Float/Integer (merged) | explicit S32/F32/S16/U32/U16/Bf16 | explicit, + PartialSum forms |
PartialSum widening forms | — | yes | yes |
VectorMoveConstrained (53rd op) | — | — | yes |
Operand frame (SourceOne/Vmask/VstSource/V0..V2) | same | same | same |
Viperfish 使用粗粒度 Float/Integer-merged 名称 — FloatAddScan, IntegerMaxScan, SegmentedFloatMinScan, IntegerMinIndexScan — 将每种 dtype 折叠为 Float 或 Integer(28 ops)。Ghostlite 将每个拆分为逐 dtype 变体(AddScanF32 / AddScanS32 / MaxScanU32 / MaxScanU16 / MaxScanBf16 …),并加入 PartialSum widening forms(52 ops)。6acc60406 加入第 53 个 op,VectorMoveConstrained。gfc opcode 字段是 6-bit @ word0x28 bit 16;glc 字段位于 bit 15(base-op predicate mask byte 41 处 16-bit 的 0x1F80 — 比 gfc 低 1 bit 的位置)。decode VALUES 和操作数框架语义在其他方面跨代稳定。
QUIRK — glc opcode 字段比 gfc 低一 bit。 glc
AddScanS32::Matchesmask(*(uint16_t*)(this+41)) & 0x1F80(word0x28的 bits 15..20);gfc maskbyte+0x2a & 0x3f(bits 16..21)。面向 glc 的 decoder 必须读取(word0x28 >> 15) & 0x3f,而不是 gfc 的>> 16— 如果只检查 op count,这个 1-bit shift 会被 field width 掩盖。该 1-bit shift 已由 base-op predicate immediate 确认;gfc bit 15 / glc bit 21 被什么占用没有单独追踪(相邻 bit 重新分配为LOW)。
函数图
| Symbol (gfc) | Address | Role |
|---|---|---|
…VectorExtendedAddScanS32Opcode::Matches | 0x1eca7520 | op 0 predicate (byte+0x2a & 0x3f == 0) — base op |
…VectorExtendedMaxScanU32Opcode::Matches | 0x1eca7560 | op 2 (& 0x3f0000 == 0x20000) |
…VectorExtendedSortFloatDescendingOpcode::Matches | 0x1eca7b00 | op 23 (0x170000 >> 16) |
…VectorExtendedVectorMoveConstrainedOpcode::Matches | 0x1eca7ba0 | op 52 (0x340000 >> 16) — gfc-only |
…VectorExtendedAddScanS32SourceOneField | 0x1eca7c40 | SourceOne @ word0x28 >> 13 & 7 (seed-port selector) |
…VectorExtendedAddScanS32VstSourceField | 0x1eca7c60 | VstSource @ word0x30 >> 27 & 0x3f (== VectorStore Source) |
…VectorExtendedAddScanS32VmaskField | 0x1eca7d40 | Vmask @ word0x28 >> 5 & 0x1f |
…VectorExtendedAddScanS32V2YVregField | 0x1eca7d00 | V2YVreg @ word0x30 >> 50 & 0x3f |
…VectorExtendedAddScanS32V0YVregField | 0x1eca7c80 | V0YVreg straddling word0x38/0x40 (shld 4) |
…VectorExtendedSortIntegerAscendingSourceTwoField | 0x1ecaade0 | SourceTwo @ word0x28 >> 10 & 7 (Sort key+payload) |
…VectorExtendedVectorMoveConstrainedVexDestField | 0x1ecab840 | VexDest @ word0x28 >> 10 & 1 (1-bit; see VEX-1) |
…VectorExtendedVectorMoveConstrainedVresDestOneField | 0x1ecab860 | VresDestOne @ word0x20 >> 53 & 0x3f |
…VectorExtendedVectorMoveConstrainedVresDestTwoField | 0x1ecab880 | VresDestTwo @ word0x20 >> 47 & 0x3f |
ConsumeOneTecVexBundleInstruction (glc) | 0x13a15ba0 | inline VEX orchestrator; main jump table dispatch |
EmitVectorSort<…> (vfc) | 0x139d2dc0 | 4-arm sort emitter |
跨代锚点:glc AddScanS32::Matches(0x1eb2cd20)mask byte 41 处 16-bit 的 0x1F80 → opcode field 6-bit @ word0x28 bit 15(vs gfc bit 16)。逐代 Matches-symbol 计数 — vfc 28,glc 52,gfc 53 — 已通过逐 namespace 枚举重新确认;vfc 名称是粗粒度 Float/Integer-merged 集合(FloatAddScan, IntegerMaxScan, SegmentedFloatMinScan)。
NOTE —
TensorCoreVectorExtended*是不同 engine;只有SparseCoreTecVectorExtended*类型贡献到此名册。 如 load 和 store 页面所述,重新实现者 grepVectorExtended时必须过滤到SparseCoreTec前缀;逐代 namespace 是gxc::gfc,gxc::glc,vxc::vfc。
注意事项
- 解码一个框架,并为所有 50 个 scan ops 复用它。 操作数框架是 op-invariant(
AddScanS32≡MaxScanU32逐字节相同)。只有 6-bit opcode 变化;只有Sort*增加SourceTwo,只有VectorMoveConstrained将Vmask换成 multi-dest fan-out。逐 op 字段表是浪费 — 按 family keyed 即可。 VstSource是 store 接缝,不是 scan operand。 将其解码为 fused store-source port(==VectorStoreSource)。把它建模为普通 V operand 会错误建模 fused write-back。SourceOne是 port selector,不是常量。 归约 identity 是放入被选 V port 的值;把SourceOne当作 constant-pool index({0, ±inf})会错误建模跨 tile accumulator chaining。- glc opcode 字段在 bit 15,gfc 在 bit 16。 glc decoder 读取
(word0x28 >> 15) & 0x3f;gfc 读取>> 16。op values 跨代稳定;field position 移动了 1 bit。 Matches名册 ≠ jump-table reachable set。 decoder 需要全部 52/53 个Matchesops;emitter 只产生 reachable 36(glc)。不要按 emitter 名册确定 decoder 大小。- 未映射(LOW/inferred)。 逐周期 systolic scan / bitonic-sort lane datapath(silicon,不在 C++ 中);read-port allocator 为每个 operand 分配哪个
V0/V1/V2port(VEX Operand-Port Binding);count×gradientmultiplicity fold(Dedup Multiplicity);gfc bit 15 与 glc bit 21 之间的 adjacent-bit reassignment;V3_Y_VREGphysical-port identity(第 4 read port vs VST alias,HIGH)。
相关组件
| Name | Relationship |
|---|---|
SparseCoreTecVectorExtended<Op>Opcode::Matches | 定义 opcode 值的逐 op predicates(0..52 @ word0x28 bit 16) |
SparseCoreTecVectorExtendedAddScanS32<Field>Field (0x1eca7c40+ gfc) | op-invariant operand-frame accessors |
SparseCoreTecVectorStore*::Source (0x1ecca3e0 gfc) | VstSource 融入的 store-source field(相同 word0x30 bit 27) |
SparseCoreTecVectorLoad* (0x1ecb9a00+ gfc) | 馈入 SourceOne 所选择 V read ports 的 load |
GhostliteProtoUtils::GetVexSourcePortEncoding (0x1c5ee280) | 将 VregReadPort → 8 个 VexSourcePortEncoding 值 |
ConsumeOneTecVexBundleInstruction (0x13a15ba0 glc) | inline orchestrator;将 scans 分派到 FindAndEmitToUnusedPort,将 sorts 分派到 EmitVectorSort |
mlir::sparse_core::SegmentedScanOp | 2-operand segmented scan;operand 1 = segment-id boundary |
交叉引用
- TEC (Vector) Engine — 负责 64 字节 bundle、slot bases,以及 encoder-dispatch 模型。
- VectorStore Slot — 此槽位通过共享
VstSource/Source字段融入的 store;33-op type×mode scatter matrix。 - VectorLoad Slot — 馈入 V ports 的 read side;
SourceOneseed enum 和 segment-operand binding 的归属处。 - TEC Vector Opcode Enumeration —
VectorAlu名册、本页复用的 opcode-recovery 模型,以及 scan 结果 drain 经过的VectorResultXRF-drain 槽位。 - VEX Operand-Port Binding — scan-emit 模板调用的
FindAndEmitToUnusedPortread-port allocator 主体。 - VEX Mask / Dest-Port / Sub-Opcode — VEX opcode dispatch 下方的 mask 字段和 sub-opcode map。
- Scan Datapath — 此槽位 reductions 馈入的 scan-input mask consumption 和
ScanOplowering。 - Segmented Scan — per-segment-reset scan 及其
reduction_op∈ {sum, max, min} lowering。 - Segmented-Add-Scan — 较新代 segment-reduce family 及其
VpackFormat/partial-sum format attributes。 - Dedup Multiplicity — dedup-lookup 路径通过这些 VEX ops 运行的 Sort → Uniquify → DuplicateCount 预处理。
- SparseCore Overview — 三类 SC engine、逐代存在性,以及 TEC vector slots 所在位置。
- Binary:
extracted/libtpu-0.0.40-cp314-cp314-manylinux_2_31_x86_64/libtpu/libtpu.so(build-id89edbbe81c5b328a958fe628a9f2207d) - Index entry: Part IX — SparseCore & BarnaCore / SparseCore ISA — back to index