TEC(向量)引擎
本页中的每个地址、位偏移、opcode 宽度以及按代际划分的计数,都是从
libtpu-0.0.40-cp314wheel(BuildID md589edbbe81c5b328a958fe628a9f2207d)里的libtpu.so按字节精确读取的,来源包括反混淆后的 C++ 符号表、嵌入的 proto 描述符字符串,以及反编译得到的逐槽Encoder::Encode函数体(BitCopy目标位立即数)。其他版本会有所不同。
摘要
TEC,即 Tile Execute Core,codec-template TpuSequencerType = 5,是 SparseCore 的宽向量数据通路,也是每次 embedding lookup 真正执行计算的引擎。SCS 是运行 program counter 并发起 launch 的标量控制定序器,TAC 是(仅 VF/GL 存在的)tile-fetch DMA 发起器,而 TEC 是计算机器:它从每 tile SRAM(TILE_SPMEM)中 vector-load embedding tile,执行逐样本 reduction、scan、sort、uniquify,小浮点格式的 pack/unpack,以及梯度 scatter-add。最接近的熟悉类比是一个 VLIW SIMD core:三个并发 vector-ALU lane,加上一个 vector load、一个 vector store、一个 transcendental(“extended”)单元和一个 result-pop 槽,全都在一个 bundle 中发射;它还连接了一个小型标量前端,该前端逐字复用 SCS 标量模板。TEC bundle 是 SCS 控制程序通过 LaunchTileTaskOp 启动的循环体;SCS 程序才是循环。
TEC bundle 是一个 64 字节(512 位)的 VLIW word,物理宽度与 TAC bundle 相同,但与 TAC 不同,它把宽度用于真实计算。低位区域(bits 7..191)是相同的 SCS 布局:四个 20 位立即数、vector-scalar bridge、scalar-misc 槽和两个 scalar-ALU lane。bit 191 之上是向量计算区域(6acc60406 上为 bits 195..474),TAC 和 SCS 会让它为空:两个额外立即数槽,随后是 VectorResult、VectorExtended、VectorLoad、VectorStore,以及堆叠的三个 vector-ALU lane Alu2/Alu1/Alu0。codec dispatcher 会把同一个输出缓冲区 Span 交给每个槽 encoder,因此每个 BitCopy(dst, dst_bitoff, …) 都写入绝对 bundle 位偏移;下面的槽图由这些立即数恢复。
TEC 是逐代增长的引擎,并且增长是因为它吸收了其他引擎卸下的工作。它的 vector-ALU opcode 集合从 Viperfish 的 148 个增长到 Ghostlite 的 229 个,再到 6acc60406 的 257 个;opcode 字段从 7 位加宽到 8 位,槽从 36 位加宽到 37 位以容纳它;而在 6acc60406 上,它接管了 TAC 原先拥有的 tile-fetch 发起职责,因为 SC-MLO 编译器在任何代际都不发出 "access"(TAC)函数;每个 tile_task body 都被 outline 成一个 TEC "execute" 函数,其 Stream 槽负责发起 gather。本页记录 codec 身份、64 字节 bundle 及其槽基址字节/位偏移、向量操作清单指针、VF-vs-Execute(access-region-vs-execute-region)拆分规则和立即数槽索引,以及证明其增长的反编译计数。
对重实现而言,契约是:
- TEC 是 codec-template
TpuSequencerType = 5,也是唯一带向量路径的 SC 引擎。 它由SparseCoreTecCodecBase<…, TpuSequencerType=5>(LN3tpu16TpuSequencerTypeE5Etemplate 字面量)编码,存在于全部三个 SC 代际。codec 模板枚举其槽 {Encoder,Decoder} 对;向量槽(TecVectorAlu0/1/2、…VectorLoad、…VectorStore、…VectorExtended、…VectorResult)是它区别于 SCS/TAC 的结构性特征。 - 64 字节 bundle 复用 SCS 低位区域(bits 7..191),并在其上方增加向量区域。 六个 20 位立即数槽(4 个低位 @7/27/47/67 + 2 个高位 @195/215)、三个 27 位标量槽(Misc/Alu1/Alu0 @111/138/165,与 SCS 按字节相同),再加上向量计算区域(
VectorResult@239、VectorExtended@261、VectorLoad@283、VectorStore@328、VectorAlu2/1/0在 6acc60406 上为 @364/401/438)。没有0x55check trailer;全零 bundle 是 NOP。 - 37 位 vector-ALU 模板(6acc60406):四个 6 位 VREG selector、一个 8 位 OPCODE @+24、双通道谓词 header。 Viperfish 是窄 36 位形式(7 位 OPCODE),匹配它的 148-op 集合。三个 lane 相隔一个槽宽堆叠;按代际的宽度差会向上累积(VF Alu0 @432,GF Alu0 @438)。
- 引擎分配是字符串属性,并且不存在 MLIR 层面的 Access/Execute 拆分。 outliner 会给 tile_task body 标记
sc.sequencer="execute"(TEC),给包围的控制程序标记"scs";它从不标记"access"。TAC(“access”)的 tile-fetch 角色在所有代际都由 TEC 自己的 Stream 槽承载,这解释了 TEC 为什么增长,也解释了为什么重实现者永远不应生成"access"函数。
| 引擎 | TEC — Tile Execute Core(SparseCore 向量数据通路) |
| 定序器 enum(codec-template) | TpuSequencerType = 5 (TPU_SEQUENCER_TYPE_SPARSE_CORE_TILE_EXECUTE_CORE_SEQUENCER) |
| Codec 根 | SparseCoreTecCodecBase<…, TpuSequencerType=5> (vxc.vfc / gxc.glc / gxc.gfc);…E5E template 字面量 |
| Bundle 大小 | 64 字节 / 512 位;无 0x55 check trailer(全零 = NOP) |
| 活动区域 | bits 7..474(低 SCS 区域 7..191 + GF 上的向量区域 195..474) |
| 向量槽 | VectorResult · VectorExtended · VectorLoad · VectorStore · VectorAlu0/1/2 |
| Vector-ALU opcode | 8 位(GF/GL)· 7 位(VF);槽 37 位(GF/GL)· 36 位(VF) |
| Vector-ALU op 计数 | VF 148 · GL 229 · GF 257(逐代增长) |
SparseCoreTec* 反编译函数 | vfc 5244 · glc 7803 · gfc 8636(增长;对比 TAC 932/952/0) |
| 存在于 | Viperfish · Ghostlite · 6acc60406(并在 6acc60406 上吸收 TAC 的角色) |
| 置信度 | CONFIRMED(反编译 / BitCopy 立即数锚定),除非某行或标注另有说明 |
QUIRK — 两套 enum 编号;本页使用 C++/codec 编号(TEC = 5)。 C++
tpu::TpuSequencerTypeenum 编号为{3 = SCS, 4 = TAC, 5 = TEC},作为 codec 上的非类型模板字面量携带;这已在 gfcSparseCoreTecCodecBase符号的LN3tpu16TpuSequencerTypeE5E后缀中按字节验证(16 个 gfc 命名空间SparseCoreTec*符号携带该字面量,三代合计 32 个)。同一 C++ 编号也是TpuSequencerTypeToString渲染的编号,并且SparseCoreTargetgeometry descriptor 用它索引TpuCoreParts(tile-execute geometry 读取于 C++ sequencer-type 5 = TEC)。存在 off-by-one 的对应物是 protobuf enumTpuSequencerTypeProto,它保留INVALID=0,因此编号为{… SCS = 4, TAC = 5, TEC = 6};TpuSequencerTypeFromProto会在任何内存内使用前把它减一转换为 C++ enum。对 TEC codec、引擎名和TpuCoreParts索引都使用 5(与 overview、scs-engine、tac-engine 一致);只有原始TpuSequencerTypeProto字段携带 TEC = 6。不要混用两者。
Codec 和定序器身份
用途
TEC 与 SCS 和 TAC 一样,由其 codec 上作为非类型模板参数携带的 tpu::TpuSequencerType 值选择。操作级别没有任何东西命名引擎;引擎分配是包围的 outlined function 上标记的 sc.sequencer 字符串属性("execute")(见下文 The Access/Execute Split),而下游读回的 codec template enum(5)会选择此 codec。
入口点
TpuSequencerType = 5 (TILE_EXECUTE_CORE_SEQUENCER)
└─ SparseCoreTecCodecBase<SparseCoreTecBundle, TecScalarSubBundle,
SparseCoreTecScalarAlu0{Decoder,Encoder}, ── scalar lane 0 (TEC variant)
SparseCoreTecScalarAlu1{Decoder,Encoder}, ── scalar lane 1 (TEC variant)
SparseCoreScalarMisc{Decoder,Encoder}, ── misc/sync/atomic (shared)
SparseCoreImmediates{Decoder,Encoder}, ── 6 × 20-bit immediates
SparseCoreVectorScalar{Encoder,Decoder}, ── scalar→vector bridge
SparseCoreTecDma{Decoder,Encoder}, ── DMA slot (TEC variant)
SparseCoreTecStream{Decoder,Encoder}, ── stream slot (TEC variant)
SparseCoreTecVectorAlu0{Decoder,Encoder}, ── vector lane 0 ┐
SparseCoreTecVectorAlu1{Decoder,Encoder}, ── vector lane 1 ├ the vector
SparseCoreTecVectorAlu2{Decoder,Encoder}, ── vector lane 2 │ path TAC/SCS
SparseCoreTecVectorLoad{Decoder,Encoder}, ── tile vector load lack
SparseCoreTecVectorStore{Decoder,Encoder}, ── tile vector store
SparseCoreTecVectorExtended{Decoder,Encoder}, ── scans/sort/uniquify
SparseCoreTecVectorResult{Decoder,Encoder}, ── XRF pop / write
…, SparseCoreTecProgram, TpuSequencerType=5>
├─ Encoder<…>::EncodeBundle ── alloc 64 B, memset 0, dispatch each slot encoder
│ └─ each <Slot>Encoder::Encode(this, Message, absl::Span<uchar> buf) ── SAME buf to all
│ └─ BitCopy(dst=buf, esi=dst_bitoff, src, src_bitoff, r8d=nbits) ── LE bit packer (0x1fa0a900)
└─ Encoder<…>::BundleSizeBytes ── codec_metadata.vtable[+0x30]() → 64 (gfc 0x1e8359e0)Codec 模板参数列表
被混淆的 SparseCoreTecCodecBase 模板名本身就是槽清单;该 codec 精确枚举它必须驱动的槽 {Encoder,Decoder} 对。下面的向量槽是它与 TAC 的结构性差异,后者的 codec 模板中没有这些槽。每个槽消费一个 proto-enum opcode 空间。
| 槽 {Enc,Dec} 类 | 角色 | 它消费的 op-enum |
|---|---|---|
TecScalarSubBundle | 两个标量 lane 的 wrapper | (结构性) |
SparseCoreTecScalarAlu0 / …Alu1 | 标量/地址 ALU lane(TEC 变体) | SparseCoreScalarAlu |
SparseCoreScalarMisc | scalar misc / sync / atomic 槽(与 SCS 共享) | SparseCoreScalarMisc |
SparseCoreImmediates | 6 × 20 位立即数槽(注意:不是 …ScalarImmediates) | SparseCoreImmediates |
SparseCoreVectorScalar | scalar→vector 值桥接(共享) | SparseCoreVectorScalar |
SparseCoreTecDma / SparseCoreTecStream | DMA / stream 槽(TEC 变体;标量 lane 的 oneof) | SparseCoreDma / SparseCoreStream |
SparseCoreTecVectorAlu0 / …Alu1 / …Alu2 | 三个并发 vector ALU lane(计算) | SparseCoreTecVectorAlu |
SparseCoreTecVectorLoad | tile vector load(TileSpmemLoad*) | SparseCoreTecVectorLoad |
SparseCoreTecVectorStore | tile vector store + scatter-add(TileSpmemStore*[Add]) | SparseCoreTecVectorStore |
SparseCoreTecVectorExtended | scan / segmented scan / sort / uniquify(类似 transcendental) | SparseCoreTecVectorExtended |
SparseCoreTecVectorResult | 把 XRF(extended-result FIFO)pop 到 VRF | SparseCoreTecVectorResult |
NOTE — 立即数槽是
SparseCoreImmediates,不是 SCS 的SparseCoreScalarImmediates,并且有六个。 SCS 携带四个 20 位立即数槽;TEC 携带六个(四个低位 @7/27/47/67 + 两个高位 @195/215)。额外两个存在,是因为向量 op 通过VectorY6 位 selector 引用 literal,并且需要比标量程序更多的槽;见 Immediate-Slot Indexing。
Bundle 大小 — BundleSizeBytes
EncoderBase<… gfc Tec …>::BundleSizeBytes(gfc 0x1e8359e0)不返回字面量;它分派到 codec-metadata vtable:return (*(codec_metadata->vtable[+0x30]))(codec_metadata),即 vtable 槽 6;该函数对 sequencer type 5 返回 64。Viperfish metadata 函数体证明了允许它的掩码:
function ViperfishCodecMetadata_BundleSizeBytesForHbm(this, seq): // 0x1ee71380
result = 32 // seq == 3 (SCS)
if seq != 3:
result = 64 // TAC or TEC
if (seq & 0xFFFFFFFE) != 4: // seq not in {4,5} → FATAL
LOG(FATAL) << "Unhandled component" // codec_metadata_viperfish.cc:31
return result(seq & 0xFFFFFFFE) != 4 掩码只允许 seq ∈ {4, 5}(TAC、TEC)进入 64 字节分支。因此 TEC(seq 5)= 64 字节,与 TAC 相同,不同于 32 字节 SCS。与所有 SC bundle 一样,没有 0x55 check trailer;EncodeBundle wrapper 在 dispatch 前用 memset 把缓冲区清零,全零 bundle 是规范的“所有槽 inactive” NOP。packed 大小(任何槽写入的最高位,在 DMA pad 到 64 之前)在 6acc60406 上为 GetBytesPerBundle = 0x3c = 60(gfc 0x13923a80),在 Viperfish 上为 0x3b = 59(vfc 0x13933660);Viperfish 小一个字节,是因为它的向量 lane 是 36 位而非 37 位。
TEC Bundle(64 字节)
布局
bundle 为 512 位。低位区域(bits 7..191)与 SCS bundle 是相同槽栈:四个立即数、vector-scalar bridge 和三个 27 位标量槽;在 VF/GL/GF 上按字节相同。bit 191 之上是向量计算区域,SCS 和 TAC 会让它为空。位偏移是绝对值(dispatcher 会把同一个缓冲区 Span 传给每个槽 encoder);下图为 6acc60406(gfc),从每个 SparseCoreTecVector*Encoder::Encode 内部的 BitCopy 目标立即数恢复。
TEC bundle — 64 bytes / 512 bits (gfc / 6acc60406)
bit: 0 7 87 111 138 165 195 239 261 283 328 364 401 438 475 511
┌────┬──────────────┬───────┬────┬────┬────┬────────┬──────┬──────────┬───────┬──────┬─────┬─────┬─────────┬─────────┐
│rsvd│ Immediates │Vector │Sc │Sc │Sc │Immed. │Vector│ Vector │Vector │Vector│Vec │Vec │ Vector │ rsvd / │
│7b │ (low) 4×20b │Scalar │Misc│Alu1│Alu0│(high) │Result│ Extended │Load │Store │Alu2 │Alu1 │ Alu0 │ pad │
│hdr │ @7/27/47/67 │bridge │op │op │op │2×20b │op │ op@261… │op │op │op │op │ op@462 │ 37 bits │
│ │ │24b │@127│@154│@181│@195/215│@239 │ (scan/ │@283 │@353 │@388 │@425 │ (8-bit) │ │
└────┴──────────────┴───────┴────┴────┴────┴────────┴──────┴ sort)────┴───────┴──────┴─────┴─────┴─────────┴─────────┘
◄──────────── SCS low region (bits 7..191, identical to SCS) ─────────►◄────────── TEC vector region (bits 195..474) ──────────►
TecDma (oneof of a scalar lane): scalar opcode @181, high payload @283/@322
TecStream(oneof of a scalar lane): scalar opcode @181/@162, high payload @283/@322| 槽 | Base | End | Width | Opcode bit | 内部模板 |
|---|---|---|---|---|---|
| (reserved header) | 0 | 6 | 7 | — | bundle prefix;含义未解码 |
Immediates (low) | 7 | 86 | 80 | — | 4 × 20-bit(@7,@27,@47,@67) |
VectorScalar | 87 | 110 | 24 | — | scalar→vector bridge |
ScalarMisc | 111 | 137 | 27 | 127 | 27 位标量模板 |
ScalarAlu1 (lane 1) | 138 | 164 | 27 | 154 | 27 位标量模板 |
ScalarAlu0 (lane 0) | 165 | 191 | 27 | 181 | 27 位标量模板 |
Immediates (high) | 195 | 234 | 40 | — | 2 × 20-bit(@195,@215) |
VectorResult | 239 | 260 | 22 | 239 | XRF-pop(EupResult/PopXrf…) |
VectorExtended | 261 | 461 | ~201 | 261 (EUP) | scan/sort/uniquify 区域;复用 VREG operand |
VectorLoad | 283 | 321 | 39 | 283 | TileSpmemLoad* |
VectorStore | 328 | 363 | 36 | 353 | TileSpmemStore*[Add] |
VectorAlu2 (lane 2) | 364 | 400 | 37 | 388 | 37 位向量模板 |
VectorAlu1 (lane 1) | 401 | 437 | 37 | 425 | 37 位向量模板 |
VectorAlu0 (lane 0) | 438 | 474 | 37 | 462 | 37 位向量模板 |
| (reserved / pad) | 475 | 511 | 37 | — | 任何槽 encoder 都不写入 |
TecDma (oneof of lane) | 87 | 327 | — | 181; 283/322 | 标量 opcode + 高位 payload |
TecStream (oneof of lane) | 99 | 327 | — | 181/162; 283/322 | 标量 opcode + 高位 payload |
QUIRK — 立即数槽被标量 lane 分隔开。 四个 20 位槽位于标量栈下方(bits 7..86),另两个位于其上方(bits 195/215),中间隔着 81 位标量槽栈和 vector-scalar bridge。它们仍然是单个 6-entry indexed array(slot index 0..5),按降序 bundle 位顺序打包(idx0→bit67 … idx3→bit7;idx4→215,idx5→195)。重实现者不能把高位一对视为单独资源;
EmitImmediate(slot_index, value)索引全部六个槽(见 Immediate-Slot Indexing)。QUIRK — Dma/Stream 槽会伸入向量区域;它们不只在低位区域中。 与 SCS/TAC Dma/Stream(descriptor 保持在 bits 87..142)不同,TEC Dma/Stream 槽是标量 lane 的 oneof(opcode @181 lane 0,stream mirror @162),但会把其高位 descriptor 字段溢出到 bits 283/322,重叠 vector-load/store 区域。这就是单个 TEC bundle 能同时发起 tile-fetch DMA 并发起消费它的 vector load 的方式:Stream 槽的 indirect operand 位于 bundle bit 322(
IndirectVregStreamindirect-offset 字段)。如果重实现者把 TEC Stream descriptor 限制在低位区域,就会重复占用向量槽。
Encoder Dispatch 和共享缓冲区
codec dispatcher(SparseCoreTecCodecBase<…>::Encode)是一个很薄的循环,依次调用每个成员槽 encoder,并把同一个输出缓冲区交给它们。Viperfish dispatcher(0x139328a0,vfc codec Encode)在每个逐槽调用之间保持 rdx=buf.ptr(在 %r14 中)和 rcx=buf.len(在 %rbx 中)不变;只有 rdi 成员 encoder 指针不同。(下面的伪代码列出 gfc dispatch 顺序和 gfc encoder 地址;gfc codec 列出 14 个 encoder 槽;vfc codec 在 gfc 的 Immediates 位置携带一个 VectorImmediates 槽,所以成员顺序不同。)随后每个 encoder 用通用 LE packer BitCopy(dst, dst_bitoff, src, src_bitoff, nbits)(0x1fa0a900)打包其字段;dst_bitoff 立即数是绝对 bundle 位。
function SparseCoreTecCodecBase_Encode(bundle, buf): // gfc dispatch order
ImmediatesEncoder.Encode( bundle, msg, buf.ptr, buf.len) // @7/27/47/67/195/215 (0x1ecd1760)
VectorScalarEncoder.Encode( bundle, msg, buf.ptr, buf.len) // @87..110 (0x1ecd1e00)
ScalarMiscEncoder.Encode( bundle, msg, buf.ptr, buf.len) // @111..137 op@127 (0x1ebad840)
TecScalarAlu1Encoder.Encode(bundle, msg, buf.ptr, buf.len) // @138..164 op@154 (0x1ebd8040)
TecScalarAlu0Encoder.Encode(bundle, msg, buf.ptr, buf.len) // @165..191 op@181 (0x1ebc54a0)
VectorResultEncoder.Encode( bundle, msg, buf.ptr, buf.len) // @239..260 op@239 (0x1ecbc9e0)
VectorExtendedEncoder.Encode(bundle,msg, buf.ptr, buf.len) // @261..461 op@261 (0x1ecab8a0)
VectorLoadEncoder.Encode( bundle, msg, buf.ptr, buf.len) // @283..321 op@283 (0x1ecb9ee0)
VectorStoreEncoder.Encode( bundle, msg, buf.ptr, buf.len) // @328..363 op@353 (0x1eccbe20)
VectorAlu2Encoder.Encode( bundle, msg, buf.ptr, buf.len) // @364..400 op@388 (0x1ec85ae0)
VectorAlu1Encoder.Encode( bundle, msg, buf.ptr, buf.len) // @401..437 op@425 (0x1ec51900)
VectorAlu0Encoder.Encode( bundle, msg, buf.ptr, buf.len) // @438..474 op@462 (0x1ec11100)
TecStreamEncoder.Encode( bundle, msg, buf.ptr, buf.len) // oneof: op@181/162, high@283/322 (0x1ebe33e0)
TecDmaEncoder.Encode( bundle, msg, buf.ptr, buf.len) // oneof: op@181, high@283/322 (0x1ebb6960)
// buf is zero-initialized by EncodeBundle; no check-byte epilogue written.37 位 Vector-ALU 槽模板
布局
三个 vector-ALU lane 共享同一个内部模板;只有槽基址不同。槽相对偏移按字节精确地由 gfc VectorAlu0 encoder(0x1ec11100)确认:其 BitCopy 调用把四个 6 位 VREG selector 写入 @438/444/450/456,把 8 位 opcode 写入 @462,并把谓词 header 写入 @470/3、@473/1、@470/4、@474/1:
37-bit vector-ALU slot (gfc; slot-relative; absolute = slot_base + offset)
+0 w6 VREG operand selector 0
+6 w6 VREG operand selector 1
+12 w6 VREG operand selector 2
+18 w6 VREG operand selector 3
+24 w8 OPCODE 8-bit (≤ 256 — matches the 257-op gfc set)
+32 w3 normal_predication SparsecoreNormalPredication
+32 w4 rotate_predication overlaps normal when is_rotate (16-entry ring)
+35 w1 predication_inversion
+36 w1 is_rotate_predication因此绝对 opcode 位是 base + 24:VectorAlu2 op @388(= 364+24)、VectorAlu1 @425(= 401+24)、VectorAlu0 @462(= 438+24)。三个 lane 以 37 位间隔直接堆叠在 vector load/store 区域上方。
| Lane | Base (GF) | VREG sel | OPCODE @+24/8 | pred header @+32 |
|---|---|---|---|---|
VectorAlu2 | 364 | 364/370/376/382 | 388 | 396/399/400 |
VectorAlu1 | 401 | 401/407/413/419 | 425 | 433/436/437 |
VectorAlu0 | 438 | 438/444/450/456 | 462 | 470/473/474 |
vector-ALU 模板是标量模板的结构近亲:27 位 scalar slot 携带两个/一个 5 位寄存器 operand 和一个 6 位 opcode,而向量槽携带四个 6 位 VREG selector 和更宽的 opcode,并在顶部使用相同的重叠 normal/rotate 谓词 header。VectorY 立即数 selector 位于 vector-scalar bridge / immediate-indexing 路径中,而不是内联在这里(见 Immediate-Slot Indexing)。
NOTE — 谓词 header 是一个 3 位/4 位重叠区,不是两个字段。
normal_predication(3 位)和rotate_predication(4 位)共享同一起始位@+32;1 位is_rotate_predication@+36选择解释方式。重实现者必须分配一个有两种含义的 4 位字段,而不是 3+4 个不同位。Viperfish 使用单通道形式:只有 4 位rotate_predication@+31加一个 1 位 inversion/is-rotate@+35,没有单独的 3 位 normal 字段;这 1 位差异使 VF 槽为 36 位。
向量操作清单
清单指针
TEC 的七个向量槽来自七个不同的 proto-enum 空间;每个 opcode、每个代际都会发出一个 C++ op-form type(SparseCore<Slot><OpName>Opcode),其 Matches() 谓词像标量 op 一样精确携带 opcode 签名(谓词形状见 SCS roster)。完整的逐槽、逐代清单归 Vector Opcode Enum 所有;下面的类别和逐代计数提供框架。VectorExtended 槽,也就是 scan、segmented scan、sort、uniquify,是 embedding-reduce 的核心,并在 VectorExtended (VEX) 中详述。
| 槽 | VF | GL | GF | 代表性 op(GF) |
|---|---|---|---|---|
VectorAlu(×3 lane) | 148 | 229 | 257 | VectorAdd{Bf16,F32,S16,S32}, VectorMultiply*, Tanh{Bf16,F32}, Reciprocal*, FP8/FP4 PackCompressed*/UnpackCompressed*, VmskAnd/Or/Xor, lane permute/scan helpers |
VectorLoad | 5 | 5 | 5 | TileSpmemLoad, …LoadCircularBuffer[PostUpdate], …LoadIndexed[CircularBuffer] |
VectorStore | 15 | 33 | 33 | TileSpmemStore* + 每 dtype scatter-add …StoreAdd{Bf16,F32,S16,S32} 变体 |
VectorExtended | 28 | 52 | 53 | AddScan*, Segmented*Scan*, Max/MinScan, Max/MinIndexScan, Sort{Float,Integer}{Asc,Desc}, Uniquify*, DuplicateCount* |
VectorResult | 14 | 14 | 14 | EupResult, VresMove, PopXrfWriteAll, PopXrfWritePartial0..4 |
TecStream | 4 | 4 | 4 | IndirectStream, IndirectVregStream, LinearStream, StridedStream |
TecDma | 3 | 3 | 3 | SimpleDma, SingleStridedDma, GeneralDma |
NOTE —
VectorExtended槽每个 bundle 触发一次,并使用单独的流水级。 Extended op(scan/sort/uniquify)是 TEC 的“transcendentals”:它们需要多个 cycle,写入 XRF(extended-result FIFO),其结果必须由VectorResult槽排出(PopXrfWritePartialN只写入前 N 个 lane,用于 reduction 比向量宽度更窄的情况)。它们运行在与三个常规VectorAlulane 不同的ProcResourcegroup 中。GOTCHA —
VectorStoreAdd*是对 tile memory 的 atomic scatter-add,不是普通 store。 每 dtype 的…StoreAdd{Bf16,F32,S16,S32}(以及 indexed/circular 变体)会把待存值累加到现有TILE_SPMEM位置。这是 embedding-table 梯度累加的构建块;跨 tile / 跨 HBM 的 atomic 等价物是 Stream 槽的STREAM_OPCODE_SCATTER_FLOAT_ADD。重实现者必须把 dtype 后缀编码为 opcode 的一部分,而不是 operand;Ghostlite 拆出了 Viperfish 折叠在一起的每 dtype 形式。
VF(Access/Execute)拆分 {#the-vf-accessexecute-split}
execute-region-only 规则
直觉上,outliner 似乎会在携带 TAC 的代际上把 tile_task 拆成一个 "access"(TAC)函数和一个 "execute"(TEC)函数。字节追踪表明,在这个 wheel 中任何代际都不存在这种拆分;SC-MLO 编译器是一条 2 定序器 SCS+TEC 流水线(VF、GL 和 GF 都如此)。这是关于 TEC 位于流水线何处的最关键事实。
sc_tpu.tile_task region (the per-tile compute body)
│ TileTaskOutliningPass::runOnOperation 0x13606220
│ per-op outlining callback 0x136066e0
▼
func.func( live-in memrefs ) sc.sequencer = "execute" ← the TEC body (the ONLY value stamped on a body)
▲ StringAttr "execute" @0x8681624 (7 chars)
│ LaunchTileTaskOp::create 0x145dd0e0
enclosing func sc.sequencer = "scs" ← the SCS control program
│
▼ read back at lowering
LowerSequencerFunctionsPass::runOnOperation 0x13532120
│ ScDialect::HasCoreSequencerTypeAttribute 0x14599ec0 (value=="scs", len 3)
│ ScDialect::HasExecuteSequencerTypeAttribute 0x1459a020 (value=="execute",len 7)
│ (NO HasAccessSequencerTypeAttribute — no len-6 "access" predicate exists)
▼
per-engine codec selected by TpuSequencerType {3=SCS, 5=TEC} ── no 4 (TAC) is ever produced逐 op outlining callback(0x136066e0,由所有代际的 Target-parameterized pass 使用)会无条件给 outlined func 标记 sc.sequencer="execute";"execute"(@0x8681624,7 chars)是它引用的唯一 sc.sequencer 值字符串,没有按 Target 条件分支到第二个值。读回谓词 HasExecuteSequencerTypeAttribute(0x1459a020)按字节确认该值:它只接受长度为 7 的属性,其字节为 0x63657865("exec")+ 0x65747563("cute")。lowering 链中不存在 HasAccessSequencerTypeAttribute,也不存在任何长度为 6 的 "access" 比较。Viperfish 和 Ghostlite emitter 的 MakeTpuCoreProgram 都恰好实例化两个 codec:SparseCoreScsCodecBase + SparseCoreTecCodecBase,其中 SparseCoreTacCodecBase 出现次数为零。
NOTE — outliner 从不发出
"access"(TAC)函数。 每个代际上,outliner 都只标记"scs"和"execute"。.rodata中独立的"access"字符串是 libc 数学函数名(abs/access/acos/…)以及sc.parallel_access/spirv.memory_access属性名,而不是sc.sequencer值。TAC(“access”)引擎只作为 legacyProgramWrapper.tacproto 字段的 standalone codec(SparseCoreTacCodecBase、TpuSequencerType=4、glc)保留下来;MLIR tile-task 流水线从不会到达它。access-region 工作在所有 SC 代际上都折叠进 TEC,而不只是6acc60406。
tile-fetch 去往哪里
因为编译器从不生成 access 函数,所以 TAC 硅片本可承载的 tile-fetch / gather 工作会通过 TEC Stream 槽发射到 TEC "execute" 函数中。GetTransferKind(0x1351b140)仍会把 transfer 分类为 kStream(gather/scatter)或 kDma(bulk),从而路由到 TecStream 槽或 TecDma 槽;但它不选择定序器:两种类型都存在于其 tile_task region 被 outline 到的 SCS 或 TEC bundle 中。IndirectVregStream 是 TEC-only(它从 VREG 读取 indirect offset,位于 bundle bit 322),这是 indirect gather 是 TEC-bundle op 而非独立引擎 op 的结构性证据。
GOTCHA — access region 是 TEC bundle 中的一个区域,不是单独引擎。 在这个 wheel 中,“Access-vs-Execute” 是一个 TEC bundle 内部 Stream/Dma descriptor 字段(access region,TEC bundle 的 bits 283/322)与向量计算槽(execute region,bits 239..474)之间的拆分。若重实现者为 VF/GL 建模一个单独的 TAC 定序器,就会生成 SC-MLO 代码生成器从不发出、lowering 链也没有谓词支持的程序。
为什么 TEC 逐代增长
计数中的增长
TEC 是在引擎清单收缩的同时累积能力的引擎。三个独立反编译计数都在 VF→GL→GF 中单调上升,而 TAC 计数在 6acc60406 上归零:
| 指标 | Viperfish (vfc) | Ghostlite (glc) | 6acc60406 (gfc) |
|---|---|---|---|
SparseCoreTec* 反编译函数 | 5244 | 7803 | 8636 |
SparseCoreTecVectorAlu* 反编译函数 | 3215 | 4856 | 5466 |
VectorAlu opcode 计数(proto enum) | 148 | 229 | 257 |
VectorStore opcode 计数 | 15 | 33 | 33 |
VectorExtended opcode 计数 | 28 | 52 | 53 |
| Vector-ALU opcode 字段宽度 | 7-bit | 8-bit | 8-bit |
| Vector-ALU 槽宽度 | 36-bit | 37-bit | 37-bit |
SparseCoreTac* 反编译函数 | 932 | 952 | 0 |
vector-ALU opcode 集合在 Viperfish(148 个 op,仅略超过 7 位,其中顶部 op 折叠进 reserved encoding)到 Ghostlite(229 个 op)之间越过了 7 位上限(128),因此 opcode 字段从 7 位加宽到 8 位,槽从 36 位加宽到 37 位,使 GF 向量 lane 相对 VF 上移(VF Alu0 base 432,GF Alu0 base 438)。Ghostlite 拆分了 transcendentals 和 conversions 的 bf16/f32 实例;6acc60406 为 embedding-optimizer 权重量化增加了 FP8(E4m3/E5m2)和通用小浮点(Exmy)pack/unpack 家族。
它为何增长:吸收其他引擎的角色
跨代有两个角色折叠进 TEC:
- access/tile-fetch 角色(编译器层面上的所有代际)。 如 The VF Split 所示,SC-MLO 编译器从不发出
"access"函数;TAC 硅片本可承载的 gather/scatter 在每个代际上都发射到 TEC Stream 槽中。TEC bundle 的高位 payload 区域(bits 283/322)在与消费 fetched tile 的 vector load/store 同一个 64 字节 word 中持有 stream descriptor,因此执行计算的引擎也是执行 fetch 的引擎。 - 内层循环 dispatch 角色(6acc60406 硅片)。 在
6acc60406上,TAC 硅片完全消失(SparseCoreTac*反编译计数 = 0,没有SparseCoreTacCodecBase,没有SparseCoreTacGFSchedModelSchedClasses)。其内层循环 tile-fetch dispatch 由 SCS 新增的BranchRelativeRotatingPreg/SetRotatingPredicateRegister旋转谓词 op 支持;这两个 op 只存在于gfc命名空间(gfc 上 27 / 31 个符号,vfc/glc 上为零),为 SCS 提供了内层 tile-fetch 可依附的硬件循环分支。TEC opTileSpmemLoadCircularBufferPostUpdate(其 post-update 会自动递增 load pointer,使 TEC bundle 可以在没有单独 TAC stream-gather 的情况下流式执行 tile-fetch)不是6acc60406新增的;它存在于全部三代(vfc/glc/gfc 都携带该 op),因此 load primitive 早于 dispatch consolidation。
结果就是二进制反映出的整合策略:引擎更少,但 6acc60406 上仅 TEC 携带的 opcode 就比 Viperfish 整个 SparseCore 还多。代价是 TEC bundle 更重,因为每个 bundle 现在同时发起计算和 tile-fetch,所以 LLVM scheduler 必须在一个 bundle 内找到更多并行性(6acc60406 的 TEC 相比 Ghostlite 增加了 2–3 个 ProcResource group,用于建模并发 DMA 发起)。
立即数槽索引 {#immediate-slot-indexing}
6-entry indexed array
需要 literal operand 的 TEC op 不会内联携带它;它通过 6 位 selector 引用六个 20 位立即数槽之一。slot-index → bundle-bit 映射按位精确地从 EmitImmediate jump table(@0xae91c68;gfc 0x13a71920,vfc 0x1398b7e0)和 SparseCoreImmediatesEncoder(0x1ecd1760)恢复;后者的 BitCopy 调用写入全部六个 20 位字段:
| Slot index | Struct field | Bundle bit | Width | Engines |
|---|---|---|---|---|
| 0 | +0x18 | 67 | 20 | SCS + TEC |
| 1 | +0x1c | 47 | 20 | SCS + TEC |
| 2 | +0x20 | 27 | 20 | SCS + TEC |
| 3 | +0x24 | 7 | 20 | SCS + TEC |
| 4 | +0x28 | 215 | 20 | TEC only |
| 5 | +0x2c | 195 | 20 | TEC only |
EmitImmediate(slot_index, value, msg) 会检查 slot_index ≤ 5(cmp $0x5)和 value < 2^20(cmp $0x100000),随后通过 6-way jump table 把该值写入 encoder 读入 bundle 的 struct field。低四个槽由 SCS 和 TEC 共用;高两个只存在于 TEC。VF 和 GF 的 TEC 立即数布局按字节相同;立即数不会在代际之间移动,只有 bit 235 以上的向量计算区域会移动。
operand → slot 链接
operand 通过 VectorY 6 位 selector(标量槽 ScalarY 的向量槽对应物)引用立即数槽。selector enum 直接命名槽:
VECTOR_Y_IMM0_ZERO…VECTOR_Y_IMM5_ZERO— 读取单个 20 位槽,并用零填充到 operand 宽度。VECTOR_Y_IMM1_IMM0/IMM3_IMM2/IMM5_IMM4— 读取跨两个相邻槽的 40 位 literal(高 20 位来自更高槽,低 20 位来自更低槽)。
因此,需要 ≤20 位 literal 的 op 会把其 VectorY selector 设为 IMMk_ZERO,emitter 调用 EmitImmediate(k, literal) 把 literal 写入槽 k。需要 ≤40 位 literal 的 op 会设置 IMM(k+1)_IMMk,emitter 调用两次 EmitImmediate(槽 k 和 k+1)。SCS ScalarY selector(SCALAR_Y_IMM0_ZERO=40 … IMM3_ZERO=43、IMM1_IMM0=44、IMM3_IMM2=45、ONES_IMM3=39)在四个标量槽上以相同方式工作。
GOTCHA — TEC op 槽中没有 inline literal 字段。 Branch target、DMA length、sync-flag id/threshold 以及 TEC op 消费的任何其他常量,都只能通过
VectorY/ScalarY立即数槽间接引用。如果重实现者试图把常量打包进 op 槽的 operand 字段,会发现没有空间;operand 字段是寄存器 selector(VREG/SREG),literal 必须分配进立即数槽,并由 selector 命名。每个 bundle 的限制是六个槽(另有一个尚未完全追踪的SparsecoreVregReadPort冲突规则,会限制三个向量 lane 一次能引用多少个不同的VectorY立即数 operand)。
函数图
| 符号 | 地址 | 角色 |
|---|---|---|
SparseCoreTecCodecBase<…>::Encode (vfc) | 0x139328a0 | bundle dispatcher;对每个槽 encoder 进行共享 Span 调用 |
BitCopy | 0x1fa0a900 | 小端 bit packer(dst, dst_bitoff, src, src_bitoff, nbits) |
SparseCoreImmediatesEncoder::Encode (gfc) | 0x1ecd1760 | 6 × 20 位立即数 @7/27/47/67/195/215 |
SparseCoreVectorScalarEncoder::Encode (gfc) | 0x1ecd1e00 | scalar→vector bridge @87..110 |
SparseCoreScalarMiscEncoder::Encode (gfc) | 0x1ebad840 | misc/sync/atomic 槽,opcode @127 |
SparseCoreTecScalarAlu1Encoder::Encode (gfc) | 0x1ebd8040 | 标量 lane 1,opcode @154 |
SparseCoreTecScalarAlu0Encoder::Encode (gfc) | 0x1ebc54a0 | 标量 lane 0,opcode @181 |
SparseCoreTecVectorResultEncoder::Encode (gfc) | 0x1ecbc9e0 | XRF-pop 槽,opcode @239 |
SparseCoreTecVectorExtendedEncoder::Encode (gfc) | 0x1ecab8a0 | scan/sort/uniquify 区域 @261..461 |
SparseCoreTecVectorLoadEncoder::Encode (gfc) | 0x1ecb9ee0 | tile vector load,opcode @283 |
SparseCoreTecVectorStoreEncoder::Encode (gfc) | 0x1eccbe20 | tile vector store + scatter-add,opcode @353 |
SparseCoreTecVectorAlu2Encoder::Encode (gfc) | 0x1ec85ae0 | 向量 lane 2,opcode @388/8;槽基址 364 |
SparseCoreTecVectorAlu1Encoder::Encode (gfc) | 0x1ec51900 | 向量 lane 1,opcode @425/8;槽基址 401 |
SparseCoreTecVectorAlu0Encoder::Encode (gfc) | 0x1ec11100 | 向量 lane 0,opcode @462/8;sel @438/444/450/456;pred @470/473/474 |
SparseCoreTecStreamEncoder::Encode (gfc) | 0x1ebe33e0 | Stream oneof-of-lane,opcode @181/162,高位 payload @283/322 |
SparseCoreTecDmaEncoder::Encode (gfc) | 0x1ebb6960 | Dma oneof-of-lane,opcode @181,高位 payload @283/322 |
EncoderBase<…gfc Tec…>::BundleSizeBytes | 0x1e8359e0 | 分派 codec-metadata vtable[+0x30] → 64 |
SparseCoreTecCodecBase GetBytesPerBundle (gfc / vfc) | 0x13923a80 / 0x13933660 | packed bytes 60(gfc)/ 59(vfc) |
TileTaskOutliningPass::runOnOperation | 0x13606220 | outline tile_task → TEC "execute" func |
| outliner per-op callback | 0x136066e0 | 无条件标记 sc.sequencer="execute" |
LaunchTileTaskOp::create | 0x145dd0e0 | 用 TEC func 的 launch 替换 tile_task |
LowerSequencerFunctionsPass::runOnOperation | 0x13532120 | 读取 sc.sequencer,lower 每引擎 body |
ScDialect::HasExecuteSequencerTypeAttribute | 0x1459a020 | 谓词:sc.sequencer == "execute"(len-7,按字节精确) |
GetTransferKind | 0x1351b140 | kStream/kDma 分类器(在定序器内部路由,不在定序器之间路由) |
跨代锚点:vfc TEC VectorAlu0 0x1e954ae0(opcode @456/7,7 位窄形式,sel @432/438/444/450);glc TEC VectorAlu0 0x1eaa4880(37 位/8 位,匹配 GF)。codec dispatcher 在所有代际都会把同一个缓冲区 Span 传给每个槽 encoder;低位区域(bits 7..191)和立即数布局在 VF/GL/GF 上按字节相同,只有 bit 235 以上的向量计算区域会移动。
注意事项
- 三个 vector ALU lane 并发发射。 合法 TEC bundle 可以在一个 64 字节 word 中命名三个独立的
VectorAluop(lane 0/1/2),外加一个 load、一个 store、一个 extended op 和一个 result-pop。scheduler 必须满足SparsecoreVregReadPort每 bundle 冲突规则(尚未完全追踪),该规则限制三个 lane 一次能使用多少个不同 VREG read port,也因此限制多少个不同的VectorY立即数 operand;六个立即数槽是上限。 - VF 是窄形式。 Viperfish vector-ALU 槽是 36 位并带 7 位 opcode(单通道谓词),而 Ghostlite/6acc60406 是 37 位/8 位/双通道形式。面向 Viperfish 的重实现必须用 7 位编码 opcode,并使用单通道谓词 header;148-op VF 集合刚好可容纳。
- 编译器层面上任何代际都没有单独 TAC。 不要从 MLIR 流水线发出
"access"函数或SparseCoreTacCodecBase程序;outliner 和 lowering 链都没有对应路径。tile-fetch 是 TEC Stream-slot op。 - 未映射区域(LOW/inferred)。 7 位 bundle prefix(
@0..6)、475..511padding,以及VectorExtended区域(261..461)和VectorScalarbridge(87..110)内部的按位精确字段标签,目前只恢复为槽基址/范围,尚未逐字段命名(per-extended-op operand-to-VREG-selector 绑定是最大的剩余缺口)。codec 是否在 epilogue 写入 version/valid nibble 尚未解码(SC bundle 没有0x55trailer;有一条分析指出 6acc60406 NOP-bundle 最后一个字节为0x50,可能是 4 位 framing 字段,但未确认,LOW)。
相关组件
| 名称 | 关系 |
|---|---|
SparseCoreTecCodecBase<…, TpuSequencerType=5> | 本页记录的 TEC codec(全部三代) |
SparseCoreTecVectorAlu0Encoder::Encode (0x1ec11100 gfc) | 向量 lane-0 槽 encoder;37 位模板的 BitCopy 立即数来源 |
TileTaskOutliningPass (0x13606220) | 标记 sc.sequencer="execute",把 tile_task body 分配给 TEC |
LaunchTileTaskOp::create (0x145dd0e0) | SCS 控制程序向 TEC 发起的 launch |
GetTransferKind (0x1351b140) | 在 execute 函数内把 transfer 路由到 TEC Stream 或 Dma 槽 |
SparseCoreScalarMiscEncoder (0x1ebad840 gfc) | TEC 与 SCS 按字节相同共享的 misc/sync/atomic 槽 |
交叉引用
- SparseCore Overview — 三类引擎、按代际存在性以及
TpuSequencerTypecodec-template enum。 - SparseCore Hardware Architecture — TEC 面向的 geometry,以及
SparseCoreTarget/TpuCoreParts定序器索引(C++{3,4,5}enum,并协调 proto off-by-one)。 - SCS (Scalar) Engine — 控制定序器;TEC 复用其低位区域 bundle 和 27 位标量模板,并由它通过
LaunchTileTaskOp启动。 - TAC Engine — 仅 VF/GL 存在的 tile-fetch 发起器,其 access 角色被 TEC 吸收(在 6acc60406 上移除)。
- Vector Opcode Enum — TEC 执行的完整逐槽、逐代向量 op 清单。
- VectorExtended (VEX) — scan/sort/uniquify 槽,TEC 向量区域中 embedding-reduce 的核心。
- Bundle Slot-Base Map — SCS / TAC / TEC 的逐引擎绝对槽位分区。
- SC Backend Pipeline — outliner 和 sequencer-lowering pass 在 SC-MLO pipeline 中的位置。
- 二进制:
extracted/libtpu-0.0.40-cp314-cp314-manylinux_2_31_x86_64/libtpu/libtpu.so(build-id89edbbe81c5b328a958fe628a9f2207d) - 索引条目: Part IX — SparseCore & BarnaCore / SparseCore engines — 返回索引