x86平台SIMD编程入门(2):通用指令

这篇具有很好参考价值的文章主要介绍了x86平台SIMD编程入门(2):通用指令。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1、重解释转换

虽然128位的XMM寄存器在硬件上只是256位YMM寄存器的下半部分,但在C++中它们是不同的类型。有一些intrinsic函数可以将它们重新解释为不同的类型,如下表所示,行代表源类型,列代表目标类型。

__m128 __m128d __m128i __m256 __m256d __m256d
__m128 = _mm_castps_pd _mm_castps_si128 _mm256_castps128_ps256
__m128d _mm_castpd_ps = _mm_castpd_si128 _mm256_castpd128_pd256
__m128i _mm_castsi128_ps _mm_castsi128_pd = _mm256_castsi128_si256
__m256 _mm256_castps256_ps128 = _mm256_castps_pd _mm256_castps_si256
__m256d _mm256_castpd256_pd128 _mm256_castpd_ps = _mm256_castpd_si256
__m256i _mm256_castsi256_si128 _mm256_castsi256_ps _mm256_castsi256_pd =

这些函数不会被编译成任何指令,所以性能上几乎没有损耗,因为它们不改变寄存器中的值,例如32位float浮点数1.0f转换成32位整数后会变为0x3f800000。将128位值转换成256位值时,上半部分是未定义的。

2、类型转换

类型转换只支持带符号的32位整数,例如:

函数示例 说明
_mm_cvtepi32_ps_mm256_cvtepi32_ps 将32位整数转换成对应的32位浮点数
_mm_cvtepi32_pd_mm256_cvtepi32_pd 将32位整数转换成对应的64位浮点数
_mm_cvtps_epi32_mm256_cvtps_epi32 将32位浮点数转换成对应的32位整数
_mm_cvtpd_epi32_mm256_cvtpd_epi32 将64位浮点数转换成对应的32位整数

当浮点数转换为整数时,函数使用MXCSR寄存器中指定的舍入模式,若要更改模式,可以使用宏_MM_SET_ROUNDING_MODE。此外,也有一些名称中带有额外t的函数会忽略MXCSR寄存器,并始终使用向零截断(_MM_ROUND_TOWARD_ZERO)的模式,例如_mm_cvttpd_epi32_mm_cvttps_epi32

此外还有一些函数可以在32位浮点数与64位浮点数之间进行转换,例如_mm256_cvtps_pd将32位浮点数转换成64位浮点数。

3、内存访问

3.1、加载

  • 对齐/非对齐加载:所有数据类型都支持对齐加载和非对齐加载。对齐加载例如_mm_load_si128_mm256_load_ps,它们要求源地址是16字节或者32字节对齐的,否则可能会导致崩溃;非对齐加载例如_mm_loadu_si128_mm256_loadu_ps,它们函数名中额外的u表示unaligned,它们的速度可能会慢于对齐加载的版本。

  • 单通道加载:__m128__m128d支持单通道加载,即只加载第一条通道并把其它通道设置成0.0,例如_mm_load_ss_mm_load_sd

  • 逆序加载:__m128__m128d支持逆序加载,即以逆序方式将数据加载到寄存器中,例如_mm_loadr_ps_mm_loadr_pd

  • 广播加载:在AVX指令集中, __m128__m256__m256d支持广播加载,也就是把单个值加载到多个寄存器通道中,例如_mm256_broadcast_ss等。

  • 掩码加载:AVX引入了掩码加载,即根据掩码的值选择性地加载数据,例如_mm_maskload_ps等。

  • 跨距加载:AVX2引入了跨距加载,它可以利用索引寄存器来加载非连续地址的数据元素,不过速度较慢,例如_mm_i32gather_ps等。

  • 流加载:这类指令绕过缓存,直接将内存数据加载到寄存器中,从而减少缓存污染和缓存替换的开销,适用于一次性读取大量数据并进行向量化计算的场景,例如_mm_stream_load_si128_mm256_stream_load_si256等。

