]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/config/nds32/nds32-fp-as-gp.c
d7932678b84b3e5e838bb4827192d9ae7fd8c5ba
[thirdparty/gcc.git] / gcc / config / nds32 / nds32-fp-as-gp.c
1 /* The fp-as-gp pass of Andes NDS32 cpu for GNU compiler
2 Copyright (C) 2012-2014 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 #include "config.h"
24 #include "system.h"
25 #include "coretypes.h"
26 #include "tm.h"
27 #include "tree.h"
28 #include "stor-layout.h"
29 #include "varasm.h"
30 #include "calls.h"
31 #include "rtl.h"
32 #include "regs.h"
33 #include "hard-reg-set.h"
34 #include "insn-config.h" /* Required by recog.h. */
35 #include "conditions.h"
36 #include "output.h"
37 #include "insn-attr.h" /* For DFA state_t. */
38 #include "insn-codes.h" /* For CODE_FOR_xxx. */
39 #include "reload.h" /* For push_reload(). */
40 #include "flags.h"
41 #include "function.h"
42 #include "expr.h"
43 #include "recog.h"
44 #include "diagnostic-core.h"
45 #include "df.h"
46 #include "tm_p.h"
47 #include "tm-constrs.h"
48 #include "optabs.h" /* For GEN_FCN. */
49 #include "target.h"
50 #include "target-def.h"
51 #include "langhooks.h" /* For add_builtin_function(). */
52 #include "ggc.h"
53 #include "builtins.h"
54
55 /* ------------------------------------------------------------------------ */
56
57 /* A helper function to check if this function should contain prologue. */
58 static int
59 nds32_have_prologue_p (void)
60 {
61 int i;
62
63 for (i = 0; i < 28; i++)
64 if (NDS32_REQUIRED_CALLEE_SAVED_P (i))
65 return 1;
66
67 return (flag_pic
68 || NDS32_REQUIRED_CALLEE_SAVED_P (FP_REGNUM)
69 || NDS32_REQUIRED_CALLEE_SAVED_P (LP_REGNUM));
70 }
71
72 /* Return true if is load/store with SYMBOL_REF addressing mode
73 and memory mode is SImode. */
74 static bool
75 nds32_symbol_load_store_p (rtx insn)
76 {
77 rtx mem_src = NULL_RTX;
78
79 switch (get_attr_type (insn))
80 {
81 case TYPE_LOAD:
82 mem_src = SET_SRC (PATTERN (insn));
83 break;
84 case TYPE_STORE:
85 mem_src = SET_DEST (PATTERN (insn));
86 break;
87 default:
88 break;
89 }
90
91 /* Find load/store insn with addressing mode is SYMBOL_REF. */
92 if (mem_src != NULL_RTX)
93 {
94 if ((GET_CODE (mem_src) == ZERO_EXTEND)
95 || (GET_CODE (mem_src) == SIGN_EXTEND))
96 mem_src = XEXP (mem_src, 0);
97
98 if ((GET_CODE (XEXP (mem_src, 0)) == SYMBOL_REF)
99 || (GET_CODE (XEXP (mem_src, 0)) == LO_SUM))
100 return true;
101 }
102
103 return false;
104 }
105
106 /* Function to determine whether it is worth to do fp_as_gp optimization.
107 Return 0: It is NOT worth to do fp_as_gp optimization.
108 Return 1: It is APPROXIMATELY worth to do fp_as_gp optimization.
109 Note that if it is worth to do fp_as_gp optimization,
110 we MUST set FP_REGNUM ever live in this function. */
111 int
112 nds32_fp_as_gp_check_available (void)
113 {
114 /* If there exists ANY of following conditions,
115 we DO NOT perform fp_as_gp optimization:
116 1. TARGET_FORBID_FP_AS_GP is set
117 regardless of the TARGET_FORCE_FP_AS_GP.
118 2. User explicitly uses 'naked' attribute.
119 3. Not optimize for size.
120 4. Need frame pointer.
121 5. If $fp is already required to be saved,
122 it means $fp is already choosen by register allocator.
123 Thus we better not to use it for fp_as_gp optimization.
124 6. This function is a vararg function.
125 DO NOT apply fp_as_gp optimization on this function
126 because it may change and break stack frame.
127 7. The epilogue is empty.
128 This happens when the function uses exit()
129 or its attribute is no_return.
130 In that case, compiler will not expand epilogue
131 so that we have no chance to output .omit_fp_end directive. */
132 if (TARGET_FORBID_FP_AS_GP
133 || lookup_attribute ("naked", DECL_ATTRIBUTES (current_function_decl))
134 || !optimize_size
135 || frame_pointer_needed
136 || NDS32_REQUIRED_CALLEE_SAVED_P (FP_REGNUM)
137 || (cfun->stdarg == 1)
138 || (find_fallthru_edge (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds) == NULL))
139 return 0;
140
141 /* Now we can check the possibility of using fp_as_gp optimization. */
142 if (TARGET_FORCE_FP_AS_GP)
143 {
144 /* User explicitly issues -mforce-fp-as-gp option. */
145 df_set_regs_ever_live (FP_REGNUM, 1);
146 return 1;
147 }
148 else
149 {
150 /* In the following we are going to evaluate whether
151 it is worth to do fp_as_gp optimization. */
152 int good_gain = 0;
153 int symbol_count = 0;
154
155 int threshold;
156 rtx insn;
157
158 /* We check if there already requires prologue.
159 Note that $gp will be saved in prologue for PIC code generation.
160 After that, we can set threshold by the existence of prologue.
161 Each fp-implied instruction will gain 2-byte code size
162 from gp-aware instruction, so we have following heuristics. */
163 if (flag_pic
164 || nds32_have_prologue_p ())
165 {
166 /* Have-prologue:
167 Compiler already intends to generate prologue content,
168 so the fp_as_gp optimization will only insert
169 'la $fp,_FP_BASE_' instruction, which will be
170 converted into 4-byte instruction at link time.
171 The threshold is "3" symbol accesses, 2 + 2 + 2 > 4. */
172 threshold = 3;
173 }
174 else
175 {
176 /* None-prologue:
177 Compiler originally does not generate prologue content,
178 so the fp_as_gp optimization will NOT ONLY insert
179 'la $fp,_FP_BASE' instruction, but also causes
180 push/pop instructions.
181 If we are using v3push (push25/pop25),
182 the threshold is "5" symbol accesses, 5*2 > 4 + 2 + 2;
183 If we are using normal push (smw/lmw),
184 the threshold is "5+2" symbol accesses 7*2 > 4 + 4 + 4. */
185 threshold = 5 + (TARGET_V3PUSH ? 0 : 2);
186 }
187
188 /* We would like to traverse every instruction in this function.
189 So we need to have push_topmost_sequence()/pop_topmost_sequence()
190 surrounding our for-loop evaluation. */
191 push_topmost_sequence ();
192 /* Counting the insn number which the addressing mode is symbol. */
193 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
194 {
195 if (single_set (insn) && nds32_symbol_load_store_p (insn))
196 symbol_count++;
197
198 if (symbol_count == threshold)
199 {
200 good_gain = 1;
201 break;
202 }
203 }
204 pop_topmost_sequence ();
205
206 /* Enable fp_as_gp optimization when potential gain is good enough. */
207 if (good_gain)
208 {
209 df_set_regs_ever_live (FP_REGNUM, 1);
210 return 1;
211 }
212 }
213
214 /* By default we return 0. */
215 return 0;
216 }
217
218 /* ------------------------------------------------------------------------ */