目次: GCC
レジスタ追加の変更の要はREG_CLASS_CONTENTSです。このマクロは32ビット整数の配列で、各レジスタ番号がどのレジスタの仲間(enum reg_class)に属するかを指定するテーブルです。こんな風に変更します。
#define REG_CLASS_CONTENTS \
{ \
- { 0x00000000, 0x00000000, 0x00000000 }, /* NO_REGS */ \
- { 0xf003fcc0, 0x00000000, 0x00000000 }, /* SIBCALL_REGS */ \
- { 0xffffffc0, 0x00000000, 0x00000000 }, /* JALR_REGS */ \
- { 0xffffffff, 0x00000000, 0x00000000 }, /* GR_REGS */ \
- { 0x00000000, 0xffffffff, 0x00000000 }, /* FP_REGS */ \
- { 0x00000000, 0x00000000, 0x00000003 }, /* FRAME_REGS */ \
- { 0xffffffff, 0xffffffff, 0x00000003 } /* ALL_REGS */ \
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, /* NO_REGS */ \
+ { 0xf003fcc0, 0x00000000, 0x00000000, 0x00000000 }, /* SIBCALL_REGS */ \
+ { 0xffffffc0, 0x00000000, 0x00000000, 0x00000000 }, /* JALR_REGS */ \
+ { 0xffffffff, 0x00000000, 0x00000000, 0x00000000 }, /* GR_REGS */ \
+ { 0x00000000, 0xffffffff, 0x00000000, 0x00000000 }, /* FP_REGS */ \
+ { 0x00000000, 0x00000000, 0xffffffff, 0x00000000 }, /* VP_REGS */ \
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000003 }, /* FRAME_REGS */ \
+ { 0xffffffff, 0xffffffff, 0xffffffff, 0x00000003 } /* ALL_REGS */ \
}
↑ここの3列目を足した
行方向は、ビットフィールドになっており非常にわかりにくいです。0要素目の0ビット目、0要素目の1ビット目、…という順に見ます。整数内では右から左(右が上位ビット)、要素間では左から右(左が0要素目)に見ます。
列方向はenum reg_classの整数値と一致しますのでさほど難しくはないでしょう。
行と列の意味 →→ 行方向、レジスタ番号(0〜FIRST_PSEUDO_REGISTER - 1まで) ↓ ↓ 列方向、enum reg_classを整数に直したもの 行方向の見方 例えば3行目(GR_REGS)がこうなっていたとすると、 { 0x0000000f, 0x0000000c, }, - 0要素目(レジスタ番号0〜31のクラス): 0x0000000f - 0, 1, 2, 3ビット目が1 = レジスタ番号0〜3はGR_REGS - 他のレジスタについては言及しない - 1要素目(レジスタ番号32〜63のクラス): 0x0000000c - 2, 3ビット目が1 = レジスタ番号34〜35はGR_REGS - 他のレジスタについては言及しない
ALL_REGSは全レジスタに1をセットしますので、ビットフィールドのルールがわかりやすいと思います。今回はレジスタが98本なので、3要素(32 * 3 = 96)+ 最後の要素は2ビット分だけ1にセットしています。
今回はVR_REGSという新たなレジスタクラスを足したいので、行が一つ増えます。レジスタの総数も増えるので、列方向も増えます。ちょうど良いことに新規に追加するレジスタは32本なので、整数1要素分を増やすだけです。
このマクロは直接使用されるわけではなく、別の配列にコピーされます。
// gcc/reginfo.c
static const unsigned int_reg_class_contents[N_REG_CLASSES][N_REG_INTS]
= REG_CLASS_CONTENTS;
...
/* Function called only once per target_globals to initialize the
target_hard_regs structure. Once this is done, various switches
may override. */
void
init_reg_sets (void)
{
int i, j;
/* First copy the register information from the initial int form into
the regsets. */
for (i = 0; i < N_REG_CLASSES; i++)
{
CLEAR_HARD_REG_SET (reg_class_contents[i]);
/* Note that we hard-code 32 here, not HOST_BITS_PER_INT. */
for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
if (int_reg_class_contents[i][j / 32] //★★ここで参照している
& ((unsigned) 1 << (j % 32)))
SET_HARD_REG_BIT (reg_class_contents[i], j);
}
// gcc/reginfo.c
struct target_hard_regs default_target_hard_regs;
// gcc/hard-reg-set.h
#if SWITCHABLE_TARGET //★★x86, ARM, MIPSなどはSWITCHABLE_TARGET = 1, RISC-Vは0のようだ
extern struct target_hard_regs *this_target_hard_regs;
#else
#define this_target_hard_regs (&default_target_hard_regs)
#endif
#define reg_class_contents \r (this_target_hard_regs->x_reg_class_contents)
難しそうに見えてやっていることはint_reg_class_contentsからdefault_target_hard_regs->x_reg_class_contentsへビットを移し替えているだけです。違いはint_reg_class_contentsが必ず32ビット幅であるのに対し、x_reg_class_contentsはアーキテクチャ最速の整数幅(x86_64なら64bitになるでしょう)である点です。
個人的には可読性を殺してまでやる意味あるの……?と疑問ですが、きっとGCC内で頻繁に呼ばれ速度的に重要なポイントだったのでしょう。
目次: GCC
前回(2020年3月6日の日記参照)はレジスタ制約(register_constraints)を追加しました。これだけでは何もできませんので、今回はベクトルレジスタの定義を追加してみます。長そうなので分割して書きます。
RISC-Vには汎用レジスタ(GP_REGS)と浮動小数点レジスタ(FP_REGS)が既に定義されているため、それらを参考にします。
変更するファイルはgcc/config/riscv/riscv.c, riscv.hです。FP_REGくらいで検索すると、下記の関数、マクロに名前が見当たりますので、真似して追加します。(詳細は パッチファイルもご覧ください、内容の正しさは全く保証できませんけど)
// gcc/config/riscv/riscv.c
riscv_regno_to_class[FIRST_PSEUDO_REGISTER] //32個レジスタを足す
riscv_hard_regno_nregs //どのマシンモードでもレジスタを1つだけ使う、よくわからん、また今度調べる
riscv_hard_regno_mode_ok //どのマシンモードでも許可する、よくわからん、また今度調べる
riscv_class_max_nregs //どのクラスでもレジスタを1つだけ使う、よくわからん、また今度調べる
// gcc/config/riscv/riscv.h
FIRST_PSEUDO_REGISTER //32個分ずれてもらう
FIXED_REGISTERS //32個足す、今回は0にした、固定された役目(スタックポインタなど)はない
CALL_USED_REGISTERS //32個足す、今回は0にした(関数呼び出しにより内容を破壊されない、s0 - s11と同じ扱い)
enum reg_class
#define REG_CLASS_NAMES //新たなレジスタクラスを足す
#define REG_CLASS_CONTENTS //後述する
#define REG_ALLOC_ORDER //レジスタの割当順、レジスタ番号で指定する
#define REGISTER_NAMES //レジスタの名前
#define ADDITIONAL_REGISTER_NAMES
初歩の初歩的な変更の割に必要な変更点はかなり多いです。どの変更が何に効くか完全にわかっていないので、合っているかわかりませんし、説明し難い変更もあります。後日、要調査ですね。
変更した中のriscv_regno_to_classをみるとFIRST_PSEUDO_REGISTERというマクロが出てきます。GCCはレジスタを2種類使い分けていて、レジスタ番号で区別できます。
正式な名前がわからない(※)ので、名付けは適当です。GCCはRTLのフェーズで命令の引数にレジスタを割り当てます。その際、いきなりメモリや物理レジスタを割り当てるのではなく、まず疑似レジスタを割り当てます。
疑似レジスタには数の制限がないので、最初の方の最適化パスで必要なだけ割り当てます。その後の最適化パスで物理レジスタや、メモリにうまく割り当てを考える二段構成になっています。
今回は32個の物理レジスタを足そうとしているので、FIRST_PSEUDO_REGISTERにも32個分だけズレてもらう必要があります。
今回の変更の要はREG_CLASS_CONTENTSです。このマクロの効き目についてはまた今度。
(※)GCCのヘンテコなマクロの意味を調べる際、GCC Internals(HTML版へのリンク)が大変参考になるのですが、この文書は用語の説明がイマイチ甘くて、正式な用語がわかりません。いつも困ります……。
目次: 車
引っ越してから1年もの間、車検証の住所変更をせずにほったらかしていました(本当は良くない)が、重い腰を上げ、大阪ナンバーにお別れを告げて、品川ナンバーになりました。
手続きに興味があったので、あえてディーラーにお任せせず自分でやってみました。面白かったですが相当面倒くさいです。もう自分でやることはないでしょうね。
今回は「変更登録」という手続きをしました。車検証の住所変更&ナンバープレートの変更です。他県から東京都に引っ越した人が該当します。手続きはざっくりいうと、
どうがんばって圧縮しても、平日を2回消費します。普通は警察、警察、陸運局、の3回消費すると思います。警察も陸運局も平日しか受け付けしていないので、勤め人にはなかなか辛いです。
興味のある人は居なさそうですが、メモ代わりに書いておきます。まずは車庫証明用の書類が必要です。
ここまでの書類は全部の警視庁のサイト(保管場所証明申請手続 - 警視庁)からゲットできます。
ナンバーの封印を付けてもらったら、そのまま車で運輸局からおさらばです。
やってみた感想は「RPGのクエストみたい」です。書類と書類を交換していくと、最後に車検証とナンバープレートが貰えます、みたいな感じですね。車のナンバー(と自動車税)管理の一環が垣間見えて、なかなか面白い社会科見学でした。
個人的にはナンバープレートの封印を破壊するのは、普段やらない体験で「え?自分で壊すの??」と緊張しました(関東運輸局だけセルフで、他地域ではやらないみたいです)。私の車は粗雑に扱っているせいなのか、フロント側のナンバーのネジが錆びて固着しており、あやうくネジをなめそうでした。次はもう外せないかもしれない。
昨今のコロナ騒ぎのせいか、いずれの窓口もガラッガラに空いていて快適でした。混んでいたら地獄だったと思います。
< | 2020 | > | ||||
<< | < | 03 | > | >> | ||
日 | 月 | 火 | 水 | 木 | 金 | 土 |
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 | - | - | - | - |
合計:
本日: