Skip to content

转置保留延迟

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

摘要

XLU 冲突惩罚表是一个静态的 6×6×3 int32 网格,用于为两个相邻跨 lane 操作之间的最坏情况结构冒险定价。该表无法捕获一种成本:跨 lane fabric 会被一次转置占用多久,而这个占用时间取决于转置的数据形状(其高度 × 宽度)以及其 VxposeMode 的打包密度。XposeXLUReservationLatency 正是提供这一动态项的机制 — 它是在转置序列的最终转置出边上获取的一个计算出来的(而非查表得到的)延迟,会在静态冲突惩罚单元格之上额外加上依赖形状的占用周期数。

参照框架与 MXU 延迟模型使用的 MCSchedModel 风格保留思想相同,但它专门针对跨 lane 单元,并针对上游 LLVM 没有对应物的一个细节:向量转置每个周期移动固定数量的打包元素,而这个吞吐量是操作数元素宽度的函数。未打包的 32-bit 转置(B32)每个 lane 每周期移动 1 个元素;Compressed B8 转置移动 4 个。因此,必须通过跨 lane 引擎排出的非对角元素数量 (width − height),在 B8 中需要的占用周期比 B32 少四倍 — 而这个比率正是 ElementCount(VxposeMode),也就是本页钉住的打包因子。

本页记录三个由字节锚定的部分:

  1. XposeXLUReservationLatency — 动态转置保留公式,覆盖三种延迟表形状(base Jellyfish / GhostLite、Viperfish、Pufferfish),包括选择该公式并把转置形状传入的高层分发器。
  2. VxposeMode — 5 个序号的转置模式枚举、它的 ElementCount 打包因子、存储它的 LloInstruction 字节、VxposeMode → XluInstrType 子表,以及按 Target 划分的 SupportsVectorXpose 掩码。
  3. MxuStat — 贪心最小 makespan 装箱器读写的每 MXU 运行状态记录。MxuStat 记录转置/锁存序列占用的 busy-interval 状态;其布局和区间扩展成本函数在这里钉住。

对于重新实现,契约是:

  • 按 generation 的 XposeXLUReservationLatency 闭式形式:static_cell + max(0, shape_term),其中 base 形式会将形状项除以 2 × ElementCount(vxpose),VF/PF 去掉该除数并增加一个 +7 设置常数(PF 还会额外取下限)。
  • IsFinalTransposeInSequence 上选择动态路径,并从最终转置 op 解析 vxpose_mode / height / width 的分发器。
  • VxposeMode 序号 {B32, Compressed B16, Compressed B8, Segmented B32, Segmented B16}ElementCount{1,2,4,1,2},以及 +0x44 处的 LloInstruction 字节。
  • 40 字节的 MxuStat 布局,以及 LatchLatencyChangeAfterAdding 区间扩展增量 c + x − y2
