AVX指令集

高级向量扩展指令集（Advanced Vector Extensions，简称AVX）是x86架构微处理器中的SIMD扩展指令集，由英特尔在2008年3月提出，并在2011年第一季度发布的Sandy Bridge系列处理器中首次支持。AMD在随后的2011年第三季度发布的Bulldozer系列处理器中开始支持AVX。AVX指令集提供了新的特性、指令和编码方案。

AVX是X86指令集的SSE延伸架构，如IA16至IA32般的把暂存器XMM 128bit提升至YMM 256bit，以增加一倍的运算效率。此架构支持了三运算指令（3-Operand Instructions），减少在编码上需要先复制才能运算的动作。在微码部分使用了LES LDS这两少用的指令作为延伸指令Prefix。

AVX2指令集将大多数整数命令操作扩展到256位，并引入了熔合乘法累积（FMA）运算。它们由Intel在2013年发布的Haswell微架构中首次支持。

AVX-512则使用新的EVEX前缀编码将AVX指令进一步扩展到512位，由Intel在2016年发布的Knights Landing协处理器中首次支持。Intel Xeon Scalable处理器支援AVX-512。

## 介绍

AVX使用十六个YMM寄存器，通过单条指令对多组数据执行操作（参见 SIMD）。每个YMM寄存器可同时存储并对以下数据进行并行运算：

- 八个 32 位单精度浮点数；或
- 四个 64 位双精度浮点数。

SIMD 寄存器的宽度从128位扩展至256位，并将XMM0~XMM7重命名为YMM0~YMM7（在x86-64模式下，则为XMM0~XMM15重命名为YMM0~YMM15）。因此传统的SSE指令仍可通过VEX前缀操作于YMM寄存器的低 128 位。

AVX 引入了一种名为VEX编码方案的三操作数SIMD指令格式，其中目标寄存器与两个源操作数不同。例如，原本采用传统双操作数形式的SSE指令 a ← a + b，现在可采用非破坏性的三操作数形式 c ← a + b，从而保留两个源操作数。最初，AVX的三操作数格式仅适用于具有SIMD操作数（YMM）的指令，不包括通用寄存器（如 EAX）相关的指令。随后在 BMI 等扩展中，该编码方案被用于为通用寄存器上的新指令进行编码。VEX 编码也用于操作 AVX-512 引入的 k0–k7 掩码寄存器的指令。

SIMD内存操作数的对齐要求已被放宽。与未使用VEX编码的对应指令不同，大多数使用VEX编码的向量指令不再要求其内存操作数必须按向量大小对齐。值得注意的是，VMOVDQA指令仍要求其内存操作数必须对齐。

新的VEX编码方案引入了一组新的代码前缀，扩展了操作码空间，允许指令拥有超过两个操作数，并支持SIMD向量寄存器长度超过128位。该VEX前缀也可用于传统SSE指令，赋予其三操作数形式，使其无需依赖VZEROUPPER和VZEROALL即可更高效地与AVX指令交互。

AVX指令同时支持128位和256位SIMD。128位版本可用于在不扩大向量化宽度的前提下优化旧代码，并避免从SSE切换到AVX所带来的性能惩罚；在某些早期AMD的AVX实现中，这些指令运行更快。此模式有时被称为 AVX-128。

与SSE系列相比，AVX在数字媒体播放、网页浏览、非对称加密等方面进一步提升了性能。

## 新指令

这些AVX指令是在对传统128位SSE指令的256位扩展指令之外新增的；其中大多数既可用于128位操作数，也可用于256位操作数。

指令｜描述

`VBROADCASTSS`, `VBROADCASTSD`, `VBROADCASTF128`｜广播加载：将一个 32 位、64 位或 128 位的内存操作数复制到 XMM 或 YMM 寄存器的所有元素中。

`VINSERTF128`｜128 位替换：将 256 位 YMM 寄存器的下半部分或上半部分替换为一个 128 位源操作数的值，寄存器的另一半保持不变。

`VEXTRACTF128`｜128 位提取：提取 256 位 YMM 寄存器的下半部分或上半部分，并将其复制到 128 位目标操作数中

