OSDN Git Service

* config/bfin/bfin.c (bfin_rtx_costs): Handle UDIV, UMOD.
[pf3gnuchains/gcc-fork.git] / gcc / config / bfin / bfin.c
1 /* The Blackfin code generation auxiliary output file.
2    Copyright (C) 2005, 2006  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 2, 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 COPYING.  If not, write to
19    the Free Software Foundation, 51 Franklin Street, Fifth Floor,
20    Boston, MA 02110-1301, USA.  */
21
22 #include "config.h"
23 #include "system.h"
24 #include "coretypes.h"
25 #include "tm.h"
26 #include "rtl.h"
27 #include "regs.h"
28 #include "hard-reg-set.h"
29 #include "real.h"
30 #include "insn-config.h"
31 #include "insn-codes.h"
32 #include "conditions.h"
33 #include "insn-flags.h"
34 #include "output.h"
35 #include "insn-attr.h"
36 #include "tree.h"
37 #include "flags.h"
38 #include "except.h"
39 #include "function.h"
40 #include "input.h"
41 #include "target.h"
42 #include "target-def.h"
43 #include "expr.h"
44 #include "toplev.h"
45 #include "recog.h"
46 #include "optabs.h"
47 #include "ggc.h"
48 #include "integrate.h"
49 #include "cgraph.h"
50 #include "langhooks.h"
51 #include "bfin-protos.h"
52 #include "tm-preds.h"
53 #include "gt-bfin.h"
54 #include "basic-block.h"
55
56 /* A C structure for machine-specific, per-function data.
57    This is added to the cfun structure.  */
58 struct machine_function GTY(())
59 {
60   int has_hardware_loops;
61 };
62
63 /* Test and compare insns in bfin.md store the information needed to
64    generate branch and scc insns here.  */
65 rtx bfin_compare_op0, bfin_compare_op1;
66
67 /* RTX for condition code flag register and RETS register */
68 extern GTY(()) rtx bfin_cc_rtx;
69 extern GTY(()) rtx bfin_rets_rtx;
70 rtx bfin_cc_rtx, bfin_rets_rtx;
71
72 int max_arg_registers = 0;
73
74 /* Arrays used when emitting register names.  */
75 const char *short_reg_names[]  =  SHORT_REGISTER_NAMES;
76 const char *high_reg_names[]   =  HIGH_REGISTER_NAMES;
77 const char *dregs_pair_names[] =  DREGS_PAIR_NAMES;
78 const char *byte_reg_names[]   =  BYTE_REGISTER_NAMES;
79
80 static int arg_regs[] = FUNCTION_ARG_REGISTERS;
81
82 /* Nonzero if -mshared-library-id was given.  */
83 static int bfin_lib_id_given;
84
85 static void
86 bfin_globalize_label (FILE *stream, const char *name)
87 {
88   fputs (".global ", stream);
89   assemble_name (stream, name);
90   fputc (';',stream);
91   fputc ('\n',stream);
92 }
93
94 static void 
95 output_file_start (void) 
96 {
97   FILE *file = asm_out_file;
98   int i;
99
100   fprintf (file, ".file \"%s\";\n", input_filename);
101   
102   for (i = 0; arg_regs[i] >= 0; i++)
103     ;
104   max_arg_registers = i;        /* how many arg reg used  */
105 }
106
107 /* Called early in the compilation to conditionally modify
108    fixed_regs/call_used_regs.  */
109
110 void 
111 conditional_register_usage (void)
112 {
113   /* initialize condition code flag register rtx */
114   bfin_cc_rtx = gen_rtx_REG (BImode, REG_CC);
115   bfin_rets_rtx = gen_rtx_REG (Pmode, REG_RETS);
116 }
117
118 /* Examine machine-dependent attributes of function type FUNTYPE and return its
119    type.  See the definition of E_FUNKIND.  */
120
121 static e_funkind funkind (tree funtype)
122 {
123   tree attrs = TYPE_ATTRIBUTES (funtype);
124   if (lookup_attribute ("interrupt_handler", attrs))
125     return INTERRUPT_HANDLER;
126   else if (lookup_attribute ("exception_handler", attrs))
127     return EXCPT_HANDLER;
128   else if (lookup_attribute ("nmi_handler", attrs))
129     return NMI_HANDLER;
130   else
131     return SUBROUTINE;
132 }
133 \f
134 /* Legitimize PIC addresses.  If the address is already position-independent,
135    we return ORIG.  Newly generated position-independent addresses go into a
136    reg.  This is REG if nonzero, otherwise we allocate register(s) as
137    necessary.  PICREG is the register holding the pointer to the PIC offset
138    table.  */
139
140 static rtx
141 legitimize_pic_address (rtx orig, rtx reg, rtx picreg)
142 {
143   rtx addr = orig;
144   rtx new = orig;
145
146   if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == LABEL_REF)
147     {
148       if (GET_CODE (addr) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (addr))
149         reg = new = orig;
150       else
151         {
152           int unspec;
153           rtx tmp;
154
155           if (TARGET_ID_SHARED_LIBRARY)
156             unspec = UNSPEC_MOVE_PIC;
157           else if (GET_CODE (addr) == SYMBOL_REF
158                    && SYMBOL_REF_FUNCTION_P (addr))
159             {
160               unspec = UNSPEC_FUNCDESC_GOT17M4;
161             }
162           else
163             {
164               unspec = UNSPEC_MOVE_FDPIC;
165             }
166
167           if (reg == 0)
168             {
169               gcc_assert (!no_new_pseudos);
170               reg = gen_reg_rtx (Pmode);
171             }
172
173           tmp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), unspec);
174           new = gen_const_mem (Pmode, gen_rtx_PLUS (Pmode, picreg, tmp));
175
176           emit_move_insn (reg, new);
177         }
178       if (picreg == pic_offset_table_rtx)
179         current_function_uses_pic_offset_table = 1;
180       return reg;
181     }
182
183   else if (GET_CODE (addr) == CONST || GET_CODE (addr) == PLUS)
184     {
185       rtx base;
186
187       if (GET_CODE (addr) == CONST)
188         {
189           addr = XEXP (addr, 0);
190           gcc_assert (GET_CODE (addr) == PLUS);
191         }
192
193       if (XEXP (addr, 0) == picreg)
194         return orig;
195
196       if (reg == 0)
197         {
198           gcc_assert (!no_new_pseudos);
199           reg = gen_reg_rtx (Pmode);
200         }
201
202       base = legitimize_pic_address (XEXP (addr, 0), reg, picreg);
203       addr = legitimize_pic_address (XEXP (addr, 1),
204                                      base == reg ? NULL_RTX : reg,
205                                      picreg);
206
207       if (GET_CODE (addr) == CONST_INT)
208         {
209           gcc_assert (! reload_in_progress && ! reload_completed);
210           addr = force_reg (Pmode, addr);
211         }
212
213       if (GET_CODE (addr) == PLUS && CONSTANT_P (XEXP (addr, 1)))
214         {
215           base = gen_rtx_PLUS (Pmode, base, XEXP (addr, 0));
216           addr = XEXP (addr, 1);
217         }
218
219       return gen_rtx_PLUS (Pmode, base, addr);
220     }
221
222   return new;
223 }
224 \f
225 /* Stack frame layout. */
226
227 /* Compute the number of DREGS to save with a push_multiple operation.
228    This could include registers that aren't modified in the function,
229    since push_multiple only takes a range of registers.
230    If IS_INTHANDLER, then everything that is live must be saved, even
231    if normally call-clobbered.  */
232
233 static int
234 n_dregs_to_save (bool is_inthandler)
235 {
236   unsigned i;
237
238   for (i = REG_R0; i <= REG_R7; i++)
239     {
240       if (regs_ever_live[i] && (is_inthandler || ! call_used_regs[i]))
241         return REG_R7 - i + 1;
242
243       if (current_function_calls_eh_return)
244         {
245           unsigned j;
246           for (j = 0; ; j++)
247             {
248               unsigned test = EH_RETURN_DATA_REGNO (j);
249               if (test == INVALID_REGNUM)
250                 break;
251               if (test == i)
252                 return REG_R7 - i + 1;
253             }
254         }
255
256     }
257   return 0;
258 }
259
260 /* Like n_dregs_to_save, but compute number of PREGS to save.  */
261
262 static int
263 n_pregs_to_save (bool is_inthandler)
264 {
265   unsigned i;
266
267   for (i = REG_P0; i <= REG_P5; i++)
268     if ((regs_ever_live[i] && (is_inthandler || ! call_used_regs[i]))
269         || (!TARGET_FDPIC
270             && i == PIC_OFFSET_TABLE_REGNUM
271             && (current_function_uses_pic_offset_table
272                 || (TARGET_ID_SHARED_LIBRARY && ! current_function_is_leaf))))
273       return REG_P5 - i + 1;
274   return 0;
275 }
276
277 /* Determine if we are going to save the frame pointer in the prologue.  */
278
279 static bool
280 must_save_fp_p (void)
281 {
282   return frame_pointer_needed || regs_ever_live[REG_FP];
283 }
284
285 static bool
286 stack_frame_needed_p (void)
287 {
288   /* EH return puts a new return address into the frame using an
289      address relative to the frame pointer.  */
290   if (current_function_calls_eh_return)
291     return true;
292   return frame_pointer_needed;
293 }
294
295 /* Emit code to save registers in the prologue.  SAVEALL is nonzero if we
296    must save all registers; this is used for interrupt handlers.
297    SPREG contains (reg:SI REG_SP).  IS_INTHANDLER is true if we're doing
298    this for an interrupt (or exception) handler.  */
299
300 static void
301 expand_prologue_reg_save (rtx spreg, int saveall, bool is_inthandler)
302 {
303   int ndregs = saveall ? 8 : n_dregs_to_save (is_inthandler);
304   int npregs = saveall ? 6 : n_pregs_to_save (is_inthandler);
305   int dregno = REG_R7 + 1 - ndregs;
306   int pregno = REG_P5 + 1 - npregs;
307   int total = ndregs + npregs;
308   int i;
309   rtx pat, insn, val;
310
311   if (total == 0)
312     return;
313
314   val = GEN_INT (-total * 4);
315   pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total + 2));
316   XVECEXP (pat, 0, 0) = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, val),
317                                         UNSPEC_PUSH_MULTIPLE);
318   XVECEXP (pat, 0, total + 1) = gen_rtx_SET (VOIDmode, spreg,
319                                              gen_rtx_PLUS (Pmode, spreg,
320                                                            val));
321   RTX_FRAME_RELATED_P (XVECEXP (pat, 0, total + 1)) = 1;
322   for (i = 0; i < total; i++)
323     {
324       rtx memref = gen_rtx_MEM (word_mode,
325                                 gen_rtx_PLUS (Pmode, spreg,
326                                               GEN_INT (- i * 4 - 4)));
327       rtx subpat;
328       if (ndregs > 0)
329         {
330           subpat = gen_rtx_SET (VOIDmode, memref, gen_rtx_REG (word_mode,
331                                                                dregno++));
332           ndregs--;
333         }
334       else
335         {
336           subpat = gen_rtx_SET (VOIDmode, memref, gen_rtx_REG (word_mode,
337                                                                pregno++));
338           npregs++;
339         }
340       XVECEXP (pat, 0, i + 1) = subpat;
341       RTX_FRAME_RELATED_P (subpat) = 1;
342     }
343   insn = emit_insn (pat);
344   RTX_FRAME_RELATED_P (insn) = 1;
345 }
346
347 /* Emit code to restore registers in the epilogue.  SAVEALL is nonzero if we
348    must save all registers; this is used for interrupt handlers.
349    SPREG contains (reg:SI REG_SP).  IS_INTHANDLER is true if we're doing
350    this for an interrupt (or exception) handler.  */
351
352 static void
353 expand_epilogue_reg_restore (rtx spreg, bool saveall, bool is_inthandler)
354 {
355   int ndregs = saveall ? 8 : n_dregs_to_save (is_inthandler);
356   int npregs = saveall ? 6 : n_pregs_to_save (is_inthandler);
357   int total = ndregs + npregs;
358   int i, regno;
359   rtx pat, insn;
360
361   if (total == 0)
362     return;
363
364   pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total + 1));
365   XVECEXP (pat, 0, 0) = gen_rtx_SET (VOIDmode, spreg,
366                                      gen_rtx_PLUS (Pmode, spreg,
367                                                    GEN_INT (total * 4)));
368
369   if (npregs > 0)
370     regno = REG_P5 + 1;
371   else
372     regno = REG_R7 + 1;
373
374   for (i = 0; i < total; i++)
375     {
376       rtx addr = (i > 0
377                   ? gen_rtx_PLUS (Pmode, spreg, GEN_INT (i * 4))
378                   : spreg);
379       rtx memref = gen_rtx_MEM (word_mode, addr);
380
381       regno--;
382       XVECEXP (pat, 0, i + 1)
383         = gen_rtx_SET (VOIDmode, gen_rtx_REG (word_mode, regno), memref);
384
385       if (npregs > 0)
386         {
387           if (--npregs == 0)
388             regno = REG_R7 + 1;
389         }
390     }
391
392   insn = emit_insn (pat);
393   RTX_FRAME_RELATED_P (insn) = 1;
394 }
395
396 /* Perform any needed actions needed for a function that is receiving a
397    variable number of arguments.
398
399    CUM is as above.
400
401    MODE and TYPE are the mode and type of the current parameter.
402
403    PRETEND_SIZE is a variable that should be set to the amount of stack
404    that must be pushed by the prolog to pretend that our caller pushed
405    it.
406
407    Normally, this macro will push all remaining incoming registers on the
408    stack and set PRETEND_SIZE to the length of the registers pushed.  
409
410    Blackfin specific :
411    - VDSP C compiler manual (our ABI) says that a variable args function
412      should save the R0, R1 and R2 registers in the stack.
413    - The caller will always leave space on the stack for the
414      arguments that are passed in registers, so we dont have
415      to leave any extra space.
416    - now, the vastart pointer can access all arguments from the stack.  */
417
418 static void
419 setup_incoming_varargs (CUMULATIVE_ARGS *cum,
420                         enum machine_mode mode ATTRIBUTE_UNUSED,
421                         tree type ATTRIBUTE_UNUSED, int *pretend_size,
422                         int no_rtl)
423 {
424   rtx mem;
425   int i;
426
427   if (no_rtl)
428     return;
429
430   /* The move for named arguments will be generated automatically by the
431      compiler.  We need to generate the move rtx for the unnamed arguments
432      if they are in the first 3 words.  We assume at least 1 named argument
433      exists, so we never generate [ARGP] = R0 here.  */
434
435   for (i = cum->words + 1; i < max_arg_registers; i++)
436     {
437       mem = gen_rtx_MEM (Pmode,
438                          plus_constant (arg_pointer_rtx, (i * UNITS_PER_WORD)));
439       emit_move_insn (mem, gen_rtx_REG (Pmode, i));
440     }
441
442   *pretend_size = 0;
443 }
444
445 /* Value should be nonzero if functions must have frame pointers.
446    Zero means the frame pointer need not be set up (and parms may
447    be accessed via the stack pointer) in functions that seem suitable.  */
448
449 int
450 bfin_frame_pointer_required (void) 
451 {
452   e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
453
454   if (fkind != SUBROUTINE)
455     return 1;
456
457   /* We turn on -fomit-frame-pointer if -momit-leaf-frame-pointer is used,
458      so we have to override it for non-leaf functions.  */
459   if (TARGET_OMIT_LEAF_FRAME_POINTER && ! current_function_is_leaf)
460     return 1;
461
462   return 0;
463 }
464
465 /* Return the number of registers pushed during the prologue.  */
466
467 static int
468 n_regs_saved_by_prologue (void)
469 {
470   e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
471   bool is_inthandler = fkind != SUBROUTINE;
472   tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
473   bool all = (lookup_attribute ("saveall", attrs) != NULL_TREE
474               || (is_inthandler && !current_function_is_leaf));
475   int ndregs = all ? 8 : n_dregs_to_save (is_inthandler);
476   int npregs = all ? 6 : n_pregs_to_save (is_inthandler);  
477   int n = ndregs + npregs;
478
479   if (all || stack_frame_needed_p ())
480     /* We use a LINK instruction in this case.  */
481     n += 2;
482   else
483     {
484       if (must_save_fp_p ())
485         n++;
486       if (! current_function_is_leaf)
487         n++;
488     }
489
490   if (fkind != SUBROUTINE)
491     {
492       int i;
493
494       /* Increment once for ASTAT.  */
495       n++;
496
497       /* RETE/X/N.  */
498       if (lookup_attribute ("nesting", attrs))
499         n++;
500
501       for (i = REG_P7 + 1; i < REG_CC; i++)
502         if (all 
503             || regs_ever_live[i]
504             || (!leaf_function_p () && call_used_regs[i]))
505           n += i == REG_A0 || i == REG_A1 ? 2 : 1;
506     }
507   return n;
508 }
509
510 /* Return the offset between two registers, one to be eliminated, and the other
511    its replacement, at the start of a routine.  */
512
513 HOST_WIDE_INT
514 bfin_initial_elimination_offset (int from, int to)
515 {
516   HOST_WIDE_INT offset = 0;
517
518   if (from == ARG_POINTER_REGNUM)
519     offset = n_regs_saved_by_prologue () * 4;
520
521   if (to == STACK_POINTER_REGNUM)
522     {
523       if (current_function_outgoing_args_size >= FIXED_STACK_AREA)
524         offset += current_function_outgoing_args_size;
525       else if (current_function_outgoing_args_size)
526         offset += FIXED_STACK_AREA;
527
528       offset += get_frame_size ();
529     }
530
531   return offset;
532 }
533
534 /* Emit code to load a constant CONSTANT into register REG; setting
535    RTX_FRAME_RELATED_P on all insns we generate if RELATED is true.
536    Make sure that the insns we generate need not be split.  */
537
538 static void
539 frame_related_constant_load (rtx reg, HOST_WIDE_INT constant, bool related)
540 {
541   rtx insn;
542   rtx cst = GEN_INT (constant);
543
544   if (constant >= -32768 && constant < 65536)
545     insn = emit_move_insn (reg, cst);
546   else
547     {
548       /* We don't call split_load_immediate here, since dwarf2out.c can get
549          confused about some of the more clever sequences it can generate.  */
550       insn = emit_insn (gen_movsi_high (reg, cst));
551       if (related)
552         RTX_FRAME_RELATED_P (insn) = 1;
553       insn = emit_insn (gen_movsi_low (reg, reg, cst));
554     }
555   if (related)
556     RTX_FRAME_RELATED_P (insn) = 1;
557 }
558
559 /* Generate efficient code to add a value to the frame pointer.  We
560    can use P1 as a scratch register.  Set RTX_FRAME_RELATED_P on the
561    generated insns if FRAME is nonzero.  */
562
563 static void
564 add_to_sp (rtx spreg, HOST_WIDE_INT value, int frame)
565 {
566   if (value == 0)
567     return;
568
569   /* Choose whether to use a sequence using a temporary register, or
570      a sequence with multiple adds.  We can add a signed 7 bit value
571      in one instruction.  */
572   if (value > 120 || value < -120)
573     {
574       rtx tmpreg = gen_rtx_REG (SImode, REG_P1);
575       rtx insn;
576
577       if (frame)
578         frame_related_constant_load (tmpreg, value, TRUE);
579       else
580         {
581           insn = emit_move_insn (tmpreg, GEN_INT (value));
582           if (frame)
583             RTX_FRAME_RELATED_P (insn) = 1;
584         }
585
586       insn = emit_insn (gen_addsi3 (spreg, spreg, tmpreg));
587       if (frame)
588         RTX_FRAME_RELATED_P (insn) = 1;
589     }
590   else
591     do
592       {
593         int size = value;
594         rtx insn;
595
596         if (size > 60)
597           size = 60;
598         else if (size < -60)
599           /* We could use -62, but that would leave the stack unaligned, so
600              it's no good.  */
601           size = -60;
602
603         insn = emit_insn (gen_addsi3 (spreg, spreg, GEN_INT (size)));
604         if (frame)
605           RTX_FRAME_RELATED_P (insn) = 1;
606         value -= size;
607       }
608     while (value != 0);
609 }
610
611 /* Generate a LINK insn for a frame sized FRAME_SIZE.  If this constant
612    is too large, generate a sequence of insns that has the same effect.
613    SPREG contains (reg:SI REG_SP).  */
614
615 static void
616 emit_link_insn (rtx spreg, HOST_WIDE_INT frame_size)
617 {
618   HOST_WIDE_INT link_size = frame_size;
619   rtx insn;
620   int i;
621
622   if (link_size > 262140)
623     link_size = 262140;
624
625   /* Use a LINK insn with as big a constant as possible, then subtract
626      any remaining size from the SP.  */
627   insn = emit_insn (gen_link (GEN_INT (-8 - link_size)));
628   RTX_FRAME_RELATED_P (insn) = 1;
629
630   for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
631     {
632       rtx set = XVECEXP (PATTERN (insn), 0, i);
633       gcc_assert (GET_CODE (set) == SET);
634       RTX_FRAME_RELATED_P (set) = 1;
635     }
636
637   frame_size -= link_size;
638
639   if (frame_size > 0)
640     {
641       /* Must use a call-clobbered PREG that isn't the static chain.  */
642       rtx tmpreg = gen_rtx_REG (Pmode, REG_P1);
643
644       frame_related_constant_load (tmpreg, -frame_size, TRUE);
645       insn = emit_insn (gen_addsi3 (spreg, spreg, tmpreg));
646       RTX_FRAME_RELATED_P (insn) = 1;
647     }
648 }
649
650 /* Return the number of bytes we must reserve for outgoing arguments
651    in the current function's stack frame.  */
652
653 static HOST_WIDE_INT
654 arg_area_size (void)
655 {
656   if (current_function_outgoing_args_size)
657     {
658       if (current_function_outgoing_args_size >= FIXED_STACK_AREA)
659         return current_function_outgoing_args_size;
660       else
661         return FIXED_STACK_AREA;
662     }
663   return 0;
664 }
665
666 /* Save RETS and FP, and allocate a stack frame.  ALL is true if the
667    function must save all its registers (true only for certain interrupt
668    handlers).  */
669
670 static void
671 do_link (rtx spreg, HOST_WIDE_INT frame_size, bool all)
672 {
673   frame_size += arg_area_size ();
674
675   if (all || stack_frame_needed_p ()
676       || (must_save_fp_p () && ! current_function_is_leaf))
677     emit_link_insn (spreg, frame_size);
678   else
679     {
680       if (! current_function_is_leaf)
681         {
682           rtx pat = gen_movsi (gen_rtx_MEM (Pmode,
683                                             gen_rtx_PRE_DEC (Pmode, spreg)),
684                                bfin_rets_rtx);
685           rtx insn = emit_insn (pat);
686           RTX_FRAME_RELATED_P (insn) = 1;
687         }
688       if (must_save_fp_p ())
689         {
690           rtx pat = gen_movsi (gen_rtx_MEM (Pmode,
691                                             gen_rtx_PRE_DEC (Pmode, spreg)),
692                                gen_rtx_REG (Pmode, REG_FP));
693           rtx insn = emit_insn (pat);
694           RTX_FRAME_RELATED_P (insn) = 1;
695         }
696       add_to_sp (spreg, -frame_size, 1);
697     }
698 }
699
700 /* Like do_link, but used for epilogues to deallocate the stack frame.  */
701
702 static void
703 do_unlink (rtx spreg, HOST_WIDE_INT frame_size, bool all)
704 {
705   frame_size += arg_area_size ();
706
707   if (all || stack_frame_needed_p ())
708     emit_insn (gen_unlink ());
709   else 
710     {
711       rtx postinc = gen_rtx_MEM (Pmode, gen_rtx_POST_INC (Pmode, spreg));
712
713       add_to_sp (spreg, frame_size, 0);
714       if (must_save_fp_p ())
715         {
716           rtx fpreg = gen_rtx_REG (Pmode, REG_FP);
717           emit_move_insn (fpreg, postinc);
718           emit_insn (gen_rtx_USE (VOIDmode, fpreg));
719         }
720       if (! current_function_is_leaf)
721         {
722           emit_move_insn (bfin_rets_rtx, postinc);
723           emit_insn (gen_rtx_USE (VOIDmode, bfin_rets_rtx));
724         }
725     }
726 }
727
728 /* Generate a prologue suitable for a function of kind FKIND.  This is
729    called for interrupt and exception handler prologues.
730    SPREG contains (reg:SI REG_SP).  */
731
732 static void
733 expand_interrupt_handler_prologue (rtx spreg, e_funkind fkind)
734 {
735   int i;
736   HOST_WIDE_INT frame_size = get_frame_size ();
737   rtx predec1 = gen_rtx_PRE_DEC (SImode, spreg);
738   rtx predec = gen_rtx_MEM (SImode, predec1);
739   rtx insn;
740   tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
741   bool all = lookup_attribute ("saveall", attrs) != NULL_TREE;
742   tree kspisusp = lookup_attribute ("kspisusp", attrs);
743
744   if (kspisusp)
745     {
746       insn = emit_move_insn (spreg, gen_rtx_REG (Pmode, REG_USP));
747       RTX_FRAME_RELATED_P (insn) = 1;
748     }
749
750   /* We need space on the stack in case we need to save the argument
751      registers.  */
752   if (fkind == EXCPT_HANDLER)
753     {
754       insn = emit_insn (gen_addsi3 (spreg, spreg, GEN_INT (-12)));
755       RTX_FRAME_RELATED_P (insn) = 1;
756     }
757
758   insn = emit_move_insn (predec, gen_rtx_REG (SImode, REG_ASTAT));
759   RTX_FRAME_RELATED_P (insn) = 1;
760
761   /* If we're calling other functions, they won't save their call-clobbered
762      registers, so we must save everything here.  */
763   if (!current_function_is_leaf)
764     all = true;
765   expand_prologue_reg_save (spreg, all, true);
766
767   for (i = REG_P7 + 1; i < REG_CC; i++)
768     if (all 
769         || regs_ever_live[i]
770         || (!leaf_function_p () && call_used_regs[i]))
771       {
772         if (i == REG_A0 || i == REG_A1)
773           insn = emit_move_insn (gen_rtx_MEM (PDImode, predec1),
774                                  gen_rtx_REG (PDImode, i));
775         else
776           insn = emit_move_insn (predec, gen_rtx_REG (SImode, i));
777         RTX_FRAME_RELATED_P (insn) = 1;
778       }
779
780   if (lookup_attribute ("nesting", attrs))
781     {
782       rtx srcreg = gen_rtx_REG (Pmode, (fkind == EXCPT_HANDLER ? REG_RETX
783                                         : fkind == NMI_HANDLER ? REG_RETN
784                                         : REG_RETI));
785       insn = emit_move_insn (predec, srcreg);
786       RTX_FRAME_RELATED_P (insn) = 1;
787     }
788
789   do_link (spreg, frame_size, all);
790
791   if (fkind == EXCPT_HANDLER)
792     {
793       rtx r0reg = gen_rtx_REG (SImode, REG_R0);
794       rtx r1reg = gen_rtx_REG (SImode, REG_R1);
795       rtx r2reg = gen_rtx_REG (SImode, REG_R2);
796       rtx insn;
797
798       insn = emit_move_insn (r0reg, gen_rtx_REG (SImode, REG_SEQSTAT));
799       REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx,
800                                             NULL_RTX);
801       insn = emit_insn (gen_ashrsi3 (r0reg, r0reg, GEN_INT (26)));
802       REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx,
803                                             NULL_RTX);
804       insn = emit_insn (gen_ashlsi3 (r0reg, r0reg, GEN_INT (26)));
805       REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx,
806                                             NULL_RTX);
807       insn = emit_move_insn (r1reg, spreg);
808       REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx,
809                                             NULL_RTX);
810       insn = emit_move_insn (r2reg, gen_rtx_REG (Pmode, REG_FP));
811       REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx,
812                                             NULL_RTX);
813       insn = emit_insn (gen_addsi3 (r2reg, r2reg, GEN_INT (8)));
814       REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx,
815                                             NULL_RTX);
816     }
817 }
818
819 /* Generate an epilogue suitable for a function of kind FKIND.  This is
820    called for interrupt and exception handler epilogues.
821    SPREG contains (reg:SI REG_SP).  */
822
823 static void
824 expand_interrupt_handler_epilogue (rtx spreg, e_funkind fkind)
825 {
826   int i;
827   rtx postinc1 = gen_rtx_POST_INC (SImode, spreg);
828   rtx postinc = gen_rtx_MEM (SImode, postinc1);
829   tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
830   bool all = lookup_attribute ("saveall", attrs) != NULL_TREE;
831
832   /* A slightly crude technique to stop flow from trying to delete "dead"
833      insns.  */
834   MEM_VOLATILE_P (postinc) = 1;
835
836   do_unlink (spreg, get_frame_size (), all);
837
838   if (lookup_attribute ("nesting", attrs))
839     {
840       rtx srcreg = gen_rtx_REG (Pmode, (fkind == EXCPT_HANDLER ? REG_RETX
841                                         : fkind == NMI_HANDLER ? REG_RETN
842                                         : REG_RETI));
843       emit_move_insn (srcreg, postinc);
844     }
845
846   /* If we're calling other functions, they won't save their call-clobbered
847      registers, so we must save (and restore) everything here.  */
848   if (!current_function_is_leaf)
849     all = true;
850
851   for (i = REG_CC - 1; i > REG_P7; i--)
852     if (all
853         || regs_ever_live[i]
854         || (!leaf_function_p () && call_used_regs[i]))
855       {
856         if (i == REG_A0 || i == REG_A1)
857           {
858             rtx mem = gen_rtx_MEM (PDImode, postinc1);
859             MEM_VOLATILE_P (mem) = 1;
860             emit_move_insn (gen_rtx_REG (PDImode, i), mem);
861           }
862         else
863           emit_move_insn (gen_rtx_REG (SImode, i), postinc);
864       }
865
866   expand_epilogue_reg_restore (spreg, all, true);
867
868   emit_move_insn (gen_rtx_REG (SImode, REG_ASTAT), postinc);
869
870   /* Deallocate any space we left on the stack in case we needed to save the
871      argument registers.  */
872   if (fkind == EXCPT_HANDLER)
873     emit_insn (gen_addsi3 (spreg, spreg, GEN_INT (12)));
874
875   emit_jump_insn (gen_return_internal (GEN_INT (fkind)));
876 }
877
878 /* Used while emitting the prologue to generate code to load the correct value
879    into the PIC register, which is passed in DEST.  */
880
881 static rtx
882 bfin_load_pic_reg (rtx dest)
883 {
884   struct cgraph_local_info *i = NULL;
885   rtx addr, insn;
886  
887   if (flag_unit_at_a_time)
888     i = cgraph_local_info (current_function_decl);
889  
890   /* Functions local to the translation unit don't need to reload the
891      pic reg, since the caller always passes a usable one.  */
892   if (i && i->local)
893     return pic_offset_table_rtx;
894       
895   if (bfin_lib_id_given)
896     addr = plus_constant (pic_offset_table_rtx, -4 - bfin_library_id * 4);
897   else
898     addr = gen_rtx_PLUS (Pmode, pic_offset_table_rtx,
899                          gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx),
900                                          UNSPEC_LIBRARY_OFFSET));
901   insn = emit_insn (gen_movsi (dest, gen_rtx_MEM (Pmode, addr)));
902   REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx, NULL);
903   return dest;
904 }
905
906 /* Generate RTL for the prologue of the current function.  */
907
908 void
909 bfin_expand_prologue (void)
910 {
911   rtx insn;
912   HOST_WIDE_INT frame_size = get_frame_size ();
913   rtx spreg = gen_rtx_REG (Pmode, REG_SP);
914   e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
915   rtx pic_reg_loaded = NULL_RTX;
916
917   if (fkind != SUBROUTINE)
918     {
919       expand_interrupt_handler_prologue (spreg, fkind);
920       return;
921     }
922
923   if (current_function_limit_stack)
924     {
925       HOST_WIDE_INT offset
926         = bfin_initial_elimination_offset (ARG_POINTER_REGNUM,
927                                            STACK_POINTER_REGNUM);
928       rtx lim = stack_limit_rtx;
929
930       if (GET_CODE (lim) == SYMBOL_REF)
931         {
932           rtx p2reg = gen_rtx_REG (Pmode, REG_P2);
933           if (TARGET_ID_SHARED_LIBRARY)
934             {
935               rtx p1reg = gen_rtx_REG (Pmode, REG_P1);
936               rtx val;
937               pic_reg_loaded = bfin_load_pic_reg (p2reg);
938               val = legitimize_pic_address (stack_limit_rtx, p1reg,
939                                             pic_reg_loaded);
940               emit_move_insn (p1reg, val);
941               frame_related_constant_load (p2reg, offset, FALSE);
942               emit_insn (gen_addsi3 (p2reg, p2reg, p1reg));
943               lim = p2reg;
944             }
945           else
946             {
947               rtx limit = plus_constant (stack_limit_rtx, offset);
948               emit_move_insn (p2reg, limit);
949               lim = p2reg;
950             }
951         }
952       emit_insn (gen_compare_lt (bfin_cc_rtx, spreg, lim));
953       emit_insn (gen_trapifcc ());
954     }
955   expand_prologue_reg_save (spreg, 0, false);
956
957   do_link (spreg, frame_size, false);
958
959   if (TARGET_ID_SHARED_LIBRARY
960       && (current_function_uses_pic_offset_table
961           || !current_function_is_leaf))
962     bfin_load_pic_reg (pic_offset_table_rtx);
963 }
964
965 /* Generate RTL for the epilogue of the current function.  NEED_RETURN is zero
966    if this is for a sibcall.  EH_RETURN is nonzero if we're expanding an
967    eh_return pattern.  */
968
969 void
970 bfin_expand_epilogue (int need_return, int eh_return)
971 {
972   rtx spreg = gen_rtx_REG (Pmode, REG_SP);
973   e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
974
975   if (fkind != SUBROUTINE)
976     {
977       expand_interrupt_handler_epilogue (spreg, fkind);
978       return;
979     }
980
981   do_unlink (spreg, get_frame_size (), false);
982
983   expand_epilogue_reg_restore (spreg, false, false);
984
985   /* Omit the return insn if this is for a sibcall.  */
986   if (! need_return)
987     return;
988
989   if (eh_return)
990     emit_insn (gen_addsi3 (spreg, spreg, gen_rtx_REG (Pmode, REG_P2)));
991
992   emit_jump_insn (gen_return_internal (GEN_INT (SUBROUTINE)));
993 }
994 \f
995 /* Return nonzero if register OLD_REG can be renamed to register NEW_REG.  */
996
997 int
998 bfin_hard_regno_rename_ok (unsigned int old_reg ATTRIBUTE_UNUSED,
999                            unsigned int new_reg)
1000 {
1001   /* Interrupt functions can only use registers that have already been
1002      saved by the prologue, even if they would normally be
1003      call-clobbered.  */
1004
1005   if (funkind (TREE_TYPE (current_function_decl)) != SUBROUTINE
1006       && !regs_ever_live[new_reg])
1007     return 0;
1008
1009   return 1;
1010 }
1011
1012 /* Return the value of the return address for the frame COUNT steps up
1013    from the current frame, after the prologue.
1014    We punt for everything but the current frame by returning const0_rtx.  */
1015
1016 rtx
1017 bfin_return_addr_rtx (int count)
1018 {
1019   if (count != 0)
1020     return const0_rtx;
1021
1022   return get_hard_reg_initial_val (Pmode, REG_RETS);
1023 }
1024
1025 /* Try machine-dependent ways of modifying an illegitimate address X
1026    to be legitimate.  If we find one, return the new, valid address,
1027    otherwise return NULL_RTX.
1028
1029    OLDX is the address as it was before break_out_memory_refs was called.
1030    In some cases it is useful to look at this to decide what needs to be done.
1031
1032    MODE is the mode of the memory reference.  */
1033
1034 rtx
1035 legitimize_address (rtx x ATTRIBUTE_UNUSED, rtx oldx ATTRIBUTE_UNUSED,
1036                     enum machine_mode mode ATTRIBUTE_UNUSED)
1037 {
1038   return NULL_RTX;
1039 }
1040
1041 static rtx
1042 bfin_delegitimize_address (rtx orig_x)
1043 {
1044   rtx x = orig_x, y;
1045
1046   if (GET_CODE (x) != MEM)
1047     return orig_x;
1048
1049   x = XEXP (x, 0);
1050   if (GET_CODE (x) == PLUS
1051       && GET_CODE (XEXP (x, 1)) == UNSPEC
1052       && XINT (XEXP (x, 1), 1) == UNSPEC_MOVE_PIC
1053       && GET_CODE (XEXP (x, 0)) == REG
1054       && REGNO (XEXP (x, 0)) == PIC_OFFSET_TABLE_REGNUM)
1055     return XVECEXP (XEXP (x, 1), 0, 0);
1056
1057   return orig_x;
1058 }
1059
1060 /* This predicate is used to compute the length of a load/store insn.
1061    OP is a MEM rtx, we return nonzero if its addressing mode requires a
1062    32 bit instruction.  */
1063
1064 int
1065 effective_address_32bit_p (rtx op, enum machine_mode mode) 
1066 {
1067   HOST_WIDE_INT offset;
1068
1069   mode = GET_MODE (op);
1070   op = XEXP (op, 0);
1071
1072   if (GET_CODE (op) != PLUS)
1073     {
1074       gcc_assert (REG_P (op) || GET_CODE (op) == POST_INC
1075                   || GET_CODE (op) == PRE_DEC || GET_CODE (op) == POST_DEC);
1076       return 0;
1077     }
1078
1079   offset = INTVAL (XEXP (op, 1));
1080
1081   /* All byte loads use a 16 bit offset.  */
1082   if (GET_MODE_SIZE (mode) == 1)
1083     return 1;
1084
1085   if (GET_MODE_SIZE (mode) == 4)
1086     {
1087       /* Frame pointer relative loads can use a negative offset, all others
1088          are restricted to a small positive one.  */
1089       if (XEXP (op, 0) == frame_pointer_rtx)
1090         return offset < -128 || offset > 60;
1091       return offset < 0 || offset > 60;
1092     }
1093
1094   /* Must be HImode now.  */
1095   return offset < 0 || offset > 30;
1096 }
1097
1098 /* Returns true if X is a memory reference using an I register.  */
1099 bool
1100 bfin_dsp_memref_p (rtx x)
1101 {
1102   if (! MEM_P (x))
1103     return false;
1104   x = XEXP (x, 0);
1105   if (GET_CODE (x) == POST_INC || GET_CODE (x) == PRE_INC
1106       || GET_CODE (x) == POST_DEC || GET_CODE (x) == PRE_DEC)
1107     x = XEXP (x, 0);
1108   return IREG_P (x);
1109 }
1110
1111 /* Return cost of the memory address ADDR.
1112    All addressing modes are equally cheap on the Blackfin.  */
1113
1114 static int
1115 bfin_address_cost (rtx addr ATTRIBUTE_UNUSED)
1116 {
1117   return 1;
1118 }
1119
1120 /* Subroutine of print_operand; used to print a memory reference X to FILE.  */
1121
1122 void
1123 print_address_operand (FILE *file, rtx x)
1124 {
1125   switch (GET_CODE (x))
1126     {
1127     case PLUS:
1128       output_address (XEXP (x, 0));
1129       fprintf (file, "+");
1130       output_address (XEXP (x, 1));
1131       break;
1132
1133     case PRE_DEC:
1134       fprintf (file, "--");
1135       output_address (XEXP (x, 0));    
1136       break;
1137     case POST_INC:
1138       output_address (XEXP (x, 0));
1139       fprintf (file, "++");
1140       break;
1141     case POST_DEC:
1142       output_address (XEXP (x, 0));
1143       fprintf (file, "--");
1144       break;
1145
1146     default:
1147       gcc_assert (GET_CODE (x) != MEM);
1148       print_operand (file, x, 0);
1149       break;
1150     }
1151 }
1152
1153 /* Adding intp DImode support by Tony
1154  * -- Q: (low  word)
1155  * -- R: (high word)
1156  */
1157
1158 void
1159 print_operand (FILE *file, rtx x, char code)
1160 {
1161   enum machine_mode mode = GET_MODE (x);
1162
1163   switch (code)
1164     {
1165     case 'j':
1166       switch (GET_CODE (x))
1167         {
1168         case EQ:
1169           fprintf (file, "e");
1170           break;
1171         case NE:
1172           fprintf (file, "ne");
1173           break;
1174         case GT:
1175           fprintf (file, "g");
1176           break;
1177         case LT:
1178           fprintf (file, "l");
1179           break;
1180         case GE:
1181           fprintf (file, "ge");
1182           break;
1183         case LE:
1184           fprintf (file, "le");
1185           break;
1186         case GTU:
1187           fprintf (file, "g");
1188           break;
1189         case LTU:
1190           fprintf (file, "l");
1191           break;
1192         case GEU:
1193           fprintf (file, "ge");
1194           break;
1195         case LEU:
1196           fprintf (file, "le");
1197           break;
1198         default:
1199           output_operand_lossage ("invalid %%j value");
1200         }
1201       break;
1202     
1203     case 'J':                                    /* reverse logic */
1204       switch (GET_CODE(x))
1205         {
1206         case EQ:
1207           fprintf (file, "ne");
1208           break;
1209         case NE:
1210           fprintf (file, "e");
1211           break;
1212         case GT:
1213           fprintf (file, "le");
1214           break;
1215         case LT:
1216           fprintf (file, "ge");
1217           break;
1218         case GE:
1219           fprintf (file, "l");
1220           break;
1221         case LE:
1222           fprintf (file, "g");
1223           break;
1224         case GTU:
1225           fprintf (file, "le");
1226           break;
1227         case LTU:
1228           fprintf (file, "ge");
1229           break;
1230         case GEU:
1231           fprintf (file, "l");
1232           break;
1233         case LEU:
1234           fprintf (file, "g");
1235           break;
1236         default:
1237           output_operand_lossage ("invalid %%J value");
1238         }
1239       break;
1240
1241     default:
1242       switch (GET_CODE (x))
1243         {
1244         case REG:
1245           if (code == 'h')
1246             {
1247               gcc_assert (REGNO (x) < 32);
1248               fprintf (file, "%s", short_reg_names[REGNO (x)]);
1249               /*fprintf (file, "\n%d\n ", REGNO (x));*/
1250               break;
1251             }
1252           else if (code == 'd')
1253             {
1254               gcc_assert (REGNO (x) < 32);
1255               fprintf (file, "%s", high_reg_names[REGNO (x)]);
1256               break;
1257             }
1258           else if (code == 'w')
1259             {
1260               gcc_assert (REGNO (x) == REG_A0 || REGNO (x) == REG_A1);
1261               fprintf (file, "%s.w", reg_names[REGNO (x)]);
1262             }
1263           else if (code == 'x')
1264             {
1265               gcc_assert (REGNO (x) == REG_A0 || REGNO (x) == REG_A1);
1266               fprintf (file, "%s.x", reg_names[REGNO (x)]);
1267             }
1268           else if (code == 'D')
1269             {
1270               fprintf (file, "%s", dregs_pair_names[REGNO (x)]);
1271             }
1272           else if (code == 'H')
1273             {
1274               gcc_assert (mode == DImode || mode == DFmode);
1275               gcc_assert (REG_P (x));
1276               fprintf (file, "%s", reg_names[REGNO (x) + 1]);
1277             }
1278           else if (code == 'T')
1279             {
1280               gcc_assert (D_REGNO_P (REGNO (x)));
1281               fprintf (file, "%s", byte_reg_names[REGNO (x)]);
1282             }
1283           else 
1284             fprintf (file, "%s", reg_names[REGNO (x)]);
1285           break;
1286
1287         case MEM:
1288           fputc ('[', file);
1289           x = XEXP (x,0);
1290           print_address_operand (file, x);
1291           fputc (']', file);
1292           break;
1293
1294         case CONST_INT:
1295           if (code == 'M')
1296             {
1297               switch (INTVAL (x))
1298                 {
1299                 case MACFLAG_NONE:
1300                   break;
1301                 case MACFLAG_FU:
1302                   fputs ("(FU)", file);
1303                   break;
1304                 case MACFLAG_T:
1305                   fputs ("(T)", file);
1306                   break;
1307                 case MACFLAG_TFU:
1308                   fputs ("(TFU)", file);
1309                   break;
1310                 case MACFLAG_W32:
1311                   fputs ("(W32)", file);
1312                   break;
1313                 case MACFLAG_IS:
1314                   fputs ("(IS)", file);
1315                   break;
1316                 case MACFLAG_IU:
1317                   fputs ("(IU)", file);
1318                   break;
1319                 case MACFLAG_IH:
1320                   fputs ("(IH)", file);
1321                   break;
1322                 case MACFLAG_M:
1323                   fputs ("(M)", file);
1324                   break;
1325                 case MACFLAG_ISS2:
1326                   fputs ("(ISS2)", file);
1327                   break;
1328                 case MACFLAG_S2RND:
1329                   fputs ("(S2RND)", file);
1330                   break;
1331                 default:
1332                   gcc_unreachable ();
1333                 }
1334               break;
1335             }
1336           else if (code == 'b')
1337             {
1338               if (INTVAL (x) == 0)
1339                 fputs ("+=", file);
1340               else if (INTVAL (x) == 1)
1341                 fputs ("-=", file);
1342               else
1343                 gcc_unreachable ();
1344               break;
1345             }
1346           /* Moves to half registers with d or h modifiers always use unsigned
1347              constants.  */
1348           else if (code == 'd')
1349             x = GEN_INT ((INTVAL (x) >> 16) & 0xffff);
1350           else if (code == 'h')
1351             x = GEN_INT (INTVAL (x) & 0xffff);
1352           else if (code == 'X')
1353             x = GEN_INT (exact_log2 (0xffffffff & INTVAL (x)));
1354           else if (code == 'Y')
1355             x = GEN_INT (exact_log2 (0xffffffff & ~INTVAL (x)));
1356           else if (code == 'Z')
1357             /* Used for LINK insns.  */
1358             x = GEN_INT (-8 - INTVAL (x));
1359
1360           /* fall through */
1361
1362         case SYMBOL_REF:
1363           output_addr_const (file, x);
1364           break;
1365
1366         case CONST_DOUBLE:
1367           output_operand_lossage ("invalid const_double operand");
1368           break;
1369
1370         case UNSPEC:
1371           switch (XINT (x, 1))
1372             {
1373             case UNSPEC_MOVE_PIC:
1374               output_addr_const (file, XVECEXP (x, 0, 0));
1375               fprintf (file, "@GOT");
1376               break;
1377
1378             case UNSPEC_MOVE_FDPIC:
1379               output_addr_const (file, XVECEXP (x, 0, 0));
1380               fprintf (file, "@GOT17M4");
1381               break;
1382
1383             case UNSPEC_FUNCDESC_GOT17M4:
1384               output_addr_const (file, XVECEXP (x, 0, 0));
1385               fprintf (file, "@FUNCDESC_GOT17M4");
1386               break;
1387
1388             case UNSPEC_LIBRARY_OFFSET:
1389               fprintf (file, "_current_shared_library_p5_offset_");
1390               break;
1391
1392             default:
1393               gcc_unreachable ();
1394             }
1395           break;
1396
1397         default:
1398           output_addr_const (file, x);
1399         }
1400     }
1401 }
1402 \f
1403 /* Argument support functions.  */
1404
1405 /* Initialize a variable CUM of type CUMULATIVE_ARGS
1406    for a call to a function whose data type is FNTYPE.
1407    For a library call, FNTYPE is 0.  
1408    VDSP C Compiler manual, our ABI says that
1409    first 3 words of arguments will use R0, R1 and R2.
1410 */
1411
1412 void
1413 init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype,
1414                       rtx libname ATTRIBUTE_UNUSED)
1415 {
1416   static CUMULATIVE_ARGS zero_cum;
1417
1418   *cum = zero_cum;
1419
1420   /* Set up the number of registers to use for passing arguments.  */
1421
1422   cum->nregs = max_arg_registers;
1423   cum->arg_regs = arg_regs;
1424
1425   cum->call_cookie = CALL_NORMAL;
1426   /* Check for a longcall attribute.  */
1427   if (fntype && lookup_attribute ("shortcall", TYPE_ATTRIBUTES (fntype)))
1428     cum->call_cookie |= CALL_SHORT;
1429   else if (fntype && lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype)))
1430     cum->call_cookie |= CALL_LONG;
1431
1432   return;
1433 }
1434
1435 /* Update the data in CUM to advance over an argument
1436    of mode MODE and data type TYPE.
1437    (TYPE is null for libcalls where that information may not be available.)  */
1438
1439 void
1440 function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
1441                       int named ATTRIBUTE_UNUSED)
1442 {
1443   int count, bytes, words;
1444
1445   bytes = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
1446   words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
1447
1448   cum->words += words;
1449   cum->nregs -= words;
1450
1451   if (cum->nregs <= 0)
1452     {
1453       cum->nregs = 0;
1454       cum->arg_regs = NULL;
1455     }
1456   else
1457     {
1458       for (count = 1; count <= words; count++)
1459         cum->arg_regs++;
1460     }
1461
1462   return;
1463 }
1464
1465 /* Define where to put the arguments to a function.
1466    Value is zero to push the argument on the stack,
1467    or a hard register in which to store the argument.
1468
1469    MODE is the argument's machine mode.
1470    TYPE is the data type of the argument (as a tree).
1471     This is null for libcalls where that information may
1472     not be available.
1473    CUM is a variable of type CUMULATIVE_ARGS which gives info about
1474     the preceding args and about the function being called.
1475    NAMED is nonzero if this argument is a named parameter
1476     (otherwise it is an extra parameter matching an ellipsis).  */
1477
1478 struct rtx_def *
1479 function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
1480               int named ATTRIBUTE_UNUSED)
1481 {
1482   int bytes
1483     = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
1484
1485   if (mode == VOIDmode)
1486     /* Compute operand 2 of the call insn.  */
1487     return GEN_INT (cum->call_cookie);
1488
1489   if (bytes == -1)
1490     return NULL_RTX;
1491
1492   if (cum->nregs)
1493     return gen_rtx_REG (mode, *(cum->arg_regs));
1494
1495   return NULL_RTX;
1496 }
1497
1498 /* For an arg passed partly in registers and partly in memory,
1499    this is the number of bytes passed in registers.
1500    For args passed entirely in registers or entirely in memory, zero.
1501
1502    Refer VDSP C Compiler manual, our ABI.
1503    First 3 words are in registers. So, if a an argument is larger
1504    than the registers available, it will span the register and
1505    stack.   */
1506
1507 static int
1508 bfin_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode,
1509                         tree type ATTRIBUTE_UNUSED,
1510                         bool named ATTRIBUTE_UNUSED)
1511 {
1512   int bytes
1513     = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
1514   int bytes_left = cum->nregs * UNITS_PER_WORD;
1515   
1516   if (bytes == -1)
1517     return 0;
1518
1519   if (bytes_left == 0)
1520     return 0;
1521   if (bytes > bytes_left)
1522     return bytes_left;
1523   return 0;
1524 }
1525
1526 /* Variable sized types are passed by reference.  */
1527
1528 static bool
1529 bfin_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
1530                         enum machine_mode mode ATTRIBUTE_UNUSED,
1531                         tree type, bool named ATTRIBUTE_UNUSED)
1532 {
1533   return type && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST;
1534 }
1535
1536 /* Decide whether a type should be returned in memory (true)
1537    or in a register (false).  This is called by the macro
1538    RETURN_IN_MEMORY.  */
1539
1540 int
1541 bfin_return_in_memory (tree type)
1542 {
1543   int size = int_size_in_bytes (type);
1544   return size > 2 * UNITS_PER_WORD || size == -1;
1545 }
1546
1547 /* Register in which address to store a structure value
1548    is passed to a function.  */
1549 static rtx
1550 bfin_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
1551                       int incoming ATTRIBUTE_UNUSED)
1552 {
1553   return gen_rtx_REG (Pmode, REG_P0);
1554 }
1555
1556 /* Return true when register may be used to pass function parameters.  */
1557
1558 bool 
1559 function_arg_regno_p (int n)
1560 {
1561   int i;
1562   for (i = 0; arg_regs[i] != -1; i++)
1563     if (n == arg_regs[i])
1564       return true;
1565   return false;
1566 }
1567
1568 /* Returns 1 if OP contains a symbol reference */
1569
1570 int
1571 symbolic_reference_mentioned_p (rtx op)
1572 {
1573   register const char *fmt;
1574   register int i;
1575
1576   if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF)
1577     return 1;
1578
1579   fmt = GET_RTX_FORMAT (GET_CODE (op));
1580   for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
1581     {
1582       if (fmt[i] == 'E')
1583         {
1584           register int j;
1585
1586           for (j = XVECLEN (op, i) - 1; j >= 0; j--)
1587             if (symbolic_reference_mentioned_p (XVECEXP (op, i, j)))
1588               return 1;
1589         }
1590
1591       else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i)))
1592         return 1;
1593     }
1594
1595   return 0;
1596 }
1597
1598 /* Decide whether we can make a sibling call to a function.  DECL is the
1599    declaration of the function being targeted by the call and EXP is the
1600    CALL_EXPR representing the call.  */
1601
1602 static bool
1603 bfin_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED,
1604                               tree exp ATTRIBUTE_UNUSED)
1605 {
1606   e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
1607   return fkind == SUBROUTINE;
1608 }
1609 \f
1610 /* Emit RTL insns to initialize the variable parts of a trampoline at
1611    TRAMP. FNADDR is an RTX for the address of the function's pure
1612    code.  CXT is an RTX for the static chain value for the function.  */
1613
1614 void
1615 initialize_trampoline (tramp, fnaddr, cxt)
1616      rtx tramp, fnaddr, cxt;
1617 {
1618   rtx t1 = copy_to_reg (fnaddr);
1619   rtx t2 = copy_to_reg (cxt);
1620   rtx addr;
1621   int i = 0;
1622
1623   if (TARGET_FDPIC)
1624     {
1625       rtx a = memory_address (Pmode, plus_constant (tramp, 8));
1626       addr = memory_address (Pmode, tramp);
1627       emit_move_insn (gen_rtx_MEM (SImode, addr), a);
1628       i = 8;
1629     }
1630
1631   addr = memory_address (Pmode, plus_constant (tramp, i + 2));
1632   emit_move_insn (gen_rtx_MEM (HImode, addr), gen_lowpart (HImode, t1));
1633   emit_insn (gen_ashrsi3 (t1, t1, GEN_INT (16)));
1634   addr = memory_address (Pmode, plus_constant (tramp, i + 6));
1635   emit_move_insn (gen_rtx_MEM (HImode, addr), gen_lowpart (HImode, t1));
1636
1637   addr = memory_address (Pmode, plus_constant (tramp, i + 10));
1638   emit_move_insn (gen_rtx_MEM (HImode, addr), gen_lowpart (HImode, t2));
1639   emit_insn (gen_ashrsi3 (t2, t2, GEN_INT (16)));
1640   addr = memory_address (Pmode, plus_constant (tramp, i + 14));
1641   emit_move_insn (gen_rtx_MEM (HImode, addr), gen_lowpart (HImode, t2));
1642 }
1643
1644 /* Emit insns to move operands[1] into operands[0].  */
1645
1646 void
1647 emit_pic_move (rtx *operands, enum machine_mode mode ATTRIBUTE_UNUSED)
1648 {
1649   rtx temp = reload_in_progress ? operands[0] : gen_reg_rtx (Pmode);
1650
1651   gcc_assert (!TARGET_FDPIC || !(reload_in_progress || reload_completed));
1652   if (GET_CODE (operands[0]) == MEM && SYMBOLIC_CONST (operands[1]))
1653     operands[1] = force_reg (SImode, operands[1]);
1654   else
1655     operands[1] = legitimize_pic_address (operands[1], temp,
1656                                           TARGET_FDPIC ? OUR_FDPIC_REG
1657                                           : pic_offset_table_rtx);
1658 }
1659
1660 /* Expand a move operation in mode MODE.  The operands are in OPERANDS.  */
1661
1662 void
1663 expand_move (rtx *operands, enum machine_mode mode)
1664 {
1665   rtx op = operands[1];
1666   if ((TARGET_ID_SHARED_LIBRARY || TARGET_FDPIC)
1667       && SYMBOLIC_CONST (op))
1668     emit_pic_move (operands, mode);
1669   /* Don't generate memory->memory or constant->memory moves, go through a
1670      register */
1671   else if ((reload_in_progress | reload_completed) == 0
1672            && GET_CODE (operands[0]) == MEM
1673            && GET_CODE (operands[1]) != REG)
1674     operands[1] = force_reg (mode, operands[1]);
1675 }
1676 \f
1677 /* Split one or more DImode RTL references into pairs of SImode
1678    references.  The RTL can be REG, offsettable MEM, integer constant, or
1679    CONST_DOUBLE.  "operands" is a pointer to an array of DImode RTL to
1680    split and "num" is its length.  lo_half and hi_half are output arrays
1681    that parallel "operands".  */
1682
1683 void
1684 split_di (rtx operands[], int num, rtx lo_half[], rtx hi_half[])
1685 {
1686   while (num--)
1687     {
1688       rtx op = operands[num];
1689
1690       /* simplify_subreg refuse to split volatile memory addresses,
1691          but we still have to handle it.  */
1692       if (GET_CODE (op) == MEM)
1693         {
1694           lo_half[num] = adjust_address (op, SImode, 0);
1695           hi_half[num] = adjust_address (op, SImode, 4);
1696         }
1697       else
1698         {
1699           lo_half[num] = simplify_gen_subreg (SImode, op,
1700                                               GET_MODE (op) == VOIDmode
1701                                               ? DImode : GET_MODE (op), 0);
1702           hi_half[num] = simplify_gen_subreg (SImode, op,
1703                                               GET_MODE (op) == VOIDmode
1704                                               ? DImode : GET_MODE (op), 4);
1705         }
1706     }
1707 }
1708 \f
1709 bool
1710 bfin_longcall_p (rtx op, int call_cookie)
1711 {
1712   gcc_assert (GET_CODE (op) == SYMBOL_REF);
1713   if (call_cookie & CALL_SHORT)
1714     return 0;
1715   if (call_cookie & CALL_LONG)
1716     return 1;
1717   if (TARGET_LONG_CALLS)
1718     return 1;
1719   return 0;
1720 }
1721
1722 /* Expand a call instruction.  FNADDR is the call target, RETVAL the return value.
1723    COOKIE is a CONST_INT holding the call_cookie prepared init_cumulative_args.
1724    SIBCALL is nonzero if this is a sibling call.  */
1725
1726 void
1727 bfin_expand_call (rtx retval, rtx fnaddr, rtx callarg1, rtx cookie, int sibcall)
1728 {
1729   rtx use = NULL, call;
1730   rtx callee = XEXP (fnaddr, 0);
1731   int nelts = 2 + !!sibcall;
1732   rtx pat;
1733   rtx picreg = get_hard_reg_initial_val (SImode, FDPIC_REGNO);
1734   int n;
1735
1736   /* In an untyped call, we can get NULL for operand 2.  */
1737   if (cookie == NULL_RTX)
1738     cookie = const0_rtx;
1739
1740   /* Static functions and indirect calls don't need the pic register.  */
1741   if (!TARGET_FDPIC && flag_pic
1742       && GET_CODE (callee) == SYMBOL_REF
1743       && !SYMBOL_REF_LOCAL_P (callee))
1744     use_reg (&use, pic_offset_table_rtx);
1745
1746   if (TARGET_FDPIC)
1747     {
1748       if (GET_CODE (callee) != SYMBOL_REF
1749           || bfin_longcall_p (callee, INTVAL (cookie)))
1750         {
1751           rtx addr = callee;
1752           if (! address_operand (addr, Pmode))
1753             addr = force_reg (Pmode, addr);
1754
1755           fnaddr = gen_reg_rtx (SImode);
1756           emit_insn (gen_load_funcdescsi (fnaddr, addr));
1757           fnaddr = gen_rtx_MEM (Pmode, fnaddr);
1758
1759           picreg = gen_reg_rtx (SImode);
1760           emit_insn (gen_load_funcdescsi (picreg,
1761                                           plus_constant (addr, 4)));
1762         }
1763
1764       nelts++;
1765     }
1766   else if ((!register_no_elim_operand (callee, Pmode)
1767             && GET_CODE (callee) != SYMBOL_REF)
1768            || (GET_CODE (callee) == SYMBOL_REF
1769                && (flag_pic
1770                    || bfin_longcall_p (callee, INTVAL (cookie)))))
1771     {
1772       callee = copy_to_mode_reg (Pmode, callee);
1773       fnaddr = gen_rtx_MEM (Pmode, callee);
1774     }
1775   call = gen_rtx_CALL (VOIDmode, fnaddr, callarg1);
1776
1777   if (retval)
1778     call = gen_rtx_SET (VOIDmode, retval, call);
1779
1780   pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (nelts));
1781   n = 0;
1782   XVECEXP (pat, 0, n++) = call;
1783   if (TARGET_FDPIC)
1784     XVECEXP (pat, 0, n++) = gen_rtx_USE (VOIDmode, picreg);
1785   XVECEXP (pat, 0, n++) = gen_rtx_USE (VOIDmode, cookie);
1786   if (sibcall)
1787     XVECEXP (pat, 0, n++) = gen_rtx_RETURN (VOIDmode);
1788   call = emit_call_insn (pat);
1789   if (use)
1790     CALL_INSN_FUNCTION_USAGE (call) = use;
1791 }
1792 \f
1793 /* Return 1 if hard register REGNO can hold a value of machine-mode MODE.  */
1794
1795 int
1796 hard_regno_mode_ok (int regno, enum machine_mode mode)
1797 {
1798   /* Allow only dregs to store value of mode HI or QI */
1799   enum reg_class class = REGNO_REG_CLASS (regno);
1800
1801   if (mode == CCmode)
1802     return 0;
1803
1804   if (mode == V2HImode)
1805     return D_REGNO_P (regno);
1806   if (class == CCREGS)
1807     return mode == BImode;
1808   if (mode == PDImode || mode == V2PDImode)
1809     return regno == REG_A0 || regno == REG_A1;
1810   if (mode == SImode
1811       && TEST_HARD_REG_BIT (reg_class_contents[PROLOGUE_REGS], regno))
1812     return 1;
1813       
1814   return TEST_HARD_REG_BIT (reg_class_contents[MOST_REGS], regno);
1815 }
1816
1817 /* Implements target hook vector_mode_supported_p.  */
1818
1819 static bool
1820 bfin_vector_mode_supported_p (enum machine_mode mode)
1821 {
1822   return mode == V2HImode;
1823 }
1824
1825 /* Return the cost of moving data from a register in class CLASS1 to
1826    one in class CLASS2.  A cost of 2 is the default.  */
1827
1828 int
1829 bfin_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
1830                          enum reg_class class1, enum reg_class class2)
1831 {
1832   /* These need secondary reloads, so they're more expensive.  */
1833   if ((class1 == CCREGS && class2 != DREGS)
1834       || (class1 != DREGS && class2 == CCREGS))
1835     return 4;
1836
1837   /* If optimizing for size, always prefer reg-reg over reg-memory moves.  */
1838   if (optimize_size)
1839     return 2;
1840
1841   /* There are some stalls involved when moving from a DREG to a different
1842      class reg, and using the value in one of the following instructions.
1843      Attempt to model this by slightly discouraging such moves.  */
1844   if (class1 == DREGS && class2 != DREGS)
1845     return 2 * 2;
1846
1847   return 2;
1848 }
1849
1850 /* Return the cost of moving data of mode M between a
1851    register and memory.  A value of 2 is the default; this cost is
1852    relative to those in `REGISTER_MOVE_COST'.
1853
1854    ??? In theory L1 memory has single-cycle latency.  We should add a switch
1855    that tells the compiler whether we expect to use only L1 memory for the
1856    program; it'll make the costs more accurate.  */
1857
1858 int
1859 bfin_memory_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
1860                        enum reg_class class,
1861                        int in ATTRIBUTE_UNUSED)
1862 {
1863   /* Make memory accesses slightly more expensive than any register-register
1864      move.  Also, penalize non-DP registers, since they need secondary
1865      reloads to load and store.  */
1866   if (! reg_class_subset_p (class, DPREGS))
1867     return 10;
1868
1869   return 8;
1870 }
1871
1872 /* Inform reload about cases where moving X with a mode MODE to a register in
1873    CLASS requires an extra scratch register.  Return the class needed for the
1874    scratch register.  */
1875
1876 static enum reg_class
1877 bfin_secondary_reload (bool in_p, rtx x, enum reg_class class,
1878                      enum machine_mode mode, secondary_reload_info *sri)
1879 {
1880   /* If we have HImode or QImode, we can only use DREGS as secondary registers;
1881      in most other cases we can also use PREGS.  */
1882   enum reg_class default_class = GET_MODE_SIZE (mode) >= 4 ? DPREGS : DREGS;
1883   enum reg_class x_class = NO_REGS;
1884   enum rtx_code code = GET_CODE (x);
1885
1886   if (code == SUBREG)
1887     x = SUBREG_REG (x), code = GET_CODE (x);
1888   if (REG_P (x))
1889     {
1890       int regno = REGNO (x);
1891       if (regno >= FIRST_PSEUDO_REGISTER)
1892         regno = reg_renumber[regno];
1893
1894       if (regno == -1)
1895         code = MEM;
1896       else
1897         x_class = REGNO_REG_CLASS (regno);
1898     }
1899
1900   /* We can be asked to reload (plus (FP) (large_constant)) into a DREG.
1901      This happens as a side effect of register elimination, and we need
1902      a scratch register to do it.  */
1903   if (fp_plus_const_operand (x, mode))
1904     {
1905       rtx op2 = XEXP (x, 1);
1906       int large_constant_p = ! CONST_7BIT_IMM_P (INTVAL (op2));
1907
1908       if (class == PREGS || class == PREGS_CLOBBERED)
1909         return NO_REGS;
1910       /* If destination is a DREG, we can do this without a scratch register
1911          if the constant is valid for an add instruction.  */
1912       if ((class == DREGS || class == DPREGS)
1913           && ! large_constant_p)
1914         return NO_REGS;
1915       /* Reloading to anything other than a DREG?  Use a PREG scratch
1916          register.  */
1917       sri->icode = CODE_FOR_reload_insi;
1918       return NO_REGS;
1919     }
1920
1921   /* Data can usually be moved freely between registers of most classes.
1922      AREGS are an exception; they can only move to or from another register
1923      in AREGS or one in DREGS.  They can also be assigned the constant 0.  */
1924   if (x_class == AREGS)
1925     return class == DREGS || class == AREGS ? NO_REGS : DREGS;
1926
1927   if (class == AREGS)
1928     {
1929       if (x != const0_rtx && x_class != DREGS)
1930         return DREGS;
1931       else
1932         return NO_REGS;
1933     }
1934
1935   /* CCREGS can only be moved from/to DREGS.  */
1936   if (class == CCREGS && x_class != DREGS)
1937     return DREGS;
1938   if (x_class == CCREGS && class != DREGS)
1939     return DREGS;
1940
1941   /* All registers other than AREGS can load arbitrary constants.  The only
1942      case that remains is MEM.  */
1943   if (code == MEM)
1944     if (! reg_class_subset_p (class, default_class))
1945       return default_class;
1946   return NO_REGS;
1947 }
1948 \f
1949 /* Implement TARGET_HANDLE_OPTION.  */
1950
1951 static bool
1952 bfin_handle_option (size_t code, const char *arg, int value)
1953 {
1954   switch (code)
1955     {
1956     case OPT_mshared_library_id_:
1957       if (value > MAX_LIBRARY_ID)
1958         error ("-mshared-library-id=%s is not between 0 and %d",
1959                arg, MAX_LIBRARY_ID);
1960       bfin_lib_id_given = 1;
1961       return true;
1962
1963     default:
1964       return true;
1965     }
1966 }
1967
1968 static struct machine_function *
1969 bfin_init_machine_status (void)
1970 {
1971   struct machine_function *f;
1972
1973   f = ggc_alloc_cleared (sizeof (struct machine_function));
1974
1975   return f;
1976 }
1977
1978 /* Implement the macro OVERRIDE_OPTIONS.  */
1979
1980 void
1981 override_options (void)
1982 {
1983   if (TARGET_OMIT_LEAF_FRAME_POINTER)
1984     flag_omit_frame_pointer = 1;
1985
1986   /* Library identification */
1987   if (bfin_lib_id_given && ! TARGET_ID_SHARED_LIBRARY)
1988     error ("-mshared-library-id= specified without -mid-shared-library");
1989
1990   if (TARGET_ID_SHARED_LIBRARY && flag_pic == 0)
1991     flag_pic = 1;
1992
1993   if (TARGET_ID_SHARED_LIBRARY && TARGET_FDPIC)
1994       error ("ID shared libraries and FD-PIC mode can't be used together.");
1995
1996   /* There is no single unaligned SI op for PIC code.  Sometimes we
1997      need to use ".4byte" and sometimes we need to use ".picptr".
1998      See bfin_assemble_integer for details.  */
1999   if (TARGET_FDPIC)
2000     targetm.asm_out.unaligned_op.si = 0;
2001
2002   /* Silently turn off flag_pic if not doing FDPIC or ID shared libraries,
2003      since we don't support it and it'll just break.  */
2004   if (flag_pic && !TARGET_FDPIC && !TARGET_ID_SHARED_LIBRARY)
2005     flag_pic = 0;
2006
2007   flag_schedule_insns = 0;
2008
2009   init_machine_status = bfin_init_machine_status;
2010 }
2011
2012 /* Return the destination address of BRANCH.
2013    We need to use this instead of get_attr_length, because the
2014    cbranch_with_nops pattern conservatively sets its length to 6, and
2015    we still prefer to use shorter sequences.  */
2016
2017 static int
2018 branch_dest (rtx branch)
2019 {
2020   rtx dest;
2021   int dest_uid;
2022   rtx pat = PATTERN (branch);
2023   if (GET_CODE (pat) == PARALLEL)
2024     pat = XVECEXP (pat, 0, 0);
2025   dest = SET_SRC (pat);
2026   if (GET_CODE (dest) == IF_THEN_ELSE)
2027     dest = XEXP (dest, 1);
2028   dest = XEXP (dest, 0);
2029   dest_uid = INSN_UID (dest);
2030   return INSN_ADDRESSES (dest_uid);
2031 }
2032
2033 /* Return nonzero if INSN is annotated with a REG_BR_PROB note that indicates
2034    it's a branch that's predicted taken.  */
2035
2036 static int
2037 cbranch_predicted_taken_p (rtx insn)
2038 {
2039   rtx x = find_reg_note (insn, REG_BR_PROB, 0);
2040
2041   if (x)
2042     {
2043       int pred_val = INTVAL (XEXP (x, 0));
2044
2045       return pred_val >= REG_BR_PROB_BASE / 2;
2046     }
2047
2048   return 0;
2049 }
2050
2051 /* Templates for use by asm_conditional_branch.  */
2052
2053 static const char *ccbranch_templates[][3] = {
2054   { "if !cc jump %3;",  "if cc jump 4 (bp); jump.s %3;",  "if cc jump 6 (bp); jump.l %3;" },
2055   { "if cc jump %3;",   "if !cc jump 4 (bp); jump.s %3;", "if !cc jump 6 (bp); jump.l %3;" },
2056   { "if !cc jump %3 (bp);",  "if cc jump 4; jump.s %3;",  "if cc jump 6; jump.l %3;" },
2057   { "if cc jump %3 (bp);",  "if !cc jump 4; jump.s %3;",  "if !cc jump 6; jump.l %3;" },
2058 };
2059
2060 /* Output INSN, which is a conditional branch instruction with operands
2061    OPERANDS.
2062
2063    We deal with the various forms of conditional branches that can be generated
2064    by bfin_reorg to prevent the hardware from doing speculative loads, by
2065    - emitting a sufficient number of nops, if N_NOPS is nonzero, or
2066    - always emitting the branch as predicted taken, if PREDICT_TAKEN is true.
2067    Either of these is only necessary if the branch is short, otherwise the
2068    template we use ends in an unconditional jump which flushes the pipeline
2069    anyway.  */
2070
2071 void
2072 asm_conditional_branch (rtx insn, rtx *operands, int n_nops, int predict_taken)
2073 {
2074   int offset = branch_dest (insn) - INSN_ADDRESSES (INSN_UID (insn));
2075   /* Note : offset for instructions like if cc jmp; jump.[sl] offset
2076             is to be taken from start of if cc rather than jump.
2077             Range for jump.s is (-4094, 4096) instead of (-4096, 4094)
2078   */
2079   int len = (offset >= -1024 && offset <= 1022 ? 0
2080              : offset >= -4094 && offset <= 4096 ? 1
2081              : 2);
2082   int bp = predict_taken && len == 0 ? 1 : cbranch_predicted_taken_p (insn);
2083   int idx = (bp << 1) | (GET_CODE (operands[0]) == EQ ? BRF : BRT);
2084   output_asm_insn (ccbranch_templates[idx][len], operands);
2085   gcc_assert (n_nops == 0 || !bp);
2086   if (len == 0)
2087     while (n_nops-- > 0)
2088       output_asm_insn ("nop;", NULL);
2089 }
2090
2091 /* Emit rtl for a comparison operation CMP in mode MODE.  Operands have been
2092    stored in bfin_compare_op0 and bfin_compare_op1 already.  */
2093
2094 rtx
2095 bfin_gen_compare (rtx cmp, enum machine_mode mode ATTRIBUTE_UNUSED)
2096 {
2097   enum rtx_code code1, code2;
2098   rtx op0 = bfin_compare_op0, op1 = bfin_compare_op1;
2099   rtx tem = bfin_cc_rtx;
2100   enum rtx_code code = GET_CODE (cmp);
2101
2102   /* If we have a BImode input, then we already have a compare result, and
2103      do not need to emit another comparison.  */
2104   if (GET_MODE (op0) == BImode)
2105     {
2106       gcc_assert ((code == NE || code == EQ) && op1 == const0_rtx);
2107       tem = op0, code2 = code;
2108     }
2109   else
2110     {
2111       switch (code) {
2112         /* bfin has these conditions */
2113       case EQ:
2114       case LT:
2115       case LE:
2116       case LEU:
2117       case LTU:
2118         code1 = code;
2119         code2 = NE;
2120         break;
2121       default:
2122         code1 = reverse_condition (code);
2123         code2 = EQ;
2124         break;
2125       }
2126       emit_insn (gen_rtx_SET (BImode, tem,
2127                               gen_rtx_fmt_ee (code1, BImode, op0, op1)));
2128     }
2129
2130   return gen_rtx_fmt_ee (code2, BImode, tem, CONST0_RTX (BImode));
2131 }
2132 \f
2133 /* Return nonzero iff C has exactly one bit set if it is interpreted
2134    as a 32 bit constant.  */
2135
2136 int
2137 log2constp (unsigned HOST_WIDE_INT c)
2138 {
2139   c &= 0xFFFFFFFF;
2140   return c != 0 && (c & (c-1)) == 0;
2141 }
2142
2143 /* Returns the number of consecutive least significant zeros in the binary
2144    representation of *V.
2145    We modify *V to contain the original value arithmetically shifted right by
2146    the number of zeroes.  */
2147
2148 static int
2149 shiftr_zero (HOST_WIDE_INT *v)
2150 {
2151   unsigned HOST_WIDE_INT tmp = *v;
2152   unsigned HOST_WIDE_INT sgn;
2153   int n = 0;
2154
2155   if (tmp == 0)
2156     return 0;
2157
2158   sgn = tmp & ((unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1));
2159   while ((tmp & 0x1) == 0 && n <= 32)
2160     {
2161       tmp = (tmp >> 1) | sgn;
2162       n++;
2163     }
2164   *v = tmp;
2165   return n;
2166 }
2167
2168 /* After reload, split the load of an immediate constant.  OPERANDS are the
2169    operands of the movsi_insn pattern which we are splitting.  We return
2170    nonzero if we emitted a sequence to load the constant, zero if we emitted
2171    nothing because we want to use the splitter's default sequence.  */
2172
2173 int
2174 split_load_immediate (rtx operands[])
2175 {
2176   HOST_WIDE_INT val = INTVAL (operands[1]);
2177   HOST_WIDE_INT tmp;
2178   HOST_WIDE_INT shifted = val;
2179   HOST_WIDE_INT shifted_compl = ~val;
2180   int num_zero = shiftr_zero (&shifted);
2181   int num_compl_zero = shiftr_zero (&shifted_compl);
2182   unsigned int regno = REGNO (operands[0]);
2183   enum reg_class class1 = REGNO_REG_CLASS (regno);
2184
2185   /* This case takes care of single-bit set/clear constants, which we could
2186      also implement with BITSET/BITCLR.  */
2187   if (num_zero
2188       && shifted >= -32768 && shifted < 65536
2189       && (D_REGNO_P (regno)
2190           || (regno >= REG_P0 && regno <= REG_P7 && num_zero <= 2)))
2191     {
2192       emit_insn (gen_movsi (operands[0], GEN_INT (shifted)));
2193       emit_insn (gen_ashlsi3 (operands[0], operands[0], GEN_INT (num_zero)));
2194       return 1;
2195     }
2196
2197   tmp = val & 0xFFFF;
2198   tmp |= -(tmp & 0x8000);
2199
2200   /* If high word has one bit set or clear, try to use a bit operation.  */
2201   if (D_REGNO_P (regno))
2202     {
2203       if (log2constp (val & 0xFFFF0000))
2204         {
2205           emit_insn (gen_movsi (operands[0], GEN_INT (val & 0xFFFF)));
2206           emit_insn (gen_iorsi3 (operands[0], operands[0], GEN_INT (val & 0xFFFF0000)));
2207           return 1;
2208         }
2209       else if (log2constp (val | 0xFFFF) && (val & 0x8000) != 0)
2210         {
2211           emit_insn (gen_movsi (operands[0], GEN_INT (tmp)));
2212           emit_insn (gen_andsi3 (operands[0], operands[0], GEN_INT (val | 0xFFFF)));
2213         }
2214     }
2215
2216   if (D_REGNO_P (regno))
2217     {
2218       if (CONST_7BIT_IMM_P (tmp))
2219         {
2220           emit_insn (gen_movsi (operands[0], GEN_INT (tmp)));
2221           emit_insn (gen_movstricthi_high (operands[0], GEN_INT (val & -65536)));
2222           return 1;
2223         }
2224
2225       if ((val & 0xFFFF0000) == 0)
2226         {
2227           emit_insn (gen_movsi (operands[0], const0_rtx));
2228           emit_insn (gen_movsi_low (operands[0], operands[0], operands[1]));
2229           return 1;
2230         }
2231
2232       if ((val & 0xFFFF0000) == 0xFFFF0000)
2233         {
2234           emit_insn (gen_movsi (operands[0], constm1_rtx));
2235           emit_insn (gen_movsi_low (operands[0], operands[0], operands[1]));
2236           return 1;
2237         }
2238     }
2239
2240   /* Need DREGs for the remaining case.  */
2241   if (regno > REG_R7)
2242     return 0;
2243
2244   if (optimize_size
2245       && num_compl_zero && CONST_7BIT_IMM_P (shifted_compl))
2246     {
2247       /* If optimizing for size, generate a sequence that has more instructions
2248          but is shorter.  */
2249       emit_insn (gen_movsi (operands[0], GEN_INT (shifted_compl)));
2250       emit_insn (gen_ashlsi3 (operands[0], operands[0],
2251                               GEN_INT (num_compl_zero)));
2252       emit_insn (gen_one_cmplsi2 (operands[0], operands[0]));
2253       return 1;
2254     }
2255   return 0;
2256 }
2257 \f
2258 /* Return true if the legitimate memory address for a memory operand of mode
2259    MODE.  Return false if not.  */
2260
2261 static bool
2262 bfin_valid_add (enum machine_mode mode, HOST_WIDE_INT value)
2263 {
2264   unsigned HOST_WIDE_INT v = value > 0 ? value : -value;
2265   int sz = GET_MODE_SIZE (mode);
2266   int shift = sz == 1 ? 0 : sz == 2 ? 1 : 2;
2267   /* The usual offsettable_memref machinery doesn't work so well for this
2268      port, so we deal with the problem here.  */
2269   unsigned HOST_WIDE_INT mask = sz == 8 ? 0x7ffe : 0x7fff;
2270   return (v & ~(mask << shift)) == 0;
2271 }
2272
2273 static bool
2274 bfin_valid_reg_p (unsigned int regno, int strict, enum machine_mode mode,
2275                   enum rtx_code outer_code)
2276 {
2277   if (strict)
2278     return REGNO_OK_FOR_BASE_STRICT_P (regno, mode, outer_code, SCRATCH);
2279   else
2280     return REGNO_OK_FOR_BASE_NONSTRICT_P (regno, mode, outer_code, SCRATCH);
2281 }
2282
2283 bool
2284 bfin_legitimate_address_p (enum machine_mode mode, rtx x, int strict)
2285 {
2286   switch (GET_CODE (x)) {
2287   case REG:
2288     if (bfin_valid_reg_p (REGNO (x), strict, mode, MEM))
2289       return true;
2290     break;
2291   case PLUS:
2292     if (REG_P (XEXP (x, 0))
2293         && bfin_valid_reg_p (REGNO (XEXP (x, 0)), strict, mode, PLUS)
2294         && ((GET_CODE (XEXP (x, 1)) == UNSPEC && mode == SImode)
2295             || (GET_CODE (XEXP (x, 1)) == CONST_INT
2296                 && bfin_valid_add (mode, INTVAL (XEXP (x, 1))))))
2297       return true;
2298     break;
2299   case POST_INC:
2300   case POST_DEC:
2301     if (LEGITIMATE_MODE_FOR_AUTOINC_P (mode)
2302         && REG_P (XEXP (x, 0))
2303         && bfin_valid_reg_p (REGNO (XEXP (x, 0)), strict, mode, POST_INC))
2304       return true;
2305   case PRE_DEC:
2306     if (LEGITIMATE_MODE_FOR_AUTOINC_P (mode)
2307         && XEXP (x, 0) == stack_pointer_rtx
2308         && REG_P (XEXP (x, 0))
2309         && bfin_valid_reg_p (REGNO (XEXP (x, 0)), strict, mode, PRE_DEC))
2310       return true;
2311     break;
2312   default:
2313     break;
2314   }
2315   return false;
2316 }
2317
2318 static bool
2319 bfin_rtx_costs (rtx x, int code, int outer_code, int *total)
2320 {
2321   int cost2 = COSTS_N_INSNS (1);
2322
2323   switch (code)
2324     {
2325     case CONST_INT:
2326       if (outer_code == SET || outer_code == PLUS)
2327         *total = CONST_7BIT_IMM_P (INTVAL (x)) ? 0 : cost2;
2328       else if (outer_code == AND)
2329         *total = log2constp (~INTVAL (x)) ? 0 : cost2;
2330       else if (outer_code == LE || outer_code == LT || outer_code == EQ)
2331         *total = (INTVAL (x) >= -4 && INTVAL (x) <= 3) ? 0 : cost2;
2332       else if (outer_code == LEU || outer_code == LTU)
2333         *total = (INTVAL (x) >= 0 && INTVAL (x) <= 7) ? 0 : cost2;
2334       else if (outer_code == MULT)
2335         *total = (INTVAL (x) == 2 || INTVAL (x) == 4) ? 0 : cost2;
2336       else if (outer_code == ASHIFT && (INTVAL (x) == 1 || INTVAL (x) == 2))
2337         *total = 0;
2338       else if (outer_code == ASHIFT || outer_code == ASHIFTRT
2339                || outer_code == LSHIFTRT)
2340         *total = (INTVAL (x) >= 0 && INTVAL (x) <= 31) ? 0 : cost2;
2341       else if (outer_code == IOR || outer_code == XOR)
2342         *total = (INTVAL (x) & (INTVAL (x) - 1)) == 0 ? 0 : cost2;
2343       else
2344         *total = cost2;
2345       return true;
2346
2347     case CONST:
2348     case LABEL_REF:
2349     case SYMBOL_REF:
2350     case CONST_DOUBLE:
2351       *total = COSTS_N_INSNS (2);
2352       return true;
2353
2354     case PLUS:
2355       if (GET_MODE (x) == Pmode)
2356         {
2357           if (GET_CODE (XEXP (x, 0)) == MULT
2358               && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)
2359             {
2360               HOST_WIDE_INT val = INTVAL (XEXP (XEXP (x, 0), 1));
2361               if (val == 2 || val == 4)
2362                 {
2363                   *total = cost2;
2364                   *total += rtx_cost (XEXP (XEXP (x, 0), 0), outer_code);
2365                   *total += rtx_cost (XEXP (x, 1), outer_code);
2366                   return true;
2367                 }
2368             }
2369         }
2370
2371       /* fall through */
2372
2373     case MINUS:
2374     case ASHIFT: 
2375     case ASHIFTRT:
2376     case LSHIFTRT:
2377       if (GET_MODE (x) == DImode)
2378         *total = 6 * cost2;
2379       return false;
2380           
2381     case AND:
2382     case IOR:
2383     case XOR:
2384       if (GET_MODE (x) == DImode)
2385         *total = 2 * cost2;
2386       return false;
2387
2388     case MULT:
2389       if (GET_MODE_SIZE (GET_MODE (x)) <= UNITS_PER_WORD)
2390         *total = COSTS_N_INSNS (3);
2391       return false;
2392
2393     case UDIV:
2394     case UMOD:
2395       *total = COSTS_N_INSNS (32);
2396       return true;
2397
2398     case VEC_CONCAT:
2399     case VEC_SELECT:
2400       if (outer_code == SET)
2401         *total = cost2;
2402       return true;
2403
2404     default:
2405       return false;
2406     }
2407 }
2408
2409 static void
2410 bfin_internal_label (FILE *stream, const char *prefix, unsigned long num)
2411 {
2412   fprintf (stream, "%s%s$%ld:\n", LOCAL_LABEL_PREFIX, prefix, num);
2413 }
2414 \f
2415 /* Used for communication between {push,pop}_multiple_operation (which
2416    we use not only as a predicate) and the corresponding output functions.  */
2417 static int first_preg_to_save, first_dreg_to_save;
2418
2419 int
2420 push_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
2421 {
2422   int lastdreg = 8, lastpreg = 6;
2423   int i, group;
2424
2425   first_preg_to_save = lastpreg;
2426   first_dreg_to_save = lastdreg;
2427   for (i = 1, group = 0; i < XVECLEN (op, 0) - 1; i++)
2428     {
2429       rtx t = XVECEXP (op, 0, i);
2430       rtx src, dest;
2431       int regno;
2432
2433       if (GET_CODE (t) != SET)
2434         return 0;
2435
2436       src = SET_SRC (t);
2437       dest = SET_DEST (t);
2438       if (GET_CODE (dest) != MEM || ! REG_P (src))
2439         return 0;
2440       dest = XEXP (dest, 0);
2441       if (GET_CODE (dest) != PLUS
2442           || ! REG_P (XEXP (dest, 0))
2443           || REGNO (XEXP (dest, 0)) != REG_SP
2444           || GET_CODE (XEXP (dest, 1)) != CONST_INT
2445           || INTVAL (XEXP (dest, 1)) != -i * 4)
2446         return 0;
2447
2448       regno = REGNO (src);
2449       if (group == 0)
2450         {
2451           if (D_REGNO_P (regno))
2452             {
2453               group = 1;
2454               first_dreg_to_save = lastdreg = regno - REG_R0;
2455             }
2456           else if (regno >= REG_P0 && regno <= REG_P7)
2457             {
2458               group = 2;
2459               first_preg_to_save = lastpreg = regno - REG_P0;
2460             }
2461           else
2462             return 0;
2463
2464           continue;
2465         }
2466
2467       if (group == 1)
2468         {
2469           if (regno >= REG_P0 && regno <= REG_P7)
2470             {
2471               group = 2;
2472               first_preg_to_save = lastpreg = regno - REG_P0;
2473             }
2474           else if (regno != REG_R0 + lastdreg + 1)
2475             return 0;
2476           else
2477             lastdreg++;
2478         }
2479       else if (group == 2)
2480         {
2481           if (regno != REG_P0 + lastpreg + 1)
2482             return 0;
2483           lastpreg++;
2484         }
2485     }
2486   return 1;
2487 }
2488
2489 int
2490 pop_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
2491 {
2492   int lastdreg = 8, lastpreg = 6;
2493   int i, group;
2494
2495   for (i = 1, group = 0; i < XVECLEN (op, 0); i++)
2496     {
2497       rtx t = XVECEXP (op, 0, i);
2498       rtx src, dest;
2499       int regno;
2500
2501       if (GET_CODE (t) != SET)
2502         return 0;
2503
2504       src = SET_SRC (t);
2505       dest = SET_DEST (t);
2506       if (GET_CODE (src) != MEM || ! REG_P (dest))
2507         return 0;
2508       src = XEXP (src, 0);
2509
2510       if (i == 1)
2511         {
2512           if (! REG_P (src) || REGNO (src) != REG_SP)
2513             return 0;
2514         }
2515       else if (GET_CODE (src) != PLUS
2516                || ! REG_P (XEXP (src, 0))
2517                || REGNO (XEXP (src, 0)) != REG_SP
2518                || GET_CODE (XEXP (src, 1)) != CONST_INT
2519                || INTVAL (XEXP (src, 1)) != (i - 1) * 4)
2520         return 0;
2521
2522       regno = REGNO (dest);
2523       if (group == 0)
2524         {
2525           if (regno == REG_R7)
2526             {
2527               group = 1;
2528               lastdreg = 7;
2529             }
2530           else if (regno != REG_P0 + lastpreg - 1)
2531             return 0;
2532           else
2533             lastpreg--;
2534         }
2535       else if (group == 1)
2536         {
2537           if (regno != REG_R0 + lastdreg - 1)
2538             return 0;
2539           else
2540             lastdreg--;
2541         }
2542     }
2543   first_dreg_to_save = lastdreg;
2544   first_preg_to_save = lastpreg;
2545   return 1;
2546 }
2547
2548 /* Emit assembly code for one multi-register push described by INSN, with
2549    operands in OPERANDS.  */
2550
2551 void
2552 output_push_multiple (rtx insn, rtx *operands)
2553 {
2554   char buf[80];
2555   int ok;
2556   
2557   /* Validate the insn again, and compute first_[dp]reg_to_save. */
2558   ok = push_multiple_operation (PATTERN (insn), VOIDmode);
2559   gcc_assert (ok);
2560   
2561   if (first_dreg_to_save == 8)
2562     sprintf (buf, "[--sp] = ( p5:%d );\n", first_preg_to_save);
2563   else if (first_preg_to_save == 6)
2564     sprintf (buf, "[--sp] = ( r7:%d );\n", first_dreg_to_save);
2565   else
2566     sprintf (buf, "[--sp] = ( r7:%d, p5:%d );\n",
2567              first_dreg_to_save, first_preg_to_save);
2568
2569   output_asm_insn (buf, operands);
2570 }
2571
2572 /* Emit assembly code for one multi-register pop described by INSN, with
2573    operands in OPERANDS.  */
2574
2575 void
2576 output_pop_multiple (rtx insn, rtx *operands)
2577 {
2578   char buf[80];
2579   int ok;
2580   
2581   /* Validate the insn again, and compute first_[dp]reg_to_save. */
2582   ok = pop_multiple_operation (PATTERN (insn), VOIDmode);
2583   gcc_assert (ok);
2584
2585   if (first_dreg_to_save == 8)
2586     sprintf (buf, "( p5:%d ) = [sp++];\n", first_preg_to_save);
2587   else if (first_preg_to_save == 6)
2588     sprintf (buf, "( r7:%d ) = [sp++];\n", first_dreg_to_save);
2589   else
2590     sprintf (buf, "( r7:%d, p5:%d ) = [sp++];\n",
2591              first_dreg_to_save, first_preg_to_save);
2592
2593   output_asm_insn (buf, operands);
2594 }
2595
2596 /* Adjust DST and SRC by OFFSET bytes, and generate one move in mode MODE.  */
2597
2598 static void
2599 single_move_for_movmem (rtx dst, rtx src, enum machine_mode mode, HOST_WIDE_INT offset)
2600 {
2601   rtx scratch = gen_reg_rtx (mode);
2602   rtx srcmem, dstmem;
2603
2604   srcmem = adjust_address_nv (src, mode, offset);
2605   dstmem = adjust_address_nv (dst, mode, offset);
2606   emit_move_insn (scratch, srcmem);
2607   emit_move_insn (dstmem, scratch);
2608 }
2609
2610 /* Expand a string move operation of COUNT_EXP bytes from SRC to DST, with
2611    alignment ALIGN_EXP.  Return true if successful, false if we should fall
2612    back on a different method.  */
2613
2614 bool
2615 bfin_expand_movmem (rtx dst, rtx src, rtx count_exp, rtx align_exp)
2616 {
2617   rtx srcreg, destreg, countreg;
2618   HOST_WIDE_INT align = 0;
2619   unsigned HOST_WIDE_INT count = 0;
2620
2621   if (GET_CODE (align_exp) == CONST_INT)
2622     align = INTVAL (align_exp);
2623   if (GET_CODE (count_exp) == CONST_INT)
2624     {
2625       count = INTVAL (count_exp);
2626 #if 0
2627       if (!TARGET_INLINE_ALL_STRINGOPS && count > 64)
2628         return false;
2629 #endif
2630     }
2631
2632   /* If optimizing for size, only do single copies inline.  */
2633   if (optimize_size)
2634     {
2635       if (count == 2 && align < 2)
2636         return false;
2637       if (count == 4 && align < 4)
2638         return false;
2639       if (count != 1 && count != 2 && count != 4)
2640         return false;
2641     }
2642   if (align < 2 && count != 1)
2643     return false;
2644
2645   destreg = copy_to_mode_reg (Pmode, XEXP (dst, 0));
2646   if (destreg != XEXP (dst, 0))
2647     dst = replace_equiv_address_nv (dst, destreg);
2648   srcreg = copy_to_mode_reg (Pmode, XEXP (src, 0));
2649   if (srcreg != XEXP (src, 0))
2650     src = replace_equiv_address_nv (src, srcreg);
2651
2652   if (count != 0 && align >= 2)
2653     {
2654       unsigned HOST_WIDE_INT offset = 0;
2655
2656       if (align >= 4)
2657         {
2658           if ((count & ~3) == 4)
2659             {
2660               single_move_for_movmem (dst, src, SImode, offset);
2661               offset = 4;
2662             }
2663           else if (count & ~3)
2664             {
2665               HOST_WIDE_INT new_count = ((count >> 2) & 0x3fffffff) - 1;
2666               countreg = copy_to_mode_reg (Pmode, GEN_INT (new_count));
2667
2668               emit_insn (gen_rep_movsi (destreg, srcreg, countreg, destreg, srcreg));
2669             }
2670           if (count & 2)
2671             {
2672               single_move_for_movmem (dst, src, HImode, offset);
2673               offset += 2;
2674             }
2675         }
2676       else
2677         {
2678           if ((count & ~1) == 2)
2679             {
2680               single_move_for_movmem (dst, src, HImode, offset);
2681               offset = 2;
2682             }
2683           else if (count & ~1)
2684             {
2685               HOST_WIDE_INT new_count = ((count >> 1) & 0x7fffffff) - 1;
2686               countreg = copy_to_mode_reg (Pmode, GEN_INT (new_count));
2687
2688               emit_insn (gen_rep_movhi (destreg, srcreg, countreg, destreg, srcreg));
2689             }
2690         }
2691       if (count & 1)
2692         {
2693           single_move_for_movmem (dst, src, QImode, offset);
2694         }
2695       return true;
2696     }
2697   return false;
2698 }
2699
2700 \f
2701 static int
2702 bfin_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
2703 {
2704   enum attr_type insn_type, dep_insn_type;
2705   int dep_insn_code_number;
2706
2707   /* Anti and output dependencies have zero cost.  */
2708   if (REG_NOTE_KIND (link) != 0)
2709     return 0;
2710
2711   dep_insn_code_number = recog_memoized (dep_insn);
2712
2713   /* If we can't recognize the insns, we can't really do anything.  */
2714   if (dep_insn_code_number < 0 || recog_memoized (insn) < 0)
2715     return cost;
2716
2717   insn_type = get_attr_type (insn);
2718   dep_insn_type = get_attr_type (dep_insn);
2719
2720   if (dep_insn_type == TYPE_MOVE || dep_insn_type == TYPE_MCLD)
2721     {
2722       rtx pat = PATTERN (dep_insn);
2723       rtx dest = SET_DEST (pat);
2724       rtx src = SET_SRC (pat);
2725       if (! ADDRESS_REGNO_P (REGNO (dest)) || ! D_REGNO_P (REGNO (src)))
2726         return cost;
2727       return cost + (dep_insn_type == TYPE_MOVE ? 4 : 3);
2728     }
2729
2730   return cost;
2731 }
2732
2733 \f
2734 /* Increment the counter for the number of loop instructions in the
2735    current function.  */
2736
2737 void
2738 bfin_hardware_loop (void)
2739 {
2740   cfun->machine->has_hardware_loops++;
2741 }
2742
2743 /* Maximum loop nesting depth.  */
2744 #define MAX_LOOP_DEPTH 2
2745
2746 /* Maximum size of a loop.  */
2747 #define MAX_LOOP_LENGTH 2042
2748
2749 /* We need to keep a vector of loops */
2750 typedef struct loop_info *loop_info;
2751 DEF_VEC_P (loop_info);
2752 DEF_VEC_ALLOC_P (loop_info,heap);
2753
2754 /* Information about a loop we have found (or are in the process of
2755    finding).  */
2756 struct loop_info GTY (())
2757 {
2758   /* loop number, for dumps */
2759   int loop_no;
2760
2761   /* Predecessor block of the loop.   This is the one that falls into
2762      the loop and contains the initialization instruction.  */
2763   basic_block predecessor;
2764
2765   /* First block in the loop.  This is the one branched to by the loop_end
2766      insn.  */
2767   basic_block head;
2768
2769   /* Last block in the loop (the one with the loop_end insn).  */
2770   basic_block tail;
2771
2772   /* The successor block of the loop.  This is the one the loop_end insn
2773      falls into.  */
2774   basic_block successor;
2775
2776   /* The last instruction in the tail.  */
2777   rtx last_insn;
2778
2779   /* The loop_end insn.  */
2780   rtx loop_end;
2781
2782   /* The iteration register.  */
2783   rtx iter_reg;
2784
2785   /* The new initialization insn.  */
2786   rtx init;
2787
2788   /* The new initialization instruction.  */
2789   rtx loop_init;
2790
2791   /* The new label placed at the beginning of the loop. */
2792   rtx start_label;
2793
2794   /* The new label placed at the end of the loop. */
2795   rtx end_label;
2796
2797   /* The length of the loop.  */
2798   int length;
2799
2800   /* The nesting depth of the loop.  Set to -1 for a bad loop.  */
2801   int depth;
2802
2803   /* True if we have visited this loop.  */
2804   int visited;
2805
2806   /* True if this loop body clobbers any of LC0, LT0, or LB0.  */
2807   int clobber_loop0;
2808
2809   /* True if this loop body clobbers any of LC1, LT1, or LB1.  */
2810   int clobber_loop1;
2811
2812   /* Next loop in the graph. */
2813   struct loop_info *next;
2814
2815   /* Immediate outer loop of this loop.  */
2816   struct loop_info *outer;
2817
2818   /* Vector of blocks only within the loop, (excluding those within
2819      inner loops).  */
2820   VEC (basic_block,heap) *blocks;
2821
2822   /* Vector of inner loops within this loop  */
2823   VEC (loop_info,heap) *loops;
2824 };
2825
2826 /* Information used during loop detection.  */
2827 typedef struct loop_work GTY(())
2828 {
2829   /* Basic block to be scanned.  */
2830   basic_block block;
2831
2832   /* Loop it will be within.  */
2833   loop_info loop;
2834 } loop_work;
2835
2836 /* Work list.  */
2837 DEF_VEC_O (loop_work);
2838 DEF_VEC_ALLOC_O (loop_work,heap);
2839
2840 static void
2841 bfin_dump_loops (loop_info loops)
2842 {
2843   loop_info loop;
2844
2845   for (loop = loops; loop; loop = loop->next)
2846     {
2847       loop_info i;
2848       basic_block b;
2849       unsigned ix;
2850
2851       fprintf (dump_file, ";; loop %d: ", loop->loop_no);
2852       fprintf (dump_file, "{head:%d, depth:%d}", loop->head->index, loop->depth);
2853
2854       fprintf (dump_file, " blocks: [ ");
2855       for (ix = 0; VEC_iterate (basic_block, loop->blocks, ix, b); ix++)
2856         fprintf (dump_file, "%d ", b->index);
2857       fprintf (dump_file, "] ");
2858
2859       fprintf (dump_file, " inner loops: [ ");
2860       for (ix = 0; VEC_iterate (loop_info, loop->loops, ix, i); ix++)
2861         fprintf (dump_file, "%d ", i->loop_no);
2862       fprintf (dump_file, "]\n");
2863     }
2864   fprintf (dump_file, "\n");
2865 }
2866
2867 /* Scan the blocks of LOOP (and its inferiors) looking for basic block
2868    BB. Return true, if we find it.  */
2869
2870 static bool
2871 bfin_bb_in_loop (loop_info loop, basic_block bb)
2872 {
2873   unsigned ix;
2874   loop_info inner;
2875   basic_block b;
2876
2877   for (ix = 0; VEC_iterate (basic_block, loop->blocks, ix, b); ix++)
2878     if (b == bb)
2879       return true;
2880
2881   for (ix = 0; VEC_iterate (loop_info, loop->loops, ix, inner); ix++)
2882     if (bfin_bb_in_loop (inner, bb))
2883       return true;
2884
2885   return false;
2886 }
2887
2888 /* Scan the blocks of LOOP (and its inferiors) looking for uses of
2889    REG.  Return true, if we find any.  Don't count the loop's loop_end
2890    insn if it matches LOOP_END.  */
2891
2892 static bool
2893 bfin_scan_loop (loop_info loop, rtx reg, rtx loop_end)
2894 {
2895   unsigned ix;
2896   loop_info inner;
2897   basic_block bb;
2898
2899   for (ix = 0; VEC_iterate (basic_block, loop->blocks, ix, bb); ix++)
2900     {
2901       rtx insn;
2902
2903       for (insn = BB_HEAD (bb);
2904            insn != NEXT_INSN (BB_END (bb));
2905            insn = NEXT_INSN (insn))
2906         {
2907           if (!INSN_P (insn))
2908             continue;
2909           if (insn == loop_end)
2910             continue;
2911           if (reg_mentioned_p (reg, PATTERN (insn)))
2912             return true;
2913         }
2914     }
2915   for (ix = 0; VEC_iterate (loop_info, loop->loops, ix, inner); ix++)
2916     if (bfin_scan_loop (inner, reg, NULL_RTX))
2917       return true;
2918
2919   return false;
2920 }
2921
2922 /* Optimize LOOP.  */
2923
2924 static void
2925 bfin_optimize_loop (loop_info loop)
2926 {
2927   basic_block bb;
2928   loop_info inner, outer;
2929   rtx insn, init_insn, last_insn, nop_insn;
2930   rtx loop_init, start_label, end_label;
2931   rtx reg_lc0, reg_lc1, reg_lt0, reg_lt1, reg_lb0, reg_lb1;
2932   rtx iter_reg;
2933   rtx lc_reg, lt_reg, lb_reg;
2934   rtx seq;
2935   int length;
2936   unsigned ix;
2937   int inner_depth = 0;
2938   int inner_num;
2939   int bb_num;
2940
2941   if (loop->visited)
2942     return;
2943
2944   loop->visited = 1;
2945
2946   for (ix = 0; VEC_iterate (loop_info, loop->loops, ix, inner); ix++)
2947     {
2948       if (inner->loop_no == loop->loop_no)
2949         loop->depth = -1;
2950       else
2951         bfin_optimize_loop (inner);
2952
2953       if (inner->depth < 0 || inner->depth > MAX_LOOP_DEPTH)
2954         {
2955           inner->outer = NULL;
2956           VEC_ordered_remove (loop_info, loop->loops, ix);
2957         }
2958
2959       if (inner_depth < inner->depth)
2960         inner_depth = inner->depth;
2961
2962       loop->clobber_loop0 |= inner->clobber_loop0;
2963       loop->clobber_loop1 |= inner->clobber_loop1;
2964     }
2965
2966   if (loop->depth < 0)
2967     {
2968       if (dump_file)
2969         fprintf (dump_file, ";; loop %d bad when found\n", loop->loop_no);
2970       goto bad_loop;
2971     }
2972
2973   loop->depth = inner_depth + 1;
2974   if (loop->depth > MAX_LOOP_DEPTH)
2975     {
2976       if (dump_file)
2977         fprintf (dump_file, ";; loop %d too deep\n", loop->loop_no);
2978       goto bad_loop;
2979     }
2980
2981   /* Make sure we only have one entry point.  */
2982   if (EDGE_COUNT (loop->head->preds) == 2)
2983     {
2984       loop->predecessor = EDGE_PRED (loop->head, 0)->src;
2985       if (loop->predecessor == loop->tail)
2986         /* We wanted the other predecessor.  */
2987         loop->predecessor = EDGE_PRED (loop->head, 1)->src;
2988
2989       /* We can only place a loop insn on a fall through edge of a
2990          single exit block.  */
2991       if (EDGE_COUNT (loop->predecessor->succs) != 1
2992           || !(EDGE_SUCC (loop->predecessor, 0)->flags & EDGE_FALLTHRU)
2993           /* If loop->predecessor is in loop, loop->head is not really
2994              the head of the loop.  */
2995           || bfin_bb_in_loop (loop, loop->predecessor))
2996         loop->predecessor = NULL;
2997     }
2998
2999   if (loop->predecessor == NULL)
3000     {
3001       if (dump_file)
3002         fprintf (dump_file, ";; loop %d has bad predecessor\n", loop->loop_no);
3003       goto bad_loop;
3004     }
3005
3006   /* Get the loop iteration register.  */
3007   iter_reg = loop->iter_reg;
3008
3009   if (!DPREG_P (iter_reg))
3010     {
3011       if (dump_file)
3012         fprintf (dump_file, ";; loop %d iteration count NOT in PREG or DREG\n",
3013                  loop->loop_no);
3014       goto bad_loop;
3015     }
3016
3017   /* Check if start_label appears before loop_end and calculate the
3018      offset between them.  We calculate the length of instructions
3019      conservatively.  */
3020   length = 0;
3021   for (insn = loop->start_label;
3022        insn && insn != loop->loop_end;
3023        insn = NEXT_INSN (insn))
3024     {
3025       if (JUMP_P (insn) && any_condjump_p (insn) && !optimize_size)
3026         {
3027           if (TARGET_CSYNC_ANOMALY)
3028             length += 8;
3029           else if (TARGET_SPECLD_ANOMALY)
3030             length += 6;
3031         }
3032       else if (LABEL_P (insn))
3033         {
3034           if (TARGET_CSYNC_ANOMALY)
3035             length += 4;
3036         }
3037
3038       if (INSN_P (insn))
3039         length += get_attr_length (insn);
3040     }
3041
3042   if (!insn)
3043     {
3044       if (dump_file)
3045         fprintf (dump_file, ";; loop %d start_label not before loop_end\n",
3046                  loop->loop_no);
3047       goto bad_loop;
3048     }
3049
3050   loop->length = length;
3051   if (loop->length > MAX_LOOP_LENGTH)
3052     {
3053       if (dump_file)
3054         fprintf (dump_file, ";; loop %d too long\n", loop->loop_no);
3055       goto bad_loop;
3056     }
3057
3058   /* Scan all the blocks to make sure they don't use iter_reg.  */
3059   if (bfin_scan_loop (loop, iter_reg, loop->loop_end))
3060     {
3061       if (dump_file)
3062         fprintf (dump_file, ";; loop %d uses iterator\n", loop->loop_no);
3063       goto bad_loop;
3064     }
3065
3066   /* Scan all the insns to see if the loop body clobber
3067      any hardware loop registers. */
3068
3069   reg_lc0 = gen_rtx_REG (SImode, REG_LC0);
3070   reg_lc1 = gen_rtx_REG (SImode, REG_LC1);
3071   reg_lt0 = gen_rtx_REG (SImode, REG_LT0);
3072   reg_lt1 = gen_rtx_REG (SImode, REG_LT1);
3073   reg_lb0 = gen_rtx_REG (SImode, REG_LB0);
3074   reg_lb1 = gen_rtx_REG (SImode, REG_LB1);
3075
3076   for (ix = 0; VEC_iterate (basic_block, loop->blocks, ix, bb); ix++)
3077     {
3078       rtx insn;
3079
3080       for (insn = BB_HEAD (bb);
3081            insn != NEXT_INSN (BB_END (bb));
3082            insn = NEXT_INSN (insn))
3083         {
3084           if (!INSN_P (insn))
3085             continue;
3086
3087           if (reg_set_p (reg_lc0, insn)
3088               || reg_set_p (reg_lt0, insn)
3089               || reg_set_p (reg_lb0, insn))
3090             loop->clobber_loop0 = 1;
3091           
3092           if (reg_set_p (reg_lc1, insn)
3093               || reg_set_p (reg_lt1, insn)
3094               || reg_set_p (reg_lb1, insn))
3095             loop->clobber_loop1 |= 1;
3096         }
3097     }
3098
3099   if ((loop->clobber_loop0 && loop->clobber_loop1)
3100       || (loop->depth == MAX_LOOP_DEPTH && loop->clobber_loop0))
3101     {
3102       loop->depth = MAX_LOOP_DEPTH + 1;
3103       if (dump_file)
3104         fprintf (dump_file, ";; loop %d no loop reg available\n",
3105                  loop->loop_no);
3106       goto bad_loop;
3107     }
3108
3109   /* There should be an instruction before the loop_end instruction
3110      in the same basic block. And the instruction must not be
3111      - JUMP
3112      - CONDITIONAL BRANCH
3113      - CALL
3114      - CSYNC
3115      - SSYNC
3116      - Returns (RTS, RTN, etc.)  */
3117
3118   bb = loop->tail;
3119   last_insn = PREV_INSN (loop->loop_end);
3120
3121   while (1)
3122     {
3123       for (; last_insn != PREV_INSN (BB_HEAD (bb));
3124            last_insn = PREV_INSN (last_insn))
3125         if (INSN_P (last_insn))
3126           break;
3127
3128       if (last_insn != PREV_INSN (BB_HEAD (bb)))
3129         break;
3130
3131       if (single_pred_p (bb)
3132           && single_pred (bb) != ENTRY_BLOCK_PTR)
3133         {
3134           bb = single_pred (bb);
3135           last_insn = BB_END (bb);
3136           continue;
3137         }
3138       else
3139         {
3140           last_insn = NULL_RTX;
3141           break;
3142         }
3143     }
3144
3145   if (!last_insn)
3146     {
3147       if (dump_file)
3148         fprintf (dump_file, ";; loop %d has no last instruction\n",
3149                  loop->loop_no);
3150       goto bad_loop;
3151     }
3152
3153   if (JUMP_P (last_insn))
3154     {
3155       loop_info inner = bb->aux;
3156       if (inner
3157           && inner->outer == loop
3158           && inner->loop_end == last_insn
3159           && inner->depth == 1)
3160         /* This jump_insn is the exact loop_end of an inner loop
3161            and to be optimized away. So use the inner's last_insn.  */
3162         last_insn = inner->last_insn;
3163       else
3164         {
3165           if (dump_file)
3166             fprintf (dump_file, ";; loop %d has bad last instruction\n",
3167                      loop->loop_no);
3168           goto bad_loop;
3169         }
3170     }
3171   else if (CALL_P (last_insn)
3172            || get_attr_type (last_insn) == TYPE_SYNC
3173            || recog_memoized (last_insn) == CODE_FOR_return_internal)
3174     {
3175       if (dump_file)
3176         fprintf (dump_file, ";; loop %d has bad last instruction\n",
3177                  loop->loop_no);
3178       goto bad_loop;
3179     }
3180
3181   if (GET_CODE (PATTERN (last_insn)) == ASM_INPUT
3182       || asm_noperands (PATTERN (last_insn)) >= 0
3183       || get_attr_seq_insns (last_insn) == SEQ_INSNS_MULTI)
3184     {
3185       nop_insn = emit_insn_after (gen_nop (), last_insn);
3186       last_insn = nop_insn;
3187     }
3188
3189   loop->last_insn = last_insn;
3190
3191   /* The loop is good for replacement.  */
3192   start_label = loop->start_label;
3193   end_label = gen_label_rtx ();
3194   iter_reg = loop->iter_reg;
3195
3196   if (loop->depth == 1 && !loop->clobber_loop1)
3197     {
3198       lc_reg = reg_lc1;
3199       lt_reg = reg_lt1;
3200       lb_reg = reg_lb1;
3201       loop->clobber_loop1 = 1;
3202     }
3203   else
3204     {
3205       lc_reg = reg_lc0;
3206       lt_reg = reg_lt0;
3207       lb_reg = reg_lb0;
3208       loop->clobber_loop0 = 1;
3209     }
3210
3211   /* If iter_reg is a DREG, we need generate an instruction to load
3212      the loop count into LC register. */
3213   if (D_REGNO_P (REGNO (iter_reg)))
3214     {
3215       init_insn = gen_movsi (lc_reg, iter_reg);
3216       loop_init = gen_lsetup_without_autoinit (lt_reg, start_label,
3217                                                lb_reg, end_label,
3218                                                lc_reg);
3219     }
3220   else if (P_REGNO_P (REGNO (iter_reg)))
3221     {
3222       init_insn = NULL_RTX;
3223       loop_init = gen_lsetup_with_autoinit (lt_reg, start_label,
3224                                             lb_reg, end_label,
3225                                             lc_reg, iter_reg);
3226     }
3227   else
3228     gcc_unreachable ();
3229
3230   loop->init = init_insn;
3231   loop->end_label = end_label;
3232   loop->loop_init = loop_init;
3233
3234   if (dump_file)
3235     {
3236       fprintf (dump_file, ";; replacing loop %d initializer with\n",
3237                loop->loop_no);
3238       print_rtl_single (dump_file, loop->loop_init);
3239       fprintf (dump_file, ";; replacing loop %d terminator with\n",
3240                loop->loop_no);
3241       print_rtl_single (dump_file, loop->loop_end);
3242     }
3243
3244   start_sequence ();
3245
3246   if (loop->init != NULL_RTX)
3247     emit_insn (loop->init);
3248   emit_insn(loop->loop_init);
3249   emit_label (loop->start_label);
3250
3251   seq = get_insns ();
3252   end_sequence ();
3253
3254   emit_insn_after (seq, BB_END (loop->predecessor));
3255   delete_insn (loop->loop_end);
3256
3257   /* Insert the loop end label before the last instruction of the loop.  */
3258   emit_label_before (loop->end_label, loop->last_insn);
3259
3260   return;
3261
3262 bad_loop:
3263
3264   if (dump_file)
3265     fprintf (dump_file, ";; loop %d is bad\n", loop->loop_no);
3266
3267   /* Mark this loop bad.  */
3268   if (loop->depth <= MAX_LOOP_DEPTH)
3269     loop->depth = -1;
3270
3271   outer = loop->outer;
3272
3273   /* Move all inner loops to loop's outer loop.  */
3274   inner_num = VEC_length (loop_info, loop->loops);
3275   if (inner_num)
3276     {
3277       loop_info l;
3278
3279       if (outer)
3280         VEC_reserve (loop_info, heap, outer->loops, inner_num);
3281
3282       for (ix = 0; VEC_iterate (loop_info, loop->loops, ix, l); ix++)
3283         {
3284           l->outer = outer;
3285           if (outer)
3286             VEC_quick_push (loop_info, outer->loops, l);
3287         }
3288
3289       VEC_free (loop_info, heap, loop->loops);
3290     }
3291
3292   /* Move all blocks to loop's outer loop.  */
3293   bb_num = VEC_length (basic_block, loop->blocks);
3294   if (bb_num)
3295     {
3296       basic_block b;
3297
3298       if (outer)
3299         VEC_reserve (basic_block, heap, outer->blocks, bb_num);
3300
3301       for (ix = 0; VEC_iterate (basic_block, loop->blocks, ix, b); ix++)
3302         {
3303           b->aux = outer;
3304           if (outer)
3305             VEC_quick_push (basic_block, outer->blocks, b);
3306         }
3307
3308       VEC_free (basic_block, heap, loop->blocks);
3309     }
3310
3311   if (DPREG_P (loop->iter_reg))
3312     {
3313       /* If loop->iter_reg is a DREG or PREG, we can split it here
3314          without scratch register.  */
3315       rtx insn;
3316
3317       emit_insn_before (gen_addsi3 (loop->iter_reg,
3318                                     loop->iter_reg,
3319                                     constm1_rtx),
3320                         loop->loop_end);
3321
3322       emit_insn_before (gen_cmpsi (loop->iter_reg, const0_rtx),
3323                         loop->loop_end);
3324
3325       insn = emit_jump_insn_before (gen_bne (loop->start_label),
3326                                     loop->loop_end);
3327
3328       JUMP_LABEL (insn) = loop->start_label;
3329       LABEL_NUSES (loop->start_label)++;
3330       delete_insn (loop->loop_end);
3331     }
3332 }
3333
3334 static void
3335 bfin_reorg_loops (FILE *dump_file)
3336 {
3337   basic_block bb;
3338   loop_info loops = NULL;
3339   loop_info loop;
3340   int nloops = 0;
3341   unsigned dwork = 0;
3342   VEC (loop_work,heap) *works = VEC_alloc (loop_work,heap,20);
3343   loop_work *work;
3344   edge e;
3345   edge_iterator ei;
3346
3347   /* Find all the possible loop tails.  This means searching for every
3348      loop_end instruction.  For each one found, create a loop_info
3349      structure and add the head block to the work list. */
3350   FOR_EACH_BB (bb)
3351     {
3352       rtx tail = BB_END (bb);
3353
3354       while (GET_CODE (tail) == NOTE)
3355         tail = PREV_INSN (tail);
3356
3357       bb->aux = NULL;
3358       if (INSN_P (tail) && recog_memoized (tail) == CODE_FOR_loop_end)
3359         {
3360           /* A possible loop end */
3361
3362           loop = XNEW (struct loop_info);
3363           loop->next = loops;
3364           loops = loop;
3365           loop->tail = bb;
3366           loop->head = BRANCH_EDGE (bb)->dest;
3367           loop->successor = FALLTHRU_EDGE (bb)->dest;
3368           loop->predecessor = NULL;
3369           loop->loop_end = tail;
3370           loop->last_insn = NULL_RTX;
3371           loop->iter_reg = SET_DEST (XVECEXP (PATTERN (tail), 0, 1));
3372           loop->depth = loop->length = 0;
3373           loop->visited = 0;
3374           loop->clobber_loop0 = loop->clobber_loop1 = 0;
3375           loop->blocks = VEC_alloc (basic_block, heap, 20);
3376           VEC_quick_push (basic_block, loop->blocks, bb);
3377           loop->outer = NULL;
3378           loop->loops = NULL;
3379           loop->loop_no = nloops++;
3380
3381           loop->init = loop->loop_init = NULL_RTX;
3382           loop->start_label = XEXP (XEXP (SET_SRC (XVECEXP (PATTERN (tail), 0, 0)), 1), 0);
3383           loop->end_label = NULL_RTX;
3384
3385           work = VEC_safe_push (loop_work, heap, works, NULL);
3386           work->block = loop->head;
3387           work->loop = loop;
3388
3389           bb->aux = loop;
3390
3391           if (dump_file)
3392             {
3393               fprintf (dump_file, ";; potential loop %d ending at\n",
3394                        loop->loop_no);
3395               print_rtl_single (dump_file, tail);
3396             }
3397         }
3398     }
3399
3400   /*  Now find all the closed loops.
3401       until work list empty,
3402        if block's auxptr is set
3403          if != loop slot
3404            if block's loop's start != block
3405              mark loop as bad
3406            else
3407              append block's loop's fallthrough block to worklist
3408              increment this loop's depth
3409        else if block is exit block
3410          mark loop as bad
3411        else
3412           set auxptr
3413           for each target of block
3414             add to worklist */
3415   while (VEC_iterate (loop_work, works, dwork++, work))
3416     {
3417       loop = work->loop;
3418       bb = work->block;
3419       if (bb == EXIT_BLOCK_PTR)
3420         /* We've reached the exit block.  The loop must be bad. */
3421         loop->depth = -1;
3422       else if (!bb->aux)
3423         {
3424           /* We've not seen this block before.  Add it to the loop's
3425              list and then add each successor to the work list.  */
3426           bb->aux = loop;
3427           VEC_safe_push (basic_block, heap, loop->blocks, bb);
3428           FOR_EACH_EDGE (e, ei, bb->succs)
3429             {
3430               if (!VEC_space (loop_work, works, 1))
3431                 {
3432                   if (dwork)
3433                     {
3434                       VEC_block_remove (loop_work, works, 0, dwork);
3435                       dwork = 0;
3436                     }
3437                   else
3438                     VEC_reserve (loop_work, heap, works, 1);
3439                 }
3440               work = VEC_quick_push (loop_work, works, NULL);
3441               work->block = EDGE_SUCC (bb, ei.index)->dest;
3442               work->loop = loop;
3443             }
3444         }
3445       else if (bb->aux != loop)
3446         {
3447           /* We've seen this block in a different loop.  If it's not
3448              the other loop's head, then this loop must be bad.
3449              Otherwise, the other loop might be a nested loop, so
3450              continue from that loop's successor.  */
3451           loop_info other = bb->aux;
3452
3453           if (other->head != bb)
3454             loop->depth = -1;
3455           else
3456             {
3457               other->outer = loop;
3458               VEC_safe_push (loop_info, heap, loop->loops, other);
3459               work = VEC_safe_push (loop_work, heap, works, NULL);
3460               work->loop = loop;
3461               work->block = other->successor;
3462             }
3463         }
3464     }
3465   VEC_free (loop_work, heap, works);
3466
3467   if (dump_file)
3468     {
3469       fprintf (dump_file, ";; All loops found:\n\n");
3470       bfin_dump_loops (loops);
3471     }
3472   
3473   /* Now apply the optimizations.  */
3474   for (loop = loops; loop; loop = loop->next)
3475     bfin_optimize_loop (loop);
3476
3477   if (dump_file)
3478     {
3479       fprintf (dump_file, ";; After hardware loops optimization:\n\n");
3480       bfin_dump_loops (loops);
3481     }
3482
3483   /* Free up the loop structures */
3484   while (loops)
3485     {
3486       loop = loops;
3487       loops = loop->next;
3488       VEC_free (loop_info, heap, loop->loops);
3489       VEC_free (basic_block, heap, loop->blocks);
3490       XDELETE (loop);
3491     }
3492
3493   if (dump_file)
3494     print_rtl (dump_file, get_insns ());
3495 }
3496
3497 \f
3498 /* We use the machine specific reorg pass for emitting CSYNC instructions
3499    after conditional branches as needed.
3500
3501    The Blackfin is unusual in that a code sequence like
3502      if cc jump label
3503      r0 = (p0)
3504    may speculatively perform the load even if the condition isn't true.  This
3505    happens for a branch that is predicted not taken, because the pipeline
3506    isn't flushed or stalled, so the early stages of the following instructions,
3507    which perform the memory reference, are allowed to execute before the
3508    jump condition is evaluated.
3509    Therefore, we must insert additional instructions in all places where this
3510    could lead to incorrect behavior.  The manual recommends CSYNC, while
3511    VDSP seems to use NOPs (even though its corresponding compiler option is
3512    named CSYNC).
3513
3514    When optimizing for speed, we emit NOPs, which seems faster than a CSYNC.
3515    When optimizing for size, we turn the branch into a predicted taken one.
3516    This may be slower due to mispredicts, but saves code size.  */
3517
3518 static void
3519 bfin_reorg (void)
3520 {
3521   rtx insn, last_condjump = NULL_RTX;
3522   int cycles_since_jump = INT_MAX;
3523
3524   /* Doloop optimization */
3525   if (cfun->machine->has_hardware_loops)
3526     bfin_reorg_loops (dump_file);
3527
3528   if (! TARGET_SPECLD_ANOMALY && ! TARGET_CSYNC_ANOMALY)
3529     return;
3530
3531   /* First pass: find predicted-false branches; if something after them
3532      needs nops, insert them or change the branch to predict true.  */
3533   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
3534     {
3535       rtx pat;
3536
3537       if (NOTE_P (insn) || BARRIER_P (insn) || LABEL_P (insn))
3538         continue;
3539
3540       pat = PATTERN (insn);
3541       if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER
3542           || GET_CODE (pat) == ASM_INPUT || GET_CODE (pat) == ADDR_VEC
3543           || GET_CODE (pat) == ADDR_DIFF_VEC || asm_noperands (pat) >= 0)
3544         continue;
3545
3546       if (JUMP_P (insn))
3547         {
3548           if (any_condjump_p (insn)
3549               && ! cbranch_predicted_taken_p (insn))
3550             {
3551               last_condjump = insn;
3552               cycles_since_jump = 0;
3553             }
3554           else
3555             cycles_since_jump = INT_MAX;
3556         }
3557       else if (INSN_P (insn))
3558         {
3559           enum attr_type type = get_attr_type (insn);
3560           int delay_needed = 0;
3561           if (cycles_since_jump < INT_MAX)
3562             cycles_since_jump++;
3563
3564           if (type == TYPE_MCLD && TARGET_SPECLD_ANOMALY)
3565             {
3566               rtx pat = single_set (insn);
3567               if (may_trap_p (SET_SRC (pat)))
3568                 delay_needed = 3;
3569             }
3570           else if (type == TYPE_SYNC && TARGET_CSYNC_ANOMALY)
3571             delay_needed = 4;
3572
3573           if (delay_needed > cycles_since_jump)
3574             {
3575               rtx pat;
3576               int num_clobbers;
3577               rtx *op = recog_data.operand;
3578
3579               delay_needed -= cycles_since_jump;
3580
3581               extract_insn (last_condjump);
3582               if (optimize_size)
3583                 {
3584                   pat = gen_cbranch_predicted_taken (op[0], op[1], op[2],
3585                                                      op[3]);
3586                   cycles_since_jump = INT_MAX;
3587                 }
3588               else
3589                 /* Do not adjust cycles_since_jump in this case, so that
3590                    we'll increase the number of NOPs for a subsequent insn
3591                    if necessary.  */
3592                 pat = gen_cbranch_with_nops (op[0], op[1], op[2], op[3],
3593                                              GEN_INT (delay_needed));
3594               PATTERN (last_condjump) = pat;
3595               INSN_CODE (last_condjump) = recog (pat, insn, &num_clobbers);
3596             }
3597         }
3598     }
3599   /* Second pass: for predicted-true branches, see if anything at the
3600      branch destination needs extra nops.  */
3601   if (! TARGET_CSYNC_ANOMALY)
3602     return;
3603
3604   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
3605     {
3606       if (JUMP_P (insn)
3607           && any_condjump_p (insn)
3608           && (INSN_CODE (insn) == CODE_FOR_cbranch_predicted_taken
3609               || cbranch_predicted_taken_p (insn)))
3610         {
3611           rtx target = JUMP_LABEL (insn);
3612           rtx label = target;
3613           cycles_since_jump = 0;
3614           for (; target && cycles_since_jump < 3; target = NEXT_INSN (target))
3615             {
3616               rtx pat;
3617
3618               if (NOTE_P (target) || BARRIER_P (target) || LABEL_P (target))
3619                 continue;
3620
3621               pat = PATTERN (target);
3622               if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER
3623                   || GET_CODE (pat) == ASM_INPUT || GET_CODE (pat) == ADDR_VEC
3624                   || GET_CODE (pat) == ADDR_DIFF_VEC || asm_noperands (pat) >= 0)
3625                 continue;
3626
3627               if (INSN_P (target))
3628                 {
3629                   enum attr_type type = get_attr_type (target);
3630                   int delay_needed = 0;
3631                   if (cycles_since_jump < INT_MAX)
3632                     cycles_since_jump++;
3633
3634                   if (type == TYPE_SYNC && TARGET_CSYNC_ANOMALY)
3635                     delay_needed = 2;
3636
3637                   if (delay_needed > cycles_since_jump)
3638                     {
3639                       rtx prev = prev_real_insn (label);
3640                       delay_needed -= cycles_since_jump;
3641                       if (dump_file)
3642                         fprintf (dump_file, "Adding %d nops after %d\n",
3643                                  delay_needed, INSN_UID (label));
3644                       if (JUMP_P (prev)
3645                           && INSN_CODE (prev) == CODE_FOR_cbranch_with_nops)
3646                         {
3647                           rtx x;
3648                           HOST_WIDE_INT v;
3649
3650                           if (dump_file)
3651                             fprintf (dump_file,
3652                                      "Reducing nops on insn %d.\n",
3653                                      INSN_UID (prev));
3654                           x = PATTERN (prev);
3655                           x = XVECEXP (x, 0, 1);
3656                           v = INTVAL (XVECEXP (x, 0, 0)) - delay_needed;
3657                           XVECEXP (x, 0, 0) = GEN_INT (v);
3658                         }
3659                       while (delay_needed-- > 0)
3660                         emit_insn_after (gen_nop (), label);
3661                       break;
3662                     }
3663                 }
3664             }
3665         }
3666     }
3667 }
3668 \f
3669 /* Handle interrupt_handler, exception_handler and nmi_handler function
3670    attributes; arguments as in struct attribute_spec.handler.  */
3671
3672 static tree
3673 handle_int_attribute (tree *node, tree name,
3674                       tree args ATTRIBUTE_UNUSED,
3675                       int flags ATTRIBUTE_UNUSED,
3676                       bool *no_add_attrs)
3677 {
3678   tree x = *node;
3679   if (TREE_CODE (x) == FUNCTION_DECL)
3680     x = TREE_TYPE (x);
3681
3682   if (TREE_CODE (x) != FUNCTION_TYPE)
3683     {
3684       warning (OPT_Wattributes, "%qs attribute only applies to functions",
3685                IDENTIFIER_POINTER (name));
3686       *no_add_attrs = true;
3687     }
3688   else if (funkind (x) != SUBROUTINE)
3689     error ("multiple function type attributes specified");
3690
3691   return NULL_TREE;
3692 }
3693
3694 /* Return 0 if the attributes for two types are incompatible, 1 if they
3695    are compatible, and 2 if they are nearly compatible (which causes a
3696    warning to be generated).  */
3697
3698 static int
3699 bfin_comp_type_attributes (tree type1, tree type2)
3700 {
3701   e_funkind kind1, kind2;
3702
3703   if (TREE_CODE (type1) != FUNCTION_TYPE)
3704     return 1;
3705
3706   kind1 = funkind (type1);
3707   kind2 = funkind (type2);
3708
3709   if (kind1 != kind2)
3710     return 0;
3711   
3712   /*  Check for mismatched modifiers */
3713   if (!lookup_attribute ("nesting", TYPE_ATTRIBUTES (type1))
3714       != !lookup_attribute ("nesting", TYPE_ATTRIBUTES (type2)))
3715     return 0;
3716
3717   if (!lookup_attribute ("saveall", TYPE_ATTRIBUTES (type1))
3718       != !lookup_attribute ("saveall", TYPE_ATTRIBUTES (type2)))
3719     return 0;
3720
3721   if (!lookup_attribute ("kspisusp", TYPE_ATTRIBUTES (type1))
3722       != !lookup_attribute ("kspisusp", TYPE_ATTRIBUTES (type2)))
3723     return 0;
3724
3725   if (!lookup_attribute ("longcall", TYPE_ATTRIBUTES (type1))
3726       != !lookup_attribute ("longcall", TYPE_ATTRIBUTES (type2)))
3727     return 0;
3728
3729   return 1;
3730 }
3731
3732 /* Handle a "longcall" or "shortcall" attribute; arguments as in
3733    struct attribute_spec.handler.  */
3734
3735 static tree
3736 bfin_handle_longcall_attribute (tree *node, tree name, 
3737                                 tree args ATTRIBUTE_UNUSED, 
3738                                 int flags ATTRIBUTE_UNUSED, 
3739                                 bool *no_add_attrs)
3740 {
3741   if (TREE_CODE (*node) != FUNCTION_TYPE
3742       && TREE_CODE (*node) != FIELD_DECL
3743       && TREE_CODE (*node) != TYPE_DECL)
3744     {
3745       warning (OPT_Wattributes, "`%s' attribute only applies to functions",
3746                IDENTIFIER_POINTER (name));
3747       *no_add_attrs = true;
3748     }
3749
3750   if ((strcmp (IDENTIFIER_POINTER (name), "longcall") == 0
3751        && lookup_attribute ("shortcall", TYPE_ATTRIBUTES (*node)))
3752       || (strcmp (IDENTIFIER_POINTER (name), "shortcall") == 0
3753           && lookup_attribute ("longcall", TYPE_ATTRIBUTES (*node))))
3754     {
3755       warning (OPT_Wattributes,
3756                "can't apply both longcall and shortcall attributes to the same function");
3757       *no_add_attrs = true;
3758     }
3759
3760   return NULL_TREE;
3761 }
3762
3763 /* Table of valid machine attributes.  */
3764 const struct attribute_spec bfin_attribute_table[] =
3765 {
3766   /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
3767   { "interrupt_handler", 0, 0, false, true,  true, handle_int_attribute },
3768   { "exception_handler", 0, 0, false, true,  true, handle_int_attribute },
3769   { "nmi_handler", 0, 0, false, true,  true, handle_int_attribute },
3770   { "nesting", 0, 0, false, true,  true, NULL },
3771   { "kspisusp", 0, 0, false, true,  true, NULL },
3772   { "saveall", 0, 0, false, true,  true, NULL },
3773   { "longcall",  0, 0, false, true,  true,  bfin_handle_longcall_attribute },
3774   { "shortcall", 0, 0, false, true,  true,  bfin_handle_longcall_attribute },
3775   { NULL, 0, 0, false, false, false, NULL }
3776 };
3777 \f
3778 /* Implementation of TARGET_ASM_INTEGER.  When using FD-PIC, we need to
3779    tell the assembler to generate pointers to function descriptors in
3780    some cases.  */
3781
3782 static bool
3783 bfin_assemble_integer (rtx value, unsigned int size, int aligned_p)
3784 {
3785   if (TARGET_FDPIC && size == UNITS_PER_WORD)
3786     {
3787       if (GET_CODE (value) == SYMBOL_REF
3788           && SYMBOL_REF_FUNCTION_P (value))
3789         {
3790           fputs ("\t.picptr\tfuncdesc(", asm_out_file);
3791           output_addr_const (asm_out_file, value);
3792           fputs (")\n", asm_out_file);
3793           return true;
3794         }
3795       if (!aligned_p)
3796         {
3797           /* We've set the unaligned SI op to NULL, so we always have to
3798              handle the unaligned case here.  */
3799           assemble_integer_with_op ("\t.4byte\t", value);
3800           return true;
3801         }
3802     }
3803   return default_assemble_integer (value, size, aligned_p);
3804 }
3805 \f
3806 /* Output the assembler code for a thunk function.  THUNK_DECL is the
3807    declaration for the thunk function itself, FUNCTION is the decl for
3808    the target function.  DELTA is an immediate constant offset to be
3809    added to THIS.  If VCALL_OFFSET is nonzero, the word at
3810    *(*this + vcall_offset) should be added to THIS.  */
3811
3812 static void
3813 bfin_output_mi_thunk (FILE *file ATTRIBUTE_UNUSED,
3814                       tree thunk ATTRIBUTE_UNUSED, HOST_WIDE_INT delta,
3815                       HOST_WIDE_INT vcall_offset, tree function)
3816 {
3817   rtx xops[3];
3818   /* The this parameter is passed as the first argument.  */
3819   rtx this = gen_rtx_REG (Pmode, REG_R0);
3820
3821   /* Adjust the this parameter by a fixed constant.  */
3822   if (delta)
3823     {
3824       xops[1] = this;
3825       if (delta >= -64 && delta <= 63)
3826         {
3827           xops[0] = GEN_INT (delta);
3828           output_asm_insn ("%1 += %0;", xops);
3829         }
3830       else if (delta >= -128 && delta < -64)
3831         {
3832           xops[0] = GEN_INT (delta + 64);
3833           output_asm_insn ("%1 += -64; %1 += %0;", xops);
3834         }
3835       else if (delta > 63 && delta <= 126)
3836         {
3837           xops[0] = GEN_INT (delta - 63);
3838           output_asm_insn ("%1 += 63; %1 += %0;", xops);
3839         }
3840       else
3841         {
3842           xops[0] = GEN_INT (delta);
3843           output_asm_insn ("r3.l = %h0; r3.h = %d0; %1 = %1 + r3;", xops);
3844         }
3845     }
3846
3847   /* Adjust the this parameter by a value stored in the vtable.  */
3848   if (vcall_offset)
3849     {
3850       rtx p2tmp = gen_rtx_REG (Pmode, REG_P2);
3851       rtx tmp = gen_rtx_REG (Pmode, REG_R2);
3852
3853       xops[1] = tmp;
3854       xops[2] = p2tmp;
3855       output_asm_insn ("%2 = r0; %2 = [%2];", xops);
3856
3857       /* Adjust the this parameter.  */
3858       xops[0] = gen_rtx_MEM (Pmode, plus_constant (p2tmp, vcall_offset));
3859       if (!memory_operand (xops[0], Pmode))
3860         {
3861           rtx tmp2 = gen_rtx_REG (Pmode, REG_P1);
3862           xops[0] = GEN_INT (vcall_offset);
3863           xops[1] = tmp2;
3864           output_asm_insn ("%h1 = %h0; %d1 = %d0; %2 = %2 + %1", xops);
3865           xops[0] = gen_rtx_MEM (Pmode, p2tmp);
3866         }
3867       xops[2] = this;
3868       output_asm_insn ("%1 = %0; %2 = %2 + %1;", xops);
3869     }
3870
3871   xops[0] = XEXP (DECL_RTL (function), 0);
3872   if (1 || !flag_pic || (*targetm.binds_local_p) (function))
3873     output_asm_insn ("jump.l\t%P0", xops);
3874 }
3875 \f
3876 /* Codes for all the Blackfin builtins.  */
3877 enum bfin_builtins
3878 {
3879   BFIN_BUILTIN_CSYNC,
3880   BFIN_BUILTIN_SSYNC,
3881   BFIN_BUILTIN_COMPOSE_2X16,
3882   BFIN_BUILTIN_EXTRACTLO,
3883   BFIN_BUILTIN_EXTRACTHI,
3884
3885   BFIN_BUILTIN_SSADD_2X16,
3886   BFIN_BUILTIN_SSSUB_2X16,
3887   BFIN_BUILTIN_SSADDSUB_2X16,
3888   BFIN_BUILTIN_SSSUBADD_2X16,
3889   BFIN_BUILTIN_MULT_2X16,
3890   BFIN_BUILTIN_MULTR_2X16,
3891   BFIN_BUILTIN_NEG_2X16,
3892   BFIN_BUILTIN_ABS_2X16,
3893   BFIN_BUILTIN_MIN_2X16,
3894   BFIN_BUILTIN_MAX_2X16,
3895
3896   BFIN_BUILTIN_SSADD_1X16,
3897   BFIN_BUILTIN_SSSUB_1X16,
3898   BFIN_BUILTIN_MULT_1X16,
3899   BFIN_BUILTIN_MULTR_1X16,
3900   BFIN_BUILTIN_NORM_1X16,
3901   BFIN_BUILTIN_NEG_1X16,
3902   BFIN_BUILTIN_ABS_1X16,
3903   BFIN_BUILTIN_MIN_1X16,
3904   BFIN_BUILTIN_MAX_1X16,
3905
3906   BFIN_BUILTIN_DIFFHL_2X16,
3907   BFIN_BUILTIN_DIFFLH_2X16,
3908
3909   BFIN_BUILTIN_SSADD_1X32,
3910   BFIN_BUILTIN_SSSUB_1X32,
3911   BFIN_BUILTIN_NORM_1X32,
3912   BFIN_BUILTIN_NEG_1X32,
3913   BFIN_BUILTIN_MIN_1X32,
3914   BFIN_BUILTIN_MAX_1X32,
3915   BFIN_BUILTIN_MULT_1X32,
3916
3917   BFIN_BUILTIN_MULHISILL,
3918   BFIN_BUILTIN_MULHISILH,
3919   BFIN_BUILTIN_MULHISIHL,
3920   BFIN_BUILTIN_MULHISIHH,
3921
3922   BFIN_BUILTIN_LSHIFT_1X16,
3923   BFIN_BUILTIN_LSHIFT_2X16,
3924   BFIN_BUILTIN_SSASHIFT_1X16,
3925   BFIN_BUILTIN_SSASHIFT_2X16,
3926
3927   BFIN_BUILTIN_CPLX_MUL_16,
3928   BFIN_BUILTIN_CPLX_MAC_16,
3929   BFIN_BUILTIN_CPLX_MSU_16,
3930
3931   BFIN_BUILTIN_MAX
3932 };
3933
3934 #define def_builtin(NAME, TYPE, CODE)                                   \
3935 do {                                                                    \
3936   lang_hooks.builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD,     \
3937                                NULL, NULL_TREE);                        \
3938 } while (0)
3939
3940 /* Set up all builtin functions for this target.  */
3941 static void
3942 bfin_init_builtins (void)
3943 {
3944   tree V2HI_type_node = build_vector_type_for_mode (intHI_type_node, V2HImode);
3945   tree void_ftype_void
3946     = build_function_type (void_type_node, void_list_node);
3947   tree short_ftype_short
3948     = build_function_type_list (short_integer_type_node, short_integer_type_node,
3949                                 NULL_TREE);
3950   tree short_ftype_int_int
3951     = build_function_type_list (short_integer_type_node, integer_type_node,
3952                                 integer_type_node, NULL_TREE);
3953   tree int_ftype_int_int
3954     = build_function_type_list (integer_type_node, integer_type_node,
3955                                 integer_type_node, NULL_TREE);
3956   tree int_ftype_int
3957     = build_function_type_list (integer_type_node, integer_type_node,
3958                                 NULL_TREE);
3959   tree short_ftype_int
3960     = build_function_type_list (short_integer_type_node, integer_type_node,
3961                                 NULL_TREE);
3962   tree int_ftype_v2hi_v2hi
3963     = build_function_type_list (integer_type_node, V2HI_type_node,
3964                                 V2HI_type_node, NULL_TREE);
3965   tree v2hi_ftype_v2hi_v2hi
3966     = build_function_type_list (V2HI_type_node, V2HI_type_node,
3967                                 V2HI_type_node, NULL_TREE);
3968   tree v2hi_ftype_v2hi_v2hi_v2hi
3969     = build_function_type_list (V2HI_type_node, V2HI_type_node,
3970                                 V2HI_type_node, V2HI_type_node, NULL_TREE);
3971   tree v2hi_ftype_int_int
3972     = build_function_type_list (V2HI_type_node, integer_type_node,
3973                                 integer_type_node, NULL_TREE);
3974   tree v2hi_ftype_v2hi_int
3975     = build_function_type_list (V2HI_type_node, V2HI_type_node,
3976                                 integer_type_node, NULL_TREE);
3977   tree int_ftype_short_short
3978     = build_function_type_list (integer_type_node, short_integer_type_node,
3979                                 short_integer_type_node, NULL_TREE);
3980   tree v2hi_ftype_v2hi
3981     = build_function_type_list (V2HI_type_node, V2HI_type_node, NULL_TREE);
3982   tree short_ftype_v2hi
3983     = build_function_type_list (short_integer_type_node, V2HI_type_node,
3984                                 NULL_TREE);
3985
3986   /* Add the remaining MMX insns with somewhat more complicated types.  */
3987   def_builtin ("__builtin_bfin_csync", void_ftype_void, BFIN_BUILTIN_CSYNC);
3988   def_builtin ("__builtin_bfin_ssync", void_ftype_void, BFIN_BUILTIN_SSYNC);
3989
3990   def_builtin ("__builtin_bfin_compose_2x16", v2hi_ftype_int_int,
3991                BFIN_BUILTIN_COMPOSE_2X16);
3992   def_builtin ("__builtin_bfin_extract_hi", short_ftype_v2hi,
3993                BFIN_BUILTIN_EXTRACTHI);
3994   def_builtin ("__builtin_bfin_extract_lo", short_ftype_v2hi,
3995                BFIN_BUILTIN_EXTRACTLO);
3996
3997   def_builtin ("__builtin_bfin_min_fr2x16", v2hi_ftype_v2hi_v2hi,
3998                BFIN_BUILTIN_MIN_2X16);
3999   def_builtin ("__builtin_bfin_max_fr2x16", v2hi_ftype_v2hi_v2hi,
4000                BFIN_BUILTIN_MAX_2X16);
4001
4002   def_builtin ("__builtin_bfin_add_fr2x16", v2hi_ftype_v2hi_v2hi,
4003                BFIN_BUILTIN_SSADD_2X16);
4004   def_builtin ("__builtin_bfin_sub_fr2x16", v2hi_ftype_v2hi_v2hi,
4005                BFIN_BUILTIN_SSSUB_2X16);
4006   def_builtin ("__builtin_bfin_dspaddsubsat", v2hi_ftype_v2hi_v2hi,
4007                BFIN_BUILTIN_SSADDSUB_2X16);
4008   def_builtin ("__builtin_bfin_dspsubaddsat", v2hi_ftype_v2hi_v2hi,
4009                BFIN_BUILTIN_SSSUBADD_2X16);
4010   def_builtin ("__builtin_bfin_mult_fr2x16", v2hi_ftype_v2hi_v2hi,
4011                BFIN_BUILTIN_MULT_2X16);
4012   def_builtin ("__builtin_bfin_multr_fr2x16", v2hi_ftype_v2hi_v2hi,
4013                BFIN_BUILTIN_MULTR_2X16);
4014   def_builtin ("__builtin_bfin_negate_fr2x16", v2hi_ftype_v2hi,
4015                BFIN_BUILTIN_NEG_2X16);
4016   def_builtin ("__builtin_bfin_abs_fr2x16", v2hi_ftype_v2hi,
4017                BFIN_BUILTIN_ABS_2X16);
4018
4019   def_builtin ("__builtin_bfin_add_fr1x16", short_ftype_int_int,
4020                BFIN_BUILTIN_SSADD_1X16);
4021   def_builtin ("__builtin_bfin_sub_fr1x16", short_ftype_int_int,
4022                BFIN_BUILTIN_SSSUB_1X16);
4023   def_builtin ("__builtin_bfin_mult_fr1x16", short_ftype_int_int,
4024                BFIN_BUILTIN_MULT_1X16);
4025   def_builtin ("__builtin_bfin_multr_fr1x16", short_ftype_int_int,
4026                BFIN_BUILTIN_MULTR_1X16);
4027   def_builtin ("__builtin_bfin_negate_fr1x16", short_ftype_short,
4028                BFIN_BUILTIN_NEG_1X16);
4029   def_builtin ("__builtin_bfin_abs_fr1x16", short_ftype_short,
4030                BFIN_BUILTIN_ABS_1X16);
4031   def_builtin ("__builtin_bfin_norm_fr1x16", short_ftype_int,
4032                BFIN_BUILTIN_NORM_1X16);
4033
4034   def_builtin ("__builtin_bfin_diff_hl_fr2x16", short_ftype_v2hi,
4035                BFIN_BUILTIN_DIFFHL_2X16);
4036   def_builtin ("__builtin_bfin_diff_lh_fr2x16", short_ftype_v2hi,
4037                BFIN_BUILTIN_DIFFLH_2X16);
4038
4039   def_builtin ("__builtin_bfin_mulhisill", int_ftype_v2hi_v2hi,
4040                BFIN_BUILTIN_MULHISILL);
4041   def_builtin ("__builtin_bfin_mulhisihl", int_ftype_v2hi_v2hi,
4042                BFIN_BUILTIN_MULHISIHL);
4043   def_builtin ("__builtin_bfin_mulhisilh", int_ftype_v2hi_v2hi,
4044                BFIN_BUILTIN_MULHISILH);
4045   def_builtin ("__builtin_bfin_mulhisihh", int_ftype_v2hi_v2hi,
4046                BFIN_BUILTIN_MULHISIHH);
4047
4048   def_builtin ("__builtin_bfin_add_fr1x32", int_ftype_int_int,
4049                BFIN_BUILTIN_SSADD_1X32);
4050   def_builtin ("__builtin_bfin_sub_fr1x32", int_ftype_int_int,
4051                BFIN_BUILTIN_SSSUB_1X32);
4052   def_builtin ("__builtin_bfin_negate_fr1x32", int_ftype_int,
4053                BFIN_BUILTIN_NEG_1X32);
4054   def_builtin ("__builtin_bfin_norm_fr1x32", short_ftype_int,
4055                BFIN_BUILTIN_NORM_1X32);
4056   def_builtin ("__builtin_bfin_mult_fr1x32", int_ftype_short_short,
4057                BFIN_BUILTIN_MULT_1X32);
4058
4059   /* Shifts.  */
4060   def_builtin ("__builtin_bfin_shl_fr1x16", short_ftype_int_int,
4061                BFIN_BUILTIN_SSASHIFT_1X16);
4062   def_builtin ("__builtin_bfin_shl_fr2x16", v2hi_ftype_v2hi_int,
4063                BFIN_BUILTIN_SSASHIFT_2X16);
4064   def_builtin ("__builtin_bfin_lshl_fr1x16", short_ftype_int_int,
4065                BFIN_BUILTIN_LSHIFT_1X16);
4066   def_builtin ("__builtin_bfin_lshl_fr2x16", v2hi_ftype_v2hi_int,
4067                BFIN_BUILTIN_LSHIFT_2X16);
4068
4069   /* Complex numbers.  */
4070   def_builtin ("__builtin_bfin_cmplx_mul", v2hi_ftype_v2hi_v2hi,
4071                BFIN_BUILTIN_CPLX_MUL_16);
4072   def_builtin ("__builtin_bfin_cmplx_mac", v2hi_ftype_v2hi_v2hi_v2hi,
4073                BFIN_BUILTIN_CPLX_MAC_16);
4074   def_builtin ("__builtin_bfin_cmplx_msu", v2hi_ftype_v2hi_v2hi_v2hi,
4075                BFIN_BUILTIN_CPLX_MSU_16);
4076 }
4077
4078
4079 struct builtin_description
4080 {
4081   const enum insn_code icode;
4082   const char *const name;
4083   const enum bfin_builtins code;
4084   int macflag;
4085 };
4086
4087 static const struct builtin_description bdesc_2arg[] =
4088 {
4089   { CODE_FOR_composev2hi, "__builtin_bfin_compose_2x16", BFIN_BUILTIN_COMPOSE_2X16, -1 },
4090
4091   { CODE_FOR_ssashiftv2hi3, "__builtin_bfin_shl_fr2x16", BFIN_BUILTIN_SSASHIFT_2X16, -1 },
4092   { CODE_FOR_ssashifthi3, "__builtin_bfin_shl_fr1x16", BFIN_BUILTIN_SSASHIFT_1X16, -1 },
4093   { CODE_FOR_lshiftv2hi3, "__builtin_bfin_lshl_fr2x16", BFIN_BUILTIN_LSHIFT_2X16, -1 },
4094   { CODE_FOR_lshifthi3, "__builtin_bfin_lshl_fr1x16", BFIN_BUILTIN_LSHIFT_1X16, -1 },
4095
4096   { CODE_FOR_sminhi3, "__builtin_bfin_min_fr1x16", BFIN_BUILTIN_MIN_1X16, -1 },
4097   { CODE_FOR_smaxhi3, "__builtin_bfin_max_fr1x16", BFIN_BUILTIN_MAX_1X16, -1 },
4098   { CODE_FOR_ssaddhi3, "__builtin_bfin_add_fr1x16", BFIN_BUILTIN_SSADD_1X16, -1 },
4099   { CODE_FOR_sssubhi3, "__builtin_bfin_sub_fr1x16", BFIN_BUILTIN_SSSUB_1X16, -1 },
4100
4101   { CODE_FOR_sminsi3, "__builtin_bfin_min_fr1x32", BFIN_BUILTIN_MIN_1X32, -1 },
4102   { CODE_FOR_smaxsi3, "__builtin_bfin_max_fr1x32", BFIN_BUILTIN_MAX_1X32, -1 },
4103   { CODE_FOR_ssaddsi3, "__builtin_bfin_add_fr1x32", BFIN_BUILTIN_SSADD_1X32, -1 },
4104   { CODE_FOR_sssubsi3, "__builtin_bfin_sub_fr1x32", BFIN_BUILTIN_SSSUB_1X32, -1 },
4105
4106   { CODE_FOR_sminv2hi3, "__builtin_bfin_min_fr2x16", BFIN_BUILTIN_MIN_2X16, -1 },
4107   { CODE_FOR_smaxv2hi3, "__builtin_bfin_max_fr2x16", BFIN_BUILTIN_MAX_2X16, -1 },
4108   { CODE_FOR_ssaddv2hi3, "__builtin_bfin_add_fr2x16", BFIN_BUILTIN_SSADD_2X16, -1 },
4109   { CODE_FOR_sssubv2hi3, "__builtin_bfin_sub_fr2x16", BFIN_BUILTIN_SSSUB_2X16, -1 },
4110   { CODE_FOR_ssaddsubv2hi3, "__builtin_bfin_dspaddsubsat", BFIN_BUILTIN_SSADDSUB_2X16, -1 },
4111   { CODE_FOR_sssubaddv2hi3, "__builtin_bfin_dspsubaddsat", BFIN_BUILTIN_SSSUBADD_2X16, -1 },
4112
4113   { CODE_FOR_flag_mulhisi, "__builtin_bfin_mult_fr1x32", BFIN_BUILTIN_MULT_1X32, MACFLAG_NONE },
4114   { CODE_FOR_flag_mulhi, "__builtin_bfin_mult_fr1x16", BFIN_BUILTIN_MULT_1X16, MACFLAG_T },
4115   { CODE_FOR_flag_mulhi, "__builtin_bfin_multr_fr1x16", BFIN_BUILTIN_MULTR_1X16, MACFLAG_NONE },
4116   { CODE_FOR_flag_mulv2hi, "__builtin_bfin_mult_fr2x16", BFIN_BUILTIN_MULT_2X16, MACFLAG_T },
4117   { CODE_FOR_flag_mulv2hi, "__builtin_bfin_multr_fr2x16", BFIN_BUILTIN_MULTR_2X16, MACFLAG_NONE }
4118 };
4119
4120 static const struct builtin_description bdesc_1arg[] =
4121 {
4122   { CODE_FOR_signbitshi2, "__builtin_bfin_norm_fr1x16", BFIN_BUILTIN_NORM_1X16, 0 },
4123   { CODE_FOR_ssneghi2, "__builtin_bfin_negate_fr1x16", BFIN_BUILTIN_NEG_1X16, 0 },
4124   { CODE_FOR_abshi2, "__builtin_bfin_abs_fr1x16", BFIN_BUILTIN_ABS_1X16, 0 },
4125
4126   { CODE_FOR_signbitssi2, "__builtin_bfin_norm_fr1x32", BFIN_BUILTIN_NORM_1X32, 0 },
4127   { CODE_FOR_ssnegsi2, "__builtin_bfin_negate_fr1x32", BFIN_BUILTIN_NEG_1X32, 0 },
4128
4129   { CODE_FOR_movv2hi_hi_low, "__builtin_bfin_extract_lo", BFIN_BUILTIN_EXTRACTLO, 0 },
4130   { CODE_FOR_movv2hi_hi_high, "__builtin_bfin_extract_hi", BFIN_BUILTIN_EXTRACTHI, 0 },
4131   { CODE_FOR_ssnegv2hi2, "__builtin_bfin_negate_fr2x16", BFIN_BUILTIN_NEG_2X16, 0 },
4132   { CODE_FOR_absv2hi2, "__builtin_bfin_abs_fr2x16", BFIN_BUILTIN_ABS_2X16, 0 }
4133 };
4134
4135 /* Errors in the source file can cause expand_expr to return const0_rtx
4136    where we expect a vector.  To avoid crashing, use one of the vector
4137    clear instructions.  */
4138 static rtx
4139 safe_vector_operand (rtx x, enum machine_mode mode)
4140 {
4141   if (x != const0_rtx)
4142     return x;
4143   x = gen_reg_rtx (SImode);
4144
4145   emit_insn (gen_movsi (x, CONST0_RTX (SImode)));
4146   return gen_lowpart (mode, x);
4147 }
4148
4149 /* Subroutine of bfin_expand_builtin to take care of binop insns.  MACFLAG is -1
4150    if this is a normal binary op, or one of the MACFLAG_xxx constants.  */
4151
4152 static rtx
4153 bfin_expand_binop_builtin (enum insn_code icode, tree arglist, rtx target,
4154                            int macflag)
4155 {
4156   rtx pat;
4157   tree arg0 = TREE_VALUE (arglist);
4158   tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
4159   rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
4160   rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
4161   enum machine_mode op0mode = GET_MODE (op0);
4162   enum machine_mode op1mode = GET_MODE (op1);
4163   enum machine_mode tmode = insn_data[icode].operand[0].mode;
4164   enum machine_mode mode0 = insn_data[icode].operand[1].mode;
4165   enum machine_mode mode1 = insn_data[icode].operand[2].mode;
4166
4167   if (VECTOR_MODE_P (mode0))
4168     op0 = safe_vector_operand (op0, mode0);
4169   if (VECTOR_MODE_P (mode1))
4170     op1 = safe_vector_operand (op1, mode1);
4171
4172   if (! target
4173       || GET_MODE (target) != tmode
4174       || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
4175     target = gen_reg_rtx (tmode);
4176
4177   if ((op0mode == SImode || op0mode == VOIDmode) && mode0 == HImode)
4178     {
4179       op0mode = HImode;
4180       op0 = gen_lowpart (HImode, op0);
4181     }
4182   if ((op1mode == SImode || op1mode == VOIDmode) && mode1 == HImode)
4183     {
4184       op1mode = HImode;
4185       op1 = gen_lowpart (HImode, op1);
4186     }
4187   /* In case the insn wants input operands in modes different from
4188      the result, abort.  */
4189   gcc_assert ((op0mode == mode0 || op0mode == VOIDmode)
4190               && (op1mode == mode1 || op1mode == VOIDmode));
4191
4192   if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
4193     op0 = copy_to_mode_reg (mode0, op0);
4194   if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
4195     op1 = copy_to_mode_reg (mode1, op1);
4196
4197   if (macflag == -1)
4198     pat = GEN_FCN (icode) (target, op0, op1);
4199   else
4200     pat = GEN_FCN (icode) (target, op0, op1, GEN_INT (macflag));
4201   if (! pat)
4202     return 0;
4203
4204   emit_insn (pat);
4205   return target;
4206 }
4207
4208 /* Subroutine of bfin_expand_builtin to take care of unop insns.  */
4209
4210 static rtx
4211 bfin_expand_unop_builtin (enum insn_code icode, tree arglist,
4212                           rtx target)
4213 {
4214   rtx pat;
4215   tree arg0 = TREE_VALUE (arglist);
4216   rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
4217   enum machine_mode op0mode = GET_MODE (op0);
4218   enum machine_mode tmode = insn_data[icode].operand[0].mode;
4219   enum machine_mode mode0 = insn_data[icode].operand[1].mode;
4220
4221   if (! target
4222       || GET_MODE (target) != tmode
4223       || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
4224     target = gen_reg_rtx (tmode);
4225
4226   if (VECTOR_MODE_P (mode0))
4227     op0 = safe_vector_operand (op0, mode0);
4228
4229   if (op0mode == SImode && mode0 == HImode)
4230     {
4231       op0mode = HImode;
4232       op0 = gen_lowpart (HImode, op0);
4233     }
4234   gcc_assert (op0mode == mode0 || op0mode == VOIDmode);
4235
4236   if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
4237     op0 = copy_to_mode_reg (mode0, op0);
4238
4239   pat = GEN_FCN (icode) (target, op0);
4240   if (! pat)
4241     return 0;
4242   emit_insn (pat);
4243   return target;
4244 }
4245
4246 /* Expand an expression EXP that calls a built-in function,
4247    with result going to TARGET if that's convenient
4248    (and in mode MODE if that's convenient).
4249    SUBTARGET may be used as the target for computing one of EXP's operands.
4250    IGNORE is nonzero if the value is to be ignored.  */
4251
4252 static rtx
4253 bfin_expand_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
4254                      rtx subtarget ATTRIBUTE_UNUSED,
4255                      enum machine_mode mode ATTRIBUTE_UNUSED,
4256                      int ignore ATTRIBUTE_UNUSED)
4257 {
4258   size_t i;
4259   enum insn_code icode;
4260   const struct builtin_description *d;
4261   tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
4262   tree arglist = TREE_OPERAND (exp, 1);
4263   unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
4264   tree arg0, arg1, arg2;
4265   rtx op0, op1, op2, accvec, pat, tmp1, tmp2;
4266   enum machine_mode tmode, mode0;
4267
4268   switch (fcode)
4269     {
4270     case BFIN_BUILTIN_CSYNC:
4271       emit_insn (gen_csync ());
4272       return 0;
4273     case BFIN_BUILTIN_SSYNC:
4274       emit_insn (gen_ssync ());
4275       return 0;
4276
4277     case BFIN_BUILTIN_DIFFHL_2X16:
4278     case BFIN_BUILTIN_DIFFLH_2X16:
4279       arg0 = TREE_VALUE (arglist);
4280       op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
4281       icode = (fcode == BFIN_BUILTIN_DIFFHL_2X16
4282                ? CODE_FOR_subhilov2hi3 : CODE_FOR_sublohiv2hi3);
4283       tmode = insn_data[icode].operand[0].mode;
4284       mode0 = insn_data[icode].operand[1].mode;
4285
4286       if (! target
4287           || GET_MODE (target) != tmode
4288           || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
4289         target = gen_reg_rtx (tmode);
4290
4291       if (VECTOR_MODE_P (mode0))
4292         op0 = safe_vector_operand (op0, mode0);
4293
4294       if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
4295         op0 = copy_to_mode_reg (mode0, op0);
4296
4297       pat = GEN_FCN (icode) (target, op0, op0);
4298       if (! pat)
4299         return 0;
4300       emit_insn (pat);
4301       return target;
4302
4303     case BFIN_BUILTIN_CPLX_MUL_16:
4304       arg0 = TREE_VALUE (arglist);
4305       arg1 = TREE_VALUE (TREE_CHAIN (arglist));
4306       op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
4307       op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
4308       accvec = gen_reg_rtx (V2PDImode);
4309
4310       if (! target
4311           || GET_MODE (target) != V2HImode
4312           || ! (*insn_data[icode].operand[0].predicate) (target, V2HImode))
4313         target = gen_reg_rtx (tmode);
4314       if (! register_operand (op0, GET_MODE (op0)))
4315         op0 = copy_to_mode_reg (GET_MODE (op0), op0);
4316       if (! register_operand (op1, GET_MODE (op1)))
4317         op1 = copy_to_mode_reg (GET_MODE (op1), op1);
4318
4319       emit_insn (gen_flag_macinit1v2hi_parts (accvec, op0, op1, const0_rtx,
4320                                               const0_rtx, const0_rtx,
4321                                               const1_rtx, GEN_INT (MACFLAG_NONE)));
4322       emit_insn (gen_flag_macv2hi_parts (target, op0, op1, const1_rtx,
4323                                          const1_rtx, const1_rtx,
4324                                          const0_rtx, accvec, const1_rtx, const0_rtx,
4325                                          GEN_INT (MACFLAG_NONE), accvec));
4326
4327       return target;
4328
4329     case BFIN_BUILTIN_CPLX_MAC_16:
4330     case BFIN_BUILTIN_CPLX_MSU_16:
4331       arg0 = TREE_VALUE (arglist);
4332       arg1 = TREE_VALUE (TREE_CHAIN (arglist));
4333       arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
4334       op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
4335       op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
4336       op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
4337       accvec = gen_reg_rtx (V2PDImode);
4338
4339       if (! target
4340           || GET_MODE (target) != V2HImode
4341           || ! (*insn_data[icode].operand[0].predicate) (target, V2HImode))
4342         target = gen_reg_rtx (tmode);
4343       if (! register_operand (op0, GET_MODE (op0)))
4344         op0 = copy_to_mode_reg (GET_MODE (op0), op0);
4345       if (! register_operand (op1, GET_MODE (op1)))
4346         op1 = copy_to_mode_reg (GET_MODE (op1), op1);
4347
4348       tmp1 = gen_reg_rtx (SImode);
4349       tmp2 = gen_reg_rtx (SImode);
4350       emit_insn (gen_ashlsi3 (tmp1, gen_lowpart (SImode, op2), GEN_INT (16)));
4351       emit_move_insn (tmp2, gen_lowpart (SImode, op2));
4352       emit_insn (gen_movstricthi_1 (gen_lowpart (HImode, tmp2), const0_rtx));
4353       emit_insn (gen_load_accumulator_pair (accvec, tmp1, tmp2));
4354       emit_insn (gen_flag_macv2hi_parts_acconly (accvec, op0, op1, const0_rtx,
4355                                                  const0_rtx, const0_rtx,
4356                                                  const1_rtx, accvec, const0_rtx,
4357                                                  const0_rtx,
4358                                                  GEN_INT (MACFLAG_W32)));
4359       tmp1 = (fcode == BFIN_BUILTIN_CPLX_MAC_16 ? const1_rtx : const0_rtx);
4360       tmp2 = (fcode == BFIN_BUILTIN_CPLX_MAC_16 ? const0_rtx : const1_rtx);
4361       emit_insn (gen_flag_macv2hi_parts (target, op0, op1, const1_rtx,
4362                                          const1_rtx, const1_rtx,
4363                                          const0_rtx, accvec, tmp1, tmp2,
4364                                          GEN_INT (MACFLAG_NONE), accvec));
4365
4366       return target;
4367
4368     default:
4369       break;
4370     }
4371
4372   for (i = 0, d = bdesc_2arg; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
4373     if (d->code == fcode)
4374       return bfin_expand_binop_builtin (d->icode, arglist, target,
4375                                         d->macflag);
4376
4377   for (i = 0, d = bdesc_1arg; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
4378     if (d->code == fcode)
4379       return bfin_expand_unop_builtin (d->icode, arglist, target);
4380
4381   gcc_unreachable ();
4382 }
4383 \f
4384 #undef TARGET_INIT_BUILTINS
4385 #define TARGET_INIT_BUILTINS bfin_init_builtins
4386
4387 #undef TARGET_EXPAND_BUILTIN
4388 #define TARGET_EXPAND_BUILTIN bfin_expand_builtin
4389
4390 #undef TARGET_ASM_GLOBALIZE_LABEL
4391 #define TARGET_ASM_GLOBALIZE_LABEL bfin_globalize_label 
4392
4393 #undef TARGET_ASM_FILE_START
4394 #define TARGET_ASM_FILE_START output_file_start
4395
4396 #undef TARGET_ATTRIBUTE_TABLE
4397 #define TARGET_ATTRIBUTE_TABLE bfin_attribute_table
4398
4399 #undef TARGET_COMP_TYPE_ATTRIBUTES
4400 #define TARGET_COMP_TYPE_ATTRIBUTES bfin_comp_type_attributes
4401
4402 #undef TARGET_RTX_COSTS
4403 #define TARGET_RTX_COSTS bfin_rtx_costs
4404
4405 #undef  TARGET_ADDRESS_COST
4406 #define TARGET_ADDRESS_COST bfin_address_cost
4407
4408 #undef TARGET_ASM_INTERNAL_LABEL
4409 #define TARGET_ASM_INTERNAL_LABEL bfin_internal_label
4410
4411 #undef  TARGET_ASM_INTEGER
4412 #define TARGET_ASM_INTEGER bfin_assemble_integer
4413
4414 #undef TARGET_MACHINE_DEPENDENT_REORG
4415 #define TARGET_MACHINE_DEPENDENT_REORG bfin_reorg
4416
4417 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
4418 #define TARGET_FUNCTION_OK_FOR_SIBCALL bfin_function_ok_for_sibcall
4419
4420 #undef TARGET_ASM_OUTPUT_MI_THUNK
4421 #define TARGET_ASM_OUTPUT_MI_THUNK bfin_output_mi_thunk
4422 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
4423 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_tree_hwi_hwi_tree_true
4424
4425 #undef TARGET_SCHED_ADJUST_COST
4426 #define TARGET_SCHED_ADJUST_COST bfin_adjust_cost
4427
4428 #undef TARGET_PROMOTE_PROTOTYPES
4429 #define TARGET_PROMOTE_PROTOTYPES hook_bool_tree_true
4430 #undef TARGET_PROMOTE_FUNCTION_ARGS
4431 #define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true
4432 #undef TARGET_PROMOTE_FUNCTION_RETURN
4433 #define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true
4434
4435 #undef TARGET_ARG_PARTIAL_BYTES
4436 #define TARGET_ARG_PARTIAL_BYTES bfin_arg_partial_bytes
4437
4438 #undef TARGET_PASS_BY_REFERENCE
4439 #define TARGET_PASS_BY_REFERENCE bfin_pass_by_reference
4440
4441 #undef TARGET_SETUP_INCOMING_VARARGS
4442 #define TARGET_SETUP_INCOMING_VARARGS setup_incoming_varargs
4443
4444 #undef TARGET_STRUCT_VALUE_RTX
4445 #define TARGET_STRUCT_VALUE_RTX bfin_struct_value_rtx
4446
4447 #undef TARGET_VECTOR_MODE_SUPPORTED_P
4448 #define TARGET_VECTOR_MODE_SUPPORTED_P bfin_vector_mode_supported_p
4449
4450 #undef TARGET_HANDLE_OPTION
4451 #define TARGET_HANDLE_OPTION bfin_handle_option
4452
4453 #undef TARGET_DEFAULT_TARGET_FLAGS
4454 #define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
4455
4456 #undef TARGET_SECONDARY_RELOAD
4457 #define TARGET_SECONDARY_RELOAD bfin_secondary_reload
4458
4459 #undef TARGET_DELEGITIMIZE_ADDRESS
4460 #define TARGET_DELEGITIMIZE_ADDRESS bfin_delegitimize_address
4461
4462 struct gcc_target targetm = TARGET_INITIALIZER;