Skip to content

AutoProto / AutoOr 解析

本页所有地址均适用于 libtpu-0.0.40-cp314 wheel 中的 libtpu.so(构建 libtpu_lts_20260413_b_RC00,build-id md5 89edbbe81c5b328a958fe628a9f2207d,781,691,048 字节,ELF x86-64 DYN,未 strip;反混淆后的 C++ 符号按原文引用)。其他版本会有所不同。

摘要

具有 AUTO / ENABLED / DISABLED 语义的 TPU 编译开关,在 TpuCompilationEnvironment (TCE) 中并不是以普通 boolint 存储的。它存储为指向 xla::jellyfish::AutoProto 的指针,这是一个单 oneof 消息:其活跃分支携带显式值,或者当 oneof_case_ == 0 时表示未设置 (AUTO)。从该 proto 到具体编译决策的桥梁是 AutoOr<T> 模板:AutoOr<T>::FromProtoOrDie 读取 oneof,将结果打包成一个present-bit / value 代码,然后每个开关手写的访问器把该代码折叠为编译器实际使用的值。本页负责说明这一解析模型:AutoOr<T> 包装器、它的 present-bit 打包方式、每个开关的 AUTO→默认极性,以及分派它的 ObjectView<TCE> 访问器区段。

参考框架是一个三态选项(带有文档化 fallback 的 std::optional<bool>),但有两个 libtpu 特有的细节,重新实现者必须精确复现。第一,present-bit 被打包进与值相同的机器字,位置取决于类型类别:bool 为 bit 8,int32/enum 为 bit 32,int64 使用成对的 dl has-byte,string/message 使用单独的 has-flag。消费者从不测试 optional::has_value();它测试打包返回值中固定位置的一个 bit。第二,也就是没有 XLA-CPU/GPU 对应物的部分,AUTO→具体 fallback 不是字段的属性。它是消费者的属性:同一个全 AUTO 默认实例 (AutoProto_globals_) 供给每个未设置的开关,而两种不同的消费者惯用法(AUTO=offAUTO=on)会把同一个 0x000 打包代码读取为相反的布尔值。每个访问器中固化的 bit 极性就是文档化默认值。

本页结构如下:AutoProto 的 wire/内存布局;AutoOr<T>::FromProtoOrDie 解析器模板及其按类型类别的打包方式;每个开关的 AUTO→具体 fallback 惯用法(两种 bool 极性、int64 sentinel 表、enum-0 规则、message 默认实例规则);托管全部 130 个解析器的 ObjectView<TCE> 访问器区段;以及第二种 inline-TristateProto 存储类,它共享三态语义,但不使用 AutoProto 机制。字符串解析入口(auto/enabled/disabledAutoProto)见 autoor-parse-grammar.md;反向文本见 autoor-unparse.md;12 个 message 分支的子默认值见 autoproto-message-arms.md

对重新实现而言,契约是:

  • AutoProto 布局 — oneof body 在 +0x10,判别器 oneof_case_+0x1coneof_case_ == 0 ⇒ AUTO;全零默认实例 AutoProto_globals_ 是任何 null TCE 字段的 fallback。
  • AutoOr<T> 打包返回值 — 每个类型类别的 present-bit 位置,以及 AUTO 会返回 present-bit 清除的全零代码 (0x000)。
  • 每个开关的极性 — 决定 AUTO 解析为何值的是消费者,而不是字段;包括 45/26 bool 划分、18 项 int64 sentinel 集合,以及 enum-0 / message-default 规则。
