1 /* The Blackfin code generation auxiliary output file.
2 Copyright (C) 2005-2017 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 3, 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 COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
21 #define IN_TARGET_CODE 1
25 #include "coretypes.h"
30 #include "stringpool.h"
41 #include "diagnostic-core.h"
43 #include "insn-attr.h"
49 #include "langhooks.h"
50 #include "tm-constrs.h"
52 #include "sel-sched.h"
53 #include "hw-doloop.h"
57 /* This file should be included last. */
58 #include "target-def.h"
60 /* A C structure for machine-specific, per-function data.
61 This is added to the cfun structure. */
62 struct GTY(()) machine_function
64 /* Set if we are notified by the doloop pass that a hardware loop
66 int has_hardware_loops
;
68 /* Set if we create a memcpy pattern that uses loop registers. */
69 int has_loopreg_clobber
;
72 /* RTX for condition code flag register and RETS register */
73 extern GTY(()) rtx bfin_cc_rtx
;
74 extern GTY(()) rtx bfin_rets_rtx
;
75 rtx bfin_cc_rtx
, bfin_rets_rtx
;
77 int max_arg_registers
= 0;
79 /* Arrays used when emitting register names. */
80 const char *short_reg_names
[] = SHORT_REGISTER_NAMES
;
81 const char *high_reg_names
[] = HIGH_REGISTER_NAMES
;
82 const char *dregs_pair_names
[] = DREGS_PAIR_NAMES
;
83 const char *byte_reg_names
[] = BYTE_REGISTER_NAMES
;
85 static int arg_regs
[] = FUNCTION_ARG_REGISTERS
;
86 static int ret_regs
[] = FUNCTION_RETURN_REGISTERS
;
88 int splitting_for_sched
, splitting_loops
;
91 bfin_globalize_label (FILE *stream
, const char *name
)
93 fputs (".global ", stream
);
94 assemble_name (stream
, name
);
100 output_file_start (void)
102 FILE *file
= asm_out_file
;
105 fprintf (file
, ".file \"%s\";\n", LOCATION_FILE (input_location
));
107 for (i
= 0; arg_regs
[i
] >= 0; i
++)
109 max_arg_registers
= i
; /* how many arg reg used */
112 /* Examine machine-dependent attributes of function type FUNTYPE and return its
113 type. See the definition of E_FUNKIND. */
116 funkind (const_tree funtype
)
118 tree attrs
= TYPE_ATTRIBUTES (funtype
);
119 if (lookup_attribute ("interrupt_handler", attrs
))
120 return INTERRUPT_HANDLER
;
121 else if (lookup_attribute ("exception_handler", attrs
))
122 return EXCPT_HANDLER
;
123 else if (lookup_attribute ("nmi_handler", attrs
))
129 /* Legitimize PIC addresses. If the address is already position-independent,
130 we return ORIG. Newly generated position-independent addresses go into a
131 reg. This is REG if nonzero, otherwise we allocate register(s) as
132 necessary. PICREG is the register holding the pointer to the PIC offset
136 legitimize_pic_address (rtx orig
, rtx reg
, rtx picreg
)
141 if (GET_CODE (addr
) == SYMBOL_REF
|| GET_CODE (addr
) == LABEL_REF
)
146 if (TARGET_ID_SHARED_LIBRARY
)
147 unspec
= UNSPEC_MOVE_PIC
;
148 else if (GET_CODE (addr
) == SYMBOL_REF
149 && SYMBOL_REF_FUNCTION_P (addr
))
150 unspec
= UNSPEC_FUNCDESC_GOT17M4
;
152 unspec
= UNSPEC_MOVE_FDPIC
;
156 gcc_assert (can_create_pseudo_p ());
157 reg
= gen_reg_rtx (Pmode
);
160 tmp
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, addr
), unspec
);
161 new_rtx
= gen_const_mem (Pmode
, gen_rtx_PLUS (Pmode
, picreg
, tmp
));
163 emit_move_insn (reg
, new_rtx
);
164 if (picreg
== pic_offset_table_rtx
)
165 crtl
->uses_pic_offset_table
= 1;
169 else if (GET_CODE (addr
) == CONST
|| GET_CODE (addr
) == PLUS
)
173 if (GET_CODE (addr
) == CONST
)
175 addr
= XEXP (addr
, 0);
176 gcc_assert (GET_CODE (addr
) == PLUS
);
179 if (XEXP (addr
, 0) == picreg
)
184 gcc_assert (can_create_pseudo_p ());
185 reg
= gen_reg_rtx (Pmode
);
188 base
= legitimize_pic_address (XEXP (addr
, 0), reg
, picreg
);
189 addr
= legitimize_pic_address (XEXP (addr
, 1),
190 base
== reg
? NULL_RTX
: reg
,
193 if (GET_CODE (addr
) == CONST_INT
)
195 gcc_assert (! reload_in_progress
&& ! reload_completed
);
196 addr
= force_reg (Pmode
, addr
);
199 if (GET_CODE (addr
) == PLUS
&& CONSTANT_P (XEXP (addr
, 1)))
201 base
= gen_rtx_PLUS (Pmode
, base
, XEXP (addr
, 0));
202 addr
= XEXP (addr
, 1);
205 return gen_rtx_PLUS (Pmode
, base
, addr
);
211 /* Stack frame layout. */
213 /* For a given REGNO, determine whether it must be saved in the function
214 prologue. IS_INTHANDLER specifies whether we're generating a normal
215 prologue or an interrupt/exception one. */
217 must_save_p (bool is_inthandler
, unsigned regno
)
219 if (D_REGNO_P (regno
))
221 bool is_eh_return_reg
= false;
222 if (crtl
->calls_eh_return
)
227 unsigned test
= EH_RETURN_DATA_REGNO (j
);
228 if (test
== INVALID_REGNUM
)
231 is_eh_return_reg
= true;
235 return (is_eh_return_reg
236 || (df_regs_ever_live_p (regno
)
237 && !fixed_regs
[regno
]
238 && (is_inthandler
|| !call_used_regs
[regno
])));
240 else if (P_REGNO_P (regno
))
242 return ((df_regs_ever_live_p (regno
)
243 && !fixed_regs
[regno
]
244 && (is_inthandler
|| !call_used_regs
[regno
]))
246 && (ENABLE_WA_05000283
|| ENABLE_WA_05000315
)
249 && regno
== PIC_OFFSET_TABLE_REGNUM
250 && (crtl
->uses_pic_offset_table
251 || (TARGET_ID_SHARED_LIBRARY
&& !crtl
->is_leaf
))));
254 return ((is_inthandler
|| !call_used_regs
[regno
])
255 && (df_regs_ever_live_p (regno
)
256 || (!leaf_function_p () && call_used_regs
[regno
])));
260 /* Compute the number of DREGS to save with a push_multiple operation.
261 This could include registers that aren't modified in the function,
262 since push_multiple only takes a range of registers.
263 If IS_INTHANDLER, then everything that is live must be saved, even
264 if normally call-clobbered.
265 If CONSECUTIVE, return the number of registers we can save in one
266 instruction with a push/pop multiple instruction. */
269 n_dregs_to_save (bool is_inthandler
, bool consecutive
)
274 for (i
= REG_R7
+ 1; i
-- != REG_R0
;)
276 if (must_save_p (is_inthandler
, i
))
278 else if (consecutive
)
284 /* Like n_dregs_to_save, but compute number of PREGS to save. */
287 n_pregs_to_save (bool is_inthandler
, bool consecutive
)
292 for (i
= REG_P5
+ 1; i
-- != REG_P0
;)
293 if (must_save_p (is_inthandler
, i
))
295 else if (consecutive
)
300 /* Determine if we are going to save the frame pointer in the prologue. */
303 must_save_fp_p (void)
305 return df_regs_ever_live_p (REG_FP
);
308 /* Determine if we are going to save the RETS register. */
310 must_save_rets_p (void)
312 return df_regs_ever_live_p (REG_RETS
);
316 stack_frame_needed_p (void)
318 /* EH return puts a new return address into the frame using an
319 address relative to the frame pointer. */
320 if (crtl
->calls_eh_return
)
322 return frame_pointer_needed
;
325 /* Emit code to save registers in the prologue. SAVEALL is nonzero if we
326 must save all registers; this is used for interrupt handlers.
327 SPREG contains (reg:SI REG_SP). IS_INTHANDLER is true if we're doing
328 this for an interrupt (or exception) handler. */
331 expand_prologue_reg_save (rtx spreg
, int saveall
, bool is_inthandler
)
333 rtx predec1
= gen_rtx_PRE_DEC (SImode
, spreg
);
334 rtx predec
= gen_rtx_MEM (SImode
, predec1
);
335 int ndregs
= saveall
? 8 : n_dregs_to_save (is_inthandler
, false);
336 int npregs
= saveall
? 6 : n_pregs_to_save (is_inthandler
, false);
337 int ndregs_consec
= saveall
? 8 : n_dregs_to_save (is_inthandler
, true);
338 int npregs_consec
= saveall
? 6 : n_pregs_to_save (is_inthandler
, true);
340 int total_consec
= ndregs_consec
+ npregs_consec
;
343 if (saveall
|| is_inthandler
)
345 rtx_insn
*insn
= emit_move_insn (predec
, gen_rtx_REG (SImode
, REG_ASTAT
));
347 RTX_FRAME_RELATED_P (insn
) = 1;
348 for (dregno
= REG_LT0
; dregno
<= REG_LB1
; dregno
++)
350 || cfun
->machine
->has_hardware_loops
351 || cfun
->machine
->has_loopreg_clobber
352 || (ENABLE_WA_05000257
353 && (dregno
== REG_LC0
|| dregno
== REG_LC1
)))
355 insn
= emit_move_insn (predec
, gen_rtx_REG (SImode
, dregno
));
356 RTX_FRAME_RELATED_P (insn
) = 1;
360 if (total_consec
!= 0)
363 rtx val
= GEN_INT (-total_consec
* 4);
364 rtx pat
= gen_rtx_PARALLEL (VOIDmode
, rtvec_alloc (total_consec
+ 2));
366 XVECEXP (pat
, 0, 0) = gen_rtx_UNSPEC (VOIDmode
, gen_rtvec (1, val
),
367 UNSPEC_PUSH_MULTIPLE
);
368 XVECEXP (pat
, 0, total_consec
+ 1) = gen_rtx_SET (spreg
,
372 RTX_FRAME_RELATED_P (XVECEXP (pat
, 0, total_consec
+ 1)) = 1;
373 d_to_save
= ndregs_consec
;
374 dregno
= REG_R7
+ 1 - ndregs_consec
;
375 pregno
= REG_P5
+ 1 - npregs_consec
;
376 for (i
= 0; i
< total_consec
; i
++)
378 rtx memref
= gen_rtx_MEM (word_mode
,
379 gen_rtx_PLUS (Pmode
, spreg
,
380 GEN_INT (- i
* 4 - 4)));
384 subpat
= gen_rtx_SET (memref
, gen_rtx_REG (word_mode
, dregno
++));
389 subpat
= gen_rtx_SET (memref
, gen_rtx_REG (word_mode
, pregno
++));
391 XVECEXP (pat
, 0, i
+ 1) = subpat
;
392 RTX_FRAME_RELATED_P (subpat
) = 1;
394 insn
= emit_insn (pat
);
395 RTX_FRAME_RELATED_P (insn
) = 1;
398 for (dregno
= REG_R0
; ndregs
!= ndregs_consec
; dregno
++)
400 if (must_save_p (is_inthandler
, dregno
))
403 emit_move_insn (predec
, gen_rtx_REG (word_mode
, dregno
));
404 RTX_FRAME_RELATED_P (insn
) = 1;
408 for (pregno
= REG_P0
; npregs
!= npregs_consec
; pregno
++)
410 if (must_save_p (is_inthandler
, pregno
))
413 emit_move_insn (predec
, gen_rtx_REG (word_mode
, pregno
));
414 RTX_FRAME_RELATED_P (insn
) = 1;
418 for (i
= REG_P7
+ 1; i
< REG_CC
; i
++)
421 && (df_regs_ever_live_p (i
)
422 || (!leaf_function_p () && call_used_regs
[i
]))))
425 if (i
== REG_A0
|| i
== REG_A1
)
426 insn
= emit_move_insn (gen_rtx_MEM (PDImode
, predec1
),
427 gen_rtx_REG (PDImode
, i
));
429 insn
= emit_move_insn (predec
, gen_rtx_REG (SImode
, i
));
430 RTX_FRAME_RELATED_P (insn
) = 1;
434 /* Emit code to restore registers in the epilogue. SAVEALL is nonzero if we
435 must save all registers; this is used for interrupt handlers.
436 SPREG contains (reg:SI REG_SP). IS_INTHANDLER is true if we're doing
437 this for an interrupt (or exception) handler. */
440 expand_epilogue_reg_restore (rtx spreg
, bool saveall
, bool is_inthandler
)
442 rtx postinc1
= gen_rtx_POST_INC (SImode
, spreg
);
443 rtx postinc
= gen_rtx_MEM (SImode
, postinc1
);
445 int ndregs
= saveall
? 8 : n_dregs_to_save (is_inthandler
, false);
446 int npregs
= saveall
? 6 : n_pregs_to_save (is_inthandler
, false);
447 int ndregs_consec
= saveall
? 8 : n_dregs_to_save (is_inthandler
, true);
448 int npregs_consec
= saveall
? 6 : n_pregs_to_save (is_inthandler
, true);
449 int total_consec
= ndregs_consec
+ npregs_consec
;
453 /* A slightly crude technique to stop flow from trying to delete "dead"
455 MEM_VOLATILE_P (postinc
) = 1;
457 for (i
= REG_CC
- 1; i
> REG_P7
; i
--)
460 && (df_regs_ever_live_p (i
)
461 || (!leaf_function_p () && call_used_regs
[i
]))))
463 if (i
== REG_A0
|| i
== REG_A1
)
465 rtx mem
= gen_rtx_MEM (PDImode
, postinc1
);
466 MEM_VOLATILE_P (mem
) = 1;
467 emit_move_insn (gen_rtx_REG (PDImode
, i
), mem
);
470 emit_move_insn (gen_rtx_REG (SImode
, i
), postinc
);
473 regno
= REG_P5
- npregs_consec
;
474 for (; npregs
!= npregs_consec
; regno
--)
476 if (must_save_p (is_inthandler
, regno
))
478 emit_move_insn (gen_rtx_REG (word_mode
, regno
), postinc
);
482 regno
= REG_R7
- ndregs_consec
;
483 for (; ndregs
!= ndregs_consec
; regno
--)
485 if (must_save_p (is_inthandler
, regno
))
487 emit_move_insn (gen_rtx_REG (word_mode
, regno
), postinc
);
492 if (total_consec
!= 0)
494 rtx pat
= gen_rtx_PARALLEL (VOIDmode
, rtvec_alloc (total_consec
+ 1));
496 = gen_rtx_SET (spreg
, gen_rtx_PLUS (Pmode
, spreg
,
497 GEN_INT (total_consec
* 4)));
499 if (npregs_consec
> 0)
504 for (i
= 0; i
< total_consec
; i
++)
507 ? gen_rtx_PLUS (Pmode
, spreg
, GEN_INT (i
* 4))
509 rtx memref
= gen_rtx_MEM (word_mode
, addr
);
512 XVECEXP (pat
, 0, i
+ 1)
513 = gen_rtx_SET (gen_rtx_REG (word_mode
, regno
), memref
);
515 if (npregs_consec
> 0)
517 if (--npregs_consec
== 0)
522 insn
= emit_insn (pat
);
523 RTX_FRAME_RELATED_P (insn
) = 1;
525 if (saveall
|| is_inthandler
)
527 for (regno
= REG_LB1
; regno
>= REG_LT0
; regno
--)
529 || cfun
->machine
->has_hardware_loops
530 || cfun
->machine
->has_loopreg_clobber
531 || (ENABLE_WA_05000257
&& (regno
== REG_LC0
|| regno
== REG_LC1
)))
532 emit_move_insn (gen_rtx_REG (SImode
, regno
), postinc
);
534 emit_move_insn (gen_rtx_REG (SImode
, REG_ASTAT
), postinc
);
538 /* Perform any needed actions needed for a function that is receiving a
539 variable number of arguments.
543 MODE and TYPE are the mode and type of the current parameter.
545 PRETEND_SIZE is a variable that should be set to the amount of stack
546 that must be pushed by the prolog to pretend that our caller pushed
549 Normally, this macro will push all remaining incoming registers on the
550 stack and set PRETEND_SIZE to the length of the registers pushed.
553 - VDSP C compiler manual (our ABI) says that a variable args function
554 should save the R0, R1 and R2 registers in the stack.
555 - The caller will always leave space on the stack for the
556 arguments that are passed in registers, so we dont have
557 to leave any extra space.
558 - now, the vastart pointer can access all arguments from the stack. */
561 setup_incoming_varargs (cumulative_args_t cum
,
562 machine_mode mode ATTRIBUTE_UNUSED
,
563 tree type ATTRIBUTE_UNUSED
, int *pretend_size
,
572 /* The move for named arguments will be generated automatically by the
573 compiler. We need to generate the move rtx for the unnamed arguments
574 if they are in the first 3 words. We assume at least 1 named argument
575 exists, so we never generate [ARGP] = R0 here. */
577 for (i
= get_cumulative_args (cum
)->words
+ 1; i
< max_arg_registers
; i
++)
579 mem
= gen_rtx_MEM (Pmode
,
580 plus_constant (Pmode
, arg_pointer_rtx
,
581 (i
* UNITS_PER_WORD
)));
582 emit_move_insn (mem
, gen_rtx_REG (Pmode
, i
));
588 /* Value should be nonzero if functions must have frame pointers.
589 Zero means the frame pointer need not be set up (and parms may
590 be accessed via the stack pointer) in functions that seem suitable. */
593 bfin_frame_pointer_required (void)
595 e_funkind fkind
= funkind (TREE_TYPE (current_function_decl
));
597 if (fkind
!= SUBROUTINE
)
600 /* We turn on -fomit-frame-pointer if -momit-leaf-frame-pointer is used,
601 so we have to override it for non-leaf functions. */
602 if (TARGET_OMIT_LEAF_FRAME_POINTER
&& ! crtl
->is_leaf
)
608 /* Return the number of registers pushed during the prologue. */
611 n_regs_saved_by_prologue (void)
613 e_funkind fkind
= funkind (TREE_TYPE (current_function_decl
));
614 bool is_inthandler
= fkind
!= SUBROUTINE
;
615 tree attrs
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
616 bool all
= (lookup_attribute ("saveall", attrs
) != NULL_TREE
617 || (is_inthandler
&& !crtl
->is_leaf
));
618 int ndregs
= all
? 8 : n_dregs_to_save (is_inthandler
, false);
619 int npregs
= all
? 6 : n_pregs_to_save (is_inthandler
, false);
620 int n
= ndregs
+ npregs
;
623 if (all
|| stack_frame_needed_p ())
627 if (must_save_fp_p ())
629 if (must_save_rets_p ())
633 if (fkind
!= SUBROUTINE
|| all
)
635 /* Increment once for ASTAT. */
638 || cfun
->machine
->has_hardware_loops
639 || cfun
->machine
->has_loopreg_clobber
)
645 if (fkind
!= SUBROUTINE
)
648 if (lookup_attribute ("nesting", attrs
))
652 for (i
= REG_P7
+ 1; i
< REG_CC
; i
++)
654 || (fkind
!= SUBROUTINE
655 && (df_regs_ever_live_p (i
)
656 || (!leaf_function_p () && call_used_regs
[i
]))))
657 n
+= i
== REG_A0
|| i
== REG_A1
? 2 : 1;
662 /* Given FROM and TO register numbers, say whether this elimination is
663 allowed. Frame pointer elimination is automatically handled.
665 All other eliminations are valid. */
668 bfin_can_eliminate (const int from ATTRIBUTE_UNUSED
, const int to
)
670 return (to
== STACK_POINTER_REGNUM
? ! frame_pointer_needed
: true);
673 /* Return the offset between two registers, one to be eliminated, and the other
674 its replacement, at the start of a routine. */
677 bfin_initial_elimination_offset (int from
, int to
)
679 HOST_WIDE_INT offset
= 0;
681 if (from
== ARG_POINTER_REGNUM
)
682 offset
= n_regs_saved_by_prologue () * 4;
684 if (to
== STACK_POINTER_REGNUM
)
686 if (crtl
->outgoing_args_size
>= FIXED_STACK_AREA
)
687 offset
+= crtl
->outgoing_args_size
;
688 else if (crtl
->outgoing_args_size
)
689 offset
+= FIXED_STACK_AREA
;
691 offset
+= get_frame_size ();
697 /* Emit code to load a constant CONSTANT into register REG; setting
698 RTX_FRAME_RELATED_P on all insns we generate if RELATED is true.
699 Make sure that the insns we generate need not be split. */
702 frame_related_constant_load (rtx reg
, HOST_WIDE_INT constant
, bool related
)
705 rtx cst
= GEN_INT (constant
);
707 if (constant
>= -32768 && constant
< 65536)
708 insn
= emit_move_insn (reg
, cst
);
711 /* We don't call split_load_immediate here, since dwarf2out.c can get
712 confused about some of the more clever sequences it can generate. */
713 insn
= emit_insn (gen_movsi_high (reg
, cst
));
715 RTX_FRAME_RELATED_P (insn
) = 1;
716 insn
= emit_insn (gen_movsi_low (reg
, reg
, cst
));
719 RTX_FRAME_RELATED_P (insn
) = 1;
722 /* Generate efficient code to add a value to a P register.
723 Set RTX_FRAME_RELATED_P on the generated insns if FRAME is nonzero.
724 EPILOGUE_P is zero if this function is called for prologue,
725 otherwise it's nonzero. And it's less than zero if this is for
729 add_to_reg (rtx reg
, HOST_WIDE_INT value
, int frame
, int epilogue_p
)
734 /* Choose whether to use a sequence using a temporary register, or
735 a sequence with multiple adds. We can add a signed 7-bit value
736 in one instruction. */
737 if (value
> 120 || value
< -120)
745 /* For prologue or normal epilogue, P1 can be safely used
746 as the temporary register. For sibcall epilogue, we try to find
747 a call used P register, which will be restored in epilogue.
748 If we cannot find such a P register, we have to use one I register
752 tmpreg
= gen_rtx_REG (SImode
, REG_P1
);
756 for (i
= REG_P0
; i
<= REG_P5
; i
++)
757 if ((df_regs_ever_live_p (i
) && ! call_used_regs
[i
])
759 && i
== PIC_OFFSET_TABLE_REGNUM
760 && (crtl
->uses_pic_offset_table
761 || (TARGET_ID_SHARED_LIBRARY
762 && ! crtl
->is_leaf
))))
765 tmpreg
= gen_rtx_REG (SImode
, i
);
768 tmpreg
= gen_rtx_REG (SImode
, REG_P1
);
769 tmpreg2
= gen_rtx_REG (SImode
, REG_I0
);
770 emit_move_insn (tmpreg2
, tmpreg
);
775 frame_related_constant_load (tmpreg
, value
, TRUE
);
777 insn
= emit_move_insn (tmpreg
, GEN_INT (value
));
779 insn
= emit_insn (gen_addsi3 (reg
, reg
, tmpreg
));
781 RTX_FRAME_RELATED_P (insn
) = 1;
783 if (tmpreg2
!= NULL_RTX
)
784 emit_move_insn (tmpreg
, tmpreg2
);
795 /* We could use -62, but that would leave the stack unaligned, so
799 insn
= emit_insn (gen_addsi3 (reg
, reg
, GEN_INT (size
)));
801 RTX_FRAME_RELATED_P (insn
) = 1;
807 /* Generate a LINK insn for a frame sized FRAME_SIZE. If this constant
808 is too large, generate a sequence of insns that has the same effect.
809 SPREG contains (reg:SI REG_SP). */
812 emit_link_insn (rtx spreg
, HOST_WIDE_INT frame_size
)
814 HOST_WIDE_INT link_size
= frame_size
;
818 if (link_size
> 262140)
821 /* Use a LINK insn with as big a constant as possible, then subtract
822 any remaining size from the SP. */
823 insn
= emit_insn (gen_link (GEN_INT (-8 - link_size
)));
824 RTX_FRAME_RELATED_P (insn
) = 1;
826 for (i
= 0; i
< XVECLEN (PATTERN (insn
), 0); i
++)
828 rtx set
= XVECEXP (PATTERN (insn
), 0, i
);
829 gcc_assert (GET_CODE (set
) == SET
);
830 RTX_FRAME_RELATED_P (set
) = 1;
833 frame_size
-= link_size
;
837 /* Must use a call-clobbered PREG that isn't the static chain. */
838 rtx tmpreg
= gen_rtx_REG (Pmode
, REG_P1
);
840 frame_related_constant_load (tmpreg
, -frame_size
, TRUE
);
841 insn
= emit_insn (gen_addsi3 (spreg
, spreg
, tmpreg
));
842 RTX_FRAME_RELATED_P (insn
) = 1;
846 /* Return the number of bytes we must reserve for outgoing arguments
847 in the current function's stack frame. */
852 if (crtl
->outgoing_args_size
)
854 if (crtl
->outgoing_args_size
>= FIXED_STACK_AREA
)
855 return crtl
->outgoing_args_size
;
857 return FIXED_STACK_AREA
;
862 /* Save RETS and FP, and allocate a stack frame. ALL is true if the
863 function must save all its registers (true only for certain interrupt
867 do_link (rtx spreg
, HOST_WIDE_INT frame_size
, bool all
)
869 frame_size
+= arg_area_size ();
872 || stack_frame_needed_p ()
873 || (must_save_rets_p () && must_save_fp_p ()))
874 emit_link_insn (spreg
, frame_size
);
877 if (must_save_rets_p ())
879 rtx pat
= gen_movsi (gen_rtx_MEM (Pmode
,
880 gen_rtx_PRE_DEC (Pmode
, spreg
)),
882 rtx_insn
*insn
= emit_insn (pat
);
883 RTX_FRAME_RELATED_P (insn
) = 1;
885 if (must_save_fp_p ())
887 rtx pat
= gen_movsi (gen_rtx_MEM (Pmode
,
888 gen_rtx_PRE_DEC (Pmode
, spreg
)),
889 gen_rtx_REG (Pmode
, REG_FP
));
890 rtx_insn
*insn
= emit_insn (pat
);
891 RTX_FRAME_RELATED_P (insn
) = 1;
893 add_to_reg (spreg
, -frame_size
, 1, 0);
897 /* Like do_link, but used for epilogues to deallocate the stack frame.
898 EPILOGUE_P is zero if this function is called for prologue,
899 otherwise it's nonzero. And it's less than zero if this is for
903 do_unlink (rtx spreg
, HOST_WIDE_INT frame_size
, bool all
, int epilogue_p
)
905 frame_size
+= arg_area_size ();
907 if (stack_frame_needed_p ())
908 emit_insn (gen_unlink ());
911 rtx postinc
= gen_rtx_MEM (Pmode
, gen_rtx_POST_INC (Pmode
, spreg
));
913 add_to_reg (spreg
, frame_size
, 0, epilogue_p
);
914 if (all
|| must_save_fp_p ())
916 rtx fpreg
= gen_rtx_REG (Pmode
, REG_FP
);
917 emit_move_insn (fpreg
, postinc
);
920 if (all
|| must_save_rets_p ())
922 emit_move_insn (bfin_rets_rtx
, postinc
);
923 emit_use (bfin_rets_rtx
);
928 /* Generate a prologue suitable for a function of kind FKIND. This is
929 called for interrupt and exception handler prologues.
930 SPREG contains (reg:SI REG_SP). */
933 expand_interrupt_handler_prologue (rtx spreg
, e_funkind fkind
, bool all
)
935 HOST_WIDE_INT frame_size
= get_frame_size ();
936 rtx predec1
= gen_rtx_PRE_DEC (SImode
, spreg
);
937 rtx predec
= gen_rtx_MEM (SImode
, predec1
);
939 tree attrs
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
940 tree kspisusp
= lookup_attribute ("kspisusp", attrs
);
944 insn
= emit_move_insn (spreg
, gen_rtx_REG (Pmode
, REG_USP
));
945 RTX_FRAME_RELATED_P (insn
) = 1;
948 /* We need space on the stack in case we need to save the argument
950 if (fkind
== EXCPT_HANDLER
)
952 insn
= emit_insn (gen_addsi3 (spreg
, spreg
, GEN_INT (-12)));
953 RTX_FRAME_RELATED_P (insn
) = 1;
956 /* If we're calling other functions, they won't save their call-clobbered
957 registers, so we must save everything here. */
960 expand_prologue_reg_save (spreg
, all
, true);
962 if (ENABLE_WA_05000283
|| ENABLE_WA_05000315
)
964 rtx chipid
= GEN_INT (trunc_int_for_mode (0xFFC00014, SImode
));
965 rtx p5reg
= gen_rtx_REG (Pmode
, REG_P5
);
966 emit_insn (gen_movbi (bfin_cc_rtx
, const1_rtx
));
967 emit_insn (gen_movsi_high (p5reg
, chipid
));
968 emit_insn (gen_movsi_low (p5reg
, p5reg
, chipid
));
969 emit_insn (gen_dummy_load (p5reg
, bfin_cc_rtx
));
972 if (lookup_attribute ("nesting", attrs
))
974 rtx srcreg
= gen_rtx_REG (Pmode
, ret_regs
[fkind
]);
975 insn
= emit_move_insn (predec
, srcreg
);
976 RTX_FRAME_RELATED_P (insn
) = 1;
979 do_link (spreg
, frame_size
, all
);
981 if (fkind
== EXCPT_HANDLER
)
983 rtx r0reg
= gen_rtx_REG (SImode
, REG_R0
);
984 rtx r1reg
= gen_rtx_REG (SImode
, REG_R1
);
985 rtx r2reg
= gen_rtx_REG (SImode
, REG_R2
);
987 emit_move_insn (r0reg
, gen_rtx_REG (SImode
, REG_SEQSTAT
));
988 emit_insn (gen_ashrsi3 (r0reg
, r0reg
, GEN_INT (26)));
989 emit_insn (gen_ashlsi3 (r0reg
, r0reg
, GEN_INT (26)));
990 emit_move_insn (r1reg
, spreg
);
991 emit_move_insn (r2reg
, gen_rtx_REG (Pmode
, REG_FP
));
992 emit_insn (gen_addsi3 (r2reg
, r2reg
, GEN_INT (8)));
996 /* Generate an epilogue suitable for a function of kind FKIND. This is
997 called for interrupt and exception handler epilogues.
998 SPREG contains (reg:SI REG_SP). */
1001 expand_interrupt_handler_epilogue (rtx spreg
, e_funkind fkind
, bool all
)
1003 tree attrs
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
1004 rtx postinc1
= gen_rtx_POST_INC (SImode
, spreg
);
1005 rtx postinc
= gen_rtx_MEM (SImode
, postinc1
);
1007 /* A slightly crude technique to stop flow from trying to delete "dead"
1009 MEM_VOLATILE_P (postinc
) = 1;
1011 do_unlink (spreg
, get_frame_size (), all
, 1);
1013 if (lookup_attribute ("nesting", attrs
))
1015 rtx srcreg
= gen_rtx_REG (Pmode
, ret_regs
[fkind
]);
1016 emit_move_insn (srcreg
, postinc
);
1019 /* If we're calling other functions, they won't save their call-clobbered
1020 registers, so we must save (and restore) everything here. */
1024 expand_epilogue_reg_restore (spreg
, all
, true);
1026 /* Deallocate any space we left on the stack in case we needed to save the
1027 argument registers. */
1028 if (fkind
== EXCPT_HANDLER
)
1029 emit_insn (gen_addsi3 (spreg
, spreg
, GEN_INT (12)));
1031 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode
, ret_regs
[fkind
])));
1034 /* Used while emitting the prologue to generate code to load the correct value
1035 into the PIC register, which is passed in DEST. */
1038 bfin_load_pic_reg (rtx dest
)
1040 struct cgraph_local_info
*i
= NULL
;
1043 i
= cgraph_node::local_info (current_function_decl
);
1045 /* Functions local to the translation unit don't need to reload the
1046 pic reg, since the caller always passes a usable one. */
1048 return pic_offset_table_rtx
;
1050 if (global_options_set
.x_bfin_library_id
)
1051 addr
= plus_constant (Pmode
, pic_offset_table_rtx
,
1052 -4 - bfin_library_id
* 4);
1054 addr
= gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
,
1055 gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, const0_rtx
),
1056 UNSPEC_LIBRARY_OFFSET
));
1057 emit_insn (gen_movsi (dest
, gen_rtx_MEM (Pmode
, addr
)));
1061 /* Generate RTL for the prologue of the current function. */
1064 bfin_expand_prologue (void)
1066 HOST_WIDE_INT frame_size
= get_frame_size ();
1067 rtx spreg
= gen_rtx_REG (Pmode
, REG_SP
);
1068 e_funkind fkind
= funkind (TREE_TYPE (current_function_decl
));
1069 rtx pic_reg_loaded
= NULL_RTX
;
1070 tree attrs
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
1071 bool all
= lookup_attribute ("saveall", attrs
) != NULL_TREE
;
1073 if (flag_stack_usage_info
)
1074 current_function_static_stack_size
= frame_size
;
1076 if (fkind
!= SUBROUTINE
)
1078 expand_interrupt_handler_prologue (spreg
, fkind
, all
);
1082 if (crtl
->limit_stack
1083 || (TARGET_STACK_CHECK_L1
1084 && !DECL_NO_LIMIT_STACK (current_function_decl
)))
1086 HOST_WIDE_INT offset
1087 = bfin_initial_elimination_offset (ARG_POINTER_REGNUM
,
1088 STACK_POINTER_REGNUM
);
1089 rtx lim
= crtl
->limit_stack
? stack_limit_rtx
: NULL_RTX
;
1090 rtx tmp
= gen_rtx_REG (Pmode
, REG_R3
);
1091 rtx p2reg
= gen_rtx_REG (Pmode
, REG_P2
);
1093 emit_move_insn (tmp
, p2reg
);
1096 emit_move_insn (p2reg
, gen_int_mode (0xFFB00000, SImode
));
1097 emit_move_insn (p2reg
, gen_rtx_MEM (Pmode
, p2reg
));
1100 if (GET_CODE (lim
) == SYMBOL_REF
)
1102 if (TARGET_ID_SHARED_LIBRARY
)
1104 rtx p1reg
= gen_rtx_REG (Pmode
, REG_P1
);
1106 pic_reg_loaded
= bfin_load_pic_reg (p2reg
);
1107 val
= legitimize_pic_address (stack_limit_rtx
, p1reg
,
1109 emit_move_insn (p1reg
, val
);
1110 frame_related_constant_load (p2reg
, offset
, FALSE
);
1111 emit_insn (gen_addsi3 (p2reg
, p2reg
, p1reg
));
1116 rtx limit
= plus_constant (Pmode
, lim
, offset
);
1117 emit_move_insn (p2reg
, limit
);
1124 emit_move_insn (p2reg
, lim
);
1125 add_to_reg (p2reg
, offset
, 0, 0);
1128 emit_insn (gen_compare_lt (bfin_cc_rtx
, spreg
, lim
));
1129 emit_insn (gen_trapifcc ());
1130 emit_move_insn (p2reg
, tmp
);
1132 expand_prologue_reg_save (spreg
, all
, false);
1134 do_link (spreg
, frame_size
, all
);
1136 if (TARGET_ID_SHARED_LIBRARY
1138 && (crtl
->uses_pic_offset_table
1140 bfin_load_pic_reg (pic_offset_table_rtx
);
1143 /* Generate RTL for the epilogue of the current function. NEED_RETURN is zero
1144 if this is for a sibcall. EH_RETURN is nonzero if we're expanding an
1145 eh_return pattern. SIBCALL_P is true if this is a sibcall epilogue,
1149 bfin_expand_epilogue (int need_return
, int eh_return
, bool sibcall_p
)
1151 rtx spreg
= gen_rtx_REG (Pmode
, REG_SP
);
1152 e_funkind fkind
= funkind (TREE_TYPE (current_function_decl
));
1153 int e
= sibcall_p
? -1 : 1;
1154 tree attrs
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
1155 bool all
= lookup_attribute ("saveall", attrs
) != NULL_TREE
;
1157 if (fkind
!= SUBROUTINE
)
1159 expand_interrupt_handler_epilogue (spreg
, fkind
, all
);
1163 do_unlink (spreg
, get_frame_size (), all
, e
);
1165 expand_epilogue_reg_restore (spreg
, all
, false);
1167 /* Omit the return insn if this is for a sibcall. */
1172 emit_insn (gen_addsi3 (spreg
, spreg
, gen_rtx_REG (Pmode
, REG_P2
)));
1174 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode
, REG_RETS
)));
1177 /* Return nonzero if register OLD_REG can be renamed to register NEW_REG. */
1180 bfin_hard_regno_rename_ok (unsigned int old_reg ATTRIBUTE_UNUSED
,
1181 unsigned int new_reg
)
1183 /* Interrupt functions can only use registers that have already been
1184 saved by the prologue, even if they would normally be
1187 if (funkind (TREE_TYPE (current_function_decl
)) != SUBROUTINE
1188 && !df_regs_ever_live_p (new_reg
))
1194 /* Implement TARGET_EXTRA_LIVE_ON_ENTRY. */
1196 bfin_extra_live_on_entry (bitmap regs
)
1199 bitmap_set_bit (regs
, FDPIC_REGNO
);
1202 /* Return the value of the return address for the frame COUNT steps up
1203 from the current frame, after the prologue.
1204 We punt for everything but the current frame by returning const0_rtx. */
1207 bfin_return_addr_rtx (int count
)
1212 return get_hard_reg_initial_val (Pmode
, REG_RETS
);
1216 bfin_delegitimize_address (rtx orig_x
)
1220 if (GET_CODE (x
) != MEM
)
1224 if (GET_CODE (x
) == PLUS
1225 && GET_CODE (XEXP (x
, 1)) == UNSPEC
1226 && XINT (XEXP (x
, 1), 1) == UNSPEC_MOVE_PIC
1227 && GET_CODE (XEXP (x
, 0)) == REG
1228 && REGNO (XEXP (x
, 0)) == PIC_OFFSET_TABLE_REGNUM
)
1229 return XVECEXP (XEXP (x
, 1), 0, 0);
1234 /* This predicate is used to compute the length of a load/store insn.
1235 OP is a MEM rtx, we return nonzero if its addressing mode requires a
1236 32-bit instruction. */
1239 effective_address_32bit_p (rtx op
, machine_mode mode
)
1241 HOST_WIDE_INT offset
;
1243 mode
= GET_MODE (op
);
1246 if (GET_CODE (op
) != PLUS
)
1248 gcc_assert (REG_P (op
) || GET_CODE (op
) == POST_INC
1249 || GET_CODE (op
) == PRE_DEC
|| GET_CODE (op
) == POST_DEC
);
1253 if (GET_CODE (XEXP (op
, 1)) == UNSPEC
)
1256 offset
= INTVAL (XEXP (op
, 1));
1258 /* All byte loads use a 16-bit offset. */
1259 if (GET_MODE_SIZE (mode
) == 1)
1262 if (GET_MODE_SIZE (mode
) == 4)
1264 /* Frame pointer relative loads can use a negative offset, all others
1265 are restricted to a small positive one. */
1266 if (XEXP (op
, 0) == frame_pointer_rtx
)
1267 return offset
< -128 || offset
> 60;
1268 return offset
< 0 || offset
> 60;
1271 /* Must be HImode now. */
1272 return offset
< 0 || offset
> 30;
1275 /* Returns true if X is a memory reference using an I register. */
1277 bfin_dsp_memref_p (rtx x
)
1282 if (GET_CODE (x
) == POST_INC
|| GET_CODE (x
) == PRE_INC
1283 || GET_CODE (x
) == POST_DEC
|| GET_CODE (x
) == PRE_DEC
)
1288 /* Return cost of the memory address ADDR.
1289 All addressing modes are equally cheap on the Blackfin. */
1292 bfin_address_cost (rtx addr ATTRIBUTE_UNUSED
,
1293 machine_mode mode ATTRIBUTE_UNUSED
,
1294 addr_space_t as ATTRIBUTE_UNUSED
,
1295 bool speed ATTRIBUTE_UNUSED
)
1300 /* Subroutine of print_operand; used to print a memory reference X to FILE. */
1303 print_address_operand (FILE *file
, rtx x
)
1305 switch (GET_CODE (x
))
1308 output_address (VOIDmode
, XEXP (x
, 0));
1309 fprintf (file
, "+");
1310 output_address (VOIDmode
, XEXP (x
, 1));
1314 fprintf (file
, "--");
1315 output_address (VOIDmode
, XEXP (x
, 0));
1318 output_address (VOIDmode
, XEXP (x
, 0));
1319 fprintf (file
, "++");
1322 output_address (VOIDmode
, XEXP (x
, 0));
1323 fprintf (file
, "--");
1327 gcc_assert (GET_CODE (x
) != MEM
);
1328 print_operand (file
, x
, 0);
1333 /* Adding intp DImode support by Tony
1339 print_operand (FILE *file
, rtx x
, char code
)
1345 if (GET_MODE (current_output_insn
) == SImode
)
1346 fprintf (file
, " ||");
1348 fprintf (file
, ";");
1352 mode
= GET_MODE (x
);
1357 switch (GET_CODE (x
))
1360 fprintf (file
, "e");
1363 fprintf (file
, "ne");
1366 fprintf (file
, "g");
1369 fprintf (file
, "l");
1372 fprintf (file
, "ge");
1375 fprintf (file
, "le");
1378 fprintf (file
, "g");
1381 fprintf (file
, "l");
1384 fprintf (file
, "ge");
1387 fprintf (file
, "le");
1390 output_operand_lossage ("invalid %%j value");
1394 case 'J': /* reverse logic */
1395 switch (GET_CODE(x
))
1398 fprintf (file
, "ne");
1401 fprintf (file
, "e");
1404 fprintf (file
, "le");
1407 fprintf (file
, "ge");
1410 fprintf (file
, "l");
1413 fprintf (file
, "g");
1416 fprintf (file
, "le");
1419 fprintf (file
, "ge");
1422 fprintf (file
, "l");
1425 fprintf (file
, "g");
1428 output_operand_lossage ("invalid %%J value");
1433 switch (GET_CODE (x
))
1439 fprintf (file
, "%s", short_reg_names
[REGNO (x
)]);
1441 output_operand_lossage ("invalid operand for code '%c'", code
);
1443 else if (code
== 'd')
1446 fprintf (file
, "%s", high_reg_names
[REGNO (x
)]);
1448 output_operand_lossage ("invalid operand for code '%c'", code
);
1450 else if (code
== 'w')
1452 if (REGNO (x
) == REG_A0
|| REGNO (x
) == REG_A1
)
1453 fprintf (file
, "%s.w", reg_names
[REGNO (x
)]);
1455 output_operand_lossage ("invalid operand for code '%c'", code
);
1457 else if (code
== 'x')
1459 if (REGNO (x
) == REG_A0
|| REGNO (x
) == REG_A1
)
1460 fprintf (file
, "%s.x", reg_names
[REGNO (x
)]);
1462 output_operand_lossage ("invalid operand for code '%c'", code
);
1464 else if (code
== 'v')
1466 if (REGNO (x
) == REG_A0
)
1467 fprintf (file
, "AV0");
1468 else if (REGNO (x
) == REG_A1
)
1469 fprintf (file
, "AV1");
1471 output_operand_lossage ("invalid operand for code '%c'", code
);
1473 else if (code
== 'D')
1475 if (D_REGNO_P (REGNO (x
)))
1476 fprintf (file
, "%s", dregs_pair_names
[REGNO (x
)]);
1478 output_operand_lossage ("invalid operand for code '%c'", code
);
1480 else if (code
== 'H')
1482 if ((mode
== DImode
|| mode
== DFmode
) && REG_P (x
))
1483 fprintf (file
, "%s", reg_names
[REGNO (x
) + 1]);
1485 output_operand_lossage ("invalid operand for code '%c'", code
);
1487 else if (code
== 'T')
1489 if (D_REGNO_P (REGNO (x
)))
1490 fprintf (file
, "%s", byte_reg_names
[REGNO (x
)]);
1492 output_operand_lossage ("invalid operand for code '%c'", code
);
1495 fprintf (file
, "%s", reg_names
[REGNO (x
)]);
1501 print_address_operand (file
, x
);
1513 fputs ("(FU)", file
);
1516 fputs ("(T)", file
);
1519 fputs ("(TFU)", file
);
1522 fputs ("(W32)", file
);
1525 fputs ("(IS)", file
);
1528 fputs ("(IU)", file
);
1531 fputs ("(IH)", file
);
1534 fputs ("(M)", file
);
1537 fputs ("(IS,M)", file
);
1540 fputs ("(ISS2)", file
);
1543 fputs ("(S2RND)", file
);
1550 else if (code
== 'b')
1552 if (INTVAL (x
) == 0)
1554 else if (INTVAL (x
) == 1)
1560 /* Moves to half registers with d or h modifiers always use unsigned
1562 else if (code
== 'd')
1563 x
= GEN_INT ((INTVAL (x
) >> 16) & 0xffff);
1564 else if (code
== 'h')
1565 x
= GEN_INT (INTVAL (x
) & 0xffff);
1566 else if (code
== 'N')
1567 x
= GEN_INT (-INTVAL (x
));
1568 else if (code
== 'X')
1569 x
= GEN_INT (exact_log2 (0xffffffff & INTVAL (x
)));
1570 else if (code
== 'Y')
1571 x
= GEN_INT (exact_log2 (0xffffffff & ~INTVAL (x
)));
1572 else if (code
== 'Z')
1573 /* Used for LINK insns. */
1574 x
= GEN_INT (-8 - INTVAL (x
));
1579 output_addr_const (file
, x
);
1583 output_operand_lossage ("invalid const_double operand");
1587 switch (XINT (x
, 1))
1589 case UNSPEC_MOVE_PIC
:
1590 output_addr_const (file
, XVECEXP (x
, 0, 0));
1591 fprintf (file
, "@GOT");
1594 case UNSPEC_MOVE_FDPIC
:
1595 output_addr_const (file
, XVECEXP (x
, 0, 0));
1596 fprintf (file
, "@GOT17M4");
1599 case UNSPEC_FUNCDESC_GOT17M4
:
1600 output_addr_const (file
, XVECEXP (x
, 0, 0));
1601 fprintf (file
, "@FUNCDESC_GOT17M4");
1604 case UNSPEC_LIBRARY_OFFSET
:
1605 fprintf (file
, "_current_shared_library_p5_offset_");
1614 output_addr_const (file
, x
);
1619 /* Argument support functions. */
1621 /* Initialize a variable CUM of type CUMULATIVE_ARGS
1622 for a call to a function whose data type is FNTYPE.
1623 For a library call, FNTYPE is 0.
1624 VDSP C Compiler manual, our ABI says that
1625 first 3 words of arguments will use R0, R1 and R2.
1629 init_cumulative_args (CUMULATIVE_ARGS
*cum
, tree fntype
,
1630 rtx libname ATTRIBUTE_UNUSED
)
1632 static CUMULATIVE_ARGS zero_cum
;
1636 /* Set up the number of registers to use for passing arguments. */
1638 cum
->nregs
= max_arg_registers
;
1639 cum
->arg_regs
= arg_regs
;
1641 cum
->call_cookie
= CALL_NORMAL
;
1642 /* Check for a longcall attribute. */
1643 if (fntype
&& lookup_attribute ("shortcall", TYPE_ATTRIBUTES (fntype
)))
1644 cum
->call_cookie
|= CALL_SHORT
;
1645 else if (fntype
&& lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype
)))
1646 cum
->call_cookie
|= CALL_LONG
;
1651 /* Update the data in CUM to advance over an argument
1652 of mode MODE and data type TYPE.
1653 (TYPE is null for libcalls where that information may not be available.) */
1656 bfin_function_arg_advance (cumulative_args_t cum_v
, machine_mode mode
,
1657 const_tree type
, bool named ATTRIBUTE_UNUSED
)
1659 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
1660 int count
, bytes
, words
;
1662 bytes
= (mode
== BLKmode
) ? int_size_in_bytes (type
) : GET_MODE_SIZE (mode
);
1663 words
= (bytes
+ UNITS_PER_WORD
- 1) / UNITS_PER_WORD
;
1665 cum
->words
+= words
;
1666 cum
->nregs
-= words
;
1668 if (cum
->nregs
<= 0)
1671 cum
->arg_regs
= NULL
;
1675 for (count
= 1; count
<= words
; count
++)
1682 /* Define where to put the arguments to a function.
1683 Value is zero to push the argument on the stack,
1684 or a hard register in which to store the argument.
1686 MODE is the argument's machine mode.
1687 TYPE is the data type of the argument (as a tree).
1688 This is null for libcalls where that information may
1690 CUM is a variable of type CUMULATIVE_ARGS which gives info about
1691 the preceding args and about the function being called.
1692 NAMED is nonzero if this argument is a named parameter
1693 (otherwise it is an extra parameter matching an ellipsis). */
1696 bfin_function_arg (cumulative_args_t cum_v
, machine_mode mode
,
1697 const_tree type
, bool named ATTRIBUTE_UNUSED
)
1699 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
1701 = (mode
== BLKmode
) ? int_size_in_bytes (type
) : GET_MODE_SIZE (mode
);
1703 if (mode
== VOIDmode
)
1704 /* Compute operand 2 of the call insn. */
1705 return GEN_INT (cum
->call_cookie
);
1711 return gen_rtx_REG (mode
, *(cum
->arg_regs
));
1716 /* For an arg passed partly in registers and partly in memory,
1717 this is the number of bytes passed in registers.
1718 For args passed entirely in registers or entirely in memory, zero.
1720 Refer VDSP C Compiler manual, our ABI.
1721 First 3 words are in registers. So, if an argument is larger
1722 than the registers available, it will span the register and
1726 bfin_arg_partial_bytes (cumulative_args_t cum
, machine_mode mode
,
1727 tree type ATTRIBUTE_UNUSED
,
1728 bool named ATTRIBUTE_UNUSED
)
1731 = (mode
== BLKmode
) ? int_size_in_bytes (type
) : GET_MODE_SIZE (mode
);
1732 int bytes_left
= get_cumulative_args (cum
)->nregs
* UNITS_PER_WORD
;
1737 if (bytes_left
== 0)
1739 if (bytes
> bytes_left
)
1744 /* Variable sized types are passed by reference. */
1747 bfin_pass_by_reference (cumulative_args_t cum ATTRIBUTE_UNUSED
,
1748 machine_mode mode ATTRIBUTE_UNUSED
,
1749 const_tree type
, bool named ATTRIBUTE_UNUSED
)
1751 return type
&& TREE_CODE (TYPE_SIZE (type
)) != INTEGER_CST
;
1754 /* Decide whether a type should be returned in memory (true)
1755 or in a register (false). This is called by the macro
1756 TARGET_RETURN_IN_MEMORY. */
1759 bfin_return_in_memory (const_tree type
, const_tree fntype ATTRIBUTE_UNUSED
)
1761 int size
= int_size_in_bytes (type
);
1762 return size
> 2 * UNITS_PER_WORD
|| size
== -1;
1765 /* Register in which address to store a structure value
1766 is passed to a function. */
1768 bfin_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED
,
1769 int incoming ATTRIBUTE_UNUSED
)
1771 return gen_rtx_REG (Pmode
, REG_P0
);
1774 /* Return true when register may be used to pass function parameters. */
1777 function_arg_regno_p (int n
)
1780 for (i
= 0; arg_regs
[i
] != -1; i
++)
1781 if (n
== arg_regs
[i
])
1786 /* Returns 1 if OP contains a symbol reference */
1789 symbolic_reference_mentioned_p (rtx op
)
1791 register const char *fmt
;
1794 if (GET_CODE (op
) == SYMBOL_REF
|| GET_CODE (op
) == LABEL_REF
)
1797 fmt
= GET_RTX_FORMAT (GET_CODE (op
));
1798 for (i
= GET_RTX_LENGTH (GET_CODE (op
)) - 1; i
>= 0; i
--)
1804 for (j
= XVECLEN (op
, i
) - 1; j
>= 0; j
--)
1805 if (symbolic_reference_mentioned_p (XVECEXP (op
, i
, j
)))
1809 else if (fmt
[i
] == 'e' && symbolic_reference_mentioned_p (XEXP (op
, i
)))
1816 /* Decide whether we can make a sibling call to a function. DECL is the
1817 declaration of the function being targeted by the call and EXP is the
1818 CALL_EXPR representing the call. */
1821 bfin_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED
,
1822 tree exp ATTRIBUTE_UNUSED
)
1824 struct cgraph_local_info
*this_func
, *called_func
;
1825 e_funkind fkind
= funkind (TREE_TYPE (current_function_decl
));
1826 if (fkind
!= SUBROUTINE
)
1828 if (!TARGET_ID_SHARED_LIBRARY
|| TARGET_SEP_DATA
)
1831 /* When compiling for ID shared libraries, can't sibcall a local function
1832 from a non-local function, because the local function thinks it does
1833 not need to reload P5 in the prologue, but the sibcall wil pop P5 in the
1834 sibcall epilogue, and we end up with the wrong value in P5. */
1837 /* Not enough information. */
1840 this_func
= cgraph_node::local_info (current_function_decl
);
1841 called_func
= cgraph_node::local_info (decl
);
1844 return !called_func
->local
|| this_func
->local
;
1847 /* Write a template for a trampoline to F. */
1850 bfin_asm_trampoline_template (FILE *f
)
1854 fprintf (f
, "\t.dd\t0x00000000\n"); /* 0 */
1855 fprintf (f
, "\t.dd\t0x00000000\n"); /* 0 */
1856 fprintf (f
, "\t.dd\t0x0000e109\n"); /* p1.l = fn low */
1857 fprintf (f
, "\t.dd\t0x0000e149\n"); /* p1.h = fn high */
1858 fprintf (f
, "\t.dd\t0x0000e10a\n"); /* p2.l = sc low */
1859 fprintf (f
, "\t.dd\t0x0000e14a\n"); /* p2.h = sc high */
1860 fprintf (f
, "\t.dw\t0xac4b\n"); /* p3 = [p1 + 4] */
1861 fprintf (f
, "\t.dw\t0x9149\n"); /* p1 = [p1] */
1862 fprintf (f
, "\t.dw\t0x0051\n"); /* jump (p1)*/
1866 fprintf (f
, "\t.dd\t0x0000e109\n"); /* p1.l = fn low */
1867 fprintf (f
, "\t.dd\t0x0000e149\n"); /* p1.h = fn high */
1868 fprintf (f
, "\t.dd\t0x0000e10a\n"); /* p2.l = sc low */
1869 fprintf (f
, "\t.dd\t0x0000e14a\n"); /* p2.h = sc high */
1870 fprintf (f
, "\t.dw\t0x0051\n"); /* jump (p1)*/
1874 /* Emit RTL insns to initialize the variable parts of a trampoline at
1875 M_TRAMP. FNDECL is the target function. CHAIN_VALUE is an RTX for
1876 the static chain value for the function. */
1879 bfin_trampoline_init (rtx m_tramp
, tree fndecl
, rtx chain_value
)
1881 rtx t1
= copy_to_reg (XEXP (DECL_RTL (fndecl
), 0));
1882 rtx t2
= copy_to_reg (chain_value
);
1886 emit_block_move (m_tramp
, assemble_trampoline_template (),
1887 GEN_INT (TRAMPOLINE_SIZE
), BLOCK_OP_NORMAL
);
1891 rtx a
= force_reg (Pmode
, plus_constant (Pmode
, XEXP (m_tramp
, 0), 8));
1892 mem
= adjust_address (m_tramp
, Pmode
, 0);
1893 emit_move_insn (mem
, a
);
1897 mem
= adjust_address (m_tramp
, HImode
, i
+ 2);
1898 emit_move_insn (mem
, gen_lowpart (HImode
, t1
));
1899 emit_insn (gen_ashrsi3 (t1
, t1
, GEN_INT (16)));
1900 mem
= adjust_address (m_tramp
, HImode
, i
+ 6);
1901 emit_move_insn (mem
, gen_lowpart (HImode
, t1
));
1903 mem
= adjust_address (m_tramp
, HImode
, i
+ 10);
1904 emit_move_insn (mem
, gen_lowpart (HImode
, t2
));
1905 emit_insn (gen_ashrsi3 (t2
, t2
, GEN_INT (16)));
1906 mem
= adjust_address (m_tramp
, HImode
, i
+ 14);
1907 emit_move_insn (mem
, gen_lowpart (HImode
, t2
));
1910 /* Emit insns to move operands[1] into operands[0]. */
1913 emit_pic_move (rtx
*operands
, machine_mode mode ATTRIBUTE_UNUSED
)
1915 rtx temp
= reload_in_progress
? operands
[0] : gen_reg_rtx (Pmode
);
1917 gcc_assert (!TARGET_FDPIC
|| !(reload_in_progress
|| reload_completed
));
1918 if (GET_CODE (operands
[0]) == MEM
&& SYMBOLIC_CONST (operands
[1]))
1919 operands
[1] = force_reg (SImode
, operands
[1]);
1921 operands
[1] = legitimize_pic_address (operands
[1], temp
,
1922 TARGET_FDPIC
? OUR_FDPIC_REG
1923 : pic_offset_table_rtx
);
1926 /* Expand a move operation in mode MODE. The operands are in OPERANDS.
1927 Returns true if no further code must be generated, false if the caller
1928 should generate an insn to move OPERANDS[1] to OPERANDS[0]. */
1931 expand_move (rtx
*operands
, machine_mode mode
)
1933 rtx op
= operands
[1];
1934 if ((TARGET_ID_SHARED_LIBRARY
|| TARGET_FDPIC
)
1935 && SYMBOLIC_CONST (op
))
1936 emit_pic_move (operands
, mode
);
1937 else if (mode
== SImode
&& GET_CODE (op
) == CONST
1938 && GET_CODE (XEXP (op
, 0)) == PLUS
1939 && GET_CODE (XEXP (XEXP (op
, 0), 0)) == SYMBOL_REF
1940 && !targetm
.legitimate_constant_p (mode
, op
))
1942 rtx dest
= operands
[0];
1944 gcc_assert (!reload_in_progress
&& !reload_completed
);
1946 op0
= force_reg (mode
, XEXP (op
, 0));
1948 if (!insn_data
[CODE_FOR_addsi3
].operand
[2].predicate (op1
, mode
))
1949 op1
= force_reg (mode
, op1
);
1950 if (GET_CODE (dest
) == MEM
)
1951 dest
= gen_reg_rtx (mode
);
1952 emit_insn (gen_addsi3 (dest
, op0
, op1
));
1953 if (dest
== operands
[0])
1957 /* Don't generate memory->memory or constant->memory moves, go through a
1959 else if ((reload_in_progress
| reload_completed
) == 0
1960 && GET_CODE (operands
[0]) == MEM
1961 && GET_CODE (operands
[1]) != REG
)
1962 operands
[1] = force_reg (mode
, operands
[1]);
1966 /* Split one or more DImode RTL references into pairs of SImode
1967 references. The RTL can be REG, offsettable MEM, integer constant, or
1968 CONST_DOUBLE. "operands" is a pointer to an array of DImode RTL to
1969 split and "num" is its length. lo_half and hi_half are output arrays
1970 that parallel "operands". */
1973 split_di (rtx operands
[], int num
, rtx lo_half
[], rtx hi_half
[])
1977 rtx op
= operands
[num
];
1979 /* simplify_subreg refuse to split volatile memory addresses,
1980 but we still have to handle it. */
1981 if (GET_CODE (op
) == MEM
)
1983 lo_half
[num
] = adjust_address (op
, SImode
, 0);
1984 hi_half
[num
] = adjust_address (op
, SImode
, 4);
1988 lo_half
[num
] = simplify_gen_subreg (SImode
, op
,
1989 GET_MODE (op
) == VOIDmode
1990 ? DImode
: GET_MODE (op
), 0);
1991 hi_half
[num
] = simplify_gen_subreg (SImode
, op
,
1992 GET_MODE (op
) == VOIDmode
1993 ? DImode
: GET_MODE (op
), 4);
1999 bfin_longcall_p (rtx op
, int call_cookie
)
2001 gcc_assert (GET_CODE (op
) == SYMBOL_REF
);
2002 if (SYMBOL_REF_WEAK (op
))
2004 if (call_cookie
& CALL_SHORT
)
2006 if (call_cookie
& CALL_LONG
)
2008 if (TARGET_LONG_CALLS
)
2013 /* Expand a call instruction. FNADDR is the call target, RETVAL the return value.
2014 COOKIE is a CONST_INT holding the call_cookie prepared init_cumulative_args.
2015 SIBCALL is nonzero if this is a sibling call. */
2018 bfin_expand_call (rtx retval
, rtx fnaddr
, rtx callarg1
, rtx cookie
, int sibcall
)
2020 rtx use
= NULL
, call
;
2021 rtx callee
= XEXP (fnaddr
, 0);
2024 rtx picreg
= get_hard_reg_initial_val (SImode
, FDPIC_REGNO
);
2025 rtx retsreg
= gen_rtx_REG (Pmode
, REG_RETS
);
2028 /* In an untyped call, we can get NULL for operand 2. */
2029 if (cookie
== NULL_RTX
)
2030 cookie
= const0_rtx
;
2032 /* Static functions and indirect calls don't need the pic register. */
2033 if (!TARGET_FDPIC
&& flag_pic
2034 && GET_CODE (callee
) == SYMBOL_REF
2035 && !SYMBOL_REF_LOCAL_P (callee
))
2036 use_reg (&use
, pic_offset_table_rtx
);
2040 int caller_in_sram
, callee_in_sram
;
2042 /* 0 is not in sram, 1 is in L1 sram, 2 is in L2 sram. */
2043 caller_in_sram
= callee_in_sram
= 0;
2045 if (lookup_attribute ("l1_text",
2046 DECL_ATTRIBUTES (cfun
->decl
)) != NULL_TREE
)
2048 else if (lookup_attribute ("l2",
2049 DECL_ATTRIBUTES (cfun
->decl
)) != NULL_TREE
)
2052 if (GET_CODE (callee
) == SYMBOL_REF
2053 && SYMBOL_REF_DECL (callee
) && DECL_P (SYMBOL_REF_DECL (callee
)))
2055 if (lookup_attribute
2057 DECL_ATTRIBUTES (SYMBOL_REF_DECL (callee
))) != NULL_TREE
)
2059 else if (lookup_attribute
2061 DECL_ATTRIBUTES (SYMBOL_REF_DECL (callee
))) != NULL_TREE
)
2065 if (GET_CODE (callee
) != SYMBOL_REF
2066 || bfin_longcall_p (callee
, INTVAL (cookie
))
2067 || (GET_CODE (callee
) == SYMBOL_REF
2068 && !SYMBOL_REF_LOCAL_P (callee
)
2069 && TARGET_INLINE_PLT
)
2070 || caller_in_sram
!= callee_in_sram
2071 || (caller_in_sram
&& callee_in_sram
2072 && (GET_CODE (callee
) != SYMBOL_REF
2073 || !SYMBOL_REF_LOCAL_P (callee
))))
2076 if (! address_operand (addr
, Pmode
))
2077 addr
= force_reg (Pmode
, addr
);
2079 fnaddr
= gen_reg_rtx (SImode
);
2080 emit_insn (gen_load_funcdescsi (fnaddr
, addr
));
2081 fnaddr
= gen_rtx_MEM (Pmode
, fnaddr
);
2083 picreg
= gen_reg_rtx (SImode
);
2084 emit_insn (gen_load_funcdescsi (picreg
,
2085 plus_constant (Pmode
, addr
, 4)));
2090 else if ((!register_no_elim_operand (callee
, Pmode
)
2091 && GET_CODE (callee
) != SYMBOL_REF
)
2092 || (GET_CODE (callee
) == SYMBOL_REF
2093 && ((TARGET_ID_SHARED_LIBRARY
&& !TARGET_LEAF_ID_SHARED_LIBRARY
)
2094 || bfin_longcall_p (callee
, INTVAL (cookie
)))))
2096 callee
= copy_to_mode_reg (Pmode
, callee
);
2097 fnaddr
= gen_rtx_MEM (Pmode
, callee
);
2099 call
= gen_rtx_CALL (VOIDmode
, fnaddr
, callarg1
);
2102 call
= gen_rtx_SET (retval
, call
);
2104 pat
= gen_rtx_PARALLEL (VOIDmode
, rtvec_alloc (nelts
));
2106 XVECEXP (pat
, 0, n
++) = call
;
2108 XVECEXP (pat
, 0, n
++) = gen_rtx_USE (VOIDmode
, picreg
);
2109 XVECEXP (pat
, 0, n
++) = gen_rtx_USE (VOIDmode
, cookie
);
2111 XVECEXP (pat
, 0, n
++) = ret_rtx
;
2113 XVECEXP (pat
, 0, n
++) = gen_rtx_CLOBBER (VOIDmode
, retsreg
);
2114 call
= emit_call_insn (pat
);
2116 CALL_INSN_FUNCTION_USAGE (call
) = use
;
2119 /* Implement TARGET_HARD_REGNO_NREGS. */
2122 bfin_hard_regno_nregs (unsigned int regno
, machine_mode mode
)
2124 if (mode
== PDImode
&& (regno
== REG_A0
|| regno
== REG_A1
))
2126 if (mode
== V2PDImode
&& (regno
== REG_A0
|| regno
== REG_A1
))
2128 return CLASS_MAX_NREGS (GENERAL_REGS
, mode
);
2131 /* Implement TARGET_HARD_REGNO_MODE_OK.
2133 Do not allow to store a value in REG_CC for any mode.
2134 Do not allow to store value in pregs if mode is not SI. */
2136 bfin_hard_regno_mode_ok (unsigned int regno
, machine_mode mode
)
2138 /* Allow only dregs to store value of mode HI or QI */
2139 enum reg_class rclass
= REGNO_REG_CLASS (regno
);
2144 if (mode
== V2HImode
)
2145 return D_REGNO_P (regno
);
2146 if (rclass
== CCREGS
)
2147 return mode
== BImode
;
2148 if (mode
== PDImode
|| mode
== V2PDImode
)
2149 return regno
== REG_A0
|| regno
== REG_A1
;
2151 /* Allow all normal 32-bit regs, except REG_M3, in case regclass ever comes
2152 up with a bad register class (such as ALL_REGS) for DImode. */
2154 return regno
< REG_M3
;
2157 && TEST_HARD_REG_BIT (reg_class_contents
[PROLOGUE_REGS
], regno
))
2160 return TEST_HARD_REG_BIT (reg_class_contents
[MOST_REGS
], regno
);
2163 /* Implement TARGET_MODES_TIEABLE_P. */
2166 bfin_modes_tieable_p (machine_mode mode1
, machine_mode mode2
)
2168 return (mode1
== mode2
2169 || ((GET_MODE_CLASS (mode1
) == MODE_INT
2170 || GET_MODE_CLASS (mode1
) == MODE_FLOAT
)
2171 && (GET_MODE_CLASS (mode2
) == MODE_INT
2172 || GET_MODE_CLASS (mode2
) == MODE_FLOAT
)
2173 && mode1
!= BImode
&& mode2
!= BImode
2174 && GET_MODE_SIZE (mode1
) <= UNITS_PER_WORD
2175 && GET_MODE_SIZE (mode2
) <= UNITS_PER_WORD
));
2178 /* Implements target hook vector_mode_supported_p. */
2181 bfin_vector_mode_supported_p (machine_mode mode
)
2183 return mode
== V2HImode
;
2186 /* Worker function for TARGET_REGISTER_MOVE_COST. */
2189 bfin_register_move_cost (machine_mode mode
,
2190 reg_class_t class1
, reg_class_t class2
)
2192 /* These need secondary reloads, so they're more expensive. */
2193 if ((class1
== CCREGS
&& !reg_class_subset_p (class2
, DREGS
))
2194 || (class2
== CCREGS
&& !reg_class_subset_p (class1
, DREGS
)))
2197 /* If optimizing for size, always prefer reg-reg over reg-memory moves. */
2201 if (GET_MODE_CLASS (mode
) == MODE_INT
)
2203 /* Discourage trying to use the accumulators. */
2204 if (TEST_HARD_REG_BIT (reg_class_contents
[class1
], REG_A0
)
2205 || TEST_HARD_REG_BIT (reg_class_contents
[class1
], REG_A1
)
2206 || TEST_HARD_REG_BIT (reg_class_contents
[class2
], REG_A0
)
2207 || TEST_HARD_REG_BIT (reg_class_contents
[class2
], REG_A1
))
2213 /* Worker function for TARGET_MEMORY_MOVE_COST.
2215 ??? In theory L1 memory has single-cycle latency. We should add a switch
2216 that tells the compiler whether we expect to use only L1 memory for the
2217 program; it'll make the costs more accurate. */
2220 bfin_memory_move_cost (machine_mode mode ATTRIBUTE_UNUSED
,
2222 bool in ATTRIBUTE_UNUSED
)
2224 /* Make memory accesses slightly more expensive than any register-register
2225 move. Also, penalize non-DP registers, since they need secondary
2226 reloads to load and store. */
2227 if (! reg_class_subset_p (rclass
, DPREGS
))
2233 /* Inform reload about cases where moving X with a mode MODE to a register in
2234 RCLASS requires an extra scratch register. Return the class needed for the
2235 scratch register. */
2238 bfin_secondary_reload (bool in_p
, rtx x
, reg_class_t rclass_i
,
2239 machine_mode mode
, secondary_reload_info
*sri
)
2241 /* If we have HImode or QImode, we can only use DREGS as secondary registers;
2242 in most other cases we can also use PREGS. */
2243 enum reg_class default_class
= GET_MODE_SIZE (mode
) >= 4 ? DPREGS
: DREGS
;
2244 enum reg_class x_class
= NO_REGS
;
2245 enum rtx_code code
= GET_CODE (x
);
2246 enum reg_class rclass
= (enum reg_class
) rclass_i
;
2249 x
= SUBREG_REG (x
), code
= GET_CODE (x
);
2252 int regno
= REGNO (x
);
2253 if (regno
>= FIRST_PSEUDO_REGISTER
)
2254 regno
= reg_renumber
[regno
];
2259 x_class
= REGNO_REG_CLASS (regno
);
2262 /* We can be asked to reload (plus (FP) (large_constant)) into a DREG.
2263 This happens as a side effect of register elimination, and we need
2264 a scratch register to do it. */
2265 if (fp_plus_const_operand (x
, mode
))
2267 rtx op2
= XEXP (x
, 1);
2268 int large_constant_p
= ! satisfies_constraint_Ks7 (op2
);
2270 if (rclass
== PREGS
|| rclass
== PREGS_CLOBBERED
)
2272 /* If destination is a DREG, we can do this without a scratch register
2273 if the constant is valid for an add instruction. */
2274 if ((rclass
== DREGS
|| rclass
== DPREGS
)
2275 && ! large_constant_p
)
2277 /* Reloading to anything other than a DREG? Use a PREG scratch
2279 sri
->icode
= CODE_FOR_reload_insi
;
2283 /* Data can usually be moved freely between registers of most classes.
2284 AREGS are an exception; they can only move to or from another register
2285 in AREGS or one in DREGS. They can also be assigned the constant 0. */
2286 if (x_class
== AREGS
|| x_class
== EVEN_AREGS
|| x_class
== ODD_AREGS
)
2287 return (rclass
== DREGS
|| rclass
== AREGS
|| rclass
== EVEN_AREGS
2288 || rclass
== ODD_AREGS
2291 if (rclass
== AREGS
|| rclass
== EVEN_AREGS
|| rclass
== ODD_AREGS
)
2295 sri
->icode
= in_p
? CODE_FOR_reload_inpdi
: CODE_FOR_reload_outpdi
;
2299 if (x
!= const0_rtx
&& x_class
!= DREGS
)
2307 /* CCREGS can only be moved from/to DREGS. */
2308 if (rclass
== CCREGS
&& x_class
!= DREGS
)
2310 if (x_class
== CCREGS
&& rclass
!= DREGS
)
2313 /* All registers other than AREGS can load arbitrary constants. The only
2314 case that remains is MEM. */
2316 if (! reg_class_subset_p (rclass
, default_class
))
2317 return default_class
;
2322 /* Implement TARGET_CLASS_LIKELY_SPILLED_P. */
2325 bfin_class_likely_spilled_p (reg_class_t rclass
)
2329 case PREGS_CLOBBERED
:
2345 static struct machine_function
*
2346 bfin_init_machine_status (void)
2348 return ggc_cleared_alloc
<machine_function
> ();
2351 /* Implement the TARGET_OPTION_OVERRIDE hook. */
2354 bfin_option_override (void)
2356 /* If processor type is not specified, enable all workarounds. */
2357 if (bfin_cpu_type
== BFIN_CPU_UNKNOWN
)
2361 for (i
= 0; bfin_cpus
[i
].name
!= NULL
; i
++)
2362 bfin_workarounds
|= bfin_cpus
[i
].workarounds
;
2364 bfin_si_revision
= 0xffff;
2367 if (bfin_csync_anomaly
== 1)
2368 bfin_workarounds
|= WA_SPECULATIVE_SYNCS
;
2369 else if (bfin_csync_anomaly
== 0)
2370 bfin_workarounds
&= ~WA_SPECULATIVE_SYNCS
;
2372 if (bfin_specld_anomaly
== 1)
2373 bfin_workarounds
|= WA_SPECULATIVE_LOADS
;
2374 else if (bfin_specld_anomaly
== 0)
2375 bfin_workarounds
&= ~WA_SPECULATIVE_LOADS
;
2377 if (TARGET_OMIT_LEAF_FRAME_POINTER
)
2378 flag_omit_frame_pointer
= 1;
2380 #ifdef SUBTARGET_FDPIC_NOT_SUPPORTED
2382 error ("-mfdpic is not supported, please use a bfin-linux-uclibc target");
2385 /* Library identification */
2386 if (global_options_set
.x_bfin_library_id
&& ! TARGET_ID_SHARED_LIBRARY
)
2387 error ("-mshared-library-id= specified without -mid-shared-library");
2389 if (stack_limit_rtx
&& TARGET_FDPIC
)
2391 warning (0, "-fstack-limit- options are ignored with -mfdpic; use -mstack-check-l1");
2392 stack_limit_rtx
= NULL_RTX
;
2395 if (stack_limit_rtx
&& TARGET_STACK_CHECK_L1
)
2396 error ("can%'t use multiple stack checking methods together");
2398 if (TARGET_ID_SHARED_LIBRARY
&& TARGET_FDPIC
)
2399 error ("ID shared libraries and FD-PIC mode can%'t be used together");
2401 /* Don't allow the user to specify -mid-shared-library and -msep-data
2402 together, as it makes little sense from a user's point of view... */
2403 if (TARGET_SEP_DATA
&& TARGET_ID_SHARED_LIBRARY
)
2404 error ("cannot specify both -msep-data and -mid-shared-library");
2405 /* ... internally, however, it's nearly the same. */
2406 if (TARGET_SEP_DATA
)
2407 target_flags
|= MASK_ID_SHARED_LIBRARY
| MASK_LEAF_ID_SHARED_LIBRARY
;
2409 if (TARGET_ID_SHARED_LIBRARY
&& flag_pic
== 0)
2412 /* There is no single unaligned SI op for PIC code. Sometimes we
2413 need to use ".4byte" and sometimes we need to use ".picptr".
2414 See bfin_assemble_integer for details. */
2416 targetm
.asm_out
.unaligned_op
.si
= 0;
2418 /* Silently turn off flag_pic if not doing FDPIC or ID shared libraries,
2419 since we don't support it and it'll just break. */
2420 if (flag_pic
&& !TARGET_FDPIC
&& !TARGET_ID_SHARED_LIBRARY
)
2423 if (TARGET_MULTICORE
&& bfin_cpu_type
!= BFIN_CPU_BF561
)
2424 error ("-mmulticore can only be used with BF561");
2426 if (TARGET_COREA
&& !TARGET_MULTICORE
)
2427 error ("-mcorea should be used with -mmulticore");
2429 if (TARGET_COREB
&& !TARGET_MULTICORE
)
2430 error ("-mcoreb should be used with -mmulticore");
2432 if (TARGET_COREA
&& TARGET_COREB
)
2433 error ("-mcorea and -mcoreb can%'t be used together");
2435 flag_schedule_insns
= 0;
2437 init_machine_status
= bfin_init_machine_status
;
2440 /* Return the destination address of BRANCH.
2441 We need to use this instead of get_attr_length, because the
2442 cbranch_with_nops pattern conservatively sets its length to 6, and
2443 we still prefer to use shorter sequences. */
2446 branch_dest (rtx_insn
*branch
)
2450 rtx pat
= PATTERN (branch
);
2451 if (GET_CODE (pat
) == PARALLEL
)
2452 pat
= XVECEXP (pat
, 0, 0);
2453 dest
= SET_SRC (pat
);
2454 if (GET_CODE (dest
) == IF_THEN_ELSE
)
2455 dest
= XEXP (dest
, 1);
2456 dest
= XEXP (dest
, 0);
2457 dest_uid
= INSN_UID (dest
);
2458 return INSN_ADDRESSES (dest_uid
);
2461 /* Return nonzero if INSN is annotated with a REG_BR_PROB note that indicates
2462 it's a branch that's predicted taken. */
2465 cbranch_predicted_taken_p (rtx insn
)
2467 rtx x
= find_reg_note (insn
, REG_BR_PROB
, 0);
2471 return profile_probability::from_reg_br_prob_note (XINT (x
, 0))
2472 >= profile_probability::even ();
2478 /* Templates for use by asm_conditional_branch. */
2480 static const char *ccbranch_templates
[][3] = {
2481 { "if !cc jump %3;", "if cc jump 4 (bp); jump.s %3;", "if cc jump 6 (bp); jump.l %3;" },
2482 { "if cc jump %3;", "if !cc jump 4 (bp); jump.s %3;", "if !cc jump 6 (bp); jump.l %3;" },
2483 { "if !cc jump %3 (bp);", "if cc jump 4; jump.s %3;", "if cc jump 6; jump.l %3;" },
2484 { "if cc jump %3 (bp);", "if !cc jump 4; jump.s %3;", "if !cc jump 6; jump.l %3;" },
2487 /* Output INSN, which is a conditional branch instruction with operands
2490 We deal with the various forms of conditional branches that can be generated
2491 by bfin_reorg to prevent the hardware from doing speculative loads, by
2492 - emitting a sufficient number of nops, if N_NOPS is nonzero, or
2493 - always emitting the branch as predicted taken, if PREDICT_TAKEN is true.
2494 Either of these is only necessary if the branch is short, otherwise the
2495 template we use ends in an unconditional jump which flushes the pipeline
2499 asm_conditional_branch (rtx_insn
*insn
, rtx
*operands
, int n_nops
, int predict_taken
)
2501 int offset
= branch_dest (insn
) - INSN_ADDRESSES (INSN_UID (insn
));
2502 /* Note : offset for instructions like if cc jmp; jump.[sl] offset
2503 is to be taken from start of if cc rather than jump.
2504 Range for jump.s is (-4094, 4096) instead of (-4096, 4094)
2506 int len
= (offset
>= -1024 && offset
<= 1022 ? 0
2507 : offset
>= -4094 && offset
<= 4096 ? 1
2509 int bp
= predict_taken
&& len
== 0 ? 1 : cbranch_predicted_taken_p (insn
);
2510 int idx
= (bp
<< 1) | (GET_CODE (operands
[0]) == EQ
? BRF
: BRT
);
2511 output_asm_insn (ccbranch_templates
[idx
][len
], operands
);
2512 gcc_assert (n_nops
== 0 || !bp
);
2514 while (n_nops
-- > 0)
2515 output_asm_insn ("nop;", NULL
);
2518 /* Emit rtl for a comparison operation CMP in mode MODE. Operands have been
2519 stored in bfin_compare_op0 and bfin_compare_op1 already. */
2522 bfin_gen_compare (rtx cmp
, machine_mode mode ATTRIBUTE_UNUSED
)
2524 enum rtx_code code1
, code2
;
2525 rtx op0
= XEXP (cmp
, 0), op1
= XEXP (cmp
, 1);
2526 rtx tem
= bfin_cc_rtx
;
2527 enum rtx_code code
= GET_CODE (cmp
);
2529 /* If we have a BImode input, then we already have a compare result, and
2530 do not need to emit another comparison. */
2531 if (GET_MODE (op0
) == BImode
)
2533 gcc_assert ((code
== NE
|| code
== EQ
) && op1
== const0_rtx
);
2534 tem
= op0
, code2
= code
;
2539 /* bfin has these conditions */
2549 code1
= reverse_condition (code
);
2553 emit_insn (gen_rtx_SET (tem
, gen_rtx_fmt_ee (code1
, BImode
, op0
, op1
)));
2556 return gen_rtx_fmt_ee (code2
, BImode
, tem
, CONST0_RTX (BImode
));
2559 /* Return nonzero iff C has exactly one bit set if it is interpreted
2560 as a 32-bit constant. */
2563 log2constp (unsigned HOST_WIDE_INT c
)
2566 return c
!= 0 && (c
& (c
-1)) == 0;
2569 /* Returns the number of consecutive least significant zeros in the binary
2570 representation of *V.
2571 We modify *V to contain the original value arithmetically shifted right by
2572 the number of zeroes. */
2575 shiftr_zero (HOST_WIDE_INT
*v
)
2577 unsigned HOST_WIDE_INT tmp
= *v
;
2578 unsigned HOST_WIDE_INT sgn
;
2584 sgn
= tmp
& ((unsigned HOST_WIDE_INT
) 1 << (HOST_BITS_PER_WIDE_INT
- 1));
2585 while ((tmp
& 0x1) == 0 && n
<= 32)
2587 tmp
= (tmp
>> 1) | sgn
;
2594 /* After reload, split the load of an immediate constant. OPERANDS are the
2595 operands of the movsi_insn pattern which we are splitting. We return
2596 nonzero if we emitted a sequence to load the constant, zero if we emitted
2597 nothing because we want to use the splitter's default sequence. */
2600 split_load_immediate (rtx operands
[])
2602 HOST_WIDE_INT val
= INTVAL (operands
[1]);
2604 HOST_WIDE_INT shifted
= val
;
2605 HOST_WIDE_INT shifted_compl
= ~val
;
2606 int num_zero
= shiftr_zero (&shifted
);
2607 int num_compl_zero
= shiftr_zero (&shifted_compl
);
2608 unsigned int regno
= REGNO (operands
[0]);
2610 /* This case takes care of single-bit set/clear constants, which we could
2611 also implement with BITSET/BITCLR. */
2613 && shifted
>= -32768 && shifted
< 65536
2614 && (D_REGNO_P (regno
)
2615 || (regno
>= REG_P0
&& regno
<= REG_P7
&& num_zero
<= 2)))
2617 emit_insn (gen_movsi (operands
[0], gen_int_mode (shifted
, SImode
)));
2618 emit_insn (gen_ashlsi3 (operands
[0], operands
[0], GEN_INT (num_zero
)));
2623 tmp
|= -(tmp
& 0x8000);
2625 /* If high word has one bit set or clear, try to use a bit operation. */
2626 if (D_REGNO_P (regno
))
2628 if (log2constp (val
& 0xFFFF0000))
2630 emit_insn (gen_movsi (operands
[0], GEN_INT (val
& 0xFFFF)));
2631 emit_insn (gen_iorsi3 (operands
[0], operands
[0],
2632 gen_int_mode (val
& 0xFFFF0000, SImode
)));
2635 else if (log2constp (val
| 0xFFFF) && (val
& 0x8000) != 0)
2637 emit_insn (gen_movsi (operands
[0], GEN_INT (tmp
)));
2638 emit_insn (gen_andsi3 (operands
[0], operands
[0],
2639 gen_int_mode (val
| 0xFFFF, SImode
)));
2643 if (D_REGNO_P (regno
))
2645 if (tmp
>= -64 && tmp
<= 63)
2647 emit_insn (gen_movsi (operands
[0], GEN_INT (tmp
)));
2648 emit_insn (gen_movstricthi_high (operands
[0],
2649 gen_int_mode (val
& -65536,
2654 if ((val
& 0xFFFF0000) == 0)
2656 emit_insn (gen_movsi (operands
[0], const0_rtx
));
2657 emit_insn (gen_movsi_low (operands
[0], operands
[0], operands
[1]));
2661 if ((val
& 0xFFFF0000) == 0xFFFF0000)
2663 emit_insn (gen_movsi (operands
[0], constm1_rtx
));
2664 emit_insn (gen_movsi_low (operands
[0], operands
[0], operands
[1]));
2669 /* Need DREGs for the remaining case. */
2674 && num_compl_zero
&& shifted_compl
>= -64 && shifted_compl
<= 63)
2676 /* If optimizing for size, generate a sequence that has more instructions
2678 emit_insn (gen_movsi (operands
[0], gen_int_mode (shifted_compl
, SImode
)));
2679 emit_insn (gen_ashlsi3 (operands
[0], operands
[0],
2680 GEN_INT (num_compl_zero
)));
2681 emit_insn (gen_one_cmplsi2 (operands
[0], operands
[0]));
2687 /* Return true if the legitimate memory address for a memory operand of mode
2688 MODE. Return false if not. */
2691 bfin_valid_add (machine_mode mode
, HOST_WIDE_INT value
)
2693 unsigned HOST_WIDE_INT v
= value
> 0 ? value
: -value
;
2694 int sz
= GET_MODE_SIZE (mode
);
2695 int shift
= sz
== 1 ? 0 : sz
== 2 ? 1 : 2;
2696 /* The usual offsettable_memref machinery doesn't work so well for this
2697 port, so we deal with the problem here. */
2698 if (value
> 0 && sz
== 8)
2700 return (v
& ~(0x7fff << shift
)) == 0;
2704 bfin_valid_reg_p (unsigned int regno
, int strict
, machine_mode mode
,
2705 enum rtx_code outer_code
)
2708 return REGNO_OK_FOR_BASE_STRICT_P (regno
, mode
, outer_code
, SCRATCH
);
2710 return REGNO_OK_FOR_BASE_NONSTRICT_P (regno
, mode
, outer_code
, SCRATCH
);
2713 /* Recognize an RTL expression that is a valid memory address for an
2714 instruction. The MODE argument is the machine mode for the MEM expression
2715 that wants to use this address.
2717 Blackfin addressing modes are as follows:
2723 W [ Preg + uimm16m2 ]
2732 bfin_legitimate_address_p (machine_mode mode
, rtx x
, bool strict
)
2734 switch (GET_CODE (x
)) {
2736 if (bfin_valid_reg_p (REGNO (x
), strict
, mode
, MEM
))
2740 if (REG_P (XEXP (x
, 0))
2741 && bfin_valid_reg_p (REGNO (XEXP (x
, 0)), strict
, mode
, PLUS
)
2742 && ((GET_CODE (XEXP (x
, 1)) == UNSPEC
&& mode
== SImode
)
2743 || (GET_CODE (XEXP (x
, 1)) == CONST_INT
2744 && bfin_valid_add (mode
, INTVAL (XEXP (x
, 1))))))
2749 if (LEGITIMATE_MODE_FOR_AUTOINC_P (mode
)
2750 && REG_P (XEXP (x
, 0))
2751 && bfin_valid_reg_p (REGNO (XEXP (x
, 0)), strict
, mode
, POST_INC
))
2755 if (LEGITIMATE_MODE_FOR_AUTOINC_P (mode
)
2756 && XEXP (x
, 0) == stack_pointer_rtx
2757 && REG_P (XEXP (x
, 0))
2758 && bfin_valid_reg_p (REGNO (XEXP (x
, 0)), strict
, mode
, PRE_DEC
))
2767 /* Decide whether we can force certain constants to memory. If we
2768 decide we can't, the caller should be able to cope with it in
2772 bfin_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED
,
2773 rtx x ATTRIBUTE_UNUSED
)
2775 /* We have only one class of non-legitimate constants, and our movsi
2776 expander knows how to handle them. Dropping these constants into the
2777 data section would only shift the problem - we'd still get relocs
2778 outside the object, in the data section rather than the text section. */
2782 /* Ensure that for any constant of the form symbol + offset, the offset
2783 remains within the object. Any other constants are ok.
2784 This ensures that flat binaries never have to deal with relocations
2785 crossing section boundaries. */
2788 bfin_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED
, rtx x
)
2791 HOST_WIDE_INT offset
;
2793 if (GET_CODE (x
) != CONST
)
2797 gcc_assert (GET_CODE (x
) == PLUS
);
2801 if (GET_CODE (sym
) != SYMBOL_REF
2802 || GET_CODE (x
) != CONST_INT
)
2804 offset
= INTVAL (x
);
2806 if (SYMBOL_REF_DECL (sym
) == 0)
2809 || offset
>= int_size_in_bytes (TREE_TYPE (SYMBOL_REF_DECL (sym
))))
2816 bfin_rtx_costs (rtx x
, machine_mode mode
, int outer_code_i
, int opno
,
2817 int *total
, bool speed
)
2819 enum rtx_code code
= GET_CODE (x
);
2820 enum rtx_code outer_code
= (enum rtx_code
) outer_code_i
;
2821 int cost2
= COSTS_N_INSNS (1);
2827 if (outer_code
== SET
|| outer_code
== PLUS
)
2828 *total
= satisfies_constraint_Ks7 (x
) ? 0 : cost2
;
2829 else if (outer_code
== AND
)
2830 *total
= log2constp (~INTVAL (x
)) ? 0 : cost2
;
2831 else if (outer_code
== LE
|| outer_code
== LT
|| outer_code
== EQ
)
2832 *total
= (INTVAL (x
) >= -4 && INTVAL (x
) <= 3) ? 0 : cost2
;
2833 else if (outer_code
== LEU
|| outer_code
== LTU
)
2834 *total
= (INTVAL (x
) >= 0 && INTVAL (x
) <= 7) ? 0 : cost2
;
2835 else if (outer_code
== MULT
)
2836 *total
= (INTVAL (x
) == 2 || INTVAL (x
) == 4) ? 0 : cost2
;
2837 else if (outer_code
== ASHIFT
&& (INTVAL (x
) == 1 || INTVAL (x
) == 2))
2839 else if (outer_code
== ASHIFT
|| outer_code
== ASHIFTRT
2840 || outer_code
== LSHIFTRT
)
2841 *total
= (INTVAL (x
) >= 0 && INTVAL (x
) <= 31) ? 0 : cost2
;
2842 else if (outer_code
== IOR
|| outer_code
== XOR
)
2843 *total
= (INTVAL (x
) & (INTVAL (x
) - 1)) == 0 ? 0 : cost2
;
2852 *total
= COSTS_N_INSNS (2);
2860 if (GET_CODE (op0
) == MULT
2861 && GET_CODE (XEXP (op0
, 1)) == CONST_INT
)
2863 HOST_WIDE_INT val
= INTVAL (XEXP (op0
, 1));
2864 if (val
== 2 || val
== 4)
2867 *total
+= rtx_cost (XEXP (op0
, 0), mode
, outer_code
,
2869 *total
+= rtx_cost (op1
, mode
, outer_code
, opno
, speed
);
2874 if (GET_CODE (op0
) != REG
2875 && (GET_CODE (op0
) != SUBREG
|| GET_CODE (SUBREG_REG (op0
)) != REG
))
2876 *total
+= set_src_cost (op0
, mode
, speed
);
2877 #if 0 /* We'd like to do this for accuracy, but it biases the loop optimizer
2878 towards creating too many induction variables. */
2879 if (!reg_or_7bit_operand (op1
, SImode
))
2880 *total
+= set_src_cost (op1
, mode
, speed
);
2883 else if (mode
== DImode
)
2886 if (GET_CODE (op1
) != CONST_INT
2887 || !satisfies_constraint_Ks7 (op1
))
2888 *total
+= rtx_cost (op1
, mode
, PLUS
, 1, speed
);
2889 if (GET_CODE (op0
) != REG
2890 && (GET_CODE (op0
) != SUBREG
|| GET_CODE (SUBREG_REG (op0
)) != REG
))
2891 *total
+= rtx_cost (op0
, mode
, PLUS
, 0, speed
);
2912 if (GET_CODE (op0
) != REG
2913 && (GET_CODE (op0
) != SUBREG
|| GET_CODE (SUBREG_REG (op0
)) != REG
))
2914 *total
+= rtx_cost (op0
, mode
, code
, 0, speed
);
2924 /* Handle special cases of IOR: rotates, ALIGN insns, movstricthi_high. */
2927 if ((GET_CODE (op0
) == LSHIFTRT
&& GET_CODE (op1
) == ASHIFT
)
2928 || (GET_CODE (op0
) == ASHIFT
&& GET_CODE (op1
) == ZERO_EXTEND
)
2929 || (GET_CODE (op0
) == ASHIFT
&& GET_CODE (op1
) == LSHIFTRT
)
2930 || (GET_CODE (op0
) == AND
&& GET_CODE (op1
) == CONST_INT
))
2937 if (GET_CODE (op0
) != REG
2938 && (GET_CODE (op0
) != SUBREG
|| GET_CODE (SUBREG_REG (op0
)) != REG
))
2939 *total
+= rtx_cost (op0
, mode
, code
, 0, speed
);
2952 if (! rhs_andsi3_operand (XEXP (x
, 1), SImode
))
2953 *total
+= rtx_cost (XEXP (x
, 1), mode
, code
, 1, speed
);
2957 if (! regorlog2_operand (XEXP (x
, 1), SImode
))
2958 *total
+= rtx_cost (XEXP (x
, 1), mode
, code
, 1, speed
);
2965 if (outer_code
== SET
2966 && XEXP (x
, 1) == const1_rtx
2967 && GET_CODE (XEXP (x
, 2)) == CONST_INT
)
2983 if (GET_CODE (op0
) == GET_CODE (op1
)
2984 && (GET_CODE (op0
) == ZERO_EXTEND
2985 || GET_CODE (op0
) == SIGN_EXTEND
))
2987 *total
= COSTS_N_INSNS (1);
2988 op0
= XEXP (op0
, 0);
2989 op1
= XEXP (op1
, 0);
2992 *total
= COSTS_N_INSNS (1);
2994 *total
= COSTS_N_INSNS (3);
2996 if (GET_CODE (op0
) != REG
2997 && (GET_CODE (op0
) != SUBREG
|| GET_CODE (SUBREG_REG (op0
)) != REG
))
2998 *total
+= rtx_cost (op0
, mode
, MULT
, 0, speed
);
2999 if (GET_CODE (op1
) != REG
3000 && (GET_CODE (op1
) != SUBREG
|| GET_CODE (SUBREG_REG (op1
)) != REG
))
3001 *total
+= rtx_cost (op1
, mode
, MULT
, 1, speed
);
3007 *total
= COSTS_N_INSNS (32);
3012 if (outer_code
== SET
)
3021 /* Used for communication between {push,pop}_multiple_operation (which
3022 we use not only as a predicate) and the corresponding output functions. */
3023 static int first_preg_to_save
, first_dreg_to_save
;
3024 static int n_regs_to_save
;
3027 analyze_push_multiple_operation (rtx op
)
3029 int lastdreg
= 8, lastpreg
= 6;
3032 first_preg_to_save
= lastpreg
;
3033 first_dreg_to_save
= lastdreg
;
3034 for (i
= 1, group
= 0; i
< XVECLEN (op
, 0) - 1; i
++)
3036 rtx t
= XVECEXP (op
, 0, i
);
3040 if (GET_CODE (t
) != SET
)
3044 dest
= SET_DEST (t
);
3045 if (GET_CODE (dest
) != MEM
|| ! REG_P (src
))
3047 dest
= XEXP (dest
, 0);
3048 if (GET_CODE (dest
) != PLUS
3049 || ! REG_P (XEXP (dest
, 0))
3050 || REGNO (XEXP (dest
, 0)) != REG_SP
3051 || GET_CODE (XEXP (dest
, 1)) != CONST_INT
3052 || INTVAL (XEXP (dest
, 1)) != -i
* 4)
3055 regno
= REGNO (src
);
3058 if (D_REGNO_P (regno
))
3061 first_dreg_to_save
= lastdreg
= regno
- REG_R0
;
3063 else if (regno
>= REG_P0
&& regno
<= REG_P7
)
3066 first_preg_to_save
= lastpreg
= regno
- REG_P0
;
3076 if (regno
>= REG_P0
&& regno
<= REG_P7
)
3079 first_preg_to_save
= lastpreg
= regno
- REG_P0
;
3081 else if (regno
!= REG_R0
+ lastdreg
+ 1)
3086 else if (group
== 2)
3088 if (regno
!= REG_P0
+ lastpreg
+ 1)
3093 n_regs_to_save
= 8 - first_dreg_to_save
+ 6 - first_preg_to_save
;
3098 analyze_pop_multiple_operation (rtx op
)
3100 int lastdreg
= 8, lastpreg
= 6;
3103 for (i
= 1, group
= 0; i
< XVECLEN (op
, 0); i
++)
3105 rtx t
= XVECEXP (op
, 0, i
);
3109 if (GET_CODE (t
) != SET
)
3113 dest
= SET_DEST (t
);
3114 if (GET_CODE (src
) != MEM
|| ! REG_P (dest
))
3116 src
= XEXP (src
, 0);
3120 if (! REG_P (src
) || REGNO (src
) != REG_SP
)
3123 else if (GET_CODE (src
) != PLUS
3124 || ! REG_P (XEXP (src
, 0))
3125 || REGNO (XEXP (src
, 0)) != REG_SP
3126 || GET_CODE (XEXP (src
, 1)) != CONST_INT
3127 || INTVAL (XEXP (src
, 1)) != (i
- 1) * 4)
3130 regno
= REGNO (dest
);
3133 if (regno
== REG_R7
)
3138 else if (regno
!= REG_P0
+ lastpreg
- 1)
3143 else if (group
== 1)
3145 if (regno
!= REG_R0
+ lastdreg
- 1)
3151 first_dreg_to_save
= lastdreg
;
3152 first_preg_to_save
= lastpreg
;
3153 n_regs_to_save
= 8 - first_dreg_to_save
+ 6 - first_preg_to_save
;
3157 /* Emit assembly code for one multi-register push described by INSN, with
3158 operands in OPERANDS. */
3161 output_push_multiple (rtx insn
, rtx
*operands
)
3166 /* Validate the insn again, and compute first_[dp]reg_to_save. */
3167 ok
= analyze_push_multiple_operation (PATTERN (insn
));
3170 if (first_dreg_to_save
== 8)
3171 sprintf (buf
, "[--sp] = ( p5:%d );\n", first_preg_to_save
);
3172 else if (first_preg_to_save
== 6)
3173 sprintf (buf
, "[--sp] = ( r7:%d );\n", first_dreg_to_save
);
3175 sprintf (buf
, "[--sp] = ( r7:%d, p5:%d );\n",
3176 first_dreg_to_save
, first_preg_to_save
);
3178 output_asm_insn (buf
, operands
);
3181 /* Emit assembly code for one multi-register pop described by INSN, with
3182 operands in OPERANDS. */
3185 output_pop_multiple (rtx insn
, rtx
*operands
)
3190 /* Validate the insn again, and compute first_[dp]reg_to_save. */
3191 ok
= analyze_pop_multiple_operation (PATTERN (insn
));
3194 if (first_dreg_to_save
== 8)
3195 sprintf (buf
, "( p5:%d ) = [sp++];\n", first_preg_to_save
);
3196 else if (first_preg_to_save
== 6)
3197 sprintf (buf
, "( r7:%d ) = [sp++];\n", first_dreg_to_save
);
3199 sprintf (buf
, "( r7:%d, p5:%d ) = [sp++];\n",
3200 first_dreg_to_save
, first_preg_to_save
);
3202 output_asm_insn (buf
, operands
);
3205 /* Adjust DST and SRC by OFFSET bytes, and generate one move in mode MODE. */
3208 single_move_for_movmem (rtx dst
, rtx src
, machine_mode mode
, HOST_WIDE_INT offset
)
3210 rtx scratch
= gen_reg_rtx (mode
);
3213 srcmem
= adjust_address_nv (src
, mode
, offset
);
3214 dstmem
= adjust_address_nv (dst
, mode
, offset
);
3215 emit_move_insn (scratch
, srcmem
);
3216 emit_move_insn (dstmem
, scratch
);
3219 /* Expand a string move operation of COUNT_EXP bytes from SRC to DST, with
3220 alignment ALIGN_EXP. Return true if successful, false if we should fall
3221 back on a different method. */
3224 bfin_expand_movmem (rtx dst
, rtx src
, rtx count_exp
, rtx align_exp
)
3226 rtx srcreg
, destreg
, countreg
;
3227 HOST_WIDE_INT align
= 0;
3228 unsigned HOST_WIDE_INT count
= 0;
3230 if (GET_CODE (align_exp
) == CONST_INT
)
3231 align
= INTVAL (align_exp
);
3232 if (GET_CODE (count_exp
) == CONST_INT
)
3234 count
= INTVAL (count_exp
);
3236 if (!TARGET_INLINE_ALL_STRINGOPS
&& count
> 64)
3241 /* If optimizing for size, only do single copies inline. */
3244 if (count
== 2 && align
< 2)
3246 if (count
== 4 && align
< 4)
3248 if (count
!= 1 && count
!= 2 && count
!= 4)
3251 if (align
< 2 && count
!= 1)
3254 destreg
= copy_to_mode_reg (Pmode
, XEXP (dst
, 0));
3255 if (destreg
!= XEXP (dst
, 0))
3256 dst
= replace_equiv_address_nv (dst
, destreg
);
3257 srcreg
= copy_to_mode_reg (Pmode
, XEXP (src
, 0));
3258 if (srcreg
!= XEXP (src
, 0))
3259 src
= replace_equiv_address_nv (src
, srcreg
);
3261 if (count
!= 0 && align
>= 2)
3263 unsigned HOST_WIDE_INT offset
= 0;
3267 if ((count
& ~3) == 4)
3269 single_move_for_movmem (dst
, src
, SImode
, offset
);
3272 else if (count
& ~3)
3274 HOST_WIDE_INT new_count
= ((count
>> 2) & 0x3fffffff) - 1;
3275 countreg
= copy_to_mode_reg (Pmode
, GEN_INT (new_count
));
3277 emit_insn (gen_rep_movsi (destreg
, srcreg
, countreg
, destreg
, srcreg
));
3278 cfun
->machine
->has_loopreg_clobber
= true;
3282 single_move_for_movmem (dst
, src
, HImode
, offset
);
3288 if ((count
& ~1) == 2)
3290 single_move_for_movmem (dst
, src
, HImode
, offset
);
3293 else if (count
& ~1)
3295 HOST_WIDE_INT new_count
= ((count
>> 1) & 0x7fffffff) - 1;
3296 countreg
= copy_to_mode_reg (Pmode
, GEN_INT (new_count
));
3298 emit_insn (gen_rep_movhi (destreg
, srcreg
, countreg
, destreg
, srcreg
));
3299 cfun
->machine
->has_loopreg_clobber
= true;
3304 single_move_for_movmem (dst
, src
, QImode
, offset
);
3311 /* Compute the alignment for a local variable.
3312 TYPE is the data type, and ALIGN is the alignment that
3313 the object would ordinarily have. The value of this macro is used
3314 instead of that alignment to align the object. */
3317 bfin_local_alignment (tree type
, unsigned align
)
3319 /* Increasing alignment for (relatively) big types allows the builtin
3320 memcpy can use 32 bit loads/stores. */
3321 if (TYPE_SIZE (type
)
3322 && TREE_CODE (TYPE_SIZE (type
)) == INTEGER_CST
3323 && wi::gtu_p (wi::to_wide (TYPE_SIZE (type
)), 8)
3329 /* Implement TARGET_SCHED_ISSUE_RATE. */
3332 bfin_issue_rate (void)
3338 bfin_adjust_cost (rtx_insn
*insn
, int dep_type
, rtx_insn
*dep_insn
, int cost
,
3341 enum attr_type dep_insn_type
;
3342 int dep_insn_code_number
;
3344 /* Anti and output dependencies have zero cost. */
3348 dep_insn_code_number
= recog_memoized (dep_insn
);
3350 /* If we can't recognize the insns, we can't really do anything. */
3351 if (dep_insn_code_number
< 0 || recog_memoized (insn
) < 0)
3354 dep_insn_type
= get_attr_type (dep_insn
);
3356 if (dep_insn_type
== TYPE_MOVE
|| dep_insn_type
== TYPE_MCLD
)
3358 rtx pat
= PATTERN (dep_insn
);
3361 if (GET_CODE (pat
) == PARALLEL
)
3362 pat
= XVECEXP (pat
, 0, 0);
3363 dest
= SET_DEST (pat
);
3364 src
= SET_SRC (pat
);
3365 if (! ADDRESS_REGNO_P (REGNO (dest
))
3366 || ! (MEM_P (src
) || D_REGNO_P (REGNO (src
))))
3368 return cost
+ (dep_insn_type
== TYPE_MOVE
? 4 : 3);
3374 /* This function acts like NEXT_INSN, but is aware of three-insn bundles and
3375 skips all subsequent parallel instructions if INSN is the start of such
3378 find_next_insn_start (rtx_insn
*insn
)
3380 if (GET_MODE (insn
) == SImode
)
3382 while (GET_MODE (insn
) != QImode
)
3383 insn
= NEXT_INSN (insn
);
3385 return NEXT_INSN (insn
);
3388 /* This function acts like PREV_INSN, but is aware of three-insn bundles and
3389 skips all subsequent parallel instructions if INSN is the start of such
3392 find_prev_insn_start (rtx_insn
*insn
)
3394 insn
= PREV_INSN (insn
);
3395 gcc_assert (GET_MODE (insn
) != SImode
);
3396 if (GET_MODE (insn
) == QImode
)
3398 while (GET_MODE (PREV_INSN (insn
)) == SImode
)
3399 insn
= PREV_INSN (insn
);
3404 /* Implement TARGET_CAN_USE_DOLOOP_P. */
3407 bfin_can_use_doloop_p (const widest_int
&, const widest_int
&iterations_max
,
3410 /* Due to limitations in the hardware (an initial loop count of 0
3411 does not loop 2^32 times) we must avoid to generate a hardware
3412 loops when we cannot rule out this case. */
3413 return (wi::ltu_p (iterations_max
, 0xFFFFFFFF));
3416 /* Increment the counter for the number of loop instructions in the
3417 current function. */
3420 bfin_hardware_loop (void)
3422 cfun
->machine
->has_hardware_loops
++;
3425 /* Maximum loop nesting depth. */
3426 #define MAX_LOOP_DEPTH 2
3428 /* Maximum size of a loop. */
3429 #define MAX_LOOP_LENGTH 2042
3431 /* Maximum distance of the LSETUP instruction from the loop start. */
3432 #define MAX_LSETUP_DISTANCE 30
3434 /* Estimate the length of INSN conservatively. */
3437 length_for_loop (rtx_insn
*insn
)
3440 if (JUMP_P (insn
) && any_condjump_p (insn
) && !optimize_size
)
3442 if (ENABLE_WA_SPECULATIVE_SYNCS
)
3444 else if (ENABLE_WA_SPECULATIVE_LOADS
)
3447 else if (LABEL_P (insn
))
3449 if (ENABLE_WA_SPECULATIVE_SYNCS
)
3453 if (NONDEBUG_INSN_P (insn
))
3454 length
+= get_attr_length (insn
);
3459 /* Optimize LOOP. */
3462 hwloop_optimize (hwloop_info loop
)
3465 rtx_insn
*insn
, *last_insn
;
3466 rtx loop_init
, start_label
, end_label
;
3467 rtx iter_reg
, scratchreg
, scratch_init
;
3468 rtx_insn
*scratch_init_insn
;
3469 rtx lc_reg
, lt_reg
, lb_reg
;
3473 bool clobber0
, clobber1
;
3475 if (loop
->depth
> MAX_LOOP_DEPTH
)
3478 fprintf (dump_file
, ";; loop %d too deep\n", loop
->loop_no
);
3482 /* Get the loop iteration register. */
3483 iter_reg
= loop
->iter_reg
;
3485 gcc_assert (REG_P (iter_reg
));
3487 scratchreg
= NULL_RTX
;
3488 scratch_init
= iter_reg
;
3489 scratch_init_insn
= NULL
;
3490 if (!PREG_P (iter_reg
) && loop
->incoming_src
)
3492 basic_block bb_in
= loop
->incoming_src
;
3494 for (i
= REG_P0
; i
<= REG_P5
; i
++)
3495 if ((df_regs_ever_live_p (i
)
3496 || (funkind (TREE_TYPE (current_function_decl
)) == SUBROUTINE
3497 && call_used_regs
[i
]))
3498 && !REGNO_REG_SET_P (df_get_live_out (bb_in
), i
))
3500 scratchreg
= gen_rtx_REG (SImode
, i
);
3503 for (insn
= BB_END (bb_in
); insn
!= BB_HEAD (bb_in
);
3504 insn
= PREV_INSN (insn
))
3507 if (NOTE_P (insn
) || BARRIER_P (insn
))
3509 set
= single_set (insn
);
3510 if (set
&& rtx_equal_p (SET_DEST (set
), iter_reg
))
3512 if (CONSTANT_P (SET_SRC (set
)))
3514 scratch_init
= SET_SRC (set
);
3515 scratch_init_insn
= insn
;
3519 else if (reg_mentioned_p (iter_reg
, PATTERN (insn
)))
3524 if (loop
->incoming_src
)
3526 /* Make sure the predecessor is before the loop start label, as required by
3527 the LSETUP instruction. */
3529 insn
= BB_END (loop
->incoming_src
);
3530 /* If we have to insert the LSETUP before a jump, count that jump in the
3532 if (vec_safe_length (loop
->incoming
) > 1
3533 || !(loop
->incoming
->last ()->flags
& EDGE_FALLTHRU
))
3535 gcc_assert (JUMP_P (insn
));
3536 insn
= PREV_INSN (insn
);
3539 for (; insn
&& insn
!= loop
->start_label
; insn
= NEXT_INSN (insn
))
3540 length
+= length_for_loop (insn
);
3545 fprintf (dump_file
, ";; loop %d lsetup not before loop_start\n",
3550 /* Account for the pop of a scratch register where necessary. */
3551 if (!PREG_P (iter_reg
) && scratchreg
== NULL_RTX
3552 && ENABLE_WA_LOAD_LCREGS
)
3555 if (length
> MAX_LSETUP_DISTANCE
)
3558 fprintf (dump_file
, ";; loop %d lsetup too far away\n", loop
->loop_no
);
3563 /* Check if start_label appears before loop_end and calculate the
3564 offset between them. We calculate the length of instructions
3567 for (insn
= loop
->start_label
;
3568 insn
&& insn
!= loop
->loop_end
;
3569 insn
= NEXT_INSN (insn
))
3570 length
+= length_for_loop (insn
);
3575 fprintf (dump_file
, ";; loop %d start_label not before loop_end\n",
3580 loop
->length
= length
;
3581 if (loop
->length
> MAX_LOOP_LENGTH
)
3584 fprintf (dump_file
, ";; loop %d too long\n", loop
->loop_no
);
3588 /* Scan all the blocks to make sure they don't use iter_reg. */
3589 if (loop
->iter_reg_used
|| loop
->iter_reg_used_outside
)
3592 fprintf (dump_file
, ";; loop %d uses iterator\n", loop
->loop_no
);
3596 clobber0
= (TEST_HARD_REG_BIT (loop
->regs_set_in_loop
, REG_LC0
)
3597 || TEST_HARD_REG_BIT (loop
->regs_set_in_loop
, REG_LB0
)
3598 || TEST_HARD_REG_BIT (loop
->regs_set_in_loop
, REG_LT0
));
3599 clobber1
= (TEST_HARD_REG_BIT (loop
->regs_set_in_loop
, REG_LC1
)
3600 || TEST_HARD_REG_BIT (loop
->regs_set_in_loop
, REG_LB1
)
3601 || TEST_HARD_REG_BIT (loop
->regs_set_in_loop
, REG_LT1
));
3602 if (clobber0
&& clobber1
)
3605 fprintf (dump_file
, ";; loop %d no loop reg available\n",
3610 /* There should be an instruction before the loop_end instruction
3611 in the same basic block. And the instruction must not be
3613 - CONDITIONAL BRANCH
3617 - Returns (RTS, RTN, etc.) */
3620 last_insn
= find_prev_insn_start (loop
->loop_end
);
3624 for (; last_insn
!= BB_HEAD (bb
);
3625 last_insn
= find_prev_insn_start (last_insn
))
3626 if (NONDEBUG_INSN_P (last_insn
))
3629 if (last_insn
!= BB_HEAD (bb
))
3632 if (single_pred_p (bb
)
3633 && single_pred_edge (bb
)->flags
& EDGE_FALLTHRU
3634 && single_pred (bb
) != ENTRY_BLOCK_PTR_FOR_FN (cfun
))
3636 bb
= single_pred (bb
);
3637 last_insn
= BB_END (bb
);
3650 fprintf (dump_file
, ";; loop %d has no last instruction\n",
3655 if (JUMP_P (last_insn
) && !any_condjump_p (last_insn
))
3658 fprintf (dump_file
, ";; loop %d has bad last instruction\n",
3662 /* In all other cases, try to replace a bad last insn with a nop. */
3663 else if (JUMP_P (last_insn
)
3664 || CALL_P (last_insn
)
3665 || get_attr_type (last_insn
) == TYPE_SYNC
3666 || get_attr_type (last_insn
) == TYPE_CALL
3667 || get_attr_seq_insns (last_insn
) == SEQ_INSNS_MULTI
3668 || recog_memoized (last_insn
) == CODE_FOR_return_internal
3669 || GET_CODE (PATTERN (last_insn
)) == ASM_INPUT
3670 || asm_noperands (PATTERN (last_insn
)) >= 0)
3672 if (loop
->length
+ 2 > MAX_LOOP_LENGTH
)
3675 fprintf (dump_file
, ";; loop %d too long\n", loop
->loop_no
);
3679 fprintf (dump_file
, ";; loop %d has bad last insn; replace with nop\n",
3682 last_insn
= emit_insn_after (gen_forced_nop (), last_insn
);
3685 loop
->last_insn
= last_insn
;
3687 /* The loop is good for replacement. */
3688 start_label
= loop
->start_label
;
3689 end_label
= gen_label_rtx ();
3690 iter_reg
= loop
->iter_reg
;
3692 if (loop
->depth
== 1 && !clobber1
)
3694 lc_reg
= gen_rtx_REG (SImode
, REG_LC1
);
3695 lb_reg
= gen_rtx_REG (SImode
, REG_LB1
);
3696 lt_reg
= gen_rtx_REG (SImode
, REG_LT1
);
3697 SET_HARD_REG_BIT (loop
->regs_set_in_loop
, REG_LC1
);
3701 lc_reg
= gen_rtx_REG (SImode
, REG_LC0
);
3702 lb_reg
= gen_rtx_REG (SImode
, REG_LB0
);
3703 lt_reg
= gen_rtx_REG (SImode
, REG_LT0
);
3704 SET_HARD_REG_BIT (loop
->regs_set_in_loop
, REG_LC0
);
3707 loop
->end_label
= end_label
;
3709 /* Create a sequence containing the loop setup. */
3712 /* LSETUP only accepts P registers. If we have one, we can use it,
3713 otherwise there are several ways of working around the problem.
3714 If we're not affected by anomaly 312, we can load the LC register
3715 from any iteration register, and use LSETUP without initialization.
3716 If we've found a P scratch register that's not live here, we can
3717 instead copy the iter_reg into that and use an initializing LSETUP.
3718 If all else fails, push and pop P0 and use it as a scratch. */
3719 if (P_REGNO_P (REGNO (iter_reg
)))
3721 loop_init
= gen_lsetup_with_autoinit (lt_reg
, start_label
,
3724 seq_end
= emit_insn (loop_init
);
3726 else if (!ENABLE_WA_LOAD_LCREGS
&& DPREG_P (iter_reg
))
3728 emit_insn (gen_movsi (lc_reg
, iter_reg
));
3729 loop_init
= gen_lsetup_without_autoinit (lt_reg
, start_label
,
3732 seq_end
= emit_insn (loop_init
);
3734 else if (scratchreg
!= NULL_RTX
)
3736 emit_insn (gen_movsi (scratchreg
, scratch_init
));
3737 loop_init
= gen_lsetup_with_autoinit (lt_reg
, start_label
,
3739 lc_reg
, scratchreg
);
3740 seq_end
= emit_insn (loop_init
);
3741 if (scratch_init_insn
!= NULL_RTX
)
3742 delete_insn (scratch_init_insn
);
3746 rtx p0reg
= gen_rtx_REG (SImode
, REG_P0
);
3747 rtx push
= gen_frame_mem (SImode
,
3748 gen_rtx_PRE_DEC (SImode
, stack_pointer_rtx
));
3749 rtx pop
= gen_frame_mem (SImode
,
3750 gen_rtx_POST_INC (SImode
, stack_pointer_rtx
));
3751 emit_insn (gen_movsi (push
, p0reg
));
3752 emit_insn (gen_movsi (p0reg
, scratch_init
));
3753 loop_init
= gen_lsetup_with_autoinit (lt_reg
, start_label
,
3756 emit_insn (loop_init
);
3757 seq_end
= emit_insn (gen_movsi (p0reg
, pop
));
3758 if (scratch_init_insn
!= NULL_RTX
)
3759 delete_insn (scratch_init_insn
);
3764 fprintf (dump_file
, ";; replacing loop %d initializer with\n",
3766 print_rtl_single (dump_file
, loop_init
);
3767 fprintf (dump_file
, ";; replacing loop %d terminator with\n",
3769 print_rtl_single (dump_file
, loop
->loop_end
);
3772 /* If the loop isn't entered at the top, also create a jump to the entry
3774 if (!loop
->incoming_src
&& loop
->head
!= loop
->incoming_dest
)
3776 rtx label
= BB_HEAD (loop
->incoming_dest
);
3777 /* If we're jumping to the final basic block in the loop, and there's
3778 only one cheap instruction before the end (typically an increment of
3779 an induction variable), we can just emit a copy here instead of a
3781 if (loop
->incoming_dest
== loop
->tail
3782 && next_real_insn (label
) == last_insn
3783 && asm_noperands (last_insn
) < 0
3784 && GET_CODE (PATTERN (last_insn
)) == SET
)
3786 seq_end
= emit_insn (copy_rtx (PATTERN (last_insn
)));
3790 rtx_insn
*ret
= emit_jump_insn (gen_jump (label
));
3791 JUMP_LABEL (ret
) = label
;
3792 LABEL_NUSES (label
)++;
3793 seq_end
= emit_barrier ();
3800 if (loop
->incoming_src
)
3802 rtx_insn
*prev
= BB_END (loop
->incoming_src
);
3803 if (vec_safe_length (loop
->incoming
) > 1
3804 || !(loop
->incoming
->last ()->flags
& EDGE_FALLTHRU
))
3806 gcc_assert (JUMP_P (prev
));
3807 prev
= PREV_INSN (prev
);
3808 emit_insn_after (seq
, prev
);
3812 emit_insn_after (seq
, prev
);
3813 BB_END (loop
->incoming_src
) = prev
;
3814 basic_block new_bb
= create_basic_block (seq
, seq_end
,
3815 loop
->head
->prev_bb
);
3816 edge e
= loop
->incoming
->last ();
3817 gcc_assert (e
->flags
& EDGE_FALLTHRU
);
3818 redirect_edge_succ (e
, new_bb
);
3819 make_edge (new_bb
, loop
->head
, 0);
3828 if (flag_checking
&& loop
->head
!= loop
->incoming_dest
)
3830 /* We aren't entering the loop at the top. Since we've established
3831 that the loop is entered only at one point, this means there
3832 can't be fallthru edges into the head. Any such fallthru edges
3833 would become invalid when we insert the new block, so verify
3834 that this does not in fact happen. */
3835 FOR_EACH_EDGE (e
, ei
, loop
->head
->preds
)
3836 gcc_assert (!(e
->flags
& EDGE_FALLTHRU
));
3839 emit_insn_before (seq
, BB_HEAD (loop
->head
));
3840 seq
= emit_label_before (gen_label_rtx (), seq
);
3842 new_bb
= create_basic_block (seq
, seq_end
, loop
->head
->prev_bb
);
3843 FOR_EACH_EDGE (e
, ei
, loop
->incoming
)
3845 if (!(e
->flags
& EDGE_FALLTHRU
)
3846 || e
->dest
!= loop
->head
)
3847 redirect_edge_and_branch_force (e
, new_bb
);
3849 redirect_edge_succ (e
, new_bb
);
3851 e
= make_edge (new_bb
, loop
->head
, 0);
3854 delete_insn (loop
->loop_end
);
3855 /* Insert the loop end label before the last instruction of the loop. */
3856 emit_label_before (as_a
<rtx_code_label
*> (loop
->end_label
),
3862 /* A callback for the hw-doloop pass. Called when a loop we have discovered
3863 turns out not to be optimizable; we have to split the doloop_end pattern
3864 into a subtract and a test. */
3866 hwloop_fail (hwloop_info loop
)
3868 rtx insn
= loop
->loop_end
;
3870 if (DPREG_P (loop
->iter_reg
))
3872 /* If loop->iter_reg is a DREG or PREG, we can split it here
3873 without scratch register. */
3876 emit_insn_before (gen_addsi3 (loop
->iter_reg
,
3881 test
= gen_rtx_NE (VOIDmode
, loop
->iter_reg
, const0_rtx
);
3882 insn
= emit_jump_insn_before (gen_cbranchsi4 (test
,
3883 loop
->iter_reg
, const0_rtx
,
3887 JUMP_LABEL (insn
) = loop
->start_label
;
3888 LABEL_NUSES (loop
->start_label
)++;
3889 delete_insn (loop
->loop_end
);
3893 splitting_loops
= 1;
3894 try_split (PATTERN (insn
), safe_as_a
<rtx_insn
*> (insn
), 1);
3895 splitting_loops
= 0;
3899 /* A callback for the hw-doloop pass. This function examines INSN; if
3900 it is a loop_end pattern we recognize, return the reg rtx for the
3901 loop counter. Otherwise, return NULL_RTX. */
3904 hwloop_pattern_reg (rtx_insn
*insn
)
3908 if (!JUMP_P (insn
) || recog_memoized (insn
) != CODE_FOR_loop_end
)
3911 reg
= SET_DEST (XVECEXP (PATTERN (insn
), 0, 1));
3917 static struct hw_doloop_hooks bfin_doloop_hooks
=
3924 /* Run from machine_dependent_reorg, this pass looks for doloop_end insns
3925 and tries to rewrite the RTL of these loops so that proper Blackfin
3926 hardware loops are generated. */
3929 bfin_reorg_loops (void)
3931 reorg_loops (true, &bfin_doloop_hooks
);
3934 /* Possibly generate a SEQUENCE out of three insns found in SLOT.
3935 Returns true if we modified the insn chain, false otherwise. */
3937 gen_one_bundle (rtx_insn
*slot
[3])
3939 gcc_assert (slot
[1] != NULL_RTX
);
3941 /* Don't add extra NOPs if optimizing for size. */
3943 && (slot
[0] == NULL_RTX
|| slot
[2] == NULL_RTX
))
3946 /* Verify that we really can do the multi-issue. */
3949 rtx_insn
*t
= NEXT_INSN (slot
[0]);
3950 while (t
!= slot
[1])
3952 if (! NOTE_P (t
) || NOTE_KIND (t
) != NOTE_INSN_DELETED
)
3959 rtx_insn
*t
= NEXT_INSN (slot
[1]);
3960 while (t
!= slot
[2])
3962 if (! NOTE_P (t
) || NOTE_KIND (t
) != NOTE_INSN_DELETED
)
3968 if (slot
[0] == NULL_RTX
)
3970 slot
[0] = emit_insn_before (gen_mnop (), slot
[1]);
3971 df_insn_rescan (slot
[0]);
3973 if (slot
[2] == NULL_RTX
)
3975 slot
[2] = emit_insn_after (gen_forced_nop (), slot
[1]);
3976 df_insn_rescan (slot
[2]);
3979 /* Avoid line number information being printed inside one bundle. */
3980 if (INSN_LOCATION (slot
[1])
3981 && INSN_LOCATION (slot
[1]) != INSN_LOCATION (slot
[0]))
3982 INSN_LOCATION (slot
[1]) = INSN_LOCATION (slot
[0]);
3983 if (INSN_LOCATION (slot
[2])
3984 && INSN_LOCATION (slot
[2]) != INSN_LOCATION (slot
[0]))
3985 INSN_LOCATION (slot
[2]) = INSN_LOCATION (slot
[0]);
3987 /* Terminate them with "|| " instead of ";" in the output. */
3988 PUT_MODE (slot
[0], SImode
);
3989 PUT_MODE (slot
[1], SImode
);
3990 /* Terminate the bundle, for the benefit of reorder_var_tracking_notes. */
3991 PUT_MODE (slot
[2], QImode
);
3995 /* Go through all insns, and use the information generated during scheduling
3996 to generate SEQUENCEs to represent bundles of instructions issued
4000 bfin_gen_bundles (void)
4003 FOR_EACH_BB_FN (bb
, cfun
)
4005 rtx_insn
*insn
, *next
;
4009 slot
[0] = slot
[1] = slot
[2] = NULL
;
4010 for (insn
= BB_HEAD (bb
);; insn
= next
)
4013 rtx_insn
*delete_this
= NULL
;
4015 if (NONDEBUG_INSN_P (insn
))
4017 enum attr_type type
= get_attr_type (insn
);
4019 if (type
== TYPE_STALL
)
4021 gcc_assert (n_filled
== 0);
4026 if (type
== TYPE_DSP32
|| type
== TYPE_DSP32SHIFTIMM
)
4028 else if (slot
[1] == NULL_RTX
)
4036 next
= NEXT_INSN (insn
);
4037 while (next
&& insn
!= BB_END (bb
)
4039 && GET_CODE (PATTERN (next
)) != USE
4040 && GET_CODE (PATTERN (next
)) != CLOBBER
))
4043 next
= NEXT_INSN (insn
);
4046 /* BB_END can change due to emitting extra NOPs, so check here. */
4047 at_end
= insn
== BB_END (bb
);
4048 if (delete_this
== NULL_RTX
&& (at_end
|| GET_MODE (next
) == TImode
))
4051 || !gen_one_bundle (slot
))
4052 && slot
[0] != NULL_RTX
)
4054 rtx pat
= PATTERN (slot
[0]);
4055 if (GET_CODE (pat
) == SET
4056 && GET_CODE (SET_SRC (pat
)) == UNSPEC
4057 && XINT (SET_SRC (pat
), 1) == UNSPEC_32BIT
)
4059 SET_SRC (pat
) = XVECEXP (SET_SRC (pat
), 0, 0);
4060 INSN_CODE (slot
[0]) = -1;
4061 df_insn_rescan (slot
[0]);
4065 slot
[0] = slot
[1] = slot
[2] = NULL
;
4067 if (delete_this
!= NULL_RTX
)
4068 delete_insn (delete_this
);
4075 /* Ensure that no var tracking notes are emitted in the middle of a
4076 three-instruction bundle. */
4079 reorder_var_tracking_notes (void)
4082 FOR_EACH_BB_FN (bb
, cfun
)
4084 rtx_insn
*insn
, *next
;
4085 rtx_insn
*queue
= NULL
;
4086 bool in_bundle
= false;
4088 for (insn
= BB_HEAD (bb
); insn
!= BB_END (bb
); insn
= next
)
4090 next
= NEXT_INSN (insn
);
4094 /* Emit queued up notes at the last instruction of a bundle. */
4095 if (GET_MODE (insn
) == QImode
)
4099 rtx_insn
*next_queue
= PREV_INSN (queue
);
4100 SET_PREV_INSN (NEXT_INSN (insn
)) = queue
;
4101 SET_NEXT_INSN (queue
) = NEXT_INSN (insn
);
4102 SET_NEXT_INSN (insn
) = queue
;
4103 SET_PREV_INSN (queue
) = insn
;
4108 else if (GET_MODE (insn
) == SImode
)
4111 else if (NOTE_P (insn
) && NOTE_KIND (insn
) == NOTE_INSN_VAR_LOCATION
)
4115 rtx_insn
*prev
= PREV_INSN (insn
);
4116 SET_PREV_INSN (next
) = prev
;
4117 SET_NEXT_INSN (prev
) = next
;
4119 SET_PREV_INSN (insn
) = queue
;
4127 /* On some silicon revisions, functions shorter than a certain number of cycles
4128 can cause unpredictable behavior. Work around this by adding NOPs as
4131 workaround_rts_anomaly (void)
4133 rtx_insn
*insn
, *first_insn
= NULL
;
4136 if (! ENABLE_WA_RETS
)
4139 for (insn
= get_insns (); insn
; insn
= NEXT_INSN (insn
))
4143 if (BARRIER_P (insn
))
4146 if (NOTE_P (insn
) || LABEL_P (insn
))
4149 if (JUMP_TABLE_DATA_P (insn
))
4152 if (first_insn
== NULL_RTX
)
4154 pat
= PATTERN (insn
);
4155 if (GET_CODE (pat
) == USE
|| GET_CODE (pat
) == CLOBBER
4156 || GET_CODE (pat
) == ASM_INPUT
4157 || asm_noperands (pat
) >= 0)
4165 if (recog_memoized (insn
) == CODE_FOR_return_internal
)
4168 /* Nothing to worry about for direct jumps. */
4169 if (!any_condjump_p (insn
))
4175 else if (INSN_P (insn
))
4177 rtx pat
= PATTERN (insn
);
4178 int this_cycles
= 1;
4180 if (GET_CODE (pat
) == PARALLEL
)
4182 if (analyze_push_multiple_operation (pat
)
4183 || analyze_pop_multiple_operation (pat
))
4184 this_cycles
= n_regs_to_save
;
4188 int icode
= recog_memoized (insn
);
4190 if (icode
== CODE_FOR_link
)
4192 else if (icode
== CODE_FOR_unlink
)
4194 else if (icode
== CODE_FOR_mulsi3
)
4197 if (this_cycles
>= cycles
)
4200 cycles
-= this_cycles
;
4205 emit_insn_before (gen_nop (), first_insn
);
4210 /* Return an insn type for INSN that can be used by the caller for anomaly
4211 workarounds. This differs from plain get_attr_type in that it handles
4214 static enum attr_type
4215 type_for_anomaly (rtx_insn
*insn
)
4217 rtx pat
= PATTERN (insn
);
4218 if (rtx_sequence
*seq
= dyn_cast
<rtx_sequence
*> (pat
))
4221 t
= get_attr_type (seq
->insn (1));
4224 t
= get_attr_type (seq
->insn (2));
4230 return get_attr_type (insn
);
4233 /* Return true iff the address found in MEM is based on the register
4234 NP_REG and optionally has a positive offset. */
4236 harmless_null_pointer_p (rtx mem
, int np_reg
)
4238 mem
= XEXP (mem
, 0);
4239 if (GET_CODE (mem
) == POST_INC
|| GET_CODE (mem
) == POST_DEC
)
4240 mem
= XEXP (mem
, 0);
4241 if (REG_P (mem
) && (int) REGNO (mem
) == np_reg
)
4243 if (GET_CODE (mem
) == PLUS
4244 && REG_P (XEXP (mem
, 0)) && (int) REGNO (XEXP (mem
, 0)) == np_reg
)
4246 mem
= XEXP (mem
, 1);
4247 if (GET_CODE (mem
) == CONST_INT
&& INTVAL (mem
) > 0)
4253 /* Return nonzero if INSN contains any loads that may trap. */
4256 trapping_loads_p (rtx_insn
*insn
, int np_reg
, bool after_np_branch
)
4258 rtx mem
= SET_SRC (single_set (insn
));
4260 if (!after_np_branch
)
4262 return ((np_reg
== -1 || !harmless_null_pointer_p (mem
, np_reg
))
4263 && may_trap_p (mem
));
4266 /* Return INSN if it is of TYPE_MCLD. Alternatively, if INSN is the start of
4267 a three-insn bundle, see if one of them is a load and return that if so.
4268 Return NULL if the insn does not contain loads. */
4270 find_load (rtx_insn
*insn
)
4272 if (!NONDEBUG_INSN_P (insn
))
4274 if (get_attr_type (insn
) == TYPE_MCLD
)
4276 if (GET_MODE (insn
) != SImode
)
4279 insn
= NEXT_INSN (insn
);
4280 if ((GET_MODE (insn
) == SImode
|| GET_MODE (insn
) == QImode
)
4281 && get_attr_type (insn
) == TYPE_MCLD
)
4283 } while (GET_MODE (insn
) != QImode
);
4287 /* Determine whether PAT is an indirect call pattern. */
4289 indirect_call_p (rtx pat
)
4291 if (GET_CODE (pat
) == PARALLEL
)
4292 pat
= XVECEXP (pat
, 0, 0);
4293 if (GET_CODE (pat
) == SET
)
4294 pat
= SET_SRC (pat
);
4295 gcc_assert (GET_CODE (pat
) == CALL
);
4296 pat
= XEXP (pat
, 0);
4297 gcc_assert (GET_CODE (pat
) == MEM
);
4298 pat
= XEXP (pat
, 0);
4303 /* During workaround_speculation, track whether we're in the shadow of a
4304 conditional branch that tests a P register for NULL. If so, we can omit
4305 emitting NOPs if we see a load from that P register, since a speculative
4306 access at address 0 isn't a problem, and the load is executed in all other
4308 Global for communication with note_np_check_stores through note_stores.
4310 int np_check_regno
= -1;
4311 bool np_after_branch
= false;
4313 /* Subroutine of workaround_speculation, called through note_stores. */
4315 note_np_check_stores (rtx x
, const_rtx pat ATTRIBUTE_UNUSED
,
4316 void *data ATTRIBUTE_UNUSED
)
4318 if (REG_P (x
) && (REGNO (x
) == REG_CC
|| (int) REGNO (x
) == np_check_regno
))
4319 np_check_regno
= -1;
4323 workaround_speculation (void)
4325 rtx_insn
*insn
, *next
;
4326 rtx_insn
*last_condjump
= NULL
;
4327 int cycles_since_jump
= INT_MAX
;
4328 int delay_added
= 0;
4330 if (! ENABLE_WA_SPECULATIVE_LOADS
&& ! ENABLE_WA_SPECULATIVE_SYNCS
4331 && ! ENABLE_WA_INDIRECT_CALLS
)
4334 /* First pass: find predicted-false branches; if something after them
4335 needs nops, insert them or change the branch to predict true. */
4336 for (insn
= get_insns (); insn
; insn
= next
)
4339 int delay_needed
= 0;
4341 next
= find_next_insn_start (insn
);
4343 if (NOTE_P (insn
) || BARRIER_P (insn
))
4345 if (JUMP_TABLE_DATA_P (insn
))
4350 np_check_regno
= -1;
4354 pat
= PATTERN (insn
);
4355 if (GET_CODE (pat
) == USE
|| GET_CODE (pat
) == CLOBBER
)
4358 if (GET_CODE (pat
) == ASM_INPUT
|| asm_noperands (pat
) >= 0)
4360 np_check_regno
= -1;
4366 /* Is this a condjump based on a null pointer comparison we saw
4368 if (np_check_regno
!= -1
4369 && recog_memoized (insn
) == CODE_FOR_cbranchbi4
)
4371 rtx op
= XEXP (SET_SRC (PATTERN (insn
)), 0);
4372 gcc_assert (GET_CODE (op
) == EQ
|| GET_CODE (op
) == NE
);
4373 if (GET_CODE (op
) == NE
)
4374 np_after_branch
= true;
4376 if (any_condjump_p (insn
)
4377 && ! cbranch_predicted_taken_p (insn
))
4379 last_condjump
= insn
;
4381 cycles_since_jump
= 0;
4384 cycles_since_jump
= INT_MAX
;
4386 else if (CALL_P (insn
))
4388 np_check_regno
= -1;
4389 if (cycles_since_jump
< INT_MAX
)
4390 cycles_since_jump
++;
4391 if (indirect_call_p (pat
) && ENABLE_WA_INDIRECT_CALLS
)
4396 else if (NONDEBUG_INSN_P (insn
))
4398 rtx_insn
*load_insn
= find_load (insn
);
4399 enum attr_type type
= type_for_anomaly (insn
);
4401 if (cycles_since_jump
< INT_MAX
)
4402 cycles_since_jump
++;
4404 /* Detect a comparison of a P register with zero. If we later
4405 see a condjump based on it, we have found a null pointer
4407 if (recog_memoized (insn
) == CODE_FOR_compare_eq
)
4409 rtx src
= SET_SRC (PATTERN (insn
));
4410 if (REG_P (XEXP (src
, 0))
4411 && P_REGNO_P (REGNO (XEXP (src
, 0)))
4412 && XEXP (src
, 1) == const0_rtx
)
4414 np_check_regno
= REGNO (XEXP (src
, 0));
4415 np_after_branch
= false;
4418 np_check_regno
= -1;
4421 if (load_insn
&& ENABLE_WA_SPECULATIVE_LOADS
)
4423 if (trapping_loads_p (load_insn
, np_check_regno
,
4427 else if (type
== TYPE_SYNC
&& ENABLE_WA_SPECULATIVE_SYNCS
)
4430 /* See if we need to forget about a null pointer comparison
4431 we found earlier. */
4432 if (recog_memoized (insn
) != CODE_FOR_compare_eq
)
4434 note_stores (PATTERN (insn
), note_np_check_stores
, NULL
);
4435 if (np_check_regno
!= -1)
4437 if (find_regno_note (insn
, REG_INC
, np_check_regno
))
4438 np_check_regno
= -1;
4444 if (delay_needed
> cycles_since_jump
4445 && (delay_needed
- cycles_since_jump
) > delay_added
)
4449 rtx
*op
= recog_data
.operand
;
4451 delay_needed
-= cycles_since_jump
;
4453 extract_insn (last_condjump
);
4456 pat1
= gen_cbranch_predicted_taken (op
[0], op
[1], op
[2],
4458 cycles_since_jump
= INT_MAX
;
4462 /* Do not adjust cycles_since_jump in this case, so that
4463 we'll increase the number of NOPs for a subsequent insn
4465 pat1
= gen_cbranch_with_nops (op
[0], op
[1], op
[2], op
[3],
4466 GEN_INT (delay_needed
));
4467 delay_added
= delay_needed
;
4469 PATTERN (last_condjump
) = pat1
;
4470 INSN_CODE (last_condjump
) = recog (pat1
, insn
, &num_clobbers
);
4474 cycles_since_jump
= INT_MAX
;
4479 /* Second pass: for predicted-true branches, see if anything at the
4480 branch destination needs extra nops. */
4481 for (insn
= get_insns (); insn
; insn
= NEXT_INSN (insn
))
4483 int cycles_since_jump
;
4485 && any_condjump_p (insn
)
4486 && (INSN_CODE (insn
) == CODE_FOR_cbranch_predicted_taken
4487 || cbranch_predicted_taken_p (insn
)))
4489 rtx_insn
*target
= JUMP_LABEL_AS_INSN (insn
);
4490 rtx_insn
*label
= target
;
4493 cycles_since_jump
= 0;
4494 for (; target
&& cycles_since_jump
< 3; target
= next_tgt
)
4498 next_tgt
= find_next_insn_start (target
);
4500 if (NOTE_P (target
) || BARRIER_P (target
) || LABEL_P (target
))
4503 if (JUMP_TABLE_DATA_P (target
))
4506 pat
= PATTERN (target
);
4507 if (GET_CODE (pat
) == USE
|| GET_CODE (pat
) == CLOBBER
4508 || GET_CODE (pat
) == ASM_INPUT
4509 || asm_noperands (pat
) >= 0)
4512 if (NONDEBUG_INSN_P (target
))
4514 rtx_insn
*load_insn
= find_load (target
);
4515 enum attr_type type
= type_for_anomaly (target
);
4516 int delay_needed
= 0;
4517 if (cycles_since_jump
< INT_MAX
)
4518 cycles_since_jump
++;
4520 if (load_insn
&& ENABLE_WA_SPECULATIVE_LOADS
)
4522 if (trapping_loads_p (load_insn
, -1, false))
4525 else if (type
== TYPE_SYNC
&& ENABLE_WA_SPECULATIVE_SYNCS
)
4528 if (delay_needed
> cycles_since_jump
)
4530 rtx_insn
*prev
= prev_real_insn (label
);
4531 delay_needed
-= cycles_since_jump
;
4533 fprintf (dump_file
, "Adding %d nops after %d\n",
4534 delay_needed
, INSN_UID (label
));
4536 && INSN_CODE (prev
) == CODE_FOR_cbranch_with_nops
)
4543 "Reducing nops on insn %d.\n",
4546 x
= XVECEXP (x
, 0, 1);
4547 v
= INTVAL (XVECEXP (x
, 0, 0)) - delay_needed
;
4548 XVECEXP (x
, 0, 0) = GEN_INT (v
);
4550 while (delay_needed
-- > 0)
4551 emit_insn_after (gen_nop (), label
);
4560 /* Called just before the final scheduling pass. If we need to insert NOPs
4561 later on to work around speculative loads, insert special placeholder
4562 insns that cause loads to be delayed for as many cycles as necessary
4563 (and possible). This reduces the number of NOPs we need to add.
4564 The dummy insns we generate are later removed by bfin_gen_bundles. */
4566 add_sched_insns_for_speculation (void)
4570 if (! ENABLE_WA_SPECULATIVE_LOADS
&& ! ENABLE_WA_SPECULATIVE_SYNCS
4571 && ! ENABLE_WA_INDIRECT_CALLS
)
4574 /* First pass: find predicted-false branches; if something after them
4575 needs nops, insert them or change the branch to predict true. */
4576 for (insn
= get_insns (); insn
; insn
= NEXT_INSN (insn
))
4580 if (NOTE_P (insn
) || BARRIER_P (insn
) || LABEL_P (insn
))
4582 if (JUMP_TABLE_DATA_P (insn
))
4585 pat
= PATTERN (insn
);
4586 if (GET_CODE (pat
) == USE
|| GET_CODE (pat
) == CLOBBER
4587 || GET_CODE (pat
) == ASM_INPUT
4588 || asm_noperands (pat
) >= 0)
4593 if (any_condjump_p (insn
)
4594 && !cbranch_predicted_taken_p (insn
))
4596 rtx_insn
*n
= next_real_insn (insn
);
4597 emit_insn_before (gen_stall (GEN_INT (3)), n
);
4602 /* Second pass: for predicted-true branches, see if anything at the
4603 branch destination needs extra nops. */
4604 for (insn
= get_insns (); insn
; insn
= NEXT_INSN (insn
))
4607 && any_condjump_p (insn
)
4608 && (cbranch_predicted_taken_p (insn
)))
4610 rtx target
= JUMP_LABEL (insn
);
4611 rtx_insn
*next
= next_real_insn (target
);
4613 if (GET_CODE (PATTERN (next
)) == UNSPEC_VOLATILE
4614 && get_attr_type (next
) == TYPE_STALL
)
4616 emit_insn_before (gen_stall (GEN_INT (1)), next
);
4621 /* We use the machine specific reorg pass for emitting CSYNC instructions
4622 after conditional branches as needed.
4624 The Blackfin is unusual in that a code sequence like
4627 may speculatively perform the load even if the condition isn't true. This
4628 happens for a branch that is predicted not taken, because the pipeline
4629 isn't flushed or stalled, so the early stages of the following instructions,
4630 which perform the memory reference, are allowed to execute before the
4631 jump condition is evaluated.
4632 Therefore, we must insert additional instructions in all places where this
4633 could lead to incorrect behavior. The manual recommends CSYNC, while
4634 VDSP seems to use NOPs (even though its corresponding compiler option is
4637 When optimizing for speed, we emit NOPs, which seems faster than a CSYNC.
4638 When optimizing for size, we turn the branch into a predicted taken one.
4639 This may be slower due to mispredicts, but saves code size. */
4644 /* We are freeing block_for_insn in the toplev to keep compatibility
4645 with old MDEP_REORGS that are not CFG based. Recompute it now. */
4646 compute_bb_for_insn ();
4648 if (flag_schedule_insns_after_reload
)
4650 splitting_for_sched
= 1;
4652 splitting_for_sched
= 0;
4654 add_sched_insns_for_speculation ();
4656 timevar_push (TV_SCHED2
);
4657 if (flag_selective_scheduling2
4658 && !maybe_skip_selective_scheduling ())
4659 run_selective_scheduling ();
4662 timevar_pop (TV_SCHED2
);
4664 /* Examine the schedule and insert nops as necessary for 64-bit parallel
4666 bfin_gen_bundles ();
4671 /* Doloop optimization */
4672 if (cfun
->machine
->has_hardware_loops
)
4673 bfin_reorg_loops ();
4675 workaround_speculation ();
4677 if (flag_var_tracking
)
4679 timevar_push (TV_VAR_TRACKING
);
4680 variable_tracking_main ();
4681 reorder_var_tracking_notes ();
4682 timevar_pop (TV_VAR_TRACKING
);
4685 df_finish_pass (false);
4687 workaround_rts_anomaly ();
4690 /* Handle interrupt_handler, exception_handler and nmi_handler function
4691 attributes; arguments as in struct attribute_spec.handler. */
4694 handle_int_attribute (tree
*node
, tree name
,
4695 tree args ATTRIBUTE_UNUSED
,
4696 int flags ATTRIBUTE_UNUSED
,
4700 if (TREE_CODE (x
) == FUNCTION_DECL
)
4703 if (TREE_CODE (x
) != FUNCTION_TYPE
)
4705 warning (OPT_Wattributes
, "%qE attribute only applies to functions",
4707 *no_add_attrs
= true;
4709 else if (funkind (x
) != SUBROUTINE
)
4710 error ("multiple function type attributes specified");
4715 /* Return 0 if the attributes for two types are incompatible, 1 if they
4716 are compatible, and 2 if they are nearly compatible (which causes a
4717 warning to be generated). */
4720 bfin_comp_type_attributes (const_tree type1
, const_tree type2
)
4722 e_funkind kind1
, kind2
;
4724 if (TREE_CODE (type1
) != FUNCTION_TYPE
)
4727 kind1
= funkind (type1
);
4728 kind2
= funkind (type2
);
4733 /* Check for mismatched modifiers */
4734 if (!lookup_attribute ("nesting", TYPE_ATTRIBUTES (type1
))
4735 != !lookup_attribute ("nesting", TYPE_ATTRIBUTES (type2
)))
4738 if (!lookup_attribute ("saveall", TYPE_ATTRIBUTES (type1
))
4739 != !lookup_attribute ("saveall", TYPE_ATTRIBUTES (type2
)))
4742 if (!lookup_attribute ("kspisusp", TYPE_ATTRIBUTES (type1
))
4743 != !lookup_attribute ("kspisusp", TYPE_ATTRIBUTES (type2
)))
4746 if (!lookup_attribute ("longcall", TYPE_ATTRIBUTES (type1
))
4747 != !lookup_attribute ("longcall", TYPE_ATTRIBUTES (type2
)))
4753 /* Handle a "longcall" or "shortcall" attribute; arguments as in
4754 struct attribute_spec.handler. */
4757 bfin_handle_longcall_attribute (tree
*node
, tree name
,
4758 tree args ATTRIBUTE_UNUSED
,
4759 int flags ATTRIBUTE_UNUSED
,
4762 if (TREE_CODE (*node
) != FUNCTION_TYPE
4763 && TREE_CODE (*node
) != FIELD_DECL
4764 && TREE_CODE (*node
) != TYPE_DECL
)
4766 warning (OPT_Wattributes
, "%qE attribute only applies to functions",
4768 *no_add_attrs
= true;
4771 if ((strcmp (IDENTIFIER_POINTER (name
), "longcall") == 0
4772 && lookup_attribute ("shortcall", TYPE_ATTRIBUTES (*node
)))
4773 || (strcmp (IDENTIFIER_POINTER (name
), "shortcall") == 0
4774 && lookup_attribute ("longcall", TYPE_ATTRIBUTES (*node
))))
4776 warning (OPT_Wattributes
,
4777 "can%'t apply both longcall and shortcall attributes to the same function");
4778 *no_add_attrs
= true;
4784 /* Handle a "l1_text" attribute; arguments as in
4785 struct attribute_spec.handler. */
4788 bfin_handle_l1_text_attribute (tree
*node
, tree name
, tree
ARG_UNUSED (args
),
4789 int ARG_UNUSED (flags
), bool *no_add_attrs
)
4793 if (TREE_CODE (decl
) != FUNCTION_DECL
)
4795 error ("%qE attribute only applies to functions",
4797 *no_add_attrs
= true;
4800 /* The decl may have already been given a section attribute
4801 from a previous declaration. Ensure they match. */
4802 else if (DECL_SECTION_NAME (decl
) != NULL
4803 && strcmp (DECL_SECTION_NAME (decl
),
4806 error ("section of %q+D conflicts with previous declaration",
4808 *no_add_attrs
= true;
4811 set_decl_section_name (decl
, ".l1.text");
4816 /* Handle a "l1_data", "l1_data_A" or "l1_data_B" attribute;
4817 arguments as in struct attribute_spec.handler. */
4820 bfin_handle_l1_data_attribute (tree
*node
, tree name
, tree
ARG_UNUSED (args
),
4821 int ARG_UNUSED (flags
), bool *no_add_attrs
)
4825 if (TREE_CODE (decl
) != VAR_DECL
)
4827 error ("%qE attribute only applies to variables",
4829 *no_add_attrs
= true;
4831 else if (current_function_decl
!= NULL_TREE
4832 && !TREE_STATIC (decl
))
4834 error ("%qE attribute cannot be specified for local variables",
4836 *no_add_attrs
= true;
4840 const char *section_name
;
4842 if (strcmp (IDENTIFIER_POINTER (name
), "l1_data") == 0)
4843 section_name
= ".l1.data";
4844 else if (strcmp (IDENTIFIER_POINTER (name
), "l1_data_A") == 0)
4845 section_name
= ".l1.data.A";
4846 else if (strcmp (IDENTIFIER_POINTER (name
), "l1_data_B") == 0)
4847 section_name
= ".l1.data.B";
4851 /* The decl may have already been given a section attribute
4852 from a previous declaration. Ensure they match. */
4853 if (DECL_SECTION_NAME (decl
) != NULL
4854 && strcmp (DECL_SECTION_NAME (decl
),
4857 error ("section of %q+D conflicts with previous declaration",
4859 *no_add_attrs
= true;
4862 set_decl_section_name (decl
, section_name
);
4868 /* Handle a "l2" attribute; arguments as in struct attribute_spec.handler. */
4871 bfin_handle_l2_attribute (tree
*node
, tree
ARG_UNUSED (name
),
4872 tree
ARG_UNUSED (args
), int ARG_UNUSED (flags
),
4877 if (TREE_CODE (decl
) == FUNCTION_DECL
)
4879 if (DECL_SECTION_NAME (decl
) != NULL
4880 && strcmp (DECL_SECTION_NAME (decl
),
4883 error ("section of %q+D conflicts with previous declaration",
4885 *no_add_attrs
= true;
4888 set_decl_section_name (decl
, ".l2.text");
4890 else if (TREE_CODE (decl
) == VAR_DECL
)
4892 if (DECL_SECTION_NAME (decl
) != NULL
4893 && strcmp (DECL_SECTION_NAME (decl
),
4896 error ("section of %q+D conflicts with previous declaration",
4898 *no_add_attrs
= true;
4901 set_decl_section_name (decl
, ".l2.data");
4907 /* Table of valid machine attributes. */
4908 static const struct attribute_spec bfin_attribute_table
[] =
4910 /* { name, min_len, max_len, decl_req, type_req, fn_type_req,
4911 affects_type_identity, handler, exclude } */
4912 { "interrupt_handler", 0, 0, false, true, true, false,
4913 handle_int_attribute
, NULL
},
4914 { "exception_handler", 0, 0, false, true, true, false,
4915 handle_int_attribute
, NULL
},
4916 { "nmi_handler", 0, 0, false, true, true, false, handle_int_attribute
,
4918 { "nesting", 0, 0, false, true, true, false, NULL
, NULL
},
4919 { "kspisusp", 0, 0, false, true, true, false, NULL
, NULL
},
4920 { "saveall", 0, 0, false, true, true, false, NULL
, NULL
},
4921 { "longcall", 0, 0, false, true, true, false,
4922 bfin_handle_longcall_attribute
, NULL
},
4923 { "shortcall", 0, 0, false, true, true, false,
4924 bfin_handle_longcall_attribute
, NULL
},
4925 { "l1_text", 0, 0, true, false, false, false,
4926 bfin_handle_l1_text_attribute
, NULL
},
4927 { "l1_data", 0, 0, true, false, false, false,
4928 bfin_handle_l1_data_attribute
, NULL
},
4929 { "l1_data_A", 0, 0, true, false, false, false,
4930 bfin_handle_l1_data_attribute
, NULL
},
4931 { "l1_data_B", 0, 0, true, false, false, false,
4932 bfin_handle_l1_data_attribute
, NULL
},
4933 { "l2", 0, 0, true, false, false, false, bfin_handle_l2_attribute
, NULL
},
4934 { NULL
, 0, 0, false, false, false, false, NULL
, NULL
}
4937 /* Implementation of TARGET_ASM_INTEGER. When using FD-PIC, we need to
4938 tell the assembler to generate pointers to function descriptors in
4942 bfin_assemble_integer (rtx value
, unsigned int size
, int aligned_p
)
4944 if (TARGET_FDPIC
&& size
== UNITS_PER_WORD
)
4946 if (GET_CODE (value
) == SYMBOL_REF
4947 && SYMBOL_REF_FUNCTION_P (value
))
4949 fputs ("\t.picptr\tfuncdesc(", asm_out_file
);
4950 output_addr_const (asm_out_file
, value
);
4951 fputs (")\n", asm_out_file
);
4956 /* We've set the unaligned SI op to NULL, so we always have to
4957 handle the unaligned case here. */
4958 assemble_integer_with_op ("\t.4byte\t", value
);
4962 return default_assemble_integer (value
, size
, aligned_p
);
4965 /* Output the assembler code for a thunk function. THUNK_DECL is the
4966 declaration for the thunk function itself, FUNCTION is the decl for
4967 the target function. DELTA is an immediate constant offset to be
4968 added to THIS. If VCALL_OFFSET is nonzero, the word at
4969 *(*this + vcall_offset) should be added to THIS. */
4972 bfin_output_mi_thunk (FILE *file ATTRIBUTE_UNUSED
,
4973 tree thunk ATTRIBUTE_UNUSED
, HOST_WIDE_INT delta
,
4974 HOST_WIDE_INT vcall_offset
, tree function
)
4977 /* The this parameter is passed as the first argument. */
4978 rtx this_rtx
= gen_rtx_REG (Pmode
, REG_R0
);
4980 /* Adjust the this parameter by a fixed constant. */
4984 if (delta
>= -64 && delta
<= 63)
4986 xops
[0] = GEN_INT (delta
);
4987 output_asm_insn ("%1 += %0;", xops
);
4989 else if (delta
>= -128 && delta
< -64)
4991 xops
[0] = GEN_INT (delta
+ 64);
4992 output_asm_insn ("%1 += -64; %1 += %0;", xops
);
4994 else if (delta
> 63 && delta
<= 126)
4996 xops
[0] = GEN_INT (delta
- 63);
4997 output_asm_insn ("%1 += 63; %1 += %0;", xops
);
5001 xops
[0] = GEN_INT (delta
);
5002 output_asm_insn ("r3.l = %h0; r3.h = %d0; %1 = %1 + r3;", xops
);
5006 /* Adjust the this parameter by a value stored in the vtable. */
5009 rtx p2tmp
= gen_rtx_REG (Pmode
, REG_P2
);
5010 rtx tmp
= gen_rtx_REG (Pmode
, REG_R3
);
5014 output_asm_insn ("%2 = r0; %2 = [%2];", xops
);
5016 /* Adjust the this parameter. */
5017 xops
[0] = gen_rtx_MEM (Pmode
, plus_constant (Pmode
, p2tmp
,
5019 if (!memory_operand (xops
[0], Pmode
))
5021 rtx tmp2
= gen_rtx_REG (Pmode
, REG_P1
);
5022 xops
[0] = GEN_INT (vcall_offset
);
5024 output_asm_insn ("%h1 = %h0; %d1 = %d0; %2 = %2 + %1", xops
);
5025 xops
[0] = gen_rtx_MEM (Pmode
, p2tmp
);
5028 output_asm_insn ("%1 = %0; %2 = %2 + %1;", xops
);
5031 xops
[0] = XEXP (DECL_RTL (function
), 0);
5032 if (1 || !flag_pic
|| (*targetm
.binds_local_p
) (function
))
5033 output_asm_insn ("jump.l\t%P0", xops
);
5036 /* Codes for all the Blackfin builtins. */
5042 BFIN_BUILTIN_COMPOSE_2X16
,
5043 BFIN_BUILTIN_EXTRACTLO
,
5044 BFIN_BUILTIN_EXTRACTHI
,
5046 BFIN_BUILTIN_SSADD_2X16
,
5047 BFIN_BUILTIN_SSSUB_2X16
,
5048 BFIN_BUILTIN_SSADDSUB_2X16
,
5049 BFIN_BUILTIN_SSSUBADD_2X16
,
5050 BFIN_BUILTIN_MULT_2X16
,
5051 BFIN_BUILTIN_MULTR_2X16
,
5052 BFIN_BUILTIN_NEG_2X16
,
5053 BFIN_BUILTIN_ABS_2X16
,
5054 BFIN_BUILTIN_MIN_2X16
,
5055 BFIN_BUILTIN_MAX_2X16
,
5057 BFIN_BUILTIN_SSADD_1X16
,
5058 BFIN_BUILTIN_SSSUB_1X16
,
5059 BFIN_BUILTIN_MULT_1X16
,
5060 BFIN_BUILTIN_MULTR_1X16
,
5061 BFIN_BUILTIN_NORM_1X16
,
5062 BFIN_BUILTIN_NEG_1X16
,
5063 BFIN_BUILTIN_ABS_1X16
,
5064 BFIN_BUILTIN_MIN_1X16
,
5065 BFIN_BUILTIN_MAX_1X16
,
5067 BFIN_BUILTIN_SUM_2X16
,
5068 BFIN_BUILTIN_DIFFHL_2X16
,
5069 BFIN_BUILTIN_DIFFLH_2X16
,
5071 BFIN_BUILTIN_SSADD_1X32
,
5072 BFIN_BUILTIN_SSSUB_1X32
,
5073 BFIN_BUILTIN_NORM_1X32
,
5074 BFIN_BUILTIN_ROUND_1X32
,
5075 BFIN_BUILTIN_NEG_1X32
,
5076 BFIN_BUILTIN_ABS_1X32
,
5077 BFIN_BUILTIN_MIN_1X32
,
5078 BFIN_BUILTIN_MAX_1X32
,
5079 BFIN_BUILTIN_MULT_1X32
,
5080 BFIN_BUILTIN_MULT_1X32X32
,
5081 BFIN_BUILTIN_MULT_1X32X32NS
,
5083 BFIN_BUILTIN_MULHISILL
,
5084 BFIN_BUILTIN_MULHISILH
,
5085 BFIN_BUILTIN_MULHISIHL
,
5086 BFIN_BUILTIN_MULHISIHH
,
5088 BFIN_BUILTIN_LSHIFT_1X16
,
5089 BFIN_BUILTIN_LSHIFT_2X16
,
5090 BFIN_BUILTIN_SSASHIFT_1X16
,
5091 BFIN_BUILTIN_SSASHIFT_2X16
,
5092 BFIN_BUILTIN_SSASHIFT_1X32
,
5094 BFIN_BUILTIN_CPLX_MUL_16
,
5095 BFIN_BUILTIN_CPLX_MAC_16
,
5096 BFIN_BUILTIN_CPLX_MSU_16
,
5098 BFIN_BUILTIN_CPLX_MUL_16_S40
,
5099 BFIN_BUILTIN_CPLX_MAC_16_S40
,
5100 BFIN_BUILTIN_CPLX_MSU_16_S40
,
5102 BFIN_BUILTIN_CPLX_SQU
,
5104 BFIN_BUILTIN_LOADBYTES
,
5109 #define def_builtin(NAME, TYPE, CODE) \
5111 add_builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD, \
5115 /* Set up all builtin functions for this target. */
5117 bfin_init_builtins (void)
5119 tree V2HI_type_node
= build_vector_type_for_mode (intHI_type_node
, V2HImode
);
5120 tree void_ftype_void
5121 = build_function_type_list (void_type_node
, NULL_TREE
);
5122 tree short_ftype_short
5123 = build_function_type_list (short_integer_type_node
, short_integer_type_node
,
5125 tree short_ftype_int_int
5126 = build_function_type_list (short_integer_type_node
, integer_type_node
,
5127 integer_type_node
, NULL_TREE
);
5128 tree int_ftype_int_int
5129 = build_function_type_list (integer_type_node
, integer_type_node
,
5130 integer_type_node
, NULL_TREE
);
5132 = build_function_type_list (integer_type_node
, integer_type_node
,
5134 tree short_ftype_int
5135 = build_function_type_list (short_integer_type_node
, integer_type_node
,
5137 tree int_ftype_v2hi_v2hi
5138 = build_function_type_list (integer_type_node
, V2HI_type_node
,
5139 V2HI_type_node
, NULL_TREE
);
5140 tree v2hi_ftype_v2hi_v2hi
5141 = build_function_type_list (V2HI_type_node
, V2HI_type_node
,
5142 V2HI_type_node
, NULL_TREE
);
5143 tree v2hi_ftype_v2hi_v2hi_v2hi
5144 = build_function_type_list (V2HI_type_node
, V2HI_type_node
,
5145 V2HI_type_node
, V2HI_type_node
, NULL_TREE
);
5146 tree v2hi_ftype_int_int
5147 = build_function_type_list (V2HI_type_node
, integer_type_node
,
5148 integer_type_node
, NULL_TREE
);
5149 tree v2hi_ftype_v2hi_int
5150 = build_function_type_list (V2HI_type_node
, V2HI_type_node
,
5151 integer_type_node
, NULL_TREE
);
5152 tree int_ftype_short_short
5153 = build_function_type_list (integer_type_node
, short_integer_type_node
,
5154 short_integer_type_node
, NULL_TREE
);
5155 tree v2hi_ftype_v2hi
5156 = build_function_type_list (V2HI_type_node
, V2HI_type_node
, NULL_TREE
);
5157 tree short_ftype_v2hi
5158 = build_function_type_list (short_integer_type_node
, V2HI_type_node
,
5161 = build_function_type_list (integer_type_node
,
5162 build_pointer_type (integer_type_node
),
5165 /* Add the remaining MMX insns with somewhat more complicated types. */
5166 def_builtin ("__builtin_bfin_csync", void_ftype_void
, BFIN_BUILTIN_CSYNC
);
5167 def_builtin ("__builtin_bfin_ssync", void_ftype_void
, BFIN_BUILTIN_SSYNC
);
5169 def_builtin ("__builtin_bfin_ones", short_ftype_int
, BFIN_BUILTIN_ONES
);
5171 def_builtin ("__builtin_bfin_compose_2x16", v2hi_ftype_int_int
,
5172 BFIN_BUILTIN_COMPOSE_2X16
);
5173 def_builtin ("__builtin_bfin_extract_hi", short_ftype_v2hi
,
5174 BFIN_BUILTIN_EXTRACTHI
);
5175 def_builtin ("__builtin_bfin_extract_lo", short_ftype_v2hi
,
5176 BFIN_BUILTIN_EXTRACTLO
);
5178 def_builtin ("__builtin_bfin_min_fr2x16", v2hi_ftype_v2hi_v2hi
,
5179 BFIN_BUILTIN_MIN_2X16
);
5180 def_builtin ("__builtin_bfin_max_fr2x16", v2hi_ftype_v2hi_v2hi
,
5181 BFIN_BUILTIN_MAX_2X16
);
5183 def_builtin ("__builtin_bfin_add_fr2x16", v2hi_ftype_v2hi_v2hi
,
5184 BFIN_BUILTIN_SSADD_2X16
);
5185 def_builtin ("__builtin_bfin_sub_fr2x16", v2hi_ftype_v2hi_v2hi
,
5186 BFIN_BUILTIN_SSSUB_2X16
);
5187 def_builtin ("__builtin_bfin_dspaddsubsat", v2hi_ftype_v2hi_v2hi
,
5188 BFIN_BUILTIN_SSADDSUB_2X16
);
5189 def_builtin ("__builtin_bfin_dspsubaddsat", v2hi_ftype_v2hi_v2hi
,
5190 BFIN_BUILTIN_SSSUBADD_2X16
);
5191 def_builtin ("__builtin_bfin_mult_fr2x16", v2hi_ftype_v2hi_v2hi
,
5192 BFIN_BUILTIN_MULT_2X16
);
5193 def_builtin ("__builtin_bfin_multr_fr2x16", v2hi_ftype_v2hi_v2hi
,
5194 BFIN_BUILTIN_MULTR_2X16
);
5195 def_builtin ("__builtin_bfin_negate_fr2x16", v2hi_ftype_v2hi
,
5196 BFIN_BUILTIN_NEG_2X16
);
5197 def_builtin ("__builtin_bfin_abs_fr2x16", v2hi_ftype_v2hi
,
5198 BFIN_BUILTIN_ABS_2X16
);
5200 def_builtin ("__builtin_bfin_min_fr1x16", short_ftype_int_int
,
5201 BFIN_BUILTIN_MIN_1X16
);
5202 def_builtin ("__builtin_bfin_max_fr1x16", short_ftype_int_int
,
5203 BFIN_BUILTIN_MAX_1X16
);
5205 def_builtin ("__builtin_bfin_add_fr1x16", short_ftype_int_int
,
5206 BFIN_BUILTIN_SSADD_1X16
);
5207 def_builtin ("__builtin_bfin_sub_fr1x16", short_ftype_int_int
,
5208 BFIN_BUILTIN_SSSUB_1X16
);
5209 def_builtin ("__builtin_bfin_mult_fr1x16", short_ftype_int_int
,
5210 BFIN_BUILTIN_MULT_1X16
);
5211 def_builtin ("__builtin_bfin_multr_fr1x16", short_ftype_int_int
,
5212 BFIN_BUILTIN_MULTR_1X16
);
5213 def_builtin ("__builtin_bfin_negate_fr1x16", short_ftype_short
,
5214 BFIN_BUILTIN_NEG_1X16
);
5215 def_builtin ("__builtin_bfin_abs_fr1x16", short_ftype_short
,
5216 BFIN_BUILTIN_ABS_1X16
);
5217 def_builtin ("__builtin_bfin_norm_fr1x16", short_ftype_int
,
5218 BFIN_BUILTIN_NORM_1X16
);
5220 def_builtin ("__builtin_bfin_sum_fr2x16", short_ftype_v2hi
,
5221 BFIN_BUILTIN_SUM_2X16
);
5222 def_builtin ("__builtin_bfin_diff_hl_fr2x16", short_ftype_v2hi
,
5223 BFIN_BUILTIN_DIFFHL_2X16
);
5224 def_builtin ("__builtin_bfin_diff_lh_fr2x16", short_ftype_v2hi
,
5225 BFIN_BUILTIN_DIFFLH_2X16
);
5227 def_builtin ("__builtin_bfin_mulhisill", int_ftype_v2hi_v2hi
,
5228 BFIN_BUILTIN_MULHISILL
);
5229 def_builtin ("__builtin_bfin_mulhisihl", int_ftype_v2hi_v2hi
,
5230 BFIN_BUILTIN_MULHISIHL
);
5231 def_builtin ("__builtin_bfin_mulhisilh", int_ftype_v2hi_v2hi
,
5232 BFIN_BUILTIN_MULHISILH
);
5233 def_builtin ("__builtin_bfin_mulhisihh", int_ftype_v2hi_v2hi
,
5234 BFIN_BUILTIN_MULHISIHH
);
5236 def_builtin ("__builtin_bfin_min_fr1x32", int_ftype_int_int
,
5237 BFIN_BUILTIN_MIN_1X32
);
5238 def_builtin ("__builtin_bfin_max_fr1x32", int_ftype_int_int
,
5239 BFIN_BUILTIN_MAX_1X32
);
5241 def_builtin ("__builtin_bfin_add_fr1x32", int_ftype_int_int
,
5242 BFIN_BUILTIN_SSADD_1X32
);
5243 def_builtin ("__builtin_bfin_sub_fr1x32", int_ftype_int_int
,
5244 BFIN_BUILTIN_SSSUB_1X32
);
5245 def_builtin ("__builtin_bfin_negate_fr1x32", int_ftype_int
,
5246 BFIN_BUILTIN_NEG_1X32
);
5247 def_builtin ("__builtin_bfin_abs_fr1x32", int_ftype_int
,
5248 BFIN_BUILTIN_ABS_1X32
);
5249 def_builtin ("__builtin_bfin_norm_fr1x32", short_ftype_int
,
5250 BFIN_BUILTIN_NORM_1X32
);
5251 def_builtin ("__builtin_bfin_round_fr1x32", short_ftype_int
,
5252 BFIN_BUILTIN_ROUND_1X32
);
5253 def_builtin ("__builtin_bfin_mult_fr1x32", int_ftype_short_short
,
5254 BFIN_BUILTIN_MULT_1X32
);
5255 def_builtin ("__builtin_bfin_mult_fr1x32x32", int_ftype_int_int
,
5256 BFIN_BUILTIN_MULT_1X32X32
);
5257 def_builtin ("__builtin_bfin_mult_fr1x32x32NS", int_ftype_int_int
,
5258 BFIN_BUILTIN_MULT_1X32X32NS
);
5261 def_builtin ("__builtin_bfin_shl_fr1x16", short_ftype_int_int
,
5262 BFIN_BUILTIN_SSASHIFT_1X16
);
5263 def_builtin ("__builtin_bfin_shl_fr2x16", v2hi_ftype_v2hi_int
,
5264 BFIN_BUILTIN_SSASHIFT_2X16
);
5265 def_builtin ("__builtin_bfin_lshl_fr1x16", short_ftype_int_int
,
5266 BFIN_BUILTIN_LSHIFT_1X16
);
5267 def_builtin ("__builtin_bfin_lshl_fr2x16", v2hi_ftype_v2hi_int
,
5268 BFIN_BUILTIN_LSHIFT_2X16
);
5269 def_builtin ("__builtin_bfin_shl_fr1x32", int_ftype_int_int
,
5270 BFIN_BUILTIN_SSASHIFT_1X32
);
5272 /* Complex numbers. */
5273 def_builtin ("__builtin_bfin_cmplx_add", v2hi_ftype_v2hi_v2hi
,
5274 BFIN_BUILTIN_SSADD_2X16
);
5275 def_builtin ("__builtin_bfin_cmplx_sub", v2hi_ftype_v2hi_v2hi
,
5276 BFIN_BUILTIN_SSSUB_2X16
);
5277 def_builtin ("__builtin_bfin_cmplx_mul", v2hi_ftype_v2hi_v2hi
,
5278 BFIN_BUILTIN_CPLX_MUL_16
);
5279 def_builtin ("__builtin_bfin_cmplx_mac", v2hi_ftype_v2hi_v2hi_v2hi
,
5280 BFIN_BUILTIN_CPLX_MAC_16
);
5281 def_builtin ("__builtin_bfin_cmplx_msu", v2hi_ftype_v2hi_v2hi_v2hi
,
5282 BFIN_BUILTIN_CPLX_MSU_16
);
5283 def_builtin ("__builtin_bfin_cmplx_mul_s40", v2hi_ftype_v2hi_v2hi
,
5284 BFIN_BUILTIN_CPLX_MUL_16_S40
);
5285 def_builtin ("__builtin_bfin_cmplx_mac_s40", v2hi_ftype_v2hi_v2hi_v2hi
,
5286 BFIN_BUILTIN_CPLX_MAC_16_S40
);
5287 def_builtin ("__builtin_bfin_cmplx_msu_s40", v2hi_ftype_v2hi_v2hi_v2hi
,
5288 BFIN_BUILTIN_CPLX_MSU_16_S40
);
5289 def_builtin ("__builtin_bfin_csqu_fr16", v2hi_ftype_v2hi
,
5290 BFIN_BUILTIN_CPLX_SQU
);
5292 /* "Unaligned" load. */
5293 def_builtin ("__builtin_bfin_loadbytes", int_ftype_pint
,
5294 BFIN_BUILTIN_LOADBYTES
);
5299 struct builtin_description
5301 const enum insn_code icode
;
5302 const char *const name
;
5303 const enum bfin_builtins code
;
5307 static const struct builtin_description bdesc_2arg
[] =
5309 { CODE_FOR_composev2hi
, "__builtin_bfin_compose_2x16", BFIN_BUILTIN_COMPOSE_2X16
, -1 },
5311 { CODE_FOR_ssashiftv2hi3
, "__builtin_bfin_shl_fr2x16", BFIN_BUILTIN_SSASHIFT_2X16
, -1 },
5312 { CODE_FOR_ssashifthi3
, "__builtin_bfin_shl_fr1x16", BFIN_BUILTIN_SSASHIFT_1X16
, -1 },
5313 { CODE_FOR_lshiftv2hi3
, "__builtin_bfin_lshl_fr2x16", BFIN_BUILTIN_LSHIFT_2X16
, -1 },
5314 { CODE_FOR_lshifthi3
, "__builtin_bfin_lshl_fr1x16", BFIN_BUILTIN_LSHIFT_1X16
, -1 },
5315 { CODE_FOR_ssashiftsi3
, "__builtin_bfin_shl_fr1x32", BFIN_BUILTIN_SSASHIFT_1X32
, -1 },
5317 { CODE_FOR_sminhi3
, "__builtin_bfin_min_fr1x16", BFIN_BUILTIN_MIN_1X16
, -1 },
5318 { CODE_FOR_smaxhi3
, "__builtin_bfin_max_fr1x16", BFIN_BUILTIN_MAX_1X16
, -1 },
5319 { CODE_FOR_ssaddhi3
, "__builtin_bfin_add_fr1x16", BFIN_BUILTIN_SSADD_1X16
, -1 },
5320 { CODE_FOR_sssubhi3
, "__builtin_bfin_sub_fr1x16", BFIN_BUILTIN_SSSUB_1X16
, -1 },
5322 { CODE_FOR_sminsi3
, "__builtin_bfin_min_fr1x32", BFIN_BUILTIN_MIN_1X32
, -1 },
5323 { CODE_FOR_smaxsi3
, "__builtin_bfin_max_fr1x32", BFIN_BUILTIN_MAX_1X32
, -1 },
5324 { CODE_FOR_ssaddsi3
, "__builtin_bfin_add_fr1x32", BFIN_BUILTIN_SSADD_1X32
, -1 },
5325 { CODE_FOR_sssubsi3
, "__builtin_bfin_sub_fr1x32", BFIN_BUILTIN_SSSUB_1X32
, -1 },
5327 { CODE_FOR_sminv2hi3
, "__builtin_bfin_min_fr2x16", BFIN_BUILTIN_MIN_2X16
, -1 },
5328 { CODE_FOR_smaxv2hi3
, "__builtin_bfin_max_fr2x16", BFIN_BUILTIN_MAX_2X16
, -1 },
5329 { CODE_FOR_ssaddv2hi3
, "__builtin_bfin_add_fr2x16", BFIN_BUILTIN_SSADD_2X16
, -1 },
5330 { CODE_FOR_sssubv2hi3
, "__builtin_bfin_sub_fr2x16", BFIN_BUILTIN_SSSUB_2X16
, -1 },
5331 { CODE_FOR_ssaddsubv2hi3
, "__builtin_bfin_dspaddsubsat", BFIN_BUILTIN_SSADDSUB_2X16
, -1 },
5332 { CODE_FOR_sssubaddv2hi3
, "__builtin_bfin_dspsubaddsat", BFIN_BUILTIN_SSSUBADD_2X16
, -1 },
5334 { CODE_FOR_flag_mulhisi
, "__builtin_bfin_mult_fr1x32", BFIN_BUILTIN_MULT_1X32
, MACFLAG_NONE
},
5335 { CODE_FOR_flag_mulhi
, "__builtin_bfin_mult_fr1x16", BFIN_BUILTIN_MULT_1X16
, MACFLAG_T
},
5336 { CODE_FOR_flag_mulhi
, "__builtin_bfin_multr_fr1x16", BFIN_BUILTIN_MULTR_1X16
, MACFLAG_NONE
},
5337 { CODE_FOR_flag_mulv2hi
, "__builtin_bfin_mult_fr2x16", BFIN_BUILTIN_MULT_2X16
, MACFLAG_T
},
5338 { CODE_FOR_flag_mulv2hi
, "__builtin_bfin_multr_fr2x16", BFIN_BUILTIN_MULTR_2X16
, MACFLAG_NONE
},
5340 { CODE_FOR_mulhisi_ll
, "__builtin_bfin_mulhisill", BFIN_BUILTIN_MULHISILL
, -1 },
5341 { CODE_FOR_mulhisi_lh
, "__builtin_bfin_mulhisilh", BFIN_BUILTIN_MULHISILH
, -1 },
5342 { CODE_FOR_mulhisi_hl
, "__builtin_bfin_mulhisihl", BFIN_BUILTIN_MULHISIHL
, -1 },
5343 { CODE_FOR_mulhisi_hh
, "__builtin_bfin_mulhisihh", BFIN_BUILTIN_MULHISIHH
, -1 }
5347 static const struct builtin_description bdesc_1arg
[] =
5349 { CODE_FOR_loadbytes
, "__builtin_bfin_loadbytes", BFIN_BUILTIN_LOADBYTES
, 0 },
5351 { CODE_FOR_ones
, "__builtin_bfin_ones", BFIN_BUILTIN_ONES
, 0 },
5353 { CODE_FOR_clrsbhi2
, "__builtin_bfin_norm_fr1x16", BFIN_BUILTIN_NORM_1X16
, 0 },
5354 { CODE_FOR_ssneghi2
, "__builtin_bfin_negate_fr1x16", BFIN_BUILTIN_NEG_1X16
, 0 },
5355 { CODE_FOR_abshi2
, "__builtin_bfin_abs_fr1x16", BFIN_BUILTIN_ABS_1X16
, 0 },
5357 { CODE_FOR_clrsbsi2
, "__builtin_bfin_norm_fr1x32", BFIN_BUILTIN_NORM_1X32
, 0 },
5358 { CODE_FOR_ssroundsi2
, "__builtin_bfin_round_fr1x32", BFIN_BUILTIN_ROUND_1X32
, 0 },
5359 { CODE_FOR_ssnegsi2
, "__builtin_bfin_negate_fr1x32", BFIN_BUILTIN_NEG_1X32
, 0 },
5360 { CODE_FOR_ssabssi2
, "__builtin_bfin_abs_fr1x32", BFIN_BUILTIN_ABS_1X32
, 0 },
5362 { CODE_FOR_movv2hi_hi_low
, "__builtin_bfin_extract_lo", BFIN_BUILTIN_EXTRACTLO
, 0 },
5363 { CODE_FOR_movv2hi_hi_high
, "__builtin_bfin_extract_hi", BFIN_BUILTIN_EXTRACTHI
, 0 },
5364 { CODE_FOR_ssnegv2hi2
, "__builtin_bfin_negate_fr2x16", BFIN_BUILTIN_NEG_2X16
, 0 },
5365 { CODE_FOR_ssabsv2hi2
, "__builtin_bfin_abs_fr2x16", BFIN_BUILTIN_ABS_2X16
, 0 }
5368 /* Errors in the source file can cause expand_expr to return const0_rtx
5369 where we expect a vector. To avoid crashing, use one of the vector
5370 clear instructions. */
5372 safe_vector_operand (rtx x
, machine_mode mode
)
5374 if (x
!= const0_rtx
)
5376 x
= gen_reg_rtx (SImode
);
5378 emit_insn (gen_movsi (x
, CONST0_RTX (SImode
)));
5379 return gen_lowpart (mode
, x
);
5382 /* Subroutine of bfin_expand_builtin to take care of binop insns. MACFLAG is -1
5383 if this is a normal binary op, or one of the MACFLAG_xxx constants. */
5386 bfin_expand_binop_builtin (enum insn_code icode
, tree exp
, rtx target
,
5390 tree arg0
= CALL_EXPR_ARG (exp
, 0);
5391 tree arg1
= CALL_EXPR_ARG (exp
, 1);
5392 rtx op0
= expand_normal (arg0
);
5393 rtx op1
= expand_normal (arg1
);
5394 machine_mode op0mode
= GET_MODE (op0
);
5395 machine_mode op1mode
= GET_MODE (op1
);
5396 machine_mode tmode
= insn_data
[icode
].operand
[0].mode
;
5397 machine_mode mode0
= insn_data
[icode
].operand
[1].mode
;
5398 machine_mode mode1
= insn_data
[icode
].operand
[2].mode
;
5400 if (VECTOR_MODE_P (mode0
))
5401 op0
= safe_vector_operand (op0
, mode0
);
5402 if (VECTOR_MODE_P (mode1
))
5403 op1
= safe_vector_operand (op1
, mode1
);
5406 || GET_MODE (target
) != tmode
5407 || ! (*insn_data
[icode
].operand
[0].predicate
) (target
, tmode
))
5408 target
= gen_reg_rtx (tmode
);
5410 if ((op0mode
== SImode
|| op0mode
== VOIDmode
) && mode0
== HImode
)
5413 op0
= gen_lowpart (HImode
, op0
);
5415 if ((op1mode
== SImode
|| op1mode
== VOIDmode
) && mode1
== HImode
)
5418 op1
= gen_lowpart (HImode
, op1
);
5420 /* In case the insn wants input operands in modes different from
5421 the result, abort. */
5422 gcc_assert ((op0mode
== mode0
|| op0mode
== VOIDmode
)
5423 && (op1mode
== mode1
|| op1mode
== VOIDmode
));
5425 if (! (*insn_data
[icode
].operand
[1].predicate
) (op0
, mode0
))
5426 op0
= copy_to_mode_reg (mode0
, op0
);
5427 if (! (*insn_data
[icode
].operand
[2].predicate
) (op1
, mode1
))
5428 op1
= copy_to_mode_reg (mode1
, op1
);
5431 pat
= GEN_FCN (icode
) (target
, op0
, op1
);
5433 pat
= GEN_FCN (icode
) (target
, op0
, op1
, GEN_INT (macflag
));
5441 /* Subroutine of bfin_expand_builtin to take care of unop insns. */
5444 bfin_expand_unop_builtin (enum insn_code icode
, tree exp
,
5448 tree arg0
= CALL_EXPR_ARG (exp
, 0);
5449 rtx op0
= expand_normal (arg0
);
5450 machine_mode op0mode
= GET_MODE (op0
);
5451 machine_mode tmode
= insn_data
[icode
].operand
[0].mode
;
5452 machine_mode mode0
= insn_data
[icode
].operand
[1].mode
;
5455 || GET_MODE (target
) != tmode
5456 || ! (*insn_data
[icode
].operand
[0].predicate
) (target
, tmode
))
5457 target
= gen_reg_rtx (tmode
);
5459 if (VECTOR_MODE_P (mode0
))
5460 op0
= safe_vector_operand (op0
, mode0
);
5462 if (op0mode
== SImode
&& mode0
== HImode
)
5465 op0
= gen_lowpart (HImode
, op0
);
5467 gcc_assert (op0mode
== mode0
|| op0mode
== VOIDmode
);
5469 if (! (*insn_data
[icode
].operand
[1].predicate
) (op0
, mode0
))
5470 op0
= copy_to_mode_reg (mode0
, op0
);
5472 pat
= GEN_FCN (icode
) (target
, op0
);
5479 /* Expand an expression EXP that calls a built-in function,
5480 with result going to TARGET if that's convenient
5481 (and in mode MODE if that's convenient).
5482 SUBTARGET may be used as the target for computing one of EXP's operands.
5483 IGNORE is nonzero if the value is to be ignored. */
5486 bfin_expand_builtin (tree exp
, rtx target ATTRIBUTE_UNUSED
,
5487 rtx subtarget ATTRIBUTE_UNUSED
,
5488 machine_mode mode ATTRIBUTE_UNUSED
,
5489 int ignore ATTRIBUTE_UNUSED
)
5492 enum insn_code icode
;
5493 const struct builtin_description
*d
;
5494 tree fndecl
= TREE_OPERAND (CALL_EXPR_FN (exp
), 0);
5495 unsigned int fcode
= DECL_FUNCTION_CODE (fndecl
);
5496 tree arg0
, arg1
, arg2
;
5497 rtx op0
, op1
, op2
, accvec
, pat
, tmp1
, tmp2
, a0reg
, a1reg
;
5498 machine_mode tmode
, mode0
;
5502 case BFIN_BUILTIN_CSYNC
:
5503 emit_insn (gen_csync ());
5505 case BFIN_BUILTIN_SSYNC
:
5506 emit_insn (gen_ssync ());
5509 case BFIN_BUILTIN_DIFFHL_2X16
:
5510 case BFIN_BUILTIN_DIFFLH_2X16
:
5511 case BFIN_BUILTIN_SUM_2X16
:
5512 arg0
= CALL_EXPR_ARG (exp
, 0);
5513 op0
= expand_normal (arg0
);
5514 icode
= (fcode
== BFIN_BUILTIN_DIFFHL_2X16
? CODE_FOR_subhilov2hi3
5515 : fcode
== BFIN_BUILTIN_DIFFLH_2X16
? CODE_FOR_sublohiv2hi3
5516 : CODE_FOR_ssaddhilov2hi3
);
5517 tmode
= insn_data
[icode
].operand
[0].mode
;
5518 mode0
= insn_data
[icode
].operand
[1].mode
;
5521 || GET_MODE (target
) != tmode
5522 || ! (*insn_data
[icode
].operand
[0].predicate
) (target
, tmode
))
5523 target
= gen_reg_rtx (tmode
);
5525 if (VECTOR_MODE_P (mode0
))
5526 op0
= safe_vector_operand (op0
, mode0
);
5528 if (! (*insn_data
[icode
].operand
[1].predicate
) (op0
, mode0
))
5529 op0
= copy_to_mode_reg (mode0
, op0
);
5531 pat
= GEN_FCN (icode
) (target
, op0
, op0
);
5537 case BFIN_BUILTIN_MULT_1X32X32
:
5538 case BFIN_BUILTIN_MULT_1X32X32NS
:
5539 arg0
= CALL_EXPR_ARG (exp
, 0);
5540 arg1
= CALL_EXPR_ARG (exp
, 1);
5541 op0
= expand_normal (arg0
);
5542 op1
= expand_normal (arg1
);
5544 || !register_operand (target
, SImode
))
5545 target
= gen_reg_rtx (SImode
);
5546 if (! register_operand (op0
, SImode
))
5547 op0
= copy_to_mode_reg (SImode
, op0
);
5548 if (! register_operand (op1
, SImode
))
5549 op1
= copy_to_mode_reg (SImode
, op1
);
5551 a1reg
= gen_rtx_REG (PDImode
, REG_A1
);
5552 a0reg
= gen_rtx_REG (PDImode
, REG_A0
);
5553 tmp1
= gen_lowpart (V2HImode
, op0
);
5554 tmp2
= gen_lowpart (V2HImode
, op1
);
5555 emit_insn (gen_flag_macinit1hi (a1reg
,
5556 gen_lowpart (HImode
, op0
),
5557 gen_lowpart (HImode
, op1
),
5558 GEN_INT (MACFLAG_FU
)));
5559 emit_insn (gen_lshrpdi3 (a1reg
, a1reg
, GEN_INT (16)));
5561 if (fcode
== BFIN_BUILTIN_MULT_1X32X32
)
5562 emit_insn (gen_flag_mul_macv2hi_parts_acconly (a0reg
, a1reg
, tmp1
, tmp2
,
5563 const1_rtx
, const1_rtx
,
5564 const1_rtx
, const0_rtx
, a1reg
,
5565 const0_rtx
, GEN_INT (MACFLAG_NONE
),
5566 GEN_INT (MACFLAG_M
)));
5569 /* For saturating multiplication, there's exactly one special case
5570 to be handled: multiplying the smallest negative value with
5571 itself. Due to shift correction in fractional multiplies, this
5572 can overflow. Iff this happens, OP2 will contain 1, which, when
5573 added in 32 bits to the smallest negative, wraps to the largest
5574 positive, which is the result we want. */
5575 op2
= gen_reg_rtx (V2HImode
);
5576 emit_insn (gen_packv2hi (op2
, tmp1
, tmp2
, const0_rtx
, const0_rtx
));
5577 emit_insn (gen_movsibi (gen_rtx_REG (BImode
, REG_CC
),
5578 gen_lowpart (SImode
, op2
)));
5579 emit_insn (gen_flag_mul_macv2hi_parts_acconly_andcc0 (a0reg
, a1reg
, tmp1
, tmp2
,
5580 const1_rtx
, const1_rtx
,
5581 const1_rtx
, const0_rtx
, a1reg
,
5582 const0_rtx
, GEN_INT (MACFLAG_NONE
),
5583 GEN_INT (MACFLAG_M
)));
5584 op2
= gen_reg_rtx (SImode
);
5585 emit_insn (gen_movbisi (op2
, gen_rtx_REG (BImode
, REG_CC
)));
5587 emit_insn (gen_flag_machi_parts_acconly (a1reg
, tmp2
, tmp1
,
5588 const1_rtx
, const0_rtx
,
5589 a1reg
, const0_rtx
, GEN_INT (MACFLAG_M
)));
5590 emit_insn (gen_ashrpdi3 (a1reg
, a1reg
, GEN_INT (15)));
5591 emit_insn (gen_sum_of_accumulators (target
, a0reg
, a0reg
, a1reg
));
5592 if (fcode
== BFIN_BUILTIN_MULT_1X32X32NS
)
5593 emit_insn (gen_addsi3 (target
, target
, op2
));
5596 case BFIN_BUILTIN_CPLX_MUL_16
:
5597 case BFIN_BUILTIN_CPLX_MUL_16_S40
:
5598 arg0
= CALL_EXPR_ARG (exp
, 0);
5599 arg1
= CALL_EXPR_ARG (exp
, 1);
5600 op0
= expand_normal (arg0
);
5601 op1
= expand_normal (arg1
);
5602 accvec
= gen_reg_rtx (V2PDImode
);
5603 icode
= CODE_FOR_flag_macv2hi_parts
;
5604 tmode
= insn_data
[icode
].operand
[0].mode
;
5607 || GET_MODE (target
) != V2HImode
5608 || ! (*insn_data
[icode
].operand
[0].predicate
) (target
, V2HImode
))
5609 target
= gen_reg_rtx (tmode
);
5610 if (! register_operand (op0
, GET_MODE (op0
)))
5611 op0
= copy_to_mode_reg (GET_MODE (op0
), op0
);
5612 if (! register_operand (op1
, GET_MODE (op1
)))
5613 op1
= copy_to_mode_reg (GET_MODE (op1
), op1
);
5615 if (fcode
== BFIN_BUILTIN_CPLX_MUL_16
)
5616 emit_insn (gen_flag_macinit1v2hi_parts (accvec
, op0
, op1
, const0_rtx
,
5617 const0_rtx
, const0_rtx
,
5618 const1_rtx
, GEN_INT (MACFLAG_W32
)));
5620 emit_insn (gen_flag_macinit1v2hi_parts (accvec
, op0
, op1
, const0_rtx
,
5621 const0_rtx
, const0_rtx
,
5622 const1_rtx
, GEN_INT (MACFLAG_NONE
)));
5623 emit_insn (gen_flag_macv2hi_parts (target
, op0
, op1
, const1_rtx
,
5624 const1_rtx
, const1_rtx
,
5625 const0_rtx
, accvec
, const1_rtx
, const0_rtx
,
5626 GEN_INT (MACFLAG_NONE
), accvec
));
5630 case BFIN_BUILTIN_CPLX_MAC_16
:
5631 case BFIN_BUILTIN_CPLX_MSU_16
:
5632 case BFIN_BUILTIN_CPLX_MAC_16_S40
:
5633 case BFIN_BUILTIN_CPLX_MSU_16_S40
:
5634 arg0
= CALL_EXPR_ARG (exp
, 0);
5635 arg1
= CALL_EXPR_ARG (exp
, 1);
5636 arg2
= CALL_EXPR_ARG (exp
, 2);
5637 op0
= expand_normal (arg0
);
5638 op1
= expand_normal (arg1
);
5639 op2
= expand_normal (arg2
);
5640 accvec
= gen_reg_rtx (V2PDImode
);
5641 icode
= CODE_FOR_flag_macv2hi_parts
;
5642 tmode
= insn_data
[icode
].operand
[0].mode
;
5645 || GET_MODE (target
) != V2HImode
5646 || ! (*insn_data
[icode
].operand
[0].predicate
) (target
, V2HImode
))
5647 target
= gen_reg_rtx (tmode
);
5648 if (! register_operand (op1
, GET_MODE (op1
)))
5649 op1
= copy_to_mode_reg (GET_MODE (op1
), op1
);
5650 if (! register_operand (op2
, GET_MODE (op2
)))
5651 op2
= copy_to_mode_reg (GET_MODE (op2
), op2
);
5653 tmp1
= gen_reg_rtx (SImode
);
5654 tmp2
= gen_reg_rtx (SImode
);
5655 emit_insn (gen_ashlsi3 (tmp1
, gen_lowpart (SImode
, op0
), GEN_INT (16)));
5656 emit_move_insn (tmp2
, gen_lowpart (SImode
, op0
));
5657 emit_insn (gen_movstricthi_1 (gen_lowpart (HImode
, tmp2
), const0_rtx
));
5658 emit_insn (gen_load_accumulator_pair (accvec
, tmp1
, tmp2
));
5659 if (fcode
== BFIN_BUILTIN_CPLX_MAC_16
5660 || fcode
== BFIN_BUILTIN_CPLX_MSU_16
)
5661 emit_insn (gen_flag_macv2hi_parts_acconly (accvec
, op1
, op2
, const0_rtx
,
5662 const0_rtx
, const0_rtx
,
5663 const1_rtx
, accvec
, const0_rtx
,
5665 GEN_INT (MACFLAG_W32
)));
5667 emit_insn (gen_flag_macv2hi_parts_acconly (accvec
, op1
, op2
, const0_rtx
,
5668 const0_rtx
, const0_rtx
,
5669 const1_rtx
, accvec
, const0_rtx
,
5671 GEN_INT (MACFLAG_NONE
)));
5672 if (fcode
== BFIN_BUILTIN_CPLX_MAC_16
5673 || fcode
== BFIN_BUILTIN_CPLX_MAC_16_S40
)
5683 emit_insn (gen_flag_macv2hi_parts (target
, op1
, op2
, const1_rtx
,
5684 const1_rtx
, const1_rtx
,
5685 const0_rtx
, accvec
, tmp1
, tmp2
,
5686 GEN_INT (MACFLAG_NONE
), accvec
));
5690 case BFIN_BUILTIN_CPLX_SQU
:
5691 arg0
= CALL_EXPR_ARG (exp
, 0);
5692 op0
= expand_normal (arg0
);
5693 accvec
= gen_reg_rtx (V2PDImode
);
5694 icode
= CODE_FOR_flag_mulv2hi
;
5695 tmp1
= gen_reg_rtx (V2HImode
);
5696 tmp2
= gen_reg_rtx (V2HImode
);
5699 || GET_MODE (target
) != V2HImode
5700 || ! (*insn_data
[icode
].operand
[0].predicate
) (target
, V2HImode
))
5701 target
= gen_reg_rtx (V2HImode
);
5702 if (! register_operand (op0
, GET_MODE (op0
)))
5703 op0
= copy_to_mode_reg (GET_MODE (op0
), op0
);
5705 emit_insn (gen_flag_mulv2hi (tmp1
, op0
, op0
, GEN_INT (MACFLAG_NONE
)));
5707 emit_insn (gen_flag_mulhi_parts (gen_lowpart (HImode
, tmp2
), op0
, op0
,
5708 const0_rtx
, const1_rtx
,
5709 GEN_INT (MACFLAG_NONE
)));
5711 emit_insn (gen_ssaddhi3_high_parts (target
, tmp2
, tmp2
, tmp2
, const0_rtx
,
5713 emit_insn (gen_sssubhi3_low_parts (target
, target
, tmp1
, tmp1
,
5714 const0_rtx
, const1_rtx
));
5722 for (i
= 0, d
= bdesc_2arg
; i
< ARRAY_SIZE (bdesc_2arg
); i
++, d
++)
5723 if (d
->code
== fcode
)
5724 return bfin_expand_binop_builtin (d
->icode
, exp
, target
,
5727 for (i
= 0, d
= bdesc_1arg
; i
< ARRAY_SIZE (bdesc_1arg
); i
++, d
++)
5728 if (d
->code
== fcode
)
5729 return bfin_expand_unop_builtin (d
->icode
, exp
, target
);
5735 bfin_conditional_register_usage (void)
5737 /* initialize condition code flag register rtx */
5738 bfin_cc_rtx
= gen_rtx_REG (BImode
, REG_CC
);
5739 bfin_rets_rtx
= gen_rtx_REG (Pmode
, REG_RETS
);
5741 call_used_regs
[FDPIC_REGNO
] = 1;
5742 if (!TARGET_FDPIC
&& flag_pic
)
5744 fixed_regs
[PIC_OFFSET_TABLE_REGNUM
] = 1;
5745 call_used_regs
[PIC_OFFSET_TABLE_REGNUM
] = 1;
5749 #undef TARGET_INIT_BUILTINS
5750 #define TARGET_INIT_BUILTINS bfin_init_builtins
5752 #undef TARGET_EXPAND_BUILTIN
5753 #define TARGET_EXPAND_BUILTIN bfin_expand_builtin
5755 #undef TARGET_ASM_GLOBALIZE_LABEL
5756 #define TARGET_ASM_GLOBALIZE_LABEL bfin_globalize_label
5758 #undef TARGET_ASM_FILE_START
5759 #define TARGET_ASM_FILE_START output_file_start
5761 #undef TARGET_ATTRIBUTE_TABLE
5762 #define TARGET_ATTRIBUTE_TABLE bfin_attribute_table
5764 #undef TARGET_COMP_TYPE_ATTRIBUTES
5765 #define TARGET_COMP_TYPE_ATTRIBUTES bfin_comp_type_attributes
5767 #undef TARGET_RTX_COSTS
5768 #define TARGET_RTX_COSTS bfin_rtx_costs
5770 #undef TARGET_ADDRESS_COST
5771 #define TARGET_ADDRESS_COST bfin_address_cost
5773 #undef TARGET_REGISTER_MOVE_COST
5774 #define TARGET_REGISTER_MOVE_COST bfin_register_move_cost
5776 #undef TARGET_MEMORY_MOVE_COST
5777 #define TARGET_MEMORY_MOVE_COST bfin_memory_move_cost
5779 #undef TARGET_ASM_INTEGER
5780 #define TARGET_ASM_INTEGER bfin_assemble_integer
5782 #undef TARGET_MACHINE_DEPENDENT_REORG
5783 #define TARGET_MACHINE_DEPENDENT_REORG bfin_reorg
5785 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
5786 #define TARGET_FUNCTION_OK_FOR_SIBCALL bfin_function_ok_for_sibcall
5788 #undef TARGET_ASM_OUTPUT_MI_THUNK
5789 #define TARGET_ASM_OUTPUT_MI_THUNK bfin_output_mi_thunk
5790 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
5791 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true
5793 #undef TARGET_SCHED_ADJUST_COST
5794 #define TARGET_SCHED_ADJUST_COST bfin_adjust_cost
5796 #undef TARGET_SCHED_ISSUE_RATE
5797 #define TARGET_SCHED_ISSUE_RATE bfin_issue_rate
5799 #undef TARGET_PROMOTE_FUNCTION_MODE
5800 #define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
5802 #undef TARGET_ARG_PARTIAL_BYTES
5803 #define TARGET_ARG_PARTIAL_BYTES bfin_arg_partial_bytes
5805 #undef TARGET_FUNCTION_ARG
5806 #define TARGET_FUNCTION_ARG bfin_function_arg
5808 #undef TARGET_FUNCTION_ARG_ADVANCE
5809 #define TARGET_FUNCTION_ARG_ADVANCE bfin_function_arg_advance
5811 #undef TARGET_PASS_BY_REFERENCE
5812 #define TARGET_PASS_BY_REFERENCE bfin_pass_by_reference
5814 #undef TARGET_SETUP_INCOMING_VARARGS
5815 #define TARGET_SETUP_INCOMING_VARARGS setup_incoming_varargs
5817 #undef TARGET_STRUCT_VALUE_RTX
5818 #define TARGET_STRUCT_VALUE_RTX bfin_struct_value_rtx
5820 #undef TARGET_VECTOR_MODE_SUPPORTED_P
5821 #define TARGET_VECTOR_MODE_SUPPORTED_P bfin_vector_mode_supported_p
5823 #undef TARGET_OPTION_OVERRIDE
5824 #define TARGET_OPTION_OVERRIDE bfin_option_override
5826 #undef TARGET_SECONDARY_RELOAD
5827 #define TARGET_SECONDARY_RELOAD bfin_secondary_reload
5829 #undef TARGET_CLASS_LIKELY_SPILLED_P
5830 #define TARGET_CLASS_LIKELY_SPILLED_P bfin_class_likely_spilled_p
5832 #undef TARGET_DELEGITIMIZE_ADDRESS
5833 #define TARGET_DELEGITIMIZE_ADDRESS bfin_delegitimize_address
5835 #undef TARGET_LEGITIMATE_CONSTANT_P
5836 #define TARGET_LEGITIMATE_CONSTANT_P bfin_legitimate_constant_p
5838 #undef TARGET_CANNOT_FORCE_CONST_MEM
5839 #define TARGET_CANNOT_FORCE_CONST_MEM bfin_cannot_force_const_mem
5841 #undef TARGET_RETURN_IN_MEMORY
5842 #define TARGET_RETURN_IN_MEMORY bfin_return_in_memory
5845 #define TARGET_LRA_P hook_bool_void_false
5847 #undef TARGET_LEGITIMATE_ADDRESS_P
5848 #define TARGET_LEGITIMATE_ADDRESS_P bfin_legitimate_address_p
5850 #undef TARGET_FRAME_POINTER_REQUIRED
5851 #define TARGET_FRAME_POINTER_REQUIRED bfin_frame_pointer_required
5853 #undef TARGET_CAN_ELIMINATE
5854 #define TARGET_CAN_ELIMINATE bfin_can_eliminate
5856 #undef TARGET_CONDITIONAL_REGISTER_USAGE
5857 #define TARGET_CONDITIONAL_REGISTER_USAGE bfin_conditional_register_usage
5859 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
5860 #define TARGET_ASM_TRAMPOLINE_TEMPLATE bfin_asm_trampoline_template
5861 #undef TARGET_TRAMPOLINE_INIT
5862 #define TARGET_TRAMPOLINE_INIT bfin_trampoline_init
5864 #undef TARGET_EXTRA_LIVE_ON_ENTRY
5865 #define TARGET_EXTRA_LIVE_ON_ENTRY bfin_extra_live_on_entry
5867 /* Passes after sched2 can break the helpful TImode annotations that
5868 haifa-sched puts on every insn. Just do scheduling in reorg. */
5869 #undef TARGET_DELAY_SCHED2
5870 #define TARGET_DELAY_SCHED2 true
5872 /* Variable tracking should be run after all optimizations which
5873 change order of insns. It also needs a valid CFG. */
5874 #undef TARGET_DELAY_VARTRACK
5875 #define TARGET_DELAY_VARTRACK true
5877 #undef TARGET_CAN_USE_DOLOOP_P
5878 #define TARGET_CAN_USE_DOLOOP_P bfin_can_use_doloop_p
5880 #undef TARGET_HARD_REGNO_NREGS
5881 #define TARGET_HARD_REGNO_NREGS bfin_hard_regno_nregs
5882 #undef TARGET_HARD_REGNO_MODE_OK
5883 #define TARGET_HARD_REGNO_MODE_OK bfin_hard_regno_mode_ok
5885 #undef TARGET_MODES_TIEABLE_P
5886 #define TARGET_MODES_TIEABLE_P bfin_modes_tieable_p
5888 #undef TARGET_CONSTANT_ALIGNMENT
5889 #define TARGET_CONSTANT_ALIGNMENT constant_alignment_word_strings
5891 struct gcc_target targetm
= TARGET_INITIALIZER
;