目次: GCC
前回(2020年5月22日の日記参照)の続きです。エラーの原因となる代入操作RTLはどこから出てきているのでしょう。RTLを遡っていくとexpandから出力されていることがわかります。expandはRTLの最初のパスで、GIMPLEからRTLに変換するためのパス(パス番号236)です。最初から間違っているということですね。
;;★★asm文に相当する箇所 (insn 74 7 10 2 (set (reg:V64SI 109 [ v1 ]) (asm_operands/v:V64SI ("vlw.v %0, %1 ") ("=&v") 0 [ (mem/c:SI (plus:SI (reg/f:SI 99 virtual-stack-vars) (const_int -360 [0xfffffffffffffe98])) [1 b+40 S4 A64]) ] [ (asm_input:SI ("A") b.c:7) ] [] b.c:7)) "b.c":7:2 -1 (nil)) ;;★★自動的に出力される代入操作らしきRTL (insn 10 74 11 2 (set (mem/c:SI (reg/f:SI 108) [1 v1+0 S4 A2048]) (subreg:SI (reg:V64SI 109 [ v1 ]) 0)) "b.c":7:2 -1 (nil)) (insn 11 10 12 2 (set (mem/c:SI (plus:SI (reg/f:SI 108) (const_int 4 [0x4])) [1 v1+4 S4 A32]) (subreg:SI (reg:V64SI 109 [ v1 ]) 4)) "b.c":7:2 -1 (nil)) (insn 12 11 13 2 (set (mem/c:SI (plus:SI (reg/f:SI 108) (const_int 8 [0x8])) [1 v1+8 S4 A64]) (subreg:SI (reg:V64SI 109 [ v1 ]) 8)) "b.c":7:2 -1 (nil)) ...
ベクトル型V64SIのまま処理してほしいのに、4バイトごとに分割されて代入処理されています。この分割はどこで行われているか調べます。GCCはinsn RTLを出力するときは必ずemit_insn() という関数で出力することを利用します。
ブレークで実行が止まったら、バックトレースを取れば呼び出しまでの経路がわかります。
(gdb) bt #0 hoge () at ./gcc/gcc/emit-rtl.c:5103 #1 0x000000000097ebf9 in emit_insn (x=0x7ffff7aaa400) at ./gcc/gcc/emit-rtl.c:5118 #2 0x00000000009ff017 in emit_move_insn_1 (x=0x7ffff7bada80, y=0x7ffff7bada98) at ./gcc/gcc/expr.c:3754 #3 0x00000000009ffa28 in emit_move_insn (x=0x7ffff7bada80, y=0x7ffff7bada98) at ./gcc/gcc/expr.c:3858 ★★↓いかにも分割していそうな、怪しい名前 #4 0x00000000009fee38 in emit_move_multi_word (mode=E_V64SImode, x=0x7ffff7bada68, y=0x7ffff7bada50) at ./gcc/gcc/expr.c:3720 #5 0x00000000009ff505 in emit_move_insn_1 (x=0x7ffff7bada68, y=0x7ffff7bada50) at ./gcc/gcc/expr.c:3791 #6 0x00000000009ffa28 in emit_move_insn (x=0x7ffff7bada68, y=0x7ffff7bada50) at ./gcc/gcc/expr.c:3858 #7 0x0000000000a0cc8d in store_expr (exp=0x7ffff7ffb480, target=0x7ffff7bada68, call_param_p=0, nontemporal=false, reverse=false) at ./gcc/gcc/expr.c:5932 #8 0x0000000000a09064 in expand_assignment (to=0x7ffff7aa7750, from=0x7ffff7ffb480, nontemporal=false) at ./gcc/gcc/expr.c:5517 #9 0x000000000076c911 in expand_asm_stmt (stmt=0x7ffff7b8f4e0) at ./gcc/gcc/cfgexpand.c:3198 #10 0x000000000076f89a in expand_gimple_stmt_1 (stmt=0x7ffff7b8f4e0) at ./gcc/gcc/cfgexpand.c:3685 #11 0x00000000007705f0 in expand_gimple_stmt (stmt=0x7ffff7b8f4e0) at ./gcc/gcc/cfgexpand.c:3853 #12 0x000000000077e7f1 in expand_gimple_basic_block (bb=0x7ffff7aba2d8, disable_tail_calls=false) at ./gcc/gcc/cfgexpand.c:5893 #13 0x0000000000781a25 in (anonymous namespace)::pass_expand::execute (this=0x449bbf0, fun=0x7ffff7baa000)
バックトレースの中に怪しい名前の関数emit_move_multi_word() があります。いかにも複数のinsnを出力しそうな名前です。emit_move_multi_wordまでを追うと、下記のような経路を辿っています。
// gcc/cfgexpand.c
static void
expand_asm_stmt (gasm *stmt)
{
...
for (i = 0; i < noutputs; ++i)
{
tree val = output_tvec[i];
tree type = TREE_TYPE (val);
bool is_inout, allows_reg, allows_mem, ok;
rtx op;
...
if ((TREE_CODE (val) == INDIRECT_REF && allows_mem)
|| (DECL_P (val)
&& (allows_mem || REG_P (DECL_RTL (val)))
&& ! (REG_P (DECL_RTL (val))
&& GET_MODE (DECL_RTL (val)) != TYPE_MODE (type)))
|| ! allows_reg
|| is_inout
|| TREE_ADDRESSABLE (type))
{
...
}
else
{
op = assign_temp (type, 0, 1);
op = validize_mem (op);
if (!MEM_P (op) && TREE_CODE (val) == SSA_NAME)
set_reg_attrs_for_decl_rtl (SSA_NAME_VAR (val), op);
generating_concat_p = old_generating_concat_p;
push_to_sequence2 (after_rtl_seq, after_rtl_end);
expand_assignment (val, make_tree (type, op), false); //★★これ
after_rtl_seq = get_insns ();
after_rtl_end = get_last_insn ();
end_sequence ();
}
// gcc/expr.c
/* Expand an assignment that stores the value of FROM into TO. If NONTEMPORAL
is true, try generating a nontemporal store. */
void
expand_assignment (tree to, tree from, bool nontemporal)
{
...
/* Compute FROM and store the value in the rtx we got. */
push_temp_slots ();
result = store_expr (from, to_rtx, 0, nontemporal, false); //★★これ
preserve_temp_slots (result);
pop_temp_slots ();
return;
}
rtx_insn *
emit_move_insn (rtx x, rtx y)
{
machine_mode mode = GET_MODE (x);
rtx y_cst = NULL_RTX;
rtx_insn *last_insn;
rtx set;
...
last_insn = emit_move_insn_1 (x, y); //★★これ
if (y_cst && REG_P (x)
&& (set = single_set (last_insn)) != NULL_RTX
&& SET_DEST (set) == x
&& ! rtx_equal_p (y_cst, SET_SRC (set)))
set_unique_reg_note (last_insn, REG_EQUAL, copy_rtx (y_cst));
return last_insn;
}
rtx_insn *
emit_move_insn_1 (rtx x, rtx y)
{
machine_mode mode = GET_MODE (x);
enum insn_code code;
gcc_assert ((unsigned int) mode < (unsigned int) MAX_MACHINE_MODE);
code = optab_handler (mov_optab, mode);
if (code != CODE_FOR_nothing) //★★CODE_FOR_nothingになるのが怪しい
return emit_insn (GEN_FCN (code) (x, y)); //★★こっちに行けばいいのだろうか??
/* Expand complex moves by moving real part and imag part. */
if (COMPLEX_MODE_P (mode))
return emit_move_complex (mode, x, y); //★★もしくはこっち??
...
return emit_move_multi_word (mode, x, y); //★★この関数が呼ばれ、分割される
}
せっかく辿っておいてこんなこというのは若干気が引けますが、なぜこの経路を辿るのか?コードを見ても全くわかりません。特にexpand_asm_stmt() からemit_move_insn() までは、各関数が非常に長く、訳のわからないif文が山ほどあります。GCCってどうして動いてるんでしょうね?大丈夫?これ??
GCCのコードの酷さはさておき、emit_move_multi_word() と他の関数への分岐点になっている、emit_move_insn_1() が怪しそうです。次回以降、この関数を中心に調べます。
< | 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.15.
using GD bundled (2.1.0 compatible)(png support.)