xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/config/nds32/nds32-fp-as-gp.c (revision 8feb0f0b7eaff0608f8350bbfa3098827b4bb91b)
1 /* The fp-as-gp pass of Andes NDS32 cpu for GNU compiler
2    Copyright (C) 2012-2020 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 "hard-reg-set.h"
30 #include "tm_p.h"
31 #include "rtl.h"
32 #include "memmodel.h"
33 #include "emit-rtl.h"
34 #include "insn-config.h"
35 #include "regs.h"
36 #include "hard-reg-set.h"
37 #include "ira.h"
38 #include "ira-int.h"
39 #include "df.h"
40 #include "tree-core.h"
41 #include "tree-pass.h"
42 #include "nds32-protos.h"
43 
44 /* ------------------------------------------------------------------------ */
45 
46 /* A helper function to check if this function should contain prologue.  */
47 static bool
nds32_have_prologue_p(void)48 nds32_have_prologue_p (void)
49 {
50   int i;
51 
52   for (i = 0; i < 28; i++)
53     if (NDS32_REQUIRED_CALLEE_SAVED_P (i))
54       return true;
55 
56   return (flag_pic
57 	  || NDS32_REQUIRED_CALLEE_SAVED_P (FP_REGNUM)
58 	  || NDS32_REQUIRED_CALLEE_SAVED_P (LP_REGNUM));
59 }
60 
61 static int
nds32_get_symbol_count(void)62 nds32_get_symbol_count (void)
63 {
64   int symbol_count = 0;
65   rtx_insn *insn;
66   basic_block bb;
67 
68   FOR_EACH_BB_FN (bb, cfun)
69     {
70       FOR_BB_INSNS (bb, insn)
71 	{
72 	  /* Counting the insn number which the addressing mode is symbol.  */
73 	  if (single_set (insn) && nds32_symbol_load_store_p (insn))
74 	    {
75 	      rtx pattern = PATTERN (insn);
76 	      rtx mem;
77 	      gcc_assert (GET_CODE (pattern) == SET);
78 	      if (GET_CODE (SET_SRC (pattern)) == REG )
79 		mem = SET_DEST (pattern);
80 	      else
81 		mem = SET_SRC (pattern);
82 
83 	      /* We have only lwi37 and swi37 for fp-as-gp optimization,
84 		 so don't count any other than SImode.
85 		 MEM for QImode and HImode will wrap by ZERO_EXTEND
86 		 or SIGN_EXTEND */
87 	      if (GET_CODE (mem) == MEM)
88 		symbol_count++;
89 	    }
90 	}
91     }
92 
93   return symbol_count;
94 }
95 
96 /* Function to determine whether it is worth to do fp_as_gp optimization.
97    Return false: It is NOT worth to do fp_as_gp optimization.
98    Return true: It is APPROXIMATELY worth to do fp_as_gp optimization.
99    Note that if it is worth to do fp_as_gp optimization,
100    we MUST set FP_REGNUM ever live in this function.  */
101 static bool
nds32_fp_as_gp_check_available(void)102 nds32_fp_as_gp_check_available (void)
103 {
104   basic_block bb;
105   basic_block exit_bb;
106   edge_iterator ei;
107   edge e;
108   bool first_exit_blocks_p;
109 
110   /* If there exists ANY of following conditions,
111      we DO NOT perform fp_as_gp optimization:
112        1. TARGET_FORBID_FP_AS_GP is set
113 	  regardless of the TARGET_FORCE_FP_AS_GP.
114        2. User explicitly uses 'naked'/'no_prologue' attribute.
115 	  We use nds32_naked_function_p() to help such checking.
116        3. Not optimize for size.
117        4. Need frame pointer.
118        5. If $fp is already required to be saved,
119 	  it means $fp is already choosen by register allocator.
120 	  Thus we better not to use it for fp_as_gp optimization.
121        6. This function is a vararg function.
122 	  DO NOT apply fp_as_gp optimization on this function
123 	  because it may change and break stack frame.
124        7. The epilogue is empty.
125 	  This happens when the function uses exit()
126 	  or its attribute is no_return.
127 	  In that case, compiler will not expand epilogue
128 	  so that we have no chance to output .omit_fp_end directive.  */
129   if (TARGET_FORBID_FP_AS_GP
130       || nds32_naked_function_p (current_function_decl)
131       || !optimize_size
132       || frame_pointer_needed
133       || NDS32_REQUIRED_CALLEE_SAVED_P (FP_REGNUM)
134       || (cfun->stdarg == 1)
135       || (find_fallthru_edge (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds) == NULL))
136     return false;
137 
138   /* Disable fp_as_gp if there is any infinite loop since the fp may
139      reuse in infinite loops by register rename.
140      For check infinite loops we should make sure exit_bb is post dominate
141      all other basic blocks if there is no infinite loops.  */
142   first_exit_blocks_p = true;
143   exit_bb = NULL;
144 
145   FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (cfun)->preds)
146     {
147       /* More than one exit block also do not perform fp_as_gp optimization.  */
148       if (!first_exit_blocks_p)
149 	return false;
150 
151       exit_bb = e->src;
152       first_exit_blocks_p = false;
153     }
154 
155   /* Not found exit_bb? just abort fp_as_gp!  */
156   if (!exit_bb)
157     return false;
158 
159   /* Each bb should post dominate by exit_bb if there is no infinite loop! */
160   FOR_EACH_BB_FN (bb, cfun)
161     {
162       if (!dominated_by_p (CDI_POST_DOMINATORS,
163 			   bb,
164 			   exit_bb))
165 	return false;
166     }
167 
168   /* Now we can check the possibility of using fp_as_gp optimization.  */
169   if (TARGET_FORCE_FP_AS_GP)
170     {
171       /* User explicitly issues -mforce-fp-as-gp option.  */
172       return true;
173     }
174   else
175     {
176       /* In the following we are going to evaluate whether
177 	 it is worth to do fp_as_gp optimization.  */
178       bool good_gain = false;
179       int symbol_count;
180 
181       int threshold;
182 
183       /* We check if there already requires prologue.
184 	 Note that $gp will be saved in prologue for PIC code generation.
185 	 After that, we can set threshold by the existence of prologue.
186 	 Each fp-implied instruction will gain 2-byte code size
187 	 from gp-aware instruction, so we have following heuristics.  */
188       if (flag_pic
189 	  || nds32_have_prologue_p ())
190 	{
191 	  /* Have-prologue:
192 	       Compiler already intends to generate prologue content,
193 	       so the fp_as_gp optimization will only insert
194 	       'la $fp,_FP_BASE_' instruction, which will be
195 	       converted into 4-byte instruction at link time.
196 	       The threshold is "3" symbol accesses, 2 + 2 + 2 > 4.  */
197 	  threshold = 3;
198 	}
199       else
200 	{
201 	  /* None-prologue:
202 	       Compiler originally does not generate prologue content,
203 	       so the fp_as_gp optimization will NOT ONLY insert
204 	       'la $fp,_FP_BASE' instruction, but also causes
205 	       push/pop instructions.
206 	       If we are using v3push (push25/pop25),
207 	       the threshold is "5" symbol accesses, 5*2 > 4 + 2 + 2;
208 	       If we are using normal push (smw/lmw),
209 	       the threshold is "5+2" symbol accesses 7*2 > 4 + 4 + 4.  */
210 	  threshold = 5 + (TARGET_V3PUSH ? 0 : 2);
211 	}
212 
213       symbol_count = nds32_get_symbol_count ();
214 
215       if (symbol_count >= threshold)
216 	good_gain = true;
217 
218       /* Enable fp_as_gp optimization when potential gain is good enough.  */
219       return good_gain;
220     }
221 }
222 
223 static unsigned int
nds32_fp_as_gp(void)224 nds32_fp_as_gp (void)
225 {
226   bool fp_as_gp_p;
227   calculate_dominance_info (CDI_POST_DOMINATORS);
228   fp_as_gp_p = nds32_fp_as_gp_check_available ();
229 
230   /* Here is a hack to IRA for enable/disable a hard register per function.
231      We *MUST* review this way after migrate gcc 4.9! */
232   if (fp_as_gp_p) {
233     SET_HARD_REG_BIT(this_target_ira_int->x_no_unit_alloc_regs, FP_REGNUM);
234     df_set_regs_ever_live (FP_REGNUM, 1);
235   } else {
236     CLEAR_HARD_REG_BIT(this_target_ira_int->x_no_unit_alloc_regs, FP_REGNUM);
237   }
238 
239   cfun->machine->fp_as_gp_p = fp_as_gp_p;
240 
241   free_dominance_info (CDI_POST_DOMINATORS);
242   return 1;
243 }
244 
245 const pass_data pass_data_nds32_fp_as_gp =
246 {
247   RTL_PASS,				/* type */
248   "fp_as_gp",				/* name */
249   OPTGROUP_NONE,			/* optinfo_flags */
250   TV_MACH_DEP,				/* tv_id */
251   0,					/* properties_required */
252   0,					/* properties_provided */
253   0,					/* properties_destroyed */
254   0,					/* todo_flags_start */
255   0					/* todo_flags_finish */
256 };
257 
258 class pass_nds32_fp_as_gp : public rtl_opt_pass
259 {
260 public:
pass_nds32_fp_as_gp(gcc::context * ctxt)261   pass_nds32_fp_as_gp (gcc::context *ctxt)
262     : rtl_opt_pass (pass_data_nds32_fp_as_gp, ctxt)
263   {}
264 
265   /* opt_pass methods: */
gate(function *)266   bool gate (function *)
267   {
268     return !TARGET_LINUX_ABI
269 	   && TARGET_16_BIT
270 	   && optimize_size;
271   }
execute(function *)272   unsigned int execute (function *) { return nds32_fp_as_gp (); }
273 };
274 
275 rtl_opt_pass *
make_pass_nds32_fp_as_gp(gcc::context * ctxt)276 make_pass_nds32_fp_as_gp (gcc::context *ctxt)
277 {
278   return new pass_nds32_fp_as_gp (ctxt);
279 }
280 
281 /* ------------------------------------------------------------------------ */
282