1 /* The Blackfin code generation auxiliary output file.
2 Copyright (C) 2005, 2006 Free Software Foundation, Inc.
3 Contributed by Analog Devices.
5 This file is part of GCC.
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.
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.
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. */
24 #include "coretypes.h"
28 #include "hard-reg-set.h"
30 #include "insn-config.h"
31 #include "insn-codes.h"
32 #include "conditions.h"
33 #include "insn-flags.h"
35 #include "insn-attr.h"
42 #include "target-def.h"
48 #include "integrate.h"
50 #include "langhooks.h"
51 #include "bfin-protos.h"
55 /* Test and compare insns in bfin.md store the information needed to
56 generate branch and scc insns here. */
57 rtx bfin_compare_op0, bfin_compare_op1;
59 /* RTX for condition code flag register and RETS register */
60 extern GTY(()) rtx bfin_cc_rtx;
61 extern GTY(()) rtx bfin_rets_rtx;
62 rtx bfin_cc_rtx, bfin_rets_rtx;
64 int max_arg_registers = 0;
66 /* Arrays used when emitting register names. */
67 const char *short_reg_names[] = SHORT_REGISTER_NAMES;
68 const char *high_reg_names[] = HIGH_REGISTER_NAMES;
69 const char *dregs_pair_names[] = DREGS_PAIR_NAMES;
70 const char *byte_reg_names[] = BYTE_REGISTER_NAMES;
72 static int arg_regs[] = FUNCTION_ARG_REGISTERS;
74 /* Nonzero if -mshared-library-id was given. */
75 static int bfin_lib_id_given;
78 bfin_globalize_label (FILE *stream, const char *name)
80 fputs (".global ", stream);
81 assemble_name (stream, name);
87 output_file_start (void)
89 FILE *file = asm_out_file;
92 fprintf (file, ".file \"%s\";\n", input_filename);
94 for (i = 0; arg_regs[i] >= 0; i++)
96 max_arg_registers = i; /* how many arg reg used */
99 /* Called early in the compilation to conditionally modify
100 fixed_regs/call_used_regs. */
103 conditional_register_usage (void)
105 /* initialize condition code flag register rtx */
106 bfin_cc_rtx = gen_rtx_REG (BImode, REG_CC);
107 bfin_rets_rtx = gen_rtx_REG (Pmode, REG_RETS);
110 /* Examine machine-dependent attributes of function type FUNTYPE and return its
111 type. See the definition of E_FUNKIND. */
113 static e_funkind funkind (tree funtype)
115 tree attrs = TYPE_ATTRIBUTES (funtype);
116 if (lookup_attribute ("interrupt_handler", attrs))
117 return INTERRUPT_HANDLER;
118 else if (lookup_attribute ("exception_handler", attrs))
119 return EXCPT_HANDLER;
120 else if (lookup_attribute ("nmi_handler", attrs))
126 /* Legitimize PIC addresses. If the address is already position-independent,
127 we return ORIG. Newly generated position-independent addresses go into a
128 reg. This is REG if nonzero, otherwise we allocate register(s) as
129 necessary. PICREG is the register holding the pointer to the PIC offset
133 legitimize_pic_address (rtx orig, rtx reg, rtx picreg)
138 if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == LABEL_REF)
140 if (GET_CODE (addr) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (addr))
147 if (TARGET_ID_SHARED_LIBRARY)
148 unspec = UNSPEC_MOVE_PIC;
149 else if (GET_CODE (addr) == SYMBOL_REF
150 && SYMBOL_REF_FUNCTION_P (addr))
152 unspec = UNSPEC_FUNCDESC_GOT17M4;
156 unspec = UNSPEC_MOVE_FDPIC;
161 gcc_assert (!no_new_pseudos);
162 reg = gen_reg_rtx (Pmode);
165 tmp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), unspec);
166 new = gen_const_mem (Pmode, gen_rtx_PLUS (Pmode, picreg, tmp));
168 emit_move_insn (reg, new);
170 if (picreg == pic_offset_table_rtx)
171 current_function_uses_pic_offset_table = 1;
175 else if (GET_CODE (addr) == CONST || GET_CODE (addr) == PLUS)
179 if (GET_CODE (addr) == CONST)
181 addr = XEXP (addr, 0);
182 gcc_assert (GET_CODE (addr) == PLUS);
185 if (XEXP (addr, 0) == picreg)
190 gcc_assert (!no_new_pseudos);
191 reg = gen_reg_rtx (Pmode);
194 base = legitimize_pic_address (XEXP (addr, 0), reg, picreg);
195 addr = legitimize_pic_address (XEXP (addr, 1),
196 base == reg ? NULL_RTX : reg,
199 if (GET_CODE (addr) == CONST_INT)
201 gcc_assert (! reload_in_progress && ! reload_completed);
202 addr = force_reg (Pmode, addr);
205 if (GET_CODE (addr) == PLUS && CONSTANT_P (XEXP (addr, 1)))
207 base = gen_rtx_PLUS (Pmode, base, XEXP (addr, 0));
208 addr = XEXP (addr, 1);
211 return gen_rtx_PLUS (Pmode, base, addr);
217 /* Stack frame layout. */
219 /* Compute the number of DREGS to save with a push_multiple operation.
220 This could include registers that aren't modified in the function,
221 since push_multiple only takes a range of registers.
222 If IS_INTHANDLER, then everything that is live must be saved, even
223 if normally call-clobbered. */
226 n_dregs_to_save (bool is_inthandler)
230 for (i = REG_R0; i <= REG_R7; i++)
232 if (regs_ever_live[i] && (is_inthandler || ! call_used_regs[i]))
233 return REG_R7 - i + 1;
235 if (current_function_calls_eh_return)
240 unsigned test = EH_RETURN_DATA_REGNO (j);
241 if (test == INVALID_REGNUM)
244 return REG_R7 - i + 1;
252 /* Like n_dregs_to_save, but compute number of PREGS to save. */
255 n_pregs_to_save (bool is_inthandler)
259 for (i = REG_P0; i <= REG_P5; i++)
260 if ((regs_ever_live[i] && (is_inthandler || ! call_used_regs[i]))
262 && i == PIC_OFFSET_TABLE_REGNUM
263 && (current_function_uses_pic_offset_table
264 || (TARGET_ID_SHARED_LIBRARY && ! current_function_is_leaf))))
265 return REG_P5 - i + 1;
269 /* Determine if we are going to save the frame pointer in the prologue. */
272 must_save_fp_p (void)
274 return frame_pointer_needed || regs_ever_live[REG_FP];
278 stack_frame_needed_p (void)
280 /* EH return puts a new return address into the frame using an
281 address relative to the frame pointer. */
282 if (current_function_calls_eh_return)
284 return frame_pointer_needed;
287 /* Emit code to save registers in the prologue. SAVEALL is nonzero if we
288 must save all registers; this is used for interrupt handlers.
289 SPREG contains (reg:SI REG_SP). IS_INTHANDLER is true if we're doing
290 this for an interrupt (or exception) handler. */
293 expand_prologue_reg_save (rtx spreg, int saveall, bool is_inthandler)
295 int ndregs = saveall ? 8 : n_dregs_to_save (is_inthandler);
296 int npregs = saveall ? 6 : n_pregs_to_save (is_inthandler);
297 int dregno = REG_R7 + 1 - ndregs;
298 int pregno = REG_P5 + 1 - npregs;
299 int total = ndregs + npregs;
306 val = GEN_INT (-total * 4);
307 pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total + 2));
308 XVECEXP (pat, 0, 0) = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, val),
309 UNSPEC_PUSH_MULTIPLE);
310 XVECEXP (pat, 0, total + 1) = gen_rtx_SET (VOIDmode, spreg,
311 gen_rtx_PLUS (Pmode, spreg,
313 RTX_FRAME_RELATED_P (XVECEXP (pat, 0, total + 1)) = 1;
314 for (i = 0; i < total; i++)
316 rtx memref = gen_rtx_MEM (word_mode,
317 gen_rtx_PLUS (Pmode, spreg,
318 GEN_INT (- i * 4 - 4)));
322 subpat = gen_rtx_SET (VOIDmode, memref, gen_rtx_REG (word_mode,
328 subpat = gen_rtx_SET (VOIDmode, memref, gen_rtx_REG (word_mode,
332 XVECEXP (pat, 0, i + 1) = subpat;
333 RTX_FRAME_RELATED_P (subpat) = 1;
335 insn = emit_insn (pat);
336 RTX_FRAME_RELATED_P (insn) = 1;
339 /* Emit code to restore registers in the epilogue. SAVEALL is nonzero if we
340 must save all registers; this is used for interrupt handlers.
341 SPREG contains (reg:SI REG_SP). IS_INTHANDLER is true if we're doing
342 this for an interrupt (or exception) handler. */
345 expand_epilogue_reg_restore (rtx spreg, bool saveall, bool is_inthandler)
347 int ndregs = saveall ? 8 : n_dregs_to_save (is_inthandler);
348 int npregs = saveall ? 6 : n_pregs_to_save (is_inthandler);
349 int total = ndregs + npregs;
356 pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total + 1));
357 XVECEXP (pat, 0, 0) = gen_rtx_SET (VOIDmode, spreg,
358 gen_rtx_PLUS (Pmode, spreg,
359 GEN_INT (total * 4)));
366 for (i = 0; i < total; i++)
369 ? gen_rtx_PLUS (Pmode, spreg, GEN_INT (i * 4))
371 rtx memref = gen_rtx_MEM (word_mode, addr);
374 XVECEXP (pat, 0, i + 1)
375 = gen_rtx_SET (VOIDmode, gen_rtx_REG (word_mode, regno), memref);
384 insn = emit_insn (pat);
385 RTX_FRAME_RELATED_P (insn) = 1;
388 /* Perform any needed actions needed for a function that is receiving a
389 variable number of arguments.
393 MODE and TYPE are the mode and type of the current parameter.
395 PRETEND_SIZE is a variable that should be set to the amount of stack
396 that must be pushed by the prolog to pretend that our caller pushed
399 Normally, this macro will push all remaining incoming registers on the
400 stack and set PRETEND_SIZE to the length of the registers pushed.
403 - VDSP C compiler manual (our ABI) says that a variable args function
404 should save the R0, R1 and R2 registers in the stack.
405 - The caller will always leave space on the stack for the
406 arguments that are passed in registers, so we dont have
407 to leave any extra space.
408 - now, the vastart pointer can access all arguments from the stack. */
411 setup_incoming_varargs (CUMULATIVE_ARGS *cum,
412 enum machine_mode mode ATTRIBUTE_UNUSED,
413 tree type ATTRIBUTE_UNUSED, int *pretend_size,
422 /* The move for named arguments will be generated automatically by the
423 compiler. We need to generate the move rtx for the unnamed arguments
424 if they are in the first 3 words. We assume at least 1 named argument
425 exists, so we never generate [ARGP] = R0 here. */
427 for (i = cum->words + 1; i < max_arg_registers; i++)
429 mem = gen_rtx_MEM (Pmode,
430 plus_constant (arg_pointer_rtx, (i * UNITS_PER_WORD)));
431 emit_move_insn (mem, gen_rtx_REG (Pmode, i));
437 /* Value should be nonzero if functions must have frame pointers.
438 Zero means the frame pointer need not be set up (and parms may
439 be accessed via the stack pointer) in functions that seem suitable. */
442 bfin_frame_pointer_required (void)
444 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
446 if (fkind != SUBROUTINE)
449 /* We turn on -fomit-frame-pointer if -momit-leaf-frame-pointer is used,
450 so we have to override it for non-leaf functions. */
451 if (TARGET_OMIT_LEAF_FRAME_POINTER && ! current_function_is_leaf)
457 /* Return the number of registers pushed during the prologue. */
460 n_regs_saved_by_prologue (void)
462 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
463 bool is_inthandler = fkind != SUBROUTINE;
464 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
465 bool all = (lookup_attribute ("saveall", attrs) != NULL_TREE
466 || (is_inthandler && !current_function_is_leaf));
467 int ndregs = all ? 8 : n_dregs_to_save (is_inthandler);
468 int npregs = all ? 6 : n_pregs_to_save (is_inthandler);
469 int n = ndregs + npregs;
471 if (all || stack_frame_needed_p ())
472 /* We use a LINK instruction in this case. */
476 if (must_save_fp_p ())
478 if (! current_function_is_leaf)
482 if (fkind != SUBROUTINE)
486 /* Increment once for ASTAT. */
490 if (lookup_attribute ("nesting", attrs))
493 for (i = REG_P7 + 1; i < REG_CC; i++)
496 || (!leaf_function_p () && call_used_regs[i]))
497 n += i == REG_A0 || i == REG_A1 ? 2 : 1;
502 /* Return the offset between two registers, one to be eliminated, and the other
503 its replacement, at the start of a routine. */
506 bfin_initial_elimination_offset (int from, int to)
508 HOST_WIDE_INT offset = 0;
510 if (from == ARG_POINTER_REGNUM)
511 offset = n_regs_saved_by_prologue () * 4;
513 if (to == STACK_POINTER_REGNUM)
515 if (current_function_outgoing_args_size >= FIXED_STACK_AREA)
516 offset += current_function_outgoing_args_size;
517 else if (current_function_outgoing_args_size)
518 offset += FIXED_STACK_AREA;
520 offset += get_frame_size ();
526 /* Emit code to load a constant CONSTANT into register REG; setting
527 RTX_FRAME_RELATED_P on all insns we generate if RELATED is true.
528 Make sure that the insns we generate need not be split. */
531 frame_related_constant_load (rtx reg, HOST_WIDE_INT constant, bool related)
534 rtx cst = GEN_INT (constant);
536 if (constant >= -32768 && constant < 65536)
537 insn = emit_move_insn (reg, cst);
540 /* We don't call split_load_immediate here, since dwarf2out.c can get
541 confused about some of the more clever sequences it can generate. */
542 insn = emit_insn (gen_movsi_high (reg, cst));
544 RTX_FRAME_RELATED_P (insn) = 1;
545 insn = emit_insn (gen_movsi_low (reg, reg, cst));
548 RTX_FRAME_RELATED_P (insn) = 1;
551 /* Generate efficient code to add a value to the frame pointer. We
552 can use P1 as a scratch register. Set RTX_FRAME_RELATED_P on the
553 generated insns if FRAME is nonzero. */
556 add_to_sp (rtx spreg, HOST_WIDE_INT value, int frame)
561 /* Choose whether to use a sequence using a temporary register, or
562 a sequence with multiple adds. We can add a signed 7 bit value
563 in one instruction. */
564 if (value > 120 || value < -120)
566 rtx tmpreg = gen_rtx_REG (SImode, REG_P1);
570 frame_related_constant_load (tmpreg, value, TRUE);
573 insn = emit_move_insn (tmpreg, GEN_INT (value));
575 RTX_FRAME_RELATED_P (insn) = 1;
578 insn = emit_insn (gen_addsi3 (spreg, spreg, tmpreg));
580 RTX_FRAME_RELATED_P (insn) = 1;
591 /* We could use -62, but that would leave the stack unaligned, so
595 insn = emit_insn (gen_addsi3 (spreg, spreg, GEN_INT (size)));
597 RTX_FRAME_RELATED_P (insn) = 1;
603 /* Generate a LINK insn for a frame sized FRAME_SIZE. If this constant
604 is too large, generate a sequence of insns that has the same effect.
605 SPREG contains (reg:SI REG_SP). */
608 emit_link_insn (rtx spreg, HOST_WIDE_INT frame_size)
610 HOST_WIDE_INT link_size = frame_size;
614 if (link_size > 262140)
617 /* Use a LINK insn with as big a constant as possible, then subtract
618 any remaining size from the SP. */
619 insn = emit_insn (gen_link (GEN_INT (-8 - link_size)));
620 RTX_FRAME_RELATED_P (insn) = 1;
622 for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
624 rtx set = XVECEXP (PATTERN (insn), 0, i);
625 gcc_assert (GET_CODE (set) == SET);
626 RTX_FRAME_RELATED_P (set) = 1;
629 frame_size -= link_size;
633 /* Must use a call-clobbered PREG that isn't the static chain. */
634 rtx tmpreg = gen_rtx_REG (Pmode, REG_P1);
636 frame_related_constant_load (tmpreg, -frame_size, TRUE);
637 insn = emit_insn (gen_addsi3 (spreg, spreg, tmpreg));
638 RTX_FRAME_RELATED_P (insn) = 1;
642 /* Return the number of bytes we must reserve for outgoing arguments
643 in the current function's stack frame. */
648 if (current_function_outgoing_args_size)
650 if (current_function_outgoing_args_size >= FIXED_STACK_AREA)
651 return current_function_outgoing_args_size;
653 return FIXED_STACK_AREA;
658 /* Save RETS and FP, and allocate a stack frame. ALL is true if the
659 function must save all its registers (true only for certain interrupt
663 do_link (rtx spreg, HOST_WIDE_INT frame_size, bool all)
665 frame_size += arg_area_size ();
667 if (all || stack_frame_needed_p ()
668 || (must_save_fp_p () && ! current_function_is_leaf))
669 emit_link_insn (spreg, frame_size);
672 if (! current_function_is_leaf)
674 rtx pat = gen_movsi (gen_rtx_MEM (Pmode,
675 gen_rtx_PRE_DEC (Pmode, spreg)),
677 rtx insn = emit_insn (pat);
678 RTX_FRAME_RELATED_P (insn) = 1;
680 if (must_save_fp_p ())
682 rtx pat = gen_movsi (gen_rtx_MEM (Pmode,
683 gen_rtx_PRE_DEC (Pmode, spreg)),
684 gen_rtx_REG (Pmode, REG_FP));
685 rtx insn = emit_insn (pat);
686 RTX_FRAME_RELATED_P (insn) = 1;
688 add_to_sp (spreg, -frame_size, 1);
692 /* Like do_link, but used for epilogues to deallocate the stack frame. */
695 do_unlink (rtx spreg, HOST_WIDE_INT frame_size, bool all)
697 frame_size += arg_area_size ();
699 if (all || stack_frame_needed_p ())
700 emit_insn (gen_unlink ());
703 rtx postinc = gen_rtx_MEM (Pmode, gen_rtx_POST_INC (Pmode, spreg));
705 add_to_sp (spreg, frame_size, 0);
706 if (must_save_fp_p ())
708 rtx fpreg = gen_rtx_REG (Pmode, REG_FP);
709 emit_move_insn (fpreg, postinc);
710 emit_insn (gen_rtx_USE (VOIDmode, fpreg));
712 if (! current_function_is_leaf)
714 emit_move_insn (bfin_rets_rtx, postinc);
715 emit_insn (gen_rtx_USE (VOIDmode, bfin_rets_rtx));
720 /* Generate a prologue suitable for a function of kind FKIND. This is
721 called for interrupt and exception handler prologues.
722 SPREG contains (reg:SI REG_SP). */
725 expand_interrupt_handler_prologue (rtx spreg, e_funkind fkind)
728 HOST_WIDE_INT frame_size = get_frame_size ();
729 rtx predec1 = gen_rtx_PRE_DEC (SImode, spreg);
730 rtx predec = gen_rtx_MEM (SImode, predec1);
732 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
733 bool all = lookup_attribute ("saveall", attrs) != NULL_TREE;
734 tree kspisusp = lookup_attribute ("kspisusp", attrs);
738 insn = emit_move_insn (spreg, gen_rtx_REG (Pmode, REG_USP));
739 RTX_FRAME_RELATED_P (insn) = 1;
742 /* We need space on the stack in case we need to save the argument
744 if (fkind == EXCPT_HANDLER)
746 insn = emit_insn (gen_addsi3 (spreg, spreg, GEN_INT (-12)));
747 RTX_FRAME_RELATED_P (insn) = 1;
750 insn = emit_move_insn (predec, gen_rtx_REG (SImode, REG_ASTAT));
751 RTX_FRAME_RELATED_P (insn) = 1;
753 /* If we're calling other functions, they won't save their call-clobbered
754 registers, so we must save everything here. */
755 if (!current_function_is_leaf)
757 expand_prologue_reg_save (spreg, all, true);
759 for (i = REG_P7 + 1; i < REG_CC; i++)
762 || (!leaf_function_p () && call_used_regs[i]))
764 if (i == REG_A0 || i == REG_A1)
765 insn = emit_move_insn (gen_rtx_MEM (PDImode, predec1),
766 gen_rtx_REG (PDImode, i));
768 insn = emit_move_insn (predec, gen_rtx_REG (SImode, i));
769 RTX_FRAME_RELATED_P (insn) = 1;
772 if (lookup_attribute ("nesting", attrs))
774 rtx srcreg = gen_rtx_REG (Pmode, (fkind == EXCPT_HANDLER ? REG_RETX
775 : fkind == NMI_HANDLER ? REG_RETN
777 insn = emit_move_insn (predec, srcreg);
778 RTX_FRAME_RELATED_P (insn) = 1;
781 do_link (spreg, frame_size, all);
783 if (fkind == EXCPT_HANDLER)
785 rtx r0reg = gen_rtx_REG (SImode, REG_R0);
786 rtx r1reg = gen_rtx_REG (SImode, REG_R1);
787 rtx r2reg = gen_rtx_REG (SImode, REG_R2);
790 insn = emit_move_insn (r0reg, gen_rtx_REG (SImode, REG_SEQSTAT));
791 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx,
793 insn = emit_insn (gen_ashrsi3 (r0reg, r0reg, GEN_INT (26)));
794 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx,
796 insn = emit_insn (gen_ashlsi3 (r0reg, r0reg, GEN_INT (26)));
797 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx,
799 insn = emit_move_insn (r1reg, spreg);
800 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx,
802 insn = emit_move_insn (r2reg, gen_rtx_REG (Pmode, REG_FP));
803 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx,
805 insn = emit_insn (gen_addsi3 (r2reg, r2reg, GEN_INT (8)));
806 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx,
811 /* Generate an epilogue suitable for a function of kind FKIND. This is
812 called for interrupt and exception handler epilogues.
813 SPREG contains (reg:SI REG_SP). */
816 expand_interrupt_handler_epilogue (rtx spreg, e_funkind fkind)
819 rtx postinc1 = gen_rtx_POST_INC (SImode, spreg);
820 rtx postinc = gen_rtx_MEM (SImode, postinc1);
821 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
822 bool all = lookup_attribute ("saveall", attrs) != NULL_TREE;
824 /* A slightly crude technique to stop flow from trying to delete "dead"
826 MEM_VOLATILE_P (postinc) = 1;
828 do_unlink (spreg, get_frame_size (), all);
830 if (lookup_attribute ("nesting", attrs))
832 rtx srcreg = gen_rtx_REG (Pmode, (fkind == EXCPT_HANDLER ? REG_RETX
833 : fkind == NMI_HANDLER ? REG_RETN
835 emit_move_insn (srcreg, postinc);
838 /* If we're calling other functions, they won't save their call-clobbered
839 registers, so we must save (and restore) everything here. */
840 if (!current_function_is_leaf)
843 for (i = REG_CC - 1; i > REG_P7; i--)
846 || (!leaf_function_p () && call_used_regs[i]))
848 if (i == REG_A0 || i == REG_A1)
850 rtx mem = gen_rtx_MEM (PDImode, postinc1);
851 MEM_VOLATILE_P (mem) = 1;
852 emit_move_insn (gen_rtx_REG (PDImode, i), mem);
855 emit_move_insn (gen_rtx_REG (SImode, i), postinc);
858 expand_epilogue_reg_restore (spreg, all, true);
860 emit_move_insn (gen_rtx_REG (SImode, REG_ASTAT), postinc);
862 /* Deallocate any space we left on the stack in case we needed to save the
863 argument registers. */
864 if (fkind == EXCPT_HANDLER)
865 emit_insn (gen_addsi3 (spreg, spreg, GEN_INT (12)));
867 emit_jump_insn (gen_return_internal (GEN_INT (fkind)));
870 /* Used while emitting the prologue to generate code to load the correct value
871 into the PIC register, which is passed in DEST. */
874 bfin_load_pic_reg (rtx dest)
876 struct cgraph_local_info *i = NULL;
879 if (flag_unit_at_a_time)
880 i = cgraph_local_info (current_function_decl);
882 /* Functions local to the translation unit don't need to reload the
883 pic reg, since the caller always passes a usable one. */
885 return pic_offset_table_rtx;
887 if (bfin_lib_id_given)
888 addr = plus_constant (pic_offset_table_rtx, -4 - bfin_library_id * 4);
890 addr = gen_rtx_PLUS (Pmode, pic_offset_table_rtx,
891 gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx),
892 UNSPEC_LIBRARY_OFFSET));
893 insn = emit_insn (gen_movsi (dest, gen_rtx_MEM (Pmode, addr)));
894 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx, NULL);
898 /* Generate RTL for the prologue of the current function. */
901 bfin_expand_prologue (void)
904 HOST_WIDE_INT frame_size = get_frame_size ();
905 rtx spreg = gen_rtx_REG (Pmode, REG_SP);
906 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
907 rtx pic_reg_loaded = NULL_RTX;
909 if (fkind != SUBROUTINE)
911 expand_interrupt_handler_prologue (spreg, fkind);
915 if (current_function_limit_stack)
918 = bfin_initial_elimination_offset (ARG_POINTER_REGNUM,
919 STACK_POINTER_REGNUM);
920 rtx lim = stack_limit_rtx;
922 if (GET_CODE (lim) == SYMBOL_REF)
924 rtx p2reg = gen_rtx_REG (Pmode, REG_P2);
925 if (TARGET_ID_SHARED_LIBRARY)
927 rtx p1reg = gen_rtx_REG (Pmode, REG_P1);
929 pic_reg_loaded = bfin_load_pic_reg (p2reg);
930 val = legitimize_pic_address (stack_limit_rtx, p1reg,
932 emit_move_insn (p1reg, val);
933 frame_related_constant_load (p2reg, offset, FALSE);
934 emit_insn (gen_addsi3 (p2reg, p2reg, p1reg));
939 rtx limit = plus_constant (stack_limit_rtx, offset);
940 emit_move_insn (p2reg, limit);
944 emit_insn (gen_compare_lt (bfin_cc_rtx, spreg, lim));
945 emit_insn (gen_trapifcc ());
947 expand_prologue_reg_save (spreg, 0, false);
949 do_link (spreg, frame_size, false);
951 if (TARGET_ID_SHARED_LIBRARY
952 && (current_function_uses_pic_offset_table
953 || !current_function_is_leaf))
954 bfin_load_pic_reg (pic_offset_table_rtx);
957 /* Generate RTL for the epilogue of the current function. NEED_RETURN is zero
958 if this is for a sibcall. EH_RETURN is nonzero if we're expanding an
959 eh_return pattern. */
962 bfin_expand_epilogue (int need_return, int eh_return)
964 rtx spreg = gen_rtx_REG (Pmode, REG_SP);
965 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
967 if (fkind != SUBROUTINE)
969 expand_interrupt_handler_epilogue (spreg, fkind);
973 do_unlink (spreg, get_frame_size (), false);
975 expand_epilogue_reg_restore (spreg, false, false);
977 /* Omit the return insn if this is for a sibcall. */
982 emit_insn (gen_addsi3 (spreg, spreg, gen_rtx_REG (Pmode, REG_P2)));
984 emit_jump_insn (gen_return_internal (GEN_INT (SUBROUTINE)));
987 /* Return nonzero if register OLD_REG can be renamed to register NEW_REG. */
990 bfin_hard_regno_rename_ok (unsigned int old_reg ATTRIBUTE_UNUSED,
991 unsigned int new_reg)
993 /* Interrupt functions can only use registers that have already been
994 saved by the prologue, even if they would normally be
997 if (funkind (TREE_TYPE (current_function_decl)) != SUBROUTINE
998 && !regs_ever_live[new_reg])
1004 /* Return the value of the return address for the frame COUNT steps up
1005 from the current frame, after the prologue.
1006 We punt for everything but the current frame by returning const0_rtx. */
1009 bfin_return_addr_rtx (int count)
1014 return get_hard_reg_initial_val (Pmode, REG_RETS);
1017 /* Try machine-dependent ways of modifying an illegitimate address X
1018 to be legitimate. If we find one, return the new, valid address,
1019 otherwise return NULL_RTX.
1021 OLDX is the address as it was before break_out_memory_refs was called.
1022 In some cases it is useful to look at this to decide what needs to be done.
1024 MODE is the mode of the memory reference. */
1027 legitimize_address (rtx x ATTRIBUTE_UNUSED, rtx oldx ATTRIBUTE_UNUSED,
1028 enum machine_mode mode ATTRIBUTE_UNUSED)
1033 /* This predicate is used to compute the length of a load/store insn.
1034 OP is a MEM rtx, we return nonzero if its addressing mode requires a
1035 32 bit instruction. */
1038 effective_address_32bit_p (rtx op, enum machine_mode mode)
1040 HOST_WIDE_INT offset;
1042 mode = GET_MODE (op);
1045 if (GET_CODE (op) != PLUS)
1047 gcc_assert (REG_P (op) || GET_CODE (op) == POST_INC
1048 || GET_CODE (op) == PRE_DEC || GET_CODE (op) == POST_DEC);
1052 offset = INTVAL (XEXP (op, 1));
1054 /* All byte loads use a 16 bit offset. */
1055 if (GET_MODE_SIZE (mode) == 1)
1058 if (GET_MODE_SIZE (mode) == 4)
1060 /* Frame pointer relative loads can use a negative offset, all others
1061 are restricted to a small positive one. */
1062 if (XEXP (op, 0) == frame_pointer_rtx)
1063 return offset < -128 || offset > 60;
1064 return offset < 0 || offset > 60;
1067 /* Must be HImode now. */
1068 return offset < 0 || offset > 30;
1071 /* Returns true if X is a memory reference using an I register. */
1073 bfin_dsp_memref_p (rtx x)
1078 if (GET_CODE (x) == POST_INC || GET_CODE (x) == PRE_INC
1079 || GET_CODE (x) == POST_DEC || GET_CODE (x) == PRE_DEC)
1084 /* Return cost of the memory address ADDR.
1085 All addressing modes are equally cheap on the Blackfin. */
1088 bfin_address_cost (rtx addr ATTRIBUTE_UNUSED)
1093 /* Subroutine of print_operand; used to print a memory reference X to FILE. */
1096 print_address_operand (FILE *file, rtx x)
1098 switch (GET_CODE (x))
1101 output_address (XEXP (x, 0));
1102 fprintf (file, "+");
1103 output_address (XEXP (x, 1));
1107 fprintf (file, "--");
1108 output_address (XEXP (x, 0));
1111 output_address (XEXP (x, 0));
1112 fprintf (file, "++");
1115 output_address (XEXP (x, 0));
1116 fprintf (file, "--");
1120 gcc_assert (GET_CODE (x) != MEM);
1121 print_operand (file, x, 0);
1126 /* Adding intp DImode support by Tony
1132 print_operand (FILE *file, rtx x, char code)
1134 enum machine_mode mode = GET_MODE (x);
1139 switch (GET_CODE (x))
1142 fprintf (file, "e");
1145 fprintf (file, "ne");
1148 fprintf (file, "g");
1151 fprintf (file, "l");
1154 fprintf (file, "ge");
1157 fprintf (file, "le");
1160 fprintf (file, "g");
1163 fprintf (file, "l");
1166 fprintf (file, "ge");
1169 fprintf (file, "le");
1172 output_operand_lossage ("invalid %%j value");
1176 case 'J': /* reverse logic */
1177 switch (GET_CODE(x))
1180 fprintf (file, "ne");
1183 fprintf (file, "e");
1186 fprintf (file, "le");
1189 fprintf (file, "ge");
1192 fprintf (file, "l");
1195 fprintf (file, "g");
1198 fprintf (file, "le");
1201 fprintf (file, "ge");
1204 fprintf (file, "l");
1207 fprintf (file, "g");
1210 output_operand_lossage ("invalid %%J value");
1215 switch (GET_CODE (x))
1220 gcc_assert (REGNO (x) < 32);
1221 fprintf (file, "%s", short_reg_names[REGNO (x)]);
1222 /*fprintf (file, "\n%d\n ", REGNO (x));*/
1225 else if (code == 'd')
1227 gcc_assert (REGNO (x) < 32);
1228 fprintf (file, "%s", high_reg_names[REGNO (x)]);
1231 else if (code == 'w')
1233 gcc_assert (REGNO (x) == REG_A0 || REGNO (x) == REG_A1);
1234 fprintf (file, "%s.w", reg_names[REGNO (x)]);
1236 else if (code == 'x')
1238 gcc_assert (REGNO (x) == REG_A0 || REGNO (x) == REG_A1);
1239 fprintf (file, "%s.x", reg_names[REGNO (x)]);
1241 else if (code == 'D')
1243 fprintf (file, "%s", dregs_pair_names[REGNO (x)]);
1245 else if (code == 'H')
1247 gcc_assert (mode == DImode || mode == DFmode);
1248 gcc_assert (REG_P (x));
1249 fprintf (file, "%s", reg_names[REGNO (x) + 1]);
1251 else if (code == 'T')
1253 gcc_assert (D_REGNO_P (REGNO (x)));
1254 fprintf (file, "%s", byte_reg_names[REGNO (x)]);
1257 fprintf (file, "%s", reg_names[REGNO (x)]);
1263 print_address_operand (file, x);
1275 fputs ("(FU)", file);
1278 fputs ("(T)", file);
1281 fputs ("(TFU)", file);
1284 fputs ("(W32)", file);
1287 fputs ("(IS)", file);
1290 fputs ("(IU)", file);
1293 fputs ("(IH)", file);
1296 fputs ("(M)", file);
1299 fputs ("(ISS2)", file);
1302 fputs ("(S2RND)", file);
1309 else if (code == 'b')
1311 if (INTVAL (x) == 0)
1313 else if (INTVAL (x) == 1)
1319 /* Moves to half registers with d or h modifiers always use unsigned
1321 else if (code == 'd')
1322 x = GEN_INT ((INTVAL (x) >> 16) & 0xffff);
1323 else if (code == 'h')
1324 x = GEN_INT (INTVAL (x) & 0xffff);
1325 else if (code == 'X')
1326 x = GEN_INT (exact_log2 (0xffffffff & INTVAL (x)));
1327 else if (code == 'Y')
1328 x = GEN_INT (exact_log2 (0xffffffff & ~INTVAL (x)));
1329 else if (code == 'Z')
1330 /* Used for LINK insns. */
1331 x = GEN_INT (-8 - INTVAL (x));
1336 output_addr_const (file, x);
1340 output_operand_lossage ("invalid const_double operand");
1344 switch (XINT (x, 1))
1346 case UNSPEC_MOVE_PIC:
1347 output_addr_const (file, XVECEXP (x, 0, 0));
1348 fprintf (file, "@GOT");
1351 case UNSPEC_MOVE_FDPIC:
1352 output_addr_const (file, XVECEXP (x, 0, 0));
1353 fprintf (file, "@GOT17M4");
1356 case UNSPEC_FUNCDESC_GOT17M4:
1357 output_addr_const (file, XVECEXP (x, 0, 0));
1358 fprintf (file, "@FUNCDESC_GOT17M4");
1361 case UNSPEC_LIBRARY_OFFSET:
1362 fprintf (file, "_current_shared_library_p5_offset_");
1371 output_addr_const (file, x);
1376 /* Argument support functions. */
1378 /* Initialize a variable CUM of type CUMULATIVE_ARGS
1379 for a call to a function whose data type is FNTYPE.
1380 For a library call, FNTYPE is 0.
1381 VDSP C Compiler manual, our ABI says that
1382 first 3 words of arguments will use R0, R1 and R2.
1386 init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype,
1387 rtx libname ATTRIBUTE_UNUSED)
1389 static CUMULATIVE_ARGS zero_cum;
1393 /* Set up the number of registers to use for passing arguments. */
1395 cum->nregs = max_arg_registers;
1396 cum->arg_regs = arg_regs;
1398 cum->call_cookie = CALL_NORMAL;
1399 /* Check for a longcall attribute. */
1400 if (fntype && lookup_attribute ("shortcall", TYPE_ATTRIBUTES (fntype)))
1401 cum->call_cookie |= CALL_SHORT;
1402 else if (fntype && lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype)))
1403 cum->call_cookie |= CALL_LONG;
1408 /* Update the data in CUM to advance over an argument
1409 of mode MODE and data type TYPE.
1410 (TYPE is null for libcalls where that information may not be available.) */
1413 function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
1414 int named ATTRIBUTE_UNUSED)
1416 int count, bytes, words;
1418 bytes = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
1419 words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
1421 cum->words += words;
1422 cum->nregs -= words;
1424 if (cum->nregs <= 0)
1427 cum->arg_regs = NULL;
1431 for (count = 1; count <= words; count++)
1438 /* Define where to put the arguments to a function.
1439 Value is zero to push the argument on the stack,
1440 or a hard register in which to store the argument.
1442 MODE is the argument's machine mode.
1443 TYPE is the data type of the argument (as a tree).
1444 This is null for libcalls where that information may
1446 CUM is a variable of type CUMULATIVE_ARGS which gives info about
1447 the preceding args and about the function being called.
1448 NAMED is nonzero if this argument is a named parameter
1449 (otherwise it is an extra parameter matching an ellipsis). */
1452 function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
1453 int named ATTRIBUTE_UNUSED)
1456 = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
1458 if (mode == VOIDmode)
1459 /* Compute operand 2 of the call insn. */
1460 return GEN_INT (cum->call_cookie);
1466 return gen_rtx_REG (mode, *(cum->arg_regs));
1471 /* For an arg passed partly in registers and partly in memory,
1472 this is the number of bytes passed in registers.
1473 For args passed entirely in registers or entirely in memory, zero.
1475 Refer VDSP C Compiler manual, our ABI.
1476 First 3 words are in registers. So, if a an argument is larger
1477 than the registers available, it will span the register and
1481 bfin_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode,
1482 tree type ATTRIBUTE_UNUSED,
1483 bool named ATTRIBUTE_UNUSED)
1486 = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
1487 int bytes_left = cum->nregs * UNITS_PER_WORD;
1492 if (bytes_left == 0)
1494 if (bytes > bytes_left)
1499 /* Variable sized types are passed by reference. */
1502 bfin_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
1503 enum machine_mode mode ATTRIBUTE_UNUSED,
1504 tree type, bool named ATTRIBUTE_UNUSED)
1506 return type && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST;
1509 /* Decide whether a type should be returned in memory (true)
1510 or in a register (false). This is called by the macro
1511 RETURN_IN_MEMORY. */
1514 bfin_return_in_memory (tree type)
1516 int size = int_size_in_bytes (type);
1517 return size > 2 * UNITS_PER_WORD || size == -1;
1520 /* Register in which address to store a structure value
1521 is passed to a function. */
1523 bfin_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
1524 int incoming ATTRIBUTE_UNUSED)
1526 return gen_rtx_REG (Pmode, REG_P0);
1529 /* Return true when register may be used to pass function parameters. */
1532 function_arg_regno_p (int n)
1535 for (i = 0; arg_regs[i] != -1; i++)
1536 if (n == arg_regs[i])
1541 /* Returns 1 if OP contains a symbol reference */
1544 symbolic_reference_mentioned_p (rtx op)
1546 register const char *fmt;
1549 if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF)
1552 fmt = GET_RTX_FORMAT (GET_CODE (op));
1553 for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
1559 for (j = XVECLEN (op, i) - 1; j >= 0; j--)
1560 if (symbolic_reference_mentioned_p (XVECEXP (op, i, j)))
1564 else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i)))
1571 /* Decide whether we can make a sibling call to a function. DECL is the
1572 declaration of the function being targeted by the call and EXP is the
1573 CALL_EXPR representing the call. */
1576 bfin_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED,
1577 tree exp ATTRIBUTE_UNUSED)
1579 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
1580 return fkind == SUBROUTINE;
1583 /* Emit RTL insns to initialize the variable parts of a trampoline at
1584 TRAMP. FNADDR is an RTX for the address of the function's pure
1585 code. CXT is an RTX for the static chain value for the function. */
1588 initialize_trampoline (tramp, fnaddr, cxt)
1589 rtx tramp, fnaddr, cxt;
1591 rtx t1 = copy_to_reg (fnaddr);
1592 rtx t2 = copy_to_reg (cxt);
1598 rtx a = memory_address (Pmode, plus_constant (tramp, 8));
1599 addr = memory_address (Pmode, tramp);
1600 emit_move_insn (gen_rtx_MEM (SImode, addr), a);
1604 addr = memory_address (Pmode, plus_constant (tramp, i + 2));
1605 emit_move_insn (gen_rtx_MEM (HImode, addr), gen_lowpart (HImode, t1));
1606 emit_insn (gen_ashrsi3 (t1, t1, GEN_INT (16)));
1607 addr = memory_address (Pmode, plus_constant (tramp, i + 6));
1608 emit_move_insn (gen_rtx_MEM (HImode, addr), gen_lowpart (HImode, t1));
1610 addr = memory_address (Pmode, plus_constant (tramp, i + 10));
1611 emit_move_insn (gen_rtx_MEM (HImode, addr), gen_lowpart (HImode, t2));
1612 emit_insn (gen_ashrsi3 (t2, t2, GEN_INT (16)));
1613 addr = memory_address (Pmode, plus_constant (tramp, i + 14));
1614 emit_move_insn (gen_rtx_MEM (HImode, addr), gen_lowpart (HImode, t2));
1617 /* Emit insns to move operands[1] into operands[0]. */
1620 emit_pic_move (rtx *operands, enum machine_mode mode ATTRIBUTE_UNUSED)
1622 rtx temp = reload_in_progress ? operands[0] : gen_reg_rtx (Pmode);
1624 gcc_assert (!TARGET_FDPIC || !(reload_in_progress || reload_completed));
1625 if (GET_CODE (operands[0]) == MEM && SYMBOLIC_CONST (operands[1]))
1626 operands[1] = force_reg (SImode, operands[1]);
1628 operands[1] = legitimize_pic_address (operands[1], temp,
1629 TARGET_FDPIC ? OUR_FDPIC_REG
1630 : pic_offset_table_rtx);
1633 /* Expand a move operation in mode MODE. The operands are in OPERANDS. */
1636 expand_move (rtx *operands, enum machine_mode mode)
1638 rtx op = operands[1];
1639 if ((TARGET_ID_SHARED_LIBRARY || TARGET_FDPIC)
1640 && SYMBOLIC_CONST (op))
1641 emit_pic_move (operands, mode);
1642 /* Don't generate memory->memory or constant->memory moves, go through a
1644 else if ((reload_in_progress | reload_completed) == 0
1645 && GET_CODE (operands[0]) == MEM
1646 && GET_CODE (operands[1]) != REG)
1647 operands[1] = force_reg (mode, operands[1]);
1650 /* Split one or more DImode RTL references into pairs of SImode
1651 references. The RTL can be REG, offsettable MEM, integer constant, or
1652 CONST_DOUBLE. "operands" is a pointer to an array of DImode RTL to
1653 split and "num" is its length. lo_half and hi_half are output arrays
1654 that parallel "operands". */
1657 split_di (rtx operands[], int num, rtx lo_half[], rtx hi_half[])
1661 rtx op = operands[num];
1663 /* simplify_subreg refuse to split volatile memory addresses,
1664 but we still have to handle it. */
1665 if (GET_CODE (op) == MEM)
1667 lo_half[num] = adjust_address (op, SImode, 0);
1668 hi_half[num] = adjust_address (op, SImode, 4);
1672 lo_half[num] = simplify_gen_subreg (SImode, op,
1673 GET_MODE (op) == VOIDmode
1674 ? DImode : GET_MODE (op), 0);
1675 hi_half[num] = simplify_gen_subreg (SImode, op,
1676 GET_MODE (op) == VOIDmode
1677 ? DImode : GET_MODE (op), 4);
1683 bfin_longcall_p (rtx op, int call_cookie)
1685 gcc_assert (GET_CODE (op) == SYMBOL_REF);
1686 if (call_cookie & CALL_SHORT)
1688 if (call_cookie & CALL_LONG)
1690 if (TARGET_LONG_CALLS)
1695 /* Expand a call instruction. FNADDR is the call target, RETVAL the return value.
1696 COOKIE is a CONST_INT holding the call_cookie prepared init_cumulative_args.
1697 SIBCALL is nonzero if this is a sibling call. */
1700 bfin_expand_call (rtx retval, rtx fnaddr, rtx callarg1, rtx cookie, int sibcall)
1702 rtx use = NULL, call;
1703 rtx callee = XEXP (fnaddr, 0);
1704 int nelts = 2 + !!sibcall;
1706 rtx picreg = get_hard_reg_initial_val (SImode, FDPIC_REGNO);
1709 /* In an untyped call, we can get NULL for operand 2. */
1710 if (cookie == NULL_RTX)
1711 cookie = const0_rtx;
1713 /* Static functions and indirect calls don't need the pic register. */
1714 if (!TARGET_FDPIC && flag_pic
1715 && GET_CODE (callee) == SYMBOL_REF
1716 && !SYMBOL_REF_LOCAL_P (callee))
1717 use_reg (&use, pic_offset_table_rtx);
1721 if (GET_CODE (callee) != SYMBOL_REF
1722 || bfin_longcall_p (callee, INTVAL (cookie)))
1725 if (! address_operand (addr, Pmode))
1726 addr = force_reg (Pmode, addr);
1728 fnaddr = gen_reg_rtx (SImode);
1729 emit_insn (gen_load_funcdescsi (fnaddr, addr));
1730 fnaddr = gen_rtx_MEM (Pmode, fnaddr);
1732 picreg = gen_reg_rtx (SImode);
1733 emit_insn (gen_load_funcdescsi (picreg,
1734 plus_constant (addr, 4)));
1739 else if ((!register_no_elim_operand (callee, Pmode)
1740 && GET_CODE (callee) != SYMBOL_REF)
1741 || (GET_CODE (callee) == SYMBOL_REF
1743 || bfin_longcall_p (callee, INTVAL (cookie)))))
1745 callee = copy_to_mode_reg (Pmode, callee);
1746 fnaddr = gen_rtx_MEM (Pmode, callee);
1748 call = gen_rtx_CALL (VOIDmode, fnaddr, callarg1);
1751 call = gen_rtx_SET (VOIDmode, retval, call);
1753 pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (nelts));
1755 XVECEXP (pat, 0, n++) = call;
1757 XVECEXP (pat, 0, n++) = gen_rtx_USE (VOIDmode, picreg);
1758 XVECEXP (pat, 0, n++) = gen_rtx_USE (VOIDmode, cookie);
1760 XVECEXP (pat, 0, n++) = gen_rtx_RETURN (VOIDmode);
1761 call = emit_call_insn (pat);
1763 CALL_INSN_FUNCTION_USAGE (call) = use;
1766 /* Return 1 if hard register REGNO can hold a value of machine-mode MODE. */
1769 hard_regno_mode_ok (int regno, enum machine_mode mode)
1771 /* Allow only dregs to store value of mode HI or QI */
1772 enum reg_class class = REGNO_REG_CLASS (regno);
1777 if (mode == V2HImode)
1778 return D_REGNO_P (regno);
1779 if (class == CCREGS)
1780 return mode == BImode;
1781 if (mode == PDImode || mode == V2PDImode)
1782 return regno == REG_A0 || regno == REG_A1;
1784 && TEST_HARD_REG_BIT (reg_class_contents[PROLOGUE_REGS], regno))
1787 return TEST_HARD_REG_BIT (reg_class_contents[MOST_REGS], regno);
1790 /* Implements target hook vector_mode_supported_p. */
1793 bfin_vector_mode_supported_p (enum machine_mode mode)
1795 return mode == V2HImode;
1798 /* Return the cost of moving data from a register in class CLASS1 to
1799 one in class CLASS2. A cost of 2 is the default. */
1802 bfin_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
1803 enum reg_class class1, enum reg_class class2)
1805 /* These need secondary reloads, so they're more expensive. */
1806 if ((class1 == CCREGS && class2 != DREGS)
1807 || (class1 != DREGS && class2 == CCREGS))
1810 /* If optimizing for size, always prefer reg-reg over reg-memory moves. */
1814 /* There are some stalls involved when moving from a DREG to a different
1815 class reg, and using the value in one of the following instructions.
1816 Attempt to model this by slightly discouraging such moves. */
1817 if (class1 == DREGS && class2 != DREGS)
1823 /* Return the cost of moving data of mode M between a
1824 register and memory. A value of 2 is the default; this cost is
1825 relative to those in `REGISTER_MOVE_COST'.
1827 ??? In theory L1 memory has single-cycle latency. We should add a switch
1828 that tells the compiler whether we expect to use only L1 memory for the
1829 program; it'll make the costs more accurate. */
1832 bfin_memory_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
1833 enum reg_class class,
1834 int in ATTRIBUTE_UNUSED)
1836 /* Make memory accesses slightly more expensive than any register-register
1837 move. Also, penalize non-DP registers, since they need secondary
1838 reloads to load and store. */
1839 if (! reg_class_subset_p (class, DPREGS))
1845 /* Inform reload about cases where moving X with a mode MODE to a register in
1846 CLASS requires an extra scratch register. Return the class needed for the
1847 scratch register. */
1849 static enum reg_class
1850 bfin_secondary_reload (bool in_p, rtx x, enum reg_class class,
1851 enum machine_mode mode, secondary_reload_info *sri)
1853 /* If we have HImode or QImode, we can only use DREGS as secondary registers;
1854 in most other cases we can also use PREGS. */
1855 enum reg_class default_class = GET_MODE_SIZE (mode) >= 4 ? DPREGS : DREGS;
1856 enum reg_class x_class = NO_REGS;
1857 enum rtx_code code = GET_CODE (x);
1860 x = SUBREG_REG (x), code = GET_CODE (x);
1863 int regno = REGNO (x);
1864 if (regno >= FIRST_PSEUDO_REGISTER)
1865 regno = reg_renumber[regno];
1870 x_class = REGNO_REG_CLASS (regno);
1873 /* We can be asked to reload (plus (FP) (large_constant)) into a DREG.
1874 This happens as a side effect of register elimination, and we need
1875 a scratch register to do it. */
1876 if (fp_plus_const_operand (x, mode))
1878 rtx op2 = XEXP (x, 1);
1879 int large_constant_p = ! CONST_7BIT_IMM_P (INTVAL (op2));
1881 if (class == PREGS || class == PREGS_CLOBBERED)
1883 /* If destination is a DREG, we can do this without a scratch register
1884 if the constant is valid for an add instruction. */
1885 if ((class == DREGS || class == DPREGS)
1886 && ! large_constant_p)
1888 /* Reloading to anything other than a DREG? Use a PREG scratch
1890 sri->icode = CODE_FOR_reload_insi;
1894 /* Data can usually be moved freely between registers of most classes.
1895 AREGS are an exception; they can only move to or from another register
1896 in AREGS or one in DREGS. They can also be assigned the constant 0. */
1897 if (x_class == AREGS)
1898 return class == DREGS || class == AREGS ? NO_REGS : DREGS;
1902 if (x != const0_rtx && x_class != DREGS)
1908 /* CCREGS can only be moved from/to DREGS. */
1909 if (class == CCREGS && x_class != DREGS)
1911 if (x_class == CCREGS && class != DREGS)
1914 /* All registers other than AREGS can load arbitrary constants. The only
1915 case that remains is MEM. */
1917 if (! reg_class_subset_p (class, default_class))
1918 return default_class;
1922 /* Implement TARGET_HANDLE_OPTION. */
1925 bfin_handle_option (size_t code, const char *arg, int value)
1929 case OPT_mshared_library_id_:
1930 if (value > MAX_LIBRARY_ID)
1931 error ("-mshared-library-id=%s is not between 0 and %d",
1932 arg, MAX_LIBRARY_ID);
1933 bfin_lib_id_given = 1;
1941 /* Implement the macro OVERRIDE_OPTIONS. */
1944 override_options (void)
1946 if (TARGET_OMIT_LEAF_FRAME_POINTER)
1947 flag_omit_frame_pointer = 1;
1949 /* Library identification */
1950 if (bfin_lib_id_given && ! TARGET_ID_SHARED_LIBRARY)
1951 error ("-mshared-library-id= specified without -mid-shared-library");
1953 if (TARGET_ID_SHARED_LIBRARY && flag_pic == 0)
1956 if (TARGET_ID_SHARED_LIBRARY && TARGET_FDPIC)
1957 error ("ID shared libraries and FD-PIC mode can't be used together.");
1959 /* There is no single unaligned SI op for PIC code. Sometimes we
1960 need to use ".4byte" and sometimes we need to use ".picptr".
1961 See bfin_assemble_integer for details. */
1963 targetm.asm_out.unaligned_op.si = 0;
1965 /* Silently turn off flag_pic if not doing FDPIC or ID shared libraries,
1966 since we don't support it and it'll just break. */
1967 if (flag_pic && !TARGET_FDPIC && !TARGET_ID_SHARED_LIBRARY)
1970 flag_schedule_insns = 0;
1973 /* Return the destination address of BRANCH.
1974 We need to use this instead of get_attr_length, because the
1975 cbranch_with_nops pattern conservatively sets its length to 6, and
1976 we still prefer to use shorter sequences. */
1979 branch_dest (rtx branch)
1983 rtx pat = PATTERN (branch);
1984 if (GET_CODE (pat) == PARALLEL)
1985 pat = XVECEXP (pat, 0, 0);
1986 dest = SET_SRC (pat);
1987 if (GET_CODE (dest) == IF_THEN_ELSE)
1988 dest = XEXP (dest, 1);
1989 dest = XEXP (dest, 0);
1990 dest_uid = INSN_UID (dest);
1991 return INSN_ADDRESSES (dest_uid);
1994 /* Return nonzero if INSN is annotated with a REG_BR_PROB note that indicates
1995 it's a branch that's predicted taken. */
1998 cbranch_predicted_taken_p (rtx insn)
2000 rtx x = find_reg_note (insn, REG_BR_PROB, 0);
2004 int pred_val = INTVAL (XEXP (x, 0));
2006 return pred_val >= REG_BR_PROB_BASE / 2;
2012 /* Templates for use by asm_conditional_branch. */
2014 static const char *ccbranch_templates[][3] = {
2015 { "if !cc jump %3;", "if cc jump 4 (bp); jump.s %3;", "if cc jump 6 (bp); jump.l %3;" },
2016 { "if cc jump %3;", "if !cc jump 4 (bp); jump.s %3;", "if !cc jump 6 (bp); jump.l %3;" },
2017 { "if !cc jump %3 (bp);", "if cc jump 4; jump.s %3;", "if cc jump 6; jump.l %3;" },
2018 { "if cc jump %3 (bp);", "if !cc jump 4; jump.s %3;", "if !cc jump 6; jump.l %3;" },
2021 /* Output INSN, which is a conditional branch instruction with operands
2024 We deal with the various forms of conditional branches that can be generated
2025 by bfin_reorg to prevent the hardware from doing speculative loads, by
2026 - emitting a sufficient number of nops, if N_NOPS is nonzero, or
2027 - always emitting the branch as predicted taken, if PREDICT_TAKEN is true.
2028 Either of these is only necessary if the branch is short, otherwise the
2029 template we use ends in an unconditional jump which flushes the pipeline
2033 asm_conditional_branch (rtx insn, rtx *operands, int n_nops, int predict_taken)
2035 int offset = branch_dest (insn) - INSN_ADDRESSES (INSN_UID (insn));
2036 /* Note : offset for instructions like if cc jmp; jump.[sl] offset
2037 is to be taken from start of if cc rather than jump.
2038 Range for jump.s is (-4094, 4096) instead of (-4096, 4094)
2040 int len = (offset >= -1024 && offset <= 1022 ? 0
2041 : offset >= -4094 && offset <= 4096 ? 1
2043 int bp = predict_taken && len == 0 ? 1 : cbranch_predicted_taken_p (insn);
2044 int idx = (bp << 1) | (GET_CODE (operands[0]) == EQ ? BRF : BRT);
2045 output_asm_insn (ccbranch_templates[idx][len], operands);
2046 gcc_assert (n_nops == 0 || !bp);
2048 while (n_nops-- > 0)
2049 output_asm_insn ("nop;", NULL);
2052 /* Emit rtl for a comparison operation CMP in mode MODE. Operands have been
2053 stored in bfin_compare_op0 and bfin_compare_op1 already. */
2056 bfin_gen_compare (rtx cmp, enum machine_mode mode ATTRIBUTE_UNUSED)
2058 enum rtx_code code1, code2;
2059 rtx op0 = bfin_compare_op0, op1 = bfin_compare_op1;
2060 rtx tem = bfin_cc_rtx;
2061 enum rtx_code code = GET_CODE (cmp);
2063 /* If we have a BImode input, then we already have a compare result, and
2064 do not need to emit another comparison. */
2065 if (GET_MODE (op0) == BImode)
2067 gcc_assert ((code == NE || code == EQ) && op1 == const0_rtx);
2068 tem = op0, code2 = code;
2073 /* bfin has these conditions */
2083 code1 = reverse_condition (code);
2087 emit_insn (gen_rtx_SET (BImode, tem,
2088 gen_rtx_fmt_ee (code1, BImode, op0, op1)));
2091 return gen_rtx_fmt_ee (code2, BImode, tem, CONST0_RTX (BImode));
2094 /* Return nonzero iff C has exactly one bit set if it is interpreted
2095 as a 32 bit constant. */
2098 log2constp (unsigned HOST_WIDE_INT c)
2101 return c != 0 && (c & (c-1)) == 0;
2104 /* Returns the number of consecutive least significant zeros in the binary
2105 representation of *V.
2106 We modify *V to contain the original value arithmetically shifted right by
2107 the number of zeroes. */
2110 shiftr_zero (HOST_WIDE_INT *v)
2112 unsigned HOST_WIDE_INT tmp = *v;
2113 unsigned HOST_WIDE_INT sgn;
2119 sgn = tmp & ((unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1));
2120 while ((tmp & 0x1) == 0 && n <= 32)
2122 tmp = (tmp >> 1) | sgn;
2129 /* After reload, split the load of an immediate constant. OPERANDS are the
2130 operands of the movsi_insn pattern which we are splitting. We return
2131 nonzero if we emitted a sequence to load the constant, zero if we emitted
2132 nothing because we want to use the splitter's default sequence. */
2135 split_load_immediate (rtx operands[])
2137 HOST_WIDE_INT val = INTVAL (operands[1]);
2139 HOST_WIDE_INT shifted = val;
2140 HOST_WIDE_INT shifted_compl = ~val;
2141 int num_zero = shiftr_zero (&shifted);
2142 int num_compl_zero = shiftr_zero (&shifted_compl);
2143 unsigned int regno = REGNO (operands[0]);
2144 enum reg_class class1 = REGNO_REG_CLASS (regno);
2146 /* This case takes care of single-bit set/clear constants, which we could
2147 also implement with BITSET/BITCLR. */
2149 && shifted >= -32768 && shifted < 65536
2150 && (D_REGNO_P (regno)
2151 || (regno >= REG_P0 && regno <= REG_P7 && num_zero <= 2)))
2153 emit_insn (gen_movsi (operands[0], GEN_INT (shifted)));
2154 emit_insn (gen_ashlsi3 (operands[0], operands[0], GEN_INT (num_zero)));
2159 tmp |= -(tmp & 0x8000);
2161 /* If high word has one bit set or clear, try to use a bit operation. */
2162 if (D_REGNO_P (regno))
2164 if (log2constp (val & 0xFFFF0000))
2166 emit_insn (gen_movsi (operands[0], GEN_INT (val & 0xFFFF)));
2167 emit_insn (gen_iorsi3 (operands[0], operands[0], GEN_INT (val & 0xFFFF0000)));
2170 else if (log2constp (val | 0xFFFF) && (val & 0x8000) != 0)
2172 emit_insn (gen_movsi (operands[0], GEN_INT (tmp)));
2173 emit_insn (gen_andsi3 (operands[0], operands[0], GEN_INT (val | 0xFFFF)));
2177 if (D_REGNO_P (regno))
2179 if (CONST_7BIT_IMM_P (tmp))
2181 emit_insn (gen_movsi (operands[0], GEN_INT (tmp)));
2182 emit_insn (gen_movstricthi_high (operands[0], GEN_INT (val & -65536)));
2186 if ((val & 0xFFFF0000) == 0)
2188 emit_insn (gen_movsi (operands[0], const0_rtx));
2189 emit_insn (gen_movsi_low (operands[0], operands[0], operands[1]));
2193 if ((val & 0xFFFF0000) == 0xFFFF0000)
2195 emit_insn (gen_movsi (operands[0], constm1_rtx));
2196 emit_insn (gen_movsi_low (operands[0], operands[0], operands[1]));
2201 /* Need DREGs for the remaining case. */
2206 && num_compl_zero && CONST_7BIT_IMM_P (shifted_compl))
2208 /* If optimizing for size, generate a sequence that has more instructions
2210 emit_insn (gen_movsi (operands[0], GEN_INT (shifted_compl)));
2211 emit_insn (gen_ashlsi3 (operands[0], operands[0],
2212 GEN_INT (num_compl_zero)));
2213 emit_insn (gen_one_cmplsi2 (operands[0], operands[0]));
2219 /* Return true if the legitimate memory address for a memory operand of mode
2220 MODE. Return false if not. */
2223 bfin_valid_add (enum machine_mode mode, HOST_WIDE_INT value)
2225 unsigned HOST_WIDE_INT v = value > 0 ? value : -value;
2226 int sz = GET_MODE_SIZE (mode);
2227 int shift = sz == 1 ? 0 : sz == 2 ? 1 : 2;
2228 /* The usual offsettable_memref machinery doesn't work so well for this
2229 port, so we deal with the problem here. */
2230 unsigned HOST_WIDE_INT mask = sz == 8 ? 0x7ffe : 0x7fff;
2231 return (v & ~(mask << shift)) == 0;
2235 bfin_valid_reg_p (unsigned int regno, int strict, enum machine_mode mode,
2236 enum rtx_code outer_code)
2239 return REGNO_OK_FOR_BASE_STRICT_P (regno, mode, outer_code, SCRATCH);
2241 return REGNO_OK_FOR_BASE_NONSTRICT_P (regno, mode, outer_code, SCRATCH);
2245 bfin_legitimate_address_p (enum machine_mode mode, rtx x, int strict)
2247 switch (GET_CODE (x)) {
2249 if (bfin_valid_reg_p (REGNO (x), strict, mode, MEM))
2253 if (REG_P (XEXP (x, 0))
2254 && bfin_valid_reg_p (REGNO (XEXP (x, 0)), strict, mode, PLUS)
2255 && ((GET_CODE (XEXP (x, 1)) == UNSPEC && mode == SImode)
2256 || (GET_CODE (XEXP (x, 1)) == CONST_INT
2257 && bfin_valid_add (mode, INTVAL (XEXP (x, 1))))))
2262 if (LEGITIMATE_MODE_FOR_AUTOINC_P (mode)
2263 && REG_P (XEXP (x, 0))
2264 && bfin_valid_reg_p (REGNO (XEXP (x, 0)), strict, mode, POST_INC))
2267 if (LEGITIMATE_MODE_FOR_AUTOINC_P (mode)
2268 && XEXP (x, 0) == stack_pointer_rtx
2269 && REG_P (XEXP (x, 0))
2270 && bfin_valid_reg_p (REGNO (XEXP (x, 0)), strict, mode, PRE_DEC))
2280 bfin_rtx_costs (rtx x, int code, int outer_code, int *total)
2282 int cost2 = COSTS_N_INSNS (1);
2287 if (outer_code == SET || outer_code == PLUS)
2288 *total = CONST_7BIT_IMM_P (INTVAL (x)) ? 0 : cost2;
2289 else if (outer_code == AND)
2290 *total = log2constp (~INTVAL (x)) ? 0 : cost2;
2291 else if (outer_code == LE || outer_code == LT || outer_code == EQ)
2292 *total = (INTVAL (x) >= -4 && INTVAL (x) <= 3) ? 0 : cost2;
2293 else if (outer_code == LEU || outer_code == LTU)
2294 *total = (INTVAL (x) >= 0 && INTVAL (x) <= 7) ? 0 : cost2;
2295 else if (outer_code == MULT)
2296 *total = (INTVAL (x) == 2 || INTVAL (x) == 4) ? 0 : cost2;
2297 else if (outer_code == ASHIFT && (INTVAL (x) == 1 || INTVAL (x) == 2))
2299 else if (outer_code == ASHIFT || outer_code == ASHIFTRT
2300 || outer_code == LSHIFTRT)
2301 *total = (INTVAL (x) >= 0 && INTVAL (x) <= 31) ? 0 : cost2;
2302 else if (outer_code == IOR || outer_code == XOR)
2303 *total = (INTVAL (x) & (INTVAL (x) - 1)) == 0 ? 0 : cost2;
2312 *total = COSTS_N_INSNS (2);
2316 if (GET_MODE (x) == Pmode)
2318 if (GET_CODE (XEXP (x, 0)) == MULT
2319 && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)
2321 HOST_WIDE_INT val = INTVAL (XEXP (XEXP (x, 0), 1));
2322 if (val == 2 || val == 4)
2325 *total += rtx_cost (XEXP (XEXP (x, 0), 0), outer_code);
2326 *total += rtx_cost (XEXP (x, 1), outer_code);
2338 if (GET_MODE (x) == DImode)
2345 if (GET_MODE (x) == DImode)
2350 if (GET_MODE_SIZE (GET_MODE (x)) <= UNITS_PER_WORD)
2351 *total = COSTS_N_INSNS (3);
2356 if (outer_code == SET)
2366 bfin_internal_label (FILE *stream, const char *prefix, unsigned long num)
2368 fprintf (stream, "%s%s$%ld:\n", LOCAL_LABEL_PREFIX, prefix, num);
2371 /* Used for communication between {push,pop}_multiple_operation (which
2372 we use not only as a predicate) and the corresponding output functions. */
2373 static int first_preg_to_save, first_dreg_to_save;
2376 push_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
2378 int lastdreg = 8, lastpreg = 6;
2381 first_preg_to_save = lastpreg;
2382 first_dreg_to_save = lastdreg;
2383 for (i = 1, group = 0; i < XVECLEN (op, 0) - 1; i++)
2385 rtx t = XVECEXP (op, 0, i);
2389 if (GET_CODE (t) != SET)
2393 dest = SET_DEST (t);
2394 if (GET_CODE (dest) != MEM || ! REG_P (src))
2396 dest = XEXP (dest, 0);
2397 if (GET_CODE (dest) != PLUS
2398 || ! REG_P (XEXP (dest, 0))
2399 || REGNO (XEXP (dest, 0)) != REG_SP
2400 || GET_CODE (XEXP (dest, 1)) != CONST_INT
2401 || INTVAL (XEXP (dest, 1)) != -i * 4)
2404 regno = REGNO (src);
2407 if (D_REGNO_P (regno))
2410 first_dreg_to_save = lastdreg = regno - REG_R0;
2412 else if (regno >= REG_P0 && regno <= REG_P7)
2415 first_preg_to_save = lastpreg = regno - REG_P0;
2425 if (regno >= REG_P0 && regno <= REG_P7)
2428 first_preg_to_save = lastpreg = regno - REG_P0;
2430 else if (regno != REG_R0 + lastdreg + 1)
2435 else if (group == 2)
2437 if (regno != REG_P0 + lastpreg + 1)
2446 pop_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
2448 int lastdreg = 8, lastpreg = 6;
2451 for (i = 1, group = 0; i < XVECLEN (op, 0); i++)
2453 rtx t = XVECEXP (op, 0, i);
2457 if (GET_CODE (t) != SET)
2461 dest = SET_DEST (t);
2462 if (GET_CODE (src) != MEM || ! REG_P (dest))
2464 src = XEXP (src, 0);
2468 if (! REG_P (src) || REGNO (src) != REG_SP)
2471 else if (GET_CODE (src) != PLUS
2472 || ! REG_P (XEXP (src, 0))
2473 || REGNO (XEXP (src, 0)) != REG_SP
2474 || GET_CODE (XEXP (src, 1)) != CONST_INT
2475 || INTVAL (XEXP (src, 1)) != (i - 1) * 4)
2478 regno = REGNO (dest);
2481 if (regno == REG_R7)
2486 else if (regno != REG_P0 + lastpreg - 1)
2491 else if (group == 1)
2493 if (regno != REG_R0 + lastdreg - 1)
2499 first_dreg_to_save = lastdreg;
2500 first_preg_to_save = lastpreg;
2504 /* Emit assembly code for one multi-register push described by INSN, with
2505 operands in OPERANDS. */
2508 output_push_multiple (rtx insn, rtx *operands)
2513 /* Validate the insn again, and compute first_[dp]reg_to_save. */
2514 ok = push_multiple_operation (PATTERN (insn), VOIDmode);
2517 if (first_dreg_to_save == 8)
2518 sprintf (buf, "[--sp] = ( p5:%d );\n", first_preg_to_save);
2519 else if (first_preg_to_save == 6)
2520 sprintf (buf, "[--sp] = ( r7:%d );\n", first_dreg_to_save);
2522 sprintf (buf, "[--sp] = ( r7:%d, p5:%d );\n",
2523 first_dreg_to_save, first_preg_to_save);
2525 output_asm_insn (buf, operands);
2528 /* Emit assembly code for one multi-register pop described by INSN, with
2529 operands in OPERANDS. */
2532 output_pop_multiple (rtx insn, rtx *operands)
2537 /* Validate the insn again, and compute first_[dp]reg_to_save. */
2538 ok = pop_multiple_operation (PATTERN (insn), VOIDmode);
2541 if (first_dreg_to_save == 8)
2542 sprintf (buf, "( p5:%d ) = [sp++];\n", first_preg_to_save);
2543 else if (first_preg_to_save == 6)
2544 sprintf (buf, "( r7:%d ) = [sp++];\n", first_dreg_to_save);
2546 sprintf (buf, "( r7:%d, p5:%d ) = [sp++];\n",
2547 first_dreg_to_save, first_preg_to_save);
2549 output_asm_insn (buf, operands);
2552 /* Adjust DST and SRC by OFFSET bytes, and generate one move in mode MODE. */
2555 single_move_for_movmem (rtx dst, rtx src, enum machine_mode mode, HOST_WIDE_INT offset)
2557 rtx scratch = gen_reg_rtx (mode);
2560 srcmem = adjust_address_nv (src, mode, offset);
2561 dstmem = adjust_address_nv (dst, mode, offset);
2562 emit_move_insn (scratch, srcmem);
2563 emit_move_insn (dstmem, scratch);
2566 /* Expand a string move operation of COUNT_EXP bytes from SRC to DST, with
2567 alignment ALIGN_EXP. Return true if successful, false if we should fall
2568 back on a different method. */
2571 bfin_expand_movmem (rtx dst, rtx src, rtx count_exp, rtx align_exp)
2573 rtx srcreg, destreg, countreg;
2574 HOST_WIDE_INT align = 0;
2575 unsigned HOST_WIDE_INT count = 0;
2577 if (GET_CODE (align_exp) == CONST_INT)
2578 align = INTVAL (align_exp);
2579 if (GET_CODE (count_exp) == CONST_INT)
2581 count = INTVAL (count_exp);
2583 if (!TARGET_INLINE_ALL_STRINGOPS && count > 64)
2588 /* If optimizing for size, only do single copies inline. */
2591 if (count == 2 && align < 2)
2593 if (count == 4 && align < 4)
2595 if (count != 1 && count != 2 && count != 4)
2598 if (align < 2 && count != 1)
2601 destreg = copy_to_mode_reg (Pmode, XEXP (dst, 0));
2602 if (destreg != XEXP (dst, 0))
2603 dst = replace_equiv_address_nv (dst, destreg);
2604 srcreg = copy_to_mode_reg (Pmode, XEXP (src, 0));
2605 if (srcreg != XEXP (src, 0))
2606 src = replace_equiv_address_nv (src, srcreg);
2608 if (count != 0 && align >= 2)
2610 unsigned HOST_WIDE_INT offset = 0;
2614 if ((count & ~3) == 4)
2616 single_move_for_movmem (dst, src, SImode, offset);
2619 else if (count & ~3)
2621 HOST_WIDE_INT new_count = ((count >> 2) & 0x3fffffff) - 1;
2622 countreg = copy_to_mode_reg (Pmode, GEN_INT (new_count));
2624 emit_insn (gen_rep_movsi (destreg, srcreg, countreg, destreg, srcreg));
2628 single_move_for_movmem (dst, src, HImode, offset);
2634 if ((count & ~1) == 2)
2636 single_move_for_movmem (dst, src, HImode, offset);
2639 else if (count & ~1)
2641 HOST_WIDE_INT new_count = ((count >> 1) & 0x7fffffff) - 1;
2642 countreg = copy_to_mode_reg (Pmode, GEN_INT (new_count));
2644 emit_insn (gen_rep_movhi (destreg, srcreg, countreg, destreg, srcreg));
2649 single_move_for_movmem (dst, src, QImode, offset);
2658 bfin_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
2660 enum attr_type insn_type, dep_insn_type;
2661 int dep_insn_code_number;
2663 /* Anti and output dependencies have zero cost. */
2664 if (REG_NOTE_KIND (link) != 0)
2667 dep_insn_code_number = recog_memoized (dep_insn);
2669 /* If we can't recognize the insns, we can't really do anything. */
2670 if (dep_insn_code_number < 0 || recog_memoized (insn) < 0)
2673 insn_type = get_attr_type (insn);
2674 dep_insn_type = get_attr_type (dep_insn);
2676 if (dep_insn_type == TYPE_MOVE || dep_insn_type == TYPE_MCLD)
2678 rtx pat = PATTERN (dep_insn);
2679 rtx dest = SET_DEST (pat);
2680 rtx src = SET_SRC (pat);
2681 if (! ADDRESS_REGNO_P (REGNO (dest)) || ! D_REGNO_P (REGNO (src)))
2683 return cost + (dep_insn_type == TYPE_MOVE ? 4 : 3);
2689 /* We use the machine specific reorg pass for emitting CSYNC instructions
2690 after conditional branches as needed.
2692 The Blackfin is unusual in that a code sequence like
2695 may speculatively perform the load even if the condition isn't true. This
2696 happens for a branch that is predicted not taken, because the pipeline
2697 isn't flushed or stalled, so the early stages of the following instructions,
2698 which perform the memory reference, are allowed to execute before the
2699 jump condition is evaluated.
2700 Therefore, we must insert additional instructions in all places where this
2701 could lead to incorrect behavior. The manual recommends CSYNC, while
2702 VDSP seems to use NOPs (even though its corresponding compiler option is
2705 When optimizing for speed, we emit NOPs, which seems faster than a CSYNC.
2706 When optimizing for size, we turn the branch into a predicted taken one.
2707 This may be slower due to mispredicts, but saves code size. */
2712 rtx insn, last_condjump = NULL_RTX;
2713 int cycles_since_jump = INT_MAX;
2715 if (! TARGET_SPECLD_ANOMALY || ! TARGET_CSYNC_ANOMALY)
2718 /* First pass: find predicted-false branches; if something after them
2719 needs nops, insert them or change the branch to predict true. */
2720 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
2724 if (NOTE_P (insn) || BARRIER_P (insn) || LABEL_P (insn))
2727 pat = PATTERN (insn);
2728 if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER
2729 || GET_CODE (pat) == ASM_INPUT || GET_CODE (pat) == ADDR_VEC
2730 || GET_CODE (pat) == ADDR_DIFF_VEC || asm_noperands (pat) >= 0)
2735 if (any_condjump_p (insn)
2736 && ! cbranch_predicted_taken_p (insn))
2738 last_condjump = insn;
2739 cycles_since_jump = 0;
2742 cycles_since_jump = INT_MAX;
2744 else if (INSN_P (insn))
2746 enum attr_type type = get_attr_type (insn);
2747 int delay_needed = 0;
2748 if (cycles_since_jump < INT_MAX)
2749 cycles_since_jump++;
2751 if (type == TYPE_MCLD && TARGET_SPECLD_ANOMALY)
2753 rtx pat = single_set (insn);
2754 if (may_trap_p (SET_SRC (pat)))
2757 else if (type == TYPE_SYNC && TARGET_CSYNC_ANOMALY)
2760 if (delay_needed > cycles_since_jump)
2764 rtx *op = recog_data.operand;
2766 delay_needed -= cycles_since_jump;
2768 extract_insn (last_condjump);
2771 pat = gen_cbranch_predicted_taken (op[0], op[1], op[2],
2773 cycles_since_jump = INT_MAX;
2776 /* Do not adjust cycles_since_jump in this case, so that
2777 we'll increase the number of NOPs for a subsequent insn
2779 pat = gen_cbranch_with_nops (op[0], op[1], op[2], op[3],
2780 GEN_INT (delay_needed));
2781 PATTERN (last_condjump) = pat;
2782 INSN_CODE (last_condjump) = recog (pat, insn, &num_clobbers);
2786 /* Second pass: for predicted-true branches, see if anything at the
2787 branch destination needs extra nops. */
2788 if (! TARGET_CSYNC_ANOMALY)
2791 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
2794 && any_condjump_p (insn)
2795 && (INSN_CODE (insn) == CODE_FOR_cbranch_predicted_taken
2796 || cbranch_predicted_taken_p (insn)))
2798 rtx target = JUMP_LABEL (insn);
2800 cycles_since_jump = 0;
2801 for (; target && cycles_since_jump < 3; target = NEXT_INSN (target))
2805 if (NOTE_P (target) || BARRIER_P (target) || LABEL_P (target))
2808 pat = PATTERN (target);
2809 if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER
2810 || GET_CODE (pat) == ASM_INPUT || GET_CODE (pat) == ADDR_VEC
2811 || GET_CODE (pat) == ADDR_DIFF_VEC || asm_noperands (pat) >= 0)
2814 if (INSN_P (target))
2816 enum attr_type type = get_attr_type (target);
2817 int delay_needed = 0;
2818 if (cycles_since_jump < INT_MAX)
2819 cycles_since_jump++;
2821 if (type == TYPE_SYNC && TARGET_CSYNC_ANOMALY)
2824 if (delay_needed > cycles_since_jump)
2826 rtx prev = prev_real_insn (label);
2827 delay_needed -= cycles_since_jump;
2829 fprintf (dump_file, "Adding %d nops after %d\n",
2830 delay_needed, INSN_UID (label));
2832 && INSN_CODE (prev) == CODE_FOR_cbranch_with_nops)
2839 "Reducing nops on insn %d.\n",
2842 x = XVECEXP (x, 0, 1);
2843 v = INTVAL (XVECEXP (x, 0, 0)) - delay_needed;
2844 XVECEXP (x, 0, 0) = GEN_INT (v);
2846 while (delay_needed-- > 0)
2847 emit_insn_after (gen_nop (), label);
2856 /* Handle interrupt_handler, exception_handler and nmi_handler function
2857 attributes; arguments as in struct attribute_spec.handler. */
2860 handle_int_attribute (tree *node, tree name,
2861 tree args ATTRIBUTE_UNUSED,
2862 int flags ATTRIBUTE_UNUSED,
2866 if (TREE_CODE (x) == FUNCTION_DECL)
2869 if (TREE_CODE (x) != FUNCTION_TYPE)
2871 warning (OPT_Wattributes, "%qs attribute only applies to functions",
2872 IDENTIFIER_POINTER (name));
2873 *no_add_attrs = true;
2875 else if (funkind (x) != SUBROUTINE)
2876 error ("multiple function type attributes specified");
2881 /* Return 0 if the attributes for two types are incompatible, 1 if they
2882 are compatible, and 2 if they are nearly compatible (which causes a
2883 warning to be generated). */
2886 bfin_comp_type_attributes (tree type1, tree type2)
2888 e_funkind kind1, kind2;
2890 if (TREE_CODE (type1) != FUNCTION_TYPE)
2893 kind1 = funkind (type1);
2894 kind2 = funkind (type2);
2899 /* Check for mismatched modifiers */
2900 if (!lookup_attribute ("nesting", TYPE_ATTRIBUTES (type1))
2901 != !lookup_attribute ("nesting", TYPE_ATTRIBUTES (type2)))
2904 if (!lookup_attribute ("saveall", TYPE_ATTRIBUTES (type1))
2905 != !lookup_attribute ("saveall", TYPE_ATTRIBUTES (type2)))
2908 if (!lookup_attribute ("kspisusp", TYPE_ATTRIBUTES (type1))
2909 != !lookup_attribute ("kspisusp", TYPE_ATTRIBUTES (type2)))
2912 if (!lookup_attribute ("longcall", TYPE_ATTRIBUTES (type1))
2913 != !lookup_attribute ("longcall", TYPE_ATTRIBUTES (type2)))
2919 /* Handle a "longcall" or "shortcall" attribute; arguments as in
2920 struct attribute_spec.handler. */
2923 bfin_handle_longcall_attribute (tree *node, tree name,
2924 tree args ATTRIBUTE_UNUSED,
2925 int flags ATTRIBUTE_UNUSED,
2928 if (TREE_CODE (*node) != FUNCTION_TYPE
2929 && TREE_CODE (*node) != FIELD_DECL
2930 && TREE_CODE (*node) != TYPE_DECL)
2932 warning (OPT_Wattributes, "`%s' attribute only applies to functions",
2933 IDENTIFIER_POINTER (name));
2934 *no_add_attrs = true;
2937 if ((strcmp (IDENTIFIER_POINTER (name), "longcall") == 0
2938 && lookup_attribute ("shortcall", TYPE_ATTRIBUTES (*node)))
2939 || (strcmp (IDENTIFIER_POINTER (name), "shortcall") == 0
2940 && lookup_attribute ("longcall", TYPE_ATTRIBUTES (*node))))
2942 warning (OPT_Wattributes,
2943 "can't apply both longcall and shortcall attributes to the same function");
2944 *no_add_attrs = true;
2950 /* Table of valid machine attributes. */
2951 const struct attribute_spec bfin_attribute_table[] =
2953 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
2954 { "interrupt_handler", 0, 0, false, true, true, handle_int_attribute },
2955 { "exception_handler", 0, 0, false, true, true, handle_int_attribute },
2956 { "nmi_handler", 0, 0, false, true, true, handle_int_attribute },
2957 { "nesting", 0, 0, false, true, true, NULL },
2958 { "kspisusp", 0, 0, false, true, true, NULL },
2959 { "saveall", 0, 0, false, true, true, NULL },
2960 { "longcall", 0, 0, false, true, true, bfin_handle_longcall_attribute },
2961 { "shortcall", 0, 0, false, true, true, bfin_handle_longcall_attribute },
2962 { NULL, 0, 0, false, false, false, NULL }
2965 /* Implementation of TARGET_ASM_INTEGER. When using FD-PIC, we need to
2966 tell the assembler to generate pointers to function descriptors in
2970 bfin_assemble_integer (rtx value, unsigned int size, int aligned_p)
2972 if (TARGET_FDPIC && size == UNITS_PER_WORD)
2974 if (GET_CODE (value) == SYMBOL_REF
2975 && SYMBOL_REF_FUNCTION_P (value))
2977 fputs ("\t.picptr\tfuncdesc(", asm_out_file);
2978 output_addr_const (asm_out_file, value);
2979 fputs (")\n", asm_out_file);
2984 /* We've set the unaligned SI op to NULL, so we always have to
2985 handle the unaligned case here. */
2986 assemble_integer_with_op ("\t.4byte\t", value);
2990 return default_assemble_integer (value, size, aligned_p);
2993 /* Output the assembler code for a thunk function. THUNK_DECL is the
2994 declaration for the thunk function itself, FUNCTION is the decl for
2995 the target function. DELTA is an immediate constant offset to be
2996 added to THIS. If VCALL_OFFSET is nonzero, the word at
2997 *(*this + vcall_offset) should be added to THIS. */
3000 bfin_output_mi_thunk (FILE *file ATTRIBUTE_UNUSED,
3001 tree thunk ATTRIBUTE_UNUSED, HOST_WIDE_INT delta,
3002 HOST_WIDE_INT vcall_offset, tree function)
3005 /* The this parameter is passed as the first argument. */
3006 rtx this = gen_rtx_REG (Pmode, REG_R0);
3008 /* Adjust the this parameter by a fixed constant. */
3012 if (delta >= -64 && delta <= 63)
3014 xops[0] = GEN_INT (delta);
3015 output_asm_insn ("%1 += %0;", xops);
3017 else if (delta >= -128 && delta < -64)
3019 xops[0] = GEN_INT (delta + 64);
3020 output_asm_insn ("%1 += -64; %1 += %0;", xops);
3022 else if (delta > 63 && delta <= 126)
3024 xops[0] = GEN_INT (delta - 63);
3025 output_asm_insn ("%1 += 63; %1 += %0;", xops);
3029 xops[0] = GEN_INT (delta);
3030 output_asm_insn ("r3.l = %h0; r3.h = %d0; %1 = %1 + r3;", xops);
3034 /* Adjust the this parameter by a value stored in the vtable. */
3037 rtx p2tmp = gen_rtx_REG (Pmode, REG_P2);
3038 rtx tmp = gen_rtx_REG (Pmode, REG_R2);
3042 output_asm_insn ("%2 = r0; %2 = [%2];", xops);
3044 /* Adjust the this parameter. */
3045 xops[0] = gen_rtx_MEM (Pmode, plus_constant (p2tmp, vcall_offset));
3046 if (!memory_operand (xops[0], Pmode))
3048 rtx tmp2 = gen_rtx_REG (Pmode, REG_P1);
3049 xops[0] = GEN_INT (vcall_offset);
3051 output_asm_insn ("%h1 = %h0; %d1 = %d0; %2 = %2 + %1", xops);
3052 xops[0] = gen_rtx_MEM (Pmode, p2tmp);
3055 output_asm_insn ("%1 = %0; %2 = %2 + %1;", xops);
3058 xops[0] = XEXP (DECL_RTL (function), 0);
3059 if (1 || !flag_pic || (*targetm.binds_local_p) (function))
3060 output_asm_insn ("jump.l\t%P0", xops);
3063 /* Codes for all the Blackfin builtins. */
3068 BFIN_BUILTIN_COMPOSE_2X16,
3069 BFIN_BUILTIN_EXTRACTLO,
3070 BFIN_BUILTIN_EXTRACTHI,
3072 BFIN_BUILTIN_SSADD_2X16,
3073 BFIN_BUILTIN_SSSUB_2X16,
3074 BFIN_BUILTIN_SSADDSUB_2X16,
3075 BFIN_BUILTIN_SSSUBADD_2X16,
3076 BFIN_BUILTIN_MULT_2X16,
3077 BFIN_BUILTIN_MULTR_2X16,
3078 BFIN_BUILTIN_NEG_2X16,
3079 BFIN_BUILTIN_ABS_2X16,
3080 BFIN_BUILTIN_MIN_2X16,
3081 BFIN_BUILTIN_MAX_2X16,
3083 BFIN_BUILTIN_SSADD_1X16,
3084 BFIN_BUILTIN_SSSUB_1X16,
3085 BFIN_BUILTIN_MULT_1X16,
3086 BFIN_BUILTIN_MULTR_1X16,
3087 BFIN_BUILTIN_NORM_1X16,
3088 BFIN_BUILTIN_NEG_1X16,
3089 BFIN_BUILTIN_ABS_1X16,
3090 BFIN_BUILTIN_MIN_1X16,
3091 BFIN_BUILTIN_MAX_1X16,
3093 BFIN_BUILTIN_DIFFHL_2X16,
3094 BFIN_BUILTIN_DIFFLH_2X16,
3096 BFIN_BUILTIN_SSADD_1X32,
3097 BFIN_BUILTIN_SSSUB_1X32,
3098 BFIN_BUILTIN_NORM_1X32,
3099 BFIN_BUILTIN_NEG_1X32,
3100 BFIN_BUILTIN_MIN_1X32,
3101 BFIN_BUILTIN_MAX_1X32,
3102 BFIN_BUILTIN_MULT_1X32,
3104 BFIN_BUILTIN_MULHISILL,
3105 BFIN_BUILTIN_MULHISILH,
3106 BFIN_BUILTIN_MULHISIHL,
3107 BFIN_BUILTIN_MULHISIHH,
3109 BFIN_BUILTIN_LSHIFT_1X16,
3110 BFIN_BUILTIN_LSHIFT_2X16,
3111 BFIN_BUILTIN_SSASHIFT_1X16,
3112 BFIN_BUILTIN_SSASHIFT_2X16,
3114 BFIN_BUILTIN_CPLX_MUL_16,
3115 BFIN_BUILTIN_CPLX_MAC_16,
3116 BFIN_BUILTIN_CPLX_MSU_16,
3121 #define def_builtin(NAME, TYPE, CODE) \
3123 lang_hooks.builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD, \
3127 /* Set up all builtin functions for this target. */
3129 bfin_init_builtins (void)
3131 tree V2HI_type_node = build_vector_type_for_mode (intHI_type_node, V2HImode);
3132 tree void_ftype_void
3133 = build_function_type (void_type_node, void_list_node);
3134 tree short_ftype_short
3135 = build_function_type_list (short_integer_type_node, short_integer_type_node,
3137 tree short_ftype_int_int
3138 = build_function_type_list (short_integer_type_node, integer_type_node,
3139 integer_type_node, NULL_TREE);
3140 tree int_ftype_int_int
3141 = build_function_type_list (integer_type_node, integer_type_node,
3142 integer_type_node, NULL_TREE);
3144 = build_function_type_list (integer_type_node, integer_type_node,
3146 tree short_ftype_int
3147 = build_function_type_list (short_integer_type_node, integer_type_node,
3149 tree int_ftype_v2hi_v2hi
3150 = build_function_type_list (integer_type_node, V2HI_type_node,
3151 V2HI_type_node, NULL_TREE);
3152 tree v2hi_ftype_v2hi_v2hi
3153 = build_function_type_list (V2HI_type_node, V2HI_type_node,
3154 V2HI_type_node, NULL_TREE);
3155 tree v2hi_ftype_v2hi_v2hi_v2hi
3156 = build_function_type_list (V2HI_type_node, V2HI_type_node,
3157 V2HI_type_node, V2HI_type_node, NULL_TREE);
3158 tree v2hi_ftype_int_int
3159 = build_function_type_list (V2HI_type_node, integer_type_node,
3160 integer_type_node, NULL_TREE);
3161 tree v2hi_ftype_v2hi_int
3162 = build_function_type_list (V2HI_type_node, V2HI_type_node,
3163 integer_type_node, NULL_TREE);
3164 tree int_ftype_short_short
3165 = build_function_type_list (integer_type_node, short_integer_type_node,
3166 short_integer_type_node, NULL_TREE);
3167 tree v2hi_ftype_v2hi
3168 = build_function_type_list (V2HI_type_node, V2HI_type_node, NULL_TREE);
3169 tree short_ftype_v2hi
3170 = build_function_type_list (short_integer_type_node, V2HI_type_node,
3173 /* Add the remaining MMX insns with somewhat more complicated types. */
3174 def_builtin ("__builtin_bfin_csync", void_ftype_void, BFIN_BUILTIN_CSYNC);
3175 def_builtin ("__builtin_bfin_ssync", void_ftype_void, BFIN_BUILTIN_SSYNC);
3177 def_builtin ("__builtin_bfin_compose_2x16", v2hi_ftype_int_int,
3178 BFIN_BUILTIN_COMPOSE_2X16);
3179 def_builtin ("__builtin_bfin_extract_hi", short_ftype_v2hi,
3180 BFIN_BUILTIN_EXTRACTHI);
3181 def_builtin ("__builtin_bfin_extract_lo", short_ftype_v2hi,
3182 BFIN_BUILTIN_EXTRACTLO);
3184 def_builtin ("__builtin_bfin_min_fr2x16", v2hi_ftype_v2hi_v2hi,
3185 BFIN_BUILTIN_MIN_2X16);
3186 def_builtin ("__builtin_bfin_max_fr2x16", v2hi_ftype_v2hi_v2hi,
3187 BFIN_BUILTIN_MAX_2X16);
3189 def_builtin ("__builtin_bfin_add_fr2x16", v2hi_ftype_v2hi_v2hi,
3190 BFIN_BUILTIN_SSADD_2X16);
3191 def_builtin ("__builtin_bfin_sub_fr2x16", v2hi_ftype_v2hi_v2hi,
3192 BFIN_BUILTIN_SSSUB_2X16);
3193 def_builtin ("__builtin_bfin_dspaddsubsat", v2hi_ftype_v2hi_v2hi,
3194 BFIN_BUILTIN_SSADDSUB_2X16);
3195 def_builtin ("__builtin_bfin_dspsubaddsat", v2hi_ftype_v2hi_v2hi,
3196 BFIN_BUILTIN_SSSUBADD_2X16);
3197 def_builtin ("__builtin_bfin_mult_fr2x16", v2hi_ftype_v2hi_v2hi,
3198 BFIN_BUILTIN_MULT_2X16);
3199 def_builtin ("__builtin_bfin_multr_fr2x16", v2hi_ftype_v2hi_v2hi,
3200 BFIN_BUILTIN_MULTR_2X16);
3201 def_builtin ("__builtin_bfin_negate_fr2x16", v2hi_ftype_v2hi,
3202 BFIN_BUILTIN_NEG_2X16);
3203 def_builtin ("__builtin_bfin_abs_fr2x16", v2hi_ftype_v2hi,
3204 BFIN_BUILTIN_ABS_2X16);
3206 def_builtin ("__builtin_bfin_add_fr1x16", short_ftype_int_int,
3207 BFIN_BUILTIN_SSADD_1X16);
3208 def_builtin ("__builtin_bfin_sub_fr1x16", short_ftype_int_int,
3209 BFIN_BUILTIN_SSSUB_1X16);
3210 def_builtin ("__builtin_bfin_mult_fr1x16", short_ftype_int_int,
3211 BFIN_BUILTIN_MULT_1X16);
3212 def_builtin ("__builtin_bfin_multr_fr1x16", short_ftype_int_int,
3213 BFIN_BUILTIN_MULTR_1X16);
3214 def_builtin ("__builtin_bfin_negate_fr1x16", short_ftype_short,
3215 BFIN_BUILTIN_NEG_1X16);
3216 def_builtin ("__builtin_bfin_abs_fr1x16", short_ftype_short,
3217 BFIN_BUILTIN_ABS_1X16);
3218 def_builtin ("__builtin_bfin_norm_fr1x16", short_ftype_int,
3219 BFIN_BUILTIN_NORM_1X16);
3221 def_builtin ("__builtin_bfin_diff_hl_fr2x16", short_ftype_v2hi,
3222 BFIN_BUILTIN_DIFFHL_2X16);
3223 def_builtin ("__builtin_bfin_diff_lh_fr2x16", short_ftype_v2hi,
3224 BFIN_BUILTIN_DIFFLH_2X16);
3226 def_builtin ("__builtin_bfin_mulhisill", int_ftype_v2hi_v2hi,
3227 BFIN_BUILTIN_MULHISILL);
3228 def_builtin ("__builtin_bfin_mulhisihl", int_ftype_v2hi_v2hi,
3229 BFIN_BUILTIN_MULHISIHL);
3230 def_builtin ("__builtin_bfin_mulhisilh", int_ftype_v2hi_v2hi,
3231 BFIN_BUILTIN_MULHISILH);
3232 def_builtin ("__builtin_bfin_mulhisihh", int_ftype_v2hi_v2hi,
3233 BFIN_BUILTIN_MULHISIHH);
3235 def_builtin ("__builtin_bfin_add_fr1x32", int_ftype_int_int,
3236 BFIN_BUILTIN_SSADD_1X32);
3237 def_builtin ("__builtin_bfin_sub_fr1x32", int_ftype_int_int,
3238 BFIN_BUILTIN_SSSUB_1X32);
3239 def_builtin ("__builtin_bfin_negate_fr1x32", int_ftype_int,
3240 BFIN_BUILTIN_NEG_1X32);
3241 def_builtin ("__builtin_bfin_norm_fr1x32", short_ftype_int,
3242 BFIN_BUILTIN_NORM_1X32);
3243 def_builtin ("__builtin_bfin_mult_fr1x32", int_ftype_short_short,
3244 BFIN_BUILTIN_MULT_1X32);
3247 def_builtin ("__builtin_bfin_shl_fr1x16", short_ftype_int_int,
3248 BFIN_BUILTIN_SSASHIFT_1X16);
3249 def_builtin ("__builtin_bfin_shl_fr2x16", v2hi_ftype_v2hi_int,
3250 BFIN_BUILTIN_SSASHIFT_2X16);
3251 def_builtin ("__builtin_bfin_lshl_fr1x16", short_ftype_int_int,
3252 BFIN_BUILTIN_LSHIFT_1X16);
3253 def_builtin ("__builtin_bfin_lshl_fr2x16", v2hi_ftype_v2hi_int,
3254 BFIN_BUILTIN_LSHIFT_2X16);
3256 /* Complex numbers. */
3257 def_builtin ("__builtin_bfin_cmplx_mul", v2hi_ftype_v2hi_v2hi,
3258 BFIN_BUILTIN_CPLX_MUL_16);
3259 def_builtin ("__builtin_bfin_cmplx_mac", v2hi_ftype_v2hi_v2hi_v2hi,
3260 BFIN_BUILTIN_CPLX_MAC_16);
3261 def_builtin ("__builtin_bfin_cmplx_msu", v2hi_ftype_v2hi_v2hi_v2hi,
3262 BFIN_BUILTIN_CPLX_MSU_16);
3266 struct builtin_description
3268 const enum insn_code icode;
3269 const char *const name;
3270 const enum bfin_builtins code;
3274 static const struct builtin_description bdesc_2arg[] =
3276 { CODE_FOR_composev2hi, "__builtin_bfin_compose_2x16", BFIN_BUILTIN_COMPOSE_2X16, -1 },
3278 { CODE_FOR_ssashiftv2hi3, "__builtin_bfin_shl_fr2x16", BFIN_BUILTIN_SSASHIFT_2X16, -1 },
3279 { CODE_FOR_ssashifthi3, "__builtin_bfin_shl_fr1x16", BFIN_BUILTIN_SSASHIFT_1X16, -1 },
3280 { CODE_FOR_lshiftv2hi3, "__builtin_bfin_lshl_fr2x16", BFIN_BUILTIN_LSHIFT_2X16, -1 },
3281 { CODE_FOR_lshifthi3, "__builtin_bfin_lshl_fr1x16", BFIN_BUILTIN_LSHIFT_1X16, -1 },
3283 { CODE_FOR_sminhi3, "__builtin_bfin_min_fr1x16", BFIN_BUILTIN_MIN_1X16, -1 },
3284 { CODE_FOR_smaxhi3, "__builtin_bfin_max_fr1x16", BFIN_BUILTIN_MAX_1X16, -1 },
3285 { CODE_FOR_ssaddhi3, "__builtin_bfin_add_fr1x16", BFIN_BUILTIN_SSADD_1X16, -1 },
3286 { CODE_FOR_sssubhi3, "__builtin_bfin_sub_fr1x16", BFIN_BUILTIN_SSSUB_1X16, -1 },
3288 { CODE_FOR_sminsi3, "__builtin_bfin_min_fr1x32", BFIN_BUILTIN_MIN_1X32, -1 },
3289 { CODE_FOR_smaxsi3, "__builtin_bfin_max_fr1x32", BFIN_BUILTIN_MAX_1X32, -1 },
3290 { CODE_FOR_ssaddsi3, "__builtin_bfin_add_fr1x32", BFIN_BUILTIN_SSADD_1X32, -1 },
3291 { CODE_FOR_sssubsi3, "__builtin_bfin_sub_fr1x32", BFIN_BUILTIN_SSSUB_1X32, -1 },
3293 { CODE_FOR_sminv2hi3, "__builtin_bfin_min_fr2x16", BFIN_BUILTIN_MIN_2X16, -1 },
3294 { CODE_FOR_smaxv2hi3, "__builtin_bfin_max_fr2x16", BFIN_BUILTIN_MAX_2X16, -1 },
3295 { CODE_FOR_ssaddv2hi3, "__builtin_bfin_add_fr2x16", BFIN_BUILTIN_SSADD_2X16, -1 },
3296 { CODE_FOR_sssubv2hi3, "__builtin_bfin_sub_fr2x16", BFIN_BUILTIN_SSSUB_2X16, -1 },
3297 { CODE_FOR_ssaddsubv2hi3, "__builtin_bfin_dspaddsubsat", BFIN_BUILTIN_SSADDSUB_2X16, -1 },
3298 { CODE_FOR_sssubaddv2hi3, "__builtin_bfin_dspsubaddsat", BFIN_BUILTIN_SSSUBADD_2X16, -1 },
3300 { CODE_FOR_flag_mulhisi, "__builtin_bfin_mult_fr1x32", BFIN_BUILTIN_MULT_1X32, MACFLAG_NONE },
3301 { CODE_FOR_flag_mulhi, "__builtin_bfin_mult_fr1x16", BFIN_BUILTIN_MULT_1X16, MACFLAG_T },
3302 { CODE_FOR_flag_mulhi, "__builtin_bfin_multr_fr1x16", BFIN_BUILTIN_MULTR_1X16, MACFLAG_NONE },
3303 { CODE_FOR_flag_mulv2hi, "__builtin_bfin_mult_fr2x16", BFIN_BUILTIN_MULT_2X16, MACFLAG_T },
3304 { CODE_FOR_flag_mulv2hi, "__builtin_bfin_multr_fr2x16", BFIN_BUILTIN_MULTR_2X16, MACFLAG_NONE }
3307 static const struct builtin_description bdesc_1arg[] =
3309 { CODE_FOR_signbitshi2, "__builtin_bfin_norm_fr1x16", BFIN_BUILTIN_NORM_1X16, 0 },
3310 { CODE_FOR_ssneghi2, "__builtin_bfin_negate_fr1x16", BFIN_BUILTIN_NEG_1X16, 0 },
3311 { CODE_FOR_abshi2, "__builtin_bfin_abs_fr1x16", BFIN_BUILTIN_ABS_1X16, 0 },
3313 { CODE_FOR_signbitssi2, "__builtin_bfin_norm_fr1x32", BFIN_BUILTIN_NORM_1X32, 0 },
3314 { CODE_FOR_ssnegsi2, "__builtin_bfin_negate_fr1x32", BFIN_BUILTIN_NEG_1X32, 0 },
3316 { CODE_FOR_movv2hi_hi_low, "__builtin_bfin_extract_lo", BFIN_BUILTIN_EXTRACTLO, 0 },
3317 { CODE_FOR_movv2hi_hi_high, "__builtin_bfin_extract_hi", BFIN_BUILTIN_EXTRACTHI, 0 },
3318 { CODE_FOR_ssnegv2hi2, "__builtin_bfin_negate_fr2x16", BFIN_BUILTIN_NEG_2X16, 0 },
3319 { CODE_FOR_absv2hi2, "__builtin_bfin_abs_fr2x16", BFIN_BUILTIN_ABS_2X16, 0 }
3322 /* Errors in the source file can cause expand_expr to return const0_rtx
3323 where we expect a vector. To avoid crashing, use one of the vector
3324 clear instructions. */
3326 safe_vector_operand (rtx x, enum machine_mode mode)
3328 if (x != const0_rtx)
3330 x = gen_reg_rtx (SImode);
3332 emit_insn (gen_movsi (x, CONST0_RTX (SImode)));
3333 return gen_lowpart (mode, x);
3336 /* Subroutine of bfin_expand_builtin to take care of binop insns. MACFLAG is -1
3337 if this is a normal binary op, or one of the MACFLAG_xxx constants. */
3340 bfin_expand_binop_builtin (enum insn_code icode, tree arglist, rtx target,
3344 tree arg0 = TREE_VALUE (arglist);
3345 tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
3346 rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
3347 rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
3348 enum machine_mode op0mode = GET_MODE (op0);
3349 enum machine_mode op1mode = GET_MODE (op1);
3350 enum machine_mode tmode = insn_data[icode].operand[0].mode;
3351 enum machine_mode mode0 = insn_data[icode].operand[1].mode;
3352 enum machine_mode mode1 = insn_data[icode].operand[2].mode;
3354 if (VECTOR_MODE_P (mode0))
3355 op0 = safe_vector_operand (op0, mode0);
3356 if (VECTOR_MODE_P (mode1))
3357 op1 = safe_vector_operand (op1, mode1);
3360 || GET_MODE (target) != tmode
3361 || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
3362 target = gen_reg_rtx (tmode);
3364 if ((op0mode == SImode || op0mode == VOIDmode) && mode0 == HImode)
3367 op0 = gen_lowpart (HImode, op0);
3369 if ((op1mode == SImode || op1mode == VOIDmode) && mode1 == HImode)
3372 op1 = gen_lowpart (HImode, op1);
3374 /* In case the insn wants input operands in modes different from
3375 the result, abort. */
3376 gcc_assert ((op0mode == mode0 || op0mode == VOIDmode)
3377 && (op1mode == mode1 || op1mode == VOIDmode));
3379 if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
3380 op0 = copy_to_mode_reg (mode0, op0);
3381 if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
3382 op1 = copy_to_mode_reg (mode1, op1);
3385 pat = GEN_FCN (icode) (target, op0, op1);
3387 pat = GEN_FCN (icode) (target, op0, op1, GEN_INT (macflag));
3395 /* Subroutine of bfin_expand_builtin to take care of unop insns. */
3398 bfin_expand_unop_builtin (enum insn_code icode, tree arglist,
3402 tree arg0 = TREE_VALUE (arglist);
3403 rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
3404 enum machine_mode op0mode = GET_MODE (op0);
3405 enum machine_mode tmode = insn_data[icode].operand[0].mode;
3406 enum machine_mode mode0 = insn_data[icode].operand[1].mode;
3409 || GET_MODE (target) != tmode
3410 || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
3411 target = gen_reg_rtx (tmode);
3413 if (VECTOR_MODE_P (mode0))
3414 op0 = safe_vector_operand (op0, mode0);
3416 if (op0mode == SImode && mode0 == HImode)
3419 op0 = gen_lowpart (HImode, op0);
3421 gcc_assert (op0mode == mode0 || op0mode == VOIDmode);
3423 if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
3424 op0 = copy_to_mode_reg (mode0, op0);
3426 pat = GEN_FCN (icode) (target, op0);
3433 /* Expand an expression EXP that calls a built-in function,
3434 with result going to TARGET if that's convenient
3435 (and in mode MODE if that's convenient).
3436 SUBTARGET may be used as the target for computing one of EXP's operands.
3437 IGNORE is nonzero if the value is to be ignored. */
3440 bfin_expand_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
3441 rtx subtarget ATTRIBUTE_UNUSED,
3442 enum machine_mode mode ATTRIBUTE_UNUSED,
3443 int ignore ATTRIBUTE_UNUSED)
3446 enum insn_code icode;
3447 const struct builtin_description *d;
3448 tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
3449 tree arglist = TREE_OPERAND (exp, 1);
3450 unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
3451 tree arg0, arg1, arg2;
3452 rtx op0, op1, op2, accvec, pat, tmp1, tmp2;
3453 enum machine_mode tmode, mode0;
3457 case BFIN_BUILTIN_CSYNC:
3458 emit_insn (gen_csync ());
3460 case BFIN_BUILTIN_SSYNC:
3461 emit_insn (gen_ssync ());
3464 case BFIN_BUILTIN_DIFFHL_2X16:
3465 case BFIN_BUILTIN_DIFFLH_2X16:
3466 arg0 = TREE_VALUE (arglist);
3467 op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
3468 icode = (fcode == BFIN_BUILTIN_DIFFHL_2X16
3469 ? CODE_FOR_subhilov2hi3 : CODE_FOR_sublohiv2hi3);
3470 tmode = insn_data[icode].operand[0].mode;
3471 mode0 = insn_data[icode].operand[1].mode;
3474 || GET_MODE (target) != tmode
3475 || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
3476 target = gen_reg_rtx (tmode);
3478 if (VECTOR_MODE_P (mode0))
3479 op0 = safe_vector_operand (op0, mode0);
3481 if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
3482 op0 = copy_to_mode_reg (mode0, op0);
3484 pat = GEN_FCN (icode) (target, op0, op0);
3490 case BFIN_BUILTIN_CPLX_MUL_16:
3491 arg0 = TREE_VALUE (arglist);
3492 arg1 = TREE_VALUE (TREE_CHAIN (arglist));
3493 op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
3494 op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
3495 accvec = gen_reg_rtx (V2PDImode);
3498 || GET_MODE (target) != V2HImode
3499 || ! (*insn_data[icode].operand[0].predicate) (target, V2HImode))
3500 target = gen_reg_rtx (tmode);
3501 if (! register_operand (op0, GET_MODE (op0)))
3502 op0 = copy_to_mode_reg (GET_MODE (op0), op0);
3503 if (! register_operand (op1, GET_MODE (op1)))
3504 op1 = copy_to_mode_reg (GET_MODE (op1), op1);
3506 emit_insn (gen_flag_macinit1v2hi_parts (accvec, op0, op1, const0_rtx,
3507 const0_rtx, const0_rtx,
3508 const1_rtx, GEN_INT (MACFLAG_NONE)));
3509 emit_insn (gen_flag_macv2hi_parts (target, op0, op1, const1_rtx,
3510 const1_rtx, const1_rtx,
3511 const0_rtx, accvec, const1_rtx, const0_rtx,
3512 GEN_INT (MACFLAG_NONE), accvec));
3516 case BFIN_BUILTIN_CPLX_MAC_16:
3517 case BFIN_BUILTIN_CPLX_MSU_16:
3518 arg0 = TREE_VALUE (arglist);
3519 arg1 = TREE_VALUE (TREE_CHAIN (arglist));
3520 arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
3521 op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
3522 op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
3523 op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
3524 accvec = gen_reg_rtx (V2PDImode);
3527 || GET_MODE (target) != V2HImode
3528 || ! (*insn_data[icode].operand[0].predicate) (target, V2HImode))
3529 target = gen_reg_rtx (tmode);
3530 if (! register_operand (op0, GET_MODE (op0)))
3531 op0 = copy_to_mode_reg (GET_MODE (op0), op0);
3532 if (! register_operand (op1, GET_MODE (op1)))
3533 op1 = copy_to_mode_reg (GET_MODE (op1), op1);
3535 tmp1 = gen_reg_rtx (SImode);
3536 tmp2 = gen_reg_rtx (SImode);
3537 emit_insn (gen_ashlsi3 (tmp1, gen_lowpart (SImode, op2), GEN_INT (16)));
3538 emit_move_insn (tmp2, gen_lowpart (SImode, op2));
3539 emit_insn (gen_movstricthi_1 (gen_lowpart (HImode, tmp2), const0_rtx));
3540 emit_insn (gen_load_accumulator_pair (accvec, tmp1, tmp2));
3541 emit_insn (gen_flag_macv2hi_parts_acconly (accvec, op0, op1, const0_rtx,
3542 const0_rtx, const0_rtx,
3543 const1_rtx, accvec, const0_rtx,
3545 GEN_INT (MACFLAG_W32)));
3546 tmp1 = (fcode == BFIN_BUILTIN_CPLX_MAC_16 ? const1_rtx : const0_rtx);
3547 tmp2 = (fcode == BFIN_BUILTIN_CPLX_MAC_16 ? const0_rtx : const1_rtx);
3548 emit_insn (gen_flag_macv2hi_parts (target, op0, op1, const1_rtx,
3549 const1_rtx, const1_rtx,
3550 const0_rtx, accvec, tmp1, tmp2,
3551 GEN_INT (MACFLAG_NONE), accvec));
3559 for (i = 0, d = bdesc_2arg; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
3560 if (d->code == fcode)
3561 return bfin_expand_binop_builtin (d->icode, arglist, target,
3564 for (i = 0, d = bdesc_1arg; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
3565 if (d->code == fcode)
3566 return bfin_expand_unop_builtin (d->icode, arglist, target);
3571 #undef TARGET_INIT_BUILTINS
3572 #define TARGET_INIT_BUILTINS bfin_init_builtins
3574 #undef TARGET_EXPAND_BUILTIN
3575 #define TARGET_EXPAND_BUILTIN bfin_expand_builtin
3577 #undef TARGET_ASM_GLOBALIZE_LABEL
3578 #define TARGET_ASM_GLOBALIZE_LABEL bfin_globalize_label
3580 #undef TARGET_ASM_FILE_START
3581 #define TARGET_ASM_FILE_START output_file_start
3583 #undef TARGET_ATTRIBUTE_TABLE
3584 #define TARGET_ATTRIBUTE_TABLE bfin_attribute_table
3586 #undef TARGET_COMP_TYPE_ATTRIBUTES
3587 #define TARGET_COMP_TYPE_ATTRIBUTES bfin_comp_type_attributes
3589 #undef TARGET_RTX_COSTS
3590 #define TARGET_RTX_COSTS bfin_rtx_costs
3592 #undef TARGET_ADDRESS_COST
3593 #define TARGET_ADDRESS_COST bfin_address_cost
3595 #undef TARGET_ASM_INTERNAL_LABEL
3596 #define TARGET_ASM_INTERNAL_LABEL bfin_internal_label
3598 #undef TARGET_ASM_INTEGER
3599 #define TARGET_ASM_INTEGER bfin_assemble_integer
3601 #undef TARGET_MACHINE_DEPENDENT_REORG
3602 #define TARGET_MACHINE_DEPENDENT_REORG bfin_reorg
3604 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
3605 #define TARGET_FUNCTION_OK_FOR_SIBCALL bfin_function_ok_for_sibcall
3607 #undef TARGET_ASM_OUTPUT_MI_THUNK
3608 #define TARGET_ASM_OUTPUT_MI_THUNK bfin_output_mi_thunk
3609 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
3610 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_tree_hwi_hwi_tree_true
3612 #undef TARGET_SCHED_ADJUST_COST
3613 #define TARGET_SCHED_ADJUST_COST bfin_adjust_cost
3615 #undef TARGET_PROMOTE_PROTOTYPES
3616 #define TARGET_PROMOTE_PROTOTYPES hook_bool_tree_true
3617 #undef TARGET_PROMOTE_FUNCTION_ARGS
3618 #define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true
3619 #undef TARGET_PROMOTE_FUNCTION_RETURN
3620 #define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true
3622 #undef TARGET_ARG_PARTIAL_BYTES
3623 #define TARGET_ARG_PARTIAL_BYTES bfin_arg_partial_bytes
3625 #undef TARGET_PASS_BY_REFERENCE
3626 #define TARGET_PASS_BY_REFERENCE bfin_pass_by_reference
3628 #undef TARGET_SETUP_INCOMING_VARARGS
3629 #define TARGET_SETUP_INCOMING_VARARGS setup_incoming_varargs
3631 #undef TARGET_STRUCT_VALUE_RTX
3632 #define TARGET_STRUCT_VALUE_RTX bfin_struct_value_rtx
3634 #undef TARGET_VECTOR_MODE_SUPPORTED_P
3635 #define TARGET_VECTOR_MODE_SUPPORTED_P bfin_vector_mode_supported_p
3637 #undef TARGET_HANDLE_OPTION
3638 #define TARGET_HANDLE_OPTION bfin_handle_option
3640 #undef TARGET_DEFAULT_TARGET_FLAGS
3641 #define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
3643 #undef TARGET_SECONDARY_RELOAD
3644 #define TARGET_SECONDARY_RELOAD bfin_secondary_reload
3646 struct gcc_target targetm = TARGET_INITIALIZER;