GCC 16がリリース
(gcc.gnu.org)- GNU Compiler Collectionの新しいリリースは、C++のデフォルト標準を gnu++20 に変更し、C++20実装をもはや experimental と見なさない重要な転換点となる
- C++26 の reflection・contracts・constexpr 機能、C++23 機能、experimental な C++23・C++26 library サポートが追加され、template エラーと type trait constraint failure の診断は階層型メッセージでより詳細になった
- OpenMP と OpenACC は GPU メモリ割り当て、target memset、device memcpy API を拡張し、Ada・Fortran・Modula-2・Algol 68 front end にも新しい言語機能と実験的コンパイラが加わった
- x86-64 は AMD Zen6、Intel Wildcat Lake、Intel Nova Lake をサポートし、AMD GPU・LoongArch・IBM z Systems・Solaris・Windows 向けでもターゲット別機能と ABI の変更が追加された
- JSON 診断形式の削除と SARIF・HTML 診断の強化、static analyzer の改善、libgdiagnostics の 37 個の entrypoint 追加により、ツール連携と診断インフラが大きく広がった
互換性の変更と共通改善
- Solaris では
int8_tなどは C99 標準準拠のためsigned charになり、これは互換性のない変更である- 詳細は Porting to GCC 16 の Solaris 項目 を参照
- Solaris では
-pthreadオプションはもはや_REENTRANTを事前定義しない- 詳細は Porting to GCC 16 の Solaris 項目 を参照
-fdiagnostics-format=のjson形式は削除され、機械可読な診断には SARIF を使う必要がある- Link-Time Optimization は
-flto-toplevel-asm-heuristicsにより最上位 asm 文の処理をより適切に扱えるようになった - speculative devirtualization は一般的な間接関数呼び出しを処理し、2 つ以上の対象推測をサポートする
- vectorizer は reduction のループ内並列性の識別がより柔軟になり、反復回数を特定できないループと uncounted loop のベクトル化をサポートする
- masking を使う vector length agnostic loop のアラインメント用 peeling、mutual peeling for alignment、early break ループの vector induction 計算削除もサポートする
- GCC Command Options と option index は、以前は抜けていた多くのオプションを含むよう修正された
- GCC-specific attributes 文書は、GCC がサポートするすべての C/C++ dialect で許可される標準 attribute 構文をより強調するように現代化された
- attribute 関連資料は重複を減らすよう再構成され、新しい attribute index が追加された
- parameter と option spec file の文書は、GCC 開発者および custom GCC 構成が必要なユーザー向けの GCC internals manual に移された
言語別の主な変更
-
OpenMPとOpenACC
- OpenMP のメモリ割り当てサポートが強化され、
pinnedtrait allocator とompx_gnu_pinned_mem_allocは利用可能な場合に CUDA API を使用し、Nvidia GPU で当該メモリへのアクセス性能を改善する - GNU 拡張の
ompx_gnu_managed_mem_allocallocator とompx_gnu_managed_mem_spaceは、host 上で device-accessible memory を割り当てる- unified-shared memory がサポートされていなくても device からアクセス可能であり、すべての host memory が device-accessible であるシステムでも、ほかのメモリとは page-migration の動作が異なる場合がある
- OpenMP 5.0 は C/C++ で限定的な
declare mapperサポートを追加し、uses_allocatorsclause は OpenMP 5.2 の文法変更と OpenMP 6.0 の semicolon サポートまで含む - OpenMP 5.1 は C/C++ で map clause と
target updateconstruct のiteratormodifier の初期サポートを追加する - OpenMP 5.2 は C/C++ で
begin declare variantdirective をサポートする - OpenMP 6.0 は
omp_target_memsetとomp_target_memset_asyncAPI routine を追加し、no_openmp_constructsassumptions clause も利用できる - OpenMP 5.0、5.1、5.2 で deprecated になった directive と clause はデフォルトで deprecation warning を出し、
-Wno-deprecated-openmpで無効化できる- deprecated named constant または API routine を使用した場合にも warning が出て、
-Wno-deprecated-declarationsで無効化できる
- deprecated named constant または API routine を使用した場合にも warning が出て、
- OpenACC は C/C++/Fortran 向けに
acc_memcpy_deviceとacc_memcpy_device_asyncAPI routine を追加する - OpenACC 3.0 の
waitdirective はifclause を受け付け、OpenACC 3.3 の Fortran API routineacc_attachとacc_detachは OpenACC 2.6 の C/C++ counterpart を補完する - OpenACC 3.4 では Fortran data clause の named constant
PARAMETERの使用が仕様と GCC で許可されるが、GCC では compile-time と runtime の動作に影響しない
- OpenMP のメモリ割り当てサポートが強化され、
-
Ada、Fortran、Modula-2、Algol 68
- Ada GNAT 拡張には Constructor と Destructor が追加され、標準 Ada とかなり異なる construction/finalization メカニズムを提供する
- Ada の Implicit with、Structural Generic instantiation、Extended_Access aspect が追加される
Extended_Accessは unconstrained array subtype を指す general access type declaration に指定でき、pointer representation を変更して、Ada が割り当てていないメモリを foreign language と連携しやすくする
- Ada は
-gnatd_Vまたは verbose mode の-gnatd_Wで compiler debugging 用の VAST を利用でき、Ada 2022 Reduction Expressions の semantic analysis、Ada.Containers.Bounded_Indefinite_Holders、accessibility rule の実装、Android サポートが改善される - Fortran は single node machine で native shared memory multithreading を使う coarray と、Fortran 2018 の
TEAMfeature を扱う - Fortran 2003 Parameterized Derived Types のサポートが改善され、LEN parameter の処理は動作するが、PR82649 に基づく将来的な representation の変更が必要となる
- Fortran 2018 は
IMPORTstatement の拡張、REDUCEintrinsic、新しいGENERICstatement をサポートする - Fortran 2023 は
sinpiのような三角関数の追加、splitintrinsic subroutine、optional lower bound を引数に取るc_f_pointerをサポートする -fexternal-blas64オプションはMATMULで 64-bit integer argument を使って external BLAS routine を呼び出し、64-bit system かつ-ffrontend-optimize適用時のみ有効である- Modula-2 は import list、module name、nested scope symbol の処理中に spelling hint を表示し、新しい wide set 実装と
M2WIDESETlibrary module を導入する- wide set の変更は ABI を変更し、以前の GCC バージョンの object file との間で link-time error を引き起こす可能性がある
- Modula-2 の基本 library には
BinDictbinary dictionary module が追加され、複数の module にWriteとWriteLnprocedure が提供され、-fm2-pathname-root=オプションにより external library module へのアクセスが改善される - GCC には experimental な Algol 68 compiler である
ga68が含まれ、Revised Report と IFIP WG2.1 Algol 68 Support subcommittee が承認した errata の実装を目指す- 一部の GNU extension と POSIX prelude も実装され、言語情報は Algol 68 website、front end 情報は wiki を参照
C++とlibstdc++
- C++ compilationのデフォルト言語バージョンが -std=gnu++17 から -std=gnu++20 に変更
- 以前のC++標準に依存するコードは、build flagに -std= を追加するか、コードをportingする必要があり、porting notes を参照
- C++20 modulesサポートは引き続きexperimentalで、-fmodules で有効化する必要がある
- C++26機能では、reflection、annotations for reflection、base class subobject splicing、function parameter reflection、contracts、constexpr exceptions、constexpr virtual inheritance など多数が実装
- P2996R13 Reflection は
-std=c++26 -freflectionで有効化される - 一部の P2686R4 は部分サポートで、structured binding は
constexprにできるが、constexprautomatic variable参照はまだ許可されていない
- P2996R13 Reflection は
- C++23機能では P2036R3、P2590R2、P2246R1 が実装
- C++ error messageは、template関連の問題などで 階層構造 を持ち、indentationとbullet pointでmessage nestingを表示
- 以前の挙動は
-fno-diagnostics-show-nestingまたは-fdiagnostics-plain-outputで復元可能
- 以前の挙動は
- experimentalなC++20 modulesサポートでは、
--compile-std-moduleオプションを追加して、<bits/stdc++.h>header unitとstd、std.compatmoduleをsource file compile前にビルドする<bits/stdc++.h>header unitがビルド済みであれば、import可能なstandard library headerの#includeを<bits/stdc++.h>importへ透過的に変換する- 報告されていた多くのbugが修正
- standard library type traitのconstraint failure diagnosticsは、
is_constructible_v、is_invocable_vなどがなぜfalseなのかをより詳しく知らせる - libstdc++で128-bit integerをサポートするtargetでは、
std::is_integral<__int128>と類似のtraitが常にtrueになる- 以前はGNU dialectではtrueだったが、strict dialectではそうではなかった
- P0952R2: A new specification for
std::generate_canonicalが、C++11以降で影響を受けるすべてのmodeに実装され、観測されるoutputに影響する- 以前の挙動は
_GLIBCXX_USE_OLD_GENERATE_CANONICAL定義で復元可能
- 以前の挙動は
std::variantABIはC++20以降のmodeと一貫するよう更新され、特定のC++17 modeのclass layoutに影響する- 以前の挙動は
_GLIBCXX_USE_VARIANT_CXX17_OLD_ABI定義で復元可能で、影響はC++17 modeにのみ該当する
- 以前の挙動は
std::regexexecutionはsystem stackではなくheap-based stackを使うように再実装され、より大きなstring matching中のstack overflowを回避- C++20実装はもはやexperimentalではなく、Windowsで
std::chrono::current_zone()が動作する - GCC 16以前のC++20サポートはexperimentalだったため、C++20 componentを使うprogramはolder releaseと互換性がないとみなすべき
- ABI変更の対象には、
<atomic>waiting/notifying function、<semaphore>semaphore type、<syncstream>synchronization、std::formatargsとstd::formatterrepresentation、<compare>のstd::partial_ordering、一部の<ranges>adaptor representation などが含まれる
- ABI変更の対象には、
- experimentalなC++23 libraryサポートには、
std::mdspan、ranges::starts_with、ranges::ends_with、ranges::shift_left、ranges::shift_right、std::allocator_traits::allocate_at_leastが含まれる - experimentalなC++26 libraryサポートには、
std::simd、std::inplace_vector、std::optional<T&>、std::copyable_function、std::function_ref、std::indirect、std::polymorphic、shared pointer向けのstd::owner_equal、<debugging>header などが含まれる
ターゲットとオペレーティングシステムのサポート
-
IA-32/x86-64
- AMD Zen6ベースのCPUは
-march=znver6でサポートされ、Zen5で有効化されたISA拡張に加えて AVX512_BMM、AVX_NE_CONVERT、AVX_IFMA、AVX_VNNI_INT8、AVX512_FP16 を有効化 - AVX512サポートが有効で、
znver4、znver5、znver6チューニング時には、自動ベクトル化が masked vector epilog の使用を試み、コードサイズを削減し性能を改善 - Intel Wildcat Lake は
-march=wildcatlake、Intel Nova Lake は-march=novalakeでサポート-march=novalakeは Panther Lake ベースのISA拡張に APX_F、AVX10.1、AVX10.2、PREFETCHI を追加で有効化
- GCC 16から、複数の
-march=スイッチで AMX-TRANSPOSE、USER_MSR、CLDEMOTE、KL、WIDEKL、PREFETCHI の有効化が削除 -mavx10.1-256、-mavx10.1-512、-mevex512は削除され、-mavx10.1の behavior change warning もあわせて廃止- AMX-TRANSPOSE サポートは GCC 16 で削除され、GCC はもはや
-mamx-transposeを受け付けない - 新しい
--enable-x86-64-mfentryconfigure option は、x86-64プロファイリングでmcountの代わりに__fentry__を使う-mfentryを有効化し、glibcターゲットではデフォルトで有効 --enable-tls=DIALECTはデフォルトTLS dialect の制御をサポートし、デフォルト値はgnu、許可される値はgnuと TLS descriptor 用のgnu2
- AMD Zen6ベースのCPUは
-
AMD GPU、LoongArch、IBM z Systems
- AMD GPUオフロードでは、OpenMP target region と OpenACC compute region の起動オーバーヘッドが大幅に削減
- AMD Instinct MI300
gfx942デバイスの実験的サポートが追加され、genericgfx9-4-genericと大部分で互換性のあるgfx950も含まれる - AMD GPUのデフォルト multilib build set は
gfx908、gfx90a、gfx9-generic、gfx9-4-generic、gfx10-3-generic、gfx11-genericに変更- generic arch がある場合、specific device 向け multilib はデフォルトではもうビルドされない
- generic architecture には ROCm 6.4.0 以降が必要
- 新しいデフォルト multilib set には LLVM 20 以降の assembler と linker が必要
- GCC の AMD installation notes と configuration notes を参照
- LoongArch は
_BitInt (N)とunsigned _BitInt (N)のような bit-precise integer type をサポート - LoongArch は
target_clones属性により、CPU feature ごとの function version を作成し、実行時に最適な version を自動選択する Function Multi-Versioning をサポート - LoongArch32 architecture のサポートが追加され、
ilp32dデフォルトABIとilp32f、ilp32sABI を含む- 標準32-bit版 LA32 と縮小32-bit版 LA32R の両方を扱い、組み込みアプリケーション向けの32-bitターゲットコード生成を可能にする
- この機能は Binutils と glibc のサポートに依存
- S/390、System z、IBM z Systems は bit-precise integer type と
_Float16floating-point type をサポート_Float16演算は software またはfloat命令で実行される
- S/390 系には、Linux kernel の canary address loading runtime patching をサポートするための global stack protector が
-mstack-protector-guard=globalとして追加され、-mstack-protector-guard-recordも追加 - S/390 系の
-m31サポートは deprecated となり、今後の release で削除予定
-
オペレーティングシステム
- Solaris は
-gsctfオプションにより、Solaris CTF、すなわち Compact C Type Format の生成を容易にサポート - Windows は native TLS、すなわち Thread-Local Storage をサポート
- 有効化するには configure 時に
--enable-tlsの指定と GNU binutils 2.44 以降が必要
- 有効化するには configure 時に
- Solaris は
診断、プラグイン、静的解析
- GCC は
-fdiagnostics-add-output=experimental-htmlにより HTML 形式の診断出力 をサポートする - SARIF 出力は dump directory に従い、
build-dir/foo.o出力の例では GCC 16 はbuild-dir/foo.c.sarifに SARIF を書き込む- GCC 15 は同じ例で
foo.c.sarifに書き込んでいた
- GCC 15 は同じ例で
- SARIF 出力は logical location nesting をキャプチャし、多くの場合
fixobject にdescriptionproperty を含む - SARIF
threadFlowLocationのkindsproperty は、非標準の control flow 表現のためにthrow,catch,unwind,setjmp,longjmpの値が新たに追加された - GCC diagnostics は directed graph を関連付けることができ、global directed graph も report できる
- graph は text sink では無視されるが SARIF sink にキャプチャされ、
experimental-htmlは dot を使って SVG ベースでレンダリングする - SARIF または HTML diagnostic sink で
cfgs=yesを設定すると、すべての optimization pass のすべての function に対する GCC intermediate representation キャプチャが有効になる
- graph は text sink では無視されるが SARIF sink にキャプチャされ、
- GCC diagnostics は XML と JSON file 内の logical location を参照できる
sarif-replaytool はこれを使って SARIF input の issue report 時に JSON pointer を提供する
GCC_DIAGNOSTICS_LOGが environment に設定されていると、diagnostic subsystem は stderr または named file に text log を出力する- diagnostic が正確にいつ、なぜ reject されるのかといった内部決定の追跡に使われる
EXPERIMENTAL_SARIF_SOCKETが environment に設定されていると、GCC は startup 時にその socket への接続を試み、発生したすべての diagnostic について JSON-RPC notification を送る- Plugin author 向けに publish/subscribe framework が追加され、loosely-coupled な sender と receiver の間で strongly-typed message を伝達する
- 今回の release で plugin が subscribe できる topic は、特定の function の optimization pass の開始/終了 event と static analyzer 関連 event のみである
- GCC diagnostic sink は
finalizerhook を持つextensionobject を持てるようになり、plugin はこれを使って SARIF output file に追加情報をキャプチャできる - GCC 16 では diagnostic machinery が大幅に整理され、
diagnostic-core.hだけを使う plugin には影響がないはずだ- diagnostics をより複雑に使う plugin maintainer は porting guide を参照する必要がある
- Static analyzer は C++ Named Return Value Optimization と exception の初期サポートを扱えるようになり、単純な C++ の例で利用できる
- ただし scaling issue のため、今回の release では production C++ code で使うのは難しい可能性が高い
-fanalyzerは-fexceptionsが有効な場合、nothrowattribute のない external function call が exception を投げる可能性があると仮定する- 新しい
-fanalyzer-assume-nothrowオプションはこの仮定を無効にする - C++ interoperability のために C code で
-fexceptionsを使うが、使用中の C API が exception を投げる可能性は低い project で warning 増加を回避する用途である
- 新しい
-fanalyzerの user code representation データ構造は、理解と debugging をより容易にするために書き直され、diagnostic location がわずかに改善された- その代わり analyzer の memory usage は増加した
-fanalyzerの memory contents simulation データ構造は再実装され、より高速で保守しやすくなった- analyzer は GCC の
value_rangemachinery を使い始め、一部の false positive を取り除く
libgdiagnostics と修正された問題
- libgdiagnostics では新たに 37 個の entrypoint が追加
- logical location 操作用の entrypoint が 5 個追加
- command-line option と SARIF playback 対応用の entrypoint が 2 個追加
- directed graph 操作用の entrypoint が 12 個追加され、graph の生成、global graph の受け渡し、diagnostic graph の接続、node と edge の追加・取得、node label と location の設定をサポート
- diagnostic text を buffer として構成するための entrypoint が 17 個追加
- message buffer の作成・解放、string/text/byte/printf の append、event id の append、URL/quote/color 範囲の処理、dump、buffer ベースの diagnostic finish と location label/event の追加を含む
diagnostic_manager_set_debug_physical_locations()も追加- GCC bug tracking system で 16.1 release に fixed とされている problem report の一覧は PR list で確認可能
- この一覧は完全ではない可能性があり、修正済みの一部 PR が含まれていない場合がある
1件のコメント
Hacker Newsのコメント
採用されるべきなのに、実際にはあまり使われなさそうな実装機能として P2590R2 Explicit lifetime management を挙げたい
これは
std::start_lifetime_asのためのもので、ポインタを構造化型へ type-pun するときの UBではない方法 である外部 I/O バッファを扱うほぼすべての zero-copy コードはだいたい
reinterpret_cast(buffer.get())のような形をしており、これは undefined behavior だが、これからはreinterpret_castをstart_lifetime_asに置き換えれば、もはや悪いことではなくなるhttps://en.cppreference.com/cpp/memory/start_lifetime_as
ここで
reinterpret_castを使うのはバグであるstart_lifetime_asは、メモリ laundering の呪文にきれいな標準名を与えるだけでなく、もう1つ役に立つ。意味的にはメモリに触れない一方で、no-opmemmoveは本質的にメモリに触れる。実際にはコンパイラがmemmoveが no-op だと見抜いて最適化できるため、大きな違いはあまりないreadの実装次第である。コンパイラから見て完全に opaque なら、カーネルやネットワークカードのようなものが実際にそのバッファ内にFooを構築していることになるので、cast は完全に正当化されるstart_lifetime_asは、バッファ lifetime がコンパイラに対して透過的で、aliasing の仮定を壊しうる場合に有用だTは完全に新しいオブジェクトで、その中に subobject があり、その1つがU型だという意味に見える。Uはbit_castのように初期化されるが、おそらくそのアドレスにすでにあるビットから cast するという意味だったのだろう。だがobjが定義なしに出てくるので、正しいアドレスにある何かを指していると考えるしかないしかし E が何なのか が曖昧だ。ページには「E is the lvalue of type U denoting obj」とあるが、
objはおそらくcharのような型のはずで、もし最初からU型ならbit_castは不要だったはずだcharバッファでは type punning が許されているさっき調べるまで、GCC のリリース日程 がこんなに規則的だとは知らなかった: https://gcc.gnu.org/develop.html
90年代までは、欲しい機能をすべて入れた大型リリースを waterfall で作れると考えられていたが、プロジェクトが大きくなると、常にまだ準備できていない機能を作業している人が出てくる。定期リリースなら、それでも顧客にリリースを届けられる
このやり方は、準備できるか不確かな開発者に不安定な機能を無効化するトグルを作らせることになり、現実的にはそれが最善に近い
昔はもっと遅く、GCC 2.95 の C++ バグを回避するのにあまりに多くの時間を費やした
問題だったバージョンをまだ覚えているという事実自体が多くを物語っている
もうしばらく使っている。Debian sid には trunk パッケージがある
c++26 reflectionが入っているので、reflection で魔法のようなことをいろいろやっていて、ser-des のような一部の用途ではずっと良いエコシステム内に LSP サーバー さえあればいいのだが
libstdが問題を起こしている-fdiagnostics-format=のいわゆるjsonフォーマットは今回のリリースで削除され、GCC で machine-readable diagnostics が必要なら SARIF を使うよう書かれているその一方で、
-fdiagnostics-add-output=experimental-htmlによって diagnostics を HTML 出力 できるようになったともあるJSON 出力を削除しながら HTML 出力を追加した判断の背景が気になる
初歩的な質問だが、GCC は内部で LLVM をどこかに使っているのか、それとも独自の code generation と optimization pipeline を持っているのか気になる。LLVM と比べてどの程度なのかも知りたい
LLVM より多くの target をサポートしており、多くの場合は同等かそれ以上に良い実行ファイルを生成する
Wikipedia によれば GCC は 1987年3月22日、LLVM の初期リリースは 2003年である
さらに大きな違いはライセンスだ。GCC は GPL、LLVM は Apache License なので、両プロジェクトはコードを共有していない
Apple は GCC から LLVM へ移行していた時期の 2012年ごろ、
llvm-gccを使っており、これは GCC front end と LLVM back end の組み合わせだったhttps://dragonegg.llvm.org
-Ofastは今でも-fno-fast-mathを無視するのか?この約3か月、unstable ソース を使ってみた
最近の GCC ではコンパイルできないが以前の GCC では問題なく動くプログラムがあり、現時点では全体として
gcc 15.xのほうが自分には合っているそれでも 3000本以上のプログラムをコンパイルすると考えれば、大半はうまくいき、一部だけがパッチを必要とする。そうしたパッチは LFS/BLFS で見つかることが多く、個別の問題を
sedで直せばたいてい動くそうした問題が修正されていることを願う。私たちみんなには安定性と「ただ動くこと」が必要だ