Compiler construction 溢出符号不会';不能改善着色性

Compiler construction 溢出符号不会';不能改善着色性,compiler-construction,arm,cpu-registers,intermediate-language,Compiler Construction,Arm,Cpu Registers,Intermediate Language,假设我有一些代码的中间表示: t1 = 1 t2 = 2 t3 = 3 t4 = t1 + t2 t5 = t3 + t4 use t5 最终目标是只使用两个ARM寄存器进行寄存器分配,r0和r1,并可能溢出一些符号 第一步是计算每个指令的活动范围: t1 = 1 | t2 = 2 | t1 t3 = 3 | t1, t2 t4 = t1 + t2 | t1, t2, t3 (this is going to become a problem) t5

假设我有一些代码的中间表示:

t1 = 1
t2 = 2
t3 = 3

t4 = t1 + t2
t5 = t3 + t4

use t5
最终目标是只使用两个ARM寄存器进行寄存器分配,
r0
r1
,并可能溢出一些符号

第一步是计算每个指令的活动范围:

t1 = 1       |
t2 = 2       | t1
t3 = 3       | t1, t2

t4 = t1 + t2 | t1, t2, t3 (this is going to become a problem)
t5 = t3 + t4 | t3, t4

use t5       | t5
寄存器干涉图 基于图着色的寄存器分配 现在使用Chaitin的算法,使用两个寄存器对其进行着色:

  • 查找边数小于2的节点
  • 找到=>
    t5
  • 将其从图表中删除
  • 将其推到堆栈上:
    [t5]
  • 查找边数小于2的节点
  • 找到=>
    t4
  • 将其从图表中删除,按下:
    [t5,t4]
  • 没有少于2条边的节点!(我们正在看
    t1-t2-t3
    三角形)
  • 随机选择一个(或具有最高阶数(所有剩余节点为2))=>
    t3
    (这可能是个问题)
  • 将其从图表中删除,按下:
    [t5、t4、t3]
  • 查找边数小于2的节点
  • 找到
    t2
  • 将其从图形中删除,按下:
    [t5、t4、t3、t2]
  • 推送最后一个节点:
    [t5、t4、t3、t2、t1]
  • 现在按相反顺序分配寄存器:

  • Pop符号=>
    t1
  • 冲突节点:无
  • 分配:
    t1=>r0
  • t1
    放回图形中
  • Pop
    t2
  • 冲突节点:
    {t1:r0}
  • 我们还有一个免费注册
  • 分配:
    t2=>r1
  • t2
    放回图形中
  • Pop
    t3
  • 冲突节点:
    {t1:r0,t2:r1}
  • 哎呀!不再免费注册
  • 溢出它=>
    t3=>m0
  • t3
    放回图形中
  • 不需要更多的泄漏 最终任务:

    t1 -> r0
    t2 -> r1
    t3 -> m0 (spilled)
    t4 -> r0 (or r1)
    t5 -> r0 (or r1)
    
    插入溢出 现在,根据(幻灯片29)和(幻灯片4):

    在每次使用[溢出符号
    t3
    ]的操作之前,插入
    t3:=load m0

    在定义[溢出符号
    t3
    ]的每个操作之后,插入
    存储t3,m0

    让我们这样做,并计算活动范围:

    t1 = 1       |
    t2 = 2       | t1
    
    t3 = 3       | t1, t2
    // STORE
    store t3, m0 | t1, t2, t3 (STILL 3 SYMBOLS!)
    
    t4 = t1 + t2 | t1, t2
    
    // LOAD
    t3 = load m0 | t4
    t5 = t3 + t4 | t3, t4
    
    use t5       | t5
    
    问题 正如你所看到的,我们仍然有一个指令,其中有三个符号相互干扰,我们也将得到与以前相同的装备

    所以泄漏没起作用

    现在,我用暴力强迫可能的候选人手动溢出,发现如果我们溢出任何一个符号,装备将保持不可2色,但如果我们溢出任何一对符号,装备将变为可2色:

    • t1
      t3
    • t2
      t3
    …还有
    t1
    t2
    t3
    ,但只溢出两个符号看起来更简单

    实际问题 我如何决定洒什么?我用什么启发法?我还希望该算法能够进行全局寄存器分配,因此纯实时范围和线性扫描分配(与构建装备相反)似乎是一种相当麻烦的方法

    另外,如果我在带有溢出的代码上重新运行相同的算法,结果将再次是“溢出
    t3
    ”,即使已经完成了,因此代码将永远循环。更重要的是,如果我继续溢出
    t3
    并插入
    load
    /
    store
    代码,我会在
    t1
    t2
    t3
    干扰的地方得到越来越多的指令,因此情况会变得更糟


    这是假设我可以只
    t3=加载m0
    ,而在ARM上(我的目标)
    m0
    应该首先存储在它自己的寄存器中。

    也许我的答案的最后一段会帮助你,即使用溢出范围更长的溢出启发式,这样溢出生成的新临时值就不会再次溢出。@antoyo,在最后一段代码上运行线性扫描算法(溢出的代码为
    t3
    )并选择溢出
    t1
    ,作为迄今为止最长有效范围的符号(在指令
    存储t3,m0
    )后,这似乎起作用了。但是装备方法会丢失关于符号活动范围的所有信息(对吗?),所以看起来我不能在这里使用它。我也可以切换到线性扫描,但我已经有了一个工作的图着色分配器(不能溢出),而且我对编写一个新的分配器不太感兴趣。所以,我在溢出成本中使用的是与活动范围相关的节点的度(即邻居的数量)。你可以试试看。@antoyo,我已经在暗中使用这个了。请参见第一个列表中的步骤2.1:“随机选择一个(或以最高程度)=>
    t3
    ”。因此,在弹出
    t4
    t5
    之后,我得到了
    t1-t2-t3
    三角形,这三个节点都有2度,所以我也不知道选择哪一个
    t1 = 1       |
    t2 = 2       | t1
    
    t3 = 3       | t1, t2
    // STORE
    store t3, m0 | t1, t2, t3 (STILL 3 SYMBOLS!)
    
    t4 = t1 + t2 | t1, t2
    
    // LOAD
    t3 = load m0 | t4
    t5 = t3 + t4 | t3, t4
    
    use t5       | t5