コグノスケ


link 未来から過去へ表示(*)  link 過去から未来へ表示

link もっと前
2020年7月6日 >>> 2020年7月6日
link もっと後

2020年7月6日

GCCを調べる - その15-1 - 浮動小数点のロードストアになぜかベクトルレジスタが出現する

目次: GCC

以前(2020年3月27日の日記参照)ベクトルレジスタの定義を追加したとき、riscv_hard_regno_mode_ok() を変更しました。machine modeは無視して、ベクトルレジスタを指すレジスタ番号だったらとにかくtrueを返すようにしましたが、実はこの実装は正しくありません。

例えば以下のようなプログラムを書くと、おかしなことが起こります。

浮動小数点を60個使うプログラム

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が発生します。

reloadでコンパイルエラー
$ 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でした。

エラーが発生する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() の前半部分に似た作りとなっています。同じようなコードを色々なところに書くのはやめてほしいですね……。

エラーが発生するconstraints
(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の定義が由来です。

エラーが起きているときのconstraints

// 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では珍しくなくて、いつも解析が難しくて困っています。

振り出しに戻ってしまいました。続きは次回。

編集者:すずき(2023/09/24 11:51)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link もっと前
2020年7月6日 >>> 2020年7月6日
link もっと後

管理用メニュー

link 記事を新規作成

<2020>
<<<07>>>
---1234
567891011
12131415161718
19202122232425
262728293031-

最近のコメント5件

  • link 24年4月22日
    hdkさん (04/24 08:36)
    「うちのHHFZ4310は15年突破しまし...」
  • link 24年4月22日
    すずきさん (04/24 00:37)
    「ちゃんと数えてないですけど蛍光管が10年...」
  • link 24年4月22日
    hdkさん (04/23 20:52)
    「おお... うちのHHFZ4310より後...」
  • link 20年6月19日
    すずきさん (04/06 22:54)
    「ディレクトリを予め作成しておけば良いです...」
  • link 20年6月19日
    斎藤さん (04/06 16:25)
    「「Preferencesというメニューか...」

最近の記事3件

  • link 24年4月25日
    すずき (04/26 16:49)
    「[AVIFの変換] AVIFが読めないアプリケーションがたまにあるので、AVIF(AV1 Image File Format)...」
  • link 24年2月7日
    すずき (04/24 02:52)
    「[複数の音声ファイルのラウドネスを統一したい] PCやデジタル音楽プレーヤーで音楽を聞いていると、曲によって音量の大小が激しく...」
  • link 24年4月22日
    すずき (04/23 20:13)
    「[仕事部屋の照明が壊れた] いきなり仕事部屋のシーリングライトが消えました。蛍光管の寿命にしては去年(2022年10月19日の...」
link もっとみる

こんてんつ

open/close wiki
open/close Linux JM
open/close Java API

過去の日記

open/close 2002年
open/close 2003年
open/close 2004年
open/close 2005年
open/close 2006年
open/close 2007年
open/close 2008年
open/close 2009年
open/close 2010年
open/close 2011年
open/close 2012年
open/close 2013年
open/close 2014年
open/close 2015年
open/close 2016年
open/close 2017年
open/close 2018年
open/close 2019年
open/close 2020年
open/close 2021年
open/close 2022年
open/close 2023年
open/close 2024年
open/close 過去日記について

その他の情報

open/close アクセス統計
open/close サーバ一覧
open/close サイトの情報

合計:  counter total
本日:  counter today

link About www.katsuster.net
RDFファイル RSS 1.0

最終更新: 04/26 16:49