xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/config/nds32/nds32-relax-opt.c (revision 8ecbf5f02b752fcb7debe1a8fab1dc82602bc760)
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.
4 
5    This file is part of GCC.
6 
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.
11 
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.
16 
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/>.  */
20 
21 /* ------------------------------------------------------------------------ */
22 
23 #define IN_TARGET_CODE 1
24 
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"
54 
55 /* This is used to create unique relax hint id value.
56    The initial value is 0.  */
57 static int relax_group_id = 0;
58 
59 /* Group the following pattern as relax candidates:
60 
61    1. sethi	$ra, hi20(sym)
62       ori	$ra, $ra, lo12(sym)
63     ==>
64       addi.gp	$ra, sym
65 
66    2. sethi	$ra, hi20(sym)
67       lwi	$rb, [$ra + lo12(sym)]
68     ==>
69       lwi.gp	$rb, [(sym)]
70 
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)] */
78 
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)
83 {
84   rtx mem_src = NULL_RTX;
85 
86   switch (get_attr_type (insn))
87     {
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;
96     }
97 
98   /* Find load/store insn with addressing mode is REG.  */
99   if (mem_src != NULL_RTX)
100     {
101       if ((GET_CODE (mem_src) == ZERO_EXTEND)
102 	  || (GET_CODE (mem_src) == SIGN_EXTEND))
103 	mem_src = XEXP (mem_src, 0);
104 
105       if (GET_CODE (XEXP (mem_src, 0)) == REG)
106 	return true;
107     }
108 
109   return false;
110 }
111 
112 /* Return true if insn is a sp/fp base or sp/fp plus load-store instruction.  */
113 
114 static bool
115 nds32_sp_base_or_plus_load_store_p (rtx_insn *insn)
116 {
117   rtx mem_src = NULL_RTX;
118 
119   switch (get_attr_type (insn))
120     {
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;
129     }
130   /* Find load/store insn with addressing mode is REG.  */
131   if (mem_src != NULL_RTX)
132     {
133       if ((GET_CODE (mem_src) == ZERO_EXTEND)
134 	  || (GET_CODE (mem_src) == SIGN_EXTEND))
135 	mem_src = XEXP (mem_src, 0);
136 
137       if ((GET_CODE (XEXP (mem_src, 0)) == PLUS))
138 	mem_src = XEXP (mem_src, 0);
139 
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;
145     }
146 
147   return false;
148 }
149 
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)
153 {
154   rtx mem_src = NULL_RTX;
155 
156   switch (get_attr_type (insn))
157     {
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;
166     }
167 
168   /* Find load/store insn with addressing mode is [REG + REG/CONST].  */
169   if (mem_src != NULL_RTX)
170     {
171       if ((GET_CODE (mem_src) == ZERO_EXTEND)
172 	  || (GET_CODE (mem_src) == SIGN_EXTEND))
173 	mem_src = XEXP (mem_src, 0);
174 
175       if ((GET_CODE (XEXP (mem_src, 0)) == PLUS))
176 	mem_src = XEXP (mem_src, 0);
177       else
178 	return false;
179 
180       if (GET_CODE (XEXP (mem_src, 0)) == REG)
181 	return true;
182 
183     }
184 
185   return false;
186 }
187 
188 /* Group the relax candidates with group id.  */
189 static void
190 nds32_group_insns (rtx sethi)
191 {
192   df_ref def_record, use_record;
193   df_link *link;
194   rtx_insn *use_insn = NULL;
195   rtx group_id;
196 
197   def_record = DF_INSN_DEFS (sethi);
198 
199   for (link = DF_REF_CHAIN (def_record); link; link = link->next)
200     {
201       if (!DF_REF_INSN_INFO (link->ref))
202 	continue;
203 
204       use_insn = DF_REF_INSN (link->ref);
205 
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;
211 
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;
217 
218       /* Skip if use_insn not active insn.  */
219       if (!active_insn_p (use_insn))
220 	return;
221 
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;
228     }
229 
230   group_id = GEN_INT (relax_group_id);
231   /* Insert .relax_* directive for sethi.  */
232   emit_insn_before (gen_relax_group (group_id), sethi);
233 
234   /* Scan the use insns and insert the directive.  */
235   for (link = DF_REF_CHAIN (def_record); link; link = link->next)
236     {
237       if (!DF_REF_INSN_INFO (link->ref))
238 	continue;
239 
240       use_insn = DF_REF_INSN (link->ref);
241 
242       /* Insert .relax_* directive.  */
243       if (active_insn_p (use_insn))
244 	emit_insn_before (gen_relax_group (group_id), use_insn);
245     }
246 
247   relax_group_id++;
248 }
249 
250 /* Group the relax candidate instructions for linker.  */
251 static void
252 nds32_relax_group (void)
253 {
254   rtx_insn *insn;
255 
256   compute_bb_for_insn ();
257 
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);
263 
264   insn = get_insns ();
265   gcc_assert (NOTE_P (insn));
266 
267   for (insn = next_active_insn (insn); insn; insn = next_active_insn (insn))
268     {
269       if (NONJUMP_INSN_P (insn))
270 	{
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);
276 	}
277     }
278 
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);
285 }
286 
287 static unsigned int
288 nds32_relax_opt (void)
289 {
290   if (TARGET_RELAX_HINT)
291     nds32_relax_group ();
292   return 1;
293 }
294 
295 const pass_data pass_data_nds32_relax_opt =
296 {
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 */
306 };
307 
308 class pass_nds32_relax_opt : public rtl_opt_pass
309 {
310 public:
311   pass_nds32_relax_opt (gcc::context *ctxt)
312     : rtl_opt_pass (pass_data_nds32_relax_opt, ctxt)
313   {}
314 
315   /* opt_pass methods: */
316   bool gate (function *) { return TARGET_RELAX_HINT; }
317   unsigned int execute (function *) { return nds32_relax_opt (); }
318 };
319 
320 rtl_opt_pass *
321 make_pass_nds32_relax_opt (gcc::context *ctxt)
322 {
323   return new pass_nds32_relax_opt (ctxt);
324 }
325