解析器模板AutoOr<bool>::FromProtoOrDie @ 0xf795300if (oneof_case_==0) return 0; else return val | 0x100
分支读取器AutoOrTypeTraits<bool>::FromAutoProto @ 0xf7953e0 — 检查 +0x1c==1,读取 body +0x10
AutoProto 布局oneof body +0x10 (8 B),oneof_case_ +0x1c (u32);0=AUTO。Oneof 名称 "value"(str @ 0x867f0e9
默认实例AutoProto_globals_ @ 0x223c8968 — body +0x10 = 0,case +0x1c = 0 ⇒ 全 AUTO
解析表 / 全局量AutoProto::_table_ @ 0x21cfa788 · AutoProto_globals_ @ 0x223c8968
解析器访问器区段0x1d6b6420 .. 0x1d6b9f60 — 130 个 ObjectView<TpuCompilationEnvironment> 单字段访问器
类型类别打包bool (present<<8)|val8 · int32/enum (present<<32)|val32 · int64 {rax=val, dl=has} · string/msg {val, has-byte}
极性统计45 个 AUTO=off bool · 26 个 AUTO=on bool · 18 个 int64 sentinel · 11 个 enum/int bt-32 · 2 个 composite · + msg/enum 分支
第二存储类67 个 inline TristateProto.Value 枚举 — cmpl $2,+OFF (ENABLED==2),不是 AutoProto
置信度CONFIRMED(字节锚定对照反编译),除非某行或标注另有说明

1. AutoProto 消息

目的

AutoProto 是一个三态开关的存储单元。它是一个 protobuf 消息,恰好带有一个 oneof(命名为 "value"),其 30 个分支覆盖 TCE 开关可携带的每种值类型:8 种标量类型、10 个枚举和 12 个子消息。活跃分支持有显式用户值;非活跃 oneof (oneof_case_ == 0) 表示该开关保留为 AUTO。TCE 以 AutoProto* 指针字段持有这些值,每个三态开关一个(1121 个 TCE 字段中约 330 个)。解析器读取下面的布局;30 分支分派和子消息分支由 autoproto-message-arms.md 负责。

内存布局

每个 AutoOrTypeTraits<T>::FromAutoProto 读取器和每个消费者访问器都读取相同两个槽位,因此布局固定且精确到字节:

text
AutoProto object
  +0x00   protobuf message header (vtable / arena / unknown-fields)
  +0x10   oneof body   (8 bytes)  ── scalar value, or sub-message pointer
  +0x1c   oneof_case_  (uint32)   ── active arm's AutoProto FIELD NUMBER; 0 = unset = AUTO
```text

`+0x1c` 处的判别器是活跃分支的*字段号*,而不是从 0 开始的索引:bool 是分支 #1,int64 #2,uint64 #3,int32 #4,uint32 #5,double #6,float #7,string #8,然后是更高编号的 enum 和 message 分支(见 [autoproto-message-arms.md](autoproto-message-arms.md))。`+0x10` 处的 body 覆盖所有分支:`bool` 在那里读取一个字节,`int64` 读取八个字节,`double` 通过 `vmovsd` 读取,子消息读取一个指针。读取器根据 `oneof_case_` 判断如何解释这八个字节。

> **注意 —** `+0x1c` 偏移是从对象基址开始的 `4*7` 个 word,在反编译中可见为 `*((_DWORD *)a1 + 7)`(bool 解析器)和 `*(_DWORD *)(a2 + 28)`(bool 读取器)。不要把它与 proto 的 `_has_bits_` 混淆;oneof 没有 has-bits,case 字段*就是*存在性指示器。

### 全 AUTO 默认实例

```text
AutoProto_globals_   @ 0x223c8968   (.data file off 0x21fc8968)
  +0x10  oneof body  = 0x0
  +0x1c  oneof_case_ = 0            ⇒ AUTO

这是每个未设置开关指向的单一默认实例。当某个 TCE AutoProto* 字段为 null(env 从未设置它)时,消费者在调用解析器前会替换为 &AutoProto_globals_,每个访问器中均确认为 if (!v1) v1 = &AutoProto_globals_;。因为它的 oneof_case_0,解析器返回全零打包代码 (0x000),而消费者的极性决定具体默认值。因此,三态开关的默认值不是一个存储的数字,而是消费者中的一条解析规则(§3)。


2. AutoOr<T> 解析器模板

目的

AutoOr<T>::FromProtoOrDie(const AutoProto&) 是把 AutoProto 转换为打包 (present, value) 代码的函数。它以 C++ 值类型为模板参数;二进制中按类型类别携带不同实例化,每个实例化骨架相同,但打包方式依类型而异。OrDie 后缀对实际路径来说名不副实,因为 AUTO guard 会在 fatal 路径可达之前返回。

入口点

text
<accessor>(ObjectView<TpuCompilationEnvironment>)   ── 0x1d6b6420..0x1d6b9f60
  ├─ load env[+OFF]                                  ── the AutoProto* for this knob
  ├─ if null → &AutoProto_globals_                   ── 0x223c8968 (all-AUTO)
  ├─ AutoOr<T>::FromProtoOrDie(autoproto)            ── 0xf795300 (bool) / 0x1092f7e0 (int64) / …
  │     └─ AutoOrTypeTraits<T>::FromAutoProto        ── 0xf7953e0 (bool); checks +0x1c, reads +0x10
  └─ apply consumer polarity                         ── bit test on the packed return (§3)
```text

### 算法

bool 解析器 `@ 0xf795300` 是规范函数体;其他类型类别只在最终打包上不同:

```c
function AutoOr<bool>::FromProtoOrDie(AutoProto* p):     // 0xf795300
    if p->oneof_case_ == 0:                              // *((_DWORD*)p + 7)  == +0x1c
        return 0                                         // AUTO ⇒ packed 0x000, present-bit clear
    sor = AutoOrTypeTraits<bool>::FromAutoProto(p)       // 0xf7953e0 → StatusOr<bool>
    if not sor.ok():                                     // unreachable: case!=0 guarantees the arm is set
        LOG(FATAL) << "Failed to convert AutoProto into an AutoOr: "  // flag_types.h:845
                   << sor.status() << "\nProto: " << AutoProtoToStr(p)
    val8 = sor.value                                     // the byte read at p+0x10 by the traits reader
    return val8 | 0x100                                  // SET present-bit (bit8); pack (present<<8)|val8

分支读取器确认了布局和存在性语义:

c
function AutoOrTypeTraits<bool>::FromAutoProto(out, AutoProto* p):   // 0xf7953e0
    if p->oneof_case_ != 1:                              // *(_DWORD*)(p+28) != 1  — bool is arm #1
        out = MakeError("bool is not set in AutoProto: " + AutoProtoToStr(p))   // flag_types.h:447
        return                                           // StatusOr not-ok
    out.value  = *(byte*)(p + 0x10)                      // body byte
    out.ok     = 1                                       // StatusOr ok-slot
```text

> **怪异点 —** `FromProtoOrDie` 会在调用读取器*之前*先以 `oneof_case_ == 0` 做 guard,而读取器只有在 case 是某个*其他*分支编号(类型不匹配,例如由 bool 读取器读取 int64 分支)时才会 fatal。因此,对于类型正确的开关,`LOG(FATAL)` 路径是死路径:未设置的 oneof 返回 `0x000`,类型正确的已设置 oneof 返回 `val | 0x100`。重新实现者可以省略 fatal 分支并保持行为,但必须精确复现这个*双 bit 代码*:present 在 bit 8,value 在 bit 0,因为消费者按位置测试它。

### 按类型类别的打包返回表示

present-bit 对每种类型类别处于不同位置,因为值占用不同宽度,且打包不得冲突:

| 类型类别 | 解析器 | 打包返回值 | Present-bit | 已验证 |
|---|---|---|---|---|
| `bool` | `AutoOr<bool>::FromProtoOrDie @ 0xf795300` | `(present<<8) \| val8` | bit 8 (`\| 0x100`) | CONFIRMED — `return v11 \| 0x100u` |
| `int32` / enum (`_Value`) | `AutoOr<int>::FromProtoOrDie @ 0x10979760` · `AutoOr<EffortLevel>::FromProtoOrDie @ 0x109294a0` | `(present<<32) \| val32` | bit 32 (`\| 0x100000000`) | CONFIRMED — `return v11 \| 0x100000000LL` |
| `int64` | `AutoOr<long>::FromProtoOrDie @ 0x1092f7e0` | `{rax = value, dl = has}` | 成对的 `dl` 字节 (`test $1,%dl`) | CONFIRMED — 返回 `v10[1]`,has-bit 在 `dl` |
| `uint32` / `uint64` / `double` / `float` | 类似的实例化 | value 在低位,present 在该宽度的最高位 / 成对 has | 按类型 | HIGH(惯用法匹配 bool/int|
| `string` / message | message traits(§ message arms) | `{value-or-submessage, separate has-byte}` | 单独 has-byte | HIGH(struct-return,has 在 `+0x58`) |

enum 案例已通过 `AutoOr<ExecutionOptions_EffortLevel>::FromProtoOrDie @ 0x109294a0` 验证,其函数体除最终 `return v11 | 0x100000000LL` 外与 bool 解析器逐字节相同:因为 enum 值占用低 32 位,present-bit 移到了 bit 32。int64 案例 `@ 0x1092f7e0` 返回 `v10[1]`(值寄存器),并在 `dl` 中携带 has-bit,这是经典的双寄存器 `StatusOr` 风格返回,因此其消费者测试 `dl & 1`,而不是值字中的某个 bit。

> **陷阱 —** 不存在单一的 `AutoOr<T>` ABI。若重新实现为每种类型都返回统一的 `{bool present; int64 value}` struct,将与消费者不匹配,因为消费者是按*打包*返回值编译的,并测试固定 bit(`0x100`、`0x100000000` 或 `dl & 1`)。present-bit 位置是契约的一部分,不是实现细节。

---

## 3. `AUTO` → 具体 fallback

### 目的

当 oneof 未设置时,`FromProtoOrDie` 返回全零打包代码。消费者访问器把该代码转换为具体编译值,且*消费者硬编码 `AUTO` 变成什么*。不存在字段级默认表;默认值是每个访问器末尾的一段指令序列。五种惯用法覆盖整个统计集合。

### 惯用法 A — `AUTO=off` bool45 个开关)

只有显式 `true` 会启用;`AUTO` 和显式 `false` 都解析为 `false`。

```c
function MxuLatencyBalancingUseSequenceDependencies(env):   // 0x1d6b9c80
    p = env[+0xbe8]                                          // the AutoProto*
    if !p: p = &AutoProto_globals_                           // 0x223c8968
    code = AutoOr<bool>::FromProtoOrDie(p)                   // 0x000 if AUTO, val|0x100 if set
    return (~code & 0x101) == 0                              // true IFF present(bit8) AND value(bit0)

(~code & 0x101) == 0 仅当 bit 8(present)和 bit 0(value)都置位时为 true,也就是打包代码恰为 0x101AUTO (0x000) 和 present-false (0x100) 都得到 false。因此 MxuLatencyBalancingUseSequenceDependencies 在 v0.0.40 中默认 OFF:全 AUTO 的 AutoProto_globals_ 解析为 0x000,无法通过 == 0x101 测试,返回 false。45 个 AUTO=off 开关集合(偏移见 tce-field-offsets-defaults.md)都共享这个 not; test $0x101; sete 函数体,其中包括 EnablePipelinedLoopUnrolling (+0x2f0)、EnableIlpLatencyHidingScheduler (+0x648)、ForceAsyncAllToAll (+0xbc8)、EnableDataDependentScOpAggregation (+0xc40)。

惯用法 B — AUTO=on bool(26 个开关)

只有显式 false 会禁用;AUTO 和显式 true 都解析为 true

c
function AllowSplitVmem(env):                               // 0x1d6b70a0
    p = env[+0x4a8]
    if !p: p = &AutoProto_globals_
    code = AutoOr<bool>::FromProtoOrDie(p)
    return (code & 0x101) != 0x100                          // false ONLY when present AND value==0
```text

`(code & 0x101) != 0x100` 仅对精确代码 `0x100`(present,value 0)为 false。`AUTO` (`0x000`) 和 present-true (`0x101`) 都得到 `true`。因此 **`AllowSplitVmem` 默认 ON**,并且它背后使用的是与上面 OFF 默认开关相同的全 AUTO `AutoProto_globals_`。26 个 `AUTO=on` 开关集合共享这个 `and $0x101; cmp $0x100; setne` 函数体,包括 `EnableMsaSyncCopyReplacement` (`+0x2f8`)、`EnableCollectivePipeliner` (`+0x8a8`)、`EnableScsOverlays` (`+0xc50`)、`IsMosaicCompatibilityModeEnabled` (`+0x470`)。

> **怪异点 —** 同一个打包代码 `0x000` 在惯用法 A 和惯用法 B 中解析为相反的布尔值。极性不在字段、proto 或默认实例中,而是访问器末尾的字面算术。重新实现者无法从存储推导开关默认值;必须读取消费者的测试。这是本页最重要的事实:**bit 极性就是文档化默认值。**

### 惯用法 C — `AUTO` → int64 sentinel(18 个开关)

int64 解析器在 `rax` 中返回值,在 `dl` 中返回 has-bit。消费者在 has-bit 清除时替换为每个开关自己的常量:

```c
function DcnTransferCountThreshold(env):                    // 0x1d6b64e0
    p = env[+0xbd0]
    if !p: p = &AutoProto_globals_
    value = AutoOr<long>::FromProtoOrDie(p)                 // value in rax, has-bit in dl
    if (has & 1) == 0:                                      // AUTO ⇒ has clear
        return 0x7FFFFFFFFFFFFFFF                           // INT64_MAX sentinel
    return value

AUTO sentinel 随开关而变,它就是该访问器用 cmove 代入的常量。已解码 12 个;其余 6 个遵循相同的 test $1,%dl; cmove rcx 惯用法,但各自有自己的常量:

开关Env 偏移AUTO sentinel
DcnTransferCountThreshold+0xbd0INT64_MAX (0x7fffffffffffffff)
IciRsPipeliningThresholdBytes+0xa98INT64_MAX
AllGatherMinBytesForSparseCoreOffload+0xaf00
AllGatherStepCount+0x8a01
GatherExpanderConcatElementGatherThreshold+0x6004
RaggedAllToAllMaxRdmaSizeKib+0x6588
SparseCoreOffloadQueuingOverlapLimit+0x73864
RotatedPincerVmemShardCopyLoopIterNum+0xbd864
MaxNumOperandsToEnableWindowCheck+0xb60128
HostCommandHandlerReapInterval+0xba01024
AutoMaxMetadataStringLength+0x688100000
MaxFetchAndAddValue+0x8c81000000000

惯用法 D — AUTO → enum-0 / int-default(11 个开关)

int32/enum 解析器打包 (present<<32)|val32。消费者测试 bit 32,并在 AUTO 时替换为 0(DEFAULT/第一个 enum 值,或零):

c
function GetBufferAssignmentAlgorithm(env):                // 0x1d6b9cc0 (pattern)
    p = env[+0xc18]
    if !p: p = &AutoProto_globals_
    code = AutoOr<EnumT_Value>::FromProtoOrDie(p)          // (present<<32)|val32
    if bt(code, 32):                                       // present?
        return (int32)code                                 // the explicit enum/int value
    return 0                                                // AUTO ⇒ enum-0 / zero
```text

`bt $0x20; cmovb; else 0` 函数体覆盖 `GetMlirVerifierOptions` (`+0x978`)、`ScHbmSpillStack` (`+0xc68`, int32)、`TpuScatterExpanderAutounrollFactor` (`+0x800`, int32)、`NumSerializedTablesToOptimizeHbm` (`+0x558`, uint32)、float 类型的 `SparseCoreMismatchDetectorAtol`/`Rtol` (`+0x340`/`+0x348`),以及 `SparseCoreElementwiseShapeScalingFactor` (`+0xb48`, float)。对 enum 案例而言,`0` 是 proto 的第一个/默认 enum 值;对 int 案例而言,是字面零。

### 惯用法 E — `AUTO` → message 默认实例

message 类型的 `AutoProto` 分支(12 个子消息分支)会把 `AUTO` 解析为*空的默认子消息*,而不是标量。`GetIlpLatencyHidingSchedulerOptions` 通过 `FromProtoOrDie @ 0x1d6bb6e0` 把 `AUTO` 解析为 `IlpLatencyHidingSchedulerOptions(arena)`(空消息);`GetSparseCoreAssertLevel` 通过 `FromProtoOrDie @ 0x1d6bcb20` 把 `AUTO` 解析为代码定义的 level。子消息的*内部*字段默认值由 [autoproto-message-arms.md](autoproto-message-arms.md) 负责;这里的 AUTO 答案仅仅是“该分支消息类型的一个空实例”。

### 惯用法 F — primary/override composite(已解码 2 个)

少数访问器读取*两个* `AutoProto` 字段,第二个字段在显式 present 时覆盖第一个字段:

```c
function ShouldEnablePostMsaSyncSliceFusion(env):          // composite
    base     = resolve(env[+0x548], AUTO=off)              // primary knob, Idiom A
    override = AutoOr<bool>::FromProtoOrDie(env[+0x448])
    if (override & 0x100) == 0:                            // override not present
        return base
    return override & 1                                    // explicit override wins

PadOperationsInputTiles (+0x618) 是第二个已解码 composite,遵循相同的 present-bit gate。其余 composite(EnableMixedPrecisionAddTransform 读取 +0x830&+0x840AllReduceMinBytesForSparseCoreOffload 读取 +0x1590&+0xa48)遵循该模式,但其第二字段语义尚未逐一解码 (LOW)。


4. 解析器访问器区段

目的

全部 130 个单字段三态解析器位于一个 .text 区段 0x1d6b6420 .. 0x1d6b9f60,每个都是自由函数 xla::jellyfish::<Name>(ObjectView<TpuCompilationEnvironment>)。它们结构一致:在固定 env 偏移处加载字段的 AutoProto*,以 AutoProto_globals_ 作为 null fallback,调用有类型的 FromProtoOrDie,再应用 §3 中的一种惯用法。该区段是可读的编译开关表面,也就是进入原本按偏移索引的 TCE 的人类命名入口。

分派维度

该区段是一个 130 行空间,但可由三条轴完整描述,因此这里无需倾倒 130 行(偏移和 flag 名称见 tce-field-offsets-defaults.md):

取值来源
类型类别bool, int64, int32/enum, float, message被调用的 AutoOr<T> 实例化
AUTO 极性off / on / sentinel / enum-0 / msg-default / composite访问器尾部的 §3 惯用法
Env 偏移每个开关一个,+0x270 .. +0xcd0AutoProto* 字段)_table_ 字段号→偏移映射

