M-Register Predicate (M0–M31)
本页中的每个 register band、bit offset、shift constant、field-offset immediate、opcode number、struct offset 和 assert string,都逐字节读取自
libtpu-0.0.40-cp314wheel 中的libtpu.so(build-id89edbbe81c5b328a958fe628a9f2207d,buildlibtpu_lts_20260413_b_RC00):来源包括GetVectorMask/GetVMDestregnoband guard、LloRegionBuilder::Vcmaskshift-pack 核心、各 target 的GetVcmaskFieldOffsets/HasVcmaskInstructionvtable body、CreateVmask/CreateLaneVmask/CreateSublaneVmask/CreateVmaskHelperbuilder,以及mlir::tpu::ScanOp::verify契约。地址为 VMA;在.text/.rodata中,VMA == 文件偏移。其他版本会有差异。
摘要
SparseCore 向量 predicate 是一个架构级掩码寄存器文件 M0..M31。一个带掩码的 VEX scan/sort/dedup op 用 5-bit selector 字段(bit0x104,由 VEX Mask/Dest-Port/Sub-Opcode 解码)命名其中之一;被命名的 M-register 提供 scan datapath 消耗的逐 (lane, sublane) 执行 predicate。本页负责 encode 侧交付的内容:M-register 文件(其 32-deep read band 与 16-deep write subset)、寄存器保存的 predicate word,以及 masked-scan inactive-lane output model,即 scan 之后 masked-off lane 读取什么。
关键结构性发现是:M-register predicate 是 range-based,而不是存储的 bitmask。一个 M-register 总是表示 2D 矩形 {sublane ∈ [s_lo, s_hi)} ∧ {lane ∈ [l_lo, l_hi)}。硬件有两种物理实现方式,由 target vtable predicate Target::HasVcmaskInstruction()(vtable slot +0x410)选择:
- NATIVE(
GhostliteTarget= v6e SC、ViperfishTargetSC;HasVcmaskInstruction()=1):四个矩形边界被打包进一个 32-bitvcmaskscalar immediate,位于Target::GetVcmaskFieldOffsets()(vtable slot+0x420)返回的固定位偏移{0, 3, 10, 13}。sublane 字段为 3-bit(⇒ 8 sublanes),lane 字段为 7-bit(⇒ 最多 128 lanes)。 - SYNTHESIZED(
JellyfishTarget、PufferfishTarget;HasVcmaskInstruction()=0):矩形由 iota 比较计算得到,即将 lane-index iota(Vxlaneid)和 sublane-index iota(Vslaneid)与边界比较,然后AND两个 1-D predicate(VectorMaskAndopcode0x195,补集半边使用VectorMaskNegateopcode0x198)。
masked-scan 的inactive-lane 行为不是 VEX bundle micro-field。Inactive input lane 对 reduction identity 作出贡献(在 silicon 中,低于 binary 层);masked-off output lane 由 MLIR lowering 中独立的、scan 之后 VectorSelect(mask, scan_result, else) 处理,其中 else 操作数决定 zero/identity 还是 preserve-old。
重新实现契约如下:
- M-register 是 2D
{sublane-range, lane-range}矩形,而不是逐 lane bitmask。 通过四个边界(s_lo, s_hi, l_lo, l_hi)构建,builder API 中每个范围都是半开[lo, hi);native packer 在打包前把高边界转换为 inclusive(hi − 1)。 - native packed word 是
WORD = (s_start<<0) | (l_start<<3) | (s_end<<10) | (l_end<<13),sublane 字段宽 3 bits(固定SublaneCount = 8),lane 字段宽 7 bits(LaneCount ≤ 128)。偏移{0,3,10,13}来自GetVcmaskFieldOffsets();两个 native generation 返回相同 pair。 - read file 是 32-deep(
M0..M31),op-write subset 是 16-deep(M0..M15)。 scan input mask 可位于M0..M31任意位置;产生 mask 结果的 op(index-scan / uniquify)以及 post-scanVectorSelect只能以M0..M15为目标。 - Masked-off output lane 由 select 驱动,而不是 bundle 驱动。 Inactive input lane 输入 reduction identity(
add→0、min→+INF、max→−INF);output disposition 是下游VectorSelect的else操作数。
| Register file | M0..M31 — SparseCore VPU mask/predicate registers |
| Read band | [0x5f, 0x7e] = M0..M31(32-deep);GetVectorMask @0x13a33320,值为 regno − 0x5f |
| Write subset | [0x5f, 0x6e] = M0..M15(16-deep);GetVMDestregno @0x13a65b20,值为 regno − 0x5f |
| Geometry | SublaneCount = 8(3-bit packed field + VectorMaskConstantPacked(uint8));LaneCount ≤ 128(7-bit field) |
| Native packer | LloRegionBuilder::Vcmask(s_start, s_end_incl, l_start, l_end_incl) @0x1d53f9c0 |
| Native gate | Target::HasVcmaskInstruction() vtable +0x410 — Ghostlite @0x1d497d20 = 1,Viperfish @0x1d49ae60 = 1;Jellyfish @0x1d4904c0 = 0,Pufferfish @0x1d494b60 = 0;abstract base @0x1d61dcc0 是 LogFatal "Unimplemented" stub |
| Field offsets | Target::GetVcmaskFieldOffsets() vtable +0x420 → {0, 3, 10, 13} |
| Native word | (s_start<<0) | (l_start<<3) | (s_end<<10) | (l_end<<13) |
| Synth ops | VectorMaskAnd 0x195,VectorMaskNegate 0x198,VcmpHelper @0x1d55ce40 |
| Output model | post-scan VectorSelect(mask, scan, else);inactive input = reduction identity |
| 置信度 | CONFIRMED(由反编译锚定),除非某行或 callout 另有说明 |
NOTE — 本页负责 M-register 文件、predicate word 和 inactive-lane output model。 用来命名 M-register 的 5-bit selector 字段(
bit0x104)、dest read-port(bit0x10c)和bit0x109second-source port 位于 VEX Mask/Dest-Port/Sub-Opcode。scan op 如何消耗所选 mask(lowering、两部分 predication datapath)位于 Scan Datapath。本页链接它们,而不重复内容。
1. M-Register 文件 — read band、write subset
1.1 两个 band guard,两个宽度
mask register file 是不对称的:scan 或 sort op 可以从 M0..M31 任意位置读取 predicate,但产生 mask 结果的 op(以及 post-scan VectorSelect)只能写入低半区 M0..M15。两个 band guard 逐字节证明了这一点。read getter GetVectorMask<SparsecoreVectorMask> @0x13a33320:
// xla::tpu::sparse_core::isa_emitter::GetVectorMask<...SparsecoreVectorMask> @0x13a33320
__int64 GetVectorMask(__int64 a1) { // a1 = &MCOperand
if ( *(_BYTE *)a1 != 1 ) { /* "operand.isReg()" */ LogFatal(...); }
unsigned int v1 = *(_DWORD *)(a1 + 8); // the register id
if ( v1 <= 0x5E ) { /* "regno >= llvm::TPU::M0" */ LogFatal(...); }
if ( v1 >= 0x7F ) { /* "regno <= llvm::TPU::M31" */ LogFatal(...); }
return v1 - 95; // 95 == 0x5f ⇒ index ∈ [0, 0x1f]
}
```text
write getter `GetVMDestregno` `@0x13a65b20` 的结构相同,但其上界 guard 是 `>= 0x6F`,而不是 `>= 0x7F`:
```c
// xla::tpu::sparse_core::isa_emitter::GetVMDestregno @0x13a65b20
__int64 GetVMDestregno(__int64 this) {
if ( *(_BYTE *)this != 1 ) { /* "operand.isReg()" */ LogFatal(...); }
unsigned int v2 = *(_DWORD *)(this + 8);
if ( v2 <= 0x5E ) { /* "regno >= llvm::TPU::M0" */ LogFatal(...); }
if ( v2 >= 0x6F ) { /* "regno <= llvm::TPU::M15" */ LogFatal(...); }
return v2 - 95; // band [0x5f,0x6e] = M0..M15
}二者都减去 95(0x5f),将文件 dense-index 到从零开始。read band [0x5f, 0x7e] 正好跨越 32 个 id;write band [0x5f, 0x6e] 正好跨越 16 个。mask register Mk 的架构 id 因此是 k + 0x5f,5-bit bit0x104 selector 编码 k = id − 0x5f。
NOTE — read-32 / write-16 是文件分区模型。 分配 mask register 的重新实现者必须遵守两个上限:scan input predicate 可以位于
M16..M31,但VectorSelectmask 和 op-produced mask result 必须位于M0..M15。M16..M31是否存在除编译器通过Vcmask/CreateVmask物化之外的任何 op-produced write path(也就是上半区是否是 read-only predicate input),仅从 band split INFERRED;尚未对上半区运行 write-path-absence search。
1.2 约束文件内容的 VPU geometry
mask register predicate 跨越 SparseCore VPU lane/sublane 网格。两个维度 getter 读取 per-target config blob:
| Getter | 计算 | 来源 |
|---|---|---|
SublaneCount() @0x1d60f300 | QWORD[[Target+0x3b8]+0x1a0] | per-target config |
LaneCount() @0x1d60f400 | QWORD[[Target+0x3b8]+0x198] | per-target config |
AllSublanesMask() @0x1d61c3e0 | (1 << SublaneCount) − 1(0xffffffff >> (32 − count),当 count == 0 时 cmov→0) | 派生 |
ChunkLanesMask() @0x1d61c3a0 | 0xffffffff >> (clz(LaneCount) + 1)(对 LaneCount 做 _BitScanReverse;若 LaneCount 为 2 的幂,则为 LaneCount − 1) | 派生 |
Vxlaneid() @0x1d51d540 | VectorLaneSequence AND ChunkLanesMask | iota |
SublaneCount = 8 由两条独立证据固定:native packed word 为每个 sublane bound 保留 3-bit 字段(0..7),并且 literal mask 可由 LloModule::VectorMaskConstantPacked(uint8) @0x1d506a80 设置,这是一个 8-bit packed sublane mask。LaneCount 从 runtime config 读取,只受 7-bit lane 字段约束(≤ 128);每代的确切值位于 config blob,而不是代码路径中 [确切值为 INFERRED]。
2. Predicate Word — native packed format(Ghostlite / Viperfish)
2.1 Packer 在四个 offset 处连接四个边界
在 native generation 上,LloRegionBuilder::Vcmask(s_start, s_end_incl, l_start, l_end_incl) @0x1d53f9c0 通过将四个边界按 target vtable 提供的偏移 OR 到一起构建 M-register,先物化一个 32-bit ScalarU32Constant,再发出 CreateVectorCreateMask。packing 核心是一个表达式:
// LloRegionBuilder::Vcmask(this, s_start a2, s_end_incl a3, l_start a4, l_end_incl a5) @0x1d53f9c0
v11 = (*(...vtable+0x420...))(target); // GetVcmaskFieldOffsets() → rax:v11, rdx:v12
// v11 = 0x300000000 ⇒ low32 = 0 (s_start shift), byte4 = 3 (l_start shift)
// v12 = 0xd0000000a ⇒ low32 = 0x0a = 10 (s_end shift), byte4 = 0x0d = 13 (l_end shift)
word = ((_QWORD)a4 << SBYTE4(v11)) // l_start << 3
| ((_QWORD)a2 << v11) // s_start << 0
| ((_QWORD)a3 << v12) // s_end << 10
| ((_QWORD)a5 << SBYTE4(v12)); // l_end << 13
v13 = LloModule::ScalarU32ConstantImpl(word, ...); // @0x1d506020
mask = LloInstruction::CreateVectorCreateMask(v13, ...); // @0x1d4db820
```text
这些 offset 是两个 native generation 都相同返回的常量 pair。`GhostliteTarget::GetVcmaskFieldOffsets()` `@0x1d497d60` 和 `ViperfishTarget::GetVcmaskFieldOffsets()` `@0x1d49aea0` 都加载 `rax = 0x300000000`、`rdx = 0xd0000000a`(原始字节 `48 b8 00 00 00 00 03 00 00 00` / `48 ba 0a 00 00 00 0d 00 00 00`),解码为四个 int offset `{0, 3, 10, 13}`。abstract base `Target::GetVcmaskFieldOffsets()` `@0x1d490500` 是 `LogFatal` stub。
> **NOTE — 参数顺序与字段顺序不同。** packing 按*寄存器 pair half* 分配 shift,因此 lane-start bound(`a4`,第三个参数)落在 offset 3,sublane-end bound(`a3`,第二个参数)落在 offset 10。最终字段布局交错了 sublane 和 lane bound;不要假设四个参数按参数顺序打包。
### 2.2 Packed word 布局
```text
31 13 12 10 9 3 2 0
┌────────────────────┬──────┬────────────────┬─────┐
native WORD = │ lane_end (incl) │ subl │ lane_start │ subl│
│ 7 bits │ _end │ 7 bits │_st │
│ << 13 │ 3b │ << 3 │3b<<0│
└────────────────────┴──────┴────────────────┴─────┘
WORD = (s_start << 0) | (l_start << 3) | (s_end << 10) | (l_end << 13)| 字段 | Vcmask 参数 | shift | bits | width | 含义 |
|---|---|---|---|---|---|
sublane_start | a2(s_start) | << 0 | [2:0] | 3 | 第一个 active sublane(0..7) |
lane_start | a4(l_start) | << 3 | [9:3] | 7 | 第一个 active lane(0..127) |
sublane_end | a3(s_end_incl) | << 10 | [12:10] | 3 | 最后一个 active sublane(inclusive) |
lane_end | a5(l_end_incl) | << 13 | [≥13] | 7 | 最后一个 active lane(inclusive) |
offset 0 和 10 处的两个 3-bit sublane 字段(中间夹着 7-bit lane 字段)直接固定 SublaneCount = 8。该 word 是 {sublane_range, lane_range} 矩形描述符,不是逐 lane bitmask;硬件的 vcmask decoder 会把四个边界展开为 active-lane set。
GOTCHA — API 中是半开,word 中是 inclusive。 builder API 接受半开范围
[lo, hi);native call site 为高边界传入hi − 1。CreateLaneVmask调用Vcmask(0, SublaneCount−1, l_lo, l_hi−1);CreateSublaneVmask调用Vcmask(s_lo, s_hi−1, 0, LaneCount−1)。因此 emitter 对 packedsublane_end/lane_end的约定是 inclusive。HWvcmaskdecoder 是否把 end 字段读作 inclusive 还是 exclusive(以及 7-bit lane 字段是在LaneCount处截断还是完整 128)尚未与 decoder arm 交叉核对;HW decode 侧为 INFERRED,emit 侧为 CONFIRMED。
2.3 Literal mask 快捷路径
两个 builder 可以不经过四边界 packer,直接设置 M-register:
| Builder | 参数 | 产物 |
|---|---|---|
LloModule::VectorMaskConstantPacked(uint8) @0x1d506a80 | 8-bit packed sublane bitmask | per-sublane literal(每个 sublane 一 bit ⇒ 8 sublanes) |
LloModule::VectorMaskConstant(bool) @0x1d506940 | true / false | all-ones / all-zeros predicate |
VectorMaskConstantPacked 的 uint8 宽度是 8-sublane geometry 的第二条独立确认。
3. Predicate Word — synthesized format(Jellyfish / Pufferfish)
当 HasVcmaskInstruction() 返回 0 时(JellyfishTarget @0x1d4904c0 和 PufferfishTarget @0x1d494b60 都返回 0),没有 vcmask 指令,因此同一逻辑矩形会被合成为一串 LLO predicate ops:将 lane 和 sublane iota 与边界比较,并 AND 两个 1-D 结果。入口 CreateVmask(s_lo, s_hi, l_lo, l_hi) @0x1d53fc40 首先根据 geometry 校验每个边界,assert string 已逐字节确认:
// CreateVmask(this, s_lo, s_hi, l_lo, l_hi) @0x1d53fc40 — validation, then AND of two sub-masks
// "start_sublane < target().SublaneCount()" / "end_sublane < target().SublaneCount()"
// "start_lane < target().LaneCount()" / "end_lane < target().LaneCount()"
if ( sublane_full && lane_full )
return LloModule::VectorMaskConstant(true); // both ranges full ⇒ all-ones
sublane_sub = CreateSublaneVmask(this, s_lo, s_hi); // optionally SimplifyPredicateNegate'd
lane_sub = CreateLaneVmask(this, l_lo, l_hi);
result = /* VectorMaskAnd(sublane_sub, lane_sub) */ ...; // op 0x195
```text
每个轴向 builder 会 short-circuit 空/满范围,否则调用 `CreateVmaskHelper`:
| Builder | Iota 来源 | 构建的 Predicate | 空/满快捷路径 |
|---|---|---|---|
| `CreateLaneVmask(l_lo, l_hi)` `@0x1d53f740` | `Vxlaneid()` `@0x1d51d540`(`VectorLaneSequence & ChunkLanesMask`) | `l_lo ≤ xlaneid < l_hi` | `l_hi==l_lo` → `false`;`l_lo==0 && l_hi==LaneCount` → `true` |
| `CreateSublaneVmask(s_lo, s_hi)` `@0x1d53d7c0` | `Vslaneid()` `@0x1d51d380`(single);`VectorLaneSequence×LaneCount`(multi) | `s_lo ≤ slaneid < s_hi`(single → `Vslaneid == const` EQ) | `s_hi==s_lo` → `false`;full → `true` |
| `CreateVmaskHelper(iota, lo, hi, range_lo, range_hi)` `@0x1d53f380` | 传入的 iota | `iota ∈ [lo, hi)` | `hi==range_hi` → 单侧(`iota ≥ lo`);`lo==range_lo` → 单侧(`iota < hi`) |
`CreateVmaskHelper` 的通用双侧情况会对 `VcmpHelper` `@0x1d55ce40` 发出两个比较:direction `5` *针对 `hi`*(产生 `iota < hi`),然后 direction `2` *针对 `lo`*(产生 `iota ≥ lo`),并用 `SimplifyPredicateAnd` `@0x1d58e4e0` 组合,后者 lowering 为 `CreateVectorMaskBinop` opcode `0x195`(`VectorMaskAnd`)。两个单侧快捷路径固定了 direction-code 的含义:`lo==range_lo` 分支为上界发出 `VcmpHelper(iota, U32Constant(hi), 4, /*dir*/ 5)`,`hi==range_hi` 分支为下界发出 `VcmpHelper(iota, U32Constant(lo), 4, /*dir*/ 2)`:
```c
// CreateVmaskHelper general (two-sided) arm @0x1d53f380
v18 = VcmpHelper(this, iota, U32Constant(hi), /*op4*/ 4, /*dir*/ 5, 0); // iota < hi
v21 = VcmpHelper(this, iota, U32Constant(lo), /*op4*/ 4, /*dir*/ 2, 0); // iota >= lo
result = SimplifyPredicateAnd(v18, v21); // → CreateVectorMaskBinop op 0x195 = VectorMaskAnd补集半边(当 sub-mask 必须被 negate 时)经过 SimplifyPredicateNegate @0x1d58eb20 → CreateVectorMaskUnop opcode 0x198(VectorMaskNegate)。合成结果是同一逻辑 M-register,即 2D 矩形 {sublane ∈ [s_lo, s_hi)} ∧ {lane ∈ [l_lo, l_hi)},只是物化为 LLO predicate-instruction chain,而不是一个 packed vcmask immediate。
| LLO opcode | 编号 | Builder |
|---|---|---|
VectorMaskAnd | 0x195 | CreateVectorMaskBinop @0x1d4d2b00 |
VectorMaskNegate | 0x198 | CreateVectorMaskUnop @0x1d4d2e80 |
4. Masked-Scan Inactive-Lane Output Model
masked scan 提出两个问题,而 binary 在两个不同位置回答它们。bundle 携带的 M-mask(bit0x104 → 一个 M-register selector)门控哪些 input lane 参与;masked-off output lane 的处置不是 VEX bundle micro-field,而是在上一层的 MLIR sc_tpu.scan lowering 中实现。
SparseCore masked scan — inactive-lane handling is TWO mechanisms
┌──────────────────────────────────────────────────────────┐
│ VEX scan slot (e.g. AddScanS32) │
│ M-mask selector (bit0x104) → names M0..M31 │ ── gates INPUT lanes (HW)
│ inactive INPUT lanes contribute the REDUCTION IDENTITY │ add→0 min→+INF max→−INF
│ output shape == input shape (full-width result) │
└──────────────────────────────────────────────────────────┘
│ scan_result (all lanes occupied)
▼
┌──────────────────────────────────────────────────────────┐
│ post-scan VectorSelect (SEPARATE LLO op, M0..M15 file) │
│ select(mask, then = scan_result, else) │ ── disposes INACTIVE OUTPUT lanes
│ else = zero/identity (fresh) OR prior value (preserve) │
└──────────────────────────────────────────────────────────┘
```text
### 4.1 scan op 携带显式 mask vector operand
`sc_tpu.scan` lowering 通过把 boolean broadcast 到 chunk width 来构建显式 mask operand,并将其送入 scan op(`AtLeastNOperands<1>`、`OneResult`、rank 1 或 2,与 2D lane×sublane geometry 匹配):
```text
scan_mask = lowering_util::BroadcastBoolToVector(b, loc, chunk_size_, /*value=*/true);
sparse_core::ScanOp::create(..., data, scan_mask, reduction_attr);完整 op-name chain 是 lower_scan / max_ell_row_size_scan / masked_scan / sc_tpu.scan / vector.scan。
4.2 verify 契约
mlir::tpu::ScanOp::verify @0x14af7460 断言(rodata error strings):
| Error string | 约束 |
|---|---|
| "Scan is supported only on the SC vector subcore" | 仅 SC vector subcore |
| "Input must be a rank 1 or 2 vector" | rank 1(lane vector)或 2(packed sublanes) |
| "Input and output shape mismatch" | output shape == input shape(scan 产生全宽结果;masked-off lane 仍占据其 slot) |
| "Output element type must be i32 vector for i1 vector inputs" | i1 input ⇒ i32 output |
| "Only sum reduction is supported for i1 vector inputs" | i1 input ⇒ 仅 sum |
i1 → i32 sum-only scan 是 count-active-lanes primitive(DuplicateCount):对置位 predicate bit 的 prefix-count。boolean input 禁止独立 mask,并禁止非 sum reduction。
4.3 Inactive input 与 masked-off output
两半独立解析:
- Inactive INPUT lane 贡献 reduction identity。 因为 scan output 是全宽的(verify 强制
output shape == input shape),masked-off input lane 不能简单消失;它输入 identity element,使运行中的 prefix 不受扰动:add为0,min为+INF,max为−INF。这由masked_scan分类和i1→i32sum 语义 CONFIRMED;每个 family 的确切 identity 是 INFERRED 细节。 - Masked-off OUTPUT lane 由 select 驱动。 LLO op 名册暴露了
VectorSelectOp和vnsel(vector negate-mask select)emitterEmitVectorSelectNegateMask(Vregno dest, Vmregno mask, variant<VregnoOrImm, Sregno> src):它按命名 mask Vmreg 在dest/src之间选择。per-target body 是GhostliteTensorCoreEmitter::EmitVectorSelectNegateMask@0x1424c8a0和ViperfishTensorCoreEmitter::EmitVectorSelectNegateMask@0x141cbca0;abstractIsaEmitter::EmitVectorSelectNegateMask@0x140c1920是LogFatalstub("Instruction vnsel not supported on this platform.")。masked-off output lane 采用 select 的else/src操作数,即 fresh result 的 broadcast identity/zero,或 preserve-old select 的 prior register value。select 的 mask 来自较窄的M0..M15write/select file(§1.1),不同于 scan 的M0..M31read file。
| Layer | 内容 | 证据 |
|---|---|---|
MLIR sc_tpu.scan | 显式 mask vector operand | scan_mask = BroadcastBoolToVector(..., true);ScanOp::create |
| op shape | AtLeastNOperands<1>,OneResult,rank 1/2 | sparse_core::ScanOp traits |
| verify | i1→i32 sum-only(count-active);全宽 output | ScanOp::verify @0x14af7460 strings |
| inactive INPUT lanes | 贡献 reduction identity(不扰动) | masked_scan 分类;sum/min/max identity |
| masked-off OUTPUT lanes | select(mask, scan, else);else = zero/identity 或 preserve-old | VectorSelectOp;vnsel emitter EmitVectorSelectNegateMask(Ghostlite @0x1424c8a0,Viperfish @0x141cbca0;base @0x140c1920 是 LogFatal stub) |
| result commit | inline(VresMove/Sort dest-port)或 out-of-line(PopXrf) | 见 VEX Mask/Dest-Port |
GOTCHA — bundle 只携带 M-mask + scan op;zero-vs-preserve 选择是 lowering 的 select wiring。 试图在 VEX bundle 中寻找 "masked-off output" micro-field 的重新实现者找不到它。硬件 bundle 通过命名的 M-register 门控 input lane;output disposition 是下游
VectorSelect,其else操作数由 lowering 按 scan family 选择。INFERRED — 最底层逐 lane write-enable micro-datapath。 VPU 在物理上是抑制 masked-off output lane 的写入,还是 lowering 总是物化 select,位于 binary 下一层。mask SELECTS predicate(CONFIRMED),inactive INPUT lane 输入 reduction identity(通过
masked_scan分类 +i1→i32sum 语义 CONFIRMED),OUTPUT 在 MLIR 层由 select 驱动(通过VectorSelectOpCONFIRMED);确切 zero-vs-preserve 选择是 per-call 的,硬件 write-enable 尚未用 simulator 核对。
5. 构建 M-Register — 两条路径并列
CreateVmask(s_lo, s_hi, l_lo, l_hi) @0x1d53fc40
│ validate vs SublaneCount() / LaneCount()
│ both ranges full ──────────────► VectorMaskConstant(true) @0x1d506940
▼
HasVcmaskInstruction() (vtable +0x410)
│ │
= 1 (NATIVE) = 0 (SYNTHESIZED)
Ghostlite / Viperfish Jellyfish / Pufferfish
│ │
Vcmask(s_lo, s_hi−1, CreateSublaneVmask(s_lo,s_hi) AND CreateLaneVmask(l_lo,l_hi)
l_lo, l_hi−1) │ Vslaneid / VectorLaneSequence │ Vxlaneid
@0x1d53f9c0 ▼ ▼
word = (s_start<<0) CreateVmaskHelper: VcmpHelper dir5 vs hi (<hi) & dir2 vs lo (≥lo)
| (l_start<<3) → SimplifyPredicateAnd
| (s_end<<10) → VectorMaskAnd op 0x195
| (l_end<<13) (negate half: SimplifyPredicateNegate → VectorMaskNegate op 0x198)
│ │
ScalarU32ConstantImpl an LLO predicate-instruction chain
→ CreateVectorCreateMask
@0x1d4db820
└──────────────┬───────────────┘
▼
one M-register holding the 2D rectangle
{sublane ∈ [s_lo,s_hi)} ∧ {lane ∈ [l_lo,l_hi)}
```text
两条路径产生相同的*逻辑* predicate;只有实现不同(一个 packed `vcmask` immediate,或一条 iota-compare instruction chain)。面向 native generation 的重新实现会发出 packed word;面向 Jellyfish/Pufferfish 的重新实现会发出 compare/AND chain。`Vsmask` `@0x1d53fc00`(sublane-only mask)和 `CreateVectorCreateSublaneMask` `@0x1d4db640` 分支在 sublane-only 情况下遵循相同的 native/synth split。
---
## 6. 尚未钉牢的内容
- **HW `vcmask` decoder inclusivity。** emitter 打包 inclusive end bound(`hi − 1`);VPU decoder 是把 `sublane_end`/`lane_end` 读作 inclusive 还是 exclusive,以及 7-bit lane 字段是在 `LaneCount` 截断还是完整 128,尚未与 decoder arm 交叉核对。HW decode 侧为 **INFERRED**。
- **masked scan 的逐 lane write-enable micro-datapath**(物理 suppress-write vs always-materialized select)。`masked_scan` 分类和 `VectorSelect` lowering 已 CONFIRMED;最低层硬件 write gate 低于 binary。
- **每代确切 `LaneCount`。** 从 runtime config blob `[Target+0x3b8]+0x198` 读取。`SublaneCount = 8` 由 3-bit packed field + `VectorMaskConstantPacked(uint8)` CONFIRMED;`LaneCount ≤ 128` 由 7-bit field 确认,但每代确切值位于 config,而不是代码中。**确切值为 INFERRED。**
- **`M16..M31` 是否有任何 op-produced write path。** read band 是 32-deep,op-write band(`GetVMDestregno`)是 16-deep;上半区是 read-only compiler-materialized predicate input 这一点,是从 band split **INFERRED**,不是来自 write-path-absence proof。native writer(`Vcmask`/`CreateVmask`)以完整逻辑 `M0..M31` 空间为目标。
---
## 交叉引用
- [VEX Mask/Dest-Port/Sub-Opcode](vex-mask-destport-subopcode.md) — 5-bit `bit0x104` M-register *selector*、`bit0x10c` dest read-port 和 `bit0x109` second-source port(命名本页所解码寄存器的 encode 侧)。
- [Scan Datapath](scan-datapath.md) — scan op 如何*消耗*所选 mask:两部分 predication datapath、`ScanOp` lowering 和 scan-mode 名册。
- [VectorExtended / VEX](vectorextended-vex.md) — VEX op family、opcode dispatch 和完整 op 名册。
- [Segmented Scan](segmented-scan.md) — segment-boundary operand frame(`(data, segment)` 绑定,不同于 M-register mask)。
- [TEC (Vector) Engine](tec-engine.md) — 承载 VEX slot 的 64-byte SparseCore vector bundle。
- [SparseCore Overview](overview.md) — TEC/VEX datapath 和 mask register file 在 SparseCore 架构中的位置。