Skip to content

OneSlot 标量路由器

本页中的每个地址、opcode 值、slot-flag 位以及跳转表边界,均逐字节读取自 libtpu-0.0.40-cp314 wheel 中的 libtpu.so(build-id 89edbbe81c5b328a958fe628a9f2207d)——来源包括反编译的 ConsumeOneSlotInstruction 函数体、其被调尾部函数以及 .rodata 跳转表。其他版本会不同。

摘要

ConsumeOneSlotInstruction 是 SparseCore SC-MLO 发射器的标量槽路由器:给定一个已解码的 MCInst,其 opcode 命名某个标量(非向量)SC 操作,它决定该操作占用 bundle 的哪个物理发射槽——StreamScalarMiscScalarAlu(及其双子槽 S0/S1)或 DMA——然后尾调用匹配的 Consume<Slot>Instruction 叶子函数,将该操作降低到该槽的 proto 字段中。它不是逐操作编码器;它是位于逐槽 consumer 之上的分派接缝,是 SparseCore 中类似 LLVM MCInst → 功能单元绑定 pass 的部分。在 TableGen 驱动的后端会把 slot 作为指令 itinerary class 携带的地方,libtpu 同时用两种方式携带它:一个 4019 项跳转表把 opcode 映射到 slot 类别,而对可在多个标量 slot 上发射的操作,则由每个 MCInst 的 flag word(getSlotFlagsFromMCInstMCInst+0x4)在发射时选择具体子槽。

该路由器具有 bundle 不变性。三个带标量区域的 SC bundle 类型——SCSTAC 以及 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,并读取 opcode DWORD[MCInst];以 0xae8dce4(TAC)处的跳转表为索引;分派到十个 arm 之一。每个非特殊 arm 选择一个 slot 类别,调用 Get<Slot>SlotEmitPredicationToSlot<…>,并尾调用 Consume<Slot>Instruction
  • 多 slot 操作的 slot-flag 子路由。 54 个 opcode 的 multi-scalar arm 没有固定 slot;它测试 slot-flag 位(flags & 1 → S0& 2 → S1& 4 → ScalarMisc),并在 {SparseCoreScalarAlu*, SparseCoreScalarMisc*} 上构造一个 std::variant value-visitor。没有设置任何位是硬错误。
  • DMA、可选跳过和 no-op arm。 70 个 opcode 的 DMA arm 在 LogFatal 保护的前置条件下,将 SparseCoreDma 实体化到 bundle 的 scalar_instruction oneof 中,然后访问 {SparseCoreDma*, SparseCoreTecDma*} variant。四个 opcode 会在 consumer 的 bool 参数置位时静默跳过;一个 opcode(0x264)不发射任何内容并返回 OK。
  • 向量路径是独立的。 ConsumeOneSlotInstruction 只处理标量 slot;TEC 向量 slot(VectorAlu/VectorLoad/VectorStore/VectorExtended)由 ConsumeOneTecBundleInstruction 分派,且 VectorAlu 通过 ConsumeVectorAluInstruction(jt base 0xb26)到达其 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)+ getSlotFlagsFromMCInstMCInst+0x4,slot-flag 位)
Arm10: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 = 4llvm::TPU::SparseCoreMCSlot
向量路径ConsumeOneTecBundleInstruction 0x13a08e00ConsumeVectorAluInstruction 0x13a0b580(独立)
来源platforms/xla/sparse_core/ghostlite/isa_emitter.cc
置信度CONFIRMED(以反编译为锚点),除非某行或标注另有说明

注意 — "OneSlot" 表示“一个标量发射槽”,不是“一条指令”。 该名称描述路由器的工作:取一个 MCInst,把它放入 bundle 的恰好一个标量 slot。它是向量分派器的标量对等物。64 字节 bundle 布局、标量 slot 的字节/位基址(Misc @111Alu1 @138Alu0 @165)以及双发射 S0/S1 几何结构位于 TEC EngineSCS Engine 页面,此处不重复。


