Skip to content

tpu → LLO ODS 降低

本页所有地址、符号和偏移都适用于 libtpu-0.0.40-cp314 wheel 中的 libtpu.so(build-id 89edbbe81c5b328a958fe628a9f2207d,781,691,048 字节,未 strip,.text VA == 文件偏移)。其他版本会有所不同;请将每个 VA 都视为绑定到该版本。

摘要

createLowerToLLOPass (0x11203ba0) 是 MLIR FunctionPass,它把 tpu 方言降到 LLO 方言,即进入 bundle packer 之前的最后一个方言层级。配套页面 MHLO → XTile → tpu 覆盖的是进入 tpu 的下降过程;本页覆盖的是从 tpu 出来并进入 LLO 的下降过程,尤其是重实现者需要、但 pass 形状概览没有承载的三类产物,它们都是复现该 lowering 的核心:LLO 目标的逐 op ODS 签名(操作数/属性顺序)、MXU 重写穿过 matmul 三联 op 传递的增益/暂存寄存器表,以及 LowerToLLO 转换 pattern 的逐 op 发射逻辑

本页所依赖的核心事实是:每个 mlir::llo::FooOp 的 ODS 操作数/属性声明,都可以从其生成的 build/create 工厂符号中逐字恢复。TableGen 会为每个声明的 OpBuilder 发射一个 build(OpBuilder&, OperationState&, <args>) 静态方法,而 demangle 后的 C++ 参数列表,在两个 MLIR 机制性前导参数之后,正好就是源顺序中的操作数+属性声明。Value → operandType/TypeRange → explicit result<Enum>Attr / unsigned / bool / ArrayRef → attribute。共有 322 个不同的 mlir::llo::*Op 类;301 个带有 typed build create,因此对绝大多数 op 来说,ODS 形状不是推断出来的,而是从二进制读出来的。

LLO 是一种寄存器机 ISA 方言,而不是张量方言:一个 llo.* SSA 值就是一个原生 vreg(每个 bundle 中的一个 VPU/MXU/Vmem slot),mask 是 llo::VectorMaskType 寄存器文件,标量谓词是 llo::PredicateType。读者应当带着熟悉的 MLIR 方言转换框架来读本页,即 RewritePatternConversionTargetTypeConverterapplyFullConversion,并把本页看作这些位置的 LLO 专用填充。凡是 LowerToLLO 偏离教科书式 applyPartialConversion lowering 的地方(它使用全量转换、把函数视为闭合叶子,并把 constant-slot 选择下推给 packer),本文都会指出。

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

  • ODS 签名提取规则 — 如何把 build/create 工厂参数列表转成操作数/结果/属性声明,以及对约 95 个使用推断 builder 的 elementwise op 的 [GEN] fallback。
  • 增益/暂存寄存器模型 — 三个 MXU 枚举(MatmulModeGainMatrixRegisterMatrixStagingRegister)加上 GainLatchMode,哪个 LLO op 携带哪个,GetGainLatchModeAndScalingFactor 选择器,以及 Lgmr/Msra 硬件 ISA 形式映射。
  • arith.constant legalizer — 确定性的类型分发决策树,以及为什么这里做 slot 选择。
  • 四个复合重写all_reduceprng_random_bitsstochastic_convert_elementwisecreate_subelement_mask — 以 LLO op multiset 的深度展开。
Pass 工厂mlir::tpu::createLowerToLLOPass(xla::jellyfish::Target const&)0x11203ba0
Pass 入口LowerToLLOPass::runOnOperation()0x11204200(0xa1ef 字节函数体,约 40 KB,结束于 0x1120e3ef
Pass CLI 名称lower-to-llo.rodata anchor)
驱动器mlir::applyFullConversion (0x1c958ac0) — 不是 partial
IR 输入 / 输出tpu + arith/math/vector/memref/cfllo + 结构性 scf/func/memref
LLO 目标数量322 个不同的 mlir::llo::*Op
ODS 来源覆盖301/322 typed buildcreate;21 个 default-builder([SIB])
MXU 寄存器枚举MatmulMode round/high/lowGainMatrixRegister gmr0..3MatrixStagingRegister MSRA/MSRBGainLatchMode(xpose×dtype)
下游消费者LLO bundle packer — MXU 槽, Immediate 槽

ODS 签名模型

目的

本单元确立本页其余部分依赖的解码规则:demangle 后的 build/create 符号如何变成 ODS 签名。没有它,下面的签名表看起来只是断言;有了它,它们就是对二进制的机械读取。

