Skip to content

V5+ EmitX 绝对位位置

本页所有地址均适用于 libtpu-0.0.40-cp314 wheel 中的 libtpu.solibtpu-0.0.40-cp314-cp314-manylinux_2_31_x86_64/libtpu/libtpu.so,BuildID 89edbbe81c5b328a958fe628a9f2207d,781,691,048 B,未 strip,.text VA == 文件偏移)。其他构建会不同。

摘要

Jellyfish(v2)和 Pufferfish(v4)用单个整体式编码器构造 bundle,即 EncoderJf::EncodeBundleInternal0x1e86c7c0)和 EncoderPfTensorCore::EncodeBundleInternal0x1e8c5c40);它们接收一个 Bundle 对象并内联打包每个槽。本构建中的每个 V5+ 代(Viperfish/vxc+vfc、Ghostlite/glc、6acc60406/gfc)都完全放弃了该模型。任何 V5+ codec 都不存在 EncodeBundleInternal。bundle 改由两阶段链路生成:上游由 xla::tpu::sparse_core::isa_emitter::EmitX proto-template 填充带类型的 proto 子消息并设置 present bit;下游由逐槽 <Slot>Encoder::Encode codec 读取该 proto,并通过一个通用的按位打包器 BitCopy(dst, dst_bit, src, src_bit, nbits)0x1fa0a900)把每个字段写到扁平 bundle 字节缓冲区中的固定绝对位位置。本页汇总 sequencer、immediate 和 predicate 槽的这些绝对位位置;各代 bundle 页面会把这些内容委托到本页。

结构性后果是:LLVM-MC InstBits 表在标准 LLVM 后端中保存每条指令的固定 opcode 位,而在每个 V5+ 代中它在磁盘上全为零。静态表中没有固定指令位;整个 bundle 布局是一张扁平的 (absolute-bit, width) 三元组列表,分布在约两百个逐 op 的 BitCopy helper 中,并由单个 EncodeBundle dispatcher 编排。每槽 BitCopy 偏移集合就是该代实际的 kIsaTable。重新实现者若寻找静态 InstBits 数组,或寻找 EncoderVf::EncodeBundleInternal,都不会找到。

本页按两个编码阶段组织,然后按槽组织。开头的 BitCopyEmitImmediate 小节确立基本原语及其 proto-field 约定;immediate、sequencer 和 predicate 小节给出各代的绝对 (dst_bit, width) 映射;MXU/result/EUP 小节汇总 compute-slot 位置;最后的逐 (slot, gen) 表是 ViperfishGhostlite6acc60406 bundle 页面引用 deferred 字段时使用的单一参考。

对重新实现而言,契约如下:

  • 两阶段链路:EmitX proto 填充(阶段 1)→ <Slot>Encoder::Encode BitCopy(阶段 2)。没有整体式 EncodeBundleInternal
  • BitCopy(dst, dst_bit, src, src_bit, nbits) 调用约定,以及位精确、LSB-first 语义。
  • EmitImmediate proto 槽映射(一个值落入 6 个 immediate 槽中的哪一个,以及它的 present bit)。
  • 对 32 字节 SCS bundle 和 64 字节 TC bundle,逐代给出 sequencer(branch/call/LCC)判别符、dest/x-target sreg 和 predication 字段的绝对 (dst_bit, width)
  • 每代绝对位差异:Viperfish 基线 → Ghostlite TC +3 位平移 → 6acc60406(自己的布局,专用双 predicate 槽,2 位逐槽选择器)。
