Skip to content

VectorExtended (VEX)

本页中的每个 opcode 值、mask 立即数、字段 shift/width,以及逐代计数,都是从 libtpu-0.0.40-cp314 wheel(build-id 89edbbe81c5b328a958fe628a9f2207d)里的 libtpu.so 逐字节读取的 — 来源包括每个 op 的 SparseCoreTecVectorExtended<Op>Opcode::Matches() 比较立即数、…<Op><Field>Field::GetConcatenatedValue() 访问器 shift,以及 ConsumeOneTecVexBundleInstructionFindAndEmitToUnusedPort / EmitVectorSort 的分派。地址适用于此构建;其他版本会不同。

摘要

VectorExtended (VEX) 是 64 字节 TEC bundle 的 scan/sort/reduce 槽位 — 即 SparseCore 的跨 lane datapath。VectorAlu 是逐 lane SIMD,VectorLoad/VectorStoreTILE_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 fusionVstSource 驱动 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 是位于 word0x28 bits 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 — 已逐字节确认 AddScanS32MaxScanU32 相同。重新实现者解码一个框架,并为所有 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) 是一个 VexSourcePortEncoding selector,用于把 scan 的 carry-in 路由到 VectorLoad 所馈入的 V0..V3/VST read 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 bundleTecVectorExtended 槽位
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 familiesAddScan · 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 storeVstSource @ 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 BindingScanOp/SegmentedScanOp MLIR lowering 在 Scan DatapathSegmented ScanSourceOne seed 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

text
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 4

QUIRK — 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。 VectorMoveConstrainedVexDest 字段位于 word0x28 bit 10;反编译访问器(0x1ecab840)读取 (word0x28 >> 10) & 1 — 一个 1-bit EUP/XRF destination select。它与 Sort ops 的 3-bit SourceTwo 共享 bit 10,但两者从不同时出现(一个 bundle 是这个 op 或另一个 op)。word0x20 bits 53/47 处的 6-bit VresDestOne/VresDestTwo 已确认。

NOTE — SourceTwoVexDest 共享 word0x28 bit 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)。逐字节精确如下:

c
// 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 路由而来(SourceOneVexSource)。

输出接缝 — VstSource 进入 store mux

VstSource 字段(word0x30 >> 27 & 0x3f)位于 VectorStore 槽位读取其 Source确切 bit 位置 — 已逐字节确认相同:gfc VEX 访问器 0x1eca7c60 读取 (word0x30 >> 27) & 0x3f,gfc TileSpmemStore Source 访问器(0x1ecca3e0)读取相同的 word0x30 >> 27 & 0x3f

text
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/Matches op family 是完整的逐代 declared set(glc 52,gfc 53),但 glc VEX jump table 只到达其中 36 个(32 个 scan/dedup arm 通过 FindAndEmitToUnusedPort + 4 个 Sort arm 通过 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 字段位置不同。差异与 VectorStoreVectorAlu 槽位展示的 dtype-merged → dtype-split ISA 演进相同。

QuantityViperfish (vfc, v5)Ghostlite (glc, v6e)6acc60406 (gfc, TPU7x)
VectorExtended op count (Matches symbols)285253
VEX jump table 中分派的 ops2836(full emitter set)
Opcode field6-bit @ word0x28 bit 166-bit @ bit 156-bit @ bit 16
dtype namingFloat/Integer (merged)explicit S32/F32/S16/U32/U16/Bf16explicit, + PartialSum forms
PartialSum widening formsyesyes
VectorMoveConstrained (53rd op)yes
Operand frame (SourceOne/Vmask/VstSource/V0..V2)samesamesame

Viperfish 使用粗粒度 Float/Integer-merged 名称FloatAddScan, IntegerMaxScan, SegmentedFloatMinScan, IntegerMinIndexScan — 将每种 dtype 折叠为 FloatInteger(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::Matches mask (*(uint16_t*)(this+41)) & 0x1F80(word 0x28 的 bits 15..20);gfc mask byte+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)AddressRole
…VectorExtendedAddScanS32Opcode::Matches0x1eca7520op 0 predicate (byte+0x2a & 0x3f == 0) — base op
…VectorExtendedMaxScanU32Opcode::Matches0x1eca7560op 2 (& 0x3f0000 == 0x20000)
…VectorExtendedSortFloatDescendingOpcode::Matches0x1eca7b00op 23 (0x170000 >> 16)
…VectorExtendedVectorMoveConstrainedOpcode::Matches0x1eca7ba0op 52 (0x340000 >> 16) — gfc-only
…VectorExtendedAddScanS32SourceOneField0x1eca7c40SourceOne @ word0x28 >> 13 & 7 (seed-port selector)
…VectorExtendedAddScanS32VstSourceField0x1eca7c60VstSource @ word0x30 >> 27 & 0x3f (== VectorStore Source)
…VectorExtendedAddScanS32VmaskField0x1eca7d40Vmask @ word0x28 >> 5 & 0x1f
…VectorExtendedAddScanS32V2YVregField0x1eca7d00V2YVreg @ word0x30 >> 50 & 0x3f
…VectorExtendedAddScanS32V0YVregField0x1eca7c80V0YVreg straddling word0x38/0x40 (shld 4)
…VectorExtendedSortIntegerAscendingSourceTwoField0x1ecaade0SourceTwo @ word0x28 >> 10 & 7 (Sort key+payload)
…VectorExtendedVectorMoveConstrainedVexDestField0x1ecab840VexDest @ word0x28 >> 10 & 1 (1-bit; see VEX-1)
…VectorExtendedVectorMoveConstrainedVresDestOneField0x1ecab860VresDestOne @ word0x20 >> 53 & 0x3f
…VectorExtendedVectorMoveConstrainedVresDestTwoField0x1ecab880VresDestTwo @ word0x20 >> 47 & 0x3f
ConsumeOneTecVexBundleInstruction (glc)0x13a15ba0inline VEX orchestrator; main jump table dispatch
EmitVectorSort<…> (vfc)0x139d2dc04-arm sort emitter

跨代锚点:glc AddScanS32::Matches0x1eb2cd20)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* 类型贡献到此名册。loadstore 页面所述,重新实现者 grep VectorExtended 时必须过滤到 SparseCoreTec 前缀;逐代 namespace 是 gxc::gfc, gxc::glc, vxc::vfc


注意事项

  • 解码一个框架,并为所有 50 个 scan ops 复用它。 操作数框架是 op-invariant(AddScanS32MaxScanU32 逐字节相同)。只有 6-bit opcode 变化;只有 Sort* 增加 SourceTwo,只有 VectorMoveConstrainedVmask 换成 multi-dest fan-out。逐 op 字段表是浪费 — 按 family keyed 即可。
  • VstSource 是 store 接缝,不是 scan operand。 将其解码为 fused store-source port(== VectorStore Source)。把它建模为普通 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 个 Matches ops;emitter 只产生 reachable 36(glc)。不要按 emitter 名册确定 decoder 大小。
  • 未映射(LOW/inferred)。 逐周期 systolic scan / bitonic-sort lane datapath(silicon,不在 C++ 中);read-port allocator 为每个 operand 分配哪个 V0/V1/V2 port(VEX Operand-Port Binding);count×gradient multiplicity fold(Dedup Multiplicity);gfc bit 15 与 glc bit 21 之间的 adjacent-bit reassignment;V3_Y_VREG physical-port identity(第 4 read port vs VST alias,HIGH)。

相关组件

NameRelationship
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::SegmentedScanOp2-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;SourceOne seed enum 和 segment-operand binding 的归属处。
  • TEC Vector Opcode EnumerationVectorAlu 名册、本页复用的 opcode-recovery 模型,以及 scan 结果 drain 经过的 VectorResult XRF-drain 槽位。
  • VEX Operand-Port Binding — scan-emit 模板调用的 FindAndEmitToUnusedPort read-port allocator 主体。
  • VEX Mask / Dest-Port / Sub-Opcode — VEX opcode dispatch 下方的 mask 字段和 sub-opcode map。
  • Scan Datapath — 此槽位 reductions 馈入的 scan-input mask consumption 和 ScanOp lowering。
  • 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-id 89edbbe81c5b328a958fe628a9f2207d)
  • Index entry: Part IX — SparseCore & BarnaCore / SparseCore ISA — back to index