动态保留(base/GL)xla::jellyfish::XluConflictPenaltyTable::XposeXLUReservationLatency @0x1c8a0640
动态保留(Viperfish)xla::viperfish::LatencyTableViperfish::XposeXLUReservationLatency @0x1c8a4e60(vtable +0x10
动态保留(Pufferfish)xla::pufferfish::LatencyTablePufferfish::XposeXLUReservationLatency @0x1c8a13e0(vtable +0x10
分发器XluConflictPenaltyBetween(LloValue*, LloValue*) @0x1c8a01c0
原始单元格读取器XluConflictPenaltyBetween(XluInstrType, XluInstrType, uint) @0x1c8a0180
IsTranspose(XluInstrType)@0x1c8a04e0(t − 2) < 3{2,3,4}
VxposeMode 字符串xla::jellyfish::VxposeModeString @0x1d629f60(5 种情况)
ElementCount(VxposeMode)@0x1d62a1400xb53c830 处的 int[5] 表 = {1,2,4,1,2}
vxpose_mode() 访问器LloInstruction::vxpose_mode @0x1d4e7440 — 对 op 0xa6/0xa7 读取 byte[inst + 0x44]
MxuStat 初始化 / 选择AssignMxusForSequenceGroupInternal @0x10f77ca0(初始化 @0x10f77d30,选择 @0x10f784d0
区间扩展成本MxuStat::LatchLatencyChangeAfterAdding @0x10f7f3e0;再平衡 LatencyChangeIfMoveTo @0x10f7fb40
置信度CONFIRMED(字节锚定),除非某行另有说明

两条转置占用周期路径

XLU 边模型会在两条路径之一上收取转置占用周期,选择依据是较早的 op 是否为一个转置序列的最终转置:

路径选择条件成本函数
静态非最终 / op 间冒险XluConflictPenaltyTable[from][to][mxuIdx] — 一个固定的 6×6×3 int32 单元格冲突惩罚表
动态较早的 op IsFinalTransposeInSequence静态单元格加上一个数据形状占用项XposeXLUReservationLatency(本页)

动态路径不会替代静态单元格 — 它读取同一个单元格并加上形状项。静态表为结构性 FIFO 冒险定价;动态项为跨 lane datapath 保持占用以排出转置非对角元素的额外周期定价。(第三种消费侧边 — LatencyBetweenXposeInstrAndResult,即下游 op 为读取最终转置结果所支付的延迟 — 位于 @0x1c8a06e0/@0x1c8a4fa0/@0x1c8a1520,vtable +0x30;它随冲突惩罚表一起记录。)


XposeXLUReservationLatency

目的

XposeXLUReservationLatency 是延迟表 vtable 槽 +0x10 处的一个虚方法。它的 demangled 签名为:

c
long XposeXLUReservationLatency(VxposeMode vx, XluInstrType from, XluInstrType to,
                                unsigned int mxuIdx, int height, int width) const;

vx 是转置的 VxposeMode(在 base 路径上驱动打包除数);from/to 是较早(转置)和较晚 op 的 XluInstrTypemxuIdx 是物理 MXU 实例索引(unit_id & 3,约束 < 3),用于选择静态单元格的第三维;height/width 是转置矩阵的维度,二者都从最终转置 op A 解析。

分发器

XluConflictPenaltyBetween(LloValue* A, LloValue* B) @0x1c8a01c0 是高层入口。它通过 GetXluInstrType 解析两个 op 的 XluInstrType,断言二者都携带有效 unit_idunit_id == later->unit_id(),CHECK 行 245/246/248),并在 A 是最终转置时经由 vtable 走动态路径。逐字节如下:

c
// XluConflictPenaltyBetween(LloValue* A /*earlier*/, LloValue* B /*later*/)  @0x1c8a01c0
unsigned fromType = GetXluInstrType(A);                  //  @0x1c89ff20
unsigned toType   = GetXluInstrType(B);
// unit_id is the 2-bit field in WORD[A+0xb] bits 8-9, gated by valid bit 10 (& 0x400):
unsigned mxuIdx   = (HIBYTE(*(u16*)(A + 11)) & 3);       //  asserts WORD[A+0xb] & 0x400, lines 245/248
LloInstruction* a = LloInstruction::FromValue(A);
if (a->IsFinalTransposeInSequence()) {                   //  @0x1c8a025b
    VxposeMode vx = a->vxpose_mode();                    //  @0x1c8a0267
    CHECK(IsTranspose(GetXluInstrType(A)));              //  else FATAL line 322
    int h = a->GetTransposeHeight();                     //  @0x1c8a0292
    CHECK(IsTranspose(GetXluInstrType(A)));              //  redundant guard, FATAL line 328
    int w = a->GetTransposeWidth();                      //  @0x1c8a02b9
    return (*(this->vtable + 0x10))(this, vx, fromType, toType, mxuIdx, h, w);  // virtual @0x1c8a02d7
}
// non-final: read the static cell directly (the other path)
return *((u32*)this + 18*fromType + 3*toType + mxuIdx + 2);   // == base + 72*from + 12*to + 4*mxuIdx + 8

vxheightwidth 全部来自最终转置 op A,从不来自 BmxuIdxMXU 实例轴(端口不对称性),与 vx(数据格式轴)是分离的关注点 — 它们是不同维度,只是容易混淆,因为二者最终都会成为同一个调用的参数(见 VxposeMode 与单元格索引说明)。

按 Generation 划分的公式

三个延迟表子类都会重写 vtable +0x10 槽。它们共享静态单元格读取,只在塑造占用项的方式上不同。来自反编译的逐字节形式如下:

c
// base Jellyfish / GhostLite  @0x1c8a0640
long XposeXLUReservationLatency(vx, from, to, mxuIdx, height, width) {
    if ((unsigned)(from - 2) >= 3)  FATAL("IsTranspose(earlier)", latency_table.cc:335);
    if (to     >= 6)  ud1;                       // bound check
    if (mxuIdx >= 3)  ud1;                        // bound check
    int cell  = *(int*)(this + 72*from + 12*to + 4*mxuIdx + 8);   // raw static cell
    int shape = (width - height) / (int)(2 * ElementCount(vx));   // SIGNED idiv @0x1c8a0690
    if (shape <= 0) shape = 0;                    // cmovle to 0
    return cell + shape;                          // NO additive constant
}

// Viperfish  @0x1c8a4e60   (vtable +0x10, thunk @0x1c8a4f00)
long XposeXLUReservationLatency(vx, from, to, mxuIdx, height, width) {
    if (!IsTranspose(from))  FATAL("IsTranspose(earlier)", latency_table_vf.cc:1038);
    int cell  = XluConflictPenaltyBetween(from, to, mxuIdx);   // == raw cell @0x1c8a0180
    int shape = width - height;
    if (shape <= 0) shape = 0;                    // cmovg
    return cell + shape + 7;                       // +7 transpose-setup; NO throughput divisor
}

// Pufferfish  @0x1c8a13e0   (vtable +0x10, thunk @0x1c8a1480)
long XposeXLUReservationLatency(vx, from, to, mxuIdx, height, width) {
    if (!IsTranspose(from))  FATAL("IsTranspose(earlier)", latency_table_pf.cc:62);
    int tmp = (width - height) + XluConflictPenaltyBetween(from, to, mxuIdx);   // NO clamp, NO divisor
    if (tmp < -5)  tmp = -6;                       // cmp $0xfffffffb / mov $0xfffffffa / cmovl
    return tmp + 7;                                // floor: result >= 1 (when tmp<-5 -> 1)
}

边界(to < 6mxuIdx < 3)和单元格地址算术,与静态表读取器 XluConflictPenaltyBetween(from, to, mxuIdx) @0x1c8a0180 逐字节相同(*(base + 72*from + 12*to + 4*mxuIdx + 8))。base 形式内联单元格读取;VF/PF 调用访问器 — 但读取的是同一个单元格。from − 2 >= 3 测试是内联的 IsTranspose:转置 op 必须是 XluInstrType ∈ {2,3,4}

解释

gen形状项常数下限
base / GLmax(0, (width − height) / (2·ElementCount(vx)))max(0,·) 隐含 ≥ 0
Viperfishmax(0, width − height)+7≥ 7
Pufferfish(width − height)(不 clamp)+7≥ 1(通过 tmp ≥ −6
  • 主导成本是静态冲突惩罚单元格 — 最坏情况结构冒险。
  • 在 base/GL 路径上,占用加数是非对角元素数量 (width − height) 除以每模式转置吞吐量 2 × ElementCount(vx)2·ElementCount(vx) = {2,4,8,2,4} 是跨 lane 引擎在该模式下每周期移动的元素数;(width − height) 是必须通过它排出的元素数;二者的商是额外占用周期。最宽的未打包 B32(除数 2)成本最高;密集打包的 B8(除数 8)成本最低 — 打包因子就是吞吐速度提升。
  • 方形转置width == height)只支付静态单元格(VF/PF 上再加上按 generation 的 +7);形状项 clamp 到 0。
  • VF 和 PF 去掉除数(将转置建模为 1 element/cycle),并改为增加一个平坦的 +7 转置设置常数。PF 还会额外取下限:如果 cell + (width − height) < −5,它会 clamp 到 −6,因此返回值 ≥ 1。这可以防止深度负值的静态单元格把保留压到低于一个周期。

数值示例

Base / GhostLite — 一个最终 Compressed B8 转置(vx = 2ElementCount = 4)馈入一个 permute,height = 8width = 512mxuIdx = 0

text
shape  = (512 - 8) / (2*4) = 504 / 8  = 63        result = cell + 63

同一个转置若为未打包 B32vx = 0ElementCount = 1):

text
shape  = (512 - 8) / (2*1) = 504 / 2  = 252       result = cell + 252

B8 打包让相同转置在 XLU 占用周期上便宜 — 正好是 ElementCount 比率 4/1

Viperfish — 一个最终 B32 转置,height = 128width = 128(方形):

text
shape  = max(0, 128 - 128) = 0        result = cell + 0 + 7 = cell + 7

方形转置只支付静态单元格加 7 周期设置;高/宽不等的转置会再支付 (width − height)


VxposeMode

目的

VxposeMode 是转置数据格式枚举:它命名元素宽度以及该转置是否为 segmented,并且是 base 保留公式中每模式吞吐量除数的唯一输入。它作为一个单字节字段存储在转置 LloInstruction 上。

枚举

五个序号,经三种独立方式确认 — 字符串表、ElementCount 打包因子以及 XluInstrType 子表全部一致。来自 VxposeModeString @0x1d629f60(五个 switch case,内联字符串写入)、ElementCount @0x1d62a1400xb53c830 处的 int[5]xxd = 01 00 00 00 02 00 00 00 04 00 00 00 01 00 00 00 02 00 00 00),以及 0xa2dcce0 处的 GetXluInstrType 转置子表(xxd = 02 00 00 00 03 00 00 00 04 00 00 00 02 00 00 00):

