kIsaTable 数据段
本页中的每个偏移、值、地址和大小都逐字节精确读取自
libtpu-0.0.40-cp314wheel 中的libtpu.so(BuildID md589edbbe81c5b328a958fe628a9f2207d,未 stripped — 完整 C++ 符号)。所有地址都是虚拟地址;.rodata/.lrodata按 1:1 映射(VA == file offset);.data.rel.ro的 VA − file offset =0x200000。其他 wheel 版本会不同。
摘要
"kIsaTable" 是对编译器 .rodata 中内置的逐代 ISA 编码描述符数据的惯用称呼,也就是编码器和解码器按 opcode 索引的 opcode/encoding 表。libtpu 中没有字面名为 kIsaTable 的符号。相反,逐代 ISA 编码这一角色被拆分到五类具体静态结构中,每一类都已定位、确定大小并部分解码:逐代 CodecMetadata 类(bundle 字节宽度、check byte、chunk 几何)、LLVM TPU 后端表(InstBits、TPUDescs、TPUInstrName*、逐代 SchedModel 表)、逐代 kNoopBundleBytes NOP 模板、Ghostlite kLloOpcodeToGlcInstruction 翻译表,以及封装 codec metadata 的逐代 Encoder*/Decoder* 类。本页是这些段的地图:每个 blob 是什么、位于哪里、有多大,以及 encode/decode 路径如何索引它。
重实现者首先需要的架构事实是:编码数据不是一个按 (gen, opcode) 索引的单体表。LLVM-MC InstBits 数组跨代共享,但只为 Pufferfish BarnaCore HwMode 填充(每个 TensorCore 和 V5+ 行都是全零 — 见 InstBits Master DB);真正的 V5+ bundle 位由逐代 proto-bundle Encoder<gen> 类生成,其几何来自 CodecMetadata 注册表,而不是来自 InstBits。因此,“kIsaTable” 实际上是一个小型联合体:用于 bundle 几何的逐代 codec-metadata vtable 注册表、用于 MC 层 descriptor/name/sched 表的 LLVM TableGen .lrodata 区域、三个静态 NOP 模板,以及一个 Ghostlite 专用 opcode 翻译数组。
本页按成员记录这个联合体 — namespace/generation 映射、CodecMetadata 类及其逐代常量、带地址和大小的 LLVM 后端表清单、NOP 模板,以及 Ghostlite LLO→GLC 表 — 并说明编码器如何到达各成员。它是一个目录页:给出已确认的地址和大小,以及索引各 blob 的算法,而不是倾倒 181 KB 的 base bits。
对重实现而言,契约是:
- generation → namespace → LLVM-target 映射(6 个 codename,3 个 HAL family,
TpuVersion 0..5)— 每个 encoder/table 符号都按这套分类命名。 - 逐代
CodecMetadata类(7 个 virtual)是 bundle-geometry “kIsaTable”:BundleSizeBytes、…ForHbm、HasCheckByteForHbm、BundleCheckByte、…Mask、BundleChunkSize、BundlesPerChunk,通过进程级注册表按(TpuVersion, TpuSequencerType)keyed。 - LLVM TPU 后端
.lrodata表(InstBits@0x3366d90、TPUDescs@0x33bf650、TPUInstrNameData/Indices、逐代 SchedModelSchedClasses/ProcResources)— MC 层 descriptor 联合体,按opcode − 499索引。 - 逐代
kNoopBundleBytes(64 字节 V5+ NOP 模板),以及 pre-V5 gens 使用kNeverExecute = 31动态构造 NOP。 - Ghostlite
kLloOpcodeToGlcInstruction(258 项排序(u16, u16)数组 @0x4067dc8)— 唯一的静态逐代 LLO→ISA 翻译表;其他 gens 使用 switch 语句。
字面 kIsaTable 符号 | 无 — 角色拆分到 5 类结构 |
| Generations | Jellyfish / Dragonfish / Pufferfish / Viperfish / Ghostlite / 6acc60406 (TPU7x) (TpuVersion 0..5) |
| Codec 注册表 | CodecMetadataRegistry (absl::flat_hash_map<TpuVersion, pair<char*, CodecMetadata*>>, StaticMapBase singleton) |
| Codec 查找 | GetMetadataOrDie(TpuVersion) → 失败时 dies "Codec metadata not registered for TpuVersion" |
| MC base-bits | InstBits @ 0x3366d90 (0x2c460 B) / InstBits_BarnaCorePxcHwMode @ 0x33931f0 |
| MC descriptors | TPUDescs @ 0x33bf650 (0x33590 B); TPUInstrNameData @ 0x33f2be0; TPUInstrNameIndices @ 0x3435d30 |
| NOP 模板 | kNoopBundleBytes — vxc @ 0xb846d64, gxc::glc @ 0xb862ff4, gxc::gfc @ 0xb88580a (各 64 B) |
| Ghostlite xlat | xla::ghostlite::kLloOpcodeToGlcInstruction @ 0x4067dc8 (0x408 B = 258 × 4) |
| 置信度 | CONFIRMED(byte-anchored),除非某行另有说明 |
Generation 和 Namespace 映射
每个表和编码器符号都按三轴分类命名:codename、HAL family 和内部 C++ namespace。该映射从符号 demangling 和嵌入的 codec_metadata_<gen>.cc 源路径锚点恢复而来。
| Codename | TpuVersion | Family | 内部 namespace | LLVM subtarget |
|---|---|---|---|---|
| Jellyfish | 0 | JXC | platforms_deepsea::jellyfish::isa | TPUSubtarget (base) |
| Dragonfish | 1 | JXC | (共享 JellyfishCodecMetadata) | base |
| Pufferfish | 2 | PXC | asic_sw::deepsea::pxc::isa | base + TPUBcSubtarget |
| Viperfish | 3 | VXC | asic_sw::deepsea::vxc::isa | TPUVfcSubtarget |
| Ghostlite | 4 | VXC=GXC | asic_sw::deepsea::gxc::glc::isa | TPUGlcSubtarget |
| 6acc60406 (TPU7x) | 5 | VXC=GXC | asic_sw::deepsea::gxc::gfc::isa | TPUGfcSubtarget |
SparseCore 子 namespace(vxc::vfc::isa、gxc::glc::isa::sparsecore、gxc::gfc::isa::sparsecore)和 Pufferfish BarnaCore(pxc::pfc::isa)带有自己的编码器。(TpuVersion, TpuSequencerType) pair 是进入 codec metadata 的完整 key — 一颗芯片有若干 sequencer type,bundle 宽度不同(见 Bundle Model)。八个 TpuSequencerType 值是 TC=0, BCS=1, BCAH=2, SCS=3, TAC=4, TEC=5, SCv0=6, SCv0AH=7;逐代 presence matrix 记录在 Bundle Model。
NOTE — v5 generation 在二进制中只以 codename
6acc60406出现(tpu::TpuVersion::k6acc60406enumerator、TPU_VERSION_6acc60406、xla_target_6acc60406,以及.../target/6acc60406/源路径);营销名 "Trillium" 和 "Ironwood" 在libtpu.so中出现 0 次。本页使用二进制 codename,并在首次出现时注释为(TPU7x)。Ghostlite (
glc) 和 6acc60406 (gfc) 都属于 GXC family,因此它们的符号共享gxc::前缀。表中可见的一个结构差异是:存在SparseCoreTacGL*SchedModel,但没有SparseCoreTacGF*— 6acc60406 没有 TAC sequencer(由下方符号缺失确认)。
CodecMetadata — Bundle-Geometry “kIsaTable”
最接近逐代 kIsaTable 的东西是 CodecMetadata 类:每代一个 subclass,派生自抽象基类 platforms_deepsea::jellyfish::isa::codec_metadata::CodecMetadata,暴露七个按 TpuSequencerType keyed 的 virtual。vtable 布局固定(由 BundleSizeBytes thunk 解引用 *((vtable) + N) 确认):
| vtable slot | virtual | 含义 |
|---|---|---|
+16 | BundleSizeBytes(seq) | 线上形式(DMA form)每个 bundle 的字节数 |
+24 | BundleSizeBytesForHbm(seq) | 存在 HBM 中每个 bundle 的字节数(可能添加 check byte) |
+32 | HasCheckByteForHbm(seq) | HBM form 是否追加 check byte? |
+40 | BundleCheckByte(seq) | 期望的 check-byte 值(普遍为 0x55) |
+48 | BundleCheckByteMask(seq) | compare 前的 mask(普遍为 0xFF) |
+56 | BundleChunkSize(seq) | 线上 chunk 大小,单位字节 |
+64 | BundlesPerChunk(seq) | 每个 chunk 的 bundle 数 |
注册表和查找
逐代实例被放入进程级 CodecMetadataRegistry — 一个通过 util_registration::StaticMapBase singleton 构建一次的 absl::flat_hash_map<tpu::TpuVersion, pair<char const*, CodecMetadata const*>>。四个全局构造函数注册四个 codec 类;GetMetadataOrDie(TpuVersion) (@ 0x1ecf6f60) 以 map 为 key 查找,miss 时以 "Codec metadata not registered for TpuVersion: " dies。自由函数 dispatch wrapper(codec_metadata::BundleSizeBytes(TpuVersion, TpuSequencerType) @ 0x1ecf7180,以及六个 sibling @ 0x1ecf71a0…0x1ecf7240)调用 GetMetadataOrDie,然后索引解析出的实例的 vtable:
// codec_metadata::BundleSizeBytes(TpuVersion v, TpuSequencerType t) @ 0x1ecf7180 (dispatch)
md = GetMetadataOrDie(v); // flat_hash_map lookup; LogFatal on miss
return md->vtable[+16](t); // virtual BundleSizeBytes(t) on the per-gen class
```text
| registering ctor | registers |
|---|---|
| `_GLOBAL__sub_I_codec_metadata_jellyfish.cc` @ `0x213673e0` | JF=0 **and** DF=1 (same instance) |
| `_GLOBAL__sub_I_codec_metadata_pufferfish.cc` @ `0x21367470` | PF=2 |
| `_GLOBAL__sub_I_codec_metadata_viperfish.cc` @ `0x213674c0` | VF=3 |
| `_GLOBAL__sub_I_codec_metadata_ghostlite.cc` @ `0x21367510` | GL=4 |
Jellyfish 注册**两个** key(0 和 1)到*同一个* `JellyfishCodecMetadata` 实例 — Dragonfish (v1) 复用 Jellyfish (v0) codec。没有 `_GLOBAL__sub_I_codec_metadata_6acc60406` 构造函数:6acc60406 没有注册 codec metadata,因此 `GetMetadataOrDie(5, …)` 会 fatal abort。6acc60406 bundle 几何只通过 `gxc::gfc::isa` 中 type-erased 的 `EncoderBase<…>` 模板 vtable 到达(它们通过自己的 `vtable[+48]` forward `BundleSizeBytes`),绝不经由注册表。
### 逐代常量
直接从 `BundleSizeBytes` virtual 反编译得到 — `(seq, return)` 分支是精确的:
```c
// JellyfishCodecMetadata::BundleSizeBytes @ 0x1ecf7460
if (seq == 0) return 41; // TensorCore
if (seq == 1) return 16; // BarnaCoreAddressHandler
LogFatal("Unhandled component"); // codec_metadata_jellyfish.cc:19
// ViperfishCodecMetadata::BundleSizeBytes @ 0x1ee71320
if (seq != 0) LogFatal("Unhandled component"); // codec_metadata_viperfish.cc:20
return 64; // TensorCore| Gen (seq=TC) | BundleSizeBytes | check byte | chunk | bundles/chunk | metadata @ |
|---|---|---|---|---|---|
| Jellyfish / Dragonfish | 41 | 0x55 | 128 | 3 | 0x1ecf7460… |
| Pufferfish | 51 | 0x55 | 51 | 1 | 0x1ecf7ac0… |
| Viperfish | 64 | 0x55 | 64 | 1 | 0x1ee71320… |
| Ghostlite | 64 | 0x55 | — | — | 0x1eeb7640… |
| 6acc60406 | 64 | (template; no registry) | — | — | (no class) |
…ForHbm virtual 在 Pufferfish/Ghostlite 上对 seq=0 会 fatal abort(它们的 TensorCore HBM 路径直接走 EncoderPfTensorCore / EncoderGlTensorCore,而不是这个 metadata);Jellyfish 的 …ForHbm 返回 42(41 + 1 check byte)。逐代完整几何 — 包括 HBM +1 check byte 和 Jellyfish 的 (n/3)*128 + (n%3)*43 chunk 布局 — 见 Bundle Model。
LLVM TPU 后端表
编译器在 libtpu 中嵌入了完整的 LLVM TPU 后端,其 TableGen 生成的表位于一个连续的 .lrodata 区域(另有少数在 .data.rel.ro 中)。这些是 MC 层 descriptor 联合体 — 逐 opcode 编码位、descriptor、mnemonic、寄存器编码和逐代调度模型。它们按 opcode − 499 索引(前 499 个 opcode 是 MC pseudos)。
| Symbol | Address | Size | Purpose |
|---|---|---|---|
…getBinaryCodeForInstr::InstBits | 0x3366d90 | 0x2c460 (181344 B = 5667 × 32) | base bits,TensorCore mode(全零) |
…InstBits_BarnaCorePxcHwMode | 0x33931f0 | 0x2c460 | BarnaCore variant(704 个填充行) |
llvm::TPUDescs | 0x33bf650 | 0x33590 | 逐 opcode MCInstrDesc(operand type、flag) |
llvm::TPUStages | 0x343bd90 | 0x7c8 | pipeline-stage 表 |
llvm::TPUInstrNameData | 0x33f2be0 | 0x4314c | mnemonic 字符串池(约 270 KB) |
llvm::TPUInstrNameIndices | 0x3435d30 | 0x6058 | opcode → NameData 中的字节偏移 |
llvm::TPURegDesc | 0x343e7b0 | 0x5358 | register descriptors |
llvm::TPURegStrings | 0x343cde0 | 0x19c9 | register name strings |
llvm::TPURegEncodingTable | 0x34469b0 | 0x6f2 | reg# → HW encoding (889 × u16) |
llvm::TPURegClassInfos | 0x334ea60 | 0x800 | register-class metadata |
llvm::TPUFeatureKV | 0x21934550 | 0x480 | SubtargetFeature KV(约 48 × 24 B) |
llvm::TPUSubTypeKV | 0x21934ca0 | 0x3f0 | subtype/CPU KV(约 42 × 24 B) |
InstBits 是该联合体的 LLVM-MC 切片;它在 InstBits Master DB 中完整记录,包括其反直觉的全零默认表(TensorCore 和 V5+ 行不携带任何 bits — 这些 bundle 由 proto-bundle Encoder<gen> 路径编码,而不是由 getBinaryCodeForInstr 编码)。索引算术((opcode − 499) × 32 字节、5667 行、239-bit APInt)见 239-Bit Record Format。names JSON 确认 TPU InstBits 符号与 AArch64/AMDGPU/ARM/R600/PPC InstBits 并列 — 二进制嵌入了多个 LLVM target,TPU 这个才是相关成员。
逐代 SchedModel 表
每个非 TensorCore sequencer 都有一个 SchedClasses 表(每个 0x79a = 1946 B)和一个 ProcResources 表(每个 MCProcResourceDesc entry 为 per-cycle resource bitmask,16 B)。这些符号集合就是逐代 sequencer 清单:
| Sequencer × gen | SchedClasses @ | ProcResources @ / size |
|---|---|---|
| BarnaCore (PF) | 0x3447630 | 0x21935740 / 0xa0 (10 PR) |
| SCS — 6acc60406 (GF) | 0x3448350 | 0x219357e0 / 0x320 (50 PR) |
| SCS — Ghostlite (GL) | 0x3449070 | 0x21935b00 / 0x300 (48 PR) |
| SCS — Viperfish (VF) | 0x3449d90 | 0x21935e00 / 0x2a0 (42 PR) |
| TAC — Ghostlite (GL) | 0x344a530 | 0x219360a0 / 0x300 |
| TAC — Viperfish (VF) | 0x344acd0 | 0x219363a0 / 0x2a0 |
| TEC — 6acc60406 (GF) | 0x344b470 | 0x21936640 / 0x320 |
| TEC — Ghostlite (GL) | 0x344bc10 | 0x21936960 / 0x300 |
| TEC — Viperfish (VF) | 0x344c3b0 | 0x21936c60 / 0x2a0 |
ProcResources 字节大小单调增长 — VF 0x2a0(42 units)、GL 0x300(48)、GF 0x320(50)— 因此 6acc60406 比 Viperfish 多 8 个 functional units。names table 中没有 SparseCoreTacGF* 符号,这是 6acc60406 没有 TAC sequencer 的字节级证据(它的 SparseCore 只有 SCS + TEC)。每个 TPUVfcSubtarget / TPUGlcSubtarget / TPUGfcSubtarget 都按 gen override getFifoDepth、getVyEncodings 和 getSyEncodings。
NOP Bundle 模板
V5+ generations 在 .rodata 中携带一个静态 64 字节 NOP-bundle 模板;pre-V5 gens 动态构造 NOP。这些模板是 empty-bundle 的 ground truth — NOP 用 kNeverExecute = 31 (0x1F) 填充每个 slot 的 predicate 字段,因此 decoder 能 round-trip 一个 absent slot。
Symbol ((anonymous namespace)::kNoopBundleBytes) | Address | Size | byte 63 | encoding style |
|---|---|---|---|---|
asic_sw::deepsea::vxc::isa | 0xb846d64 | 64 B | 0x55 | 每个 slot predicate 为 0x1F << shift |
asic_sw::deepsea::gxc::glc::isa | 0xb862ff4 | 64 B | 0x53 | 更紧凑的 shift base(e0 01、c0 03) |
asic_sw::deepsea::gxc::gfc::isa | 0xb88580a | 64 B | 0x50 | 全零 body(zero-default slots) |
Viperfish 模板的非零 pattern(00 3c、00 0f、00 f0、00 78)是将 0x1F 移到每个 slot 的 predicate bit offset,byte 63 = 0x55 check byte。Ghostlite 使用不同的(更紧凑的)shift base,因此其 slot bit layout 不同(byte 63 = 0x53,不是字面 check byte — 高位携带最后一个 slot 的 predicate,与 check field OR 在一起)。6acc60406 的模板除 byte 63 = 0x50 外全为零 — 6acc60406 安排 slot 时让全零表示“present but inactive”,而不是“active with an always-false predicate”。Jellyfish 和 Pufferfish 没有 kNoopBundleBytes 静态量;它们的 EncodeBundleInternal 将 buffer zero-init,并在运行时把 kNeverExecute = 31 patch 到每个 predicate 字段中。kNeverExecute = 31 / kAlwaysExecute = 15 / kPredicateRegisterCount = 15 常量(0xb834cf4…0xb834cff)确认 Jellyfish predicate 字段为 5 bit。见 Bundle Model §Empty-Slot。
Ghostlite LLO → GLC 翻译表
xla::ghostlite::kLloOpcodeToGlcInstruction(0x4067dc8,0x408 B)是 xla:: namespace 中唯一的逐代静态 LLO→ISA 翻译表:一个 258 项排序数组,元素为 (uint16_t llo_opcode, uint16_t glc_instruction) pair,按 llo_opcode 二分搜索。
// xla::ghostlite::kLloOpcodeToGlcInstruction @ 0x4067dc8 (258 × 4 B, sorted ascending)
struct { uint16_t llo_opcode; uint16_t glc_instruction; } entries[258];
// e.g. {9, 118}, {10, 474}, {11, 474}, {13, 70}, ... {424, 23}, {425, 26}, {426, 25}
```text
- LLO opcode 覆盖是稀疏的:`9..426`(所用约 418 范围中的 258 个)。
- GLC instruction 范围是 `0..475`。
- 该映射是**多对一** — 例如 LLO `10` 和 `11` 都映射到 GLC `474`;LLO `37` 和 `39` 都映射到 GLC `0` — 因此 GLC opcodes 比 LLO IR opcodes 粒度更粗。
为什么只有 Ghostlite 是静态数组:Jellyfish、Pufferfish、Viperfish 和 6acc60406 都把 LLO→ISA 映射实现为 **switch 语句**(例如 `xla::jellyfish::LloOpcodeToIsaScalarOpcode` @ `0x140bc1e0`,一个 162-case switch)。Ghostlite 的 GLC 映射足够宽(>200 entries),因此优先使用排序数组二分搜索而不是 switch。反向 LLO 方向是未命名的 `LloOpcodeToProto` 表 @ `0x344cb4c`(`462 × u32`);LLO opcode 编号本身(proto `1..499` → internal `0..461`)在 `ProtoToLloOpcode`(`0x14420040`)中重建。
---
## 这些段不包含什么
这个联合体诚实地说明了自身边界:
- **完整的逐 opcode TensorCore / V5+ 编码位。** `InstBits` 对这些 opcode 全为零(没有 `.rela.dyn`,已证明);真实 bits 来自逐代 `Encoder<gen>::EncodeBundleInternal` + `<Slot>Encoder::Encode` `BitCopy` 调用,其位置是逐代 slot ladders([Immediate Slot](slot-immediate.md)、逐代 bundle 页面)。*(5667-case MC encoder switch 和内部逐 slot encoder 方法没有穷举 — 太大,无法手工枚举;未遍历的 V5+ slot encoders 为 MEDIUM。)*
- **来自注册表的 6acc60406 codec 常量。** 6acc60406 没有注册 `CodecMetadata`;此处的 64 字节几何读取自 `kNoopBundleBytes` 大小和 `EncoderBase` 模板,而不是注册表条目。*(6acc60406 check byte 为 HIGH,而非 CONFIRMED。)*
- **GLC instruction mnemonics。** `kLloOpcodeToGlcInstruction` ID(`0..475`)已解码,但其名称需要在 Ghostlite HwMode 下交叉解码 `TPUInstrNameData` — 此处未做。
- **逐代 `TPUFeatureKV` / `TPUSubTypeKV` 内容。** 已定位并确定大小(约 48 features、约 42 subtargets),但未枚举单个 feature/CPU 字符串。
---
## 交叉引用
- [Bundle Model](bundle-model-overview.md) — `(TpuVersion, TpuSequencerType)` codec-metadata dispatch、逐代 bundle 宽度和 empty-slot `kNeverExecute` 约定。
- [InstBits Master DB](instbits-master-db.md) — `InstBits` base-bits 数据库(该联合体的 LLVM-MC 成员)、其全零默认表,以及 BarnaCore class field maps。
- [239-Bit Record Format](record-format.md) — `InstBits`/`TPUDescs` 表输入的 MC `APInt` record,以及 `opcode − 499` 索引。
- [MC-Emitter](mc-emitter.md) — `getBinaryCodeForInstr`,索引 `InstBits` 和 `TPUDescs` 的 consumer。
- [Immediate Slot](slot-immediate.md) — V5+ proto-bundle 编码器写入的逐代 immediate-slot ladders(`InstBits` *不*包含的 bits)。
- [TPUMCImm / SyImm32](tpumcimm-syimm32.md) — 通过相同后端表携带的 MC immediate operand。