Skip to content

每代 Encoder Latch 序列化

地址适用于 libtpu-0.0.40-cp314 wheel 中的 libtpu.so(BuildID md5 89edbbe81c5b328a958fe628a9f2207d,未 strip,包含完整 C++ 符号)。其他版本会有所不同。

摘要

Latch 分配决定每个 MXU weight-latch op 在其 MxuSequence 内携带哪个索引。本页是编码侧:每个 TPU generation 的 Encoder 如何把一个已完成的 latch op——已经携带其 GainLatchModeBYTE[op+0x40])、unit-id/GMR(WORD[op+0x0b] bits 8–9)和 MSR(BYTE[op+0x44])——lower 到每代 TensorCore VLIW bundle 的 MXU / VectorExtended slot 的绝对 bit 位置。latch 从不以原始字段形式传递;它经过两阶段 lowering:每代的 *Emitter::EmitVectorLatch 把 LLO 字段写入一个 protobuf submessage,然后每代 encoder 再把该 submessage bit-pack 到 bundle bitstream 中。

编码工具包是 gloopbitcoding.cc writer 家族:byte 级 Encoder 可增长缓冲区、带内联 PutBits/PutVarInt/PutGamma primitives 的 BitEncoder accumulator、与 reader 共享的 (1<<k)-1 mask_ 表,以及——对于 V5+ protobuf-backed slots——独立的 BitCopy(dst, dst_bit, src, src_bit, nbits) field-blitter,V5+ codecs 每个字段调用一次。相同工具包也服务 route-cache codec 和 profiler trace codec;本页记录序列化 MXU latch 的那一半。reader 半边(BitDecoder GetBits64/GetGamma/GetVarInt/SkipBits)位于 route-cache codec 页面

跨 generation 有两种不同的 encoder 形态。Jellyfish (v2)单体式EncoderJf::EncodeVectorExtendedInstruction 是一个函数,它读取 proto 的 VectorExtendedOpcode 字段并运行一个 35-case switch,把 opcode-field 常量直接 OR-shift 到 QWORD[bundle+12] 中,GLM 先通过 6-entry {7,10,9,12,8,11} 表映射。Pufferfish (v4)、Viperfish (v5p) 和 Ghostlite/6acc60406 (v6e/TPU7x)oneof-typedEmitVectorLatch 按 GLM 选择 typed PushGains*/Pushmatrix*/PushMatrix* submessage,并由每个 variant 一个生成的 Encode…<Variant> sub-encoder 用 BitCopy blit 其字段。只有 Viperfish 会拆分其 7-bit MXU opcode 字段,因此 latch 和 matmul 共享该字段,并且 matmul opcode 的 LSB 是 MSR-select bit(bundle bit 57)——这是 MSR-A/MSR-B overrun handshake 的 bundle-level 编码,也只有 Viperfish 拥有它。

最后,本页钉住 CreateVectorLatchLsf entry guard opcode_produced_register_type[gain_src.opcode] != 4。Register-type 4 是vector类;该 guard 要求 LSF latch 消费的 gain matrix 来自 vector register,否则走较慢的 LloModule::UpdateStatus diagnostic path。它是决定哪些 latch ops 会被构建的 gate,也是 latch 的 register_number 是 Vregno 的原因。

对于重新实现,契约是:

  • latch 的 GainLatchMode 变成 slot opcode(在 V5+ 上还变成 dtype/format)。 在 JF 上,它索引 6-entry GLM→VEopcode 表,然后进入 35-case VEopcode→opcode-field switch。在 PF 上,它选择一个 PushGains* oneof,其 7-bit opcode @abs91 遵循 0x20 + variant + 8·transposed + 0x10·masked。在 VF 上,它选择一个 Pushmatrix* oneof,写入 opcode-high 14 @abs59 (5b) + MatmulDataFormat @abs51 (4b);dtype 搭载在 format 字段上,而不是 opcode 上(masked variants 则把 opcode 提升到 15..23)。
  • unit-id/GMR(MXU quadrant)变成 slot 字段。 JF 通过 AddMxuNumToVectorExtended 把它写入 proto +0x70,编码为 @abs27-28 (2b)。
  • MSR 是 Viperfish-only bit。 PF 只有单个 MSR,不发射 MSR bit。VF 把 MSR-A/MSR-B 编码为 7-bit matmul opcode @abs57 的 LSB;latch 从 proto +0x20 写入 1-bit control field @abs57,并从 proto +0x24 写入一个耦合 control bit @abs58
  • BitCopy(dst, abs_bit, &value, 0, width) 是 V5+ field writer。 abs_bit 是绝对 bundle bit,width 是字段 bit 宽;bundle 是 flat byte buffer,每个 byte 内 LSB-first。
  • type-4(vector)gain-register guard 约束构建。 CreateVectorLatchLsf 读取 opcode_produced_register_type[gain_src.opcode];如果它不是 4,则在继续前通过 UpdateStatus 记录一个 chunk->ProducesVreg() diagnostic。
