Skip to content

InstBits 主数据库

本页中的每个偏移、值和地址都从 libtpu-0.0.40-cp314 wheel 中的 libtpu.so 逐字节读取而来(BuildID md5 89edbbe81c5b328a958fe628a9f2207d)。其他版本会有差异。

摘要

InstBits 是 LLVM TableGen 的逐 opcode base-bits 数据库,驱动 TPUMCCodeEmitter::getBinaryCodeForInstr。它是 TPU 后端中对应 LLVM 在每个 target 上称为 getBinaryCodeForInstr::InstBits 的数组实例:一个按 opcode 索引的稠密表,包含固定 instruction bit,MC emitter 会先把它复制到工作 record 中,然后 operand encoder 覆盖 operand 形状的空洞。在常规 target 上,这张表就是整个编码 — 置位 bit 是 opcode discriminator 和常量子字段,零区间是 operand 的位置。在 TPU 上,它只对一个 HwMode 是这样,对其他所有 HwMode 只是形式存在。

该数据库不是一张表,而是两张,在 .lrodata 中首尾相接:默认 InstBits0x3366d90)和 InstBits_BarnaCorePxcHwMode0x33931f0)。两者都是 5667 × 32 字节 — 每个 opcode 一行 4-word(4 × uint64),按 opcode − 499 索引,并解释为一个 239-bit APInt。emitter 通过对 MCSubtargetInfo 的 HwMode 查询在二者之间选择。逐字节验证得到的反直觉发现是:默认表在磁盘上完全为零且没有 relocation,而只有 BarnaCore 变体被填充(opcode 范围 2855..3991 中有 704 个非零行)。对每条 TensorCore 和 V5+(Viperfish / Ghostlite / 6acc60406)指令,base 都不贡献任何内容;它们的字节来自 proto-bundle emitter 路径,而不是这张表。

本页描述数据库的各个轴 — generation/HwMode × instruction-class × field — 它在二进制中的表示形式(静态 .lrodata 数组加 emitter-prologue 访问器算术),以及 slot 字段如何映射到 239-bit record 中的绝对 bit 位置。它展示真正携带数据的行(BarnaCore vector-load、vector-store、loop 和 predicate slot layout),而不是倾倒两张表的全部 11,334 行。

对重新实现而言,契约是:

  • 索引算术:index = opcode − 499,5667 个 record,32-byte stride,239-bit APInt 宽度。
  • 两表布局以及选择 default 或 BarnaCorePxcHwMode 的 HwMode select。
  • 行模型:base bit 设置 discriminator,零空洞标记 (pos, width) operand window,逐 class 的 insertBits 填充它们。
  • 已填充(BarnaCore)class 的绝对 slot-field bit 位置,这些位置从 case body 的 insertBits(pos, width) deposit 中恢复。
  • 默认表的全零 / no-RELA 属性,以及它对重新实现者的含义(V5+ encoding 位于别处)。
