AVX指令集介绍

AVX:指令集的快速应用

最近在学习指令集相关知识,刚好来练练手。在正式应用前首先看一段代码吧

Eigen::MatrixXd mB;
mB.resize(num, 1);
for (size_t i = 0; i < num; i++)
{
	mB(i, 0) = std::pow(input_->points[i].x, 2) + std::pow(input_->points[i].y, 2) + std::pow(input_->points[i].z, 2);
}

这段代码很容易理解,依次将各点进行 x 2 + y 2 + z 2 x^2+y^2+z^2 x2+y2+z2计算,然后赋值给矩阵mB。那么变成AVX指令集加速版本应该是这样的。

#if defined (__AVX__) && defined (__AVX2__)
	size_t i = 0;
	__m256 avx_vector_x, avx_vector_y, avx_vector_z, sum_square;
	__m128 low128, high128;
	//每次处理8个
	for (; (i + 8) <= num; i += 8)
	{
		avx_vector_x = _mm256_setr_ps(input_->points[i].x, input_->points[i + 1].x, input_->points[i+2].x, input_->points[i+3].x, input_->points[i+4].x, input_->points[i+5].x, input_->points[i+6].x, input_->points[i+7].x);
		avx_vector_y = _mm256_setr_ps(input_->points[i].y, input_->points[i + 1].y, input_->points[i + 2].y, input_->points[i + 3].y, input_->points[i + 4].y, input_->points[i + 5].y, input_->points[i + 6].y, input_->points[i + 7].y);
		avx_vector_z = _mm256_setr_ps(input_->points[i].z, input_->points[i + 1].z, input_->points[i + 2].z, input_->points[i + 3].z, input_->points[i + 4].z, input_->points[i + 5].z, input_->points[i + 6].z, input_->points[i + 7].z);
		sum_square = _mm256_fmadd_ps(avx_vector_x, avx_vector_x, _mm256_fmadd_ps(avx_vector_y, avx_vector_y, _mm256_mul_ps(avx_vector_z, avx_vector_z)));
		low128 =_mm256_extractf128_ps(sum_square, 0);
		high128 = _mm256_extractf128_ps(sum_square, 1);
		// 提取并存储结果到 Eigen 矩阵 mB
		mB(i, 0) = _mm_cvtss_f32(low128);
		mB(i + 1, 0) = _mm_cvtss_f32(_mm_shuffle_ps(low128, low128, _MM_SHUFFLE(3, 2, 0, 1)));
		mB(i + 2, 0) = _mm_cvtss_f32(_mm_shuffle_ps(low128, low128, _MM_SHUFFLE(3, 1, 0, 2)));
		mB(i + 3, 0) = _mm_cvtss_f32(_mm_shuffle_ps(low128, low128, _MM_SHUFFLE(2, 1, 0, 3)));
		mB(i + 4, 0) = _mm_cvtss_f32(high128);
		mB(i + 5, 0) = _mm_cvtss_f32(_mm_shuffle_ps(high128, high128, _MM_SHUFFLE(3, 2, 0, 1)));
		mB(i + 6, 0) = _mm_cvtss_f32(_mm_shuffle_ps(high128, high128, _MM_SHUFFLE(3, 1, 0, 2)));
		mB(i + 7, 0) = _mm_cvtss_f32(_mm_shuffle_ps(high128, high128, _MM_SHUFFLE(2, 1, 0, 3)));
	}
	//剩下的不足8个按照常规处理
	for (; i < num; i++)
	{
		mB(i, 0) = std::pow(input_->points[i].x, 2) + std::pow(input_->points[i].y, 2) + std::pow(input_->points[i].z, 2);
	}
#endif

这段代码中出现了好几个关键的指令集方法,第一次看这个我也是懵逼状态。不过查阅了手册后,很快便能理解AVX指令的一些规则。

AVX指令集规则

数据类型

学这个首先得学习常见的数据类型,下面是一些基本数据类型的介绍。

数据类型描述大小
__m128包含4个float类型的128bit向量(16字节)4*32bit
__m128d包含2个double类型的128bit向量(16字节)2*64bit
__m128i包含数个int类型的128bit向量(16字节)128bit
__m256包含8个float的256bit向量(32字节)8*32bit
__m256d包含4个double类型的256bit向量(32字节)4*64bit
__m256i包含数个int类型的256bit向量(32字节)256bit

这里主要解释下__m128i和__m256i两个类型:这里的整型包括char,short,int,long,以及unsigned以上类型,所以,例如__m256i就可以由32个char(8bits),或者16个short(16bits),或者8个int(32bits),又或者4个long(64bits)构成。

函数解释

AVX指令集函数命名规则基本上是这样的,

_mm<bit_width>_<name>_<data_type>

以上面的程序中_mm256_setr_ps为例: 256指输出bit_width,setr指按反方向设置,ps指的是输入类型为float。
这里一般来说:

ps:float类型
pd:double类型
epi8/epi16/epi32/epi64:向量里每个数都是整型,一个整型8bit/16bit/32bit/64bit
epu8/epu16/epu32/epu64:向量里每个数都是无符号整型(unsigned),一个整型8bit/16bit/32bit/64bit
m128/m128i/m128d/m256/m256i/m256d:输入值与返回类型不同时会出现 ,例如__m256i_mm256_setr_m128i(__m128ilo,__m128ihi),输入两个__m128i向量 ,把他们拼在一起,变成一个__m256i返回 。另外这种结尾只见于load
si128/si256:不需要知道啥类型,反正128bit/256bit

另外解释下这里面的另外几个函数:

_mm256_mul_ps:两向量相乘,注意不是向量的dot方式乘法,而是各位置相乘
_mm256_fmadd_ps(a,b,c): a*b+c
_mm_cvtss_f32:将低字节的32位转换为float类型输出
_mm_shuffle_ps:将字节重新排列

这里解释一下,比如这句mB(i + 1, 0) = _mm_cvtss_f32(_mm_shuffle_ps(low128, low128, _MM_SHUFFLE(3, 2, 0, 1)));原本low128是按照高位到低位依次是(1.1,2.2,3.3,4.4)。经过重排列后,原本应该是(3,2,1,0),现在把1和0的位置上的值做了交换。
当然这里还可以改成更简单的版本。无需写重新排列的代码。
在程序i的for循环下加入:

for (int j = 0; j < 8; j++)
{
	mB(i+j, 0) = sum_square.m256_f32[j];
}

这样写的话代码会简洁很多。
以上就是我的初学体会,如果有错,感谢各位指正。
参考链接

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值