Skip to content

算法Algorithm

仿射归纳变量强度削弱

Affine induction strength reduction · Induction-variable strength reduction · 仿射归纳变量递推

在规范整数循环中把每轮重算m乘i加c变成新鲜载体递推,证明非零起点、更新相位与零轮状态保持,并区分循环运算和新增初始化成本。

形式陈述 ​

不变的增量,也能维护变化的值 ​

设循环变量 i 每轮增加3,循环中不断计算5i−4。这个表达式并不循环不变:当 i 为2、5、8、11时,它依次是6、21、36、51。可以利用的不是值不变,而是相邻两次结果总相差15。先计算6,以后每轮加15,就不必每轮乘5。

本页承接循环不变代码外提中的入环初始化、不变操作数和提前求值条件。区别在于这里只把初值与固定增量放到循环前,结果载体仍在循环内更新。不能把变化的5i−4直接外提成第一次的6。

输入是明确的规范循环 ​

程序先顺序执行有限初始化段,再反复检查一个整数比较条件。条件为真时,顺序执行有限循环体;为假时返回若干表达式。运算仅有数学整数上的加、减、乘和比较,比较返回0或1。没有内存、调用、异常、溢出、I/O、随机性或资源耗尽观察。

选定一个局部归纳变量 i。初始化段最后一条恰是 i:=i₀,此前不定义 i,i 也不是输入参数。循环体最后一条恰是 i:=i+s,或者语义相同的加法、减法形式;循环体没有其他对 i 的赋值。s 的所有变量都已在入环前定义,且整个循环体不写它们。s 可正、负或零,不预设循环一定终止。

这里的“最后一条”是输入合同,不是编译器偷偷调整的结果。它给出统一相位:本轮其他语句读取更新前的 i,最后才生成下一轮 i。带 continue、条件递增、多入口或体中间更新的程序需要先做相应规范化及证明,参考器不直接接收为本算法候选。

选定表达式

e(i)=mi+c,

其中 m 是编译期给定的整数常量,c 是只依赖已初始化且体内不写变量的纯表达式。m 可为0。参考语法明确写成 add(mul(m,i),c),按完整有序语法键寻找循环体前部的出现,既可是一整条右侧,也可嵌在更大的表达式中。不自动证明别的代数形状与它相等。

源程序所有读取均须在第一次执行到该处时有定义,返回值也须在零轮情况下已定义。例如准备在体内更新 j,循环前仍应先给 j 一个旧值。如果目标想处理本来就含未初始化读取的源程序,已超出本页合同。

新鲜载体与固定更新位置 ​

建立两个没有与源变量重名的临时量 h 和 d。在源初始化段之后追加

h:=mi+c,d:=ms.

只由整数常量构成的新增子表达式可在编译期折叠。随后把循环体中每个选定 e 的出现替换成读取 h,保留原赋值目标和位置。最后在原 i 更新之后追加 h:=h+d。原循环条件和返回表达式暂不改写。

例如源中 j:=e 并不被删掉;它成为 j:=h。即使循环不执行,j 的旧值仍由原初始化段决定,新增 h 不会冒充源变量 j。参考器输出完整目标程序、替换位置和出现次数、新鲜名字、斜率、偏移、步长及初始 i 表达式。

编译时若找不到任何更新前的 e 出现,或者发现步长、偏移在体内被写,便拒绝该候选。验证结构之后才能生成递推;一次试跑中某个被写变量恰好没变,不是循环不变证明。

直觉

想象逐格填写一列等差数列。每格都从行号乘出值是可行的;若已经知道相邻格差15,也可以从第一格向下累加。编译器需要证明的是“这一格的载体确实对应这一轮的 i”,并把下一格的更新放在正确时刻。

新鲜 h 同时分开了两个职责。它维护以后可能需要的值;源变量 j 仍在原位置接收当前值。即使 j 在体中稍后被覆盖,也不会破坏 h 的下一轮递推。

例子与边界

非零起点与跨过上界 ​

取 start=2、limit=13、bias=−4,源程序为:

text
sum := 0
j := 99
i := start
while i < limit:
    j := 5*i+bias
    sum := sum+j
    i := i+3
return (sum,j)

各轮体入口 i 为2、5、8、11;j 为6、21、36、51。sum 依次为6、27、63、114,最后 i=14,条件14<13为假。返回 (114,51),退出的 i 不必恰等于循环界13。

变换后先令 h=6、d=15。每轮把 j:=5*i+bias 改为 j:=h,保留 sum 的累加与 i 的更新,再做 h:=h+15。五个循环头状态为

完成轮数01234i2581114h621365166sum062763114

最后 h=66 对应下一次 i=14 的表达式值;源 j 仍是最后真正执行那轮的51。二者不是同一个生命周期,不应把返回 j 改成返回 h。

维护下一轮载体,不覆盖最后一次源赋值

源执行4次乘法、12次加法,目标执行1次乘法、13次加法。d=5×3在编译期折叠;目标的1次乘法用于 h 初值。加法多1次来自初始化 h 的偏移计算,循环内的新 h 更新替代了原仿射式的加法,而 i 与 sum 仍每轮各更新一次。这里只给出该语言的操作计数,不预言机器速度。

提前一相位就会错 ​

若把 h:=h+15 放到循环体开头,第一轮 j 就读取21,而不是6。四轮读到21、36、51、66,返回 (174,66)。这份程序仍有一个等差数列,却没有在源使用位置保持同一个值。

