目次: GCC
前回(2020年5月31日の日記参照)見たとおり、メモリというかオフセット付きアドレスを全部禁止するのは明らかにやりすぎで、他の命令に悪影響を及ぼしていました。スカラ命令はオフセット付きアドレスを許可し、ベクトル命令だけオフセット付きアドレスを禁止したいところです。
オペランドを許可する、しないを判断するコードを改造すればできるでしょうか?コードを見てみます。
// gcc/common.md
(define_memory_constraint "TARGET_MEM_CONSTRAINT"
"Matches any valid memory."
(and (match_code "mem")
(match_test "memory_address_addr_space_p (GET_MODE (op), XEXP (op, 0),
MEM_ADDR_SPACE (op))")))
// gcc/recog.c
//★★各引数の値
//mode = E_V64SImode
//addr = (plus:SI (reg/f:SI 108)
// (const_int 256 [0x100]))
//as = 0
int
memory_address_addr_space_p (machine_mode mode ATTRIBUTE_UNUSED,
rtx addr, addr_space_t as)
{
#ifdef GO_IF_LEGITIMATE_ADDRESS
...
#else
return targetm.addr_space.legitimate_address_p (mode, addr, 0, as);
#endif
}
// gcc/targhook.c
//★★各引数の値
//mode = E_V64SImode
//mem = (plus:SI (reg/f:SI 108)
// (const_int 256 [0x100]))
//strict = 0
//as = 0
bool
default_addr_space_legitimate_address_p (machine_mode mode, rtx mem,
bool strict,
addr_space_t as ATTRIBUTE_UNUSED)
{
return targetm.legitimate_address_p (mode, mem, strict);
}
// gcc/config/riscv/riscv.c
#undef TARGET_LEGITIMATE_ADDRESS_P
#define TARGET_LEGITIMATE_ADDRESS_P riscv_legitimate_address_p
// gcc/config/riscv/riscv.c
//★★各引数の値
//mode = E_V64SImode
//mem = (plus:SI (reg/f:SI 108)
// (const_int 256 [0x100]))
//strict_p = 0
static bool
riscv_legitimate_address_p (machine_mode mode, rtx x, bool strict_p)
{
struct riscv_address_info addr;
return riscv_classify_address (&addr, x, mode, strict_p);
}
// gcc/config/riscv/riscv.c
//★★各引数の値
//x = (plus:SI (reg/f:SI 108)
// (const_int 256 [0x100]))
//mode = E_V64SImode
//strict_p = 0
static bool
riscv_classify_address (struct riscv_address_info *info, rtx x,
machine_mode mode, bool strict_p)
{
switch (GET_CODE (x))
{
...
case PLUS:
info->type = ADDRESS_REG;
info->reg = XEXP (x, 0);
info->offset = XEXP (x, 1);
//★★各変数の値
//info->reg = x->u.fld[0].rt_rtx = (reg/f:SI 108)
//info->offset = x->u.fld[1].rt_rtx = (const_int 256 [0x100])
return (riscv_valid_base_register_p (info->reg, mode, strict_p)
&& riscv_valid_offset_p (info->offset, mode));
...
}
}
関数memory_address_addr_space_p() のaddrを見ると、メモリアドレスを表すRTLしか渡されません。この情報だけではスカラ命令のオペランドか、ベクトル命令のオペランドか、判断するのは困難です。
ベクトル命令はmachine modeがV64SIであることを利用するとうまくいくかもしれません。関数riscv_classify_address() を変更し、mode == V64SIだったらPLUSなどREG以外を使ったRTLに対しfalseを返せば良さそうです。
// gcc/config/riscv/riscv.c
//★★各引数の値
//x = (plus:SI (reg/f:SI 108)
// (const_int 256 [0x100]))
//mode = E_V64SImode
//strict_p = 0
static bool
riscv_classify_address (struct riscv_address_info *info, rtx x,
machine_mode mode, bool strict_p)
{
switch (GET_CODE (x))
{
...
case PLUS:
if (mode == E_V64SImode) //★★machine modeがV64SIならオフセット付きアドレスは許可しない
return false;
info->type = ADDRESS_REG;
info->reg = XEXP (x, 0);
info->offset = XEXP (x, 1);
return (riscv_valid_base_register_p (info->reg, mode, strict_p)
&& riscv_valid_offset_p (info->offset, mode));
...
}
}
$ diff -u b_before.s b_mod.s
--- b_before.s 2020-05-28 21:17:24.607184754 +0900
+++ b_mod.s 2020-05-30 22:37:02.370663628 +0900
@@ -35,7 +35,8 @@
# 0 "" 2
#NO_APP
- vsw.v v0,256(a5)
+ addi a4,a5,256
+ vsw.v v0,0(a4)
.loc 1 9 2
addi a4,s0,-336
#APP
結果だけ見ると良さそうですが、将来的にオフセットアドレスが使えるベクトル命令が出てきたときに、判別不能になり困ります。その場しのぎ感が否めません。もっと良い方法はあるでしょうか?
実はもっと簡単な方法で対処できます。変更すべき箇所については、この取り組みの発端「constraint "m" をチェックしていそうな箇所から調査を開始した」ことを思い出していただければ想像が付くと思います。constraint "m" を使っている箇所はdefine_insnです。
;; gcc/config/riscv/riscv.md
(define_attr "vecmode" "unknown,V64SI"
(const_string "unknown"))
(define_insn "*movv64si_internal"
[(set (match_operand:V64SI 0 "nonimmediate_operand" "=v,v,m")
(match_operand:V64SI 1 "move_operand" " v,m,v"))] //★★constraint "m" を使っている場所
"(register_operand (operands[0], V64SImode)
|| reg_or_0_operand (operands[1], V64SImode))" return riscv_output_move (operands[0], operands[1]);
[(set_attr "move_type" "move,load,store")
(set_attr "vecmode" "V64SI")])
この "m" を変更して、オフセット付きアドレスオペランドだけを拒否したいですが、そんな都合の良いconstraintはあるでしょうか?実はRISC-Vには既にあります。constraint "A" です。
;; gcc/config/riscv/constraints.md
(define_memory_constraint "A"
"An address that is held in a general-purpose register."
(and (match_code "mem")
(match_test "GET_CODE(XEXP(op,0)) == REG")))
コードを見ると、constraint "A" が見ている条件は、種別がメモリであり、オペランドがREG(オフセットありだとPLUSなどになる)であることです。先程の改造と同じ発想ですね。mをAに変更します。
;; gcc/config/riscv/riscv.md
(define_insn "*movv64si_internal"
[(set (match_operand:V64SI 0 "nonimmediate_operand" "=v,v,A")
(match_operand:V64SI 1 "move_operand" " v,A,v"))] //★★constraint "A" に変更
...
$ diff -u b_before.s b_final.s
--- b_before.s 2020-05-28 21:17:24.607184754 +0900
+++ b_final.s 2020-05-28 21:20:20.219175573 +0900
@@ -35,7 +35,8 @@
# 0 "" 2
#NO_APP
- vsw.v v0,256(a5)
+ addi a4,a5,256
+ vsw.v v0,0(a4)
.loc 1 9 2
addi a4,s0,-336
#APP
出力結果のアセンブリも良い感じですし、ビルドの際にアセンブラも文句を言わなくなりました。
長きに渡りましたが、やっとベクトル型を使ったGCC拡張インラインアセンブラが書けるようになりました。良かった良かった。
< | 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.)