NOP / 未用槽位规范编码
本页中的每个偏移、opcode 值和地址都从
libtpu-0.0.40-cp314wheel 中的libtpu.so按字节精确读取(BuildID md589edbbe81c5b328a958fe628a9f2207d— 明确锚点;运行时报告的0.103无法在二进制中静态验证)。其他版本会不同。
摘要
TensorCore bundle 是一个固定宽度的 VLIW 发射字 — 41 B(Jellyfish / TPU v2)、51 B(Pufferfish / TPU v4)、64 B(Viperfish / Ghostlite / 6acc60406、TPU v5p / v6e / TPU7x)— 每个执行单元一个槽位(MXU、两条标量 lane、两条向量 ALU lane、向量 load / store / cmem-load、两个 vector-extended-to-MXU 端口、两个 vector-result-FIFO read,以及一个 misc/sequencer 槽位)。在几乎每个周期里,编译器都不会为其中一些槽位安排操作,因此编码器必须发出一个已定义的“此槽位不做任何事”模式,使解码器能够往返处理,并且硬件会可靠跳过。本页是该模式的编码/解码支持参考:空闲槽位和整个空闲 bundle 在线上的样子。
这里有两种不同的无操作机制,重新实现者必须把它们分开。第一种是空槽位谓词填充:每个槽位都携带一个谓词字段,未填充槽位会被盖上架构哨兵 kNeverExecute = 31(0xb834cfc),sequencer 将其读作“此槽位在本周期被谓词关闭”。这是把缺席槽位变为 no-op 的机制,也是整 bundle NOP 的来源。第二种是 opcode 空间 NOP:每个槽位的 opcode 枚举保留一个专用 Noop 值 — 一个 <Slot>_Noop proto 子消息,其 opcode 字段是该字段的全 1 最大值(5 位 opcode 为 31,4 位 Viperfish vector-extended opcode 为 15)。当某个槽位必须出现在 bundle 的 has-mask 中(因此解码器会访问它)但又不携带工作时,会使用 opcode 空间 NOP;最重要的情况是在 codec 需要一个有效但惰性的模板时物化出的默认 bundle 内部。
两者共存的原因是 bundle 的两级占用模型。bundle 有按槽位的 has-bit(此槽位是否存在于 proto 中?)以及独立的按槽位谓词(如果存在,本周期是否触发?)。最便宜的空槽位会清除 has-bit,并且根本不编码 — 但 codec 的 FillDefaultBundle 路径需要每个槽位都存在(所有 has-bit 置位),使字节确定;对于这些存在但惰性的槽位,它把 kNeverExecute 谓词与 opcode 空间 Noop 配对(或者在 scalar-0 槽位中配对 ScalarHalt)。本页依次介绍:整 bundle NOP 概览;按代际的空槽位谓词填充;每槽位 opcode 空间 Noop 值及其位位置;以及 bundle 打包器在降低 LLO 流时如何留下未用槽位。
对于重新实现,契约是:
- 空槽位哨兵
kNeverExecute = 31及各代际盖写它的位置(EncoderJf::EncodeBundleInternal序言;FillDefaultBundle;V5+ bundle header)。 - 每个槽位的 opcode 空间
Noop:一个独立 proto 类型,其 opcode 字段是该字段宽度的全 1 值,由<Slot>NoopOpcode::Matches识别。 - 默认 bundle 例外:
FillDefaultBundle将谓词15(kAlwaysExecute)+ 一个ScalarHalt操作盖写到 scalar-0,并将31(kNeverExecute)盖写到其他每个槽位。 - 打包器填充规则:打包器让未用槽位的 has-bit 保持清除;编码器的预填充(
kNeverExecute)提供 no-op,因此新建的 bundle 不是全零缓冲区。
| 空槽位哨兵 | kNeverExecute = 31 (0x1F) @ 0xb834cfc |
| 始终执行哨兵 | kAlwaysExecute = 15 (0x0F) @ 0xb834cf8 |
| 谓词字段宽度 | 每槽位 5 位([0:3] 寄存器索引,[4] 极性;0x1F = never) |
| Opcode 空间 NOP | <Slot>_Noop proto;opcode 字段 = 字段宽度的全 1(5-bit → 31,VF VEx 4-bit → 15) |
| JF 空槽位盖写 | EncoderJf::EncodeBundleInternal @ 0x1e86c7c0(内联序言 store) |
| PF 默认 bundle | TensorCoreCodecBase<…>::FillDefaultBundle @ 0x1d222ee0 |
| NOP 识别器 | <Slot>NoopOpcode::Matches — (~field & mask) == 0(每个 opcode 位都置位) |
| 默认 scalar-0 操作 | TensorCoreScalar0_ScalarHalt(在 FillDefaultBundle 中默认构造) |
| 置信度 | CONFIRMED(字节锚定),除非某行另有说明 |
整 Bundle NOP 概览
规范空闲 bundle 是每个槽位都被谓词关闭。它不是全零缓冲区:每个槽位的谓词字段都必须持有非零哨兵 31。下表按代际给出必须盖写谓词的槽位数量、盖写值,以及执行盖写的函数。
| Gen | Bundle | 空闲 bundle 定义 | 盖写值 | 盖写函数 |
|---|---|---|---|---|
| Jellyfish (v2) | 41 B | 全部 8 个槽位谓词字段 = kNeverExecute | 31 | EncoderJf::EncodeBundleInternal @ 0x1e86c7c0(内联序言) |
| Pufferfish (v4) | 51 B | 全部 12 个槽位谓词 = 31;scalar-0 默认 = ScalarHalt@15 | 31 / 15 | …CodecBase<TensorCoreBundle,…>::FillDefaultBundle @ 0x1d222ee0 |
| Viperfish (v5p) | 64 B | 每槽位谓词字段 = 31;缺席槽位不编码 | 31 | bundle-header 预填充(vxc 编码器集) |
| Ghostlite (v6e) | 64 B | 每槽位谓词字段 = 31 | 31 | bundle-header 预填充(glc 编码器集) |
6acc60406 (TPU7x) | 64 B | 两项 TensorCorePredicates 池 + 每槽位选择器;空闲选择器指向一个等价于 31 的池项 | 池索引 | bundle-header 预填充(gfc 编码器集) |
陷阱 — 空闲 bundle 是非零的。 因为空标记是
kNeverExecute = 31(0x1F)— 一个复制到每个槽位谓词字段中的非零 5 位模式 — 所以先memset(bundle, 0, width)再只填充活跃槽位,会让非活跃槽位保持谓词0,而这是对谓词寄存器 P0 的有效引用(槽位会触发,受 P0 门控)。空值是显式的31盖写,绝不是零。用清零内存构造“预期空闲 bundle”的位精确往返测试,会在每个未用槽位上与真实编码器静默不一致。注意 — “整 bundle NOP”有两种形式,并且编码不同。打包器的空闲 bundle 会让未用槽位的 has-bit 清除,因此它们完全不序列化,只出现 header 预填充的谓词字节。codec 的
FillDefaultBundle模板会设置所有 has-bit,并给每个存在槽位一个谓词-31+ opcode-Noop对(scalar-0 除外)。前者是真实调度在稀疏周期中发出的内容;后者是用于定大小、零初始化和解码器预热的确定性全存在模板。
空槽位谓词填充
谓词字段是通用的“跳过此槽位”杠杆,编码器会在任何真实操作覆盖之前,把哨兵写入每个槽位。谓词是 5 位字段:位 [0:3] 是谓词寄存器索引(0..14 = P0..P14,15 = kAlwaysExecute 常真),位 [4] 是极性/取反位,全置位值 0x1F = 31 是 kNeverExecute — 该槽位不运行。三个哨兵常量在 .rodata 中相邻:kPredicateRegisterCount = 15 @ 0xb834cf4、kAlwaysExecute = 15 @ 0xb834cf8、kNeverExecute = 31 @ 0xb834cfc。
Jellyfish — 内联序言盖写
EncoderJf::EncodeBundleInternal(0x1e86c7c0)是直接打包编码器:它在一个 53 字节 scratch 结构中工作,用两个 ymm store 清零槽位区域,然后通过把哨兵直接写入该结构 qword 中槽位的绝对 bit,把 kNeverExecute & 0x1F 盖写到每个槽位的谓词字段。反编译并去混淆后的序言如下:
// EncoderJf::EncodeBundleInternal prologue @ 0x1e86c7c0
vmovups [struct+0x20] = 0; vmovups [struct+0x14] = 0; // clear the slot region
nx = kNeverExecute & 0x1F; // = 31
*(uint64*)(struct+0x2D) = (nx << 53) | (nx << 26); // scalar_0 pred @abs 317, scalar_1 @abs 290
*(uint16*)(struct+0x1D) = nx << 11; // VALU lane0 pred @abs 147
*(uint32*)(struct+0x16) = nx << 5; // VALU lane1 opcode-region init
*(uint16*)(struct+0x1A) = nx << 4; // = 0x1F0 // VALU lane1 pred @abs 116
*(uint8 *)(struct+0x1C) = 0; // window high byte clear
*(uint64*)(struct+0x0C) = (0x400000800000000 * nx) // VLoad pred @abs 58 + MXU pred @abs 35
| (nx << 22) // VResult pred @abs 22
| (nx << 13); // Misc predication @abs 13
```text
常量 `0x400000800000000` 正好有两个置位 bit — bit 35 和 bit 58 — 因此乘以 `31` 会一次性把 `kNeverExecute` 放到 MXU 谓词(abs 35)和 vector-load 谓词(abs 58)。由于结构字节 `0x0C` 是 bundle bit 96,qword-0 的 shift 常量(`<<35`、`<<58`、`<<22`、`<<13`)可直接读作绝对 bundle bit 位置。存在槽位的每槽位 writer(例如 `EmitVectorBinop`)随后会用真实的 `EncodePredication` 值覆盖其谓词字段;缺席槽位保留 `31`。
| 槽位 | 谓词绝对 bit | 预填充 store |
|---|---:|---|
| Scalar 0 | 317 | `[struct+0x2D] \|= 31<<53` |
| Scalar 1 | 290 | `[struct+0x2D] \|= 31<<26` |
| VALU lane 0 | 147 | `[struct+0x1D] = 31<<11` |
| VALU lane 1 | 116 | `[struct+0x1A] = 0x1F0` |
| Vector load | 58 | `[struct+0x0C] \|= 31·0x400000800000000` (bit 58) |
| MXU | 35 | `[struct+0x0C] \|= 31·0x400000800000000` (bit 35) |
| Vector result | 22 | `[struct+0x0C] \|= 31<<22` |
| Misc | 13 | `[struct+0x0C] \|= 31<<13` |
### Pufferfish — `FillDefaultBundle`
Pufferfish 是基于记录的:codec 构建一个全存在默认 bundle,并让字节序列化器读取它。`TensorCoreCodecBase<TensorCoreBundle, …>::FillDefaultBundle`(`0x1d222ee0`)默认构造十二个槽位子消息中的每一个,在 `proto+0x10` 的字中设置全部十二个 has-bit,并把谓词值写入每个子消息的谓词字段(位于子消息偏移 `+0x1c` 或 `+0x20`,取决于槽位类型;反编译为 `*(_DWORD*)(slot+28) = 31` / `*(_DWORD*)(slot+32) = 31`)。这里有**十一个** `= 31` store 加上一个 `= 15` store — 即下面的 scalar-0 例外。
```c
// FillDefaultBundle(TensorCoreBundle*) @ 0x1d222ee0 (decompiled, de-obfuscated)
TensorCoreBundle(bundle, /*arena*/0);
bundle->has_mask |= 1; // proto+0x10 bit0 = scalar_0 present
s0 = DefaultConstruct<TensorCoreScalar0>(arena); // slot 0
s0->predicate = 15; // kAlwaysExecute — NOT 31
s0->has_mask |= 4;
s0->inst_case = 6; // ScalarHalt oneof tag
s0->inst = DefaultConstruct<TensorCoreScalar0_ScalarHalt>(arena); // proto+0x48
s1 = DefaultConstruct<TensorCoreScalar1>(arena); s1->predicate = 31; // kNeverExecute
valu0 = DefaultConstruct<TensorCoreVectorAlu0>(arena); valu0->predicate = 31;
valu1 = DefaultConstruct<TensorCoreVectorAlu1>(arena); valu1->predicate = 31;
vstore = DefaultConstruct<TensorCoreVectorStore>(arena); vstore->predicate = 31;
vload = DefaultConstruct<TensorCoreVectorLoad>(arena); vload->predicate = 31;
cmem = DefaultConstruct<TensorCoreCmemLoad>(arena); cmem->predicate = 31;
vex0 = DefaultConstruct<TensorCoreVectorExtended0>(arena); vex0->predicate = 31;
vex1 = DefaultConstruct<TensorCoreVectorExtended1>(arena); vex1->predicate = 31;
vres0 = DefaultConstruct<TensorCoreVectorResult0>(arena); vres0->predicate = 31;
vres1 = DefaultConstruct<TensorCoreVectorResult1>(arena); vres1->predicate = 31;
misc = DefaultConstruct<TensorCoreMisc>(arena); misc->predicate = 31;
// all 12 has-bits now set; serializer produces the deterministic default 51-byte word陷阱 — 默认 bundle 不是“所有槽位都被谓词关闭”。Scalar-0 是例外:
FillDefaultBundle把谓词15(kAlwaysExecute) 盖写到 scalar-0,并给它一个默认ScalarHalt操作,而其他每个槽位都得到谓词31(kNeverExecute)。因此默认 bundle 会执行一条指令 — halt — 并跳过其余槽位。这是一个刻意的安全模板:落入默认状态的 bundle 会停止程序,而不是运行垃圾。把31盖写到 scalar-0 以构造“完全空闲”默认值的重新实现,会让执行越过末尾而不是停机。
Viperfish / Ghostlite / 6acc60406 — header 预填充
V5+ 代际(vxc、glc、gfc)使用通用 bit 打包器 BitCopy(dst, dst_bit, src, src_bit, nbits)(0x1fa0a900)构建 64 字节缓冲区,由每个槽位的 <Slot>Encoder::Encode 驱动。空槽位谓词会在任何槽位被填充之前写入 bundle header,其精神与 JF/PF 盖写相同;已填充槽位的每槽位谓词字段随后会覆盖默认值。在 Viperfish 上,谓词是每个标量槽位本地的 4+1 字段(4 位寄存器索引 + 1 位反转)。在 6acc60406 上,每槽位字段缩小为一个 2 位选择器,索引 bundle 级两项 TensorCorePredicates 池;空闲槽位的选择器解析为 never-execute 池项。(VF/GL header 预填充为 HIGH;6acc60406 池选择器空闲值为 MEDIUM — “never”的确切池项编码未像 JF/PF 的 31 盖写那样绑定到单个 store,见残余空白。)
每槽位 Opcode 空间 NOP
独立于谓词,每个槽位的 opcode 枚举都保留一个 Noop 值。它存在的原因是让一个槽位能够出现在 has-mask 中并被解码器访问,同时不携带操作 — 这是 FillDefaultBundle 产生的情况,也是反汇编器必须往返处理的情况。Noop 是一个独立 proto 子消息类型(<Slot>_Noop),不持有字段 — 其构造函数只安装 vtable 和 arena 指针(TensorCoreScalar0_Noop::TensorCoreScalar0_Noop @ 0x1fa64240、TensorCoreMisc_Noop @ 0x1fa62000、vxc::isa::TensorCoreVectorExtended_Noop @ 0x1fb0a120)— 并且其 opcode 字段是该字段 bit 宽度的全 1 最大值。
全 1 规则
规范证据是每个槽位的 <Slot>NoopOpcode::Matches 谓词。Matches 当且仅当槽位 opcode 字段的每一位都置位时返回 true,在二进制中写作惯用式 (~field & mask) == 0 — 即 ~field 在 mask 内没有任何 bit,因此 field 拥有 mask 的全部 bit。该 mask 是该槽位的连续 opcode 字段:
| Gen / slot | <Slot>NoopOpcode::Matches @ | Opcode mask | 字段宽度 / 位置 | NOP opcode 值 |
|---|---|---|---|---|
| PF VectorAlu0 | 0x1ed40820 | 0x1F00000000000 | 5-bit @ bit 44 | 31 |
| PF VectorAlu1 | 0x1ed63c80 | (5-bit, sym to Alu0) | 5-bit | 31 |
| PF Scalar0 | 0x1ed14480 | 0xF80000 | 5-bit @ bit 19 | 31 |
| PF Scalar1 | 0x1ed27be0 | (5-bit) | 5-bit | 31 |
| PF Misc | 0x1ed016c0 | 0x1F000000000 | 5-bit @ bit 36 | 31 |
| PF VectorLoad | 0x1ee280e0 | 0x1F00 | 5-bit @ bit 8 | 31 |
| PF VectorStore | 0x1ee38e00 | 0x7C00000000 | 5-bit @ bit 34 | 31 |
| PF CmemLoad | 0x1ecf87e0 | 0x7C000000000000 | 5-bit @ bit 50 | 31 |
| PF VectorExtended0 | 0x1eda6400 | 0x7C00000000 | 5-bit @ bit 34 | 31 |
| PF VectorExtended1 | 0x1edfdc60 | (5-bit) | 5-bit | 31 |
| PF VectorResult0 | 0x1ee2ae40 | 0x7C00000000000000 | 5-bit @ bit 58 | 31 |
| PF VectorResult1 | 0x1ee2ce00 | (5-bit) | 5-bit | 31 |
| VF VectorExtended0 | 0x1ef98480 | 0xF | 4-bit @ bit 0 | 15 |
| VF VectorExtended1 | 0x1efe3540 | (4-bit) | 4-bit | 15 |
示例 — TensorCoreVectorAlu0NoopOpcode::Matches(0x1ed40820)反编译为单个表达式:
// asic_sw::deepsea::pxc::isa::TensorCoreVectorAlu0NoopOpcode::Matches @ 0x1ed40820
bool Matches(this) {
return (~*(uint64*)(this + 32) & 0x1F00000000000LL) == 0; // every bit of the 5-bit
} // opcode field (bits 44..48) set
```text
`0x1F00000000000` 是 `0b11111 << 44` — 一个全置位值为 `31` 的 5 位字段。相同形态会在每个 PF 槽位中重复出现(始终 5 位,始终全 1 = `31`),并在 Viperfish vector-extended 槽位中缩小为 4 位(`0xF`,全 1 = `15`),后者的 opcode 空间窄一位。
> **怪癖 — NOP opcode 是*最后一个* opcode,而不是第一个。** 每个槽位的 opcode 枚举都把 `Noop` 放在最大可编码值(全 1),而不是 `0`。Opcode `0` 在每个槽位中都是真实操作(例如第一个算术 op),因此为“无工作”发出 opcode `0` 的重新实现会发射一个活跃 ALU op。可靠的“此槽位 opcode 空间中无工作”值是字段的全 1 最大值,解码器通过全 bit 置位测试识别它,而不是通过单个具名常量。
>
> **注意 — opcode-`Noop` 和 predicate-`kNeverExecute` 是正交的,并且通常组合使用。** 在 `FillDefaultBundle` 中,非 scalar-0 槽位既是 opcode-`Noop`,也是 predicate-`31`。任一者单独都足以让槽位惰性:predicate-`31` 会无视 opcode 跳过它,而 has-bit 清除的槽位甚至不会被解码。opcode-`Noop` 专门在存在且被访问的情况下重要,此时解码器必须分类 opcode bit,否则会拒绝未知值。
### LLO 层 no-op
在 bundle 之上,[LLO opcode 枚举](llo-opcode-enum.md)携带自己的具名 no-op,并降低为这些槽位编码:`kVectorNop`(`0x047`,向量 no-op,与 `kVectorMaskMove` 共享 `GhPerf` cost 行 `0x1B4`)会降低到一个 VALU 槽位,其 opcode 空间值是全 1 `Noop`;`kScalarHalt`(`0x025`,`…YieldConditional`/`…OnError` 位于 `0x026`/`0x027`)是 scalar-0 默认操作物化出的 sequencer halt。这些是 IR 可见名称;bundle 字节是上文记录的全 1 opcode 和谓词哨兵。
---
## Bundle 打包器对未用槽位的填充
[bundle 打包器](../sched/llo-bundle-packing.md)把独立 LLO op 分组到一个 `Bundle` proto 中,每个已填充槽位一个有类型子消息,其余留空。它**不会**合成 `Noop` op,也不会清零任何内容 — 它完全依赖编码器序言的 `kNeverExecute` 预填充。该模型可从 JF `MakeInstruction` / `FindFreeSlot` 路径以及 `EncodeBundleInternal` 中的槽位掩码分派看到:
```c
// Conceptual packer → encoder flow (JF; PF/V5+ analogous)
function PackAndEncode(llo_ops, bundle):
bundle.slot_mask = 0; // proto+0x10 — all slots absent
for op in llo_ops_in_this_cycle:
slot = FindFreeSlot(bundle, op.kind); // 0x140c0180 — legality + occupancy
if slot == NONE: break; // start a new bundle
slot.fill(op); // EmitVectorBinop / EmitScalarLoad / …
bundle.slot_mask |= (1 << slot.index); // mark has-bit set
EncodeBundleInternal(bundle): // 0x1e86c7c0
prefill_all_predicates(kNeverExecute); // 31 into every slot's predicate field
for slot in slots:
if bundle.slot_mask & (1 << slot.index):
slot_encoder.write(bundle.sub[slot]); // overwrites predicate with real value
// else: leave the prefilled kNeverExecute — this is the canonical empty slot重新实现者必须复现三个后果:
- 未用槽位在 proto 中缺席,从不是显式
Noop。 打包器让 has-bit 保持清除;槽位字节完全来自预填充。显式<Slot>_Noopop 只通过FillDefaultBundle出现,不通过正常打包出现。 - 预填充就是契约。 因为编码器先清零槽位区域,然后把
31盖写到谓词子字段,空槽位字节是确定且解码稳定的。跳过预填充会让空槽位继承 scratch 缓冲区中原有的任何内容。 ValidatePacking会重新检查谓词范围。 每个槽位的谓词字段都必须在{0..14, 15, 31}内;打包器的 hazard 分析(add_consumes_predicate_register0x1e851be0、add_produces_predicate_register0x1e851c60)跟踪谓词 def-use,因此已打包 bundle 的谓词合法,而未填充槽位的预填充31按构造通过。
陷阱 — 没有 bundle 内转发意味着空槽位确实是空闲的。 因为 bundle 中所有槽位在同一周期发射,并且没有 write→read 转发(见 Bundle 模型),留下空槽位不会带来正确性成本 — 只会浪费发射宽度。打包器的职责是为吞吐量填充槽位,而不是满足 bundle 内依赖;真实依赖总是跨 bundle 序列化或通过同步标志等待。因此规范 NOP 纯粹是密度产物,而不是 hazard 修复。
解码侧
解码器会往返处理两种机制。谓词读取是 DecoderJf::GetPredicateRegister(0x1e84eae0,返回 v & 15 — 4 位寄存器索引,其中 15 = always)和 GetPredicateValue(0x1e84eb00,返回 (v & 16) == 0 — 极性位);完整 5 位读取到 0x1F 就是 kNeverExecute skip。opcode 空间 Noop 由每个槽位 Decode 阶梯内部的 <Slot>NoopOpcode::Matches 全 bit 置位测试识别。V5+ 解码器按固定顺序尝试 opcode 候选 — gfc::isa::TensorCoreVectorExtended0Decoder::Decode(0x1f96d020)会遍历 LoadMultiplicandUpperBlock… → B32Masked → B16Masked → B8Masked opcode Matches 谓词;拥有 Noop 的向量槽位(例如承载 MatrixMultiply*/PushMatrix* 的 extended 槽位)会较早测试 Noop,因此惰性槽位能解析,而不会落入“value does not match any encodings”状态错误。见 解码侧:JF / PF 和 解码侧:VF / GXC。
残余空白
6acc60406(gfc) 空闲槽位值 — MEDIUM。6acc60406用指向两项TensorCorePredicates池的 2 位选择器替代每槽位谓词字段。因此整 bundle 空闲模式取决于池内容,而“never execute”的确切池项编码(以及未填充槽位携带的默认选择器)没有像 JF/PF 的31盖写那样绑定到单个 store。预期全 1 opcode-Noop规则仍然成立(gfc向量槽位携带同一Noopopcode 族),但尚未读取gfc::…NoopOpcode::Matches函数体来确认字段宽度;对6acc60406标记为 Inferred。缺失证据:gfcbundle-header 预填充 store 和一个gfcNoopOpcode::Matches函数体。- Viperfish / Ghostlite header 预填充位置 — HIGH 而非 CONFIRMED。
vxc/glc空槽位谓词会在槽位填充前写入 bundle-header 构造(这与每槽位 4+1 谓词字段以及上文确认的 VFTensorCoreVectorExtended0NoopOpcode::Matches4 位0xF一致),但单条预填充指令没有像 JF/PF 的EncodeBundleInternal/FillDefaultBundle那样隔离到一个地址。缺失证据: 确切的vxc/glcheader-stamp store 地址。
交叉引用
- Bundle 模型 — VLIW no-scoreboard 契约以及本页按槽位展开的
kNeverExecute空槽位约定 - Bundle: Jellyfish 41 B —
EncodeBundleInternal序言和 JF 预填充的每槽位谓词绝对 bit 映射 - Bundle: Pufferfish 51 B —
FillDefaultBundle以及十二槽位31盖写 /ScalarHalt默认值