Вывести переменную __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
4 ответа
Используйте эту функцию, чтобы напечатать их:
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++.
- полностью безопасен со всеми уровнями оптимизации: нет наложения указателей (в отличие от большинства других ответов)
- печатать в шестнадцатеричном виде как элементы u8, u16, u32 или u64 ( на основе ответа @AG1)
- Печатает в порядке памяти (сначала наименее значимый элемент, например
_mm_setr_epiX
). Поменяйте местами индексы массива, если вы предпочитаете печатать в том же порядке, в котором используются руководства Intel, где наиболее значимый элемент находится слева (например,_mm_set_epiX
). Связанный: Конвенция для отображения векторных регистров
Используя __m128i*
загрузить из массива int
безопасно, потому что __m128
типы определены, чтобы позволить псевдонимы. (например, в заголовках gcc определение включает __attribute__((may_alias))
.)
Обратное не безопасно (__m128i
объект и int
указатель). Это может сработать в большинстве случаев, но зачем рисковать?
(uint32_t*) &my_vector
нарушает правила псевдонимов C и C++ и не гарантирует, что будет работать так, как вы ожидаете. Хранение в локальном массиве и последующий доступ к нему гарантированно безопасны. Он даже оптимизирует работу с большинством компиляторов, так что вы получите movq
/ pextrq
например, непосредственно из xmm в целочисленные регистры вместо фактического сохранения / перезагрузки.
Исходный код + вывод asm в проводнике компилятора Godbolt: доказательство того, что он компилируется с 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 с -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 <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)
см. /questions/45183338/kak-vyivesti-simvol-v-vide-tselogo-chisla-cherez-cout/45183362#45183362
#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;
}
Попробуйте этот код.