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