1. XOP 与 FMA4 指令简介
1、 XOP 指令产生的背景
AMD 抢出推出 SSE5 指令集,但 Intel 打着如意算盘,却不跟进,推出了全新的 AVX 指令集。
AVX 借鉴了一些 SSE5 的思想,但进行了扩充改良。客观地说,AVX 比 SSE5 更优,但 SSE5 既然有 Intel 值得学习的地方,AMD 是知道的。
AMD 最终决定放弃 SSE5 指令集跟进 Intel,除发布兼容 AVX 指令集的 FMA4 指令外,另外推出一套 XOP 指令集。但是 AMD 的 FMA4 指令只是对 AVX 指令集有限支持。
XOP 指令集的产生是 AMD 也不愿 SSE5 被全盘推翻,保留了一些 SSE5 指令的优秀的地方。
2、 AMD 的 FMA4 指令与 Intel 的 AVX 指令的关系
FMA4 指令是 FMA 指令的 AMD 版本。
可以说 AMD 的 FMA4 与 Intel 的 AVX 指令(包括 Intel 的 FMA 指令)在编码方式上大同小义,差异很小。
即可说:FMA4 指令沿用 AVX 指令的编码方式,并进行一些修改与扩充。
AMD 的 FMA4 指令与 Intel 的 AVX 指令(包括 Intel 的 FMA 指令)区别就象是:AMD 的 SSE 指令与 Intel 的 SSE 指令之间的区别。
也就是说:Intel 的 AVX 中的 FMA 指令有的,AMD 的 FMA4 可能会有,可能不会有。而 AMD 有的,Intel 不会有。
3、 XOP 指令集的特点
可以说 XOP 指令集编码方案是基于 AVX 指令集的。只是有些修改。当然 XOP 指令集有自已的特点。
(1)在 XOP 指令中使用 XOP prefix 代替 VEX prefix
说白了,在 XOP 中称为 XOP prefix 而不是 VEX prefix,但并不是简单的名称不同,虽然编码方案一样,但内容差异很大。
(2)XOP prefix 固定为 3-byte,并没有 2-byte 的 XOP prefix
(3)XOP 指令的改良主要体现在 operands 的寻址上,XOP 指令的 operands 寻址更灵活强大。
4、 XOP 指令与 AVX 指令的区别
XOP 与 AVX 之间的区别就像是: AMD 的 3Dnow 指令与 Intel 的 SSE 指令之间的区别。
XOP 是 AMD 自已推出的另一套指令。这是 Intel 目前不具备的。
而 Intel 的 AVX 指令 AMD 则进行了有限的支持。
2. XOP 指令格式
上图是 XOP 指令编码格式,这和 AVX 指令编码序列是一样的,只是 XOP prefix 不同而已。
1、 legacy prefix 部分
这些是原来的 prefix,即:
• effective opernad-size override prefix:66
• effective address-size override prefix:67
• effective segment override prefix:2E、3E、26、64、65、36
• lock prefix:F0
• rep/repz prefix:F3
• repz prefix:F2
但是,和 AVX 指令情形一样,在 XOP 指令序列里,仅有 address-size override prefix 和 segment override prefix 才有效。
其它 legacy prefix 与 XOP prefix 同时出现会产生 #UD 异常。
2、 XOP prefix 部分
XOP prefix 集成了 SIMD prefix 与 REX prefix,但是在 XOP 指令中并不需要 escape prefix。
XOP prefix 固定为 3-byte 而第 1 个 byte 固定为 8F
XOP prefix 的作用为:
• 提供 registers 寻址
• 集成 REX prefix 与 escape prefix
• 对 opcode 的补充
• 指明 operands 的 size
3、 opcode 部分
除了是 XOP 指令的 opcode 部分外,还提供操作数据的 size
4、ModRM 部分
和通用指令中的 ModRM 意义一样,提供 operands 寻址
5、 SIB 部分
和通用指令中的 SIB 意义一样。提供 memory 寻址。
6、 displacement 部分
和通用指令中的 displacement 意义一样,提供 displacement 值。
7、 immediate 部分
除了提供 immediate 值外,主要的作用是提供 registers 寻址。
imme[7:4] 提供 registers 寻址。
3. XOP prefix
上面的 XOP prefix 的结构图。
XOP prefix 共有 3 bytes,其中 first byte 是 8F,记作: XOP.8F
1、XOP.8F
XOP prefix 的第 1 个字节了是 8F,在通用指令里 opcode 8F 是一组 Group opcode,仅当 ModRM.reg = 000 时,这个 opcode 才是有效的,它是 POP 指令。
ModRM.reg ≠ 000 时,这个 opcode 8F 是无效的 opcode,即:当 ModRM 值大于等于 00-001-000(08H)时, 这个 8F 是无效的 opcode
AMD 选择使用 8F 作为 XOP prefix,正是基于这个原因。
(1)XOP prefix 与 VEX prefix 的对比
VEX prefix 是 C4 或 C5,在 16 位 或 32 位下它必须保证下一个字节是以 11-**** 开头的。
XOP prefix 是 8F,则需保证下一个字节是大于等于 08H 则可
关于 VEX prefix 详见:VEX prefix
由于,这个 prefix 的取值不同,就决定了它们之间的编码差异。
2、 XOP prefix 的 byte 1 结构
域 位 描述
R [7] [XOP.R + ModRM.reg]
X [6] [XOP.X + SIB.index]
B [5] [XOP.B + SIB.base],[XOP.B + ModRM.r/m] 以及 [XOP.B + opcode.reg]
mmmmm [4:0] = 08 表示指令需要 imm8 字节
= 09 表示指令不需要 imm8 字节
XOP.RXB 与 VEX.RXB 作用一致,这一位也是反相作用。 分别用于扩展 ModRM.reg、SIB.index 以及 ModRM.r/m、SIB.base、opcode.reg
例如:当 XOP.R = 1、ModRM.reg = 000 时,register ID 值为 1000 表示 xmm0 寄存器。
XOP.mmmmm 指示 imm8 部分是否存在,另一个作用是表明 opcode 是 XOP 指令:ModRM >= 08H
有关 registers 编码反相,详见:AVX 和 XOP 指令中的 registers 编码反相
3、XOP prefix 的 byte 2 结构
域 位 描述
W [7] 在 XOP/FMA4 指令中主要作用是:对 operands 寻址进行配置
vvvv [6:3] 提供 retisters 寻址,具体是哪个 operand 依赖于 opcode
L [2] operands 长度(xmm or ymm?)
pp [1:0] 00 none
01 66
10 F3
11 F2
XOP.vvvv 提供的 registers 寻址依赖于 XOP.W 配置。
有关 XOP.vvvv 寻址,详见:operands 寻址
4、XOP.RXB 与 VEX.RXB 的差异
在 AVX 指令的 VEX prefix 中,VEX.RXB 在 legacy 模式与 long 的 compaitibility 模式下必须: VEX.RXB = 11X(以 11 开头)
而 XOP 指令的 XOP prefix 中,XOP.RXB 则在 legacy 模式与 long 的 compaitibility 模式下不必为 11 开头
前面已经说过,这是因为:opcode 8F 仅当 ModRM.reg = 000 时才有效。因此,只要大于等于 08H,就能区分通用指令与 XOP 指令。
XOP 指令以下这条指令为例:
vpmacsdd xmm0, xmm7, [eax], xmm1
它的 opcode 是 9e,在 32 位模式下,它的编码结构如下:
8f 101 01000 0 1000 0 00 9e 00 000 000 0001 0000
XOP.8F RXB mmmmm W vvvv L pp opcode mod reg r/m [7:4] [3:0]
XOP.[RXBmmmmm] = a8 XOP.[WvvvvLpp] = 40 ModRM = 00 imm8 = 10
它最终的编码为:8f a8 40 9e 00 10
5、Intel 的 FMA 指令中 VEX.W 与 AMD 的 FMA4 指令中 VEX.W 的差异
对于 W 标志位, AMD 与 Intel 存在设计理念的差异。
(1)Intel 的 FMA 指令中 VEX.W 主要作用是选择指令处理数据的不同,从而根据不同的数据产生不同的指令,例如:
vfmadd132ps xmm0, xmm1, xmm2
vfmadd132pd xmm0, xmm1, xmm2
上面是 2 个版本的指令,它们的 opcode 码是相同的
1. 第 1 条的 VEX.W = 0
2. 第 2 条的 VEX.W = 1
它们处理的数据分别是 packed single-precision float-point 数据和 packed double-precision float-point 数据
当 VEX.W = 0 是处理 packed single-precision float point 数据
当 VEX.W = 1 是处理 packed double-precision float point 数据。
(2)AMD 的 FMA4 指令中 XOP.W 主要作用对 operands 寻址进行配置,例如:
vfmaddpd xmm1, xmm2, [rax], xmm4
vfmaddpd xmm1, xmm2, xmm3, [rax]
上面是 2 个版本的 vfmaddpd 指令,它们处理的是 packed double-precision float point 数据。
1. 第 1 条的 VEX.W = 0
2. 第 2 条的 VEX.W = 1
当 XOP.W = 0 时, ModRM.r/m 提供 third operand(即:src2)寻址。
当 XOP.W = 1 时, ModRM.r/m 提供 fourth operand(即:src3)寻址。
再来看一看,下面两条 FMA4 指令:
vfmaddps xmm1, xmm2, [rax], xmm4
vfmaddps xmm1, xmm2, xmm3, [rax]
上面是 2 个版本的 vfmaddps 指令,它们处理的是 packed singled-precision float point 数据。
这两条指令和上面两条指令的 opcode 是不同的。
Intel 的设计理念是:采用相同的 opcode 码,而根据 VEX.W 的取值不同,从而达到指令处理多种数据。
AMD 的设计理念是:采用不同的 opcode 码,达到指令处理多种数据。又而根据 VEX.W 的取值不同,而达到 operand 寻址的多样性。
AMD 的设计上允许 operand 的多样性,达到真正的 4 个 operands
而 Intel 的指令不支持 4 个 operands。
这就是为什么 Intel 的是 FMA 指令,而 AMD 的是 FMA4 指令的原因。
4. FMA4/XOP 指令 opcode 描述方式
1、FMA4 指令的 opcode 描述
由于 FMA4 指令是 FMA 指令的 AMD 版本,支持 4 个操作数。
vfmaddpd xmm1, xmm2, xmm3/mem128, xmm4
上面这条指令形式,它的 opcode 描述为:
VEX RXB.mmmmm W.vvvv.L.pp Opcode
C4 RXB.03 0.xsrc1.0.01 69 /r /is4
可以很直观的看出:
1. VEX.C4
2. VEX.mmmmm = 11
3. VEX.W = 0
4. VEX.vvvv 对 src1 进行寻址
5. VEX.L = 0
6. VEX.pp = 01
7. opcode = 69
8. imm8[7:4] 提供寻址
(1)operands 寻址表
这条指令有 4 个 operands,这 4 个 operands 的寻址情况是:
ModRM.reg VEX.vvvv ModRM.r/m imm8[7:4]
提供 first operand 寻址 提供 second operand 寻址 提供 third operand 寻址 提供 fouth operand 寻址
/r:表示 destination operand(first operand)由 ModRM.reg 提供寻址。
2、XOP 指令的 opcode 描述
vphaddbd xmm1, xmm2/mem128
这是一条 XOP 指令,它的 opcode 描述为:
XOP RXB.mmmmmm W.vvvv.L.pp Opcode
8F RXB.09 0.1111.0.00 c2 /r
1. 8F:这是 XOP prefix
2. XOP.mmmmmm = 09 : 表示不需要 imm8
3. XOP.W = 0 :2 个 operands 时为 0
4. XOP.vvvv = 1111 :表示不需要 XOP.vvvv 提供寻址,它必须为 1111
5. XOP.L = 0 : 128 位
6. XOP.pp = 00 :不需要 SIMD prefix
7. opcode = c2
8. /r :ModRM.reg 提供 destination operand 寻址
(2)operands 寻址表
这条指令只有 2 个 operands,那么它的寻址就简单多了
ModRM.reg VEX.vvvv ModRM.r/m imm8[7:4]
提供 first operand 寻址 不需要,必须为 1111 提供 second operand 寻址 不需要
只有 2 个 operands,它不需要 imm8 字节。
随着 Opcode 的复杂化,无论是 Intel 还是 AMD 的 opcode 描述,都是旨在使用很容易对 Opcode 掌握清楚。
相对比通用指令集中的 opcode 描述要复杂。关于通用指令的 opcode 描述,详见:指令 opcode 码
5. FMA4/XOP 指令 operands 寻址
MD 的 XOP/FMA4 指令 operands 最多可以 4 个 operands,因此要分开下以几种情况描述
XOP/FMA4 指令的 operands 寻址很大程度上依赖于 XOP.W 和 VEX.W 的取值。
1、 4 个 operands 的寻址情况
像以下这个 FMA4 指令的 2 种寻址模式
VEX RXB.mmmmmm W.vvvv.L.pp Opcode
vfmaddpd xmm1, xmm2, xmm3/mem128, xmm4 c4 RXB.03 0.xsrc1.0.01 69 /r /is4
VEX RXB.mmmmmm W.vvvv.L.pp Opcode
vfmaddpd xmm1, xmm2, xmm3, xmm4/mem128 c4 RXB.03 1.xsrc1.0.01 69 /r /is4
AMD 定义的 operands 寻址模式表:
VEX.W/XOP.W ModRM.reg VEX.vvvv/XOP.vvvv ModRM.r/m imm8[7:4]
0 dest src1 src2 src3
1 dest src1 src3 src2
当 VEX.W/XOP.W = 0 时:ModRM.r/m 提供 src2 operand(即:third operand)寻址,而 imm8[7:4] 则提供 src3(即:fourth operand)寻址。
当 VEX.W/XOP.W = 1 时:ModRM.r/m 提供 src3 operand(即:fourth operand)寻址,而 imm8[7:4] 则提供 src2(即:third operand)寻址。
而 dest operand(即:first operand)固定由 ModRm.reg 提供寻址。
src1 operand(即:second operand)固定由 VEX.vvvv/XOP.vvvv 提供寻址。
那么,指令 vfmaddpd 的 2 种寻址模式如下:
实际上,很容易看出 xmm3/mem128 这个 operands 到底是由谁提供寻址。
因为,指令中 xmm3/mem128 既可 register 也可以 memory,那么它只能由 ModRM.r/m 提供寻址,这是肯定的。
2、 3 个 operands 的寻址情况
下面是某条 XOP 指令的 opcode 描述:
对于 3 个 operands 都是 register 的情况下:
XOP.W ModRM.reg XOP.vvvv ModRM.r/m
0 dest src2 src1
1 dest src1 src2
对于,第 3 个 operand 是 imm8 的情况下:
XOP.W ModRM.reg XOP.vvvv ModRM.r/m imm8
0 dest 1111 src1 src2
这种情况下,XOP.vvvv 必须为 1111,指示指令不需要 XOP.vvvv 寻址,而 src2 则由 imm8 提供立即数。
那么,这条指令的 3 种寻址模式是:
3、2 个 operands 的寻址情况
像下面这条 XOP 指令:
XOP.W ModRM.reg XOP.vvvv ModRM.r/m
0 dest 1111 src
它的 operands 寻址情况是:
那么这条指令的 operand 是:
4、FMA4/XOP 指令的 operands 寻址总结
(1)destination operand(first operand)由 ModRM.reg 提供寻址。
(2)而指令的 src1 和 src2 以及 src3 根据 VEX.W/XOP.W 的取值不同,以及指令的 operands 个数而不同。
6. FMA4/XOP 指令解析
以上一节的几条指令为例,说一说 FMA4/XOP 指令的解析
1、 FMA4 指令的解析
(1)有以下指令:
vfmaddpd xmm1, xmm9, [rax], xmm10
接上节,它的 opcode 描述是:
将指令分解为:
c4 101 00011 0 0110 0 01 69 00 001 000 1010 0000
VEX.C4 VEX.RXB VEX.mmmmm VEX.W VEX.vvvv VEX.L VEX.pp opcode mod reg r/m
VEX.[RXBmmmmm] = a3 VEX.[WvvvvLpp] = 31 ModRM = 08 imm8 = a0
那么,它的编码是:c4 a3 31 69 08 a0
(2)将它的 operands 改变一下为:
vfmaddpd xmm1, xmm9, xmm10, [rax]
将指令为解为:
c4 101 00011 1 0110 0 01 69 00 001 000 1010 0000
VEX.C4 VEX.RXB VEX.mmmmm VEX.W VEX.vvvv VEX.L VEX.pp opcode mod reg r/m
VEX.[RXBmmmmm] = a3 VEX.[WvvvvLpp] = b1 ModRM = 08 imm8 = a0
那么,它的编码是:c4 a3 b1 69 08 a0
可以看出:上面两个例子中,仅仅只有 VEX.W 不同而已,其它是完全相同的。对于 memory 寻址,所有的通用指令中的 memory 寻址修饰都可以使用在这里,即:可以作 address-size override 以及 segment override
2、 XOP 指令解析
(1)3 个 operands 的指令
举上节中的例子:
(1) vprotb xmm8, [rax], xmm0
(2) vprotb xmm0, xmm10, [rax]
(3) vprotb xmm0, [rax], 1
指令1 的分解部分为:
8f 001 01001 0 1111 0 00 90 00 000 000
XOP.8F XOP.RXB XOP.mmmmm XOP.W XOP.vvvv XOP.L XOP.pp opcode mod reg r/m
XOP.[RXBmmmmm] = 29 XOP.[WvvvvLpp] = 78 ModRM = 00
它的最终编码是: 8f 29 78 90 00
指令2 的分解部分为:
8f 101 01001 1 0101 0 00 90 00 000 000
XOP.8F XOP.RXB XOP.mmmmm XOP.W XOP.vvvv XOP.L XOP.pp opcode mod reg r/m
XOP.[RXBmmmmm] = a9 XOP.[WvvvvLpp] = a8 ModRM = 00
它的最终编码是: 8f a9 a8 90 00
指令3 的分解部分为:
8f 101 01000 0 1111 0 00 c0 00 000 000 01
XOP.8F XOP.RXB XOP.mmmmm XOP.W XOP.vvvv XOP.L XOP.pp opcode mod reg r/m
XOP.[RXBmmmmm] = a8 XOP.[WvvvvLpp] = 78 ModRM = 00 imm8 = 01
它的最终编码是: 8f a8 78 c0 00 01
(2)2 个 operands 的指令
(1)vfrczpd xmm1, xmm2
(2)vfpczpd xmm1, [rax]
指令1 的分解部分为:
8f 101 01001 0 1111 0 00 81 11 001 010
XOP.8F XOP.RXB XOP.mmmmm XOP.W XOP.vvvv XOP.L XOP.pp opcode mod reg r/m
XOP.[RXBmmmmm] = a9 XOP.[WvvvvLpp] = 78 ModRM = ca
它的编码是:8f a9 78 81 ca
指令2 的分解部分为:
8f 101 01001 0 1111 0 00 81 00 001 000
XOP.8F XOP.RXB XOP.mmmmm XOP.W XOP.vvvv XOP.L XOP.pp opcode mod reg r/m
XOP.[RXBmmmmm] = a9 XOP.[WvvvvLpp] = 78 ModRM = 08
它的编码是:8f a9 78 81 08
*AVX与XOP指令集中的registers编码反相
、VEX prefix 中的 VEX.RXB 与 XOP prefix 中的 XOP.RXB 反相作用
2-byte 版本的 VEX prefix 为:C5 + VEX.[RvvvvLpp]
3-byte 版本的 VEX prefix 为:C4 + VEX.[RXBmmmmm] + VEX.[WvvvvLpp]
3-byte 的 XOP prefix 为:8F + XOP.[RXBmmmmm] + XOP.[WvvvvLpp]
这些 RXB 对 ModRM.reg、ModRM.r/m 以及 SIB.index、SIB.base 提供的 registers 编码进行扩展。
VEX.RXB 与 XOP.RXB 是反相位。它颠倒 ModRM 字节和 SIB 字节提供的高 8 个与低 8 个 registers
VEX.RXB 与 XOP.RXB 对 registers 的高半部分/低半部分反相表:
RXB ModRM/SIB registers
1 000 rax/xmm0/ymm0
001 rcx/xmm1/ymm1
010 rdx/xmm2/ymm2
011 rbx/xmm3/ymm3
100 rsp/xmm4/ymm4
101 rbp/xmm5/ymm5
110 rsi/xmm6/ymm6
111 rdi/xmm7/ymm7
0 000 r8/xmm8/ymm8
001 r9/xmm9/ymm9
010 r10/xmm10/ymm10
011 r11/xmm11/ymm11
100 r12/xmm12/ymm12
101 r13/xmm13/ymm13
110 r14/xmm14/ymm14
111 r15/xmm15/ymm15
可以看出,对于 ModRM 与 SIB 字节提供的 registers 编码不变,只是 RXB 标志颠倒高半部分与低半部分。
2、VEX.vvvv 与 XOP.vvvv 的反相作用
相对于 VEX.RXB 与 XOP.RXB 的反相高低半部分来说,VEX.vvvv 与 XOP.vvvv 则是提供完全相反的 registers 编码。
如下表所示:
模式 VEX.vvvv/XOP.vvvv registers
64-bit (full) legacy/compatibility 1111 xmm0/ymm0
1110 xmm1/ymm1
1101 xmm2/ymm2
1100 xmm3/ymm3
1011 xmm4/ymm4
1010 xmm5/ymm5
1001 xmm6/ymm6
1000 xmm7/ymm7
64-bit (only ) 0111 xmm8/ymm8
0110 xmm9/ymm9
0101 xmm10/ymm10
0100 xmm11/ymm11
0011 xmm12/ymm12
0010 xmm13/ymm13
0001 xmm14/ymm14
0000 xmm15/ymm15
3、imm8[7:4] 中提供的 registers 编码
对于 imm8[7:4] 提供的 registers 寻址来说,它并不提供反相作用。
如下表:
imm8[7:4] registers
0000 rax/xmm0/ymm0
0001 rcx/xmm1/ymm1
0010 rdx/xmm2/ymm2
0011 rbx/xmm3/ymm3
0100 rsp/xmm4/ymm4
0101 rbp/xmm5/ymm5
0110 rsi/xmm6/ymm6
0111 rdi/xmm7/ymm7
1000 r8/xmm8/ymm8
1001 r9/xmm9/ymm9
1010 r10/xmm10/ymm10
1011 r11/xmm11/ymm11
1100 r12/xmm12/ymm12
1101 r13/xmm13/ymm13
1110 r14/xmm14/ymm14
1111 r15/xmm15/ymm15
版权 mik(deng zhi)所有,转载注明出处
|