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