Skip to content

XLU 操作清单

本页中的每个 opcode、地址、偏移、位位置和立即数,都是从 libtpu-0.0.40-cp314 wheel 中的 libtpu.so 按字节精确读取的(BuildID md5 89edbbe81c5b328a958fe628a9f2207d,781,691,048 字节,未 strip —— 完整 C++ 符号,nm -C 可解析每个方法)。.text.rodata VMA 等于其文件偏移;.data.rel.ro VMA − 0x200000 = 文件偏移。其他 libtpu 构建会有所不同。

摘要

XLU(Cross-Lane Unit,跨 lane 单元)是 TensorCore 中跨 lane 移动数据的引擎,也是 otherwise per-lane 的向量结构里 lane i 可以读取 lane j 的唯一位置。它支撑 transpose、任意 lane permute、lane rotate,以及 cross-lane reductions(sum/max/min 及其 argmax/argmin index 变体,普通和分段两种)。所有这些都共享一个 bundle slot —— VectorExtended(VEX)slot,该 slot 也由 MXUEUP 超越函数 使用 —— 因此编译器在把它们放入 bundle 之前,必须对它们进行打包、在每代的 XLU 数量之间做平衡,并估算其延迟。

本页是权威的 XLU 参考。它分为三部分,每部分都锚定到二进制:

  1. 操作清单。 同一硬件的两个视图。在 IR 层级,后端通过 LloRegionBuilder 的 cross-lane factory 集(Vsetperm/Vxpose/Vpermute/Vrotate/Vsetspr/reduce family/…)发出高层 LloOpcode;每个 factory 都是薄包装器,调用一个 LloInstruction::CreateVector* op-constructor,后者再用固定 opcode 立即数调用 LloInstruction::New(LloOpcode, operand-Span, …)。在线路层级,每代 encoder 将这些操作打包到 bundle 的 VEX slot 中,作为 Jellyfish (v2) VectorExtendedOpcode —— 一个紧凑的 35 值 protobuf enum {0..34},其上半区间 {13..34} 就是 XLU/transpose/permute/cross-lane 家族。清单表列出两个编号空间以及它们之间的桥接。

  2. 组合流水线。 LloXluGraphOptimizer::Optimize 运行五阶段 XLU op-graph 重写 —— ComputeCombinablePairs(融合相邻且相同的 XLU ops)→ AssignXlu(贪心 least-loaded XLU-unit 平衡)→ ReorderToShortenCriticalPath(按延迟加权的 list scheduler)→ ReemitReorderedCombinedXluOperations(发出融合 ops,共享 permute/segment-pattern prologue)→ AssignSourceBus(VEX source-bus 打包)。每个放置、排序和融合决策都以同一个 cost function 为键。

  3. 成本。 CyclesAddedByXluOperation —— 五个阶段共同使用的单一 marginal-latency 表达式 —— 以及 PreXluAssignmentLatencyTable edge 模型(XLU↔XLU edges 为 ceil(base / xlu_count))。另外还有 transpose-fusion slot-fit 几何:SupportsVectorXpose / divisibility / NumVexSlots 三重 gate predicate,用于决定两个 transpose tiles 是否能折叠为一个受 VEX-slot 约束的 fused transpose。

对于重新实现,契约是:

  • factory → CreateVector*New(LloOpcode, operand-count) 表,以及 bundle encoder 打包到其中的 JF VectorExtendedOpcode {0..34} 清单。
  • ProtoUtils::Is* classifier ranges(proto-enum 编号),用于 gate matmul / push-gains / transpose / RPU dispatch。
  • 组合流水线顺序和 fusion predicate(相同 metadata + tracker-ready + cost-bounded;control ops 从不 fuse)。
  • CyclesAddedByXluOperation 闭式形式,以及 ceil(base/xlu_count) XLU edge weight。
  • transpose slot-fit predicate 和 VxposeMode/ElementCount 几何。