默认表InstBits @ 0x3366d90,size 0x2c460(181344 B = 5667 × 32)
HwMode 变体InstBits_BarnaCorePxcHwMode @ 0x33931f0,size 0x2c460(紧邻其后)
4 × uint64 = 32 B,读取为 APInt(BitWidth=0xEF=239, NumWords=4)
索引opcode − 499;首行 = 0x1f3 = 499ADDri);5667 行
访问器TPUMCCodeEmitter::getBinaryCodeForInstr @ 0x13c74da0(prologue 算术)
HwMode select默认 InstBits(GOT − 65189758)vs BarnaCore(GOT − 65167090
磁盘上的默认表全零(0 / 22668 个非零 word),没有 .rela.dyn relocation
BarnaCore 已填充704 个非零行,opcode 范围 2855..3991
置信度除非某行另有说明,否则均为 CONFIRMED(byte-anchored)

数据库轴

InstBits 数据库最好理解为一个三轴立方体。重新实现者必须复现全部三条轴;每行 32-byte payload 是从这些轴生成的,而不是作为自由数据存放。

AxisValuesSource
HwMode / tabledefaultInstBits),BarnaCorePxcHwModeInstBits_BarnaCorePxcHwModegetBinaryCodeForInstr 中两个 GOT-relative base 计算(− 65189758 / − 65167090);HwMode 查询是通过 MCSubtargetInfo vtable slot +0x28、feature index 3 的 virtual call((*(*subtarget + 40))(subtarget, 3)
instruction class22 个 encoder case body(1 个 zero-base default + 21 个 BarnaCore class)getBinaryCodeForInstr 中的 switch (opcode) 降低为一个位于 0xaed7dac 的 self-relative jump table,按 opcode − 499 索引(add $-0x1f3, %ebx; cmp $0x1622, %ebx; movslq (%rcx,%rbx,4),%rdx; add %rcx,%rdx; jmp *%rdx @ 0x13c74e7b,table base 0xaed7dac%rcx 中):一个 default arm(target 0x13c74e9d,zero base,copy-and-return)加上 opcode band 2855..3991 上的 21 个已填充 arm。Opcodes 0-498 在 table read 前由 cmp 0x1f2 / jbe 截到 trap;在 table 自身内部,opcode 499..2854(index 0..2355)的前导 entry 是死 padding — 全部持有 self-relative offset 0x08d9d0f1(即 default arm 0x13c74e9d)— 直到已填充 band 从 index 2356(opcode 2855)开始。
field逐 class 固定的 (pos, width) window(例如 base-reg @ bit 35 w6,dst @ bit 88 w5,imm @ bit 207 w16)每个 case body 中的 insertBits(value, pos, width) deposit

该立方体是稀疏的。HwMode 轴有两个值,但只有一个(BarnaCorePxcHwMode)携带数据。instruction-class 轴有 22 个值,但其中一个 — zero-base default — 吸收了 5667 个 opcode 中的 4956 个。field 轴只在 BarnaCore class 内部是稠密的;default class 根本没有字段(复制一个零行并返回)。整个编码主体都位于 2855..3991 opcode band 中,在一个 HwMode 里,分布于 21 个 case body。

QUIRK — 默认表不是等待 linker 填充的占位符。 读取 InstBits @ 0x3366d90 的全部 181344 字节会得到 0 / 22668 个非零 8-byte word,并且没有任何 .rela.dyn relocation 指向 [0x3366d90, 0x3366d90 + 0x2c460) 范围(扫描了 file offset 0x91700x1878c30 字节 .rela.dyn 中的全部 1069186Elf64_Rela entry,在任一 InstBits 范围内命中数为零)。零值就是实际编码,不是未 relocation 的 stub。期望 load-time relocation 填充这些 base bit 的重新实现会把每条 TensorCore 和 V5+ 指令编码为全零 — 而且不会看到错误,因为 proto-bundle 路径在下游提供真实字节。(作为对照,对该二进制中 AArch64 后端 InstBits 做同样提取会发现它被稠密填充,确认提取方法本身正确。)


二进制内表示

.lrodata TableGen 区域

InstBits 表是 .lrodata 中一个连续 TableGen-emitted 区域的一部分。因为该二进制中 .lrodata 满足 VA == file offset,下面每个地址都可以直接 seek。该区域是 LLVM TPUGenMCCodeEmitter / TPUGenInstrInfo / TPUGenRegisterInfo 数据,由 TableGen 后端相邻发出:

text
0x3360640  getMnemonic::OpInfo1            6166 × u32   InstPrinter mnemonic op-info
0x33666a0  getRegisterName::RegAsmOffset   ...          InstPrinter reg-name offsets
0x3366d90  InstBits                        5667 × 32B   <-- default base bits (all-zero)
0x33931f0  InstBits_BarnaCorePxcHwMode     5667 × 32B   <-- BarnaCore base bits (populated)
0x33bf650  TPUDescs                        0x33590 B    per-opcode MCInstrDesc (6166 opcodes)
0x33f2be0  TPUInstrNameData                274764 B     mnemonic string pool
0x3435d30  TPUInstrNameIndices             6166 × u32   opcode -> byte offset into NameData
0x343bd90  TPUStages                       0x7c8        pipeline stages
0x343cde0  TPURegStrings / 0x343e7b0 TPURegDesc          register names / descriptors
0x34469b0  TPURegEncodingTable             889 × u16    reg# -> HW encoding
0x344cb4c  LloOpcodeToProto                462 × u32    LloOpcode -> proto field id
```text

两张 InstBits 表恰好相隔 `0x2c460`(首尾相接),这正是 emitter 的两个 base 计算编码的间隔(`65189758 − 65167090 = 22668` 个 index unit = `0x2c460` 字节)。operand encoder 读取的 descriptor、name 和 register-encoding 表记录在 [Instr Name Data](instr-name-data.md);它们打包进入的逐 opcode 239-bit record 见 [Record Format](record-format.md)。

### 访问器算术

没有导出的 accessor function;表只在 emitter prologue 内部被访问。反编译 body 固定了本页的每个常量:

```c
// TPUMCCodeEmitter::getBinaryCodeForInstr @ 0x13c74da0  (prologue, decompiled)
uint32_t opc = *(uint32_t *)inst;          // MCInst opcode
if (opc <= 0x1F2u)                          // opcode <= 498: pseudo / target-independent
    reportUnsupportedInst(inst, inst);      //   trap (never reaches the table)

uint32_t index4 = (uint32_t)(4 * opc - 1996);  // 1996 = 0x7CC = 499*4 ; word-index = (opc-499)*4
if (index4 >= 0x588D)                        // 0x588D = 22669 -> 5667 rows
    __asm { ud1 };                           //   out of range: trap

// default path: InstBits row -> 239-bit APInt record
APInt(&record, /*BitWidth=*/239, &GLOBAL_OFFSET_TABLE_ + index4 - 65189758, /*NumWords=*/4);
// BarnaCore path (taken inside a populated case after the HwMode query):
APInt(&record, /*BitWidth=*/239, &GLOBAL_OFFSET_TABLE_ + index4 - 65167090, /*NumWords=*/4);

该算术是精确的。index4 = 4 * opc − 1996 是 word index,即 (opc − 499) × 4;乘以 8(word size)得到 (opc − 499) × 32 字节,也就是 32-byte row stride。边界 index4 < 0x588D 给出 0x588D / 4 = 0x1623 = 5667 行,而 5667 × 32 = 0x2c460 = 181344 — 两个符号在磁盘上的大小。APInt 宽度 literal 为 2390xEF),四个 word;256-bit 存储的高 17 bit 是 padding。pseudo guard(opc ≤ 498)和 ud1 out-of-range trap 是两个边界;完整 pipeline 见 MC-Emitter

