一种针对混合长度指令集的寄存器分配方法

文档序号:6436708阅读:315来源:国知局
专利名称:一种针对混合长度指令集的寄存器分配方法
技术领域
本发明涉及一种编译技术,尤其涉及一种针对混合长度指令集的寄存器分配方法。
背景技术
嵌入式系统常采用RISC架构,其指令集一般为定长指令集,即只具有单一长度的指令。指令长度一般为整数个字节,例如,16位指令,32位指令。较长的指令长度可以编码更多的操作数,寻址更多的寄存器,或者可使用更大的立即数等,故一般具有更好的性能; 而较短的指令长度可以使得编译生成的可执行程序更小。为了在具有长指令高性能的同时具有短指令的高代码密度,现代的RISC处理器开始采用两种或者两种以上不同长度指令混合编码的指令集。例如,ARM的thumb2指令集和中天微公司的cskyV2指令集都是16位与32位指令混合编码的指令集(以下简称“混编指令集”)。在混编指令集中,短指令相比长指令而言,寻址的操作数个数少,可编码的立即数范围小,或者单个地址只可使用部分寄存器。例如,在cskyV2指令集中,长指令可使用 R(TR31全部共32个通用寄存器,而绝大多数短指令只可使用R(TR15共16个通用寄存器; 长指令一般具有3操作数,而短指令最多只有2操作数。短指令在功能上是长指令的一个子集。通常,编译器按照长指令的功能来生成汇编指令,而汇编器生成机器指令时,会根据指令的类型和其操作数来决定生成长指令还是短指令。以cskyv2为例,如果一条指令的某个寄存器操作数被分配了 R16 R31的寄存器,那么该指令将生成一条长指令(个别指令除外,下外将介绍);但一条指令即使只使用 R(TR15的寄存器,它也并不一定生成短指令,因为它可能使用了超出短指令可编码范围的立即数,或者使用了 3个不同的操作数等等。以cskyV2为例,如果一条指令的某个寄存器操作数被分配了 R16 R31的寄存器,那么该指令将生成一条长指令(个别指令除外,下外将介绍);但一条指令即使只使用R(TR15的寄存器,它也并不一定生成短指令,因为它可能使用了超出短指令可编码范围的立即数,或者使用了 3个不同的操作数,等等。如果一条指令最终生成的机器指令是长指令还是短指令取决于其分配到的寄存器(以下简称A类指令); 反之,如果不论其寄存器操作数分配到哪个寄存器,其必然生成一条长指令,或者必然生成一条短指令(以下简称B类指令)。如何以较小的代价使得所有的A类指令最终生成的机器指令为短指令,是技术人员需要克服的难点。

发明内容
针对上述技术难点,本发明的提出一种针对混合长度指令集的寄存器分配方法。为了解决上述技术问题,本发明的技术方案如下
一种针对混合长度指令集的寄存器分配方法,包括如下步骤 1)查找函数中的所有生命周期,通过设置标志位是否置位来判断设该生命期为A类生命期还是B类生命期;2)执行图着色寄存器分配方法的Renumber^build^ coalesce^ spill Cost1、和 Simplify1五个过程,为所有A类生命期分配lo-regs寄存器,得到未进行任何溢出操作的冲突图G1;
3)计算空闲lo-regs寄存器数m,如果所述冲突图G1非空,则空闲lo-regs寄存器数 m为0,如果所述冲突图G1为空图,则执行图着色寄存器分配方法的Select1过程,并根据生成的寄存器分配方案计算空闲的lo-regs寄存器数m,并记录空闲寄存器信息;
4)执行图着色寄存器分配方法的Renumber2、build2、coalesce^ Simplify2、spill Code2和Select2过程,为B类生命期分配hi-regs寄存器和m个空闲的lo-regs寄存器, 并根据生成的分配方案计算空闲的hi-regs寄存器数量n,并记录空闲寄存器信息;
5)执行图着色寄存器分配方法的spillCode1和Select1过程,如果Select1过程已
经在
步骤3)执行,则步骤结束,如果没有,重复执行spill Code1、Renumber1, build^ coalesce^ spill Cost1, Simplify1过程直到所述冲突图G1为空,然后执行Select1过程为A类生命期生成寄存器分配方案;
Renumber” build” coalesce” spill cost” Simplify1 、 spill Code1 、 select” Renumber2λ build2、coalesce” spill cost2、Simplify2、spill code2 和 Select2 过禾呈均为图着色寄存器分配方法的步骤;
所述图着色寄存器分配方法包括如下步骤
11)Renumber 在数据流分析的基础上,找到函数中的所有生命期,并为其分配唯一的编号,其中一个生命期从一个变量的一次定值开始,到对该值的最后一次使用结束;
12)build:建立冲突图G,所述冲突图G中的结点为生命期,边则表示通过其相连的两个生命期有冲突,不能为它们分配同一个寄存器;
13)coalesce判断是否需要合并生命期,如需要则通过合并生命期删除不必要的复制语句,合并后返回,重新执行步骤12),如不需要合并,则执行步骤14);
14)spill cost 计算每个生命期的溢出代价;
15)simplify对所述冲突图G进行简化,反复地检查图G,删除G中度数小于可用寄存器数k的节点,删除的同时将该节点压入栈s ;
16)spillcode 当所述冲突图G中所有节点的度都大于等于k时,需要将溢出代价最小的生命期溢出,即删除其节点,将其压入栈s,并将其标记为溢出,溢出一个生命期之后返回执行步骤11);
17)select当所述冲突图G为空时,将栈s中的生命期弹出,为其分配寄存器,并为标记为溢出的生命期插入溢出代码;
所述lo-regs寄存器为短指令可寻址的寄存器,剩下的为所述hi-regs寄存器,所述标志位是否置位的标准为将有A类指令引用的生命期设为置位,将只有B类指令引用的生命期设为不置位;
所述A类指令为一条指令最终生成的机器指令是长指令还是短指令取决于其分配到的寄存器;
所述B类指令为不论其寄存器操作数分配到哪个寄存器,其必然生成一条长指令,或者必然生成一条短指令。
进一步的,所述标志位设于记录生命期信息的结构体中。进一步的,所述步骤5)中spill Code1的过程包括如下步骤
31)在构造所述冲突图G1保存一个所述冲突图G1的备份冲突图Gfbackup;
32)每次Simplify1决定溢出某个生命期1时,首先判断是否有空闲的hi-regs寄存器可用于溢出,如果有,那么在1的每次赋值后和使用前插入move指令,并记录生命期1溢出到hi-regs寄存器的信息;并且当每个hi-regs寄存器都已经有关联的溢出生命期时,根据所述备份冲突图Gfbackup判断是否有寄存器关联的所有溢出生命期都不与当前要溢出的生命期1冲突,如果有这样的寄存器,那么它可用于1的溢出,如果没有空闲的hi-regs 用于溢出,那么spill Code1使用load/store指令将生命期溢出到存储器。本发明的有益效果在于适用于具有两种或两种以上不同长度指令,并且其中较短指令可访问寄存器的集合为较长指令可访问寄存器的集合的子集的指令集,本发明可提高生成代码的指令密度,并且简单实用,可靠性强,最终以较小的代价使得所有的A类指令最终生成的机器指令为短指令。