优化器xla::jellyfish::LloXluGraphOptimizer::Optimize @ 0x126cdb80
Factory 集LloRegionBuilder::V{setperm,setspr,permute,permuteres,rotate,xpose,xposeres,packBf16,…}
Op-constructorLloInstruction::CreateVector*LloInstruction::New(LloOpcode, Span<LloValue*>, …) @ 0x1d4cf560
线路 enumplatforms_deepsea::jellyfish::isa::VectorExtendedOpcode —— 紧凑 {0..34}(descriptor @ 0x1fa1fd00
ClassifiersProtoUtils::Is{MatrixMultiply,PushGains,Transpose,Rpu} @ 0x1e875b{20,80,40,60}
组合ComputeCombinablePairs @ 0x126d2480
单元分配AssignXlu @ 0x126d3100(贪心 least-loaded;要求 XlusPerTensorCore() > 1
重排ReorderToShortenCriticalPath @ 0x126d3460(per-XLU max-heap list scheduler)
重新发出ReemitReorderedCombinedXluOperations @ 0x126d5460
Source busAssignSourceBus @ 0x126d70e0(此构建中仅 Pufferfish)
成本CyclesAddedByXluOperation @ 0x126d22a0;edge = ceil(base / xlu_count)
XLU 数量Target::XlusPerTensorCore() = VectorIsa.xlu_count = DWORD[Target+0x4b0]
可信度CONFIRMED(字节锚定),除非行内另有说明

两个编号空间

重新实现者最先会困惑的是:一个 XLU operation 有两个不同身份,而二进制两者都会使用。

IR 身份LloOpcode —— 后端约 461 项 opcode 空间中的一个值(opcode_name table @ 0x21ccfef0)。这是 LloRegionBuilder factories 发出的内容,也是每个 optimizer pass switch 的对象。与 XLU 相关的 LloOpcode 有:0x36 kVectorPermute0x3a kVectorRotate0x3b kVectorBroadcastLane0x8b kVectorSetPermutePattern0x8c kVectorSetSegmentPattern0xa6 kVectorTranspose0xa7 kVectorTransposeBinary、reduce family 0xf5..0x1010x150 kVectorPermuteResult0x154 kVectorTransposeResult0x155 kVectorTransposeClear

线路身份是每代 bundle-slot opcode。在 Jellyfish (v2) 上,它是 VectorExtendedOpcode proto enum,一个紧凑的 35 值 enum {0..34},被切分为三类 op:matmul {0..6}、push-gains/latch {7..12},以及 XLU/transpose/permute/cross-lane 家族 {13..34}。matmul 和 latch 区段属于 MXUmatprep/latch slots;{13..34} 区段是本页记录的 XLU 家族。

两个空间在 bundle encode 时桥接:factory 发出的高层 LloOpcode,在打包 bundle 的 VEX slot 时被降低到其 VectorExtendedOpcode ordinal。下面的清单表列出两者。

注意 —— proto 值 vs encoded-bundle 字段。 VectorExtendedOpcode value(protobuf enum 编号,等价于规范 op name index)是 ProtoUtils::Is* classifiers 所索引的值。encoder OR 到 VEX slot bits 中的 encoded-bundle field{13..34} 范围内不同于 proto value(SET_PERMUTE/SET_SEGMENT 这一对会移动 encode-side mapping)。本页记录的是 proto-value 编号 —— classifiers 和 LLO bridge 使用的那一个。encoded-field value 是 JF bundle 布局 的另一个问题。


XLU Op-Factory 集

目的

后端 materialize 的每个 XLU op 都会经过 LloRegionBuilder cross-lane factory 集。重新实现者需要每个 factory 发出的精确 opcode + operand-span,因为这就是随后整个 optimizer 调度、encoder 打包的 LLO word。

算法

每个 factory 的形状相同,按字节精确来自 Vsetperm @ 0x1d52ba20

c
// LloRegionBuilder::Vsetperm(LloValue* in, SetPermuteMode mode, int xlu, optional<int> bus)
LloValue* r = LloInstruction::CreateVectorSetPermutePattern(in, mode, xlu, bus, this->region());
return this->region()->AppendInstruction(r);   // jmp AppendInstruction @0x1d50f9a0
```text

factory 是一个包装器;`CreateVector*` op-constructor 持有 opcode。每个 `CreateVector*` 在栈上构建 operand `Span`,然后调用一个 primitive —— 已在反编译中确认,例如 `CreateVectorSetPermutePattern` 发出 `LloInstruction::New(139, span, 1, region, …)`(139 = `0x8b`),`CreateVectorPermute` 发出 `New(54, span, 2, …)`(54 = `0x36`),`CreateVectorTranspose` 发出 `New(166, span, 2, …)`(166 = `0xa6`):

```c
// LloInstruction::New(LloOpcode op, Span<LloValue* const> operands,
//                     LloRegion*, LloValue*, PredicationPolarity, LloValue*)  @0x1d4cf560
// op is the first immediate; the Span size is the operand count.
v = LloInstruction::New(/*op=*/166, /*operands=*/&span, /*count=*/2, region, 0, 0, ...);

New 写入 WORD[value] = op(op word),并把 Span 连为 source operands。

Op → Factory → Opcode 表

所有 factories 都在命名空间 xla::jellyfish::LloRegionBuilder:: 中。发出的 opcode 是 New 的第一个 immediate;operand count 是 Span 的大小。十进制/十六进制都列出,因为反编译输出十进制。

Factory @addrCreateVector* @addr发出的 op(dec / hex)operands
Vsetperm @1d52ba20…SetPermutePattern @1d4d62a0139 / 0x8b kVectorSetPermutePattern1
Vsetspr @1d52ba60…SetSegmentPattern @1d4d64a0140 / 0x8c kVectorSetSegmentPattern1
Vpermute @1d52c180…Permute @1d4d55c054 / 0x36 kVectorPermute2 {data,pat}
Vpermuteres @1d52bfa0…PermuteResult @1d4d5e40336 / 0x150 kVectorPermuteResult1
Vrotate @1d52c6c0…Rotate @1d4d58a058 / 0x3a kVectorRotate2 {data,amt}
Vbroadcastlane @1d52c9a0…LaneBroadcast @1d4d608059 / 0x3b kVectorBroadcastLane2 (+0x3d,1)
Vxpose @1d54f580…Transpose @1d4dcfe0166 / 0xa6 kVectorTranspose2
Vxposeres @1d5501e0…TransposeResult @1d4d5b60340 / 0x154 kVectorTransposeResult0(FIFO pop)
VxposeBinaryCompressedB16 @1d550220…TransposeBinaryCompressedB16 @1d4dd7e0167 / 0xa7 kVectorTransposeBinary3(+scale)
VpackBf16 @1d554680…Weird @1d4d4e20174 / 0xae kVectorWeird1
VunpackUpperCF32 @1d567f20…Unpack @1d4d37c0271 / 0x10f kVectorDynamicUnpack
VunpackLowerCF32 @1d567e20…Unpack @1d4d37c0271 / 0x10f kVectorDynamicUnpack
Vunpackf32 @1d554620— composite —VunpackLowerF32+CastTo(0x12)+VunpackUpperF32+CastTo(0x12)
VpermuteSync @1d52baa0— composite —Vpermute(0x36) then Vpermuteres(0x150)
VpermuteSlane @1d52d220CreateVectorBinop @1d4d27c0(由 opcode 参数驱动)
VpackiB16 @1d553380 / VpackcB16 @1d562700CreateVectorPack @1d4d3140(由 opcode 参数驱动)2

注意 —— VxposeBinaryCompressedB16 发出单个 0xa7 op(3 operands),不是 multiply/pow chain。它的 factory(@0x1d550220)和 constructor(@0x1d4dd7e0)把第三个 operand 作为 LloModule::ScalarU32ConstantImpl scale value;唯一额外动作是 target().SupportsVsupp() gate(CHECK string 位于 llo_region_builder.cc:8617)。XLU 路径上不存在 New(0x156/0x158/0x159) 调用。


JF VectorExtendedOpcode 清单 {0..34}

目的

这是 bundle encoder 打包进 JF VEX slot 的线路层 enum。{13..34} 区段是 XLU 家族;{0..12} 区段是 matmul + push-gains,记录在 MXUmatprep/latch slots 中。ProtoUtils::Is* classifiers 用 proto-enum value 做索引,以路由 decode/encode dispatch。

Classifier Ranges(binary-exact)

直接从二进制反编译而来 —— 这些是 proto-enum 编号中的真实 dispatch ranges:

c
IsMatrixMultiply(op) = (op < 7) & (0x77 >> op)        // {0,1,2,4,5,6}  (3 = DONE_WITH_GAINS excluded)
IsPushGains(op)      = (unsigned)(op - 7)  < 6         // {7..12}
IsTranspose(op)      = (unsigned)(op - 15) < 2         // {15,16}
IsRpu(op)            = (unsigned)(op - 17) < 0x12      // {17..34}
VectorExtendedUsesData(op) = (op != 3)                 // only op 3 reads no vector data operand
```text

`ProtoUtils::IsRpu`(@ `0x1e875b60`)计算 `(op - 17) < 0x12`,所以 RPU 区段是 `{17..34}` —— 从 `PERMUTE(17)` 到 `CROSS_LANE_SEGMENTED_MIN_INDEX_PERMUTE(34)`。`TRANSPOSE(15)`/`TRANSPOSE_START(16)` 归入 `IsTranspose`,不归入 `IsRpu`。

### 清单表

`mnemonic` 是 `ParserJf` cross-lane parse-pair string(assembler 侧);`LLO` 是 `LloRegionBuilder` factory 发出的高层 `LloOpcode`。

|| 名称 | classifier | mnemonic / LLO bridge |
|---|---|---|---|
| 0 | `MATRIX_MULTIPLY` | `IsMatrixMultiply` | matmul |
| 1 | `MATRIX_MULTIPLY_LOW` | `IsMatrixMultiply` | matmul.low |
| 2 | `MATRIX_MULTIPLY_HIGH` | `IsMatrixMultiply` | matmul.hi |
| 3 | `DONE_WITH_GAINS` | `UsesData=false` | done-with-gains(无 vector operand) |
| 4 | `MATRIX_MULTIPLY_DONE_WITH_GAINS` | `IsMatrixMultiply` | matmul.dwg |
| 5 | `MATRIX_MULTIPLY_LOW_DONE_WITH_GAINS` | `IsMatrixMultiply` | matmul.low.dwg |
| 6 | `MATRIX_MULTIPLY_HIGH_DONE_WITH_GAINS` | `IsMatrixMultiply` | matmul.hi.dwg |
| 7 | `PUSH_GAINS` | `IsPushGains` | push-gains |
| 8 | `PUSH_GAINS_LOW` | `IsPushGains` | push-gains.low |
| 9 | `PUSH_GAINS_HIGH` | `IsPushGains` | push-gains.hi |
| 10 | `PUSH_GAINS_TRANSPOSED` | `IsPushGains` | push-gains.xpose |
| 11 | `PUSH_GAINS_LOW_TRANSPOSED` | `IsPushGains` | push-gains.low.xpose |
| 12 | `PUSH_GAINS_HIGH_TRANSPOSED` | `IsPushGains` | push-gains.hi.xpose |
| 13 | `SET_PERMUTE_CONTROL_REGISTER` || LLO `0x8b` `Vsetperm` |
| 14 | `SET_SEGMENT_PATTERN_REGISTER` || LLO `0x8c` `Vsetspr` |
| 15 | `TRANSPOSE` | `IsTranspose` | `vxpose` — LLO `0xa6` `Vxpose` |
| 16 | `TRANSPOSE_START` | `IsTranspose` | `vxpose.start` — LLO `0xa7` `VxposeBinaryCompressedB16` |
| 17 | `PERMUTE` | `IsRpu` | LLO `0x36` `Vpermute` |
| 18 | `LANE_ROTATE` | `IsRpu` | LLO `0x3a` `Vrotate` |
| 19 | `ROTATING_PERMUTE` | `IsRpu` |(rotating permute)|
| 20 | `CROSS_LANE_ADD` | `IsRpu` | `vadd.xlane` — LLO reduce-add |
| 21 | `CROSS_LANE_MAX` | `IsRpu` | `vmax.xlane` — LLO reduce-max |
| 22 | `CROSS_LANE_MIN` | `IsRpu` | `vmin.xlane` — LLO reduce-min |
| 23 | `CROSS_LANE_MAX_INDEX` | `IsRpu` | `vmax.index.xlane` |
| 24 | `CROSS_LANE_MIN_INDEX` | `IsRpu` | `vmin.index.xlane` |
| 25 | `CROSS_LANE_ADD_PERMUTE` | `IsRpu` | `vadd.xlane.perm` |
| 26 | `CROSS_LANE_MAX_PERMUTE` | `IsRpu` | `vmax.xlane.perm` |
| 27 | `CROSS_LANE_MIN_PERMUTE` | `IsRpu` | `vmin.xlane.perm` |
| 28 | `CROSS_LANE_MAX_INDEX_PERMUTE` | `IsRpu` | `vmax.index.xlane.perm` |
| 29 | `CROSS_LANE_MIN_INDEX_PERMUTE` | `IsRpu` | `vmin.index.xlane.perm` |
| 30 | `CROSS_LANE_SEGMENTED_ADD_PERMUTE` | `IsRpu` | `vadd.xlane.seg.perm` — LLO `0xfc` seg-reduce |
| 31 | `CROSS_LANE_SEGMENTED_MAX_PERMUTE` | `IsRpu` | `vmax.xlane.seg.perm` — LLO `0xfa` seg-reduce |
| 32 | `CROSS_LANE_SEGMENTED_MIN_PERMUTE` | `IsRpu` | `vmin.xlane.seg.perm` — LLO `0xfb` seg-reduce |
| 33 | `CROSS_LANE_SEGMENTED_MAX_INDEX_PERMUTE` | `IsRpu` | `vmax.index.xlane.seg.perm` |
| 34 | `CROSS_LANE_SEGMENTED_MIN_INDEX_PERMUTE` | `IsRpu` | `vmin.index.xlane.seg.perm` |

紧凑范围 `{0..34}` 由 `NameOfDenseEnum<descriptor,0,34>` 实例化 @ `0x2239bce8` 确认;名称是 protobuf `EnumValueDescriptorProto` identifiers(descriptor @ `0x1fa1fd00`)。两个 `SET_*` 名称也可作为 `.rodata` strings 独立可见;`Is*` classifier bodies 已按字节精确反编译(见上)。

> **注意 —— LLO reduce-family → cross-lane bridge。** 高层 reduce LLO ops `0xf5..0x101` 会降低到 `CROSS_LANE_*` 区段 `{20..34}`。分流由 `LloOpcodeIsSegmentedReduction(op) = (op - 250) < 3 = {0xfa,0xfb,0xfc}` 决定(binary-confirmed @ `0x1d60c340`):segment reduces 使用 `SET_SEGMENT_PATTERN_REGISTER`(`Vsetspr`)prologue,并降低到 `CROSS_LANE_SEGMENTED_*`;所有其他 reduces 使用 `SET_PERMUTE_CONTROL_REGISTER`(`Vsetperm`)prologue,并降低到非分段 `CROSS_LANE_*` ops。

---

## XLU Op 组合流水线

### 目的

XLU 是从一个与 MXU 共享的 slot 发出的稀缺多周期资源。两个执行*相同* cross-lane operation 的相邻 XLU ops(例如两个 sum-reduces 使用同一 permute pattern)可以融合为一次 cross-lane pass,并且只支付一次 pattern setup 成本。`LloXluGraphOptimizer::Optimize` 就是找到这些融合、在每代 XLU units 之间平衡保留下来的 ops、重排以缩短 critical path,并把它们打包到 VEX source buses 上的重写。

### 流水线顺序

五个阶段按以下精确顺序运行,来自 `Optimize` 函数体的字节映射(`@0x126cdb80`):

```text
AdjustEdgesBeforeXluAssignment   @0x126d1de0   ; pre-adjust dependency-graph edges
build PreXluAssignmentLatencyTable              ; XLU↔XLU edge = ceil(base / xlu_count)
CrossXlu Create (tracker #1, reverse=0)         ; data-dependency tracker over the XLU ops
ComputeCombinablePairs           @0x126d2480   ; (1) fuse-candidate pairs
[gate optimizer+0x28==1] AssignXlu @0x126d3100  ; (2) greedy least-loaded XLU-unit assign
CrossXlu Create (tracker #2, reverse=1)         ; rebuilt on the unit-assigned graph
ReorderToShortenCriticalPath     @0x126d3460   ; (3) latency-weighted list scheduler
ReemitReorderedCombinedXluOperations @0x126d5460; (4) emit fused/reordered LLO ops
[gate optimizer+0x28==1] AssignSourceBus @0x126d70e0 ; (5) VEX source-bus pack (Pufferfish only)

dependency tracker(CrossXluOperationsDataDependencyTracker)会构建两次:一次在 combine 之前(reverse=0),一次在 reorder 之前(reverse=1,针对 post-combine、post-unit-assign graph)。两个阶段都会查询它的 XluOperationIsReady predicate(in-edge count == 0)。

阶段 1 — ComputeCombinablePairs

ComputeCombinablePairs@0x126d2480)接收 XLU-op list(一个 vector<variant<TransposeTile, RpuOperation, XluControlOperation>*>)、cross-region from/to boundary LloValue pair,以及 dependency tracker,并返回可融合 pair 的 vector<pair<variant*,variant*>>

它构建 per-op cost / value / cumulative-max arrays(critical-path DP),然后按 metadata key 将 ops 分组到 per-key btree_set<long> buckets 中;只要较晚的 op 与较早的 op 在同一 key 上碰撞、tracker-ready 且 cost-compatible,就发出一个 combinable pair。

两个 metadata keys,每个可融合 variant 一个:

variantkey struct(byte-exact)extractor
RpuOperation(idx 1)RpuOperationMetadata {u16 opcode@0, LloValue* op0@8, LloValue* op1@0x10 (gated u8@0x18==1)}GetRpuTransposeOperationKeyFrom @ 0x126d8520
TransposeTile(idx 0)TransposeTileMetadata {i32 height@0, i64@8, u16@0x10, u8 vxpose_mode@0x12, u8@0x13}内联于 $_0 visitor

对于 RPU op,key 是 {opcode, source-operand-0, source-operand-1} —— 但 opcode == 0x3aVrotate)例外,它只使用一个 from-end operand(op1 = 0has1 = 0)。对于 transpose tile,key 是 {height, anchor, vxpose-mode, …}

完整 fusion predicate:

两个相邻 XLU ops 会融合为一个 cross-lane operation,当且仅当 (a) variant kind 相同 fusion metadata 相同;(b) 第二个 op 在 dependency graph 中 list-scheduling-ready(XluOperationIsReady,所有 predecessor XLU ops 已调度);并且 (c) 合并后 critical-path cost 仍有界(CyclesAddedByXluOperation DP arrays)。XluControlOperation ops 从不 fuse —— $_2 visitor arm(@0x2139b1c0)是硬 LogFatal

阶段 2 — AssignXlu

AssignXlu@0x126d3100)是贪心 least-loaded bin-packer。它只在 XlusPerTensorCore() > 1 时有意义 —— 反编译中包含精确 CHECK string "dep_graph_->target()->XlusPerTensorCore() > 1"(line 2563),如果该代少于 2 个 XLU 则 LogFatal

它分配一个 per-XLU running-cost record array(xlu_count 条记录,每条 0x20 B),然后对每个 combinable pair 扫描所有记录,选择 accumulated cost 最小的 XLU,将该 unit index 写入每个 backing LloInstruction 的 unit-selector field($_0 lambda @ 0x126db0a0),并把该 op 的 CyclesAddedByXluOperation 加到该 XLU 的 running cost。unit 选择会立即提交到 instruction word,因此后续 reorder 和最终 emission 都能看到它。

unit-selector 写入与下面的 ValidateAndSetXluAndSourceBus emission writer 按字节相同 —— AssignXlu 是同一字段在 scheduler 侧的生产者。

阶段 3 — ReorderToShortenCriticalPath

ReorderToShortenCriticalPath@0x126d3460)是在已完成 unit-assigned 的 ops 上运行的标准 latency-weighted list scheduler。它分配一个 per-XLU PerXluOperations state struct(stride 0x60):

