1 /* The Blackfin code generation auxiliary output file.
2 Copyright (C) 2005 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, 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
24 #include "coretypes.h"
28 #include "hard-reg-set.h"
30 #include "insn-config.h"
31 #include "conditions.h"
32 #include "insn-flags.h"
34 #include "insn-attr.h"
41 #include "target-def.h"
46 #include "integrate.h"
47 #include "bfin-protos.h"
51 /* Test and compare insns in bfin.md store the information needed to
52 generate branch and scc insns here. */
53 rtx bfin_compare_op0, bfin_compare_op1;
55 /* RTX for condition code flag register and RETS register */
56 extern GTY(()) rtx bfin_cc_rtx;
57 extern GTY(()) rtx bfin_rets_rtx;
58 rtx bfin_cc_rtx, bfin_rets_rtx;
60 int max_arg_registers = 0;
62 /* Arrays used when emitting register names. */
63 const char *short_reg_names[] = SHORT_REGISTER_NAMES;
64 const char *high_reg_names[] = HIGH_REGISTER_NAMES;
65 const char *dregs_pair_names[] = DREGS_PAIR_NAMES;
66 const char *byte_reg_names[] = BYTE_REGISTER_NAMES;
68 static int arg_regs[] = FUNCTION_ARG_REGISTERS;
70 /* The value passed to -mshared-library-id=. */
71 static int bfin_library_id;
72 /* Nonzero if -mshared-library-id was given. */
73 static int bfin_lib_id_given;
76 bfin_globalize_label (FILE *stream, const char *name)
78 fputs (".global ", stream);
79 assemble_name (stream, name);
85 output_file_start (void)
87 FILE *file = asm_out_file;
90 fprintf (file, ".file \"%s\";\n", input_filename);
92 for (i = 0; arg_regs[i] >= 0; i++)
94 max_arg_registers = i; /* how many arg reg used */
97 /* Called early in the compilation to conditionally modify
98 fixed_regs/call_used_regs. */
101 conditional_register_usage (void)
103 /* initialize condition code flag register rtx */
104 bfin_cc_rtx = gen_rtx_REG (BImode, REG_CC);
105 bfin_rets_rtx = gen_rtx_REG (Pmode, REG_RETS);
108 /* Examine machine-dependent attributes of function type FUNTYPE and return its
109 type. See the definition of E_FUNKIND. */
111 static e_funkind funkind (tree funtype)
113 tree attrs = TYPE_ATTRIBUTES (funtype);
114 if (lookup_attribute ("interrupt_handler", attrs))
115 return INTERRUPT_HANDLER;
116 else if (lookup_attribute ("exception_handler", attrs))
117 return EXCPT_HANDLER;
118 else if (lookup_attribute ("nmi_handler", attrs))
124 /* Stack frame layout. */
126 /* Compute the number of DREGS to save with a push_multiple operation.
127 This could include registers that aren't modified in the function,
128 since push_multiple only takes a range of registers. */
131 n_dregs_to_save (void)
135 for (i = REG_R0; i <= REG_R7; i++)
137 if (regs_ever_live[i] && ! call_used_regs[i])
138 return REG_R7 - i + 1;
140 if (current_function_calls_eh_return)
145 unsigned test = EH_RETURN_DATA_REGNO (j);
146 if (test == INVALID_REGNUM)
149 return REG_R7 - i + 1;
157 /* Like n_dregs_to_save, but compute number of PREGS to save. */
160 n_pregs_to_save (void)
164 for (i = REG_P0; i <= REG_P5; i++)
165 if ((regs_ever_live[i] && ! call_used_regs[i])
166 || (i == PIC_OFFSET_TABLE_REGNUM
167 && (current_function_uses_pic_offset_table
168 || (TARGET_ID_SHARED_LIBRARY && ! current_function_is_leaf))))
169 return REG_P5 - i + 1;
173 /* Determine if we are going to save the frame pointer in the prologue. */
176 must_save_fp_p (void)
178 return (frame_pointer_needed || regs_ever_live[REG_FP]);
182 stack_frame_needed_p (void)
184 /* EH return puts a new return address into the frame using an
185 address relative to the frame pointer. */
186 if (current_function_calls_eh_return)
188 return frame_pointer_needed;
191 /* Emit code to save registers in the prologue. SAVEALL is nonzero if we
192 must save all registers; this is used for interrupt handlers.
193 SPREG contains (reg:SI REG_SP). */
196 expand_prologue_reg_save (rtx spreg, int saveall)
198 int ndregs = saveall ? 8 : n_dregs_to_save ();
199 int npregs = saveall ? 6 : n_pregs_to_save ();
200 int dregno = REG_R7 + 1 - ndregs;
201 int pregno = REG_P5 + 1 - npregs;
202 int total = ndregs + npregs;
209 val = GEN_INT (-total * 4);
210 pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total + 2));
211 XVECEXP (pat, 0, 0) = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, val),
212 UNSPEC_PUSH_MULTIPLE);
213 XVECEXP (pat, 0, total + 1) = gen_rtx_SET (VOIDmode, spreg,
214 gen_rtx_PLUS (Pmode, spreg,
216 RTX_FRAME_RELATED_P (XVECEXP (pat, 0, total + 1)) = 1;
217 for (i = 0; i < total; i++)
219 rtx memref = gen_rtx_MEM (word_mode,
220 gen_rtx_PLUS (Pmode, spreg,
221 GEN_INT (- i * 4 - 4)));
225 subpat = gen_rtx_SET (VOIDmode, memref, gen_rtx_REG (word_mode,
231 subpat = gen_rtx_SET (VOIDmode, memref, gen_rtx_REG (word_mode,
235 XVECEXP (pat, 0, i + 1) = subpat;
236 RTX_FRAME_RELATED_P (subpat) = 1;
238 insn = emit_insn (pat);
239 RTX_FRAME_RELATED_P (insn) = 1;
242 /* Emit code to restore registers in the epilogue. SAVEALL is nonzero if we
243 must save all registers; this is used for interrupt handlers.
244 SPREG contains (reg:SI REG_SP). */
247 expand_epilogue_reg_restore (rtx spreg, int saveall)
249 int ndregs = saveall ? 8 : n_dregs_to_save ();
250 int npregs = saveall ? 6 : n_pregs_to_save ();
251 int total = ndregs + npregs;
258 pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total + 1));
259 XVECEXP (pat, 0, 0) = gen_rtx_SET (VOIDmode, spreg,
260 gen_rtx_PLUS (Pmode, spreg,
261 GEN_INT (total * 4)));
268 for (i = 0; i < total; i++)
271 ? gen_rtx_PLUS (Pmode, spreg, GEN_INT (i * 4))
273 rtx memref = gen_rtx_MEM (word_mode, addr);
276 XVECEXP (pat, 0, i + 1)
277 = gen_rtx_SET (VOIDmode, gen_rtx_REG (word_mode, regno), memref);
286 insn = emit_insn (pat);
287 RTX_FRAME_RELATED_P (insn) = 1;
290 /* Perform any needed actions needed for a function that is receiving a
291 variable number of arguments.
295 MODE and TYPE are the mode and type of the current parameter.
297 PRETEND_SIZE is a variable that should be set to the amount of stack
298 that must be pushed by the prolog to pretend that our caller pushed
301 Normally, this macro will push all remaining incoming registers on the
302 stack and set PRETEND_SIZE to the length of the registers pushed.
305 - VDSP C compiler manual (our ABI) says that a variable args function
306 should save the R0, R1 and R2 registers in the stack.
307 - The caller will always leave space on the stack for the
308 arguments that are passed in registers, so we dont have
309 to leave any extra space.
310 - now, the vastart pointer can access all arguments from the stack. */
313 setup_incoming_varargs (CUMULATIVE_ARGS *cum,
314 enum machine_mode mode ATTRIBUTE_UNUSED,
315 tree type ATTRIBUTE_UNUSED, int *pretend_size,
324 /* The move for named arguments will be generated automatically by the
325 compiler. We need to generate the move rtx for the unnamed arguments
326 if they are in the first 3 words. We assume at least 1 named argument
327 exists, so we never generate [ARGP] = R0 here. */
329 for (i = cum->words + 1; i < max_arg_registers; i++)
331 mem = gen_rtx_MEM (Pmode,
332 plus_constant (arg_pointer_rtx, (i * UNITS_PER_WORD)));
333 emit_move_insn (mem, gen_rtx_REG (Pmode, i));
339 /* Value should be nonzero if functions must have frame pointers.
340 Zero means the frame pointer need not be set up (and parms may
341 be accessed via the stack pointer) in functions that seem suitable. */
344 bfin_frame_pointer_required (void)
346 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
348 if (fkind != SUBROUTINE)
351 /* We turn on on -fomit-frame-pointer if -momit-leaf-frame-pointer is used,
352 so we have to override it for non-leaf functions. */
353 if (TARGET_OMIT_LEAF_FRAME_POINTER && ! current_function_is_leaf)
359 /* Return the number of registers pushed during the prologue. */
362 n_regs_saved_by_prologue (void)
364 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
365 int n = n_dregs_to_save () + n_pregs_to_save ();
367 if (stack_frame_needed_p ())
368 /* We use a LINK instruction in this case. */
372 if (must_save_fp_p ())
374 if (! current_function_is_leaf)
378 if (fkind != SUBROUTINE)
380 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
381 tree all = lookup_attribute ("saveall", attrs);
384 /* Increment once for ASTAT. */
388 if (lookup_attribute ("nesting", attrs))
391 for (i = REG_P7 + 1; i < REG_CC; i++)
394 || (!leaf_function_p () && call_used_regs[i]))
395 n += i == REG_A0 || i == REG_A1 ? 2 : 1;
400 /* Return the offset between two registers, one to be eliminated, and the other
401 its replacement, at the start of a routine. */
404 bfin_initial_elimination_offset (int from, int to)
406 HOST_WIDE_INT offset = 0;
408 if (from == ARG_POINTER_REGNUM)
409 offset = n_regs_saved_by_prologue () * 4;
411 if (to == STACK_POINTER_REGNUM)
413 if (current_function_outgoing_args_size >= FIXED_STACK_AREA)
414 offset += current_function_outgoing_args_size;
415 else if (current_function_outgoing_args_size)
416 offset += FIXED_STACK_AREA;
418 offset += get_frame_size ();
424 /* Emit code to load a constant CONSTANT into register REG; setting
425 RTX_FRAME_RELATED_P on all insns we generate. Make sure that the insns
426 we generate need not be split. */
429 frame_related_constant_load (rtx reg, HOST_WIDE_INT constant)
432 rtx cst = GEN_INT (constant);
434 if (constant >= -32768 && constant < 65536)
435 insn = emit_move_insn (reg, cst);
438 /* We don't call split_load_immediate here, since dwarf2out.c can get
439 confused about some of the more clever sequences it can generate. */
440 insn = emit_insn (gen_movsi_high (reg, cst));
441 RTX_FRAME_RELATED_P (insn) = 1;
442 insn = emit_insn (gen_movsi_low (reg, reg, cst));
444 RTX_FRAME_RELATED_P (insn) = 1;
447 /* Generate efficient code to add a value to the frame pointer. We
448 can use P1 as a scratch register. Set RTX_FRAME_RELATED_P on the
449 generated insns if FRAME is nonzero. */
452 add_to_sp (rtx spreg, HOST_WIDE_INT value, int frame)
457 /* Choose whether to use a sequence using a temporary register, or
458 a sequence with multiple adds. We can add a signed 7 bit value
459 in one instruction. */
460 if (value > 120 || value < -120)
462 rtx tmpreg = gen_rtx_REG (SImode, REG_P1);
466 frame_related_constant_load (tmpreg, value);
469 insn = emit_move_insn (tmpreg, GEN_INT (value));
471 RTX_FRAME_RELATED_P (insn) = 1;
474 insn = emit_insn (gen_addsi3 (spreg, spreg, tmpreg));
476 RTX_FRAME_RELATED_P (insn) = 1;
487 /* We could use -62, but that would leave the stack unaligned, so
491 insn = emit_insn (gen_addsi3 (spreg, spreg, GEN_INT (size)));
493 RTX_FRAME_RELATED_P (insn) = 1;
499 /* Generate a LINK insn for a frame sized FRAME_SIZE. If this constant
500 is too large, generate a sequence of insns that has the same effect.
501 SPREG contains (reg:SI REG_SP). */
504 emit_link_insn (rtx spreg, HOST_WIDE_INT frame_size)
506 HOST_WIDE_INT link_size = frame_size;
510 if (link_size > 262140)
513 /* Use a LINK insn with as big a constant as possible, then subtract
514 any remaining size from the SP. */
515 insn = emit_insn (gen_link (GEN_INT (-8 - link_size)));
516 RTX_FRAME_RELATED_P (insn) = 1;
518 for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
520 rtx set = XVECEXP (PATTERN (insn), 0, i);
521 if (GET_CODE (set) != SET)
523 RTX_FRAME_RELATED_P (set) = 1;
526 frame_size -= link_size;
530 /* Must use a call-clobbered PREG that isn't the static chain. */
531 rtx tmpreg = gen_rtx_REG (Pmode, REG_P1);
533 frame_related_constant_load (tmpreg, -frame_size);
534 insn = emit_insn (gen_addsi3 (spreg, spreg, tmpreg));
535 RTX_FRAME_RELATED_P (insn) = 1;
539 /* Return the number of bytes we must reserve for outgoing arguments
540 in the current function's stack frame. */
545 if (current_function_outgoing_args_size)
547 if (current_function_outgoing_args_size >= FIXED_STACK_AREA)
548 return current_function_outgoing_args_size;
550 return FIXED_STACK_AREA;
555 /* Save RETS and FP, and allocate a stack frame. */
558 do_link (rtx spreg, HOST_WIDE_INT frame_size)
560 frame_size += arg_area_size ();
562 if (stack_frame_needed_p ()
563 || (must_save_fp_p () && ! current_function_is_leaf))
564 emit_link_insn (spreg, frame_size);
567 if (! current_function_is_leaf)
569 rtx pat = gen_movsi (gen_rtx_MEM (Pmode,
570 gen_rtx_PRE_DEC (Pmode, spreg)),
572 rtx insn = emit_insn (pat);
573 RTX_FRAME_RELATED_P (insn) = 1;
575 if (must_save_fp_p ())
577 rtx pat = gen_movsi (gen_rtx_MEM (Pmode,
578 gen_rtx_PRE_DEC (Pmode, spreg)),
579 gen_rtx_REG (Pmode, REG_FP));
580 rtx insn = emit_insn (pat);
581 RTX_FRAME_RELATED_P (insn) = 1;
583 add_to_sp (spreg, -frame_size, 1);
587 /* Like do_link, but used for epilogues to deallocate the stack frame. */
590 do_unlink (rtx spreg, HOST_WIDE_INT frame_size)
592 frame_size += arg_area_size ();
594 if (stack_frame_needed_p ())
595 emit_insn (gen_unlink ());
598 rtx postinc = gen_rtx_MEM (Pmode, gen_rtx_POST_INC (Pmode, spreg));
600 add_to_sp (spreg, frame_size, 0);
601 if (must_save_fp_p ())
603 rtx fpreg = gen_rtx_REG (Pmode, REG_FP);
604 emit_move_insn (fpreg, postinc);
605 emit_insn (gen_rtx_USE (VOIDmode, fpreg));
607 if (! current_function_is_leaf)
609 emit_move_insn (bfin_rets_rtx, postinc);
610 emit_insn (gen_rtx_USE (VOIDmode, bfin_rets_rtx));
615 /* Generate a prologue suitable for a function of kind FKIND. This is
616 called for interrupt and exception handler prologues.
617 SPREG contains (reg:SI REG_SP). */
620 expand_interrupt_handler_prologue (rtx spreg, e_funkind fkind)
623 HOST_WIDE_INT frame_size = get_frame_size ();
624 rtx predec1 = gen_rtx_PRE_DEC (SImode, spreg);
625 rtx predec = gen_rtx_MEM (SImode, predec1);
627 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
628 tree all = lookup_attribute ("saveall", attrs);
629 tree kspisusp = lookup_attribute ("kspisusp", attrs);
633 insn = emit_move_insn (spreg, gen_rtx_REG (Pmode, REG_USP));
634 RTX_FRAME_RELATED_P (insn) = 1;
637 /* We need space on the stack in case we need to save the argument
639 if (fkind == EXCPT_HANDLER)
641 insn = emit_insn (gen_addsi3 (spreg, spreg, GEN_INT (-12)));
642 RTX_FRAME_RELATED_P (insn) = 1;
645 insn = emit_move_insn (predec, gen_rtx_REG (SImode, REG_ASTAT));
646 RTX_FRAME_RELATED_P (insn) = 1;
648 expand_prologue_reg_save (spreg, all != NULL_TREE);
650 for (i = REG_P7 + 1; i < REG_CC; i++)
653 || (!leaf_function_p () && call_used_regs[i]))
655 if (i == REG_A0 || i == REG_A1)
656 insn = emit_move_insn (gen_rtx_MEM (PDImode, predec1),
657 gen_rtx_REG (PDImode, i));
659 insn = emit_move_insn (predec, gen_rtx_REG (SImode, i));
660 RTX_FRAME_RELATED_P (insn) = 1;
663 if (lookup_attribute ("nesting", attrs))
665 rtx srcreg = gen_rtx_REG (Pmode, (fkind == EXCPT_HANDLER ? REG_RETX
666 : fkind == NMI_HANDLER ? REG_RETN
668 insn = emit_move_insn (predec, srcreg);
669 RTX_FRAME_RELATED_P (insn) = 1;
672 do_link (spreg, frame_size);
674 if (fkind == EXCPT_HANDLER)
676 rtx r0reg = gen_rtx_REG (SImode, REG_R0);
677 rtx r1reg = gen_rtx_REG (SImode, REG_R1);
678 rtx r2reg = gen_rtx_REG (SImode, REG_R2);
681 insn = emit_move_insn (r0reg, gen_rtx_REG (SImode, REG_SEQSTAT));
682 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx,
684 insn = emit_insn (gen_ashrsi3 (r0reg, r0reg, GEN_INT (26)));
685 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx,
687 insn = emit_insn (gen_ashlsi3 (r0reg, r0reg, GEN_INT (26)));
688 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx,
690 insn = emit_move_insn (r1reg, spreg);
691 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx,
693 insn = emit_move_insn (r2reg, gen_rtx_REG (Pmode, REG_FP));
694 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx,
696 insn = emit_insn (gen_addsi3 (r2reg, r2reg, GEN_INT (8)));
697 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx,
702 /* Generate an epilogue suitable for a function of kind FKIND. This is
703 called for interrupt and exception handler epilogues.
704 SPREG contains (reg:SI REG_SP). */
707 expand_interrupt_handler_epilogue (rtx spreg, e_funkind fkind)
710 rtx postinc1 = gen_rtx_POST_INC (SImode, spreg);
711 rtx postinc = gen_rtx_MEM (SImode, postinc1);
712 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
713 tree all = lookup_attribute ("saveall", attrs);
715 /* A slightly crude technique to stop flow from trying to delete "dead"
717 MEM_VOLATILE_P (postinc) = 1;
719 do_unlink (spreg, get_frame_size ());
721 if (lookup_attribute ("nesting", attrs))
723 rtx srcreg = gen_rtx_REG (Pmode, (fkind == EXCPT_HANDLER ? REG_RETX
724 : fkind == NMI_HANDLER ? REG_RETN
726 emit_move_insn (srcreg, postinc);
729 for (i = REG_CC - 1; i > REG_P7; i--)
732 || (!leaf_function_p () && call_used_regs[i]))
734 if (i == REG_A0 || i == REG_A1)
736 rtx mem = gen_rtx_MEM (PDImode, postinc1);
737 MEM_VOLATILE_P (mem) = 1;
738 emit_move_insn (gen_rtx_REG (PDImode, i), mem);
741 emit_move_insn (gen_rtx_REG (SImode, i), postinc);
744 expand_epilogue_reg_restore (spreg, all != NULL_TREE);
746 emit_move_insn (gen_rtx_REG (SImode, REG_ASTAT), postinc);
748 /* Deallocate any space we left on the stack in case we needed to save the
749 argument registers. */
750 if (fkind == EXCPT_HANDLER)
751 emit_insn (gen_addsi3 (spreg, spreg, GEN_INT (12)));
753 emit_jump_insn (gen_return_internal (GEN_INT (fkind)));
756 /* Generate RTL for the prologue of the current function. */
759 bfin_expand_prologue (void)
762 HOST_WIDE_INT frame_size = get_frame_size ();
763 rtx spreg = gen_rtx_REG (Pmode, REG_SP);
764 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
766 if (fkind != SUBROUTINE)
768 expand_interrupt_handler_prologue (spreg, fkind);
772 expand_prologue_reg_save (spreg, 0);
774 do_link (spreg, frame_size);
776 if (TARGET_ID_SHARED_LIBRARY
777 && (current_function_uses_pic_offset_table
778 || !current_function_is_leaf))
782 if (bfin_lib_id_given)
783 addr = plus_constant (pic_offset_table_rtx, -4 - bfin_library_id * 4);
785 addr = gen_rtx_PLUS (Pmode, pic_offset_table_rtx,
786 gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx),
787 UNSPEC_LIBRARY_OFFSET));
788 insn = emit_insn (gen_movsi (pic_offset_table_rtx,
789 gen_rtx_MEM (Pmode, addr)));
790 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx, NULL);
794 /* Generate RTL for the epilogue of the current function. NEED_RETURN is zero
795 if this is for a sibcall. EH_RETURN is nonzero if we're expanding an
796 eh_return pattern. */
799 bfin_expand_epilogue (int need_return, int eh_return)
801 rtx spreg = gen_rtx_REG (Pmode, REG_SP);
802 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
804 if (fkind != SUBROUTINE)
806 expand_interrupt_handler_epilogue (spreg, fkind);
810 do_unlink (spreg, get_frame_size ());
812 expand_epilogue_reg_restore (spreg, 0);
814 /* Omit the return insn if this is for a sibcall. */
819 emit_insn (gen_addsi3 (spreg, spreg, gen_rtx_REG (Pmode, REG_P2)));
821 emit_jump_insn (gen_return_internal (GEN_INT (SUBROUTINE)));
824 /* Return nonzero if register OLD_REG can be renamed to register NEW_REG. */
827 bfin_hard_regno_rename_ok (unsigned int old_reg ATTRIBUTE_UNUSED,
828 unsigned int new_reg)
830 /* Interrupt functions can only use registers that have already been
831 saved by the prologue, even if they would normally be
834 if (funkind (TREE_TYPE (current_function_decl)) != SUBROUTINE
835 && !regs_ever_live[new_reg])
841 /* Return the value of the return address for the frame COUNT steps up
842 from the current frame, after the prologue.
843 We punt for everything but the current frame by returning const0_rtx. */
846 bfin_return_addr_rtx (int count)
851 return get_hard_reg_initial_val (Pmode, REG_RETS);
854 /* Try machine-dependent ways of modifying an illegitimate address X
855 to be legitimate. If we find one, return the new, valid address,
856 otherwise return NULL_RTX.
858 OLDX is the address as it was before break_out_memory_refs was called.
859 In some cases it is useful to look at this to decide what needs to be done.
861 MODE is the mode of the memory reference. */
864 legitimize_address (rtx x ATTRIBUTE_UNUSED, rtx oldx ATTRIBUTE_UNUSED,
865 enum machine_mode mode ATTRIBUTE_UNUSED)
870 /* This predicate is used to compute the length of a load/store insn.
871 OP is a MEM rtx, we return nonzero if its addressing mode requires a
872 32 bit instruction. */
875 effective_address_32bit_p (rtx op, enum machine_mode mode)
877 HOST_WIDE_INT offset;
879 mode = GET_MODE (op);
882 if (REG_P (op) || GET_CODE (op) == POST_INC
883 || GET_CODE (op) == PRE_DEC || GET_CODE (op) == POST_DEC)
885 if (GET_CODE (op) != PLUS)
888 offset = INTVAL (XEXP (op, 1));
890 /* All byte loads use a 16 bit offset. */
891 if (GET_MODE_SIZE (mode) == 1)
894 if (GET_MODE_SIZE (mode) == 4)
896 /* Frame pointer relative loads can use a negative offset, all others
897 are restricted to a small positive one. */
898 if (XEXP (op, 0) == frame_pointer_rtx)
899 return offset < -128 || offset > 60;
900 return offset < 0 || offset > 60;
903 /* Must be HImode now. */
904 return offset < 0 || offset > 30;
907 /* Return cost of the memory address ADDR.
908 All addressing modes are equally cheap on the Blackfin. */
911 bfin_address_cost (rtx addr ATTRIBUTE_UNUSED)
916 /* Subroutine of print_operand; used to print a memory reference X to FILE. */
919 print_address_operand (FILE *file, rtx x)
921 if (GET_CODE (x) == MEM)
924 switch (GET_CODE (x))
927 output_address (XEXP (x, 0));
929 output_address (XEXP (x, 1));
933 fprintf (file, "--");
934 output_address (XEXP (x, 0));
937 output_address (XEXP (x, 0));
938 fprintf (file, "++");
941 output_address (XEXP (x, 0));
942 fprintf (file, "--");
946 print_operand (file, x, 0);
950 /* Adding intp DImode support by Tony
956 print_operand (FILE *file, rtx x, char code)
958 enum machine_mode mode = GET_MODE (x);
963 switch (GET_CODE (x))
969 fprintf (file, "ne");
978 fprintf (file, "ge");
981 fprintf (file, "le");
990 fprintf (file, "ge");
993 fprintf (file, "le");
996 output_operand_lossage ("invalid %%j value");
1000 case 'J': /* reverse logic */
1001 switch (GET_CODE(x))
1004 fprintf (file, "ne");
1007 fprintf (file, "e");
1010 fprintf (file, "le");
1013 fprintf (file, "ge");
1016 fprintf (file, "l");
1019 fprintf (file, "g");
1022 fprintf (file, "le");
1025 fprintf (file, "ge");
1028 fprintf (file, "l");
1031 fprintf (file, "g");
1034 output_operand_lossage ("invalid %%J value");
1039 switch (GET_CODE (x))
1044 gcc_assert (REGNO (x) < 32);
1045 fprintf (file, "%s", short_reg_names[REGNO (x)]);
1046 /*fprintf (file, "\n%d\n ", REGNO (x));*/
1049 else if (code == 'd')
1051 gcc_assert (REGNO (x) < 32);
1052 fprintf (file, "%s", high_reg_names[REGNO (x)]);
1055 else if (code == 'w')
1057 gcc_assert (REGNO (x) == REG_A0 || REGNO (x) == REG_A1);
1058 fprintf (file, "%s.w", reg_names[REGNO (x)]);
1060 else if (code == 'x')
1062 gcc_assert (REGNO (x) == REG_A0 || REGNO (x) == REG_A1);
1063 fprintf (file, "%s.x", reg_names[REGNO (x)]);
1065 else if (code == 'D')
1067 fprintf (file, "%s", dregs_pair_names[REGNO (x)]);
1069 else if (code == 'H')
1071 gcc_assert (mode == DImode || mode == DFmode);
1072 gcc_assert (REG_P (x));
1073 fprintf (file, "%s", reg_names[REGNO (x) + 1]);
1075 else if (code == 'T')
1079 fprintf (file, "%s", byte_reg_names[REGNO (x)]);
1082 fprintf (file, "%s", reg_names[REGNO (x)]);
1088 print_address_operand (file, x);
1093 /* Moves to half registers with d or h modifiers always use unsigned
1096 x = GEN_INT ((INTVAL (x) >> 16) & 0xffff);
1097 else if (code == 'h')
1098 x = GEN_INT (INTVAL (x) & 0xffff);
1099 else if (code == 'X')
1100 x = GEN_INT (exact_log2 (0xffffffff & INTVAL (x)));
1101 else if (code == 'Y')
1102 x = GEN_INT (exact_log2 (0xffffffff & ~INTVAL (x)));
1103 else if (code == 'Z')
1104 /* Used for LINK insns. */
1105 x = GEN_INT (-8 - INTVAL (x));
1110 output_addr_const (file, x);
1111 if (code == 'G' && flag_pic)
1112 fprintf (file, "@GOT");
1116 output_operand_lossage ("invalid const_double operand");
1120 if (XINT (x, 1) == UNSPEC_MOVE_PIC)
1122 output_addr_const (file, XVECEXP (x, 0, 0));
1123 fprintf (file, "@GOT");
1125 else if (XINT (x, 1) == UNSPEC_LIBRARY_OFFSET)
1126 fprintf (file, "_current_shared_library_p5_offset_");
1132 output_addr_const (file, x);
1137 /* Argument support functions. */
1139 /* Initialize a variable CUM of type CUMULATIVE_ARGS
1140 for a call to a function whose data type is FNTYPE.
1141 For a library call, FNTYPE is 0.
1142 VDSP C Compiler manual, our ABI says that
1143 first 3 words of arguments will use R0, R1 and R2.
1147 init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype ATTRIBUTE_UNUSED,
1148 rtx libname ATTRIBUTE_UNUSED)
1150 static CUMULATIVE_ARGS zero_cum;
1154 /* Set up the number of registers to use for passing arguments. */
1156 cum->nregs = max_arg_registers;
1157 cum->arg_regs = arg_regs;
1162 /* Update the data in CUM to advance over an argument
1163 of mode MODE and data type TYPE.
1164 (TYPE is null for libcalls where that information may not be available.) */
1167 function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
1168 int named ATTRIBUTE_UNUSED)
1170 int count, bytes, words;
1172 bytes = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
1173 words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
1175 cum->words += words;
1176 cum->nregs -= words;
1178 if (cum->nregs <= 0)
1181 cum->arg_regs = NULL;
1185 for (count = 1; count <= words; count++)
1192 /* Define where to put the arguments to a function.
1193 Value is zero to push the argument on the stack,
1194 or a hard register in which to store the argument.
1196 MODE is the argument's machine mode.
1197 TYPE is the data type of the argument (as a tree).
1198 This is null for libcalls where that information may
1200 CUM is a variable of type CUMULATIVE_ARGS which gives info about
1201 the preceding args and about the function being called.
1202 NAMED is nonzero if this argument is a named parameter
1203 (otherwise it is an extra parameter matching an ellipsis). */
1206 function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
1207 int named ATTRIBUTE_UNUSED)
1210 = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
1216 return gen_rtx_REG (mode, *(cum->arg_regs));
1221 /* For an arg passed partly in registers and partly in memory,
1222 this is the number of bytes passed in registers.
1223 For args passed entirely in registers or entirely in memory, zero.
1225 Refer VDSP C Compiler manual, our ABI.
1226 First 3 words are in registers. So, if a an argument is larger
1227 than the registers available, it will span the register and
1231 bfin_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode,
1232 tree type ATTRIBUTE_UNUSED,
1233 bool named ATTRIBUTE_UNUSED)
1236 = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
1237 int bytes_left = cum->nregs * UNITS_PER_WORD;
1242 if (bytes_left == 0)
1244 if (bytes > bytes_left)
1249 /* Variable sized types are passed by reference. */
1252 bfin_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
1253 enum machine_mode mode ATTRIBUTE_UNUSED,
1254 tree type, bool named ATTRIBUTE_UNUSED)
1256 return type && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST;
1259 /* Decide whether a type should be returned in memory (true)
1260 or in a register (false). This is called by the macro
1261 RETURN_IN_MEMORY. */
1264 bfin_return_in_memory (tree type)
1267 enum machine_mode mode = TYPE_MODE (type);
1269 if (mode == BLKmode)
1271 size = int_size_in_bytes (type);
1272 if (VECTOR_MODE_P (mode) || mode == TImode)
1274 /* User-created vectors small enough to fit in REG. */
1277 if (size == 8 || size == 16)
1286 /* Register in which address to store a structure value
1287 is passed to a function. */
1289 bfin_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
1290 int incoming ATTRIBUTE_UNUSED)
1292 return gen_rtx_REG (Pmode, REG_P0);
1295 /* Return true when register may be used to pass function parameters. */
1298 function_arg_regno_p (int n)
1301 for (i = 0; arg_regs[i] != -1; i++)
1302 if (n == arg_regs[i])
1307 /* Returns 1 if OP contains a symbol reference */
1310 symbolic_reference_mentioned_p (rtx op)
1312 register const char *fmt;
1315 if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF)
1318 fmt = GET_RTX_FORMAT (GET_CODE (op));
1319 for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
1325 for (j = XVECLEN (op, i) - 1; j >= 0; j--)
1326 if (symbolic_reference_mentioned_p (XVECEXP (op, i, j)))
1330 else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i)))
1337 /* Decide whether we can make a sibling call to a function. DECL is the
1338 declaration of the function being targeted by the call and EXP is the
1339 CALL_EXPR representing the call. */
1342 bfin_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED,
1343 tree exp ATTRIBUTE_UNUSED)
1348 /* Emit RTL insns to initialize the variable parts of a trampoline at
1349 TRAMP. FNADDR is an RTX for the address of the function's pure
1350 code. CXT is an RTX for the static chain value for the function. */
1353 initialize_trampoline (tramp, fnaddr, cxt)
1354 rtx tramp, fnaddr, cxt;
1356 rtx t1 = copy_to_reg (fnaddr);
1357 rtx t2 = copy_to_reg (cxt);
1360 addr = memory_address (Pmode, plus_constant (tramp, 2));
1361 emit_move_insn (gen_rtx_MEM (HImode, addr), gen_lowpart (HImode, t1));
1362 emit_insn (gen_ashrsi3 (t1, t1, GEN_INT (16)));
1363 addr = memory_address (Pmode, plus_constant (tramp, 6));
1364 emit_move_insn (gen_rtx_MEM (HImode, addr), gen_lowpart (HImode, t1));
1366 addr = memory_address (Pmode, plus_constant (tramp, 10));
1367 emit_move_insn (gen_rtx_MEM (HImode, addr), gen_lowpart (HImode, t2));
1368 emit_insn (gen_ashrsi3 (t2, t2, GEN_INT (16)));
1369 addr = memory_address (Pmode, plus_constant (tramp, 14));
1370 emit_move_insn (gen_rtx_MEM (HImode, addr), gen_lowpart (HImode, t2));
1373 /* Legitimize PIC addresses. If the address is already position-independent,
1374 we return ORIG. Newly generated position-independent addresses go into a
1375 reg. This is REG if nonzero, otherwise we allocate register(s) as
1379 legitimize_pic_address (rtx orig, rtx reg)
1384 if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == LABEL_REF)
1386 if (GET_CODE (addr) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (addr))
1394 reg = gen_reg_rtx (Pmode);
1399 emit_insn (gen_movsi_high_pic (reg, addr));
1400 emit_insn (gen_movsi_low_pic (reg, reg, addr));
1401 emit_insn (gen_addsi3 (reg, reg, pic_offset_table_rtx));
1402 new = gen_rtx_MEM (Pmode, reg);
1406 rtx tmp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr),
1408 new = gen_rtx_MEM (Pmode,
1409 gen_rtx_PLUS (Pmode, pic_offset_table_rtx,
1412 emit_move_insn (reg, new);
1414 current_function_uses_pic_offset_table = 1;
1418 else if (GET_CODE (addr) == CONST || GET_CODE (addr) == PLUS)
1422 if (GET_CODE (addr) == CONST)
1424 addr = XEXP (addr, 0);
1425 if (GET_CODE (addr) != PLUS)
1429 if (XEXP (addr, 0) == pic_offset_table_rtx)
1436 reg = gen_reg_rtx (Pmode);
1439 base = legitimize_pic_address (XEXP (addr, 0), reg);
1440 addr = legitimize_pic_address (XEXP (addr, 1),
1441 base == reg ? NULL_RTX : reg);
1443 if (GET_CODE (addr) == CONST_INT)
1445 if (! reload_in_progress && ! reload_completed)
1446 addr = force_reg (Pmode, addr);
1448 /* If we reach here, then something is seriously wrong. */
1452 if (GET_CODE (addr) == PLUS && CONSTANT_P (XEXP (addr, 1)))
1454 base = gen_rtx_PLUS (Pmode, base, XEXP (addr, 0));
1455 addr = XEXP (addr, 1);
1458 return gen_rtx_PLUS (Pmode, base, addr);
1464 /* Emit insns to move operands[1] into operands[0]. */
1467 emit_pic_move (rtx *operands, enum machine_mode mode ATTRIBUTE_UNUSED)
1469 rtx temp = reload_in_progress ? operands[0] : gen_reg_rtx (Pmode);
1471 if (GET_CODE (operands[0]) == MEM && SYMBOLIC_CONST (operands[1]))
1472 operands[1] = force_reg (SImode, operands[1]);
1474 operands[1] = legitimize_pic_address (operands[1], temp);
1477 /* Expand a move operation in mode MODE. The operands are in OPERANDS. */
1480 expand_move (rtx *operands, enum machine_mode mode)
1482 if (flag_pic && SYMBOLIC_CONST (operands[1]))
1483 emit_pic_move (operands, mode);
1485 /* Don't generate memory->memory or constant->memory moves, go through a
1487 else if ((reload_in_progress | reload_completed) == 0
1488 && GET_CODE (operands[0]) == MEM
1489 && GET_CODE (operands[1]) != REG)
1490 operands[1] = force_reg (mode, operands[1]);
1493 /* Split one or more DImode RTL references into pairs of SImode
1494 references. The RTL can be REG, offsettable MEM, integer constant, or
1495 CONST_DOUBLE. "operands" is a pointer to an array of DImode RTL to
1496 split and "num" is its length. lo_half and hi_half are output arrays
1497 that parallel "operands". */
1500 split_di (rtx operands[], int num, rtx lo_half[], rtx hi_half[])
1504 rtx op = operands[num];
1506 /* simplify_subreg refuse to split volatile memory addresses,
1507 but we still have to handle it. */
1508 if (GET_CODE (op) == MEM)
1510 lo_half[num] = adjust_address (op, SImode, 0);
1511 hi_half[num] = adjust_address (op, SImode, 4);
1515 lo_half[num] = simplify_gen_subreg (SImode, op,
1516 GET_MODE (op) == VOIDmode
1517 ? DImode : GET_MODE (op), 0);
1518 hi_half[num] = simplify_gen_subreg (SImode, op,
1519 GET_MODE (op) == VOIDmode
1520 ? DImode : GET_MODE (op), 4);
1525 /* Expand a call instruction. FNADDR is the call target, RETVAL the return value.
1526 SIBCALL is nonzero if this is a sibling call. */
1529 bfin_expand_call (rtx retval, rtx fnaddr, rtx callarg1, int sibcall)
1531 rtx use = NULL, call;
1533 /* Static functions and indirect calls don't need the pic register. */
1535 && GET_CODE (XEXP (fnaddr, 0)) == SYMBOL_REF
1536 && ! SYMBOL_REF_LOCAL_P (XEXP (fnaddr, 0)))
1537 use_reg (&use, pic_offset_table_rtx);
1539 if (! call_insn_operand (XEXP (fnaddr, 0), Pmode))
1541 fnaddr = copy_to_mode_reg (Pmode, XEXP (fnaddr, 0));
1542 fnaddr = gen_rtx_MEM (Pmode, fnaddr);
1544 call = gen_rtx_CALL (VOIDmode, fnaddr, callarg1);
1547 call = gen_rtx_SET (VOIDmode, retval, call);
1550 rtx pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (2));
1551 XVECEXP (pat, 0, 0) = call;
1552 XVECEXP (pat, 0, 1) = gen_rtx_RETURN (VOIDmode);
1555 call = emit_call_insn (call);
1557 CALL_INSN_FUNCTION_USAGE (call) = use;
1560 /* Return 1 if hard register REGNO can hold a value of machine-mode MODE. */
1563 hard_regno_mode_ok (int regno, enum machine_mode mode)
1565 /* Allow only dregs to store value of mode HI or QI */
1566 enum reg_class class = REGNO_REG_CLASS (regno);
1571 if (mode == V2HImode)
1572 return D_REGNO_P (regno);
1573 if (class == CCREGS)
1574 return mode == BImode;
1575 if (mode == PDImode)
1576 return regno == REG_A0 || regno == REG_A1;
1578 && TEST_HARD_REG_BIT (reg_class_contents[PROLOGUE_REGS], regno))
1581 return TEST_HARD_REG_BIT (reg_class_contents[MOST_REGS], regno);
1584 /* Implements target hook vector_mode_supported_p. */
1587 bfin_vector_mode_supported_p (enum machine_mode mode)
1589 return mode == V2HImode;
1592 /* Return the cost of moving data from a register in class CLASS1 to
1593 one in class CLASS2. A cost of 2 is the default. */
1596 bfin_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
1597 enum reg_class class1, enum reg_class class2)
1599 /* If optimizing for size, always prefer reg-reg over reg-memory moves. */
1603 /* There are some stalls involved when moving from a DREG to a different
1604 class reg, and using the value in one of the following instructions.
1605 Attempt to model this by slightly discouraging such moves. */
1606 if (class1 == DREGS && class2 != DREGS)
1612 /* Return the cost of moving data of mode M between a
1613 register and memory. A value of 2 is the default; this cost is
1614 relative to those in `REGISTER_MOVE_COST'.
1616 ??? In theory L1 memory has single-cycle latency. We should add a switch
1617 that tells the compiler whether we expect to use only L1 memory for the
1618 program; it'll make the costs more accurate. */
1621 bfin_memory_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
1622 enum reg_class class,
1623 int in ATTRIBUTE_UNUSED)
1625 /* Make memory accesses slightly more expensive than any register-register
1626 move. Also, penalize non-DP registers, since they need secondary
1627 reloads to load and store. */
1628 if (! reg_class_subset_p (class, DPREGS))
1634 /* Inform reload about cases where moving X with a mode MODE to a register in
1635 CLASS requires an extra scratch register. Return the class needed for the
1636 scratch register. */
1639 secondary_input_reload_class (enum reg_class class, enum machine_mode mode,
1642 /* If we have HImode or QImode, we can only use DREGS as secondary registers;
1643 in most other cases we can also use PREGS. */
1644 enum reg_class default_class = GET_MODE_SIZE (mode) >= 4 ? DPREGS : DREGS;
1645 enum reg_class x_class = NO_REGS;
1646 enum rtx_code code = GET_CODE (x);
1649 x = SUBREG_REG (x), code = GET_CODE (x);
1652 int regno = REGNO (x);
1653 if (regno >= FIRST_PSEUDO_REGISTER)
1654 regno = reg_renumber[regno];
1659 x_class = REGNO_REG_CLASS (regno);
1662 /* We can be asked to reload (plus (FP) (large_constant)) into a DREG.
1663 This happens as a side effect of register elimination, and we need
1664 a scratch register to do it. */
1665 if (fp_plus_const_operand (x, mode))
1667 rtx op2 = XEXP (x, 1);
1668 int large_constant_p = ! CONST_7BIT_IMM_P (INTVAL (op2));
1670 if (class == PREGS || class == PREGS_CLOBBERED)
1672 /* If destination is a DREG, we can do this without a scratch register
1673 if the constant is valid for an add instruction. */
1674 if (class == DREGS || class == DPREGS)
1675 return large_constant_p ? PREGS : NO_REGS;
1676 /* Reloading to anything other than a DREG? Use a PREG scratch
1681 /* Data can usually be moved freely between registers of most classes.
1682 AREGS are an exception; they can only move to or from another register
1683 in AREGS or one in DREGS. They can also be assigned the constant 0. */
1684 if (x_class == AREGS)
1685 return class == DREGS || class == AREGS ? NO_REGS : DREGS;
1689 if (x != const0_rtx && x_class != DREGS)
1695 /* CCREGS can only be moved from/to DREGS. */
1696 if (class == CCREGS && x_class != DREGS)
1698 if (x_class == CCREGS && class != DREGS)
1700 /* All registers other than AREGS can load arbitrary constants. The only
1701 case that remains is MEM. */
1703 if (! reg_class_subset_p (class, default_class))
1704 return default_class;
1708 /* Like secondary_input_reload_class; and all we do is call that function. */
1711 secondary_output_reload_class (enum reg_class class, enum machine_mode mode,
1714 return secondary_input_reload_class (class, mode, x);
1717 /* Implement TARGET_HANDLE_OPTION. */
1720 bfin_handle_option (size_t code, const char *arg, int value)
1724 case OPT_mshared_library_id_:
1725 if (value > MAX_LIBRARY_ID)
1726 error ("-mshared-library-id=%s is not between 0 and %d",
1727 arg, MAX_LIBRARY_ID);
1729 bfin_library_id = value;
1730 bfin_lib_id_given = 1;
1738 /* Implement the macro OVERRIDE_OPTIONS. */
1741 override_options (void)
1743 if (TARGET_OMIT_LEAF_FRAME_POINTER)
1744 flag_omit_frame_pointer = 1;
1746 /* Library identification */
1747 if (bfin_lib_id_given && ! TARGET_ID_SHARED_LIBRARY)
1748 error ("-mshared-library-id= specified without -mid-shared-library");
1750 if (TARGET_ID_SHARED_LIBRARY)
1751 /* ??? Provide a way to use a bigger GOT. */
1754 flag_schedule_insns = 0;
1757 /* Return the destination address of BRANCH. */
1760 branch_dest (rtx branch)
1764 rtx pat = PATTERN (branch);
1765 if (GET_CODE (pat) == PARALLEL)
1766 pat = XVECEXP (pat, 0, 0);
1767 dest = SET_SRC (pat);
1768 if (GET_CODE (dest) == IF_THEN_ELSE)
1769 dest = XEXP (dest, 1);
1770 dest = XEXP (dest, 0);
1771 dest_uid = INSN_UID (dest);
1772 return INSN_ADDRESSES (dest_uid);
1775 /* Return nonzero if INSN is annotated with a REG_BR_PROB note that indicates
1776 it's a branch that's predicted taken. */
1779 cbranch_predicted_taken_p (rtx insn)
1781 rtx x = find_reg_note (insn, REG_BR_PROB, 0);
1785 int pred_val = INTVAL (XEXP (x, 0));
1787 return pred_val >= REG_BR_PROB_BASE / 2;
1793 /* Templates for use by asm_conditional_branch. */
1795 static const char *ccbranch_templates[][3] = {
1796 { "if !cc jump %3;", "if cc jump 4 (bp); jump.s %3;", "if cc jump 6 (bp); jump.l %3;" },
1797 { "if cc jump %3;", "if !cc jump 4 (bp); jump.s %3;", "if !cc jump 6 (bp); jump.l %3;" },
1798 { "if !cc jump %3 (bp);", "if cc jump 4; jump.s %3;", "if cc jump 6; jump.l %3;" },
1799 { "if cc jump %3 (bp);", "if !cc jump 4; jump.s %3;", "if !cc jump 6; jump.l %3;" },
1802 /* Output INSN, which is a conditional branch instruction with operands
1805 We deal with the various forms of conditional branches that can be generated
1806 by bfin_reorg to prevent the hardware from doing speculative loads, by
1807 - emitting a sufficient number of nops, if N_NOPS is nonzero, or
1808 - always emitting the branch as predicted taken, if PREDICT_TAKEN is true.
1809 Either of these is only necessary if the branch is short, otherwise the
1810 template we use ends in an unconditional jump which flushes the pipeline
1814 asm_conditional_branch (rtx insn, rtx *operands, int n_nops, int predict_taken)
1816 int offset = branch_dest (insn) - INSN_ADDRESSES (INSN_UID (insn));
1817 /* Note : offset for instructions like if cc jmp; jump.[sl] offset
1818 is to be taken from start of if cc rather than jump.
1819 Range for jump.s is (-4094, 4096) instead of (-4096, 4094)
1821 int len = (offset >= -1024 && offset <= 1022 ? 0
1822 : offset >= -4094 && offset <= 4096 ? 1
1824 int bp = predict_taken && len == 0 ? 1 : cbranch_predicted_taken_p (insn);
1825 int idx = (bp << 1) | (GET_CODE (operands[0]) == EQ ? BRF : BRT);
1826 output_asm_insn (ccbranch_templates[idx][len], operands);
1827 if (n_nops > 0 && bp)
1830 while (n_nops-- > 0)
1831 output_asm_insn ("nop;", NULL);
1834 /* Emit rtl for a comparison operation CMP in mode MODE. Operands have been
1835 stored in bfin_compare_op0 and bfin_compare_op1 already. */
1838 bfin_gen_compare (rtx cmp, enum machine_mode mode ATTRIBUTE_UNUSED)
1840 enum rtx_code code1, code2;
1841 rtx op0 = bfin_compare_op0, op1 = bfin_compare_op1;
1842 rtx tem = bfin_cc_rtx;
1843 enum rtx_code code = GET_CODE (cmp);
1845 /* If we have a BImode input, then we already have a compare result, and
1846 do not need to emit another comparison. */
1847 if (GET_MODE (op0) == BImode)
1849 if ((code == NE || code == EQ) && op1 == const0_rtx)
1850 tem = op0, code2 = code;
1857 /* bfin has these conditions */
1867 code1 = reverse_condition (code);
1871 emit_insn (gen_rtx_SET (BImode, tem,
1872 gen_rtx_fmt_ee (code1, BImode, op0, op1)));
1875 return gen_rtx_fmt_ee (code2, BImode, tem, CONST0_RTX (BImode));
1878 /* Return nonzero iff C has exactly one bit set if it is interpreted
1879 as a 32 bit constant. */
1882 log2constp (unsigned HOST_WIDE_INT c)
1885 return c != 0 && (c & (c-1)) == 0;
1888 /* Returns the number of consecutive least significant zeros in the binary
1889 representation of *V.
1890 We modify *V to contain the original value arithmetically shifted right by
1891 the number of zeroes. */
1894 shiftr_zero (HOST_WIDE_INT *v)
1896 unsigned HOST_WIDE_INT tmp = *v;
1897 unsigned HOST_WIDE_INT sgn;
1903 sgn = tmp & ((unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1));
1904 while ((tmp & 0x1) == 0 && n <= 32)
1906 tmp = (tmp >> 1) | sgn;
1913 /* After reload, split the load of an immediate constant. OPERANDS are the
1914 operands of the movsi_insn pattern which we are splitting. We return
1915 nonzero if we emitted a sequence to load the constant, zero if we emitted
1916 nothing because we want to use the splitter's default sequence. */
1919 split_load_immediate (rtx operands[])
1921 HOST_WIDE_INT val = INTVAL (operands[1]);
1923 HOST_WIDE_INT shifted = val;
1924 HOST_WIDE_INT shifted_compl = ~val;
1925 int num_zero = shiftr_zero (&shifted);
1926 int num_compl_zero = shiftr_zero (&shifted_compl);
1927 unsigned int regno = REGNO (operands[0]);
1928 enum reg_class class1 = REGNO_REG_CLASS (regno);
1930 /* This case takes care of single-bit set/clear constants, which we could
1931 also implement with BITSET/BITCLR. */
1933 && shifted >= -32768 && shifted < 65536
1934 && (D_REGNO_P (regno)
1935 || (regno >= REG_P0 && regno <= REG_P7 && num_zero <= 2)))
1937 emit_insn (gen_movsi (operands[0], GEN_INT (shifted)));
1938 emit_insn (gen_ashlsi3 (operands[0], operands[0], GEN_INT (num_zero)));
1943 tmp |= -(tmp & 0x8000);
1945 /* If high word has one bit set or clear, try to use a bit operation. */
1946 if (D_REGNO_P (regno))
1948 if (log2constp (val & 0xFFFF0000))
1950 emit_insn (gen_movsi (operands[0], GEN_INT (val & 0xFFFF)));
1951 emit_insn (gen_iorsi3 (operands[0], operands[0], GEN_INT (val & 0xFFFF0000)));
1954 else if (log2constp (val | 0xFFFF) && (val & 0x8000) != 0)
1956 emit_insn (gen_movsi (operands[0], GEN_INT (tmp)));
1957 emit_insn (gen_andsi3 (operands[0], operands[0], GEN_INT (val | 0xFFFF)));
1961 if (D_REGNO_P (regno))
1963 if (CONST_7BIT_IMM_P (tmp))
1965 emit_insn (gen_movsi (operands[0], GEN_INT (tmp)));
1966 emit_insn (gen_movstricthi_high (operands[0], GEN_INT (val & -65536)));
1970 if ((val & 0xFFFF0000) == 0)
1972 emit_insn (gen_movsi (operands[0], const0_rtx));
1973 emit_insn (gen_movsi_low (operands[0], operands[0], operands[1]));
1977 if ((val & 0xFFFF0000) == 0xFFFF0000)
1979 emit_insn (gen_movsi (operands[0], constm1_rtx));
1980 emit_insn (gen_movsi_low (operands[0], operands[0], operands[1]));
1985 /* Need DREGs for the remaining case. */
1990 && num_compl_zero && CONST_7BIT_IMM_P (shifted_compl))
1992 /* If optimizing for size, generate a sequence that has more instructions
1994 emit_insn (gen_movsi (operands[0], GEN_INT (shifted_compl)));
1995 emit_insn (gen_ashlsi3 (operands[0], operands[0],
1996 GEN_INT (num_compl_zero)));
1997 emit_insn (gen_one_cmplsi2 (operands[0], operands[0]));
2003 /* Return true if the legitimate memory address for a memory operand of mode
2004 MODE. Return false if not. */
2007 bfin_valid_add (enum machine_mode mode, HOST_WIDE_INT value)
2009 unsigned HOST_WIDE_INT v = value > 0 ? value : -value;
2010 int sz = GET_MODE_SIZE (mode);
2011 int shift = sz == 1 ? 0 : sz == 2 ? 1 : 2;
2012 /* The usual offsettable_memref machinery doesn't work so well for this
2013 port, so we deal with the problem here. */
2014 unsigned HOST_WIDE_INT mask = sz == 8 ? 0x7ffe : 0x7fff;
2015 return (v & ~(mask << shift)) == 0;
2019 bfin_valid_reg_p (unsigned int regno, int strict)
2021 return ((strict && REGNO_OK_FOR_BASE_STRICT_P (regno))
2022 || (!strict && REGNO_OK_FOR_BASE_NONSTRICT_P (regno)));
2026 bfin_legitimate_address_p (enum machine_mode mode, rtx x, int strict)
2028 switch (GET_CODE (x)) {
2030 if (bfin_valid_reg_p (REGNO (x), strict))
2034 if (REG_P (XEXP (x, 0))
2035 && bfin_valid_reg_p (REGNO (XEXP (x, 0)), strict)
2036 && (GET_CODE (XEXP (x, 1)) == UNSPEC
2037 || (GET_CODE (XEXP (x, 1)) == CONST_INT
2038 && bfin_valid_add (mode, INTVAL (XEXP (x, 1))))))
2043 if (LEGITIMATE_MODE_FOR_AUTOINC_P (mode)
2044 && REG_P (XEXP (x, 0))
2045 && bfin_valid_reg_p (REGNO (XEXP (x, 0)), strict))
2048 if (LEGITIMATE_MODE_FOR_AUTOINC_P (mode)
2049 && XEXP (x, 0) == stack_pointer_rtx
2050 && REG_P (XEXP (x, 0))
2051 && bfin_valid_reg_p (REGNO (XEXP (x, 0)), strict))
2061 bfin_rtx_costs (rtx x, int code, int outer_code, int *total)
2063 int cost2 = COSTS_N_INSNS (1);
2068 if (outer_code == SET || outer_code == PLUS)
2069 *total = CONST_7BIT_IMM_P (INTVAL (x)) ? 0 : cost2;
2070 else if (outer_code == AND)
2071 *total = log2constp (~INTVAL (x)) ? 0 : cost2;
2072 else if (outer_code == LE || outer_code == LT || outer_code == EQ)
2073 *total = (INTVAL (x) >= -4 && INTVAL (x) <= 3) ? 0 : cost2;
2074 else if (outer_code == LEU || outer_code == LTU)
2075 *total = (INTVAL (x) >= 0 && INTVAL (x) <= 7) ? 0 : cost2;
2076 else if (outer_code == MULT)
2077 *total = (INTVAL (x) == 2 || INTVAL (x) == 4) ? 0 : cost2;
2078 else if (outer_code == ASHIFT && (INTVAL (x) == 1 || INTVAL (x) == 2))
2080 else if (outer_code == ASHIFT || outer_code == ASHIFTRT
2081 || outer_code == LSHIFTRT)
2082 *total = (INTVAL (x) >= 0 && INTVAL (x) <= 31) ? 0 : cost2;
2083 else if (outer_code == IOR || outer_code == XOR)
2084 *total = (INTVAL (x) & (INTVAL (x) - 1)) == 0 ? 0 : cost2;
2093 *total = COSTS_N_INSNS (2);
2097 if (GET_MODE (x) == Pmode)
2099 if (GET_CODE (XEXP (x, 0)) == MULT
2100 && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)
2102 HOST_WIDE_INT val = INTVAL (XEXP (XEXP (x, 0), 1));
2103 if (val == 2 || val == 4)
2106 *total += rtx_cost (XEXP (XEXP (x, 0), 0), outer_code);
2107 *total += rtx_cost (XEXP (x, 1), outer_code);
2119 if (GET_MODE (x) == DImode)
2126 if (GET_MODE (x) == DImode)
2131 if (GET_MODE_SIZE (GET_MODE (x)) <= UNITS_PER_WORD)
2132 *total = COSTS_N_INSNS (3);
2141 bfin_internal_label (FILE *stream, const char *prefix, unsigned long num)
2143 fprintf (stream, "%s%s$%ld:\n", LOCAL_LABEL_PREFIX, prefix, num);
2146 /* Used for communication between {push,pop}_multiple_operation (which
2147 we use not only as a predicate) and the corresponding output functions. */
2148 static int first_preg_to_save, first_dreg_to_save;
2151 push_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
2153 int lastdreg = 8, lastpreg = 6;
2156 first_preg_to_save = lastpreg;
2157 first_dreg_to_save = lastdreg;
2158 for (i = 1, group = 0; i < XVECLEN (op, 0) - 1; i++)
2160 rtx t = XVECEXP (op, 0, i);
2164 if (GET_CODE (t) != SET)
2168 dest = SET_DEST (t);
2169 if (GET_CODE (dest) != MEM || ! REG_P (src))
2171 dest = XEXP (dest, 0);
2172 if (GET_CODE (dest) != PLUS
2173 || ! REG_P (XEXP (dest, 0))
2174 || REGNO (XEXP (dest, 0)) != REG_SP
2175 || GET_CODE (XEXP (dest, 1)) != CONST_INT
2176 || INTVAL (XEXP (dest, 1)) != -i * 4)
2179 regno = REGNO (src);
2182 if (D_REGNO_P (regno))
2185 first_dreg_to_save = lastdreg = regno - REG_R0;
2187 else if (regno >= REG_P0 && regno <= REG_P7)
2190 first_preg_to_save = lastpreg = regno - REG_P0;
2200 if (regno >= REG_P0 && regno <= REG_P7)
2203 first_preg_to_save = lastpreg = regno - REG_P0;
2205 else if (regno != REG_R0 + lastdreg + 1)
2210 else if (group == 2)
2212 if (regno != REG_P0 + lastpreg + 1)
2221 pop_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
2223 int lastdreg = 8, lastpreg = 6;
2226 for (i = 1, group = 0; i < XVECLEN (op, 0); i++)
2228 rtx t = XVECEXP (op, 0, i);
2232 if (GET_CODE (t) != SET)
2236 dest = SET_DEST (t);
2237 if (GET_CODE (src) != MEM || ! REG_P (dest))
2239 src = XEXP (src, 0);
2243 if (! REG_P (src) || REGNO (src) != REG_SP)
2246 else if (GET_CODE (src) != PLUS
2247 || ! REG_P (XEXP (src, 0))
2248 || REGNO (XEXP (src, 0)) != REG_SP
2249 || GET_CODE (XEXP (src, 1)) != CONST_INT
2250 || INTVAL (XEXP (src, 1)) != (i - 1) * 4)
2253 regno = REGNO (dest);
2256 if (regno == REG_R7)
2261 else if (regno != REG_P0 + lastpreg - 1)
2266 else if (group == 1)
2268 if (regno != REG_R0 + lastdreg - 1)
2274 first_dreg_to_save = lastdreg;
2275 first_preg_to_save = lastpreg;
2279 /* Emit assembly code for one multi-register push described by INSN, with
2280 operands in OPERANDS. */
2283 output_push_multiple (rtx insn, rtx *operands)
2286 /* Validate the insn again, and compute first_[dp]reg_to_save. */
2287 if (! push_multiple_operation (PATTERN (insn), VOIDmode))
2289 if (first_dreg_to_save == 8)
2290 sprintf (buf, "[--sp] = ( p5:%d );\n", first_preg_to_save);
2291 else if (first_preg_to_save == 6)
2292 sprintf (buf, "[--sp] = ( r7:%d );\n", first_dreg_to_save);
2294 sprintf (buf, "[--sp] = ( r7:%d, p5:%d );\n", first_dreg_to_save, first_preg_to_save);
2296 output_asm_insn (buf, operands);
2299 /* Emit assembly code for one multi-register pop described by INSN, with
2300 operands in OPERANDS. */
2303 output_pop_multiple (rtx insn, rtx *operands)
2306 /* Validate the insn again, and compute first_[dp]reg_to_save. */
2307 if (! pop_multiple_operation (PATTERN (insn), VOIDmode))
2310 if (first_dreg_to_save == 8)
2311 sprintf (buf, "( p5:%d ) = [sp++];\n", first_preg_to_save);
2312 else if (first_preg_to_save == 6)
2313 sprintf (buf, "( r7:%d ) = [sp++];\n", first_dreg_to_save);
2315 sprintf (buf, "( r7:%d, p5:%d ) = [sp++];\n", first_dreg_to_save, first_preg_to_save);
2317 output_asm_insn (buf, operands);
2320 /* Adjust DST and SRC by OFFSET bytes, and generate one move in mode MODE. */
2323 single_move_for_strmov (rtx dst, rtx src, enum machine_mode mode, HOST_WIDE_INT offset)
2325 rtx scratch = gen_reg_rtx (mode);
2328 srcmem = adjust_address_nv (src, mode, offset);
2329 dstmem = adjust_address_nv (dst, mode, offset);
2330 emit_move_insn (scratch, srcmem);
2331 emit_move_insn (dstmem, scratch);
2334 /* Expand a string move operation of COUNT_EXP bytes from SRC to DST, with
2335 alignment ALIGN_EXP. Return true if successful, false if we should fall
2336 back on a different method. */
2339 bfin_expand_strmov (rtx dst, rtx src, rtx count_exp, rtx align_exp)
2341 rtx srcreg, destreg, countreg;
2342 HOST_WIDE_INT align = 0;
2343 unsigned HOST_WIDE_INT count = 0;
2345 if (GET_CODE (align_exp) == CONST_INT)
2346 align = INTVAL (align_exp);
2347 if (GET_CODE (count_exp) == CONST_INT)
2349 count = INTVAL (count_exp);
2351 if (!TARGET_INLINE_ALL_STRINGOPS && count > 64)
2356 /* If optimizing for size, only do single copies inline. */
2359 if (count == 2 && align < 2)
2361 if (count == 4 && align < 4)
2363 if (count != 1 && count != 2 && count != 4)
2366 if (align < 2 && count != 1)
2369 destreg = copy_to_mode_reg (Pmode, XEXP (dst, 0));
2370 if (destreg != XEXP (dst, 0))
2371 dst = replace_equiv_address_nv (dst, destreg);
2372 srcreg = copy_to_mode_reg (Pmode, XEXP (src, 0));
2373 if (srcreg != XEXP (src, 0))
2374 src = replace_equiv_address_nv (src, srcreg);
2376 if (count != 0 && align >= 2)
2378 unsigned HOST_WIDE_INT offset = 0;
2382 if ((count & ~3) == 4)
2384 single_move_for_strmov (dst, src, SImode, offset);
2387 else if (count & ~3)
2389 HOST_WIDE_INT new_count = ((count >> 2) & 0x3fffffff) - 1;
2390 countreg = copy_to_mode_reg (Pmode, GEN_INT (new_count));
2392 emit_insn (gen_rep_movsi (destreg, srcreg, countreg, destreg, srcreg));
2397 if ((count & ~1) == 2)
2399 single_move_for_strmov (dst, src, HImode, offset);
2402 else if (count & ~1)
2404 HOST_WIDE_INT new_count = ((count >> 1) & 0x7fffffff) - 1;
2405 countreg = copy_to_mode_reg (Pmode, GEN_INT (new_count));
2407 emit_insn (gen_rep_movhi (destreg, srcreg, countreg, destreg, srcreg));
2412 single_move_for_strmov (dst, src, HImode, offset);
2417 single_move_for_strmov (dst, src, QImode, offset);
2426 bfin_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
2428 enum attr_type insn_type, dep_insn_type;
2429 int dep_insn_code_number;
2431 /* Anti and output dependencies have zero cost. */
2432 if (REG_NOTE_KIND (link) != 0)
2435 dep_insn_code_number = recog_memoized (dep_insn);
2437 /* If we can't recognize the insns, we can't really do anything. */
2438 if (dep_insn_code_number < 0 || recog_memoized (insn) < 0)
2441 insn_type = get_attr_type (insn);
2442 dep_insn_type = get_attr_type (dep_insn);
2444 if (dep_insn_type == TYPE_MOVE || dep_insn_type == TYPE_MCLD)
2446 rtx pat = PATTERN (dep_insn);
2447 rtx dest = SET_DEST (pat);
2448 rtx src = SET_SRC (pat);
2449 if (! ADDRESS_REGNO_P (REGNO (dest)) || ! D_REGNO_P (REGNO (src)))
2451 return cost + (dep_insn_type == TYPE_MOVE ? 4 : 3);
2457 /* We use the machine specific reorg pass for emitting CSYNC instructions
2458 after conditional branches as needed.
2460 The Blackfin is unusual in that a code sequence like
2463 may speculatively perform the load even if the condition isn't true. This
2464 happens for a branch that is predicted not taken, because the pipeline
2465 isn't flushed or stalled, so the early stages of the following instructions,
2466 which perform the memory reference, are allowed to execute before the
2467 jump condition is evaluated.
2468 Therefore, we must insert additional instructions in all places where this
2469 could lead to incorrect behaviour. The manual recommends CSYNC, while
2470 VDSP seems to use NOPs (even though its corresponding compiler option is
2473 When optimizing for speed, we emit NOPs, which seems faster than a CSYNC.
2474 When optimizing for size, we turn the branch into a predicted taken one.
2475 This may be slower due to mispredicts, but saves code size. */
2480 rtx insn, last_condjump = NULL_RTX;
2481 int cycles_since_jump = INT_MAX;
2486 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
2490 if (NOTE_P (insn) || BARRIER_P (insn) || LABEL_P (insn))
2493 pat = PATTERN (insn);
2494 if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER
2495 || GET_CODE (pat) == ASM_INPUT || GET_CODE (pat) == ADDR_VEC
2496 || GET_CODE (pat) == ADDR_DIFF_VEC || asm_noperands (pat) >= 0)
2501 if (any_condjump_p (insn)
2502 && ! cbranch_predicted_taken_p (insn))
2504 last_condjump = insn;
2505 cycles_since_jump = 0;
2508 cycles_since_jump = INT_MAX;
2510 else if (INSN_P (insn))
2512 enum attr_type type = get_attr_type (insn);
2513 if (cycles_since_jump < INT_MAX)
2514 cycles_since_jump++;
2516 if (type == TYPE_MCLD && cycles_since_jump < 3)
2520 pat = single_set (insn);
2521 if (may_trap_p (SET_SRC (pat)))
2524 rtx *op = recog_data.operand;
2526 extract_insn (last_condjump);
2528 pat = gen_cbranch_predicted_taken (op[0], op[1], op[2],
2531 pat = gen_cbranch_with_nops (op[0], op[1], op[2], op[3],
2532 GEN_INT (3 - cycles_since_jump));
2533 PATTERN (last_condjump) = pat;
2534 INSN_CODE (last_condjump) = recog (pat, insn, &num_clobbers);
2535 cycles_since_jump = INT_MAX;
2542 /* Handle interrupt_handler, exception_handler and nmi_handler function
2543 attributes; arguments as in struct attribute_spec.handler. */
2546 handle_int_attribute (tree *node, tree name,
2547 tree args ATTRIBUTE_UNUSED,
2548 int flags ATTRIBUTE_UNUSED,
2552 if (TREE_CODE (x) == FUNCTION_DECL)
2555 if (TREE_CODE (x) != FUNCTION_TYPE)
2557 warning ("%qs attribute only applies to functions",
2558 IDENTIFIER_POINTER (name));
2559 *no_add_attrs = true;
2561 else if (funkind (x) != SUBROUTINE)
2562 error ("multiple function type attributes specified");
2567 /* Return 0 if the attributes for two types are incompatible, 1 if they
2568 are compatible, and 2 if they are nearly compatible (which causes a
2569 warning to be generated). */
2572 bfin_comp_type_attributes (tree type1, tree type2)
2574 e_funkind kind1, kind2;
2576 if (TREE_CODE (type1) != FUNCTION_TYPE)
2579 kind1 = funkind (type1);
2580 kind2 = funkind (type2);
2585 /* Check for mismatched modifiers */
2586 if (!lookup_attribute ("nesting", TYPE_ATTRIBUTES (type1))
2587 != !lookup_attribute ("nesting", TYPE_ATTRIBUTES (type2)))
2590 if (!lookup_attribute ("saveall", TYPE_ATTRIBUTES (type1))
2591 != !lookup_attribute ("saveall", TYPE_ATTRIBUTES (type2)))
2594 if (!lookup_attribute ("kspisusp", TYPE_ATTRIBUTES (type1))
2595 != !lookup_attribute ("kspisusp", TYPE_ATTRIBUTES (type2)))
2601 /* Table of valid machine attributes. */
2602 const struct attribute_spec bfin_attribute_table[] =
2604 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
2605 { "interrupt_handler", 0, 0, false, true, true, handle_int_attribute },
2606 { "exception_handler", 0, 0, false, true, true, handle_int_attribute },
2607 { "nmi_handler", 0, 0, false, true, true, handle_int_attribute },
2608 { "nesting", 0, 0, false, true, true, NULL },
2609 { "kspisusp", 0, 0, false, true, true, NULL },
2610 { "saveall", 0, 0, false, true, true, NULL },
2611 { NULL, 0, 0, false, false, false, NULL }
2614 /* Output the assembler code for a thunk function. THUNK_DECL is the
2615 declaration for the thunk function itself, FUNCTION is the decl for
2616 the target function. DELTA is an immediate constant offset to be
2617 added to THIS. If VCALL_OFFSET is nonzero, the word at
2618 *(*this + vcall_offset) should be added to THIS. */
2621 bfin_output_mi_thunk (FILE *file ATTRIBUTE_UNUSED,
2622 tree thunk ATTRIBUTE_UNUSED, HOST_WIDE_INT delta,
2623 HOST_WIDE_INT vcall_offset, tree function)
2626 /* The this parameter is passed as the first argument. */
2627 rtx this = gen_rtx_REG (Pmode, REG_R0);
2629 /* Adjust the this parameter by a fixed constant. */
2633 if (delta >= -64 && delta <= 63)
2635 xops[0] = GEN_INT (delta);
2636 output_asm_insn ("%1 += %0;", xops);
2638 else if (delta >= -128 && delta < -64)
2640 xops[0] = GEN_INT (delta + 64);
2641 output_asm_insn ("%1 += -64; %1 += %0;", xops);
2643 else if (delta > 63 && delta <= 126)
2645 xops[0] = GEN_INT (delta - 63);
2646 output_asm_insn ("%1 += 63; %1 += %0;", xops);
2650 xops[0] = GEN_INT (delta);
2651 output_asm_insn ("r3.l = %h0; r3.h = %d0; %1 = %1 + r3;", xops);
2655 /* Adjust the this parameter by a value stored in the vtable. */
2658 rtx p2tmp = gen_rtx_REG (Pmode, REG_P2);
2659 rtx tmp = gen_rtx_REG (Pmode, REG_R2);
2663 output_asm_insn ("%2 = r0; %2 = [%2];", xops);
2665 /* Adjust the this parameter. */
2666 xops[0] = gen_rtx_MEM (Pmode, plus_constant (p2tmp, vcall_offset));
2667 if (!memory_operand (xops[0], Pmode))
2669 rtx tmp2 = gen_rtx_REG (Pmode, REG_P1);
2670 xops[0] = GEN_INT (vcall_offset);
2672 output_asm_insn ("%h1 = %h0; %d1 = %d0; %2 = %2 + %1", xops);
2673 xops[0] = gen_rtx_MEM (Pmode, p2tmp);
2676 output_asm_insn ("%1 = %0; %2 = %2 + %1;", xops);
2679 xops[0] = XEXP (DECL_RTL (function), 0);
2680 if (1 || !flag_pic || (*targetm.binds_local_p) (function))
2681 output_asm_insn ("jump.l\t%P0", xops);
2684 #undef TARGET_ASM_GLOBALIZE_LABEL
2685 #define TARGET_ASM_GLOBALIZE_LABEL bfin_globalize_label
2687 #undef TARGET_ASM_FILE_START
2688 #define TARGET_ASM_FILE_START output_file_start
2690 #undef TARGET_ATTRIBUTE_TABLE
2691 #define TARGET_ATTRIBUTE_TABLE bfin_attribute_table
2693 #undef TARGET_COMP_TYPE_ATTRIBUTES
2694 #define TARGET_COMP_TYPE_ATTRIBUTES bfin_comp_type_attributes
2696 #undef TARGET_RTX_COSTS
2697 #define TARGET_RTX_COSTS bfin_rtx_costs
2699 #undef TARGET_ADDRESS_COST
2700 #define TARGET_ADDRESS_COST bfin_address_cost
2702 #undef TARGET_ASM_INTERNAL_LABEL
2703 #define TARGET_ASM_INTERNAL_LABEL bfin_internal_label
2705 #undef TARGET_MACHINE_DEPENDENT_REORG
2706 #define TARGET_MACHINE_DEPENDENT_REORG bfin_reorg
2708 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
2709 #define TARGET_FUNCTION_OK_FOR_SIBCALL bfin_function_ok_for_sibcall
2711 #undef TARGET_ASM_OUTPUT_MI_THUNK
2712 #define TARGET_ASM_OUTPUT_MI_THUNK bfin_output_mi_thunk
2713 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
2714 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_tree_hwi_hwi_tree_true
2716 #undef TARGET_SCHED_ADJUST_COST
2717 #define TARGET_SCHED_ADJUST_COST bfin_adjust_cost
2719 #undef TARGET_PROMOTE_PROTOTYPES
2720 #define TARGET_PROMOTE_PROTOTYPES hook_bool_tree_true
2721 #undef TARGET_PROMOTE_FUNCTION_ARGS
2722 #define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true
2723 #undef TARGET_PROMOTE_FUNCTION_RETURN
2724 #define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true
2726 #undef TARGET_ARG_PARTIAL_BYTES
2727 #define TARGET_ARG_PARTIAL_BYTES bfin_arg_partial_bytes
2729 #undef TARGET_PASS_BY_REFERENCE
2730 #define TARGET_PASS_BY_REFERENCE bfin_pass_by_reference
2732 #undef TARGET_SETUP_INCOMING_VARARGS
2733 #define TARGET_SETUP_INCOMING_VARARGS setup_incoming_varargs
2735 #undef TARGET_STRUCT_VALUE_RTX
2736 #define TARGET_STRUCT_VALUE_RTX bfin_struct_value_rtx
2738 #undef TARGET_VECTOR_MODE_SUPPORTED_P
2739 #define TARGET_VECTOR_MODE_SUPPORTED_P bfin_vector_mode_supported_p
2741 #undef TARGET_HANDLE_OPTION
2742 #define TARGET_HANDLE_OPTION bfin_handle_option
2744 struct gcc_target targetm = TARGET_INITIALIZER;