Требования выравнивания для uint8x16_t, загружаемого из байтового массива?
1309 просмотра
3 ответа
У нас есть запуск assert под сборками Debug, которые проверяют выравнивание. Утверждение для байтового массива, который загружен в uint8x16_t
использование vld1q_u8
. Пока утверждают пожары, мы не наблюдали SIG_BUS
.
Вот использование в коде:
const byte* input = ...;
...
assert(IsAlignedOn(input, GetAlignmentOf(uint8x16_t));
uint64x2_t message = vreinterpretq_u64_u8(vld1q_u8(input));
Я также попытался со следующим, и утверждают, что стрельба для выравнивания uint8_t*
:
assert(IsAlignedOn(input, GetAlignmentOf(uint8_t*));
uint64x2_t message = vreinterpretq_u64_u8(vld1q_u8(input));
Каковы требования к выравниванию массива байтов при загрузке его в uint8x16_t
с vld1q_u8
?
В приведенном выше коде, input
это параметр функции. IsAlignedOn
проверяет выравнивание двух своих аргументов, гарантируя, что первый выровнен по крайней мере ко второму. GetAlignmentOf
является абстракцией, которая извлекает выравнивание для типа или переменной.
uint8x16_t
и uint64x2_t
128-битных ARM NEON векторные типы данных, которые , как ожидается, будет помещен в регистр Q . vld1q_u8
является псевдоинструкцией NEON, которая, как ожидается, будет скомпилирована в VLD1.8
инструкцию. vreinterpretq_u64_u8
является псевдоинструкцией NEON, которая облегчает использование типов данных.
Ответы (3)
4 плюса
При написании прямого ассемблера (как встроенного, так и во внешних файлах) вы можете выбрать, хотите ли вы указать выравнивание (например vld1.8 {q0}, [r0, :64]
) или пропустить его (например vld1.8 {q0}, [r0]
). Если он не указан, он вообще не требует какого-либо конкретного выравнивания, как говорит Dric512.
При использовании vld1q_u8
через intrinsics вы никогда не указываете выравнивание, так что, насколько я знаю, компилятор не принимает это и выдает инструкцию без спецификации выравнивания. Я не уверен, что некоторые компиляторы могут вывести некоторые случаи, когда выравнивание фактически гарантировано, и использовать спецификатор выравнивания в этих случаях. (Похоже, что и gcc, clang и MSVC производят vld1.8
без спецификаторов выравнивания в данном конкретном случае.)
Обратите внимание, что это проблема только 32-битной руки; в AArch64 нет спецификатора выравнивания для ld1
инструкции. Но даже в этом случае выравнивание все еще очевидно помогает, вы получите худшую производительность, если будете использовать ее с невыровненными адресами.
3 плюса
Естественное выравнивание VLD1.8
инструкции, загружающей 16 байтов в регистр Quad, является байтом. Это означает, что даже если не выровненные переводы не разрешены, эта инструкция не может быть ошибочной.
Похоже, это конкретное утверждение неверно.
Автор: Dric512 Размещён: 28.05.2016 08:092 плюса
Если посмотреть на это с другой стороны, вот фактическое определение этого типа с точки зрения одного примера компилятора (Visual Studio 2015's arm_neon.h
):
typedef union __declspec(intrin_type) _ADVSIMD_ALIGN(8) __n128
{
unsigned __int64 n128_u64[2];
unsigned __int32 n128_u32[4];
unsigned __int16 n128_u16[8];
unsigned __int8 n128_u8[16];
__int64 n128_i64[2];
__int32 n128_i32[4];
__int16 n128_i16[8];
__int8 n128_i8[16];
float n128_f32[4];
struct
{
__n64 low64;
__n64 high64;
} DUMMYNEONSTRUCT;
} __n128;
...
typedef __n128 int8x16_t;
Так что, по крайней мере, на платформах Windows потребуется не меньше, чем выравнивание __int64
благодарности этому объединению, и от AAPCS, что означает 8 байтов (и даже без не очень сложного предположения о том, что _ADVSIMD_ALIGN(8)
могло бы означать ...) .)
Это даже более просто, чем это, потому что оказывается, что у AAPCS действительно есть последнее слово в этом непосредственно через его определение векторных типов в терминах контейнерных векторов (§4.1.2):
Содержимое контейнера в векторе непрозрачно для большинства стандартов вызова процедур: единственным определенным аспектом его компоновки является сопоставление между форматом памяти (способ хранения основного типа в памяти) и различными классами регистров при вызове процедуры интерфейс.
Другими словами, на уровне ABI векторный тип является векторным типом, независимо от того, что может или не может быть в нем, и как 64-битные, так и 128-битные контейнеризованные векторы требуют 8-байтового выравнивания, потому что ABI говорит об этом (§ 4,1). Таким образом, независимо от того, на что способны базовые инструкции, реализация Microsoft даже не слишком строга, как я изначально предполагал, она просто соответствует. Восемь должно быть числом, которое вы хотите выровнять, а число выровненных должно быть восемь .
С vld1q_u8()
другой стороны, аргументом является a uint8_t const *
, чьи указываемые данные не имеют требования к выравниванию, поэтому можно утверждать, что они удовлетворяют 8-байтовому выравниванию, что может привести к значительным ошибкам.
Вопросы из категории :
- arm Looking for an efficient integer square root algorithm for ARM Thumb2
- arm Как инструкции отличаются от данных?
- arm выравнивание памяти в структурах gcc
- arm Как использовать инструкцию MOV в ARM с непосредственным номером в качестве второго операнда
- arm Симулятор ARM в Windows
- memory-alignment Всегда ли члены класса / структуры создаются в памяти в порядке их объявления?
- memory-alignment Why can't C compilers rearrange struct members to eliminate alignment padding?
- memory-alignment Вопросы о распределителе стека Хиннанта
- memory-alignment Как определяется размер класса C ++?
- memory-alignment Нераспределенный доступ вызывает ошибку на ARM Cortex-M4
- neon ffmpeg для Android: неоновая сборка имеет перемещение текста
- neon ARM/neon memcpy optimized for *uncached* memory?
- neon Как помешать GCC взломать мою природу NEON?
- neon переупорядочение значений в 128-битном векторе в коде сборки arm neon
- neon Доступ к половине регистра в расширенной SIMD AArch64
- intrinsics C # быстрый расчет crc32:
- intrinsics 128-битное деление, присущее Visual C ++
- intrinsics SSE Загрузка и добавление
- intrinsics Как сохранить содержимое вектора simd __m128d как double, не обращаясь к нему как к объединению?
- intrinsics Получить член __m128 по индексу?