offsetfield作用
+0x00..0x38absl::btree_set<long, less, alloc, 256>per-XLU pending op-index set
+0x38i64remaining running-cycle accumulator(尚未调度 ops 的 Σ cost)
+0x40 / +0x48LloValue* pairlast-scheduled op 的 source operand 0 / 1(next-delta anchor)
+0x50variant*此 XLU 上 last-scheduled op(下一次 CyclesAddedprev
+0x58i64per-XLU completion-time clock(critical-path frontier)

Phase A 为每个 op 预计算 cost[i] = CyclesAddedByXluOperation(...),累计到 PerXlu[xlu][+0x38],并构建 pending sets。Phase B 运行 per-XLU priority_queue<pair<long,long>> max-heap,key 为 {marginal_cost, op_index}less<> ⇒ longest-marginal-cost ready op 优先,tie 由更高 op-index 打破)。它弹出最高优先级 op;$_2 lambda 测试 XluOperationIsReady 加 completion-clock critical-path test([+0x58] + cost >= finish[idx]);ready 时,$_1 lambda 提交(从 pending set 删除,推进 [+0x58] = max([+0x58]+cost, finish[idx]),把 pair 写入输出);not-ready 时,$_3 lambda 重新定价并把 op 重新入队。一个 pre-test(cmp heap_top_cost, [PerXlu+0x38]; jl skip)只在仍然能缩短该 XLU 的 remaining path 时尝试 reorder —— 这就是函数名所描述的 critical-path-shortening gate。

