Pack/Unpack 精度
本页中的所有地址适用于来自
libtpu-0.0.40-cp314wheel 的libtpu.so(build-id89edbbe81c5b328a958fe628a9f2207d,781,691,048 bytes,未 strip)。.text和.rodataVMA 等于其 file offset;.data.rel.roVMA 减去0x200000等于其 file offset。其他 libtpu build 会有所不同。
摘要
这是 XLU 的 precision-conversion datapath:一族 LLO op,用于在 f32 与窄 16-bit 格式(bf16)之间移动数据;bf16 在 vector register 内部以 每 lane 打包两个 的形式存在。此外还包括每 segment 的 cross-lane reduction,它消费一个已打包并拓宽的 embedding tensor。这里存在两种不同的硬件机制,二进制把它们放在不同的 factory chain 上,重新实现者不能混淆。
第一种是 lane pack/unpack。bf16 与 IEEE f32 的 高 16 bit 完全 bit-identical,因此一个 2 元素 bf16 vector 可以放进一个 32-bit lane,而 f32 widen 只是位置移动并补零,不需要算术 rounding。VpackBf16 把两个 bf16 vreg interleave 到一个 packed lane(kVectorPack 0x126,VpackFormat = 7 InterleavedBf16);反向的 VunpackUpperCF32 / VunpackLowerCF32 选出其中一个 bf16 half(kVectorUnpack 0x109,CompressedBf16,带有 uint upper/lower index);组合式的 VunpackF32 则通过 把 low lane 左移 16 并 把 high lane mask 到 0xffff0000,把两个 half 拓宽为完整 f32。format 和 unpack sub-lane index 被打包进 +0x40 处的一个 64-bit instruction word。这就是 EUP AluEp UnpackFOp/PackFOp 最终降低到的 LLO 层级(见 EUP / Transcendental Slot)。
第二种是 segmented reduction(每 segment 的 cross-lane reduce)。三个仅 F32 的 opcode:kVector{Max,Min,Add}SegmentReduceF32 0xfa/0xfb/0xfc,会在 lane segment 内部 reduce;segment 边界由一个单独的 kVectorSetSegmentPattern(0x8c)op 编程,该 op 由 Vsetspr 构建。它是 embedding segment-sum 的 TensorCore 类比:accumulator 在 pattern register 标记的每个 segment boundary 处重置。RPU re-emit pass 会通过共享一个 pattern setup 来 fuse 一对 segment reduce。在 device codegen 路径上,这是仅 Jellyfish/Pufferfish 支持的 primitive;Viperfish 和 Ghostlite 的 SupportsSegmentedReduce 返回 false,其 TensorCore emitter 是不可达的 LogFatal stub,因为这些 generation 上每 segment 的 embedding reduce 已经移到 SparseCore。
对重新实现而言,契约是:
- bf16 pack:
VpackBf16→kVectorPack 0x126,两个 operand,VpackFormat = 7 InterleavedBf16,由SupportsVectorPackOps(7)gate。 - bf16 unpack:
Vunpack{Upper,Lower}CF32→kVectorUnpack 0x109,一个 operand,VpackFormat = 1 CompressedBf16,uintindex1(upper)/0(lower),由SupportsVectorUnpackOpsgate。 - f32 widen:
VunpackF32 = { CastTo(f32, lower<<16), CastTo(f32, upper&0xffff0000) }。 +0x40处的 instruction-word format field:VpackFormat位于 bits 0-15,sub-lane/unpack index 位于 bits 16-31,并带有各 opcode class 的 has-value / fan-in 检查。- segment-reduce opcode 集合
{0xfa,0xfb,0xfc}(仅 F32)、kVectorSetSegmentPattern 0x8cboundary program、RPU shared-pattern dispatch、per-gen VEX-opcode map,以及仅 JF/PF 支持的 gate。
| bf16 pack | VpackBf16 (0x1d554680) → VpackBf16Inst (0x1d565940) → CreateVectorPack (0x1d4d3140) → kVectorPack 0x126, InterleavedBf16 (7) |
| bf16 unpack | Vunpack{Upper,Lower}CF32 (0x1d567f20/0x1d567e20) → CreateVectorUnpack (0x1d4d37c0) → kVectorUnpack 0x109, CompressedBf16 (1), index 1/0 |
| f32 widen | VunpackF32 (0x1d554620); lower <<16 (SimplifyShllU32), upper &0xffff0000 (SimplifyAndU32) |
| Format word | set_pack_format_sublane (0x1d4d3440) → WORD[instr+0x40] bits 0-15 = VpackFormat, bits 16-31 = sub-lane index |
| Segment reduce | kVector{Max,Min,Add}SegmentReduceF32 0xfa/0xfb/0xfc(仅 F32);LloOpcodeIsSegmentedReduction (0x1d60c340) = (op-0xfa)<3 |
| Segment pattern | Vsetspr (0x1d52ba60) → CreateVectorSetSegmentPattern (0x1d4d64a0) → kVectorSetSegmentPattern 0x8c(无 mode field) |
| Segment-reduce 支持 | 仅 JF / PF;VF / GL SupportsSegmentedReduce = false,TC emitter 是 LogFatal |
bf16 Pack:InterleavedBf16,两个 Lane 合成一个
目的
重新实现者的入口点是“两个 bf16 vreg → 一个 packed f32-width vreg”。这是 EUP/XLU pipeline 移动 bf16 reduction 所用的格式,因为要用 f32 reduce 一个 packed embedding row,必须先将其拓宽(下一节),而把结果存为 bf16 又需要重新 pack。
算法
VpackBf16(a, b)(0x1d554680)先做 peephole front,然后 tail-call 到真正的 factory:
function VpackBf16(a, b): // 0x1d554680
folded = SimplifyPackF16(a, b, RegisterType=4) // 0x1d599360, const-fold two bf16 constants
if folded: return folded
return VpackBf16Inst(a, b) // 0x1d565940 (tail)
function VpackBf16Inst(a, b): // 0x1d565940
target = this->module->target // *(this+56)->+16
if not target->vtable[+0x4c8](7): // SupportsVectorPackOps(format=7)
UpdateStatus("target().SupportsVectorPackOps(format)") // llo_region_builder.cc:13132
inst = CreateVectorPack(0x126, 7, a, b, region) // 0x1d4d3140
return region->AppendInstruction(inst)
```text
反编译显示,`VpackBf16Inst` 在 gate `(*(…+1224))(v7, 7)` 之后调用 `CreateVectorPack(294, 7u, …)`;其中 `294` = `0x126` = `kVectorPack`,format `7` = `InterleavedBf16`,`1224` = `0x4c8` 是 target sub-object vtable 中 `SupportsVectorPackOps` 的 slot。`CreateVectorPack`(`0x1d4d3140`)构建一个双 operand 的 `New(0x126, {a,b})`,并调用 `set_pack_format_sublane(7, nullopt)`。
> **NOTE —** bf16 pair-pack **不是** `kVectorWeird`(`0xae`)。`0xae` op 是 *另一个单 operand* 的 `VweirdBf16` factory(`0x1d5546e0` → `CreateVectorWeird` `0x1d4d4e20`),是一个 single-input cross-lane op,由 `SupportsBf16AluInstructions`(vtable `+0x780`)gate;反编译向 `CreateVectorWeird` 传入固定的 result `PrimitiveType` `0x10`(F16),后者构建 `New(0xae, {in}, 1)`。二者不共享 factory。
### 函数映射
| Function | Address | 作用 |
|---|---|---|
| `LloRegionBuilder::VpackBf16` | `0x1d554680` | Peephole + tail-call entry |
| `LloRegionBuilder::VpackBf16Inst` | `0x1d565940` | Gate + emit `0x126` |
| `LloInstruction::CreateVectorPack` | `0x1d4d3140` | `New(0x126, {a,b})` + format |
| `llo_simplifier::SimplifyPackF16` | `0x1d599360` | Constant-fold 两个 bf16 |
| `LloRegionBuilder::VweirdBf16` | `0x1d5546e0` | 独立的 1-op `0xae` factory |
---
## bf16 Unpack:带 Upper/Lower Index 的 CompressedBf16
### 目的
pack 的反向操作:从一个 packed lane 中取回两个 bf16 half 之一。CF32 形式把结果保留在 compressed(16-bit-lane)域;F32 形式(下一节)把它拓宽为完整 32-bit float。
### 算法
```c
function VunpackUpperCF32(in): // 0x1d567f20
folded = SimplifyUnpack(index=1, format=1, in, 0) // 0x1d593060
if folded: return folded
target = this->module->target
if not target->vtable[+0x4d8](1, 0): // SupportsVectorUnpackOps(format=1, TpuCoreType=0)
UpdateStatus("target().SupportsVectorUnpackOps(format)") // llo_region_builder.cc:13740
inst = CreateVectorUnpack(0x109, index=1, format=1, in, region) // 0x1d4d37c0
return region->AppendInstruction(inst)
function VunpackLowerCF32(in): // 0x1d567e20
// identical, index = 0; llo_region_builder.cc:13730反编译非常明确:VunpackUpperCF32 调用 CreateVectorUnpack(0x109u, 1, 1u, …),VunpackLowerCF32 调用 CreateVectorUnpack(0x109u, 0, 1u, …);opcode 0x109(kVectorUnpack),index 1/0,format 1(CompressedBf16)。gate vtable slot +0x4d8(1240)是 SupportsVectorUnpackOps,调用参数为 (1, 0)。Upper = index 1,lower = index 0。
CreateVectorUnpack(0x1d4d37c0)构建一个单 operand 的 New(0x109, {in}),并调用 set_pack_format_sublane(format, index | engaged);index 被折入 sub-lane field(下一节)。
bf16 unpack opcode 是 0x109 kVectorUnpack,不同于 0x10f kVectorDynamicUnpack。0x10f 是单独的 CreateVectorDynamicUnpack(0x1d4d3d80),由 SupportsDynamicUnpackOps(vtable +0x4e0,在 Viperfish 上为 false)gate。相邻的 sub-byte unpack kVectorUnpackAndJoinB2ToB4/B4ToB8(0x10a-0x10d)以及 kVectorUnpackEXMY(0x10e)又是不同的 opcode。
函数映射
| Function | Address | Emits |
|---|---|---|
LloRegionBuilder::VunpackUpperCF32 | 0x1d567f20 | 0x109, idx 1, fmt 1 |
LloRegionBuilder::VunpackLowerCF32 | 0x1d567e20 | 0x109, idx 0, fmt 1 |
LloInstruction::CreateVectorUnpack | 0x1d4d37c0 | New(0x109, {in}) + format |
LloInstruction::CreateVectorDynamicUnpack | 0x1d4d3d80 | 0x10f(单独路径) |
llo_simplifier::SimplifyUnpack | 0x1d593060 | Const-fold peephole |
f32 Widen:低 Lane 移位,高 Lane Mask
目的
bf16 是 f32 的高 16 bit。因此 widen 不需要 rounding,只需要重新定位。VunpackF32 从一个 packed bf16 vreg 生成 一对 widened f32 lane。
算法
function VunpackF32(in): // 0x1d554620
lo = CastTo(f32 /*0x12*/, VunpackLowerF32(in)) // 0x1d528660
hi = CastTo(f32 /*0x12*/, VunpackUpperF32(in)) // 0x1d528580
return { lo, hi } // composite pair
function VunpackLowerF32(in): // 0x1d528660
u = CreateVectorUnpack(0x109, index=0, format=7 /*InterleavedBf16*/, in)
return SimplifyShllU32(u, VectorU32Constant(16)) // 0x1d58f8a0 : low bf16 -> high 16 of f32, low 16 = 0
function VunpackUpperF32(in): // 0x1d528580
u = CreateVectorUnpack(0x109, index=1, format=7, in)
return SimplifyAndU32(VectorU32Constant(0xffff0000), u) // 0x1d58dac0 : high bf16 already in place, mask low 16
```text
反编译确认了每一步:`VunpackLowerF32` 构建 `VectorU32Constant(0x10)` 并调用 `SimplifyShllU32`(左移 16);`VunpackUpperF32` 构建 `VectorU32Constant(0xFFFF0000)` 并调用 `SimplifyAndU32`(mask)。lower lane 的 16 个 bf16 bit 成为一个 f32 的高半部分,低 16 位为 0;upper lane 已经位于高半部分,因此只需干净地 mask。结果是精确的,`pack`/`unpack` round-trip 保持 bit 不变(`bf16` 是 f32 的高半)。
> **NOTE —** `VunpackF32` family 使用 `VpackFormat = 7 InterleavedBf16`(*interleaved* layout,fan-in 2)进行 widen,而 CF32 family 使用 `VpackFormat = 1 CompressedBf16`。format 选择两个 bf16 lane 在 source word 中如何布局;widen 算术(shift/mask)在两种情况下相同。
---
## Instruction-Word Format Field(`+0x40`)
### 目的
pack 和 unpack 都把其 format(以及 unpack 的 sub-lane index)存进 LLO instruction 的一个 64-bit field 中。编码这些 op 的重新实现者必须复现 bit layout 和 per-opcode validity check。
### 编码
`set_pack_format_sublane(VpackFormat fmt, optional<u16> sublane)`(`0x1d4d3440`)写入 `QWORD[instr+0x40]`。反编译按 opcode switch:
```c
function set_pack_format_sublane(instr, fmt, sublane): // 0x1d4d3440
switch instr.opcode:
case 0x109, 0x10E: // unpack / unpackEXMY -> sublane REQUIRED
assert sublane.has_value() // llo_instruction.cc:3714
assert *sublane < VpackFormatSublanesIndices(fmt) // :3715 (index < lane fan-in)
word = (word & ~0xFFFF0000) | (sublane << 16)
case 0x10F, 0x126: // dynamic-unpack / pack -> sublane FORBIDDEN
assert not sublane.has_value() // llo_instruction.cc:3723
default:
LogFatal("unexpected instruction: <opcode>") // :3726
word = (word & ~0xFFFF) | fmt // VpackFormat in bits 0-15
instr[+0x40] = word因此 bits 0-15 = VpackFormat,bits 16-31 = sub-lane/unpack index。unpack opcode(0x109、0x10e)要求 有 sub-lane index,并检查它低于该 format 的 lane fan-in;pack opcode(0x126、0x10f)禁止 带 sub-lane index。VpackFormatSublanesIndices(fmt)(0x1d629d60)是一行 return dword_B53C790[fmt],直接索引位于 0xb53c790 的 .rodata i32 表;该表给出 fan into one packed slot 的 source lane 数量(每种 format 为 2 或 4)。
VpackFormat(选定值)
VpackFormat enum 名称来自 VpackFormatString(0x1d629960)。直接位于 bf16↔f32 datapath 上的值如下:
| Value | Name | Lane fan-in | 作用 |
|---|---|---|---|
| 0 | (invalid) | — | Sentinel / unset |
| 1 | CompressedBf16 | 2 | CF32 unpack source |
| 7 | InterleavedBf16 | 2 | VpackBf16 pack format;VunpackF32 widen |
| 11 | CompressedHf16 | 2 | f16 (half) compressed |
| 19-22 | Compressed{U8,S8,U4,S4}ToBf16 | 2 / 4 | int→bf16 dequant(embedding quant) |
完整的 26-entry enum 一直扩展到 fp8(F8E5M2/F8E4M3*)和 sub-byte dequant format;这些属于 quant pack/unpack 路径的领域。见 Bias-Add & Quant/Dequant Helpers。
各代 Pack/Unpack Capability Mask
target 的 +0x10 sub-object 上的 gate vtable slot(+0x4c8 pack、+0x4d8 unpack、+0x4e0 dynamic-unpack)是逐字节精确的 bitmask predicate:
| Target / method | Address | Predicate | Supported formats |
|---|---|---|---|
ViperfishTarget::SupportsVectorPackOps | 0x1d49b1a0 | (fmt-1) < 0xA | 1..10 |
ViperfishTarget::SupportsVectorUnpackOps | 0x1d49b1c0 | fmt < 0xE && (0x39FE >> fmt)&1 | 1,2,3,4,5,6,7,8,11,12,13 |
GhostliteTarget::SupportsVectorPackOps | 0x1d498020 | fmt < 0x17 && (0x7807FE >> fmt)&1 | 1..10, 19..22 |
GhostliteTarget::SupportsVectorUnpackOps | 0x1d498040 | fmt < 0x17 && (0x7839FE >> fmt)&1 | 1..13, 19..22 |
InterleavedBf16(7)位于两个 generation 的 pack set 中,CompressedBf16(1)位于两个 generation 的 unpack set 中,因此 bf16↔f32 datapath 普遍可用;Ghostlite 还允许 U8/S8/U4/S4→bf16 dequant pack format(embedding quantization)。
Segmented Reduction:每 Segment 的 Cross-Lane Reduce
目的
segment reduce 是一种 embedding 风格的聚合:vreg 的 lane 被划分为 segment,reduce 为每个 segment 产生一个 accumulator,并在每个边界处重置。边界 pattern 由一个单独的 op 提供。重新实现者必须把它建模为一个 two-op 序列:先设置 pattern,再依据它执行 reduce。
算法
opcode 集合恰好有三个,且仅 F32:
bool LloOpcodeIsSegmentedReduction(op): // 0x1d60c340
return (uint16)(op - 0xfa) < 3 // {0xfa, 0xfb, 0xfc}
```text
- `0xfa` `kVectorMaxSegmentReduceF32`
- `0xfb` `kVectorMinSegmentReduceF32`
- `0xfc` `kVectorAddSegmentReduceF32`
没有 **bf16 segment reduce**:周围的 reduce family 是 `0xf5`-`0xf9`(普通 F32 Min/Max/Add/MaxIndex/MinIndex),然后是 `0xfa`-`0xfc`(F32 segment),再之后是 `0xfd`-`0x101`(普通 bf16 reduce);`0x102`(`kVectorSublaneId`)是下一个非 reduce op。
boundary register 由 `Vsetspr` 编程:
```c
function Vsetspr(pattern_src, xlu, source_bus): // 0x1d52ba60
inst = CreateVectorSetSegmentPattern(pattern_src, xlu, source_bus, region) // 0x1d4d64a0
return region->AppendInstruction(inst)
function CreateVectorSetSegmentPattern(pattern, xlu, bus, region): // 0x1d4d64a0
assert opcode_produced_register_type[pattern.opcode] == 4 // "pattern->ProducesVreg()", llo_instruction.cc:918
inst = New(0x8c /*kVectorSetSegmentPattern*/, {pattern}) // one operand
ValidateAndSetXluAndSourceBus(xlu, bus, inst) // XLU index -> WORD[instr+0xb]
set_annotation(inst)
return instCreateVectorSetSegmentPattern(0x1d4d64a0)断言 pattern source ProducesVreg()(opcode_produced_register_type == 4),构建单 operand 的 New(0x8c, {pattern}),并通过 ValidateAndSetXluAndSourceBus(0x1d4d5180:bits 8-9 = xlu & 3,bit 10 0x400 = XLU-op flag)把 XLU/source-bus 写入 WORD[instr+0xb]。
NOTE —
kVectorSetSegmentPattern(0x8c)不携带 任何 mode field,这不同于它的 siblingkVectorSetPermutePattern(0x8b),后者在DWORD[instr+0x40]存储一个SetPermuteMode({one_sublane=0, one_sublanes=1})。segment pattern 是一个纯粹的 per-lane segment-boundary program;permute pattern 还会选择 permute granularity。见 XLU Op Roster。
RPU Re-emit:共享一个 Pattern Setup
目的
reorder/pipeline(RPU)re-emit pass 会 fuse 相邻的 XLU reduce,使一 对 segment reduce 共享一个 Vsetspr pattern setup,也就是每 segment cross-lane reduce 的节约方式。重新实现者的 scheduler 必须复制这种 fusion,才能匹配发出的 bundle stream。
算法
ReemitReorderedCombinedXluOperations 在 per-XLU state record 中为每个 XLU 缓存一个 pattern result,然后把 fused reduce operand 重连到它上面:
// per source producer:
if producer is SetPermutePattern (0x8b):
Vsetperm(mode = variant[+0x40], xlu = rpu[+0x20]); cache -> PerXluState[+0x08]
if producer is SetSegmentPattern (0x8c):
Vsetspr(xlu = rpu[+0x20]); cache -> PerXluState[+0x18]
// reduce body:
if LloOpcodeIsSegmentedReduction(op): // segment path
ReplaceOperandIn(op_a, shared_segment_result) // DOUBLE rewire ...
ReplaceOperandIn(op_b, shared_segment_result) // ... both fused operands
else: // plain reduce path
ReplaceOperandIn(op, shared_permute_result) // single rewire
PopInstruction(); AppendInstruction() // re-home both ops
```text
segment path 会执行 **两次** `ReplaceOperandIn`(两个 fused-reduce source operand 都重连到共享的 `Vsetspr` segment-pattern result 上);plain reduce path 则把单个 operand 重连到共享的 `Vsetperm` permute result 上。这就是同一 XLU 上两个 segment reduce 如何折叠为一个 pattern program 加两个 reduce。
---
## 各代 TensorCore Emit 与支持
### 目的
LLO segment op 会映射到 TensorCore bundle 可理解的 VEX-control opcode,但仅限 Jellyfish 和 Pufferfish。面向 Viperfish 或更新 generation 的重新实现者,必须改为把 per-segment embedding reduction 路由到 SparseCore。
### 编码
`JellyfishEmitter::EmitVectorSegmentedReduce`(`0x140b6c80`)把 LLO opcode 映射到一个 VEX opcode,并通过 `EmitVectorExtendedInstruction` 发出(一个 `Vregno` data operand,被调度进一个 VEX bundle slot):
```c
function EmitVectorSegmentedReduce(op, src, trf_id): // 0x140b6c80
CHECK(trf_id == 0) // jellyfish_emitter.cc:1248
switch op:
case 0xfa: vex = 0x1f // kVectorMaxSegmentReduceF32
case 0xfb: vex = 0x20 // kVectorMinSegmentReduceF32
case 0xfc: vex = 0x1e // kVectorAddSegmentReduceF32
default: NoteError("unhandled opcode for vector segmented reduce: %s")
EmitVectorExtendedInstruction(this, vex, src, 0)
function EmitVectorSetSegmentPattern(src, spr_id): // 0x140b58e0
CHECK(spr_id == 0) // jellyfish_emitter.cc:1027
EmitVectorExtendedInstruction(this, 0xe, src, 0) // VEX opcode 0xe反编译确认了字面 VEX 值:0xfa→0x1f(31)、0xfb→0x20(32)、0xfc→0x1e(30)、SetSegmentPattern→0xe(14)。普通 reduce family 0xf5-0xf9 映射到 VEX {0x16,0x15,0x14,0x17,0x18}(一个独立的 cross-lane-reduce emitter)。.rodata 中的 .seg.perm cross-lane mnemonic(vadd.xlane.seg.perm、vmax.xlane.seg.perm、vmin.xlane.seg.perm)确认了 segment-pattern-driven reduce 语义。
| LLO opcode | Name | JF VEX opcode |
|---|---|---|
0x8c | kVectorSetSegmentPattern | 0xe |
0xfc | kVectorAddSegmentReduceF32 | 0x1e |
0xfa | kVectorMaxSegmentReduceF32 | 0x1f |
0xfb | kVectorMinSegmentReduceF32 | 0x20 |
仅 JF/PF 支持的 Gate
SupportsSegmentedReduce 是每个 target 上一行 predicate:
| Target | Address | Returns | TC emitter behaviour |
|---|---|---|---|
JellyfishTarget | 0x1d4909c0 | 1 (true) | Emits VEX 0xe/0x1e/0x1f/0x20 |
PufferfishTarget | 0x1d494f80 | 1 (true) | Emits(无 partial-result drain — SupportsSegmentedReducePartialResults false) |
ViperfishTarget | 0x1d49b380 | 0 (false) | LogFatal "Operation not supported." |
GhostliteTarget | 0x1d4981c0 | 0 (false) | LogFatal "Operation not supported on Ghostlite." |
Viperfish(ViperfishTensorCoreEmitter::EmitVectorSegmentedReduce 0x141dd2c0)和 Ghostlite(GhostliteTensorCoreEmitter::EmitVectorSegmentedReduce 0x1429ff60)的 TensorCore segment-reduce emitter 都是 __noreturn LogMessageFatal stub。在这些 generation 上,per-segment embedding aggregation 运行在 SparseCore VectorExtended unit 上,而不是 TensorCore XLU;segment-reduce 已成为 JF/PF legacy primitive。
示例:用 f32 Reduce 一个 Packed bf16 Embedding Row
一个 bf16 embedding tensor 以 two-bf16-per-32-bit-lane (InterleavedBf16) 形式存在。若要用 f32 reduce:
1. WIDEN VunpackF32(packed) -> { CastTo(f32, VunpackLowerF32), CastTo(f32, VunpackUpperF32) }
lower: kVectorUnpack(0x109, idx0, fmt7) -> <<16 (low bf16 -> high 16 of f32)
upper: kVectorUnpack(0x109, idx1, fmt7) -> &0xffff0000
2. REDUCE (JF/PF) Vsetspr -> kVectorSetSegmentPattern(0x8c) 对 per-lane boundary 编程;
kVectorAddSegmentReduceF32(0xfc -> VEX 0x1e) 对每个 segment 求和,并在 boundary 处重置。
同一 XLU 上的第二个 reduce 会共享这一个 Vsetspr(RPU double ReplaceOperandIn)。
3. RE-PACK VpackBf16(lo, hi) -> kVectorPack(0x126, InterleavedBf16) interleave f32 half,
回到一个 packed bf16 lane 以便存储。
在 Viperfish/Ghostlite 上,step 2 没有 TensorCore 路径:segment reduce 运行在 SparseCore 上。
```text
---
## 尚未解码的内容
- 精确的中间 `VpackFormat` enum index(`CompressedB8/B4/B2/B1` 分支,以及 fp8/sub-byte dequant 分支 12-25)在 `VpackFormatString` 中已有命名;但这里没有固定它们各分支的 byte-overlap offset。
- dequant format(12-25)的 `VpackFormatSublanesIndices` fan-in 语义:已经 dump 出 `2`/`4` 表值,但没有按 format 区分 `4` 是指“每 slot 4 个 sub-byte element”还是“4-bit element width”。
- segment-reduce / SetSegmentPattern op 落入的 per-gen VEX *bundle slot*(`EmitVectorExtendedInstruction` 通过 `CurrentBundle`/`GetPopulatedSlots`/`FindFreeSlot` 调度)。
- `VectorExtendedOpcode` proto enum 的每个值对应的 *symbolic name*(descriptor `0x1fa1fd00`):这里列出了 VEX 值,但没有从 serialized FileDescriptor 中拉取 proto member name。
- 发出 `SetSegmentPattern` + `SegmentReduce` 对的 host-side embedding lowering(HLO segment-sum 的 offset 如何成为 segment-id pattern source)。
---
## 交叉引用
- [VPU (Vector-ALU) Slot](slot-vpu.md) — 承载 `vpack`/`vunpack` opcode immediate 和 convert family 的 VALU slot。
- [EUP / Transcendental Slot](slot-eup-transcendental.md) — 这些 LLO op 降低自的 `AluEp` `UnpackFOp`/`PackFOp` 与 `SupportsBf16AluInstructions` lane-width model。
- [XLU Op Roster](xlu-op-roster.md) — `Vsetperm`/`Vsetspr` set-pattern factory 以及 permute-vs-segment 区别。
- [Bias-Add & Quant/Dequant Helpers](bias-quantization-helpers.md) — fp8/int8 pack format(12-25)以及共享 `set_pack_format_sublane` 的 quant pack/unpack helper。
- [Bundle Model](bundle-model-overview.md) — VEX-control segment op 所调度进入的各代 VLIW bundle。