CgReligion
Я бы с тобой согласился, если бы при атрибуте ms_abi они показывали одинаковый результат:
https://godbolt.org/z/q6MyvQ
DevilDevil
Можно предположить, что причина различия здесь совсем в другом. Проведённые некоторые исследования только подтверждают то, что написано выше. Кстати, если компилировать пример GCC, то для всех версий последнего получится идентичный код. Значение выталкивается из st(0) и сохраняется в памяти. При компиляции clang с таргетом смотрящим в сторону Linux такого не происходит, даже, при использовании атрибута __attribute__ ((ms_abi)).
сlang для передачи из функции значения long double задействует регистр st(0), то есть использует специальное соглашение для типа long double. И здесь вроде бы происходит нарушение соглашения о вызовах Windows x64. При этом там тип long double точно не определен, но в большинстве случаев он трактуется, как double. сlang же генерирует код со своим собственным специальным соглашение для long double с которым он (и только он) знает, как работать. Это особенность компилятора в рамках выбранной реализации в полном соответствии со Стандартом языка. И вообще, компилятор не обязан создавать совместимый код для двоично несовместимых с OC типов. При этом сlang будет генерировать полностью ABI-совместимый код для Windows x64, если long double мутанта спрятать так, чтобы он его не видел:
typedef struct b16 { char s[16]; } b16; __attribute__ (( ms_abi)) b16 test( ) { long double x = 0; return *( b16*)&x; }
Можно так же добавить, что long double прямо не отображается ни в один из известных типов IEEE 754. Поэтому он определятся компилятором и в разных ситуация это определение может отличаться.
CgReligion
Я не знаю, офтоп это или нет, но если есть какой-то таргет, которым можно убрать дефолтное выравнивание функций - я с удовольствием выслушаю. По крайней мере флаг -falign-functions=4 не работает.
Описание проблемы: https://stackoverflow.com/questions/58754551/clang-functions-aligning
DevilDevil
Указанный флаг компиляции -falign-functions к таргету вообще никакого отношения не имеет. Это флаг, который просит компилятор сделать что-то, если тот предоставляет такую возможность. Обращение к невыровненным данным приводит к задержке исполнения, а на некоторых архитектурах к возникновению аппаратного исключения. Поэтому обычно требуется выравнивание, а не его отсутствие. Если компилятор не поддерживает флаг -falign-functions, значит у него есть основания так поступать. И вообще он лучше знает, что, как, в каком порядке и где расставлять. Конкретные адреса размещения функций и выравнивание особенно, относятся к конкретной реализации и от них ничего не должно зависеть. Контроль над ними находится точно уровнем ниже.
CgReligion
Просто на GCC можно сделать выравнивание, а на Clang не понятно, как это сделать )
DevilDevil
В сlang функции выравниваются на границу 16 байт и это нельзя изменить. Это связанно с особенностями реализации указателей на функции-члены класса в C++ ABI. Они определяются двум указателями. Выравнивание адресов функций С, по всей видимости, было захвачено заодно. Но в этом ничего плохого нет, потому как выравнивание — это хорошо.
CgReligion
Я привёл пример, когда выравнивание это плохо. И очень жаль. Может быть придётся мучать GCC )
DevilDevil
Здесь внезапно обнаружилось заклинание, которое воздействует на адреса функций:
-mllvm -align-all-functions=n где alignment = 2^n, n >= 1
Но полагаться на всё это в длительной перспективе вряд ли стоит.
CgReligion
Да
Сделал параметр 16 и офигел :)
Выравнивание на 4 байта получилось при параметре 2
Ок
А можно как-то это применить локально для определённого набора функций?
DevilDevil
Можно. Тогда определённый набор функций нужно разместить локально в одном файле и откомпилировать, с заданными флагами или без, в зависимости от того к какому множеству он относится.
CgReligion
Не, у меня один скрипт на все файлы
Я имел ввиду через атрибуты или прагму как-то
Друзья, тут всплыла ещё одна особенность, которую хотелось бы устранить
Допустим, у нас платформа Win32, есть функция, которая возвращает 8 байт
Когда возвращается int64_t - нормально возвращаться в паре EAX:EDX
Но если это структура - результат должен передаваться через скрытый указатель
В нашем же примере это условие не только не выполняется, но ещё и зависит от состава структуры. Что с этим можно сделать? На уровне опций компилятора имею ввиду :)
typedef struct { char values[8]; } char_struct; typedef struct { double value; } double_struct; char_struct char_test() { char_struct ret; ret.values[0] = sizeof( int_struct); ret.values[1] = sizeof( double_struct); ret.values[2] = sizeof( char_struct); return ret; } double_struct double_test( ) { double_struct ret; ret.value = 1; return ret; }
Дизасм:
_char_test: # @char_test mov eax, 526344 xor edx, edx ret _double_test: # @double_test fld1 ret
Кстати на линуксе работает правильно, а вот на винде и маке нет:
https://godbolt.org/z/CZmQAY
Всем привет
Возникли ещё вопросы по таргетам
На текущий момент использую следующие опции компилятора:
-target i386-windows-gnu -mno-sse -c -O3
-target x86_64-windows-gnu -mcx16 -c -O3
-target i386-linux-gnu -mno-sse -c -O3
-target x86_64-linux-gnu -mcx16 -c -O3
-target i386-darwin-gnu -mno-sse -fomit-frame-pointer -c -O3
-target x86_64-macos-gnu -fomit-frame-pointer -c -O3
-target armv7-none-linux-androideabi -mfpu=neon -mfloat-abi=hard -mthumb -fPIC -c -O3
-target aarch64-linux-android -c -O3
-target armv7m-none-ios-gnueabi -mfpu=neon -mfloat-abi=hard -mthumb -c -O3
-target arm64-darwin-gnu -fno-stack-protector -c -O3
Нареканий нет только по Линуксу/Андроиду. Для остальных платформ выдаёт ворнинг (https://godbolt.org/z/YhZ5uc). Раньше я думал, что дело в других аргументах кроме -target, но если их убрать - ничего не меняется:
clang-9: warning: argument unused during compilation: '--gcc-toolchain=/opt/compiler-explorer/gcc-9.2.0' [-Wunused-command-line-argument]
Compiler returned: 0
Эта история хотя бы компилится. Для Mac/iOS начинается история с неподдержкой TLS-переменных (https://godbolt.org/z/6bqjby):
Чё с этим делать?
up? )
Тема в архиве.