gcc 10の変更点

gcc 10がリリースされました。 早速何が変わったのかを見てみましょう。

Changes, New Features, and Fixesを読む

変更点は Changes, New Features, and Fixes に書かれています。

まず増えたビルトイン関数やオプションの説明があって、最適化があって、C言語ではUnicode識別子が使えるようになってて -std=c2x モードの実装が始まってて、C++もC++20の実装が着々と進んでて、相変わらずFortranも活発に開発されてていい感じですね。 対応CPUもAArch64が活発ですが、x86もしっかり新製品に対応してきているようです。

うんうん、今回も実り多いバージョンアップのようです。 おしまい。

…。

……。

あの、Adaフロントエンドは? ついでにD言語やGoすら何も触れられていません。

いやリリースされたばっかりでまだ書かれてないだけ、と9の変更点8の変更点を辿っていっても、C/C++とFortran以外はほとんど何も書かれていません。

変更点がないのでしょうか。 もう開発されてないのでしょうか。 勿論そんなことはないです。 gccのChangesには全ての変更点が書かれるわけではないのです。 特に各言語のフロントエンドに関しては、C/C++とFortran以外はほとんど全スルーが常態化しています。

変更点が知りたければ調べろ!

私事で申し訳ありませんがカスタムのAdaランタイム(規格違反)を作ってまして、そのためにgccのAdaフロントエンドの変更点を書き留めています。

https://github.com/ytomino/drake/wiki/GCC-Versions

ここにgcc 10の分も書き足そう、というのが今日の主題です。

どこから調べるか

闇雲に試して変更が洗い出せるというわけでもありませんし取っ掛かりは必要です。

gcc-patches

まず真っ先に思いつくのが開発用メーリングリストである gcc-patches を購読することです。

一年間購読してみました。 メールボックスがとんでもないことになりました。 物量があり過ぎますので購読はやめたほうがいいです。

それでもログを眺めておくと雰囲気を掴む役には立って、AdaCore社はgccのスケジュールを守らずにStage 3になってからも平気でバグ修正以外のコミットをしてやがるな、とかそういうことがわかります。 コミッターの名前を把握しておくとバグ報告するときに見当違いな行動を取らずに済むかもしれません。

AdaCore社のDevelopment Logs

AdaCore社の Development Logs にはGNAT Proの変更点が書かれています。 GNAT Proはgccをカスタマイズした有償版の製品で、フロントエンドは共通です。

Adaフロントエンドに加えられた変更が細かく解説されていて役に立ちます。 ただしGNAT Proと本家gccは構成やリリースサイクルが異なっており、はっきりしたバージョンの対応があるわけではありません。 どの変更がgccのどのバージョンから適用されているか簡単にわかる方法はありません。 時期から大雑把に絞り込んで、後は複数バージョンのgccを比べながら試してみることになります。

gcc-patchesを検索して対応するコミットがあれば確実なのですが、共通のキーワードがあったりはしませんので実際には難しいです。 それでも両方を眺めておくと、あ、この変更がこっちにも来ている、と気付けるときもあります。

git diff

というわけで本命です。

gccのリポジトリを取ってきてgit diffで調べます。

どうせビルドもするのですから毎回ソースアーカイブを展開するよりリポジトリの形で持っていたほうが楽ですし。 (え?ディストリビューションのパッケージを使う派ですって?)

gccのリポジトリをローカルにfetchする

gccのリポジトリは巨大ですから何も考えずにgit cloneしてしまいますととんでもないことになります。 サイズもそうですしサーバーに過大な負荷をかけてしまうのも申し訳ないです。 最低限必要なものだけfetchするようにしましょう。

まずは空のbareリポジトリを作ります。 bareリポジトリは格納専用のリポジトリです。 実際の作業はgit worktree addして別の場所で行います。 bareリポジトリにすることは必須ではありませんが巨大なリポジトリを扱うにはこの方が後で融通が利きます。

$ mkdir gcc.git
$ cd gcc.git
$ git init --bare

一旦手を止めて作ったgcc.gitディレクトリをデスクトップ検索から除外しましょう。 bareリポジトリに検索インデックスが作られても嬉しくありませんし、電気代の無駄です。 macOSであればSpotlightのプライバシーに追加、他の環境でもデスクトップ検索機能があるなら除外する方法もあるはずです。

閑話休題。 gccのリポジトリをリモートリポジトリとして追加します。

公式のリポジトリについては Anonymous read-only Git access に書かれています。 勿論githubやrepo.or.cz等にあるミラーでもいいです。

