Merged trunk at revision 161680 into branch.
[official-gcc.git] / gcc / config / bfin / bfin.c
blob1232ecc7378d01613f5fc17fbbe7c6bd9dec2d6d
1 /* The Blackfin code generation auxiliary output file.
2 Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010
3 Free Software Foundation, Inc.
4 Contributed by Analog Devices.
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published
10 by the Free Software Foundation; either version 3, or (at your
11 option) any later version.
13 GCC is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16 License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. */
22 #include "config.h"
23 #include "system.h"
24 #include "coretypes.h"
25 #include "tm.h"
26 #include "rtl.h"
27 #include "regs.h"
28 #include "hard-reg-set.h"
29 #include "insn-config.h"
30 #include "insn-codes.h"
31 #include "conditions.h"
32 #include "insn-flags.h"
33 #include "output.h"
34 #include "insn-attr.h"
35 #include "tree.h"
36 #include "flags.h"
37 #include "except.h"
38 #include "function.h"
39 #include "input.h"
40 #include "target.h"
41 #include "target-def.h"
42 #include "expr.h"
43 #include "toplev.h"
44 #include "recog.h"
45 #include "optabs.h"
46 #include "ggc.h"
47 #include "integrate.h"
48 #include "cgraph.h"
49 #include "langhooks.h"
50 #include "bfin-protos.h"
51 #include "tm-preds.h"
52 #include "tm-constrs.h"
53 #include "gt-bfin.h"
54 #include "basic-block.h"
55 #include "cfglayout.h"
56 #include "timevar.h"
57 #include "df.h"
59 /* A C structure for machine-specific, per-function data.
60 This is added to the cfun structure. */
61 struct GTY(()) machine_function
63 /* Set if we are notified by the doloop pass that a hardware loop
64 was created. */
65 int has_hardware_loops;
67 /* Set if we create a memcpy pattern that uses loop registers. */
68 int has_loopreg_clobber;
71 /* RTX for condition code flag register and RETS register */
72 extern GTY(()) rtx bfin_cc_rtx;
73 extern GTY(()) rtx bfin_rets_rtx;
74 rtx bfin_cc_rtx, bfin_rets_rtx;
76 int max_arg_registers = 0;
78 /* Arrays used when emitting register names. */
79 const char *short_reg_names[] = SHORT_REGISTER_NAMES;
80 const char *high_reg_names[] = HIGH_REGISTER_NAMES;
81 const char *dregs_pair_names[] = DREGS_PAIR_NAMES;
82 const char *byte_reg_names[] = BYTE_REGISTER_NAMES;
84 static int arg_regs[] = FUNCTION_ARG_REGISTERS;
85 static int ret_regs[] = FUNCTION_RETURN_REGISTERS;
87 /* Nonzero if -mshared-library-id was given. */
88 static int bfin_lib_id_given;
90 /* Nonzero if -fschedule-insns2 was given. We override it and
91 call the scheduler ourselves during reorg. */
92 static int bfin_flag_schedule_insns2;
94 /* Determines whether we run variable tracking in machine dependent
95 reorganization. */
96 static int bfin_flag_var_tracking;
98 /* -mcpu support */
99 bfin_cpu_t bfin_cpu_type = BFIN_CPU_UNKNOWN;
101 /* -msi-revision support. There are three special values:
102 -1 -msi-revision=none.
103 0xffff -msi-revision=any. */
104 int bfin_si_revision;
106 /* The workarounds enabled */
107 unsigned int bfin_workarounds = 0;
109 struct bfin_cpu
111 const char *name;
112 bfin_cpu_t type;
113 int si_revision;
114 unsigned int workarounds;
117 struct bfin_cpu bfin_cpus[] =
119 {"bf512", BFIN_CPU_BF512, 0x0000,
120 WA_SPECULATIVE_LOADS | WA_05000074},
122 {"bf514", BFIN_CPU_BF514, 0x0000,
123 WA_SPECULATIVE_LOADS | WA_05000074},
125 {"bf516", BFIN_CPU_BF516, 0x0000,
126 WA_SPECULATIVE_LOADS | WA_05000074},
128 {"bf518", BFIN_CPU_BF518, 0x0000,
129 WA_SPECULATIVE_LOADS | WA_05000074},
131 {"bf522", BFIN_CPU_BF522, 0x0002,
132 WA_SPECULATIVE_LOADS | WA_05000074},
133 {"bf522", BFIN_CPU_BF522, 0x0001,
134 WA_SPECULATIVE_LOADS | WA_RETS | WA_05000074},
135 {"bf522", BFIN_CPU_BF522, 0x0000,
136 WA_SPECULATIVE_LOADS | WA_RETS | WA_05000074},
138 {"bf523", BFIN_CPU_BF523, 0x0002,
139 WA_SPECULATIVE_LOADS | WA_05000074},
140 {"bf523", BFIN_CPU_BF523, 0x0001,
141 WA_SPECULATIVE_LOADS | WA_RETS | WA_05000074},
142 {"bf523", BFIN_CPU_BF523, 0x0000,
143 WA_SPECULATIVE_LOADS | WA_RETS | WA_05000074},
145 {"bf524", BFIN_CPU_BF524, 0x0002,
146 WA_SPECULATIVE_LOADS | WA_05000074},
147 {"bf524", BFIN_CPU_BF524, 0x0001,
148 WA_SPECULATIVE_LOADS | WA_RETS | WA_05000074},
149 {"bf524", BFIN_CPU_BF524, 0x0000,
150 WA_SPECULATIVE_LOADS | WA_RETS | WA_05000074},
152 {"bf525", BFIN_CPU_BF525, 0x0002,
153 WA_SPECULATIVE_LOADS | WA_05000074},
154 {"bf525", BFIN_CPU_BF525, 0x0001,
155 WA_SPECULATIVE_LOADS | WA_RETS | WA_05000074},
156 {"bf525", BFIN_CPU_BF525, 0x0000,
157 WA_SPECULATIVE_LOADS | WA_RETS | WA_05000074},
159 {"bf526", BFIN_CPU_BF526, 0x0002,
160 WA_SPECULATIVE_LOADS | WA_05000074},
161 {"bf526", BFIN_CPU_BF526, 0x0001,
162 WA_SPECULATIVE_LOADS | WA_RETS | WA_05000074},
163 {"bf526", BFIN_CPU_BF526, 0x0000,
164 WA_SPECULATIVE_LOADS | WA_RETS | WA_05000074},
166 {"bf527", BFIN_CPU_BF527, 0x0002,
167 WA_SPECULATIVE_LOADS | WA_05000074},
168 {"bf527", BFIN_CPU_BF527, 0x0001,
169 WA_SPECULATIVE_LOADS | WA_RETS | WA_05000074},
170 {"bf527", BFIN_CPU_BF527, 0x0000,
171 WA_SPECULATIVE_LOADS | WA_RETS | WA_05000074},
173 {"bf531", BFIN_CPU_BF531, 0x0006,
174 WA_SPECULATIVE_LOADS | WA_LOAD_LCREGS | WA_05000074},
175 {"bf531", BFIN_CPU_BF531, 0x0005,
176 WA_SPECULATIVE_LOADS | WA_RETS | WA_05000283 | WA_05000315
177 | WA_LOAD_LCREGS | WA_05000074},
178 {"bf531", BFIN_CPU_BF531, 0x0004,
179 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
180 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS
181 | WA_05000074},
182 {"bf531", BFIN_CPU_BF531, 0x0003,
183 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
184 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS
185 | WA_05000074},
187 {"bf532", BFIN_CPU_BF532, 0x0006,
188 WA_SPECULATIVE_LOADS | WA_LOAD_LCREGS | WA_05000074},
189 {"bf532", BFIN_CPU_BF532, 0x0005,
190 WA_SPECULATIVE_LOADS | WA_RETS | WA_05000283 | WA_05000315
191 | WA_LOAD_LCREGS | WA_05000074},
192 {"bf532", BFIN_CPU_BF532, 0x0004,
193 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
194 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS
195 | WA_05000074},
196 {"bf532", BFIN_CPU_BF532, 0x0003,
197 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
198 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS
199 | WA_05000074},
201 {"bf533", BFIN_CPU_BF533, 0x0006,
202 WA_SPECULATIVE_LOADS | WA_LOAD_LCREGS | WA_05000074},
203 {"bf533", BFIN_CPU_BF533, 0x0005,
204 WA_SPECULATIVE_LOADS | WA_RETS | WA_05000283 | WA_05000315
205 | WA_LOAD_LCREGS | WA_05000074},
206 {"bf533", BFIN_CPU_BF533, 0x0004,
207 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
208 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS
209 | WA_05000074},
210 {"bf533", BFIN_CPU_BF533, 0x0003,
211 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
212 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS
213 | WA_05000074},
215 {"bf534", BFIN_CPU_BF534, 0x0003,
216 WA_SPECULATIVE_LOADS | WA_RETS | WA_LOAD_LCREGS | WA_05000074},
217 {"bf534", BFIN_CPU_BF534, 0x0002,
218 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
219 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS
220 | WA_05000074},
221 {"bf534", BFIN_CPU_BF534, 0x0001,
222 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
223 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS
224 | WA_05000074},
226 {"bf536", BFIN_CPU_BF536, 0x0003,
227 WA_SPECULATIVE_LOADS | WA_RETS | WA_LOAD_LCREGS | WA_05000074},
228 {"bf536", BFIN_CPU_BF536, 0x0002,
229 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
230 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS
231 | WA_05000074},
232 {"bf536", BFIN_CPU_BF536, 0x0001,
233 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
234 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS
235 | WA_05000074},
237 {"bf537", BFIN_CPU_BF537, 0x0003,
238 WA_SPECULATIVE_LOADS | WA_RETS | WA_LOAD_LCREGS | WA_05000074},
239 {"bf537", BFIN_CPU_BF537, 0x0002,
240 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
241 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS
242 | WA_05000074},
243 {"bf537", BFIN_CPU_BF537, 0x0001,
244 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
245 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS
246 | WA_05000074},
248 {"bf538", BFIN_CPU_BF538, 0x0005,
249 WA_SPECULATIVE_LOADS | WA_LOAD_LCREGS | WA_05000074},
250 {"bf538", BFIN_CPU_BF538, 0x0004,
251 WA_SPECULATIVE_LOADS | WA_RETS | WA_LOAD_LCREGS | WA_05000074},
252 {"bf538", BFIN_CPU_BF538, 0x0003,
253 WA_SPECULATIVE_LOADS | WA_RETS
254 | WA_05000283 | WA_05000315 | WA_LOAD_LCREGS | WA_05000074},
255 {"bf538", BFIN_CPU_BF538, 0x0002,
256 WA_SPECULATIVE_LOADS | WA_RETS
257 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS
258 | WA_05000074},
260 {"bf539", BFIN_CPU_BF539, 0x0005,
261 WA_SPECULATIVE_LOADS | WA_LOAD_LCREGS | WA_05000074},
262 {"bf539", BFIN_CPU_BF539, 0x0004,
263 WA_SPECULATIVE_LOADS | WA_RETS | WA_LOAD_LCREGS | WA_05000074},
264 {"bf539", BFIN_CPU_BF539, 0x0003,
265 WA_SPECULATIVE_LOADS | WA_RETS
266 | WA_05000283 | WA_05000315 | WA_LOAD_LCREGS | WA_05000074},
267 {"bf539", BFIN_CPU_BF539, 0x0002,
268 WA_SPECULATIVE_LOADS | WA_RETS
269 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS
270 | WA_05000074},
272 {"bf542m", BFIN_CPU_BF542M, 0x0003,
273 WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS | WA_05000074},
275 {"bf542", BFIN_CPU_BF542, 0x0002,
276 WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS | WA_05000074},
277 {"bf542", BFIN_CPU_BF542, 0x0001,
278 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS | WA_05000074},
279 {"bf542", BFIN_CPU_BF542, 0x0000,
280 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS | WA_LOAD_LCREGS
281 | WA_05000074},
283 {"bf544m", BFIN_CPU_BF544M, 0x0003,
284 WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS | WA_05000074},
286 {"bf544", BFIN_CPU_BF544, 0x0002,
287 WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS | WA_05000074},
288 {"bf544", BFIN_CPU_BF544, 0x0001,
289 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS | WA_05000074},
290 {"bf544", BFIN_CPU_BF544, 0x0000,
291 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS | WA_LOAD_LCREGS
292 | WA_05000074},
294 {"bf547m", BFIN_CPU_BF547M, 0x0003,
295 WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS | WA_05000074},
297 {"bf547", BFIN_CPU_BF547, 0x0002,
298 WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS | WA_05000074},
299 {"bf547", BFIN_CPU_BF547, 0x0001,
300 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS | WA_05000074},
301 {"bf547", BFIN_CPU_BF547, 0x0000,
302 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS | WA_LOAD_LCREGS
303 | WA_05000074},
305 {"bf548m", BFIN_CPU_BF548M, 0x0003,
306 WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS | WA_05000074},
308 {"bf548", BFIN_CPU_BF548, 0x0002,
309 WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS | WA_05000074},
310 {"bf548", BFIN_CPU_BF548, 0x0001,
311 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS | WA_05000074},
312 {"bf548", BFIN_CPU_BF548, 0x0000,
313 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS | WA_LOAD_LCREGS
314 | WA_05000074},
316 {"bf549m", BFIN_CPU_BF549M, 0x0003,
317 WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS | WA_05000074},
319 {"bf549", BFIN_CPU_BF549, 0x0002,
320 WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS | WA_05000074},
321 {"bf549", BFIN_CPU_BF549, 0x0001,
322 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS | WA_05000074},
323 {"bf549", BFIN_CPU_BF549, 0x0000,
324 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS | WA_LOAD_LCREGS
325 | WA_05000074},
327 {"bf561", BFIN_CPU_BF561, 0x0005, WA_RETS
328 | WA_05000283 | WA_05000315 | WA_LOAD_LCREGS | WA_05000074},
329 {"bf561", BFIN_CPU_BF561, 0x0003,
330 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
331 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS
332 | WA_05000074},
333 {"bf561", BFIN_CPU_BF561, 0x0002,
334 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
335 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS
336 | WA_05000074},
338 {NULL, 0, 0, 0}
341 int splitting_for_sched, splitting_loops;
343 static void
344 bfin_globalize_label (FILE *stream, const char *name)
346 fputs (".global ", stream);
347 assemble_name (stream, name);
348 fputc (';',stream);
349 fputc ('\n',stream);
352 static void
353 output_file_start (void)
355 FILE *file = asm_out_file;
356 int i;
358 /* Variable tracking should be run after all optimizations which change order
359 of insns. It also needs a valid CFG. This can't be done in
360 override_options, because flag_var_tracking is finalized after
361 that. */
362 bfin_flag_var_tracking = flag_var_tracking;
363 flag_var_tracking = 0;
365 fprintf (file, ".file \"%s\";\n", input_filename);
367 for (i = 0; arg_regs[i] >= 0; i++)
369 max_arg_registers = i; /* how many arg reg used */
372 /* Called early in the compilation to conditionally modify
373 fixed_regs/call_used_regs. */
375 void
376 conditional_register_usage (void)
378 /* initialize condition code flag register rtx */
379 bfin_cc_rtx = gen_rtx_REG (BImode, REG_CC);
380 bfin_rets_rtx = gen_rtx_REG (Pmode, REG_RETS);
383 /* Examine machine-dependent attributes of function type FUNTYPE and return its
384 type. See the definition of E_FUNKIND. */
386 static e_funkind
387 funkind (const_tree funtype)
389 tree attrs = TYPE_ATTRIBUTES (funtype);
390 if (lookup_attribute ("interrupt_handler", attrs))
391 return INTERRUPT_HANDLER;
392 else if (lookup_attribute ("exception_handler", attrs))
393 return EXCPT_HANDLER;
394 else if (lookup_attribute ("nmi_handler", attrs))
395 return NMI_HANDLER;
396 else
397 return SUBROUTINE;
400 /* Legitimize PIC addresses. If the address is already position-independent,
401 we return ORIG. Newly generated position-independent addresses go into a
402 reg. This is REG if nonzero, otherwise we allocate register(s) as
403 necessary. PICREG is the register holding the pointer to the PIC offset
404 table. */
406 static rtx
407 legitimize_pic_address (rtx orig, rtx reg, rtx picreg)
409 rtx addr = orig;
410 rtx new_rtx = orig;
412 if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == LABEL_REF)
414 int unspec;
415 rtx tmp;
417 if (TARGET_ID_SHARED_LIBRARY)
418 unspec = UNSPEC_MOVE_PIC;
419 else if (GET_CODE (addr) == SYMBOL_REF
420 && SYMBOL_REF_FUNCTION_P (addr))
421 unspec = UNSPEC_FUNCDESC_GOT17M4;
422 else
423 unspec = UNSPEC_MOVE_FDPIC;
425 if (reg == 0)
427 gcc_assert (can_create_pseudo_p ());
428 reg = gen_reg_rtx (Pmode);
431 tmp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), unspec);
432 new_rtx = gen_const_mem (Pmode, gen_rtx_PLUS (Pmode, picreg, tmp));
434 emit_move_insn (reg, new_rtx);
435 if (picreg == pic_offset_table_rtx)
436 crtl->uses_pic_offset_table = 1;
437 return reg;
440 else if (GET_CODE (addr) == CONST || GET_CODE (addr) == PLUS)
442 rtx base;
444 if (GET_CODE (addr) == CONST)
446 addr = XEXP (addr, 0);
447 gcc_assert (GET_CODE (addr) == PLUS);
450 if (XEXP (addr, 0) == picreg)
451 return orig;
453 if (reg == 0)
455 gcc_assert (can_create_pseudo_p ());
456 reg = gen_reg_rtx (Pmode);
459 base = legitimize_pic_address (XEXP (addr, 0), reg, picreg);
460 addr = legitimize_pic_address (XEXP (addr, 1),
461 base == reg ? NULL_RTX : reg,
462 picreg);
464 if (GET_CODE (addr) == CONST_INT)
466 gcc_assert (! reload_in_progress && ! reload_completed);
467 addr = force_reg (Pmode, addr);
470 if (GET_CODE (addr) == PLUS && CONSTANT_P (XEXP (addr, 1)))
472 base = gen_rtx_PLUS (Pmode, base, XEXP (addr, 0));
473 addr = XEXP (addr, 1);
476 return gen_rtx_PLUS (Pmode, base, addr);
479 return new_rtx;
482 /* Stack frame layout. */
484 /* For a given REGNO, determine whether it must be saved in the function
485 prologue. IS_INTHANDLER specifies whether we're generating a normal
486 prologue or an interrupt/exception one. */
487 static bool
488 must_save_p (bool is_inthandler, unsigned regno)
490 if (D_REGNO_P (regno))
492 bool is_eh_return_reg = false;
493 if (crtl->calls_eh_return)
495 unsigned j;
496 for (j = 0; ; j++)
498 unsigned test = EH_RETURN_DATA_REGNO (j);
499 if (test == INVALID_REGNUM)
500 break;
501 if (test == regno)
502 is_eh_return_reg = true;
506 return (is_eh_return_reg
507 || (df_regs_ever_live_p (regno)
508 && !fixed_regs[regno]
509 && (is_inthandler || !call_used_regs[regno])));
511 else if (P_REGNO_P (regno))
513 return ((df_regs_ever_live_p (regno)
514 && !fixed_regs[regno]
515 && (is_inthandler || !call_used_regs[regno]))
516 || (is_inthandler
517 && (ENABLE_WA_05000283 || ENABLE_WA_05000315)
518 && regno == REG_P5)
519 || (!TARGET_FDPIC
520 && regno == PIC_OFFSET_TABLE_REGNUM
521 && (crtl->uses_pic_offset_table
522 || (TARGET_ID_SHARED_LIBRARY && !current_function_is_leaf))));
524 else
525 return ((is_inthandler || !call_used_regs[regno])
526 && (df_regs_ever_live_p (regno)
527 || (!leaf_function_p () && call_used_regs[regno])));
531 /* Compute the number of DREGS to save with a push_multiple operation.
532 This could include registers that aren't modified in the function,
533 since push_multiple only takes a range of registers.
534 If IS_INTHANDLER, then everything that is live must be saved, even
535 if normally call-clobbered.
536 If CONSECUTIVE, return the number of registers we can save in one
537 instruction with a push/pop multiple instruction. */
539 static int
540 n_dregs_to_save (bool is_inthandler, bool consecutive)
542 int count = 0;
543 unsigned i;
545 for (i = REG_R7 + 1; i-- != REG_R0;)
547 if (must_save_p (is_inthandler, i))
548 count++;
549 else if (consecutive)
550 return count;
552 return count;
555 /* Like n_dregs_to_save, but compute number of PREGS to save. */
557 static int
558 n_pregs_to_save (bool is_inthandler, bool consecutive)
560 int count = 0;
561 unsigned i;
563 for (i = REG_P5 + 1; i-- != REG_P0;)
564 if (must_save_p (is_inthandler, i))
565 count++;
566 else if (consecutive)
567 return count;
568 return count;
571 /* Determine if we are going to save the frame pointer in the prologue. */
573 static bool
574 must_save_fp_p (void)
576 return df_regs_ever_live_p (REG_FP);
579 /* Determine if we are going to save the RETS register. */
580 static bool
581 must_save_rets_p (void)
583 return df_regs_ever_live_p (REG_RETS);
586 static bool
587 stack_frame_needed_p (void)
589 /* EH return puts a new return address into the frame using an
590 address relative to the frame pointer. */
591 if (crtl->calls_eh_return)
592 return true;
593 return frame_pointer_needed;
596 /* Emit code to save registers in the prologue. SAVEALL is nonzero if we
597 must save all registers; this is used for interrupt handlers.
598 SPREG contains (reg:SI REG_SP). IS_INTHANDLER is true if we're doing
599 this for an interrupt (or exception) handler. */
601 static void
602 expand_prologue_reg_save (rtx spreg, int saveall, bool is_inthandler)
604 rtx predec1 = gen_rtx_PRE_DEC (SImode, spreg);
605 rtx predec = gen_rtx_MEM (SImode, predec1);
606 int ndregs = saveall ? 8 : n_dregs_to_save (is_inthandler, false);
607 int npregs = saveall ? 6 : n_pregs_to_save (is_inthandler, false);
608 int ndregs_consec = saveall ? 8 : n_dregs_to_save (is_inthandler, true);
609 int npregs_consec = saveall ? 6 : n_pregs_to_save (is_inthandler, true);
610 int dregno, pregno;
611 int total_consec = ndregs_consec + npregs_consec;
612 int i, d_to_save;
614 if (saveall || is_inthandler)
616 rtx insn = emit_move_insn (predec, gen_rtx_REG (SImode, REG_ASTAT));
618 RTX_FRAME_RELATED_P (insn) = 1;
619 for (dregno = REG_LT0; dregno <= REG_LB1; dregno++)
620 if (! current_function_is_leaf
621 || cfun->machine->has_hardware_loops
622 || cfun->machine->has_loopreg_clobber
623 || (ENABLE_WA_05000257
624 && (dregno == REG_LC0 || dregno == REG_LC1)))
626 insn = emit_move_insn (predec, gen_rtx_REG (SImode, dregno));
627 RTX_FRAME_RELATED_P (insn) = 1;
631 if (total_consec != 0)
633 rtx insn;
634 rtx val = GEN_INT (-total_consec * 4);
635 rtx pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total_consec + 2));
637 XVECEXP (pat, 0, 0) = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, val),
638 UNSPEC_PUSH_MULTIPLE);
639 XVECEXP (pat, 0, total_consec + 1) = gen_rtx_SET (VOIDmode, spreg,
640 gen_rtx_PLUS (Pmode,
641 spreg,
642 val));
643 RTX_FRAME_RELATED_P (XVECEXP (pat, 0, total_consec + 1)) = 1;
644 d_to_save = ndregs_consec;
645 dregno = REG_R7 + 1 - ndregs_consec;
646 pregno = REG_P5 + 1 - npregs_consec;
647 for (i = 0; i < total_consec; i++)
649 rtx memref = gen_rtx_MEM (word_mode,
650 gen_rtx_PLUS (Pmode, spreg,
651 GEN_INT (- i * 4 - 4)));
652 rtx subpat;
653 if (d_to_save > 0)
655 subpat = gen_rtx_SET (VOIDmode, memref, gen_rtx_REG (word_mode,
656 dregno++));
657 d_to_save--;
659 else
661 subpat = gen_rtx_SET (VOIDmode, memref, gen_rtx_REG (word_mode,
662 pregno++));
664 XVECEXP (pat, 0, i + 1) = subpat;
665 RTX_FRAME_RELATED_P (subpat) = 1;
667 insn = emit_insn (pat);
668 RTX_FRAME_RELATED_P (insn) = 1;
671 for (dregno = REG_R0; ndregs != ndregs_consec; dregno++)
673 if (must_save_p (is_inthandler, dregno))
675 rtx insn = emit_move_insn (predec, gen_rtx_REG (word_mode, dregno));
676 RTX_FRAME_RELATED_P (insn) = 1;
677 ndregs--;
680 for (pregno = REG_P0; npregs != npregs_consec; pregno++)
682 if (must_save_p (is_inthandler, pregno))
684 rtx insn = emit_move_insn (predec, gen_rtx_REG (word_mode, pregno));
685 RTX_FRAME_RELATED_P (insn) = 1;
686 npregs--;
689 for (i = REG_P7 + 1; i < REG_CC; i++)
690 if (saveall
691 || (is_inthandler
692 && (df_regs_ever_live_p (i)
693 || (!leaf_function_p () && call_used_regs[i]))))
695 rtx insn;
696 if (i == REG_A0 || i == REG_A1)
697 insn = emit_move_insn (gen_rtx_MEM (PDImode, predec1),
698 gen_rtx_REG (PDImode, i));
699 else
700 insn = emit_move_insn (predec, gen_rtx_REG (SImode, i));
701 RTX_FRAME_RELATED_P (insn) = 1;
705 /* Emit code to restore registers in the epilogue. SAVEALL is nonzero if we
706 must save all registers; this is used for interrupt handlers.
707 SPREG contains (reg:SI REG_SP). IS_INTHANDLER is true if we're doing
708 this for an interrupt (or exception) handler. */
710 static void
711 expand_epilogue_reg_restore (rtx spreg, bool saveall, bool is_inthandler)
713 rtx postinc1 = gen_rtx_POST_INC (SImode, spreg);
714 rtx postinc = gen_rtx_MEM (SImode, postinc1);
716 int ndregs = saveall ? 8 : n_dregs_to_save (is_inthandler, false);
717 int npregs = saveall ? 6 : n_pregs_to_save (is_inthandler, false);
718 int ndregs_consec = saveall ? 8 : n_dregs_to_save (is_inthandler, true);
719 int npregs_consec = saveall ? 6 : n_pregs_to_save (is_inthandler, true);
720 int total_consec = ndregs_consec + npregs_consec;
721 int i, regno;
722 rtx insn;
724 /* A slightly crude technique to stop flow from trying to delete "dead"
725 insns. */
726 MEM_VOLATILE_P (postinc) = 1;
728 for (i = REG_CC - 1; i > REG_P7; i--)
729 if (saveall
730 || (is_inthandler
731 && (df_regs_ever_live_p (i)
732 || (!leaf_function_p () && call_used_regs[i]))))
734 if (i == REG_A0 || i == REG_A1)
736 rtx mem = gen_rtx_MEM (PDImode, postinc1);
737 MEM_VOLATILE_P (mem) = 1;
738 emit_move_insn (gen_rtx_REG (PDImode, i), mem);
740 else
741 emit_move_insn (gen_rtx_REG (SImode, i), postinc);
744 regno = REG_P5 - npregs_consec;
745 for (; npregs != npregs_consec; regno--)
747 if (must_save_p (is_inthandler, regno))
749 emit_move_insn (gen_rtx_REG (word_mode, regno), postinc);
750 npregs--;
753 regno = REG_R7 - ndregs_consec;
754 for (; ndregs != ndregs_consec; regno--)
756 if (must_save_p (is_inthandler, regno))
758 emit_move_insn (gen_rtx_REG (word_mode, regno), postinc);
759 ndregs--;
763 if (total_consec != 0)
765 rtx pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total_consec + 1));
766 XVECEXP (pat, 0, 0)
767 = gen_rtx_SET (VOIDmode, spreg,
768 gen_rtx_PLUS (Pmode, spreg,
769 GEN_INT (total_consec * 4)));
771 if (npregs_consec > 0)
772 regno = REG_P5 + 1;
773 else
774 regno = REG_R7 + 1;
776 for (i = 0; i < total_consec; i++)
778 rtx addr = (i > 0
779 ? gen_rtx_PLUS (Pmode, spreg, GEN_INT (i * 4))
780 : spreg);
781 rtx memref = gen_rtx_MEM (word_mode, addr);
783 regno--;
784 XVECEXP (pat, 0, i + 1)
785 = gen_rtx_SET (VOIDmode, gen_rtx_REG (word_mode, regno), memref);
787 if (npregs_consec > 0)
789 if (--npregs_consec == 0)
790 regno = REG_R7 + 1;
794 insn = emit_insn (pat);
795 RTX_FRAME_RELATED_P (insn) = 1;
797 if (saveall || is_inthandler)
799 for (regno = REG_LB1; regno >= REG_LT0; regno--)
800 if (! current_function_is_leaf
801 || cfun->machine->has_hardware_loops
802 || cfun->machine->has_loopreg_clobber
803 || (ENABLE_WA_05000257 && (regno == REG_LC0 || regno == REG_LC1)))
804 emit_move_insn (gen_rtx_REG (SImode, regno), postinc);
806 emit_move_insn (gen_rtx_REG (SImode, REG_ASTAT), postinc);
810 /* Perform any needed actions needed for a function that is receiving a
811 variable number of arguments.
813 CUM is as above.
815 MODE and TYPE are the mode and type of the current parameter.
817 PRETEND_SIZE is a variable that should be set to the amount of stack
818 that must be pushed by the prolog to pretend that our caller pushed
821 Normally, this macro will push all remaining incoming registers on the
822 stack and set PRETEND_SIZE to the length of the registers pushed.
824 Blackfin specific :
825 - VDSP C compiler manual (our ABI) says that a variable args function
826 should save the R0, R1 and R2 registers in the stack.
827 - The caller will always leave space on the stack for the
828 arguments that are passed in registers, so we dont have
829 to leave any extra space.
830 - now, the vastart pointer can access all arguments from the stack. */
832 static void
833 setup_incoming_varargs (CUMULATIVE_ARGS *cum,
834 enum machine_mode mode ATTRIBUTE_UNUSED,
835 tree type ATTRIBUTE_UNUSED, int *pretend_size,
836 int no_rtl)
838 rtx mem;
839 int i;
841 if (no_rtl)
842 return;
844 /* The move for named arguments will be generated automatically by the
845 compiler. We need to generate the move rtx for the unnamed arguments
846 if they are in the first 3 words. We assume at least 1 named argument
847 exists, so we never generate [ARGP] = R0 here. */
849 for (i = cum->words + 1; i < max_arg_registers; i++)
851 mem = gen_rtx_MEM (Pmode,
852 plus_constant (arg_pointer_rtx, (i * UNITS_PER_WORD)));
853 emit_move_insn (mem, gen_rtx_REG (Pmode, i));
856 *pretend_size = 0;
859 /* Value should be nonzero if functions must have frame pointers.
860 Zero means the frame pointer need not be set up (and parms may
861 be accessed via the stack pointer) in functions that seem suitable. */
863 static bool
864 bfin_frame_pointer_required (void)
866 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
868 if (fkind != SUBROUTINE)
869 return true;
871 /* We turn on -fomit-frame-pointer if -momit-leaf-frame-pointer is used,
872 so we have to override it for non-leaf functions. */
873 if (TARGET_OMIT_LEAF_FRAME_POINTER && ! current_function_is_leaf)
874 return true;
876 return false;
879 /* Return the number of registers pushed during the prologue. */
881 static int
882 n_regs_saved_by_prologue (void)
884 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
885 bool is_inthandler = fkind != SUBROUTINE;
886 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
887 bool all = (lookup_attribute ("saveall", attrs) != NULL_TREE
888 || (is_inthandler && !current_function_is_leaf));
889 int ndregs = all ? 8 : n_dregs_to_save (is_inthandler, false);
890 int npregs = all ? 6 : n_pregs_to_save (is_inthandler, false);
891 int n = ndregs + npregs;
892 int i;
894 if (all || stack_frame_needed_p ())
895 n += 2;
896 else
898 if (must_save_fp_p ())
899 n++;
900 if (must_save_rets_p ())
901 n++;
904 if (fkind != SUBROUTINE || all)
906 /* Increment once for ASTAT. */
907 n++;
908 if (! current_function_is_leaf
909 || cfun->machine->has_hardware_loops
910 || cfun->machine->has_loopreg_clobber)
912 n += 6;
916 if (fkind != SUBROUTINE)
918 /* RETE/X/N. */
919 if (lookup_attribute ("nesting", attrs))
920 n++;
923 for (i = REG_P7 + 1; i < REG_CC; i++)
924 if (all
925 || (fkind != SUBROUTINE
926 && (df_regs_ever_live_p (i)
927 || (!leaf_function_p () && call_used_regs[i]))))
928 n += i == REG_A0 || i == REG_A1 ? 2 : 1;
930 return n;
933 /* Given FROM and TO register numbers, say whether this elimination is
934 allowed. Frame pointer elimination is automatically handled.
936 All other eliminations are valid. */
938 static bool
939 bfin_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to)
941 return (to == STACK_POINTER_REGNUM ? ! frame_pointer_needed : true);
944 /* Return the offset between two registers, one to be eliminated, and the other
945 its replacement, at the start of a routine. */
947 HOST_WIDE_INT
948 bfin_initial_elimination_offset (int from, int to)
950 HOST_WIDE_INT offset = 0;
952 if (from == ARG_POINTER_REGNUM)
953 offset = n_regs_saved_by_prologue () * 4;
955 if (to == STACK_POINTER_REGNUM)
957 if (crtl->outgoing_args_size >= FIXED_STACK_AREA)
958 offset += crtl->outgoing_args_size;
959 else if (crtl->outgoing_args_size)
960 offset += FIXED_STACK_AREA;
962 offset += get_frame_size ();
965 return offset;
968 /* Emit code to load a constant CONSTANT into register REG; setting
969 RTX_FRAME_RELATED_P on all insns we generate if RELATED is true.
970 Make sure that the insns we generate need not be split. */
972 static void
973 frame_related_constant_load (rtx reg, HOST_WIDE_INT constant, bool related)
975 rtx insn;
976 rtx cst = GEN_INT (constant);
978 if (constant >= -32768 && constant < 65536)
979 insn = emit_move_insn (reg, cst);
980 else
982 /* We don't call split_load_immediate here, since dwarf2out.c can get
983 confused about some of the more clever sequences it can generate. */
984 insn = emit_insn (gen_movsi_high (reg, cst));
985 if (related)
986 RTX_FRAME_RELATED_P (insn) = 1;
987 insn = emit_insn (gen_movsi_low (reg, reg, cst));
989 if (related)
990 RTX_FRAME_RELATED_P (insn) = 1;
993 /* Generate efficient code to add a value to a P register.
994 Set RTX_FRAME_RELATED_P on the generated insns if FRAME is nonzero.
995 EPILOGUE_P is zero if this function is called for prologue,
996 otherwise it's nonzero. And it's less than zero if this is for
997 sibcall epilogue. */
999 static void
1000 add_to_reg (rtx reg, HOST_WIDE_INT value, int frame, int epilogue_p)
1002 if (value == 0)
1003 return;
1005 /* Choose whether to use a sequence using a temporary register, or
1006 a sequence with multiple adds. We can add a signed 7-bit value
1007 in one instruction. */
1008 if (value > 120 || value < -120)
1010 rtx tmpreg;
1011 rtx tmpreg2;
1012 rtx insn;
1014 tmpreg2 = NULL_RTX;
1016 /* For prologue or normal epilogue, P1 can be safely used
1017 as the temporary register. For sibcall epilogue, we try to find
1018 a call used P register, which will be restored in epilogue.
1019 If we cannot find such a P register, we have to use one I register
1020 to help us. */
1022 if (epilogue_p >= 0)
1023 tmpreg = gen_rtx_REG (SImode, REG_P1);
1024 else
1026 int i;
1027 for (i = REG_P0; i <= REG_P5; i++)
1028 if ((df_regs_ever_live_p (i) && ! call_used_regs[i])
1029 || (!TARGET_FDPIC
1030 && i == PIC_OFFSET_TABLE_REGNUM
1031 && (crtl->uses_pic_offset_table
1032 || (TARGET_ID_SHARED_LIBRARY
1033 && ! current_function_is_leaf))))
1034 break;
1035 if (i <= REG_P5)
1036 tmpreg = gen_rtx_REG (SImode, i);
1037 else
1039 tmpreg = gen_rtx_REG (SImode, REG_P1);
1040 tmpreg2 = gen_rtx_REG (SImode, REG_I0);
1041 emit_move_insn (tmpreg2, tmpreg);
1045 if (frame)
1046 frame_related_constant_load (tmpreg, value, TRUE);
1047 else
1048 insn = emit_move_insn (tmpreg, GEN_INT (value));
1050 insn = emit_insn (gen_addsi3 (reg, reg, tmpreg));
1051 if (frame)
1052 RTX_FRAME_RELATED_P (insn) = 1;
1054 if (tmpreg2 != NULL_RTX)
1055 emit_move_insn (tmpreg, tmpreg2);
1057 else
1060 int size = value;
1061 rtx insn;
1063 if (size > 60)
1064 size = 60;
1065 else if (size < -60)
1066 /* We could use -62, but that would leave the stack unaligned, so
1067 it's no good. */
1068 size = -60;
1070 insn = emit_insn (gen_addsi3 (reg, reg, GEN_INT (size)));
1071 if (frame)
1072 RTX_FRAME_RELATED_P (insn) = 1;
1073 value -= size;
1075 while (value != 0);
1078 /* Generate a LINK insn for a frame sized FRAME_SIZE. If this constant
1079 is too large, generate a sequence of insns that has the same effect.
1080 SPREG contains (reg:SI REG_SP). */
1082 static void
1083 emit_link_insn (rtx spreg, HOST_WIDE_INT frame_size)
1085 HOST_WIDE_INT link_size = frame_size;
1086 rtx insn;
1087 int i;
1089 if (link_size > 262140)
1090 link_size = 262140;
1092 /* Use a LINK insn with as big a constant as possible, then subtract
1093 any remaining size from the SP. */
1094 insn = emit_insn (gen_link (GEN_INT (-8 - link_size)));
1095 RTX_FRAME_RELATED_P (insn) = 1;
1097 for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
1099 rtx set = XVECEXP (PATTERN (insn), 0, i);
1100 gcc_assert (GET_CODE (set) == SET);
1101 RTX_FRAME_RELATED_P (set) = 1;
1104 frame_size -= link_size;
1106 if (frame_size > 0)
1108 /* Must use a call-clobbered PREG that isn't the static chain. */
1109 rtx tmpreg = gen_rtx_REG (Pmode, REG_P1);
1111 frame_related_constant_load (tmpreg, -frame_size, TRUE);
1112 insn = emit_insn (gen_addsi3 (spreg, spreg, tmpreg));
1113 RTX_FRAME_RELATED_P (insn) = 1;
1117 /* Return the number of bytes we must reserve for outgoing arguments
1118 in the current function's stack frame. */
1120 static HOST_WIDE_INT
1121 arg_area_size (void)
1123 if (crtl->outgoing_args_size)
1125 if (crtl->outgoing_args_size >= FIXED_STACK_AREA)
1126 return crtl->outgoing_args_size;
1127 else
1128 return FIXED_STACK_AREA;
1130 return 0;
1133 /* Save RETS and FP, and allocate a stack frame. ALL is true if the
1134 function must save all its registers (true only for certain interrupt
1135 handlers). */
1137 static void
1138 do_link (rtx spreg, HOST_WIDE_INT frame_size, bool all)
1140 frame_size += arg_area_size ();
1142 if (all
1143 || stack_frame_needed_p ()
1144 || (must_save_rets_p () && must_save_fp_p ()))
1145 emit_link_insn (spreg, frame_size);
1146 else
1148 if (must_save_rets_p ())
1150 rtx pat = gen_movsi (gen_rtx_MEM (Pmode,
1151 gen_rtx_PRE_DEC (Pmode, spreg)),
1152 bfin_rets_rtx);
1153 rtx insn = emit_insn (pat);
1154 RTX_FRAME_RELATED_P (insn) = 1;
1156 if (must_save_fp_p ())
1158 rtx pat = gen_movsi (gen_rtx_MEM (Pmode,
1159 gen_rtx_PRE_DEC (Pmode, spreg)),
1160 gen_rtx_REG (Pmode, REG_FP));
1161 rtx insn = emit_insn (pat);
1162 RTX_FRAME_RELATED_P (insn) = 1;
1164 add_to_reg (spreg, -frame_size, 1, 0);
1168 /* Like do_link, but used for epilogues to deallocate the stack frame.
1169 EPILOGUE_P is zero if this function is called for prologue,
1170 otherwise it's nonzero. And it's less than zero if this is for
1171 sibcall epilogue. */
1173 static void
1174 do_unlink (rtx spreg, HOST_WIDE_INT frame_size, bool all, int epilogue_p)
1176 frame_size += arg_area_size ();
1178 if (stack_frame_needed_p ())
1179 emit_insn (gen_unlink ());
1180 else
1182 rtx postinc = gen_rtx_MEM (Pmode, gen_rtx_POST_INC (Pmode, spreg));
1184 add_to_reg (spreg, frame_size, 0, epilogue_p);
1185 if (all || must_save_fp_p ())
1187 rtx fpreg = gen_rtx_REG (Pmode, REG_FP);
1188 emit_move_insn (fpreg, postinc);
1189 emit_use (fpreg);
1191 if (all || must_save_rets_p ())
1193 emit_move_insn (bfin_rets_rtx, postinc);
1194 emit_use (bfin_rets_rtx);
1199 /* Generate a prologue suitable for a function of kind FKIND. This is
1200 called for interrupt and exception handler prologues.
1201 SPREG contains (reg:SI REG_SP). */
1203 static void
1204 expand_interrupt_handler_prologue (rtx spreg, e_funkind fkind, bool all)
1206 HOST_WIDE_INT frame_size = get_frame_size ();
1207 rtx predec1 = gen_rtx_PRE_DEC (SImode, spreg);
1208 rtx predec = gen_rtx_MEM (SImode, predec1);
1209 rtx insn;
1210 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1211 tree kspisusp = lookup_attribute ("kspisusp", attrs);
1213 if (kspisusp)
1215 insn = emit_move_insn (spreg, gen_rtx_REG (Pmode, REG_USP));
1216 RTX_FRAME_RELATED_P (insn) = 1;
1219 /* We need space on the stack in case we need to save the argument
1220 registers. */
1221 if (fkind == EXCPT_HANDLER)
1223 insn = emit_insn (gen_addsi3 (spreg, spreg, GEN_INT (-12)));
1224 RTX_FRAME_RELATED_P (insn) = 1;
1227 /* If we're calling other functions, they won't save their call-clobbered
1228 registers, so we must save everything here. */
1229 if (!current_function_is_leaf)
1230 all = true;
1231 expand_prologue_reg_save (spreg, all, true);
1233 if (ENABLE_WA_05000283 || ENABLE_WA_05000315)
1235 rtx chipid = GEN_INT (trunc_int_for_mode (0xFFC00014, SImode));
1236 rtx p5reg = gen_rtx_REG (Pmode, REG_P5);
1237 emit_insn (gen_movbi (bfin_cc_rtx, const1_rtx));
1238 emit_insn (gen_movsi_high (p5reg, chipid));
1239 emit_insn (gen_movsi_low (p5reg, p5reg, chipid));
1240 emit_insn (gen_dummy_load (p5reg, bfin_cc_rtx));
1243 if (lookup_attribute ("nesting", attrs))
1245 rtx srcreg = gen_rtx_REG (Pmode, ret_regs[fkind]);
1246 insn = emit_move_insn (predec, srcreg);
1247 RTX_FRAME_RELATED_P (insn) = 1;
1250 do_link (spreg, frame_size, all);
1252 if (fkind == EXCPT_HANDLER)
1254 rtx r0reg = gen_rtx_REG (SImode, REG_R0);
1255 rtx r1reg = gen_rtx_REG (SImode, REG_R1);
1256 rtx r2reg = gen_rtx_REG (SImode, REG_R2);
1257 rtx insn;
1259 insn = emit_move_insn (r0reg, gen_rtx_REG (SImode, REG_SEQSTAT));
1260 insn = emit_insn (gen_ashrsi3 (r0reg, r0reg, GEN_INT (26)));
1261 insn = emit_insn (gen_ashlsi3 (r0reg, r0reg, GEN_INT (26)));
1262 insn = emit_move_insn (r1reg, spreg);
1263 insn = emit_move_insn (r2reg, gen_rtx_REG (Pmode, REG_FP));
1264 insn = emit_insn (gen_addsi3 (r2reg, r2reg, GEN_INT (8)));
1268 /* Generate an epilogue suitable for a function of kind FKIND. This is
1269 called for interrupt and exception handler epilogues.
1270 SPREG contains (reg:SI REG_SP). */
1272 static void
1273 expand_interrupt_handler_epilogue (rtx spreg, e_funkind fkind, bool all)
1275 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1276 rtx postinc1 = gen_rtx_POST_INC (SImode, spreg);
1277 rtx postinc = gen_rtx_MEM (SImode, postinc1);
1279 /* A slightly crude technique to stop flow from trying to delete "dead"
1280 insns. */
1281 MEM_VOLATILE_P (postinc) = 1;
1283 do_unlink (spreg, get_frame_size (), all, 1);
1285 if (lookup_attribute ("nesting", attrs))
1287 rtx srcreg = gen_rtx_REG (Pmode, ret_regs[fkind]);
1288 emit_move_insn (srcreg, postinc);
1291 /* If we're calling other functions, they won't save their call-clobbered
1292 registers, so we must save (and restore) everything here. */
1293 if (!current_function_is_leaf)
1294 all = true;
1296 expand_epilogue_reg_restore (spreg, all, true);
1298 /* Deallocate any space we left on the stack in case we needed to save the
1299 argument registers. */
1300 if (fkind == EXCPT_HANDLER)
1301 emit_insn (gen_addsi3 (spreg, spreg, GEN_INT (12)));
1303 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode, ret_regs[fkind])));
1306 /* Used while emitting the prologue to generate code to load the correct value
1307 into the PIC register, which is passed in DEST. */
1309 static rtx
1310 bfin_load_pic_reg (rtx dest)
1312 struct cgraph_local_info *i = NULL;
1313 rtx addr, insn;
1315 i = cgraph_local_info (current_function_decl);
1317 /* Functions local to the translation unit don't need to reload the
1318 pic reg, since the caller always passes a usable one. */
1319 if (i && i->local)
1320 return pic_offset_table_rtx;
1322 if (bfin_lib_id_given)
1323 addr = plus_constant (pic_offset_table_rtx, -4 - bfin_library_id * 4);
1324 else
1325 addr = gen_rtx_PLUS (Pmode, pic_offset_table_rtx,
1326 gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx),
1327 UNSPEC_LIBRARY_OFFSET));
1328 insn = emit_insn (gen_movsi (dest, gen_rtx_MEM (Pmode, addr)));
1329 return dest;
1332 /* Generate RTL for the prologue of the current function. */
1334 void
1335 bfin_expand_prologue (void)
1337 HOST_WIDE_INT frame_size = get_frame_size ();
1338 rtx spreg = gen_rtx_REG (Pmode, REG_SP);
1339 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
1340 rtx pic_reg_loaded = NULL_RTX;
1341 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1342 bool all = lookup_attribute ("saveall", attrs) != NULL_TREE;
1344 if (fkind != SUBROUTINE)
1346 expand_interrupt_handler_prologue (spreg, fkind, all);
1347 return;
1350 if (crtl->limit_stack
1351 || (TARGET_STACK_CHECK_L1
1352 && !DECL_NO_LIMIT_STACK (current_function_decl)))
1354 HOST_WIDE_INT offset
1355 = bfin_initial_elimination_offset (ARG_POINTER_REGNUM,
1356 STACK_POINTER_REGNUM);
1357 rtx lim = crtl->limit_stack ? stack_limit_rtx : NULL_RTX;
1358 rtx p2reg = gen_rtx_REG (Pmode, REG_P2);
1360 if (!lim)
1362 emit_move_insn (p2reg, gen_int_mode (0xFFB00000, SImode));
1363 emit_move_insn (p2reg, gen_rtx_MEM (Pmode, p2reg));
1364 lim = p2reg;
1366 if (GET_CODE (lim) == SYMBOL_REF)
1368 if (TARGET_ID_SHARED_LIBRARY)
1370 rtx p1reg = gen_rtx_REG (Pmode, REG_P1);
1371 rtx val;
1372 pic_reg_loaded = bfin_load_pic_reg (p2reg);
1373 val = legitimize_pic_address (stack_limit_rtx, p1reg,
1374 pic_reg_loaded);
1375 emit_move_insn (p1reg, val);
1376 frame_related_constant_load (p2reg, offset, FALSE);
1377 emit_insn (gen_addsi3 (p2reg, p2reg, p1reg));
1378 lim = p2reg;
1380 else
1382 rtx limit = plus_constant (lim, offset);
1383 emit_move_insn (p2reg, limit);
1384 lim = p2reg;
1387 else
1389 if (lim != p2reg)
1390 emit_move_insn (p2reg, lim);
1391 add_to_reg (p2reg, offset, 0, 0);
1392 lim = p2reg;
1394 emit_insn (gen_compare_lt (bfin_cc_rtx, spreg, lim));
1395 emit_insn (gen_trapifcc ());
1397 expand_prologue_reg_save (spreg, all, false);
1399 do_link (spreg, frame_size, all);
1401 if (TARGET_ID_SHARED_LIBRARY
1402 && !TARGET_SEP_DATA
1403 && (crtl->uses_pic_offset_table
1404 || !current_function_is_leaf))
1405 bfin_load_pic_reg (pic_offset_table_rtx);
1408 /* Generate RTL for the epilogue of the current function. NEED_RETURN is zero
1409 if this is for a sibcall. EH_RETURN is nonzero if we're expanding an
1410 eh_return pattern. SIBCALL_P is true if this is a sibcall epilogue,
1411 false otherwise. */
1413 void
1414 bfin_expand_epilogue (int need_return, int eh_return, bool sibcall_p)
1416 rtx spreg = gen_rtx_REG (Pmode, REG_SP);
1417 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
1418 int e = sibcall_p ? -1 : 1;
1419 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1420 bool all = lookup_attribute ("saveall", attrs) != NULL_TREE;
1422 if (fkind != SUBROUTINE)
1424 expand_interrupt_handler_epilogue (spreg, fkind, all);
1425 return;
1428 do_unlink (spreg, get_frame_size (), all, e);
1430 expand_epilogue_reg_restore (spreg, all, false);
1432 /* Omit the return insn if this is for a sibcall. */
1433 if (! need_return)
1434 return;
1436 if (eh_return)
1437 emit_insn (gen_addsi3 (spreg, spreg, gen_rtx_REG (Pmode, REG_P2)));
1439 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode, REG_RETS)));
1442 /* Return nonzero if register OLD_REG can be renamed to register NEW_REG. */
1445 bfin_hard_regno_rename_ok (unsigned int old_reg ATTRIBUTE_UNUSED,
1446 unsigned int new_reg)
1448 /* Interrupt functions can only use registers that have already been
1449 saved by the prologue, even if they would normally be
1450 call-clobbered. */
1452 if (funkind (TREE_TYPE (current_function_decl)) != SUBROUTINE
1453 && !df_regs_ever_live_p (new_reg))
1454 return 0;
1456 return 1;
1459 /* Return the value of the return address for the frame COUNT steps up
1460 from the current frame, after the prologue.
1461 We punt for everything but the current frame by returning const0_rtx. */
1464 bfin_return_addr_rtx (int count)
1466 if (count != 0)
1467 return const0_rtx;
1469 return get_hard_reg_initial_val (Pmode, REG_RETS);
1472 static rtx
1473 bfin_delegitimize_address (rtx orig_x)
1475 rtx x = orig_x;
1477 if (GET_CODE (x) != MEM)
1478 return orig_x;
1480 x = XEXP (x, 0);
1481 if (GET_CODE (x) == PLUS
1482 && GET_CODE (XEXP (x, 1)) == UNSPEC
1483 && XINT (XEXP (x, 1), 1) == UNSPEC_MOVE_PIC
1484 && GET_CODE (XEXP (x, 0)) == REG
1485 && REGNO (XEXP (x, 0)) == PIC_OFFSET_TABLE_REGNUM)
1486 return XVECEXP (XEXP (x, 1), 0, 0);
1488 return orig_x;
1491 /* This predicate is used to compute the length of a load/store insn.
1492 OP is a MEM rtx, we return nonzero if its addressing mode requires a
1493 32-bit instruction. */
1496 effective_address_32bit_p (rtx op, enum machine_mode mode)
1498 HOST_WIDE_INT offset;
1500 mode = GET_MODE (op);
1501 op = XEXP (op, 0);
1503 if (GET_CODE (op) != PLUS)
1505 gcc_assert (REG_P (op) || GET_CODE (op) == POST_INC
1506 || GET_CODE (op) == PRE_DEC || GET_CODE (op) == POST_DEC);
1507 return 0;
1510 if (GET_CODE (XEXP (op, 1)) == UNSPEC)
1511 return 1;
1513 offset = INTVAL (XEXP (op, 1));
1515 /* All byte loads use a 16-bit offset. */
1516 if (GET_MODE_SIZE (mode) == 1)
1517 return 1;
1519 if (GET_MODE_SIZE (mode) == 4)
1521 /* Frame pointer relative loads can use a negative offset, all others
1522 are restricted to a small positive one. */
1523 if (XEXP (op, 0) == frame_pointer_rtx)
1524 return offset < -128 || offset > 60;
1525 return offset < 0 || offset > 60;
1528 /* Must be HImode now. */
1529 return offset < 0 || offset > 30;
1532 /* Returns true if X is a memory reference using an I register. */
1533 bool
1534 bfin_dsp_memref_p (rtx x)
1536 if (! MEM_P (x))
1537 return false;
1538 x = XEXP (x, 0);
1539 if (GET_CODE (x) == POST_INC || GET_CODE (x) == PRE_INC
1540 || GET_CODE (x) == POST_DEC || GET_CODE (x) == PRE_DEC)
1541 x = XEXP (x, 0);
1542 return IREG_P (x);
1545 /* Return cost of the memory address ADDR.
1546 All addressing modes are equally cheap on the Blackfin. */
1548 static int
1549 bfin_address_cost (rtx addr ATTRIBUTE_UNUSED, bool speed ATTRIBUTE_UNUSED)
1551 return 1;
1554 /* Subroutine of print_operand; used to print a memory reference X to FILE. */
1556 void
1557 print_address_operand (FILE *file, rtx x)
1559 switch (GET_CODE (x))
1561 case PLUS:
1562 output_address (XEXP (x, 0));
1563 fprintf (file, "+");
1564 output_address (XEXP (x, 1));
1565 break;
1567 case PRE_DEC:
1568 fprintf (file, "--");
1569 output_address (XEXP (x, 0));
1570 break;
1571 case POST_INC:
1572 output_address (XEXP (x, 0));
1573 fprintf (file, "++");
1574 break;
1575 case POST_DEC:
1576 output_address (XEXP (x, 0));
1577 fprintf (file, "--");
1578 break;
1580 default:
1581 gcc_assert (GET_CODE (x) != MEM);
1582 print_operand (file, x, 0);
1583 break;
1587 /* Adding intp DImode support by Tony
1588 * -- Q: (low word)
1589 * -- R: (high word)
1592 void
1593 print_operand (FILE *file, rtx x, char code)
1595 enum machine_mode mode;
1597 if (code == '!')
1599 if (GET_MODE (current_output_insn) == SImode)
1600 fprintf (file, " ||");
1601 else
1602 fprintf (file, ";");
1603 return;
1606 mode = GET_MODE (x);
1608 switch (code)
1610 case 'j':
1611 switch (GET_CODE (x))
1613 case EQ:
1614 fprintf (file, "e");
1615 break;
1616 case NE:
1617 fprintf (file, "ne");
1618 break;
1619 case GT:
1620 fprintf (file, "g");
1621 break;
1622 case LT:
1623 fprintf (file, "l");
1624 break;
1625 case GE:
1626 fprintf (file, "ge");
1627 break;
1628 case LE:
1629 fprintf (file, "le");
1630 break;
1631 case GTU:
1632 fprintf (file, "g");
1633 break;
1634 case LTU:
1635 fprintf (file, "l");
1636 break;
1637 case GEU:
1638 fprintf (file, "ge");
1639 break;
1640 case LEU:
1641 fprintf (file, "le");
1642 break;
1643 default:
1644 output_operand_lossage ("invalid %%j value");
1646 break;
1648 case 'J': /* reverse logic */
1649 switch (GET_CODE(x))
1651 case EQ:
1652 fprintf (file, "ne");
1653 break;
1654 case NE:
1655 fprintf (file, "e");
1656 break;
1657 case GT:
1658 fprintf (file, "le");
1659 break;
1660 case LT:
1661 fprintf (file, "ge");
1662 break;
1663 case GE:
1664 fprintf (file, "l");
1665 break;
1666 case LE:
1667 fprintf (file, "g");
1668 break;
1669 case GTU:
1670 fprintf (file, "le");
1671 break;
1672 case LTU:
1673 fprintf (file, "ge");
1674 break;
1675 case GEU:
1676 fprintf (file, "l");
1677 break;
1678 case LEU:
1679 fprintf (file, "g");
1680 break;
1681 default:
1682 output_operand_lossage ("invalid %%J value");
1684 break;
1686 default:
1687 switch (GET_CODE (x))
1689 case REG:
1690 if (code == 'h')
1692 if (REGNO (x) < 32)
1693 fprintf (file, "%s", short_reg_names[REGNO (x)]);
1694 else
1695 output_operand_lossage ("invalid operand for code '%c'", code);
1697 else if (code == 'd')
1699 if (REGNO (x) < 32)
1700 fprintf (file, "%s", high_reg_names[REGNO (x)]);
1701 else
1702 output_operand_lossage ("invalid operand for code '%c'", code);
1704 else if (code == 'w')
1706 if (REGNO (x) == REG_A0 || REGNO (x) == REG_A1)
1707 fprintf (file, "%s.w", reg_names[REGNO (x)]);
1708 else
1709 output_operand_lossage ("invalid operand for code '%c'", code);
1711 else if (code == 'x')
1713 if (REGNO (x) == REG_A0 || REGNO (x) == REG_A1)
1714 fprintf (file, "%s.x", reg_names[REGNO (x)]);
1715 else
1716 output_operand_lossage ("invalid operand for code '%c'", code);
1718 else if (code == 'v')
1720 if (REGNO (x) == REG_A0)
1721 fprintf (file, "AV0");
1722 else if (REGNO (x) == REG_A1)
1723 fprintf (file, "AV1");
1724 else
1725 output_operand_lossage ("invalid operand for code '%c'", code);
1727 else if (code == 'D')
1729 if (D_REGNO_P (REGNO (x)))
1730 fprintf (file, "%s", dregs_pair_names[REGNO (x)]);
1731 else
1732 output_operand_lossage ("invalid operand for code '%c'", code);
1734 else if (code == 'H')
1736 if ((mode == DImode || mode == DFmode) && REG_P (x))
1737 fprintf (file, "%s", reg_names[REGNO (x) + 1]);
1738 else
1739 output_operand_lossage ("invalid operand for code '%c'", code);
1741 else if (code == 'T')
1743 if (D_REGNO_P (REGNO (x)))
1744 fprintf (file, "%s", byte_reg_names[REGNO (x)]);
1745 else
1746 output_operand_lossage ("invalid operand for code '%c'", code);
1748 else
1749 fprintf (file, "%s", reg_names[REGNO (x)]);
1750 break;
1752 case MEM:
1753 fputc ('[', file);
1754 x = XEXP (x,0);
1755 print_address_operand (file, x);
1756 fputc (']', file);
1757 break;
1759 case CONST_INT:
1760 if (code == 'M')
1762 switch (INTVAL (x))
1764 case MACFLAG_NONE:
1765 break;
1766 case MACFLAG_FU:
1767 fputs ("(FU)", file);
1768 break;
1769 case MACFLAG_T:
1770 fputs ("(T)", file);
1771 break;
1772 case MACFLAG_TFU:
1773 fputs ("(TFU)", file);
1774 break;
1775 case MACFLAG_W32:
1776 fputs ("(W32)", file);
1777 break;
1778 case MACFLAG_IS:
1779 fputs ("(IS)", file);
1780 break;
1781 case MACFLAG_IU:
1782 fputs ("(IU)", file);
1783 break;
1784 case MACFLAG_IH:
1785 fputs ("(IH)", file);
1786 break;
1787 case MACFLAG_M:
1788 fputs ("(M)", file);
1789 break;
1790 case MACFLAG_IS_M:
1791 fputs ("(IS,M)", file);
1792 break;
1793 case MACFLAG_ISS2:
1794 fputs ("(ISS2)", file);
1795 break;
1796 case MACFLAG_S2RND:
1797 fputs ("(S2RND)", file);
1798 break;
1799 default:
1800 gcc_unreachable ();
1802 break;
1804 else if (code == 'b')
1806 if (INTVAL (x) == 0)
1807 fputs ("+=", file);
1808 else if (INTVAL (x) == 1)
1809 fputs ("-=", file);
1810 else
1811 gcc_unreachable ();
1812 break;
1814 /* Moves to half registers with d or h modifiers always use unsigned
1815 constants. */
1816 else if (code == 'd')
1817 x = GEN_INT ((INTVAL (x) >> 16) & 0xffff);
1818 else if (code == 'h')
1819 x = GEN_INT (INTVAL (x) & 0xffff);
1820 else if (code == 'N')
1821 x = GEN_INT (-INTVAL (x));
1822 else if (code == 'X')
1823 x = GEN_INT (exact_log2 (0xffffffff & INTVAL (x)));
1824 else if (code == 'Y')
1825 x = GEN_INT (exact_log2 (0xffffffff & ~INTVAL (x)));
1826 else if (code == 'Z')
1827 /* Used for LINK insns. */
1828 x = GEN_INT (-8 - INTVAL (x));
1830 /* fall through */
1832 case SYMBOL_REF:
1833 output_addr_const (file, x);
1834 break;
1836 case CONST_DOUBLE:
1837 output_operand_lossage ("invalid const_double operand");
1838 break;
1840 case UNSPEC:
1841 switch (XINT (x, 1))
1843 case UNSPEC_MOVE_PIC:
1844 output_addr_const (file, XVECEXP (x, 0, 0));
1845 fprintf (file, "@GOT");
1846 break;
1848 case UNSPEC_MOVE_FDPIC:
1849 output_addr_const (file, XVECEXP (x, 0, 0));
1850 fprintf (file, "@GOT17M4");
1851 break;
1853 case UNSPEC_FUNCDESC_GOT17M4:
1854 output_addr_const (file, XVECEXP (x, 0, 0));
1855 fprintf (file, "@FUNCDESC_GOT17M4");
1856 break;
1858 case UNSPEC_LIBRARY_OFFSET:
1859 fprintf (file, "_current_shared_library_p5_offset_");
1860 break;
1862 default:
1863 gcc_unreachable ();
1865 break;
1867 default:
1868 output_addr_const (file, x);
1873 /* Argument support functions. */
1875 /* Initialize a variable CUM of type CUMULATIVE_ARGS
1876 for a call to a function whose data type is FNTYPE.
1877 For a library call, FNTYPE is 0.
1878 VDSP C Compiler manual, our ABI says that
1879 first 3 words of arguments will use R0, R1 and R2.
1882 void
1883 init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype,
1884 rtx libname ATTRIBUTE_UNUSED)
1886 static CUMULATIVE_ARGS zero_cum;
1888 *cum = zero_cum;
1890 /* Set up the number of registers to use for passing arguments. */
1892 cum->nregs = max_arg_registers;
1893 cum->arg_regs = arg_regs;
1895 cum->call_cookie = CALL_NORMAL;
1896 /* Check for a longcall attribute. */
1897 if (fntype && lookup_attribute ("shortcall", TYPE_ATTRIBUTES (fntype)))
1898 cum->call_cookie |= CALL_SHORT;
1899 else if (fntype && lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype)))
1900 cum->call_cookie |= CALL_LONG;
1902 return;
1905 /* Update the data in CUM to advance over an argument
1906 of mode MODE and data type TYPE.
1907 (TYPE is null for libcalls where that information may not be available.) */
1909 void
1910 function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
1911 int named ATTRIBUTE_UNUSED)
1913 int count, bytes, words;
1915 bytes = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
1916 words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
1918 cum->words += words;
1919 cum->nregs -= words;
1921 if (cum->nregs <= 0)
1923 cum->nregs = 0;
1924 cum->arg_regs = NULL;
1926 else
1928 for (count = 1; count <= words; count++)
1929 cum->arg_regs++;
1932 return;
1935 /* Define where to put the arguments to a function.
1936 Value is zero to push the argument on the stack,
1937 or a hard register in which to store the argument.
1939 MODE is the argument's machine mode.
1940 TYPE is the data type of the argument (as a tree).
1941 This is null for libcalls where that information may
1942 not be available.
1943 CUM is a variable of type CUMULATIVE_ARGS which gives info about
1944 the preceding args and about the function being called.
1945 NAMED is nonzero if this argument is a named parameter
1946 (otherwise it is an extra parameter matching an ellipsis). */
1948 struct rtx_def *
1949 function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
1950 int named ATTRIBUTE_UNUSED)
1952 int bytes
1953 = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
1955 if (mode == VOIDmode)
1956 /* Compute operand 2 of the call insn. */
1957 return GEN_INT (cum->call_cookie);
1959 if (bytes == -1)
1960 return NULL_RTX;
1962 if (cum->nregs)
1963 return gen_rtx_REG (mode, *(cum->arg_regs));
1965 return NULL_RTX;
1968 /* For an arg passed partly in registers and partly in memory,
1969 this is the number of bytes passed in registers.
1970 For args passed entirely in registers or entirely in memory, zero.
1972 Refer VDSP C Compiler manual, our ABI.
1973 First 3 words are in registers. So, if an argument is larger
1974 than the registers available, it will span the register and
1975 stack. */
1977 static int
1978 bfin_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode,
1979 tree type ATTRIBUTE_UNUSED,
1980 bool named ATTRIBUTE_UNUSED)
1982 int bytes
1983 = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
1984 int bytes_left = cum->nregs * UNITS_PER_WORD;
1986 if (bytes == -1)
1987 return 0;
1989 if (bytes_left == 0)
1990 return 0;
1991 if (bytes > bytes_left)
1992 return bytes_left;
1993 return 0;
1996 /* Variable sized types are passed by reference. */
1998 static bool
1999 bfin_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
2000 enum machine_mode mode ATTRIBUTE_UNUSED,
2001 const_tree type, bool named ATTRIBUTE_UNUSED)
2003 return type && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST;
2006 /* Decide whether a type should be returned in memory (true)
2007 or in a register (false). This is called by the macro
2008 TARGET_RETURN_IN_MEMORY. */
2010 static bool
2011 bfin_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
2013 int size = int_size_in_bytes (type);
2014 return size > 2 * UNITS_PER_WORD || size == -1;
2017 /* Register in which address to store a structure value
2018 is passed to a function. */
2019 static rtx
2020 bfin_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
2021 int incoming ATTRIBUTE_UNUSED)
2023 return gen_rtx_REG (Pmode, REG_P0);
2026 /* Return true when register may be used to pass function parameters. */
2028 bool
2029 function_arg_regno_p (int n)
2031 int i;
2032 for (i = 0; arg_regs[i] != -1; i++)
2033 if (n == arg_regs[i])
2034 return true;
2035 return false;
2038 /* Returns 1 if OP contains a symbol reference */
2041 symbolic_reference_mentioned_p (rtx op)
2043 register const char *fmt;
2044 register int i;
2046 if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF)
2047 return 1;
2049 fmt = GET_RTX_FORMAT (GET_CODE (op));
2050 for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
2052 if (fmt[i] == 'E')
2054 register int j;
2056 for (j = XVECLEN (op, i) - 1; j >= 0; j--)
2057 if (symbolic_reference_mentioned_p (XVECEXP (op, i, j)))
2058 return 1;
2061 else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i)))
2062 return 1;
2065 return 0;
2068 /* Decide whether we can make a sibling call to a function. DECL is the
2069 declaration of the function being targeted by the call and EXP is the
2070 CALL_EXPR representing the call. */
2072 static bool
2073 bfin_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED,
2074 tree exp ATTRIBUTE_UNUSED)
2076 struct cgraph_local_info *this_func, *called_func;
2077 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
2078 if (fkind != SUBROUTINE)
2079 return false;
2080 if (!TARGET_ID_SHARED_LIBRARY || TARGET_SEP_DATA)
2081 return true;
2083 /* When compiling for ID shared libraries, can't sibcall a local function
2084 from a non-local function, because the local function thinks it does
2085 not need to reload P5 in the prologue, but the sibcall wil pop P5 in the
2086 sibcall epilogue, and we end up with the wrong value in P5. */
2088 if (!decl)
2089 /* Not enough information. */
2090 return false;
2092 this_func = cgraph_local_info (current_function_decl);
2093 called_func = cgraph_local_info (decl);
2094 return !called_func->local || this_func->local;
2097 /* Write a template for a trampoline to F. */
2099 static void
2100 bfin_asm_trampoline_template (FILE *f)
2102 if (TARGET_FDPIC)
2104 fprintf (f, "\t.dd\t0x00000000\n"); /* 0 */
2105 fprintf (f, "\t.dd\t0x00000000\n"); /* 0 */
2106 fprintf (f, "\t.dd\t0x0000e109\n"); /* p1.l = fn low */
2107 fprintf (f, "\t.dd\t0x0000e149\n"); /* p1.h = fn high */
2108 fprintf (f, "\t.dd\t0x0000e10a\n"); /* p2.l = sc low */
2109 fprintf (f, "\t.dd\t0x0000e14a\n"); /* p2.h = sc high */
2110 fprintf (f, "\t.dw\t0xac4b\n"); /* p3 = [p1 + 4] */
2111 fprintf (f, "\t.dw\t0x9149\n"); /* p1 = [p1] */
2112 fprintf (f, "\t.dw\t0x0051\n"); /* jump (p1)*/
2114 else
2116 fprintf (f, "\t.dd\t0x0000e109\n"); /* p1.l = fn low */
2117 fprintf (f, "\t.dd\t0x0000e149\n"); /* p1.h = fn high */
2118 fprintf (f, "\t.dd\t0x0000e10a\n"); /* p2.l = sc low */
2119 fprintf (f, "\t.dd\t0x0000e14a\n"); /* p2.h = sc high */
2120 fprintf (f, "\t.dw\t0x0051\n"); /* jump (p1)*/
2124 /* Emit RTL insns to initialize the variable parts of a trampoline at
2125 M_TRAMP. FNDECL is the target function. CHAIN_VALUE is an RTX for
2126 the static chain value for the function. */
2128 static void
2129 bfin_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
2131 rtx t1 = copy_to_reg (XEXP (DECL_RTL (fndecl), 0));
2132 rtx t2 = copy_to_reg (chain_value);
2133 rtx mem;
2134 int i = 0;
2136 emit_block_move (m_tramp, assemble_trampoline_template (),
2137 GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
2139 if (TARGET_FDPIC)
2141 rtx a = force_reg (Pmode, plus_constant (XEXP (m_tramp, 0), 8));
2142 mem = adjust_address (m_tramp, Pmode, 0);
2143 emit_move_insn (mem, a);
2144 i = 8;
2147 mem = adjust_address (m_tramp, HImode, i + 2);
2148 emit_move_insn (mem, gen_lowpart (HImode, t1));
2149 emit_insn (gen_ashrsi3 (t1, t1, GEN_INT (16)));
2150 mem = adjust_address (m_tramp, HImode, i + 6);
2151 emit_move_insn (mem, gen_lowpart (HImode, t1));
2153 mem = adjust_address (m_tramp, HImode, i + 10);
2154 emit_move_insn (mem, gen_lowpart (HImode, t2));
2155 emit_insn (gen_ashrsi3 (t2, t2, GEN_INT (16)));
2156 mem = adjust_address (m_tramp, HImode, i + 14);
2157 emit_move_insn (mem, gen_lowpart (HImode, t2));
2160 /* Emit insns to move operands[1] into operands[0]. */
2162 void
2163 emit_pic_move (rtx *operands, enum machine_mode mode ATTRIBUTE_UNUSED)
2165 rtx temp = reload_in_progress ? operands[0] : gen_reg_rtx (Pmode);
2167 gcc_assert (!TARGET_FDPIC || !(reload_in_progress || reload_completed));
2168 if (GET_CODE (operands[0]) == MEM && SYMBOLIC_CONST (operands[1]))
2169 operands[1] = force_reg (SImode, operands[1]);
2170 else
2171 operands[1] = legitimize_pic_address (operands[1], temp,
2172 TARGET_FDPIC ? OUR_FDPIC_REG
2173 : pic_offset_table_rtx);
2176 /* Expand a move operation in mode MODE. The operands are in OPERANDS.
2177 Returns true if no further code must be generated, false if the caller
2178 should generate an insn to move OPERANDS[1] to OPERANDS[0]. */
2180 bool
2181 expand_move (rtx *operands, enum machine_mode mode)
2183 rtx op = operands[1];
2184 if ((TARGET_ID_SHARED_LIBRARY || TARGET_FDPIC)
2185 && SYMBOLIC_CONST (op))
2186 emit_pic_move (operands, mode);
2187 else if (mode == SImode && GET_CODE (op) == CONST
2188 && GET_CODE (XEXP (op, 0)) == PLUS
2189 && GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF
2190 && !bfin_legitimate_constant_p (op))
2192 rtx dest = operands[0];
2193 rtx op0, op1;
2194 gcc_assert (!reload_in_progress && !reload_completed);
2195 op = XEXP (op, 0);
2196 op0 = force_reg (mode, XEXP (op, 0));
2197 op1 = XEXP (op, 1);
2198 if (!insn_data[CODE_FOR_addsi3].operand[2].predicate (op1, mode))
2199 op1 = force_reg (mode, op1);
2200 if (GET_CODE (dest) == MEM)
2201 dest = gen_reg_rtx (mode);
2202 emit_insn (gen_addsi3 (dest, op0, op1));
2203 if (dest == operands[0])
2204 return true;
2205 operands[1] = dest;
2207 /* Don't generate memory->memory or constant->memory moves, go through a
2208 register */
2209 else if ((reload_in_progress | reload_completed) == 0
2210 && GET_CODE (operands[0]) == MEM
2211 && GET_CODE (operands[1]) != REG)
2212 operands[1] = force_reg (mode, operands[1]);
2213 return false;
2216 /* Split one or more DImode RTL references into pairs of SImode
2217 references. The RTL can be REG, offsettable MEM, integer constant, or
2218 CONST_DOUBLE. "operands" is a pointer to an array of DImode RTL to
2219 split and "num" is its length. lo_half and hi_half are output arrays
2220 that parallel "operands". */
2222 void
2223 split_di (rtx operands[], int num, rtx lo_half[], rtx hi_half[])
2225 while (num--)
2227 rtx op = operands[num];
2229 /* simplify_subreg refuse to split volatile memory addresses,
2230 but we still have to handle it. */
2231 if (GET_CODE (op) == MEM)
2233 lo_half[num] = adjust_address (op, SImode, 0);
2234 hi_half[num] = adjust_address (op, SImode, 4);
2236 else
2238 lo_half[num] = simplify_gen_subreg (SImode, op,
2239 GET_MODE (op) == VOIDmode
2240 ? DImode : GET_MODE (op), 0);
2241 hi_half[num] = simplify_gen_subreg (SImode, op,
2242 GET_MODE (op) == VOIDmode
2243 ? DImode : GET_MODE (op), 4);
2248 bool
2249 bfin_longcall_p (rtx op, int call_cookie)
2251 gcc_assert (GET_CODE (op) == SYMBOL_REF);
2252 if (SYMBOL_REF_WEAK (op))
2253 return 1;
2254 if (call_cookie & CALL_SHORT)
2255 return 0;
2256 if (call_cookie & CALL_LONG)
2257 return 1;
2258 if (TARGET_LONG_CALLS)
2259 return 1;
2260 return 0;
2263 /* Expand a call instruction. FNADDR is the call target, RETVAL the return value.
2264 COOKIE is a CONST_INT holding the call_cookie prepared init_cumulative_args.
2265 SIBCALL is nonzero if this is a sibling call. */
2267 void
2268 bfin_expand_call (rtx retval, rtx fnaddr, rtx callarg1, rtx cookie, int sibcall)
2270 rtx use = NULL, call;
2271 rtx callee = XEXP (fnaddr, 0);
2272 int nelts = 3;
2273 rtx pat;
2274 rtx picreg = get_hard_reg_initial_val (SImode, FDPIC_REGNO);
2275 rtx retsreg = gen_rtx_REG (Pmode, REG_RETS);
2276 int n;
2278 /* In an untyped call, we can get NULL for operand 2. */
2279 if (cookie == NULL_RTX)
2280 cookie = const0_rtx;
2282 /* Static functions and indirect calls don't need the pic register. */
2283 if (!TARGET_FDPIC && flag_pic
2284 && GET_CODE (callee) == SYMBOL_REF
2285 && !SYMBOL_REF_LOCAL_P (callee))
2286 use_reg (&use, pic_offset_table_rtx);
2288 if (TARGET_FDPIC)
2290 int caller_in_sram, callee_in_sram;
2292 /* 0 is not in sram, 1 is in L1 sram, 2 is in L2 sram. */
2293 caller_in_sram = callee_in_sram = 0;
2295 if (lookup_attribute ("l1_text",
2296 DECL_ATTRIBUTES (cfun->decl)) != NULL_TREE)
2297 caller_in_sram = 1;
2298 else if (lookup_attribute ("l2",
2299 DECL_ATTRIBUTES (cfun->decl)) != NULL_TREE)
2300 caller_in_sram = 2;
2302 if (GET_CODE (callee) == SYMBOL_REF
2303 && SYMBOL_REF_DECL (callee) && DECL_P (SYMBOL_REF_DECL (callee)))
2305 if (lookup_attribute
2306 ("l1_text",
2307 DECL_ATTRIBUTES (SYMBOL_REF_DECL (callee))) != NULL_TREE)
2308 callee_in_sram = 1;
2309 else if (lookup_attribute
2310 ("l2",
2311 DECL_ATTRIBUTES (SYMBOL_REF_DECL (callee))) != NULL_TREE)
2312 callee_in_sram = 2;
2315 if (GET_CODE (callee) != SYMBOL_REF
2316 || bfin_longcall_p (callee, INTVAL (cookie))
2317 || (GET_CODE (callee) == SYMBOL_REF
2318 && !SYMBOL_REF_LOCAL_P (callee)
2319 && TARGET_INLINE_PLT)
2320 || caller_in_sram != callee_in_sram
2321 || (caller_in_sram && callee_in_sram
2322 && (GET_CODE (callee) != SYMBOL_REF
2323 || !SYMBOL_REF_LOCAL_P (callee))))
2325 rtx addr = callee;
2326 if (! address_operand (addr, Pmode))
2327 addr = force_reg (Pmode, addr);
2329 fnaddr = gen_reg_rtx (SImode);
2330 emit_insn (gen_load_funcdescsi (fnaddr, addr));
2331 fnaddr = gen_rtx_MEM (Pmode, fnaddr);
2333 picreg = gen_reg_rtx (SImode);
2334 emit_insn (gen_load_funcdescsi (picreg,
2335 plus_constant (addr, 4)));
2338 nelts++;
2340 else if ((!register_no_elim_operand (callee, Pmode)
2341 && GET_CODE (callee) != SYMBOL_REF)
2342 || (GET_CODE (callee) == SYMBOL_REF
2343 && ((TARGET_ID_SHARED_LIBRARY && !TARGET_LEAF_ID_SHARED_LIBRARY)
2344 || bfin_longcall_p (callee, INTVAL (cookie)))))
2346 callee = copy_to_mode_reg (Pmode, callee);
2347 fnaddr = gen_rtx_MEM (Pmode, callee);
2349 call = gen_rtx_CALL (VOIDmode, fnaddr, callarg1);
2351 if (retval)
2352 call = gen_rtx_SET (VOIDmode, retval, call);
2354 pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (nelts));
2355 n = 0;
2356 XVECEXP (pat, 0, n++) = call;
2357 if (TARGET_FDPIC)
2358 XVECEXP (pat, 0, n++) = gen_rtx_USE (VOIDmode, picreg);
2359 XVECEXP (pat, 0, n++) = gen_rtx_USE (VOIDmode, cookie);
2360 if (sibcall)
2361 XVECEXP (pat, 0, n++) = gen_rtx_RETURN (VOIDmode);
2362 else
2363 XVECEXP (pat, 0, n++) = gen_rtx_CLOBBER (VOIDmode, retsreg);
2364 call = emit_call_insn (pat);
2365 if (use)
2366 CALL_INSN_FUNCTION_USAGE (call) = use;
2369 /* Return 1 if hard register REGNO can hold a value of machine-mode MODE. */
2372 hard_regno_mode_ok (int regno, enum machine_mode mode)
2374 /* Allow only dregs to store value of mode HI or QI */
2375 enum reg_class rclass = REGNO_REG_CLASS (regno);
2377 if (mode == CCmode)
2378 return 0;
2380 if (mode == V2HImode)
2381 return D_REGNO_P (regno);
2382 if (rclass == CCREGS)
2383 return mode == BImode;
2384 if (mode == PDImode || mode == V2PDImode)
2385 return regno == REG_A0 || regno == REG_A1;
2387 /* Allow all normal 32-bit regs, except REG_M3, in case regclass ever comes
2388 up with a bad register class (such as ALL_REGS) for DImode. */
2389 if (mode == DImode)
2390 return regno < REG_M3;
2392 if (mode == SImode
2393 && TEST_HARD_REG_BIT (reg_class_contents[PROLOGUE_REGS], regno))
2394 return 1;
2396 return TEST_HARD_REG_BIT (reg_class_contents[MOST_REGS], regno);
2399 /* Implements target hook vector_mode_supported_p. */
2401 static bool
2402 bfin_vector_mode_supported_p (enum machine_mode mode)
2404 return mode == V2HImode;
2407 /* Return the cost of moving data from a register in class CLASS1 to
2408 one in class CLASS2. A cost of 2 is the default. */
2411 bfin_register_move_cost (enum machine_mode mode,
2412 enum reg_class class1, enum reg_class class2)
2414 /* These need secondary reloads, so they're more expensive. */
2415 if ((class1 == CCREGS && !reg_class_subset_p (class2, DREGS))
2416 || (class2 == CCREGS && !reg_class_subset_p (class1, DREGS)))
2417 return 4;
2419 /* If optimizing for size, always prefer reg-reg over reg-memory moves. */
2420 if (optimize_size)
2421 return 2;
2423 if (GET_MODE_CLASS (mode) == MODE_INT)
2425 /* Discourage trying to use the accumulators. */
2426 if (TEST_HARD_REG_BIT (reg_class_contents[class1], REG_A0)
2427 || TEST_HARD_REG_BIT (reg_class_contents[class1], REG_A1)
2428 || TEST_HARD_REG_BIT (reg_class_contents[class2], REG_A0)
2429 || TEST_HARD_REG_BIT (reg_class_contents[class2], REG_A1))
2430 return 20;
2432 return 2;
2435 /* Return the cost of moving data of mode M between a
2436 register and memory. A value of 2 is the default; this cost is
2437 relative to those in `REGISTER_MOVE_COST'.
2439 ??? In theory L1 memory has single-cycle latency. We should add a switch
2440 that tells the compiler whether we expect to use only L1 memory for the
2441 program; it'll make the costs more accurate. */
2444 bfin_memory_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
2445 enum reg_class rclass,
2446 int in ATTRIBUTE_UNUSED)
2448 /* Make memory accesses slightly more expensive than any register-register
2449 move. Also, penalize non-DP registers, since they need secondary
2450 reloads to load and store. */
2451 if (! reg_class_subset_p (rclass, DPREGS))
2452 return 10;
2454 return 8;
2457 /* Inform reload about cases where moving X with a mode MODE to a register in
2458 RCLASS requires an extra scratch register. Return the class needed for the
2459 scratch register. */
2461 static reg_class_t
2462 bfin_secondary_reload (bool in_p, rtx x, reg_class_t rclass_i,
2463 enum machine_mode mode, secondary_reload_info *sri)
2465 /* If we have HImode or QImode, we can only use DREGS as secondary registers;
2466 in most other cases we can also use PREGS. */
2467 enum reg_class default_class = GET_MODE_SIZE (mode) >= 4 ? DPREGS : DREGS;
2468 enum reg_class x_class = NO_REGS;
2469 enum rtx_code code = GET_CODE (x);
2470 enum reg_class rclass = (enum reg_class) rclass_i;
2472 if (code == SUBREG)
2473 x = SUBREG_REG (x), code = GET_CODE (x);
2474 if (REG_P (x))
2476 int regno = REGNO (x);
2477 if (regno >= FIRST_PSEUDO_REGISTER)
2478 regno = reg_renumber[regno];
2480 if (regno == -1)
2481 code = MEM;
2482 else
2483 x_class = REGNO_REG_CLASS (regno);
2486 /* We can be asked to reload (plus (FP) (large_constant)) into a DREG.
2487 This happens as a side effect of register elimination, and we need
2488 a scratch register to do it. */
2489 if (fp_plus_const_operand (x, mode))
2491 rtx op2 = XEXP (x, 1);
2492 int large_constant_p = ! satisfies_constraint_Ks7 (op2);
2494 if (rclass == PREGS || rclass == PREGS_CLOBBERED)
2495 return NO_REGS;
2496 /* If destination is a DREG, we can do this without a scratch register
2497 if the constant is valid for an add instruction. */
2498 if ((rclass == DREGS || rclass == DPREGS)
2499 && ! large_constant_p)
2500 return NO_REGS;
2501 /* Reloading to anything other than a DREG? Use a PREG scratch
2502 register. */
2503 sri->icode = CODE_FOR_reload_insi;
2504 return NO_REGS;
2507 /* Data can usually be moved freely between registers of most classes.
2508 AREGS are an exception; they can only move to or from another register
2509 in AREGS or one in DREGS. They can also be assigned the constant 0. */
2510 if (x_class == AREGS || x_class == EVEN_AREGS || x_class == ODD_AREGS)
2511 return (rclass == DREGS || rclass == AREGS || rclass == EVEN_AREGS
2512 || rclass == ODD_AREGS
2513 ? NO_REGS : DREGS);
2515 if (rclass == AREGS || rclass == EVEN_AREGS || rclass == ODD_AREGS)
2517 if (code == MEM)
2519 sri->icode = in_p ? CODE_FOR_reload_inpdi : CODE_FOR_reload_outpdi;
2520 return NO_REGS;
2523 if (x != const0_rtx && x_class != DREGS)
2525 return DREGS;
2527 else
2528 return NO_REGS;
2531 /* CCREGS can only be moved from/to DREGS. */
2532 if (rclass == CCREGS && x_class != DREGS)
2533 return DREGS;
2534 if (x_class == CCREGS && rclass != DREGS)
2535 return DREGS;
2537 /* All registers other than AREGS can load arbitrary constants. The only
2538 case that remains is MEM. */
2539 if (code == MEM)
2540 if (! reg_class_subset_p (rclass, default_class))
2541 return default_class;
2543 return NO_REGS;
2546 /* Implement TARGET_HANDLE_OPTION. */
2548 static bool
2549 bfin_handle_option (size_t code, const char *arg, int value)
2551 switch (code)
2553 case OPT_mshared_library_id_:
2554 if (value > MAX_LIBRARY_ID)
2555 error ("-mshared-library-id=%s is not between 0 and %d",
2556 arg, MAX_LIBRARY_ID);
2557 bfin_lib_id_given = 1;
2558 return true;
2560 case OPT_mcpu_:
2562 const char *p, *q;
2563 int i;
2565 i = 0;
2566 while ((p = bfin_cpus[i].name) != NULL)
2568 if (strncmp (arg, p, strlen (p)) == 0)
2569 break;
2570 i++;
2573 if (p == NULL)
2575 error ("-mcpu=%s is not valid", arg);
2576 return false;
2579 bfin_cpu_type = bfin_cpus[i].type;
2581 q = arg + strlen (p);
2583 if (*q == '\0')
2585 bfin_si_revision = bfin_cpus[i].si_revision;
2586 bfin_workarounds |= bfin_cpus[i].workarounds;
2588 else if (strcmp (q, "-none") == 0)
2589 bfin_si_revision = -1;
2590 else if (strcmp (q, "-any") == 0)
2592 bfin_si_revision = 0xffff;
2593 while (bfin_cpus[i].type == bfin_cpu_type)
2595 bfin_workarounds |= bfin_cpus[i].workarounds;
2596 i++;
2599 else
2601 unsigned int si_major, si_minor;
2602 int rev_len, n;
2604 rev_len = strlen (q);
2606 if (sscanf (q, "-%u.%u%n", &si_major, &si_minor, &n) != 2
2607 || n != rev_len
2608 || si_major > 0xff || si_minor > 0xff)
2610 invalid_silicon_revision:
2611 error ("-mcpu=%s has invalid silicon revision", arg);
2612 return false;
2615 bfin_si_revision = (si_major << 8) | si_minor;
2617 while (bfin_cpus[i].type == bfin_cpu_type
2618 && bfin_cpus[i].si_revision != bfin_si_revision)
2619 i++;
2621 if (bfin_cpus[i].type != bfin_cpu_type)
2622 goto invalid_silicon_revision;
2624 bfin_workarounds |= bfin_cpus[i].workarounds;
2627 return true;
2630 default:
2631 return true;
2635 static struct machine_function *
2636 bfin_init_machine_status (void)
2638 return ggc_alloc_cleared_machine_function ();
2641 /* Implement the macro OVERRIDE_OPTIONS. */
2643 void
2644 override_options (void)
2646 /* If processor type is not specified, enable all workarounds. */
2647 if (bfin_cpu_type == BFIN_CPU_UNKNOWN)
2649 int i;
2651 for (i = 0; bfin_cpus[i].name != NULL; i++)
2652 bfin_workarounds |= bfin_cpus[i].workarounds;
2654 bfin_si_revision = 0xffff;
2657 if (bfin_csync_anomaly == 1)
2658 bfin_workarounds |= WA_SPECULATIVE_SYNCS;
2659 else if (bfin_csync_anomaly == 0)
2660 bfin_workarounds &= ~WA_SPECULATIVE_SYNCS;
2662 if (bfin_specld_anomaly == 1)
2663 bfin_workarounds |= WA_SPECULATIVE_LOADS;
2664 else if (bfin_specld_anomaly == 0)
2665 bfin_workarounds &= ~WA_SPECULATIVE_LOADS;
2667 if (TARGET_OMIT_LEAF_FRAME_POINTER)
2668 flag_omit_frame_pointer = 1;
2670 /* Library identification */
2671 if (bfin_lib_id_given && ! TARGET_ID_SHARED_LIBRARY)
2672 error ("-mshared-library-id= specified without -mid-shared-library");
2674 if (stack_limit_rtx && TARGET_STACK_CHECK_L1)
2675 error ("Can't use multiple stack checking methods together.");
2677 if (TARGET_ID_SHARED_LIBRARY && TARGET_FDPIC)
2678 error ("ID shared libraries and FD-PIC mode can't be used together.");
2680 /* Don't allow the user to specify -mid-shared-library and -msep-data
2681 together, as it makes little sense from a user's point of view... */
2682 if (TARGET_SEP_DATA && TARGET_ID_SHARED_LIBRARY)
2683 error ("cannot specify both -msep-data and -mid-shared-library");
2684 /* ... internally, however, it's nearly the same. */
2685 if (TARGET_SEP_DATA)
2686 target_flags |= MASK_ID_SHARED_LIBRARY | MASK_LEAF_ID_SHARED_LIBRARY;
2688 if (TARGET_ID_SHARED_LIBRARY && flag_pic == 0)
2689 flag_pic = 1;
2691 /* There is no single unaligned SI op for PIC code. Sometimes we
2692 need to use ".4byte" and sometimes we need to use ".picptr".
2693 See bfin_assemble_integer for details. */
2694 if (TARGET_FDPIC)
2695 targetm.asm_out.unaligned_op.si = 0;
2697 /* Silently turn off flag_pic if not doing FDPIC or ID shared libraries,
2698 since we don't support it and it'll just break. */
2699 if (flag_pic && !TARGET_FDPIC && !TARGET_ID_SHARED_LIBRARY)
2700 flag_pic = 0;
2702 if (TARGET_MULTICORE && bfin_cpu_type != BFIN_CPU_BF561)
2703 error ("-mmulticore can only be used with BF561");
2705 if (TARGET_COREA && !TARGET_MULTICORE)
2706 error ("-mcorea should be used with -mmulticore");
2708 if (TARGET_COREB && !TARGET_MULTICORE)
2709 error ("-mcoreb should be used with -mmulticore");
2711 if (TARGET_COREA && TARGET_COREB)
2712 error ("-mcorea and -mcoreb can't be used together");
2714 flag_schedule_insns = 0;
2716 /* Passes after sched2 can break the helpful TImode annotations that
2717 haifa-sched puts on every insn. Just do scheduling in reorg. */
2718 bfin_flag_schedule_insns2 = flag_schedule_insns_after_reload;
2719 flag_schedule_insns_after_reload = 0;
2721 init_machine_status = bfin_init_machine_status;
2724 /* Return the destination address of BRANCH.
2725 We need to use this instead of get_attr_length, because the
2726 cbranch_with_nops pattern conservatively sets its length to 6, and
2727 we still prefer to use shorter sequences. */
2729 static int
2730 branch_dest (rtx branch)
2732 rtx dest;
2733 int dest_uid;
2734 rtx pat = PATTERN (branch);
2735 if (GET_CODE (pat) == PARALLEL)
2736 pat = XVECEXP (pat, 0, 0);
2737 dest = SET_SRC (pat);
2738 if (GET_CODE (dest) == IF_THEN_ELSE)
2739 dest = XEXP (dest, 1);
2740 dest = XEXP (dest, 0);
2741 dest_uid = INSN_UID (dest);
2742 return INSN_ADDRESSES (dest_uid);
2745 /* Return nonzero if INSN is annotated with a REG_BR_PROB note that indicates
2746 it's a branch that's predicted taken. */
2748 static int
2749 cbranch_predicted_taken_p (rtx insn)
2751 rtx x = find_reg_note (insn, REG_BR_PROB, 0);
2753 if (x)
2755 int pred_val = INTVAL (XEXP (x, 0));
2757 return pred_val >= REG_BR_PROB_BASE / 2;
2760 return 0;
2763 /* Templates for use by asm_conditional_branch. */
2765 static const char *ccbranch_templates[][3] = {
2766 { "if !cc jump %3;", "if cc jump 4 (bp); jump.s %3;", "if cc jump 6 (bp); jump.l %3;" },
2767 { "if cc jump %3;", "if !cc jump 4 (bp); jump.s %3;", "if !cc jump 6 (bp); jump.l %3;" },
2768 { "if !cc jump %3 (bp);", "if cc jump 4; jump.s %3;", "if cc jump 6; jump.l %3;" },
2769 { "if cc jump %3 (bp);", "if !cc jump 4; jump.s %3;", "if !cc jump 6; jump.l %3;" },
2772 /* Output INSN, which is a conditional branch instruction with operands
2773 OPERANDS.
2775 We deal with the various forms of conditional branches that can be generated
2776 by bfin_reorg to prevent the hardware from doing speculative loads, by
2777 - emitting a sufficient number of nops, if N_NOPS is nonzero, or
2778 - always emitting the branch as predicted taken, if PREDICT_TAKEN is true.
2779 Either of these is only necessary if the branch is short, otherwise the
2780 template we use ends in an unconditional jump which flushes the pipeline
2781 anyway. */
2783 void
2784 asm_conditional_branch (rtx insn, rtx *operands, int n_nops, int predict_taken)
2786 int offset = branch_dest (insn) - INSN_ADDRESSES (INSN_UID (insn));
2787 /* Note : offset for instructions like if cc jmp; jump.[sl] offset
2788 is to be taken from start of if cc rather than jump.
2789 Range for jump.s is (-4094, 4096) instead of (-4096, 4094)
2791 int len = (offset >= -1024 && offset <= 1022 ? 0
2792 : offset >= -4094 && offset <= 4096 ? 1
2793 : 2);
2794 int bp = predict_taken && len == 0 ? 1 : cbranch_predicted_taken_p (insn);
2795 int idx = (bp << 1) | (GET_CODE (operands[0]) == EQ ? BRF : BRT);
2796 output_asm_insn (ccbranch_templates[idx][len], operands);
2797 gcc_assert (n_nops == 0 || !bp);
2798 if (len == 0)
2799 while (n_nops-- > 0)
2800 output_asm_insn ("nop;", NULL);
2803 /* Emit rtl for a comparison operation CMP in mode MODE. Operands have been
2804 stored in bfin_compare_op0 and bfin_compare_op1 already. */
2807 bfin_gen_compare (rtx cmp, enum machine_mode mode ATTRIBUTE_UNUSED)
2809 enum rtx_code code1, code2;
2810 rtx op0 = XEXP (cmp, 0), op1 = XEXP (cmp, 1);
2811 rtx tem = bfin_cc_rtx;
2812 enum rtx_code code = GET_CODE (cmp);
2814 /* If we have a BImode input, then we already have a compare result, and
2815 do not need to emit another comparison. */
2816 if (GET_MODE (op0) == BImode)
2818 gcc_assert ((code == NE || code == EQ) && op1 == const0_rtx);
2819 tem = op0, code2 = code;
2821 else
2823 switch (code) {
2824 /* bfin has these conditions */
2825 case EQ:
2826 case LT:
2827 case LE:
2828 case LEU:
2829 case LTU:
2830 code1 = code;
2831 code2 = NE;
2832 break;
2833 default:
2834 code1 = reverse_condition (code);
2835 code2 = EQ;
2836 break;
2838 emit_insn (gen_rtx_SET (VOIDmode, tem,
2839 gen_rtx_fmt_ee (code1, BImode, op0, op1)));
2842 return gen_rtx_fmt_ee (code2, BImode, tem, CONST0_RTX (BImode));
2845 /* Return nonzero iff C has exactly one bit set if it is interpreted
2846 as a 32-bit constant. */
2849 log2constp (unsigned HOST_WIDE_INT c)
2851 c &= 0xFFFFFFFF;
2852 return c != 0 && (c & (c-1)) == 0;
2855 /* Returns the number of consecutive least significant zeros in the binary
2856 representation of *V.
2857 We modify *V to contain the original value arithmetically shifted right by
2858 the number of zeroes. */
2860 static int
2861 shiftr_zero (HOST_WIDE_INT *v)
2863 unsigned HOST_WIDE_INT tmp = *v;
2864 unsigned HOST_WIDE_INT sgn;
2865 int n = 0;
2867 if (tmp == 0)
2868 return 0;
2870 sgn = tmp & ((unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1));
2871 while ((tmp & 0x1) == 0 && n <= 32)
2873 tmp = (tmp >> 1) | sgn;
2874 n++;
2876 *v = tmp;
2877 return n;
2880 /* After reload, split the load of an immediate constant. OPERANDS are the
2881 operands of the movsi_insn pattern which we are splitting. We return
2882 nonzero if we emitted a sequence to load the constant, zero if we emitted
2883 nothing because we want to use the splitter's default sequence. */
2886 split_load_immediate (rtx operands[])
2888 HOST_WIDE_INT val = INTVAL (operands[1]);
2889 HOST_WIDE_INT tmp;
2890 HOST_WIDE_INT shifted = val;
2891 HOST_WIDE_INT shifted_compl = ~val;
2892 int num_zero = shiftr_zero (&shifted);
2893 int num_compl_zero = shiftr_zero (&shifted_compl);
2894 unsigned int regno = REGNO (operands[0]);
2896 /* This case takes care of single-bit set/clear constants, which we could
2897 also implement with BITSET/BITCLR. */
2898 if (num_zero
2899 && shifted >= -32768 && shifted < 65536
2900 && (D_REGNO_P (regno)
2901 || (regno >= REG_P0 && regno <= REG_P7 && num_zero <= 2)))
2903 emit_insn (gen_movsi (operands[0], GEN_INT (shifted)));
2904 emit_insn (gen_ashlsi3 (operands[0], operands[0], GEN_INT (num_zero)));
2905 return 1;
2908 tmp = val & 0xFFFF;
2909 tmp |= -(tmp & 0x8000);
2911 /* If high word has one bit set or clear, try to use a bit operation. */
2912 if (D_REGNO_P (regno))
2914 if (log2constp (val & 0xFFFF0000))
2916 emit_insn (gen_movsi (operands[0], GEN_INT (val & 0xFFFF)));
2917 emit_insn (gen_iorsi3 (operands[0], operands[0], GEN_INT (val & 0xFFFF0000)));
2918 return 1;
2920 else if (log2constp (val | 0xFFFF) && (val & 0x8000) != 0)
2922 emit_insn (gen_movsi (operands[0], GEN_INT (tmp)));
2923 emit_insn (gen_andsi3 (operands[0], operands[0], GEN_INT (val | 0xFFFF)));
2927 if (D_REGNO_P (regno))
2929 if (tmp >= -64 && tmp <= 63)
2931 emit_insn (gen_movsi (operands[0], GEN_INT (tmp)));
2932 emit_insn (gen_movstricthi_high (operands[0], GEN_INT (val & -65536)));
2933 return 1;
2936 if ((val & 0xFFFF0000) == 0)
2938 emit_insn (gen_movsi (operands[0], const0_rtx));
2939 emit_insn (gen_movsi_low (operands[0], operands[0], operands[1]));
2940 return 1;
2943 if ((val & 0xFFFF0000) == 0xFFFF0000)
2945 emit_insn (gen_movsi (operands[0], constm1_rtx));
2946 emit_insn (gen_movsi_low (operands[0], operands[0], operands[1]));
2947 return 1;
2951 /* Need DREGs for the remaining case. */
2952 if (regno > REG_R7)
2953 return 0;
2955 if (optimize_size
2956 && num_compl_zero && shifted_compl >= -64 && shifted_compl <= 63)
2958 /* If optimizing for size, generate a sequence that has more instructions
2959 but is shorter. */
2960 emit_insn (gen_movsi (operands[0], GEN_INT (shifted_compl)));
2961 emit_insn (gen_ashlsi3 (operands[0], operands[0],
2962 GEN_INT (num_compl_zero)));
2963 emit_insn (gen_one_cmplsi2 (operands[0], operands[0]));
2964 return 1;
2966 return 0;
2969 /* Return true if the legitimate memory address for a memory operand of mode
2970 MODE. Return false if not. */
2972 static bool
2973 bfin_valid_add (enum machine_mode mode, HOST_WIDE_INT value)
2975 unsigned HOST_WIDE_INT v = value > 0 ? value : -value;
2976 int sz = GET_MODE_SIZE (mode);
2977 int shift = sz == 1 ? 0 : sz == 2 ? 1 : 2;
2978 /* The usual offsettable_memref machinery doesn't work so well for this
2979 port, so we deal with the problem here. */
2980 if (value > 0 && sz == 8)
2981 v += 4;
2982 return (v & ~(0x7fff << shift)) == 0;
2985 static bool
2986 bfin_valid_reg_p (unsigned int regno, int strict, enum machine_mode mode,
2987 enum rtx_code outer_code)
2989 if (strict)
2990 return REGNO_OK_FOR_BASE_STRICT_P (regno, mode, outer_code, SCRATCH);
2991 else
2992 return REGNO_OK_FOR_BASE_NONSTRICT_P (regno, mode, outer_code, SCRATCH);
2995 /* Recognize an RTL expression that is a valid memory address for an
2996 instruction. The MODE argument is the machine mode for the MEM expression
2997 that wants to use this address.
2999 Blackfin addressing modes are as follows:
3001 [preg]
3002 [preg + imm16]
3004 B [ Preg + uimm15 ]
3005 W [ Preg + uimm16m2 ]
3006 [ Preg + uimm17m4 ]
3008 [preg++]
3009 [preg--]
3010 [--sp]
3013 static bool
3014 bfin_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
3016 switch (GET_CODE (x)) {
3017 case REG:
3018 if (bfin_valid_reg_p (REGNO (x), strict, mode, MEM))
3019 return true;
3020 break;
3021 case PLUS:
3022 if (REG_P (XEXP (x, 0))
3023 && bfin_valid_reg_p (REGNO (XEXP (x, 0)), strict, mode, PLUS)
3024 && ((GET_CODE (XEXP (x, 1)) == UNSPEC && mode == SImode)
3025 || (GET_CODE (XEXP (x, 1)) == CONST_INT
3026 && bfin_valid_add (mode, INTVAL (XEXP (x, 1))))))
3027 return true;
3028 break;
3029 case POST_INC:
3030 case POST_DEC:
3031 if (LEGITIMATE_MODE_FOR_AUTOINC_P (mode)
3032 && REG_P (XEXP (x, 0))
3033 && bfin_valid_reg_p (REGNO (XEXP (x, 0)), strict, mode, POST_INC))
3034 return true;
3035 case PRE_DEC:
3036 if (LEGITIMATE_MODE_FOR_AUTOINC_P (mode)
3037 && XEXP (x, 0) == stack_pointer_rtx
3038 && REG_P (XEXP (x, 0))
3039 && bfin_valid_reg_p (REGNO (XEXP (x, 0)), strict, mode, PRE_DEC))
3040 return true;
3041 break;
3042 default:
3043 break;
3045 return false;
3048 /* Decide whether we can force certain constants to memory. If we
3049 decide we can't, the caller should be able to cope with it in
3050 another way. */
3052 static bool
3053 bfin_cannot_force_const_mem (rtx x ATTRIBUTE_UNUSED)
3055 /* We have only one class of non-legitimate constants, and our movsi
3056 expander knows how to handle them. Dropping these constants into the
3057 data section would only shift the problem - we'd still get relocs
3058 outside the object, in the data section rather than the text section. */
3059 return true;
3062 /* Ensure that for any constant of the form symbol + offset, the offset
3063 remains within the object. Any other constants are ok.
3064 This ensures that flat binaries never have to deal with relocations
3065 crossing section boundaries. */
3067 bool
3068 bfin_legitimate_constant_p (rtx x)
3070 rtx sym;
3071 HOST_WIDE_INT offset;
3073 if (GET_CODE (x) != CONST)
3074 return true;
3076 x = XEXP (x, 0);
3077 gcc_assert (GET_CODE (x) == PLUS);
3079 sym = XEXP (x, 0);
3080 x = XEXP (x, 1);
3081 if (GET_CODE (sym) != SYMBOL_REF
3082 || GET_CODE (x) != CONST_INT)
3083 return true;
3084 offset = INTVAL (x);
3086 if (SYMBOL_REF_DECL (sym) == 0)
3087 return true;
3088 if (offset < 0
3089 || offset >= int_size_in_bytes (TREE_TYPE (SYMBOL_REF_DECL (sym))))
3090 return false;
3092 return true;
3095 static bool
3096 bfin_rtx_costs (rtx x, int code, int outer_code, int *total, bool speed)
3098 int cost2 = COSTS_N_INSNS (1);
3099 rtx op0, op1;
3101 switch (code)
3103 case CONST_INT:
3104 if (outer_code == SET || outer_code == PLUS)
3105 *total = satisfies_constraint_Ks7 (x) ? 0 : cost2;
3106 else if (outer_code == AND)
3107 *total = log2constp (~INTVAL (x)) ? 0 : cost2;
3108 else if (outer_code == LE || outer_code == LT || outer_code == EQ)
3109 *total = (INTVAL (x) >= -4 && INTVAL (x) <= 3) ? 0 : cost2;
3110 else if (outer_code == LEU || outer_code == LTU)
3111 *total = (INTVAL (x) >= 0 && INTVAL (x) <= 7) ? 0 : cost2;
3112 else if (outer_code == MULT)
3113 *total = (INTVAL (x) == 2 || INTVAL (x) == 4) ? 0 : cost2;
3114 else if (outer_code == ASHIFT && (INTVAL (x) == 1 || INTVAL (x) == 2))
3115 *total = 0;
3116 else if (outer_code == ASHIFT || outer_code == ASHIFTRT
3117 || outer_code == LSHIFTRT)
3118 *total = (INTVAL (x) >= 0 && INTVAL (x) <= 31) ? 0 : cost2;
3119 else if (outer_code == IOR || outer_code == XOR)
3120 *total = (INTVAL (x) & (INTVAL (x) - 1)) == 0 ? 0 : cost2;
3121 else
3122 *total = cost2;
3123 return true;
3125 case CONST:
3126 case LABEL_REF:
3127 case SYMBOL_REF:
3128 case CONST_DOUBLE:
3129 *total = COSTS_N_INSNS (2);
3130 return true;
3132 case PLUS:
3133 op0 = XEXP (x, 0);
3134 op1 = XEXP (x, 1);
3135 if (GET_MODE (x) == SImode)
3137 if (GET_CODE (op0) == MULT
3138 && GET_CODE (XEXP (op0, 1)) == CONST_INT)
3140 HOST_WIDE_INT val = INTVAL (XEXP (op0, 1));
3141 if (val == 2 || val == 4)
3143 *total = cost2;
3144 *total += rtx_cost (XEXP (op0, 0), outer_code, speed);
3145 *total += rtx_cost (op1, outer_code, speed);
3146 return true;
3149 *total = cost2;
3150 if (GET_CODE (op0) != REG
3151 && (GET_CODE (op0) != SUBREG || GET_CODE (SUBREG_REG (op0)) != REG))
3152 *total += rtx_cost (op0, SET, speed);
3153 #if 0 /* We'd like to do this for accuracy, but it biases the loop optimizer
3154 towards creating too many induction variables. */
3155 if (!reg_or_7bit_operand (op1, SImode))
3156 *total += rtx_cost (op1, SET, speed);
3157 #endif
3159 else if (GET_MODE (x) == DImode)
3161 *total = 6 * cost2;
3162 if (GET_CODE (op1) != CONST_INT
3163 || !satisfies_constraint_Ks7 (op1))
3164 *total += rtx_cost (op1, PLUS, speed);
3165 if (GET_CODE (op0) != REG
3166 && (GET_CODE (op0) != SUBREG || GET_CODE (SUBREG_REG (op0)) != REG))
3167 *total += rtx_cost (op0, PLUS, speed);
3169 return true;
3171 case MINUS:
3172 if (GET_MODE (x) == DImode)
3173 *total = 6 * cost2;
3174 else
3175 *total = cost2;
3176 return true;
3178 case ASHIFT:
3179 case ASHIFTRT:
3180 case LSHIFTRT:
3181 if (GET_MODE (x) == DImode)
3182 *total = 6 * cost2;
3183 else
3184 *total = cost2;
3186 op0 = XEXP (x, 0);
3187 op1 = XEXP (x, 1);
3188 if (GET_CODE (op0) != REG
3189 && (GET_CODE (op0) != SUBREG || GET_CODE (SUBREG_REG (op0)) != REG))
3190 *total += rtx_cost (op0, code, speed);
3192 return true;
3194 case IOR:
3195 case AND:
3196 case XOR:
3197 op0 = XEXP (x, 0);
3198 op1 = XEXP (x, 1);
3200 /* Handle special cases of IOR: rotates, ALIGN insns, movstricthi_high. */
3201 if (code == IOR)
3203 if ((GET_CODE (op0) == LSHIFTRT && GET_CODE (op1) == ASHIFT)
3204 || (GET_CODE (op0) == ASHIFT && GET_CODE (op1) == ZERO_EXTEND)
3205 || (GET_CODE (op0) == ASHIFT && GET_CODE (op1) == LSHIFTRT)
3206 || (GET_CODE (op0) == AND && GET_CODE (op1) == CONST_INT))
3208 *total = cost2;
3209 return true;
3213 if (GET_CODE (op0) != REG
3214 && (GET_CODE (op0) != SUBREG || GET_CODE (SUBREG_REG (op0)) != REG))
3215 *total += rtx_cost (op0, code, speed);
3217 if (GET_MODE (x) == DImode)
3219 *total = 2 * cost2;
3220 return true;
3222 *total = cost2;
3223 if (GET_MODE (x) != SImode)
3224 return true;
3226 if (code == AND)
3228 if (! rhs_andsi3_operand (XEXP (x, 1), SImode))
3229 *total += rtx_cost (XEXP (x, 1), code, speed);
3231 else
3233 if (! regorlog2_operand (XEXP (x, 1), SImode))
3234 *total += rtx_cost (XEXP (x, 1), code, speed);
3237 return true;
3239 case ZERO_EXTRACT:
3240 case SIGN_EXTRACT:
3241 if (outer_code == SET
3242 && XEXP (x, 1) == const1_rtx
3243 && GET_CODE (XEXP (x, 2)) == CONST_INT)
3245 *total = 2 * cost2;
3246 return true;
3248 /* fall through */
3250 case SIGN_EXTEND:
3251 case ZERO_EXTEND:
3252 *total = cost2;
3253 return true;
3255 case MULT:
3257 op0 = XEXP (x, 0);
3258 op1 = XEXP (x, 1);
3259 if (GET_CODE (op0) == GET_CODE (op1)
3260 && (GET_CODE (op0) == ZERO_EXTEND
3261 || GET_CODE (op0) == SIGN_EXTEND))
3263 *total = COSTS_N_INSNS (1);
3264 op0 = XEXP (op0, 0);
3265 op1 = XEXP (op1, 0);
3267 else if (!speed)
3268 *total = COSTS_N_INSNS (1);
3269 else
3270 *total = COSTS_N_INSNS (3);
3272 if (GET_CODE (op0) != REG
3273 && (GET_CODE (op0) != SUBREG || GET_CODE (SUBREG_REG (op0)) != REG))
3274 *total += rtx_cost (op0, MULT, speed);
3275 if (GET_CODE (op1) != REG
3276 && (GET_CODE (op1) != SUBREG || GET_CODE (SUBREG_REG (op1)) != REG))
3277 *total += rtx_cost (op1, MULT, speed);
3279 return true;
3281 case UDIV:
3282 case UMOD:
3283 *total = COSTS_N_INSNS (32);
3284 return true;
3286 case VEC_CONCAT:
3287 case VEC_SELECT:
3288 if (outer_code == SET)
3289 *total = cost2;
3290 return true;
3292 default:
3293 return false;
3297 /* Used for communication between {push,pop}_multiple_operation (which
3298 we use not only as a predicate) and the corresponding output functions. */
3299 static int first_preg_to_save, first_dreg_to_save;
3300 static int n_regs_to_save;
3303 push_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
3305 int lastdreg = 8, lastpreg = 6;
3306 int i, group;
3308 first_preg_to_save = lastpreg;
3309 first_dreg_to_save = lastdreg;
3310 for (i = 1, group = 0; i < XVECLEN (op, 0) - 1; i++)
3312 rtx t = XVECEXP (op, 0, i);
3313 rtx src, dest;
3314 int regno;
3316 if (GET_CODE (t) != SET)
3317 return 0;
3319 src = SET_SRC (t);
3320 dest = SET_DEST (t);
3321 if (GET_CODE (dest) != MEM || ! REG_P (src))
3322 return 0;
3323 dest = XEXP (dest, 0);
3324 if (GET_CODE (dest) != PLUS
3325 || ! REG_P (XEXP (dest, 0))
3326 || REGNO (XEXP (dest, 0)) != REG_SP
3327 || GET_CODE (XEXP (dest, 1)) != CONST_INT
3328 || INTVAL (XEXP (dest, 1)) != -i * 4)
3329 return 0;
3331 regno = REGNO (src);
3332 if (group == 0)
3334 if (D_REGNO_P (regno))
3336 group = 1;
3337 first_dreg_to_save = lastdreg = regno - REG_R0;
3339 else if (regno >= REG_P0 && regno <= REG_P7)
3341 group = 2;
3342 first_preg_to_save = lastpreg = regno - REG_P0;
3344 else
3345 return 0;
3347 continue;
3350 if (group == 1)
3352 if (regno >= REG_P0 && regno <= REG_P7)
3354 group = 2;
3355 first_preg_to_save = lastpreg = regno - REG_P0;
3357 else if (regno != REG_R0 + lastdreg + 1)
3358 return 0;
3359 else
3360 lastdreg++;
3362 else if (group == 2)
3364 if (regno != REG_P0 + lastpreg + 1)
3365 return 0;
3366 lastpreg++;
3369 n_regs_to_save = 8 - first_dreg_to_save + 6 - first_preg_to_save;
3370 return 1;
3374 pop_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
3376 int lastdreg = 8, lastpreg = 6;
3377 int i, group;
3379 for (i = 1, group = 0; i < XVECLEN (op, 0); i++)
3381 rtx t = XVECEXP (op, 0, i);
3382 rtx src, dest;
3383 int regno;
3385 if (GET_CODE (t) != SET)
3386 return 0;
3388 src = SET_SRC (t);
3389 dest = SET_DEST (t);
3390 if (GET_CODE (src) != MEM || ! REG_P (dest))
3391 return 0;
3392 src = XEXP (src, 0);
3394 if (i == 1)
3396 if (! REG_P (src) || REGNO (src) != REG_SP)
3397 return 0;
3399 else if (GET_CODE (src) != PLUS
3400 || ! REG_P (XEXP (src, 0))
3401 || REGNO (XEXP (src, 0)) != REG_SP
3402 || GET_CODE (XEXP (src, 1)) != CONST_INT
3403 || INTVAL (XEXP (src, 1)) != (i - 1) * 4)
3404 return 0;
3406 regno = REGNO (dest);
3407 if (group == 0)
3409 if (regno == REG_R7)
3411 group = 1;
3412 lastdreg = 7;
3414 else if (regno != REG_P0 + lastpreg - 1)
3415 return 0;
3416 else
3417 lastpreg--;
3419 else if (group == 1)
3421 if (regno != REG_R0 + lastdreg - 1)
3422 return 0;
3423 else
3424 lastdreg--;
3427 first_dreg_to_save = lastdreg;
3428 first_preg_to_save = lastpreg;
3429 n_regs_to_save = 8 - first_dreg_to_save + 6 - first_preg_to_save;
3430 return 1;
3433 /* Emit assembly code for one multi-register push described by INSN, with
3434 operands in OPERANDS. */
3436 void
3437 output_push_multiple (rtx insn, rtx *operands)
3439 char buf[80];
3440 int ok;
3442 /* Validate the insn again, and compute first_[dp]reg_to_save. */
3443 ok = push_multiple_operation (PATTERN (insn), VOIDmode);
3444 gcc_assert (ok);
3446 if (first_dreg_to_save == 8)
3447 sprintf (buf, "[--sp] = ( p5:%d );\n", first_preg_to_save);
3448 else if (first_preg_to_save == 6)
3449 sprintf (buf, "[--sp] = ( r7:%d );\n", first_dreg_to_save);
3450 else
3451 sprintf (buf, "[--sp] = ( r7:%d, p5:%d );\n",
3452 first_dreg_to_save, first_preg_to_save);
3454 output_asm_insn (buf, operands);
3457 /* Emit assembly code for one multi-register pop described by INSN, with
3458 operands in OPERANDS. */
3460 void
3461 output_pop_multiple (rtx insn, rtx *operands)
3463 char buf[80];
3464 int ok;
3466 /* Validate the insn again, and compute first_[dp]reg_to_save. */
3467 ok = pop_multiple_operation (PATTERN (insn), VOIDmode);
3468 gcc_assert (ok);
3470 if (first_dreg_to_save == 8)
3471 sprintf (buf, "( p5:%d ) = [sp++];\n", first_preg_to_save);
3472 else if (first_preg_to_save == 6)
3473 sprintf (buf, "( r7:%d ) = [sp++];\n", first_dreg_to_save);
3474 else
3475 sprintf (buf, "( r7:%d, p5:%d ) = [sp++];\n",
3476 first_dreg_to_save, first_preg_to_save);
3478 output_asm_insn (buf, operands);
3481 /* Adjust DST and SRC by OFFSET bytes, and generate one move in mode MODE. */
3483 static void
3484 single_move_for_movmem (rtx dst, rtx src, enum machine_mode mode, HOST_WIDE_INT offset)
3486 rtx scratch = gen_reg_rtx (mode);
3487 rtx srcmem, dstmem;
3489 srcmem = adjust_address_nv (src, mode, offset);
3490 dstmem = adjust_address_nv (dst, mode, offset);
3491 emit_move_insn (scratch, srcmem);
3492 emit_move_insn (dstmem, scratch);
3495 /* Expand a string move operation of COUNT_EXP bytes from SRC to DST, with
3496 alignment ALIGN_EXP. Return true if successful, false if we should fall
3497 back on a different method. */
3499 bool
3500 bfin_expand_movmem (rtx dst, rtx src, rtx count_exp, rtx align_exp)
3502 rtx srcreg, destreg, countreg;
3503 HOST_WIDE_INT align = 0;
3504 unsigned HOST_WIDE_INT count = 0;
3506 if (GET_CODE (align_exp) == CONST_INT)
3507 align = INTVAL (align_exp);
3508 if (GET_CODE (count_exp) == CONST_INT)
3510 count = INTVAL (count_exp);
3511 #if 0
3512 if (!TARGET_INLINE_ALL_STRINGOPS && count > 64)
3513 return false;
3514 #endif
3517 /* If optimizing for size, only do single copies inline. */
3518 if (optimize_size)
3520 if (count == 2 && align < 2)
3521 return false;
3522 if (count == 4 && align < 4)
3523 return false;
3524 if (count != 1 && count != 2 && count != 4)
3525 return false;
3527 if (align < 2 && count != 1)
3528 return false;
3530 destreg = copy_to_mode_reg (Pmode, XEXP (dst, 0));
3531 if (destreg != XEXP (dst, 0))
3532 dst = replace_equiv_address_nv (dst, destreg);
3533 srcreg = copy_to_mode_reg (Pmode, XEXP (src, 0));
3534 if (srcreg != XEXP (src, 0))
3535 src = replace_equiv_address_nv (src, srcreg);
3537 if (count != 0 && align >= 2)
3539 unsigned HOST_WIDE_INT offset = 0;
3541 if (align >= 4)
3543 if ((count & ~3) == 4)
3545 single_move_for_movmem (dst, src, SImode, offset);
3546 offset = 4;
3548 else if (count & ~3)
3550 HOST_WIDE_INT new_count = ((count >> 2) & 0x3fffffff) - 1;
3551 countreg = copy_to_mode_reg (Pmode, GEN_INT (new_count));
3553 emit_insn (gen_rep_movsi (destreg, srcreg, countreg, destreg, srcreg));
3554 cfun->machine->has_loopreg_clobber = true;
3556 if (count & 2)
3558 single_move_for_movmem (dst, src, HImode, offset);
3559 offset += 2;
3562 else
3564 if ((count & ~1) == 2)
3566 single_move_for_movmem (dst, src, HImode, offset);
3567 offset = 2;
3569 else if (count & ~1)
3571 HOST_WIDE_INT new_count = ((count >> 1) & 0x7fffffff) - 1;
3572 countreg = copy_to_mode_reg (Pmode, GEN_INT (new_count));
3574 emit_insn (gen_rep_movhi (destreg, srcreg, countreg, destreg, srcreg));
3575 cfun->machine->has_loopreg_clobber = true;
3578 if (count & 1)
3580 single_move_for_movmem (dst, src, QImode, offset);
3582 return true;
3584 return false;
3587 /* Compute the alignment for a local variable.
3588 TYPE is the data type, and ALIGN is the alignment that
3589 the object would ordinarily have. The value of this macro is used
3590 instead of that alignment to align the object. */
3593 bfin_local_alignment (tree type, int align)
3595 /* Increasing alignment for (relatively) big types allows the builtin
3596 memcpy can use 32 bit loads/stores. */
3597 if (TYPE_SIZE (type)
3598 && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
3599 && (TREE_INT_CST_LOW (TYPE_SIZE (type)) > 8
3600 || TREE_INT_CST_HIGH (TYPE_SIZE (type))) && align < 32)
3601 return 32;
3602 return align;
3605 /* Implement TARGET_SCHED_ISSUE_RATE. */
3607 static int
3608 bfin_issue_rate (void)
3610 return 3;
3613 static int
3614 bfin_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
3616 enum attr_type insn_type, dep_insn_type;
3617 int dep_insn_code_number;
3619 /* Anti and output dependencies have zero cost. */
3620 if (REG_NOTE_KIND (link) != 0)
3621 return 0;
3623 dep_insn_code_number = recog_memoized (dep_insn);
3625 /* If we can't recognize the insns, we can't really do anything. */
3626 if (dep_insn_code_number < 0 || recog_memoized (insn) < 0)
3627 return cost;
3629 insn_type = get_attr_type (insn);
3630 dep_insn_type = get_attr_type (dep_insn);
3632 if (dep_insn_type == TYPE_MOVE || dep_insn_type == TYPE_MCLD)
3634 rtx pat = PATTERN (dep_insn);
3635 if (GET_CODE (pat) == PARALLEL)
3636 pat = XVECEXP (pat, 0, 0);
3637 rtx dest = SET_DEST (pat);
3638 rtx src = SET_SRC (pat);
3639 if (! ADDRESS_REGNO_P (REGNO (dest))
3640 || ! (MEM_P (src) || D_REGNO_P (REGNO (src))))
3641 return cost;
3642 return cost + (dep_insn_type == TYPE_MOVE ? 4 : 3);
3645 return cost;
3648 /* This function acts like NEXT_INSN, but is aware of three-insn bundles and
3649 skips all subsequent parallel instructions if INSN is the start of such
3650 a group. */
3651 static rtx
3652 find_next_insn_start (rtx insn)
3654 if (GET_MODE (insn) == SImode)
3656 while (GET_MODE (insn) != QImode)
3657 insn = NEXT_INSN (insn);
3659 return NEXT_INSN (insn);
3662 /* This function acts like PREV_INSN, but is aware of three-insn bundles and
3663 skips all subsequent parallel instructions if INSN is the start of such
3664 a group. */
3665 static rtx
3666 find_prev_insn_start (rtx insn)
3668 insn = PREV_INSN (insn);
3669 gcc_assert (GET_MODE (insn) != SImode);
3670 if (GET_MODE (insn) == QImode)
3672 while (GET_MODE (PREV_INSN (insn)) == SImode)
3673 insn = PREV_INSN (insn);
3675 return insn;
3678 /* Increment the counter for the number of loop instructions in the
3679 current function. */
3681 void
3682 bfin_hardware_loop (void)
3684 cfun->machine->has_hardware_loops++;
3687 /* Maximum loop nesting depth. */
3688 #define MAX_LOOP_DEPTH 2
3690 /* Maximum size of a loop. */
3691 #define MAX_LOOP_LENGTH 2042
3693 /* Maximum distance of the LSETUP instruction from the loop start. */
3694 #define MAX_LSETUP_DISTANCE 30
3696 /* We need to keep a vector of loops */
3697 typedef struct loop_info *loop_info;
3698 DEF_VEC_P (loop_info);
3699 DEF_VEC_ALLOC_P (loop_info,heap);
3701 /* Information about a loop we have found (or are in the process of
3702 finding). */
3703 struct GTY (()) loop_info
3705 /* loop number, for dumps */
3706 int loop_no;
3708 /* All edges that jump into and out of the loop. */
3709 VEC(edge,gc) *incoming;
3711 /* We can handle two cases: all incoming edges have the same destination
3712 block, or all incoming edges have the same source block. These two
3713 members are set to the common source or destination we found, or NULL
3714 if different blocks were found. If both are NULL the loop can't be
3715 optimized. */
3716 basic_block incoming_src;
3717 basic_block incoming_dest;
3719 /* First block in the loop. This is the one branched to by the loop_end
3720 insn. */
3721 basic_block head;
3723 /* Last block in the loop (the one with the loop_end insn). */
3724 basic_block tail;
3726 /* The successor block of the loop. This is the one the loop_end insn
3727 falls into. */
3728 basic_block successor;
3730 /* The last instruction in the tail. */
3731 rtx last_insn;
3733 /* The loop_end insn. */
3734 rtx loop_end;
3736 /* The iteration register. */
3737 rtx iter_reg;
3739 /* The new label placed at the beginning of the loop. */
3740 rtx start_label;
3742 /* The new label placed at the end of the loop. */
3743 rtx end_label;
3745 /* The length of the loop. */
3746 int length;
3748 /* The nesting depth of the loop. */
3749 int depth;
3751 /* Nonzero if we can't optimize this loop. */
3752 int bad;
3754 /* True if we have visited this loop. */
3755 int visited;
3757 /* True if this loop body clobbers any of LC0, LT0, or LB0. */
3758 int clobber_loop0;
3760 /* True if this loop body clobbers any of LC1, LT1, or LB1. */
3761 int clobber_loop1;
3763 /* Next loop in the graph. */
3764 struct loop_info *next;
3766 /* Immediate outer loop of this loop. */
3767 struct loop_info *outer;
3769 /* Vector of blocks only within the loop, including those within
3770 inner loops. */
3771 VEC (basic_block,heap) *blocks;
3773 /* Same information in a bitmap. */
3774 bitmap block_bitmap;
3776 /* Vector of inner loops within this loop */
3777 VEC (loop_info,heap) *loops;
3780 static void
3781 bfin_dump_loops (loop_info loops)
3783 loop_info loop;
3785 for (loop = loops; loop; loop = loop->next)
3787 loop_info i;
3788 basic_block b;
3789 unsigned ix;
3791 fprintf (dump_file, ";; loop %d: ", loop->loop_no);
3792 if (loop->bad)
3793 fprintf (dump_file, "(bad) ");
3794 fprintf (dump_file, "{head:%d, depth:%d}", loop->head->index, loop->depth);
3796 fprintf (dump_file, " blocks: [ ");
3797 for (ix = 0; VEC_iterate (basic_block, loop->blocks, ix, b); ix++)
3798 fprintf (dump_file, "%d ", b->index);
3799 fprintf (dump_file, "] ");
3801 fprintf (dump_file, " inner loops: [ ");
3802 for (ix = 0; VEC_iterate (loop_info, loop->loops, ix, i); ix++)
3803 fprintf (dump_file, "%d ", i->loop_no);
3804 fprintf (dump_file, "]\n");
3806 fprintf (dump_file, "\n");
3809 /* Scan the blocks of LOOP (and its inferiors) looking for basic block
3810 BB. Return true, if we find it. */
3812 static bool
3813 bfin_bb_in_loop (loop_info loop, basic_block bb)
3815 return bitmap_bit_p (loop->block_bitmap, bb->index);
3818 /* Scan the blocks of LOOP (and its inferiors) looking for uses of
3819 REG. Return true, if we find any. Don't count the loop's loop_end
3820 insn if it matches LOOP_END. */
3822 static bool
3823 bfin_scan_loop (loop_info loop, rtx reg, rtx loop_end)
3825 unsigned ix;
3826 basic_block bb;
3828 for (ix = 0; VEC_iterate (basic_block, loop->blocks, ix, bb); ix++)
3830 rtx insn;
3832 for (insn = BB_HEAD (bb);
3833 insn != NEXT_INSN (BB_END (bb));
3834 insn = NEXT_INSN (insn))
3836 if (!INSN_P (insn))
3837 continue;
3838 if (insn == loop_end)
3839 continue;
3840 if (reg_mentioned_p (reg, PATTERN (insn)))
3841 return true;
3844 return false;
3847 /* Estimate the length of INSN conservatively. */
3849 static int
3850 length_for_loop (rtx insn)
3852 int length = 0;
3853 if (JUMP_P (insn) && any_condjump_p (insn) && !optimize_size)
3855 if (ENABLE_WA_SPECULATIVE_SYNCS)
3856 length = 8;
3857 else if (ENABLE_WA_SPECULATIVE_LOADS)
3858 length = 6;
3860 else if (LABEL_P (insn))
3862 if (ENABLE_WA_SPECULATIVE_SYNCS)
3863 length = 4;
3866 if (NONDEBUG_INSN_P (insn))
3867 length += get_attr_length (insn);
3869 return length;
3872 /* Optimize LOOP. */
3874 static void
3875 bfin_optimize_loop (loop_info loop)
3877 basic_block bb;
3878 loop_info inner;
3879 rtx insn, last_insn;
3880 rtx loop_init, start_label, end_label;
3881 rtx reg_lc0, reg_lc1, reg_lt0, reg_lt1, reg_lb0, reg_lb1;
3882 rtx iter_reg, scratchreg, scratch_init, scratch_init_insn;
3883 rtx lc_reg, lt_reg, lb_reg;
3884 rtx seq, seq_end;
3885 int length;
3886 unsigned ix;
3887 int inner_depth = 0;
3889 if (loop->visited)
3890 return;
3892 loop->visited = 1;
3894 if (loop->bad)
3896 if (dump_file)
3897 fprintf (dump_file, ";; loop %d bad when found\n", loop->loop_no);
3898 goto bad_loop;
3901 /* Every loop contains in its list of inner loops every loop nested inside
3902 it, even if there are intermediate loops. This works because we're doing
3903 a depth-first search here and never visit a loop more than once. */
3904 for (ix = 0; VEC_iterate (loop_info, loop->loops, ix, inner); ix++)
3906 bfin_optimize_loop (inner);
3908 if (!inner->bad && inner_depth < inner->depth)
3910 inner_depth = inner->depth;
3912 loop->clobber_loop0 |= inner->clobber_loop0;
3913 loop->clobber_loop1 |= inner->clobber_loop1;
3917 loop->depth = inner_depth + 1;
3918 if (loop->depth > MAX_LOOP_DEPTH)
3920 if (dump_file)
3921 fprintf (dump_file, ";; loop %d too deep\n", loop->loop_no);
3922 goto bad_loop;
3925 /* Get the loop iteration register. */
3926 iter_reg = loop->iter_reg;
3928 if (!REG_P (iter_reg))
3930 if (dump_file)
3931 fprintf (dump_file, ";; loop %d iteration count not in a register\n",
3932 loop->loop_no);
3933 goto bad_loop;
3935 scratchreg = NULL_RTX;
3936 scratch_init = iter_reg;
3937 scratch_init_insn = NULL_RTX;
3938 if (!PREG_P (iter_reg) && loop->incoming_src)
3940 basic_block bb_in = loop->incoming_src;
3941 int i;
3942 for (i = REG_P0; i <= REG_P5; i++)
3943 if ((df_regs_ever_live_p (i)
3944 || (funkind (TREE_TYPE (current_function_decl)) == SUBROUTINE
3945 && call_used_regs[i]))
3946 && !REGNO_REG_SET_P (df_get_live_out (bb_in), i))
3948 scratchreg = gen_rtx_REG (SImode, i);
3949 break;
3951 for (insn = BB_END (bb_in); insn != BB_HEAD (bb_in);
3952 insn = PREV_INSN (insn))
3954 rtx set;
3955 if (NOTE_P (insn) || BARRIER_P (insn))
3956 continue;
3957 set = single_set (insn);
3958 if (set && rtx_equal_p (SET_DEST (set), iter_reg))
3960 if (CONSTANT_P (SET_SRC (set)))
3962 scratch_init = SET_SRC (set);
3963 scratch_init_insn = insn;
3965 break;
3967 else if (reg_mentioned_p (iter_reg, PATTERN (insn)))
3968 break;
3972 if (loop->incoming_src)
3974 /* Make sure the predecessor is before the loop start label, as required by
3975 the LSETUP instruction. */
3976 length = 0;
3977 insn = BB_END (loop->incoming_src);
3978 /* If we have to insert the LSETUP before a jump, count that jump in the
3979 length. */
3980 if (VEC_length (edge, loop->incoming) > 1
3981 || !(VEC_last (edge, loop->incoming)->flags & EDGE_FALLTHRU))
3983 gcc_assert (JUMP_P (insn));
3984 insn = PREV_INSN (insn);
3987 for (; insn && insn != loop->start_label; insn = NEXT_INSN (insn))
3988 length += length_for_loop (insn);
3990 if (!insn)
3992 if (dump_file)
3993 fprintf (dump_file, ";; loop %d lsetup not before loop_start\n",
3994 loop->loop_no);
3995 goto bad_loop;
3998 /* Account for the pop of a scratch register where necessary. */
3999 if (!PREG_P (iter_reg) && scratchreg == NULL_RTX
4000 && ENABLE_WA_LOAD_LCREGS)
4001 length += 2;
4003 if (length > MAX_LSETUP_DISTANCE)
4005 if (dump_file)
4006 fprintf (dump_file, ";; loop %d lsetup too far away\n", loop->loop_no);
4007 goto bad_loop;
4011 /* Check if start_label appears before loop_end and calculate the
4012 offset between them. We calculate the length of instructions
4013 conservatively. */
4014 length = 0;
4015 for (insn = loop->start_label;
4016 insn && insn != loop->loop_end;
4017 insn = NEXT_INSN (insn))
4018 length += length_for_loop (insn);
4020 if (!insn)
4022 if (dump_file)
4023 fprintf (dump_file, ";; loop %d start_label not before loop_end\n",
4024 loop->loop_no);
4025 goto bad_loop;
4028 loop->length = length;
4029 if (loop->length > MAX_LOOP_LENGTH)
4031 if (dump_file)
4032 fprintf (dump_file, ";; loop %d too long\n", loop->loop_no);
4033 goto bad_loop;
4036 /* Scan all the blocks to make sure they don't use iter_reg. */
4037 if (bfin_scan_loop (loop, iter_reg, loop->loop_end))
4039 if (dump_file)
4040 fprintf (dump_file, ";; loop %d uses iterator\n", loop->loop_no);
4041 goto bad_loop;
4044 /* Scan all the insns to see if the loop body clobber
4045 any hardware loop registers. */
4047 reg_lc0 = gen_rtx_REG (SImode, REG_LC0);
4048 reg_lc1 = gen_rtx_REG (SImode, REG_LC1);
4049 reg_lt0 = gen_rtx_REG (SImode, REG_LT0);
4050 reg_lt1 = gen_rtx_REG (SImode, REG_LT1);
4051 reg_lb0 = gen_rtx_REG (SImode, REG_LB0);
4052 reg_lb1 = gen_rtx_REG (SImode, REG_LB1);
4054 for (ix = 0; VEC_iterate (basic_block, loop->blocks, ix, bb); ix++)
4056 rtx insn;
4058 for (insn = BB_HEAD (bb);
4059 insn != NEXT_INSN (BB_END (bb));
4060 insn = NEXT_INSN (insn))
4062 if (!INSN_P (insn))
4063 continue;
4065 if (reg_set_p (reg_lc0, insn)
4066 || reg_set_p (reg_lt0, insn)
4067 || reg_set_p (reg_lb0, insn))
4068 loop->clobber_loop0 = 1;
4070 if (reg_set_p (reg_lc1, insn)
4071 || reg_set_p (reg_lt1, insn)
4072 || reg_set_p (reg_lb1, insn))
4073 loop->clobber_loop1 |= 1;
4077 if ((loop->clobber_loop0 && loop->clobber_loop1)
4078 || (loop->depth == MAX_LOOP_DEPTH && loop->clobber_loop0))
4080 loop->depth = MAX_LOOP_DEPTH + 1;
4081 if (dump_file)
4082 fprintf (dump_file, ";; loop %d no loop reg available\n",
4083 loop->loop_no);
4084 goto bad_loop;
4087 /* There should be an instruction before the loop_end instruction
4088 in the same basic block. And the instruction must not be
4089 - JUMP
4090 - CONDITIONAL BRANCH
4091 - CALL
4092 - CSYNC
4093 - SSYNC
4094 - Returns (RTS, RTN, etc.) */
4096 bb = loop->tail;
4097 last_insn = find_prev_insn_start (loop->loop_end);
4099 while (1)
4101 for (; last_insn != BB_HEAD (bb);
4102 last_insn = find_prev_insn_start (last_insn))
4103 if (NONDEBUG_INSN_P (last_insn))
4104 break;
4106 if (last_insn != BB_HEAD (bb))
4107 break;
4109 if (single_pred_p (bb)
4110 && single_pred_edge (bb)->flags & EDGE_FALLTHRU
4111 && single_pred (bb) != ENTRY_BLOCK_PTR)
4113 bb = single_pred (bb);
4114 last_insn = BB_END (bb);
4115 continue;
4117 else
4119 last_insn = NULL_RTX;
4120 break;
4124 if (!last_insn)
4126 if (dump_file)
4127 fprintf (dump_file, ";; loop %d has no last instruction\n",
4128 loop->loop_no);
4129 goto bad_loop;
4132 if (JUMP_P (last_insn) && !any_condjump_p (last_insn))
4134 if (dump_file)
4135 fprintf (dump_file, ";; loop %d has bad last instruction\n",
4136 loop->loop_no);
4137 goto bad_loop;
4139 /* In all other cases, try to replace a bad last insn with a nop. */
4140 else if (JUMP_P (last_insn)
4141 || CALL_P (last_insn)
4142 || get_attr_type (last_insn) == TYPE_SYNC
4143 || get_attr_type (last_insn) == TYPE_CALL
4144 || get_attr_seq_insns (last_insn) == SEQ_INSNS_MULTI
4145 || recog_memoized (last_insn) == CODE_FOR_return_internal
4146 || GET_CODE (PATTERN (last_insn)) == ASM_INPUT
4147 || asm_noperands (PATTERN (last_insn)) >= 0)
4149 if (loop->length + 2 > MAX_LOOP_LENGTH)
4151 if (dump_file)
4152 fprintf (dump_file, ";; loop %d too long\n", loop->loop_no);
4153 goto bad_loop;
4155 if (dump_file)
4156 fprintf (dump_file, ";; loop %d has bad last insn; replace with nop\n",
4157 loop->loop_no);
4159 last_insn = emit_insn_after (gen_forced_nop (), last_insn);
4162 loop->last_insn = last_insn;
4164 /* The loop is good for replacement. */
4165 start_label = loop->start_label;
4166 end_label = gen_label_rtx ();
4167 iter_reg = loop->iter_reg;
4169 if (loop->depth == 1 && !loop->clobber_loop1)
4171 lc_reg = reg_lc1;
4172 lt_reg = reg_lt1;
4173 lb_reg = reg_lb1;
4174 loop->clobber_loop1 = 1;
4176 else
4178 lc_reg = reg_lc0;
4179 lt_reg = reg_lt0;
4180 lb_reg = reg_lb0;
4181 loop->clobber_loop0 = 1;
4184 loop->end_label = end_label;
4186 /* Create a sequence containing the loop setup. */
4187 start_sequence ();
4189 /* LSETUP only accepts P registers. If we have one, we can use it,
4190 otherwise there are several ways of working around the problem.
4191 If we're not affected by anomaly 312, we can load the LC register
4192 from any iteration register, and use LSETUP without initialization.
4193 If we've found a P scratch register that's not live here, we can
4194 instead copy the iter_reg into that and use an initializing LSETUP.
4195 If all else fails, push and pop P0 and use it as a scratch. */
4196 if (P_REGNO_P (REGNO (iter_reg)))
4198 loop_init = gen_lsetup_with_autoinit (lt_reg, start_label,
4199 lb_reg, end_label,
4200 lc_reg, iter_reg);
4201 seq_end = emit_insn (loop_init);
4203 else if (!ENABLE_WA_LOAD_LCREGS && DPREG_P (iter_reg))
4205 emit_insn (gen_movsi (lc_reg, iter_reg));
4206 loop_init = gen_lsetup_without_autoinit (lt_reg, start_label,
4207 lb_reg, end_label,
4208 lc_reg);
4209 seq_end = emit_insn (loop_init);
4211 else if (scratchreg != NULL_RTX)
4213 emit_insn (gen_movsi (scratchreg, scratch_init));
4214 loop_init = gen_lsetup_with_autoinit (lt_reg, start_label,
4215 lb_reg, end_label,
4216 lc_reg, scratchreg);
4217 seq_end = emit_insn (loop_init);
4218 if (scratch_init_insn != NULL_RTX)
4219 delete_insn (scratch_init_insn);
4221 else
4223 rtx p0reg = gen_rtx_REG (SImode, REG_P0);
4224 rtx push = gen_frame_mem (SImode,
4225 gen_rtx_PRE_DEC (SImode, stack_pointer_rtx));
4226 rtx pop = gen_frame_mem (SImode,
4227 gen_rtx_POST_INC (SImode, stack_pointer_rtx));
4228 emit_insn (gen_movsi (push, p0reg));
4229 emit_insn (gen_movsi (p0reg, scratch_init));
4230 loop_init = gen_lsetup_with_autoinit (lt_reg, start_label,
4231 lb_reg, end_label,
4232 lc_reg, p0reg);
4233 emit_insn (loop_init);
4234 seq_end = emit_insn (gen_movsi (p0reg, pop));
4235 if (scratch_init_insn != NULL_RTX)
4236 delete_insn (scratch_init_insn);
4239 if (dump_file)
4241 fprintf (dump_file, ";; replacing loop %d initializer with\n",
4242 loop->loop_no);
4243 print_rtl_single (dump_file, loop_init);
4244 fprintf (dump_file, ";; replacing loop %d terminator with\n",
4245 loop->loop_no);
4246 print_rtl_single (dump_file, loop->loop_end);
4249 /* If the loop isn't entered at the top, also create a jump to the entry
4250 point. */
4251 if (!loop->incoming_src && loop->head != loop->incoming_dest)
4253 rtx label = BB_HEAD (loop->incoming_dest);
4254 /* If we're jumping to the final basic block in the loop, and there's
4255 only one cheap instruction before the end (typically an increment of
4256 an induction variable), we can just emit a copy here instead of a
4257 jump. */
4258 if (loop->incoming_dest == loop->tail
4259 && next_real_insn (label) == last_insn
4260 && asm_noperands (last_insn) < 0
4261 && GET_CODE (PATTERN (last_insn)) == SET)
4263 seq_end = emit_insn (copy_rtx (PATTERN (last_insn)));
4265 else
4267 emit_jump_insn (gen_jump (label));
4268 seq_end = emit_barrier ();
4272 seq = get_insns ();
4273 end_sequence ();
4275 if (loop->incoming_src)
4277 rtx prev = BB_END (loop->incoming_src);
4278 if (VEC_length (edge, loop->incoming) > 1
4279 || !(VEC_last (edge, loop->incoming)->flags & EDGE_FALLTHRU))
4281 gcc_assert (JUMP_P (prev));
4282 prev = PREV_INSN (prev);
4284 emit_insn_after (seq, prev);
4286 else
4288 basic_block new_bb;
4289 edge e;
4290 edge_iterator ei;
4292 #ifdef ENABLE_CHECKING
4293 if (loop->head != loop->incoming_dest)
4295 /* We aren't entering the loop at the top. Since we've established
4296 that the loop is entered only at one point, this means there
4297 can't be fallthru edges into the head. Any such fallthru edges
4298 would become invalid when we insert the new block, so verify
4299 that this does not in fact happen. */
4300 FOR_EACH_EDGE (e, ei, loop->head->preds)
4301 gcc_assert (!(e->flags & EDGE_FALLTHRU));
4303 #endif
4305 emit_insn_before (seq, BB_HEAD (loop->head));
4306 seq = emit_label_before (gen_label_rtx (), seq);
4308 new_bb = create_basic_block (seq, seq_end, loop->head->prev_bb);
4309 FOR_EACH_EDGE (e, ei, loop->incoming)
4311 if (!(e->flags & EDGE_FALLTHRU)
4312 || e->dest != loop->head)
4313 redirect_edge_and_branch_force (e, new_bb);
4314 else
4315 redirect_edge_succ (e, new_bb);
4317 e = make_edge (new_bb, loop->head, 0);
4320 delete_insn (loop->loop_end);
4321 /* Insert the loop end label before the last instruction of the loop. */
4322 emit_label_before (loop->end_label, loop->last_insn);
4324 return;
4326 bad_loop:
4328 if (dump_file)
4329 fprintf (dump_file, ";; loop %d is bad\n", loop->loop_no);
4331 loop->bad = 1;
4333 if (DPREG_P (loop->iter_reg))
4335 /* If loop->iter_reg is a DREG or PREG, we can split it here
4336 without scratch register. */
4337 rtx insn, test;
4339 emit_insn_before (gen_addsi3 (loop->iter_reg,
4340 loop->iter_reg,
4341 constm1_rtx),
4342 loop->loop_end);
4344 test = gen_rtx_NE (VOIDmode, loop->iter_reg, const0_rtx);
4345 insn = emit_jump_insn_before (gen_cbranchsi4 (test,
4346 loop->iter_reg, const0_rtx,
4347 loop->start_label),
4348 loop->loop_end);
4350 JUMP_LABEL (insn) = loop->start_label;
4351 LABEL_NUSES (loop->start_label)++;
4352 delete_insn (loop->loop_end);
4356 /* Called from bfin_reorg_loops when a potential loop end is found. LOOP is
4357 a newly set up structure describing the loop, it is this function's
4358 responsibility to fill most of it. TAIL_BB and TAIL_INSN point to the
4359 loop_end insn and its enclosing basic block. */
4361 static void
4362 bfin_discover_loop (loop_info loop, basic_block tail_bb, rtx tail_insn)
4364 unsigned dwork = 0;
4365 basic_block bb;
4366 VEC (basic_block,heap) *works = VEC_alloc (basic_block,heap,20);
4368 loop->tail = tail_bb;
4369 loop->head = BRANCH_EDGE (tail_bb)->dest;
4370 loop->successor = FALLTHRU_EDGE (tail_bb)->dest;
4371 loop->loop_end = tail_insn;
4372 loop->last_insn = NULL_RTX;
4373 loop->iter_reg = SET_DEST (XVECEXP (PATTERN (tail_insn), 0, 1));
4374 loop->depth = loop->length = 0;
4375 loop->visited = 0;
4376 loop->clobber_loop0 = loop->clobber_loop1 = 0;
4377 loop->outer = NULL;
4378 loop->loops = NULL;
4379 loop->incoming = VEC_alloc (edge, gc, 2);
4380 loop->start_label = XEXP (XEXP (SET_SRC (XVECEXP (PATTERN (tail_insn), 0, 0)), 1), 0);
4381 loop->end_label = NULL_RTX;
4382 loop->bad = 0;
4384 VEC_safe_push (basic_block, heap, works, loop->head);
4386 while (VEC_iterate (basic_block, works, dwork++, bb))
4388 edge e;
4389 edge_iterator ei;
4390 if (bb == EXIT_BLOCK_PTR)
4392 /* We've reached the exit block. The loop must be bad. */
4393 if (dump_file)
4394 fprintf (dump_file,
4395 ";; Loop is bad - reached exit block while scanning\n");
4396 loop->bad = 1;
4397 break;
4400 if (bitmap_bit_p (loop->block_bitmap, bb->index))
4401 continue;
4403 /* We've not seen this block before. Add it to the loop's
4404 list and then add each successor to the work list. */
4406 VEC_safe_push (basic_block, heap, loop->blocks, bb);
4407 bitmap_set_bit (loop->block_bitmap, bb->index);
4409 if (bb != tail_bb)
4411 FOR_EACH_EDGE (e, ei, bb->succs)
4413 basic_block succ = EDGE_SUCC (bb, ei.index)->dest;
4414 if (!REGNO_REG_SET_P (df_get_live_in (succ),
4415 REGNO (loop->iter_reg)))
4416 continue;
4417 if (!VEC_space (basic_block, works, 1))
4419 if (dwork)
4421 VEC_block_remove (basic_block, works, 0, dwork);
4422 dwork = 0;
4424 else
4425 VEC_reserve (basic_block, heap, works, 1);
4427 VEC_quick_push (basic_block, works, succ);
4432 /* Find the predecessor, and make sure nothing else jumps into this loop. */
4433 if (!loop->bad)
4435 int pass, retry;
4436 for (dwork = 0; VEC_iterate (basic_block, loop->blocks, dwork, bb); dwork++)
4438 edge e;
4439 edge_iterator ei;
4440 FOR_EACH_EDGE (e, ei, bb->preds)
4442 basic_block pred = e->src;
4444 if (!bfin_bb_in_loop (loop, pred))
4446 if (dump_file)
4447 fprintf (dump_file, ";; Loop %d: incoming edge %d -> %d\n",
4448 loop->loop_no, pred->index,
4449 e->dest->index);
4450 VEC_safe_push (edge, gc, loop->incoming, e);
4455 for (pass = 0, retry = 1; retry && pass < 2; pass++)
4457 edge e;
4458 edge_iterator ei;
4459 bool first = true;
4460 retry = 0;
4462 FOR_EACH_EDGE (e, ei, loop->incoming)
4464 if (first)
4466 loop->incoming_src = e->src;
4467 loop->incoming_dest = e->dest;
4468 first = false;
4470 else
4472 if (e->dest != loop->incoming_dest)
4473 loop->incoming_dest = NULL;
4474 if (e->src != loop->incoming_src)
4475 loop->incoming_src = NULL;
4477 if (loop->incoming_src == NULL && loop->incoming_dest == NULL)
4479 if (pass == 0)
4481 if (dump_file)
4482 fprintf (dump_file,
4483 ";; retrying loop %d with forwarder blocks\n",
4484 loop->loop_no);
4485 retry = 1;
4486 break;
4488 loop->bad = 1;
4489 if (dump_file)
4490 fprintf (dump_file,
4491 ";; can't find suitable entry for loop %d\n",
4492 loop->loop_no);
4493 goto out;
4496 if (retry)
4498 retry = 0;
4499 FOR_EACH_EDGE (e, ei, loop->incoming)
4501 if (forwarder_block_p (e->src))
4503 edge e2;
4504 edge_iterator ei2;
4506 if (dump_file)
4507 fprintf (dump_file,
4508 ";; Adding forwarder block %d to loop %d and retrying\n",
4509 e->src->index, loop->loop_no);
4510 VEC_safe_push (basic_block, heap, loop->blocks, e->src);
4511 bitmap_set_bit (loop->block_bitmap, e->src->index);
4512 FOR_EACH_EDGE (e2, ei2, e->src->preds)
4513 VEC_safe_push (edge, gc, loop->incoming, e2);
4514 VEC_unordered_remove (edge, loop->incoming, ei.index);
4515 retry = 1;
4516 break;
4519 if (!retry)
4521 if (dump_file)
4522 fprintf (dump_file, ";; No forwarder blocks found\n");
4523 loop->bad = 1;
4529 out:
4530 VEC_free (basic_block, heap, works);
4533 /* Analyze the structure of the loops in the current function. Use STACK
4534 for bitmap allocations. Returns all the valid candidates for hardware
4535 loops found in this function. */
4536 static loop_info
4537 bfin_discover_loops (bitmap_obstack *stack, FILE *dump_file)
4539 loop_info loops = NULL;
4540 loop_info loop;
4541 basic_block bb;
4542 bitmap tmp_bitmap;
4543 int nloops = 0;
4545 /* Find all the possible loop tails. This means searching for every
4546 loop_end instruction. For each one found, create a loop_info
4547 structure and add the head block to the work list. */
4548 FOR_EACH_BB (bb)
4550 rtx tail = BB_END (bb);
4552 while (GET_CODE (tail) == NOTE)
4553 tail = PREV_INSN (tail);
4555 bb->aux = NULL;
4557 if (INSN_P (tail) && recog_memoized (tail) == CODE_FOR_loop_end)
4559 rtx insn;
4560 /* A possible loop end */
4562 /* There's a degenerate case we can handle - an empty loop consisting
4563 of only a back branch. Handle that by deleting the branch. */
4564 insn = BB_HEAD (BRANCH_EDGE (bb)->dest);
4565 if (next_real_insn (insn) == tail)
4567 if (dump_file)
4569 fprintf (dump_file, ";; degenerate loop ending at\n");
4570 print_rtl_single (dump_file, tail);
4572 delete_insn_and_edges (tail);
4573 continue;
4576 loop = XNEW (struct loop_info);
4577 loop->next = loops;
4578 loops = loop;
4579 loop->loop_no = nloops++;
4580 loop->blocks = VEC_alloc (basic_block, heap, 20);
4581 loop->block_bitmap = BITMAP_ALLOC (stack);
4582 bb->aux = loop;
4584 if (dump_file)
4586 fprintf (dump_file, ";; potential loop %d ending at\n",
4587 loop->loop_no);
4588 print_rtl_single (dump_file, tail);
4591 bfin_discover_loop (loop, bb, tail);
4595 tmp_bitmap = BITMAP_ALLOC (stack);
4596 /* Compute loop nestings. */
4597 for (loop = loops; loop; loop = loop->next)
4599 loop_info other;
4600 if (loop->bad)
4601 continue;
4603 for (other = loop->next; other; other = other->next)
4605 if (other->bad)
4606 continue;
4608 bitmap_and (tmp_bitmap, other->block_bitmap, loop->block_bitmap);
4609 if (bitmap_empty_p (tmp_bitmap))
4610 continue;
4611 if (bitmap_equal_p (tmp_bitmap, other->block_bitmap))
4613 other->outer = loop;
4614 VEC_safe_push (loop_info, heap, loop->loops, other);
4616 else if (bitmap_equal_p (tmp_bitmap, loop->block_bitmap))
4618 loop->outer = other;
4619 VEC_safe_push (loop_info, heap, other->loops, loop);
4621 else
4623 if (dump_file)
4624 fprintf (dump_file,
4625 ";; can't find suitable nesting for loops %d and %d\n",
4626 loop->loop_no, other->loop_no);
4627 loop->bad = other->bad = 1;
4631 BITMAP_FREE (tmp_bitmap);
4633 return loops;
4636 /* Free up the loop structures in LOOPS. */
4637 static void
4638 free_loops (loop_info loops)
4640 while (loops)
4642 loop_info loop = loops;
4643 loops = loop->next;
4644 VEC_free (loop_info, heap, loop->loops);
4645 VEC_free (basic_block, heap, loop->blocks);
4646 BITMAP_FREE (loop->block_bitmap);
4647 XDELETE (loop);
4651 #define BB_AUX_INDEX(BB) ((unsigned)(BB)->aux)
4653 /* The taken-branch edge from the loop end can actually go forward. Since the
4654 Blackfin's LSETUP instruction requires that the loop end be after the loop
4655 start, try to reorder a loop's basic blocks when we find such a case. */
4656 static void
4657 bfin_reorder_loops (loop_info loops, FILE *dump_file)
4659 basic_block bb;
4660 loop_info loop;
4662 FOR_EACH_BB (bb)
4663 bb->aux = NULL;
4664 cfg_layout_initialize (0);
4666 for (loop = loops; loop; loop = loop->next)
4668 unsigned index;
4669 basic_block bb;
4670 edge e;
4671 edge_iterator ei;
4673 if (loop->bad)
4674 continue;
4676 /* Recreate an index for basic blocks that represents their order. */
4677 for (bb = ENTRY_BLOCK_PTR->next_bb, index = 0;
4678 bb != EXIT_BLOCK_PTR;
4679 bb = bb->next_bb, index++)
4680 bb->aux = (PTR) index;
4682 if (BB_AUX_INDEX (loop->head) < BB_AUX_INDEX (loop->tail))
4683 continue;
4685 FOR_EACH_EDGE (e, ei, loop->head->succs)
4687 if (bitmap_bit_p (loop->block_bitmap, e->dest->index)
4688 && BB_AUX_INDEX (e->dest) < BB_AUX_INDEX (loop->tail))
4690 basic_block start_bb = e->dest;
4691 basic_block start_prev_bb = start_bb->prev_bb;
4693 if (dump_file)
4694 fprintf (dump_file, ";; Moving block %d before block %d\n",
4695 loop->head->index, start_bb->index);
4696 loop->head->prev_bb->next_bb = loop->head->next_bb;
4697 loop->head->next_bb->prev_bb = loop->head->prev_bb;
4699 loop->head->prev_bb = start_prev_bb;
4700 loop->head->next_bb = start_bb;
4701 start_prev_bb->next_bb = start_bb->prev_bb = loop->head;
4702 break;
4705 loops = loops->next;
4708 FOR_EACH_BB (bb)
4710 if (bb->next_bb != EXIT_BLOCK_PTR)
4711 bb->aux = bb->next_bb;
4712 else
4713 bb->aux = NULL;
4715 cfg_layout_finalize ();
4716 df_analyze ();
4719 /* Run from machine_dependent_reorg, this pass looks for doloop_end insns
4720 and tries to rewrite the RTL of these loops so that proper Blackfin
4721 hardware loops are generated. */
4723 static void
4724 bfin_reorg_loops (FILE *dump_file)
4726 loop_info loops = NULL;
4727 loop_info loop;
4728 basic_block bb;
4729 bitmap_obstack stack;
4731 bitmap_obstack_initialize (&stack);
4733 if (dump_file)
4734 fprintf (dump_file, ";; Find loops, first pass\n\n");
4736 loops = bfin_discover_loops (&stack, dump_file);
4738 if (dump_file)
4739 bfin_dump_loops (loops);
4741 bfin_reorder_loops (loops, dump_file);
4742 free_loops (loops);
4744 if (dump_file)
4745 fprintf (dump_file, ";; Find loops, second pass\n\n");
4747 loops = bfin_discover_loops (&stack, dump_file);
4748 if (dump_file)
4750 fprintf (dump_file, ";; All loops found:\n\n");
4751 bfin_dump_loops (loops);
4754 /* Now apply the optimizations. */
4755 for (loop = loops; loop; loop = loop->next)
4756 bfin_optimize_loop (loop);
4758 if (dump_file)
4760 fprintf (dump_file, ";; After hardware loops optimization:\n\n");
4761 bfin_dump_loops (loops);
4764 free_loops (loops);
4766 if (dump_file)
4767 print_rtl (dump_file, get_insns ());
4769 FOR_EACH_BB (bb)
4770 bb->aux = NULL;
4772 splitting_loops = 1;
4773 FOR_EACH_BB (bb)
4775 rtx insn = BB_END (bb);
4776 if (!JUMP_P (insn))
4777 continue;
4779 try_split (PATTERN (insn), insn, 1);
4781 splitting_loops = 0;
4784 /* Possibly generate a SEQUENCE out of three insns found in SLOT.
4785 Returns true if we modified the insn chain, false otherwise. */
4786 static bool
4787 gen_one_bundle (rtx slot[3])
4789 gcc_assert (slot[1] != NULL_RTX);
4791 /* Don't add extra NOPs if optimizing for size. */
4792 if (optimize_size
4793 && (slot[0] == NULL_RTX || slot[2] == NULL_RTX))
4794 return false;
4796 /* Verify that we really can do the multi-issue. */
4797 if (slot[0])
4799 rtx t = NEXT_INSN (slot[0]);
4800 while (t != slot[1])
4802 if (GET_CODE (t) != NOTE
4803 || NOTE_KIND (t) != NOTE_INSN_DELETED)
4804 return false;
4805 t = NEXT_INSN (t);
4808 if (slot[2])
4810 rtx t = NEXT_INSN (slot[1]);
4811 while (t != slot[2])
4813 if (GET_CODE (t) != NOTE
4814 || NOTE_KIND (t) != NOTE_INSN_DELETED)
4815 return false;
4816 t = NEXT_INSN (t);
4820 if (slot[0] == NULL_RTX)
4822 slot[0] = emit_insn_before (gen_mnop (), slot[1]);
4823 df_insn_rescan (slot[0]);
4825 if (slot[2] == NULL_RTX)
4827 slot[2] = emit_insn_after (gen_forced_nop (), slot[1]);
4828 df_insn_rescan (slot[2]);
4831 /* Avoid line number information being printed inside one bundle. */
4832 if (INSN_LOCATOR (slot[1])
4833 && INSN_LOCATOR (slot[1]) != INSN_LOCATOR (slot[0]))
4834 INSN_LOCATOR (slot[1]) = INSN_LOCATOR (slot[0]);
4835 if (INSN_LOCATOR (slot[2])
4836 && INSN_LOCATOR (slot[2]) != INSN_LOCATOR (slot[0]))
4837 INSN_LOCATOR (slot[2]) = INSN_LOCATOR (slot[0]);
4839 /* Terminate them with "|| " instead of ";" in the output. */
4840 PUT_MODE (slot[0], SImode);
4841 PUT_MODE (slot[1], SImode);
4842 /* Terminate the bundle, for the benefit of reorder_var_tracking_notes. */
4843 PUT_MODE (slot[2], QImode);
4844 return true;
4847 /* Go through all insns, and use the information generated during scheduling
4848 to generate SEQUENCEs to represent bundles of instructions issued
4849 simultaneously. */
4851 static void
4852 bfin_gen_bundles (void)
4854 basic_block bb;
4855 FOR_EACH_BB (bb)
4857 rtx insn, next;
4858 rtx slot[3];
4859 int n_filled = 0;
4861 slot[0] = slot[1] = slot[2] = NULL_RTX;
4862 for (insn = BB_HEAD (bb);; insn = next)
4864 int at_end;
4865 rtx delete_this = NULL_RTX;
4867 if (NONDEBUG_INSN_P (insn))
4869 enum attr_type type = get_attr_type (insn);
4871 if (type == TYPE_STALL)
4873 gcc_assert (n_filled == 0);
4874 delete_this = insn;
4876 else
4878 if (type == TYPE_DSP32 || type == TYPE_DSP32SHIFTIMM)
4879 slot[0] = insn;
4880 else if (slot[1] == NULL_RTX)
4881 slot[1] = insn;
4882 else
4883 slot[2] = insn;
4884 n_filled++;
4888 next = NEXT_INSN (insn);
4889 while (next && insn != BB_END (bb)
4890 && !(INSN_P (next)
4891 && GET_CODE (PATTERN (next)) != USE
4892 && GET_CODE (PATTERN (next)) != CLOBBER))
4894 insn = next;
4895 next = NEXT_INSN (insn);
4898 /* BB_END can change due to emitting extra NOPs, so check here. */
4899 at_end = insn == BB_END (bb);
4900 if (delete_this == NULL_RTX && (at_end || GET_MODE (next) == TImode))
4902 if ((n_filled < 2
4903 || !gen_one_bundle (slot))
4904 && slot[0] != NULL_RTX)
4906 rtx pat = PATTERN (slot[0]);
4907 if (GET_CODE (pat) == SET
4908 && GET_CODE (SET_SRC (pat)) == UNSPEC
4909 && XINT (SET_SRC (pat), 1) == UNSPEC_32BIT)
4911 SET_SRC (pat) = XVECEXP (SET_SRC (pat), 0, 0);
4912 INSN_CODE (slot[0]) = -1;
4913 df_insn_rescan (slot[0]);
4916 n_filled = 0;
4917 slot[0] = slot[1] = slot[2] = NULL_RTX;
4919 if (delete_this != NULL_RTX)
4920 delete_insn (delete_this);
4921 if (at_end)
4922 break;
4927 /* Ensure that no var tracking notes are emitted in the middle of a
4928 three-instruction bundle. */
4930 static void
4931 reorder_var_tracking_notes (void)
4933 basic_block bb;
4934 FOR_EACH_BB (bb)
4936 rtx insn, next;
4937 rtx queue = NULL_RTX;
4938 bool in_bundle = false;
4940 for (insn = BB_HEAD (bb); insn != BB_END (bb); insn = next)
4942 next = NEXT_INSN (insn);
4944 if (INSN_P (insn))
4946 /* Emit queued up notes at the last instruction of a bundle. */
4947 if (GET_MODE (insn) == QImode)
4949 while (queue)
4951 rtx next_queue = PREV_INSN (queue);
4952 PREV_INSN (NEXT_INSN (insn)) = queue;
4953 NEXT_INSN (queue) = NEXT_INSN (insn);
4954 NEXT_INSN (insn) = queue;
4955 PREV_INSN (queue) = insn;
4956 queue = next_queue;
4958 in_bundle = false;
4960 else if (GET_MODE (insn) == SImode)
4961 in_bundle = true;
4963 else if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION)
4965 if (in_bundle)
4967 rtx prev = PREV_INSN (insn);
4968 PREV_INSN (next) = prev;
4969 NEXT_INSN (prev) = next;
4971 PREV_INSN (insn) = queue;
4972 queue = insn;
4979 /* On some silicon revisions, functions shorter than a certain number of cycles
4980 can cause unpredictable behaviour. Work around this by adding NOPs as
4981 needed. */
4982 static void
4983 workaround_rts_anomaly (void)
4985 rtx insn, first_insn = NULL_RTX;
4986 int cycles = 4;
4988 if (! ENABLE_WA_RETS)
4989 return;
4991 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
4993 rtx pat;
4995 if (BARRIER_P (insn))
4996 return;
4998 if (NOTE_P (insn) || LABEL_P (insn))
4999 continue;
5001 if (first_insn == NULL_RTX)
5002 first_insn = insn;
5003 pat = PATTERN (insn);
5004 if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER
5005 || GET_CODE (pat) == ASM_INPUT || GET_CODE (pat) == ADDR_VEC
5006 || GET_CODE (pat) == ADDR_DIFF_VEC || asm_noperands (pat) >= 0)
5007 continue;
5009 if (CALL_P (insn))
5010 return;
5012 if (JUMP_P (insn))
5014 if (recog_memoized (insn) == CODE_FOR_return_internal)
5015 break;
5017 /* Nothing to worry about for direct jumps. */
5018 if (!any_condjump_p (insn))
5019 return;
5020 if (cycles <= 1)
5021 return;
5022 cycles--;
5024 else if (INSN_P (insn))
5026 rtx pat = PATTERN (insn);
5027 int this_cycles = 1;
5029 if (GET_CODE (pat) == PARALLEL)
5031 if (push_multiple_operation (pat, VOIDmode)
5032 || pop_multiple_operation (pat, VOIDmode))
5033 this_cycles = n_regs_to_save;
5035 else
5037 enum insn_code icode = recog_memoized (insn);
5038 if (icode == CODE_FOR_link)
5039 this_cycles = 4;
5040 else if (icode == CODE_FOR_unlink)
5041 this_cycles = 3;
5042 else if (icode == CODE_FOR_mulsi3)
5043 this_cycles = 5;
5045 if (this_cycles >= cycles)
5046 return;
5048 cycles -= this_cycles;
5051 while (cycles > 0)
5053 emit_insn_before (gen_nop (), first_insn);
5054 cycles--;
5058 /* Return an insn type for INSN that can be used by the caller for anomaly
5059 workarounds. This differs from plain get_attr_type in that it handles
5060 SEQUENCEs. */
5062 static enum attr_type
5063 type_for_anomaly (rtx insn)
5065 rtx pat = PATTERN (insn);
5066 if (GET_CODE (pat) == SEQUENCE)
5068 enum attr_type t;
5069 t = get_attr_type (XVECEXP (pat, 0, 1));
5070 if (t == TYPE_MCLD)
5071 return t;
5072 t = get_attr_type (XVECEXP (pat, 0, 2));
5073 if (t == TYPE_MCLD)
5074 return t;
5075 return TYPE_MCST;
5077 else
5078 return get_attr_type (insn);
5081 /* Return true iff the address found in MEM is based on the register
5082 NP_REG and optionally has a positive offset. */
5083 static bool
5084 harmless_null_pointer_p (rtx mem, int np_reg)
5086 mem = XEXP (mem, 0);
5087 if (GET_CODE (mem) == POST_INC || GET_CODE (mem) == POST_DEC)
5088 mem = XEXP (mem, 0);
5089 if (REG_P (mem) && REGNO (mem) == np_reg)
5090 return true;
5091 if (GET_CODE (mem) == PLUS
5092 && REG_P (XEXP (mem, 0)) && REGNO (XEXP (mem, 0)) == np_reg)
5094 mem = XEXP (mem, 1);
5095 if (GET_CODE (mem) == CONST_INT && INTVAL (mem) > 0)
5096 return true;
5098 return false;
5101 /* Return nonzero if INSN contains any loads that may trap. */
5103 static bool
5104 trapping_loads_p (rtx insn, int np_reg, bool after_np_branch)
5106 rtx pat = PATTERN (insn);
5107 rtx mem = SET_SRC (single_set (insn));
5109 if (!after_np_branch)
5110 np_reg = -1;
5111 return ((np_reg == -1 || !harmless_null_pointer_p (mem, np_reg))
5112 && may_trap_p (mem));
5115 /* Return INSN if it is of TYPE_MCLD. Alternatively, if INSN is the start of
5116 a three-insn bundle, see if one of them is a load and return that if so.
5117 Return NULL_RTX if the insn does not contain loads. */
5118 static rtx
5119 find_load (rtx insn)
5121 if (!NONDEBUG_INSN_P (insn))
5122 return NULL_RTX;
5123 if (get_attr_type (insn) == TYPE_MCLD)
5124 return insn;
5125 if (GET_MODE (insn) != SImode)
5126 return NULL_RTX;
5127 do {
5128 insn = NEXT_INSN (insn);
5129 if ((GET_MODE (insn) == SImode || GET_MODE (insn) == QImode)
5130 && get_attr_type (insn) == TYPE_MCLD)
5131 return insn;
5132 } while (GET_MODE (insn) != QImode);
5133 return NULL_RTX;
5136 /* Determine whether PAT is an indirect call pattern. */
5137 static bool
5138 indirect_call_p (rtx pat)
5140 if (GET_CODE (pat) == PARALLEL)
5141 pat = XVECEXP (pat, 0, 0);
5142 if (GET_CODE (pat) == SET)
5143 pat = SET_SRC (pat);
5144 gcc_assert (GET_CODE (pat) == CALL);
5145 pat = XEXP (pat, 0);
5146 gcc_assert (GET_CODE (pat) == MEM);
5147 pat = XEXP (pat, 0);
5149 return REG_P (pat);
5152 /* During workaround_speculation, track whether we're in the shadow of a
5153 conditional branch that tests a P register for NULL. If so, we can omit
5154 emitting NOPs if we see a load from that P register, since a speculative
5155 access at address 0 isn't a problem, and the load is executed in all other
5156 cases anyway.
5157 Global for communication with note_np_check_stores through note_stores.
5159 int np_check_regno = -1;
5160 bool np_after_branch = false;
5162 /* Subroutine of workaround_speculation, called through note_stores. */
5163 static void
5164 note_np_check_stores (rtx x, const_rtx pat, void *data ATTRIBUTE_UNUSED)
5166 if (REG_P (x) && (REGNO (x) == REG_CC || REGNO (x) == np_check_regno))
5167 np_check_regno = -1;
5170 static void
5171 workaround_speculation (void)
5173 rtx insn, next;
5174 rtx last_condjump = NULL_RTX;
5175 int cycles_since_jump = INT_MAX;
5176 int delay_added = 0;
5178 if (! ENABLE_WA_SPECULATIVE_LOADS && ! ENABLE_WA_SPECULATIVE_SYNCS
5179 && ! ENABLE_WA_INDIRECT_CALLS)
5180 return;
5182 /* First pass: find predicted-false branches; if something after them
5183 needs nops, insert them or change the branch to predict true. */
5184 for (insn = get_insns (); insn; insn = next)
5186 rtx pat;
5187 int delay_needed = 0;
5189 next = find_next_insn_start (insn);
5191 if (NOTE_P (insn) || BARRIER_P (insn))
5192 continue;
5194 if (LABEL_P (insn))
5196 np_check_regno = -1;
5197 continue;
5200 pat = PATTERN (insn);
5201 if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER
5202 || GET_CODE (pat) == ADDR_VEC || GET_CODE (pat) == ADDR_DIFF_VEC)
5203 continue;
5205 if (GET_CODE (pat) == ASM_INPUT || asm_noperands (pat) >= 0)
5207 np_check_regno = -1;
5208 continue;
5211 if (JUMP_P (insn))
5213 /* Is this a condjump based on a null pointer comparison we saw
5214 earlier? */
5215 if (np_check_regno != -1
5216 && recog_memoized (insn) == CODE_FOR_cbranchbi4)
5218 rtx op = XEXP (SET_SRC (PATTERN (insn)), 0);
5219 gcc_assert (GET_CODE (op) == EQ || GET_CODE (op) == NE);
5220 if (GET_CODE (op) == NE)
5221 np_after_branch = true;
5223 if (any_condjump_p (insn)
5224 && ! cbranch_predicted_taken_p (insn))
5226 last_condjump = insn;
5227 delay_added = 0;
5228 cycles_since_jump = 0;
5230 else
5231 cycles_since_jump = INT_MAX;
5233 else if (CALL_P (insn))
5235 np_check_regno = -1;
5236 if (cycles_since_jump < INT_MAX)
5237 cycles_since_jump++;
5238 if (indirect_call_p (pat) && ENABLE_WA_INDIRECT_CALLS)
5240 delay_needed = 3;
5243 else if (NONDEBUG_INSN_P (insn))
5245 rtx load_insn = find_load (insn);
5246 enum attr_type type = type_for_anomaly (insn);
5248 if (cycles_since_jump < INT_MAX)
5249 cycles_since_jump++;
5251 /* Detect a comparison of a P register with zero. If we later
5252 see a condjump based on it, we have found a null pointer
5253 check. */
5254 if (recog_memoized (insn) == CODE_FOR_compare_eq)
5256 rtx src = SET_SRC (PATTERN (insn));
5257 if (REG_P (XEXP (src, 0))
5258 && P_REGNO_P (REGNO (XEXP (src, 0)))
5259 && XEXP (src, 1) == const0_rtx)
5261 np_check_regno = REGNO (XEXP (src, 0));
5262 np_after_branch = false;
5264 else
5265 np_check_regno = -1;
5268 if (load_insn && ENABLE_WA_SPECULATIVE_LOADS)
5270 if (trapping_loads_p (load_insn, np_check_regno,
5271 np_after_branch))
5272 delay_needed = 4;
5274 else if (type == TYPE_SYNC && ENABLE_WA_SPECULATIVE_SYNCS)
5275 delay_needed = 3;
5277 /* See if we need to forget about a null pointer comparison
5278 we found earlier. */
5279 if (recog_memoized (insn) != CODE_FOR_compare_eq)
5281 note_stores (PATTERN (insn), note_np_check_stores, NULL);
5282 if (np_check_regno != -1)
5284 if (find_regno_note (insn, REG_INC, np_check_regno))
5285 np_check_regno = -1;
5291 if (delay_needed > cycles_since_jump
5292 && (delay_needed - cycles_since_jump) > delay_added)
5294 rtx pat1;
5295 int num_clobbers;
5296 rtx *op = recog_data.operand;
5298 delay_needed -= cycles_since_jump;
5300 extract_insn (last_condjump);
5301 if (optimize_size)
5303 pat1 = gen_cbranch_predicted_taken (op[0], op[1], op[2],
5304 op[3]);
5305 cycles_since_jump = INT_MAX;
5307 else
5309 /* Do not adjust cycles_since_jump in this case, so that
5310 we'll increase the number of NOPs for a subsequent insn
5311 if necessary. */
5312 pat1 = gen_cbranch_with_nops (op[0], op[1], op[2], op[3],
5313 GEN_INT (delay_needed));
5314 delay_added = delay_needed;
5316 PATTERN (last_condjump) = pat1;
5317 INSN_CODE (last_condjump) = recog (pat1, insn, &num_clobbers);
5319 if (CALL_P (insn))
5321 cycles_since_jump = INT_MAX;
5322 delay_added = 0;
5326 /* Second pass: for predicted-true branches, see if anything at the
5327 branch destination needs extra nops. */
5328 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
5330 int cycles_since_jump;
5331 if (JUMP_P (insn)
5332 && any_condjump_p (insn)
5333 && (INSN_CODE (insn) == CODE_FOR_cbranch_predicted_taken
5334 || cbranch_predicted_taken_p (insn)))
5336 rtx target = JUMP_LABEL (insn);
5337 rtx label = target;
5338 rtx next_tgt;
5340 cycles_since_jump = 0;
5341 for (; target && cycles_since_jump < 3; target = next_tgt)
5343 rtx pat;
5345 next_tgt = find_next_insn_start (target);
5347 if (NOTE_P (target) || BARRIER_P (target) || LABEL_P (target))
5348 continue;
5350 pat = PATTERN (target);
5351 if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER
5352 || GET_CODE (pat) == ASM_INPUT || GET_CODE (pat) == ADDR_VEC
5353 || GET_CODE (pat) == ADDR_DIFF_VEC || asm_noperands (pat) >= 0)
5354 continue;
5356 if (NONDEBUG_INSN_P (target))
5358 rtx load_insn = find_load (target);
5359 enum attr_type type = type_for_anomaly (target);
5360 int delay_needed = 0;
5361 if (cycles_since_jump < INT_MAX)
5362 cycles_since_jump++;
5364 if (load_insn && ENABLE_WA_SPECULATIVE_LOADS)
5366 if (trapping_loads_p (load_insn, -1, false))
5367 delay_needed = 2;
5369 else if (type == TYPE_SYNC && ENABLE_WA_SPECULATIVE_SYNCS)
5370 delay_needed = 2;
5372 if (delay_needed > cycles_since_jump)
5374 rtx prev = prev_real_insn (label);
5375 delay_needed -= cycles_since_jump;
5376 if (dump_file)
5377 fprintf (dump_file, "Adding %d nops after %d\n",
5378 delay_needed, INSN_UID (label));
5379 if (JUMP_P (prev)
5380 && INSN_CODE (prev) == CODE_FOR_cbranch_with_nops)
5382 rtx x;
5383 HOST_WIDE_INT v;
5385 if (dump_file)
5386 fprintf (dump_file,
5387 "Reducing nops on insn %d.\n",
5388 INSN_UID (prev));
5389 x = PATTERN (prev);
5390 x = XVECEXP (x, 0, 1);
5391 v = INTVAL (XVECEXP (x, 0, 0)) - delay_needed;
5392 XVECEXP (x, 0, 0) = GEN_INT (v);
5394 while (delay_needed-- > 0)
5395 emit_insn_after (gen_nop (), label);
5396 break;
5404 /* Called just before the final scheduling pass. If we need to insert NOPs
5405 later on to work around speculative loads, insert special placeholder
5406 insns that cause loads to be delayed for as many cycles as necessary
5407 (and possible). This reduces the number of NOPs we need to add.
5408 The dummy insns we generate are later removed by bfin_gen_bundles. */
5409 static void
5410 add_sched_insns_for_speculation (void)
5412 rtx insn;
5414 if (! ENABLE_WA_SPECULATIVE_LOADS && ! ENABLE_WA_SPECULATIVE_SYNCS
5415 && ! ENABLE_WA_INDIRECT_CALLS)
5416 return;
5418 /* First pass: find predicted-false branches; if something after them
5419 needs nops, insert them or change the branch to predict true. */
5420 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
5422 rtx pat;
5424 if (NOTE_P (insn) || BARRIER_P (insn) || LABEL_P (insn))
5425 continue;
5427 pat = PATTERN (insn);
5428 if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER
5429 || GET_CODE (pat) == ASM_INPUT || GET_CODE (pat) == ADDR_VEC
5430 || GET_CODE (pat) == ADDR_DIFF_VEC || asm_noperands (pat) >= 0)
5431 continue;
5433 if (JUMP_P (insn))
5435 if (any_condjump_p (insn)
5436 && !cbranch_predicted_taken_p (insn))
5438 rtx n = next_real_insn (insn);
5439 emit_insn_before (gen_stall (GEN_INT (3)), n);
5444 /* Second pass: for predicted-true branches, see if anything at the
5445 branch destination needs extra nops. */
5446 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
5448 if (JUMP_P (insn)
5449 && any_condjump_p (insn)
5450 && (cbranch_predicted_taken_p (insn)))
5452 rtx target = JUMP_LABEL (insn);
5453 rtx next = next_real_insn (target);
5455 if (GET_CODE (PATTERN (next)) == UNSPEC_VOLATILE
5456 && get_attr_type (next) == TYPE_STALL)
5457 continue;
5458 emit_insn_before (gen_stall (GEN_INT (1)), next);
5463 /* We use the machine specific reorg pass for emitting CSYNC instructions
5464 after conditional branches as needed.
5466 The Blackfin is unusual in that a code sequence like
5467 if cc jump label
5468 r0 = (p0)
5469 may speculatively perform the load even if the condition isn't true. This
5470 happens for a branch that is predicted not taken, because the pipeline
5471 isn't flushed or stalled, so the early stages of the following instructions,
5472 which perform the memory reference, are allowed to execute before the
5473 jump condition is evaluated.
5474 Therefore, we must insert additional instructions in all places where this
5475 could lead to incorrect behavior. The manual recommends CSYNC, while
5476 VDSP seems to use NOPs (even though its corresponding compiler option is
5477 named CSYNC).
5479 When optimizing for speed, we emit NOPs, which seems faster than a CSYNC.
5480 When optimizing for size, we turn the branch into a predicted taken one.
5481 This may be slower due to mispredicts, but saves code size. */
5483 static void
5484 bfin_reorg (void)
5486 /* We are freeing block_for_insn in the toplev to keep compatibility
5487 with old MDEP_REORGS that are not CFG based. Recompute it now. */
5488 compute_bb_for_insn ();
5490 if (bfin_flag_schedule_insns2)
5492 splitting_for_sched = 1;
5493 split_all_insns ();
5494 splitting_for_sched = 0;
5496 add_sched_insns_for_speculation ();
5498 timevar_push (TV_SCHED2);
5499 if (flag_selective_scheduling2
5500 && !maybe_skip_selective_scheduling ())
5501 run_selective_scheduling ();
5502 else
5503 schedule_insns ();
5504 timevar_pop (TV_SCHED2);
5506 /* Examine the schedule and insert nops as necessary for 64-bit parallel
5507 instructions. */
5508 bfin_gen_bundles ();
5511 df_analyze ();
5513 /* Doloop optimization */
5514 if (cfun->machine->has_hardware_loops)
5515 bfin_reorg_loops (dump_file);
5517 workaround_speculation ();
5519 if (bfin_flag_var_tracking)
5521 timevar_push (TV_VAR_TRACKING);
5522 variable_tracking_main ();
5523 reorder_var_tracking_notes ();
5524 timevar_pop (TV_VAR_TRACKING);
5527 df_finish_pass (false);
5529 workaround_rts_anomaly ();
5532 /* Handle interrupt_handler, exception_handler and nmi_handler function
5533 attributes; arguments as in struct attribute_spec.handler. */
5535 static tree
5536 handle_int_attribute (tree *node, tree name,
5537 tree args ATTRIBUTE_UNUSED,
5538 int flags ATTRIBUTE_UNUSED,
5539 bool *no_add_attrs)
5541 tree x = *node;
5542 if (TREE_CODE (x) == FUNCTION_DECL)
5543 x = TREE_TYPE (x);
5545 if (TREE_CODE (x) != FUNCTION_TYPE)
5547 warning (OPT_Wattributes, "%qE attribute only applies to functions",
5548 name);
5549 *no_add_attrs = true;
5551 else if (funkind (x) != SUBROUTINE)
5552 error ("multiple function type attributes specified");
5554 return NULL_TREE;
5557 /* Return 0 if the attributes for two types are incompatible, 1 if they
5558 are compatible, and 2 if they are nearly compatible (which causes a
5559 warning to be generated). */
5561 static int
5562 bfin_comp_type_attributes (const_tree type1, const_tree type2)
5564 e_funkind kind1, kind2;
5566 if (TREE_CODE (type1) != FUNCTION_TYPE)
5567 return 1;
5569 kind1 = funkind (type1);
5570 kind2 = funkind (type2);
5572 if (kind1 != kind2)
5573 return 0;
5575 /* Check for mismatched modifiers */
5576 if (!lookup_attribute ("nesting", TYPE_ATTRIBUTES (type1))
5577 != !lookup_attribute ("nesting", TYPE_ATTRIBUTES (type2)))
5578 return 0;
5580 if (!lookup_attribute ("saveall", TYPE_ATTRIBUTES (type1))
5581 != !lookup_attribute ("saveall", TYPE_ATTRIBUTES (type2)))
5582 return 0;
5584 if (!lookup_attribute ("kspisusp", TYPE_ATTRIBUTES (type1))
5585 != !lookup_attribute ("kspisusp", TYPE_ATTRIBUTES (type2)))
5586 return 0;
5588 if (!lookup_attribute ("longcall", TYPE_ATTRIBUTES (type1))
5589 != !lookup_attribute ("longcall", TYPE_ATTRIBUTES (type2)))
5590 return 0;
5592 return 1;
5595 /* Handle a "longcall" or "shortcall" attribute; arguments as in
5596 struct attribute_spec.handler. */
5598 static tree
5599 bfin_handle_longcall_attribute (tree *node, tree name,
5600 tree args ATTRIBUTE_UNUSED,
5601 int flags ATTRIBUTE_UNUSED,
5602 bool *no_add_attrs)
5604 if (TREE_CODE (*node) != FUNCTION_TYPE
5605 && TREE_CODE (*node) != FIELD_DECL
5606 && TREE_CODE (*node) != TYPE_DECL)
5608 warning (OPT_Wattributes, "%qE attribute only applies to functions",
5609 name);
5610 *no_add_attrs = true;
5613 if ((strcmp (IDENTIFIER_POINTER (name), "longcall") == 0
5614 && lookup_attribute ("shortcall", TYPE_ATTRIBUTES (*node)))
5615 || (strcmp (IDENTIFIER_POINTER (name), "shortcall") == 0
5616 && lookup_attribute ("longcall", TYPE_ATTRIBUTES (*node))))
5618 warning (OPT_Wattributes,
5619 "can't apply both longcall and shortcall attributes to the same function");
5620 *no_add_attrs = true;
5623 return NULL_TREE;
5626 /* Handle a "l1_text" attribute; arguments as in
5627 struct attribute_spec.handler. */
5629 static tree
5630 bfin_handle_l1_text_attribute (tree *node, tree name, tree ARG_UNUSED (args),
5631 int ARG_UNUSED (flags), bool *no_add_attrs)
5633 tree decl = *node;
5635 if (TREE_CODE (decl) != FUNCTION_DECL)
5637 error ("%qE attribute only applies to functions",
5638 name);
5639 *no_add_attrs = true;
5642 /* The decl may have already been given a section attribute
5643 from a previous declaration. Ensure they match. */
5644 else if (DECL_SECTION_NAME (decl) != NULL_TREE
5645 && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
5646 ".l1.text") != 0)
5648 error ("section of %q+D conflicts with previous declaration",
5649 decl);
5650 *no_add_attrs = true;
5652 else
5653 DECL_SECTION_NAME (decl) = build_string (9, ".l1.text");
5655 return NULL_TREE;
5658 /* Handle a "l1_data", "l1_data_A" or "l1_data_B" attribute;
5659 arguments as in struct attribute_spec.handler. */
5661 static tree
5662 bfin_handle_l1_data_attribute (tree *node, tree name, tree ARG_UNUSED (args),
5663 int ARG_UNUSED (flags), bool *no_add_attrs)
5665 tree decl = *node;
5667 if (TREE_CODE (decl) != VAR_DECL)
5669 error ("%qE attribute only applies to variables",
5670 name);
5671 *no_add_attrs = true;
5673 else if (current_function_decl != NULL_TREE
5674 && !TREE_STATIC (decl))
5676 error ("%qE attribute cannot be specified for local variables",
5677 name);
5678 *no_add_attrs = true;
5680 else
5682 const char *section_name;
5684 if (strcmp (IDENTIFIER_POINTER (name), "l1_data") == 0)
5685 section_name = ".l1.data";
5686 else if (strcmp (IDENTIFIER_POINTER (name), "l1_data_A") == 0)
5687 section_name = ".l1.data.A";
5688 else if (strcmp (IDENTIFIER_POINTER (name), "l1_data_B") == 0)
5689 section_name = ".l1.data.B";
5690 else
5691 gcc_unreachable ();
5693 /* The decl may have already been given a section attribute
5694 from a previous declaration. Ensure they match. */
5695 if (DECL_SECTION_NAME (decl) != NULL_TREE
5696 && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
5697 section_name) != 0)
5699 error ("section of %q+D conflicts with previous declaration",
5700 decl);
5701 *no_add_attrs = true;
5703 else
5704 DECL_SECTION_NAME (decl)
5705 = build_string (strlen (section_name) + 1, section_name);
5708 return NULL_TREE;
5711 /* Handle a "l2" attribute; arguments as in struct attribute_spec.handler. */
5713 static tree
5714 bfin_handle_l2_attribute (tree *node, tree ARG_UNUSED (name),
5715 tree ARG_UNUSED (args), int ARG_UNUSED (flags),
5716 bool *no_add_attrs)
5718 tree decl = *node;
5720 if (TREE_CODE (decl) == FUNCTION_DECL)
5722 if (DECL_SECTION_NAME (decl) != NULL_TREE
5723 && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
5724 ".l2.text") != 0)
5726 error ("section of %q+D conflicts with previous declaration",
5727 decl);
5728 *no_add_attrs = true;
5730 else
5731 DECL_SECTION_NAME (decl) = build_string (9, ".l2.text");
5733 else if (TREE_CODE (decl) == VAR_DECL)
5735 if (DECL_SECTION_NAME (decl) != NULL_TREE
5736 && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
5737 ".l2.data") != 0)
5739 error ("section of %q+D conflicts with previous declaration",
5740 decl);
5741 *no_add_attrs = true;
5743 else
5744 DECL_SECTION_NAME (decl) = build_string (9, ".l2.data");
5747 return NULL_TREE;
5750 /* Table of valid machine attributes. */
5751 static const struct attribute_spec bfin_attribute_table[] =
5753 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
5754 { "interrupt_handler", 0, 0, false, true, true, handle_int_attribute },
5755 { "exception_handler", 0, 0, false, true, true, handle_int_attribute },
5756 { "nmi_handler", 0, 0, false, true, true, handle_int_attribute },
5757 { "nesting", 0, 0, false, true, true, NULL },
5758 { "kspisusp", 0, 0, false, true, true, NULL },
5759 { "saveall", 0, 0, false, true, true, NULL },
5760 { "longcall", 0, 0, false, true, true, bfin_handle_longcall_attribute },
5761 { "shortcall", 0, 0, false, true, true, bfin_handle_longcall_attribute },
5762 { "l1_text", 0, 0, true, false, false, bfin_handle_l1_text_attribute },
5763 { "l1_data", 0, 0, true, false, false, bfin_handle_l1_data_attribute },
5764 { "l1_data_A", 0, 0, true, false, false, bfin_handle_l1_data_attribute },
5765 { "l1_data_B", 0, 0, true, false, false, bfin_handle_l1_data_attribute },
5766 { "l2", 0, 0, true, false, false, bfin_handle_l2_attribute },
5767 { NULL, 0, 0, false, false, false, NULL }
5770 /* Implementation of TARGET_ASM_INTEGER. When using FD-PIC, we need to
5771 tell the assembler to generate pointers to function descriptors in
5772 some cases. */
5774 static bool
5775 bfin_assemble_integer (rtx value, unsigned int size, int aligned_p)
5777 if (TARGET_FDPIC && size == UNITS_PER_WORD)
5779 if (GET_CODE (value) == SYMBOL_REF
5780 && SYMBOL_REF_FUNCTION_P (value))
5782 fputs ("\t.picptr\tfuncdesc(", asm_out_file);
5783 output_addr_const (asm_out_file, value);
5784 fputs (")\n", asm_out_file);
5785 return true;
5787 if (!aligned_p)
5789 /* We've set the unaligned SI op to NULL, so we always have to
5790 handle the unaligned case here. */
5791 assemble_integer_with_op ("\t.4byte\t", value);
5792 return true;
5795 return default_assemble_integer (value, size, aligned_p);
5798 /* Output the assembler code for a thunk function. THUNK_DECL is the
5799 declaration for the thunk function itself, FUNCTION is the decl for
5800 the target function. DELTA is an immediate constant offset to be
5801 added to THIS. If VCALL_OFFSET is nonzero, the word at
5802 *(*this + vcall_offset) should be added to THIS. */
5804 static void
5805 bfin_output_mi_thunk (FILE *file ATTRIBUTE_UNUSED,
5806 tree thunk ATTRIBUTE_UNUSED, HOST_WIDE_INT delta,
5807 HOST_WIDE_INT vcall_offset, tree function)
5809 rtx xops[3];
5810 /* The this parameter is passed as the first argument. */
5811 rtx this_rtx = gen_rtx_REG (Pmode, REG_R0);
5813 /* Adjust the this parameter by a fixed constant. */
5814 if (delta)
5816 xops[1] = this_rtx;
5817 if (delta >= -64 && delta <= 63)
5819 xops[0] = GEN_INT (delta);
5820 output_asm_insn ("%1 += %0;", xops);
5822 else if (delta >= -128 && delta < -64)
5824 xops[0] = GEN_INT (delta + 64);
5825 output_asm_insn ("%1 += -64; %1 += %0;", xops);
5827 else if (delta > 63 && delta <= 126)
5829 xops[0] = GEN_INT (delta - 63);
5830 output_asm_insn ("%1 += 63; %1 += %0;", xops);
5832 else
5834 xops[0] = GEN_INT (delta);
5835 output_asm_insn ("r3.l = %h0; r3.h = %d0; %1 = %1 + r3;", xops);
5839 /* Adjust the this parameter by a value stored in the vtable. */
5840 if (vcall_offset)
5842 rtx p2tmp = gen_rtx_REG (Pmode, REG_P2);
5843 rtx tmp = gen_rtx_REG (Pmode, REG_R3);
5845 xops[1] = tmp;
5846 xops[2] = p2tmp;
5847 output_asm_insn ("%2 = r0; %2 = [%2];", xops);
5849 /* Adjust the this parameter. */
5850 xops[0] = gen_rtx_MEM (Pmode, plus_constant (p2tmp, vcall_offset));
5851 if (!memory_operand (xops[0], Pmode))
5853 rtx tmp2 = gen_rtx_REG (Pmode, REG_P1);
5854 xops[0] = GEN_INT (vcall_offset);
5855 xops[1] = tmp2;
5856 output_asm_insn ("%h1 = %h0; %d1 = %d0; %2 = %2 + %1", xops);
5857 xops[0] = gen_rtx_MEM (Pmode, p2tmp);
5859 xops[2] = this_rtx;
5860 output_asm_insn ("%1 = %0; %2 = %2 + %1;", xops);
5863 xops[0] = XEXP (DECL_RTL (function), 0);
5864 if (1 || !flag_pic || (*targetm.binds_local_p) (function))
5865 output_asm_insn ("jump.l\t%P0", xops);
5868 /* Codes for all the Blackfin builtins. */
5869 enum bfin_builtins
5871 BFIN_BUILTIN_CSYNC,
5872 BFIN_BUILTIN_SSYNC,
5873 BFIN_BUILTIN_ONES,
5874 BFIN_BUILTIN_COMPOSE_2X16,
5875 BFIN_BUILTIN_EXTRACTLO,
5876 BFIN_BUILTIN_EXTRACTHI,
5878 BFIN_BUILTIN_SSADD_2X16,
5879 BFIN_BUILTIN_SSSUB_2X16,
5880 BFIN_BUILTIN_SSADDSUB_2X16,
5881 BFIN_BUILTIN_SSSUBADD_2X16,
5882 BFIN_BUILTIN_MULT_2X16,
5883 BFIN_BUILTIN_MULTR_2X16,
5884 BFIN_BUILTIN_NEG_2X16,
5885 BFIN_BUILTIN_ABS_2X16,
5886 BFIN_BUILTIN_MIN_2X16,
5887 BFIN_BUILTIN_MAX_2X16,
5889 BFIN_BUILTIN_SSADD_1X16,
5890 BFIN_BUILTIN_SSSUB_1X16,
5891 BFIN_BUILTIN_MULT_1X16,
5892 BFIN_BUILTIN_MULTR_1X16,
5893 BFIN_BUILTIN_NORM_1X16,
5894 BFIN_BUILTIN_NEG_1X16,
5895 BFIN_BUILTIN_ABS_1X16,
5896 BFIN_BUILTIN_MIN_1X16,
5897 BFIN_BUILTIN_MAX_1X16,
5899 BFIN_BUILTIN_SUM_2X16,
5900 BFIN_BUILTIN_DIFFHL_2X16,
5901 BFIN_BUILTIN_DIFFLH_2X16,
5903 BFIN_BUILTIN_SSADD_1X32,
5904 BFIN_BUILTIN_SSSUB_1X32,
5905 BFIN_BUILTIN_NORM_1X32,
5906 BFIN_BUILTIN_ROUND_1X32,
5907 BFIN_BUILTIN_NEG_1X32,
5908 BFIN_BUILTIN_ABS_1X32,
5909 BFIN_BUILTIN_MIN_1X32,
5910 BFIN_BUILTIN_MAX_1X32,
5911 BFIN_BUILTIN_MULT_1X32,
5912 BFIN_BUILTIN_MULT_1X32X32,
5913 BFIN_BUILTIN_MULT_1X32X32NS,
5915 BFIN_BUILTIN_MULHISILL,
5916 BFIN_BUILTIN_MULHISILH,
5917 BFIN_BUILTIN_MULHISIHL,
5918 BFIN_BUILTIN_MULHISIHH,
5920 BFIN_BUILTIN_LSHIFT_1X16,
5921 BFIN_BUILTIN_LSHIFT_2X16,
5922 BFIN_BUILTIN_SSASHIFT_1X16,
5923 BFIN_BUILTIN_SSASHIFT_2X16,
5924 BFIN_BUILTIN_SSASHIFT_1X32,
5926 BFIN_BUILTIN_CPLX_MUL_16,
5927 BFIN_BUILTIN_CPLX_MAC_16,
5928 BFIN_BUILTIN_CPLX_MSU_16,
5930 BFIN_BUILTIN_CPLX_MUL_16_S40,
5931 BFIN_BUILTIN_CPLX_MAC_16_S40,
5932 BFIN_BUILTIN_CPLX_MSU_16_S40,
5934 BFIN_BUILTIN_CPLX_SQU,
5936 BFIN_BUILTIN_LOADBYTES,
5938 BFIN_BUILTIN_MAX
5941 #define def_builtin(NAME, TYPE, CODE) \
5942 do { \
5943 add_builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD, \
5944 NULL, NULL_TREE); \
5945 } while (0)
5947 /* Set up all builtin functions for this target. */
5948 static void
5949 bfin_init_builtins (void)
5951 tree V2HI_type_node = build_vector_type_for_mode (intHI_type_node, V2HImode);
5952 tree void_ftype_void
5953 = build_function_type (void_type_node, void_list_node);
5954 tree short_ftype_short
5955 = build_function_type_list (short_integer_type_node, short_integer_type_node,
5956 NULL_TREE);
5957 tree short_ftype_int_int
5958 = build_function_type_list (short_integer_type_node, integer_type_node,
5959 integer_type_node, NULL_TREE);
5960 tree int_ftype_int_int
5961 = build_function_type_list (integer_type_node, integer_type_node,
5962 integer_type_node, NULL_TREE);
5963 tree int_ftype_int
5964 = build_function_type_list (integer_type_node, integer_type_node,
5965 NULL_TREE);
5966 tree short_ftype_int
5967 = build_function_type_list (short_integer_type_node, integer_type_node,
5968 NULL_TREE);
5969 tree int_ftype_v2hi_v2hi
5970 = build_function_type_list (integer_type_node, V2HI_type_node,
5971 V2HI_type_node, NULL_TREE);
5972 tree v2hi_ftype_v2hi_v2hi
5973 = build_function_type_list (V2HI_type_node, V2HI_type_node,
5974 V2HI_type_node, NULL_TREE);
5975 tree v2hi_ftype_v2hi_v2hi_v2hi
5976 = build_function_type_list (V2HI_type_node, V2HI_type_node,
5977 V2HI_type_node, V2HI_type_node, NULL_TREE);
5978 tree v2hi_ftype_int_int
5979 = build_function_type_list (V2HI_type_node, integer_type_node,
5980 integer_type_node, NULL_TREE);
5981 tree v2hi_ftype_v2hi_int
5982 = build_function_type_list (V2HI_type_node, V2HI_type_node,
5983 integer_type_node, NULL_TREE);
5984 tree int_ftype_short_short
5985 = build_function_type_list (integer_type_node, short_integer_type_node,
5986 short_integer_type_node, NULL_TREE);
5987 tree v2hi_ftype_v2hi
5988 = build_function_type_list (V2HI_type_node, V2HI_type_node, NULL_TREE);
5989 tree short_ftype_v2hi
5990 = build_function_type_list (short_integer_type_node, V2HI_type_node,
5991 NULL_TREE);
5992 tree int_ftype_pint
5993 = build_function_type_list (integer_type_node,
5994 build_pointer_type (integer_type_node),
5995 NULL_TREE);
5997 /* Add the remaining MMX insns with somewhat more complicated types. */
5998 def_builtin ("__builtin_bfin_csync", void_ftype_void, BFIN_BUILTIN_CSYNC);
5999 def_builtin ("__builtin_bfin_ssync", void_ftype_void, BFIN_BUILTIN_SSYNC);
6001 def_builtin ("__builtin_bfin_ones", short_ftype_int, BFIN_BUILTIN_ONES);
6003 def_builtin ("__builtin_bfin_compose_2x16", v2hi_ftype_int_int,
6004 BFIN_BUILTIN_COMPOSE_2X16);
6005 def_builtin ("__builtin_bfin_extract_hi", short_ftype_v2hi,
6006 BFIN_BUILTIN_EXTRACTHI);
6007 def_builtin ("__builtin_bfin_extract_lo", short_ftype_v2hi,
6008 BFIN_BUILTIN_EXTRACTLO);
6010 def_builtin ("__builtin_bfin_min_fr2x16", v2hi_ftype_v2hi_v2hi,
6011 BFIN_BUILTIN_MIN_2X16);
6012 def_builtin ("__builtin_bfin_max_fr2x16", v2hi_ftype_v2hi_v2hi,
6013 BFIN_BUILTIN_MAX_2X16);
6015 def_builtin ("__builtin_bfin_add_fr2x16", v2hi_ftype_v2hi_v2hi,
6016 BFIN_BUILTIN_SSADD_2X16);
6017 def_builtin ("__builtin_bfin_sub_fr2x16", v2hi_ftype_v2hi_v2hi,
6018 BFIN_BUILTIN_SSSUB_2X16);
6019 def_builtin ("__builtin_bfin_dspaddsubsat", v2hi_ftype_v2hi_v2hi,
6020 BFIN_BUILTIN_SSADDSUB_2X16);
6021 def_builtin ("__builtin_bfin_dspsubaddsat", v2hi_ftype_v2hi_v2hi,
6022 BFIN_BUILTIN_SSSUBADD_2X16);
6023 def_builtin ("__builtin_bfin_mult_fr2x16", v2hi_ftype_v2hi_v2hi,
6024 BFIN_BUILTIN_MULT_2X16);
6025 def_builtin ("__builtin_bfin_multr_fr2x16", v2hi_ftype_v2hi_v2hi,
6026 BFIN_BUILTIN_MULTR_2X16);
6027 def_builtin ("__builtin_bfin_negate_fr2x16", v2hi_ftype_v2hi,
6028 BFIN_BUILTIN_NEG_2X16);
6029 def_builtin ("__builtin_bfin_abs_fr2x16", v2hi_ftype_v2hi,
6030 BFIN_BUILTIN_ABS_2X16);
6032 def_builtin ("__builtin_bfin_min_fr1x16", short_ftype_int_int,
6033 BFIN_BUILTIN_MIN_1X16);
6034 def_builtin ("__builtin_bfin_max_fr1x16", short_ftype_int_int,
6035 BFIN_BUILTIN_MAX_1X16);
6037 def_builtin ("__builtin_bfin_add_fr1x16", short_ftype_int_int,
6038 BFIN_BUILTIN_SSADD_1X16);
6039 def_builtin ("__builtin_bfin_sub_fr1x16", short_ftype_int_int,
6040 BFIN_BUILTIN_SSSUB_1X16);
6041 def_builtin ("__builtin_bfin_mult_fr1x16", short_ftype_int_int,
6042 BFIN_BUILTIN_MULT_1X16);
6043 def_builtin ("__builtin_bfin_multr_fr1x16", short_ftype_int_int,
6044 BFIN_BUILTIN_MULTR_1X16);
6045 def_builtin ("__builtin_bfin_negate_fr1x16", short_ftype_short,
6046 BFIN_BUILTIN_NEG_1X16);
6047 def_builtin ("__builtin_bfin_abs_fr1x16", short_ftype_short,
6048 BFIN_BUILTIN_ABS_1X16);
6049 def_builtin ("__builtin_bfin_norm_fr1x16", short_ftype_int,
6050 BFIN_BUILTIN_NORM_1X16);
6052 def_builtin ("__builtin_bfin_sum_fr2x16", short_ftype_v2hi,
6053 BFIN_BUILTIN_SUM_2X16);
6054 def_builtin ("__builtin_bfin_diff_hl_fr2x16", short_ftype_v2hi,
6055 BFIN_BUILTIN_DIFFHL_2X16);
6056 def_builtin ("__builtin_bfin_diff_lh_fr2x16", short_ftype_v2hi,
6057 BFIN_BUILTIN_DIFFLH_2X16);
6059 def_builtin ("__builtin_bfin_mulhisill", int_ftype_v2hi_v2hi,
6060 BFIN_BUILTIN_MULHISILL);
6061 def_builtin ("__builtin_bfin_mulhisihl", int_ftype_v2hi_v2hi,
6062 BFIN_BUILTIN_MULHISIHL);
6063 def_builtin ("__builtin_bfin_mulhisilh", int_ftype_v2hi_v2hi,
6064 BFIN_BUILTIN_MULHISILH);
6065 def_builtin ("__builtin_bfin_mulhisihh", int_ftype_v2hi_v2hi,
6066 BFIN_BUILTIN_MULHISIHH);
6068 def_builtin ("__builtin_bfin_min_fr1x32", int_ftype_int_int,
6069 BFIN_BUILTIN_MIN_1X32);
6070 def_builtin ("__builtin_bfin_max_fr1x32", int_ftype_int_int,
6071 BFIN_BUILTIN_MAX_1X32);
6073 def_builtin ("__builtin_bfin_add_fr1x32", int_ftype_int_int,
6074 BFIN_BUILTIN_SSADD_1X32);
6075 def_builtin ("__builtin_bfin_sub_fr1x32", int_ftype_int_int,
6076 BFIN_BUILTIN_SSSUB_1X32);
6077 def_builtin ("__builtin_bfin_negate_fr1x32", int_ftype_int,
6078 BFIN_BUILTIN_NEG_1X32);
6079 def_builtin ("__builtin_bfin_abs_fr1x32", int_ftype_int,
6080 BFIN_BUILTIN_ABS_1X32);
6081 def_builtin ("__builtin_bfin_norm_fr1x32", short_ftype_int,
6082 BFIN_BUILTIN_NORM_1X32);
6083 def_builtin ("__builtin_bfin_round_fr1x32", short_ftype_int,
6084 BFIN_BUILTIN_ROUND_1X32);
6085 def_builtin ("__builtin_bfin_mult_fr1x32", int_ftype_short_short,
6086 BFIN_BUILTIN_MULT_1X32);
6087 def_builtin ("__builtin_bfin_mult_fr1x32x32", int_ftype_int_int,
6088 BFIN_BUILTIN_MULT_1X32X32);
6089 def_builtin ("__builtin_bfin_mult_fr1x32x32NS", int_ftype_int_int,
6090 BFIN_BUILTIN_MULT_1X32X32NS);
6092 /* Shifts. */
6093 def_builtin ("__builtin_bfin_shl_fr1x16", short_ftype_int_int,
6094 BFIN_BUILTIN_SSASHIFT_1X16);
6095 def_builtin ("__builtin_bfin_shl_fr2x16", v2hi_ftype_v2hi_int,
6096 BFIN_BUILTIN_SSASHIFT_2X16);
6097 def_builtin ("__builtin_bfin_lshl_fr1x16", short_ftype_int_int,
6098 BFIN_BUILTIN_LSHIFT_1X16);
6099 def_builtin ("__builtin_bfin_lshl_fr2x16", v2hi_ftype_v2hi_int,
6100 BFIN_BUILTIN_LSHIFT_2X16);
6101 def_builtin ("__builtin_bfin_shl_fr1x32", int_ftype_int_int,
6102 BFIN_BUILTIN_SSASHIFT_1X32);
6104 /* Complex numbers. */
6105 def_builtin ("__builtin_bfin_cmplx_add", v2hi_ftype_v2hi_v2hi,
6106 BFIN_BUILTIN_SSADD_2X16);
6107 def_builtin ("__builtin_bfin_cmplx_sub", v2hi_ftype_v2hi_v2hi,
6108 BFIN_BUILTIN_SSSUB_2X16);
6109 def_builtin ("__builtin_bfin_cmplx_mul", v2hi_ftype_v2hi_v2hi,
6110 BFIN_BUILTIN_CPLX_MUL_16);
6111 def_builtin ("__builtin_bfin_cmplx_mac", v2hi_ftype_v2hi_v2hi_v2hi,
6112 BFIN_BUILTIN_CPLX_MAC_16);
6113 def_builtin ("__builtin_bfin_cmplx_msu", v2hi_ftype_v2hi_v2hi_v2hi,
6114 BFIN_BUILTIN_CPLX_MSU_16);
6115 def_builtin ("__builtin_bfin_cmplx_mul_s40", v2hi_ftype_v2hi_v2hi,
6116 BFIN_BUILTIN_CPLX_MUL_16_S40);
6117 def_builtin ("__builtin_bfin_cmplx_mac_s40", v2hi_ftype_v2hi_v2hi_v2hi,
6118 BFIN_BUILTIN_CPLX_MAC_16_S40);
6119 def_builtin ("__builtin_bfin_cmplx_msu_s40", v2hi_ftype_v2hi_v2hi_v2hi,
6120 BFIN_BUILTIN_CPLX_MSU_16_S40);
6121 def_builtin ("__builtin_bfin_csqu_fr16", v2hi_ftype_v2hi,
6122 BFIN_BUILTIN_CPLX_SQU);
6124 /* "Unaligned" load. */
6125 def_builtin ("__builtin_bfin_loadbytes", int_ftype_pint,
6126 BFIN_BUILTIN_LOADBYTES);
6131 struct builtin_description
6133 const enum insn_code icode;
6134 const char *const name;
6135 const enum bfin_builtins code;
6136 int macflag;
6139 static const struct builtin_description bdesc_2arg[] =
6141 { CODE_FOR_composev2hi, "__builtin_bfin_compose_2x16", BFIN_BUILTIN_COMPOSE_2X16, -1 },
6143 { CODE_FOR_ssashiftv2hi3, "__builtin_bfin_shl_fr2x16", BFIN_BUILTIN_SSASHIFT_2X16, -1 },
6144 { CODE_FOR_ssashifthi3, "__builtin_bfin_shl_fr1x16", BFIN_BUILTIN_SSASHIFT_1X16, -1 },
6145 { CODE_FOR_lshiftv2hi3, "__builtin_bfin_lshl_fr2x16", BFIN_BUILTIN_LSHIFT_2X16, -1 },
6146 { CODE_FOR_lshifthi3, "__builtin_bfin_lshl_fr1x16", BFIN_BUILTIN_LSHIFT_1X16, -1 },
6147 { CODE_FOR_ssashiftsi3, "__builtin_bfin_shl_fr1x32", BFIN_BUILTIN_SSASHIFT_1X32, -1 },
6149 { CODE_FOR_sminhi3, "__builtin_bfin_min_fr1x16", BFIN_BUILTIN_MIN_1X16, -1 },
6150 { CODE_FOR_smaxhi3, "__builtin_bfin_max_fr1x16", BFIN_BUILTIN_MAX_1X16, -1 },
6151 { CODE_FOR_ssaddhi3, "__builtin_bfin_add_fr1x16", BFIN_BUILTIN_SSADD_1X16, -1 },
6152 { CODE_FOR_sssubhi3, "__builtin_bfin_sub_fr1x16", BFIN_BUILTIN_SSSUB_1X16, -1 },
6154 { CODE_FOR_sminsi3, "__builtin_bfin_min_fr1x32", BFIN_BUILTIN_MIN_1X32, -1 },
6155 { CODE_FOR_smaxsi3, "__builtin_bfin_max_fr1x32", BFIN_BUILTIN_MAX_1X32, -1 },
6156 { CODE_FOR_ssaddsi3, "__builtin_bfin_add_fr1x32", BFIN_BUILTIN_SSADD_1X32, -1 },
6157 { CODE_FOR_sssubsi3, "__builtin_bfin_sub_fr1x32", BFIN_BUILTIN_SSSUB_1X32, -1 },
6159 { CODE_FOR_sminv2hi3, "__builtin_bfin_min_fr2x16", BFIN_BUILTIN_MIN_2X16, -1 },
6160 { CODE_FOR_smaxv2hi3, "__builtin_bfin_max_fr2x16", BFIN_BUILTIN_MAX_2X16, -1 },
6161 { CODE_FOR_ssaddv2hi3, "__builtin_bfin_add_fr2x16", BFIN_BUILTIN_SSADD_2X16, -1 },
6162 { CODE_FOR_sssubv2hi3, "__builtin_bfin_sub_fr2x16", BFIN_BUILTIN_SSSUB_2X16, -1 },
6163 { CODE_FOR_ssaddsubv2hi3, "__builtin_bfin_dspaddsubsat", BFIN_BUILTIN_SSADDSUB_2X16, -1 },
6164 { CODE_FOR_sssubaddv2hi3, "__builtin_bfin_dspsubaddsat", BFIN_BUILTIN_SSSUBADD_2X16, -1 },
6166 { CODE_FOR_flag_mulhisi, "__builtin_bfin_mult_fr1x32", BFIN_BUILTIN_MULT_1X32, MACFLAG_NONE },
6167 { CODE_FOR_flag_mulhi, "__builtin_bfin_mult_fr1x16", BFIN_BUILTIN_MULT_1X16, MACFLAG_T },
6168 { CODE_FOR_flag_mulhi, "__builtin_bfin_multr_fr1x16", BFIN_BUILTIN_MULTR_1X16, MACFLAG_NONE },
6169 { CODE_FOR_flag_mulv2hi, "__builtin_bfin_mult_fr2x16", BFIN_BUILTIN_MULT_2X16, MACFLAG_T },
6170 { CODE_FOR_flag_mulv2hi, "__builtin_bfin_multr_fr2x16", BFIN_BUILTIN_MULTR_2X16, MACFLAG_NONE },
6172 { CODE_FOR_mulhisi_ll, "__builtin_bfin_mulhisill", BFIN_BUILTIN_MULHISILL, -1 },
6173 { CODE_FOR_mulhisi_lh, "__builtin_bfin_mulhisilh", BFIN_BUILTIN_MULHISILH, -1 },
6174 { CODE_FOR_mulhisi_hl, "__builtin_bfin_mulhisihl", BFIN_BUILTIN_MULHISIHL, -1 },
6175 { CODE_FOR_mulhisi_hh, "__builtin_bfin_mulhisihh", BFIN_BUILTIN_MULHISIHH, -1 }
6179 static const struct builtin_description bdesc_1arg[] =
6181 { CODE_FOR_loadbytes, "__builtin_bfin_loadbytes", BFIN_BUILTIN_LOADBYTES, 0 },
6183 { CODE_FOR_ones, "__builtin_bfin_ones", BFIN_BUILTIN_ONES, 0 },
6185 { CODE_FOR_signbitshi2, "__builtin_bfin_norm_fr1x16", BFIN_BUILTIN_NORM_1X16, 0 },
6186 { CODE_FOR_ssneghi2, "__builtin_bfin_negate_fr1x16", BFIN_BUILTIN_NEG_1X16, 0 },
6187 { CODE_FOR_abshi2, "__builtin_bfin_abs_fr1x16", BFIN_BUILTIN_ABS_1X16, 0 },
6189 { CODE_FOR_signbitssi2, "__builtin_bfin_norm_fr1x32", BFIN_BUILTIN_NORM_1X32, 0 },
6190 { CODE_FOR_ssroundsi2, "__builtin_bfin_round_fr1x32", BFIN_BUILTIN_ROUND_1X32, 0 },
6191 { CODE_FOR_ssnegsi2, "__builtin_bfin_negate_fr1x32", BFIN_BUILTIN_NEG_1X32, 0 },
6192 { CODE_FOR_ssabssi2, "__builtin_bfin_abs_fr1x32", BFIN_BUILTIN_ABS_1X32, 0 },
6194 { CODE_FOR_movv2hi_hi_low, "__builtin_bfin_extract_lo", BFIN_BUILTIN_EXTRACTLO, 0 },
6195 { CODE_FOR_movv2hi_hi_high, "__builtin_bfin_extract_hi", BFIN_BUILTIN_EXTRACTHI, 0 },
6196 { CODE_FOR_ssnegv2hi2, "__builtin_bfin_negate_fr2x16", BFIN_BUILTIN_NEG_2X16, 0 },
6197 { CODE_FOR_ssabsv2hi2, "__builtin_bfin_abs_fr2x16", BFIN_BUILTIN_ABS_2X16, 0 }
6200 /* Errors in the source file can cause expand_expr to return const0_rtx
6201 where we expect a vector. To avoid crashing, use one of the vector
6202 clear instructions. */
6203 static rtx
6204 safe_vector_operand (rtx x, enum machine_mode mode)
6206 if (x != const0_rtx)
6207 return x;
6208 x = gen_reg_rtx (SImode);
6210 emit_insn (gen_movsi (x, CONST0_RTX (SImode)));
6211 return gen_lowpart (mode, x);
6214 /* Subroutine of bfin_expand_builtin to take care of binop insns. MACFLAG is -1
6215 if this is a normal binary op, or one of the MACFLAG_xxx constants. */
6217 static rtx
6218 bfin_expand_binop_builtin (enum insn_code icode, tree exp, rtx target,
6219 int macflag)
6221 rtx pat;
6222 tree arg0 = CALL_EXPR_ARG (exp, 0);
6223 tree arg1 = CALL_EXPR_ARG (exp, 1);
6224 rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6225 rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
6226 enum machine_mode op0mode = GET_MODE (op0);
6227 enum machine_mode op1mode = GET_MODE (op1);
6228 enum machine_mode tmode = insn_data[icode].operand[0].mode;
6229 enum machine_mode mode0 = insn_data[icode].operand[1].mode;
6230 enum machine_mode mode1 = insn_data[icode].operand[2].mode;
6232 if (VECTOR_MODE_P (mode0))
6233 op0 = safe_vector_operand (op0, mode0);
6234 if (VECTOR_MODE_P (mode1))
6235 op1 = safe_vector_operand (op1, mode1);
6237 if (! target
6238 || GET_MODE (target) != tmode
6239 || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
6240 target = gen_reg_rtx (tmode);
6242 if ((op0mode == SImode || op0mode == VOIDmode) && mode0 == HImode)
6244 op0mode = HImode;
6245 op0 = gen_lowpart (HImode, op0);
6247 if ((op1mode == SImode || op1mode == VOIDmode) && mode1 == HImode)
6249 op1mode = HImode;
6250 op1 = gen_lowpart (HImode, op1);
6252 /* In case the insn wants input operands in modes different from
6253 the result, abort. */
6254 gcc_assert ((op0mode == mode0 || op0mode == VOIDmode)
6255 && (op1mode == mode1 || op1mode == VOIDmode));
6257 if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
6258 op0 = copy_to_mode_reg (mode0, op0);
6259 if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
6260 op1 = copy_to_mode_reg (mode1, op1);
6262 if (macflag == -1)
6263 pat = GEN_FCN (icode) (target, op0, op1);
6264 else
6265 pat = GEN_FCN (icode) (target, op0, op1, GEN_INT (macflag));
6266 if (! pat)
6267 return 0;
6269 emit_insn (pat);
6270 return target;
6273 /* Subroutine of bfin_expand_builtin to take care of unop insns. */
6275 static rtx
6276 bfin_expand_unop_builtin (enum insn_code icode, tree exp,
6277 rtx target)
6279 rtx pat;
6280 tree arg0 = CALL_EXPR_ARG (exp, 0);
6281 rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6282 enum machine_mode op0mode = GET_MODE (op0);
6283 enum machine_mode tmode = insn_data[icode].operand[0].mode;
6284 enum machine_mode mode0 = insn_data[icode].operand[1].mode;
6286 if (! target
6287 || GET_MODE (target) != tmode
6288 || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
6289 target = gen_reg_rtx (tmode);
6291 if (VECTOR_MODE_P (mode0))
6292 op0 = safe_vector_operand (op0, mode0);
6294 if (op0mode == SImode && mode0 == HImode)
6296 op0mode = HImode;
6297 op0 = gen_lowpart (HImode, op0);
6299 gcc_assert (op0mode == mode0 || op0mode == VOIDmode);
6301 if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
6302 op0 = copy_to_mode_reg (mode0, op0);
6304 pat = GEN_FCN (icode) (target, op0);
6305 if (! pat)
6306 return 0;
6307 emit_insn (pat);
6308 return target;
6311 /* Expand an expression EXP that calls a built-in function,
6312 with result going to TARGET if that's convenient
6313 (and in mode MODE if that's convenient).
6314 SUBTARGET may be used as the target for computing one of EXP's operands.
6315 IGNORE is nonzero if the value is to be ignored. */
6317 static rtx
6318 bfin_expand_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
6319 rtx subtarget ATTRIBUTE_UNUSED,
6320 enum machine_mode mode ATTRIBUTE_UNUSED,
6321 int ignore ATTRIBUTE_UNUSED)
6323 size_t i;
6324 enum insn_code icode;
6325 const struct builtin_description *d;
6326 tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
6327 unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
6328 tree arg0, arg1, arg2;
6329 rtx op0, op1, op2, accvec, pat, tmp1, tmp2, a0reg, a1reg;
6330 enum machine_mode tmode, mode0;
6332 switch (fcode)
6334 case BFIN_BUILTIN_CSYNC:
6335 emit_insn (gen_csync ());
6336 return 0;
6337 case BFIN_BUILTIN_SSYNC:
6338 emit_insn (gen_ssync ());
6339 return 0;
6341 case BFIN_BUILTIN_DIFFHL_2X16:
6342 case BFIN_BUILTIN_DIFFLH_2X16:
6343 case BFIN_BUILTIN_SUM_2X16:
6344 arg0 = CALL_EXPR_ARG (exp, 0);
6345 op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6346 icode = (fcode == BFIN_BUILTIN_DIFFHL_2X16 ? CODE_FOR_subhilov2hi3
6347 : fcode == BFIN_BUILTIN_DIFFLH_2X16 ? CODE_FOR_sublohiv2hi3
6348 : CODE_FOR_ssaddhilov2hi3);
6349 tmode = insn_data[icode].operand[0].mode;
6350 mode0 = insn_data[icode].operand[1].mode;
6352 if (! target
6353 || GET_MODE (target) != tmode
6354 || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
6355 target = gen_reg_rtx (tmode);
6357 if (VECTOR_MODE_P (mode0))
6358 op0 = safe_vector_operand (op0, mode0);
6360 if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
6361 op0 = copy_to_mode_reg (mode0, op0);
6363 pat = GEN_FCN (icode) (target, op0, op0);
6364 if (! pat)
6365 return 0;
6366 emit_insn (pat);
6367 return target;
6369 case BFIN_BUILTIN_MULT_1X32X32:
6370 case BFIN_BUILTIN_MULT_1X32X32NS:
6371 arg0 = CALL_EXPR_ARG (exp, 0);
6372 arg1 = CALL_EXPR_ARG (exp, 1);
6373 op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6374 op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
6375 if (! target
6376 || !register_operand (target, SImode))
6377 target = gen_reg_rtx (SImode);
6378 if (! register_operand (op0, SImode))
6379 op0 = copy_to_mode_reg (SImode, op0);
6380 if (! register_operand (op1, SImode))
6381 op1 = copy_to_mode_reg (SImode, op1);
6383 a1reg = gen_rtx_REG (PDImode, REG_A1);
6384 a0reg = gen_rtx_REG (PDImode, REG_A0);
6385 tmp1 = gen_lowpart (V2HImode, op0);
6386 tmp2 = gen_lowpart (V2HImode, op1);
6387 emit_insn (gen_flag_macinit1hi (a1reg,
6388 gen_lowpart (HImode, op0),
6389 gen_lowpart (HImode, op1),
6390 GEN_INT (MACFLAG_FU)));
6391 emit_insn (gen_lshrpdi3 (a1reg, a1reg, GEN_INT (16)));
6393 if (fcode == BFIN_BUILTIN_MULT_1X32X32)
6394 emit_insn (gen_flag_mul_macv2hi_parts_acconly (a0reg, a1reg, tmp1, tmp2,
6395 const1_rtx, const1_rtx,
6396 const1_rtx, const0_rtx, a1reg,
6397 const0_rtx, GEN_INT (MACFLAG_NONE),
6398 GEN_INT (MACFLAG_M)));
6399 else
6401 /* For saturating multiplication, there's exactly one special case
6402 to be handled: multiplying the smallest negative value with
6403 itself. Due to shift correction in fractional multiplies, this
6404 can overflow. Iff this happens, OP2 will contain 1, which, when
6405 added in 32 bits to the smallest negative, wraps to the largest
6406 positive, which is the result we want. */
6407 op2 = gen_reg_rtx (V2HImode);
6408 emit_insn (gen_packv2hi (op2, tmp1, tmp2, const0_rtx, const0_rtx));
6409 emit_insn (gen_movsibi (gen_rtx_REG (BImode, REG_CC),
6410 gen_lowpart (SImode, op2)));
6411 emit_insn (gen_flag_mul_macv2hi_parts_acconly_andcc0 (a0reg, a1reg, tmp1, tmp2,
6412 const1_rtx, const1_rtx,
6413 const1_rtx, const0_rtx, a1reg,
6414 const0_rtx, GEN_INT (MACFLAG_NONE),
6415 GEN_INT (MACFLAG_M)));
6416 op2 = gen_reg_rtx (SImode);
6417 emit_insn (gen_movbisi (op2, gen_rtx_REG (BImode, REG_CC)));
6419 emit_insn (gen_flag_machi_parts_acconly (a1reg, tmp2, tmp1,
6420 const1_rtx, const0_rtx,
6421 a1reg, const0_rtx, GEN_INT (MACFLAG_M)));
6422 emit_insn (gen_ashrpdi3 (a1reg, a1reg, GEN_INT (15)));
6423 emit_insn (gen_sum_of_accumulators (target, a0reg, a0reg, a1reg));
6424 if (fcode == BFIN_BUILTIN_MULT_1X32X32NS)
6425 emit_insn (gen_addsi3 (target, target, op2));
6426 return target;
6428 case BFIN_BUILTIN_CPLX_MUL_16:
6429 case BFIN_BUILTIN_CPLX_MUL_16_S40:
6430 arg0 = CALL_EXPR_ARG (exp, 0);
6431 arg1 = CALL_EXPR_ARG (exp, 1);
6432 op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6433 op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
6434 accvec = gen_reg_rtx (V2PDImode);
6435 icode = CODE_FOR_flag_macv2hi_parts;
6437 if (! target
6438 || GET_MODE (target) != V2HImode
6439 || ! (*insn_data[icode].operand[0].predicate) (target, V2HImode))
6440 target = gen_reg_rtx (tmode);
6441 if (! register_operand (op0, GET_MODE (op0)))
6442 op0 = copy_to_mode_reg (GET_MODE (op0), op0);
6443 if (! register_operand (op1, GET_MODE (op1)))
6444 op1 = copy_to_mode_reg (GET_MODE (op1), op1);
6446 if (fcode == BFIN_BUILTIN_CPLX_MUL_16)
6447 emit_insn (gen_flag_macinit1v2hi_parts (accvec, op0, op1, const0_rtx,
6448 const0_rtx, const0_rtx,
6449 const1_rtx, GEN_INT (MACFLAG_W32)));
6450 else
6451 emit_insn (gen_flag_macinit1v2hi_parts (accvec, op0, op1, const0_rtx,
6452 const0_rtx, const0_rtx,
6453 const1_rtx, GEN_INT (MACFLAG_NONE)));
6454 emit_insn (gen_flag_macv2hi_parts (target, op0, op1, const1_rtx,
6455 const1_rtx, const1_rtx,
6456 const0_rtx, accvec, const1_rtx, const0_rtx,
6457 GEN_INT (MACFLAG_NONE), accvec));
6459 return target;
6461 case BFIN_BUILTIN_CPLX_MAC_16:
6462 case BFIN_BUILTIN_CPLX_MSU_16:
6463 case BFIN_BUILTIN_CPLX_MAC_16_S40:
6464 case BFIN_BUILTIN_CPLX_MSU_16_S40:
6465 arg0 = CALL_EXPR_ARG (exp, 0);
6466 arg1 = CALL_EXPR_ARG (exp, 1);
6467 arg2 = CALL_EXPR_ARG (exp, 2);
6468 op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6469 op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
6470 op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
6471 accvec = gen_reg_rtx (V2PDImode);
6472 icode = CODE_FOR_flag_macv2hi_parts;
6474 if (! target
6475 || GET_MODE (target) != V2HImode
6476 || ! (*insn_data[icode].operand[0].predicate) (target, V2HImode))
6477 target = gen_reg_rtx (tmode);
6478 if (! register_operand (op1, GET_MODE (op1)))
6479 op1 = copy_to_mode_reg (GET_MODE (op1), op1);
6480 if (! register_operand (op2, GET_MODE (op2)))
6481 op2 = copy_to_mode_reg (GET_MODE (op2), op2);
6483 tmp1 = gen_reg_rtx (SImode);
6484 tmp2 = gen_reg_rtx (SImode);
6485 emit_insn (gen_ashlsi3 (tmp1, gen_lowpart (SImode, op0), GEN_INT (16)));
6486 emit_move_insn (tmp2, gen_lowpart (SImode, op0));
6487 emit_insn (gen_movstricthi_1 (gen_lowpart (HImode, tmp2), const0_rtx));
6488 emit_insn (gen_load_accumulator_pair (accvec, tmp1, tmp2));
6489 if (fcode == BFIN_BUILTIN_CPLX_MAC_16
6490 || fcode == BFIN_BUILTIN_CPLX_MSU_16)
6491 emit_insn (gen_flag_macv2hi_parts_acconly (accvec, op1, op2, const0_rtx,
6492 const0_rtx, const0_rtx,
6493 const1_rtx, accvec, const0_rtx,
6494 const0_rtx,
6495 GEN_INT (MACFLAG_W32)));
6496 else
6497 emit_insn (gen_flag_macv2hi_parts_acconly (accvec, op1, op2, const0_rtx,
6498 const0_rtx, const0_rtx,
6499 const1_rtx, accvec, const0_rtx,
6500 const0_rtx,
6501 GEN_INT (MACFLAG_NONE)));
6502 if (fcode == BFIN_BUILTIN_CPLX_MAC_16
6503 || fcode == BFIN_BUILTIN_CPLX_MAC_16_S40)
6505 tmp1 = const1_rtx;
6506 tmp2 = const0_rtx;
6508 else
6510 tmp1 = const0_rtx;
6511 tmp2 = const1_rtx;
6513 emit_insn (gen_flag_macv2hi_parts (target, op1, op2, const1_rtx,
6514 const1_rtx, const1_rtx,
6515 const0_rtx, accvec, tmp1, tmp2,
6516 GEN_INT (MACFLAG_NONE), accvec));
6518 return target;
6520 case BFIN_BUILTIN_CPLX_SQU:
6521 arg0 = CALL_EXPR_ARG (exp, 0);
6522 op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6523 accvec = gen_reg_rtx (V2PDImode);
6524 icode = CODE_FOR_flag_mulv2hi;
6525 tmp1 = gen_reg_rtx (V2HImode);
6526 tmp2 = gen_reg_rtx (V2HImode);
6528 if (! target
6529 || GET_MODE (target) != V2HImode
6530 || ! (*insn_data[icode].operand[0].predicate) (target, V2HImode))
6531 target = gen_reg_rtx (V2HImode);
6532 if (! register_operand (op0, GET_MODE (op0)))
6533 op0 = copy_to_mode_reg (GET_MODE (op0), op0);
6535 emit_insn (gen_flag_mulv2hi (tmp1, op0, op0, GEN_INT (MACFLAG_NONE)));
6537 emit_insn (gen_flag_mulhi_parts (gen_lowpart (HImode, tmp2), op0, op0,
6538 const0_rtx, const1_rtx,
6539 GEN_INT (MACFLAG_NONE)));
6541 emit_insn (gen_ssaddhi3_high_parts (target, tmp2, tmp2, tmp2, const0_rtx,
6542 const0_rtx));
6543 emit_insn (gen_sssubhi3_low_parts (target, target, tmp1, tmp1,
6544 const0_rtx, const1_rtx));
6546 return target;
6548 default:
6549 break;
6552 for (i = 0, d = bdesc_2arg; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
6553 if (d->code == fcode)
6554 return bfin_expand_binop_builtin (d->icode, exp, target,
6555 d->macflag);
6557 for (i = 0, d = bdesc_1arg; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
6558 if (d->code == fcode)
6559 return bfin_expand_unop_builtin (d->icode, exp, target);
6561 gcc_unreachable ();
6564 #undef TARGET_INIT_BUILTINS
6565 #define TARGET_INIT_BUILTINS bfin_init_builtins
6567 #undef TARGET_EXPAND_BUILTIN
6568 #define TARGET_EXPAND_BUILTIN bfin_expand_builtin
6570 #undef TARGET_ASM_GLOBALIZE_LABEL
6571 #define TARGET_ASM_GLOBALIZE_LABEL bfin_globalize_label
6573 #undef TARGET_ASM_FILE_START
6574 #define TARGET_ASM_FILE_START output_file_start
6576 #undef TARGET_ATTRIBUTE_TABLE
6577 #define TARGET_ATTRIBUTE_TABLE bfin_attribute_table
6579 #undef TARGET_COMP_TYPE_ATTRIBUTES
6580 #define TARGET_COMP_TYPE_ATTRIBUTES bfin_comp_type_attributes
6582 #undef TARGET_RTX_COSTS
6583 #define TARGET_RTX_COSTS bfin_rtx_costs
6585 #undef TARGET_ADDRESS_COST
6586 #define TARGET_ADDRESS_COST bfin_address_cost
6588 #undef TARGET_ASM_INTEGER
6589 #define TARGET_ASM_INTEGER bfin_assemble_integer
6591 #undef TARGET_MACHINE_DEPENDENT_REORG
6592 #define TARGET_MACHINE_DEPENDENT_REORG bfin_reorg
6594 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
6595 #define TARGET_FUNCTION_OK_FOR_SIBCALL bfin_function_ok_for_sibcall
6597 #undef TARGET_ASM_OUTPUT_MI_THUNK
6598 #define TARGET_ASM_OUTPUT_MI_THUNK bfin_output_mi_thunk
6599 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
6600 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true
6602 #undef TARGET_SCHED_ADJUST_COST
6603 #define TARGET_SCHED_ADJUST_COST bfin_adjust_cost
6605 #undef TARGET_SCHED_ISSUE_RATE
6606 #define TARGET_SCHED_ISSUE_RATE bfin_issue_rate
6608 #undef TARGET_PROMOTE_FUNCTION_MODE
6609 #define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
6611 #undef TARGET_ARG_PARTIAL_BYTES
6612 #define TARGET_ARG_PARTIAL_BYTES bfin_arg_partial_bytes
6614 #undef TARGET_PASS_BY_REFERENCE
6615 #define TARGET_PASS_BY_REFERENCE bfin_pass_by_reference
6617 #undef TARGET_SETUP_INCOMING_VARARGS
6618 #define TARGET_SETUP_INCOMING_VARARGS setup_incoming_varargs
6620 #undef TARGET_STRUCT_VALUE_RTX
6621 #define TARGET_STRUCT_VALUE_RTX bfin_struct_value_rtx
6623 #undef TARGET_VECTOR_MODE_SUPPORTED_P
6624 #define TARGET_VECTOR_MODE_SUPPORTED_P bfin_vector_mode_supported_p
6626 #undef TARGET_HANDLE_OPTION
6627 #define TARGET_HANDLE_OPTION bfin_handle_option
6629 #undef TARGET_DEFAULT_TARGET_FLAGS
6630 #define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
6632 #undef TARGET_SECONDARY_RELOAD
6633 #define TARGET_SECONDARY_RELOAD bfin_secondary_reload
6635 #undef TARGET_DELEGITIMIZE_ADDRESS
6636 #define TARGET_DELEGITIMIZE_ADDRESS bfin_delegitimize_address
6638 #undef TARGET_CANNOT_FORCE_CONST_MEM
6639 #define TARGET_CANNOT_FORCE_CONST_MEM bfin_cannot_force_const_mem
6641 #undef TARGET_RETURN_IN_MEMORY
6642 #define TARGET_RETURN_IN_MEMORY bfin_return_in_memory
6644 #undef TARGET_LEGITIMATE_ADDRESS_P
6645 #define TARGET_LEGITIMATE_ADDRESS_P bfin_legitimate_address_p
6647 #undef TARGET_FRAME_POINTER_REQUIRED
6648 #define TARGET_FRAME_POINTER_REQUIRED bfin_frame_pointer_required
6650 #undef TARGET_CAN_ELIMINATE
6651 #define TARGET_CAN_ELIMINATE bfin_can_eliminate
6653 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
6654 #define TARGET_ASM_TRAMPOLINE_TEMPLATE bfin_asm_trampoline_template
6655 #undef TARGET_TRAMPOLINE_INIT
6656 #define TARGET_TRAMPOLINE_INIT bfin_trampoline_init
6658 struct gcc_target targetm = TARGET_INITIALIZER;