SIMD基本入门

举报
ZhjDayDayUp 发表于 2021/11/01 21:35:23 2021/11/01
【摘要】 IMD全称Single Instruction Multiple Data,即单指令多数据流,一次运算指令可以执行多个数据流,可以提升程序的运行速度。由于工作中,clickhouse中使用到了SSE2(Streaming SIMD Extensions 2),这里主要记录SSE2相关的指令集和函数。

官网,需要查询什么的有用:
https://software.intel.com/sites/landingpage/IntrinsicsGuide
https://www.sunxidong.com/357.html
SIMD全称Single Instruction Multiple Data,即单指令多数据流,一次运算指令可以执行多个数据流,可以提升程序的运行速度。由于工作中,clickhouse中使用到了SSE2(Streaming SIMD Extensions 2),这里主要记录SSE2相关的指令集和函数。

一、SSE指令简介

1、SSE寄存器
SSE(为Streaming SIMD Extensions的缩写)是由 Intel公司推出的指令集,是一种SIMD指令集,而SSE2针对SSE做了扩展,不过,基本原理是一样的。

SSE有8个128位寄存器,XMM0 ~XMM7。这些128位的寄存器,可以用来存放四个32位的单精确度浮点数。SSE的浮点数运算指令就是使用这些寄存器。

2、SSE浮点运算指令分类

SSE的浮点运算指令分为两大类:Packed 和Scalar。
Packed指令是一次对XMM寄存器中的四个浮点数(即DATA0 ~ DATA3)均进行计算,而Scalar则只对XMM暂存器中的DATA0进行计算。

SSE指令的一般格式,由三部分组成,第一部分是表示指令的作用,比如加法add等,第二部分是s或者p分别表示scalar或packed,第三部分为s,表示单精度浮点数(single precision floating point data)。

常用到的sse2指令集见:

http://www.cppblog.com/tgh621/archive/2010/08/20/124113.aspx

二、SSE2函数

查询sse2的函数
https://software.intel.com/sites/landingpage/IntrinsicsGuide
https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/x7s4chk3(v=vs.100)
https://blog.csdn.net/bwl111/article/details/8979638?spm=1001.2014.3001.5501
https://blog.csdn.net/bwl111/article/details/8968956?spm=1001.2014.3001.5501
https://blog.csdn.net/bwl111/article/details/8969125?spm=1001.2014.3001.5501
https://blog.csdn.net/bwl111/article/details/8970577?spm=1001.2014.3001.5501
https://blog.csdn.net/bwl111/article/details/8979770?spm=1001.2014.3001.5501
https://blog.csdn.net/bwl111/article/details/8980449?spm=1001.2014.3001.5501
https://blog.csdn.net/bwl111/article/details/8980902?spm=1001.2014.3001.5501

三、简单例子

使用sse2指令,写个简单例子,算是简单入门吧:寻找字符串中的某个符号,并返回字符串中的第一个位置。

#include <iostream>
#include <string>
#include <emmintrin.h>
using namespace std;
int FindLocByChar(string str, char ch)
{
    __m128i ch_s = _mm_set1_epi8(ch); // 16个8bit,都赋值为ch
    const char * next_pos = str.c_str();
    size_t len = str.length();
    int i = 0;
    for (; i + 15 < len; i += 16)
    {
        __m128i next_ch = _mm_load_si128(reinterpret_cast<const __m128i *>(next_pos + i)); // 加载128 bit的值。
        __m128i eq_pos = _mm_cmpeq_epi8(ch_s, next_ch); // 比较这128bit中,哪个字节的值是相等的。如果相等的话,则赋值0xFF
        uint16_t bit_mask = _mm_movemask_epi8(eq_pos); // 取16位中,每位的最高位的值,组成一个新的128bit的值,但是只有前16bit有效,直接截取
        if (bit_mask)
            return __builtin_ctz(bit_mask) + i * 16; // 因为加载的时候,数据是这样排列的 dst[127:0] := MEM[mem_addr+127:mem_addr]
    }
    while (i < len && *(next_pos + i) != ch)
        i++;
    
    return i == len ? -1 : i;
} 
int main()
{
    string str = "123qwe1\r23fsffhgsd45\r\n1234";
    char ch = '\r';
    cout << str.find_first_of(ch) << endl;
    cout << FindLocByChar(str, ch) << endl;
    return 0;
}
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。