目次: GCC
引き続き、ベクトル型を使用する際の下記の問題に取り組みます。
前回(2020年5月22日の日記、2020年5月23日の日記、2020年5月24日の日記参照)にてdefine_expandを追加し、Internal compile error: maximum number of generated reload insns per insn achieved (90) は出なくなりましたが、別のエラーが出ました。
b.c: In function '_start': b.c:25:1: error: unrecognizable insn: 25 | } | ^ (insn 10 11 0 2 (set (mem/c:V64SI (reg/f:SI 108) [1 v1+0 S256 A2048]) (reg:V64SI 109 [ v1 ])) "b.c":7:2 -1 (nil)) during RTL pass: vregs dump file: b.c.237r.vregs b.c:25:1: internal compiler error: in extract_insn, at recog.c:2294
エラーの起きている箇所はvregというパスで、RTLのパスでは2番目(expandの次)です。序盤のパスですし、変なRTLが後ろのパスに伝わって意味不明なエラー、というケースではなさそうです。素直にエラーが出ている箇所を見ます。
// gcc/recog.c
void
extract_insn (rtx_insn *insn)
{
int i;
int icode;
int noperands;
rtx body = PATTERN (insn);
...
switch (GET_CODE (body))
{
...
case SET:
if (GET_CODE (SET_SRC (body)) == ASM_OPERANDS)
goto asm_insn;
else
goto normal_insn; //★★ここにきて、ジャンプ
...
default:
normal_insn:
/* Ordinary insn: recognize it, get the operands via insn_extract
and get the constraints. */
icode = recog_memoized (insn);
if (icode < 0)
fatal_insn_not_found (insn); //★★ここでエラー
...
// gcc/recog.h
/* Try recognizing the instruction INSN,
and return the code number that results.
Remember the code so that repeated calls do not
need to spend the time for actual rerecognition.
This function is the normal interface to instruction recognition.
The automatically-generated function `recog' is normally called
through this one. */
static inline int
recog_memoized (rtx_insn *insn)
{
if (INSN_CODE (insn) < 0)
INSN_CODE (insn) = recog (PATTERN (insn), insn, 0);
return INSN_CODE (insn);
}
// ★★PATTERN(insn) はinsn->u.fld[3]->rt_rtxを返す。
PATTERN() の3という数値はinsnのRTL formatに基づいています。insnのRTLの引数は "uuBeiie" となっており、4つ目の引数eがinsnの実行したい処理を表しているようです。残念ながらPATTERN() という関数名から、そのような事情は掴めないですよね、普通。
|u |u|B|e ↓これ
(insn 10 11 0 2 (set (mem/c:V64SI (reg/f:SI 108) [1 v1+0 S256 A2048])
(reg:V64SI 109 [ v1 ])) "b.c":7:2 -1
(nil))
続きを追います。recog() という関数に入っていきます。recogから始まる関数群は自動生成されたコードです。自動生成コードは読みにくいですが、GCC本体よりロジックがシンプルで理解しやすいです。GCC本体は読みにくい&理解不能なので、辛くて泣けてきます。
// build_gcc/insn-recog.c
int
recog (rtx x1 ATTRIBUTE_UNUSED,
rtx_insn *insn ATTRIBUTE_UNUSED,
int *pnum_clobbers ATTRIBUTE_UNUSED)
{
rtx * const operands ATTRIBUTE_UNUSED = &recog_data.operand[0];
rtx x2, x3, x4, x5, x6, x7, x8, x9;
rtx x10, x11, x12, x13, x14, x15, x16, x17;
rtx x18, x19, x20, x21, x22, x23, x24, x25;
rtx x26, x27, x28;
int res ATTRIBUTE_UNUSED;
recog_data.insn = NULL;
switch (GET_CODE (x1))
{
case SET:
return recog_17 (x1, insn, pnum_clobbers); //★★これ
...
static int
recog_17 (rtx x1 ATTRIBUTE_UNUSED,
rtx_insn *insn ATTRIBUTE_UNUSED,
int *pnum_clobbers ATTRIBUTE_UNUSED)
{
rtx * const operands ATTRIBUTE_UNUSED = &recog_data.operand[0];
rtx x2, x3, x4, x5, x6, x7;
int res ATTRIBUTE_UNUSED;
x2 = XEXP (x1, 1);
switch (GET_CODE (x2))
{
...
case CONST_INT:
case CONST_WIDE_INT:
case CONST_POLY_INT:
case CONST_FIXED:
case CONST_DOUBLE:
case CONST_VECTOR:
case CONST:
case REG:
case SUBREG:
case MEM:
case LABEL_REF:
case SYMBOL_REF:
case HIGH:
return recog_7 (x1, insn, pnum_clobbers); //★★これ
...
static int
recog_7 (rtx x1 ATTRIBUTE_UNUSED,
rtx_insn *insn ATTRIBUTE_UNUSED,
int *pnum_clobbers ATTRIBUTE_UNUSED)
{
rtx * const operands ATTRIBUTE_UNUSED = &recog_data.operand[0];
rtx x2, x3, x4;
int res ATTRIBUTE_UNUSED;
x2 = XEXP (x1, 0);
switch (GET_CODE (x2))
{
case REG:
case SUBREG:
case MEM:
res = recog_2 (x1, insn, pnum_clobbers); //★★これ
if (res >= 0)
return res;
break;
...
static int
recog_2 (rtx x1 ATTRIBUTE_UNUSED,
rtx_insn *insn ATTRIBUTE_UNUSED,
int *pnum_clobbers ATTRIBUTE_UNUSED)
{
rtx * const operands ATTRIBUTE_UNUSED = &recog_data.operand[0];
rtx x2, x3, x4;
int res ATTRIBUTE_UNUSED;
x2 = XEXP (x1, 0);
operands[0] = x2;
x3 = XEXP (x1, 1);
operands[1] = x3;
switch (GET_MODE (operands[0]))
{
...
default:
break; //★★V64SImodeはいずれのcaseにも該当しないのでここにくる
}
...
if (pnum_clobbers == NULL //★★この条件に引っかかる
|| GET_CODE (x2) != MEM)
return -1; //★★ここにくる
...
なぜかrecog() 関数はデバッグ情報がおかしくて、gdbのnextコマンドが正常に動きません。非常にデバッグしづらいです。gdbで追うときはbuild_gcc/insn-recog.c内の #lineディレクティブを全て削除するとデバッグしやすいです。
エラーを解消するにはrecog_2のswitch-caseに変化を及ぼす方法を知る必要があります。しかしそんなものわかる訳ありません。仕方ないので周辺のコードを眺めます。
static int
recog_2 (rtx x1 ATTRIBUTE_UNUSED,
rtx_insn *insn ATTRIBUTE_UNUSED,
int *pnum_clobbers ATTRIBUTE_UNUSED)
{
...
switch (GET_MODE (operands[0]))
{
case E_DImode:
if (nonimmediate_operand (operands[0], E_DImode)
&& move_operand (operands[1], E_DImode))
{
if (
#line 1340 "./gcc/gcc/config/riscv/riscv.md" //★★この辺りにヒントがあるのでは??
(!TARGET_64BIT
&& (register_operand (operands[0], DImode)
|| reg_or_0_operand (operands[1], DImode))))
return 135; /* *movdi_32bit */
if (
#line 1350 "./gcc/gcc/config/riscv/riscv.md"
(TARGET_64BIT
&& (register_operand (operands[0], DImode)
|| reg_or_0_operand (operands[1], DImode))))
return 136; /* *movdi_64bit */
}
break;
ぐちゃぐちゃのif文の中に #lineが差し込まれています。コードの一部をriscv.mdから持ってきているようです。
;; gcc/config/riscv/riscv.md
(define_insn "*movdi_32bit"
[(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,m, *f,*f,*r,*f,*m")
(match_operand:DI 1 "move_operand" " r,i,m,r,*J*r,*m,*f,*f,*f"))]
★★↓このコードがrecog_2にコピーされている
"!TARGET_64BIT
&& (register_operand (operands[0], DImode)
|| reg_or_0_operand (operands[1], DImode))"
★★↑
{ return riscv_output_move (operands[0], operands[1]); }
[(set_attr "move_type" "move,const,load,store,mtc,fpload,mfc,fmove,fpstore")
(set_attr "mode" "DI")])
おそらくdefine_insnを定義すれば、recog_2() も変わるでしょう。近しいものをコピーして作ります。
;; gcc/config/riscv/riscv.md
(define_attr "vecmode" "unknown,V64SI"
(const_string "unknown"))
(define_insn "*movv64si_internal"
[(set (match_operand:V64SI 0 "nonimmediate_operand" "=v,v,m")
(match_operand:V64SI 1 "move_operand" " v,m,v"))] //★★RTL template
"(register_operand (operands[0], V64SImode)
|| reg_or_0_operand (operands[1], V64SImode))" //★★condition
{ return riscv_output_move (operands[0], operands[1]); } //★★output template
[(set_attr "move_type" "move,load,store")
(set_attr "vecmode" "V64SI")]) //★★insn attributes
とりあえずRTL template, condition, insn attributesに出現するmachine modeだけ変更しました。これが合っているのかわかりませんが、ダメなら後で直しましょう。
static int
recog_2 (rtx x1 ATTRIBUTE_UNUSED,
rtx_insn *insn ATTRIBUTE_UNUSED,
int *pnum_clobbers ATTRIBUTE_UNUSED)
{
...
switch (GET_MODE (operands[0]))
{
case E_V64SImode:
if (nonimmediate_operand (operands[0], E_V64SImode)
&& move_operand (operands[1], E_V64SImode)
&&
#line 1320 "./gcc/gcc/config/riscv/riscv.md"
((register_operand (operands[0], V64SImode)
|| reg_or_0_operand (operands[1], V64SImode))))
return 134; /* *movv64si_internal */ //★★ここにくるようになった
break;
再びrecog_2() を追いかけてみると、先程はなかったcaseが増えており、-1ではない値が返されるようになりました。
during RTL pass: final dump file: b.c.314r.final b.c: In function '_start': b.c:25:1: internal compiler error: in riscv_output_move, at config/riscv/riscv.c:2000 25 | } | ^ 0x1ae3d41 riscv_output_move(rtx_def*, rtx_def*)
今度こそうまく行くかと思いきや、また別のエラーが発生しました。道のりは長そうです。
< | 2020 | > | ||||
<< | < | 05 | > | >> | ||
日 | 月 | 火 | 水 | 木 | 金 | 土 |
- | - | - | - | - | 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.)