Daily bump.
[official-gcc.git] / gcc / config / nds32 / nds32-relax-opt.c
blob0349be4725d2aacb356864f6a7ccf06be6e0621d
1 /* relax-opt pass of Andes NDS32 cpu for GNU compiler
2 Copyright (C) 2012-2018 Free Software Foundation, Inc.
3 Contributed by Andes Technology Corporation.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published
9 by the Free Software Foundation; either version 3, or (at your
10 option) any later version.
12 GCC is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
15 License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
21 /* ------------------------------------------------------------------------ */
23 #define IN_TARGET_CODE 1
25 #include "config.h"
26 #include "system.h"
27 #include "coretypes.h"
28 #include "backend.h"
29 #include "target.h"
30 #include "rtl.h"
31 #include "tree.h"
32 #include "stringpool.h"
33 #include "attribs.h"
34 #include "df.h"
35 #include "memmodel.h"
36 #include "tm_p.h"
37 #include "optabs.h" /* For GEN_FCN. */
38 #include "regs.h"
39 #include "emit-rtl.h"
40 #include "recog.h"
41 #include "diagnostic-core.h"
42 #include "stor-layout.h"
43 #include "varasm.h"
44 #include "calls.h"
45 #include "output.h"
46 #include "explow.h"
47 #include "expr.h"
48 #include "tm-constrs.h"
49 #include "builtins.h"
50 #include "cpplib.h"
51 #include "insn-attr.h"
52 #include "cfgrtl.h"
53 #include "tree-pass.h"
55 /* This is used to create unique relax hint id value.
56 The initial value is 0. */
57 static int relax_group_id = 0;
59 /* Group the following pattern as relax candidates:
61 1. sethi $ra, hi20(sym)
62 ori $ra, $ra, lo12(sym)
63 ==>
64 addi.gp $ra, sym
66 2. sethi $ra, hi20(sym)
67 lwi $rb, [$ra + lo12(sym)]
68 ==>
69 lwi.gp $rb, [(sym)]
71 3. sethi $ra, hi20(sym)
72 ori $ra, $ra, lo12(sym)
73 lwi $rb, [$ra]
74 swi $rc, [$ra]
75 ==>
76 lwi37 $rb, [(sym)]
77 swi37 $rc, [(sym)] */
79 /* Return true if is load/store with REG addressing mode
80 and memory mode is SImode. */
81 static bool
82 nds32_reg_base_load_store_p (rtx_insn *insn)
84 rtx mem_src = NULL_RTX;
86 switch (get_attr_type (insn))
88 case TYPE_LOAD:
89 mem_src = SET_SRC (PATTERN (insn));
90 break;
91 case TYPE_STORE:
92 mem_src = SET_DEST (PATTERN (insn));
93 break;
94 default:
95 break;
98 /* Find load/store insn with addressing mode is REG. */
99 if (mem_src != NULL_RTX)
101 if ((GET_CODE (mem_src) == ZERO_EXTEND)
102 || (GET_CODE (mem_src) == SIGN_EXTEND))
103 mem_src = XEXP (mem_src, 0);
105 if (GET_CODE (XEXP (mem_src, 0)) == REG)
106 return true;
109 return false;
112 /* Return true if insn is a sp/fp base or sp/fp plus load-store instruction. */
114 static bool
115 nds32_sp_base_or_plus_load_store_p (rtx_insn *insn)
117 rtx mem_src = NULL_RTX;
119 switch (get_attr_type (insn))
121 case TYPE_LOAD:
122 mem_src = SET_SRC (PATTERN (insn));
123 break;
124 case TYPE_STORE:
125 mem_src = SET_DEST (PATTERN (insn));
126 break;
127 default:
128 break;
130 /* Find load/store insn with addressing mode is REG. */
131 if (mem_src != NULL_RTX)
133 if ((GET_CODE (mem_src) == ZERO_EXTEND)
134 || (GET_CODE (mem_src) == SIGN_EXTEND))
135 mem_src = XEXP (mem_src, 0);
137 if ((GET_CODE (XEXP (mem_src, 0)) == PLUS))
138 mem_src = XEXP (mem_src, 0);
140 if (REG_P (XEXP (mem_src, 0))
141 && ((frame_pointer_needed
142 && REGNO (XEXP (mem_src, 0)) == FP_REGNUM)
143 || REGNO (XEXP (mem_src, 0)) == SP_REGNUM))
144 return true;
147 return false;
150 /* Return true if is load with [REG + REG/CONST_INT] addressing mode. */
151 static bool
152 nds32_plus_reg_load_store_p (rtx_insn *insn)
154 rtx mem_src = NULL_RTX;
156 switch (get_attr_type (insn))
158 case TYPE_LOAD:
159 mem_src = SET_SRC (PATTERN (insn));
160 break;
161 case TYPE_STORE:
162 mem_src = SET_DEST (PATTERN (insn));
163 break;
164 default:
165 break;
168 /* Find load/store insn with addressing mode is [REG + REG/CONST]. */
169 if (mem_src != NULL_RTX)
171 if ((GET_CODE (mem_src) == ZERO_EXTEND)
172 || (GET_CODE (mem_src) == SIGN_EXTEND))
173 mem_src = XEXP (mem_src, 0);
175 if ((GET_CODE (XEXP (mem_src, 0)) == PLUS))
176 mem_src = XEXP (mem_src, 0);
177 else
178 return false;
180 if (GET_CODE (XEXP (mem_src, 0)) == REG)
181 return true;
185 return false;
188 /* Group the relax candidates with group id. */
189 static void
190 nds32_group_insns (rtx sethi)
192 df_ref def_record, use_record;
193 df_link *link;
194 rtx_insn *use_insn = NULL;
195 rtx group_id;
197 def_record = DF_INSN_DEFS (sethi);
199 for (link = DF_REF_CHAIN (def_record); link; link = link->next)
201 if (!DF_REF_INSN_INFO (link->ref))
202 continue;
204 use_insn = DF_REF_INSN (link->ref);
206 /* Skip if define insn and use insn not in the same basic block. */
207 if (!dominated_by_p (CDI_DOMINATORS,
208 BLOCK_FOR_INSN (use_insn),
209 BLOCK_FOR_INSN (sethi)))
210 return;
212 /* Skip if the low-part used register is from different high-part
213 instructions. */
214 use_record = DF_INSN_USES (use_insn);
215 if (DF_REF_CHAIN (use_record) && DF_REF_CHAIN (use_record)->next)
216 return;
218 /* Skip if use_insn not active insn. */
219 if (!active_insn_p (use_insn))
220 return;
222 /* Initial use_insn_type. */
223 if (!(recog_memoized (use_insn) == CODE_FOR_lo_sum
224 || nds32_symbol_load_store_p (use_insn)
225 || (nds32_reg_base_load_store_p (use_insn)
226 &&!nds32_sp_base_or_plus_load_store_p (use_insn))))
227 return;
230 group_id = GEN_INT (relax_group_id);
231 /* Insert .relax_* directive for sethi. */
232 emit_insn_before (gen_relax_group (group_id), sethi);
234 /* Scan the use insns and insert the directive. */
235 for (link = DF_REF_CHAIN (def_record); link; link = link->next)
237 if (!DF_REF_INSN_INFO (link->ref))
238 continue;
240 use_insn = DF_REF_INSN (link->ref);
242 /* Insert .relax_* directive. */
243 if (active_insn_p (use_insn))
244 emit_insn_before (gen_relax_group (group_id), use_insn);
247 relax_group_id++;
250 /* Group the relax candidate instructions for linker. */
251 static void
252 nds32_relax_group (void)
254 rtx_insn *insn;
256 compute_bb_for_insn ();
258 df_chain_add_problem (DF_DU_CHAIN | DF_UD_CHAIN);
259 df_insn_rescan_all ();
260 df_analyze ();
261 df_set_flags (DF_DEFER_INSN_RESCAN);
262 calculate_dominance_info (CDI_DOMINATORS);
264 insn = get_insns ();
265 gcc_assert (NOTE_P (insn));
267 for (insn = next_active_insn (insn); insn; insn = next_active_insn (insn))
269 if (NONJUMP_INSN_P (insn))
271 /* Find sethi ra, symbol instruction. */
272 if (recog_memoized (insn) == CODE_FOR_sethi
273 && nds32_symbolic_operand (XEXP (SET_SRC (PATTERN (insn)), 0),
274 SImode))
275 nds32_group_insns (insn);
279 /* We must call df_finish_pass manually because it should be invoked before
280 BB information is destroyed. Hence we cannot set the TODO_df_finish flag
281 to the pass manager. */
282 df_insn_rescan_all ();
283 df_finish_pass (false);
284 free_dominance_info (CDI_DOMINATORS);
287 static unsigned int
288 nds32_relax_opt (void)
290 if (TARGET_RELAX_HINT)
291 nds32_relax_group ();
292 return 1;
295 const pass_data pass_data_nds32_relax_opt =
297 RTL_PASS, /* type */
298 "relax_opt", /* name */
299 OPTGROUP_NONE, /* optinfo_flags */
300 TV_MACH_DEP, /* tv_id */
301 0, /* properties_required */
302 0, /* properties_provided */
303 0, /* properties_destroyed */
304 0, /* todo_flags_start */
305 TODO_df_finish, /* todo_flags_finish */
308 class pass_nds32_relax_opt : public rtl_opt_pass
310 public:
311 pass_nds32_relax_opt (gcc::context *ctxt)
312 : rtl_opt_pass (pass_data_nds32_relax_opt, ctxt)
315 /* opt_pass methods: */
316 bool gate (function *) { return TARGET_RELAX_HINT; }
317 unsigned int execute (function *) { return nds32_relax_opt (); }
320 rtl_opt_pass *
321 make_pass_nds32_relax_opt (gcc::context *ctxt)
323 return new pass_nds32_relax_opt (ctxt);