目次: GCC
前回(2020年5月30日の日記参照)見たとおり、関数process_alt_operands() がグローバル変数goal_alt_winを変更しました。
フラグの変更が呼び出し元のcurr_insn_transform() にどう影響するか調べます。RTLが変化するところに、適宜コメントを入れました。
// gcc/lra-constraints.c
static bool
curr_insn_transform (bool check_only_p)
{
...
if (process_alt_operands (reused_alternative_num))
alt_p = true;
...
n_outputs = 0;
outputs[0] = -1;
for (i = 0; i < n_operands; i++)
{
int regno;
bool optional_p = false;
rtx old, new_reg;
rtx op = *curr_id->operand_loc[i];
//★★goal_alt_win = {false, true, }
if (goal_alt_win[i]) //★★i = 0メモリオペランドのときは成立しない
{
...
}
//★★goal_alt_matches = {-1, -1, }
/* Operands that match previous ones have already been handled. */
if (goal_alt_matches[i] >= 0) //★★成立しない
continue;
//★★goal_alt_matched[i] = {-1, -47, ...}
//★★goal_alt_offmemok = {true, false, }
/* We should not have an operand with a non-offsettable address
appearing where an offsettable address will do. It also may
be a case when the address should be special in other words
not a general one (e.g. it needs no index reg). */
if (goal_alt_matched[i][0] == -1 && goal_alt_offmemok[i] && MEM_P (op)) //★★成立する
{
enum reg_class rclass;
rtx *loc = &XEXP (op, 0);
enum rtx_code code = GET_CODE (*loc);
push_to_sequence (before);
rclass = base_reg_class (GET_MODE (op), MEM_ADDR_SPACE (op),
MEM, SCRATCH);
if (GET_RTX_CLASS (code) == RTX_AUTOINC)
new_reg = emit_inc (rclass, *loc, *loc,
/* This value does not matter for MODIFY. */
GET_MODE_SIZE (GET_MODE (op)));
else if (get_reload_reg (OP_IN, Pmode, *loc, rclass, FALSE,
"offsetable address", &new_reg)) //★★オフセットの設定が2つのRTLに分割される
{
rtx addr = *loc;
enum rtx_code code = GET_CODE (addr);
if (code == AND && CONST_INT_P (XEXP (addr, 1)))
/* (and ... (const_int -X)) is used to align to X bytes. */
addr = XEXP (*loc, 0);
lra_emit_move (new_reg, addr); //★★ベースレジスタにオフセットを加算するRTLを作成
//★★こんなのが作成される
//(insn 22 0 0 (set (reg:SI 114)
// (plus:SI (reg/f:SI 108)
// (const_int 256 [0x100]))) 3 {addsi3}
// (nil))
if (addr != *loc)
emit_move_insn (new_reg, gen_rtx_AND (GET_MODE (new_reg), new_reg, XEXP (*loc, 1)));
}
before = get_insns ();
end_sequence ();
//★★*locとnew_regの値
//
//*loc = (plus:SI (reg/f:SI 108)
// (const_int 256 [0x100]))
//
//new_reg = (reg:SI 114)
//★★Before:
// ↓このRTL plusがregに置き換わる
//(insn 10 11 13 2 (set (mem/c:V64SI (plus:SI (reg/f:SI 108)
// (const_int 256 [0x100])) [1 v1+0 S256 A2048])
// (reg:V64SI 109 [ v1 ])) "b.c":8:2 134 {*movv64si_internal}
// (expr_list:REG_DEAD (reg:V64SI 109 [ v1 ])
// (nil)))
//
//★★After:
//
//(insn 10 11 13 2 (set (mem/c:V64SI (reg:SI 114) [1 v1+0 S256 A2048])
// (reg:V64SI 109 [ v1 ])) "b.c":8:2 134 {*movv64si_internal}
// (expr_list:REG_DEAD (reg:V64SI 109 [ v1 ])
// (nil)))
*loc = new_reg;
lra_update_dup (curr_id, i);
}
...
lra_process_new_insns (curr_insn, before, after, "Inserting insn reload"); //★★オフセットを事前計算するRTLが追加される
return change_p;
}
最後のlra_process_new_insns() はちょっとややこしくて、1つ目の引数(curr_insn)の前に2つ目の引数(before)のRTLを足し、後ろに3つ目の引数を(after)を足す関数です。図示したほうがわかりやすいですね。
関数呼び出し前後のRTLの中身を下記に示します。今回はafterはNULLなので、curr_insnの後ろには何も足されません。
(insn 21 7 11 2 (set (reg:SI 113)
(plus:SI (reg/f:SI 97 frame)
(const_int -376 [0xfffffffffffffe88]))) "b.c":8:2 3 {addsi3}
(nil))
(insn 11 21 10 2 (set (reg:V64SI 109 [ v1 ])
(asm_operands/v:V64SI ("vlw.v %0, %1") ("=&v") 0 [
(mem/c:SI (reg:SI 113) [1 b+40 S4 A64])
]
[
(asm_input:SI ("A") b.c:8)
]
[] b.c:8)) "b.c":8:2 -1
(nil))
★curr_insnは↓のRTLを指している
(insn 10 11 13 2 (set (mem/c:V64SI (reg:SI 114) [1 v1+0 S256 A2048]) ★*loc = new_reg; でオペランド変更済み
(reg:V64SI 109 [ v1 ])) "b.c":8:2 134 {*movv64si_internal}
(expr_list:REG_DEAD (reg:V64SI 109 [ v1 ])
(nil)))
(insn 13 10 12 2 (set (reg:V64SI 110 [ v2 ])
(asm_operands/v:V64SI ("vlw.v %0, %1") ("=&v") 0 [
(mem/c:SI (plus:SI (reg/f:SI 97 frame)
(const_int -336 [0xfffffffffffffeb0])) [1 b+80 S4 A64])
]
[
(asm_input:SI ("A") b.c:9)
]
[] b.c:9)) "b.c":9:2 -1
(nil))
...
(insn 21 7 11 2 (set (reg:SI 113)
(plus:SI (reg/f:SI 97 frame)
(const_int -376 [0xfffffffffffffe88]))) "b.c":8:2 3 {addsi3}
(nil))
(insn 11 21 22 2 (set (reg:V64SI 109 [ v1 ])
(asm_operands/v:V64SI ("vlw.v %0, %1") ("=&v") 0 [
(mem/c:SI (reg:SI 113) [1 b+40 S4 A64])
]
[
(asm_input:SI ("A") b.c:8)
]
[] b.c:8)) "b.c":8:2 -1
(nil))
★beforeは↓のRTLを指している
(insn 22 11 10 2 (set (reg:SI 114) ★このRTLが追加された(事前にアドレスを格納するレジスタにオフセットを足すため)
(plus:SI (reg/f:SI 108)
(const_int 256 [0x100]))) "b.c":8:2 3 {addsi3}
(nil))
★curr_insnは↓のRTLを指している
(insn 10 22 13 2 (set (mem/c:V64SI (reg:SI 114) [1 v1+0 S256 A2048])
(reg:V64SI 109 [ v1 ])) "b.c":8:2 134 {*movv64si_internal}
(expr_list:REG_DEAD (reg:V64SI 109 [ v1 ])
(nil)))
(insn 13 10 12 2 (set (reg:V64SI 110 [ v2 ])
(asm_operands/v:V64SI ("vlw.v %0, %1") ("=&v") 0 [
(mem/c:SI (plus:SI (reg/f:SI 97 frame)
(const_int -336 [0xfffffffffffffeb0])) [1 b+80 S4 A64])
]
[
(asm_input:SI ("A") b.c:9)
]
[] b.c:9)) "b.c":9:2 -1
(nil))
...
ベクトル命令のRTLの前にアドレスを計算するRTLが出力されました。うまくいってそうです。
話が長くなってきて忘れてしまいそうですが、やりたかったことは、ベクトル命令のオペランドにオフセット付きアドレスを指定しないことです。
先程まで見てきたように、常にwin = falseにすれば目的を達成しているように見えます。しかし残念ながら常にオフセット付きアドレスを拒絶することになり、スカラ命令にも影響が出てしまいます。変更前と変更後のアセンブラを比較します。
--- b_before.s 2020-05-28 21:17:24.607184754 +0900
+++ b_after.s 2020-05-28 21:14:31.375142095 +0900
@@ -21,8 +21,10 @@
addi s0,sp,1200
.cfi_def_cfa 8, 0
addi a5,s0,-16
#★★スカラ命令なのにアドレスオペランドのオフセット設定が分解されている(この分割は本来不要)
- sw a5,-1188(s0)
- lw a5,-1188(s0)
+ addi a4,s0,-1188
+ sw a5,0(a4)
+ addi a5,s0,-1188
+ lw a5,0(a5)
addi a5,a5,-1168
addi a5,a5,255
srli a5,a5,8
@@ -35,7 +37,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
ベクトル命令は狙い通りですが、スカラ命令までアドレスオペランドのオフセット設定が分解されてしまいました。この分割は本来不要です。
これをどう抑えるかはまた次回。
< | 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.)