Hexagon处理器的条件执行机制

来源:互联网 发布:c 递归算法 全排列 编辑:程序博客网 时间:2024/06/16 01:24

概述
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 trueif (!P2) R2 = R5               // assign register if !P2 is trueif (P1) R0 = sub(R2,R3) // conditionally subtract if P1if (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 trueR1: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:2R2 = #0P0 = vcmpb.eq(R1:0,R3:2) // compare bytes in A to zeroR5: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]
0 0