初始化也不能套用零起点简式 h:=c。本例 i₀=2,正确 h₀=5×2−4=6;若只取−4,四轮会读取−4、11、26、41,累计74。原论文和教学代码中的特定起点,不是可以省略 i₀ 的一般许可证。

零轮保留源变量,但未必省工作 ​

把 start 改为14,仍令 limit=13。源直接返回 (0,99),体内 j 没有赋值。正确目标也返回 (0,99),因为只新建 h,没有提前赋给 j。

源乘法0次,目标为了 h 仍乘1次。纯总整数运算使这个新增工作在返回观察中不可见,但不能因此声称每个输入都更便宜。如果表达式可能抛异常、发散或产生事件,必须重新证明提前执行安全,不能沿用本页条件。

整数恒等式不能直接当作浮点恒等式 ​

本页递推使用精确分配律 m(i+s)+c=(mi+c)+ms。在通常二进制浮点下,重复加0.1六次可得到0.6,而0.1×6得到0.6000000000000001。两种舍入历史不同,即使表面上都是线性关系,也不再逐值相同。

固定宽度回绕整数则要另行指定环语义。模同一字宽的加乘可能仍满足仿射递推,但有序比较并不随模乘保持。下一页的循环测试替换需要更强条件;不能因为地址递推在模环里成立,就继续把数学整数的大小关系搬过去。

推论与应用

逐循环头的不变量 ​

进入第一次条件检查时,目标已经根据相同的源状态计算 h=mi+c、d=ms。源变量保持相同,因而归纳起点成立。证明不要求循环执行至少一次。

假设某次循环头源变量相同且 h=mi+c。原条件不变,因此源与目标要么一起退出,要么一起进入循环体。进入后,i 在尾部之前不变,c 的变量整个体内不被写,所以每个原 e 出现都等于当前 h。用 h 替换它,不改变整条右侧的值,也不改变赋值后的任何源变量。

到达尾部,源与目标都执行 i′=i+s。随后目标更新

h′=h+d=(mi+c)+ms=m(i+s)+c=mi′+c.

因为 s、c 的变量在体内不变,d 仍等于当前 ms,下一循环头恢复不变量。对体内语句和循环轮数分别归纳,所有原变量在对应循环头一致;退出返回也就相同。

这一归纳同样覆盖负步长、零步长和无限循环。每个源轮次仍由一个有限目标轮次匹配,新增初始化与更新都是纯总有限运算;既不会制造新的发散,也不会把原无限控制流变成有限返回。预算耗尽只是一份有限前缀记录,不是一般终止判定。

变化的结果与不变的系数要分开 ​

若体内修改 bias,则旧 h 加固定15不再对应新的5i+bias。若体内修改步长变量 step,d 的预计算也失效。参考器按体内所有写目标检查这两种情况;它保守拒绝,即使某条赋值在数值上恰好写回原值。

即使 e 在体内出现多次,一轮也只更新一次 h。这会进一步减少原乘法出现数,但多个源赋值仍各自在原位置执行。若其他语句仍直接读取 i,强度削弱并不删除 i;是否能改写循环条件并移除该变量,是线性函数测试替换的另一项合同。

变换成本与执行成本 ​

令 A 为输入程序与所选表达式语法的总大小,Q 为不同变量数,常数折叠的实际整数算术工作为 F。若不变性证据已给出且表达式键查询按常数计,记录位置与发出改写是一次语法扫描,输出大小仍为 O(A)。只增添固定数量的初始化与一条体尾更新,不按动态轮数复制代码。

参考器没有假设完整表达式比较恒为常数。它在子树处比较选定表达式,且用递归变量集合做初始化和不变性验证;集合并的粗界为 O(AQ),结构比较可到 O(A²)。以名字和小整数为常数字,实际变换可保守界为 O(A²+F),额外工作空间为 O(A²),包含递归集合和程序复制;目标语法本身仍为 O(A)。任意精度整数的折叠与运行还需按位数计费。

对于主例的 N 轮,源选定表达式有 N 次乘法,强度削弱有1次入环乘法;若步长本身在运行时才取得,d=ms可能再需1次初始化乘法。源每轮的完整表达式代价、目标每轮加法和复制、零轮新增工作、延长活跃范围都应分别记账。

可执行终点要求交出五个循环头、非零起点和提前相位的坏例,再把斜率改成负数、步长改成0,说明哪些结论由不变量保持,哪些只是有限预算检查。

参考资料
  • Keith D. Cooper、L. Taylor Simpson、Christopher A. Vick,Operator Strength Reduction,作者预稿,对应 ACM TOPLAS 23(5),2001,pp.603–625。实际读取预稿PDF第1–6页的迭代式削弱、Figure1–2及ACK背景;本页只实现规范标量循环,不冒称完整SSA图OSR。预稿有TBD刊头,PDF页码不作正式刊页
  • Adrian Sampson,Cornell CS6120: Loop Optimization,归纳变量、不变步长及更新位置的教学顺序。本页保留任意起点m i₀+c、源赋值位置与零轮返回条件,不沿用只适用于特定起点的初始化简式
关系图谱4 个相邻概念 · 1 类关系

拖动节点调整位置。

显示关系

显示:依赖

  1. 前置三跳
  2. 前置二跳
  3. 前置一跳
  4. 当前条目
  5. 后续一跳
  6. 后续二跳
  7. 后续三跳
文字版关系按与当前条目的最短距离分组