Эльбрус/lcc: различия между версиями
м (→-std=c++11: добавил по c++17) |
м (→система программирования: +sp-1.29) |
||
(не показаны 32 промежуточные версии 2 участников) | |||
Строка 5: | Строка 5: | ||
= lcc на e2k = | = lcc на e2k = | ||
Сразу оговорюсь: речь именно о ''родном'' режиме работы lcc, кроссовым (собирать для e2k, сидя на x86) мы не пользуемся. | Сразу оговорюсь: речь именно о ''родном'' режиме работы lcc, так как кроссовым (собирать для e2k, сидя на x86) мы не пользуемся. | ||
Основная часть проблем, возникающих при сборке рассчитанного на gcc программного обеспечения сводится к тому, что lcc -- это всё же ''не'' gcc, несмотря на выставленный <tt>__GNUC__</tt><ref> соответственно заявленной в {{cmd|`lcc -v`}} совместимой версии</ref>; в патчах можно проверять взведённый/заполненный <tt>[http://sourceforge.net/p/predef/mailman/message/37243657/ __LCC__]</tt><ref><tt>__LCC__ <= 123, например</tt></ref>, хотя порой даже проще прикинуться <tt>__ICC</tt> или <tt>__clang__</tt>, у которых во многом схожие ограничения -- начиная с того, что они тоже не gcc. | Основная часть проблем, возникающих при сборке рассчитанного на gcc программного обеспечения сводится к тому, что lcc -- это всё же ''не'' gcc, несмотря на выставленный <tt>__GNUC__</tt><ref> соответственно заявленной в {{cmd|`lcc -v`}} совместимой версии</ref>; в патчах можно проверять взведённый/заполненный <tt>[http://sourceforge.net/p/predef/mailman/message/37243657/ __LCC__]</tt><ref><tt>__LCC__ <= 123, например</tt></ref>, хотя порой даже проще прикинуться <tt>__ICC</tt> или <tt>__clang__</tt>, у которых во многом схожие ограничения -- начиная с того, что они тоже не gcc. | ||
С версии 1.25 LCC также взводит <tt>[http://github.com/a1batross/predef/blob/master/Compilers.md#mcst-lcc __MCST__]</tt>. | |||
В любом случае мы стараемся донести сообщения о проблемах до коллег, занимающихся lcc, ради возможности улучшения будущих версий. | В любом случае мы стараемся донести сообщения о проблемах до коллег, занимающихся lcc, ради возможности улучшения будущих версий. | ||
Строка 17: | Строка 19: | ||
== фронтэнд == | == фронтэнд == | ||
Надо понимать, что МЦСТ применяет в lcc сторонний фронтэнд | Надо понимать, что МЦСТ применяет в lcc сторонний фронтэнд EDG<ref>...соответственно взводит <tt>__EDG__</tt></ref>, как несколько раньше делал и Intel в своём icc. | ||
Собственно, в основном проблемы здесь -- и с новыми версиями стандартов вроде C++20 (стабилизируется lcc 1. | Собственно, в основном проблемы здесь -- и с новыми версиями стандартов вроде C++20 (стабилизируется lcc 1.26<ref>см. тж. вкладку "Характеристики" на [http://mcst.ru/lcc mcst.ru/lcc]:<br/>1.25 поддерживает C++11/C++14 и частично C++17/C++20;<br/>1.24 -- C++11/C++14 и частично C++17;<br/>1.23 -- C++11 и частично C++14,<br/>1.21 -- частично C++11</ref>), и с отсутствием поддержки как некоторых расширений GNU (в первую очередь [http://hub.darcs.net/imz/cuglify вложенных] [http://lists.altlinux.org/pipermail/devel/2016-January/200765.html функций] -- nested functions, и массивов переменной длины в структуре -- variable length array in structure, VLAIS), так и ряда языков -- Objective C, D, Ada, Go -- либо конкретных опций, специфичных для gcc или других компиляторов (возможно, просто [[#bugreport|не поддержанных]] lcc). | ||
Стоит отметить, что часть "проблем" на самом деле относится именно к собираемому софту и находится в нём -- просто gcc или смотрит сквозь пальцы, ограничиваясь предупреждениями, или не делает даже их, что позволяет фактическим ошибкам оставаться в коде даже с <tt>-Werror</tt>. | Стоит отметить, что часть "проблем" на самом деле относится именно к собираемому софту и находится в нём -- просто gcc или смотрит сквозь пальцы, ограничиваясь предупреждениями, или не делает даже их, что позволяет фактическим ошибкам оставаться в коде даже с <tt>-Werror</tt>. | ||
Строка 29: | Строка 31: | ||
=== misoptimization === | === misoptimization === | ||
Обычно замечается по странным сбоям в работе программы (особенно Illegal instruction, оно же SIGILL); диагностируется по корректности работы собранного с -O0 и/или -g0 кода; [[#bugreport|исправляется]] в компиляторе или обходится в коде. | Обычно замечается по странным сбоям в работе программы (особенно <tt>Illegal instruction</tt>, оно же <tt>SIGILL</tt>); диагностируется по корректности работы собранного с <tt>-O0</tt> и/или <tt>-g0</tt> кода; [[#bugreport|исправляется]] в компиляторе или обходится в коде. | ||
Без отключения оптимизаций отладочная информация будет бесполезна: lcc её построит, но она не будет ассоциирована с кодом. | Без отключения оптимизаций отладочная информация будет бесполезна: lcc её построит, но она не будет ассоциирована с кодом. | ||
При точечном поиске может пригодиться навесить на конкретную функцию <tt>__attribute__((optimize(0)))</tt><ref>см. тж. mcst#4061, lcc <= 1.24.05 принимал здесь только численный аргумент</ref> или <tt>__attribute__((optimize("-O0")))</tt>. | |||
Также могут пригодиться <tt>#pragma diag_suppress</tt> и <tt>#pragma diag_default</tt>. <!-- Igor Molchanov --> | Также могут пригодиться <tt>#pragma diag_suppress</tt> и <tt>#pragma diag_default</tt>. <!-- Igor Molchanov --> | ||
Строка 44: | Строка 48: | ||
== линкер == | == линкер == | ||
Между сборками {{pkg|binutils}} в ОС Эльбрус<ref>...где "как в апстриме"</ref> и ОС Альт есть существенная разница в поведении компоновщика по умолчанию (#3675): в альтовой [[TextRel|из соображений безопасности]] ''не'' задана опция <tt>-Wl,--no-warn-shared-textrel</tt>, которая отключает предупреждения о создании релокаций и совместно с опцией <tt>-Wl,--fatal-warnings</tt> может привести к сбоям сборки вида: | Между сборками {{pkg|binutils}} в ОС Эльбрус<ref>...где "как в апстриме"</ref> и ОС Альт есть существенная разница в поведении компоновщика по умолчанию (mcst#3675): в альтовой [[TextRel|из соображений безопасности]] ''не'' задана опция <tt>-Wl,--no-warn-shared-textrel</tt>, которая отключает предупреждения о создании релокаций и совместно с опцией <tt>-Wl,--fatal-warnings</tt> может привести к сбоям сборки вида: | ||
/usr/bin/ld: CMakeFiles/KF5CoreAddons.dir/plugin/desktopfileparser.cpp.o: warning: relocation against `_ZTISt9bad_alloc' in readonly section `.gcc_except_table'. | /usr/bin/ld: CMakeFiles/KF5CoreAddons.dir/plugin/desktopfileparser.cpp.o: warning: relocation against `_ZTISt9bad_alloc' in readonly section `.gcc_except_table'. | ||
Строка 55: | Строка 59: | ||
Проверив, что компилятору (в момент получения объектного файла) передана опция <tt>-fPIC</tt>, в качестве обходной меры можно передать <tt>-Wl,--no-warn-shared-textrel</tt> явно: в некоторых версиях компилятора известна нефатальная ошибка, которая может приводить к подобным сбоям. | Проверив, что компилятору (в момент получения объектного файла) передана опция <tt>-fPIC</tt>, в качестве обходной меры можно передать <tt>-Wl,--no-warn-shared-textrel</tt> явно: в некоторых версиях компилятора известна нефатальная ошибка, которая может приводить к подобным сбоям. | ||
В lcc 1.28 данная нефатальная ошибка компилятора исправлена. | |||
<div id="openmp"></div> | <div id="openmp"></div> | ||
== OpenMP == | == OpenMP == | ||
В [[lcc]] <= 1.23 доступна реализация OpenMP 2.5, начиная с lcc-1.24 реализована OpenMP 3.1 с некоторыми ограничениями (см. /opt/mcst/doc/openmp.html). Кроме того, в старших версиях компилятора есть исправление ряда ошибок и расширение функциональности, поэтому рекомендуется использовать их. | В [[lcc]] <= 1.23 доступна реализация OpenMP 2.5, начиная с lcc-1.24 реализована OpenMP 3.1 с некоторыми ограничениями (см. /opt/mcst/doc/openmp.html). Кроме того, в старших версиях компилятора есть исправление ряда ошибок и расширение функциональности, поэтому рекомендуется использовать их. | ||
Строка 65: | Строка 72: | ||
+ int c = a > b; | + int c = a > b; | ||
+#pragma omp parallel sections if (c) | +#pragma omp parallel sections if (c) | ||
+ int n_gt_128 = n > 128; | |||
#pragma omp parallel for num_threads(CHOLMOD_OMP_NUM_THREADS) \ | |||
- if ( n > 128 ) schedule (static) | |||
+ if ( n_gt_128 ) schedule (static) | |||
Наткнувшись на ошибку "<tt>omp-регион не является замкнутым</tt>", запрашивайте обновление компилятора до 1.23.20 или выше (mcst#3639). | Наткнувшись на ошибку "<tt>omp-регион не является замкнутым</tt>", запрашивайте обновление компилятора до 1.23.20 или выше (mcst#3639). | ||
sed-патч от ilyakurdyukov@ на примере siril: | |||
<pre> | |||
%ifarch %e2k | |||
sed -i -E "/^[[:space:]]*#pragma omp.*\\\\$/N;\ | |||
/^[[:space:]]*#pragma omp .*(num_threads| if)\(/{s/#/for(long &/;\ | |||
s/(#.*num_threads\()([^()]*)\)/_xxxn=\\2,\\1_xxxn)/;\ | |||
s/(#.*if | |||
*\()([^()]*(\([^()]*(\([^()]*\)[^()]*)*\)[^()]*)*)\)/_xxxi=\\2,\\1_xxxi)/;\ | |||
s/(#.*schedule\([^()]*, *)([^()]*)\)/_xxxs=\\2,\\1_xxxs)/;\ | |||
s/#/_xxxc=1;_xxxc;_xxxc=0)\n&/}" \ | |||
SOURCES.c | |||
%endif | |||
</pre> | |||
== howto == | == howto == | ||
Строка 92: | Строка 119: | ||
"nullptr" не определен | "nullptr" не определен | ||
По умолчанию в lcc 1.23 идёт -std=c++03, как и в gcc 5.5; если код подразумевает [http://en.cppreference.com/w/cpp/memory/c/aligned_alloc более новый стандарт] без учёта этого в системе сборки -- включаем явно: | По умолчанию в lcc 1.23 идёт <tt>-std=c++03</tt>, как и в gcc 5.5; если код подразумевает [http://en.cppreference.com/w/cpp/memory/c/aligned_alloc более новый стандарт] без учёта этого в системе сборки -- включаем явно: | ||
%ifarch %e2k | %ifarch %e2k | ||
Строка 116: | Строка 143: | ||
- E2K: fix hardwired optimization level | - E2K: fix hardwired optimization level | ||
==== [http://t.me/qemu_e2k/21951 цитата разработчика] ==== | |||
<helce> На O3 работает резолвер<ref>O4, если что, его тупо отрубает и всегда использует O3, насколько я понимаю</ref>, который на основе эвристик определяет реально необходимый уровень оптимизаций. И фактически выставляет в O2 или O3. | |||
<helce> И если что, нет никакой стандартизации. Есть gnu, и есть все остальное. Lcc не gnu, он всего лишь gnu-совместимый | |||
<helce> В gcc уровень оптимизаций включает строго определенные линейки оптимизаций. И да на O3 O4 есть действительно агрессивные. Lcc работает иначе. | |||
<helce> Ну и есть все тот же clang, который точно также кладет болт на стандарты gcc и в optimize режиме использует O3 | |||
=== optimize("O0") === | === optimize("O0") === | ||
Строка 166: | Строка 199: | ||
=== int128 === | === int128 === | ||
int128_t/uint128_t поддержаны начиная с lcc 1.24 (#1802); для 1.23 и более ранних веток применяем аналогичные вышеизложенным для [[#__builtin|__builtin_*]] обходы либо прикидываемся 32-битной платформой с максимум 64-битными целыми, смотря по ситуации (такие в | <tt>int128_t</tt> / <tt>uint128_t</tt> поддержаны начиная с lcc 1.24 (#1802); для 1.23 и более ранних веток применяем аналогичные вышеизложенным для [[#__builtin|__builtin_*]] обходы либо прикидываемся 32-битной платформой с максимум 64-битными целыми, смотря по ситуации (такие в Сизифе оказались довольно редки, апстрим libtommath [[эльбрус/upstream|патчик]] уже принял). | ||
=== FP*/Decimal* === | === FP*/Decimal* === | ||
Строка 172: | Строка 205: | ||
См. [http://forum.elbrus.ru/viewtopic.php?p=7248#p7248 обсуждение на форуме]: | См. [http://forum.elbrus.ru/viewtopic.php?p=7248#p7248 обсуждение на форуме]: | ||
Аппаратно поддержаны FP32 (float), FP64 (double), FP80 (long double, __float80). У FP128 (__float128) поддержка программная. Всё симметрично во всех моделях процессоров. | Аппаратно поддержаны FP32 (<tt>float</tt>), FP64 (<tt>double</tt>), FP80 (<tt>long double</tt>, <tt>__float80</tt>). У FP128 (<tt>__float128</tt>) поддержка программная. Всё симметрично во всех моделях процессоров. | ||
Для FP256 и Decimal'ов (Decimal64, Decimal128...) и вообще для какого угодно формата можно было бы сделать программную поддержку, но проблема упирается в то, что покупной фронтенд edg, на базе которого построен компилятор lcc, данные типы не поддерживает. | Для FP256 и Decimal'ов (Decimal64, Decimal128...) и вообще для какого угодно формата можно было бы сделать программную поддержку, но проблема упирается в то, что покупной фронтенд edg, на базе которого построен компилятор lcc, данные типы не поддерживает. | ||
Строка 184: | Строка 217: | ||
попытайтесь заменить во флагах компиляции <tt>-g</tt> на <tt>-g0</tt> (либо добавить <tt>-g0</tt> ''после'' остальных флагов), чтобы снизить объём отладочной информации, или вовсе отключить её порождение (также бывает необходимо убрать <tt>-ggdb</tt> из конфигурации сборочной системы проекта). | попытайтесь заменить во флагах компиляции <tt>-g</tt> на <tt>-g0</tt> (либо добавить <tt>-g0</tt> ''после'' остальных флагов), чтобы снизить объём отладочной информации, или вовсе отключить её порождение (также бывает необходимо убрать <tt>-ggdb</tt> из конфигурации сборочной системы проекта). | ||
В альтовом spec-файле это может выглядеть так, если сборочная система проекта обращает внимание на CFLAGS/CXXFLAGS (или [http://packages.altlinux.org/ru/p9/specfiles/qt4-webkit/1:2.3.4-alt5.E2K.1 так]): | В альтовом spec-файле это может выглядеть так, если сборочная система проекта обращает внимание на <tt>CFLAGS</tt> / <tt>CXXFLAGS</tt> (или [http://packages.altlinux.org/ru/p9/specfiles/qt4-webkit/1:2.3.4-alt5.E2K.1 так]): | ||
# due to R_E2K_32_ABS debuginfo truncation, cf.: webkit | # due to R_E2K_32_ABS debuginfo truncation, cf.: webkit | ||
Строка 190: | Строка 223: | ||
%add_optflags -g0 | %add_optflags -g0 | ||
Для новых сборок пакетов с библиотеками полное отключение отладочной информации может быть неприятным вдвойне, т.к. на их debuginfo-части наверняка будут зависимости у других пакетов и может потребоваться каскадное [[RPM/debuginfo|отключение *-debuginfo]]. По возможности просто снижайте уровень (на "ругань" %remove_optflags можно не обращать внимания). | Для новых сборок пакетов с библиотеками полное отключение отладочной информации может быть неприятным вдвойне, т.к. на их debuginfo-части наверняка будут зависимости у других пакетов и может потребоваться каскадное [[RPM/debuginfo|отключение <tt>*-debuginfo</tt>]]. По возможности просто снижайте уровень (на "ругань" <tt>%remove_optflags</tt> можно не обращать внимания). | ||
Начиная с lcc-1.26.06 в компиляторе будет доступна опция <tt>--dwarf2-64bit</tt>, по которой при построении отладочной информации будут задействованы возможности из стандарта DWARF-3, которые позволяют формировать секции с отладочной информацией, которые после линковки превысят размер в 4 гигабайта. | |||
=== -Wno-номер === | |||
Если необходимо подавить, скажем, <tt>warning #2506</tt> (для разных версий номер одного и того же предупреждения разный): | |||
<tt>lcc --version</tt>, получаем версию LCC; допустим, это <tt>1.23.45</tt> (1.MAJOR.MINOR), тогда: | |||
<source lang="c"> | |||
// code | |||
#if (__LCC__ == 123 && __LCC_MINOR__ == 45) // change to correct 100+MAJOR and MINOR correspondingly | |||
#pragma diag_suppress 2506 | |||
#endif | |||
// code that generates the warning | |||
#if (__LCC__ == 123 && __LCC_MINOR__ == 45) // change to correct 100+MAJOR and MINOR correspondingly | |||
#pragma diag_default 2506 | |||
#endif | |||
// other code | |||
</source> | |||
=== precompile_header === | |||
При ошибках qmake-сборки плюсового кода вроде такой: | |||
lcc: Command-line error #1696: cannot open source file "release/qcadecmaapi" | |||
попробуйте отключить прекомпиляцию заголовков, если включена: | |||
%ifarch %e2k | |||
sed -i '/CONFIG += precompile_header/d' src/scripting/ecmaapi/ecmaapi.pro | |||
%endif | |||
=== пропавший нестатический inline === | |||
Из mcst#6575 (вкратце -- бывает в lcc 1.25 и 1.26, исправлено в lcc 1.27): | |||
>> Функция audio_linear_dither по недосмотру объявлена inline без static.<br> | |||
>> Что в итоге приводит к ошибке при линковке:<br> | |||
>> <tt>ld: mad.o: in function `output':</tt><br> | |||
>> <tt>mpg321-0.3.2-orig/mad.c:941: undefined reference to `audio_linear_dither'</tt> | |||
> Объясните мне, каким образом неподставленный inline'ом вызов функции<br> | |||
> приводит к ошибке линковки? | |||
Тело функции audio_linear_dither - это то, что в GNU C по смыслу эквивалентно extern inline'у. Т.е. функцию нужно либо про'inline'ить, либо удалить тело из кода. При этом в другом модуле должно быть объявлено "нормальное" тело функции без inline'а | |||
Это довольно массовая проблема, которая вылезала в момент появления стандарта C11. Связано с тем, что стандарт C11 ввёл таким образом ключевое слово inline, что оно начало конфликтовать с существовавшим на тот момент поведением слова inline в языке GNU C. Для этого gnu'шники и вводили опцию <tt>-fgnu89-inline</tt> на переходный период. | |||
Обход: | |||
%add_optflags -fgnu89-inline | |||
Исправление: | |||
sed -i "s/^inline/static &/" mad.c | |||
Комментарий:<br> | |||
''inline без static в C<ref>семантика в C++ совсем иная</ref> -- это признак дурного тона или очень старого кода. В современном коде все inline должны быть со static, нестатичный инлайн это редкая и никому не нужная фича, и лучше бы её не было во избежание подобных проблем.<ref>Это проблема ''и'' GCC, но он почти всегда инлайнит функции, а LCC часто не инлайнит крупные и не очень. Поэтому для GCC большинство подобных кривых инлайнов проходят незамечеными, а на LCC проявляется. (и если бы код изначально оказался загнут под LCC, а не GCC -- на последнем полезли бы симметричные проблемы; как и в других аналогичных случаях недетерминированного поведения)''</ref> | |||
=== bugreport === | === bugreport === | ||
Строка 209: | Строка 293: | ||
Если в исходной строке запуска была указана опция <tt>-o</tt> с именем бинарного объекта, её стоит удалить. | Если в исходной строке запуска была указана опция <tt>-o</tt> с именем бинарного объекта, её стоит удалить. | ||
Текст следует по возможности давать текстом, а не снимками экрана или фотографиями. | |||
= особенности = | = особенности = | ||
<div id="versions"></div> | |||
== система программирования == | == система программирования == | ||
Строка 224: | Строка 310: | ||
|- | |- | ||
! ядро Linux !! glibc !! lcc !! binutils | ! ядро Linux !! glibc !! lcc !! binutils | ||
|- | |||
| 6.1 || 2.35 || 1.29 || 2.41 | |||
|- | |||
| 5.10 || 2.35 || 1.26 || 2.39 | |||
|- | |- | ||
| 5.4 || 2.29 || 1.25 || 2.34 | | 5.4 || 2.29 || 1.25 || 2.34 | ||
Строка 249: | Строка 339: | ||
Обратите внимание, что для некоторых случаев C++-кода, который написан так, чтобы линковаться gcc вместо g++<ref>и которому это удаётся из-за умения GCC встраивать вызов <tt>__cxa_vec_ctor</tt>; например, {{pkg|libgraphite2}}</ref>, на 1.23 может потребоваться другой обход -- компоновка с <tt>-lsupc++ -lgcc_eh -llcc</tt> из {{pkg|libstdc++5-devel-static}}. | Обратите внимание, что для некоторых случаев C++-кода, который написан так, чтобы линковаться gcc вместо g++<ref>и которому это удаётся из-за умения GCC встраивать вызов <tt>__cxa_vec_ctor</tt>; например, {{pkg|libgraphite2}}</ref>, на 1.23 может потребоваться другой обход -- компоновка с <tt>-lsupc++ -lgcc_eh -llcc</tt> из {{pkg|libstdc++5-devel-static}}. | ||
<div id="asm"></div> | |||
== ассемблерные вставки == | |||
С ассемблерными вставками есть такой нюанс: они бывают открытыми (когда не используются фигурные скобки) и закрытыми. В последнем случая компилятор один-в-один вставит широкие команды именно так, как они написаны. В случае открытых вставок операции попадут в представление как отдельные и перемешаются со всеми остальными, ну и спланируются планировщиком с учетом всех задержек. | |||
= оптимизация = | = оптимизация = | ||
{{main|эльбрус/оптимизация}} | |||
По умолчанию lcc собирает без оптимизации (<tt>-O0</tt>), что удобно для отладки. Для релизов и предназначенных для использования версий '''настоятельно рекомендуется <tt>-O3</tt>'''; при этом прыгать на четвёртый уровень бездумно не стоит, т.к. там выключен <tt>gos-solver</tt>, что может привести к сильному раздуванию кода и обратному эффекту -- понижению производительности полученного бинарника; посмотрите сперва внимательней на <tt>-fwhole</tt>. | По умолчанию lcc собирает без оптимизации (<tt>-O0</tt>), что удобно для отладки. Для релизов и предназначенных для использования версий '''настоятельно рекомендуется <tt>-O3</tt>'''; при этом прыгать на четвёртый уровень бездумно не стоит, т.к. там выключен <tt>gos-solver</tt>, что может привести к сильному раздуванию кода и обратному эффекту -- понижению производительности полученного бинарника; посмотрите сперва внимательней на <tt>-fwhole</tt>. | ||
Строка 258: | Строка 352: | ||
== -O3 == | == -O3 == | ||
Сборочные системы приложений обычно предполагают <tt>-O2</tt>, а порой вдобавок игнорируют выставленные CFLAGS/CXXFLAGS; собранные так программы могут работать на e2k медленней, чем способны при <tt>-O3</tt>. | Сборочные системы приложений обычно предполагают <tt>-O2</tt>, а порой вдобавок игнорируют выставленные <tt>CFLAGS</tt> / <tt>CXXFLAGS</tt>; собранные так программы могут работать на e2k медленней, чем способны при <tt>-O3</tt>. | ||
Учтите, что lcc в некоторых случаях, как и gcc, может выдавать при <tt>-O3</tt> менее эффективный код, чем в режиме <tt>-O2</tt>. Поэтому на данный момент рекомендуется внимательно замерять и сопоставлять итоговую производительность. | |||
== -fwhole == | == -fwhole == | ||
Строка 264: | Строка 360: | ||
Данный режим работы объединяет все модули программы в один большой модуль, что позволяет обходить ограничения классической помодульной сборки проекта и применять межпроцедурные оптимизации для процедур, находящихся в разных модулях. Режим похож на <tt>-flto</tt> у gcc и llvm, но обладает совершенно иной технической реализацией; по этой причине всё связанное с <tt>-flto</tt> (например, <tt>-fuse-linker-plugin</tt>, #4020) следует удалять из сборки под e2k. | Данный режим работы объединяет все модули программы в один большой модуль, что позволяет обходить ограничения классической помодульной сборки проекта и применять межпроцедурные оптимизации для процедур, находящихся в разных модулях. Режим похож на <tt>-flto</tt> у gcc и llvm, но обладает совершенно иной технической реализацией; по этой причине всё связанное с <tt>-flto</tt> (например, <tt>-fuse-linker-plugin</tt>, #4020) следует удалять из сборки под e2k. | ||
Оптимизация очень сильная: разница между <tt>-O3</tt> и <tt>-O3 -fwhole</tt> обычно больше, чем между <tt>-O2</tt> и <tt>-O3</tt>. Но эту опцию нельзя просто так применять: в зависимости от ситуации нужно выбирать между <tt>-fwhole</tt> и <tt>-fwhole-shared</tt> для конкретных файлов, иногда вовсе нельзя: -fwhole можно применять для исполняемых файлов, но нельзя для динамических библиотек (-shared); для последних есть -fwhole-shared, но в ней есть смысл только совместно с -fvisibility=protected, что встречается редко. Опция обязательно должна подаваться не только на стадии компиляции, но и на финальной линковке. Несовместима с <tt>-g</tt> (#5104) и некоторыми расширениями GNU, см. документацию компилятора. | Оптимизация очень сильная: разница между <tt>-O3</tt> и <tt>-O3 -fwhole</tt> обычно больше, чем между <tt>-O2</tt> и <tt>-O3</tt>. Но эту опцию нельзя просто так применять: в зависимости от ситуации нужно выбирать между <tt>-fwhole</tt> и <tt>-fwhole-shared</tt> для конкретных файлов, иногда вовсе нельзя: <tt>-fwhole</tt> можно применять для исполняемых файлов, но нельзя для динамических библиотек (<tt>-shared</tt>); для последних есть <tt>-fwhole-shared</tt>, но в ней есть смысл только совместно с <tt>-fvisibility=protected</tt>, что встречается редко. Опция обязательно должна подаваться не только на стадии компиляции, но и на финальной линковке. Несовместима с <tt>-g</tt> (#5104) и некоторыми расширениями GNU, см. документацию компилятора. | ||
С точки зрения оптимизаций данный режим имеет большое влияние на любые межпроцедурные оптимизации: подстановка функций, анализы указателей, распространение констант, девиртуализация и т.д. Косвенным образом влияет и на внутрипроцедурные оптимизации, т.к. расширяет количество информации о коде. Для этого режима важно соблюдать ODR (One Definition Rule), т.е. не допускать наличия классов или объектов с одним именем, но различной реализацией. | С точки зрения оптимизаций данный режим имеет большое влияние на любые межпроцедурные оптимизации: подстановка функций, анализы указателей, распространение констант, девиртуализация и т.д. Косвенным образом влияет и на внутрипроцедурные оптимизации, т.к. расширяет количество информации о коде. Для этого режима важно соблюдать ODR (One Definition Rule), т.е. не допускать наличия классов или объектов с одним именем, но различной реализацией. | ||
Строка 275: | Строка 371: | ||
= ссылки = | = ссылки = | ||
* [http://mcst.ru/lcc Компилятор «LCC» (ТВГИ.00500)] | * [http://mcst.ru/lcc Компилятор «LCC» (ТВГИ.00500)] | ||
** [http://mcst.ru/files/5fe5d1/99dece/61aa69/33a144/a.l._markin_obzor_kompilyatora_lcc_dlya_mikroprotsessora_elbrus.pdf Обзор компилятора lcc для микропроцессора Эльбрус. А.Л. Маркин, АО «МЦСТ»] | |||
* [http://mcst.ru/elbrus_prog Руководство по эффективному программированию на платформе «Эльбрус»] | * [http://mcst.ru/elbrus_prog Руководство по эффективному программированию на платформе «Эльбрус»] | ||
** [http://ftp.altlinux.org/pub/people/mike/elbrus/docs/elbrus_prog/html/chapter3.html 3. Отличия в интерфейсах] | ** [http://ftp.altlinux.org/pub/people/mike/elbrus/docs/elbrus_prog/html/chapter3.html 3. Отличия в интерфейсах] | ||
Строка 288: | Строка 385: | ||
** [http://ce.mentality.rip/ Compiler Explorer] ''счётчик тактов (<tt>-fverbose-asm</tt>): filter -> comments'' | ** [http://ce.mentality.rip/ Compiler Explorer] ''счётчик тактов (<tt>-fverbose-asm</tt>): filter -> comments'' | ||
* [http://sourceforge.net/p/predef/mailman/message/37243657/ [Predef-contribute] Adding MCST Elbrus architecture and MCST lcc compiler] | * [http://sourceforge.net/p/predef/mailman/message/37243657/ [Predef-contribute] Adding MCST Elbrus architecture and MCST lcc compiler] | ||
* [http://0x1.tv/20191115BL Structure Splitting для компилятора для микропроцессоров Эльбрус (Виктор Шампаров, SECR-2019)] | |||
* [http://alexanius.ru/comp_modern_2020.html Учебный курс «Устройство современных компиляторов» - 2020] (МАИ, @alexanius) | |||
* [[эльбрус/отладка]] | |||
= примечания = | = примечания = |
Текущая версия от 18:43, 22 октября 2024
См. тж. Руководство по эффективному программированию на платформе «Эльбрус»
lcc на e2k
Сразу оговорюсь: речь именно о родном режиме работы lcc, так как кроссовым (собирать для e2k, сидя на x86) мы не пользуемся.
Основная часть проблем, возникающих при сборке рассчитанного на gcc программного обеспечения сводится к тому, что lcc -- это всё же не gcc, несмотря на выставленный __GNUC__[1]; в патчах можно проверять взведённый/заполненный __LCC__[2], хотя порой даже проще прикинуться __ICC или __clang__, у которых во многом схожие ограничения -- начиная с того, что они тоже не gcc.
С версии 1.25 LCC также взводит __MCST__.
В любом случае мы стараемся донести сообщения о проблемах до коллег, занимающихся lcc, ради возможности улучшения будущих версий.
В то же время компилятор предоставляет богатые возможности оптимизации под весьма отзывчивую на них VLIW-платформу, причём от ветки к ветке производительность одного и того же исходного кода на одной и той же аппаратуре в среднем растёт; обратите также внимание на библиотеку EML.
проблемы
фронтэнд
Надо понимать, что МЦСТ применяет в lcc сторонний фронтэнд EDG[3], как несколько раньше делал и Intel в своём icc.
Собственно, в основном проблемы здесь -- и с новыми версиями стандартов вроде C++20 (стабилизируется lcc 1.26[4]), и с отсутствием поддержки как некоторых расширений GNU (в первую очередь вложенных функций -- nested functions, и массивов переменной длины в структуре -- variable length array in structure, VLAIS), так и ряда языков -- Objective C, D, Ada, Go -- либо конкретных опций, специфичных для gcc или других компиляторов (возможно, просто не поддержанных lcc).
Стоит отметить, что часть "проблем" на самом деле относится именно к собираемому софту и находится в нём -- просто gcc или смотрит сквозь пальцы, ограничиваясь предупреждениями, или не делает даже их, что позволяет фактическим ошибкам оставаться в коде даже с -Werror.
бэкенд
С ним бывают проблемы в основном двух типов: неверная оптимизация или сбой самого оптимизатора.
misoptimization
Обычно замечается по странным сбоям в работе программы (особенно Illegal instruction, оно же SIGILL); диагностируется по корректности работы собранного с -O0 и/или -g0 кода; исправляется в компиляторе или обходится в коде.
Без отключения оптимизаций отладочная информация будет бесполезна: lcc её построит, но она не будет ассоциирована с кодом.
При точечном поиске может пригодиться навесить на конкретную функцию __attribute__((optimize(0)))[5] или __attribute__((optimize("-O0"))).
Также могут пригодиться #pragma diag_suppress и #pragma diag_default.
segfault
работа /opt/mcst/lcc-home/1.23.12/e2k-v3-linux/bin/ecf_opt64 завершена по сигналу Segmentation fault (11)
При падении компилятора остаётся только вешать отчёт об ошибке в lcc.
линкер
Между сборками binutils в ОС Эльбрус[6] и ОС Альт есть существенная разница в поведении компоновщика по умолчанию (mcst#3675): в альтовой из соображений безопасности не задана опция -Wl,--no-warn-shared-textrel, которая отключает предупреждения о создании релокаций и совместно с опцией -Wl,--fatal-warnings может привести к сбоям сборки вида:
/usr/bin/ld: CMakeFiles/KF5CoreAddons.dir/plugin/desktopfileparser.cpp.o: warning: relocation against `_ZTISt9bad_alloc' in readonly section `.gcc_except_table'. /usr/bin/ld: warning: creating a DT_TEXTREL in a shared object.
либо
/usr/bin/ld: CMakeFiles/openbabel.dir/mcdlutil.cpp.o: предупреждение: перемещение указывает на «_ZTISt9exception» из раздела только для чтения «.gcc_except_table». /usr/bin/ld: предупреждение: создаётся DT_TEXTREL в общем объекте.
Проверив, что компилятору (в момент получения объектного файла) передана опция -fPIC, в качестве обходной меры можно передать -Wl,--no-warn-shared-textrel явно: в некоторых версиях компилятора известна нефатальная ошибка, которая может приводить к подобным сбоям.
В lcc 1.28 данная нефатальная ошибка компилятора исправлена.
OpenMP
В lcc <= 1.23 доступна реализация OpenMP 2.5, начиная с lcc-1.24 реализована OpenMP 3.1 с некоторыми ограничениями (см. /opt/mcst/doc/openmp.html). Кроме того, в старших версиях компилятора есть исправление ряда ошибок и расширение функциональности, поэтому рекомендуется использовать их.
Для собираемости могут потребоваться положенное -fopenmp вместо явного -lgomp (mcst#2483) и хак в виде подстановки переменных, содержащих значение выражения, вместо выражения:
-#pragma omp parallel sections if (a > b) + int c = a > b; +#pragma omp parallel sections if (c)
+ int n_gt_128 = n > 128; #pragma omp parallel for num_threads(CHOLMOD_OMP_NUM_THREADS) \ - if ( n > 128 ) schedule (static) + if ( n_gt_128 ) schedule (static)
Наткнувшись на ошибку "omp-регион не является замкнутым", запрашивайте обновление компилятора до 1.23.20 или выше (mcst#3639).
sed-патч от ilyakurdyukov@ на примере siril:
%ifarch %e2k sed -i -E "/^[[:space:]]*#pragma omp.*\\\\$/N;\ /^[[:space:]]*#pragma omp .*(num_threads| if)\(/{s/#/for(long &/;\ s/(#.*num_threads\()([^()]*)\)/_xxxn=\\2,\\1_xxxn)/;\ s/(#.*if *\()([^()]*(\([^()]*(\([^()]*\)[^()]*)*\)[^()]*)*)\)/_xxxi=\\2,\\1_xxxi)/;\ s/(#.*schedule\([^()]*, *)([^()]*)\)/_xxxs=\\2,\\1_xxxs)/;\ s/#/_xxxc=1;_xxxc;_xxxc=0)\n&/}" \ SOURCES.c %endif
howto
Маленький сборник проверенных на пакетах для e2k-alt-linux рецептов.
UTF-8 BOM
Проблема (#2418): строгий фронтэнд с негодованием спотыкается на трёхбайтном маркере в начале файла, указывающем, что используется кодировка UTF-8 (обычно оставлен текстовым редактором); изменение этого поведения ожидается в версии 1.24[7], а до того может понадобиться:
%ifarch %e2k # strip UTF-8 BOM for lcc < 1.24 find -type f -print0 -name '*.cpp' -o -name '*.hpp' -o -name '*.cc' -o -name '*.h' | xargs -r0 sed -ri 's,^\xEF\xBB\xBF,,' %endif
Такие пакеты при обходе проблемы в альте обычно получают подобную запись в %changelog:
- E2K: strip UTF-8 BOM for lcc < 1.24
-std=c++11
Ошибки могут быть довольно разнообразными; скажем,
"nullptr" не определен
По умолчанию в lcc 1.23 идёт -std=c++03, как и в gcc 5.5; если код подразумевает более новый стандарт без учёта этого в системе сборки -- включаем явно:
%ifarch %e2k # -std=c++03 by default as of lcc 1.23.20 %add_optflags -std=c++11 %endif
- E2K: explicit -std=c++11
В lcc 1.25 по умолчанию -std=gnu++14; в каждом конкретном случае можно справиться с man lcc по -std=; сводка поддерживаемых стандартов доступна на страничке mcst.ru/lcc во вкладке "Характеристики".
-O
Некоторые пакеты указывают уровень оптимизации сверх специфицированных (-O6, -O9, -O20): gcc такое допускает, хотя реально ставит -O3, а EDG -- нет (#2266); понижаем до заданного:
%ifarch %e2k sed -i 's/-O6/-O%_optlevel/g' configure* %endif
- E2K: fix superfluous optimization level
Аналогично в случаях, когда гвоздиком прибит -O2, а нам с lcc надо выше.
- E2K: fix hardwired optimization level
цитата разработчика
<helce> На O3 работает резолвер[8], который на основе эвристик определяет реально необходимый уровень оптимизаций. И фактически выставляет в O2 или O3. <helce> И если что, нет никакой стандартизации. Есть gnu, и есть все остальное. Lcc не gnu, он всего лишь gnu-совместимый <helce> В gcc уровень оптимизаций включает строго определенные линейки оптимизаций. И да на O3 O4 есть действительно агрессивные. Lcc работает иначе. <helce> Ну и есть все тот же clang, который точно также кладет болт на стандарты gcc и в optimize режиме использует O3
optimize("O0")
Проблема (#4061): lcc до версии 1.24.03 воспринимает другой вариант синтаксиса таких атрибутов -- численный[9]; обход:
%ifarch %e2k # lcc before 1.24.03 can't do that (mcst#4061) find -type f -print0 -name '*.c' | xargs -r0 sed -i 's,optimize("-O3"),optimize(3),g' %endif
В случаях вроде
__attribute__((optimize("-fno-fast-math")))
придётся переносить опцию на уровень файла или проекта.
символьные константы
Проблема (#3940): по умолчанию символьные константы в UTF-8 не будут разобраны фронтэндом:
lcc: "static_unicode_sets.h", строка 111: ошибка: слишком много символов в символьной константе {RUPEE_SIGN, u'₨'}, ^
Добавим опцию -finput-charset=utf8:
%ifarch %e2k # lcc 1.23.12 doesn't grok u'’' by default %add_optflags -finput-charset=utf8 %endif
- E2K: expect UTF-8 input
__builtin
В lcc 1.23 не поддерживается ряд типично ожидаемых от заявленного gcc5 builtin'ов[10], в т.ч.: __builtin_mul_overflow_p, __builtin_constant_p, __builtin_uadd_overflow, __builtin_sub_overflow, __builtin_add_overflow.
Смысл патча обычно заключается в добавлении проверки на lcc <= 1.23 -- например, для включающих gnulib проектов:
-#if 5 <= __GNUC__ && !defined __ICC +#if 5 <= __GNUC__ && !defined __ICC && !(defined __LCC__ && __LCC__ <= 123) ... -#elif 5 <= __GNUC__ && !defined __ICC && !__STRICT_ANSI__ +#elif 5 <= __GNUC__ && !defined __ICC && \ + !(defined __LCC__ && __LCC__ <= 123) && !__STRICT_ANSI__
Также не поддерживается vector_shuffle (#3982 о libfreetype >= 2.9) -- пока неясно, будет ли реализация в lcc.
int128
int128_t / uint128_t поддержаны начиная с lcc 1.24 (#1802); для 1.23 и более ранних веток применяем аналогичные вышеизложенным для __builtin_* обходы либо прикидываемся 32-битной платформой с максимум 64-битными целыми, смотря по ситуации (такие в Сизифе оказались довольно редки, апстрим libtommath патчик уже принял).
FP*/Decimal*
См. обсуждение на форуме:
Аппаратно поддержаны FP32 (float), FP64 (double), FP80 (long double, __float80). У FP128 (__float128) поддержка программная. Всё симметрично во всех моделях процессоров.
Для FP256 и Decimal'ов (Decimal64, Decimal128...) и вообще для какого угодно формата можно было бы сделать программную поддержку, но проблема упирается в то, что покупной фронтенд edg, на базе которого построен компилятор lcc, данные типы не поддерживает.
R_E2K_32_ABS
При столкновении с ошибкой вида
relocation truncated to fit: R_E2K_32_ABS against `.debug_info'
попытайтесь заменить во флагах компиляции -g на -g0 (либо добавить -g0 после остальных флагов), чтобы снизить объём отладочной информации, или вовсе отключить её порождение (также бывает необходимо убрать -ggdb из конфигурации сборочной системы проекта).
В альтовом spec-файле это может выглядеть так, если сборочная система проекта обращает внимание на CFLAGS / CXXFLAGS (или так):
# due to R_E2K_32_ABS debuginfo truncation, cf.: webkit %remove_optflags -g %add_optflags -g0
Для новых сборок пакетов с библиотеками полное отключение отладочной информации может быть неприятным вдвойне, т.к. на их debuginfo-части наверняка будут зависимости у других пакетов и может потребоваться каскадное отключение *-debuginfo. По возможности просто снижайте уровень (на "ругань" %remove_optflags можно не обращать внимания).
Начиная с lcc-1.26.06 в компиляторе будет доступна опция --dwarf2-64bit, по которой при построении отладочной информации будут задействованы возможности из стандарта DWARF-3, которые позволяют формировать секции с отладочной информацией, которые после линковки превысят размер в 4 гигабайта.
-Wno-номер
Если необходимо подавить, скажем, warning #2506 (для разных версий номер одного и того же предупреждения разный):
lcc --version, получаем версию LCC; допустим, это 1.23.45 (1.MAJOR.MINOR), тогда:
// code
#if (__LCC__ == 123 && __LCC_MINOR__ == 45) // change to correct 100+MAJOR and MINOR correspondingly
#pragma diag_suppress 2506
#endif
// code that generates the warning
#if (__LCC__ == 123 && __LCC_MINOR__ == 45) // change to correct 100+MAJOR and MINOR correspondingly
#pragma diag_default 2506
#endif
// other code
precompile_header
При ошибках qmake-сборки плюсового кода вроде такой:
lcc: Command-line error #1696: cannot open source file "release/qcadecmaapi"
попробуйте отключить прекомпиляцию заголовков, если включена:
%ifarch %e2k sed -i '/CONFIG += precompile_header/d' src/scripting/ecmaapi/ecmaapi.pro %endif
пропавший нестатический inline
Из mcst#6575 (вкратце -- бывает в lcc 1.25 и 1.26, исправлено в lcc 1.27):
>> Функция audio_linear_dither по недосмотру объявлена inline без static.
>> Что в итоге приводит к ошибке при линковке:
>> ld: mad.o: in function `output':
>> mpg321-0.3.2-orig/mad.c:941: undefined reference to `audio_linear_dither'
> Объясните мне, каким образом неподставленный inline'ом вызов функции
> приводит к ошибке линковки?
Тело функции audio_linear_dither - это то, что в GNU C по смыслу эквивалентно extern inline'у. Т.е. функцию нужно либо про'inline'ить, либо удалить тело из кода. При этом в другом модуле должно быть объявлено "нормальное" тело функции без inline'а
Это довольно массовая проблема, которая вылезала в момент появления стандарта C11. Связано с тем, что стандарт C11 ввёл таким образом ключевое слово inline, что оно начало конфликтовать с существовавшим на тот момент поведением слова inline в языке GNU C. Для этого gnu'шники и вводили опцию -fgnu89-inline на переходный период.
Обход:
%add_optflags -fgnu89-inline
Исправление:
sed -i "s/^inline/static &/" mad.c
Комментарий:
inline без static в C[11] -- это признак дурного тона или очень старого кода. В современном коде все inline должны быть со static, нестатичный инлайн это редкая и никому не нужная фича, и лучше бы её не было во избежание подобных проблем.[12]
bugreport
Пишем на user@mcst.ru заявку на регистрацию в системе отслеживания ошибок (с рабочего адреса и указав серийный номер используемого "Эльбруса" либо сообщив о применении удалённого доступа).
Если проблема с неподдерживаемой опцией -- следует вешать одно сообщение об ошибке на одну опцию; максимум одно сообщение с перечислением нескольких связанных между собой опций в течение одного дня (это связано с порядком обработки багрепортов компиляторщиками и экономит им силы на синхронизацию обстановки с внутренним багтрекером).
Если произошёл сбой компиляции, к отчёту об ошибке стоит приложить препроцессированный исходник (-E) и строчку запуска -- например,
g++ -Wall -O2 -DNDEBUG -std=c++11 -c -I ./include/ ./core/xhtmlgenerator.cpp
...превращается в:
$ g++ -Wall -O2 -DNDEBUG -std=c++11 -I ./include/ ./core/xhtmlgenerator.cpp -E -o test.pp.cpp
Если в исходной строке запуска была указана опция -o с именем бинарного объекта, её стоит удалить.
Текст следует по возможности давать текстом, а не снимками экрана или фотографиями.
особенности
система программирования
- см. тж. mcst.ru/sdk
Для корректной работы следует придерживаться проверенных МЦСТ комбинаций Linux, glibc, lcc и binutils -- смежные версии могут работать (особенно в окрестностях точек перехода), но далее разработчики закладываются на особенности новых lcc в новых ядрах и т.д.; например, вот эта диагностика похожа на признак "перекоса" установки (получена от lcc 1.25 под Linux 4.9):
Assembler messages: Error: literals cannot be packed into a wide command Error: cannot place literals
ядро Linux | glibc | lcc | binutils |
---|---|---|---|
6.1 | 2.35 | 1.29 | 2.41 |
5.10 | 2.35 | 1.26 | 2.39 |
5.4 | 2.29 | 1.25 | 2.34 |
4.19 | 2.29 | 1.24 | 2.34 |
4.9 | 2.23 | 1.23 | 2.29 |
3.14 | 2.23 | 1.21 | 2.26 |
libcxa
lcc до 1.23 требовал явной линковки libcxa к C++-программам, иначе можно было получить один из характерных симптомов (#1811):
undefined reference to `__cxa_vec_ctor'
либо в случае подключаемых модулей, так или иначе слинкованных с C++-кодом (особенность ветки 1.21):
cannot allocate memory in static TLS block
Рекомендуемый разработчиками компилятора обход обеих проблем при невозможности перехода на lcc >= 1.23 -- принудительная линковка такой программы с -lcxa; в случае плагинов линковать требуется то, к чему они линкуются, причём "до упора" (т.е. если имеем C++-плагин к mod_php к apache, то линковать так придётся именно apache). Подчас оказывалось достаточно export LIBS=-lcxa перед запуском autoreconf и configure.
В целом же лучше перейти на 1.23+, где помимо доработок по части zero cost exceptions и поддержки стандартов внедрено множество иных улучшений и оптимизаций. Обратите внимание, что добавленные -lcxa в этом случае обязательно убрать.
Обратите внимание, что для некоторых случаев C++-кода, который написан так, чтобы линковаться gcc вместо g++[13], на 1.23 может потребоваться другой обход -- компоновка с -lsupc++ -lgcc_eh -llcc из libstdc++5-devel-static.
ассемблерные вставки
С ассемблерными вставками есть такой нюанс: они бывают открытыми (когда не используются фигурные скобки) и закрытыми. В последнем случая компилятор один-в-один вставит широкие команды именно так, как они написаны. В случае открытых вставок операции попадут в представление как отдельные и перемешаются со всеми остальными, ну и спланируются планировщиком с учетом всех задержек.
оптимизация
По умолчанию lcc собирает без оптимизации (-O0), что удобно для отладки. Для релизов и предназначенных для использования версий настоятельно рекомендуется -O3; при этом прыгать на четвёртый уровень бездумно не стоит, т.к. там выключен gos-solver, что может привести к сильному раздуванию кода и обратному эффекту -- понижению производительности полученного бинарника; посмотрите сперва внимательней на -fwhole.
При отладке стоит понижать уровень оптимизации до -O0 и порой отключать генерацию отладочной информации (-g0, см. выше).
-O3
Сборочные системы приложений обычно предполагают -O2, а порой вдобавок игнорируют выставленные CFLAGS / CXXFLAGS; собранные так программы могут работать на e2k медленней, чем способны при -O3.
Учтите, что lcc в некоторых случаях, как и gcc, может выдавать при -O3 менее эффективный код, чем в режиме -O2. Поэтому на данный момент рекомендуется внимательно замерять и сопоставлять итоговую производительность.
-fwhole
Данный режим работы объединяет все модули программы в один большой модуль, что позволяет обходить ограничения классической помодульной сборки проекта и применять межпроцедурные оптимизации для процедур, находящихся в разных модулях. Режим похож на -flto у gcc и llvm, но обладает совершенно иной технической реализацией; по этой причине всё связанное с -flto (например, -fuse-linker-plugin, #4020) следует удалять из сборки под e2k.
Оптимизация очень сильная: разница между -O3 и -O3 -fwhole обычно больше, чем между -O2 и -O3. Но эту опцию нельзя просто так применять: в зависимости от ситуации нужно выбирать между -fwhole и -fwhole-shared для конкретных файлов, иногда вовсе нельзя: -fwhole можно применять для исполняемых файлов, но нельзя для динамических библиотек (-shared); для последних есть -fwhole-shared, но в ней есть смысл только совместно с -fvisibility=protected, что встречается редко. Опция обязательно должна подаваться не только на стадии компиляции, но и на финальной линковке. Несовместима с -g (#5104) и некоторыми расширениями GNU, см. документацию компилятора.
С точки зрения оптимизаций данный режим имеет большое влияние на любые межпроцедурные оптимизации: подстановка функций, анализы указателей, распространение констант, девиртуализация и т.д. Косвенным образом влияет и на внутрипроцедурные оптимизации, т.к. расширяет количество информации о коде. Для этого режима важно соблюдать ODR (One Definition Rule), т.е. не допускать наличия классов или объектов с одним именем, но различной реализацией.
версии
На том же самом оборудовании более новые версии lcc, как правило, позволяют добиться большей производительности -- поэтому есть прямой смысл обновлять сборки приложений, ключевых библиотек, а также ядра и окружения применяемой ОС.
ссылки
- Компилятор «LCC» (ТВГИ.00500)
- Руководство по эффективному программированию на платформе «Эльбрус»
- Yandex Day: 3. Компилятор для процессоров "Эльбрус". Алексей Маркин (видео)
- Yandex Day: 4. Прикладное программирование на Эльбрусе. Антон Аникин (видео)
- М. И. Нейман-заде, В. Ю. Волконский. «Среды программирования и оптимизирующие компиляторы для компьютеров с микропроцессорами архитектуры «Эльбрус»
- Elbrus Compilers
- Алексей Маркин
- Это непростое условное выполнение
- Интерактивный lcc онлайн ...как вариант, добавь флаг -xc
- Compiler Explorer счётчик тактов (-fverbose-asm): filter -> comments
- [Predef-contribute] Adding MCST Elbrus architecture and MCST lcc compiler
- Structure Splitting для компилятора для микропроцессоров Эльбрус (Виктор Шампаров, SECR-2019)
- Учебный курс «Устройство современных компиляторов» - 2020 (МАИ, @alexanius)
- эльбрус/отладка
примечания
- ↑ соответственно заявленной в `lcc -v` совместимой версии
- ↑ __LCC__ <= 123, например
- ↑ ...соответственно взводит __EDG__
- ↑ см. тж. вкладку "Характеристики" на mcst.ru/lcc:
1.25 поддерживает C++11/C++14 и частично C++17/C++20;
1.24 -- C++11/C++14 и частично C++17;
1.23 -- C++11 и частично C++14,
1.21 -- частично C++11 - ↑ см. тж. mcst#4061, lcc <= 1.24.05 принимал здесь только численный аргумент
- ↑ ...где "как в апстриме"
- ↑ lcc 1.23.17 обучен опции --ignore-utf8-bom, но её не будет в 1.24.x.
- ↑ O4, если что, его тупо отрубает и всегда использует O3, насколько я понимаю
- ↑ это ограничение соответствующей версии фронтэнда EDG -- или символьный, или целочисленный вариант должен быть выбран при сборке компилятора; в случае lcc исторически был выбран численный
- ↑ исправлено в 1.24, но тот представляется gcc7, от которого ожидают ещё более новых builtin'ов, в свою очередь
- ↑ семантика в C++ совсем иная
- ↑ Это проблема и GCC, но он почти всегда инлайнит функции, а LCC часто не инлайнит крупные и не очень. Поэтому для GCC большинство подобных кривых инлайнов проходят незамечеными, а на LCC проявляется. (и если бы код изначально оказался загнут под LCC, а не GCC -- на последнем полезли бы симметричные проблемы; как и в других аналогичных случаях недетерминированного поведения)
- ↑ и которому это удаётся из-за умения GCC встраивать вызов __cxa_vec_ctor; например, libgraphite2