算法

TableGen 生成的 MLIR op 会为每个声明的 OpBuilder 带上一个静态 build 方法以及一个 create 转发器。首个非 generic builder 的 demangle 签名就是事实标准 ODS 形状:

c
// build(OpBuilder&, OperationState&, <ODS args in declaration order>)
// create(OpBuilder&, Location,      <same ODS args>)
//
// Decode each trailing arg → ODS role:
mlir::Value                  -> 1 SSA operand
mlir::ValueRange             -> variadic operand list
mlir::Type                   -> 1 explicit result type (inference-free op)
mlir::TypeRange              -> multiple / variadic result types
mlir::<X>Attr (IntegerAttr…) -> 1 typed attribute
llo::<Enum> / llo::<Enum>Attr-> 1 enum attribute (GainLatchMode / MatmulMode /
                                MatmulDataFormat / VpackFormat / SequencerType…)
unsigned int / unsigned long -> 1 integer attribute (count / size / mxu-id)
bool                         -> 1 unit/bool attribute (flag)
llvm::ArrayRef<int|long>     -> 1 dense-array attribute (shape / strides)
StringRef / StringAttr       -> 1 string attribute
```text

如果某个 builder 的*唯一*形式是 generic `(TypeRange, ValueRange, ArrayRef<NamedAttribute>)`,说明该 op 使用 **default** builder:结果类型会被推断(`InferTypeOpInterface` / `SameOperandsAndResultType`),具体操作数数量则从 op 名称族读取(unary = 1,binary = 2)。这些在下文标为 **[GEN]**

> **注意 —** [GEN] 与 typed 的分裂可以直接观察到。reduce 族让这一点很清楚:`VectorAddReduceS32Op::build(…, Value)` (`0x13f97a20`) 是 *typed* 形式,即一个显式 `Value` 操作数;而它的兄弟 `VectorAddReduceF32Op::build(…, ValueRange, ArrayRef<NamedAttribute>)` (`0x13f970a0`) 是带推断结果的 *generic* [GEN] 形式。同一个 op 族,两种 builder 形状,二者都在二进制中确认;整数类型 reduce 固定其操作数,浮点 reduce 则推断它。

### 函数映射

| 来源 | 数量 | 含义 |
|---|---|---|
| `mlir::llo::*Op` 类 | 322 | 不同的 LLO 目标(与 `tpu` 方言清单中的 LLO 数量匹配) |
| `*Op::build(` 符号 | 231 | 215 个不同 op 上共有 225 个 typed + 6 个 generic 出现 |
| `*Op::create(` 符号 | 329 | 301 个不同 op 由 `build` 或 `create` 覆盖(每个有 `build` 的 op 也有 `create`) |
| default-builder op | 21 | 没有 typed factory;签名取自兄弟 op([SIB]) |

> **怪癖 —** 对约 95 个 elementwise 标量/向量算术和超越函数 op 来说,builder 会*省略*结果 `Type`,因为该 op 声明了 `SameOperandsAndResultType`。因此它们的结果类型不在工厂签名中;它要从 op 名称中的 `F32`/`BF16`/`S16`/`S32`/`U32` 后缀恢复,并由 `verifyInvariantsImpl` 确认。重实现者必须从名称而不是 builder 恢复 `let results =` 约束。

---

## 逐 Op ODS 签名

完整表有 322 行;逐字粘贴会违反 dump 规则。因此,下面每个族给出其**形状语法**(该族共享的 operand/attr 模式)以及签名已由二进制确认的代表行。图例:`V`=Value operand,`VR`=ValueRange(variadic),`T`=Type result,`TR`=TypeRange,`A`=typed Attr,`u`=unsigned int-attr,`b`=bool flag-attr,`AR`=ArrayRef dense-array attr,`Str`=string attr,`[GEN]`=inference builder,`[SIB]`=sibling-recovered。

### 结构 / 控制 / 内存 / DMA

结构族中显式 `Type` builder 占主导(这些 op 没有结果类型推断)。最重的是 `EnqueueDMAOp`,即 `tpu.enqueue_dma` 的 LLO 实现。

```text
ConstantOp        : T, Attribute                         (result, value)
AllocaSmemOp      : T, IntegerAttr                        (result, size)
AllocaSyncFlagOp  : T, u                                  (result, count)
AllocaVmemOp      : u                                     (size → vmem ref)
AddrScaledOp      : V, V, IntegerAttr                     (base, index, scale)
AssumeMultipleOp  : V, u                                  (value, multiple)
DMADoneOp         : V, V, b                               (sflag, dma, is_remote)
EnqueueDMAOp      : V,V,V,V,V, AR<int>,AR<int>, VR, V,V, SequencerType, u, b
                    (src, dst, srcoff, dstoff, sflag, src_strides, dst_strides,
                     dyn_sizes, deviceid, coreid, seq, count, remote)
ErrorIfOp         : V, StringAttr                         (pred, message)
LogicalDeviceIdOp : T   ;  ChipIdOp / CoreIndexOp : ()    (i32 results)
RegionOp          : TR  ;  YieldOp : VR
TraceOp           : TR, StringAttr, IntegerAttr           (region; name, level)

EnqueueDMAOp::build 签名在 0x13f64100 按字节确认(build(OpBuilder&, OperationState&, Value, Value, Value, Value, Value, ArrayRef<int>, ArrayRef<int>, ValueRange, Value, Value, SequencerType, j, b)):五个 SSA 操作数(src/dst/srcoff/dstoff/sflag)、两个 dense-array stride 属性、一个 variadic dynamic-size 操作数列表、两个跨芯片路由操作数,随后是 SequencerType 枚举 + count + remote 标志。方言转换驱动器把实际 tile 分解(rolled/retiled loop nest)推入共享的 LowerPassBase helper;见 LowerToMlo DMA Bridge-Cast(DMA 桥接转换)

标量地址 / load / store / ALU

Scalar* op 对 SPU 建模。二元 ALU op 分成两种 builder 形状:bitwise/shift 形式接受 (V, V)(没有显式 Type,结果被推断),少数带符号类型的 op 则携带显式结果 T

text
ScalarAddress{Smem,Vmem,Cmem,Hbm,Sflag}Op : V, V          (base, offset)
ScalarLoadOp   : T, V, V        ScalarStoreOp : V, V
ScalarToVectorOp : T, V (broadcast)   ScalarBitcastOp : T, V
ScalarSelectOp : T, V, V, V     (pred, t, f)
ScalarAddS32Op / ScalarMulU32Op / ScalarBitwise{And,Or,Xor}Op /
  ScalarShll/Shra/ShrlOp / ScalarFloor{Div,Rem}S32Op       : V, V
ScalarSubS32Op : T, V, V
ScalarCmp{Eq,Ge,Gt,Le,Lt,Ne}{F32,S32,U32}Op : V, V → i1
Scalar{Abs,Add,Sub,Mul,Div,Max,Min,Rem,Neg}F32 + transcendentals : [GEN]
ScalarConvert{S32ToF32,U32ToF32,F32ToU32,F32ToS32}Op : T, V
ScalarConvert{F32ToNarrowFloat,NarrowFloatToF32}Op   : T, V, T  (value, narrow-type)
```text

标量 ALU 通过 `ScalarElementwisePattern<>` 模板族(45 个实例化)映射 `arith`/`math` 源 op。完整 source→target 表位于 pass 形状配套页面;本页只断言 *LLO 侧*形状。

### 向量 elementwise / convert / pack / mask

向量算术绝大多数是 [GEN]。显式 `T` 的例外是比较 op(它们产生与操作数类型不同的 *mask* 类型,因此不能应用 `SameOperandsAndResultType`)以及少数 bitwise/shift op。

```text
VectorAddF32 / VectorAddS32 / VectorMulF32 / VectorMulBF16 / VectorOrU32 / VectorXOrU32 : V, V
VectorAndU32 / VectorShiftLeftLogical / VectorShiftRight{Arithmetic,Logical} : T, V, V
Vector{Add,Sub,Mul,Max,Min,Div,Rem,Neg}{BF16,F32,S16,S32,U16,U32} (no explicit-T) : [GEN]
Vector{Abs,Ceil,Cos,Erf,Exp,Floor,Log,Log1p,Pow,Pow2,Round,RoundEven,Rsqrt,
       Sin,Sqrt,Tan,Tanh,Trunc}{F32,BF16}, VectorAtan2,
       VectorCountLeadingZeros, VectorPopulationCount                       : [GEN]
VectorCmp{Eq,Ge,Gt,Le,Lt,Ne}{BF16,F32,S16,S32,U32}Op : T, V, V → mask
VectorConvert{S32ToF32,U32ToF32,F32ToU32,F32ToS32}Op : T, V
VectorConvertF32To{If8,E4M3,E5M2,Bf16}StochasticOp   : T, V, V   (value, dither)
ConvertVectorF8NegativeZeroToZeroOp : T, V
VectorPackOp   : T, VpackFormat, V, V       VectorUnpackOp : T, u, VpackFormat, V
VectorMaskAndOp : T, V, V   VectorMaskNegateOp : T, V   VectorMask{Or,Xor}Op : [GEN]
VectorCreateMaskOp : T, u, u, u, u          (4 bound attrs)
VectorCreateSublaneMaskOp : T, V
VectorSelectOp : T, V, V, V                 (pred, true, false)

VectorCreateMaskOp::build(…, Type, m, m, m, m)0x13fb38e0 按字节确认:一个结果 Type 加四个 unsigned long bound 属性(≤2 维时每维的 [start,end] 对)。stochastic-convert 工厂在 0x13fae680If8)、0x13fad180Bf16)、0x13fad880E4M3)、0x13fadf80E5M2)确认,每个都是 create(…, Type, Value, Value):结果类型 + value + 每 lane dither,正是 stochastic-round 复合重写所需的 2 操作数形状。mask-type 向量 op 经过 M-Register 文件 路由。

