5. XOP 指令集架构简介


介绍 XOP 指令集之前应该要先了解一下 SSE5 指令集的情况,AMD 在 2007 年发布 SSE5 指令集规范,SSE5 指令集是原生 128 位设计,而 AVX 指令采用的是 256 位原生设计,AVX 的规格功强更强大。SSE5 指令最大的特色是支持 4 个操作数。并且引进了 multiply-add/subtract(融合了乘加减)类运算。

SSE5 提供的功能总结为:

由于是 128 位设计,SSE5 指令最使用的操作数是 128 位 xmm 寄存器,事实上 XOP 指令集和 FMA 指令集(包括 FMA3 和 FMA4)都取材自 SSE5 指令集,XOP 继承了 SSE5 的整数指令,而 FMA 继承了 floating point multiply-add/subtract 类运算。

5.1 XOP 指令集功能

SSE5 指令集已经被宣布废止了,AMD 推出 XOP 和 FMA4 来取代 SSE5,并且继承了 SSE5 的绝大部分功能,虽然 XOP 也被扩展为 256 位设计,可是大部分指令依旧是使用 128 位的操作数,256 位操作数的指令为数不多,所以 XOP 最大的改进和特色是:

XOP 废除了 SSE5 沿用多年的 SIMD 指令编码方式(SIMD prefix + escape opcode + opcode),引用了 XOP prefix 来设计指令编码,XOP prefix 与 AVX 的 VEX prefix 起相同的作用。

XOP 指令集提供的功能总结为:

可以看出 XOP 继承了大部分 SSE5 指令功能,提供了整数操作指令和少量的浮点操作指令。而另一个分支: FMA 指令(包括 Intel 的 FMA3 和 AMD 的 FMA4)提供了浮点的 mulitply-add/subtract 运算指令。

5.1.1 integer multiply and add(accumulate) 指令

这类指令做的运算是:

d = a * b + c

它们支持 4 个操作数,这类指令如下图的表格所示:

上面这些指令操作的都是 singed integer (符号数),分为 saturation non-saturation 两类,指令的 mnemonic(助记符)设定都有特定的规律,下面描述为:

v  p  m  ac  s  s  w  w
   -  -  --  -  -  -  -
   |  |   |  |  |  |  |
   +--+---+--+--+--+--+--------->  packed
      |   |  |  |  |  |
      +---+--+--+--+--+--------->  multiply
          |  |  |  |  |
          +--+--+--+--+--------->  accumulate
             |  |  |  |
             +--+--+--+--------->  singned
                |  |  |
                +--+--+--------->  saturation
                   |  |
                   +--+--------->  word (to)
                      |
                      +--------->  word (from)

上面是指令 vpmacssww 的 mnemonic 格式描述说明,上表中 mnemonic 还有 l 表示 lowh 表示 high

5.1.2 saturation(饱和)的结果值

我们来看看什么是 saturation 的结果,什么是 non-saturation 结果,在 SIMD 系列指令中,在进行 packed integer 的运算中结果有可能会产生 overflow(溢出)的情况。

下面的例子在一个 packed integer 为 word 宽度的运算中,当 7000H + 2000H 的结果是多少呢?

      7000       (正数)
+     2000       (正数)
-------------
      9000       (负数)

没错结果等于 9000H,然而这个结果 overflow(溢出)了:两个正数相加结果为负数! 在 SIMD 系列指令中对这类结果的处理为分 saturationnon-saturation,non-saturation 是不进行任何处理,结果值直接写入目标操作数,这个结果值往往不是我们想要的结果,在这种情况下,我们并不知道结果值是否 overflow 了。

因此有另一个处理手法,是 saturation 处理,当发生溢出的时候,结果值会被限定为一个最大值(也就是饱和值),规则是:

这表明 saturation 的结果是 limit 值,如果是 byte 宽度的数据,则 saturation 结果被限定为 7Fh80h,需要明白的是,正数和负数相加是不可能发生溢出情况的。

同样在一个 unsigned integer 运算中也可能会产生 overflow 情况,saturation 处理手法同样被使用在 unsigned integer 的 SIMD 数据中,以 word 宽度为例,规则是:

例如:FF00h + C000h = 1BF00h 这个结果产生了 overflow 情况,那么 saturation 结果就是 FFFFh

总结 saturation 处理手法的结果就是可以让我们知道,这个结果溢出了。在 non-saturation 结果中,我们可能并不能保证计算的结果是否正确。从上面的表格我们知道 XOP 指令集中提供了 saturation 处理和 non-saturation 处理的两类运算指令。

