目次: GCC
以前(2020年5月24日の日記参照)、変数の代入操作をexpandで展開する際、代入を分割するか分割しないか、を決める条件の1つとして、optab_handler() という関数が出てきました。この関数の動作に関わるgenopinitというツールの動作を調べます。
前回(2020年6月3日の日記参照)は分岐条件に関わるenum optab_tagの生成について調べました。今回はもう少し複雑なpats[].scodeの生成について調べます。
突然pats[].scodeと言われても何だかわからないと思います。私もこんなひどい名前の変数、全く覚えられません。復習も兼ねてoptab_handler() を見直します。
// gcc/optabs-query.h
/* Return the insn used to implement mode MODE of OP, or CODE_FOR_nothing
if the target does not have such an insn. */
inline enum insn_code
optab_handler (optab op, machine_mode mode)
{
unsigned scode = (op << 16) | mode; //★★scodeの意味はここにある通り
gcc_assert (op > LAST_CONV_OPTAB);
return raw_optab_handler (scode); //★★これ
}
// build_gcc/insn-opinit.c
enum insn_code
raw_optab_handler (unsigned scode)
{
int i = lookup_handler (scode); //★★これ
return (i >= 0 && this_fn_optabs->pat_enable[i]
? pats[i].icode : CODE_FOR_nothing);
}
static int
lookup_handler (unsigned scode)
{
int l = 0, h = ARRAY_SIZE (pats), m;
while (h > l)
{
m = (h + l) / 2;
if (scode == pats[m].scode) //★★これ
return m;
else if (scode < pats[m].scode) //★★これ
h = m;
else
l = m + 1;
}
return -1;
}
//★★pats[] の定義
struct optab_pat {
unsigned scode;
enum insn_code icode;
};
static const struct optab_pat pats[NUM_OPTAB_PATTERNS] = {
{ 0x010405, CODE_FOR_extendqihi2 },
{ 0x010406, CODE_FOR_extendqisi2 },
{ 0x010407, CODE_FOR_extendqidi2 },
{ 0x010505, CODE_FOR_extendhihi2 },
...
{ 0x021c1b, CODE_FOR_truncdfsf2 }, //★★この変な数字(scode)0x021c1bは誰が作るのか?
...
コードからscodeの意味、上位16ビットがoptabで、下位16ビットがmachine mode、は理解できると思います。patsにはscodeが無数に並んでいますが、この数字を誰が作るかというとgenopinitです。
前に見たoptabsの定義は色々ありますが、必ず2つ以上の引数を取り、1番目がname(mov_optab, trunc_optabなど)、2番目がpatternとなっており、この2つは全ての定義に存在します。
// gcc/optabs.def
OPTAB_CL(trunc_optab, "trunc$b$a2", TRUNCATE, "trunc", gen_trunc_conv_libfunc)
'-- name `-- pattern
このうちnameはenum optab_tagの変数名として使っていました。その他にもcode_to_optab_[] という配列の定義にも使いますが、今はどうでもいいです。前後に文字が付くくらいで、基本的に名前がそのまま使われます。
一方2番目のpattern(例えば "mov$a", "trunc$b$a2" など)はちょっと変わっています。$aや $bという不思議な文字が入ります。
前回説明したとおりgenopinitの入力はgcc/common.md, gcc/config/riscv/riscv.md, build_gcc/insn-conditions.mdの3つの *.mdファイルです(mdはmachine descriptorの略)。Lispっぽい記法で、define_insnやdefine_expandを追加したファイルです。
基本的なgenopinitの動作は、
パターンマッチのコードはこんな感じです。
// gcc/gensupport.h
/* Information about an .md define_* rtx. */
class md_rtx_info {
public:
/* The rtx itself. */
rtx def;
/* The location of the first line of the rtx. */
file_location loc;
/* The unique number attached to the rtx. Currently all define_insns,
define_expands, define_splits, define_peepholes and define_peephole2s
share the same insn_code index space. */
int index;
};
// gcc/genopinit.c
int
main (int argc, const char **argv)
{
...
if (!init_rtx_reader_args_cb (argc, argv, handle_arg)) //★★ *.mdを解析
return (FATAL_EXIT_CODE);
...
/* Read the machine description. */
md_rtx_info info;
while (read_md_rtx (&info)) //★★RTXを1つずつ取り出す
switch (GET_CODE (info.def))
{
case DEFINE_INSN: //★★define_insn, define_expandだけ注目
case DEFINE_EXPAND:
gen_insn (&info); //★★これ
break;
static void
gen_insn (md_rtx_info *info)
{
optab_pattern p;
if (find_optab (&p, XSTR (info->def, 0))) //★★これ
patterns.safe_push (p);
}
// gcc/gensupport.c
bool
find_optab (optab_pattern *p, const char *name)
{
...
/* See if NAME matches one of the patterns we have for the optabs
we know about. */
for (unsigned int pindex = 0; pindex < ARRAY_SIZE (optabs); pindex++) //★★全てのpatternを試す
{
p->m1 = p->m2 = 0;
if (match_pattern (p, name, optabs[pindex].pattern)) //★★これ
{
p->name = name;
p->op = optabs[pindex].op;
p->sort_num = (p->op << 16) | (p->m2 << 8) | p->m1; //★★scodeを作る
return true;
}
// gcc/gensupport.h
/* Information about an instruction name that matches an optab pattern. */
struct optab_pattern
{
/* The name of the instruction. */
const char *name;
/* The matching optab. */
unsigned int op;
/* The optab modes. M2 is only significant for conversion optabs;
it is zero otherwise. */
unsigned int m1, m2;
/* An index that provides a lexicographical sort of (OP, M2, M1).
Used by genopinit.c. */
unsigned int sort_num;
};
申し訳ないですが *.mdファイルの解析関数init_rtx_reader_args_cb(), read_md_rtx() 辺りは調べる予定がありません。どなたか調べてくれたら嬉しいです。
パターンマッチはnameに対して行われ、全てのpatternとマッチするか試します。マッチしなければmatch_pattern() はfalseを返しますから、次のpatternを試します。マッチしたら、結果はoptab_pattern *pに格納され、match_patter() が作り出すp->m1, p->m2という謎の数からscodeが生成されます。
なぜgenopinitではsort_numという変数名にしたんでしょうね?scodeにすればもう少しわかりやすいのに。
パターンマッチのルールと、m1, m2が何者か?については、文章で説明できる気がしないので、例としてname = "truncdfsf2" を見ながら説明したいと思います。マッチするpatternは "trunc$b$a2" です。他のpatternはマッチしません。
// gcc/config/riscv/riscv.md
//★★nameの例
(define_insn "truncdfsf2" ★★名前
[(set (match_operand:SF 0 "register_operand" "=f")
(float_truncate:SF
(match_operand:DF 1 "register_operand" " f")))]
"TARGET_DOUBLE_FLOAT"
"fcvt.s.dt%0,%1"
[(set_attr "type" "fcvt")
(set_attr "mode" "SF")])
// gcc/optab.def
//★★ マッチするpatternの定義部分(2番目の引数)
OPTAB_CL(trunc_optab, "trunc$b$a2", TRUNCATE, "trunc", gen_trunc_conv_libfunc)
// gcc/gensupport.c
//★★
//pは結果格納用の変数
//name = "truncdfsf2"
//pat = "trunc$b$a2"
static bool
match_pattern (optab_pattern *p, const char *name, const char *pat)
{
...
★★match_pattern() がtrueを返した後、find_optab() がreturn trueで終了する直前でダンプ (gdb) p optabs[pindex] $13 = { name = 0x4574b5 "trunc_optab", pattern = 0x4574c1 "trunc$b$a2", base = 0x4574cc ""trunc"", suffix = 0x457478 "'\0'", libcall = 0x4574d4 "gen_trunc_conv_libfunc", op = 2, fcode = TRUNCATE, rcode = UNKNOWN, kind = 1 } (gdb) p/x *p $15 = { name = 0x4dd270, op = 0x2, m1 = 0x1b, m2 = 0x1c, sort_num = 0x21c1b } pは結果格納用のoptab_pattern *p
この定義のpatternは2番目の引数 "trunc$b$a2" です。全部繋がっていてわかりにくいですが、下記の4つの要素から構成されます。
このうち $aや $bはmachine modeの名前にマッチします。具体的には下記のようになります。
nameとpatが name = "truncdfsf2" pat = "trunc$b$a2" の場合、 $b -> df $a -> sf にマッチします。$a, $bのマッチを調べるときはmode_nameを先頭から検索(大文字小文字の違いは無視)します。 全モードの名前はmode_name[] という配列に入っています。 $bはmode_name[28] = "DF" と一致する。 $aはmode_name[27] = "SF" と一致する。 match_pattern() は一致したモードの番号をm1, m2に格納します。 つまりoptab_patternのm1, m2の意味はそれぞれ m1: $aがマッチしたモードのインデックス、今回だと27 = 0x1b (E_SFmode) m2: $bがマッチしたモードのインデックス、今回だと28 = 0x1c (E_DFmode) 結果scodeはこうなります。 p->sort_num = (p->op << 16) | (p->m2 << 8) | p->m1; = (2 << 16) | (28 << 8) | 27; = 0x21c1b // build_gcc/insn-opinit.c static const struct optab_pat pats[NUM_OPTAB_PATTERNS] = { ... { 0x021c1b, CODE_FOR_truncdfsf2 }, //★★この値が生成された
謎のpats[].scodeはこんな仕組みで生成されていたのでした。ややこしいですね。
< | 2020 | > | ||||
<< | < | 06 | > | >> | ||
日 | 月 | 火 | 水 | 木 | 金 | 土 |
- | 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 | - | - | - | - |
合計:
本日:
管理者: 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.)