Bit-writer primitivesgloop coder.cc Encoder + bitcoding.cc BitEncoderPutBits/PutVarInt/PutGamma,内联)
V5+ field blitterBitCopy(dst, dst_bit, src, src_bit, nbits) sub_1FA0A900
共享 mask tableBitEncoder::mask_ @0xbe79440 — 65 qwords, mask_[k]=(1<<k)-1
JF encoder(单体式)EncoderJf::EncodeVectorExtendedInstruction sub_1E869F00
JF GLM→VEopcode 表dword_AEF42AC = {7,10,9,12,8,11}(6 entries,按 GLM 0..5 索引)
PF emitter / encoderPufferfishTensorCoreEmitter::EmitVectorLatch sub_1410E1A0PushGains* sub-encoders sub_1EDC1660
VF latch encoder (bf16)Encode…0PushmatrixBf16 sub_1EFAF820: op 14@abs59, fmt 3@abs51, MSR @abs57, ctl @abs58
VF MSR-select bitbundle bit 57 = matmul 7-bit opcode 的 LSB(…Msra=2, …Msrb=3)
Type-4 gain guardCreateVectorLatchLsf sub_1D4D7AA0: opcode_produced_register_type[gain_src.opcode] != 4 → slow UpdateStatus
置信度CONFIRMED(byte-anchored),除非某行或 callout 另有说明

Bit-Writer Primitives

目的

每个 bundle byte 都由同一个 gloop writer 工具包产生。该工具包有三层:byte 级可增长缓冲区(Encoder)、其上的 bit accumulator(BitEncoder),以及——用于 protobuf-backed V5+ slots——独立的 BitCopy,它按绝对 bit 位置直接把一个字段写入 bundle 的 flat byte array。JF 的单体式 encoder 绕过 BitCopy,把常量直接 shift 进一个 uint64 bundle word;V5+ encoders 则逐字段用 BitCopy blit。没有导出的 PutBits/WriteBits 符号——它们内联进每个 call site——因此 primitives 是从 BitEncoder::Initialize(gamma-table self-test,执行完整 encode→decode round-trip)和真实 V5+ sub-encoders 中 byte-exact 重构的。

Encoder byte buffer

Encodercoder.cc)是一个四指针可增长缓冲区。其 destructor(sub_21073980)带有 buffer-overrun guard,这是其 layout 的最强证据:

c
struct Encoder {                 // 0x20 bytes
    char* cursor;     // +0x00  buf_  — next write position
    char* limit;      // +0x08  limit_ — one-past the writable region
    char* begin;      // +0x10  owned allocation base
    char* alloc_end;  // +0x18  alloc end | owns-heap flag (top bit); SSO marker 0x8000000000000028
};

function Encoder::~Encoder(this):                 // sub_21073980
    if (this.cursor > this.limit):                // CHECK buf_ <= limit_  (coder.cc:34)
        LogFatal("buf_ <= limit_")                // overrun guard — fires on any spill past limit_
    if (this.alloc_end == this.begin):            // a heap slot was taken
        free(this.begin)

GOTCHA — overrun guard 是 destructor CHECK,不是每次写入的 bounds check。 coder.cc:34buf_ <= limit_)只在 buffer 被销毁时触发,因此 encoder 在 packing 期间越过 limit_ 后会继续写过 allocation,直到 teardown 才 abort。重新实现必须预先把 buffer size 设为 bundle width;gloop writer 依赖 inline SSO buffer(0x8000000000000028 marker)对所有已发布 bundle 都足够大,并且 grow/realloc path 不在任何 latch-encode trace 上。

PutBits / PutVarInt / PutGamma

BitEncoder 包装一个 Encoder、一个 uint64 accumulator 和一个 bit count。BitEncoder::Initializesub_21072D40)通过用 PutGamma 编码每个值 1..255 并用 GetGamma 重新解码、断言相等,构建 runtime gamma table——这 byte-exact 暴露了内联 primitives:

c
// PutBits(value, n): mask to n bits, OR into the accumulator at the current
// bit position, then spill whole bytes LSB-first to the Encoder.
function PutBits(value, n):
    acc |= (value & mask_[n]) << bitpos       // mask_ @0xbe79440 = (1<<k)-1
    bitpos += n
    while bitpos >= 8:                         // byte-spill loop (seen in Initialize)
        *cursor = (uint8)acc                   //   *(_BYTE*)v13 = v6
        cursor += 1
        acc >>= 8                              //   v12 >>= 8
        bitpos -= 8                            //   v5 -= 8

// PutGamma(value>=1): Elias-gamma — b zero-bits, a 1, then the low b bits.
function PutGamma(value):
    b = floor(log2(value))                     // _BitScanReverse64(value | 1)
    emit b zero-bits, then a 1, then (value & mask_[b])
    // Initialize stores gamma_[i] = i | (codeword_len << 24);
    //   CHECK (value & 0xffffff) == value   (bitcoding.cc:110)
    //   re-decodes via GetGamma; CHECK v == i (bitcoding.cc:128)

