Требования выравнивания для uint8x16_t, загружаемого из байтового массива?

arm memory-alignment neon intrinsics

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_t128-битных ARM NEON векторные типы данных, которые , как ожидается, будет помещен в регистр Q . vld1q_u8является псевдоинструкцией NEON, которая, как ожидается, будет скомпилирована в VLD1.8инструкцию. vreinterpretq_u64_u8является псевдоинструкцией NEON, которая облегчает использование типов данных.

Автор: jww Источник Размещён: 31.10.2019 05:08

Ответы (3)


4 плюса

При написании прямого ассемблера (как встроенного, так и во внешних файлах) вы можете выбрать, хотите ли вы указать выравнивание (например vld1.8 {q0}, [r0, :64]) или пропустить его (например vld1.8 {q0}, [r0]). Если он не указан, он вообще не требует какого-либо конкретного выравнивания, как говорит Dric512.

При использовании vld1q_u8через intrinsics вы никогда не указываете выравнивание, так что, насколько я знаю, компилятор не принимает это и выдает инструкцию без спецификации выравнивания. Я не уверен, что некоторые компиляторы могут вывести некоторые случаи, когда выравнивание фактически гарантировано, и использовать спецификатор выравнивания в этих случаях. (Похоже, что и gcc, clang и MSVC производят vld1.8без спецификаторов выравнивания в данном конкретном случае.)

Обратите внимание, что это проблема только 32-битной руки; в AArch64 нет спецификатора выравнивания для ld1инструкции. Но даже в этом случае выравнивание все еще очевидно помогает, вы получите худшую производительность, если будете использовать ее с невыровненными адресами.

Автор: mstorsjo Размещён: 31.05.2016 06:07

3 плюса

Естественное выравнивание VLD1.8инструкции, загружающей 16 байтов в регистр Quad, является байтом. Это означает, что даже если не выровненные переводы не разрешены, эта инструкция не может быть ошибочной.

Похоже, это конкретное утверждение неверно.

Автор: Dric512 Размещён: 28.05.2016 08:09

2 плюса

Если посмотреть на это с другой стороны, вот фактическое определение этого типа с точки зрения одного примера компилятора (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-байтовому выравниванию, что может привести к значительным ошибкам.

Автор: Notlikethat Размещён: 01.06.2016 10:38
Вопросы из категории :
32x32