Skip to content

SC 后端流水线

地址、符号和 pass 顺序适用于 libtpu-0.0.40-cp314 wheel 中的 libtpu.so(build-id 89edbbe81c5b328a958fe628a9f2207d);该二进制随完整 C++ 符号发布(未 strip)。其他版本会不同。

摘要

当 XLA 降低 SparseCore offload 计算时,稠密的 tpu 方言 IR 会先经过一条固定的后端 pass 流水线,然后才变成可编码的 SC bundle。该流水线由 CustomKernelEmitter::RunPasses0x13202780)构建并驱动。本页把这条流水线记录为一份契约十二个 pass 的精确有序列表、每个 pass 的 MLIR factory 入口点和命名空间、每个 pass 的挂接方式(顶层 addPass 还是 func 嵌套 nest)、倒数第二个运行的 device-id remap pass,以及 MEGACORE barrier —— 当部件是双核 SparseCore megachip 时,流水线最后的 lowering pass 会发出的偶/奇核心对跨核同步。

最重要的结构事实是,RunPasses 不是构建一个持有十二个 pass 的 PassManager。它会按顺序构建并运行十二个独立的单 pass PassManager,每个都只携带一个 pass,每个都有自己的 IR 打印 gating closure,并且每个都通过 jellyfish::RunPass 独立驱动。这对重新实现很重要:十二个阶段之间没有共享的 pass-manager analysis cache,IR dump 按阶段 gate,顺序硬编码在调用序列中,而不是从 registry 组装出来。LLVM 读者可以宽松类比:这相当于在同一个 ModuleOp 上连续运行十二次 mlir::PassManager::run 的手写版本,而不是一条填充好的单一流水线。

第二个结构事实是,MEGACORE barrier 不是一种 barrier kindEmitScsBarrier(从最后一个 pass 到达的 SC 侧 barrier dispatcher)只分派 GLOBALCUSTOMMEGACORE enum 值在那里是非法的(会 RetCheck)。megacore 偶/奇 partner sync 是一条内部代码路径,只要 Target::LogicalDevicesPerChip(SparseCore) == 2GLOBALCUSTOM 两种 lowering 都会运行它。"Megacore" 命名的是硬件拓扑(双核 megachip),不是 producer 选择的一种 barrier。

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

  • 十二个单 pass manager,固定顺序。 ConvertIntegerMemrefs → InferMemRefLayout → Canonicalizer → CanonicalizeOperations → CanonicalizeMemorySpace → TilingPropagation → mosaic_sc::InferVectorLayout → mosaic_sc::InsertRelayout → mosaic_sc::ApplyVectorLayout → CSE → LogicalToPhysicalDeviceId → LowerToMlo。顺序是先 vector-layout 再 lower;重排 layout 三件套(7/8/9)或把 LogicalToPhysicalDeviceId 移到 LowerToMlo 之后都会破坏构建。
  • Pass 7/8/9 是 mlir::mosaic_sc,不是 mlir::tpu SC vector-layout 三件套(InferVectorLayoutInsertRelayoutApplyVectorLayout)位于 mosaic_sc 命名空间。Pass 3 是通用mlir::createCanonicalizerPass;pass 4/5 是 tpu 专用 canonicalizer。
  • device-id remap 必须紧挨着在 LowerToMlo 之前运行。 LogicalToPhysicalDeviceIdPass(pass 11)把 tpu::EnqueueDMAOp / tpu::SemaphoreSignalOpdevice_id 操作数从逻辑 id 重写为物理核心 id(对 SC 为 i32(CoreIndex * stride + TileId))。它必须在 barrier-lowering pass 之前运行,这样 LowerToMlo 发出的 sync op 才会指向正确的物理核心。
  • MEGACORE 是拓扑 gate,不是 barrier 类型。 偶/奇 partner sync(partner = local core id XOR 1)在 GLOBALCUSTOM 两个 barrier 分支内部都由 LogicalDevicesPerChip(SC) == 2 gate。单核部件(LDPC(SC) == 1)会抑制 partner 路径(它会 RetCheck),只保留本地 sync。
