[NDS32] Implement fp-as-gp optimization.
[official-gcc.git] / gcc / config / nds32 / nds32-fp-as-gp.c
blob1abad1dc24a14183ccd93ecdee9593ccca07aba6
1 /* The fp-as-gp 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 "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"
44 /* ------------------------------------------------------------------------ */
46 /* A helper function to check if this function should contain prologue. */
47 static bool
48 nds32_have_prologue_p (void)
50 int i;
52 for (i = 0; i < 28; i++)
53 if (NDS32_REQUIRED_CALLEE_SAVED_P (i))
54 return true;
56 return (flag_pic
57 || NDS32_REQUIRED_CALLEE_SAVED_P (FP_REGNUM)
58 || NDS32_REQUIRED_CALLEE_SAVED_P (LP_REGNUM));
61 static int
62 nds32_get_symbol_count (void)
64 int symbol_count = 0;
65 rtx_insn *insn;
66 basic_block bb;
68 FOR_EACH_BB_FN (bb, cfun)
70 FOR_BB_INSNS (bb, insn)
72 /* Counting the insn number which the addressing mode is symbol. */
73 if (single_set (insn) && nds32_symbol_load_store_p (insn))
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);
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++;
93 return symbol_count;
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
102 nds32_fp_as_gp_check_available (void)
104 basic_block bb;
105 basic_block exit_bb;
106 edge_iterator ei;
107 edge e;
108 bool first_exit_blocks_p;
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;
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;
145 FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (cfun)->preds)
147 /* More than one exit block also do not perform fp_as_gp optimization. */
148 if (!first_exit_blocks_p)
149 return false;
151 exit_bb = e->src;
152 first_exit_blocks_p = false;
155 /* Not found exit_bb? just abort fp_as_gp! */
156 if (!exit_bb)
157 return false;
159 /* Each bb should post dominate by exit_bb if there is no infinite loop! */
160 FOR_EACH_BB_FN (bb, cfun)
162 if (!dominated_by_p (CDI_POST_DOMINATORS,
164 exit_bb))
165 return false;
168 /* Now we can check the possibility of using fp_as_gp optimization. */
169 if (TARGET_FORCE_FP_AS_GP)
171 /* User explicitly issues -mforce-fp-as-gp option. */
172 return true;
174 else
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;
181 int threshold;
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 ())
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;
199 else
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);
213 symbol_count = nds32_get_symbol_count ();
215 if (symbol_count >= threshold)
216 good_gain = true;
218 /* Enable fp_as_gp optimization when potential gain is good enough. */
219 return good_gain;
223 static unsigned int
224 nds32_fp_as_gp (void)
226 bool fp_as_gp_p;
227 calculate_dominance_info (CDI_POST_DOMINATORS);
228 fp_as_gp_p = nds32_fp_as_gp_check_available ();
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);
239 cfun->machine->fp_as_gp_p = fp_as_gp_p;
241 free_dominance_info (CDI_POST_DOMINATORS);
242 return 1;
245 const pass_data pass_data_nds32_fp_as_gp =
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 */
258 class pass_nds32_fp_as_gp : public rtl_opt_pass
260 public:
261 pass_nds32_fp_as_gp (gcc::context *ctxt)
262 : rtl_opt_pass (pass_data_nds32_fp_as_gp, ctxt)
265 /* opt_pass methods: */
266 bool gate (function *)
268 return TARGET_16_BIT
269 && optimize_size;
271 unsigned int execute (function *) { return nds32_fp_as_gp (); }
274 rtl_opt_pass *
275 make_pass_nds32_fp_as_gp (gcc::context *ctxt)
277 return new pass_nds32_fp_as_gp (ctxt);
280 /* ------------------------------------------------------------------------ */