// PutVarInt(chunk, value): self-delimiting integer — exact inverse of GetVarInt.
function PutVarInt(chunk, value):
    num_groups = max(1, ceil(bitlen(value) / chunk))
    emit (num_groups-1) one-bits then a 0      // unary prefix
    emit num_groups little-endian chunk-bit groups of value

mask_@0xbe79440.rodata,65 qwords)与 reader 共享;两者都用 value & mask_[n] 把值 clamp 到 n bits。gamma_@0x22593d00.bss,256 × uint32)在 runtime 构建,不是 baked。

NOTE — MXU latch path 不使用 PutVarInt/PutGamma 这些 self-delimiting 形式只出现在 route-cache path(和 gamma self-test)上。JF 单体式 encoder 使用 raw shift/OR;V5+ encoders 使用 fixed-width BitCopy。Latch 字段全是 fixed-width。这里记录 PutVarInt/PutGamma 只是因为它们共享 Encoder/mask_ substrate。

BitCopy — V5+ field blitter

V5+ TensorCore codecs 不累积;它们把每个字段直接写进 bundle byte array:

c
// BitCopy(dst, dst_bit, src, src_bit, nbits)        // sub_1FA0A900
//   dst      : the bundle's flat byte buffer
//   dst_bit  : absolute bit position in the bundle (LSB-first within each byte)
//   src      : pointer to the field value (the sub-encoders pass &local_qword)
//   src_bit  : 0 at every latch call site
//   nbits    : field width in bits

每个 V5+ latch 字段都以 local = value; BitCopy(bundle, abs_bit, &local, 0, width) 发射。该函数会 mask、shift 并 OR-merge 跨越目标 bytes 的 source bits(长拷贝使用 AVX2 batched body,否则使用 scalar tail),保留 [dst_bit, dst_bit+nbits) 之外的 bits。因此 sub-encoder 中的字段顺序与 wire 结果无关:每个 BitCopy 都是对固定 bit window 的独立 masked merge。


Jellyfish — 单体式 VectorExtended Encode

目的

Jellyfish(TPU v2)没有按 variant 生成的 encoder。单个 EmitVectorLatch 把 GLM 映射到 VectorExtendedOpcode,把它和 MXU number stamp 到 bundle 的 VectorExtendedInstruction proto 中,而 EncoderJf::EncodeVectorExtendedInstruction 随后把该 proto bit-pack 到 bundle 中。slot 位于 JF 41-byte bundle 的 VectorExtended 区域(@abs27-39);本节补充 latch-specific occupants。(Dragonfish,即 v3 gen,共享 JF emitter family——不过 AddMxuNumToVectorExtended 会以 TpuVersionToDeviceIdentifiers == kDragonfishIdentifiers gate 其 mxu_num proto write,因此在 plain Jellyfish 上该字段保留 default。)

入口点

text
JellyfishEmitter::EmitVectorLatch          sub_140B8C20  ── GLM→VEopcode + emit
  └─ EmitVectorExtendedInstruction         sub_140B4F80  ── VEopcode → proto+0x60, Vs → proto+0x6c
  └─ AddMxuNumToVectorExtended             sub_140B8DA0  ── mxu_num → proto+0x70
        … (bundle finalize) …
        EncoderJf::EncodeVectorExtendedInstruction  sub_1E869F00  ── proto → bundle bits

算法

c
function JellyfishEmitter::EmitVectorLatch(glm, vs_reg, mxu_num):   // sub_140B8C20
    if (glm >= 6) LogFatal("Unexpected Software latch mode.")       // jellyfish_emitter.cc:1647
    veopcode = dword_AEF42AC[glm]                                   // {7,10,9,12,8,11}
    EmitVectorExtendedInstruction(veopcode, vs_reg, /*imm=*/0)      // sub_140B4F80
    AddMxuNumToVectorExtended(mxu_num)                              // sub_140B8DA0

function EmitVectorExtendedInstruction(veop, vs, imm):              // sub_140B4F80
    ve = bundle.mutable_vector_extended()                           // proto submessage @bundle+0x50
    *(DWORD*)(ve + 0x60) = veop                                     // VEopcode field
    SetPredication(ve)
    *(DWORD*)(ve + 0x6c) = vs                                       // rotate-Vs / source reg

function AddMxuNumToVectorExtended(mxu):                            // sub_140B8DA0
    CheckMxuNum(mxu)
    *(DWORD*)(ve + 0x70) = mxu                                      // mxu_num field