Lane / sublane shuffle / transpose / reduce

text
VectorLaneSeqOp / VectorLaneSeq{Compressed,Interleaved}B16Op : T   (0 operands, 1 lane-index result)
VectorLaneBroadcastOp     : T, V, V, V, BitDataFormat
VectorBroadcastSublaneChunkOp : T, V, V    VectorSublaneReplicateOp : T, V, V
VectorSublaneReverseOp    : T, V           VectorSublaneRotateOp    : T, V, V
VectorSublaneShuffleOp    : T, V, DenseArrayAttr<int>
VectorSublanePermuteOp    : T, V, V, PermSlanePatternGranularity
VectorRotateOp            : T, V, V, IntegerAttr
VectorTransposeOp         : V, VxposeMode, V, u, u, u, IntegerAttr
VectorBitcastOp           : T, V
VectorAddReduceS32Op / VectorMaxReduceS32Op / VectorMinReduceS32Op : V       (typed)
VectorAdd/Max/MinReduce{BF16,F32}Op : [GEN]                                  (1 operand, inferred)
VectorAdd/Max/MinSublaneReduce{BF16,F32,S32}Op : V
VectorMax/MinIndexReduceF32Op : TR, VR, [Attrs]    (2 results: index + value)
```text

`VectorLaneSeqOp` 及其 B16 变体被确认为 `ZeroRegions, OneResult` MLIR op(例如 `0x13f07200` 处的 op model):零操作数、一个结果,匹配 `0` 操作数 ODS。它们是硬件 ISA 助记符为 `vslaneid`/`vxlaneid` 的 LLO op;底层指令工厂是 `LloInstruction::CreateVectorLaneSequence{,CompressedB16,InterleavedB16}`(`0x1d4d0480` / `0x1d4d04c0` / `0x1d4d0500`)。当某个 lowering 写作 `tpu.iota → llo.vslaneid / llo.vxlaneid + add` 时,它指的 LLO *op* 是 `VectorLaneSeqOp` 族;`vslaneid`/`vxlaneid` 是这些 op 的 ISA 级助记符,不是独立的方言 op;B16 iota 则通过 `Interleaved`/`Compressed` B16 变体打包。

---

## MXU 增益 / 暂存寄存器表

### 目的

matmul 三联 op 的 ODS 属性是该 pass 中最密集的重实现风险点:三个*不同*的 MXU 寄存器枚举挂在 matmul op 上,第四个(`GainLatchMode`)挂在 latch op 上。把错误属性放到错误 op 上,会产生 bundle packer 错误打包的 LLO。本单元固定每个枚举、每个承载 op,以及选择值的 selector。

### 四个枚举

| 枚举 | MLIR 助记符 | 成员(二进制字符串) | 作用 |
|---|---|---|---|
| `llo::MatmulMode` | `round` / `high` / `low` | round (`kRound`, normal/value 0), high (`kHigh`, value 1), low (`kLow`, value 2), 以及 `soft_low_of_eight`/`soft_middle_of_eight` 变体 | matmul 执行 f32-on-bf16-MXU 仿真中的哪一轮精度 pass(rounded 还是 high/low mantissa half) |
| `llo::GainLatchMode` | `xpose.*` / `packed_*` | `GAIN_LATCH_MODE_{NONE, NO_XPOSE_F32, NO_XPOSE_HI_F32, XPOSE_F32, XPOSE_HI_F32, XPOSE_LOW_F32, XPOSE_NIBBLE0/1, XPOSE_S4/S8/U4/U8, PACKED_*}` | STATIONARY 操作数如何被 latch(transpose + dtype staging) |
| `llo::GainMatrixRegister` | `gmr` | gmr0, gmr1, gmr2, gmr3 | gains 位于 4 个 GMR bank 中的哪一个 |
| `llo::MatrixStagingRegister` | `msr` | MSRA, MSRB (= `MATPUSH_TARGET_MSRA`/`_MSRB`) | 哪个 MSR 暂存 MOVING 操作数 |

四者都由一次 `Dialect::addAttributes<MatrixStagingRegisterAttr, GainMatrixRegisterAttr, GainLatchModeAttr, MatmulModeAttr, …>` 调用(`0x13e5e860`)注册为 MLIR 属性。属性工厂:`GainMatrixRegisterAttr::get(MLIRContext*, GainMatrixRegister)`(`0x13e4f5c0`,parse `0x13e4f6a0`);`MatmulModeAttr` 经由 `symbolizeMatmulMode`(`0x13e4e660`);存储类 `llo::detail::{GainMatrixRegisterAttrStorage, MatrixStagingRegisterAttrStorage}` 存在。枚举字符串字面量 `GAIN_LATCH_MODE_*`、`DONE_WITH_GAINS_MODE_{NONE,TRANSPOSED}`、`MATPUSH_TARGET_MSR{A,B}` 和 `MRF_SOURCE_MRF_{0,1,2,3}` 都存活在 `.rodata` 中。

> **陷阱 —** `GainMatrixRegister` 和 `MatrixStagingRegister` 不是同一个轴。GMR(gmr0..3)命名 *stationary* gains 所在位置;MSR(MSRA/MSRB)命名哪个双缓冲暂存 *moving* 操作数。把它们折叠成一个“MXU register”属性的重实现,会发射 packer 无法解析到 slot 的 matmul op。

### 哪个 op 携带哪个寄存器

承载映射直接从 MXU op 的 `build` 签名读取;这些就是穿过寄存器的行。

| LLO op | ODS 签名(在 `OperationState&` 之后) | GMR | MSR | mode | `build` VA |
|---|---|---|---|---|---|
| `VectorLatchOp` | `V, GainLatchMode, u(mxu)` | – | – | – | `0x13fbd020` |
| `VectorLatchIOp` | `V, u, GainLatchMode, MatrixStagingRegisterAttr, u(mxu)` | – | yes | – | `0x13fbbf40` |
| `VectorMatprepSubrOp` | `V, GainLatchMode, u(mxu)` | – | – | – | `0x13fcd0a0` |
| `VectorMatprepMubrOp` | `V, MatmulMode, MatmulDataFormat, u(mxu)` | – | – | yes | `0x13fcc120` |
| `VectorMatmulOp` | `V, MatmulMode, u(sublanes), b(transposed), MatmulDataFormat` | – | – | yes | `0x13fcad80` |
| `VectorMatmulMubrOp` | `V, MatmulMode, GainMatrixRegisterAttr, MatrixStagingRegisterAttr, u, b, MatmulDataFormat, IntegerAttr` | yes | yes | yes | `0x13fc9520` |
| `VectorMatresOp` | `T(result), MatmulDataFormat, u(sublanes), IntegerAttr(align)` | – | – | – | `0x13fce2a0` |
| `VectorDoneWithGainsOp` | `u(mxu)` | – | – | – | – |

规范的 conv/dot matmul(`.mubr` 形式)在*一个* `VectorMatmulMubrOp` 上携带完整的 `{MatmulMode, GMR, MSR, sublane_count, transposed, MatmulDataFormat, alignment}` 集合。这一点按字节确认:`VectorMatmulMubrOp::build(OpBuilder&, OperationState&, Value, MatmulMode, GainMatrixRegisterAttr, MatrixStagingRegisterAttr, …)` 位于 `0x13fc9520`(create 位于 `0x13fc98e0`)。普通 `VectorMatmulOp`(非 mubr)省略显式 GMR/MSR,并对简单 dot 使用隐式单 GMR/MSR 路径。`VectorLatchIOp` 是唯一显式固定 MSR target 的 latch 形式(`0x13fbbf40` 处的 `build`:`Value, j, GainLatchMode, MatrixStagingRegisterAttr, j`)。`VectorLatchOp`(`0x13fbcfa0`)、`VectorLatchIOp`(`0x13fbbe60`)和 `VectorMatprepSubrOp`(`0x13fcd020`)上的 `getGainLatchMode()` accessor 确认这些 op 携带 `GainLatchMode` 属性。

### 硬件 ISA 形式 ↔ 属性映射

这些方言属性会在发射时解析为具名 MXU ISA 形式。matmul opcode 中的 `Lgmr` 表示“从 GMR 读取 gains”;opcode 同时命名 source GMR 和 staging MSR。

| 硬件 MXU op(VectorExtended ISA) | LLO op + 属性 |
|---|---|
| `LoadMatrixRegisterGmrMsra` / `GmrMsrb` | `VectorLatch(I)` + `GainLatchMode` + MSR ∈ {A,B} |
| `LoadMatrixRegisterGmrWithBf16ConversionMsr{a,b}` | `VectorLatchI` + `GAIN_LATCH_MODE_*_TO_BF16` |
| `MatrixMultiplyBf16Lgmr{Msra,Msrb}[Masked]` | `VectorMatmulMubr` (mode ∈ {round,high,low}, GMR=gmrN, MSR ∈ {A,B}, fmt=bf16) |
| `MatrixMultiply{S4,S8,U4,U8}Lgmr{Msra,Msrb}` | `VectorMatmulMubr` (fmt=int) |
| `MatrixMultiplyF32RoundedLgmr{Msra,Msrb}[Masked]` | `VectorMatmulMubr` (fmt=f32, rounded path) |

`Masked` 变体为 predicated-lane matmul 接受额外的 `Vmask` 操作数。4 个结果 FIFO `MRF_SOURCE_MRF_0..3` 由 `VectorMatres` drain(result-mode 选择哪个 MRF)。这些形式的 slot-bit 编码见 [MXU 槽](../isa/slot-mxu.md)、[Matprep/IAR/Latch 子槽](../isa/slot-matprep-iar-latch.md) 和 [ResultFifo 和 ArchRegister 枚举](../isa/resultfifo-archregister.md)。

### 选择器

```c
// GetGainLatchModeAndScalingFactor(Operation*, VectorType, bool isLhs,
//                                  bool isRhs, Target const&)   @ 0x112433a0
GainLatchMode select_latch(op, vty, isLhs, isRhs, target):
    // element-type dispatch (isF32 / isBF16 / isSignlessInteger callees):
    if vty.isF32():   return one of {NO_XPOSE_F32, HI_F32, LOW_F32}  // split-feed
    if vty.isBF16():  return PACKED_BF16          // after VectorPack of a pair
    if int8:          return NO_XPOSE_{S8,U8}     // after VectorPack low
    if int4:          return NO_XPOSE_{S4,U4} / NIBBLE0/1
    if f8:            return {F8E4M3*_TO_BF16, F8E5M2_TO_BF16}
    // geometry callees: target().LaneCount() / SublaneCount()
    // packing callees: VectorPackOp::create (×2), VectorUnpackOp::create (×4),
    //                  RollVectorsOp::create  (operand packing into one vreg)
    return (mode, scaling_factor)

