OSDN Git Service

2009-04-21 Taras Glek <tglek@mozilla.com>
[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, nop_insn;
3796   rtx loop_init, start_label, end_label;
3797   rtx reg_lc0, reg_lc1, reg_lt0, reg_lt1, reg_lb0, reg_lb1;
3798   rtx iter_reg;
3799   rtx lc_reg, lt_reg, lb_reg;
3800   rtx seq, seq_end;
3801   int length;
3802   unsigned ix;
3803   int inner_depth = 0;
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))
4007     {
4008       loop_info inner = (loop_info) bb->aux;
4009       if (inner
4010           && inner->outer == loop
4011           && inner->loop_end == last_insn
4012           && inner->depth == 1)
4013         /* This jump_insn is the exact loop_end of an inner loop
4014            and to be optimized away. So use the inner's last_insn.  */
4015         last_insn = inner->last_insn;
4016       else
4017         {
4018           if (dump_file)
4019             fprintf (dump_file, ";; loop %d has bad last instruction\n",
4020                      loop->loop_no);
4021           goto bad_loop;
4022         }
4023     }
4024   else if (CALL_P (last_insn)
4025            || (GET_CODE (PATTERN (last_insn)) != SEQUENCE
4026                && get_attr_type (last_insn) == TYPE_SYNC)
4027            || recog_memoized (last_insn) == CODE_FOR_return_internal)
4028     {
4029       if (dump_file)
4030         fprintf (dump_file, ";; loop %d has bad last instruction\n",
4031                  loop->loop_no);
4032       goto bad_loop;
4033     }
4034
4035   if (GET_CODE (PATTERN (last_insn)) == ASM_INPUT
4036       || asm_noperands (PATTERN (last_insn)) >= 0
4037       || (GET_CODE (PATTERN (last_insn)) != SEQUENCE
4038           && get_attr_seq_insns (last_insn) == SEQ_INSNS_MULTI))
4039     {
4040       nop_insn = emit_insn_after (gen_nop (), last_insn);
4041       last_insn = nop_insn;
4042     }
4043
4044   loop->last_insn = last_insn;
4045
4046   /* The loop is good for replacement.  */
4047   start_label = loop->start_label;
4048   end_label = gen_label_rtx ();
4049   iter_reg = loop->iter_reg;
4050
4051   if (loop->depth == 1 && !loop->clobber_loop1)
4052     {
4053       lc_reg = reg_lc1;
4054       lt_reg = reg_lt1;
4055       lb_reg = reg_lb1;
4056       loop->clobber_loop1 = 1;
4057     }
4058   else
4059     {
4060       lc_reg = reg_lc0;
4061       lt_reg = reg_lt0;
4062       lb_reg = reg_lb0;
4063       loop->clobber_loop0 = 1;
4064     }
4065
4066   /* If iter_reg is a DREG, we need generate an instruction to load
4067      the loop count into LC register. */
4068   if (D_REGNO_P (REGNO (iter_reg)))
4069     {
4070       init_insn = gen_movsi (lc_reg, iter_reg);
4071       loop_init = gen_lsetup_without_autoinit (lt_reg, start_label,
4072                                                lb_reg, end_label,
4073                                                lc_reg);
4074     }
4075   else if (P_REGNO_P (REGNO (iter_reg)))
4076     {
4077       init_insn = NULL_RTX;
4078       loop_init = gen_lsetup_with_autoinit (lt_reg, start_label,
4079                                             lb_reg, end_label,
4080                                             lc_reg, iter_reg);
4081     }
4082   else
4083     gcc_unreachable ();
4084
4085   loop->init = init_insn;
4086   loop->end_label = end_label;
4087   loop->loop_init = loop_init;
4088
4089   if (dump_file)
4090     {
4091       fprintf (dump_file, ";; replacing loop %d initializer with\n",
4092                loop->loop_no);
4093       print_rtl_single (dump_file, loop->loop_init);
4094       fprintf (dump_file, ";; replacing loop %d terminator with\n",
4095                loop->loop_no);
4096       print_rtl_single (dump_file, loop->loop_end);
4097     }
4098
4099   /* Create a sequence containing the loop setup.  */
4100   start_sequence ();
4101
4102   if (loop->init != NULL_RTX)
4103     emit_insn (loop->init);
4104   seq_end = emit_insn (loop->loop_init);
4105
4106   /* If the loop isn't entered at the top, also create a jump to the entry
4107      point.  */
4108   if (!loop->incoming_src && loop->head != loop->incoming_dest)
4109     {
4110       rtx label = BB_HEAD (loop->incoming_dest);
4111       /* If we're jumping to the final basic block in the loop, and there's
4112          only one cheap instruction before the end (typically an increment of
4113          an induction variable), we can just emit a copy here instead of a
4114          jump.  */
4115       if (loop->incoming_dest == loop->tail
4116           && next_real_insn (label) == last_insn
4117           && asm_noperands (last_insn) < 0
4118           && GET_CODE (PATTERN (last_insn)) == SET)
4119         {
4120           seq_end = emit_insn (copy_rtx (PATTERN (last_insn)));
4121         }
4122       else
4123         seq_end = emit_insn (gen_jump (label));
4124     }
4125
4126   seq = get_insns ();
4127   end_sequence ();
4128
4129   if (loop->incoming_src)
4130     {
4131       rtx prev = BB_END (loop->incoming_src);
4132       if (VEC_length (edge, loop->incoming) > 1
4133           || !(VEC_last (edge, loop->incoming)->flags & EDGE_FALLTHRU))
4134         {
4135           gcc_assert (JUMP_P (prev));
4136           prev = PREV_INSN (prev);
4137         }
4138       emit_insn_after (seq, prev);
4139     }
4140   else
4141     {
4142       basic_block new_bb;
4143       edge e;
4144       edge_iterator ei;
4145
4146 #ifdef ENABLE_CHECKING
4147       if (loop->head != loop->incoming_dest)
4148         {
4149           /* We aren't entering the loop at the top.  Since we've established
4150              that the loop is entered only at one point, this means there
4151              can't be fallthru edges into the head.  Any such fallthru edges
4152              would become invalid when we insert the new block, so verify
4153              that this does not in fact happen.  */
4154           FOR_EACH_EDGE (e, ei, loop->head->preds)
4155             gcc_assert (!(e->flags & EDGE_FALLTHRU));
4156         }
4157 #endif
4158
4159       emit_insn_before (seq, BB_HEAD (loop->head));
4160       seq = emit_label_before (gen_label_rtx (), seq);
4161
4162       new_bb = create_basic_block (seq, seq_end, loop->head->prev_bb);
4163       FOR_EACH_EDGE (e, ei, loop->incoming)
4164         {
4165           if (!(e->flags & EDGE_FALLTHRU)
4166               || e->dest != loop->head)
4167             redirect_edge_and_branch_force (e, new_bb);
4168           else
4169             redirect_edge_succ (e, new_bb);
4170         }
4171     }
4172   
4173   delete_insn (loop->loop_end);
4174   /* Insert the loop end label before the last instruction of the loop.  */
4175   emit_label_before (loop->end_label, loop->last_insn);
4176
4177   return;
4178
4179  bad_loop:
4180
4181   if (dump_file)
4182     fprintf (dump_file, ";; loop %d is bad\n", loop->loop_no);
4183
4184   loop->bad = 1;
4185
4186   if (DPREG_P (loop->iter_reg))
4187     {
4188       /* If loop->iter_reg is a DREG or PREG, we can split it here
4189          without scratch register.  */
4190       rtx insn;
4191
4192       emit_insn_before (gen_addsi3 (loop->iter_reg,
4193                                     loop->iter_reg,
4194                                     constm1_rtx),
4195                         loop->loop_end);
4196
4197       emit_insn_before (gen_cmpsi (loop->iter_reg, const0_rtx),
4198                         loop->loop_end);
4199
4200       insn = emit_jump_insn_before (gen_bne (loop->start_label),
4201                                     loop->loop_end);
4202
4203       JUMP_LABEL (insn) = loop->start_label;
4204       LABEL_NUSES (loop->start_label)++;
4205       delete_insn (loop->loop_end);
4206     }
4207 }
4208
4209 /* Called from bfin_reorg_loops when a potential loop end is found.  LOOP is
4210    a newly set up structure describing the loop, it is this function's
4211    responsibility to fill most of it.  TAIL_BB and TAIL_INSN point to the
4212    loop_end insn and its enclosing basic block.  */
4213
4214 static void
4215 bfin_discover_loop (loop_info loop, basic_block tail_bb, rtx tail_insn)
4216 {
4217   unsigned dwork = 0;
4218   basic_block bb;
4219   VEC (basic_block,heap) *works = VEC_alloc (basic_block,heap,20);
4220
4221   loop->tail = tail_bb;
4222   loop->head = BRANCH_EDGE (tail_bb)->dest;
4223   loop->successor = FALLTHRU_EDGE (tail_bb)->dest;
4224   loop->loop_end = tail_insn;
4225   loop->last_insn = NULL_RTX;
4226   loop->iter_reg = SET_DEST (XVECEXP (PATTERN (tail_insn), 0, 1));
4227   loop->depth = loop->length = 0;
4228   loop->visited = 0;
4229   loop->clobber_loop0 = loop->clobber_loop1 = 0;
4230   loop->outer = NULL;
4231   loop->loops = NULL;
4232   loop->incoming = VEC_alloc (edge, gc, 2);
4233   loop->init = loop->loop_init = NULL_RTX;
4234   loop->start_label = XEXP (XEXP (SET_SRC (XVECEXP (PATTERN (tail_insn), 0, 0)), 1), 0);
4235   loop->end_label = NULL_RTX;
4236   loop->bad = 0;
4237
4238   VEC_safe_push (basic_block, heap, works, loop->head);
4239
4240   while (VEC_iterate (basic_block, works, dwork++, bb))
4241     {
4242       edge e;
4243       edge_iterator ei;
4244       if (bb == EXIT_BLOCK_PTR)
4245         {
4246           /* We've reached the exit block.  The loop must be bad. */
4247           if (dump_file)
4248             fprintf (dump_file,
4249                      ";; Loop is bad - reached exit block while scanning\n");
4250           loop->bad = 1;
4251           break;
4252         }
4253
4254       if (bitmap_bit_p (loop->block_bitmap, bb->index))
4255         continue;
4256
4257       /* We've not seen this block before.  Add it to the loop's
4258          list and then add each successor to the work list.  */
4259
4260       VEC_safe_push (basic_block, heap, loop->blocks, bb);
4261       bitmap_set_bit (loop->block_bitmap, bb->index);
4262
4263       if (bb != tail_bb)
4264         {
4265           FOR_EACH_EDGE (e, ei, bb->succs)
4266             {
4267               basic_block succ = EDGE_SUCC (bb, ei.index)->dest;
4268               if (!REGNO_REG_SET_P (df_get_live_in (succ),
4269                                     REGNO (loop->iter_reg)))
4270                 continue;
4271               if (!VEC_space (basic_block, works, 1))
4272                 {
4273                   if (dwork)
4274                     {
4275                       VEC_block_remove (basic_block, works, 0, dwork);
4276                       dwork = 0;
4277                     }
4278                   else
4279                     VEC_reserve (basic_block, heap, works, 1);
4280                 }
4281               VEC_quick_push (basic_block, works, succ);
4282             }
4283         }
4284     }
4285
4286   /* Find the predecessor, and make sure nothing else jumps into this loop.  */
4287   if (!loop->bad)
4288     {
4289       int pass, retry;
4290       for (dwork = 0; VEC_iterate (basic_block, loop->blocks, dwork, bb); dwork++)
4291         {
4292           edge e;
4293           edge_iterator ei;
4294           FOR_EACH_EDGE (e, ei, bb->preds)
4295             {
4296               basic_block pred = e->src;
4297
4298               if (!bfin_bb_in_loop (loop, pred))
4299                 {
4300                   if (dump_file)
4301                     fprintf (dump_file, ";; Loop %d: incoming edge %d -> %d\n",
4302                              loop->loop_no, pred->index,
4303                              e->dest->index);
4304                   VEC_safe_push (edge, gc, loop->incoming, e);
4305                 }
4306             }
4307         }
4308
4309       for (pass = 0, retry = 1; retry && pass < 2; pass++)
4310         {
4311           edge e;
4312           edge_iterator ei;
4313           bool first = true;
4314           retry = 0;
4315
4316           FOR_EACH_EDGE (e, ei, loop->incoming)
4317             {
4318               if (first)
4319                 {
4320                   loop->incoming_src = e->src;
4321                   loop->incoming_dest = e->dest;
4322                   first = false;
4323                 }
4324               else
4325                 {
4326                   if (e->dest != loop->incoming_dest)
4327                     loop->incoming_dest = NULL;
4328                   if (e->src != loop->incoming_src)
4329                     loop->incoming_src = NULL;
4330                 }
4331               if (loop->incoming_src == NULL && loop->incoming_dest == NULL)
4332                 {
4333                   if (pass == 0)
4334                     {
4335                       if (dump_file)
4336                         fprintf (dump_file,
4337                                  ";; retrying loop %d with forwarder blocks\n",
4338                                  loop->loop_no);
4339                       retry = 1;
4340                       break;
4341                     }
4342                   loop->bad = 1;
4343                   if (dump_file)
4344                     fprintf (dump_file,
4345                              ";; can't find suitable entry for loop %d\n",
4346                              loop->loop_no);
4347                   goto out;
4348                 }
4349             }
4350           if (retry)
4351             {
4352               retry = 0;
4353               FOR_EACH_EDGE (e, ei, loop->incoming)
4354                 {
4355                   if (forwarder_block_p (e->src))
4356                     {
4357                       edge e2;
4358                       edge_iterator ei2;
4359
4360                       if (dump_file)
4361                         fprintf (dump_file,
4362                                  ";; Adding forwarder block %d to loop %d and retrying\n",
4363                                  e->src->index, loop->loop_no);
4364                       VEC_safe_push (basic_block, heap, loop->blocks, e->src);
4365                       bitmap_set_bit (loop->block_bitmap, e->src->index);
4366                       FOR_EACH_EDGE (e2, ei2, e->src->preds)
4367                         VEC_safe_push (edge, gc, loop->incoming, e2);
4368                       VEC_unordered_remove (edge, loop->incoming, ei.index);
4369                       retry = 1;
4370                       break;
4371                     }
4372                 }
4373               if (!retry)
4374                 {
4375                   if (dump_file)
4376                     fprintf (dump_file, ";; No forwarder blocks found\n");
4377                   loop->bad = 1;
4378                 }
4379             }
4380         }
4381     }
4382
4383  out:
4384   VEC_free (basic_block, heap, works);
4385 }
4386
4387 /* Analyze the structure of the loops in the current function.  Use STACK
4388    for bitmap allocations.  Returns all the valid candidates for hardware
4389    loops found in this function.  */
4390 static loop_info
4391 bfin_discover_loops (bitmap_obstack *stack, FILE *dump_file)
4392 {
4393   loop_info loops = NULL;
4394   loop_info loop;
4395   basic_block bb;
4396   bitmap tmp_bitmap;
4397   int nloops = 0;
4398
4399   /* Find all the possible loop tails.  This means searching for every
4400      loop_end instruction.  For each one found, create a loop_info
4401      structure and add the head block to the work list. */
4402   FOR_EACH_BB (bb)
4403     {
4404       rtx tail = BB_END (bb);
4405
4406       while (GET_CODE (tail) == NOTE)
4407         tail = PREV_INSN (tail);
4408
4409       bb->aux = NULL;
4410
4411       if (INSN_P (tail) && recog_memoized (tail) == CODE_FOR_loop_end)
4412         {
4413           rtx insn;
4414           /* A possible loop end */
4415
4416           /* There's a degenerate case we can handle - an empty loop consisting
4417              of only a back branch.  Handle that by deleting the branch.  */
4418           insn = BB_HEAD (BRANCH_EDGE (bb)->dest);
4419           if (next_real_insn (insn) == tail)
4420             {
4421               if (dump_file)
4422                 {
4423                   fprintf (dump_file, ";; degenerate loop ending at\n");
4424                   print_rtl_single (dump_file, tail);
4425                 }
4426               delete_insn_and_edges (tail);
4427               continue;
4428             }
4429
4430           loop = XNEW (struct loop_info);
4431           loop->next = loops;
4432           loops = loop;
4433           loop->loop_no = nloops++;
4434           loop->blocks = VEC_alloc (basic_block, heap, 20);
4435           loop->block_bitmap = BITMAP_ALLOC (stack);
4436           bb->aux = loop;
4437
4438           if (dump_file)
4439             {
4440               fprintf (dump_file, ";; potential loop %d ending at\n",
4441                        loop->loop_no);
4442               print_rtl_single (dump_file, tail);
4443             }
4444
4445           bfin_discover_loop (loop, bb, tail);
4446         }
4447     }
4448
4449   tmp_bitmap = BITMAP_ALLOC (stack);
4450   /* Compute loop nestings.  */
4451   for (loop = loops; loop; loop = loop->next)
4452     {
4453       loop_info other;
4454       if (loop->bad)
4455         continue;
4456
4457       for (other = loop->next; other; other = other->next)
4458         {
4459           if (other->bad)
4460             continue;
4461
4462           bitmap_and (tmp_bitmap, other->block_bitmap, loop->block_bitmap);
4463           if (bitmap_empty_p (tmp_bitmap))
4464             continue;
4465           if (bitmap_equal_p (tmp_bitmap, other->block_bitmap))
4466             {
4467               other->outer = loop;
4468               VEC_safe_push (loop_info, heap, loop->loops, other);
4469             }
4470           else if (bitmap_equal_p (tmp_bitmap, loop->block_bitmap))
4471             {
4472               loop->outer = other;
4473               VEC_safe_push (loop_info, heap, other->loops, loop);
4474             }
4475           else
4476             {
4477               if (dump_file)
4478                 fprintf (dump_file,
4479                          ";; can't find suitable nesting for loops %d and %d\n",
4480                          loop->loop_no, other->loop_no);
4481               loop->bad = other->bad = 1;
4482             }
4483         }
4484     }
4485   BITMAP_FREE (tmp_bitmap);
4486
4487   return loops;
4488 }
4489
4490 /* Free up the loop structures in LOOPS.  */
4491 static void
4492 free_loops (loop_info loops)
4493 {
4494   while (loops)
4495     {
4496       loop_info loop = loops;
4497       loops = loop->next;
4498       VEC_free (loop_info, heap, loop->loops);
4499       VEC_free (basic_block, heap, loop->blocks);
4500       BITMAP_FREE (loop->block_bitmap);
4501       XDELETE (loop);
4502     }
4503 }
4504
4505 #define BB_AUX_INDEX(BB) ((unsigned)(BB)->aux)
4506
4507 /* The taken-branch edge from the loop end can actually go forward.  Since the
4508    Blackfin's LSETUP instruction requires that the loop end be after the loop
4509    start, try to reorder a loop's basic blocks when we find such a case.  */
4510 static void
4511 bfin_reorder_loops (loop_info loops, FILE *dump_file)
4512 {
4513   basic_block bb;
4514   loop_info loop;
4515
4516   FOR_EACH_BB (bb)
4517     bb->aux = NULL;
4518   cfg_layout_initialize (0);
4519
4520   for (loop = loops; loop; loop = loop->next)
4521     {
4522       unsigned index;
4523       basic_block bb;
4524       edge e;
4525       edge_iterator ei;
4526
4527       if (loop->bad)
4528         continue;
4529
4530       /* Recreate an index for basic blocks that represents their order.  */
4531       for (bb = ENTRY_BLOCK_PTR->next_bb, index = 0;
4532            bb != EXIT_BLOCK_PTR;
4533            bb = bb->next_bb, index++)
4534         bb->aux = (PTR) index;
4535
4536       if (BB_AUX_INDEX (loop->head) < BB_AUX_INDEX (loop->tail))
4537         continue;
4538
4539       FOR_EACH_EDGE (e, ei, loop->head->succs)
4540         {
4541           if (bitmap_bit_p (loop->block_bitmap, e->dest->index)
4542               && BB_AUX_INDEX (e->dest) < BB_AUX_INDEX (loop->tail))
4543             {
4544               basic_block start_bb = e->dest;
4545               basic_block start_prev_bb = start_bb->prev_bb;
4546
4547               if (dump_file)
4548                 fprintf (dump_file, ";; Moving block %d before block %d\n",
4549                          loop->head->index, start_bb->index);
4550               loop->head->prev_bb->next_bb = loop->head->next_bb;
4551               loop->head->next_bb->prev_bb = loop->head->prev_bb;
4552
4553               loop->head->prev_bb = start_prev_bb;
4554               loop->head->next_bb = start_bb;
4555               start_prev_bb->next_bb = start_bb->prev_bb = loop->head;
4556               break;
4557             }
4558         }
4559       loops = loops->next;
4560     }
4561   
4562   FOR_EACH_BB (bb)
4563     {
4564       if (bb->next_bb != EXIT_BLOCK_PTR)
4565         bb->aux = bb->next_bb;
4566       else
4567         bb->aux = NULL;
4568     }
4569   cfg_layout_finalize ();
4570   df_analyze ();
4571 }
4572
4573 /* Run from machine_dependent_reorg, this pass looks for doloop_end insns
4574    and tries to rewrite the RTL of these loops so that proper Blackfin
4575    hardware loops are generated.  */
4576
4577 static void
4578 bfin_reorg_loops (FILE *dump_file)
4579 {
4580   loop_info loops = NULL;
4581   loop_info loop;
4582   basic_block bb;
4583   bitmap_obstack stack;
4584
4585   bitmap_obstack_initialize (&stack);
4586
4587   if (dump_file)
4588     fprintf (dump_file, ";; Find loops, first pass\n\n");
4589
4590   loops = bfin_discover_loops (&stack, dump_file);
4591
4592   if (dump_file)
4593     bfin_dump_loops (loops);
4594
4595   bfin_reorder_loops (loops, dump_file);
4596   free_loops (loops);
4597
4598   if (dump_file)
4599     fprintf (dump_file, ";; Find loops, second pass\n\n");
4600
4601   loops = bfin_discover_loops (&stack, dump_file);
4602   if (dump_file)
4603     {
4604       fprintf (dump_file, ";; All loops found:\n\n");
4605       bfin_dump_loops (loops);
4606     }
4607   
4608   /* Now apply the optimizations.  */
4609   for (loop = loops; loop; loop = loop->next)
4610     bfin_optimize_loop (loop);
4611
4612   if (dump_file)
4613     {
4614       fprintf (dump_file, ";; After hardware loops optimization:\n\n");
4615       bfin_dump_loops (loops);
4616     }
4617
4618   free_loops (loops);
4619
4620   if (dump_file)
4621     print_rtl (dump_file, get_insns ());
4622
4623   FOR_EACH_BB (bb)
4624     bb->aux = NULL;
4625 }
4626 \f
4627 /* Possibly generate a SEQUENCE out of three insns found in SLOT.
4628    Returns true if we modified the insn chain, false otherwise.  */
4629 static bool
4630 gen_one_bundle (rtx slot[3])
4631 {
4632   gcc_assert (slot[1] != NULL_RTX);
4633
4634   /* Don't add extra NOPs if optimizing for size.  */
4635   if (optimize_size
4636       && (slot[0] == NULL_RTX || slot[2] == NULL_RTX))
4637     return false;
4638
4639   /* Verify that we really can do the multi-issue.  */
4640   if (slot[0])
4641     {
4642       rtx t = NEXT_INSN (slot[0]);
4643       while (t != slot[1])
4644         {
4645           if (GET_CODE (t) != NOTE
4646               || NOTE_KIND (t) != NOTE_INSN_DELETED)
4647             return false;
4648           t = NEXT_INSN (t);
4649         }
4650     }
4651   if (slot[2])
4652     {
4653       rtx t = NEXT_INSN (slot[1]);
4654       while (t != slot[2])
4655         {
4656           if (GET_CODE (t) != NOTE
4657               || NOTE_KIND (t) != NOTE_INSN_DELETED)
4658             return false;
4659           t = NEXT_INSN (t);
4660         }
4661     }
4662
4663   if (slot[0] == NULL_RTX)
4664     {
4665       slot[0] = emit_insn_before (gen_mnop (), slot[1]);
4666       df_insn_rescan (slot[0]);
4667     }
4668   if (slot[2] == NULL_RTX)
4669     {
4670       slot[2] = emit_insn_after (gen_forced_nop (), slot[1]);
4671       df_insn_rescan (slot[2]);
4672     }
4673
4674   /* Avoid line number information being printed inside one bundle.  */
4675   if (INSN_LOCATOR (slot[1])
4676       && INSN_LOCATOR (slot[1]) != INSN_LOCATOR (slot[0]))
4677     INSN_LOCATOR (slot[1]) = INSN_LOCATOR (slot[0]);
4678   if (INSN_LOCATOR (slot[2])
4679       && INSN_LOCATOR (slot[2]) != INSN_LOCATOR (slot[0]))
4680     INSN_LOCATOR (slot[2]) = INSN_LOCATOR (slot[0]);
4681
4682   /* Terminate them with "|| " instead of ";" in the output.  */
4683   PUT_MODE (slot[0], SImode);
4684   PUT_MODE (slot[1], SImode);
4685   /* Terminate the bundle, for the benefit of reorder_var_tracking_notes.  */
4686   PUT_MODE (slot[2], QImode);
4687   return true;
4688 }
4689
4690 /* Go through all insns, and use the information generated during scheduling
4691    to generate SEQUENCEs to represent bundles of instructions issued
4692    simultaneously.  */
4693
4694 static void
4695 bfin_gen_bundles (void)
4696 {
4697   basic_block bb;
4698   FOR_EACH_BB (bb)
4699     {
4700       rtx insn, next;
4701       rtx slot[3];
4702       int n_filled = 0;
4703
4704       slot[0] = slot[1] = slot[2] = NULL_RTX;
4705       for (insn = BB_HEAD (bb);; insn = next)
4706         {
4707           int at_end;
4708           if (INSN_P (insn))
4709             {
4710               if (get_attr_type (insn) == TYPE_DSP32)
4711                 slot[0] = insn;
4712               else if (slot[1] == NULL_RTX)
4713                 slot[1] = insn;
4714               else
4715                 slot[2] = insn;
4716               n_filled++;
4717             }
4718
4719           next = NEXT_INSN (insn);
4720           while (next && insn != BB_END (bb)
4721                  && !(INSN_P (next)
4722                       && GET_CODE (PATTERN (next)) != USE
4723                       && GET_CODE (PATTERN (next)) != CLOBBER))
4724             {
4725               insn = next;
4726               next = NEXT_INSN (insn);
4727             }
4728
4729           /* BB_END can change due to emitting extra NOPs, so check here.  */
4730           at_end = insn == BB_END (bb);
4731           if (at_end || GET_MODE (next) == TImode)
4732             {
4733               if ((n_filled < 2
4734                    || !gen_one_bundle (slot))
4735                   && slot[0] != NULL_RTX)
4736                 {
4737                   rtx pat = PATTERN (slot[0]);
4738                   if (GET_CODE (pat) == SET
4739                       && GET_CODE (SET_SRC (pat)) == UNSPEC
4740                       && XINT (SET_SRC (pat), 1) == UNSPEC_32BIT)
4741                     {
4742                       SET_SRC (pat) = XVECEXP (SET_SRC (pat), 0, 0);
4743                       INSN_CODE (slot[0]) = -1;
4744                       df_insn_rescan (slot[0]);
4745                     }
4746                 }
4747               n_filled = 0;
4748               slot[0] = slot[1] = slot[2] = NULL_RTX;
4749             }
4750           if (at_end)
4751             break;
4752         }
4753     }
4754 }
4755
4756 /* Ensure that no var tracking notes are emitted in the middle of a
4757    three-instruction bundle.  */
4758
4759 static void
4760 reorder_var_tracking_notes (void)
4761 {
4762   basic_block bb;
4763   FOR_EACH_BB (bb)
4764     {
4765       rtx insn, next;
4766       rtx queue = NULL_RTX;
4767       bool in_bundle = false;
4768
4769       for (insn = BB_HEAD (bb); insn != BB_END (bb); insn = next)
4770         {
4771           next = NEXT_INSN (insn);
4772
4773           if (INSN_P (insn))
4774             {
4775               /* Emit queued up notes at the last instruction of a bundle.  */
4776               if (GET_MODE (insn) == QImode)
4777                 {
4778                   while (queue)
4779                     {
4780                       rtx next_queue = PREV_INSN (queue);
4781                       PREV_INSN (NEXT_INSN (insn)) = queue;
4782                       NEXT_INSN (queue) = NEXT_INSN (insn);
4783                       NEXT_INSN (insn) = queue;
4784                       PREV_INSN (queue) = insn;
4785                       queue = next_queue;
4786                     }
4787                   in_bundle = false;
4788                 }
4789               else if (GET_MODE (insn) == SImode)
4790                 in_bundle = true;
4791             }
4792           else if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION)
4793             {
4794               if (in_bundle)
4795                 {
4796                   rtx prev = PREV_INSN (insn);
4797                   PREV_INSN (next) = prev;
4798                   NEXT_INSN (prev) = next;
4799
4800                   PREV_INSN (insn) = queue;
4801                   queue = insn;
4802                 }
4803             }
4804         }
4805     }
4806 }
4807 \f
4808 /* On some silicon revisions, functions shorter than a certain number of cycles
4809    can cause unpredictable behaviour.  Work around this by adding NOPs as
4810    needed.  */
4811 static void
4812 workaround_rts_anomaly (void)
4813 {
4814   rtx insn, first_insn = NULL_RTX;
4815   int cycles = 4;
4816
4817   if (! ENABLE_WA_RETS)
4818     return;
4819
4820   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
4821     {
4822       rtx pat;
4823
4824       if (BARRIER_P (insn))
4825         return;
4826       
4827       if (NOTE_P (insn) || LABEL_P (insn))
4828         continue;
4829
4830       if (first_insn == NULL_RTX)
4831         first_insn = insn;
4832       pat = PATTERN (insn);
4833       if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER
4834           || GET_CODE (pat) == ASM_INPUT || GET_CODE (pat) == ADDR_VEC
4835           || GET_CODE (pat) == ADDR_DIFF_VEC || asm_noperands (pat) >= 0)
4836         continue;
4837
4838       if (CALL_P (insn))
4839         return;
4840
4841       if (JUMP_P (insn))
4842         {
4843           if (recog_memoized (insn) == CODE_FOR_return_internal)
4844             break;
4845
4846           /* Nothing to worry about for direct jumps.  */
4847           if (!any_condjump_p (insn))
4848             return;
4849           if (cycles <= 1)
4850             return;
4851           cycles--;
4852         }
4853       else if (INSN_P (insn))
4854         {
4855           rtx pat = PATTERN (insn);
4856           int this_cycles = 1;
4857
4858           if (GET_CODE (pat) == PARALLEL)
4859             {
4860               if (push_multiple_operation (pat, VOIDmode)
4861                   || pop_multiple_operation (pat, VOIDmode))
4862                 this_cycles = n_regs_to_save;
4863             }
4864           else
4865             {
4866               enum insn_code icode = recog_memoized (insn);
4867               if (icode == CODE_FOR_link)
4868                 this_cycles = 4;
4869               else if (icode == CODE_FOR_unlink)
4870                 this_cycles = 3;
4871               else if (icode == CODE_FOR_mulsi3)
4872                 this_cycles = 5;
4873             }
4874           if (this_cycles >= cycles)
4875             return;
4876
4877           cycles -= this_cycles;
4878         }
4879     }
4880   while (cycles > 0)
4881     {
4882       emit_insn_before (gen_nop (), first_insn);
4883       cycles--;
4884     }
4885 }
4886
4887 /* Return an insn type for INSN that can be used by the caller for anomaly
4888    workarounds.  This differs from plain get_attr_type in that it handles
4889    SEQUENCEs.  */
4890
4891 static enum attr_type
4892 type_for_anomaly (rtx insn)
4893 {
4894   rtx pat = PATTERN (insn);
4895   if (GET_CODE (pat) == SEQUENCE)
4896     {
4897       enum attr_type t;
4898       t = get_attr_type (XVECEXP (pat, 0, 1));
4899       if (t == TYPE_MCLD)
4900         return t;
4901       t = get_attr_type (XVECEXP (pat, 0, 2));
4902       if (t == TYPE_MCLD)
4903         return t;
4904       return TYPE_MCST;
4905     }
4906   else
4907     return get_attr_type (insn);
4908 }
4909
4910 /* Return nonzero if INSN contains any loads that may trap.  It handles
4911    SEQUENCEs correctly.  */
4912
4913 static bool
4914 trapping_loads_p (rtx insn)
4915 {
4916   rtx pat = PATTERN (insn);
4917   if (GET_CODE (pat) == SEQUENCE)
4918     {
4919       enum attr_type t;
4920       t = get_attr_type (XVECEXP (pat, 0, 1));
4921       if (t == TYPE_MCLD
4922           && may_trap_p (SET_SRC (PATTERN (XVECEXP (pat, 0, 1)))))
4923         return true;
4924       t = get_attr_type (XVECEXP (pat, 0, 2));
4925       if (t == TYPE_MCLD
4926           && may_trap_p (SET_SRC (PATTERN (XVECEXP (pat, 0, 2)))))
4927         return true;
4928       return false;
4929     }
4930   else
4931     return may_trap_p (SET_SRC (single_set (insn)));
4932 }
4933
4934 /* Return INSN if it is of TYPE_MCLD.  Alternatively, if INSN is the start of
4935    a three-insn bundle, see if one of them is a load and return that if so.
4936    Return NULL_RTX if the insn does not contain loads.  */
4937 static rtx
4938 find_load (rtx insn)
4939 {
4940   if (get_attr_type (insn) == TYPE_MCLD)
4941     return insn;
4942   if (GET_MODE (insn) != SImode)
4943     return NULL_RTX;
4944   do {
4945     insn = NEXT_INSN (insn);
4946     if ((GET_MODE (insn) == SImode || GET_MODE (insn) == QImode)
4947         && get_attr_type (insn) == TYPE_MCLD)
4948       return insn;
4949   } while (GET_MODE (insn) != QImode);
4950   return NULL_RTX;
4951 }
4952
4953 /* Determine whether PAT is an indirect call pattern.  */
4954 static bool
4955 indirect_call_p (rtx pat)
4956 {
4957   if (GET_CODE (pat) == PARALLEL)
4958     pat = XVECEXP (pat, 0, 0);
4959   if (GET_CODE (pat) == SET)
4960     pat = SET_SRC (pat);
4961   gcc_assert (GET_CODE (pat) == CALL);
4962   pat = XEXP (pat, 0);
4963   gcc_assert (GET_CODE (pat) == MEM);
4964   pat = XEXP (pat, 0);
4965   
4966   return REG_P (pat);
4967 }
4968
4969 static void
4970 workaround_speculation (void)
4971 {
4972   rtx insn, next;
4973   rtx last_condjump = NULL_RTX;
4974   int cycles_since_jump = INT_MAX;
4975   int delay_added = 0;
4976
4977   if (! ENABLE_WA_SPECULATIVE_LOADS && ! ENABLE_WA_SPECULATIVE_SYNCS
4978       && ! ENABLE_WA_INDIRECT_CALLS)
4979     return;
4980
4981   /* First pass: find predicted-false branches; if something after them
4982      needs nops, insert them or change the branch to predict true.  */
4983   for (insn = get_insns (); insn; insn = next)
4984     {
4985       rtx pat;
4986       int delay_needed = 0;
4987
4988       next = find_next_insn_start (insn);
4989       
4990       if (NOTE_P (insn) || BARRIER_P (insn) || LABEL_P (insn))
4991         continue;
4992
4993       pat = PATTERN (insn);
4994       if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER
4995           || GET_CODE (pat) == ASM_INPUT || GET_CODE (pat) == ADDR_VEC
4996           || GET_CODE (pat) == ADDR_DIFF_VEC || asm_noperands (pat) >= 0)
4997         continue;
4998
4999       if (JUMP_P (insn))
5000         {
5001           if (any_condjump_p (insn)
5002               && ! cbranch_predicted_taken_p (insn))
5003             {
5004               last_condjump = insn;
5005               delay_added = 0;
5006               cycles_since_jump = 0;
5007             }
5008           else
5009             cycles_since_jump = INT_MAX;
5010         }
5011       else if (CALL_P (insn))
5012         {
5013           if (cycles_since_jump < INT_MAX)
5014             cycles_since_jump++;
5015           if (indirect_call_p (pat) && ENABLE_WA_INDIRECT_CALLS)
5016             {
5017               delay_needed = 3;
5018             }
5019         }
5020       else if (INSN_P (insn))
5021         {
5022           rtx load_insn = find_load (insn);
5023           enum attr_type type = type_for_anomaly (insn);
5024
5025           if (cycles_since_jump < INT_MAX)
5026             cycles_since_jump++;
5027
5028           if (load_insn && ENABLE_WA_SPECULATIVE_LOADS)
5029             {
5030               if (trapping_loads_p (load_insn))
5031                 delay_needed = 4;
5032             }
5033           else if (type == TYPE_SYNC && ENABLE_WA_SPECULATIVE_SYNCS)
5034             delay_needed = 3;
5035         }
5036
5037       if (delay_needed > cycles_since_jump
5038           && (delay_needed - cycles_since_jump) > delay_added)
5039         {
5040           rtx pat1;
5041           int num_clobbers;
5042           rtx *op = recog_data.operand;
5043
5044           delay_needed -= cycles_since_jump;
5045
5046           extract_insn (last_condjump);
5047           if (optimize_size)
5048             {
5049               pat1 = gen_cbranch_predicted_taken (op[0], op[1], op[2],
5050                                                  op[3]);
5051               cycles_since_jump = INT_MAX;
5052             }
5053           else
5054             {
5055               /* Do not adjust cycles_since_jump in this case, so that
5056                  we'll increase the number of NOPs for a subsequent insn
5057                  if necessary.  */
5058               pat1 = gen_cbranch_with_nops (op[0], op[1], op[2], op[3],
5059                                             GEN_INT (delay_needed));
5060               delay_added = delay_needed;
5061             }
5062           PATTERN (last_condjump) = pat1;
5063           INSN_CODE (last_condjump) = recog (pat1, insn, &num_clobbers);
5064         }
5065       if (CALL_P (insn))
5066         {
5067           cycles_since_jump = INT_MAX;
5068           delay_added = 0;
5069         }
5070     }
5071
5072   /* Second pass: for predicted-true branches, see if anything at the
5073      branch destination needs extra nops.  */
5074   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
5075     {
5076       int cycles_since_jump;
5077       if (JUMP_P (insn)
5078           && any_condjump_p (insn)
5079           && (INSN_CODE (insn) == CODE_FOR_cbranch_predicted_taken
5080               || cbranch_predicted_taken_p (insn)))
5081         {
5082           rtx target = JUMP_LABEL (insn);
5083           rtx label = target;
5084           rtx next_tgt;
5085
5086           cycles_since_jump = 0;
5087           for (; target && cycles_since_jump < 3; target = next_tgt)
5088             {
5089               rtx pat;
5090
5091               next_tgt = find_next_insn_start (target);
5092
5093               if (NOTE_P (target) || BARRIER_P (target) || LABEL_P (target))
5094                 continue;
5095
5096               pat = PATTERN (target);
5097               if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER
5098                   || GET_CODE (pat) == ASM_INPUT || GET_CODE (pat) == ADDR_VEC
5099                   || GET_CODE (pat) == ADDR_DIFF_VEC || asm_noperands (pat) >= 0)
5100                 continue;
5101
5102               if (INSN_P (target))
5103                 {
5104                   rtx load_insn = find_load (target);
5105                   enum attr_type type = type_for_anomaly (target);
5106                   int delay_needed = 0;
5107                   if (cycles_since_jump < INT_MAX)
5108                     cycles_since_jump++;
5109
5110                   if (load_insn && ENABLE_WA_SPECULATIVE_LOADS)
5111                     {
5112                       if (trapping_loads_p (load_insn))
5113                         delay_needed = 2;
5114                     }
5115                   else if (type == TYPE_SYNC && ENABLE_WA_SPECULATIVE_SYNCS)
5116                     delay_needed = 2;
5117
5118                   if (delay_needed > cycles_since_jump)
5119                     {
5120                       rtx prev = prev_real_insn (label);
5121                       delay_needed -= cycles_since_jump;
5122                       if (dump_file)
5123                         fprintf (dump_file, "Adding %d nops after %d\n",
5124                                  delay_needed, INSN_UID (label));
5125                       if (JUMP_P (prev)
5126                           && INSN_CODE (prev) == CODE_FOR_cbranch_with_nops)
5127                         {
5128                           rtx x;
5129                           HOST_WIDE_INT v;
5130
5131                           if (dump_file)
5132                             fprintf (dump_file,
5133                                      "Reducing nops on insn %d.\n",
5134                                      INSN_UID (prev));
5135                           x = PATTERN (prev);
5136                           x = XVECEXP (x, 0, 1);
5137                           v = INTVAL (XVECEXP (x, 0, 0)) - delay_needed;
5138                           XVECEXP (x, 0, 0) = GEN_INT (v);
5139                         }
5140                       while (delay_needed-- > 0)
5141                         emit_insn_after (gen_nop (), label);
5142                       break;
5143                     }
5144                 }
5145             }
5146         }
5147     }
5148 }
5149
5150 /* We use the machine specific reorg pass for emitting CSYNC instructions
5151    after conditional branches as needed.
5152
5153    The Blackfin is unusual in that a code sequence like
5154      if cc jump label
5155      r0 = (p0)
5156    may speculatively perform the load even if the condition isn't true.  This
5157    happens for a branch that is predicted not taken, because the pipeline
5158    isn't flushed or stalled, so the early stages of the following instructions,
5159    which perform the memory reference, are allowed to execute before the
5160    jump condition is evaluated.
5161    Therefore, we must insert additional instructions in all places where this
5162    could lead to incorrect behavior.  The manual recommends CSYNC, while
5163    VDSP seems to use NOPs (even though its corresponding compiler option is
5164    named CSYNC).
5165
5166    When optimizing for speed, we emit NOPs, which seems faster than a CSYNC.
5167    When optimizing for size, we turn the branch into a predicted taken one.
5168    This may be slower due to mispredicts, but saves code size.  */
5169
5170 static void
5171 bfin_reorg (void)
5172 {
5173   /* We are freeing block_for_insn in the toplev to keep compatibility
5174      with old MDEP_REORGS that are not CFG based.  Recompute it now.  */
5175   compute_bb_for_insn ();
5176
5177   if (bfin_flag_schedule_insns2)
5178     {
5179       splitting_for_sched = 1;
5180       split_all_insns ();
5181       splitting_for_sched = 0;
5182
5183       timevar_push (TV_SCHED2);
5184       schedule_insns ();
5185       timevar_pop (TV_SCHED2);
5186
5187       /* Examine the schedule and insert nops as necessary for 64-bit parallel
5188          instructions.  */
5189       bfin_gen_bundles ();
5190     }
5191
5192   df_analyze ();
5193
5194   /* Doloop optimization */
5195   if (cfun->machine->has_hardware_loops)
5196     bfin_reorg_loops (dump_file);
5197
5198   workaround_speculation ();
5199
5200   if (bfin_flag_var_tracking)
5201     {
5202       timevar_push (TV_VAR_TRACKING);
5203       variable_tracking_main ();
5204       reorder_var_tracking_notes ();
5205       timevar_pop (TV_VAR_TRACKING);
5206     }
5207
5208   df_finish_pass (false);
5209
5210   workaround_rts_anomaly ();
5211 }
5212 \f
5213 /* Handle interrupt_handler, exception_handler and nmi_handler function
5214    attributes; arguments as in struct attribute_spec.handler.  */
5215
5216 static tree
5217 handle_int_attribute (tree *node, tree name,
5218                       tree args ATTRIBUTE_UNUSED,
5219                       int flags ATTRIBUTE_UNUSED,
5220                       bool *no_add_attrs)
5221 {
5222   tree x = *node;
5223   if (TREE_CODE (x) == FUNCTION_DECL)
5224     x = TREE_TYPE (x);
5225
5226   if (TREE_CODE (x) != FUNCTION_TYPE)
5227     {
5228       warning (OPT_Wattributes, "%qs attribute only applies to functions",
5229                IDENTIFIER_POINTER (name));
5230       *no_add_attrs = true;
5231     }
5232   else if (funkind (x) != SUBROUTINE)
5233     error ("multiple function type attributes specified");
5234
5235   return NULL_TREE;
5236 }
5237
5238 /* Return 0 if the attributes for two types are incompatible, 1 if they
5239    are compatible, and 2 if they are nearly compatible (which causes a
5240    warning to be generated).  */
5241
5242 static int
5243 bfin_comp_type_attributes (const_tree type1, const_tree type2)
5244 {
5245   e_funkind kind1, kind2;
5246
5247   if (TREE_CODE (type1) != FUNCTION_TYPE)
5248     return 1;
5249
5250   kind1 = funkind (type1);
5251   kind2 = funkind (type2);
5252
5253   if (kind1 != kind2)
5254     return 0;
5255   
5256   /*  Check for mismatched modifiers */
5257   if (!lookup_attribute ("nesting", TYPE_ATTRIBUTES (type1))
5258       != !lookup_attribute ("nesting", TYPE_ATTRIBUTES (type2)))
5259     return 0;
5260
5261   if (!lookup_attribute ("saveall", TYPE_ATTRIBUTES (type1))
5262       != !lookup_attribute ("saveall", TYPE_ATTRIBUTES (type2)))
5263     return 0;
5264
5265   if (!lookup_attribute ("kspisusp", TYPE_ATTRIBUTES (type1))
5266       != !lookup_attribute ("kspisusp", TYPE_ATTRIBUTES (type2)))
5267     return 0;
5268
5269   if (!lookup_attribute ("longcall", TYPE_ATTRIBUTES (type1))
5270       != !lookup_attribute ("longcall", TYPE_ATTRIBUTES (type2)))
5271     return 0;
5272
5273   return 1;
5274 }
5275
5276 /* Handle a "longcall" or "shortcall" attribute; arguments as in
5277    struct attribute_spec.handler.  */
5278
5279 static tree
5280 bfin_handle_longcall_attribute (tree *node, tree name, 
5281                                 tree args ATTRIBUTE_UNUSED, 
5282                                 int flags ATTRIBUTE_UNUSED, 
5283                                 bool *no_add_attrs)
5284 {
5285   if (TREE_CODE (*node) != FUNCTION_TYPE
5286       && TREE_CODE (*node) != FIELD_DECL
5287       && TREE_CODE (*node) != TYPE_DECL)
5288     {
5289       warning (OPT_Wattributes, "`%s' attribute only applies to functions",
5290                IDENTIFIER_POINTER (name));
5291       *no_add_attrs = true;
5292     }
5293
5294   if ((strcmp (IDENTIFIER_POINTER (name), "longcall") == 0
5295        && lookup_attribute ("shortcall", TYPE_ATTRIBUTES (*node)))
5296       || (strcmp (IDENTIFIER_POINTER (name), "shortcall") == 0
5297           && lookup_attribute ("longcall", TYPE_ATTRIBUTES (*node))))
5298     {
5299       warning (OPT_Wattributes,
5300                "can't apply both longcall and shortcall attributes to the same function");
5301       *no_add_attrs = true;
5302     }
5303
5304   return NULL_TREE;
5305 }
5306
5307 /* Handle a "l1_text" attribute; arguments as in
5308    struct attribute_spec.handler.  */
5309
5310 static tree
5311 bfin_handle_l1_text_attribute (tree *node, tree name, tree ARG_UNUSED (args),
5312                                int ARG_UNUSED (flags), bool *no_add_attrs)
5313 {
5314   tree decl = *node;
5315
5316   if (TREE_CODE (decl) != FUNCTION_DECL)
5317     {
5318       error ("`%s' attribute only applies to functions",
5319              IDENTIFIER_POINTER (name));
5320       *no_add_attrs = true;
5321     }
5322
5323   /* The decl may have already been given a section attribute
5324      from a previous declaration. Ensure they match.  */
5325   else if (DECL_SECTION_NAME (decl) != NULL_TREE
5326            && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
5327                       ".l1.text") != 0)
5328     {
5329       error ("section of %q+D conflicts with previous declaration",
5330              decl);
5331       *no_add_attrs = true;
5332     }
5333   else
5334     DECL_SECTION_NAME (decl) = build_string (9, ".l1.text");
5335
5336   return NULL_TREE;
5337 }
5338
5339 /* Handle a "l1_data", "l1_data_A" or "l1_data_B" attribute;
5340    arguments as in struct attribute_spec.handler.  */
5341
5342 static tree
5343 bfin_handle_l1_data_attribute (tree *node, tree name, tree ARG_UNUSED (args),
5344                                int ARG_UNUSED (flags), bool *no_add_attrs)
5345 {
5346   tree decl = *node;
5347
5348   if (TREE_CODE (decl) != VAR_DECL)
5349     {
5350       error ("`%s' attribute only applies to variables",
5351              IDENTIFIER_POINTER (name));
5352       *no_add_attrs = true;
5353     }
5354   else if (current_function_decl != NULL_TREE
5355            && !TREE_STATIC (decl))
5356     {
5357       error ("`%s' attribute cannot be specified for local variables",
5358              IDENTIFIER_POINTER (name));
5359       *no_add_attrs = true;
5360     }
5361   else
5362     {
5363       const char *section_name;
5364
5365       if (strcmp (IDENTIFIER_POINTER (name), "l1_data") == 0)
5366         section_name = ".l1.data";
5367       else if (strcmp (IDENTIFIER_POINTER (name), "l1_data_A") == 0)
5368         section_name = ".l1.data.A";
5369       else if (strcmp (IDENTIFIER_POINTER (name), "l1_data_B") == 0)
5370         section_name = ".l1.data.B";
5371       else
5372         gcc_unreachable ();
5373
5374       /* The decl may have already been given a section attribute
5375          from a previous declaration. Ensure they match.  */
5376       if (DECL_SECTION_NAME (decl) != NULL_TREE
5377           && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
5378                      section_name) != 0)
5379         {
5380           error ("section of %q+D conflicts with previous declaration",
5381                  decl);
5382           *no_add_attrs = true;
5383         }
5384       else
5385         DECL_SECTION_NAME (decl)
5386           = build_string (strlen (section_name) + 1, section_name);
5387     }
5388
5389  return NULL_TREE;
5390 }
5391
5392 /* Table of valid machine attributes.  */
5393 const struct attribute_spec bfin_attribute_table[] =
5394 {
5395   /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
5396   { "interrupt_handler", 0, 0, false, true,  true, handle_int_attribute },
5397   { "exception_handler", 0, 0, false, true,  true, handle_int_attribute },
5398   { "nmi_handler", 0, 0, false, true,  true, handle_int_attribute },
5399   { "nesting", 0, 0, false, true,  true, NULL },
5400   { "kspisusp", 0, 0, false, true,  true, NULL },
5401   { "saveall", 0, 0, false, true,  true, NULL },
5402   { "longcall",  0, 0, false, true,  true,  bfin_handle_longcall_attribute },
5403   { "shortcall", 0, 0, false, true,  true,  bfin_handle_longcall_attribute },
5404   { "l1_text", 0, 0, true, false, false,  bfin_handle_l1_text_attribute },
5405   { "l1_data", 0, 0, true, false, false,  bfin_handle_l1_data_attribute },
5406   { "l1_data_A", 0, 0, true, false, false, bfin_handle_l1_data_attribute },
5407   { "l1_data_B", 0, 0, true, false, false,  bfin_handle_l1_data_attribute },
5408   { NULL, 0, 0, false, false, false, NULL }
5409 };
5410 \f
5411 /* Implementation of TARGET_ASM_INTEGER.  When using FD-PIC, we need to
5412    tell the assembler to generate pointers to function descriptors in
5413    some cases.  */
5414
5415 static bool
5416 bfin_assemble_integer (rtx value, unsigned int size, int aligned_p)
5417 {
5418   if (TARGET_FDPIC && size == UNITS_PER_WORD)
5419     {
5420       if (GET_CODE (value) == SYMBOL_REF
5421           && SYMBOL_REF_FUNCTION_P (value))
5422         {
5423           fputs ("\t.picptr\tfuncdesc(", asm_out_file);
5424           output_addr_const (asm_out_file, value);
5425           fputs (")\n", asm_out_file);
5426           return true;
5427         }
5428       if (!aligned_p)
5429         {
5430           /* We've set the unaligned SI op to NULL, so we always have to
5431              handle the unaligned case here.  */
5432           assemble_integer_with_op ("\t.4byte\t", value);
5433           return true;
5434         }
5435     }
5436   return default_assemble_integer (value, size, aligned_p);
5437 }
5438 \f
5439 /* Output the assembler code for a thunk function.  THUNK_DECL is the
5440    declaration for the thunk function itself, FUNCTION is the decl for
5441    the target function.  DELTA is an immediate constant offset to be
5442    added to THIS.  If VCALL_OFFSET is nonzero, the word at
5443    *(*this + vcall_offset) should be added to THIS.  */
5444
5445 static void
5446 bfin_output_mi_thunk (FILE *file ATTRIBUTE_UNUSED,
5447                       tree thunk ATTRIBUTE_UNUSED, HOST_WIDE_INT delta,
5448                       HOST_WIDE_INT vcall_offset, tree function)
5449 {
5450   rtx xops[3];
5451   /* The this parameter is passed as the first argument.  */
5452   rtx this_rtx = gen_rtx_REG (Pmode, REG_R0);
5453
5454   /* Adjust the this parameter by a fixed constant.  */
5455   if (delta)
5456     {
5457       xops[1] = this_rtx;
5458       if (delta >= -64 && delta <= 63)
5459         {
5460           xops[0] = GEN_INT (delta);
5461           output_asm_insn ("%1 += %0;", xops);
5462         }
5463       else if (delta >= -128 && delta < -64)
5464         {
5465           xops[0] = GEN_INT (delta + 64);
5466           output_asm_insn ("%1 += -64; %1 += %0;", xops);
5467         }
5468       else if (delta > 63 && delta <= 126)
5469         {
5470           xops[0] = GEN_INT (delta - 63);
5471           output_asm_insn ("%1 += 63; %1 += %0;", xops);
5472         }
5473       else
5474         {
5475           xops[0] = GEN_INT (delta);
5476           output_asm_insn ("r3.l = %h0; r3.h = %d0; %1 = %1 + r3;", xops);
5477         }
5478     }
5479
5480   /* Adjust the this parameter by a value stored in the vtable.  */
5481   if (vcall_offset)
5482     {
5483       rtx p2tmp = gen_rtx_REG (Pmode, REG_P2);
5484       rtx tmp = gen_rtx_REG (Pmode, REG_R3);
5485
5486       xops[1] = tmp;
5487       xops[2] = p2tmp;
5488       output_asm_insn ("%2 = r0; %2 = [%2];", xops);
5489
5490       /* Adjust the this parameter.  */
5491       xops[0] = gen_rtx_MEM (Pmode, plus_constant (p2tmp, vcall_offset));
5492       if (!memory_operand (xops[0], Pmode))
5493         {
5494           rtx tmp2 = gen_rtx_REG (Pmode, REG_P1);
5495           xops[0] = GEN_INT (vcall_offset);
5496           xops[1] = tmp2;
5497           output_asm_insn ("%h1 = %h0; %d1 = %d0; %2 = %2 + %1", xops);
5498           xops[0] = gen_rtx_MEM (Pmode, p2tmp);
5499         }
5500       xops[2] = this_rtx;
5501       output_asm_insn ("%1 = %0; %2 = %2 + %1;", xops);
5502     }
5503
5504   xops[0] = XEXP (DECL_RTL (function), 0);
5505   if (1 || !flag_pic || (*targetm.binds_local_p) (function))
5506     output_asm_insn ("jump.l\t%P0", xops);
5507 }
5508 \f
5509 /* Codes for all the Blackfin builtins.  */
5510 enum bfin_builtins
5511 {
5512   BFIN_BUILTIN_CSYNC,
5513   BFIN_BUILTIN_SSYNC,
5514   BFIN_BUILTIN_ONES,
5515   BFIN_BUILTIN_COMPOSE_2X16,
5516   BFIN_BUILTIN_EXTRACTLO,
5517   BFIN_BUILTIN_EXTRACTHI,
5518
5519   BFIN_BUILTIN_SSADD_2X16,
5520   BFIN_BUILTIN_SSSUB_2X16,
5521   BFIN_BUILTIN_SSADDSUB_2X16,
5522   BFIN_BUILTIN_SSSUBADD_2X16,
5523   BFIN_BUILTIN_MULT_2X16,
5524   BFIN_BUILTIN_MULTR_2X16,
5525   BFIN_BUILTIN_NEG_2X16,
5526   BFIN_BUILTIN_ABS_2X16,
5527   BFIN_BUILTIN_MIN_2X16,
5528   BFIN_BUILTIN_MAX_2X16,
5529
5530   BFIN_BUILTIN_SSADD_1X16,
5531   BFIN_BUILTIN_SSSUB_1X16,
5532   BFIN_BUILTIN_MULT_1X16,
5533   BFIN_BUILTIN_MULTR_1X16,
5534   BFIN_BUILTIN_NORM_1X16,
5535   BFIN_BUILTIN_NEG_1X16,
5536   BFIN_BUILTIN_ABS_1X16,
5537   BFIN_BUILTIN_MIN_1X16,
5538   BFIN_BUILTIN_MAX_1X16,
5539
5540   BFIN_BUILTIN_SUM_2X16,
5541   BFIN_BUILTIN_DIFFHL_2X16,
5542   BFIN_BUILTIN_DIFFLH_2X16,
5543
5544   BFIN_BUILTIN_SSADD_1X32,
5545   BFIN_BUILTIN_SSSUB_1X32,
5546   BFIN_BUILTIN_NORM_1X32,
5547   BFIN_BUILTIN_ROUND_1X32,
5548   BFIN_BUILTIN_NEG_1X32,
5549   BFIN_BUILTIN_ABS_1X32,
5550   BFIN_BUILTIN_MIN_1X32,
5551   BFIN_BUILTIN_MAX_1X32,
5552   BFIN_BUILTIN_MULT_1X32,
5553   BFIN_BUILTIN_MULT_1X32X32,
5554   BFIN_BUILTIN_MULT_1X32X32NS,
5555
5556   BFIN_BUILTIN_MULHISILL,
5557   BFIN_BUILTIN_MULHISILH,
5558   BFIN_BUILTIN_MULHISIHL,
5559   BFIN_BUILTIN_MULHISIHH,
5560
5561   BFIN_BUILTIN_LSHIFT_1X16,
5562   BFIN_BUILTIN_LSHIFT_2X16,
5563   BFIN_BUILTIN_SSASHIFT_1X16,
5564   BFIN_BUILTIN_SSASHIFT_2X16,
5565   BFIN_BUILTIN_SSASHIFT_1X32,
5566
5567   BFIN_BUILTIN_CPLX_MUL_16,
5568   BFIN_BUILTIN_CPLX_MAC_16,
5569   BFIN_BUILTIN_CPLX_MSU_16,
5570
5571   BFIN_BUILTIN_CPLX_MUL_16_S40,
5572   BFIN_BUILTIN_CPLX_MAC_16_S40,
5573   BFIN_BUILTIN_CPLX_MSU_16_S40,
5574
5575   BFIN_BUILTIN_CPLX_SQU,
5576
5577   BFIN_BUILTIN_LOADBYTES,
5578
5579   BFIN_BUILTIN_MAX
5580 };
5581
5582 #define def_builtin(NAME, TYPE, CODE)                                   \
5583 do {                                                                    \
5584   add_builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD,            \
5585                        NULL, NULL_TREE);                                \
5586 } while (0)
5587
5588 /* Set up all builtin functions for this target.  */
5589 static void
5590 bfin_init_builtins (void)
5591 {
5592   tree V2HI_type_node = build_vector_type_for_mode (intHI_type_node, V2HImode);
5593   tree void_ftype_void
5594     = build_function_type (void_type_node, void_list_node);
5595   tree short_ftype_short
5596     = build_function_type_list (short_integer_type_node, short_integer_type_node,
5597                                 NULL_TREE);
5598   tree short_ftype_int_int
5599     = build_function_type_list (short_integer_type_node, integer_type_node,
5600                                 integer_type_node, NULL_TREE);
5601   tree int_ftype_int_int
5602     = build_function_type_list (integer_type_node, integer_type_node,
5603                                 integer_type_node, NULL_TREE);
5604   tree int_ftype_int
5605     = build_function_type_list (integer_type_node, integer_type_node,
5606                                 NULL_TREE);
5607   tree short_ftype_int
5608     = build_function_type_list (short_integer_type_node, integer_type_node,
5609                                 NULL_TREE);
5610   tree int_ftype_v2hi_v2hi
5611     = build_function_type_list (integer_type_node, V2HI_type_node,
5612                                 V2HI_type_node, NULL_TREE);
5613   tree v2hi_ftype_v2hi_v2hi
5614     = build_function_type_list (V2HI_type_node, V2HI_type_node,
5615                                 V2HI_type_node, NULL_TREE);
5616   tree v2hi_ftype_v2hi_v2hi_v2hi
5617     = build_function_type_list (V2HI_type_node, V2HI_type_node,
5618                                 V2HI_type_node, V2HI_type_node, NULL_TREE);
5619   tree v2hi_ftype_int_int
5620     = build_function_type_list (V2HI_type_node, integer_type_node,
5621                                 integer_type_node, NULL_TREE);
5622   tree v2hi_ftype_v2hi_int
5623     = build_function_type_list (V2HI_type_node, V2HI_type_node,
5624                                 integer_type_node, NULL_TREE);
5625   tree int_ftype_short_short
5626     = build_function_type_list (integer_type_node, short_integer_type_node,
5627                                 short_integer_type_node, NULL_TREE);
5628   tree v2hi_ftype_v2hi
5629     = build_function_type_list (V2HI_type_node, V2HI_type_node, NULL_TREE);
5630   tree short_ftype_v2hi
5631     = build_function_type_list (short_integer_type_node, V2HI_type_node,
5632                                 NULL_TREE);
5633   tree int_ftype_pint
5634     = build_function_type_list (integer_type_node,
5635                                 build_pointer_type (integer_type_node),
5636                                 NULL_TREE);
5637   
5638   /* Add the remaining MMX insns with somewhat more complicated types.  */
5639   def_builtin ("__builtin_bfin_csync", void_ftype_void, BFIN_BUILTIN_CSYNC);
5640   def_builtin ("__builtin_bfin_ssync", void_ftype_void, BFIN_BUILTIN_SSYNC);
5641
5642   def_builtin ("__builtin_bfin_ones", short_ftype_int, BFIN_BUILTIN_ONES);
5643
5644   def_builtin ("__builtin_bfin_compose_2x16", v2hi_ftype_int_int,
5645                BFIN_BUILTIN_COMPOSE_2X16);
5646   def_builtin ("__builtin_bfin_extract_hi", short_ftype_v2hi,
5647                BFIN_BUILTIN_EXTRACTHI);
5648   def_builtin ("__builtin_bfin_extract_lo", short_ftype_v2hi,
5649                BFIN_BUILTIN_EXTRACTLO);
5650
5651   def_builtin ("__builtin_bfin_min_fr2x16", v2hi_ftype_v2hi_v2hi,
5652                BFIN_BUILTIN_MIN_2X16);
5653   def_builtin ("__builtin_bfin_max_fr2x16", v2hi_ftype_v2hi_v2hi,
5654                BFIN_BUILTIN_MAX_2X16);
5655
5656   def_builtin ("__builtin_bfin_add_fr2x16", v2hi_ftype_v2hi_v2hi,
5657                BFIN_BUILTIN_SSADD_2X16);
5658   def_builtin ("__builtin_bfin_sub_fr2x16", v2hi_ftype_v2hi_v2hi,
5659                BFIN_BUILTIN_SSSUB_2X16);
5660   def_builtin ("__builtin_bfin_dspaddsubsat", v2hi_ftype_v2hi_v2hi,
5661                BFIN_BUILTIN_SSADDSUB_2X16);
5662   def_builtin ("__builtin_bfin_dspsubaddsat", v2hi_ftype_v2hi_v2hi,
5663                BFIN_BUILTIN_SSSUBADD_2X16);
5664   def_builtin ("__builtin_bfin_mult_fr2x16", v2hi_ftype_v2hi_v2hi,
5665                BFIN_BUILTIN_MULT_2X16);
5666   def_builtin ("__builtin_bfin_multr_fr2x16", v2hi_ftype_v2hi_v2hi,
5667                BFIN_BUILTIN_MULTR_2X16);
5668   def_builtin ("__builtin_bfin_negate_fr2x16", v2hi_ftype_v2hi,
5669                BFIN_BUILTIN_NEG_2X16);
5670   def_builtin ("__builtin_bfin_abs_fr2x16", v2hi_ftype_v2hi,
5671                BFIN_BUILTIN_ABS_2X16);
5672
5673   def_builtin ("__builtin_bfin_min_fr1x16", short_ftype_int_int,
5674                BFIN_BUILTIN_MIN_1X16);
5675   def_builtin ("__builtin_bfin_max_fr1x16", short_ftype_int_int,
5676                BFIN_BUILTIN_MAX_1X16);
5677
5678   def_builtin ("__builtin_bfin_add_fr1x16", short_ftype_int_int,
5679                BFIN_BUILTIN_SSADD_1X16);
5680   def_builtin ("__builtin_bfin_sub_fr1x16", short_ftype_int_int,
5681                BFIN_BUILTIN_SSSUB_1X16);
5682   def_builtin ("__builtin_bfin_mult_fr1x16", short_ftype_int_int,
5683                BFIN_BUILTIN_MULT_1X16);
5684   def_builtin ("__builtin_bfin_multr_fr1x16", short_ftype_int_int,
5685                BFIN_BUILTIN_MULTR_1X16);
5686   def_builtin ("__builtin_bfin_negate_fr1x16", short_ftype_short,
5687                BFIN_BUILTIN_NEG_1X16);
5688   def_builtin ("__builtin_bfin_abs_fr1x16", short_ftype_short,
5689                BFIN_BUILTIN_ABS_1X16);
5690   def_builtin ("__builtin_bfin_norm_fr1x16", short_ftype_int,
5691                BFIN_BUILTIN_NORM_1X16);
5692
5693   def_builtin ("__builtin_bfin_sum_fr2x16", short_ftype_v2hi,
5694                BFIN_BUILTIN_SUM_2X16);
5695   def_builtin ("__builtin_bfin_diff_hl_fr2x16", short_ftype_v2hi,
5696                BFIN_BUILTIN_DIFFHL_2X16);
5697   def_builtin ("__builtin_bfin_diff_lh_fr2x16", short_ftype_v2hi,
5698                BFIN_BUILTIN_DIFFLH_2X16);
5699
5700   def_builtin ("__builtin_bfin_mulhisill", int_ftype_v2hi_v2hi,
5701                BFIN_BUILTIN_MULHISILL);
5702   def_builtin ("__builtin_bfin_mulhisihl", int_ftype_v2hi_v2hi,
5703                BFIN_BUILTIN_MULHISIHL);
5704   def_builtin ("__builtin_bfin_mulhisilh", int_ftype_v2hi_v2hi,
5705                BFIN_BUILTIN_MULHISILH);
5706   def_builtin ("__builtin_bfin_mulhisihh", int_ftype_v2hi_v2hi,
5707                BFIN_BUILTIN_MULHISIHH);
5708
5709   def_builtin ("__builtin_bfin_min_fr1x32", int_ftype_int_int,
5710                BFIN_BUILTIN_MIN_1X32);
5711   def_builtin ("__builtin_bfin_max_fr1x32", int_ftype_int_int,
5712                BFIN_BUILTIN_MAX_1X32);
5713
5714   def_builtin ("__builtin_bfin_add_fr1x32", int_ftype_int_int,
5715                BFIN_BUILTIN_SSADD_1X32);
5716   def_builtin ("__builtin_bfin_sub_fr1x32", int_ftype_int_int,
5717                BFIN_BUILTIN_SSSUB_1X32);
5718   def_builtin ("__builtin_bfin_negate_fr1x32", int_ftype_int,
5719                BFIN_BUILTIN_NEG_1X32);
5720   def_builtin ("__builtin_bfin_abs_fr1x32", int_ftype_int,
5721                BFIN_BUILTIN_ABS_1X32);
5722   def_builtin ("__builtin_bfin_norm_fr1x32", short_ftype_int,
5723                BFIN_BUILTIN_NORM_1X32);
5724   def_builtin ("__builtin_bfin_round_fr1x32", short_ftype_int,
5725                BFIN_BUILTIN_ROUND_1X32);
5726   def_builtin ("__builtin_bfin_mult_fr1x32", int_ftype_short_short,
5727                BFIN_BUILTIN_MULT_1X32);
5728   def_builtin ("__builtin_bfin_mult_fr1x32x32", int_ftype_int_int,
5729                BFIN_BUILTIN_MULT_1X32X32);
5730   def_builtin ("__builtin_bfin_mult_fr1x32x32NS", int_ftype_int_int,
5731                BFIN_BUILTIN_MULT_1X32X32NS);
5732
5733   /* Shifts.  */
5734   def_builtin ("__builtin_bfin_shl_fr1x16", short_ftype_int_int,
5735                BFIN_BUILTIN_SSASHIFT_1X16);
5736   def_builtin ("__builtin_bfin_shl_fr2x16", v2hi_ftype_v2hi_int,
5737                BFIN_BUILTIN_SSASHIFT_2X16);
5738   def_builtin ("__builtin_bfin_lshl_fr1x16", short_ftype_int_int,
5739                BFIN_BUILTIN_LSHIFT_1X16);
5740   def_builtin ("__builtin_bfin_lshl_fr2x16", v2hi_ftype_v2hi_int,
5741                BFIN_BUILTIN_LSHIFT_2X16);
5742   def_builtin ("__builtin_bfin_shl_fr1x32", int_ftype_int_int,
5743                BFIN_BUILTIN_SSASHIFT_1X32);
5744
5745   /* Complex numbers.  */
5746   def_builtin ("__builtin_bfin_cmplx_add", v2hi_ftype_v2hi_v2hi,
5747                BFIN_BUILTIN_SSADD_2X16);
5748   def_builtin ("__builtin_bfin_cmplx_sub", v2hi_ftype_v2hi_v2hi,
5749                BFIN_BUILTIN_SSSUB_2X16);
5750   def_builtin ("__builtin_bfin_cmplx_mul", v2hi_ftype_v2hi_v2hi,
5751                BFIN_BUILTIN_CPLX_MUL_16);
5752   def_builtin ("__builtin_bfin_cmplx_mac", v2hi_ftype_v2hi_v2hi_v2hi,
5753                BFIN_BUILTIN_CPLX_MAC_16);
5754   def_builtin ("__builtin_bfin_cmplx_msu", v2hi_ftype_v2hi_v2hi_v2hi,
5755                BFIN_BUILTIN_CPLX_MSU_16);
5756   def_builtin ("__builtin_bfin_cmplx_mul_s40", v2hi_ftype_v2hi_v2hi,
5757                BFIN_BUILTIN_CPLX_MUL_16_S40);
5758   def_builtin ("__builtin_bfin_cmplx_mac_s40", v2hi_ftype_v2hi_v2hi_v2hi,
5759                BFIN_BUILTIN_CPLX_MAC_16_S40);
5760   def_builtin ("__builtin_bfin_cmplx_msu_s40", v2hi_ftype_v2hi_v2hi_v2hi,
5761                BFIN_BUILTIN_CPLX_MSU_16_S40);
5762   def_builtin ("__builtin_bfin_csqu_fr16", v2hi_ftype_v2hi,
5763                BFIN_BUILTIN_CPLX_SQU);
5764
5765   /* "Unaligned" load.  */
5766   def_builtin ("__builtin_bfin_loadbytes", int_ftype_pint,
5767                BFIN_BUILTIN_LOADBYTES);
5768
5769 }
5770
5771
5772 struct builtin_description
5773 {
5774   const enum insn_code icode;
5775   const char *const name;
5776   const enum bfin_builtins code;
5777   int macflag;
5778 };
5779
5780 static const struct builtin_description bdesc_2arg[] =
5781 {
5782   { CODE_FOR_composev2hi, "__builtin_bfin_compose_2x16", BFIN_BUILTIN_COMPOSE_2X16, -1 },
5783
5784   { CODE_FOR_ssashiftv2hi3, "__builtin_bfin_shl_fr2x16", BFIN_BUILTIN_SSASHIFT_2X16, -1 },
5785   { CODE_FOR_ssashifthi3, "__builtin_bfin_shl_fr1x16", BFIN_BUILTIN_SSASHIFT_1X16, -1 },
5786   { CODE_FOR_lshiftv2hi3, "__builtin_bfin_lshl_fr2x16", BFIN_BUILTIN_LSHIFT_2X16, -1 },
5787   { CODE_FOR_lshifthi3, "__builtin_bfin_lshl_fr1x16", BFIN_BUILTIN_LSHIFT_1X16, -1 },
5788   { CODE_FOR_ssashiftsi3, "__builtin_bfin_shl_fr1x32", BFIN_BUILTIN_SSASHIFT_1X32, -1 },
5789
5790   { CODE_FOR_sminhi3, "__builtin_bfin_min_fr1x16", BFIN_BUILTIN_MIN_1X16, -1 },
5791   { CODE_FOR_smaxhi3, "__builtin_bfin_max_fr1x16", BFIN_BUILTIN_MAX_1X16, -1 },
5792   { CODE_FOR_ssaddhi3, "__builtin_bfin_add_fr1x16", BFIN_BUILTIN_SSADD_1X16, -1 },
5793   { CODE_FOR_sssubhi3, "__builtin_bfin_sub_fr1x16", BFIN_BUILTIN_SSSUB_1X16, -1 },
5794
5795   { CODE_FOR_sminsi3, "__builtin_bfin_min_fr1x32", BFIN_BUILTIN_MIN_1X32, -1 },
5796   { CODE_FOR_smaxsi3, "__builtin_bfin_max_fr1x32", BFIN_BUILTIN_MAX_1X32, -1 },
5797   { CODE_FOR_ssaddsi3, "__builtin_bfin_add_fr1x32", BFIN_BUILTIN_SSADD_1X32, -1 },
5798   { CODE_FOR_sssubsi3, "__builtin_bfin_sub_fr1x32", BFIN_BUILTIN_SSSUB_1X32, -1 },
5799
5800   { CODE_FOR_sminv2hi3, "__builtin_bfin_min_fr2x16", BFIN_BUILTIN_MIN_2X16, -1 },
5801   { CODE_FOR_smaxv2hi3, "__builtin_bfin_max_fr2x16", BFIN_BUILTIN_MAX_2X16, -1 },
5802   { CODE_FOR_ssaddv2hi3, "__builtin_bfin_add_fr2x16", BFIN_BUILTIN_SSADD_2X16, -1 },
5803   { CODE_FOR_sssubv2hi3, "__builtin_bfin_sub_fr2x16", BFIN_BUILTIN_SSSUB_2X16, -1 },
5804   { CODE_FOR_ssaddsubv2hi3, "__builtin_bfin_dspaddsubsat", BFIN_BUILTIN_SSADDSUB_2X16, -1 },
5805   { CODE_FOR_sssubaddv2hi3, "__builtin_bfin_dspsubaddsat", BFIN_BUILTIN_SSSUBADD_2X16, -1 },
5806
5807   { CODE_FOR_flag_mulhisi, "__builtin_bfin_mult_fr1x32", BFIN_BUILTIN_MULT_1X32, MACFLAG_NONE },
5808   { CODE_FOR_flag_mulhi, "__builtin_bfin_mult_fr1x16", BFIN_BUILTIN_MULT_1X16, MACFLAG_T },
5809   { CODE_FOR_flag_mulhi, "__builtin_bfin_multr_fr1x16", BFIN_BUILTIN_MULTR_1X16, MACFLAG_NONE },
5810   { CODE_FOR_flag_mulv2hi, "__builtin_bfin_mult_fr2x16", BFIN_BUILTIN_MULT_2X16, MACFLAG_T },
5811   { CODE_FOR_flag_mulv2hi, "__builtin_bfin_multr_fr2x16", BFIN_BUILTIN_MULTR_2X16, MACFLAG_NONE },
5812
5813   { CODE_FOR_mulhisi_ll, "__builtin_bfin_mulhisill", BFIN_BUILTIN_MULHISILL, -1 },
5814   { CODE_FOR_mulhisi_lh, "__builtin_bfin_mulhisilh", BFIN_BUILTIN_MULHISILH, -1 },
5815   { CODE_FOR_mulhisi_hl, "__builtin_bfin_mulhisihl", BFIN_BUILTIN_MULHISIHL, -1 },
5816   { CODE_FOR_mulhisi_hh, "__builtin_bfin_mulhisihh", BFIN_BUILTIN_MULHISIHH, -1 }
5817
5818 };
5819
5820 static const struct builtin_description bdesc_1arg[] =
5821 {
5822   { CODE_FOR_loadbytes, "__builtin_bfin_loadbytes", BFIN_BUILTIN_LOADBYTES, 0 },
5823
5824   { CODE_FOR_ones, "__builtin_bfin_ones", BFIN_BUILTIN_ONES, 0 },
5825
5826   { CODE_FOR_signbitshi2, "__builtin_bfin_norm_fr1x16", BFIN_BUILTIN_NORM_1X16, 0 },
5827   { CODE_FOR_ssneghi2, "__builtin_bfin_negate_fr1x16", BFIN_BUILTIN_NEG_1X16, 0 },
5828   { CODE_FOR_abshi2, "__builtin_bfin_abs_fr1x16", BFIN_BUILTIN_ABS_1X16, 0 },
5829
5830   { CODE_FOR_signbitssi2, "__builtin_bfin_norm_fr1x32", BFIN_BUILTIN_NORM_1X32, 0 },
5831   { CODE_FOR_ssroundsi2, "__builtin_bfin_round_fr1x32", BFIN_BUILTIN_ROUND_1X32, 0 },
5832   { CODE_FOR_ssnegsi2, "__builtin_bfin_negate_fr1x32", BFIN_BUILTIN_NEG_1X32, 0 },
5833   { CODE_FOR_ssabssi2, "__builtin_bfin_abs_fr1x32", BFIN_BUILTIN_ABS_1X32, 0 },
5834
5835   { CODE_FOR_movv2hi_hi_low, "__builtin_bfin_extract_lo", BFIN_BUILTIN_EXTRACTLO, 0 },
5836   { CODE_FOR_movv2hi_hi_high, "__builtin_bfin_extract_hi", BFIN_BUILTIN_EXTRACTHI, 0 },
5837   { CODE_FOR_ssnegv2hi2, "__builtin_bfin_negate_fr2x16", BFIN_BUILTIN_NEG_2X16, 0 },
5838   { CODE_FOR_ssabsv2hi2, "__builtin_bfin_abs_fr2x16", BFIN_BUILTIN_ABS_2X16, 0 }
5839 };
5840
5841 /* Errors in the source file can cause expand_expr to return const0_rtx
5842    where we expect a vector.  To avoid crashing, use one of the vector
5843    clear instructions.  */
5844 static rtx
5845 safe_vector_operand (rtx x, enum machine_mode mode)
5846 {
5847   if (x != const0_rtx)
5848     return x;
5849   x = gen_reg_rtx (SImode);
5850
5851   emit_insn (gen_movsi (x, CONST0_RTX (SImode)));
5852   return gen_lowpart (mode, x);
5853 }
5854
5855 /* Subroutine of bfin_expand_builtin to take care of binop insns.  MACFLAG is -1
5856    if this is a normal binary op, or one of the MACFLAG_xxx constants.  */
5857
5858 static rtx
5859 bfin_expand_binop_builtin (enum insn_code icode, tree exp, rtx target,
5860                            int macflag)
5861 {
5862   rtx pat;
5863   tree arg0 = CALL_EXPR_ARG (exp, 0);
5864   tree arg1 = CALL_EXPR_ARG (exp, 1);
5865   rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
5866   rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
5867   enum machine_mode op0mode = GET_MODE (op0);
5868   enum machine_mode op1mode = GET_MODE (op1);
5869   enum machine_mode tmode = insn_data[icode].operand[0].mode;
5870   enum machine_mode mode0 = insn_data[icode].operand[1].mode;
5871   enum machine_mode mode1 = insn_data[icode].operand[2].mode;
5872
5873   if (VECTOR_MODE_P (mode0))
5874     op0 = safe_vector_operand (op0, mode0);
5875   if (VECTOR_MODE_P (mode1))
5876     op1 = safe_vector_operand (op1, mode1);
5877
5878   if (! target
5879       || GET_MODE (target) != tmode
5880       || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
5881     target = gen_reg_rtx (tmode);
5882
5883   if ((op0mode == SImode || op0mode == VOIDmode) && mode0 == HImode)
5884     {
5885       op0mode = HImode;
5886       op0 = gen_lowpart (HImode, op0);
5887     }
5888   if ((op1mode == SImode || op1mode == VOIDmode) && mode1 == HImode)
5889     {
5890       op1mode = HImode;
5891       op1 = gen_lowpart (HImode, op1);
5892     }
5893   /* In case the insn wants input operands in modes different from
5894      the result, abort.  */
5895   gcc_assert ((op0mode == mode0 || op0mode == VOIDmode)
5896               && (op1mode == mode1 || op1mode == VOIDmode));
5897
5898   if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
5899     op0 = copy_to_mode_reg (mode0, op0);
5900   if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
5901     op1 = copy_to_mode_reg (mode1, op1);
5902
5903   if (macflag == -1)
5904     pat = GEN_FCN (icode) (target, op0, op1);
5905   else
5906     pat = GEN_FCN (icode) (target, op0, op1, GEN_INT (macflag));
5907   if (! pat)
5908     return 0;
5909
5910   emit_insn (pat);
5911   return target;
5912 }
5913
5914 /* Subroutine of bfin_expand_builtin to take care of unop insns.  */
5915
5916 static rtx
5917 bfin_expand_unop_builtin (enum insn_code icode, tree exp,
5918                           rtx target)
5919 {
5920   rtx pat;
5921   tree arg0 = CALL_EXPR_ARG (exp, 0);
5922   rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
5923   enum machine_mode op0mode = GET_MODE (op0);
5924   enum machine_mode tmode = insn_data[icode].operand[0].mode;
5925   enum machine_mode mode0 = insn_data[icode].operand[1].mode;
5926
5927   if (! target
5928       || GET_MODE (target) != tmode
5929       || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
5930     target = gen_reg_rtx (tmode);
5931
5932   if (VECTOR_MODE_P (mode0))
5933     op0 = safe_vector_operand (op0, mode0);
5934
5935   if (op0mode == SImode && mode0 == HImode)
5936     {
5937       op0mode = HImode;
5938       op0 = gen_lowpart (HImode, op0);
5939     }
5940   gcc_assert (op0mode == mode0 || op0mode == VOIDmode);
5941
5942   if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
5943     op0 = copy_to_mode_reg (mode0, op0);
5944
5945   pat = GEN_FCN (icode) (target, op0);
5946   if (! pat)
5947     return 0;
5948   emit_insn (pat);
5949   return target;
5950 }
5951
5952 /* Expand an expression EXP that calls a built-in function,
5953    with result going to TARGET if that's convenient
5954    (and in mode MODE if that's convenient).
5955    SUBTARGET may be used as the target for computing one of EXP's operands.
5956    IGNORE is nonzero if the value is to be ignored.  */
5957
5958 static rtx
5959 bfin_expand_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
5960                      rtx subtarget ATTRIBUTE_UNUSED,
5961                      enum machine_mode mode ATTRIBUTE_UNUSED,
5962                      int ignore ATTRIBUTE_UNUSED)
5963 {
5964   size_t i;
5965   enum insn_code icode;
5966   const struct builtin_description *d;
5967   tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
5968   unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
5969   tree arg0, arg1, arg2;
5970   rtx op0, op1, op2, accvec, pat, tmp1, tmp2, a0reg, a1reg;
5971   enum machine_mode tmode, mode0;
5972
5973   switch (fcode)
5974     {
5975     case BFIN_BUILTIN_CSYNC:
5976       emit_insn (gen_csync ());
5977       return 0;
5978     case BFIN_BUILTIN_SSYNC:
5979       emit_insn (gen_ssync ());
5980       return 0;
5981
5982     case BFIN_BUILTIN_DIFFHL_2X16:
5983     case BFIN_BUILTIN_DIFFLH_2X16:
5984     case BFIN_BUILTIN_SUM_2X16:
5985       arg0 = CALL_EXPR_ARG (exp, 0);
5986       op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
5987       icode = (fcode == BFIN_BUILTIN_DIFFHL_2X16 ? CODE_FOR_subhilov2hi3
5988                : fcode == BFIN_BUILTIN_DIFFLH_2X16 ? CODE_FOR_sublohiv2hi3
5989                : CODE_FOR_ssaddhilov2hi3);
5990       tmode = insn_data[icode].operand[0].mode;
5991       mode0 = insn_data[icode].operand[1].mode;
5992
5993       if (! target
5994           || GET_MODE (target) != tmode
5995           || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
5996         target = gen_reg_rtx (tmode);
5997
5998       if (VECTOR_MODE_P (mode0))
5999         op0 = safe_vector_operand (op0, mode0);
6000
6001       if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
6002         op0 = copy_to_mode_reg (mode0, op0);
6003
6004       pat = GEN_FCN (icode) (target, op0, op0);
6005       if (! pat)
6006         return 0;
6007       emit_insn (pat);
6008       return target;
6009
6010     case BFIN_BUILTIN_MULT_1X32X32:
6011     case BFIN_BUILTIN_MULT_1X32X32NS:
6012       arg0 = CALL_EXPR_ARG (exp, 0);
6013       arg1 = CALL_EXPR_ARG (exp, 1);
6014       op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6015       op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
6016       if (! target
6017           || !register_operand (target, SImode))
6018         target = gen_reg_rtx (SImode);
6019
6020       a1reg = gen_rtx_REG (PDImode, REG_A1);
6021       a0reg = gen_rtx_REG (PDImode, REG_A0);
6022       tmp1 = gen_lowpart (V2HImode, op0);
6023       tmp2 = gen_lowpart (V2HImode, op1);
6024       emit_insn (gen_flag_macinit1hi (a1reg,
6025                                       gen_lowpart (HImode, op0),
6026                                       gen_lowpart (HImode, op1),
6027                                       GEN_INT (MACFLAG_FU)));
6028       emit_insn (gen_lshrpdi3 (a1reg, a1reg, GEN_INT (16)));
6029
6030       if (fcode == BFIN_BUILTIN_MULT_1X32X32)
6031         emit_insn (gen_flag_mul_macv2hi_parts_acconly (a0reg, a1reg, tmp1, tmp2,
6032                                                        const1_rtx, const1_rtx,
6033                                                        const1_rtx, const0_rtx, a1reg,
6034                                                        const0_rtx, GEN_INT (MACFLAG_NONE),
6035                                                        GEN_INT (MACFLAG_M)));
6036       else
6037         {
6038           /* For saturating multiplication, there's exactly one special case
6039              to be handled: multiplying the smallest negative value with
6040              itself.  Due to shift correction in fractional multiplies, this
6041              can overflow.  Iff this happens, OP2 will contain 1, which, when
6042              added in 32 bits to the smallest negative, wraps to the largest
6043              positive, which is the result we want.  */
6044           op2 = gen_reg_rtx (V2HImode);
6045           emit_insn (gen_packv2hi (op2, tmp1, tmp2, const0_rtx, const0_rtx));
6046           emit_insn (gen_movsibi (gen_rtx_REG (BImode, REG_CC),
6047                                   gen_lowpart (SImode, op2)));
6048           emit_insn (gen_flag_mul_macv2hi_parts_acconly_andcc0 (a0reg, a1reg, tmp1, tmp2,
6049                                                                 const1_rtx, const1_rtx,
6050                                                                 const1_rtx, const0_rtx, a1reg,
6051                                                                 const0_rtx, GEN_INT (MACFLAG_NONE),
6052                                                                 GEN_INT (MACFLAG_M)));
6053           op2 = gen_reg_rtx (SImode);
6054           emit_insn (gen_movbisi (op2, gen_rtx_REG (BImode, REG_CC)));
6055         }
6056       emit_insn (gen_flag_machi_parts_acconly (a1reg, tmp2, tmp1,
6057                                                const1_rtx, const0_rtx,
6058                                                a1reg, const0_rtx, GEN_INT (MACFLAG_M)));
6059       emit_insn (gen_ashrpdi3 (a1reg, a1reg, GEN_INT (15)));
6060       emit_insn (gen_sum_of_accumulators (target, a0reg, a0reg, a1reg));
6061       if (fcode == BFIN_BUILTIN_MULT_1X32X32NS)
6062         emit_insn (gen_addsi3 (target, target, op2));
6063       return target;
6064
6065     case BFIN_BUILTIN_CPLX_MUL_16:
6066     case BFIN_BUILTIN_CPLX_MUL_16_S40:
6067       arg0 = CALL_EXPR_ARG (exp, 0);
6068       arg1 = CALL_EXPR_ARG (exp, 1);
6069       op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6070       op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
6071       accvec = gen_reg_rtx (V2PDImode);
6072
6073       if (! target
6074           || GET_MODE (target) != V2HImode
6075           || ! (*insn_data[icode].operand[0].predicate) (target, V2HImode))
6076         target = gen_reg_rtx (tmode);
6077       if (! register_operand (op0, GET_MODE (op0)))
6078         op0 = copy_to_mode_reg (GET_MODE (op0), op0);
6079       if (! register_operand (op1, GET_MODE (op1)))
6080         op1 = copy_to_mode_reg (GET_MODE (op1), op1);
6081
6082       if (fcode == BFIN_BUILTIN_CPLX_MUL_16)
6083         emit_insn (gen_flag_macinit1v2hi_parts (accvec, op0, op1, const0_rtx,
6084                                                 const0_rtx, const0_rtx,
6085                                                 const1_rtx, GEN_INT (MACFLAG_W32)));
6086       else
6087         emit_insn (gen_flag_macinit1v2hi_parts (accvec, op0, op1, const0_rtx,
6088                                                 const0_rtx, const0_rtx,
6089                                                 const1_rtx, GEN_INT (MACFLAG_NONE)));
6090       emit_insn (gen_flag_macv2hi_parts (target, op0, op1, const1_rtx,
6091                                          const1_rtx, const1_rtx,
6092                                          const0_rtx, accvec, const1_rtx, const0_rtx,
6093                                          GEN_INT (MACFLAG_NONE), accvec));
6094
6095       return target;
6096
6097     case BFIN_BUILTIN_CPLX_MAC_16:
6098     case BFIN_BUILTIN_CPLX_MSU_16:
6099     case BFIN_BUILTIN_CPLX_MAC_16_S40:
6100     case BFIN_BUILTIN_CPLX_MSU_16_S40:
6101       arg0 = CALL_EXPR_ARG (exp, 0);
6102       arg1 = CALL_EXPR_ARG (exp, 1);
6103       arg2 = CALL_EXPR_ARG (exp, 2);
6104       op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6105       op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
6106       op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
6107       accvec = gen_reg_rtx (V2PDImode);
6108
6109       if (! target
6110           || GET_MODE (target) != V2HImode
6111           || ! (*insn_data[icode].operand[0].predicate) (target, V2HImode))
6112         target = gen_reg_rtx (tmode);
6113       if (! register_operand (op1, GET_MODE (op1)))
6114         op1 = copy_to_mode_reg (GET_MODE (op1), op1);
6115       if (! register_operand (op2, GET_MODE (op2)))
6116         op2 = copy_to_mode_reg (GET_MODE (op2), op2);
6117
6118       tmp1 = gen_reg_rtx (SImode);
6119       tmp2 = gen_reg_rtx (SImode);
6120       emit_insn (gen_ashlsi3 (tmp1, gen_lowpart (SImode, op0), GEN_INT (16)));
6121       emit_move_insn (tmp2, gen_lowpart (SImode, op0));
6122       emit_insn (gen_movstricthi_1 (gen_lowpart (HImode, tmp2), const0_rtx));
6123       emit_insn (gen_load_accumulator_pair (accvec, tmp1, tmp2));
6124       if (fcode == BFIN_BUILTIN_CPLX_MAC_16
6125           || fcode == BFIN_BUILTIN_CPLX_MSU_16)
6126         emit_insn (gen_flag_macv2hi_parts_acconly (accvec, op1, op2, const0_rtx,
6127                                                    const0_rtx, const0_rtx,
6128                                                    const1_rtx, accvec, const0_rtx,
6129                                                    const0_rtx,
6130                                                    GEN_INT (MACFLAG_W32)));
6131       else
6132         emit_insn (gen_flag_macv2hi_parts_acconly (accvec, op1, op2, const0_rtx,
6133                                                    const0_rtx, const0_rtx,
6134                                                    const1_rtx, accvec, const0_rtx,
6135                                                    const0_rtx,
6136                                                    GEN_INT (MACFLAG_NONE)));
6137       if (fcode == BFIN_BUILTIN_CPLX_MAC_16
6138           || fcode == BFIN_BUILTIN_CPLX_MAC_16_S40)
6139         {
6140           tmp1 = const1_rtx;
6141           tmp2 = const0_rtx;
6142         }
6143       else
6144         {
6145           tmp1 = const0_rtx;
6146           tmp2 = const1_rtx;
6147         }
6148       emit_insn (gen_flag_macv2hi_parts (target, op1, op2, const1_rtx,
6149                                          const1_rtx, const1_rtx,
6150                                          const0_rtx, accvec, tmp1, tmp2,
6151                                          GEN_INT (MACFLAG_NONE), accvec));
6152
6153       return target;
6154
6155     case BFIN_BUILTIN_CPLX_SQU:
6156       arg0 = CALL_EXPR_ARG (exp, 0);
6157       op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6158       accvec = gen_reg_rtx (V2PDImode);
6159       icode = CODE_FOR_flag_mulv2hi;
6160       tmp1 = gen_reg_rtx (V2HImode);
6161       tmp2 = gen_reg_rtx (V2HImode);
6162
6163       if (! target
6164           || GET_MODE (target) != V2HImode
6165           || ! (*insn_data[icode].operand[0].predicate) (target, V2HImode))
6166         target = gen_reg_rtx (V2HImode);
6167       if (! register_operand (op0, GET_MODE (op0)))
6168         op0 = copy_to_mode_reg (GET_MODE (op0), op0);
6169
6170       emit_insn (gen_flag_mulv2hi (tmp1, op0, op0, GEN_INT (MACFLAG_NONE)));
6171
6172       emit_insn (gen_flag_mulhi_parts (tmp2, op0, op0, const0_rtx,
6173                                        const0_rtx, const1_rtx,
6174                                        GEN_INT (MACFLAG_NONE)));
6175
6176       emit_insn (gen_ssaddhi3_parts (target, tmp2, tmp2, const1_rtx,
6177                                           const0_rtx, const0_rtx));
6178
6179       emit_insn (gen_sssubhi3_parts (target, tmp1, tmp1, const0_rtx,
6180                                           const0_rtx, const1_rtx));
6181
6182       return target;
6183
6184     default:
6185       break;
6186     }
6187
6188   for (i = 0, d = bdesc_2arg; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
6189     if (d->code == fcode)
6190       return bfin_expand_binop_builtin (d->icode, exp, target,
6191                                         d->macflag);
6192
6193   for (i = 0, d = bdesc_1arg; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
6194     if (d->code == fcode)
6195       return bfin_expand_unop_builtin (d->icode, exp, target);
6196
6197   gcc_unreachable ();
6198 }
6199 \f
6200 #undef TARGET_INIT_BUILTINS
6201 #define TARGET_INIT_BUILTINS bfin_init_builtins
6202
6203 #undef TARGET_EXPAND_BUILTIN
6204 #define TARGET_EXPAND_BUILTIN bfin_expand_builtin
6205
6206 #undef TARGET_ASM_GLOBALIZE_LABEL
6207 #define TARGET_ASM_GLOBALIZE_LABEL bfin_globalize_label 
6208
6209 #undef TARGET_ASM_FILE_START
6210 #define TARGET_ASM_FILE_START output_file_start
6211
6212 #undef TARGET_ATTRIBUTE_TABLE
6213 #define TARGET_ATTRIBUTE_TABLE bfin_attribute_table
6214
6215 #undef TARGET_COMP_TYPE_ATTRIBUTES
6216 #define TARGET_COMP_TYPE_ATTRIBUTES bfin_comp_type_attributes
6217
6218 #undef TARGET_RTX_COSTS
6219 #define TARGET_RTX_COSTS bfin_rtx_costs
6220
6221 #undef  TARGET_ADDRESS_COST
6222 #define TARGET_ADDRESS_COST bfin_address_cost
6223
6224 #undef  TARGET_ASM_INTEGER
6225 #define TARGET_ASM_INTEGER bfin_assemble_integer
6226
6227 #undef TARGET_MACHINE_DEPENDENT_REORG
6228 #define TARGET_MACHINE_DEPENDENT_REORG bfin_reorg
6229
6230 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
6231 #define TARGET_FUNCTION_OK_FOR_SIBCALL bfin_function_ok_for_sibcall
6232
6233 #undef TARGET_ASM_OUTPUT_MI_THUNK
6234 #define TARGET_ASM_OUTPUT_MI_THUNK bfin_output_mi_thunk
6235 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
6236 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true
6237
6238 #undef TARGET_SCHED_ADJUST_COST
6239 #define TARGET_SCHED_ADJUST_COST bfin_adjust_cost
6240
6241 #undef TARGET_SCHED_ISSUE_RATE
6242 #define TARGET_SCHED_ISSUE_RATE bfin_issue_rate
6243
6244 #undef TARGET_PROMOTE_PROTOTYPES
6245 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
6246 #undef TARGET_PROMOTE_FUNCTION_ARGS
6247 #define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_const_tree_true
6248 #undef TARGET_PROMOTE_FUNCTION_RETURN
6249 #define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_const_tree_true
6250
6251 #undef TARGET_ARG_PARTIAL_BYTES
6252 #define TARGET_ARG_PARTIAL_BYTES bfin_arg_partial_bytes
6253
6254 #undef TARGET_PASS_BY_REFERENCE
6255 #define TARGET_PASS_BY_REFERENCE bfin_pass_by_reference
6256
6257 #undef TARGET_SETUP_INCOMING_VARARGS
6258 #define TARGET_SETUP_INCOMING_VARARGS setup_incoming_varargs
6259
6260 #undef TARGET_STRUCT_VALUE_RTX
6261 #define TARGET_STRUCT_VALUE_RTX bfin_struct_value_rtx
6262
6263 #undef TARGET_VECTOR_MODE_SUPPORTED_P
6264 #define TARGET_VECTOR_MODE_SUPPORTED_P bfin_vector_mode_supported_p
6265
6266 #undef TARGET_HANDLE_OPTION
6267 #define TARGET_HANDLE_OPTION bfin_handle_option
6268
6269 #undef TARGET_DEFAULT_TARGET_FLAGS
6270 #define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
6271
6272 #undef TARGET_SECONDARY_RELOAD
6273 #define TARGET_SECONDARY_RELOAD bfin_secondary_reload
6274
6275 #undef TARGET_DELEGITIMIZE_ADDRESS
6276 #define TARGET_DELEGITIMIZE_ADDRESS bfin_delegitimize_address
6277
6278 #undef TARGET_CANNOT_FORCE_CONST_MEM
6279 #define TARGET_CANNOT_FORCE_CONST_MEM bfin_cannot_force_const_mem
6280
6281 #undef TARGET_RETURN_IN_MEMORY
6282 #define TARGET_RETURN_IN_MEMORY bfin_return_in_memory
6283
6284 struct gcc_target targetm = TARGET_INITIALIZER;