流水线构建器xla::tpu::sparse_core::CustomKernelEmitter::RunPasses @ 0x13202780
逐 pass 驱动器jellyfish::RunPass @ 0x14514d60; mlir::PassManager ctor @ 0x1cb700a0; 通过 OpPassManager::addPass @ 0x1cb6c000 / ::nest @ 0x1cb6d3e0 挂接
Pass 数量 / 形状12 个 pass,每个都在自己的单 pass PassManager 中(不是一条 12-pass 流水线)
最后一个 passcreateLowerToMloPass @ 0x1322adc0 — SC → MLO lowering;collective op → EmitScsBarrier
Device-id remappass 11 createLogicalToPhysicalDeviceIdPass @ 0x132d5720; body runOnOperation @ 0x132d5ec0; GetPhysicalCoreID @ 0x132d8de0
SC barrier 分派CollectiveEmitterBase::EmitScsBarrier @ 0x13352500 — 仅 GLOBAL(1)/CUSTOM(3)
Megacore gateTarget::LogicalDevicesPerChip(SparseCore) == 2; partner = OffloadFactory::ToPartnerGlobalCoreId @ 0x133e66e0core XOR 1

十二 Pass 流水线

RunPasses(ModuleOp module, bool, bool, BarrierConfig const* bc) 保存 BarrierConfig*(它会被传入最后一个 pass),然后按顺序运行十二个 pass。每个 pass 都遵循相同的四步惯用法:

  1. 用名称和 Nesting 构造一个新的 mlir::PassManager(ctor 0x1cb700a0);
  2. 安装 IR 打印的 "should-print" closure(逐阶段 VLOG/dump gate);
  3. 通过 OpPassManager::addPass(顶层,作用于 ModuleOp OpPassManager::nest<func::FuncOp>(...).addPass(func 嵌套,逐函数作用)挂接唯一的 pass;
  4. 通过 jellyfish::RunPass(pm, module, ...) 运行它。

在 pass 之间,RunPasses 会读取 HLO BackendConfigSparseCoreConfig 默认值以及逐元素 layout flag(ShouldEnableLarge2ndMinorLayoutForX16/X8/X4)来填充 pass 选项 —— 最明显的是传给 InferMemRefLayout 的 tiling span,以及 InferVectorLayoutPassOptions / ApplyVectorLayoutPassOptions

text
tpu-dialect SparseCore module (post region→sequencer outlining)

   ▼  RunPasses @0x13202780  — 十二个单 pass PassManager,按顺序:

   1  createConvertIntegerMemrefsPass        addPass   int-memref 合法化
   2  createInferMemRefLayoutPass            nest      tile/layout 推断(X16/X8/X4 flag)(逐 func)
   3  createCanonicalizerPass                addPass   通用贪婪 canonicalization
   4  createCanonicalizeOperationsPass       nest      tpu op canonicalization       (逐 func)
   5  createCanonicalizeMemorySpacePass      nest      memory-space canonicalization (逐 func)
   6  createTilingPropagationPass            nest      传播 {N,2} tiling              (逐 func)
   7  mosaic_sc::createInferVectorLayoutPass nest      SC vector layout 推断          (逐 func)
   8  mosaic_sc::createInsertRelayoutPass    nest      插入 layout-conversion op      (逐 func)
   9  mosaic_sc::createApplyVectorLayoutPass nest      应用选定的 vector layout       (逐 func)
   10 createCSEPass                          addPass   common-subexpression elim.
   11 createLogicalToPhysicalDeviceIdPass    nest      device_id → 物理核心 id        (逐 func)  ── §Device-Id Remap
   12 createLowerToMloPass                   addPass   SC → MLO lowering(最后)                    ── reaches EmitScsBarrier


MLO IR  ─→  SC bundle emission (per-engine SCS/TAC/TEC codecs)
```text

### 逐 pass 表

这十二个 `create*Pass` 调用严格按此顺序出现;pass 7/8/9 带有 `mosaic_sc` 限定;`addPass`/`nest` 的划分与调用点一一对应。

| # | Factory (VMA) | 命名空间 | 挂接 | `mlir::Pass` 子类 / 作用 |
|---|---|---|---|---|
| 1 | `createConvertIntegerMemrefsPass` @ `0x132bca60` | `mlir::tpu` | `addPass` | `ConvertIntegerMemrefsPass` — integer-memref 合法化 |
| 2 | `createInferMemRefLayoutPass` @ `0x132c0f00` | `mlir::tpu` | `nest` | `InferMemRefLayoutPass` — tile/layout 推断;opts = `(int, Span<long const> tiling, TpuTilingFlags)`,由 X16/X8/X4 layout flag 构建 |
| 3 | `createCanonicalizerPass` @ `0x1c941920` | `mlir`(通用) | `addPass` | `Canonicalizer` — 通用贪婪 canonicalization |
| 4 | `createCanonicalizeOperationsPass` @ `0x132bb260` | `mlir::tpu` | `nest` | `CanonicalizeOperationsPass` — `tpu` op canonicalization |
| 5 | `createCanonicalizeMemorySpacePass` @ `0x132a2280` | `mlir::tpu` | `nest` | `CanonicalizeMemorySpacePass` — memory-space canonicalization |
| 6 | `createTilingPropagationPass` @ `0x132e0900` | `mlir::tpu` | `nest` | `TilingPropagationPass` — 传播 `{N,2}` tiling;opts = `(array<long,2>, bool)` |
| 7 | `createInferVectorLayoutPass` @ `0x132ecf60` | `mlir::mosaic_sc` | `nest` | `InferVectorLayoutPass` — SC vector-layout 推断;opts = `InferVectorLayoutPassOptions` |
| 8 | `createInsertRelayoutPass` @ `0x132eff80` | `mlir::mosaic_sc` | `nest` | `InsertRelayoutPass` — 插入 layout-conversion op |
| 9 | `createApplyVectorLayoutPass` @ `0x132e57e0` | `mlir::mosaic_sc` | `nest` | `ApplyVectorLayoutPass` — 应用选定 layout;opts = `ApplyVectorLayoutPassOptions` |
| 10 | `createCSEPass` @ `0x1c93e180` | `mlir`(通用) | `addPass` | `CSE` — common-subexpression elimination |
| 11 | `createLogicalToPhysicalDeviceIdPass` @ `0x132d5720` | `mlir::tpu` | `nest` | `LogicalToPhysicalDeviceIdPass` — remap DMA/semaphore `device_id` → 物理核心 id(见 [§Device-Id Remap](#device-id-remap-pass-11)) |
| 12 | `createLowerToMloPass` @ `0x1322adc0`(**最后**) | `mlir::tpu` | `addPass` | `LowerToMloPass` — SC → MLO lowering;collective op lower 到 `EmitScsBarrier` |

### 逐 pass 构造惯用法

十二个阶段中的每一个都用同一套固定调用序列构建 —— `RunPasses` 的主体实际上是此模板的十二份拷贝,只在 factory 和挂接模式上不同:

```text
// for each pass p in the twelve:
pm = mlir::PassManager(ctx, name, Nesting)        // 0x1cb700a0 — a fresh single-pass manager
pm.enableIRPrinting( $_0 should-print closure )   // 0x132048e0 — the per-stage IR-dump gate
op = pm.<addPass | nest<func::FuncOp>().addPass>( create<P>Pass(opts) )   // 0x1cb6c000 / 0x1cb6d3e0
jellyfish::RunPass(pm, module, dump_prefix, ...)  // 0x14514d60 — run this one pass over the module
// pm destructed before the next stage

十二个 pass 中有三个携带非平凡的 options struct,RunPasses 会在 pass 之间读取周边配置来物化这些选项:

  • Pass 2(InferMemRefLayoutSpan<long const> tilingTpuTilingFlagsTarget::ShouldEnableLarge2ndMinorLayoutForX16 / X8 / X40x1d6b6920 / 0x1d6b6860 / 0x1d6b6840)构建;layout flag 随代际和元素宽度而不同,因此这个 option block 是流水线中按代际变化的接缝。
  • Pass 7 和 9InferVectorLayoutPassOptions / ApplyVectorLayoutPassOptionsSparseCoreConfig 默认值(SparseCoreConfig_globals_ @ 0x223a99c8)和 HLO BackendConfig0xf58e6c0)填充。
  • Pass 11(LogicalToPhysicalDeviceId — 它的 optional<DeviceAssignment> 参数来自 HloModuleConfig::static_device_assignment()0x10fb7f60);ChipTopology 和尾部的 bool 来自 emitter 的 target。见 §Device-Id Remap