GetGainLatchModeAndScalingFactor 确认位于 0x112433a0;其 data-format 兄弟 GetMatmulDataFormatAndScalingFactor0x11242b80)选择 MatmulDataFormat。该 selector 返回 (GainLatchMode, scaling) 对。

注意 — 数值型 GMR index(0..3)以及 MSR 的 A/B 交替不是由这个 selector 选择的。它们是 matmul allocator 的逐 tile 分配:GMR index 是一个受 systolic depth 约束的递增计数器,相邻 matprep 按 MSRA → MSRB 交替。该分配存在于 dot/conv→MXU 下降过程中;见 Dot / Conv → MXU 降低。本页的主张限于枚举成员和承载 op(HIGH);逐 (gen, dtype, latch_idx) 的数值调度不在范围内(此处为 LOW,由下游拥有)。


arith.constant 合法化

目的

arith.constant 会存活到 LowerToLLO,并且必须合法化为 llo.constant。此前曾怀疑其决策规则是非确定性的 slot-admission 规则;事实上它是纯粹、确定性的类型 legalizer。本单元固定该决策树,并纠正早先的推断。

算法

lambda 函数体被内联进 0x11223100 处的 __call_func policy thunk(0x340 字节;存在于函数表中)。它唯一的决策是类型测试;它只发射一个 llo.constant,从不选择 slot。

