Наиболее важные изменения при переходе от lcc-1.29 к lcc-1.30 (changelog)

Изменения, затрагивающие совместимость

  • Улучшена реализация PGO (опции -fprofile-generate, -fprofile-use) - теперь добавление или удаление цикловых прагм в исходнике не приводит к необходимости переполучения профиля. Побочным эффектом данной доработки стало то, что файлы с профильной информацией, полученные с помощью предыдущих версий компилятора, с большой вероятностью не подцепятся в режиме -fprofile-use на текущей версии компилятора; в этом случае следует переполучить профили с помощью текущей версии компилятора.

  • Изменен смысл прагмы comb_oper. Раньше прагма влияла только на эвристику комбинирования пар арифметических операций в соответствующем цикле, и не влияла на результат операций в этом цикле. В текущей версии компилятора эта прагма может влиять на результат в случае, когда на вход вещественной арифметической инструкции приходят аргументы inf и nan; инструкция может выдать inf вместо nan и наоборот. При этом прагма по-прежнему не влияет на точность результата.

  • Полностью переписана выдача предупреждений по опции -Wstrict-aliasing=<N>, где N может принимать значения от 1 до 3. Это может приводить к выдаче предупреждений там, где они раньше не выдавались, или отсутствию предупреждений там, где они раньше были. Основная проблема предупреждений -Wstrict-aliasing=<N> в нашем компиляторе состоит в том, что все три уровня реализованы в backend’е (у gcc первые два уровня реализованы во frontend’е), из-за этого могут выдаваться ложные предупреждения для конверсий типов, созданных frontend’ом, т.е. на те места, где в исходнике вообще не было конверсии типов (ни явной, ни неявной). Если подобные предупреждения мешают, их можно отключить опцией -Wno-strict-aliasing или повысить уровень предупреждений N.

  • В заголовочном файле e2kintrin.h заведены E2K-зависимые intrinsic’и с именами _e2k_<имя_операции_e2k>, которые соответствуют существующим builtin’ам. Макросы __builtin_e2k_[ld,st]_…, работающие через вызов __builtin_e2k_loadmas/storemas, объявлены устаревшими и будут удалены в будущих версиях. Вместо них заведены intrinsic’и с именами _e2k_[ld,st]_…

  • Следующие опции объявлены устаревшими (DEPRECATED) и будут удалены в будущих версиях компилятора:

    • -fautopar (игнорируется)

    • -fthreads= (игнорируется)

    • -fpar-numa= (игнорируется)

    • -fpar-distr-mem= (игнорируется)

    • -fno-dam4swp (используйте -fno-swp-dam)

    • -fdam-no-rbranch (используйте -fdam-no-short-cc)

    • -fext-strict-aliasing (игнорируется)

    • -fno-ext-strict-aliasing (игнорируется)

  • Прекращена поддержка процессора elbrus-2c+ с системой команд elbrus-v2

