简单的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
}

posted @ 2022-09-01 15:45  无聊的白色骷髅头画家  阅读(109)  评论(0)    收藏  举报