`VMASKMOVPS`, `VMASKMOVPD`｜条件 SIMD 加载/存储：根据掩码，从 SIMD 向量内存操作数中有条件地读取任意数量的元素到目标寄存器，未读取的元素位置置零；或从 SIMD 向量寄存器中有条件地将任意数量的元素写入内存操作数，内存中未被写入的元素保持不变。需要注意的是，在 AMD Jaguar 处理器架构中，当掩码为零时，该指令（内存源操作数版本）耗时超过 300 个时钟周期——尽管此时指令本应什么也不做。这被认为是一个设计缺陷。

`VPERMILPS`, `VPERMILPD`｜通道内置换（Permute In-Lane）：对输入操作数的 32 位或 64 位向量元素进行打乱。这是一类作用于 256 位的“通道内”指令，即在两个独立的 128 位通道内分别执行打乱操作，因此无法跨 128 位通道进行元素交换

`VPERM2F128`｜跨通道打乱（Shuffle）：将两个 256 位源操作数中的四个 128 位向量元素，依据一个立即数选择器，打乱后送入 256 位目标操作数

`VTESTPS`, `VTESTPD`｜打包符号位测试：对打包的单精度或双精度浮点数的符号位进行位测试，根据“与”（AND）的结果设置 ZF 标志，根据“与非”（ANDN）的结果设置 CF 标志

`VZEROALL`｜清零所有 YMM 寄存器：将所有 YMM 寄存器置零，并标记为未使用。该操作通常在 128 位与 256 位使用模式切换时执行

`VZEROUPPER`｜清零 YMM 寄存器上半部分：将所有 YMM 寄存器的上半部分置零，用于从 256 位模式切换回 128 位模式时清空高 128 位

## 支援

### CPU对AVX指令集的支持情况

- 英特尔
- Sandy Bridge（2011年Q1）及更新的的处理器（除赛扬和奔腾）均支持
- Tiger Lake（2020年Q3）及更新的的奔腾和赛扬处理器均支持
- 推土机微架构（2011年Q4）及更新的处理器均支持
- 威盛电子
- Nano QuadCore
- Eden X4
- 基于五道口架构的处理器（KX-5000及KH-20000）

### 编译器和汇编器对AVX指令集的支持情况

- Absoft编译器支持-mavx选项
- Free Pascal编译器从2.7.1版本开始为AVX和AVX2提供-CfAVX和-CfAVX2选项
- Delphi从RAD studio v11.0 Alexandria版本开始支持AVX2和AVX512
- GNU汇编器从GNU Binutils 2.19版本开始支持AVX
- 4.6版本的GCC和11.1版本的Intel编译器套件开始支持AVX
- Open64编译器从4.5.1版本开始使用-mavx标志支持AVX
- PathScale编译器支持-mavx选项
- Vector Pascal编译器通过-cpuAVX32选项支持AVX
- Visual Studio 2010/2012 编译器通过内联函数（intrinsic）和 /arch:AVX选项支持AVX
- NASM从2.03版本开始支持 AVX，并在 2.04 版本中，进行了许多与 AVX 相关的错误修复和更新

### 操作系统对AVX指令集的支持情况

AVX通过256 位宽的YMM寄存器添加了新的寄存器状态，因此需要操作系统显式支持，以在上下文切换时正确保存和恢复AVX的扩展寄存器。以下操作系统版本支持 AVX：

- DragonFly BSD：在2013年初添加支持
- FreeBSD：在2012年1月21日提交的补丁中添加支持，该补丁包含在9.1稳定版中
- Linux：内核版本2.6.30（发布于2009年6月9日）开始支持
- macOS：从10.6.8版本（Snow Leopard，发布于2011年6月23日）开始支持。macOS Ventura 不支持没有AVX2指令集的 x86 处理器
- OpenBSD：在2015年3月21日添加支持
- Solaris：在 Solaris 10 Update 10 和 Solaris 11 中开始支持。
- Windows：在 Windows 7 SP1（KB976932）、Windows Server 2008 R2 SP1、Windows 8、Windows 10 中提供支持
- Windows Server 2008 R2 SP1 结合 Hyper-V 需要热修复（KB2568088）以支持 AMD AVX（Opteron 6200 和 4200 系列）处理器
- Windows XP 和 Windows Server 2003 在内核驱动和用户应用程序中都不支持 AVX

## 外部链接

- Intel Intrinsics Guide