LloOpcode 枚举
本页中的每个偏移、值和地址都逐字节精确读取自
libtpu-0.0.40-cp314wheel 中的libtpu.so(BuildID md589edbbe81c5b328a958fe628a9f2207d)。其他版本会不同。
摘要
xla::jellyfish::LloOpcode 是 LLO(Low-Level Optimizer IR)的内存中 opcode 枚举;LLO 是 TPU 专用的后期编译器 IR,位于 MHLO/TLP 之下、逐代 TensorCore bundle 编码器之上。它是一个密集、从零开始的枚举:二进制精确写出了 461 个 enumerator,值为 0x000..0x1CC(0..460),没有空洞。每个值在一个 relocated char* 表中都有一个带 k 前缀的名称;这些名称能清晰地归入若干功能族 — sequencer/sync、scalar SPU arithmetic、vector VPU arithmetic、EUP transcendentals、cross-lane/reduction/XLU、MXU matmul/latch/transpose/result 组、load/store、40-opcode DMA block、predicate/mask、pseudo nodes,以及 33-opcode BarnaCore(SparseCore)block。
LloOpcode 不同于三个 sibling index space,重实现者不能混淆。它不是 LloOpcodeProto wire enum(1-based,最大值 499,38 个 reserved gaps — 见 LloOpcode↔Proto)。它不是 GhPerf::Instruction cost-grid enum(更密集的 0..0x1DB 空间,其中 19 行由多个 opcode 共享)。它也不是 MC-Emitter dispatch 的 MC MCInst opcode space(偏移 +499,以 opcode <= 0x1F2 gating,并索引 4*opc-1996)。LloOpcode 是其他所有空间映射来源的那个空间。
本页是结构化参考目录,不是算法追踪。它按 family 对 461 个值分组,给出每个 family 的值范围和代表成员,命名二进制使用的 per-family classifier,并标出逐代新增项(F8 conversions、stochastic rounding、S4/U4 matmul、dual matrix staging)。完整 461 行 dump 位于 appendix;这里的目标是说明该空间的形状。
| Enum | xla::jellyfish::LloOpcode — 461 enumerators,dense,0x000..0x1CC |
| Name accessor | LloOpcodeName(LloOpcode) @ 0x1d631280 — bound >= 0x1CD → ud1 |
| Name table | opcode_name @ 0x21ccfef0 (.data.rel.ro, 461 × char*, R_X86_64_RELATIVE) |
| Property word | opcode_info @ 0x223a1320 (461 × uint16) — Push/Pop/Remat/Fold/Cse + reg-file class |
| Descriptor | opcode_info_big @ 0x227b5570 (461 × 28 B) — result-FIFO + arch-register lists |
| Family classifiers | LloOpcodeIsVector @ 0x1d60c1c0, LloOpcodeIsScalar @ 0x1d60c7e0 (= !IsVector), LloOpcodeIsVectorUnop/Binop/Load/Store, … |
| 置信度 | CONFIRMED(byte-anchored),除非某行另有说明 |
枚举如何存储和命名
LloOpcode 是普通的 C++ scoped enum;二进制中没有把它作为 class 存储。唯一的 reflection 片段是 LloOpcodeName,它把值转换为字符串:
// xla::jellyfish::LloOpcodeName @ 0x1d631280 (decompiled, exact)
std::string LloOpcodeName(uint32_t opcode) {
if (opcode >= 0x1CD) // bound = 461 enumerators
__builtin_trap(); // ud1 — out of enum range
const char *s = opcode_name[(uint16_t)opcode]; // opcode_name @ 0x21ccfef0
return std::string(s, strlen(s)); // SSO or heap copy
}
```text
bound `0x1CD` 就是契约:有效域为包含端点的 `0x000`..`0x1CC`,共 461 个值。`opcode_name` 是 `.data.rel.ro` 中的 `char*` 表;每个 slot 在文件中存为 `0`,并由一个指向 `.rodata` 的 `R_X86_64_RELATIVE` relocation 填充。全部 461 个 slot 都有 relocation,全部 461 个字符串都非空。这个同样的 461-bound 逐字出现在两个 per-opcode metadata 表的每个 consumer 中(`cmp opcode, 0x1CE; jae <fatal>` — `< 0x1CE` 形式),且 metadata 表(`opcode_info`、`opcode_info_big`)各自大小都是 `461 × stride`。
> **QUIRK — 该 enum 有 461 个成员,不是 462 个。** [ISA overview](overview.md) 引用的 “462” 数字是 `LloOpcodeProto` *wire* enum 的*名义*成员数:1-based,带 value-0 sentinel,因此 461 个 live(可映射)wire values + 1 个 sentinel = 462 nominal。它的可寻址范围还更宽(最大 499,有 38 个 reserved gaps;`499 − 38 = 461` live — 见 [LloOpcode↔Proto](llo-opcode-to-proto.md))。重实现者的编译器操作的内存中 `LloOpcode` 精确为 461 个密集值(`LloOpcodeName` bound `0x1CD`,已在 `0x1d631280` 验证)。用 462 驱动 switch 会让最后一个 index 读过表尾;用 proto 的 499 会索引垃圾。
### 两个 metadata 表与 enum 并行
每个 opcode 都以 lock-step 方式索引到两个并行 per-opcode 表中,供 LLO scheduler 和 optimizer 读取:
| Table | Address | Stride | Carries |
|---|---|---|---|
| `opcode_info` | `0x223a1320` | 2 B (`uint16`) | LOW byte = property bitfield(bit0 Push / bit1 Pop / bit4 Remat / bit5 Fold-const / bit6 Cse / bit7 pred-mask tag);HIGH byte = register-file class(0 none/pred,1 scalar/mask,2 vector) |
| `opcode_info_big` | `0x227b5570` | 28 B | `int8 result_fifos[8]` @+0x00(负值终止,ResultFifo 0..0x18),`int8 arch_registers_read[12]` @+0x08(负值终止,ArchRegister 1..0x32),`int8 arch_registers_written[8]` @+0x14(负值终止,ArchRegister 1..0x32) |
两者都用原始 `LloOpcode` 值索引,并使用同一个 `< 0x1CE` bound。它们记录在自己的页面中;本页只引用它们来锚定每个 family 的 scheduler 行为(哪些 opcode push/pop result FIFO,哪些可 CSE,哪些写 register)。
---
## Family 分类
二进制没有为每个 opcode 存储 family tag;family membership 由以下内容恢复:(a) 每个名称的 `k` 前缀,(b) 密集 classifier switches(`LloOpcodeIsVector`、`LloOpcodeIsVectorUnop`、`LloOpcodeIsVectorLoad` 等),以及 (c) `opcode_info` register-file-class byte。下表是十一个 family 的速览图;后续 per-family 小节给出范围和代表项。
| Family | Value range (mostly contiguous) | Count | Reg-file (typical) | Primary classifier |
|---|---|---:|---|---|
| Sequencer / sync / FIFO transfer | `0x000`..`0x030`(交错) | ~50 | scalar/none | — |
| Scalar SPU arithmetic & control | scattered,dense tail `0x16B`..`0x1AA` | 63 | scalar | `!LloOpcodeIsVector` |
| Vector VPU arithmetic & logic | dense `0x11B`..`0x1A2` core | (295 的子集) | vector | `LloOpcodeIsVectorUnop/Binop` |
| Vector convert / pack / unpack | `0x05B`..`0x076`, `0x107`..`0x10F`, `0x126`..`0x127` | ~45 | vector | (convert-prefix) |
| EUP transcendentals | `0x128`..`0x14D` | 38 | vector (EUP FIFO) | (Tanh/Pow2/Recip/Log2/Rsqrt/Sig/Sin/Cos/Erf × F32/Bf16 × {,AndPop}) |
| Cross-lane / reduce / XLU result | `0x0F5`..`0x101`, `0x14E`..`0x155` | ~28 | vector | (Reduce/Result prefix) |
| MXU matmul / latch / matprep / matres | `0x08D`..`0x0AB`, `0x152`..`0x153` | ~33 | vector | `LloOpcodeIsVectorMatprep*`, matmul band `0x8D`..`0xA5` |
| Load / store / IAR / RNG | `0x001`..`0x004`, `0x030`..`0x046`, `0x077`..`0x078` | ~30 | mixed | `LloOpcodeIsVectorLoad` @ `0x14024900`, `…IsVectorStore` @ `0x14024920` |
| DMA | `0x0B3`..`0x0DA`(连续) | 40 | none | (Dma prefix) |
| Predicate / mask | `0x0E1`..`0x0F1`, `0x193`..`0x199` | ~18 | predicate/mask | (Predicate/Mask prefix) |
| Constants / pseudo / call | `0x0DB`..`0x0F4`, `0x02C`..`0x02E`, `0x17C` | ~25 | mixed | (Constant/Phi/Pseudo/Call prefix) |
| BarnaCore (SparseCore) | `0x1AC`..`0x1CC`(连续) | 33 | mixed | (BarnaCore prefix) |
> **NOTE — vector-vs-scalar 是 per-opcode 分区,不是范围切分。** `LloOpcodeIsScalar` 字面上是 `LloOpcodeIsVector(op) ^ 1`(@ `0x1d60c7e0`),而 `LloOpcodeIsVector`(@ `0x1d60c1c0`)是一个密集 `switch`,对 vector opcodes 返回 `1`,对其余返回 `0` — 但这两个集合在值空间中交错。例如 `kEvent` (0)、`kLog` (5)、`kHloStart`/`kHloEnd` (6/7) 是非 vector;`kVectorReadIar` (1) 是 vector;BarnaCore vector load/store ops(457..460)是 vector,而 BarnaCore scalar ops(428..456)不是。重实现者必须移植该 switch,而不是用 `>= threshold` 测试。
---
## Sequencer、Sync 和 FIFO-Transfer Family(`0x000`..`0x030`)
低位 opcode 是 control-and-handshake 层:program boundaries、scheduling barriers、fences,以及在 SPU、VPU 和 cross-FIFO(CCF)staging registers 之间移动值的 scalar/vector/sync-flag result-FIFO push/pop primitives。
| Value | Name | Role |
|---|---|---|
| `0x000` | `kEvent` | program/trace event marker |
| `0x006` / `0x007` | `kHloStart` / `kHloEnd` | source-HLO span markers(debug-info) |
| `0x008` | `kSchedulingBarrier` | hard reorder barrier(vetoes CSE across it) |
| `0x009` | `kScalarToVector` | scalar→vector broadcast push |
| `0x00A`..`0x012` | `kVectorToScalarPush` … `kDrfPop` | V→S / sync-flag→scalar FIFO push/pop quartet |
| `0x013`..`0x014` | `kScalarFence` / `kVectorStoreFence` | ordering fences |
| `0x015`..`0x01C` | `kScalarCcfPush` … `kVectorCcfPopAsymmetrical` | cross-core FIFO (CCF) push/pop,symmetric + asymmetric |
| `0x01D` | `kMegacoreSwapCoresPseudo` | megacore core-swap pseudo |
| `0x01E` | `kCmemFence` | CMEM ordering fence(Pufferfish+) |
| `0x01F`..`0x024` | `kScalarReadCycleStart` … `kScalarReadCycleLow` | cycle-counter reads / 64-bit splits |
| `0x025`..`0x027` | `kScalarHalt` / `…YieldConditional` / `…OnError` | sequencer halt variants |
| `0x029` | `kProgramLaunchSc` | SparseCore program launch |
| `0x02B` | `kVectorInterrupt` | vector-side interrupt |
静态 `opcode_info` low-byte push/pop bits 并不像直觉那样与 `*Push`/`*Pop` opcode 名称对齐,因此 FIFO 行为必须取自 helper functions,而不是按名称读表。从 on-disk `opcode_info`(base `0x223a1320`,uint16 stride)解码可见:`kVectorToScalarPush` (0x0A)、`kSyncFlagToScalarPush` (0x0B) 和 `kSyncFlagToSfrfPush` (0x0F) 都读为 `0x0000`(无 bit0);而 `kSfrfPop` (0x11) 读为 `0x0073`,`kDrfPop` (0x12) 读为 `0x0002`(两者 bit1 set)。`LloInstructionPushesToResultFifo`(`opcode_info[op] & 1`)和 `LloInstructionPopsFromResultFifo`(matres special-case + bit-field extract)才是权威 push/pop 测试。`kScalarHalt`/`kScalarHaltOnError` 共享 `GhPerf` cost row 0x000。
---
## Scalar SPU Family
Scalar opcode 是 vector 集合的补集。它们聚集在两处:`0x085`..`0x089` band 中的少数 address/compose/branch/select 成员,以及 `0x16B`..`0x1AA` 的密集 arithmetic-and-shift tail。这些 opcode 的 register-file-class byte 为 `1`(scalar/mask)。
| Value | Name | Role |
|---|---|---|
| `0x085` | `kScalarComposeU64` | 将两个 `u32` pack 成一个 `u64` |
| `0x086` | `kScalarAddressCalculation` | address arithmetic(与 `kScalarAddS32` 共享 `GhPerf` 0x00C) |
| `0x087`/`0x088` | `kScalarBranchRel` / `kScalarBranchInd` | relative / indirect branch |
| `0x089` | `kScalarSelect` | scalar conditional select |
| `0x16B`..`0x16C` | `kScalarCompare` / `kScalarAddCarryU32` | compare + add-with-carry |
| `0x16D`..`0x172` | `kScalarMultiplyWordAddr` … `kScalarAddS32` | multiplies + adds(`u24`/`u32`/`f32`/`s32`) |
| `0x173`..`0x177` | `kScalarSubtractS32` … `kScalarBitwiseXor` | sub + bitwise and/or/xor |
| `0x178`..`0x17A` | `kScalarDivRemU32` / `kScalarDivU32AndPop` / `kScalarRemU32AndPop` | divide/remainder(在 FIFO analyses 中 data-format-special-cased) |
| `0x17B` | `kScalarMove` | scalar copy — **Move-exclusion** opcode(绝不 CSE/remat) |
| `0x17D`..`0x17F` | `kScalarFloorF32` / `kScalarCeilF32` / `kScalarCountLeadingZeros` | scalar rounding + CLZ |
| `0x1A3`..`0x1A6` | `kScalarShrl` … `kScalarShllOnes` | logical/arith shifts |
| `0x1A7`..`0x1AA` | `kScalarMinimumF32` … `kScalarMaximumU32` | min/max(`f32`/`u32`) |
---
## Vector VPU Arithmetic & Logic Family
Vector ALU 是最大的 family。其 arithmetic core 是连续的 `0x11B`..`0x1A2` block;clamp/accumulate helper 更早位于 `0x048`..`0x05A`。`LloOpcodeIsVectorUnop`(@ `0x1d60c200`)和 `LloOpcodeIsVectorBinop`(@ `0x1d60c680`)划分 unary 与 binary forms。register-file byte 为 `2`(vector);foldable/CSE-able bits(`opcode_info` bit5/bit6)在 pure-functional 成员上设置。
| Value | Name | Role |
|---|---|---|
| `0x048`..`0x050` | `kVectorClampGezF32` … `kVectorRemapBf16` | clamp / remap(gez、symmetric、asymmetric;F32/Bf16/S4) |
| `0x051`..`0x05A` | `kVectorMultiplyAccumulate` … `kVectorMoveEvenAccLow` | MAC + accumulator moves(MAC family 设置 FOLD bit) |
| `0x11B`..`0x124` | `kVectorAddS32` … `kVectorSubtractS16` | add/subtract(`s32`/`f32`/`bf16`/`s16`,以及 Bf16-high/low) |
| `0x156`..`0x15B` | `kVectorPowF32` … `kVectorMultiplyBf16` | pow + multiply(F32/U32/U16/Bf16) |
| `0x15C`..`0x15F` | `kVectorAndU32` … `kVectorXorU32` | bitwise and / and-negated / or / xor |
| `0x162`..`0x166` | `kVectorMultiplyComposeU64` … `kVectorExtractHigh32` | 64-bit multiply compose + word extracts |
| `0x180`..`0x184` | `kVectorCountLeadingZeros` … `kVectorExtractSignificand` | CLZ / move / popcount / FP field extracts |
| `0x19A`..`0x19C` | `kVectorShiftRightLogical` … `kVectorShiftLeftLogical` | vector shifts |
| `0x19D`..`0x1A2` | `kVectorMaximumF32` … `kVectorMinimumU32` | min/max(F32/Bf16/U32) |
`kVectorMove` (0x181) 携带 CSE/remat bits,但和 `kScalarMove` 一样是无条件 **Move-exclusion** opcode — LLO CSE/remat passes 永远不会对它触发。
---
## Convert / Pack / Unpack Family
类型转换分布在三个 band:`0x05B`..`0x076` 的 `f32→{s32,f8,hf16}` 和 `{s8,s4,u8,u4}↔bf16` block、`0x107`..`0x11A` 的 unpack/round/truncate block,以及 `0x125`..`0x127` 的 pack/compose。这些是跨 generation 增长最多的 opcodes。
| Value | Name | Role |
|---|---|---|
| `0x05B`..`0x060` | `kScalarConvertF32ToS32WithProbRounding` … `kVectorConvertF32ToS32TowardsZeroPseudo` | F32→S32(prob-round / towards-zero) |
| `0x061`..`0x064` | `kVectorConvertF32ToF8E5M2` / `…E4M3Fn` / `…E4M3B11` / `…ToHf16` | F32→F8 / Hf16(**F8 added Pufferfish+**) |
| `0x066`..`0x06D` | `kVectorConvertS8ToBf16` … `kVectorConvertBf16ToU4` | int↔Bf16(`s8`/`s4`/`u8`/`u4`;**S4/U4 Pufferfish+**) |
| `0x06E`..`0x06F` | `kVectorConvertEXMYToE4M3` / `…ToE5M2` | generic FP8 reformat |
| `0x070`..`0x074` | `kVectorConvertF32ToE5M2Stochastic` … `kVectorConvertF32ToHf16Stochastic` | **stochastic-rounding converts(Viperfish+)** |
| `0x109`..`0x10F` | `kVectorUnpack` … `kVectorDynamicUnpack` | unpack + B2→B4 / B4→B8 join + EXMY/dynamic |
| `0x110`..`0x11A` | `kVectorCeilF32` … `kVectorTruncateBf16` | round-to-int / RTNA / RTNE / truncate |
| `0x125`..`0x127` | `kVectorComposeF32` / `kVectorPack` / `kVectorPackEXMY` | compose + pack |
---
## EUP Transcendental Family(`0x128`..`0x14D`)
Extended Unit Pipeline 以 deferred-result pipeline 计算 transcendentals:九个函数(Tanh、Pow2、Reciprocal、Log2、Rsqrt、SigShft、Sinq、Cosq、Erf,加上 standalone `PushErf`)各自有四种形式 — `F32`、`Bf16`、`F32AndPop`、`Bf16AndPop`。`*AndPop` variants 在一个 opcode 中同时 issue transcendental 并从 EUP FIFO pop 结果;裸形式只 issue(bit0 Push set),结果稍后由 `kVectorEupResult` (0x14E) 收集。
| Value band | Members | Form |
|---|---|---|
| `0x128`..`0x131` | Tanh/Pow2/Reciprocal/Log2/Rsqrt/SigShft/Sinq/Cosq/Erf + `kVectorPushErf` | F32,issue-only |
| `0x132`..`0x13A` | same set | Bf16,issue-only |
| `0x13B`..`0x144` | same set + `kVectorPushErfAndPop` | F32,issue+pop |
| `0x145`..`0x14D` | same set | Bf16,issue+pop |
> **NOTE — EUP FIFO push/pop 不是从静态 `opcode_info` bit 读取的。** `LloInstructionPushesToResultFifo`(@ `0x1d4f3600`)测试 `opcode_info[op] & 1`,而 `LloInstructionPopsFromResultFifo`(@ `0x1d4f3720`)special-case matres band(`0x152`/`0x153`),否则从 property word 抽取一个 sign-bit field(`shl 0xC; cwde; sar 0xD`)— 它并不测试固定 `Pop` bit。`kVectorEupResult` (0x14E) 的静态 `opcode_info` slot 在磁盘上读为 `0x0000`(file offset `0x223a15bc`),因此重实现者必须由 push/pop *helpers*(及其 matres/EUP special-cases)驱动 EUP FIFO,而不是使用字面 property-word 常量。`*AndPop` opcodes 将 issue+pop fuse 成一条 instruction。
---
## Cross-Lane、Reduction 和 XLU-Result Family
Reductions(`0x0F5`..`0x101`)跨 lane 或 segment 计算 F32 和 Bf16 的 min/max/add/argmin/argmax;result-collection opcodes(`0x14E`..`0x155`)pop 各种 deferred-result FIFO(EUP、cross-lane、permute、CMEM、transpose)。cross-lane permute/rotate/broadcast primitives 更早位于 `0x036`..`0x03B`。
| Value | Name | Role |
|---|---|---|
| `0x0F5`..`0x0FC` | `kVectorMinReduceF32` … `kVectorAddSegmentReduceF32` | F32 reductions(whole + segmented + index) |
| `0x0FD`..`0x101` | `kVectorMinReduceBf16` … `kVectorMinIndexReduceBf16` | Bf16 reductions |
| `0x102`..`0x106` | `kVectorSublaneId` … `kVectorLaneSequenceInterleavedB16` | lane/sublane identity sequences(remat-able constants) |
| `0x14E` | `kVectorEupResult` | pop EUP result FIFO(Pop bit) |
| `0x14F`..`0x151` | `kVectorXlaneResult` / `kVectorPermuteResult` / `kVectorCmemResult` | pop XLU / permute / CMEM result FIFOs |
| `0x152`..`0x153` | `kVectorMatres` / `kVectorMatresAdd` | pop MXU result(plain / accumulate) |
| `0x154`..`0x155` | `kVectorTransposeResult` / `kVectorTransposeClear` | pop transpose result / clear transpose FIFO |
`kVectorXlaneResult`/`kVectorPermuteResult`/`kVectorTransposeResult` 共享 `GhPerf` cost row 0x1C7。`kVectorTransposeClear` (0x155) 的 `opcode_info` word 是 `0x0911`(file offset `0x223a15ca` 处字节 `11 09`)。
---
## MXU Family — Matmul、Latch、Matprep、Result
matrix unit pipeline 会 stage stationary operand(latch)、准备 moving operand(matprep)、issue matmul,并收集 result(matres)。latch/matmul opcodes(`0x08D`..`0x0A5`)是 FIFO 和 cost analyses special-case 的 data-format-dependent band:它们的 result-FIFO 行为和 `GhPerf` cost row 从运行时 `matmul_data_format` / `latch_mode` 计算,而不是从静态表读取。
| Value | Name | Role |
|---|---|---|
| `0x08D`..`0x096` | `kVectorLatchLsf` … `kVectorLatch3Msk` | stationary-operand latch(Lsf / 0..3,masked variants) |
| `0x097`..`0x09A` | `kVectorMatprepSubr` … `kVectorMatprepMubrMsk` | moving-operand prep(single/multi broadcast,masked) |
| `0x09B`..`0x0A5` | `kVectorMatmul` … `kVectorMatmulLmr` | matmul(Mubr / High / Low / Msk / Packed / Lmr) |
| `0x0A6`..`0x0A7` | `kVectorTranspose` / `kVectorTransposeBinary` | XLU transpose(vxpose-mode dispatched) |
| `0x0A8`..`0x0AB` | `kVectorDoneWithGains` … `kVectorLoadLmrWithBf16Conversion` | gain handshake + GMR/LMR loads |
| `0x152`..`0x153` | `kVectorMatres` / `kVectorMatresAdd` | matmul result collection(也属于 result family) |
> **GOTCHA — matmul band 在读取 property-word 表*之前*被 special-cased。** `LloInstructionPushesToResultFifo` 通过 bitmask 测试 matmul band(`0x8D`..`0xA5`),并路由到 `matmul_data_format` vtable 调用;只有 band 外的 opcodes 才 fall through 到 `opcode_info[op] & 1`。重实现者如果读取 matmul opcode 的静态 Push bit,会得到错误的 FIFO 行为 — matmul 的 push 取决于其 data format,由 instruction instance 决定,而不是由 opcode 决定。
---
## Load / Store / IAR / RNG Family
内存访问和 per-lane index-address-register(IAR)设置。`LloOpcodeIsVectorLoad`(@ `0x14024900`)和 `LloOpcodeIsVectorStore`(@ `0x14024920`)分类 vector forms;RNG opcodes(`0x03C`..`0x03E`)seed 和读取 stochastic conversions 使用的 per-lane PRNG。
| Value | Name | Role |
|---|---|---|
| `0x001`..`0x004` | `kVectorReadIar` … `kVectorSetIarSublane` | read / set index-address register |
| `0x030`..`0x035` | `kVectorLoadSublaneShuffle` … `kVectorCmemLoadAndPop` | vector + CMEM loads |
| `0x036`..`0x03B` | `kVectorPermute` … `kVectorBroadcastLane` | cross-lane permute / rotate / combine / broadcast |
| `0x03C`..`0x03E` | `kVectorPrng` / `kVectorSetRngSeed` / `kVectorGetRngSeed` | per-lane PRNG |
| `0x03F`..`0x046` | `kVectorStore` … `kVectorStoreEvenOddSublanes` | vector + CMEM stores(indexed、masked、shuffle) |
| `0x077`..`0x078` | `kScalarLoad` / `kScalarStore` | scalar memory access |
| `0x047` | `kVectorNop` | vector no-op(与 `kVectorMaskMove` 共享 `GhPerf` 0x1B4) |
---
## DMA Family(`0x0B3`..`0x0DA`)
40 个连续 DMA opcodes 是最大的单个连续 block。它们枚举 direction(HBM/VMEM/SMEM/CMEM/HIB/IMEM/Host,以及 IOVA-addressed host),并与 source/destination-register variants(`Vsrc`/`Vdst`/`VsrcVdst`)和 `WithHibUpdate` family 交叉。两个 terminator `kDmaDone`/`kDmaDoneWait` 结束一个 DMA。
| Value | Name | Role |
|---|---|---|
| `0x0B3`..`0x0B4` | `kDmaGeneral` / `kDma` | generic DMA forms |
| `0x0B5`..`0x0CC` | `kDmaHbmToVmem` … `kDmaSmemToVmem` | direction matrix(HBM/VMEM/SMEM/CMEM/HIB/IMEM) |
| `0x0CD`..`0x0D0` | `kDmaHbmToVmemWithHibUpdate` … `…VdstWithHibUpdate` | HBM→VMEM with HIB update |
| `0x0D1`..`0x0D8` | `kDmaHbmToHost` … `kDmaSmemToHostIova` | host DMA(direct + IOVA) |
| `0x0D9`..`0x0DA` | `kDmaDone` / `kDmaDoneWait` | DMA completion / wait |
> **NOTE — cost model 按 direction-class 而不是 per-opcode 为 DMA 定价。** 14 个 HBM/Host-DMA opcodes 全部折叠到 `GhPerf` cost row 0x40,14 个 VMEM/SMEM-DMA opcodes 折叠到 row 0x43。40 个不同的 `LloOpcode` 值是真实且必须存在的,但 latency model 把每个 direction family 作为一个处理。没有 DMA opcode 设置 result-FIFO Push/Pop bit(`opcode_info` LOW byte `0x00`);它们通过 memory 产生 side effect,而不是通过 FIFO。
---
## Predicate / Mask Family
Predicate(single-bit,P-register)和 vector-mask(lane-mask,VM-register)ops。register-file class 为 `0`/`1`(none/predicate 或 scalar/mask)。CSE-able + predicate-tag bits(`opcode_info` `0xC0`/`0xD0`/`0xE0`)标记这个 family。
| Value | Name | Role |
|---|---|---|
| `0x0E1` | `kPredicateConstant` | remat-able predicate constant(`opcode_info` `0x222C`,file offset `0x223a14e2`) |
| `0x0E5`..`0x0E8` | `kPredicateNegate` … `kPredicateOr` | predicate logic(共享 `GhPerf` row 0x032) |
| `0x0E6` | `kPredicateMove` | predicate copy — **Move-exclusion** opcode |
| `0x0E2`..`0x0E3` | `kVectorMaskConstant` / `…Packed` | mask constants |
| `0x167`..`0x16A` | `kVectorCompare` … `kVectorAddCarryU16` | mask-producing compares + add-carry |
| `0x193`..`0x199` | `kVectorMaskXor` … `kVectorMaskMove` | mask logic / pack-compressed / negate / move |
| `0x199` | `kVectorMaskMove` | mask copy — **Move-exclusion** opcode |
四个 Move-exclusion opcodes — `kScalarMove` (0x17B)、`kVectorMove` (0x181)、`kVectorMaskMove` (0x199)、`kPredicateMove` (0xE6) — 构成 bitmask `0x40000041`(base 0x17B 上)∪ `{0xE6}`,LLO CSE/remat/fold passes 用它跳过 moves。gate 细节见 [opcode property word](instbits-master-db.md)。
---
## Constants、Pseudo 和 Call Family
Constants(`0x0DB`..`0x0E4`)、Phi/pseudo SSA nodes(`0x0E9`..`0x0F4`),以及 call/tuple 组。Constants 设置 remat bit(`opcode_info` `0x50`);Phi nodes(`0x0E9`..`0x0EC`)在 latency model 中 short-circuit 到 cost 0。
| Value | Name | Role |
|---|---|---|
| `0x02C`..`0x02E` | `kAllocationAddress` / `kParameterAddress` / `kIntToPtr` | address materialization(remat-able) |
| `0x0DB`..`0x0E0` | `kScalarConstantU32` … `kVectorConstantF32` | scalar/vector constants(U32/PackedBf16/F32) |
| `0x0E4` | `kVectorConstantU64` | 64-bit vector constant |
| `0x0E9`..`0x0EC` | `kPredicatePhi` / `kScalarPhi` / `kVectorPhi` / `kVectorMaskPhi` | SSA phi nodes(cost 0) |
| `0x0ED`..`0x0F0` | `kTuple` / `kInlinedCall` / `kCall` / `kInlinedCallOperand` | call / tuple structure |
| `0x0F1`..`0x0F4` | `kPredicatePseudo` … `kVectorMaskPseudo` | pseudo placeholders per register class |
| `0x17C` | `kRelocatableConstant` | link-time relocated constant |
---
## BarnaCore (SparseCore) Family(`0x1AC`..`0x1CC`)
最高的 33 个 opcode 是 BarnaCore(SparseCore)instruction set — 嵌入 scatter/gather、sparse reduce、remote scalar writes,以及 BarnaCore-local vector load/store/move。这些是 [MC-Emitter](mc-emitter.md) 实际用真实 `insertBits` sequences 编码的 opcodes(其填充的 `InstBits_BarnaCorePxcHwMode` 表覆盖该范围),与返回全零的 TensorCore opcodes 形成对比。
| Value | Name | Role |
|---|---|---|
| `0x1AC`..`0x1B3` | `kBarnaCoreScalarWaitDone` … `kBarnaCoreScalarWaitNe` | scalar wait/sync primitives |
| `0x1B4`..`0x1B7` | `kBarnaCoreScalarSyncDoneRead` … `…SyncPublicAccessWrite` | sync-flag read/write |
| `0x1B8`..`0x1BB` | `kBarnaCoreScalarPop` … `kBarnaCoreScalarFence` | pop / FSM issue / fence |
| `0x1BC`..`0x1C8` | `kBarnaCoreRemoteScalarWrite` … `kBarnaCorePfLocalScatterGradients` | remote write / scatter-gather / sparse-reduce(Pf = prefetch variants) |
| `0x1C9`..`0x1CC` | `kBarnaCoreVectorLoad` … `kBarnaCoreVectorStore` | BarnaCore vector load/store/move |
> **QUIRK — BarnaCore vector load/store opcodes(457..460)在 `LloOpcodeIsVector` 中测试为 *vector*,而 BarnaCore scalar/sync opcodes(428..456)测试为 non-vector。** 这是 BarnaCore block 唯一跨越 vector/scalar 分区的地方,并且会影响 register-class selection:`kBarnaCoreVectorLoad`/`…ImmediateOffset`/`…MoveScalarReg`/`…VectorStore` 获得 vector register file,即使它们的 family prefix 是 "BarnaCore" 而不是 "Vector"。
---
## 逐代新增项
`LloOpcode` 在其*编号*上是 gen-invariant 的 — 同一个 enum value 在每个 TPU generation 上表示同一个 opcode — 但*有效子集*随每代 silicon 增长。compaction encoders 的 vtable slot 数跟踪了这种增长(`vxc` Viperfish ≈ 403,`gxc::glc` Ghostlite ≈ 623,`gxc::gfc` ≈ 674 slots),反映 later gens 上更多合法的(opcode × data-format)组合。下面的 codename 是二进制自身的内部字符串(`Jellyfish`、`Pufferfish`、`Viperfish`、`Ghostlite` 都逐字出现在 `libtpu.so` 中);最新 generation 只以其 hashed family tag `6acc60406` 命名 — 营销名 "Trillium"/"Ironwood" 在此 build 中有**零**次字节出现。
| Generation | Codename | LloOpcode additions |
|---|---|---|
| TPU v2 | Jellyfish | base set(proto-direct encoding,无 Compact encoder) |
| TPU v4 | Pufferfish | F8 converts(`0x061`..`0x063`)、S4/U4 int↔Bf16(`0x067`/`0x069`/`0x06B`/`0x06D`)、`kCmemFence`(`0x01E`)、CMEM DMA/load opcodes |
| TPU v5p | Viperfish | stochastic-rounding converts(`0x070`..`0x074`) |
| TPU v6e | Ghostlite | `vector_misc` slot ops |
| TPU7x | `6acc60406` | dual matrix staging(MATPUSH target MSRA/MSRB);newest-gen-only opcodes `kVectorToScalarPush` (0x0A) / `kSyncFlagToScalarPush` (0x0B) 映射到最高 `GhPerf` rows(0x1DA),只在 476-row grid 上有效 |
> **NOTE — 该 enum 是 append-and-insert,而不是 append-only,这就是 proto 和内存中编号分歧的原因。** 新 opcode 会插入内存中 `LloOpcode` 的 family 自然位置(保持 family 连续),但追加到 `LloOpcodeProto` *wire* enum 的*末尾*(保持 wire compatibility)。结果就是 [LloOpcode↔Proto](llo-opcode-to-proto.md) map 的 non-monotonic tail:proto value 499(最新 wire slot)映射到内存中 `0x197`(`kVectorMaskPackCompressedEven`),proto value 498 映射到 `0x084`(`kVectorTraceArg`)。
---
## 交叉引用
- [LloOpcode↔Proto](llo-opcode-to-proto.md) — `LloOpcodeToProto` / `ProtoToLloOpcode` wire-value map 和 38 个 reserved proto gaps。
- [MC-Emitter](mc-emitter.md) — MC opcode space(`LloOpcode` + 499)上的 `getBinaryCodeForInstr` dispatch,它只编码 BarnaCore 子集,并对 TensorCore 子集返回全零。
- [InstBits DB](instbits-master-db.md) — `opcode_info` property word、`opcode_info_big` descriptor,以及按这些 opcodes keyed 的 Move-exclusion / CSE / remat gates。
- [LLO Opcode Table (appendix)](../appendix/llo-opcode-table.md) — 完整的 461 行 value↔name dump。