function EncoderJf::EncodeVectorExtendedInstruction(ve, bundle):    // sub_1E869F00
    word = QWORD[bundle + 12]                                       // the VectorExtended bundle qword
    word = (word & ~(0x1F << 35)) | ((pred & 0x1F) << 35)           // predication @abs35-39
    word = (word & ~(0x3  << 27)) | ((ve.mxu_num & 3) << 27)        // mxu-id/GMR @abs27-28
    switch (ve.VEopcode):                                           // 35-case opcode→field switch
        case 0:  word = (word & 0xFFFFFFF81FFFFFFF) | 0x20000000    // field 1 @abs29-34 (no-op opcode)
        case 7:  word = (word & 0xFFFFFFF81FFFFFFF) | (0x9 << 29)   // ← LATCH GLM0 (bf16 NO_XPOSE)
        case 8:  word = (word & 0xFFFFFFF81FFFFFFF) | (0xa << 29)   // ← LATCH GLM4 (int8/S8)
        case 9:  word = (word & 0xFFFFFFF81FFFFFFF) | (0xb << 29)   // ← LATCH GLM2 (packed-bf16)
        case 10: word = (word & 0xFFFFFFF81FFFFFFF) | (0xd << 29)   // ← LATCH GLM1 (bf16 alt)
        case 11: word = (word & 0xFFFFFFF81FFFFFFF) | (0xe << 29)   // ← LATCH GLM5 (fp8-conv)
        case 12: word = (word & 0xFFFFFFF81FFFFFFF) | (0xf << 29)   // ← LATCH GLM3 (fp8 / E5M2)
        … (matmul / matres / EUP VEopcodes 1..6, 13..34) …
        default: LogFatal("Unknown opcode: ")                       // encoder_jf.cc:2570
    QWORD[bundle + 12] = word

常量 << 29 是位于 @abs29-34 的 6-bit opcode-field;每个 populated case 都先清除该字段(& 0xFFFFFFF81FFFFFFF,bits 29–34),再 OR 进 case value。该字段不是统一为 odd——0xa(GLM4)和 0xe(GLM5)的 bit 29 为 clear——因此它是普通 6-bit opcode,而不是 opcode-plus-fixed-valid-bit。

latch GLM → bundle opcode 链

把两个表串起来运行——GLM 通过 dword_AEF42AC,然后 VEopcode 通过 encoder switch——得到六个 JF latch opcodes:

GLM含义VEopcodeopcode-field @abs29
0bf16 NO_XPOSE70x9
1bf16 alt100xd
2packed-bf1690xb
3fp8 / E5M2120xf
4int8 / S880xa
5fp8-conv110xe

NOTE — 六个 GLM opcode-fields 全部不同;该 map 是 bijection。EncoderJf::EncodeVectorExtendedInstruction0x1e869f00)中,LABEL_55 cases(VEopcode 8, 11)在 LABEL_53 cases 使用的相同 base 上额外加 0x20000000,因此 VEopcode 8 编码为 field 0xa(不是 0x9),VEopcode 11 编码为 0xe(不是 0xd)。所以六个 JF latch opcode-fields 是 {0x9, 0xd, 0xb, 0xf, 0xa, 0xe}——全部不同,是六种 latch modes 上的 bijection。很容易误读为 GLM0/GLM4 和 GLM1/GLM5 发生碰撞(0x9/0xd);0x20000000 项正是区分它们的部分。

NOTE — JF VectorExtended slot 不携带单独的 format 字段。 虽然 opcode 字段区分所有六个 latch GLMs,但它是单个 6-bit 字段,没有像 VF 的 @abs51 那样的配套 MatmulDataFormat。dtype 隐含在 opcode value 中,因此 JF decoder 只从 opcode field 重构 data type(0x9→bf16 NO_XPOSE, 0xa→int8, …),而不是从 side field 重构。

函数映射

函数地址角色
JellyfishEmitter::EmitVectorLatchsub_140B8C20GLM bound < 6、GLM→VEopcode lookup、emit chain
JellyfishEmitter::EmitVectorExtendedInstructionsub_140B4F80VEopcode → proto +0x60,Vs → proto +0x6c
JellyfishEmitter::AddMxuNumToVectorExtendedsub_140B8DA0mxu_num → proto +0x70
EncoderJf::EncodeVectorExtendedInstructionsub_1E869F0035-case VEopcode → bundle bits;pred @abs35,mxu-id @abs27,opcode @abs29
dword_AEF42AC.rodata6-entry GLM→VEopcode table {7,10,9,12,8,11}

NOTE — encoder 从 proto +0x64 读取 MXU id;emitter 把它写到 +0x70 encoder 从 proto +0x64*((DWORD*)ve + 25))读取 MXU id,而 AddMxuNumToVectorExtended 写入 mxu_num 到 proto +0x70。两者可解释为 emitter 通过一次 indirection 持有 submessage,而 encoder 直接接收它;unit-id → @abs27-28 binding 无论哪种方式都是 byte-exact,但哪个 protobuf field number 占用 +0x64 vs +0x70 未与 proto descriptor 交叉核对。精确 field-number layout 为 MEDIUM;bundle-bit binding 为 CONFIRMED。


Pufferfish — PushGains Oneof Encode

目的

