Skip to content

TEC(向量)引擎

本页中的每个地址、位偏移、opcode 宽度以及按代际划分的计数,都是从 libtpu-0.0.40-cp314 wheel(BuildID md5 89edbbe81c5b328a958fe628a9f2207d)里的 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 会让它为空:两个额外立即数槽,随后是 VectorResultVectorExtendedVectorLoadVectorStore,以及堆叠的三个 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>LN3tpu16TpuSequencerTypeE5E template 字面量)编码,存在于全部三个 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)。没有 0x55 check 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 opcode8 位(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::TpuSequencerType enum 编号为 {3 = SCS, 4 = TAC, 5 = TEC},作为 codec 上的非类型模板字面量携带;这已在 gfc SparseCoreTecCodecBase 符号的 LN3tpu16TpuSequencerTypeE5E 后缀中按字节验证(16 个 gfc 命名空间 SparseCoreTec* 符号携带该字面量,三代合计 32 个)。同一 C++ 编号也是 TpuSequencerTypeToString 渲染的编号,并且 SparseCoreTarget geometry descriptor 用它索引 TpuCoreParts(tile-execute geometry 读取于 C++ sequencer-type 5 = TEC)。存在 off-by-one 的对应物是 protobuf enum TpuSequencerTypeProto,它保留 INVALID=0,因此编号为 {… SCS = 4, TAC = 5, TEC = 6}TpuSequencerTypeFromProto 会在任何内存内使用前把它减一转换为 C++ enum。对 TEC codec、引擎名和 TpuCoreParts 索引都使用 5(与 overviewscs-enginetac-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。

入口点

text
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
SparseCoreScalarMiscscalar misc / sync / atomic 槽(与 SCS 共享)SparseCoreScalarMisc
SparseCoreImmediates6 × 20 位立即数槽(注意:不是 …ScalarImmediatesSparseCoreImmediates
SparseCoreVectorScalarscalar→vector 值桥接(共享)SparseCoreVectorScalar
SparseCoreTecDma / SparseCoreTecStreamDMA / stream 槽(TEC 变体;标量 lane 的 oneof)SparseCoreDma / SparseCoreStream
SparseCoreTecVectorAlu0 / …Alu1 / …Alu2三个并发 vector ALU lane(计算)SparseCoreTecVectorAlu
SparseCoreTecVectorLoadtile vector load(TileSpmemLoad*SparseCoreTecVectorLoad
SparseCoreTecVectorStoretile vector store + scatter-add(TileSpmemStore*[Add]SparseCoreTecVectorStore
SparseCoreTecVectorExtendedscan / segmented scan / sort / uniquify(类似 transcendental)SparseCoreTecVectorExtended
SparseCoreTecVectorResult把 XRF(extended-result FIFO)pop 到 VRFSparseCoreTecVectorResult

NOTE — 立即数槽是 SparseCoreImmediates,不是 SCS 的 SparseCoreScalarImmediates,并且有六个。 SCS 携带四个 20 位立即数槽;TEC 携带六个(四个低位 @7/27/47/67 + 两个高位 @195/215)。额外两个存在,是因为向量 op 通过 VectorY 6 位 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 函数体证明了允许它的掩码:

c
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 目标立即数恢复。

text
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
BaseEndWidthOpcode bit内部模板
(reserved header)067bundle prefix;含义未解码
Immediates (low)786804 × 20-bit(@7,@27,@47,@67
VectorScalar8711024scalar→vector bridge
ScalarMisc1111372712727 位标量模板
ScalarAlu1 (lane 1)1381642715427 位标量模板
ScalarAlu0 (lane 0)1651912718127 位标量模板
Immediates (high)195234402 × 20-bit(@195,@215
VectorResult23926022239XRF-pop(EupResult/PopXrf…
VectorExtended261461~201261 (EUP)scan/sort/uniquify 区域;复用 VREG operand
VectorLoad28332139283TileSpmemLoad*
VectorStore32836336353TileSpmemStore*[Add]
VectorAlu2 (lane 2)3644003738837 位向量模板
VectorAlu1 (lane 1)4014373742537 位向量模板
VectorAlu0 (lane 0)4384743746237 位向量模板
(reserved / pad)47551137任何槽 encoder 都不写入
TecDma (oneof of lane)87327181; 283/322标量 opcode + 高位 payload
TecStream (oneof of lane)99327181/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(IndirectVregStream indirect-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 位。

c
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

text
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 + 24VectorAlu2 op @388(= 364+24)、VectorAlu1 @425(= 401+24)、VectorAlu0 @462(= 438+24)。三个 lane 以 37 位间隔直接堆叠在 vector load/store 区域上方。

LaneBase (GF)VREG selOPCODE @+24/8pred header @+32
VectorAlu2364364/370/376/382388396/399/400
VectorAlu1401401/407/413/419425433/436/437
VectorAlu0438438/444/450/456462470/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) 中详述。

VFGLGF代表性 op(GF)
VectorAlu(×3 lane)148229257VectorAdd{Bf16,F32,S16,S32}, VectorMultiply*, Tanh{Bf16,F32}, Reciprocal*, FP8/FP4 PackCompressed*/UnpackCompressed*, VmskAnd/Or/Xor, lane permute/scan helpers
VectorLoad555TileSpmemLoad, …LoadCircularBuffer[PostUpdate], …LoadIndexed[CircularBuffer]
VectorStore153333TileSpmemStore* + 每 dtype scatter-add …StoreAdd{Bf16,F32,S16,S32} 变体
VectorExtended285253AddScan*, Segmented*Scan*, Max/MinScan, Max/MinIndexScan, Sort{Float,Integer}{Asc,Desc}, Uniquify*, DuplicateCount*
VectorResult141414EupResult, VresMove, PopXrfWriteAll, PopXrfWritePartial0..4
TecStream444IndirectStream, IndirectVregStream, LinearStream, StridedStream
TecDma333SimpleDma, SingleStridedDma, GeneralDma

NOTE — VectorExtended 槽每个 bundle 触发一次,并使用单独的流水级。 Extended op(scan/sort/uniquify)是 TEC 的“transcendentals”:它们需要多个 cycle,写入 XRF(extended-result FIFO),其结果必须由 VectorResult 槽排出(PopXrfWritePartialN 只写入前 N 个 lane,用于 reduction 比向量宽度更窄的情况)。它们运行在与三个常规 VectorAlu lane 不同的 ProcResource group 中。

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 位于流水线何处的最关键事实。

text
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 条件分支到第二个值。读回谓词 HasExecuteSequencerTypeAttribute0x1459a020)按字节确认该值:它只接受长度为 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”)引擎只作为 legacy ProgramWrapper.tac proto 字段的 standalone codec(SparseCoreTacCodecBaseTpuSequencerType=4、glc)保留下来;MLIR tile-task 流水线从不会到达它。access-region 工作在所有 SC 代际上都折叠进 TEC,而不只是 6acc60406

tile-fetch 去往哪里

因为编译器从不生成 access 函数,所以 TAC 硅片本可承载的 tile-fetch / gather 工作会通过 TEC Stream 槽发射到 TEC "execute" 函数中。GetTransferKind0x1351b140)仍会把 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* 反编译函数524478038636
SparseCoreTecVectorAlu* 反编译函数321548565466
VectorAlu opcode 计数(proto enum)148229257
VectorStore opcode 计数153333
VectorExtended opcode 计数285253
Vector-ALU opcode 字段宽度7-bit8-bit8-bit
Vector-ALU 槽宽度36-bit37-bit37-bit
SparseCoreTac* 反编译函数9329520

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 op TileSpmemLoadCircularBufferPostUpdate(其 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)和 SparseCoreImmediatesEncoder0x1ecd1760)恢复;后者的 BitCopy 调用写入全部六个 20 位字段:

Slot indexStruct fieldBundle bitWidthEngines
0+0x186720SCS + TEC
1+0x1c4720SCS + TEC
2+0x202720SCS + TEC
3+0x24720SCS + TEC
4+0x2821520TEC only
5+0x2c19520TEC only

EmitImmediate(slot_index, value, msg) 会检查 slot_index ≤ 5cmp $0x5)和 value < 2^20cmp $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_ZEROVECTOR_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=40IMM3_ZERO=43IMM1_IMM0=44IMM3_IMM2=45ONES_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)0x139328a0bundle dispatcher;对每个槽 encoder 进行共享 Span 调用
BitCopy0x1fa0a900小端 bit packer(dst, dst_bitoff, src, src_bitoff, nbits
SparseCoreImmediatesEncoder::Encode (gfc)0x1ecd17606 × 20 位立即数 @7/27/47/67/195/215
SparseCoreVectorScalarEncoder::Encode (gfc)0x1ecd1e00scalar→vector bridge @87..110
SparseCoreScalarMiscEncoder::Encode (gfc)0x1ebad840misc/sync/atomic 槽,opcode @127
SparseCoreTecScalarAlu1Encoder::Encode (gfc)0x1ebd8040标量 lane 1,opcode @154
SparseCoreTecScalarAlu0Encoder::Encode (gfc)0x1ebc54a0标量 lane 0,opcode @181
SparseCoreTecVectorResultEncoder::Encode (gfc)0x1ecbc9e0XRF-pop 槽,opcode @239
SparseCoreTecVectorExtendedEncoder::Encode (gfc)0x1ecab8a0scan/sort/uniquify 区域 @261..461
SparseCoreTecVectorLoadEncoder::Encode (gfc)0x1ecb9ee0tile vector load,opcode @283
SparseCoreTecVectorStoreEncoder::Encode (gfc)0x1eccbe20tile 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)0x1ebe33e0Stream oneof-of-lane,opcode @181/162,高位 payload @283/322
SparseCoreTecDmaEncoder::Encode (gfc)0x1ebb6960Dma oneof-of-lane,opcode @181,高位 payload @283/322
EncoderBase<…gfc Tec…>::BundleSizeBytes0x1e8359e0分派 codec-metadata vtable[+0x30] → 64
SparseCoreTecCodecBase GetBytesPerBundle (gfc / vfc)0x13923a80 / 0x13933660packed bytes 60(gfc)/ 59(vfc)
TileTaskOutliningPass::runOnOperation0x13606220outline tile_task → TEC "execute" func
outliner per-op callback0x136066e0无条件标记 sc.sequencer="execute"
LaunchTileTaskOp::create0x145dd0e0用 TEC func 的 launch 替换 tile_task
LowerSequencerFunctionsPass::runOnOperation0x13532120读取 sc.sequencer,lower 每引擎 body
ScDialect::HasExecuteSequencerTypeAttribute0x1459a020谓词:sc.sequencer == "execute"(len-7,按字节精确)
GetTransferKind0x1351b140kStream/kDma 分类器(在定序器内部路由,不在定序器之间路由)

跨代锚点:vfc TEC VectorAlu0 0x1e954ae0(opcode @456/77 位窄形式,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 中命名三个独立的 VectorAlu op(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..511 padding,以及 VectorExtended 区域(261..461)和 VectorScalar bridge(87..110)内部的按位精确字段标签,目前只恢复为槽基址/范围,尚未逐字段命名(per-extended-op operand-to-VREG-selector 绑定是最大的剩余缺口)。codec 是否在 epilogue 写入 version/valid nibble 尚未解码(SC bundle 没有 0x55 trailer;有一条分析指出 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 — 三类引擎、按代际存在性以及 TpuSequencerType codec-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-id 89edbbe81c5b328a958fe628a9f2207d
  • 索引条目: Part IX — SparseCore & BarnaCore / SparseCore engines — 返回索引