7. 深入解析 VEX 编码规则(包括 XOP 编码方案)


Intel 最新发布的 AVX 指令集,在指令编码方案中最主要的也最重要改变就是推出了 VEX 编码规则。可以预见 VEX 编码规则将会统治着未来 x86/x64 体系编码方案相当长的一段时间。

这里主要围绕 VEX 编码规则进行较为深入的解析,为什么会包括探讨 XOP 编码呢?应该要清楚地认识到 XOP 编码是从 VEX 编码基础而来的,它们方案虽然有区别,大致上是一致的。实质上换个角度来看,XOP 指令可以说是 AVX 指令集的子集(当然是属于 AMD 的子集)或者是补充。

7.1 AVX 与 XOP 指令格式

看看下面这个图,描述了 AVX 和 XOP 指令的整体格式:

实际上和通用指令(GPI)格式几乎一样,只是多了一个额外的扩展前缀(extended prefix)部分,然而就是这个 extended prefix 是整个 AVX 和 XOP 指令的基石,它的作用是非常重要的,不可缺少的。对于 AVX 指令来说这部分是 2 bytes 或者是 3 bytes 的 VEX prefix,而对于 XOP 指令来说,它是 3 bytes 的 XOP prefix,注意这里也不存在 REX prefix,它将被集成到 VEX prefix(XOP prefix)里。

7.1.1 Legacy prefix 部分

针对在不同的指令环境:通用指令,SSE 系列指令以及 AVX 指令(及其子集,包括 XOP 指令)中 Legacy prefix 有不同的使用方式和意义。

7.1.1.1 通用指令的 legacy prefix 

通用指令中可以使用全部的 legacy prefix 集,包括下面:

7.1.1.2 SSE 指令中的 legacy prefix

在 SSE 系列指令中,部分原有的 prefix 将被重新定义,LOCK prefix 将不可用,部分 legacy prefix 依然得到保留并且意义不变,它们是:

很明显这部分 legacy prefix 只能是用于 memory 操作数的,它的意义和通用指令中的 legacy prefix 完全一致。

部分 legacy prefix 被重定义,演变为其它类型的 prefix,它们是:

这些 prefix 意义在于修饰 SSE 指令的 opcode 码,使用 opcode 码有多个操作。

7.1.1.3 AVX 指令中的 legacy prefix

在 AVX 指令集及其子集中,SSE 系列指令的 SIMD prefix(66H, F3H F2H)不再使用,LOCK prefix 不可用,只剩下:

它们依然可以使用在 memory 操作数上。这里也不存在 REX prefix,它与 SIMD prefix 一样被集成在 VEX prefix 里

因此下面的 Legacy prefix 出现在 AVX 指令里,将会产生 #UD 异常:

7.1.2 escape opcode

在通用指令和 SSE 系列指令中,可由 escape opcode(或称 escape prefix)组成 2 或 3 个 opcode 码,这些 escape opcode 是:

在 AVX 指令集系统中同样也已经被集成在 VEX prefix 里。

7.1.3 extended prefix(VEX prefix/XOP prefix)

这部分是 VEX prefix 或者 XOP prefix,VEX prefix 可以是 2 bytes 或 3 bytes,XOP prefix 只使用 3 bytes。

VEX prefix(包括 XOP prefix)的主要角色:

VEX prefix 另一大作用是也提供对操作数的寻址和控制操作数的大小:

7.1.4 opcode 部分

这部分是指令真正的 opcode 码,可是这个 1 byte 的 opcode 码并不能唯一决定指令的真正操作属性,在原有的 SSE 指令上 opcode 必须结合 escape opcode 或者 SIMD prefix 来确定指令具体的操作,而在 AVX 系列和 XOP 系列指令上,opcode 必须结合 VEX prefixXOP prefix 来确定指令的具体操作。

大部分原有的 SSE 指令都实现了 VEX 编码版本(AVX 版本),它们被重新用 VEX 编码规则进行编码,这表示,大部分原指令即有 SSE 版本也有相应的 VEX 版本,下面这个表格是一个例子:

SSE 版本

opcode

VEX 版本

opcode

addps

0F + 58

vaddps

VEX.mmmmm = 1,VEX.pp = 0

58

addpd

66 + 0F + 58

vaddpd

VEX.mmmmm = 1,VEX.pp = 1

58

