DevilDevil
> Cмогу ли я включить SSE-оптимизацию для конкретных функций?
Функции с SSE-оптимизацией нужно писать в файлах, которые будут собираться с поддержкой SSE. Нормальный компилятор в рамках одного объектного модуля не будет переключать режим кодогенерации.
Даже тот кто занимается кроссплатформенной сборкой в промышленном масштабе по виду триплета цели не сможет точно сказать про возможные ошибки в ней. Сlang почему-то принимает цели, которые не имеют никакого смысла и при этом, даже, ничего не сообщает. Это называется нестрогой типизацией с согласием на всё. Например:
clang -target i686-w -c main.c clang -target i686-wr -c main.c clang -target i686-wro -c main.c clang -target i686-wron -c main.c clang -target i686-wrong -c main.c clang -target arm64-something-wrong -c main.c
Для параметра arch вместо armv7-a правильно писать armv7 — без дефиса. Дефис разделяет параметры триплета цели triple == arch(sub)-pc-sys-abi. Иначе появляется двусмысленность.
Вот, например, триплеты из документации по сборке под Андроид:
ABI Triple
armeabi-v7a armv7a-linux-androideabi
arm64-v8a aarch64-linux-android
x86 i686-linux-android
x86-64 x86_64-linux-android
Что в итоге компилируется, можно смотреть в листинге получаемом через -S. Там нужно искать поля касающиеся CPU, системы команд и версии OS. Ещё важно знать, что Apple для обозначения архитектуры Aarch64 использует символ arm64.
clang -target arm64-apple-ios7 -S main.c -> main.S clang -target arm64-apple-ios8.1 -S main.c clang -target i686-apple-macos10.6 -S main.c
С хлипкостью bat-файла всё понятно. После того как он написан неверно, найти в нём ошибку будет сложнее, чем написать заново. Но вот этим всем -mno-sse, -mthumb место, очевидно, не в таргете, а во флагах.
Вообще, правильно начинать с построения исполнительного файла хотя бы для одного таргета.
CgReligion
Я на Годболте проверяю кодогенерацию. Получается что-то похожее на требуемое
Кстати вот такое не собирается:
-target armv7a-darwin-gnu -mthumb -c -O3
DevilDevil
> Кстати вот такое не собирается:
-target armv7a-darwin-gnu -mthumb -c -O3
Там архитектуру команд нужно другую задать armv7m:
-target armv7m-darwin-gnu -mthumb -c -O3
> Возникла трабла со стрековыми фреймами под MacOS. Какими атрибутами их отключить?
Отключается через -fomit-frame-pointer.
CgReligion
А ты не мог бы проверить работоспобность такой конструкции? Интрисинки NEON будут доступны?
CgReligion
> Отключается через -fomit-frame-pointer
Это опять для всего кода. Мне нужно для конкретных функций
DevilDevil
> А ты не мог бы проверить работоспобность такой конструкции? Интрисинки NEON будут доступны?
Clang может компилировать код для всех поддерживаемых архитектур, но нужно внимательно изучать документацию по нему. Код с поддержкой NEON компилируется, например, следующими заклинаниями:
$ clang -target armv7m-none-ios-gnueabi -mfpu=neon -mfloat-abi=hard -S main.c $ clang -target armv7m-darwin -mfpu=neon -mfloat-abi=softfp -S main.c #include <arm_neon.h> void add3(uint8x16_t *data) { uint8x16_t three = vmovq_n_u8(3); *data = vaddq_u8(*data, three); }
> Это опять для всего кода. Мне нужно для конкретных функций
Для конкретных функций нужно писать свой маленький, тёплый, ламповый кодогенератор. Но, например, Apple в продакшене за это строго преследует.
CgReligion
1. Спасибо, что протестировал NEON
2. Но что в итоге выставить для 32-битных Android и iOS, чтобы поддерживался NEON и набор команд thumb-2?
3. Вопрос фрейма стека и SSE - они примерно одного контекста. Я хочу использовать интрисинки SSE и генерировать фреймы стека для MacOS, но мне нужно разделять: общие настройки всего проекта и особые фичи для отдельных функций. Си всегда позиционировался как низкоуровневый язык. У меня как раз низкоуровневая задача. Я не хочу отказываться от стандартных фреймов для всего проекта, если отказ от них мне нужен в 1-2 функциях. Я не хочу одни c-файлы собирать с одними настройками, а другие - с другими. По логике это должны быть атрибуты или временные опции типа #pragma pack(push, 1) / #pragma pack(pop). Как этого добиться?
DevilDevil
Для генерации инструкций NEON и thumb-2, очевидно, нужно передать компилятору флаги -mfpu=neon и -mthumb. Там в источнике выше сказано:
Все кристаллы ARMv7 поддерживают набор команд Thumb-2, а некоторые кристаллы, вроде Cortex-m3, поддерживают только Thumb-2. Остальные кристаллы Cortex и ARM11 поддерживают наборы команд как Thumb-2, так и ARM.
То есть любой современный компилятор будет использовать кодирование Thumb-2 для всех процессоров ARMv7*, если указана опция -mthumb либо её аналог.
> Я не хочу одни c-файлы собирать с одними настройками, а другие - с другими. По логике это должны быть атрибуты или временные опции типа.
Так они есть. Например, переключать набор инструкций для кодогенерации можно через пару.
#pragma clang attribute push(__attribute__( ( target( "sse4, avx"))), apply_to=function) ... #pragma clang attribute pop
Но изменить режим генерации кода на FPU нельзя, потому как он сильное легаси из 80-х годов.
PS: Оказывается, включить генерацию только FPU-команд тоже можно:
#pragma clang attribute push(__attribute__( ( target( "no-sse"))), apply_to=function)
CgReligion
Так.
С этого места поподробнее :)
Смотри. ARM с поддержкой NEON может быть как минимум в 3х режимах: ARM, Thumb и Thumb-2. Ты говоришь, что при флаге -mthumb он генерирует Thumb-2. А если я захочу генерировать обычный Thumb, какие флаги выставить?
Теперь по поводу SSE.
Хочешь сказать при флаге -mno-sse через #pragma clang attribute push нельзя будет задать режим SSE? Уже проверял?
Самое интересное. Т.е. я как-то могу задать -fomit-frame-pointer через #pragma clang attribute push ?
DevilDevil
> А если я захочу генерировать обычный Thumb, какие флаги выставить?
Тогда нужно указывать тот же самый флаг -mthumb, но другую архитектуру/процессор. Thumb вроде бы используется в настоящее время только в микроконтроллерах на Cortex-M0 и им подобных.
>Хочешь сказать при флаге -mno-sse через #pragma clang attribute push нельзя будет задать режим SSE?
Оказывается, что можно. Но там синтаксис сложнее:
#pragma clang attribute push(__attribute__( ( target( "no-sse"))), apply_to=function)
CgReligion
Наоборот. Если по дефолту, -mno-sse, то для локальных функций так получается?
__attribute__((target("sse"))
Что с -fomit-frame-pointer?
В идеале конечно делать его. Но вот я думаю, если не получится, может локально менять triple на линуксовый вместо макосьного?
DevilDevil
Да, так. Всё это нужно постоянно проверять. Потом во всех этих низкоуровневых деталях можно просто потеряться.
> Но вот я думаю, если не получится, может локально менять triple на линуксовый вместо макосьного?
Это смотря какие цели преследуются. Объектные файлы у них разные, потому как это разные системы и они точно будут несовместимы.
CgReligion
Ок. Тогда как отключить фрейм стека для конкретных функций под макосью?
DevilDevil
> Тогда как отключить фрейм стека для конкретных функций под макосью?
Вообще это требует исследований. Но для 32-битного кода можно как-то так:
__attribute(( naked)) int foo( ) { asm( "movl $100, %eax"); asm( "retl"); }
У меня есть большие подозрения, что это совсем не то чего хотелось бы, но non-ASM statement in naked function is not supported.
Тема в архиве.