目次: GCC
以前(2020年3月27日の日記参照)ベクトルレジスタの定義を追加したとき、riscv_hard_regno_mode_ok() を変更しました。machine modeは無視して、ベクトルレジスタを指すレジスタ番号だったらとにかくtrueを返すようにしましたが、実はこの実装は正しくありません。
例えば以下のようなプログラムを書くと、おかしなことが起こります。
void _start(void)
{
static volatile float gf[60];
float f00, f01, f02, f03, f04, f05, f06, f07, f08, f09;
float f10, f11, f12, f13, f14, f15, f16, f17, f18, f19;
float f20, f21, f22, f23, f24, f25, f26, f27, f28, f29;
float f30, f31, f32, f33, f34, f35, f36, f37, f38, f39;
float f40, f41, f42, f43, f44, f45, f46, f47, f48, f49;
float f50, f51, f52, f53, f54, f55, f56, f57, f58, f59;
__asm__ volatile("nop;\n");
f00 = gf[ 0]; f01 = gf[ 1]; f02 = gf[ 2]; f03 = gf[ 3]; f04 = gf[ 4];
f05 = gf[ 5]; f06 = gf[ 6]; f07 = gf[ 7]; f08 = gf[ 8]; f09 = gf[ 9];
f10 = gf[10]; f11 = gf[11]; f12 = gf[12]; f13 = gf[13]; f14 = gf[14];
f15 = gf[15]; f16 = gf[16]; f17 = gf[17]; f18 = gf[18]; f19 = gf[19];
f20 = gf[20]; f21 = gf[21]; f22 = gf[22]; f23 = gf[23]; f24 = gf[24];
f25 = gf[25]; f26 = gf[26]; f27 = gf[27]; f28 = gf[28]; f29 = gf[29];
f30 = gf[30]; f31 = gf[31]; f32 = gf[32]; f33 = gf[33]; f34 = gf[34];
f35 = gf[35]; f36 = gf[36]; f37 = gf[37]; f38 = gf[38]; f39 = gf[39];
f40 = gf[40]; f41 = gf[41]; f42 = gf[42]; f43 = gf[43]; f44 = gf[44];
f45 = gf[45]; f46 = gf[46]; f47 = gf[47]; f48 = gf[48]; f49 = gf[49];
f50 = gf[59]; f51 = gf[51]; f52 = gf[52]; f53 = gf[53]; f54 = gf[54];
f55 = gf[55]; f56 = gf[56]; f57 = gf[57]; f58 = gf[58]; f59 = gf[59];
__asm__ volatile("nop;\n");
gf[ 0] = f00; gf[ 1] = f01; gf[ 2] = f02; gf[ 3] = f03; gf[ 4] = f04;
gf[ 5] = f05; gf[ 6] = f06; gf[ 7] = f07; gf[ 8] = f08; gf[ 9] = f09;
gf[10] = f10; gf[11] = f11; gf[12] = f12; gf[13] = f13; gf[14] = f14;
gf[15] = f15; gf[16] = f16; gf[17] = f17; gf[18] = f18; gf[19] = f19;
gf[20] = f20; gf[21] = f21; gf[22] = f22; gf[23] = f23; gf[24] = f24;
gf[25] = f25; gf[26] = f26; gf[27] = f27; gf[28] = f28; gf[29] = f29;
gf[30] = f30; gf[31] = f31; gf[32] = f32; gf[33] = f33; gf[34] = f34;
gf[35] = f35; gf[36] = f36; gf[37] = f37; gf[38] = f38; gf[39] = f39;
gf[40] = f40; gf[41] = f41; gf[42] = f42; gf[43] = f43; gf[44] = f44;
gf[45] = f45; gf[46] = f46; gf[47] = f47; gf[48] = f48; gf[49] = f49;
gf[50] = f50; gf[51] = f51; gf[52] = f52; gf[53] = f53; gf[54] = f54;
gf[55] = f55; gf[56] = f56; gf[57] = f57; gf[58] = f58; gf[59] = f59;
__asm__ volatile("nop;\n");
}
最適化O1以上でビルドするとinternal compile errorが発生します。
$ riscv32-unknown-elf-gcc b.c -march=rv32imafcv -mabi=ilp32f -O3 -Wall -fno-builtin -fno-inline -nostdlib -g b.c: In function '_start': b.c:52:1: error: insn does not satisfy its constraints: 52 | } | ^ (insn 562 17 18 2 (set (reg/v:SF 65 v1 [orig:104 f00 ] [104]) (reg/v:SF 47 fa5 [orig:104 f00 ] [104])) "b.c":23:6 153 {*movsf_hardfloat} (nil)) during RTL pass: reload dump file: b.c.282r.reload b.c:52:1: internal compiler error: in extract_constrain_insn, at recog.c:2195 0x11b9e4d _fatal_insn(char const*, rtx_def const*, char const*, int, char const*) gcc/gcc/rtl-error.c:108 0x11b9ed1 _fatal_insn_not_found(rtx_def const*, char const*, int, char const*) gcc/gcc/rtl-error.c:118 0x1130298 extract_constrain_insn(rtx_insn*) gcc/gcc/recog.c:2195 0xeabdd8 check_rtl gcc/gcc/lra.c:2167 0xead5c0 lra(_IO_FILE*) gcc/gcc/lra.c:2604 0xe1a63b do_reload gcc/gcc/ira.c:5523 0xe1b078 execute gcc/gcc/ira.c:5709
エラーが発生している箇所はreloadで、エラーの原因となったRTLも出力されています。RTLのsetを見ると、宛先がreg/v:SF 65 v1になっています。浮動小数点の処理のはずなのに、どうしてベクトルレジスタが選択されているのでしょうか?
エラーを出力するのは関数check_rtl() です。lra() の最初あたりcheck_rtl(false) と、最後あたりcheck_rtl(true) の2回呼ばれます。エラーが発生しているのは、2回目の呼び出しです。
// gcc/lra.c
/* Function checks RTL for correctness. If FINAL_P is true, it is
done at the end of LRA and the check is more rigorous. */
static void
check_rtl (bool final_p)
{
basic_block bb;
rtx_insn *insn;
lra_assert (! final_p || reload_completed);
FOR_EACH_BB_FN (bb, cfun)
FOR_BB_INSNS (bb, insn)
if (NONDEBUG_INSN_P (insn)
&& GET_CODE (PATTERN (insn)) != USE
&& GET_CODE (PATTERN (insn)) != CLOBBER
&& GET_CODE (PATTERN (insn)) != ASM_INPUT)
{
if (final_p)
{
extract_constrain_insn (insn); //★★これ
continue;
}
// gcc/recog.c
/* Do uncached extract_insn, constrain_operands and complain about failures.
This should be used when extracting a pre-existing constrained instruction
if the caller wants to know which alternative was chosen. */
void
extract_constrain_insn (rtx_insn *insn)
{
extract_insn (insn); //★★INSN RTLからrecog_dataを作成する
if (!constrain_operands (reload_completed, get_enabled_alternatives (insn))) //★★ここでfalseが返る
fatal_insn_not_found (insn); //★★internal compile errorが出力される
}
おさらいですが、エラーが発生するときのinsnの先頭は下記のようなRTLでした。
(insn 562 17 18 2 (set (reg/v:SF 65 v1 [orig:104 f00 ] [104])
(reg/v:SF 47 fa5 [orig:104 f00 ] [104])) "b.c":23:6 145 {*movsf_hardfloat}
(nil))
関数constrain_operands() は何度も呼ばれるので、エラーが起きるRTLが来たときUID 562で止めます。INSN_UID(insn) == 562が来たときに止められるようにコードを少し改変し、ブレークポイントを仕掛けます。
もしくはINSN_UID(insn) はデバッガから参照するときはinsn->u2.insn_uidで見えますから、条件ブレークでも止められると思います。
// gcc/lra.c
/* Function checks RTL for correctness. If FINAL_P is true, it is
done at the end of LRA and the check is more rigorous. */
static void
check_rtl (bool final_p)
{
basic_block bb;
rtx_insn *insn;
lra_assert (! final_p || reload_completed);
FOR_EACH_BB_FN (bb, cfun)
FOR_BB_INSNS (bb, insn)
if (NONDEBUG_INSN_P (insn)
&& GET_CODE (PATTERN (insn)) != USE
&& GET_CODE (PATTERN (insn)) != CLOBBER
&& GET_CODE (PATTERN (insn)) != ASM_INPUT)
{
if (INSN_UID(insn) == 562) //★★ブレークポイントを仕掛けるために追加した部分
printf("check point!!\n"); //★★ブレークポイントを仕掛けるために追加した部分
if (final_p)
{
extract_constrain_insn (insn);
continue;
}
関数constrain_operands() を追ってみると、RTLが取るオペランド(今回は2つ取っている)に対応するconstraintsをチェックしています。recog_data.constraintsを見るとconstraintsがわかります。
コードは以前(2020年3月29日の日記参照)見たprocess_alt_operands() の前半部分に似た作りとなっています。同じようなコードを色々なところに書くのはやめてほしいですね……。
(gdb) p recog_data.constraints $6 = { 0x2d717f9 "=f,f,f,m,m,*f,*r,*r,*r,*m", 0x2d71813 "f,G,m,f,G,*r,*f,*G*r,*m,*r", ...
このconstraintsは降って湧いたものではなくて、下記の *movsf_hardfloatの定義が由来です。
// gcc/config/riscv/riscv.md
(define_insn "*movsf_hardfloat"
[(set (match_operand:SF 0 "nonimmediate_operand" "=f,f,f,m,m,*f,*r, *r,*r,*m")
(match_operand:SF 1 "move_operand" " f,G,m,f,G,*r,*f,*G*r,*m,*r"))]
...
浮動小数点の移動の定義ですから当たり前なんですけど、ベクトルレジスタを受け付けるconstraints 'v' は含まれません。なのにベクトルレジスタを渡そうとしているのでconstrain_operands() が怒っているわけです。
と、ここまでエラー出力に至るまでを追いましたが、残念なことにエラーの原因はreloadパスにはありません。エラーが出ている箇所と、エラーの原因が全く関係ない現象はGCCでは珍しくなくて、いつも解析が難しくて困っています。
振り出しに戻ってしまいました。続きは次回。
< | 2020 | > | ||||
<< | < | 07 | > | >> | ||
日 | 月 | 火 | 水 | 木 | 金 | 土 |
- | - | - | 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 | 31 | - |
合計:
本日:
管理者: Katsuhiro Suzuki(katsuhiro( a t )katsuster.net)
This is Simple Diary 1.0
Copyright(C) Katsuhiro Suzuki 2006-2023.
Powered by PHP 8.2.15.
using GD bundled (2.1.0 compatible)(png support.)