NOTE — 十二个 manager,而不是一个。 RunPasses 为每个 pass 构造一个新的 mlir::PassManager,并在下一个阶段前销毁它。没有携带的 analysis state,也没有 fused nesting:每个通过 nest 挂接的 pass 都包装在自己的 manager 中,其顶层是 ModuleOp,唯一的嵌套 pass 会在每个 func::FuncOp 上运行。构建一个 PassManageraddPass 所有十二个 pass 的重新实现,在正确性上行为等价,但不会复现二进制发出的逐阶段 IR-dump gate 或逐阶段 RunPass 计时,并且会折叠二进制刻意丢弃的 analysis cache。

GOTCHA — layout 三件套顺序对加载顺序敏感。 InferVectorLayout(7)标注选定的 vector layout,InsertRelayout(8)在相邻 op layout 不一致处物化 conversion op,ApplyVectorLayout(9)把 op 重写为选定 layout。在 InsertRelayout 之前运行 ApplyVectorLayout 会留下没有 conversion op 桥接的 layout mismatch;在 InferVectorLayout 之前运行任一 pass 都会针对未设置的 layout 重写。三者是严格的三阶段序列,全都是 mosaic_sc,全都是 func 嵌套。


Device-Id Remap(Pass 11) {#device-id-remap-pass-11}

Pass 11,LogicalToPhysicalDeviceIdPass,是流水线能够发出命中正确硬件的跨核 barrier 的原因。它紧挨着在最后的 LowerToMlo lowering 之前运行,把 DMA/semaphore op 上的 device_id 操作数从逻辑设备索引重写为物理 SparseCore 核心 id。Pass 名称字符串从 .rodata 读取:kPassName = "LogicalToPhysicalDeviceIdPass"kArgumentName = "logical-to-physical-device-id"

构造

Factory(0x132d5720,签名 (optional<DeviceAssignment>, ChipTopology, bool))在堆上分配 pass,memcpy optional<DeviceAssignment>(设置其 present-bit)和 ChipTopology 到 pass 对象中,并将逐 CoreType topology map 清零初始化。在 RunPasses 中,DeviceAssignment 来源是 HloModuleConfig::static_device_assignment()0x10fb7f60),它供给 pass-11 构造。