c
// arith::ConstantOp lowering lambda — thunk @ 0x11223100
LogicalResult legalize_constant(op, adaptor, rewriter):
    attr = op.getValueAttr()                        // @0x11223125
    ty   = attr.getType()
    // --- scalar dispatch ---
    if ty.isUnsignedInteger() || ty.isSignlessInteger():  goto INT_PATH
    if ty.isF32():                                        goto EMIT_DIRECT
    // --- vector / splat path ---
    if DenseElementsAttr::classof(attr) && DenseElementsAttr::isSplat(attr)
       && (isRepresentableVectorType(ty) || isMaskVectorType(ty)):
        goto EMIT_DIRECT                             // vector splat
    // --- index path: the ONLY rewrite ---
    if ty.isIndex():
        i32ty = Builder::getI32Type()
        i32a  = Builder::getI32IntegerAttr((i32) IntegerAttr::getInt(attr))
        v = llo::ConstantOp::create(b, loc, i32ty, i32a)   // index → i32
        rewriter.eraseOp(op)
        return success
  INT_PATH:                                          // @0x1122320b
    require IntegerType, signless, width <= 31 (cmp 0x1f)
    // (cmp 0x40 = APInt single-word vs multi-word value storage, NOT a slot test)
    goto EMIT_DIRECT
  EMIT_DIRECT:                                        // @0x112231ce
    llo::ConstantOp::create(b, loc, ty, attr)         // 1 result Type + 1 Attribute
    rewriter.replaceOp(...); return success
  // default: emitOpError(...) -> failure                @0x112233a9