分类逻辑

目的

路由器对每个 MCInst 回答一个问题:这个操作在哪个标量 slot 上发射? SC 标量 opcode 空间按 slot 类别划分为近似连续的区段——一个很长的 Stream 块、一个 ScalarMisc 块、一个带交错 S0/S1 双发射区段的 ScalarAlu 块——而该路由器就是解码这个划分的表。Slot 分配是 SC 指令放置的后半部分:engine(哪个 sequencer:SCS/TAC/TEC)由上游 section-classifier 选择;bundle 内的 slot 在这里选择。

入口点

text
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 路由器具有相同分布。

ArmOpcodesSlot class → action
Stream888GetStreamSlot + EmitPredicationToSlot<…Stream> + ConsumeStreamInstruction
ScalarMisc92GetScalarMiscSlot + …<…ScalarMisc> + ConsumeScalarMiscInstruction
ScalarAlu49GetScalarAluSlot(StatusOr)+ …<…ScalarAlu> + ConsumeScalarAluInstruction
ScalarAlu-S127GetScalarAluSlotS1 + ConsumeScalarAluSlotS1Instruction(固定 S1)
ScalarAlu-S017GetScalarAluSlotS0 + ConsumeScalarAluSlotS0Instruction(固定 S0)
DMA70guard oneof → clear_scalar_instructionDefaultConstruct<SparseCoreDma> → variant
Multi-scalar(flag)54flags & 1 → S0 / & 2 → S1 / & 4 → Misc;均无 → error
Optional-skip4if tolerate_skip return OK; else DEFAULT0x100d/0x100e/0x1015/0x10f2
No-op1return OK(opcode 0x264
Default / OOB2817MakeErrorImpl "Unsupported opcode while consuming slot instruction: $0 : $1"

易错点 — slot 类别在跳转表中,但 54 个操作的子槽MCInst flags 中,而不在 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,由 getSlotFlagsFromMCInst0x13c798e0)读取,其整个函数体是 return *((u32*)mcinst + 1)——也就是 flags 位于 MCInst+0x4。低三位是 llvm::TPU::SparseCoreMCSlot 枚举,由调度器在上游写入(setSlotFlagInMCInst,见 SCS scalar opcode page):

BitMaskSparseCoreMCSlot含义
00x1SLOT_S0在 scalar-ALU 子槽 0 上发射
10x2SLOT_S1在 scalar-ALU 子槽 1 上发射
20x4SLOT_SM在 ScalarMisc slot 上发射

Multi-scalar 分派

对 54 个 multi-slot opcode,该 arm 按这些位做优先级测试,并构建一个两元素 std::variant value-visitor,其索引选择 slot accessor 的 proto 类型:

c
// 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_S0SLOT_S1 除 oneof 为空的前置条件外,反编译还显示两个 LogFatal 断言:DMA 操作必须携带两个 scalar-ALU slot-flag 位(SLOT_S0SLOT_S1)。DMA 描述符占据两个双发射标量 lane 的宽度,因此调度器必须同时保留二者;缺少任一位的 DMA MCInst 是致命的编译器不变量违规,不是可恢复状态。随后 {SparseCoreDma*, SparseCoreTecDma*} 上的 variant 会把 simple/general/strided/iova DMA 子 consumer 路由到下游。

可选跳过(4 个 opcode)和 no-op(1 个 opcode)

c
// 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)——它还传递 SparsecoreVregReadPort btree 和预先选定的 SparseCoreTecVectorAlu proto,因为向量操作会绑定调度器按 bundle 追踪的读端口。重新实现者不能把标量路由器的调用约定复用于向量 slot。


函数映射

