annotate gcc/config/nds32/nds32.c @ 111:04ced10e8804

gcc 7
author kono
date Fri, 27 Oct 2017 22:46:09 +0900
parents
children 84e7813d76e9
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
111
kono
parents:
diff changeset
1 /* Subroutines used for code generation of Andes NDS32 cpu for GNU compiler
kono
parents:
diff changeset
2 Copyright (C) 2012-2017 Free Software Foundation, Inc.
kono
parents:
diff changeset
3 Contributed by Andes Technology Corporation.
kono
parents:
diff changeset
4
kono
parents:
diff changeset
5 This file is part of GCC.
kono
parents:
diff changeset
6
kono
parents:
diff changeset
7 GCC is free software; you can redistribute it and/or modify it
kono
parents:
diff changeset
8 under the terms of the GNU General Public License as published
kono
parents:
diff changeset
9 by the Free Software Foundation; either version 3, or (at your
kono
parents:
diff changeset
10 option) any later version.
kono
parents:
diff changeset
11
kono
parents:
diff changeset
12 GCC is distributed in the hope that it will be useful, but WITHOUT
kono
parents:
diff changeset
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
kono
parents:
diff changeset
14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
kono
parents:
diff changeset
15 License for more details.
kono
parents:
diff changeset
16
kono
parents:
diff changeset
17 You should have received a copy of the GNU General Public License
kono
parents:
diff changeset
18 along with GCC; see the file COPYING3. If not see
kono
parents:
diff changeset
19 <http://www.gnu.org/licenses/>. */
kono
parents:
diff changeset
20
kono
parents:
diff changeset
21 /* ------------------------------------------------------------------------ */
kono
parents:
diff changeset
22
kono
parents:
diff changeset
23 #include "config.h"
kono
parents:
diff changeset
24 #include "system.h"
kono
parents:
diff changeset
25 #include "coretypes.h"
kono
parents:
diff changeset
26 #include "backend.h"
kono
parents:
diff changeset
27 #include "target.h"
kono
parents:
diff changeset
28 #include "rtl.h"
kono
parents:
diff changeset
29 #include "tree.h"
kono
parents:
diff changeset
30 #include "stringpool.h"
kono
parents:
diff changeset
31 #include "attribs.h"
kono
parents:
diff changeset
32 #include "df.h"
kono
parents:
diff changeset
33 #include "memmodel.h"
kono
parents:
diff changeset
34 #include "tm_p.h"
kono
parents:
diff changeset
35 #include "optabs.h" /* For GEN_FCN. */
kono
parents:
diff changeset
36 #include "regs.h"
kono
parents:
diff changeset
37 #include "emit-rtl.h"
kono
parents:
diff changeset
38 #include "recog.h"
kono
parents:
diff changeset
39 #include "diagnostic-core.h"
kono
parents:
diff changeset
40 #include "stor-layout.h"
kono
parents:
diff changeset
41 #include "varasm.h"
kono
parents:
diff changeset
42 #include "calls.h"
kono
parents:
diff changeset
43 #include "output.h"
kono
parents:
diff changeset
44 #include "explow.h"
kono
parents:
diff changeset
45 #include "expr.h"
kono
parents:
diff changeset
46 #include "tm-constrs.h"
kono
parents:
diff changeset
47 #include "builtins.h"
kono
parents:
diff changeset
48
kono
parents:
diff changeset
49 /* This file should be included last. */
kono
parents:
diff changeset
50 #include "target-def.h"
kono
parents:
diff changeset
51
kono
parents:
diff changeset
52 /* ------------------------------------------------------------------------ */
kono
parents:
diff changeset
53
kono
parents:
diff changeset
54 /* This file is divided into five parts:
kono
parents:
diff changeset
55
kono
parents:
diff changeset
56 PART 1: Auxiliary static variable definitions and
kono
parents:
diff changeset
57 target hook static variable definitions.
kono
parents:
diff changeset
58
kono
parents:
diff changeset
59 PART 2: Auxiliary static function definitions.
kono
parents:
diff changeset
60
kono
parents:
diff changeset
61 PART 3: Implement target hook stuff definitions.
kono
parents:
diff changeset
62
kono
parents:
diff changeset
63 PART 4: Implemet extern function definitions,
kono
parents:
diff changeset
64 the prototype is in nds32-protos.h.
kono
parents:
diff changeset
65
kono
parents:
diff changeset
66 PART 5: Initialize target hook structure and definitions. */
kono
parents:
diff changeset
67
kono
parents:
diff changeset
68 /* ------------------------------------------------------------------------ */
kono
parents:
diff changeset
69
kono
parents:
diff changeset
70 /* PART 1: Auxiliary static variable definitions and
kono
parents:
diff changeset
71 target hook static variable definitions. */
kono
parents:
diff changeset
72
kono
parents:
diff changeset
73 /* Define intrinsic register names.
kono
parents:
diff changeset
74 Please refer to nds32_intrinsic.h file, the index is corresponding to
kono
parents:
diff changeset
75 'enum nds32_intrinsic_registers' data type values.
kono
parents:
diff changeset
76 NOTE that the base value starting from 1024. */
kono
parents:
diff changeset
77 static const char * const nds32_intrinsic_register_names[] =
kono
parents:
diff changeset
78 {
kono
parents:
diff changeset
79 "$PSW", "$IPSW", "$ITYPE", "$IPC"
kono
parents:
diff changeset
80 };
kono
parents:
diff changeset
81
kono
parents:
diff changeset
82 /* Defining target-specific uses of __attribute__. */
kono
parents:
diff changeset
83 static const struct attribute_spec nds32_attribute_table[] =
kono
parents:
diff changeset
84 {
kono
parents:
diff changeset
85 /* Syntax: { name, min_len, max_len, decl_required, type_required,
kono
parents:
diff changeset
86 function_type_required, handler, affects_type_identity } */
kono
parents:
diff changeset
87
kono
parents:
diff changeset
88 /* The interrupt vid: [0-63]+ (actual vector number starts from 9 to 72). */
kono
parents:
diff changeset
89 { "interrupt", 1, 64, false, false, false, NULL, false },
kono
parents:
diff changeset
90 /* The exception vid: [1-8]+ (actual vector number starts from 1 to 8). */
kono
parents:
diff changeset
91 { "exception", 1, 8, false, false, false, NULL, false },
kono
parents:
diff changeset
92 /* Argument is user's interrupt numbers. The vector number is always 0. */
kono
parents:
diff changeset
93 { "reset", 1, 1, false, false, false, NULL, false },
kono
parents:
diff changeset
94
kono
parents:
diff changeset
95 /* The attributes describing isr nested type. */
kono
parents:
diff changeset
96 { "nested", 0, 0, false, false, false, NULL, false },
kono
parents:
diff changeset
97 { "not_nested", 0, 0, false, false, false, NULL, false },
kono
parents:
diff changeset
98 { "nested_ready", 0, 0, false, false, false, NULL, false },
kono
parents:
diff changeset
99
kono
parents:
diff changeset
100 /* The attributes describing isr register save scheme. */
kono
parents:
diff changeset
101 { "save_all", 0, 0, false, false, false, NULL, false },
kono
parents:
diff changeset
102 { "partial_save", 0, 0, false, false, false, NULL, false },
kono
parents:
diff changeset
103
kono
parents:
diff changeset
104 /* The attributes used by reset attribute. */
kono
parents:
diff changeset
105 { "nmi", 1, 1, false, false, false, NULL, false },
kono
parents:
diff changeset
106 { "warm", 1, 1, false, false, false, NULL, false },
kono
parents:
diff changeset
107
kono
parents:
diff changeset
108 /* The attribute telling no prologue/epilogue. */
kono
parents:
diff changeset
109 { "naked", 0, 0, false, false, false, NULL, false },
kono
parents:
diff changeset
110
kono
parents:
diff changeset
111 /* The last attribute spec is set to be NULL. */
kono
parents:
diff changeset
112 { NULL, 0, 0, false, false, false, NULL, false }
kono
parents:
diff changeset
113 };
kono
parents:
diff changeset
114
kono
parents:
diff changeset
115
kono
parents:
diff changeset
116 /* ------------------------------------------------------------------------ */
kono
parents:
diff changeset
117
kono
parents:
diff changeset
118 /* PART 2: Auxiliary static function definitions. */
kono
parents:
diff changeset
119
kono
parents:
diff changeset
120 /* Function to save and restore machine-specific function data. */
kono
parents:
diff changeset
121 static struct machine_function *
kono
parents:
diff changeset
122 nds32_init_machine_status (void)
kono
parents:
diff changeset
123 {
kono
parents:
diff changeset
124 struct machine_function *machine;
kono
parents:
diff changeset
125 machine = ggc_cleared_alloc<machine_function> ();
kono
parents:
diff changeset
126
kono
parents:
diff changeset
127 /* Initially assume this function needs prologue/epilogue. */
kono
parents:
diff changeset
128 machine->naked_p = 0;
kono
parents:
diff changeset
129
kono
parents:
diff changeset
130 /* Initially assume this function does NOT use fp_as_gp optimization. */
kono
parents:
diff changeset
131 machine->fp_as_gp_p = 0;
kono
parents:
diff changeset
132
kono
parents:
diff changeset
133 return machine;
kono
parents:
diff changeset
134 }
kono
parents:
diff changeset
135
kono
parents:
diff changeset
136 /* Function to compute stack frame size and
kono
parents:
diff changeset
137 store into cfun->machine structure. */
kono
parents:
diff changeset
138 static void
kono
parents:
diff changeset
139 nds32_compute_stack_frame (void)
kono
parents:
diff changeset
140 {
kono
parents:
diff changeset
141 int r;
kono
parents:
diff changeset
142 int block_size;
kono
parents:
diff changeset
143
kono
parents:
diff changeset
144 /* Because nds32_compute_stack_frame() will be called from different place,
kono
parents:
diff changeset
145 everytime we enter this function, we have to assume this function
kono
parents:
diff changeset
146 needs prologue/epilogue. */
kono
parents:
diff changeset
147 cfun->machine->naked_p = 0;
kono
parents:
diff changeset
148
kono
parents:
diff changeset
149 /* Get variadic arguments size to prepare pretend arguments and
kono
parents:
diff changeset
150 we will push them into stack at prologue by ourself. */
kono
parents:
diff changeset
151 cfun->machine->va_args_size = crtl->args.pretend_args_size;
kono
parents:
diff changeset
152 if (cfun->machine->va_args_size != 0)
kono
parents:
diff changeset
153 {
kono
parents:
diff changeset
154 cfun->machine->va_args_first_regno
kono
parents:
diff changeset
155 = NDS32_GPR_ARG_FIRST_REGNUM
kono
parents:
diff changeset
156 + NDS32_MAX_GPR_REGS_FOR_ARGS
kono
parents:
diff changeset
157 - (crtl->args.pretend_args_size / UNITS_PER_WORD);
kono
parents:
diff changeset
158 cfun->machine->va_args_last_regno
kono
parents:
diff changeset
159 = NDS32_GPR_ARG_FIRST_REGNUM + NDS32_MAX_GPR_REGS_FOR_ARGS - 1;
kono
parents:
diff changeset
160 }
kono
parents:
diff changeset
161 else
kono
parents:
diff changeset
162 {
kono
parents:
diff changeset
163 cfun->machine->va_args_first_regno = SP_REGNUM;
kono
parents:
diff changeset
164 cfun->machine->va_args_last_regno = SP_REGNUM;
kono
parents:
diff changeset
165 }
kono
parents:
diff changeset
166
kono
parents:
diff changeset
167 /* Important: We need to make sure that varargs area is 8-byte alignment. */
kono
parents:
diff changeset
168 block_size = cfun->machine->va_args_size;
kono
parents:
diff changeset
169 if (!NDS32_DOUBLE_WORD_ALIGN_P (block_size))
kono
parents:
diff changeset
170 {
kono
parents:
diff changeset
171 cfun->machine->va_args_area_padding_bytes
kono
parents:
diff changeset
172 = NDS32_ROUND_UP_DOUBLE_WORD (block_size) - block_size;
kono
parents:
diff changeset
173 }
kono
parents:
diff changeset
174
kono
parents:
diff changeset
175 /* Get local variables, incoming variables, and temporary variables size.
kono
parents:
diff changeset
176 Note that we need to make sure it is 8-byte alignment because
kono
parents:
diff changeset
177 there may be no padding bytes if we are using LRA. */
kono
parents:
diff changeset
178 cfun->machine->local_size = NDS32_ROUND_UP_DOUBLE_WORD (get_frame_size ());
kono
parents:
diff changeset
179
kono
parents:
diff changeset
180 /* Get outgoing arguments size. */
kono
parents:
diff changeset
181 cfun->machine->out_args_size = crtl->outgoing_args_size;
kono
parents:
diff changeset
182
kono
parents:
diff changeset
183 /* If $fp value is required to be saved on stack, it needs 4 bytes space.
kono
parents:
diff changeset
184 Check whether $fp is ever live. */
kono
parents:
diff changeset
185 cfun->machine->fp_size = (df_regs_ever_live_p (FP_REGNUM)) ? 4 : 0;
kono
parents:
diff changeset
186
kono
parents:
diff changeset
187 /* If $gp value is required to be saved on stack, it needs 4 bytes space.
kono
parents:
diff changeset
188 Check whether we are using PIC code genration. */
kono
parents:
diff changeset
189 cfun->machine->gp_size = (flag_pic) ? 4 : 0;
kono
parents:
diff changeset
190
kono
parents:
diff changeset
191 /* If $lp value is required to be saved on stack, it needs 4 bytes space.
kono
parents:
diff changeset
192 Check whether $lp is ever live. */
kono
parents:
diff changeset
193 cfun->machine->lp_size = (df_regs_ever_live_p (LP_REGNUM)) ? 4 : 0;
kono
parents:
diff changeset
194
kono
parents:
diff changeset
195 /* Initially there is no padding bytes. */
kono
parents:
diff changeset
196 cfun->machine->callee_saved_area_gpr_padding_bytes = 0;
kono
parents:
diff changeset
197
kono
parents:
diff changeset
198 /* Calculate the bytes of saving callee-saved registers on stack. */
kono
parents:
diff changeset
199 cfun->machine->callee_saved_gpr_regs_size = 0;
kono
parents:
diff changeset
200 cfun->machine->callee_saved_first_gpr_regno = SP_REGNUM;
kono
parents:
diff changeset
201 cfun->machine->callee_saved_last_gpr_regno = SP_REGNUM;
kono
parents:
diff changeset
202 /* Currently, there is no need to check $r28~$r31
kono
parents:
diff changeset
203 because we will save them in another way. */
kono
parents:
diff changeset
204 for (r = 0; r < 28; r++)
kono
parents:
diff changeset
205 {
kono
parents:
diff changeset
206 if (NDS32_REQUIRED_CALLEE_SAVED_P (r))
kono
parents:
diff changeset
207 {
kono
parents:
diff changeset
208 /* Mark the first required callee-saved register
kono
parents:
diff changeset
209 (only need to set it once).
kono
parents:
diff changeset
210 If first regno == SP_REGNUM, we can tell that
kono
parents:
diff changeset
211 it is the first time to be here. */
kono
parents:
diff changeset
212 if (cfun->machine->callee_saved_first_gpr_regno == SP_REGNUM)
kono
parents:
diff changeset
213 cfun->machine->callee_saved_first_gpr_regno = r;
kono
parents:
diff changeset
214 /* Mark the last required callee-saved register. */
kono
parents:
diff changeset
215 cfun->machine->callee_saved_last_gpr_regno = r;
kono
parents:
diff changeset
216 }
kono
parents:
diff changeset
217 }
kono
parents:
diff changeset
218
kono
parents:
diff changeset
219 /* Check if this function can omit prologue/epilogue code fragment.
kono
parents:
diff changeset
220 If there is 'naked' attribute in this function,
kono
parents:
diff changeset
221 we can set 'naked_p' flag to indicate that
kono
parents:
diff changeset
222 we do not have to generate prologue/epilogue.
kono
parents:
diff changeset
223 Or, if all the following conditions succeed,
kono
parents:
diff changeset
224 we can set this function 'naked_p' as well:
kono
parents:
diff changeset
225 condition 1: first_regno == last_regno == SP_REGNUM,
kono
parents:
diff changeset
226 which means we do not have to save
kono
parents:
diff changeset
227 any callee-saved registers.
kono
parents:
diff changeset
228 condition 2: Both $lp and $fp are NOT live in this function,
kono
parents:
diff changeset
229 which means we do not need to save them and there
kono
parents:
diff changeset
230 is no outgoing size.
kono
parents:
diff changeset
231 condition 3: There is no local_size, which means
kono
parents:
diff changeset
232 we do not need to adjust $sp. */
kono
parents:
diff changeset
233 if (lookup_attribute ("naked", DECL_ATTRIBUTES (current_function_decl))
kono
parents:
diff changeset
234 || (cfun->machine->callee_saved_first_gpr_regno == SP_REGNUM
kono
parents:
diff changeset
235 && cfun->machine->callee_saved_last_gpr_regno == SP_REGNUM
kono
parents:
diff changeset
236 && !df_regs_ever_live_p (FP_REGNUM)
kono
parents:
diff changeset
237 && !df_regs_ever_live_p (LP_REGNUM)
kono
parents:
diff changeset
238 && cfun->machine->local_size == 0))
kono
parents:
diff changeset
239 {
kono
parents:
diff changeset
240 /* Set this function 'naked_p' and other functions can check this flag.
kono
parents:
diff changeset
241 Note that in nds32 port, the 'naked_p = 1' JUST means there is no
kono
parents:
diff changeset
242 callee-saved, local size, and outgoing size.
kono
parents:
diff changeset
243 The varargs space and ret instruction may still present in
kono
parents:
diff changeset
244 the prologue/epilogue expanding. */
kono
parents:
diff changeset
245 cfun->machine->naked_p = 1;
kono
parents:
diff changeset
246
kono
parents:
diff changeset
247 /* No need to save $fp, $gp, and $lp.
kono
parents:
diff changeset
248 We should set these value to be zero
kono
parents:
diff changeset
249 so that nds32_initial_elimination_offset() can work properly. */
kono
parents:
diff changeset
250 cfun->machine->fp_size = 0;
kono
parents:
diff changeset
251 cfun->machine->gp_size = 0;
kono
parents:
diff changeset
252 cfun->machine->lp_size = 0;
kono
parents:
diff changeset
253
kono
parents:
diff changeset
254 /* If stack usage computation is required,
kono
parents:
diff changeset
255 we need to provide the static stack size. */
kono
parents:
diff changeset
256 if (flag_stack_usage_info)
kono
parents:
diff changeset
257 current_function_static_stack_size = 0;
kono
parents:
diff changeset
258
kono
parents:
diff changeset
259 /* No need to do following adjustment, return immediately. */
kono
parents:
diff changeset
260 return;
kono
parents:
diff changeset
261 }
kono
parents:
diff changeset
262
kono
parents:
diff changeset
263 /* Adjustment for v3push instructions:
kono
parents:
diff changeset
264 If we are using v3push (push25/pop25) instructions,
kono
parents:
diff changeset
265 we need to make sure Rb is $r6 and Re is
kono
parents:
diff changeset
266 located on $r6, $r8, $r10, or $r14.
kono
parents:
diff changeset
267 Some results above will be discarded and recomputed.
kono
parents:
diff changeset
268 Note that it is only available under V3/V3M ISA and we
kono
parents:
diff changeset
269 DO NOT setup following stuff for isr or variadic function. */
kono
parents:
diff changeset
270 if (TARGET_V3PUSH
kono
parents:
diff changeset
271 && !nds32_isr_function_p (current_function_decl)
kono
parents:
diff changeset
272 && (cfun->machine->va_args_size == 0))
kono
parents:
diff changeset
273 {
kono
parents:
diff changeset
274 /* Recompute:
kono
parents:
diff changeset
275 cfun->machine->fp_size
kono
parents:
diff changeset
276 cfun->machine->gp_size
kono
parents:
diff changeset
277 cfun->machine->lp_size
kono
parents:
diff changeset
278 cfun->machine->callee_saved_first_gpr_regno
kono
parents:
diff changeset
279 cfun->machine->callee_saved_last_gpr_regno */
kono
parents:
diff changeset
280
kono
parents:
diff changeset
281 /* For v3push instructions, $fp, $gp, and $lp are always saved. */
kono
parents:
diff changeset
282 cfun->machine->fp_size = 4;
kono
parents:
diff changeset
283 cfun->machine->gp_size = 4;
kono
parents:
diff changeset
284 cfun->machine->lp_size = 4;
kono
parents:
diff changeset
285
kono
parents:
diff changeset
286 /* Remember to set Rb = $r6. */
kono
parents:
diff changeset
287 cfun->machine->callee_saved_first_gpr_regno = 6;
kono
parents:
diff changeset
288
kono
parents:
diff changeset
289 if (cfun->machine->callee_saved_last_gpr_regno <= 6)
kono
parents:
diff changeset
290 {
kono
parents:
diff changeset
291 /* Re = $r6 */
kono
parents:
diff changeset
292 cfun->machine->callee_saved_last_gpr_regno = 6;
kono
parents:
diff changeset
293 }
kono
parents:
diff changeset
294 else if (cfun->machine->callee_saved_last_gpr_regno <= 8)
kono
parents:
diff changeset
295 {
kono
parents:
diff changeset
296 /* Re = $r8 */
kono
parents:
diff changeset
297 cfun->machine->callee_saved_last_gpr_regno = 8;
kono
parents:
diff changeset
298 }
kono
parents:
diff changeset
299 else if (cfun->machine->callee_saved_last_gpr_regno <= 10)
kono
parents:
diff changeset
300 {
kono
parents:
diff changeset
301 /* Re = $r10 */
kono
parents:
diff changeset
302 cfun->machine->callee_saved_last_gpr_regno = 10;
kono
parents:
diff changeset
303 }
kono
parents:
diff changeset
304 else if (cfun->machine->callee_saved_last_gpr_regno <= 14)
kono
parents:
diff changeset
305 {
kono
parents:
diff changeset
306 /* Re = $r14 */
kono
parents:
diff changeset
307 cfun->machine->callee_saved_last_gpr_regno = 14;
kono
parents:
diff changeset
308 }
kono
parents:
diff changeset
309 else if (cfun->machine->callee_saved_last_gpr_regno == SP_REGNUM)
kono
parents:
diff changeset
310 {
kono
parents:
diff changeset
311 /* If last_regno is SP_REGNUM, which means
kono
parents:
diff changeset
312 it is never changed, so set it to Re = $r6. */
kono
parents:
diff changeset
313 cfun->machine->callee_saved_last_gpr_regno = 6;
kono
parents:
diff changeset
314 }
kono
parents:
diff changeset
315 else
kono
parents:
diff changeset
316 {
kono
parents:
diff changeset
317 /* The program flow should not go here. */
kono
parents:
diff changeset
318 gcc_unreachable ();
kono
parents:
diff changeset
319 }
kono
parents:
diff changeset
320 }
kono
parents:
diff changeset
321
kono
parents:
diff changeset
322 /* We have correctly set callee_saved_first_gpr_regno
kono
parents:
diff changeset
323 and callee_saved_last_gpr_regno.
kono
parents:
diff changeset
324 Initially, the callee_saved_gpr_regs_size is supposed to be 0.
kono
parents:
diff changeset
325 As long as callee_saved_last_gpr_regno is not SP_REGNUM,
kono
parents:
diff changeset
326 we can update callee_saved_gpr_regs_size with new size. */
kono
parents:
diff changeset
327 if (cfun->machine->callee_saved_last_gpr_regno != SP_REGNUM)
kono
parents:
diff changeset
328 {
kono
parents:
diff changeset
329 /* Compute pushed size of callee-saved registers. */
kono
parents:
diff changeset
330 cfun->machine->callee_saved_gpr_regs_size
kono
parents:
diff changeset
331 = 4 * (cfun->machine->callee_saved_last_gpr_regno
kono
parents:
diff changeset
332 - cfun->machine->callee_saved_first_gpr_regno
kono
parents:
diff changeset
333 + 1);
kono
parents:
diff changeset
334 }
kono
parents:
diff changeset
335
kono
parents:
diff changeset
336 /* Important: We need to make sure that
kono
parents:
diff changeset
337 (fp_size + gp_size + lp_size + callee_saved_gpr_regs_size)
kono
parents:
diff changeset
338 is 8-byte alignment.
kono
parents:
diff changeset
339 If it is not, calculate the padding bytes. */
kono
parents:
diff changeset
340 block_size = cfun->machine->fp_size
kono
parents:
diff changeset
341 + cfun->machine->gp_size
kono
parents:
diff changeset
342 + cfun->machine->lp_size
kono
parents:
diff changeset
343 + cfun->machine->callee_saved_gpr_regs_size;
kono
parents:
diff changeset
344 if (!NDS32_DOUBLE_WORD_ALIGN_P (block_size))
kono
parents:
diff changeset
345 {
kono
parents:
diff changeset
346 cfun->machine->callee_saved_area_gpr_padding_bytes
kono
parents:
diff changeset
347 = NDS32_ROUND_UP_DOUBLE_WORD (block_size) - block_size;
kono
parents:
diff changeset
348 }
kono
parents:
diff changeset
349
kono
parents:
diff changeset
350 /* If stack usage computation is required,
kono
parents:
diff changeset
351 we need to provide the static stack size. */
kono
parents:
diff changeset
352 if (flag_stack_usage_info)
kono
parents:
diff changeset
353 {
kono
parents:
diff changeset
354 current_function_static_stack_size
kono
parents:
diff changeset
355 = NDS32_ROUND_UP_DOUBLE_WORD (block_size)
kono
parents:
diff changeset
356 + cfun->machine->local_size
kono
parents:
diff changeset
357 + cfun->machine->out_args_size;
kono
parents:
diff changeset
358 }
kono
parents:
diff changeset
359 }
kono
parents:
diff changeset
360
kono
parents:
diff changeset
361 /* Function to create a parallel rtx pattern
kono
parents:
diff changeset
362 which presents stack push multiple behavior.
kono
parents:
diff changeset
363 The overall concept are:
kono
parents:
diff changeset
364 "push registers to memory",
kono
parents:
diff changeset
365 "adjust stack pointer". */
kono
parents:
diff changeset
366 static void
kono
parents:
diff changeset
367 nds32_emit_stack_push_multiple (rtx Rb, rtx Re, rtx En4, bool vaarg_p)
kono
parents:
diff changeset
368 {
kono
parents:
diff changeset
369 int regno;
kono
parents:
diff changeset
370 int extra_count;
kono
parents:
diff changeset
371 int num_use_regs;
kono
parents:
diff changeset
372 int par_index;
kono
parents:
diff changeset
373 int offset;
kono
parents:
diff changeset
374 int save_fp, save_gp, save_lp;
kono
parents:
diff changeset
375
kono
parents:
diff changeset
376 rtx reg;
kono
parents:
diff changeset
377 rtx mem;
kono
parents:
diff changeset
378 rtx push_rtx;
kono
parents:
diff changeset
379 rtx adjust_sp_rtx;
kono
parents:
diff changeset
380 rtx parallel_insn;
kono
parents:
diff changeset
381 rtx dwarf;
kono
parents:
diff changeset
382
kono
parents:
diff changeset
383 /* We need to provide a customized rtx which contains
kono
parents:
diff changeset
384 necessary information for data analysis,
kono
parents:
diff changeset
385 so we create a parallel rtx like this:
kono
parents:
diff changeset
386 (parallel [(set (mem (plus (reg:SI SP_REGNUM) (const_int -32)))
kono
parents:
diff changeset
387 (reg:SI Rb))
kono
parents:
diff changeset
388 (set (mem (plus (reg:SI SP_REGNUM) (const_int -28)))
kono
parents:
diff changeset
389 (reg:SI Rb+1))
kono
parents:
diff changeset
390 ...
kono
parents:
diff changeset
391 (set (mem (plus (reg:SI SP_REGNUM) (const_int -16)))
kono
parents:
diff changeset
392 (reg:SI Re))
kono
parents:
diff changeset
393 (set (mem (plus (reg:SI SP_REGNUM) (const_int -12)))
kono
parents:
diff changeset
394 (reg:SI FP_REGNUM))
kono
parents:
diff changeset
395 (set (mem (plus (reg:SI SP_REGNUM) (const_int -8)))
kono
parents:
diff changeset
396 (reg:SI GP_REGNUM))
kono
parents:
diff changeset
397 (set (mem (plus (reg:SI SP_REGNUM) (const_int -4)))
kono
parents:
diff changeset
398 (reg:SI LP_REGNUM))
kono
parents:
diff changeset
399 (set (reg:SI SP_REGNUM)
kono
parents:
diff changeset
400 (plus (reg:SI SP_REGNUM) (const_int -32)))]) */
kono
parents:
diff changeset
401
kono
parents:
diff changeset
402 /* Determine whether we need to save $fp, $gp, or $lp. */
kono
parents:
diff changeset
403 save_fp = INTVAL (En4) & 0x8;
kono
parents:
diff changeset
404 save_gp = INTVAL (En4) & 0x4;
kono
parents:
diff changeset
405 save_lp = INTVAL (En4) & 0x2;
kono
parents:
diff changeset
406
kono
parents:
diff changeset
407 /* Calculate the number of registers that will be pushed. */
kono
parents:
diff changeset
408 extra_count = 0;
kono
parents:
diff changeset
409 if (save_fp)
kono
parents:
diff changeset
410 extra_count++;
kono
parents:
diff changeset
411 if (save_gp)
kono
parents:
diff changeset
412 extra_count++;
kono
parents:
diff changeset
413 if (save_lp)
kono
parents:
diff changeset
414 extra_count++;
kono
parents:
diff changeset
415 /* Note that Rb and Re may be SP_REGNUM. DO NOT count it in. */
kono
parents:
diff changeset
416 if (REGNO (Rb) == SP_REGNUM && REGNO (Re) == SP_REGNUM)
kono
parents:
diff changeset
417 num_use_regs = extra_count;
kono
parents:
diff changeset
418 else
kono
parents:
diff changeset
419 num_use_regs = REGNO (Re) - REGNO (Rb) + 1 + extra_count;
kono
parents:
diff changeset
420
kono
parents:
diff changeset
421 /* In addition to used registers,
kono
parents:
diff changeset
422 we need one more space for (set sp sp-x) rtx. */
kono
parents:
diff changeset
423 parallel_insn = gen_rtx_PARALLEL (VOIDmode,
kono
parents:
diff changeset
424 rtvec_alloc (num_use_regs + 1));
kono
parents:
diff changeset
425 par_index = 0;
kono
parents:
diff changeset
426
kono
parents:
diff changeset
427 /* Initialize offset and start to create push behavior. */
kono
parents:
diff changeset
428 offset = -(num_use_regs * 4);
kono
parents:
diff changeset
429
kono
parents:
diff changeset
430 /* Create (set mem regX) from Rb, Rb+1 up to Re. */
kono
parents:
diff changeset
431 for (regno = REGNO (Rb); regno <= (int) REGNO (Re); regno++)
kono
parents:
diff changeset
432 {
kono
parents:
diff changeset
433 /* Rb and Re may be SP_REGNUM.
kono
parents:
diff changeset
434 We need to break this loop immediately. */
kono
parents:
diff changeset
435 if (regno == SP_REGNUM)
kono
parents:
diff changeset
436 break;
kono
parents:
diff changeset
437
kono
parents:
diff changeset
438 reg = gen_rtx_REG (SImode, regno);
kono
parents:
diff changeset
439 mem = gen_frame_mem (SImode, plus_constant (Pmode,
kono
parents:
diff changeset
440 stack_pointer_rtx,
kono
parents:
diff changeset
441 offset));
kono
parents:
diff changeset
442 push_rtx = gen_rtx_SET (mem, reg);
kono
parents:
diff changeset
443 XVECEXP (parallel_insn, 0, par_index) = push_rtx;
kono
parents:
diff changeset
444 RTX_FRAME_RELATED_P (push_rtx) = 1;
kono
parents:
diff changeset
445 offset = offset + 4;
kono
parents:
diff changeset
446 par_index++;
kono
parents:
diff changeset
447 }
kono
parents:
diff changeset
448
kono
parents:
diff changeset
449 /* Create (set mem fp), (set mem gp), and (set mem lp) if necessary. */
kono
parents:
diff changeset
450 if (save_fp)
kono
parents:
diff changeset
451 {
kono
parents:
diff changeset
452 reg = gen_rtx_REG (SImode, FP_REGNUM);
kono
parents:
diff changeset
453 mem = gen_frame_mem (SImode, plus_constant (Pmode,
kono
parents:
diff changeset
454 stack_pointer_rtx,
kono
parents:
diff changeset
455 offset));
kono
parents:
diff changeset
456 push_rtx = gen_rtx_SET (mem, reg);
kono
parents:
diff changeset
457 XVECEXP (parallel_insn, 0, par_index) = push_rtx;
kono
parents:
diff changeset
458 RTX_FRAME_RELATED_P (push_rtx) = 1;
kono
parents:
diff changeset
459 offset = offset + 4;
kono
parents:
diff changeset
460 par_index++;
kono
parents:
diff changeset
461 }
kono
parents:
diff changeset
462 if (save_gp)
kono
parents:
diff changeset
463 {
kono
parents:
diff changeset
464 reg = gen_rtx_REG (SImode, GP_REGNUM);
kono
parents:
diff changeset
465 mem = gen_frame_mem (SImode, plus_constant (Pmode,
kono
parents:
diff changeset
466 stack_pointer_rtx,
kono
parents:
diff changeset
467 offset));
kono
parents:
diff changeset
468 push_rtx = gen_rtx_SET (mem, reg);
kono
parents:
diff changeset
469 XVECEXP (parallel_insn, 0, par_index) = push_rtx;
kono
parents:
diff changeset
470 RTX_FRAME_RELATED_P (push_rtx) = 1;
kono
parents:
diff changeset
471 offset = offset + 4;
kono
parents:
diff changeset
472 par_index++;
kono
parents:
diff changeset
473 }
kono
parents:
diff changeset
474 if (save_lp)
kono
parents:
diff changeset
475 {
kono
parents:
diff changeset
476 reg = gen_rtx_REG (SImode, LP_REGNUM);
kono
parents:
diff changeset
477 mem = gen_frame_mem (SImode, plus_constant (Pmode,
kono
parents:
diff changeset
478 stack_pointer_rtx,
kono
parents:
diff changeset
479 offset));
kono
parents:
diff changeset
480 push_rtx = gen_rtx_SET (mem, reg);
kono
parents:
diff changeset
481 XVECEXP (parallel_insn, 0, par_index) = push_rtx;
kono
parents:
diff changeset
482 RTX_FRAME_RELATED_P (push_rtx) = 1;
kono
parents:
diff changeset
483 offset = offset + 4;
kono
parents:
diff changeset
484 par_index++;
kono
parents:
diff changeset
485 }
kono
parents:
diff changeset
486
kono
parents:
diff changeset
487 /* Create (set sp sp-x). */
kono
parents:
diff changeset
488
kono
parents:
diff changeset
489 /* We need to re-calculate the offset value again for adjustment. */
kono
parents:
diff changeset
490 offset = -(num_use_regs * 4);
kono
parents:
diff changeset
491 adjust_sp_rtx
kono
parents:
diff changeset
492 = gen_rtx_SET (stack_pointer_rtx,
kono
parents:
diff changeset
493 plus_constant (Pmode, stack_pointer_rtx, offset));
kono
parents:
diff changeset
494 XVECEXP (parallel_insn, 0, par_index) = adjust_sp_rtx;
kono
parents:
diff changeset
495 RTX_FRAME_RELATED_P (adjust_sp_rtx) = 1;
kono
parents:
diff changeset
496
kono
parents:
diff changeset
497 parallel_insn = emit_insn (parallel_insn);
kono
parents:
diff changeset
498
kono
parents:
diff changeset
499 /* The insn rtx 'parallel_insn' will change frame layout.
kono
parents:
diff changeset
500 We need to use RTX_FRAME_RELATED_P so that GCC is able to
kono
parents:
diff changeset
501 generate CFI (Call Frame Information) stuff. */
kono
parents:
diff changeset
502 RTX_FRAME_RELATED_P (parallel_insn) = 1;
kono
parents:
diff changeset
503
kono
parents:
diff changeset
504 /* Don't use GCC's logic for CFI info if we are generate a push for VAARG
kono
parents:
diff changeset
505 since we will not restore those register at epilogue. */
kono
parents:
diff changeset
506 if (vaarg_p)
kono
parents:
diff changeset
507 {
kono
parents:
diff changeset
508 dwarf = alloc_reg_note (REG_CFA_ADJUST_CFA,
kono
parents:
diff changeset
509 copy_rtx (adjust_sp_rtx), NULL_RTX);
kono
parents:
diff changeset
510 REG_NOTES (parallel_insn) = dwarf;
kono
parents:
diff changeset
511 }
kono
parents:
diff changeset
512 }
kono
parents:
diff changeset
513
kono
parents:
diff changeset
514 /* Function to create a parallel rtx pattern
kono
parents:
diff changeset
515 which presents stack pop multiple behavior.
kono
parents:
diff changeset
516 The overall concept are:
kono
parents:
diff changeset
517 "pop registers from memory",
kono
parents:
diff changeset
518 "adjust stack pointer". */
kono
parents:
diff changeset
519 static void
kono
parents:
diff changeset
520 nds32_emit_stack_pop_multiple (rtx Rb, rtx Re, rtx En4)
kono
parents:
diff changeset
521 {
kono
parents:
diff changeset
522 int regno;
kono
parents:
diff changeset
523 int extra_count;
kono
parents:
diff changeset
524 int num_use_regs;
kono
parents:
diff changeset
525 int par_index;
kono
parents:
diff changeset
526 int offset;
kono
parents:
diff changeset
527 int save_fp, save_gp, save_lp;
kono
parents:
diff changeset
528
kono
parents:
diff changeset
529 rtx reg;
kono
parents:
diff changeset
530 rtx mem;
kono
parents:
diff changeset
531 rtx pop_rtx;
kono
parents:
diff changeset
532 rtx adjust_sp_rtx;
kono
parents:
diff changeset
533 rtx parallel_insn;
kono
parents:
diff changeset
534 rtx dwarf = NULL_RTX;
kono
parents:
diff changeset
535
kono
parents:
diff changeset
536 /* We need to provide a customized rtx which contains
kono
parents:
diff changeset
537 necessary information for data analysis,
kono
parents:
diff changeset
538 so we create a parallel rtx like this:
kono
parents:
diff changeset
539 (parallel [(set (reg:SI Rb)
kono
parents:
diff changeset
540 (mem (reg:SI SP_REGNUM)))
kono
parents:
diff changeset
541 (set (reg:SI Rb+1)
kono
parents:
diff changeset
542 (mem (plus (reg:SI SP_REGNUM) (const_int 4))))
kono
parents:
diff changeset
543 ...
kono
parents:
diff changeset
544 (set (reg:SI Re)
kono
parents:
diff changeset
545 (mem (plus (reg:SI SP_REGNUM) (const_int 16))))
kono
parents:
diff changeset
546 (set (reg:SI FP_REGNUM)
kono
parents:
diff changeset
547 (mem (plus (reg:SI SP_REGNUM) (const_int 20))))
kono
parents:
diff changeset
548 (set (reg:SI GP_REGNUM)
kono
parents:
diff changeset
549 (mem (plus (reg:SI SP_REGNUM) (const_int 24))))
kono
parents:
diff changeset
550 (set (reg:SI LP_REGNUM)
kono
parents:
diff changeset
551 (mem (plus (reg:SI SP_REGNUM) (const_int 28))))
kono
parents:
diff changeset
552 (set (reg:SI SP_REGNUM)
kono
parents:
diff changeset
553 (plus (reg:SI SP_REGNUM) (const_int 32)))]) */
kono
parents:
diff changeset
554
kono
parents:
diff changeset
555 /* Determine whether we need to restore $fp, $gp, or $lp. */
kono
parents:
diff changeset
556 save_fp = INTVAL (En4) & 0x8;
kono
parents:
diff changeset
557 save_gp = INTVAL (En4) & 0x4;
kono
parents:
diff changeset
558 save_lp = INTVAL (En4) & 0x2;
kono
parents:
diff changeset
559
kono
parents:
diff changeset
560 /* Calculate the number of registers that will be poped. */
kono
parents:
diff changeset
561 extra_count = 0;
kono
parents:
diff changeset
562 if (save_fp)
kono
parents:
diff changeset
563 extra_count++;
kono
parents:
diff changeset
564 if (save_gp)
kono
parents:
diff changeset
565 extra_count++;
kono
parents:
diff changeset
566 if (save_lp)
kono
parents:
diff changeset
567 extra_count++;
kono
parents:
diff changeset
568 /* Note that Rb and Re may be SP_REGNUM. DO NOT count it in. */
kono
parents:
diff changeset
569 if (REGNO (Rb) == SP_REGNUM && REGNO (Re) == SP_REGNUM)
kono
parents:
diff changeset
570 num_use_regs = extra_count;
kono
parents:
diff changeset
571 else
kono
parents:
diff changeset
572 num_use_regs = REGNO (Re) - REGNO (Rb) + 1 + extra_count;
kono
parents:
diff changeset
573
kono
parents:
diff changeset
574 /* In addition to used registers,
kono
parents:
diff changeset
575 we need one more space for (set sp sp+x) rtx. */
kono
parents:
diff changeset
576 parallel_insn = gen_rtx_PARALLEL (VOIDmode,
kono
parents:
diff changeset
577 rtvec_alloc (num_use_regs + 1));
kono
parents:
diff changeset
578 par_index = 0;
kono
parents:
diff changeset
579
kono
parents:
diff changeset
580 /* Initialize offset and start to create pop behavior. */
kono
parents:
diff changeset
581 offset = 0;
kono
parents:
diff changeset
582
kono
parents:
diff changeset
583 /* Create (set regX mem) from Rb, Rb+1 up to Re. */
kono
parents:
diff changeset
584 for (regno = REGNO (Rb); regno <= (int) REGNO (Re); regno++)
kono
parents:
diff changeset
585 {
kono
parents:
diff changeset
586 /* Rb and Re may be SP_REGNUM.
kono
parents:
diff changeset
587 We need to break this loop immediately. */
kono
parents:
diff changeset
588 if (regno == SP_REGNUM)
kono
parents:
diff changeset
589 break;
kono
parents:
diff changeset
590
kono
parents:
diff changeset
591 reg = gen_rtx_REG (SImode, regno);
kono
parents:
diff changeset
592 mem = gen_frame_mem (SImode, plus_constant (Pmode,
kono
parents:
diff changeset
593 stack_pointer_rtx,
kono
parents:
diff changeset
594 offset));
kono
parents:
diff changeset
595 pop_rtx = gen_rtx_SET (reg, mem);
kono
parents:
diff changeset
596 XVECEXP (parallel_insn, 0, par_index) = pop_rtx;
kono
parents:
diff changeset
597 RTX_FRAME_RELATED_P (pop_rtx) = 1;
kono
parents:
diff changeset
598 offset = offset + 4;
kono
parents:
diff changeset
599 par_index++;
kono
parents:
diff changeset
600
kono
parents:
diff changeset
601 dwarf = alloc_reg_note (REG_CFA_RESTORE, reg, dwarf);
kono
parents:
diff changeset
602 }
kono
parents:
diff changeset
603
kono
parents:
diff changeset
604 /* Create (set fp mem), (set gp mem), and (set lp mem) if necessary. */
kono
parents:
diff changeset
605 if (save_fp)
kono
parents:
diff changeset
606 {
kono
parents:
diff changeset
607 reg = gen_rtx_REG (SImode, FP_REGNUM);
kono
parents:
diff changeset
608 mem = gen_frame_mem (SImode, plus_constant (Pmode,
kono
parents:
diff changeset
609 stack_pointer_rtx,
kono
parents:
diff changeset
610 offset));
kono
parents:
diff changeset
611 pop_rtx = gen_rtx_SET (reg, mem);
kono
parents:
diff changeset
612 XVECEXP (parallel_insn, 0, par_index) = pop_rtx;
kono
parents:
diff changeset
613 RTX_FRAME_RELATED_P (pop_rtx) = 1;
kono
parents:
diff changeset
614 offset = offset + 4;
kono
parents:
diff changeset
615 par_index++;
kono
parents:
diff changeset
616
kono
parents:
diff changeset
617 dwarf = alloc_reg_note (REG_CFA_RESTORE, reg, dwarf);
kono
parents:
diff changeset
618 }
kono
parents:
diff changeset
619 if (save_gp)
kono
parents:
diff changeset
620 {
kono
parents:
diff changeset
621 reg = gen_rtx_REG (SImode, GP_REGNUM);
kono
parents:
diff changeset
622 mem = gen_frame_mem (SImode, plus_constant (Pmode,
kono
parents:
diff changeset
623 stack_pointer_rtx,
kono
parents:
diff changeset
624 offset));
kono
parents:
diff changeset
625 pop_rtx = gen_rtx_SET (reg, mem);
kono
parents:
diff changeset
626 XVECEXP (parallel_insn, 0, par_index) = pop_rtx;
kono
parents:
diff changeset
627 RTX_FRAME_RELATED_P (pop_rtx) = 1;
kono
parents:
diff changeset
628 offset = offset + 4;
kono
parents:
diff changeset
629 par_index++;
kono
parents:
diff changeset
630
kono
parents:
diff changeset
631 dwarf = alloc_reg_note (REG_CFA_RESTORE, reg, dwarf);
kono
parents:
diff changeset
632 }
kono
parents:
diff changeset
633 if (save_lp)
kono
parents:
diff changeset
634 {
kono
parents:
diff changeset
635 reg = gen_rtx_REG (SImode, LP_REGNUM);
kono
parents:
diff changeset
636 mem = gen_frame_mem (SImode, plus_constant (Pmode,
kono
parents:
diff changeset
637 stack_pointer_rtx,
kono
parents:
diff changeset
638 offset));
kono
parents:
diff changeset
639 pop_rtx = gen_rtx_SET (reg, mem);
kono
parents:
diff changeset
640 XVECEXP (parallel_insn, 0, par_index) = pop_rtx;
kono
parents:
diff changeset
641 RTX_FRAME_RELATED_P (pop_rtx) = 1;
kono
parents:
diff changeset
642 offset = offset + 4;
kono
parents:
diff changeset
643 par_index++;
kono
parents:
diff changeset
644
kono
parents:
diff changeset
645 dwarf = alloc_reg_note (REG_CFA_RESTORE, reg, dwarf);
kono
parents:
diff changeset
646 }
kono
parents:
diff changeset
647
kono
parents:
diff changeset
648 /* Create (set sp sp+x). */
kono
parents:
diff changeset
649
kono
parents:
diff changeset
650 /* The offset value is already in place. No need to re-calculate it. */
kono
parents:
diff changeset
651 adjust_sp_rtx
kono
parents:
diff changeset
652 = gen_rtx_SET (stack_pointer_rtx,
kono
parents:
diff changeset
653 plus_constant (Pmode, stack_pointer_rtx, offset));
kono
parents:
diff changeset
654 XVECEXP (parallel_insn, 0, par_index) = adjust_sp_rtx;
kono
parents:
diff changeset
655
kono
parents:
diff changeset
656 /* Tell gcc we adjust SP in this insn. */
kono
parents:
diff changeset
657 dwarf = alloc_reg_note (REG_CFA_ADJUST_CFA, copy_rtx (adjust_sp_rtx), dwarf);
kono
parents:
diff changeset
658
kono
parents:
diff changeset
659 parallel_insn = emit_insn (parallel_insn);
kono
parents:
diff changeset
660
kono
parents:
diff changeset
661 /* The insn rtx 'parallel_insn' will change frame layout.
kono
parents:
diff changeset
662 We need to use RTX_FRAME_RELATED_P so that GCC is able to
kono
parents:
diff changeset
663 generate CFI (Call Frame Information) stuff. */
kono
parents:
diff changeset
664 RTX_FRAME_RELATED_P (parallel_insn) = 1;
kono
parents:
diff changeset
665
kono
parents:
diff changeset
666 /* Add CFI info by manual. */
kono
parents:
diff changeset
667 REG_NOTES (parallel_insn) = dwarf;
kono
parents:
diff changeset
668 }
kono
parents:
diff changeset
669
kono
parents:
diff changeset
670 /* Function to create a parallel rtx pattern
kono
parents:
diff changeset
671 which presents stack v3push behavior.
kono
parents:
diff changeset
672 The overall concept are:
kono
parents:
diff changeset
673 "push registers to memory",
kono
parents:
diff changeset
674 "adjust stack pointer". */
kono
parents:
diff changeset
675 static void
kono
parents:
diff changeset
676 nds32_emit_stack_v3push (rtx Rb,
kono
parents:
diff changeset
677 rtx Re,
kono
parents:
diff changeset
678 rtx En4 ATTRIBUTE_UNUSED,
kono
parents:
diff changeset
679 rtx imm8u)
kono
parents:
diff changeset
680 {
kono
parents:
diff changeset
681 int regno;
kono
parents:
diff changeset
682 int num_use_regs;
kono
parents:
diff changeset
683 int par_index;
kono
parents:
diff changeset
684 int offset;
kono
parents:
diff changeset
685
kono
parents:
diff changeset
686 rtx reg;
kono
parents:
diff changeset
687 rtx mem;
kono
parents:
diff changeset
688 rtx push_rtx;
kono
parents:
diff changeset
689 rtx adjust_sp_rtx;
kono
parents:
diff changeset
690 rtx parallel_insn;
kono
parents:
diff changeset
691
kono
parents:
diff changeset
692 /* We need to provide a customized rtx which contains
kono
parents:
diff changeset
693 necessary information for data analysis,
kono
parents:
diff changeset
694 so we create a parallel rtx like this:
kono
parents:
diff changeset
695 (parallel [(set (mem (plus (reg:SI SP_REGNUM) (const_int -32)))
kono
parents:
diff changeset
696 (reg:SI Rb))
kono
parents:
diff changeset
697 (set (mem (plus (reg:SI SP_REGNUM) (const_int -28)))
kono
parents:
diff changeset
698 (reg:SI Rb+1))
kono
parents:
diff changeset
699 ...
kono
parents:
diff changeset
700 (set (mem (plus (reg:SI SP_REGNUM) (const_int -16)))
kono
parents:
diff changeset
701 (reg:SI Re))
kono
parents:
diff changeset
702 (set (mem (plus (reg:SI SP_REGNUM) (const_int -12)))
kono
parents:
diff changeset
703 (reg:SI FP_REGNUM))
kono
parents:
diff changeset
704 (set (mem (plus (reg:SI SP_REGNUM) (const_int -8)))
kono
parents:
diff changeset
705 (reg:SI GP_REGNUM))
kono
parents:
diff changeset
706 (set (mem (plus (reg:SI SP_REGNUM) (const_int -4)))
kono
parents:
diff changeset
707 (reg:SI LP_REGNUM))
kono
parents:
diff changeset
708 (set (reg:SI SP_REGNUM)
kono
parents:
diff changeset
709 (plus (reg:SI SP_REGNUM) (const_int -32-imm8u)))]) */
kono
parents:
diff changeset
710
kono
parents:
diff changeset
711 /* Calculate the number of registers that will be pushed.
kono
parents:
diff changeset
712 Since $fp, $gp, and $lp is always pushed with v3push instruction,
kono
parents:
diff changeset
713 we need to count these three registers.
kono
parents:
diff changeset
714 Under v3push, Rb is $r6, while Re is $r6, $r8, $r10, or $r14.
kono
parents:
diff changeset
715 So there is no need to worry about Rb=Re=SP_REGNUM case. */
kono
parents:
diff changeset
716 num_use_regs = REGNO (Re) - REGNO (Rb) + 1 + 3;
kono
parents:
diff changeset
717
kono
parents:
diff changeset
718 /* In addition to used registers,
kono
parents:
diff changeset
719 we need one more space for (set sp sp-x-imm8u) rtx. */
kono
parents:
diff changeset
720 parallel_insn = gen_rtx_PARALLEL (VOIDmode,
kono
parents:
diff changeset
721 rtvec_alloc (num_use_regs + 1));
kono
parents:
diff changeset
722 par_index = 0;
kono
parents:
diff changeset
723
kono
parents:
diff changeset
724 /* Initialize offset and start to create push behavior. */
kono
parents:
diff changeset
725 offset = -(num_use_regs * 4);
kono
parents:
diff changeset
726
kono
parents:
diff changeset
727 /* Create (set mem regX) from Rb, Rb+1 up to Re.
kono
parents:
diff changeset
728 Under v3push, Rb is $r6, while Re is $r6, $r8, $r10, or $r14.
kono
parents:
diff changeset
729 So there is no need to worry about Rb=Re=SP_REGNUM case. */
kono
parents:
diff changeset
730 for (regno = REGNO (Rb); regno <= (int) REGNO (Re); regno++)
kono
parents:
diff changeset
731 {
kono
parents:
diff changeset
732 reg = gen_rtx_REG (SImode, regno);
kono
parents:
diff changeset
733 mem = gen_frame_mem (SImode, plus_constant (Pmode,
kono
parents:
diff changeset
734 stack_pointer_rtx,
kono
parents:
diff changeset
735 offset));
kono
parents:
diff changeset
736 push_rtx = gen_rtx_SET (mem, reg);
kono
parents:
diff changeset
737 XVECEXP (parallel_insn, 0, par_index) = push_rtx;
kono
parents:
diff changeset
738 RTX_FRAME_RELATED_P (push_rtx) = 1;
kono
parents:
diff changeset
739 offset = offset + 4;
kono
parents:
diff changeset
740 par_index++;
kono
parents:
diff changeset
741 }
kono
parents:
diff changeset
742
kono
parents:
diff changeset
743 /* Create (set mem fp). */
kono
parents:
diff changeset
744 reg = gen_rtx_REG (SImode, FP_REGNUM);
kono
parents:
diff changeset
745 mem = gen_frame_mem (SImode, plus_constant (Pmode,
kono
parents:
diff changeset
746 stack_pointer_rtx,
kono
parents:
diff changeset
747 offset));
kono
parents:
diff changeset
748 push_rtx = gen_rtx_SET (mem, reg);
kono
parents:
diff changeset
749 XVECEXP (parallel_insn, 0, par_index) = push_rtx;
kono
parents:
diff changeset
750 RTX_FRAME_RELATED_P (push_rtx) = 1;
kono
parents:
diff changeset
751 offset = offset + 4;
kono
parents:
diff changeset
752 par_index++;
kono
parents:
diff changeset
753 /* Create (set mem gp). */
kono
parents:
diff changeset
754 reg = gen_rtx_REG (SImode, GP_REGNUM);
kono
parents:
diff changeset
755 mem = gen_frame_mem (SImode, plus_constant (Pmode,
kono
parents:
diff changeset
756 stack_pointer_rtx,
kono
parents:
diff changeset
757 offset));
kono
parents:
diff changeset
758 push_rtx = gen_rtx_SET (mem, reg);
kono
parents:
diff changeset
759 XVECEXP (parallel_insn, 0, par_index) = push_rtx;
kono
parents:
diff changeset
760 RTX_FRAME_RELATED_P (push_rtx) = 1;
kono
parents:
diff changeset
761 offset = offset + 4;
kono
parents:
diff changeset
762 par_index++;
kono
parents:
diff changeset
763 /* Create (set mem lp). */
kono
parents:
diff changeset
764 reg = gen_rtx_REG (SImode, LP_REGNUM);
kono
parents:
diff changeset
765 mem = gen_frame_mem (SImode, plus_constant (Pmode,
kono
parents:
diff changeset
766 stack_pointer_rtx,
kono
parents:
diff changeset
767 offset));
kono
parents:
diff changeset
768 push_rtx = gen_rtx_SET (mem, reg);
kono
parents:
diff changeset
769 XVECEXP (parallel_insn, 0, par_index) = push_rtx;
kono
parents:
diff changeset
770 RTX_FRAME_RELATED_P (push_rtx) = 1;
kono
parents:
diff changeset
771 offset = offset + 4;
kono
parents:
diff changeset
772 par_index++;
kono
parents:
diff changeset
773
kono
parents:
diff changeset
774 /* Create (set sp sp-x-imm8u). */
kono
parents:
diff changeset
775
kono
parents:
diff changeset
776 /* We need to re-calculate the offset value again for adjustment. */
kono
parents:
diff changeset
777 offset = -(num_use_regs * 4);
kono
parents:
diff changeset
778 adjust_sp_rtx
kono
parents:
diff changeset
779 = gen_rtx_SET (stack_pointer_rtx,
kono
parents:
diff changeset
780 plus_constant (Pmode,
kono
parents:
diff changeset
781 stack_pointer_rtx,
kono
parents:
diff changeset
782 offset - INTVAL (imm8u)));
kono
parents:
diff changeset
783 XVECEXP (parallel_insn, 0, par_index) = adjust_sp_rtx;
kono
parents:
diff changeset
784 RTX_FRAME_RELATED_P (adjust_sp_rtx) = 1;
kono
parents:
diff changeset
785
kono
parents:
diff changeset
786 parallel_insn = emit_insn (parallel_insn);
kono
parents:
diff changeset
787
kono
parents:
diff changeset
788 /* The insn rtx 'parallel_insn' will change frame layout.
kono
parents:
diff changeset
789 We need to use RTX_FRAME_RELATED_P so that GCC is able to
kono
parents:
diff changeset
790 generate CFI (Call Frame Information) stuff. */
kono
parents:
diff changeset
791 RTX_FRAME_RELATED_P (parallel_insn) = 1;
kono
parents:
diff changeset
792 }
kono
parents:
diff changeset
793
kono
parents:
diff changeset
794 /* Function to create a parallel rtx pattern
kono
parents:
diff changeset
795 which presents stack v3pop behavior.
kono
parents:
diff changeset
796 The overall concept are:
kono
parents:
diff changeset
797 "pop registers from memory",
kono
parents:
diff changeset
798 "adjust stack pointer". */
kono
parents:
diff changeset
799 static void
kono
parents:
diff changeset
800 nds32_emit_stack_v3pop (rtx Rb,
kono
parents:
diff changeset
801 rtx Re,
kono
parents:
diff changeset
802 rtx En4 ATTRIBUTE_UNUSED,
kono
parents:
diff changeset
803 rtx imm8u)
kono
parents:
diff changeset
804 {
kono
parents:
diff changeset
805 int regno;
kono
parents:
diff changeset
806 int num_use_regs;
kono
parents:
diff changeset
807 int par_index;
kono
parents:
diff changeset
808 int offset;
kono
parents:
diff changeset
809
kono
parents:
diff changeset
810 rtx reg;
kono
parents:
diff changeset
811 rtx mem;
kono
parents:
diff changeset
812 rtx pop_rtx;
kono
parents:
diff changeset
813 rtx adjust_sp_rtx;
kono
parents:
diff changeset
814 rtx parallel_insn;
kono
parents:
diff changeset
815 rtx dwarf = NULL_RTX;
kono
parents:
diff changeset
816
kono
parents:
diff changeset
817 /* We need to provide a customized rtx which contains
kono
parents:
diff changeset
818 necessary information for data analysis,
kono
parents:
diff changeset
819 so we create a parallel rtx like this:
kono
parents:
diff changeset
820 (parallel [(set (reg:SI Rb)
kono
parents:
diff changeset
821 (mem (reg:SI SP_REGNUM)))
kono
parents:
diff changeset
822 (set (reg:SI Rb+1)
kono
parents:
diff changeset
823 (mem (plus (reg:SI SP_REGNUM) (const_int 4))))
kono
parents:
diff changeset
824 ...
kono
parents:
diff changeset
825 (set (reg:SI Re)
kono
parents:
diff changeset
826 (mem (plus (reg:SI SP_REGNUM) (const_int 16))))
kono
parents:
diff changeset
827 (set (reg:SI FP_REGNUM)
kono
parents:
diff changeset
828 (mem (plus (reg:SI SP_REGNUM) (const_int 20))))
kono
parents:
diff changeset
829 (set (reg:SI GP_REGNUM)
kono
parents:
diff changeset
830 (mem (plus (reg:SI SP_REGNUM) (const_int 24))))
kono
parents:
diff changeset
831 (set (reg:SI LP_REGNUM)
kono
parents:
diff changeset
832 (mem (plus (reg:SI SP_REGNUM) (const_int 28))))
kono
parents:
diff changeset
833 (set (reg:SI SP_REGNUM)
kono
parents:
diff changeset
834 (plus (reg:SI SP_REGNUM) (const_int 32+imm8u)))]) */
kono
parents:
diff changeset
835
kono
parents:
diff changeset
836 /* Calculate the number of registers that will be poped.
kono
parents:
diff changeset
837 Since $fp, $gp, and $lp is always poped with v3pop instruction,
kono
parents:
diff changeset
838 we need to count these three registers.
kono
parents:
diff changeset
839 Under v3push, Rb is $r6, while Re is $r6, $r8, $r10, or $r14.
kono
parents:
diff changeset
840 So there is no need to worry about Rb=Re=SP_REGNUM case. */
kono
parents:
diff changeset
841 num_use_regs = REGNO (Re) - REGNO (Rb) + 1 + 3;
kono
parents:
diff changeset
842
kono
parents:
diff changeset
843 /* In addition to used registers,
kono
parents:
diff changeset
844 we need one more space for (set sp sp+x+imm8u) rtx. */
kono
parents:
diff changeset
845 parallel_insn = gen_rtx_PARALLEL (VOIDmode,
kono
parents:
diff changeset
846 rtvec_alloc (num_use_regs + 1));
kono
parents:
diff changeset
847 par_index = 0;
kono
parents:
diff changeset
848
kono
parents:
diff changeset
849 /* Initialize offset and start to create pop behavior. */
kono
parents:
diff changeset
850 offset = 0;
kono
parents:
diff changeset
851
kono
parents:
diff changeset
852 /* Create (set regX mem) from Rb, Rb+1 up to Re.
kono
parents:
diff changeset
853 Under v3pop, Rb is $r6, while Re is $r6, $r8, $r10, or $r14.
kono
parents:
diff changeset
854 So there is no need to worry about Rb=Re=SP_REGNUM case. */
kono
parents:
diff changeset
855 for (regno = REGNO (Rb); regno <= (int) REGNO (Re); regno++)
kono
parents:
diff changeset
856 {
kono
parents:
diff changeset
857 reg = gen_rtx_REG (SImode, regno);
kono
parents:
diff changeset
858 mem = gen_frame_mem (SImode, plus_constant (Pmode,
kono
parents:
diff changeset
859 stack_pointer_rtx,
kono
parents:
diff changeset
860 offset));
kono
parents:
diff changeset
861 pop_rtx = gen_rtx_SET (reg, mem);
kono
parents:
diff changeset
862 XVECEXP (parallel_insn, 0, par_index) = pop_rtx;
kono
parents:
diff changeset
863 RTX_FRAME_RELATED_P (pop_rtx) = 1;
kono
parents:
diff changeset
864 offset = offset + 4;
kono
parents:
diff changeset
865 par_index++;
kono
parents:
diff changeset
866
kono
parents:
diff changeset
867 dwarf = alloc_reg_note (REG_CFA_RESTORE, reg, dwarf);
kono
parents:
diff changeset
868 }
kono
parents:
diff changeset
869
kono
parents:
diff changeset
870 /* Create (set fp mem). */
kono
parents:
diff changeset
871 reg = gen_rtx_REG (SImode, FP_REGNUM);
kono
parents:
diff changeset
872 mem = gen_frame_mem (SImode, plus_constant (Pmode,
kono
parents:
diff changeset
873 stack_pointer_rtx,
kono
parents:
diff changeset
874 offset));
kono
parents:
diff changeset
875 pop_rtx = gen_rtx_SET (reg, mem);
kono
parents:
diff changeset
876 XVECEXP (parallel_insn, 0, par_index) = pop_rtx;
kono
parents:
diff changeset
877 RTX_FRAME_RELATED_P (pop_rtx) = 1;
kono
parents:
diff changeset
878 offset = offset + 4;
kono
parents:
diff changeset
879 par_index++;
kono
parents:
diff changeset
880 dwarf = alloc_reg_note (REG_CFA_RESTORE, reg, dwarf);
kono
parents:
diff changeset
881
kono
parents:
diff changeset
882 /* Create (set gp mem). */
kono
parents:
diff changeset
883 reg = gen_rtx_REG (SImode, GP_REGNUM);
kono
parents:
diff changeset
884 mem = gen_frame_mem (SImode, plus_constant (Pmode,
kono
parents:
diff changeset
885 stack_pointer_rtx,
kono
parents:
diff changeset
886 offset));
kono
parents:
diff changeset
887 pop_rtx = gen_rtx_SET (reg, mem);
kono
parents:
diff changeset
888 XVECEXP (parallel_insn, 0, par_index) = pop_rtx;
kono
parents:
diff changeset
889 RTX_FRAME_RELATED_P (pop_rtx) = 1;
kono
parents:
diff changeset
890 offset = offset + 4;
kono
parents:
diff changeset
891 par_index++;
kono
parents:
diff changeset
892 dwarf = alloc_reg_note (REG_CFA_RESTORE, reg, dwarf);
kono
parents:
diff changeset
893
kono
parents:
diff changeset
894 /* Create (set lp mem ). */
kono
parents:
diff changeset
895 reg = gen_rtx_REG (SImode, LP_REGNUM);
kono
parents:
diff changeset
896 mem = gen_frame_mem (SImode, plus_constant (Pmode,
kono
parents:
diff changeset
897 stack_pointer_rtx,
kono
parents:
diff changeset
898 offset));
kono
parents:
diff changeset
899 pop_rtx = gen_rtx_SET (reg, mem);
kono
parents:
diff changeset
900 XVECEXP (parallel_insn, 0, par_index) = pop_rtx;
kono
parents:
diff changeset
901 RTX_FRAME_RELATED_P (pop_rtx) = 1;
kono
parents:
diff changeset
902 offset = offset + 4;
kono
parents:
diff changeset
903 par_index++;
kono
parents:
diff changeset
904 dwarf = alloc_reg_note (REG_CFA_RESTORE, reg, dwarf);
kono
parents:
diff changeset
905
kono
parents:
diff changeset
906 /* Create (set sp sp+x+imm8u). */
kono
parents:
diff changeset
907
kono
parents:
diff changeset
908 /* The offset value is already in place. No need to re-calculate it. */
kono
parents:
diff changeset
909 adjust_sp_rtx
kono
parents:
diff changeset
910 = gen_rtx_SET (stack_pointer_rtx,
kono
parents:
diff changeset
911 plus_constant (Pmode,
kono
parents:
diff changeset
912 stack_pointer_rtx,
kono
parents:
diff changeset
913 offset + INTVAL (imm8u)));
kono
parents:
diff changeset
914 XVECEXP (parallel_insn, 0, par_index) = adjust_sp_rtx;
kono
parents:
diff changeset
915
kono
parents:
diff changeset
916 /* Tell gcc we adjust SP in this insn. */
kono
parents:
diff changeset
917 dwarf = alloc_reg_note (REG_CFA_ADJUST_CFA, copy_rtx (adjust_sp_rtx), dwarf);
kono
parents:
diff changeset
918
kono
parents:
diff changeset
919 parallel_insn = emit_insn (parallel_insn);
kono
parents:
diff changeset
920
kono
parents:
diff changeset
921 /* The insn rtx 'parallel_insn' will change frame layout.
kono
parents:
diff changeset
922 We need to use RTX_FRAME_RELATED_P so that GCC is able to
kono
parents:
diff changeset
923 generate CFI (Call Frame Information) stuff. */
kono
parents:
diff changeset
924 RTX_FRAME_RELATED_P (parallel_insn) = 1;
kono
parents:
diff changeset
925
kono
parents:
diff changeset
926 /* Add CFI info by manual. */
kono
parents:
diff changeset
927 REG_NOTES (parallel_insn) = dwarf;
kono
parents:
diff changeset
928 }
kono
parents:
diff changeset
929
kono
parents:
diff changeset
930 /* Function that may creates more instructions
kono
parents:
diff changeset
931 for large value on adjusting stack pointer.
kono
parents:
diff changeset
932
kono
parents:
diff changeset
933 In nds32 target, 'addi' can be used for stack pointer
kono
parents:
diff changeset
934 adjustment in prologue/epilogue stage.
kono
parents:
diff changeset
935 However, sometimes there are too many local variables so that
kono
parents:
diff changeset
936 the adjustment value is not able to be fit in the 'addi' instruction.
kono
parents:
diff changeset
937 One solution is to move value into a register
kono
parents:
diff changeset
938 and then use 'add' instruction.
kono
parents:
diff changeset
939 In practice, we use TA_REGNUM ($r15) to accomplish this purpose.
kono
parents:
diff changeset
940 Also, we need to return zero for sp adjustment so that
kono
parents:
diff changeset
941 proglogue/epilogue knows there is no need to create 'addi' instruction. */
kono
parents:
diff changeset
942 static int
kono
parents:
diff changeset
943 nds32_force_addi_stack_int (int full_value)
kono
parents:
diff changeset
944 {
kono
parents:
diff changeset
945 int adjust_value;
kono
parents:
diff changeset
946
kono
parents:
diff changeset
947 rtx tmp_reg;
kono
parents:
diff changeset
948 rtx sp_adjust_insn;
kono
parents:
diff changeset
949
kono
parents:
diff changeset
950 if (!satisfies_constraint_Is15 (GEN_INT (full_value)))
kono
parents:
diff changeset
951 {
kono
parents:
diff changeset
952 /* The value is not able to fit in single addi instruction.
kono
parents:
diff changeset
953 Create more instructions of moving value into a register
kono
parents:
diff changeset
954 and then add stack pointer with it. */
kono
parents:
diff changeset
955
kono
parents:
diff changeset
956 /* $r15 is going to be temporary register to hold the value. */
kono
parents:
diff changeset
957 tmp_reg = gen_rtx_REG (SImode, TA_REGNUM);
kono
parents:
diff changeset
958
kono
parents:
diff changeset
959 /* Create one more instruction to move value
kono
parents:
diff changeset
960 into the temporary register. */
kono
parents:
diff changeset
961 emit_move_insn (tmp_reg, GEN_INT (full_value));
kono
parents:
diff changeset
962
kono
parents:
diff changeset
963 /* Create new 'add' rtx. */
kono
parents:
diff changeset
964 sp_adjust_insn = gen_addsi3 (stack_pointer_rtx,
kono
parents:
diff changeset
965 stack_pointer_rtx,
kono
parents:
diff changeset
966 tmp_reg);
kono
parents:
diff changeset
967 /* Emit rtx into insn list and receive its transformed insn rtx. */
kono
parents:
diff changeset
968 sp_adjust_insn = emit_insn (sp_adjust_insn);
kono
parents:
diff changeset
969
kono
parents:
diff changeset
970 /* At prologue, we need to tell GCC that this is frame related insn,
kono
parents:
diff changeset
971 so that we can consider this instruction to output debug information.
kono
parents:
diff changeset
972 If full_value is NEGATIVE, it means this function
kono
parents:
diff changeset
973 is invoked by expand_prologue. */
kono
parents:
diff changeset
974 if (full_value < 0)
kono
parents:
diff changeset
975 {
kono
parents:
diff changeset
976 /* Because (tmp_reg <- full_value) may be split into two
kono
parents:
diff changeset
977 rtl patterns, we can not set its RTX_FRAME_RELATED_P.
kono
parents:
diff changeset
978 We need to construct another (sp <- sp + full_value)
kono
parents:
diff changeset
979 and then insert it into sp_adjust_insn's reg note to
kono
parents:
diff changeset
980 represent a frame related expression.
kono
parents:
diff changeset
981 GCC knows how to refer it and output debug information. */
kono
parents:
diff changeset
982
kono
parents:
diff changeset
983 rtx plus_rtx;
kono
parents:
diff changeset
984 rtx set_rtx;
kono
parents:
diff changeset
985
kono
parents:
diff changeset
986 plus_rtx = plus_constant (Pmode, stack_pointer_rtx, full_value);
kono
parents:
diff changeset
987 set_rtx = gen_rtx_SET (stack_pointer_rtx, plus_rtx);
kono
parents:
diff changeset
988 add_reg_note (sp_adjust_insn, REG_FRAME_RELATED_EXPR, set_rtx);
kono
parents:
diff changeset
989
kono
parents:
diff changeset
990 RTX_FRAME_RELATED_P (sp_adjust_insn) = 1;
kono
parents:
diff changeset
991 }
kono
parents:
diff changeset
992
kono
parents:
diff changeset
993 /* We have used alternative way to adjust stack pointer value.
kono
parents:
diff changeset
994 Return zero so that prologue/epilogue
kono
parents:
diff changeset
995 will not generate other instructions. */
kono
parents:
diff changeset
996 return 0;
kono
parents:
diff changeset
997 }
kono
parents:
diff changeset
998 else
kono
parents:
diff changeset
999 {
kono
parents:
diff changeset
1000 /* The value is able to fit in addi instruction.
kono
parents:
diff changeset
1001 However, remember to make it to be positive value
kono
parents:
diff changeset
1002 because we want to return 'adjustment' result. */
kono
parents:
diff changeset
1003 adjust_value = (full_value < 0) ? (-full_value) : (full_value);
kono
parents:
diff changeset
1004
kono
parents:
diff changeset
1005 return adjust_value;
kono
parents:
diff changeset
1006 }
kono
parents:
diff changeset
1007 }
kono
parents:
diff changeset
1008
kono
parents:
diff changeset
1009 /* Return true if MODE/TYPE need double word alignment. */
kono
parents:
diff changeset
1010 static bool
kono
parents:
diff changeset
1011 nds32_needs_double_word_align (machine_mode mode, const_tree type)
kono
parents:
diff changeset
1012 {
kono
parents:
diff changeset
1013 unsigned int align;
kono
parents:
diff changeset
1014
kono
parents:
diff changeset
1015 /* Pick up the alignment according to the mode or type. */
kono
parents:
diff changeset
1016 align = NDS32_MODE_TYPE_ALIGN (mode, type);
kono
parents:
diff changeset
1017
kono
parents:
diff changeset
1018 return (align > PARM_BOUNDARY);
kono
parents:
diff changeset
1019 }
kono
parents:
diff changeset
1020
kono
parents:
diff changeset
1021 /* Return true if FUNC is a naked function. */
kono
parents:
diff changeset
1022 static bool
kono
parents:
diff changeset
1023 nds32_naked_function_p (tree func)
kono
parents:
diff changeset
1024 {
kono
parents:
diff changeset
1025 tree t;
kono
parents:
diff changeset
1026
kono
parents:
diff changeset
1027 if (TREE_CODE (func) != FUNCTION_DECL)
kono
parents:
diff changeset
1028 abort ();
kono
parents:
diff changeset
1029
kono
parents:
diff changeset
1030 t = lookup_attribute ("naked", DECL_ATTRIBUTES (func));
kono
parents:
diff changeset
1031
kono
parents:
diff changeset
1032 return (t != NULL_TREE);
kono
parents:
diff changeset
1033 }
kono
parents:
diff changeset
1034
kono
parents:
diff changeset
1035 /* Function that check if 'X' is a valid address register.
kono
parents:
diff changeset
1036 The variable 'STRICT' is very important to
kono
parents:
diff changeset
1037 make decision for register number.
kono
parents:
diff changeset
1038
kono
parents:
diff changeset
1039 STRICT : true
kono
parents:
diff changeset
1040 => We are in reload pass or after reload pass.
kono
parents:
diff changeset
1041 The register number should be strictly limited in general registers.
kono
parents:
diff changeset
1042
kono
parents:
diff changeset
1043 STRICT : false
kono
parents:
diff changeset
1044 => Before reload pass, we are free to use any register number. */
kono
parents:
diff changeset
1045 static bool
kono
parents:
diff changeset
1046 nds32_address_register_rtx_p (rtx x, bool strict)
kono
parents:
diff changeset
1047 {
kono
parents:
diff changeset
1048 int regno;
kono
parents:
diff changeset
1049
kono
parents:
diff changeset
1050 if (GET_CODE (x) != REG)
kono
parents:
diff changeset
1051 return false;
kono
parents:
diff changeset
1052
kono
parents:
diff changeset
1053 regno = REGNO (x);
kono
parents:
diff changeset
1054
kono
parents:
diff changeset
1055 if (strict)
kono
parents:
diff changeset
1056 return REGNO_OK_FOR_BASE_P (regno);
kono
parents:
diff changeset
1057 else
kono
parents:
diff changeset
1058 return true;
kono
parents:
diff changeset
1059 }
kono
parents:
diff changeset
1060
kono
parents:
diff changeset
1061 /* Function that check if 'INDEX' is valid to be a index rtx for address.
kono
parents:
diff changeset
1062
kono
parents:
diff changeset
1063 OUTER_MODE : Machine mode of outer address rtx.
kono
parents:
diff changeset
1064 INDEX : Check if this rtx is valid to be a index for address.
kono
parents:
diff changeset
1065 STRICT : If it is true, we are in reload pass or after reload pass. */
kono
parents:
diff changeset
1066 static bool
kono
parents:
diff changeset
1067 nds32_legitimate_index_p (machine_mode outer_mode,
kono
parents:
diff changeset
1068 rtx index,
kono
parents:
diff changeset
1069 bool strict)
kono
parents:
diff changeset
1070 {
kono
parents:
diff changeset
1071 int regno;
kono
parents:
diff changeset
1072 rtx op0;
kono
parents:
diff changeset
1073 rtx op1;
kono
parents:
diff changeset
1074
kono
parents:
diff changeset
1075 switch (GET_CODE (index))
kono
parents:
diff changeset
1076 {
kono
parents:
diff changeset
1077 case REG:
kono
parents:
diff changeset
1078 regno = REGNO (index);
kono
parents:
diff changeset
1079 /* If we are in reload pass or after reload pass,
kono
parents:
diff changeset
1080 we need to limit it to general register. */
kono
parents:
diff changeset
1081 if (strict)
kono
parents:
diff changeset
1082 return REGNO_OK_FOR_INDEX_P (regno);
kono
parents:
diff changeset
1083 else
kono
parents:
diff changeset
1084 return true;
kono
parents:
diff changeset
1085
kono
parents:
diff changeset
1086 case CONST_INT:
kono
parents:
diff changeset
1087 /* The alignment of the integer value is determined by 'outer_mode'. */
kono
parents:
diff changeset
1088 if (GET_MODE_SIZE (outer_mode) == 1)
kono
parents:
diff changeset
1089 {
kono
parents:
diff changeset
1090 /* Further check if the value is legal for the 'outer_mode'. */
kono
parents:
diff changeset
1091 if (!satisfies_constraint_Is15 (index))
kono
parents:
diff changeset
1092 return false;
kono
parents:
diff changeset
1093
kono
parents:
diff changeset
1094 /* Pass all test, the value is valid, return true. */
kono
parents:
diff changeset
1095 return true;
kono
parents:
diff changeset
1096 }
kono
parents:
diff changeset
1097 if (GET_MODE_SIZE (outer_mode) == 2
kono
parents:
diff changeset
1098 && NDS32_HALF_WORD_ALIGN_P (INTVAL (index)))
kono
parents:
diff changeset
1099 {
kono
parents:
diff changeset
1100 /* Further check if the value is legal for the 'outer_mode'. */
kono
parents:
diff changeset
1101 if (!satisfies_constraint_Is16 (index))
kono
parents:
diff changeset
1102 return false;
kono
parents:
diff changeset
1103
kono
parents:
diff changeset
1104 /* Pass all test, the value is valid, return true. */
kono
parents:
diff changeset
1105 return true;
kono
parents:
diff changeset
1106 }
kono
parents:
diff changeset
1107 if (GET_MODE_SIZE (outer_mode) == 4
kono
parents:
diff changeset
1108 && NDS32_SINGLE_WORD_ALIGN_P (INTVAL (index)))
kono
parents:
diff changeset
1109 {
kono
parents:
diff changeset
1110 /* Further check if the value is legal for the 'outer_mode'. */
kono
parents:
diff changeset
1111 if (!satisfies_constraint_Is17 (index))
kono
parents:
diff changeset
1112 return false;
kono
parents:
diff changeset
1113
kono
parents:
diff changeset
1114 /* Pass all test, the value is valid, return true. */
kono
parents:
diff changeset
1115 return true;
kono
parents:
diff changeset
1116 }
kono
parents:
diff changeset
1117 if (GET_MODE_SIZE (outer_mode) == 8
kono
parents:
diff changeset
1118 && NDS32_SINGLE_WORD_ALIGN_P (INTVAL (index)))
kono
parents:
diff changeset
1119 {
kono
parents:
diff changeset
1120 /* Further check if the value is legal for the 'outer_mode'. */
kono
parents:
diff changeset
1121 if (!satisfies_constraint_Is17 (gen_int_mode (INTVAL (index) + 4,
kono
parents:
diff changeset
1122 SImode)))
kono
parents:
diff changeset
1123 return false;
kono
parents:
diff changeset
1124
kono
parents:
diff changeset
1125 /* Pass all test, the value is valid, return true. */
kono
parents:
diff changeset
1126 return true;
kono
parents:
diff changeset
1127 }
kono
parents:
diff changeset
1128
kono
parents:
diff changeset
1129 return false;
kono
parents:
diff changeset
1130
kono
parents:
diff changeset
1131 case MULT:
kono
parents:
diff changeset
1132 op0 = XEXP (index, 0);
kono
parents:
diff changeset
1133 op1 = XEXP (index, 1);
kono
parents:
diff changeset
1134
kono
parents:
diff changeset
1135 if (REG_P (op0) && CONST_INT_P (op1))
kono
parents:
diff changeset
1136 {
kono
parents:
diff changeset
1137 int multiplier;
kono
parents:
diff changeset
1138 multiplier = INTVAL (op1);
kono
parents:
diff changeset
1139
kono
parents:
diff changeset
1140 /* We only allow (mult reg const_int_1)
kono
parents:
diff changeset
1141 or (mult reg const_int_2) or (mult reg const_int_4). */
kono
parents:
diff changeset
1142 if (multiplier != 1 && multiplier != 2 && multiplier != 4)
kono
parents:
diff changeset
1143 return false;
kono
parents:
diff changeset
1144
kono
parents:
diff changeset
1145 regno = REGNO (op0);
kono
parents:
diff changeset
1146 /* Limit it in general registers if we are
kono
parents:
diff changeset
1147 in reload pass or after reload pass. */
kono
parents:
diff changeset
1148 if(strict)
kono
parents:
diff changeset
1149 return REGNO_OK_FOR_INDEX_P (regno);
kono
parents:
diff changeset
1150 else
kono
parents:
diff changeset
1151 return true;
kono
parents:
diff changeset
1152 }
kono
parents:
diff changeset
1153
kono
parents:
diff changeset
1154 return false;
kono
parents:
diff changeset
1155
kono
parents:
diff changeset
1156 case ASHIFT:
kono
parents:
diff changeset
1157 op0 = XEXP (index, 0);
kono
parents:
diff changeset
1158 op1 = XEXP (index, 1);
kono
parents:
diff changeset
1159
kono
parents:
diff changeset
1160 if (REG_P (op0) && CONST_INT_P (op1))
kono
parents:
diff changeset
1161 {
kono
parents:
diff changeset
1162 int sv;
kono
parents:
diff changeset
1163 /* op1 is already the sv value for use to do left shift. */
kono
parents:
diff changeset
1164 sv = INTVAL (op1);
kono
parents:
diff changeset
1165
kono
parents:
diff changeset
1166 /* We only allow (ashift reg const_int_0)
kono
parents:
diff changeset
1167 or (ashift reg const_int_1) or (ashift reg const_int_2). */
kono
parents:
diff changeset
1168 if (sv != 0 && sv != 1 && sv !=2)
kono
parents:
diff changeset
1169 return false;
kono
parents:
diff changeset
1170
kono
parents:
diff changeset
1171 regno = REGNO (op0);
kono
parents:
diff changeset
1172 /* Limit it in general registers if we are
kono
parents:
diff changeset
1173 in reload pass or after reload pass. */
kono
parents:
diff changeset
1174 if(strict)
kono
parents:
diff changeset
1175 return REGNO_OK_FOR_INDEX_P (regno);
kono
parents:
diff changeset
1176 else
kono
parents:
diff changeset
1177 return true;
kono
parents:
diff changeset
1178 }
kono
parents:
diff changeset
1179
kono
parents:
diff changeset
1180 return false;
kono
parents:
diff changeset
1181
kono
parents:
diff changeset
1182 default:
kono
parents:
diff changeset
1183 return false;
kono
parents:
diff changeset
1184 }
kono
parents:
diff changeset
1185 }
kono
parents:
diff changeset
1186
kono
parents:
diff changeset
1187 /* ------------------------------------------------------------------------ */
kono
parents:
diff changeset
1188
kono
parents:
diff changeset
1189 /* PART 3: Implement target hook stuff definitions. */
kono
parents:
diff changeset
1190
kono
parents:
diff changeset
1191 /* Register Classes. */
kono
parents:
diff changeset
1192
kono
parents:
diff changeset
1193 static unsigned char
kono
parents:
diff changeset
1194 nds32_class_max_nregs (reg_class_t rclass ATTRIBUTE_UNUSED,
kono
parents:
diff changeset
1195 machine_mode mode)
kono
parents:
diff changeset
1196 {
kono
parents:
diff changeset
1197 /* Return the maximum number of consecutive registers
kono
parents:
diff changeset
1198 needed to represent "mode" in a register of "rclass". */
kono
parents:
diff changeset
1199 return ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD);
kono
parents:
diff changeset
1200 }
kono
parents:
diff changeset
1201
kono
parents:
diff changeset
1202 static int
kono
parents:
diff changeset
1203 nds32_register_priority (int hard_regno)
kono
parents:
diff changeset
1204 {
kono
parents:
diff changeset
1205 /* Encourage to use r0-r7 for LRA when optimize for size. */
kono
parents:
diff changeset
1206 if (optimize_size && hard_regno < 8)
kono
parents:
diff changeset
1207 return 4;
kono
parents:
diff changeset
1208 return 3;
kono
parents:
diff changeset
1209 }
kono
parents:
diff changeset
1210
kono
parents:
diff changeset
1211
kono
parents:
diff changeset
1212 /* Stack Layout and Calling Conventions. */
kono
parents:
diff changeset
1213
kono
parents:
diff changeset
1214 /* There are three kinds of pointer concepts using in GCC compiler:
kono
parents:
diff changeset
1215
kono
parents:
diff changeset
1216 frame pointer: A pointer to the first location of local variables.
kono
parents:
diff changeset
1217 stack pointer: A pointer to the top of a stack frame.
kono
parents:
diff changeset
1218 argument pointer: A pointer to the incoming arguments.
kono
parents:
diff changeset
1219
kono
parents:
diff changeset
1220 In nds32 target calling convention, we are using 8-byte alignment.
kono
parents:
diff changeset
1221 Besides, we would like to have each stack frame of a function includes:
kono
parents:
diff changeset
1222
kono
parents:
diff changeset
1223 [Block A]
kono
parents:
diff changeset
1224 1. previous hard frame pointer
kono
parents:
diff changeset
1225 2. return address
kono
parents:
diff changeset
1226 3. callee-saved registers
kono
parents:
diff changeset
1227 4. <padding bytes> (we will calculte in nds32_compute_stack_frame()
kono
parents:
diff changeset
1228 and save it at
kono
parents:
diff changeset
1229 cfun->machine->callee_saved_area_padding_bytes)
kono
parents:
diff changeset
1230
kono
parents:
diff changeset
1231 [Block B]
kono
parents:
diff changeset
1232 1. local variables
kono
parents:
diff changeset
1233 2. spilling location
kono
parents:
diff changeset
1234 3. <padding bytes> (it will be calculated by GCC itself)
kono
parents:
diff changeset
1235 4. incoming arguments
kono
parents:
diff changeset
1236 5. <padding bytes> (it will be calculated by GCC itself)
kono
parents:
diff changeset
1237
kono
parents:
diff changeset
1238 [Block C]
kono
parents:
diff changeset
1239 1. <padding bytes> (it will be calculated by GCC itself)
kono
parents:
diff changeset
1240 2. outgoing arguments
kono
parents:
diff changeset
1241
kono
parents:
diff changeset
1242 We 'wrap' these blocks together with
kono
parents:
diff changeset
1243 hard frame pointer ($r28) and stack pointer ($r31).
kono
parents:
diff changeset
1244 By applying the basic frame/stack/argument pointers concept,
kono
parents:
diff changeset
1245 the layout of a stack frame shoule be like this:
kono
parents:
diff changeset
1246
kono
parents:
diff changeset
1247 | |
kono
parents:
diff changeset
1248 old stack pointer -> ----
kono
parents:
diff changeset
1249 | | \
kono
parents:
diff changeset
1250 | | saved arguments for
kono
parents:
diff changeset
1251 | | vararg functions
kono
parents:
diff changeset
1252 | | /
kono
parents:
diff changeset
1253 hard frame pointer -> --
kono
parents:
diff changeset
1254 & argument pointer | | \
kono
parents:
diff changeset
1255 | | previous hardware frame pointer
kono
parents:
diff changeset
1256 | | return address
kono
parents:
diff changeset
1257 | | callee-saved registers
kono
parents:
diff changeset
1258 | | /
kono
parents:
diff changeset
1259 frame pointer -> --
kono
parents:
diff changeset
1260 | | \
kono
parents:
diff changeset
1261 | | local variables
kono
parents:
diff changeset
1262 | | and incoming arguments
kono
parents:
diff changeset
1263 | | /
kono
parents:
diff changeset
1264 --
kono
parents:
diff changeset
1265 | | \
kono
parents:
diff changeset
1266 | | outgoing
kono
parents:
diff changeset
1267 | | arguments
kono
parents:
diff changeset
1268 | | /
kono
parents:
diff changeset
1269 stack pointer -> ----
kono
parents:
diff changeset
1270
kono
parents:
diff changeset
1271 $SFP and $AP are used to represent frame pointer and arguments pointer,
kono
parents:
diff changeset
1272 which will be both eliminated as hard frame pointer. */
kono
parents:
diff changeset
1273
kono
parents:
diff changeset
1274 /* -- Eliminating Frame Pointer and Arg Pointer. */
kono
parents:
diff changeset
1275
kono
parents:
diff changeset
1276 static bool
kono
parents:
diff changeset
1277 nds32_can_eliminate (const int from_reg, const int to_reg)
kono
parents:
diff changeset
1278 {
kono
parents:
diff changeset
1279 if (from_reg == ARG_POINTER_REGNUM && to_reg == STACK_POINTER_REGNUM)
kono
parents:
diff changeset
1280 return true;
kono
parents:
diff changeset
1281
kono
parents:
diff changeset
1282 if (from_reg == ARG_POINTER_REGNUM && to_reg == HARD_FRAME_POINTER_REGNUM)
kono
parents:
diff changeset
1283 return true;
kono
parents:
diff changeset
1284
kono
parents:
diff changeset
1285 if (from_reg == FRAME_POINTER_REGNUM && to_reg == STACK_POINTER_REGNUM)
kono
parents:
diff changeset
1286 return true;
kono
parents:
diff changeset
1287
kono
parents:
diff changeset
1288 if (from_reg == FRAME_POINTER_REGNUM && to_reg == HARD_FRAME_POINTER_REGNUM)
kono
parents:
diff changeset
1289 return true;
kono
parents:
diff changeset
1290
kono
parents:
diff changeset
1291 return false;
kono
parents:
diff changeset
1292 }
kono
parents:
diff changeset
1293
kono
parents:
diff changeset
1294 /* -- Passing Arguments in Registers. */
kono
parents:
diff changeset
1295
kono
parents:
diff changeset
1296 static rtx
kono
parents:
diff changeset
1297 nds32_function_arg (cumulative_args_t ca, machine_mode mode,
kono
parents:
diff changeset
1298 const_tree type, bool named)
kono
parents:
diff changeset
1299 {
kono
parents:
diff changeset
1300 unsigned int regno;
kono
parents:
diff changeset
1301 CUMULATIVE_ARGS *cum = get_cumulative_args (ca);
kono
parents:
diff changeset
1302
kono
parents:
diff changeset
1303 /* The last time this hook is called,
kono
parents:
diff changeset
1304 it is called with MODE == VOIDmode. */
kono
parents:
diff changeset
1305 if (mode == VOIDmode)
kono
parents:
diff changeset
1306 return NULL_RTX;
kono
parents:
diff changeset
1307
kono
parents:
diff changeset
1308 /* For nameless arguments, we need to take care it individually. */
kono
parents:
diff changeset
1309 if (!named)
kono
parents:
diff changeset
1310 {
kono
parents:
diff changeset
1311 /* If we are under hard float abi, we have arguments passed on the
kono
parents:
diff changeset
1312 stack and all situation can be handled by GCC itself. */
kono
parents:
diff changeset
1313 if (TARGET_HARD_FLOAT)
kono
parents:
diff changeset
1314 return NULL_RTX;
kono
parents:
diff changeset
1315
kono
parents:
diff changeset
1316 if (NDS32_ARG_PARTIAL_IN_GPR_REG_P (cum->gpr_offset, mode, type))
kono
parents:
diff changeset
1317 {
kono
parents:
diff changeset
1318 /* If we still have enough registers to pass argument, pick up
kono
parents:
diff changeset
1319 next available register number. */
kono
parents:
diff changeset
1320 regno
kono
parents:
diff changeset
1321 = NDS32_AVAILABLE_REGNUM_FOR_GPR_ARG (cum->gpr_offset, mode, type);
kono
parents:
diff changeset
1322 return gen_rtx_REG (mode, regno);
kono
parents:
diff changeset
1323 }
kono
parents:
diff changeset
1324
kono
parents:
diff changeset
1325 /* No register available, return NULL_RTX.
kono
parents:
diff changeset
1326 The compiler will use stack to pass argument instead. */
kono
parents:
diff changeset
1327 return NULL_RTX;
kono
parents:
diff changeset
1328 }
kono
parents:
diff changeset
1329
kono
parents:
diff changeset
1330 /* The following is to handle named argument.
kono
parents:
diff changeset
1331 Note that the strategies of TARGET_HARD_FLOAT and !TARGET_HARD_FLOAT
kono
parents:
diff changeset
1332 are different. */
kono
parents:
diff changeset
1333 if (TARGET_HARD_FLOAT)
kono
parents:
diff changeset
1334 {
kono
parents:
diff changeset
1335 /* Currently we have not implemented hard float yet. */
kono
parents:
diff changeset
1336 gcc_unreachable ();
kono
parents:
diff changeset
1337 }
kono
parents:
diff changeset
1338 else
kono
parents:
diff changeset
1339 {
kono
parents:
diff changeset
1340 /* For !TARGET_HARD_FLOAT calling convention, we always use GPR to pass
kono
parents:
diff changeset
1341 argument. Since we allow to pass argument partially in registers,
kono
parents:
diff changeset
1342 we can just return it if there are still registers available. */
kono
parents:
diff changeset
1343 if (NDS32_ARG_PARTIAL_IN_GPR_REG_P (cum->gpr_offset, mode, type))
kono
parents:
diff changeset
1344 {
kono
parents:
diff changeset
1345 /* Pick up the next available register number. */
kono
parents:
diff changeset
1346 regno
kono
parents:
diff changeset
1347 = NDS32_AVAILABLE_REGNUM_FOR_GPR_ARG (cum->gpr_offset, mode, type);
kono
parents:
diff changeset
1348 return gen_rtx_REG (mode, regno);
kono
parents:
diff changeset
1349 }
kono
parents:
diff changeset
1350
kono
parents:
diff changeset
1351 }
kono
parents:
diff changeset
1352
kono
parents:
diff changeset
1353 /* No register available, return NULL_RTX.
kono
parents:
diff changeset
1354 The compiler will use stack to pass argument instead. */
kono
parents:
diff changeset
1355 return NULL_RTX;
kono
parents:
diff changeset
1356 }
kono
parents:
diff changeset
1357
kono
parents:
diff changeset
1358 static bool
kono
parents:
diff changeset
1359 nds32_must_pass_in_stack (machine_mode mode, const_tree type)
kono
parents:
diff changeset
1360 {
kono
parents:
diff changeset
1361 /* Return true if a type must be passed in memory.
kono
parents:
diff changeset
1362 If it is NOT using hard float abi, small aggregates can be
kono
parents:
diff changeset
1363 passed in a register even we are calling a variadic function.
kono
parents:
diff changeset
1364 So there is no need to take padding into consideration. */
kono
parents:
diff changeset
1365 if (TARGET_HARD_FLOAT)
kono
parents:
diff changeset
1366 return must_pass_in_stack_var_size_or_pad (mode, type);
kono
parents:
diff changeset
1367 else
kono
parents:
diff changeset
1368 return must_pass_in_stack_var_size (mode, type);
kono
parents:
diff changeset
1369 }
kono
parents:
diff changeset
1370
kono
parents:
diff changeset
1371 static int
kono
parents:
diff changeset
1372 nds32_arg_partial_bytes (cumulative_args_t ca, machine_mode mode,
kono
parents:
diff changeset
1373 tree type, bool named ATTRIBUTE_UNUSED)
kono
parents:
diff changeset
1374 {
kono
parents:
diff changeset
1375 /* Returns the number of bytes at the beginning of an argument that
kono
parents:
diff changeset
1376 must be put in registers. The value must be zero for arguments that are
kono
parents:
diff changeset
1377 passed entirely in registers or that are entirely pushed on the stack.
kono
parents:
diff changeset
1378 Besides, TARGET_FUNCTION_ARG for these arguments should return the
kono
parents:
diff changeset
1379 first register to be used by the caller for this argument. */
kono
parents:
diff changeset
1380 unsigned int needed_reg_count;
kono
parents:
diff changeset
1381 unsigned int remaining_reg_count;
kono
parents:
diff changeset
1382 CUMULATIVE_ARGS *cum;
kono
parents:
diff changeset
1383
kono
parents:
diff changeset
1384 cum = get_cumulative_args (ca);
kono
parents:
diff changeset
1385
kono
parents:
diff changeset
1386 /* Under hard float abi, we better have argument entirely passed in
kono
parents:
diff changeset
1387 registers or pushed on the stack so that we can reduce the complexity
kono
parents:
diff changeset
1388 of dealing with cum->gpr_offset and cum->fpr_offset. */
kono
parents:
diff changeset
1389 if (TARGET_HARD_FLOAT)
kono
parents:
diff changeset
1390 return 0;
kono
parents:
diff changeset
1391
kono
parents:
diff changeset
1392 /* If we have already runned out of argument registers, return zero
kono
parents:
diff changeset
1393 so that the argument will be entirely pushed on the stack. */
kono
parents:
diff changeset
1394 if (NDS32_AVAILABLE_REGNUM_FOR_GPR_ARG (cum->gpr_offset, mode, type)
kono
parents:
diff changeset
1395 >= NDS32_GPR_ARG_FIRST_REGNUM + NDS32_MAX_GPR_REGS_FOR_ARGS)
kono
parents:
diff changeset
1396 return 0;
kono
parents:
diff changeset
1397
kono
parents:
diff changeset
1398 /* Calculate how many registers do we need for this argument. */
kono
parents:
diff changeset
1399 needed_reg_count = NDS32_NEED_N_REGS_FOR_ARG (mode, type);
kono
parents:
diff changeset
1400
kono
parents:
diff changeset
1401 /* Calculate how many argument registers have left for passing argument.
kono
parents:
diff changeset
1402 Note that we should count it from next available register number. */
kono
parents:
diff changeset
1403 remaining_reg_count
kono
parents:
diff changeset
1404 = NDS32_MAX_GPR_REGS_FOR_ARGS
kono
parents:
diff changeset
1405 - (NDS32_AVAILABLE_REGNUM_FOR_GPR_ARG (cum->gpr_offset, mode, type)
kono
parents:
diff changeset
1406 - NDS32_GPR_ARG_FIRST_REGNUM);
kono
parents:
diff changeset
1407
kono
parents:
diff changeset
1408 /* Note that we have to return the nubmer of bytes, not registers count. */
kono
parents:
diff changeset
1409 if (needed_reg_count > remaining_reg_count)
kono
parents:
diff changeset
1410 return remaining_reg_count * UNITS_PER_WORD;
kono
parents:
diff changeset
1411
kono
parents:
diff changeset
1412 return 0;
kono
parents:
diff changeset
1413 }
kono
parents:
diff changeset
1414
kono
parents:
diff changeset
1415 static void
kono
parents:
diff changeset
1416 nds32_function_arg_advance (cumulative_args_t ca, machine_mode mode,
kono
parents:
diff changeset
1417 const_tree type, bool named)
kono
parents:
diff changeset
1418 {
kono
parents:
diff changeset
1419 machine_mode sub_mode;
kono
parents:
diff changeset
1420 CUMULATIVE_ARGS *cum = get_cumulative_args (ca);
kono
parents:
diff changeset
1421
kono
parents:
diff changeset
1422 if (named)
kono
parents:
diff changeset
1423 {
kono
parents:
diff changeset
1424 /* We need to further check TYPE and MODE so that we can determine
kono
parents:
diff changeset
1425 which kind of register we shall advance. */
kono
parents:
diff changeset
1426 if (type && TREE_CODE (type) == COMPLEX_TYPE)
kono
parents:
diff changeset
1427 sub_mode = TYPE_MODE (TREE_TYPE (type));
kono
parents:
diff changeset
1428 else
kono
parents:
diff changeset
1429 sub_mode = mode;
kono
parents:
diff changeset
1430
kono
parents:
diff changeset
1431 /* Under hard float abi, we may advance FPR registers. */
kono
parents:
diff changeset
1432 if (TARGET_HARD_FLOAT && GET_MODE_CLASS (sub_mode) == MODE_FLOAT)
kono
parents:
diff changeset
1433 {
kono
parents:
diff changeset
1434 /* Currently we have not implemented hard float yet. */
kono
parents:
diff changeset
1435 gcc_unreachable ();
kono
parents:
diff changeset
1436 }
kono
parents:
diff changeset
1437 else
kono
parents:
diff changeset
1438 {
kono
parents:
diff changeset
1439 cum->gpr_offset
kono
parents:
diff changeset
1440 = NDS32_AVAILABLE_REGNUM_FOR_GPR_ARG (cum->gpr_offset, mode, type)
kono
parents:
diff changeset
1441 - NDS32_GPR_ARG_FIRST_REGNUM
kono
parents:
diff changeset
1442 + NDS32_NEED_N_REGS_FOR_ARG (mode, type);
kono
parents:
diff changeset
1443 }
kono
parents:
diff changeset
1444 }
kono
parents:
diff changeset
1445 else
kono
parents:
diff changeset
1446 {
kono
parents:
diff changeset
1447 /* If this nameless argument is NOT under TARGET_HARD_FLOAT,
kono
parents:
diff changeset
1448 we can advance next register as well so that caller is
kono
parents:
diff changeset
1449 able to pass arguments in registers and callee must be
kono
parents:
diff changeset
1450 in charge of pushing all of them into stack. */
kono
parents:
diff changeset
1451 if (!TARGET_HARD_FLOAT)
kono
parents:
diff changeset
1452 {
kono
parents:
diff changeset
1453 cum->gpr_offset
kono
parents:
diff changeset
1454 = NDS32_AVAILABLE_REGNUM_FOR_GPR_ARG (cum->gpr_offset, mode, type)
kono
parents:
diff changeset
1455 - NDS32_GPR_ARG_FIRST_REGNUM
kono
parents:
diff changeset
1456 + NDS32_NEED_N_REGS_FOR_ARG (mode, type);
kono
parents:
diff changeset
1457 }
kono
parents:
diff changeset
1458 }
kono
parents:
diff changeset
1459 }
kono
parents:
diff changeset
1460
kono
parents:
diff changeset
1461 static unsigned int
kono
parents:
diff changeset
1462 nds32_function_arg_boundary (machine_mode mode, const_tree type)
kono
parents:
diff changeset
1463 {
kono
parents:
diff changeset
1464 return (nds32_needs_double_word_align (mode, type)
kono
parents:
diff changeset
1465 ? NDS32_DOUBLE_WORD_ALIGNMENT
kono
parents:
diff changeset
1466 : PARM_BOUNDARY);
kono
parents:
diff changeset
1467 }
kono
parents:
diff changeset
1468
kono
parents:
diff changeset
1469 /* -- How Scalar Function Values Are Returned. */
kono
parents:
diff changeset
1470
kono
parents:
diff changeset
1471 static rtx
kono
parents:
diff changeset
1472 nds32_function_value (const_tree ret_type,
kono
parents:
diff changeset
1473 const_tree fn_decl_or_type ATTRIBUTE_UNUSED,
kono
parents:
diff changeset
1474 bool outgoing ATTRIBUTE_UNUSED)
kono
parents:
diff changeset
1475 {
kono
parents:
diff changeset
1476 machine_mode mode;
kono
parents:
diff changeset
1477 int unsignedp;
kono
parents:
diff changeset
1478
kono
parents:
diff changeset
1479 mode = TYPE_MODE (ret_type);
kono
parents:
diff changeset
1480 unsignedp = TYPE_UNSIGNED (ret_type);
kono
parents:
diff changeset
1481
kono
parents:
diff changeset
1482 mode = promote_mode (ret_type, mode, &unsignedp);
kono
parents:
diff changeset
1483
kono
parents:
diff changeset
1484 return gen_rtx_REG (mode, NDS32_GPR_RET_FIRST_REGNUM);
kono
parents:
diff changeset
1485 }
kono
parents:
diff changeset
1486
kono
parents:
diff changeset
1487 static rtx
kono
parents:
diff changeset
1488 nds32_libcall_value (machine_mode mode,
kono
parents:
diff changeset
1489 const_rtx fun ATTRIBUTE_UNUSED)
kono
parents:
diff changeset
1490 {
kono
parents:
diff changeset
1491 return gen_rtx_REG (mode, NDS32_GPR_RET_FIRST_REGNUM);
kono
parents:
diff changeset
1492 }
kono
parents:
diff changeset
1493
kono
parents:
diff changeset
1494 static bool
kono
parents:
diff changeset
1495 nds32_function_value_regno_p (const unsigned int regno)
kono
parents:
diff changeset
1496 {
kono
parents:
diff changeset
1497 return (regno == NDS32_GPR_RET_FIRST_REGNUM);
kono
parents:
diff changeset
1498 }
kono
parents:
diff changeset
1499
kono
parents:
diff changeset
1500 /* -- Function Entry and Exit. */
kono
parents:
diff changeset
1501
kono
parents:
diff changeset
1502 /* The content produced from this function
kono
parents:
diff changeset
1503 will be placed before prologue body. */
kono
parents:
diff changeset
1504 static void
kono
parents:
diff changeset
1505 nds32_asm_function_prologue (FILE *file)
kono
parents:
diff changeset
1506 {
kono
parents:
diff changeset
1507 int r;
kono
parents:
diff changeset
1508 const char *func_name;
kono
parents:
diff changeset
1509 tree attrs;
kono
parents:
diff changeset
1510 tree name;
kono
parents:
diff changeset
1511
kono
parents:
diff changeset
1512 /* All stack frame information is supposed to be
kono
parents:
diff changeset
1513 already computed when expanding prologue.
kono
parents:
diff changeset
1514 The result is in cfun->machine.
kono
parents:
diff changeset
1515 DO NOT call nds32_compute_stack_frame() here
kono
parents:
diff changeset
1516 because it may corrupt the essential information. */
kono
parents:
diff changeset
1517
kono
parents:
diff changeset
1518 fprintf (file, "\t! BEGIN PROLOGUE\n");
kono
parents:
diff changeset
1519 fprintf (file, "\t! fp needed: %d\n", frame_pointer_needed);
kono
parents:
diff changeset
1520 fprintf (file, "\t! pretend_args: %d\n", cfun->machine->va_args_size);
kono
parents:
diff changeset
1521 fprintf (file, "\t! local_size: %d\n", cfun->machine->local_size);
kono
parents:
diff changeset
1522 fprintf (file, "\t! out_args_size: %d\n", cfun->machine->out_args_size);
kono
parents:
diff changeset
1523
kono
parents:
diff changeset
1524 /* Use df_regs_ever_live_p() to detect if the register
kono
parents:
diff changeset
1525 is ever used in the current function. */
kono
parents:
diff changeset
1526 fprintf (file, "\t! registers ever_live: ");
kono
parents:
diff changeset
1527 for (r = 0; r < 32; r++)
kono
parents:
diff changeset
1528 {
kono
parents:
diff changeset
1529 if (df_regs_ever_live_p (r))
kono
parents:
diff changeset
1530 fprintf (file, "%s, ", reg_names[r]);
kono
parents:
diff changeset
1531 }
kono
parents:
diff changeset
1532 fputc ('\n', file);
kono
parents:
diff changeset
1533
kono
parents:
diff changeset
1534 /* Display the attributes of this function. */
kono
parents:
diff changeset
1535 fprintf (file, "\t! function attributes: ");
kono
parents:
diff changeset
1536 /* Get the attributes tree list.
kono
parents:
diff changeset
1537 Note that GCC builds attributes list with reverse order. */
kono
parents:
diff changeset
1538 attrs = DECL_ATTRIBUTES (current_function_decl);
kono
parents:
diff changeset
1539
kono
parents:
diff changeset
1540 /* If there is no any attribute, print out "None". */
kono
parents:
diff changeset
1541 if (!attrs)
kono
parents:
diff changeset
1542 fprintf (file, "None");
kono
parents:
diff changeset
1543
kono
parents:
diff changeset
1544 /* If there are some attributes, try if we need to
kono
parents:
diff changeset
1545 construct isr vector information. */
kono
parents:
diff changeset
1546 func_name = IDENTIFIER_POINTER (DECL_NAME (current_function_decl));
kono
parents:
diff changeset
1547 nds32_construct_isr_vectors_information (attrs, func_name);
kono
parents:
diff changeset
1548
kono
parents:
diff changeset
1549 /* Display all attributes of this function. */
kono
parents:
diff changeset
1550 while (attrs)
kono
parents:
diff changeset
1551 {
kono
parents:
diff changeset
1552 name = TREE_PURPOSE (attrs);
kono
parents:
diff changeset
1553 fprintf (file, "%s ", IDENTIFIER_POINTER (name));
kono
parents:
diff changeset
1554
kono
parents:
diff changeset
1555 /* Pick up the next attribute. */
kono
parents:
diff changeset
1556 attrs = TREE_CHAIN (attrs);
kono
parents:
diff changeset
1557 }
kono
parents:
diff changeset
1558 fputc ('\n', file);
kono
parents:
diff changeset
1559 }
kono
parents:
diff changeset
1560
kono
parents:
diff changeset
1561 /* After rtl prologue has been expanded, this function is used. */
kono
parents:
diff changeset
1562 static void
kono
parents:
diff changeset
1563 nds32_asm_function_end_prologue (FILE *file)
kono
parents:
diff changeset
1564 {
kono
parents:
diff changeset
1565 fprintf (file, "\t! END PROLOGUE\n");
kono
parents:
diff changeset
1566
kono
parents:
diff changeset
1567 /* If frame pointer is NOT needed and -mfp-as-gp is issued,
kono
parents:
diff changeset
1568 we can generate special directive: ".omit_fp_begin"
kono
parents:
diff changeset
1569 to guide linker doing fp-as-gp optimization.
kono
parents:
diff changeset
1570 However, for a naked function, which means
kono
parents:
diff changeset
1571 it should not have prologue/epilogue,
kono
parents:
diff changeset
1572 using fp-as-gp still requires saving $fp by push/pop behavior and
kono
parents:
diff changeset
1573 there is no benefit to use fp-as-gp on such small function.
kono
parents:
diff changeset
1574 So we need to make sure this function is NOT naked as well. */
kono
parents:
diff changeset
1575 if (!frame_pointer_needed
kono
parents:
diff changeset
1576 && !cfun->machine->naked_p
kono
parents:
diff changeset
1577 && cfun->machine->fp_as_gp_p)
kono
parents:
diff changeset
1578 {
kono
parents:
diff changeset
1579 fprintf (file, "\t! ----------------------------------------\n");
kono
parents:
diff changeset
1580 fprintf (file, "\t! Guide linker to do "
kono
parents:
diff changeset
1581 "link time optimization: fp-as-gp\n");
kono
parents:
diff changeset
1582 fprintf (file, "\t! We add one more instruction to "
kono
parents:
diff changeset
1583 "initialize $fp near to $gp location.\n");
kono
parents:
diff changeset
1584 fprintf (file, "\t! If linker fails to use fp-as-gp transformation,\n");
kono
parents:
diff changeset
1585 fprintf (file, "\t! this extra instruction should be "
kono
parents:
diff changeset
1586 "eliminated at link stage.\n");
kono
parents:
diff changeset
1587 fprintf (file, "\t.omit_fp_begin\n");
kono
parents:
diff changeset
1588 fprintf (file, "\tla\t$fp,_FP_BASE_\n");
kono
parents:
diff changeset
1589 fprintf (file, "\t! ----------------------------------------\n");
kono
parents:
diff changeset
1590 }
kono
parents:
diff changeset
1591 }
kono
parents:
diff changeset
1592
kono
parents:
diff changeset
1593 /* Before rtl epilogue has been expanded, this function is used. */
kono
parents:
diff changeset
1594 static void
kono
parents:
diff changeset
1595 nds32_asm_function_begin_epilogue (FILE *file)
kono
parents:
diff changeset
1596 {
kono
parents:
diff changeset
1597 /* If frame pointer is NOT needed and -mfp-as-gp is issued,
kono
parents:
diff changeset
1598 we can generate special directive: ".omit_fp_end"
kono
parents:
diff changeset
1599 to claim fp-as-gp optimization range.
kono
parents:
diff changeset
1600 However, for a naked function,
kono
parents:
diff changeset
1601 which means it should not have prologue/epilogue,
kono
parents:
diff changeset
1602 using fp-as-gp still requires saving $fp by push/pop behavior and
kono
parents:
diff changeset
1603 there is no benefit to use fp-as-gp on such small function.
kono
parents:
diff changeset
1604 So we need to make sure this function is NOT naked as well. */
kono
parents:
diff changeset
1605 if (!frame_pointer_needed
kono
parents:
diff changeset
1606 && !cfun->machine->naked_p
kono
parents:
diff changeset
1607 && cfun->machine->fp_as_gp_p)
kono
parents:
diff changeset
1608 {
kono
parents:
diff changeset
1609 fprintf (file, "\t! ----------------------------------------\n");
kono
parents:
diff changeset
1610 fprintf (file, "\t! Claim the range of fp-as-gp "
kono
parents:
diff changeset
1611 "link time optimization\n");
kono
parents:
diff changeset
1612 fprintf (file, "\t.omit_fp_end\n");
kono
parents:
diff changeset
1613 fprintf (file, "\t! ----------------------------------------\n");
kono
parents:
diff changeset
1614 }
kono
parents:
diff changeset
1615
kono
parents:
diff changeset
1616 fprintf (file, "\t! BEGIN EPILOGUE\n");
kono
parents:
diff changeset
1617 }
kono
parents:
diff changeset
1618
kono
parents:
diff changeset
1619 /* The content produced from this function
kono
parents:
diff changeset
1620 will be placed after epilogue body. */
kono
parents:
diff changeset
1621 static void
kono
parents:
diff changeset
1622 nds32_asm_function_epilogue (FILE *file)
kono
parents:
diff changeset
1623 {
kono
parents:
diff changeset
1624 fprintf (file, "\t! END EPILOGUE\n");
kono
parents:
diff changeset
1625 }
kono
parents:
diff changeset
1626
kono
parents:
diff changeset
1627 static void
kono
parents:
diff changeset
1628 nds32_asm_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
kono
parents:
diff changeset
1629 HOST_WIDE_INT delta,
kono
parents:
diff changeset
1630 HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED,
kono
parents:
diff changeset
1631 tree function)
kono
parents:
diff changeset
1632 {
kono
parents:
diff changeset
1633 int this_regno;
kono
parents:
diff changeset
1634
kono
parents:
diff changeset
1635 /* Make sure unwind info is emitted for the thunk if needed. */
kono
parents:
diff changeset
1636 final_start_function (emit_barrier (), file, 1);
kono
parents:
diff changeset
1637
kono
parents:
diff changeset
1638 this_regno = (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function)
kono
parents:
diff changeset
1639 ? 1
kono
parents:
diff changeset
1640 : 0);
kono
parents:
diff changeset
1641
kono
parents:
diff changeset
1642 if (delta != 0)
kono
parents:
diff changeset
1643 {
kono
parents:
diff changeset
1644 if (satisfies_constraint_Is15 (GEN_INT (delta)))
kono
parents:
diff changeset
1645 {
kono
parents:
diff changeset
1646 fprintf (file, "\taddi\t$r%d, $r%d, %ld\n",
kono
parents:
diff changeset
1647 this_regno, this_regno, delta);
kono
parents:
diff changeset
1648 }
kono
parents:
diff changeset
1649 else if (satisfies_constraint_Is20 (GEN_INT (delta)))
kono
parents:
diff changeset
1650 {
kono
parents:
diff changeset
1651 fprintf (file, "\tmovi\t$ta, %ld\n", delta);
kono
parents:
diff changeset
1652 fprintf (file, "\tadd\t$r%d, $r%d, $ta\n", this_regno, this_regno);
kono
parents:
diff changeset
1653 }
kono
parents:
diff changeset
1654 else
kono
parents:
diff changeset
1655 {
kono
parents:
diff changeset
1656 fprintf (file, "\tsethi\t$ta, hi20(%ld)\n", delta);
kono
parents:
diff changeset
1657 fprintf (file, "\tori\t$ta, $ta, lo12(%ld)\n", delta);
kono
parents:
diff changeset
1658 fprintf (file, "\tadd\t$r%d, $r%d, $ta\n", this_regno, this_regno);
kono
parents:
diff changeset
1659 }
kono
parents:
diff changeset
1660 }
kono
parents:
diff changeset
1661
kono
parents:
diff changeset
1662 fprintf (file, "\tb\t");
kono
parents:
diff changeset
1663 assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0));
kono
parents:
diff changeset
1664 fprintf (file, "\n");
kono
parents:
diff changeset
1665
kono
parents:
diff changeset
1666 final_end_function ();
kono
parents:
diff changeset
1667 }
kono
parents:
diff changeset
1668
kono
parents:
diff changeset
1669 /* -- Permitting tail calls. */
kono
parents:
diff changeset
1670
kono
parents:
diff changeset
1671 /* Determine whether we need to enable warning for function return check. */
kono
parents:
diff changeset
1672 static bool
kono
parents:
diff changeset
1673 nds32_warn_func_return (tree decl)
kono
parents:
diff changeset
1674 {
kono
parents:
diff changeset
1675 /* Naked functions are implemented entirely in assembly, including the
kono
parents:
diff changeset
1676 return sequence, so suppress warnings about this. */
kono
parents:
diff changeset
1677 return !nds32_naked_function_p (decl);
kono
parents:
diff changeset
1678 }
kono
parents:
diff changeset
1679
kono
parents:
diff changeset
1680
kono
parents:
diff changeset
1681 /* Implementing the Varargs Macros. */
kono
parents:
diff changeset
1682
kono
parents:
diff changeset
1683 static void
kono
parents:
diff changeset
1684 nds32_setup_incoming_varargs (cumulative_args_t ca,
kono
parents:
diff changeset
1685 machine_mode mode,
kono
parents:
diff changeset
1686 tree type,
kono
parents:
diff changeset
1687 int *pretend_args_size,
kono
parents:
diff changeset
1688 int second_time ATTRIBUTE_UNUSED)
kono
parents:
diff changeset
1689 {
kono
parents:
diff changeset
1690 unsigned int total_args_regs;
kono
parents:
diff changeset
1691 unsigned int num_of_used_regs;
kono
parents:
diff changeset
1692 unsigned int remaining_reg_count;
kono
parents:
diff changeset
1693 CUMULATIVE_ARGS *cum;
kono
parents:
diff changeset
1694
kono
parents:
diff changeset
1695 /* If we are under hard float abi, we do not need to set *pretend_args_size.
kono
parents:
diff changeset
1696 So that all nameless arguments are pushed by caller and all situation
kono
parents:
diff changeset
1697 can be handled by GCC itself. */
kono
parents:
diff changeset
1698 if (TARGET_HARD_FLOAT)
kono
parents:
diff changeset
1699 return;
kono
parents:
diff changeset
1700
kono
parents:
diff changeset
1701 /* We are using NDS32_MAX_GPR_REGS_FOR_ARGS registers,
kono
parents:
diff changeset
1702 counting from NDS32_GPR_ARG_FIRST_REGNUM, for saving incoming arguments.
kono
parents:
diff changeset
1703 However, for nameless(anonymous) arguments, we should push them on the
kono
parents:
diff changeset
1704 stack so that all the nameless arguments appear to have been passed
kono
parents:
diff changeset
1705 consecutively in the memory for accessing. Hence, we need to check and
kono
parents:
diff changeset
1706 exclude the registers that are used for named arguments. */
kono
parents:
diff changeset
1707
kono
parents:
diff changeset
1708 cum = get_cumulative_args (ca);
kono
parents:
diff changeset
1709
kono
parents:
diff changeset
1710 /* The MODE and TYPE describe the last argument.
kono
parents:
diff changeset
1711 We need those information to determine the remaining registers
kono
parents:
diff changeset
1712 for varargs. */
kono
parents:
diff changeset
1713 total_args_regs
kono
parents:
diff changeset
1714 = NDS32_MAX_GPR_REGS_FOR_ARGS + NDS32_GPR_ARG_FIRST_REGNUM;
kono
parents:
diff changeset
1715 num_of_used_regs
kono
parents:
diff changeset
1716 = NDS32_AVAILABLE_REGNUM_FOR_GPR_ARG (cum->gpr_offset, mode, type)
kono
parents:
diff changeset
1717 + NDS32_NEED_N_REGS_FOR_ARG (mode, type);
kono
parents:
diff changeset
1718
kono
parents:
diff changeset
1719 remaining_reg_count = total_args_regs - num_of_used_regs;
kono
parents:
diff changeset
1720 *pretend_args_size = remaining_reg_count * UNITS_PER_WORD;
kono
parents:
diff changeset
1721
kono
parents:
diff changeset
1722 return;
kono
parents:
diff changeset
1723 }
kono
parents:
diff changeset
1724
kono
parents:
diff changeset
1725 static bool
kono
parents:
diff changeset
1726 nds32_strict_argument_naming (cumulative_args_t ca ATTRIBUTE_UNUSED)
kono
parents:
diff changeset
1727 {
kono
parents:
diff changeset
1728 /* If this hook returns true, the named argument of FUNCTION_ARG is always
kono
parents:
diff changeset
1729 true for named arguments, and false for unnamed arguments. */
kono
parents:
diff changeset
1730 return true;
kono
parents:
diff changeset
1731 }
kono
parents:
diff changeset
1732
kono
parents:
diff changeset
1733
kono
parents:
diff changeset
1734 /* Trampolines for Nested Functions. */
kono
parents:
diff changeset
1735
kono
parents:
diff changeset
1736 static void
kono
parents:
diff changeset
1737 nds32_asm_trampoline_template (FILE *f)
kono
parents:
diff changeset
1738 {
kono
parents:
diff changeset
1739 if (TARGET_REDUCED_REGS)
kono
parents:
diff changeset
1740 {
kono
parents:
diff changeset
1741 /* Trampoline is not supported on reduced-set registers yet. */
kono
parents:
diff changeset
1742 sorry ("a nested function is not supported for reduced registers");
kono
parents:
diff changeset
1743 }
kono
parents:
diff changeset
1744 else
kono
parents:
diff changeset
1745 {
kono
parents:
diff changeset
1746 asm_fprintf (f, "\t! Trampoline code template\n");
kono
parents:
diff changeset
1747 asm_fprintf (f, "\t! This code fragment will be copied "
kono
parents:
diff changeset
1748 "into stack on demand\n");
kono
parents:
diff changeset
1749
kono
parents:
diff changeset
1750 asm_fprintf (f, "\tmfusr\t$r16,$pc\n");
kono
parents:
diff changeset
1751 asm_fprintf (f, "\tlwi\t$r15,[$r16 + 20] "
kono
parents:
diff changeset
1752 "! load nested function address\n");
kono
parents:
diff changeset
1753 asm_fprintf (f, "\tlwi\t$r16,[$r16 + 16] "
kono
parents:
diff changeset
1754 "! load chain_value\n");
kono
parents:
diff changeset
1755 asm_fprintf (f, "\tjr\t$r15\n");
kono
parents:
diff changeset
1756 }
kono
parents:
diff changeset
1757
kono
parents:
diff changeset
1758 /* Preserve space ($pc + 16) for saving chain_value,
kono
parents:
diff changeset
1759 nds32_trampoline_init will fill the value in this slot. */
kono
parents:
diff changeset
1760 asm_fprintf (f, "\t! space for saving chain_value\n");
kono
parents:
diff changeset
1761 assemble_aligned_integer (UNITS_PER_WORD, const0_rtx);
kono
parents:
diff changeset
1762
kono
parents:
diff changeset
1763 /* Preserve space ($pc + 20) for saving nested function address,
kono
parents:
diff changeset
1764 nds32_trampoline_init will fill the value in this slot. */
kono
parents:
diff changeset
1765 asm_fprintf (f, "\t! space for saving nested function address\n");
kono
parents:
diff changeset
1766 assemble_aligned_integer (UNITS_PER_WORD, const0_rtx);
kono
parents:
diff changeset
1767 }
kono
parents:
diff changeset
1768
kono
parents:
diff changeset
1769 /* Emit RTL insns to initialize the variable parts of a trampoline. */
kono
parents:
diff changeset
1770 static void
kono
parents:
diff changeset
1771 nds32_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
kono
parents:
diff changeset
1772 {
kono
parents:
diff changeset
1773 int i;
kono
parents:
diff changeset
1774
kono
parents:
diff changeset
1775 /* Nested function address. */
kono
parents:
diff changeset
1776 rtx fnaddr;
kono
parents:
diff changeset
1777 /* The memory rtx that is going to
kono
parents:
diff changeset
1778 be filled with chain_value. */
kono
parents:
diff changeset
1779 rtx chain_value_mem;
kono
parents:
diff changeset
1780 /* The memory rtx that is going to
kono
parents:
diff changeset
1781 be filled with nested function address. */
kono
parents:
diff changeset
1782 rtx nested_func_mem;
kono
parents:
diff changeset
1783
kono
parents:
diff changeset
1784 /* Start address of trampoline code in stack, for doing cache sync. */
kono
parents:
diff changeset
1785 rtx sync_cache_addr;
kono
parents:
diff changeset
1786 /* Temporary register for sync instruction. */
kono
parents:
diff changeset
1787 rtx tmp_reg;
kono
parents:
diff changeset
1788 /* Instruction-cache sync instruction,
kono
parents:
diff changeset
1789 requesting an argument as starting address. */
kono
parents:
diff changeset
1790 rtx isync_insn;
kono
parents:
diff changeset
1791 /* For convenience reason of doing comparison. */
kono
parents:
diff changeset
1792 int tramp_align_in_bytes;
kono
parents:
diff changeset
1793
kono
parents:
diff changeset
1794 /* Trampoline is not supported on reduced-set registers yet. */
kono
parents:
diff changeset
1795 if (TARGET_REDUCED_REGS)
kono
parents:
diff changeset
1796 sorry ("a nested function is not supported for reduced registers");
kono
parents:
diff changeset
1797
kono
parents:
diff changeset
1798 /* STEP 1: Copy trampoline code template into stack,
kono
parents:
diff changeset
1799 fill up essential data into stack. */
kono
parents:
diff changeset
1800
kono
parents:
diff changeset
1801 /* Extract nested function address rtx. */
kono
parents:
diff changeset
1802 fnaddr = XEXP (DECL_RTL (fndecl), 0);
kono
parents:
diff changeset
1803
kono
parents:
diff changeset
1804 /* m_tramp is memory rtx that is going to be filled with trampoline code.
kono
parents:
diff changeset
1805 We have nds32_asm_trampoline_template() to emit template pattern. */
kono
parents:
diff changeset
1806 emit_block_move (m_tramp, assemble_trampoline_template (),
kono
parents:
diff changeset
1807 GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
kono
parents:
diff changeset
1808
kono
parents:
diff changeset
1809 /* After copying trampoline code into stack,
kono
parents:
diff changeset
1810 fill chain_value into stack. */
kono
parents:
diff changeset
1811 chain_value_mem = adjust_address (m_tramp, SImode, 16);
kono
parents:
diff changeset
1812 emit_move_insn (chain_value_mem, chain_value);
kono
parents:
diff changeset
1813 /* After copying trampoline code int stack,
kono
parents:
diff changeset
1814 fill nested function address into stack. */
kono
parents:
diff changeset
1815 nested_func_mem = adjust_address (m_tramp, SImode, 20);
kono
parents:
diff changeset
1816 emit_move_insn (nested_func_mem, fnaddr);
kono
parents:
diff changeset
1817
kono
parents:
diff changeset
1818 /* STEP 2: Sync instruction-cache. */
kono
parents:
diff changeset
1819
kono
parents:
diff changeset
1820 /* We have successfully filled trampoline code into stack.
kono
parents:
diff changeset
1821 However, in order to execute code in stack correctly,
kono
parents:
diff changeset
1822 we must sync instruction cache. */
kono
parents:
diff changeset
1823 sync_cache_addr = XEXP (m_tramp, 0);
kono
parents:
diff changeset
1824 tmp_reg = gen_reg_rtx (SImode);
kono
parents:
diff changeset
1825 isync_insn = gen_unspec_volatile_isync (tmp_reg);
kono
parents:
diff changeset
1826
kono
parents:
diff changeset
1827 /* Because nds32_cache_block_size is in bytes,
kono
parents:
diff changeset
1828 we get trampoline alignment in bytes for convenient comparison. */
kono
parents:
diff changeset
1829 tramp_align_in_bytes = TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT;
kono
parents:
diff changeset
1830
kono
parents:
diff changeset
1831 if (tramp_align_in_bytes >= nds32_cache_block_size
kono
parents:
diff changeset
1832 && (tramp_align_in_bytes % nds32_cache_block_size) == 0)
kono
parents:
diff changeset
1833 {
kono
parents:
diff changeset
1834 /* Under this condition, the starting address of trampoline
kono
parents:
diff changeset
1835 must be aligned to the starting address of each cache block
kono
parents:
diff changeset
1836 and we do not have to worry about cross-boundary issue. */
kono
parents:
diff changeset
1837 for (i = 0;
kono
parents:
diff changeset
1838 i < (TRAMPOLINE_SIZE + nds32_cache_block_size - 1)
kono
parents:
diff changeset
1839 / nds32_cache_block_size;
kono
parents:
diff changeset
1840 i++)
kono
parents:
diff changeset
1841 {
kono
parents:
diff changeset
1842 emit_move_insn (tmp_reg,
kono
parents:
diff changeset
1843 plus_constant (Pmode, sync_cache_addr,
kono
parents:
diff changeset
1844 nds32_cache_block_size * i));
kono
parents:
diff changeset
1845 emit_insn (isync_insn);
kono
parents:
diff changeset
1846 }
kono
parents:
diff changeset
1847 }
kono
parents:
diff changeset
1848 else if (TRAMPOLINE_SIZE > nds32_cache_block_size)
kono
parents:
diff changeset
1849 {
kono
parents:
diff changeset
1850 /* The starting address of trampoline code
kono
parents:
diff changeset
1851 may not be aligned to the cache block,
kono
parents:
diff changeset
1852 so the trampoline code may be across two cache block.
kono
parents:
diff changeset
1853 We need to sync the last element, which is 4-byte size,
kono
parents:
diff changeset
1854 of trampoline template. */
kono
parents:
diff changeset
1855 for (i = 0;
kono
parents:
diff changeset
1856 i < (TRAMPOLINE_SIZE + nds32_cache_block_size - 1)
kono
parents:
diff changeset
1857 / nds32_cache_block_size;
kono
parents:
diff changeset
1858 i++)
kono
parents:
diff changeset
1859 {
kono
parents:
diff changeset
1860 emit_move_insn (tmp_reg,
kono
parents:
diff changeset
1861 plus_constant (Pmode, sync_cache_addr,
kono
parents:
diff changeset
1862 nds32_cache_block_size * i));
kono
parents:
diff changeset
1863 emit_insn (isync_insn);
kono
parents:
diff changeset
1864 }
kono
parents:
diff changeset
1865
kono
parents:
diff changeset
1866 /* The last element of trampoline template is 4-byte size. */
kono
parents:
diff changeset
1867 emit_move_insn (tmp_reg,
kono
parents:
diff changeset
1868 plus_constant (Pmode, sync_cache_addr,
kono
parents:
diff changeset
1869 TRAMPOLINE_SIZE - 4));
kono
parents:
diff changeset
1870 emit_insn (isync_insn);
kono
parents:
diff changeset
1871 }
kono
parents:
diff changeset
1872 else
kono
parents:
diff changeset
1873 {
kono
parents:
diff changeset
1874 /* This is the simplest case.
kono
parents:
diff changeset
1875 Because TRAMPOLINE_SIZE is less than or
kono
parents:
diff changeset
1876 equal to nds32_cache_block_size,
kono
parents:
diff changeset
1877 we can just sync start address and
kono
parents:
diff changeset
1878 the last element of trampoline code. */
kono
parents:
diff changeset
1879
kono
parents:
diff changeset
1880 /* Sync starting address of tampoline code. */
kono
parents:
diff changeset
1881 emit_move_insn (tmp_reg, sync_cache_addr);
kono
parents:
diff changeset
1882 emit_insn (isync_insn);
kono
parents:
diff changeset
1883 /* Sync the last element, which is 4-byte size,
kono
parents:
diff changeset
1884 of trampoline template. */
kono
parents:
diff changeset
1885 emit_move_insn (tmp_reg,
kono
parents:
diff changeset
1886 plus_constant (Pmode, sync_cache_addr,
kono
parents:
diff changeset
1887 TRAMPOLINE_SIZE - 4));
kono
parents:
diff changeset
1888 emit_insn (isync_insn);
kono
parents:
diff changeset
1889 }
kono
parents:
diff changeset
1890
kono
parents:
diff changeset
1891 /* Set instruction serialization barrier
kono
parents:
diff changeset
1892 to guarantee the correct operations. */
kono
parents:
diff changeset
1893 emit_insn (gen_unspec_volatile_isb ());
kono
parents:
diff changeset
1894 }
kono
parents:
diff changeset
1895
kono
parents:
diff changeset
1896
kono
parents:
diff changeset
1897 /* Addressing Modes. */
kono
parents:
diff changeset
1898
kono
parents:
diff changeset
1899 static bool
kono
parents:
diff changeset
1900 nds32_legitimate_address_p (machine_mode mode, rtx x, bool strict)
kono
parents:
diff changeset
1901 {
kono
parents:
diff changeset
1902 /* For (mem:DI addr) or (mem:DF addr) case,
kono
parents:
diff changeset
1903 we only allow 'addr' to be [reg], [symbol_ref],
kono
parents:
diff changeset
1904 [const], or [reg + const_int] pattern. */
kono
parents:
diff changeset
1905 if (mode == DImode || mode == DFmode)
kono
parents:
diff changeset
1906 {
kono
parents:
diff changeset
1907 /* Allow [Reg + const_int] addressing mode. */
kono
parents:
diff changeset
1908 if (GET_CODE (x) == PLUS)
kono
parents:
diff changeset
1909 {
kono
parents:
diff changeset
1910 if (nds32_address_register_rtx_p (XEXP (x, 0), strict)
kono
parents:
diff changeset
1911 && nds32_legitimate_index_p (mode, XEXP (x, 1), strict)
kono
parents:
diff changeset
1912 && CONST_INT_P (XEXP (x, 1)))
kono
parents:
diff changeset
1913 return true;
kono
parents:
diff changeset
1914 else if (nds32_address_register_rtx_p (XEXP (x, 1), strict)
kono
parents:
diff changeset
1915 && nds32_legitimate_index_p (mode, XEXP (x, 0), strict)
kono
parents:
diff changeset
1916 && CONST_INT_P (XEXP (x, 0)))
kono
parents:
diff changeset
1917 return true;
kono
parents:
diff changeset
1918 }
kono
parents:
diff changeset
1919
kono
parents:
diff changeset
1920 /* Now check [reg], [symbol_ref], and [const]. */
kono
parents:
diff changeset
1921 if (GET_CODE (x) != REG
kono
parents:
diff changeset
1922 && GET_CODE (x) != SYMBOL_REF
kono
parents:
diff changeset
1923 && GET_CODE (x) != CONST)
kono
parents:
diff changeset
1924 return false;
kono
parents:
diff changeset
1925 }
kono
parents:
diff changeset
1926
kono
parents:
diff changeset
1927 /* Check if 'x' is a valid address. */
kono
parents:
diff changeset
1928 switch (GET_CODE (x))
kono
parents:
diff changeset
1929 {
kono
parents:
diff changeset
1930 case REG:
kono
parents:
diff changeset
1931 /* (mem (reg A)) => [Ra] */
kono
parents:
diff changeset
1932 return nds32_address_register_rtx_p (x, strict);
kono
parents:
diff changeset
1933
kono
parents:
diff changeset
1934 case SYMBOL_REF:
kono
parents:
diff changeset
1935 /* (mem (symbol_ref A)) => [symbol_ref] */
kono
parents:
diff changeset
1936 /* If -mcmodel=large, the 'symbol_ref' is not a valid address
kono
parents:
diff changeset
1937 during or after LRA/reload phase. */
kono
parents:
diff changeset
1938 if (TARGET_CMODEL_LARGE
kono
parents:
diff changeset
1939 && (reload_completed
kono
parents:
diff changeset
1940 || reload_in_progress
kono
parents:
diff changeset
1941 || lra_in_progress))
kono
parents:
diff changeset
1942 return false;
kono
parents:
diff changeset
1943 /* If -mcmodel=medium and the symbol references to rodata section,
kono
parents:
diff changeset
1944 the 'symbol_ref' is not a valid address during or after
kono
parents:
diff changeset
1945 LRA/reload phase. */
kono
parents:
diff changeset
1946 if (TARGET_CMODEL_MEDIUM
kono
parents:
diff changeset
1947 && NDS32_SYMBOL_REF_RODATA_P (x)
kono
parents:
diff changeset
1948 && (reload_completed
kono
parents:
diff changeset
1949 || reload_in_progress
kono
parents:
diff changeset
1950 || lra_in_progress))
kono
parents:
diff changeset
1951 return false;
kono
parents:
diff changeset
1952
kono
parents:
diff changeset
1953 return true;
kono
parents:
diff changeset
1954
kono
parents:
diff changeset
1955 case CONST:
kono
parents:
diff changeset
1956 /* (mem (const (...)))
kono
parents:
diff changeset
1957 => [ + const_addr ], where const_addr = symbol_ref + const_int */
kono
parents:
diff changeset
1958 if (GET_CODE (XEXP (x, 0)) == PLUS)
kono
parents:
diff changeset
1959 {
kono
parents:
diff changeset
1960 rtx plus_op = XEXP (x, 0);
kono
parents:
diff changeset
1961
kono
parents:
diff changeset
1962 rtx op0 = XEXP (plus_op, 0);
kono
parents:
diff changeset
1963 rtx op1 = XEXP (plus_op, 1);
kono
parents:
diff changeset
1964
kono
parents:
diff changeset
1965 if (GET_CODE (op0) == SYMBOL_REF && CONST_INT_P (op1))
kono
parents:
diff changeset
1966 {
kono
parents:
diff changeset
1967 /* Now we see the [ + const_addr ] pattern, but we need
kono
parents:
diff changeset
1968 some further checking. */
kono
parents:
diff changeset
1969 /* If -mcmodel=large, the 'const_addr' is not a valid address
kono
parents:
diff changeset
1970 during or after LRA/reload phase. */
kono
parents:
diff changeset
1971 if (TARGET_CMODEL_LARGE
kono
parents:
diff changeset
1972 && (reload_completed
kono
parents:
diff changeset
1973 || reload_in_progress
kono
parents:
diff changeset
1974 || lra_in_progress))
kono
parents:
diff changeset
1975 return false;
kono
parents:
diff changeset
1976 /* If -mcmodel=medium and the symbol references to rodata section,
kono
parents:
diff changeset
1977 the 'const_addr' is not a valid address during or after
kono
parents:
diff changeset
1978 LRA/reload phase. */
kono
parents:
diff changeset
1979 if (TARGET_CMODEL_MEDIUM
kono
parents:
diff changeset
1980 && NDS32_SYMBOL_REF_RODATA_P (op0)
kono
parents:
diff changeset
1981 && (reload_completed
kono
parents:
diff changeset
1982 || reload_in_progress
kono
parents:
diff changeset
1983 || lra_in_progress))
kono
parents:
diff changeset
1984 return false;
kono
parents:
diff changeset
1985
kono
parents:
diff changeset
1986 /* At this point we can make sure 'const_addr' is a
kono
parents:
diff changeset
1987 valid address. */
kono
parents:
diff changeset
1988 return true;
kono
parents:
diff changeset
1989 }
kono
parents:
diff changeset
1990 }
kono
parents:
diff changeset
1991
kono
parents:
diff changeset
1992 return false;
kono
parents:
diff changeset
1993
kono
parents:
diff changeset
1994 case POST_MODIFY:
kono
parents:
diff changeset
1995 /* (mem (post_modify (reg) (plus (reg) (reg))))
kono
parents:
diff changeset
1996 => [Ra], Rb */
kono
parents:
diff changeset
1997 /* (mem (post_modify (reg) (plus (reg) (const_int))))
kono
parents:
diff changeset
1998 => [Ra], const_int */
kono
parents:
diff changeset
1999 if (GET_CODE (XEXP (x, 0)) == REG
kono
parents:
diff changeset
2000 && GET_CODE (XEXP (x, 1)) == PLUS)
kono
parents:
diff changeset
2001 {
kono
parents:
diff changeset
2002 rtx plus_op = XEXP (x, 1);
kono
parents:
diff changeset
2003
kono
parents:
diff changeset
2004 rtx op0 = XEXP (plus_op, 0);
kono
parents:
diff changeset
2005 rtx op1 = XEXP (plus_op, 1);
kono
parents:
diff changeset
2006
kono
parents:
diff changeset
2007 if (nds32_address_register_rtx_p (op0, strict)
kono
parents:
diff changeset
2008 && nds32_legitimate_index_p (mode, op1, strict))
kono
parents:
diff changeset
2009 return true;
kono
parents:
diff changeset
2010 else
kono
parents:
diff changeset
2011 return false;
kono
parents:
diff changeset
2012 }
kono
parents:
diff changeset
2013
kono
parents:
diff changeset
2014 return false;
kono
parents:
diff changeset
2015
kono
parents:
diff changeset
2016 case POST_INC:
kono
parents:
diff changeset
2017 case POST_DEC:
kono
parents:
diff changeset
2018 /* (mem (post_inc reg)) => [Ra], 1/2/4 */
kono
parents:
diff changeset
2019 /* (mem (post_dec reg)) => [Ra], -1/-2/-4 */
kono
parents:
diff changeset
2020 /* The 1/2/4 or -1/-2/-4 have been displayed in nds32.md.
kono
parents:
diff changeset
2021 We only need to deal with register Ra. */
kono
parents:
diff changeset
2022 if (nds32_address_register_rtx_p (XEXP (x, 0), strict))
kono
parents:
diff changeset
2023 return true;
kono
parents:
diff changeset
2024 else
kono
parents:
diff changeset
2025 return false;
kono
parents:
diff changeset
2026
kono
parents:
diff changeset
2027 case PLUS:
kono
parents:
diff changeset
2028 /* (mem (plus reg const_int))
kono
parents:
diff changeset
2029 => [Ra + imm] */
kono
parents:
diff changeset
2030 /* (mem (plus reg reg))
kono
parents:
diff changeset
2031 => [Ra + Rb] */
kono
parents:
diff changeset
2032 /* (mem (plus (mult reg const_int) reg))
kono
parents:
diff changeset
2033 => [Ra + Rb << sv] */
kono
parents:
diff changeset
2034 if (nds32_address_register_rtx_p (XEXP (x, 0), strict)
kono
parents:
diff changeset
2035 && nds32_legitimate_index_p (mode, XEXP (x, 1), strict))
kono
parents:
diff changeset
2036 return true;
kono
parents:
diff changeset
2037 else if (nds32_address_register_rtx_p (XEXP (x, 1), strict)
kono
parents:
diff changeset
2038 && nds32_legitimate_index_p (mode, XEXP (x, 0), strict))
kono
parents:
diff changeset
2039 return true;
kono
parents:
diff changeset
2040 else
kono
parents:
diff changeset
2041 return false;
kono
parents:
diff changeset
2042
kono
parents:
diff changeset
2043 case LO_SUM:
kono
parents:
diff changeset
2044 /* (mem (lo_sum (reg) (symbol_ref))) */
kono
parents:
diff changeset
2045 /* (mem (lo_sum (reg) (const))) */
kono
parents:
diff changeset
2046 gcc_assert (REG_P (XEXP (x, 0)));
kono
parents:
diff changeset
2047 if (GET_CODE (XEXP (x, 1)) == SYMBOL_REF
kono
parents:
diff changeset
2048 || GET_CODE (XEXP (x, 1)) == CONST)
kono
parents:
diff changeset
2049 return nds32_legitimate_address_p (mode, XEXP (x, 1), strict);
kono
parents:
diff changeset
2050 else
kono
parents:
diff changeset
2051 return false;
kono
parents:
diff changeset
2052
kono
parents:
diff changeset
2053 default:
kono
parents:
diff changeset
2054 return false;
kono
parents:
diff changeset
2055 }
kono
parents:
diff changeset
2056 }
kono
parents:
diff changeset
2057
kono
parents:
diff changeset
2058
kono
parents:
diff changeset
2059 /* Describing Relative Costs of Operations. */
kono
parents:
diff changeset
2060
kono
parents:
diff changeset
2061 static int
kono
parents:
diff changeset
2062 nds32_register_move_cost (machine_mode mode ATTRIBUTE_UNUSED,
kono
parents:
diff changeset
2063 reg_class_t from,
kono
parents:
diff changeset
2064 reg_class_t to)
kono
parents:
diff changeset
2065 {
kono
parents:
diff changeset
2066 if (from == HIGH_REGS || to == HIGH_REGS)
kono
parents:
diff changeset
2067 return 6;
kono
parents:
diff changeset
2068
kono
parents:
diff changeset
2069 return 2;
kono
parents:
diff changeset
2070 }
kono
parents:
diff changeset
2071
kono
parents:
diff changeset
2072 static int
kono
parents:
diff changeset
2073 nds32_memory_move_cost (machine_mode mode ATTRIBUTE_UNUSED,
kono
parents:
diff changeset
2074 reg_class_t rclass ATTRIBUTE_UNUSED,
kono
parents:
diff changeset
2075 bool in ATTRIBUTE_UNUSED)
kono
parents:
diff changeset
2076 {
kono
parents:
diff changeset
2077 return 8;
kono
parents:
diff changeset
2078 }
kono
parents:
diff changeset
2079
kono
parents:
diff changeset
2080 /* This target hook describes the relative costs of RTL expressions.
kono
parents:
diff changeset
2081 Return 'true' when all subexpressions of x have been processed.
kono
parents:
diff changeset
2082 Return 'false' to sum the costs of sub-rtx, plus cost of this operation.
kono
parents:
diff changeset
2083 Refer to gcc/rtlanal.c for more information. */
kono
parents:
diff changeset
2084 static bool
kono
parents:
diff changeset
2085 nds32_rtx_costs (rtx x,
kono
parents:
diff changeset
2086 machine_mode mode,
kono
parents:
diff changeset
2087 int outer_code,
kono
parents:
diff changeset
2088 int opno,
kono
parents:
diff changeset
2089 int *total,
kono
parents:
diff changeset
2090 bool speed)
kono
parents:
diff changeset
2091 {
kono
parents:
diff changeset
2092 return nds32_rtx_costs_impl (x, mode, outer_code, opno, total, speed);
kono
parents:
diff changeset
2093 }
kono
parents:
diff changeset
2094
kono
parents:
diff changeset
2095 static int
kono
parents:
diff changeset
2096 nds32_address_cost (rtx address,
kono
parents:
diff changeset
2097 machine_mode mode,
kono
parents:
diff changeset
2098 addr_space_t as,
kono
parents:
diff changeset
2099 bool speed)
kono
parents:
diff changeset
2100 {
kono
parents:
diff changeset
2101 return nds32_address_cost_impl (address, mode, as, speed);
kono
parents:
diff changeset
2102 }
kono
parents:
diff changeset
2103
kono
parents:
diff changeset
2104
kono
parents:
diff changeset
2105 /* Dividing the Output into Sections (Texts, Data, . . . ). */
kono
parents:
diff changeset
2106
kono
parents:
diff changeset
2107 /* If references to a symbol or a constant must be treated differently
kono
parents:
diff changeset
2108 depending on something about the variable or function named by the symbol
kono
parents:
diff changeset
2109 (such as what section it is in), we use this hook to store flags
kono
parents:
diff changeset
2110 in symbol_ref rtx. */
kono
parents:
diff changeset
2111 static void
kono
parents:
diff changeset
2112 nds32_encode_section_info (tree decl, rtx rtl, int new_decl_p)
kono
parents:
diff changeset
2113 {
kono
parents:
diff changeset
2114 default_encode_section_info (decl, rtl, new_decl_p);
kono
parents:
diff changeset
2115
kono
parents:
diff changeset
2116 /* For the memory rtx, if it references to rodata section, we can store
kono
parents:
diff changeset
2117 NDS32_SYMBOL_FLAG_RODATA flag into symbol_ref rtx so that the
kono
parents:
diff changeset
2118 nds32_legitimate_address_p() can determine how to treat such symbol_ref
kono
parents:
diff changeset
2119 based on -mcmodel=X and this information. */
kono
parents:
diff changeset
2120 if (MEM_P (rtl) && MEM_READONLY_P (rtl))
kono
parents:
diff changeset
2121 {
kono
parents:
diff changeset
2122 rtx addr = XEXP (rtl, 0);
kono
parents:
diff changeset
2123
kono
parents:
diff changeset
2124 if (GET_CODE (addr) == SYMBOL_REF)
kono
parents:
diff changeset
2125 {
kono
parents:
diff changeset
2126 /* For (mem (symbol_ref X)) case. */
kono
parents:
diff changeset
2127 SYMBOL_REF_FLAGS (addr) |= NDS32_SYMBOL_FLAG_RODATA;
kono
parents:
diff changeset
2128 }
kono
parents:
diff changeset
2129 else if (GET_CODE (addr) == CONST
kono
parents:
diff changeset
2130 && GET_CODE (XEXP (addr, 0)) == PLUS)
kono
parents:
diff changeset
2131 {
kono
parents:
diff changeset
2132 /* For (mem (const (plus (symbol_ref X) (const_int N)))) case. */
kono
parents:
diff changeset
2133 rtx plus_op = XEXP (addr, 0);
kono
parents:
diff changeset
2134 rtx op0 = XEXP (plus_op, 0);
kono
parents:
diff changeset
2135 rtx op1 = XEXP (plus_op, 1);
kono
parents:
diff changeset
2136
kono
parents:
diff changeset
2137 if (GET_CODE (op0) == SYMBOL_REF && CONST_INT_P (op1))
kono
parents:
diff changeset
2138 SYMBOL_REF_FLAGS (op0) |= NDS32_SYMBOL_FLAG_RODATA;
kono
parents:
diff changeset
2139 }
kono
parents:
diff changeset
2140 }
kono
parents:
diff changeset
2141 }
kono
parents:
diff changeset
2142
kono
parents:
diff changeset
2143
kono
parents:
diff changeset
2144 /* Defining the Output Assembler Language. */
kono
parents:
diff changeset
2145
kono
parents:
diff changeset
2146 /* -- The Overall Framework of an Assembler File. */
kono
parents:
diff changeset
2147
kono
parents:
diff changeset
2148 static void
kono
parents:
diff changeset
2149 nds32_asm_file_start (void)
kono
parents:
diff changeset
2150 {
kono
parents:
diff changeset
2151 default_file_start ();
kono
parents:
diff changeset
2152
kono
parents:
diff changeset
2153 /* Tell assembler which ABI we are using. */
kono
parents:
diff changeset
2154 fprintf (asm_out_file, "\t! ABI version\n");
kono
parents:
diff changeset
2155 fprintf (asm_out_file, "\t.abi_2\n");
kono
parents:
diff changeset
2156
kono
parents:
diff changeset
2157 /* Tell assembler that this asm code is generated by compiler. */
kono
parents:
diff changeset
2158 fprintf (asm_out_file, "\t! This asm file is generated by compiler\n");
kono
parents:
diff changeset
2159 fprintf (asm_out_file, "\t.flag\tverbatim\n");
kono
parents:
diff changeset
2160 /* Give assembler the size of each vector for interrupt handler. */
kono
parents:
diff changeset
2161 fprintf (asm_out_file, "\t! This vector size directive is required "
kono
parents:
diff changeset
2162 "for checking inconsistency on interrupt handler\n");
kono
parents:
diff changeset
2163 fprintf (asm_out_file, "\t.vec_size\t%d\n", nds32_isr_vector_size);
kono
parents:
diff changeset
2164
kono
parents:
diff changeset
2165 fprintf (asm_out_file, "\t! ------------------------------------\n");
kono
parents:
diff changeset
2166
kono
parents:
diff changeset
2167 if (TARGET_ISA_V2)
kono
parents:
diff changeset
2168 fprintf (asm_out_file, "\t! ISA family\t\t: %s\n", "V2");
kono
parents:
diff changeset
2169 if (TARGET_ISA_V3)
kono
parents:
diff changeset
2170 fprintf (asm_out_file, "\t! ISA family\t\t: %s\n", "V3");
kono
parents:
diff changeset
2171 if (TARGET_ISA_V3M)
kono
parents:
diff changeset
2172 fprintf (asm_out_file, "\t! ISA family\t\t: %s\n", "V3M");
kono
parents:
diff changeset
2173
kono
parents:
diff changeset
2174 if (TARGET_CMODEL_SMALL)
kono
parents:
diff changeset
2175 fprintf (asm_out_file, "\t! Code model\t\t: %s\n", "SMALL");
kono
parents:
diff changeset
2176 if (TARGET_CMODEL_MEDIUM)
kono
parents:
diff changeset
2177 fprintf (asm_out_file, "\t! Code model\t\t: %s\n", "MEDIUM");
kono
parents:
diff changeset
2178 if (TARGET_CMODEL_LARGE)
kono
parents:
diff changeset
2179 fprintf (asm_out_file, "\t! Code model\t\t: %s\n", "LARGE");
kono
parents:
diff changeset
2180
kono
parents:
diff changeset
2181 fprintf (asm_out_file, "\t! Endian setting\t: %s\n",
kono
parents:
diff changeset
2182 ((TARGET_BIG_ENDIAN) ? "big-endian"
kono
parents:
diff changeset
2183 : "little-endian"));
kono
parents:
diff changeset
2184
kono
parents:
diff changeset
2185 fprintf (asm_out_file, "\t! ------------------------------------\n");
kono
parents:
diff changeset
2186
kono
parents:
diff changeset
2187 fprintf (asm_out_file, "\t! Use conditional move\t\t: %s\n",
kono
parents:
diff changeset
2188 ((TARGET_CMOV) ? "Yes"
kono
parents:
diff changeset
2189 : "No"));
kono
parents:
diff changeset
2190 fprintf (asm_out_file, "\t! Use performance extension\t: %s\n",
kono
parents:
diff changeset
2191 ((TARGET_PERF_EXT) ? "Yes"
kono
parents:
diff changeset
2192 : "No"));
kono
parents:
diff changeset
2193
kono
parents:
diff changeset
2194 fprintf (asm_out_file, "\t! ------------------------------------\n");
kono
parents:
diff changeset
2195
kono
parents:
diff changeset
2196 fprintf (asm_out_file, "\t! V3PUSH instructions\t: %s\n",
kono
parents:
diff changeset
2197 ((TARGET_V3PUSH) ? "Yes"
kono
parents:
diff changeset
2198 : "No"));
kono
parents:
diff changeset
2199 fprintf (asm_out_file, "\t! 16-bit instructions\t: %s\n",
kono
parents:
diff changeset
2200 ((TARGET_16_BIT) ? "Yes"
kono
parents:
diff changeset
2201 : "No"));
kono
parents:
diff changeset
2202 fprintf (asm_out_file, "\t! Reduced registers set\t: %s\n",
kono
parents:
diff changeset
2203 ((TARGET_REDUCED_REGS) ? "Yes"
kono
parents:
diff changeset
2204 : "No"));
kono
parents:
diff changeset
2205
kono
parents:
diff changeset
2206 fprintf (asm_out_file, "\t! ------------------------------------\n");
kono
parents:
diff changeset
2207
kono
parents:
diff changeset
2208 if (optimize_size)
kono
parents:
diff changeset
2209 fprintf (asm_out_file, "\t! Optimization level\t: -Os\n");
kono
parents:
diff changeset
2210 else
kono
parents:
diff changeset
2211 fprintf (asm_out_file, "\t! Optimization level\t: -O%d\n", optimize);
kono
parents:
diff changeset
2212
kono
parents:
diff changeset
2213 fprintf (asm_out_file, "\t! ------------------------------------\n");
kono
parents:
diff changeset
2214
kono
parents:
diff changeset
2215 fprintf (asm_out_file, "\t! Cache block size\t: %d\n",
kono
parents:
diff changeset
2216 nds32_cache_block_size);
kono
parents:
diff changeset
2217
kono
parents:
diff changeset
2218 fprintf (asm_out_file, "\t! ------------------------------------\n");
kono
parents:
diff changeset
2219
kono
parents:
diff changeset
2220 nds32_asm_file_start_for_isr ();
kono
parents:
diff changeset
2221 }
kono
parents:
diff changeset
2222
kono
parents:
diff changeset
2223 static void
kono
parents:
diff changeset
2224 nds32_asm_file_end (void)
kono
parents:
diff changeset
2225 {
kono
parents:
diff changeset
2226 nds32_asm_file_end_for_isr ();
kono
parents:
diff changeset
2227
kono
parents:
diff changeset
2228 fprintf (asm_out_file, "\t! ------------------------------------\n");
kono
parents:
diff changeset
2229 }
kono
parents:
diff changeset
2230
kono
parents:
diff changeset
2231 /* -- Output and Generation of Labels. */
kono
parents:
diff changeset
2232
kono
parents:
diff changeset
2233 static void
kono
parents:
diff changeset
2234 nds32_asm_globalize_label (FILE *stream, const char *name)
kono
parents:
diff changeset
2235 {
kono
parents:
diff changeset
2236 fputs ("\t.global\t", stream);
kono
parents:
diff changeset
2237 assemble_name (stream, name);
kono
parents:
diff changeset
2238 fputs ("\n", stream);
kono
parents:
diff changeset
2239 }
kono
parents:
diff changeset
2240
kono
parents:
diff changeset
2241 /* -- Output of Assembler Instructions. */
kono
parents:
diff changeset
2242
kono
parents:
diff changeset
2243 static void
kono
parents:
diff changeset
2244 nds32_print_operand (FILE *stream, rtx x, int code)
kono
parents:
diff changeset
2245 {
kono
parents:
diff changeset
2246 int op_value;
kono
parents:
diff changeset
2247
kono
parents:
diff changeset
2248 switch (code)
kono
parents:
diff changeset
2249 {
kono
parents:
diff changeset
2250 case 0 :
kono
parents:
diff changeset
2251 /* Do nothing special. */
kono
parents:
diff changeset
2252 break;
kono
parents:
diff changeset
2253
kono
parents:
diff changeset
2254 case 'V':
kono
parents:
diff changeset
2255 /* 'x' is supposed to be CONST_INT, get the value. */
kono
parents:
diff changeset
2256 gcc_assert (CONST_INT_P (x));
kono
parents:
diff changeset
2257 op_value = INTVAL (x);
kono
parents:
diff changeset
2258
kono
parents:
diff changeset
2259 /* According to the Andes architecture,
kono
parents:
diff changeset
2260 the system/user register index range is 0 ~ 1023.
kono
parents:
diff changeset
2261 In order to avoid conflict between user-specified-integer value
kono
parents:
diff changeset
2262 and enum-specified-register value,
kono
parents:
diff changeset
2263 the 'enum nds32_intrinsic_registers' value
kono
parents:
diff changeset
2264 in nds32_intrinsic.h starts from 1024. */
kono
parents:
diff changeset
2265 if (op_value < 1024 && op_value >= 0)
kono
parents:
diff changeset
2266 {
kono
parents:
diff changeset
2267 /* If user gives integer value directly (0~1023),
kono
parents:
diff changeset
2268 we just print out the value. */
kono
parents:
diff changeset
2269 fprintf (stream, "%d", op_value);
kono
parents:
diff changeset
2270 }
kono
parents:
diff changeset
2271 else if (op_value < 0
kono
parents:
diff changeset
2272 || op_value >= ((int) ARRAY_SIZE (nds32_intrinsic_register_names)
kono
parents:
diff changeset
2273 + 1024))
kono
parents:
diff changeset
2274 {
kono
parents:
diff changeset
2275 /* The enum index value for array size is out of range. */
kono
parents:
diff changeset
2276 error ("intrinsic register index is out of range");
kono
parents:
diff changeset
2277 }
kono
parents:
diff changeset
2278 else
kono
parents:
diff changeset
2279 {
kono
parents:
diff changeset
2280 /* If user applies normal way with __NDS32_REG_XXX__ enum data,
kono
parents:
diff changeset
2281 we can print out register name. Remember to substract 1024. */
kono
parents:
diff changeset
2282 fprintf (stream, "%s",
kono
parents:
diff changeset
2283 nds32_intrinsic_register_names[op_value - 1024]);
kono
parents:
diff changeset
2284 }
kono
parents:
diff changeset
2285
kono
parents:
diff changeset
2286 /* No need to handle following process, so return immediately. */
kono
parents:
diff changeset
2287 return;
kono
parents:
diff changeset
2288
kono
parents:
diff changeset
2289 default :
kono
parents:
diff changeset
2290 /* Unknown flag. */
kono
parents:
diff changeset
2291 output_operand_lossage ("invalid operand output code");
kono
parents:
diff changeset
2292 break;
kono
parents:
diff changeset
2293 }
kono
parents:
diff changeset
2294
kono
parents:
diff changeset
2295 switch (GET_CODE (x))
kono
parents:
diff changeset
2296 {
kono
parents:
diff changeset
2297 case LABEL_REF:
kono
parents:
diff changeset
2298 case SYMBOL_REF:
kono
parents:
diff changeset
2299 output_addr_const (stream, x);
kono
parents:
diff changeset
2300 break;
kono
parents:
diff changeset
2301
kono
parents:
diff changeset
2302 case REG:
kono
parents:
diff changeset
2303 /* Forbid using static chain register ($r16)
kono
parents:
diff changeset
2304 on reduced-set registers configuration. */
kono
parents:
diff changeset
2305 if (TARGET_REDUCED_REGS
kono
parents:
diff changeset
2306 && REGNO (x) == STATIC_CHAIN_REGNUM)
kono
parents:
diff changeset
2307 sorry ("a nested function is not supported for reduced registers");
kono
parents:
diff changeset
2308
kono
parents:
diff changeset
2309 /* Normal cases, print out register name. */
kono
parents:
diff changeset
2310 fputs (reg_names[REGNO (x)], stream);
kono
parents:
diff changeset
2311 break;
kono
parents:
diff changeset
2312
kono
parents:
diff changeset
2313 case MEM:
kono
parents:
diff changeset
2314 output_address (GET_MODE (x), XEXP (x, 0));
kono
parents:
diff changeset
2315 break;
kono
parents:
diff changeset
2316
kono
parents:
diff changeset
2317 case CODE_LABEL:
kono
parents:
diff changeset
2318 case CONST_INT:
kono
parents:
diff changeset
2319 case CONST:
kono
parents:
diff changeset
2320 output_addr_const (stream, x);
kono
parents:
diff changeset
2321 break;
kono
parents:
diff changeset
2322
kono
parents:
diff changeset
2323 default:
kono
parents:
diff changeset
2324 /* Generally, output_addr_const () is able to handle most cases.
kono
parents:
diff changeset
2325 We want to see what CODE could appear,
kono
parents:
diff changeset
2326 so we use gcc_unreachable() to stop it. */
kono
parents:
diff changeset
2327 debug_rtx (x);
kono
parents:
diff changeset
2328 gcc_unreachable ();
kono
parents:
diff changeset
2329 break;
kono
parents:
diff changeset
2330 }
kono
parents:
diff changeset
2331 }
kono
parents:
diff changeset
2332
kono
parents:
diff changeset
2333 static void
kono
parents:
diff changeset
2334 nds32_print_operand_address (FILE *stream, machine_mode /*mode*/, rtx x)
kono
parents:
diff changeset
2335 {
kono
parents:
diff changeset
2336 rtx op0, op1;
kono
parents:
diff changeset
2337
kono
parents:
diff changeset
2338 switch (GET_CODE (x))
kono
parents:
diff changeset
2339 {
kono
parents:
diff changeset
2340 case SYMBOL_REF:
kono
parents:
diff changeset
2341 case CONST:
kono
parents:
diff changeset
2342 /* [ + symbol_ref] */
kono
parents:
diff changeset
2343 /* [ + const_addr], where const_addr = symbol_ref + const_int */
kono
parents:
diff changeset
2344 fputs ("[ + ", stream);
kono
parents:
diff changeset
2345 output_addr_const (stream, x);
kono
parents:
diff changeset
2346 fputs ("]", stream);
kono
parents:
diff changeset
2347 break;
kono
parents:
diff changeset
2348
kono
parents:
diff changeset
2349 case REG:
kono
parents:
diff changeset
2350 /* Forbid using static chain register ($r16)
kono
parents:
diff changeset
2351 on reduced-set registers configuration. */
kono
parents:
diff changeset
2352 if (TARGET_REDUCED_REGS
kono
parents:
diff changeset
2353 && REGNO (x) == STATIC_CHAIN_REGNUM)
kono
parents:
diff changeset
2354 sorry ("a nested function is not supported for reduced registers");
kono
parents:
diff changeset
2355
kono
parents:
diff changeset
2356 /* [Ra] */
kono
parents:
diff changeset
2357 fprintf (stream, "[%s]", reg_names[REGNO (x)]);
kono
parents:
diff changeset
2358 break;
kono
parents:
diff changeset
2359
kono
parents:
diff changeset
2360 case PLUS:
kono
parents:
diff changeset
2361 op0 = XEXP (x, 0);
kono
parents:
diff changeset
2362 op1 = XEXP (x, 1);
kono
parents:
diff changeset
2363
kono
parents:
diff changeset
2364 /* Checking op0, forbid using static chain register ($r16)
kono
parents:
diff changeset
2365 on reduced-set registers configuration. */
kono
parents:
diff changeset
2366 if (TARGET_REDUCED_REGS
kono
parents:
diff changeset
2367 && REG_P (op0)
kono
parents:
diff changeset
2368 && REGNO (op0) == STATIC_CHAIN_REGNUM)
kono
parents:
diff changeset
2369 sorry ("a nested function is not supported for reduced registers");
kono
parents:
diff changeset
2370 /* Checking op1, forbid using static chain register ($r16)
kono
parents:
diff changeset
2371 on reduced-set registers configuration. */
kono
parents:
diff changeset
2372 if (TARGET_REDUCED_REGS
kono
parents:
diff changeset
2373 && REG_P (op1)
kono
parents:
diff changeset
2374 && REGNO (op1) == STATIC_CHAIN_REGNUM)
kono
parents:
diff changeset
2375 sorry ("a nested function is not supported for reduced registers");
kono
parents:
diff changeset
2376
kono
parents:
diff changeset
2377 if (REG_P (op0) && CONST_INT_P (op1))
kono
parents:
diff changeset
2378 {
kono
parents:
diff changeset
2379 /* [Ra + imm] */
kono
parents:
diff changeset
2380 fprintf (stream, "[%s + (%d)]",
kono
parents:
diff changeset
2381 reg_names[REGNO (op0)], (int)INTVAL (op1));
kono
parents:
diff changeset
2382 }
kono
parents:
diff changeset
2383 else if (REG_P (op0) && REG_P (op1))
kono
parents:
diff changeset
2384 {
kono
parents:
diff changeset
2385 /* [Ra + Rb] */
kono
parents:
diff changeset
2386 fprintf (stream, "[%s + %s]",
kono
parents:
diff changeset
2387 reg_names[REGNO (op0)], reg_names[REGNO (op1)]);
kono
parents:
diff changeset
2388 }
kono
parents:
diff changeset
2389 else if (GET_CODE (op0) == MULT && REG_P (op1))
kono
parents:
diff changeset
2390 {
kono
parents:
diff changeset
2391 /* [Ra + Rb << sv]
kono
parents:
diff changeset
2392 From observation, the pattern looks like:
kono
parents:
diff changeset
2393 (plus:SI (mult:SI (reg:SI 58)
kono
parents:
diff changeset
2394 (const_int 4 [0x4]))
kono
parents:
diff changeset
2395 (reg/f:SI 57)) */
kono
parents:
diff changeset
2396 int sv;
kono
parents:
diff changeset
2397
kono
parents:
diff changeset
2398 /* We need to set sv to output shift value. */
kono
parents:
diff changeset
2399 if (INTVAL (XEXP (op0, 1)) == 1)
kono
parents:
diff changeset
2400 sv = 0;
kono
parents:
diff changeset
2401 else if (INTVAL (XEXP (op0, 1)) == 2)
kono
parents:
diff changeset
2402 sv = 1;
kono
parents:
diff changeset
2403 else if (INTVAL (XEXP (op0, 1)) == 4)
kono
parents:
diff changeset
2404 sv = 2;
kono
parents:
diff changeset
2405 else
kono
parents:
diff changeset
2406 gcc_unreachable ();
kono
parents:
diff changeset
2407
kono
parents:
diff changeset
2408 fprintf (stream, "[%s + %s << %d]",
kono
parents:
diff changeset
2409 reg_names[REGNO (op1)],
kono
parents:
diff changeset
2410 reg_names[REGNO (XEXP (op0, 0))],
kono
parents:
diff changeset
2411 sv);
kono
parents:
diff changeset
2412 }
kono
parents:
diff changeset
2413 else
kono
parents:
diff changeset
2414 {
kono
parents:
diff changeset
2415 /* The control flow is not supposed to be here. */
kono
parents:
diff changeset
2416 debug_rtx (x);
kono
parents:
diff changeset
2417 gcc_unreachable ();
kono
parents:
diff changeset
2418 }
kono
parents:
diff changeset
2419
kono
parents:
diff changeset
2420 break;
kono
parents:
diff changeset
2421
kono
parents:
diff changeset
2422 case POST_MODIFY:
kono
parents:
diff changeset
2423 /* (post_modify (regA) (plus (regA) (regB)))
kono
parents:
diff changeset
2424 (post_modify (regA) (plus (regA) (const_int)))
kono
parents:
diff changeset
2425 We would like to extract
kono
parents:
diff changeset
2426 regA and regB (or const_int) from plus rtx. */
kono
parents:
diff changeset
2427 op0 = XEXP (XEXP (x, 1), 0);
kono
parents:
diff changeset
2428 op1 = XEXP (XEXP (x, 1), 1);
kono
parents:
diff changeset
2429
kono
parents:
diff changeset
2430 /* Checking op0, forbid using static chain register ($r16)
kono
parents:
diff changeset
2431 on reduced-set registers configuration. */
kono
parents:
diff changeset
2432 if (TARGET_REDUCED_REGS
kono
parents:
diff changeset
2433 && REG_P (op0)
kono
parents:
diff changeset
2434 && REGNO (op0) == STATIC_CHAIN_REGNUM)
kono
parents:
diff changeset
2435 sorry ("a nested function is not supported for reduced registers");
kono
parents:
diff changeset
2436 /* Checking op1, forbid using static chain register ($r16)
kono
parents:
diff changeset
2437 on reduced-set registers configuration. */
kono
parents:
diff changeset
2438 if (TARGET_REDUCED_REGS
kono
parents:
diff changeset
2439 && REG_P (op1)
kono
parents:
diff changeset
2440 && REGNO (op1) == STATIC_CHAIN_REGNUM)
kono
parents:
diff changeset
2441 sorry ("a nested function is not supported for reduced registers");
kono
parents:
diff changeset
2442
kono
parents:
diff changeset
2443 if (REG_P (op0) && REG_P (op1))
kono
parents:
diff changeset
2444 {
kono
parents:
diff changeset
2445 /* [Ra], Rb */
kono
parents:
diff changeset
2446 fprintf (stream, "[%s], %s",
kono
parents:
diff changeset
2447 reg_names[REGNO (op0)], reg_names[REGNO (op1)]);
kono
parents:
diff changeset
2448 }
kono
parents:
diff changeset
2449 else if (REG_P (op0) && CONST_INT_P (op1))
kono
parents:
diff changeset
2450 {
kono
parents:
diff changeset
2451 /* [Ra], imm */
kono
parents:
diff changeset
2452 fprintf (stream, "[%s], %d",
kono
parents:
diff changeset
2453 reg_names[REGNO (op0)], (int)INTVAL (op1));
kono
parents:
diff changeset
2454 }
kono
parents:
diff changeset
2455 else
kono
parents:
diff changeset
2456 {
kono
parents:
diff changeset
2457 /* The control flow is not supposed to be here. */
kono
parents:
diff changeset
2458 debug_rtx (x);
kono
parents:
diff changeset
2459 gcc_unreachable ();
kono
parents:
diff changeset
2460 }
kono
parents:
diff changeset
2461
kono
parents:
diff changeset
2462 break;
kono
parents:
diff changeset
2463
kono
parents:
diff changeset
2464 case POST_INC:
kono
parents:
diff changeset
2465 case POST_DEC:
kono
parents:
diff changeset
2466 op0 = XEXP (x, 0);
kono
parents:
diff changeset
2467
kono
parents:
diff changeset
2468 /* Checking op0, forbid using static chain register ($r16)
kono
parents:
diff changeset
2469 on reduced-set registers configuration. */
kono
parents:
diff changeset
2470 if (TARGET_REDUCED_REGS
kono
parents:
diff changeset
2471 && REG_P (op0)
kono
parents:
diff changeset
2472 && REGNO (op0) == STATIC_CHAIN_REGNUM)
kono
parents:
diff changeset
2473 sorry ("a nested function is not supported for reduced registers");
kono
parents:
diff changeset
2474
kono
parents:
diff changeset
2475 if (REG_P (op0))
kono
parents:
diff changeset
2476 {
kono
parents:
diff changeset
2477 /* "[Ra], 1/2/4" or "[Ra], -1/-2/-4"
kono
parents:
diff changeset
2478 The 1/2/4 or -1/-2/-4 have been displayed in nds32.md.
kono
parents:
diff changeset
2479 We only need to deal with register Ra. */
kono
parents:
diff changeset
2480 fprintf (stream, "[%s]", reg_names[REGNO (op0)]);
kono
parents:
diff changeset
2481 }
kono
parents:
diff changeset
2482 else
kono
parents:
diff changeset
2483 {
kono
parents:
diff changeset
2484 /* The control flow is not supposed to be here. */
kono
parents:
diff changeset
2485 debug_rtx (x);
kono
parents:
diff changeset
2486 gcc_unreachable ();
kono
parents:
diff changeset
2487 }
kono
parents:
diff changeset
2488
kono
parents:
diff changeset
2489 break;
kono
parents:
diff changeset
2490
kono
parents:
diff changeset
2491 default :
kono
parents:
diff changeset
2492 /* Generally, output_addr_const () is able to handle most cases.
kono
parents:
diff changeset
2493 We want to see what CODE could appear,
kono
parents:
diff changeset
2494 so we use gcc_unreachable() to stop it. */
kono
parents:
diff changeset
2495 debug_rtx (x);
kono
parents:
diff changeset
2496 gcc_unreachable ();
kono
parents:
diff changeset
2497 break;
kono
parents:
diff changeset
2498 }
kono
parents:
diff changeset
2499 }
kono
parents:
diff changeset
2500
kono
parents:
diff changeset
2501
kono
parents:
diff changeset
2502 /* Defining target-specific uses of __attribute__. */
kono
parents:
diff changeset
2503
kono
parents:
diff changeset
2504 /* Add some checking after merging attributes. */
kono
parents:
diff changeset
2505 static tree
kono
parents:
diff changeset
2506 nds32_merge_decl_attributes (tree olddecl, tree newdecl)
kono
parents:
diff changeset
2507 {
kono
parents:
diff changeset
2508 tree combined_attrs;
kono
parents:
diff changeset
2509
kono
parents:
diff changeset
2510 /* Create combined attributes. */
kono
parents:
diff changeset
2511 combined_attrs = merge_attributes (DECL_ATTRIBUTES (olddecl),
kono
parents:
diff changeset
2512 DECL_ATTRIBUTES (newdecl));
kono
parents:
diff changeset
2513
kono
parents:
diff changeset
2514 /* Since newdecl is acutally a duplicate of olddecl,
kono
parents:
diff changeset
2515 we can take olddecl for some operations. */
kono
parents:
diff changeset
2516 if (TREE_CODE (olddecl) == FUNCTION_DECL)
kono
parents:
diff changeset
2517 {
kono
parents:
diff changeset
2518 /* Check isr-specific attributes conflict. */
kono
parents:
diff changeset
2519 nds32_check_isr_attrs_conflict (olddecl, combined_attrs);
kono
parents:
diff changeset
2520 }
kono
parents:
diff changeset
2521
kono
parents:
diff changeset
2522 return combined_attrs;
kono
parents:
diff changeset
2523 }
kono
parents:
diff changeset
2524
kono
parents:
diff changeset
2525 /* Add some checking when inserting attributes. */
kono
parents:
diff changeset
2526 static void
kono
parents:
diff changeset
2527 nds32_insert_attributes (tree decl, tree *attributes)
kono
parents:
diff changeset
2528 {
kono
parents:
diff changeset
2529 /* For function declaration, we need to check isr-specific attributes:
kono
parents:
diff changeset
2530 1. Call nds32_check_isr_attrs_conflict() to check any conflict.
kono
parents:
diff changeset
2531 2. Check valid integer value for interrupt/exception.
kono
parents:
diff changeset
2532 3. Check valid integer value for reset.
kono
parents:
diff changeset
2533 4. Check valid function for nmi/warm. */
kono
parents:
diff changeset
2534 if (TREE_CODE (decl) == FUNCTION_DECL)
kono
parents:
diff changeset
2535 {
kono
parents:
diff changeset
2536 tree func_attrs;
kono
parents:
diff changeset
2537 tree intr, excp, reset;
kono
parents:
diff changeset
2538
kono
parents:
diff changeset
2539 /* Pick up function attributes. */
kono
parents:
diff changeset
2540 func_attrs = *attributes;
kono
parents:
diff changeset
2541
kono
parents:
diff changeset
2542 /* 1. Call nds32_check_isr_attrs_conflict() to check any conflict. */
kono
parents:
diff changeset
2543 nds32_check_isr_attrs_conflict (decl, func_attrs);
kono
parents:
diff changeset
2544
kono
parents:
diff changeset
2545 /* Now we are starting to check valid id value
kono
parents:
diff changeset
2546 for interrupt/exception/reset.
kono
parents:
diff changeset
2547 Note that we ONLY check its validity here.
kono
parents:
diff changeset
2548 To construct isr vector information, it is still performed
kono
parents:
diff changeset
2549 by nds32_construct_isr_vectors_information(). */
kono
parents:
diff changeset
2550 intr = lookup_attribute ("interrupt", func_attrs);
kono
parents:
diff changeset
2551 excp = lookup_attribute ("exception", func_attrs);
kono
parents:
diff changeset
2552 reset = lookup_attribute ("reset", func_attrs);
kono
parents:
diff changeset
2553
kono
parents:
diff changeset
2554 if (intr || excp)
kono
parents:
diff changeset
2555 {
kono
parents:
diff changeset
2556 /* Deal with interrupt/exception. */
kono
parents:
diff changeset
2557 tree id_list;
kono
parents:
diff changeset
2558 unsigned int lower_bound, upper_bound;
kono
parents:
diff changeset
2559
kono
parents:
diff changeset
2560 /* The way to handle interrupt or exception is the same,
kono
parents:
diff changeset
2561 we just need to take care of actual vector number.
kono
parents:
diff changeset
2562 For interrupt(0..63), the actual vector number is (9..72).
kono
parents:
diff changeset
2563 For exception(1..8), the actual vector number is (1..8). */
kono
parents:
diff changeset
2564 lower_bound = (intr) ? (0) : (1);
kono
parents:
diff changeset
2565 upper_bound = (intr) ? (63) : (8);
kono
parents:
diff changeset
2566
kono
parents:
diff changeset
2567 /* Prepare id list so that we can traverse id value. */
kono
parents:
diff changeset
2568 id_list = (intr) ? (TREE_VALUE (intr)) : (TREE_VALUE (excp));
kono
parents:
diff changeset
2569
kono
parents:
diff changeset
2570 /* 2. Check valid integer value for interrupt/exception. */
kono
parents:
diff changeset
2571 while (id_list)
kono
parents:
diff changeset
2572 {
kono
parents:
diff changeset
2573 tree id;
kono
parents:
diff changeset
2574
kono
parents:
diff changeset
2575 /* Pick up each vector id value. */
kono
parents:
diff changeset
2576 id = TREE_VALUE (id_list);
kono
parents:
diff changeset
2577 /* Issue error if it is not a valid integer value. */
kono
parents:
diff changeset
2578 if (TREE_CODE (id) != INTEGER_CST
kono
parents:
diff changeset
2579 || wi::ltu_p (wi::to_wide (id), lower_bound)
kono
parents:
diff changeset
2580 || wi::gtu_p (wi::to_wide (id), upper_bound))
kono
parents:
diff changeset
2581 error ("invalid id value for interrupt/exception attribute");
kono
parents:
diff changeset
2582
kono
parents:
diff changeset
2583 /* Advance to next id. */
kono
parents:
diff changeset
2584 id_list = TREE_CHAIN (id_list);
kono
parents:
diff changeset
2585 }
kono
parents:
diff changeset
2586 }
kono
parents:
diff changeset
2587 else if (reset)
kono
parents:
diff changeset
2588 {
kono
parents:
diff changeset
2589 /* Deal with reset. */
kono
parents:
diff changeset
2590 tree id_list;
kono
parents:
diff changeset
2591 tree id;
kono
parents:
diff changeset
2592 tree nmi, warm;
kono
parents:
diff changeset
2593 unsigned int lower_bound;
kono
parents:
diff changeset
2594 unsigned int upper_bound;
kono
parents:
diff changeset
2595
kono
parents:
diff changeset
2596 /* Prepare id_list and identify id value so that
kono
parents:
diff changeset
2597 we can check if total number of vectors is valid. */
kono
parents:
diff changeset
2598 id_list = TREE_VALUE (reset);
kono
parents:
diff changeset
2599 id = TREE_VALUE (id_list);
kono
parents:
diff changeset
2600
kono
parents:
diff changeset
2601 /* The maximum numbers for user's interrupt is 64. */
kono
parents:
diff changeset
2602 lower_bound = 0;
kono
parents:
diff changeset
2603 upper_bound = 64;
kono
parents:
diff changeset
2604
kono
parents:
diff changeset
2605 /* 3. Check valid integer value for reset. */
kono
parents:
diff changeset
2606 if (TREE_CODE (id) != INTEGER_CST
kono
parents:
diff changeset
2607 || wi::ltu_p (wi::to_wide (id), lower_bound)
kono
parents:
diff changeset
2608 || wi::gtu_p (wi::to_wide (id), upper_bound))
kono
parents:
diff changeset
2609 error ("invalid id value for reset attribute");
kono
parents:
diff changeset
2610
kono
parents:
diff changeset
2611 /* 4. Check valid function for nmi/warm. */
kono
parents:
diff changeset
2612 nmi = lookup_attribute ("nmi", func_attrs);
kono
parents:
diff changeset
2613 warm = lookup_attribute ("warm", func_attrs);
kono
parents:
diff changeset
2614
kono
parents:
diff changeset
2615 if (nmi != NULL_TREE)
kono
parents:
diff changeset
2616 {
kono
parents:
diff changeset
2617 tree nmi_func_list;
kono
parents:
diff changeset
2618 tree nmi_func;
kono
parents:
diff changeset
2619
kono
parents:
diff changeset
2620 nmi_func_list = TREE_VALUE (nmi);
kono
parents:
diff changeset
2621 nmi_func = TREE_VALUE (nmi_func_list);
kono
parents:
diff changeset
2622
kono
parents:
diff changeset
2623 /* Issue error if it is not a valid nmi function. */
kono
parents:
diff changeset
2624 if (TREE_CODE (nmi_func) != IDENTIFIER_NODE)
kono
parents:
diff changeset
2625 error ("invalid nmi function for reset attribute");
kono
parents:
diff changeset
2626 }
kono
parents:
diff changeset
2627
kono
parents:
diff changeset
2628 if (warm != NULL_TREE)
kono
parents:
diff changeset
2629 {
kono
parents:
diff changeset
2630 tree warm_func_list;
kono
parents:
diff changeset
2631 tree warm_func;
kono
parents:
diff changeset
2632
kono
parents:
diff changeset
2633 warm_func_list = TREE_VALUE (warm);
kono
parents:
diff changeset
2634 warm_func = TREE_VALUE (warm_func_list);
kono
parents:
diff changeset
2635
kono
parents:
diff changeset
2636 /* Issue error if it is not a valid warm function. */
kono
parents:
diff changeset
2637 if (TREE_CODE (warm_func) != IDENTIFIER_NODE)
kono
parents:
diff changeset
2638 error ("invalid warm function for reset attribute");
kono
parents:
diff changeset
2639 }
kono
parents:
diff changeset
2640 }
kono
parents:
diff changeset
2641 else
kono
parents:
diff changeset
2642 {
kono
parents:
diff changeset
2643 /* No interrupt, exception, or reset attribute is set. */
kono
parents:
diff changeset
2644 return;
kono
parents:
diff changeset
2645 }
kono
parents:
diff changeset
2646 }
kono
parents:
diff changeset
2647 }
kono
parents:
diff changeset
2648
kono
parents:
diff changeset
2649 static bool
kono
parents:
diff changeset
2650 nds32_option_pragma_parse (tree args ATTRIBUTE_UNUSED,
kono
parents:
diff changeset
2651 tree pop_target ATTRIBUTE_UNUSED)
kono
parents:
diff changeset
2652 {
kono
parents:
diff changeset
2653 /* Currently, we do not parse any pragma target by ourself,
kono
parents:
diff changeset
2654 so just simply return false. */
kono
parents:
diff changeset
2655 return false;
kono
parents:
diff changeset
2656 }
kono
parents:
diff changeset
2657
kono
parents:
diff changeset
2658 static void
kono
parents:
diff changeset
2659 nds32_option_override (void)
kono
parents:
diff changeset
2660 {
kono
parents:
diff changeset
2661 /* After all the command options have been parsed,
kono
parents:
diff changeset
2662 we shall deal with some flags for changing compiler settings. */
kono
parents:
diff changeset
2663
kono
parents:
diff changeset
2664 /* At first, we check if we have to strictly
kono
parents:
diff changeset
2665 set some flags based on ISA family. */
kono
parents:
diff changeset
2666 if (TARGET_ISA_V2)
kono
parents:
diff changeset
2667 {
kono
parents:
diff changeset
2668 /* Under V2 ISA, we need to strictly disable TARGET_V3PUSH. */
kono
parents:
diff changeset
2669 target_flags &= ~MASK_V3PUSH;
kono
parents:
diff changeset
2670 }
kono
parents:
diff changeset
2671 if (TARGET_ISA_V3)
kono
parents:
diff changeset
2672 {
kono
parents:
diff changeset
2673 /* Under V3 ISA, currently nothing should be strictly set. */
kono
parents:
diff changeset
2674 }
kono
parents:
diff changeset
2675 if (TARGET_ISA_V3M)
kono
parents:
diff changeset
2676 {
kono
parents:
diff changeset
2677 /* Under V3M ISA, we need to strictly enable TARGET_REDUCED_REGS. */
kono
parents:
diff changeset
2678 target_flags |= MASK_REDUCED_REGS;
kono
parents:
diff changeset
2679 /* Under V3M ISA, we need to strictly disable TARGET_PERF_EXT. */
kono
parents:
diff changeset
2680 target_flags &= ~MASK_PERF_EXT;
kono
parents:
diff changeset
2681 }
kono
parents:
diff changeset
2682
kono
parents:
diff changeset
2683 /* See if we are using reduced-set registers:
kono
parents:
diff changeset
2684 $r0~$r5, $r6~$r10, $r15, $r28, $r29, $r30, $r31
kono
parents:
diff changeset
2685 If so, we must forbid using $r11~$r14, $r16~$r27. */
kono
parents:
diff changeset
2686 if (TARGET_REDUCED_REGS)
kono
parents:
diff changeset
2687 {
kono
parents:
diff changeset
2688 int r;
kono
parents:
diff changeset
2689
kono
parents:
diff changeset
2690 /* Prevent register allocator from
kono
parents:
diff changeset
2691 choosing it as doing register allocation. */
kono
parents:
diff changeset
2692 for (r = 11; r <= 14; r++)
kono
parents:
diff changeset
2693 fixed_regs[r] = call_used_regs[r] = 1;
kono
parents:
diff changeset
2694 for (r = 16; r <= 27; r++)
kono
parents:
diff changeset
2695 fixed_regs[r] = call_used_regs[r] = 1;
kono
parents:
diff changeset
2696 }
kono
parents:
diff changeset
2697
kono
parents:
diff changeset
2698 if (!TARGET_16_BIT)
kono
parents:
diff changeset
2699 {
kono
parents:
diff changeset
2700 /* Under no 16 bit ISA, we need to strictly disable TARGET_V3PUSH. */
kono
parents:
diff changeset
2701 target_flags &= ~MASK_V3PUSH;
kono
parents:
diff changeset
2702 }
kono
parents:
diff changeset
2703
kono
parents:
diff changeset
2704 /* Currently, we don't support PIC code generation yet. */
kono
parents:
diff changeset
2705 if (flag_pic)
kono
parents:
diff changeset
2706 sorry ("position-independent code not supported");
kono
parents:
diff changeset
2707 }
kono
parents:
diff changeset
2708
kono
parents:
diff changeset
2709
kono
parents:
diff changeset
2710 /* Miscellaneous Parameters. */
kono
parents:
diff changeset
2711
kono
parents:
diff changeset
2712 static void
kono
parents:
diff changeset
2713 nds32_init_builtins (void)
kono
parents:
diff changeset
2714 {
kono
parents:
diff changeset
2715 nds32_init_builtins_impl ();
kono
parents:
diff changeset
2716 }
kono
parents:
diff changeset
2717
kono
parents:
diff changeset
2718 static rtx
kono
parents:
diff changeset
2719 nds32_expand_builtin (tree exp,
kono
parents:
diff changeset
2720 rtx target,
kono
parents:
diff changeset
2721 rtx subtarget,
kono
parents:
diff changeset
2722 machine_mode mode,
kono
parents:
diff changeset
2723 int ignore)
kono
parents:
diff changeset
2724 {
kono
parents:
diff changeset
2725 return nds32_expand_builtin_impl (exp, target, subtarget, mode, ignore);
kono
parents:
diff changeset
2726 }
kono
parents:
diff changeset
2727
kono
parents:
diff changeset
2728
kono
parents:
diff changeset
2729 /* ------------------------------------------------------------------------ */
kono
parents:
diff changeset
2730
kono
parents:
diff changeset
2731 /* PART 4: Implemet extern function definitions,
kono
parents:
diff changeset
2732 the prototype is in nds32-protos.h. */
kono
parents:
diff changeset
2733
kono
parents:
diff changeset
2734 /* Defining Data Structures for Per-function Information. */
kono
parents:
diff changeset
2735
kono
parents:
diff changeset
2736 void
kono
parents:
diff changeset
2737 nds32_init_expanders (void)
kono
parents:
diff changeset
2738 {
kono
parents:
diff changeset
2739 /* Arrange to initialize and mark the machine per-function status. */
kono
parents:
diff changeset
2740 init_machine_status = nds32_init_machine_status;
kono
parents:
diff changeset
2741 }
kono
parents:
diff changeset
2742
kono
parents:
diff changeset
2743
kono
parents:
diff changeset
2744 /* Register Usage. */
kono
parents:
diff changeset
2745
kono
parents:
diff changeset
2746 /* -- How Values Fit in Registers. */
kono
parents:
diff changeset
2747
kono
parents:
diff changeset
2748 /* Implement TARGET_HARD_REGNO_MODE_OK. */
kono
parents:
diff changeset
2749
kono
parents:
diff changeset
2750 static bool
kono
parents:
diff changeset
2751 nds32_hard_regno_mode_ok (unsigned int regno, machine_mode mode)
kono
parents:
diff changeset
2752 {
kono
parents:
diff changeset
2753 /* Restrict double-word quantities to even register pairs. */
kono
parents:
diff changeset
2754 if (targetm.hard_regno_nregs (regno, mode) == 1
kono
parents:
diff changeset
2755 || !((regno) & 1))
kono
parents:
diff changeset
2756 return true;
kono
parents:
diff changeset
2757
kono
parents:
diff changeset
2758 return false;
kono
parents:
diff changeset
2759 }
kono
parents:
diff changeset
2760
kono
parents:
diff changeset
2761 #undef TARGET_HARD_REGNO_MODE_OK
kono
parents:
diff changeset
2762 #define TARGET_HARD_REGNO_MODE_OK nds32_hard_regno_mode_ok
kono
parents:
diff changeset
2763
kono
parents:
diff changeset
2764 /* Implement TARGET_MODES_TIEABLE_P. We can use general registers to
kono
parents:
diff changeset
2765 tie QI/HI/SI modes together. */
kono
parents:
diff changeset
2766
kono
parents:
diff changeset
2767 static bool
kono
parents:
diff changeset
2768 nds32_modes_tieable_p (machine_mode mode1, machine_mode mode2)
kono
parents:
diff changeset
2769 {
kono
parents:
diff changeset
2770 return (GET_MODE_CLASS (mode1) == MODE_INT
kono
parents:
diff changeset
2771 && GET_MODE_CLASS (mode2) == MODE_INT
kono
parents:
diff changeset
2772 && GET_MODE_SIZE (mode1) <= UNITS_PER_WORD
kono
parents:
diff changeset
2773 && GET_MODE_SIZE (mode2) <= UNITS_PER_WORD);
kono
parents:
diff changeset
2774 }
kono
parents:
diff changeset
2775
kono
parents:
diff changeset
2776 #undef TARGET_MODES_TIEABLE_P
kono
parents:
diff changeset
2777 #define TARGET_MODES_TIEABLE_P nds32_modes_tieable_p
kono
parents:
diff changeset
2778
kono
parents:
diff changeset
2779 /* Register Classes. */
kono
parents:
diff changeset
2780
kono
parents:
diff changeset
2781 enum reg_class
kono
parents:
diff changeset
2782 nds32_regno_reg_class (int regno)
kono
parents:
diff changeset
2783 {
kono
parents:
diff changeset
2784 /* Refer to nds32.h for more register class details. */
kono
parents:
diff changeset
2785
kono
parents:
diff changeset
2786 if (regno >= 0 && regno <= 7)
kono
parents:
diff changeset
2787 return LOW_REGS;
kono
parents:
diff changeset
2788 else if (regno >= 8 && regno <= 11)
kono
parents:
diff changeset
2789 return MIDDLE_REGS;
kono
parents:
diff changeset
2790 else if (regno >= 12 && regno <= 14)
kono
parents:
diff changeset
2791 return HIGH_REGS;
kono
parents:
diff changeset
2792 else if (regno == 15)
kono
parents:
diff changeset
2793 return R15_TA_REG;
kono
parents:
diff changeset
2794 else if (regno >= 16 && regno <= 19)
kono
parents:
diff changeset
2795 return MIDDLE_REGS;
kono
parents:
diff changeset
2796 else if (regno >= 20 && regno <= 31)
kono
parents:
diff changeset
2797 return HIGH_REGS;
kono
parents:
diff changeset
2798 else if (regno == 32 || regno == 33)
kono
parents:
diff changeset
2799 return FRAME_REGS;
kono
parents:
diff changeset
2800 else
kono
parents:
diff changeset
2801 return NO_REGS;
kono
parents:
diff changeset
2802 }
kono
parents:
diff changeset
2803
kono
parents:
diff changeset
2804
kono
parents:
diff changeset
2805 /* Stack Layout and Calling Conventions. */
kono
parents:
diff changeset
2806
kono
parents:
diff changeset
2807 /* -- Basic Stack Layout. */
kono
parents:
diff changeset
2808
kono
parents:
diff changeset
2809 rtx
kono
parents:
diff changeset
2810 nds32_return_addr_rtx (int count,
kono
parents:
diff changeset
2811 rtx frameaddr ATTRIBUTE_UNUSED)
kono
parents:
diff changeset
2812 {
kono
parents:
diff changeset
2813 /* There is no way to determine the return address
kono
parents:
diff changeset
2814 if frameaddr is the frame that has 'count' steps
kono
parents:
diff changeset
2815 up from current frame. */
kono
parents:
diff changeset
2816 if (count != 0)
kono
parents:
diff changeset
2817 return NULL_RTX;
kono
parents:
diff changeset
2818
kono
parents:
diff changeset
2819 /* If count == 0, it means we are at current frame,
kono
parents:
diff changeset
2820 the return address is $r30 ($lp). */
kono
parents:
diff changeset
2821 return get_hard_reg_initial_val (Pmode, LP_REGNUM);
kono
parents:
diff changeset
2822 }
kono
parents:
diff changeset
2823
kono
parents:
diff changeset
2824 /* -- Eliminating Frame Pointer and Arg Pointer. */
kono
parents:
diff changeset
2825
kono
parents:
diff changeset
2826 HOST_WIDE_INT
kono
parents:
diff changeset
2827 nds32_initial_elimination_offset (unsigned int from_reg, unsigned int to_reg)
kono
parents:
diff changeset
2828 {
kono
parents:
diff changeset
2829 HOST_WIDE_INT offset;
kono
parents:
diff changeset
2830
kono
parents:
diff changeset
2831 /* Compute and setup stack frame size.
kono
parents:
diff changeset
2832 The result will be in cfun->machine. */
kono
parents:
diff changeset
2833 nds32_compute_stack_frame ();
kono
parents:
diff changeset
2834
kono
parents:
diff changeset
2835 /* Remember to consider
kono
parents:
diff changeset
2836 cfun->machine->callee_saved_area_gpr_padding_bytes
kono
parents:
diff changeset
2837 when calculating offset. */
kono
parents:
diff changeset
2838 if (from_reg == ARG_POINTER_REGNUM && to_reg == STACK_POINTER_REGNUM)
kono
parents:
diff changeset
2839 {
kono
parents:
diff changeset
2840 offset = (cfun->machine->fp_size
kono
parents:
diff changeset
2841 + cfun->machine->gp_size
kono
parents:
diff changeset
2842 + cfun->machine->lp_size
kono
parents:
diff changeset
2843 + cfun->machine->callee_saved_gpr_regs_size
kono
parents:
diff changeset
2844 + cfun->machine->callee_saved_area_gpr_padding_bytes
kono
parents:
diff changeset
2845 + cfun->machine->local_size
kono
parents:
diff changeset
2846 + cfun->machine->out_args_size);
kono
parents:
diff changeset
2847 }
kono
parents:
diff changeset
2848 else if (from_reg == ARG_POINTER_REGNUM
kono
parents:
diff changeset
2849 && to_reg == HARD_FRAME_POINTER_REGNUM)
kono
parents:
diff changeset
2850 {
kono
parents:
diff changeset
2851 offset = 0;
kono
parents:
diff changeset
2852 }
kono
parents:
diff changeset
2853 else if (from_reg == FRAME_POINTER_REGNUM
kono
parents:
diff changeset
2854 && to_reg == STACK_POINTER_REGNUM)
kono
parents:
diff changeset
2855 {
kono
parents:
diff changeset
2856 offset = (cfun->machine->local_size + cfun->machine->out_args_size);
kono
parents:
diff changeset
2857 }
kono
parents:
diff changeset
2858 else if (from_reg == FRAME_POINTER_REGNUM
kono
parents:
diff changeset
2859 && to_reg == HARD_FRAME_POINTER_REGNUM)
kono
parents:
diff changeset
2860 {
kono
parents:
diff changeset
2861 offset = (-1) * (cfun->machine->fp_size
kono
parents:
diff changeset
2862 + cfun->machine->gp_size
kono
parents:
diff changeset
2863 + cfun->machine->lp_size
kono
parents:
diff changeset
2864 + cfun->machine->callee_saved_gpr_regs_size
kono
parents:
diff changeset
2865 + cfun->machine->callee_saved_area_gpr_padding_bytes);
kono
parents:
diff changeset
2866 }
kono
parents:
diff changeset
2867 else
kono
parents:
diff changeset
2868 {
kono
parents:
diff changeset
2869 gcc_unreachable ();
kono
parents:
diff changeset
2870 }
kono
parents:
diff changeset
2871
kono
parents:
diff changeset
2872 return offset;
kono
parents:
diff changeset
2873 }
kono
parents:
diff changeset
2874
kono
parents:
diff changeset
2875 /* -- Passing Arguments in Registers. */
kono
parents:
diff changeset
2876
kono
parents:
diff changeset
2877 void
kono
parents:
diff changeset
2878 nds32_init_cumulative_args (CUMULATIVE_ARGS *cum,
kono
parents:
diff changeset
2879 tree fntype ATTRIBUTE_UNUSED,
kono
parents:
diff changeset
2880 rtx libname ATTRIBUTE_UNUSED,
kono
parents:
diff changeset
2881 tree fndecl ATTRIBUTE_UNUSED,
kono
parents:
diff changeset
2882 int n_named_args ATTRIBUTE_UNUSED)
kono
parents:
diff changeset
2883 {
kono
parents:
diff changeset
2884 /* Initial available registers
kono
parents:
diff changeset
2885 (in offset, corresponding to NDS32_GPR_ARG_FIRST_REGNUM)
kono
parents:
diff changeset
2886 for passing arguments. */
kono
parents:
diff changeset
2887 cum->gpr_offset = 0;
kono
parents:
diff changeset
2888 }
kono
parents:
diff changeset
2889
kono
parents:
diff changeset
2890 /* -- Function Entry and Exit. */
kono
parents:
diff changeset
2891
kono
parents:
diff changeset
2892 /* Function for normal multiple push prologue. */
kono
parents:
diff changeset
2893 void
kono
parents:
diff changeset
2894 nds32_expand_prologue (void)
kono
parents:
diff changeset
2895 {
kono
parents:
diff changeset
2896 int fp_adjust;
kono
parents:
diff changeset
2897 int sp_adjust;
kono
parents:
diff changeset
2898 int en4_const;
kono
parents:
diff changeset
2899
kono
parents:
diff changeset
2900 rtx Rb, Re;
kono
parents:
diff changeset
2901 rtx fp_adjust_insn, sp_adjust_insn;
kono
parents:
diff changeset
2902
kono
parents:
diff changeset
2903 /* Compute and setup stack frame size.
kono
parents:
diff changeset
2904 The result will be in cfun->machine. */
kono
parents:
diff changeset
2905 nds32_compute_stack_frame ();
kono
parents:
diff changeset
2906
kono
parents:
diff changeset
2907 /* If this is a variadic function, first we need to push argument
kono
parents:
diff changeset
2908 registers that hold the unnamed argument value. */
kono
parents:
diff changeset
2909 if (cfun->machine->va_args_size != 0)
kono
parents:
diff changeset
2910 {
kono
parents:
diff changeset
2911 Rb = gen_rtx_REG (SImode, cfun->machine->va_args_first_regno);
kono
parents:
diff changeset
2912 Re = gen_rtx_REG (SImode, cfun->machine->va_args_last_regno);
kono
parents:
diff changeset
2913 /* No need to push $fp, $gp, or $lp, so use GEN_INT(0). */
kono
parents:
diff changeset
2914 nds32_emit_stack_push_multiple (Rb, Re, GEN_INT (0), true);
kono
parents:
diff changeset
2915
kono
parents:
diff changeset
2916 /* We may also need to adjust stack pointer for padding bytes
kono
parents:
diff changeset
2917 because varargs may cause $sp not 8-byte aligned. */
kono
parents:
diff changeset
2918 if (cfun->machine->va_args_area_padding_bytes)
kono
parents:
diff changeset
2919 {
kono
parents:
diff changeset
2920 /* Generate sp adjustment instruction. */
kono
parents:
diff changeset
2921 sp_adjust = cfun->machine->va_args_area_padding_bytes;
kono
parents:
diff changeset
2922 sp_adjust_insn = gen_addsi3 (stack_pointer_rtx,
kono
parents:
diff changeset
2923 stack_pointer_rtx,
kono
parents:
diff changeset
2924 GEN_INT (-1 * sp_adjust));
kono
parents:
diff changeset
2925
kono
parents:
diff changeset
2926 /* Emit rtx into instructions list and receive INSN rtx form. */
kono
parents:
diff changeset
2927 sp_adjust_insn = emit_insn (sp_adjust_insn);
kono
parents:
diff changeset
2928
kono
parents:
diff changeset
2929 /* The insn rtx 'sp_adjust_insn' will change frame layout.
kono
parents:
diff changeset
2930 We need to use RTX_FRAME_RELATED_P so that GCC is able to
kono
parents:
diff changeset
2931 generate CFI (Call Frame Information) stuff. */
kono
parents:
diff changeset
2932 RTX_FRAME_RELATED_P (sp_adjust_insn) = 1;
kono
parents:
diff changeset
2933 }
kono
parents:
diff changeset
2934 }
kono
parents:
diff changeset
2935
kono
parents:
diff changeset
2936 /* If the function is 'naked',
kono
parents:
diff changeset
2937 we do not have to generate prologue code fragment. */
kono
parents:
diff changeset
2938 if (cfun->machine->naked_p)
kono
parents:
diff changeset
2939 return;
kono
parents:
diff changeset
2940
kono
parents:
diff changeset
2941 /* Get callee_first_regno and callee_last_regno. */
kono
parents:
diff changeset
2942 Rb = gen_rtx_REG (SImode, cfun->machine->callee_saved_first_gpr_regno);
kono
parents:
diff changeset
2943 Re = gen_rtx_REG (SImode, cfun->machine->callee_saved_last_gpr_regno);
kono
parents:
diff changeset
2944
kono
parents:
diff changeset
2945 /* nds32_emit_stack_push_multiple(first_regno, last_regno),
kono
parents:
diff changeset
2946 the pattern 'stack_push_multiple' is implemented in nds32.md.
kono
parents:
diff changeset
2947 For En4 field, we have to calculate its constant value.
kono
parents:
diff changeset
2948 Refer to Andes ISA for more information. */
kono
parents:
diff changeset
2949 en4_const = 0;
kono
parents:
diff changeset
2950 if (cfun->machine->fp_size)
kono
parents:
diff changeset
2951 en4_const += 8;
kono
parents:
diff changeset
2952 if (cfun->machine->gp_size)
kono
parents:
diff changeset
2953 en4_const += 4;
kono
parents:
diff changeset
2954 if (cfun->machine->lp_size)
kono
parents:
diff changeset
2955 en4_const += 2;
kono
parents:
diff changeset
2956
kono
parents:
diff changeset
2957 /* If $fp, $gp, $lp, and all callee-save registers are NOT required
kono
parents:
diff changeset
2958 to be saved, we don't have to create multiple push instruction.
kono
parents:
diff changeset
2959 Otherwise, a multiple push instruction is needed. */
kono
parents:
diff changeset
2960 if (!(REGNO (Rb) == SP_REGNUM && REGNO (Re) == SP_REGNUM && en4_const == 0))
kono
parents:
diff changeset
2961 {
kono
parents:
diff changeset
2962 /* Create multiple push instruction rtx. */
kono
parents:
diff changeset
2963 nds32_emit_stack_push_multiple (Rb, Re, GEN_INT (en4_const), false);
kono
parents:
diff changeset
2964 }
kono
parents:
diff changeset
2965
kono
parents:
diff changeset
2966 /* Check frame_pointer_needed to see
kono
parents:
diff changeset
2967 if we shall emit fp adjustment instruction. */
kono
parents:
diff changeset
2968 if (frame_pointer_needed)
kono
parents:
diff changeset
2969 {
kono
parents:
diff changeset
2970 /* adjust $fp = $sp + ($fp size) + ($gp size) + ($lp size)
kono
parents:
diff changeset
2971 + (4 * callee-saved-registers)
kono
parents:
diff changeset
2972 Note: No need to adjust
kono
parents:
diff changeset
2973 cfun->machine->callee_saved_area_gpr_padding_bytes,
kono
parents:
diff changeset
2974 because, at this point, stack pointer is just
kono
parents:
diff changeset
2975 at the position after push instruction. */
kono
parents:
diff changeset
2976 fp_adjust = cfun->machine->fp_size
kono
parents:
diff changeset
2977 + cfun->machine->gp_size
kono
parents:
diff changeset
2978 + cfun->machine->lp_size
kono
parents:
diff changeset
2979 + cfun->machine->callee_saved_gpr_regs_size;
kono
parents:
diff changeset
2980 fp_adjust_insn = gen_addsi3 (hard_frame_pointer_rtx,
kono
parents:
diff changeset
2981 stack_pointer_rtx,
kono
parents:
diff changeset
2982 GEN_INT (fp_adjust));
kono
parents:
diff changeset
2983 /* Emit rtx into instructions list and receive INSN rtx form. */
kono
parents:
diff changeset
2984 fp_adjust_insn = emit_insn (fp_adjust_insn);
kono
parents:
diff changeset
2985
kono
parents:
diff changeset
2986 /* The insn rtx 'fp_adjust_insn' will change frame layout. */
kono
parents:
diff changeset
2987 RTX_FRAME_RELATED_P (fp_adjust_insn) = 1;
kono
parents:
diff changeset
2988 }
kono
parents:
diff changeset
2989
kono
parents:
diff changeset
2990 /* Adjust $sp = $sp - local_size - out_args_size
kono
parents:
diff changeset
2991 - callee_saved_area_gpr_padding_bytes. */
kono
parents:
diff changeset
2992 sp_adjust = cfun->machine->local_size
kono
parents:
diff changeset
2993 + cfun->machine->out_args_size
kono
parents:
diff changeset
2994 + cfun->machine->callee_saved_area_gpr_padding_bytes;
kono
parents:
diff changeset
2995 /* sp_adjust value may be out of range of the addi instruction,
kono
parents:
diff changeset
2996 create alternative add behavior with TA_REGNUM if necessary,
kono
parents:
diff changeset
2997 using NEGATIVE value to tell that we are decreasing address. */
kono
parents:
diff changeset
2998 sp_adjust = nds32_force_addi_stack_int ( (-1) * sp_adjust);
kono
parents:
diff changeset
2999 if (sp_adjust)
kono
parents:
diff changeset
3000 {
kono
parents:
diff changeset
3001 /* Generate sp adjustment instruction if and only if sp_adjust != 0. */
kono
parents:
diff changeset
3002 sp_adjust_insn = gen_addsi3 (stack_pointer_rtx,
kono
parents:
diff changeset
3003 stack_pointer_rtx,
kono
parents:
diff changeset
3004 GEN_INT (-1 * sp_adjust));
kono
parents:
diff changeset
3005 /* Emit rtx into instructions list and receive INSN rtx form. */
kono
parents:
diff changeset
3006 sp_adjust_insn = emit_insn (sp_adjust_insn);
kono
parents:
diff changeset
3007
kono
parents:
diff changeset
3008 /* The insn rtx 'sp_adjust_insn' will change frame layout.
kono
parents:
diff changeset
3009 We need to use RTX_FRAME_RELATED_P so that GCC is able to
kono
parents:
diff changeset
3010 generate CFI (Call Frame Information) stuff. */
kono
parents:
diff changeset
3011 RTX_FRAME_RELATED_P (sp_adjust_insn) = 1;
kono
parents:
diff changeset
3012 }
kono
parents:
diff changeset
3013
kono
parents:
diff changeset
3014 /* Prevent the instruction scheduler from
kono
parents:
diff changeset
3015 moving instructions across the boundary. */
kono
parents:
diff changeset
3016 emit_insn (gen_blockage ());
kono
parents:
diff changeset
3017 }
kono
parents:
diff changeset
3018
kono
parents:
diff changeset
3019 /* Function for normal multiple pop epilogue. */
kono
parents:
diff changeset
3020 void
kono
parents:
diff changeset
3021 nds32_expand_epilogue (bool sibcall_p)
kono
parents:
diff changeset
3022 {
kono
parents:
diff changeset
3023 int sp_adjust;
kono
parents:
diff changeset
3024 int en4_const;
kono
parents:
diff changeset
3025
kono
parents:
diff changeset
3026 rtx Rb, Re;
kono
parents:
diff changeset
3027 rtx sp_adjust_insn;
kono
parents:
diff changeset
3028
kono
parents:
diff changeset
3029 /* Compute and setup stack frame size.
kono
parents:
diff changeset
3030 The result will be in cfun->machine. */
kono
parents:
diff changeset
3031 nds32_compute_stack_frame ();
kono
parents:
diff changeset
3032
kono
parents:
diff changeset
3033 /* Prevent the instruction scheduler from
kono
parents:
diff changeset
3034 moving instructions across the boundary. */
kono
parents:
diff changeset
3035 emit_insn (gen_blockage ());
kono
parents:
diff changeset
3036
kono
parents:
diff changeset
3037 /* If the function is 'naked', we do not have to generate
kono
parents:
diff changeset
3038 epilogue code fragment BUT 'ret' instruction.
kono
parents:
diff changeset
3039 However, if this function is also a variadic function,
kono
parents:
diff changeset
3040 we need to create adjust stack pointer before 'ret' instruction. */
kono
parents:
diff changeset
3041 if (cfun->machine->naked_p)
kono
parents:
diff changeset
3042 {
kono
parents:
diff changeset
3043 /* If this is a variadic function, we do not have to restore argument
kono
parents:
diff changeset
3044 registers but need to adjust stack pointer back to previous stack
kono
parents:
diff changeset
3045 frame location before return. */
kono
parents:
diff changeset
3046 if (cfun->machine->va_args_size != 0)
kono
parents:
diff changeset
3047 {
kono
parents:
diff changeset
3048 /* Generate sp adjustment instruction.
kono
parents:
diff changeset
3049 We need to consider padding bytes here. */
kono
parents:
diff changeset
3050 sp_adjust = cfun->machine->va_args_size
kono
parents:
diff changeset
3051 + cfun->machine->va_args_area_padding_bytes;
kono
parents:
diff changeset
3052 sp_adjust_insn = gen_addsi3 (stack_pointer_rtx,
kono
parents:
diff changeset
3053 stack_pointer_rtx,
kono
parents:
diff changeset
3054 GEN_INT (sp_adjust));
kono
parents:
diff changeset
3055 /* Emit rtx into instructions list and receive INSN rtx form. */
kono
parents:
diff changeset
3056 sp_adjust_insn = emit_insn (sp_adjust_insn);
kono
parents:
diff changeset
3057
kono
parents:
diff changeset
3058 /* The insn rtx 'sp_adjust_insn' will change frame layout.
kono
parents:
diff changeset
3059 We need to use RTX_FRAME_RELATED_P so that GCC is able to
kono
parents:
diff changeset
3060 generate CFI (Call Frame Information) stuff. */
kono
parents:
diff changeset
3061 RTX_FRAME_RELATED_P (sp_adjust_insn) = 1;
kono
parents:
diff changeset
3062 }
kono
parents:
diff changeset
3063
kono
parents:
diff changeset
3064 /* Generate return instruction by using 'return_internal' pattern.
kono
parents:
diff changeset
3065 Make sure this instruction is after gen_blockage(). */
kono
parents:
diff changeset
3066 if (!sibcall_p)
kono
parents:
diff changeset
3067 emit_jump_insn (gen_return_internal ());
kono
parents:
diff changeset
3068 return;
kono
parents:
diff changeset
3069 }
kono
parents:
diff changeset
3070
kono
parents:
diff changeset
3071 if (frame_pointer_needed)
kono
parents:
diff changeset
3072 {
kono
parents:
diff changeset
3073 /* adjust $sp = $fp - ($fp size) - ($gp size) - ($lp size)
kono
parents:
diff changeset
3074 - (4 * callee-saved-registers)
kono
parents:
diff changeset
3075 Note: No need to adjust
kono
parents:
diff changeset
3076 cfun->machine->callee_saved_area_gpr_padding_bytes,
kono
parents:
diff changeset
3077 because we want to adjust stack pointer
kono
parents:
diff changeset
3078 to the position for pop instruction. */
kono
parents:
diff changeset
3079 sp_adjust = cfun->machine->fp_size
kono
parents:
diff changeset
3080 + cfun->machine->gp_size
kono
parents:
diff changeset
3081 + cfun->machine->lp_size
kono
parents:
diff changeset
3082 + cfun->machine->callee_saved_gpr_regs_size;
kono
parents:
diff changeset
3083 sp_adjust_insn = gen_addsi3 (stack_pointer_rtx,
kono
parents:
diff changeset
3084 hard_frame_pointer_rtx,
kono
parents:
diff changeset
3085 GEN_INT (-1 * sp_adjust));
kono
parents:
diff changeset
3086 /* Emit rtx into instructions list and receive INSN rtx form. */
kono
parents:
diff changeset
3087 sp_adjust_insn = emit_insn (sp_adjust_insn);
kono
parents:
diff changeset
3088
kono
parents:
diff changeset
3089 /* The insn rtx 'sp_adjust_insn' will change frame layout. */
kono
parents:
diff changeset
3090 RTX_FRAME_RELATED_P (sp_adjust_insn) = 1;
kono
parents:
diff changeset
3091 }
kono
parents:
diff changeset
3092 else
kono
parents:
diff changeset
3093 {
kono
parents:
diff changeset
3094 /* If frame pointer is NOT needed,
kono
parents:
diff changeset
3095 we cannot calculate the sp adjustment from frame pointer.
kono
parents:
diff changeset
3096 Instead, we calculate the adjustment by local_size,
kono
parents:
diff changeset
3097 out_args_size, and callee_saved_area_padding_bytes.
kono
parents:
diff changeset
3098 Notice that such sp adjustment value may be out of range,
kono
parents:
diff changeset
3099 so we have to deal with it as well. */
kono
parents:
diff changeset
3100
kono
parents:
diff changeset
3101 /* Adjust $sp = $sp + local_size + out_args_size
kono
parents:
diff changeset
3102 + callee_saved_area_padding_bytes. */
kono
parents:
diff changeset
3103 sp_adjust = cfun->machine->local_size
kono
parents:
diff changeset
3104 + cfun->machine->out_args_size
kono
parents:
diff changeset
3105 + cfun->machine->callee_saved_area_gpr_padding_bytes;
kono
parents:
diff changeset
3106 /* sp_adjust value may be out of range of the addi instruction,
kono
parents:
diff changeset
3107 create alternative add behavior with TA_REGNUM if necessary,
kono
parents:
diff changeset
3108 using POSITIVE value to tell that we are increasing address. */
kono
parents:
diff changeset
3109 sp_adjust = nds32_force_addi_stack_int (sp_adjust);
kono
parents:
diff changeset
3110 if (sp_adjust)
kono
parents:
diff changeset
3111 {
kono
parents:
diff changeset
3112 /* Generate sp adjustment instruction
kono
parents:
diff changeset
3113 if and only if sp_adjust != 0. */
kono
parents:
diff changeset
3114 sp_adjust_insn = gen_addsi3 (stack_pointer_rtx,
kono
parents:
diff changeset
3115 stack_pointer_rtx,
kono
parents:
diff changeset
3116 GEN_INT (sp_adjust));
kono
parents:
diff changeset
3117 /* Emit rtx into instructions list and receive INSN rtx form. */
kono
parents:
diff changeset
3118 sp_adjust_insn = emit_insn (sp_adjust_insn);
kono
parents:
diff changeset
3119
kono
parents:
diff changeset
3120 /* The insn rtx 'sp_adjust_insn' will change frame layout. */
kono
parents:
diff changeset
3121 RTX_FRAME_RELATED_P (sp_adjust_insn) = 1;
kono
parents:
diff changeset
3122 }
kono
parents:
diff changeset
3123 }
kono
parents:
diff changeset
3124
kono
parents:
diff changeset
3125 /* Get callee_first_regno and callee_last_regno. */
kono
parents:
diff changeset
3126 Rb = gen_rtx_REG (SImode, cfun->machine->callee_saved_first_gpr_regno);
kono
parents:
diff changeset
3127 Re = gen_rtx_REG (SImode, cfun->machine->callee_saved_last_gpr_regno);
kono
parents:
diff changeset
3128
kono
parents:
diff changeset
3129 /* nds32_emit_stack_pop_multiple(first_regno, last_regno),
kono
parents:
diff changeset
3130 the pattern 'stack_pop_multiple' is implementad in nds32.md.
kono
parents:
diff changeset
3131 For En4 field, we have to calculate its constant value.
kono
parents:
diff changeset
3132 Refer to Andes ISA for more information. */
kono
parents:
diff changeset
3133 en4_const = 0;
kono
parents:
diff changeset
3134 if (cfun->machine->fp_size)
kono
parents:
diff changeset
3135 en4_const += 8;
kono
parents:
diff changeset
3136 if (cfun->machine->gp_size)
kono
parents:
diff changeset
3137 en4_const += 4;
kono
parents:
diff changeset
3138 if (cfun->machine->lp_size)
kono
parents:
diff changeset
3139 en4_const += 2;
kono
parents:
diff changeset
3140
kono
parents:
diff changeset
3141 /* If $fp, $gp, $lp, and all callee-save registers are NOT required
kono
parents:
diff changeset
3142 to be saved, we don't have to create multiple pop instruction.
kono
parents:
diff changeset
3143 Otherwise, a multiple pop instruction is needed. */
kono
parents:
diff changeset
3144 if (!(REGNO (Rb) == SP_REGNUM && REGNO (Re) == SP_REGNUM && en4_const == 0))
kono
parents:
diff changeset
3145 {
kono
parents:
diff changeset
3146 /* Create multiple pop instruction rtx. */
kono
parents:
diff changeset
3147 nds32_emit_stack_pop_multiple (Rb, Re, GEN_INT (en4_const));
kono
parents:
diff changeset
3148 }
kono
parents:
diff changeset
3149
kono
parents:
diff changeset
3150 /* If this is a variadic function, we do not have to restore argument
kono
parents:
diff changeset
3151 registers but need to adjust stack pointer back to previous stack
kono
parents:
diff changeset
3152 frame location before return. */
kono
parents:
diff changeset
3153 if (cfun->machine->va_args_size != 0)
kono
parents:
diff changeset
3154 {
kono
parents:
diff changeset
3155 /* Generate sp adjustment instruction.
kono
parents:
diff changeset
3156 We need to consider padding bytes here. */
kono
parents:
diff changeset
3157 sp_adjust = cfun->machine->va_args_size
kono
parents:
diff changeset
3158 + cfun->machine->va_args_area_padding_bytes;
kono
parents:
diff changeset
3159 sp_adjust_insn = gen_addsi3 (stack_pointer_rtx,
kono
parents:
diff changeset
3160 stack_pointer_rtx,
kono
parents:
diff changeset
3161 GEN_INT (sp_adjust));
kono
parents:
diff changeset
3162 /* Emit rtx into instructions list and receive INSN rtx form. */
kono
parents:
diff changeset
3163 sp_adjust_insn = emit_insn (sp_adjust_insn);
kono
parents:
diff changeset
3164
kono
parents:
diff changeset
3165 /* The insn rtx 'sp_adjust_insn' will change frame layout.
kono
parents:
diff changeset
3166 We need to use RTX_FRAME_RELATED_P so that GCC is able to
kono
parents:
diff changeset
3167 generate CFI (Call Frame Information) stuff. */
kono
parents:
diff changeset
3168 RTX_FRAME_RELATED_P (sp_adjust_insn) = 1;
kono
parents:
diff changeset
3169 }
kono
parents:
diff changeset
3170
kono
parents:
diff changeset
3171 /* Generate return instruction. */
kono
parents:
diff changeset
3172 if (!sibcall_p)
kono
parents:
diff changeset
3173 emit_jump_insn (gen_return_internal ());
kono
parents:
diff changeset
3174 }
kono
parents:
diff changeset
3175
kono
parents:
diff changeset
3176 /* Function for v3push prologue. */
kono
parents:
diff changeset
3177 void
kono
parents:
diff changeset
3178 nds32_expand_prologue_v3push (void)
kono
parents:
diff changeset
3179 {
kono
parents:
diff changeset
3180 int fp_adjust;
kono
parents:
diff changeset
3181 int sp_adjust;
kono
parents:
diff changeset
3182
kono
parents:
diff changeset
3183 rtx Rb, Re;
kono
parents:
diff changeset
3184 rtx fp_adjust_insn, sp_adjust_insn;
kono
parents:
diff changeset
3185
kono
parents:
diff changeset
3186 /* Compute and setup stack frame size.
kono
parents:
diff changeset
3187 The result will be in cfun->machine. */
kono
parents:
diff changeset
3188 nds32_compute_stack_frame ();
kono
parents:
diff changeset
3189
kono
parents:
diff changeset
3190 /* If the function is 'naked',
kono
parents:
diff changeset
3191 we do not have to generate prologue code fragment. */
kono
parents:
diff changeset
3192 if (cfun->machine->naked_p)
kono
parents:
diff changeset
3193 return;
kono
parents:
diff changeset
3194
kono
parents:
diff changeset
3195 /* Get callee_first_regno and callee_last_regno. */
kono
parents:
diff changeset
3196 Rb = gen_rtx_REG (SImode, cfun->machine->callee_saved_first_gpr_regno);
kono
parents:
diff changeset
3197 Re = gen_rtx_REG (SImode, cfun->machine->callee_saved_last_gpr_regno);
kono
parents:
diff changeset
3198
kono
parents:
diff changeset
3199 /* Calculate sp_adjust first to test if 'push25 Re,imm8u' is available,
kono
parents:
diff changeset
3200 where imm8u has to be 8-byte alignment. */
kono
parents:
diff changeset
3201 sp_adjust = cfun->machine->local_size
kono
parents:
diff changeset
3202 + cfun->machine->out_args_size
kono
parents:
diff changeset
3203 + cfun->machine->callee_saved_area_gpr_padding_bytes;
kono
parents:
diff changeset
3204
kono
parents:
diff changeset
3205 if (satisfies_constraint_Iu08 (GEN_INT (sp_adjust))
kono
parents:
diff changeset
3206 && NDS32_DOUBLE_WORD_ALIGN_P (sp_adjust))
kono
parents:
diff changeset
3207 {
kono
parents:
diff changeset
3208 /* We can use 'push25 Re,imm8u'. */
kono
parents:
diff changeset
3209
kono
parents:
diff changeset
3210 /* nds32_emit_stack_v3push(last_regno, sp_adjust),
kono
parents:
diff changeset
3211 the pattern 'stack_v3push' is implemented in nds32.md.
kono
parents:
diff changeset
3212 The (const_int 14) means v3push always push { $fp $gp $lp }. */
kono
parents:
diff changeset
3213 nds32_emit_stack_v3push (Rb, Re,
kono
parents:
diff changeset
3214 GEN_INT (14), GEN_INT (sp_adjust));
kono
parents:
diff changeset
3215
kono
parents:
diff changeset
3216 /* Check frame_pointer_needed to see
kono
parents:
diff changeset
3217 if we shall emit fp adjustment instruction. */
kono
parents:
diff changeset
3218 if (frame_pointer_needed)
kono
parents:
diff changeset
3219 {
kono
parents:
diff changeset
3220 /* adjust $fp = $sp + 4 ($fp size)
kono
parents:
diff changeset
3221 + 4 ($gp size)
kono
parents:
diff changeset
3222 + 4 ($lp size)
kono
parents:
diff changeset
3223 + (4 * n) (callee-saved registers)
kono
parents:
diff changeset
3224 + sp_adjust ('push25 Re,imm8u')
kono
parents:
diff changeset
3225 Note: Since we use 'push25 Re,imm8u',
kono
parents:
diff changeset
3226 the position of stack pointer is further
kono
parents:
diff changeset
3227 changed after push instruction.
kono
parents:
diff changeset
3228 Hence, we need to take sp_adjust value
kono
parents:
diff changeset
3229 into consideration. */
kono
parents:
diff changeset
3230 fp_adjust = cfun->machine->fp_size
kono
parents:
diff changeset
3231 + cfun->machine->gp_size
kono
parents:
diff changeset
3232 + cfun->machine->lp_size
kono
parents:
diff changeset
3233 + cfun->machine->callee_saved_gpr_regs_size
kono
parents:
diff changeset
3234 + sp_adjust;
kono
parents:
diff changeset
3235 fp_adjust_insn = gen_addsi3 (hard_frame_pointer_rtx,
kono
parents:
diff changeset
3236 stack_pointer_rtx,
kono
parents:
diff changeset
3237 GEN_INT (fp_adjust));
kono
parents:
diff changeset
3238 /* Emit rtx into instructions list and receive INSN rtx form. */
kono
parents:
diff changeset
3239 fp_adjust_insn = emit_insn (fp_adjust_insn);
kono
parents:
diff changeset
3240 }
kono
parents:
diff changeset
3241 }
kono
parents:
diff changeset
3242 else
kono
parents:
diff changeset
3243 {
kono
parents:
diff changeset
3244 /* We have to use 'push25 Re,0' and
kono
parents:
diff changeset
3245 expand one more instruction to adjust $sp later. */
kono
parents:
diff changeset
3246
kono
parents:
diff changeset
3247 /* nds32_emit_stack_v3push(last_regno, sp_adjust),
kono
parents:
diff changeset
3248 the pattern 'stack_v3push' is implemented in nds32.md.
kono
parents:
diff changeset
3249 The (const_int 14) means v3push always push { $fp $gp $lp }. */
kono
parents:
diff changeset
3250 nds32_emit_stack_v3push (Rb, Re,
kono
parents:
diff changeset
3251 GEN_INT (14), GEN_INT (0));
kono
parents:
diff changeset
3252
kono
parents:
diff changeset
3253 /* Check frame_pointer_needed to see
kono
parents:
diff changeset
3254 if we shall emit fp adjustment instruction. */
kono
parents:
diff changeset
3255 if (frame_pointer_needed)
kono
parents:
diff changeset
3256 {
kono
parents:
diff changeset
3257 /* adjust $fp = $sp + 4 ($fp size)
kono
parents:
diff changeset
3258 + 4 ($gp size)
kono
parents:
diff changeset
3259 + 4 ($lp size)
kono
parents:
diff changeset
3260 + (4 * n) (callee-saved registers)
kono
parents:
diff changeset
3261 Note: Since we use 'push25 Re,0',
kono
parents:
diff changeset
3262 the stack pointer is just at the position
kono
parents:
diff changeset
3263 after push instruction.
kono
parents:
diff changeset
3264 No need to take sp_adjust into consideration. */
kono
parents:
diff changeset
3265 fp_adjust = cfun->machine->fp_size
kono
parents:
diff changeset
3266 + cfun->machine->gp_size
kono
parents:
diff changeset
3267 + cfun->machine->lp_size
kono
parents:
diff changeset
3268 + cfun->machine->callee_saved_gpr_regs_size;
kono
parents:
diff changeset
3269 fp_adjust_insn = gen_addsi3 (hard_frame_pointer_rtx,
kono
parents:
diff changeset
3270 stack_pointer_rtx,
kono
parents:
diff changeset
3271 GEN_INT (fp_adjust));
kono
parents:
diff changeset
3272 /* Emit rtx into instructions list and receive INSN rtx form. */
kono
parents:
diff changeset
3273 fp_adjust_insn = emit_insn (fp_adjust_insn);
kono
parents:
diff changeset
3274 }
kono
parents:
diff changeset
3275
kono
parents:
diff changeset
3276 /* Because we use 'push25 Re,0',
kono
parents:
diff changeset
3277 we need to expand one more instruction to adjust $sp.
kono
parents:
diff changeset
3278 However, sp_adjust value may be out of range of the addi instruction,
kono
parents:
diff changeset
3279 create alternative add behavior with TA_REGNUM if necessary,
kono
parents:
diff changeset
3280 using NEGATIVE value to tell that we are decreasing address. */
kono
parents:
diff changeset
3281 sp_adjust = nds32_force_addi_stack_int ( (-1) * sp_adjust);
kono
parents:
diff changeset
3282 if (sp_adjust)
kono
parents:
diff changeset
3283 {
kono
parents:
diff changeset
3284 /* Generate sp adjustment instruction
kono
parents:
diff changeset
3285 if and only if sp_adjust != 0. */
kono
parents:
diff changeset
3286 sp_adjust_insn = gen_addsi3 (stack_pointer_rtx,
kono
parents:
diff changeset
3287 stack_pointer_rtx,
kono
parents:
diff changeset
3288 GEN_INT (-1 * sp_adjust));
kono
parents:
diff changeset
3289 /* Emit rtx into instructions list and receive INSN rtx form. */
kono
parents:
diff changeset
3290 sp_adjust_insn = emit_insn (sp_adjust_insn);
kono
parents:
diff changeset
3291
kono
parents:
diff changeset
3292 /* The insn rtx 'sp_adjust_insn' will change frame layout.
kono
parents:
diff changeset
3293 We need to use RTX_FRAME_RELATED_P so that GCC is able to
kono
parents:
diff changeset
3294 generate CFI (Call Frame Information) stuff. */
kono
parents:
diff changeset
3295 RTX_FRAME_RELATED_P (sp_adjust_insn) = 1;
kono
parents:
diff changeset
3296 }
kono
parents:
diff changeset
3297 }
kono
parents:
diff changeset
3298
kono
parents:
diff changeset
3299 /* Prevent the instruction scheduler from
kono
parents:
diff changeset
3300 moving instructions across the boundary. */
kono
parents:
diff changeset
3301 emit_insn (gen_blockage ());
kono
parents:
diff changeset
3302 }
kono
parents:
diff changeset
3303
kono
parents:
diff changeset
3304 /* Function for v3pop epilogue. */
kono
parents:
diff changeset
3305 void
kono
parents:
diff changeset
3306 nds32_expand_epilogue_v3pop (bool sibcall_p)
kono
parents:
diff changeset
3307 {
kono
parents:
diff changeset
3308 int sp_adjust;
kono
parents:
diff changeset
3309
kono
parents:
diff changeset
3310 rtx Rb, Re;
kono
parents:
diff changeset
3311 rtx sp_adjust_insn;
kono
parents:
diff changeset
3312
kono
parents:
diff changeset
3313 /* Compute and setup stack frame size.
kono
parents:
diff changeset
3314 The result will be in cfun->machine. */
kono
parents:
diff changeset
3315 nds32_compute_stack_frame ();
kono
parents:
diff changeset
3316
kono
parents:
diff changeset
3317 /* Prevent the instruction scheduler from
kono
parents:
diff changeset
3318 moving instructions across the boundary. */
kono
parents:
diff changeset
3319 emit_insn (gen_blockage ());
kono
parents:
diff changeset
3320
kono
parents:
diff changeset
3321 /* If the function is 'naked', we do not have to generate
kono
parents:
diff changeset
3322 epilogue code fragment BUT 'ret' instruction. */
kono
parents:
diff changeset
3323 if (cfun->machine->naked_p)
kono
parents:
diff changeset
3324 {
kono
parents:
diff changeset
3325 /* Generate return instruction by using 'return_internal' pattern.
kono
parents:
diff changeset
3326 Make sure this instruction is after gen_blockage(). */
kono
parents:
diff changeset
3327 if (!sibcall_p)
kono
parents:
diff changeset
3328 emit_jump_insn (gen_return_internal ());
kono
parents:
diff changeset
3329 return;
kono
parents:
diff changeset
3330 }
kono
parents:
diff changeset
3331
kono
parents:
diff changeset
3332 /* Get callee_first_regno and callee_last_regno. */
kono
parents:
diff changeset
3333 Rb = gen_rtx_REG (SImode, cfun->machine->callee_saved_first_gpr_regno);
kono
parents:
diff changeset
3334 Re = gen_rtx_REG (SImode, cfun->machine->callee_saved_last_gpr_regno);
kono
parents:
diff changeset
3335
kono
parents:
diff changeset
3336 /* Calculate sp_adjust first to test if 'pop25 Re,imm8u' is available,
kono
parents:
diff changeset
3337 where imm8u has to be 8-byte alignment. */
kono
parents:
diff changeset
3338 sp_adjust = cfun->machine->local_size
kono
parents:
diff changeset
3339 + cfun->machine->out_args_size
kono
parents:
diff changeset
3340 + cfun->machine->callee_saved_area_gpr_padding_bytes;
kono
parents:
diff changeset
3341
kono
parents:
diff changeset
3342 /* We have to consider alloca issue as well.
kono
parents:
diff changeset
3343 If the function does call alloca(), the stack pointer is not fixed.
kono
parents:
diff changeset
3344 In that case, we cannot use 'pop25 Re,imm8u' directly.
kono
parents:
diff changeset
3345 We have to caculate stack pointer from frame pointer
kono
parents:
diff changeset
3346 and then use 'pop25 Re,0'.
kono
parents:
diff changeset
3347 Of course, the frame_pointer_needed should be nonzero
kono
parents:
diff changeset
3348 if the function calls alloca(). */
kono
parents:
diff changeset
3349 if (satisfies_constraint_Iu08 (GEN_INT (sp_adjust))
kono
parents:
diff changeset
3350 && NDS32_DOUBLE_WORD_ALIGN_P (sp_adjust)
kono
parents:
diff changeset
3351 && !cfun->calls_alloca)
kono
parents:
diff changeset
3352 {
kono
parents:
diff changeset
3353 /* We can use 'pop25 Re,imm8u'. */
kono
parents:
diff changeset
3354
kono
parents:
diff changeset
3355 /* nds32_emit_stack_v3pop(last_regno, sp_adjust),
kono
parents:
diff changeset
3356 the pattern 'stack_v3pop' is implementad in nds32.md.
kono
parents:
diff changeset
3357 The (const_int 14) means v3pop always pop { $fp $gp $lp }. */
kono
parents:
diff changeset
3358 nds32_emit_stack_v3pop (Rb, Re,
kono
parents:
diff changeset
3359 GEN_INT (14), GEN_INT (sp_adjust));
kono
parents:
diff changeset
3360 }
kono
parents:
diff changeset
3361 else
kono
parents:
diff changeset
3362 {
kono
parents:
diff changeset
3363 /* We have to use 'pop25 Re,0', and prior to it,
kono
parents:
diff changeset
3364 we must expand one more instruction to adjust $sp. */
kono
parents:
diff changeset
3365
kono
parents:
diff changeset
3366 if (frame_pointer_needed)
kono
parents:
diff changeset
3367 {
kono
parents:
diff changeset
3368 /* adjust $sp = $fp - 4 ($fp size)
kono
parents:
diff changeset
3369 - 4 ($gp size)
kono
parents:
diff changeset
3370 - 4 ($lp size)
kono
parents:
diff changeset
3371 - (4 * n) (callee-saved registers)
kono
parents:
diff changeset
3372 Note: No need to adjust
kono
parents:
diff changeset
3373 cfun->machine->callee_saved_area_gpr_padding_bytes,
kono
parents:
diff changeset
3374 because we want to adjust stack pointer
kono
parents:
diff changeset
3375 to the position for pop instruction. */
kono
parents:
diff changeset
3376 sp_adjust = cfun->machine->fp_size
kono
parents:
diff changeset
3377 + cfun->machine->gp_size
kono
parents:
diff changeset
3378 + cfun->machine->lp_size
kono
parents:
diff changeset
3379 + cfun->machine->callee_saved_gpr_regs_size;
kono
parents:
diff changeset
3380 sp_adjust_insn = gen_addsi3 (stack_pointer_rtx,
kono
parents:
diff changeset
3381 hard_frame_pointer_rtx,
kono
parents:
diff changeset
3382 GEN_INT (-1 * sp_adjust));
kono
parents:
diff changeset
3383 /* Emit rtx into instructions list and receive INSN rtx form. */
kono
parents:
diff changeset
3384 sp_adjust_insn = emit_insn (sp_adjust_insn);
kono
parents:
diff changeset
3385 }
kono
parents:
diff changeset
3386 else
kono
parents:
diff changeset
3387 {
kono
parents:
diff changeset
3388 /* If frame pointer is NOT needed,
kono
parents:
diff changeset
3389 we cannot calculate the sp adjustment from frame pointer.
kono
parents:
diff changeset
3390 Instead, we calculate the adjustment by local_size,
kono
parents:
diff changeset
3391 out_args_size, and callee_saved_area_padding_bytes.
kono
parents:
diff changeset
3392 Notice that such sp adjustment value may be out of range,
kono
parents:
diff changeset
3393 so we have to deal with it as well. */
kono
parents:
diff changeset
3394
kono
parents:
diff changeset
3395 /* Adjust $sp = $sp + local_size + out_args_size
kono
parents:
diff changeset
3396 + callee_saved_area_gpr_padding_bytes. */
kono
parents:
diff changeset
3397 sp_adjust = cfun->machine->local_size
kono
parents:
diff changeset
3398 + cfun->machine->out_args_size
kono
parents:
diff changeset
3399 + cfun->machine->callee_saved_area_gpr_padding_bytes;
kono
parents:
diff changeset
3400 /* sp_adjust value may be out of range of the addi instruction,
kono
parents:
diff changeset
3401 create alternative add behavior with TA_REGNUM if necessary,
kono
parents:
diff changeset
3402 using POSITIVE value to tell that we are increasing address. */
kono
parents:
diff changeset
3403 sp_adjust = nds32_force_addi_stack_int (sp_adjust);
kono
parents:
diff changeset
3404 if (sp_adjust)
kono
parents:
diff changeset
3405 {
kono
parents:
diff changeset
3406 /* Generate sp adjustment instruction
kono
parents:
diff changeset
3407 if and only if sp_adjust != 0. */
kono
parents:
diff changeset
3408 sp_adjust_insn = gen_addsi3 (stack_pointer_rtx,
kono
parents:
diff changeset
3409 stack_pointer_rtx,
kono
parents:
diff changeset
3410 GEN_INT (sp_adjust));
kono
parents:
diff changeset
3411 /* Emit rtx into instructions list and receive INSN rtx form. */
kono
parents:
diff changeset
3412 sp_adjust_insn = emit_insn (sp_adjust_insn);
kono
parents:
diff changeset
3413 }
kono
parents:
diff changeset
3414 }
kono
parents:
diff changeset
3415
kono
parents:
diff changeset
3416 /* nds32_emit_stack_v3pop(last_regno, sp_adjust),
kono
parents:
diff changeset
3417 the pattern 'stack_v3pop' is implementad in nds32.md. */
kono
parents:
diff changeset
3418 /* The (const_int 14) means v3pop always pop { $fp $gp $lp }. */
kono
parents:
diff changeset
3419 nds32_emit_stack_v3pop (Rb, Re,
kono
parents:
diff changeset
3420 GEN_INT (14), GEN_INT (0));
kono
parents:
diff changeset
3421 }
kono
parents:
diff changeset
3422
kono
parents:
diff changeset
3423 /* Generate return instruction. */
kono
parents:
diff changeset
3424 emit_jump_insn (gen_pop25return ());
kono
parents:
diff changeset
3425 }
kono
parents:
diff changeset
3426
kono
parents:
diff changeset
3427 /* Return nonzero if this function is known to have a null epilogue.
kono
parents:
diff changeset
3428 This allows the optimizer to omit jumps to jumps if no stack
kono
parents:
diff changeset
3429 was created. */
kono
parents:
diff changeset
3430 int
kono
parents:
diff changeset
3431 nds32_can_use_return_insn (void)
kono
parents:
diff changeset
3432 {
kono
parents:
diff changeset
3433 /* Prior to reloading, we can't tell how many registers must be saved.
kono
parents:
diff changeset
3434 Thus we can not determine whether this function has null epilogue. */
kono
parents:
diff changeset
3435 if (!reload_completed)
kono
parents:
diff changeset
3436 return 0;
kono
parents:
diff changeset
3437
kono
parents:
diff changeset
3438 /* If no stack was created, two conditions must be satisfied:
kono
parents:
diff changeset
3439 1. This is a naked function.
kono
parents:
diff changeset
3440 So there is no callee-saved, local size, or outgoing size.
kono
parents:
diff changeset
3441 2. This is NOT a variadic function.
kono
parents:
diff changeset
3442 So there is no pushing arguement registers into the stack. */
kono
parents:
diff changeset
3443 return (cfun->machine->naked_p && (cfun->machine->va_args_size == 0));
kono
parents:
diff changeset
3444 }
kono
parents:
diff changeset
3445
kono
parents:
diff changeset
3446 /* ------------------------------------------------------------------------ */
kono
parents:
diff changeset
3447
kono
parents:
diff changeset
3448 /* Function to test 333-form for load/store instructions.
kono
parents:
diff changeset
3449 This is auxiliary extern function for auxiliary macro in nds32.h.
kono
parents:
diff changeset
3450 Because it is a little complicated, we use function instead of macro. */
kono
parents:
diff changeset
3451 bool
kono
parents:
diff changeset
3452 nds32_ls_333_p (rtx rt, rtx ra, rtx imm, machine_mode mode)
kono
parents:
diff changeset
3453 {
kono
parents:
diff changeset
3454 if (REGNO_REG_CLASS (REGNO (rt)) == LOW_REGS
kono
parents:
diff changeset
3455 && REGNO_REG_CLASS (REGNO (ra)) == LOW_REGS)
kono
parents:
diff changeset
3456 {
kono
parents:
diff changeset
3457 if (GET_MODE_SIZE (mode) == 4)
kono
parents:
diff changeset
3458 return satisfies_constraint_Iu05 (imm);
kono
parents:
diff changeset
3459
kono
parents:
diff changeset
3460 if (GET_MODE_SIZE (mode) == 2)
kono
parents:
diff changeset
3461 return satisfies_constraint_Iu04 (imm);
kono
parents:
diff changeset
3462
kono
parents:
diff changeset
3463 if (GET_MODE_SIZE (mode) == 1)
kono
parents:
diff changeset
3464 return satisfies_constraint_Iu03 (imm);
kono
parents:
diff changeset
3465 }
kono
parents:
diff changeset
3466
kono
parents:
diff changeset
3467 return false;
kono
parents:
diff changeset
3468 }
kono
parents:
diff changeset
3469
kono
parents:
diff changeset
3470
kono
parents:
diff changeset
3471 /* Computing the Length of an Insn.
kono
parents:
diff changeset
3472 Modifies the length assigned to instruction INSN.
kono
parents:
diff changeset
3473 LEN is the initially computed length of the insn. */
kono
parents:
diff changeset
3474 int
kono
parents:
diff changeset
3475 nds32_adjust_insn_length (rtx_insn *insn, int length)
kono
parents:
diff changeset
3476 {
kono
parents:
diff changeset
3477 rtx src, dst;
kono
parents:
diff changeset
3478
kono
parents:
diff changeset
3479 switch (recog_memoized (insn))
kono
parents:
diff changeset
3480 {
kono
parents:
diff changeset
3481 case CODE_FOR_move_df:
kono
parents:
diff changeset
3482 case CODE_FOR_move_di:
kono
parents:
diff changeset
3483 /* Adjust length of movd44 to 2. */
kono
parents:
diff changeset
3484 src = XEXP (PATTERN (insn), 1);
kono
parents:
diff changeset
3485 dst = XEXP (PATTERN (insn), 0);
kono
parents:
diff changeset
3486
kono
parents:
diff changeset
3487 if (REG_P (src)
kono
parents:
diff changeset
3488 && REG_P (dst)
kono
parents:
diff changeset
3489 && (REGNO (src) % 2) == 0
kono
parents:
diff changeset
3490 && (REGNO (dst) % 2) == 0)
kono
parents:
diff changeset
3491 length = 2;
kono
parents:
diff changeset
3492 break;
kono
parents:
diff changeset
3493
kono
parents:
diff changeset
3494 default:
kono
parents:
diff changeset
3495 break;
kono
parents:
diff changeset
3496 }
kono
parents:
diff changeset
3497
kono
parents:
diff changeset
3498 return length;
kono
parents:
diff changeset
3499 }
kono
parents:
diff changeset
3500
kono
parents:
diff changeset
3501
kono
parents:
diff changeset
3502 /* Return align 2 (log base 2) if the next instruction of LABEL is 4 byte. */
kono
parents:
diff changeset
3503 int
kono
parents:
diff changeset
3504 nds32_target_alignment (rtx_insn *label)
kono
parents:
diff changeset
3505 {
kono
parents:
diff changeset
3506 rtx_insn *insn;
kono
parents:
diff changeset
3507
kono
parents:
diff changeset
3508 if (optimize_size)
kono
parents:
diff changeset
3509 return 0;
kono
parents:
diff changeset
3510
kono
parents:
diff changeset
3511 insn = next_active_insn (label);
kono
parents:
diff changeset
3512
kono
parents:
diff changeset
3513 if (insn == 0)
kono
parents:
diff changeset
3514 return 0;
kono
parents:
diff changeset
3515 else if ((get_attr_length (insn) % 4) == 0)
kono
parents:
diff changeset
3516 return 2;
kono
parents:
diff changeset
3517 else
kono
parents:
diff changeset
3518 return 0;
kono
parents:
diff changeset
3519 }
kono
parents:
diff changeset
3520
kono
parents:
diff changeset
3521 /* ------------------------------------------------------------------------ */
kono
parents:
diff changeset
3522
kono
parents:
diff changeset
3523 /* PART 5: Initialize target hook structure and definitions. */
kono
parents:
diff changeset
3524
kono
parents:
diff changeset
3525 /* Controlling the Compilation Driver. */
kono
parents:
diff changeset
3526
kono
parents:
diff changeset
3527
kono
parents:
diff changeset
3528 /* Run-time Target Specification. */
kono
parents:
diff changeset
3529
kono
parents:
diff changeset
3530
kono
parents:
diff changeset
3531 /* Defining Data Structures for Per-function Information. */
kono
parents:
diff changeset
3532
kono
parents:
diff changeset
3533
kono
parents:
diff changeset
3534 /* Storage Layout. */
kono
parents:
diff changeset
3535
kono
parents:
diff changeset
3536 #undef TARGET_PROMOTE_FUNCTION_MODE
kono
parents:
diff changeset
3537 #define TARGET_PROMOTE_FUNCTION_MODE \
kono
parents:
diff changeset
3538 default_promote_function_mode_always_promote
kono
parents:
diff changeset
3539
kono
parents:
diff changeset
3540
kono
parents:
diff changeset
3541 /* Layout of Source Language Data Types. */
kono
parents:
diff changeset
3542
kono
parents:
diff changeset
3543
kono
parents:
diff changeset
3544 /* Register Usage. */
kono
parents:
diff changeset
3545
kono
parents:
diff changeset
3546 /* -- Basic Characteristics of Registers. */
kono
parents:
diff changeset
3547
kono
parents:
diff changeset
3548 /* -- Order of Allocation of Registers. */
kono
parents:
diff changeset
3549
kono
parents:
diff changeset
3550 /* -- How Values Fit in Registers. */
kono
parents:
diff changeset
3551
kono
parents:
diff changeset
3552 /* -- Handling Leaf Functions. */
kono
parents:
diff changeset
3553
kono
parents:
diff changeset
3554 /* -- Registers That Form a Stack. */
kono
parents:
diff changeset
3555
kono
parents:
diff changeset
3556
kono
parents:
diff changeset
3557 /* Register Classes. */
kono
parents:
diff changeset
3558
kono
parents:
diff changeset
3559 #undef TARGET_CLASS_MAX_NREGS
kono
parents:
diff changeset
3560 #define TARGET_CLASS_MAX_NREGS nds32_class_max_nregs
kono
parents:
diff changeset
3561
kono
parents:
diff changeset
3562 #undef TARGET_REGISTER_PRIORITY
kono
parents:
diff changeset
3563 #define TARGET_REGISTER_PRIORITY nds32_register_priority
kono
parents:
diff changeset
3564
kono
parents:
diff changeset
3565
kono
parents:
diff changeset
3566 /* Obsolete Macros for Defining Constraints. */
kono
parents:
diff changeset
3567
kono
parents:
diff changeset
3568
kono
parents:
diff changeset
3569 /* Stack Layout and Calling Conventions. */
kono
parents:
diff changeset
3570
kono
parents:
diff changeset
3571 /* -- Basic Stack Layout. */
kono
parents:
diff changeset
3572
kono
parents:
diff changeset
3573 /* -- Exception Handling Support. */
kono
parents:
diff changeset
3574
kono
parents:
diff changeset
3575 /* -- Specifying How Stack Checking is Done. */
kono
parents:
diff changeset
3576
kono
parents:
diff changeset
3577 /* -- Registers That Address the Stack Frame. */
kono
parents:
diff changeset
3578
kono
parents:
diff changeset
3579 /* -- Eliminating Frame Pointer and Arg Pointer. */
kono
parents:
diff changeset
3580
kono
parents:
diff changeset
3581 #undef TARGET_CAN_ELIMINATE
kono
parents:
diff changeset
3582 #define TARGET_CAN_ELIMINATE nds32_can_eliminate
kono
parents:
diff changeset
3583
kono
parents:
diff changeset
3584 /* -- Passing Function Arguments on the Stack. */
kono
parents:
diff changeset
3585
kono
parents:
diff changeset
3586 /* -- Passing Arguments in Registers. */
kono
parents:
diff changeset
3587
kono
parents:
diff changeset
3588 #undef TARGET_FUNCTION_ARG
kono
parents:
diff changeset
3589 #define TARGET_FUNCTION_ARG nds32_function_arg
kono
parents:
diff changeset
3590
kono
parents:
diff changeset
3591 #undef TARGET_MUST_PASS_IN_STACK
kono
parents:
diff changeset
3592 #define TARGET_MUST_PASS_IN_STACK nds32_must_pass_in_stack
kono
parents:
diff changeset
3593
kono
parents:
diff changeset
3594 #undef TARGET_ARG_PARTIAL_BYTES
kono
parents:
diff changeset
3595 #define TARGET_ARG_PARTIAL_BYTES nds32_arg_partial_bytes
kono
parents:
diff changeset
3596
kono
parents:
diff changeset
3597 #undef TARGET_FUNCTION_ARG_ADVANCE
kono
parents:
diff changeset
3598 #define TARGET_FUNCTION_ARG_ADVANCE nds32_function_arg_advance
kono
parents:
diff changeset
3599
kono
parents:
diff changeset
3600 #undef TARGET_FUNCTION_ARG_BOUNDARY
kono
parents:
diff changeset
3601 #define TARGET_FUNCTION_ARG_BOUNDARY nds32_function_arg_boundary
kono
parents:
diff changeset
3602
kono
parents:
diff changeset
3603 /* -- How Scalar Function Values Are Returned. */
kono
parents:
diff changeset
3604
kono
parents:
diff changeset
3605 #undef TARGET_FUNCTION_VALUE
kono
parents:
diff changeset
3606 #define TARGET_FUNCTION_VALUE nds32_function_value
kono
parents:
diff changeset
3607
kono
parents:
diff changeset
3608 #undef TARGET_LIBCALL_VALUE
kono
parents:
diff changeset
3609 #define TARGET_LIBCALL_VALUE nds32_libcall_value
kono
parents:
diff changeset
3610
kono
parents:
diff changeset
3611 #undef TARGET_FUNCTION_VALUE_REGNO_P
kono
parents:
diff changeset
3612 #define TARGET_FUNCTION_VALUE_REGNO_P nds32_function_value_regno_p
kono
parents:
diff changeset
3613
kono
parents:
diff changeset
3614 /* -- How Large Values Are Returned. */
kono
parents:
diff changeset
3615
kono
parents:
diff changeset
3616 /* -- Caller-Saves Register Allocation. */
kono
parents:
diff changeset
3617
kono
parents:
diff changeset
3618 /* -- Function Entry and Exit. */
kono
parents:
diff changeset
3619
kono
parents:
diff changeset
3620 #undef TARGET_ASM_FUNCTION_PROLOGUE
kono
parents:
diff changeset
3621 #define TARGET_ASM_FUNCTION_PROLOGUE nds32_asm_function_prologue
kono
parents:
diff changeset
3622
kono
parents:
diff changeset
3623 #undef TARGET_ASM_FUNCTION_END_PROLOGUE
kono
parents:
diff changeset
3624 #define TARGET_ASM_FUNCTION_END_PROLOGUE nds32_asm_function_end_prologue
kono
parents:
diff changeset
3625
kono
parents:
diff changeset
3626 #undef TARGET_ASM_FUNCTION_BEGIN_EPILOGUE
kono
parents:
diff changeset
3627 #define TARGET_ASM_FUNCTION_BEGIN_EPILOGUE nds32_asm_function_begin_epilogue
kono
parents:
diff changeset
3628
kono
parents:
diff changeset
3629 #undef TARGET_ASM_FUNCTION_EPILOGUE
kono
parents:
diff changeset
3630 #define TARGET_ASM_FUNCTION_EPILOGUE nds32_asm_function_epilogue
kono
parents:
diff changeset
3631
kono
parents:
diff changeset
3632 #undef TARGET_ASM_OUTPUT_MI_THUNK
kono
parents:
diff changeset
3633 #define TARGET_ASM_OUTPUT_MI_THUNK nds32_asm_output_mi_thunk
kono
parents:
diff changeset
3634
kono
parents:
diff changeset
3635 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
kono
parents:
diff changeset
3636 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK default_can_output_mi_thunk_no_vcall
kono
parents:
diff changeset
3637
kono
parents:
diff changeset
3638 /* -- Generating Code for Profiling. */
kono
parents:
diff changeset
3639
kono
parents:
diff changeset
3640 /* -- Permitting tail calls. */
kono
parents:
diff changeset
3641
kono
parents:
diff changeset
3642 #undef TARGET_WARN_FUNC_RETURN
kono
parents:
diff changeset
3643 #define TARGET_WARN_FUNC_RETURN nds32_warn_func_return
kono
parents:
diff changeset
3644
kono
parents:
diff changeset
3645 /* Stack smashing protection. */
kono
parents:
diff changeset
3646
kono
parents:
diff changeset
3647
kono
parents:
diff changeset
3648 /* Implementing the Varargs Macros. */
kono
parents:
diff changeset
3649
kono
parents:
diff changeset
3650 #undef TARGET_SETUP_INCOMING_VARARGS
kono
parents:
diff changeset
3651 #define TARGET_SETUP_INCOMING_VARARGS nds32_setup_incoming_varargs
kono
parents:
diff changeset
3652
kono
parents:
diff changeset
3653 #undef TARGET_STRICT_ARGUMENT_NAMING
kono
parents:
diff changeset
3654 #define TARGET_STRICT_ARGUMENT_NAMING nds32_strict_argument_naming
kono
parents:
diff changeset
3655
kono
parents:
diff changeset
3656
kono
parents:
diff changeset
3657 /* Trampolines for Nested Functions. */
kono
parents:
diff changeset
3658
kono
parents:
diff changeset
3659 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
kono
parents:
diff changeset
3660 #define TARGET_ASM_TRAMPOLINE_TEMPLATE nds32_asm_trampoline_template
kono
parents:
diff changeset
3661
kono
parents:
diff changeset
3662 #undef TARGET_TRAMPOLINE_INIT
kono
parents:
diff changeset
3663 #define TARGET_TRAMPOLINE_INIT nds32_trampoline_init
kono
parents:
diff changeset
3664
kono
parents:
diff changeset
3665
kono
parents:
diff changeset
3666 /* Implicit Calls to Library Routines. */
kono
parents:
diff changeset
3667
kono
parents:
diff changeset
3668
kono
parents:
diff changeset
3669 /* Addressing Modes. */
kono
parents:
diff changeset
3670
kono
parents:
diff changeset
3671 #undef TARGET_LEGITIMATE_ADDRESS_P
kono
parents:
diff changeset
3672 #define TARGET_LEGITIMATE_ADDRESS_P nds32_legitimate_address_p
kono
parents:
diff changeset
3673
kono
parents:
diff changeset
3674
kono
parents:
diff changeset
3675 /* Anchored Addresses. */
kono
parents:
diff changeset
3676
kono
parents:
diff changeset
3677
kono
parents:
diff changeset
3678 /* Condition Code Status. */
kono
parents:
diff changeset
3679
kono
parents:
diff changeset
3680 /* -- Representation of condition codes using (cc0). */
kono
parents:
diff changeset
3681
kono
parents:
diff changeset
3682 /* -- Representation of condition codes using registers. */
kono
parents:
diff changeset
3683
kono
parents:
diff changeset
3684 /* -- Macros to control conditional execution. */
kono
parents:
diff changeset
3685
kono
parents:
diff changeset
3686
kono
parents:
diff changeset
3687 /* Describing Relative Costs of Operations. */
kono
parents:
diff changeset
3688
kono
parents:
diff changeset
3689 #undef TARGET_REGISTER_MOVE_COST
kono
parents:
diff changeset
3690 #define TARGET_REGISTER_MOVE_COST nds32_register_move_cost
kono
parents:
diff changeset
3691
kono
parents:
diff changeset
3692 #undef TARGET_MEMORY_MOVE_COST
kono
parents:
diff changeset
3693 #define TARGET_MEMORY_MOVE_COST nds32_memory_move_cost
kono
parents:
diff changeset
3694
kono
parents:
diff changeset
3695 #undef TARGET_RTX_COSTS
kono
parents:
diff changeset
3696 #define TARGET_RTX_COSTS nds32_rtx_costs
kono
parents:
diff changeset
3697
kono
parents:
diff changeset
3698 #undef TARGET_ADDRESS_COST
kono
parents:
diff changeset
3699 #define TARGET_ADDRESS_COST nds32_address_cost
kono
parents:
diff changeset
3700
kono
parents:
diff changeset
3701
kono
parents:
diff changeset
3702 /* Adjusting the Instruction Scheduler. */
kono
parents:
diff changeset
3703
kono
parents:
diff changeset
3704
kono
parents:
diff changeset
3705 /* Dividing the Output into Sections (Texts, Data, . . . ). */
kono
parents:
diff changeset
3706
kono
parents:
diff changeset
3707 #undef TARGET_ENCODE_SECTION_INFO
kono
parents:
diff changeset
3708 #define TARGET_ENCODE_SECTION_INFO nds32_encode_section_info
kono
parents:
diff changeset
3709
kono
parents:
diff changeset
3710
kono
parents:
diff changeset
3711 /* Position Independent Code. */
kono
parents:
diff changeset
3712
kono
parents:
diff changeset
3713
kono
parents:
diff changeset
3714 /* Defining the Output Assembler Language. */
kono
parents:
diff changeset
3715
kono
parents:
diff changeset
3716 /* -- The Overall Framework of an Assembler File. */
kono
parents:
diff changeset
3717
kono
parents:
diff changeset
3718 #undef TARGET_ASM_FILE_START
kono
parents:
diff changeset
3719 #define TARGET_ASM_FILE_START nds32_asm_file_start
kono
parents:
diff changeset
3720 #undef TARGET_ASM_FILE_END
kono
parents:
diff changeset
3721 #define TARGET_ASM_FILE_END nds32_asm_file_end
kono
parents:
diff changeset
3722
kono
parents:
diff changeset
3723 /* -- Output of Data. */
kono
parents:
diff changeset
3724
kono
parents:
diff changeset
3725 #undef TARGET_ASM_ALIGNED_HI_OP
kono
parents:
diff changeset
3726 #define TARGET_ASM_ALIGNED_HI_OP "\t.hword\t"
kono
parents:
diff changeset
3727
kono
parents:
diff changeset
3728 #undef TARGET_ASM_ALIGNED_SI_OP
kono
parents:
diff changeset
3729 #define TARGET_ASM_ALIGNED_SI_OP "\t.word\t"
kono
parents:
diff changeset
3730
kono
parents:
diff changeset
3731 /* -- Output of Uninitialized Variables. */
kono
parents:
diff changeset
3732
kono
parents:
diff changeset
3733 /* -- Output and Generation of Labels. */
kono
parents:
diff changeset
3734
kono
parents:
diff changeset
3735 #undef TARGET_ASM_GLOBALIZE_LABEL
kono
parents:
diff changeset
3736 #define TARGET_ASM_GLOBALIZE_LABEL nds32_asm_globalize_label
kono
parents:
diff changeset
3737
kono
parents:
diff changeset
3738 /* -- How Initialization Functions Are Handled. */
kono
parents:
diff changeset
3739
kono
parents:
diff changeset
3740 /* -- Macros Controlling Initialization Routines. */
kono
parents:
diff changeset
3741
kono
parents:
diff changeset
3742 /* -- Output of Assembler Instructions. */
kono
parents:
diff changeset
3743
kono
parents:
diff changeset
3744 #undef TARGET_PRINT_OPERAND
kono
parents:
diff changeset
3745 #define TARGET_PRINT_OPERAND nds32_print_operand
kono
parents:
diff changeset
3746 #undef TARGET_PRINT_OPERAND_ADDRESS
kono
parents:
diff changeset
3747 #define TARGET_PRINT_OPERAND_ADDRESS nds32_print_operand_address
kono
parents:
diff changeset
3748
kono
parents:
diff changeset
3749 /* -- Output of Dispatch Tables. */
kono
parents:
diff changeset
3750
kono
parents:
diff changeset
3751 /* -- Assembler Commands for Exception Regions. */
kono
parents:
diff changeset
3752
kono
parents:
diff changeset
3753 /* -- Assembler Commands for Alignment. */
kono
parents:
diff changeset
3754
kono
parents:
diff changeset
3755
kono
parents:
diff changeset
3756 /* Controlling Debugging Information Format. */
kono
parents:
diff changeset
3757
kono
parents:
diff changeset
3758 /* -- Macros Affecting All Debugging Formats. */
kono
parents:
diff changeset
3759
kono
parents:
diff changeset
3760 /* -- Specific Options for DBX Output. */
kono
parents:
diff changeset
3761
kono
parents:
diff changeset
3762 /* -- Open-Ended Hooks for DBX Format. */
kono
parents:
diff changeset
3763
kono
parents:
diff changeset
3764 /* -- File Names in DBX Format. */
kono
parents:
diff changeset
3765
kono
parents:
diff changeset
3766 /* -- Macros for SDB and DWARF Output. */
kono
parents:
diff changeset
3767
kono
parents:
diff changeset
3768 /* -- Macros for VMS Debug Format. */
kono
parents:
diff changeset
3769
kono
parents:
diff changeset
3770
kono
parents:
diff changeset
3771 /* Cross Compilation and Floating Point. */
kono
parents:
diff changeset
3772
kono
parents:
diff changeset
3773
kono
parents:
diff changeset
3774 /* Mode Switching Instructions. */
kono
parents:
diff changeset
3775
kono
parents:
diff changeset
3776
kono
parents:
diff changeset
3777 /* Defining target-specific uses of __attribute__. */
kono
parents:
diff changeset
3778
kono
parents:
diff changeset
3779 #undef TARGET_ATTRIBUTE_TABLE
kono
parents:
diff changeset
3780 #define TARGET_ATTRIBUTE_TABLE nds32_attribute_table
kono
parents:
diff changeset
3781
kono
parents:
diff changeset
3782 #undef TARGET_MERGE_DECL_ATTRIBUTES
kono
parents:
diff changeset
3783 #define TARGET_MERGE_DECL_ATTRIBUTES nds32_merge_decl_attributes
kono
parents:
diff changeset
3784
kono
parents:
diff changeset
3785 #undef TARGET_INSERT_ATTRIBUTES
kono
parents:
diff changeset
3786 #define TARGET_INSERT_ATTRIBUTES nds32_insert_attributes
kono
parents:
diff changeset
3787
kono
parents:
diff changeset
3788 #undef TARGET_OPTION_PRAGMA_PARSE
kono
parents:
diff changeset
3789 #define TARGET_OPTION_PRAGMA_PARSE nds32_option_pragma_parse
kono
parents:
diff changeset
3790
kono
parents:
diff changeset
3791 #undef TARGET_OPTION_OVERRIDE
kono
parents:
diff changeset
3792 #define TARGET_OPTION_OVERRIDE nds32_option_override
kono
parents:
diff changeset
3793
kono
parents:
diff changeset
3794
kono
parents:
diff changeset
3795 /* Emulating TLS. */
kono
parents:
diff changeset
3796
kono
parents:
diff changeset
3797
kono
parents:
diff changeset
3798 /* Defining coprocessor specifics for MIPS targets. */
kono
parents:
diff changeset
3799
kono
parents:
diff changeset
3800
kono
parents:
diff changeset
3801 /* Parameters for Precompiled Header Validity Checking. */
kono
parents:
diff changeset
3802
kono
parents:
diff changeset
3803
kono
parents:
diff changeset
3804 /* C++ ABI parameters. */
kono
parents:
diff changeset
3805
kono
parents:
diff changeset
3806
kono
parents:
diff changeset
3807 /* Adding support for named address spaces. */
kono
parents:
diff changeset
3808
kono
parents:
diff changeset
3809
kono
parents:
diff changeset
3810 /* Miscellaneous Parameters. */
kono
parents:
diff changeset
3811
kono
parents:
diff changeset
3812 #undef TARGET_INIT_BUILTINS
kono
parents:
diff changeset
3813 #define TARGET_INIT_BUILTINS nds32_init_builtins
kono
parents:
diff changeset
3814
kono
parents:
diff changeset
3815 #undef TARGET_EXPAND_BUILTIN
kono
parents:
diff changeset
3816 #define TARGET_EXPAND_BUILTIN nds32_expand_builtin
kono
parents:
diff changeset
3817
kono
parents:
diff changeset
3818
kono
parents:
diff changeset
3819 /* ------------------------------------------------------------------------ */
kono
parents:
diff changeset
3820
kono
parents:
diff changeset
3821 /* Initialize the GCC target structure. */
kono
parents:
diff changeset
3822
kono
parents:
diff changeset
3823 struct gcc_target targetm = TARGET_INITIALIZER;
kono
parents:
diff changeset
3824
kono
parents:
diff changeset
3825 /* ------------------------------------------------------------------------ */