```text

发射出的形状 `llo::ConstantOp::create(OpBuilder&, Location, Type, Attribute)` 匹配 `ConstantOp` ODS `T, Attribute`。`i1`、≤31-bit 的 signless integer、F32,以及 representable/mask dense-splat 向量常量会被**原地**合法化;`index` 常量是**唯一**被重写的常量(重建为 i32,因为 TPU 标量寄存器是 32-bit),原 op 随后被删除。其他任何情况(例如 non-splat dense vector)都会命中 `emitOpError`,因此非法。

> **注意 — 该 lowering pass 是纯类型 legalizer;常量放置稍后决定。** lambda 发射单个 `llo.constant`;该常量的*命运*,即对 0/±1/±0.5/±π/±e 使用 hardwired-constant `ScalarYEncoding` 引用、若适配 16-bit(JF)/ 20-bit(V5+)宽度则使用 bundle immediate slot、否则使用 SMEM constant-pool load,是 bundle packer 中依赖值的 pack-time 决策。见 [Immediate 槽](../isa/slot-immediate.md) 和 [SPU / 标量槽](../isa/slot-spu-scalar.md)。此处 31-bit 的 `cmp 0x1f` 是 IR 层面的 immediate 上限检查,而不是 slot 选择。

---

## 复合重写

### 目的

四个 `tpu` op 会展开成大型且彼此不同的 LLO op multiset,而不是 1:1 目标。每个复合重写的 LLO 集合都从 rewrite-lambda 函数体中的 `llo::*Op::create` 调用点解码而来。理解这个 *multiset*(而不只是主 op)才能让重实现者复现发射出的指令流,并估算其 bundle 成本。

### tpu.prng_random_bits → EmitThreefryRound ×N

`EmitThreefryRound` (`0x1125ada0`) 每轮发射 Threefry-2x32 mix。lane rotate 是**合成**出来的,不是硬件 rotate。

```c
// EmitThreefryRound(Operation*, ConversionPatternRewriter&, VectorType,
//                   Value key, Value ctr, int round)   @ 0x1125ada0
//   add  = VectorAddS32Op(x, y)                        // mix-add
//   rot  = VectorOrU32Op( VectorShiftLeftLogicalOp(x, k),
//                         VectorShiftRightLogicalOp(x, 32-k) )   // (x<<k)|(x>>(32-k))
//   xor  = VectorXOrU32Op(a, b)                        // lane-XOR
//   ConstantOp ×2                                      // rotate amount + add const