NOTE — BarnaCore base read 使用同一个 index4,只是 GOT displacement 不同。两张表是在相同 opcode − 499 索引空间上的平行数组;某 opcode 的 BarnaCore 行和它的(零)default 行位于各自表中的相同索引。选择完全由 case body 使用哪个 displacement 决定,并受 HwMode feature query 门控。


Default vs BarnaCore:两张表

两张表结构相同,语义相反。default 不持有任何内容;variant 持有 MC emitter 编码的全部内容。

PropertyInstBits (default)InstBits_BarnaCorePxcHwMode
Address0x3366d900x33931f0
Size0x2c460 (5667 × 32 B)0x2c460 (5667 × 32 B)
Non-zero rows0704
Non-zero 8-byte words0 / 226682144
Populated opcode rangenone2855..3991
.rela.dyn relocationsnonenone
Opcodes encoded through it无(返回的 record 全零)Pufferfish BarnaCore lanes + native ops
Selected whenHwMode feature BarnaCorePxcHwMode inactivefeature active(vtable call MCSubtargetInfo+0x28,feature idx 3)

BarnaCore 表中已填充的行落入少量 instruction class。class taxonomy(从 getBinaryCodeForInstr switch 的 case-body grouping 恢复)是数据库的第二条轴:

ClassRowsWhat it covers
_V0 lane vector-ALU228BarnaCore vector lane 0 ops
_V1 lane vector-ALU228BarnaCore vector lane 1 ops
_V2 lane vector-ALU227BarnaCore vector lane 2 ops
_VM mask lane6BarnaCore mask-lane ops
bc* native11bcHALT / bcLOOP_START / bcNOP / bcVLD* / bcVST* / bcVSHIFT
other4misc

已填充行的 base bit 主要是 1-bit,并带有结构化零空洞。置位 bit 编码固定 opcode discriminator 以及默认字段值;空洞正是该 class 的 operand encoder 写入的 (pos, width) window。同一个 class 中每个 opcode 共享同一种空洞 layout — 每个 opcode 的差异只在 base 中的 discriminator 值。重新实现者可以通过读取 base 的零区间,或通过读取 case body 的 insertBits 参数,来恢复 class 的 field map;二者逐 bit 一致。21 个 BarnaCore class 与 dispatch 中的 21 个 non-default case body 一一对应(MC-Emitter §Per-Opcode Dispatch)。


字段映射:Slot 到绝对 Bit 位置

