地址空间 ID 表(AS0–AS225/501/502)
本页中的每个 ID、MemorySpace 编号和池名称,都是从
libtpu-0.0.40-cp314wheel 中libtpu.so(BuildID md589edbbe81c5b328a958fe628a9f2207d)里的 SparseCore LLVM lowering 函数按字节精确解码得到的。其他版本会有所不同。
摘要
LLVM 后端中的 SparseCore 指针携带一个数值型 地址空间 ID,也就是 !llvm.ptr<N> 中的整数 N。不同于典型 GPU 后端使用紧凑的 AS0..AS5 编号,SparseCore LLVM 方言使用稀疏的分段 ID 空间:0 表示继承的标量内存,201..225(基址 0xc9)表示 SparseCore 专用池及其别名组,501/502(0x1f5/0x1f6)表示两个环形缓冲区窗口。每个 ID 都 1:1 映射到一个从 1 开始的 mlir::sparse_core::MemorySpace 枚举值,而该枚举值又命名一个物理(或虚拟/别名)内存池:smem、tile_spmem、spmem、hbm、sflag、vmem、dreg、timem、simem、iova、mar、按 tile/按 SCS 的变体,以及可能别名的 *_any 超集。
ID 是 LowerToSparseCoreLlvm pass 将 ScDialect memref 操作数路由到叶子 tpu_* intrinsic 的方式:DMA 和 stream lowering 按 (srcMemSpaceID, dstMemSpaceID) 对分派,而 addrspacecast lowering 通过比较两个 ID 转换出的 LLVM 指针类型,来省略或发出 llvm.addrspacecast。这张表通过三条彼此独立且一致到 ID 级别的路径恢复出来:正向 AddressSpaceDescription(ID)→string switch、AddressSpaceToMemorySpace(ID)→MemorySpace jump table,以及反向 MemorySpaceToAddressSpace(MemorySpace)→ID 表。
对重新实现者的约定是:为每个 SparseCore 指针标上其池对应的 ID;用一行 IsOffTileMemory 掩码区分 on-tile 与 off-tile;当精确 tile/core 在静态上未知时,为别名分析规范化到 *Any 超集。
| ID 分段 | 0(基础 Smem);201..225 = 0xc9..0xe1(SC 池 + 别名组);501/502 = 0x1f5/0x1f6(CB 窗口) |
| 命名 ID | 22 个(201 分段中的 19 个 + ID 0 + 501 + 502);6 个保留/空洞槽位(206、207、209、210、221、222) |
| MemorySpace 枚举 | 22 个枚举槽位(从 1 开始,最大 0x16);21 个有效,值 8 是未使用空洞(空名称,无 AS) |
| 正向(ID→name) | mlir::sparse_core::LlvmTpuDialect::AddressSpaceDescription(int) @ 0x135462c0 |
| 正向(ID→MS) | mlir::sparse_core::AddressSpaceToMemorySpace(uint) @ 0x14b78800 |
| 反向(MS→ID) | mlir::sparse_core::MemorySpaceToAddressSpace(MemorySpace) @ 0x14b78780 |
| 池名称(MS→str) | mlir::sparse_core::stringifyMemorySpace(MemorySpace) @ 0x14b78240 |
| On-/off-tile | IsOffTileMemory(MemorySpace) @ 0x13d7ac00 = (ms & ~0x10) != 2 |
| 别名规范化 | GetAnyTypeFromAddressSpace(int) @ 0x1357b400 |
| 可信度 | 除非单元格另有标注,否则均为 CONFIRMED |
主 AS-ID 表
AS# 是 LLVM 地址空间整数(!llvm.ptr<N> 中的 N)。Region/pool 是 stringifyMemorySpace(MS#)。MS# 是 MemorySpace 枚举值(从 1 开始;0 = 无规范池)。Width 是该池覆盖的寻址尺度:每 tile 为 KB、芯片共享为 MB、全局为 GB。tile? 是 IsOffTileMemory==false,仅 MS 2 和 MS 18 为 true。notes 中的 ✓ 表示 ID↔MS 映射已由反向 MemorySpaceToAddressSpace 表确认。
| AS# | hex | Region / pool | MS# | Width | tile? | 含义 · 可信度 |
|---|---|---|---|---|---|---|
| 0 | 0x0 | smem | 1 | KB | off | 继承的基础 TPU 标量内存 ✓ |
| 201 | 0xc9 | tile_spmem | 2 | KB | ON | 每 tile SparseCore SRAM ✓ |
| 202 | 0xca | spmem | 3 | MB | off | 芯片共享 SparseCore SRAM ✓ |
| 203 | 0xcb | hbm | 4 | GB | off | 全局 HBM(embedding 表)✓ |
| 204 | 0xcc | sflag | 5 | — | off | 同步标志内存 ✓(MS 22 sflag_tc 也映射到这里) |
| 205 | 0xcd | vmem | 6 | MB | off | TensorCore 向量内存(TC↔SC 交接)✓ |
| 206 | 0xce | — | 0 | — | — | 保留 / 空洞 |
| 207 | 0xcf | — | 0 | — | — | 保留 / 空洞 |
| 208 | 0xd0 | dreg | 7 | — | off | 数据寄存器窗口 ✓ |
| 209 | 0xd1 | — | 0 | — | — | 保留 / 空洞 |
| 210 | 0xd2 | — | 0 | — | — | 保留 / 空洞 |
| 211 | 0xd3 | — (alias) | 0 | — | off | SflagAny 可能别名超集(无池) |
| 212 | 0xd4 | smem_any | 9 | — | off | SmemAny 可能别名超集 ✓ |
| 213 | 0xd5 | hbm_any | 10 | — | off | HBMAny 可能别名超集 ✓ |
| 214 | 0xd6 | timem | 11 | — | off | 每 tile 指令内存 ✓ |
| 215 | 0xd7 | simem | 12 | — | off | SC 指令内存 ✓ † |
| 216 | 0xd8 | iova | 13 | GB | off | I/O 虚拟地址 ✓ |
| 217 | 0xd9 | sflag_tile | 14 | — | off | 每 tile sflag bank ✓ |
| 218 | 0xda | spmem_any | 15 | — | off | SpmemAny 可能别名超集 ✓ |
| 219 | 0xdb | smem_tile | 16 | KB | off | 每 tile SMEM(TileSmem)✓ |
| 220 | 0xdc | mar | 17 | — | off | memory-access-region ✓ † |
| 221 | 0xdd | — | 0 | — | — | 保留 / 空洞 |
| 222 | 0xde | — | 0 | — | — | 保留 / 空洞 |
| 223 | 0xdf | sflag_scs | 20 | — | off | 每 SCS sflag bank(SflagScs)✓ |
| 224 | 0xe0 | smem_scs | 21 | KB | off | 每 SCS SMEM(SmemScs)✓ |
| 225 | 0xe1 | — (alias) | 0 | — | off | SflagAnySynctile(无池) |
| 501 | 0x1f5 | tile_spmem_cb | 18 | KB | ON | CBREG 窗口化的 TILE_SPMEM ✓ |
| 502 | 0x1f6 | smem_cb | 19 | KB | off | CBREG 窗口化的 SMEM ✓ |
某行上的 † 表示该 ID 的池名称只来自 stringifyMemorySpace,而非 AddressSpaceDescription(见下面的 GOTCHA)。
命名 ID 的 desc(AddressSpaceDescription)字符串按 case 顺序为:TileSpmem、Spmem、HBM、Sflag、Vmem、Dreg、SflagAny、SmemAny、HBMAny、Timem、IOVA、SflagTile、SpmemAny、TileSmem、SflagScs、SmemScs、SflagAnySynctile;ID 0 返回 Smem;501/502 返回 "TileSpmem Circular Buffer" / "Smem Circular Buffer";其他全部返回 "Unknown"。
GOTCHA — ID 215(
simem)和 220(mar)携带真实的MemorySpace(12 和 17),但AddressSpaceDescription会为它们返回空默认值——它们落入与真正保留空洞相同的case 206/207/209/210/215/220/221/222: return result分支。池名称simem/mar来自stringifyMemorySpace,而不是 description switch。只从AddressSpaceDescription派生名称的读取器会错误地把 215/220 当作保留项。
后端如何标记指针
LlvmTpuDialect 不为每个池声明单独的“指针类型”。相反,上面的地址空间整数就是 LLVM 指针类型 !llvm.ptr<N> 中的 N,而 ScDialect memref 通过 memref 属性携带其 MemorySpace。lowering 将其转换为 LLVM AS 编号,并将它用作分派键:
ScDialect op (memref with MemorySpace attr)
→ AddressSpaceToMemorySpace / MemorySpaceToAddressSpace (ID ↔ MS, 1:1)
→ getStridedElementPtr → !llvm.ptr<AS#> (raw element pointer)
→ DMA/stream lowering dispatch on (srcAS, dstAS) (selects tpu_* intrinsic)
```text
`AddressSpaceToMemorySpace(uint)` 是覆盖 ID `201..224` 并带有显式 `501→18` / `502→19` 分支的 jump table;其 `0x1_0000000N` 返回值的低 32 位就是 `MemorySpace` 枚举。`MemorySpaceToAddressSpace(MemorySpace)` 是精确反函数:它索引 `dword_AF36CE8[ms-1]`,并受范围检查 `ms-1 > 0x15`(拒绝 `ms > 22`)和有效性掩码 `0x3fff7f` 约束,后者以 `(0x3fff7f >> (ms-1)) & 1` 测试——`0x3fff7f` 有 **21 位被置位**(21 个有效 MemorySpace 值;bit 7 清零,即值 8 被拒绝)。`stringifyMemorySpace` 和 `TpuVersionToString` 都是指针表查找(`off_219AF590[ms-1]` 和 `off_22011BF0[ver]`,都从 1 开始),其字符串指针位于 `.data.rel.ro`,并在加载时由 `R_X86_64_RELATIVE` 重定位填入——它们在磁盘镜像中读作零(已确认:`off_219AF590` 的每个槽位在磁盘上都是 `0x0`;解析 RELATIVE 重定位后得到 `smem`、`tile_spmem`、…、`sflag_tc`)。
---
## On-Tile 与 Off-Tile(访问语义门控)
`IsOffTileMemory(MemorySpace)` 是一个单独的带掩码比较:
```c
bool IsOffTileMemory(int ms) { return (ms & 0xFFFFFFEF) != 2; } // (ms & ~0x10) != 2清除 bit 4(0x10)会把 MS 2(tile_spmem)和 MS 18 = 0x12(tile_spmem_cb)折叠到一起,因此只有这两个是 on-tile。其他每个池——hbm、spmem、smem、sflag、vmem、dreg、timem、simem、iova、mar,以及所有 *_tile/*_scs/*_any 变体——都是 off-tile,需要通过 DMA、stream 或 sync 才能到达。这就是 DMA 和 stream lowering 在选择数据移动 intrinsic 前查询的谓词。
*Any 可能别名规范化
当指针的精确 tile 或 core 在静态上未知时,SparseCore LLVM 后端会将其拓宽到通配 *Any 空间,以供别名分析使用。GetAnyTypeFromAddressSpace(int) 是规范化器:
| 具体 ID(名称) | → 规范 ID(名称) |
|---|---|
201 TileSpmem, 202 Spmem | 218 SpmemAny |
203 HBM | 213 HBMAny |
204 Sflag | 211 SflagAny |
205 Vmem | 205 Vmem(自身——没有单独的通配符) |
219 TileSmem, 0 Smem | 212 SmemAny |
*Any ID(211/212/213/218)携带 description,但没有 MemorySpace 池——它们是别名分析分组,不是物理池。对已经是通配空间或叶子空间(Dreg、Timem、IOVA、SflagTile、*Any ID 自身)调用 GetAnyTypeFromAddressSpace 会命中 LogFatal("Unsupported address space: ") 分支(llvm_tpu_dialect_only.h:100),因此该规范化器只在上面的具体空间上是全函数。
NOTE —
*Any拓宽是 SparseCore 对 fat-pointer 问题的回答:指向 HBM/SPMEM 且所属 tile 为运行时值的指针,无法证明与另一个同类指针不相交,因此后端为两者都分配HBMAny/SpmemAny超集,并让别名分析把它们视为 may-alias。具体空间与 Any 空间的区别,让静态解析出的 tile-local 访问不会被悲观化。
交叉验证与 CheckAddressSpaces
四个访问器构成一个闭合的自检系统:
AddressSpaceDescription(ID) : ID → human string @0x135462c0
AddressSpaceToMemorySpace(ID) : ID → MemorySpace @0x14b78800
MemorySpaceToAddressSpace(MS) : MemorySpace → ID (inv) @0x14b78780
stringifyMemorySpace(MS) : MemorySpace → pool name @0x14b78240
```text
对全部 21 个命名 ID,正向和反向 ID↔MS 映射都是精确反函数(已逐分支对照反编译 switch 验证)。`CheckAddressSpaces(SparseCoreTarget&, Operation*, int, int)` @ `0x135b8e00` 是 lowering 在发出数据移动 intrinsic 之前,用来针对目标验证 `(src, dst)` ID 对的 verifier;它的完整合法性矩阵(每个 primitive 允许哪些 pair)此处未枚举——这里只确认其存在和签名。
---
## 相关组件
| 名称 | 关系 |
|---|---|
| `LowerToSparseCoreLlvm` pass | 读取这些 ID,将 memref 操作数路由到 `tpu_*` intrinsic |
| `MemorySpaceCastOpLowering` @ `0x135a5c20` | 通过比较转换后的指针类型来省略/发出 `llvm.addrspacecast` |
| `DmaSimpleStartOpLowering` / `LinearStreamStartOpLowering` | 按 `(srcAS, dstAS)` / `(dtype, off-tile MS, verb)` 分派 |
| `getStridedElementPtr` | 将 memref+index 转成原始 `!llvm.ptr<AS#>` |
## 交叉引用
- [内存层级](memory-hierarchy.md) — 这些池所填充的 HBM/VMEM/SMEM/SFLAG/CMEM 分层模型
- [内存空间枚举](../isa/memory-space-enum.md) — `MemorySpace` 枚举:22 个槽位,21 个有效(值 8 为空洞)
- [Fat Pointers (AS 7/8/9)](../sparsecore/fat-pointers-as789.md) — SparseCore fat-pointer 编码与 `*Any` 超集关系
- [addrspacecast ISel](../sparsecore/addrspacecast-isel.md) — 针对这些 ID 的 `llvm.addrspacecast` 省略或发出规则
- [Tile-ID Cast](../sparsecore/tile-id-cast.md) — 具体 tile-local AS 如何拓宽为其 `*Any` 规范形式
- [SC Type Converter](../compiler/sc-type-converter.md) — `SCTypeConverter` 将 `MemorySpace` memref 属性映射到 `!llvm.ptr<AS#>` 的方式
- [Lower To SparseCore LLVM](../compiler/lower-to-sparsecore-llvm.md) — 消费这些 ID 并将 memref 操作数路由到 `tpu_*` intrinsic 的 pass