对反编译函数体的 grep 确认:VectorAddS32OpVectorShiftLeftLogicalOpVectorShiftRightLogicalOpVectorOrU32OpVectorXOrU32Op 各一个,外加两个 Constant;并且 vrot / VectorRotate 引用为

注意 — lane rotate 通过 VectorShiftLeftLogical | VectorShiftRightLogical | VectorOrU32 合成为 (x << k) | (x >> (32-k));该轮中没有硬件 vrot。每个 prng_random_bits vreg 的 LLO op 总数约为 6 × rounds + fold。相关 ODS:VectorShiftLeftLogicalOp : T, V, VVectorOrU32Op : V, VVectorAddS32Op : V, VVectorRNGSetSeedOp : Vprng_set_seed_32 承载者)。

tpu.stochastic_convert_elementwise → F8/Bf16 stochastic-round family

text
per target format:
  scale         : VectorMulF32Op
  stochastic    : VectorConvertF32To{If8,E4M3,E5M2,Bf16}StochasticOp  (value + dither)
  fix-up -0.0   : ConvertVectorF8NegativeZeroToZeroOp
  NaN/special   : VectorCmpNeF32Op (×2) → VectorSelectOp (×3)
  + ScalarConvert{F32ToNarrowFloat,NarrowFloatToF32}Op, VectorBitcastOp (×2), ConstantOp (×4)