通用打包器BitCopy(void* dst, int dst_bit, const void* src, int src_bit, int nbits) @ 0x1fa0a900(mangled _Z7BitCopyPviPKvii
调用约定dst=rdidst_bit=esisrc=rdxsrc_bit=ecxnbits=r8d(System V);按位粒度,LSB-first
阶段 1 发射器命名空间xla::tpu::sparse_core::isa_emitter::EmitX<…>EmitImmediateEmitBranchOpEmitCallOpEmitPredicationToSlot
阶段 2 codec 命名空间asic_sw::deepsea::{vxc,vxc::vfc,gxc::glc,gxc::gfc}::isa::<Slot>Encoder::Encode
编排器EncodeBundle 0x1e838cc0(6acc60406 codec;TC worker 0x1d371540),EncoderGlTensorCore::EncodeBundle 0x1d331d00(Ghostlite)
SCS bundle32 B / 256 bit;branch/call offset(imm slot 0)位于 bit 67,所有 V5+ 代相同
TC bundle64 B / 512 bit;branch/call offset(imm slot 0)位于 bit 430(vxc)/ 433(glc)/ 423(gfc
InstBits0x3366d90,对每个 V5+ 代均全零,无重定位

两阶段编码链路

目的

指令含义(带类型的 proto 子消息,与代无关)和位放在哪里(逐代 BitCopy 偏移映射)分离。阶段 1 在前半发射器中运行,为每个占用槽产生带已填充子消息的 *Bundle proto。阶段 2 在 codec 中运行,把该 proto 序列化为 wire bundle。这个拆分解释了为什么同一个 LLO op 在 Viperfish、Ghostlite 和 6acc60406 上会编码成三种不同位布局,而前端发射器逻辑无需改变,只有 codec 的偏移字面量不同。

入口点

text
LLO MCInst
  └─ isa_emitter::EmitX<Slot, OpKind>      ── Stage 1: populate proto sub-message
       │   sets present bit, writes operand fields

  <gen> proto bundle (SparseCoreScsBundle / TensorCoreBundle / …)

  EncodeBundle  0x1e838cc0  (dispatch on TpuSequencerType)
       ├─ case 0 → TensorCoreCodecBase<…>   → TC worker 0x1d371540
       ├─ case 3 → SparseCoreScsCodecBase<…> → EncoderBase::EncodeBundle
       └─ case 5 → SparseCoreTecCodecBase<…> → EncoderBase::EncodeBundle
                       │   walk per-slot Encoders in template-arg order

  <Slot>Encoder::Encode                    ── Stage 2: BitCopy fields → bundle bytes
       └─ BitCopy(buf, dst_bit, &field, 0, width)   0x1fa0a900
```text

### 算法

阶段 1 的 immediate 填充由 demangled 的 `isa_emitter::EmitImmediate<glc::isa::SparseCoreImmediates>` 函数体(`0x139f7060`)确认:

```c
function EmitImmediate(slot_index, value, immediates_msg):    // 0x139f7060
    if value >= 0x100000:                                     // llvm::isUInt<20> RET_CHECK
        return Error("isa_emitter_base.h:587")                //   (signed 20-bit offsets are pre-masked)
    switch slot_index:                                        // jump on slot 0..5
        case 0: field = msg+0x18; present = 0x01; break       //   imm_0()
        case 1: field = msg+0x1c; present = 0x02; break       //   imm_1()
        case 2: field = msg+0x20; present = 0x04; break       //   imm_2()
        case 3: field = msg+0x24; present = 0x08; break       //   imm_3()
        case 4: field = msg+0x28; present = 0x10; break       //   imm_4()
        case 5: field = msg+0x2c; present = 0x20; break       //   imm_5()
        default: return Error("Invalid immediate: <n>")
    if (msg+0x10 & present) && *field != value:               // RET_CHECK: re-set must match
        return Error("imm_N() == value")
    *field = value
    msg+0x10 |= present                                       // set present bit at msg+0x10
    return Ok

阶段 2 中,逐槽编码器读取每个已填充的子消息,并发出一串 BitCopy 调用。编码器主体是在 proto opcode 判别符上的 switch,该判别符在 Viperfish/Ghostlite 标量编码器和 gfc TC sequencer 中位于 proto+0x50,在 gfc SCS sequencer 和 gfc predicates 编码器中位于 proto+0x58gfc proto 有更宽的 header);每个 arm 是一个 op 家族的字段布局。通用形状(来自 immediates 编码器)如下:

c
function <Slot>Encoder::Encode(this, proto, out_buf):
    scratch[0] = proto.imm_0                                  // stage value into 8-byte scratch
    BitCopy(out_buf, ABS_BIT_0, scratch, 0, WIDTH_0)          // place WIDTH_0 bits at ABS_BIT_0
    scratch[0] = proto.imm_1
    BitCopy(out_buf, ABS_BIT_1, scratch, 0, WIDTH_1)
    ...                                                       // one BitCopy per field
    return Ok
```text

> **NOTE —** `EmitImmediate` **不知道**绝对位。它只选择六个 proto 字段之一并设置 present bit。绝对位完全由阶段 2 的编码器 `BitCopy` 字面量决定。这就是为什么同一个逻辑 immediate slot 0 在 SCS 中位于 bit 67,而在 TC 中位于 bit 430 的原因:proto 字段相同,编码器不同。

---

## BitCopy:通用打包器

### 目的

一个函数负责打包每个 V5+ bundle 的每个字段。不存在按类型划分的序列化器;每个 `<Slot>Encoder::Encode` 都是一张扁平的 `BitCopy` 调用列表。恢复任意槽的布局,等价于读取命名编码器中每个 `BitCopy` 调用前的 `(dst_bit, nbits)` 立即数对。

### 调用约定和语义

`BitCopy` 是 `_Z7BitCopyPviPKvii`,即 `BitCopy(void* dst, int dst_bit, const void* src, int src_bit, int nbits)`。在 System V 下,参数进入 `rdi`、`esi`、`rdx`、`ecx`、`r8d`。反编译函数体(`0x1fa0a900`)确认了位精确、LSB-first 行为:

```c
function BitCopy(dst, dst_bit, src, src_bit, nbits):          // 0x1fa0a900
    if nbits == 0: return                                     //   early-out, then vzeroupper
    dst_byte = dst_bit / 8                                    //   = dst_bit >> 3
    dst_off  = dst_bit & 7                                    //   bit-in-byte
    src_byte = src_bit / 8
    src_off  = src_bit & 7
    // copy nbits from src starting at (src_byte, src_off) into dst at (dst_byte, dst_off),
    // LSB-first, preserving the surrounding bits of any straddled dst byte
    // (vectorized inner loop when the run is >= 24 bits; scalar head/tail otherwise)

函数体完全按上述方式计算 dst_bit / 8dst_bit & 7,对前导/尾随的部分字节做掩码,使相邻字段不受影响,并对 24 位及以上的连续区间使用 AVX 内循环。bit 0 是 bundle 缓冲区 byte 0 的 LSB。

QUIRK — 由于每个字段都是独立 BitCopy 到共享缓冲区,字段顺序对正确性无关紧要,只要窗口不重叠。编码器会先写 predication header,再分派逐 op 逻辑,但重新实现可以按任意顺序发出调用。重叠本身是设计允许的:在 6acc60406 SCS 上,3 位 predicate selector 和 4 位 dual-predicate index 都从 bit 187 开始(见 Predicate Slot)。

因此,每个具体的 mov esi,<dst_bit>; mov r8d,<width>; call BitCopy 都可以直接读作“把 width 位放到绝对 bit dst_bit”。下面所有位置都从命名编码器中的这些立即数恢复而来。


Immediate 槽映射

目的

branch/call/sync 目标偏移和所有其他 immediate 都位于 immediate 槽中,而不是位于任何 opcode 字段中。分支的 20 位有符号目标偏移是 immediate slot 0;sequencer 槽中的 opcode 判别符只区分 absolute/relative/call。本页就是各代 bundle 页面委托说明这些位置的归宿。

SCS Bundle(32 B / 256 bit)

SparseCoreImmediatesEncoder::Encode 读取 proto 字段 a2[6]..a2[11](proto +0x18..+0x2c,即 imm_0..imm_5),并以 20 位宽度对每个字段执行 BitCopy。三代均逐字节相同:

imm slotproto 字段dst_bit(hex)dst_bit(dec)宽度
0(branch/call offset)+0x180x436720
1+0x1c0x2f4720
2+0x200x1b2720
3+0x240x07720
4+0x280xd721520
5+0x2c0xc319520

编码器地址:vfc 0x1ee75ee0glc 0x1eb563c0gfc 0x1ecd1760。slot 4 和 5(bits 215/195)出现在完整的 SparseCoreImmediatesEncoder 中;SCS branch/call 路径只使用 slots 0..3。第二个类 SparseCoreScalarImmediatesEncodergfc 0x1eb5bd20)只在同样的 bits 67/47/27/7 打包 slots 0..3,它是 gfc SCS codec template 命名的编码器。gfc SCS codec template(在 EncodeBundle 0x1e838cc0 case 3 SparseCoreScsCodecBase<…> 参数列表中确认)选择 SparseCoreScalarImmediatesEncoder,因此 0x1eb5bd20 是 SCS 分支路径实际调用的函数;完整的 SparseCoreImmediatesEncoder::Encode(slots 0..5,bits 215/195)位于 0x1ecd1760。branch/call offset(imm slot 0 = bit 67)在两个编码器之间相同。

