目次: GCC
前回(2020年5月29日の日記参照)メモリというかオフセット付きアドレスのconstraintをチェックしていそうな箇所を見つけました。
ベクトル命令の場合は、オフセット付きアドレスを拒否してほしいです。試しにwin = true; の部分をwin = false; に変更するとどんな動きをするでしょうか?
// gcc/lra-constraints.c
static bool
process_alt_operands (int only_alternative)
{
...
for (nalt = 0; nalt < n_alternatives; nalt++) //★★基本的には全ての選択肢を検討するのだが、losersが0だとbreakする(ループ終端(1000行後)で判定している)
{
...
for (nop = 0; nop < n_operands; nop++)
{
...
costly_p = false;
do
{
switch ((c = *p, len = CONSTRAINT_LEN (c, p)), c)
{
...
default:
cn = lookup_constraint (p);
switch (get_constraint_type (cn))
{
...
case CT_MEMORY:
if (MEM_P (op)
&& satisfies_memory_constraint_p (op, cn)) //★★今回はこちら
win = false; //★★常にfalseにする
...
}
while ((p += len), c);
scratch_p = (operand_reg[nop] != NULL_RTX
&& lra_former_scratch_p (REGNO (operand_reg[nop])));
/* Record which operands fit this alternative. */
if (win) //★★不成立、this_alternative_winはfalseのまま
{
this_alternative_win = true;
...
}
else if (did_match)
this_alternative_match_win = true;
else
{
int const_to_mem = 0;
bool no_regs_p;
reject += op_reject;
...
/* If the operand is dying, has a matching constraint,
and satisfies constraints of the matched operand
which failed to satisfy the own constraints, most probably
the reload for this operand will be gone. */
if (this_alternative_matches >= 0
&& !curr_alt_win[this_alternative_matches]
&& REG_P (op)
&& find_regno_note (curr_insn, REG_DEAD, REGNO (op))
&& (hard_regno[nop] >= 0
? in_hard_reg_set_p (this_alternative_set,
mode, hard_regno[nop])
: in_class_p (op, this_alternative, NULL))) //★★不成立
{
...
}
else
{
/* Strict_low_part requires to reload the register
not the sub-register. In this case we should
check that a final reload hard reg can hold the
value mode. */
if (curr_static_id->operand[nop].strict_low
&& REG_P (op)
&& hard_regno[nop] < 0
&& GET_CODE (*curr_id->operand_loc[nop]) == SUBREG
&& ira_class_hard_regs_num[this_alternative] > 0
&& (!targetm.hard_regno_mode_ok
(ira_class_hard_regs[this_alternative][0],
GET_MODE (*curr_id->operand_loc[nop])))) //★★不成立
{
...
}
losers++; //★★この変数が0以外だと、続けて他の選択肢も検討される
}
...
if (MEM_P (op) && offmemok)
addr_losers++;
else
...
curr_alt[nop] = this_alternative;
curr_alt_set[nop] = this_alternative_set;
curr_alt_win[nop] = this_alternative_win; //★★false
curr_alt_match_win[nop] = this_alternative_match_win;
curr_alt_offmemok[nop] = this_alternative_offmemok;
curr_alt_matches[nop] = this_alternative_matches;
if (this_alternative_matches >= 0
&& !did_match && !this_alternative_win)
curr_alt_win[this_alternative_matches] = false;
if (early_clobber_p && operand_reg[nop] != NULL_RTX)
early_clobbered_nops[early_clobbered_regs_num++] = nop;
}
...
ok_p = true; //★★関数の返り値
curr_alt_dont_inherit_ops_num = 0;
...
/* If this alternative can be made to work by reloading, and it
needs less reloading than the others checked so far, record
it as the chosen goal for reloading. */
if ((best_losers != 0 && losers == 0)
|| (((best_losers == 0 && losers == 0)
|| (best_losers != 0 && losers != 0))
&& (best_overall > overall
|| (best_overall == overall
/* If the cost of the reloads is the same,
prefer alternative which requires minimal
number of reload regs. */
&& (reload_nregs < best_reload_nregs
|| (reload_nregs == best_reload_nregs
&& (best_reload_sum < reload_sum
|| (best_reload_sum == reload_sum
&& nalt < goal_alt_number))))))))
{
for (nop = 0; nop < n_operands; nop++)
{
goal_alt_win[nop] = curr_alt_win[nop]; //★★false
goal_alt_match_win[nop] = curr_alt_match_win[nop];
goal_alt_matches[nop] = curr_alt_matches[nop];
goal_alt[nop] = curr_alt[nop];
goal_alt_offmemok[nop] = curr_alt_offmemok[nop];
}
goal_alt_dont_inherit_ops_num = curr_alt_dont_inherit_ops_num;
for (nop = 0; nop < curr_alt_dont_inherit_ops_num; nop++)
goal_alt_dont_inherit_ops[nop] = curr_alt_dont_inherit_ops[nop];
goal_alt_swapped = curr_swapped;
best_overall = overall;
best_losers = losers;
best_reload_nregs = reload_nregs;
best_reload_sum = reload_sum;
goal_alt_number = nalt;
}
if (losers == 0) //★★最初の方のfor (nalt = 0; nalt < n_alternatives; nalt++) をbreakするかどうか決めてる
/* Everything is satisfied. Do not process alternatives
anymore. */
break;
fail:
;
}
return ok_p;
}
長ったらしくてわかりにくいですが、今回注目したい制御条件はwinに関係する部分です。
関数process_alt_operands() の返り値はbool型で、falseは他のオペランドの選択肢はない、trueは他の選択肢があるという意味だそうです。今回はtrueを返します。だから何?と思いますが、あとでこの値がちょっとだけ出ます。
関数の最後に設定するgoal_alt_winというグローバル変数が、process_alt_operands() 関数の「外側」の制御に影響を及ぼします。これはひどい。良い子の皆さんはこういうコードを書いてはいけません。
今回注目しているinsnのオペランドは2つあり、nop = 0がメモリのオペランド、nop = 1がレジスタのオペランドです。デバッガで追いかけるとthis_ なんちゃらの値はそれぞれ下記のようになっていました。
---------- nop = 0 op = (mem/c:V64SI (plus:SI (reg/f:SI 108) (const_int 256 [0x100])) [1 v1+0 S256 A2048]) this_alternative = NO_REGS this_alternative_set = {elts = {0, 0}} this_alternative_win = false this_alternative_match_win = false this_alternative_offmemok = true this_alternative_matches = -1 ---------- nop = 1 op = (reg:V64SI 109 [ v1 ]) this_alternative = VP_REGS this_alternative_set = {elts = {0, 4294967295}} this_alternative_win = true this_alternative_match_win = false this_alternative_offmemok = false this_alternative_matches = -1
似たような名前の変数this_, curr_, goal_ が3つ出てきます。勝ち抜き方式にして一番良い選択肢を残しているようです。一番内側のforループでthis_XX(ローカル変数)の値を作り、良さそうな値ならcurr_alt_XX配列(static変数)に代入します。curr_alt_ はどんどん上書きされ、最後に残った値がgoal_alt_XX配列(グローバル変数)に代入されます。
処理の骨組みだけ示すと下記のようになります。
process_alt_operands
{
for (nalt = 0; nalt < n_alternatives; nalt++) //★★選択肢の数だけループ
{
for (nop = 0; nop < n_operands; nop++) //★★オペランドの数だけループ
{
{
//★★this_XXを決める戦い
}
//★★this_XXが決められないなら、次のオペランドを処理
//★★選ばれしthis_XXがcurr_alt_XX[op] に保存(後の選択肢のほうがさらに良ければ上書きされる)
}
}
//★★curr_alt_XX[op] をgoal_alt_XX[op] に保存
}
最終的にgoal_alt_XXの値がどうなるかというと、
goal_alt = {NO_REGS, VP_REGS, } goal_alt_win = {false, true, } goal_alt_match_win = {false, false, } goal_alt_offmemok = {true, false, } goal_alt_matches = {-1, -1, }
関数process_alt_operands() の最後でブレークしてgoal_alt_XXの値をダンプしました。コードを追いかけて求めるのはかなり困難です……。
グローバル変数goal_alt_winを変更したことによる影響は、また次回。
< | 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.18.
using GD 2.3.3(png support.)