图1为图着色寄存器分配方法的基本流程图; 图2为本发明的具体实施流程图3为标记生命期类型流程图; 图4为spill Code1流程图; 图5为备份的冲突图的部分图。
具体实施例方式下面将结合附图和具体实施方式
对本发明做进一步的说明。本发明是一种在图着色寄存器分配法基础上进行改进的寄存器分配方法。图着色是传统的,也是最为常用的寄存器分配方法,其基本流程如图1所示,各阶段的简要说明如下重命名(Renumber)在本阶段之前,中间代码可以引用数目无限的“虚拟寄存器”。本阶段在数据流分析的基础上,找到函数中的所有生命期,并为其分配唯一的编号。一个生命期从一个变量的一次定值开始,到对该值的最后一次使用结束。构造冲突图(Build)本阶段建立“冲突图G”,G中的结点为生命期,边则表示通过其相连的两个生命期有冲突,即它们在某条指令处同时活跃,故不能为它们分配同一个
寄存器。合并生命期(Coalesce)本阶段通过合并生命期来删除不必要的复制语句。合并生命期改变了冲突图,故合并之后需要重新执行“Build”过程。溢出代价分析(Spill cost)本阶段用于计算每个生命期的溢出代价。简化冲突图(Simplify)本阶段中对冲突图G进行简化,反复地检查图G,删除G 中度数小于可用寄存器数k的节点,删除的同时将该节点压入栈S。插入溢出代码(Spill code):当图G中所有节点的度都大于等于k时, “Simplify”过程无法继续。此时,需要将溢出代价最小的生命期溢出,即删除其节点,将其压入栈s,并将其标记为溢出。溢出一个生命期之后需要从“重命名”阶段重新开始执行图着色算法。着色(Select)图G最终会被简化为一个空图,此时将栈s中的生命期弹出,为其分配寄存器,并为标记为溢出的生命期插入溢出代码。首先将寄存器进行分类,其中大多数短指令可寻址的寄存器称为lo-regs,而其余的寄存器称为hi-regs。然后为每个生命期增加一个标志位,标记其是否曾被A类指令引用,将只有B类指令引用的生命期称为“B类生命期”;而将有A类指令引用的生命期称为“A 类生命期”,并通过扫描整个函数的指令流为每个生命期设置该标记。接着执行 两个图着色过程,为A类生命期分配lo-regs,为B类生命期分配 hi-regs ;如果lo-regs、hi-regs分别足够A类生命期、B类生命期使用,或者两个图着色过程寄存器都不足,都需要溢出生命期,那么这两个图着色过程独立进行。如果lo-regs足够A类生命期分配且有空闲,但hi-regs不够B类生命期分配,那么将lo-regs中空闲的寄存器和hi-regs寄存器一起分配给B类生命期。反之,如果hi-regs有空闲而lo-regs不足,那么在lo-regs分配过程中生成溢出代码时,优先将生命期溢出到空闲的hi-regs,当无hi-regs寄存器可进行溢出时才溢出到存储器。本方法的具体实现流程如图2所示,具体步骤如下
一、生命期标记。本阶段查找函数中的所有生命期;并通过扫描当前函数的所有指令对每个生命期的类型进行标记。^,Renumber^build^coalesce^spill Cost1、禾口 simplify^
算法流程中的前5个阶段,为所有A类生命期分配lo-regs寄存器。本步骤执行结束后,将得到未进行任何溢出操作的冲突图Α。三、计算空闲lo-regs寄存器数。本步骤计算空闲的lo-regs寄存器数m,如果G1 非空,那么m为0 ;反之,如果G1为空图,那么我们执行Select1过程,并根据生成的寄存器分配方案计算空闲的lo-regs寄存器数,并记录空闲寄存器信息。四、Renumber2λ build2、coalesce” spill cost2、Simplify2、spill code2 禾口 selects本步骤是一个完整的传统图着色寄存器分配过程。我们使用这一过程为B类生命期分配hi-regs寄存器和m个空闲的lo-regs寄存器。并根据生成的分配方案计算空闲的hi-regs寄存器数量n,并记录空闲寄存器信息。五、spill Code1和Select1。如果G1为空,那么Select1已在步骤三中执行,整
;^PJ,ΜΜ Α^fT spill Code1 、 Renumber1^ build^ coalesce^ spill Cost1^ Simplify1过程,直到G1为空,然后Select1为A类生命期生成寄存器分配方案。本步骤的特殊之处在于,如果n>0,那么在执行插入spill Code1时,我们优先将生命期溢出到空闲的 hi-regs寄存器,只有当无hi-regs寄存器可用时,才将生命期溢出到存储器。这样做的优点在于使用move指令生成的将生命期溢出到空闲的hi-regs寄存器的代码,其执行速度一般要快于使用load/store执行生成的将生命期溢出到存储器的代码。另外,混编指令集通常提供特殊的短指令——move,它是一条短指令,但可以寻址所有的寄存器。此时,使用move指令生成的将生命期溢出到空闲hi-regs寄存器的代码相比溢出到存储器将更加高效(使用了短指令进行溢出,而不是通常的长指令)。本方法只需要在传统的图着色寄存器分配方法上进行少量的修改,即可充分利用混编指令集的特点,生成代码密度更高的代码,具有简单实用,可靠性强的特点。
下面结合具体实例进行更加详细的说明
首先,在记录生命期信息的结构体中增加一个标志位flag_sh0rt,如果该标志位置位, 则说明该生命期是一个A类生命期,否则其为一个B类生命期。在“生命期识别”过程结束后,增加一个“标记生命期类型”的过程,如图3所示。该过程通过依次扫描当前函数中的每一条指令,为每一个生命期设置flag_Short标志。然后,需要执行两个图着色过程。其中Select1为所有A类生命期分配lo-regs 寄存器;Select2为所有B类生命期分配hi-regs寄存器以及可能的空闲lo-regs寄存器。 并且Select2可能在Select1完成之后执行,也可能在selectl的第一次简化冲突图G1过程后执行,如图2所示。这取决于lo-regs是否足够A类生命期分配,如果足够使用,那么 Select1首先执行完毕,这样剩余的空闲lo-regs能够提供给Select2阶段进行分配;否则, Select1在执行第一次Simplify1过程后,执行整个Select2流程,这样如果Select2过程有空闲的hi-regs的话,它们可以用于Select1的插入spill Code1阶段。总之,我们使用了 selects Select2两个图着色过程,其中Select1为所有flag_short为true的生命期分配 lo-regs寄存器;Select2为所有flag_Short为false的生命期分配hi-regs寄存器和可能的空闲lo-regs寄存器。这两个图着色过程中,本发明只需要在传统的图着色算法中增加一个对生命期的flag_short标志的判断,使select^ Select2分别处理flag_short为 true、false的生命期,并简单的重新组织select^ Select2的执行流程即可。最后,本发明还可以修改传统图着色算法的溢出过程插入spill Code1,其流程如图4所示。首先,在执行构造冲突图G1过程时,需要保存一个备份的冲突图^-!^沙叩;然后在每次简化冲突图G1决定溢出某个生命期1时,首先判断是否有空闲的hi-regs可用于溢出,如果有,那么在1的每次赋值后和使用前插入move指令,并记录生命期1溢出到 hi-regs的信息。需要注意的是,当每个hi-regs都已经有关联的溢出生命期时,并不意味着没有hi-regs可用于溢出;这时,需要根据Gfbackup判断是否有某个寄存器,其关联的所有溢出生命期都不与当前要溢出的生命期1冲突,如果有这样的寄存器,那么它可用于1 的溢出。如果没有空闲的hi-regs用于溢出,那么spill Code1执行与传统图着色算法同样的过程,即使用load/store指令将生命期溢出到存储器。以下是一个溢出到寄存器的例子,首先给出在构造冲突图G1执行结束后备份的 Gi-backup,如下图所示(为了简化说明,示意图中只包括4个生命期,可以认为是冲突图的一小部分)
权利要求
1. 一种针对混合长度指令集的寄存器分配方法,其特征在于,包括如下步骤1)查找函数中的所有生命周期,通过设置标志位是否置位来判断设该生命期为A类生命期还是B类生命期;2)执行图着色寄存器分配方法的Renumber^build^ coalesce^ spill Cost1、和 Simplify1五个过程,为所有A类生命期分配lo-regs寄存器,得到未进行任何溢出操作的冲突图G1;3)计算空闲lo-regs寄存器数m,如果所述冲突图G1非空,则空闲lo-regs寄存器数m 为0,如果所述冲突图G1为空图,则执行图着色寄存器分配方法的Select1过程,并根据生成的寄存器分配方案计算空闲的lo-regs寄存器数m,并记录空闲寄存器信息;4)执行图着色寄存器分配方法的Renumber2、build2、coalesce^ Simplify2、spill Code2和Select2过程,为B类生命期分配hi-regs寄存器和m个空闲的lo-regs寄存器, 并根据生成的分配方案计算空闲的hi-regs寄存器数量n,并记录空闲寄存器信息;5)执行图着色寄存器分配方法的spillCode1和Select1过程,如果Select1过程已经在步骤3)执行则结束所有步骤,如果没有,则重复执行spill Code1、Renumber1, build^ coalesce^ spill Cost1, Simplify1过程直到所述冲突图G1为空,然后执行Select1过程为A类生命期生成寄存器分配方案;Renumber” build” coalesce” spill cost” Simplify1 、 spill Code1 、 select” Renumber2λ build2、coalesce” spill cost2、Simplify2、spill code2 和 Select2 过禾呈均为图着色寄存器分配方法的步骤;所述图着色寄存器分配方法包括如下步骤11)Renumber 在数据流分析的基础上,找到函数中的所有生命期,并为其分配唯一的编号,其中一个生命期从一个变量的一次定值开始,到对该值的最后一次使用结束;12)build:建立冲突图G,所述冲突图G中的结点为生命期,边则表示通过其相连的两个生命期有冲突,不能为它们分配同一个寄存器;13)coalesce判断是否需要合并生命期,如需要则通过合并生命期删除不必要的复制语句,合并后返回,重新执行步骤12),如不需要合并,则执行步骤14);14)spill cost 计算每个生命期的溢出代价;15)simplify对所述冲突图G进行简化,反复地检查图G,删除G中度数小于可用寄存器数k的节点,删除的同时将该节点压入栈s ;16)spillcode 当所述冲突图G中所有节点的度都大于等于k时,需要将溢出代价最小的生命期溢出,即删除其节点,将其压入栈s,并将其标记为溢出,溢出一个生命期之后返回执行步骤11);17)select:当所述冲突图G为空时,将栈s中的生命期弹出,为其分配寄存器,并为标记为溢出的生命期插入溢出代码;所述lo-regs寄存器为短指令可寻址的寄存器,剩下的为所述hi-regs寄存器,所述标志位是否置位的标准为将有A类指令引用的生命期设为置位,将只有B类指令引用的生命期设为不置位;所述A类指令为一条指令最终生成的机器指令是长指令还是短指令取决于其分配到的寄存器;所述B类指令为不论其寄存器操作数分配到哪个寄存器,其必然生成一条长指令,或者必然生成一条短指令。
2.根据权利要求1所述的一种针对混合长度指令集的寄存器分配方法,其特征在于, 所述标志位设于记录生命期信息的结构体中。
3.根据权利要求1所述的一种针对混合长度指令集的寄存器分配方法,其特征在于, 所述步骤5)中spill Code1的过程包括如下步骤31)在构造所述冲突图G1保存一个所述冲突图G1的备份冲突图Gfbackup;32)每次Simplify1决定溢出某个生命期1时,首先判断是否有空闲的hi-regs寄存器可用于溢出,如果有,那么在1的每次赋值后和使用前插入move指令,并记录生命期1溢出到hi-regs寄存器的信息;并且当每个hi-regs寄存器都已经有关联的溢出生命期时,根据所述备份冲突图Gfbackup判断是否有寄存器关联的所有溢出生命期都不与当前要溢出的生命期1冲突,如果有这样的寄存器,那么它可用于1的溢出,如果没有空闲的hi-regs 用于溢出,那么spill Code1使用load/store指令将生命期溢出到存储器。
全文摘要
本发明公开了一种针对混合长度指令集的寄存器分配方法,通过对传统的图着色寄存器分配方法上进行少量的修改,即可充分利用混编指令集的特点,生成代码密度更高的代码,具有简单实用,可靠性强的特点。
文档编号G06F9/30GK102360280SQ201110333460
公开日2012年2月22日 申请日期2011年10月28日 优先权日2011年10月28日
发明者吴健, 吴朝晖, 尹建伟, 李莹, 邓水光, 闫卫斌 申请人:浙江大学
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1