Pufferfish(TPU v4)是第一代具备 generated、per-variant encoders 的 generation。EmitVectorLatch 把 GLM 分发到 TensorCoreVectorExtended0(MXU0)或 TensorCoreVectorExtended1(MXU1)submessage 内的 typed PushGains{Rounded,Low,Hi,Packed,Byte}{,Transposed}{,Masked} oneof;随后 generated Encode…<Variant> sub-encoder 用 BitCopy 写字段。PF 只有单个 MSR(没有 overrun handshake),因此不发射 MSR bit。

入口点

text
PufferfishTensorCoreEmitter::EmitVectorLatch     sub_1410E1A0  ── switch(glm) → PushGains oneof
  ├─ DefaultConstruct<…_PushGainsRounded>                       (MXU0 slot, bundle flag 0x80)
  │   or DefaultConstruct<…1_PushGainsRounded>                  (MXU1 slot, bundle flag 0x100)
  └─ … 20 PushGains variants …
        EncodeTensorCoreVectorExtended0PushGainsRounded sub_1EDC1660  ── BitCopy fields → bundle

算法

EmitVectorLatch 是一个 switch(glm),按 GLM claim 一个 MXU slot 并构造匹配的 oneof。MXU0/MXU1 选择以 bundle 的 populated-slot flags 为 key(0x80 = MXU0 taken,0x100 = MXU1 taken;两者都 set ⇒ "All vector extended slots occupied."):

c
function PufferfishTensorCoreEmitter::EmitVectorLatch(glm, vs, msr, mxu):  // sub_1410E1A0
    bundle = CurrentBundle()
    switch (glm):
        case 0: variant = PushGainsRounded            // oneof tag 104
        case 1: variant = PushGainsRoundedTransposed  // oneof tag 109
        case 2: variant = PushGainsHi                 // oneof tag 106
        case 3: variant = PushGainsHiTransposed       // oneof tag 111
        case 4: variant = PushGainsLow                // oneof tag 105
        … (GLM 5..13; 6..9 share an error branch) …
    ve = (bundle.mxu0_free()) ? bundle.mutable_tcve0()    // proto @bundle+0x50
                              : bundle.mutable_tcve1()    // proto @bundle+0x58
    SetPredicate(ve)
    ve.set_oneof(variant); ve.set_vsreg(vs)

function EncodeTensorCoreVectorExtended0PushGainsRounded(bundle, ve):   // sub_1EDC1660
    op = 0x20;  BitCopy(bundle, 91, &op, 0, 7)            // opcode @abs91 (7b)
    if ve.has_mode():    BitCopy(bundle, 89, &ve.mode,  0, 2)   // mode   @abs89 (2b)
    if ve.has_subop():   BitCopy(bundle, 83, &ve.subop, 0, 3)   // sub-op @abs83 (3b)
    if ve.has_op0():     BitCopy(bundle, 225, &ve.op0, 0, 5)    // register operands,
    if ve.has_op1():     BitCopy(bundle, 182, &ve.op1, 0, 5)    //   5b each, shared
    if ve.has_op2():     BitCopy(bundle, 152, &ve.op2, 0, 5)    //   operand pool
    if ve.has_op3():     BitCopy(bundle, 203, &ve.op3, 0, 5)
    if ve.has_op4():     BitCopy(bundle, 172, &ve.op4, 0, 5)
    // NOTE: predication is @abs98 (5b), written by the slot's shared pred path

PushGains opcode 表(@abs91, 7-bit)

20 个 variants 遵循规则结构:opcode = 0x20 + variant + 8·transposed + 0x10·masked,其中 variant ∈ {Rounded:0, Low:1, Hi:2, Packed:3, Byte:4}

Variantbase+Transposed+Masked+Transp+Masked
Rounded0x200x280x300x38
Low0x210x290x310x39
Hi0x220x2a0x320x3a
Packed0x230x2b0x330x3b
Byte0x240x2c0x340x3c

函数映射

函数地址角色
PufferfishTensorCoreEmitter::EmitVectorLatchsub_1410E1A0switch(glm)PushGains* oneof;MXU0/MXU1 slot select
Encode…0PushGainsRoundedsub_1EDC1660BitCopy opcode 0x20@abs91,mode @abs89,sub-op @abs83,operands
19 个 sibling Encode…0PushGains*sub_1EDC1920..sub_1EDC4E00per-variant opcode 0x21..0x3c @abs91

NOTE — Pufferfish 上没有 MSR bit。 PF 有单个 matrix-staging register,且 HasMsrOverrunChecks()FALSE(见 latch assignment)。PushGains sub-encoders 不写 MSR-select 字段;PF codec 中没有任何带 MSR suffix 的 oneof types。MSR-A/MSR-B 区分是 Viperfish-only 功能。


Viperfish — Pushmatrix Oneof 和 MSR-Select Bit

目的

Viperfish(TPU v5p)把其 MXU0 opcode 打包进 @abs57-63 处的 7-bit 字段,latch 和 matmul 共享该字段。latch 只写 high 5 bits(@abs59)和 4-bit MatmulDataFormat@abs51),留下 low two bits 作为 control;matmul 写入 @abs57 处的完整 7-bit opcode,并且其 LSB(@abs57)是 MSR-select bit。这是 MSR-A/MSR-B overrun handshake 的 bundle-level 编码——也是唯一拥有该 handshake 的 generation,与 HasMsrOverrunChecks 只在 Viperfish 上为 TRUE 一致。Viperfish 64-byte bundle 的 MXU slot map 位于 VF bundle 页面

算法

latch sub-encoder(下面展示 bf16)通过一次 BitCopy 写入 opcode-high、format、两个 control bits、sub-fields 和 operands:

c
function EncodeTensorCoreVectorExtended0PushmatrixBf16(bundle, ve):   // sub_1EFAF820
    hi = 14;  BitCopy(bundle, 59, &hi,  0, 5)             // opcode-high @abs59 (5b) = 14 (bf16)
    fmt = 3;  BitCopy(bundle, 51, &fmt, 0, 4)             // MatmulDataFormat @abs51 (4b) = 3 (Bf16)
    if ve.has_sub0():  BitCopy(bundle, 48, &ve.sub0, 0, 3)        // sub @abs48 (3b)
    if ve.has_sub1():  BitCopy(bundle, 55, &ve.sub1, 0, 2)        // sub @abs55 (2b)
    if ve.has_msr():   BitCopy(bundle, 57, &ve.msr,  0, 1)        // MSR-select @abs57 (1b), proto+0x20
    if ve.has_ctl():   BitCopy(bundle, 58, &ve.ctl,  0, 1)        // control    @abs58 (1b), proto+0x24
    // register operands @abs157/282/293/248/259/214/225/180 (6b each)

matmul 侧证明了 MSR bit。U8 matmul 有两个 encoders,它们在写到 @abs57 的 opcode value 上不同:

c
function Encode…0MatrixMultiplyU8LgmrMsra(bundle, ve):   // sub_1EFA4A20
    op = 2;  BitCopy(bundle, 57, &op, 0, 7)              // full 7-bit opcode = 2 ⇒ bit57 = 0 (MSR-A)

function Encode…0MatrixMultiplyU8LgmrMsrb(bundle, ve):   // sub_1EFA4E00
    op = 3;  BitCopy(bundle, 57, &op, 0, 7)              // full 7-bit opcode = 3 ⇒ bit57 = 1 (MSR-B)

QUIRK — 在 Viperfish 上,latch dtype 搭载在 format 字段,而不是 opcode。 每个 non-masked Pushmatrix* variant 都在 @abs59 写入 opcode-high 14;data type 完全位于 @abs51 的 4-bit MatmulDataFormat 中。只有 masked variants 会把 opcode-high 提升到 15..23。因此,一个读取 @abs59 来区分 bf16 和 int8 的 decoder 会看到两者都是 14,必须查询 @abs51。这与 JF slot 相反,后者在 opcode 字段中(部分)携带 dtype,且没有 format 字段。

每种 dtype 的 Pushmatrix opcode + format

Oneofop-high @abs59format @abs51Masked oneofop-high @abs59
PushmatrixRounded140RoundedMasked15
PushmatrixPackedIf8Conv142PackedIf8ConvMasked17
PushmatrixBf16143Bf16Masked18
PushmatrixBf8144Bf8Masked19
PushmatrixU8145U8Masked20
PushmatrixS8146S8Masked21
PushmatrixU4147U4Masked22
PushmatrixS4148S4Masked23

MXU1(VectorExtended1)slot 是 MXU0 layout 下移 20 bits:opcode-high @abs39、format @abs31、MSR @abs37

函数映射

函数地址角色
Encode…0PushmatrixBf16sub_1EFAF820latch: op 14@abs59,fmt 3@abs51,MSR @abs57,ctl @abs58,operands
15 个 sibling Encode…0Pushmatrix*sub_1EFAE520..sub_1EFB2C40per-dtype op 14/masked 15..23,fmt 0..8
Encode…0MatrixMultiplyU8LgmrMsrasub_1EFA4A20matmul opcode 2@abs57(bit57=0,MSR-A)
Encode…0MatrixMultiplyU8LgmrMsrbsub_1EFA4E00matmul opcode 3@abs57(bit57=1,MSR-B)

NOTE — bit 57 把 encode 侧与 latch-assignment overrun gate 和 VF cost model 连接起来。 matmul 在 @abs57 携带的 MSR-A/MSR-B 选择,正是 Viperfish cost model 以 {Msr:2/6} 计费的额外 reservation 所对应的 handshake(见 MatmulMode and Modifiers)。latch 的 MSR 字段(BYTE[op+0x44])决定 consuming matmul 读取哪个 bank,从而决定触发哪个 …Msra/…Msrb matmul encoder——也就是 bit 57 的值。SetLatchIndices 只在 Viperfish wide formats 上分配的 first-latch index 是 scheduling-side decision;bit 57 是它的 bundle-level result。