NOTE — EncodeBundle 0x1e838cc0 专门是 6acc60406 codec dispatcher:其 default arm 报告 "EncodeBundle not implemented for sequencer type",三个有效 case 构造 gfc::isa::{TensorCore,SparseCoreScs,SparseCoreTec}CodecBase<…>。Ghostlite 有自己的 EncoderGlTensorCore::EncodeBundle0x1d331d00)。slot-walk 机制在 v5+ 中共享,但 dispatcher 符号是代特定的。

TensorCore Bundle(64 B / 512 bit)

TensorCoreImmediatesEncoder::Encode 读取 imm_0..imm_5(proto +0x18..+0x2c),并以 20 位宽度对每个字段执行 BitCopy。逐代位位置由编码器 BitCopy 字面量逐字确认:

imm slotproto 字段vxc (VF)glc (GL)gfc (GF)宽度
0(branch/call offset)+0x18430 (0x1ae)433 (0x1b1)423 (0x1a7)20
1+0x1c41041340320
2+0x2039039338320
3+0x2437037336320
4+0x2835035334320
5+0x2c33033332320

编码器地址:vxc 0x1eebee40glc 0x1f20d520gfc 0x1f86de20

逐代差异是核心事实:Ghostlite = Viperfish + 3 位(TC scalar/sequencer/immediate 区域整体 +3,为 7→8 位 opcode 扩宽腾出空间),而 6acc60406 = Viperfish − 7 位(immediate block 下移,为其上方更宽的 scalar/predicate 区域腾出空间;在 gfc 上该区域包含 bits 496..505 的专用 dual-predicate 槽)。

