跳转至

UnrollLoops Pass

在编译时展开 ForKind::Unroll 循环,将循环体内联到每次迭代中。

概述

此 Pass 静态展开通过 pl.unroll() 创建的 for 循环,将其替换为循环体的多份副本,其中循环变量被替换为每次迭代的常量值。

使用场景: 在默认流水线(pipeline)中自动运行,位于 ConvertToSSA 之前。当循环次数为编译时常量并且您希望为每次迭代复制循环体时,使用 pl.unroll()。

API

C++ Python 级别
pass::UnrollLoops() passes.unroll_loops() 函数级(Function-level)

Python 用法:

from pypto import passes

# 创建并应用 Pass
result = passes.unroll_loops()(program)

DSL 语法

# 基本展开:循环体复制 4 次,i = 0, 1, 2, 3
for i in pl.unroll(4):
    x = pl.add(x, i)

# 带 start/stop/step:循环体复制,i = 0, 2, 4
for i in pl.unroll(0, 6, 2):
    x = pl.add(x, i)

约束条件

约束 原因
start、stop、step 必须为整数常量 编译时需要确定值
step 不能为零 防止无限循环
输入 Unroll 循环不能带 SSA iter_args 此 Pass 展开非 SSA 循环体,必须先于 ConvertToSSA 运行
行程数(trip count)必须 ≤ 1024(kMaxUnrollIterations) 限制编译期展开规模 —— 超出会抛出 ValueError;请重构循环或改用 pl.range()

IR 仍可表示带 iter_args 的 ForKind.Unroll,例如直接对累加器循环运行 ConvertToSSA 时会产生该过渡形式。打印器和解析器通过 pl.unroll(..., init_values=(...)) 保留它,往返检查会实际验证整个程序。 可往返不代表 Pass 顺序合法:UnrollLoops 仍拒绝此 SSA 输入。可执行内核应在 pl.unroll() 内使用普通赋值,并遵循正常流水线顺序。

示例

展开前(包含展开循环):

@pl.program
class Before:
    @pl.function
    def main(self, x: pl.Tensor[[64], pl.FP32]) -> pl.Tensor[[64], pl.FP32]:
        for i in pl.unroll(3):
            x = pl.add(x, i)
        return x

展开后(循环已展开):

@pl.program
class After:
    @pl.function
    def main(self, x: pl.Tensor[[64], pl.FP32]) -> pl.Tensor[[64], pl.FP32]:
        x = pl.add(x, 0)
        x = pl.add(x, 1)
        x = pl.add(x, 2)
        return x

流水线位置

UnrollLoops 在 Default 中只运行一次,位于控制流结构化之前:

UnrollLoops → CtrlFlowTransform → ConvertToSSA → FlattenCallExpr → OutlineHierarchyScopes → OutlineIncoreScopes → ...

UnrollLoops 将 pl.unroll() 循环展开为完全平铺的直线代码形式。

Pass 属性

属性 值
前置要求(Required) —
产生(Produced) UnrollResolved
失效(Invalidated) —