addss

F3 + 0F + 58

vaddss

VEX.mmmmm = 1,VEX.pp = 2

58

addsd

F2 + 0F + 58

vaddsd

VEX.mmmmm = 1,VEX.pp = 3

58

可以看到,这一系列指令的 opcode 码都是 58H,加上 escape opcode 和 SIMD prefix 修饰后,衍生出一系列的操作,它们的 escape opcode 都是 0FH,不同的只是 SIMD prefix

在原有的 SSE 指令中,escape opcode 和 SIMD prefix 都是明码提供的,AVX 指令采用了 VEX 编码方案后,escape opcode 和 SIMD prefix 已经集成在 VEX prefix 中,我们在这里初步看到了 VEX 编码规则的威力,其最大的威力是:通过这种编码方案很容易扩展出新的指令集

7.1.5 ModRM,SIB 与 Displacement

在 AVX 指令中,这些组部分与通用指令中的 ModRM,SIB 与 Displacement 意义是完全一致的,详情请参阅 http://www.mouseos.com/x64/index.html 的相关内容。

7.1.6 Immediate 部分

在 AVX 和 XOP 指令中,这个 immediate 值只有 1 byte,因此记作 imm8,它提供第 4 个操作数的寻址:

 

7.2 VEX prefix 与 XOP prefix 的实现细节

VEX prefix 与 XOP prefix 结构是相同的,可是某些地方的意义不一致,下面是 VEX prefix 与 XOP prefix 的结构:

VEX prefix 分为 3-bytes2-bytes 两个版本:

XOP prefix 只有 3-bytes 的,以 8F 字节开头。

7.2.1 VEX prefix 组成部分

3-bytes VEX prefix 组成部分如下:

C4 + [RXBmmmmm] + [WvvvvLpp]

2-bytes VEX prefix 组成部分如下:

C5 + [RvvvvLpp]

在上面的 byte 1 和 byte 2 中每个字母占 1 bit,因此:VEX.mmmmm 域 5 bits 宽,VEX.vvvv 域 4 bits 宽,VEX.pp 域 2 bits 宽,其余的域 1 bit 宽。

7.2.2 VEX.RXB 与 VEX.W

事实上这就是 VEX prefix 集成 x64 编码中的 REX prefix 的体现:

它们的作用是和 REX.WRXB 大致相同的,如下示意:

  byte 1        byte 2


R X B mmmmm   W vvvv L pp
- - -         -  
| | |         |         
| | |         +------------------------> W: 扩展指令中的 GPRs 到 64 位(如果指令中支持 GPR 操作数)
| | |
| | +----------------------------------> B: 扩展 SIB.base,ModRM.r/m 域
| |
| +------------------------------------> X: 扩展 SIB.index 域
|
+--------------------------------------> R: 扩展 ModRM.reg 域

关于 REX.WRXB 的作用,详情请参阅:http://www.mouseos.com/x64/doc4.html

在 AVX 指令中 VEX.W 遭遇了 3 个情境:

现阶段 VEX.W 的作用是保留为兼容原有 SSE 指令,绝大多情况下 VEX.W 应该置为 0

然而对于 XOP.W 来说,它的意义与 VEX.W 是不同的:XOP.W 控制指令操作数的寻址

表1:XOP 中 4 个操作数

在 4 个操作数的 XOP 指令中,XOP.W 主要控制 src2 和 src3 操作数,在由 imm8[7:4] 和 ModRM.r/m 寻址之间作选择。

表2:XOP 中的 3 操作数

由于只有 3 个操作数,XOP.W 将控制 src(src1 操作数)和 count(src2 操作数),由 ModRM.r/m 与 XOP.vvvv 之间作选择。当 XOP 指令只有 2 个操作数时,XOP.W 需置为 0,不需要 XOP.vvvv 进行寻址,XOP.vvvv 必须置为 1111b

在 VEX prefix 中的 VEX.RXB 同样是起了扩展作用,可是 VEX.RXB 的扩展与 REX.RXB 的扩展是存在较在差别:

以 REX.R 的原码扩展为例:

以 VEX.R 的反相扩展为例:

反相扩展的结果是:VEX.RXB 取反,然后扩展相应的域,下面的两个表格列出了所有反相扩展的值:

表1:VEX.RB 的反相扩展

表2:VEX.XB 的反相扩展