≈ 25 LLO ops; lambda @ 0x1125be00
```text

stochastic `create` 工厂在 `0x13fae680`/`0x13fad180`/`0x13fad880`/`0x13fadf80` 确认,每个都是 `(Type, Value, Value)`;第二个 `Value` 是每 lane 的随机 dither。3 操作数 `VectorSelectOp : T, V, V, V`(pred, true, false)在 rounded result、special-case value 和 passthrough 之间选择。

### tpu.create_subelement_mask → sublane-mask + negate + and

```text
VectorCreateSublaneMaskOp (×1) : T, V
VectorMaskNegateOp        (×1) : T, V      (complement region)
VectorMaskAndOp           (×1) : T, V, V   (AND with per-subelement const mask)
ConstantOp                (×2)
≈ 5 LLO ops; lambda @ 0x11237800

tpu.all_reduce → reductor + comms chain

最重的单个 TPU→LLO 重写(lambda 0x11238820),会展开为约 30 个不同 LLO op。重实现内容是其维度结构,而不是 30 行本身:

备注
reduce-kindadd, max, min, argmax, argminargmax/argmin 使用 VectorMax/MinIndexReduceF32Op(2 个结果)
element-typebf16, f32, s32选择 reductor 后缀(每种 dtype 对应 *F32 typed/[GEN])
reduce-axislane, sublane先发射 lane-reduce,再发射 sublane-reduce
comms / stagingscratch store/load + cross-core shuffleVectorStore[Masked], Vst[Masked]WithArbitrarySlaneStride, Vld…, VectorLoadSublaneShuffle, ScalarAddressVmem (×3)

lambda 按 (reduce-kind × element-type) 选择 reductor,先做 lane 再做 sublane reduce,将 partial 溢出到 scratch VMEM buffer(ScalarAddressVmem + VectorStore),通过 arbitrary-slane-stride store/load(加 masked 变体)跨 core shuffle,然后重新 load 并 finalize。跨芯片 remote reduction 通过 sflag 路径发信号(vsync.add.remote)。reduce-op ODS 确认了前文提到的 [GEN]/typed 分裂:VectorAddReduceS32Op : V(typed,0x13f97a20)对比 VectorAddReduceBF16Op : ValueRange, ArrayRef<NamedAttribute>([GEN],0x13f95b60)。


本页不包含什么

  • 完整 322 行 ODS 表逐字内容 — 这是有意为之(dump 规则)。上面的族语法加上二进制确认的代表行,让重实现者可以从 build/create 符号重建每一行;没有 typed factory 的族(21 个 op,[SIB])继承其兄弟的形状(MEDIUM)。
  • 结果类型约束LLO_Vreg / LLO_Predicate / LLO_Mask 谓词)。build 签名给出 operand+attr 形状,以及存在时的显式结果类型;let results = 谓词位于每个 op 的 verifyInvariantsImpl 中(例如 ConstantOp::verifyInvariantsImpl 0x13f5f320),本文没有逐 op 解码。
  • (gen, dtype, latch_idx) 的数值 GMR/MSR schedule — 由 dot/conv→MXU 下降过程(systolic allocator)拥有;这里只做交叉引用,不重新推导。
  • pass 形状本身TypeConverter callback、MloConversionTarget legal-set、动态 SCF/func legality callback,以及完整的约 242 个 pattern source→target 清单,都是配套概览的材料;本页假定它们存在。

交叉引用