Общие улучшения

  • Расширена поддержка OpenMP 4.5 (lcc-1.29 поддерживал OpenMP 4.5 частично):

    • Реализована корректная поддержка прагм omp atomic через атомарные конструкции вместо критических секций в большинстве случаев.

    • Добавлена поддержка clause collapse по опции -fopenmp-collapse

    • Поддержаны подмассивы в качестве переменных редукции

    • В библиотеку поддержки добавлены недостающие функции и переменные окружения для управления thread affinity policy

    • Улучшен цикловой анализ

    Оставшиеся ограничения текущей реализации OpenMP:

    • Игнорируются конструкции для гетерогенных систем

    • Не поддержаны пользовательские редукции

    • Не поддержана конструкция ordered с параметром (сейчас параметр игнорируется)

    • Модификаторы планирования в цикловых конструкциях игнорируются

  • Добавлена полноценная поддержка выражений в прагмах OpenMP (lcc-1.29 поддерживал выражения частично).

  • Добавлена поддержка опции -fprofile-partial-training. По умолчанию, в режиме -fprofile-use компилятор очень консервативно оптимизирует участки кода, не покрытые тренировочным запуском, - оптимизируется размер кода, а не скорость его исполнения. Это может негативно сказаться на оптимизации горячих участков кода, не покрытых тренировочными запусками. С опцией -fprofile-partial-training компилятор уменьшает степень доверия профильной информации и начинает оптимизировать непокрытые профилем участки кода более агрессивно:

    • Функции, не исполнявшиеся на тренировочных запусках оптимизируются так же, как и без опции -fprofile-use

    • Если функция исполнялась на тренировочном запуске, но в ней есть циклы, которые не исполнялись, то компилятор оптимизирует их более агрессивно.

  • Добавлена поддержка опции -fuse-regs-part=<f>, позволяющая уменьшить количество доступных распределителю регистров. Опция может быть полезна в специфичных случаях, когда при работе программы значительная доля времени исполнения тратится на аппаратное сохранение/восстановление регистрового окна.

  • Добавлена опция -fswp-dam-cc (-fno-swp-dam-cc), которая включает (выключает) построение компенсирующего кода при применении DAM в конвейеризованных циклах. Стоит отметить, что DAM без компенсирующего кода (-fno-swp-dam-cc) имеет весьма низкую эффективность. Режим по умолчанию: -fswp-dam-cc (в режиме -O3), -fno-swp-dam-cc (в режиме -O2).

  • Добавлена поддержка опции -falign-loops=<n[:m]>, позволяющей выранивать начало кода циклов на величину, равную степени двойки, большей либо равной n, пропустив при этом не более m - 1 байт. В более ранних версиях компилятора данная опция игнорировалась для совместимости с GCC.

  • Добавлена поддержка опции -fopt-report-asm для печати отчёта о применении оптимизаций в ассемблер. По этой опции в ассемблере перед кодом цикла вставляется комментарий, содержащий информацию о применении оптимизаций к данному циклу. Имеет смысл только вместе с опциями -fopt-report=<N> и -S

  • Добавлена опция -fstrict-aliasing-relaxed-char, позволяющая трактовать char как обычный тип в анализе указателей на основе типов (tbaa).

  • Существенно повышена надёжность реализации Address Sanitizer (опция -fsanitize=address) после перехода на новую версию библиотеки поддержки

  • Реализована полноценная поддержка барьеров для операций обращения к памяти: __builtin_read_barrier, __builtin_write_barrier, __builtin_mem_barrier. В предыдущих версиях компилятора данные барьеры работали только на поздних оптимизационных фазах, что делало их практически бессмысленными. Формально эти барьеры остаются экспериментальными, поскольку проверять корректность их поддержки можно только вручную.

  • Добавлена опция -fspec-volatile-st (-fno-spec-volatile-st), разрешающая (запрещающая) ставить в спекулятивный режим исполнения операции записи в память по указателю с квалификатором volatile. Опция -fno-spec-volatile-st может быть полезна для системного ПО (ядро linux, например), в котором есть обращения к особым типам памяти, для которых запрещены спекулятивные обращения.

  • В runtime-анализатор качества работы оптимизаций (опция -fsanitize=opt) добавлена поддержка оптимизаций vect и rtmd. Анализатор по-прежнему имеет статус экспериментального.

  • Расширен набор e2k-зависимых builtin’ов для построения конкретных арифметических машинных операций

  • Начиная с версии lcc-1.30.03 оптимизация full peeling отключается, если значение прагмы unroll не совпадает с количеством итераций цикла

  • Добавлена опция -ffinite-loops (-fno-finite-loops), позволяющая устранить неоднозначность в определении бесконечных циклов в случае, когда условие выхода из цикла является инвариантным, но не константным. Опция поддерживается начиная с версии lcc-1.30.03

  • Введена опция -faligned-apb (-fno-aligned-apb), по которой при задействовании механизма аппаратной подкачки массивов считаем, что все чтения из памяти в наиболее вложенных циклах выровнены на свой формат. Опция поддерживается начиная с версии lcc-1.30.03

  • Введена #pragma apb_aligned, по которой при задействовании механизма аппаратной подкачки массивов считаем, что все чтения из памяти в ближайшем после объявления прагмы цикле являются выровненными на свой формат. Прагма поддерживается начиная с версии lcc-1.30.03

  • Начиная с версии lcc-1.30.05, отключена поддержка #pragma ivdep для режима -m128 (конструкция игнорируется)