GOTCHA — EmitImmediate 中的 immediate slot index 是逻辑索引,不是固定 bit。slot 0 在 SCS 中是 bit 67,但在 TC 中是 bit 430/433/423。重新实现若为 "immediate slot 0" 硬编码一个 bit,会破坏每个跨 engine 分支。应根据 (engine, generation) 对解析 bit,而不是只看 slot index。


Sequencer 槽映射

目的

sequencer 槽(ScalarAlu0)承载 branch/call 判别符、call return-address(dest)sreg、branch-by-register x-target sreg 和 predication header。branch/call 目标偏移在这里,而是在 immediate slot 0。sequencer 槽是各代 bundle 页面委托到本页的位置;尤其是 TC sequencer 无法从 InstBits 中提取,因为 InstBits 为空。

判别符模型

每个 ScalarAlu0 op 写一个 opcode-HIGH 字段(宽度 6,family)和一个 opcode-LOW 字段(宽度 5,寻址判别符)。对所有 branch/call control op,opcode-HIGH = 0;标量 ALU compute op 则把自身 opcode 放在 opcode-HIGH 中(例如 CompareIntegerEq = 0x1e)。opcode-LOW 判别符值在 SCS 和 TC、所有 V5+ 代中一致:

opcode-LOWOp额外字段
4BranchAbsoluteoffset → imm slot 0
5BranchRelativeoffset → imm slot 0
6CallAbsoluteoffset → imm slot 0;dest(link)sreg → dest 字段
7CallRelativeoffset → imm slot 0;dest(link)sreg → dest 字段
4(使用 family 字段)BranchSregx-target sreg → x-target 字段
0x18 (24)BranchRelativeRotatingPregrotating-preg index → 专用字段(仅 gfc SCS)

绝对、相对和调用的分支偏移范围均为有符号 20 位(−0x80000..+0x7FFFF);abs/rel 区别纯粹是判别符值。return 不是专用 op,它是读取 link sreg 的 BranchSreg

SCS Sequencer(SparseCoreScalarAlu0Encoder::Encode

编码器写入通用 predication header,然后分派 jmp *jt[proto+0x50](上界 0x56 = 86 项)到逐 op helper。由 glc 0x1e9d2140BranchAbsolute helper 0x1e9d67c0 确认;Viperfish(vfc encoder 0x1ee82ce0BranchAbsolute helper 0x1ee873c0)逐字节相同。

字段dst_bithex宽度来源 / 写入者
predication reg index1870xbb4proto +0x20,主编码器
predication inversion1910xbf1proto +0x18(byte),主编码器
opcode-HIGH / family1810xb56逐 op helper(branch/call 为 =0)
opcode-LOW / discriminator1760xb05逐 op helper(4/5/6/7/0x18)
x-target / 2nd operand170(gfc)/ 176(vfc/glc0xaa / 0xb06 / 5BranchSreg/aux(gfc 0x1eb6dd40vfc 0x1ee87480
call dest(return-addr)sreg1650xa55CallAbsolute/CallRelative
rotating-preg index(gfc1650xa54BranchRelativeRotatingPreg

在 6acc60406(gfc encoder 0x1eb693c0)上,SCS predication 变窄:bit 187(0xbb)处 3 位 selector + bit 190(0xbe)处 inversion,与同样从 bit 187 开始的 4 位 dual-predicate index + bit 191 处 inversion 重叠。gfc BranchRelativeRotatingPreg helper(0x1eb6b9c0)在 bit 176(w5)写判别符 24,在 bit 181(w6)写 opcode-HIGH 0,在 bit 165(w4)写 rotating-preg index,并在 bit 170 写 6 位 aux。

TC Sequencer(TensorCoreScalarAlu0Encoder::Encode

该槽无法由 InstBits 容纳。由 vxc 0x1eecb900(及 helper 0x1eecf960)、glc 0x1f219b40(及 helper 0x1f21da40)和 gfc 0x1f87b420 确认。

字段vxc (VF)glc (GL)gfc (GF)
predication reg indexbit 499 w4bit 502 w4—(2 位 selector)
predication inversionbit 503 w1bit 506 w1
predication 2-bit selectorbit 489 w2
opcode-HIGH / familybit 493 w6bit 496 w6bit 483 w6
opcode-LOW / discriminatorbit 488 w5bit 491 w5bit 478 w5
x-target / 2nd operandbit 482 w6bit 485 w6bit 472 w6
call dest(return-addr)sregbit 477 w5bit 480 w5bit 467 w5

Ghostlite 将整个 TC scalar/sequencer 区域在 Viperfish 基础上上移 +3 位,与 TC immediate block 的 +3 位平移(433 vs 430)同步;整个 TC scalar/sequencer/immediate block 作为一个刚性窗口平移,以吸收 7→8 位 opcode 扩宽(glc::isa::TensorCoreScalarAlu0Encoder::Encode 0x1f219b40 及其 BranchAbsolute helper 0x1f21da40:predicate reg @ 502 而非 499,inversion @ 506 而非 503,opcode-HIGH @ 496 而非 493,opcode-LOW @ 491 而非 488,x-target aux @ 485 而非 482,call dest @ 480 而非 477)。SCS sequencer 没有平移,glc 在那里与 vxc 逐字节相同(0x1e9d2140);见 Ghostlite Bundle。6acc60406 的 TC scalar 槽最宽:它在 bit 472 增加 6 位 operand,并将逐槽 predication 缩小为 bit 489 处的 2 位 selector,而实际的 16 寄存器 predicate 池移到了专用的 TensorCorePredicates 槽。

NOTE — TC vxc x-target 跨两个不同字段。bit 488(w5)是 opcode-LOW 判别符(与 BranchSreg x-target 共享);secondary-operand / LCC-read aux 字段则是 bit 482(0x1da)处的独立 6 位字段,由 vxc 编码器主体(0x1eecb900)确认。BranchSreg 会用 x() sreg 覆盖判别符窗口,但 LCC read 同时使用 bit 488 的 5 位判别符和 bit 482 的 6 位 aux。


Predicate 槽映射 {#predicate-slot-map}

目的

确定每个 V5+ bundle 槽内 predicate 字段的确切字节偏移,即此前 predicate-field 分析留下的空白位置(当时称其“受 InstBits 控制”,而 InstBits 为空)。Viperfish/Ghostlite 的逐槽方案和 6acc60406 的专用 dual-predicate 槽模型不同。

Viperfish / Ghostlite:逐槽 4+1 字段

每个已填充的 functional 槽都携带自己的 predicate:4 位寄存器索引加 1 位 inversion(encodePredicateOperand 布局的 2 位扩展是该字段高端,在非 rotating 代码中为 0)。在 scalar 槽顶部:

reg indexinversion编码器
TC ScalarAlu0vxcbit 499 w4bit 503 w10x1eecb900
TC ScalarAlu0glcbit 502 w4bit 506 w10x1f219b40
SCS ScalarAlu0glc/vfcbit 187 w4bit 191 w10x1e9d2140 / 0x1ee82ce0

6acc60406:专用 Dual-Predicate 槽

TensorCorePredicatesEncoder::Encodegfc 0x1f86e500)把两个每 bundle predicate 写入 64 字节 TC bundle 的最顶部;随后每个 functional 槽只携带 2 位 selector,在 {pred_0, pred_1, always, never} 中选择:

字段dst_bithex宽度proto src
pred_0 reg5010x1f54msg word
pred_0 inversion5050x1f91msg +0x20(byte)
pred_1 reg4960x1f04msg word
pred_1 inversion5000x1f41msg +0x21(byte)

16 寄存器 predicate 池(PredicationSlot 枚举 0..15)被编码进 pred_0/pred_1;逐槽 2 位 selector 对该池建立索引。"predication overflow — both predicate slots already taken" 条件正是 bits 496..505 中这两个 4 位 (reg, inversion) 条目已满的状态。2 位 selector 的具体值到 {pred_0,pred_1,always,never} 的映射尚未解码(selector 自己的跳转表未遍历);selector 字段偏移已确认(值语义 LOW confidence)。


Compute 槽:MXU、Result、EUP

目的

MXU matmul/push/latch(VectorExtended)、matres/EUP pop(VectorResult)和 transcendental push(VALU slot 3)都来自同一套 <Slot>Encoder::Encode + BitCopy 机制。它们在 MXU SlotVPU SlotEUP/Transcendental Slot 中完整记录;绝对位位置在这里汇总。

MXU VectorExtended

两个 MXU 槽(VectorExtended0VectorExtended1),每个物理矩阵单元一个。这两个槽共享 source-vreg(systolic-feed)区域,但在 6acc60406 上,opcode/control 区域相差一个 25 位槽步长。opcode 字段跨代从 7 位扩宽到 8 位,与 VALU 槽一致。由 gfc MatrixMultiplyBf16 0x1f99a920 确认:

字段vxcglcgfc VEx0gfc VEx1
MXU-id(unit)[proto +0x1c]bit 64 w4bit 66 w4bit 70 w2bit 45 w2
opcode-HIGHbit 57 w7bit 58 w8bit 62 w8bit 37 w8
data-format sub-discbit 51 w4bit 52 w4bit 57 w4bit 32 w4
done-gains/latch flagbit 55 w2bit 56 w1bit 61 w1bit 36 w1
control(3 位)bit 48 w3bit 49 w3bit 54 w3bit 29 w3
primary operandbit 180 w6bit 183 w6bit 47 w7bit 22 w7
src vregs(8 × 6 位,gfc156/276/287/243/254/210/221/177(相同)
opcode bound(#ops)0x66 (103)0x70 (113)0x54 (85)0x54 (85)

编码器地址:vxc 0x1efa0f60glc 0x1f32fd00gfc VEx0 0x1f996940 / VEx1 0x1f9d3800。weight latch 是 LoadMatrixRegister{Gmr,Lmr}{Msra,Msrb}gfc 上 opcode-HIGH 0x37,0x1f9a04a0);moving-operand push 是 PushMatrix{fmt}(opcode-HIGH 0xe)。8 个 source-vreg 字段在 VEx0 和 VEx1 之间逐字节相同,这一编码事实表明两个 MXU 从同一组 vector read port 取数。

VectorResult 槽(matres pop / EUP pop)

VectorResult0Encoder::Encode 读取 result-type 判别符(proto +0x1c),分派 jmp *jt[proto+0x50],设置逐 result-type 子消息 present tag,然后在公共尾部用 BitCopy 写 dest vreg。由 gfc 0x1fa01820 确认:

字段vxcglcgfc
result-type discriminatorbit 24 w4bit 24 w4bit 20 w2
dest vregbit 14 w6bit 14 w6bit 11 w6
PopMxu accum-mode/format(按 +0x1c)(按 +0x1c)bit 323 w8
result-opcode bound0x8 (9)0x8 (9)0x7 (8)

matres-pop opcode 在所有代上都是 6(PopMxuResult),EUP-pop opcode 都是 7(PopEupResult)。Ghostlite 增加了 PopAddMxu01Result(融合 matres+accumulate,K>128 多 pass);Viperfish 增加了 PopCcrfResult(scalar/CRF pop)。result 槽自身的 predication 字段访问器是 TensorCoreVectorResult1PredicationField::GetConcatenatedValuegfc 0x1fa02520);其确切 bit 未单独遍历(相邻的 result-mode/format 字段 bits 17..21 已解码)。

EUP / Transcendental Push:VALU Slot 3

在所有 V5+ 代上,transcendental push 都是 VALU slot-3(Alu3)op,而不是 VectorExtended op;这一点由 EUP helper 只存在于 Alu3 集合中确认。VALU opcode 字段选择 EUP-push 家族(值 0x0);5 位 EUP-function selector 选择具体 transcendental。由 gfc F32Tanh 0x1f96ae40 确认:

字段vxcglcgfc
VALU opcode(EUP-push family = 0x0)bit 197 w7bit 194 w8bit 194 w8
EUP-function selectorbit 186 w5bit 183 w5bit 183 w5
src vreg(slot-3)bit 188 w6bit 188 w6

gfc 5 位 function selector 值映射(VALU op = 0x0,selector @ bit 183)由逐 helper 确认:

functionF32 selectorBf16 selector
Erf0x0e0x0f
ReciprocalSqrt0x100x0c
PowTwo (2^x)0x110x19
LogTwo (log2)0x120x1a
Tanh0x130x1b
ShiftedSigmoid0x140x1c
Reciprocal0x150x1d
Sinq (sin)0x170x1e
Cosq (cos)0x180x1f

push-pop 协议是位精确的:bundle N 中的 PUSH 是上述 VALU slot-3 op;bundle N+k 中的 POP 是 result-opcode 7(PopEupResult)的 VectorResult op,dest vreg 位于 bit 11(gfc)。XLU 是 single-issue,因此只有 VALU slot 3 能发起 EUP push。


逐 (Slot, Generation) 绝对位位置表

这是各代 bundle 页面引用的汇总参考。所有位置均为 bit <n> w<width>;bit 0 = byte 0 的 LSB。

SCS Bundle(32 B / 256 bit)

slot / 字段vfc (VF)glc (GL)gfc (GF)
branch/call offset(imm 0)67 w2067 w2067 w20
imm slot 147 w2047 w2047 w20
imm slot 227 w2027 w2027 w20
imm slot 37 w207 w207 w20
seq opcode-HIGH181 w6181 w6181 w6
seq opcode-LOW(discriminator)176 w5176 w5176 w5
seq x-target / 2nd operand176 w5176 w5170 w6
seq call dest sreg165 w5165 w5165 w5
seq predicate reg187 w4187 w4187 w3(selector)/ w4(dual)
seq predicate inversion191 w1191 w1190 w1
rotating-preg index165 w4

TensorCore Bundle(64 B / 512 bit)

slot / 字段vxc (VF)glc (GL)gfc (GF)
branch/call offset(imm 0)430 w20433 w20423 w20
imm slots 1..5410/390/370/350/330413/393/373/353/333403/383/363/343/323
seq opcode-HIGH493 w6496 w6483 w6
seq opcode-LOW(discriminator)488 w5491 w5478 w5
seq x-target / 2nd operand(aux)482 w6485 w6472 w6
seq call dest sreg477 w5480 w5467 w5
seq per-slot predicatereg 499 w4 + inv 503 w1reg 502 w4 + inv 506 w12-bit selector @ 489
dual predicate pred_0reg 501 w4 + inv 505 w1
dual predicate pred_1reg 496 w4 + inv 500 w1
MXU opcode-HIGH(VEx0)57 w758 w862 w8
MXU data-format sub-disc51 w452 w457 w4
MXU-id(unit)64 w466 w470 w2
VectorResult discriminator24 w424 w420 w2
VectorResult dest vreg14 w614 w611 w6
EUP-push VALU opcode(Alu3)197 w7194 w8194 w8
EUP-function selector186 w5183 w5183 w5

逐代差异一句话概括:Ghostlite 将整个 TC scalar/sequencer/immediate 窗口上移 +3 位(immediate slot 0 bit 430 → 433;sequencer opcode-HIGH 493 → 496),作为一个刚性块吸收 7→8 位 opcode 扩宽;6acc60406 将 TC immediate block 下移 −7 位(bit 430 → 423),并把 scalar/sequencer 区域下移,为 bits 496..505 的专用 dual-predicate 槽和 bit 472 处更宽的 scalar operand 腾出空间。


Delay-Slot 和 Loop 说明

标准 LLVM-MC 思维模型预期会被编码的两个字段,在 V5+ 上不是 bundle 内位字段:

  • Delay-slot count。 没有任何 V5+ branch/call helper(Ghostlite、Viperfish 或 6acc60406)会发出 delay_slots BitCopy。branch/call helper 只写 {opcode-HIGH, opcode-LOW, offset (imm 0), dest}。delay-slot count 是 bundle-packer pad count(在分支之后追加的空 bundle),由 packer 上的 LLVM-MC verifier bound(delay_slots <= 5)门控,而不是编码后的槽字段。
  • Hardware-loop length。 V5+ 没有 hardware-loop setup 槽位字段。loop 是 LCC 硬件计数器读取(ReadRegisterLccLow/High,sequencer-slot opcode 位于 bit 181 + dst 位于 bit 176)馈入条件 BranchRelative。所谓“loop counter”是寄存器,而不是编码后的 loop-length 字段。

GOTCHA — 重新实现如果在 bundle 内分配 3 位 delay-slot 字段(像 BarnaCore 风格 v4 布局那样),会让后续每个字段都失步。在 V5+ 上,分支的 dest 字段之后的下一批 bit 属于下一个槽,而不是 delay count。


交叉引用