OneSlot 标量路由器
本页中的每个地址、opcode 值、slot-flag 位以及跳转表边界,均逐字节读取自
libtpu-0.0.40-cp314wheel 中的libtpu.so(build-id89edbbe81c5b328a958fe628a9f2207d)——来源包括反编译的ConsumeOneSlotInstruction函数体、其被调尾部函数以及.rodata跳转表。其他版本会不同。
摘要
ConsumeOneSlotInstruction 是 SparseCore SC-MLO 发射器的标量槽路由器:给定一个已解码的 MCInst,其 opcode 命名某个标量(非向量)SC 操作,它决定该操作占用 bundle 的哪个物理发射槽——Stream、ScalarMisc、ScalarAlu(及其双子槽 S0/S1)或 DMA——然后尾调用匹配的 Consume<Slot>Instruction 叶子函数,将该操作降低到该槽的 proto 字段中。它不是逐操作编码器;它是位于逐槽 consumer 之上的分派接缝,是 SparseCore 中类似 LLVM MCInst → 功能单元绑定 pass 的部分。在 TableGen 驱动的后端会把 slot 作为指令 itinerary class 携带的地方,libtpu 同时用两种方式携带它:一个 4019 项跳转表把 opcode 映射到 slot 类别,而对可在多个标量 slot 上发射的操作,则由每个 MCInst 的 flag word(getSlotFlagsFromMCInst,MCInst+0x4)在发射时选择具体子槽。
该路由器具有 bundle 不变性。三个带标量区域的 SC bundle 类型——SCS、TAC 以及 TEC 的标量半区——都从同一个模板实例化 ConsumeOneSlotInstruction<Bundle>,并且三者共享完全相同的 opcode→arm 分布:相同的跳转表基址(opcode − 0x1f3)、相同的边界(0xfb2 = 4019)、相同的十个 arm 以及相同的操作计数。只有 slot accessor 上的 bundle 模板实参不同(GetStreamSlot<…,SparseCoreScsBundle> vs …TacBundle vs …TecBundle)。重新实现者只需编写一次路由器,并按 bundle 参数化。
本页记录该路由器按 opcode 分类的逻辑(十个 arm 及其 slot 类别)、多 slot 操作的逐 MCInst slot-flag 子路由、三个特殊 arm(DMA 实体化、可选跳过、no-op)、默认错误路径;并且由于本页的任务是说明单个 bundle slot 如何到达其子编码器,也说明向量 slot 分派是一个独立机制:TEC bundle 的向量 slot 由 ConsumeOneTecBundleInstruction 路由,后者通过 ConsumeVectorAluInstruction 到达 142 操作的 VectorAlu 表。向量 opcode 清单本身归 TEC Vector Opcode Enumeration 页面所有,此处只链接而不重复。
对重新实现而言,契约是:
- 分类表:
opcode − 0x1f3,边界0xfb2,十个 arm。 将MCInst+0x4读入 slot-flags word,并读取 opcodeDWORD[MCInst];以0xae8dce4(TAC)处的跳转表为索引;分派到十个 arm 之一。每个非特殊 arm 选择一个 slot 类别,调用Get<Slot>Slot、EmitPredicationToSlot<…>,并尾调用Consume<Slot>Instruction。 - 多 slot 操作的 slot-flag 子路由。 54 个 opcode 的 multi-scalar arm 没有固定 slot;它测试 slot-flag 位(
flags & 1 → S0,& 2 → S1,& 4 → ScalarMisc),并在{SparseCoreScalarAlu*, SparseCoreScalarMisc*}上构造一个std::variantvalue-visitor。没有设置任何位是硬错误。 - DMA、可选跳过和 no-op arm。 70 个 opcode 的 DMA arm 在
LogFatal保护的前置条件下,将SparseCoreDma实体化到 bundle 的scalar_instructiononeof 中,然后访问{SparseCoreDma*, SparseCoreTecDma*}variant。四个 opcode 会在 consumer 的bool参数置位时静默跳过;一个 opcode(0x264)不发射任何内容并返回 OK。 - 向量路径是独立的。
ConsumeOneSlotInstruction只处理标量 slot;TEC 向量 slot(VectorAlu/VectorLoad/VectorStore/VectorExtended)由ConsumeOneTecBundleInstruction分派,且VectorAlu通过ConsumeVectorAluInstruction(jt base0xb26)到达其 142 操作表。
| 路由器 | ConsumeOneSlotInstruction<Bundle>(逐 bundle 的标量 slot 分派器) |
| TAC 入口 | 0x139f1360; jt 0xae8dce4, base 0x1f3, bound 0xfb2(4019 项) |
| SCS / TEC 入口 | 0x13a50540(jt 0xaea9fb4) · 0x13a15500(jt 0xaea4ba0)— arm 映射相同 |
| 分类输入 | DWORD[MCInst](opcode)+ getSlotFlagsFromMCInst(MCInst+0x4,slot-flag 位) |
| Arm | 10:Stream 888 · ScalarMisc 92 · ScalarAlu 49 · …S1 27 · …S0 17 · DMA 70 · multi-scalar 54 · skip 4 · no-op 1 · default 2817 |
| Slot-flag 位 | SLOT_S0 = 1 · SLOT_S1 = 2 · SLOT_SM = 4(llvm::TPU::SparseCoreMCSlot) |
| 向量路径 | ConsumeOneTecBundleInstruction 0x13a08e00 → ConsumeVectorAluInstruction 0x13a0b580(独立) |
| 来源 | platforms/xla/sparse_core/ghostlite/isa_emitter.cc |
| 置信度 | CONFIRMED(以反编译为锚点),除非某行或标注另有说明 |
注意 — "OneSlot" 表示“一个标量发射槽”,不是“一条指令”。 该名称描述路由器的工作:取一个
MCInst,把它放入 bundle 的恰好一个标量 slot。它是向量分派器的标量对等物。64 字节 bundle 布局、标量 slot 的字节/位基址(Misc @111、Alu1 @138、Alu0 @165)以及双发射 S0/S1 几何结构位于 TEC Engine 和 SCS Engine 页面,此处不重复。
分类逻辑
目的
路由器对每个 MCInst 回答一个问题:这个操作在哪个标量 slot 上发射? SC 标量 opcode 空间按 slot 类别划分为近似连续的区段——一个很长的 Stream 块、一个 ScalarMisc 块、一个带交错 S0/S1 双发射区段的 ScalarAlu 块——而该路由器就是解码这个划分的表。Slot 分配是 SC 指令放置的后半部分:engine(哪个 sequencer:SCS/TAC/TEC)由上游 section-classifier 选择;bundle 内的 slot 在这里选择。
入口点
ConsumeOneTecBundleInstruction (0x13a08e00) ── 逐 MCInst 的 TEC bundle 分派器
├─ ConsumeOneSlotInstruction<Bundle> (0x139f1360 TAC) ── 本路由器:标量 slot
│ ├─ GetStreamSlot → ConsumeStreamInstruction (0x139fa940)
│ ├─ GetScalarMiscSlot → ConsumeScalarMiscInstruction (0x139eeca0)
│ ├─ GetScalarAluSlot → ConsumeScalarAluInstruction (0x139f09c0)
│ ├─ GetScalarAluSlotS0 → ConsumeScalarAluSlotS0Instruction (0x139f9480)
│ ├─ GetScalarAluSlotS1 → ConsumeScalarAluSlotS1Instruction (0x139f9be0)
│ └─ DefaultConstruct<SparseCoreDma> → variant{Dma,TecDma} (0x13a04820)
└─ ConsumeVectorAluInstruction (0x13a0b580) ── 独立:VectorAlu(142 个操作)
```text
### 算法
```c
// ConsumeOneSlotInstruction<SparseCoreTacBundle> // glc 0x139f1360
// args: (printer, mcinst, &bundle, bool tolerate_skip)
function ConsumeOneSlotInstruction(printer, mcinst, bundle, tolerate_skip):
flags = getSlotFlagsFromMCInst(mcinst) // 0x13c798e0 → *(u32*)(mcinst+0x4)
opcode = mcinst.opcode // DWORD[mcinst]
idx = opcode - 0x1f3 // jt base 0x1f3
if (unsigned)idx > 0xfb2: // bound check (4019 entries)
goto DEFAULT
switch jt[idx]: // jt @0xae8dce4 (TAC), 4019×int32 rel
MULTI_SCALAR: // 54 opcodes, slot chosen by flags
if flags & 1: slot = GetScalarAluSlotS0(flags, bundle); vidx = 0 // SparseCoreScalarAlu
elif flags & 2: slot = GetScalarAluSlotS1(flags, bundle); vidx = 0
elif flags & 4: slot = GetScalarMiscSlot(flags, bundle); vidx = 1 // SparseCoreScalarMisc
else: return Error("Invalid slot. Expected Scalar Slot. " // line 5882
"MCInst Flags: $0", flags)
return variant_visit[vidx](slot, mcinst) // {ScalarAlu*, ScalarMisc*} value-visitor
SCALAR_ALU_S0: // 17 opcodes, fixed S0
slot = GetScalarAluSlotS0(flags, bundle)
if EmitPredicationToSlot<…ScalarAlu>(mcinst, slot) != OK: return log(5969)
return ConsumeScalarAluSlotS0Instruction(printer, …)
SCALAR_ALU_S1: // 27 opcodes, fixed S1
slot = GetScalarAluSlotS1(flags, bundle)
if EmitPredicationToSlot<…ScalarAlu>(mcinst, slot) != OK: return log(6003)
return ConsumeScalarAluSlotS1Instruction(printer, …)
SCALAR_ALU: // 49 opcodes, generic ScalarAlu
slot = GetScalarAluSlot(flags, bundle) // returns StatusOr
if EmitPredicationToSlot<…ScalarAlu>(mcinst, slot) != OK: return log(5945)
return ConsumeScalarAluInstruction(printer, …, bundle)
STREAM: // 888 opcodes (DMA-stream descriptors)
slot = GetStreamSlot(flags, bundle)
if EmitPredicationToSlot<…Stream>(mcinst, slot) != OK: return log(7288)
return ConsumeStreamInstruction(printer)
SCALAR_MISC: // 92 opcodes (sync/atomic/barrier/watch)
slot = GetScalarMiscSlot(flags, bundle)
if EmitPredicationToSlot<…ScalarMisc>(mcinst, slot) != OK: return log(6102)
return ConsumeScalarMiscInstruction(printer, …, slot, bundle)
DMA: // 70 opcodes 0xfa1..0x1024 — see below
...materialize SparseCoreDma into scalar_instruction oneof...
OPTIONAL_SKIP: // 4 opcodes 0x100d/0x100e/0x1015/0x10f2
if !tolerate_skip: goto DEFAULT
return OK // silently drop
NO_OP: return OK // opcode 0x264 only
DEFAULT: // 2817 opcodes (and OOB)
return Error("Unsupported opcode while consuming slot instruction: "
"$0 : $1", opcode, getOpcodeName(opcode)) // line 7307反编译把跳转表呈现为 C switch,但序言是真正的间接跳转——lea ecx,[r12-0x1f3]; cmp ecx,0xfb2; ja default; movsxd rcx,[rdx+rcx*4]; add rcx,rdx; jmp rcx——因此 4019 个表项是指向十个 arm 目标的有符号 32 位相对偏移,正好符合下面的维度表形状。每个非特殊 arm 上的 EmitPredicationToSlot<…> 调用会在叶子 consumer 填充 slot body 之前,把操作的 predicate guard 写入 slot 的 predication header;它返回非 OK 状态时,会在对应 arm 的 isa_emitter.cc 行号处转换为带日志的状态。
Arm 映射
十个 arm,已对 TAC 函数体及其跳转表逐字节确认;SCS 和 TEC 路由器具有相同分布。
| Arm | Opcodes | Slot class → action |
|---|---|---|
| Stream | 888 | GetStreamSlot + EmitPredicationToSlot<…Stream> + ConsumeStreamInstruction |
| ScalarMisc | 92 | GetScalarMiscSlot + …<…ScalarMisc> + ConsumeScalarMiscInstruction |
| ScalarAlu | 49 | GetScalarAluSlot(StatusOr)+ …<…ScalarAlu> + ConsumeScalarAluInstruction |
| ScalarAlu-S1 | 27 | GetScalarAluSlotS1 + ConsumeScalarAluSlotS1Instruction(固定 S1) |
| ScalarAlu-S0 | 17 | GetScalarAluSlotS0 + ConsumeScalarAluSlotS0Instruction(固定 S0) |
| DMA | 70 | guard oneof → clear_scalar_instruction → DefaultConstruct<SparseCoreDma> → variant |
| Multi-scalar(flag) | 54 | flags & 1 → S0 / & 2 → S1 / & 4 → Misc;均无 → error |
| Optional-skip | 4 | if tolerate_skip return OK; else DEFAULT(0x100d/0x100e/0x1015/0x10f2) |
| No-op | 1 | return OK(opcode 0x264) |
| Default / OOB | 2817 | MakeErrorImpl "Unsupported opcode while consuming slot instruction: $0 : $1" |
易错点 — slot 类别在跳转表中,但 54 个操作的子槽在
MCInstflags 中,而不在 opcode 中。 五个固定 slot arm(Stream、ScalarMisc、ScalarAlu、S0、S1)只根据 opcode 决定 slot。multi-scalar arm 不是这样:它不携带固定 slot,而是读取逐MCInst的 flag word 来选择 S0/S1/Misc。若重新实现者静态地映射 opcode→slot,就会错误路由这 54 个操作中的每一个,因为同一个 opcode 可根据调度器写入的 flag,在不同 bundle 中落到不同标量子槽。
Slot-Flag 子路由
Flag word 及其位
路由器的第二个输入是 slot-flags word,由 getSlotFlagsFromMCInst(0x13c798e0)读取,其整个函数体是 return *((u32*)mcinst + 1)——也就是 flags 位于 MCInst+0x4。低三位是 llvm::TPU::SparseCoreMCSlot 枚举,由调度器在上游写入(setSlotFlagInMCInst,见 SCS scalar opcode page):
| Bit | Mask | SparseCoreMCSlot | 含义 |
|---|---|---|---|
| 0 | 0x1 | SLOT_S0 | 在 scalar-ALU 子槽 0 上发射 |
| 1 | 0x2 | SLOT_S1 | 在 scalar-ALU 子槽 1 上发射 |
| 2 | 0x4 | SLOT_SM | 在 ScalarMisc slot 上发射 |
Multi-scalar 分派
对 54 个 multi-slot opcode,该 arm 按这些位做优先级测试,并构建一个两元素 std::variant value-visitor,其索引选择 slot accessor 的 proto 类型:
// multi-scalar arm (glc 0x139f14f8)
if (flags & 1): // SLOT_S0 — highest priority
slot = GetScalarAluSlotS0<SparseCoreScalarAlu,Bundle>(flags, bundle)
visitor_index = 0 // → SparseCoreScalarAlu*
else if (flags & 2): // SLOT_S1
slot = GetScalarAluSlotS1<SparseCoreScalarAlu,Bundle>(flags, bundle)
visitor_index = 0 // → SparseCoreScalarAlu*
else if (flags & 4): // SLOT_SM
slot = GetScalarMiscSlot<SparseCoreScalarMisc,Bundle>(flags, bundle)
visitor_index = 1 // → SparseCoreScalarMisc*
else: // no slot bit set
return MakeError("Invalid slot. Expected Scalar Slot. MCInst Flags: $0", flags)
return __variant_dispatch[visitor_index](visitor, slot) // {ScalarAlu*, ScalarMisc*}
```text
`else` 分支——路由器认为某操作是标量,但没有设置任何 `SLOT_S0/S1/SM` 位——会通过 `FastIntToBuffer` 和 `SubstituteAndAppendArray` 格式化 flags,生成路由器两个错误字符串中的第二个并返回(`isa_emitter.cc:151` 的 `MakeErrorImpl<9>`,source-location 5882)。这是路由器的内部一致性检查:跳转表声称该操作是标量,但调度器没有写入标量 slot,因此无法继续发射。
> **特性 — S0 优先于 S1,S1 优先于 Misc;测试顺序就是策略。** Flag 位按固定优先级 `S0 → S1 → SM` 检查,而不是作为 one-hot 检查。若一个 `MCInst` 同时设置了 `SLOT_S0` 和 `SLOT_S1`,会路由到 S0。调度器是否会在 multi-scalar 操作上设置多个位未追踪(LOW),但如果发生,路由器行为是确定的,即上述测试顺序,而不是报错。
---
## DMA、可选跳过和 No-Op Arm
### DMA 实体化(70 个 opcode,`0xfa1..0x1024`)
DMA arm 不调用 `Get<Slot>Slot` accessor。DMA 操作不是填充某个 slot;它是一个描述符,路由器将其实体化到 bundle 的 `scalar_instruction` oneof 中,然后通过 DMA 类型 variant visitor 分派。
```c
// DMA arm (glc 0x139f1467)
oneof = *(u32*)(bundle + 0x38) // scalar_instruction oneof tag
switch oneof: // precondition: must be empty
case 2: LogFatal("!bundle.has_dma()", isa_emitter.cc:157)
case 6: LogFatal("!bundle.has_stream()", isa_emitter.cc:158)
case 1: LogFatal("!bundle.has_scalar_alu()", isa_emitter.cc:159)
if !(flags & 1): LogFatal("flags & SLOT_S0", isa_emitter.cc:161) // requires S0
if !(flags & 2): LogFatal("flags & SLOT_S1", isa_emitter.cc:162) // and S1
clear_scalar_instruction(bundle) // 0x1fb59220
*(u32*)(bundle + 0x38) = 2 // set oneof = dma
dma = Arena::DefaultConstruct<SparseCoreDma>(bundle.arena) // 0x1fb5a480
*(u64*)(bundle + 0x30) = dma
return __variant_dispatch[0](visitor, dma) // {SparseCoreDma*, SparseCoreTecDma*}注意 — DMA arm 要求同时设置
SLOT_S0和SLOT_S1。 除 oneof 为空的前置条件外,反编译还显示两个LogFatal断言:DMA 操作必须携带两个 scalar-ALU slot-flag 位(SLOT_S0和SLOT_S1)。DMA 描述符占据两个双发射标量 lane 的宽度,因此调度器必须同时保留二者;缺少任一位的 DMAMCInst是致命的编译器不变量违规,不是可恢复状态。随后{SparseCoreDma*, SparseCoreTecDma*}上的 variant 会把 simple/general/strided/iova DMA 子 consumer 路由到下游。
可选跳过(4 个 opcode)和 no-op(1 个 opcode)
// optional-skip arm (glc 0x139f17bf)
case 0x100d: case 0x100e: case 0x1015: case 0x10f2:
if (!tolerate_skip) goto DEFAULT // bool = consumer's 4th argument
return OK // silently drop the op
// no-op arm (glc 0x139f176a)
case 0x264:
return OK // no slot fill, no descriptor
```text
optional-skip arm 由 consumer 的 `bool` 参数(反编译中的 `char a4`,第 4 个参数)门控四个 opcode:置位时,这四个操作被静默接受且不产生发射;清零时,它们落入默认错误 arm。单个 no-op opcode `0x264` 始终不发射任何内容并返回 OK——它是某个不占编码的 bundle slot 放置([TEC Engine](tec-engine.md) 页面描述的全零 NOP)。
> **特性 — optional-skip bool 会让四个 opcode 在“静默丢弃”和“硬错误”之间切换。** 该 flag 的含义(容忍 padding、speculative-decode,或逐代 feature gate)未追踪到调用方(LOW)。确定的是:flag 清零时,opcode `0x100d/0x100e/0x1015/0x10f2` 不受支持;flag 置位时,它们从 bundle 中消失且不报错。重新实现者必须从 bundle-consume loop 传递这个 bool,否则包含这四个操作的 stream 要么报错,要么 round-trip 不一致。
---
## Bundle 不变性
`ConsumeOneSlotInstruction` 是以 bundle 类型为参数的模板,SC 发射器将其例化三次——分别用于 SCS、TAC 和 TEC 标量区域。所有三个实例在分类结构上逐字节相同。
| Bundle | 路由器入口 | 跳转表 | Base | Bound | Arm 分布 |
|---|---|---|---:|---:|---|
| `SparseCoreTacBundle` | `0x139f1360` | `0xae8dce4` | `0x1f3` | `0xfb2` | 2817/888/92/70/54/49/27/17/4/1 |
| `SparseCoreScsBundle` | `0x13a50540` | `0xaea9fb4` | `0x1f3` | `0xfb2` | identical |
| `SparseCoreTecBundle` | `0x13a15500` | `0xaea4ba0` | `0x1f3` | `0xfb2` | identical |
opcode→arm 映射在三者之间相同;只有 `GetStreamSlot<…,Bundle>`、`GetScalarAluSlot<…,Bundle>` 等函数上的 bundle 模板实参不同。三个 bundle 都携带双 scalar-ALU 子槽(`GetScalarAluSlotS0`/`S1` 在每个实例中都存在且可达),因此 S0/S1 双发射标量几何是 SC 标量 slot 的属性,而不是某个 engine 独有的属性。
> **注意 — TEC bundle 的*向量* slot 在别处路由。** `ConsumeOneSlotInstruction<SparseCoreTecBundle>` 只处理 TEC bundle 的*标量*区域(与 SCS 和 TAC 相同的 Stream/Misc/Alu/DMA slot)。TEC 的向量 slot 由独立的 `ConsumeOneTecBundleInstruction`(`0x13a08e00`)分派,如下一节所述。重新实现者不应在 OneSlot 路由器中寻找 `VectorAlu`;它不在那里。
---
## 到达 VectorAlu — 独立的向量路径
### 为什么向量分派是另一个函数
TEC bundle 是唯一带向量计算区域的 SC bundle,其向量 slot(`VectorAlu0/1/2`、`VectorLoad`、`VectorStore`、`VectorExtended`、`VectorResult`)由 `ConsumeOneTecBundleInstruction`(`0x13a08e00`)路由,该函数在逐 `MCInst` 的 TEC 分派器下与 `ConsumeOneSlotInstruction` *并列*。标量路由器和向量路由器共享相同的分类*惯用法*——读取 `DWORD[MCInst]`、减去基址、边界检查、通过 `.rodata` 表间接跳转——但它们是带有不同表的不同函数,因为标量 opcode 空间(基于 `0x1f3`)和向量 opcode 空间(`VectorAlu` 基于 `0xb26`)互不相交。
### `ConsumeVectorAluInstruction` — 到达 142 个操作
`VectorAlu` slot 的 consumer 是 `ConsumeVectorAluInstruction<glc::SparseCoreTecBundle>`(`0x13a0b580`),对 `VectorAlu` 块中的任何 opcode,它由 `ConsumeOneTecBundleInstruction` 到达。其分派形状与标量路由器相同,但使用向量基址和边界:
```c
// ConsumeVectorAluInstruction // glc 0x13a0b580
// args: (printer, mcinst, &vregports /*btree_set<SparsecoreVregReadPort>*/, &proto, &bundle)
function ConsumeVectorAluInstruction(printer, mcinst, vregports, proto, bundle):
idx = mcinst.opcode - 0xb26 // jt base 0xb26
if (unsigned)idx > 0x5cf: // bound 0x5cf (1488 entries)
return Error("Unsupported opcode for Vector Alu slot: $0 : $1", …)
switch jt[idx]: // jt @0xae9d3dc, 143 targets
case 0xb26: proto.mutable_vector_add_bf16();
return EmitVectorBinop<…VectorAddBf16,SparsecoreVregReadPort>(mcinst)
case 0xc9f: proto.mutable_cosq_f32();
return EmitExtendedVectorVxUnop<…CosqF32>(mcinst)
case 0xe87: GetOperandAndVsEncoding(mcinst, 1);
proto.mutable_pack_compressed_b16_to_b8();
return EmitPackVectorBinop<…PackCompressedB16ToB8>(mcinst)
// 7 f32 compares + VectorMove share one oneof-dispatch chain [proto+0x50]
default: return Error(…) // 1213 opcodes每个 arm 都调用 SparseCoreTecVectorAlu::_internal_mutable_<op>() 选择 proto oneof 字段,然后尾跳到九种 Emit* 模板之一。第五个模板参数 SparsecoreVregReadPort(作为 btree_set 参数携带)是 bundle 调度器必须在三个并发 lane 间满足的逐 bundle 读端口保留。142 个可达操作——135 个单操作 arm 加上通过一个共享 f32-compare/move oneof 链到达的七个操作——其 opcode 值、发射模板和逐代差异,是 TEC Vector Opcode Enumeration 页面的主题,此处不重复。
注意 — 标量和向量的默认错误字符串是不同的
.rodata字面量。VectorAlu默认错误字符串是 "Unsupported opcode for Vector Alu slot: $0 : $1"。标量 OneSlot 路由器使用 "while consuming slot instruction" 表述;向量 consumer 使用 "for Vector Alu slot"。二者均已在反编译函数体中逐字节确认。易错点 — 标量与向量分派不仅表不同,签名也不同。
ConsumeOneSlotInstruction接收(printer, mcinst, &bundle, bool),填充一个标量 slot 后返回。ConsumeVectorAluInstruction接收(printer, mcinst, &vregports, &proto, &bundle)——它还传递SparsecoreVregReadPortbtree 和预先选定的SparseCoreTecVectorAluproto,因为向量操作会绑定调度器按 bundle 追踪的读端口。重新实现者不能把标量路由器的调用约定复用于向量 slot。
函数映射
| Symbol | Address | Role |
|---|---|---|
ConsumeOneSlotInstruction<…TacBundle> | 0x139f1360 | 标量 slot 路由器(本页);jt base 0x1f3,bound 0xfb2 |
ConsumeOneSlotInstruction<…ScsBundle> | 0x13a50540 | SCS 实例;jt 0xaea9fb4,arm 映射相同 |
ConsumeOneSlotInstruction<…TecBundle> | 0x13a15500 | TEC 标量实例;jt 0xaea4ba0,arm 映射相同 |
getSlotFlagsFromMCInst | 0x13c798e0 | return *(u32*)(mcinst+0x4) — slot-flag word 来源 |
| OneSlot jump table(TAC) | 0xae8dce4 | 4019×int32 rel offsets;10 个 arm 目标 |
GetStreamSlot<…,TacBundle> | 0x139fa760 | Stream slot accessor |
GetScalarMiscSlot<…,TacBundle> | 0x139eeac0 | ScalarMisc slot accessor |
GetScalarAluSlot<…,TacBundle> | 0x139f0800 | 通用 ScalarAlu slot accessor(StatusOr) |
GetScalarAluSlotS0 / …S1 | 0x139f7300 / 0x139f74a0 | 双发射子槽 accessor |
ConsumeStreamInstruction | 0x139fa940 | Stream slot 叶子 consumer |
ConsumeScalarMiscInstruction | 0x139eeca0 | ScalarMisc slot 叶子 consumer |
ConsumeScalarAluInstruction | 0x139f09c0 | 通用 ScalarAlu 叶子 consumer |
ConsumeScalarAluSlotS0Instruction / …S1 | 0x139f9480 / 0x139f9be0 | 双发射叶子 consumer |
clear_scalar_instruction | 0x1fb59220 | DMA arm:清除 scalar_instruction oneof |
Arena::DefaultConstruct<SparseCoreDma> | 0x1fb5a480 | DMA arm:实体化 DMA 描述符 |
| DMA variant dispatcher | 0x13a04820 | {SparseCoreDma*, SparseCoreTecDma*} value-visitor |
MakeErrorImpl<9> | 0x2111e900 | 两条路由器错误路径 |
ConsumeOneTecBundleInstruction | 0x13a08e00 | 独立的 TEC 向量 slot 分派器 |
ConsumeVectorAluInstruction<…TecBundle> | 0x13a0b580 | 到达 142 操作的 VectorAlu 表;jt 0xae9d3dc,base 0xb26 |
错误字符串(.rodata):"Unsupported opcode while consuming slot instruction: $0 : $1"(0x9e6fbec,default arm)和 "Invalid slot. Expected Scalar Slot. MCInst Flags: $0"(0x9fbf02c,multi-scalar no-flag arm)。源文件 platforms/xla/sparse_core/ghostlite/isa_emitter.cc(0x8762dbb)。
注意事项
- Slot 类别由 opcode 驱动;子槽由 flag 驱动。 五个固定 slot arm 只从 opcode 解码;54 操作的 multi-scalar arm 和 DMA arm 读取
SparseCoreMCSlotflag word(MCInst+0x4)。正确重新实现需要同时具备 4019 项表和上游 flag 写入纪律,否则 multi-slot 操作会被错误路由。 - 路由器是放置接缝,不是编码器。 它选择 slot 并写入 predication(
EmitPredicationToSlot);逐 slot 的Consume<Slot>Instruction叶子函数填充 slot body,而<Slot>Encoder::Encode(BitCopy)在其下方写入绝对 bundle 位。字节级编码位于各个逐 slot 页面,不在此处。 - DMA 前置条件是
LogFatal,不是 status。 DMA arm 的 oneof-empty 检查及其SLOT_S0/SLOT_S1要求是编译器不变量(LogMessageFatal),因此违规会 abort,而不是返回错误状态。重新实现者必须在上游保证这些条件;它们在路由器处不可恢复。 - 向量分派是并行机制,不是子 arm。
ConsumeOneSlotInstruction永远不会到达VectorAlu;向量 slot 由ConsumeOneTecBundleInstruction→ConsumeVectorAluInstruction路由,且签名不同(传递SparsecoreVregReadPortbtree 和SparseCoreTecVectorAluproto)。应把两个路由器视为 TEC bundle 分派器下的同级。 - optional-skip bool 是未追踪的策略输入(LOW)。 四个 opcode 会依据 consumer 的
bool在 drop 和 error 之间切换。该位已逐字节确认;其调用方含义尚未确认。请从 bundle-consume loop 传递它,并把这四个 opcode 视为有条件支持。
相关组件
| Name | Relationship |
|---|---|
ConsumeOneTecBundleInstruction(0x13a08e00) | 位于本路由器和向量 consumer 之上的逐 MCInst TEC 分派器 |
ConsumeVectorAluInstruction(0x13a0b580) | 同级向量 slot consumer,到达 142 操作的 VectorAlu 表 |
getSlotFlagsFromMCInst(0x13c798e0) | multi-scalar 和 DMA arm 用于子路由的 MCInst+0x4 slot-flag word |
Get<Slot>Slot / Consume<Slot>Instruction family | 各个 arm 尾调用的 slot accessor 和叶子 consumer |
EmitPredicationToSlot<…> | 在叶子 consumer 填充 slot 之前,把操作的 predicate guard 写入该 slot |
交叉引用
- TEC(向量)Engine — 64 字节 bundle、标量 slot 字节/位基址,以及路由器把操作放入其中的双发射 S0/S1 几何结构。
- SCS Engine — 标量控制 sequencer;
ConsumeOneSlotInstruction<SparseCoreScsBundle>是用于 SCS 标量区域的同一个路由器。 - TEC Vector Opcode Enumeration — 142 操作
VectorAlu清单及其发射模板,通过ConsumeVectorAluInstruction到达(此处链接,不重复)。 - SCS Scalar Opcode Enumeration — 标量 opcode 清单,以及写入本路由器读取的
SparseCoreMCSlot位的setSlotFlagInMCInst纪律。 - VectorLoad Slot — 由
ConsumeOneTecBundleInstruction路由的 TEC 向量 slot,不由本标量路由器路由。 - VectorStore Slot — tile vector-store + scatter-add slot,同样属于向量路径。
- VectorExtended (VEX) — scan/sort/dedup 向量 slot,也通过向量分派器到达。
- SparseCore Overview — 三个 engine 类别、逐代存在性以及 codec-template sequencer enum。
- 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