序号VxposeModeStringElementCount每个 32-bit lane 的打包元素XluInstrType
0"B32"11(未打包 32-bit)2 = kTransposeB32
1"Compressed B16"22(打包 16-bit)3 = kTransposeB16
2"Compressed B8"44(打包 8-bit)4 = kTransposeB8
3"Segmented B32"11(segmented 32-bit)2 = kTransposeB32
4"Segmented B16"22(segmented 16-bit)3 = kTransposeB16(默认;子表大小 4)

ElementCount 是每个 32-bit lane 中的打包元素数量:B32 → 1B16 → 2B8 → 4。字符串表 case 0 将字面量存为三个字节(0x3342 然后 '2'"B32");case 1–4 是对命名字面量的 strcpy。该子表对 vx ∈ {0,1,2,3} 直接按 vxpose_mode 索引;GetXluInstrType @0x1c89ff20 读取 subtable[vx],并将 vx ≥ 4 clamp 到 XluInstrType = 3kTransposeB16),因此 Segmented B16 表现为 kTransposeB16

存储位置 — vxpose_mode()

LloInstruction::vxpose_mode() @0x1d4e7440 从 instruction 上读取单个字节。逐字节如下:

c
// LloInstruction::vxpose_mode()  @0x1d4e7440
VxposeMode vxpose_mode() const {
    if ((WORD[this] & 0xFFFE) == 0xA6)            // opcode 0xa6 (Vxpose) or 0xa7 (VxposeBinary)
        return BYTE[this + 0x44];                  // the VxposeMode byte
    FATAL("LloOpcodeIsTranspose(opcode())");       // llo_instruction.cc:3367
}