runOnOperation0x132d5ec0

主体读取 Target::CoresPerChip(TpuCoreType)Target::LogicalDevicesPerChip(TpuCoreType)TpuChipConfig::Megachip(),从复制的 ChipTopology + DeviceAssignment 构建 FlatHashMap<CoreType, CoreTopology>,然后遍历每个 func::FuncOpmlir::detail::walk,主 callback 0x132d71c0)。Callback 匹配携带 (target_core_type, device_id) 操作数对的 op,并重写 device_id

text
for each matched op in func:
    phys = GetPhysicalCoreID(builder, loc, op.getTargetCoreType())   // §below
    op.getDeviceIdMutable().assign(phys)                             // MutableOperandRange::assign
```text

反编译 callback(`0x132d71c0`)确认它处理 `tpu::EnqueueDMAOp` 和 `tpu::SemaphoreSignalOp`(二者都通过 `getTargetCoreType` / `getDeviceIdMutable`),在四处调用 `GetPhysicalCoreID`,并通过 `MutableOperandRange::assign` 提交。该 pass 也可能 `insertArguments` 来传递物理核心索引函数参数。

### `GetPhysicalCoreID`(`0x132d8de0`)

这是逻辑→物理的物化器。对 `CoreType == SparseCore`,它发出如下 MLIR op 链(反编译第 177–183 行,按顺序):

```text
ci   = sparse_core::CoreIndexOp::create(b, loc)            // current SC core index
k    = arith::ConstantIndexOp::create(b, loc, stride)      // per-tile physical stride
mul  = arith::MulIOp::create(b, loc, ci, k)
tid  = sparse_core::TileIdOp::create(b, loc)               // tile id within the core
add  = arith::AddIOp::create(b, loc, mul, tid)
i32  = Builder::getI32Type()
phys = arith::IndexCastOp::create(b, loc, i32, add)        // → physical_core_id : i32
                                                           //   = i32(CoreIndex * stride + TileId)

对非 SC(TensorCore)路径,它直接返回 llo::CoreIndexOp::create(b, loc)stride 通过遍历 ChipTopology core-entry 数组(逐核心 role tag)选择,其字面值取决于 chip-config proto。

