打印__m128i变量

我正在尝试学习使用内在函数进行编码,下面是一个添加代码的代码

compiler used: icc

 #include #include int main() { __m128i a = _mm_set_epi32(1,2,3,4); __m128i b = _mm_set_epi32(1,2,3,4); __m128i c; c = _mm_add_epi32(a,b); printf("%d\n",c[2]); return 0; } 

我得到以下错误:

 test.c(9): error: expression must have pointer-to-object type printf("%d\n",c[2]); 

如何在变量c打印__m128i类型的__m128i

使用此function打印它们:

 void print128_num(__m128i var) { uint16_t *val = (uint16_t*) &var; printf("Numerical: %i %i %i %i %i %i %i %i \n", val[0], val[1], val[2], val[3], val[4], val[5], val[6], val[7]); } 

在打印之前将128位分成16位(或32位)。

如果您有64位支持,这是一种64位拆分和打印方式:

 void print128_num(__m128i var) { int64_t *v64val = (int64_t*) &var; printf("%.16llx %.16llx\n", v64val[1], v64val[0]); } 
  • 可移植到gcc / clang / ICC / MSVC,C和C ++。
  • 完全安全的所有优化级别:无指针别名 (与大多数其他答案不同)
  • 以hex打印为u8,u16,u32或u64元素( 基于@ AG1的答案 )
  • 以内存顺序打印(首先是最不重要的元素,如_mm_setr_epiX )。 如果您希望以英特尔手册使用的相同顺序打印,则反转数组索引,其中最重要的元素位于左侧(如_mm_set_epiX )。 相关: 用于显示向量寄存器的约定

使用__m128i*int数组加载是安全的,因为__m128类型被定义为允许别名。 (例如,在gcc的头文件中,定义包括__attribute__((may_alias)) 。)

反向不安全( __m128i对象和int指针)。 在大多数情况下它可能会起作用,但为什么要冒风险呢?

(uint32_t*) &my_vector违反了C和C ++别名规则,并且无法保证以您期望的方式工作 。 存储到本地arrays然后访问它是保证安全的。 它甚至可以通过大多数编译器进行优化,因此您可以将movq / pextrq直接从xmm寄存到整数寄存器,而不是实际存储/重新加载。

Godbolt编译器资源管理器上的Source + asm输出 :certificate它与MSVC编译等等。

 #include  #include  #include  #ifndef __cplusplus #include  // C11 defines _Alignas(). This header defines alignas() #endif void p128_hex_u8(__m128i in) { alignas(16) uint8_t v[16]; _mm_store_si128((__m128i*)v, in); printf("v16_u8: %x %x %x %x | %x %x %x %x | %x %x %x %x | %x %x %x %x\n", v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11], v[12], v[13], v[14], v[15]); } void p128_hex_u16(__m128i in) { alignas(16) uint16_t v[8]; _mm_store_si128((__m128i*)v, in); printf("v8_u16: %x %x %x %x, %x %x %x %x\n", v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]); } void p128_hex_u32(__m128i in) { alignas(16) uint32_t v[4]; _mm_store_si128((__m128i*)v, in); printf("v4_u32: %x %x %x %x\n", v[0], v[1], v[2], v[3]); } void p128_hex_u64(__m128i in) { alignas(16) unsigned long long v[2]; // uint64_t might give format-string warnings with %llx; it's just long in some ABIs _mm_store_si128((__m128i*)v, in); printf("v2_u64: %llx %llx\n", v[0], v[1]); } 

如果您需要可移植到C99或C ++ 03或更早版本(即没有C11 / C ++ 11),请删除alignas()并使用storeu而不是store 。 或者使用__attribute__((aligned(16)))__declspec( align(16) )代替。

(如果您正在使用内在函数编写代码,那么您应该使用最新的编译器版本。较新的编译器通常比旧版编译器更好,包括SSE / AVX内在函数。但是也许你想使用gcc-6.3和-std=gnu++03 C ++ 03模式,用于尚未为C ++ 11或其他东西做好准备的代码库。)


调用所有4个函数的示例输出

 // source used: __m128i vec = _mm_setr_epi8(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); // output: v2_u64: 0x807060504030201 0x100f0e0d0c0b0a09 v4_u32: 0x4030201 0x8070605 0xc0b0a09 0x100f0e0d v8_u16: 0x201 0x403 0x605 0x807 | 0xa09 0xc0b 0xe0d 0x100f v16_u8: 0x1 0x2 0x3 0x4 | 0x5 0x6 0x7 0x8 | 0x9 0xa 0xb 0xc | 0xd 0xe 0xf 0x10 

如果要使用前导零填充以获得一致的输出宽度,请调整格式字符串。 见printf(3)

我知道这个问题标记为C,但在寻找同一问题的C ++解决方案时,它也是最好的搜索结果。

所以,这可能是一个C ++实现:

 #include  #include  #include  #if defined(__SSE2__) template  std::string __m128i_toString(const __m128i var) { std::stringstream sstr; T values[16/sizeof(T)]; std::memcpy(values,&var,sizeof(values)); //See discussion below if (sizeof(T) == 1) { for (unsigned int i = 0; i < sizeof(__m128i); i++) { //C++11: Range for also possible sstr << (int) values[i] << " "; } } else { for (unsigned int i = 0; i < sizeof(__m128i) / sizeof(T); i++) { //C++11: Range for also possible sstr << values[i] << " "; } } return sstr.str(); } #endif 

用法:

 #include  [..] __m128i x [..] std::cout << __m128i_toString(x) << std::endl; std::cout << __m128i_toString(x) << std::endl; std::cout << __m128i_toString(x) << std::endl; std::cout << __m128i_toString(x) << std::endl; 

结果:

 141 114 0 0 0 0 0 0 151 104 0 0 0 0 0 0 29325 0 0 0 26775 0 0 0 29325 0 26775 0 29325 26775 

注意:有一种简单的方法可以避免if (size(T)==1) ,请参阅https://stackoverflow.com/a/28414758/2436175

 #include #include int main() { __m128i a = _mm_set_epi32(1,2,3,4); __m128i b = _mm_set_epi32(1,2,3,4); __m128i c; const int32_t* q; //add a pointer c = _mm_add_epi32(a,b); q = (const int32_t*) &c; printf("%d\n",q[2]); //printf("%d\n",c[2]); return 0; } 

试试这个代码。