Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/150.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/65.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何使用SIMD比较两个字符向量并将结果存储为浮点?_C++_C_Simd_X86 - Fatal编程技术网

C++ 如何使用SIMD比较两个字符向量并将结果存储为浮点?

C++ 如何使用SIMD比较两个字符向量并将结果存储为浮点?,c++,c,simd,x86,C++,C,Simd,X86,目标:使用最少数量的算术运算,即每个{mask1和mask2}识别内部函数以转换4个布尔“uint8_t” > Stime>更新:为了优化代码,我在C++中使用SIMD。与此相反,我们的目标是为大规模阵列处理/支持掩码。后者使用“内部”掩码属性(“”)进行示例: uint8_t mask1[4]={0,1,1,0};uint8_t mask2[4]={1,1,0,0};浮点数据[4]={5,4,2,1}; {//!运行正常的朴素代码: 浮点数和=0; 对于(int i=0;i

目标:使用最少数量的算术运算,即每个{mask1和mask2}识别内部函数以转换4个布尔“uint8_t”

<> > Stime>更新:为了优化代码,我在C++中使用SIMD。与此相反,我们的目标是为大规模阵列处理/支持掩码。后者使用“内部”掩码属性(“”)进行示例:

uint8_t mask1[4]={0,1,1,0};uint8_t mask2[4]={1,1,0,0};浮点数据[4]={5,4,2,1};
{//!运行正常的朴素代码:
浮点数和=0;
对于(int i=0;i<4;i++){
if(mask1[i]&&mask2[i]){sum+=data[i];}
}
}
从上面我们观察到掩码与简单算法相结合的使用:尽管上述操作集由优化算法支持,“内部”有几个缺点:(a)限制操作的数量,(b)对更新的编译器提出要求(情况并非总是如此)

上下文: 挑战涉及从“char”数据类型到“float”数据类型的转换。为了演示我的代码中的错误,这里有一个简短的摘录:

//! Setup, a setup which is wrong as mask1 and mask2 are chars and not floats.
#include <emmintrin.h>
#include <x86intrin.h>                                                               

char mask1[4] = {0, 1, 0, 1};
char mask2[4] = {1, 0, 0, 1};
const int j = 0;

//! The logics, which is expected to work correct for flroats, ie, not chars.
const __m128 vec_empty_empty = _mm_set1_ps(0);              
const __m128 vec_empty_ones = _mm_set1_ps(1);
const __m128 term1  = _mm_load_ps(&rmul1[j2]); 
const __m128 term2  = mm_load_ps(&rmul2[j2]);
__m128 vec_cmp_1 = _mm_cmplt_ps(term1, vec_empty_empty); 
__m128 vec_cmp_2 = _mm_cmplt_ps(term2, vec_empty_empty); 

//! Intersect the values: included to allow other 'empty values' than '1'.
vec_cmp_1 =  _mm_and_ps(vec_cmp_1, vec_empty_ones);
vec_cmp_2 = _mm_and_ps(vec_cmp_2, vec_empty_ones);

//! Seperately for each 'cell' find the '1's which are in both:
__m128 mask = _mm_and_ps(vec_cmp_1, vec_cmp_2); 
/!设置,一个错误的设置,因为mask1和mask2是字符而不是浮动。
#包括
#包括
char mask1[4]={0,1,0,1};
char mask2[4]={1,0,0,1};
常数j=0;
//! 逻辑,预计对FLROAT(即非字符)正确工作。
常量m128向量空向量空向量=_mm_set1_ps(0);
常量m128向量空值=_mm_set1_ps(1);
常数m128第1项=_mm_载荷ps(&rmul1[j2]);
常数m128第2项=毫米荷载ps(&rmul2[j2]);
__m128向量cmp1=_mm_cmplt_ps(term1,向量为空);
__m128向量cmp2=_mm_cmplt_ps(term2,向量为空);
//! 与值相交:包括以允许“1”以外的其他“空值”。
vec_cmp_1=_mm_和_ps(vec_cmp_1,vec_空的_);
vec_cmp_2=_mm_和_ps(vec_cmp_2,vec_空的_);
//! 分别为每个“单元格”查找两个单元格中的“1”:
__m128掩模=_mm_和_ps(vec_cmp_1,vec_cmp_2);

上述结果用于与浮点向量相交(即相乘)
float arr[4]
。因此,如果有人对如何将SIMD char向量转换为浮点SIMD向量有任何建议,我将不胜感激

使用SSE4.1
pmovsxbd
pmovzxbd
对4字节的块进行签名或零扩展,使其成为32位整数元素的16B向量

请注意,似乎不可能安全高效地写入,因为没有内存操作数更窄的内在函数

要进行比较部分,请使用
pcmpeqd
生成元素中所有零位或所有一位的掩码(即
-1
)。使用它来屏蔽FP数据的向量。(所有零是IEEE浮点中
0.0
的位表示,0.0是加法恒等式。)


如果元素总是只有0或1,则可以使用
uint32\u t
保存所有四个字节,并使用标量and(C的
&
运算符)作为所有四个
mask1[i]&&mask2[i]
检查的SWAR实现。将该整数转换为向量并
pmovsxbd
。如果您的元素实际上是0和-1(全部为1),这将更好地工作,否则您需要额外的步骤来获得向量掩码。(例如,pcmpeqb与所有零向量相对)

如果您不能使用
-1
而不是
1
,那么您最好的选择可能仍然是将掩码解包为32位元素和
pcmpeqd

总的想法是:

__m128i m1vec = _mm_epi8_epi32(mask1);         // where mask1 has to be a __m128i vector already, not a 4byte memory location.
__m128i m2vec = _mm_epi8_epi32(mask2);

// sign-extension turns each 0 or -1 byte into a 0 or -1 dword (32bit) element

__m128i mask = _mm_and_si128(mask1, mask2);
// convert from 0/1 to 0/-1 if necessary.  I'm assuming the simple case.

__m128 masked_floats = _mm_and_ps(floats, _mm_castsi128_ps(mask));   // 0.0 or original value

sum = _mm_add_ps(sum, masked_floats);
如果掩码元素可以不是0/-1,则可能需要使用
\u mm\u cmpeq\u epi32(m1vec,\u mm\u setzero\u si128())
或其他工具分别对它们进行布尔化。(将非零变为零,反之亦然)


有关链接,请参见tag wiki,特别是使用SSE4.1
pmovsxbd
pmovsxbd
对4字节块进行签名或零扩展,将其扩展为32位整数元素的16B向量

请注意,似乎不可能安全高效地写入,因为没有内存操作数更窄的内在函数

要进行比较部分,请使用
pcmpeqd
生成元素中所有零位或所有一位的掩码(即
-1
)。使用它来屏蔽FP数据的向量。(所有零是IEEE浮点中
0.0
的位表示,0.0是加法恒等式。)


如果元素总是只有0或1,则可以使用
uint32\u t
保存所有四个字节,并使用标量and(C的
&
运算符)作为所有四个
mask1[i]&&mask2[i]
检查的SWAR实现。将该整数转换为向量并
pmovsxbd
。如果您的元素实际上是0和-1(全部为1),这将更好地工作,否则您需要额外的步骤来获得向量掩码。(例如,pcmpeqb与所有零向量相对)

如果您不能使用
-1
而不是
1
,那么您最好的选择可能仍然是将掩码解包为32位元素和
pcmpeqd

总的想法是:

__m128i m1vec = _mm_epi8_epi32(mask1);         // where mask1 has to be a __m128i vector already, not a 4byte memory location.
__m128i m2vec = _mm_epi8_epi32(mask2);

// sign-extension turns each 0 or -1 byte into a 0 or -1 dword (32bit) element

__m128i mask = _mm_and_si128(mask1, mask2);
// convert from 0/1 to 0/-1 if necessary.  I'm assuming the simple case.

__m128 masked_floats = _mm_and_ps(floats, _mm_castsi128_ps(mask));   // 0.0 or original value

sum = _mm_add_ps(sum, masked_floats);
如果掩码元素可以不是0/-1,则可能需要使用
\u mm\u cmpeq\u epi32(m1vec,\u mm\u setzero\u si128())
或其他工具分别对它们进行布尔化。(将非零变为零,反之亦然)


请参见标签维基,以获取链接,尤其是。

您是否可以提供一个非simd,包括您试图实现的目标的内部和预期输出?可能重复感谢您的回答:wrt@像素化学家我现在已经做出了更详细的回答。@PeterCordes的建议引用的建议仅描述标量操作,即不包括基于向量的优化的使用