掩码 & 0xFFFE 让该测试覆盖 0xa6kVectorTranspose)和 0xa7kVectorTransposeBinary)二者 — 这对 opcode 只在 bit 0 上不同。VxposeModeLloInstruction + 0x44 处的字节,仅对这两个 opcode 有效;在任何其他 opcode 上读取它都会触发硬 FATAL

按 Target 划分的支持 — SupportsVectorXpose

某个 generation 是否能发出给定 VxposeMode,由 Target::SupportsVectorXpose(VxposeMode) 控制。逐字节来自每个按 generation 重写的版本:

Target(gen)SupportsVectorXpose(vx)接受
JellyfishTarget @0x1d48f780vx == 0B32
GhostliteTarget @0x1d497160vx < 3B32Compressed B16Compressed B8
ViperfishTarget @0x1d49a000vx != 2Compressed B8 外全部
PufferfishTarget @0x1d4940a0vx != 2Compressed B8 外全部
Target(base)@0x1d61ce00abstract

注意 — PF/VF 的 SupportsVectorXpose 掩码是 mode != 2:PF/VF 支持Compressed B8 外的每种模式vx == 2),而不是只支持 B8。这与 Pufferfish 转置 emitter 一致,后者会用 InvalidArgument("compressed B8 format is not supported on PxC") 拒绝 Compressed B8。(如果误判 setne/sete 极性,ICF-folded 的 cmp esi,2; ret thunk 可能会被读成 mode == 2;反编译体是 return a2 != 2。)完整模式集见 XLU op 清单

