OSDN Git Service

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