OSDN Git Service

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