]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/config/nds32/nds32-fp-as-gp.c
Update copyright years.
[thirdparty/gcc.git] / gcc / config / nds32 / nds32-fp-as-gp.c
CommitLineData
f54be922 1/* The fp-as-gp pass of Andes NDS32 cpu for GNU compiler
fbd26352 2 Copyright (C) 2012-2019 Free Software Foundation, Inc.
f54be922 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/>. */
f63b3b56 20
21/* ------------------------------------------------------------------------ */
22
785790dc 23#define IN_TARGET_CODE 1
24
f63b3b56 25#include "config.h"
26#include "system.h"
27#include "coretypes.h"
9ef16211 28#include "backend.h"
5ef15975 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"
f63b3b56 43
44/* ------------------------------------------------------------------------ */
45
5ef15975 46/* A helper function to check if this function should contain prologue. */
47static bool
48nds32_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
61static int
62nds32_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
f63b3b56 96/* Function to determine whether it is worth to do fp_as_gp optimization.
5ef15975 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.
f63b3b56 99 Note that if it is worth to do fp_as_gp optimization,
100 we MUST set FP_REGNUM ever live in this function. */
5ef15975 101static bool
f63b3b56 102nds32_fp_as_gp_check_available (void)
103{
5ef15975 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
223static unsigned int
224nds32_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
245const 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
258class pass_nds32_fp_as_gp : public rtl_opt_pass
259{
260public:
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: */
266 bool gate (function *)
267 {
a5a22b4f 268 return !TARGET_LINUX_ABI
269 && TARGET_16_BIT
5ef15975 270 && optimize_size;
271 }
272 unsigned int execute (function *) { return nds32_fp_as_gp (); }
273};
274
275rtl_opt_pass *
276make_pass_nds32_fp_as_gp (gcc::context *ctxt)
277{
278 return new pass_nds32_fp_as_gp (ctxt);
f63b3b56 279}
280
281/* ------------------------------------------------------------------------ */