介绍 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 类运算。
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 运算指令。
这类指令做的运算是:
| 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 表示 low,h 表示 high
我们来看看什么是 saturation 的结果,什么是 non-saturation 结果,在 SIMD 系列指令中,在进行 packed integer 的运算中结果有可能会产生 overflow(溢出)的情况。
下面的例子在一个 packed integer 为 word 宽度的运算中,当 7000H + 2000H 的结果是多少呢?
|
7000 (正数) |
没错结果等于 9000H,然而这个结果 overflow(溢出)了:两个正数相加结果为负数! 在 SIMD 系列指令中对这类结果的处理为分 saturation 和 non-saturation,non-saturation 是不进行任何处理,结果值直接写入目标操作数,这个结果值往往不是我们想要的结果,在这种情况下,我们并不知道结果值是否 overflow 了。
因此有另一个处理手法,是 saturation 处理,当发生溢出的时候,结果值会被限定为一个最大值(也就是饱和值),规则是:
这表明 saturation 的结果是 limit 值,如果是 byte 宽度的数据,则 saturation 结果被限定为 7Fh 和 80h,需要明白的是,正数和负数相加是不可能发生溢出情况的。
同样在一个 unsigned integer 运算中也可能会产生 overflow 情况,saturation 处理手法同样被使用在 unsigned integer 的 SIMD 数据中,以 word 宽度为例,规则是:
例如:FF00h + C000h = 1BF00h 这个结果产生了 overflow 情况,那么 saturation 结果就是 FFFFh
总结 saturation 处理手法的结果就是可以让我们知道,这个结果溢出了。在 non-saturation 结果中,我们可能并不能保证计算的结果是否正确。从上面的表格我们知道 XOP 指令集中提供了 saturation 处理和 non-saturation 处理的两类运算指令。
这类指令提供的操作如下面的示意:
|
short a[8], b[8]; /* word */ |
这类指令只有 2 条:
同样分为 saturation 和 non-saturation 版本,multiply-add 是 word 宽度,最后 accumulate 是 double word 宽度。
这类指令做的运算是:
|
short a[8]; /* word */ |
这类指令提供了如下表格:

其中包括了 signed 和 unsigned integer,分为 add 和 subtract 运算。
这类指令共有两条:
这两条指令都有 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[1] = selector[1] ? src1[1] : src2[1]; |
目标操作数的每 1 bit 根据 selector 相应的 bit 来进行选择,当 = 1 时从 src1 相应的位送到 dest,当 = 0 时,从 src2 相应的位送到 dest
这条指令以 byte 为单位进行传递,它的操作如下示意:
|
char dest[16], src1[16], src2[16], selector[16]; /* xmm or mem128 */ /****** select from src1 to dest *******/ case 0x00: dest[0] = src1[0]; break; /***** select from src2 to dest ********/ case 0x10: dest[0] = src2[0]; break; switch (selector[15] & 0x1F) |
selector 除了 [4:0] 之外,还有 [7:5] 控制着 move 的方式。