hashtab.h: Update GTY annotations to new syntax
[official-gcc.git] / gcc / config / bfin / bfin.c
blobadb72b077a826b3be29a2ab1813798e92bc43fec
1 /* The Blackfin code generation auxiliary output file.
2 Copyright (C) 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
3 Contributed by Analog Devices.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published
9 by the Free Software Foundation; either version 3, or (at your
10 option) any later version.
12 GCC is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
15 License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "tm.h"
25 #include "rtl.h"
26 #include "regs.h"
27 #include "hard-reg-set.h"
28 #include "real.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;
66 /* Set if we create a memcpy pattern that uses loop registers. */
67 int has_loopreg_clobber;
70 /* Test and compare insns in bfin.md store the information needed to
71 generate branch and scc insns here. */
72 rtx bfin_compare_op0, bfin_compare_op1;
74 /* RTX for condition code flag register and RETS register */
75 extern GTY(()) rtx bfin_cc_rtx;
76 extern GTY(()) rtx bfin_rets_rtx;
77 rtx bfin_cc_rtx, bfin_rets_rtx;
79 int max_arg_registers = 0;
81 /* Arrays used when emitting register names. */
82 const char *short_reg_names[] = SHORT_REGISTER_NAMES;
83 const char *high_reg_names[] = HIGH_REGISTER_NAMES;
84 const char *dregs_pair_names[] = DREGS_PAIR_NAMES;
85 const char *byte_reg_names[] = BYTE_REGISTER_NAMES;
87 static int arg_regs[] = FUNCTION_ARG_REGISTERS;
89 /* Nonzero if -mshared-library-id was given. */
90 static int bfin_lib_id_given;
92 /* Nonzero if -fschedule-insns2 was given. We override it and
93 call the scheduler ourselves during reorg. */
94 static int bfin_flag_schedule_insns2;
96 /* Determines whether we run variable tracking in machine dependent
97 reorganization. */
98 static int bfin_flag_var_tracking;
100 /* -mcpu support */
101 bfin_cpu_t bfin_cpu_type = BFIN_CPU_UNKNOWN;
103 /* -msi-revision support. There are three special values:
104 -1 -msi-revision=none.
105 0xffff -msi-revision=any. */
106 int bfin_si_revision;
108 /* The workarounds enabled */
109 unsigned int bfin_workarounds = 0;
111 struct bfin_cpu
113 const char *name;
114 bfin_cpu_t type;
115 int si_revision;
116 unsigned int workarounds;
119 struct bfin_cpu bfin_cpus[] =
121 {"bf512", BFIN_CPU_BF512, 0x0000,
122 WA_SPECULATIVE_LOADS},
124 {"bf514", BFIN_CPU_BF514, 0x0000,
125 WA_SPECULATIVE_LOADS},
127 {"bf516", BFIN_CPU_BF516, 0x0000,
128 WA_SPECULATIVE_LOADS},
130 {"bf518", BFIN_CPU_BF518, 0x0000,
131 WA_SPECULATIVE_LOADS},
133 {"bf522", BFIN_CPU_BF522, 0x0002,
134 WA_SPECULATIVE_LOADS},
135 {"bf522", BFIN_CPU_BF522, 0x0001,
136 WA_SPECULATIVE_LOADS | WA_RETS},
137 {"bf522", BFIN_CPU_BF522, 0x0000,
138 WA_SPECULATIVE_LOADS | WA_RETS},
140 {"bf523", BFIN_CPU_BF523, 0x0002,
141 WA_SPECULATIVE_LOADS},
142 {"bf523", BFIN_CPU_BF523, 0x0001,
143 WA_SPECULATIVE_LOADS | WA_RETS},
144 {"bf523", BFIN_CPU_BF523, 0x0000,
145 WA_SPECULATIVE_LOADS | WA_RETS},
147 {"bf524", BFIN_CPU_BF524, 0x0002,
148 WA_SPECULATIVE_LOADS},
149 {"bf524", BFIN_CPU_BF524, 0x0001,
150 WA_SPECULATIVE_LOADS | WA_RETS},
151 {"bf524", BFIN_CPU_BF524, 0x0000,
152 WA_SPECULATIVE_LOADS | WA_RETS},
154 {"bf525", BFIN_CPU_BF525, 0x0002,
155 WA_SPECULATIVE_LOADS},
156 {"bf525", BFIN_CPU_BF525, 0x0001,
157 WA_SPECULATIVE_LOADS | WA_RETS},
158 {"bf525", BFIN_CPU_BF525, 0x0000,
159 WA_SPECULATIVE_LOADS | WA_RETS},
161 {"bf526", BFIN_CPU_BF526, 0x0002,
162 WA_SPECULATIVE_LOADS},
163 {"bf526", BFIN_CPU_BF526, 0x0001,
164 WA_SPECULATIVE_LOADS | WA_RETS},
165 {"bf526", BFIN_CPU_BF526, 0x0000,
166 WA_SPECULATIVE_LOADS | WA_RETS},
168 {"bf527", BFIN_CPU_BF527, 0x0002,
169 WA_SPECULATIVE_LOADS},
170 {"bf527", BFIN_CPU_BF527, 0x0001,
171 WA_SPECULATIVE_LOADS | WA_RETS},
172 {"bf527", BFIN_CPU_BF527, 0x0000,
173 WA_SPECULATIVE_LOADS | WA_RETS},
175 {"bf531", BFIN_CPU_BF531, 0x0006,
176 WA_SPECULATIVE_LOADS},
177 {"bf531", BFIN_CPU_BF531, 0x0005,
178 WA_SPECULATIVE_LOADS | WA_RETS | WA_05000283 | WA_05000315},
179 {"bf531", BFIN_CPU_BF531, 0x0004,
180 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
181 | WA_05000283 | WA_05000257 | WA_05000315},
182 {"bf531", BFIN_CPU_BF531, 0x0003,
183 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
184 | WA_05000283 | WA_05000257 | WA_05000315},
186 {"bf532", BFIN_CPU_BF532, 0x0006,
187 WA_SPECULATIVE_LOADS},
188 {"bf532", BFIN_CPU_BF532, 0x0005,
189 WA_SPECULATIVE_LOADS | WA_RETS | WA_05000283 | WA_05000315},
190 {"bf532", BFIN_CPU_BF532, 0x0004,
191 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
192 | WA_05000283 | WA_05000257 | WA_05000315},
193 {"bf532", BFIN_CPU_BF532, 0x0003,
194 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
195 | WA_05000283 | WA_05000257 | WA_05000315},
197 {"bf533", BFIN_CPU_BF533, 0x0006,
198 WA_SPECULATIVE_LOADS},
199 {"bf533", BFIN_CPU_BF533, 0x0005,
200 WA_SPECULATIVE_LOADS | WA_RETS | WA_05000283 | WA_05000315},
201 {"bf533", BFIN_CPU_BF533, 0x0004,
202 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
203 | WA_05000283 | WA_05000257 | WA_05000315},
204 {"bf533", BFIN_CPU_BF533, 0x0003,
205 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
206 | WA_05000283 | WA_05000257 | WA_05000315},
208 {"bf534", BFIN_CPU_BF534, 0x0003,
209 WA_SPECULATIVE_LOADS | WA_RETS},
210 {"bf534", BFIN_CPU_BF534, 0x0002,
211 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
212 | WA_05000283 | WA_05000257 | WA_05000315},
213 {"bf534", BFIN_CPU_BF534, 0x0001,
214 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
215 | WA_05000283 | WA_05000257 | WA_05000315},
217 {"bf536", BFIN_CPU_BF536, 0x0003,
218 WA_SPECULATIVE_LOADS | WA_RETS},
219 {"bf536", BFIN_CPU_BF536, 0x0002,
220 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
221 | WA_05000283 | WA_05000257 | WA_05000315},
222 {"bf536", BFIN_CPU_BF536, 0x0001,
223 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
224 | WA_05000283 | WA_05000257 | WA_05000315},
226 {"bf537", BFIN_CPU_BF537, 0x0003,
227 WA_SPECULATIVE_LOADS | WA_RETS},
228 {"bf537", BFIN_CPU_BF537, 0x0002,
229 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
230 | WA_05000283 | WA_05000257 | WA_05000315},
231 {"bf537", BFIN_CPU_BF537, 0x0001,
232 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
233 | WA_05000283 | WA_05000257 | WA_05000315},
235 {"bf538", BFIN_CPU_BF538, 0x0005,
236 WA_SPECULATIVE_LOADS},
237 {"bf538", BFIN_CPU_BF538, 0x0004,
238 WA_SPECULATIVE_LOADS | WA_RETS},
239 {"bf538", BFIN_CPU_BF538, 0x0003,
240 WA_SPECULATIVE_LOADS | WA_RETS
241 | WA_05000283 | WA_05000315},
242 {"bf538", BFIN_CPU_BF538, 0x0002,
243 WA_SPECULATIVE_LOADS | WA_RETS | WA_05000283 | WA_05000257 | WA_05000315},
245 {"bf539", BFIN_CPU_BF539, 0x0005,
246 WA_SPECULATIVE_LOADS},
247 {"bf539", BFIN_CPU_BF539, 0x0004,
248 WA_SPECULATIVE_LOADS | WA_RETS},
249 {"bf539", BFIN_CPU_BF539, 0x0003,
250 WA_SPECULATIVE_LOADS | WA_RETS
251 | WA_05000283 | WA_05000315},
252 {"bf539", BFIN_CPU_BF539, 0x0002,
253 WA_SPECULATIVE_LOADS | WA_RETS
254 | WA_05000283 | WA_05000257 | WA_05000315},
256 {"bf542", BFIN_CPU_BF542, 0x0002,
257 WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS},
258 {"bf542", BFIN_CPU_BF542, 0x0001,
259 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS},
260 {"bf542", BFIN_CPU_BF542, 0x0000,
261 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS},
263 {"bf544", BFIN_CPU_BF544, 0x0002,
264 WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS},
265 {"bf544", BFIN_CPU_BF544, 0x0001,
266 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS},
267 {"bf544", BFIN_CPU_BF544, 0x0000,
268 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS},
270 {"bf547", BFIN_CPU_BF547, 0x0002,
271 WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS},
272 {"bf547", BFIN_CPU_BF547, 0x0001,
273 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS},
274 {"bf547", BFIN_CPU_BF547, 0x0000,
275 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS},
277 {"bf548", BFIN_CPU_BF548, 0x0002,
278 WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS},
279 {"bf548", BFIN_CPU_BF548, 0x0001,
280 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS},
281 {"bf548", BFIN_CPU_BF548, 0x0000,
282 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS},
284 {"bf549", BFIN_CPU_BF549, 0x0002,
285 WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS},
286 {"bf549", BFIN_CPU_BF549, 0x0001,
287 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS},
288 {"bf549", BFIN_CPU_BF549, 0x0000,
289 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS},
291 {"bf561", BFIN_CPU_BF561, 0x0005, WA_RETS
292 | WA_05000283 | WA_05000315},
293 {"bf561", BFIN_CPU_BF561, 0x0003,
294 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
295 | WA_05000283 | WA_05000257 | WA_05000315},
296 {"bf561", BFIN_CPU_BF561, 0x0002,
297 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
298 | WA_05000283 | WA_05000257 | WA_05000315},
300 {NULL, 0, 0, 0}
303 int splitting_for_sched;
305 static void
306 bfin_globalize_label (FILE *stream, const char *name)
308 fputs (".global ", stream);
309 assemble_name (stream, name);
310 fputc (';',stream);
311 fputc ('\n',stream);
314 static void
315 output_file_start (void)
317 FILE *file = asm_out_file;
318 int i;
320 /* Variable tracking should be run after all optimizations which change order
321 of insns. It also needs a valid CFG. This can't be done in
322 override_options, because flag_var_tracking is finalized after
323 that. */
324 bfin_flag_var_tracking = flag_var_tracking;
325 flag_var_tracking = 0;
327 fprintf (file, ".file \"%s\";\n", input_filename);
329 for (i = 0; arg_regs[i] >= 0; i++)
331 max_arg_registers = i; /* how many arg reg used */
334 /* Called early in the compilation to conditionally modify
335 fixed_regs/call_used_regs. */
337 void
338 conditional_register_usage (void)
340 /* initialize condition code flag register rtx */
341 bfin_cc_rtx = gen_rtx_REG (BImode, REG_CC);
342 bfin_rets_rtx = gen_rtx_REG (Pmode, REG_RETS);
345 /* Examine machine-dependent attributes of function type FUNTYPE and return its
346 type. See the definition of E_FUNKIND. */
348 static e_funkind
349 funkind (const_tree funtype)
351 tree attrs = TYPE_ATTRIBUTES (funtype);
352 if (lookup_attribute ("interrupt_handler", attrs))
353 return INTERRUPT_HANDLER;
354 else if (lookup_attribute ("exception_handler", attrs))
355 return EXCPT_HANDLER;
356 else if (lookup_attribute ("nmi_handler", attrs))
357 return NMI_HANDLER;
358 else
359 return SUBROUTINE;
362 /* Legitimize PIC addresses. If the address is already position-independent,
363 we return ORIG. Newly generated position-independent addresses go into a
364 reg. This is REG if nonzero, otherwise we allocate register(s) as
365 necessary. PICREG is the register holding the pointer to the PIC offset
366 table. */
368 static rtx
369 legitimize_pic_address (rtx orig, rtx reg, rtx picreg)
371 rtx addr = orig;
372 rtx new_rtx = orig;
374 if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == LABEL_REF)
376 int unspec;
377 rtx tmp;
379 if (TARGET_ID_SHARED_LIBRARY)
380 unspec = UNSPEC_MOVE_PIC;
381 else if (GET_CODE (addr) == SYMBOL_REF
382 && SYMBOL_REF_FUNCTION_P (addr))
383 unspec = UNSPEC_FUNCDESC_GOT17M4;
384 else
385 unspec = UNSPEC_MOVE_FDPIC;
387 if (reg == 0)
389 gcc_assert (can_create_pseudo_p ());
390 reg = gen_reg_rtx (Pmode);
393 tmp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), unspec);
394 new_rtx = gen_const_mem (Pmode, gen_rtx_PLUS (Pmode, picreg, tmp));
396 emit_move_insn (reg, new_rtx);
397 if (picreg == pic_offset_table_rtx)
398 crtl->uses_pic_offset_table = 1;
399 return reg;
402 else if (GET_CODE (addr) == CONST || GET_CODE (addr) == PLUS)
404 rtx base;
406 if (GET_CODE (addr) == CONST)
408 addr = XEXP (addr, 0);
409 gcc_assert (GET_CODE (addr) == PLUS);
412 if (XEXP (addr, 0) == picreg)
413 return orig;
415 if (reg == 0)
417 gcc_assert (can_create_pseudo_p ());
418 reg = gen_reg_rtx (Pmode);
421 base = legitimize_pic_address (XEXP (addr, 0), reg, picreg);
422 addr = legitimize_pic_address (XEXP (addr, 1),
423 base == reg ? NULL_RTX : reg,
424 picreg);
426 if (GET_CODE (addr) == CONST_INT)
428 gcc_assert (! reload_in_progress && ! reload_completed);
429 addr = force_reg (Pmode, addr);
432 if (GET_CODE (addr) == PLUS && CONSTANT_P (XEXP (addr, 1)))
434 base = gen_rtx_PLUS (Pmode, base, XEXP (addr, 0));
435 addr = XEXP (addr, 1);
438 return gen_rtx_PLUS (Pmode, base, addr);
441 return new_rtx;
444 /* Stack frame layout. */
446 /* For a given REGNO, determine whether it must be saved in the function
447 prologue. IS_INTHANDLER specifies whether we're generating a normal
448 prologue or an interrupt/exception one. */
449 static bool
450 must_save_p (bool is_inthandler, unsigned regno)
452 if (D_REGNO_P (regno))
454 bool is_eh_return_reg = false;
455 if (crtl->calls_eh_return)
457 unsigned j;
458 for (j = 0; ; j++)
460 unsigned test = EH_RETURN_DATA_REGNO (j);
461 if (test == INVALID_REGNUM)
462 break;
463 if (test == regno)
464 is_eh_return_reg = true;
468 return (is_eh_return_reg
469 || (df_regs_ever_live_p (regno)
470 && !fixed_regs[regno]
471 && (is_inthandler || !call_used_regs[regno])));
473 else if (P_REGNO_P (regno))
475 return ((df_regs_ever_live_p (regno)
476 && !fixed_regs[regno]
477 && (is_inthandler || !call_used_regs[regno]))
478 || (is_inthandler
479 && (ENABLE_WA_05000283 || ENABLE_WA_05000315)
480 && regno == REG_P5)
481 || (!TARGET_FDPIC
482 && regno == PIC_OFFSET_TABLE_REGNUM
483 && (crtl->uses_pic_offset_table
484 || (TARGET_ID_SHARED_LIBRARY && !current_function_is_leaf))));
486 else
487 return ((is_inthandler || !call_used_regs[regno])
488 && (df_regs_ever_live_p (regno)
489 || (!leaf_function_p () && call_used_regs[regno])));
493 /* Compute the number of DREGS to save with a push_multiple operation.
494 This could include registers that aren't modified in the function,
495 since push_multiple only takes a range of registers.
496 If IS_INTHANDLER, then everything that is live must be saved, even
497 if normally call-clobbered.
498 If CONSECUTIVE, return the number of registers we can save in one
499 instruction with a push/pop multiple instruction. */
501 static int
502 n_dregs_to_save (bool is_inthandler, bool consecutive)
504 int count = 0;
505 unsigned i;
507 for (i = REG_R7 + 1; i-- != REG_R0;)
509 if (must_save_p (is_inthandler, i))
510 count++;
511 else if (consecutive)
512 return count;
514 return count;
517 /* Like n_dregs_to_save, but compute number of PREGS to save. */
519 static int
520 n_pregs_to_save (bool is_inthandler, bool consecutive)
522 int count = 0;
523 unsigned i;
525 for (i = REG_P5 + 1; i-- != REG_P0;)
526 if (must_save_p (is_inthandler, i))
527 count++;
528 else if (consecutive)
529 return count;
530 return count;
533 /* Determine if we are going to save the frame pointer in the prologue. */
535 static bool
536 must_save_fp_p (void)
538 return frame_pointer_needed || df_regs_ever_live_p (REG_FP);
541 static bool
542 stack_frame_needed_p (void)
544 /* EH return puts a new return address into the frame using an
545 address relative to the frame pointer. */
546 if (crtl->calls_eh_return)
547 return true;
548 return frame_pointer_needed;
551 /* Emit code to save registers in the prologue. SAVEALL is nonzero if we
552 must save all registers; this is used for interrupt handlers.
553 SPREG contains (reg:SI REG_SP). IS_INTHANDLER is true if we're doing
554 this for an interrupt (or exception) handler. */
556 static void
557 expand_prologue_reg_save (rtx spreg, int saveall, bool is_inthandler)
559 rtx predec1 = gen_rtx_PRE_DEC (SImode, spreg);
560 rtx predec = gen_rtx_MEM (SImode, predec1);
561 int ndregs = saveall ? 8 : n_dregs_to_save (is_inthandler, false);
562 int npregs = saveall ? 6 : n_pregs_to_save (is_inthandler, false);
563 int ndregs_consec = saveall ? 8 : n_dregs_to_save (is_inthandler, true);
564 int npregs_consec = saveall ? 6 : n_pregs_to_save (is_inthandler, true);
565 int dregno, pregno;
566 int total_consec = ndregs_consec + npregs_consec;
567 int i, d_to_save;
569 if (saveall || is_inthandler)
571 rtx insn = emit_move_insn (predec, gen_rtx_REG (SImode, REG_ASTAT));
573 RTX_FRAME_RELATED_P (insn) = 1;
574 for (dregno = REG_LT0; dregno <= REG_LB1; dregno++)
575 if (! current_function_is_leaf
576 || cfun->machine->has_hardware_loops
577 || cfun->machine->has_loopreg_clobber
578 || (ENABLE_WA_05000257
579 && (dregno == REG_LC0 || dregno == REG_LC1)))
581 insn = emit_move_insn (predec, gen_rtx_REG (SImode, dregno));
582 RTX_FRAME_RELATED_P (insn) = 1;
586 if (total_consec != 0)
588 rtx insn;
589 rtx val = GEN_INT (-total_consec * 4);
590 rtx pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total_consec + 2));
592 XVECEXP (pat, 0, 0) = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, val),
593 UNSPEC_PUSH_MULTIPLE);
594 XVECEXP (pat, 0, total_consec + 1) = gen_rtx_SET (VOIDmode, spreg,
595 gen_rtx_PLUS (Pmode,
596 spreg,
597 val));
598 RTX_FRAME_RELATED_P (XVECEXP (pat, 0, total_consec + 1)) = 1;
599 d_to_save = ndregs_consec;
600 dregno = REG_R7 + 1 - ndregs_consec;
601 pregno = REG_P5 + 1 - npregs_consec;
602 for (i = 0; i < total_consec; i++)
604 rtx memref = gen_rtx_MEM (word_mode,
605 gen_rtx_PLUS (Pmode, spreg,
606 GEN_INT (- i * 4 - 4)));
607 rtx subpat;
608 if (d_to_save > 0)
610 subpat = gen_rtx_SET (VOIDmode, memref, gen_rtx_REG (word_mode,
611 dregno++));
612 d_to_save--;
614 else
616 subpat = gen_rtx_SET (VOIDmode, memref, gen_rtx_REG (word_mode,
617 pregno++));
619 XVECEXP (pat, 0, i + 1) = subpat;
620 RTX_FRAME_RELATED_P (subpat) = 1;
622 insn = emit_insn (pat);
623 RTX_FRAME_RELATED_P (insn) = 1;
626 for (dregno = REG_R0; ndregs != ndregs_consec; dregno++)
628 if (must_save_p (is_inthandler, dregno))
630 rtx insn = emit_move_insn (predec, gen_rtx_REG (word_mode, dregno));
631 RTX_FRAME_RELATED_P (insn) = 1;
632 ndregs--;
635 for (pregno = REG_P0; npregs != npregs_consec; pregno++)
637 if (must_save_p (is_inthandler, pregno))
639 rtx insn = emit_move_insn (predec, gen_rtx_REG (word_mode, pregno));
640 RTX_FRAME_RELATED_P (insn) = 1;
641 npregs--;
644 for (i = REG_P7 + 1; i < REG_CC; i++)
645 if (saveall
646 || (is_inthandler
647 && (df_regs_ever_live_p (i)
648 || (!leaf_function_p () && call_used_regs[i]))))
650 rtx insn;
651 if (i == REG_A0 || i == REG_A1)
652 insn = emit_move_insn (gen_rtx_MEM (PDImode, predec1),
653 gen_rtx_REG (PDImode, i));
654 else
655 insn = emit_move_insn (predec, gen_rtx_REG (SImode, i));
656 RTX_FRAME_RELATED_P (insn) = 1;
660 /* Emit code to restore registers in the epilogue. SAVEALL is nonzero if we
661 must save all registers; this is used for interrupt handlers.
662 SPREG contains (reg:SI REG_SP). IS_INTHANDLER is true if we're doing
663 this for an interrupt (or exception) handler. */
665 static void
666 expand_epilogue_reg_restore (rtx spreg, bool saveall, bool is_inthandler)
668 rtx postinc1 = gen_rtx_POST_INC (SImode, spreg);
669 rtx postinc = gen_rtx_MEM (SImode, postinc1);
671 int ndregs = saveall ? 8 : n_dregs_to_save (is_inthandler, false);
672 int npregs = saveall ? 6 : n_pregs_to_save (is_inthandler, false);
673 int ndregs_consec = saveall ? 8 : n_dregs_to_save (is_inthandler, true);
674 int npregs_consec = saveall ? 6 : n_pregs_to_save (is_inthandler, true);
675 int total_consec = ndregs_consec + npregs_consec;
676 int i, regno;
677 rtx insn;
679 /* A slightly crude technique to stop flow from trying to delete "dead"
680 insns. */
681 MEM_VOLATILE_P (postinc) = 1;
683 for (i = REG_CC - 1; i > REG_P7; i--)
684 if (saveall
685 || (is_inthandler
686 && (df_regs_ever_live_p (i)
687 || (!leaf_function_p () && call_used_regs[i]))))
689 if (i == REG_A0 || i == REG_A1)
691 rtx mem = gen_rtx_MEM (PDImode, postinc1);
692 MEM_VOLATILE_P (mem) = 1;
693 emit_move_insn (gen_rtx_REG (PDImode, i), mem);
695 else
696 emit_move_insn (gen_rtx_REG (SImode, i), postinc);
699 regno = REG_P5 - npregs_consec;
700 for (; npregs != npregs_consec; regno--)
702 if (must_save_p (is_inthandler, regno))
704 emit_move_insn (gen_rtx_REG (word_mode, regno), postinc);
705 npregs--;
708 regno = REG_R7 - ndregs_consec;
709 for (; ndregs != ndregs_consec; regno--)
711 if (must_save_p (is_inthandler, regno))
713 emit_move_insn (gen_rtx_REG (word_mode, regno), postinc);
714 ndregs--;
718 if (total_consec != 0)
720 rtx pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total_consec + 1));
721 XVECEXP (pat, 0, 0)
722 = gen_rtx_SET (VOIDmode, spreg,
723 gen_rtx_PLUS (Pmode, spreg,
724 GEN_INT (total_consec * 4)));
726 if (npregs_consec > 0)
727 regno = REG_P5 + 1;
728 else
729 regno = REG_R7 + 1;
731 for (i = 0; i < total_consec; i++)
733 rtx addr = (i > 0
734 ? gen_rtx_PLUS (Pmode, spreg, GEN_INT (i * 4))
735 : spreg);
736 rtx memref = gen_rtx_MEM (word_mode, addr);
738 regno--;
739 XVECEXP (pat, 0, i + 1)
740 = gen_rtx_SET (VOIDmode, gen_rtx_REG (word_mode, regno), memref);
742 if (npregs_consec > 0)
744 if (--npregs_consec == 0)
745 regno = REG_R7 + 1;
749 insn = emit_insn (pat);
750 RTX_FRAME_RELATED_P (insn) = 1;
752 if (saveall || is_inthandler)
754 for (regno = REG_LB1; regno >= REG_LT0; regno--)
755 if (! current_function_is_leaf
756 || cfun->machine->has_hardware_loops
757 || cfun->machine->has_loopreg_clobber
758 || (ENABLE_WA_05000257 && (regno == REG_LC0 || regno == REG_LC1)))
759 emit_move_insn (gen_rtx_REG (SImode, regno), postinc);
761 emit_move_insn (gen_rtx_REG (SImode, REG_ASTAT), postinc);
765 /* Perform any needed actions needed for a function that is receiving a
766 variable number of arguments.
768 CUM is as above.
770 MODE and TYPE are the mode and type of the current parameter.
772 PRETEND_SIZE is a variable that should be set to the amount of stack
773 that must be pushed by the prolog to pretend that our caller pushed
776 Normally, this macro will push all remaining incoming registers on the
777 stack and set PRETEND_SIZE to the length of the registers pushed.
779 Blackfin specific :
780 - VDSP C compiler manual (our ABI) says that a variable args function
781 should save the R0, R1 and R2 registers in the stack.
782 - The caller will always leave space on the stack for the
783 arguments that are passed in registers, so we dont have
784 to leave any extra space.
785 - now, the vastart pointer can access all arguments from the stack. */
787 static void
788 setup_incoming_varargs (CUMULATIVE_ARGS *cum,
789 enum machine_mode mode ATTRIBUTE_UNUSED,
790 tree type ATTRIBUTE_UNUSED, int *pretend_size,
791 int no_rtl)
793 rtx mem;
794 int i;
796 if (no_rtl)
797 return;
799 /* The move for named arguments will be generated automatically by the
800 compiler. We need to generate the move rtx for the unnamed arguments
801 if they are in the first 3 words. We assume at least 1 named argument
802 exists, so we never generate [ARGP] = R0 here. */
804 for (i = cum->words + 1; i < max_arg_registers; i++)
806 mem = gen_rtx_MEM (Pmode,
807 plus_constant (arg_pointer_rtx, (i * UNITS_PER_WORD)));
808 emit_move_insn (mem, gen_rtx_REG (Pmode, i));
811 *pretend_size = 0;
814 /* Value should be nonzero if functions must have frame pointers.
815 Zero means the frame pointer need not be set up (and parms may
816 be accessed via the stack pointer) in functions that seem suitable. */
819 bfin_frame_pointer_required (void)
821 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
823 if (fkind != SUBROUTINE)
824 return 1;
826 /* We turn on -fomit-frame-pointer if -momit-leaf-frame-pointer is used,
827 so we have to override it for non-leaf functions. */
828 if (TARGET_OMIT_LEAF_FRAME_POINTER && ! current_function_is_leaf)
829 return 1;
831 return 0;
834 /* Return the number of registers pushed during the prologue. */
836 static int
837 n_regs_saved_by_prologue (void)
839 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
840 bool is_inthandler = fkind != SUBROUTINE;
841 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
842 bool all = (lookup_attribute ("saveall", attrs) != NULL_TREE
843 || (is_inthandler && !current_function_is_leaf));
844 int ndregs = all ? 8 : n_dregs_to_save (is_inthandler, false);
845 int npregs = all ? 6 : n_pregs_to_save (is_inthandler, false);
846 int n = ndregs + npregs;
847 int i;
849 if (all || stack_frame_needed_p ())
850 /* We use a LINK instruction in this case. */
851 n += 2;
852 else
854 if (must_save_fp_p ())
855 n++;
856 if (! current_function_is_leaf)
857 n++;
860 if (fkind != SUBROUTINE || all)
862 /* Increment once for ASTAT. */
863 n++;
864 if (! current_function_is_leaf
865 || cfun->machine->has_hardware_loops
866 || cfun->machine->has_loopreg_clobber)
868 n += 6;
872 if (fkind != SUBROUTINE)
874 /* RETE/X/N. */
875 if (lookup_attribute ("nesting", attrs))
876 n++;
879 for (i = REG_P7 + 1; i < REG_CC; i++)
880 if (all
881 || (fkind != SUBROUTINE
882 && (df_regs_ever_live_p (i)
883 || (!leaf_function_p () && call_used_regs[i]))))
884 n += i == REG_A0 || i == REG_A1 ? 2 : 1;
886 return n;
889 /* Return the offset between two registers, one to be eliminated, and the other
890 its replacement, at the start of a routine. */
892 HOST_WIDE_INT
893 bfin_initial_elimination_offset (int from, int to)
895 HOST_WIDE_INT offset = 0;
897 if (from == ARG_POINTER_REGNUM)
898 offset = n_regs_saved_by_prologue () * 4;
900 if (to == STACK_POINTER_REGNUM)
902 if (crtl->outgoing_args_size >= FIXED_STACK_AREA)
903 offset += crtl->outgoing_args_size;
904 else if (crtl->outgoing_args_size)
905 offset += FIXED_STACK_AREA;
907 offset += get_frame_size ();
910 return offset;
913 /* Emit code to load a constant CONSTANT into register REG; setting
914 RTX_FRAME_RELATED_P on all insns we generate if RELATED is true.
915 Make sure that the insns we generate need not be split. */
917 static void
918 frame_related_constant_load (rtx reg, HOST_WIDE_INT constant, bool related)
920 rtx insn;
921 rtx cst = GEN_INT (constant);
923 if (constant >= -32768 && constant < 65536)
924 insn = emit_move_insn (reg, cst);
925 else
927 /* We don't call split_load_immediate here, since dwarf2out.c can get
928 confused about some of the more clever sequences it can generate. */
929 insn = emit_insn (gen_movsi_high (reg, cst));
930 if (related)
931 RTX_FRAME_RELATED_P (insn) = 1;
932 insn = emit_insn (gen_movsi_low (reg, reg, cst));
934 if (related)
935 RTX_FRAME_RELATED_P (insn) = 1;
938 /* Generate efficient code to add a value to a P register.
939 Set RTX_FRAME_RELATED_P on the generated insns if FRAME is nonzero.
940 EPILOGUE_P is zero if this function is called for prologue,
941 otherwise it's nonzero. And it's less than zero if this is for
942 sibcall epilogue. */
944 static void
945 add_to_reg (rtx reg, HOST_WIDE_INT value, int frame, int epilogue_p)
947 if (value == 0)
948 return;
950 /* Choose whether to use a sequence using a temporary register, or
951 a sequence with multiple adds. We can add a signed 7-bit value
952 in one instruction. */
953 if (value > 120 || value < -120)
955 rtx tmpreg;
956 rtx tmpreg2;
957 rtx insn;
959 tmpreg2 = NULL_RTX;
961 /* For prologue or normal epilogue, P1 can be safely used
962 as the temporary register. For sibcall epilogue, we try to find
963 a call used P register, which will be restored in epilogue.
964 If we cannot find such a P register, we have to use one I register
965 to help us. */
967 if (epilogue_p >= 0)
968 tmpreg = gen_rtx_REG (SImode, REG_P1);
969 else
971 int i;
972 for (i = REG_P0; i <= REG_P5; i++)
973 if ((df_regs_ever_live_p (i) && ! call_used_regs[i])
974 || (!TARGET_FDPIC
975 && i == PIC_OFFSET_TABLE_REGNUM
976 && (crtl->uses_pic_offset_table
977 || (TARGET_ID_SHARED_LIBRARY
978 && ! current_function_is_leaf))))
979 break;
980 if (i <= REG_P5)
981 tmpreg = gen_rtx_REG (SImode, i);
982 else
984 tmpreg = gen_rtx_REG (SImode, REG_P1);
985 tmpreg2 = gen_rtx_REG (SImode, REG_I0);
986 emit_move_insn (tmpreg2, tmpreg);
990 if (frame)
991 frame_related_constant_load (tmpreg, value, TRUE);
992 else
993 insn = emit_move_insn (tmpreg, GEN_INT (value));
995 insn = emit_insn (gen_addsi3 (reg, reg, tmpreg));
996 if (frame)
997 RTX_FRAME_RELATED_P (insn) = 1;
999 if (tmpreg2 != NULL_RTX)
1000 emit_move_insn (tmpreg, tmpreg2);
1002 else
1005 int size = value;
1006 rtx insn;
1008 if (size > 60)
1009 size = 60;
1010 else if (size < -60)
1011 /* We could use -62, but that would leave the stack unaligned, so
1012 it's no good. */
1013 size = -60;
1015 insn = emit_insn (gen_addsi3 (reg, reg, GEN_INT (size)));
1016 if (frame)
1017 RTX_FRAME_RELATED_P (insn) = 1;
1018 value -= size;
1020 while (value != 0);
1023 /* Generate a LINK insn for a frame sized FRAME_SIZE. If this constant
1024 is too large, generate a sequence of insns that has the same effect.
1025 SPREG contains (reg:SI REG_SP). */
1027 static void
1028 emit_link_insn (rtx spreg, HOST_WIDE_INT frame_size)
1030 HOST_WIDE_INT link_size = frame_size;
1031 rtx insn;
1032 int i;
1034 if (link_size > 262140)
1035 link_size = 262140;
1037 /* Use a LINK insn with as big a constant as possible, then subtract
1038 any remaining size from the SP. */
1039 insn = emit_insn (gen_link (GEN_INT (-8 - link_size)));
1040 RTX_FRAME_RELATED_P (insn) = 1;
1042 for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
1044 rtx set = XVECEXP (PATTERN (insn), 0, i);
1045 gcc_assert (GET_CODE (set) == SET);
1046 RTX_FRAME_RELATED_P (set) = 1;
1049 frame_size -= link_size;
1051 if (frame_size > 0)
1053 /* Must use a call-clobbered PREG that isn't the static chain. */
1054 rtx tmpreg = gen_rtx_REG (Pmode, REG_P1);
1056 frame_related_constant_load (tmpreg, -frame_size, TRUE);
1057 insn = emit_insn (gen_addsi3 (spreg, spreg, tmpreg));
1058 RTX_FRAME_RELATED_P (insn) = 1;
1062 /* Return the number of bytes we must reserve for outgoing arguments
1063 in the current function's stack frame. */
1065 static HOST_WIDE_INT
1066 arg_area_size (void)
1068 if (crtl->outgoing_args_size)
1070 if (crtl->outgoing_args_size >= FIXED_STACK_AREA)
1071 return crtl->outgoing_args_size;
1072 else
1073 return FIXED_STACK_AREA;
1075 return 0;
1078 /* Save RETS and FP, and allocate a stack frame. ALL is true if the
1079 function must save all its registers (true only for certain interrupt
1080 handlers). */
1082 static void
1083 do_link (rtx spreg, HOST_WIDE_INT frame_size, bool all)
1085 frame_size += arg_area_size ();
1087 if (all || stack_frame_needed_p ()
1088 || (must_save_fp_p () && ! current_function_is_leaf))
1089 emit_link_insn (spreg, frame_size);
1090 else
1092 if (! current_function_is_leaf)
1094 rtx pat = gen_movsi (gen_rtx_MEM (Pmode,
1095 gen_rtx_PRE_DEC (Pmode, spreg)),
1096 bfin_rets_rtx);
1097 rtx insn = emit_insn (pat);
1098 RTX_FRAME_RELATED_P (insn) = 1;
1100 if (must_save_fp_p ())
1102 rtx pat = gen_movsi (gen_rtx_MEM (Pmode,
1103 gen_rtx_PRE_DEC (Pmode, spreg)),
1104 gen_rtx_REG (Pmode, REG_FP));
1105 rtx insn = emit_insn (pat);
1106 RTX_FRAME_RELATED_P (insn) = 1;
1108 add_to_reg (spreg, -frame_size, 1, 0);
1112 /* Like do_link, but used for epilogues to deallocate the stack frame.
1113 EPILOGUE_P is zero if this function is called for prologue,
1114 otherwise it's nonzero. And it's less than zero if this is for
1115 sibcall epilogue. */
1117 static void
1118 do_unlink (rtx spreg, HOST_WIDE_INT frame_size, bool all, int epilogue_p)
1120 frame_size += arg_area_size ();
1122 if (all || stack_frame_needed_p ())
1123 emit_insn (gen_unlink ());
1124 else
1126 rtx postinc = gen_rtx_MEM (Pmode, gen_rtx_POST_INC (Pmode, spreg));
1128 add_to_reg (spreg, frame_size, 0, epilogue_p);
1129 if (must_save_fp_p ())
1131 rtx fpreg = gen_rtx_REG (Pmode, REG_FP);
1132 emit_move_insn (fpreg, postinc);
1133 emit_use (fpreg);
1135 if (! current_function_is_leaf)
1137 emit_move_insn (bfin_rets_rtx, postinc);
1138 emit_use (bfin_rets_rtx);
1143 /* Generate a prologue suitable for a function of kind FKIND. This is
1144 called for interrupt and exception handler prologues.
1145 SPREG contains (reg:SI REG_SP). */
1147 static void
1148 expand_interrupt_handler_prologue (rtx spreg, e_funkind fkind, bool all)
1150 HOST_WIDE_INT frame_size = get_frame_size ();
1151 rtx predec1 = gen_rtx_PRE_DEC (SImode, spreg);
1152 rtx predec = gen_rtx_MEM (SImode, predec1);
1153 rtx insn;
1154 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1155 tree kspisusp = lookup_attribute ("kspisusp", attrs);
1157 if (kspisusp)
1159 insn = emit_move_insn (spreg, gen_rtx_REG (Pmode, REG_USP));
1160 RTX_FRAME_RELATED_P (insn) = 1;
1163 /* We need space on the stack in case we need to save the argument
1164 registers. */
1165 if (fkind == EXCPT_HANDLER)
1167 insn = emit_insn (gen_addsi3 (spreg, spreg, GEN_INT (-12)));
1168 RTX_FRAME_RELATED_P (insn) = 1;
1171 /* If we're calling other functions, they won't save their call-clobbered
1172 registers, so we must save everything here. */
1173 if (!current_function_is_leaf)
1174 all = true;
1175 expand_prologue_reg_save (spreg, all, true);
1177 if (ENABLE_WA_05000283 || ENABLE_WA_05000315)
1179 rtx chipid = GEN_INT (trunc_int_for_mode (0xFFC00014, SImode));
1180 rtx p5reg = gen_rtx_REG (Pmode, REG_P5);
1181 emit_insn (gen_movbi (bfin_cc_rtx, const1_rtx));
1182 emit_insn (gen_movsi_high (p5reg, chipid));
1183 emit_insn (gen_movsi_low (p5reg, p5reg, chipid));
1184 emit_insn (gen_dummy_load (p5reg, bfin_cc_rtx));
1187 if (lookup_attribute ("nesting", attrs))
1189 rtx srcreg = gen_rtx_REG (Pmode, (fkind == EXCPT_HANDLER ? REG_RETX
1190 : fkind == NMI_HANDLER ? REG_RETN
1191 : REG_RETI));
1192 insn = emit_move_insn (predec, srcreg);
1193 RTX_FRAME_RELATED_P (insn) = 1;
1196 do_link (spreg, frame_size, all);
1198 if (fkind == EXCPT_HANDLER)
1200 rtx r0reg = gen_rtx_REG (SImode, REG_R0);
1201 rtx r1reg = gen_rtx_REG (SImode, REG_R1);
1202 rtx r2reg = gen_rtx_REG (SImode, REG_R2);
1203 rtx insn;
1205 insn = emit_move_insn (r0reg, gen_rtx_REG (SImode, REG_SEQSTAT));
1206 insn = emit_insn (gen_ashrsi3 (r0reg, r0reg, GEN_INT (26)));
1207 insn = emit_insn (gen_ashlsi3 (r0reg, r0reg, GEN_INT (26)));
1208 insn = emit_move_insn (r1reg, spreg);
1209 insn = emit_move_insn (r2reg, gen_rtx_REG (Pmode, REG_FP));
1210 insn = emit_insn (gen_addsi3 (r2reg, r2reg, GEN_INT (8)));
1214 /* Generate an epilogue suitable for a function of kind FKIND. This is
1215 called for interrupt and exception handler epilogues.
1216 SPREG contains (reg:SI REG_SP). */
1218 static void
1219 expand_interrupt_handler_epilogue (rtx spreg, e_funkind fkind, bool all)
1221 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1222 rtx postinc1 = gen_rtx_POST_INC (SImode, spreg);
1223 rtx postinc = gen_rtx_MEM (SImode, postinc1);
1225 /* A slightly crude technique to stop flow from trying to delete "dead"
1226 insns. */
1227 MEM_VOLATILE_P (postinc) = 1;
1229 do_unlink (spreg, get_frame_size (), all, 1);
1231 if (lookup_attribute ("nesting", attrs))
1233 rtx srcreg = gen_rtx_REG (Pmode, (fkind == EXCPT_HANDLER ? REG_RETX
1234 : fkind == NMI_HANDLER ? REG_RETN
1235 : REG_RETI));
1236 emit_move_insn (srcreg, postinc);
1239 /* If we're calling other functions, they won't save their call-clobbered
1240 registers, so we must save (and restore) everything here. */
1241 if (!current_function_is_leaf)
1242 all = true;
1244 expand_epilogue_reg_restore (spreg, all, true);
1246 /* Deallocate any space we left on the stack in case we needed to save the
1247 argument registers. */
1248 if (fkind == EXCPT_HANDLER)
1249 emit_insn (gen_addsi3 (spreg, spreg, GEN_INT (12)));
1251 emit_jump_insn (gen_return_internal (GEN_INT (fkind)));
1254 /* Used while emitting the prologue to generate code to load the correct value
1255 into the PIC register, which is passed in DEST. */
1257 static rtx
1258 bfin_load_pic_reg (rtx dest)
1260 struct cgraph_local_info *i = NULL;
1261 rtx addr, insn;
1263 i = cgraph_local_info (current_function_decl);
1265 /* Functions local to the translation unit don't need to reload the
1266 pic reg, since the caller always passes a usable one. */
1267 if (i && i->local)
1268 return pic_offset_table_rtx;
1270 if (bfin_lib_id_given)
1271 addr = plus_constant (pic_offset_table_rtx, -4 - bfin_library_id * 4);
1272 else
1273 addr = gen_rtx_PLUS (Pmode, pic_offset_table_rtx,
1274 gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx),
1275 UNSPEC_LIBRARY_OFFSET));
1276 insn = emit_insn (gen_movsi (dest, gen_rtx_MEM (Pmode, addr)));
1277 return dest;
1280 /* Generate RTL for the prologue of the current function. */
1282 void
1283 bfin_expand_prologue (void)
1285 HOST_WIDE_INT frame_size = get_frame_size ();
1286 rtx spreg = gen_rtx_REG (Pmode, REG_SP);
1287 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
1288 rtx pic_reg_loaded = NULL_RTX;
1289 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1290 bool all = lookup_attribute ("saveall", attrs) != NULL_TREE;
1292 if (fkind != SUBROUTINE)
1294 expand_interrupt_handler_prologue (spreg, fkind, all);
1295 return;
1298 if (crtl->limit_stack
1299 || (TARGET_STACK_CHECK_L1
1300 && !DECL_NO_LIMIT_STACK (current_function_decl)))
1302 HOST_WIDE_INT offset
1303 = bfin_initial_elimination_offset (ARG_POINTER_REGNUM,
1304 STACK_POINTER_REGNUM);
1305 rtx lim = crtl->limit_stack ? stack_limit_rtx : NULL_RTX;
1306 rtx p2reg = gen_rtx_REG (Pmode, REG_P2);
1308 if (!lim)
1310 emit_move_insn (p2reg, gen_int_mode (0xFFB00000, SImode));
1311 emit_move_insn (p2reg, gen_rtx_MEM (Pmode, p2reg));
1312 lim = p2reg;
1314 if (GET_CODE (lim) == SYMBOL_REF)
1316 if (TARGET_ID_SHARED_LIBRARY)
1318 rtx p1reg = gen_rtx_REG (Pmode, REG_P1);
1319 rtx val;
1320 pic_reg_loaded = bfin_load_pic_reg (p2reg);
1321 val = legitimize_pic_address (stack_limit_rtx, p1reg,
1322 pic_reg_loaded);
1323 emit_move_insn (p1reg, val);
1324 frame_related_constant_load (p2reg, offset, FALSE);
1325 emit_insn (gen_addsi3 (p2reg, p2reg, p1reg));
1326 lim = p2reg;
1328 else
1330 rtx limit = plus_constant (lim, offset);
1331 emit_move_insn (p2reg, limit);
1332 lim = p2reg;
1335 else
1337 if (lim != p2reg)
1338 emit_move_insn (p2reg, lim);
1339 add_to_reg (p2reg, offset, 0, 0);
1340 lim = p2reg;
1342 emit_insn (gen_compare_lt (bfin_cc_rtx, spreg, lim));
1343 emit_insn (gen_trapifcc ());
1345 expand_prologue_reg_save (spreg, all, false);
1347 do_link (spreg, frame_size, false);
1349 if (TARGET_ID_SHARED_LIBRARY
1350 && !TARGET_SEP_DATA
1351 && (crtl->uses_pic_offset_table
1352 || !current_function_is_leaf))
1353 bfin_load_pic_reg (pic_offset_table_rtx);
1356 /* Generate RTL for the epilogue of the current function. NEED_RETURN is zero
1357 if this is for a sibcall. EH_RETURN is nonzero if we're expanding an
1358 eh_return pattern. SIBCALL_P is true if this is a sibcall epilogue,
1359 false otherwise. */
1361 void
1362 bfin_expand_epilogue (int need_return, int eh_return, bool sibcall_p)
1364 rtx spreg = gen_rtx_REG (Pmode, REG_SP);
1365 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
1366 int e = sibcall_p ? -1 : 1;
1367 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1368 bool all = lookup_attribute ("saveall", attrs) != NULL_TREE;
1370 if (fkind != SUBROUTINE)
1372 expand_interrupt_handler_epilogue (spreg, fkind, all);
1373 return;
1376 do_unlink (spreg, get_frame_size (), false, e);
1378 expand_epilogue_reg_restore (spreg, all, false);
1380 /* Omit the return insn if this is for a sibcall. */
1381 if (! need_return)
1382 return;
1384 if (eh_return)
1385 emit_insn (gen_addsi3 (spreg, spreg, gen_rtx_REG (Pmode, REG_P2)));
1387 emit_jump_insn (gen_return_internal (GEN_INT (SUBROUTINE)));
1390 /* Return nonzero if register OLD_REG can be renamed to register NEW_REG. */
1393 bfin_hard_regno_rename_ok (unsigned int old_reg ATTRIBUTE_UNUSED,
1394 unsigned int new_reg)
1396 /* Interrupt functions can only use registers that have already been
1397 saved by the prologue, even if they would normally be
1398 call-clobbered. */
1400 if (funkind (TREE_TYPE (current_function_decl)) != SUBROUTINE
1401 && !df_regs_ever_live_p (new_reg))
1402 return 0;
1404 return 1;
1407 /* Return the value of the return address for the frame COUNT steps up
1408 from the current frame, after the prologue.
1409 We punt for everything but the current frame by returning const0_rtx. */
1412 bfin_return_addr_rtx (int count)
1414 if (count != 0)
1415 return const0_rtx;
1417 return get_hard_reg_initial_val (Pmode, REG_RETS);
1420 /* Try machine-dependent ways of modifying an illegitimate address X
1421 to be legitimate. If we find one, return the new, valid address,
1422 otherwise return NULL_RTX.
1424 OLDX is the address as it was before break_out_memory_refs was called.
1425 In some cases it is useful to look at this to decide what needs to be done.
1427 MODE is the mode of the memory reference. */
1430 legitimize_address (rtx x ATTRIBUTE_UNUSED, rtx oldx ATTRIBUTE_UNUSED,
1431 enum machine_mode mode ATTRIBUTE_UNUSED)
1433 return NULL_RTX;
1436 static rtx
1437 bfin_delegitimize_address (rtx orig_x)
1439 rtx x = orig_x;
1441 if (GET_CODE (x) != MEM)
1442 return orig_x;
1444 x = XEXP (x, 0);
1445 if (GET_CODE (x) == PLUS
1446 && GET_CODE (XEXP (x, 1)) == UNSPEC
1447 && XINT (XEXP (x, 1), 1) == UNSPEC_MOVE_PIC
1448 && GET_CODE (XEXP (x, 0)) == REG
1449 && REGNO (XEXP (x, 0)) == PIC_OFFSET_TABLE_REGNUM)
1450 return XVECEXP (XEXP (x, 1), 0, 0);
1452 return orig_x;
1455 /* This predicate is used to compute the length of a load/store insn.
1456 OP is a MEM rtx, we return nonzero if its addressing mode requires a
1457 32-bit instruction. */
1460 effective_address_32bit_p (rtx op, enum machine_mode mode)
1462 HOST_WIDE_INT offset;
1464 mode = GET_MODE (op);
1465 op = XEXP (op, 0);
1467 if (GET_CODE (op) != PLUS)
1469 gcc_assert (REG_P (op) || GET_CODE (op) == POST_INC
1470 || GET_CODE (op) == PRE_DEC || GET_CODE (op) == POST_DEC);
1471 return 0;
1474 if (GET_CODE (XEXP (op, 1)) == UNSPEC)
1475 return 1;
1477 offset = INTVAL (XEXP (op, 1));
1479 /* All byte loads use a 16-bit offset. */
1480 if (GET_MODE_SIZE (mode) == 1)
1481 return 1;
1483 if (GET_MODE_SIZE (mode) == 4)
1485 /* Frame pointer relative loads can use a negative offset, all others
1486 are restricted to a small positive one. */
1487 if (XEXP (op, 0) == frame_pointer_rtx)
1488 return offset < -128 || offset > 60;
1489 return offset < 0 || offset > 60;
1492 /* Must be HImode now. */
1493 return offset < 0 || offset > 30;
1496 /* Returns true if X is a memory reference using an I register. */
1497 bool
1498 bfin_dsp_memref_p (rtx x)
1500 if (! MEM_P (x))
1501 return false;
1502 x = XEXP (x, 0);
1503 if (GET_CODE (x) == POST_INC || GET_CODE (x) == PRE_INC
1504 || GET_CODE (x) == POST_DEC || GET_CODE (x) == PRE_DEC)
1505 x = XEXP (x, 0);
1506 return IREG_P (x);
1509 /* Return cost of the memory address ADDR.
1510 All addressing modes are equally cheap on the Blackfin. */
1512 static int
1513 bfin_address_cost (rtx addr ATTRIBUTE_UNUSED, bool speed ATTRIBUTE_UNUSED)
1515 return 1;
1518 /* Subroutine of print_operand; used to print a memory reference X to FILE. */
1520 void
1521 print_address_operand (FILE *file, rtx x)
1523 switch (GET_CODE (x))
1525 case PLUS:
1526 output_address (XEXP (x, 0));
1527 fprintf (file, "+");
1528 output_address (XEXP (x, 1));
1529 break;
1531 case PRE_DEC:
1532 fprintf (file, "--");
1533 output_address (XEXP (x, 0));
1534 break;
1535 case POST_INC:
1536 output_address (XEXP (x, 0));
1537 fprintf (file, "++");
1538 break;
1539 case POST_DEC:
1540 output_address (XEXP (x, 0));
1541 fprintf (file, "--");
1542 break;
1544 default:
1545 gcc_assert (GET_CODE (x) != MEM);
1546 print_operand (file, x, 0);
1547 break;
1551 /* Adding intp DImode support by Tony
1552 * -- Q: (low word)
1553 * -- R: (high word)
1556 void
1557 print_operand (FILE *file, rtx x, char code)
1559 enum machine_mode mode;
1561 if (code == '!')
1563 if (GET_MODE (current_output_insn) == SImode)
1564 fprintf (file, " ||");
1565 else
1566 fprintf (file, ";");
1567 return;
1570 mode = GET_MODE (x);
1572 switch (code)
1574 case 'j':
1575 switch (GET_CODE (x))
1577 case EQ:
1578 fprintf (file, "e");
1579 break;
1580 case NE:
1581 fprintf (file, "ne");
1582 break;
1583 case GT:
1584 fprintf (file, "g");
1585 break;
1586 case LT:
1587 fprintf (file, "l");
1588 break;
1589 case GE:
1590 fprintf (file, "ge");
1591 break;
1592 case LE:
1593 fprintf (file, "le");
1594 break;
1595 case GTU:
1596 fprintf (file, "g");
1597 break;
1598 case LTU:
1599 fprintf (file, "l");
1600 break;
1601 case GEU:
1602 fprintf (file, "ge");
1603 break;
1604 case LEU:
1605 fprintf (file, "le");
1606 break;
1607 default:
1608 output_operand_lossage ("invalid %%j value");
1610 break;
1612 case 'J': /* reverse logic */
1613 switch (GET_CODE(x))
1615 case EQ:
1616 fprintf (file, "ne");
1617 break;
1618 case NE:
1619 fprintf (file, "e");
1620 break;
1621 case GT:
1622 fprintf (file, "le");
1623 break;
1624 case LT:
1625 fprintf (file, "ge");
1626 break;
1627 case GE:
1628 fprintf (file, "l");
1629 break;
1630 case LE:
1631 fprintf (file, "g");
1632 break;
1633 case GTU:
1634 fprintf (file, "le");
1635 break;
1636 case LTU:
1637 fprintf (file, "ge");
1638 break;
1639 case GEU:
1640 fprintf (file, "l");
1641 break;
1642 case LEU:
1643 fprintf (file, "g");
1644 break;
1645 default:
1646 output_operand_lossage ("invalid %%J value");
1648 break;
1650 default:
1651 switch (GET_CODE (x))
1653 case REG:
1654 if (code == 'h')
1656 if (REGNO (x) < 32)
1657 fprintf (file, "%s", short_reg_names[REGNO (x)]);
1658 else
1659 output_operand_lossage ("invalid operand for code '%c'", code);
1661 else if (code == 'd')
1663 if (REGNO (x) < 32)
1664 fprintf (file, "%s", high_reg_names[REGNO (x)]);
1665 else
1666 output_operand_lossage ("invalid operand for code '%c'", code);
1668 else if (code == 'w')
1670 if (REGNO (x) == REG_A0 || REGNO (x) == REG_A1)
1671 fprintf (file, "%s.w", reg_names[REGNO (x)]);
1672 else
1673 output_operand_lossage ("invalid operand for code '%c'", code);
1675 else if (code == 'x')
1677 if (REGNO (x) == REG_A0 || REGNO (x) == REG_A1)
1678 fprintf (file, "%s.x", reg_names[REGNO (x)]);
1679 else
1680 output_operand_lossage ("invalid operand for code '%c'", code);
1682 else if (code == 'v')
1684 if (REGNO (x) == REG_A0)
1685 fprintf (file, "AV0");
1686 else if (REGNO (x) == REG_A1)
1687 fprintf (file, "AV1");
1688 else
1689 output_operand_lossage ("invalid operand for code '%c'", code);
1691 else if (code == 'D')
1693 if (D_REGNO_P (REGNO (x)))
1694 fprintf (file, "%s", dregs_pair_names[REGNO (x)]);
1695 else
1696 output_operand_lossage ("invalid operand for code '%c'", code);
1698 else if (code == 'H')
1700 if ((mode == DImode || mode == DFmode) && REG_P (x))
1701 fprintf (file, "%s", reg_names[REGNO (x) + 1]);
1702 else
1703 output_operand_lossage ("invalid operand for code '%c'", code);
1705 else if (code == 'T')
1707 if (D_REGNO_P (REGNO (x)))
1708 fprintf (file, "%s", byte_reg_names[REGNO (x)]);
1709 else
1710 output_operand_lossage ("invalid operand for code '%c'", code);
1712 else
1713 fprintf (file, "%s", reg_names[REGNO (x)]);
1714 break;
1716 case MEM:
1717 fputc ('[', file);
1718 x = XEXP (x,0);
1719 print_address_operand (file, x);
1720 fputc (']', file);
1721 break;
1723 case CONST_INT:
1724 if (code == 'M')
1726 switch (INTVAL (x))
1728 case MACFLAG_NONE:
1729 break;
1730 case MACFLAG_FU:
1731 fputs ("(FU)", file);
1732 break;
1733 case MACFLAG_T:
1734 fputs ("(T)", file);
1735 break;
1736 case MACFLAG_TFU:
1737 fputs ("(TFU)", file);
1738 break;
1739 case MACFLAG_W32:
1740 fputs ("(W32)", file);
1741 break;
1742 case MACFLAG_IS:
1743 fputs ("(IS)", file);
1744 break;
1745 case MACFLAG_IU:
1746 fputs ("(IU)", file);
1747 break;
1748 case MACFLAG_IH:
1749 fputs ("(IH)", file);
1750 break;
1751 case MACFLAG_M:
1752 fputs ("(M)", file);
1753 break;
1754 case MACFLAG_IS_M:
1755 fputs ("(IS,M)", file);
1756 break;
1757 case MACFLAG_ISS2:
1758 fputs ("(ISS2)", file);
1759 break;
1760 case MACFLAG_S2RND:
1761 fputs ("(S2RND)", file);
1762 break;
1763 default:
1764 gcc_unreachable ();
1766 break;
1768 else if (code == 'b')
1770 if (INTVAL (x) == 0)
1771 fputs ("+=", file);
1772 else if (INTVAL (x) == 1)
1773 fputs ("-=", file);
1774 else
1775 gcc_unreachable ();
1776 break;
1778 /* Moves to half registers with d or h modifiers always use unsigned
1779 constants. */
1780 else if (code == 'd')
1781 x = GEN_INT ((INTVAL (x) >> 16) & 0xffff);
1782 else if (code == 'h')
1783 x = GEN_INT (INTVAL (x) & 0xffff);
1784 else if (code == 'N')
1785 x = GEN_INT (-INTVAL (x));
1786 else if (code == 'X')
1787 x = GEN_INT (exact_log2 (0xffffffff & INTVAL (x)));
1788 else if (code == 'Y')
1789 x = GEN_INT (exact_log2 (0xffffffff & ~INTVAL (x)));
1790 else if (code == 'Z')
1791 /* Used for LINK insns. */
1792 x = GEN_INT (-8 - INTVAL (x));
1794 /* fall through */
1796 case SYMBOL_REF:
1797 output_addr_const (file, x);
1798 break;
1800 case CONST_DOUBLE:
1801 output_operand_lossage ("invalid const_double operand");
1802 break;
1804 case UNSPEC:
1805 switch (XINT (x, 1))
1807 case UNSPEC_MOVE_PIC:
1808 output_addr_const (file, XVECEXP (x, 0, 0));
1809 fprintf (file, "@GOT");
1810 break;
1812 case UNSPEC_MOVE_FDPIC:
1813 output_addr_const (file, XVECEXP (x, 0, 0));
1814 fprintf (file, "@GOT17M4");
1815 break;
1817 case UNSPEC_FUNCDESC_GOT17M4:
1818 output_addr_const (file, XVECEXP (x, 0, 0));
1819 fprintf (file, "@FUNCDESC_GOT17M4");
1820 break;
1822 case UNSPEC_LIBRARY_OFFSET:
1823 fprintf (file, "_current_shared_library_p5_offset_");
1824 break;
1826 default:
1827 gcc_unreachable ();
1829 break;
1831 default:
1832 output_addr_const (file, x);
1837 /* Argument support functions. */
1839 /* Initialize a variable CUM of type CUMULATIVE_ARGS
1840 for a call to a function whose data type is FNTYPE.
1841 For a library call, FNTYPE is 0.
1842 VDSP C Compiler manual, our ABI says that
1843 first 3 words of arguments will use R0, R1 and R2.
1846 void
1847 init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype,
1848 rtx libname ATTRIBUTE_UNUSED)
1850 static CUMULATIVE_ARGS zero_cum;
1852 *cum = zero_cum;
1854 /* Set up the number of registers to use for passing arguments. */
1856 cum->nregs = max_arg_registers;
1857 cum->arg_regs = arg_regs;
1859 cum->call_cookie = CALL_NORMAL;
1860 /* Check for a longcall attribute. */
1861 if (fntype && lookup_attribute ("shortcall", TYPE_ATTRIBUTES (fntype)))
1862 cum->call_cookie |= CALL_SHORT;
1863 else if (fntype && lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype)))
1864 cum->call_cookie |= CALL_LONG;
1866 return;
1869 /* Update the data in CUM to advance over an argument
1870 of mode MODE and data type TYPE.
1871 (TYPE is null for libcalls where that information may not be available.) */
1873 void
1874 function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
1875 int named ATTRIBUTE_UNUSED)
1877 int count, bytes, words;
1879 bytes = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
1880 words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
1882 cum->words += words;
1883 cum->nregs -= words;
1885 if (cum->nregs <= 0)
1887 cum->nregs = 0;
1888 cum->arg_regs = NULL;
1890 else
1892 for (count = 1; count <= words; count++)
1893 cum->arg_regs++;
1896 return;
1899 /* Define where to put the arguments to a function.
1900 Value is zero to push the argument on the stack,
1901 or a hard register in which to store the argument.
1903 MODE is the argument's machine mode.
1904 TYPE is the data type of the argument (as a tree).
1905 This is null for libcalls where that information may
1906 not be available.
1907 CUM is a variable of type CUMULATIVE_ARGS which gives info about
1908 the preceding args and about the function being called.
1909 NAMED is nonzero if this argument is a named parameter
1910 (otherwise it is an extra parameter matching an ellipsis). */
1912 struct rtx_def *
1913 function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
1914 int named ATTRIBUTE_UNUSED)
1916 int bytes
1917 = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
1919 if (mode == VOIDmode)
1920 /* Compute operand 2 of the call insn. */
1921 return GEN_INT (cum->call_cookie);
1923 if (bytes == -1)
1924 return NULL_RTX;
1926 if (cum->nregs)
1927 return gen_rtx_REG (mode, *(cum->arg_regs));
1929 return NULL_RTX;
1932 /* For an arg passed partly in registers and partly in memory,
1933 this is the number of bytes passed in registers.
1934 For args passed entirely in registers or entirely in memory, zero.
1936 Refer VDSP C Compiler manual, our ABI.
1937 First 3 words are in registers. So, if an argument is larger
1938 than the registers available, it will span the register and
1939 stack. */
1941 static int
1942 bfin_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode,
1943 tree type ATTRIBUTE_UNUSED,
1944 bool named ATTRIBUTE_UNUSED)
1946 int bytes
1947 = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
1948 int bytes_left = cum->nregs * UNITS_PER_WORD;
1950 if (bytes == -1)
1951 return 0;
1953 if (bytes_left == 0)
1954 return 0;
1955 if (bytes > bytes_left)
1956 return bytes_left;
1957 return 0;
1960 /* Variable sized types are passed by reference. */
1962 static bool
1963 bfin_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
1964 enum machine_mode mode ATTRIBUTE_UNUSED,
1965 const_tree type, bool named ATTRIBUTE_UNUSED)
1967 return type && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST;
1970 /* Decide whether a type should be returned in memory (true)
1971 or in a register (false). This is called by the macro
1972 TARGET_RETURN_IN_MEMORY. */
1974 static bool
1975 bfin_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
1977 int size = int_size_in_bytes (type);
1978 return size > 2 * UNITS_PER_WORD || size == -1;
1981 /* Register in which address to store a structure value
1982 is passed to a function. */
1983 static rtx
1984 bfin_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
1985 int incoming ATTRIBUTE_UNUSED)
1987 return gen_rtx_REG (Pmode, REG_P0);
1990 /* Return true when register may be used to pass function parameters. */
1992 bool
1993 function_arg_regno_p (int n)
1995 int i;
1996 for (i = 0; arg_regs[i] != -1; i++)
1997 if (n == arg_regs[i])
1998 return true;
1999 return false;
2002 /* Returns 1 if OP contains a symbol reference */
2005 symbolic_reference_mentioned_p (rtx op)
2007 register const char *fmt;
2008 register int i;
2010 if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF)
2011 return 1;
2013 fmt = GET_RTX_FORMAT (GET_CODE (op));
2014 for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
2016 if (fmt[i] == 'E')
2018 register int j;
2020 for (j = XVECLEN (op, i) - 1; j >= 0; j--)
2021 if (symbolic_reference_mentioned_p (XVECEXP (op, i, j)))
2022 return 1;
2025 else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i)))
2026 return 1;
2029 return 0;
2032 /* Decide whether we can make a sibling call to a function. DECL is the
2033 declaration of the function being targeted by the call and EXP is the
2034 CALL_EXPR representing the call. */
2036 static bool
2037 bfin_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED,
2038 tree exp ATTRIBUTE_UNUSED)
2040 struct cgraph_local_info *this_func, *called_func;
2041 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
2042 if (fkind != SUBROUTINE)
2043 return false;
2044 if (!TARGET_ID_SHARED_LIBRARY || TARGET_SEP_DATA)
2045 return true;
2047 /* When compiling for ID shared libraries, can't sibcall a local function
2048 from a non-local function, because the local function thinks it does
2049 not need to reload P5 in the prologue, but the sibcall wil pop P5 in the
2050 sibcall epilogue, and we end up with the wrong value in P5. */
2052 if (!decl)
2053 /* Not enough information. */
2054 return false;
2056 this_func = cgraph_local_info (current_function_decl);
2057 called_func = cgraph_local_info (decl);
2058 return !called_func->local || this_func->local;
2061 /* Emit RTL insns to initialize the variable parts of a trampoline at
2062 TRAMP. FNADDR is an RTX for the address of the function's pure
2063 code. CXT is an RTX for the static chain value for the function. */
2065 void
2066 initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt)
2068 rtx t1 = copy_to_reg (fnaddr);
2069 rtx t2 = copy_to_reg (cxt);
2070 rtx addr;
2071 int i = 0;
2073 if (TARGET_FDPIC)
2075 rtx a = memory_address (Pmode, plus_constant (tramp, 8));
2076 addr = memory_address (Pmode, tramp);
2077 emit_move_insn (gen_rtx_MEM (SImode, addr), a);
2078 i = 8;
2081 addr = memory_address (Pmode, plus_constant (tramp, i + 2));
2082 emit_move_insn (gen_rtx_MEM (HImode, addr), gen_lowpart (HImode, t1));
2083 emit_insn (gen_ashrsi3 (t1, t1, GEN_INT (16)));
2084 addr = memory_address (Pmode, plus_constant (tramp, i + 6));
2085 emit_move_insn (gen_rtx_MEM (HImode, addr), gen_lowpart (HImode, t1));
2087 addr = memory_address (Pmode, plus_constant (tramp, i + 10));
2088 emit_move_insn (gen_rtx_MEM (HImode, addr), gen_lowpart (HImode, t2));
2089 emit_insn (gen_ashrsi3 (t2, t2, GEN_INT (16)));
2090 addr = memory_address (Pmode, plus_constant (tramp, i + 14));
2091 emit_move_insn (gen_rtx_MEM (HImode, addr), gen_lowpart (HImode, t2));
2094 /* Emit insns to move operands[1] into operands[0]. */
2096 void
2097 emit_pic_move (rtx *operands, enum machine_mode mode ATTRIBUTE_UNUSED)
2099 rtx temp = reload_in_progress ? operands[0] : gen_reg_rtx (Pmode);
2101 gcc_assert (!TARGET_FDPIC || !(reload_in_progress || reload_completed));
2102 if (GET_CODE (operands[0]) == MEM && SYMBOLIC_CONST (operands[1]))
2103 operands[1] = force_reg (SImode, operands[1]);
2104 else
2105 operands[1] = legitimize_pic_address (operands[1], temp,
2106 TARGET_FDPIC ? OUR_FDPIC_REG
2107 : pic_offset_table_rtx);
2110 /* Expand a move operation in mode MODE. The operands are in OPERANDS.
2111 Returns true if no further code must be generated, false if the caller
2112 should generate an insn to move OPERANDS[1] to OPERANDS[0]. */
2114 bool
2115 expand_move (rtx *operands, enum machine_mode mode)
2117 rtx op = operands[1];
2118 if ((TARGET_ID_SHARED_LIBRARY || TARGET_FDPIC)
2119 && SYMBOLIC_CONST (op))
2120 emit_pic_move (operands, mode);
2121 else if (mode == SImode && GET_CODE (op) == CONST
2122 && GET_CODE (XEXP (op, 0)) == PLUS
2123 && GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF
2124 && !bfin_legitimate_constant_p (op))
2126 rtx dest = operands[0];
2127 rtx op0, op1;
2128 gcc_assert (!reload_in_progress && !reload_completed);
2129 op = XEXP (op, 0);
2130 op0 = force_reg (mode, XEXP (op, 0));
2131 op1 = XEXP (op, 1);
2132 if (!insn_data[CODE_FOR_addsi3].operand[2].predicate (op1, mode))
2133 op1 = force_reg (mode, op1);
2134 if (GET_CODE (dest) == MEM)
2135 dest = gen_reg_rtx (mode);
2136 emit_insn (gen_addsi3 (dest, op0, op1));
2137 if (dest == operands[0])
2138 return true;
2139 operands[1] = dest;
2141 /* Don't generate memory->memory or constant->memory moves, go through a
2142 register */
2143 else if ((reload_in_progress | reload_completed) == 0
2144 && GET_CODE (operands[0]) == MEM
2145 && GET_CODE (operands[1]) != REG)
2146 operands[1] = force_reg (mode, operands[1]);
2147 return false;
2150 /* Split one or more DImode RTL references into pairs of SImode
2151 references. The RTL can be REG, offsettable MEM, integer constant, or
2152 CONST_DOUBLE. "operands" is a pointer to an array of DImode RTL to
2153 split and "num" is its length. lo_half and hi_half are output arrays
2154 that parallel "operands". */
2156 void
2157 split_di (rtx operands[], int num, rtx lo_half[], rtx hi_half[])
2159 while (num--)
2161 rtx op = operands[num];
2163 /* simplify_subreg refuse to split volatile memory addresses,
2164 but we still have to handle it. */
2165 if (GET_CODE (op) == MEM)
2167 lo_half[num] = adjust_address (op, SImode, 0);
2168 hi_half[num] = adjust_address (op, SImode, 4);
2170 else
2172 lo_half[num] = simplify_gen_subreg (SImode, op,
2173 GET_MODE (op) == VOIDmode
2174 ? DImode : GET_MODE (op), 0);
2175 hi_half[num] = simplify_gen_subreg (SImode, op,
2176 GET_MODE (op) == VOIDmode
2177 ? DImode : GET_MODE (op), 4);
2182 bool
2183 bfin_longcall_p (rtx op, int call_cookie)
2185 gcc_assert (GET_CODE (op) == SYMBOL_REF);
2186 if (call_cookie & CALL_SHORT)
2187 return 0;
2188 if (call_cookie & CALL_LONG)
2189 return 1;
2190 if (TARGET_LONG_CALLS)
2191 return 1;
2192 return 0;
2195 /* Expand a call instruction. FNADDR is the call target, RETVAL the return value.
2196 COOKIE is a CONST_INT holding the call_cookie prepared init_cumulative_args.
2197 SIBCALL is nonzero if this is a sibling call. */
2199 void
2200 bfin_expand_call (rtx retval, rtx fnaddr, rtx callarg1, rtx cookie, int sibcall)
2202 rtx use = NULL, call;
2203 rtx callee = XEXP (fnaddr, 0);
2204 int nelts = 2 + !!sibcall;
2205 rtx pat;
2206 rtx picreg = get_hard_reg_initial_val (SImode, FDPIC_REGNO);
2207 int n;
2209 /* In an untyped call, we can get NULL for operand 2. */
2210 if (cookie == NULL_RTX)
2211 cookie = const0_rtx;
2213 /* Static functions and indirect calls don't need the pic register. */
2214 if (!TARGET_FDPIC && flag_pic
2215 && GET_CODE (callee) == SYMBOL_REF
2216 && !SYMBOL_REF_LOCAL_P (callee))
2217 use_reg (&use, pic_offset_table_rtx);
2219 if (TARGET_FDPIC)
2221 int caller_has_l1_text, callee_has_l1_text;
2223 caller_has_l1_text = callee_has_l1_text = 0;
2225 if (lookup_attribute ("l1_text",
2226 DECL_ATTRIBUTES (cfun->decl)) != NULL_TREE)
2227 caller_has_l1_text = 1;
2229 if (GET_CODE (callee) == SYMBOL_REF
2230 && SYMBOL_REF_DECL (callee) && DECL_P (SYMBOL_REF_DECL (callee))
2231 && lookup_attribute
2232 ("l1_text",
2233 DECL_ATTRIBUTES (SYMBOL_REF_DECL (callee))) != NULL_TREE)
2234 callee_has_l1_text = 1;
2236 if (GET_CODE (callee) != SYMBOL_REF
2237 || bfin_longcall_p (callee, INTVAL (cookie))
2238 || (GET_CODE (callee) == SYMBOL_REF
2239 && !SYMBOL_REF_LOCAL_P (callee)
2240 && TARGET_INLINE_PLT)
2241 || caller_has_l1_text != callee_has_l1_text
2242 || (caller_has_l1_text && callee_has_l1_text
2243 && (GET_CODE (callee) != SYMBOL_REF
2244 || !SYMBOL_REF_LOCAL_P (callee))))
2246 rtx addr = callee;
2247 if (! address_operand (addr, Pmode))
2248 addr = force_reg (Pmode, addr);
2250 fnaddr = gen_reg_rtx (SImode);
2251 emit_insn (gen_load_funcdescsi (fnaddr, addr));
2252 fnaddr = gen_rtx_MEM (Pmode, fnaddr);
2254 picreg = gen_reg_rtx (SImode);
2255 emit_insn (gen_load_funcdescsi (picreg,
2256 plus_constant (addr, 4)));
2259 nelts++;
2261 else if ((!register_no_elim_operand (callee, Pmode)
2262 && GET_CODE (callee) != SYMBOL_REF)
2263 || (GET_CODE (callee) == SYMBOL_REF
2264 && ((TARGET_ID_SHARED_LIBRARY && !TARGET_LEAF_ID_SHARED_LIBRARY)
2265 || bfin_longcall_p (callee, INTVAL (cookie)))))
2267 callee = copy_to_mode_reg (Pmode, callee);
2268 fnaddr = gen_rtx_MEM (Pmode, callee);
2270 call = gen_rtx_CALL (VOIDmode, fnaddr, callarg1);
2272 if (retval)
2273 call = gen_rtx_SET (VOIDmode, retval, call);
2275 pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (nelts));
2276 n = 0;
2277 XVECEXP (pat, 0, n++) = call;
2278 if (TARGET_FDPIC)
2279 XVECEXP (pat, 0, n++) = gen_rtx_USE (VOIDmode, picreg);
2280 XVECEXP (pat, 0, n++) = gen_rtx_USE (VOIDmode, cookie);
2281 if (sibcall)
2282 XVECEXP (pat, 0, n++) = gen_rtx_RETURN (VOIDmode);
2283 call = emit_call_insn (pat);
2284 if (use)
2285 CALL_INSN_FUNCTION_USAGE (call) = use;
2288 /* Return 1 if hard register REGNO can hold a value of machine-mode MODE. */
2291 hard_regno_mode_ok (int regno, enum machine_mode mode)
2293 /* Allow only dregs to store value of mode HI or QI */
2294 enum reg_class rclass = REGNO_REG_CLASS (regno);
2296 if (mode == CCmode)
2297 return 0;
2299 if (mode == V2HImode)
2300 return D_REGNO_P (regno);
2301 if (rclass == CCREGS)
2302 return mode == BImode;
2303 if (mode == PDImode || mode == V2PDImode)
2304 return regno == REG_A0 || regno == REG_A1;
2306 /* Allow all normal 32-bit regs, except REG_M3, in case regclass ever comes
2307 up with a bad register class (such as ALL_REGS) for DImode. */
2308 if (mode == DImode)
2309 return regno < REG_M3;
2311 if (mode == SImode
2312 && TEST_HARD_REG_BIT (reg_class_contents[PROLOGUE_REGS], regno))
2313 return 1;
2315 return TEST_HARD_REG_BIT (reg_class_contents[MOST_REGS], regno);
2318 /* Implements target hook vector_mode_supported_p. */
2320 static bool
2321 bfin_vector_mode_supported_p (enum machine_mode mode)
2323 return mode == V2HImode;
2326 /* Return the cost of moving data from a register in class CLASS1 to
2327 one in class CLASS2. A cost of 2 is the default. */
2330 bfin_register_move_cost (enum machine_mode mode,
2331 enum reg_class class1, enum reg_class class2)
2333 /* These need secondary reloads, so they're more expensive. */
2334 if ((class1 == CCREGS && class2 != DREGS)
2335 || (class1 != DREGS && class2 == CCREGS))
2336 return 4;
2338 /* If optimizing for size, always prefer reg-reg over reg-memory moves. */
2339 if (optimize_size)
2340 return 2;
2342 /* There are some stalls involved when moving from a DREG to a different
2343 class reg, and using the value in one of the following instructions.
2344 Attempt to model this by slightly discouraging such moves. */
2345 if (class1 == DREGS && class2 != DREGS)
2346 return 2 * 2;
2348 if (GET_MODE_CLASS (mode) == MODE_INT)
2350 /* Discourage trying to use the accumulators. */
2351 if (TEST_HARD_REG_BIT (reg_class_contents[class1], REG_A0)
2352 || TEST_HARD_REG_BIT (reg_class_contents[class1], REG_A1)
2353 || TEST_HARD_REG_BIT (reg_class_contents[class2], REG_A0)
2354 || TEST_HARD_REG_BIT (reg_class_contents[class2], REG_A1))
2355 return 20;
2357 return 2;
2360 /* Return the cost of moving data of mode M between a
2361 register and memory. A value of 2 is the default; this cost is
2362 relative to those in `REGISTER_MOVE_COST'.
2364 ??? In theory L1 memory has single-cycle latency. We should add a switch
2365 that tells the compiler whether we expect to use only L1 memory for the
2366 program; it'll make the costs more accurate. */
2369 bfin_memory_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
2370 enum reg_class rclass,
2371 int in ATTRIBUTE_UNUSED)
2373 /* Make memory accesses slightly more expensive than any register-register
2374 move. Also, penalize non-DP registers, since they need secondary
2375 reloads to load and store. */
2376 if (! reg_class_subset_p (rclass, DPREGS))
2377 return 10;
2379 return 8;
2382 /* Inform reload about cases where moving X with a mode MODE to a register in
2383 RCLASS requires an extra scratch register. Return the class needed for the
2384 scratch register. */
2386 static enum reg_class
2387 bfin_secondary_reload (bool in_p, rtx x, enum reg_class rclass,
2388 enum machine_mode mode, secondary_reload_info *sri)
2390 /* If we have HImode or QImode, we can only use DREGS as secondary registers;
2391 in most other cases we can also use PREGS. */
2392 enum reg_class default_class = GET_MODE_SIZE (mode) >= 4 ? DPREGS : DREGS;
2393 enum reg_class x_class = NO_REGS;
2394 enum rtx_code code = GET_CODE (x);
2396 if (code == SUBREG)
2397 x = SUBREG_REG (x), code = GET_CODE (x);
2398 if (REG_P (x))
2400 int regno = REGNO (x);
2401 if (regno >= FIRST_PSEUDO_REGISTER)
2402 regno = reg_renumber[regno];
2404 if (regno == -1)
2405 code = MEM;
2406 else
2407 x_class = REGNO_REG_CLASS (regno);
2410 /* We can be asked to reload (plus (FP) (large_constant)) into a DREG.
2411 This happens as a side effect of register elimination, and we need
2412 a scratch register to do it. */
2413 if (fp_plus_const_operand (x, mode))
2415 rtx op2 = XEXP (x, 1);
2416 int large_constant_p = ! satisfies_constraint_Ks7 (op2);
2418 if (rclass == PREGS || rclass == PREGS_CLOBBERED)
2419 return NO_REGS;
2420 /* If destination is a DREG, we can do this without a scratch register
2421 if the constant is valid for an add instruction. */
2422 if ((rclass == DREGS || rclass == DPREGS)
2423 && ! large_constant_p)
2424 return NO_REGS;
2425 /* Reloading to anything other than a DREG? Use a PREG scratch
2426 register. */
2427 sri->icode = CODE_FOR_reload_insi;
2428 return NO_REGS;
2431 /* Data can usually be moved freely between registers of most classes.
2432 AREGS are an exception; they can only move to or from another register
2433 in AREGS or one in DREGS. They can also be assigned the constant 0. */
2434 if (x_class == AREGS || x_class == EVEN_AREGS || x_class == ODD_AREGS)
2435 return (rclass == DREGS || rclass == AREGS || rclass == EVEN_AREGS
2436 || rclass == ODD_AREGS
2437 ? NO_REGS : DREGS);
2439 if (rclass == AREGS || rclass == EVEN_AREGS || rclass == ODD_AREGS)
2441 if (code == MEM)
2443 sri->icode = in_p ? CODE_FOR_reload_inpdi : CODE_FOR_reload_outpdi;
2444 return NO_REGS;
2447 if (x != const0_rtx && x_class != DREGS)
2449 return DREGS;
2451 else
2452 return NO_REGS;
2455 /* CCREGS can only be moved from/to DREGS. */
2456 if (rclass == CCREGS && x_class != DREGS)
2457 return DREGS;
2458 if (x_class == CCREGS && rclass != DREGS)
2459 return DREGS;
2461 /* All registers other than AREGS can load arbitrary constants. The only
2462 case that remains is MEM. */
2463 if (code == MEM)
2464 if (! reg_class_subset_p (rclass, default_class))
2465 return default_class;
2467 return NO_REGS;
2470 /* Implement TARGET_HANDLE_OPTION. */
2472 static bool
2473 bfin_handle_option (size_t code, const char *arg, int value)
2475 switch (code)
2477 case OPT_mshared_library_id_:
2478 if (value > MAX_LIBRARY_ID)
2479 error ("-mshared-library-id=%s is not between 0 and %d",
2480 arg, MAX_LIBRARY_ID);
2481 bfin_lib_id_given = 1;
2482 return true;
2484 case OPT_mcpu_:
2486 const char *p, *q;
2487 int i;
2489 i = 0;
2490 while ((p = bfin_cpus[i].name) != NULL)
2492 if (strncmp (arg, p, strlen (p)) == 0)
2493 break;
2494 i++;
2497 if (p == NULL)
2499 error ("-mcpu=%s is not valid", arg);
2500 return false;
2503 bfin_cpu_type = bfin_cpus[i].type;
2505 q = arg + strlen (p);
2507 if (*q == '\0')
2509 bfin_si_revision = bfin_cpus[i].si_revision;
2510 bfin_workarounds |= bfin_cpus[i].workarounds;
2512 else if (strcmp (q, "-none") == 0)
2513 bfin_si_revision = -1;
2514 else if (strcmp (q, "-any") == 0)
2516 bfin_si_revision = 0xffff;
2517 while (bfin_cpus[i].type == bfin_cpu_type)
2519 bfin_workarounds |= bfin_cpus[i].workarounds;
2520 i++;
2523 else
2525 unsigned int si_major, si_minor;
2526 int rev_len, n;
2528 rev_len = strlen (q);
2530 if (sscanf (q, "-%u.%u%n", &si_major, &si_minor, &n) != 2
2531 || n != rev_len
2532 || si_major > 0xff || si_minor > 0xff)
2534 invalid_silicon_revision:
2535 error ("-mcpu=%s has invalid silicon revision", arg);
2536 return false;
2539 bfin_si_revision = (si_major << 8) | si_minor;
2541 while (bfin_cpus[i].type == bfin_cpu_type
2542 && bfin_cpus[i].si_revision != bfin_si_revision)
2543 i++;
2545 if (bfin_cpus[i].type != bfin_cpu_type)
2546 goto invalid_silicon_revision;
2548 bfin_workarounds |= bfin_cpus[i].workarounds;
2551 return true;
2554 default:
2555 return true;
2559 static struct machine_function *
2560 bfin_init_machine_status (void)
2562 struct machine_function *f;
2564 f = GGC_CNEW (struct machine_function);
2566 return f;
2569 /* Implement the macro OVERRIDE_OPTIONS. */
2571 void
2572 override_options (void)
2574 /* If processor type is not specified, enable all workarounds. */
2575 if (bfin_cpu_type == BFIN_CPU_UNKNOWN)
2577 int i;
2579 for (i = 0; bfin_cpus[i].name != NULL; i++)
2580 bfin_workarounds |= bfin_cpus[i].workarounds;
2582 bfin_si_revision = 0xffff;
2585 if (bfin_csync_anomaly == 1)
2586 bfin_workarounds |= WA_SPECULATIVE_SYNCS;
2587 else if (bfin_csync_anomaly == 0)
2588 bfin_workarounds &= ~WA_SPECULATIVE_SYNCS;
2590 if (bfin_specld_anomaly == 1)
2591 bfin_workarounds |= WA_SPECULATIVE_LOADS;
2592 else if (bfin_specld_anomaly == 0)
2593 bfin_workarounds &= ~WA_SPECULATIVE_LOADS;
2595 if (TARGET_OMIT_LEAF_FRAME_POINTER)
2596 flag_omit_frame_pointer = 1;
2598 /* Library identification */
2599 if (bfin_lib_id_given && ! TARGET_ID_SHARED_LIBRARY)
2600 error ("-mshared-library-id= specified without -mid-shared-library");
2602 if (stack_limit_rtx && TARGET_STACK_CHECK_L1)
2603 error ("Can't use multiple stack checking methods together.");
2605 if (TARGET_ID_SHARED_LIBRARY && TARGET_FDPIC)
2606 error ("ID shared libraries and FD-PIC mode can't be used together.");
2608 /* Don't allow the user to specify -mid-shared-library and -msep-data
2609 together, as it makes little sense from a user's point of view... */
2610 if (TARGET_SEP_DATA && TARGET_ID_SHARED_LIBRARY)
2611 error ("cannot specify both -msep-data and -mid-shared-library");
2612 /* ... internally, however, it's nearly the same. */
2613 if (TARGET_SEP_DATA)
2614 target_flags |= MASK_ID_SHARED_LIBRARY | MASK_LEAF_ID_SHARED_LIBRARY;
2616 if (TARGET_ID_SHARED_LIBRARY && flag_pic == 0)
2617 flag_pic = 1;
2619 /* There is no single unaligned SI op for PIC code. Sometimes we
2620 need to use ".4byte" and sometimes we need to use ".picptr".
2621 See bfin_assemble_integer for details. */
2622 if (TARGET_FDPIC)
2623 targetm.asm_out.unaligned_op.si = 0;
2625 /* Silently turn off flag_pic if not doing FDPIC or ID shared libraries,
2626 since we don't support it and it'll just break. */
2627 if (flag_pic && !TARGET_FDPIC && !TARGET_ID_SHARED_LIBRARY)
2628 flag_pic = 0;
2630 if (TARGET_MULTICORE && bfin_cpu_type != BFIN_CPU_BF561)
2631 error ("-mmulticore can only be used with BF561");
2633 if (TARGET_COREA && !TARGET_MULTICORE)
2634 error ("-mcorea should be used with -mmulticore");
2636 if (TARGET_COREB && !TARGET_MULTICORE)
2637 error ("-mcoreb should be used with -mmulticore");
2639 if (TARGET_COREA && TARGET_COREB)
2640 error ("-mcorea and -mcoreb can't be used together");
2642 flag_schedule_insns = 0;
2644 /* Passes after sched2 can break the helpful TImode annotations that
2645 haifa-sched puts on every insn. Just do scheduling in reorg. */
2646 bfin_flag_schedule_insns2 = flag_schedule_insns_after_reload;
2647 flag_schedule_insns_after_reload = 0;
2649 init_machine_status = bfin_init_machine_status;
2652 /* Return the destination address of BRANCH.
2653 We need to use this instead of get_attr_length, because the
2654 cbranch_with_nops pattern conservatively sets its length to 6, and
2655 we still prefer to use shorter sequences. */
2657 static int
2658 branch_dest (rtx branch)
2660 rtx dest;
2661 int dest_uid;
2662 rtx pat = PATTERN (branch);
2663 if (GET_CODE (pat) == PARALLEL)
2664 pat = XVECEXP (pat, 0, 0);
2665 dest = SET_SRC (pat);
2666 if (GET_CODE (dest) == IF_THEN_ELSE)
2667 dest = XEXP (dest, 1);
2668 dest = XEXP (dest, 0);
2669 dest_uid = INSN_UID (dest);
2670 return INSN_ADDRESSES (dest_uid);
2673 /* Return nonzero if INSN is annotated with a REG_BR_PROB note that indicates
2674 it's a branch that's predicted taken. */
2676 static int
2677 cbranch_predicted_taken_p (rtx insn)
2679 rtx x = find_reg_note (insn, REG_BR_PROB, 0);
2681 if (x)
2683 int pred_val = INTVAL (XEXP (x, 0));
2685 return pred_val >= REG_BR_PROB_BASE / 2;
2688 return 0;
2691 /* Templates for use by asm_conditional_branch. */
2693 static const char *ccbranch_templates[][3] = {
2694 { "if !cc jump %3;", "if cc jump 4 (bp); jump.s %3;", "if cc jump 6 (bp); jump.l %3;" },
2695 { "if cc jump %3;", "if !cc jump 4 (bp); jump.s %3;", "if !cc jump 6 (bp); jump.l %3;" },
2696 { "if !cc jump %3 (bp);", "if cc jump 4; jump.s %3;", "if cc jump 6; jump.l %3;" },
2697 { "if cc jump %3 (bp);", "if !cc jump 4; jump.s %3;", "if !cc jump 6; jump.l %3;" },
2700 /* Output INSN, which is a conditional branch instruction with operands
2701 OPERANDS.
2703 We deal with the various forms of conditional branches that can be generated
2704 by bfin_reorg to prevent the hardware from doing speculative loads, by
2705 - emitting a sufficient number of nops, if N_NOPS is nonzero, or
2706 - always emitting the branch as predicted taken, if PREDICT_TAKEN is true.
2707 Either of these is only necessary if the branch is short, otherwise the
2708 template we use ends in an unconditional jump which flushes the pipeline
2709 anyway. */
2711 void
2712 asm_conditional_branch (rtx insn, rtx *operands, int n_nops, int predict_taken)
2714 int offset = branch_dest (insn) - INSN_ADDRESSES (INSN_UID (insn));
2715 /* Note : offset for instructions like if cc jmp; jump.[sl] offset
2716 is to be taken from start of if cc rather than jump.
2717 Range for jump.s is (-4094, 4096) instead of (-4096, 4094)
2719 int len = (offset >= -1024 && offset <= 1022 ? 0
2720 : offset >= -4094 && offset <= 4096 ? 1
2721 : 2);
2722 int bp = predict_taken && len == 0 ? 1 : cbranch_predicted_taken_p (insn);
2723 int idx = (bp << 1) | (GET_CODE (operands[0]) == EQ ? BRF : BRT);
2724 output_asm_insn (ccbranch_templates[idx][len], operands);
2725 gcc_assert (n_nops == 0 || !bp);
2726 if (len == 0)
2727 while (n_nops-- > 0)
2728 output_asm_insn ("nop;", NULL);
2731 /* Emit rtl for a comparison operation CMP in mode MODE. Operands have been
2732 stored in bfin_compare_op0 and bfin_compare_op1 already. */
2735 bfin_gen_compare (rtx cmp, enum machine_mode mode ATTRIBUTE_UNUSED)
2737 enum rtx_code code1, code2;
2738 rtx op0 = bfin_compare_op0, op1 = bfin_compare_op1;
2739 rtx tem = bfin_cc_rtx;
2740 enum rtx_code code = GET_CODE (cmp);
2742 /* If we have a BImode input, then we already have a compare result, and
2743 do not need to emit another comparison. */
2744 if (GET_MODE (op0) == BImode)
2746 gcc_assert ((code == NE || code == EQ) && op1 == const0_rtx);
2747 tem = op0, code2 = code;
2749 else
2751 switch (code) {
2752 /* bfin has these conditions */
2753 case EQ:
2754 case LT:
2755 case LE:
2756 case LEU:
2757 case LTU:
2758 code1 = code;
2759 code2 = NE;
2760 break;
2761 default:
2762 code1 = reverse_condition (code);
2763 code2 = EQ;
2764 break;
2766 emit_insn (gen_rtx_SET (BImode, tem,
2767 gen_rtx_fmt_ee (code1, BImode, op0, op1)));
2770 return gen_rtx_fmt_ee (code2, BImode, tem, CONST0_RTX (BImode));
2773 /* Return nonzero iff C has exactly one bit set if it is interpreted
2774 as a 32-bit constant. */
2777 log2constp (unsigned HOST_WIDE_INT c)
2779 c &= 0xFFFFFFFF;
2780 return c != 0 && (c & (c-1)) == 0;
2783 /* Returns the number of consecutive least significant zeros in the binary
2784 representation of *V.
2785 We modify *V to contain the original value arithmetically shifted right by
2786 the number of zeroes. */
2788 static int
2789 shiftr_zero (HOST_WIDE_INT *v)
2791 unsigned HOST_WIDE_INT tmp = *v;
2792 unsigned HOST_WIDE_INT sgn;
2793 int n = 0;
2795 if (tmp == 0)
2796 return 0;
2798 sgn = tmp & ((unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1));
2799 while ((tmp & 0x1) == 0 && n <= 32)
2801 tmp = (tmp >> 1) | sgn;
2802 n++;
2804 *v = tmp;
2805 return n;
2808 /* After reload, split the load of an immediate constant. OPERANDS are the
2809 operands of the movsi_insn pattern which we are splitting. We return
2810 nonzero if we emitted a sequence to load the constant, zero if we emitted
2811 nothing because we want to use the splitter's default sequence. */
2814 split_load_immediate (rtx operands[])
2816 HOST_WIDE_INT val = INTVAL (operands[1]);
2817 HOST_WIDE_INT tmp;
2818 HOST_WIDE_INT shifted = val;
2819 HOST_WIDE_INT shifted_compl = ~val;
2820 int num_zero = shiftr_zero (&shifted);
2821 int num_compl_zero = shiftr_zero (&shifted_compl);
2822 unsigned int regno = REGNO (operands[0]);
2824 /* This case takes care of single-bit set/clear constants, which we could
2825 also implement with BITSET/BITCLR. */
2826 if (num_zero
2827 && shifted >= -32768 && shifted < 65536
2828 && (D_REGNO_P (regno)
2829 || (regno >= REG_P0 && regno <= REG_P7 && num_zero <= 2)))
2831 emit_insn (gen_movsi (operands[0], GEN_INT (shifted)));
2832 emit_insn (gen_ashlsi3 (operands[0], operands[0], GEN_INT (num_zero)));
2833 return 1;
2836 tmp = val & 0xFFFF;
2837 tmp |= -(tmp & 0x8000);
2839 /* If high word has one bit set or clear, try to use a bit operation. */
2840 if (D_REGNO_P (regno))
2842 if (log2constp (val & 0xFFFF0000))
2844 emit_insn (gen_movsi (operands[0], GEN_INT (val & 0xFFFF)));
2845 emit_insn (gen_iorsi3 (operands[0], operands[0], GEN_INT (val & 0xFFFF0000)));
2846 return 1;
2848 else if (log2constp (val | 0xFFFF) && (val & 0x8000) != 0)
2850 emit_insn (gen_movsi (operands[0], GEN_INT (tmp)));
2851 emit_insn (gen_andsi3 (operands[0], operands[0], GEN_INT (val | 0xFFFF)));
2855 if (D_REGNO_P (regno))
2857 if (tmp >= -64 && tmp <= 63)
2859 emit_insn (gen_movsi (operands[0], GEN_INT (tmp)));
2860 emit_insn (gen_movstricthi_high (operands[0], GEN_INT (val & -65536)));
2861 return 1;
2864 if ((val & 0xFFFF0000) == 0)
2866 emit_insn (gen_movsi (operands[0], const0_rtx));
2867 emit_insn (gen_movsi_low (operands[0], operands[0], operands[1]));
2868 return 1;
2871 if ((val & 0xFFFF0000) == 0xFFFF0000)
2873 emit_insn (gen_movsi (operands[0], constm1_rtx));
2874 emit_insn (gen_movsi_low (operands[0], operands[0], operands[1]));
2875 return 1;
2879 /* Need DREGs for the remaining case. */
2880 if (regno > REG_R7)
2881 return 0;
2883 if (optimize_size
2884 && num_compl_zero && shifted_compl >= -64 && shifted_compl <= 63)
2886 /* If optimizing for size, generate a sequence that has more instructions
2887 but is shorter. */
2888 emit_insn (gen_movsi (operands[0], GEN_INT (shifted_compl)));
2889 emit_insn (gen_ashlsi3 (operands[0], operands[0],
2890 GEN_INT (num_compl_zero)));
2891 emit_insn (gen_one_cmplsi2 (operands[0], operands[0]));
2892 return 1;
2894 return 0;
2897 /* Return true if the legitimate memory address for a memory operand of mode
2898 MODE. Return false if not. */
2900 static bool
2901 bfin_valid_add (enum machine_mode mode, HOST_WIDE_INT value)
2903 unsigned HOST_WIDE_INT v = value > 0 ? value : -value;
2904 int sz = GET_MODE_SIZE (mode);
2905 int shift = sz == 1 ? 0 : sz == 2 ? 1 : 2;
2906 /* The usual offsettable_memref machinery doesn't work so well for this
2907 port, so we deal with the problem here. */
2908 if (value > 0 && sz == 8)
2909 v += 4;
2910 return (v & ~(0x7fff << shift)) == 0;
2913 static bool
2914 bfin_valid_reg_p (unsigned int regno, int strict, enum machine_mode mode,
2915 enum rtx_code outer_code)
2917 if (strict)
2918 return REGNO_OK_FOR_BASE_STRICT_P (regno, mode, outer_code, SCRATCH);
2919 else
2920 return REGNO_OK_FOR_BASE_NONSTRICT_P (regno, mode, outer_code, SCRATCH);
2923 bool
2924 bfin_legitimate_address_p (enum machine_mode mode, rtx x, int strict)
2926 switch (GET_CODE (x)) {
2927 case REG:
2928 if (bfin_valid_reg_p (REGNO (x), strict, mode, MEM))
2929 return true;
2930 break;
2931 case PLUS:
2932 if (REG_P (XEXP (x, 0))
2933 && bfin_valid_reg_p (REGNO (XEXP (x, 0)), strict, mode, PLUS)
2934 && ((GET_CODE (XEXP (x, 1)) == UNSPEC && mode == SImode)
2935 || (GET_CODE (XEXP (x, 1)) == CONST_INT
2936 && bfin_valid_add (mode, INTVAL (XEXP (x, 1))))))
2937 return true;
2938 break;
2939 case POST_INC:
2940 case POST_DEC:
2941 if (LEGITIMATE_MODE_FOR_AUTOINC_P (mode)
2942 && REG_P (XEXP (x, 0))
2943 && bfin_valid_reg_p (REGNO (XEXP (x, 0)), strict, mode, POST_INC))
2944 return true;
2945 case PRE_DEC:
2946 if (LEGITIMATE_MODE_FOR_AUTOINC_P (mode)
2947 && XEXP (x, 0) == stack_pointer_rtx
2948 && REG_P (XEXP (x, 0))
2949 && bfin_valid_reg_p (REGNO (XEXP (x, 0)), strict, mode, PRE_DEC))
2950 return true;
2951 break;
2952 default:
2953 break;
2955 return false;
2958 /* Decide whether we can force certain constants to memory. If we
2959 decide we can't, the caller should be able to cope with it in
2960 another way. */
2962 static bool
2963 bfin_cannot_force_const_mem (rtx x ATTRIBUTE_UNUSED)
2965 /* We have only one class of non-legitimate constants, and our movsi
2966 expander knows how to handle them. Dropping these constants into the
2967 data section would only shift the problem - we'd still get relocs
2968 outside the object, in the data section rather than the text section. */
2969 return true;
2972 /* Ensure that for any constant of the form symbol + offset, the offset
2973 remains within the object. Any other constants are ok.
2974 This ensures that flat binaries never have to deal with relocations
2975 crossing section boundaries. */
2977 bool
2978 bfin_legitimate_constant_p (rtx x)
2980 rtx sym;
2981 HOST_WIDE_INT offset;
2983 if (GET_CODE (x) != CONST)
2984 return true;
2986 x = XEXP (x, 0);
2987 gcc_assert (GET_CODE (x) == PLUS);
2989 sym = XEXP (x, 0);
2990 x = XEXP (x, 1);
2991 if (GET_CODE (sym) != SYMBOL_REF
2992 || GET_CODE (x) != CONST_INT)
2993 return true;
2994 offset = INTVAL (x);
2996 if (SYMBOL_REF_DECL (sym) == 0)
2997 return true;
2998 if (offset < 0
2999 || offset >= int_size_in_bytes (TREE_TYPE (SYMBOL_REF_DECL (sym))))
3000 return false;
3002 return true;
3005 static bool
3006 bfin_rtx_costs (rtx x, int code, int outer_code, int *total, bool speed)
3008 int cost2 = COSTS_N_INSNS (1);
3009 rtx op0, op1;
3011 switch (code)
3013 case CONST_INT:
3014 if (outer_code == SET || outer_code == PLUS)
3015 *total = satisfies_constraint_Ks7 (x) ? 0 : cost2;
3016 else if (outer_code == AND)
3017 *total = log2constp (~INTVAL (x)) ? 0 : cost2;
3018 else if (outer_code == LE || outer_code == LT || outer_code == EQ)
3019 *total = (INTVAL (x) >= -4 && INTVAL (x) <= 3) ? 0 : cost2;
3020 else if (outer_code == LEU || outer_code == LTU)
3021 *total = (INTVAL (x) >= 0 && INTVAL (x) <= 7) ? 0 : cost2;
3022 else if (outer_code == MULT)
3023 *total = (INTVAL (x) == 2 || INTVAL (x) == 4) ? 0 : cost2;
3024 else if (outer_code == ASHIFT && (INTVAL (x) == 1 || INTVAL (x) == 2))
3025 *total = 0;
3026 else if (outer_code == ASHIFT || outer_code == ASHIFTRT
3027 || outer_code == LSHIFTRT)
3028 *total = (INTVAL (x) >= 0 && INTVAL (x) <= 31) ? 0 : cost2;
3029 else if (outer_code == IOR || outer_code == XOR)
3030 *total = (INTVAL (x) & (INTVAL (x) - 1)) == 0 ? 0 : cost2;
3031 else
3032 *total = cost2;
3033 return true;
3035 case CONST:
3036 case LABEL_REF:
3037 case SYMBOL_REF:
3038 case CONST_DOUBLE:
3039 *total = COSTS_N_INSNS (2);
3040 return true;
3042 case PLUS:
3043 op0 = XEXP (x, 0);
3044 op1 = XEXP (x, 1);
3045 if (GET_MODE (x) == SImode)
3047 if (GET_CODE (op0) == MULT
3048 && GET_CODE (XEXP (op0, 1)) == CONST_INT)
3050 HOST_WIDE_INT val = INTVAL (XEXP (op0, 1));
3051 if (val == 2 || val == 4)
3053 *total = cost2;
3054 *total += rtx_cost (XEXP (op0, 0), outer_code, speed);
3055 *total += rtx_cost (op1, outer_code, speed);
3056 return true;
3059 *total = cost2;
3060 if (GET_CODE (op0) != REG
3061 && (GET_CODE (op0) != SUBREG || GET_CODE (SUBREG_REG (op0)) != REG))
3062 *total += rtx_cost (op0, SET, speed);
3063 #if 0 /* We'd like to do this for accuracy, but it biases the loop optimizer
3064 towards creating too many induction variables. */
3065 if (!reg_or_7bit_operand (op1, SImode))
3066 *total += rtx_cost (op1, SET, speed);
3067 #endif
3069 else if (GET_MODE (x) == DImode)
3071 *total = 6 * cost2;
3072 if (GET_CODE (op1) != CONST_INT
3073 || !satisfies_constraint_Ks7 (op1))
3074 *total += rtx_cost (op1, PLUS, speed);
3075 if (GET_CODE (op0) != REG
3076 && (GET_CODE (op0) != SUBREG || GET_CODE (SUBREG_REG (op0)) != REG))
3077 *total += rtx_cost (op0, PLUS, speed);
3079 return true;
3081 case MINUS:
3082 if (GET_MODE (x) == DImode)
3083 *total = 6 * cost2;
3084 else
3085 *total = cost2;
3086 return true;
3088 case ASHIFT:
3089 case ASHIFTRT:
3090 case LSHIFTRT:
3091 if (GET_MODE (x) == DImode)
3092 *total = 6 * cost2;
3093 else
3094 *total = cost2;
3096 op0 = XEXP (x, 0);
3097 op1 = XEXP (x, 1);
3098 if (GET_CODE (op0) != REG
3099 && (GET_CODE (op0) != SUBREG || GET_CODE (SUBREG_REG (op0)) != REG))
3100 *total += rtx_cost (op0, code, speed);
3102 return true;
3104 case IOR:
3105 case AND:
3106 case XOR:
3107 op0 = XEXP (x, 0);
3108 op1 = XEXP (x, 1);
3110 /* Handle special cases of IOR: rotates, ALIGN insns, movstricthi_high. */
3111 if (code == IOR)
3113 if ((GET_CODE (op0) == LSHIFTRT && GET_CODE (op1) == ASHIFT)
3114 || (GET_CODE (op0) == ASHIFT && GET_CODE (op1) == ZERO_EXTEND)
3115 || (GET_CODE (op0) == ASHIFT && GET_CODE (op1) == LSHIFTRT)
3116 || (GET_CODE (op0) == AND && GET_CODE (op1) == CONST_INT))
3118 *total = cost2;
3119 return true;
3123 if (GET_CODE (op0) != REG
3124 && (GET_CODE (op0) != SUBREG || GET_CODE (SUBREG_REG (op0)) != REG))
3125 *total += rtx_cost (op0, code, speed);
3127 if (GET_MODE (x) == DImode)
3129 *total = 2 * cost2;
3130 return true;
3132 *total = cost2;
3133 if (GET_MODE (x) != SImode)
3134 return true;
3136 if (code == AND)
3138 if (! rhs_andsi3_operand (XEXP (x, 1), SImode))
3139 *total += rtx_cost (XEXP (x, 1), code, speed);
3141 else
3143 if (! regorlog2_operand (XEXP (x, 1), SImode))
3144 *total += rtx_cost (XEXP (x, 1), code, speed);
3147 return true;
3149 case ZERO_EXTRACT:
3150 case SIGN_EXTRACT:
3151 if (outer_code == SET
3152 && XEXP (x, 1) == const1_rtx
3153 && GET_CODE (XEXP (x, 2)) == CONST_INT)
3155 *total = 2 * cost2;
3156 return true;
3158 /* fall through */
3160 case SIGN_EXTEND:
3161 case ZERO_EXTEND:
3162 *total = cost2;
3163 return true;
3165 case MULT:
3167 op0 = XEXP (x, 0);
3168 op1 = XEXP (x, 1);
3169 if (GET_CODE (op0) == GET_CODE (op1)
3170 && (GET_CODE (op0) == ZERO_EXTEND
3171 || GET_CODE (op0) == SIGN_EXTEND))
3173 *total = COSTS_N_INSNS (1);
3174 op0 = XEXP (op0, 0);
3175 op1 = XEXP (op1, 0);
3177 else if (!speed)
3178 *total = COSTS_N_INSNS (1);
3179 else
3180 *total = COSTS_N_INSNS (3);
3182 if (GET_CODE (op0) != REG
3183 && (GET_CODE (op0) != SUBREG || GET_CODE (SUBREG_REG (op0)) != REG))
3184 *total += rtx_cost (op0, MULT, speed);
3185 if (GET_CODE (op1) != REG
3186 && (GET_CODE (op1) != SUBREG || GET_CODE (SUBREG_REG (op1)) != REG))
3187 *total += rtx_cost (op1, MULT, speed);
3189 return true;
3191 case UDIV:
3192 case UMOD:
3193 *total = COSTS_N_INSNS (32);
3194 return true;
3196 case VEC_CONCAT:
3197 case VEC_SELECT:
3198 if (outer_code == SET)
3199 *total = cost2;
3200 return true;
3202 default:
3203 return false;
3207 /* Used for communication between {push,pop}_multiple_operation (which
3208 we use not only as a predicate) and the corresponding output functions. */
3209 static int first_preg_to_save, first_dreg_to_save;
3210 static int n_regs_to_save;
3213 push_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
3215 int lastdreg = 8, lastpreg = 6;
3216 int i, group;
3218 first_preg_to_save = lastpreg;
3219 first_dreg_to_save = lastdreg;
3220 for (i = 1, group = 0; i < XVECLEN (op, 0) - 1; i++)
3222 rtx t = XVECEXP (op, 0, i);
3223 rtx src, dest;
3224 int regno;
3226 if (GET_CODE (t) != SET)
3227 return 0;
3229 src = SET_SRC (t);
3230 dest = SET_DEST (t);
3231 if (GET_CODE (dest) != MEM || ! REG_P (src))
3232 return 0;
3233 dest = XEXP (dest, 0);
3234 if (GET_CODE (dest) != PLUS
3235 || ! REG_P (XEXP (dest, 0))
3236 || REGNO (XEXP (dest, 0)) != REG_SP
3237 || GET_CODE (XEXP (dest, 1)) != CONST_INT
3238 || INTVAL (XEXP (dest, 1)) != -i * 4)
3239 return 0;
3241 regno = REGNO (src);
3242 if (group == 0)
3244 if (D_REGNO_P (regno))
3246 group = 1;
3247 first_dreg_to_save = lastdreg = regno - REG_R0;
3249 else if (regno >= REG_P0 && regno <= REG_P7)
3251 group = 2;
3252 first_preg_to_save = lastpreg = regno - REG_P0;
3254 else
3255 return 0;
3257 continue;
3260 if (group == 1)
3262 if (regno >= REG_P0 && regno <= REG_P7)
3264 group = 2;
3265 first_preg_to_save = lastpreg = regno - REG_P0;
3267 else if (regno != REG_R0 + lastdreg + 1)
3268 return 0;
3269 else
3270 lastdreg++;
3272 else if (group == 2)
3274 if (regno != REG_P0 + lastpreg + 1)
3275 return 0;
3276 lastpreg++;
3279 n_regs_to_save = 8 - first_dreg_to_save + 6 - first_preg_to_save;
3280 return 1;
3284 pop_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
3286 int lastdreg = 8, lastpreg = 6;
3287 int i, group;
3289 for (i = 1, group = 0; i < XVECLEN (op, 0); i++)
3291 rtx t = XVECEXP (op, 0, i);
3292 rtx src, dest;
3293 int regno;
3295 if (GET_CODE (t) != SET)
3296 return 0;
3298 src = SET_SRC (t);
3299 dest = SET_DEST (t);
3300 if (GET_CODE (src) != MEM || ! REG_P (dest))
3301 return 0;
3302 src = XEXP (src, 0);
3304 if (i == 1)
3306 if (! REG_P (src) || REGNO (src) != REG_SP)
3307 return 0;
3309 else if (GET_CODE (src) != PLUS
3310 || ! REG_P (XEXP (src, 0))
3311 || REGNO (XEXP (src, 0)) != REG_SP
3312 || GET_CODE (XEXP (src, 1)) != CONST_INT
3313 || INTVAL (XEXP (src, 1)) != (i - 1) * 4)
3314 return 0;
3316 regno = REGNO (dest);
3317 if (group == 0)
3319 if (regno == REG_R7)
3321 group = 1;
3322 lastdreg = 7;
3324 else if (regno != REG_P0 + lastpreg - 1)
3325 return 0;
3326 else
3327 lastpreg--;
3329 else if (group == 1)
3331 if (regno != REG_R0 + lastdreg - 1)
3332 return 0;
3333 else
3334 lastdreg--;
3337 first_dreg_to_save = lastdreg;
3338 first_preg_to_save = lastpreg;
3339 n_regs_to_save = 8 - first_dreg_to_save + 6 - first_preg_to_save;
3340 return 1;
3343 /* Emit assembly code for one multi-register push described by INSN, with
3344 operands in OPERANDS. */
3346 void
3347 output_push_multiple (rtx insn, rtx *operands)
3349 char buf[80];
3350 int ok;
3352 /* Validate the insn again, and compute first_[dp]reg_to_save. */
3353 ok = push_multiple_operation (PATTERN (insn), VOIDmode);
3354 gcc_assert (ok);
3356 if (first_dreg_to_save == 8)
3357 sprintf (buf, "[--sp] = ( p5:%d );\n", first_preg_to_save);
3358 else if (first_preg_to_save == 6)
3359 sprintf (buf, "[--sp] = ( r7:%d );\n", first_dreg_to_save);
3360 else
3361 sprintf (buf, "[--sp] = ( r7:%d, p5:%d );\n",
3362 first_dreg_to_save, first_preg_to_save);
3364 output_asm_insn (buf, operands);
3367 /* Emit assembly code for one multi-register pop described by INSN, with
3368 operands in OPERANDS. */
3370 void
3371 output_pop_multiple (rtx insn, rtx *operands)
3373 char buf[80];
3374 int ok;
3376 /* Validate the insn again, and compute first_[dp]reg_to_save. */
3377 ok = pop_multiple_operation (PATTERN (insn), VOIDmode);
3378 gcc_assert (ok);
3380 if (first_dreg_to_save == 8)
3381 sprintf (buf, "( p5:%d ) = [sp++];\n", first_preg_to_save);
3382 else if (first_preg_to_save == 6)
3383 sprintf (buf, "( r7:%d ) = [sp++];\n", first_dreg_to_save);
3384 else
3385 sprintf (buf, "( r7:%d, p5:%d ) = [sp++];\n",
3386 first_dreg_to_save, first_preg_to_save);
3388 output_asm_insn (buf, operands);
3391 /* Adjust DST and SRC by OFFSET bytes, and generate one move in mode MODE. */
3393 static void
3394 single_move_for_movmem (rtx dst, rtx src, enum machine_mode mode, HOST_WIDE_INT offset)
3396 rtx scratch = gen_reg_rtx (mode);
3397 rtx srcmem, dstmem;
3399 srcmem = adjust_address_nv (src, mode, offset);
3400 dstmem = adjust_address_nv (dst, mode, offset);
3401 emit_move_insn (scratch, srcmem);
3402 emit_move_insn (dstmem, scratch);
3405 /* Expand a string move operation of COUNT_EXP bytes from SRC to DST, with
3406 alignment ALIGN_EXP. Return true if successful, false if we should fall
3407 back on a different method. */
3409 bool
3410 bfin_expand_movmem (rtx dst, rtx src, rtx count_exp, rtx align_exp)
3412 rtx srcreg, destreg, countreg;
3413 HOST_WIDE_INT align = 0;
3414 unsigned HOST_WIDE_INT count = 0;
3416 if (GET_CODE (align_exp) == CONST_INT)
3417 align = INTVAL (align_exp);
3418 if (GET_CODE (count_exp) == CONST_INT)
3420 count = INTVAL (count_exp);
3421 #if 0
3422 if (!TARGET_INLINE_ALL_STRINGOPS && count > 64)
3423 return false;
3424 #endif
3427 /* If optimizing for size, only do single copies inline. */
3428 if (optimize_size)
3430 if (count == 2 && align < 2)
3431 return false;
3432 if (count == 4 && align < 4)
3433 return false;
3434 if (count != 1 && count != 2 && count != 4)
3435 return false;
3437 if (align < 2 && count != 1)
3438 return false;
3440 destreg = copy_to_mode_reg (Pmode, XEXP (dst, 0));
3441 if (destreg != XEXP (dst, 0))
3442 dst = replace_equiv_address_nv (dst, destreg);
3443 srcreg = copy_to_mode_reg (Pmode, XEXP (src, 0));
3444 if (srcreg != XEXP (src, 0))
3445 src = replace_equiv_address_nv (src, srcreg);
3447 if (count != 0 && align >= 2)
3449 unsigned HOST_WIDE_INT offset = 0;
3451 if (align >= 4)
3453 if ((count & ~3) == 4)
3455 single_move_for_movmem (dst, src, SImode, offset);
3456 offset = 4;
3458 else if (count & ~3)
3460 HOST_WIDE_INT new_count = ((count >> 2) & 0x3fffffff) - 1;
3461 countreg = copy_to_mode_reg (Pmode, GEN_INT (new_count));
3463 emit_insn (gen_rep_movsi (destreg, srcreg, countreg, destreg, srcreg));
3464 cfun->machine->has_loopreg_clobber = true;
3466 if (count & 2)
3468 single_move_for_movmem (dst, src, HImode, offset);
3469 offset += 2;
3472 else
3474 if ((count & ~1) == 2)
3476 single_move_for_movmem (dst, src, HImode, offset);
3477 offset = 2;
3479 else if (count & ~1)
3481 HOST_WIDE_INT new_count = ((count >> 1) & 0x7fffffff) - 1;
3482 countreg = copy_to_mode_reg (Pmode, GEN_INT (new_count));
3484 emit_insn (gen_rep_movhi (destreg, srcreg, countreg, destreg, srcreg));
3485 cfun->machine->has_loopreg_clobber = true;
3488 if (count & 1)
3490 single_move_for_movmem (dst, src, QImode, offset);
3492 return true;
3494 return false;
3497 /* Compute the alignment for a local variable.
3498 TYPE is the data type, and ALIGN is the alignment that
3499 the object would ordinarily have. The value of this macro is used
3500 instead of that alignment to align the object. */
3503 bfin_local_alignment (tree type, int align)
3505 /* Increasing alignment for (relatively) big types allows the builtin
3506 memcpy can use 32 bit loads/stores. */
3507 if (TYPE_SIZE (type)
3508 && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
3509 && (TREE_INT_CST_LOW (TYPE_SIZE (type)) > 8
3510 || TREE_INT_CST_HIGH (TYPE_SIZE (type))) && align < 32)
3511 return 32;
3512 return align;
3515 /* Implement TARGET_SCHED_ISSUE_RATE. */
3517 static int
3518 bfin_issue_rate (void)
3520 return 3;
3523 static int
3524 bfin_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
3526 enum attr_type insn_type, dep_insn_type;
3527 int dep_insn_code_number;
3529 /* Anti and output dependencies have zero cost. */
3530 if (REG_NOTE_KIND (link) != 0)
3531 return 0;
3533 dep_insn_code_number = recog_memoized (dep_insn);
3535 /* If we can't recognize the insns, we can't really do anything. */
3536 if (dep_insn_code_number < 0 || recog_memoized (insn) < 0)
3537 return cost;
3539 insn_type = get_attr_type (insn);
3540 dep_insn_type = get_attr_type (dep_insn);
3542 if (dep_insn_type == TYPE_MOVE || dep_insn_type == TYPE_MCLD)
3544 rtx pat = PATTERN (dep_insn);
3545 if (GET_CODE (pat) == PARALLEL)
3546 pat = XVECEXP (pat, 0, 0);
3547 rtx dest = SET_DEST (pat);
3548 rtx src = SET_SRC (pat);
3549 if (! ADDRESS_REGNO_P (REGNO (dest))
3550 || ! (MEM_P (src) || D_REGNO_P (REGNO (src))))
3551 return cost;
3552 return cost + (dep_insn_type == TYPE_MOVE ? 4 : 3);
3555 return cost;
3558 /* This function acts like NEXT_INSN, but is aware of three-insn bundles and
3559 skips all subsequent parallel instructions if INSN is the start of such
3560 a group. */
3561 static rtx
3562 find_next_insn_start (rtx insn)
3564 if (GET_MODE (insn) == SImode)
3566 while (GET_MODE (insn) != QImode)
3567 insn = NEXT_INSN (insn);
3569 return NEXT_INSN (insn);
3572 /* This function acts like PREV_INSN, but is aware of three-insn bundles and
3573 skips all subsequent parallel instructions if INSN is the start of such
3574 a group. */
3575 static rtx
3576 find_prev_insn_start (rtx insn)
3578 insn = PREV_INSN (insn);
3579 gcc_assert (GET_MODE (insn) != SImode);
3580 if (GET_MODE (insn) == QImode)
3582 while (GET_MODE (PREV_INSN (insn)) == SImode)
3583 insn = PREV_INSN (insn);
3585 return insn;
3588 /* Increment the counter for the number of loop instructions in the
3589 current function. */
3591 void
3592 bfin_hardware_loop (void)
3594 cfun->machine->has_hardware_loops++;
3597 /* Maximum loop nesting depth. */
3598 #define MAX_LOOP_DEPTH 2
3600 /* Maximum size of a loop. */
3601 #define MAX_LOOP_LENGTH 2042
3603 /* Maximum distance of the LSETUP instruction from the loop start. */
3604 #define MAX_LSETUP_DISTANCE 30
3606 /* We need to keep a vector of loops */
3607 typedef struct loop_info *loop_info;
3608 DEF_VEC_P (loop_info);
3609 DEF_VEC_ALLOC_P (loop_info,heap);
3611 /* Information about a loop we have found (or are in the process of
3612 finding). */
3613 struct GTY (()) loop_info
3615 /* loop number, for dumps */
3616 int loop_no;
3618 /* All edges that jump into and out of the loop. */
3619 VEC(edge,gc) *incoming;
3621 /* We can handle two cases: all incoming edges have the same destination
3622 block, or all incoming edges have the same source block. These two
3623 members are set to the common source or destination we found, or NULL
3624 if different blocks were found. If both are NULL the loop can't be
3625 optimized. */
3626 basic_block incoming_src;
3627 basic_block incoming_dest;
3629 /* First block in the loop. This is the one branched to by the loop_end
3630 insn. */
3631 basic_block head;
3633 /* Last block in the loop (the one with the loop_end insn). */
3634 basic_block tail;
3636 /* The successor block of the loop. This is the one the loop_end insn
3637 falls into. */
3638 basic_block successor;
3640 /* The last instruction in the tail. */
3641 rtx last_insn;
3643 /* The loop_end insn. */
3644 rtx loop_end;
3646 /* The iteration register. */
3647 rtx iter_reg;
3649 /* The new initialization insn. */
3650 rtx init;
3652 /* The new initialization instruction. */
3653 rtx loop_init;
3655 /* The new label placed at the beginning of the loop. */
3656 rtx start_label;
3658 /* The new label placed at the end of the loop. */
3659 rtx end_label;
3661 /* The length of the loop. */
3662 int length;
3664 /* The nesting depth of the loop. */
3665 int depth;
3667 /* Nonzero if we can't optimize this loop. */
3668 int bad;
3670 /* True if we have visited this loop. */
3671 int visited;
3673 /* True if this loop body clobbers any of LC0, LT0, or LB0. */
3674 int clobber_loop0;
3676 /* True if this loop body clobbers any of LC1, LT1, or LB1. */
3677 int clobber_loop1;
3679 /* Next loop in the graph. */
3680 struct loop_info *next;
3682 /* Immediate outer loop of this loop. */
3683 struct loop_info *outer;
3685 /* Vector of blocks only within the loop, including those within
3686 inner loops. */
3687 VEC (basic_block,heap) *blocks;
3689 /* Same information in a bitmap. */
3690 bitmap block_bitmap;
3692 /* Vector of inner loops within this loop */
3693 VEC (loop_info,heap) *loops;
3696 static void
3697 bfin_dump_loops (loop_info loops)
3699 loop_info loop;
3701 for (loop = loops; loop; loop = loop->next)
3703 loop_info i;
3704 basic_block b;
3705 unsigned ix;
3707 fprintf (dump_file, ";; loop %d: ", loop->loop_no);
3708 if (loop->bad)
3709 fprintf (dump_file, "(bad) ");
3710 fprintf (dump_file, "{head:%d, depth:%d}", loop->head->index, loop->depth);
3712 fprintf (dump_file, " blocks: [ ");
3713 for (ix = 0; VEC_iterate (basic_block, loop->blocks, ix, b); ix++)
3714 fprintf (dump_file, "%d ", b->index);
3715 fprintf (dump_file, "] ");
3717 fprintf (dump_file, " inner loops: [ ");
3718 for (ix = 0; VEC_iterate (loop_info, loop->loops, ix, i); ix++)
3719 fprintf (dump_file, "%d ", i->loop_no);
3720 fprintf (dump_file, "]\n");
3722 fprintf (dump_file, "\n");
3725 /* Scan the blocks of LOOP (and its inferiors) looking for basic block
3726 BB. Return true, if we find it. */
3728 static bool
3729 bfin_bb_in_loop (loop_info loop, basic_block bb)
3731 return bitmap_bit_p (loop->block_bitmap, bb->index);
3734 /* Scan the blocks of LOOP (and its inferiors) looking for uses of
3735 REG. Return true, if we find any. Don't count the loop's loop_end
3736 insn if it matches LOOP_END. */
3738 static bool
3739 bfin_scan_loop (loop_info loop, rtx reg, rtx loop_end)
3741 unsigned ix;
3742 basic_block bb;
3744 for (ix = 0; VEC_iterate (basic_block, loop->blocks, ix, bb); ix++)
3746 rtx insn;
3748 for (insn = BB_HEAD (bb);
3749 insn != NEXT_INSN (BB_END (bb));
3750 insn = NEXT_INSN (insn))
3752 if (!INSN_P (insn))
3753 continue;
3754 if (insn == loop_end)
3755 continue;
3756 if (reg_mentioned_p (reg, PATTERN (insn)))
3757 return true;
3760 return false;
3763 /* Estimate the length of INSN conservatively. */
3765 static int
3766 length_for_loop (rtx insn)
3768 int length = 0;
3769 if (JUMP_P (insn) && any_condjump_p (insn) && !optimize_size)
3771 if (ENABLE_WA_SPECULATIVE_SYNCS)
3772 length = 8;
3773 else if (ENABLE_WA_SPECULATIVE_LOADS)
3774 length = 6;
3776 else if (LABEL_P (insn))
3778 if (ENABLE_WA_SPECULATIVE_SYNCS)
3779 length = 4;
3782 if (INSN_P (insn))
3783 length += get_attr_length (insn);
3785 return length;
3788 /* Optimize LOOP. */
3790 static void
3791 bfin_optimize_loop (loop_info loop)
3793 basic_block bb;
3794 loop_info inner;
3795 rtx insn, init_insn, last_insn, nop_insn;
3796 rtx loop_init, start_label, end_label;
3797 rtx reg_lc0, reg_lc1, reg_lt0, reg_lt1, reg_lb0, reg_lb1;
3798 rtx iter_reg;
3799 rtx lc_reg, lt_reg, lb_reg;
3800 rtx seq, seq_end;
3801 int length;
3802 unsigned ix;
3803 int inner_depth = 0;
3805 if (loop->visited)
3806 return;
3808 loop->visited = 1;
3810 if (loop->bad)
3812 if (dump_file)
3813 fprintf (dump_file, ";; loop %d bad when found\n", loop->loop_no);
3814 goto bad_loop;
3817 /* Every loop contains in its list of inner loops every loop nested inside
3818 it, even if there are intermediate loops. This works because we're doing
3819 a depth-first search here and never visit a loop more than once. */
3820 for (ix = 0; VEC_iterate (loop_info, loop->loops, ix, inner); ix++)
3822 bfin_optimize_loop (inner);
3824 if (!inner->bad && inner_depth < inner->depth)
3826 inner_depth = inner->depth;
3828 loop->clobber_loop0 |= inner->clobber_loop0;
3829 loop->clobber_loop1 |= inner->clobber_loop1;
3833 loop->depth = inner_depth + 1;
3834 if (loop->depth > MAX_LOOP_DEPTH)
3836 if (dump_file)
3837 fprintf (dump_file, ";; loop %d too deep\n", loop->loop_no);
3838 goto bad_loop;
3841 /* Get the loop iteration register. */
3842 iter_reg = loop->iter_reg;
3844 if (!DPREG_P (iter_reg))
3846 if (dump_file)
3847 fprintf (dump_file, ";; loop %d iteration count NOT in PREG or DREG\n",
3848 loop->loop_no);
3849 goto bad_loop;
3852 if (loop->incoming_src)
3854 /* Make sure the predecessor is before the loop start label, as required by
3855 the LSETUP instruction. */
3856 length = 0;
3857 insn = BB_END (loop->incoming_src);
3858 /* If we have to insert the LSETUP before a jump, count that jump in the
3859 length. */
3860 if (VEC_length (edge, loop->incoming) > 1
3861 || !(VEC_last (edge, loop->incoming)->flags & EDGE_FALLTHRU))
3863 gcc_assert (JUMP_P (insn));
3864 insn = PREV_INSN (insn);
3867 for (; insn && insn != loop->start_label; insn = NEXT_INSN (insn))
3868 length += length_for_loop (insn);
3870 if (!insn)
3872 if (dump_file)
3873 fprintf (dump_file, ";; loop %d lsetup not before loop_start\n",
3874 loop->loop_no);
3875 goto bad_loop;
3878 if (length > MAX_LSETUP_DISTANCE)
3880 if (dump_file)
3881 fprintf (dump_file, ";; loop %d lsetup too far away\n", loop->loop_no);
3882 goto bad_loop;
3886 /* Check if start_label appears before loop_end and calculate the
3887 offset between them. We calculate the length of instructions
3888 conservatively. */
3889 length = 0;
3890 for (insn = loop->start_label;
3891 insn && insn != loop->loop_end;
3892 insn = NEXT_INSN (insn))
3893 length += length_for_loop (insn);
3895 if (!insn)
3897 if (dump_file)
3898 fprintf (dump_file, ";; loop %d start_label not before loop_end\n",
3899 loop->loop_no);
3900 goto bad_loop;
3903 loop->length = length;
3904 if (loop->length > MAX_LOOP_LENGTH)
3906 if (dump_file)
3907 fprintf (dump_file, ";; loop %d too long\n", loop->loop_no);
3908 goto bad_loop;
3911 /* Scan all the blocks to make sure they don't use iter_reg. */
3912 if (bfin_scan_loop (loop, iter_reg, loop->loop_end))
3914 if (dump_file)
3915 fprintf (dump_file, ";; loop %d uses iterator\n", loop->loop_no);
3916 goto bad_loop;
3919 /* Scan all the insns to see if the loop body clobber
3920 any hardware loop registers. */
3922 reg_lc0 = gen_rtx_REG (SImode, REG_LC0);
3923 reg_lc1 = gen_rtx_REG (SImode, REG_LC1);
3924 reg_lt0 = gen_rtx_REG (SImode, REG_LT0);
3925 reg_lt1 = gen_rtx_REG (SImode, REG_LT1);
3926 reg_lb0 = gen_rtx_REG (SImode, REG_LB0);
3927 reg_lb1 = gen_rtx_REG (SImode, REG_LB1);
3929 for (ix = 0; VEC_iterate (basic_block, loop->blocks, ix, bb); ix++)
3931 rtx insn;
3933 for (insn = BB_HEAD (bb);
3934 insn != NEXT_INSN (BB_END (bb));
3935 insn = NEXT_INSN (insn))
3937 if (!INSN_P (insn))
3938 continue;
3940 if (reg_set_p (reg_lc0, insn)
3941 || reg_set_p (reg_lt0, insn)
3942 || reg_set_p (reg_lb0, insn))
3943 loop->clobber_loop0 = 1;
3945 if (reg_set_p (reg_lc1, insn)
3946 || reg_set_p (reg_lt1, insn)
3947 || reg_set_p (reg_lb1, insn))
3948 loop->clobber_loop1 |= 1;
3952 if ((loop->clobber_loop0 && loop->clobber_loop1)
3953 || (loop->depth == MAX_LOOP_DEPTH && loop->clobber_loop0))
3955 loop->depth = MAX_LOOP_DEPTH + 1;
3956 if (dump_file)
3957 fprintf (dump_file, ";; loop %d no loop reg available\n",
3958 loop->loop_no);
3959 goto bad_loop;
3962 /* There should be an instruction before the loop_end instruction
3963 in the same basic block. And the instruction must not be
3964 - JUMP
3965 - CONDITIONAL BRANCH
3966 - CALL
3967 - CSYNC
3968 - SSYNC
3969 - Returns (RTS, RTN, etc.) */
3971 bb = loop->tail;
3972 last_insn = find_prev_insn_start (loop->loop_end);
3974 while (1)
3976 for (; last_insn != BB_HEAD (bb);
3977 last_insn = find_prev_insn_start (last_insn))
3978 if (INSN_P (last_insn))
3979 break;
3981 if (last_insn != BB_HEAD (bb))
3982 break;
3984 if (single_pred_p (bb)
3985 && single_pred (bb) != ENTRY_BLOCK_PTR)
3987 bb = single_pred (bb);
3988 last_insn = BB_END (bb);
3989 continue;
3991 else
3993 last_insn = NULL_RTX;
3994 break;
3998 if (!last_insn)
4000 if (dump_file)
4001 fprintf (dump_file, ";; loop %d has no last instruction\n",
4002 loop->loop_no);
4003 goto bad_loop;
4006 if (JUMP_P (last_insn))
4008 loop_info inner = (loop_info) bb->aux;
4009 if (inner
4010 && inner->outer == loop
4011 && inner->loop_end == last_insn
4012 && inner->depth == 1)
4013 /* This jump_insn is the exact loop_end of an inner loop
4014 and to be optimized away. So use the inner's last_insn. */
4015 last_insn = inner->last_insn;
4016 else
4018 if (dump_file)
4019 fprintf (dump_file, ";; loop %d has bad last instruction\n",
4020 loop->loop_no);
4021 goto bad_loop;
4024 else if (CALL_P (last_insn)
4025 || (GET_CODE (PATTERN (last_insn)) != SEQUENCE
4026 && get_attr_type (last_insn) == TYPE_SYNC)
4027 || recog_memoized (last_insn) == CODE_FOR_return_internal)
4029 if (dump_file)
4030 fprintf (dump_file, ";; loop %d has bad last instruction\n",
4031 loop->loop_no);
4032 goto bad_loop;
4035 if (GET_CODE (PATTERN (last_insn)) == ASM_INPUT
4036 || asm_noperands (PATTERN (last_insn)) >= 0
4037 || (GET_CODE (PATTERN (last_insn)) != SEQUENCE
4038 && get_attr_seq_insns (last_insn) == SEQ_INSNS_MULTI))
4040 nop_insn = emit_insn_after (gen_nop (), last_insn);
4041 last_insn = nop_insn;
4044 loop->last_insn = last_insn;
4046 /* The loop is good for replacement. */
4047 start_label = loop->start_label;
4048 end_label = gen_label_rtx ();
4049 iter_reg = loop->iter_reg;
4051 if (loop->depth == 1 && !loop->clobber_loop1)
4053 lc_reg = reg_lc1;
4054 lt_reg = reg_lt1;
4055 lb_reg = reg_lb1;
4056 loop->clobber_loop1 = 1;
4058 else
4060 lc_reg = reg_lc0;
4061 lt_reg = reg_lt0;
4062 lb_reg = reg_lb0;
4063 loop->clobber_loop0 = 1;
4066 /* If iter_reg is a DREG, we need generate an instruction to load
4067 the loop count into LC register. */
4068 if (D_REGNO_P (REGNO (iter_reg)))
4070 init_insn = gen_movsi (lc_reg, iter_reg);
4071 loop_init = gen_lsetup_without_autoinit (lt_reg, start_label,
4072 lb_reg, end_label,
4073 lc_reg);
4075 else if (P_REGNO_P (REGNO (iter_reg)))
4077 init_insn = NULL_RTX;
4078 loop_init = gen_lsetup_with_autoinit (lt_reg, start_label,
4079 lb_reg, end_label,
4080 lc_reg, iter_reg);
4082 else
4083 gcc_unreachable ();
4085 loop->init = init_insn;
4086 loop->end_label = end_label;
4087 loop->loop_init = loop_init;
4089 if (dump_file)
4091 fprintf (dump_file, ";; replacing loop %d initializer with\n",
4092 loop->loop_no);
4093 print_rtl_single (dump_file, loop->loop_init);
4094 fprintf (dump_file, ";; replacing loop %d terminator with\n",
4095 loop->loop_no);
4096 print_rtl_single (dump_file, loop->loop_end);
4099 /* Create a sequence containing the loop setup. */
4100 start_sequence ();
4102 if (loop->init != NULL_RTX)
4103 emit_insn (loop->init);
4104 seq_end = emit_insn (loop->loop_init);
4106 /* If the loop isn't entered at the top, also create a jump to the entry
4107 point. */
4108 if (!loop->incoming_src && loop->head != loop->incoming_dest)
4110 rtx label = BB_HEAD (loop->incoming_dest);
4111 /* If we're jumping to the final basic block in the loop, and there's
4112 only one cheap instruction before the end (typically an increment of
4113 an induction variable), we can just emit a copy here instead of a
4114 jump. */
4115 if (loop->incoming_dest == loop->tail
4116 && next_real_insn (label) == last_insn
4117 && asm_noperands (last_insn) < 0
4118 && GET_CODE (PATTERN (last_insn)) == SET)
4120 seq_end = emit_insn (copy_rtx (PATTERN (last_insn)));
4122 else
4123 seq_end = emit_insn (gen_jump (label));
4126 seq = get_insns ();
4127 end_sequence ();
4129 if (loop->incoming_src)
4131 rtx prev = BB_END (loop->incoming_src);
4132 if (VEC_length (edge, loop->incoming) > 1
4133 || !(VEC_last (edge, loop->incoming)->flags & EDGE_FALLTHRU))
4135 gcc_assert (JUMP_P (prev));
4136 prev = PREV_INSN (prev);
4138 emit_insn_after (seq, prev);
4140 else
4142 basic_block new_bb;
4143 edge e;
4144 edge_iterator ei;
4146 #ifdef ENABLE_CHECKING
4147 if (loop->head != loop->incoming_dest)
4149 /* We aren't entering the loop at the top. Since we've established
4150 that the loop is entered only at one point, this means there
4151 can't be fallthru edges into the head. Any such fallthru edges
4152 would become invalid when we insert the new block, so verify
4153 that this does not in fact happen. */
4154 FOR_EACH_EDGE (e, ei, loop->head->preds)
4155 gcc_assert (!(e->flags & EDGE_FALLTHRU));
4157 #endif
4159 emit_insn_before (seq, BB_HEAD (loop->head));
4160 seq = emit_label_before (gen_label_rtx (), seq);
4162 new_bb = create_basic_block (seq, seq_end, loop->head->prev_bb);
4163 FOR_EACH_EDGE (e, ei, loop->incoming)
4165 if (!(e->flags & EDGE_FALLTHRU)
4166 || e->dest != loop->head)
4167 redirect_edge_and_branch_force (e, new_bb);
4168 else
4169 redirect_edge_succ (e, new_bb);
4173 delete_insn (loop->loop_end);
4174 /* Insert the loop end label before the last instruction of the loop. */
4175 emit_label_before (loop->end_label, loop->last_insn);
4177 return;
4179 bad_loop:
4181 if (dump_file)
4182 fprintf (dump_file, ";; loop %d is bad\n", loop->loop_no);
4184 loop->bad = 1;
4186 if (DPREG_P (loop->iter_reg))
4188 /* If loop->iter_reg is a DREG or PREG, we can split it here
4189 without scratch register. */
4190 rtx insn;
4192 emit_insn_before (gen_addsi3 (loop->iter_reg,
4193 loop->iter_reg,
4194 constm1_rtx),
4195 loop->loop_end);
4197 emit_insn_before (gen_cmpsi (loop->iter_reg, const0_rtx),
4198 loop->loop_end);
4200 insn = emit_jump_insn_before (gen_bne (loop->start_label),
4201 loop->loop_end);
4203 JUMP_LABEL (insn) = loop->start_label;
4204 LABEL_NUSES (loop->start_label)++;
4205 delete_insn (loop->loop_end);
4209 /* Called from bfin_reorg_loops when a potential loop end is found. LOOP is
4210 a newly set up structure describing the loop, it is this function's
4211 responsibility to fill most of it. TAIL_BB and TAIL_INSN point to the
4212 loop_end insn and its enclosing basic block. */
4214 static void
4215 bfin_discover_loop (loop_info loop, basic_block tail_bb, rtx tail_insn)
4217 unsigned dwork = 0;
4218 basic_block bb;
4219 VEC (basic_block,heap) *works = VEC_alloc (basic_block,heap,20);
4221 loop->tail = tail_bb;
4222 loop->head = BRANCH_EDGE (tail_bb)->dest;
4223 loop->successor = FALLTHRU_EDGE (tail_bb)->dest;
4224 loop->loop_end = tail_insn;
4225 loop->last_insn = NULL_RTX;
4226 loop->iter_reg = SET_DEST (XVECEXP (PATTERN (tail_insn), 0, 1));
4227 loop->depth = loop->length = 0;
4228 loop->visited = 0;
4229 loop->clobber_loop0 = loop->clobber_loop1 = 0;
4230 loop->outer = NULL;
4231 loop->loops = NULL;
4232 loop->incoming = VEC_alloc (edge, gc, 2);
4233 loop->init = loop->loop_init = NULL_RTX;
4234 loop->start_label = XEXP (XEXP (SET_SRC (XVECEXP (PATTERN (tail_insn), 0, 0)), 1), 0);
4235 loop->end_label = NULL_RTX;
4236 loop->bad = 0;
4238 VEC_safe_push (basic_block, heap, works, loop->head);
4240 while (VEC_iterate (basic_block, works, dwork++, bb))
4242 edge e;
4243 edge_iterator ei;
4244 if (bb == EXIT_BLOCK_PTR)
4246 /* We've reached the exit block. The loop must be bad. */
4247 if (dump_file)
4248 fprintf (dump_file,
4249 ";; Loop is bad - reached exit block while scanning\n");
4250 loop->bad = 1;
4251 break;
4254 if (bitmap_bit_p (loop->block_bitmap, bb->index))
4255 continue;
4257 /* We've not seen this block before. Add it to the loop's
4258 list and then add each successor to the work list. */
4260 VEC_safe_push (basic_block, heap, loop->blocks, bb);
4261 bitmap_set_bit (loop->block_bitmap, bb->index);
4263 if (bb != tail_bb)
4265 FOR_EACH_EDGE (e, ei, bb->succs)
4267 basic_block succ = EDGE_SUCC (bb, ei.index)->dest;
4268 if (!REGNO_REG_SET_P (df_get_live_in (succ),
4269 REGNO (loop->iter_reg)))
4270 continue;
4271 if (!VEC_space (basic_block, works, 1))
4273 if (dwork)
4275 VEC_block_remove (basic_block, works, 0, dwork);
4276 dwork = 0;
4278 else
4279 VEC_reserve (basic_block, heap, works, 1);
4281 VEC_quick_push (basic_block, works, succ);
4286 /* Find the predecessor, and make sure nothing else jumps into this loop. */
4287 if (!loop->bad)
4289 int pass, retry;
4290 for (dwork = 0; VEC_iterate (basic_block, loop->blocks, dwork, bb); dwork++)
4292 edge e;
4293 edge_iterator ei;
4294 FOR_EACH_EDGE (e, ei, bb->preds)
4296 basic_block pred = e->src;
4298 if (!bfin_bb_in_loop (loop, pred))
4300 if (dump_file)
4301 fprintf (dump_file, ";; Loop %d: incoming edge %d -> %d\n",
4302 loop->loop_no, pred->index,
4303 e->dest->index);
4304 VEC_safe_push (edge, gc, loop->incoming, e);
4309 for (pass = 0, retry = 1; retry && pass < 2; pass++)
4311 edge e;
4312 edge_iterator ei;
4313 bool first = true;
4314 retry = 0;
4316 FOR_EACH_EDGE (e, ei, loop->incoming)
4318 if (first)
4320 loop->incoming_src = e->src;
4321 loop->incoming_dest = e->dest;
4322 first = false;
4324 else
4326 if (e->dest != loop->incoming_dest)
4327 loop->incoming_dest = NULL;
4328 if (e->src != loop->incoming_src)
4329 loop->incoming_src = NULL;
4331 if (loop->incoming_src == NULL && loop->incoming_dest == NULL)
4333 if (pass == 0)
4335 if (dump_file)
4336 fprintf (dump_file,
4337 ";; retrying loop %d with forwarder blocks\n",
4338 loop->loop_no);
4339 retry = 1;
4340 break;
4342 loop->bad = 1;
4343 if (dump_file)
4344 fprintf (dump_file,
4345 ";; can't find suitable entry for loop %d\n",
4346 loop->loop_no);
4347 goto out;
4350 if (retry)
4352 retry = 0;
4353 FOR_EACH_EDGE (e, ei, loop->incoming)
4355 if (forwarder_block_p (e->src))
4357 edge e2;
4358 edge_iterator ei2;
4360 if (dump_file)
4361 fprintf (dump_file,
4362 ";; Adding forwarder block %d to loop %d and retrying\n",
4363 e->src->index, loop->loop_no);
4364 VEC_safe_push (basic_block, heap, loop->blocks, e->src);
4365 bitmap_set_bit (loop->block_bitmap, e->src->index);
4366 FOR_EACH_EDGE (e2, ei2, e->src->preds)
4367 VEC_safe_push (edge, gc, loop->incoming, e2);
4368 VEC_unordered_remove (edge, loop->incoming, ei.index);
4369 retry = 1;
4370 break;
4373 if (!retry)
4375 if (dump_file)
4376 fprintf (dump_file, ";; No forwarder blocks found\n");
4377 loop->bad = 1;
4383 out:
4384 VEC_free (basic_block, heap, works);
4387 /* Analyze the structure of the loops in the current function. Use STACK
4388 for bitmap allocations. Returns all the valid candidates for hardware
4389 loops found in this function. */
4390 static loop_info
4391 bfin_discover_loops (bitmap_obstack *stack, FILE *dump_file)
4393 loop_info loops = NULL;
4394 loop_info loop;
4395 basic_block bb;
4396 bitmap tmp_bitmap;
4397 int nloops = 0;
4399 /* Find all the possible loop tails. This means searching for every
4400 loop_end instruction. For each one found, create a loop_info
4401 structure and add the head block to the work list. */
4402 FOR_EACH_BB (bb)
4404 rtx tail = BB_END (bb);
4406 while (GET_CODE (tail) == NOTE)
4407 tail = PREV_INSN (tail);
4409 bb->aux = NULL;
4411 if (INSN_P (tail) && recog_memoized (tail) == CODE_FOR_loop_end)
4413 rtx insn;
4414 /* A possible loop end */
4416 /* There's a degenerate case we can handle - an empty loop consisting
4417 of only a back branch. Handle that by deleting the branch. */
4418 insn = BB_HEAD (BRANCH_EDGE (bb)->dest);
4419 if (next_real_insn (insn) == tail)
4421 if (dump_file)
4423 fprintf (dump_file, ";; degenerate loop ending at\n");
4424 print_rtl_single (dump_file, tail);
4426 delete_insn_and_edges (tail);
4427 continue;
4430 loop = XNEW (struct loop_info);
4431 loop->next = loops;
4432 loops = loop;
4433 loop->loop_no = nloops++;
4434 loop->blocks = VEC_alloc (basic_block, heap, 20);
4435 loop->block_bitmap = BITMAP_ALLOC (stack);
4436 bb->aux = loop;
4438 if (dump_file)
4440 fprintf (dump_file, ";; potential loop %d ending at\n",
4441 loop->loop_no);
4442 print_rtl_single (dump_file, tail);
4445 bfin_discover_loop (loop, bb, tail);
4449 tmp_bitmap = BITMAP_ALLOC (stack);
4450 /* Compute loop nestings. */
4451 for (loop = loops; loop; loop = loop->next)
4453 loop_info other;
4454 if (loop->bad)
4455 continue;
4457 for (other = loop->next; other; other = other->next)
4459 if (other->bad)
4460 continue;
4462 bitmap_and (tmp_bitmap, other->block_bitmap, loop->block_bitmap);
4463 if (bitmap_empty_p (tmp_bitmap))
4464 continue;
4465 if (bitmap_equal_p (tmp_bitmap, other->block_bitmap))
4467 other->outer = loop;
4468 VEC_safe_push (loop_info, heap, loop->loops, other);
4470 else if (bitmap_equal_p (tmp_bitmap, loop->block_bitmap))
4472 loop->outer = other;
4473 VEC_safe_push (loop_info, heap, other->loops, loop);
4475 else
4477 if (dump_file)
4478 fprintf (dump_file,
4479 ";; can't find suitable nesting for loops %d and %d\n",
4480 loop->loop_no, other->loop_no);
4481 loop->bad = other->bad = 1;
4485 BITMAP_FREE (tmp_bitmap);
4487 return loops;
4490 /* Free up the loop structures in LOOPS. */
4491 static void
4492 free_loops (loop_info loops)
4494 while (loops)
4496 loop_info loop = loops;
4497 loops = loop->next;
4498 VEC_free (loop_info, heap, loop->loops);
4499 VEC_free (basic_block, heap, loop->blocks);
4500 BITMAP_FREE (loop->block_bitmap);
4501 XDELETE (loop);
4505 #define BB_AUX_INDEX(BB) ((unsigned)(BB)->aux)
4507 /* The taken-branch edge from the loop end can actually go forward. Since the
4508 Blackfin's LSETUP instruction requires that the loop end be after the loop
4509 start, try to reorder a loop's basic blocks when we find such a case. */
4510 static void
4511 bfin_reorder_loops (loop_info loops, FILE *dump_file)
4513 basic_block bb;
4514 loop_info loop;
4516 FOR_EACH_BB (bb)
4517 bb->aux = NULL;
4518 cfg_layout_initialize (0);
4520 for (loop = loops; loop; loop = loop->next)
4522 unsigned index;
4523 basic_block bb;
4524 edge e;
4525 edge_iterator ei;
4527 if (loop->bad)
4528 continue;
4530 /* Recreate an index for basic blocks that represents their order. */
4531 for (bb = ENTRY_BLOCK_PTR->next_bb, index = 0;
4532 bb != EXIT_BLOCK_PTR;
4533 bb = bb->next_bb, index++)
4534 bb->aux = (PTR) index;
4536 if (BB_AUX_INDEX (loop->head) < BB_AUX_INDEX (loop->tail))
4537 continue;
4539 FOR_EACH_EDGE (e, ei, loop->head->succs)
4541 if (bitmap_bit_p (loop->block_bitmap, e->dest->index)
4542 && BB_AUX_INDEX (e->dest) < BB_AUX_INDEX (loop->tail))
4544 basic_block start_bb = e->dest;
4545 basic_block start_prev_bb = start_bb->prev_bb;
4547 if (dump_file)
4548 fprintf (dump_file, ";; Moving block %d before block %d\n",
4549 loop->head->index, start_bb->index);
4550 loop->head->prev_bb->next_bb = loop->head->next_bb;
4551 loop->head->next_bb->prev_bb = loop->head->prev_bb;
4553 loop->head->prev_bb = start_prev_bb;
4554 loop->head->next_bb = start_bb;
4555 start_prev_bb->next_bb = start_bb->prev_bb = loop->head;
4556 break;
4559 loops = loops->next;
4562 FOR_EACH_BB (bb)
4564 if (bb->next_bb != EXIT_BLOCK_PTR)
4565 bb->aux = bb->next_bb;
4566 else
4567 bb->aux = NULL;
4569 cfg_layout_finalize ();
4570 df_analyze ();
4573 /* Run from machine_dependent_reorg, this pass looks for doloop_end insns
4574 and tries to rewrite the RTL of these loops so that proper Blackfin
4575 hardware loops are generated. */
4577 static void
4578 bfin_reorg_loops (FILE *dump_file)
4580 loop_info loops = NULL;
4581 loop_info loop;
4582 basic_block bb;
4583 bitmap_obstack stack;
4585 bitmap_obstack_initialize (&stack);
4587 if (dump_file)
4588 fprintf (dump_file, ";; Find loops, first pass\n\n");
4590 loops = bfin_discover_loops (&stack, dump_file);
4592 if (dump_file)
4593 bfin_dump_loops (loops);
4595 bfin_reorder_loops (loops, dump_file);
4596 free_loops (loops);
4598 if (dump_file)
4599 fprintf (dump_file, ";; Find loops, second pass\n\n");
4601 loops = bfin_discover_loops (&stack, dump_file);
4602 if (dump_file)
4604 fprintf (dump_file, ";; All loops found:\n\n");
4605 bfin_dump_loops (loops);
4608 /* Now apply the optimizations. */
4609 for (loop = loops; loop; loop = loop->next)
4610 bfin_optimize_loop (loop);
4612 if (dump_file)
4614 fprintf (dump_file, ";; After hardware loops optimization:\n\n");
4615 bfin_dump_loops (loops);
4618 free_loops (loops);
4620 if (dump_file)
4621 print_rtl (dump_file, get_insns ());
4623 FOR_EACH_BB (bb)
4624 bb->aux = NULL;
4627 /* Possibly generate a SEQUENCE out of three insns found in SLOT.
4628 Returns true if we modified the insn chain, false otherwise. */
4629 static bool
4630 gen_one_bundle (rtx slot[3])
4632 gcc_assert (slot[1] != NULL_RTX);
4634 /* Don't add extra NOPs if optimizing for size. */
4635 if (optimize_size
4636 && (slot[0] == NULL_RTX || slot[2] == NULL_RTX))
4637 return false;
4639 /* Verify that we really can do the multi-issue. */
4640 if (slot[0])
4642 rtx t = NEXT_INSN (slot[0]);
4643 while (t != slot[1])
4645 if (GET_CODE (t) != NOTE
4646 || NOTE_KIND (t) != NOTE_INSN_DELETED)
4647 return false;
4648 t = NEXT_INSN (t);
4651 if (slot[2])
4653 rtx t = NEXT_INSN (slot[1]);
4654 while (t != slot[2])
4656 if (GET_CODE (t) != NOTE
4657 || NOTE_KIND (t) != NOTE_INSN_DELETED)
4658 return false;
4659 t = NEXT_INSN (t);
4663 if (slot[0] == NULL_RTX)
4665 slot[0] = emit_insn_before (gen_mnop (), slot[1]);
4666 df_insn_rescan (slot[0]);
4668 if (slot[2] == NULL_RTX)
4670 slot[2] = emit_insn_after (gen_forced_nop (), slot[1]);
4671 df_insn_rescan (slot[2]);
4674 /* Avoid line number information being printed inside one bundle. */
4675 if (INSN_LOCATOR (slot[1])
4676 && INSN_LOCATOR (slot[1]) != INSN_LOCATOR (slot[0]))
4677 INSN_LOCATOR (slot[1]) = INSN_LOCATOR (slot[0]);
4678 if (INSN_LOCATOR (slot[2])
4679 && INSN_LOCATOR (slot[2]) != INSN_LOCATOR (slot[0]))
4680 INSN_LOCATOR (slot[2]) = INSN_LOCATOR (slot[0]);
4682 /* Terminate them with "|| " instead of ";" in the output. */
4683 PUT_MODE (slot[0], SImode);
4684 PUT_MODE (slot[1], SImode);
4685 /* Terminate the bundle, for the benefit of reorder_var_tracking_notes. */
4686 PUT_MODE (slot[2], QImode);
4687 return true;
4690 /* Go through all insns, and use the information generated during scheduling
4691 to generate SEQUENCEs to represent bundles of instructions issued
4692 simultaneously. */
4694 static void
4695 bfin_gen_bundles (void)
4697 basic_block bb;
4698 FOR_EACH_BB (bb)
4700 rtx insn, next;
4701 rtx slot[3];
4702 int n_filled = 0;
4704 slot[0] = slot[1] = slot[2] = NULL_RTX;
4705 for (insn = BB_HEAD (bb);; insn = next)
4707 int at_end;
4708 if (INSN_P (insn))
4710 if (get_attr_type (insn) == TYPE_DSP32)
4711 slot[0] = insn;
4712 else if (slot[1] == NULL_RTX)
4713 slot[1] = insn;
4714 else
4715 slot[2] = insn;
4716 n_filled++;
4719 next = NEXT_INSN (insn);
4720 while (next && insn != BB_END (bb)
4721 && !(INSN_P (next)
4722 && GET_CODE (PATTERN (next)) != USE
4723 && GET_CODE (PATTERN (next)) != CLOBBER))
4725 insn = next;
4726 next = NEXT_INSN (insn);
4729 /* BB_END can change due to emitting extra NOPs, so check here. */
4730 at_end = insn == BB_END (bb);
4731 if (at_end || GET_MODE (next) == TImode)
4733 if ((n_filled < 2
4734 || !gen_one_bundle (slot))
4735 && slot[0] != NULL_RTX)
4737 rtx pat = PATTERN (slot[0]);
4738 if (GET_CODE (pat) == SET
4739 && GET_CODE (SET_SRC (pat)) == UNSPEC
4740 && XINT (SET_SRC (pat), 1) == UNSPEC_32BIT)
4742 SET_SRC (pat) = XVECEXP (SET_SRC (pat), 0, 0);
4743 INSN_CODE (slot[0]) = -1;
4744 df_insn_rescan (slot[0]);
4747 n_filled = 0;
4748 slot[0] = slot[1] = slot[2] = NULL_RTX;
4750 if (at_end)
4751 break;
4756 /* Ensure that no var tracking notes are emitted in the middle of a
4757 three-instruction bundle. */
4759 static void
4760 reorder_var_tracking_notes (void)
4762 basic_block bb;
4763 FOR_EACH_BB (bb)
4765 rtx insn, next;
4766 rtx queue = NULL_RTX;
4767 bool in_bundle = false;
4769 for (insn = BB_HEAD (bb); insn != BB_END (bb); insn = next)
4771 next = NEXT_INSN (insn);
4773 if (INSN_P (insn))
4775 /* Emit queued up notes at the last instruction of a bundle. */
4776 if (GET_MODE (insn) == QImode)
4778 while (queue)
4780 rtx next_queue = PREV_INSN (queue);
4781 PREV_INSN (NEXT_INSN (insn)) = queue;
4782 NEXT_INSN (queue) = NEXT_INSN (insn);
4783 NEXT_INSN (insn) = queue;
4784 PREV_INSN (queue) = insn;
4785 queue = next_queue;
4787 in_bundle = false;
4789 else if (GET_MODE (insn) == SImode)
4790 in_bundle = true;
4792 else if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION)
4794 if (in_bundle)
4796 rtx prev = PREV_INSN (insn);
4797 PREV_INSN (next) = prev;
4798 NEXT_INSN (prev) = next;
4800 PREV_INSN (insn) = queue;
4801 queue = insn;
4808 /* On some silicon revisions, functions shorter than a certain number of cycles
4809 can cause unpredictable behaviour. Work around this by adding NOPs as
4810 needed. */
4811 static void
4812 workaround_rts_anomaly (void)
4814 rtx insn, first_insn = NULL_RTX;
4815 int cycles = 4;
4817 if (! ENABLE_WA_RETS)
4818 return;
4820 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
4822 rtx pat;
4824 if (BARRIER_P (insn))
4825 return;
4827 if (NOTE_P (insn) || LABEL_P (insn))
4828 continue;
4830 if (first_insn == NULL_RTX)
4831 first_insn = insn;
4832 pat = PATTERN (insn);
4833 if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER
4834 || GET_CODE (pat) == ASM_INPUT || GET_CODE (pat) == ADDR_VEC
4835 || GET_CODE (pat) == ADDR_DIFF_VEC || asm_noperands (pat) >= 0)
4836 continue;
4838 if (CALL_P (insn))
4839 return;
4841 if (JUMP_P (insn))
4843 if (recog_memoized (insn) == CODE_FOR_return_internal)
4844 break;
4846 /* Nothing to worry about for direct jumps. */
4847 if (!any_condjump_p (insn))
4848 return;
4849 if (cycles <= 1)
4850 return;
4851 cycles--;
4853 else if (INSN_P (insn))
4855 rtx pat = PATTERN (insn);
4856 int this_cycles = 1;
4858 if (GET_CODE (pat) == PARALLEL)
4860 if (push_multiple_operation (pat, VOIDmode)
4861 || pop_multiple_operation (pat, VOIDmode))
4862 this_cycles = n_regs_to_save;
4864 else
4866 enum insn_code icode = recog_memoized (insn);
4867 if (icode == CODE_FOR_link)
4868 this_cycles = 4;
4869 else if (icode == CODE_FOR_unlink)
4870 this_cycles = 3;
4871 else if (icode == CODE_FOR_mulsi3)
4872 this_cycles = 5;
4874 if (this_cycles >= cycles)
4875 return;
4877 cycles -= this_cycles;
4880 while (cycles > 0)
4882 emit_insn_before (gen_nop (), first_insn);
4883 cycles--;
4887 /* Return an insn type for INSN that can be used by the caller for anomaly
4888 workarounds. This differs from plain get_attr_type in that it handles
4889 SEQUENCEs. */
4891 static enum attr_type
4892 type_for_anomaly (rtx insn)
4894 rtx pat = PATTERN (insn);
4895 if (GET_CODE (pat) == SEQUENCE)
4897 enum attr_type t;
4898 t = get_attr_type (XVECEXP (pat, 0, 1));
4899 if (t == TYPE_MCLD)
4900 return t;
4901 t = get_attr_type (XVECEXP (pat, 0, 2));
4902 if (t == TYPE_MCLD)
4903 return t;
4904 return TYPE_MCST;
4906 else
4907 return get_attr_type (insn);
4910 /* Return nonzero if INSN contains any loads that may trap. It handles
4911 SEQUENCEs correctly. */
4913 static bool
4914 trapping_loads_p (rtx insn)
4916 rtx pat = PATTERN (insn);
4917 if (GET_CODE (pat) == SEQUENCE)
4919 enum attr_type t;
4920 t = get_attr_type (XVECEXP (pat, 0, 1));
4921 if (t == TYPE_MCLD
4922 && may_trap_p (SET_SRC (PATTERN (XVECEXP (pat, 0, 1)))))
4923 return true;
4924 t = get_attr_type (XVECEXP (pat, 0, 2));
4925 if (t == TYPE_MCLD
4926 && may_trap_p (SET_SRC (PATTERN (XVECEXP (pat, 0, 2)))))
4927 return true;
4928 return false;
4930 else
4931 return may_trap_p (SET_SRC (single_set (insn)));
4934 /* Return INSN if it is of TYPE_MCLD. Alternatively, if INSN is the start of
4935 a three-insn bundle, see if one of them is a load and return that if so.
4936 Return NULL_RTX if the insn does not contain loads. */
4937 static rtx
4938 find_load (rtx insn)
4940 if (get_attr_type (insn) == TYPE_MCLD)
4941 return insn;
4942 if (GET_MODE (insn) != SImode)
4943 return NULL_RTX;
4944 do {
4945 insn = NEXT_INSN (insn);
4946 if ((GET_MODE (insn) == SImode || GET_MODE (insn) == QImode)
4947 && get_attr_type (insn) == TYPE_MCLD)
4948 return insn;
4949 } while (GET_MODE (insn) != QImode);
4950 return NULL_RTX;
4953 /* Determine whether PAT is an indirect call pattern. */
4954 static bool
4955 indirect_call_p (rtx pat)
4957 if (GET_CODE (pat) == PARALLEL)
4958 pat = XVECEXP (pat, 0, 0);
4959 if (GET_CODE (pat) == SET)
4960 pat = SET_SRC (pat);
4961 gcc_assert (GET_CODE (pat) == CALL);
4962 pat = XEXP (pat, 0);
4963 gcc_assert (GET_CODE (pat) == MEM);
4964 pat = XEXP (pat, 0);
4966 return REG_P (pat);
4969 static void
4970 workaround_speculation (void)
4972 rtx insn, next;
4973 rtx last_condjump = NULL_RTX;
4974 int cycles_since_jump = INT_MAX;
4975 int delay_added = 0;
4977 if (! ENABLE_WA_SPECULATIVE_LOADS && ! ENABLE_WA_SPECULATIVE_SYNCS
4978 && ! ENABLE_WA_INDIRECT_CALLS)
4979 return;
4981 /* First pass: find predicted-false branches; if something after them
4982 needs nops, insert them or change the branch to predict true. */
4983 for (insn = get_insns (); insn; insn = next)
4985 rtx pat;
4986 int delay_needed = 0;
4988 next = find_next_insn_start (insn);
4990 if (NOTE_P (insn) || BARRIER_P (insn) || LABEL_P (insn))
4991 continue;
4993 pat = PATTERN (insn);
4994 if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER
4995 || GET_CODE (pat) == ASM_INPUT || GET_CODE (pat) == ADDR_VEC
4996 || GET_CODE (pat) == ADDR_DIFF_VEC || asm_noperands (pat) >= 0)
4997 continue;
4999 if (JUMP_P (insn))
5001 if (any_condjump_p (insn)
5002 && ! cbranch_predicted_taken_p (insn))
5004 last_condjump = insn;
5005 delay_added = 0;
5006 cycles_since_jump = 0;
5008 else
5009 cycles_since_jump = INT_MAX;
5011 else if (CALL_P (insn))
5013 if (cycles_since_jump < INT_MAX)
5014 cycles_since_jump++;
5015 if (indirect_call_p (pat) && ENABLE_WA_INDIRECT_CALLS)
5017 delay_needed = 3;
5020 else if (INSN_P (insn))
5022 rtx load_insn = find_load (insn);
5023 enum attr_type type = type_for_anomaly (insn);
5025 if (cycles_since_jump < INT_MAX)
5026 cycles_since_jump++;
5028 if (load_insn && ENABLE_WA_SPECULATIVE_LOADS)
5030 if (trapping_loads_p (load_insn))
5031 delay_needed = 4;
5033 else if (type == TYPE_SYNC && ENABLE_WA_SPECULATIVE_SYNCS)
5034 delay_needed = 3;
5037 if (delay_needed > cycles_since_jump
5038 && (delay_needed - cycles_since_jump) > delay_added)
5040 rtx pat1;
5041 int num_clobbers;
5042 rtx *op = recog_data.operand;
5044 delay_needed -= cycles_since_jump;
5046 extract_insn (last_condjump);
5047 if (optimize_size)
5049 pat1 = gen_cbranch_predicted_taken (op[0], op[1], op[2],
5050 op[3]);
5051 cycles_since_jump = INT_MAX;
5053 else
5055 /* Do not adjust cycles_since_jump in this case, so that
5056 we'll increase the number of NOPs for a subsequent insn
5057 if necessary. */
5058 pat1 = gen_cbranch_with_nops (op[0], op[1], op[2], op[3],
5059 GEN_INT (delay_needed));
5060 delay_added = delay_needed;
5062 PATTERN (last_condjump) = pat1;
5063 INSN_CODE (last_condjump) = recog (pat1, insn, &num_clobbers);
5065 if (CALL_P (insn))
5067 cycles_since_jump = INT_MAX;
5068 delay_added = 0;
5072 /* Second pass: for predicted-true branches, see if anything at the
5073 branch destination needs extra nops. */
5074 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
5076 int cycles_since_jump;
5077 if (JUMP_P (insn)
5078 && any_condjump_p (insn)
5079 && (INSN_CODE (insn) == CODE_FOR_cbranch_predicted_taken
5080 || cbranch_predicted_taken_p (insn)))
5082 rtx target = JUMP_LABEL (insn);
5083 rtx label = target;
5084 rtx next_tgt;
5086 cycles_since_jump = 0;
5087 for (; target && cycles_since_jump < 3; target = next_tgt)
5089 rtx pat;
5091 next_tgt = find_next_insn_start (target);
5093 if (NOTE_P (target) || BARRIER_P (target) || LABEL_P (target))
5094 continue;
5096 pat = PATTERN (target);
5097 if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER
5098 || GET_CODE (pat) == ASM_INPUT || GET_CODE (pat) == ADDR_VEC
5099 || GET_CODE (pat) == ADDR_DIFF_VEC || asm_noperands (pat) >= 0)
5100 continue;
5102 if (INSN_P (target))
5104 rtx load_insn = find_load (target);
5105 enum attr_type type = type_for_anomaly (target);
5106 int delay_needed = 0;
5107 if (cycles_since_jump < INT_MAX)
5108 cycles_since_jump++;
5110 if (load_insn && ENABLE_WA_SPECULATIVE_LOADS)
5112 if (trapping_loads_p (load_insn))
5113 delay_needed = 2;
5115 else if (type == TYPE_SYNC && ENABLE_WA_SPECULATIVE_SYNCS)
5116 delay_needed = 2;
5118 if (delay_needed > cycles_since_jump)
5120 rtx prev = prev_real_insn (label);
5121 delay_needed -= cycles_since_jump;
5122 if (dump_file)
5123 fprintf (dump_file, "Adding %d nops after %d\n",
5124 delay_needed, INSN_UID (label));
5125 if (JUMP_P (prev)
5126 && INSN_CODE (prev) == CODE_FOR_cbranch_with_nops)
5128 rtx x;
5129 HOST_WIDE_INT v;
5131 if (dump_file)
5132 fprintf (dump_file,
5133 "Reducing nops on insn %d.\n",
5134 INSN_UID (prev));
5135 x = PATTERN (prev);
5136 x = XVECEXP (x, 0, 1);
5137 v = INTVAL (XVECEXP (x, 0, 0)) - delay_needed;
5138 XVECEXP (x, 0, 0) = GEN_INT (v);
5140 while (delay_needed-- > 0)
5141 emit_insn_after (gen_nop (), label);
5142 break;
5150 /* We use the machine specific reorg pass for emitting CSYNC instructions
5151 after conditional branches as needed.
5153 The Blackfin is unusual in that a code sequence like
5154 if cc jump label
5155 r0 = (p0)
5156 may speculatively perform the load even if the condition isn't true. This
5157 happens for a branch that is predicted not taken, because the pipeline
5158 isn't flushed or stalled, so the early stages of the following instructions,
5159 which perform the memory reference, are allowed to execute before the
5160 jump condition is evaluated.
5161 Therefore, we must insert additional instructions in all places where this
5162 could lead to incorrect behavior. The manual recommends CSYNC, while
5163 VDSP seems to use NOPs (even though its corresponding compiler option is
5164 named CSYNC).
5166 When optimizing for speed, we emit NOPs, which seems faster than a CSYNC.
5167 When optimizing for size, we turn the branch into a predicted taken one.
5168 This may be slower due to mispredicts, but saves code size. */
5170 static void
5171 bfin_reorg (void)
5173 /* We are freeing block_for_insn in the toplev to keep compatibility
5174 with old MDEP_REORGS that are not CFG based. Recompute it now. */
5175 compute_bb_for_insn ();
5177 if (bfin_flag_schedule_insns2)
5179 splitting_for_sched = 1;
5180 split_all_insns ();
5181 splitting_for_sched = 0;
5183 timevar_push (TV_SCHED2);
5184 schedule_insns ();
5185 timevar_pop (TV_SCHED2);
5187 /* Examine the schedule and insert nops as necessary for 64-bit parallel
5188 instructions. */
5189 bfin_gen_bundles ();
5192 df_analyze ();
5194 /* Doloop optimization */
5195 if (cfun->machine->has_hardware_loops)
5196 bfin_reorg_loops (dump_file);
5198 workaround_speculation ();
5200 if (bfin_flag_var_tracking)
5202 timevar_push (TV_VAR_TRACKING);
5203 variable_tracking_main ();
5204 reorder_var_tracking_notes ();
5205 timevar_pop (TV_VAR_TRACKING);
5208 df_finish_pass (false);
5210 workaround_rts_anomaly ();
5213 /* Handle interrupt_handler, exception_handler and nmi_handler function
5214 attributes; arguments as in struct attribute_spec.handler. */
5216 static tree
5217 handle_int_attribute (tree *node, tree name,
5218 tree args ATTRIBUTE_UNUSED,
5219 int flags ATTRIBUTE_UNUSED,
5220 bool *no_add_attrs)
5222 tree x = *node;
5223 if (TREE_CODE (x) == FUNCTION_DECL)
5224 x = TREE_TYPE (x);
5226 if (TREE_CODE (x) != FUNCTION_TYPE)
5228 warning (OPT_Wattributes, "%qs attribute only applies to functions",
5229 IDENTIFIER_POINTER (name));
5230 *no_add_attrs = true;
5232 else if (funkind (x) != SUBROUTINE)
5233 error ("multiple function type attributes specified");
5235 return NULL_TREE;
5238 /* Return 0 if the attributes for two types are incompatible, 1 if they
5239 are compatible, and 2 if they are nearly compatible (which causes a
5240 warning to be generated). */
5242 static int
5243 bfin_comp_type_attributes (const_tree type1, const_tree type2)
5245 e_funkind kind1, kind2;
5247 if (TREE_CODE (type1) != FUNCTION_TYPE)
5248 return 1;
5250 kind1 = funkind (type1);
5251 kind2 = funkind (type2);
5253 if (kind1 != kind2)
5254 return 0;
5256 /* Check for mismatched modifiers */
5257 if (!lookup_attribute ("nesting", TYPE_ATTRIBUTES (type1))
5258 != !lookup_attribute ("nesting", TYPE_ATTRIBUTES (type2)))
5259 return 0;
5261 if (!lookup_attribute ("saveall", TYPE_ATTRIBUTES (type1))
5262 != !lookup_attribute ("saveall", TYPE_ATTRIBUTES (type2)))
5263 return 0;
5265 if (!lookup_attribute ("kspisusp", TYPE_ATTRIBUTES (type1))
5266 != !lookup_attribute ("kspisusp", TYPE_ATTRIBUTES (type2)))
5267 return 0;
5269 if (!lookup_attribute ("longcall", TYPE_ATTRIBUTES (type1))
5270 != !lookup_attribute ("longcall", TYPE_ATTRIBUTES (type2)))
5271 return 0;
5273 return 1;
5276 /* Handle a "longcall" or "shortcall" attribute; arguments as in
5277 struct attribute_spec.handler. */
5279 static tree
5280 bfin_handle_longcall_attribute (tree *node, tree name,
5281 tree args ATTRIBUTE_UNUSED,
5282 int flags ATTRIBUTE_UNUSED,
5283 bool *no_add_attrs)
5285 if (TREE_CODE (*node) != FUNCTION_TYPE
5286 && TREE_CODE (*node) != FIELD_DECL
5287 && TREE_CODE (*node) != TYPE_DECL)
5289 warning (OPT_Wattributes, "`%s' attribute only applies to functions",
5290 IDENTIFIER_POINTER (name));
5291 *no_add_attrs = true;
5294 if ((strcmp (IDENTIFIER_POINTER (name), "longcall") == 0
5295 && lookup_attribute ("shortcall", TYPE_ATTRIBUTES (*node)))
5296 || (strcmp (IDENTIFIER_POINTER (name), "shortcall") == 0
5297 && lookup_attribute ("longcall", TYPE_ATTRIBUTES (*node))))
5299 warning (OPT_Wattributes,
5300 "can't apply both longcall and shortcall attributes to the same function");
5301 *no_add_attrs = true;
5304 return NULL_TREE;
5307 /* Handle a "l1_text" attribute; arguments as in
5308 struct attribute_spec.handler. */
5310 static tree
5311 bfin_handle_l1_text_attribute (tree *node, tree name, tree ARG_UNUSED (args),
5312 int ARG_UNUSED (flags), bool *no_add_attrs)
5314 tree decl = *node;
5316 if (TREE_CODE (decl) != FUNCTION_DECL)
5318 error ("`%s' attribute only applies to functions",
5319 IDENTIFIER_POINTER (name));
5320 *no_add_attrs = true;
5323 /* The decl may have already been given a section attribute
5324 from a previous declaration. Ensure they match. */
5325 else if (DECL_SECTION_NAME (decl) != NULL_TREE
5326 && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
5327 ".l1.text") != 0)
5329 error ("section of %q+D conflicts with previous declaration",
5330 decl);
5331 *no_add_attrs = true;
5333 else
5334 DECL_SECTION_NAME (decl) = build_string (9, ".l1.text");
5336 return NULL_TREE;
5339 /* Handle a "l1_data", "l1_data_A" or "l1_data_B" attribute;
5340 arguments as in struct attribute_spec.handler. */
5342 static tree
5343 bfin_handle_l1_data_attribute (tree *node, tree name, tree ARG_UNUSED (args),
5344 int ARG_UNUSED (flags), bool *no_add_attrs)
5346 tree decl = *node;
5348 if (TREE_CODE (decl) != VAR_DECL)
5350 error ("`%s' attribute only applies to variables",
5351 IDENTIFIER_POINTER (name));
5352 *no_add_attrs = true;
5354 else if (current_function_decl != NULL_TREE
5355 && !TREE_STATIC (decl))
5357 error ("`%s' attribute cannot be specified for local variables",
5358 IDENTIFIER_POINTER (name));
5359 *no_add_attrs = true;
5361 else
5363 const char *section_name;
5365 if (strcmp (IDENTIFIER_POINTER (name), "l1_data") == 0)
5366 section_name = ".l1.data";
5367 else if (strcmp (IDENTIFIER_POINTER (name), "l1_data_A") == 0)
5368 section_name = ".l1.data.A";
5369 else if (strcmp (IDENTIFIER_POINTER (name), "l1_data_B") == 0)
5370 section_name = ".l1.data.B";
5371 else
5372 gcc_unreachable ();
5374 /* The decl may have already been given a section attribute
5375 from a previous declaration. Ensure they match. */
5376 if (DECL_SECTION_NAME (decl) != NULL_TREE
5377 && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
5378 section_name) != 0)
5380 error ("section of %q+D conflicts with previous declaration",
5381 decl);
5382 *no_add_attrs = true;
5384 else
5385 DECL_SECTION_NAME (decl)
5386 = build_string (strlen (section_name) + 1, section_name);
5389 return NULL_TREE;
5392 /* Table of valid machine attributes. */
5393 const struct attribute_spec bfin_attribute_table[] =
5395 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
5396 { "interrupt_handler", 0, 0, false, true, true, handle_int_attribute },
5397 { "exception_handler", 0, 0, false, true, true, handle_int_attribute },
5398 { "nmi_handler", 0, 0, false, true, true, handle_int_attribute },
5399 { "nesting", 0, 0, false, true, true, NULL },
5400 { "kspisusp", 0, 0, false, true, true, NULL },
5401 { "saveall", 0, 0, false, true, true, NULL },
5402 { "longcall", 0, 0, false, true, true, bfin_handle_longcall_attribute },
5403 { "shortcall", 0, 0, false, true, true, bfin_handle_longcall_attribute },
5404 { "l1_text", 0, 0, true, false, false, bfin_handle_l1_text_attribute },
5405 { "l1_data", 0, 0, true, false, false, bfin_handle_l1_data_attribute },
5406 { "l1_data_A", 0, 0, true, false, false, bfin_handle_l1_data_attribute },
5407 { "l1_data_B", 0, 0, true, false, false, bfin_handle_l1_data_attribute },
5408 { NULL, 0, 0, false, false, false, NULL }
5411 /* Implementation of TARGET_ASM_INTEGER. When using FD-PIC, we need to
5412 tell the assembler to generate pointers to function descriptors in
5413 some cases. */
5415 static bool
5416 bfin_assemble_integer (rtx value, unsigned int size, int aligned_p)
5418 if (TARGET_FDPIC && size == UNITS_PER_WORD)
5420 if (GET_CODE (value) == SYMBOL_REF
5421 && SYMBOL_REF_FUNCTION_P (value))
5423 fputs ("\t.picptr\tfuncdesc(", asm_out_file);
5424 output_addr_const (asm_out_file, value);
5425 fputs (")\n", asm_out_file);
5426 return true;
5428 if (!aligned_p)
5430 /* We've set the unaligned SI op to NULL, so we always have to
5431 handle the unaligned case here. */
5432 assemble_integer_with_op ("\t.4byte\t", value);
5433 return true;
5436 return default_assemble_integer (value, size, aligned_p);
5439 /* Output the assembler code for a thunk function. THUNK_DECL is the
5440 declaration for the thunk function itself, FUNCTION is the decl for
5441 the target function. DELTA is an immediate constant offset to be
5442 added to THIS. If VCALL_OFFSET is nonzero, the word at
5443 *(*this + vcall_offset) should be added to THIS. */
5445 static void
5446 bfin_output_mi_thunk (FILE *file ATTRIBUTE_UNUSED,
5447 tree thunk ATTRIBUTE_UNUSED, HOST_WIDE_INT delta,
5448 HOST_WIDE_INT vcall_offset, tree function)
5450 rtx xops[3];
5451 /* The this parameter is passed as the first argument. */
5452 rtx this_rtx = gen_rtx_REG (Pmode, REG_R0);
5454 /* Adjust the this parameter by a fixed constant. */
5455 if (delta)
5457 xops[1] = this_rtx;
5458 if (delta >= -64 && delta <= 63)
5460 xops[0] = GEN_INT (delta);
5461 output_asm_insn ("%1 += %0;", xops);
5463 else if (delta >= -128 && delta < -64)
5465 xops[0] = GEN_INT (delta + 64);
5466 output_asm_insn ("%1 += -64; %1 += %0;", xops);
5468 else if (delta > 63 && delta <= 126)
5470 xops[0] = GEN_INT (delta - 63);
5471 output_asm_insn ("%1 += 63; %1 += %0;", xops);
5473 else
5475 xops[0] = GEN_INT (delta);
5476 output_asm_insn ("r3.l = %h0; r3.h = %d0; %1 = %1 + r3;", xops);
5480 /* Adjust the this parameter by a value stored in the vtable. */
5481 if (vcall_offset)
5483 rtx p2tmp = gen_rtx_REG (Pmode, REG_P2);
5484 rtx tmp = gen_rtx_REG (Pmode, REG_R3);
5486 xops[1] = tmp;
5487 xops[2] = p2tmp;
5488 output_asm_insn ("%2 = r0; %2 = [%2];", xops);
5490 /* Adjust the this parameter. */
5491 xops[0] = gen_rtx_MEM (Pmode, plus_constant (p2tmp, vcall_offset));
5492 if (!memory_operand (xops[0], Pmode))
5494 rtx tmp2 = gen_rtx_REG (Pmode, REG_P1);
5495 xops[0] = GEN_INT (vcall_offset);
5496 xops[1] = tmp2;
5497 output_asm_insn ("%h1 = %h0; %d1 = %d0; %2 = %2 + %1", xops);
5498 xops[0] = gen_rtx_MEM (Pmode, p2tmp);
5500 xops[2] = this_rtx;
5501 output_asm_insn ("%1 = %0; %2 = %2 + %1;", xops);
5504 xops[0] = XEXP (DECL_RTL (function), 0);
5505 if (1 || !flag_pic || (*targetm.binds_local_p) (function))
5506 output_asm_insn ("jump.l\t%P0", xops);
5509 /* Codes for all the Blackfin builtins. */
5510 enum bfin_builtins
5512 BFIN_BUILTIN_CSYNC,
5513 BFIN_BUILTIN_SSYNC,
5514 BFIN_BUILTIN_ONES,
5515 BFIN_BUILTIN_COMPOSE_2X16,
5516 BFIN_BUILTIN_EXTRACTLO,
5517 BFIN_BUILTIN_EXTRACTHI,
5519 BFIN_BUILTIN_SSADD_2X16,
5520 BFIN_BUILTIN_SSSUB_2X16,
5521 BFIN_BUILTIN_SSADDSUB_2X16,
5522 BFIN_BUILTIN_SSSUBADD_2X16,
5523 BFIN_BUILTIN_MULT_2X16,
5524 BFIN_BUILTIN_MULTR_2X16,
5525 BFIN_BUILTIN_NEG_2X16,
5526 BFIN_BUILTIN_ABS_2X16,
5527 BFIN_BUILTIN_MIN_2X16,
5528 BFIN_BUILTIN_MAX_2X16,
5530 BFIN_BUILTIN_SSADD_1X16,
5531 BFIN_BUILTIN_SSSUB_1X16,
5532 BFIN_BUILTIN_MULT_1X16,
5533 BFIN_BUILTIN_MULTR_1X16,
5534 BFIN_BUILTIN_NORM_1X16,
5535 BFIN_BUILTIN_NEG_1X16,
5536 BFIN_BUILTIN_ABS_1X16,
5537 BFIN_BUILTIN_MIN_1X16,
5538 BFIN_BUILTIN_MAX_1X16,
5540 BFIN_BUILTIN_SUM_2X16,
5541 BFIN_BUILTIN_DIFFHL_2X16,
5542 BFIN_BUILTIN_DIFFLH_2X16,
5544 BFIN_BUILTIN_SSADD_1X32,
5545 BFIN_BUILTIN_SSSUB_1X32,
5546 BFIN_BUILTIN_NORM_1X32,
5547 BFIN_BUILTIN_ROUND_1X32,
5548 BFIN_BUILTIN_NEG_1X32,
5549 BFIN_BUILTIN_ABS_1X32,
5550 BFIN_BUILTIN_MIN_1X32,
5551 BFIN_BUILTIN_MAX_1X32,
5552 BFIN_BUILTIN_MULT_1X32,
5553 BFIN_BUILTIN_MULT_1X32X32,
5554 BFIN_BUILTIN_MULT_1X32X32NS,
5556 BFIN_BUILTIN_MULHISILL,
5557 BFIN_BUILTIN_MULHISILH,
5558 BFIN_BUILTIN_MULHISIHL,
5559 BFIN_BUILTIN_MULHISIHH,
5561 BFIN_BUILTIN_LSHIFT_1X16,
5562 BFIN_BUILTIN_LSHIFT_2X16,
5563 BFIN_BUILTIN_SSASHIFT_1X16,
5564 BFIN_BUILTIN_SSASHIFT_2X16,
5565 BFIN_BUILTIN_SSASHIFT_1X32,
5567 BFIN_BUILTIN_CPLX_MUL_16,
5568 BFIN_BUILTIN_CPLX_MAC_16,
5569 BFIN_BUILTIN_CPLX_MSU_16,
5571 BFIN_BUILTIN_CPLX_MUL_16_S40,
5572 BFIN_BUILTIN_CPLX_MAC_16_S40,
5573 BFIN_BUILTIN_CPLX_MSU_16_S40,
5575 BFIN_BUILTIN_CPLX_SQU,
5577 BFIN_BUILTIN_LOADBYTES,
5579 BFIN_BUILTIN_MAX
5582 #define def_builtin(NAME, TYPE, CODE) \
5583 do { \
5584 add_builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD, \
5585 NULL, NULL_TREE); \
5586 } while (0)
5588 /* Set up all builtin functions for this target. */
5589 static void
5590 bfin_init_builtins (void)
5592 tree V2HI_type_node = build_vector_type_for_mode (intHI_type_node, V2HImode);
5593 tree void_ftype_void
5594 = build_function_type (void_type_node, void_list_node);
5595 tree short_ftype_short
5596 = build_function_type_list (short_integer_type_node, short_integer_type_node,
5597 NULL_TREE);
5598 tree short_ftype_int_int
5599 = build_function_type_list (short_integer_type_node, integer_type_node,
5600 integer_type_node, NULL_TREE);
5601 tree int_ftype_int_int
5602 = build_function_type_list (integer_type_node, integer_type_node,
5603 integer_type_node, NULL_TREE);
5604 tree int_ftype_int
5605 = build_function_type_list (integer_type_node, integer_type_node,
5606 NULL_TREE);
5607 tree short_ftype_int
5608 = build_function_type_list (short_integer_type_node, integer_type_node,
5609 NULL_TREE);
5610 tree int_ftype_v2hi_v2hi
5611 = build_function_type_list (integer_type_node, V2HI_type_node,
5612 V2HI_type_node, NULL_TREE);
5613 tree v2hi_ftype_v2hi_v2hi
5614 = build_function_type_list (V2HI_type_node, V2HI_type_node,
5615 V2HI_type_node, NULL_TREE);
5616 tree v2hi_ftype_v2hi_v2hi_v2hi
5617 = build_function_type_list (V2HI_type_node, V2HI_type_node,
5618 V2HI_type_node, V2HI_type_node, NULL_TREE);
5619 tree v2hi_ftype_int_int
5620 = build_function_type_list (V2HI_type_node, integer_type_node,
5621 integer_type_node, NULL_TREE);
5622 tree v2hi_ftype_v2hi_int
5623 = build_function_type_list (V2HI_type_node, V2HI_type_node,
5624 integer_type_node, NULL_TREE);
5625 tree int_ftype_short_short
5626 = build_function_type_list (integer_type_node, short_integer_type_node,
5627 short_integer_type_node, NULL_TREE);
5628 tree v2hi_ftype_v2hi
5629 = build_function_type_list (V2HI_type_node, V2HI_type_node, NULL_TREE);
5630 tree short_ftype_v2hi
5631 = build_function_type_list (short_integer_type_node, V2HI_type_node,
5632 NULL_TREE);
5633 tree int_ftype_pint
5634 = build_function_type_list (integer_type_node,
5635 build_pointer_type (integer_type_node),
5636 NULL_TREE);
5638 /* Add the remaining MMX insns with somewhat more complicated types. */
5639 def_builtin ("__builtin_bfin_csync", void_ftype_void, BFIN_BUILTIN_CSYNC);
5640 def_builtin ("__builtin_bfin_ssync", void_ftype_void, BFIN_BUILTIN_SSYNC);
5642 def_builtin ("__builtin_bfin_ones", short_ftype_int, BFIN_BUILTIN_ONES);
5644 def_builtin ("__builtin_bfin_compose_2x16", v2hi_ftype_int_int,
5645 BFIN_BUILTIN_COMPOSE_2X16);
5646 def_builtin ("__builtin_bfin_extract_hi", short_ftype_v2hi,
5647 BFIN_BUILTIN_EXTRACTHI);
5648 def_builtin ("__builtin_bfin_extract_lo", short_ftype_v2hi,
5649 BFIN_BUILTIN_EXTRACTLO);
5651 def_builtin ("__builtin_bfin_min_fr2x16", v2hi_ftype_v2hi_v2hi,
5652 BFIN_BUILTIN_MIN_2X16);
5653 def_builtin ("__builtin_bfin_max_fr2x16", v2hi_ftype_v2hi_v2hi,
5654 BFIN_BUILTIN_MAX_2X16);
5656 def_builtin ("__builtin_bfin_add_fr2x16", v2hi_ftype_v2hi_v2hi,
5657 BFIN_BUILTIN_SSADD_2X16);
5658 def_builtin ("__builtin_bfin_sub_fr2x16", v2hi_ftype_v2hi_v2hi,
5659 BFIN_BUILTIN_SSSUB_2X16);
5660 def_builtin ("__builtin_bfin_dspaddsubsat", v2hi_ftype_v2hi_v2hi,
5661 BFIN_BUILTIN_SSADDSUB_2X16);
5662 def_builtin ("__builtin_bfin_dspsubaddsat", v2hi_ftype_v2hi_v2hi,
5663 BFIN_BUILTIN_SSSUBADD_2X16);
5664 def_builtin ("__builtin_bfin_mult_fr2x16", v2hi_ftype_v2hi_v2hi,
5665 BFIN_BUILTIN_MULT_2X16);
5666 def_builtin ("__builtin_bfin_multr_fr2x16", v2hi_ftype_v2hi_v2hi,
5667 BFIN_BUILTIN_MULTR_2X16);
5668 def_builtin ("__builtin_bfin_negate_fr2x16", v2hi_ftype_v2hi,
5669 BFIN_BUILTIN_NEG_2X16);
5670 def_builtin ("__builtin_bfin_abs_fr2x16", v2hi_ftype_v2hi,
5671 BFIN_BUILTIN_ABS_2X16);
5673 def_builtin ("__builtin_bfin_min_fr1x16", short_ftype_int_int,
5674 BFIN_BUILTIN_MIN_1X16);
5675 def_builtin ("__builtin_bfin_max_fr1x16", short_ftype_int_int,
5676 BFIN_BUILTIN_MAX_1X16);
5678 def_builtin ("__builtin_bfin_add_fr1x16", short_ftype_int_int,
5679 BFIN_BUILTIN_SSADD_1X16);
5680 def_builtin ("__builtin_bfin_sub_fr1x16", short_ftype_int_int,
5681 BFIN_BUILTIN_SSSUB_1X16);
5682 def_builtin ("__builtin_bfin_mult_fr1x16", short_ftype_int_int,
5683 BFIN_BUILTIN_MULT_1X16);
5684 def_builtin ("__builtin_bfin_multr_fr1x16", short_ftype_int_int,
5685 BFIN_BUILTIN_MULTR_1X16);
5686 def_builtin ("__builtin_bfin_negate_fr1x16", short_ftype_short,
5687 BFIN_BUILTIN_NEG_1X16);
5688 def_builtin ("__builtin_bfin_abs_fr1x16", short_ftype_short,
5689 BFIN_BUILTIN_ABS_1X16);
5690 def_builtin ("__builtin_bfin_norm_fr1x16", short_ftype_int,
5691 BFIN_BUILTIN_NORM_1X16);
5693 def_builtin ("__builtin_bfin_sum_fr2x16", short_ftype_v2hi,
5694 BFIN_BUILTIN_SUM_2X16);
5695 def_builtin ("__builtin_bfin_diff_hl_fr2x16", short_ftype_v2hi,
5696 BFIN_BUILTIN_DIFFHL_2X16);
5697 def_builtin ("__builtin_bfin_diff_lh_fr2x16", short_ftype_v2hi,
5698 BFIN_BUILTIN_DIFFLH_2X16);
5700 def_builtin ("__builtin_bfin_mulhisill", int_ftype_v2hi_v2hi,
5701 BFIN_BUILTIN_MULHISILL);
5702 def_builtin ("__builtin_bfin_mulhisihl", int_ftype_v2hi_v2hi,
5703 BFIN_BUILTIN_MULHISIHL);
5704 def_builtin ("__builtin_bfin_mulhisilh", int_ftype_v2hi_v2hi,
5705 BFIN_BUILTIN_MULHISILH);
5706 def_builtin ("__builtin_bfin_mulhisihh", int_ftype_v2hi_v2hi,
5707 BFIN_BUILTIN_MULHISIHH);
5709 def_builtin ("__builtin_bfin_min_fr1x32", int_ftype_int_int,
5710 BFIN_BUILTIN_MIN_1X32);
5711 def_builtin ("__builtin_bfin_max_fr1x32", int_ftype_int_int,
5712 BFIN_BUILTIN_MAX_1X32);
5714 def_builtin ("__builtin_bfin_add_fr1x32", int_ftype_int_int,
5715 BFIN_BUILTIN_SSADD_1X32);
5716 def_builtin ("__builtin_bfin_sub_fr1x32", int_ftype_int_int,
5717 BFIN_BUILTIN_SSSUB_1X32);
5718 def_builtin ("__builtin_bfin_negate_fr1x32", int_ftype_int,
5719 BFIN_BUILTIN_NEG_1X32);
5720 def_builtin ("__builtin_bfin_abs_fr1x32", int_ftype_int,
5721 BFIN_BUILTIN_ABS_1X32);
5722 def_builtin ("__builtin_bfin_norm_fr1x32", short_ftype_int,
5723 BFIN_BUILTIN_NORM_1X32);
5724 def_builtin ("__builtin_bfin_round_fr1x32", short_ftype_int,
5725 BFIN_BUILTIN_ROUND_1X32);
5726 def_builtin ("__builtin_bfin_mult_fr1x32", int_ftype_short_short,
5727 BFIN_BUILTIN_MULT_1X32);
5728 def_builtin ("__builtin_bfin_mult_fr1x32x32", int_ftype_int_int,
5729 BFIN_BUILTIN_MULT_1X32X32);
5730 def_builtin ("__builtin_bfin_mult_fr1x32x32NS", int_ftype_int_int,
5731 BFIN_BUILTIN_MULT_1X32X32NS);
5733 /* Shifts. */
5734 def_builtin ("__builtin_bfin_shl_fr1x16", short_ftype_int_int,
5735 BFIN_BUILTIN_SSASHIFT_1X16);
5736 def_builtin ("__builtin_bfin_shl_fr2x16", v2hi_ftype_v2hi_int,
5737 BFIN_BUILTIN_SSASHIFT_2X16);
5738 def_builtin ("__builtin_bfin_lshl_fr1x16", short_ftype_int_int,
5739 BFIN_BUILTIN_LSHIFT_1X16);
5740 def_builtin ("__builtin_bfin_lshl_fr2x16", v2hi_ftype_v2hi_int,
5741 BFIN_BUILTIN_LSHIFT_2X16);
5742 def_builtin ("__builtin_bfin_shl_fr1x32", int_ftype_int_int,
5743 BFIN_BUILTIN_SSASHIFT_1X32);
5745 /* Complex numbers. */
5746 def_builtin ("__builtin_bfin_cmplx_add", v2hi_ftype_v2hi_v2hi,
5747 BFIN_BUILTIN_SSADD_2X16);
5748 def_builtin ("__builtin_bfin_cmplx_sub", v2hi_ftype_v2hi_v2hi,
5749 BFIN_BUILTIN_SSSUB_2X16);
5750 def_builtin ("__builtin_bfin_cmplx_mul", v2hi_ftype_v2hi_v2hi,
5751 BFIN_BUILTIN_CPLX_MUL_16);
5752 def_builtin ("__builtin_bfin_cmplx_mac", v2hi_ftype_v2hi_v2hi_v2hi,
5753 BFIN_BUILTIN_CPLX_MAC_16);
5754 def_builtin ("__builtin_bfin_cmplx_msu", v2hi_ftype_v2hi_v2hi_v2hi,
5755 BFIN_BUILTIN_CPLX_MSU_16);
5756 def_builtin ("__builtin_bfin_cmplx_mul_s40", v2hi_ftype_v2hi_v2hi,
5757 BFIN_BUILTIN_CPLX_MUL_16_S40);
5758 def_builtin ("__builtin_bfin_cmplx_mac_s40", v2hi_ftype_v2hi_v2hi_v2hi,
5759 BFIN_BUILTIN_CPLX_MAC_16_S40);
5760 def_builtin ("__builtin_bfin_cmplx_msu_s40", v2hi_ftype_v2hi_v2hi_v2hi,
5761 BFIN_BUILTIN_CPLX_MSU_16_S40);
5762 def_builtin ("__builtin_bfin_csqu_fr16", v2hi_ftype_v2hi,
5763 BFIN_BUILTIN_CPLX_SQU);
5765 /* "Unaligned" load. */
5766 def_builtin ("__builtin_bfin_loadbytes", int_ftype_pint,
5767 BFIN_BUILTIN_LOADBYTES);
5772 struct builtin_description
5774 const enum insn_code icode;
5775 const char *const name;
5776 const enum bfin_builtins code;
5777 int macflag;
5780 static const struct builtin_description bdesc_2arg[] =
5782 { CODE_FOR_composev2hi, "__builtin_bfin_compose_2x16", BFIN_BUILTIN_COMPOSE_2X16, -1 },
5784 { CODE_FOR_ssashiftv2hi3, "__builtin_bfin_shl_fr2x16", BFIN_BUILTIN_SSASHIFT_2X16, -1 },
5785 { CODE_FOR_ssashifthi3, "__builtin_bfin_shl_fr1x16", BFIN_BUILTIN_SSASHIFT_1X16, -1 },
5786 { CODE_FOR_lshiftv2hi3, "__builtin_bfin_lshl_fr2x16", BFIN_BUILTIN_LSHIFT_2X16, -1 },
5787 { CODE_FOR_lshifthi3, "__builtin_bfin_lshl_fr1x16", BFIN_BUILTIN_LSHIFT_1X16, -1 },
5788 { CODE_FOR_ssashiftsi3, "__builtin_bfin_shl_fr1x32", BFIN_BUILTIN_SSASHIFT_1X32, -1 },
5790 { CODE_FOR_sminhi3, "__builtin_bfin_min_fr1x16", BFIN_BUILTIN_MIN_1X16, -1 },
5791 { CODE_FOR_smaxhi3, "__builtin_bfin_max_fr1x16", BFIN_BUILTIN_MAX_1X16, -1 },
5792 { CODE_FOR_ssaddhi3, "__builtin_bfin_add_fr1x16", BFIN_BUILTIN_SSADD_1X16, -1 },
5793 { CODE_FOR_sssubhi3, "__builtin_bfin_sub_fr1x16", BFIN_BUILTIN_SSSUB_1X16, -1 },
5795 { CODE_FOR_sminsi3, "__builtin_bfin_min_fr1x32", BFIN_BUILTIN_MIN_1X32, -1 },
5796 { CODE_FOR_smaxsi3, "__builtin_bfin_max_fr1x32", BFIN_BUILTIN_MAX_1X32, -1 },
5797 { CODE_FOR_ssaddsi3, "__builtin_bfin_add_fr1x32", BFIN_BUILTIN_SSADD_1X32, -1 },
5798 { CODE_FOR_sssubsi3, "__builtin_bfin_sub_fr1x32", BFIN_BUILTIN_SSSUB_1X32, -1 },
5800 { CODE_FOR_sminv2hi3, "__builtin_bfin_min_fr2x16", BFIN_BUILTIN_MIN_2X16, -1 },
5801 { CODE_FOR_smaxv2hi3, "__builtin_bfin_max_fr2x16", BFIN_BUILTIN_MAX_2X16, -1 },
5802 { CODE_FOR_ssaddv2hi3, "__builtin_bfin_add_fr2x16", BFIN_BUILTIN_SSADD_2X16, -1 },
5803 { CODE_FOR_sssubv2hi3, "__builtin_bfin_sub_fr2x16", BFIN_BUILTIN_SSSUB_2X16, -1 },
5804 { CODE_FOR_ssaddsubv2hi3, "__builtin_bfin_dspaddsubsat", BFIN_BUILTIN_SSADDSUB_2X16, -1 },
5805 { CODE_FOR_sssubaddv2hi3, "__builtin_bfin_dspsubaddsat", BFIN_BUILTIN_SSSUBADD_2X16, -1 },
5807 { CODE_FOR_flag_mulhisi, "__builtin_bfin_mult_fr1x32", BFIN_BUILTIN_MULT_1X32, MACFLAG_NONE },
5808 { CODE_FOR_flag_mulhi, "__builtin_bfin_mult_fr1x16", BFIN_BUILTIN_MULT_1X16, MACFLAG_T },
5809 { CODE_FOR_flag_mulhi, "__builtin_bfin_multr_fr1x16", BFIN_BUILTIN_MULTR_1X16, MACFLAG_NONE },
5810 { CODE_FOR_flag_mulv2hi, "__builtin_bfin_mult_fr2x16", BFIN_BUILTIN_MULT_2X16, MACFLAG_T },
5811 { CODE_FOR_flag_mulv2hi, "__builtin_bfin_multr_fr2x16", BFIN_BUILTIN_MULTR_2X16, MACFLAG_NONE },
5813 { CODE_FOR_mulhisi_ll, "__builtin_bfin_mulhisill", BFIN_BUILTIN_MULHISILL, -1 },
5814 { CODE_FOR_mulhisi_lh, "__builtin_bfin_mulhisilh", BFIN_BUILTIN_MULHISILH, -1 },
5815 { CODE_FOR_mulhisi_hl, "__builtin_bfin_mulhisihl", BFIN_BUILTIN_MULHISIHL, -1 },
5816 { CODE_FOR_mulhisi_hh, "__builtin_bfin_mulhisihh", BFIN_BUILTIN_MULHISIHH, -1 }
5820 static const struct builtin_description bdesc_1arg[] =
5822 { CODE_FOR_loadbytes, "__builtin_bfin_loadbytes", BFIN_BUILTIN_LOADBYTES, 0 },
5824 { CODE_FOR_ones, "__builtin_bfin_ones", BFIN_BUILTIN_ONES, 0 },
5826 { CODE_FOR_signbitshi2, "__builtin_bfin_norm_fr1x16", BFIN_BUILTIN_NORM_1X16, 0 },
5827 { CODE_FOR_ssneghi2, "__builtin_bfin_negate_fr1x16", BFIN_BUILTIN_NEG_1X16, 0 },
5828 { CODE_FOR_abshi2, "__builtin_bfin_abs_fr1x16", BFIN_BUILTIN_ABS_1X16, 0 },
5830 { CODE_FOR_signbitssi2, "__builtin_bfin_norm_fr1x32", BFIN_BUILTIN_NORM_1X32, 0 },
5831 { CODE_FOR_ssroundsi2, "__builtin_bfin_round_fr1x32", BFIN_BUILTIN_ROUND_1X32, 0 },
5832 { CODE_FOR_ssnegsi2, "__builtin_bfin_negate_fr1x32", BFIN_BUILTIN_NEG_1X32, 0 },
5833 { CODE_FOR_ssabssi2, "__builtin_bfin_abs_fr1x32", BFIN_BUILTIN_ABS_1X32, 0 },
5835 { CODE_FOR_movv2hi_hi_low, "__builtin_bfin_extract_lo", BFIN_BUILTIN_EXTRACTLO, 0 },
5836 { CODE_FOR_movv2hi_hi_high, "__builtin_bfin_extract_hi", BFIN_BUILTIN_EXTRACTHI, 0 },
5837 { CODE_FOR_ssnegv2hi2, "__builtin_bfin_negate_fr2x16", BFIN_BUILTIN_NEG_2X16, 0 },
5838 { CODE_FOR_ssabsv2hi2, "__builtin_bfin_abs_fr2x16", BFIN_BUILTIN_ABS_2X16, 0 }
5841 /* Errors in the source file can cause expand_expr to return const0_rtx
5842 where we expect a vector. To avoid crashing, use one of the vector
5843 clear instructions. */
5844 static rtx
5845 safe_vector_operand (rtx x, enum machine_mode mode)
5847 if (x != const0_rtx)
5848 return x;
5849 x = gen_reg_rtx (SImode);
5851 emit_insn (gen_movsi (x, CONST0_RTX (SImode)));
5852 return gen_lowpart (mode, x);
5855 /* Subroutine of bfin_expand_builtin to take care of binop insns. MACFLAG is -1
5856 if this is a normal binary op, or one of the MACFLAG_xxx constants. */
5858 static rtx
5859 bfin_expand_binop_builtin (enum insn_code icode, tree exp, rtx target,
5860 int macflag)
5862 rtx pat;
5863 tree arg0 = CALL_EXPR_ARG (exp, 0);
5864 tree arg1 = CALL_EXPR_ARG (exp, 1);
5865 rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
5866 rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
5867 enum machine_mode op0mode = GET_MODE (op0);
5868 enum machine_mode op1mode = GET_MODE (op1);
5869 enum machine_mode tmode = insn_data[icode].operand[0].mode;
5870 enum machine_mode mode0 = insn_data[icode].operand[1].mode;
5871 enum machine_mode mode1 = insn_data[icode].operand[2].mode;
5873 if (VECTOR_MODE_P (mode0))
5874 op0 = safe_vector_operand (op0, mode0);
5875 if (VECTOR_MODE_P (mode1))
5876 op1 = safe_vector_operand (op1, mode1);
5878 if (! target
5879 || GET_MODE (target) != tmode
5880 || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
5881 target = gen_reg_rtx (tmode);
5883 if ((op0mode == SImode || op0mode == VOIDmode) && mode0 == HImode)
5885 op0mode = HImode;
5886 op0 = gen_lowpart (HImode, op0);
5888 if ((op1mode == SImode || op1mode == VOIDmode) && mode1 == HImode)
5890 op1mode = HImode;
5891 op1 = gen_lowpart (HImode, op1);
5893 /* In case the insn wants input operands in modes different from
5894 the result, abort. */
5895 gcc_assert ((op0mode == mode0 || op0mode == VOIDmode)
5896 && (op1mode == mode1 || op1mode == VOIDmode));
5898 if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
5899 op0 = copy_to_mode_reg (mode0, op0);
5900 if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
5901 op1 = copy_to_mode_reg (mode1, op1);
5903 if (macflag == -1)
5904 pat = GEN_FCN (icode) (target, op0, op1);
5905 else
5906 pat = GEN_FCN (icode) (target, op0, op1, GEN_INT (macflag));
5907 if (! pat)
5908 return 0;
5910 emit_insn (pat);
5911 return target;
5914 /* Subroutine of bfin_expand_builtin to take care of unop insns. */
5916 static rtx
5917 bfin_expand_unop_builtin (enum insn_code icode, tree exp,
5918 rtx target)
5920 rtx pat;
5921 tree arg0 = CALL_EXPR_ARG (exp, 0);
5922 rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
5923 enum machine_mode op0mode = GET_MODE (op0);
5924 enum machine_mode tmode = insn_data[icode].operand[0].mode;
5925 enum machine_mode mode0 = insn_data[icode].operand[1].mode;
5927 if (! target
5928 || GET_MODE (target) != tmode
5929 || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
5930 target = gen_reg_rtx (tmode);
5932 if (VECTOR_MODE_P (mode0))
5933 op0 = safe_vector_operand (op0, mode0);
5935 if (op0mode == SImode && mode0 == HImode)
5937 op0mode = HImode;
5938 op0 = gen_lowpart (HImode, op0);
5940 gcc_assert (op0mode == mode0 || op0mode == VOIDmode);
5942 if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
5943 op0 = copy_to_mode_reg (mode0, op0);
5945 pat = GEN_FCN (icode) (target, op0);
5946 if (! pat)
5947 return 0;
5948 emit_insn (pat);
5949 return target;
5952 /* Expand an expression EXP that calls a built-in function,
5953 with result going to TARGET if that's convenient
5954 (and in mode MODE if that's convenient).
5955 SUBTARGET may be used as the target for computing one of EXP's operands.
5956 IGNORE is nonzero if the value is to be ignored. */
5958 static rtx
5959 bfin_expand_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
5960 rtx subtarget ATTRIBUTE_UNUSED,
5961 enum machine_mode mode ATTRIBUTE_UNUSED,
5962 int ignore ATTRIBUTE_UNUSED)
5964 size_t i;
5965 enum insn_code icode;
5966 const struct builtin_description *d;
5967 tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
5968 unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
5969 tree arg0, arg1, arg2;
5970 rtx op0, op1, op2, accvec, pat, tmp1, tmp2, a0reg, a1reg;
5971 enum machine_mode tmode, mode0;
5973 switch (fcode)
5975 case BFIN_BUILTIN_CSYNC:
5976 emit_insn (gen_csync ());
5977 return 0;
5978 case BFIN_BUILTIN_SSYNC:
5979 emit_insn (gen_ssync ());
5980 return 0;
5982 case BFIN_BUILTIN_DIFFHL_2X16:
5983 case BFIN_BUILTIN_DIFFLH_2X16:
5984 case BFIN_BUILTIN_SUM_2X16:
5985 arg0 = CALL_EXPR_ARG (exp, 0);
5986 op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
5987 icode = (fcode == BFIN_BUILTIN_DIFFHL_2X16 ? CODE_FOR_subhilov2hi3
5988 : fcode == BFIN_BUILTIN_DIFFLH_2X16 ? CODE_FOR_sublohiv2hi3
5989 : CODE_FOR_ssaddhilov2hi3);
5990 tmode = insn_data[icode].operand[0].mode;
5991 mode0 = insn_data[icode].operand[1].mode;
5993 if (! target
5994 || GET_MODE (target) != tmode
5995 || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
5996 target = gen_reg_rtx (tmode);
5998 if (VECTOR_MODE_P (mode0))
5999 op0 = safe_vector_operand (op0, mode0);
6001 if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
6002 op0 = copy_to_mode_reg (mode0, op0);
6004 pat = GEN_FCN (icode) (target, op0, op0);
6005 if (! pat)
6006 return 0;
6007 emit_insn (pat);
6008 return target;
6010 case BFIN_BUILTIN_MULT_1X32X32:
6011 case BFIN_BUILTIN_MULT_1X32X32NS:
6012 arg0 = CALL_EXPR_ARG (exp, 0);
6013 arg1 = CALL_EXPR_ARG (exp, 1);
6014 op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6015 op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
6016 if (! target
6017 || !register_operand (target, SImode))
6018 target = gen_reg_rtx (SImode);
6020 a1reg = gen_rtx_REG (PDImode, REG_A1);
6021 a0reg = gen_rtx_REG (PDImode, REG_A0);
6022 tmp1 = gen_lowpart (V2HImode, op0);
6023 tmp2 = gen_lowpart (V2HImode, op1);
6024 emit_insn (gen_flag_macinit1hi (a1reg,
6025 gen_lowpart (HImode, op0),
6026 gen_lowpart (HImode, op1),
6027 GEN_INT (MACFLAG_FU)));
6028 emit_insn (gen_lshrpdi3 (a1reg, a1reg, GEN_INT (16)));
6030 if (fcode == BFIN_BUILTIN_MULT_1X32X32)
6031 emit_insn (gen_flag_mul_macv2hi_parts_acconly (a0reg, a1reg, tmp1, tmp2,
6032 const1_rtx, const1_rtx,
6033 const1_rtx, const0_rtx, a1reg,
6034 const0_rtx, GEN_INT (MACFLAG_NONE),
6035 GEN_INT (MACFLAG_M)));
6036 else
6038 /* For saturating multiplication, there's exactly one special case
6039 to be handled: multiplying the smallest negative value with
6040 itself. Due to shift correction in fractional multiplies, this
6041 can overflow. Iff this happens, OP2 will contain 1, which, when
6042 added in 32 bits to the smallest negative, wraps to the largest
6043 positive, which is the result we want. */
6044 op2 = gen_reg_rtx (V2HImode);
6045 emit_insn (gen_packv2hi (op2, tmp1, tmp2, const0_rtx, const0_rtx));
6046 emit_insn (gen_movsibi (gen_rtx_REG (BImode, REG_CC),
6047 gen_lowpart (SImode, op2)));
6048 emit_insn (gen_flag_mul_macv2hi_parts_acconly_andcc0 (a0reg, a1reg, tmp1, tmp2,
6049 const1_rtx, const1_rtx,
6050 const1_rtx, const0_rtx, a1reg,
6051 const0_rtx, GEN_INT (MACFLAG_NONE),
6052 GEN_INT (MACFLAG_M)));
6053 op2 = gen_reg_rtx (SImode);
6054 emit_insn (gen_movbisi (op2, gen_rtx_REG (BImode, REG_CC)));
6056 emit_insn (gen_flag_machi_parts_acconly (a1reg, tmp2, tmp1,
6057 const1_rtx, const0_rtx,
6058 a1reg, const0_rtx, GEN_INT (MACFLAG_M)));
6059 emit_insn (gen_ashrpdi3 (a1reg, a1reg, GEN_INT (15)));
6060 emit_insn (gen_sum_of_accumulators (target, a0reg, a0reg, a1reg));
6061 if (fcode == BFIN_BUILTIN_MULT_1X32X32NS)
6062 emit_insn (gen_addsi3 (target, target, op2));
6063 return target;
6065 case BFIN_BUILTIN_CPLX_MUL_16:
6066 case BFIN_BUILTIN_CPLX_MUL_16_S40:
6067 arg0 = CALL_EXPR_ARG (exp, 0);
6068 arg1 = CALL_EXPR_ARG (exp, 1);
6069 op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6070 op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
6071 accvec = gen_reg_rtx (V2PDImode);
6073 if (! target
6074 || GET_MODE (target) != V2HImode
6075 || ! (*insn_data[icode].operand[0].predicate) (target, V2HImode))
6076 target = gen_reg_rtx (tmode);
6077 if (! register_operand (op0, GET_MODE (op0)))
6078 op0 = copy_to_mode_reg (GET_MODE (op0), op0);
6079 if (! register_operand (op1, GET_MODE (op1)))
6080 op1 = copy_to_mode_reg (GET_MODE (op1), op1);
6082 if (fcode == BFIN_BUILTIN_CPLX_MUL_16)
6083 emit_insn (gen_flag_macinit1v2hi_parts (accvec, op0, op1, const0_rtx,
6084 const0_rtx, const0_rtx,
6085 const1_rtx, GEN_INT (MACFLAG_W32)));
6086 else
6087 emit_insn (gen_flag_macinit1v2hi_parts (accvec, op0, op1, const0_rtx,
6088 const0_rtx, const0_rtx,
6089 const1_rtx, GEN_INT (MACFLAG_NONE)));
6090 emit_insn (gen_flag_macv2hi_parts (target, op0, op1, const1_rtx,
6091 const1_rtx, const1_rtx,
6092 const0_rtx, accvec, const1_rtx, const0_rtx,
6093 GEN_INT (MACFLAG_NONE), accvec));
6095 return target;
6097 case BFIN_BUILTIN_CPLX_MAC_16:
6098 case BFIN_BUILTIN_CPLX_MSU_16:
6099 case BFIN_BUILTIN_CPLX_MAC_16_S40:
6100 case BFIN_BUILTIN_CPLX_MSU_16_S40:
6101 arg0 = CALL_EXPR_ARG (exp, 0);
6102 arg1 = CALL_EXPR_ARG (exp, 1);
6103 arg2 = CALL_EXPR_ARG (exp, 2);
6104 op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6105 op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
6106 op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
6107 accvec = gen_reg_rtx (V2PDImode);
6109 if (! target
6110 || GET_MODE (target) != V2HImode
6111 || ! (*insn_data[icode].operand[0].predicate) (target, V2HImode))
6112 target = gen_reg_rtx (tmode);
6113 if (! register_operand (op1, GET_MODE (op1)))
6114 op1 = copy_to_mode_reg (GET_MODE (op1), op1);
6115 if (! register_operand (op2, GET_MODE (op2)))
6116 op2 = copy_to_mode_reg (GET_MODE (op2), op2);
6118 tmp1 = gen_reg_rtx (SImode);
6119 tmp2 = gen_reg_rtx (SImode);
6120 emit_insn (gen_ashlsi3 (tmp1, gen_lowpart (SImode, op0), GEN_INT (16)));
6121 emit_move_insn (tmp2, gen_lowpart (SImode, op0));
6122 emit_insn (gen_movstricthi_1 (gen_lowpart (HImode, tmp2), const0_rtx));
6123 emit_insn (gen_load_accumulator_pair (accvec, tmp1, tmp2));
6124 if (fcode == BFIN_BUILTIN_CPLX_MAC_16
6125 || fcode == BFIN_BUILTIN_CPLX_MSU_16)
6126 emit_insn (gen_flag_macv2hi_parts_acconly (accvec, op1, op2, const0_rtx,
6127 const0_rtx, const0_rtx,
6128 const1_rtx, accvec, const0_rtx,
6129 const0_rtx,
6130 GEN_INT (MACFLAG_W32)));
6131 else
6132 emit_insn (gen_flag_macv2hi_parts_acconly (accvec, op1, op2, const0_rtx,
6133 const0_rtx, const0_rtx,
6134 const1_rtx, accvec, const0_rtx,
6135 const0_rtx,
6136 GEN_INT (MACFLAG_NONE)));
6137 if (fcode == BFIN_BUILTIN_CPLX_MAC_16
6138 || fcode == BFIN_BUILTIN_CPLX_MAC_16_S40)
6140 tmp1 = const1_rtx;
6141 tmp2 = const0_rtx;
6143 else
6145 tmp1 = const0_rtx;
6146 tmp2 = const1_rtx;
6148 emit_insn (gen_flag_macv2hi_parts (target, op1, op2, const1_rtx,
6149 const1_rtx, const1_rtx,
6150 const0_rtx, accvec, tmp1, tmp2,
6151 GEN_INT (MACFLAG_NONE), accvec));
6153 return target;
6155 case BFIN_BUILTIN_CPLX_SQU:
6156 arg0 = CALL_EXPR_ARG (exp, 0);
6157 op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6158 accvec = gen_reg_rtx (V2PDImode);
6159 icode = CODE_FOR_flag_mulv2hi;
6160 tmp1 = gen_reg_rtx (V2HImode);
6161 tmp2 = gen_reg_rtx (V2HImode);
6163 if (! target
6164 || GET_MODE (target) != V2HImode
6165 || ! (*insn_data[icode].operand[0].predicate) (target, V2HImode))
6166 target = gen_reg_rtx (V2HImode);
6167 if (! register_operand (op0, GET_MODE (op0)))
6168 op0 = copy_to_mode_reg (GET_MODE (op0), op0);
6170 emit_insn (gen_flag_mulv2hi (tmp1, op0, op0, GEN_INT (MACFLAG_NONE)));
6172 emit_insn (gen_flag_mulhi_parts (tmp2, op0, op0, const0_rtx,
6173 const0_rtx, const1_rtx,
6174 GEN_INT (MACFLAG_NONE)));
6176 emit_insn (gen_ssaddhi3_parts (target, tmp2, tmp2, const1_rtx,
6177 const0_rtx, const0_rtx));
6179 emit_insn (gen_sssubhi3_parts (target, tmp1, tmp1, const0_rtx,
6180 const0_rtx, const1_rtx));
6182 return target;
6184 default:
6185 break;
6188 for (i = 0, d = bdesc_2arg; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
6189 if (d->code == fcode)
6190 return bfin_expand_binop_builtin (d->icode, exp, target,
6191 d->macflag);
6193 for (i = 0, d = bdesc_1arg; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
6194 if (d->code == fcode)
6195 return bfin_expand_unop_builtin (d->icode, exp, target);
6197 gcc_unreachable ();
6200 #undef TARGET_INIT_BUILTINS
6201 #define TARGET_INIT_BUILTINS bfin_init_builtins
6203 #undef TARGET_EXPAND_BUILTIN
6204 #define TARGET_EXPAND_BUILTIN bfin_expand_builtin
6206 #undef TARGET_ASM_GLOBALIZE_LABEL
6207 #define TARGET_ASM_GLOBALIZE_LABEL bfin_globalize_label
6209 #undef TARGET_ASM_FILE_START
6210 #define TARGET_ASM_FILE_START output_file_start
6212 #undef TARGET_ATTRIBUTE_TABLE
6213 #define TARGET_ATTRIBUTE_TABLE bfin_attribute_table
6215 #undef TARGET_COMP_TYPE_ATTRIBUTES
6216 #define TARGET_COMP_TYPE_ATTRIBUTES bfin_comp_type_attributes
6218 #undef TARGET_RTX_COSTS
6219 #define TARGET_RTX_COSTS bfin_rtx_costs
6221 #undef TARGET_ADDRESS_COST
6222 #define TARGET_ADDRESS_COST bfin_address_cost
6224 #undef TARGET_ASM_INTEGER
6225 #define TARGET_ASM_INTEGER bfin_assemble_integer
6227 #undef TARGET_MACHINE_DEPENDENT_REORG
6228 #define TARGET_MACHINE_DEPENDENT_REORG bfin_reorg
6230 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
6231 #define TARGET_FUNCTION_OK_FOR_SIBCALL bfin_function_ok_for_sibcall
6233 #undef TARGET_ASM_OUTPUT_MI_THUNK
6234 #define TARGET_ASM_OUTPUT_MI_THUNK bfin_output_mi_thunk
6235 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
6236 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true
6238 #undef TARGET_SCHED_ADJUST_COST
6239 #define TARGET_SCHED_ADJUST_COST bfin_adjust_cost
6241 #undef TARGET_SCHED_ISSUE_RATE
6242 #define TARGET_SCHED_ISSUE_RATE bfin_issue_rate
6244 #undef TARGET_PROMOTE_PROTOTYPES
6245 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
6246 #undef TARGET_PROMOTE_FUNCTION_ARGS
6247 #define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_const_tree_true
6248 #undef TARGET_PROMOTE_FUNCTION_RETURN
6249 #define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_const_tree_true
6251 #undef TARGET_ARG_PARTIAL_BYTES
6252 #define TARGET_ARG_PARTIAL_BYTES bfin_arg_partial_bytes
6254 #undef TARGET_PASS_BY_REFERENCE
6255 #define TARGET_PASS_BY_REFERENCE bfin_pass_by_reference
6257 #undef TARGET_SETUP_INCOMING_VARARGS
6258 #define TARGET_SETUP_INCOMING_VARARGS setup_incoming_varargs
6260 #undef TARGET_STRUCT_VALUE_RTX
6261 #define TARGET_STRUCT_VALUE_RTX bfin_struct_value_rtx
6263 #undef TARGET_VECTOR_MODE_SUPPORTED_P
6264 #define TARGET_VECTOR_MODE_SUPPORTED_P bfin_vector_mode_supported_p
6266 #undef TARGET_HANDLE_OPTION
6267 #define TARGET_HANDLE_OPTION bfin_handle_option
6269 #undef TARGET_DEFAULT_TARGET_FLAGS
6270 #define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
6272 #undef TARGET_SECONDARY_RELOAD
6273 #define TARGET_SECONDARY_RELOAD bfin_secondary_reload
6275 #undef TARGET_DELEGITIMIZE_ADDRESS
6276 #define TARGET_DELEGITIMIZE_ADDRESS bfin_delegitimize_address
6278 #undef TARGET_CANNOT_FORCE_CONST_MEM
6279 #define TARGET_CANNOT_FORCE_CONST_MEM bfin_cannot_force_const_mem
6281 #undef TARGET_RETURN_IN_MEMORY
6282 #define TARGET_RETURN_IN_MEMORY bfin_return_in_memory
6284 struct gcc_target targetm = TARGET_INITIALIZER;