コグノスケ


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

link もっと前
2020年5月30日 >>> 2020年5月30日
link もっと後

2020年5月30日

GCCを調べる - その13-2 - オフセット付きアドレス全部禁止

目次: GCC

前回(2020年5月29日の日記参照)メモリというかオフセット付きアドレスのconstraintをチェックしていそうな箇所を見つけました。

ベクトル命令の場合は、オフセット付きアドレスを拒否してほしいです。試しにwin = true; の部分をwin = false; に変更するとどんな動きをするでしょうか?

常に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に関係する部分です。

  • this_alternative_winがfalse
  • curr_alt_win[nop] がfalse(nop = 0のとき)
  • goal_alt_win[nop] がfalse(nop = 0のとき)

関数process_alt_operands() の返り値はbool型で、falseは他のオペランドの選択肢はない、trueは他の選択肢があるという意味だそうです。今回はtrueを返します。だから何?と思いますが、あとでこの値がちょっとだけ出ます。

関数の最後に設定するgoal_alt_winというグローバル変数が、process_alt_operands() 関数の「外側」の制御に影響を及ぼします。これはひどい。良い子の皆さんはこういうコードを書いてはいけません。

今回注目しているinsnのオペランドは2つあり、nop = 0がメモリのオペランド、nop = 1がレジスタのオペランドです。デバッガで追いかけるとthis_ なんちゃらの値はそれぞれ下記のようになっていました。

各オペランドのwinの値
---------- 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配列(グローバル変数)に代入されます。

処理の骨組みだけ示すと下記のようになります。

goal_alt_XX[op] が決まる仕組み

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_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を変更したことによる影響は、また次回。

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

コメント一覧

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



link もっと前
2020年5月30日 >>> 2020年5月30日
link もっと後

管理用メニュー

link 記事を新規作成

<2020>
<<<05>>>
-----12
3456789
10111213141516
17181920212223
24252627282930
31------

最近のコメント5件

  • link 21年3月13日
    すずきさん (03/05 15:13)
    「あー、このプログラムがまずいんですね。ご...」
  • link 21年3月13日
    emkさん (03/05 12:44)
    「キャストでvolatileを外してアクセ...」
  • link 24年1月24日
    すずきさん (02/19 18:37)
    「簡単にできる方法はPowerShellの...」
  • link 24年1月24日
    KKKさん (02/19 02:30)
    「追伸です。\nネットで調べたらマイクロソ...」
  • link 24年1月24日
    KKKさん (02/19 02:25)
    「私もエラーで困ってます\n手動での回復パ...」

最近の記事3件

  • link 24年3月25日
    すずき (03/26 03:20)
    「[Might and Magic Book One TASのその後] 目次: Might and Magicファミコン版以前(...」
  • link 21年10月4日
    すずき (03/26 03:14)
    「[Might and Magicファミコン版 - まとめリンク] 目次: Might and Magicファミコン版TASに挑...」
  • link 24年3月19日
    すずき (03/20 02:52)
    「[モジュラージャックの規格] 古くは電話線で、今だとEthernetで良く見かけるモジュラージャックというコネクタとレセプタク...」
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

最終更新: 03/26 03:20