GOTCHA — @abs58 control bit 的角色未钉住。(LOW) VF latch 从 proto +0x24 写入第二个 1-bit 字段 @abs58,与 @abs57 的 MSR bit 相邻。它是独立的 per-latch control flag,但它是 arm overrun handshake、选择第二个 MSR,还是确认 transpose,尚未被隔离到命名字段。@abs57 MSR-select 是 CONFIRMED(通过 matmul Msra/Msrb LSB);@abs58LOW


Ghostlite / 6acc60406 — PushMatrix Oneof

目的

Ghostlite(v6e,glc)和 6acc60406(TPU7x,gfc)使用与 Viperfish 相同的 oneof-typed 形态,带有 PushMatrix*{,Masked} variants,并且也有 Msra/Msrb matmul family。两者的 dtype roster 不同:glc 将其 variants 命名为 {F32, Bf16, Bf8, If8, S4, S8, U4, U8},而 gfc 命名为 {F32, Bf16, E4m3, E5m2, …}——也就是说,gfc 上的 fp8 modes 按 encoding(E4m3/E5m2)而不是按 role(Bf8/If8)拼写。只有 bf16 latch opcode bit base 和 value 被逐 cell trace。

编码

Genbf16 latch encoderopcode bit / widthopcode value (bf16)
Ghostlite (v6e, glc)PushMatrixBf16 sub_1F33FE00@abs60 (6b)14 (0xe)
6acc60406 (TPU7x, gfc)PushMatrixBf16 sub_1F9A14E0@abs64 (6b)14 (0xe)

dtype 是 oneof type;opcode value 是两者共享的 matpush constant 14glcgfc bit base 漂移 +4 bits。完整 latch-slot field roster(pred、format、MSR positions)在 opcode bit base 之外没有为任一 gen trace。opcode bit/value 之外为 MEDIUM


Type-4 Gain-Register Guard

目的

在任何 latch op 被构建之前,CreateVectorLatchLsf 检查 gain source——feeding LSF latch 的 LloValue——是否产生 type 4(vector class)的 register。该检查是决定 latch 走 fast build path 还是记录 diagnostic 的 gate;它是 assignment-side guards 的 encode-pipeline analog,也是 latch 的 register_numberBYTE[op+0x0a])是 Vregno 的原因。

算法

c
function LloInstruction::CreateVectorLatchLsf(gain_src, glm, unit_id, region):  // sub_1D4D7AA0
    op_code = WORD[gain_src]                                  // the gain SOURCE opcode
    if (op_code >= 0x1CD) trap                                // bound 461 (ud1)
    while (opcode_produced_register_type[op_code] != 4):      // .data table @0x223a16c0
        cf = new CheckFailer()
        diag = make_unique<StatusWrapper>(cf, "chunk->ProducesVreg()",
                                          {line 1073, llo_instruction.cc})
        LloModule::UpdateStatus(region.module, diag)          // slow diagnostic path
        // loop re-checks after the status is recorded
    if (glm > 0x33 || !bittest(0xF0000003C0C03, glm)):
        LogFatal("LSF latch mode not expected.")              // llo_instruction.cc:1089
    op = LloInstruction::New(0x8d /*kVectorLatchLsf*/, {gain_src}, region)
    set_latch_mode(op, glm)                                   // BYTE[op+0x40] = glm
    set_matrix_staging_register(op, 1)                        // BYTE[op+0x44] = 1 (LSF staging slot)
    ValidateAndSetMxuAndSourceBus(unit_id, op)                // WORD[op+0x0b] unit-id
    return op

opcode_produced_register_type@0x223a16c0.data;indices 0..460 的 461 个 one-byte entries——>= 0x1CD bound,位于 464-byte symbol span 内)按producer opcode 索引,并使用 taxonomy {0=none, 1=predicate, 2=scalar, 3=vector-mask, 4=vector}。latch opcodes 0x8d..0x96 自身映射到 type 0——它们没有 destination register;它们 push 到 systolic array 中。因此 guard 读取的是 gain source 的 entry,而不是 latch 的 entry。同样的 table-read 出现在 Matprep/IAR/Latch ISA 页面,该页把 matprep source guard 建模为 opcode_produced_register_type[source.opcode] == 4

为什么是 register-type 4

Type 4 是 bulk vector register class。latch 加载到 MXU 中的 gain matrix 必须位于 vector register 中,因此 latch operand 的 producer 必须是 vector-producing op——load、scalar-to-vector、IAR read 等。如果 gain source 反而是 scalar(type 2)、mask(type 3)或 predicate(type 1)producer,guard 会通过 UpdateStatusStatusWrapper slow path)记录 chunk->ProducesVreg() diagnostic,而不是直接 abort。

