【发布时间】:2016-05-23 23:30:06
【问题描述】:
目标:使用最少数量的算术运算(即每个{mask1 AND mask2})识别内在函数以转换 4 个布尔“uint8_t”。
更新:为了优化代码,我在 C++ 中使用 SIMD。与Loading 8 chars from memory into an __m256 variable as packed single precision floats 相比,目标是处理/支持大规模数组的掩码。后者使用“内部”掩码属性(“https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=10,13”)进行示例:
uint8_t mask1[4] = {0, 1, 1, 0}; uint8_t mask2[4] = {1, 1, 0, 0}; float data[4] = {5, 4, 2, 1};
{ //! Naive code which works:
float sum = 0;
for(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);
上面的结果将用于与浮点向量float arr[4] 相交(即相乘)。因此,如果有人对如何将 SIMD 字符向量转换为浮点 SIMD 向量有任何建议,我将不胜感激! ;)
【问题讨论】:
-
您能否提供一个非 simd mcve,包括您想要实现的目标和预期输出?
-
感谢您的回答:wrt。 @Pixelchemist 我现在已经把答案更详细了。
-
写。 @PeterCordes 的建议提到的建议仅描述标量操作,即不包括使用基于向量的优化:简而言之,该建议导致超过 2 倍的性能问题(与非屏蔽的后继方案相比)。
-
好吧,这与我的问题不同。更新了我的答案。