$ git remote add origin git://gcc.gnu.org/git/gcc.git

いよいよfetchを行います。 必要なものだけを取れるように欲しいタグを指定してオプション --depth=1 も付けます。

$ git fetch --depth=1 origin releases/gcc-10.1.0

特にオプション --depth=1 は忘れないようにしないといけません。 これを付けないと履歴を全部取ることになりますのでほとんど全cloneと変わりません。

比較のために9.1も取っておきます。 現状9.3まで出ていますがブランチが別れたのは9.1の時点ですので10.1と比較するなら9.1です。

$ git fetch --depth=1 origin releases/gcc-9.1.0

bareリポジトリでもgit diffを見ることはできます。

$ git diff origin/releases/gcc-9.1.0 origin/releases/gcc-10.1.0

必要なものを一通り取ってきたらワークツリーを作りましょう。 直接見えたほうが便利ですしビルドもしなければなりませんし。

$ git config gc.worktreePruneExpire never
$ git worktree add -b my-gcc-10.1 ~/gcc-10.1-src origin/releases/gcc-10.1.0
$ cd ~/gcc-10.1-src

gc.worktreePruneExpire はワークツリーの有効期限です。 デフォルトですと3ヶ月で消されます。 次のバージョンが出て変更点を調べるためにこのリポジトリを操作しようとして何かおかしいと気付くことになります。 要らんでしょうgitのこの仕様。

差分を見ていく

それでは実際にgcc 10の変更点を調べていきましょう。

doc/

新機能がドキュメントに書かれていれば手っ取り早いです。

ただしドキュメントに差分として現れたからといって本当に変更点かは疑ってかかる必要があります。 単にこれまで書いていなかっただけというケースも考えられます。 またASIS関係のツールやGNAT Studio(GPS)はFSF公式版gccには収録されていませんがドキュメントには書かれています。

新しく増えたらしいものを探しますと、こんな感じでしょうか。

  • No_Caching アスペクト

  • pragma Aggregate_Individually_Assign

  • pragma Initialize_Scalars が引数を取れるようになっている

  • pragma Machine_Attribute で属性へ引数を複数渡せるようになっている

  • pragma No_Caching

  • pragma No_Run_Time が削除されている

  • GNAT.Branch_Prediction

  • -gnatw_a/-gnatw_A

  • -gnatw_c/-gnatw_C

  • -gnatw_r/-gnatw_R

  • -gnatyD

  • gnatbindのオプション -H

  • gnatbindのオプション -minimal

  • gnatelimが削除されている

  • gnatmemが引数として深さ(DEPTH)を取れるようになっている

  • gnatmetricに追加されたオプション多数(省略)

  • gnatppに追加されたオプション多数(省略)、削除されたオプションもある

うちgnatelim、gnatmetric、gnatppはASIS関係のツールとなります。 GNAT版のソースコードは公開されていますので公式版gccで使いたければ別途調整しながらコンパイルする必要があります。 やろうとしたこともありますがかなり手間です、と付け加えておきます。 ASIS関係が使いたければ素直にGNAT Community Editionで使うほうがいいです。

gnatbindについての記述が大きく変わっていたのは気にしておきます。

snames.ads-tmpl

snames.ads-tmplには属性、アスペクト、pragma等がリストアップされています。 つまり新しい属性等はこのファイルの差分に現れます。

@@ -389,6 +389,7 @@ package Snames is
    Name_Ada_12                         : constant Name_Id := N + $; -- GNAT
    Name_Ada_2012                       : constant Name_Id := N + $; -- GNAT
    Name_Ada_2020                       : constant Name_Id := N + $; -- GNAT
+   Name_Aggregate_Individually_Assign  : constant Name_Id := N + $; -- GNAT
    Name_Allow_Integer_Address          : constant Name_Id := N + $; -- GNAT
    Name_Annotate                       : constant Name_Id := N + $; -- GNAT
    Name_Assertion_Policy               : constant Name_Id := N + $; -- Ada 05
@@ -592,10 +593,12 @@ package Snames is
    Name_Machine_Attribute              : constant Name_Id := N + $; -- GNAT
    Name_Main                           : constant Name_Id := N + $; -- GNAT
    Name_Main_Storage                   : constant Name_Id := N + $; -- GNAT