阶段 4 — ReemitReorderedCombinedXluOperations

ReemitReorderedCombinedXluOperations@0x126d5460)是把 scheduler 决策转成实际 LLO 的 IR rewriter。它构建新的 emission LloRegionBuilder 和 per-XLU PerXluState array(stride 0x20)—— per-XLU “currently-set pattern” cache:

offsetfield
+0x00当前在此 XLU 上设置的 permute-pattern source value
+0x08已发出的 Vsetperm result(共享 SetPermutePattern setup)
+0x10当前在此 XLU 上设置的 segment-pattern source value
+0x18已发出的 Vsetspr result(共享 SetSegmentPattern setup)

对每个 combinable pair,它通过 factory 集发出一个 fused cross-lane op:

  • RPU pair(variant idx 1):对于 producer 是 SetPermutePattern0x8b)op 的每个 source,将其与 PerXluState[xlu][+0x00] 比较;如果不同则发出 Vsetperm 并缓存结果,否则复用缓存的 pattern。(SetSegmentPattern 0x8cVsetspr,缓存在 +0x18/+0x10。)然后发出 fused reduce body,消费单个共享 pattern result —— 两个 combinable reduces 折叠为一个 cross-lane reduce。ReplaceUsesOfInstruction 重定向第二个 op 的 uses;RemoveNode 删除原始 ops。
  • Transpose pair(variant idx 0):匹配两个 tiles 的 geometry(见下面的 slot-fit),在 SupportsVectorXpose/NumVexSlots 上 gate,发出一个 fused Vxpose / VxposeBinaryCompressedB16,重新安置两个 tiles 的 instructions(PopInstruction/AppendInstruction),并对每个 result chunk 发出 VxposeresReplaceUsesOfInstruction