SymbolAddressRole
ConsumeOneSlotInstruction<…TacBundle>0x139f1360标量 slot 路由器(本页);jt base 0x1f3,bound 0xfb2
ConsumeOneSlotInstruction<…ScsBundle>0x13a50540SCS 实例;jt 0xaea9fb4,arm 映射相同
ConsumeOneSlotInstruction<…TecBundle>0x13a15500TEC 标量实例;jt 0xaea4ba0,arm 映射相同
getSlotFlagsFromMCInst0x13c798e0return *(u32*)(mcinst+0x4) — slot-flag word 来源
OneSlot jump table(TAC)0xae8dce44019×int32 rel offsets;10 个 arm 目标
GetStreamSlot<…,TacBundle>0x139fa760Stream slot accessor
GetScalarMiscSlot<…,TacBundle>0x139eeac0ScalarMisc slot accessor
GetScalarAluSlot<…,TacBundle>0x139f0800通用 ScalarAlu slot accessor(StatusOr)
GetScalarAluSlotS0 / …S10x139f7300 / 0x139f74a0双发射子槽 accessor
ConsumeStreamInstruction0x139fa940Stream slot 叶子 consumer
ConsumeScalarMiscInstruction0x139eeca0ScalarMisc slot 叶子 consumer
ConsumeScalarAluInstruction0x139f09c0通用 ScalarAlu 叶子 consumer
ConsumeScalarAluSlotS0Instruction / …S10x139f9480 / 0x139f9be0双发射叶子 consumer
clear_scalar_instruction0x1fb59220DMA arm:清除 scalar_instruction oneof
Arena::DefaultConstruct<SparseCoreDma>0x1fb5a480DMA arm:实体化 DMA 描述符
DMA variant dispatcher0x13a04820{SparseCoreDma*, SparseCoreTecDma*} value-visitor
MakeErrorImpl<9>0x2111e900两条路由器错误路径
ConsumeOneTecBundleInstruction0x13a08e00独立的 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.cc0x8762dbb)。


注意事项

  • Slot 类别由 opcode 驱动;子槽由 flag 驱动。 五个固定 slot arm 只从 opcode 解码;54 操作的 multi-scalar arm 和 DMA arm 读取 SparseCoreMCSlot flag word(MCInst+0x4)。正确重新实现需要同时具备 4019 项表和上游 flag 写入纪律,否则 multi-slot 操作会被错误路由。
  • 路由器是放置接缝,不是编码器。 它选择 slot 并写入 predication(EmitPredicationToSlot);逐 slot 的 Consume<Slot>Instruction 叶子函数填充 slot body,而 <Slot>Encoder::EncodeBitCopy)在其下方写入绝对 bundle 位。字节级编码位于各个逐 slot 页面,不在此处。
  • DMA 前置条件是 LogFatal,不是 status。 DMA arm 的 oneof-empty 检查及其 SLOT_S0/SLOT_S1 要求是编译器不变量(LogMessageFatal),因此违规会 abort,而不是返回错误状态。重新实现者必须在上游保证这些条件;它们在路由器处不可恢复。
  • 向量分派是并行机制,不是子 arm。 ConsumeOneSlotInstruction 永远不会到达 VectorAlu;向量 slot 由 ConsumeOneTecBundleInstructionConsumeVectorAluInstruction 路由,且签名不同(传递 SparsecoreVregReadPort btree 和 SparseCoreTecVectorAlu proto)。应把两个路由器视为 TEC bundle 分派器下的同级。
  • optional-skip bool 是未追踪的策略输入(LOW)。 四个 opcode 会依据 consumer 的 bool 在 drop 和 error 之间切换。该位已逐字节确认;其调用方含义尚未确认。请从 bundle-consume loop 传递它,并把这四个 opcode 视为有条件支持。

相关组件

NameRelationship
ConsumeOneTecBundleInstruction0x13a08e00位于本路由器和向量 consumer 之上的逐 MCInst TEC 分派器
ConsumeVectorAluInstruction0x13a0b580同级向量 slot consumer,到达 142 操作的 VectorAlu
getSlotFlagsFromMCInst0x13c798e0multi-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-id 89edbbe81c5b328a958fe628a9f2207d
  • Index entry: Part IX — SparseCore & BarnaCore / SparseCore ISA — back to index