1 /* Shorten memrefs pass for RISC-V.
2 Copyright (C) 2018-2024 Free Software Foundation, Inc.
4 This file is part of GCC.
6 GCC is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
11 GCC is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING3. If not see
18 <http://www.gnu.org/licenses/>. */
20 #define IN_TARGET_CODE 1
24 #include "coretypes.h"
34 #include "tree-pass.h"
36 /* Try to make more use of compressed load and store instructions by replacing
37 a load/store at address BASE + LARGE_OFFSET with a new load/store at address
38 NEW BASE + SMALL OFFSET. If NEW BASE is stored in a compressed register, the
39 load/store can be compressed. Since creating NEW BASE incurs an overhead,
40 the change is only attempted when BASE is referenced by at least four
41 load/stores in the same basic block. */
45 const pass_data pass_data_shorten_memrefs
=
48 "shorten_memrefs", /* name */
49 OPTGROUP_NONE
, /* optinfo_flags */
51 0, /* properties_required */
52 0, /* properties_provided */
53 0, /* properties_destroyed */
54 0, /* todo_flags_start */
55 0, /* todo_flags_finish */
58 class pass_shorten_memrefs
: public rtl_opt_pass
61 pass_shorten_memrefs (gcc::context
*ctxt
)
62 : rtl_opt_pass (pass_data_shorten_memrefs
, ctxt
)
65 /* opt_pass methods: */
66 virtual bool gate (function
*)
68 return (TARGET_RVC
|| TARGET_ZCA
)
69 && riscv_mshorten_memrefs
&& optimize
> 0;
71 virtual unsigned int execute (function
*);
74 typedef int_hash
<HOST_WIDE_INT
, 0> regno_hash
;
75 typedef hash_map
<regno_hash
, int> regno_map
;
77 regno_map
* analyze (basic_block bb
);
78 void transform (regno_map
*m
, basic_block bb
);
79 bool get_si_mem_base_reg (rtx mem
, rtx
*addr
, bool *extend
);
80 }; // class pass_shorten_memrefs
83 pass_shorten_memrefs::get_si_mem_base_reg (rtx mem
, rtx
*addr
, bool *extend
)
85 /* Whether it's sign/zero extended. */
86 if (GET_CODE (mem
) == ZERO_EXTEND
|| GET_CODE (mem
) == SIGN_EXTEND
)
92 if (!MEM_P (mem
) || GET_MODE (mem
) != SImode
)
94 *addr
= XEXP (mem
, 0);
95 return GET_CODE (*addr
) == PLUS
&& REG_P (XEXP (*addr
, 0));
98 /* Count how many times each regno is referenced as base address for a memory
101 pass_shorten_memrefs::regno_map
*
102 pass_shorten_memrefs::analyze (basic_block bb
)
104 regno_map
*m
= hash_map
<regno_hash
, int>::create_ggc (10);
107 regstat_init_n_sets_and_refs ();
109 FOR_BB_INSNS (bb
, insn
)
111 if (!NONJUMP_INSN_P (insn
))
113 rtx pat
= PATTERN (insn
);
114 if (GET_CODE (pat
) != SET
)
116 /* Analyze stores first then loads. */
117 for (int i
= 0; i
< 2; i
++)
119 rtx mem
= XEXP (pat
, i
);
122 if (get_si_mem_base_reg (mem
, &addr
, &extend
))
124 HOST_WIDE_INT regno
= REGNO (XEXP (addr
, 0));
125 /* Do not count store zero as these cannot be compressed. */
128 if (XEXP (pat
, 1) == CONST0_RTX (GET_MODE (XEXP (pat
, 1))))
131 if (REG_N_REFS (regno
) < 4)
133 m
->get_or_insert (regno
)++;
137 regstat_free_n_sets_and_refs ();
142 /* Convert BASE + LARGE_OFFSET to NEW_BASE + SMALL_OFFSET for each load/store
143 with a base reg referenced at least 4 times. */
146 pass_shorten_memrefs::transform (regno_map
*m
, basic_block bb
)
149 FOR_BB_INSNS (bb
, insn
)
151 if (!NONJUMP_INSN_P (insn
))
153 rtx pat
= PATTERN (insn
);
154 if (GET_CODE (pat
) != SET
)
157 /* Transform stores first then loads. */
158 for (int i
= 0; i
< 2; i
++)
160 rtx mem
= XEXP (pat
, i
);
163 if (get_si_mem_base_reg (mem
, &addr
, &extend
))
165 HOST_WIDE_INT regno
= REGNO (XEXP (addr
, 0));
166 /* Do not transform store zero as these cannot be compressed. */
169 if (XEXP (pat
, 1) == CONST0_RTX (GET_MODE (XEXP (pat
, 1))))
172 if (m
->get_or_insert (regno
) > 3)
177 = targetm
.legitimize_address (addr
, addr
,
178 GET_MODE (XEXP (mem
, 0)));
179 XEXP (XEXP (pat
, i
), 0)
180 = replace_equiv_address (XEXP (mem
, 0), addr
);
184 addr
= targetm
.legitimize_address (addr
, addr
,
186 XEXP (pat
, i
) = replace_equiv_address (mem
, addr
);
188 df_insn_rescan (insn
);
192 rtx_insn
*seq
= get_insns ();
194 emit_insn_before (seq
, insn
);
199 pass_shorten_memrefs::execute (function
*fn
)
203 FOR_ALL_BB_FN (bb
, fn
)
206 if (optimize_bb_for_speed_p (bb
))
218 make_pass_shorten_memrefs (gcc::context
*ctxt
)
220 return new pass_shorten_memrefs (ctxt
);