5.1.3 integer multiply add and accumulate 指令

这类指令提供的操作如下面的示意:

short a[8], b[8];                      /* word */
int d[4], c[4];                        /* doube word */


d[3] = (a[7] * b[7] + a[6] * b[6]) + c[3]);
d[2] = (a[5] * b[5] + a[4] * b[4]) + c[2]);
d[1] = (a[3] * b[3] + a[2] * b[2]) + c[1]);
d[0] = (a[1] * b[1] + a[0] * b[0]) + c[0]);
        ----------    -----------    ----
          multiply      multiply      |
          ----------------------      |
                  add                 |
                                      |
                   |                  |
                   +-- accumulate ----+

这类指令只有 2 条:

同样分为 saturation 和 non-saturation 版本,multiply-add 是 word 宽度,最后 accumulate 是 double word 宽度。

5.1.4 packed integer horizontal add and subtract 指令

这类指令做的运算是:

short a[8];                            /* word */
int d[4];                              /* doube word */


d[3] = a[7] ± a[6];                   /* add or subtract */
d[2] = a[5] ± a[4];
d[1] = a[3] ± a[2];
d[0] = a[1] ± a[0];
       ------------
             |
             +------>  word add(subtract) to double word

这类指令提供了如下表格:

其中包括了 signed 和 unsigned integer,分为 add 和 subtract 运算。

5.1.5 vector conditional moves 指令

这类指令共有两条:

这两条指令都有 4 个操作数,其中第 4 个操作数(src3)是 selector

这条指令做的操作如下示意:

Bit dest[128], src1[128], src2[128], selector[128];                 /* xmm or mem128 */

dest[127] = selector[127] ? src1[127] : src2[127];
dest[126] = selector[126] ? src1[126] : src2[126];

... ...                                         

dest[1] = selector[1] ? src1[1] : src2[1];
dest[0] = selector[0] ? src1[0] : src2[0];

目标操作数的每 1 bit 根据 selector 相应的 bit 来进行选择,当 = 1 时从 src1 相应的位送到 dest,当 = 0 时,从 src2 相应的位送到 dest

这条指令以 byte 为单位进行传递,它的操作如下示意:

char dest[16], src1[16], src2[16], selector[16];         /* xmm or mem128 */


switch (selector[0] & 0x1F)                             /* bit[4:0] : 0x00 - 0x1F */
{

/****** select from src1 to dest *******/

case 0x00:      dest[0] = src1[0];     break;
case 0x01:      dest[0] = src1[1];     break;
case 0x02:      dest[0] = src1[2];     break;
case 0x03:      dest[0] = src1[3];     break;
case 0x04:      dest[0] = src1[4];     break;
case 0x05:      dest[0] = src1[5];     break;
case 0x06:      dest[0] = src1[6];     break;
case 0x07:      dest[0] = src1[7];     break;
case 0x08:      dest[0] = src1[8];     break;
case 0x09:      dest[0] = src1[9];     break;
case 0x0A:      dest[0] = src1[10];    break;
case 0x0B:      dest[0] = src1[11];    break;
case 0x0C:      dest[0] = src1[12];    break;
case 0x0D:      dest[0] = src1[13];    break;
case 0x0E:      dest[0] = src1[14];    break;
case 0x0F:      dest[0] = src1[15];    break;

/***** select from src2 to dest ********/

case 0x10:      dest[0] = src2[0];     break;
case 0x11:      dest[0] = src2[1];     break;
case 0x12:      dest[0] = src2[2];     break;
case 0x13:      dest[0] = src2[3];     break;
case 0x14:      dest[0] = src2[4];     break;
case 0x15:      dest[0] = src2[5];     break;
case 0x16:      dest[0] = src2[6];     break;
case 0x17:      dest[0] = src2[7];     break;
case 0x18:      dest[0] = src2[8];     break;
case 0x19:      dest[0] = src2[9];     break;
case 0x1A:      dest[0] = src2[10];    break;
case 0x1B:      dest[0] = src2[11];    break;
case 0x1C:      dest[0] = src2[12];    break;
case 0x1D:      dest[0] = src2[13];    break;
case 0x1E:      dest[0] = src2[14];    break;
case 0x1F:      dest[0] = src2[15];    break;
}


... ...

switch (selector[15] & 0x1F)
{
    ... ...
}

selector 除了 [4:0] 之外,还有 [7:5] 控制着 move 的方式。

 


版权所有 mik 2009-2011