所以我阅读了英特尔关于 _mm_blendv_ps 的文档,但不太明白该函数的真正作用。所以我写了下面的代码:
__m128 a = { 18.0,4.0,19.0,21.0 };
__m128 b = { 67.0,92.0,888.0,47.0 };
__m128 mask = { 1.0,0.0,0.0,1.0 };
__m128 result = _mm_blendv_ps(a, b, mask);
cout << "Result is: " << result[0] << " " << result[1] << " " << result[2] << " " << result[4] << endl;
Run Code Online (Sandbox Code Playgroud)
但我收到错误“没有运算符 [] 与这些操作数匹配”。为什么我无法访问结果?结果不是32位浮点向量吗?
那么为什么我无法访问结果呢?我怎样才能访问它?cout 的结果是什么(blendv 做什么)?
Blendv 使用最高设置位在两个结果之间进行选择。它相当于这段代码:
__m128 _mm_blendv_ps(__m128 false_result, __m128 true_result, __m128 mask) {
__m128 r;
r[0] = (mask[0] & 0x80000000) ? true_result[0] : false_result[0];
r[1] = (mask[1] & 0x80000000) ? true_result[1] : false_result[1];
r[2] = (mask[2] & 0x80000000) ? true_result[2] : false_result[2];
r[3] = (mask[3] & 0x80000000) ? true_result[3] : false_result[3];
return r;
}
Run Code Online (Sandbox Code Playgroud)
我实际上倾向于包装它,因为参数顺序与标准有点不同if(cmp) { true } else { false };
__m128 select(__m128 mask, __m128 true_result, __m128 false_result) {
return _mm_blendv_ps(false_result, true_result, mask);
}
Run Code Online (Sandbox Code Playgroud)
通常您会使用它来执行if(a < b) {} else {}类型操作,例如
// if (a < b) {return true_result;} else {return false_result;}
__m128 select_if_lt(__m128 a, __m128 b, __m128 true_result, __m128 false_result) {
return select(_mm_cmplt_ps(a, b), true_result, false_result);
}
// if (a >= b) {return true_result;} else {return false_result;}
__m128 select_if_ge(__m128 a, __m128 b, __m128 true_result, __m128 false_result) {
return select(_mm_cmpge_ps(a, b), true_result, false_result);
}
Run Code Online (Sandbox Code Playgroud)
在您上面发布的代码中:
__m128 mask = { 1.0,0.0,0.0,1.0 };
Run Code Online (Sandbox Code Playgroud)
1.0 的最高位实际上是零,所以你需要一个负数来使掩码起作用,例如
// it doesn't matter which negative number you use,
// it just requires the sign bit to be set. -0.0f works!
__m128 mask = { -0.0f,0.0,0.0,-0.0f };
Run Code Online (Sandbox Code Playgroud)
仅查看符号位的好处是您可以执行某些 if/else 操作,而无需使用比较指令,例如
// if (a < 0) {return true_result;} else {return false_result;}
__m128 select_if_negative(__m128 a, __m128 true_result, __m128 false_result) {
return select(a, true_result, false_result);
}
Run Code Online (Sandbox Code Playgroud)
但请注意,您将得到 -0.0f 的误报,这对您可能重要也可能不重要。
至于访问 __m128 的内容,这通常不是跨平台的(一些编译器重载数组运算符,一些指定 .x/.y 等,一些具有内部联合成员变量)。因此,如果您想要一种跨平台访问内容的方法,您有两个选择:
_mm_extract_ps使用。_mm_cvtss_f32std::ostream& operator << (std::ostream& os, const __m128& v) {
os << "(" <<
_mm_cvtss_f32(v) << ", " <<
_mm_cvtss_f32(_mm_shuffle_ps(b, b, _MM_SHUFFLE(1, 1, 1, 1))) << ", " <<
_mm_cvtss_f32(_mm_unpackhi_ps(b, b)) << ", " <<
_mm_cvtss_f32(_mm_shuffle_ps(b, b, _MM_SHUFFLE(3, 3, 3, 3))) << ")";
return os;
}
Run Code Online (Sandbox Code Playgroud)
_mm_store_psstd::ostream& operator << (std::ostream& os, const __m128& v) {
float f[4];
_mm_storeu_ps(f, v);
os << "(" <<
f[0] << ", " <<
f[1] << ", " <<
f[2] << ", " <<
f[3] << ")";
return os;
}
Run Code Online (Sandbox Code Playgroud)
不管你怎么做,访问 XMM 寄存器的元素总是会产生成本(当然,除了 [0]),所以一般规则是尽量避免这样做!
| 归档时间: |
|
| 查看次数: |
359 次 |
| 最近记录: |