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函数及其功能如下表所示:
| 函数示例 | 返回结果 |
|---|---|
_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 |
testz和testc结果都为0时返回1,否则返回0 |
_mm_test_all_ones |
把输入向量取反后与全1向量按位与,如果等于0则返回1,否则返回0 |
_mm_test_all_zeros |
把输入向量与掩码向量按位与,如果等于0则返回1,否则返回0 |
x86平台SIMD编程入门(2):通用指令的更多相关文章
- x86平台转x64平台关于内联汇编不再支持的解决
x86平台转x64平台关于内联汇编不再支持的解决 2011/08/25 把自己碰到的问题以及解决方法给记录下来,留着备用! 工具:VS2005 编译器:cl.exe(X86 C/C+ ...
- X86平台乱序执行简要分析(翻译为主)
多处理器使用松散的内存模型可能会非常混乱,写操作可能会无序,读操作可能会返回不是我们想要的值,为了解决这些问题,我们需要使用内存栅栏(memory fences),或者说内存屏障(memory bar ...
- 【浅墨著作】《OpenCV3编程入门》内容简单介绍&勘误&配套源码下载
经过近一年的沉淀和总结,<OpenCV3编程入门>一书最终和大家见面了. 近期有为数不少的小伙伴们发邮件给浅墨建议最好在博客里面贴出这本书的文件夹,方便大家更好的了解这本书的内容.事实上近 ...
- VS2010MFC编程入门
一.MFC编程入门教程之目录 第1部分:MFC编程入门教程之目录 1.MFC编程入门之前言 鸡啄米的C++编程入门系列给大家讲了C++的编程入门知识,大家对C++语言在语法和设计思想上应该有了一定的 ...
- Linux.中断处理.入口x86平台entry_32.S
Linux.中断处理.入口x86平台entry_32.S Linux.中断处理.入口x86平台entry_32.S 在保护模式下处理器是通过中断号和IDTR找到中断处理程序的入口地址的.IDTR存的是 ...
- 编程入门选什么语言好?C 语言还是Python ?为你解析
前面我分享过计算机行业已经成了学校选择排名第一,家长和学生都很看好计算机类专业.现在IT行业也越来越火爆,程序员越来越被人看好.面对相比同龄人高薪资的诱惑,人们很难不心动,即使秃头也值得! 那么问题来 ...
- WinPcap编程入门实践
转自:http://www.cnblogs.com/blacksword/archive/2012/03/19/2406098.html WinPcap可能对大多数人都很陌生,我在这里就先简单介绍一下 ...
- PC游戏编程(入门篇)(前言写的很不错)
PC游戏编程(入门篇) 第一章 基石 1. 1 BOSS登场--GAF简介 第二章 2D图形程式初体验 2.l 饮水思源--第一个"游戏"程式 2.2 知其所以然一一2D图形学基础 ...
- Matlab与.NET基于类型安全的接口混合编程入门
原文:[原创]Matlab与.NET基于类型安全的接口混合编程入门 如果这些文章对你有用,有帮助,期待更多开源组件介绍,请不要吝啬手中的鼠标. [原创分享]Matlab.NET混编调用Figure窗体 ...
- Mysql C语言API编程入门讲解
原文:Mysql C语言API编程入门讲解 软件开发中我们经常要访问数据库,存取数据,之前已经有网友提出让鸡啄米讲讲数据库编程的知识,本文就详细讲解如何使用Mysql的C语言API进行数据库编程. ...
随机推荐
- LLM论文研读: GraphRAG的替代者LightRAG
1. 背景 最近有一个很火的开源项目LightRAG,Github6.4K+星※,北邮和港大联合出品,是一款微软GraphRAG的优秀替代者,因此本qiang~得了空闲,读读论文.跑跑源码,遂有了这篇 ...
- 去除tinymce中粘贴的样式
import "tinymce/plugins/paste"; tinymce.init({ ...其他配置, plugins: ["paste"], past ...
- 一款.NET开源的屏幕实时翻译工具
前言 今天大姚给大家推荐一款.NET开源的屏幕实时翻译工具:Translumo. 工具介绍 Translumo是一个.NET开源的高级屏幕翻译工具,能够实时检测和翻译选定区域内的文本(如字幕).Tra ...
- 【原创】PREEMPT-RT 系统cpu使用率周期CPU飙高问题
PREEMPT-RT 系统cpu使用率周期CPU飙高问题 目录 PREEMPT-RT 系统cpu使用率周期CPU飙高问题 背景 现象 复现条件 原因 解决措施 背景 在22年进行PREEMPT-RT系 ...
- pycharm生成的allure测试报告如何查看本地的index.html文件?
pycharm生成的allure测试报告应该是通过服务启动查看,但是如果把这个文件保存到本地查看,直接打开页面无内容 可以使用allure-combine工具实现本地正常打开 `from allure ...
- delphi Image32 之 快速入门
官方快速入门,加上了一些注解 [从WORD粘贴后失去了样式] TImage32 类是关键.TImage32 对象包含单个图像,所有图像操作都作用于此对象. uses Img32; //引用单元 .. ...
- AI智能学生体测小程序解决方案
引言: 近年来,随着教育理念的提升,对学生综合素质的教育越发重视,特别是越发重视学生的身体素质提升,各阶段的升学考试也将体测纳入考核范围.学校也推出了各种体测锻炼促进手段,今天为您介绍一个基于小程序的 ...
- CodeForces - 1398C Good Subarrays
CodeForces - 1398C 挺简单的题目,但是没有想到还是整理一下 方法1 把每个元素都减1,那么满足题意的就是一段和的值是0,然后维护前缀和,如果发现这个前缀和之前出现过,就说明有满足题意 ...
- python的egg的制作
egg包是目前最流行的python应用打包部署方式.如何制作和安装egg包?下面我就简单的分析了一下. 总是安装别人的egg包,是不是也想制作自己的egg包呢?好,接下来我们就自己制作一个简单的egg ...
- 设计一个基于 LSTM 神经网络的文本分类器
前一篇:<用于自然语言处理的循环神经网络RNN> 序言:本节主要讲解如何使用循环神经网络(RNN)创建一个文本分类器.RNN 是一类适合处理序列数据的神经网络的统称,而我们将在本节中使用 ...