Доработки оптимизаций

  • Полностью переписан анализ указателей на основе типов (tbaa - Type Based Aliasing Analysis). Анализ включается опцией -fstrict-aliasing (входит в состав -ffast). Новая версия анализа позволяет разрывать больше зависимостей между операциями обращения к памяти по сравнению с предыдущими версиями компилятора, особенно для обращений к полям struct, union и class. По нашим замерам новый анализ позволяет ускорить задачи spec cpu 2017 в среднем на 4-9% в зависимости от режима компиляции, отдельные задачи ускоряются до 1.9 раз. Нарушения правил строгой типизации (strict aliasing), которые прописаны в стандартах языков C и C++, встречаются в программах довольно часто; из-за таких ошибок в программах анализ tbaa может разрывать зависимости между операциями, работающими с пересекающимися областями памяти. Чтобы подобные ошибки в исходных кодах реже приводили к некорректной работе программ, в анализе tbaa предусмотрены специальные меры:

    • Считаем, что указатель типа void * может пересекаться с указателем любого другого типа. И хотя в стандартах языков C и C++ нет такого требования, мы учитываем здесь сложившуюся практику программирования. Аналогичным образом работает анализ tbaa в GCC.

    • Если какой-либо другой анализ указателей выявил точное пересечение адресов двух операций обращения к памяти, анализ tbaa не разрешает зависимости между этими операциями. Аналогичным образом работает анализ tbaa в GCC.

    • Если в коде функции в переменную типа “указатель” пишется значение несовместимого (с т.з. правил strict aliasing) типа, то для такого указателя анализ tbaa отключается в данной функции.

    • Если в адресном выражении операции обращения к памяти есть преобразование между несовместимыми типами указателей, то для такой операции анализ tbaa отключается.

    Для выключения последних двух проверок в анализе нарушений можно использовать опцию -funsafe-strict-aliasing. Для поиска нарушений правил strict aliasing в исходниках рекомендуется использовать опцию -Wstrict-aliasing=<N>.

  • Реализованы оптимизации для массивов переменной длины (VLA):

    • Удаление неиспользуемых массивов

    • Замена массива переменной длины на обычный массив, если в процессе оптимизаций удалось статически вычислить его длину

    • Удаление избыточных операций выделения/освобождения стека

  • Изменилось поведение DAM в конвейеризованных циклах: раньше в режиме -O3 при выборе решателем линейки оптимизаций уровня -O2 DAM не строил компенсирующий код, а теперь начал его строить. Это может привести к увеличению размера кода в режиме -O3; поведение компилятора в режиме -O2 не изменилось. Согласно нашим замерам, в режиме -O2 добавление опции -fswp-dam-cc приводит к увеличению размера кода на 1-2% в среднем, при среднем ускорении исполнения около 5%.

  • Расширена область применимости оптимизации exp_vars, теперь расширение 32-разрядных индуктивных переменных циклов до 64-разрядных должно выполняться для большего числа контекстов. Данная оптимизация имеет мало смысла сама по себе, однако, она критически необходима для применения других важных оптимизаций (например, apb, sle, rle и т.д.) в случае, когда формат индуктивной переменной цикла меньше формата адреса операций обращения к памяти.

  • Оптимизация ICF доработана для объединения статических read-only переменных с одинаковыми значениями.

  • Сняты некоторые ограничения на комбинирование вещественных операций (например, fmul_fadds) в случаях, когда для комбинирования требуется перестановка аргументов операций местами. Сейчас данное преобразование требует лишь опцию -ffinite-math-only или прагму comb_oper.

  • Добавлена оптимизация машин состояний, которые заданы конструкцией switch в цикле по опции -ffinite-state-machine-transform. Оптимизация имеет статус экспериментальной и корректность её работы не гарантируется.

  • Реализована оптимизация apb_versioning по опции -floop-apb-align-versioning (включена по умолчанию), позволяющая динамически проверять выровненность адресов чтений в наиболее вложенных циклах, и в зависимости от результата проверки передавать управление на одну из версий цикла. В Elbrus V2-V4 оптимизация apb применяется только к тем чтениям, для которых статически или динамически удалось доказать выровненность адреса, это аппаратное ограничение; начиная с Elbrus V5 данное ограничение было снято. Таким образом apb_versioning не имеет смысла сама по себе, а нужна лишь для расширения применимости apb на старых версиях Elbrus. Поскольку apb_versioning может приводить к значительному росту размера кода, данное преобразование применяется только к циклам, имеющим достаточно большое количество итераций.

  • Реализована оптимизация rwpe (Redundant Writes through Pointer Elimination) - удаление избыточных записей в таблицу виртуальных методов в деструкторах.