Skip to content

M-Register Predicate (M0–M31)

本页中的每个 register band、bit offset、shift constant、field-offset immediate、opcode number、struct offset 和 assert string,都逐字节读取自 libtpu-0.0.40-cp314 wheel 中的 libtpu.so(build-id 89edbbe81c5b328a958fe628a9f2207d,build libtpu_lts_20260413_b_RC00):来源包括 GetVectorMask/GetVMDestregno band guard、LloRegionBuilder::Vcmask shift-pack 核心、各 target 的 GetVcmaskFieldOffsets/HasVcmaskInstruction vtable body、CreateVmask/CreateLaneVmask/CreateSublaneVmask/CreateVmaskHelper builder,以及 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)选择:

  • NATIVEGhostliteTarget = v6e SC、ViperfishTarget SC;HasVcmaskInstruction() = 1):四个矩形边界被打包进一个 32-bit vcmask scalar immediate,位于 Target::GetVcmaskFieldOffsets()(vtable slot +0x420)返回的固定位偏移 {0, 3, 10, 13}。sublane 字段为 3-bit(⇒ 8 sublanes),lane 字段为 7-bit(⇒ 最多 128 lanes)。
  • SYNTHESIZEDJellyfishTargetPufferfishTargetHasVcmaskInstruction() = 0):矩形由 iota 比较计算得到,即将 lane-index iota(Vxlaneid)和 sublane-index iota(Vslaneid)与边界比较,然后 AND 两个 1-D predicate(VectorMaskAnd opcode 0x195,补集半边使用 VectorMaskNegate opcode 0x198)。

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-scan VectorSelect 只能以 M0..M15 为目标。
  • Masked-off output lane 由 select 驱动,而不是 bundle 驱动。 Inactive input lane 输入 reduction identity(add→0min→+INFmax→−INF);output disposition 是下游 VectorSelectelse 操作数。
Register fileM0..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
GeometrySublaneCount = 8(3-bit packed field + VectorMaskConstantPacked(uint8));LaneCount ≤ 128(7-bit field)
Native packerLloRegionBuilder::Vcmask(s_start, s_end_incl, l_start, l_end_incl) @0x1d53f9c0
Native gateTarget::HasVcmaskInstruction() vtable +0x410 — Ghostlite @0x1d497d20 = 1,Viperfish @0x1d49ae60 = 1;Jellyfish @0x1d4904c0 = 0,Pufferfish @0x1d494b60 = 0;abstract base @0x1d61dcc0LogFatal "Unimplemented" stub
Field offsetsTarget::GetVcmaskFieldOffsets() vtable +0x420{0, 3, 10, 13}
Native word(s_start<<0) | (l_start<<3) | (s_end<<10) | (l_end<<13)
Synth opsVectorMaskAnd 0x195VectorMaskNegate 0x198VcmpHelper @0x1d55ce40
Output modelpost-scan VectorSelect(mask, scan, else);inactive input = reduction identity
置信度CONFIRMED(由反编译锚定),除非某行或 callout 另有说明

NOTE — 本页负责 M-register 文件predicate wordinactive-lane output model 用来命名 M-register 的 5-bit selector 字段(bit0x104)、dest read-port(bit0x10c)和 bit0x109 second-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

c
// 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
}