NOTE — 为什么它必须先于 LowerToMlo Pass 12 中的 barrier lowering 会把 collective op 转成硬件 sync(SemaphoreSignal / SyncAdd),其目标是 device_id 操作数。如果这些操作数仍保存逻辑 id,发出的 barrier 就会 signal 错误的物理核心。把 remap 作为 pass 11 运行,保证 LowerToMlo 消费时每个 DMA/semaphore op 都携带物理核心 id。


MEGACORE Barrier

最后一个 pass,LowerToMloPass,会 lower SC collective op;对于 barrier,它会到达 CollectiveEmitterBase::EmitScsBarrier0x13352500)。megacore 偶/奇核心对 sync 位于该 emitter 分派的两个 barrier 分支内部 —— 它不是第四个分派 case。

分派:EmitScsBarrier0x13352500

Emitter 读取 HLO BackendConfigBarrierConfig(缺失时默认用 BarrierConfig_globals_),然后在 offset +0x20 处 switch barrier_type(反编译为 *((_DWORD*)cfg + 8)):

barrier_type分派SFLAG-number 来源
1 GLOBALEmitGlobalBarrier @ 0x13352820GetSyncFlagForBarrierId(reserved id)(见 Barrier → SFLAG Binding
3 CUSTOMEmitCustomBarrierFromConfig @ 0x13352cc0EmitCustomBarrierStart @ 0x13352fc0GetSyncFlagForBarrierId(colored id)
0 / 2 / 4(含 MEGACORE=4RetCheckFailSlowPath(source line 0x5fn/a — 在 SC kernel emission 中非法

反编译主体精确确认了这一点:v11 == 1 调用 EmitGlobalBarrierv11 == 3 调用 EmitCustomBarrierFromConfig,而 else 分支用消息 "backend_config.barrier_config().barrier_type() == jellyfish::BarrierType::CUSTOM" 执行 RetCheckFail

GOTCHA — MEGACORE 不是 barrier kind。 BarrierType::MEGACORE(4) 到达 EmitScsBarrier 是硬错误(RetCheck)。该 enum 值是producer 侧 annotation,不是 SC kernel emitter 会消费的东西。实际 megacore 行为是一个由拓扑 gate 的 partner 跨核 sync(ToPartnerGlobalCoreId + partner SyncAddOp),只要 LogicalDevicesPerChip(SC) == 2GLOBALCUSTOM 两个分支都会共享它;显式偶/奇 Predicated/Not leader/partner 谓词化在 EmitGlobalBarrierGLOBAL 分支)中物化,而 CUSTOM start emitter 携带 partner-add 但没有 Predicated 包装。重新实现者不得把 "megacore barrier" 建模为一个独立 lowering 分支。

Megacore 拆分:EmitGlobalBarrier0x13352820

当部件是双核 megachip 时,EmitGlobalBarrier 构建偶/奇 leader/partner predicate,并把 barrier 发成两个互斥的 predicated region。反编译主体按顺序显示了算术:

text
ChipCount();  ldpc = LogicalDevicesPerChip(SC);          // total SC cores = ChipCount * ldpc
// even/odd LSB selector:
Shli(x, 1); And(...);  Compare(eq)  ── is_even predicate (LSB == 0 ⇒ leader)
lowering_util::Assert(...)
core_index    = GetCoreIndex()
chip          = DivU(core_index, CoresPerChip(SC))
gcid          = ToGlobalCoreId(chip, ...)
pred          = Compare(gcid, ...)                       ── leader/partner predicate
Predicated(pred,      $_0)   ── EVEN / LEADER  arm  @0x13355b60
Predicated(Not(pred), $_1)   ── ODD  / PARTNER arm  @0x13355f80
```text

### 两个分支

每个分支都是一个 `__policy_func` thunk,接收 `OpBuilder&` 并返回 `Status`。反编译 op-create 计数(逐分支验证):

| 分支 | `SyncWaitOp` | local `SyncAddOp` | partner `SyncAddOp` | `scf::ForOp` |
|---|:---:|:---:|:---:|:---:|
| `$_0` even / leader(`0x13355b60`) | 1 | 1 | 1(在 `ForOp` 内) | 1 |
| `$_1` odd / partner(`0x13355f80`) | 1 | 1 | 1 | 0 |

每个分支:

- 发出 `sparse_core::SyncWaitOp::create`(`0x14618fa0`),并通过 `setAttr` 用值为 **`259`(= `0x103` = `IciDim::kCoresOnChip`)** 的 `getStringAttr` twine 标记 —— 也就是说,wait 被明确标记为跨核(cores-on-chip)wait。字面量 `259` 直接来自反编译 thunk(`v46 = 259`);
- 发出简单的本地 `sparse_core::SyncAddOp::create`(`0x14611f40`)—— 本地 sync increment;
- 发出 **megacore-partner** `sparse_core::SyncAddOp::create` 变体(`0x146120c0`,较长的 `(…CoreTypeAttr, bool)` 签名),以 partner core 为目标,跨核 sflag offset 通过 `SubsliceToFullSlice`(`0x133e79a0`)计算。在 leader 分支中,此 partner add 被包装在 `scf::ForOp`(`0x17866d60`)里,范围为 `LogicalDevicesPerChip(SC)`。

`0x103`/`kCoresOnChip` tag 把这个 barrier 绑定到 SC tensor-split 使用的同一个 megacore knob —— 见 [Megacore Even/Odd Split](../twist/megacore-even-odd.md)。

### Partner:`ToPartnerGlobalCoreId`(`0x133e66e0`)

跨核 `SyncAdd` 指向的*partner*核心由 `OffloadFactory::ToPartnerGlobalCoreId` 计算。反编译主体毫不含糊:

```text
RetCheck( LogicalDevicesPerChip(SC) == 2 )               // megacore-only; else RetCheck line 0x50
local = GetCoreIndex()
chip  = DivUIOp(local, CoresPerChip(SC))
gcid  = ToGlobalCoreId(chip, ...)
return XOrIOp(gcid, ConstantIndexOp(1))                  // flip the low bit ⇒ even↔odd partner

Partner 是当前核心 id 翻转低位(XOR 1)后的值:megachip 对内 core 0 ↔ core 1。主体先 flatten(ToGlobalCoreId(chip)),再对得到的 global id 执行 XOR 1。如果 LDPC(SC) == 2 RetCheck 失败,慢路径会记录 "GetPartnerGlobalCoreId() is only available for 2 logical devices per chip configurations." —— 除非部件是双核 megachip,否则不存在 partner。

Worked rendezvous — 两个分支完成的事

具体来说,取一个带 SC core {0, 1} 的 megachip(LDPC(SC) == 2)。Core 0 是偶数(leader,运行 $_0);core 1 是奇数(partner,运行 $_1)。每个核心发出的程序,用 MLIR 术语表示为:

text
core 0 ($_0 leader):                       core 1 ($_1 partner):
  SyncWait(local sflag, tag=kCoresOnChip)    SyncWait(local sflag, tag=kCoresOnChip)
  SyncAdd(local sflag)                       SyncAdd(local sflag)
  for d in 0..LDPC(SC):                       SyncAdd( partner = ToPartnerGlobalCoreId()
    SyncAdd( partner = ToPartnerGlobalCoreId()              = (1) XOR 1 = core 0 )
            = (0) XOR 1 = core 1 )
```text

Core `0` 的 partner 是 `0 XOR 1 = 1`;core `1` 的 partner 是 `1 XOR 1 = 0`。每个核心都会递增*另一个*核心的 sync flag(通过 `SubsliceToFullSlice` 寻址到 partner 的 sflag window 的跨核 `SyncAdd`),并等待自己的 sync flag(带 `kCoresOnChip` tag 的 `SyncWait`),因此这对核心会在继续前 rendezvous。这个结构在单核部件上完全不存在 —— 那里会抑制 partner add 和偶/奇谓词化,barrier 退化为纯本地 `SyncAdd`/`SyncWait`。

### CUSTOM 分支共享 partner 跨核 sync

`EmitCustomBarrierStart`(`0x13352fc0`,通过 color-id closure thunk `0x13355420` 从 `CUSTOM(3)` 分派到达)调用 `ToPartnerGlobalCoreId`、`GetSyncFlagForBarrierId`(colored barrier id → SFLAG number)和 megacore-partner `SyncAddOp` 变体(`0x146120c0`,两次 —— 一次用于本地侧,一次通过 `SubsliceToFullSlice` `0x133e79a0` 跨核)—— 也就是 `GLOBAL` 分支使用的同一个 partner 跨核 sync。跨核 SFLAG 寻址来源是 `GLOBAL` 和 `CUSTOM` 之间唯一的一阶差异(reserved id vs colored id)。注意 `EmitCustomBarrierStart` 自身**不**调用 `Predicated`/`Not`:不同于 `EmitGlobalBarrier`,偶/奇谓词化不会在 CUSTOM start emitter 内部物化(它携带 partner-add 机制,但没有显式 leader/partner predicate split)。两个分支共享的是 `ToPartnerGlobalCoreId` partner core 计算和 partner `SyncAddOp`,不是 `Predicated` 包装。

> **GOTCHA — 单核部件没有 partner 路径。** 在 `LogicalDevicesPerChip(SC) == 1` 的部件上,`ToPartnerGlobalCoreId` 会 `RetCheck`,所以 partner-add 和偶/奇谓词化都不会触发 —— 只剩本地 `SyncAdd` / `SyncWait`。重新实现者必须用 `LDPC(SC) == 2` gate 整套 partner 机制,而不是无条件发出。

---

## SC 流水线与 TensorCore 栈的对比

[TensorCore scheduling stack](../sched/overview.md) 是跨两个 IR 的三阶段流程(HLO latency-hiding scheduler → MXU/MRB assignment → LLO bundle packer),由 bundle cost model 定价。SC 后端流水线是另一类东西:一条作用于 `tpu`/`mosaic_sc` 方言的扁平十二 pass MLIR 流水线,以 MLO lowering 结束,**没有独立的 resource-assignment 阶段**,也**没有由 cost-model 定价的重排序**。SC 流水线唯一“接近调度”的决策是 vector layout(pass 7–9)以及在此流水线*之前*发生的逐 engine outlining(见 [Region → Sequencer Outliner](region-to-sequencer-outliner.md))。两条流水线只在 chip 边界相遇:此流水线发出的 SC barrier 通过共享 sync-flag 池与 TensorCore 同步,而 device-id remap(pass 11)正是让这些跨 engine signal 落到正确物理核心上的机制。

---

## 交叉引用

- [SparseCore 概览](overview.md) — 三类 engine、逐代际存在性,以及此流水线 lower 的 embedding data path。
- [SparseCore 架构](architecture.md) — engine 角色和 embedding datapath 详解。
- [Region → Sequencer Outliner](region-to-sequencer-outliner.md) — 生成此流水线消费的 `tpu` 方言 module 的逐 engine outlining。
- [SC EmitX Dispatcher](sc-emitx-dispatcher.md) — 下游逐 engine codec 使用的 seq3/seq4/seq5 → EmitX jump table。
- [getSequencerType](getsequencertype.md) — SCS/TAC/TEC engine-selection 函数。
- [SCS(Scalar)Engine](scs-engine.md) — 运行发出的 sync op 的 scalar sequencer。
- [TAC Engine](tac-engine.md) — tile-access / DMA-issuer engine。
- [TEC(Vector)Engine](tec-engine.md) — layout pass(7–9)面向的宽 vector compute engine。
- [SC Core Selection](sc-core-selection.md) — 物理 SparseCore 核心选择,是此流水线 device-id remap 的对应部分。
- [GetSparseCoreConfig](getsparsecoreconfig.md) — 供给流水线的 offload op-type 配置来源。
- [Barrier → SFLAG Number Binding](../barrier/barrier-to-sflag-binding.md) — barrier 分支调用的 colored/reserved barrier id → hardware SFLAG number 映射。
- [BarrierColoring](../barrier/barrier-coloring.md) — 分配 CUSTOM barrier color 的 graph-coloring engine。
- [Global-Barrier SFLAG Window](../barrier/global-barrier-window.md) — GLOBAL 分支取用的 reserved SFLAG window。
- [Megacore Even/Odd Split](../twist/megacore-even-odd.md) — 此 barrier 的 partner sync 共享的 `LDPC(SC)==2` / `kCoresOnChip` 拓扑 knob。
- [Physical-Core Placement](../collectives/physical-core-placement.md) — SC-offload collective 的逐 color 物理核心映射。
- [TPU Scheduling Pipeline](../sched/overview.md) — 用于对比的 TensorCore 侧三阶段 scheduling stack。
- **Binary:** `extracted/libtpu-0.0.40-cp314-cp314-manylinux_2_31_x86_64/libtpu/libtpu.so`(build-id `89edbbe81c5b328a958fe628a9f2207d`)
- **索引条目:** Part IX — SparseCore & BarnaCore / SparseCore back-end — [返回索引](../index.md)