目次: GCC
前回(2020年7月7日の日記参照)はベクトルレジスタが選択されてしまう仕組みが何となくわかりました。
今回やりたかったことを復習しておくと「ベクトルの演算以外でベクトルレジスタを使わないでほしい」でした。つまりira_prohibited_class_mode_regs[cl][j] のうちベクトル以外のmachine modeかつベクトルレジスタに相当するビットを「セット」つまり割り当て禁止状態にすれば良いはずです。
配列の次元のうちclはレジスタのクラス(enum reg_class)で、jはmachine modeです。レジスタのクラスは以前(2020年3月28日の日記参照)ちょっとだけ使いました。幸いなことに、今回はレジスタのクラスは気にしなくて良いです、というかコードのif文の条件hard_regno_mode_ok(hard_regno, (machine_mode) j) を見るとわかるように、そもそもレジスタのクラスが渡されないので、ターゲット側(=RISC-V依存の実装部分)で何もできないです。
重要なのはmachine modeで、ベクトル以外のモード(浮動小数点など)だったらベクトルレジスタを割り当て禁止状態にすれば良いです。
// gcc/config/riscv/riscv.c
/* Implement TARGET_HARD_REGNO_MODE_OK. */
static bool
riscv_hard_regno_mode_ok (unsigned int regno, machine_mode mode)
{
unsigned int nregs = riscv_hard_regno_nregs (regno, mode);
if (GP_REG_P (regno))
{
if (!GP_REG_P (regno + nregs - 1))
return false;
}
else if (FP_REG_P (regno))
{
if (!FP_REG_P (regno + nregs - 1))
return false;
if (GET_MODE_CLASS (mode) != MODE_FLOAT
&& GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT)
return false;
/* Only use callee-saved registers if a potential callee is guaranteed
to spill the requisite width. */
if (GET_MODE_UNIT_SIZE (mode) > UNITS_PER_FP_REG
|| (!call_used_or_fixed_reg_p (regno)
&& GET_MODE_UNIT_SIZE (mode) > UNITS_PER_FP_ARG))
return false;
}
else if (VP_REG_P (regno)) //★★前回足した実装
{
return true;
}
else
return false;
...
ここでベクトル系のmachine modeを直接記述(mode == V64SImodeなど)しても間違いではないと思うのですが、単純にモードがたくさんあると鬱陶しいですし、該当するモードがあとで増えたときの修正が大変です。こういうときはmachine modeのクラスが便利です。クラスってなんだったかというと、machmode.defやriscv-modes.defに書いたあれです。
// gcc/machmode.def
...
/* Basic integer modes. We go up to TI in generic code (128 bits).
TImode is needed here because the some front ends now genericly
support __int128. If the front ends decide to generically support
larger types, then corresponding modes must be added here. The
name OI is reserved for a 256-bit type (needed by some back ends).
*/
//★★MODE_INTクラスになる
INT_MODE (QI, 1);
INT_MODE (HI, 2);
INT_MODE (SI, 4);
INT_MODE (DI, 8);
INT_MODE (TI, 16);
...
// gcc/config/riscv/riscv-modes.def
//★★MODE_FLOATクラスになる
FLOAT_MODE (TF, 16, ieee_quad_format);
//★★以前、追加した実装
//★★VECTOR_MODEの場合は少し特殊で、MODE_VECTOR + 最初の引数 クラスになる
//★★この例だとMODE_VECTOR_INTになる
VECTOR_MODE (INT, SI, 32);
VECTOR_MODE (INT, SI, 64);
クラスは上記の通り各所の *.defにて定義されますが、正直言ってどこにあるかわかりにくいし、クラスの名前も見えません。machine modeとクラスの対応を確認するだけなら、ビルド時に生成されるinsn-modes.cを見たほうが早いです。
// build_gcc/insn-modes.c
const unsigned char mode_class[NUM_MACHINE_MODES] =
{
MODE_RANDOM, /* VOID */
MODE_RANDOM, /* BLK */
MODE_CC, /* CC */
MODE_INT, /* BI */
MODE_INT, /* QI */
MODE_INT, /* HI */
MODE_INT, /* SI */
MODE_INT, /* DI */
MODE_INT, /* TI */
MODE_FRACT, /* QQ */
MODE_FRACT, /* HQ */
MODE_FRACT, /* SQ */
MODE_FRACT, /* DQ */
MODE_FRACT, /* TQ */
MODE_UFRACT, /* UQQ */
MODE_UFRACT, /* UHQ */
MODE_UFRACT, /* USQ */
MODE_UFRACT, /* UDQ */
MODE_UFRACT, /* UTQ */
MODE_ACCUM, /* HA */
MODE_ACCUM, /* SA */
MODE_ACCUM, /* DA */
MODE_ACCUM, /* TA */
MODE_UACCUM, /* UHA */
MODE_UACCUM, /* USA */
MODE_UACCUM, /* UDA */
MODE_UACCUM, /* UTA */
MODE_FLOAT, /* SF */
MODE_FLOAT, /* DF */
MODE_FLOAT, /* TF */
...
MODE_COMPLEX_FLOAT, /* SC */
MODE_COMPLEX_FLOAT, /* DC */
MODE_COMPLEX_FLOAT, /* TC */
MODE_VECTOR_INT, /* V32SI */
MODE_VECTOR_INT, /* V64SI */
};
ベクトル系のmachine modeを引っ掛けるにはMODE_VECTOR_INTを使えば良さそうです。今の実装では使っていませんがRISC-Vのベクトルは浮動小数点のベクトル(MODE_VECTOR_FLOAT)も扱えるはずなので、これも条件に追加しておきましょう。
// gcc/config/riscv/riscv.c
/* Implement TARGET_HARD_REGNO_MODE_OK. */
static bool
riscv_hard_regno_mode_ok (unsigned int regno, machine_mode mode)
{
unsigned int nregs = riscv_hard_regno_nregs (regno, mode);
if (GP_REG_P (regno))
{
if (!GP_REG_P (regno + nregs - 1))
return false;
}
else if (FP_REG_P (regno))
{
if (!FP_REG_P (regno + nregs - 1))
return false;
if (GET_MODE_CLASS (mode) != MODE_FLOAT
&& GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT)
return false;
/* Only use callee-saved registers if a potential callee is guaranteed
to spill the requisite width. */
if (GET_MODE_UNIT_SIZE (mode) > UNITS_PER_FP_REG
|| (!call_used_or_fixed_reg_p (regno)
&& GET_MODE_UNIT_SIZE (mode) > UNITS_PER_FP_ARG))
return false;
}
else if (VP_REG_P (regno)) //★★前回足した実装
{
if (GET_MODE_CLASS (mode) != MODE_VECTOR_INT
&& GET_MODE_CLASS (mode) != MODE_VECTOR_FLOAT) //★★今回足した実装
return false;
return true;
}
else
return false;
...
修正後のコンパイラは浮動小数点数を60個使うコードを正常にコンパイルできます。たったこの3行を説明するだけで、えらい時間を費やしました。GCCは魔界ですね。
お気づきの方もいるかと思いますが、実は1つ上のelse if節にほぼ全く同じ判定文が既にあります。何も考えずに上からパクってMODEの名前を書き換えれば、今回の問題は直るんですけど、それだとどうして直るのか全くわからないんですよ……。
< | 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.)