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