目次: GCC
GCC 8.3のバグを追った記録です。来月になったら絶対に忘れて、説明できなくなるので、できる限り詳細にメモしておきたいと思います。
再現は簡単で、下記のコードをコンパイルするとinternal compile errorになります。
float cargf(float _Complex z);
float atan2f(float y, float x);
void func(float _Complex cval, float val)
{
__builtin_cargf(cval);
__builtin_atan2f(val, 1.0f);
}
$ x86_64-unknown-elf-gcc -Wall -O2 -g a.c a.c: In function 'func': a.c:7:2: warning: statement with no effect [-Wunused-value] __builtin_cargf(cval); ^~~~~~~~~~~~~~~~~~~~~ during GIMPLE pass: forwprop a.c:9:1: internal compiler error: tree check: expected ssa_name, have var_decl in simplify_builtin_call, at tree-ssa-forwprop.c:1246 } ^ 0x1331604 tree_check_failed(tree_node const*, char const*, int, char const*, ...) ../../gcc/tree.c:9338 0x7ca7f2 tree_check(tree_node*, char const*, int, char const*, tree_code) ../../gcc/tree.h:3142 0x1135fb9 simplify_builtin_call ../../gcc/tree-ssa-forwprop.c:1246 0x113b55f execute ../../gcc/tree-ssa-forwprop.c:2527 Please submit a full bug report, with preprocessed source if appropriate. Please include the complete backtrace with any bug report. See <https://gcc.gnu.org/bugs/> for instructions.
再現にあたり重要なポイントは2点です。
なぜこの2点が重要か?については、追々説明します。この条件だけで原因が「ああ、あれか」と見当がつく人は超凄いです。GCCマスターか天才ですね。この記事は一切読む必要がないです。ちなみに私は解析に1週間近く掛かりました。辛かったです……。
このエラーはディストリビューションが配布するGCC 8.3のバイナリでは発生しません。x86_64向けのGCCでも発生させるには、下記に示すように特殊なビルド条件にする必要があります。
(※)GNUのビルドシステムが使うシステム名の表し方です。machine-vendor-operatingsystemの順で表します。
PC向けでは特殊なビルド条件ですが、ベアメタル向けのクロスコンパイラだと、割とこの条件に当てはまるものは多いです。
$ ../configure \ --target=x86_64-unknown-elf \ --prefix=/path/to/gcc/build/_install \ --disable-bootstrap \ --disable-libsanitizer \ --enable-checking=yes \ --enable-languages="c,c++" \ CFLAGS="-g -O0 -fno-inline" \ CXXFLAGS="-g -O0 -fno-inline" $ make -j8 all-gcc $ make install-gcc
ビルドコンフィグの一例を示しました。disable-bootstrapはデバッグ用ビルドオプション(CFLAGS, CXXFLAGS)を指定するために使っています(詳しくは 2021年3月30日の日記参照)。disable-libsanitizerは私の環境でビルドエラーになったので、仕方なくビルド対象から外しています。enable-languagesはFortranなどの今回使わない言語を削ってビルド時間を短縮するためです。
デバッグする対象はおなじみcc1です。なぜcc1なのかは以前書いた(2019年5月17日の日記参照)とおりです。
#### gdbでデバッグするなら $ gdb /path/to/build/_install/libexec/gcc/x86_64-unknown-elf/8.3.0/cc1 (gdb) run -quiet a.c -mtune=generic -march=x86-64 \ -g -O2 -Wall -std=c99 -o zzzzzzzz.s #### gdbserverを使うなら $ gdbserver --multi localhost:1234 \ -quiet a.c -mtune=generic -march=x86-64 \ -g -O2 -Wall -std=c99 -o zzzzzzzz.s
問題の再現と、GCCのコードを追う準備ができました。
目次: GCC
前回(2021年3月29日の日記参照)はconfigureオプションに --disable-bootstrapを指定してブートストラップモードを無効にしてビルドしました。ブートストラップモードが有効なときについても、メモしておこうと思います。
ブートストラップモードはホストのコンパイラでSTAGE1コンパイラをビルドし、STAGE1コンパイラを使ってSTAGE2とSTAGE3コンパイラをビルドして、ビルド結果に食い違いがないことを比較するモードです。ライブラリのビルドなどに使われる(最終的にインストールされる)のはSTAGE3のコンパイラのようです。3回GCCをビルドするので、ビルド時間は非ブートストラップモードの3倍近い時間がかかります。
ブートストラップモードのときはconfigureにCFLAGS, CXXFLAGSを指定する方法は使えません。代わりに GCCのマニュアルに記載がある通りmake BOOT_CFLAGS="-O0 -g -fno-inline" bootstrapとすれば良いです。
こちらがおそらく正規の手順で、configureにCFLAGS, CXXFLAGSを指定する方法は邪道なんでしょうけど、ブートストラップモードはビルドが遅くて辛いんだよなー……。
$ mkdir build $ cd build $ ../configure \ --prefix=`pwd`/_install \ --enable-languages=c,c++ $ make -j8 BOOT_CFLAGS="-O0 -g -fno-inline" bootstrap $ make install
ただしBOOT_CFLAGSの指定はSTAGE1には効きません。STAGE1だけは常に手堅い安定したオプションでビルドされます。
# gcc/Makefile.in
...
# Flags to pass to stage2 and later makes. They are defined
# here so that they can be overridden by Makefile fragments.
BOOT_CFLAGS= -g -O2
BOOT_LDFLAGS=
BOOT_ADAFLAGS= -gnatpg
...
# Defaults for all stages; some are overridden below.
STAGE_CFLAGS = $(BOOT_CFLAGS) ★★STAGE_CFLAGS = BOOT_CFLAGS★★
STAGE_TFLAGS = $(TFLAGS)
STAGE_CONFIGURE_FLAGS=@stage2_werror_flag@
# Defaults for stage 1; some are overridden below.
STAGE1_CFLAGS = $(STAGE_CFLAGS) ★★STAGE1_CFLAGS = STAGE_CFLAGS★★
STAGE1_CXXFLAGS = $(CXXFLAGS)
@if target-libstdc++-v3-bootstrap
# Override the above if we're bootstrapping C++.
STAGE1_CXXFLAGS = $(STAGE1_CFLAGS)
@endif target-libstdc++-v3-bootstrap
...
# By default, C and C++ are the only stage1 languages, because they are the
# only ones we require to build with the bootstrap compiler, and also the
# only ones useful for building stage2.
STAGE1_CFLAGS = @stage1_cflags@ ★★STAGE1_CFLAGSだけ無理やり上書きされる★★
STAGE1_CHECKING = @stage1_checking@
STAGE1_LANGUAGES = @stage1_languages@
当然ですがSTAGE2とSTAGE3には設定が反映されます。STAGE1コンパイラを手動で使って何かビルドする人はほぼいないと思うので、特に問題ないでしょう。
目次: GCC
去年あたりにGCCのデバッグ環境について書きました(2019年5月17日の日記参照)。GDBでGCCの動作を調べる際に、最適化が効いていると色々デバッグ時に不都合が生じます。例えば、
通常のアプリケーションだと気になりませんが、相手は魔界GCCです。勝手にブレークポイントがずれてもらってはたまったものではないです。こういうときはGCCのビルドオプションを変えて、最適化を全てOFFにしてしまうと見やすいです。
環境はDebian Testingです。GCCは8.3を使っています。
$ mkdir build $ cd build $ ../configure \ --prefix=`pwd`/_install \ --enable-languages=c,c++ \ --disable-libsanitizer \ --disable-bootstrap \ CFLAGS="-O0 -g -fno-inline" \ CXXFLAGS="-O0 -g -fno-inline" $ make -j8 $ make install
私はCとC++ だけ使えれば良いので、--enable-languages=c,c++ を指定して、ついでにビルド時間短縮しています。C以外の言語(Fortranなど)に用事がある場合は、適宜足してください。Debian TestingでGCC 8.3をビルドするとなんでかlibsanitizerがビルドエラーになった(深追いしてません)ので、--disable-libsanitizerを付けて回避しました。環境によっては要らないかも?
また、ブートストラップモードだと、ビルドに時間がかかりすぎるので --disable-bootstrapで無効にしています。ビルドオプションは "-O0 -g -fno-inline" 最適化なし、デバッグ情報あり、インライン展開なし、です。
インストール先はどこでも良いですが、インストールするディレクトリは、build下の _installディレクトリにしています。buildディレクトリと一緒に消せて、間違って古いバイナリを使う心配がほぼないため、最近お気に入りのインストール先です。
オプション -O2 -gでビルドしたバイナリを使って、GDBでインライン関数にブレークポイントを設定すると、こんなふうになります。
/* Set the implicit flag for a builtin function. */
static inline void
set_builtin_decl_implicit_p (enum built_in_function fncode, bool implicit_p)
{
size_t uns_fncode = (size_t)fncode;
gcc_checking_assert (BUILTIN_VALID_P (fncode)
&& builtin_info[uns_fncode].decl != NULL_TREE);
builtin_info[uns_fncode].implicit_p = implicit_p; //★ここにブレークポイントを設定★
}
$ gdb /path/to/gcc/build/_install/libexec/gcc/x86_64-pc-linux-gnu/8.3.0/cc1 (gdb) b tree.h:5245 Breakpoint 1 at 0x7cc7c3: tree.h:5245. (2 locations) (gdb) r -quiet -imultiarch x86_64-linux-gnu a.c -dumpbase a.c -mtune=generic \ -march=x86-64 -auxbase a -g -O2 -Wall -std=c99 -o zzzzzzzz.s Breakpoint 1, set_builtin_decl_implicit_p (implicit_p=true, fncode=12304) at ../../gcc/tree.h:5245 5245 builtin_info[uns_fncode].implicit_p = implicit_p; (gdb) p uns_fncode $1 = <optimized out>
一応ブレークはしますが、表示がおかしいです。引数の順序が逆ですし、fncodeの値もおかしい(16のはず)です。ローカル変数は最適化によって消されてprint不可能です。
#0 set_builtin_decl_implicit_p (implicit_p=true, fncode=12304) at ../../gcc/tree.h:5245 #1 gimplify_addr_expr (expr_p=expr_p@entry=0x7ffff76682e0, pre_p=pre_p@entry=0x7fffffffd600, post_p=post_p@entry=0x7fffffffd190) at ../../gcc/gimplify.c:6051 #2 0x000000000084301d in gimplify_expr (expr_p=0x7ffff76682e0, pre_p=<optimized out>, post_p=<optimized out>, gimple_test_f=<optimized out>, fallback=<optimized out>) at ../../gcc/gimplify.c:11581 #3 0x0000000000846a55 in gimplify_call_expr (expr_p=0x7ffff77eaee0, pre_p=0x7fffffffd600, want_value=<optimized out>) at ../../gcc/gimplify.c:3308 #4 0x00000000008436d6 in gimplify_expr (expr_p=0x7ffff77eaee0, pre_p=<optimized out>, post_p=<optimized out>, gimple_test_f=<optimized out>, fallback=<optimized out>) at ../../gcc/gimplify.c:11506 #5 0x0000000000843c0e in gimplify_stmt (seq_p=<optimized out>, stmt_p=<optimized out>) at ../../gcc/gimplify.c:6690 #6 gimplify_statement_list (pre_p=<optimized out>, expr_p=0x7ffff743ddd0) at ../../gcc/gimplify.c:1764 #7 gimplify_expr (expr_p=0x7ffff743ddd0, pre_p=<optimized out>, post_p=<optimized out>, gimple_test_f=<optimized out>, fallback=<optimized out>) at ../../gcc/gimplify.c:11963 #8 0x0000000000848f42 in gimplify_stmt (seq_p=0x7fffffffd600, stmt_p=0x7ffff743ddd0) at ../../gcc/gimplify.c:6690 #9 gimplify_bind_expr (expr_p=expr_p@entry=0x7ffff744b1c0, pre_p=pre_p@entry=0x7fffffffd7e8) at ../../gcc/gimplify.c:1331 #10 0x000000000084344b in gimplify_expr (expr_p=0x7ffff744b1c0, pre_p=<optimized out>, post_p=<optimized out>, gimple_test_f=<optimized out>, fallback=<optimized out>) at ../../gcc/gimplify.c:11735 #11 0x0000000000847508 in gimplify_stmt (seq_p=0x7fffffffd7e8, stmt_p=0x7ffff744b1c0) at ../../gcc/gimplify.c:6690 #12 gimplify_body (fndecl=0x7ffff744b100, do_parms=<optimized out>) at ../../gcc/gimplify.c:12735 #13 0x00000000008478e6 in gimplify_function_tree (fndecl=fndecl@entry=0x7ffff744b100) at ../../gcc/gimplify.c:12900 #14 0x00000000006f6ab0 in cgraph_node::analyze (this=0x7ffff74472e0) at ../../gcc/cgraphunit.c:670 #15 0x00000000006f8e68 in analyze_functions (first_time=<optimized out>) at ../../gcc/cgraphunit.c:1131 #16 0x00000000006f99c3 in symbol_table::finalize_compilation_unit (this=0x7ffff7658100) at ../../gcc/cgraphunit.c:2691 #17 0x0000000000a689fb in compile_file () at ../../gcc/toplev.c:480 #18 0x00000000005bbe3d in do_compile () at ../../gcc/toplev.c:2132 #19 toplev::main (this=this@entry=0x7fffffffda9e, argc=<optimized out>, argc@entry=17, argv=<optimized out>, argv@entry=0x7fffffffdba8) at ../../gcc/toplev.c:2267 #20 0x00000000005be0cf in main (argc=17, argv=0x7fffffffdba8) at ../../gcc/main.c:39
このケースだとバックトレースに抜けはなさそうですが、表示される引数にoptimized outが多く、何が渡されたのかわかりません。
ビルドオプション -O0 -g -fno-inlineでビルドして、GDBでインライン関数にブレークを設定します。
$ gdb /path/to/gcc/build/_install/libexec/gcc/x86_64-pc-linux-gnu/8.3.0/cc1 (gdb) b tree.h:5245 Breakpoint 1 at 0x7cc7c3: tree.h:5245. (2 locations) (gdb) r -quiet -imultiarch x86_64-linux-gnu a.c -dumpbase a.c -mtune=generic \ -march=x86-64 -auxbase a -g -O2 -Wall -std=c99 -o zzzzzzzz.s Breakpoint 1, set_builtin_decl_implicit_p (fncode=BUILT_IN_ATAN2F, implicit_p=true) at ../../gcc/tree.h:5245 5245 builtin_info[uns_fncode].implicit_p = implicit_p; (gdb) p uns_fncode $1 = 16
引数のenumも名前で出ていますし、ローカル変数も表示できます。
#0 set_builtin_decl_implicit_p (fncode=BUILT_IN_ATAN2F, implicit_p=true) at ../../gcc/tree.h:5245 #1 0x0000000000b55843 in gimplify_addr_expr (expr_p=0x7ffff76682e0, pre_p=0x7fffffffd3f0, post_p=0x7fffffffcc08) at ../../gcc/gimplify.c:6051 #2 0x0000000000b636a5 in gimplify_expr (expr_p=0x7ffff76682e0, pre_p=0x7fffffffd3f0, post_p=0x7fffffffcc08, gimple_test_f=0xb16def <is_gimple_call_addr(tree_node*)>, fallback=1) at ../../gcc/gimplify.c:11581 #3 0x0000000000b4f52c in gimplify_call_expr (expr_p=0x7ffff77eaee0, pre_p=0x7fffffffd3f0, want_value=false) at ../../gcc/gimplify.c:3308 #4 0x0000000000b6336e in gimplify_expr (expr_p=0x7ffff77eaee0, pre_p=0x7fffffffd3f0, post_p=0x7fffffffcf58, gimple_test_f=0xb5411f <is_gimple_stmt(tree)>, fallback=0) at ../../gcc/gimplify.c:11506 #5 0x0000000000b571dd in gimplify_stmt (stmt_p=0x7ffff77eaee0, seq_p=0x7fffffffd3f0) at ../../gcc/gimplify.c:6690 #6 0x0000000000b4bcb9 in gimplify_statement_list (expr_p=0x7ffff743ddd0, pre_p=0x7fffffffd3f0) at ../../gcc/gimplify.c:1764 #7 0x0000000000b647a5 in gimplify_expr (expr_p=0x7ffff743ddd0, pre_p=0x7fffffffd3f0, post_p=0x7fffffffd208, gimple_test_f=0xb5411f <is_gimple_stmt(tree)>, fallback=0) at ../../gcc/gimplify.c:11963 #8 0x0000000000b571dd in gimplify_stmt (stmt_p=0x7ffff743ddd0, seq_p=0x7fffffffd3f0) at ../../gcc/gimplify.c:6690 #9 0x0000000000b4ad3a in gimplify_bind_expr (expr_p=0x7ffff744b1c0, pre_p=0x7fffffffd708) at ../../gcc/gimplify.c:1331 #10 0x0000000000b63d56 in gimplify_expr (expr_p=0x7ffff744b1c0, pre_p=0x7fffffffd708, post_p=0x7fffffffd558, gimple_test_f=0xb5411f <is_gimple_stmt(tree)>, fallback=0) at ../../gcc/gimplify.c:11735 #11 0x0000000000b571dd in gimplify_stmt (stmt_p=0x7ffff744b1c0, seq_p=0x7fffffffd708) at ../../gcc/gimplify.c:6690 #12 0x0000000000b6610a in gimplify_body (fndecl=0x7ffff744b100, do_parms=true) at ../../gcc/gimplify.c:12735 #13 0x0000000000b66740 in gimplify_function_tree (fndecl=0x7ffff744b100) at ../../gcc/gimplify.c:12900 #14 0x00000000009798ad in cgraph_node::analyze (this=0x7ffff74472e0) at ../../gcc/cgraphunit.c:670 #15 0x000000000097aa60 in analyze_functions (first_time=true) at ../../gcc/cgraphunit.c:1131 #16 0x000000000097e71a in symbol_table::finalize_compilation_unit (this=0x7ffff7658100) at ../../gcc/cgraphunit.c:2691 #17 0x0000000000e79db0 in compile_file () at ../../gcc/toplev.c:480 #18 0x0000000000e7c68a in do_compile () at ../../gcc/toplev.c:2132 #19 0x0000000000e7c966 in toplev::main (this=0x7fffffffda7e, argc=18, argv=0x7fffffffdb88) at ../../gcc/toplev.c:2267 #20 0x00000000019e07e6 in main (argc=18, argv=0x7fffffffdb88) at ../../gcc/main.c:39
バックトレースの引数表示もうまくいっているようです。
3階で思い出したんですが、私は高所恐怖症らしく、背丈の2〜3倍くらいの高さから下を見ると、動悸がして手から変な汗が出ます。
崖、高い吊り橋など、誰でも怖いところは当然怖いんですけど、他の人が怖くないのに、私だけ怖がっている(=理解してもらえない)恐怖スポットとして、
(※)自分の背の半分以下の柵、高さがあっても頭が通るくらいの隙間が空いてる柵は怖いです。
私が怖いと感じるタイプの階段(パナソニックのサイトから引用)
何が怖いの?と聞かれますが、説明が難しいです。強いて言えば「一歩踏み出したら隙間に吸い込まれそうな恐怖感」でしょうか。隙間から落ちることはないと理解していても、それでも怖いから不思議です。
観光地の「景観スポット」はたいてい恐怖スポットです。さらに良くないことに、周りの人は私が冗談を言ってるように聞こえるようで、ふざけて段差側に押されたりします。本当に恐怖です。勘弁して……。
Facebookではいくつかコメントいただいて、興味深かったです。高いところが怖いというのは割と普遍的ですが、怖さの感じるポイントや、感じ方は人それぞれです。
閉所恐怖症なんてのも教えてもらいました。そういうのもあるのか。この年になるとどこかに閉じ込められるという経験をすることはほぼないので、自分が閉所恐怖症なのかどうかすらわからないですね。
メモ: 技術系の話はFacebookから転記しておくことにした。階段の板の名前の図を追加。
実家を出て20年が経ちました。振り返ると、9割「3階に住んで」います。自分の意志で借りた部屋に限れば、全て3階です。住所の遍歴はこんな感じ。
こう書くと、3階に恨みでもあるか、憑りついている地縛霊みたいですが、私は人間です。さておき真面目な話、1階の部屋と3階の部屋(2〜5階もほぼ同条件)を比べ下記の点が気に入っています。
こちらから不動産屋に「3階がいい」と1度も言ったことはないので、1度くらい4階や5階と巡り合っても不思議はなかったはずですが、結局ずっと3階でした。謎の縁ですね。
メモ: 技術系の話はFacebookから転記しておくことにした。
目次: OpenCL
一部OpenVXの話も含まれています。
< | 2021 | > | ||||
<< | < | 04 | > | >> | ||
日 | 月 | 火 | 水 | 木 | 金 | 土 |
- | - | - | - | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | - |
合計:
本日: