打印__m128i变量

时间:2012-11-06 18:34:34

标签: c assembly sse simd intrinsics

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

的代码

compiler used: icc

#include<stdio.h>
#include<emmintrin.h>
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中打印值

4 个答案:

答案 0 :(得分:21)

使用此功能打印它们:

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]);
}

答案 1 :(得分:9)

  • 可移植到gcc / clang / ICC / MSVC,C和C ++。
  • 所有优化级别完全安全:无指针别名(与大多数其他答案不同)
  • 以十六进制打印为u8,u16,u32或u64元素(based on @AG1's answer
  • 以内存顺序打印(首先是最不重要的元素,如_mm_setr_epiX)。如果您希望以英特尔手册使用的相同顺序打印,则反转数组索引,其中最重要的元素位于左侧(如_mm_set_epiX)。相关:Convention for displaying vector registers

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

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

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

Source + asm output on the Godbolt compiler explorer:证明它与MSVC编译等等。

#include <immintrin.h>
#include <stdint.h>
#include <stdio.h>

#ifndef __cplusplus
#include <stdalign.h>   // 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和{ {1}} C ++ 03模式,用于尚未为C ++ 11或其他东西做好准备的代码库。)

调用

上所有4个函数的示例输出
-std=gnu++03

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

答案 2 :(得分:4)

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

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

#include <string>
#include <cstring>
#include <sstream>

#if defined(__SSE2__)
template <typename T>
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 <iostream>
[..]
__m128i x
[..]
std::cout << __m128i_toString<uint8_t>(x) << std::endl;
std::cout << __m128i_toString<uint16_t>(x) << std::endl;
std::cout << __m128i_toString<uint32_t>(x) << std::endl;
std::cout << __m128i_toString<uint64_t>(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

答案 3 :(得分:2)

#include<stdio.h>
#include<emmintrin.h>
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;
}

试试这段代码。