表2 中的 VEX.XB 扩展是用来内存操作数的寻址上,从这两个表我们可以知道,在 32 位模式下,仅能使用其中的一半寄存器。

VEX.RXB 执行的是反相扩展,然而 VEX.vvvv 执行的是反相编码,我们将会在后面看到 VEX.vvvv 的更彻底的反相编码

7.2.3 VEX.vvvv

在 AVX 指令中大部分都是 3 个 operands 的指令,VEX.vvvv 提供对寄存器操作数的寻址:

必须注意的是:当不需要使用 VEX.vvvv 进行寻址时,VEX.vvvv 必须置为 1111b 值。这种情况下,只需要 ModRM.reg 和 ModRM.r/m 进行寻址就足够了。

4 bits 宽的 VEX.vvvv 提供的是反相编码。下面看看 VEX.vvvv 的反相编码表:

 

可以看到,在 VEX.vvvv = 1111b 实际等于原码的 0000b,这时对应的寄存器是 xmm0/ymm0 寄存器。

7.2.4 VEX 编码中的反相设计

上面所看到的反相扩展以及反相编码,是经过研究设计后的必然结果,我们看看为什么会这样设计。

7.2.4.1 32 位模式下的 legacy opcode

首先我们来看看 VEX prefix 中的 byte 0,它们是:

这两个字节被用来作为 VEX prefix 的首字节,需要解决的首要问题是如何避免冲突!在原来的指令里 C4LES 指令的 opcode 码。

下面这条指令:

les edi, [eax]

它的指令指令编码是:

les edi, [eax]
         -----
           |
           +----------> far pointer mem16:32


      c4  38
          --
          |
          +-----------> mod: 00
                        reg: 111
                        r/m: 000

les 指令所需要的操作数必须是 memory 操作数,它存放着 far pointer(mem16:16 或 mem16:32),所以,我们不能这样:

因此,VEX 编码正是利用了这个无效操作数的错误来设计的:

现在,我们就找到了设计的关键:在 32 位模式下,必须让 C4 后面的字节 ModRM.mod = 11b,从而产生了 VEX.RXB反相扩展设计方案,以下面这条指令为例:

vaddps ymm1, ymm2, [r10]

它的指令编码是:C4 C1 6C 58 0A

vaddps ymm1, ymm2, [r10]


