После года разработки опубликован релиз свободного набора компиляторов GCC 11.1, первый значительный выпуск в новой ветке GCC 11.x. В соответствии с новой схемой нумерации выпусков, версия 11.0 использовалась в процессе разработки, а незадолго до выхода GCC 11.1 уже ответвилась ветка GCC 12.0, на базе которой будет сформирован следующий значительный релиз GCC 12.1.
GCC 11.1 примечателен переходом на использование по умолчанию формата отладочных файлов DWARF 5, включением по умолчанию стандарта C++17 (“-std=gnu++17”), значительным улучшением поддержки стандарта C++20, экспериментальной поддержкой C++23, улучшениями, связанными с будущим стандартом языка Си (C2x), новыми оптимизациями производительности.
Основные изменения:
- Режим по умолчанию для языка C++ переключён на использование стандарта C++17 (-std=gnu++17) вместо ранее предлагавшегося C++14. Возможно выборочное отключение нового поведения C++17 при обработке шаблонов, в которых в качестве параметра используются другие шаблоны (-fno-new-ttp-matching).
- Добавлена поддержка аппаратного ускорения работы инструмента AddressSanitizer, позволяющего определить факты обращения к освобождённым областям памяти, выхода за пределы границ выделенного буфера и некоторые другие типы ошибок при работе с памятью. Аппаратное ускорение пока доступно только для архитектуры AArch64 и пока сосредоточено на использование при компиляции ядра Linux. Для включения аппаратного ускорения AddressSanitizer при сборке компонентов пространства пользователя добавлен флаг “-fsanitize=hwaddress”, а для ядра – “-fsanitize=kernel-hwaddress”.
- При генерации отладочной информации по умолчанию задействован формат DWARF 5, по сравнению с прошлыми версиями позволяющий генерировать на 25% более компактные отладочные данные. Для полной поддержки DWARF 5 требуется binutils как минимум версии 2.35.2. В отладочных инструментах формат DWARF 5 поддерживается начиная с GDB 8.0, valgrind 3.17.0, elfutils 0.172 и dwz 0.14. Для генерации отладочных файлов с использованием других версий DWARF можно использовать опции “-gdwarf-2”, “-gdwarf-3” и “-gdwarf-4”.
- Повышены требования к компиляторам, которые можно использовать для сборки GCC. Компилятор теперь должен поддерживать стандарт C++11 (ранее требовался C++98), т.е. если для сборки GCC 10 достаточно было наличия GCC 3.4, для для сборки GCC 11 теперь требуется как минимум GCC 4.8.
- Изменено наименование и размещение файлов для сохранения дампов, временных файлов и дополнительной информации, необходимой для проведения LTO-оптимизации. Подобные файлы теперь всегда сохраняются в текущем каталоге, если путь явно не изменён через параметры “-dumpbase”, “-dumpdir” и “-save-temps=*”.
- Объявлена устаревшей и скоро будет удалена поддержка
бинарного формата BRIG, предназначенного для использования с языком HSAIL (Heterogeneous System Architecture Intermediate Language). - Расширены возможности режима ThreadSanitizer (-fsanitize=thread), предназначенного для обнаружения состояния гонки при совместном доступе к одним и тем же данным из различных нитей многопоточного приложения. В новом выпуске добавлена поддержка альтернативных runtime и окружений, а также поддержка отладочного инструмента KCSAN (Kernel Concurrency Sanitizer), предназначенного для динамического выявления состояний гонки внутри ядра Linux. Добавлены новые опции “–param tsan-distinguish-volatile” и “–param tsan-instrument-func-entry-exit”.
- Номера столбцов в диагностических сообщениях теперь отражают не счётчик байт от начала строки, а действительно номера столбцов, учитывающих многобайтовые символы и символы занимающие несколько позиций в строке (например, символ 🙂 занимает две позиции и кодируется 4 байтами). Аналогично символы табуляции теперь обрабатываются как определённое число пробелов (настраивается через опцию -ftabstop, по умолчанию 8). Для восстановления старого поведения предложено опция “-fdiagnostics-column-unit=byte”, а для определения начального значения (нумерация с 0 или 1) опция “-fdiagnostics-column-origin=“.
- В векторизаторе обеспечен учёт всего содержимого функции и обработка возможностей, связанных с пересечениями и отсылками к предыдущим блокам в графе потока управления (CFG, control-flow graph).
- В оптимизаторе реализована возможность преобразования в выражение switch серии условных операций, в которых сравнивается одна и та же переменная. В дальнейшем выражение switch может быть закодировано с применением инструкций битового тестирования (для управления подобного преобразования добавлена опция “-fbit-tests”).
- Улучшены межпроцедурные оптимизации. Добавлен новый проход IPA-modref (-fipa-modref) для отслеживания побочных эффектов при вызове функций и повышения точности анализа. Улучшена реализация прохода IPA-ICF (-fipa-icf), в котором сокращено потребление памяти при компиляции и увеличено числу унифицированных функций, для которых выполняется объединение идентичных блоков кода. В проходе IPA-CP (Interprocedural constant propagation) улучшена эвристика по прогнозированию с учётом известных границ и особенностей работы циклов.
- В реализации оптимизаций на этапе связывания (LTO) формат байткода оптимизирован для сокращения размера и повышения скорости обработки. Уменьшено пиковое потребление памяти на этапе связывания.
- В механизме оптимизации на основе результатов профилирования кода (PGO – Profile-guided optimization), позволяющем генерировать более оптимальный код на основе анализа особенностей выполнения, сокращён размер файлов с данными GCOV за счёт более компактной упаковки нулевых счётчиков. Улучшен режим “-fprofile-values“, благодаря отслеживанию большего числа параметров при косвенных вызовах.
- Продолжена реализация стандарта OpenMP 5.0 (Open Multi-Processing), определяющего API и способы применения методов параллельного программирования на многоядерных и гибридных (CPU+GPU/DSP) системах с общей памятью и блоками векторизации (SIMD). Добавлена начальная поддержка директивы allocate и возможность использования неоднородных циклов в конструкциях OpenMP. Реализована поддержка переменной окружения OMP_TARGET_OFFLOAD.
- Улучшена предоставляемая для языков C, C++ и Fortran реализация спецификации параллельного программирования OpenACC 2.6, определяющей средства для выноса операций (offloading) на GPU и специализированные процессоры, такие как NVIDIA PTX.
- Для языков семейства Си реализован новый атрибут “no_stack_protector”, предназначенный для пометки функций для которых не следует включать защиту стека (“-fstack-protector”). Атрибут malloc расширен поддержкой идентификации пар вызовов для выделения и освобождения памяти (allocator/deallocator), что используется в статическом анализаторе для определения типовых ошибок работы с памятью (утечки памяти, использование после освобождения, двойной вызов функции free и т.п.) и в предупреждениях компилятора “-Wmismatched-dealloc”, “-Wmismatched-new-delete” и “-Wfree-nonheap-object”, информирующих о несогласованности операций освобождения и выделения памяти.
- Для языка Си добавлены новые предупреждения:
- “-Wmismatched-dealloc” (включён по умолчанию) – предупреждает об операциях освобождения памяти в которых используется указатель, не сочетающийся с функциями выделения памяти.
- “-Wsizeof-array-div” (включается при указании “-Wall”) – предупреждает о делении двух операторов sizeof, если делитель не соответствует размеру элемента массива.
- “-Wstringop-overread” (включён по умолчанию) – предупреждает о вызове строковой функции, читающей данных из области вне границы массива.
- “-Wtsan” (включён по умолчанию) – предупреждает о использовании возможностей (таких как std::atomic_thread_fence), не поддерживаемых в ThreadSanitizer.
- “-Warray-parameter” и “-Wvla-parameter” (включается при указании “-Wall”) – предупреждает о переопределении функций с не сочетающимся объявлением аргументов, связанных с массивами фиксированной и переменной длины.
- Предупреждение “-Wuninitialized” теперь определяет попытки чтения из неинициализированной динамически выделенной памяти.
- В предупреждении “-Wfree-nonheap-object” расширен спектр определяемых случаев вызова функций освобождения памяти с указателем, полученным не через функции динамического выделения памяти.
- В предупреждении “-Wmaybe-uninitialized” расширено выявление передачи в функции указателей, ссылающихся на неинициализированные области памяти.
- Для языка Си реализована порция новых возможностей, развиваемых в рамках стандарта C2X (включается через указание -std=c2x и -std=gnu2x): макросы BOOL_MAX и BOOL_WIDTH, необязательность указания имён неиспользуемых параметров в определениях функций (как в C++), атрибут “[[nodiscard]]”, оператор препроцессора “__has_c_attribute”, макросы FLT_IS_IEC_60559, DBL_IS_IEC_60559, LDBL_IS_IEC_60559, __STDC_WANT_IEC_60559_EXT__, INFINITY, NAN, FLT_SNAN, DBL_SNAN, LDBL_SNAN, DEC_INFINITY и DEC_NAN, NaN=макросы для FloatN, _FloatNx и _DecimalN, возможность указания меток перехода до объявлений и в конце составных операторов.
- Для C++ реализована порция изменений и новшеств, предложенных в стандарте C++20, включая виртуальные функции “consteval virtual”, псевдодеструкторы окончания жизненного цикла объектов, использование класса enum и вычисление размера массива в выражении “new”.
- Для C++ добавлена экспериментальная поддержка некоторых улучшений, развиваемых для будущего стандарта C++23 (-std=c++23, -std=gnu++23, -std=c++2b, -std=gnu++2b). Например, появилась поддержка литерального суффикса “zu” для знаковых значений size_t.
- В libstdc++ улучшена поддержка стандарта C++17, включая появление реализации std::from_chars и std::to_chars для типов с плавающей запятой. Реализованы новые элементы стандарта C++20, включая std::bit_cast, std::source_location, атомарные операции wait и notify, , , , , а также будущего стандарта C++23 (std::to_underlying, std::is_scoped_enum)
Добавлена экспериментальная поддержка типов для параллельной обработки данных (SIMD, Data-Parallel Types). Ускорена реализация std::uniform_int_distribution. - Снят признак альфа-качества с libgccjit, разделяемой библиотеки для встраивания генератора кода в другие процессы и использования для организации JIT-компиляции байткода в машинный код. Добавлена возможность сборки libgccjit для MinGW.
- Добавлена поддержка архитектуры AArch64 Armv8-R (-march=armv8-r).
Для архитектур AArch64 и ARM добавлена поддержка процессоров (для указания в параметрах -mcpu и -mtune): Arm Cortex-A78 (cortex-a78), Arm Cortex-A78AE (cortex-a78ae), Arm Cortex-A78C (cortex-a78c), Arm Cortex-X1 (cortex-x1), Arm Neoverse V1 (neoverse-v1) и Arm Neoverse N2 (neoverse-n2). Также добавлены CPU Fujitsu A64FX (a64fx) и Arm Cortex-R82 (cortex-r82), поддерживающие только архитектуру AArch64. - Добавлена поддержка автовекторизации c использованием SIMD-инструкций Armv8.3-a (AArch64/AArch32), SVE (AArch64), SVE2 (AArch64) и MVE (AArch32 M-profile) операций, выполняющих сложение, вычитание, умножение и варианты сложения/вычитания над комплексными числами.
Для ARM добавлена начальная поддержка автовекторизации с использованием набора инструкций MVE. - Для ARM-платформ предоставлен полный набор встроенных в компилятор Си-функций (Intrinsics), заменяемых на расширенные векторные инструкции (SIMD), охватывающий все инструкции NEON, документированные в спецификации ACLE Q3 2020.
- В бэкенд для генерации кода для GPU AMD на базе микроархитектуры GCN добавлена поддержка GPU gfx908.
- Добавлена поддержка новых процессоров и реализованных в них новых расширений набора инструкций:
- Intel Sapphire Rapids (-march=sapphirerapids, включает поддержку инструкций MOVDIRI, MOVDIR64B, AVX512VP2INTERSECT, ENQCMD, CLDEMOTE, SERIALIZE, PTWRITE, WAITPKG, TSXLDTRK, AMT-TILE, AMX-INT8, AMX-BF16 и AVX-VNNI).
- Intel Alderlake (-march=alderlake, включает поддержку инструкций CLDEMOTE, PTWRITE, WAITPKG, SERIALIZE, KEYLOCKER, AVX-VNNI и HRESET).
- Intel Rocketlake (-march=rocketlake, аналог Rocket Lake без поддержки SGX).
- AMD Zen 3 (-march=znver3).
- Для систем IA-32/x86-64 на базе процессоров Intel добавлена поддержка новых процессорных инструкций TSXLDTRK, SERIALIZE, HRESET, UINTRKEYLOCKER, AMX-TILE, AMX-INT8, AMX-BF16, AVX-VNNI.
- Добавлена поддержка флагов “-march=x86-64-v[234]” для выбора уровней архитектуры x86-64 (v2 – охватывает расширения SSE4.2, SSSE3, POPCNT и CMPXCHG16B; v3 – AVX2 и MOVBE; v4 – AVX-512).
- Добавлена поддержка систем RISC-V с порядком следования байт “big-endian”. Добавлена опция “-misa-spec=*” для выбора версии спецификации архитектуры набора команд RISC-V. Добавлена поддержка AddressSanitizer и защиты стека при помощи канареечных меток.
- Продолжено усовершенствование режима статического анализа “-fanalyzer“, который выполняет ресурсоёмкий межпроцедурный анализ путей выполнения кода и потоков данных в программе. Режим способен на этапе компиляции выявлять такие проблемы, как двойной вызов функции free() для одной области памяти, утечки файловых дескрипторов, разыменование и передачу нулевых указателей, обращение к освобождённым блокам памяти, использование неинициализированных значений и т.п. В новой версии:
- Полностью переписан код для отслеживания состояния программы. Решены проблемы с проверкой очень больших Си-файлов.
- Добавлена начальная поддержка C++.
- Анализ выделения и освобождения памяти абстрагирован от конкретных функций malloc и free, и теперь поддерживает new/delete и new[]/delete[].
- Добавлены новые предупреждения: -Wanalyzer-shift-count-negative, -Wanalyzer-shift-count-overflow, -Wanalyzer-write-to-const и -Wanalyzer-write-to-string-literal.
- Добавлены новые отладочные опции -fdump-analyzer-json и -fno-analyzer-feasibility.
- Реализована возможность расширения анализатора через плагины к GCC (например, подготовлен плагин для проверки некорректного использования глобальной блокировки (GIL) в CPython).