复写传播

复写(复制,赋值)传播的目的是借助复写语句,尽可能将tac中对复写左端项的引用替换成对右端项的引用。虽然表面上没有减少指令的条数,但这样做的好处在于优化后复写左端项有可能不再活跃,从而让死代码消除可以删除这条复写语句。

复写传播的实现方法与公共表达式提取是类似的,与可用表达式对应,它考虑的是可用复写语句。一条复写语句生成一条可用复写语句,一条带有定值的语句可以杀死与被定值的虚拟寄存器相关的所有复写语句(包括它出现在左端项或者右端项的)。除此之外,复写传播的数据流方向,交汇运算和初始值均与可用表达式的数据流相同。

按照老套路计算出每条语句处所有的可用复写语句后,考察一条语句使用的虚拟寄存器a,如果存在一条可用的复写语句,它的左端项是a,那么a可以被替换成它的右端项。这个过程还可以递归地进行下去:设这个右端项为b,如果存在一条可用的复写语句,它的左端项是b,则a可以进一步被替换成它的右端项c。这样就可以一步传播多层。

一个例子如下:

  b = a
  c = b
  d = c
  x = y + d

计算可用复写语句,每个语句后的方括号内的内容是这条语句执行的可用复写语句集合:

  b = a []
  c = b [b = a]
  a = x [b = a, c = b]
  d = c [c = b, a = x] // 上一条语句杀死了b = a
  x = y + d [c = b, a = x, d = c]

执行转换:

  b = a
  c = a # 因为b = a可用,所以b被替换成a
  a = x
  d = b # 因为c = b可用,所以c被替换成b
  x = y + b # 因为d = c,c = b可用,所以d被替换成b

Last updated