@@ -241,15 +241,16 @@ pto.tfree_from_aiv { split = 0 }
241241
242242### 4.1 逻辑 pipe
243243
244- 本文中的“ 逻辑 pipe”指一条单向通信通道 。
244+ 本文中的” 逻辑 pipe”指一条通信通道 。
245245
246246- C2V:Cube producer -> Vector consumer
247247- V2C:Vector producer -> Cube consumer
248248
249- ` DIR_MASK=3 ` 表示前端一个同时包含 C2V 和 V2C 的初始化请求,在 PTOAS lowering 后拆成两条单向逻辑 pipe:
250-
251- - 一条 ` dir_mask = 1 ` 的 C2V pipe
252- - 一条 ` dir_mask = 2 ` 的 V2C pipe
249+ ` DIR_MASK=3 ` 表示前端一个同时包含 C2V 和 V2C 的初始化请求。在 PTOAS lowering
250+ 后,生成单条 ` dir_mask = 3 ` 的 DIR_BOTH 内部 pipe,同时承载 C2V 和 V2C 双向
251+ 通信。该 pipe 携带两个地址操作数:` local_addr ` (C2V consumer buf)和
252+ ` peer_local_addr ` (V2C consumer buf)。下游 TPUSH/TPOP/TFREE 共享同一 pipe
253+ handle。
253254
254255### 4.2 ` split ` 的角色
255256
@@ -288,7 +289,7 @@ pto.tfree_from_aiv { split = 0 }
288289` SLOT_NUM ` 由 ` DIR_MASK ` 固定决定:
289290
290291- ` DIR_MASK = 1 ` 或 ` 2 ` :` SLOT_NUM = 8 `
291- - ` DIR_MASK = 3 ` :拆成两条单向 pipe,且每条 ` SLOT_NUM = 4 `
292+ - ` DIR_MASK = 3 ` (DIR_BOTH):单条 pipe,` SLOT_NUM = 4 ` (每方向 4 slot,总缓冲 2 × 4 × SLOT_SIZE)
292293
293294` SLOT_NUM ` 不由 ` split ` 决定。
294295
@@ -306,13 +307,26 @@ pto.tfree_from_aiv { split = 0 }
306307
307308用于 A2/A3 路径。
308309
310+ 单向示例:
311+
309312``` mlir
310313%pipe = pto.initialize_l2g2l_pipe {
311314 dir_mask = 1,
312315 slot_size = 512,
313316 slot_num = 8,
314317 local_slot_num = 8
315- }(%gm_addr, %local_addr) -> !pto.pipe
318+ }(%gm_addr : i32, %local_addr : i32) -> !pto.pipe
319+ ```
320+
321+ DIR_BOTH 示例:
322+
323+ ``` mlir
324+ %pipe = pto.initialize_l2g2l_pipe {
325+ dir_mask = 3,
326+ slot_size = 512,
327+ slot_num = 4,
328+ local_slot_num = 4
329+ }(%gm_addr : i32, %c2v_addr : i32, %v2c_addr : i32) -> !pto.pipe
316330```
317331
318332#### 必需属性
@@ -327,10 +341,10 @@ pto.tfree_from_aiv { split = 0 }
327341 - 仅 ` initialize_l2g2l_pipe ` 承载
328342 - 表示 GM 路径下 consumer 侧 local slot buffer 的槽数
329343 - 仅在通过 GM 传递时对底层 ` TPipe ` 模板参数有意义,不改变 GM FIFO 的 ` slot_num `
330- - 缺省值等于该内部单向 pipe 的 ` slot_num `
344+ - 缺省值等于该内部 pipe 的 ` slot_num `
331345 - 因此当前固定规则下:
332346 - ` DIR_MASK=1/2 ` 直接 lowering 时,` local_slot_num = 8 `
333- - ` DIR_MASK=3 ` 拆成两条单向 pipe 后,每条 ` local_slot_num = 4 `
347+ - ` DIR_MASK=3 ` 单条 DIR_BOTH pipe, ` local_slot_num = 4 `
334348- ` flag_base `
335349 - 由 PTOAS flag 分配阶段填写
336350 - frontend lowering 阶段可以缺省
@@ -339,23 +353,36 @@ pto.tfree_from_aiv { split = 0 }
339353#### 操作数
340354
341355- ` gm_addr `
342- - ` local_addr `
356+ - ` local_addr ` :C2V consumer buf(或单向时唯一方向的 consumer buf)
357+ - ` peer_local_addr ` (可选):V2C consumer buf,仅 ` dir_mask = 3 ` 时出现
343358
344359### 5.3 ` pto.initialize_l2l_pipe `
345360
346361用于 A5 路径。
347362
363+ 单向示例:
364+
348365``` mlir
349366%pipe = pto.initialize_l2l_pipe {
350367 dir_mask = 1,
351368 slot_size = 512,
352369 slot_num = 8
353- }(%local_addr) -> !pto.pipe
370+ }(%local_addr : i32) -> !pto.pipe
371+ ```
372+
373+ 双向(DIR_BOTH)示例:
374+
375+ ``` mlir
376+ %pipe = pto.initialize_l2l_pipe {
377+ dir_mask = 3,
378+ slot_size = 1024,
379+ slot_num = 4
380+ }(%c2v_addr : i32, %v2c_addr : i32) -> !pto.pipe
354381```
355382
356383#### 必需属性
357384
358- - ` dir_mask `
385+ - ` dir_mask ` :合法值 ` 1 ` (C2V)、 ` 2 ` (V2C)、 ` 3 ` (DIR_BOTH)
359386- ` slot_size `
360387- ` slot_num `
361388
@@ -368,6 +395,11 @@ pto.tfree_from_aiv { split = 0 }
368395
369396#### 操作数
370397
398+ - ` local_addr ` :C2V consumer buf(或单向时唯一方向的 consumer buf)
399+ - ` peer_local_addr ` (可选):V2C consumer buf,仅 ` dir_mask = 3 ` 时出现
400+
401+ #### 操作数
402+
371403- ` local_addr `
372404
373405### 5.4 ` pto.tpush `
@@ -417,31 +449,30 @@ pto.tfree(%pipe) { split = 0 }
417449
418450### 6.3 ` DIR_MASK=3 `
419451
420- 前端一个 init op 固定拆成两条内部 pipe:
452+ 前端一个 init op 生成 ** 单条 ** DIR_BOTH 内部 pipe:
421453
422- - ` %pipe_c2v ` :` dir_mask = 1 ` ,` slot_num = 4 `
423- - ` %pipe_v2c ` :` dir_mask = 2 ` ,` slot_num = 4 `
424-
425- 若 lowering 为 ` initialize_l2g2l_pipe ` ,则两条内部 pipe 还满足:
426-
427- - ` %pipe_c2v ` :` local_slot_num = 4 `
428- - ` %pipe_v2c ` :` local_slot_num = 4 `
454+ - ` %pipe ` :` dir_mask = 3 ` ,` slot_num = 4 `
455+ - 若 lowering 为 ` initialize_l2g2l_pipe ` ,` local_slot_num = 4 `
429456
430457地址选择规则:
431458
432- - ` %pipe_c2v ` 使用 ` C2V_CONSUMER_BUF `
433- - ` %pipe_v2c ` 使用 ` V2C_CONSUMER_BUF `
459+ - ` local_addr ` = ` C2V_CONSUMER_BUF `
460+ - ` peer_local_addr ` = ` V2C_CONSUMER_BUF `
461+
462+ ` FrontendPipeHandles ` 中 ` c2vPipe ` 和 ` v2cPipe ` 指向同一个 pipe Value。
434463
435464### 6.4 前端数据传输 op 与内部 pipe 的绑定
436465
437466绑定规则固定如下:
438467
439468| 前端 op | 所在函数 | 方向 | 使用的内部 pipe |
440469| ---| ---| ---| ---|
441- | ` tpush_to_aiv ` | Cube | C2V | ` dir_mask = 1 ` |
442- | ` tpop_from_aic ` | Vector | C2V | ` dir_mask = 1 ` |
443- | ` tfree_from_aic ` | Vector | C2V | ` dir_mask = 1 ` |
444- | ` tpush_to_aic ` | Vector | V2C | ` dir_mask = 2 ` |
470+ | ` tpush_to_aiv ` | Cube | C2V | ` c2vPipe ` |
471+ | ` tpop_from_aic ` | Vector | C2V | ` c2vPipe ` |
472+ | ` tfree_from_aic ` | Vector | C2V | ` c2vPipe ` |
473+ | ` tpush_to_aic ` | Vector | V2C | ` v2cPipe ` |
474+
475+ 当 ` DIR_MASK=3 ` 时,` c2vPipe ` 和 ` v2cPipe ` 指向同一个 DIR_BOTH pipe,下游 TPUSH/TPOP/TFREE 只关心 pipe handle 是否存在,不关心是否是同一个。
445476| ` tpop_from_aiv ` | Cube | V2C | ` dir_mask = 2 ` |
446477| ` tfree_from_aiv ` | Cube | V2C | ` dir_mask = 2 ` |
447478
@@ -602,16 +633,17 @@ pass 在模块级按两步执行:
602633其中第一步的实现方式是:
603634
604635- 遍历模块内所有 ` pto.initialize_l2l_pipe ` / ` pto.initialize_l2g2l_pipe `
605- - 若其 ` local_addr ` 来自 ` reserve_buffer ` ,则以“当前函数 + reserve 名字 + dir_mask”识别逻辑 pipe
606- - 若其 ` local_addr ` 来自 ` import_reserved_buffer ` ,则以“peer_func + reserve 名字 + dir_mask”识别逻辑 pipe
636+ - 对每条 init op 的每个地址操作数,以”函数 + reserve 名字 + 方向”构建 PipePeerKey 并归入逻辑 pipe 分组:
637+ - ` dir_mask = 1/2 ` :只有 ` local_addr ` ,方向即 ` dir_mask `
638+ - ` dir_mask = 3 ` (DIR_BOTH):一条 pipe 携带两个地址,分别归入两个逻辑方向——` local_addr ` 归入 C2V(方向 1),` peer_local_addr ` 归入 V2C(方向 2)
607639- 将 peer 两侧引用到同一逻辑 pipe 的内部 init op 归并到同一组
608640- 若某条 init 未显式提供 ` flag_base ` ,则其 ` local_addr ` 必须来自 ` reserve_buffer ` 或 ` import_reserved_buffer `
609641- 对每个逻辑 pipe 分组,要求必须形成完整 peer init pair:恰好两条 init,且分别来自 peer 两侧函数;若 peer 信息不完整则直接报错
610642- 在同一组内,若任一侧已显式提供 ` flag_base ` ,则该值作为该组最终值;若两侧显式值冲突则报错
611643- 若同组两侧都未显式提供 ` flag_base ` ,则按默认规则回填:
612644 - 单向场景:` flag_base = 0 `
613645 - 双向场景:C2V 组 ` flag_base = 0 ` ,V2C 组 ` flag_base = 2 `
614- - 所谓 “双向场景”,是指同一对 peer 函数之间同时存在 ` dir_mask = 1 ` 和 ` dir_mask = 2 ` 两个逻辑 pipe 分组
646+ - “双向场景”指同一对 peer 函数之间同时存在 C2V 和 V2C 两个逻辑 pipe 分组;DIR_BOTH 的一条物理 pipe 天然产生这两个分组
615647- 完成分组决策后,将最终 ` flag_base ` 回填到该组内所有尚未显式填写的 init op,保证 peer 两侧一致
616648
617649第二步的实现方式是:
@@ -663,16 +695,18 @@ pass 在模块级按两步执行:
663695
664696### 8.3 双向场景
665697
666- 当前规划中,当 ` DIR_MASK = 3 ` 时,可采用 :
698+ 当前规划中,当 ` DIR_MASK = 3 ` (DIR_BOTH)时,虽然物理上只有一条 pipe,但 resolve pass 将其拆为两个逻辑方向分别分配 ` flag_base ` :
667699
668- - C2V pipe :` flag_base = 0 `
669- - V2C pipe :` flag_base = 2 `
700+ - C2V 方向 :` flag_base = 0 `
701+ - V2C 方向 :` flag_base = 2 `
670702
671703因此双向固定占用两组逻辑 flag:
672704
673705- C2V:` 0 ` / ` 1 `
674706- V2C:` 2 ` / ` 3 `
675707
708+ 对于单条 DIR_BOTH pipe,最终 ` flag_base ` 取 C2V 方向的值(` 0 ` ),底层 pto-isa ` TPipe<flagBase, Direction::DIR_BOTH, ...> ` 会自动管理两个方向的 flag 对。
709+
676710### 8.4 与地址传播的关系
677711
678712地址传播 pass 在识别出 ` import_reserved_buffer ` 与 ` reserve_buffer ` 的 peer 对应关系后,同时可以完成 peer pipe 的 ` flag_base ` 对齐。
@@ -758,10 +792,21 @@ EmitC 将以下内部 init op 映射到底层 `TPipe`:
758792- ` dir_mask `
759793- ` slot_size `
760794- ` slot_num `
761- - ` local_slot_num `
795+ - ` local_slot_num ` (仅 ` initialize_l2g2l_pipe ` )
762796- ` flag_base `
763- - ` gm_addr `
797+ - ` gm_addr ` (仅 ` initialize_l2g2l_pipe ` )
764798- ` local_addr `
799+ - ` peer_local_addr ` (仅 ` dir_mask = 3 ` 时)
800+
801+ ` dir_mask ` 到 ` Direction ` 枚举的映射:
802+
803+ | ` dir_mask ` | ` Direction ` 令牌 |
804+ | ---| ---|
805+ | 1 | ` Direction::DIR_C2V ` |
806+ | 2 | ` Direction::DIR_V2C ` |
807+ | 3 | ` Direction::DIR_BOTH ` |
808+
809+ 当 ` dir_mask = 3 ` 时,EmitC 将 ` local_addr ` 作为 C2V consumer buf、` peer_local_addr ` 作为 V2C consumer buf 传入 ` TPipe ` 构造函数。
765810
766811其中:
767812
0 commit comments