- полностью безопасен со всеми уровнями оптимизации: нет нарушения строгого псевдонима UB
- напечатать в шестнадцатеричном формате как элементы u8, u16, u32 или u64 (на основе ответа @ AG1 < / а>)
- Печатает в порядке памяти (сначала наименее значимый элемент, например
_mm_setr_epiX
). Переверните индексы массива, если вы предпочитаете печатать в том же порядке, что и в руководствах Intel, где наиболее значимый элемент находится слева (например, _mm_set_epiX
). Связано: Соглашение об отображении векторных регистров
- Я знаю, что этот вопрос помечен тегом C, но это был лучший результат поиска также при поиске решения C ++ для той же проблемы.
Использование __m128i*
для загрузки из массива int
безопасно, потому что типы __m128
определены так, чтобы разрешить наложение, как и ISO C unsigned char*
. (например, в заголовках gcc определение включает __attribute__((may_alias))
.)
Обратное небезопасно (указывает int*
на часть объекта __m128i
). MSVC гарантирует, что это безопасно, но GCC / clang - нет. (-fstrict-aliasing
включен по умолчанию). Иногда это работает с GCC / clang, но зачем рисковать? Иногда это даже мешает оптимизации; см. этот вопрос и ответ. См. Также Переинтерпретирует_кастирование между аппаратными SIMD указатель вектора и соответствующий тип неопределенного поведения?
(uint32_t*) &my_vector
нарушает правила псевдонимов C и C ++, и его работа не гарантируется должным образом. Сохранение в локальном массиве и последующий доступ к нему гарантированно безопасны. Он даже оптимизируется вместе с большинством компиляторов, поэтому вы получаете movq
/ pextrq
непосредственно из xmm в целочисленные регистры вместо, например, фактического сохранения / перезагрузки.
Если вам нужна переносимость на C99 или C ++ 03 или более раннюю версию (то есть без C11 / C ++ 11), удалите _ 15_ и используйте storeu
вместо store
. Или используйте вместо этого __attribute__((aligned(16)))
или __declspec( align(16) )
.
#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]);
}
(Если вы пишете код с встроенными функциями, вам следует использовать последнюю версию компилятора. Новые компиляторы обычно лучше, чем старые компиляторы, в том числе для встроенных функций SSE / AVX. Но, возможно, вы захотите использовать gcc-6.3 с -std=gnu++03
C ++ 03 для кодовой базы, которая не готова для C ++ 11 или чего-то подобного.)
Пример вывода всех 4 функций на
Отрегулируйте строки формата, если вы хотите дополнить их ведущими нулями для обеспечения согласованной ширины вывода. См. printf(3)
.
// 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
Переносится через gcc / clang / ICC / MSVC, C и C ++.
person
Peter Cordes
schedule
15.10.2017
0
наc = a + (b & mask)
, если хотите int. - person Peter Cordes   schedule 17.04.2016