SSE 系列内置函数中的 shuffle 函数
SSE 系列内置函数中的 shuffle 函数
邮箱: quarrying@qq.com
博客: http://www.cnblogs.com/quarryman/
发布时间: 2017年04月18日
版权声明: 自由分享, 保持署名-非商业用途-非衍生, 知识共享3.0协议。
水平有限, 欢迎大家批评指正!
这份博文总结了 SSE 系列内置函数中与 shuffle 有关的宏和函数。分析验证了 _mm_shuffle_epi16 存在的可能性,并利用 _mm_shuffle_epi8 实现了该函数。
下面是 SSE 系列内置函数中与 shuffle 有关的 intrinsic 函数:
// Integer shuffle, SSE
extern __m64 _mm_shuffle_pi16(__m64 _A, int _Imm);
// SP FP shuffle, SSE
extern __m128 _mm_shuffle_ps(__m128 _A, __m128 _B, unsigned int _Imm);
// DP FP shuffle, SSE2
extern __m128d _mm_shuffle_pd(__m128d _A, __m128d _B, int _Imm);
// Integer shuffle, SSE2
extern __m128i _mm_shuffle_epi32(__m128i _A, int _Imm);
extern __m128i _mm_shufflehi_epi16(__m128i _A, int _Imm);
extern __m128i _mm_shufflelo_epi16(__m128i _A, int _Imm);
// Integer shuffle, SSSE3
extern __m128i _mm_shuffle_epi8 (__m128i a, __m128i b);
extern __m64 _mm_shuffle_pi8 (__m64 a, __m64 b);
1. _mm_shuffle_pd 和 _MM_SHUFFLE2
可以使用 _MM_SHUFFLE2 来构造 _mm_shuffle_pd 中的参数 _Imm, _MM_SHUFFLE2 是 SSE2 中定义的一个宏, 定义如下
#define _MM_SHUFFLE2(x,y) (((x)<<1) | (y))
因为 __m128d 能容纳 2 个 DP FP (双精度浮点数) , 所以 x,y 的取值集合为 {0, 1}, _MM_SHUFFLE2(x,y) 的最大值为
(((1)<<1) | (1)) == 3 <= 2^32 - 1
显然可以用 int 来表示立即数 _Imm.
2. _mm_shuffle_ps 和 _MM_SHUFFLE
可以使用 _MM_SHUFFLE 来构造 _mm_shuffle_ps 中的参数 _Imm, _MM_SHUFFLE 是 SSE 中定义的一个宏, 定义如下
#define _MM_SHUFFLE(fp3, fp2, fp1, fp0) (((fp3) << 6) | ((fp2) << 4) | \
((fp1) << 2) | ((fp0)))
因为 __m128 能容纳 4 个 SP FP (单精度浮点数) , 所以 fp3, fp2, fp1, fp0 的取值集合为 {0, 1, 2, 3}, _MM_SHUFFLE(fp3, fp2, fp1, fp0) 的最大值为
(((3) << 6) | ((3) << 4) | ((3) << 2) | ((3))) == 255 == 2^8 - 1 <= 2^32 - 1
显然可以用 unsigned int 来表示立即数 _Imm.
注意: 文档和代码注释中只说到使用 _MM_SHUFFLE 来构造 _mm_shuffle_ps 中的参数 _Imm, 实际上除了 _mm_shuffle_ps, 上面的 _mm_shuffle_pi16, _mm_shuffle_epi32, _mm_shufflehi_epi16, _mm_shufflelo_epi16, 都可以使用 _MM_SHUFFLE 来构造 _Imm.
3. _mm_shuffle_epi16 和 _MM_SHUFFLE8
SSE 系列内置函数中并没有定义 _mm_shuffle_epi16, 而是定义了 _mm_shufflehi_epi16, _mm_shufflelo_epi16.
我们不妨定义 __m128i _mm_shuffle_epi16(__m128i _A, int _Imm);, 且定义 _MM_SHUFFLE8 来构造第二个参数 _Imm, 定义如下
#define _MM_SHUFFLE8(fp7, fp6, fp5, fp4, fp3, fp2, fp1, fp0)\
(((fp7) << 21) | ((fp6) << 18) | ((fp5) << 15) | ((fp4) << 12)) |\
(((fp3) << 9) | ((fp2) << 6) | ((fp1) << 3) | ((fp0)))
因为 __m128i 能容纳 8 个 16 位整型数据, 所以fp7, fp6, fp5, fp4, fp3, fp2, fp1, fp0 的取值集合为 {0, 1, 2, 3, 4, 5, 6, 7}, 则 _MM_SHUFFLE8(fp7, fp6, fp5, fp4, fp3, fp2, fp1, fp0) 的最大值为
(((7) << 21) | ((7) << 18) | ((7) << 15) | ((7) << 12)) |
(((7) << 9) | ((7) << 6) | ((7) << 3) | ((7))) == 16777215 == 2^24 - 1 <= 2^32 - 1
所以上面定义的 _mm_shuffle_epi16 理论上是可行的, 然而 SSE 系列内置函数中却没有这个函数, 我的猜测是:
_mm_shufflehi_epi16, _mm_shufflelo_epi16 可以使用 _MM_SHUFFLE 构造立即数 _Imm, 而要实现 _mm_shuffle_epi16, 还要配套实现 _MM_SHUFFLE8, 开发人员容易弄混各种 shuffle 相关的宏和函数.实际上, 可以利用 _mm_shufflehi_epi16 和 _mm_shufflelo_epi16 来实现 _mm_shuffle_epi16( 可能比较麻烦), 也可以利用 SSSE3 中的 _mm_shuffle_epi8 来实现 _mm_shuffle_epi16.
3.1 代码一, 利用 _mm_shuffle_epi8 实现 _mm_shuffle_epi16
/*
博客: http://www.cnblogs.com/quarryman/
发布时间: 2017年04月18日
版权声明: 自由分享, 保持署名-非商业用途-非衍生, 知识共享3.0协议。
如有错误和建议, 欢迎发邮件或留言!
*/
#include <stdio.h>
#include <emmintrin.h>
#include <tmmintrin.h>
#define _MM_SHUFFLE8(fp7, fp6, fp5, fp4, fp3, fp2, fp1, fp0)\
(((fp7) << 21) | ((fp6) << 18) | ((fp5) << 15) | ((fp4) << 12)) | \
(((fp3) << 9) | ((fp2) << 6) | ((fp1) << 3) | ((fp0)))
__m128i _mm_shuffle_epi16(__m128i _A, int _Imm)
{
_Imm &= 0xffffff;
char m01 = (_Imm >> 0) & 0x7, m03 = (_Imm >> 3) & 0x7;
char m05 = (_Imm >> 6) & 0x7, m07 = (_Imm >> 9) & 0x7;
char m09 = (_Imm >> 12) & 0x7, m11 = (_Imm >> 15) & 0x7;
char m13 = (_Imm >> 18) & 0x7, m15 = (_Imm >> 21) & 0x7;
m01 <<= 1; m03 <<= 1; m05 <<= 1; m07 <<= 1;
m09 <<= 1; m11 <<= 1; m13 <<= 1; m15 <<= 1;
char m00 = m01 + 1, m02 = m03 + 1, m04 = m05 + 1, m06 = m07 + 1;
char m08 = m09 + 1, m10 = m11 + 1, m12 = m13 + 1, m14 = m15 + 1;
//__m128i vMask = _mm_set_epi8(m00, m01, m02, m03, m04, m05, m06, m07,
// m08, m09, m10, m11, m12, m13, m14, m15);
__m128i vMask = _mm_set_epi8(m14, m15, m12, m13, m10, m11, m08, m09,
m06, m07, m04, m05, m02, m03, m00, m01);
return _mm_shuffle_epi8(_A, vMask);
}
void icvPrintM128i_16s(const __m128i& v)
{
printf("(%d, %d, %d, %d, %d, %d, %d, %d)",
v.m128i_i16[0], v.m128i_i16[1], v.m128i_i16[2], v.m128i_i16[3],
v.m128i_i16[4], v.m128i_i16[5], v.m128i_i16[6], v.m128i_i16[7]);
}
int main()
{
__m128i val = _mm_setr_epi16(0, 1, 2, 3, 4, 5, 6, 7);
icvPrintM128i_16s(val);
val = _mm_shuffle_epi16(val, _MM_SHUFFLE8(1, 2, 3, 5, 4, 7, 6, 0));
icvPrintM128i_16s(val);
getchar();
return 0;
}
4. _mm_shuffle_epi8
注意到 _mm_shuffle_epi8 的第二个参数使用的是 __m128i, 而不是 int 或 unsigned int. 可以同理得到第二个参数理论上的最大值:
(((15) << 60) | ((15) << 56) | ((15) << 52) | ((15) << 48)) |
(((15) << 44) | ((15) << 40) | ((15) << 36) | ((15) << 32)) |
(((15) << 28) | ((15) << 24) | ((15) << 20) | ((15) << 16)) |
(((15) << 12) | ((15) << 8) | ((15) << 4) | ((15))) == 2**64 - 1
所以不能用 32 位整型表示, 却能用 128 位的 __m128i 表示.
SSE 系列内置函数中的 shuffle 函数的更多相关文章
- SSE系列内置函数中的shuffle函数
SSE 系列内置函数中的 shuffle 函数 邮箱: quarrying@qq.com 博客: http://www.cnblogs.com/quarryman/ 发布时间: 2017年04月18日 ...
- 手机QQ内置网页,微信内置网页中进行分享到QQ和微信的操作
微信内的网页分享: API内容详见微信开发文档 https://mp.weixin.qq.com/wiki 这里需要注意的是:调用微信API的时候修改的是微信内网页右上角三个点那里打开后,选择分享之 ...
- 微信内置浏览器中,点击下拉框出现页面乱跳转现象(iphone)
微信内置浏览器中,点击下拉框出现页面乱跳转现象(iphone) 前言: 这是小菜博客的第三篇文章.一直认为自己可以表达的东西太过简单,难以上台面,总是吝啬地不肯写.就算是写,也不知道从何开始.在同事的 ...
- Android 操作手机内置存储卡中的文件
场景:需要读取指定文件的内容,此文件是手动存储到手机内置存储卡中的,且手机上不存在SD卡. 对于android通过activity提供的openFileOutput和openFileInput可以直接 ...
- 转:jsp内置对象中page与pageContext与el内置对象pageScope与pageContext区别
原文地址:jsp内置对象中page与pageContext与el内置对象pageScope与pageContext区别 首先说明一下jsp9大内置对象 (1)HttpSession类的session对 ...
- 微信内置浏览器中的cookie很诡异呀
微信内置浏览器中的cookie很诡异呀 这是设置和删除COOKIE的代码 function set_cookie($var ,$value = '' ,$expire = 0){ $path = '/ ...
- js循环函数中的匿名函数和闭包问题(匿名函数要用循环中变量的问题)
js循环函数中的匿名函数和闭包问题(匿名函数要用循环中变量的问题) 一.总结 需要好好看下面代码 本质是因为匿名函数用到了循环中的变量,而普通方式访问的话,匿名函数的访问在循环之后,所以得到的i是循环 ...
- MySQL内置功能之事务、函数和流程控制
主要内容: 一.事务 二.函数 三.流程控制 1️⃣ 事务 一.何谓事务? 事务用于将某些操作的多个SQL作为原子性操作,一旦有某一个出现错误,即可回滚到原来的状态,从而保证数据库数据完整性. # ...
- Mysql内置功能《五》 函数
一 函数 MySQL中提供了许多内置函数,例如: 一.数学函数 ROUND(x,y) 返回参数x的四舍五入的有y位小数的值 RAND() 返回0到1内的随机值,可以通过提供一个参数(种子)使RAND( ...
随机推荐
- Filebeat issue 排查--single.go:140: ERR Connecting error publishing events (retrying): dial tcp ****:5044: i/o timeout
我个人用docker搭建了一套日志分析平台:ELK+Filebeat 在正常跑了半个多月之后,Kibana刷新日志时突然发现日志不在更新了,停在某个时刻,就再也没有新log. 首先我查看了elk,lo ...
- Windows 黑屏问题
这两天使用Microsoft Visual Studio编译项目,不断黑屏闪现!回想下应该是之前设置的DOS窗口全屏的原因. 记得又一次使用MSDOS,老感觉屏幕台下,于是就设置成了全屏显示,全屏后发 ...
- js 各进制前缀 及 转换
二进制前缀0b var a=0b11;//a=3 八进制前缀0 var a=011;//a=9 十进制不用前缀 十六进制前缀0x var a=0x11;//a=17 数字转各进制字符串用num.toS ...
- JS入门(五)
前面提了很多JS的基础知识,像一些基本输出语句啊,JS中的关键字呐.然后是JS中的一些循环,数组之类的,在之后就是函数了.这些都是在JS中很基础的一些东西,在我刚开始学JS的时候,这些我就觉得很简单, ...
- sonarqube代码检测
1.安装java环境 略 2.下载sonarqube包 sonarqube与sonar-runner的下载地址:http://www.sonarqube.org/downloads/ 将下载好的软件包 ...
- 1036: [ZJOI2008]树的统计Count
1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 7496 Solved: 3078[Submit] ...
- 1935: [Shoi2007]Tree 园丁的烦恼
1935: [Shoi2007]Tree 园丁的烦恼 Time Limit: 15 Sec Memory Limit: 357 MBSubmit: 648 Solved: 273[Submit][ ...
- Archlinux 的U盘自动装载(三)udevil
U盘的自动装载方法,目前我已经使用过以下几种方法: udev 规则 基于 udev 规则的 Shell script udisks 以及 udisks2 结果,总是存在这样那样的小问题.例如,文件名乱 ...
- 菜鸟Scrum敏捷实践系列(三)用户故事的组织---功能架构的规划
菜鸟Scrum敏捷实践系列索引 菜鸟Scrum敏捷实践系列(一)用户故事概念 菜鸟Scrum敏捷实践系列(二)用户故事验收 菜鸟Scrum敏捷实践系列(三)用户故事的组织---功能架构的规划 采用Sc ...
- jquery实现名单滚动
转:http://www.qdfuns.com/notes/25341/917d9cb031f835a086dd445b77b6e04e.html 介绍:记录滚动特效.就是那一排文字不停地滚啊滚啊滚得 ...