寄存器分配
1. 如何计算D-U链
(1) 首先遍历整个routine,保存所有def值;
问题:
你如何去保存这些def值呢?要保证能快速的得到每个def值,因为每一 个 def 值不仅仅只包含dst寄存器号,还包括这条指令,以及其它信息。
解答之一:
最快速的查找算法,就是hash算法。在我们这里通过构建一个含有256个元素的hash表,hash[regNo & (256-1)] = defIndex;对于hash冲突的处理方法是,在def值的结构中存放一个变量,用来保存冲突的defIndex.
比如:
r1 = r2 + r3;//defIndex = x;
r1 = r1 * r4;//defIndex = x + 1;
很显然,此时两次def的r1的hash值是一样的,但两次def的defIndex是不一样的, 假定第一次的defIndex = x, 那么(pDefs + defIndex) ->hashNextDefIndex = x + 1;其实可以把这理解为链表的形式处理hash冲突,但冲突不是在hash表上处理的而已。
(2) 自顶向下计算每个Basic Block的LiveOut def值,这里的LiveOut def值表示在离开当前block后还可能活跃的def值。然后通过数据流分析,得到每个Basic Block的LiveIn def值。
问题:
如何计算?
解答之一 :
根据routine中的def值的数目,来定义一个长度为32bit倍数的变量(假定变量名字为FlowFunction),每一位用来表示对应的defIndex, 为1,表示活跃, 为0, 表示不活跃。
1) 分block扫描所有指令,在每一个block里,对有dst的指令,将FlowFunction变量的对应位置为1;如果出现多次定义一个变量的情况,则只会把最后一次的defIndex置为1,也就是在每次扫描的过程中,在最后一次def的时候,会把前一次的def clear 掉;这样每个Basic Block的FlowFunction变量的值就得到了;
2) 上一步只是得到每一个Block中的LiveOut def变量,因为在整个routine中block是有数据流关系的,如果当前Block有predecessor Block,则当前Block的LiveIn def变量 = 所有predecessor Block的LiveOut的或运算。
比如:
LiveIn(Block 5) = LiveOut(Block 3) | LiveOut(Block 4);
(3) 计算完每个Basic Block的LiveIn def值后,自顶向下扫描每个Block。首先检查每条指令的src, 然后根据src可以得到其所有的defIndex, 如果这个defIndex在LiveIn中,那么就将这个Usage添加到这个def中。然后检查这条指令的dst,这个dst是否已经在LiveIn中,如果是,则将 旧的defIndex从LiveIn中删掉,否则将这个dst的defIndex添加到LiveIn中。(此时的LiveIn已经不是原来的LiveIn,只能说初始值是原来的LiveIn吧)。
问题:为什么要计算LiveIn的def变量?如下图所示,如果不计算第1个block的LiveOut def值,那么在其successor block中use变量i就不知道来自于哪个def了