简单的Register Allocation学习
学习链接:
https://zhuanlan.zhihu.com/p/470413251
https://zhuanlan.zhihu.com/p/178228779
https://blog.csdn.net/pc153262603/article/details/125416273
https://blog.csdn.net/cicuinie0996/article/details/100829405
https://homepages.dcc.ufmg.br/~fernando/classes/dcc888/ementa/
linearScan
线性扫描的做法是先分析得到临时寄存器的live range,[1, 5]代表了指令下标为1的时候该临时寄存器live,5的时候寄存器dead;
根据live range的start对所有的LR进行排序,比如我们可以得到:
[0, 2],[1, 3],[1, 6],[2, 4],[2, 5],[3, 6]
得到以上排序后的LR之后,我们就可以逐顺序为其分配寄存器了;
大致逻辑代码如下:
点击查看代码
while(LR!=null)
if(activeListHead->end < LR->start)
freeRegister(ativeListHead)
remove(activeListHead) // or activeListHead = activeList->next;
if(LR->Register == null)
allocRegister(LR)
add_active(LR)
LR = LR->next
该算法不是最优算法,却非常的简单;
graph coloring
图着色也要分析liveness,并根据同一时间live的寄存器建立引用图,然后逐一从图中取出都小于图最大度的点,并按照此顺序装回去,在装回去的过程中给其分配颜色,颜色color就代表了寄存器资源,保证相互连接的节点不是同一颜色即可;
图着色并没有深入了解;
SPILL
当寄存器资源不够的时候,可以考虑先关一点优化,如果是并行计算的话,那么考虑减少并发度来增加per资源,如果以上都不行的话,那么就spill吧,利用load store指令将数据存出去,再拿回来;这样就能看到多条指令其实都在用同一个寄存器,这同一个寄存器就是穿插在指令中的load的dst,所以即使发生了spill,也是需要预留寄存器给load store来使用的;
local RA的算法
点击查看代码
allocate(Block b) {
for (Inst i: b.instructions()) {
for (Operand o: i.operands()) {
if (o is in memory m) {
r = find_reg(i)
assign r to o
add "r = load m" before i
}
}
for (Operand o: i.operands()) {
if (i is the last use of o) {
return the register bound to o to the list of free registers
}
}
v = i.definition
r = find_reg(i)
assign r to v
}
}
find_reg(i) {
if there is free register r
return r
else
let v be the latest variable to be used after i, that is in a register
if v does not have a memory slot
let m be a fresh memory slot
else
let m be the memory slot assigned to v
add "store v m" right after the definition of v
return r
}

浙公网安备 33010602011771号