-   Name_Max_Entry_Queue_Depth          : constant Name_Id := N + $; -- Ada 12
+   Name_Max_Entry_Queue_Depth          : constant Name_Id := N + $; -- GNAT
+   Name_Max_Entry_Queue_Length         : constant Name_Id := N + $; -- Ada 12
    Name_Max_Queue_Length               : constant Name_Id := N + $; -- GNAT
    Name_Memory_Size                    : constant Name_Id := N + $; -- Ada 83
    Name_No_Body                        : constant Name_Id := N + $; -- GNAT
+   Name_No_Caching                     : constant Name_Id := N + $; -- GNAT
    Name_No_Elaboration_Code_All        : constant Name_Id := N + $; -- GNAT
    Name_No_Inline                      : constant Name_Id := N + $; -- GNAT
    Name_No_Return                      : constant Name_Id := N + $; -- Ada 05
@@ -781,7 +784,6 @@ package Snames is
    Name_Link_Name                      : constant Name_Id := N + $;
    Name_Low_Order_First                : constant Name_Id := N + $;
    Name_Lowercase                      : constant Name_Id := N + $;
-   Name_Max_Entry_Queue_Length         : constant Name_Id := N + $;
    Name_Max_Size                       : constant Name_Id := N + $;
    Name_Mechanism                      : constant Name_Id := N + $;
    Name_Message                        : constant Name_Id := N + $;
@@ -1000,6 +1002,7 @@ package Snames is
    Name_Priority                       : constant Name_Id := N + $; -- Ada 05
    Name_Range                          : constant Name_Id := N + $;
    Name_Range_Length                   : constant Name_Id := N + $; -- GNAT
+   Name_Reduce                         : constant Name_Id := N + $;
    Name_Ref                            : constant Name_Id := N + $; -- GNAT
    Name_Restriction_Set                : constant Name_Id := N + $; -- GNAT
    Name_Result                         : constant Name_Id := N + $; -- GNAT
@@ -1511,6 +1514,11 @@ package Snames is
    Name_Runtime_Library_Dir              : constant Name_Id := N + $;
    Name_Runtime_Source_Dir               : constant Name_Id := N + $;

+   --  Additional names used by the Repinfo unit
+
+   Name_Discriminant                     : constant Name_Id := N + $;
+   Name_Operands                         : constant Name_Id := N + $;
+
    --  Other miscellaneous names used in front end

    Name_Unaligned_Valid                  : constant Name_Id := N + $;
@@ -1667,6 +1675,7 @@ package Snames is
       Attribute_Priority,
       Attribute_Range,
       Attribute_Range_Length,
+      Attribute_Reduce,
       Attribute_Ref,
       Attribute_Restriction_Set,
       Attribute_Result,
@@ -1841,6 +1850,7 @@ package Snames is
       Pragma_Ada_2020,
       --  Note that there is no Pragma_Ada_20. Pragma_Ada_05/12 are for
       --  compatibility reasons only; the full year names are preferred.
+      Pragma_Aggregate_Individually_Assign,
       Pragma_Allow_Integer_Address,
       Pragma_Annotate,
       Pragma_Assertion_Policy,
@@ -2001,9 +2011,11 @@ package Snames is
       Pragma_Main,
       Pragma_Main_Storage,
       Pragma_Max_Entry_Queue_Depth,
+      Pragma_Max_Entry_Queue_Length,
       Pragma_Max_Queue_Length,
       Pragma_Memory_Size,
       Pragma_No_Body,
+      Pragma_No_Caching,
       Pragma_No_Elaboration_Code_All,
       Pragma_No_Inline,
       Pragma_No_Return,

ドキュメントに書かれていた No_Caching アスペクトやpragma Aggregate_Individually_Assign 等が追加されているのが確認できます。

他にも追加がありました。

  • 'Reduce 属性

  • pragma Max_Entry_Queue_Length

どちらもAda 202xの機能ですのでドキュメントには書かれなかったのでしょう。 'Reduce 属性実装ですよ。 ちゃんと使えるかどうかは試してみないとですね。

libgnat/s-rident.ads

libgnat/s-rident.adsにはpragma Restrictions で指定できる制限がリストアップされています。

このファイルに差分はありませんでした。

rtsfind.ads

rtsfind.adsにはコンパイラによって参照されるライブラリ中の識別子がリストアップされています。 つまり必須ライブラリが増えていればこのファイルの差分に現れます。 (C++で言えばtypeid演算子が std::type_info を必要とするようなものです。)

@@ -220,6 +171,7 @@ package Rtsfind is
       System_Atomic_Primitives,
       System_Aux_DEC,
       System_Bignums,
+      System_Bitfields,
       System_Bit_Ops,
       System_Boolean_Array_Operations,
       System_Byte_Swapping,