字段在 239-bit record 中的绝对位置按 instruction class 固定,而不是按 opcode 固定。下面的位置从已填充 case body 中的 insertBits(value, pos, width) deposit 恢复(已对反编译的 getBinaryCodeForInstr body 验证:deposit-position histogram 精确包含这些常量 — 0x23/60x58/50x8D/20xCF/0x100xDF/0x10、predicate 0/4 + 5/2 等)。这些就是逐 slot LLO 报告中委托给“InstBits table”的绝对位置 — 但只适用于 BarnaCore 路径。TensorCore / V5+ 位置在这里(见全零发现)。

predicate 字段(每个已填充 slot)

复用最多的字段是逐 slot predicate,由 encodePredicateOperand0x13c77c40)写入。它的三个 deposit 形成一个 7-bit 字段:

text
 bits [0:3]  predicate register index   insertBits(reg_enc, pos=0, width=4)   reg# via TPURegEncodingTable
 bit  [4]    negate / inversion          word0 |= 0x10  (if operand flag bit 0 set)
 bits [5:6]  predication mode            insertBits((flags>>5)&3, pos=5, width=2)
```text

register index 是 4 bit,因为 `TPURegEncodingTable` 的 predicate block 持有值 `1..15`(`P0..P14`)。同一字段会在 multi-slot class 的每个 sub-slot 中重复(例如 load slot 会在每个 VLD sub-slot window 起始处复制它)。反编译的 `encodePredicateOperand` 原样显示 deposit:`insertBits(dst, *(u16*)(table + 2*reg_index), 0, 4)`,然后在 negate flag 上执行 `dst |= 0x10`,再执行 `insertBits(dst, (flags>>5)&3, 5, 2)`。

### `bcVLDi` / `bcVLDr` — BarnaCore vector-load slot

load class case body(`0x13c767c0`)在两个 sub-slot 上执行约 26 个 `insertBits` deposit。第一个 sub-slot:

| Field | Position | Width | Encoder |
|---|---|---:|---|
| base-address register | bit 35 (`0x23`) | 6 | `getMachineOpValue` |
| predicate (mode + reg) | bits 126/128 | 2 + 5 | `encodePredicateOperand` |
| addressing-mode sub-opcode | bit 133 (`0x85`) | 3 | `getMachineOpValue` |
| destination Vreg | bit 136 (`0x88`) | 5 | `getMachineOpValue` |
| load qualifier | bit 141 (`0x8D`) | 2 | constant |
| immediate displacement | bit 207 (`0xCF`) | 16 | `getMachineOpValue` |

第二个 VLD sub-slot 重复相同字段形状并整体上移(`+21`),它的 immediate displacement 落在 bit 223(`0xDF`,width 16)— 这是数据库中最高的字段,也是 record 大小为 239 bit 的原因。因此 BarnaCore vector load 是 `{predicate(7b), base-reg(6b), addr-mode(3b), dst-Vreg(5b), qualifier(2b), imm16}` 的双份。

### `bcVST*` — BarnaCore vector-store slot

store class 通过一个 64-bit window 加若干离散 register 字段来打包 source register 和 addressing。下面的 deposit 从 `getBinaryCodeForInstr` 的 store case body 中读取(四个 `insertBits(value, 0xAF, 0x40)` cluster site):一次 `insertBits(value, 0xAF, 0x40)` 会把 64-bit packed address/source word 写到 bit 175,然后在其周围 deposit 多个 5-bit register 字段和 2-bit qualifier 字段。精确的 opcode-to-class binding 对 store arm 是 UNVERIFIED(反编译的 `switch` 不携带 inline address);字段位置本身是 byte-anchored:

| Field | Position | Width | Encoder |
|---|---|---:|---|
| predicate (mode + reg) | bits 60/62 (`0x3C`/`0x3E`) | 2 + 5 | `encodePredicateOperand` |
| source / address register | bit 88 (`0x58`) | 5 | `getMachineOpValue` |
| index register | bit 73 (`0x49`) | 5 | `getMachineOpValue` |
| packed address/source word | bit 175 (`0xAF`) | 64 | `getMachineOpValue`(extract `64@0x20`) |
| register field | bit 83 (`0x53`) | 5 | from packed word |
| register field | bit 78 (`0x4E`) | 5 | from packed word |
| qualifier | bit 39 (`0x27`) | 2 | from packed word |
| qualifier | bit 37 (`0x25`) | 2 | from packed word |
| base-address bits | bit 35 (`0x23`) | 2 | from packed word |

本节早期草稿曾列出 bit 126(`0x7E`)处的单个 21-bit “source + addressing pack”;这是错误的 — emitter body 中任何地方都不存在 width 21(`0x15`)的 `insertBits`(`0x15` 只作为 *extract* offset 出现)。最宽的 store deposit 是 `0xAF` 处的 64-bit window。`0x7E`/width-2 deposit 是 VLD-class predicate-mode 字段,不是 store window。

### `bcLOOP_START` — BarnaCore loop slot

loop class(`0x13c770f8`)是 base-only:它的行持有 discriminator,并把 trip/length 字段留作空洞。恢复出的空洞 map(opcode 3978):

| Field | Position | Width | Meaning |
|---|---|---:|---|
| loop mode / type | bit 0 | 2 | loop kind |
| opcode discriminator | bit 2 | 1 | fixed (=1) |
| loop length / body offset | bit 3 | 9 | hardware-loop trip / length |
| bundle-common byte | bit 24 (`0x18`) | 8 | shared by all bc ops |
| bundle-common field | bit 58 (`0x3A`) | 2 | shared by all bc ops |

bit 3 处的 9-bit length 是 BarnaCore hardware-loop trip count。bits 24 和 58 处的 bundle-common 字段由每个已填充的 BarnaCore opcode 共享(bits `24:31` 处的 `00` byte 是在其他位置以 1-bit 为主的 base 中的零空洞,例如低位 pattern `f3ffffff00fff004`)。

> **GOTCHA — sequencer branch/call/halt opcode 会索引此数据库,但编码为零。** `BRabs`(505)、`BRind`(507)、`BRrel`(508)、`BRrelrot`(509)、`CALLabs`(514)、`CALLrel`(515)和 `HALT`(571)是真实 MC opcode,在 `InstBits` 中有行 — 但这些行全零(default table),并路由到 zero-base default case。它们的 offset、destination register 和 predication 由 proto-bundle 的 `EmitBranchOp` / `EmitCallOp` / `EmitImmediate` / `EmitPredicationToSlot` 路径写入,从不通过 InstBits。试图读取 `BRrel` 的 InstBits 行来寻找 branch-offset 字段的重新实现者只会看到零;该字段在 bundle emitter 中。MC `BR`/`BRcond`/`BRcondrot`/`BRret` pseudo(opcodes 325/328/330/331)位于 499 以下,会在 MC emission 前展开 — 它们根本不会到达数据库。

---

## 这个数据库不包含什么

InstBits 数据库是 TPU 编码栈中的 LLVM-MC 切片,并且它的边界很明确。它**不**包含:

- **TensorCore / V5+ 绝对 bit 位置。** 由全零、no-RELA 默认表证明。这些位置由 proto-bundle `isa_emitter` `EmitX` 模板和逐代 `TensorCoreCodecBase` 的 `BitCopy(dest, bit_offset, src, 0, width)` 调用产生。该数据库证明了它们**不在哪里**,从而关闭了逐 slot 报告留下的问题。
- **完整的 BarnaCore vector-ALU `_V0/_V1/_V2` field map。** VLD / VST / LOOP / predicate class 已在上文逐 bit 精确解码;两个大型 vector-ALU class(`0x13c74eb9`、`0x13c74f47`)以及 17 个较小 vector class(`0x13c75723 … 0x13c75d77`)只做了抽样,没有穷尽(其 X/Y operand、immediate 和 sublane-mask window)。(*对未穷尽 vector class 的置信度为 MEDIUM。*)
- **`TPURegEncodingTable` 背后的 register-class 划分。** predicate block(`1..15`)以及递降 scalar/vector block 可见;完整 reg# →(class, encoding)绑定需要对 `TPURegClassInfos`(`0x334ea60`)+ `TPURegDesc`(`0x343e7b0`)做交叉解码。参见 [Instr Name Data §Register Encoding](instr-name-data.md#register-encoding-tpuregencodingtable)。

---

## 交叉引用

- [Instr Name Data](instr-name-data.md) — `TPUInstrNameData` / `TPUDescs` / `TPURegEncodingTable`,即 InstBits operand encoder 读取的 descriptor、mnemonic 和 register-encoding 表。
- [Record Format](record-format.md) — InstBits 行被载入的 239-bit `APInt`,以及 base-bits / `insertBits`-holes 模型。
- [MXU Slot](slot-mxu.md) — 一个字段**不**在 InstBits 中(zero base),而是由 proto-bundle 路径发出的 TensorCore slot。
- [kIsaTable Data](kisatable-data-sections.md) — 逐世代 ISA-encoding 划分;InstBits 是该划分中的 LLVM-MC 成员,与逐代 codec metadata 和 NOP template 互补。