OSDN Git Service

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