__int128 ошибка сегмента выравнивания с gcc -O SSE optimize - PullRequest
0 голосов
/ 27 сентября 2018

Я использую __int128 в качестве члена структуры.Работает поиск с -O0 (без оптимизации).

Однако происходит сбой при сбое сегмента, если включена оптимизация (-O1).

Сбой при выполнении инструкции movdqa, которая требуетvar выровнен на 16. Хотя адрес выделен malloc(), который выровнен только на 8.

Я попытался отключить оптимизацию SSE на -mno-sse, но он не компилируется:

/usr/include/x86_64-linux-gnu/bits/stdlib-float.h:27:1: error: SSE register return with SSE disabled

Так что же я могу сделать, если я хочу использовать __int128 и -O1 оба?

Заранее спасибо Wu

Кстати, кажется, что все в порядке, если __int128 используется только настек (не в куче).

==== РЕДАКТИРОВАТЬ ====

Извините, что я не сказал правду.

На самом деле я не использовал malloc().Я использовал библиотеку пула памяти, которая возвращает адрес, выровненный по 8. Я сказал malloc(), просто чтобы упростить задачу.

После тестирования я понял, что malloc() выравнивается по 16. И __int128 элемент также выровнен на 16 в структуре.

Так что проблема заключается только в моей библиотеке пулов памяти.

Большое спасибо.

1 Ответ

0 голосов
/ 27 сентября 2018

Для x86-64 System V, alignof(maxalign_t) == 16, поэтому malloc всегда возвращает 16-байтовые выровненные указатели.Похоже, ваш распределитель не работает и будет нарушать ABI, если используется также для long double.(Повторно отправив это как ответ, поскольку выясняется, что было ответом.)

Память, возвращаемая malloc, гарантированно может содержать любой стандартный тип, что означает выравниваниедостаточно, если размер достаточно велик.

Это не может быть 32-битный код, потому что gcc не поддерживает __int128 в 32-битных целях.(32-битный glibc malloc гарантирует только 8-байтовое выравнивание.)


В общем, компилятору разрешается создавать код, который дает сбой, если вы нарушаете требования к выравниванию типов.На x86 все обычно работает с не выровненной памятью, пока компилятор не использует необходимые SIMD инструкции для выравнивания.Даже автоматическая векторизация с неправильным выравниванием uint16_t* может привести к сбою ( Почему невыровненный доступ к памяти mmap иногда вызывает ошибку по умолчанию на AMD64? ), поэтому не думайте, что узкие типы всегда безопасны.Используйте memcpy, если вам нужно выразить невыровненную нагрузку в C.


Очевидно, alignof(__int128) равно 16. Таким образом, они не повторяют странности из i386 System V, где даже 8-байтовые объекты являютсяТолько гарантированное 4-байтовое выравнивание и правила упаковки структуры означают, что компиляторы не могут дать им естественное выравнивание.

Это хорошо, потому что это делает его эффективным для копирования с SSE, а значит _Atomic __int128не требуется никакой дополнительной специальной обработки, чтобы избежать разбиения строки кэша, что делает lock cmpxchg16b очень медленным.

...