@@ -809,6 +761,8 @@ package Rtsfind is
      RE_To_Bignum,                       -- System.Bignums
      RE_From_Bignum,                     -- System.Bignums

+     RE_Copy_Bitfield,                   -- System.Bitfields
+
      RE_Bit_And,                         -- System.Bit_Ops
      RE_Bit_Eq,                          -- System.Bit_Ops
      RE_Bit_Not,                         -- System.Bit_Ops
@@ -2051,6 +2005,8 @@ package Rtsfind is
      RE_To_Bignum                        => System_Bignums,
      RE_From_Bignum                      => System_Bignums,

+     RE_Copy_Bitfield                    => System_Bitfields,
+
      RE_Bit_And                          => System_Bit_Ops,
      RE_Bit_Eq                           => System_Bit_Ops,
      RE_Bit_Not                          => System_Bit_Ops,

gcc 10では System_Bitfields.Copy_Bitfield が新たに必要になっていました。

RE_Copy_Bitfield でgrepしますとexp_ch5.adbで配列の代入のためにこれを呼ぶコードを生成しているようです。

実装の方はlibgnat/s-bitfie.adsからlibgnat/s-bituti.adsと見ていきますと、どうやら Copy_Bitfield はビットオフセット付きの memcpy のようです。

例えばこのようなコードが Copy_Bitfield の呼び出しにコンパイルされるようです。 (従来はループが生成されていました。)

declare
   type Unsigned_5 is mod 2 ** 5
      with Size => 5;
   type Unsigned_5_Array is array (1 .. 64) of Unsigned_5
      with Component_Size => 5;
   A, B : Unsigned_5_Array;
begin
   A (10 .. 19) := B (30 .. 39);

gnatmake --help

追加されたオプションについてはこちらでも確認します。

$ /opt/ytomino/gcc-9.3.0-vanilla/bin/gnatmake --help > 9
$ /opt/ytomino/gcc-10.1.0-vanilla/bin/gnatmake --help > 10
$ diff -u 9 10
@@ -184,6 +184,8 @@
         A    turn off all optional info/warnings
         .a*+ turn on warnings for failing assertion
         .A   turn off warnings for failing assertion
+        _a*+ turn on warnings for anonymous allocators
+        _A   turn off warnings for anonymous allocators
         b+   turn on warnings for bad fixed value (not multiple of small)
         B*   turn off warnings for bad fixed value (not multiple of small)
         .b*+ turn on warnings for biased representation

-gnatw_a/-gnatw_A はありましたがドキュメントには書かれていた -gnatw_c/-gnatw_C-gnatw_r/-gnatw_R-gnatyD がありませんね? これらについては実際に試してみる必要がありそうです。

gnatbind --help

ドキュメントではgnatbindの変更が多かったのでこちらも見ておきます。

$ /opt/ytomino/gcc-9.3.0-vanilla/bin/gnatbind --help > 9
$ /opt/ytomino/gcc-10.1.0-vanilla/bin/gnatbind --help > 10
$ diff -u 9 10
@@ -21,13 +21,16 @@
   -E        Same as -Ea
   -ffile    Force elaboration order from given file
   -F        Force checking of elaboration Flags
+  -G        Generate binder file suitable for CCG
   -h        Output this usage (help) information
+  -H        Legacy elaboration order model enabled
   -Idir     Specify library and source files search path
   -I-       Don't look for sources & library files in default directory
   -K        Give list of linker options specified for link
   -l        Output chosen elaboration order
   -Lxyz     Library build: adainit/final renamed to xyzinit/final, implies -n
   -mnnn     Limit number of detected errors/warnings to nnn (1-999999)
+  -minimal  Generate binder file suitable for space-constrained applications
   -Mxyz     Rename generated main program from main to xyz
   -n        No Ada main program (foreign main routine)
   -nostdinc Don't look for source files in the system default directory

どうやら初期化順を求めるやり方が変わったみたいです。 (しょっちゅう変わっている気もしますが。) -H は前のやり方を使うオプションでしょう。

-G はドキュメントにはありませんでしたがCCG関係ということで無視します。 CCGは現在開発中のC言語バックエンドらしくてgccとは関係なさそうです。

-minimal は試してみたいですね。

試す

これで取っ掛かりは出てきましたので、後は試していくだけです。

もし他にこの作業をしておられる方がいましたら是非記事を書いてください。 DやGoも。

もしgccのコミッタの方がこれを見ておられましたら、変更点は書いていただけると嬉しいです……。