该区段统计:45 个 AUTO=off bool、26 个 AUTO=on bool、18 个 int64 sentinel、11 个 enum/int bt-32、2 个 primary/override composite,外加 enum-instance 和 message-default 分支。少数多字段 composite 读取 2 个以上 AutoProto 字段,并单独计数。

函数映射

函数地址角色
AutoOr<bool>::FromProtoOrDie0xf795300bool 解析器 — (present<<8)|val8 打包
AutoOrTypeTraits<bool>::FromAutoProto0xf7953e0bool 分支读取器 — +0x1c==1,body +0x10
AutoOr<long>::FromProtoOrDie0x1092f7e0int64 解析器 — {rax, dl} has-pair
AutoOr<int>::FromProtoOrDie0x10979760int32 解析器 — (present<<32)|val32
AutoOr<ExecutionOptions_EffortLevel>::FromProtoOrDie0x109294a0enum 解析器 — | 0x100000000
AutoProto::_table_0x21cfa78830 分支 oneof 的解析表
AutoProto_globals_0x223c8968全 AUTO 默认实例
MxuLatencyBalancingUseSequenceDependencies0x1d6b9c80AUTO=off 示例 (+0xbe8)
AllowSplitVmem0x1d6b70a0AUTO=on 示例 (+0x4a8)
DcnTransferCountThreshold0x1d6b64e0int64 sentinel 示例 (+0xbd0, INT64_MAX)
GetBufferAssignmentAlgorithm0x1d6b9cc0enum bt-32 示例 (+0xc18)
EnableLloLinter0x1d6b6740inline-Tristate 示例 (+0x15ac, §5)