3.2、存储

  • 对齐/非对齐存储:与对齐/非对齐加载同理,对应的存储指令也有_mm_store_ps_mm_storeu_ps等。

  • 单通道存储:与单通道加载类似,只把第一条通道的数据写入内存,例如_mm_store_ss等。

  • 逆序存储:与逆序加载类似,它以逆序方式将数据写入内存中,例如_mm_storer_ps等。

  • 掩码存储:与掩码加载类似,根据掩码的值选择性地存储数据,例如_mm_maskstore_ps等。

  • 流存储:与流加载指令类似,绕过缓存直接将数据写入内存,从而减少了缓存写回的开销,适用于大规模数据的存储操作,例如_mm_stream_ps_mm256_stream_si256等。

4、向量寄存器初始化

所有向量寄存器类型都有_mm_setzero_ps_mm256_setzero_si256这样的函数,用于将寄存器初始化为全零,它可能会被编译成xorps xmm0, xmm0, xmm0这样的指令,其执行效率很高。

虽然CPU无法使用0以外的常量来初始化寄存器,但编译器还是提供了一些函数来实现非0初始化,例如_mm_set_ps可以用不同的值初始化各个通道,_mm256_set1_epi用相同的值初始化所有通道。这些函数的实现依据具体情况而定:如果参数是编译时的常量,它们通常会被编译成二进制文件中的只读数据;如果编译时无法确定参数,编译器就会执行其它合理操作,例如寄存器大部分为0,而我们只设置了一条通道,那么编译器可能会执行插入指令,再比如参数来自变量,编译器就可能会先实行洗牌或标量存储、然后再进行向量加载。

5、向量寄存器与通用寄存器的转换

数据类型 数据复制方向 函数示例
整数 向量寄存器最低通道 ==> 通用寄存器 _mm_cvtsi128_si32_mm_cvtsi128_si64
整数 通用寄存器 ==> 向量寄存器最低通道 _mm_cvtsi32_si128_mm_cvtsi64x_si128
浮点数 向量寄存器最低通道 ==> 通用寄存器 _mm_cvtss_f32_mm_cvtsd_f64
浮点数 通用寄存器 ==> 向量寄存器最低通道 没有对应的转换函数,但可以使用_mm_set_ps_mm_set1_ps实现相同功能

上表中列举的转换函数只操作向量寄存器的最低通道,除此之外还有一类函数可以将整数向量寄存器任意通道的值复制到通用寄存器,它们是_mm_extract_epi8_mm_extract_epi16等。

当程序是32位时,所有通用寄存器也都是32位的,在向量寄存器和通用寄存器之间移动64位整数的指令不可用。

6、位运算

浮点数和整数有一套完整的位运算指令,它们包含AND、OR、XOR、ANDNOT指令,例如_mm_and_ps_mm256_xor_epi32等。如果需要位运算NOT,最快的方法可能是与所有1进行XOR,例如:

__m128i bitwiseNot(__m128i x)
{
    const __m128i zero = _mm_setzero_si128();
    const __m128i one = _mm_cmpeq_epi32(zero, zero);
    return _mm_xor_si128(x, one);
}

test指令将计算结果直接保存到int型的通用寄存器中,部分test函数及其功能如下表所示:文章来源地址https://www.toymoban.com/news/detail-741777.html

函数示例 返回结果
_mm_testz_si128_mm256_testz_si256 return ((a & b) == 0) ? 1 : 0
_mm_testc_si128_mm256_testc_si256 return (((~a) & b) == 0) ? 1 : 0
_mm_testnzc_si128_mm256_testnzc_si256 testztestc结果都为0时返回1,否则返回0
_mm_test_all_ones 把输入向量取反后与全1向量按位与,如果等于0则返回1,否则返回0
_mm_test_all_zeros 把输入向量与掩码向量按位与,如果等于0则返回1,否则返回0