二者都减去 950x5f),将文件 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,但 VectorSelect mask 和 op-produced mask result 必须位于 M0..M15M16..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() @0x1d60f300QWORD[[Target+0x3b8]+0x1a0]per-target config
LaneCount() @0x1d60f400QWORD[[Target+0x3b8]+0x198]per-target config
AllSublanesMask() @0x1d61c3e0(1 << SublaneCount) − 10xffffffff >> (32 − count),当 count == 0 时 cmov→0派生
ChunkLanesMask() @0x1d61c3a00xffffffff >> (clz(LaneCount) + 1)(对 LaneCount_BitScanReverse;若 LaneCount 为 2 的幂,则为 LaneCount − 1派生
Vxlaneid() @0x1d51d540VectorLaneSequence AND ChunkLanesMaskiota

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 核心是一个表达式:

c
// 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  │
<< 133b<< 33b<<0
                  └────────────────────┴──────┴────────────────┴─────┘
   WORD = (s_start << 0) | (l_start << 3) | (s_end << 10) | (l_end << 13)
字段Vcmask 参数shiftbitswidth含义
sublane_starta2s_start<< 0[2:0]3第一个 active sublane(0..7
lane_starta4l_start<< 3[9:3]7第一个 active lane(0..127
sublane_enda3s_end_incl<< 10[12:10]3最后一个 active sublane(inclusive)
lane_enda5l_end_incl<< 13[≥13]7最后一个 active lane(inclusive)

offset 010 处的两个 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 − 1CreateLaneVmask 调用 Vcmask(0, SublaneCount−1, l_lo, l_hi−1)CreateSublaneVmask 调用 Vcmask(s_lo, s_hi−1, 0, LaneCount−1)。因此 emitter 对 packed sublane_end/lane_end 的约定是 inclusive。HW vcmask decoder 是否把 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) @0x1d506a808-bit packed sublane bitmaskper-sublane literal(每个 sublane 一 bit ⇒ 8 sublanes)
LloModule::VectorMaskConstant(bool) @0x1d506940true / falseall-ones / all-zeros predicate

VectorMaskConstantPackeduint8 宽度是 8-sublane geometry 的第二条独立确认。


3. Predicate Word — synthesized format(Jellyfish / Pufferfish)

HasVcmaskInstruction() 返回 0 时(JellyfishTarget @0x1d4904c0PufferfishTarget @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 已逐字节确认:

c
// 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 @0x1d58eb20CreateVectorMaskUnop opcode 0x198VectorMaskNegate)。合成结果是同一逻辑 M-register,即 2D 矩形 {sublane ∈ [s_lo, s_hi)} ∧ {lane ∈ [l_lo, l_hi)},只是物化为 LLO predicate-instruction chain,而不是一个 packed vcmask immediate。

LLO opcode编号Builder
VectorMaskAnd0x195CreateVectorMaskBinop @0x1d4d2b00
VectorMaskNegate0x198CreateVectorMaskUnop @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 中实现。

text
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 不受扰动:add0min+INFmax−INF。这由 masked_scan 分类和 i1→i32 sum 语义 CONFIRMED;每个 family 的确切 identity 是 INFERRED 细节。
  • Masked-off OUTPUT lane 由 select 驱动。 LLO op 名册暴露了 VectorSelectOpvnsel(vector negate-mask select)emitter EmitVectorSelectNegateMask(Vregno dest, Vmregno mask, variant<VregnoOrImm, Sregno> src):它按命名 mask Vmreg 在 dest/src 之间选择。per-target body 是 GhostliteTensorCoreEmitter::EmitVectorSelectNegateMask @0x1424c8a0ViperfishTensorCoreEmitter::EmitVectorSelectNegateMask @0x141cbca0;abstract IsaEmitter::EmitVectorSelectNegateMask @0x140c1920LogFatal stub("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..M15 write/select file(§1.1),不同于 scan 的 M0..M31 read file。
Layer内容证据
MLIR sc_tpu.scan显式 mask vector operandscan_mask = BroadcastBoolToVector(..., true)ScanOp::create
op shapeAtLeastNOperands<1>OneResult,rank 1/2sparse_core::ScanOp traits
verifyi1→i32 sum-only(count-active);全宽 outputScanOp::verify @0x14af7460 strings
inactive INPUT lanes贡献 reduction identity(不扰动)masked_scan 分类;sum/min/max identity
masked-off OUTPUT lanesselect(mask, scan, else)else = zero/identity 或 preserve-oldVectorSelectOpvnsel emitter EmitVectorSelectNegateMask(Ghostlite @0x1424c8a0,Viperfish @0x141cbca0;base @0x140c1920LogFatal stub)
result commitinline(VresMove/Sort dest-port)或 out-of-line(PopXrfVEX 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→i32 sum 语义 CONFIRMED),OUTPUT 在 MLIR 层由 select 驱动(通过 VectorSelectOp CONFIRMED);确切 zero-vs-preserve 选择是 per-call 的,硬件 write-enable 尚未用 simulator 核对。


5. 构建 M-Register — 两条路径并列

text
                    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 架构中的位置。