注意 — segmented 模式仅 Pufferfish。 没有 generation 报告 SupportsVectorXpose 支持 Segmented B32/Segmented B16vx 3/4)— base = vx==0,GL = vx<3,VF/PF = vx!=2,后者确实接受 3/4。segmented ISA 编码只存在于 deepsea PxC(Pufferfish)指令集中;在其他 generation 上,segmented 模式只能通过子表默认臂到达,而不是通过已确认的 emitter 到达。它们的 ElementCount {1,2}XluInstrType 映射已钉住,但其保留成本只在 Pufferfish 转置上被执行。

VxposeMode 不是单元格索引

一个微妙陷阱:XposeXLUReservationLatency 接收 vx(一个 VxposeMode以及 mxuIdx(静态 6×6×3 单元格的第三个索引),二者是不同的轴:

  • mxuIdx 是物理 MXU 实例 id(unit_id & 3,约束 < 3)— XluConflictPenaltyTable[from][to][mxuIdx] 的第三维,用于建模每端口冒险不对称性。
  • vx 是转置数据格式 — 它只在 base 形状除数中馈入 ElementCount(vx);它从不索引静态单元格。

静态单元格的第三个索引是 MXU 实例,而不是转置模式。使用 VxposeMode 索引冲突惩罚单元格的重新实现是错误的。


MxuStat — 装箱器运行状态

目的

转置 op 所属的 MXU/latch 序列会由一个贪心最小 makespan 装箱器(AssignMxusForSequenceGroupInternal @0x10f77ca0)分配到物理 MXU。MxuStat 是该装箱器读写的每 MXU 运行状态记录:每个物理 MXU 一个(Jellyfish 有 4 个)。它记录累积 makespan,以及占用该 MXU 的序列组成的按时间排序 map,每个序列都有一个 busy interval — 这是序列放置时转置保留成本所针对的状态。

布局

MxuStat 为 40 字节(sizeof = 0x28),由数组初始化循环 @0x10f77d30(每次迭代写入五个字段,然后前进 5 个 qword = 40 字节)以及计数算术 (end − 40) / 0x28 + 1 @0x10f7910d 逐字节确认:

c
struct MxuStat {                       // 40 bytes; one per physical MXU (Jellyfish = 4)
    long          accumulated_latency; // +0x00  init 0     running per-MXU makespan term (read in the score)
    CycleTable*   cycle_table;         // +0x08  init arg    shared back-ref to the CycleTable arg
    btree_node*   root;                // +0x10  init &EmptyNode   absl::btree_map<int, SequenceInfo> root
    btree_node*   rightmost;           // +0x18  init &EmptyNode   btree rightmost-node cache
    size_t        size;                // +0x20  init 0      btree element count
};

初始化循环对每条记录写入:*p = 0(accumulated_latency)、p[1] = cycle_table_argp[2] = p[3] = &EmptyNode(VA 0x2181cb90 处的 absl btree empty sentinel)、p[4] = 0(size)。嵌入在 MxuStat + 0x10btree_map<int, SequenceInfo> 以 int 为 key 存储每个序列,并存储其 SequenceInfo 值;每个 btree slot 是一个 0x48 字节的 pair<const int, SequenceInfo>(int key 在 slot+0,value 跟在后面)。成本函数只读取 value 的 busy interval — busy_start 位于 pair +0x38busy_end 位于 pair +0x40。完整 SequenceInfo 记录(其 latch_latency 和两个 owning vector<int>)记录在 MxuSequence / SequenceInfo;本页只钉住顶层 MxuStat 布局,以及成本模型消费的区间。

成本函数遍历的 btree 节点布局是标准 absl::btree_nodenode+0x0a = 元素数量(u8),node+0x0b = is-internal 标志(u8,0 ⇒ leaf),node+0x10 = 第一个 slot(stride 0x48),node+0x130 = child-pointer 数组(仅 internal 节点)。

区间扩展成本 — LatchLatencyChangeAfterAdding

MxuStat::LatchLatencyChangeAfterAdding @0x10f7f3e0 是每个 (MXU, new-sequence) 的增量:当新的 latch/matmul 序列插入其按时间排序的位置时,MXU 的 occupied window 会增长多少额外 busy 周期。它定位 key == arg 的 slot 及其前驱,然后计算区间扩展增量。逐字节如下(尾部 @0x10f7f5d5):

c
// MxuStat::LatchLatencyChangeAfterAdding(int key, long new_val, long free)  @0x10f7f3e0
//   locate slot with key==arg  -> found_busy_start  (= found_slot interval start)
//   locate predecessor of key  -> pred_busy_end     (= pred_slot interval end)
//   CHECK_EQ(new_val == pred_slot.latch_latency)    // "latch_latency == prev_it->second.latch_latency"
//                                                    //  FATAL mxu_latency_balancing.cc:236
long c  = max(0, new_val          - pred_busy_end);  // cmovle to 0
long x  = max(0, found_busy_start - free);           // cmovle to 0
long y2 = max(0, found_busy_start - pred_busy_end);  // cmovle to 0
return (x - y2) + c;                                 // the interval-extension delta

反编译器从定位到的 btree slot 上按 qword 偏移 9·idx + 9found_busy_start)和 9·idx + 10pred_busy_end)读取 busy 字段 — slot stride 为 9 qword = 0x48,也就是 SequenceInfo 区间对。第 236 行的 CHECK_EQ 断言候选的 latch_latency 与前驱记录值匹配。