编码:C4  C1 6C 58 0A
         --
         |
         +----------------------> 解码1: 作为 ModRM 字节时:mod = 11  (错误:无效操作数
                                                            reg = 000
                                                            r/m = 001

                                  解码2: 作为 VEX prefix 时:VEX.R = 1
                                                             VEX.X = 1
                                                             VEX.B = 0
                                                             VEX.mmmmm = 00001

从上面可以看到,在 32 位模式下 AVX 指令的 VEX.RX 必须为 11b 才能保证正确是解码为 AVX 指令,所以:

这就是 VEX.RXB 的反相扩展的设计方案。

同样的设计原理,VEX.vvvv 在 32 位模式下必须以 1b 开头,以 vaddps 指令为例:

vaddps ymm1, ymm2, ymm3


编码:C5  EC 58 CB
         --
         |
         +----------------------> VEX.R:    1
                                  VEX.vvvv: 1101
                                  VEX.L:    1
                                  VEX.pp:   00

上面使用的是 2-bytes 版本的 VEX prefix 编码规则,在 32 位模式下 C5LDS 指令的 opcode 码,这里同样要求 VEX.vvvv 必须以 VEX.R 为 1b,以及 VEX.vvvv 以 1b 开头,VEX.vvvv 被设计为更彻底的反相编码,与 VEX.RXB 的仅仅反相扩展有些区别。

7.2.4.2 XOP prefix 的反相设计

事实上 XOP prefix 为了兼容 VEX prefix 而选择使用反相设计,从原理上来看 XOP prefix 可以做到不需要反相设计。XOP prefix 使用 8F 作为 byte 0

上面这个表格可以看出,只有当 ModRM.reg = 000 时,这个 opcode 才是有效的,因此,当 ModRM.reg 不为 000b 时(也就是大于 08H),就可以识别出 XOP prefix 了,pop 指令的操作数既可以是寄存器,也可以是内存操作数,从设计原理上来说使用 8F 作为 XOP prefix 并不一定需要对 ModRM.mod 进行限制,但是基于兼容 VEX prefix 的目的,XOP prefix 同样使用了反相编码设计。

7.2.5 VEX.mmmmm 与 VEX.pp

VEX.mmmmm 里集成了 escape opcode:

而 VEX.pp 里集成了 SIMD prefix:

因此,原有的 SSE 系列指令很容易移植成 AVX 指令,通过使用 VEX 编码规则进行重新编码就形成了 AVX 指令版本,大多数 SSE 指令都有相对应的 AVX 指令形式。

addpd xmm1, xmm2                     ; SSE2, encode: 66 0F 58 CA
vaddpd xmm1, xmm2, xmm3              ; AVX,  encode: C4 E1 69 58 CB

上面就是同一条指令的 SSE 版本和 AVX 版本,它们所执行的操作是完全一样的,AVX 版本使用 VEX 编码规则。

表1 VEX.mmmmm 对应表:

VEX.mmmmm
escape opcode
00000
保留
00001
0F
00010
0F 38
00011
0F 3A

表2 VEX.pp 对应表:

VEX.pp
SIMD prefix
00
01
66
10
F3
11
F2

VEX.mmmmm 域仅存在于 3-bytes 的 VEX prefix 中,对于 2-bytes 的 VEX prefix 缺省是集成 0F 的,基于这个原因,部分 3-bytes VEX 的 AVX 指令可以使用 2-bytes VEX 进行编码。

我们看看上面的指令:

vaddpd xmm1, xmm2, xmm3

这条指令典型地可以译为 2-bytes VEX 版本和 3-bytes VEX 版本。

先来看看 3-bytes VEX 的版本:

C4  E1  69  58  CB
    --  --
    |   |
    +---+---------------------> 111 00001
        |                       --- -----
        |                       RXB  mmmmmm   ==> 00001 指出 escape opcode 为 0F
        |
        |
        +---------------------> 0 1101 0 01
                                - ---- - --
                                W vvvv L pp   ==> 01 指出 SIMD prefix 为 66

现在来看看 2-bytes VEX 版本:

C5  E9  58  CB
    -- 
    |  
    |
    +------------------------> 1 1101 0 01
                               - ---- - --
                               R vvvv L pp   ==> 01 指出 SIMD prefix 为 66
                                                 而 escape opcode 缺省使用 0F

上面两种译法都是正确的,因此绝大多数编译器在可能的前提下会选择译为 2-bytes VEX 的编码,这样生成的指令编码更短。当然,很显然并不是所有的 3-bytes VEX 都可以译为 2-bytes VEX 版本,下面三种情况是不能的:

  1. 指令中使用了内存操作数,而这个内存操作数的 base 寄存器或 index 寄存器并且需要使用 VEX.XB 扩展访问的情况下。
  2. 这条指令的 escape opcode 不是缺省的 0F 情况下,它需要使用 VEX.mmmmm
  3. 指令中使用了通用寄存器,并且需要扩展访问的情况下,它需要使用 REV.W。这类指令较少。

7.2.6 XOP.mmmmm

XOP 指令中的 XOP.pp 意义与 VEX.pp 是一样的,可以 XOP.mmmmm 却与 VEX.mmmmm 完全不同,从上面的节 《7.2.4.2 XOP prefix 的反相设计》中我们可以看到,在 XOP.mmmmm 要求是大于或等于 08H

XOP.mmmmm
意义
01000
指令中需要提供 imm8 操作数
01001
指令中无需 imm8 操作数

可见,XOP.mmmmm 无不是提供 escape opcode,而是用来控制操作数,前面已经提过必须大于或等于 08H 是因为必须保证 ModRM.reg 不为 0,这是正确解码出 XOP 指令方法。

这是一条 XOP 指令,它的机器编码是:8F E8 68 EC CB 00 第 4 个操作数是 imm8,看看下面的示意:

8F  E8  68  EC  CB  00   
    --  --
    |   |
    +---+---------------------> 111 01000
        |                       --- -----
        |                       RXB mmmmm     ==> 08H 指出指令需要 imm8 操作数
        |
        |
        +---------------------> 0 1101 0 00
                                - ---- - -- 
                                R vvvv L pp   ==> 不使用 SIMD prefix

现在,我们知道 XOP 是全新的指令集,它不使用 escape opcode 也不使用 SIMD prefix。

7.2.7 VEX.L

最后来看看 VEX.L 域,VEX.L 域有三种意义:

7.2.7.1 指示操作数大小

这是比较常见的指令,它是用来控制指令的操作数大小

大部份 AVX 或 XOP 指令可以操作 128 和 256 位数据。

vaddpd xmm1, xmm2, xmm3               ; 128-bit
vaddpd ymm1, ymm2, ymm3               ; 256-bit

这两条指令的差别在于使用的寄存器,看看下面的示意:

C5  E9  58  CB
    --
    |
    +-------------------------> 1 1101 0 01
                                - ---- - --
                                R vvvv L pp    ==> VEX.L = 0 使用 128 位寄存器


C5  ED  58  CB
    --
    |
    +-------------------------> 1 1101 1 01
                                - ---- - --
                                R vvvv L pp    ==> VEX.L = 1 使用 256 位寄存器

除了 VEX.L 不同外,其它都是完全一样的。

7.2.7.2 操作 scalar 类指令被忽略

这类指令同样比较常见,这类指令的 mnemonic 中包括:

它们的 VEX.L 将被忽略不起作用,下面是典型的指令例子:

vaddsd xmm1, xmm2, xmm3

它的机器编码是:C5 EB 58 CB

C5  EB  58  CB
    --
    |
    |
    +---------------> 1 1101 0 11        1 1101 1 11
                      - ---- - --   或   - ---- - --
                      W vvvv L pp        W vvvv L pp

这个编码中的 VEX.L 将被忽略,因此 VEX.L = 0VEX.L = 1 都是正确的。

7.2.7.3 在 AVX2 中的通用指令中,VEX.L 必须为 0

AVX2 是 AVX 指令的扩展,新增了使用 VEX-prefix 的通用指令,它们的 VEX.L 必须为 0

下面这条指令是例子:

andn rax, rbx, rax

它的编码是:C4 E2 E0 F2 C0

C4  E2  E0  F2  C0
    --  --  --  --
    |   |   |   |
    |   |   |   |
    +---+---+---+----------------> 111 00010
        |   |   |                  --- -----
        |   |   |                  RXB mmmmm
        |   |   |
        +---+---+----------------> 1 1100 0 00
            |   |                  - ---- - --
            |   |                  W vvvv L pp
            |   |
            +---+----------------> opcode
                |
                |
                +----------------> 11 000 000
                                   -- --- ---
                                  mod reg r/m

operand1: VEX.R + ModRM.reg = 1000(rax 寄存器)
operand2: VEX.vvvv = 1100(rbx 寄存器)
operand3: VEX.B + ModRM.r/m = 1000(rax 寄存器)

这里的 VEX.L 必须为 0,当置 VEX.L = 1 时这个 opcode 是无效的,执行它会产生 #UD 异常。

7.3 操作数寻址

在指令编码中,能提供操作数寻址的 4 个域是:

因此,VEX 指令能提供最多 4 个操作数。在这里对于 4 个操作数统一使用下面的术语:

目标操作数只有一个,我们可以肯定的:operand1 就是目标操作数。可是在 Intel 或 AMD 官方的手册里,关于源操作数确实有时会让人产生迷惑,这个迷惑首先来自 first source operand(第 1 个源操作数),那么哪个是 first source operand 呢?答案是:operand1 和 operand2 都有可能

那是因为某些指令:它的 operand1 既是目标操作数,也是源操作数,也就有可能 operand1 是 frist source operand。因此这里统一使用 operand1 到 operand4 术语。

7.3.1 由 VEX.vvvv 提供的操作数

这里先来看看 VEX.vvvv 提供的操作数是哪些:

也就是:VEX.vvvv 可以提供目标操作数源操作数进行寻址。大多数情况下,VEX.vvvv 提供 operand2 寻址,只有少量的指令需要 VEX.vvvv 提供 operand1(即:目标操作数)寻址,当 VEX.vvvv 不被使用时,必须置为 1111b 值。

7.3.1.1 VEX.vvvv 作为目标操作数

下面这个表格列出使用 VEX.vvvv 来寻址的指令形式:

vpslldq xmm1, xmm2, imm8
vpsrldq xmm1, xmm2, imm8
vpsrlw xmm1, xmm2, imm8
vpsrld xmm1, xmm2, imm8
vpsrlq xmm1, xmm2, imm8
vpsraw xmm1, xmm2, imm8
vpsrad xmm1, xmm2, imm8
vpsllw xmm1, xmm2, imm8
vpslld xmm1, xmm2, imm8
vpsllq xmm1, xmm2, imm8

在整个 AVX 指令中,仅仅只有上面的 10 条指令是使用 VEX.vvvv 对 operand1(也就是:目标操作数)进行寻址的。

operand1(目标操作数)
operand2
operand3
VEX.vvvv
ModRM.r/m
imm8

这些指令的 VEX.vvvv 作为 operand1,ModRM.r/m 作为 operand2。为什么不使用 ModRM.reg 进行寻址呢,实际上这 10 条指令是 Group 属性的 opcode 码,ModRM.reg 需要为 opcode 提供辅助识别。基于这个原因,不能使用 ModRM.reg 寻址操作数。

7.3.1.2 VEX.vvvv 提供源操作数寻址

在 3 个操作数以及 4 个操作数的指令中,除了上述的 10 条指令外,VEX.vvvv 都作为 operand2 寻址(即:源操作数),VEX.vvvv 不会被作为 operand3,在 AVX 系列指令集中 operand3 可以是 registermemory 操作数,因此:operand3 必需由 ModRM.r/m 提供寻址。

7.3.2 ModRM.reg 与 ModRM.r/m 的寻址

ModRM.reg 提供寄存器操作数,而 ModRM.r/m 提供寄存器和内存操作数。当指令形式中存在 memory 操作数,那么必须由 ModRM.r/m 提供寻址。

7.3.2.1 两个操作数的寻址

operand1
operand2
operand3
operand4
ModRM.reg
ModRM.r/m
ModRM.r/m
ModRM.reg

在两个操作数的情况下并不使用 VEX.vvvv 寻址,因此 VEX.vvvv 的值必需设为 1111b,当 ModRM.r/m 出现在 operand1(目标操作数)的位置上,那么这类指令是典型的 store 类指令

7.3.2.2 三个操作数的寻址

operand1
operand2
operand3
operand4
ModRM.reg
VEX.vvvv
ModRM.r/m
ModRM.reg
ModRM.r/m
imm8
VEX.vvvv
ModRM.r/m
imm8

上面列出了几种情况,第 1 类指令是占了多数。没使用 VEX.vvvv 时,VEX.vvvv 必须为 1111b 值,这里的 imm8 是立即数,表示一个控制位或 mask 值。

7.3.2.3 四个操作数的寻址

operand1
operand2
operand3
operand4
ModRM.reg
VEX.vvvv
ModRM.r/m
imm8(立即数)
ModRM.reg
VEX.vvvv
ModRM.r/m
imm8[7:4](寄存器)

上面是 AVX 的四个操作数指令,operand4 是 imm8,有两种情况:

7.3.3 imm8 寻址

AVX 指令实现真正的 4 个寄存器操作数,那么在原有 x86 指令编码结构中必须要有表达第 4 个寄存器操作数的部件,既不是 ModRM 也不是 SIB 更不是 displacement,唯有 immediate 是可以利用的地方。

在 VEX 编码中的 imm8 有两种意义:

值得注意的是:imm8[7:4] 提供的是原码编码,并不像 VEX.vvvv 那样提供反相编码。

vblendvpd ymm1, ymm2, ymm3, ymm4

这条是典型的 4 操作数指令,它的编码是 C4 E3 6D 4B CB 40,如下所示:

C4  E3  6D  4B  CB  40
    --  --      --  --
    |   |       |   |
    |   |       |   |
    +---+-------+---+--------------> 111 00011
        |       |   |                --- -----
        |       |   |                RXB mmmmm
        |       |   |
        +-------+---+--------------> 0 1101 1 01
                |   |                - ---- - --
                |   |                W vvvv L pp
                |   |
                +---+--------------> 11 001 011    
                    |                -- --- ---
                    |               mod reg r/m
                    |
                    +--------------> 0100 0000
                                     ----
                                     ymm4


operand1: VEX.R + ModRM.reg = 1001(ymm1)
operand2: VEX.vvvv = 1101(ymm2)
operand3: VEX.B + ModRM.r/m = 1011(ymm3)
operand4: imm8[7:4] = 0100(ymm4)

 


版权所有 mik 2009-2011