Hexagon处理器支持如下的程序流程机制
软件分支包括了跳转(jump),调用(call)以及返回(return)。Hexagon一共支持四种不同的跳转(jump):
很多Hexagon内部的处理器可以被选择性的执行。例如:
if (P0) R0 = memw(R2) // conditionally loadword if P0 if (!P1) jump label // conditionally jumpif not P1
更多的指令可以去看我的文章
Hexagon处理器包括了硬件循环指令。硬件循环指令可以实现循环分支,例如:
loop0(start,#3) // loop 3 times start: { R0 = mpyi(R0,R0) } :endloop0
loop0和loop1提供了两系列的循环指令,两个循环可以将硬件循环形成一级嵌套。例如:
// Sum the rows of a 100x200 matrix. loop1(outer_start,#100) outer_start: R0 = #0 loop0(inner_start,#200) inner_start: R3 = memw(R1++#4) { R0 = add(R0,R3) }:endloop0 { memw(R2++#4) = R0 }:endloop1
硬件指令主要的应用场景如下:
每个硬件循环与一对特定的循环寄存器相关:
硬件循环设置指令可以一次性设置两个寄存器的值,既然如此我们就没必要分开两次来设置他们。但是,因为循环寄存器需要单独的设置循环状态,他的值可以被保存并且存储(既可以通过中断也可以通过软件执行),这使得循环寄存器可以被重新导入并正常继续。
Hexagon处理器为两个硬件循环提供了两列循环寄存器:
下图列出了硬件循环的指令:
为了设置一个硬件循环,循环寄存器SAn与LCn必须被设置为相应的值。我们可以通过两种方法来实现:
一个loopN指令
向SAn以及LCn的寄存器转移指令
loopN指令可实现所有设置SAn和LCn的工作。例如:
loop0(start,#3) // SA0=&start, LC0=3 start: { R0 = mpyi(R0,R0) } :endloop0
在这个案例中,硬件循环被执行了三次。loop0指令设置寄存器SA0的职位start的地址,设置LC0为3.
如果将循环数设置为立即数,则循环数的范围为0-1023。如果期望的循环次数比这个值大,那么我们必须用寄存器的值来定义它。例如:
使用loopN
R0 = #20000; loop0(start,R0) // LC0=20000, SA0=&start start: { R0 = mpyi(R0,R0) } :endloop0
使用寄存器转移:
R0 = #20000 LC0 = R0 // LC0=20000 R0 = #start SA0 = R0 // SA0=&start start: { R0 = mpyi(R0,R0) } :endloop0
如果一个loopN指令与他的循环开始地址距离太远,那么程序寄存器相对移位的值也许会超出指令起始操作数的最大范围。在这种情况下,要么把loopN的指令搬到离地址更近的地方,要么以一个32位的常数值来定义。例如:
R0 = #20000; loop0(##start,R0) // LC0=20000, SA0=&start ...
嵌套硬件循环可以将同样的指令指定为内部或外部循环的终止。例如:
// Sum the rows of a 100x200 matrix. // Software pipeline the outer loop. p0 = cmp.gt(R0,R0) // p0 = false loop1(outer_start,#100) outer_start: { if (p0) memw(R2++#4) = R0 p0 = cmp.eq(R0,R0) // p0 = true R0 = #0 loop0(inner_start,#200) } inner_start: R3 = memw(R1++#4) { R0 = add(R0,R3) }:endloop0:endloop1 memw(R2++#4) = R0
虽然endloopN表现的像一个常用的指令,但请注意他不会在任何堆中执行,并且不会在指令包中计数。因此一个单一指令包可以实现超过六个指令,其中包括:
l 四个常规指令
l endloop0指令
l endloop1指令
当我们为Hexagon DSP设置好硬件循环后,循环主体最起码会被执行一次,无论是否定义了循环次数(因为循环次数在执行后才会被检测)。因此,如果一个循环需要选择性的执行0次,那么必须用一个特殊而清晰的条件分支来定义,例如:
loop0(start,R1) P0 = cmp.eq(R1,#0) if (P0) jump skip start: { R1 = add(R1,#1) } :endloop0 skip:
在这个案例中,我们在R1寄存器中设置好了一个硬件循环,但是如果R1中的值为1,那么软件分支会直接跳过这个循环主体。
循环结束指令后,Hexagon处理器将检查相应的循环技术寄存器中的值:
l 如果值大于1,那么处理器将循环计数的值建议并实现一个跳转至start地址
l 如果值小于1,那么处理器将会立即继续程序的执行。
l loopN中的循环设置指令包不能包含间接跳转,新值比较跳转或者dealloc_return指令
l 循环中的最后一个包不能包括任何程序流程指令(包括跳转和调用)
l loop0中的循环终止包不能包含任何改变寄存器SA0或LC0的指令。同样的,loop1中的循环终止包不包含任何改变寄存器SA1或LC1的指令。
l spNloop0的循环终止包不能包含任何改变P3寄存器的指令