概述
概述
Hexagon处理器基于比较指令在四个预测寄存器(P0-P3)中设置预测位来实现条件执行模型。这些预测位可以用来有条件的执行某些指令。
条件标量操作只可以对预测寄存器的最后一位进行操作,条件矢量操作则可以操作寄存器的多个位。
这些预测寄存器主要用于分支预测的控制。
标量预测
标量预测是一个八位的值,该值在条件指令中表示两种真值:
0xff表示为真
0x00表示假
Hexagon处理器提供了P0-P3四个八位的预测寄存器来控制矢量预测。这些寄存器通过预测驱动指令来设置,通过预测消费指令进行查看。
驱动标量预测
如下的指令可以驱动标量预测:
比较字节、半字、字、双字
比较单精度、双精度的浮点数
分类浮点值
比较比特掩码
边界检测
TLB匹配
保存条件
下图列出了预测驱动指令
比较指令(cmp..eq)包括了一个变量,这个变量保存了一个存储在通用寄存器中的二进制值。
使用标量检测
基于标量预测,CPU可以判断条件从而执行正确的指令,或者有选择的将某个标量预测作为输入或输出。
使用标量预测值的条件指令只能查看预测值的最低一位。在最简单的情况下,该比特位将直接决定CPU将要执行的指令:
1 表明该指令可以被执行
0 表明该指令不能执行
如果条件指令在预测表达式中包括了操作!,那么比特值的逻辑取反将会作为预测的判断值。
条件指令在汇编指令中用指令前缀“if(pred_expr)”来表示,pred_expr表示预测表达式,例如:
if (P0) jump target
// jump if P0 is true
if (!P2) R2 = R5
// assign register if !P2 is true
if (P1) R0 = sub(R2,R3) // conditionally subtract if P1
if (P2) R0 = memw(R2) // conditionally load word if P2
如下指令可以被用来做条件指令:
跳转指令(jump)与调用指令(call)
大部分的load和store指令
逻辑指令如AND/OR/XOR
32位寄存器或立即数的加/减
半字的移位
寄存器的立即转移
当条件load或者store指令被执行,或是预测表达式为false时,指令会被取消(包括指令可能带来的错误)。例如如果条件load使用了一个违反内存权限的操作,那么预测指令会被判定为假,那么load指令不会被执行而异常也不会被取出。
Rd = Mux(Ps, Rs ,Rt)
mux根据Ps位中的最后一位决定选择Rs或Rt。如果Ps的最后一位是1,那么Rd被设置为Rs,否则的话被设置为Rt。
Auto-AND预测
如果一个包中的多个比较指令写入相同的预测寄存器,结果等于比较结果的逻辑与。例如:
{
P0 = cmp(A)
// if A && B then jump
P0 = cmp(B)
if (P0.new) jump:T taken_path
}
为了实现响应的或操作,如下的指令可以被用来计算已有比较的取反(德•摩根定律)也就是:
非(P 且 Q)=(非 P)或(非 Q)
非(P 或 Q)=(非 P)且(非 Q)
Pd
=
!cmp.{eq,gt}(Rs, {#s10,Rt} )
n Pd
=
!cmp.gtu(Rs, {#u9,Rt} )
n Pd
=
!tstbit(Rs, {#u5,Rt} )
n Pd
=
!bitsclr(Rs, {#u6,Rt} )
n Pd
=
!bitsset(Rs,Rt)
Auto-AND预测有如下的限制:
如果包中包含了endloopN, 它不能在寄存器P3上实现一个自动与功能
转移到预测寄存器上的包不能被收入到另一个预测驱动指令中
指令decbin、tlbmatch,memw_locked以及memd_locked不能与另一个设置为相同预测寄存器的指令包含。
Dot-new预测
Hexagon处理器可以在同一个指令包中驱动并使用标量预测。这一特性通过在汇编语言中为寄存器添加.new前缀实现。例如:
if (P0.new) R3 = memw(R4)
为了展示dot-new指令是如何实现的,可以看看如下的C表达式以及相应的编译器汇编指令:
C statement
if (R2 == 4)
R3 = *R4;
else
R5 = 5;
Assembly code
{
P0 = cmp.eq(R2,#4)
if (P0.new) R3 = memw(R4)
if (!P0.new) R5 = #5
}
在汇编指令中,一个标量寄存器被驱动并在同一个指令包中调用两次
如下的条件可以适用于dot-new预测:
预测必须通过相同包中的指令来驱动。汇编器通常会强制这种限制,但如果处理器执行了一个违反该规定的指令,那么执行的结果将是不可预测的。
单个包可以同时包含dot-new以及普通的预测。普通预测将会检验预测寄存器中的旧值而不是新驱动的值。例如:
{
P0 = cmp.eq(R2,#4)
if (P0.new) R3 = memw(R4) // use newly-generated P0 value
if (P0) R5 = #5 // use previous P0 value
}
依赖限制
一个指令包中的指令不应该同时写同一个目标寄存器。对这种规则的特例是如果这两个指令是有条件,那么只有两个指令中的一个应该被允许执行并被设置为真。
例如,如下的包是有效的,P2以及P3寄存器不会被同时采用。
{
if (P2) R3 = #4 // P2, P3, or both must be false
if (P3) R3 = #7
}
因为预测值在运行时总是会改变,程序员又不要保证每个包在程序执行时总是有效的。如果程序变得无效,处理器将会执行如下动作:
当写目标为通用寄存器时,将会提出一个错误异常
当写目标为预测或控制寄存器时,结果是无法预测的
矢量比较
一个矢量比较操作将输入两个64位的实例,为每个矢量元素执行隔离的比较操作,并产生一个包含了一位真值的位矢量。
下图显示了矢量字节比较的案例:
矢量多指令
矢量多指令通常用于有条件的为两个矢量选择元素。该指令选择两个源矢量以及一个预测寄存器作为输入。对于矢量中的每个字节,预测寄存器中的位相应为被用来从输入矢量中选择。最终汇总的结果被写入到目标寄存器中。
矢量多指令
在mux指令中改变源操作的顺序可以使两个结果都能形成,例如:
R1:0 = vmux(P0,R3:2,R5:4) // choose bytes from R3:2 if true
R1:0 = vmux(P0,R5:4,R3:2) // choose bytes from R3:2 if false
矢量条件
矢量条件支持在条件语句中被用来矢量化循环
考虑如下的C表达式:
for (i=0; i<8; i++) {
if (A[i]) {
B[i] = C[i];
}
}
假设数列为字节,那么代码可以被矢量化如下:
R1:0 = memd(R_A) // R1:0 holds A[7]-A[0]
R3 = #0 // clear R3:2
R2 = #0
P0 = vcmpb.eq(R1:0,R3:2) // compare bytes in A to zero
R5:4 = memd(R_B) // R5:4 holds B[7]-B[0]
R7:6 = memd(R_C) // R7:6 holds C[7]-C[0]
R3:2 = vmux(P0,R7:6,R5:4) // if (A[i]) B[i]=C[i]
memd(R_B) = R3:2 // store B[7]-B[0]
最后
以上就是欣喜小馒头为你收集整理的Hexagon处理器的条件执行机制的全部内容,希望文章能够帮你解决Hexagon处理器的条件执行机制所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复