贪心选择循环

选择循环 @0x10f784d0 会为每个 MxuSequence 选择使结果 makespan 最小的 MXU。逐字节如下:

c
long best = 0x7FFFFFFFFFFFFFFF;        // running min makespan
int  argmin = current_best;
for (int i = 0; i < num_mxus; i++) {   // num_mxus = Target MXU count (Jellyfish = 4)
    long delta = mxus[i].LatchLatencyChangeAfterAdding(key, new_val, free);
    long score = delta + free + mxus[i].accumulated_latency;   // accumulated = MxuStat+0x00
    if (best <= score) argmin = current_index;   // cmovle — smaller index wins ties
    if (best >  score) /* mark improved */ ;
    best = min(best, score);                       // cmovge
    /* advance mxus by stride 0x28 */
}
// assign sequence -> argmin MXU

MxuStat 条目之间的 stride 是 0x28(40 字节),再次确认了该布局。score 将区间扩展 delta、free-window free 以及 MXU 的 accumulated_latency 相加;结果 makespan 最小的 MXU 获胜,平局偏向较小索引。转置保留延迟会经由为每个序列的 busy interval 播种的 CycleTable 馈入此 makespan。

第二遍再平衡 MxuStat::LatencyChangeIfMoveTo @0x10f7fb40 会重新评估把已放置序列移动到另一个 MXU 的代价(读取同一个 busy_start/busy_end 区间,并在目标处 tail-call LatchLatencyChangeAfterAdding)。它用 FATAL("it != sequences_.end()", mxu_latency_balancing.cc:267) 防护 missing/self move。第 2 遍是迭代到不动点还是只运行一次改进交换尚未钉住(INFERRED single pass)。


函数映射