注意 — 不要混淆这两个解析表。AutoProto::_table_ @ 0x21cfa788 是 AutoProto 消息自己的 TcParseTableBase,也是驱动 30 分支 FromAutoProto 反射的 descriptor。TCE 的主 _table_ @ 0x21cfa9e0(1121 个字段号→偏移的 oracle)是附近地址处的另一个表:它们在 .data.rel.ro 中相邻,是因为两个 proto 位于同一翻译单元。应按符号交叉引用,而不是凭地址观察。


5. 第二存储类 — inline TristateProto

目的

并非每个三态开关都是 AutoProto。第二类存储方式有 67 个字段,它把三态存为 inline TristateProto.Value 枚举,也就是 TCE 结构体中的一个直接 4 字节字段,没有 AutoProto 指针,也没有 AutoOr<T> 调用。语义相同(AUTO/ENABLED/DISABLED),但机制是直接枚举比较。重新实现者必须同时处理两类;它们不能互换。

算法

c
function EnableLloLinter(env):                             // 0x1d6b6740
    return env[+0x15ac] == 2                                // ENABLED == 2; AUTO==0, DISABLED==1 → false
```text

没有解析器,没有 fallback 实例,也没有 present-bit。枚举值直接通过 `cmpl $0x2, +OFF(%rdi); sete` 读取。`ENABLED` 是常量 `2`;`AUTO` (`0`) 和 `DISABLED` (`1`) 比较结果都为不相等,因此都解析为 `false`。这里的 `AUTO`→具体值是字段的 *proto enum 默认值*(`TristateProto` 统计分为 21 个 default-`ENABLED`、37 个 default-`AUTO`、9 个 default-`DISABLED`)。

### 两类的区别

| 属性 | 类 A — `AutoProto*` | 类 B — inline `TristateProto` |
|---|---|---|
| 存储 | `AutoProto*` 指针字段 | 4 字节 enum 字段 |
| 字段数量 | ~330130 个命名单字段解析器) | 67 |
| 解析器 | `AutoOr<T>::FromProtoOrDie` + 极性 | 直接 `cmpl $2,+OFF; sete` |
| Present 模型 | 打包 present-bit(bit 8 / 32 / `dl`) | enum 值 (`ENABLED==2`) |
| `AUTO` 默认值 | 消费者极性 (§3) | proto enum 默认值 |
| Null fallback | `&AutoProto_globals_` | n/a(值为 inline|

> **陷阱 —** 开关名称(`Enable…`/`Should…`)无法告诉你它的类别。`EnableLloLinter` 是 inline `TristateProto` (`cmpl $2`),而 `EnablePipelinedLoopUnrolling` 是 `AutoProto`(`AUTO=off` bool)。枚举三态开关时,重新实现者必须按访问器函数体分类:pointer-load-and-resolve(类 A)对比 inline-compare(类 B),而不是按名称或其听起来像三态的类型分类。

---

## 相关组件

| 组件 | 关系 |
|---|---|
| `AutoOr<bool>::FromProtoOrDie @ 0xf795300` | 解析器模板 — present-bit 打包 |
| `AutoProto_globals_ @ 0x223c8968` | 每个未设置开关 fallback 到的全 AUTO 默认实例 |
| `AutoProto::_table_ @ 0x21cfa788` | 驱动 `FromAutoProto` 的 30 分支 oneof 解析表 |
| `ObjectView<TCE>` band `0x1d6b6420..0x1d6b9f60` | 130 个命名单字段解析器及其极性尾部 |
| `TpuCompilationEnvironment` (TCE) | 托管 `AutoProto*` 字段和 inline `TristateProto` 字段 |

## 交叉引用

- [overview.md](overview.md) — 三层配置流水线;本页负责 Stage 3,即 AUTO 解析器
- [tpu-compilation-environment.md](tpu-compilation-environment.md) — 托管 `AutoProto*` 与 inline-`Tristate` 字段的 TCE proto,以及字段号→偏移 oracle
- [tce-field-offsets-defaults.md](tce-field-offsets-defaults.md) — 字节精确的字段号→偏移→默认值映射;此处每个解析器引用的 env 偏移
- [autoproto-message-arms.md](autoproto-message-arms.md) — 30 分支 oneof 和 12 个 message 分支的子默认值(惯用法 E)
- [autoor-parse-grammar.md](autoor-parse-grammar.md) — 字符串→`AutoProto` 入口(`auto`/`enabled`/`disabled`/literal)
- [autoor-unparse.md](autoor-unparse.md) — 反向 `AbslUnparseFlag<AutoOr<T>>` 文本方向