到了这里,关于x86平台SIMD编程入门(2):通用指令的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【ARMv8 SIMD和浮点指令编程】NEON 通用数据处理指令——复制、反转、提取、转置...

    NEON 通用数据处理指令包括以下指令(不限于): • DUP 将标量复制到向量的所有向量线。 • EXT 提取。 • REV16、REV32、REV64 反转向量中的元素。 • TBL、TBX 向量表查找。 • TRN 向量转置。 • UZP、ZIP 向量交叉存取和反向交叉存取。 1 DUP (element) 将向量元素复制为向量或标量。

    2024年02月07日
    浏览(32)
  • 【ARMv8 SIMD和浮点指令编程】浮点数据转换指令——数据类型互转必备

    浮点数据转换指令包括不同的浮点精度数之间的转换,还包括整型和浮点数之间的转化。 在了解数据转换指令前,必须学习 IEEE 754 定义的五种舍入规则。前两条规则舍入到最接近的值,其他的称为定向舍入: 舍入到最接近的值 Round to nearest, ties to even – rounds to the nearest va

    2024年02月02日
    浏览(44)
  • 2023年的深度学习入门指南(9) - SIMD和通用GPU编程

    深度学习从一开始就跟GPU有不解之缘,因为算力是深度学习不可或缺的一部分。 时至今日,虽然多任务编程早已经深入人心,但是很多同学还没有接触过CPU上的SIMD指令,更不用说GPGPU的编程。这一篇我们先给SIMD和GPU编程扫个盲,让大家以后用到的时候有个感性认识。 从多线

    2024年02月02日
    浏览(34)
  • (汇编) 基于VS的x86汇编基础指令

    visual studio 选择x86运行 示例代码 OV 溢出 超出表示范围为溢出 1,否则 0 UP 增量 1:以递减顺序对数据串处理;0:以递增顺序对数据串处理 EI 允许中断 CPU允许中断1,否则0 PL 正 运算结果为正则为1,否则0 ZR 零 运算结果为0则为1,否则0 AC 辅助进位 低4位向高位进位1,否则0 P

    2024年02月06日
    浏览(35)
  • x86汇编_MUL/IMUL乘法指令_笔记52

    32位模式下整数乘法可以实现32、16或8位的操作,64位下还可以使用64位操作数。MUL执行无符号乘法,IMUL执行有符号乘法。 MUL指令:无符号数乘法 32 位模式下,MUL(无符号数乘法)指令有三种类型: 执行 8 位操作数与 AL 寄存器的乘法; 执行 16 位操作数与 AX 寄存器的乘法;

    2024年02月07日
    浏览(28)
  • 华为云RDS通用型(x86) vs 鲲鹏(ARM)架构的性能对比

    之前,我们对比了阿里云RDS的经济版(ARM)与x86版的性价比,这次我们来看看华为云的RDS MySQL的“通用型”(x86)与“鲲鹏通用增强型”(ARM)版本的情况如何。 这里依旧选择了用户较为常用的4c16g的规格进行测试,测试工具使用了sysbench的oltp_read_write模型进行测试。配置参数与选

    2024年02月03日
    浏览(34)
  • 发布 VectorTraits v2.0(支持 x86的Sse系列指令集等)

    目录 支持 x86的Sse系列指令集 为 Vector128/Vector256 补充全部的向量方法 提供CPU型号信息 结果范例1: X86 CPU on Windows 结果范例2: Arm CPU on Linux 结果范例3: Arm CPU on Mac OS 提供所支持的指令集信息 结果范例1: X86 CPU on Windows 结果范例2: Arm CPU on Linux 结果范例3: Arm CPU on Mac OS 新增了向量方

    2024年03月17日
    浏览(28)
  • x86 平台运行 arm 的方法

    参考: https://github.com/multiarch/qemu-user-static 核心是使用 binfmt_misc 设定运行 arm 的默认程序为 qemu-aarch64-static 1.先下载 arm64 即 aarch64 的运行文件 2.设置默认打开方式, 即设置 binfmt_misc 以支持 arm64 程序的运行 # --reset 会删除同名条目后重新设置 3.测试 4.不用映射qemu-*-static也可以使用

    2024年02月12日
    浏览(209)
  • 【ARMv8 SIMD和浮点指令编程】NEON 乘法指令——乘法知多少?

    NEON 乘法指令包括向量乘法、向量乘加和向量乘减,还有和饱和相关的指令。总之,乘法指令是必修课,在我们的实际开发中会经常遇到。 1 MUL (by element) 乘(向量,按元素)。该指令将第一个源 SIMDFP 寄存器中的向量元素乘以第二个源 SIMDFP 寄存器中的指定值,将结果放入向

    2024年02月08日
    浏览(30)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包