OSDN Git Service

43682a3dd57cf69a633277e00cb8c33572c67e3b
[pf3gnuchains/gcc-fork.git] / gcc / config / bfin / bfin.c
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.
4
5    This file is part of GCC.
6
7    GCC is free software; you can redistribute it and/or modify it
8    under the terms of the GNU General Public License as published
9    by the Free Software Foundation; either version 3, or (at your
10    option) any later version.
11
12    GCC is distributed in the hope that it will be useful, but WITHOUT
13    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
15    License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with GCC; see the file COPYING3.  If not see
19    <http://www.gnu.org/licenses/>.  */
20
21 #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"
58
59 /* A C structure for machine-specific, per-function data.
60    This is added to the cfun structure.  */
61 struct GTY(()) machine_function
62 {
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;
68 };
69
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;
73
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;
78
79 int max_arg_registers = 0;
80
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;
86
87 static int arg_regs[] = FUNCTION_ARG_REGISTERS;
88
89 /* Nonzero if -mshared-library-id was given.  */
90 static int bfin_lib_id_given;
91
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;
95
96 /* Determines whether we run variable tracking in machine dependent
97    reorganization.  */
98 static int bfin_flag_var_tracking;
99
100 /* -mcpu support */
101 bfin_cpu_t bfin_cpu_type = BFIN_CPU_UNKNOWN;
102
103 /* -msi-revision support. There are three special values:
104    -1      -msi-revision=none.
105    0xffff  -msi-revision=any.  */
106 int bfin_si_revision;
107
108 /* The workarounds enabled */
109 unsigned int bfin_workarounds = 0;
110
111 struct bfin_cpu
112 {
113   const char *name;
114   bfin_cpu_t type;
115   int si_revision;
116   unsigned int workarounds;
117 };
118
119 struct bfin_cpu bfin_cpus[] =
120 {
121   {"bf512", BFIN_CPU_BF512, 0x0000,
122    WA_SPECULATIVE_LOADS},
123
124   {"bf514", BFIN_CPU_BF514, 0x0000,
125    WA_SPECULATIVE_LOADS},
126
127   {"bf516", BFIN_CPU_BF516, 0x0000,
128    WA_SPECULATIVE_LOADS},
129
130   {"bf518", BFIN_CPU_BF518, 0x0000,
131    WA_SPECULATIVE_LOADS},
132
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},
139
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},
146
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},
153
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},
160
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},
167
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},
174
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},
185
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},
196
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},
207
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},
216
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},
225
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},
234
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},
244
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},
255
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},
262
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},
269
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},
276
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},
283
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},
290
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},
299
300   {NULL, 0, 0, 0}
301 };
302
303 int splitting_for_sched;
304
305 static void
306 bfin_globalize_label (FILE *stream, const char *name)
307 {
308   fputs (".global ", stream);
309   assemble_name (stream, name);
310   fputc (';',stream);
311   fputc ('\n',stream);
312 }
313
314 static void 
315 output_file_start (void) 
316 {
317   FILE *file = asm_out_file;
318   int i;
319
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;
326
327   fprintf (file, ".file \"%s\";\n", input_filename);
328   
329   for (i = 0; arg_regs[i] >= 0; i++)
330     ;
331   max_arg_registers = i;        /* how many arg reg used  */
332 }
333
334 /* Called early in the compilation to conditionally modify
335    fixed_regs/call_used_regs.  */
336
337 void 
338 conditional_register_usage (void)
339 {
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);
343 }
344
345 /* Examine machine-dependent attributes of function type FUNTYPE and return its
346    type.  See the definition of E_FUNKIND.  */
347
348 static e_funkind
349 funkind (const_tree funtype)
350 {
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;
360 }
361 \f
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.  */
367
368 static rtx
369 legitimize_pic_address (rtx orig, rtx reg, rtx picreg)
370 {
371   rtx addr = orig;
372   rtx new_rtx = orig;
373
374   if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == LABEL_REF)
375     {
376       int unspec;
377       rtx tmp;
378
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;
386
387       if (reg == 0)
388         {
389           gcc_assert (can_create_pseudo_p ());
390           reg = gen_reg_rtx (Pmode);
391         }
392
393       tmp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), unspec);
394       new_rtx = gen_const_mem (Pmode, gen_rtx_PLUS (Pmode, picreg, tmp));
395
396       emit_move_insn (reg, new_rtx);
397       if (picreg == pic_offset_table_rtx)
398         crtl->uses_pic_offset_table = 1;
399       return reg;
400     }
401
402   else if (GET_CODE (addr) == CONST || GET_CODE (addr) == PLUS)
403     {
404       rtx base;
405
406       if (GET_CODE (addr) == CONST)
407         {
408           addr = XEXP (addr, 0);
409           gcc_assert (GET_CODE (addr) == PLUS);
410         }
411
412       if (XEXP (addr, 0) == picreg)
413         return orig;
414
415       if (reg == 0)
416         {
417           gcc_assert (can_create_pseudo_p ());
418           reg = gen_reg_rtx (Pmode);
419         }
420
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);
425
426       if (GET_CODE (addr) == CONST_INT)
427         {
428           gcc_assert (! reload_in_progress && ! reload_completed);
429           addr = force_reg (Pmode, addr);
430         }
431
432       if (GET_CODE (addr) == PLUS && CONSTANT_P (XEXP (addr, 1)))
433         {
434           base = gen_rtx_PLUS (Pmode, base, XEXP (addr, 0));
435           addr = XEXP (addr, 1);
436         }
437
438       return gen_rtx_PLUS (Pmode, base, addr);
439     }
440
441   return new_rtx;
442 }
443 \f
444 /* Stack frame layout. */
445
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)
451 {
452   if (D_REGNO_P (regno))
453     {
454       bool is_eh_return_reg = false;
455       if (crtl->calls_eh_return)
456         {
457           unsigned j;
458           for (j = 0; ; j++)
459             {
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;
465             }
466         }
467
468       return (is_eh_return_reg
469               || (df_regs_ever_live_p (regno)
470                   && !fixed_regs[regno]
471                   && (is_inthandler || !call_used_regs[regno])));
472     }
473   else if (P_REGNO_P (regno))
474     {
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))));
485     }
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])));
490
491 }
492
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.  */
500
501 static int
502 n_dregs_to_save (bool is_inthandler, bool consecutive)
503 {
504   int count = 0;
505   unsigned i;
506
507   for (i = REG_R7 + 1; i-- != REG_R0;)
508     {
509       if (must_save_p (is_inthandler, i))
510         count++;
511       else if (consecutive)
512         return count;
513     }
514   return count;
515 }
516
517 /* Like n_dregs_to_save, but compute number of PREGS to save.  */
518
519 static int
520 n_pregs_to_save (bool is_inthandler, bool consecutive)
521 {
522   int count = 0;
523   unsigned i;
524
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;
531 }
532
533 /* Determine if we are going to save the frame pointer in the prologue.  */
534
535 static bool
536 must_save_fp_p (void)
537 {
538   return frame_pointer_needed || df_regs_ever_live_p (REG_FP);
539 }
540
541 static bool
542 stack_frame_needed_p (void)
543 {
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;
549 }
550
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.  */
555
556 static void
557 expand_prologue_reg_save (rtx spreg, int saveall, bool is_inthandler)
558 {
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;
568
569   if (saveall || is_inthandler)
570     {
571       rtx insn = emit_move_insn (predec, gen_rtx_REG (SImode, REG_ASTAT));
572
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)))
580           {
581             insn = emit_move_insn (predec, gen_rtx_REG (SImode, dregno));
582             RTX_FRAME_RELATED_P (insn) = 1;
583           }
584     }
585
586   if (total_consec != 0)
587     {
588       rtx insn;
589       rtx val = GEN_INT (-total_consec * 4);
590       rtx pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total_consec + 2));
591
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++)
603         {
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)
609             {
610               subpat = gen_rtx_SET (VOIDmode, memref, gen_rtx_REG (word_mode,
611                                                                    dregno++));
612               d_to_save--;
613             }
614           else
615             {
616               subpat = gen_rtx_SET (VOIDmode, memref, gen_rtx_REG (word_mode,
617                                                                    pregno++));
618             }
619           XVECEXP (pat, 0, i + 1) = subpat;
620           RTX_FRAME_RELATED_P (subpat) = 1;
621         }
622       insn = emit_insn (pat);
623       RTX_FRAME_RELATED_P (insn) = 1;
624     }
625
626   for (dregno = REG_R0; ndregs != ndregs_consec; dregno++)
627     {
628       if (must_save_p (is_inthandler, dregno))
629         {
630           rtx insn = emit_move_insn (predec, gen_rtx_REG (word_mode, dregno));
631           RTX_FRAME_RELATED_P (insn) = 1;
632           ndregs--;
633         }
634     }
635   for (pregno = REG_P0; npregs != npregs_consec; pregno++)
636     {
637       if (must_save_p (is_inthandler, pregno))
638         {
639           rtx insn = emit_move_insn (predec, gen_rtx_REG (word_mode, pregno));
640           RTX_FRAME_RELATED_P (insn) = 1;
641           npregs--;
642         }
643     }
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]))))
649       {
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;
657       }
658 }
659
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.  */
664
665 static void
666 expand_epilogue_reg_restore (rtx spreg, bool saveall, bool is_inthandler)
667 {
668   rtx postinc1 = gen_rtx_POST_INC (SImode, spreg);
669   rtx postinc = gen_rtx_MEM (SImode, postinc1);
670
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;
678
679   /* A slightly crude technique to stop flow from trying to delete "dead"
680      insns.  */
681   MEM_VOLATILE_P (postinc) = 1;
682
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]))))
688       {
689         if (i == REG_A0 || i == REG_A1)
690           {
691             rtx mem = gen_rtx_MEM (PDImode, postinc1);
692             MEM_VOLATILE_P (mem) = 1;
693             emit_move_insn (gen_rtx_REG (PDImode, i), mem);
694           }
695         else
696           emit_move_insn (gen_rtx_REG (SImode, i), postinc);
697       }
698
699   regno = REG_P5 - npregs_consec;
700   for (; npregs != npregs_consec; regno--)
701     {
702       if (must_save_p (is_inthandler, regno))
703         {
704           emit_move_insn (gen_rtx_REG (word_mode, regno), postinc);
705           npregs--;
706         }
707     }
708   regno = REG_R7 - ndregs_consec;
709   for (; ndregs != ndregs_consec; regno--)
710     {
711       if (must_save_p (is_inthandler, regno))
712         {
713           emit_move_insn (gen_rtx_REG (word_mode, regno), postinc);
714           ndregs--;
715         }
716     }
717
718   if (total_consec != 0)
719     {
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)));
725
726       if (npregs_consec > 0)
727         regno = REG_P5 + 1;
728       else
729         regno = REG_R7 + 1;
730
731       for (i = 0; i < total_consec; i++)
732         {
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);
737
738           regno--;
739           XVECEXP (pat, 0, i + 1)
740             = gen_rtx_SET (VOIDmode, gen_rtx_REG (word_mode, regno), memref);
741
742           if (npregs_consec > 0)
743             {
744               if (--npregs_consec == 0)
745                 regno = REG_R7 + 1;
746             }
747         }
748
749       insn = emit_insn (pat);
750       RTX_FRAME_RELATED_P (insn) = 1;
751     }
752   if (saveall || is_inthandler)
753     {
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);
760
761       emit_move_insn (gen_rtx_REG (SImode, REG_ASTAT), postinc);
762     }
763 }
764
765 /* Perform any needed actions needed for a function that is receiving a
766    variable number of arguments.
767
768    CUM is as above.
769
770    MODE and TYPE are the mode and type of the current parameter.
771
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
774    it.
775
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.  
778
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.  */
786
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)
792 {
793   rtx mem;
794   int i;
795
796   if (no_rtl)
797     return;
798
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.  */
803
804   for (i = cum->words + 1; i < max_arg_registers; i++)
805     {
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));
809     }
810
811   *pretend_size = 0;
812 }
813
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.  */
817
818 int
819 bfin_frame_pointer_required (void) 
820 {
821   e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
822
823   if (fkind != SUBROUTINE)
824     return 1;
825
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;
830
831   return 0;
832 }
833
834 /* Return the number of registers pushed during the prologue.  */
835
836 static int
837 n_regs_saved_by_prologue (void)
838 {
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;
848
849   if (all || stack_frame_needed_p ())
850     /* We use a LINK instruction in this case.  */
851     n += 2;
852   else
853     {
854       if (must_save_fp_p ())
855         n++;
856       if (! current_function_is_leaf)
857         n++;
858     }
859
860   if (fkind != SUBROUTINE || all)
861     {
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)
867         {
868           n += 6;
869         }
870     }
871
872   if (fkind != SUBROUTINE)
873     {
874       /* RETE/X/N.  */
875       if (lookup_attribute ("nesting", attrs))
876         n++;
877     }
878
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;
885
886   return n;
887 }
888
889 /* Return the offset between two registers, one to be eliminated, and the other
890    its replacement, at the start of a routine.  */
891
892 HOST_WIDE_INT
893 bfin_initial_elimination_offset (int from, int to)
894 {
895   HOST_WIDE_INT offset = 0;
896
897   if (from == ARG_POINTER_REGNUM)
898     offset = n_regs_saved_by_prologue () * 4;
899
900   if (to == STACK_POINTER_REGNUM)
901     {
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;
906
907       offset += get_frame_size ();
908     }
909
910   return offset;
911 }
912
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.  */
916
917 static void
918 frame_related_constant_load (rtx reg, HOST_WIDE_INT constant, bool related)
919 {
920   rtx insn;
921   rtx cst = GEN_INT (constant);
922
923   if (constant >= -32768 && constant < 65536)
924     insn = emit_move_insn (reg, cst);
925   else
926     {
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));
933     }
934   if (related)
935     RTX_FRAME_RELATED_P (insn) = 1;
936 }
937
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.  */
943
944 static void
945 add_to_reg (rtx reg, HOST_WIDE_INT value, int frame, int epilogue_p)
946 {
947   if (value == 0)
948     return;
949
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)
954     {
955       rtx tmpreg;
956       rtx tmpreg2;
957       rtx insn;
958
959       tmpreg2 = NULL_RTX;
960
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.  */
966
967       if (epilogue_p >= 0)
968         tmpreg = gen_rtx_REG (SImode, REG_P1);
969       else
970         {
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
983             {
984               tmpreg = gen_rtx_REG (SImode, REG_P1);
985               tmpreg2 = gen_rtx_REG (SImode, REG_I0);
986               emit_move_insn (tmpreg2, tmpreg);
987             }
988         }
989
990       if (frame)
991         frame_related_constant_load (tmpreg, value, TRUE);
992       else
993         insn = emit_move_insn (tmpreg, GEN_INT (value));
994
995       insn = emit_insn (gen_addsi3 (reg, reg, tmpreg));
996       if (frame)
997         RTX_FRAME_RELATED_P (insn) = 1;
998
999       if (tmpreg2 != NULL_RTX)
1000         emit_move_insn (tmpreg, tmpreg2);
1001     }
1002   else
1003     do
1004       {
1005         int size = value;
1006         rtx insn;
1007
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;
1014
1015         insn = emit_insn (gen_addsi3 (reg, reg, GEN_INT (size)));
1016         if (frame)
1017           RTX_FRAME_RELATED_P (insn) = 1;
1018         value -= size;
1019       }
1020     while (value != 0);
1021 }
1022
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).  */
1026
1027 static void
1028 emit_link_insn (rtx spreg, HOST_WIDE_INT frame_size)
1029 {
1030   HOST_WIDE_INT link_size = frame_size;
1031   rtx insn;
1032   int i;
1033
1034   if (link_size > 262140)
1035     link_size = 262140;
1036
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;
1041
1042   for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
1043     {
1044       rtx set = XVECEXP (PATTERN (insn), 0, i);
1045       gcc_assert (GET_CODE (set) == SET);
1046       RTX_FRAME_RELATED_P (set) = 1;
1047     }
1048
1049   frame_size -= link_size;
1050
1051   if (frame_size > 0)
1052     {
1053       /* Must use a call-clobbered PREG that isn't the static chain.  */
1054       rtx tmpreg = gen_rtx_REG (Pmode, REG_P1);
1055
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;
1059     }
1060 }
1061
1062 /* Return the number of bytes we must reserve for outgoing arguments
1063    in the current function's stack frame.  */
1064
1065 static HOST_WIDE_INT
1066 arg_area_size (void)
1067 {
1068   if (crtl->outgoing_args_size)
1069     {
1070       if (crtl->outgoing_args_size >= FIXED_STACK_AREA)
1071         return crtl->outgoing_args_size;
1072       else
1073         return FIXED_STACK_AREA;
1074     }
1075   return 0;
1076 }
1077
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).  */
1081
1082 static void
1083 do_link (rtx spreg, HOST_WIDE_INT frame_size, bool all)
1084 {
1085   frame_size += arg_area_size ();
1086
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
1091     {
1092       if (! current_function_is_leaf)
1093         {
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;
1099         }
1100       if (must_save_fp_p ())
1101         {
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;
1107         }
1108       add_to_reg (spreg, -frame_size, 1, 0);
1109     }
1110 }
1111
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.  */
1116
1117 static void
1118 do_unlink (rtx spreg, HOST_WIDE_INT frame_size, bool all, int epilogue_p)
1119 {
1120   frame_size += arg_area_size ();
1121
1122   if (all || stack_frame_needed_p ())
1123     emit_insn (gen_unlink ());
1124   else 
1125     {
1126       rtx postinc = gen_rtx_MEM (Pmode, gen_rtx_POST_INC (Pmode, spreg));
1127
1128       add_to_reg (spreg, frame_size, 0, epilogue_p);
1129       if (must_save_fp_p ())
1130         {
1131           rtx fpreg = gen_rtx_REG (Pmode, REG_FP);
1132           emit_move_insn (fpreg, postinc);
1133           emit_use (fpreg);
1134         }
1135       if (! current_function_is_leaf)
1136         {
1137           emit_move_insn (bfin_rets_rtx, postinc);
1138           emit_use (bfin_rets_rtx);
1139         }
1140     }
1141 }
1142
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).  */
1146
1147 static void
1148 expand_interrupt_handler_prologue (rtx spreg, e_funkind fkind, bool all)
1149 {
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);
1156
1157   if (kspisusp)
1158     {
1159       insn = emit_move_insn (spreg, gen_rtx_REG (Pmode, REG_USP));
1160       RTX_FRAME_RELATED_P (insn) = 1;
1161     }
1162
1163   /* We need space on the stack in case we need to save the argument
1164      registers.  */
1165   if (fkind == EXCPT_HANDLER)
1166     {
1167       insn = emit_insn (gen_addsi3 (spreg, spreg, GEN_INT (-12)));
1168       RTX_FRAME_RELATED_P (insn) = 1;
1169     }
1170
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);
1176
1177   if (ENABLE_WA_05000283 || ENABLE_WA_05000315)
1178     {
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));
1185     }
1186   
1187   if (lookup_attribute ("nesting", attrs))
1188     {
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;
1194     }
1195
1196   do_link (spreg, frame_size, all);
1197
1198   if (fkind == EXCPT_HANDLER)
1199     {
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;
1204
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)));
1211     }
1212 }
1213
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).  */
1217
1218 static void
1219 expand_interrupt_handler_epilogue (rtx spreg, e_funkind fkind, bool all)
1220 {
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);
1224
1225   /* A slightly crude technique to stop flow from trying to delete "dead"
1226      insns.  */
1227   MEM_VOLATILE_P (postinc) = 1;
1228
1229   do_unlink (spreg, get_frame_size (), all, 1);
1230
1231   if (lookup_attribute ("nesting", attrs))
1232     {
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);
1237     }
1238
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;
1243
1244   expand_epilogue_reg_restore (spreg, all, true);
1245
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)));
1250
1251   emit_jump_insn (gen_return_internal (GEN_INT (fkind)));
1252 }
1253
1254 /* Used while emitting the prologue to generate code to load the correct value
1255    into the PIC register, which is passed in DEST.  */
1256
1257 static rtx
1258 bfin_load_pic_reg (rtx dest)
1259 {
1260   struct cgraph_local_info *i = NULL;
1261   rtx addr, insn;
1262  
1263   i = cgraph_local_info (current_function_decl);
1264  
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;
1269       
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;
1278 }
1279
1280 /* Generate RTL for the prologue of the current function.  */
1281
1282 void
1283 bfin_expand_prologue (void)
1284 {
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;
1291
1292   if (fkind != SUBROUTINE)
1293     {
1294       expand_interrupt_handler_prologue (spreg, fkind, all);
1295       return;
1296     }
1297
1298   if (crtl->limit_stack
1299       || (TARGET_STACK_CHECK_L1
1300           && !DECL_NO_LIMIT_STACK (current_function_decl)))
1301     {
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);
1307
1308       if (!lim)
1309         {
1310           emit_move_insn (p2reg, gen_int_mode (0xFFB00000, SImode));
1311           emit_move_insn (p2reg, gen_rtx_MEM (Pmode, p2reg));
1312           lim = p2reg;
1313         }
1314       if (GET_CODE (lim) == SYMBOL_REF)
1315         {
1316           if (TARGET_ID_SHARED_LIBRARY)
1317             {
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;
1327             }
1328           else
1329             {
1330               rtx limit = plus_constant (lim, offset);
1331               emit_move_insn (p2reg, limit);
1332               lim = p2reg;
1333             }
1334         }
1335       else
1336         {
1337           if (lim != p2reg)
1338             emit_move_insn (p2reg, lim);
1339           add_to_reg (p2reg, offset, 0, 0);
1340           lim = p2reg;
1341         }
1342       emit_insn (gen_compare_lt (bfin_cc_rtx, spreg, lim));
1343       emit_insn (gen_trapifcc ());
1344     }
1345   expand_prologue_reg_save (spreg, all, false);
1346
1347   do_link (spreg, frame_size, false);
1348
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);
1354 }
1355
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.  */
1360
1361 void
1362 bfin_expand_epilogue (int need_return, int eh_return, bool sibcall_p)
1363 {
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;
1369
1370   if (fkind != SUBROUTINE)
1371     {
1372       expand_interrupt_handler_epilogue (spreg, fkind, all);
1373       return;
1374     }
1375
1376   do_unlink (spreg, get_frame_size (), false, e);
1377
1378   expand_epilogue_reg_restore (spreg, all, false);
1379
1380   /* Omit the return insn if this is for a sibcall.  */
1381   if (! need_return)
1382     return;
1383
1384   if (eh_return)
1385     emit_insn (gen_addsi3 (spreg, spreg, gen_rtx_REG (Pmode, REG_P2)));
1386
1387   emit_jump_insn (gen_return_internal (GEN_INT (SUBROUTINE)));
1388 }
1389 \f
1390 /* Return nonzero if register OLD_REG can be renamed to register NEW_REG.  */
1391
1392 int
1393 bfin_hard_regno_rename_ok (unsigned int old_reg ATTRIBUTE_UNUSED,
1394                            unsigned int new_reg)
1395 {
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.  */
1399
1400   if (funkind (TREE_TYPE (current_function_decl)) != SUBROUTINE
1401       && !df_regs_ever_live_p (new_reg))
1402     return 0;
1403
1404   return 1;
1405 }
1406
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.  */
1410
1411 rtx
1412 bfin_return_addr_rtx (int count)
1413 {
1414   if (count != 0)
1415     return const0_rtx;
1416
1417   return get_hard_reg_initial_val (Pmode, REG_RETS);
1418 }
1419
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.
1423
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.
1426
1427    MODE is the mode of the memory reference.  */
1428
1429 rtx
1430 legitimize_address (rtx x ATTRIBUTE_UNUSED, rtx oldx ATTRIBUTE_UNUSED,
1431                     enum machine_mode mode ATTRIBUTE_UNUSED)
1432 {
1433   return NULL_RTX;
1434 }
1435
1436 static rtx
1437 bfin_delegitimize_address (rtx orig_x)
1438 {
1439   rtx x = orig_x;
1440
1441   if (GET_CODE (x) != MEM)
1442     return orig_x;
1443
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);
1451
1452   return orig_x;
1453 }
1454
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.  */
1458
1459 int
1460 effective_address_32bit_p (rtx op, enum machine_mode mode) 
1461 {
1462   HOST_WIDE_INT offset;
1463
1464   mode = GET_MODE (op);
1465   op = XEXP (op, 0);
1466
1467   if (GET_CODE (op) != PLUS)
1468     {
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;
1472     }
1473
1474   if (GET_CODE (XEXP (op, 1)) == UNSPEC)
1475     return 1;
1476
1477   offset = INTVAL (XEXP (op, 1));
1478
1479   /* All byte loads use a 16-bit offset.  */
1480   if (GET_MODE_SIZE (mode) == 1)
1481     return 1;
1482
1483   if (GET_MODE_SIZE (mode) == 4)
1484     {
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;
1490     }
1491
1492   /* Must be HImode now.  */
1493   return offset < 0 || offset > 30;
1494 }
1495
1496 /* Returns true if X is a memory reference using an I register.  */
1497 bool
1498 bfin_dsp_memref_p (rtx x)
1499 {
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);
1507 }
1508
1509 /* Return cost of the memory address ADDR.
1510    All addressing modes are equally cheap on the Blackfin.  */
1511
1512 static int
1513 bfin_address_cost (rtx addr ATTRIBUTE_UNUSED, bool speed ATTRIBUTE_UNUSED)
1514 {
1515   return 1;
1516 }
1517
1518 /* Subroutine of print_operand; used to print a memory reference X to FILE.  */
1519
1520 void
1521 print_address_operand (FILE *file, rtx x)
1522 {
1523   switch (GET_CODE (x))
1524     {
1525     case PLUS:
1526       output_address (XEXP (x, 0));
1527       fprintf (file, "+");
1528       output_address (XEXP (x, 1));
1529       break;
1530
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;
1543
1544     default:
1545       gcc_assert (GET_CODE (x) != MEM);
1546       print_operand (file, x, 0);
1547       break;
1548     }
1549 }
1550
1551 /* Adding intp DImode support by Tony
1552  * -- Q: (low  word)
1553  * -- R: (high word)
1554  */
1555
1556 void
1557 print_operand (FILE *file, rtx x, char code)
1558 {
1559   enum machine_mode mode;
1560
1561   if (code == '!')
1562     {
1563       if (GET_MODE (current_output_insn) == SImode)
1564         fprintf (file, " ||");
1565       else
1566         fprintf (file, ";");
1567       return;
1568     }
1569
1570   mode = GET_MODE (x);
1571
1572   switch (code)
1573     {
1574     case 'j':
1575       switch (GET_CODE (x))
1576         {
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");
1609         }
1610       break;
1611     
1612     case 'J':                                    /* reverse logic */
1613       switch (GET_CODE(x))
1614         {
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");
1647         }
1648       break;
1649
1650     default:
1651       switch (GET_CODE (x))
1652         {
1653         case REG:
1654           if (code == 'h')
1655             {
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);
1660             }
1661           else if (code == 'd')
1662             {
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);
1667             }
1668           else if (code == 'w')
1669             {
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);
1674             }
1675           else if (code == 'x')
1676             {
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);
1681             }
1682           else if (code == 'v')
1683             {
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);
1690             }
1691           else if (code == 'D')
1692             {
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);
1697             }
1698           else if (code == 'H')
1699             {
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);
1704             }
1705           else if (code == 'T')
1706             {
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);
1711             }
1712           else 
1713             fprintf (file, "%s", reg_names[REGNO (x)]);
1714           break;
1715
1716         case MEM:
1717           fputc ('[', file);
1718           x = XEXP (x,0);
1719           print_address_operand (file, x);
1720           fputc (']', file);
1721           break;
1722
1723         case CONST_INT:
1724           if (code == 'M')
1725             {
1726               switch (INTVAL (x))
1727                 {
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 ();
1765                 }
1766               break;
1767             }
1768           else if (code == 'b')
1769             {
1770               if (INTVAL (x) == 0)
1771                 fputs ("+=", file);
1772               else if (INTVAL (x) == 1)
1773                 fputs ("-=", file);
1774               else
1775                 gcc_unreachable ();
1776               break;
1777             }
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));
1793
1794           /* fall through */
1795
1796         case SYMBOL_REF:
1797           output_addr_const (file, x);
1798           break;
1799
1800         case CONST_DOUBLE:
1801           output_operand_lossage ("invalid const_double operand");
1802           break;
1803
1804         case UNSPEC:
1805           switch (XINT (x, 1))
1806             {
1807             case UNSPEC_MOVE_PIC:
1808               output_addr_const (file, XVECEXP (x, 0, 0));
1809               fprintf (file, "@GOT");
1810               break;
1811
1812             case UNSPEC_MOVE_FDPIC:
1813               output_addr_const (file, XVECEXP (x, 0, 0));
1814               fprintf (file, "@GOT17M4");
1815               break;
1816
1817             case UNSPEC_FUNCDESC_GOT17M4:
1818               output_addr_const (file, XVECEXP (x, 0, 0));
1819               fprintf (file, "@FUNCDESC_GOT17M4");
1820               break;
1821
1822             case UNSPEC_LIBRARY_OFFSET:
1823               fprintf (file, "_current_shared_library_p5_offset_");
1824               break;
1825
1826             default:
1827               gcc_unreachable ();
1828             }
1829           break;
1830
1831         default:
1832           output_addr_const (file, x);
1833         }
1834     }
1835 }
1836 \f
1837 /* Argument support functions.  */
1838
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.
1844 */
1845
1846 void
1847 init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype,
1848                       rtx libname ATTRIBUTE_UNUSED)
1849 {
1850   static CUMULATIVE_ARGS zero_cum;
1851
1852   *cum = zero_cum;
1853
1854   /* Set up the number of registers to use for passing arguments.  */
1855
1856   cum->nregs = max_arg_registers;
1857   cum->arg_regs = arg_regs;
1858
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;
1865
1866   return;
1867 }
1868
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.)  */
1872
1873 void
1874 function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
1875                       int named ATTRIBUTE_UNUSED)
1876 {
1877   int count, bytes, words;
1878
1879   bytes = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
1880   words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
1881
1882   cum->words += words;
1883   cum->nregs -= words;
1884
1885   if (cum->nregs <= 0)
1886     {
1887       cum->nregs = 0;
1888       cum->arg_regs = NULL;
1889     }
1890   else
1891     {
1892       for (count = 1; count <= words; count++)
1893         cum->arg_regs++;
1894     }
1895
1896   return;
1897 }
1898
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.
1902
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).  */
1911
1912 struct rtx_def *
1913 function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
1914               int named ATTRIBUTE_UNUSED)
1915 {
1916   int bytes
1917     = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
1918
1919   if (mode == VOIDmode)
1920     /* Compute operand 2 of the call insn.  */
1921     return GEN_INT (cum->call_cookie);
1922
1923   if (bytes == -1)
1924     return NULL_RTX;
1925
1926   if (cum->nregs)
1927     return gen_rtx_REG (mode, *(cum->arg_regs));
1928
1929   return NULL_RTX;
1930 }
1931
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.
1935
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.   */
1940
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)
1945 {
1946   int bytes
1947     = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
1948   int bytes_left = cum->nregs * UNITS_PER_WORD;
1949   
1950   if (bytes == -1)
1951     return 0;
1952
1953   if (bytes_left == 0)
1954     return 0;
1955   if (bytes > bytes_left)
1956     return bytes_left;
1957   return 0;
1958 }
1959
1960 /* Variable sized types are passed by reference.  */
1961
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)
1966 {
1967   return type && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST;
1968 }
1969
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.  */
1973
1974 static bool
1975 bfin_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
1976 {
1977   int size = int_size_in_bytes (type);
1978   return size > 2 * UNITS_PER_WORD || size == -1;
1979 }
1980
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)
1986 {
1987   return gen_rtx_REG (Pmode, REG_P0);
1988 }
1989
1990 /* Return true when register may be used to pass function parameters.  */
1991
1992 bool 
1993 function_arg_regno_p (int n)
1994 {
1995   int i;
1996   for (i = 0; arg_regs[i] != -1; i++)
1997     if (n == arg_regs[i])
1998       return true;
1999   return false;
2000 }
2001
2002 /* Returns 1 if OP contains a symbol reference */
2003
2004 int
2005 symbolic_reference_mentioned_p (rtx op)
2006 {
2007   register const char *fmt;
2008   register int i;
2009
2010   if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF)
2011     return 1;
2012
2013   fmt = GET_RTX_FORMAT (GET_CODE (op));
2014   for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
2015     {
2016       if (fmt[i] == 'E')
2017         {
2018           register int j;
2019
2020           for (j = XVECLEN (op, i) - 1; j >= 0; j--)
2021             if (symbolic_reference_mentioned_p (XVECEXP (op, i, j)))
2022               return 1;
2023         }
2024
2025       else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i)))
2026         return 1;
2027     }
2028
2029   return 0;
2030 }
2031
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.  */
2035
2036 static bool
2037 bfin_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED,
2038                               tree exp ATTRIBUTE_UNUSED)
2039 {
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;
2046
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.  */
2051
2052   if (!decl)
2053     /* Not enough information.  */
2054     return false;
2055  
2056   this_func = cgraph_local_info (current_function_decl);
2057   called_func = cgraph_local_info (decl);
2058   return !called_func->local || this_func->local;
2059 }
2060 \f
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.  */
2064
2065 void
2066 initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt)
2067 {
2068   rtx t1 = copy_to_reg (fnaddr);
2069   rtx t2 = copy_to_reg (cxt);
2070   rtx addr;
2071   int i = 0;
2072
2073   if (TARGET_FDPIC)
2074     {
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;
2079     }
2080
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));
2086
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));
2092 }
2093
2094 /* Emit insns to move operands[1] into operands[0].  */
2095
2096 void
2097 emit_pic_move (rtx *operands, enum machine_mode mode ATTRIBUTE_UNUSED)
2098 {
2099   rtx temp = reload_in_progress ? operands[0] : gen_reg_rtx (Pmode);
2100
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);
2108 }
2109
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].  */
2113
2114 bool
2115 expand_move (rtx *operands, enum machine_mode mode)
2116 {
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))
2125     {
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;
2140     }
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;
2148 }
2149 \f
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".  */
2155
2156 void
2157 split_di (rtx operands[], int num, rtx lo_half[], rtx hi_half[])
2158 {
2159   while (num--)
2160     {
2161       rtx op = operands[num];
2162
2163       /* simplify_subreg refuse to split volatile memory addresses,
2164          but we still have to handle it.  */
2165       if (GET_CODE (op) == MEM)
2166         {
2167           lo_half[num] = adjust_address (op, SImode, 0);
2168           hi_half[num] = adjust_address (op, SImode, 4);
2169         }
2170       else
2171         {
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);
2178         }
2179     }
2180 }
2181 \f
2182 bool
2183 bfin_longcall_p (rtx op, int call_cookie)
2184 {
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;
2193 }
2194
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.  */
2198
2199 void
2200 bfin_expand_call (rtx retval, rtx fnaddr, rtx callarg1, rtx cookie, int sibcall)
2201 {
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;
2208
2209   /* In an untyped call, we can get NULL for operand 2.  */
2210   if (cookie == NULL_RTX)
2211     cookie = const0_rtx;
2212
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);
2218
2219   if (TARGET_FDPIC)
2220     {
2221       int caller_has_l1_text, callee_has_l1_text;
2222
2223       caller_has_l1_text = callee_has_l1_text = 0;
2224
2225       if (lookup_attribute ("l1_text",
2226                             DECL_ATTRIBUTES (cfun->decl)) != NULL_TREE)
2227         caller_has_l1_text = 1;
2228
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;
2235
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))))
2245         {
2246           rtx addr = callee;
2247           if (! address_operand (addr, Pmode))
2248             addr = force_reg (Pmode, addr);
2249
2250           fnaddr = gen_reg_rtx (SImode);
2251           emit_insn (gen_load_funcdescsi (fnaddr, addr));
2252           fnaddr = gen_rtx_MEM (Pmode, fnaddr);
2253
2254           picreg = gen_reg_rtx (SImode);
2255           emit_insn (gen_load_funcdescsi (picreg,
2256                                           plus_constant (addr, 4)));
2257         }
2258
2259       nelts++;
2260     }
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)))))
2266     {
2267       callee = copy_to_mode_reg (Pmode, callee);
2268       fnaddr = gen_rtx_MEM (Pmode, callee);
2269     }
2270   call = gen_rtx_CALL (VOIDmode, fnaddr, callarg1);
2271
2272   if (retval)
2273     call = gen_rtx_SET (VOIDmode, retval, call);
2274
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;
2286 }
2287 \f
2288 /* Return 1 if hard register REGNO can hold a value of machine-mode MODE.  */
2289
2290 int
2291 hard_regno_mode_ok (int regno, enum machine_mode mode)
2292 {
2293   /* Allow only dregs to store value of mode HI or QI */
2294   enum reg_class rclass = REGNO_REG_CLASS (regno);
2295
2296   if (mode == CCmode)
2297     return 0;
2298
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;
2305
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;
2310
2311   if (mode == SImode
2312       && TEST_HARD_REG_BIT (reg_class_contents[PROLOGUE_REGS], regno))
2313     return 1;
2314
2315   return TEST_HARD_REG_BIT (reg_class_contents[MOST_REGS], regno);
2316 }
2317
2318 /* Implements target hook vector_mode_supported_p.  */
2319
2320 static bool
2321 bfin_vector_mode_supported_p (enum machine_mode mode)
2322 {
2323   return mode == V2HImode;
2324 }
2325
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.  */
2328
2329 int
2330 bfin_register_move_cost (enum machine_mode mode,
2331                          enum reg_class class1, enum reg_class class2)
2332 {
2333   /* These need secondary reloads, so they're more expensive.  */
2334   if ((class1 == CCREGS && class2 != DREGS)
2335       || (class1 != DREGS && class2 == CCREGS))
2336     return 4;
2337
2338   /* If optimizing for size, always prefer reg-reg over reg-memory moves.  */
2339   if (optimize_size)
2340     return 2;
2341
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;
2347
2348   if (GET_MODE_CLASS (mode) == MODE_INT)
2349     {
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;
2356     }
2357   return 2;
2358 }
2359
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'.
2363
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.  */
2367
2368 int
2369 bfin_memory_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
2370                        enum reg_class rclass,
2371                        int in ATTRIBUTE_UNUSED)
2372 {
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;
2378
2379   return 8;
2380 }
2381
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.  */
2385
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)
2389 {
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);
2395
2396   if (code == SUBREG)
2397     x = SUBREG_REG (x), code = GET_CODE (x);
2398   if (REG_P (x))
2399     {
2400       int regno = REGNO (x);
2401       if (regno >= FIRST_PSEUDO_REGISTER)
2402         regno = reg_renumber[regno];
2403
2404       if (regno == -1)
2405         code = MEM;
2406       else
2407         x_class = REGNO_REG_CLASS (regno);
2408     }
2409
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))
2414     {
2415       rtx op2 = XEXP (x, 1);
2416       int large_constant_p = ! satisfies_constraint_Ks7 (op2);
2417
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;
2429     }
2430
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);
2438
2439   if (rclass == AREGS || rclass == EVEN_AREGS || rclass == ODD_AREGS)
2440     {
2441       if (code == MEM)
2442         {
2443           sri->icode = in_p ? CODE_FOR_reload_inpdi : CODE_FOR_reload_outpdi;
2444           return NO_REGS;
2445         }
2446
2447       if (x != const0_rtx && x_class != DREGS)
2448         {
2449           return DREGS;
2450         }
2451       else
2452         return NO_REGS;
2453     }
2454
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;
2460
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;
2466
2467   return NO_REGS;
2468 }
2469 \f
2470 /* Implement TARGET_HANDLE_OPTION.  */
2471
2472 static bool
2473 bfin_handle_option (size_t code, const char *arg, int value)
2474 {
2475   switch (code)
2476     {
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;
2483
2484     case OPT_mcpu_:
2485       {
2486         const char *p, *q;
2487         int i;
2488
2489         i = 0;
2490         while ((p = bfin_cpus[i].name) != NULL)
2491           {
2492             if (strncmp (arg, p, strlen (p)) == 0)
2493               break;
2494             i++;
2495           }
2496
2497         if (p == NULL)
2498           {
2499             error ("-mcpu=%s is not valid", arg);
2500             return false;
2501           }
2502
2503         bfin_cpu_type = bfin_cpus[i].type;
2504
2505         q = arg + strlen (p);
2506
2507         if (*q == '\0')
2508           {
2509             bfin_si_revision = bfin_cpus[i].si_revision;
2510             bfin_workarounds |= bfin_cpus[i].workarounds;
2511           }
2512         else if (strcmp (q, "-none") == 0)
2513           bfin_si_revision = -1;
2514         else if (strcmp (q, "-any") == 0)
2515           {
2516             bfin_si_revision = 0xffff;
2517             while (bfin_cpus[i].type == bfin_cpu_type)
2518               {
2519                 bfin_workarounds |= bfin_cpus[i].workarounds;
2520                 i++;
2521               }
2522           }
2523         else
2524           {
2525             unsigned int si_major, si_minor;
2526             int rev_len, n;
2527
2528             rev_len = strlen (q);
2529
2530             if (sscanf (q, "-%u.%u%n", &si_major, &si_minor, &n) != 2
2531                 || n != rev_len
2532                 || si_major > 0xff || si_minor > 0xff)
2533               {
2534               invalid_silicon_revision:
2535                 error ("-mcpu=%s has invalid silicon revision", arg);
2536                 return false;
2537               }
2538
2539             bfin_si_revision = (si_major << 8) | si_minor;
2540
2541             while (bfin_cpus[i].type == bfin_cpu_type
2542                    && bfin_cpus[i].si_revision != bfin_si_revision)
2543               i++;
2544
2545             if (bfin_cpus[i].type != bfin_cpu_type)
2546               goto invalid_silicon_revision;
2547
2548             bfin_workarounds |= bfin_cpus[i].workarounds;
2549           }
2550
2551         return true;
2552       }
2553
2554     default:
2555       return true;
2556     }
2557 }
2558
2559 static struct machine_function *
2560 bfin_init_machine_status (void)
2561 {
2562   struct machine_function *f;
2563
2564   f = GGC_CNEW (struct machine_function);
2565
2566   return f;
2567 }
2568
2569 /* Implement the macro OVERRIDE_OPTIONS.  */
2570
2571 void
2572 override_options (void)
2573 {
2574   /* If processor type is not specified, enable all workarounds.  */
2575   if (bfin_cpu_type == BFIN_CPU_UNKNOWN)
2576     {
2577       int i;
2578
2579       for (i = 0; bfin_cpus[i].name != NULL; i++)
2580         bfin_workarounds |= bfin_cpus[i].workarounds;
2581
2582       bfin_si_revision = 0xffff;
2583     }
2584
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;
2589
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;
2594
2595   if (TARGET_OMIT_LEAF_FRAME_POINTER)
2596     flag_omit_frame_pointer = 1;
2597
2598   /* Library identification */
2599   if (bfin_lib_id_given && ! TARGET_ID_SHARED_LIBRARY)
2600     error ("-mshared-library-id= specified without -mid-shared-library");
2601
2602   if (stack_limit_rtx && TARGET_STACK_CHECK_L1)
2603     error ("Can't use multiple stack checking methods together.");
2604
2605   if (TARGET_ID_SHARED_LIBRARY && TARGET_FDPIC)
2606     error ("ID shared libraries and FD-PIC mode can't be used together.");
2607
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;
2615
2616   if (TARGET_ID_SHARED_LIBRARY && flag_pic == 0)
2617     flag_pic = 1;
2618
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;
2624
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;
2629
2630   if (TARGET_MULTICORE && bfin_cpu_type != BFIN_CPU_BF561)
2631     error ("-mmulticore can only be used with BF561");
2632
2633   if (TARGET_COREA && !TARGET_MULTICORE)
2634     error ("-mcorea should be used with -mmulticore");
2635
2636   if (TARGET_COREB && !TARGET_MULTICORE)
2637     error ("-mcoreb should be used with -mmulticore");
2638
2639   if (TARGET_COREA && TARGET_COREB)
2640     error ("-mcorea and -mcoreb can't be used together");
2641
2642   flag_schedule_insns = 0;
2643
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;
2648
2649   init_machine_status = bfin_init_machine_status;
2650 }
2651
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.  */
2656
2657 static int
2658 branch_dest (rtx branch)
2659 {
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);
2671 }
2672
2673 /* Return nonzero if INSN is annotated with a REG_BR_PROB note that indicates
2674    it's a branch that's predicted taken.  */
2675
2676 static int
2677 cbranch_predicted_taken_p (rtx insn)
2678 {
2679   rtx x = find_reg_note (insn, REG_BR_PROB, 0);
2680
2681   if (x)
2682     {
2683       int pred_val = INTVAL (XEXP (x, 0));
2684
2685       return pred_val >= REG_BR_PROB_BASE / 2;
2686     }
2687
2688   return 0;
2689 }
2690
2691 /* Templates for use by asm_conditional_branch.  */
2692
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;" },
2698 };
2699
2700 /* Output INSN, which is a conditional branch instruction with operands
2701    OPERANDS.
2702
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.  */
2710
2711 void
2712 asm_conditional_branch (rtx insn, rtx *operands, int n_nops, int predict_taken)
2713 {
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)
2718   */
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);
2729 }
2730
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.  */
2733
2734 rtx
2735 bfin_gen_compare (rtx cmp, enum machine_mode mode ATTRIBUTE_UNUSED)
2736 {
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);
2741
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)
2745     {
2746       gcc_assert ((code == NE || code == EQ) && op1 == const0_rtx);
2747       tem = op0, code2 = code;
2748     }
2749   else
2750     {
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;
2765       }
2766       emit_insn (gen_rtx_SET (BImode, tem,
2767                               gen_rtx_fmt_ee (code1, BImode, op0, op1)));
2768     }
2769
2770   return gen_rtx_fmt_ee (code2, BImode, tem, CONST0_RTX (BImode));
2771 }
2772 \f
2773 /* Return nonzero iff C has exactly one bit set if it is interpreted
2774    as a 32-bit constant.  */
2775
2776 int
2777 log2constp (unsigned HOST_WIDE_INT c)
2778 {
2779   c &= 0xFFFFFFFF;
2780   return c != 0 && (c & (c-1)) == 0;
2781 }
2782
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.  */
2787
2788 static int
2789 shiftr_zero (HOST_WIDE_INT *v)
2790 {
2791   unsigned HOST_WIDE_INT tmp = *v;
2792   unsigned HOST_WIDE_INT sgn;
2793   int n = 0;
2794
2795   if (tmp == 0)
2796     return 0;
2797
2798   sgn = tmp & ((unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1));
2799   while ((tmp & 0x1) == 0 && n <= 32)
2800     {
2801       tmp = (tmp >> 1) | sgn;
2802       n++;
2803     }
2804   *v = tmp;
2805   return n;
2806 }
2807
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.  */
2812
2813 int
2814 split_load_immediate (rtx operands[])
2815 {
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]);
2823
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)))
2830     {
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;
2834     }
2835
2836   tmp = val & 0xFFFF;
2837   tmp |= -(tmp & 0x8000);
2838
2839   /* If high word has one bit set or clear, try to use a bit operation.  */
2840   if (D_REGNO_P (regno))
2841     {
2842       if (log2constp (val & 0xFFFF0000))
2843         {
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;
2847         }
2848       else if (log2constp (val | 0xFFFF) && (val & 0x8000) != 0)
2849         {
2850           emit_insn (gen_movsi (operands[0], GEN_INT (tmp)));
2851           emit_insn (gen_andsi3 (operands[0], operands[0], GEN_INT (val | 0xFFFF)));
2852         }
2853     }
2854
2855   if (D_REGNO_P (regno))
2856     {
2857       if (tmp >= -64 && tmp <= 63)
2858         {
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;
2862         }
2863
2864       if ((val & 0xFFFF0000) == 0)
2865         {
2866           emit_insn (gen_movsi (operands[0], const0_rtx));
2867           emit_insn (gen_movsi_low (operands[0], operands[0], operands[1]));
2868           return 1;
2869         }
2870
2871       if ((val & 0xFFFF0000) == 0xFFFF0000)
2872         {
2873           emit_insn (gen_movsi (operands[0], constm1_rtx));
2874           emit_insn (gen_movsi_low (operands[0], operands[0], operands[1]));
2875           return 1;
2876         }
2877     }
2878
2879   /* Need DREGs for the remaining case.  */
2880   if (regno > REG_R7)
2881     return 0;
2882
2883   if (optimize_size
2884       && num_compl_zero && shifted_compl >= -64 && shifted_compl <= 63)
2885     {
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;
2893     }
2894   return 0;
2895 }
2896 \f
2897 /* Return true if the legitimate memory address for a memory operand of mode
2898    MODE.  Return false if not.  */
2899
2900 static bool
2901 bfin_valid_add (enum machine_mode mode, HOST_WIDE_INT value)
2902 {
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;
2911 }
2912
2913 static bool
2914 bfin_valid_reg_p (unsigned int regno, int strict, enum machine_mode mode,
2915                   enum rtx_code outer_code)
2916 {
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);
2921 }
2922
2923 bool
2924 bfin_legitimate_address_p (enum machine_mode mode, rtx x, int strict)
2925 {
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;
2954   }
2955   return false;
2956 }
2957
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.  */
2961
2962 static bool
2963 bfin_cannot_force_const_mem (rtx x ATTRIBUTE_UNUSED)
2964 {
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;
2970 }
2971
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.  */
2976
2977 bool
2978 bfin_legitimate_constant_p (rtx x)
2979 {
2980   rtx sym;
2981   HOST_WIDE_INT offset;
2982
2983   if (GET_CODE (x) != CONST)
2984     return true;
2985
2986   x = XEXP (x, 0);
2987   gcc_assert (GET_CODE (x) == PLUS);
2988
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);
2995
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;
3001
3002   return true;
3003 }
3004
3005 static bool
3006 bfin_rtx_costs (rtx x, int code, int outer_code, int *total, bool speed)
3007 {
3008   int cost2 = COSTS_N_INSNS (1);
3009   rtx op0, op1;
3010
3011   switch (code)
3012     {
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;
3034
3035     case CONST:
3036     case LABEL_REF:
3037     case SYMBOL_REF:
3038     case CONST_DOUBLE:
3039       *total = COSTS_N_INSNS (2);
3040       return true;
3041
3042     case PLUS:
3043       op0 = XEXP (x, 0);
3044       op1 = XEXP (x, 1);
3045       if (GET_MODE (x) == SImode)
3046         {
3047           if (GET_CODE (op0) == MULT
3048               && GET_CODE (XEXP (op0, 1)) == CONST_INT)
3049             {
3050               HOST_WIDE_INT val = INTVAL (XEXP (op0, 1));
3051               if (val == 2 || val == 4)
3052                 {
3053                   *total = cost2;
3054                   *total += rtx_cost (XEXP (op0, 0), outer_code, speed);
3055                   *total += rtx_cost (op1, outer_code, speed);
3056                   return true;
3057                 }
3058             }
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
3068         }
3069       else if (GET_MODE (x) == DImode)
3070         {
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);
3078         }
3079       return true;
3080
3081     case MINUS:
3082       if (GET_MODE (x) == DImode)
3083         *total = 6 * cost2;
3084       else
3085         *total = cost2;
3086       return true;
3087       
3088     case ASHIFT: 
3089     case ASHIFTRT:
3090     case LSHIFTRT:
3091       if (GET_MODE (x) == DImode)
3092         *total = 6 * cost2;
3093       else
3094         *total = cost2;
3095
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);
3101
3102       return true;
3103           
3104     case IOR:
3105     case AND:
3106     case XOR:
3107       op0 = XEXP (x, 0);
3108       op1 = XEXP (x, 1);
3109
3110       /* Handle special cases of IOR: rotates, ALIGN insns, movstricthi_high.  */
3111       if (code == IOR)
3112         {
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))
3117             {
3118               *total = cost2;
3119               return true;
3120             }
3121         }
3122
3123       if (GET_CODE (op0) != REG
3124           && (GET_CODE (op0) != SUBREG || GET_CODE (SUBREG_REG (op0)) != REG))
3125         *total += rtx_cost (op0, code, speed);
3126
3127       if (GET_MODE (x) == DImode)
3128         {
3129           *total = 2 * cost2;
3130           return true;
3131         }
3132       *total = cost2;
3133       if (GET_MODE (x) != SImode)
3134         return true;
3135
3136       if (code == AND)
3137         {
3138           if (! rhs_andsi3_operand (XEXP (x, 1), SImode))
3139             *total += rtx_cost (XEXP (x, 1), code, speed);
3140         }
3141       else
3142         {
3143           if (! regorlog2_operand (XEXP (x, 1), SImode))
3144             *total += rtx_cost (XEXP (x, 1), code, speed);
3145         }
3146
3147       return true;
3148
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)
3154         {
3155           *total = 2 * cost2;
3156           return true;
3157         }
3158       /* fall through */
3159
3160     case SIGN_EXTEND:
3161     case ZERO_EXTEND:
3162       *total = cost2;
3163       return true;
3164
3165     case MULT:
3166         {
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))
3172             {
3173               *total = COSTS_N_INSNS (1);
3174               op0 = XEXP (op0, 0);
3175               op1 = XEXP (op1, 0);
3176             }
3177           else if (!speed)
3178             *total = COSTS_N_INSNS (1);
3179           else
3180             *total = COSTS_N_INSNS (3);
3181
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);
3188         }
3189       return true;
3190
3191     case UDIV:
3192     case UMOD:
3193       *total = COSTS_N_INSNS (32);
3194       return true;
3195
3196     case VEC_CONCAT:
3197     case VEC_SELECT:
3198       if (outer_code == SET)
3199         *total = cost2;
3200       return true;
3201
3202     default:
3203       return false;
3204     }
3205 }
3206 \f
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;
3211
3212 int
3213 push_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
3214 {
3215   int lastdreg = 8, lastpreg = 6;
3216   int i, group;
3217
3218   first_preg_to_save = lastpreg;
3219   first_dreg_to_save = lastdreg;
3220   for (i = 1, group = 0; i < XVECLEN (op, 0) - 1; i++)
3221     {
3222       rtx t = XVECEXP (op, 0, i);
3223       rtx src, dest;
3224       int regno;
3225
3226       if (GET_CODE (t) != SET)
3227         return 0;
3228
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;
3240
3241       regno = REGNO (src);
3242       if (group == 0)
3243         {
3244           if (D_REGNO_P (regno))
3245             {
3246               group = 1;
3247               first_dreg_to_save = lastdreg = regno - REG_R0;
3248             }
3249           else if (regno >= REG_P0 && regno <= REG_P7)
3250             {
3251               group = 2;
3252               first_preg_to_save = lastpreg = regno - REG_P0;
3253             }
3254           else
3255             return 0;
3256
3257           continue;
3258         }
3259
3260       if (group == 1)
3261         {
3262           if (regno >= REG_P0 && regno <= REG_P7)
3263             {
3264               group = 2;
3265               first_preg_to_save = lastpreg = regno - REG_P0;
3266             }
3267           else if (regno != REG_R0 + lastdreg + 1)
3268             return 0;
3269           else
3270             lastdreg++;
3271         }
3272       else if (group == 2)
3273         {
3274           if (regno != REG_P0 + lastpreg + 1)
3275             return 0;
3276           lastpreg++;
3277         }
3278     }
3279   n_regs_to_save = 8 - first_dreg_to_save + 6 - first_preg_to_save;
3280   return 1;
3281 }
3282
3283 int
3284 pop_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
3285 {
3286   int lastdreg = 8, lastpreg = 6;
3287   int i, group;
3288
3289   for (i = 1, group = 0; i < XVECLEN (op, 0); i++)
3290     {
3291       rtx t = XVECEXP (op, 0, i);
3292       rtx src, dest;
3293       int regno;
3294
3295       if (GET_CODE (t) != SET)
3296         return 0;
3297
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);
3303
3304       if (i == 1)
3305         {
3306           if (! REG_P (src) || REGNO (src) != REG_SP)
3307             return 0;
3308         }
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;
3315
3316       regno = REGNO (dest);
3317       if (group == 0)
3318         {
3319           if (regno == REG_R7)
3320             {
3321               group = 1;
3322               lastdreg = 7;
3323             }
3324           else if (regno != REG_P0 + lastpreg - 1)
3325             return 0;
3326           else
3327             lastpreg--;
3328         }
3329       else if (group == 1)
3330         {
3331           if (regno != REG_R0 + lastdreg - 1)
3332             return 0;
3333           else
3334             lastdreg--;
3335         }
3336     }
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;
3341 }
3342
3343 /* Emit assembly code for one multi-register push described by INSN, with
3344    operands in OPERANDS.  */
3345
3346 void
3347 output_push_multiple (rtx insn, rtx *operands)
3348 {
3349   char buf[80];
3350   int ok;
3351   
3352   /* Validate the insn again, and compute first_[dp]reg_to_save. */
3353   ok = push_multiple_operation (PATTERN (insn), VOIDmode);
3354   gcc_assert (ok);
3355   
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);
3363
3364   output_asm_insn (buf, operands);
3365 }
3366
3367 /* Emit assembly code for one multi-register pop described by INSN, with
3368    operands in OPERANDS.  */
3369
3370 void
3371 output_pop_multiple (rtx insn, rtx *operands)
3372 {
3373   char buf[80];
3374   int ok;
3375   
3376   /* Validate the insn again, and compute first_[dp]reg_to_save. */
3377   ok = pop_multiple_operation (PATTERN (insn), VOIDmode);
3378   gcc_assert (ok);
3379
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);
3387
3388   output_asm_insn (buf, operands);
3389 }
3390
3391 /* Adjust DST and SRC by OFFSET bytes, and generate one move in mode MODE.  */
3392
3393 static void
3394 single_move_for_movmem (rtx dst, rtx src, enum machine_mode mode, HOST_WIDE_INT offset)
3395 {
3396   rtx scratch = gen_reg_rtx (mode);
3397   rtx srcmem, dstmem;
3398
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);
3403 }
3404
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.  */
3408
3409 bool
3410 bfin_expand_movmem (rtx dst, rtx src, rtx count_exp, rtx align_exp)
3411 {
3412   rtx srcreg, destreg, countreg;
3413   HOST_WIDE_INT align = 0;
3414   unsigned HOST_WIDE_INT count = 0;
3415
3416   if (GET_CODE (align_exp) == CONST_INT)
3417     align = INTVAL (align_exp);
3418   if (GET_CODE (count_exp) == CONST_INT)
3419     {
3420       count = INTVAL (count_exp);
3421 #if 0
3422       if (!TARGET_INLINE_ALL_STRINGOPS && count > 64)
3423         return false;
3424 #endif
3425     }
3426
3427   /* If optimizing for size, only do single copies inline.  */
3428   if (optimize_size)
3429     {
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;
3436     }
3437   if (align < 2 && count != 1)
3438     return false;
3439
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);
3446
3447   if (count != 0 && align >= 2)
3448     {
3449       unsigned HOST_WIDE_INT offset = 0;
3450
3451       if (align >= 4)
3452         {
3453           if ((count & ~3) == 4)
3454             {
3455               single_move_for_movmem (dst, src, SImode, offset);
3456               offset = 4;
3457             }
3458           else if (count & ~3)
3459             {
3460               HOST_WIDE_INT new_count = ((count >> 2) & 0x3fffffff) - 1;
3461               countreg = copy_to_mode_reg (Pmode, GEN_INT (new_count));
3462
3463               emit_insn (gen_rep_movsi (destreg, srcreg, countreg, destreg, srcreg));
3464               cfun->machine->has_loopreg_clobber = true;
3465             }
3466           if (count & 2)
3467             {
3468               single_move_for_movmem (dst, src, HImode, offset);
3469               offset += 2;
3470             }
3471         }
3472       else
3473         {
3474           if ((count & ~1) == 2)
3475             {
3476               single_move_for_movmem (dst, src, HImode, offset);
3477               offset = 2;
3478             }
3479           else if (count & ~1)
3480             {
3481               HOST_WIDE_INT new_count = ((count >> 1) & 0x7fffffff) - 1;
3482               countreg = copy_to_mode_reg (Pmode, GEN_INT (new_count));
3483
3484               emit_insn (gen_rep_movhi (destreg, srcreg, countreg, destreg, srcreg));
3485               cfun->machine->has_loopreg_clobber = true;
3486             }
3487         }
3488       if (count & 1)
3489         {
3490           single_move_for_movmem (dst, src, QImode, offset);
3491         }
3492       return true;
3493     }
3494   return false;
3495 }
3496 \f
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.  */
3501
3502 int
3503 bfin_local_alignment (tree type, int align)
3504 {
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;
3513 }
3514 \f
3515 /* Implement TARGET_SCHED_ISSUE_RATE.  */
3516
3517 static int
3518 bfin_issue_rate (void)
3519 {
3520   return 3;
3521 }
3522
3523 static int
3524 bfin_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
3525 {
3526   enum attr_type insn_type, dep_insn_type;
3527   int dep_insn_code_number;
3528
3529   /* Anti and output dependencies have zero cost.  */
3530   if (REG_NOTE_KIND (link) != 0)
3531     return 0;
3532
3533   dep_insn_code_number = recog_memoized (dep_insn);
3534
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;
3538
3539   insn_type = get_attr_type (insn);
3540   dep_insn_type = get_attr_type (dep_insn);
3541
3542   if (dep_insn_type == TYPE_MOVE || dep_insn_type == TYPE_MCLD)
3543     {
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);
3553     }
3554
3555   return cost;
3556 }
3557 \f
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)
3563 {
3564   if (GET_MODE (insn) == SImode)
3565     {
3566       while (GET_MODE (insn) != QImode)
3567         insn = NEXT_INSN (insn);
3568     }
3569   return NEXT_INSN (insn);
3570 }
3571
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)
3577 {
3578   insn = PREV_INSN (insn);
3579   gcc_assert (GET_MODE (insn) != SImode);
3580   if (GET_MODE (insn) == QImode)
3581     {
3582       while (GET_MODE (PREV_INSN (insn)) == SImode)
3583         insn = PREV_INSN (insn);
3584     }
3585   return insn;
3586 }
3587 \f
3588 /* Increment the counter for the number of loop instructions in the
3589    current function.  */
3590
3591 void
3592 bfin_hardware_loop (void)
3593 {
3594   cfun->machine->has_hardware_loops++;
3595 }
3596
3597 /* Maximum loop nesting depth.  */
3598 #define MAX_LOOP_DEPTH 2
3599
3600 /* Maximum size of a loop.  */
3601 #define MAX_LOOP_LENGTH 2042
3602
3603 /* Maximum distance of the LSETUP instruction from the loop start.  */
3604 #define MAX_LSETUP_DISTANCE 30
3605
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);
3610
3611 /* Information about a loop we have found (or are in the process of
3612    finding).  */
3613 struct GTY (()) loop_info
3614 {
3615   /* loop number, for dumps */
3616   int loop_no;
3617
3618   /* All edges that jump into and out of the loop.  */
3619   VEC(edge,gc) *incoming;
3620
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;
3628
3629   /* First block in the loop.  This is the one branched to by the loop_end
3630      insn.  */
3631   basic_block head;
3632
3633   /* Last block in the loop (the one with the loop_end insn).  */
3634   basic_block tail;
3635
3636   /* The successor block of the loop.  This is the one the loop_end insn
3637      falls into.  */
3638   basic_block successor;
3639
3640   /* The last instruction in the tail.  */
3641   rtx last_insn;
3642
3643   /* The loop_end insn.  */
3644   rtx loop_end;
3645
3646   /* The iteration register.  */
3647   rtx iter_reg;
3648
3649   /* The new initialization insn.  */
3650   rtx init;
3651
3652   /* The new initialization instruction.  */
3653   rtx loop_init;
3654
3655   /* The new label placed at the beginning of the loop. */
3656   rtx start_label;
3657
3658   /* The new label placed at the end of the loop. */
3659   rtx end_label;
3660
3661   /* The length of the loop.  */
3662   int length;
3663
3664   /* The nesting depth of the loop.  */
3665   int depth;
3666
3667   /* Nonzero if we can't optimize this loop.  */
3668   int bad;
3669
3670   /* True if we have visited this loop.  */
3671   int visited;
3672
3673   /* True if this loop body clobbers any of LC0, LT0, or LB0.  */
3674   int clobber_loop0;
3675
3676   /* True if this loop body clobbers any of LC1, LT1, or LB1.  */
3677   int clobber_loop1;
3678
3679   /* Next loop in the graph. */
3680   struct loop_info *next;
3681
3682   /* Immediate outer loop of this loop.  */
3683   struct loop_info *outer;
3684
3685   /* Vector of blocks only within the loop, including those within
3686      inner loops.  */
3687   VEC (basic_block,heap) *blocks;
3688
3689   /* Same information in a bitmap.  */
3690   bitmap block_bitmap;
3691
3692   /* Vector of inner loops within this loop  */
3693   VEC (loop_info,heap) *loops;
3694 };
3695
3696 static void
3697 bfin_dump_loops (loop_info loops)
3698 {
3699   loop_info loop;
3700
3701   for (loop = loops; loop; loop = loop->next)
3702     {
3703       loop_info i;
3704       basic_block b;
3705       unsigned ix;
3706
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);
3711
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, "] ");
3716
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");
3721     }
3722   fprintf (dump_file, "\n");
3723 }
3724
3725 /* Scan the blocks of LOOP (and its inferiors) looking for basic block
3726    BB. Return true, if we find it.  */
3727
3728 static bool
3729 bfin_bb_in_loop (loop_info loop, basic_block bb)
3730 {
3731   return bitmap_bit_p (loop->block_bitmap, bb->index);
3732 }
3733
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.  */
3737
3738 static bool
3739 bfin_scan_loop (loop_info loop, rtx reg, rtx loop_end)
3740 {
3741   unsigned ix;
3742   basic_block bb;
3743
3744   for (ix = 0; VEC_iterate (basic_block, loop->blocks, ix, bb); ix++)
3745     {
3746       rtx insn;
3747
3748       for (insn = BB_HEAD (bb);
3749            insn != NEXT_INSN (BB_END (bb));
3750            insn = NEXT_INSN (insn))
3751         {
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;
3758         }
3759     }
3760   return false;
3761 }
3762
3763 /* Estimate the length of INSN conservatively.  */
3764
3765 static int
3766 length_for_loop (rtx insn)
3767 {
3768   int length = 0;
3769   if (JUMP_P (insn) && any_condjump_p (insn) && !optimize_size)
3770     {
3771       if (ENABLE_WA_SPECULATIVE_SYNCS)
3772         length = 8;
3773       else if (ENABLE_WA_SPECULATIVE_LOADS)
3774         length = 6;
3775     }
3776   else if (LABEL_P (insn))
3777     {
3778       if (ENABLE_WA_SPECULATIVE_SYNCS)
3779         length = 4;
3780     }
3781
3782   if (INSN_P (insn))
3783     length += get_attr_length (insn);
3784
3785   return length;
3786 }
3787
3788 /* Optimize LOOP.  */
3789
3790 static void
3791 bfin_optimize_loop (loop_info loop)
3792 {
3793   basic_block bb;
3794   loop_info inner;
3795   rtx insn, init_insn, last_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;
3804
3805   if (loop->visited)
3806     return;
3807
3808   loop->visited = 1;
3809
3810   if (loop->bad)
3811     {
3812       if (dump_file)
3813         fprintf (dump_file, ";; loop %d bad when found\n", loop->loop_no);
3814       goto bad_loop;
3815     }
3816
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++)
3821     {
3822       bfin_optimize_loop (inner);
3823
3824       if (!inner->bad && inner_depth < inner->depth)
3825         {
3826           inner_depth = inner->depth;
3827
3828           loop->clobber_loop0 |= inner->clobber_loop0;
3829           loop->clobber_loop1 |= inner->clobber_loop1;
3830         }
3831     }
3832
3833   loop->depth = inner_depth + 1;
3834   if (loop->depth > MAX_LOOP_DEPTH)
3835     {
3836       if (dump_file)
3837         fprintf (dump_file, ";; loop %d too deep\n", loop->loop_no);
3838       goto bad_loop;
3839     }
3840
3841   /* Get the loop iteration register.  */
3842   iter_reg = loop->iter_reg;
3843
3844   if (!DPREG_P (iter_reg))
3845     {
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;
3850     }
3851
3852   if (loop->incoming_src)
3853     {
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))
3862         {
3863           gcc_assert (JUMP_P (insn));
3864           insn = PREV_INSN (insn);
3865         }
3866
3867       for (; insn && insn != loop->start_label; insn = NEXT_INSN (insn))
3868         length += length_for_loop (insn);
3869       
3870       if (!insn)
3871         {
3872           if (dump_file)
3873             fprintf (dump_file, ";; loop %d lsetup not before loop_start\n",
3874                      loop->loop_no);
3875           goto bad_loop;
3876         }
3877
3878       if (length > MAX_LSETUP_DISTANCE)
3879         {
3880           if (dump_file)
3881             fprintf (dump_file, ";; loop %d lsetup too far away\n", loop->loop_no);
3882           goto bad_loop;
3883         }
3884     }
3885
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);
3894
3895   if (!insn)
3896     {
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;
3901     }
3902
3903   loop->length = length;
3904   if (loop->length > MAX_LOOP_LENGTH)
3905     {
3906       if (dump_file)
3907         fprintf (dump_file, ";; loop %d too long\n", loop->loop_no);
3908       goto bad_loop;
3909     }
3910
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))
3913     {
3914       if (dump_file)
3915         fprintf (dump_file, ";; loop %d uses iterator\n", loop->loop_no);
3916       goto bad_loop;
3917     }
3918
3919   /* Scan all the insns to see if the loop body clobber
3920      any hardware loop registers. */
3921
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);
3928
3929   for (ix = 0; VEC_iterate (basic_block, loop->blocks, ix, bb); ix++)
3930     {
3931       rtx insn;
3932
3933       for (insn = BB_HEAD (bb);
3934            insn != NEXT_INSN (BB_END (bb));
3935            insn = NEXT_INSN (insn))
3936         {
3937           if (!INSN_P (insn))
3938             continue;
3939
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;
3944           
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;
3949         }
3950     }
3951
3952   if ((loop->clobber_loop0 && loop->clobber_loop1)
3953       || (loop->depth == MAX_LOOP_DEPTH && loop->clobber_loop0))
3954     {
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;
3960     }
3961
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.)  */
3970
3971   bb = loop->tail;
3972   last_insn = find_prev_insn_start (loop->loop_end);
3973
3974   while (1)
3975     {
3976       for (; last_insn != BB_HEAD (bb);
3977            last_insn = find_prev_insn_start (last_insn))
3978         if (INSN_P (last_insn))
3979           break;
3980
3981       if (last_insn != BB_HEAD (bb))
3982         break;
3983
3984       if (single_pred_p (bb)
3985           && single_pred (bb) != ENTRY_BLOCK_PTR)
3986         {
3987           bb = single_pred (bb);
3988           last_insn = BB_END (bb);
3989           continue;
3990         }
3991       else
3992         {
3993           last_insn = NULL_RTX;
3994           break;
3995         }
3996     }
3997
3998   if (!last_insn)
3999     {
4000       if (dump_file)
4001         fprintf (dump_file, ";; loop %d has no last instruction\n",
4002                  loop->loop_no);
4003       goto bad_loop;
4004     }
4005
4006   if (JUMP_P (last_insn) && !any_condjump_p (last_insn))
4007     {
4008       if (dump_file)
4009         fprintf (dump_file, ";; loop %d has bad last instruction\n",
4010                  loop->loop_no);
4011       goto bad_loop;
4012     }
4013   /* In all other cases, try to replace a bad last insn with a nop.  */
4014   else if (JUMP_P (last_insn)
4015            || CALL_P (last_insn)
4016            || get_attr_type (last_insn) == TYPE_SYNC
4017            || get_attr_type (last_insn) == TYPE_CALL
4018            || get_attr_seq_insns (last_insn) == SEQ_INSNS_MULTI
4019            || recog_memoized (last_insn) == CODE_FOR_return_internal
4020            || GET_CODE (PATTERN (last_insn)) == ASM_INPUT
4021            || asm_noperands (PATTERN (last_insn)) >= 0)
4022     {
4023       if (loop->length + 2 > MAX_LOOP_LENGTH)
4024         {
4025           if (dump_file)
4026             fprintf (dump_file, ";; loop %d too long\n", loop->loop_no);
4027           goto bad_loop;
4028         }
4029       if (dump_file)
4030         fprintf (dump_file, ";; loop %d has bad last insn; replace with nop\n",
4031                  loop->loop_no);
4032
4033       last_insn = emit_insn_after (gen_forced_nop (), last_insn);
4034     }
4035
4036   loop->last_insn = last_insn;
4037
4038   /* The loop is good for replacement.  */
4039   start_label = loop->start_label;
4040   end_label = gen_label_rtx ();
4041   iter_reg = loop->iter_reg;
4042
4043   if (loop->depth == 1 && !loop->clobber_loop1)
4044     {
4045       lc_reg = reg_lc1;
4046       lt_reg = reg_lt1;
4047       lb_reg = reg_lb1;
4048       loop->clobber_loop1 = 1;
4049     }
4050   else
4051     {
4052       lc_reg = reg_lc0;
4053       lt_reg = reg_lt0;
4054       lb_reg = reg_lb0;
4055       loop->clobber_loop0 = 1;
4056     }
4057
4058   /* If iter_reg is a DREG, we need generate an instruction to load
4059      the loop count into LC register. */
4060   if (D_REGNO_P (REGNO (iter_reg)))
4061     {
4062       init_insn = gen_movsi (lc_reg, iter_reg);
4063       loop_init = gen_lsetup_without_autoinit (lt_reg, start_label,
4064                                                lb_reg, end_label,
4065                                                lc_reg);
4066     }
4067   else if (P_REGNO_P (REGNO (iter_reg)))
4068     {
4069       init_insn = NULL_RTX;
4070       loop_init = gen_lsetup_with_autoinit (lt_reg, start_label,
4071                                             lb_reg, end_label,
4072                                             lc_reg, iter_reg);
4073     }
4074   else
4075     gcc_unreachable ();
4076
4077   loop->init = init_insn;
4078   loop->end_label = end_label;
4079   loop->loop_init = loop_init;
4080
4081   if (dump_file)
4082     {
4083       fprintf (dump_file, ";; replacing loop %d initializer with\n",
4084                loop->loop_no);
4085       print_rtl_single (dump_file, loop->loop_init);
4086       fprintf (dump_file, ";; replacing loop %d terminator with\n",
4087                loop->loop_no);
4088       print_rtl_single (dump_file, loop->loop_end);
4089     }
4090
4091   /* Create a sequence containing the loop setup.  */
4092   start_sequence ();
4093
4094   if (loop->init != NULL_RTX)
4095     emit_insn (loop->init);
4096   seq_end = emit_insn (loop->loop_init);
4097
4098   /* If the loop isn't entered at the top, also create a jump to the entry
4099      point.  */
4100   if (!loop->incoming_src && loop->head != loop->incoming_dest)
4101     {
4102       rtx label = BB_HEAD (loop->incoming_dest);
4103       /* If we're jumping to the final basic block in the loop, and there's
4104          only one cheap instruction before the end (typically an increment of
4105          an induction variable), we can just emit a copy here instead of a
4106          jump.  */
4107       if (loop->incoming_dest == loop->tail
4108           && next_real_insn (label) == last_insn
4109           && asm_noperands (last_insn) < 0
4110           && GET_CODE (PATTERN (last_insn)) == SET)
4111         {
4112           seq_end = emit_insn (copy_rtx (PATTERN (last_insn)));
4113         }
4114       else
4115         seq_end = emit_insn (gen_jump (label));
4116     }
4117
4118   seq = get_insns ();
4119   end_sequence ();
4120
4121   if (loop->incoming_src)
4122     {
4123       rtx prev = BB_END (loop->incoming_src);
4124       if (VEC_length (edge, loop->incoming) > 1
4125           || !(VEC_last (edge, loop->incoming)->flags & EDGE_FALLTHRU))
4126         {
4127           gcc_assert (JUMP_P (prev));
4128           prev = PREV_INSN (prev);
4129         }
4130       emit_insn_after (seq, prev);
4131     }
4132   else
4133     {
4134       basic_block new_bb;
4135       edge e;
4136       edge_iterator ei;
4137
4138 #ifdef ENABLE_CHECKING
4139       if (loop->head != loop->incoming_dest)
4140         {
4141           /* We aren't entering the loop at the top.  Since we've established
4142              that the loop is entered only at one point, this means there
4143              can't be fallthru edges into the head.  Any such fallthru edges
4144              would become invalid when we insert the new block, so verify
4145              that this does not in fact happen.  */
4146           FOR_EACH_EDGE (e, ei, loop->head->preds)
4147             gcc_assert (!(e->flags & EDGE_FALLTHRU));
4148         }
4149 #endif
4150
4151       emit_insn_before (seq, BB_HEAD (loop->head));
4152       seq = emit_label_before (gen_label_rtx (), seq);
4153
4154       new_bb = create_basic_block (seq, seq_end, loop->head->prev_bb);
4155       FOR_EACH_EDGE (e, ei, loop->incoming)
4156         {
4157           if (!(e->flags & EDGE_FALLTHRU)
4158               || e->dest != loop->head)
4159             redirect_edge_and_branch_force (e, new_bb);
4160           else
4161             redirect_edge_succ (e, new_bb);
4162         }
4163     }
4164
4165   delete_insn (loop->loop_end);
4166   /* Insert the loop end label before the last instruction of the loop.  */
4167   emit_label_before (loop->end_label, loop->last_insn);
4168
4169   return;
4170
4171  bad_loop:
4172
4173   if (dump_file)
4174     fprintf (dump_file, ";; loop %d is bad\n", loop->loop_no);
4175
4176   loop->bad = 1;
4177
4178   if (DPREG_P (loop->iter_reg))
4179     {
4180       /* If loop->iter_reg is a DREG or PREG, we can split it here
4181          without scratch register.  */
4182       rtx insn;
4183
4184       emit_insn_before (gen_addsi3 (loop->iter_reg,
4185                                     loop->iter_reg,
4186                                     constm1_rtx),
4187                         loop->loop_end);
4188
4189       emit_insn_before (gen_cmpsi (loop->iter_reg, const0_rtx),
4190                         loop->loop_end);
4191
4192       insn = emit_jump_insn_before (gen_bne (loop->start_label),
4193                                     loop->loop_end);
4194
4195       JUMP_LABEL (insn) = loop->start_label;
4196       LABEL_NUSES (loop->start_label)++;
4197       delete_insn (loop->loop_end);
4198     }
4199 }
4200
4201 /* Called from bfin_reorg_loops when a potential loop end is found.  LOOP is
4202    a newly set up structure describing the loop, it is this function's
4203    responsibility to fill most of it.  TAIL_BB and TAIL_INSN point to the
4204    loop_end insn and its enclosing basic block.  */
4205
4206 static void
4207 bfin_discover_loop (loop_info loop, basic_block tail_bb, rtx tail_insn)
4208 {
4209   unsigned dwork = 0;
4210   basic_block bb;
4211   VEC (basic_block,heap) *works = VEC_alloc (basic_block,heap,20);
4212
4213   loop->tail = tail_bb;
4214   loop->head = BRANCH_EDGE (tail_bb)->dest;
4215   loop->successor = FALLTHRU_EDGE (tail_bb)->dest;
4216   loop->loop_end = tail_insn;
4217   loop->last_insn = NULL_RTX;
4218   loop->iter_reg = SET_DEST (XVECEXP (PATTERN (tail_insn), 0, 1));
4219   loop->depth = loop->length = 0;
4220   loop->visited = 0;
4221   loop->clobber_loop0 = loop->clobber_loop1 = 0;
4222   loop->outer = NULL;
4223   loop->loops = NULL;
4224   loop->incoming = VEC_alloc (edge, gc, 2);
4225   loop->init = loop->loop_init = NULL_RTX;
4226   loop->start_label = XEXP (XEXP (SET_SRC (XVECEXP (PATTERN (tail_insn), 0, 0)), 1), 0);
4227   loop->end_label = NULL_RTX;
4228   loop->bad = 0;
4229
4230   VEC_safe_push (basic_block, heap, works, loop->head);
4231
4232   while (VEC_iterate (basic_block, works, dwork++, bb))
4233     {
4234       edge e;
4235       edge_iterator ei;
4236       if (bb == EXIT_BLOCK_PTR)
4237         {
4238           /* We've reached the exit block.  The loop must be bad. */
4239           if (dump_file)
4240             fprintf (dump_file,
4241                      ";; Loop is bad - reached exit block while scanning\n");
4242           loop->bad = 1;
4243           break;
4244         }
4245
4246       if (bitmap_bit_p (loop->block_bitmap, bb->index))
4247         continue;
4248
4249       /* We've not seen this block before.  Add it to the loop's
4250          list and then add each successor to the work list.  */
4251
4252       VEC_safe_push (basic_block, heap, loop->blocks, bb);
4253       bitmap_set_bit (loop->block_bitmap, bb->index);
4254
4255       if (bb != tail_bb)
4256         {
4257           FOR_EACH_EDGE (e, ei, bb->succs)
4258             {
4259               basic_block succ = EDGE_SUCC (bb, ei.index)->dest;
4260               if (!REGNO_REG_SET_P (df_get_live_in (succ),
4261                                     REGNO (loop->iter_reg)))
4262                 continue;
4263               if (!VEC_space (basic_block, works, 1))
4264                 {
4265                   if (dwork)
4266                     {
4267                       VEC_block_remove (basic_block, works, 0, dwork);
4268                       dwork = 0;
4269                     }
4270                   else
4271                     VEC_reserve (basic_block, heap, works, 1);
4272                 }
4273               VEC_quick_push (basic_block, works, succ);
4274             }
4275         }
4276     }
4277
4278   /* Find the predecessor, and make sure nothing else jumps into this loop.  */
4279   if (!loop->bad)
4280     {
4281       int pass, retry;
4282       for (dwork = 0; VEC_iterate (basic_block, loop->blocks, dwork, bb); dwork++)
4283         {
4284           edge e;
4285           edge_iterator ei;
4286           FOR_EACH_EDGE (e, ei, bb->preds)
4287             {
4288               basic_block pred = e->src;
4289
4290               if (!bfin_bb_in_loop (loop, pred))
4291                 {
4292                   if (dump_file)
4293                     fprintf (dump_file, ";; Loop %d: incoming edge %d -> %d\n",
4294                              loop->loop_no, pred->index,
4295                              e->dest->index);
4296                   VEC_safe_push (edge, gc, loop->incoming, e);
4297                 }
4298             }
4299         }
4300
4301       for (pass = 0, retry = 1; retry && pass < 2; pass++)
4302         {
4303           edge e;
4304           edge_iterator ei;
4305           bool first = true;
4306           retry = 0;
4307
4308           FOR_EACH_EDGE (e, ei, loop->incoming)
4309             {
4310               if (first)
4311                 {
4312                   loop->incoming_src = e->src;
4313                   loop->incoming_dest = e->dest;
4314                   first = false;
4315                 }
4316               else
4317                 {
4318                   if (e->dest != loop->incoming_dest)
4319                     loop->incoming_dest = NULL;
4320                   if (e->src != loop->incoming_src)
4321                     loop->incoming_src = NULL;
4322                 }
4323               if (loop->incoming_src == NULL && loop->incoming_dest == NULL)
4324                 {
4325                   if (pass == 0)
4326                     {
4327                       if (dump_file)
4328                         fprintf (dump_file,
4329                                  ";; retrying loop %d with forwarder blocks\n",
4330                                  loop->loop_no);
4331                       retry = 1;
4332                       break;
4333                     }
4334                   loop->bad = 1;
4335                   if (dump_file)
4336                     fprintf (dump_file,
4337                              ";; can't find suitable entry for loop %d\n",
4338                              loop->loop_no);
4339                   goto out;
4340                 }
4341             }
4342           if (retry)
4343             {
4344               retry = 0;
4345               FOR_EACH_EDGE (e, ei, loop->incoming)
4346                 {
4347                   if (forwarder_block_p (e->src))
4348                     {
4349                       edge e2;
4350                       edge_iterator ei2;
4351
4352                       if (dump_file)
4353                         fprintf (dump_file,
4354                                  ";; Adding forwarder block %d to loop %d and retrying\n",
4355                                  e->src->index, loop->loop_no);
4356                       VEC_safe_push (basic_block, heap, loop->blocks, e->src);
4357                       bitmap_set_bit (loop->block_bitmap, e->src->index);
4358                       FOR_EACH_EDGE (e2, ei2, e->src->preds)
4359                         VEC_safe_push (edge, gc, loop->incoming, e2);
4360                       VEC_unordered_remove (edge, loop->incoming, ei.index);
4361                       retry = 1;
4362                       break;
4363                     }
4364                 }
4365               if (!retry)
4366                 {
4367                   if (dump_file)
4368                     fprintf (dump_file, ";; No forwarder blocks found\n");
4369                   loop->bad = 1;
4370                 }
4371             }
4372         }
4373     }
4374
4375  out:
4376   VEC_free (basic_block, heap, works);
4377 }
4378
4379 /* Analyze the structure of the loops in the current function.  Use STACK
4380    for bitmap allocations.  Returns all the valid candidates for hardware
4381    loops found in this function.  */
4382 static loop_info
4383 bfin_discover_loops (bitmap_obstack *stack, FILE *dump_file)
4384 {
4385   loop_info loops = NULL;
4386   loop_info loop;
4387   basic_block bb;
4388   bitmap tmp_bitmap;
4389   int nloops = 0;
4390
4391   /* Find all the possible loop tails.  This means searching for every
4392      loop_end instruction.  For each one found, create a loop_info
4393      structure and add the head block to the work list. */
4394   FOR_EACH_BB (bb)
4395     {
4396       rtx tail = BB_END (bb);
4397
4398       while (GET_CODE (tail) == NOTE)
4399         tail = PREV_INSN (tail);
4400
4401       bb->aux = NULL;
4402
4403       if (INSN_P (tail) && recog_memoized (tail) == CODE_FOR_loop_end)
4404         {
4405           rtx insn;
4406           /* A possible loop end */
4407
4408           /* There's a degenerate case we can handle - an empty loop consisting
4409              of only a back branch.  Handle that by deleting the branch.  */
4410           insn = BB_HEAD (BRANCH_EDGE (bb)->dest);
4411           if (next_real_insn (insn) == tail)
4412             {
4413               if (dump_file)
4414                 {
4415                   fprintf (dump_file, ";; degenerate loop ending at\n");
4416                   print_rtl_single (dump_file, tail);
4417                 }
4418               delete_insn_and_edges (tail);
4419               continue;
4420             }
4421
4422           loop = XNEW (struct loop_info);
4423           loop->next = loops;
4424           loops = loop;
4425           loop->loop_no = nloops++;
4426           loop->blocks = VEC_alloc (basic_block, heap, 20);
4427           loop->block_bitmap = BITMAP_ALLOC (stack);
4428           bb->aux = loop;
4429
4430           if (dump_file)
4431             {
4432               fprintf (dump_file, ";; potential loop %d ending at\n",
4433                        loop->loop_no);
4434               print_rtl_single (dump_file, tail);
4435             }
4436
4437           bfin_discover_loop (loop, bb, tail);
4438         }
4439     }
4440
4441   tmp_bitmap = BITMAP_ALLOC (stack);
4442   /* Compute loop nestings.  */
4443   for (loop = loops; loop; loop = loop->next)
4444     {
4445       loop_info other;
4446       if (loop->bad)
4447         continue;
4448
4449       for (other = loop->next; other; other = other->next)
4450         {
4451           if (other->bad)
4452             continue;
4453
4454           bitmap_and (tmp_bitmap, other->block_bitmap, loop->block_bitmap);
4455           if (bitmap_empty_p (tmp_bitmap))
4456             continue;
4457           if (bitmap_equal_p (tmp_bitmap, other->block_bitmap))
4458             {
4459               other->outer = loop;
4460               VEC_safe_push (loop_info, heap, loop->loops, other);
4461             }
4462           else if (bitmap_equal_p (tmp_bitmap, loop->block_bitmap))
4463             {
4464               loop->outer = other;
4465               VEC_safe_push (loop_info, heap, other->loops, loop);
4466             }
4467           else
4468             {
4469               if (dump_file)
4470                 fprintf (dump_file,
4471                          ";; can't find suitable nesting for loops %d and %d\n",
4472                          loop->loop_no, other->loop_no);
4473               loop->bad = other->bad = 1;
4474             }
4475         }
4476     }
4477   BITMAP_FREE (tmp_bitmap);
4478
4479   return loops;
4480 }
4481
4482 /* Free up the loop structures in LOOPS.  */
4483 static void
4484 free_loops (loop_info loops)
4485 {
4486   while (loops)
4487     {
4488       loop_info loop = loops;
4489       loops = loop->next;
4490       VEC_free (loop_info, heap, loop->loops);
4491       VEC_free (basic_block, heap, loop->blocks);
4492       BITMAP_FREE (loop->block_bitmap);
4493       XDELETE (loop);
4494     }
4495 }
4496
4497 #define BB_AUX_INDEX(BB) ((unsigned)(BB)->aux)
4498
4499 /* The taken-branch edge from the loop end can actually go forward.  Since the
4500    Blackfin's LSETUP instruction requires that the loop end be after the loop
4501    start, try to reorder a loop's basic blocks when we find such a case.  */
4502 static void
4503 bfin_reorder_loops (loop_info loops, FILE *dump_file)
4504 {
4505   basic_block bb;
4506   loop_info loop;
4507
4508   FOR_EACH_BB (bb)
4509     bb->aux = NULL;
4510   cfg_layout_initialize (0);
4511
4512   for (loop = loops; loop; loop = loop->next)
4513     {
4514       unsigned index;
4515       basic_block bb;
4516       edge e;
4517       edge_iterator ei;
4518
4519       if (loop->bad)
4520         continue;
4521
4522       /* Recreate an index for basic blocks that represents their order.  */
4523       for (bb = ENTRY_BLOCK_PTR->next_bb, index = 0;
4524            bb != EXIT_BLOCK_PTR;
4525            bb = bb->next_bb, index++)
4526         bb->aux = (PTR) index;
4527
4528       if (BB_AUX_INDEX (loop->head) < BB_AUX_INDEX (loop->tail))
4529         continue;
4530
4531       FOR_EACH_EDGE (e, ei, loop->head->succs)
4532         {
4533           if (bitmap_bit_p (loop->block_bitmap, e->dest->index)
4534               && BB_AUX_INDEX (e->dest) < BB_AUX_INDEX (loop->tail))
4535             {
4536               basic_block start_bb = e->dest;
4537               basic_block start_prev_bb = start_bb->prev_bb;
4538
4539               if (dump_file)
4540                 fprintf (dump_file, ";; Moving block %d before block %d\n",
4541                          loop->head->index, start_bb->index);
4542               loop->head->prev_bb->next_bb = loop->head->next_bb;
4543               loop->head->next_bb->prev_bb = loop->head->prev_bb;
4544
4545               loop->head->prev_bb = start_prev_bb;
4546               loop->head->next_bb = start_bb;
4547               start_prev_bb->next_bb = start_bb->prev_bb = loop->head;
4548               break;
4549             }
4550         }
4551       loops = loops->next;
4552     }
4553   
4554   FOR_EACH_BB (bb)
4555     {
4556       if (bb->next_bb != EXIT_BLOCK_PTR)
4557         bb->aux = bb->next_bb;
4558       else
4559         bb->aux = NULL;
4560     }
4561   cfg_layout_finalize ();
4562   df_analyze ();
4563 }
4564
4565 /* Run from machine_dependent_reorg, this pass looks for doloop_end insns
4566    and tries to rewrite the RTL of these loops so that proper Blackfin
4567    hardware loops are generated.  */
4568
4569 static void
4570 bfin_reorg_loops (FILE *dump_file)
4571 {
4572   loop_info loops = NULL;
4573   loop_info loop;
4574   basic_block bb;
4575   bitmap_obstack stack;
4576
4577   bitmap_obstack_initialize (&stack);
4578
4579   if (dump_file)
4580     fprintf (dump_file, ";; Find loops, first pass\n\n");
4581
4582   loops = bfin_discover_loops (&stack, dump_file);
4583
4584   if (dump_file)
4585     bfin_dump_loops (loops);
4586
4587   bfin_reorder_loops (loops, dump_file);
4588   free_loops (loops);
4589
4590   if (dump_file)
4591     fprintf (dump_file, ";; Find loops, second pass\n\n");
4592
4593   loops = bfin_discover_loops (&stack, dump_file);
4594   if (dump_file)
4595     {
4596       fprintf (dump_file, ";; All loops found:\n\n");
4597       bfin_dump_loops (loops);
4598     }
4599   
4600   /* Now apply the optimizations.  */
4601   for (loop = loops; loop; loop = loop->next)
4602     bfin_optimize_loop (loop);
4603
4604   if (dump_file)
4605     {
4606       fprintf (dump_file, ";; After hardware loops optimization:\n\n");
4607       bfin_dump_loops (loops);
4608     }
4609
4610   free_loops (loops);
4611
4612   if (dump_file)
4613     print_rtl (dump_file, get_insns ());
4614
4615   FOR_EACH_BB (bb)
4616     bb->aux = NULL;
4617 }
4618 \f
4619 /* Possibly generate a SEQUENCE out of three insns found in SLOT.
4620    Returns true if we modified the insn chain, false otherwise.  */
4621 static bool
4622 gen_one_bundle (rtx slot[3])
4623 {
4624   gcc_assert (slot[1] != NULL_RTX);
4625
4626   /* Don't add extra NOPs if optimizing for size.  */
4627   if (optimize_size
4628       && (slot[0] == NULL_RTX || slot[2] == NULL_RTX))
4629     return false;
4630
4631   /* Verify that we really can do the multi-issue.  */
4632   if (slot[0])
4633     {
4634       rtx t = NEXT_INSN (slot[0]);
4635       while (t != slot[1])
4636         {
4637           if (GET_CODE (t) != NOTE
4638               || NOTE_KIND (t) != NOTE_INSN_DELETED)
4639             return false;
4640           t = NEXT_INSN (t);
4641         }
4642     }
4643   if (slot[2])
4644     {
4645       rtx t = NEXT_INSN (slot[1]);
4646       while (t != slot[2])
4647         {
4648           if (GET_CODE (t) != NOTE
4649               || NOTE_KIND (t) != NOTE_INSN_DELETED)
4650             return false;
4651           t = NEXT_INSN (t);
4652         }
4653     }
4654
4655   if (slot[0] == NULL_RTX)
4656     {
4657       slot[0] = emit_insn_before (gen_mnop (), slot[1]);
4658       df_insn_rescan (slot[0]);
4659     }
4660   if (slot[2] == NULL_RTX)
4661     {
4662       slot[2] = emit_insn_after (gen_forced_nop (), slot[1]);
4663       df_insn_rescan (slot[2]);
4664     }
4665
4666   /* Avoid line number information being printed inside one bundle.  */
4667   if (INSN_LOCATOR (slot[1])
4668       && INSN_LOCATOR (slot[1]) != INSN_LOCATOR (slot[0]))
4669     INSN_LOCATOR (slot[1]) = INSN_LOCATOR (slot[0]);
4670   if (INSN_LOCATOR (slot[2])
4671       && INSN_LOCATOR (slot[2]) != INSN_LOCATOR (slot[0]))
4672     INSN_LOCATOR (slot[2]) = INSN_LOCATOR (slot[0]);
4673
4674   /* Terminate them with "|| " instead of ";" in the output.  */
4675   PUT_MODE (slot[0], SImode);
4676   PUT_MODE (slot[1], SImode);
4677   /* Terminate the bundle, for the benefit of reorder_var_tracking_notes.  */
4678   PUT_MODE (slot[2], QImode);
4679   return true;
4680 }
4681
4682 /* Go through all insns, and use the information generated during scheduling
4683    to generate SEQUENCEs to represent bundles of instructions issued
4684    simultaneously.  */
4685
4686 static void
4687 bfin_gen_bundles (void)
4688 {
4689   basic_block bb;
4690   FOR_EACH_BB (bb)
4691     {
4692       rtx insn, next;
4693       rtx slot[3];
4694       int n_filled = 0;
4695
4696       slot[0] = slot[1] = slot[2] = NULL_RTX;
4697       for (insn = BB_HEAD (bb);; insn = next)
4698         {
4699           int at_end;
4700           if (INSN_P (insn))
4701             {
4702               if (get_attr_type (insn) == TYPE_DSP32)
4703                 slot[0] = insn;
4704               else if (slot[1] == NULL_RTX)
4705                 slot[1] = insn;
4706               else
4707                 slot[2] = insn;
4708               n_filled++;
4709             }
4710
4711           next = NEXT_INSN (insn);
4712           while (next && insn != BB_END (bb)
4713                  && !(INSN_P (next)
4714                       && GET_CODE (PATTERN (next)) != USE
4715                       && GET_CODE (PATTERN (next)) != CLOBBER))
4716             {
4717               insn = next;
4718               next = NEXT_INSN (insn);
4719             }
4720
4721           /* BB_END can change due to emitting extra NOPs, so check here.  */
4722           at_end = insn == BB_END (bb);
4723           if (at_end || GET_MODE (next) == TImode)
4724             {
4725               if ((n_filled < 2
4726                    || !gen_one_bundle (slot))
4727                   && slot[0] != NULL_RTX)
4728                 {
4729                   rtx pat = PATTERN (slot[0]);
4730                   if (GET_CODE (pat) == SET
4731                       && GET_CODE (SET_SRC (pat)) == UNSPEC
4732                       && XINT (SET_SRC (pat), 1) == UNSPEC_32BIT)
4733                     {
4734                       SET_SRC (pat) = XVECEXP (SET_SRC (pat), 0, 0);
4735                       INSN_CODE (slot[0]) = -1;
4736                       df_insn_rescan (slot[0]);
4737                     }
4738                 }
4739               n_filled = 0;
4740               slot[0] = slot[1] = slot[2] = NULL_RTX;
4741             }
4742           if (at_end)
4743             break;
4744         }
4745     }
4746 }
4747
4748 /* Ensure that no var tracking notes are emitted in the middle of a
4749    three-instruction bundle.  */
4750
4751 static void
4752 reorder_var_tracking_notes (void)
4753 {
4754   basic_block bb;
4755   FOR_EACH_BB (bb)
4756     {
4757       rtx insn, next;
4758       rtx queue = NULL_RTX;
4759       bool in_bundle = false;
4760
4761       for (insn = BB_HEAD (bb); insn != BB_END (bb); insn = next)
4762         {
4763           next = NEXT_INSN (insn);
4764
4765           if (INSN_P (insn))
4766             {
4767               /* Emit queued up notes at the last instruction of a bundle.  */
4768               if (GET_MODE (insn) == QImode)
4769                 {
4770                   while (queue)
4771                     {
4772                       rtx next_queue = PREV_INSN (queue);
4773                       PREV_INSN (NEXT_INSN (insn)) = queue;
4774                       NEXT_INSN (queue) = NEXT_INSN (insn);
4775                       NEXT_INSN (insn) = queue;
4776                       PREV_INSN (queue) = insn;
4777                       queue = next_queue;
4778                     }
4779                   in_bundle = false;
4780                 }
4781               else if (GET_MODE (insn) == SImode)
4782                 in_bundle = true;
4783             }
4784           else if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION)
4785             {
4786               if (in_bundle)
4787                 {
4788                   rtx prev = PREV_INSN (insn);
4789                   PREV_INSN (next) = prev;
4790                   NEXT_INSN (prev) = next;
4791
4792                   PREV_INSN (insn) = queue;
4793                   queue = insn;
4794                 }
4795             }
4796         }
4797     }
4798 }
4799 \f
4800 /* On some silicon revisions, functions shorter than a certain number of cycles
4801    can cause unpredictable behaviour.  Work around this by adding NOPs as
4802    needed.  */
4803 static void
4804 workaround_rts_anomaly (void)
4805 {
4806   rtx insn, first_insn = NULL_RTX;
4807   int cycles = 4;
4808
4809   if (! ENABLE_WA_RETS)
4810     return;
4811
4812   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
4813     {
4814       rtx pat;
4815
4816       if (BARRIER_P (insn))
4817         return;
4818       
4819       if (NOTE_P (insn) || LABEL_P (insn))
4820         continue;
4821
4822       if (first_insn == NULL_RTX)
4823         first_insn = insn;
4824       pat = PATTERN (insn);
4825       if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER
4826           || GET_CODE (pat) == ASM_INPUT || GET_CODE (pat) == ADDR_VEC
4827           || GET_CODE (pat) == ADDR_DIFF_VEC || asm_noperands (pat) >= 0)
4828         continue;
4829
4830       if (CALL_P (insn))
4831         return;
4832
4833       if (JUMP_P (insn))
4834         {
4835           if (recog_memoized (insn) == CODE_FOR_return_internal)
4836             break;
4837
4838           /* Nothing to worry about for direct jumps.  */
4839           if (!any_condjump_p (insn))
4840             return;
4841           if (cycles <= 1)
4842             return;
4843           cycles--;
4844         }
4845       else if (INSN_P (insn))
4846         {
4847           rtx pat = PATTERN (insn);
4848           int this_cycles = 1;
4849
4850           if (GET_CODE (pat) == PARALLEL)
4851             {
4852               if (push_multiple_operation (pat, VOIDmode)
4853                   || pop_multiple_operation (pat, VOIDmode))
4854                 this_cycles = n_regs_to_save;
4855             }
4856           else
4857             {
4858               enum insn_code icode = recog_memoized (insn);
4859               if (icode == CODE_FOR_link)
4860                 this_cycles = 4;
4861               else if (icode == CODE_FOR_unlink)
4862                 this_cycles = 3;
4863               else if (icode == CODE_FOR_mulsi3)
4864                 this_cycles = 5;
4865             }
4866           if (this_cycles >= cycles)
4867             return;
4868
4869           cycles -= this_cycles;
4870         }
4871     }
4872   while (cycles > 0)
4873     {
4874       emit_insn_before (gen_nop (), first_insn);
4875       cycles--;
4876     }
4877 }
4878
4879 /* Return an insn type for INSN that can be used by the caller for anomaly
4880    workarounds.  This differs from plain get_attr_type in that it handles
4881    SEQUENCEs.  */
4882
4883 static enum attr_type
4884 type_for_anomaly (rtx insn)
4885 {
4886   rtx pat = PATTERN (insn);
4887   if (GET_CODE (pat) == SEQUENCE)
4888     {
4889       enum attr_type t;
4890       t = get_attr_type (XVECEXP (pat, 0, 1));
4891       if (t == TYPE_MCLD)
4892         return t;
4893       t = get_attr_type (XVECEXP (pat, 0, 2));
4894       if (t == TYPE_MCLD)
4895         return t;
4896       return TYPE_MCST;
4897     }
4898   else
4899     return get_attr_type (insn);
4900 }
4901
4902 /* Return nonzero if INSN contains any loads that may trap.  It handles
4903    SEQUENCEs correctly.  */
4904
4905 static bool
4906 trapping_loads_p (rtx insn)
4907 {
4908   rtx pat = PATTERN (insn);
4909   if (GET_CODE (pat) == SEQUENCE)
4910     {
4911       enum attr_type t;
4912       t = get_attr_type (XVECEXP (pat, 0, 1));
4913       if (t == TYPE_MCLD
4914           && may_trap_p (SET_SRC (PATTERN (XVECEXP (pat, 0, 1)))))
4915         return true;
4916       t = get_attr_type (XVECEXP (pat, 0, 2));
4917       if (t == TYPE_MCLD
4918           && may_trap_p (SET_SRC (PATTERN (XVECEXP (pat, 0, 2)))))
4919         return true;
4920       return false;
4921     }
4922   else
4923     return may_trap_p (SET_SRC (single_set (insn)));
4924 }
4925
4926 /* Return INSN if it is of TYPE_MCLD.  Alternatively, if INSN is the start of
4927    a three-insn bundle, see if one of them is a load and return that if so.
4928    Return NULL_RTX if the insn does not contain loads.  */
4929 static rtx
4930 find_load (rtx insn)
4931 {
4932   if (get_attr_type (insn) == TYPE_MCLD)
4933     return insn;
4934   if (GET_MODE (insn) != SImode)
4935     return NULL_RTX;
4936   do {
4937     insn = NEXT_INSN (insn);
4938     if ((GET_MODE (insn) == SImode || GET_MODE (insn) == QImode)
4939         && get_attr_type (insn) == TYPE_MCLD)
4940       return insn;
4941   } while (GET_MODE (insn) != QImode);
4942   return NULL_RTX;
4943 }
4944
4945 /* Determine whether PAT is an indirect call pattern.  */
4946 static bool
4947 indirect_call_p (rtx pat)
4948 {
4949   if (GET_CODE (pat) == PARALLEL)
4950     pat = XVECEXP (pat, 0, 0);
4951   if (GET_CODE (pat) == SET)
4952     pat = SET_SRC (pat);
4953   gcc_assert (GET_CODE (pat) == CALL);
4954   pat = XEXP (pat, 0);
4955   gcc_assert (GET_CODE (pat) == MEM);
4956   pat = XEXP (pat, 0);
4957   
4958   return REG_P (pat);
4959 }
4960
4961 static void
4962 workaround_speculation (void)
4963 {
4964   rtx insn, next;
4965   rtx last_condjump = NULL_RTX;
4966   int cycles_since_jump = INT_MAX;
4967   int delay_added = 0;
4968
4969   if (! ENABLE_WA_SPECULATIVE_LOADS && ! ENABLE_WA_SPECULATIVE_SYNCS
4970       && ! ENABLE_WA_INDIRECT_CALLS)
4971     return;
4972
4973   /* First pass: find predicted-false branches; if something after them
4974      needs nops, insert them or change the branch to predict true.  */
4975   for (insn = get_insns (); insn; insn = next)
4976     {
4977       rtx pat;
4978       int delay_needed = 0;
4979
4980       next = find_next_insn_start (insn);
4981       
4982       if (NOTE_P (insn) || BARRIER_P (insn) || LABEL_P (insn))
4983         continue;
4984
4985       pat = PATTERN (insn);
4986       if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER
4987           || GET_CODE (pat) == ASM_INPUT || GET_CODE (pat) == ADDR_VEC
4988           || GET_CODE (pat) == ADDR_DIFF_VEC || asm_noperands (pat) >= 0)
4989         continue;
4990
4991       if (JUMP_P (insn))
4992         {
4993           if (any_condjump_p (insn)
4994               && ! cbranch_predicted_taken_p (insn))
4995             {
4996               last_condjump = insn;
4997               delay_added = 0;
4998               cycles_since_jump = 0;
4999             }
5000           else
5001             cycles_since_jump = INT_MAX;
5002         }
5003       else if (CALL_P (insn))
5004         {
5005           if (cycles_since_jump < INT_MAX)
5006             cycles_since_jump++;
5007           if (indirect_call_p (pat) && ENABLE_WA_INDIRECT_CALLS)
5008             {
5009               delay_needed = 3;
5010             }
5011         }
5012       else if (INSN_P (insn))
5013         {
5014           rtx load_insn = find_load (insn);
5015           enum attr_type type = type_for_anomaly (insn);
5016
5017           if (cycles_since_jump < INT_MAX)
5018             cycles_since_jump++;
5019
5020           if (load_insn && ENABLE_WA_SPECULATIVE_LOADS)
5021             {
5022               if (trapping_loads_p (load_insn))
5023                 delay_needed = 4;
5024             }
5025           else if (type == TYPE_SYNC && ENABLE_WA_SPECULATIVE_SYNCS)
5026             delay_needed = 3;
5027         }
5028
5029       if (delay_needed > cycles_since_jump
5030           && (delay_needed - cycles_since_jump) > delay_added)
5031         {
5032           rtx pat1;
5033           int num_clobbers;
5034           rtx *op = recog_data.operand;
5035
5036           delay_needed -= cycles_since_jump;
5037
5038           extract_insn (last_condjump);
5039           if (optimize_size)
5040             {
5041               pat1 = gen_cbranch_predicted_taken (op[0], op[1], op[2],
5042                                                  op[3]);
5043               cycles_since_jump = INT_MAX;
5044             }
5045           else
5046             {
5047               /* Do not adjust cycles_since_jump in this case, so that
5048                  we'll increase the number of NOPs for a subsequent insn
5049                  if necessary.  */
5050               pat1 = gen_cbranch_with_nops (op[0], op[1], op[2], op[3],
5051                                             GEN_INT (delay_needed));
5052               delay_added = delay_needed;
5053             }
5054           PATTERN (last_condjump) = pat1;
5055           INSN_CODE (last_condjump) = recog (pat1, insn, &num_clobbers);
5056         }
5057       if (CALL_P (insn))
5058         {
5059           cycles_since_jump = INT_MAX;
5060           delay_added = 0;
5061         }
5062     }
5063
5064   /* Second pass: for predicted-true branches, see if anything at the
5065      branch destination needs extra nops.  */
5066   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
5067     {
5068       int cycles_since_jump;
5069       if (JUMP_P (insn)
5070           && any_condjump_p (insn)
5071           && (INSN_CODE (insn) == CODE_FOR_cbranch_predicted_taken
5072               || cbranch_predicted_taken_p (insn)))
5073         {
5074           rtx target = JUMP_LABEL (insn);
5075           rtx label = target;
5076           rtx next_tgt;
5077
5078           cycles_since_jump = 0;
5079           for (; target && cycles_since_jump < 3; target = next_tgt)
5080             {
5081               rtx pat;
5082
5083               next_tgt = find_next_insn_start (target);
5084
5085               if (NOTE_P (target) || BARRIER_P (target) || LABEL_P (target))
5086                 continue;
5087
5088               pat = PATTERN (target);
5089               if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER
5090                   || GET_CODE (pat) == ASM_INPUT || GET_CODE (pat) == ADDR_VEC
5091                   || GET_CODE (pat) == ADDR_DIFF_VEC || asm_noperands (pat) >= 0)
5092                 continue;
5093
5094               if (INSN_P (target))
5095                 {
5096                   rtx load_insn = find_load (target);
5097                   enum attr_type type = type_for_anomaly (target);
5098                   int delay_needed = 0;
5099                   if (cycles_since_jump < INT_MAX)
5100                     cycles_since_jump++;
5101
5102                   if (load_insn && ENABLE_WA_SPECULATIVE_LOADS)
5103                     {
5104                       if (trapping_loads_p (load_insn))
5105                         delay_needed = 2;
5106                     }
5107                   else if (type == TYPE_SYNC && ENABLE_WA_SPECULATIVE_SYNCS)
5108                     delay_needed = 2;
5109
5110                   if (delay_needed > cycles_since_jump)
5111                     {
5112                       rtx prev = prev_real_insn (label);
5113                       delay_needed -= cycles_since_jump;
5114                       if (dump_file)
5115                         fprintf (dump_file, "Adding %d nops after %d\n",
5116                                  delay_needed, INSN_UID (label));
5117                       if (JUMP_P (prev)
5118                           && INSN_CODE (prev) == CODE_FOR_cbranch_with_nops)
5119                         {
5120                           rtx x;
5121                           HOST_WIDE_INT v;
5122
5123                           if (dump_file)
5124                             fprintf (dump_file,
5125                                      "Reducing nops on insn %d.\n",
5126                                      INSN_UID (prev));
5127                           x = PATTERN (prev);
5128                           x = XVECEXP (x, 0, 1);
5129                           v = INTVAL (XVECEXP (x, 0, 0)) - delay_needed;
5130                           XVECEXP (x, 0, 0) = GEN_INT (v);
5131                         }
5132                       while (delay_needed-- > 0)
5133                         emit_insn_after (gen_nop (), label);
5134                       break;
5135                     }
5136                 }
5137             }
5138         }
5139     }
5140 }
5141
5142 /* We use the machine specific reorg pass for emitting CSYNC instructions
5143    after conditional branches as needed.
5144
5145    The Blackfin is unusual in that a code sequence like
5146      if cc jump label
5147      r0 = (p0)
5148    may speculatively perform the load even if the condition isn't true.  This
5149    happens for a branch that is predicted not taken, because the pipeline
5150    isn't flushed or stalled, so the early stages of the following instructions,
5151    which perform the memory reference, are allowed to execute before the
5152    jump condition is evaluated.
5153    Therefore, we must insert additional instructions in all places where this
5154    could lead to incorrect behavior.  The manual recommends CSYNC, while
5155    VDSP seems to use NOPs (even though its corresponding compiler option is
5156    named CSYNC).
5157
5158    When optimizing for speed, we emit NOPs, which seems faster than a CSYNC.
5159    When optimizing for size, we turn the branch into a predicted taken one.
5160    This may be slower due to mispredicts, but saves code size.  */
5161
5162 static void
5163 bfin_reorg (void)
5164 {
5165   /* We are freeing block_for_insn in the toplev to keep compatibility
5166      with old MDEP_REORGS that are not CFG based.  Recompute it now.  */
5167   compute_bb_for_insn ();
5168
5169   if (bfin_flag_schedule_insns2)
5170     {
5171       splitting_for_sched = 1;
5172       split_all_insns ();
5173       splitting_for_sched = 0;
5174
5175       timevar_push (TV_SCHED2);
5176       schedule_insns ();
5177       timevar_pop (TV_SCHED2);
5178
5179       /* Examine the schedule and insert nops as necessary for 64-bit parallel
5180          instructions.  */
5181       bfin_gen_bundles ();
5182     }
5183
5184   df_analyze ();
5185
5186   /* Doloop optimization */
5187   if (cfun->machine->has_hardware_loops)
5188     bfin_reorg_loops (dump_file);
5189
5190   workaround_speculation ();
5191
5192   if (bfin_flag_var_tracking)
5193     {
5194       timevar_push (TV_VAR_TRACKING);
5195       variable_tracking_main ();
5196       reorder_var_tracking_notes ();
5197       timevar_pop (TV_VAR_TRACKING);
5198     }
5199
5200   df_finish_pass (false);
5201
5202   workaround_rts_anomaly ();
5203 }
5204 \f
5205 /* Handle interrupt_handler, exception_handler and nmi_handler function
5206    attributes; arguments as in struct attribute_spec.handler.  */
5207
5208 static tree
5209 handle_int_attribute (tree *node, tree name,
5210                       tree args ATTRIBUTE_UNUSED,
5211                       int flags ATTRIBUTE_UNUSED,
5212                       bool *no_add_attrs)
5213 {
5214   tree x = *node;
5215   if (TREE_CODE (x) == FUNCTION_DECL)
5216     x = TREE_TYPE (x);
5217
5218   if (TREE_CODE (x) != FUNCTION_TYPE)
5219     {
5220       warning (OPT_Wattributes, "%qs attribute only applies to functions",
5221                IDENTIFIER_POINTER (name));
5222       *no_add_attrs = true;
5223     }
5224   else if (funkind (x) != SUBROUTINE)
5225     error ("multiple function type attributes specified");
5226
5227   return NULL_TREE;
5228 }
5229
5230 /* Return 0 if the attributes for two types are incompatible, 1 if they
5231    are compatible, and 2 if they are nearly compatible (which causes a
5232    warning to be generated).  */
5233
5234 static int
5235 bfin_comp_type_attributes (const_tree type1, const_tree type2)
5236 {
5237   e_funkind kind1, kind2;
5238
5239   if (TREE_CODE (type1) != FUNCTION_TYPE)
5240     return 1;
5241
5242   kind1 = funkind (type1);
5243   kind2 = funkind (type2);
5244
5245   if (kind1 != kind2)
5246     return 0;
5247   
5248   /*  Check for mismatched modifiers */
5249   if (!lookup_attribute ("nesting", TYPE_ATTRIBUTES (type1))
5250       != !lookup_attribute ("nesting", TYPE_ATTRIBUTES (type2)))
5251     return 0;
5252
5253   if (!lookup_attribute ("saveall", TYPE_ATTRIBUTES (type1))
5254       != !lookup_attribute ("saveall", TYPE_ATTRIBUTES (type2)))
5255     return 0;
5256
5257   if (!lookup_attribute ("kspisusp", TYPE_ATTRIBUTES (type1))
5258       != !lookup_attribute ("kspisusp", TYPE_ATTRIBUTES (type2)))
5259     return 0;
5260
5261   if (!lookup_attribute ("longcall", TYPE_ATTRIBUTES (type1))
5262       != !lookup_attribute ("longcall", TYPE_ATTRIBUTES (type2)))
5263     return 0;
5264
5265   return 1;
5266 }
5267
5268 /* Handle a "longcall" or "shortcall" attribute; arguments as in
5269    struct attribute_spec.handler.  */
5270
5271 static tree
5272 bfin_handle_longcall_attribute (tree *node, tree name, 
5273                                 tree args ATTRIBUTE_UNUSED, 
5274                                 int flags ATTRIBUTE_UNUSED, 
5275                                 bool *no_add_attrs)
5276 {
5277   if (TREE_CODE (*node) != FUNCTION_TYPE
5278       && TREE_CODE (*node) != FIELD_DECL
5279       && TREE_CODE (*node) != TYPE_DECL)
5280     {
5281       warning (OPT_Wattributes, "`%s' attribute only applies to functions",
5282                IDENTIFIER_POINTER (name));
5283       *no_add_attrs = true;
5284     }
5285
5286   if ((strcmp (IDENTIFIER_POINTER (name), "longcall") == 0
5287        && lookup_attribute ("shortcall", TYPE_ATTRIBUTES (*node)))
5288       || (strcmp (IDENTIFIER_POINTER (name), "shortcall") == 0
5289           && lookup_attribute ("longcall", TYPE_ATTRIBUTES (*node))))
5290     {
5291       warning (OPT_Wattributes,
5292                "can't apply both longcall and shortcall attributes to the same function");
5293       *no_add_attrs = true;
5294     }
5295
5296   return NULL_TREE;
5297 }
5298
5299 /* Handle a "l1_text" attribute; arguments as in
5300    struct attribute_spec.handler.  */
5301
5302 static tree
5303 bfin_handle_l1_text_attribute (tree *node, tree name, tree ARG_UNUSED (args),
5304                                int ARG_UNUSED (flags), bool *no_add_attrs)
5305 {
5306   tree decl = *node;
5307
5308   if (TREE_CODE (decl) != FUNCTION_DECL)
5309     {
5310       error ("`%s' attribute only applies to functions",
5311              IDENTIFIER_POINTER (name));
5312       *no_add_attrs = true;
5313     }
5314
5315   /* The decl may have already been given a section attribute
5316      from a previous declaration. Ensure they match.  */
5317   else if (DECL_SECTION_NAME (decl) != NULL_TREE
5318            && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
5319                       ".l1.text") != 0)
5320     {
5321       error ("section of %q+D conflicts with previous declaration",
5322              decl);
5323       *no_add_attrs = true;
5324     }
5325   else
5326     DECL_SECTION_NAME (decl) = build_string (9, ".l1.text");
5327
5328   return NULL_TREE;
5329 }
5330
5331 /* Handle a "l1_data", "l1_data_A" or "l1_data_B" attribute;
5332    arguments as in struct attribute_spec.handler.  */
5333
5334 static tree
5335 bfin_handle_l1_data_attribute (tree *node, tree name, tree ARG_UNUSED (args),
5336                                int ARG_UNUSED (flags), bool *no_add_attrs)
5337 {
5338   tree decl = *node;
5339
5340   if (TREE_CODE (decl) != VAR_DECL)
5341     {
5342       error ("`%s' attribute only applies to variables",
5343              IDENTIFIER_POINTER (name));
5344       *no_add_attrs = true;
5345     }
5346   else if (current_function_decl != NULL_TREE
5347            && !TREE_STATIC (decl))
5348     {
5349       error ("`%s' attribute cannot be specified for local variables",
5350              IDENTIFIER_POINTER (name));
5351       *no_add_attrs = true;
5352     }
5353   else
5354     {
5355       const char *section_name;
5356
5357       if (strcmp (IDENTIFIER_POINTER (name), "l1_data") == 0)
5358         section_name = ".l1.data";
5359       else if (strcmp (IDENTIFIER_POINTER (name), "l1_data_A") == 0)
5360         section_name = ".l1.data.A";
5361       else if (strcmp (IDENTIFIER_POINTER (name), "l1_data_B") == 0)
5362         section_name = ".l1.data.B";
5363       else
5364         gcc_unreachable ();
5365
5366       /* The decl may have already been given a section attribute
5367          from a previous declaration. Ensure they match.  */
5368       if (DECL_SECTION_NAME (decl) != NULL_TREE
5369           && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
5370                      section_name) != 0)
5371         {
5372           error ("section of %q+D conflicts with previous declaration",
5373                  decl);
5374           *no_add_attrs = true;
5375         }
5376       else
5377         DECL_SECTION_NAME (decl)
5378           = build_string (strlen (section_name) + 1, section_name);
5379     }
5380
5381  return NULL_TREE;
5382 }
5383
5384 /* Table of valid machine attributes.  */
5385 const struct attribute_spec bfin_attribute_table[] =
5386 {
5387   /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
5388   { "interrupt_handler", 0, 0, false, true,  true, handle_int_attribute },
5389   { "exception_handler", 0, 0, false, true,  true, handle_int_attribute },
5390   { "nmi_handler", 0, 0, false, true,  true, handle_int_attribute },
5391   { "nesting", 0, 0, false, true,  true, NULL },
5392   { "kspisusp", 0, 0, false, true,  true, NULL },
5393   { "saveall", 0, 0, false, true,  true, NULL },
5394   { "longcall",  0, 0, false, true,  true,  bfin_handle_longcall_attribute },
5395   { "shortcall", 0, 0, false, true,  true,  bfin_handle_longcall_attribute },
5396   { "l1_text", 0, 0, true, false, false,  bfin_handle_l1_text_attribute },
5397   { "l1_data", 0, 0, true, false, false,  bfin_handle_l1_data_attribute },
5398   { "l1_data_A", 0, 0, true, false, false, bfin_handle_l1_data_attribute },
5399   { "l1_data_B", 0, 0, true, false, false,  bfin_handle_l1_data_attribute },
5400   { NULL, 0, 0, false, false, false, NULL }
5401 };
5402 \f
5403 /* Implementation of TARGET_ASM_INTEGER.  When using FD-PIC, we need to
5404    tell the assembler to generate pointers to function descriptors in
5405    some cases.  */
5406
5407 static bool
5408 bfin_assemble_integer (rtx value, unsigned int size, int aligned_p)
5409 {
5410   if (TARGET_FDPIC && size == UNITS_PER_WORD)
5411     {
5412       if (GET_CODE (value) == SYMBOL_REF
5413           && SYMBOL_REF_FUNCTION_P (value))
5414         {
5415           fputs ("\t.picptr\tfuncdesc(", asm_out_file);
5416           output_addr_const (asm_out_file, value);
5417           fputs (")\n", asm_out_file);
5418           return true;
5419         }
5420       if (!aligned_p)
5421         {
5422           /* We've set the unaligned SI op to NULL, so we always have to
5423              handle the unaligned case here.  */
5424           assemble_integer_with_op ("\t.4byte\t", value);
5425           return true;
5426         }
5427     }
5428   return default_assemble_integer (value, size, aligned_p);
5429 }
5430 \f
5431 /* Output the assembler code for a thunk function.  THUNK_DECL is the
5432    declaration for the thunk function itself, FUNCTION is the decl for
5433    the target function.  DELTA is an immediate constant offset to be
5434    added to THIS.  If VCALL_OFFSET is nonzero, the word at
5435    *(*this + vcall_offset) should be added to THIS.  */
5436
5437 static void
5438 bfin_output_mi_thunk (FILE *file ATTRIBUTE_UNUSED,
5439                       tree thunk ATTRIBUTE_UNUSED, HOST_WIDE_INT delta,
5440                       HOST_WIDE_INT vcall_offset, tree function)
5441 {
5442   rtx xops[3];
5443   /* The this parameter is passed as the first argument.  */
5444   rtx this_rtx = gen_rtx_REG (Pmode, REG_R0);
5445
5446   /* Adjust the this parameter by a fixed constant.  */
5447   if (delta)
5448     {
5449       xops[1] = this_rtx;
5450       if (delta >= -64 && delta <= 63)
5451         {
5452           xops[0] = GEN_INT (delta);
5453           output_asm_insn ("%1 += %0;", xops);
5454         }
5455       else if (delta >= -128 && delta < -64)
5456         {
5457           xops[0] = GEN_INT (delta + 64);
5458           output_asm_insn ("%1 += -64; %1 += %0;", xops);
5459         }
5460       else if (delta > 63 && delta <= 126)
5461         {
5462           xops[0] = GEN_INT (delta - 63);
5463           output_asm_insn ("%1 += 63; %1 += %0;", xops);
5464         }
5465       else
5466         {
5467           xops[0] = GEN_INT (delta);
5468           output_asm_insn ("r3.l = %h0; r3.h = %d0; %1 = %1 + r3;", xops);
5469         }
5470     }
5471
5472   /* Adjust the this parameter by a value stored in the vtable.  */
5473   if (vcall_offset)
5474     {
5475       rtx p2tmp = gen_rtx_REG (Pmode, REG_P2);
5476       rtx tmp = gen_rtx_REG (Pmode, REG_R3);
5477
5478       xops[1] = tmp;
5479       xops[2] = p2tmp;
5480       output_asm_insn ("%2 = r0; %2 = [%2];", xops);
5481
5482       /* Adjust the this parameter.  */
5483       xops[0] = gen_rtx_MEM (Pmode, plus_constant (p2tmp, vcall_offset));
5484       if (!memory_operand (xops[0], Pmode))
5485         {
5486           rtx tmp2 = gen_rtx_REG (Pmode, REG_P1);
5487           xops[0] = GEN_INT (vcall_offset);
5488           xops[1] = tmp2;
5489           output_asm_insn ("%h1 = %h0; %d1 = %d0; %2 = %2 + %1", xops);
5490           xops[0] = gen_rtx_MEM (Pmode, p2tmp);
5491         }
5492       xops[2] = this_rtx;
5493       output_asm_insn ("%1 = %0; %2 = %2 + %1;", xops);
5494     }
5495
5496   xops[0] = XEXP (DECL_RTL (function), 0);
5497   if (1 || !flag_pic || (*targetm.binds_local_p) (function))
5498     output_asm_insn ("jump.l\t%P0", xops);
5499 }
5500 \f
5501 /* Codes for all the Blackfin builtins.  */
5502 enum bfin_builtins
5503 {
5504   BFIN_BUILTIN_CSYNC,
5505   BFIN_BUILTIN_SSYNC,
5506   BFIN_BUILTIN_ONES,
5507   BFIN_BUILTIN_COMPOSE_2X16,
5508   BFIN_BUILTIN_EXTRACTLO,
5509   BFIN_BUILTIN_EXTRACTHI,
5510
5511   BFIN_BUILTIN_SSADD_2X16,
5512   BFIN_BUILTIN_SSSUB_2X16,
5513   BFIN_BUILTIN_SSADDSUB_2X16,
5514   BFIN_BUILTIN_SSSUBADD_2X16,
5515   BFIN_BUILTIN_MULT_2X16,
5516   BFIN_BUILTIN_MULTR_2X16,
5517   BFIN_BUILTIN_NEG_2X16,
5518   BFIN_BUILTIN_ABS_2X16,
5519   BFIN_BUILTIN_MIN_2X16,
5520   BFIN_BUILTIN_MAX_2X16,
5521
5522   BFIN_BUILTIN_SSADD_1X16,
5523   BFIN_BUILTIN_SSSUB_1X16,
5524   BFIN_BUILTIN_MULT_1X16,
5525   BFIN_BUILTIN_MULTR_1X16,
5526   BFIN_BUILTIN_NORM_1X16,
5527   BFIN_BUILTIN_NEG_1X16,
5528   BFIN_BUILTIN_ABS_1X16,
5529   BFIN_BUILTIN_MIN_1X16,
5530   BFIN_BUILTIN_MAX_1X16,
5531
5532   BFIN_BUILTIN_SUM_2X16,
5533   BFIN_BUILTIN_DIFFHL_2X16,
5534   BFIN_BUILTIN_DIFFLH_2X16,
5535
5536   BFIN_BUILTIN_SSADD_1X32,
5537   BFIN_BUILTIN_SSSUB_1X32,
5538   BFIN_BUILTIN_NORM_1X32,
5539   BFIN_BUILTIN_ROUND_1X32,
5540   BFIN_BUILTIN_NEG_1X32,
5541   BFIN_BUILTIN_ABS_1X32,
5542   BFIN_BUILTIN_MIN_1X32,
5543   BFIN_BUILTIN_MAX_1X32,
5544   BFIN_BUILTIN_MULT_1X32,
5545   BFIN_BUILTIN_MULT_1X32X32,
5546   BFIN_BUILTIN_MULT_1X32X32NS,
5547
5548   BFIN_BUILTIN_MULHISILL,
5549   BFIN_BUILTIN_MULHISILH,
5550   BFIN_BUILTIN_MULHISIHL,
5551   BFIN_BUILTIN_MULHISIHH,
5552
5553   BFIN_BUILTIN_LSHIFT_1X16,
5554   BFIN_BUILTIN_LSHIFT_2X16,
5555   BFIN_BUILTIN_SSASHIFT_1X16,
5556   BFIN_BUILTIN_SSASHIFT_2X16,
5557   BFIN_BUILTIN_SSASHIFT_1X32,
5558
5559   BFIN_BUILTIN_CPLX_MUL_16,
5560   BFIN_BUILTIN_CPLX_MAC_16,
5561   BFIN_BUILTIN_CPLX_MSU_16,
5562
5563   BFIN_BUILTIN_CPLX_MUL_16_S40,
5564   BFIN_BUILTIN_CPLX_MAC_16_S40,
5565   BFIN_BUILTIN_CPLX_MSU_16_S40,
5566
5567   BFIN_BUILTIN_CPLX_SQU,
5568
5569   BFIN_BUILTIN_LOADBYTES,
5570
5571   BFIN_BUILTIN_MAX
5572 };
5573
5574 #define def_builtin(NAME, TYPE, CODE)                                   \
5575 do {                                                                    \
5576   add_builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD,            \
5577                        NULL, NULL_TREE);                                \
5578 } while (0)
5579
5580 /* Set up all builtin functions for this target.  */
5581 static void
5582 bfin_init_builtins (void)
5583 {
5584   tree V2HI_type_node = build_vector_type_for_mode (intHI_type_node, V2HImode);
5585   tree void_ftype_void
5586     = build_function_type (void_type_node, void_list_node);
5587   tree short_ftype_short
5588     = build_function_type_list (short_integer_type_node, short_integer_type_node,
5589                                 NULL_TREE);
5590   tree short_ftype_int_int
5591     = build_function_type_list (short_integer_type_node, integer_type_node,
5592                                 integer_type_node, NULL_TREE);
5593   tree int_ftype_int_int
5594     = build_function_type_list (integer_type_node, integer_type_node,
5595                                 integer_type_node, NULL_TREE);
5596   tree int_ftype_int
5597     = build_function_type_list (integer_type_node, integer_type_node,
5598                                 NULL_TREE);
5599   tree short_ftype_int
5600     = build_function_type_list (short_integer_type_node, integer_type_node,
5601                                 NULL_TREE);
5602   tree int_ftype_v2hi_v2hi
5603     = build_function_type_list (integer_type_node, V2HI_type_node,
5604                                 V2HI_type_node, NULL_TREE);
5605   tree v2hi_ftype_v2hi_v2hi
5606     = build_function_type_list (V2HI_type_node, V2HI_type_node,
5607                                 V2HI_type_node, NULL_TREE);
5608   tree v2hi_ftype_v2hi_v2hi_v2hi
5609     = build_function_type_list (V2HI_type_node, V2HI_type_node,
5610                                 V2HI_type_node, V2HI_type_node, NULL_TREE);
5611   tree v2hi_ftype_int_int
5612     = build_function_type_list (V2HI_type_node, integer_type_node,
5613                                 integer_type_node, NULL_TREE);
5614   tree v2hi_ftype_v2hi_int
5615     = build_function_type_list (V2HI_type_node, V2HI_type_node,
5616                                 integer_type_node, NULL_TREE);
5617   tree int_ftype_short_short
5618     = build_function_type_list (integer_type_node, short_integer_type_node,
5619                                 short_integer_type_node, NULL_TREE);
5620   tree v2hi_ftype_v2hi
5621     = build_function_type_list (V2HI_type_node, V2HI_type_node, NULL_TREE);
5622   tree short_ftype_v2hi
5623     = build_function_type_list (short_integer_type_node, V2HI_type_node,
5624                                 NULL_TREE);
5625   tree int_ftype_pint
5626     = build_function_type_list (integer_type_node,
5627                                 build_pointer_type (integer_type_node),
5628                                 NULL_TREE);
5629   
5630   /* Add the remaining MMX insns with somewhat more complicated types.  */
5631   def_builtin ("__builtin_bfin_csync", void_ftype_void, BFIN_BUILTIN_CSYNC);
5632   def_builtin ("__builtin_bfin_ssync", void_ftype_void, BFIN_BUILTIN_SSYNC);
5633
5634   def_builtin ("__builtin_bfin_ones", short_ftype_int, BFIN_BUILTIN_ONES);
5635
5636   def_builtin ("__builtin_bfin_compose_2x16", v2hi_ftype_int_int,
5637                BFIN_BUILTIN_COMPOSE_2X16);
5638   def_builtin ("__builtin_bfin_extract_hi", short_ftype_v2hi,
5639                BFIN_BUILTIN_EXTRACTHI);
5640   def_builtin ("__builtin_bfin_extract_lo", short_ftype_v2hi,
5641                BFIN_BUILTIN_EXTRACTLO);
5642
5643   def_builtin ("__builtin_bfin_min_fr2x16", v2hi_ftype_v2hi_v2hi,
5644                BFIN_BUILTIN_MIN_2X16);
5645   def_builtin ("__builtin_bfin_max_fr2x16", v2hi_ftype_v2hi_v2hi,
5646                BFIN_BUILTIN_MAX_2X16);
5647
5648   def_builtin ("__builtin_bfin_add_fr2x16", v2hi_ftype_v2hi_v2hi,
5649                BFIN_BUILTIN_SSADD_2X16);
5650   def_builtin ("__builtin_bfin_sub_fr2x16", v2hi_ftype_v2hi_v2hi,
5651                BFIN_BUILTIN_SSSUB_2X16);
5652   def_builtin ("__builtin_bfin_dspaddsubsat", v2hi_ftype_v2hi_v2hi,
5653                BFIN_BUILTIN_SSADDSUB_2X16);
5654   def_builtin ("__builtin_bfin_dspsubaddsat", v2hi_ftype_v2hi_v2hi,
5655                BFIN_BUILTIN_SSSUBADD_2X16);
5656   def_builtin ("__builtin_bfin_mult_fr2x16", v2hi_ftype_v2hi_v2hi,
5657                BFIN_BUILTIN_MULT_2X16);
5658   def_builtin ("__builtin_bfin_multr_fr2x16", v2hi_ftype_v2hi_v2hi,
5659                BFIN_BUILTIN_MULTR_2X16);
5660   def_builtin ("__builtin_bfin_negate_fr2x16", v2hi_ftype_v2hi,
5661                BFIN_BUILTIN_NEG_2X16);
5662   def_builtin ("__builtin_bfin_abs_fr2x16", v2hi_ftype_v2hi,
5663                BFIN_BUILTIN_ABS_2X16);
5664
5665   def_builtin ("__builtin_bfin_min_fr1x16", short_ftype_int_int,
5666                BFIN_BUILTIN_MIN_1X16);
5667   def_builtin ("__builtin_bfin_max_fr1x16", short_ftype_int_int,
5668                BFIN_BUILTIN_MAX_1X16);
5669
5670   def_builtin ("__builtin_bfin_add_fr1x16", short_ftype_int_int,
5671                BFIN_BUILTIN_SSADD_1X16);
5672   def_builtin ("__builtin_bfin_sub_fr1x16", short_ftype_int_int,
5673                BFIN_BUILTIN_SSSUB_1X16);
5674   def_builtin ("__builtin_bfin_mult_fr1x16", short_ftype_int_int,
5675                BFIN_BUILTIN_MULT_1X16);
5676   def_builtin ("__builtin_bfin_multr_fr1x16", short_ftype_int_int,
5677                BFIN_BUILTIN_MULTR_1X16);
5678   def_builtin ("__builtin_bfin_negate_fr1x16", short_ftype_short,
5679                BFIN_BUILTIN_NEG_1X16);
5680   def_builtin ("__builtin_bfin_abs_fr1x16", short_ftype_short,
5681                BFIN_BUILTIN_ABS_1X16);
5682   def_builtin ("__builtin_bfin_norm_fr1x16", short_ftype_int,
5683                BFIN_BUILTIN_NORM_1X16);
5684
5685   def_builtin ("__builtin_bfin_sum_fr2x16", short_ftype_v2hi,
5686                BFIN_BUILTIN_SUM_2X16);
5687   def_builtin ("__builtin_bfin_diff_hl_fr2x16", short_ftype_v2hi,
5688                BFIN_BUILTIN_DIFFHL_2X16);
5689   def_builtin ("__builtin_bfin_diff_lh_fr2x16", short_ftype_v2hi,
5690                BFIN_BUILTIN_DIFFLH_2X16);
5691
5692   def_builtin ("__builtin_bfin_mulhisill", int_ftype_v2hi_v2hi,
5693                BFIN_BUILTIN_MULHISILL);
5694   def_builtin ("__builtin_bfin_mulhisihl", int_ftype_v2hi_v2hi,
5695                BFIN_BUILTIN_MULHISIHL);
5696   def_builtin ("__builtin_bfin_mulhisilh", int_ftype_v2hi_v2hi,
5697                BFIN_BUILTIN_MULHISILH);
5698   def_builtin ("__builtin_bfin_mulhisihh", int_ftype_v2hi_v2hi,
5699                BFIN_BUILTIN_MULHISIHH);
5700
5701   def_builtin ("__builtin_bfin_min_fr1x32", int_ftype_int_int,
5702                BFIN_BUILTIN_MIN_1X32);
5703   def_builtin ("__builtin_bfin_max_fr1x32", int_ftype_int_int,
5704                BFIN_BUILTIN_MAX_1X32);
5705
5706   def_builtin ("__builtin_bfin_add_fr1x32", int_ftype_int_int,
5707                BFIN_BUILTIN_SSADD_1X32);
5708   def_builtin ("__builtin_bfin_sub_fr1x32", int_ftype_int_int,
5709                BFIN_BUILTIN_SSSUB_1X32);
5710   def_builtin ("__builtin_bfin_negate_fr1x32", int_ftype_int,
5711                BFIN_BUILTIN_NEG_1X32);
5712   def_builtin ("__builtin_bfin_abs_fr1x32", int_ftype_int,
5713                BFIN_BUILTIN_ABS_1X32);
5714   def_builtin ("__builtin_bfin_norm_fr1x32", short_ftype_int,
5715                BFIN_BUILTIN_NORM_1X32);
5716   def_builtin ("__builtin_bfin_round_fr1x32", short_ftype_int,
5717                BFIN_BUILTIN_ROUND_1X32);
5718   def_builtin ("__builtin_bfin_mult_fr1x32", int_ftype_short_short,
5719                BFIN_BUILTIN_MULT_1X32);
5720   def_builtin ("__builtin_bfin_mult_fr1x32x32", int_ftype_int_int,
5721                BFIN_BUILTIN_MULT_1X32X32);
5722   def_builtin ("__builtin_bfin_mult_fr1x32x32NS", int_ftype_int_int,
5723                BFIN_BUILTIN_MULT_1X32X32NS);
5724
5725   /* Shifts.  */
5726   def_builtin ("__builtin_bfin_shl_fr1x16", short_ftype_int_int,
5727                BFIN_BUILTIN_SSASHIFT_1X16);
5728   def_builtin ("__builtin_bfin_shl_fr2x16", v2hi_ftype_v2hi_int,
5729                BFIN_BUILTIN_SSASHIFT_2X16);
5730   def_builtin ("__builtin_bfin_lshl_fr1x16", short_ftype_int_int,
5731                BFIN_BUILTIN_LSHIFT_1X16);
5732   def_builtin ("__builtin_bfin_lshl_fr2x16", v2hi_ftype_v2hi_int,
5733                BFIN_BUILTIN_LSHIFT_2X16);
5734   def_builtin ("__builtin_bfin_shl_fr1x32", int_ftype_int_int,
5735                BFIN_BUILTIN_SSASHIFT_1X32);
5736
5737   /* Complex numbers.  */
5738   def_builtin ("__builtin_bfin_cmplx_add", v2hi_ftype_v2hi_v2hi,
5739                BFIN_BUILTIN_SSADD_2X16);
5740   def_builtin ("__builtin_bfin_cmplx_sub", v2hi_ftype_v2hi_v2hi,
5741                BFIN_BUILTIN_SSSUB_2X16);
5742   def_builtin ("__builtin_bfin_cmplx_mul", v2hi_ftype_v2hi_v2hi,
5743                BFIN_BUILTIN_CPLX_MUL_16);
5744   def_builtin ("__builtin_bfin_cmplx_mac", v2hi_ftype_v2hi_v2hi_v2hi,
5745                BFIN_BUILTIN_CPLX_MAC_16);
5746   def_builtin ("__builtin_bfin_cmplx_msu", v2hi_ftype_v2hi_v2hi_v2hi,
5747                BFIN_BUILTIN_CPLX_MSU_16);
5748   def_builtin ("__builtin_bfin_cmplx_mul_s40", v2hi_ftype_v2hi_v2hi,
5749                BFIN_BUILTIN_CPLX_MUL_16_S40);
5750   def_builtin ("__builtin_bfin_cmplx_mac_s40", v2hi_ftype_v2hi_v2hi_v2hi,
5751                BFIN_BUILTIN_CPLX_MAC_16_S40);
5752   def_builtin ("__builtin_bfin_cmplx_msu_s40", v2hi_ftype_v2hi_v2hi_v2hi,
5753                BFIN_BUILTIN_CPLX_MSU_16_S40);
5754   def_builtin ("__builtin_bfin_csqu_fr16", v2hi_ftype_v2hi,
5755                BFIN_BUILTIN_CPLX_SQU);
5756
5757   /* "Unaligned" load.  */
5758   def_builtin ("__builtin_bfin_loadbytes", int_ftype_pint,
5759                BFIN_BUILTIN_LOADBYTES);
5760
5761 }
5762
5763
5764 struct builtin_description
5765 {
5766   const enum insn_code icode;
5767   const char *const name;
5768   const enum bfin_builtins code;
5769   int macflag;
5770 };
5771
5772 static const struct builtin_description bdesc_2arg[] =
5773 {
5774   { CODE_FOR_composev2hi, "__builtin_bfin_compose_2x16", BFIN_BUILTIN_COMPOSE_2X16, -1 },
5775
5776   { CODE_FOR_ssashiftv2hi3, "__builtin_bfin_shl_fr2x16", BFIN_BUILTIN_SSASHIFT_2X16, -1 },
5777   { CODE_FOR_ssashifthi3, "__builtin_bfin_shl_fr1x16", BFIN_BUILTIN_SSASHIFT_1X16, -1 },
5778   { CODE_FOR_lshiftv2hi3, "__builtin_bfin_lshl_fr2x16", BFIN_BUILTIN_LSHIFT_2X16, -1 },
5779   { CODE_FOR_lshifthi3, "__builtin_bfin_lshl_fr1x16", BFIN_BUILTIN_LSHIFT_1X16, -1 },
5780   { CODE_FOR_ssashiftsi3, "__builtin_bfin_shl_fr1x32", BFIN_BUILTIN_SSASHIFT_1X32, -1 },
5781
5782   { CODE_FOR_sminhi3, "__builtin_bfin_min_fr1x16", BFIN_BUILTIN_MIN_1X16, -1 },
5783   { CODE_FOR_smaxhi3, "__builtin_bfin_max_fr1x16", BFIN_BUILTIN_MAX_1X16, -1 },
5784   { CODE_FOR_ssaddhi3, "__builtin_bfin_add_fr1x16", BFIN_BUILTIN_SSADD_1X16, -1 },
5785   { CODE_FOR_sssubhi3, "__builtin_bfin_sub_fr1x16", BFIN_BUILTIN_SSSUB_1X16, -1 },
5786
5787   { CODE_FOR_sminsi3, "__builtin_bfin_min_fr1x32", BFIN_BUILTIN_MIN_1X32, -1 },
5788   { CODE_FOR_smaxsi3, "__builtin_bfin_max_fr1x32", BFIN_BUILTIN_MAX_1X32, -1 },
5789   { CODE_FOR_ssaddsi3, "__builtin_bfin_add_fr1x32", BFIN_BUILTIN_SSADD_1X32, -1 },
5790   { CODE_FOR_sssubsi3, "__builtin_bfin_sub_fr1x32", BFIN_BUILTIN_SSSUB_1X32, -1 },
5791
5792   { CODE_FOR_sminv2hi3, "__builtin_bfin_min_fr2x16", BFIN_BUILTIN_MIN_2X16, -1 },
5793   { CODE_FOR_smaxv2hi3, "__builtin_bfin_max_fr2x16", BFIN_BUILTIN_MAX_2X16, -1 },
5794   { CODE_FOR_ssaddv2hi3, "__builtin_bfin_add_fr2x16", BFIN_BUILTIN_SSADD_2X16, -1 },
5795   { CODE_FOR_sssubv2hi3, "__builtin_bfin_sub_fr2x16", BFIN_BUILTIN_SSSUB_2X16, -1 },
5796   { CODE_FOR_ssaddsubv2hi3, "__builtin_bfin_dspaddsubsat", BFIN_BUILTIN_SSADDSUB_2X16, -1 },
5797   { CODE_FOR_sssubaddv2hi3, "__builtin_bfin_dspsubaddsat", BFIN_BUILTIN_SSSUBADD_2X16, -1 },
5798
5799   { CODE_FOR_flag_mulhisi, "__builtin_bfin_mult_fr1x32", BFIN_BUILTIN_MULT_1X32, MACFLAG_NONE },
5800   { CODE_FOR_flag_mulhi, "__builtin_bfin_mult_fr1x16", BFIN_BUILTIN_MULT_1X16, MACFLAG_T },
5801   { CODE_FOR_flag_mulhi, "__builtin_bfin_multr_fr1x16", BFIN_BUILTIN_MULTR_1X16, MACFLAG_NONE },
5802   { CODE_FOR_flag_mulv2hi, "__builtin_bfin_mult_fr2x16", BFIN_BUILTIN_MULT_2X16, MACFLAG_T },
5803   { CODE_FOR_flag_mulv2hi, "__builtin_bfin_multr_fr2x16", BFIN_BUILTIN_MULTR_2X16, MACFLAG_NONE },
5804
5805   { CODE_FOR_mulhisi_ll, "__builtin_bfin_mulhisill", BFIN_BUILTIN_MULHISILL, -1 },
5806   { CODE_FOR_mulhisi_lh, "__builtin_bfin_mulhisilh", BFIN_BUILTIN_MULHISILH, -1 },
5807   { CODE_FOR_mulhisi_hl, "__builtin_bfin_mulhisihl", BFIN_BUILTIN_MULHISIHL, -1 },
5808   { CODE_FOR_mulhisi_hh, "__builtin_bfin_mulhisihh", BFIN_BUILTIN_MULHISIHH, -1 }
5809
5810 };
5811
5812 static const struct builtin_description bdesc_1arg[] =
5813 {
5814   { CODE_FOR_loadbytes, "__builtin_bfin_loadbytes", BFIN_BUILTIN_LOADBYTES, 0 },
5815
5816   { CODE_FOR_ones, "__builtin_bfin_ones", BFIN_BUILTIN_ONES, 0 },
5817
5818   { CODE_FOR_signbitshi2, "__builtin_bfin_norm_fr1x16", BFIN_BUILTIN_NORM_1X16, 0 },
5819   { CODE_FOR_ssneghi2, "__builtin_bfin_negate_fr1x16", BFIN_BUILTIN_NEG_1X16, 0 },
5820   { CODE_FOR_abshi2, "__builtin_bfin_abs_fr1x16", BFIN_BUILTIN_ABS_1X16, 0 },
5821
5822   { CODE_FOR_signbitssi2, "__builtin_bfin_norm_fr1x32", BFIN_BUILTIN_NORM_1X32, 0 },
5823   { CODE_FOR_ssroundsi2, "__builtin_bfin_round_fr1x32", BFIN_BUILTIN_ROUND_1X32, 0 },
5824   { CODE_FOR_ssnegsi2, "__builtin_bfin_negate_fr1x32", BFIN_BUILTIN_NEG_1X32, 0 },
5825   { CODE_FOR_ssabssi2, "__builtin_bfin_abs_fr1x32", BFIN_BUILTIN_ABS_1X32, 0 },
5826
5827   { CODE_FOR_movv2hi_hi_low, "__builtin_bfin_extract_lo", BFIN_BUILTIN_EXTRACTLO, 0 },
5828   { CODE_FOR_movv2hi_hi_high, "__builtin_bfin_extract_hi", BFIN_BUILTIN_EXTRACTHI, 0 },
5829   { CODE_FOR_ssnegv2hi2, "__builtin_bfin_negate_fr2x16", BFIN_BUILTIN_NEG_2X16, 0 },
5830   { CODE_FOR_ssabsv2hi2, "__builtin_bfin_abs_fr2x16", BFIN_BUILTIN_ABS_2X16, 0 }
5831 };
5832
5833 /* Errors in the source file can cause expand_expr to return const0_rtx
5834    where we expect a vector.  To avoid crashing, use one of the vector
5835    clear instructions.  */
5836 static rtx
5837 safe_vector_operand (rtx x, enum machine_mode mode)
5838 {
5839   if (x != const0_rtx)
5840     return x;
5841   x = gen_reg_rtx (SImode);
5842
5843   emit_insn (gen_movsi (x, CONST0_RTX (SImode)));
5844   return gen_lowpart (mode, x);
5845 }
5846
5847 /* Subroutine of bfin_expand_builtin to take care of binop insns.  MACFLAG is -1
5848    if this is a normal binary op, or one of the MACFLAG_xxx constants.  */
5849
5850 static rtx
5851 bfin_expand_binop_builtin (enum insn_code icode, tree exp, rtx target,
5852                            int macflag)
5853 {
5854   rtx pat;
5855   tree arg0 = CALL_EXPR_ARG (exp, 0);
5856   tree arg1 = CALL_EXPR_ARG (exp, 1);
5857   rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
5858   rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
5859   enum machine_mode op0mode = GET_MODE (op0);
5860   enum machine_mode op1mode = GET_MODE (op1);
5861   enum machine_mode tmode = insn_data[icode].operand[0].mode;
5862   enum machine_mode mode0 = insn_data[icode].operand[1].mode;
5863   enum machine_mode mode1 = insn_data[icode].operand[2].mode;
5864
5865   if (VECTOR_MODE_P (mode0))
5866     op0 = safe_vector_operand (op0, mode0);
5867   if (VECTOR_MODE_P (mode1))
5868     op1 = safe_vector_operand (op1, mode1);
5869
5870   if (! target
5871       || GET_MODE (target) != tmode
5872       || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
5873     target = gen_reg_rtx (tmode);
5874
5875   if ((op0mode == SImode || op0mode == VOIDmode) && mode0 == HImode)
5876     {
5877       op0mode = HImode;
5878       op0 = gen_lowpart (HImode, op0);
5879     }
5880   if ((op1mode == SImode || op1mode == VOIDmode) && mode1 == HImode)
5881     {
5882       op1mode = HImode;
5883       op1 = gen_lowpart (HImode, op1);
5884     }
5885   /* In case the insn wants input operands in modes different from
5886      the result, abort.  */
5887   gcc_assert ((op0mode == mode0 || op0mode == VOIDmode)
5888               && (op1mode == mode1 || op1mode == VOIDmode));
5889
5890   if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
5891     op0 = copy_to_mode_reg (mode0, op0);
5892   if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
5893     op1 = copy_to_mode_reg (mode1, op1);
5894
5895   if (macflag == -1)
5896     pat = GEN_FCN (icode) (target, op0, op1);
5897   else
5898     pat = GEN_FCN (icode) (target, op0, op1, GEN_INT (macflag));
5899   if (! pat)
5900     return 0;
5901
5902   emit_insn (pat);
5903   return target;
5904 }
5905
5906 /* Subroutine of bfin_expand_builtin to take care of unop insns.  */
5907
5908 static rtx
5909 bfin_expand_unop_builtin (enum insn_code icode, tree exp,
5910                           rtx target)
5911 {
5912   rtx pat;
5913   tree arg0 = CALL_EXPR_ARG (exp, 0);
5914   rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
5915   enum machine_mode op0mode = GET_MODE (op0);
5916   enum machine_mode tmode = insn_data[icode].operand[0].mode;
5917   enum machine_mode mode0 = insn_data[icode].operand[1].mode;
5918
5919   if (! target
5920       || GET_MODE (target) != tmode
5921       || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
5922     target = gen_reg_rtx (tmode);
5923
5924   if (VECTOR_MODE_P (mode0))
5925     op0 = safe_vector_operand (op0, mode0);
5926
5927   if (op0mode == SImode && mode0 == HImode)
5928     {
5929       op0mode = HImode;
5930       op0 = gen_lowpart (HImode, op0);
5931     }
5932   gcc_assert (op0mode == mode0 || op0mode == VOIDmode);
5933
5934   if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
5935     op0 = copy_to_mode_reg (mode0, op0);
5936
5937   pat = GEN_FCN (icode) (target, op0);
5938   if (! pat)
5939     return 0;
5940   emit_insn (pat);
5941   return target;
5942 }
5943
5944 /* Expand an expression EXP that calls a built-in function,
5945    with result going to TARGET if that's convenient
5946    (and in mode MODE if that's convenient).
5947    SUBTARGET may be used as the target for computing one of EXP's operands.
5948    IGNORE is nonzero if the value is to be ignored.  */
5949
5950 static rtx
5951 bfin_expand_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
5952                      rtx subtarget ATTRIBUTE_UNUSED,
5953                      enum machine_mode mode ATTRIBUTE_UNUSED,
5954                      int ignore ATTRIBUTE_UNUSED)
5955 {
5956   size_t i;
5957   enum insn_code icode;
5958   const struct builtin_description *d;
5959   tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
5960   unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
5961   tree arg0, arg1, arg2;
5962   rtx op0, op1, op2, accvec, pat, tmp1, tmp2, a0reg, a1reg;
5963   enum machine_mode tmode, mode0;
5964
5965   switch (fcode)
5966     {
5967     case BFIN_BUILTIN_CSYNC:
5968       emit_insn (gen_csync ());
5969       return 0;
5970     case BFIN_BUILTIN_SSYNC:
5971       emit_insn (gen_ssync ());
5972       return 0;
5973
5974     case BFIN_BUILTIN_DIFFHL_2X16:
5975     case BFIN_BUILTIN_DIFFLH_2X16:
5976     case BFIN_BUILTIN_SUM_2X16:
5977       arg0 = CALL_EXPR_ARG (exp, 0);
5978       op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
5979       icode = (fcode == BFIN_BUILTIN_DIFFHL_2X16 ? CODE_FOR_subhilov2hi3
5980                : fcode == BFIN_BUILTIN_DIFFLH_2X16 ? CODE_FOR_sublohiv2hi3
5981                : CODE_FOR_ssaddhilov2hi3);
5982       tmode = insn_data[icode].operand[0].mode;
5983       mode0 = insn_data[icode].operand[1].mode;
5984
5985       if (! target
5986           || GET_MODE (target) != tmode
5987           || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
5988         target = gen_reg_rtx (tmode);
5989
5990       if (VECTOR_MODE_P (mode0))
5991         op0 = safe_vector_operand (op0, mode0);
5992
5993       if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
5994         op0 = copy_to_mode_reg (mode0, op0);
5995
5996       pat = GEN_FCN (icode) (target, op0, op0);
5997       if (! pat)
5998         return 0;
5999       emit_insn (pat);
6000       return target;
6001
6002     case BFIN_BUILTIN_MULT_1X32X32:
6003     case BFIN_BUILTIN_MULT_1X32X32NS:
6004       arg0 = CALL_EXPR_ARG (exp, 0);
6005       arg1 = CALL_EXPR_ARG (exp, 1);
6006       op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6007       op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
6008       if (! target
6009           || !register_operand (target, SImode))
6010         target = gen_reg_rtx (SImode);
6011
6012       a1reg = gen_rtx_REG (PDImode, REG_A1);
6013       a0reg = gen_rtx_REG (PDImode, REG_A0);
6014       tmp1 = gen_lowpart (V2HImode, op0);
6015       tmp2 = gen_lowpart (V2HImode, op1);
6016       emit_insn (gen_flag_macinit1hi (a1reg,
6017                                       gen_lowpart (HImode, op0),
6018                                       gen_lowpart (HImode, op1),
6019                                       GEN_INT (MACFLAG_FU)));
6020       emit_insn (gen_lshrpdi3 (a1reg, a1reg, GEN_INT (16)));
6021
6022       if (fcode == BFIN_BUILTIN_MULT_1X32X32)
6023         emit_insn (gen_flag_mul_macv2hi_parts_acconly (a0reg, a1reg, tmp1, tmp2,
6024                                                        const1_rtx, const1_rtx,
6025                                                        const1_rtx, const0_rtx, a1reg,
6026                                                        const0_rtx, GEN_INT (MACFLAG_NONE),
6027                                                        GEN_INT (MACFLAG_M)));
6028       else
6029         {
6030           /* For saturating multiplication, there's exactly one special case
6031              to be handled: multiplying the smallest negative value with
6032              itself.  Due to shift correction in fractional multiplies, this
6033              can overflow.  Iff this happens, OP2 will contain 1, which, when
6034              added in 32 bits to the smallest negative, wraps to the largest
6035              positive, which is the result we want.  */
6036           op2 = gen_reg_rtx (V2HImode);
6037           emit_insn (gen_packv2hi (op2, tmp1, tmp2, const0_rtx, const0_rtx));
6038           emit_insn (gen_movsibi (gen_rtx_REG (BImode, REG_CC),
6039                                   gen_lowpart (SImode, op2)));
6040           emit_insn (gen_flag_mul_macv2hi_parts_acconly_andcc0 (a0reg, a1reg, tmp1, tmp2,
6041                                                                 const1_rtx, const1_rtx,
6042                                                                 const1_rtx, const0_rtx, a1reg,
6043                                                                 const0_rtx, GEN_INT (MACFLAG_NONE),
6044                                                                 GEN_INT (MACFLAG_M)));
6045           op2 = gen_reg_rtx (SImode);
6046           emit_insn (gen_movbisi (op2, gen_rtx_REG (BImode, REG_CC)));
6047         }
6048       emit_insn (gen_flag_machi_parts_acconly (a1reg, tmp2, tmp1,
6049                                                const1_rtx, const0_rtx,
6050                                                a1reg, const0_rtx, GEN_INT (MACFLAG_M)));
6051       emit_insn (gen_ashrpdi3 (a1reg, a1reg, GEN_INT (15)));
6052       emit_insn (gen_sum_of_accumulators (target, a0reg, a0reg, a1reg));
6053       if (fcode == BFIN_BUILTIN_MULT_1X32X32NS)
6054         emit_insn (gen_addsi3 (target, target, op2));
6055       return target;
6056
6057     case BFIN_BUILTIN_CPLX_MUL_16:
6058     case BFIN_BUILTIN_CPLX_MUL_16_S40:
6059       arg0 = CALL_EXPR_ARG (exp, 0);
6060       arg1 = CALL_EXPR_ARG (exp, 1);
6061       op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6062       op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
6063       accvec = gen_reg_rtx (V2PDImode);
6064
6065       if (! target
6066           || GET_MODE (target) != V2HImode
6067           || ! (*insn_data[icode].operand[0].predicate) (target, V2HImode))
6068         target = gen_reg_rtx (tmode);
6069       if (! register_operand (op0, GET_MODE (op0)))
6070         op0 = copy_to_mode_reg (GET_MODE (op0), op0);
6071       if (! register_operand (op1, GET_MODE (op1)))
6072         op1 = copy_to_mode_reg (GET_MODE (op1), op1);
6073
6074       if (fcode == BFIN_BUILTIN_CPLX_MUL_16)
6075         emit_insn (gen_flag_macinit1v2hi_parts (accvec, op0, op1, const0_rtx,
6076                                                 const0_rtx, const0_rtx,
6077                                                 const1_rtx, GEN_INT (MACFLAG_W32)));
6078       else
6079         emit_insn (gen_flag_macinit1v2hi_parts (accvec, op0, op1, const0_rtx,
6080                                                 const0_rtx, const0_rtx,
6081                                                 const1_rtx, GEN_INT (MACFLAG_NONE)));
6082       emit_insn (gen_flag_macv2hi_parts (target, op0, op1, const1_rtx,
6083                                          const1_rtx, const1_rtx,
6084                                          const0_rtx, accvec, const1_rtx, const0_rtx,
6085                                          GEN_INT (MACFLAG_NONE), accvec));
6086
6087       return target;
6088
6089     case BFIN_BUILTIN_CPLX_MAC_16:
6090     case BFIN_BUILTIN_CPLX_MSU_16:
6091     case BFIN_BUILTIN_CPLX_MAC_16_S40:
6092     case BFIN_BUILTIN_CPLX_MSU_16_S40:
6093       arg0 = CALL_EXPR_ARG (exp, 0);
6094       arg1 = CALL_EXPR_ARG (exp, 1);
6095       arg2 = CALL_EXPR_ARG (exp, 2);
6096       op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6097       op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
6098       op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
6099       accvec = gen_reg_rtx (V2PDImode);
6100
6101       if (! target
6102           || GET_MODE (target) != V2HImode
6103           || ! (*insn_data[icode].operand[0].predicate) (target, V2HImode))
6104         target = gen_reg_rtx (tmode);
6105       if (! register_operand (op1, GET_MODE (op1)))
6106         op1 = copy_to_mode_reg (GET_MODE (op1), op1);
6107       if (! register_operand (op2, GET_MODE (op2)))
6108         op2 = copy_to_mode_reg (GET_MODE (op2), op2);
6109
6110       tmp1 = gen_reg_rtx (SImode);
6111       tmp2 = gen_reg_rtx (SImode);
6112       emit_insn (gen_ashlsi3 (tmp1, gen_lowpart (SImode, op0), GEN_INT (16)));
6113       emit_move_insn (tmp2, gen_lowpart (SImode, op0));
6114       emit_insn (gen_movstricthi_1 (gen_lowpart (HImode, tmp2), const0_rtx));
6115       emit_insn (gen_load_accumulator_pair (accvec, tmp1, tmp2));
6116       if (fcode == BFIN_BUILTIN_CPLX_MAC_16
6117           || fcode == BFIN_BUILTIN_CPLX_MSU_16)
6118         emit_insn (gen_flag_macv2hi_parts_acconly (accvec, op1, op2, const0_rtx,
6119                                                    const0_rtx, const0_rtx,
6120                                                    const1_rtx, accvec, const0_rtx,
6121                                                    const0_rtx,
6122                                                    GEN_INT (MACFLAG_W32)));
6123       else
6124         emit_insn (gen_flag_macv2hi_parts_acconly (accvec, op1, op2, const0_rtx,
6125                                                    const0_rtx, const0_rtx,
6126                                                    const1_rtx, accvec, const0_rtx,
6127                                                    const0_rtx,
6128                                                    GEN_INT (MACFLAG_NONE)));
6129       if (fcode == BFIN_BUILTIN_CPLX_MAC_16
6130           || fcode == BFIN_BUILTIN_CPLX_MAC_16_S40)
6131         {
6132           tmp1 = const1_rtx;
6133           tmp2 = const0_rtx;
6134         }
6135       else
6136         {
6137           tmp1 = const0_rtx;
6138           tmp2 = const1_rtx;
6139         }
6140       emit_insn (gen_flag_macv2hi_parts (target, op1, op2, const1_rtx,
6141                                          const1_rtx, const1_rtx,
6142                                          const0_rtx, accvec, tmp1, tmp2,
6143                                          GEN_INT (MACFLAG_NONE), accvec));
6144
6145       return target;
6146
6147     case BFIN_BUILTIN_CPLX_SQU:
6148       arg0 = CALL_EXPR_ARG (exp, 0);
6149       op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6150       accvec = gen_reg_rtx (V2PDImode);
6151       icode = CODE_FOR_flag_mulv2hi;
6152       tmp1 = gen_reg_rtx (V2HImode);
6153       tmp2 = gen_reg_rtx (V2HImode);
6154
6155       if (! target
6156           || GET_MODE (target) != V2HImode
6157           || ! (*insn_data[icode].operand[0].predicate) (target, V2HImode))
6158         target = gen_reg_rtx (V2HImode);
6159       if (! register_operand (op0, GET_MODE (op0)))
6160         op0 = copy_to_mode_reg (GET_MODE (op0), op0);
6161
6162       emit_insn (gen_flag_mulv2hi (tmp1, op0, op0, GEN_INT (MACFLAG_NONE)));
6163
6164       emit_insn (gen_flag_mulhi_parts (gen_lowpart (HImode, tmp2), op0, op0,
6165                                        const0_rtx, const1_rtx,
6166                                        GEN_INT (MACFLAG_NONE)));
6167
6168       emit_insn (gen_ssaddhi3_high_parts (target, tmp2, tmp2, tmp2, const0_rtx,
6169                                           const0_rtx));
6170       emit_insn (gen_sssubhi3_low_parts (target, target, tmp1, tmp1,
6171                                          const0_rtx, const1_rtx));
6172
6173       return target;
6174
6175     default:
6176       break;
6177     }
6178
6179   for (i = 0, d = bdesc_2arg; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
6180     if (d->code == fcode)
6181       return bfin_expand_binop_builtin (d->icode, exp, target,
6182                                         d->macflag);
6183
6184   for (i = 0, d = bdesc_1arg; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
6185     if (d->code == fcode)
6186       return bfin_expand_unop_builtin (d->icode, exp, target);
6187
6188   gcc_unreachable ();
6189 }
6190 \f
6191 #undef TARGET_INIT_BUILTINS
6192 #define TARGET_INIT_BUILTINS bfin_init_builtins
6193
6194 #undef TARGET_EXPAND_BUILTIN
6195 #define TARGET_EXPAND_BUILTIN bfin_expand_builtin
6196
6197 #undef TARGET_ASM_GLOBALIZE_LABEL
6198 #define TARGET_ASM_GLOBALIZE_LABEL bfin_globalize_label 
6199
6200 #undef TARGET_ASM_FILE_START
6201 #define TARGET_ASM_FILE_START output_file_start
6202
6203 #undef TARGET_ATTRIBUTE_TABLE
6204 #define TARGET_ATTRIBUTE_TABLE bfin_attribute_table
6205
6206 #undef TARGET_COMP_TYPE_ATTRIBUTES
6207 #define TARGET_COMP_TYPE_ATTRIBUTES bfin_comp_type_attributes
6208
6209 #undef TARGET_RTX_COSTS
6210 #define TARGET_RTX_COSTS bfin_rtx_costs
6211
6212 #undef  TARGET_ADDRESS_COST
6213 #define TARGET_ADDRESS_COST bfin_address_cost
6214
6215 #undef  TARGET_ASM_INTEGER
6216 #define TARGET_ASM_INTEGER bfin_assemble_integer
6217
6218 #undef TARGET_MACHINE_DEPENDENT_REORG
6219 #define TARGET_MACHINE_DEPENDENT_REORG bfin_reorg
6220
6221 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
6222 #define TARGET_FUNCTION_OK_FOR_SIBCALL bfin_function_ok_for_sibcall
6223
6224 #undef TARGET_ASM_OUTPUT_MI_THUNK
6225 #define TARGET_ASM_OUTPUT_MI_THUNK bfin_output_mi_thunk
6226 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
6227 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true
6228
6229 #undef TARGET_SCHED_ADJUST_COST
6230 #define TARGET_SCHED_ADJUST_COST bfin_adjust_cost
6231
6232 #undef TARGET_SCHED_ISSUE_RATE
6233 #define TARGET_SCHED_ISSUE_RATE bfin_issue_rate
6234
6235 #undef TARGET_PROMOTE_PROTOTYPES
6236 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
6237 #undef TARGET_PROMOTE_FUNCTION_ARGS
6238 #define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_const_tree_true
6239 #undef TARGET_PROMOTE_FUNCTION_RETURN
6240 #define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_const_tree_true
6241
6242 #undef TARGET_ARG_PARTIAL_BYTES
6243 #define TARGET_ARG_PARTIAL_BYTES bfin_arg_partial_bytes
6244
6245 #undef TARGET_PASS_BY_REFERENCE
6246 #define TARGET_PASS_BY_REFERENCE bfin_pass_by_reference
6247
6248 #undef TARGET_SETUP_INCOMING_VARARGS
6249 #define TARGET_SETUP_INCOMING_VARARGS setup_incoming_varargs
6250
6251 #undef TARGET_STRUCT_VALUE_RTX
6252 #define TARGET_STRUCT_VALUE_RTX bfin_struct_value_rtx
6253
6254 #undef TARGET_VECTOR_MODE_SUPPORTED_P
6255 #define TARGET_VECTOR_MODE_SUPPORTED_P bfin_vector_mode_supported_p
6256
6257 #undef TARGET_HANDLE_OPTION
6258 #define TARGET_HANDLE_OPTION bfin_handle_option
6259
6260 #undef TARGET_DEFAULT_TARGET_FLAGS
6261 #define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
6262
6263 #undef TARGET_SECONDARY_RELOAD
6264 #define TARGET_SECONDARY_RELOAD bfin_secondary_reload
6265
6266 #undef TARGET_DELEGITIMIZE_ADDRESS
6267 #define TARGET_DELEGITIMIZE_ADDRESS bfin_delegitimize_address
6268
6269 #undef TARGET_CANNOT_FORCE_CONST_MEM
6270 #define TARGET_CANNOT_FORCE_CONST_MEM bfin_cannot_force_const_mem
6271
6272 #undef TARGET_RETURN_IN_MEMORY
6273 #define TARGET_RETURN_IN_MEMORY bfin_return_in_memory
6274
6275 struct gcc_target targetm = TARGET_INITIALIZER;