LlvmTpu 内在表
此页面上的所有计数、名称和地址适用于
libtpu-0.0.40-cp314轮中的libtpu.so(构建 ID89edbbe81c5b328a958fe628a9f2207d,745 MB,ELF x86-64,未剥离)。其他 libtpu 构建每代都会添加/删除内部函数; 1356 数字与此版本完全相同。
摘要
TPU LLVM 后端公开 llvm.tpu.* 目标内在函数的平面命名空间 — SparseCore MLIR 方言 (mlir::sparse_core::*) 降低到的堆栈底部 IR 表面,并且 SelectionDAG 指令选择器与之匹配。本附录是该表面的主要枚举:正好 1356 个不同的内在函数,从符合操作的二进制文件中恢复了两种独立的方式(请参阅 §验证)。每个都是 ODS 注册的 MLIR 操作(C++ 类 tpu_X_Y_Z)和 LLVM 内部名称(llvm.tpu.X.Y.Z,下划线→点);两组是相同的。
这是参考目录,而不是算法页面。深层语义 - 槽位布局、降低机构、ISel 匹配器臂、每个引擎描述符编码 - 位于 sparsecore/ 和 isa/ 页面上,该表按系列交叉链接。在这里,重新实现者获得了空间的形状:系列、每个系列的确切数量、每个系列的代表性枚举子集,以及每个系列降低到的 LLO 操作/硬件单元/SparseCore 引擎。
最重要的结构事实:**llvm.tpu.* 表面是 SparseCore 内在 ISA,而不是 TensorCore。**它不包含 MXU/matmul 和 XLU/转置内在函数 - 这些通过单独的 tpu→LLO TensorCore ODS 路径。 llvm.tpu.* 系列以 SparseCore 嵌入流引擎为主(62%),详细信息请参见下面的 备注。
为了重新实现,目录必须捕获:
- 名称↔类双射 — 每个
llvm.tpu.X内在函数都有一个mlir::sparse_core::tpu_X模型,反之亦然;打印名称字符串是带入后端的 LLVM 内部名称。 - 功能分类 — 每个内在函数都属于 ~20 个家族中的一个;所列举的 20 个家庭恢复了 1356 个家庭中的 1341 个,其中约 15 个家庭处于中等置信度家庭边界(参见 §概览)。
- 系列→硬件映射 — 每个系列降低到哪个 LLO 插槽/操作、SparseCore 计算单元或流引擎描述符,以及通过哪个通道。
- 每代变异 - 新一代添加了内在函数(此版本是其目标世代的联合);计数是每个构建的快照。
| 总内在函数 | 1356(两种方式确认,零错配) |
| 印刷名称字符串 | 1356 不同的 llvm.tpu.* 在 .rodata |
| 模型类别 | 1356 个不同的 mlir::sparse_core::tpu_* RegisteredOperationName::Model vtable |
| 名称↔类映射 | 机械:tpu_X_Y ↔ llvm.tpu.X.Y(下划线→点) |
| 注册 | registerLlvmTpuDialectOperations @0x146d0560,10批分注册商 |
| 方言 | mlir::sparse_core::LlvmTpuDialect(构造函数@0x146cde80) |
| MLIR→IR翻译 | convertOperation @0x13933e40 → createIntrinsicCall @0x1683f440 |
| 消耗下降通道 | LowerToSparseCoreLlvmPass::runOnOperation @0x13566d00 |
| 主导家庭 | llvm.tpu.stream.* — 834 次操作 (62%) |
| 表面范围 仅 | SparseCore — 无 MXU,无 XLU 内在函数 |
验证 {#verification}
1356这个数字不是凭信心得出的;它是来自该二进制文件的两个独立恢复的一致点。
- 打印名称字符串。
.rodata打印名称表包含 1356 与^llvm\.tpu\.匹配的不同字符串(例如llvm.tpu.addrspacecast、llvm.tpu.stream.linear.gather.add.f32.hbm.to.tilespmem)。重新探测的注意事项:一些名称带有大写字母(scan2xN、scan1xNf)——[a-z0-9_.]字符类计数不足至 1060;正确的计数需要[^"]或明确的大写余量。 - 模型类 vtables。 符号表保存 1356 不同的
mlir::sparse_core::tpu_*类名(每个内在的RegisteredOperationName::Model<…>注册概念)。 vtable跨度运行tpu_16i1_to_32i1…tpu_wrcbreg_tilespmem_base。 - 设置身份。 将每个类
tpu_X映射到llvm.tpu.X(下划线→点)并与字符串集进行比较会产生零不对称差异 - 每个模型都有一个打印名称,反之亦然。
注意 — 下面的每个系列子计数是来自打印名称字符串的字节 grep 总数,按名称前缀分类。少数操作是可双重分类的(例如,
sc.permute既是通道操作又是 SC 控制操作),因此两名分析师可能会在相邻系列之间转移一个或两个操作; 总数是准确的,并且主要系列(流、打包/解包、vld/vst、等待/观看、dma、扫描、转换)是准确的。带有歧义的家庭行被标记为MEDIUM信心。注意 —
llvm.tpu.*表面包含无 MXU/matmul 且无 XLU/转置置换内在函数。mat的全表 grep 返回 0;对于xlu/transp返回 0。 MXU 和 XLU 操作名册是通过单独的tpu→LLO322-op ODS 路径(参见isa/slot-mxu.md和isa/xlu-op-roster.md)而不是通过llvm.tpu.*实现的 TensorCore 概念。期望llvm.tpu.matmul的重新实现者将找不到它; SparseCore 上的 matmul 握手记录在sparsecore/sc-mxu-handshake.md中。此页面的系列仅是 SparseCore 矢量/标量/内存/流/同步/控制原语。
概览 — 族分类 {#at-a-glance--family-taxonomy}
每个内在函数都分配给一个系列。 20 个枚举的家族行恢复了 1356 个 grep 确认的名称中的 1341 个;其余 15 个位于相邻族之间的中等置信度边界上,并在显式余数行中进行携带,而不是强制分配。 LLO/HW 列是降低目标:SparseCore 重用它的 TensorCore 风格的 LLO 插槽/操作、SparseCore 特定的计算单元或 SparseCore 流引擎。状态:C = 在其他地方进行字节确认的编码,I = 由名称系列标识的引擎,操作码未单独进行字节转储。
| 家族 | # | LLO操作/硬件单元 | St |
|---|---|---|---|
| 流(聚集/分散/vreg) | 834 | SparseCore 流/分散引擎描述符 → LowerToSparseCoreLlvm → LLVM 调用 | I |
| 打包/解包(子元素) | 87 | VPU 打包/拆包插槽 → llo.vpack* / llo.vunpack* | C |
| 矢量加载/存储 | 74 | VPU 内存插槽 → llo.vector_{load,store}[_masked] | C |
| 信号量等待/观看 | 47 | sflag V等待槽 → llo.vwait.{eq,ne,lt,le,gt,ge}[.done] | C |
| DMA描述符 | 40 | SparseCore DMA 引擎 cmd(3 个复杂度层) | C |
| 扫描/分段扫描/缩小 | 32 | SparseCore 扫描单元(add/max/min × full/half/1xN/2xN × seg × index) | I |
| 矢量转换 | 28 | VPU转换插槽 → llo.vcvt.* | C |
| 分配/分配 | 24 | SparseCore分配器(smem/spmem/vmem/sflag/hbm/iova/timem/tilespmem/dreg/cbreg) | C |
| 信号量设置/添加(sflag) | 22 | sflag VSync 插槽 → llo.vsync.{add,set}[.done,.remote] | C |
| 超验/EUP | 22 | EUP VALU3推送(Alu3 op0 + 5位选择器)+ PopEupResult | C |
| 控制寄存器rd/set | 21 | 标量 RdReg/SetReg → SCS 标量槽 | C |
| 指针/寻址/循环-bc | 16 | LLVM inttoptr/ptrtoint/addrspace + 循环字节码 | C |
| 地址空间广播 | 16 | 幸存的 @llvm.tpu.addrspacecast.* IR 内部调用(ID 0x33b1–0x33c0) | C |
| 标量 ALU / 标量内存 | 14 | SCS 标量槽(移位、溢出加法、addcarry、add_high/low_f32) | C |
| 车道/子车道排列 | 14 | VPU跨通道插槽 → llo.vrot.slane / vperm.sublane / sc.permute | C |
| CBREG /循环缓冲区 | 12 | 标量 CBREG 操作(ReadCbreg/WriteCbreg/AddCbreg/MoveCbreg/SLD/SST.cb) | C |
| 跟踪/遥测/sc-控制 | 12 | SparseCore 控制/跟踪(strace、事件、周期计数、ssetpstate) | C |
| 排序/唯一/重复计数 | 11 | SparseCore排序/重复数据删除单元(嵌入重复数据删除) | I |
| 任务/控制/结构 | 10 | SparseCore 平铺任务 + 结构(task_dispatch、loop_*、barrier、nop) | C |
| i1-掩模宽度转换 | 5 | VPU mask slot — 矢量掩模宽度重新打包 | C |
| 未分类余数(边界/杂项) | 15 | 分布在中等置信度家族中 — 未单独列举 | I |
| 总计 | 1356 |
总和检查:834+87+74+47+40+32+28+24+22+22+21+16+16+14+14+12+12+11+10+5 = 1341; 20 个枚举家族恢复了 1356 个 grep 确认的名称中的 1341 个,在该分类法未单独存储的中等置信度家族边界上留下了 15 个内在函数(上面的“未分类剩余”行)。 1356总计是字节确认的真相;每个系列的划分是分析师分类,仅适用于 grep 锚定的系列(stream、pack/unpack、vld/vst、wait/watch、dma、scan、convert、alloca、sync、addrspacecast、i1-width)。
流引擎——主导家族 {#stream-engine-the-dominant-family}
1356 个内在函数中的 834 个 (62%) 是 llvm.tpu.stream.*:SparseCore 嵌入流/分散引擎。这是一个编码为不同操作的组合叉积 - 硬件流命令变体是通过操作标识而不是属性来选择的,因此类型系统带有 (pattern, verb, dtype, memspace) 选择。深层语义存在于 sparsecore/stream-gather-scatter.md 和 sparsecore/indirect-vreg-stream.md 上;不要在此处重现 834 行。
叉积轴
| 轴 | 值 | 贡献计数 |
|---|---|---|
| 图案 | linear · strided · indirect | 线性 180 · 跨步 114 · 间接 540 |
| 动词 | vreg(聚集+分散)、gather(非vreg)、scatter(非vreg) | vreg 360 · 聚集 246 · 分散 228 |
| dtype | bf16 · e4m3 · e5m2 · f32 · s16 · s32 | 每个数据类型 111 个操作(×6 = 666 个数据类型) |
| 转 | _to_tilespmem · _to_spmem · _to_smem · _to_hbm4b · _to_hbm | tilepmem 399 · spmem 210 · smem 27 · hbm4b 15 · hbm 15 |
| 修改器 | .cb.(CBREG 窗口)·.add(分散添加)·.np(无谓词) | CB 窗口 556 / 834 |
命名模板
llvm.tpu.stream.<pattern>.[vreg.]{gather|scatter}.[cb.][add.]<dtype>.<src>.to.<dst>
e.g. llvm.tpu.stream.linear.gather.add.f32.hbm.to.tilespmem
(class tpu_stream_linear_gather_add_f32_hbm_to_tilespmem;
create(OpBuilder&, Location, Value×6) — 6 SSA operands)CBREG 窗口间接形式(556 个操作)使用 INDIRECT_OFFSET_SOURCE_CBREG 源进行嵌入表窗口(请参阅 sparsecore/cbreg.md)。间接收集将嵌入行从 HBM/SPMEM 表(由 CBREG 窗口偏移流索引)拉入图块本地 SPMEM;匹配的分散相加将累积的梯度推回原处。这些通过 LowerToSparseCoreLlvmPass @0x13566d00 将 LLVM 调用降低到流/分散引擎中。
明白了 — 没有带有属性选择器的单个
llvm.tpu.stream操作。将流引擎建模为一个参数化操作的重新实现者将会与二进制文件不匹配,二进制文件将所有 834 个组合注册为单独的操作,并通过 ISel 匹配器中的操作标识来调度它们。 834 路爆炸就是编码。
打包/解包(子元素暂存) {#pack--unpack-subelement-staging}
87 操作。 VPU 打包/解包插槽 — 用于量化 MXU 源的子字节宽度分级。降低至 llo.vpack* / llo.vunpack*(参见 isa/pack-unpack-precision.md 和 isa/slot-vpu.md)。
| 代表内在 | 它的作用是什么 | 降低至 |
|---|---|---|
llvm.tpu.packc | 标量包压缩 | VPU包插槽 |
llvm.tpu.pack.c.b32.b16 | 包 b32 → b16 | llo.vpack(宽度阶段) |
llvm.tpu.pack.c.b16.b8 | 包 b16 → b8 | llo.vpack |
llvm.tpu.pack.c.b8.b4 | 包 b8 → b4 | llo.vpack |
llvm.tpu.pack.c.b4.b2 | 包 b4 → b2 | llo.vpack |
llvm.tpu.pack.c.b2.b1 | 包 b2 → b1 | llo.vpack |
llvm.tpu.pack.c.f32.bf16 | 包 f32 → bf16 | llo.vpack |
llvm.tpu.pack.c.bf16.e4m3 | 包 bf16 → e4m3 (FP8) | llo.vpack |
llvm.tpu.pack.c.bf16.e5m2 | 包 bf16 → e5m2 (FP8) | llo.vpack |
llvm.tpu.pack.c.bf16.s8 / .bf16.u8 | 包 bf16 → s8/u8 | llo.vpack |
llvm.tpu.pack.c.b16i1.b8i1 | 面膜 b16i1 → b8i1 | VPU面膜包 |
llvm.tpu.unpack.* | 逆宽度扩展 | llo.vunpack |
宽度阶梯为 b32 → b16 → b8 → b4 → b2 → b1,具有 FP8 (e4m3/e5m2) 和整数 (s8/u8) 端点用于量化。
矢量加载/存储(vmem/cb) {#vector-load--store-vmem--cb}
74 操作。 VPU 内存插槽 → llo.vector_{load,store}[_masked]。 sparsecore/vectorload-slot.md 和 sparsecore/vectorstore-slot.md 的语义; isa/slot-memory-load.md / isa/slot-memory-store.md 上的插槽编码。
该系列是 vld/vst 基础上的修改器叉积。每个负载都被屏蔽(.msk);商店添加分散 (.add) 和 FP8 商店包 (.e4m3/.e5m2)。
| 修改器 | 含义 |
|---|---|
.msk | 屏蔽(谓词)- 存在于所有 |
.cb | CBREG窗口地址 |
.upd | 更新后自动递增 |
.idx | 已索引(聚集/分散地址) |
.strided | 跨步访问 |
.add | 分散添加(存储端减少) |
.e4m3 / .e5m2 | FP8 存储包 |
.np | 无谓词快速变体 |
| 代表内在 | 它的作用是什么 |
|---|---|
llvm.tpu.vld.msk | 屏蔽矢量加载 |
llvm.tpu.vld.msk.idx | 屏蔽索引(收集)负载 |
llvm.tpu.vld.msk.strided | 屏蔽跨步负载 |
llvm.tpu.vld.cb.msk | CBREG 窗口屏蔽负载 |
llvm.tpu.vld.cb.upd.msk | CBREG 窗口更新后屏蔽加载 |
llvm.tpu.vst.cb.msk | CBREG 橱窗蒙面商店 |
llvm.tpu.vst.cb.msk.add | CBREG 窗口屏蔽分散添加存储 |
llvm.tpu.vst.cb.msk.add.e4m3 | 分散添加存储,FP8 封装 |
llvm.tpu.vst.cb.msk.idx.add | 索引分散添加存储 |
同步/等待/观看(sflagatomics) {#sync--wait--watch-sflag-atomics}
sflag(信号量标志)原子表面分为本页一起计数的子系列。字节确认联合 (^llvm\.tpu\.(sync|sfence|wait|watch|fetch)) 为 73 操作:sync*/sfence = 25、wait* = 31、watch* = 16、fetch.and.add = 1。(上面的分类行对此进行了不同的划分 - 等待/观察= 47,同步设置/添加 = 22 — 三个 sync{donemov,pamov,readpa} 操作和 fetch.and.add 位于相邻行中。)所有这些都通过 VPU/SPU 同步/等待槽以 sflag 组为目标(请参阅 isa/slot-vpu.md、isa/slot-spu-scalar.md)。
同步/设置/添加 — 22 个操作 → llo.vsync.{add,set}
| 代表内在 | 它的作用是什么 |
|---|---|
llvm.tpu.syncadd | 原子添加到 sflag |
llvm.tpu.syncadd.done / .notdone | 添加 + 信号完成/未完成 |
llvm.tpu.syncadd.remote / .remote.done / .remote.doneinv | 通过 ICI 添加到对等核心的 sflag |
llvm.tpu.syncadd.tile / .both / .other | 每块/双向/其他银行目标 |
llvm.tpu.syncset.done / .notdone / .both / .both.done | 原子集 |
llvm.tpu.syncset.remote[.done/.doneinv] | 通过 ICI 远程设置 |
llvm.tpu.syncset.tile[.done/.doneinv] | 每块套装 |
llvm.tpu.syncsetpa | 集,公共访问银行 |
llvm.tpu.sfence | sflag 内存栅栏 |
等待/观看 — 47 次操作 → llo.vwait.{eq,ne,lt,le,gt,ge}[.done]
| 代表内在 | 它的作用是什么 |
|---|---|
llvm.tpu.waiteq / waitne / waitlt / waitle / waitgt / waitge | 等待 sflag {==,!=,<,<=,>,>=} 阈值 |
llvm.tpu.wait{eq,ge,…}ordone | 等待或完成变体 |
llvm.tpu.wait{…}.yieldable | 定序器等待产量变体 |
llvm.tpu.wait{eq,ge,gt,lt,ne}.imem | 指令-内存-标志等待 |
llvm.tpu.waitdone / .yieldable | 等待完成信号 |
llvm.tpu.waitnotdone / .yieldable | 等待未完成 |
llvm.tpu.watch{eq,ne,lt,gt,…}[ordone] | 无阻塞手表臂 |
llvm.tpu.watch.wait / .wait.sel / .end / .end.sel | 监视寄存器生命周期 |
llvm.tpu.fetch.and.add | sflag 读取-修改-写入 (V, V, V) |
QUIRK —
_remote通过 ICI 路由到对等核心的 sflag(超大规模屏障路径),.tile/.pa目标为每块/公共访问库,.doneinv反转完成意义,并且.yieldable让定序器在受阻时屈服。重新实现者必须将这些后缀视为不同的硬件行为,而不是装饰别名。
DMA 描述符生成器 {#dma-descriptor-builders}
40 操作。 SparseCore DMA 引擎命令构建器。命名为 llvm.tpu.dma.<src>.to.<dst>.sc.{simple,single.strided,general}。后缀是描述符复杂度层;该层由类型化创建操作数计数来确认。
| 等级 | 后缀 | # 操作 | 操作数(位置之后) |
|---|---|---|---|
| 简单 | .sc.simple | 16 | 8 值(src、dst + 基数/偏移量/大小 + sflag) |
| 单步 | .sc.single.strided | 12 | 11 值(+1 步幅三倍) |
| 通用 | .sc.general | 12 | 16 值(+ 多暗淡步幅/尺寸) |
src/dst 系列涵盖 hbm、iova、smem、spmem、timem、simem。代表:llvm.tpu.dma.hbm.to.spmem.sc.simple、llvm.tpu.dma.spmem.to.hbm.sc.single.strided、llvm.tpu.dma.hbm.to.spmem.sc.general。 (iova src/dst 仅出现在 simple/single.strided 层中,而不出现在 general 中。)这些是高级 DmaSimpleStart / DmaSingleStridedStart / DmaGeneralStart 方言的 SparseCore 等效项操作;本质是后端转化为DMA引擎命令的后降低形式。
扫描/缩减(嵌入聚合) {#scan--reduce-embedding-aggregation}
32 操作。 SparseCore 扫描单元——嵌入聚合原语。 sparsecore/scan-datapath.md、sparsecore/segmented-scan.md 和 sparsecore/segmented-add-scan.md 上的深度数据路径。
该系列是一个干净的交叉产品:{add, max, min} × {scan1xN, scan2xN} × {seg, non-seg} × {index, value} × {f, i}。
| 代表内在 | 它的作用是什么 |
|---|---|
llvm.tpu.add.scan1xNf / .add.scan1xNi | 1×N 前缀和,浮点/整数 |
llvm.tpu.add.seg.scan1xNf | 分段1×N前缀和 |
llvm.tpu.add.full.scan2xN / .add.half.scan2xN | 2×N扫描,全/半 |
llvm.tpu.add.full.seg.scan2xN | 分段2×N全扫描 |
llvm.tpu.max.scan1xNf / .max.scan2xN | 最大扫描 |
llvm.tpu.max.index.scan1xNf | argmax-索引扫描 |
llvm.tpu.max.seg.index.scan2xN | 分段argmax扫描 |
llvm.tpu.min.scan1xNi / .min.seg.scan2xN | 最小/分段最小扫描 |
.seg 标记分段(分段边界感知)扫描; .index 产生 arg-position 而不是值。
矢量转换 {#vector-convert}
28 操作。 VPU转换插槽→llo.vcvt.*(参见isa/slot-vpu.md)。 Float↔int 和 float↔narrow-float 转换,具有随机轮 (.sr) 和概率轮 (.pr) 变体。
| 代表内在 | 它的作用是什么 |
|---|---|
llvm.tpu.vcvt.f32.bf16 / .f32.bf8 / .f32.hf16 / .f32.if8 | 加宽窄浮点 → f32 |
llvm.tpu.vcvt.s32.f32 / .f32.s32 | int ↔ 浮点 |
llvm.tpu.vcvt.bf16.s4 / .bf16.s8 / .bf16.u4 / .bf16.u8 | dequant int → bf16 |
llvm.tpu.vcvt.s4.bf16 / .s8.bf16 / .u4.bf16 / .u8.bf16 | 定量 bf16 → int |
llvm.tpu.vcvt.sr.f32.bf16 / .sr.fptobf16 | 随机回合收窄 |
llvm.tpu.vcvt.fptobf16 / .fptobf8 / .fptohf16 / .fptoif8 | 浮点 → 窄浮点 |
llvm.tpu.cvt.fptosi / .cvt.pr.fptosi | 标量浮点数 → 有符号整数 |
分配/分配 {#alloca--allocate}
24 操作。 SparseCore 分配器 → 每个银行的分配。 tpu_alloca_*是堆栈式分配; tpu_allocate_* 是每个银行(包括 CBREG)的分配器。银行:smem、spmem、vmem、sflag、hbm、iova、timem、tilespmem、dreg、 cbreg,加上 _dyn(动态)和 _any(任何银行)。代表:llvm.tpu.alloca.smem、llvm.tpu.alloca.sflag、llvm.tpu.allocate.dreg、llvm.tpu.allocate.cbreg。
超验/EUP {#transcendental--eup}
22 操作。扩展单元管道 (EUP) 超越 — VALU slot-3 push + pop 对。每个都以 1:1 的方式映射到 V5+ EUP 超越,其函数→选择器值在 isa/slot-eup-transcendental.md 上解码。推入的是VALU Alu3(操作码0x0 + 5位选择器);结果通过 VectorResult0 PopEupResult 槽排出。
内在 (+.macro) | 功能 | EUP选择器(F32 / Bf16) |
|---|---|---|
llvm.tpu.rcp | 倒数 | 0x15 / 0x1d |
llvm.tpu.rsqrt | 倒数平方根 | 0x10 / 0x0c |
llvm.tpu.tanh | tanh | 0x13 / 0x1b |
llvm.tpu.sigshft | 移位 S 形 | 0x14 / 0x1c |
llvm.tpu.log2 | log2 | 0x12 / 0x1a |
llvm.tpu.pow2 | 2ˣ | 0x11 / 0x19 |
llvm.tpu.erf | 错误函数 | 0x0e / 0x0f |
llvm.tpu.sin | 正弦(Sinq) | 0x17 / 0x1e |
llvm.tpu.cos | 余弦 (Cosq) | 0x18 / 0x1f |
裸形式(llvm.tpu.sin)是原始EUP推送; .macro 形式(llvm.tpu.sin.macro,键入 (Type, Value) → 1 个结果,1 个操作数)是push+pop 宏。加上非配对的 EUP 操作:llvm.tpu.exponent、llvm.tpu.significand、llvm.tpu.vclass(FP 分类)、llvm.tpu.eup.pop(显式结果消耗)。
控制寄存器rd/set {#control-register-rd--set}
21 操作。标量控制寄存器读/写 → SCS 标量槽 RdReg/SetReg(参见 isa/slot-spu-scalar.md)。
| 代表内在 | 寄存器读取/设置 |
|---|---|
llvm.tpu.rdreg.gtc.hi / .gtc.lo | 全局时间计数器(64 位,高/低) |
llvm.tpu.rdreg.lcc.hi / .lcc.lo | 本地周期计数器 |
llvm.tpu.rdreg.crr.hi / .crr.lo | 核心资源计数器 |
llvm.tpu.rdreg.tid / .scid / .tag / .tbm / .tm | 线程/稀疏核心/标签/tile-base/tile-mask id |
llvm.tpu.rdreg.fsr / .ddr / .dmacrdt / .btr / .yieldreq | 状态/信用/收益寄存器 |
llvm.tpu.setreg.sflagrange / .dmacrdt / .pdepth / .tag / .ifvalue | 配置sflag范围/DMA信用/谓词深度 |
指针/寻址/循环字节码 {#pointer--addressing--loop-bytecode}
16 操作。 LLVM inttoptr/ptrtoint/addrspace 加上循环字节码帮助程序。代表:llvm.tpu.inttoptr、llvm.tpu.ptrtoint、llvm.tpu.make.restrict.ptr、llvm.tpu.bc.load.aliaddr、llvm.tpu.bc.store.aliaddr、llvm.tpu.bc.select.predicate、llvm.tpu.bc.extractvalue.loopindex、llvm.tpu.bc.insertvalue.loopindex。 bc.*(循环字节码)操作在 ID 0x33d9/0x33da 的 PerformDAGCombine 操作码 0x30 臂中处理。 (MEDIUM — 几个 bc.*loopindex 操作上任务/结构重叠的边界。)
AddrSpaceCast {#addrspacecast}
16 操作。 SparseCore 地址空间转换转换。这些系列的后端处理是端到端的字节跟踪,并纠正了一个常见的假设 - 它们作为幸存的 LLVM-IR 内部调用发出,而不是折叠到通用 IR addrspacecast 或 ISD::ADDRSPACECAST。对sparsecore/addrspacecast-isel.md和sparsecore/tile-id-cast.md进行深度处理。
全16
llvm.tpu.addrspacecast (plain, 1-operand)
llvm.tpu.addrspacecast.scs
llvm.tpu.addrspacecast.smem
llvm.tpu.addrspacecast.spmem
llvm.tpu.addrspacecast.tac
llvm.tpu.addrspacecast.tc
llvm.tpu.addrspacecast.tec
llvm.tpu.addrspacecast.scs.sflag.scs
llvm.tpu.addrspacecast.tec.sflag.tec
llvm.tpu.addrspacecast.smem.tile.scs
llvm.tpu.addrspacecast.smem.tile.tec
llvm.tpu.addrspacecast.sflag.tile.scs
llvm.tpu.addrspacecast.sflag.tile.tac
llvm.tpu.addrspacecast.sflag.tile.tec
llvm.tpu.addrspacecast.sflag.tile.sflag.scs
llvm.tpu.addrspacecast.sflag.tile.sflag.tec普通转换为 1 操作数 (create(Type, Value));每核 (tec/tac/scs) 和平铺窗口形式需要额外的 i32tile-id 值。
排放和遣散
| 舞台 | 网站 | 行动 |
|---|---|---|
| MLIR 操作 → IR 调用 | convertOperation @0x13933e40(16臂0x1393c460–0x1393c8da)→蹦床@0x1393bf27→createIntrinsicCall @0x1683f440 | 发出 @llvm.tpu.addrspacecast.* IR 调用,固有 ID 0x33b1–0x33c0 (13233–13248) — 根据 IntrinsicNameTableStorage @0x4179440 的存储顺序进行字节验证(llvm.tpu.addrspacecast = ID 0x33b1;之前的 0x33b0–0x33bf 推导偏差了 1) |
| IR内在幸存 | (无转换) | 未降低至 ISD::ADDRSPACECAST (0xf4) — 无匹配臂,无 Select/LowerOp/Combine 臂 |
| 放电 | 通用 INTRINSIC_WO_CHAIN 折叠/消耗 SC 加载存储 ISel | 保值铸件被消费者吸收(推断) |
注意 — SparseCore
addrspacecast内在函数不会成为ISD::ADDRSPACECAST(0xf4) 节点。0xf4节点仅由真正的 IRaddrspacecast指令(通过SelectionDAGBuilder::visitAddrSpaceCast@0x19333020→getAddrSpaceCast@0x192e2360)产生,没有 TPU/SparseCore 代码发出 — 整个.text外部参照addrspacecast构造函数将每个调用者放置在通用 LLVM 中,没有放置在 TPU/SC 频段中。铸造内在系列和0xf4/0xf3降低是两个独立的机制;0xf4→0xf3寄存器复制路径仅服务于通用 TensorCore 前端。0x33b1–0x33c0的唯一 ID 键控后端站点是:convertOperation发出、Select默认路由表 (@0xaec81ecidx0x10–0x1f→SelectCode默认)和TPUVerifier::runImpl@0x13c54912(仅验证)。无下降部位。
标量 ALU / 标量内存 {#scalar-alu--scalar-mem}
14 操作。 SCS 标量槽 — 移位、溢出算术、进位、FP 分量加法。代表:llvm.tpu.shll、llvm.tpu.shra、llvm.tpu.shrl、llvm.tpu.sshllo、llvm.tpu.sadd.ov、llvm.tpu.ssub.ov、llvm.tpu.sshla.ov(溢出标记加/减/移)、llvm.tpu.addcarry、 llvm.tpu.add.high.f32.bf16、llvm.tpu.add.low.f32.bf16(bf16-分解-f32 添加一半)。 (MEDIUM — add.high/low.f32.bf16 也可以分组在 EUP/精度下。)
车道/子车道排列 {#lane--sublane-permute}
14 操作。 VPU 跨通道槽 — 子通道洗牌/旋转/排列和 SC 排列。代表:llvm.tpu.vrot.sublane、llvm.tpu.vrot.sublane.down、llvm.tpu.vperm.sublane、llvm.tpu.vshift.insert、llvm.tpu.sc.permute、llvm.tpu.sc.mask.permute,加上vlaneseq序列生成器形式(llvm.tpu.vlaneseq.c.bf16、.i.bf16、 .u32)。有关排列驱动的基数排序的使用,请参阅 sparsecore/rank-and-permute-radixsort.md。 (MEDIUM — sc.permute/sc.mask.permute 跨式车道操作与 SC 控制。)
CBREG /循环缓冲区 {#cbreg--circular-buffer}
12 操作。标量 CBREG(循环缓冲区寄存器)操作驱动每组 16 个 CBREG 循环缓冲区,对 SMEM 和 TILE_SPMEM 进行窗口化。 sparsecore/cbreg.md 上的完整编码。
| 内在 | LLO 操作 |
|---|---|
llvm.tpu.rdcbreg.offset / .size / .smem.base / .tilespmem.base | ReadCbreg (0x36), CbregMetadata {BASE=0,SIZE=1,OFFSET=2} |
llvm.tpu.wrcbreg.offset / .size / .smem.base / .tilespmem.base | WriteCbreg (0x35) |
llvm.tpu.cbreg.add.offset / .add.offset.in.place | AddCbreg(0x33,目标偏移) |
llvm.tpu.copy.cbreg | MoveCbreg(转义0x00/子0x1b) |
llvm.tpu.allocate.cbreg | CBREG 分配(每个 SCS/TAC/TEC 银行 16 个之一) |
llvm.tpu.sld.cb / .sld.cb.upd | SLDCircularBuffer(0x3f / 0x3e、.upd = 更新后) |
llvm.tpu.sst.cb / .sst.cb.upd | SStoreCircularBuffer (0x3d / 0x3c) |
双基(smem.base 与 tilespmem.base)是双地址空间窗口:CBREG 窗口包括 SMEM 和 TILE_SPMEM。
跟踪/遥测/sc-control {#trace--telemetry--sc-control}
12 操作。 SparseCore 控制/跟踪和遥测。代表:llvm.tpu.sc.strace、llvm.tpu.event、llvm.tpu.spill.debug、llvm.tpu.mprefix、llvm.tpu.read.global.cycle.count、llvm.tpu.read.local.cycle.count、llvm.tpu.ssetpstate、llvm.tpu.sc.ssettm、llvm.tpu.sc.dma.core.id、 llvm.tpu.sc.sint。 (MEDIUM — 任务/结构的边界。)
排序/唯一/重复计数 {#sort--unique--dupcount}
11 操作。 SparseCore 排序/去重单元 — 嵌入去重原语。请参见 sparsecore/dedup-multiplicity.md 和 sparsecore/rank-and-permute-radixsort.md。
| 内在 | 它的作用是什么 |
|---|---|
llvm.tpu.sort.ascdf / .ascdi | 升序排序,float / int |
llvm.tpu.sort.dscdf / .dscdi | 降序排序,float / int |
llvm.tpu.uniquef / .uniquei | unique-reduce, float / int |
llvm.tpu.dupcntf / .dupcnti | 重复计数,浮点/整数 |
llvm.tpu.vmctz | 向量计数尾随零 |
llvm.tpu.vmpcnt.ones | 矢量掩码 popcount |
任务/控制/结构 {#task--control--structural}
10 操作。 SparseCore 平铺任务 + 结构操作。代表:llvm.tpu.task.dispatch、llvm.tpu.task.dispatch.clear.ibuf、llvm.tpu.loop.name、llvm.tpu.loop.parallel、llvm.tpu.barrier、llvm.tpu.nop、llvm.tpu.delay、llvm.tpu.tileid、llvm.tpu.halt.trap、 llvm.tpu.capture.hbm.stack/init.stack。 tpu_tileid 操作(类型为 (Type) → 0 操作数 id)读取 STILEID 寄存器;它是每核 addrspacecast 转换消耗的tile-id 源。 (MEDIUM — 与堆栈操作上的控制寄存器和指针系列重叠。)
i1-掩模宽度转换 {#i1-mask-width-conversion}
5 操作。 VPU mask slot — 矢量掩码宽度重新打包。全套:llvm.tpu.8i1.to.16i1、llvm.tpu.8i1.to.32i1、llvm.tpu.16i1.to.8i1、llvm.tpu.16i1.to.32i1、llvm.tpu.32i1.to.8i1。请参见 sparsecore/m-register-predicate.md 和 isa/slot-vcreate-mask-mregister.md。
ODS操作数形状(代表性) 1356 中的
466 携带类型化的 create(OpBuilder&, Location, …),其参数列表是 ODS 声明;其他 890 使用通用默认构建器(从名称家族数量 + verifyInvariantsImpl 存在推断的形状)。 T = 结果类型,V = 值操作数。
| 内在(系列) | 创建参数(位置之后) | 形状 |
|---|---|---|
tpu_addrspacecast(地址空间广播) | T, V | 1 个资源,1 个操作数 |
tpu_addrspacecast_smem(地址空间广播) | T, V, V | +平铺窗口 |
tpu_dma_*_sc_simple(DMA) | V×8 | 8 字段描述符 |
tpu_dma_*_sc_single_strided(DMA) | V×11 | +跨步三倍 |
tpu_dma_*_sc_general(DMA) | V×16 | 多调光 |
tpu_stream_*_{gather,scatter}_*(流) | V×6 | 流描述符 |
tpu_syncadd(同步) | V, V | 标志,增量 |
tpu_syncadd_remote / syncset_remote(同步) | V×5 | +dev/core/id |
tpu_fetch_and_add(等待) | V, V, V | sflag、addr、val |
tpu_waitge / waiteq / …(等待) | V, V | 标志,阈值 |
tpu_alloca_smem / alloca_sflag(分配) | T, V | 结果,尺寸 |
tpu_rdcbreg_offset / rdcbreg_size (CBREG) | T, V | 结果,cbreg |
tpu_wrcbreg_offset (CBREG) | T, V, V | CBreg,值 |
tpu_cbreg_add_offset (CBREG) | T, V, V | CBEG,三角洲 |
tpu_inttoptr / ptrtoint (ptr) | T, V | 结果,值 |
tpu_setreg_sflagrange(ctl-reg) | V | 范围值 |
tpu_sin_macro / tpu_*_macro (EUP) | T, V | 结果、操作数 |
tpu_tileid(任务/结构) | T | 0-操作数id |
tpu_barrier(任务/结构) | V, V, V | 屏障参数 |
tpu_delay(任务/结构) | V | 循环 |
890 个默认构建器操作(裸超越 tpu_sin/tpu_rcp、tpu_*i1_to_*i1、scan2xN、打包/解包、vld/vst、 rdreg_* 计数器、sld_cb、eup_pop)使用通用 (TypeRange, ValueRange, ArrayRef<NamedAttribute>) 构建器 — 推断结果类型 (SameOperandsAndResultType/InferType),按名称系列数量进行操作数计数。
默认构建器 Arity(从 ODS 特征包读取字节) {#default-builder-arity-byte-read-from-the-ods-trait-pack}
890 个默认构建器操作不需要需要从名称系列启发式猜测其操作数计数:TableGen 将结果计数和操作数计数特征烘焙到损坏的 Op<…> 类模板中,并且该模板名称以字节形式存在于符号表中。每个 tpu_* 操作都被实例化为
mlir::Op<sparse_core::tpu_NAME,
OpTrait::ZeroRegions, OneResult|ZeroResults,
OneTypedResult<mlir::Type>::Impl, ZeroSuccessors,
OneOperand | ZeroOperands | NOperands<Lj N>::Impl,
OpInvariants [, MemoryEffectOpInterface::Trait]>并且该特征列表逐字显示在每个操作 getHasTraitFn / getFoldHookFn / printAssembly 回调符号(nm 代币 OpINS…sparse_core<len>tpu_NAME EJ … OpInvariants)内。操作数计数是文字 OneOperand (1)、ZeroOperands (0) 或 NOperands<Lj N> (N) 标记;结果计数为 OneResult (1) 与 ZeroResults (0)。不需要反汇编——元数是符号中的字符串。
注意 — 结果
TypeConstraint不是该层的精炼Vreg/Mask/Scalar/Ptr谓词。 每个操作的结果特征都是通用的OneTypedResult<mlir::Type>—mlir::Type,不是寄存器类子类型。验证者主体(tpu_NAME::verifyInvariantsImpl)通过一个共享约束函数__mlir_ods_local_type_constraint_…llvm_tpu_ops1(例如@0x149de120)释放其单一结果类型检查,其整个主体是if (!LLVM::isCompatibleOuterType(t)) emitOpError(...)(call isCompatibleOuterType @0x17473060位于149de146,字节验证)。区分调用站点的StringRef参数只是诊断角色标签 —"result"(.rodata @0x84f7815) 与"operand"(.rodata @0x86f4942),由xxd读取 — 而不是谓词选择器。 在此 MLIR 层中编码没有每操作Vreg/Mask/Scalar/Ptr结果约束;寄存器类细化仅存在于 ISel 下游消耗的 LLVM 内在签名中,而不存在于 ODS 验证器中。因此,这个间隙的“结果TypeConstraint” 的一半 * 在这里每个操作都不是静态可分离的 - 每个叶子都携带相同的通用 LLVM 兼容类型结果检查。 (HIGH)
数量分布 — 1356 字节读取中的 1060 个
从每个操作的 Op<…> 符号中解析 OneResult/ZeroResults × OneOperand/ZeroOperands/NOperands<Lj N> 令牌可恢复精确的 (#results, #operands) 形状 1060不同的 tpu_* 操作(未列出的 296 个 Op<…> 包仅内联发出,并且不携带独立的回调符号;它们的数量遵循相同的名称系列模式)。完整的字节读取分布:
| #res | #操作数 | # 操作 | 此桶中的主导家族 |
|---|---|---|---|
| 0 | 8 | 358 | stream_{strided,indirect}_* (342) + dma_*_sc_simple 非 iova 窗口 (16) |
| 1 | 1 | 147 | 裸EUP(sin / rcp / eup_pop / sigshft / exponent),unpackl / unpacku, inttoptr/ptrtoint、i1-宽度铸件 |
| 0 | 6 | 118 | stream_linear_* + sync{add,set}_remote_* |
| 0 | 9 | 114 | stream_indirect_vreg_vreg_*(聚集+分散) |
| 1 | 2 | 94 | sld_cb、pack_c_*、dupcnt{f,i}、uniquef、sshllo、vclass、wrcbreg_* |
| 0 | 2 | 51 | syncadd/waiteq/…(标志、阈值) |
| 0 | 4 | 29 | 跨步/多参数同步 + vst 变体 |
| 0 | 1 | 26 | delay,单参数存储 |
| 1 | 0 | 25 | tileid + 所有 rdreg_* 计数器(0 操作数寄存器读取) |
| 0 | 5 | 23 | 同步/DMA 中间层 |
| 0 | 3 | 21 | vst_msk 级商店、fetch_and_add 级、barrier |
| 1 | 3 | 14 | sort_{asc,dsc}d{f,i},3 操作数向量运算 |
| 0 | 16 | 12 | dma_*_sc_general |
| 1 | 4 | 9 | 4 操作数类型操作 |
| 0 | 11 | 10 | dma_*_sc_single_strided(非 iova) |
| 0 | 0 | 6 | nop级零一切操作 |
| 0 | 12 | 2 | dma_{hbm_to_iova,iova_to_hbm}_sc_single_strided(iova增加1个操作数) |
| 1 | 10 | 1 | tpu_sfence(10 个 sflag 操作数) |
总和 = 1060。
字节验证的叶样本(直接从符号读取的令牌)
每行的 #res/#operands 是从该操作的损坏中提取的 OneResult/ZeroResults 和 OneOperand/ZeroOperands/NOperands<Lj N> 令牌nm 表中的 Op<…sparse_core…tpu_NAME EJ…OpInvariants> 回调符号 — 确切的字符串就是证据。
| 本征(类) | 结果代币 | 操作数标记 | (#res,#opnd) |
|---|---|---|---|
tpu_sin(裸EUP) | OneResult | OneOperand | (1, 1) |
tpu_addrspacecast | OneResult | OneOperand | (1, 1) |
tpu_tileid | OneResult | ZeroOperands | (1, 0) |
tpu_vld_msk | OneResult | NOperands<Lj2> | (1, 2) |
tpu_sld_cb | OneResult | NOperands<Lj2> | (1, 2) |
tpu_pack_c_b32_b16 | OneResult | NOperands<Lj2> | (1, 2) |
tpu_sort_ascdf | OneResult | NOperands<Lj3> | (1, 3) |
tpu_vst_msk | ZeroResults | NOperands<Lj3> | (0, 3) |
tpu_syncadd | ZeroResults | NOperands<Lj2> | (0, 2) |
tpu_stream_linear_gather_hbm_to_tilespmem | ZeroResults | NOperands<Lj6> | (0, 6) |
tpu_stream_strided_gather_hbm_to_tilespmem | ZeroResults | NOperands<Lj8> | (0, 8) |
tpu_stream_indirect_vreg_vreg_gather_hbm_to_tilespmem | ZeroResults | NOperands<Lj9> | (0, 9) |
tpu_dma_hbm_to_spmem_sc_single_strided | ZeroResults | NOperands<Lj11> | (0, 11) |
tpu_dma_hbm_to_iova_sc_single_strided | ZeroResults | NOperands<Lj12> | (0, 12) |
tpu_sfence | OneResult | NOperands<Lj10> | (1, 10) |
QUIRK — 流系列不统一
V×6。 §流 类型创建示例显示 6 操作数线性形式,但字节读取元数将 834 个流操作分为 三个由寻址模式键入的操作数计数:stream_linear_*= 6,stream_{strided,indirect}_*= 8,stream_indirect_vreg_vreg_*= 9。额外的操作数携带更复杂模式所需的步幅/索引/vreg 偏移源。使用固定的 6 操作数列表构建每个流操作的重新实现者将无法提供跨步/间接形式。同样,DMAsingle.strided层通常为 11 个操作数,但当涉及iova端点时为 12 个(dma_hbm_to_iova/dma_iova_to_hbm),细化 §DMA 中的平坦“11 值”。注意 - 覆盖范围,无静默上限。 15 个叶子在上面进行了字节验证(令牌直接从每个操作的损坏的
Op<…>符号读取),跨越 EUP / addrspacecast / task / vld / cbreg / pack / sort / vst /sync /stream-{linear,strided,indirect-vreg} / dma-{单步,iova} / 栅栏系列。完整的(#res, #operands)形状是 1356 个操作中的 1060 个操作的字节读取(每个Op<…>包都作为独立的回调符号存在);上面的分布表是这 1060 个操作的精确普查。其余 296 个操作仅内联发出其特征包,并且不**单独转录 - 它们的数量遵循相同的名称家族布局(每个操作都相距一个rg -o 'sparse_core…tpu_NAME EJ…OpInvariants'令牌)。这完全涵盖了“890 个默认构建器操作”缺口的 arity 一半; 结果-TypeConstraint一半由上述注释关闭(统一通用mlir::Type+isCompatibleOuterType,无每操作Vreg/Mask/Scalar/Ptr)。
Per-Intrinsic IntrProperties(LLVM属性表) {#per-intrinsic-intrproperties-llvm-attribute-table}
每个 llvm.tpu.* 内在函数都带有一个 IntrProperties 集 — IntrNoMem/IntrArgMemOnly/IntrReadMem/IntrWillReturn/… 位 TableGen 降低到由返回的 LLVM 函数属性列表中llvm::Intrinsic::getAttributes (@0x1da0b460)。这是后端的别名分析和调用调度契约。该集合可通过双表查找进行字节恢复;下面的示例是直接从这些表中读取的。
查找(从 getAttributes 字节解码)
getAttributes(ctx, ID, FT) 读取 IntrinsicsToAttributesMap(_ZL25IntrinsicsToAttributesMap @0x416fb30,uint16_t[17648],每个 LLVM 内在 ID 一个条目,索引为 [ID−1])。打包后的 uint16 拆分:
| 字段 | 位 | 解码站点(在getAttributes) |
|---|---|---|
| arg-attr-设置索引 | [8:0] (& 0x1ff) | 1da0b4ab: and $0x1ff,%ecx → ArgAttributesInfoTable @0x4178510(4 字节步长:1da0b4c0: movzwl 0x2(%rdx,%rsi,4)) |
| fn-attr-集索引 | [15:9] (>> 9) | 1da0b564: shr $0x9,%esi; 0x7f =“无 fn 属性”哨兵 (1da0b567: cmp $0x7f) |
fn-attr-set 索引通过 0xb550f54 处的跳转表(int32 相对偏移量,按集 ID 索引)选择 getIntrinsicFnAttributeSet (_ZL26getIntrinsicFnAttributeSet @0x1da0d460) 中的情况。每种情况都是 Attribute::get(ctx, AttrKind, 0) 调用 (@0x1d912ee0) 的固定序列,可选地后跟一个 Attribute::getWithMemoryEffects(ctx, ME) (@0x1d9139a0)。每次调用之前的 mov $0xNN,%esi 中的 AttrKind 立即数是 LLVM Attribute::AttrKind 枚举值; ME 立即数是 MemoryEffects 位掩码。
AttrKind 枚举值(从 mov $imm,%esi 操作数读取字节;根据符号表中二进制文件的 IRAttribute<AttrKind N>/AA*Impl 模板实例进行交叉检查的名称):0x2c=44 NoUnwind, 0x50=80 WillReturn,0x47=71 可推测(INFERRED 名称 — 枚举值字节读取,来自 NoMem+WillReturn 纯内在配对的名称;没有属性 AA 携带 71)。 MemoryEffects 位掩码(2 位/位置,ModRef = Ref(1)/Mod(2)/ModRef(3),位置 ArgMem/InaccessibleMem/其他):0x0=memory(none) (IntrNoMem)、0x555=memory(read) (IntrReadMem)、 0xaaa=memory(write)(IntrWriteMem)、0x3=memory(argmem: readwrite)(IntrArgMemOnly)、0x1=memory(argmem: read)、0x2=memory(argmem: write)、 0xc=memory(inaccessiblemem: readwrite); 不存在 = 完全未建模的 ModRef(副作用)。
12 fn-attr 设置 llvm.tpu.* 表面使用
对所有 1356 个数据进行普查(从每个内在函数的映射条目中读取 fn-attr-set 索引;通过将其 getIntrinsicFnAttributeSet 情况跟踪到 AttributeSetNode::get 终结器 @0x1da0f134 来解码每个集合的内容):
| 套装 | # of 1356 | 枚举属性 | 记忆效应 | LLVM IntrProperties 简写 |
|---|---|---|---|---|
| 11 | 215 | NoUnwind | memory(none) | IntrNoMem |
| 13 | 128 | NoUnwind | memory(argmem: readwrite) | IntrArgMemOnly |
| 112 | 843 | NoUnwind | memory(argmem: readwrite) | IntrArgMemOnly |
| 14 | 8 | NoUnwind | memory(argmem: read) | IntrReadMem+IntrArgMemOnly |
| 32 | 11 | NoUnwind | memory(read) | IntrReadMem |
| 34 | 8 | 未解除,将返回 | memory(write) | IntrWriteMem+IntrWillReturn |
| 36 | 26 | 未解除,将返回 | memory(write) | IntrWriteMem+IntrWillReturn |
| 83 | 8 | NoUnwind | memory(argmem: write) | IntrWriteMem+IntrArgMemOnly |
| 108 | 50 | 未解除,将返回,可推测 | memory(none) | IntrNoMem+IntrWillReturn+IntrSpeculatable |
| 114 | 19 | NoUnwind | memory(inaccessiblemem: readwrite) | IntrInaccessibleMemOnly |
| 5 | 19 | NoUnwind | (无) | 副作用(完整 ModRef) |
| 10 | 21 | NoUnwind | (无) | 副作用(完整 ModRef) |
总和:215+128+843+8+11+8+26+8+50+19+19+21 = 1356 — 确切地说,每个 llvm.tpu.* 内在映射到这 12 个集合之一。
字节验证的每叶样本(名称→ID→映射条目→集合)
每行:内在名称、其 LLVM 内在 ID(IntrinsicNameTableStorage @0x4179440 中的存储顺序索引,其中 not_intrinsic=0、llvm.abs=1,...)、从 IntrinsicsToAttributesMap[ID−1] 读取的 uint16 以及解码的 fn-attr-set。
| 内在 | ID | 地图 uint16 | fn 组 | 已解决 IntrProperties |
|---|---|---|---|---|
llvm.tpu.addrspacecast | 0x33b1 | 0x1601 | 11 | IntrNoMem |
llvm.tpu.pack.c.b32.b16 | 0x3453 | 0x1601 | 11 | IntrNoMem |
llvm.tpu.vcvt.f32.bf16 | 0x384e | 0x1601 | 11 | IntrNoMem |
llvm.tpu.16i1.to.32i1 | 0x33a1 | 0x1601 | 11 | IntrNoMem |
llvm.tpu.nop / llvm.tpu.delay / llvm.tpu.sfence | — | 0x1601 | 11 | IntrNoMem |
llvm.tpu.dma.hbm.to.spmem.sc.simple | 0x3408 | 0x1afb | 13 | IntrArgMemOnly |
llvm.tpu.dma.hbm.to.spmem.sc.general | 0x3407 | 0x1afa | 13 | IntrArgMemOnly |
llvm.tpu.syncadd | 0x37e8 | 0x1a01 | 13 | IntrArgMemOnly |
llvm.tpu.waiteq | 0x38bb | 0x1a01 | 13 | IntrArgMemOnly |
llvm.tpu.stream.linear.gather.add.f32.hbm.to.tilespmem | 0x36ce | 0xe0ff | 112 | IntrArgMemOnly |
llvm.tpu.vst.msk.idx.add(+所有索引分散存储) | — | 0x…ff/0xe0… | 112 | IntrArgMemOnly |
llvm.tpu.vld.cb.msk / llvm.tpu.rdcbreg.offset / llvm.tpu.sin.macro | 0x346a/0x3498 | 0x4001 | 32 | IntrReadMem |
llvm.tpu.vst.cb.msk.add / llvm.tpu.vst.cb.msk | 0x387e | 0x4801 | 36 | IntrWriteMem+IntrWillReturn |
llvm.tpu.rcp / rsqrt / tanh / sort.ascdf / add.scan1xNf | 0x3468/0x349b/0x33ac | 0xd801 | 108 | IntrNoMem+IntrWillReturn+IntrSpeculatable |
llvm.tpu.rdreg.gtc.hi / read.global.cycle.count | 0x3474 | 0x1401 | 10 | 副作用(完整 ModRef) |
llvm.tpu.fetch.and.add / task.dispatch / eup.pop | 0x342d/0x3802 | 0x0a01 | 5 | 副作用(完整 ModRef) |
每个的映射 uint16 是文件偏移 0x416fb30 + (ID−1)*2 处的精确小端半字;例如ID 0x33b1 在 0x4176290 (= 0x416fb30 + (0x33b1−1)·2) → 0x1601 → arg = 0x1601 & 0x1ff = 1、fnset = 0x1601 >> 9 = 11 处读取 01 16。
注意 - 覆盖范围,无静默上限。 16 个代表性叶子在此处针对映射进行字节验证(跨越 addrspacecast / pack / Convert / mask-width / DMA /sync / wait / Stream / CBREG load+store / EUP-macro / transcendental / scan / sort / control-reg /atomic / task family),并且所有 12 个 fn-attr 集都在中进行字节解码来自
getIntrinsicFnAttributeSet的完整。其余 1340 个内在函数的每叶集分配不单独转录,但上面的 fn 集普查是精确的(总和为 1356)并且查找是确定性的:来自IntrinsicNameTableStorage @0x4179440存储顺序的set = (IntrinsicsToAttributesMap[ID−1] >> 9)、ID。重新实现者使用一个半字加载+一个表调度来读取任何叶子的IntrProperties。明白了 — 主要的 fn 集是 112(843 个操作,≈ 所有 834 个流 + 9 个索引分散存储)=
nounwind memory(argmem: readwrite)=IntrArgMemOnly,不是IntrNoMem。将流操作标记为IntrNoMem(因为它们看起来像纯数据移动器)的重新实现者将让调度程序在它们实际读写的嵌入表中提升/CSE/死代码消除它们——这是一个正确性错误。流引擎接触参数指向的内存,因此argmem: readwrite是二进制文件的结论。相反,纯数学集 108 (rcp/rsqrt/tanh/sort/scan) 是唯一携带IntrSpeculatable的集 — 这些是可安全提升的集。
注册绑定
mlir::sparse_core::registerLlvmTpuDialectOperations @0x146d0560 尾调10批分注册商;每个 RegisteredOperationName::insert 约 135 个操作(TableGen 操作注册分为 ≤256 个操作批次,以限制每个函数实例化大小)。 10 × ~135 = 1356。
| 分注册商 | 地址 |
|---|---|
registerLlvmTpuDialectOperations0 | 0x146d05c0 |
registerLlvmTpuDialectOperations1 | 0x1472bea0 |
registerLlvmTpuDialectOperations2 | 0x1478b500 |
registerLlvmTpuDialectOperations3 | 0x147e1c40 |
registerLlvmTpuDialectOperations4 | 0x14835b80 |
registerLlvmTpuDialectOperations5 | 0x148891c0 |
registerLlvmTpuDialectOperations6 | 0x148dc3c0 |
registerLlvmTpuDialectOperations7 | 0x1492d5c0 |
registerLlvmTpuDialectOperations8 | 0x14982d00 |
registerLlvmTpuDialectOperations9 | 0x149d88e0(最终批次) |
注意 — 这些内在函数通过这个单独的 10 批次
LlvmTpuDialect路径注册,不是通过高级ScDialect115 操作addOperations@0x14594f60。仅跟踪ScDialect注册的重新实现者将看到内在表面“无明显”,并错过所有 1356。
每代变化
1356 计数是此构建目标各代的并集;每一代的内在表面都会增长。尺寸不同:
| 变异来源 | 效果 |
|---|---|
新数据类型(FP8 e4m3/e5m2,窄整数) | 为每个数据类型添加流/转换/打包操作行 |
| 新流模式/内存空间 | 扩展834路流跨积 |
| 新 EUP 超越选择器 | 添加超验 + .macro 对 |
| 新地址空间 | 添加了 addrspacecast 叶子变体 |
| 代门控操作 | 较早的世代可能缺少名称(可到达的 getSequencerType / EmitX 世代调度门) |
深层每代可达性位于 isa/sequencer-ops-per-gen.md 和 isa/v5plus-emitx-bit-positions.md 上。本附录快照了此构建的完整注册集;针对单个世代的重新实现者必须根据该世代的 EmitX 调度来控制名称。
流命令是组合的,而不是按叶的 {#the-stream-command-is-composed-not-per-leaf}
834路llvm.tpu.stream.*爆炸是隐藏每叶的主要嫌疑人 数字命令表:834 个不同的操作看起来像834 个不同的硬件操作码。的 二进制文件另有说明。 SparseCore 流排序器使用的数字命令是 在编码时由四个正交 SparseCoreStream 原始位域组装;那里 不是由 (pattern,verb,dtype,memspace) 索引的静态数组,也没有每内部命令 常数。 834 个叶子折叠成 4 个寻址形式 × 一个 8 值动词 × 一个 dtype 位 × 内存空间枚举,打包到一个插槽中。通过读取编码器的数据证实了这一点 oneof 直接调度和每个字段访问器 — 地址为 gfc/TPU7x; .text VA==0xe63c000 处的文件偏移量。
编码器在表单上调度,而不是在叶子上
SparseCoreStreamEncoder::Encode @ 0x1eb9b4c0 通过读取原型来选择编码内容 oneof 鉴别器并将其限制在消息的字段计数处 — 不是 内在 ID 键控表:
1eb9b55e: mov 0x58(%r15),%eax ; oneof discriminator (which addressing form)
1eb9b562: cmp $0xa,%rax ; bound = 0xa → at most 11 cases (fields 0..10)
1eb9b566: ja 1eb9bd64 ; default/error arm
1eb9b571: lea -0x13363470(%rip),%rcx ; jump table @0xb838108 (11 × int32 rel offsets)
1eb9b5a2: cmpl $0x8,0x58(%r15) ; field #8 == LinearStream
1eb9b5a7: lea SparseCoreStream_LinearStream_globals_(%rip),%r12.rodata 0xb838108 处的跳转表为 11 个条目(字段 0–10),并且 xxd 显示 条目 8/9/10 是唯一具有不同目标的条目 — 线性/跨步/间接形式 臂 — 而字段 0-7 共享默认臂。 745 MB 二进制注册 834 个独立的 流操作仍然通过 11-case 开关将它们全部路由:爆炸发生在 MLIR 操作中 名册,不在任何硬件命令表中。 (SCS 编码器边界为 0xa;TEC 编码器边界为 0xa;TEC 编码器边界为 0xa 在 0xb 处界限以接纳仅 TEC 的 IndirectVregStream 第四种形式 — 请参阅 间接 Vreg 流。)
四个命令字段,每个字节都从其访问器进行验证
(pattern,verb,dtype,memspace) 元组的每个轴都是一个单独的位字段,具有自己的 GetConcatenatedValue/Matches 访问器。移位/掩码直接从 拆解是现场准确的槽位和宽度:
| 轴 | 字段 | 附件 @ | 字节读取体 | 槽位 | 验证值 |
|---|---|---|---|---|---|
| 图案(表格) | 形式操作码 | 0x1eb9aa60 线性 | (q[+0x18] & 0x7E0…<<52)==0x76…<<52 | 位 53–58 | 线性 = 0x76>>1 = 0x3b |
0x1eb9aa80 跨步 | …==0x74…<<52 | 位 53–58 | 跨步 = 0x74>>1 = 0x3a | ||
0x1eb9aaa0 间接 | …==0x72…<<52 | 位 53–58 | 间接 = 0x72>>1 = 0x39 | ||
| 动词 | StreamOpcode | 0x1eb9b3a0 | (d[+0x18] >> 9) & 7 | +0x18 位 9,w3 | GATHER=0 … SCATTER_FLOAT_ADD=6 |
| dtype | GatherScatterAddIsB16 | 0x1eb9b3c0 | (d[+0x18] >> 0xc) & 1 | +0x18 位 12,w1 | bf16-add = 1,f32-add = 0 |
| 内存空间 | OffTileMemoryType | 0x1eb9b420 | (q[+0x10] >> 0x2f) & 7 | +0x10 位 47,w3 | SPMEM=0 · TILE_SPMEM_N=1 · HBM=2 · HBM_4B=3 |
工作样本 — 12 个代表性叶子和每个生成的 composed slot 命令。这 命令是元组(form, StreamOpcode, IsB16, OffTileMemoryType);没有一个整数是 按叶子分配,因此“命令”列是字节派生的字段组合:
| 流叶(模式 × 动词 × dtype × 内存空间) | 表格 | 动词 | IsB16 | 内存空间 | 字节证据 |
|---|---|---|---|---|---|
stream_linear 聚集 → HBM,f32 | 0x3b | 0 | 0 | 2 | 线性 Matches==0x76<<52; verb >>9&7=0 |
stream_linear_add 分散-f32-add → HBM | 0x3b | 6 | 0 | 2 | StreamOpcode>>9&7=6; IsB16>>0xc&1=0 |
stream_strided 聚集 → HBM,f32 | 0x3a | 0 | 0 | 2 | 跨步 Matches==0x74<<52 |
stream_strided_add 分散-f32-add | 0x3a | 6 | 0 | 2 | 形式 0x3a;动词6 |
stream_indirect 聚集 → HBM,f32 | 0x39 | 0 | 0 | 2 | 间接 Matches==0x72<<52 |
stream_indirect 聚集 → HBM_4B | 0x39 | 0 | 0 | 3 | OffTileMemoryType>>0x2f&7=3 |
stream_indirect_add 分散-f32-add → HBM | 0x39 | 6 | 0 | 2 | 动词 6,IsB16 0 |
stream_indirect_add 分散-bf16-add → HBM | 0x39 | 6 | 1 | 2 | IsB16>>0xc&1=1 |
stream_indirect 聚集-f32-add → HBM | 0x39 | 2 | 0 | 2 | 动词 GATHER_FLOAT_ADD=2 |
stream_indirect 聚集-int-添加 → HBM | 0x39 | 1 | — | 2 | 动词 GATHER_INTEGER_ADD=1 |
stream_indirect 分散 → SPMEM 池 | 0x39 | 4 | 0 | 0 | 动词 SCATTER=4;内存空间 0 |
stream_indirect_vreg 聚集(仅限 TEC) | 0x38 | 0 | 0 | 2 | TEC 绑定之一 0xb;形成第4种情况 |
注意 — 无静音盖;这是一个诚实的负面结果。 在 834 中 流叶,0 具有单独字节转储的每叶命令整数,因为 不存在这样的整数 — 搜索在编码器的 11-case 处终止
oneof开关 (cmp $0xa/$0xb) 和四个正交现场访问器。 是什么 字节验证:3 of 4 形式操作码(0x3b/0x3a/0x39直接来自其Matches常数;第四个,IndirectVreg0x38,记录在 同级页面 仅作为 TEC)和 所有四个 命令 字段的移位/掩码。因此,任何一个叶子的命令都可以从它的(pattern,verb,dtype,memspace)没有表的名称分解 — 但有表本身 不存在可转储。重新实现者必须通过打包这四个字段来构建插槽, 不是通过查找叶操作码。明白了 —
(verb, dtype, memspace)与插槽中的操作标识无关。 两个 不同的内在函数(stream_indirect与stream_indirect_add)仅在 3 位上有所不同StreamOpcode他们设置; bf16-vs-f32 的分割是一位,而不是具有两个操作码的两个操作; HBM-vs-HBM_4B 拆分是 memspace 枚举,而不是第三个操作系列。 834路ISel 花名册将这些编码为操作身份(请参阅 §Stream 陷阱 上面),但它们“收敛到”相同的四场槽。每叶“操作码”a 重新实现者可能期望的是 MLIR 层操作爆炸的产物,而不是 HW 命令 号。
深层字段语义、完整编码/解码位图和 StreamOpcode/OffTileMemoryType 枚举名单在 流聚集/分散 上直播;这个 部分的贡献证明了每叶命令间隙是一个“类别错误”—— 命令组成,组成就是上面的四个字段。
此处未列举的内容
本目录中的诚实差距:
- 每叶流→HW 操作码 — 解析为否定结果(参见 §流命令是组合的,而不是按叶的):没有 834 条目静态每叶命令表。 SparseCore 流定序器使用的数字槽命令是在降低时间组装的,由四个正交
SparseCoreStream原型位域组成 — 一个 6 位寻址 form 操作码加上 3 位 verb (StreamOpcode)、一个 1 位 dtype 选择 (GatherScatterAddIsB16) 和一个 3 位 memspace (OffTileMemoryType) — 每个都由其自己确认的访问者读取。(pattern,verb,dtype,memspace)选择不是一个操作码;而是一个操作码。它是这些字段的笛卡尔集合。早期的INFERRED“每叶操作码”框架是错误的:每叶没有任何字节转储,因为编码器开关仅限于 4 个表单,而不是 834 个叶。 - 每固有 LLVM
IntrProperties— 恢复(请参阅 §每内在 IntrProperties):表面使用的所有 12 个 fn-attr 集均经过字节解码,并且每集普查是准确的(总和为 1356);set = IntrinsicsToAttributesMap[ID−1] >> 9查找是确定性的。只有 1340 个非采样 ID 的每叶分配不会单独转录(每个 ID 都加载一个半字)。 MLIR 侧的 OpInterface(MemoryEffect285、AliasAnalysis546、AccessGroup180、Bytecode188)是方言层的对应项。 - 890 个默认构建器操作的精确数量 + 结果
TypeConstraint— 恢复数量(请参阅 §默认构建器数量):(#results, #operands)形状是从每个操作的损坏的Op<…OneResult/ZeroResults…OneOperand/NOperands<Lj N>…>特征包(1356 个中的 1060 个)中字节读取的ops,并列出了完整的分布。结果TypeConstraint一半被解析为负结果:MLIR 层没有每操作Vreg/Mask/Scalar/Ptr谓词 - 每个结果特征都是通用的OneTypedResult<mlir::Type>,验证者通过一个共享的isCompatibleOuterType检查;寄存器类细化仅由下游 LLVM 内在签名执行,而不由 ODS 验证程序执行。 - 扫描/排序/独特引擎操作码位布局 — 按名称映射到 SparseCore 扫描/排序/重复数据删除单元;每个操作的硬件命令位布局未解码(SparseCore 特定的计算单元,而不是 TensorCore LLO 插槽)。
- 完整的数字地址空间 ID 表 —
AddressSpaceDescription开关基数 (201) 和采样的 case 字符串已知;完整的 ID↔ 空间映射(以及addrspacecast叶子在哪些数字 ID 之间进行投射)需要完整的开关臂行走。
交叉引用
- SparseCore 概述 — 这些内在函数是堆栈底部 ISA 的子系统
- SparseCore 后端管道 —
LowerToSparseCoreLlvm位于下降链条中 - 流聚集/分散 — 834 操作主导系列的语义
- 间接 Vreg 流 — CBREG 加窗间接流形式
- CBREG 循环缓冲寄存器 — CBREG 系列驱动器每组 16 个 CBREG 操作
- AddrSpaceCast ISel — 为什么 16 个类型转换作为 IR 内在函数而不是
0xf4节点存在 - Tile-ID 铸件 — 每核转换的tile-id 操作数
- 扫描数据路径 / 分段扫描 — 扫描/缩减系列
- 排序、排名、基数排序 — 排序/唯一/排列系列
- 标量操作码枚举 / 向量操作码枚举 — SC 标量/向量槽操作码的内在函数低于
- EUP / 超越插槽 — 超越系列的 EUP 推送选择器值
- VPU插槽 — 打包/解包/转换/通道/掩码 LLO 编码
- 内存加载插槽 / 内存存储插槽 —
vld/vst插槽编码 - SPU标量插槽 — 标量 ALU 和控制寄存器插槽
- 装拆精度 — 子字节宽度阶梯
- LLO 操作码枚举 — LLO 操作编号系列降低目标
- LLO 操作码表 — 同级附录,LLO 操作码主列表
- 内存空间表 — 同级附录,stream/dma/alloca 系列引用的地址空间 ID
- ISA 概述 — 这些内在函数提供的 LLO 槽/捆绑模型