OSDN Git Service

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