经济性:per-XLU SetPermute/SetSegment pattern op 每个 XLU 只发出一次并复用 —— 共享同一 pattern 的 N 个 reduces 只支付一次 pattern setup。

阶段 5 — AssignSourceBus

AssignSourceBus@0x126d70e0)把每个 XLU op 的 operands 路由到 VEX source buses。它由 Target::HasVexSourceBuses()(vtable +0x408)gate —— 此构建中只有 Pufferfish (v4) 返回 trueJF/DF/VF/GL 返回 false),因此 source-bus pass 在这里的其他所有代上都是 no-op。

启用时,它按拓扑顺序遍历 dependency graph,并为每个满足 LloOpcodeUsesSourceBus(下面的 29-opcode set)的 op 绑定 bus。MXU ops(LloOpcodeUsesMxu)绑定到显式 MXU-indexed bus;纯 XLU ops 贪心占用下一个空闲 bus。bus pool 来自 SourceBusesForXlu(i) —— 在 Pufferfish 上为 {i, i+2}(反编译:[+8]=i, [+0xc]=i+2, count-tag=4)—— 因此 XLU 0 拥有 buses {0,2},XLU 1 拥有 {1,3},即 V0/V1/V2/V3 read ports 按 (V0,V2)/(V1,V3) 配对。落到同一 bus 的两个 ops 会获得新的 latency-weighted serialization edge(UpdateEdge)—— 共享 bus 的 structural hazard。