函数地址作用
jellyfish::…::XposeXLUReservationLatency0x1c8a0640base/GL 动态保留;cell + max(0, shape/(2·EC))
viperfish::…::XposeXLUReservationLatency0x1c8a4e60VF 重写;cell + max(0, w−h) + 7(thunk 0x1c8a4f00
pufferfish::…::XposeXLUReservationLatency0x1c8a13e0PF 重写;floor-1、+7、无除数(thunk 0x1c8a1480
XluConflictPenaltyBetween(LloValue*, LloValue*)0x1c8a01c0分发器;在 IsFinalTransposeInSequence 上选择动态路径
XluConflictPenaltyBetween(InstrType, InstrType, uint)0x1c8a0180原始静态单元格读取器 base + 72·f + 12·t + 4·m + 8
IsTranspose(XluInstrType)0x1c8a04e0(t − 2) < 3{2,3,4}
GetXluInstrType(LloValue*)0x1c89ff20op → XluInstrType;转置子表 0xa2dcce0 = {2,3,4,2}
VxposeModeString(VxposeMode)0x1d629f605-case enum-name 表
ElementCount(VxposeMode)0x1d62a1400xb53c830 处的 int[5] = {1,2,4,1,2}
LloInstruction::vxpose_mode()0x1d4e7440对 op 0xa6/0xa7 读取 byte[inst + 0x44]
JellyfishTarget::SupportsVectorXpose0x1d48f780vx == 0
GhostliteTarget::SupportsVectorXpose0x1d497160vx < 3
ViperfishTarget::SupportsVectorXpose0x1d49a000vx != 2
PufferfishTarget::SupportsVectorXpose0x1d4940a0vx != 2
AssignMxusForSequenceGroupInternal0x10f77ca0装箱器;初始化 0x10f77d30,选择 0x10f784d0
MxuStat::LatchLatencyChangeAfterAdding0x10f7f3e0区间扩展增量 c + x − y2(FATAL 236)
MxuStat::LatencyChangeIfMoveTo0x10f7fb40第 2 遍再平衡评分(FATAL 267)

尚未钉住的内容

  • 完整的 SequenceInfo 成员清单(+0x08/+0x18 处的两个 owning vector<int>,以及 +0x00 处的 latch_latency):布局逐字节精确,但哪个 int-vector 是 instruction-set list、哪个是 result-chunk list,是从构建点来源推断的。记录在 MxuSequence / SequenceInfo。元素语义为 LOW。
  • VF/PF 是否有意将转置建模为 1 element/cycle(去掉的 /(2·ElementCount) 除数),还是将吞吐量折入按 generation 的 +7/floor 常数 — 二者都是字节精确;设计动机是推断的。
  • CycleTable::Instruction 的逐 instruction cycle 访问器([vtable+0x10]),它为每个序列的 busy_start/busy_end 播种:求和循环是字节精确的,但 Instruction 记录体和访问器返回值是基于类型名采信的。
  • 第 2 遍再平衡终止条件(单次改进交换 vs 迭代到不动点):LatencyChangeIfMoveTo 控制流是字节精确的;外层循环边界为 INFERRED single pass。
  • Segmented B32/B16vx 3/4)保留成本只在 Pufferfish 转置上可达(segmented ISA 仅 PxC);这里尚未由其他 generation 上的已确认 emitter 执行。

交叉引用

  • XLU 冲突惩罚表 — 该项所加到的静态 6×6×3 单元格、XluInstrType 枚举,以及消费侧 LatencyBetweenXposeInstrAndResult 边。
  • XLU Op 清单 — 跨 lane op 家族、转置 slot-fit 谓词中的 VxposeMode/ElementCount 几何,以及 Vxpose/VxposeBinaryCompressedB16 factory。
  • XLU Reemit 成本CyclesAddedByXluOperation,combine/reorder 阶段消费的边际延迟表达式。
  • XLU Combine / Source-BusComputeCombinablePairs 以及 XLU 优化器运行的 source-bus pack。
  • MXU 延迟概览 — MXU 侧保留模型,其 MxuLatencyTable 为 matmul/latch 占用定价;这是本转置保留项的同级项。
  • MxuSequence / SequenceInfo — 装箱器存储在每个 MxuStat btree 中的完整每序列记录,以及 set_mxu 提交。