QUIRK — 该 guard 是 status-recording loop,不是 hard FATAL。 与其下方的 GLM-validity check(对 unexpected latch mode 调用 LogFatal)不同,type-4 mismatch path 会分配 StatusWrapper、调用 LloModule::UpdateStatus,然后在 loop 中重新检查——在 module 上记录 register-class diagnostic,同时仍继续构建 op。把 type-4 mismatch 变成 hard error 的重新实现,会偏离 binary 更柔和的 status-accumulating 行为。

函数映射

函数地址角色
LloInstruction::CreateVectorLatchLsfsub_1D4D7AA0gain-source bound、type-4 guard、slow path、field stamp
opcode_produced_register_type@0x223a16c0 (.data)461-entry(每项 1 byte)producer→reg-type table;4=vector
set_latch_modesub_1D4D7C20BYTE[op+0x40] = glm
set_matrix_staging_registersub_1D4D7D40MSR opcode-mux: latch→+0x44,matmul→+0x46,load-LMR→+0x42,dwg→+0x41
set_latch_index_in_sequencesub_1D4E7960WORD[op+0x42] = index,bound ≤ 0xFFFF

NOTE — latch_index 字段不是 per-latch bundle bit。 set_latch_index_in_sequencesub_1D4E7960)把分配的 ordinal 存到 WORD[op+0x42](在 llo_instruction.cc:3399 重新检查 LloOpcodeIsVectorLatch,并在 :3400 bound index <= 65535),但没有 encoder 把该 ordinal blit 到 bundle 中。index 是 encode 前消费的scheduling artifact:在 Viperfish 上,first-latch index gate overrun handshake 是否触发,而它在 bundle 中只间接表现为 MSR-select bit @abs57。wire bundle 携带 opcode、format、unit-id 和 MSR——从不携带 sequence index。


LLO → Proto → Bundle 字段对应关系

对于一个 latch op,三种表示对齐如下:

LLO field(assignment side)Proto fieldBundle bit(per gen)
GainLatchMode BYTE[op+0x40]VEopcode / oneof typeJF opcode @abs29-34; PF op @abs91; VF op @abs59 + fmt @abs51; GXC op @abs60(glc)/@abs64(gfc)
unit-id/GMR WORD[op+0x0b] bits 8–9mxu-num(JF proto +0x70JF @abs27-28
MSR BYTE[op+0x44]Msra/Msrb oneof(VF)VF @abs57(MSR-select);PF/JF: none
register_number BYTE[op+0x0a]gain-source Vregnotype-4-guarded vector reg selector
latch_index_in_sequence WORD[op+0x42](assignment only)不是 per-latch bundle bit;间接 gate VF @abs57

相关组件

组件关系
Latch Assignment & Overrun填写 BYTE[op+0x40]/WORD[op+0x42] 的 assignment pass;本页是它的 encode-side consumer
MxuSequence / SequenceInfolatches 在此编码的 sequence record
Matprep, IAR, and Latch Sub-Slotslatch-op LLO field layout,以及来自 ISA side 的 matprep type-4 source guard
MXU Slotlatched gains feed 的 systolic-array matmul slot
Viperfish 64-Byte Bundle本页拆分其 MXU0 7-bit opcode 字段 @abs57-63 的 VF bundle
Pufferfish 51-Byte BundleMXU0 slot 持有 PushGains opcode @abs91 的 PF bundle
Jellyfish 41-Byte BundleVectorExtended slot 持有 latch opcode @abs29-34 的 JF bundle

交叉引用

  • Latch Assignment & Overrun — 分配本页序列化的 latch indices 和 GLMs;BYTE[op+0x40]WORD[op+0x42]BYTE[op+0x44] 的来源。
  • MxuSequence / SequenceInfo — 产生 latch ops 的 MxuSequence record 和 LatchLhs partition。
  • Matprep, IAR, and Latch Sub-Slots — latch-op LloInstruction field offsets,以及 matprep opcode_produced_register_type == 4 source guard,即此处 gain guard 的 sibling。
  • MXU Slot — matmul op family,其 Msra/Msrb encoders 设置 VF @abs57 MSR-select bit。
  • Viperfish 64-Byte Bundle — 本页 latch fields 所占用的 VF MXU0/MXU1 slot map。
  • Pufferfish 51-Byte Bundle — PF MXU0 slot map;PushGains opcode @abs91
  • Jellyfish 41-Byte Bundle — JF VectorExtended slot map;latch opcode-field @abs29-34
  • Route-Cache Codec — 与本页 writer primitives 共享的 gloop BitDecoder/BitEncoder bit-codec 工具包的 reader 半边。
  • MatmulMode and Modifiers — Viperfish {Msr:2/6} overrun-check reservation;此处解码的 MSR-select bit 的 cost-side consumer。
  • Binary: extracted/libtpu-0.0.40-cp314-cp314-manylinux_2_31_x86_64/libtpu/libtpu.so(build-id 89edbbe81c5b328a958fe628a9f2207d
  • Index entry: Part VIII — Instruction Scheduling & Bundle Packing — 返回索引