c++ - C++ 中的 Clang vector 扩展和相等运算符

标签 c++ clang simd

我使用 Clang SIMD vector 扩展编写了一个 vector 类型。它运行良好,除非我需要检查两个 vector 是否相等。 == 运算符似乎没有为 Clang 的 vector 类型正确定义。奇怪的是,尝试用 == 比较两个 vector 似乎计算出与被比较的两个 vector 类型相同的第三个 vector ,而不是 bool。我觉得这很奇怪,因为应用其他操作,如 +- 编译没有问题,并输出预期的结果。这是我的代码,使用 Clang 3.5 (Xcode) 编译:

// in vect.h 
template <typename NumericType>
using vec2 = NumericType __attribute__((ext_vector_type(2))) ;

//in main.cpp
#include "vect.h"

int main(int argc, const char ** argv) {

    vec2<int> v0 {0, 1} ;
    vec2<int> v1 {0, 1} ;

    vec2<int> sumVs = v0 + v1 ; //OK: evaluates to {0, 2} when run

    bool equal = (v0 == v1) ; /* Compiler error with message: "Cannot initialize
        a variable of type 'bool' with an rvalue of type 'int __attribute__((ext_vector_type(2)))'" */

    return 0;
}

是否有任何方法可以使用 operator == 和 Clang 的 vector 类型,或者任何其他解决此问题的方法?因为它们被认为是原始类型而不是类类型,所以我不能自己重载比较运算符,并且编写全局 equals() 函数似乎笨拙且不优雅。

更新:或者如果没有人有我正在寻找的解决方案,也许有人可以解释 == 运算符在比较两个 SIMD vector 时的默认行为?

更新 #2:Hurkyl 建议 == 对两个 vector 进行向量化比较。我更新了代码以测试这种可能性:

template <typename NumericType>
using vec3 = NumericType __attribute__((ext_vector_type(3))) ;

int main(int argc, const char ** argv) {

    vec3<int> v0 {1, 2, 3} ;
    vec3<int> v1 {3, 2, 1} ;

    auto compareVs = (v0 == v1) ;

    return 0;
}

LLDB 将 compareVs 的值报告为 {0, -1, 0},如果是这样的话,这似乎几乎是正确的,但是 true 似乎很奇怪-1,false 为 0。

更新#3:好的,多亏了我收到的反馈,我现在对如何将关系运算符和比较运算符应用于 vector 有了更好的理解。但我的基本问题仍然存在。对于任何两个 SIMD 类型的 vector v1v2,我需要一种简单而优雅的方法来检查它们是否等效。换句话说,我需要能够检查 v1v2 中的每个索引 iv1[i] = = v2[i],表示为单个 bool 值(即,不是 bool 的 vector/数组)。如果唯一的答案真的是一个像这样的函数:

template <typename NumericType>
bool equals(vec2<NumericType> v1, vec2<NumericType> v2) ...

...那么我会接受的。但我希望有人能提出一些不那么笨拙的建议。

最佳答案

如果不使用特定于编译器的语言扩展,而是使用内部函数(例如,在 xmmintrin.h 中提供),那么您可以使用 _mm_movemask_ps(__m128) 及其亲戚。例如

__m128 a,b;
/* some code to fill a,b with integer elements */
bool a_equals_b = 15 == _mm_movemask_ps(_mm_cmpeq_epi32(a,b));

这段代码的工作原理如下。首先,_mm_cmpeq_ps(a,b) 生成另一个 __m128,其中四个元素中的每一个都为全 0 位或全位 1 – 我假设 operator== 对于编译器生成的 vector 扩展调用正是这个内在的)。接下来,int _mm_movemask_ps(__m128) 返回一个整数,第 k 位设置为其参数的第 k 个元素的符号位。因此,如果所有元素都为 a==b,则 _mm_movemask_ps(_mm_cmpeq_epi32(a,b)) 返回 1|2|4|8=15.

我不知道编译器支持的语言扩展,但如果你可以获得底层的 __m128(对于 128 位宽 vector ),那么你可以使用这种方法(可能只是调用_mm_movemask_ps()).

关于c++ - C++ 中的 Clang vector 扩展和相等运算符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29464942/

相关文章:

C++ fstream 输出错误的数据

include - 如何使用 clang libtooling 获取 #includes 的源位置?

ios - 链接同一库的两个版本(相同的符号)

x86-64 - 所有 64 位英特尔架构都支持 SSSE3/SSE4.1/SSE4.2 指令吗?

c++ - “… already defined in *.obj”,但我没有在同一范围内两次定义任何变量

c++ - Golang 中 binary.write 的 C++ 等价物是什么?

c++ - 为什么 GCC 错误地检测到移位计数溢出?

cuda - CUDA 可以使用 SIMD 扩展吗?

iphone - 在 iPhone 上使用 ARM SIMD 进行游戏向量/矩阵运算的正确方法是什么?

c++ - 从类成员获取类型