OSDN Git Service

* config/bfin/bfin.c (bfin_optimize_loop): When looking for the last
[pf3gnuchains/gcc-fork.git] / gcc / config / bfin / bfin.c
1 /* The Blackfin code generation auxiliary output file.
2    Copyright (C) 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
3    Contributed by Analog Devices.
4
5    This file is part of GCC.
6
7    GCC is free software; you can redistribute it and/or modify it
8    under the terms of the GNU General Public License as published
9    by the Free Software Foundation; either version 3, or (at your
10    option) any later version.
11
12    GCC is distributed in the hope that it will be useful, but WITHOUT
13    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
15    License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with GCC; see the file COPYING3.  If not see
19    <http://www.gnu.org/licenses/>.  */
20
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "tm.h"
25 #include "rtl.h"
26 #include "regs.h"
27 #include "hard-reg-set.h"
28 #include "real.h"
29 #include "insn-config.h"
30 #include "insn-codes.h"
31 #include "conditions.h"
32 #include "insn-flags.h"
33 #include "output.h"
34 #include "insn-attr.h"
35 #include "tree.h"
36 #include "flags.h"
37 #include "except.h"
38 #include "function.h"
39 #include "input.h"
40 #include "target.h"
41 #include "target-def.h"
42 #include "expr.h"
43 #include "toplev.h"
44 #include "recog.h"
45 #include "optabs.h"
46 #include "ggc.h"
47 #include "integrate.h"
48 #include "cgraph.h"
49 #include "langhooks.h"
50 #include "bfin-protos.h"
51 #include "tm-preds.h"
52 #include "tm-constrs.h"
53 #include "gt-bfin.h"
54 #include "basic-block.h"
55 #include "cfglayout.h"
56 #include "timevar.h"
57 #include "df.h"
58
59 /* A C structure for machine-specific, per-function data.
60    This is added to the cfun structure.  */
61 struct GTY(()) machine_function
62 {
63   /* Set if we are notified by the doloop pass that a hardware loop
64      was created.  */
65   int has_hardware_loops;
66   /* Set if we create a memcpy pattern that uses loop registers.  */
67   int has_loopreg_clobber;
68 };
69
70 /* Test and compare insns in bfin.md store the information needed to
71    generate branch and scc insns here.  */
72 rtx bfin_compare_op0, bfin_compare_op1;
73
74 /* RTX for condition code flag register and RETS register */
75 extern GTY(()) rtx bfin_cc_rtx;
76 extern GTY(()) rtx bfin_rets_rtx;
77 rtx bfin_cc_rtx, bfin_rets_rtx;
78
79 int max_arg_registers = 0;
80
81 /* Arrays used when emitting register names.  */
82 const char *short_reg_names[]  =  SHORT_REGISTER_NAMES;
83 const char *high_reg_names[]   =  HIGH_REGISTER_NAMES;
84 const char *dregs_pair_names[] =  DREGS_PAIR_NAMES;
85 const char *byte_reg_names[]   =  BYTE_REGISTER_NAMES;
86
87 static int arg_regs[] = FUNCTION_ARG_REGISTERS;
88
89 /* Nonzero if -mshared-library-id was given.  */
90 static int bfin_lib_id_given;
91
92 /* Nonzero if -fschedule-insns2 was given.  We override it and
93    call the scheduler ourselves during reorg.  */
94 static int bfin_flag_schedule_insns2;
95
96 /* Determines whether we run variable tracking in machine dependent
97    reorganization.  */
98 static int bfin_flag_var_tracking;
99
100 /* -mcpu support */
101 bfin_cpu_t bfin_cpu_type = BFIN_CPU_UNKNOWN;
102
103 /* -msi-revision support. There are three special values:
104    -1      -msi-revision=none.
105    0xffff  -msi-revision=any.  */
106 int bfin_si_revision;
107
108 /* The workarounds enabled */
109 unsigned int bfin_workarounds = 0;
110
111 struct bfin_cpu
112 {
113   const char *name;
114   bfin_cpu_t type;
115   int si_revision;
116   unsigned int workarounds;
117 };
118
119 struct bfin_cpu bfin_cpus[] =
120 {
121   {"bf512", BFIN_CPU_BF512, 0x0000,
122    WA_SPECULATIVE_LOADS},
123
124   {"bf514", BFIN_CPU_BF514, 0x0000,
125    WA_SPECULATIVE_LOADS},
126
127   {"bf516", BFIN_CPU_BF516, 0x0000,
128    WA_SPECULATIVE_LOADS},
129
130   {"bf518", BFIN_CPU_BF518, 0x0000,
131    WA_SPECULATIVE_LOADS},
132
133   {"bf522", BFIN_CPU_BF522, 0x0002,
134    WA_SPECULATIVE_LOADS},
135   {"bf522", BFIN_CPU_BF522, 0x0001,
136    WA_SPECULATIVE_LOADS | WA_RETS},
137   {"bf522", BFIN_CPU_BF522, 0x0000,
138    WA_SPECULATIVE_LOADS | WA_RETS},
139
140   {"bf523", BFIN_CPU_BF523, 0x0002,
141    WA_SPECULATIVE_LOADS},
142   {"bf523", BFIN_CPU_BF523, 0x0001,
143    WA_SPECULATIVE_LOADS | WA_RETS},
144   {"bf523", BFIN_CPU_BF523, 0x0000,
145    WA_SPECULATIVE_LOADS | WA_RETS},
146
147   {"bf524", BFIN_CPU_BF524, 0x0002,
148    WA_SPECULATIVE_LOADS},
149   {"bf524", BFIN_CPU_BF524, 0x0001,
150    WA_SPECULATIVE_LOADS | WA_RETS},
151   {"bf524", BFIN_CPU_BF524, 0x0000,
152    WA_SPECULATIVE_LOADS | WA_RETS},
153
154   {"bf525", BFIN_CPU_BF525, 0x0002,
155    WA_SPECULATIVE_LOADS},
156   {"bf525", BFIN_CPU_BF525, 0x0001,
157    WA_SPECULATIVE_LOADS | WA_RETS},
158   {"bf525", BFIN_CPU_BF525, 0x0000,
159    WA_SPECULATIVE_LOADS | WA_RETS},
160
161   {"bf526", BFIN_CPU_BF526, 0x0002,
162    WA_SPECULATIVE_LOADS},
163   {"bf526", BFIN_CPU_BF526, 0x0001,
164    WA_SPECULATIVE_LOADS | WA_RETS},
165   {"bf526", BFIN_CPU_BF526, 0x0000,
166    WA_SPECULATIVE_LOADS | WA_RETS},
167
168   {"bf527", BFIN_CPU_BF527, 0x0002,
169    WA_SPECULATIVE_LOADS},
170   {"bf527", BFIN_CPU_BF527, 0x0001,
171    WA_SPECULATIVE_LOADS | WA_RETS},
172   {"bf527", BFIN_CPU_BF527, 0x0000,
173    WA_SPECULATIVE_LOADS | WA_RETS},
174
175   {"bf531", BFIN_CPU_BF531, 0x0006,
176    WA_SPECULATIVE_LOADS | WA_LOAD_LCREGS},
177   {"bf531", BFIN_CPU_BF531, 0x0005,
178    WA_SPECULATIVE_LOADS | WA_RETS | WA_05000283 | WA_05000315 | WA_LOAD_LCREGS},
179   {"bf531", BFIN_CPU_BF531, 0x0004,
180    WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
181    | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS},
182   {"bf531", BFIN_CPU_BF531, 0x0003,
183    WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
184    | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS},
185
186   {"bf532", BFIN_CPU_BF532, 0x0006,
187    WA_SPECULATIVE_LOADS | WA_LOAD_LCREGS},
188   {"bf532", BFIN_CPU_BF532, 0x0005,
189    WA_SPECULATIVE_LOADS | WA_RETS | WA_05000283 | WA_05000315 | WA_LOAD_LCREGS},
190   {"bf532", BFIN_CPU_BF532, 0x0004,
191    WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
192    | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS},
193   {"bf532", BFIN_CPU_BF532, 0x0003,
194    WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
195    | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS},
196
197   {"bf533", BFIN_CPU_BF533, 0x0006,
198    WA_SPECULATIVE_LOADS | WA_LOAD_LCREGS},
199   {"bf533", BFIN_CPU_BF533, 0x0005,
200    WA_SPECULATIVE_LOADS | WA_RETS | WA_05000283 | WA_05000315 | WA_LOAD_LCREGS},
201   {"bf533", BFIN_CPU_BF533, 0x0004,
202    WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
203    | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS},
204   {"bf533", BFIN_CPU_BF533, 0x0003,
205    WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
206    | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS},
207
208   {"bf534", BFIN_CPU_BF534, 0x0003,
209    WA_SPECULATIVE_LOADS | WA_RETS | WA_LOAD_LCREGS},
210   {"bf534", BFIN_CPU_BF534, 0x0002,
211    WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
212    | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS},
213   {"bf534", BFIN_CPU_BF534, 0x0001,
214    WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
215    | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS},
216
217   {"bf536", BFIN_CPU_BF536, 0x0003,
218    WA_SPECULATIVE_LOADS | WA_RETS | WA_LOAD_LCREGS},
219   {"bf536", BFIN_CPU_BF536, 0x0002,
220    WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
221    | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS},
222   {"bf536", BFIN_CPU_BF536, 0x0001,
223    WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
224    | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS},
225
226   {"bf537", BFIN_CPU_BF537, 0x0003,
227    WA_SPECULATIVE_LOADS | WA_RETS | WA_LOAD_LCREGS},
228   {"bf537", BFIN_CPU_BF537, 0x0002,
229    WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
230    | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS},
231   {"bf537", BFIN_CPU_BF537, 0x0001,
232    WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
233    | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS},
234
235   {"bf538", BFIN_CPU_BF538, 0x0005,
236    WA_SPECULATIVE_LOADS | WA_LOAD_LCREGS},
237   {"bf538", BFIN_CPU_BF538, 0x0004,
238    WA_SPECULATIVE_LOADS | WA_RETS | WA_LOAD_LCREGS},
239   {"bf538", BFIN_CPU_BF538, 0x0003,
240    WA_SPECULATIVE_LOADS | WA_RETS
241    | WA_05000283 | WA_05000315 | WA_LOAD_LCREGS},
242   {"bf538", BFIN_CPU_BF538, 0x0002,
243    WA_SPECULATIVE_LOADS | WA_RETS
244    | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS},
245
246   {"bf539", BFIN_CPU_BF539, 0x0005,
247    WA_SPECULATIVE_LOADS | WA_LOAD_LCREGS},
248   {"bf539", BFIN_CPU_BF539, 0x0004,
249    WA_SPECULATIVE_LOADS | WA_RETS | WA_LOAD_LCREGS},
250   {"bf539", BFIN_CPU_BF539, 0x0003,
251    WA_SPECULATIVE_LOADS | WA_RETS
252    | WA_05000283 | WA_05000315 | WA_LOAD_LCREGS},
253   {"bf539", BFIN_CPU_BF539, 0x0002,
254    WA_SPECULATIVE_LOADS | WA_RETS
255    | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS},
256
257   {"bf542", BFIN_CPU_BF542, 0x0002,
258    WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS},
259   {"bf542", BFIN_CPU_BF542, 0x0001,
260    WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS},
261   {"bf542", BFIN_CPU_BF542, 0x0000,
262    WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS | WA_LOAD_LCREGS},
263
264   {"bf544", BFIN_CPU_BF544, 0x0002,
265    WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS},
266   {"bf544", BFIN_CPU_BF544, 0x0001,
267    WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS},
268   {"bf544", BFIN_CPU_BF544, 0x0000,
269    WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS | WA_LOAD_LCREGS},
270
271   {"bf547", BFIN_CPU_BF547, 0x0002,
272    WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS},
273   {"bf547", BFIN_CPU_BF547, 0x0001,
274    WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS},
275   {"bf547", BFIN_CPU_BF547, 0x0000,
276    WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS | WA_LOAD_LCREGS},
277
278   {"bf548", BFIN_CPU_BF548, 0x0002,
279    WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS},
280   {"bf548", BFIN_CPU_BF548, 0x0001,
281    WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS},
282   {"bf548", BFIN_CPU_BF548, 0x0000,
283    WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS | WA_LOAD_LCREGS},
284
285   {"bf549", BFIN_CPU_BF549, 0x0002,
286    WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS},
287   {"bf549", BFIN_CPU_BF549, 0x0001,
288    WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS},
289   {"bf549", BFIN_CPU_BF549, 0x0000,
290    WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS | WA_LOAD_LCREGS},
291
292   {"bf561", BFIN_CPU_BF561, 0x0005, WA_RETS
293    | WA_05000283 | WA_05000315 | WA_LOAD_LCREGS},
294   {"bf561", BFIN_CPU_BF561, 0x0003,
295    WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
296    | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS},
297   {"bf561", BFIN_CPU_BF561, 0x0002,
298    WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
299    | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS},
300
301   {NULL, 0, 0, 0}
302 };
303
304 int splitting_for_sched, splitting_loops;
305
306 static void
307 bfin_globalize_label (FILE *stream, const char *name)
308 {
309   fputs (".global ", stream);
310   assemble_name (stream, name);
311   fputc (';',stream);
312   fputc ('\n',stream);
313 }
314
315 static void 
316 output_file_start (void) 
317 {
318   FILE *file = asm_out_file;
319   int i;
320
321   /* Variable tracking should be run after all optimizations which change order
322      of insns.  It also needs a valid CFG.  This can't be done in
323      override_options, because flag_var_tracking is finalized after
324      that.  */
325   bfin_flag_var_tracking = flag_var_tracking;
326   flag_var_tracking = 0;
327
328   fprintf (file, ".file \"%s\";\n", input_filename);
329   
330   for (i = 0; arg_regs[i] >= 0; i++)
331     ;
332   max_arg_registers = i;        /* how many arg reg used  */
333 }
334
335 /* Called early in the compilation to conditionally modify
336    fixed_regs/call_used_regs.  */
337
338 void 
339 conditional_register_usage (void)
340 {
341   /* initialize condition code flag register rtx */
342   bfin_cc_rtx = gen_rtx_REG (BImode, REG_CC);
343   bfin_rets_rtx = gen_rtx_REG (Pmode, REG_RETS);
344 }
345
346 /* Examine machine-dependent attributes of function type FUNTYPE and return its
347    type.  See the definition of E_FUNKIND.  */
348
349 static e_funkind
350 funkind (const_tree funtype)
351 {
352   tree attrs = TYPE_ATTRIBUTES (funtype);
353   if (lookup_attribute ("interrupt_handler", attrs))
354     return INTERRUPT_HANDLER;
355   else if (lookup_attribute ("exception_handler", attrs))
356     return EXCPT_HANDLER;
357   else if (lookup_attribute ("nmi_handler", attrs))
358     return NMI_HANDLER;
359   else
360     return SUBROUTINE;
361 }
362 \f
363 /* Legitimize PIC addresses.  If the address is already position-independent,
364    we return ORIG.  Newly generated position-independent addresses go into a
365    reg.  This is REG if nonzero, otherwise we allocate register(s) as
366    necessary.  PICREG is the register holding the pointer to the PIC offset
367    table.  */
368
369 static rtx
370 legitimize_pic_address (rtx orig, rtx reg, rtx picreg)
371 {
372   rtx addr = orig;
373   rtx new_rtx = orig;
374
375   if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == LABEL_REF)
376     {
377       int unspec;
378       rtx tmp;
379
380       if (TARGET_ID_SHARED_LIBRARY)
381         unspec = UNSPEC_MOVE_PIC;
382       else if (GET_CODE (addr) == SYMBOL_REF
383                && SYMBOL_REF_FUNCTION_P (addr))
384         unspec = UNSPEC_FUNCDESC_GOT17M4;
385       else
386         unspec = UNSPEC_MOVE_FDPIC;
387
388       if (reg == 0)
389         {
390           gcc_assert (can_create_pseudo_p ());
391           reg = gen_reg_rtx (Pmode);
392         }
393
394       tmp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), unspec);
395       new_rtx = gen_const_mem (Pmode, gen_rtx_PLUS (Pmode, picreg, tmp));
396
397       emit_move_insn (reg, new_rtx);
398       if (picreg == pic_offset_table_rtx)
399         crtl->uses_pic_offset_table = 1;
400       return reg;
401     }
402
403   else if (GET_CODE (addr) == CONST || GET_CODE (addr) == PLUS)
404     {
405       rtx base;
406
407       if (GET_CODE (addr) == CONST)
408         {
409           addr = XEXP (addr, 0);
410           gcc_assert (GET_CODE (addr) == PLUS);
411         }
412
413       if (XEXP (addr, 0) == picreg)
414         return orig;
415
416       if (reg == 0)
417         {
418           gcc_assert (can_create_pseudo_p ());
419           reg = gen_reg_rtx (Pmode);
420         }
421
422       base = legitimize_pic_address (XEXP (addr, 0), reg, picreg);
423       addr = legitimize_pic_address (XEXP (addr, 1),
424                                      base == reg ? NULL_RTX : reg,
425                                      picreg);
426
427       if (GET_CODE (addr) == CONST_INT)
428         {
429           gcc_assert (! reload_in_progress && ! reload_completed);
430           addr = force_reg (Pmode, addr);
431         }
432
433       if (GET_CODE (addr) == PLUS && CONSTANT_P (XEXP (addr, 1)))
434         {
435           base = gen_rtx_PLUS (Pmode, base, XEXP (addr, 0));
436           addr = XEXP (addr, 1);
437         }
438
439       return gen_rtx_PLUS (Pmode, base, addr);
440     }
441
442   return new_rtx;
443 }
444 \f
445 /* Stack frame layout. */
446
447 /* For a given REGNO, determine whether it must be saved in the function
448    prologue.  IS_INTHANDLER specifies whether we're generating a normal
449    prologue or an interrupt/exception one.  */
450 static bool
451 must_save_p (bool is_inthandler, unsigned regno)
452 {
453   if (D_REGNO_P (regno))
454     {
455       bool is_eh_return_reg = false;
456       if (crtl->calls_eh_return)
457         {
458           unsigned j;
459           for (j = 0; ; j++)
460             {
461               unsigned test = EH_RETURN_DATA_REGNO (j);
462               if (test == INVALID_REGNUM)
463                 break;
464               if (test == regno)
465                 is_eh_return_reg = true;
466             }
467         }
468
469       return (is_eh_return_reg
470               || (df_regs_ever_live_p (regno)
471                   && !fixed_regs[regno]
472                   && (is_inthandler || !call_used_regs[regno])));
473     }
474   else if (P_REGNO_P (regno))
475     {
476       return ((df_regs_ever_live_p (regno)
477                && !fixed_regs[regno]
478                && (is_inthandler || !call_used_regs[regno]))
479               || (is_inthandler
480                   && (ENABLE_WA_05000283 || ENABLE_WA_05000315)
481                   && regno == REG_P5)
482               || (!TARGET_FDPIC
483                   && regno == PIC_OFFSET_TABLE_REGNUM
484                   && (crtl->uses_pic_offset_table
485                       || (TARGET_ID_SHARED_LIBRARY && !current_function_is_leaf))));
486     }
487   else
488     return ((is_inthandler || !call_used_regs[regno])
489             && (df_regs_ever_live_p (regno)
490                 || (!leaf_function_p () && call_used_regs[regno])));
491
492 }
493
494 /* Compute the number of DREGS to save with a push_multiple operation.
495    This could include registers that aren't modified in the function,
496    since push_multiple only takes a range of registers.
497    If IS_INTHANDLER, then everything that is live must be saved, even
498    if normally call-clobbered.
499    If CONSECUTIVE, return the number of registers we can save in one
500    instruction with a push/pop multiple instruction.  */
501
502 static int
503 n_dregs_to_save (bool is_inthandler, bool consecutive)
504 {
505   int count = 0;
506   unsigned i;
507
508   for (i = REG_R7 + 1; i-- != REG_R0;)
509     {
510       if (must_save_p (is_inthandler, i))
511         count++;
512       else if (consecutive)
513         return count;
514     }
515   return count;
516 }
517
518 /* Like n_dregs_to_save, but compute number of PREGS to save.  */
519
520 static int
521 n_pregs_to_save (bool is_inthandler, bool consecutive)
522 {
523   int count = 0;
524   unsigned i;
525
526   for (i = REG_P5 + 1; i-- != REG_P0;)
527     if (must_save_p (is_inthandler, i))
528       count++;
529     else if (consecutive)
530       return count;
531   return count;
532 }
533
534 /* Determine if we are going to save the frame pointer in the prologue.  */
535
536 static bool
537 must_save_fp_p (void)
538 {
539   return frame_pointer_needed || df_regs_ever_live_p (REG_FP);
540 }
541
542 static bool
543 stack_frame_needed_p (void)
544 {
545   /* EH return puts a new return address into the frame using an
546      address relative to the frame pointer.  */
547   if (crtl->calls_eh_return)
548     return true;
549   return frame_pointer_needed;
550 }
551
552 /* Emit code to save registers in the prologue.  SAVEALL is nonzero if we
553    must save all registers; this is used for interrupt handlers.
554    SPREG contains (reg:SI REG_SP).  IS_INTHANDLER is true if we're doing
555    this for an interrupt (or exception) handler.  */
556
557 static void
558 expand_prologue_reg_save (rtx spreg, int saveall, bool is_inthandler)
559 {
560   rtx predec1 = gen_rtx_PRE_DEC (SImode, spreg);
561   rtx predec = gen_rtx_MEM (SImode, predec1);
562   int ndregs = saveall ? 8 : n_dregs_to_save (is_inthandler, false);
563   int npregs = saveall ? 6 : n_pregs_to_save (is_inthandler, false);
564   int ndregs_consec = saveall ? 8 : n_dregs_to_save (is_inthandler, true);
565   int npregs_consec = saveall ? 6 : n_pregs_to_save (is_inthandler, true);
566   int dregno, pregno;
567   int total_consec = ndregs_consec + npregs_consec;
568   int i, d_to_save;
569
570   if (saveall || is_inthandler)
571     {
572       rtx insn = emit_move_insn (predec, gen_rtx_REG (SImode, REG_ASTAT));
573
574       RTX_FRAME_RELATED_P (insn) = 1;
575       for (dregno = REG_LT0; dregno <= REG_LB1; dregno++)
576         if (! current_function_is_leaf
577             || cfun->machine->has_hardware_loops
578             || cfun->machine->has_loopreg_clobber
579             || (ENABLE_WA_05000257
580                 && (dregno == REG_LC0 || dregno == REG_LC1)))
581           {
582             insn = emit_move_insn (predec, gen_rtx_REG (SImode, dregno));
583             RTX_FRAME_RELATED_P (insn) = 1;
584           }
585     }
586
587   if (total_consec != 0)
588     {
589       rtx insn;
590       rtx val = GEN_INT (-total_consec * 4);
591       rtx pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total_consec + 2));
592
593       XVECEXP (pat, 0, 0) = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, val),
594                                             UNSPEC_PUSH_MULTIPLE);
595       XVECEXP (pat, 0, total_consec + 1) = gen_rtx_SET (VOIDmode, spreg,
596                                                         gen_rtx_PLUS (Pmode,
597                                                                       spreg,
598                                                                       val));
599       RTX_FRAME_RELATED_P (XVECEXP (pat, 0, total_consec + 1)) = 1;
600       d_to_save = ndregs_consec;
601       dregno = REG_R7 + 1 - ndregs_consec;
602       pregno = REG_P5 + 1 - npregs_consec;
603       for (i = 0; i < total_consec; i++)
604         {
605           rtx memref = gen_rtx_MEM (word_mode,
606                                     gen_rtx_PLUS (Pmode, spreg,
607                                                   GEN_INT (- i * 4 - 4)));
608           rtx subpat;
609           if (d_to_save > 0)
610             {
611               subpat = gen_rtx_SET (VOIDmode, memref, gen_rtx_REG (word_mode,
612                                                                    dregno++));
613               d_to_save--;
614             }
615           else
616             {
617               subpat = gen_rtx_SET (VOIDmode, memref, gen_rtx_REG (word_mode,
618                                                                    pregno++));
619             }
620           XVECEXP (pat, 0, i + 1) = subpat;
621           RTX_FRAME_RELATED_P (subpat) = 1;
622         }
623       insn = emit_insn (pat);
624       RTX_FRAME_RELATED_P (insn) = 1;
625     }
626
627   for (dregno = REG_R0; ndregs != ndregs_consec; dregno++)
628     {
629       if (must_save_p (is_inthandler, dregno))
630         {
631           rtx insn = emit_move_insn (predec, gen_rtx_REG (word_mode, dregno));
632           RTX_FRAME_RELATED_P (insn) = 1;
633           ndregs--;
634         }
635     }
636   for (pregno = REG_P0; npregs != npregs_consec; pregno++)
637     {
638       if (must_save_p (is_inthandler, pregno))
639         {
640           rtx insn = emit_move_insn (predec, gen_rtx_REG (word_mode, pregno));
641           RTX_FRAME_RELATED_P (insn) = 1;
642           npregs--;
643         }
644     }
645   for (i = REG_P7 + 1; i < REG_CC; i++)
646     if (saveall 
647         || (is_inthandler
648             && (df_regs_ever_live_p (i)
649                 || (!leaf_function_p () && call_used_regs[i]))))
650       {
651         rtx insn;
652         if (i == REG_A0 || i == REG_A1)
653           insn = emit_move_insn (gen_rtx_MEM (PDImode, predec1),
654                                  gen_rtx_REG (PDImode, i));
655         else
656           insn = emit_move_insn (predec, gen_rtx_REG (SImode, i));
657         RTX_FRAME_RELATED_P (insn) = 1;
658       }
659 }
660
661 /* Emit code to restore registers in the epilogue.  SAVEALL is nonzero if we
662    must save all registers; this is used for interrupt handlers.
663    SPREG contains (reg:SI REG_SP).  IS_INTHANDLER is true if we're doing
664    this for an interrupt (or exception) handler.  */
665
666 static void
667 expand_epilogue_reg_restore (rtx spreg, bool saveall, bool is_inthandler)
668 {
669   rtx postinc1 = gen_rtx_POST_INC (SImode, spreg);
670   rtx postinc = gen_rtx_MEM (SImode, postinc1);
671
672   int ndregs = saveall ? 8 : n_dregs_to_save (is_inthandler, false);
673   int npregs = saveall ? 6 : n_pregs_to_save (is_inthandler, false);
674   int ndregs_consec = saveall ? 8 : n_dregs_to_save (is_inthandler, true);
675   int npregs_consec = saveall ? 6 : n_pregs_to_save (is_inthandler, true);
676   int total_consec = ndregs_consec + npregs_consec;
677   int i, regno;
678   rtx insn;
679
680   /* A slightly crude technique to stop flow from trying to delete "dead"
681      insns.  */
682   MEM_VOLATILE_P (postinc) = 1;
683
684   for (i = REG_CC - 1; i > REG_P7; i--)
685     if (saveall
686         || (is_inthandler
687             && (df_regs_ever_live_p (i)
688                 || (!leaf_function_p () && call_used_regs[i]))))
689       {
690         if (i == REG_A0 || i == REG_A1)
691           {
692             rtx mem = gen_rtx_MEM (PDImode, postinc1);
693             MEM_VOLATILE_P (mem) = 1;
694             emit_move_insn (gen_rtx_REG (PDImode, i), mem);
695           }
696         else
697           emit_move_insn (gen_rtx_REG (SImode, i), postinc);
698       }
699
700   regno = REG_P5 - npregs_consec;
701   for (; npregs != npregs_consec; regno--)
702     {
703       if (must_save_p (is_inthandler, regno))
704         {
705           emit_move_insn (gen_rtx_REG (word_mode, regno), postinc);
706           npregs--;
707         }
708     }
709   regno = REG_R7 - ndregs_consec;
710   for (; ndregs != ndregs_consec; regno--)
711     {
712       if (must_save_p (is_inthandler, regno))
713         {
714           emit_move_insn (gen_rtx_REG (word_mode, regno), postinc);
715           ndregs--;
716         }
717     }
718
719   if (total_consec != 0)
720     {
721       rtx pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total_consec + 1));
722       XVECEXP (pat, 0, 0)
723         = gen_rtx_SET (VOIDmode, spreg,
724                        gen_rtx_PLUS (Pmode, spreg,
725                                      GEN_INT (total_consec * 4)));
726
727       if (npregs_consec > 0)
728         regno = REG_P5 + 1;
729       else
730         regno = REG_R7 + 1;
731
732       for (i = 0; i < total_consec; i++)
733         {
734           rtx addr = (i > 0
735                       ? gen_rtx_PLUS (Pmode, spreg, GEN_INT (i * 4))
736                       : spreg);
737           rtx memref = gen_rtx_MEM (word_mode, addr);
738
739           regno--;
740           XVECEXP (pat, 0, i + 1)
741             = gen_rtx_SET (VOIDmode, gen_rtx_REG (word_mode, regno), memref);
742
743           if (npregs_consec > 0)
744             {
745               if (--npregs_consec == 0)
746                 regno = REG_R7 + 1;
747             }
748         }
749
750       insn = emit_insn (pat);
751       RTX_FRAME_RELATED_P (insn) = 1;
752     }
753   if (saveall || is_inthandler)
754     {
755       for (regno = REG_LB1; regno >= REG_LT0; regno--)
756         if (! current_function_is_leaf
757             || cfun->machine->has_hardware_loops
758             || cfun->machine->has_loopreg_clobber
759             || (ENABLE_WA_05000257 && (regno == REG_LC0 || regno == REG_LC1)))
760           emit_move_insn (gen_rtx_REG (SImode, regno), postinc);
761
762       emit_move_insn (gen_rtx_REG (SImode, REG_ASTAT), postinc);
763     }
764 }
765
766 /* Perform any needed actions needed for a function that is receiving a
767    variable number of arguments.
768
769    CUM is as above.
770
771    MODE and TYPE are the mode and type of the current parameter.
772
773    PRETEND_SIZE is a variable that should be set to the amount of stack
774    that must be pushed by the prolog to pretend that our caller pushed
775    it.
776
777    Normally, this macro will push all remaining incoming registers on the
778    stack and set PRETEND_SIZE to the length of the registers pushed.  
779
780    Blackfin specific :
781    - VDSP C compiler manual (our ABI) says that a variable args function
782      should save the R0, R1 and R2 registers in the stack.
783    - The caller will always leave space on the stack for the
784      arguments that are passed in registers, so we dont have
785      to leave any extra space.
786    - now, the vastart pointer can access all arguments from the stack.  */
787
788 static void
789 setup_incoming_varargs (CUMULATIVE_ARGS *cum,
790                         enum machine_mode mode ATTRIBUTE_UNUSED,
791                         tree type ATTRIBUTE_UNUSED, int *pretend_size,
792                         int no_rtl)
793 {
794   rtx mem;
795   int i;
796
797   if (no_rtl)
798     return;
799
800   /* The move for named arguments will be generated automatically by the
801      compiler.  We need to generate the move rtx for the unnamed arguments
802      if they are in the first 3 words.  We assume at least 1 named argument
803      exists, so we never generate [ARGP] = R0 here.  */
804
805   for (i = cum->words + 1; i < max_arg_registers; i++)
806     {
807       mem = gen_rtx_MEM (Pmode,
808                          plus_constant (arg_pointer_rtx, (i * UNITS_PER_WORD)));
809       emit_move_insn (mem, gen_rtx_REG (Pmode, i));
810     }
811
812   *pretend_size = 0;
813 }
814
815 /* Value should be nonzero if functions must have frame pointers.
816    Zero means the frame pointer need not be set up (and parms may
817    be accessed via the stack pointer) in functions that seem suitable.  */
818
819 int
820 bfin_frame_pointer_required (void) 
821 {
822   e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
823
824   if (fkind != SUBROUTINE)
825     return 1;
826
827   /* We turn on -fomit-frame-pointer if -momit-leaf-frame-pointer is used,
828      so we have to override it for non-leaf functions.  */
829   if (TARGET_OMIT_LEAF_FRAME_POINTER && ! current_function_is_leaf)
830     return 1;
831
832   return 0;
833 }
834
835 /* Return the number of registers pushed during the prologue.  */
836
837 static int
838 n_regs_saved_by_prologue (void)
839 {
840   e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
841   bool is_inthandler = fkind != SUBROUTINE;
842   tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
843   bool all = (lookup_attribute ("saveall", attrs) != NULL_TREE
844               || (is_inthandler && !current_function_is_leaf));
845   int ndregs = all ? 8 : n_dregs_to_save (is_inthandler, false);
846   int npregs = all ? 6 : n_pregs_to_save (is_inthandler, false);
847   int n = ndregs + npregs;
848   int i;
849
850   if (all || stack_frame_needed_p ())
851     /* We use a LINK instruction in this case.  */
852     n += 2;
853   else
854     {
855       if (must_save_fp_p ())
856         n++;
857       if (! current_function_is_leaf)
858         n++;
859     }
860
861   if (fkind != SUBROUTINE || all)
862     {
863       /* Increment once for ASTAT.  */
864       n++;
865       if (! current_function_is_leaf
866           || cfun->machine->has_hardware_loops
867           || cfun->machine->has_loopreg_clobber)
868         {
869           n += 6;
870         }
871     }
872
873   if (fkind != SUBROUTINE)
874     {
875       /* RETE/X/N.  */
876       if (lookup_attribute ("nesting", attrs))
877         n++;
878     }
879
880   for (i = REG_P7 + 1; i < REG_CC; i++)
881     if (all
882         || (fkind != SUBROUTINE
883             && (df_regs_ever_live_p (i)
884                 || (!leaf_function_p () && call_used_regs[i]))))
885       n += i == REG_A0 || i == REG_A1 ? 2 : 1;
886
887   return n;
888 }
889
890 /* Return the offset between two registers, one to be eliminated, and the other
891    its replacement, at the start of a routine.  */
892
893 HOST_WIDE_INT
894 bfin_initial_elimination_offset (int from, int to)
895 {
896   HOST_WIDE_INT offset = 0;
897
898   if (from == ARG_POINTER_REGNUM)
899     offset = n_regs_saved_by_prologue () * 4;
900
901   if (to == STACK_POINTER_REGNUM)
902     {
903       if (crtl->outgoing_args_size >= FIXED_STACK_AREA)
904         offset += crtl->outgoing_args_size;
905       else if (crtl->outgoing_args_size)
906         offset += FIXED_STACK_AREA;
907
908       offset += get_frame_size ();
909     }
910
911   return offset;
912 }
913
914 /* Emit code to load a constant CONSTANT into register REG; setting
915    RTX_FRAME_RELATED_P on all insns we generate if RELATED is true.
916    Make sure that the insns we generate need not be split.  */
917
918 static void
919 frame_related_constant_load (rtx reg, HOST_WIDE_INT constant, bool related)
920 {
921   rtx insn;
922   rtx cst = GEN_INT (constant);
923
924   if (constant >= -32768 && constant < 65536)
925     insn = emit_move_insn (reg, cst);
926   else
927     {
928       /* We don't call split_load_immediate here, since dwarf2out.c can get
929          confused about some of the more clever sequences it can generate.  */
930       insn = emit_insn (gen_movsi_high (reg, cst));
931       if (related)
932         RTX_FRAME_RELATED_P (insn) = 1;
933       insn = emit_insn (gen_movsi_low (reg, reg, cst));
934     }
935   if (related)
936     RTX_FRAME_RELATED_P (insn) = 1;
937 }
938
939 /* Generate efficient code to add a value to a P register.
940    Set RTX_FRAME_RELATED_P on the generated insns if FRAME is nonzero.
941    EPILOGUE_P is zero if this function is called for prologue,
942    otherwise it's nonzero. And it's less than zero if this is for
943    sibcall epilogue.  */
944
945 static void
946 add_to_reg (rtx reg, HOST_WIDE_INT value, int frame, int epilogue_p)
947 {
948   if (value == 0)
949     return;
950
951   /* Choose whether to use a sequence using a temporary register, or
952      a sequence with multiple adds.  We can add a signed 7-bit value
953      in one instruction.  */
954   if (value > 120 || value < -120)
955     {
956       rtx tmpreg;
957       rtx tmpreg2;
958       rtx insn;
959
960       tmpreg2 = NULL_RTX;
961
962       /* For prologue or normal epilogue, P1 can be safely used
963          as the temporary register. For sibcall epilogue, we try to find
964          a call used P register, which will be restored in epilogue.
965          If we cannot find such a P register, we have to use one I register
966          to help us.  */
967
968       if (epilogue_p >= 0)
969         tmpreg = gen_rtx_REG (SImode, REG_P1);
970       else
971         {
972           int i;
973           for (i = REG_P0; i <= REG_P5; i++)
974             if ((df_regs_ever_live_p (i) && ! call_used_regs[i])
975                 || (!TARGET_FDPIC
976                     && i == PIC_OFFSET_TABLE_REGNUM
977                     && (crtl->uses_pic_offset_table
978                         || (TARGET_ID_SHARED_LIBRARY
979                             && ! current_function_is_leaf))))
980               break;
981           if (i <= REG_P5)
982             tmpreg = gen_rtx_REG (SImode, i);
983           else
984             {
985               tmpreg = gen_rtx_REG (SImode, REG_P1);
986               tmpreg2 = gen_rtx_REG (SImode, REG_I0);
987               emit_move_insn (tmpreg2, tmpreg);
988             }
989         }
990
991       if (frame)
992         frame_related_constant_load (tmpreg, value, TRUE);
993       else
994         insn = emit_move_insn (tmpreg, GEN_INT (value));
995
996       insn = emit_insn (gen_addsi3 (reg, reg, tmpreg));
997       if (frame)
998         RTX_FRAME_RELATED_P (insn) = 1;
999
1000       if (tmpreg2 != NULL_RTX)
1001         emit_move_insn (tmpreg, tmpreg2);
1002     }
1003   else
1004     do
1005       {
1006         int size = value;
1007         rtx insn;
1008
1009         if (size > 60)
1010           size = 60;
1011         else if (size < -60)
1012           /* We could use -62, but that would leave the stack unaligned, so
1013              it's no good.  */
1014           size = -60;
1015
1016         insn = emit_insn (gen_addsi3 (reg, reg, GEN_INT (size)));
1017         if (frame)
1018           RTX_FRAME_RELATED_P (insn) = 1;
1019         value -= size;
1020       }
1021     while (value != 0);
1022 }
1023
1024 /* Generate a LINK insn for a frame sized FRAME_SIZE.  If this constant
1025    is too large, generate a sequence of insns that has the same effect.
1026    SPREG contains (reg:SI REG_SP).  */
1027
1028 static void
1029 emit_link_insn (rtx spreg, HOST_WIDE_INT frame_size)
1030 {
1031   HOST_WIDE_INT link_size = frame_size;
1032   rtx insn;
1033   int i;
1034
1035   if (link_size > 262140)
1036     link_size = 262140;
1037
1038   /* Use a LINK insn with as big a constant as possible, then subtract
1039      any remaining size from the SP.  */
1040   insn = emit_insn (gen_link (GEN_INT (-8 - link_size)));
1041   RTX_FRAME_RELATED_P (insn) = 1;
1042
1043   for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
1044     {
1045       rtx set = XVECEXP (PATTERN (insn), 0, i);
1046       gcc_assert (GET_CODE (set) == SET);
1047       RTX_FRAME_RELATED_P (set) = 1;
1048     }
1049
1050   frame_size -= link_size;
1051
1052   if (frame_size > 0)
1053     {
1054       /* Must use a call-clobbered PREG that isn't the static chain.  */
1055       rtx tmpreg = gen_rtx_REG (Pmode, REG_P1);
1056
1057       frame_related_constant_load (tmpreg, -frame_size, TRUE);
1058       insn = emit_insn (gen_addsi3 (spreg, spreg, tmpreg));
1059       RTX_FRAME_RELATED_P (insn) = 1;
1060     }
1061 }
1062
1063 /* Return the number of bytes we must reserve for outgoing arguments
1064    in the current function's stack frame.  */
1065
1066 static HOST_WIDE_INT
1067 arg_area_size (void)
1068 {
1069   if (crtl->outgoing_args_size)
1070     {
1071       if (crtl->outgoing_args_size >= FIXED_STACK_AREA)
1072         return crtl->outgoing_args_size;
1073       else
1074         return FIXED_STACK_AREA;
1075     }
1076   return 0;
1077 }
1078
1079 /* Save RETS and FP, and allocate a stack frame.  ALL is true if the
1080    function must save all its registers (true only for certain interrupt
1081    handlers).  */
1082
1083 static void
1084 do_link (rtx spreg, HOST_WIDE_INT frame_size, bool all)
1085 {
1086   frame_size += arg_area_size ();
1087
1088   if (all || stack_frame_needed_p ()
1089       || (must_save_fp_p () && ! current_function_is_leaf))
1090     emit_link_insn (spreg, frame_size);
1091   else
1092     {
1093       if (! current_function_is_leaf)
1094         {
1095           rtx pat = gen_movsi (gen_rtx_MEM (Pmode,
1096                                             gen_rtx_PRE_DEC (Pmode, spreg)),
1097                                bfin_rets_rtx);
1098           rtx insn = emit_insn (pat);
1099           RTX_FRAME_RELATED_P (insn) = 1;
1100         }
1101       if (must_save_fp_p ())
1102         {
1103           rtx pat = gen_movsi (gen_rtx_MEM (Pmode,
1104                                             gen_rtx_PRE_DEC (Pmode, spreg)),
1105                                gen_rtx_REG (Pmode, REG_FP));
1106           rtx insn = emit_insn (pat);
1107           RTX_FRAME_RELATED_P (insn) = 1;
1108         }
1109       add_to_reg (spreg, -frame_size, 1, 0);
1110     }
1111 }
1112
1113 /* Like do_link, but used for epilogues to deallocate the stack frame.
1114    EPILOGUE_P is zero if this function is called for prologue,
1115    otherwise it's nonzero. And it's less than zero if this is for
1116    sibcall epilogue.  */
1117
1118 static void
1119 do_unlink (rtx spreg, HOST_WIDE_INT frame_size, bool all, int epilogue_p)
1120 {
1121   frame_size += arg_area_size ();
1122
1123   if (all || stack_frame_needed_p ())
1124     emit_insn (gen_unlink ());
1125   else 
1126     {
1127       rtx postinc = gen_rtx_MEM (Pmode, gen_rtx_POST_INC (Pmode, spreg));
1128
1129       add_to_reg (spreg, frame_size, 0, epilogue_p);
1130       if (must_save_fp_p ())
1131         {
1132           rtx fpreg = gen_rtx_REG (Pmode, REG_FP);
1133           emit_move_insn (fpreg, postinc);
1134           emit_use (fpreg);
1135         }
1136       if (! current_function_is_leaf)
1137         {
1138           emit_move_insn (bfin_rets_rtx, postinc);
1139           emit_use (bfin_rets_rtx);
1140         }
1141     }
1142 }
1143
1144 /* Generate a prologue suitable for a function of kind FKIND.  This is
1145    called for interrupt and exception handler prologues.
1146    SPREG contains (reg:SI REG_SP).  */
1147
1148 static void
1149 expand_interrupt_handler_prologue (rtx spreg, e_funkind fkind, bool all)
1150 {
1151   HOST_WIDE_INT frame_size = get_frame_size ();
1152   rtx predec1 = gen_rtx_PRE_DEC (SImode, spreg);
1153   rtx predec = gen_rtx_MEM (SImode, predec1);
1154   rtx insn;
1155   tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1156   tree kspisusp = lookup_attribute ("kspisusp", attrs);
1157
1158   if (kspisusp)
1159     {
1160       insn = emit_move_insn (spreg, gen_rtx_REG (Pmode, REG_USP));
1161       RTX_FRAME_RELATED_P (insn) = 1;
1162     }
1163
1164   /* We need space on the stack in case we need to save the argument
1165      registers.  */
1166   if (fkind == EXCPT_HANDLER)
1167     {
1168       insn = emit_insn (gen_addsi3 (spreg, spreg, GEN_INT (-12)));
1169       RTX_FRAME_RELATED_P (insn) = 1;
1170     }
1171
1172   /* If we're calling other functions, they won't save their call-clobbered
1173      registers, so we must save everything here.  */
1174   if (!current_function_is_leaf)
1175     all = true;
1176   expand_prologue_reg_save (spreg, all, true);
1177
1178   if (ENABLE_WA_05000283 || ENABLE_WA_05000315)
1179     {
1180       rtx chipid = GEN_INT (trunc_int_for_mode (0xFFC00014, SImode));
1181       rtx p5reg = gen_rtx_REG (Pmode, REG_P5);
1182       emit_insn (gen_movbi (bfin_cc_rtx, const1_rtx));
1183       emit_insn (gen_movsi_high (p5reg, chipid));
1184       emit_insn (gen_movsi_low (p5reg, p5reg, chipid));
1185       emit_insn (gen_dummy_load (p5reg, bfin_cc_rtx));
1186     }
1187   
1188   if (lookup_attribute ("nesting", attrs))
1189     {
1190       rtx srcreg = gen_rtx_REG (Pmode, (fkind == EXCPT_HANDLER ? REG_RETX
1191                                         : fkind == NMI_HANDLER ? REG_RETN
1192                                         : REG_RETI));
1193       insn = emit_move_insn (predec, srcreg);
1194       RTX_FRAME_RELATED_P (insn) = 1;
1195     }
1196
1197   do_link (spreg, frame_size, all);
1198
1199   if (fkind == EXCPT_HANDLER)
1200     {
1201       rtx r0reg = gen_rtx_REG (SImode, REG_R0);
1202       rtx r1reg = gen_rtx_REG (SImode, REG_R1);
1203       rtx r2reg = gen_rtx_REG (SImode, REG_R2);
1204       rtx insn;
1205
1206       insn = emit_move_insn (r0reg, gen_rtx_REG (SImode, REG_SEQSTAT));
1207       insn = emit_insn (gen_ashrsi3 (r0reg, r0reg, GEN_INT (26)));
1208       insn = emit_insn (gen_ashlsi3 (r0reg, r0reg, GEN_INT (26)));
1209       insn = emit_move_insn (r1reg, spreg);
1210       insn = emit_move_insn (r2reg, gen_rtx_REG (Pmode, REG_FP));
1211       insn = emit_insn (gen_addsi3 (r2reg, r2reg, GEN_INT (8)));
1212     }
1213 }
1214
1215 /* Generate an epilogue suitable for a function of kind FKIND.  This is
1216    called for interrupt and exception handler epilogues.
1217    SPREG contains (reg:SI REG_SP).  */
1218
1219 static void
1220 expand_interrupt_handler_epilogue (rtx spreg, e_funkind fkind, bool all)
1221 {
1222   tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1223   rtx postinc1 = gen_rtx_POST_INC (SImode, spreg);
1224   rtx postinc = gen_rtx_MEM (SImode, postinc1);
1225
1226   /* A slightly crude technique to stop flow from trying to delete "dead"
1227      insns.  */
1228   MEM_VOLATILE_P (postinc) = 1;
1229
1230   do_unlink (spreg, get_frame_size (), all, 1);
1231
1232   if (lookup_attribute ("nesting", attrs))
1233     {
1234       rtx srcreg = gen_rtx_REG (Pmode, (fkind == EXCPT_HANDLER ? REG_RETX
1235                                         : fkind == NMI_HANDLER ? REG_RETN
1236                                         : REG_RETI));
1237       emit_move_insn (srcreg, postinc);
1238     }
1239
1240   /* If we're calling other functions, they won't save their call-clobbered
1241      registers, so we must save (and restore) everything here.  */
1242   if (!current_function_is_leaf)
1243     all = true;
1244
1245   expand_epilogue_reg_restore (spreg, all, true);
1246
1247   /* Deallocate any space we left on the stack in case we needed to save the
1248      argument registers.  */
1249   if (fkind == EXCPT_HANDLER)
1250     emit_insn (gen_addsi3 (spreg, spreg, GEN_INT (12)));
1251
1252   emit_jump_insn (gen_return_internal (GEN_INT (fkind)));
1253 }
1254
1255 /* Used while emitting the prologue to generate code to load the correct value
1256    into the PIC register, which is passed in DEST.  */
1257
1258 static rtx
1259 bfin_load_pic_reg (rtx dest)
1260 {
1261   struct cgraph_local_info *i = NULL;
1262   rtx addr, insn;
1263  
1264   i = cgraph_local_info (current_function_decl);
1265  
1266   /* Functions local to the translation unit don't need to reload the
1267      pic reg, since the caller always passes a usable one.  */
1268   if (i && i->local)
1269     return pic_offset_table_rtx;
1270       
1271   if (bfin_lib_id_given)
1272     addr = plus_constant (pic_offset_table_rtx, -4 - bfin_library_id * 4);
1273   else
1274     addr = gen_rtx_PLUS (Pmode, pic_offset_table_rtx,
1275                          gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx),
1276                                          UNSPEC_LIBRARY_OFFSET));
1277   insn = emit_insn (gen_movsi (dest, gen_rtx_MEM (Pmode, addr)));
1278   return dest;
1279 }
1280
1281 /* Generate RTL for the prologue of the current function.  */
1282
1283 void
1284 bfin_expand_prologue (void)
1285 {
1286   HOST_WIDE_INT frame_size = get_frame_size ();
1287   rtx spreg = gen_rtx_REG (Pmode, REG_SP);
1288   e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
1289   rtx pic_reg_loaded = NULL_RTX;
1290   tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1291   bool all = lookup_attribute ("saveall", attrs) != NULL_TREE;
1292
1293   if (fkind != SUBROUTINE)
1294     {
1295       expand_interrupt_handler_prologue (spreg, fkind, all);
1296       return;
1297     }
1298
1299   if (crtl->limit_stack
1300       || (TARGET_STACK_CHECK_L1
1301           && !DECL_NO_LIMIT_STACK (current_function_decl)))
1302     {
1303       HOST_WIDE_INT offset
1304         = bfin_initial_elimination_offset (ARG_POINTER_REGNUM,
1305                                            STACK_POINTER_REGNUM);
1306       rtx lim = crtl->limit_stack ? stack_limit_rtx : NULL_RTX;
1307       rtx p2reg = gen_rtx_REG (Pmode, REG_P2);
1308
1309       if (!lim)
1310         {
1311           emit_move_insn (p2reg, gen_int_mode (0xFFB00000, SImode));
1312           emit_move_insn (p2reg, gen_rtx_MEM (Pmode, p2reg));
1313           lim = p2reg;
1314         }
1315       if (GET_CODE (lim) == SYMBOL_REF)
1316         {
1317           if (TARGET_ID_SHARED_LIBRARY)
1318             {
1319               rtx p1reg = gen_rtx_REG (Pmode, REG_P1);
1320               rtx val;
1321               pic_reg_loaded = bfin_load_pic_reg (p2reg);
1322               val = legitimize_pic_address (stack_limit_rtx, p1reg,
1323                                             pic_reg_loaded);
1324               emit_move_insn (p1reg, val);
1325               frame_related_constant_load (p2reg, offset, FALSE);
1326               emit_insn (gen_addsi3 (p2reg, p2reg, p1reg));
1327               lim = p2reg;
1328             }
1329           else
1330             {
1331               rtx limit = plus_constant (lim, offset);
1332               emit_move_insn (p2reg, limit);
1333               lim = p2reg;
1334             }
1335         }
1336       else
1337         {
1338           if (lim != p2reg)
1339             emit_move_insn (p2reg, lim);
1340           add_to_reg (p2reg, offset, 0, 0);
1341           lim = p2reg;
1342         }
1343       emit_insn (gen_compare_lt (bfin_cc_rtx, spreg, lim));
1344       emit_insn (gen_trapifcc ());
1345     }
1346   expand_prologue_reg_save (spreg, all, false);
1347
1348   do_link (spreg, frame_size, false);
1349
1350   if (TARGET_ID_SHARED_LIBRARY
1351       && !TARGET_SEP_DATA
1352       && (crtl->uses_pic_offset_table
1353           || !current_function_is_leaf))
1354     bfin_load_pic_reg (pic_offset_table_rtx);
1355 }
1356
1357 /* Generate RTL for the epilogue of the current function.  NEED_RETURN is zero
1358    if this is for a sibcall.  EH_RETURN is nonzero if we're expanding an
1359    eh_return pattern. SIBCALL_P is true if this is a sibcall epilogue,
1360    false otherwise.  */
1361
1362 void
1363 bfin_expand_epilogue (int need_return, int eh_return, bool sibcall_p)
1364 {
1365   rtx spreg = gen_rtx_REG (Pmode, REG_SP);
1366   e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
1367   int e = sibcall_p ? -1 : 1;
1368   tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1369   bool all = lookup_attribute ("saveall", attrs) != NULL_TREE;
1370
1371   if (fkind != SUBROUTINE)
1372     {
1373       expand_interrupt_handler_epilogue (spreg, fkind, all);
1374       return;
1375     }
1376
1377   do_unlink (spreg, get_frame_size (), false, e);
1378
1379   expand_epilogue_reg_restore (spreg, all, false);
1380
1381   /* Omit the return insn if this is for a sibcall.  */
1382   if (! need_return)
1383     return;
1384
1385   if (eh_return)
1386     emit_insn (gen_addsi3 (spreg, spreg, gen_rtx_REG (Pmode, REG_P2)));
1387
1388   emit_jump_insn (gen_return_internal (GEN_INT (SUBROUTINE)));
1389 }
1390 \f
1391 /* Return nonzero if register OLD_REG can be renamed to register NEW_REG.  */
1392
1393 int
1394 bfin_hard_regno_rename_ok (unsigned int old_reg ATTRIBUTE_UNUSED,
1395                            unsigned int new_reg)
1396 {
1397   /* Interrupt functions can only use registers that have already been
1398      saved by the prologue, even if they would normally be
1399      call-clobbered.  */
1400
1401   if (funkind (TREE_TYPE (current_function_decl)) != SUBROUTINE
1402       && !df_regs_ever_live_p (new_reg))
1403     return 0;
1404
1405   return 1;
1406 }
1407
1408 /* Return the value of the return address for the frame COUNT steps up
1409    from the current frame, after the prologue.
1410    We punt for everything but the current frame by returning const0_rtx.  */
1411
1412 rtx
1413 bfin_return_addr_rtx (int count)
1414 {
1415   if (count != 0)
1416     return const0_rtx;
1417
1418   return get_hard_reg_initial_val (Pmode, REG_RETS);
1419 }
1420
1421 /* Try machine-dependent ways of modifying an illegitimate address X
1422    to be legitimate.  If we find one, return the new, valid address,
1423    otherwise return NULL_RTX.
1424
1425    OLDX is the address as it was before break_out_memory_refs was called.
1426    In some cases it is useful to look at this to decide what needs to be done.
1427
1428    MODE is the mode of the memory reference.  */
1429
1430 rtx
1431 legitimize_address (rtx x ATTRIBUTE_UNUSED, rtx oldx ATTRIBUTE_UNUSED,
1432                     enum machine_mode mode ATTRIBUTE_UNUSED)
1433 {
1434   return NULL_RTX;
1435 }
1436
1437 static rtx
1438 bfin_delegitimize_address (rtx orig_x)
1439 {
1440   rtx x = orig_x;
1441
1442   if (GET_CODE (x) != MEM)
1443     return orig_x;
1444
1445   x = XEXP (x, 0);
1446   if (GET_CODE (x) == PLUS
1447       && GET_CODE (XEXP (x, 1)) == UNSPEC
1448       && XINT (XEXP (x, 1), 1) == UNSPEC_MOVE_PIC
1449       && GET_CODE (XEXP (x, 0)) == REG
1450       && REGNO (XEXP (x, 0)) == PIC_OFFSET_TABLE_REGNUM)
1451     return XVECEXP (XEXP (x, 1), 0, 0);
1452
1453   return orig_x;
1454 }
1455
1456 /* This predicate is used to compute the length of a load/store insn.
1457    OP is a MEM rtx, we return nonzero if its addressing mode requires a
1458    32-bit instruction.  */
1459
1460 int
1461 effective_address_32bit_p (rtx op, enum machine_mode mode) 
1462 {
1463   HOST_WIDE_INT offset;
1464
1465   mode = GET_MODE (op);
1466   op = XEXP (op, 0);
1467
1468   if (GET_CODE (op) != PLUS)
1469     {
1470       gcc_assert (REG_P (op) || GET_CODE (op) == POST_INC
1471                   || GET_CODE (op) == PRE_DEC || GET_CODE (op) == POST_DEC);
1472       return 0;
1473     }
1474
1475   if (GET_CODE (XEXP (op, 1)) == UNSPEC)
1476     return 1;
1477
1478   offset = INTVAL (XEXP (op, 1));
1479
1480   /* All byte loads use a 16-bit offset.  */
1481   if (GET_MODE_SIZE (mode) == 1)
1482     return 1;
1483
1484   if (GET_MODE_SIZE (mode) == 4)
1485     {
1486       /* Frame pointer relative loads can use a negative offset, all others
1487          are restricted to a small positive one.  */
1488       if (XEXP (op, 0) == frame_pointer_rtx)
1489         return offset < -128 || offset > 60;
1490       return offset < 0 || offset > 60;
1491     }
1492
1493   /* Must be HImode now.  */
1494   return offset < 0 || offset > 30;
1495 }
1496
1497 /* Returns true if X is a memory reference using an I register.  */
1498 bool
1499 bfin_dsp_memref_p (rtx x)
1500 {
1501   if (! MEM_P (x))
1502     return false;
1503   x = XEXP (x, 0);
1504   if (GET_CODE (x) == POST_INC || GET_CODE (x) == PRE_INC
1505       || GET_CODE (x) == POST_DEC || GET_CODE (x) == PRE_DEC)
1506     x = XEXP (x, 0);
1507   return IREG_P (x);
1508 }
1509
1510 /* Return cost of the memory address ADDR.
1511    All addressing modes are equally cheap on the Blackfin.  */
1512
1513 static int
1514 bfin_address_cost (rtx addr ATTRIBUTE_UNUSED, bool speed ATTRIBUTE_UNUSED)
1515 {
1516   return 1;
1517 }
1518
1519 /* Subroutine of print_operand; used to print a memory reference X to FILE.  */
1520
1521 void
1522 print_address_operand (FILE *file, rtx x)
1523 {
1524   switch (GET_CODE (x))
1525     {
1526     case PLUS:
1527       output_address (XEXP (x, 0));
1528       fprintf (file, "+");
1529       output_address (XEXP (x, 1));
1530       break;
1531
1532     case PRE_DEC:
1533       fprintf (file, "--");
1534       output_address (XEXP (x, 0));    
1535       break;
1536     case POST_INC:
1537       output_address (XEXP (x, 0));
1538       fprintf (file, "++");
1539       break;
1540     case POST_DEC:
1541       output_address (XEXP (x, 0));
1542       fprintf (file, "--");
1543       break;
1544
1545     default:
1546       gcc_assert (GET_CODE (x) != MEM);
1547       print_operand (file, x, 0);
1548       break;
1549     }
1550 }
1551
1552 /* Adding intp DImode support by Tony
1553  * -- Q: (low  word)
1554  * -- R: (high word)
1555  */
1556
1557 void
1558 print_operand (FILE *file, rtx x, char code)
1559 {
1560   enum machine_mode mode;
1561
1562   if (code == '!')
1563     {
1564       if (GET_MODE (current_output_insn) == SImode)
1565         fprintf (file, " ||");
1566       else
1567         fprintf (file, ";");
1568       return;
1569     }
1570
1571   mode = GET_MODE (x);
1572
1573   switch (code)
1574     {
1575     case 'j':
1576       switch (GET_CODE (x))
1577         {
1578         case EQ:
1579           fprintf (file, "e");
1580           break;
1581         case NE:
1582           fprintf (file, "ne");
1583           break;
1584         case GT:
1585           fprintf (file, "g");
1586           break;
1587         case LT:
1588           fprintf (file, "l");
1589           break;
1590         case GE:
1591           fprintf (file, "ge");
1592           break;
1593         case LE:
1594           fprintf (file, "le");
1595           break;
1596         case GTU:
1597           fprintf (file, "g");
1598           break;
1599         case LTU:
1600           fprintf (file, "l");
1601           break;
1602         case GEU:
1603           fprintf (file, "ge");
1604           break;
1605         case LEU:
1606           fprintf (file, "le");
1607           break;
1608         default:
1609           output_operand_lossage ("invalid %%j value");
1610         }
1611       break;
1612     
1613     case 'J':                                    /* reverse logic */
1614       switch (GET_CODE(x))
1615         {
1616         case EQ:
1617           fprintf (file, "ne");
1618           break;
1619         case NE:
1620           fprintf (file, "e");
1621           break;
1622         case GT:
1623           fprintf (file, "le");
1624           break;
1625         case LT:
1626           fprintf (file, "ge");
1627           break;
1628         case GE:
1629           fprintf (file, "l");
1630           break;
1631         case LE:
1632           fprintf (file, "g");
1633           break;
1634         case GTU:
1635           fprintf (file, "le");
1636           break;
1637         case LTU:
1638           fprintf (file, "ge");
1639           break;
1640         case GEU:
1641           fprintf (file, "l");
1642           break;
1643         case LEU:
1644           fprintf (file, "g");
1645           break;
1646         default:
1647           output_operand_lossage ("invalid %%J value");
1648         }
1649       break;
1650
1651     default:
1652       switch (GET_CODE (x))
1653         {
1654         case REG:
1655           if (code == 'h')
1656             {
1657               if (REGNO (x) < 32)
1658                 fprintf (file, "%s", short_reg_names[REGNO (x)]);
1659               else
1660                 output_operand_lossage ("invalid operand for code '%c'", code);
1661             }
1662           else if (code == 'd')
1663             {
1664               if (REGNO (x) < 32)
1665                 fprintf (file, "%s", high_reg_names[REGNO (x)]);
1666               else
1667                 output_operand_lossage ("invalid operand for code '%c'", code);
1668             }
1669           else if (code == 'w')
1670             {
1671               if (REGNO (x) == REG_A0 || REGNO (x) == REG_A1)
1672                 fprintf (file, "%s.w", reg_names[REGNO (x)]);
1673               else
1674                 output_operand_lossage ("invalid operand for code '%c'", code);
1675             }
1676           else if (code == 'x')
1677             {
1678               if (REGNO (x) == REG_A0 || REGNO (x) == REG_A1)
1679                 fprintf (file, "%s.x", reg_names[REGNO (x)]);
1680               else
1681                 output_operand_lossage ("invalid operand for code '%c'", code);
1682             }
1683           else if (code == 'v')
1684             {
1685               if (REGNO (x) == REG_A0)
1686                 fprintf (file, "AV0");
1687               else if (REGNO (x) == REG_A1)
1688                 fprintf (file, "AV1");
1689               else
1690                 output_operand_lossage ("invalid operand for code '%c'", code);
1691             }
1692           else if (code == 'D')
1693             {
1694               if (D_REGNO_P (REGNO (x)))
1695                 fprintf (file, "%s", dregs_pair_names[REGNO (x)]);
1696               else
1697                 output_operand_lossage ("invalid operand for code '%c'", code);
1698             }
1699           else if (code == 'H')
1700             {
1701               if ((mode == DImode || mode == DFmode) && REG_P (x))
1702                 fprintf (file, "%s", reg_names[REGNO (x) + 1]);
1703               else
1704                 output_operand_lossage ("invalid operand for code '%c'", code);
1705             }
1706           else if (code == 'T')
1707             {
1708               if (D_REGNO_P (REGNO (x)))
1709                 fprintf (file, "%s", byte_reg_names[REGNO (x)]);
1710               else
1711                 output_operand_lossage ("invalid operand for code '%c'", code);
1712             }
1713           else 
1714             fprintf (file, "%s", reg_names[REGNO (x)]);
1715           break;
1716
1717         case MEM:
1718           fputc ('[', file);
1719           x = XEXP (x,0);
1720           print_address_operand (file, x);
1721           fputc (']', file);
1722           break;
1723
1724         case CONST_INT:
1725           if (code == 'M')
1726             {
1727               switch (INTVAL (x))
1728                 {
1729                 case MACFLAG_NONE:
1730                   break;
1731                 case MACFLAG_FU:
1732                   fputs ("(FU)", file);
1733                   break;
1734                 case MACFLAG_T:
1735                   fputs ("(T)", file);
1736                   break;
1737                 case MACFLAG_TFU:
1738                   fputs ("(TFU)", file);
1739                   break;
1740                 case MACFLAG_W32:
1741                   fputs ("(W32)", file);
1742                   break;
1743                 case MACFLAG_IS:
1744                   fputs ("(IS)", file);
1745                   break;
1746                 case MACFLAG_IU:
1747                   fputs ("(IU)", file);
1748                   break;
1749                 case MACFLAG_IH:
1750                   fputs ("(IH)", file);
1751                   break;
1752                 case MACFLAG_M:
1753                   fputs ("(M)", file);
1754                   break;
1755                 case MACFLAG_IS_M:
1756                   fputs ("(IS,M)", file);
1757                   break;
1758                 case MACFLAG_ISS2:
1759                   fputs ("(ISS2)", file);
1760                   break;
1761                 case MACFLAG_S2RND:
1762                   fputs ("(S2RND)", file);
1763                   break;
1764                 default:
1765                   gcc_unreachable ();
1766                 }
1767               break;
1768             }
1769           else if (code == 'b')
1770             {
1771               if (INTVAL (x) == 0)
1772                 fputs ("+=", file);
1773               else if (INTVAL (x) == 1)
1774                 fputs ("-=", file);
1775               else
1776                 gcc_unreachable ();
1777               break;
1778             }
1779           /* Moves to half registers with d or h modifiers always use unsigned
1780              constants.  */
1781           else if (code == 'd')
1782             x = GEN_INT ((INTVAL (x) >> 16) & 0xffff);
1783           else if (code == 'h')
1784             x = GEN_INT (INTVAL (x) & 0xffff);
1785           else if (code == 'N')
1786             x = GEN_INT (-INTVAL (x));
1787           else if (code == 'X')
1788             x = GEN_INT (exact_log2 (0xffffffff & INTVAL (x)));
1789           else if (code == 'Y')
1790             x = GEN_INT (exact_log2 (0xffffffff & ~INTVAL (x)));
1791           else if (code == 'Z')
1792             /* Used for LINK insns.  */
1793             x = GEN_INT (-8 - INTVAL (x));
1794
1795           /* fall through */
1796
1797         case SYMBOL_REF:
1798           output_addr_const (file, x);
1799           break;
1800
1801         case CONST_DOUBLE:
1802           output_operand_lossage ("invalid const_double operand");
1803           break;
1804
1805         case UNSPEC:
1806           switch (XINT (x, 1))
1807             {
1808             case UNSPEC_MOVE_PIC:
1809               output_addr_const (file, XVECEXP (x, 0, 0));
1810               fprintf (file, "@GOT");
1811               break;
1812
1813             case UNSPEC_MOVE_FDPIC:
1814               output_addr_const (file, XVECEXP (x, 0, 0));
1815               fprintf (file, "@GOT17M4");
1816               break;
1817
1818             case UNSPEC_FUNCDESC_GOT17M4:
1819               output_addr_const (file, XVECEXP (x, 0, 0));
1820               fprintf (file, "@FUNCDESC_GOT17M4");
1821               break;
1822
1823             case UNSPEC_LIBRARY_OFFSET:
1824               fprintf (file, "_current_shared_library_p5_offset_");
1825               break;
1826
1827             default:
1828               gcc_unreachable ();
1829             }
1830           break;
1831
1832         default:
1833           output_addr_const (file, x);
1834         }
1835     }
1836 }
1837 \f
1838 /* Argument support functions.  */
1839
1840 /* Initialize a variable CUM of type CUMULATIVE_ARGS
1841    for a call to a function whose data type is FNTYPE.
1842    For a library call, FNTYPE is 0.  
1843    VDSP C Compiler manual, our ABI says that
1844    first 3 words of arguments will use R0, R1 and R2.
1845 */
1846
1847 void
1848 init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype,
1849                       rtx libname ATTRIBUTE_UNUSED)
1850 {
1851   static CUMULATIVE_ARGS zero_cum;
1852
1853   *cum = zero_cum;
1854
1855   /* Set up the number of registers to use for passing arguments.  */
1856
1857   cum->nregs = max_arg_registers;
1858   cum->arg_regs = arg_regs;
1859
1860   cum->call_cookie = CALL_NORMAL;
1861   /* Check for a longcall attribute.  */
1862   if (fntype && lookup_attribute ("shortcall", TYPE_ATTRIBUTES (fntype)))
1863     cum->call_cookie |= CALL_SHORT;
1864   else if (fntype && lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype)))
1865     cum->call_cookie |= CALL_LONG;
1866
1867   return;
1868 }
1869
1870 /* Update the data in CUM to advance over an argument
1871    of mode MODE and data type TYPE.
1872    (TYPE is null for libcalls where that information may not be available.)  */
1873
1874 void
1875 function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
1876                       int named ATTRIBUTE_UNUSED)
1877 {
1878   int count, bytes, words;
1879
1880   bytes = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
1881   words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
1882
1883   cum->words += words;
1884   cum->nregs -= words;
1885
1886   if (cum->nregs <= 0)
1887     {
1888       cum->nregs = 0;
1889       cum->arg_regs = NULL;
1890     }
1891   else
1892     {
1893       for (count = 1; count <= words; count++)
1894         cum->arg_regs++;
1895     }
1896
1897   return;
1898 }
1899
1900 /* Define where to put the arguments to a function.
1901    Value is zero to push the argument on the stack,
1902    or a hard register in which to store the argument.
1903
1904    MODE is the argument's machine mode.
1905    TYPE is the data type of the argument (as a tree).
1906     This is null for libcalls where that information may
1907     not be available.
1908    CUM is a variable of type CUMULATIVE_ARGS which gives info about
1909     the preceding args and about the function being called.
1910    NAMED is nonzero if this argument is a named parameter
1911     (otherwise it is an extra parameter matching an ellipsis).  */
1912
1913 struct rtx_def *
1914 function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
1915               int named ATTRIBUTE_UNUSED)
1916 {
1917   int bytes
1918     = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
1919
1920   if (mode == VOIDmode)
1921     /* Compute operand 2 of the call insn.  */
1922     return GEN_INT (cum->call_cookie);
1923
1924   if (bytes == -1)
1925     return NULL_RTX;
1926
1927   if (cum->nregs)
1928     return gen_rtx_REG (mode, *(cum->arg_regs));
1929
1930   return NULL_RTX;
1931 }
1932
1933 /* For an arg passed partly in registers and partly in memory,
1934    this is the number of bytes passed in registers.
1935    For args passed entirely in registers or entirely in memory, zero.
1936
1937    Refer VDSP C Compiler manual, our ABI.
1938    First 3 words are in registers. So, if an argument is larger
1939    than the registers available, it will span the register and
1940    stack.   */
1941
1942 static int
1943 bfin_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode,
1944                         tree type ATTRIBUTE_UNUSED,
1945                         bool named ATTRIBUTE_UNUSED)
1946 {
1947   int bytes
1948     = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
1949   int bytes_left = cum->nregs * UNITS_PER_WORD;
1950   
1951   if (bytes == -1)
1952     return 0;
1953
1954   if (bytes_left == 0)
1955     return 0;
1956   if (bytes > bytes_left)
1957     return bytes_left;
1958   return 0;
1959 }
1960
1961 /* Variable sized types are passed by reference.  */
1962
1963 static bool
1964 bfin_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
1965                         enum machine_mode mode ATTRIBUTE_UNUSED,
1966                         const_tree type, bool named ATTRIBUTE_UNUSED)
1967 {
1968   return type && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST;
1969 }
1970
1971 /* Decide whether a type should be returned in memory (true)
1972    or in a register (false).  This is called by the macro
1973    TARGET_RETURN_IN_MEMORY.  */
1974
1975 static bool
1976 bfin_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
1977 {
1978   int size = int_size_in_bytes (type);
1979   return size > 2 * UNITS_PER_WORD || size == -1;
1980 }
1981
1982 /* Register in which address to store a structure value
1983    is passed to a function.  */
1984 static rtx
1985 bfin_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
1986                       int incoming ATTRIBUTE_UNUSED)
1987 {
1988   return gen_rtx_REG (Pmode, REG_P0);
1989 }
1990
1991 /* Return true when register may be used to pass function parameters.  */
1992
1993 bool 
1994 function_arg_regno_p (int n)
1995 {
1996   int i;
1997   for (i = 0; arg_regs[i] != -1; i++)
1998     if (n == arg_regs[i])
1999       return true;
2000   return false;
2001 }
2002
2003 /* Returns 1 if OP contains a symbol reference */
2004
2005 int
2006 symbolic_reference_mentioned_p (rtx op)
2007 {
2008   register const char *fmt;
2009   register int i;
2010
2011   if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF)
2012     return 1;
2013
2014   fmt = GET_RTX_FORMAT (GET_CODE (op));
2015   for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
2016     {
2017       if (fmt[i] == 'E')
2018         {
2019           register int j;
2020
2021           for (j = XVECLEN (op, i) - 1; j >= 0; j--)
2022             if (symbolic_reference_mentioned_p (XVECEXP (op, i, j)))
2023               return 1;
2024         }
2025
2026       else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i)))
2027         return 1;
2028     }
2029
2030   return 0;
2031 }
2032
2033 /* Decide whether we can make a sibling call to a function.  DECL is the
2034    declaration of the function being targeted by the call and EXP is the
2035    CALL_EXPR representing the call.  */
2036
2037 static bool
2038 bfin_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED,
2039                               tree exp ATTRIBUTE_UNUSED)
2040 {
2041   struct cgraph_local_info *this_func, *called_func;
2042   e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
2043   if (fkind != SUBROUTINE)
2044     return false;
2045   if (!TARGET_ID_SHARED_LIBRARY || TARGET_SEP_DATA)
2046     return true;
2047
2048   /* When compiling for ID shared libraries, can't sibcall a local function
2049      from a non-local function, because the local function thinks it does
2050      not need to reload P5 in the prologue, but the sibcall wil pop P5 in the
2051      sibcall epilogue, and we end up with the wrong value in P5.  */
2052
2053   if (!decl)
2054     /* Not enough information.  */
2055     return false;
2056  
2057   this_func = cgraph_local_info (current_function_decl);
2058   called_func = cgraph_local_info (decl);
2059   return !called_func->local || this_func->local;
2060 }
2061 \f
2062 /* Emit RTL insns to initialize the variable parts of a trampoline at
2063    TRAMP. FNADDR is an RTX for the address of the function's pure
2064    code.  CXT is an RTX for the static chain value for the function.  */
2065
2066 void
2067 initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt)
2068 {
2069   rtx t1 = copy_to_reg (fnaddr);
2070   rtx t2 = copy_to_reg (cxt);
2071   rtx addr;
2072   int i = 0;
2073
2074   if (TARGET_FDPIC)
2075     {
2076       rtx a = memory_address (Pmode, plus_constant (tramp, 8));
2077       addr = memory_address (Pmode, tramp);
2078       emit_move_insn (gen_rtx_MEM (SImode, addr), a);
2079       i = 8;
2080     }
2081
2082   addr = memory_address (Pmode, plus_constant (tramp, i + 2));
2083   emit_move_insn (gen_rtx_MEM (HImode, addr), gen_lowpart (HImode, t1));
2084   emit_insn (gen_ashrsi3 (t1, t1, GEN_INT (16)));
2085   addr = memory_address (Pmode, plus_constant (tramp, i + 6));
2086   emit_move_insn (gen_rtx_MEM (HImode, addr), gen_lowpart (HImode, t1));
2087
2088   addr = memory_address (Pmode, plus_constant (tramp, i + 10));
2089   emit_move_insn (gen_rtx_MEM (HImode, addr), gen_lowpart (HImode, t2));
2090   emit_insn (gen_ashrsi3 (t2, t2, GEN_INT (16)));
2091   addr = memory_address (Pmode, plus_constant (tramp, i + 14));
2092   emit_move_insn (gen_rtx_MEM (HImode, addr), gen_lowpart (HImode, t2));
2093 }
2094
2095 /* Emit insns to move operands[1] into operands[0].  */
2096
2097 void
2098 emit_pic_move (rtx *operands, enum machine_mode mode ATTRIBUTE_UNUSED)
2099 {
2100   rtx temp = reload_in_progress ? operands[0] : gen_reg_rtx (Pmode);
2101
2102   gcc_assert (!TARGET_FDPIC || !(reload_in_progress || reload_completed));
2103   if (GET_CODE (operands[0]) == MEM && SYMBOLIC_CONST (operands[1]))
2104     operands[1] = force_reg (SImode, operands[1]);
2105   else
2106     operands[1] = legitimize_pic_address (operands[1], temp,
2107                                           TARGET_FDPIC ? OUR_FDPIC_REG
2108                                           : pic_offset_table_rtx);
2109 }
2110
2111 /* Expand a move operation in mode MODE.  The operands are in OPERANDS.
2112    Returns true if no further code must be generated, false if the caller
2113    should generate an insn to move OPERANDS[1] to OPERANDS[0].  */
2114
2115 bool
2116 expand_move (rtx *operands, enum machine_mode mode)
2117 {
2118   rtx op = operands[1];
2119   if ((TARGET_ID_SHARED_LIBRARY || TARGET_FDPIC)
2120       && SYMBOLIC_CONST (op))
2121     emit_pic_move (operands, mode);
2122   else if (mode == SImode && GET_CODE (op) == CONST
2123            && GET_CODE (XEXP (op, 0)) == PLUS
2124            && GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF
2125            && !bfin_legitimate_constant_p (op))
2126     {
2127       rtx dest = operands[0];
2128       rtx op0, op1;
2129       gcc_assert (!reload_in_progress && !reload_completed);
2130       op = XEXP (op, 0);
2131       op0 = force_reg (mode, XEXP (op, 0));
2132       op1 = XEXP (op, 1);
2133       if (!insn_data[CODE_FOR_addsi3].operand[2].predicate (op1, mode))
2134         op1 = force_reg (mode, op1);
2135       if (GET_CODE (dest) == MEM)
2136         dest = gen_reg_rtx (mode);
2137       emit_insn (gen_addsi3 (dest, op0, op1));
2138       if (dest == operands[0])
2139         return true;
2140       operands[1] = dest;
2141     }
2142   /* Don't generate memory->memory or constant->memory moves, go through a
2143      register */
2144   else if ((reload_in_progress | reload_completed) == 0
2145            && GET_CODE (operands[0]) == MEM
2146            && GET_CODE (operands[1]) != REG)
2147     operands[1] = force_reg (mode, operands[1]);
2148   return false;
2149 }
2150 \f
2151 /* Split one or more DImode RTL references into pairs of SImode
2152    references.  The RTL can be REG, offsettable MEM, integer constant, or
2153    CONST_DOUBLE.  "operands" is a pointer to an array of DImode RTL to
2154    split and "num" is its length.  lo_half and hi_half are output arrays
2155    that parallel "operands".  */
2156
2157 void
2158 split_di (rtx operands[], int num, rtx lo_half[], rtx hi_half[])
2159 {
2160   while (num--)
2161     {
2162       rtx op = operands[num];
2163
2164       /* simplify_subreg refuse to split volatile memory addresses,
2165          but we still have to handle it.  */
2166       if (GET_CODE (op) == MEM)
2167         {
2168           lo_half[num] = adjust_address (op, SImode, 0);
2169           hi_half[num] = adjust_address (op, SImode, 4);
2170         }
2171       else
2172         {
2173           lo_half[num] = simplify_gen_subreg (SImode, op,
2174                                               GET_MODE (op) == VOIDmode
2175                                               ? DImode : GET_MODE (op), 0);
2176           hi_half[num] = simplify_gen_subreg (SImode, op,
2177                                               GET_MODE (op) == VOIDmode
2178                                               ? DImode : GET_MODE (op), 4);
2179         }
2180     }
2181 }
2182 \f
2183 bool
2184 bfin_longcall_p (rtx op, int call_cookie)
2185 {
2186   gcc_assert (GET_CODE (op) == SYMBOL_REF);
2187   if (call_cookie & CALL_SHORT)
2188     return 0;
2189   if (call_cookie & CALL_LONG)
2190     return 1;
2191   if (TARGET_LONG_CALLS)
2192     return 1;
2193   return 0;
2194 }
2195
2196 /* Expand a call instruction.  FNADDR is the call target, RETVAL the return value.
2197    COOKIE is a CONST_INT holding the call_cookie prepared init_cumulative_args.
2198    SIBCALL is nonzero if this is a sibling call.  */
2199
2200 void
2201 bfin_expand_call (rtx retval, rtx fnaddr, rtx callarg1, rtx cookie, int sibcall)
2202 {
2203   rtx use = NULL, call;
2204   rtx callee = XEXP (fnaddr, 0);
2205   int nelts = 2 + !!sibcall;
2206   rtx pat;
2207   rtx picreg = get_hard_reg_initial_val (SImode, FDPIC_REGNO);
2208   int n;
2209
2210   /* In an untyped call, we can get NULL for operand 2.  */
2211   if (cookie == NULL_RTX)
2212     cookie = const0_rtx;
2213
2214   /* Static functions and indirect calls don't need the pic register.  */
2215   if (!TARGET_FDPIC && flag_pic
2216       && GET_CODE (callee) == SYMBOL_REF
2217       && !SYMBOL_REF_LOCAL_P (callee))
2218     use_reg (&use, pic_offset_table_rtx);
2219
2220   if (TARGET_FDPIC)
2221     {
2222       int caller_has_l1_text, callee_has_l1_text;
2223
2224       caller_has_l1_text = callee_has_l1_text = 0;
2225
2226       if (lookup_attribute ("l1_text",
2227                             DECL_ATTRIBUTES (cfun->decl)) != NULL_TREE)
2228         caller_has_l1_text = 1;
2229
2230       if (GET_CODE (callee) == SYMBOL_REF
2231           && SYMBOL_REF_DECL (callee) && DECL_P (SYMBOL_REF_DECL (callee))
2232           && lookup_attribute
2233                ("l1_text",
2234                 DECL_ATTRIBUTES (SYMBOL_REF_DECL (callee))) != NULL_TREE)
2235         callee_has_l1_text = 1;
2236
2237       if (GET_CODE (callee) != SYMBOL_REF
2238           || bfin_longcall_p (callee, INTVAL (cookie))
2239           || (GET_CODE (callee) == SYMBOL_REF
2240               && !SYMBOL_REF_LOCAL_P (callee)
2241               && TARGET_INLINE_PLT)
2242           || caller_has_l1_text != callee_has_l1_text
2243           || (caller_has_l1_text && callee_has_l1_text
2244               && (GET_CODE (callee) != SYMBOL_REF
2245                   || !SYMBOL_REF_LOCAL_P (callee))))
2246         {
2247           rtx addr = callee;
2248           if (! address_operand (addr, Pmode))
2249             addr = force_reg (Pmode, addr);
2250
2251           fnaddr = gen_reg_rtx (SImode);
2252           emit_insn (gen_load_funcdescsi (fnaddr, addr));
2253           fnaddr = gen_rtx_MEM (Pmode, fnaddr);
2254
2255           picreg = gen_reg_rtx (SImode);
2256           emit_insn (gen_load_funcdescsi (picreg,
2257                                           plus_constant (addr, 4)));
2258         }
2259
2260       nelts++;
2261     }
2262   else if ((!register_no_elim_operand (callee, Pmode)
2263             && GET_CODE (callee) != SYMBOL_REF)
2264            || (GET_CODE (callee) == SYMBOL_REF
2265                && ((TARGET_ID_SHARED_LIBRARY && !TARGET_LEAF_ID_SHARED_LIBRARY)
2266                    || bfin_longcall_p (callee, INTVAL (cookie)))))
2267     {
2268       callee = copy_to_mode_reg (Pmode, callee);
2269       fnaddr = gen_rtx_MEM (Pmode, callee);
2270     }
2271   call = gen_rtx_CALL (VOIDmode, fnaddr, callarg1);
2272
2273   if (retval)
2274     call = gen_rtx_SET (VOIDmode, retval, call);
2275
2276   pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (nelts));
2277   n = 0;
2278   XVECEXP (pat, 0, n++) = call;
2279   if (TARGET_FDPIC)
2280     XVECEXP (pat, 0, n++) = gen_rtx_USE (VOIDmode, picreg);
2281   XVECEXP (pat, 0, n++) = gen_rtx_USE (VOIDmode, cookie);
2282   if (sibcall)
2283     XVECEXP (pat, 0, n++) = gen_rtx_RETURN (VOIDmode);
2284   call = emit_call_insn (pat);
2285   if (use)
2286     CALL_INSN_FUNCTION_USAGE (call) = use;
2287 }
2288 \f
2289 /* Return 1 if hard register REGNO can hold a value of machine-mode MODE.  */
2290
2291 int
2292 hard_regno_mode_ok (int regno, enum machine_mode mode)
2293 {
2294   /* Allow only dregs to store value of mode HI or QI */
2295   enum reg_class rclass = REGNO_REG_CLASS (regno);
2296
2297   if (mode == CCmode)
2298     return 0;
2299
2300   if (mode == V2HImode)
2301     return D_REGNO_P (regno);
2302   if (rclass == CCREGS)
2303     return mode == BImode;
2304   if (mode == PDImode || mode == V2PDImode)
2305     return regno == REG_A0 || regno == REG_A1;
2306
2307   /* Allow all normal 32-bit regs, except REG_M3, in case regclass ever comes
2308      up with a bad register class (such as ALL_REGS) for DImode.  */
2309   if (mode == DImode)
2310     return regno < REG_M3;
2311
2312   if (mode == SImode
2313       && TEST_HARD_REG_BIT (reg_class_contents[PROLOGUE_REGS], regno))
2314     return 1;
2315
2316   return TEST_HARD_REG_BIT (reg_class_contents[MOST_REGS], regno);
2317 }
2318
2319 /* Implements target hook vector_mode_supported_p.  */
2320
2321 static bool
2322 bfin_vector_mode_supported_p (enum machine_mode mode)
2323 {
2324   return mode == V2HImode;
2325 }
2326
2327 /* Return the cost of moving data from a register in class CLASS1 to
2328    one in class CLASS2.  A cost of 2 is the default.  */
2329
2330 int
2331 bfin_register_move_cost (enum machine_mode mode,
2332                          enum reg_class class1, enum reg_class class2)
2333 {
2334   /* These need secondary reloads, so they're more expensive.  */
2335   if ((class1 == CCREGS && !reg_class_subset_p (class2, DREGS))
2336       || (class2 == CCREGS && !reg_class_subset_p (class1, DREGS)))
2337     return 4;
2338
2339   /* If optimizing for size, always prefer reg-reg over reg-memory moves.  */
2340   if (optimize_size)
2341     return 2;
2342
2343   if (GET_MODE_CLASS (mode) == MODE_INT)
2344     {
2345       /* Discourage trying to use the accumulators.  */
2346       if (TEST_HARD_REG_BIT (reg_class_contents[class1], REG_A0)
2347           || TEST_HARD_REG_BIT (reg_class_contents[class1], REG_A1)
2348           || TEST_HARD_REG_BIT (reg_class_contents[class2], REG_A0)
2349           || TEST_HARD_REG_BIT (reg_class_contents[class2], REG_A1))
2350         return 20;
2351     }
2352   return 2;
2353 }
2354
2355 /* Return the cost of moving data of mode M between a
2356    register and memory.  A value of 2 is the default; this cost is
2357    relative to those in `REGISTER_MOVE_COST'.
2358
2359    ??? In theory L1 memory has single-cycle latency.  We should add a switch
2360    that tells the compiler whether we expect to use only L1 memory for the
2361    program; it'll make the costs more accurate.  */
2362
2363 int
2364 bfin_memory_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
2365                        enum reg_class rclass,
2366                        int in ATTRIBUTE_UNUSED)
2367 {
2368   /* Make memory accesses slightly more expensive than any register-register
2369      move.  Also, penalize non-DP registers, since they need secondary
2370      reloads to load and store.  */
2371   if (! reg_class_subset_p (rclass, DPREGS))
2372     return 10;
2373
2374   return 8;
2375 }
2376
2377 /* Inform reload about cases where moving X with a mode MODE to a register in
2378    RCLASS requires an extra scratch register.  Return the class needed for the
2379    scratch register.  */
2380
2381 static enum reg_class
2382 bfin_secondary_reload (bool in_p, rtx x, enum reg_class rclass,
2383                        enum machine_mode mode, secondary_reload_info *sri)
2384 {
2385   /* If we have HImode or QImode, we can only use DREGS as secondary registers;
2386      in most other cases we can also use PREGS.  */
2387   enum reg_class default_class = GET_MODE_SIZE (mode) >= 4 ? DPREGS : DREGS;
2388   enum reg_class x_class = NO_REGS;
2389   enum rtx_code code = GET_CODE (x);
2390
2391   if (code == SUBREG)
2392     x = SUBREG_REG (x), code = GET_CODE (x);
2393   if (REG_P (x))
2394     {
2395       int regno = REGNO (x);
2396       if (regno >= FIRST_PSEUDO_REGISTER)
2397         regno = reg_renumber[regno];
2398
2399       if (regno == -1)
2400         code = MEM;
2401       else
2402         x_class = REGNO_REG_CLASS (regno);
2403     }
2404
2405   /* We can be asked to reload (plus (FP) (large_constant)) into a DREG.
2406      This happens as a side effect of register elimination, and we need
2407      a scratch register to do it.  */
2408   if (fp_plus_const_operand (x, mode))
2409     {
2410       rtx op2 = XEXP (x, 1);
2411       int large_constant_p = ! satisfies_constraint_Ks7 (op2);
2412
2413       if (rclass == PREGS || rclass == PREGS_CLOBBERED)
2414         return NO_REGS;
2415       /* If destination is a DREG, we can do this without a scratch register
2416          if the constant is valid for an add instruction.  */
2417       if ((rclass == DREGS || rclass == DPREGS)
2418           && ! large_constant_p)
2419         return NO_REGS;
2420       /* Reloading to anything other than a DREG?  Use a PREG scratch
2421          register.  */
2422       sri->icode = CODE_FOR_reload_insi;
2423       return NO_REGS;
2424     }
2425
2426   /* Data can usually be moved freely between registers of most classes.
2427      AREGS are an exception; they can only move to or from another register
2428      in AREGS or one in DREGS.  They can also be assigned the constant 0.  */
2429   if (x_class == AREGS || x_class == EVEN_AREGS || x_class == ODD_AREGS)
2430     return (rclass == DREGS || rclass == AREGS || rclass == EVEN_AREGS
2431             || rclass == ODD_AREGS
2432             ? NO_REGS : DREGS);
2433
2434   if (rclass == AREGS || rclass == EVEN_AREGS || rclass == ODD_AREGS)
2435     {
2436       if (code == MEM)
2437         {
2438           sri->icode = in_p ? CODE_FOR_reload_inpdi : CODE_FOR_reload_outpdi;
2439           return NO_REGS;
2440         }
2441
2442       if (x != const0_rtx && x_class != DREGS)
2443         {
2444           return DREGS;
2445         }
2446       else
2447         return NO_REGS;
2448     }
2449
2450   /* CCREGS can only be moved from/to DREGS.  */
2451   if (rclass == CCREGS && x_class != DREGS)
2452     return DREGS;
2453   if (x_class == CCREGS && rclass != DREGS)
2454     return DREGS;
2455
2456   /* All registers other than AREGS can load arbitrary constants.  The only
2457      case that remains is MEM.  */
2458   if (code == MEM)
2459     if (! reg_class_subset_p (rclass, default_class))
2460       return default_class;
2461
2462   return NO_REGS;
2463 }
2464 \f
2465 /* Implement TARGET_HANDLE_OPTION.  */
2466
2467 static bool
2468 bfin_handle_option (size_t code, const char *arg, int value)
2469 {
2470   switch (code)
2471     {
2472     case OPT_mshared_library_id_:
2473       if (value > MAX_LIBRARY_ID)
2474         error ("-mshared-library-id=%s is not between 0 and %d",
2475                arg, MAX_LIBRARY_ID);
2476       bfin_lib_id_given = 1;
2477       return true;
2478
2479     case OPT_mcpu_:
2480       {
2481         const char *p, *q;
2482         int i;
2483
2484         i = 0;
2485         while ((p = bfin_cpus[i].name) != NULL)
2486           {
2487             if (strncmp (arg, p, strlen (p)) == 0)
2488               break;
2489             i++;
2490           }
2491
2492         if (p == NULL)
2493           {
2494             error ("-mcpu=%s is not valid", arg);
2495             return false;
2496           }
2497
2498         bfin_cpu_type = bfin_cpus[i].type;
2499
2500         q = arg + strlen (p);
2501
2502         if (*q == '\0')
2503           {
2504             bfin_si_revision = bfin_cpus[i].si_revision;
2505             bfin_workarounds |= bfin_cpus[i].workarounds;
2506           }
2507         else if (strcmp (q, "-none") == 0)
2508           bfin_si_revision = -1;
2509         else if (strcmp (q, "-any") == 0)
2510           {
2511             bfin_si_revision = 0xffff;
2512             while (bfin_cpus[i].type == bfin_cpu_type)
2513               {
2514                 bfin_workarounds |= bfin_cpus[i].workarounds;
2515                 i++;
2516               }
2517           }
2518         else
2519           {
2520             unsigned int si_major, si_minor;
2521             int rev_len, n;
2522
2523             rev_len = strlen (q);
2524
2525             if (sscanf (q, "-%u.%u%n", &si_major, &si_minor, &n) != 2
2526                 || n != rev_len
2527                 || si_major > 0xff || si_minor > 0xff)
2528               {
2529               invalid_silicon_revision:
2530                 error ("-mcpu=%s has invalid silicon revision", arg);
2531                 return false;
2532               }
2533
2534             bfin_si_revision = (si_major << 8) | si_minor;
2535
2536             while (bfin_cpus[i].type == bfin_cpu_type
2537                    && bfin_cpus[i].si_revision != bfin_si_revision)
2538               i++;
2539
2540             if (bfin_cpus[i].type != bfin_cpu_type)
2541               goto invalid_silicon_revision;
2542
2543             bfin_workarounds |= bfin_cpus[i].workarounds;
2544           }
2545
2546         return true;
2547       }
2548
2549     default:
2550       return true;
2551     }
2552 }
2553
2554 static struct machine_function *
2555 bfin_init_machine_status (void)
2556 {
2557   struct machine_function *f;
2558
2559   f = GGC_CNEW (struct machine_function);
2560
2561   return f;
2562 }
2563
2564 /* Implement the macro OVERRIDE_OPTIONS.  */
2565
2566 void
2567 override_options (void)
2568 {
2569   /* If processor type is not specified, enable all workarounds.  */
2570   if (bfin_cpu_type == BFIN_CPU_UNKNOWN)
2571     {
2572       int i;
2573
2574       for (i = 0; bfin_cpus[i].name != NULL; i++)
2575         bfin_workarounds |= bfin_cpus[i].workarounds;
2576
2577       bfin_si_revision = 0xffff;
2578     }
2579
2580   if (bfin_csync_anomaly == 1)
2581     bfin_workarounds |= WA_SPECULATIVE_SYNCS;
2582   else if (bfin_csync_anomaly == 0)
2583     bfin_workarounds &= ~WA_SPECULATIVE_SYNCS;
2584
2585   if (bfin_specld_anomaly == 1)
2586     bfin_workarounds |= WA_SPECULATIVE_LOADS;
2587   else if (bfin_specld_anomaly == 0)
2588     bfin_workarounds &= ~WA_SPECULATIVE_LOADS;
2589
2590   if (TARGET_OMIT_LEAF_FRAME_POINTER)
2591     flag_omit_frame_pointer = 1;
2592
2593   /* Library identification */
2594   if (bfin_lib_id_given && ! TARGET_ID_SHARED_LIBRARY)
2595     error ("-mshared-library-id= specified without -mid-shared-library");
2596
2597   if (stack_limit_rtx && TARGET_STACK_CHECK_L1)
2598     error ("Can't use multiple stack checking methods together.");
2599
2600   if (TARGET_ID_SHARED_LIBRARY && TARGET_FDPIC)
2601     error ("ID shared libraries and FD-PIC mode can't be used together.");
2602
2603   /* Don't allow the user to specify -mid-shared-library and -msep-data
2604      together, as it makes little sense from a user's point of view...  */
2605   if (TARGET_SEP_DATA && TARGET_ID_SHARED_LIBRARY)
2606     error ("cannot specify both -msep-data and -mid-shared-library");
2607   /* ... internally, however, it's nearly the same.  */
2608   if (TARGET_SEP_DATA)
2609     target_flags |= MASK_ID_SHARED_LIBRARY | MASK_LEAF_ID_SHARED_LIBRARY;
2610
2611   if (TARGET_ID_SHARED_LIBRARY && flag_pic == 0)
2612     flag_pic = 1;
2613
2614   /* There is no single unaligned SI op for PIC code.  Sometimes we
2615      need to use ".4byte" and sometimes we need to use ".picptr".
2616      See bfin_assemble_integer for details.  */
2617   if (TARGET_FDPIC)
2618     targetm.asm_out.unaligned_op.si = 0;
2619
2620   /* Silently turn off flag_pic if not doing FDPIC or ID shared libraries,
2621      since we don't support it and it'll just break.  */
2622   if (flag_pic && !TARGET_FDPIC && !TARGET_ID_SHARED_LIBRARY)
2623     flag_pic = 0;
2624
2625   if (TARGET_MULTICORE && bfin_cpu_type != BFIN_CPU_BF561)
2626     error ("-mmulticore can only be used with BF561");
2627
2628   if (TARGET_COREA && !TARGET_MULTICORE)
2629     error ("-mcorea should be used with -mmulticore");
2630
2631   if (TARGET_COREB && !TARGET_MULTICORE)
2632     error ("-mcoreb should be used with -mmulticore");
2633
2634   if (TARGET_COREA && TARGET_COREB)
2635     error ("-mcorea and -mcoreb can't be used together");
2636
2637   flag_schedule_insns = 0;
2638
2639   /* Passes after sched2 can break the helpful TImode annotations that
2640      haifa-sched puts on every insn.  Just do scheduling in reorg.  */
2641   bfin_flag_schedule_insns2 = flag_schedule_insns_after_reload;
2642   flag_schedule_insns_after_reload = 0;
2643
2644   init_machine_status = bfin_init_machine_status;
2645 }
2646
2647 /* Return the destination address of BRANCH.
2648    We need to use this instead of get_attr_length, because the
2649    cbranch_with_nops pattern conservatively sets its length to 6, and
2650    we still prefer to use shorter sequences.  */
2651
2652 static int
2653 branch_dest (rtx branch)
2654 {
2655   rtx dest;
2656   int dest_uid;
2657   rtx pat = PATTERN (branch);
2658   if (GET_CODE (pat) == PARALLEL)
2659     pat = XVECEXP (pat, 0, 0);
2660   dest = SET_SRC (pat);
2661   if (GET_CODE (dest) == IF_THEN_ELSE)
2662     dest = XEXP (dest, 1);
2663   dest = XEXP (dest, 0);
2664   dest_uid = INSN_UID (dest);
2665   return INSN_ADDRESSES (dest_uid);
2666 }
2667
2668 /* Return nonzero if INSN is annotated with a REG_BR_PROB note that indicates
2669    it's a branch that's predicted taken.  */
2670
2671 static int
2672 cbranch_predicted_taken_p (rtx insn)
2673 {
2674   rtx x = find_reg_note (insn, REG_BR_PROB, 0);
2675
2676   if (x)
2677     {
2678       int pred_val = INTVAL (XEXP (x, 0));
2679
2680       return pred_val >= REG_BR_PROB_BASE / 2;
2681     }
2682
2683   return 0;
2684 }
2685
2686 /* Templates for use by asm_conditional_branch.  */
2687
2688 static const char *ccbranch_templates[][3] = {
2689   { "if !cc jump %3;",  "if cc jump 4 (bp); jump.s %3;",  "if cc jump 6 (bp); jump.l %3;" },
2690   { "if cc jump %3;",   "if !cc jump 4 (bp); jump.s %3;", "if !cc jump 6 (bp); jump.l %3;" },
2691   { "if !cc jump %3 (bp);",  "if cc jump 4; jump.s %3;",  "if cc jump 6; jump.l %3;" },
2692   { "if cc jump %3 (bp);",  "if !cc jump 4; jump.s %3;",  "if !cc jump 6; jump.l %3;" },
2693 };
2694
2695 /* Output INSN, which is a conditional branch instruction with operands
2696    OPERANDS.
2697
2698    We deal with the various forms of conditional branches that can be generated
2699    by bfin_reorg to prevent the hardware from doing speculative loads, by
2700    - emitting a sufficient number of nops, if N_NOPS is nonzero, or
2701    - always emitting the branch as predicted taken, if PREDICT_TAKEN is true.
2702    Either of these is only necessary if the branch is short, otherwise the
2703    template we use ends in an unconditional jump which flushes the pipeline
2704    anyway.  */
2705
2706 void
2707 asm_conditional_branch (rtx insn, rtx *operands, int n_nops, int predict_taken)
2708 {
2709   int offset = branch_dest (insn) - INSN_ADDRESSES (INSN_UID (insn));
2710   /* Note : offset for instructions like if cc jmp; jump.[sl] offset
2711             is to be taken from start of if cc rather than jump.
2712             Range for jump.s is (-4094, 4096) instead of (-4096, 4094)
2713   */
2714   int len = (offset >= -1024 && offset <= 1022 ? 0
2715              : offset >= -4094 && offset <= 4096 ? 1
2716              : 2);
2717   int bp = predict_taken && len == 0 ? 1 : cbranch_predicted_taken_p (insn);
2718   int idx = (bp << 1) | (GET_CODE (operands[0]) == EQ ? BRF : BRT);
2719   output_asm_insn (ccbranch_templates[idx][len], operands);
2720   gcc_assert (n_nops == 0 || !bp);
2721   if (len == 0)
2722     while (n_nops-- > 0)
2723       output_asm_insn ("nop;", NULL);
2724 }
2725
2726 /* Emit rtl for a comparison operation CMP in mode MODE.  Operands have been
2727    stored in bfin_compare_op0 and bfin_compare_op1 already.  */
2728
2729 rtx
2730 bfin_gen_compare (rtx cmp, enum machine_mode mode ATTRIBUTE_UNUSED)
2731 {
2732   enum rtx_code code1, code2;
2733   rtx op0 = bfin_compare_op0, op1 = bfin_compare_op1;
2734   rtx tem = bfin_cc_rtx;
2735   enum rtx_code code = GET_CODE (cmp);
2736
2737   /* If we have a BImode input, then we already have a compare result, and
2738      do not need to emit another comparison.  */
2739   if (GET_MODE (op0) == BImode)
2740     {
2741       gcc_assert ((code == NE || code == EQ) && op1 == const0_rtx);
2742       tem = op0, code2 = code;
2743     }
2744   else
2745     {
2746       switch (code) {
2747         /* bfin has these conditions */
2748       case EQ:
2749       case LT:
2750       case LE:
2751       case LEU:
2752       case LTU:
2753         code1 = code;
2754         code2 = NE;
2755         break;
2756       default:
2757         code1 = reverse_condition (code);
2758         code2 = EQ;
2759         break;
2760       }
2761       emit_insn (gen_rtx_SET (BImode, tem,
2762                               gen_rtx_fmt_ee (code1, BImode, op0, op1)));
2763     }
2764
2765   return gen_rtx_fmt_ee (code2, BImode, tem, CONST0_RTX (BImode));
2766 }
2767 \f
2768 /* Return nonzero iff C has exactly one bit set if it is interpreted
2769    as a 32-bit constant.  */
2770
2771 int
2772 log2constp (unsigned HOST_WIDE_INT c)
2773 {
2774   c &= 0xFFFFFFFF;
2775   return c != 0 && (c & (c-1)) == 0;
2776 }
2777
2778 /* Returns the number of consecutive least significant zeros in the binary
2779    representation of *V.
2780    We modify *V to contain the original value arithmetically shifted right by
2781    the number of zeroes.  */
2782
2783 static int
2784 shiftr_zero (HOST_WIDE_INT *v)
2785 {
2786   unsigned HOST_WIDE_INT tmp = *v;
2787   unsigned HOST_WIDE_INT sgn;
2788   int n = 0;
2789
2790   if (tmp == 0)
2791     return 0;
2792
2793   sgn = tmp & ((unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1));
2794   while ((tmp & 0x1) == 0 && n <= 32)
2795     {
2796       tmp = (tmp >> 1) | sgn;
2797       n++;
2798     }
2799   *v = tmp;
2800   return n;
2801 }
2802
2803 /* After reload, split the load of an immediate constant.  OPERANDS are the
2804    operands of the movsi_insn pattern which we are splitting.  We return
2805    nonzero if we emitted a sequence to load the constant, zero if we emitted
2806    nothing because we want to use the splitter's default sequence.  */
2807
2808 int
2809 split_load_immediate (rtx operands[])
2810 {
2811   HOST_WIDE_INT val = INTVAL (operands[1]);
2812   HOST_WIDE_INT tmp;
2813   HOST_WIDE_INT shifted = val;
2814   HOST_WIDE_INT shifted_compl = ~val;
2815   int num_zero = shiftr_zero (&shifted);
2816   int num_compl_zero = shiftr_zero (&shifted_compl);
2817   unsigned int regno = REGNO (operands[0]);
2818
2819   /* This case takes care of single-bit set/clear constants, which we could
2820      also implement with BITSET/BITCLR.  */
2821   if (num_zero
2822       && shifted >= -32768 && shifted < 65536
2823       && (D_REGNO_P (regno)
2824           || (regno >= REG_P0 && regno <= REG_P7 && num_zero <= 2)))
2825     {
2826       emit_insn (gen_movsi (operands[0], GEN_INT (shifted)));
2827       emit_insn (gen_ashlsi3 (operands[0], operands[0], GEN_INT (num_zero)));
2828       return 1;
2829     }
2830
2831   tmp = val & 0xFFFF;
2832   tmp |= -(tmp & 0x8000);
2833
2834   /* If high word has one bit set or clear, try to use a bit operation.  */
2835   if (D_REGNO_P (regno))
2836     {
2837       if (log2constp (val & 0xFFFF0000))
2838         {
2839           emit_insn (gen_movsi (operands[0], GEN_INT (val & 0xFFFF)));
2840           emit_insn (gen_iorsi3 (operands[0], operands[0], GEN_INT (val & 0xFFFF0000)));
2841           return 1;
2842         }
2843       else if (log2constp (val | 0xFFFF) && (val & 0x8000) != 0)
2844         {
2845           emit_insn (gen_movsi (operands[0], GEN_INT (tmp)));
2846           emit_insn (gen_andsi3 (operands[0], operands[0], GEN_INT (val | 0xFFFF)));
2847         }
2848     }
2849
2850   if (D_REGNO_P (regno))
2851     {
2852       if (tmp >= -64 && tmp <= 63)
2853         {
2854           emit_insn (gen_movsi (operands[0], GEN_INT (tmp)));
2855           emit_insn (gen_movstricthi_high (operands[0], GEN_INT (val & -65536)));
2856           return 1;
2857         }
2858
2859       if ((val & 0xFFFF0000) == 0)
2860         {
2861           emit_insn (gen_movsi (operands[0], const0_rtx));
2862           emit_insn (gen_movsi_low (operands[0], operands[0], operands[1]));
2863           return 1;
2864         }
2865
2866       if ((val & 0xFFFF0000) == 0xFFFF0000)
2867         {
2868           emit_insn (gen_movsi (operands[0], constm1_rtx));
2869           emit_insn (gen_movsi_low (operands[0], operands[0], operands[1]));
2870           return 1;
2871         }
2872     }
2873
2874   /* Need DREGs for the remaining case.  */
2875   if (regno > REG_R7)
2876     return 0;
2877
2878   if (optimize_size
2879       && num_compl_zero && shifted_compl >= -64 && shifted_compl <= 63)
2880     {
2881       /* If optimizing for size, generate a sequence that has more instructions
2882          but is shorter.  */
2883       emit_insn (gen_movsi (operands[0], GEN_INT (shifted_compl)));
2884       emit_insn (gen_ashlsi3 (operands[0], operands[0],
2885                               GEN_INT (num_compl_zero)));
2886       emit_insn (gen_one_cmplsi2 (operands[0], operands[0]));
2887       return 1;
2888     }
2889   return 0;
2890 }
2891 \f
2892 /* Return true if the legitimate memory address for a memory operand of mode
2893    MODE.  Return false if not.  */
2894
2895 static bool
2896 bfin_valid_add (enum machine_mode mode, HOST_WIDE_INT value)
2897 {
2898   unsigned HOST_WIDE_INT v = value > 0 ? value : -value;
2899   int sz = GET_MODE_SIZE (mode);
2900   int shift = sz == 1 ? 0 : sz == 2 ? 1 : 2;
2901   /* The usual offsettable_memref machinery doesn't work so well for this
2902      port, so we deal with the problem here.  */
2903   if (value > 0 && sz == 8)
2904     v += 4;
2905   return (v & ~(0x7fff << shift)) == 0;
2906 }
2907
2908 static bool
2909 bfin_valid_reg_p (unsigned int regno, int strict, enum machine_mode mode,
2910                   enum rtx_code outer_code)
2911 {
2912   if (strict)
2913     return REGNO_OK_FOR_BASE_STRICT_P (regno, mode, outer_code, SCRATCH);
2914   else
2915     return REGNO_OK_FOR_BASE_NONSTRICT_P (regno, mode, outer_code, SCRATCH);
2916 }
2917
2918 bool
2919 bfin_legitimate_address_p (enum machine_mode mode, rtx x, int strict)
2920 {
2921   switch (GET_CODE (x)) {
2922   case REG:
2923     if (bfin_valid_reg_p (REGNO (x), strict, mode, MEM))
2924       return true;
2925     break;
2926   case PLUS:
2927     if (REG_P (XEXP (x, 0))
2928         && bfin_valid_reg_p (REGNO (XEXP (x, 0)), strict, mode, PLUS)
2929         && ((GET_CODE (XEXP (x, 1)) == UNSPEC && mode == SImode)
2930             || (GET_CODE (XEXP (x, 1)) == CONST_INT
2931                 && bfin_valid_add (mode, INTVAL (XEXP (x, 1))))))
2932       return true;
2933     break;
2934   case POST_INC:
2935   case POST_DEC:
2936     if (LEGITIMATE_MODE_FOR_AUTOINC_P (mode)
2937         && REG_P (XEXP (x, 0))
2938         && bfin_valid_reg_p (REGNO (XEXP (x, 0)), strict, mode, POST_INC))
2939       return true;
2940   case PRE_DEC:
2941     if (LEGITIMATE_MODE_FOR_AUTOINC_P (mode)
2942         && XEXP (x, 0) == stack_pointer_rtx
2943         && REG_P (XEXP (x, 0))
2944         && bfin_valid_reg_p (REGNO (XEXP (x, 0)), strict, mode, PRE_DEC))
2945       return true;
2946     break;
2947   default:
2948     break;
2949   }
2950   return false;
2951 }
2952
2953 /* Decide whether we can force certain constants to memory.  If we
2954    decide we can't, the caller should be able to cope with it in
2955    another way.  */
2956
2957 static bool
2958 bfin_cannot_force_const_mem (rtx x ATTRIBUTE_UNUSED)
2959 {
2960   /* We have only one class of non-legitimate constants, and our movsi
2961      expander knows how to handle them.  Dropping these constants into the
2962      data section would only shift the problem - we'd still get relocs
2963      outside the object, in the data section rather than the text section.  */
2964   return true;
2965 }
2966
2967 /* Ensure that for any constant of the form symbol + offset, the offset
2968    remains within the object.  Any other constants are ok.
2969    This ensures that flat binaries never have to deal with relocations
2970    crossing section boundaries.  */
2971
2972 bool
2973 bfin_legitimate_constant_p (rtx x)
2974 {
2975   rtx sym;
2976   HOST_WIDE_INT offset;
2977
2978   if (GET_CODE (x) != CONST)
2979     return true;
2980
2981   x = XEXP (x, 0);
2982   gcc_assert (GET_CODE (x) == PLUS);
2983
2984   sym = XEXP (x, 0);
2985   x = XEXP (x, 1);
2986   if (GET_CODE (sym) != SYMBOL_REF
2987       || GET_CODE (x) != CONST_INT)
2988     return true;
2989   offset = INTVAL (x);
2990
2991   if (SYMBOL_REF_DECL (sym) == 0)
2992     return true;
2993   if (offset < 0
2994       || offset >= int_size_in_bytes (TREE_TYPE (SYMBOL_REF_DECL (sym))))
2995     return false;
2996
2997   return true;
2998 }
2999
3000 static bool
3001 bfin_rtx_costs (rtx x, int code, int outer_code, int *total, bool speed)
3002 {
3003   int cost2 = COSTS_N_INSNS (1);
3004   rtx op0, op1;
3005
3006   switch (code)
3007     {
3008     case CONST_INT:
3009       if (outer_code == SET || outer_code == PLUS)
3010         *total = satisfies_constraint_Ks7 (x) ? 0 : cost2;
3011       else if (outer_code == AND)
3012         *total = log2constp (~INTVAL (x)) ? 0 : cost2;
3013       else if (outer_code == LE || outer_code == LT || outer_code == EQ)
3014         *total = (INTVAL (x) >= -4 && INTVAL (x) <= 3) ? 0 : cost2;
3015       else if (outer_code == LEU || outer_code == LTU)
3016         *total = (INTVAL (x) >= 0 && INTVAL (x) <= 7) ? 0 : cost2;
3017       else if (outer_code == MULT)
3018         *total = (INTVAL (x) == 2 || INTVAL (x) == 4) ? 0 : cost2;
3019       else if (outer_code == ASHIFT && (INTVAL (x) == 1 || INTVAL (x) == 2))
3020         *total = 0;
3021       else if (outer_code == ASHIFT || outer_code == ASHIFTRT
3022                || outer_code == LSHIFTRT)
3023         *total = (INTVAL (x) >= 0 && INTVAL (x) <= 31) ? 0 : cost2;
3024       else if (outer_code == IOR || outer_code == XOR)
3025         *total = (INTVAL (x) & (INTVAL (x) - 1)) == 0 ? 0 : cost2;
3026       else
3027         *total = cost2;
3028       return true;
3029
3030     case CONST:
3031     case LABEL_REF:
3032     case SYMBOL_REF:
3033     case CONST_DOUBLE:
3034       *total = COSTS_N_INSNS (2);
3035       return true;
3036
3037     case PLUS:
3038       op0 = XEXP (x, 0);
3039       op1 = XEXP (x, 1);
3040       if (GET_MODE (x) == SImode)
3041         {
3042           if (GET_CODE (op0) == MULT
3043               && GET_CODE (XEXP (op0, 1)) == CONST_INT)
3044             {
3045               HOST_WIDE_INT val = INTVAL (XEXP (op0, 1));
3046               if (val == 2 || val == 4)
3047                 {
3048                   *total = cost2;
3049                   *total += rtx_cost (XEXP (op0, 0), outer_code, speed);
3050                   *total += rtx_cost (op1, outer_code, speed);
3051                   return true;
3052                 }
3053             }
3054           *total = cost2;
3055           if (GET_CODE (op0) != REG
3056               && (GET_CODE (op0) != SUBREG || GET_CODE (SUBREG_REG (op0)) != REG))
3057             *total += rtx_cost (op0, SET, speed);
3058 #if 0 /* We'd like to do this for accuracy, but it biases the loop optimizer
3059          towards creating too many induction variables.  */
3060           if (!reg_or_7bit_operand (op1, SImode))
3061             *total += rtx_cost (op1, SET, speed);
3062 #endif
3063         }
3064       else if (GET_MODE (x) == DImode)
3065         {
3066           *total = 6 * cost2;
3067           if (GET_CODE (op1) != CONST_INT
3068               || !satisfies_constraint_Ks7 (op1))
3069             *total += rtx_cost (op1, PLUS, speed);
3070           if (GET_CODE (op0) != REG
3071               && (GET_CODE (op0) != SUBREG || GET_CODE (SUBREG_REG (op0)) != REG))
3072             *total += rtx_cost (op0, PLUS, speed);
3073         }
3074       return true;
3075
3076     case MINUS:
3077       if (GET_MODE (x) == DImode)
3078         *total = 6 * cost2;
3079       else
3080         *total = cost2;
3081       return true;
3082       
3083     case ASHIFT: 
3084     case ASHIFTRT:
3085     case LSHIFTRT:
3086       if (GET_MODE (x) == DImode)
3087         *total = 6 * cost2;
3088       else
3089         *total = cost2;
3090
3091       op0 = XEXP (x, 0);
3092       op1 = XEXP (x, 1);
3093       if (GET_CODE (op0) != REG
3094           && (GET_CODE (op0) != SUBREG || GET_CODE (SUBREG_REG (op0)) != REG))
3095         *total += rtx_cost (op0, code, speed);
3096
3097       return true;
3098           
3099     case IOR:
3100     case AND:
3101     case XOR:
3102       op0 = XEXP (x, 0);
3103       op1 = XEXP (x, 1);
3104
3105       /* Handle special cases of IOR: rotates, ALIGN insns, movstricthi_high.  */
3106       if (code == IOR)
3107         {
3108           if ((GET_CODE (op0) == LSHIFTRT && GET_CODE (op1) == ASHIFT)
3109               || (GET_CODE (op0) == ASHIFT && GET_CODE (op1) == ZERO_EXTEND)
3110               || (GET_CODE (op0) == ASHIFT && GET_CODE (op1) == LSHIFTRT)
3111               || (GET_CODE (op0) == AND && GET_CODE (op1) == CONST_INT))
3112             {
3113               *total = cost2;
3114               return true;
3115             }
3116         }
3117
3118       if (GET_CODE (op0) != REG
3119           && (GET_CODE (op0) != SUBREG || GET_CODE (SUBREG_REG (op0)) != REG))
3120         *total += rtx_cost (op0, code, speed);
3121
3122       if (GET_MODE (x) == DImode)
3123         {
3124           *total = 2 * cost2;
3125           return true;
3126         }
3127       *total = cost2;
3128       if (GET_MODE (x) != SImode)
3129         return true;
3130
3131       if (code == AND)
3132         {
3133           if (! rhs_andsi3_operand (XEXP (x, 1), SImode))
3134             *total += rtx_cost (XEXP (x, 1), code, speed);
3135         }
3136       else
3137         {
3138           if (! regorlog2_operand (XEXP (x, 1), SImode))
3139             *total += rtx_cost (XEXP (x, 1), code, speed);
3140         }
3141
3142       return true;
3143
3144     case ZERO_EXTRACT:
3145     case SIGN_EXTRACT:
3146       if (outer_code == SET
3147           && XEXP (x, 1) == const1_rtx
3148           && GET_CODE (XEXP (x, 2)) == CONST_INT)
3149         {
3150           *total = 2 * cost2;
3151           return true;
3152         }
3153       /* fall through */
3154
3155     case SIGN_EXTEND:
3156     case ZERO_EXTEND:
3157       *total = cost2;
3158       return true;
3159
3160     case MULT:
3161         {
3162           op0 = XEXP (x, 0);
3163           op1 = XEXP (x, 1);
3164           if (GET_CODE (op0) == GET_CODE (op1)
3165               && (GET_CODE (op0) == ZERO_EXTEND
3166                   || GET_CODE (op0) == SIGN_EXTEND))
3167             {
3168               *total = COSTS_N_INSNS (1);
3169               op0 = XEXP (op0, 0);
3170               op1 = XEXP (op1, 0);
3171             }
3172           else if (!speed)
3173             *total = COSTS_N_INSNS (1);
3174           else
3175             *total = COSTS_N_INSNS (3);
3176
3177           if (GET_CODE (op0) != REG
3178               && (GET_CODE (op0) != SUBREG || GET_CODE (SUBREG_REG (op0)) != REG))
3179             *total += rtx_cost (op0, MULT, speed);
3180           if (GET_CODE (op1) != REG
3181               && (GET_CODE (op1) != SUBREG || GET_CODE (SUBREG_REG (op1)) != REG))
3182             *total += rtx_cost (op1, MULT, speed);
3183         }
3184       return true;
3185
3186     case UDIV:
3187     case UMOD:
3188       *total = COSTS_N_INSNS (32);
3189       return true;
3190
3191     case VEC_CONCAT:
3192     case VEC_SELECT:
3193       if (outer_code == SET)
3194         *total = cost2;
3195       return true;
3196
3197     default:
3198       return false;
3199     }
3200 }
3201 \f
3202 /* Used for communication between {push,pop}_multiple_operation (which
3203    we use not only as a predicate) and the corresponding output functions.  */
3204 static int first_preg_to_save, first_dreg_to_save;
3205 static int n_regs_to_save;
3206
3207 int
3208 push_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
3209 {
3210   int lastdreg = 8, lastpreg = 6;
3211   int i, group;
3212
3213   first_preg_to_save = lastpreg;
3214   first_dreg_to_save = lastdreg;
3215   for (i = 1, group = 0; i < XVECLEN (op, 0) - 1; i++)
3216     {
3217       rtx t = XVECEXP (op, 0, i);
3218       rtx src, dest;
3219       int regno;
3220
3221       if (GET_CODE (t) != SET)
3222         return 0;
3223
3224       src = SET_SRC (t);
3225       dest = SET_DEST (t);
3226       if (GET_CODE (dest) != MEM || ! REG_P (src))
3227         return 0;
3228       dest = XEXP (dest, 0);
3229       if (GET_CODE (dest) != PLUS
3230           || ! REG_P (XEXP (dest, 0))
3231           || REGNO (XEXP (dest, 0)) != REG_SP
3232           || GET_CODE (XEXP (dest, 1)) != CONST_INT
3233           || INTVAL (XEXP (dest, 1)) != -i * 4)
3234         return 0;
3235
3236       regno = REGNO (src);
3237       if (group == 0)
3238         {
3239           if (D_REGNO_P (regno))
3240             {
3241               group = 1;
3242               first_dreg_to_save = lastdreg = regno - REG_R0;
3243             }
3244           else if (regno >= REG_P0 && regno <= REG_P7)
3245             {
3246               group = 2;
3247               first_preg_to_save = lastpreg = regno - REG_P0;
3248             }
3249           else
3250             return 0;
3251
3252           continue;
3253         }
3254
3255       if (group == 1)
3256         {
3257           if (regno >= REG_P0 && regno <= REG_P7)
3258             {
3259               group = 2;
3260               first_preg_to_save = lastpreg = regno - REG_P0;
3261             }
3262           else if (regno != REG_R0 + lastdreg + 1)
3263             return 0;
3264           else
3265             lastdreg++;
3266         }
3267       else if (group == 2)
3268         {
3269           if (regno != REG_P0 + lastpreg + 1)
3270             return 0;
3271           lastpreg++;
3272         }
3273     }
3274   n_regs_to_save = 8 - first_dreg_to_save + 6 - first_preg_to_save;
3275   return 1;
3276 }
3277
3278 int
3279 pop_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
3280 {
3281   int lastdreg = 8, lastpreg = 6;
3282   int i, group;
3283
3284   for (i = 1, group = 0; i < XVECLEN (op, 0); i++)
3285     {
3286       rtx t = XVECEXP (op, 0, i);
3287       rtx src, dest;
3288       int regno;
3289
3290       if (GET_CODE (t) != SET)
3291         return 0;
3292
3293       src = SET_SRC (t);
3294       dest = SET_DEST (t);
3295       if (GET_CODE (src) != MEM || ! REG_P (dest))
3296         return 0;
3297       src = XEXP (src, 0);
3298
3299       if (i == 1)
3300         {
3301           if (! REG_P (src) || REGNO (src) != REG_SP)
3302             return 0;
3303         }
3304       else if (GET_CODE (src) != PLUS
3305                || ! REG_P (XEXP (src, 0))
3306                || REGNO (XEXP (src, 0)) != REG_SP
3307                || GET_CODE (XEXP (src, 1)) != CONST_INT
3308                || INTVAL (XEXP (src, 1)) != (i - 1) * 4)
3309         return 0;
3310
3311       regno = REGNO (dest);
3312       if (group == 0)
3313         {
3314           if (regno == REG_R7)
3315             {
3316               group = 1;
3317               lastdreg = 7;
3318             }
3319           else if (regno != REG_P0 + lastpreg - 1)
3320             return 0;
3321           else
3322             lastpreg--;
3323         }
3324       else if (group == 1)
3325         {
3326           if (regno != REG_R0 + lastdreg - 1)
3327             return 0;
3328           else
3329             lastdreg--;
3330         }
3331     }
3332   first_dreg_to_save = lastdreg;
3333   first_preg_to_save = lastpreg;
3334   n_regs_to_save = 8 - first_dreg_to_save + 6 - first_preg_to_save;
3335   return 1;
3336 }
3337
3338 /* Emit assembly code for one multi-register push described by INSN, with
3339    operands in OPERANDS.  */
3340
3341 void
3342 output_push_multiple (rtx insn, rtx *operands)
3343 {
3344   char buf[80];
3345   int ok;
3346   
3347   /* Validate the insn again, and compute first_[dp]reg_to_save. */
3348   ok = push_multiple_operation (PATTERN (insn), VOIDmode);
3349   gcc_assert (ok);
3350   
3351   if (first_dreg_to_save == 8)
3352     sprintf (buf, "[--sp] = ( p5:%d );\n", first_preg_to_save);
3353   else if (first_preg_to_save == 6)
3354     sprintf (buf, "[--sp] = ( r7:%d );\n", first_dreg_to_save);
3355   else
3356     sprintf (buf, "[--sp] = ( r7:%d, p5:%d );\n",
3357              first_dreg_to_save, first_preg_to_save);
3358
3359   output_asm_insn (buf, operands);
3360 }
3361
3362 /* Emit assembly code for one multi-register pop described by INSN, with
3363    operands in OPERANDS.  */
3364
3365 void
3366 output_pop_multiple (rtx insn, rtx *operands)
3367 {
3368   char buf[80];
3369   int ok;
3370   
3371   /* Validate the insn again, and compute first_[dp]reg_to_save. */
3372   ok = pop_multiple_operation (PATTERN (insn), VOIDmode);
3373   gcc_assert (ok);
3374
3375   if (first_dreg_to_save == 8)
3376     sprintf (buf, "( p5:%d ) = [sp++];\n", first_preg_to_save);
3377   else if (first_preg_to_save == 6)
3378     sprintf (buf, "( r7:%d ) = [sp++];\n", first_dreg_to_save);
3379   else
3380     sprintf (buf, "( r7:%d, p5:%d ) = [sp++];\n",
3381              first_dreg_to_save, first_preg_to_save);
3382
3383   output_asm_insn (buf, operands);
3384 }
3385
3386 /* Adjust DST and SRC by OFFSET bytes, and generate one move in mode MODE.  */
3387
3388 static void
3389 single_move_for_movmem (rtx dst, rtx src, enum machine_mode mode, HOST_WIDE_INT offset)
3390 {
3391   rtx scratch = gen_reg_rtx (mode);
3392   rtx srcmem, dstmem;
3393
3394   srcmem = adjust_address_nv (src, mode, offset);
3395   dstmem = adjust_address_nv (dst, mode, offset);
3396   emit_move_insn (scratch, srcmem);
3397   emit_move_insn (dstmem, scratch);
3398 }
3399
3400 /* Expand a string move operation of COUNT_EXP bytes from SRC to DST, with
3401    alignment ALIGN_EXP.  Return true if successful, false if we should fall
3402    back on a different method.  */
3403
3404 bool
3405 bfin_expand_movmem (rtx dst, rtx src, rtx count_exp, rtx align_exp)
3406 {
3407   rtx srcreg, destreg, countreg;
3408   HOST_WIDE_INT align = 0;
3409   unsigned HOST_WIDE_INT count = 0;
3410
3411   if (GET_CODE (align_exp) == CONST_INT)
3412     align = INTVAL (align_exp);
3413   if (GET_CODE (count_exp) == CONST_INT)
3414     {
3415       count = INTVAL (count_exp);
3416 #if 0
3417       if (!TARGET_INLINE_ALL_STRINGOPS && count > 64)
3418         return false;
3419 #endif
3420     }
3421
3422   /* If optimizing for size, only do single copies inline.  */
3423   if (optimize_size)
3424     {
3425       if (count == 2 && align < 2)
3426         return false;
3427       if (count == 4 && align < 4)
3428         return false;
3429       if (count != 1 && count != 2 && count != 4)
3430         return false;
3431     }
3432   if (align < 2 && count != 1)
3433     return false;
3434
3435   destreg = copy_to_mode_reg (Pmode, XEXP (dst, 0));
3436   if (destreg != XEXP (dst, 0))
3437     dst = replace_equiv_address_nv (dst, destreg);
3438   srcreg = copy_to_mode_reg (Pmode, XEXP (src, 0));
3439   if (srcreg != XEXP (src, 0))
3440     src = replace_equiv_address_nv (src, srcreg);
3441
3442   if (count != 0 && align >= 2)
3443     {
3444       unsigned HOST_WIDE_INT offset = 0;
3445
3446       if (align >= 4)
3447         {
3448           if ((count & ~3) == 4)
3449             {
3450               single_move_for_movmem (dst, src, SImode, offset);
3451               offset = 4;
3452             }
3453           else if (count & ~3)
3454             {
3455               HOST_WIDE_INT new_count = ((count >> 2) & 0x3fffffff) - 1;
3456               countreg = copy_to_mode_reg (Pmode, GEN_INT (new_count));
3457
3458               emit_insn (gen_rep_movsi (destreg, srcreg, countreg, destreg, srcreg));
3459               cfun->machine->has_loopreg_clobber = true;
3460             }
3461           if (count & 2)
3462             {
3463               single_move_for_movmem (dst, src, HImode, offset);
3464               offset += 2;
3465             }
3466         }
3467       else
3468         {
3469           if ((count & ~1) == 2)
3470             {
3471               single_move_for_movmem (dst, src, HImode, offset);
3472               offset = 2;
3473             }
3474           else if (count & ~1)
3475             {
3476               HOST_WIDE_INT new_count = ((count >> 1) & 0x7fffffff) - 1;
3477               countreg = copy_to_mode_reg (Pmode, GEN_INT (new_count));
3478
3479               emit_insn (gen_rep_movhi (destreg, srcreg, countreg, destreg, srcreg));
3480               cfun->machine->has_loopreg_clobber = true;
3481             }
3482         }
3483       if (count & 1)
3484         {
3485           single_move_for_movmem (dst, src, QImode, offset);
3486         }
3487       return true;
3488     }
3489   return false;
3490 }
3491 \f
3492 /* Compute the alignment for a local variable.
3493    TYPE is the data type, and ALIGN is the alignment that
3494    the object would ordinarily have.  The value of this macro is used
3495    instead of that alignment to align the object.  */
3496
3497 int
3498 bfin_local_alignment (tree type, int align)
3499 {
3500   /* Increasing alignment for (relatively) big types allows the builtin
3501      memcpy can use 32 bit loads/stores.  */
3502   if (TYPE_SIZE (type)
3503       && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
3504       && (TREE_INT_CST_LOW (TYPE_SIZE (type)) > 8
3505           || TREE_INT_CST_HIGH (TYPE_SIZE (type))) && align < 32)
3506     return 32;
3507   return align;
3508 }
3509 \f
3510 /* Implement TARGET_SCHED_ISSUE_RATE.  */
3511
3512 static int
3513 bfin_issue_rate (void)
3514 {
3515   return 3;
3516 }
3517
3518 static int
3519 bfin_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
3520 {
3521   enum attr_type insn_type, dep_insn_type;
3522   int dep_insn_code_number;
3523
3524   /* Anti and output dependencies have zero cost.  */
3525   if (REG_NOTE_KIND (link) != 0)
3526     return 0;
3527
3528   dep_insn_code_number = recog_memoized (dep_insn);
3529
3530   /* If we can't recognize the insns, we can't really do anything.  */
3531   if (dep_insn_code_number < 0 || recog_memoized (insn) < 0)
3532     return cost;
3533
3534   insn_type = get_attr_type (insn);
3535   dep_insn_type = get_attr_type (dep_insn);
3536
3537   if (dep_insn_type == TYPE_MOVE || dep_insn_type == TYPE_MCLD)
3538     {
3539       rtx pat = PATTERN (dep_insn);
3540       if (GET_CODE (pat) == PARALLEL)
3541         pat = XVECEXP (pat, 0, 0);
3542       rtx dest = SET_DEST (pat);
3543       rtx src = SET_SRC (pat);
3544       if (! ADDRESS_REGNO_P (REGNO (dest))
3545           || ! (MEM_P (src) || D_REGNO_P (REGNO (src))))
3546         return cost;
3547       return cost + (dep_insn_type == TYPE_MOVE ? 4 : 3);
3548     }
3549
3550   return cost;
3551 }
3552 \f
3553 /* This function acts like NEXT_INSN, but is aware of three-insn bundles and
3554    skips all subsequent parallel instructions if INSN is the start of such
3555    a group.  */
3556 static rtx
3557 find_next_insn_start (rtx insn)
3558 {
3559   if (GET_MODE (insn) == SImode)
3560     {
3561       while (GET_MODE (insn) != QImode)
3562         insn = NEXT_INSN (insn);
3563     }
3564   return NEXT_INSN (insn);
3565 }
3566
3567 /* This function acts like PREV_INSN, but is aware of three-insn bundles and
3568    skips all subsequent parallel instructions if INSN is the start of such
3569    a group.  */
3570 static rtx
3571 find_prev_insn_start (rtx insn)
3572 {
3573   insn = PREV_INSN (insn);
3574   gcc_assert (GET_MODE (insn) != SImode);
3575   if (GET_MODE (insn) == QImode)
3576     {
3577       while (GET_MODE (PREV_INSN (insn)) == SImode)
3578         insn = PREV_INSN (insn);
3579     }
3580   return insn;
3581 }
3582 \f
3583 /* Increment the counter for the number of loop instructions in the
3584    current function.  */
3585
3586 void
3587 bfin_hardware_loop (void)
3588 {
3589   cfun->machine->has_hardware_loops++;
3590 }
3591
3592 /* Maximum loop nesting depth.  */
3593 #define MAX_LOOP_DEPTH 2
3594
3595 /* Maximum size of a loop.  */
3596 #define MAX_LOOP_LENGTH 2042
3597
3598 /* Maximum distance of the LSETUP instruction from the loop start.  */
3599 #define MAX_LSETUP_DISTANCE 30
3600
3601 /* We need to keep a vector of loops */
3602 typedef struct loop_info *loop_info;
3603 DEF_VEC_P (loop_info);
3604 DEF_VEC_ALLOC_P (loop_info,heap);
3605
3606 /* Information about a loop we have found (or are in the process of
3607    finding).  */
3608 struct GTY (()) loop_info
3609 {
3610   /* loop number, for dumps */
3611   int loop_no;
3612
3613   /* All edges that jump into and out of the loop.  */
3614   VEC(edge,gc) *incoming;
3615
3616   /* We can handle two cases: all incoming edges have the same destination
3617      block, or all incoming edges have the same source block.  These two
3618      members are set to the common source or destination we found, or NULL
3619      if different blocks were found.  If both are NULL the loop can't be
3620      optimized.  */
3621   basic_block incoming_src;
3622   basic_block incoming_dest;
3623
3624   /* First block in the loop.  This is the one branched to by the loop_end
3625      insn.  */
3626   basic_block head;
3627
3628   /* Last block in the loop (the one with the loop_end insn).  */
3629   basic_block tail;
3630
3631   /* The successor block of the loop.  This is the one the loop_end insn
3632      falls into.  */
3633   basic_block successor;
3634
3635   /* The last instruction in the tail.  */
3636   rtx last_insn;
3637
3638   /* The loop_end insn.  */
3639   rtx loop_end;
3640
3641   /* The iteration register.  */
3642   rtx iter_reg;
3643
3644   /* The new label placed at the beginning of the loop. */
3645   rtx start_label;
3646
3647   /* The new label placed at the end of the loop. */
3648   rtx end_label;
3649
3650   /* The length of the loop.  */
3651   int length;
3652
3653   /* The nesting depth of the loop.  */
3654   int depth;
3655
3656   /* Nonzero if we can't optimize this loop.  */
3657   int bad;
3658
3659   /* True if we have visited this loop.  */
3660   int visited;
3661
3662   /* True if this loop body clobbers any of LC0, LT0, or LB0.  */
3663   int clobber_loop0;
3664
3665   /* True if this loop body clobbers any of LC1, LT1, or LB1.  */
3666   int clobber_loop1;
3667
3668   /* Next loop in the graph. */
3669   struct loop_info *next;
3670
3671   /* Immediate outer loop of this loop.  */
3672   struct loop_info *outer;
3673
3674   /* Vector of blocks only within the loop, including those within
3675      inner loops.  */
3676   VEC (basic_block,heap) *blocks;
3677
3678   /* Same information in a bitmap.  */
3679   bitmap block_bitmap;
3680
3681   /* Vector of inner loops within this loop  */
3682   VEC (loop_info,heap) *loops;
3683 };
3684
3685 static void
3686 bfin_dump_loops (loop_info loops)
3687 {
3688   loop_info loop;
3689
3690   for (loop = loops; loop; loop = loop->next)
3691     {
3692       loop_info i;
3693       basic_block b;
3694       unsigned ix;
3695
3696       fprintf (dump_file, ";; loop %d: ", loop->loop_no);
3697       if (loop->bad)
3698         fprintf (dump_file, "(bad) ");
3699       fprintf (dump_file, "{head:%d, depth:%d}", loop->head->index, loop->depth);
3700
3701       fprintf (dump_file, " blocks: [ ");
3702       for (ix = 0; VEC_iterate (basic_block, loop->blocks, ix, b); ix++)
3703         fprintf (dump_file, "%d ", b->index);
3704       fprintf (dump_file, "] ");
3705
3706       fprintf (dump_file, " inner loops: [ ");
3707       for (ix = 0; VEC_iterate (loop_info, loop->loops, ix, i); ix++)
3708         fprintf (dump_file, "%d ", i->loop_no);
3709       fprintf (dump_file, "]\n");
3710     }
3711   fprintf (dump_file, "\n");
3712 }
3713
3714 /* Scan the blocks of LOOP (and its inferiors) looking for basic block
3715    BB. Return true, if we find it.  */
3716
3717 static bool
3718 bfin_bb_in_loop (loop_info loop, basic_block bb)
3719 {
3720   return bitmap_bit_p (loop->block_bitmap, bb->index);
3721 }
3722
3723 /* Scan the blocks of LOOP (and its inferiors) looking for uses of
3724    REG.  Return true, if we find any.  Don't count the loop's loop_end
3725    insn if it matches LOOP_END.  */
3726
3727 static bool
3728 bfin_scan_loop (loop_info loop, rtx reg, rtx loop_end)
3729 {
3730   unsigned ix;
3731   basic_block bb;
3732
3733   for (ix = 0; VEC_iterate (basic_block, loop->blocks, ix, bb); ix++)
3734     {
3735       rtx insn;
3736
3737       for (insn = BB_HEAD (bb);
3738            insn != NEXT_INSN (BB_END (bb));
3739            insn = NEXT_INSN (insn))
3740         {
3741           if (!INSN_P (insn))
3742             continue;
3743           if (insn == loop_end)
3744             continue;
3745           if (reg_mentioned_p (reg, PATTERN (insn)))
3746             return true;
3747         }
3748     }
3749   return false;
3750 }
3751
3752 /* Estimate the length of INSN conservatively.  */
3753
3754 static int
3755 length_for_loop (rtx insn)
3756 {
3757   int length = 0;
3758   if (JUMP_P (insn) && any_condjump_p (insn) && !optimize_size)
3759     {
3760       if (ENABLE_WA_SPECULATIVE_SYNCS)
3761         length = 8;
3762       else if (ENABLE_WA_SPECULATIVE_LOADS)
3763         length = 6;
3764     }
3765   else if (LABEL_P (insn))
3766     {
3767       if (ENABLE_WA_SPECULATIVE_SYNCS)
3768         length = 4;
3769     }
3770
3771   if (INSN_P (insn))
3772     length += get_attr_length (insn);
3773
3774   return length;
3775 }
3776
3777 /* Optimize LOOP.  */
3778
3779 static void
3780 bfin_optimize_loop (loop_info loop)
3781 {
3782   basic_block bb;
3783   loop_info inner;
3784   rtx insn, last_insn;
3785   rtx loop_init, start_label, end_label;
3786   rtx reg_lc0, reg_lc1, reg_lt0, reg_lt1, reg_lb0, reg_lb1;
3787   rtx iter_reg, scratchreg, scratch_init, scratch_init_insn;
3788   rtx lc_reg, lt_reg, lb_reg;
3789   rtx seq, seq_end;
3790   int length;
3791   unsigned ix;
3792   int inner_depth = 0;
3793
3794   if (loop->visited)
3795     return;
3796
3797   loop->visited = 1;
3798
3799   if (loop->bad)
3800     {
3801       if (dump_file)
3802         fprintf (dump_file, ";; loop %d bad when found\n", loop->loop_no);
3803       goto bad_loop;
3804     }
3805
3806   /* Every loop contains in its list of inner loops every loop nested inside
3807      it, even if there are intermediate loops.  This works because we're doing
3808      a depth-first search here and never visit a loop more than once.  */
3809   for (ix = 0; VEC_iterate (loop_info, loop->loops, ix, inner); ix++)
3810     {
3811       bfin_optimize_loop (inner);
3812
3813       if (!inner->bad && inner_depth < inner->depth)
3814         {
3815           inner_depth = inner->depth;
3816
3817           loop->clobber_loop0 |= inner->clobber_loop0;
3818           loop->clobber_loop1 |= inner->clobber_loop1;
3819         }
3820     }
3821
3822   loop->depth = inner_depth + 1;
3823   if (loop->depth > MAX_LOOP_DEPTH)
3824     {
3825       if (dump_file)
3826         fprintf (dump_file, ";; loop %d too deep\n", loop->loop_no);
3827       goto bad_loop;
3828     }
3829
3830   /* Get the loop iteration register.  */
3831   iter_reg = loop->iter_reg;
3832
3833   if (!REG_P (iter_reg))
3834     {
3835       if (dump_file)
3836         fprintf (dump_file, ";; loop %d iteration count not in a register\n",
3837                  loop->loop_no);
3838       goto bad_loop;
3839     }
3840   scratchreg = NULL_RTX;
3841   scratch_init = iter_reg;
3842   scratch_init_insn = NULL_RTX;
3843   if (!PREG_P (iter_reg) && loop->incoming_src)
3844     {
3845       basic_block bb_in = loop->incoming_src;
3846       int i;
3847       for (i = REG_P0; i <= REG_P5; i++)
3848         if ((df_regs_ever_live_p (i)
3849              || (funkind (TREE_TYPE (current_function_decl)) == SUBROUTINE
3850                  && call_used_regs[i]))
3851             && !REGNO_REG_SET_P (df_get_live_out (bb_in), i))
3852           {
3853             scratchreg = gen_rtx_REG (SImode, i);
3854             break;
3855           }
3856       for (insn = BB_END (bb_in); insn != BB_HEAD (bb_in);
3857            insn = PREV_INSN (insn))
3858         {
3859           rtx set;
3860           if (NOTE_P (insn) || BARRIER_P (insn))
3861             continue;
3862           set = single_set (insn);
3863           if (set && rtx_equal_p (SET_DEST (set), iter_reg))
3864             {
3865               if (CONSTANT_P (SET_SRC (set)))
3866                 {
3867                   scratch_init = SET_SRC (set);
3868                   scratch_init_insn = insn;
3869                 }
3870               break;
3871             }
3872           else if (reg_mentioned_p (iter_reg, PATTERN (insn)))
3873             break;
3874         }
3875     }
3876
3877   if (loop->incoming_src)
3878     {
3879       /* Make sure the predecessor is before the loop start label, as required by
3880          the LSETUP instruction.  */
3881       length = 0;
3882       insn = BB_END (loop->incoming_src);
3883       /* If we have to insert the LSETUP before a jump, count that jump in the
3884          length.  */
3885       if (VEC_length (edge, loop->incoming) > 1
3886           || !(VEC_last (edge, loop->incoming)->flags & EDGE_FALLTHRU))
3887         {
3888           gcc_assert (JUMP_P (insn));
3889           insn = PREV_INSN (insn);
3890         }
3891
3892       for (; insn && insn != loop->start_label; insn = NEXT_INSN (insn))
3893         length += length_for_loop (insn);
3894
3895       if (!insn)
3896         {
3897           if (dump_file)
3898             fprintf (dump_file, ";; loop %d lsetup not before loop_start\n",
3899                      loop->loop_no);
3900           goto bad_loop;
3901         }
3902
3903       /* Account for the pop of a scratch register where necessary.  */
3904       if (!PREG_P (iter_reg) && scratchreg == NULL_RTX
3905           && ENABLE_WA_LOAD_LCREGS)
3906         length += 2;
3907
3908       if (length > MAX_LSETUP_DISTANCE)
3909         {
3910           if (dump_file)
3911             fprintf (dump_file, ";; loop %d lsetup too far away\n", loop->loop_no);
3912           goto bad_loop;
3913         }
3914     }
3915
3916   /* Check if start_label appears before loop_end and calculate the
3917      offset between them.  We calculate the length of instructions
3918      conservatively.  */
3919   length = 0;
3920   for (insn = loop->start_label;
3921        insn && insn != loop->loop_end;
3922        insn = NEXT_INSN (insn))
3923     length += length_for_loop (insn);
3924
3925   if (!insn)
3926     {
3927       if (dump_file)
3928         fprintf (dump_file, ";; loop %d start_label not before loop_end\n",
3929                  loop->loop_no);
3930       goto bad_loop;
3931     }
3932
3933   loop->length = length;
3934   if (loop->length > MAX_LOOP_LENGTH)
3935     {
3936       if (dump_file)
3937         fprintf (dump_file, ";; loop %d too long\n", loop->loop_no);
3938       goto bad_loop;
3939     }
3940
3941   /* Scan all the blocks to make sure they don't use iter_reg.  */
3942   if (bfin_scan_loop (loop, iter_reg, loop->loop_end))
3943     {
3944       if (dump_file)
3945         fprintf (dump_file, ";; loop %d uses iterator\n", loop->loop_no);
3946       goto bad_loop;
3947     }
3948
3949   /* Scan all the insns to see if the loop body clobber
3950      any hardware loop registers. */
3951
3952   reg_lc0 = gen_rtx_REG (SImode, REG_LC0);
3953   reg_lc1 = gen_rtx_REG (SImode, REG_LC1);
3954   reg_lt0 = gen_rtx_REG (SImode, REG_LT0);
3955   reg_lt1 = gen_rtx_REG (SImode, REG_LT1);
3956   reg_lb0 = gen_rtx_REG (SImode, REG_LB0);
3957   reg_lb1 = gen_rtx_REG (SImode, REG_LB1);
3958
3959   for (ix = 0; VEC_iterate (basic_block, loop->blocks, ix, bb); ix++)
3960     {
3961       rtx insn;
3962
3963       for (insn = BB_HEAD (bb);
3964            insn != NEXT_INSN (BB_END (bb));
3965            insn = NEXT_INSN (insn))
3966         {
3967           if (!INSN_P (insn))
3968             continue;
3969
3970           if (reg_set_p (reg_lc0, insn)
3971               || reg_set_p (reg_lt0, insn)
3972               || reg_set_p (reg_lb0, insn))
3973             loop->clobber_loop0 = 1;
3974           
3975           if (reg_set_p (reg_lc1, insn)
3976               || reg_set_p (reg_lt1, insn)
3977               || reg_set_p (reg_lb1, insn))
3978             loop->clobber_loop1 |= 1;
3979         }
3980     }
3981
3982   if ((loop->clobber_loop0 && loop->clobber_loop1)
3983       || (loop->depth == MAX_LOOP_DEPTH && loop->clobber_loop0))
3984     {
3985       loop->depth = MAX_LOOP_DEPTH + 1;
3986       if (dump_file)
3987         fprintf (dump_file, ";; loop %d no loop reg available\n",
3988                  loop->loop_no);
3989       goto bad_loop;
3990     }
3991
3992   /* There should be an instruction before the loop_end instruction
3993      in the same basic block. And the instruction must not be
3994      - JUMP
3995      - CONDITIONAL BRANCH
3996      - CALL
3997      - CSYNC
3998      - SSYNC
3999      - Returns (RTS, RTN, etc.)  */
4000
4001   bb = loop->tail;
4002   last_insn = find_prev_insn_start (loop->loop_end);
4003
4004   while (1)
4005     {
4006       for (; last_insn != BB_HEAD (bb);
4007            last_insn = find_prev_insn_start (last_insn))
4008         if (INSN_P (last_insn))
4009           break;
4010
4011       if (last_insn != BB_HEAD (bb))
4012         break;
4013
4014       if (single_pred_p (bb)
4015           && single_pred_edge (bb)->flags & EDGE_FALLTHRU
4016           && single_pred (bb) != ENTRY_BLOCK_PTR)
4017         {
4018           bb = single_pred (bb);
4019           last_insn = BB_END (bb);
4020           continue;
4021         }
4022       else
4023         {
4024           last_insn = NULL_RTX;
4025           break;
4026         }
4027     }
4028
4029   if (!last_insn)
4030     {
4031       if (dump_file)
4032         fprintf (dump_file, ";; loop %d has no last instruction\n",
4033                  loop->loop_no);
4034       goto bad_loop;
4035     }
4036
4037   if (JUMP_P (last_insn) && !any_condjump_p (last_insn))
4038     {
4039       if (dump_file)
4040         fprintf (dump_file, ";; loop %d has bad last instruction\n",
4041                  loop->loop_no);
4042       goto bad_loop;
4043     }
4044   /* In all other cases, try to replace a bad last insn with a nop.  */
4045   else if (JUMP_P (last_insn)
4046            || CALL_P (last_insn)
4047            || get_attr_type (last_insn) == TYPE_SYNC
4048            || get_attr_type (last_insn) == TYPE_CALL
4049            || get_attr_seq_insns (last_insn) == SEQ_INSNS_MULTI
4050            || recog_memoized (last_insn) == CODE_FOR_return_internal
4051            || GET_CODE (PATTERN (last_insn)) == ASM_INPUT
4052            || asm_noperands (PATTERN (last_insn)) >= 0)
4053     {
4054       if (loop->length + 2 > MAX_LOOP_LENGTH)
4055         {
4056           if (dump_file)
4057             fprintf (dump_file, ";; loop %d too long\n", loop->loop_no);
4058           goto bad_loop;
4059         }
4060       if (dump_file)
4061         fprintf (dump_file, ";; loop %d has bad last insn; replace with nop\n",
4062                  loop->loop_no);
4063
4064       last_insn = emit_insn_after (gen_forced_nop (), last_insn);
4065     }
4066
4067   loop->last_insn = last_insn;
4068
4069   /* The loop is good for replacement.  */
4070   start_label = loop->start_label;
4071   end_label = gen_label_rtx ();
4072   iter_reg = loop->iter_reg;
4073
4074   if (loop->depth == 1 && !loop->clobber_loop1)
4075     {
4076       lc_reg = reg_lc1;
4077       lt_reg = reg_lt1;
4078       lb_reg = reg_lb1;
4079       loop->clobber_loop1 = 1;
4080     }
4081   else
4082     {
4083       lc_reg = reg_lc0;
4084       lt_reg = reg_lt0;
4085       lb_reg = reg_lb0;
4086       loop->clobber_loop0 = 1;
4087     }
4088
4089   loop->end_label = end_label;
4090
4091   /* Create a sequence containing the loop setup.  */
4092   start_sequence ();
4093
4094   /* LSETUP only accepts P registers.  If we have one, we can use it,
4095      otherwise there are several ways of working around the problem.
4096      If we're not affected by anomaly 312, we can load the LC register
4097      from any iteration register, and use LSETUP without initialization.
4098      If we've found a P scratch register that's not live here, we can
4099      instead copy the iter_reg into that and use an initializing LSETUP.
4100      If all else fails, push and pop P0 and use it as a scratch.  */
4101   if (P_REGNO_P (REGNO (iter_reg)))
4102     {
4103       loop_init = gen_lsetup_with_autoinit (lt_reg, start_label,
4104                                             lb_reg, end_label,
4105                                             lc_reg, iter_reg);
4106       seq_end = emit_insn (loop_init);
4107     }
4108   else if (!ENABLE_WA_LOAD_LCREGS && DPREG_P (iter_reg))
4109     {
4110       emit_insn (gen_movsi (lc_reg, iter_reg));
4111       loop_init = gen_lsetup_without_autoinit (lt_reg, start_label,
4112                                                lb_reg, end_label,
4113                                                lc_reg);
4114       seq_end = emit_insn (loop_init);
4115     }
4116   else if (scratchreg != NULL_RTX)
4117     {
4118       emit_insn (gen_movsi (scratchreg, scratch_init));
4119       loop_init = gen_lsetup_with_autoinit (lt_reg, start_label,
4120                                             lb_reg, end_label,
4121                                             lc_reg, scratchreg);
4122       seq_end = emit_insn (loop_init);
4123       if (scratch_init_insn != NULL_RTX)
4124         delete_insn (scratch_init_insn);
4125     }
4126   else
4127     {
4128       rtx p0reg = gen_rtx_REG (SImode, REG_P0);
4129       rtx push = gen_frame_mem (SImode,
4130                                 gen_rtx_PRE_DEC (SImode, stack_pointer_rtx));
4131       rtx pop = gen_frame_mem (SImode,
4132                                gen_rtx_POST_INC (SImode, stack_pointer_rtx));
4133       emit_insn (gen_movsi (push, p0reg));
4134       emit_insn (gen_movsi (p0reg, scratch_init));
4135       loop_init = gen_lsetup_with_autoinit (lt_reg, start_label,
4136                                             lb_reg, end_label,
4137                                             lc_reg, p0reg);
4138       emit_insn (loop_init);
4139       seq_end = emit_insn (gen_movsi (p0reg, pop));
4140       if (scratch_init_insn != NULL_RTX)
4141         delete_insn (scratch_init_insn);
4142     }
4143
4144   if (dump_file)
4145     {
4146       fprintf (dump_file, ";; replacing loop %d initializer with\n",
4147                loop->loop_no);
4148       print_rtl_single (dump_file, loop_init);
4149       fprintf (dump_file, ";; replacing loop %d terminator with\n",
4150                loop->loop_no);
4151       print_rtl_single (dump_file, loop->loop_end);
4152     }
4153
4154   /* If the loop isn't entered at the top, also create a jump to the entry
4155      point.  */
4156   if (!loop->incoming_src && loop->head != loop->incoming_dest)
4157     {
4158       rtx label = BB_HEAD (loop->incoming_dest);
4159       /* If we're jumping to the final basic block in the loop, and there's
4160          only one cheap instruction before the end (typically an increment of
4161          an induction variable), we can just emit a copy here instead of a
4162          jump.  */
4163       if (loop->incoming_dest == loop->tail
4164           && next_real_insn (label) == last_insn
4165           && asm_noperands (last_insn) < 0
4166           && GET_CODE (PATTERN (last_insn)) == SET)
4167         {
4168           seq_end = emit_insn (copy_rtx (PATTERN (last_insn)));
4169         }
4170       else
4171         seq_end = emit_jump_insn (gen_jump (label));
4172     }
4173
4174   seq = get_insns ();
4175   end_sequence ();
4176
4177   if (loop->incoming_src)
4178     {
4179       rtx prev = BB_END (loop->incoming_src);
4180       if (VEC_length (edge, loop->incoming) > 1
4181           || !(VEC_last (edge, loop->incoming)->flags & EDGE_FALLTHRU))
4182         {
4183           gcc_assert (JUMP_P (prev));
4184           prev = PREV_INSN (prev);
4185         }
4186       emit_insn_after (seq, prev);
4187     }
4188   else
4189     {
4190       basic_block new_bb;
4191       edge e;
4192       edge_iterator ei;
4193
4194 #ifdef ENABLE_CHECKING
4195       if (loop->head != loop->incoming_dest)
4196         {
4197           /* We aren't entering the loop at the top.  Since we've established
4198              that the loop is entered only at one point, this means there
4199              can't be fallthru edges into the head.  Any such fallthru edges
4200              would become invalid when we insert the new block, so verify
4201              that this does not in fact happen.  */
4202           FOR_EACH_EDGE (e, ei, loop->head->preds)
4203             gcc_assert (!(e->flags & EDGE_FALLTHRU));
4204         }
4205 #endif
4206
4207       emit_insn_before (seq, BB_HEAD (loop->head));
4208       seq = emit_label_before (gen_label_rtx (), seq);
4209
4210       new_bb = create_basic_block (seq, seq_end, loop->head->prev_bb);
4211       FOR_EACH_EDGE (e, ei, loop->incoming)
4212         {
4213           if (!(e->flags & EDGE_FALLTHRU)
4214               || e->dest != loop->head)
4215             redirect_edge_and_branch_force (e, new_bb);
4216           else
4217             redirect_edge_succ (e, new_bb);
4218         }
4219     }
4220
4221   delete_insn (loop->loop_end);
4222   /* Insert the loop end label before the last instruction of the loop.  */
4223   emit_label_before (loop->end_label, loop->last_insn);
4224
4225   return;
4226
4227  bad_loop:
4228
4229   if (dump_file)
4230     fprintf (dump_file, ";; loop %d is bad\n", loop->loop_no);
4231
4232   loop->bad = 1;
4233
4234   if (DPREG_P (loop->iter_reg))
4235     {
4236       /* If loop->iter_reg is a DREG or PREG, we can split it here
4237          without scratch register.  */
4238       rtx insn;
4239
4240       emit_insn_before (gen_addsi3 (loop->iter_reg,
4241                                     loop->iter_reg,
4242                                     constm1_rtx),
4243                         loop->loop_end);
4244
4245       emit_insn_before (gen_cmpsi (loop->iter_reg, const0_rtx),
4246                         loop->loop_end);
4247
4248       insn = emit_jump_insn_before (gen_bne (loop->start_label),
4249                                     loop->loop_end);
4250
4251       JUMP_LABEL (insn) = loop->start_label;
4252       LABEL_NUSES (loop->start_label)++;
4253       delete_insn (loop->loop_end);
4254     }
4255 }
4256
4257 /* Called from bfin_reorg_loops when a potential loop end is found.  LOOP is
4258    a newly set up structure describing the loop, it is this function's
4259    responsibility to fill most of it.  TAIL_BB and TAIL_INSN point to the
4260    loop_end insn and its enclosing basic block.  */
4261
4262 static void
4263 bfin_discover_loop (loop_info loop, basic_block tail_bb, rtx tail_insn)
4264 {
4265   unsigned dwork = 0;
4266   basic_block bb;
4267   VEC (basic_block,heap) *works = VEC_alloc (basic_block,heap,20);
4268
4269   loop->tail = tail_bb;
4270   loop->head = BRANCH_EDGE (tail_bb)->dest;
4271   loop->successor = FALLTHRU_EDGE (tail_bb)->dest;
4272   loop->loop_end = tail_insn;
4273   loop->last_insn = NULL_RTX;
4274   loop->iter_reg = SET_DEST (XVECEXP (PATTERN (tail_insn), 0, 1));
4275   loop->depth = loop->length = 0;
4276   loop->visited = 0;
4277   loop->clobber_loop0 = loop->clobber_loop1 = 0;
4278   loop->outer = NULL;
4279   loop->loops = NULL;
4280   loop->incoming = VEC_alloc (edge, gc, 2);
4281   loop->start_label = XEXP (XEXP (SET_SRC (XVECEXP (PATTERN (tail_insn), 0, 0)), 1), 0);
4282   loop->end_label = NULL_RTX;
4283   loop->bad = 0;
4284
4285   VEC_safe_push (basic_block, heap, works, loop->head);
4286
4287   while (VEC_iterate (basic_block, works, dwork++, bb))
4288     {
4289       edge e;
4290       edge_iterator ei;
4291       if (bb == EXIT_BLOCK_PTR)
4292         {
4293           /* We've reached the exit block.  The loop must be bad. */
4294           if (dump_file)
4295             fprintf (dump_file,
4296                      ";; Loop is bad - reached exit block while scanning\n");
4297           loop->bad = 1;
4298           break;
4299         }
4300
4301       if (bitmap_bit_p (loop->block_bitmap, bb->index))
4302         continue;
4303
4304       /* We've not seen this block before.  Add it to the loop's
4305          list and then add each successor to the work list.  */
4306
4307       VEC_safe_push (basic_block, heap, loop->blocks, bb);
4308       bitmap_set_bit (loop->block_bitmap, bb->index);
4309
4310       if (bb != tail_bb)
4311         {
4312           FOR_EACH_EDGE (e, ei, bb->succs)
4313             {
4314               basic_block succ = EDGE_SUCC (bb, ei.index)->dest;
4315               if (!REGNO_REG_SET_P (df_get_live_in (succ),
4316                                     REGNO (loop->iter_reg)))
4317                 continue;
4318               if (!VEC_space (basic_block, works, 1))
4319                 {
4320                   if (dwork)
4321                     {
4322                       VEC_block_remove (basic_block, works, 0, dwork);
4323                       dwork = 0;
4324                     }
4325                   else
4326                     VEC_reserve (basic_block, heap, works, 1);
4327                 }
4328               VEC_quick_push (basic_block, works, succ);
4329             }
4330         }
4331     }
4332
4333   /* Find the predecessor, and make sure nothing else jumps into this loop.  */
4334   if (!loop->bad)
4335     {
4336       int pass, retry;
4337       for (dwork = 0; VEC_iterate (basic_block, loop->blocks, dwork, bb); dwork++)
4338         {
4339           edge e;
4340           edge_iterator ei;
4341           FOR_EACH_EDGE (e, ei, bb->preds)
4342             {
4343               basic_block pred = e->src;
4344
4345               if (!bfin_bb_in_loop (loop, pred))
4346                 {
4347                   if (dump_file)
4348                     fprintf (dump_file, ";; Loop %d: incoming edge %d -> %d\n",
4349                              loop->loop_no, pred->index,
4350                              e->dest->index);
4351                   VEC_safe_push (edge, gc, loop->incoming, e);
4352                 }
4353             }
4354         }
4355
4356       for (pass = 0, retry = 1; retry && pass < 2; pass++)
4357         {
4358           edge e;
4359           edge_iterator ei;
4360           bool first = true;
4361           retry = 0;
4362
4363           FOR_EACH_EDGE (e, ei, loop->incoming)
4364             {
4365               if (first)
4366                 {
4367                   loop->incoming_src = e->src;
4368                   loop->incoming_dest = e->dest;
4369                   first = false;
4370                 }
4371               else
4372                 {
4373                   if (e->dest != loop->incoming_dest)
4374                     loop->incoming_dest = NULL;
4375                   if (e->src != loop->incoming_src)
4376                     loop->incoming_src = NULL;
4377                 }
4378               if (loop->incoming_src == NULL && loop->incoming_dest == NULL)
4379                 {
4380                   if (pass == 0)
4381                     {
4382                       if (dump_file)
4383                         fprintf (dump_file,
4384                                  ";; retrying loop %d with forwarder blocks\n",
4385                                  loop->loop_no);
4386                       retry = 1;
4387                       break;
4388                     }
4389                   loop->bad = 1;
4390                   if (dump_file)
4391                     fprintf (dump_file,
4392                              ";; can't find suitable entry for loop %d\n",
4393                              loop->loop_no);
4394                   goto out;
4395                 }
4396             }
4397           if (retry)
4398             {
4399               retry = 0;
4400               FOR_EACH_EDGE (e, ei, loop->incoming)
4401                 {
4402                   if (forwarder_block_p (e->src))
4403                     {
4404                       edge e2;
4405                       edge_iterator ei2;
4406
4407                       if (dump_file)
4408                         fprintf (dump_file,
4409                                  ";; Adding forwarder block %d to loop %d and retrying\n",
4410                                  e->src->index, loop->loop_no);
4411                       VEC_safe_push (basic_block, heap, loop->blocks, e->src);
4412                       bitmap_set_bit (loop->block_bitmap, e->src->index);
4413                       FOR_EACH_EDGE (e2, ei2, e->src->preds)
4414                         VEC_safe_push (edge, gc, loop->incoming, e2);
4415                       VEC_unordered_remove (edge, loop->incoming, ei.index);
4416                       retry = 1;
4417                       break;
4418                     }
4419                 }
4420               if (!retry)
4421                 {
4422                   if (dump_file)
4423                     fprintf (dump_file, ";; No forwarder blocks found\n");
4424                   loop->bad = 1;
4425                 }
4426             }
4427         }
4428     }
4429
4430  out:
4431   VEC_free (basic_block, heap, works);
4432 }
4433
4434 /* Analyze the structure of the loops in the current function.  Use STACK
4435    for bitmap allocations.  Returns all the valid candidates for hardware
4436    loops found in this function.  */
4437 static loop_info
4438 bfin_discover_loops (bitmap_obstack *stack, FILE *dump_file)
4439 {
4440   loop_info loops = NULL;
4441   loop_info loop;
4442   basic_block bb;
4443   bitmap tmp_bitmap;
4444   int nloops = 0;
4445
4446   /* Find all the possible loop tails.  This means searching for every
4447      loop_end instruction.  For each one found, create a loop_info
4448      structure and add the head block to the work list. */
4449   FOR_EACH_BB (bb)
4450     {
4451       rtx tail = BB_END (bb);
4452
4453       while (GET_CODE (tail) == NOTE)
4454         tail = PREV_INSN (tail);
4455
4456       bb->aux = NULL;
4457
4458       if (INSN_P (tail) && recog_memoized (tail) == CODE_FOR_loop_end)
4459         {
4460           rtx insn;
4461           /* A possible loop end */
4462
4463           /* There's a degenerate case we can handle - an empty loop consisting
4464              of only a back branch.  Handle that by deleting the branch.  */
4465           insn = BB_HEAD (BRANCH_EDGE (bb)->dest);
4466           if (next_real_insn (insn) == tail)
4467             {
4468               if (dump_file)
4469                 {
4470                   fprintf (dump_file, ";; degenerate loop ending at\n");
4471                   print_rtl_single (dump_file, tail);
4472                 }
4473               delete_insn_and_edges (tail);
4474               continue;
4475             }
4476
4477           loop = XNEW (struct loop_info);
4478           loop->next = loops;
4479           loops = loop;
4480           loop->loop_no = nloops++;
4481           loop->blocks = VEC_alloc (basic_block, heap, 20);
4482           loop->block_bitmap = BITMAP_ALLOC (stack);
4483           bb->aux = loop;
4484
4485           if (dump_file)
4486             {
4487               fprintf (dump_file, ";; potential loop %d ending at\n",
4488                        loop->loop_no);
4489               print_rtl_single (dump_file, tail);
4490             }
4491
4492           bfin_discover_loop (loop, bb, tail);
4493         }
4494     }
4495
4496   tmp_bitmap = BITMAP_ALLOC (stack);
4497   /* Compute loop nestings.  */
4498   for (loop = loops; loop; loop = loop->next)
4499     {
4500       loop_info other;
4501       if (loop->bad)
4502         continue;
4503
4504       for (other = loop->next; other; other = other->next)
4505         {
4506           if (other->bad)
4507             continue;
4508
4509           bitmap_and (tmp_bitmap, other->block_bitmap, loop->block_bitmap);
4510           if (bitmap_empty_p (tmp_bitmap))
4511             continue;
4512           if (bitmap_equal_p (tmp_bitmap, other->block_bitmap))
4513             {
4514               other->outer = loop;
4515               VEC_safe_push (loop_info, heap, loop->loops, other);
4516             }
4517           else if (bitmap_equal_p (tmp_bitmap, loop->block_bitmap))
4518             {
4519               loop->outer = other;
4520               VEC_safe_push (loop_info, heap, other->loops, loop);
4521             }
4522           else
4523             {
4524               if (dump_file)
4525                 fprintf (dump_file,
4526                          ";; can't find suitable nesting for loops %d and %d\n",
4527                          loop->loop_no, other->loop_no);
4528               loop->bad = other->bad = 1;
4529             }
4530         }
4531     }
4532   BITMAP_FREE (tmp_bitmap);
4533
4534   return loops;
4535 }
4536
4537 /* Free up the loop structures in LOOPS.  */
4538 static void
4539 free_loops (loop_info loops)
4540 {
4541   while (loops)
4542     {
4543       loop_info loop = loops;
4544       loops = loop->next;
4545       VEC_free (loop_info, heap, loop->loops);
4546       VEC_free (basic_block, heap, loop->blocks);
4547       BITMAP_FREE (loop->block_bitmap);
4548       XDELETE (loop);
4549     }
4550 }
4551
4552 #define BB_AUX_INDEX(BB) ((unsigned)(BB)->aux)
4553
4554 /* The taken-branch edge from the loop end can actually go forward.  Since the
4555    Blackfin's LSETUP instruction requires that the loop end be after the loop
4556    start, try to reorder a loop's basic blocks when we find such a case.  */
4557 static void
4558 bfin_reorder_loops (loop_info loops, FILE *dump_file)
4559 {
4560   basic_block bb;
4561   loop_info loop;
4562
4563   FOR_EACH_BB (bb)
4564     bb->aux = NULL;
4565   cfg_layout_initialize (0);
4566
4567   for (loop = loops; loop; loop = loop->next)
4568     {
4569       unsigned index;
4570       basic_block bb;
4571       edge e;
4572       edge_iterator ei;
4573
4574       if (loop->bad)
4575         continue;
4576
4577       /* Recreate an index for basic blocks that represents their order.  */
4578       for (bb = ENTRY_BLOCK_PTR->next_bb, index = 0;
4579            bb != EXIT_BLOCK_PTR;
4580            bb = bb->next_bb, index++)
4581         bb->aux = (PTR) index;
4582
4583       if (BB_AUX_INDEX (loop->head) < BB_AUX_INDEX (loop->tail))
4584         continue;
4585
4586       FOR_EACH_EDGE (e, ei, loop->head->succs)
4587         {
4588           if (bitmap_bit_p (loop->block_bitmap, e->dest->index)
4589               && BB_AUX_INDEX (e->dest) < BB_AUX_INDEX (loop->tail))
4590             {
4591               basic_block start_bb = e->dest;
4592               basic_block start_prev_bb = start_bb->prev_bb;
4593
4594               if (dump_file)
4595                 fprintf (dump_file, ";; Moving block %d before block %d\n",
4596                          loop->head->index, start_bb->index);
4597               loop->head->prev_bb->next_bb = loop->head->next_bb;
4598               loop->head->next_bb->prev_bb = loop->head->prev_bb;
4599
4600               loop->head->prev_bb = start_prev_bb;
4601               loop->head->next_bb = start_bb;
4602               start_prev_bb->next_bb = start_bb->prev_bb = loop->head;
4603               break;
4604             }
4605         }
4606       loops = loops->next;
4607     }
4608   
4609   FOR_EACH_BB (bb)
4610     {
4611       if (bb->next_bb != EXIT_BLOCK_PTR)
4612         bb->aux = bb->next_bb;
4613       else
4614         bb->aux = NULL;
4615     }
4616   cfg_layout_finalize ();
4617   df_analyze ();
4618 }
4619
4620 /* Run from machine_dependent_reorg, this pass looks for doloop_end insns
4621    and tries to rewrite the RTL of these loops so that proper Blackfin
4622    hardware loops are generated.  */
4623
4624 static void
4625 bfin_reorg_loops (FILE *dump_file)
4626 {
4627   loop_info loops = NULL;
4628   loop_info loop;
4629   basic_block bb;
4630   bitmap_obstack stack;
4631
4632   bitmap_obstack_initialize (&stack);
4633
4634   if (dump_file)
4635     fprintf (dump_file, ";; Find loops, first pass\n\n");
4636
4637   loops = bfin_discover_loops (&stack, dump_file);
4638
4639   if (dump_file)
4640     bfin_dump_loops (loops);
4641
4642   bfin_reorder_loops (loops, dump_file);
4643   free_loops (loops);
4644
4645   if (dump_file)
4646     fprintf (dump_file, ";; Find loops, second pass\n\n");
4647
4648   loops = bfin_discover_loops (&stack, dump_file);
4649   if (dump_file)
4650     {
4651       fprintf (dump_file, ";; All loops found:\n\n");
4652       bfin_dump_loops (loops);
4653     }
4654
4655   /* Now apply the optimizations.  */
4656   for (loop = loops; loop; loop = loop->next)
4657     bfin_optimize_loop (loop);
4658
4659   if (dump_file)
4660     {
4661       fprintf (dump_file, ";; After hardware loops optimization:\n\n");
4662       bfin_dump_loops (loops);
4663     }
4664
4665   free_loops (loops);
4666
4667   if (dump_file)
4668     print_rtl (dump_file, get_insns ());
4669
4670   FOR_EACH_BB (bb)
4671     bb->aux = NULL;
4672
4673   splitting_loops = 1;
4674   FOR_EACH_BB (bb)
4675     {
4676       rtx insn = BB_END (bb);
4677       if (!JUMP_P (insn))
4678         continue;
4679
4680       try_split (PATTERN (insn), insn, 1);
4681     }
4682   splitting_loops = 0;
4683 }
4684 \f
4685 /* Possibly generate a SEQUENCE out of three insns found in SLOT.
4686    Returns true if we modified the insn chain, false otherwise.  */
4687 static bool
4688 gen_one_bundle (rtx slot[3])
4689 {
4690   gcc_assert (slot[1] != NULL_RTX);
4691
4692   /* Don't add extra NOPs if optimizing for size.  */
4693   if (optimize_size
4694       && (slot[0] == NULL_RTX || slot[2] == NULL_RTX))
4695     return false;
4696
4697   /* Verify that we really can do the multi-issue.  */
4698   if (slot[0])
4699     {
4700       rtx t = NEXT_INSN (slot[0]);
4701       while (t != slot[1])
4702         {
4703           if (GET_CODE (t) != NOTE
4704               || NOTE_KIND (t) != NOTE_INSN_DELETED)
4705             return false;
4706           t = NEXT_INSN (t);
4707         }
4708     }
4709   if (slot[2])
4710     {
4711       rtx t = NEXT_INSN (slot[1]);
4712       while (t != slot[2])
4713         {
4714           if (GET_CODE (t) != NOTE
4715               || NOTE_KIND (t) != NOTE_INSN_DELETED)
4716             return false;
4717           t = NEXT_INSN (t);
4718         }
4719     }
4720
4721   if (slot[0] == NULL_RTX)
4722     {
4723       slot[0] = emit_insn_before (gen_mnop (), slot[1]);
4724       df_insn_rescan (slot[0]);
4725     }
4726   if (slot[2] == NULL_RTX)
4727     {
4728       slot[2] = emit_insn_after (gen_forced_nop (), slot[1]);
4729       df_insn_rescan (slot[2]);
4730     }
4731
4732   /* Avoid line number information being printed inside one bundle.  */
4733   if (INSN_LOCATOR (slot[1])
4734       && INSN_LOCATOR (slot[1]) != INSN_LOCATOR (slot[0]))
4735     INSN_LOCATOR (slot[1]) = INSN_LOCATOR (slot[0]);
4736   if (INSN_LOCATOR (slot[2])
4737       && INSN_LOCATOR (slot[2]) != INSN_LOCATOR (slot[0]))
4738     INSN_LOCATOR (slot[2]) = INSN_LOCATOR (slot[0]);
4739
4740   /* Terminate them with "|| " instead of ";" in the output.  */
4741   PUT_MODE (slot[0], SImode);
4742   PUT_MODE (slot[1], SImode);
4743   /* Terminate the bundle, for the benefit of reorder_var_tracking_notes.  */
4744   PUT_MODE (slot[2], QImode);
4745   return true;
4746 }
4747
4748 /* Go through all insns, and use the information generated during scheduling
4749    to generate SEQUENCEs to represent bundles of instructions issued
4750    simultaneously.  */
4751
4752 static void
4753 bfin_gen_bundles (void)
4754 {
4755   basic_block bb;
4756   FOR_EACH_BB (bb)
4757     {
4758       rtx insn, next;
4759       rtx slot[3];
4760       int n_filled = 0;
4761
4762       slot[0] = slot[1] = slot[2] = NULL_RTX;
4763       for (insn = BB_HEAD (bb);; insn = next)
4764         {
4765           int at_end;
4766           if (INSN_P (insn))
4767             {
4768               if (get_attr_type (insn) == TYPE_DSP32)
4769                 slot[0] = insn;
4770               else if (slot[1] == NULL_RTX)
4771                 slot[1] = insn;
4772               else
4773                 slot[2] = insn;
4774               n_filled++;
4775             }
4776
4777           next = NEXT_INSN (insn);
4778           while (next && insn != BB_END (bb)
4779                  && !(INSN_P (next)
4780                       && GET_CODE (PATTERN (next)) != USE
4781                       && GET_CODE (PATTERN (next)) != CLOBBER))
4782             {
4783               insn = next;
4784               next = NEXT_INSN (insn);
4785             }
4786
4787           /* BB_END can change due to emitting extra NOPs, so check here.  */
4788           at_end = insn == BB_END (bb);
4789           if (at_end || GET_MODE (next) == TImode)
4790             {
4791               if ((n_filled < 2
4792                    || !gen_one_bundle (slot))
4793                   && slot[0] != NULL_RTX)
4794                 {
4795                   rtx pat = PATTERN (slot[0]);
4796                   if (GET_CODE (pat) == SET
4797                       && GET_CODE (SET_SRC (pat)) == UNSPEC
4798                       && XINT (SET_SRC (pat), 1) == UNSPEC_32BIT)
4799                     {
4800                       SET_SRC (pat) = XVECEXP (SET_SRC (pat), 0, 0);
4801                       INSN_CODE (slot[0]) = -1;
4802                       df_insn_rescan (slot[0]);
4803                     }
4804                 }
4805               n_filled = 0;
4806               slot[0] = slot[1] = slot[2] = NULL_RTX;
4807             }
4808           if (at_end)
4809             break;
4810         }
4811     }
4812 }
4813
4814 /* Ensure that no var tracking notes are emitted in the middle of a
4815    three-instruction bundle.  */
4816
4817 static void
4818 reorder_var_tracking_notes (void)
4819 {
4820   basic_block bb;
4821   FOR_EACH_BB (bb)
4822     {
4823       rtx insn, next;
4824       rtx queue = NULL_RTX;
4825       bool in_bundle = false;
4826
4827       for (insn = BB_HEAD (bb); insn != BB_END (bb); insn = next)
4828         {
4829           next = NEXT_INSN (insn);
4830
4831           if (INSN_P (insn))
4832             {
4833               /* Emit queued up notes at the last instruction of a bundle.  */
4834               if (GET_MODE (insn) == QImode)
4835                 {
4836                   while (queue)
4837                     {
4838                       rtx next_queue = PREV_INSN (queue);
4839                       PREV_INSN (NEXT_INSN (insn)) = queue;
4840                       NEXT_INSN (queue) = NEXT_INSN (insn);
4841                       NEXT_INSN (insn) = queue;
4842                       PREV_INSN (queue) = insn;
4843                       queue = next_queue;
4844                     }
4845                   in_bundle = false;
4846                 }
4847               else if (GET_MODE (insn) == SImode)
4848                 in_bundle = true;
4849             }
4850           else if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION)
4851             {
4852               if (in_bundle)
4853                 {
4854                   rtx prev = PREV_INSN (insn);
4855                   PREV_INSN (next) = prev;
4856                   NEXT_INSN (prev) = next;
4857
4858                   PREV_INSN (insn) = queue;
4859                   queue = insn;
4860                 }
4861             }
4862         }
4863     }
4864 }
4865 \f
4866 /* On some silicon revisions, functions shorter than a certain number of cycles
4867    can cause unpredictable behaviour.  Work around this by adding NOPs as
4868    needed.  */
4869 static void
4870 workaround_rts_anomaly (void)
4871 {
4872   rtx insn, first_insn = NULL_RTX;
4873   int cycles = 4;
4874
4875   if (! ENABLE_WA_RETS)
4876     return;
4877
4878   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
4879     {
4880       rtx pat;
4881
4882       if (BARRIER_P (insn))
4883         return;
4884       
4885       if (NOTE_P (insn) || LABEL_P (insn))
4886         continue;
4887
4888       if (first_insn == NULL_RTX)
4889         first_insn = insn;
4890       pat = PATTERN (insn);
4891       if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER
4892           || GET_CODE (pat) == ASM_INPUT || GET_CODE (pat) == ADDR_VEC
4893           || GET_CODE (pat) == ADDR_DIFF_VEC || asm_noperands (pat) >= 0)
4894         continue;
4895
4896       if (CALL_P (insn))
4897         return;
4898
4899       if (JUMP_P (insn))
4900         {
4901           if (recog_memoized (insn) == CODE_FOR_return_internal)
4902             break;
4903
4904           /* Nothing to worry about for direct jumps.  */
4905           if (!any_condjump_p (insn))
4906             return;
4907           if (cycles <= 1)
4908             return;
4909           cycles--;
4910         }
4911       else if (INSN_P (insn))
4912         {
4913           rtx pat = PATTERN (insn);
4914           int this_cycles = 1;
4915
4916           if (GET_CODE (pat) == PARALLEL)
4917             {
4918               if (push_multiple_operation (pat, VOIDmode)
4919                   || pop_multiple_operation (pat, VOIDmode))
4920                 this_cycles = n_regs_to_save;
4921             }
4922           else
4923             {
4924               enum insn_code icode = recog_memoized (insn);
4925               if (icode == CODE_FOR_link)
4926                 this_cycles = 4;
4927               else if (icode == CODE_FOR_unlink)
4928                 this_cycles = 3;
4929               else if (icode == CODE_FOR_mulsi3)
4930                 this_cycles = 5;
4931             }
4932           if (this_cycles >= cycles)
4933             return;
4934
4935           cycles -= this_cycles;
4936         }
4937     }
4938   while (cycles > 0)
4939     {
4940       emit_insn_before (gen_nop (), first_insn);
4941       cycles--;
4942     }
4943 }
4944
4945 /* Return an insn type for INSN that can be used by the caller for anomaly
4946    workarounds.  This differs from plain get_attr_type in that it handles
4947    SEQUENCEs.  */
4948
4949 static enum attr_type
4950 type_for_anomaly (rtx insn)
4951 {
4952   rtx pat = PATTERN (insn);
4953   if (GET_CODE (pat) == SEQUENCE)
4954     {
4955       enum attr_type t;
4956       t = get_attr_type (XVECEXP (pat, 0, 1));
4957       if (t == TYPE_MCLD)
4958         return t;
4959       t = get_attr_type (XVECEXP (pat, 0, 2));
4960       if (t == TYPE_MCLD)
4961         return t;
4962       return TYPE_MCST;
4963     }
4964   else
4965     return get_attr_type (insn);
4966 }
4967
4968 /* Return nonzero if INSN contains any loads that may trap.  It handles
4969    SEQUENCEs correctly.  */
4970
4971 static bool
4972 trapping_loads_p (rtx insn)
4973 {
4974   rtx pat = PATTERN (insn);
4975   if (GET_CODE (pat) == SEQUENCE)
4976     {
4977       enum attr_type t;
4978       t = get_attr_type (XVECEXP (pat, 0, 1));
4979       if (t == TYPE_MCLD
4980           && may_trap_p (SET_SRC (PATTERN (XVECEXP (pat, 0, 1)))))
4981         return true;
4982       t = get_attr_type (XVECEXP (pat, 0, 2));
4983       if (t == TYPE_MCLD
4984           && may_trap_p (SET_SRC (PATTERN (XVECEXP (pat, 0, 2)))))
4985         return true;
4986       return false;
4987     }
4988   else
4989     return may_trap_p (SET_SRC (single_set (insn)));
4990 }
4991
4992 /* Return INSN if it is of TYPE_MCLD.  Alternatively, if INSN is the start of
4993    a three-insn bundle, see if one of them is a load and return that if so.
4994    Return NULL_RTX if the insn does not contain loads.  */
4995 static rtx
4996 find_load (rtx insn)
4997 {
4998   if (get_attr_type (insn) == TYPE_MCLD)
4999     return insn;
5000   if (GET_MODE (insn) != SImode)
5001     return NULL_RTX;
5002   do {
5003     insn = NEXT_INSN (insn);
5004     if ((GET_MODE (insn) == SImode || GET_MODE (insn) == QImode)
5005         && get_attr_type (insn) == TYPE_MCLD)
5006       return insn;
5007   } while (GET_MODE (insn) != QImode);
5008   return NULL_RTX;
5009 }
5010
5011 /* Determine whether PAT is an indirect call pattern.  */
5012 static bool
5013 indirect_call_p (rtx pat)
5014 {
5015   if (GET_CODE (pat) == PARALLEL)
5016     pat = XVECEXP (pat, 0, 0);
5017   if (GET_CODE (pat) == SET)
5018     pat = SET_SRC (pat);
5019   gcc_assert (GET_CODE (pat) == CALL);
5020   pat = XEXP (pat, 0);
5021   gcc_assert (GET_CODE (pat) == MEM);
5022   pat = XEXP (pat, 0);
5023   
5024   return REG_P (pat);
5025 }
5026
5027 static void
5028 workaround_speculation (void)
5029 {
5030   rtx insn, next;
5031   rtx last_condjump = NULL_RTX;
5032   int cycles_since_jump = INT_MAX;
5033   int delay_added = 0;
5034
5035   if (! ENABLE_WA_SPECULATIVE_LOADS && ! ENABLE_WA_SPECULATIVE_SYNCS
5036       && ! ENABLE_WA_INDIRECT_CALLS)
5037     return;
5038
5039   /* First pass: find predicted-false branches; if something after them
5040      needs nops, insert them or change the branch to predict true.  */
5041   for (insn = get_insns (); insn; insn = next)
5042     {
5043       rtx pat;
5044       int delay_needed = 0;
5045
5046       next = find_next_insn_start (insn);
5047       
5048       if (NOTE_P (insn) || BARRIER_P (insn) || LABEL_P (insn))
5049         continue;
5050
5051       pat = PATTERN (insn);
5052       if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER
5053           || GET_CODE (pat) == ASM_INPUT || GET_CODE (pat) == ADDR_VEC
5054           || GET_CODE (pat) == ADDR_DIFF_VEC || asm_noperands (pat) >= 0)
5055         continue;
5056
5057       if (JUMP_P (insn))
5058         {
5059           if (any_condjump_p (insn)
5060               && ! cbranch_predicted_taken_p (insn))
5061             {
5062               last_condjump = insn;
5063               delay_added = 0;
5064               cycles_since_jump = 0;
5065             }
5066           else
5067             cycles_since_jump = INT_MAX;
5068         }
5069       else if (CALL_P (insn))
5070         {
5071           if (cycles_since_jump < INT_MAX)
5072             cycles_since_jump++;
5073           if (indirect_call_p (pat) && ENABLE_WA_INDIRECT_CALLS)
5074             {
5075               delay_needed = 3;
5076             }
5077         }
5078       else if (INSN_P (insn))
5079         {
5080           rtx load_insn = find_load (insn);
5081           enum attr_type type = type_for_anomaly (insn);
5082
5083           if (cycles_since_jump < INT_MAX)
5084             cycles_since_jump++;
5085
5086           if (load_insn && ENABLE_WA_SPECULATIVE_LOADS)
5087             {
5088               if (trapping_loads_p (load_insn))
5089                 delay_needed = 4;
5090             }
5091           else if (type == TYPE_SYNC && ENABLE_WA_SPECULATIVE_SYNCS)
5092             delay_needed = 3;
5093         }
5094
5095       if (delay_needed > cycles_since_jump
5096           && (delay_needed - cycles_since_jump) > delay_added)
5097         {
5098           rtx pat1;
5099           int num_clobbers;
5100           rtx *op = recog_data.operand;
5101
5102           delay_needed -= cycles_since_jump;
5103
5104           extract_insn (last_condjump);
5105           if (optimize_size)
5106             {
5107               pat1 = gen_cbranch_predicted_taken (op[0], op[1], op[2],
5108                                                  op[3]);
5109               cycles_since_jump = INT_MAX;
5110             }
5111           else
5112             {
5113               /* Do not adjust cycles_since_jump in this case, so that
5114                  we'll increase the number of NOPs for a subsequent insn
5115                  if necessary.  */
5116               pat1 = gen_cbranch_with_nops (op[0], op[1], op[2], op[3],
5117                                             GEN_INT (delay_needed));
5118               delay_added = delay_needed;
5119             }
5120           PATTERN (last_condjump) = pat1;
5121           INSN_CODE (last_condjump) = recog (pat1, insn, &num_clobbers);
5122         }
5123       if (CALL_P (insn))
5124         {
5125           cycles_since_jump = INT_MAX;
5126           delay_added = 0;
5127         }
5128     }
5129
5130   /* Second pass: for predicted-true branches, see if anything at the
5131      branch destination needs extra nops.  */
5132   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
5133     {
5134       int cycles_since_jump;
5135       if (JUMP_P (insn)
5136           && any_condjump_p (insn)
5137           && (INSN_CODE (insn) == CODE_FOR_cbranch_predicted_taken
5138               || cbranch_predicted_taken_p (insn)))
5139         {
5140           rtx target = JUMP_LABEL (insn);
5141           rtx label = target;
5142           rtx next_tgt;
5143
5144           cycles_since_jump = 0;
5145           for (; target && cycles_since_jump < 3; target = next_tgt)
5146             {
5147               rtx pat;
5148
5149               next_tgt = find_next_insn_start (target);
5150
5151               if (NOTE_P (target) || BARRIER_P (target) || LABEL_P (target))
5152                 continue;
5153
5154               pat = PATTERN (target);
5155               if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER
5156                   || GET_CODE (pat) == ASM_INPUT || GET_CODE (pat) == ADDR_VEC
5157                   || GET_CODE (pat) == ADDR_DIFF_VEC || asm_noperands (pat) >= 0)
5158                 continue;
5159
5160               if (INSN_P (target))
5161                 {
5162                   rtx load_insn = find_load (target);
5163                   enum attr_type type = type_for_anomaly (target);
5164                   int delay_needed = 0;
5165                   if (cycles_since_jump < INT_MAX)
5166                     cycles_since_jump++;
5167
5168                   if (load_insn && ENABLE_WA_SPECULATIVE_LOADS)
5169                     {
5170                       if (trapping_loads_p (load_insn))
5171                         delay_needed = 2;
5172                     }
5173                   else if (type == TYPE_SYNC && ENABLE_WA_SPECULATIVE_SYNCS)
5174                     delay_needed = 2;
5175
5176                   if (delay_needed > cycles_since_jump)
5177                     {
5178                       rtx prev = prev_real_insn (label);
5179                       delay_needed -= cycles_since_jump;
5180                       if (dump_file)
5181                         fprintf (dump_file, "Adding %d nops after %d\n",
5182                                  delay_needed, INSN_UID (label));
5183                       if (JUMP_P (prev)
5184                           && INSN_CODE (prev) == CODE_FOR_cbranch_with_nops)
5185                         {
5186                           rtx x;
5187                           HOST_WIDE_INT v;
5188
5189                           if (dump_file)
5190                             fprintf (dump_file,
5191                                      "Reducing nops on insn %d.\n",
5192                                      INSN_UID (prev));
5193                           x = PATTERN (prev);
5194                           x = XVECEXP (x, 0, 1);
5195                           v = INTVAL (XVECEXP (x, 0, 0)) - delay_needed;
5196                           XVECEXP (x, 0, 0) = GEN_INT (v);
5197                         }
5198                       while (delay_needed-- > 0)
5199                         emit_insn_after (gen_nop (), label);
5200                       break;
5201                     }
5202                 }
5203             }
5204         }
5205     }
5206 }
5207
5208 /* We use the machine specific reorg pass for emitting CSYNC instructions
5209    after conditional branches as needed.
5210
5211    The Blackfin is unusual in that a code sequence like
5212      if cc jump label
5213      r0 = (p0)
5214    may speculatively perform the load even if the condition isn't true.  This
5215    happens for a branch that is predicted not taken, because the pipeline
5216    isn't flushed or stalled, so the early stages of the following instructions,
5217    which perform the memory reference, are allowed to execute before the
5218    jump condition is evaluated.
5219    Therefore, we must insert additional instructions in all places where this
5220    could lead to incorrect behavior.  The manual recommends CSYNC, while
5221    VDSP seems to use NOPs (even though its corresponding compiler option is
5222    named CSYNC).
5223
5224    When optimizing for speed, we emit NOPs, which seems faster than a CSYNC.
5225    When optimizing for size, we turn the branch into a predicted taken one.
5226    This may be slower due to mispredicts, but saves code size.  */
5227
5228 static void
5229 bfin_reorg (void)
5230 {
5231   /* We are freeing block_for_insn in the toplev to keep compatibility
5232      with old MDEP_REORGS that are not CFG based.  Recompute it now.  */
5233   compute_bb_for_insn ();
5234
5235   if (bfin_flag_schedule_insns2)
5236     {
5237       splitting_for_sched = 1;
5238       split_all_insns ();
5239       splitting_for_sched = 0;
5240
5241       timevar_push (TV_SCHED2);
5242       schedule_insns ();
5243       timevar_pop (TV_SCHED2);
5244
5245       /* Examine the schedule and insert nops as necessary for 64-bit parallel
5246          instructions.  */
5247       bfin_gen_bundles ();
5248     }
5249
5250   df_analyze ();
5251
5252   /* Doloop optimization */
5253   if (cfun->machine->has_hardware_loops)
5254     bfin_reorg_loops (dump_file);
5255
5256   workaround_speculation ();
5257
5258   if (bfin_flag_var_tracking)
5259     {
5260       timevar_push (TV_VAR_TRACKING);
5261       variable_tracking_main ();
5262       reorder_var_tracking_notes ();
5263       timevar_pop (TV_VAR_TRACKING);
5264     }
5265
5266   df_finish_pass (false);
5267
5268   workaround_rts_anomaly ();
5269 }
5270 \f
5271 /* Handle interrupt_handler, exception_handler and nmi_handler function
5272    attributes; arguments as in struct attribute_spec.handler.  */
5273
5274 static tree
5275 handle_int_attribute (tree *node, tree name,
5276                       tree args ATTRIBUTE_UNUSED,
5277                       int flags ATTRIBUTE_UNUSED,
5278                       bool *no_add_attrs)
5279 {
5280   tree x = *node;
5281   if (TREE_CODE (x) == FUNCTION_DECL)
5282     x = TREE_TYPE (x);
5283
5284   if (TREE_CODE (x) != FUNCTION_TYPE)
5285     {
5286       warning (OPT_Wattributes, "%qs attribute only applies to functions",
5287                IDENTIFIER_POINTER (name));
5288       *no_add_attrs = true;
5289     }
5290   else if (funkind (x) != SUBROUTINE)
5291     error ("multiple function type attributes specified");
5292
5293   return NULL_TREE;
5294 }
5295
5296 /* Return 0 if the attributes for two types are incompatible, 1 if they
5297    are compatible, and 2 if they are nearly compatible (which causes a
5298    warning to be generated).  */
5299
5300 static int
5301 bfin_comp_type_attributes (const_tree type1, const_tree type2)
5302 {
5303   e_funkind kind1, kind2;
5304
5305   if (TREE_CODE (type1) != FUNCTION_TYPE)
5306     return 1;
5307
5308   kind1 = funkind (type1);
5309   kind2 = funkind (type2);
5310
5311   if (kind1 != kind2)
5312     return 0;
5313   
5314   /*  Check for mismatched modifiers */
5315   if (!lookup_attribute ("nesting", TYPE_ATTRIBUTES (type1))
5316       != !lookup_attribute ("nesting", TYPE_ATTRIBUTES (type2)))
5317     return 0;
5318
5319   if (!lookup_attribute ("saveall", TYPE_ATTRIBUTES (type1))
5320       != !lookup_attribute ("saveall", TYPE_ATTRIBUTES (type2)))
5321     return 0;
5322
5323   if (!lookup_attribute ("kspisusp", TYPE_ATTRIBUTES (type1))
5324       != !lookup_attribute ("kspisusp", TYPE_ATTRIBUTES (type2)))
5325     return 0;
5326
5327   if (!lookup_attribute ("longcall", TYPE_ATTRIBUTES (type1))
5328       != !lookup_attribute ("longcall", TYPE_ATTRIBUTES (type2)))
5329     return 0;
5330
5331   return 1;
5332 }
5333
5334 /* Handle a "longcall" or "shortcall" attribute; arguments as in
5335    struct attribute_spec.handler.  */
5336
5337 static tree
5338 bfin_handle_longcall_attribute (tree *node, tree name, 
5339                                 tree args ATTRIBUTE_UNUSED, 
5340                                 int flags ATTRIBUTE_UNUSED, 
5341                                 bool *no_add_attrs)
5342 {
5343   if (TREE_CODE (*node) != FUNCTION_TYPE
5344       && TREE_CODE (*node) != FIELD_DECL
5345       && TREE_CODE (*node) != TYPE_DECL)
5346     {
5347       warning (OPT_Wattributes, "`%s' attribute only applies to functions",
5348                IDENTIFIER_POINTER (name));
5349       *no_add_attrs = true;
5350     }
5351
5352   if ((strcmp (IDENTIFIER_POINTER (name), "longcall") == 0
5353        && lookup_attribute ("shortcall", TYPE_ATTRIBUTES (*node)))
5354       || (strcmp (IDENTIFIER_POINTER (name), "shortcall") == 0
5355           && lookup_attribute ("longcall", TYPE_ATTRIBUTES (*node))))
5356     {
5357       warning (OPT_Wattributes,
5358                "can't apply both longcall and shortcall attributes to the same function");
5359       *no_add_attrs = true;
5360     }
5361
5362   return NULL_TREE;
5363 }
5364
5365 /* Handle a "l1_text" attribute; arguments as in
5366    struct attribute_spec.handler.  */
5367
5368 static tree
5369 bfin_handle_l1_text_attribute (tree *node, tree name, tree ARG_UNUSED (args),
5370                                int ARG_UNUSED (flags), bool *no_add_attrs)
5371 {
5372   tree decl = *node;
5373
5374   if (TREE_CODE (decl) != FUNCTION_DECL)
5375     {
5376       error ("`%s' attribute only applies to functions",
5377              IDENTIFIER_POINTER (name));
5378       *no_add_attrs = true;
5379     }
5380
5381   /* The decl may have already been given a section attribute
5382      from a previous declaration. Ensure they match.  */
5383   else if (DECL_SECTION_NAME (decl) != NULL_TREE
5384            && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
5385                       ".l1.text") != 0)
5386     {
5387       error ("section of %q+D conflicts with previous declaration",
5388              decl);
5389       *no_add_attrs = true;
5390     }
5391   else
5392     DECL_SECTION_NAME (decl) = build_string (9, ".l1.text");
5393
5394   return NULL_TREE;
5395 }
5396
5397 /* Handle a "l1_data", "l1_data_A" or "l1_data_B" attribute;
5398    arguments as in struct attribute_spec.handler.  */
5399
5400 static tree
5401 bfin_handle_l1_data_attribute (tree *node, tree name, tree ARG_UNUSED (args),
5402                                int ARG_UNUSED (flags), bool *no_add_attrs)
5403 {
5404   tree decl = *node;
5405
5406   if (TREE_CODE (decl) != VAR_DECL)
5407     {
5408       error ("`%s' attribute only applies to variables",
5409              IDENTIFIER_POINTER (name));
5410       *no_add_attrs = true;
5411     }
5412   else if (current_function_decl != NULL_TREE
5413            && !TREE_STATIC (decl))
5414     {
5415       error ("`%s' attribute cannot be specified for local variables",
5416              IDENTIFIER_POINTER (name));
5417       *no_add_attrs = true;
5418     }
5419   else
5420     {
5421       const char *section_name;
5422
5423       if (strcmp (IDENTIFIER_POINTER (name), "l1_data") == 0)
5424         section_name = ".l1.data";
5425       else if (strcmp (IDENTIFIER_POINTER (name), "l1_data_A") == 0)
5426         section_name = ".l1.data.A";
5427       else if (strcmp (IDENTIFIER_POINTER (name), "l1_data_B") == 0)
5428         section_name = ".l1.data.B";
5429       else
5430         gcc_unreachable ();
5431
5432       /* The decl may have already been given a section attribute
5433          from a previous declaration. Ensure they match.  */
5434       if (DECL_SECTION_NAME (decl) != NULL_TREE
5435           && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
5436                      section_name) != 0)
5437         {
5438           error ("section of %q+D conflicts with previous declaration",
5439                  decl);
5440           *no_add_attrs = true;
5441         }
5442       else
5443         DECL_SECTION_NAME (decl)
5444           = build_string (strlen (section_name) + 1, section_name);
5445     }
5446
5447  return NULL_TREE;
5448 }
5449
5450 /* Table of valid machine attributes.  */
5451 const struct attribute_spec bfin_attribute_table[] =
5452 {
5453   /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
5454   { "interrupt_handler", 0, 0, false, true,  true, handle_int_attribute },
5455   { "exception_handler", 0, 0, false, true,  true, handle_int_attribute },
5456   { "nmi_handler", 0, 0, false, true,  true, handle_int_attribute },
5457   { "nesting", 0, 0, false, true,  true, NULL },
5458   { "kspisusp", 0, 0, false, true,  true, NULL },
5459   { "saveall", 0, 0, false, true,  true, NULL },
5460   { "longcall",  0, 0, false, true,  true,  bfin_handle_longcall_attribute },
5461   { "shortcall", 0, 0, false, true,  true,  bfin_handle_longcall_attribute },
5462   { "l1_text", 0, 0, true, false, false,  bfin_handle_l1_text_attribute },
5463   { "l1_data", 0, 0, true, false, false,  bfin_handle_l1_data_attribute },
5464   { "l1_data_A", 0, 0, true, false, false, bfin_handle_l1_data_attribute },
5465   { "l1_data_B", 0, 0, true, false, false,  bfin_handle_l1_data_attribute },
5466   { NULL, 0, 0, false, false, false, NULL }
5467 };
5468 \f
5469 /* Implementation of TARGET_ASM_INTEGER.  When using FD-PIC, we need to
5470    tell the assembler to generate pointers to function descriptors in
5471    some cases.  */
5472
5473 static bool
5474 bfin_assemble_integer (rtx value, unsigned int size, int aligned_p)
5475 {
5476   if (TARGET_FDPIC && size == UNITS_PER_WORD)
5477     {
5478       if (GET_CODE (value) == SYMBOL_REF
5479           && SYMBOL_REF_FUNCTION_P (value))
5480         {
5481           fputs ("\t.picptr\tfuncdesc(", asm_out_file);
5482           output_addr_const (asm_out_file, value);
5483           fputs (")\n", asm_out_file);
5484           return true;
5485         }
5486       if (!aligned_p)
5487         {
5488           /* We've set the unaligned SI op to NULL, so we always have to
5489              handle the unaligned case here.  */
5490           assemble_integer_with_op ("\t.4byte\t", value);
5491           return true;
5492         }
5493     }
5494   return default_assemble_integer (value, size, aligned_p);
5495 }
5496 \f
5497 /* Output the assembler code for a thunk function.  THUNK_DECL is the
5498    declaration for the thunk function itself, FUNCTION is the decl for
5499    the target function.  DELTA is an immediate constant offset to be
5500    added to THIS.  If VCALL_OFFSET is nonzero, the word at
5501    *(*this + vcall_offset) should be added to THIS.  */
5502
5503 static void
5504 bfin_output_mi_thunk (FILE *file ATTRIBUTE_UNUSED,
5505                       tree thunk ATTRIBUTE_UNUSED, HOST_WIDE_INT delta,
5506                       HOST_WIDE_INT vcall_offset, tree function)
5507 {
5508   rtx xops[3];
5509   /* The this parameter is passed as the first argument.  */
5510   rtx this_rtx = gen_rtx_REG (Pmode, REG_R0);
5511
5512   /* Adjust the this parameter by a fixed constant.  */
5513   if (delta)
5514     {
5515       xops[1] = this_rtx;
5516       if (delta >= -64 && delta <= 63)
5517         {
5518           xops[0] = GEN_INT (delta);
5519           output_asm_insn ("%1 += %0;", xops);
5520         }
5521       else if (delta >= -128 && delta < -64)
5522         {
5523           xops[0] = GEN_INT (delta + 64);
5524           output_asm_insn ("%1 += -64; %1 += %0;", xops);
5525         }
5526       else if (delta > 63 && delta <= 126)
5527         {
5528           xops[0] = GEN_INT (delta - 63);
5529           output_asm_insn ("%1 += 63; %1 += %0;", xops);
5530         }
5531       else
5532         {
5533           xops[0] = GEN_INT (delta);
5534           output_asm_insn ("r3.l = %h0; r3.h = %d0; %1 = %1 + r3;", xops);
5535         }
5536     }
5537
5538   /* Adjust the this parameter by a value stored in the vtable.  */
5539   if (vcall_offset)
5540     {
5541       rtx p2tmp = gen_rtx_REG (Pmode, REG_P2);
5542       rtx tmp = gen_rtx_REG (Pmode, REG_R3);
5543
5544       xops[1] = tmp;
5545       xops[2] = p2tmp;
5546       output_asm_insn ("%2 = r0; %2 = [%2];", xops);
5547
5548       /* Adjust the this parameter.  */
5549       xops[0] = gen_rtx_MEM (Pmode, plus_constant (p2tmp, vcall_offset));
5550       if (!memory_operand (xops[0], Pmode))
5551         {
5552           rtx tmp2 = gen_rtx_REG (Pmode, REG_P1);
5553           xops[0] = GEN_INT (vcall_offset);
5554           xops[1] = tmp2;
5555           output_asm_insn ("%h1 = %h0; %d1 = %d0; %2 = %2 + %1", xops);
5556           xops[0] = gen_rtx_MEM (Pmode, p2tmp);
5557         }
5558       xops[2] = this_rtx;
5559       output_asm_insn ("%1 = %0; %2 = %2 + %1;", xops);
5560     }
5561
5562   xops[0] = XEXP (DECL_RTL (function), 0);
5563   if (1 || !flag_pic || (*targetm.binds_local_p) (function))
5564     output_asm_insn ("jump.l\t%P0", xops);
5565 }
5566 \f
5567 /* Codes for all the Blackfin builtins.  */
5568 enum bfin_builtins
5569 {
5570   BFIN_BUILTIN_CSYNC,
5571   BFIN_BUILTIN_SSYNC,
5572   BFIN_BUILTIN_ONES,
5573   BFIN_BUILTIN_COMPOSE_2X16,
5574   BFIN_BUILTIN_EXTRACTLO,
5575   BFIN_BUILTIN_EXTRACTHI,
5576
5577   BFIN_BUILTIN_SSADD_2X16,
5578   BFIN_BUILTIN_SSSUB_2X16,
5579   BFIN_BUILTIN_SSADDSUB_2X16,
5580   BFIN_BUILTIN_SSSUBADD_2X16,
5581   BFIN_BUILTIN_MULT_2X16,
5582   BFIN_BUILTIN_MULTR_2X16,
5583   BFIN_BUILTIN_NEG_2X16,
5584   BFIN_BUILTIN_ABS_2X16,
5585   BFIN_BUILTIN_MIN_2X16,
5586   BFIN_BUILTIN_MAX_2X16,
5587
5588   BFIN_BUILTIN_SSADD_1X16,
5589   BFIN_BUILTIN_SSSUB_1X16,
5590   BFIN_BUILTIN_MULT_1X16,
5591   BFIN_BUILTIN_MULTR_1X16,
5592   BFIN_BUILTIN_NORM_1X16,
5593   BFIN_BUILTIN_NEG_1X16,
5594   BFIN_BUILTIN_ABS_1X16,
5595   BFIN_BUILTIN_MIN_1X16,
5596   BFIN_BUILTIN_MAX_1X16,
5597
5598   BFIN_BUILTIN_SUM_2X16,
5599   BFIN_BUILTIN_DIFFHL_2X16,
5600   BFIN_BUILTIN_DIFFLH_2X16,
5601
5602   BFIN_BUILTIN_SSADD_1X32,
5603   BFIN_BUILTIN_SSSUB_1X32,
5604   BFIN_BUILTIN_NORM_1X32,
5605   BFIN_BUILTIN_ROUND_1X32,
5606   BFIN_BUILTIN_NEG_1X32,
5607   BFIN_BUILTIN_ABS_1X32,
5608   BFIN_BUILTIN_MIN_1X32,
5609   BFIN_BUILTIN_MAX_1X32,
5610   BFIN_BUILTIN_MULT_1X32,
5611   BFIN_BUILTIN_MULT_1X32X32,
5612   BFIN_BUILTIN_MULT_1X32X32NS,
5613
5614   BFIN_BUILTIN_MULHISILL,
5615   BFIN_BUILTIN_MULHISILH,
5616   BFIN_BUILTIN_MULHISIHL,
5617   BFIN_BUILTIN_MULHISIHH,
5618
5619   BFIN_BUILTIN_LSHIFT_1X16,
5620   BFIN_BUILTIN_LSHIFT_2X16,
5621   BFIN_BUILTIN_SSASHIFT_1X16,
5622   BFIN_BUILTIN_SSASHIFT_2X16,
5623   BFIN_BUILTIN_SSASHIFT_1X32,
5624
5625   BFIN_BUILTIN_CPLX_MUL_16,
5626   BFIN_BUILTIN_CPLX_MAC_16,
5627   BFIN_BUILTIN_CPLX_MSU_16,
5628
5629   BFIN_BUILTIN_CPLX_MUL_16_S40,
5630   BFIN_BUILTIN_CPLX_MAC_16_S40,
5631   BFIN_BUILTIN_CPLX_MSU_16_S40,
5632
5633   BFIN_BUILTIN_CPLX_SQU,
5634
5635   BFIN_BUILTIN_LOADBYTES,
5636
5637   BFIN_BUILTIN_MAX
5638 };
5639
5640 #define def_builtin(NAME, TYPE, CODE)                                   \
5641 do {                                                                    \
5642   add_builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD,            \
5643                        NULL, NULL_TREE);                                \
5644 } while (0)
5645
5646 /* Set up all builtin functions for this target.  */
5647 static void
5648 bfin_init_builtins (void)
5649 {
5650   tree V2HI_type_node = build_vector_type_for_mode (intHI_type_node, V2HImode);
5651   tree void_ftype_void
5652     = build_function_type (void_type_node, void_list_node);
5653   tree short_ftype_short
5654     = build_function_type_list (short_integer_type_node, short_integer_type_node,
5655                                 NULL_TREE);
5656   tree short_ftype_int_int
5657     = build_function_type_list (short_integer_type_node, integer_type_node,
5658                                 integer_type_node, NULL_TREE);
5659   tree int_ftype_int_int
5660     = build_function_type_list (integer_type_node, integer_type_node,
5661                                 integer_type_node, NULL_TREE);
5662   tree int_ftype_int
5663     = build_function_type_list (integer_type_node, integer_type_node,
5664                                 NULL_TREE);
5665   tree short_ftype_int
5666     = build_function_type_list (short_integer_type_node, integer_type_node,
5667                                 NULL_TREE);
5668   tree int_ftype_v2hi_v2hi
5669     = build_function_type_list (integer_type_node, V2HI_type_node,
5670                                 V2HI_type_node, NULL_TREE);
5671   tree v2hi_ftype_v2hi_v2hi
5672     = build_function_type_list (V2HI_type_node, V2HI_type_node,
5673                                 V2HI_type_node, NULL_TREE);
5674   tree v2hi_ftype_v2hi_v2hi_v2hi
5675     = build_function_type_list (V2HI_type_node, V2HI_type_node,
5676                                 V2HI_type_node, V2HI_type_node, NULL_TREE);
5677   tree v2hi_ftype_int_int
5678     = build_function_type_list (V2HI_type_node, integer_type_node,
5679                                 integer_type_node, NULL_TREE);
5680   tree v2hi_ftype_v2hi_int
5681     = build_function_type_list (V2HI_type_node, V2HI_type_node,
5682                                 integer_type_node, NULL_TREE);
5683   tree int_ftype_short_short
5684     = build_function_type_list (integer_type_node, short_integer_type_node,
5685                                 short_integer_type_node, NULL_TREE);
5686   tree v2hi_ftype_v2hi
5687     = build_function_type_list (V2HI_type_node, V2HI_type_node, NULL_TREE);
5688   tree short_ftype_v2hi
5689     = build_function_type_list (short_integer_type_node, V2HI_type_node,
5690                                 NULL_TREE);
5691   tree int_ftype_pint
5692     = build_function_type_list (integer_type_node,
5693                                 build_pointer_type (integer_type_node),
5694                                 NULL_TREE);
5695   
5696   /* Add the remaining MMX insns with somewhat more complicated types.  */
5697   def_builtin ("__builtin_bfin_csync", void_ftype_void, BFIN_BUILTIN_CSYNC);
5698   def_builtin ("__builtin_bfin_ssync", void_ftype_void, BFIN_BUILTIN_SSYNC);
5699
5700   def_builtin ("__builtin_bfin_ones", short_ftype_int, BFIN_BUILTIN_ONES);
5701
5702   def_builtin ("__builtin_bfin_compose_2x16", v2hi_ftype_int_int,
5703                BFIN_BUILTIN_COMPOSE_2X16);
5704   def_builtin ("__builtin_bfin_extract_hi", short_ftype_v2hi,
5705                BFIN_BUILTIN_EXTRACTHI);
5706   def_builtin ("__builtin_bfin_extract_lo", short_ftype_v2hi,
5707                BFIN_BUILTIN_EXTRACTLO);
5708
5709   def_builtin ("__builtin_bfin_min_fr2x16", v2hi_ftype_v2hi_v2hi,
5710                BFIN_BUILTIN_MIN_2X16);
5711   def_builtin ("__builtin_bfin_max_fr2x16", v2hi_ftype_v2hi_v2hi,
5712                BFIN_BUILTIN_MAX_2X16);
5713
5714   def_builtin ("__builtin_bfin_add_fr2x16", v2hi_ftype_v2hi_v2hi,
5715                BFIN_BUILTIN_SSADD_2X16);
5716   def_builtin ("__builtin_bfin_sub_fr2x16", v2hi_ftype_v2hi_v2hi,
5717                BFIN_BUILTIN_SSSUB_2X16);
5718   def_builtin ("__builtin_bfin_dspaddsubsat", v2hi_ftype_v2hi_v2hi,
5719                BFIN_BUILTIN_SSADDSUB_2X16);
5720   def_builtin ("__builtin_bfin_dspsubaddsat", v2hi_ftype_v2hi_v2hi,
5721                BFIN_BUILTIN_SSSUBADD_2X16);
5722   def_builtin ("__builtin_bfin_mult_fr2x16", v2hi_ftype_v2hi_v2hi,
5723                BFIN_BUILTIN_MULT_2X16);
5724   def_builtin ("__builtin_bfin_multr_fr2x16", v2hi_ftype_v2hi_v2hi,
5725                BFIN_BUILTIN_MULTR_2X16);
5726   def_builtin ("__builtin_bfin_negate_fr2x16", v2hi_ftype_v2hi,
5727                BFIN_BUILTIN_NEG_2X16);
5728   def_builtin ("__builtin_bfin_abs_fr2x16", v2hi_ftype_v2hi,
5729                BFIN_BUILTIN_ABS_2X16);
5730
5731   def_builtin ("__builtin_bfin_min_fr1x16", short_ftype_int_int,
5732                BFIN_BUILTIN_MIN_1X16);
5733   def_builtin ("__builtin_bfin_max_fr1x16", short_ftype_int_int,
5734                BFIN_BUILTIN_MAX_1X16);
5735
5736   def_builtin ("__builtin_bfin_add_fr1x16", short_ftype_int_int,
5737                BFIN_BUILTIN_SSADD_1X16);
5738   def_builtin ("__builtin_bfin_sub_fr1x16", short_ftype_int_int,
5739                BFIN_BUILTIN_SSSUB_1X16);
5740   def_builtin ("__builtin_bfin_mult_fr1x16", short_ftype_int_int,
5741                BFIN_BUILTIN_MULT_1X16);
5742   def_builtin ("__builtin_bfin_multr_fr1x16", short_ftype_int_int,
5743                BFIN_BUILTIN_MULTR_1X16);
5744   def_builtin ("__builtin_bfin_negate_fr1x16", short_ftype_short,
5745                BFIN_BUILTIN_NEG_1X16);
5746   def_builtin ("__builtin_bfin_abs_fr1x16", short_ftype_short,
5747                BFIN_BUILTIN_ABS_1X16);
5748   def_builtin ("__builtin_bfin_norm_fr1x16", short_ftype_int,
5749                BFIN_BUILTIN_NORM_1X16);
5750
5751   def_builtin ("__builtin_bfin_sum_fr2x16", short_ftype_v2hi,
5752                BFIN_BUILTIN_SUM_2X16);
5753   def_builtin ("__builtin_bfin_diff_hl_fr2x16", short_ftype_v2hi,
5754                BFIN_BUILTIN_DIFFHL_2X16);
5755   def_builtin ("__builtin_bfin_diff_lh_fr2x16", short_ftype_v2hi,
5756                BFIN_BUILTIN_DIFFLH_2X16);
5757
5758   def_builtin ("__builtin_bfin_mulhisill", int_ftype_v2hi_v2hi,
5759                BFIN_BUILTIN_MULHISILL);
5760   def_builtin ("__builtin_bfin_mulhisihl", int_ftype_v2hi_v2hi,
5761                BFIN_BUILTIN_MULHISIHL);
5762   def_builtin ("__builtin_bfin_mulhisilh", int_ftype_v2hi_v2hi,
5763                BFIN_BUILTIN_MULHISILH);
5764   def_builtin ("__builtin_bfin_mulhisihh", int_ftype_v2hi_v2hi,
5765                BFIN_BUILTIN_MULHISIHH);
5766
5767   def_builtin ("__builtin_bfin_min_fr1x32", int_ftype_int_int,
5768                BFIN_BUILTIN_MIN_1X32);
5769   def_builtin ("__builtin_bfin_max_fr1x32", int_ftype_int_int,
5770                BFIN_BUILTIN_MAX_1X32);
5771
5772   def_builtin ("__builtin_bfin_add_fr1x32", int_ftype_int_int,
5773                BFIN_BUILTIN_SSADD_1X32);
5774   def_builtin ("__builtin_bfin_sub_fr1x32", int_ftype_int_int,
5775                BFIN_BUILTIN_SSSUB_1X32);
5776   def_builtin ("__builtin_bfin_negate_fr1x32", int_ftype_int,
5777                BFIN_BUILTIN_NEG_1X32);
5778   def_builtin ("__builtin_bfin_abs_fr1x32", int_ftype_int,
5779                BFIN_BUILTIN_ABS_1X32);
5780   def_builtin ("__builtin_bfin_norm_fr1x32", short_ftype_int,
5781                BFIN_BUILTIN_NORM_1X32);
5782   def_builtin ("__builtin_bfin_round_fr1x32", short_ftype_int,
5783                BFIN_BUILTIN_ROUND_1X32);
5784   def_builtin ("__builtin_bfin_mult_fr1x32", int_ftype_short_short,
5785                BFIN_BUILTIN_MULT_1X32);
5786   def_builtin ("__builtin_bfin_mult_fr1x32x32", int_ftype_int_int,
5787                BFIN_BUILTIN_MULT_1X32X32);
5788   def_builtin ("__builtin_bfin_mult_fr1x32x32NS", int_ftype_int_int,
5789                BFIN_BUILTIN_MULT_1X32X32NS);
5790
5791   /* Shifts.  */
5792   def_builtin ("__builtin_bfin_shl_fr1x16", short_ftype_int_int,
5793                BFIN_BUILTIN_SSASHIFT_1X16);
5794   def_builtin ("__builtin_bfin_shl_fr2x16", v2hi_ftype_v2hi_int,
5795                BFIN_BUILTIN_SSASHIFT_2X16);
5796   def_builtin ("__builtin_bfin_lshl_fr1x16", short_ftype_int_int,
5797                BFIN_BUILTIN_LSHIFT_1X16);
5798   def_builtin ("__builtin_bfin_lshl_fr2x16", v2hi_ftype_v2hi_int,
5799                BFIN_BUILTIN_LSHIFT_2X16);
5800   def_builtin ("__builtin_bfin_shl_fr1x32", int_ftype_int_int,
5801                BFIN_BUILTIN_SSASHIFT_1X32);
5802
5803   /* Complex numbers.  */
5804   def_builtin ("__builtin_bfin_cmplx_add", v2hi_ftype_v2hi_v2hi,
5805                BFIN_BUILTIN_SSADD_2X16);
5806   def_builtin ("__builtin_bfin_cmplx_sub", v2hi_ftype_v2hi_v2hi,
5807                BFIN_BUILTIN_SSSUB_2X16);
5808   def_builtin ("__builtin_bfin_cmplx_mul", v2hi_ftype_v2hi_v2hi,
5809                BFIN_BUILTIN_CPLX_MUL_16);
5810   def_builtin ("__builtin_bfin_cmplx_mac", v2hi_ftype_v2hi_v2hi_v2hi,
5811                BFIN_BUILTIN_CPLX_MAC_16);
5812   def_builtin ("__builtin_bfin_cmplx_msu", v2hi_ftype_v2hi_v2hi_v2hi,
5813                BFIN_BUILTIN_CPLX_MSU_16);
5814   def_builtin ("__builtin_bfin_cmplx_mul_s40", v2hi_ftype_v2hi_v2hi,
5815                BFIN_BUILTIN_CPLX_MUL_16_S40);
5816   def_builtin ("__builtin_bfin_cmplx_mac_s40", v2hi_ftype_v2hi_v2hi_v2hi,
5817                BFIN_BUILTIN_CPLX_MAC_16_S40);
5818   def_builtin ("__builtin_bfin_cmplx_msu_s40", v2hi_ftype_v2hi_v2hi_v2hi,
5819                BFIN_BUILTIN_CPLX_MSU_16_S40);
5820   def_builtin ("__builtin_bfin_csqu_fr16", v2hi_ftype_v2hi,
5821                BFIN_BUILTIN_CPLX_SQU);
5822
5823   /* "Unaligned" load.  */
5824   def_builtin ("__builtin_bfin_loadbytes", int_ftype_pint,
5825                BFIN_BUILTIN_LOADBYTES);
5826
5827 }
5828
5829
5830 struct builtin_description
5831 {
5832   const enum insn_code icode;
5833   const char *const name;
5834   const enum bfin_builtins code;
5835   int macflag;
5836 };
5837
5838 static const struct builtin_description bdesc_2arg[] =
5839 {
5840   { CODE_FOR_composev2hi, "__builtin_bfin_compose_2x16", BFIN_BUILTIN_COMPOSE_2X16, -1 },
5841
5842   { CODE_FOR_ssashiftv2hi3, "__builtin_bfin_shl_fr2x16", BFIN_BUILTIN_SSASHIFT_2X16, -1 },
5843   { CODE_FOR_ssashifthi3, "__builtin_bfin_shl_fr1x16", BFIN_BUILTIN_SSASHIFT_1X16, -1 },
5844   { CODE_FOR_lshiftv2hi3, "__builtin_bfin_lshl_fr2x16", BFIN_BUILTIN_LSHIFT_2X16, -1 },
5845   { CODE_FOR_lshifthi3, "__builtin_bfin_lshl_fr1x16", BFIN_BUILTIN_LSHIFT_1X16, -1 },
5846   { CODE_FOR_ssashiftsi3, "__builtin_bfin_shl_fr1x32", BFIN_BUILTIN_SSASHIFT_1X32, -1 },
5847
5848   { CODE_FOR_sminhi3, "__builtin_bfin_min_fr1x16", BFIN_BUILTIN_MIN_1X16, -1 },
5849   { CODE_FOR_smaxhi3, "__builtin_bfin_max_fr1x16", BFIN_BUILTIN_MAX_1X16, -1 },
5850   { CODE_FOR_ssaddhi3, "__builtin_bfin_add_fr1x16", BFIN_BUILTIN_SSADD_1X16, -1 },
5851   { CODE_FOR_sssubhi3, "__builtin_bfin_sub_fr1x16", BFIN_BUILTIN_SSSUB_1X16, -1 },
5852
5853   { CODE_FOR_sminsi3, "__builtin_bfin_min_fr1x32", BFIN_BUILTIN_MIN_1X32, -1 },
5854   { CODE_FOR_smaxsi3, "__builtin_bfin_max_fr1x32", BFIN_BUILTIN_MAX_1X32, -1 },
5855   { CODE_FOR_ssaddsi3, "__builtin_bfin_add_fr1x32", BFIN_BUILTIN_SSADD_1X32, -1 },
5856   { CODE_FOR_sssubsi3, "__builtin_bfin_sub_fr1x32", BFIN_BUILTIN_SSSUB_1X32, -1 },
5857
5858   { CODE_FOR_sminv2hi3, "__builtin_bfin_min_fr2x16", BFIN_BUILTIN_MIN_2X16, -1 },
5859   { CODE_FOR_smaxv2hi3, "__builtin_bfin_max_fr2x16", BFIN_BUILTIN_MAX_2X16, -1 },
5860   { CODE_FOR_ssaddv2hi3, "__builtin_bfin_add_fr2x16", BFIN_BUILTIN_SSADD_2X16, -1 },
5861   { CODE_FOR_sssubv2hi3, "__builtin_bfin_sub_fr2x16", BFIN_BUILTIN_SSSUB_2X16, -1 },
5862   { CODE_FOR_ssaddsubv2hi3, "__builtin_bfin_dspaddsubsat", BFIN_BUILTIN_SSADDSUB_2X16, -1 },
5863   { CODE_FOR_sssubaddv2hi3, "__builtin_bfin_dspsubaddsat", BFIN_BUILTIN_SSSUBADD_2X16, -1 },
5864
5865   { CODE_FOR_flag_mulhisi, "__builtin_bfin_mult_fr1x32", BFIN_BUILTIN_MULT_1X32, MACFLAG_NONE },
5866   { CODE_FOR_flag_mulhi, "__builtin_bfin_mult_fr1x16", BFIN_BUILTIN_MULT_1X16, MACFLAG_T },
5867   { CODE_FOR_flag_mulhi, "__builtin_bfin_multr_fr1x16", BFIN_BUILTIN_MULTR_1X16, MACFLAG_NONE },
5868   { CODE_FOR_flag_mulv2hi, "__builtin_bfin_mult_fr2x16", BFIN_BUILTIN_MULT_2X16, MACFLAG_T },
5869   { CODE_FOR_flag_mulv2hi, "__builtin_bfin_multr_fr2x16", BFIN_BUILTIN_MULTR_2X16, MACFLAG_NONE },
5870
5871   { CODE_FOR_mulhisi_ll, "__builtin_bfin_mulhisill", BFIN_BUILTIN_MULHISILL, -1 },
5872   { CODE_FOR_mulhisi_lh, "__builtin_bfin_mulhisilh", BFIN_BUILTIN_MULHISILH, -1 },
5873   { CODE_FOR_mulhisi_hl, "__builtin_bfin_mulhisihl", BFIN_BUILTIN_MULHISIHL, -1 },
5874   { CODE_FOR_mulhisi_hh, "__builtin_bfin_mulhisihh", BFIN_BUILTIN_MULHISIHH, -1 }
5875
5876 };
5877
5878 static const struct builtin_description bdesc_1arg[] =
5879 {
5880   { CODE_FOR_loadbytes, "__builtin_bfin_loadbytes", BFIN_BUILTIN_LOADBYTES, 0 },
5881
5882   { CODE_FOR_ones, "__builtin_bfin_ones", BFIN_BUILTIN_ONES, 0 },
5883
5884   { CODE_FOR_signbitshi2, "__builtin_bfin_norm_fr1x16", BFIN_BUILTIN_NORM_1X16, 0 },
5885   { CODE_FOR_ssneghi2, "__builtin_bfin_negate_fr1x16", BFIN_BUILTIN_NEG_1X16, 0 },
5886   { CODE_FOR_abshi2, "__builtin_bfin_abs_fr1x16", BFIN_BUILTIN_ABS_1X16, 0 },
5887
5888   { CODE_FOR_signbitssi2, "__builtin_bfin_norm_fr1x32", BFIN_BUILTIN_NORM_1X32, 0 },
5889   { CODE_FOR_ssroundsi2, "__builtin_bfin_round_fr1x32", BFIN_BUILTIN_ROUND_1X32, 0 },
5890   { CODE_FOR_ssnegsi2, "__builtin_bfin_negate_fr1x32", BFIN_BUILTIN_NEG_1X32, 0 },
5891   { CODE_FOR_ssabssi2, "__builtin_bfin_abs_fr1x32", BFIN_BUILTIN_ABS_1X32, 0 },
5892
5893   { CODE_FOR_movv2hi_hi_low, "__builtin_bfin_extract_lo", BFIN_BUILTIN_EXTRACTLO, 0 },
5894   { CODE_FOR_movv2hi_hi_high, "__builtin_bfin_extract_hi", BFIN_BUILTIN_EXTRACTHI, 0 },
5895   { CODE_FOR_ssnegv2hi2, "__builtin_bfin_negate_fr2x16", BFIN_BUILTIN_NEG_2X16, 0 },
5896   { CODE_FOR_ssabsv2hi2, "__builtin_bfin_abs_fr2x16", BFIN_BUILTIN_ABS_2X16, 0 }
5897 };
5898
5899 /* Errors in the source file can cause expand_expr to return const0_rtx
5900    where we expect a vector.  To avoid crashing, use one of the vector
5901    clear instructions.  */
5902 static rtx
5903 safe_vector_operand (rtx x, enum machine_mode mode)
5904 {
5905   if (x != const0_rtx)
5906     return x;
5907   x = gen_reg_rtx (SImode);
5908
5909   emit_insn (gen_movsi (x, CONST0_RTX (SImode)));
5910   return gen_lowpart (mode, x);
5911 }
5912
5913 /* Subroutine of bfin_expand_builtin to take care of binop insns.  MACFLAG is -1
5914    if this is a normal binary op, or one of the MACFLAG_xxx constants.  */
5915
5916 static rtx
5917 bfin_expand_binop_builtin (enum insn_code icode, tree exp, rtx target,
5918                            int macflag)
5919 {
5920   rtx pat;
5921   tree arg0 = CALL_EXPR_ARG (exp, 0);
5922   tree arg1 = CALL_EXPR_ARG (exp, 1);
5923   rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
5924   rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
5925   enum machine_mode op0mode = GET_MODE (op0);
5926   enum machine_mode op1mode = GET_MODE (op1);
5927   enum machine_mode tmode = insn_data[icode].operand[0].mode;
5928   enum machine_mode mode0 = insn_data[icode].operand[1].mode;
5929   enum machine_mode mode1 = insn_data[icode].operand[2].mode;
5930
5931   if (VECTOR_MODE_P (mode0))
5932     op0 = safe_vector_operand (op0, mode0);
5933   if (VECTOR_MODE_P (mode1))
5934     op1 = safe_vector_operand (op1, mode1);
5935
5936   if (! target
5937       || GET_MODE (target) != tmode
5938       || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
5939     target = gen_reg_rtx (tmode);
5940
5941   if ((op0mode == SImode || op0mode == VOIDmode) && mode0 == HImode)
5942     {
5943       op0mode = HImode;
5944       op0 = gen_lowpart (HImode, op0);
5945     }
5946   if ((op1mode == SImode || op1mode == VOIDmode) && mode1 == HImode)
5947     {
5948       op1mode = HImode;
5949       op1 = gen_lowpart (HImode, op1);
5950     }
5951   /* In case the insn wants input operands in modes different from
5952      the result, abort.  */
5953   gcc_assert ((op0mode == mode0 || op0mode == VOIDmode)
5954               && (op1mode == mode1 || op1mode == VOIDmode));
5955
5956   if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
5957     op0 = copy_to_mode_reg (mode0, op0);
5958   if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
5959     op1 = copy_to_mode_reg (mode1, op1);
5960
5961   if (macflag == -1)
5962     pat = GEN_FCN (icode) (target, op0, op1);
5963   else
5964     pat = GEN_FCN (icode) (target, op0, op1, GEN_INT (macflag));
5965   if (! pat)
5966     return 0;
5967
5968   emit_insn (pat);
5969   return target;
5970 }
5971
5972 /* Subroutine of bfin_expand_builtin to take care of unop insns.  */
5973
5974 static rtx
5975 bfin_expand_unop_builtin (enum insn_code icode, tree exp,
5976                           rtx target)
5977 {
5978   rtx pat;
5979   tree arg0 = CALL_EXPR_ARG (exp, 0);
5980   rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
5981   enum machine_mode op0mode = GET_MODE (op0);
5982   enum machine_mode tmode = insn_data[icode].operand[0].mode;
5983   enum machine_mode mode0 = insn_data[icode].operand[1].mode;
5984
5985   if (! target
5986       || GET_MODE (target) != tmode
5987       || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
5988     target = gen_reg_rtx (tmode);
5989
5990   if (VECTOR_MODE_P (mode0))
5991     op0 = safe_vector_operand (op0, mode0);
5992
5993   if (op0mode == SImode && mode0 == HImode)
5994     {
5995       op0mode = HImode;
5996       op0 = gen_lowpart (HImode, op0);
5997     }
5998   gcc_assert (op0mode == mode0 || op0mode == VOIDmode);
5999
6000   if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
6001     op0 = copy_to_mode_reg (mode0, op0);
6002
6003   pat = GEN_FCN (icode) (target, op0);
6004   if (! pat)
6005     return 0;
6006   emit_insn (pat);
6007   return target;
6008 }
6009
6010 /* Expand an expression EXP that calls a built-in function,
6011    with result going to TARGET if that's convenient
6012    (and in mode MODE if that's convenient).
6013    SUBTARGET may be used as the target for computing one of EXP's operands.
6014    IGNORE is nonzero if the value is to be ignored.  */
6015
6016 static rtx
6017 bfin_expand_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
6018                      rtx subtarget ATTRIBUTE_UNUSED,
6019                      enum machine_mode mode ATTRIBUTE_UNUSED,
6020                      int ignore ATTRIBUTE_UNUSED)
6021 {
6022   size_t i;
6023   enum insn_code icode;
6024   const struct builtin_description *d;
6025   tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
6026   unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
6027   tree arg0, arg1, arg2;
6028   rtx op0, op1, op2, accvec, pat, tmp1, tmp2, a0reg, a1reg;
6029   enum machine_mode tmode, mode0;
6030
6031   switch (fcode)
6032     {
6033     case BFIN_BUILTIN_CSYNC:
6034       emit_insn (gen_csync ());
6035       return 0;
6036     case BFIN_BUILTIN_SSYNC:
6037       emit_insn (gen_ssync ());
6038       return 0;
6039
6040     case BFIN_BUILTIN_DIFFHL_2X16:
6041     case BFIN_BUILTIN_DIFFLH_2X16:
6042     case BFIN_BUILTIN_SUM_2X16:
6043       arg0 = CALL_EXPR_ARG (exp, 0);
6044       op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6045       icode = (fcode == BFIN_BUILTIN_DIFFHL_2X16 ? CODE_FOR_subhilov2hi3
6046                : fcode == BFIN_BUILTIN_DIFFLH_2X16 ? CODE_FOR_sublohiv2hi3
6047                : CODE_FOR_ssaddhilov2hi3);
6048       tmode = insn_data[icode].operand[0].mode;
6049       mode0 = insn_data[icode].operand[1].mode;
6050
6051       if (! target
6052           || GET_MODE (target) != tmode
6053           || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
6054         target = gen_reg_rtx (tmode);
6055
6056       if (VECTOR_MODE_P (mode0))
6057         op0 = safe_vector_operand (op0, mode0);
6058
6059       if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
6060         op0 = copy_to_mode_reg (mode0, op0);
6061
6062       pat = GEN_FCN (icode) (target, op0, op0);
6063       if (! pat)
6064         return 0;
6065       emit_insn (pat);
6066       return target;
6067
6068     case BFIN_BUILTIN_MULT_1X32X32:
6069     case BFIN_BUILTIN_MULT_1X32X32NS:
6070       arg0 = CALL_EXPR_ARG (exp, 0);
6071       arg1 = CALL_EXPR_ARG (exp, 1);
6072       op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6073       op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
6074       if (! target
6075           || !register_operand (target, SImode))
6076         target = gen_reg_rtx (SImode);
6077
6078       a1reg = gen_rtx_REG (PDImode, REG_A1);
6079       a0reg = gen_rtx_REG (PDImode, REG_A0);
6080       tmp1 = gen_lowpart (V2HImode, op0);
6081       tmp2 = gen_lowpart (V2HImode, op1);
6082       emit_insn (gen_flag_macinit1hi (a1reg,
6083                                       gen_lowpart (HImode, op0),
6084                                       gen_lowpart (HImode, op1),
6085                                       GEN_INT (MACFLAG_FU)));
6086       emit_insn (gen_lshrpdi3 (a1reg, a1reg, GEN_INT (16)));
6087
6088       if (fcode == BFIN_BUILTIN_MULT_1X32X32)
6089         emit_insn (gen_flag_mul_macv2hi_parts_acconly (a0reg, a1reg, tmp1, tmp2,
6090                                                        const1_rtx, const1_rtx,
6091                                                        const1_rtx, const0_rtx, a1reg,
6092                                                        const0_rtx, GEN_INT (MACFLAG_NONE),
6093                                                        GEN_INT (MACFLAG_M)));
6094       else
6095         {
6096           /* For saturating multiplication, there's exactly one special case
6097              to be handled: multiplying the smallest negative value with
6098              itself.  Due to shift correction in fractional multiplies, this
6099              can overflow.  Iff this happens, OP2 will contain 1, which, when
6100              added in 32 bits to the smallest negative, wraps to the largest
6101              positive, which is the result we want.  */
6102           op2 = gen_reg_rtx (V2HImode);
6103           emit_insn (gen_packv2hi (op2, tmp1, tmp2, const0_rtx, const0_rtx));
6104           emit_insn (gen_movsibi (gen_rtx_REG (BImode, REG_CC),
6105                                   gen_lowpart (SImode, op2)));
6106           emit_insn (gen_flag_mul_macv2hi_parts_acconly_andcc0 (a0reg, a1reg, tmp1, tmp2,
6107                                                                 const1_rtx, const1_rtx,
6108                                                                 const1_rtx, const0_rtx, a1reg,
6109                                                                 const0_rtx, GEN_INT (MACFLAG_NONE),
6110                                                                 GEN_INT (MACFLAG_M)));
6111           op2 = gen_reg_rtx (SImode);
6112           emit_insn (gen_movbisi (op2, gen_rtx_REG (BImode, REG_CC)));
6113         }
6114       emit_insn (gen_flag_machi_parts_acconly (a1reg, tmp2, tmp1,
6115                                                const1_rtx, const0_rtx,
6116                                                a1reg, const0_rtx, GEN_INT (MACFLAG_M)));
6117       emit_insn (gen_ashrpdi3 (a1reg, a1reg, GEN_INT (15)));
6118       emit_insn (gen_sum_of_accumulators (target, a0reg, a0reg, a1reg));
6119       if (fcode == BFIN_BUILTIN_MULT_1X32X32NS)
6120         emit_insn (gen_addsi3 (target, target, op2));
6121       return target;
6122
6123     case BFIN_BUILTIN_CPLX_MUL_16:
6124     case BFIN_BUILTIN_CPLX_MUL_16_S40:
6125       arg0 = CALL_EXPR_ARG (exp, 0);
6126       arg1 = CALL_EXPR_ARG (exp, 1);
6127       op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6128       op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
6129       accvec = gen_reg_rtx (V2PDImode);
6130
6131       if (! target
6132           || GET_MODE (target) != V2HImode
6133           || ! (*insn_data[icode].operand[0].predicate) (target, V2HImode))
6134         target = gen_reg_rtx (tmode);
6135       if (! register_operand (op0, GET_MODE (op0)))
6136         op0 = copy_to_mode_reg (GET_MODE (op0), op0);
6137       if (! register_operand (op1, GET_MODE (op1)))
6138         op1 = copy_to_mode_reg (GET_MODE (op1), op1);
6139
6140       if (fcode == BFIN_BUILTIN_CPLX_MUL_16)
6141         emit_insn (gen_flag_macinit1v2hi_parts (accvec, op0, op1, const0_rtx,
6142                                                 const0_rtx, const0_rtx,
6143                                                 const1_rtx, GEN_INT (MACFLAG_W32)));
6144       else
6145         emit_insn (gen_flag_macinit1v2hi_parts (accvec, op0, op1, const0_rtx,
6146                                                 const0_rtx, const0_rtx,
6147                                                 const1_rtx, GEN_INT (MACFLAG_NONE)));
6148       emit_insn (gen_flag_macv2hi_parts (target, op0, op1, const1_rtx,
6149                                          const1_rtx, const1_rtx,
6150                                          const0_rtx, accvec, const1_rtx, const0_rtx,
6151                                          GEN_INT (MACFLAG_NONE), accvec));
6152
6153       return target;
6154
6155     case BFIN_BUILTIN_CPLX_MAC_16:
6156     case BFIN_BUILTIN_CPLX_MSU_16:
6157     case BFIN_BUILTIN_CPLX_MAC_16_S40:
6158     case BFIN_BUILTIN_CPLX_MSU_16_S40:
6159       arg0 = CALL_EXPR_ARG (exp, 0);
6160       arg1 = CALL_EXPR_ARG (exp, 1);
6161       arg2 = CALL_EXPR_ARG (exp, 2);
6162       op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6163       op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
6164       op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
6165       accvec = gen_reg_rtx (V2PDImode);
6166
6167       if (! target
6168           || GET_MODE (target) != V2HImode
6169           || ! (*insn_data[icode].operand[0].predicate) (target, V2HImode))
6170         target = gen_reg_rtx (tmode);
6171       if (! register_operand (op1, GET_MODE (op1)))
6172         op1 = copy_to_mode_reg (GET_MODE (op1), op1);
6173       if (! register_operand (op2, GET_MODE (op2)))
6174         op2 = copy_to_mode_reg (GET_MODE (op2), op2);
6175
6176       tmp1 = gen_reg_rtx (SImode);
6177       tmp2 = gen_reg_rtx (SImode);
6178       emit_insn (gen_ashlsi3 (tmp1, gen_lowpart (SImode, op0), GEN_INT (16)));
6179       emit_move_insn (tmp2, gen_lowpart (SImode, op0));
6180       emit_insn (gen_movstricthi_1 (gen_lowpart (HImode, tmp2), const0_rtx));
6181       emit_insn (gen_load_accumulator_pair (accvec, tmp1, tmp2));
6182       if (fcode == BFIN_BUILTIN_CPLX_MAC_16
6183           || fcode == BFIN_BUILTIN_CPLX_MSU_16)
6184         emit_insn (gen_flag_macv2hi_parts_acconly (accvec, op1, op2, const0_rtx,
6185                                                    const0_rtx, const0_rtx,
6186                                                    const1_rtx, accvec, const0_rtx,
6187                                                    const0_rtx,
6188                                                    GEN_INT (MACFLAG_W32)));
6189       else
6190         emit_insn (gen_flag_macv2hi_parts_acconly (accvec, op1, op2, const0_rtx,
6191                                                    const0_rtx, const0_rtx,
6192                                                    const1_rtx, accvec, const0_rtx,
6193                                                    const0_rtx,
6194                                                    GEN_INT (MACFLAG_NONE)));
6195       if (fcode == BFIN_BUILTIN_CPLX_MAC_16
6196           || fcode == BFIN_BUILTIN_CPLX_MAC_16_S40)
6197         {
6198           tmp1 = const1_rtx;
6199           tmp2 = const0_rtx;
6200         }
6201       else
6202         {
6203           tmp1 = const0_rtx;
6204           tmp2 = const1_rtx;
6205         }
6206       emit_insn (gen_flag_macv2hi_parts (target, op1, op2, const1_rtx,
6207                                          const1_rtx, const1_rtx,
6208                                          const0_rtx, accvec, tmp1, tmp2,
6209                                          GEN_INT (MACFLAG_NONE), accvec));
6210
6211       return target;
6212
6213     case BFIN_BUILTIN_CPLX_SQU:
6214       arg0 = CALL_EXPR_ARG (exp, 0);
6215       op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6216       accvec = gen_reg_rtx (V2PDImode);
6217       icode = CODE_FOR_flag_mulv2hi;
6218       tmp1 = gen_reg_rtx (V2HImode);
6219       tmp2 = gen_reg_rtx (V2HImode);
6220
6221       if (! target
6222           || GET_MODE (target) != V2HImode
6223           || ! (*insn_data[icode].operand[0].predicate) (target, V2HImode))
6224         target = gen_reg_rtx (V2HImode);
6225       if (! register_operand (op0, GET_MODE (op0)))
6226         op0 = copy_to_mode_reg (GET_MODE (op0), op0);
6227
6228       emit_insn (gen_flag_mulv2hi (tmp1, op0, op0, GEN_INT (MACFLAG_NONE)));
6229
6230       emit_insn (gen_flag_mulhi_parts (gen_lowpart (HImode, tmp2), op0, op0,
6231                                        const0_rtx, const1_rtx,
6232                                        GEN_INT (MACFLAG_NONE)));
6233
6234       emit_insn (gen_ssaddhi3_high_parts (target, tmp2, tmp2, tmp2, const0_rtx,
6235                                           const0_rtx));
6236       emit_insn (gen_sssubhi3_low_parts (target, target, tmp1, tmp1,
6237                                          const0_rtx, const1_rtx));
6238
6239       return target;
6240
6241     default:
6242       break;
6243     }
6244
6245   for (i = 0, d = bdesc_2arg; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
6246     if (d->code == fcode)
6247       return bfin_expand_binop_builtin (d->icode, exp, target,
6248                                         d->macflag);
6249
6250   for (i = 0, d = bdesc_1arg; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
6251     if (d->code == fcode)
6252       return bfin_expand_unop_builtin (d->icode, exp, target);
6253
6254   gcc_unreachable ();
6255 }
6256 \f
6257 #undef TARGET_INIT_BUILTINS
6258 #define TARGET_INIT_BUILTINS bfin_init_builtins
6259
6260 #undef TARGET_EXPAND_BUILTIN
6261 #define TARGET_EXPAND_BUILTIN bfin_expand_builtin
6262
6263 #undef TARGET_ASM_GLOBALIZE_LABEL
6264 #define TARGET_ASM_GLOBALIZE_LABEL bfin_globalize_label 
6265
6266 #undef TARGET_ASM_FILE_START
6267 #define TARGET_ASM_FILE_START output_file_start
6268
6269 #undef TARGET_ATTRIBUTE_TABLE
6270 #define TARGET_ATTRIBUTE_TABLE bfin_attribute_table
6271
6272 #undef TARGET_COMP_TYPE_ATTRIBUTES
6273 #define TARGET_COMP_TYPE_ATTRIBUTES bfin_comp_type_attributes
6274
6275 #undef TARGET_RTX_COSTS
6276 #define TARGET_RTX_COSTS bfin_rtx_costs
6277
6278 #undef  TARGET_ADDRESS_COST
6279 #define TARGET_ADDRESS_COST bfin_address_cost
6280
6281 #undef  TARGET_ASM_INTEGER
6282 #define TARGET_ASM_INTEGER bfin_assemble_integer
6283
6284 #undef TARGET_MACHINE_DEPENDENT_REORG
6285 #define TARGET_MACHINE_DEPENDENT_REORG bfin_reorg
6286
6287 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
6288 #define TARGET_FUNCTION_OK_FOR_SIBCALL bfin_function_ok_for_sibcall
6289
6290 #undef TARGET_ASM_OUTPUT_MI_THUNK
6291 #define TARGET_ASM_OUTPUT_MI_THUNK bfin_output_mi_thunk
6292 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
6293 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true
6294
6295 #undef TARGET_SCHED_ADJUST_COST
6296 #define TARGET_SCHED_ADJUST_COST bfin_adjust_cost
6297
6298 #undef TARGET_SCHED_ISSUE_RATE
6299 #define TARGET_SCHED_ISSUE_RATE bfin_issue_rate
6300
6301 #undef TARGET_PROMOTE_PROTOTYPES
6302 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
6303 #undef TARGET_PROMOTE_FUNCTION_ARGS
6304 #define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_const_tree_true
6305 #undef TARGET_PROMOTE_FUNCTION_RETURN
6306 #define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_const_tree_true
6307
6308 #undef TARGET_ARG_PARTIAL_BYTES
6309 #define TARGET_ARG_PARTIAL_BYTES bfin_arg_partial_bytes
6310
6311 #undef TARGET_PASS_BY_REFERENCE
6312 #define TARGET_PASS_BY_REFERENCE bfin_pass_by_reference
6313
6314 #undef TARGET_SETUP_INCOMING_VARARGS
6315 #define TARGET_SETUP_INCOMING_VARARGS setup_incoming_varargs
6316
6317 #undef TARGET_STRUCT_VALUE_RTX
6318 #define TARGET_STRUCT_VALUE_RTX bfin_struct_value_rtx
6319
6320 #undef TARGET_VECTOR_MODE_SUPPORTED_P
6321 #define TARGET_VECTOR_MODE_SUPPORTED_P bfin_vector_mode_supported_p
6322
6323 #undef TARGET_HANDLE_OPTION
6324 #define TARGET_HANDLE_OPTION bfin_handle_option
6325
6326 #undef TARGET_DEFAULT_TARGET_FLAGS
6327 #define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
6328
6329 #undef TARGET_SECONDARY_RELOAD
6330 #define TARGET_SECONDARY_RELOAD bfin_secondary_reload
6331
6332 #undef TARGET_DELEGITIMIZE_ADDRESS
6333 #define TARGET_DELEGITIMIZE_ADDRESS bfin_delegitimize_address
6334
6335 #undef TARGET_CANNOT_FORCE_CONST_MEM
6336 #define TARGET_CANNOT_FORCE_CONST_MEM bfin_cannot_force_const_mem
6337
6338 #undef TARGET_RETURN_IN_MEMORY
6339 #define TARGET_RETURN_IN_MEMORY bfin_return_in_memory
6340
6341 struct gcc_target targetm = TARGET_INITIALIZER;