programing

__m128i 변수 인쇄

skycolor 2023. 10. 24. 21:09
반응형

__m128i 변수 인쇄

나는 고유성을 이용하여 코딩하는 것을 배우려고 노력하고 있고 아래는 추가를 하는 코드입니다.

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

다음 기능을 사용하여 인쇄합니다.

#include <stdint.h>
#include <string.h>

void print128_num(__m128i var)
{
    uint16_t val[8];
    memcpy(val, &var, sizeof(val));
    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비트를 분할하여 인쇄하는 방법입니다.

#include <inttypes.h>

void print128_num(__m128i var) 
{
    int64_t v64val[2];
    memcpy(v64val, &var, sizeof(v64val));
    printf("%.16llx %.16llx\n", v64val[1], v64val[0]);
}

참고: 캐스팅&var직접적으로int*아니면uint16_t*MSVC도 작동하지만 이는 엄격한 앨리어싱을 위반하며 정의되지 않은 동작입니다.사용.memcpy는 동일한 작업을 수행하는 표준 준수 방식이며 최소 최적화를 통해 컴파일러는 정확히 동일한 이진 코드를 생성합니다.

  • gcc/clang/ICC/MSVC, C 및 C++에서 휴대 가능.
  • 모든 최적화 수준에서 완벽하게 안전: 엄격한 앨리어싱 위반 UB 없음
  • hexas u8, u16, u32 또는 u64 요소로 인쇄(@AG1의 답변 기준)
  • 메모리 순서로 인쇄합니다(가장 중요하지 않은 요소 먼저)._mm_setr_epiX인텔의 매뉴얼이 사용하는 것과 같은 순서로 인쇄하고 싶다면 배열 인덱스를 반대로 합니다. 가장 중요한 요소는 왼쪽에 있습니다(예:_mm_set_epiX) 관련:벡터 레지스터를 표시하는 규약

A를 사용.__m128i*일련의 것에서 로드하다int안전하기 때문에__m128ISO C와 마찬가지로 앨리어싱을 허용하도록 유형이 정의됩니다.unsigned char*. (예: gcc의 헤더에서, 그 정의는 다음을 포함합니다.__attribute__((may_alias)).)

은 안전하지 않습니다. (안을 가리키며)int*의 일부에__m128i목적어).MSVC는 그것이 안전하다고 보장하지만 GCC/clang은 그렇지 않습니다. (-fstrict-aliasing는 기본적으로 켜져 있습니다.GCC/clang과 함께 작동하는 경우도 있지만, 왜 위험을 감수해야 합니까?때로는 최적화에 방해가 되기도 합니다. 이 Q&A를 참조하십시오.참고 항목 하드웨어 SIMD 벡터 포인터와 해당 유형 간의 'reinterpret_casting'이 정의되지 않은 동작입니까?

GCC AVX_m256i cast to int array는 다음을 가리키는 GCC breaking code의 실제 예에 대해 잘못된 값으로 이어집니다.int*__m256i.


(uint32_t*) &my_vector 는 C 및 C++ 에일리어싱 규칙을 위반하며, 사용자가 기대하는 대로 작동할 것을 보장받지 못합니다.로컬 어레이에 저장한 다음 액세스하면 안전합니다.대부분의 컴파일러에서 최적화를 수행하기 때문에movq/pextrq예를 들어, 실제 저장소/reload 대신 xmm에서 정수 레지스터로 직접 이동합니다.

Godbolt 컴파일러 탐색기의 소스 + asm 출력: 증명 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 없음)으로 휴대성이 필요한 경우 를 제거하고 사용합니다.storeu대신에store. 아니면 사용__attribute__((aligned(16)))아니면__declspec( align(16) )대신.

(만약 당신이 고유성을 가진 코드를 쓴다면, 당신은 최신 컴파일러 버전을 사용해야 합니다.최신 컴파일러는 SSE/AVX 고유의 경우를 포함하여 이전 컴파일러보다 더 나은 ASM을 만듭니다.은 gcc-6과 도 있습니다.3을 사용하고 싶을 것입니다.-std=gnu++03C++11 같은 것을 위해 준비되지 않은 코드베이스를 위한 C++03 모드.)


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

일관된 출력 폭을 위해 선행 0으로 패딩하려면 형식 문자열을 조정합니다.보세요.

이 문제는 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 를 참조하십시오.

#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;
}

이 코드를 사용해 보세요.

언급URL : https://stackoverflow.com/questions/13257166/print-a-m128i-variable

반응형