コグノスケ


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

link もっと前
2020年3月6日 >>> 2020年2月22日
link もっと後

2020年3月6日

GCCを調べる - その6 - ベクトルレジスタ用のregister constraintを足す

目次: GCC

GCCのインラインアセンブラでは __asm__("ins %0" : "=r"(aaa) : : ); のように、"=r" という不思議な文字列が出てきます。

これはconstraintsと呼ばれ(GCCのマニュアルへのリンク)、引数がレジスタ(r)なのかメモリアドレス(m)なのか、書き換えられるのか(=)などを説明しています。

どんな文字でも書けるわけではなく、変な文字(例えば 'v')を指定すると「impossible constraint in 'asm'」と怒られます。これは一体どこでチェックしているのでしょう?また、どうやって足せばよいでしょうか?

エラーを出している箇所

このエラーを出すのは、パスでいうと234r.vregsです。

ちなみにbuild_gccというディレクトリ名はGCCのビルドディレクトリのことです。GCCは自動生成コードをかなりの量出力するので、そちらも合わせて見る必要があります。

エラーメッセージを出している箇所

// gcc/function.c

static void
instantiate_virtual_regs_in_insn (rtx_insn *insn)
{
...
  if (asm_noperands (PATTERN (insn)) >= 0)
    {
      if (!check_asm_operands (PATTERN (insn)))  //★★このエラーチェックに引っかかっている
	{
	  error_for_asm (insn, "impossible constraint in %<asm%>");  //★★このエラーメッセージが出ている


// gcc/recog.c

int
check_asm_operands (rtx x)
{
...
  for (i = 0; i < noperands; i++)
    {
      const char *c = constraints[i];
      if (c[0] == '%')
	c++;
      if (! asm_operand_ok (operands[i], c, constraints))  //★★このエラーチェックに引っかかっている
	return 0;
    }

このチェックは何をしているのかというと、lookup_constraint() で文字(例えば 'v')をテーブルから探し、constraintの種類に変換します。未知の文字の場合はCONSTRAINT_UNKNOWNになります。

次にget_constraint_type() でどのカテゴリに属するか見ます。この関数はおかしくて、なぜかCONSTRAINT__UNKNOWNをCT_REGISTERと判定します。レジスタじゃないですよね?意味不明です。

asm文のconstraintを見ている箇所

// gcc/recog.c

int
asm_operand_ok (rtx op, const char *constraint, const char **constraints)
{
  int result = 0;
...
  while (*constraint)
    {
      enum constraint_num cn;
      char c = *constraint;
      int len;
      switch (c)
	{
...
	default:
	  cn = lookup_constraint (constraint);  //★★文字からconstraint_numに変換
						//    未知の文字の場合CONSTRAINT__UNKNOWNになる
	  switch (get_constraint_type (cn))
	    {
	    case CT_REGISTER:  //★★なぜかここに行く
	      if (!result
		  && reg_class_for_constraint (cn) != NO_REGS  //★★レジスタのconstraintがNO_REGSになるとNG
		  && GET_MODE (op) != BLKmode
		  && register_operand (op, VOIDmode))
		result = 1;
	      break;


// build_gcc/gcc/tm-preds.h

static inline enum constraint_num
lookup_constraint (const char *p)
{
  unsigned int index = lookup_constraint_array[(unsigned char) *p];  //★★この配列がカギ
  return (index == UCHAR_MAX
          ? lookup_constraint_1 (p)
          : (enum constraint_num) index);
}

enum constraint_num
{
  CONSTRAINT__UNKNOWN = 0,
  CONSTRAINT_r,
  CONSTRAINT_f,
...

static inline enum constraint_type
get_constraint_type (enum constraint_num c)
{
  if (c >= CONSTRAINT_p)
    {
      if (c >= CONSTRAINT_G)
        return CT_FIXED_FORM;
      return CT_ADDRESS;
    }
  if (c >= CONSTRAINT_m)
    return CT_MEMORY;
  if (c >= CONSTRAINT_I)
    return CT_CONST_INT;
  return CT_REGISTER;  //★★cがCONSTRAINT__UNKNOWNつまり0の場合、どれにも当てはまらずCT_REGISTERと判断される
}


// build_gcc/insn-preds.c

const unsigned char lookup_constraint_array[] = {
  CONSTRAINT__UNKNOWN,
  CONSTRAINT__UNKNOWN,
...
  MIN ((int) CONSTRAINT_r, (int) UCHAR_MAX),
  MIN ((int) CONSTRAINT_s, (int) UCHAR_MAX),
  CONSTRAINT__UNKNOWN,
  CONSTRAINT__UNKNOWN,
  CONSTRAINT__UNKNOWN,  //★★'v' は未定義、未知の文字の場合は全てCONSTRAINT__UNKNOWNになる
  CONSTRAINT__UNKNOWN,
...


// build_gcc/gcc/tm-preds.h

static inline enum reg_class
reg_class_for_constraint (enum constraint_num c)
{
  if (insn_extra_register_constraint (c))
    return reg_class_for_constraint_1 (c);  //★★ここで見つからないとNO_REGSが返されてNG
  return NO_REGS;
}


// build_gcc/gcc/insn-preds.c

enum reg_class
reg_class_for_constraint_1 (enum constraint_num c)
{
  switch (c)
    {
    case CONSTRAINT_r: return GENERAL_REGS;
    case CONSTRAINT_f: return TARGET_HARD_FLOAT ? FP_REGS : NO_REGS;
    case CONSTRAINT_j: return SIBCALL_REGS;
    case CONSTRAINT_l: return JALR_REGS;
    default: break;  //★★CONSTRAINT__UNKNOWNはどのcaseにも当てはまらないのでNO_REGSが返されてNG
    }
  return NO_REGS;
}

明らかにレジスタとは思えないCONSTRAINT__UNKNOWNが返ってきますが、なぜかCT_REGISTERだと思って処理し始め、最終的にエラーとして弾きます。結果オーライですがこれで良いんでしょうか。GCCのコードは訳がわかりません……。

register_constraintの足し方

ではvを正当なconstraintの一員にするにはどうしたら良いでしょうか?

第一歩としてはGCCのconfigディレクトリの下にある *.mdファイル(MarkdownではなくMachine Descriptorです)を編集します。

define_register_constraintを足す

;; config/riscv/riscv.md

(include "predicates.md")
(include "constraints.md")


;; config/riscv/constraints.md

(define_register_constraint "v" "TARGET_VECTOR ? VP_REGS : NO_REGS"
  "A vector register (if available).")

これを足すと(他にも色々やらないといけないんですけど)、先程のreg_class_for_constraint_1() に変化が生じます。

asm文のconstraintチェックが変わる

// build_gcc/gcc/insn-preds.c

enum reg_class
reg_class_for_constraint_1 (enum constraint_num c)
{
  switch (c)
    {
    case CONSTRAINT_r: return GENERAL_REGS;
    case CONSTRAINT_f: return TARGET_HARD_FLOAT ? FP_REGS : NO_REGS;
    case CONSTRAINT_j: return SIBCALL_REGS;
    case CONSTRAINT_v: return TARGET_VECTOR ? VP_REGS : NO_REGS;  //★★これが足されて通過するようになる
    case CONSTRAINT_l: return JALR_REGS;
    default: break;
    }
  return NO_REGS;
}

GCCはこの手のピタゴラスイッチの塊で、何を変えると望みの機能が実装できるか、全くわかりません。こんなもの良くメンテナンスできるなあ、と思います。

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

コメント一覧

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



2020年3月2日

GCCを調べる - その5 - RTL (Register Transfer Language) の定義

目次: GCC

全てのRTLの定義はgcc/rtl.defに定義されています。例えばinsnの定義は下記のとおりです。

insnの定義

/* An instruction that cannot jump.  */
DEF_RTL_EXPR(INSN, "insn", "uuBeiie", RTX_INSN)

何となくわかるけど、何だこれ?と思いますよね、私は思いました。それもそのはずで、実はこのファイルは単体では意味をなさず、Cファイルから何度も再利用されるからです。Cファイルからrtl.defをインクルードして使いますが、その際にDEF_RTL_EXPR() の意味が変わります。

比較的わかりやすい例を挙げるとしたら、gcc/rtl.cのrtx_formatの定義です。DEF_RTL_EXPR() を定義してから #include "rtl.def" を行う様子がわかるかと思います。

rtl.defの利用方法の一例(gcc/rtl.cより)

/* Indexed by rtx code, gives a sequence of operand-types for
   rtx's of that code.  The sequence is a C string in which
   each character describes one operand.  */

const char * const rtx_format[NUM_RTX_CODE] = {
  /* "*" undefined.
         can cause a warning message
     "0" field is unused (or used in a phase-dependent manner)
         prints nothing
     "i" an integer
         prints the integer
     "n" like "i", but prints entries from `note_insn_name'
     "w" an integer of width HOST_BITS_PER_WIDE_INT
         prints the integer
     "s" a pointer to a string
         prints the string
     "S" like "s", but optional:
	 the containing rtx may end before this operand
     "T" like "s", but treated specially by the RTL reader;
         only found in machine description patterns.
     "e" a pointer to an rtl expression
         prints the expression
     "E" a pointer to a vector that points to a number of rtl expressions
         prints a list of the rtl expressions
     "V" like "E", but optional:
	 the containing rtx may end before this operand
     "u" a pointer to another insn
         prints the uid of the insn.
     "b" is a pointer to a bitmap header.
     "B" is a basic block pointer.
     "t" is a tree pointer.
     "r" a register.
     "p" is a poly_uint16 offset.  */

#define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS)   FORMAT ,
#include "rtl.def"		/* rtl expressions are defined here */
#undef DEF_RTL_EXPR
};

このrtx_formatの場合は、第3引数(FORMAT)とカンマを残して、他は無視するようにDEF_RTL_EXPR() を定義しています。

コメントなどを無視して考えるとrtl.defをインクルードしたあとは、コードは下記のようになります。

include後のrtl.defのイメージ

const char * const rtx_format[NUM_RTX_CODE] = {
DEF_RTL_EXPR(UNKNOWN, "UnKnown", "*", RTX_EXTRA)

DEF_RTL_EXPR(VALUE, "value", "0", RTX_OBJ)

DEF_RTL_EXPR(DEBUG_EXPR, "debug_expr", "0", RTX_OBJ)

...
};

マクロDEF_RTL_EXPR() の展開後はこうなります。

マクロDEF_RTL_EXPR() 展開後のrtl.defのイメージ

const char * const rtx_format[NUM_RTX_CODE] = {
"*",

"0",

"0",

...
};

最終的にrtx_formatは文字列の配列になります。

私もrtl.defの用途全てを理解しているわけではなく、全てを説明することもできないので、またわかったら書くことにします。

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

コメント一覧

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



2020年2月22日

Zephyr - まとめリンク

目次: Zephyr

導入、ブート周り

ボード、ドライバなど

SMP対応編

浮動小数点数命令など

その他

目次: 一覧の一覧

編集者:すずき(2025/06/08 23:40)

コメント一覧

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



link もっと前
2020年3月6日 >>> 2020年2月22日
link もっと後

管理用メニュー

link 記事を新規作成

<2020>
<<<03>>>
1234567
891011121314
15161718192021
22232425262728
293031----

最近のコメント5件

  • link 25年10月6日
    すずきさん (10/10 13:14)
    「ですね。ccはもはやコンパイラというより...」
  • link 25年10月6日
    hdkさん (10/10 08:27)
    「ただのHello, worldでも試して...」
  • link 25年9月29日
    すずきさん (10/03 00:29)
    「なんと、メタパッケージ入れてなかったです...」
  • link 25年9月29日
    hdkさん (10/02 06:51)
    「あれ、dkmsは自動ビルドされるのが便利...」
  • link 20年8月24日
    すずきさん (08/30 22:06)
    「ですね、自分も今はPulseAudioを...」

最近の記事20件

  • link 25年10月15日
    すずき (10/19 16:54)
    「[PipeWireの音切れ問題 - サーバー側の設定確認と反映] 目次: ALSAPipeWireに変えてから音切れがなくなり...」
  • link 25年10月18日
    すずき (10/19 16:52)
    「[PipeWireの音切れ問題 - サーバー側PipeWireの設定] 目次: ALSAPipeWireに変えてから音切れがな...」
  • link 22年5月5日
    すずき (10/19 16:49)
    「[ALSA - まとめリンク] 目次: ALSAALSAの話。ALSAその1 - 使ってみようALSAその2 - カードとデバ...」
  • link 25年10月19日
    すずき (10/19 16:47)
    「[PipeWireの音切れ問題 - サーバー側pipewire-pulseの設定] 目次: ALSA未だにPipeWireの音...」
  • link 23年4月11日
    すずき (10/19 14:55)
    「[ブラウザー/メーラー - まとめリンク] 目次: ブラウザー/メーラー関係の深いまとめリンク。目次: Linuxブラウザー。...」
  • link 06年4月22日
    すずき (10/19 14:54)
    「[Seamonkey/Firefoxのメモリ使用量最小化] 目次: ブラウザー/メーラーGIGAZINE 2006年4月15日...」
  • link 25年10月17日
    すずき (10/19 14:53)
    「[Linux版Firefoxアドレスバーの黒線] 目次: ブラウザー/メーラーLinuxデスクトップマシンのFirefox(1...」
  • link 25年10月6日
    すずき (10/16 03:20)
    「[makeのデフォルトルールのリンクはLDを使わない] 目次: LinuxMakefileの達人には常識かもしれませんが、ma...」
  • link 25年10月13日
    すずき (10/16 03:19)
    「[PipeWireをPulseAudioサーバーの代わりにする、その2 - 音切れ多発] 目次: ALSA先日(2025年10...」
  • link 20年10月23日
    すずき (10/16 03:15)
    「[ARM - まとめリンク] 目次: ARMROCK64ブート周りの話のまとめ。ROCK64購入ROCK64とU-Bootのd...」
  • link 25年10月12日
    すずき (10/16 03:14)
    「[ROCK 5BのDebianをアップデート] 目次: ARMDebian StableがTrixieに変わったことをすっかり...」
  • link 20年8月29日
    すずき (10/16 02:36)
    「[ROCK64をRaspberry Pi 3のケースに無理やり格納] 目次: ARM先日KADHAS VIM2, VIM3を購...」
  • link 19年1月13日
    すずき (10/16 02:35)
    「[ROCK64とTinker BoardのU-Boot設定メモ] 目次: ARM完全に自分のためのメモですが、ROCK64とT...」
  • link 18年10月13日
    すずき (10/16 02:35)
    「[Welcome back ROCK64] 目次: ARMやっとROCK64を置けそうな場所を確保できて、Linuxカーネルで...」
  • link 18年9月3日
    すずき (10/16 02:35)
    「[ROCK64のカーネルだけ元に戻したい] 目次: ARMROCK64のカーネルを入れ替えていたら、動かないカーネルを書き込ん...」
  • link 18年8月20日
    すずき (10/16 02:35)
    「[ROCK64のU-Bootスクリプトを読む] 目次: ARM先日(2018年7月23日の日記参照)ROCK64のU-Boot...」
  • link 18年7月23日
    すずき (10/16 02:35)
    「[ROCK64とU-Bootのdistro boot] 目次: ARM昨日(2018年7月22日の日記参照)に引き続き、ROC...」
  • link 18年7月22日
    すずき (10/16 02:34)
    「[ROCK64購入] 目次: ARMRockchip RK3328搭載のシングルボードコンピュータ、ROCK64 4GB版を買...」
  • link 18年10月14日
    すずき (10/16 02:34)
    「[ROCK64のアナログオーディオ - その1 - I2Sとクロックレジスタ] 目次: ARMまた忘れてしまいそうなので、メモ...」
  • link 18年11月10日
    すずき (10/16 02:33)
    「[ROCK64のアナログオーディオ - その2 - I2SのDMA問題] 目次: ARM[ROCK64のI2Sが動かない] 先日(2...」
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 2025年
open/close 過去日記について

その他の情報

open/close アクセス統計
open/close サーバ一覧
open/close サイトの情報

合計:  counter total
本日:  counter today

link About www2.katsuster.net
RDFファイル RSS 1.0

最終更新: 10/19 16:54