LloOpcodeUsesSourceBus(binary-confirmed @ 0x10c0d420)对精确 29 个 opcodes 返回 true

text
{0x36, 0x3a, 0x3b}        permute / rotate / broadcast-lane
{0x8b, 0x8c}              set-permute-pattern / set-segment-pattern
{0x8f .. 0x96}            8 matmul-push ops (MXU operand path, UsesMxu)
{0xa6, 0xa7}              transpose / transpose-binary
{0xf5 .. 0x101}           13 cross-lane reduce / index / segment-reduce ops
{0x155}                   transpose-clear
```text

### Scheduler 侧 Bit-Field

`AssignXlu`(unit)和 `AssignSourceBus`(bus)都会写 `WORD[LloInstruction + 0xb]`;LLO-emission validators `ValidateAndSetXluAndSourceBus` / `ValidateAndSetMxuAndSourceBus` 会重新断言同一字段。来自反编译的字节精确形式:

```c
// unit selector (XLU or MXU instance):
WORD[instr+0xb] = ((xlu & 3) << 8) | (WORD[instr+0xb] & 0xF8FF) | 0x400;   // bits 8-9 + valid bit 10
// source bus (Pufferfish only):
WORD[instr+0xb] = ((bus & 3) << 11) | (WORD[instr+0xb] & 0xC7FF) | 0x2000;  // bits 11-12 + valid bit 13

source-bus 字段保存原始 2-bit index {0..3} —— 不是 SparseCore VexSourcePortEncoding proto enum,后者是另一条 datapath 上的不同 3-bit encoding(见 VPU Slot)。


XLU 成本模型

CyclesAddedByXluOperation

CyclesAddedByXluOperation@0x126d22a0)是 combine DP、AssignXlu min-cost pick 和 reorder heap priority 共同使用的单一 marginal-latency 函数。按字节精确反编译,闭式形式为:

c
long CyclesAddedByXluOperation(variant* prev, variant* cur,
                               LloValue* from, LloValue* to, LatencyTable& tbl) {
    if (cur == null) {
        // empty-XLU base case → only a transpose prev contributes
        if (prev == null || prev.discr != 0 /*TransposeTile*/) {
            if (prev == null) return 0;
            goto transpose_tail;       // prev.discr == 0
        }
        return 0;
    }
    // MAIN EDGE: prev's anchor op → cur's anchor op
    long cost = tbl.LatencyBetween( op_data(prev), op_data(cur) );

    if (prev != null && prev.discr != 0 /*not TransposeTile*/) {
        if (cur.discr == 0 /*cur is TransposeTile*/) goto transpose_tail;
        CHECK(prev.discr == 1 /*RpuOperation*/);     // XluControlOperation prev ⇒ LogFatal line 1012
        // RPU prev: two inline source-operand identities at [prev+0x00], [prev+0x08]
        if (prev.src0 && prev.src0->operands(0) != from)
            cost += tbl.LatencyBetween( GetAnchorInstruction(cur), prev.src0 );
        if (prev.src1 && prev.src1->operands(0) != to)
            cost += tbl.LatencyBetween( GetAnchorInstruction(cur), prev.src1 );
        return cost;
    }

transpose_tail:                                       // prev is TransposeTile (or cur==null path)
    long n = prev.read_set_size;                      // [prev+0x08]
    if (n >= 2)
        cost += (n - 1) * tbl.LatencyBetween( readset[0].op_data, readset[1].op_data );
    return cost;
}
```text

解释:

- 主导项是从 XLU 上一个 op 到新 op 的 **per-(op,op) edge latency**,取自 optimizer 的 table。
- 对 RPU op,**其两个 source operands 中每一个不是 cross-region boundary value**(`from`/`to`)的 operand,都会额外增加一次 `LatencyBetween(cur_anchor, prev_source)` —— 这是在 XLU 上 materialize 非 boundary source 的 fan-in penalty。Boundary operands 免费。
- 对 transpose chain,成本是 `(read-set − 1)` 份第一个和第二个 tile elements 之间的 latency —— per-extra-chunk transpose-sequence latency。
- `XluControlOperation` 作为 `prev` 是硬 `LogFatal` —— control ops 从不定价,这与它们从不 combinable 一致。

`GetAnchorInstruction`(`@0x126cda00`)把 variant 解析到其 anchor `LloValue`:idx 1(RPU)→ `[v+0x10]`;idx 2(control)→ `[v]`;idx 0(transpose)→ 最后一个 read-set element;`op_data(v) = [resolve(v) + 0x10]`。

### PreXluAssignmentLatencyTable Edge

`LatencyBetween` 运行在 optimizer 自己的 `PreXluAssignmentLatencyTable` 上,这是对每代 base `LatencyTable`(由 `LatencyTable::Create(TpuVersion)` registry dispatch 选择)的 wrapper。其 `LatencyBetweenInternal`(`@0x126e0e40`)按反编译字节精确为:

```c
long LatencyBetweenInternal(LloValue* from, LloValue* to) {
    if (IsXluOp(from.op) && IsXluOp(to.op)) {
        int raw = delegate.LatencyBetween(from, to);   // [this+0x18] per-gen base table
        int div = xlu_count;                            // [this+0x20]
        return ceil(raw / div);                         // div>0: quotient + (raw > quotient*div ? 1 : 0)
    }
    return delegate.LatencyBetween(from, to);           // pass-through for non-XLU edges
}

IsXluOp(op) 是 21 个 XLU opcodes {0x8b, 0x8c, 0xa6, 0xa7, 0xf5..0x101, 0x14f, 0x150, 0x154, 0x155}(反编译中的 case labels)与 low-band bit-mask op <= 0x3b && bt(0xc40000000000000, op) = {0x36, 0x3a, 0x3b} 的并集 —— Vpermute / Vrotate / Vbroadcastlane

XLU↔XLU edge 是每代 base latency 除以可用 cross-lane units 数量:XLU 越多,单个 XLU↔XLU edge 越便宜 —— 这就是整个 optimizer 用来定价的 parallelism discount。xlu_count = Target::XlusPerTensorCore() = VectorIsa.xlu_count = DWORD[Target+0x4b0]


Transpose Slot-Fit 几何

目的

fused transpose 必须适配每代 VEX-slot budget。reemit transpose 路径在把两个 tile fusion 折叠为一个 Vxpose 之前,会用一个三条件 predicate gate 它。

VxposeMode 和 ElementCount

VxposeMode 是 5 值 enum;ElementCount(mode) 是该 mode 的 elements-per-chunk,从 0xb53c830 处的表读取。按字节精确确认(.rodataxxd 给出 01 00 00 00 02 00 00 00 04 00 00 00 01 00 00 00 02 00 00 00):

mode名称ElementCount含义
0B321full-width 32-bit transpose(默认)
1Compressed B162bf16-compressed,2 elements/chunk
2Compressed B84b8-compressed,4 elements/chunk
3Segmented B321segmented 32-bit transpose
4Segmented B162segmented bf16 transpose

三重 Gate Predicate

来自 reemit transpose block(@0x126d5b1b..0x126d5f5a)的字节精确形式:

gate条件接受 / 拒绝
G1target->SupportsVectorXpose(vxpose_mode) == true(vtable +0x100如果该 gen 不支持此 mode,则 reject(no fusion)
G2[tile+0x30] % (SublaneCount() * ElementCount(mode)) == 0(imul + idiv + test-remainder)如果 chunk dimension 不是整数量的 slot-sized element chunks,则 reject
G3NumVexSlots() != 0(vtable +0x690accept → emit;打包到 NumVexSlots() 个 VEX slots
G3′如果 NumVexSlots() == 0ChunksPerTile() == (chunks >> mode_shift)如果不相等则 reject(no-VEX-slot path)

带有 VEX slots 的 gen 会把 fused transpose 打包到 NumVexSlots() 个 vector_extended slots;没有 VEX slots 的 gen 只能融合正好占用一个 tile chunks 的 transpose。(在 gates 之前,两个 tiles 已经必须在 GetNumberOfChunksInTransposeSequencevxpose_modeTransposeResultChunkCountGetTransposeWidth 上匹配。)

Per-Gen Target Overrides

来自 per-Target vtable slots 的字节精确结果。NumVexSlots() 是每代 vector_extended slot 数量 —— 与 MXUEUP 使用的是同一个 slot;在 JF 上,它是 41-byte bundle 的单个 VEX slot。

Target (gen)NumVexSlots()SupportsVectorXpose(mode)
JellyfishTarget (v2)1(return 1mode == 0(仅 B32)
PufferfishTarget (v4)2mode != 2(除 Compressed B8 外全部)
GhostliteTarget (v6e)2mode < 3(B32 / Compressed B16 / B8)
ViperfishTarget (v5p)2mode != 2(除 Compressed B8 外全部)
Target (base)LogFatalabstract

注意 —— PF/VF SupportsVectorXpose bodies(0x1d4940a0 / 0x1d49a000)是 return a2 != 2;:它们接受除 mode 2(Compressed B8)以外的每个 VxposeModecmp esi, 2; ret 形式是不等测试,不是 mode == 2。参见 Transpose Reservation Latency 获取 VxposeMode ordinal 清单。


示例 —— 两个 kVectorAddReduceF32 融合(Pufferfish v4,xlu_count = 2)

  1. ComputeCombinablePairs 发出 pair {&R_a, &R_b} —— 相同 RpuOperationMetadata{0xf7, src0, src1}0xf7 ≠ 0x3a,所以有两个 source operands),R_b tracker-ready,cost-compatible。
  2. AssignXluxlu_count == 2(≥ 2 OK)。两者都适配 XLU 0(min cost,tie → index 0)。$_0 lambda 把 unit = 0 | valid 写入两个 instruction words。成本 = CyclesAddedByXluOperation(...) = ceil(B / 2),其中 B 是每代 base reduce-edge latency —— 因为两个 XLU 并行运行,所以是串行延迟的一半。
  3. tracker 在 unit-assigned graph 上重建(reverse = 1)。ReorderToShortenCriticalPath 初始化 PerXluOperations[0],将 R_a/R_b$_3 marginal cost 入队,并优先调度 longest-cost ready op。
  4. ReemitReorderedCombinedXluOperations:pair {R_a, R_b},两者都是 RPU,xlu = 0只发出一次 Vsetperm(缓存在 PerXluState[0][+0x08]);两个 reduces 折叠为一个 fused cross-lane reduce,消费该单个 pattern setup。ReplaceUsesOfInstruction 重定向 R_b 的 uses;RemoveNode 删除原始 ops。
  5. AssignSourceBusHasVexSourceBuses = true):把 fused op 打包到来自 SourceBusesForXlu(0) = {0,2} 的一个 V-port 上;2-bit bus index 写入 WORD[+0xb] bits 11-13。

对比 segment reduce pair(0xfc):LloOpcodeIsSegmentedReduction(0xfc) = true,所以共享 prologue 是 Vsetspr(缓存在 PerXluState[+0x18]),而不是 Vsetperm。对比 transpose pair(0xa6):variant idx 0;reemit 匹配 vxpose-mode/height/chunk-count,在三重 gate slot-fit predicate 上 gate,发出一个 fused Vxpose,重新安置两个 tiles 的 instructions,并对每个 result chunk 发出 Vxposeres


未固定内容

  • SetPermuteMode enumerator names(第 2 个 Vsetperm arg):该值作为 DWORD[variant+0x40] 穿过,但未定位到 SetPermuteModeToString。LOW。
  • VunpackUpperCF32 / VunpackLowerCF32 的精确 CreateVectorUnpack arm + 其 VpackFormat:存在多个 New arms(0x10f 和 dynamic-opcode arm),CF32-specific half 未隔离。LOW。
  • VpermuteSlane / VpackiB16 / VpackcB16 发出的 opcodes 作为参数传给 CreateVectorBinop / CreateVectorPack;每个调用的具体值未隔离。LOW。
  • PF/VF SupportsVectorXpose 精确 mode mask(ICF-folded cmp esi,2; ret thunk)。LOW。
  • LatencyBetween stochastic perturbation(当 [table+0x10] != 0 时添加 UniformDistribution(0,0x65)):存在于 cost path 中,其启用条件和 scheduling effect 未隔离。

交叉引用

  • VPU Slot —— per-lane vector ALU;EUP/XLU push-pop protocol 和不同的 SparseCore VexSourcePortEncoding
  • MatPrep/IAR/Latch Slot —— 与 XLU 共享 VectorExtended slot 的 matmul {0..6} / push-gains {7..12} 区段。
  • vcreate_mask & M-Register —— masked-scan family 所选择的 SparseCore vector-mask file。
  • ResultFifo & ArchRegister —— Vxposeres / Vpermuteres pops 所 drain 的 result FIFOs。
  • Bundle Model —— encoder 将 XLU op 打包进入的 VLIW bundle;每代 NumVexSlots() budget。