1 /* The Blackfin code generation auxiliary output file.
2 Copyright (C) 2005, 2006, 2007 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/>. */
23 #include "coretypes.h"
27 #include "hard-reg-set.h"
29 #include "insn-config.h"
30 #include "insn-codes.h"
31 #include "conditions.h"
32 #include "insn-flags.h"
34 #include "insn-attr.h"
41 #include "target-def.h"
47 #include "integrate.h"
49 #include "langhooks.h"
50 #include "bfin-protos.h"
53 #include "basic-block.h"
54 #include "cfglayout.h"
58 /* A C structure for machine-specific, per-function data.
59 This is added to the cfun structure. */
60 struct machine_function
GTY(())
62 int has_hardware_loops
;
65 /* Test and compare insns in bfin.md store the information needed to
66 generate branch and scc insns here. */
67 rtx bfin_compare_op0
, bfin_compare_op1
;
69 /* RTX for condition code flag register and RETS register */
70 extern GTY(()) rtx bfin_cc_rtx
;
71 extern GTY(()) rtx bfin_rets_rtx
;
72 rtx bfin_cc_rtx
, bfin_rets_rtx
;
74 int max_arg_registers
= 0;
76 /* Arrays used when emitting register names. */
77 const char *short_reg_names
[] = SHORT_REGISTER_NAMES
;
78 const char *high_reg_names
[] = HIGH_REGISTER_NAMES
;
79 const char *dregs_pair_names
[] = DREGS_PAIR_NAMES
;
80 const char *byte_reg_names
[] = BYTE_REGISTER_NAMES
;
82 static int arg_regs
[] = FUNCTION_ARG_REGISTERS
;
84 /* Nonzero if -mshared-library-id was given. */
85 static int bfin_lib_id_given
;
87 /* Nonzero if -fschedule-insns2 was given. We override it and
88 call the scheduler ourselves during reorg. */
89 static int bfin_flag_schedule_insns2
;
91 /* Determines whether we run variable tracking in machine dependent
93 static int bfin_flag_var_tracking
;
96 bfin_cpu_t bfin_cpu_type
= DEFAULT_CPU_TYPE
;
98 /* -msi-revision support. There are three special values:
99 -1 -msi-revision=none.
100 0xffff -msi-revision=any. */
101 int bfin_si_revision
;
103 /* The workarounds enabled */
104 unsigned int bfin_workarounds
= 0;
111 unsigned int workarounds
;
114 struct bfin_cpu bfin_cpus
[] =
116 {"bf522", BFIN_CPU_BF522
, 0x0000,
117 WA_SPECULATIVE_LOADS
},
119 {"bf525", BFIN_CPU_BF525
, 0x0000,
120 WA_SPECULATIVE_LOADS
},
122 {"bf527", BFIN_CPU_BF527
, 0x0000,
123 WA_SPECULATIVE_LOADS
},
125 {"bf531", BFIN_CPU_BF531
, 0x0005,
126 WA_SPECULATIVE_LOADS
},
127 {"bf531", BFIN_CPU_BF531
, 0x0004,
128 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
},
129 {"bf531", BFIN_CPU_BF531
, 0x0003,
130 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
},
132 {"bf532", BFIN_CPU_BF532
, 0x0005,
133 WA_SPECULATIVE_LOADS
},
134 {"bf532", BFIN_CPU_BF532
, 0x0004,
135 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
},
136 {"bf532", BFIN_CPU_BF532
, 0x0003,
137 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
},
139 {"bf533", BFIN_CPU_BF533
, 0x0005,
140 WA_SPECULATIVE_LOADS
},
141 {"bf533", BFIN_CPU_BF533
, 0x0004,
142 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
},
143 {"bf533", BFIN_CPU_BF533
, 0x0003,
144 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
},
146 {"bf534", BFIN_CPU_BF534
, 0x0003,
147 WA_SPECULATIVE_LOADS
},
148 {"bf534", BFIN_CPU_BF534
, 0x0002,
149 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
},
150 {"bf534", BFIN_CPU_BF534
, 0x0001,
151 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
},
153 {"bf536", BFIN_CPU_BF536
, 0x0003,
154 WA_SPECULATIVE_LOADS
},
155 {"bf536", BFIN_CPU_BF536
, 0x0002,
156 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
},
157 {"bf536", BFIN_CPU_BF536
, 0x0001,
158 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
},
160 {"bf537", BFIN_CPU_BF537
, 0x0003,
161 WA_SPECULATIVE_LOADS
},
162 {"bf537", BFIN_CPU_BF537
, 0x0002,
163 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
},
164 {"bf537", BFIN_CPU_BF537
, 0x0001,
165 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
},
167 {"bf538", BFIN_CPU_BF538
, 0x0004,
168 WA_SPECULATIVE_LOADS
},
169 {"bf538", BFIN_CPU_BF538
, 0x0003,
170 WA_SPECULATIVE_LOADS
},
172 {"bf539", BFIN_CPU_BF539
, 0x0004,
173 WA_SPECULATIVE_LOADS
},
174 {"bf539", BFIN_CPU_BF539
, 0x0003,
175 WA_SPECULATIVE_LOADS
},
176 {"bf539", BFIN_CPU_BF539
, 0x0002,
177 WA_SPECULATIVE_LOADS
},
179 {"bf542", BFIN_CPU_BF542
, 0x0000,
180 WA_SPECULATIVE_LOADS
},
182 {"bf544", BFIN_CPU_BF544
, 0x0000,
183 WA_SPECULATIVE_LOADS
},
185 {"bf548", BFIN_CPU_BF548
, 0x0000,
186 WA_SPECULATIVE_LOADS
},
188 {"bf549", BFIN_CPU_BF549
, 0x0000,
189 WA_SPECULATIVE_LOADS
},
191 {"bf561", BFIN_CPU_BF561
, 0x0005, 0},
192 {"bf561", BFIN_CPU_BF561
, 0x0003,
193 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
},
194 {"bf561", BFIN_CPU_BF561
, 0x0002,
195 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
},
200 int splitting_for_sched
;
203 bfin_globalize_label (FILE *stream
, const char *name
)
205 fputs (".global ", stream
);
206 assemble_name (stream
, name
);
212 output_file_start (void)
214 FILE *file
= asm_out_file
;
217 /* Variable tracking should be run after all optimizations which change order
218 of insns. It also needs a valid CFG. This can't be done in
219 override_options, because flag_var_tracking is finalized after
221 bfin_flag_var_tracking
= flag_var_tracking
;
222 flag_var_tracking
= 0;
224 fprintf (file
, ".file \"%s\";\n", input_filename
);
226 for (i
= 0; arg_regs
[i
] >= 0; i
++)
228 max_arg_registers
= i
; /* how many arg reg used */
231 /* Called early in the compilation to conditionally modify
232 fixed_regs/call_used_regs. */
235 conditional_register_usage (void)
237 /* initialize condition code flag register rtx */
238 bfin_cc_rtx
= gen_rtx_REG (BImode
, REG_CC
);
239 bfin_rets_rtx
= gen_rtx_REG (Pmode
, REG_RETS
);
242 /* Examine machine-dependent attributes of function type FUNTYPE and return its
243 type. See the definition of E_FUNKIND. */
246 funkind (const_tree funtype
)
248 tree attrs
= TYPE_ATTRIBUTES (funtype
);
249 if (lookup_attribute ("interrupt_handler", attrs
))
250 return INTERRUPT_HANDLER
;
251 else if (lookup_attribute ("exception_handler", attrs
))
252 return EXCPT_HANDLER
;
253 else if (lookup_attribute ("nmi_handler", attrs
))
259 /* Legitimize PIC addresses. If the address is already position-independent,
260 we return ORIG. Newly generated position-independent addresses go into a
261 reg. This is REG if nonzero, otherwise we allocate register(s) as
262 necessary. PICREG is the register holding the pointer to the PIC offset
266 legitimize_pic_address (rtx orig
, rtx reg
, rtx picreg
)
271 if (GET_CODE (addr
) == SYMBOL_REF
|| GET_CODE (addr
) == LABEL_REF
)
276 if (TARGET_ID_SHARED_LIBRARY
)
277 unspec
= UNSPEC_MOVE_PIC
;
278 else if (GET_CODE (addr
) == SYMBOL_REF
279 && SYMBOL_REF_FUNCTION_P (addr
))
280 unspec
= UNSPEC_FUNCDESC_GOT17M4
;
282 unspec
= UNSPEC_MOVE_FDPIC
;
286 gcc_assert (can_create_pseudo_p ());
287 reg
= gen_reg_rtx (Pmode
);
290 tmp
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, addr
), unspec
);
291 new = gen_const_mem (Pmode
, gen_rtx_PLUS (Pmode
, picreg
, tmp
));
293 emit_move_insn (reg
, new);
294 if (picreg
== pic_offset_table_rtx
)
295 current_function_uses_pic_offset_table
= 1;
299 else if (GET_CODE (addr
) == CONST
|| GET_CODE (addr
) == PLUS
)
303 if (GET_CODE (addr
) == CONST
)
305 addr
= XEXP (addr
, 0);
306 gcc_assert (GET_CODE (addr
) == PLUS
);
309 if (XEXP (addr
, 0) == picreg
)
314 gcc_assert (can_create_pseudo_p ());
315 reg
= gen_reg_rtx (Pmode
);
318 base
= legitimize_pic_address (XEXP (addr
, 0), reg
, picreg
);
319 addr
= legitimize_pic_address (XEXP (addr
, 1),
320 base
== reg
? NULL_RTX
: reg
,
323 if (GET_CODE (addr
) == CONST_INT
)
325 gcc_assert (! reload_in_progress
&& ! reload_completed
);
326 addr
= force_reg (Pmode
, addr
);
329 if (GET_CODE (addr
) == PLUS
&& CONSTANT_P (XEXP (addr
, 1)))
331 base
= gen_rtx_PLUS (Pmode
, base
, XEXP (addr
, 0));
332 addr
= XEXP (addr
, 1);
335 return gen_rtx_PLUS (Pmode
, base
, addr
);
341 /* Stack frame layout. */
343 /* Compute the number of DREGS to save with a push_multiple operation.
344 This could include registers that aren't modified in the function,
345 since push_multiple only takes a range of registers.
346 If IS_INTHANDLER, then everything that is live must be saved, even
347 if normally call-clobbered. */
350 n_dregs_to_save (bool is_inthandler
)
354 for (i
= REG_R0
; i
<= REG_R7
; i
++)
356 if (df_regs_ever_live_p (i
) && (is_inthandler
|| ! call_used_regs
[i
]))
357 return REG_R7
- i
+ 1;
359 if (current_function_calls_eh_return
)
364 unsigned test
= EH_RETURN_DATA_REGNO (j
);
365 if (test
== INVALID_REGNUM
)
368 return REG_R7
- i
+ 1;
376 /* Like n_dregs_to_save, but compute number of PREGS to save. */
379 n_pregs_to_save (bool is_inthandler
)
383 for (i
= REG_P0
; i
<= REG_P5
; i
++)
384 if ((df_regs_ever_live_p (i
) && (is_inthandler
|| ! call_used_regs
[i
]))
386 && i
== PIC_OFFSET_TABLE_REGNUM
387 && (current_function_uses_pic_offset_table
388 || (TARGET_ID_SHARED_LIBRARY
&& ! current_function_is_leaf
))))
389 return REG_P5
- i
+ 1;
393 /* Determine if we are going to save the frame pointer in the prologue. */
396 must_save_fp_p (void)
398 return frame_pointer_needed
|| df_regs_ever_live_p (REG_FP
);
402 stack_frame_needed_p (void)
404 /* EH return puts a new return address into the frame using an
405 address relative to the frame pointer. */
406 if (current_function_calls_eh_return
)
408 return frame_pointer_needed
;
411 /* Emit code to save registers in the prologue. SAVEALL is nonzero if we
412 must save all registers; this is used for interrupt handlers.
413 SPREG contains (reg:SI REG_SP). IS_INTHANDLER is true if we're doing
414 this for an interrupt (or exception) handler. */
417 expand_prologue_reg_save (rtx spreg
, int saveall
, bool is_inthandler
)
419 rtx predec1
= gen_rtx_PRE_DEC (SImode
, spreg
);
420 rtx predec
= gen_rtx_MEM (SImode
, predec1
);
421 int ndregs
= saveall
? 8 : n_dregs_to_save (is_inthandler
);
422 int npregs
= saveall
? 6 : n_pregs_to_save (is_inthandler
);
423 int dregno
= REG_R7
+ 1 - ndregs
;
424 int pregno
= REG_P5
+ 1 - npregs
;
425 int total
= ndregs
+ npregs
;
429 if (saveall
|| is_inthandler
)
431 insn
= emit_move_insn (predec
, gen_rtx_REG (SImode
, REG_ASTAT
));
432 RTX_FRAME_RELATED_P (insn
) = 1;
435 if (total
== 0 && !saveall
)
438 val
= GEN_INT (-total
* 4);
439 pat
= gen_rtx_PARALLEL (VOIDmode
, rtvec_alloc (total
+ 2));
440 XVECEXP (pat
, 0, 0) = gen_rtx_UNSPEC (VOIDmode
, gen_rtvec (1, val
),
441 UNSPEC_PUSH_MULTIPLE
);
442 XVECEXP (pat
, 0, total
+ 1) = gen_rtx_SET (VOIDmode
, spreg
,
443 gen_rtx_PLUS (Pmode
, spreg
,
445 RTX_FRAME_RELATED_P (XVECEXP (pat
, 0, total
+ 1)) = 1;
446 for (i
= 0; i
< total
; i
++)
448 rtx memref
= gen_rtx_MEM (word_mode
,
449 gen_rtx_PLUS (Pmode
, spreg
,
450 GEN_INT (- i
* 4 - 4)));
454 subpat
= gen_rtx_SET (VOIDmode
, memref
, gen_rtx_REG (word_mode
,
460 subpat
= gen_rtx_SET (VOIDmode
, memref
, gen_rtx_REG (word_mode
,
464 XVECEXP (pat
, 0, i
+ 1) = subpat
;
465 RTX_FRAME_RELATED_P (subpat
) = 1;
467 insn
= emit_insn (pat
);
468 RTX_FRAME_RELATED_P (insn
) = 1;
470 for (i
= REG_P7
+ 1; i
< REG_CC
; i
++)
473 && (df_regs_ever_live_p (i
)
474 || (!leaf_function_p () && call_used_regs
[i
]))))
476 if (i
== REG_A0
|| i
== REG_A1
)
477 insn
= emit_move_insn (gen_rtx_MEM (PDImode
, predec1
),
478 gen_rtx_REG (PDImode
, i
));
480 insn
= emit_move_insn (predec
, gen_rtx_REG (SImode
, i
));
481 RTX_FRAME_RELATED_P (insn
) = 1;
485 /* Emit code to restore registers in the epilogue. SAVEALL is nonzero if we
486 must save all registers; this is used for interrupt handlers.
487 SPREG contains (reg:SI REG_SP). IS_INTHANDLER is true if we're doing
488 this for an interrupt (or exception) handler. */
491 expand_epilogue_reg_restore (rtx spreg
, bool saveall
, bool is_inthandler
)
493 rtx postinc1
= gen_rtx_POST_INC (SImode
, spreg
);
494 rtx postinc
= gen_rtx_MEM (SImode
, postinc1
);
496 int ndregs
= saveall
? 8 : n_dregs_to_save (is_inthandler
);
497 int npregs
= saveall
? 6 : n_pregs_to_save (is_inthandler
);
498 int total
= ndregs
+ npregs
;
502 /* A slightly crude technique to stop flow from trying to delete "dead"
504 MEM_VOLATILE_P (postinc
) = 1;
506 for (i
= REG_CC
- 1; i
> REG_P7
; i
--)
509 && (df_regs_ever_live_p (i
)
510 || (!leaf_function_p () && call_used_regs
[i
]))))
512 if (i
== REG_A0
|| i
== REG_A1
)
514 rtx mem
= gen_rtx_MEM (PDImode
, postinc1
);
515 MEM_VOLATILE_P (mem
) = 1;
516 emit_move_insn (gen_rtx_REG (PDImode
, i
), mem
);
519 emit_move_insn (gen_rtx_REG (SImode
, i
), postinc
);
525 pat
= gen_rtx_PARALLEL (VOIDmode
, rtvec_alloc (total
+ 1));
526 XVECEXP (pat
, 0, 0) = gen_rtx_SET (VOIDmode
, spreg
,
527 gen_rtx_PLUS (Pmode
, spreg
,
528 GEN_INT (total
* 4)));
535 for (i
= 0; i
< total
; i
++)
538 ? gen_rtx_PLUS (Pmode
, spreg
, GEN_INT (i
* 4))
540 rtx memref
= gen_rtx_MEM (word_mode
, addr
);
543 XVECEXP (pat
, 0, i
+ 1)
544 = gen_rtx_SET (VOIDmode
, gen_rtx_REG (word_mode
, regno
), memref
);
553 insn
= emit_insn (pat
);
554 RTX_FRAME_RELATED_P (insn
) = 1;
556 if (saveall
|| is_inthandler
)
557 emit_move_insn (gen_rtx_REG (SImode
, REG_ASTAT
), postinc
);
560 /* Perform any needed actions needed for a function that is receiving a
561 variable number of arguments.
565 MODE and TYPE are the mode and type of the current parameter.
567 PRETEND_SIZE is a variable that should be set to the amount of stack
568 that must be pushed by the prolog to pretend that our caller pushed
571 Normally, this macro will push all remaining incoming registers on the
572 stack and set PRETEND_SIZE to the length of the registers pushed.
575 - VDSP C compiler manual (our ABI) says that a variable args function
576 should save the R0, R1 and R2 registers in the stack.
577 - The caller will always leave space on the stack for the
578 arguments that are passed in registers, so we dont have
579 to leave any extra space.
580 - now, the vastart pointer can access all arguments from the stack. */
583 setup_incoming_varargs (CUMULATIVE_ARGS
*cum
,
584 enum machine_mode mode ATTRIBUTE_UNUSED
,
585 tree type ATTRIBUTE_UNUSED
, int *pretend_size
,
594 /* The move for named arguments will be generated automatically by the
595 compiler. We need to generate the move rtx for the unnamed arguments
596 if they are in the first 3 words. We assume at least 1 named argument
597 exists, so we never generate [ARGP] = R0 here. */
599 for (i
= cum
->words
+ 1; i
< max_arg_registers
; i
++)
601 mem
= gen_rtx_MEM (Pmode
,
602 plus_constant (arg_pointer_rtx
, (i
* UNITS_PER_WORD
)));
603 emit_move_insn (mem
, gen_rtx_REG (Pmode
, i
));
609 /* Value should be nonzero if functions must have frame pointers.
610 Zero means the frame pointer need not be set up (and parms may
611 be accessed via the stack pointer) in functions that seem suitable. */
614 bfin_frame_pointer_required (void)
616 e_funkind fkind
= funkind (TREE_TYPE (current_function_decl
));
618 if (fkind
!= SUBROUTINE
)
621 /* We turn on -fomit-frame-pointer if -momit-leaf-frame-pointer is used,
622 so we have to override it for non-leaf functions. */
623 if (TARGET_OMIT_LEAF_FRAME_POINTER
&& ! current_function_is_leaf
)
629 /* Return the number of registers pushed during the prologue. */
632 n_regs_saved_by_prologue (void)
634 e_funkind fkind
= funkind (TREE_TYPE (current_function_decl
));
635 bool is_inthandler
= fkind
!= SUBROUTINE
;
636 tree attrs
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
637 bool all
= (lookup_attribute ("saveall", attrs
) != NULL_TREE
638 || (is_inthandler
&& !current_function_is_leaf
));
639 int ndregs
= all
? 8 : n_dregs_to_save (is_inthandler
);
640 int npregs
= all
? 6 : n_pregs_to_save (is_inthandler
);
641 int n
= ndregs
+ npregs
;
644 if (all
|| stack_frame_needed_p ())
645 /* We use a LINK instruction in this case. */
649 if (must_save_fp_p ())
651 if (! current_function_is_leaf
)
655 if (fkind
!= SUBROUTINE
|| all
)
656 /* Increment once for ASTAT. */
659 if (fkind
!= SUBROUTINE
)
662 if (lookup_attribute ("nesting", attrs
))
666 for (i
= REG_P7
+ 1; i
< REG_CC
; i
++)
668 || (fkind
!= SUBROUTINE
669 && (df_regs_ever_live_p (i
)
670 || (!leaf_function_p () && call_used_regs
[i
]))))
671 n
+= i
== REG_A0
|| i
== REG_A1
? 2 : 1;
676 /* Return the offset between two registers, one to be eliminated, and the other
677 its replacement, at the start of a routine. */
680 bfin_initial_elimination_offset (int from
, int to
)
682 HOST_WIDE_INT offset
= 0;
684 if (from
== ARG_POINTER_REGNUM
)
685 offset
= n_regs_saved_by_prologue () * 4;
687 if (to
== STACK_POINTER_REGNUM
)
689 if (current_function_outgoing_args_size
>= FIXED_STACK_AREA
)
690 offset
+= current_function_outgoing_args_size
;
691 else if (current_function_outgoing_args_size
)
692 offset
+= FIXED_STACK_AREA
;
694 offset
+= get_frame_size ();
700 /* Emit code to load a constant CONSTANT into register REG; setting
701 RTX_FRAME_RELATED_P on all insns we generate if RELATED is true.
702 Make sure that the insns we generate need not be split. */
705 frame_related_constant_load (rtx reg
, HOST_WIDE_INT constant
, bool related
)
708 rtx cst
= GEN_INT (constant
);
710 if (constant
>= -32768 && constant
< 65536)
711 insn
= emit_move_insn (reg
, cst
);
714 /* We don't call split_load_immediate here, since dwarf2out.c can get
715 confused about some of the more clever sequences it can generate. */
716 insn
= emit_insn (gen_movsi_high (reg
, cst
));
718 RTX_FRAME_RELATED_P (insn
) = 1;
719 insn
= emit_insn (gen_movsi_low (reg
, reg
, cst
));
722 RTX_FRAME_RELATED_P (insn
) = 1;
725 /* Generate efficient code to add a value to a P register.
726 Set RTX_FRAME_RELATED_P on the generated insns if FRAME is nonzero.
727 EPILOGUE_P is zero if this function is called for prologue,
728 otherwise it's nonzero. And it's less than zero if this is for
732 add_to_reg (rtx reg
, HOST_WIDE_INT value
, int frame
, int epilogue_p
)
737 /* Choose whether to use a sequence using a temporary register, or
738 a sequence with multiple adds. We can add a signed 7-bit value
739 in one instruction. */
740 if (value
> 120 || value
< -120)
748 /* For prologue or normal epilogue, P1 can be safely used
749 as the temporary register. For sibcall epilogue, we try to find
750 a call used P register, which will be restored in epilogue.
751 If we cannot find such a P register, we have to use one I register
755 tmpreg
= gen_rtx_REG (SImode
, REG_P1
);
759 for (i
= REG_P0
; i
<= REG_P5
; i
++)
760 if ((df_regs_ever_live_p (i
) && ! call_used_regs
[i
])
762 && i
== PIC_OFFSET_TABLE_REGNUM
763 && (current_function_uses_pic_offset_table
764 || (TARGET_ID_SHARED_LIBRARY
765 && ! current_function_is_leaf
))))
768 tmpreg
= gen_rtx_REG (SImode
, i
);
771 tmpreg
= gen_rtx_REG (SImode
, REG_P1
);
772 tmpreg2
= gen_rtx_REG (SImode
, REG_I0
);
773 emit_move_insn (tmpreg2
, tmpreg
);
778 frame_related_constant_load (tmpreg
, value
, TRUE
);
780 insn
= emit_move_insn (tmpreg
, GEN_INT (value
));
782 insn
= emit_insn (gen_addsi3 (reg
, reg
, tmpreg
));
784 RTX_FRAME_RELATED_P (insn
) = 1;
786 if (tmpreg2
!= NULL_RTX
)
787 emit_move_insn (tmpreg
, tmpreg2
);
798 /* We could use -62, but that would leave the stack unaligned, so
802 insn
= emit_insn (gen_addsi3 (reg
, reg
, GEN_INT (size
)));
804 RTX_FRAME_RELATED_P (insn
) = 1;
810 /* Generate a LINK insn for a frame sized FRAME_SIZE. If this constant
811 is too large, generate a sequence of insns that has the same effect.
812 SPREG contains (reg:SI REG_SP). */
815 emit_link_insn (rtx spreg
, HOST_WIDE_INT frame_size
)
817 HOST_WIDE_INT link_size
= frame_size
;
821 if (link_size
> 262140)
824 /* Use a LINK insn with as big a constant as possible, then subtract
825 any remaining size from the SP. */
826 insn
= emit_insn (gen_link (GEN_INT (-8 - link_size
)));
827 RTX_FRAME_RELATED_P (insn
) = 1;
829 for (i
= 0; i
< XVECLEN (PATTERN (insn
), 0); i
++)
831 rtx set
= XVECEXP (PATTERN (insn
), 0, i
);
832 gcc_assert (GET_CODE (set
) == SET
);
833 RTX_FRAME_RELATED_P (set
) = 1;
836 frame_size
-= link_size
;
840 /* Must use a call-clobbered PREG that isn't the static chain. */
841 rtx tmpreg
= gen_rtx_REG (Pmode
, REG_P1
);
843 frame_related_constant_load (tmpreg
, -frame_size
, TRUE
);
844 insn
= emit_insn (gen_addsi3 (spreg
, spreg
, tmpreg
));
845 RTX_FRAME_RELATED_P (insn
) = 1;
849 /* Return the number of bytes we must reserve for outgoing arguments
850 in the current function's stack frame. */
855 if (current_function_outgoing_args_size
)
857 if (current_function_outgoing_args_size
>= FIXED_STACK_AREA
)
858 return current_function_outgoing_args_size
;
860 return FIXED_STACK_AREA
;
865 /* Save RETS and FP, and allocate a stack frame. ALL is true if the
866 function must save all its registers (true only for certain interrupt
870 do_link (rtx spreg
, HOST_WIDE_INT frame_size
, bool all
)
872 frame_size
+= arg_area_size ();
874 if (all
|| stack_frame_needed_p ()
875 || (must_save_fp_p () && ! current_function_is_leaf
))
876 emit_link_insn (spreg
, frame_size
);
879 if (! current_function_is_leaf
)
881 rtx pat
= gen_movsi (gen_rtx_MEM (Pmode
,
882 gen_rtx_PRE_DEC (Pmode
, spreg
)),
884 rtx insn
= emit_insn (pat
);
885 RTX_FRAME_RELATED_P (insn
) = 1;
887 if (must_save_fp_p ())
889 rtx pat
= gen_movsi (gen_rtx_MEM (Pmode
,
890 gen_rtx_PRE_DEC (Pmode
, spreg
)),
891 gen_rtx_REG (Pmode
, REG_FP
));
892 rtx insn
= emit_insn (pat
);
893 RTX_FRAME_RELATED_P (insn
) = 1;
895 add_to_reg (spreg
, -frame_size
, 1, 0);
899 /* Like do_link, but used for epilogues to deallocate the stack frame.
900 EPILOGUE_P is zero if this function is called for prologue,
901 otherwise it's nonzero. And it's less than zero if this is for
905 do_unlink (rtx spreg
, HOST_WIDE_INT frame_size
, bool all
, int epilogue_p
)
907 frame_size
+= arg_area_size ();
909 if (all
|| stack_frame_needed_p ())
910 emit_insn (gen_unlink ());
913 rtx postinc
= gen_rtx_MEM (Pmode
, gen_rtx_POST_INC (Pmode
, spreg
));
915 add_to_reg (spreg
, frame_size
, 0, epilogue_p
);
916 if (must_save_fp_p ())
918 rtx fpreg
= gen_rtx_REG (Pmode
, REG_FP
);
919 emit_move_insn (fpreg
, postinc
);
920 emit_insn (gen_rtx_USE (VOIDmode
, fpreg
));
922 if (! current_function_is_leaf
)
924 emit_move_insn (bfin_rets_rtx
, postinc
);
925 emit_insn (gen_rtx_USE (VOIDmode
, bfin_rets_rtx
));
930 /* Generate a prologue suitable for a function of kind FKIND. This is
931 called for interrupt and exception handler prologues.
932 SPREG contains (reg:SI REG_SP). */
935 expand_interrupt_handler_prologue (rtx spreg
, e_funkind fkind
, bool all
)
937 HOST_WIDE_INT frame_size
= get_frame_size ();
938 rtx predec1
= gen_rtx_PRE_DEC (SImode
, spreg
);
939 rtx predec
= gen_rtx_MEM (SImode
, predec1
);
941 tree attrs
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
942 tree kspisusp
= lookup_attribute ("kspisusp", attrs
);
946 insn
= emit_move_insn (spreg
, gen_rtx_REG (Pmode
, REG_USP
));
947 RTX_FRAME_RELATED_P (insn
) = 1;
950 /* We need space on the stack in case we need to save the argument
952 if (fkind
== EXCPT_HANDLER
)
954 insn
= emit_insn (gen_addsi3 (spreg
, spreg
, GEN_INT (-12)));
955 RTX_FRAME_RELATED_P (insn
) = 1;
958 /* If we're calling other functions, they won't save their call-clobbered
959 registers, so we must save everything here. */
960 if (!current_function_is_leaf
)
962 expand_prologue_reg_save (spreg
, all
, true);
964 if (lookup_attribute ("nesting", attrs
))
966 rtx srcreg
= gen_rtx_REG (Pmode
, (fkind
== EXCPT_HANDLER
? REG_RETX
967 : fkind
== NMI_HANDLER
? REG_RETN
969 insn
= emit_move_insn (predec
, srcreg
);
970 RTX_FRAME_RELATED_P (insn
) = 1;
973 do_link (spreg
, frame_size
, all
);
975 if (fkind
== EXCPT_HANDLER
)
977 rtx r0reg
= gen_rtx_REG (SImode
, REG_R0
);
978 rtx r1reg
= gen_rtx_REG (SImode
, REG_R1
);
979 rtx r2reg
= gen_rtx_REG (SImode
, REG_R2
);
982 insn
= emit_move_insn (r0reg
, gen_rtx_REG (SImode
, REG_SEQSTAT
));
983 insn
= emit_insn (gen_ashrsi3 (r0reg
, r0reg
, GEN_INT (26)));
984 insn
= emit_insn (gen_ashlsi3 (r0reg
, r0reg
, GEN_INT (26)));
985 insn
= emit_move_insn (r1reg
, spreg
);
986 insn
= emit_move_insn (r2reg
, gen_rtx_REG (Pmode
, REG_FP
));
987 insn
= emit_insn (gen_addsi3 (r2reg
, r2reg
, GEN_INT (8)));
991 /* Generate an epilogue suitable for a function of kind FKIND. This is
992 called for interrupt and exception handler epilogues.
993 SPREG contains (reg:SI REG_SP). */
996 expand_interrupt_handler_epilogue (rtx spreg
, e_funkind fkind
, bool all
)
998 tree attrs
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
999 rtx postinc1
= gen_rtx_POST_INC (SImode
, spreg
);
1000 rtx postinc
= gen_rtx_MEM (SImode
, postinc1
);
1002 /* A slightly crude technique to stop flow from trying to delete "dead"
1004 MEM_VOLATILE_P (postinc
) = 1;
1006 do_unlink (spreg
, get_frame_size (), all
, 1);
1008 if (lookup_attribute ("nesting", attrs
))
1010 rtx srcreg
= gen_rtx_REG (Pmode
, (fkind
== EXCPT_HANDLER
? REG_RETX
1011 : fkind
== NMI_HANDLER
? REG_RETN
1013 emit_move_insn (srcreg
, postinc
);
1016 /* If we're calling other functions, they won't save their call-clobbered
1017 registers, so we must save (and restore) everything here. */
1018 if (!current_function_is_leaf
)
1021 expand_epilogue_reg_restore (spreg
, all
, true);
1023 /* Deallocate any space we left on the stack in case we needed to save the
1024 argument registers. */
1025 if (fkind
== EXCPT_HANDLER
)
1026 emit_insn (gen_addsi3 (spreg
, spreg
, GEN_INT (12)));
1028 emit_jump_insn (gen_return_internal (GEN_INT (fkind
)));
1031 /* Used while emitting the prologue to generate code to load the correct value
1032 into the PIC register, which is passed in DEST. */
1035 bfin_load_pic_reg (rtx dest
)
1037 struct cgraph_local_info
*i
= NULL
;
1040 if (flag_unit_at_a_time
)
1041 i
= cgraph_local_info (current_function_decl
);
1043 /* Functions local to the translation unit don't need to reload the
1044 pic reg, since the caller always passes a usable one. */
1046 return pic_offset_table_rtx
;
1048 if (bfin_lib_id_given
)
1049 addr
= plus_constant (pic_offset_table_rtx
, -4 - bfin_library_id
* 4);
1051 addr
= gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
,
1052 gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, const0_rtx
),
1053 UNSPEC_LIBRARY_OFFSET
));
1054 insn
= emit_insn (gen_movsi (dest
, gen_rtx_MEM (Pmode
, addr
)));
1058 /* Generate RTL for the prologue of the current function. */
1061 bfin_expand_prologue (void)
1063 HOST_WIDE_INT frame_size
= get_frame_size ();
1064 rtx spreg
= gen_rtx_REG (Pmode
, REG_SP
);
1065 e_funkind fkind
= funkind (TREE_TYPE (current_function_decl
));
1066 rtx pic_reg_loaded
= NULL_RTX
;
1067 tree attrs
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
1068 bool all
= lookup_attribute ("saveall", attrs
) != NULL_TREE
;
1070 if (fkind
!= SUBROUTINE
)
1072 expand_interrupt_handler_prologue (spreg
, fkind
, all
);
1076 if (current_function_limit_stack
1077 || TARGET_STACK_CHECK_L1
)
1079 HOST_WIDE_INT offset
1080 = bfin_initial_elimination_offset (ARG_POINTER_REGNUM
,
1081 STACK_POINTER_REGNUM
);
1082 rtx lim
= current_function_limit_stack
? stack_limit_rtx
: NULL_RTX
;
1083 rtx p2reg
= gen_rtx_REG (Pmode
, REG_P2
);
1087 emit_move_insn (p2reg
, gen_int_mode (0xFFB00000, SImode
));
1088 emit_move_insn (p2reg
, gen_rtx_MEM (Pmode
, p2reg
));
1091 if (GET_CODE (lim
) == SYMBOL_REF
)
1093 if (TARGET_ID_SHARED_LIBRARY
)
1095 rtx p1reg
= gen_rtx_REG (Pmode
, REG_P1
);
1097 pic_reg_loaded
= bfin_load_pic_reg (p2reg
);
1098 val
= legitimize_pic_address (stack_limit_rtx
, p1reg
,
1100 emit_move_insn (p1reg
, val
);
1101 frame_related_constant_load (p2reg
, offset
, FALSE
);
1102 emit_insn (gen_addsi3 (p2reg
, p2reg
, p1reg
));
1107 rtx limit
= plus_constant (lim
, offset
);
1108 emit_move_insn (p2reg
, limit
);
1115 emit_move_insn (p2reg
, lim
);
1116 add_to_reg (p2reg
, offset
, 0, 0);
1119 emit_insn (gen_compare_lt (bfin_cc_rtx
, spreg
, lim
));
1120 emit_insn (gen_trapifcc ());
1122 expand_prologue_reg_save (spreg
, all
, false);
1124 do_link (spreg
, frame_size
, false);
1126 if (TARGET_ID_SHARED_LIBRARY
1128 && (current_function_uses_pic_offset_table
1129 || !current_function_is_leaf
))
1130 bfin_load_pic_reg (pic_offset_table_rtx
);
1133 /* Generate RTL for the epilogue of the current function. NEED_RETURN is zero
1134 if this is for a sibcall. EH_RETURN is nonzero if we're expanding an
1135 eh_return pattern. SIBCALL_P is true if this is a sibcall epilogue,
1139 bfin_expand_epilogue (int need_return
, int eh_return
, bool sibcall_p
)
1141 rtx spreg
= gen_rtx_REG (Pmode
, REG_SP
);
1142 e_funkind fkind
= funkind (TREE_TYPE (current_function_decl
));
1143 int e
= sibcall_p
? -1 : 1;
1144 tree attrs
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
1145 bool all
= lookup_attribute ("saveall", attrs
) != NULL_TREE
;
1147 if (fkind
!= SUBROUTINE
)
1149 expand_interrupt_handler_epilogue (spreg
, fkind
, all
);
1153 do_unlink (spreg
, get_frame_size (), false, e
);
1155 expand_epilogue_reg_restore (spreg
, all
, false);
1157 /* Omit the return insn if this is for a sibcall. */
1162 emit_insn (gen_addsi3 (spreg
, spreg
, gen_rtx_REG (Pmode
, REG_P2
)));
1164 emit_jump_insn (gen_return_internal (GEN_INT (SUBROUTINE
)));
1167 /* Return nonzero if register OLD_REG can be renamed to register NEW_REG. */
1170 bfin_hard_regno_rename_ok (unsigned int old_reg ATTRIBUTE_UNUSED
,
1171 unsigned int new_reg
)
1173 /* Interrupt functions can only use registers that have already been
1174 saved by the prologue, even if they would normally be
1177 if (funkind (TREE_TYPE (current_function_decl
)) != SUBROUTINE
1178 && !df_regs_ever_live_p (new_reg
))
1184 /* Return the value of the return address for the frame COUNT steps up
1185 from the current frame, after the prologue.
1186 We punt for everything but the current frame by returning const0_rtx. */
1189 bfin_return_addr_rtx (int count
)
1194 return get_hard_reg_initial_val (Pmode
, REG_RETS
);
1197 /* Try machine-dependent ways of modifying an illegitimate address X
1198 to be legitimate. If we find one, return the new, valid address,
1199 otherwise return NULL_RTX.
1201 OLDX is the address as it was before break_out_memory_refs was called.
1202 In some cases it is useful to look at this to decide what needs to be done.
1204 MODE is the mode of the memory reference. */
1207 legitimize_address (rtx x ATTRIBUTE_UNUSED
, rtx oldx ATTRIBUTE_UNUSED
,
1208 enum machine_mode mode ATTRIBUTE_UNUSED
)
1214 bfin_delegitimize_address (rtx orig_x
)
1218 if (GET_CODE (x
) != MEM
)
1222 if (GET_CODE (x
) == PLUS
1223 && GET_CODE (XEXP (x
, 1)) == UNSPEC
1224 && XINT (XEXP (x
, 1), 1) == UNSPEC_MOVE_PIC
1225 && GET_CODE (XEXP (x
, 0)) == REG
1226 && REGNO (XEXP (x
, 0)) == PIC_OFFSET_TABLE_REGNUM
)
1227 return XVECEXP (XEXP (x
, 1), 0, 0);
1232 /* This predicate is used to compute the length of a load/store insn.
1233 OP is a MEM rtx, we return nonzero if its addressing mode requires a
1234 32-bit instruction. */
1237 effective_address_32bit_p (rtx op
, enum machine_mode mode
)
1239 HOST_WIDE_INT offset
;
1241 mode
= GET_MODE (op
);
1244 if (GET_CODE (op
) != PLUS
)
1246 gcc_assert (REG_P (op
) || GET_CODE (op
) == POST_INC
1247 || GET_CODE (op
) == PRE_DEC
|| GET_CODE (op
) == POST_DEC
);
1251 if (GET_CODE (XEXP (op
, 1)) == UNSPEC
)
1254 offset
= INTVAL (XEXP (op
, 1));
1256 /* All byte loads use a 16-bit offset. */
1257 if (GET_MODE_SIZE (mode
) == 1)
1260 if (GET_MODE_SIZE (mode
) == 4)
1262 /* Frame pointer relative loads can use a negative offset, all others
1263 are restricted to a small positive one. */
1264 if (XEXP (op
, 0) == frame_pointer_rtx
)
1265 return offset
< -128 || offset
> 60;
1266 return offset
< 0 || offset
> 60;
1269 /* Must be HImode now. */
1270 return offset
< 0 || offset
> 30;
1273 /* Returns true if X is a memory reference using an I register. */
1275 bfin_dsp_memref_p (rtx x
)
1280 if (GET_CODE (x
) == POST_INC
|| GET_CODE (x
) == PRE_INC
1281 || GET_CODE (x
) == POST_DEC
|| GET_CODE (x
) == PRE_DEC
)
1286 /* Return cost of the memory address ADDR.
1287 All addressing modes are equally cheap on the Blackfin. */
1290 bfin_address_cost (rtx addr ATTRIBUTE_UNUSED
)
1295 /* Subroutine of print_operand; used to print a memory reference X to FILE. */
1298 print_address_operand (FILE *file
, rtx x
)
1300 switch (GET_CODE (x
))
1303 output_address (XEXP (x
, 0));
1304 fprintf (file
, "+");
1305 output_address (XEXP (x
, 1));
1309 fprintf (file
, "--");
1310 output_address (XEXP (x
, 0));
1313 output_address (XEXP (x
, 0));
1314 fprintf (file
, "++");
1317 output_address (XEXP (x
, 0));
1318 fprintf (file
, "--");
1322 gcc_assert (GET_CODE (x
) != MEM
);
1323 print_operand (file
, x
, 0);
1328 /* Adding intp DImode support by Tony
1334 print_operand (FILE *file
, rtx x
, char code
)
1336 enum machine_mode mode
;
1340 if (GET_MODE (current_output_insn
) == SImode
)
1341 fprintf (file
, " ||");
1343 fprintf (file
, ";");
1347 mode
= GET_MODE (x
);
1352 switch (GET_CODE (x
))
1355 fprintf (file
, "e");
1358 fprintf (file
, "ne");
1361 fprintf (file
, "g");
1364 fprintf (file
, "l");
1367 fprintf (file
, "ge");
1370 fprintf (file
, "le");
1373 fprintf (file
, "g");
1376 fprintf (file
, "l");
1379 fprintf (file
, "ge");
1382 fprintf (file
, "le");
1385 output_operand_lossage ("invalid %%j value");
1389 case 'J': /* reverse logic */
1390 switch (GET_CODE(x
))
1393 fprintf (file
, "ne");
1396 fprintf (file
, "e");
1399 fprintf (file
, "le");
1402 fprintf (file
, "ge");
1405 fprintf (file
, "l");
1408 fprintf (file
, "g");
1411 fprintf (file
, "le");
1414 fprintf (file
, "ge");
1417 fprintf (file
, "l");
1420 fprintf (file
, "g");
1423 output_operand_lossage ("invalid %%J value");
1428 switch (GET_CODE (x
))
1434 fprintf (file
, "%s", short_reg_names
[REGNO (x
)]);
1436 output_operand_lossage ("invalid operand for code '%c'", code
);
1438 else if (code
== 'd')
1441 fprintf (file
, "%s", high_reg_names
[REGNO (x
)]);
1443 output_operand_lossage ("invalid operand for code '%c'", code
);
1445 else if (code
== 'w')
1447 if (REGNO (x
) == REG_A0
|| REGNO (x
) == REG_A1
)
1448 fprintf (file
, "%s.w", reg_names
[REGNO (x
)]);
1450 output_operand_lossage ("invalid operand for code '%c'", code
);
1452 else if (code
== 'x')
1454 if (REGNO (x
) == REG_A0
|| REGNO (x
) == REG_A1
)
1455 fprintf (file
, "%s.x", reg_names
[REGNO (x
)]);
1457 output_operand_lossage ("invalid operand for code '%c'", code
);
1459 else if (code
== 'v')
1461 if (REGNO (x
) == REG_A0
)
1462 fprintf (file
, "AV0");
1463 else if (REGNO (x
) == REG_A1
)
1464 fprintf (file
, "AV1");
1466 output_operand_lossage ("invalid operand for code '%c'", code
);
1468 else if (code
== 'D')
1470 if (D_REGNO_P (REGNO (x
)))
1471 fprintf (file
, "%s", dregs_pair_names
[REGNO (x
)]);
1473 output_operand_lossage ("invalid operand for code '%c'", code
);
1475 else if (code
== 'H')
1477 if ((mode
== DImode
|| mode
== DFmode
) && REG_P (x
))
1478 fprintf (file
, "%s", reg_names
[REGNO (x
) + 1]);
1480 output_operand_lossage ("invalid operand for code '%c'", code
);
1482 else if (code
== 'T')
1484 if (D_REGNO_P (REGNO (x
)))
1485 fprintf (file
, "%s", byte_reg_names
[REGNO (x
)]);
1487 output_operand_lossage ("invalid operand for code '%c'", code
);
1490 fprintf (file
, "%s", reg_names
[REGNO (x
)]);
1496 print_address_operand (file
, x
);
1508 fputs ("(FU)", file
);
1511 fputs ("(T)", file
);
1514 fputs ("(TFU)", file
);
1517 fputs ("(W32)", file
);
1520 fputs ("(IS)", file
);
1523 fputs ("(IU)", file
);
1526 fputs ("(IH)", file
);
1529 fputs ("(M)", file
);
1532 fputs ("(IS,M)", file
);
1535 fputs ("(ISS2)", file
);
1538 fputs ("(S2RND)", file
);
1545 else if (code
== 'b')
1547 if (INTVAL (x
) == 0)
1549 else if (INTVAL (x
) == 1)
1555 /* Moves to half registers with d or h modifiers always use unsigned
1557 else if (code
== 'd')
1558 x
= GEN_INT ((INTVAL (x
) >> 16) & 0xffff);
1559 else if (code
== 'h')
1560 x
= GEN_INT (INTVAL (x
) & 0xffff);
1561 else if (code
== 'N')
1562 x
= GEN_INT (-INTVAL (x
));
1563 else if (code
== 'X')
1564 x
= GEN_INT (exact_log2 (0xffffffff & INTVAL (x
)));
1565 else if (code
== 'Y')
1566 x
= GEN_INT (exact_log2 (0xffffffff & ~INTVAL (x
)));
1567 else if (code
== 'Z')
1568 /* Used for LINK insns. */
1569 x
= GEN_INT (-8 - INTVAL (x
));
1574 output_addr_const (file
, x
);
1578 output_operand_lossage ("invalid const_double operand");
1582 switch (XINT (x
, 1))
1584 case UNSPEC_MOVE_PIC
:
1585 output_addr_const (file
, XVECEXP (x
, 0, 0));
1586 fprintf (file
, "@GOT");
1589 case UNSPEC_MOVE_FDPIC
:
1590 output_addr_const (file
, XVECEXP (x
, 0, 0));
1591 fprintf (file
, "@GOT17M4");
1594 case UNSPEC_FUNCDESC_GOT17M4
:
1595 output_addr_const (file
, XVECEXP (x
, 0, 0));
1596 fprintf (file
, "@FUNCDESC_GOT17M4");
1599 case UNSPEC_LIBRARY_OFFSET
:
1600 fprintf (file
, "_current_shared_library_p5_offset_");
1609 output_addr_const (file
, x
);
1614 /* Argument support functions. */
1616 /* Initialize a variable CUM of type CUMULATIVE_ARGS
1617 for a call to a function whose data type is FNTYPE.
1618 For a library call, FNTYPE is 0.
1619 VDSP C Compiler manual, our ABI says that
1620 first 3 words of arguments will use R0, R1 and R2.
1624 init_cumulative_args (CUMULATIVE_ARGS
*cum
, tree fntype
,
1625 rtx libname ATTRIBUTE_UNUSED
)
1627 static CUMULATIVE_ARGS zero_cum
;
1631 /* Set up the number of registers to use for passing arguments. */
1633 cum
->nregs
= max_arg_registers
;
1634 cum
->arg_regs
= arg_regs
;
1636 cum
->call_cookie
= CALL_NORMAL
;
1637 /* Check for a longcall attribute. */
1638 if (fntype
&& lookup_attribute ("shortcall", TYPE_ATTRIBUTES (fntype
)))
1639 cum
->call_cookie
|= CALL_SHORT
;
1640 else if (fntype
&& lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype
)))
1641 cum
->call_cookie
|= CALL_LONG
;
1646 /* Update the data in CUM to advance over an argument
1647 of mode MODE and data type TYPE.
1648 (TYPE is null for libcalls where that information may not be available.) */
1651 function_arg_advance (CUMULATIVE_ARGS
*cum
, enum machine_mode mode
, tree type
,
1652 int named ATTRIBUTE_UNUSED
)
1654 int count
, bytes
, words
;
1656 bytes
= (mode
== BLKmode
) ? int_size_in_bytes (type
) : GET_MODE_SIZE (mode
);
1657 words
= (bytes
+ UNITS_PER_WORD
- 1) / UNITS_PER_WORD
;
1659 cum
->words
+= words
;
1660 cum
->nregs
-= words
;
1662 if (cum
->nregs
<= 0)
1665 cum
->arg_regs
= NULL
;
1669 for (count
= 1; count
<= words
; count
++)
1676 /* Define where to put the arguments to a function.
1677 Value is zero to push the argument on the stack,
1678 or a hard register in which to store the argument.
1680 MODE is the argument's machine mode.
1681 TYPE is the data type of the argument (as a tree).
1682 This is null for libcalls where that information may
1684 CUM is a variable of type CUMULATIVE_ARGS which gives info about
1685 the preceding args and about the function being called.
1686 NAMED is nonzero if this argument is a named parameter
1687 (otherwise it is an extra parameter matching an ellipsis). */
1690 function_arg (CUMULATIVE_ARGS
*cum
, enum machine_mode mode
, tree type
,
1691 int named ATTRIBUTE_UNUSED
)
1694 = (mode
== BLKmode
) ? int_size_in_bytes (type
) : GET_MODE_SIZE (mode
);
1696 if (mode
== VOIDmode
)
1697 /* Compute operand 2 of the call insn. */
1698 return GEN_INT (cum
->call_cookie
);
1704 return gen_rtx_REG (mode
, *(cum
->arg_regs
));
1709 /* For an arg passed partly in registers and partly in memory,
1710 this is the number of bytes passed in registers.
1711 For args passed entirely in registers or entirely in memory, zero.
1713 Refer VDSP C Compiler manual, our ABI.
1714 First 3 words are in registers. So, if an argument is larger
1715 than the registers available, it will span the register and
1719 bfin_arg_partial_bytes (CUMULATIVE_ARGS
*cum
, enum machine_mode mode
,
1720 tree type ATTRIBUTE_UNUSED
,
1721 bool named ATTRIBUTE_UNUSED
)
1724 = (mode
== BLKmode
) ? int_size_in_bytes (type
) : GET_MODE_SIZE (mode
);
1725 int bytes_left
= cum
->nregs
* UNITS_PER_WORD
;
1730 if (bytes_left
== 0)
1732 if (bytes
> bytes_left
)
1737 /* Variable sized types are passed by reference. */
1740 bfin_pass_by_reference (CUMULATIVE_ARGS
*cum ATTRIBUTE_UNUSED
,
1741 enum machine_mode mode ATTRIBUTE_UNUSED
,
1742 const_tree type
, bool named ATTRIBUTE_UNUSED
)
1744 return type
&& TREE_CODE (TYPE_SIZE (type
)) != INTEGER_CST
;
1747 /* Decide whether a type should be returned in memory (true)
1748 or in a register (false). This is called by the macro
1749 RETURN_IN_MEMORY. */
1752 bfin_return_in_memory (const_tree type
)
1754 int size
= int_size_in_bytes (type
);
1755 return size
> 2 * UNITS_PER_WORD
|| size
== -1;
1758 /* Register in which address to store a structure value
1759 is passed to a function. */
1761 bfin_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED
,
1762 int incoming ATTRIBUTE_UNUSED
)
1764 return gen_rtx_REG (Pmode
, REG_P0
);
1767 /* Return true when register may be used to pass function parameters. */
1770 function_arg_regno_p (int n
)
1773 for (i
= 0; arg_regs
[i
] != -1; i
++)
1774 if (n
== arg_regs
[i
])
1779 /* Returns 1 if OP contains a symbol reference */
1782 symbolic_reference_mentioned_p (rtx op
)
1784 register const char *fmt
;
1787 if (GET_CODE (op
) == SYMBOL_REF
|| GET_CODE (op
) == LABEL_REF
)
1790 fmt
= GET_RTX_FORMAT (GET_CODE (op
));
1791 for (i
= GET_RTX_LENGTH (GET_CODE (op
)) - 1; i
>= 0; i
--)
1797 for (j
= XVECLEN (op
, i
) - 1; j
>= 0; j
--)
1798 if (symbolic_reference_mentioned_p (XVECEXP (op
, i
, j
)))
1802 else if (fmt
[i
] == 'e' && symbolic_reference_mentioned_p (XEXP (op
, i
)))
1809 /* Decide whether we can make a sibling call to a function. DECL is the
1810 declaration of the function being targeted by the call and EXP is the
1811 CALL_EXPR representing the call. */
1814 bfin_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED
,
1815 tree exp ATTRIBUTE_UNUSED
)
1817 e_funkind fkind
= funkind (TREE_TYPE (current_function_decl
));
1818 if (fkind
!= SUBROUTINE
)
1820 if (!TARGET_ID_SHARED_LIBRARY
|| TARGET_SEP_DATA
)
1823 /* When compiling for ID shared libraries, can't sibcall a local function
1824 from a non-local function, because the local function thinks it does
1825 not need to reload P5 in the prologue, but the sibcall wil pop P5 in the
1826 sibcall epilogue, and we end up with the wrong value in P5. */
1828 if (!flag_unit_at_a_time
|| decl
== NULL
)
1829 /* Not enough information. */
1833 struct cgraph_local_info
*this_func
, *called_func
;
1835 this_func
= cgraph_local_info (current_function_decl
);
1836 called_func
= cgraph_local_info (decl
);
1837 return !called_func
->local
|| this_func
->local
;
1841 /* Emit RTL insns to initialize the variable parts of a trampoline at
1842 TRAMP. FNADDR is an RTX for the address of the function's pure
1843 code. CXT is an RTX for the static chain value for the function. */
1846 initialize_trampoline (rtx tramp
, rtx fnaddr
, rtx cxt
)
1848 rtx t1
= copy_to_reg (fnaddr
);
1849 rtx t2
= copy_to_reg (cxt
);
1855 rtx a
= memory_address (Pmode
, plus_constant (tramp
, 8));
1856 addr
= memory_address (Pmode
, tramp
);
1857 emit_move_insn (gen_rtx_MEM (SImode
, addr
), a
);
1861 addr
= memory_address (Pmode
, plus_constant (tramp
, i
+ 2));
1862 emit_move_insn (gen_rtx_MEM (HImode
, addr
), gen_lowpart (HImode
, t1
));
1863 emit_insn (gen_ashrsi3 (t1
, t1
, GEN_INT (16)));
1864 addr
= memory_address (Pmode
, plus_constant (tramp
, i
+ 6));
1865 emit_move_insn (gen_rtx_MEM (HImode
, addr
), gen_lowpart (HImode
, t1
));
1867 addr
= memory_address (Pmode
, plus_constant (tramp
, i
+ 10));
1868 emit_move_insn (gen_rtx_MEM (HImode
, addr
), gen_lowpart (HImode
, t2
));
1869 emit_insn (gen_ashrsi3 (t2
, t2
, GEN_INT (16)));
1870 addr
= memory_address (Pmode
, plus_constant (tramp
, i
+ 14));
1871 emit_move_insn (gen_rtx_MEM (HImode
, addr
), gen_lowpart (HImode
, t2
));
1874 /* Emit insns to move operands[1] into operands[0]. */
1877 emit_pic_move (rtx
*operands
, enum machine_mode mode ATTRIBUTE_UNUSED
)
1879 rtx temp
= reload_in_progress
? operands
[0] : gen_reg_rtx (Pmode
);
1881 gcc_assert (!TARGET_FDPIC
|| !(reload_in_progress
|| reload_completed
));
1882 if (GET_CODE (operands
[0]) == MEM
&& SYMBOLIC_CONST (operands
[1]))
1883 operands
[1] = force_reg (SImode
, operands
[1]);
1885 operands
[1] = legitimize_pic_address (operands
[1], temp
,
1886 TARGET_FDPIC
? OUR_FDPIC_REG
1887 : pic_offset_table_rtx
);
1890 /* Expand a move operation in mode MODE. The operands are in OPERANDS.
1891 Returns true if no further code must be generated, false if the caller
1892 should generate an insn to move OPERANDS[1] to OPERANDS[0]. */
1895 expand_move (rtx
*operands
, enum machine_mode mode
)
1897 rtx op
= operands
[1];
1898 if ((TARGET_ID_SHARED_LIBRARY
|| TARGET_FDPIC
)
1899 && SYMBOLIC_CONST (op
))
1900 emit_pic_move (operands
, mode
);
1901 else if (mode
== SImode
&& GET_CODE (op
) == CONST
1902 && GET_CODE (XEXP (op
, 0)) == PLUS
1903 && GET_CODE (XEXP (XEXP (op
, 0), 0)) == SYMBOL_REF
1904 && !bfin_legitimate_constant_p (op
))
1906 rtx dest
= operands
[0];
1908 gcc_assert (!reload_in_progress
&& !reload_completed
);
1910 op0
= force_reg (mode
, XEXP (op
, 0));
1912 if (!insn_data
[CODE_FOR_addsi3
].operand
[2].predicate (op1
, mode
))
1913 op1
= force_reg (mode
, op1
);
1914 if (GET_CODE (dest
) == MEM
)
1915 dest
= gen_reg_rtx (mode
);
1916 emit_insn (gen_addsi3 (dest
, op0
, op1
));
1917 if (dest
== operands
[0])
1921 /* Don't generate memory->memory or constant->memory moves, go through a
1923 else if ((reload_in_progress
| reload_completed
) == 0
1924 && GET_CODE (operands
[0]) == MEM
1925 && GET_CODE (operands
[1]) != REG
)
1926 operands
[1] = force_reg (mode
, operands
[1]);
1930 /* Split one or more DImode RTL references into pairs of SImode
1931 references. The RTL can be REG, offsettable MEM, integer constant, or
1932 CONST_DOUBLE. "operands" is a pointer to an array of DImode RTL to
1933 split and "num" is its length. lo_half and hi_half are output arrays
1934 that parallel "operands". */
1937 split_di (rtx operands
[], int num
, rtx lo_half
[], rtx hi_half
[])
1941 rtx op
= operands
[num
];
1943 /* simplify_subreg refuse to split volatile memory addresses,
1944 but we still have to handle it. */
1945 if (GET_CODE (op
) == MEM
)
1947 lo_half
[num
] = adjust_address (op
, SImode
, 0);
1948 hi_half
[num
] = adjust_address (op
, SImode
, 4);
1952 lo_half
[num
] = simplify_gen_subreg (SImode
, op
,
1953 GET_MODE (op
) == VOIDmode
1954 ? DImode
: GET_MODE (op
), 0);
1955 hi_half
[num
] = simplify_gen_subreg (SImode
, op
,
1956 GET_MODE (op
) == VOIDmode
1957 ? DImode
: GET_MODE (op
), 4);
1963 bfin_longcall_p (rtx op
, int call_cookie
)
1965 gcc_assert (GET_CODE (op
) == SYMBOL_REF
);
1966 if (call_cookie
& CALL_SHORT
)
1968 if (call_cookie
& CALL_LONG
)
1970 if (TARGET_LONG_CALLS
)
1975 /* Expand a call instruction. FNADDR is the call target, RETVAL the return value.
1976 COOKIE is a CONST_INT holding the call_cookie prepared init_cumulative_args.
1977 SIBCALL is nonzero if this is a sibling call. */
1980 bfin_expand_call (rtx retval
, rtx fnaddr
, rtx callarg1
, rtx cookie
, int sibcall
)
1982 rtx use
= NULL
, call
;
1983 rtx callee
= XEXP (fnaddr
, 0);
1984 int nelts
= 2 + !!sibcall
;
1986 rtx picreg
= get_hard_reg_initial_val (SImode
, FDPIC_REGNO
);
1989 /* In an untyped call, we can get NULL for operand 2. */
1990 if (cookie
== NULL_RTX
)
1991 cookie
= const0_rtx
;
1993 /* Static functions and indirect calls don't need the pic register. */
1994 if (!TARGET_FDPIC
&& flag_pic
1995 && GET_CODE (callee
) == SYMBOL_REF
1996 && !SYMBOL_REF_LOCAL_P (callee
))
1997 use_reg (&use
, pic_offset_table_rtx
);
2001 int caller_has_l1_text
, callee_has_l1_text
;
2003 caller_has_l1_text
= callee_has_l1_text
= 0;
2005 if (lookup_attribute ("l1_text",
2006 DECL_ATTRIBUTES (cfun
->decl
)) != NULL_TREE
)
2007 caller_has_l1_text
= 1;
2009 if (GET_CODE (callee
) == SYMBOL_REF
2010 && SYMBOL_REF_DECL (callee
) && DECL_P (SYMBOL_REF_DECL (callee
))
2013 DECL_ATTRIBUTES (SYMBOL_REF_DECL (callee
))) != NULL_TREE
)
2014 callee_has_l1_text
= 1;
2016 if (GET_CODE (callee
) != SYMBOL_REF
2017 || bfin_longcall_p (callee
, INTVAL (cookie
))
2018 || (GET_CODE (callee
) == SYMBOL_REF
2019 && !SYMBOL_REF_LOCAL_P (callee
)
2020 && TARGET_INLINE_PLT
)
2021 || caller_has_l1_text
!= callee_has_l1_text
2022 || (caller_has_l1_text
&& callee_has_l1_text
2023 && (GET_CODE (callee
) != SYMBOL_REF
2024 || !SYMBOL_REF_LOCAL_P (callee
))))
2027 if (! address_operand (addr
, Pmode
))
2028 addr
= force_reg (Pmode
, addr
);
2030 fnaddr
= gen_reg_rtx (SImode
);
2031 emit_insn (gen_load_funcdescsi (fnaddr
, addr
));
2032 fnaddr
= gen_rtx_MEM (Pmode
, fnaddr
);
2034 picreg
= gen_reg_rtx (SImode
);
2035 emit_insn (gen_load_funcdescsi (picreg
,
2036 plus_constant (addr
, 4)));
2041 else if ((!register_no_elim_operand (callee
, Pmode
)
2042 && GET_CODE (callee
) != SYMBOL_REF
)
2043 || (GET_CODE (callee
) == SYMBOL_REF
2044 && ((TARGET_ID_SHARED_LIBRARY
&& !TARGET_LEAF_ID_SHARED_LIBRARY
)
2045 || bfin_longcall_p (callee
, INTVAL (cookie
)))))
2047 callee
= copy_to_mode_reg (Pmode
, callee
);
2048 fnaddr
= gen_rtx_MEM (Pmode
, callee
);
2050 call
= gen_rtx_CALL (VOIDmode
, fnaddr
, callarg1
);
2053 call
= gen_rtx_SET (VOIDmode
, retval
, call
);
2055 pat
= gen_rtx_PARALLEL (VOIDmode
, rtvec_alloc (nelts
));
2057 XVECEXP (pat
, 0, n
++) = call
;
2059 XVECEXP (pat
, 0, n
++) = gen_rtx_USE (VOIDmode
, picreg
);
2060 XVECEXP (pat
, 0, n
++) = gen_rtx_USE (VOIDmode
, cookie
);
2062 XVECEXP (pat
, 0, n
++) = gen_rtx_RETURN (VOIDmode
);
2063 call
= emit_call_insn (pat
);
2065 CALL_INSN_FUNCTION_USAGE (call
) = use
;
2068 /* Return 1 if hard register REGNO can hold a value of machine-mode MODE. */
2071 hard_regno_mode_ok (int regno
, enum machine_mode mode
)
2073 /* Allow only dregs to store value of mode HI or QI */
2074 enum reg_class
class = REGNO_REG_CLASS (regno
);
2079 if (mode
== V2HImode
)
2080 return D_REGNO_P (regno
);
2081 if (class == CCREGS
)
2082 return mode
== BImode
;
2083 if (mode
== PDImode
|| mode
== V2PDImode
)
2084 return regno
== REG_A0
|| regno
== REG_A1
;
2086 /* Allow all normal 32-bit regs, except REG_M3, in case regclass ever comes
2087 up with a bad register class (such as ALL_REGS) for DImode. */
2089 return regno
< REG_M3
;
2092 && TEST_HARD_REG_BIT (reg_class_contents
[PROLOGUE_REGS
], regno
))
2095 return TEST_HARD_REG_BIT (reg_class_contents
[MOST_REGS
], regno
);
2098 /* Implements target hook vector_mode_supported_p. */
2101 bfin_vector_mode_supported_p (enum machine_mode mode
)
2103 return mode
== V2HImode
;
2106 /* Return the cost of moving data from a register in class CLASS1 to
2107 one in class CLASS2. A cost of 2 is the default. */
2110 bfin_register_move_cost (enum machine_mode mode
,
2111 enum reg_class class1
, enum reg_class class2
)
2113 /* These need secondary reloads, so they're more expensive. */
2114 if ((class1
== CCREGS
&& class2
!= DREGS
)
2115 || (class1
!= DREGS
&& class2
== CCREGS
))
2118 /* If optimizing for size, always prefer reg-reg over reg-memory moves. */
2122 /* There are some stalls involved when moving from a DREG to a different
2123 class reg, and using the value in one of the following instructions.
2124 Attempt to model this by slightly discouraging such moves. */
2125 if (class1
== DREGS
&& class2
!= DREGS
)
2128 if (GET_MODE_CLASS (mode
) == MODE_INT
)
2130 /* Discourage trying to use the accumulators. */
2131 if (TEST_HARD_REG_BIT (reg_class_contents
[class1
], REG_A0
)
2132 || TEST_HARD_REG_BIT (reg_class_contents
[class1
], REG_A1
)
2133 || TEST_HARD_REG_BIT (reg_class_contents
[class2
], REG_A0
)
2134 || TEST_HARD_REG_BIT (reg_class_contents
[class2
], REG_A1
))
2140 /* Return the cost of moving data of mode M between a
2141 register and memory. A value of 2 is the default; this cost is
2142 relative to those in `REGISTER_MOVE_COST'.
2144 ??? In theory L1 memory has single-cycle latency. We should add a switch
2145 that tells the compiler whether we expect to use only L1 memory for the
2146 program; it'll make the costs more accurate. */
2149 bfin_memory_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED
,
2150 enum reg_class
class,
2151 int in ATTRIBUTE_UNUSED
)
2153 /* Make memory accesses slightly more expensive than any register-register
2154 move. Also, penalize non-DP registers, since they need secondary
2155 reloads to load and store. */
2156 if (! reg_class_subset_p (class, DPREGS
))
2162 /* Inform reload about cases where moving X with a mode MODE to a register in
2163 CLASS requires an extra scratch register. Return the class needed for the
2164 scratch register. */
2166 static enum reg_class
2167 bfin_secondary_reload (bool in_p
, rtx x
, enum reg_class
class,
2168 enum machine_mode mode
, secondary_reload_info
*sri
)
2170 /* If we have HImode or QImode, we can only use DREGS as secondary registers;
2171 in most other cases we can also use PREGS. */
2172 enum reg_class default_class
= GET_MODE_SIZE (mode
) >= 4 ? DPREGS
: DREGS
;
2173 enum reg_class x_class
= NO_REGS
;
2174 enum rtx_code code
= GET_CODE (x
);
2177 x
= SUBREG_REG (x
), code
= GET_CODE (x
);
2180 int regno
= REGNO (x
);
2181 if (regno
>= FIRST_PSEUDO_REGISTER
)
2182 regno
= reg_renumber
[regno
];
2187 x_class
= REGNO_REG_CLASS (regno
);
2190 /* We can be asked to reload (plus (FP) (large_constant)) into a DREG.
2191 This happens as a side effect of register elimination, and we need
2192 a scratch register to do it. */
2193 if (fp_plus_const_operand (x
, mode
))
2195 rtx op2
= XEXP (x
, 1);
2196 int large_constant_p
= ! CONST_7BIT_IMM_P (INTVAL (op2
));
2198 if (class == PREGS
|| class == PREGS_CLOBBERED
)
2200 /* If destination is a DREG, we can do this without a scratch register
2201 if the constant is valid for an add instruction. */
2202 if ((class == DREGS
|| class == DPREGS
)
2203 && ! large_constant_p
)
2205 /* Reloading to anything other than a DREG? Use a PREG scratch
2207 sri
->icode
= CODE_FOR_reload_insi
;
2211 /* Data can usually be moved freely between registers of most classes.
2212 AREGS are an exception; they can only move to or from another register
2213 in AREGS or one in DREGS. They can also be assigned the constant 0. */
2214 if (x_class
== AREGS
|| x_class
== EVEN_AREGS
|| x_class
== ODD_AREGS
)
2215 return (class == DREGS
|| class == AREGS
|| class == EVEN_AREGS
2216 || class == ODD_AREGS
2219 if (class == AREGS
|| class == EVEN_AREGS
|| class == ODD_AREGS
)
2223 sri
->icode
= in_p
? CODE_FOR_reload_inpdi
: CODE_FOR_reload_outpdi
;
2227 if (x
!= const0_rtx
&& x_class
!= DREGS
)
2235 /* CCREGS can only be moved from/to DREGS. */
2236 if (class == CCREGS
&& x_class
!= DREGS
)
2238 if (x_class
== CCREGS
&& class != DREGS
)
2241 /* All registers other than AREGS can load arbitrary constants. The only
2242 case that remains is MEM. */
2244 if (! reg_class_subset_p (class, default_class
))
2245 return default_class
;
2250 /* Implement TARGET_HANDLE_OPTION. */
2253 bfin_handle_option (size_t code
, const char *arg
, int value
)
2257 case OPT_mshared_library_id_
:
2258 if (value
> MAX_LIBRARY_ID
)
2259 error ("-mshared-library-id=%s is not between 0 and %d",
2260 arg
, MAX_LIBRARY_ID
);
2261 bfin_lib_id_given
= 1;
2270 while ((p
= bfin_cpus
[i
].name
) != NULL
)
2272 if (strncmp (arg
, p
, strlen (p
)) == 0)
2279 error ("-mcpu=%s is not valid", arg
);
2283 bfin_cpu_type
= bfin_cpus
[i
].type
;
2285 q
= arg
+ strlen (p
);
2289 bfin_si_revision
= bfin_cpus
[i
].si_revision
;
2290 bfin_workarounds
|= bfin_cpus
[i
].workarounds
;
2292 else if (strcmp (q
, "-none") == 0)
2293 bfin_si_revision
= -1;
2294 else if (strcmp (q
, "-any") == 0)
2296 bfin_si_revision
= 0xffff;
2297 while (bfin_cpus
[i
].type
== bfin_cpu_type
)
2299 bfin_workarounds
|= bfin_cpus
[i
].workarounds
;
2305 unsigned int si_major
, si_minor
;
2308 rev_len
= strlen (q
);
2310 if (sscanf (q
, "-%u.%u%n", &si_major
, &si_minor
, &n
) != 2
2312 || si_major
> 0xff || si_minor
> 0xff)
2314 invalid_silicon_revision
:
2315 error ("-mcpu=%s has invalid silicon revision", arg
);
2319 bfin_si_revision
= (si_major
<< 8) | si_minor
;
2321 while (bfin_cpus
[i
].type
== bfin_cpu_type
2322 && bfin_cpus
[i
].si_revision
!= bfin_si_revision
)
2325 if (bfin_cpus
[i
].type
!= bfin_cpu_type
)
2326 goto invalid_silicon_revision
;
2328 bfin_workarounds
|= bfin_cpus
[i
].workarounds
;
2331 if (bfin_cpu_type
== BFIN_CPU_BF561
)
2332 warning (0, "bf561 support is incomplete yet.");
2342 static struct machine_function
*
2343 bfin_init_machine_status (void)
2345 struct machine_function
*f
;
2347 f
= ggc_alloc_cleared (sizeof (struct machine_function
));
2352 /* Implement the macro OVERRIDE_OPTIONS. */
2355 override_options (void)
2357 if (bfin_csync_anomaly
== 1)
2358 bfin_workarounds
|= WA_SPECULATIVE_SYNCS
;
2359 else if (bfin_csync_anomaly
== 0)
2360 bfin_workarounds
&= ~WA_SPECULATIVE_SYNCS
;
2362 if (bfin_specld_anomaly
== 1)
2363 bfin_workarounds
|= WA_SPECULATIVE_LOADS
;
2364 else if (bfin_specld_anomaly
== 0)
2365 bfin_workarounds
&= ~WA_SPECULATIVE_LOADS
;
2367 if (TARGET_OMIT_LEAF_FRAME_POINTER
)
2368 flag_omit_frame_pointer
= 1;
2370 /* Library identification */
2371 if (bfin_lib_id_given
&& ! TARGET_ID_SHARED_LIBRARY
)
2372 error ("-mshared-library-id= specified without -mid-shared-library");
2374 if (TARGET_ID_SHARED_LIBRARY
&& flag_pic
== 0)
2377 if (stack_limit_rtx
&& TARGET_STACK_CHECK_L1
)
2378 error ("Can't use multiple stack checking methods together.");
2380 if (TARGET_ID_SHARED_LIBRARY
&& TARGET_FDPIC
)
2381 error ("ID shared libraries and FD-PIC mode can't be used together.");
2383 /* Don't allow the user to specify -mid-shared-library and -msep-data
2384 together, as it makes little sense from a user's point of view... */
2385 if (TARGET_SEP_DATA
&& TARGET_ID_SHARED_LIBRARY
)
2386 error ("cannot specify both -msep-data and -mid-shared-library");
2387 /* ... internally, however, it's nearly the same. */
2388 if (TARGET_SEP_DATA
)
2389 target_flags
|= MASK_ID_SHARED_LIBRARY
| MASK_LEAF_ID_SHARED_LIBRARY
;
2391 /* There is no single unaligned SI op for PIC code. Sometimes we
2392 need to use ".4byte" and sometimes we need to use ".picptr".
2393 See bfin_assemble_integer for details. */
2395 targetm
.asm_out
.unaligned_op
.si
= 0;
2397 /* Silently turn off flag_pic if not doing FDPIC or ID shared libraries,
2398 since we don't support it and it'll just break. */
2399 if (flag_pic
&& !TARGET_FDPIC
&& !TARGET_ID_SHARED_LIBRARY
)
2402 flag_schedule_insns
= 0;
2404 /* Passes after sched2 can break the helpful TImode annotations that
2405 haifa-sched puts on every insn. Just do scheduling in reorg. */
2406 bfin_flag_schedule_insns2
= flag_schedule_insns_after_reload
;
2407 flag_schedule_insns_after_reload
= 0;
2409 init_machine_status
= bfin_init_machine_status
;
2412 /* Return the destination address of BRANCH.
2413 We need to use this instead of get_attr_length, because the
2414 cbranch_with_nops pattern conservatively sets its length to 6, and
2415 we still prefer to use shorter sequences. */
2418 branch_dest (rtx branch
)
2422 rtx pat
= PATTERN (branch
);
2423 if (GET_CODE (pat
) == PARALLEL
)
2424 pat
= XVECEXP (pat
, 0, 0);
2425 dest
= SET_SRC (pat
);
2426 if (GET_CODE (dest
) == IF_THEN_ELSE
)
2427 dest
= XEXP (dest
, 1);
2428 dest
= XEXP (dest
, 0);
2429 dest_uid
= INSN_UID (dest
);
2430 return INSN_ADDRESSES (dest_uid
);
2433 /* Return nonzero if INSN is annotated with a REG_BR_PROB note that indicates
2434 it's a branch that's predicted taken. */
2437 cbranch_predicted_taken_p (rtx insn
)
2439 rtx x
= find_reg_note (insn
, REG_BR_PROB
, 0);
2443 int pred_val
= INTVAL (XEXP (x
, 0));
2445 return pred_val
>= REG_BR_PROB_BASE
/ 2;
2451 /* Templates for use by asm_conditional_branch. */
2453 static const char *ccbranch_templates
[][3] = {
2454 { "if !cc jump %3;", "if cc jump 4 (bp); jump.s %3;", "if cc jump 6 (bp); jump.l %3;" },
2455 { "if cc jump %3;", "if !cc jump 4 (bp); jump.s %3;", "if !cc jump 6 (bp); jump.l %3;" },
2456 { "if !cc jump %3 (bp);", "if cc jump 4; jump.s %3;", "if cc jump 6; jump.l %3;" },
2457 { "if cc jump %3 (bp);", "if !cc jump 4; jump.s %3;", "if !cc jump 6; jump.l %3;" },
2460 /* Output INSN, which is a conditional branch instruction with operands
2463 We deal with the various forms of conditional branches that can be generated
2464 by bfin_reorg to prevent the hardware from doing speculative loads, by
2465 - emitting a sufficient number of nops, if N_NOPS is nonzero, or
2466 - always emitting the branch as predicted taken, if PREDICT_TAKEN is true.
2467 Either of these is only necessary if the branch is short, otherwise the
2468 template we use ends in an unconditional jump which flushes the pipeline
2472 asm_conditional_branch (rtx insn
, rtx
*operands
, int n_nops
, int predict_taken
)
2474 int offset
= branch_dest (insn
) - INSN_ADDRESSES (INSN_UID (insn
));
2475 /* Note : offset for instructions like if cc jmp; jump.[sl] offset
2476 is to be taken from start of if cc rather than jump.
2477 Range for jump.s is (-4094, 4096) instead of (-4096, 4094)
2479 int len
= (offset
>= -1024 && offset
<= 1022 ? 0
2480 : offset
>= -4094 && offset
<= 4096 ? 1
2482 int bp
= predict_taken
&& len
== 0 ? 1 : cbranch_predicted_taken_p (insn
);
2483 int idx
= (bp
<< 1) | (GET_CODE (operands
[0]) == EQ
? BRF
: BRT
);
2484 output_asm_insn (ccbranch_templates
[idx
][len
], operands
);
2485 gcc_assert (n_nops
== 0 || !bp
);
2487 while (n_nops
-- > 0)
2488 output_asm_insn ("nop;", NULL
);
2491 /* Emit rtl for a comparison operation CMP in mode MODE. Operands have been
2492 stored in bfin_compare_op0 and bfin_compare_op1 already. */
2495 bfin_gen_compare (rtx cmp
, enum machine_mode mode ATTRIBUTE_UNUSED
)
2497 enum rtx_code code1
, code2
;
2498 rtx op0
= bfin_compare_op0
, op1
= bfin_compare_op1
;
2499 rtx tem
= bfin_cc_rtx
;
2500 enum rtx_code code
= GET_CODE (cmp
);
2502 /* If we have a BImode input, then we already have a compare result, and
2503 do not need to emit another comparison. */
2504 if (GET_MODE (op0
) == BImode
)
2506 gcc_assert ((code
== NE
|| code
== EQ
) && op1
== const0_rtx
);
2507 tem
= op0
, code2
= code
;
2512 /* bfin has these conditions */
2522 code1
= reverse_condition (code
);
2526 emit_insn (gen_rtx_SET (BImode
, tem
,
2527 gen_rtx_fmt_ee (code1
, BImode
, op0
, op1
)));
2530 return gen_rtx_fmt_ee (code2
, BImode
, tem
, CONST0_RTX (BImode
));
2533 /* Return nonzero iff C has exactly one bit set if it is interpreted
2534 as a 32-bit constant. */
2537 log2constp (unsigned HOST_WIDE_INT c
)
2540 return c
!= 0 && (c
& (c
-1)) == 0;
2543 /* Returns the number of consecutive least significant zeros in the binary
2544 representation of *V.
2545 We modify *V to contain the original value arithmetically shifted right by
2546 the number of zeroes. */
2549 shiftr_zero (HOST_WIDE_INT
*v
)
2551 unsigned HOST_WIDE_INT tmp
= *v
;
2552 unsigned HOST_WIDE_INT sgn
;
2558 sgn
= tmp
& ((unsigned HOST_WIDE_INT
) 1 << (HOST_BITS_PER_WIDE_INT
- 1));
2559 while ((tmp
& 0x1) == 0 && n
<= 32)
2561 tmp
= (tmp
>> 1) | sgn
;
2568 /* After reload, split the load of an immediate constant. OPERANDS are the
2569 operands of the movsi_insn pattern which we are splitting. We return
2570 nonzero if we emitted a sequence to load the constant, zero if we emitted
2571 nothing because we want to use the splitter's default sequence. */
2574 split_load_immediate (rtx operands
[])
2576 HOST_WIDE_INT val
= INTVAL (operands
[1]);
2578 HOST_WIDE_INT shifted
= val
;
2579 HOST_WIDE_INT shifted_compl
= ~val
;
2580 int num_zero
= shiftr_zero (&shifted
);
2581 int num_compl_zero
= shiftr_zero (&shifted_compl
);
2582 unsigned int regno
= REGNO (operands
[0]);
2584 /* This case takes care of single-bit set/clear constants, which we could
2585 also implement with BITSET/BITCLR. */
2587 && shifted
>= -32768 && shifted
< 65536
2588 && (D_REGNO_P (regno
)
2589 || (regno
>= REG_P0
&& regno
<= REG_P7
&& num_zero
<= 2)))
2591 emit_insn (gen_movsi (operands
[0], GEN_INT (shifted
)));
2592 emit_insn (gen_ashlsi3 (operands
[0], operands
[0], GEN_INT (num_zero
)));
2597 tmp
|= -(tmp
& 0x8000);
2599 /* If high word has one bit set or clear, try to use a bit operation. */
2600 if (D_REGNO_P (regno
))
2602 if (log2constp (val
& 0xFFFF0000))
2604 emit_insn (gen_movsi (operands
[0], GEN_INT (val
& 0xFFFF)));
2605 emit_insn (gen_iorsi3 (operands
[0], operands
[0], GEN_INT (val
& 0xFFFF0000)));
2608 else if (log2constp (val
| 0xFFFF) && (val
& 0x8000) != 0)
2610 emit_insn (gen_movsi (operands
[0], GEN_INT (tmp
)));
2611 emit_insn (gen_andsi3 (operands
[0], operands
[0], GEN_INT (val
| 0xFFFF)));
2615 if (D_REGNO_P (regno
))
2617 if (CONST_7BIT_IMM_P (tmp
))
2619 emit_insn (gen_movsi (operands
[0], GEN_INT (tmp
)));
2620 emit_insn (gen_movstricthi_high (operands
[0], GEN_INT (val
& -65536)));
2624 if ((val
& 0xFFFF0000) == 0)
2626 emit_insn (gen_movsi (operands
[0], const0_rtx
));
2627 emit_insn (gen_movsi_low (operands
[0], operands
[0], operands
[1]));
2631 if ((val
& 0xFFFF0000) == 0xFFFF0000)
2633 emit_insn (gen_movsi (operands
[0], constm1_rtx
));
2634 emit_insn (gen_movsi_low (operands
[0], operands
[0], operands
[1]));
2639 /* Need DREGs for the remaining case. */
2644 && num_compl_zero
&& CONST_7BIT_IMM_P (shifted_compl
))
2646 /* If optimizing for size, generate a sequence that has more instructions
2648 emit_insn (gen_movsi (operands
[0], GEN_INT (shifted_compl
)));
2649 emit_insn (gen_ashlsi3 (operands
[0], operands
[0],
2650 GEN_INT (num_compl_zero
)));
2651 emit_insn (gen_one_cmplsi2 (operands
[0], operands
[0]));
2657 /* Return true if the legitimate memory address for a memory operand of mode
2658 MODE. Return false if not. */
2661 bfin_valid_add (enum machine_mode mode
, HOST_WIDE_INT value
)
2663 unsigned HOST_WIDE_INT v
= value
> 0 ? value
: -value
;
2664 int sz
= GET_MODE_SIZE (mode
);
2665 int shift
= sz
== 1 ? 0 : sz
== 2 ? 1 : 2;
2666 /* The usual offsettable_memref machinery doesn't work so well for this
2667 port, so we deal with the problem here. */
2668 if (value
> 0 && sz
== 8)
2670 return (v
& ~(0x7fff << shift
)) == 0;
2674 bfin_valid_reg_p (unsigned int regno
, int strict
, enum machine_mode mode
,
2675 enum rtx_code outer_code
)
2678 return REGNO_OK_FOR_BASE_STRICT_P (regno
, mode
, outer_code
, SCRATCH
);
2680 return REGNO_OK_FOR_BASE_NONSTRICT_P (regno
, mode
, outer_code
, SCRATCH
);
2684 bfin_legitimate_address_p (enum machine_mode mode
, rtx x
, int strict
)
2686 switch (GET_CODE (x
)) {
2688 if (bfin_valid_reg_p (REGNO (x
), strict
, mode
, MEM
))
2692 if (REG_P (XEXP (x
, 0))
2693 && bfin_valid_reg_p (REGNO (XEXP (x
, 0)), strict
, mode
, PLUS
)
2694 && ((GET_CODE (XEXP (x
, 1)) == UNSPEC
&& mode
== SImode
)
2695 || (GET_CODE (XEXP (x
, 1)) == CONST_INT
2696 && bfin_valid_add (mode
, INTVAL (XEXP (x
, 1))))))
2701 if (LEGITIMATE_MODE_FOR_AUTOINC_P (mode
)
2702 && REG_P (XEXP (x
, 0))
2703 && bfin_valid_reg_p (REGNO (XEXP (x
, 0)), strict
, mode
, POST_INC
))
2706 if (LEGITIMATE_MODE_FOR_AUTOINC_P (mode
)
2707 && XEXP (x
, 0) == stack_pointer_rtx
2708 && REG_P (XEXP (x
, 0))
2709 && bfin_valid_reg_p (REGNO (XEXP (x
, 0)), strict
, mode
, PRE_DEC
))
2718 /* Decide whether we can force certain constants to memory. If we
2719 decide we can't, the caller should be able to cope with it in
2723 bfin_cannot_force_const_mem (rtx x ATTRIBUTE_UNUSED
)
2725 /* We have only one class of non-legitimate constants, and our movsi
2726 expander knows how to handle them. Dropping these constants into the
2727 data section would only shift the problem - we'd still get relocs
2728 outside the object, in the data section rather than the text section. */
2732 /* Ensure that for any constant of the form symbol + offset, the offset
2733 remains within the object. Any other constants are ok.
2734 This ensures that flat binaries never have to deal with relocations
2735 crossing section boundaries. */
2738 bfin_legitimate_constant_p (rtx x
)
2741 HOST_WIDE_INT offset
;
2743 if (GET_CODE (x
) != CONST
)
2747 gcc_assert (GET_CODE (x
) == PLUS
);
2751 if (GET_CODE (sym
) != SYMBOL_REF
2752 || GET_CODE (x
) != CONST_INT
)
2754 offset
= INTVAL (x
);
2756 if (SYMBOL_REF_DECL (sym
) == 0)
2759 || offset
>= int_size_in_bytes (TREE_TYPE (SYMBOL_REF_DECL (sym
))))
2766 bfin_rtx_costs (rtx x
, int code
, int outer_code
, int *total
)
2768 int cost2
= COSTS_N_INSNS (1);
2774 if (outer_code
== SET
|| outer_code
== PLUS
)
2775 *total
= CONST_7BIT_IMM_P (INTVAL (x
)) ? 0 : cost2
;
2776 else if (outer_code
== AND
)
2777 *total
= log2constp (~INTVAL (x
)) ? 0 : cost2
;
2778 else if (outer_code
== LE
|| outer_code
== LT
|| outer_code
== EQ
)
2779 *total
= (INTVAL (x
) >= -4 && INTVAL (x
) <= 3) ? 0 : cost2
;
2780 else if (outer_code
== LEU
|| outer_code
== LTU
)
2781 *total
= (INTVAL (x
) >= 0 && INTVAL (x
) <= 7) ? 0 : cost2
;
2782 else if (outer_code
== MULT
)
2783 *total
= (INTVAL (x
) == 2 || INTVAL (x
) == 4) ? 0 : cost2
;
2784 else if (outer_code
== ASHIFT
&& (INTVAL (x
) == 1 || INTVAL (x
) == 2))
2786 else if (outer_code
== ASHIFT
|| outer_code
== ASHIFTRT
2787 || outer_code
== LSHIFTRT
)
2788 *total
= (INTVAL (x
) >= 0 && INTVAL (x
) <= 31) ? 0 : cost2
;
2789 else if (outer_code
== IOR
|| outer_code
== XOR
)
2790 *total
= (INTVAL (x
) & (INTVAL (x
) - 1)) == 0 ? 0 : cost2
;
2799 *total
= COSTS_N_INSNS (2);
2805 if (GET_MODE (x
) == SImode
)
2807 if (GET_CODE (op0
) == MULT
2808 && GET_CODE (XEXP (op0
, 1)) == CONST_INT
)
2810 HOST_WIDE_INT val
= INTVAL (XEXP (op0
, 1));
2811 if (val
== 2 || val
== 4)
2814 *total
+= rtx_cost (XEXP (op0
, 0), outer_code
);
2815 *total
+= rtx_cost (op1
, outer_code
);
2820 if (GET_CODE (op0
) != REG
2821 && (GET_CODE (op0
) != SUBREG
|| GET_CODE (SUBREG_REG (op0
)) != REG
))
2822 *total
+= rtx_cost (op0
, SET
);
2823 #if 0 /* We'd like to do this for accuracy, but it biases the loop optimizer
2824 towards creating too many induction variables. */
2825 if (!reg_or_7bit_operand (op1
, SImode
))
2826 *total
+= rtx_cost (op1
, SET
);
2829 else if (GET_MODE (x
) == DImode
)
2832 if (GET_CODE (op1
) != CONST_INT
2833 || !CONST_7BIT_IMM_P (INTVAL (op1
)))
2834 *total
+= rtx_cost (op1
, PLUS
);
2835 if (GET_CODE (op0
) != REG
2836 && (GET_CODE (op0
) != SUBREG
|| GET_CODE (SUBREG_REG (op0
)) != REG
))
2837 *total
+= rtx_cost (op0
, PLUS
);
2842 if (GET_MODE (x
) == DImode
)
2851 if (GET_MODE (x
) == DImode
)
2858 if (GET_CODE (op0
) != REG
2859 && (GET_CODE (op0
) != SUBREG
|| GET_CODE (SUBREG_REG (op0
)) != REG
))
2860 *total
+= rtx_cost (op0
, code
);
2870 /* Handle special cases of IOR: rotates, ALIGN insns, movstricthi_high. */
2873 if ((GET_CODE (op0
) == LSHIFTRT
&& GET_CODE (op1
) == ASHIFT
)
2874 || (GET_CODE (op0
) == ASHIFT
&& GET_CODE (op1
) == ZERO_EXTEND
)
2875 || (GET_CODE (op0
) == ASHIFT
&& GET_CODE (op1
) == LSHIFTRT
)
2876 || (GET_CODE (op0
) == AND
&& GET_CODE (op1
) == CONST_INT
))
2883 if (GET_CODE (op0
) != REG
2884 && (GET_CODE (op0
) != SUBREG
|| GET_CODE (SUBREG_REG (op0
)) != REG
))
2885 *total
+= rtx_cost (op0
, code
);
2887 if (GET_MODE (x
) == DImode
)
2893 if (GET_MODE (x
) != SImode
)
2898 if (! rhs_andsi3_operand (XEXP (x
, 1), SImode
))
2899 *total
+= rtx_cost (XEXP (x
, 1), code
);
2903 if (! regorlog2_operand (XEXP (x
, 1), SImode
))
2904 *total
+= rtx_cost (XEXP (x
, 1), code
);
2911 if (outer_code
== SET
2912 && XEXP (x
, 1) == const1_rtx
2913 && GET_CODE (XEXP (x
, 2)) == CONST_INT
)
2929 if (GET_CODE (op0
) == GET_CODE (op1
)
2930 && (GET_CODE (op0
) == ZERO_EXTEND
2931 || GET_CODE (op0
) == SIGN_EXTEND
))
2933 *total
= COSTS_N_INSNS (1);
2934 op0
= XEXP (op0
, 0);
2935 op1
= XEXP (op1
, 0);
2937 else if (optimize_size
)
2938 *total
= COSTS_N_INSNS (1);
2940 *total
= COSTS_N_INSNS (3);
2942 if (GET_CODE (op0
) != REG
2943 && (GET_CODE (op0
) != SUBREG
|| GET_CODE (SUBREG_REG (op0
)) != REG
))
2944 *total
+= rtx_cost (op0
, MULT
);
2945 if (GET_CODE (op1
) != REG
2946 && (GET_CODE (op1
) != SUBREG
|| GET_CODE (SUBREG_REG (op1
)) != REG
))
2947 *total
+= rtx_cost (op1
, MULT
);
2953 *total
= COSTS_N_INSNS (32);
2958 if (outer_code
== SET
)
2967 /* Used for communication between {push,pop}_multiple_operation (which
2968 we use not only as a predicate) and the corresponding output functions. */
2969 static int first_preg_to_save
, first_dreg_to_save
;
2972 push_multiple_operation (rtx op
, enum machine_mode mode ATTRIBUTE_UNUSED
)
2974 int lastdreg
= 8, lastpreg
= 6;
2977 first_preg_to_save
= lastpreg
;
2978 first_dreg_to_save
= lastdreg
;
2979 for (i
= 1, group
= 0; i
< XVECLEN (op
, 0) - 1; i
++)
2981 rtx t
= XVECEXP (op
, 0, i
);
2985 if (GET_CODE (t
) != SET
)
2989 dest
= SET_DEST (t
);
2990 if (GET_CODE (dest
) != MEM
|| ! REG_P (src
))
2992 dest
= XEXP (dest
, 0);
2993 if (GET_CODE (dest
) != PLUS
2994 || ! REG_P (XEXP (dest
, 0))
2995 || REGNO (XEXP (dest
, 0)) != REG_SP
2996 || GET_CODE (XEXP (dest
, 1)) != CONST_INT
2997 || INTVAL (XEXP (dest
, 1)) != -i
* 4)
3000 regno
= REGNO (src
);
3003 if (D_REGNO_P (regno
))
3006 first_dreg_to_save
= lastdreg
= regno
- REG_R0
;
3008 else if (regno
>= REG_P0
&& regno
<= REG_P7
)
3011 first_preg_to_save
= lastpreg
= regno
- REG_P0
;
3021 if (regno
>= REG_P0
&& regno
<= REG_P7
)
3024 first_preg_to_save
= lastpreg
= regno
- REG_P0
;
3026 else if (regno
!= REG_R0
+ lastdreg
+ 1)
3031 else if (group
== 2)
3033 if (regno
!= REG_P0
+ lastpreg
+ 1)
3042 pop_multiple_operation (rtx op
, enum machine_mode mode ATTRIBUTE_UNUSED
)
3044 int lastdreg
= 8, lastpreg
= 6;
3047 for (i
= 1, group
= 0; i
< XVECLEN (op
, 0); i
++)
3049 rtx t
= XVECEXP (op
, 0, i
);
3053 if (GET_CODE (t
) != SET
)
3057 dest
= SET_DEST (t
);
3058 if (GET_CODE (src
) != MEM
|| ! REG_P (dest
))
3060 src
= XEXP (src
, 0);
3064 if (! REG_P (src
) || REGNO (src
) != REG_SP
)
3067 else if (GET_CODE (src
) != PLUS
3068 || ! REG_P (XEXP (src
, 0))
3069 || REGNO (XEXP (src
, 0)) != REG_SP
3070 || GET_CODE (XEXP (src
, 1)) != CONST_INT
3071 || INTVAL (XEXP (src
, 1)) != (i
- 1) * 4)
3074 regno
= REGNO (dest
);
3077 if (regno
== REG_R7
)
3082 else if (regno
!= REG_P0
+ lastpreg
- 1)
3087 else if (group
== 1)
3089 if (regno
!= REG_R0
+ lastdreg
- 1)
3095 first_dreg_to_save
= lastdreg
;
3096 first_preg_to_save
= lastpreg
;
3100 /* Emit assembly code for one multi-register push described by INSN, with
3101 operands in OPERANDS. */
3104 output_push_multiple (rtx insn
, rtx
*operands
)
3109 /* Validate the insn again, and compute first_[dp]reg_to_save. */
3110 ok
= push_multiple_operation (PATTERN (insn
), VOIDmode
);
3113 if (first_dreg_to_save
== 8)
3114 sprintf (buf
, "[--sp] = ( p5:%d );\n", first_preg_to_save
);
3115 else if (first_preg_to_save
== 6)
3116 sprintf (buf
, "[--sp] = ( r7:%d );\n", first_dreg_to_save
);
3118 sprintf (buf
, "[--sp] = ( r7:%d, p5:%d );\n",
3119 first_dreg_to_save
, first_preg_to_save
);
3121 output_asm_insn (buf
, operands
);
3124 /* Emit assembly code for one multi-register pop described by INSN, with
3125 operands in OPERANDS. */
3128 output_pop_multiple (rtx insn
, rtx
*operands
)
3133 /* Validate the insn again, and compute first_[dp]reg_to_save. */
3134 ok
= pop_multiple_operation (PATTERN (insn
), VOIDmode
);
3137 if (first_dreg_to_save
== 8)
3138 sprintf (buf
, "( p5:%d ) = [sp++];\n", first_preg_to_save
);
3139 else if (first_preg_to_save
== 6)
3140 sprintf (buf
, "( r7:%d ) = [sp++];\n", first_dreg_to_save
);
3142 sprintf (buf
, "( r7:%d, p5:%d ) = [sp++];\n",
3143 first_dreg_to_save
, first_preg_to_save
);
3145 output_asm_insn (buf
, operands
);
3148 /* Adjust DST and SRC by OFFSET bytes, and generate one move in mode MODE. */
3151 single_move_for_movmem (rtx dst
, rtx src
, enum machine_mode mode
, HOST_WIDE_INT offset
)
3153 rtx scratch
= gen_reg_rtx (mode
);
3156 srcmem
= adjust_address_nv (src
, mode
, offset
);
3157 dstmem
= adjust_address_nv (dst
, mode
, offset
);
3158 emit_move_insn (scratch
, srcmem
);
3159 emit_move_insn (dstmem
, scratch
);
3162 /* Expand a string move operation of COUNT_EXP bytes from SRC to DST, with
3163 alignment ALIGN_EXP. Return true if successful, false if we should fall
3164 back on a different method. */
3167 bfin_expand_movmem (rtx dst
, rtx src
, rtx count_exp
, rtx align_exp
)
3169 rtx srcreg
, destreg
, countreg
;
3170 HOST_WIDE_INT align
= 0;
3171 unsigned HOST_WIDE_INT count
= 0;
3173 if (GET_CODE (align_exp
) == CONST_INT
)
3174 align
= INTVAL (align_exp
);
3175 if (GET_CODE (count_exp
) == CONST_INT
)
3177 count
= INTVAL (count_exp
);
3179 if (!TARGET_INLINE_ALL_STRINGOPS
&& count
> 64)
3184 /* If optimizing for size, only do single copies inline. */
3187 if (count
== 2 && align
< 2)
3189 if (count
== 4 && align
< 4)
3191 if (count
!= 1 && count
!= 2 && count
!= 4)
3194 if (align
< 2 && count
!= 1)
3197 destreg
= copy_to_mode_reg (Pmode
, XEXP (dst
, 0));
3198 if (destreg
!= XEXP (dst
, 0))
3199 dst
= replace_equiv_address_nv (dst
, destreg
);
3200 srcreg
= copy_to_mode_reg (Pmode
, XEXP (src
, 0));
3201 if (srcreg
!= XEXP (src
, 0))
3202 src
= replace_equiv_address_nv (src
, srcreg
);
3204 if (count
!= 0 && align
>= 2)
3206 unsigned HOST_WIDE_INT offset
= 0;
3210 if ((count
& ~3) == 4)
3212 single_move_for_movmem (dst
, src
, SImode
, offset
);
3215 else if (count
& ~3)
3217 HOST_WIDE_INT new_count
= ((count
>> 2) & 0x3fffffff) - 1;
3218 countreg
= copy_to_mode_reg (Pmode
, GEN_INT (new_count
));
3220 emit_insn (gen_rep_movsi (destreg
, srcreg
, countreg
, destreg
, srcreg
));
3224 single_move_for_movmem (dst
, src
, HImode
, offset
);
3230 if ((count
& ~1) == 2)
3232 single_move_for_movmem (dst
, src
, HImode
, offset
);
3235 else if (count
& ~1)
3237 HOST_WIDE_INT new_count
= ((count
>> 1) & 0x7fffffff) - 1;
3238 countreg
= copy_to_mode_reg (Pmode
, GEN_INT (new_count
));
3240 emit_insn (gen_rep_movhi (destreg
, srcreg
, countreg
, destreg
, srcreg
));
3245 single_move_for_movmem (dst
, src
, QImode
, offset
);
3252 /* Compute the alignment for a local variable.
3253 TYPE is the data type, and ALIGN is the alignment that
3254 the object would ordinarily have. The value of this macro is used
3255 instead of that alignment to align the object. */
3258 bfin_local_alignment (tree type
, int align
)
3260 /* Increasing alignment for (relatively) big types allows the builtin
3261 memcpy can use 32 bit loads/stores. */
3262 if (TYPE_SIZE (type
)
3263 && TREE_CODE (TYPE_SIZE (type
)) == INTEGER_CST
3264 && (TREE_INT_CST_LOW (TYPE_SIZE (type
)) > 8
3265 || TREE_INT_CST_HIGH (TYPE_SIZE (type
))) && align
< 32)
3270 /* Implement TARGET_SCHED_ISSUE_RATE. */
3273 bfin_issue_rate (void)
3279 bfin_adjust_cost (rtx insn
, rtx link
, rtx dep_insn
, int cost
)
3281 enum attr_type insn_type
, dep_insn_type
;
3282 int dep_insn_code_number
;
3284 /* Anti and output dependencies have zero cost. */
3285 if (REG_NOTE_KIND (link
) != 0)
3288 dep_insn_code_number
= recog_memoized (dep_insn
);
3290 /* If we can't recognize the insns, we can't really do anything. */
3291 if (dep_insn_code_number
< 0 || recog_memoized (insn
) < 0)
3294 insn_type
= get_attr_type (insn
);
3295 dep_insn_type
= get_attr_type (dep_insn
);
3297 if (dep_insn_type
== TYPE_MOVE
|| dep_insn_type
== TYPE_MCLD
)
3299 rtx pat
= PATTERN (dep_insn
);
3300 rtx dest
= SET_DEST (pat
);
3301 rtx src
= SET_SRC (pat
);
3302 if (! ADDRESS_REGNO_P (REGNO (dest
))
3303 || ! (MEM_P (src
) || D_REGNO_P (REGNO (src
))))
3305 return cost
+ (dep_insn_type
== TYPE_MOVE
? 4 : 3);
3312 /* Increment the counter for the number of loop instructions in the
3313 current function. */
3316 bfin_hardware_loop (void)
3318 cfun
->machine
->has_hardware_loops
++;
3321 /* Maximum loop nesting depth. */
3322 #define MAX_LOOP_DEPTH 2
3324 /* Maximum size of a loop. */
3325 #define MAX_LOOP_LENGTH 2042
3327 /* Maximum distance of the LSETUP instruction from the loop start. */
3328 #define MAX_LSETUP_DISTANCE 30
3330 /* We need to keep a vector of loops */
3331 typedef struct loop_info
*loop_info
;
3332 DEF_VEC_P (loop_info
);
3333 DEF_VEC_ALLOC_P (loop_info
,heap
);
3335 /* Information about a loop we have found (or are in the process of
3337 struct loop_info
GTY (())
3339 /* loop number, for dumps */
3342 /* All edges that jump into and out of the loop. */
3343 VEC(edge
,gc
) *incoming
;
3345 /* We can handle two cases: all incoming edges have the same destination
3346 block, or all incoming edges have the same source block. These two
3347 members are set to the common source or destination we found, or NULL
3348 if different blocks were found. If both are NULL the loop can't be
3350 basic_block incoming_src
;
3351 basic_block incoming_dest
;
3353 /* First block in the loop. This is the one branched to by the loop_end
3357 /* Last block in the loop (the one with the loop_end insn). */
3360 /* The successor block of the loop. This is the one the loop_end insn
3362 basic_block successor
;
3364 /* The last instruction in the tail. */
3367 /* The loop_end insn. */
3370 /* The iteration register. */
3373 /* The new initialization insn. */
3376 /* The new initialization instruction. */
3379 /* The new label placed at the beginning of the loop. */
3382 /* The new label placed at the end of the loop. */
3385 /* The length of the loop. */
3388 /* The nesting depth of the loop. */
3391 /* Nonzero if we can't optimize this loop. */
3394 /* True if we have visited this loop. */
3397 /* True if this loop body clobbers any of LC0, LT0, or LB0. */
3400 /* True if this loop body clobbers any of LC1, LT1, or LB1. */
3403 /* Next loop in the graph. */
3404 struct loop_info
*next
;
3406 /* Immediate outer loop of this loop. */
3407 struct loop_info
*outer
;
3409 /* Vector of blocks only within the loop, including those within
3411 VEC (basic_block
,heap
) *blocks
;
3413 /* Same information in a bitmap. */
3414 bitmap block_bitmap
;
3416 /* Vector of inner loops within this loop */
3417 VEC (loop_info
,heap
) *loops
;
3421 bfin_dump_loops (loop_info loops
)
3425 for (loop
= loops
; loop
; loop
= loop
->next
)
3431 fprintf (dump_file
, ";; loop %d: ", loop
->loop_no
);
3433 fprintf (dump_file
, "(bad) ");
3434 fprintf (dump_file
, "{head:%d, depth:%d}", loop
->head
->index
, loop
->depth
);
3436 fprintf (dump_file
, " blocks: [ ");
3437 for (ix
= 0; VEC_iterate (basic_block
, loop
->blocks
, ix
, b
); ix
++)
3438 fprintf (dump_file
, "%d ", b
->index
);
3439 fprintf (dump_file
, "] ");
3441 fprintf (dump_file
, " inner loops: [ ");
3442 for (ix
= 0; VEC_iterate (loop_info
, loop
->loops
, ix
, i
); ix
++)
3443 fprintf (dump_file
, "%d ", i
->loop_no
);
3444 fprintf (dump_file
, "]\n");
3446 fprintf (dump_file
, "\n");
3449 /* Scan the blocks of LOOP (and its inferiors) looking for basic block
3450 BB. Return true, if we find it. */
3453 bfin_bb_in_loop (loop_info loop
, basic_block bb
)
3455 return bitmap_bit_p (loop
->block_bitmap
, bb
->index
);
3458 /* Scan the blocks of LOOP (and its inferiors) looking for uses of
3459 REG. Return true, if we find any. Don't count the loop's loop_end
3460 insn if it matches LOOP_END. */
3463 bfin_scan_loop (loop_info loop
, rtx reg
, rtx loop_end
)
3468 for (ix
= 0; VEC_iterate (basic_block
, loop
->blocks
, ix
, bb
); ix
++)
3472 for (insn
= BB_HEAD (bb
);
3473 insn
!= NEXT_INSN (BB_END (bb
));
3474 insn
= NEXT_INSN (insn
))
3478 if (insn
== loop_end
)
3480 if (reg_mentioned_p (reg
, PATTERN (insn
)))
3487 /* Estimate the length of INSN conservatively. */
3490 length_for_loop (rtx insn
)
3493 if (JUMP_P (insn
) && any_condjump_p (insn
) && !optimize_size
)
3495 if (ENABLE_WA_SPECULATIVE_SYNCS
)
3497 else if (ENABLE_WA_SPECULATIVE_LOADS
)
3500 else if (LABEL_P (insn
))
3502 if (ENABLE_WA_SPECULATIVE_SYNCS
)
3507 length
+= get_attr_length (insn
);
3512 /* Optimize LOOP. */
3515 bfin_optimize_loop (loop_info loop
)
3519 rtx insn
, init_insn
, last_insn
, nop_insn
;
3520 rtx loop_init
, start_label
, end_label
;
3521 rtx reg_lc0
, reg_lc1
, reg_lt0
, reg_lt1
, reg_lb0
, reg_lb1
;
3523 rtx lc_reg
, lt_reg
, lb_reg
;
3527 int inner_depth
= 0;
3537 fprintf (dump_file
, ";; loop %d bad when found\n", loop
->loop_no
);
3541 /* Every loop contains in its list of inner loops every loop nested inside
3542 it, even if there are intermediate loops. This works because we're doing
3543 a depth-first search here and never visit a loop more than once. */
3544 for (ix
= 0; VEC_iterate (loop_info
, loop
->loops
, ix
, inner
); ix
++)
3546 bfin_optimize_loop (inner
);
3548 if (!inner
->bad
&& inner_depth
< inner
->depth
)
3550 inner_depth
= inner
->depth
;
3552 loop
->clobber_loop0
|= inner
->clobber_loop0
;
3553 loop
->clobber_loop1
|= inner
->clobber_loop1
;
3557 loop
->depth
= inner_depth
+ 1;
3558 if (loop
->depth
> MAX_LOOP_DEPTH
)
3561 fprintf (dump_file
, ";; loop %d too deep\n", loop
->loop_no
);
3565 /* Get the loop iteration register. */
3566 iter_reg
= loop
->iter_reg
;
3568 if (!DPREG_P (iter_reg
))
3571 fprintf (dump_file
, ";; loop %d iteration count NOT in PREG or DREG\n",
3576 if (loop
->incoming_src
)
3578 /* Make sure the predecessor is before the loop start label, as required by
3579 the LSETUP instruction. */
3581 for (insn
= BB_END (loop
->incoming_src
);
3582 insn
&& insn
!= loop
->start_label
;
3583 insn
= NEXT_INSN (insn
))
3584 length
+= length_for_loop (insn
);
3589 fprintf (dump_file
, ";; loop %d lsetup not before loop_start\n",
3594 if (length
> MAX_LSETUP_DISTANCE
)
3597 fprintf (dump_file
, ";; loop %d lsetup too far away\n", loop
->loop_no
);
3602 /* Check if start_label appears before loop_end and calculate the
3603 offset between them. We calculate the length of instructions
3606 for (insn
= loop
->start_label
;
3607 insn
&& insn
!= loop
->loop_end
;
3608 insn
= NEXT_INSN (insn
))
3609 length
+= length_for_loop (insn
);
3614 fprintf (dump_file
, ";; loop %d start_label not before loop_end\n",
3619 loop
->length
= length
;
3620 if (loop
->length
> MAX_LOOP_LENGTH
)
3623 fprintf (dump_file
, ";; loop %d too long\n", loop
->loop_no
);
3627 /* Scan all the blocks to make sure they don't use iter_reg. */
3628 if (bfin_scan_loop (loop
, iter_reg
, loop
->loop_end
))
3631 fprintf (dump_file
, ";; loop %d uses iterator\n", loop
->loop_no
);
3635 /* Scan all the insns to see if the loop body clobber
3636 any hardware loop registers. */
3638 reg_lc0
= gen_rtx_REG (SImode
, REG_LC0
);
3639 reg_lc1
= gen_rtx_REG (SImode
, REG_LC1
);
3640 reg_lt0
= gen_rtx_REG (SImode
, REG_LT0
);
3641 reg_lt1
= gen_rtx_REG (SImode
, REG_LT1
);
3642 reg_lb0
= gen_rtx_REG (SImode
, REG_LB0
);
3643 reg_lb1
= gen_rtx_REG (SImode
, REG_LB1
);
3645 for (ix
= 0; VEC_iterate (basic_block
, loop
->blocks
, ix
, bb
); ix
++)
3649 for (insn
= BB_HEAD (bb
);
3650 insn
!= NEXT_INSN (BB_END (bb
));
3651 insn
= NEXT_INSN (insn
))
3656 if (reg_set_p (reg_lc0
, insn
)
3657 || reg_set_p (reg_lt0
, insn
)
3658 || reg_set_p (reg_lb0
, insn
))
3659 loop
->clobber_loop0
= 1;
3661 if (reg_set_p (reg_lc1
, insn
)
3662 || reg_set_p (reg_lt1
, insn
)
3663 || reg_set_p (reg_lb1
, insn
))
3664 loop
->clobber_loop1
|= 1;
3668 if ((loop
->clobber_loop0
&& loop
->clobber_loop1
)
3669 || (loop
->depth
== MAX_LOOP_DEPTH
&& loop
->clobber_loop0
))
3671 loop
->depth
= MAX_LOOP_DEPTH
+ 1;
3673 fprintf (dump_file
, ";; loop %d no loop reg available\n",
3678 /* There should be an instruction before the loop_end instruction
3679 in the same basic block. And the instruction must not be
3681 - CONDITIONAL BRANCH
3685 - Returns (RTS, RTN, etc.) */
3688 last_insn
= PREV_INSN (loop
->loop_end
);
3692 for (; last_insn
!= PREV_INSN (BB_HEAD (bb
));
3693 last_insn
= PREV_INSN (last_insn
))
3694 if (INSN_P (last_insn
))
3697 if (last_insn
!= PREV_INSN (BB_HEAD (bb
)))
3700 if (single_pred_p (bb
)
3701 && single_pred (bb
) != ENTRY_BLOCK_PTR
)
3703 bb
= single_pred (bb
);
3704 last_insn
= BB_END (bb
);
3709 last_insn
= NULL_RTX
;
3717 fprintf (dump_file
, ";; loop %d has no last instruction\n",
3722 if (JUMP_P (last_insn
))
3724 loop_info inner
= bb
->aux
;
3726 && inner
->outer
== loop
3727 && inner
->loop_end
== last_insn
3728 && inner
->depth
== 1)
3729 /* This jump_insn is the exact loop_end of an inner loop
3730 and to be optimized away. So use the inner's last_insn. */
3731 last_insn
= inner
->last_insn
;
3735 fprintf (dump_file
, ";; loop %d has bad last instruction\n",
3740 else if (CALL_P (last_insn
)
3741 || (GET_CODE (PATTERN (last_insn
)) != SEQUENCE
3742 && get_attr_type (last_insn
) == TYPE_SYNC
)
3743 || recog_memoized (last_insn
) == CODE_FOR_return_internal
)
3746 fprintf (dump_file
, ";; loop %d has bad last instruction\n",
3751 if (GET_CODE (PATTERN (last_insn
)) == ASM_INPUT
3752 || asm_noperands (PATTERN (last_insn
)) >= 0
3753 || (GET_CODE (PATTERN (last_insn
)) != SEQUENCE
3754 && get_attr_seq_insns (last_insn
) == SEQ_INSNS_MULTI
))
3756 nop_insn
= emit_insn_after (gen_nop (), last_insn
);
3757 last_insn
= nop_insn
;
3760 loop
->last_insn
= last_insn
;
3762 /* The loop is good for replacement. */
3763 start_label
= loop
->start_label
;
3764 end_label
= gen_label_rtx ();
3765 iter_reg
= loop
->iter_reg
;
3767 if (loop
->depth
== 1 && !loop
->clobber_loop1
)
3772 loop
->clobber_loop1
= 1;
3779 loop
->clobber_loop0
= 1;
3782 /* If iter_reg is a DREG, we need generate an instruction to load
3783 the loop count into LC register. */
3784 if (D_REGNO_P (REGNO (iter_reg
)))
3786 init_insn
= gen_movsi (lc_reg
, iter_reg
);
3787 loop_init
= gen_lsetup_without_autoinit (lt_reg
, start_label
,
3791 else if (P_REGNO_P (REGNO (iter_reg
)))
3793 init_insn
= NULL_RTX
;
3794 loop_init
= gen_lsetup_with_autoinit (lt_reg
, start_label
,
3801 loop
->init
= init_insn
;
3802 loop
->end_label
= end_label
;
3803 loop
->loop_init
= loop_init
;
3807 fprintf (dump_file
, ";; replacing loop %d initializer with\n",
3809 print_rtl_single (dump_file
, loop
->loop_init
);
3810 fprintf (dump_file
, ";; replacing loop %d terminator with\n",
3812 print_rtl_single (dump_file
, loop
->loop_end
);
3817 if (loop
->init
!= NULL_RTX
)
3818 emit_insn (loop
->init
);
3819 seq_end
= emit_insn (loop
->loop_init
);
3824 if (loop
->incoming_src
)
3826 rtx prev
= BB_END (loop
->incoming_src
);
3827 if (VEC_length (edge
, loop
->incoming
) > 1
3828 || !(VEC_last (edge
, loop
->incoming
)->flags
& EDGE_FALLTHRU
))
3830 gcc_assert (JUMP_P (prev
));
3831 prev
= PREV_INSN (prev
);
3833 emit_insn_after (seq
, prev
);
3841 if (loop
->head
!= loop
->incoming_dest
)
3843 FOR_EACH_EDGE (e
, ei
, loop
->head
->preds
)
3845 if (e
->flags
& EDGE_FALLTHRU
)
3847 rtx newjump
= gen_jump (loop
->start_label
);
3848 emit_insn_before (newjump
, BB_HEAD (loop
->head
));
3849 new_bb
= create_basic_block (newjump
, newjump
, loop
->head
->prev_bb
);
3850 gcc_assert (new_bb
= loop
->head
->prev_bb
);
3856 emit_insn_before (seq
, BB_HEAD (loop
->head
));
3857 seq
= emit_label_before (gen_label_rtx (), seq
);
3859 new_bb
= create_basic_block (seq
, seq_end
, loop
->head
->prev_bb
);
3860 FOR_EACH_EDGE (e
, ei
, loop
->incoming
)
3862 if (!(e
->flags
& EDGE_FALLTHRU
)
3863 || e
->dest
!= loop
->head
)
3864 redirect_edge_and_branch_force (e
, new_bb
);
3866 redirect_edge_succ (e
, new_bb
);
3870 delete_insn (loop
->loop_end
);
3871 /* Insert the loop end label before the last instruction of the loop. */
3872 emit_label_before (loop
->end_label
, loop
->last_insn
);
3879 fprintf (dump_file
, ";; loop %d is bad\n", loop
->loop_no
);
3883 if (DPREG_P (loop
->iter_reg
))
3885 /* If loop->iter_reg is a DREG or PREG, we can split it here
3886 without scratch register. */
3889 emit_insn_before (gen_addsi3 (loop
->iter_reg
,
3894 emit_insn_before (gen_cmpsi (loop
->iter_reg
, const0_rtx
),
3897 insn
= emit_jump_insn_before (gen_bne (loop
->start_label
),
3900 JUMP_LABEL (insn
) = loop
->start_label
;
3901 LABEL_NUSES (loop
->start_label
)++;
3902 delete_insn (loop
->loop_end
);
3906 /* Called from bfin_reorg_loops when a potential loop end is found. LOOP is
3907 a newly set up structure describing the loop, it is this function's
3908 responsibility to fill most of it. TAIL_BB and TAIL_INSN point to the
3909 loop_end insn and its enclosing basic block. */
3912 bfin_discover_loop (loop_info loop
, basic_block tail_bb
, rtx tail_insn
)
3916 VEC (basic_block
,heap
) *works
= VEC_alloc (basic_block
,heap
,20);
3918 loop
->tail
= tail_bb
;
3919 loop
->head
= BRANCH_EDGE (tail_bb
)->dest
;
3920 loop
->successor
= FALLTHRU_EDGE (tail_bb
)->dest
;
3921 loop
->loop_end
= tail_insn
;
3922 loop
->last_insn
= NULL_RTX
;
3923 loop
->iter_reg
= SET_DEST (XVECEXP (PATTERN (tail_insn
), 0, 1));
3924 loop
->depth
= loop
->length
= 0;
3926 loop
->clobber_loop0
= loop
->clobber_loop1
= 0;
3929 loop
->incoming
= VEC_alloc (edge
, gc
, 2);
3930 loop
->init
= loop
->loop_init
= NULL_RTX
;
3931 loop
->start_label
= XEXP (XEXP (SET_SRC (XVECEXP (PATTERN (tail_insn
), 0, 0)), 1), 0);
3932 loop
->end_label
= NULL_RTX
;
3935 VEC_safe_push (basic_block
, heap
, works
, loop
->head
);
3937 while (VEC_iterate (basic_block
, works
, dwork
++, bb
))
3941 if (bb
== EXIT_BLOCK_PTR
)
3943 /* We've reached the exit block. The loop must be bad. */
3946 ";; Loop is bad - reached exit block while scanning\n");
3951 if (bitmap_bit_p (loop
->block_bitmap
, bb
->index
))
3954 /* We've not seen this block before. Add it to the loop's
3955 list and then add each successor to the work list. */
3957 VEC_safe_push (basic_block
, heap
, loop
->blocks
, bb
);
3958 bitmap_set_bit (loop
->block_bitmap
, bb
->index
);
3962 FOR_EACH_EDGE (e
, ei
, bb
->succs
)
3964 basic_block succ
= EDGE_SUCC (bb
, ei
.index
)->dest
;
3965 if (!REGNO_REG_SET_P (df_get_live_in (succ
),
3966 REGNO (loop
->iter_reg
)))
3968 if (!VEC_space (basic_block
, works
, 1))
3972 VEC_block_remove (basic_block
, works
, 0, dwork
);
3976 VEC_reserve (basic_block
, heap
, works
, 1);
3978 VEC_quick_push (basic_block
, works
, succ
);
3983 /* Find the predecessor, and make sure nothing else jumps into this loop. */
3987 for (dwork
= 0; VEC_iterate (basic_block
, loop
->blocks
, dwork
, bb
); dwork
++)
3991 FOR_EACH_EDGE (e
, ei
, bb
->preds
)
3993 basic_block pred
= e
->src
;
3995 if (!bfin_bb_in_loop (loop
, pred
))
3998 fprintf (dump_file
, ";; Loop %d: incoming edge %d -> %d\n",
3999 loop
->loop_no
, pred
->index
,
4001 VEC_safe_push (edge
, gc
, loop
->incoming
, e
);
4006 for (pass
= 0, retry
= 1; retry
&& pass
< 2; pass
++)
4013 FOR_EACH_EDGE (e
, ei
, loop
->incoming
)
4017 loop
->incoming_src
= e
->src
;
4018 loop
->incoming_dest
= e
->dest
;
4023 if (e
->dest
!= loop
->incoming_dest
)
4024 loop
->incoming_dest
= NULL
;
4025 if (e
->src
!= loop
->incoming_src
)
4026 loop
->incoming_src
= NULL
;
4028 if (loop
->incoming_src
== NULL
&& loop
->incoming_dest
== NULL
)
4034 ";; retrying loop %d with forwarder blocks\n",
4042 ";; can't find suitable entry for loop %d\n",
4050 FOR_EACH_EDGE (e
, ei
, loop
->incoming
)
4052 if (forwarder_block_p (e
->src
))
4059 ";; Adding forwarder block %d to loop %d and retrying\n",
4060 e
->src
->index
, loop
->loop_no
);
4061 VEC_safe_push (basic_block
, heap
, loop
->blocks
, e
->src
);
4062 bitmap_set_bit (loop
->block_bitmap
, e
->src
->index
);
4063 FOR_EACH_EDGE (e2
, ei2
, e
->src
->preds
)
4064 VEC_safe_push (edge
, gc
, loop
->incoming
, e2
);
4065 VEC_unordered_remove (edge
, loop
->incoming
, ei
.index
);
4075 VEC_free (basic_block
, heap
, works
);
4078 /* Analyze the structure of the loops in the current function. Use STACK
4079 for bitmap allocations. Returns all the valid candidates for hardware
4080 loops found in this function. */
4082 bfin_discover_loops (bitmap_obstack
*stack
, FILE *dump_file
)
4084 loop_info loops
= NULL
;
4090 /* Find all the possible loop tails. This means searching for every
4091 loop_end instruction. For each one found, create a loop_info
4092 structure and add the head block to the work list. */
4095 rtx tail
= BB_END (bb
);
4097 while (GET_CODE (tail
) == NOTE
)
4098 tail
= PREV_INSN (tail
);
4102 if (INSN_P (tail
) && recog_memoized (tail
) == CODE_FOR_loop_end
)
4104 /* A possible loop end */
4106 loop
= XNEW (struct loop_info
);
4109 loop
->loop_no
= nloops
++;
4110 loop
->blocks
= VEC_alloc (basic_block
, heap
, 20);
4111 loop
->block_bitmap
= BITMAP_ALLOC (stack
);
4116 fprintf (dump_file
, ";; potential loop %d ending at\n",
4118 print_rtl_single (dump_file
, tail
);
4121 bfin_discover_loop (loop
, bb
, tail
);
4125 tmp_bitmap
= BITMAP_ALLOC (stack
);
4126 /* Compute loop nestings. */
4127 for (loop
= loops
; loop
; loop
= loop
->next
)
4133 for (other
= loop
->next
; other
; other
= other
->next
)
4138 bitmap_and (tmp_bitmap
, other
->block_bitmap
, loop
->block_bitmap
);
4139 if (bitmap_empty_p (tmp_bitmap
))
4141 if (bitmap_equal_p (tmp_bitmap
, other
->block_bitmap
))
4143 other
->outer
= loop
;
4144 VEC_safe_push (loop_info
, heap
, loop
->loops
, other
);
4146 else if (bitmap_equal_p (tmp_bitmap
, loop
->block_bitmap
))
4148 loop
->outer
= other
;
4149 VEC_safe_push (loop_info
, heap
, other
->loops
, loop
);
4155 ";; can't find suitable nesting for loops %d and %d\n",
4156 loop
->loop_no
, other
->loop_no
);
4157 loop
->bad
= other
->bad
= 1;
4161 BITMAP_FREE (tmp_bitmap
);
4166 /* Free up the loop structures in LOOPS. */
4168 free_loops (loop_info loops
)
4172 loop_info loop
= loops
;
4174 VEC_free (loop_info
, heap
, loop
->loops
);
4175 VEC_free (basic_block
, heap
, loop
->blocks
);
4176 BITMAP_FREE (loop
->block_bitmap
);
4181 #define BB_AUX_INDEX(BB) ((unsigned)(BB)->aux)
4183 /* The taken-branch edge from the loop end can actually go forward. Since the
4184 Blackfin's LSETUP instruction requires that the loop end be after the loop
4185 start, try to reorder a loop's basic blocks when we find such a case. */
4187 bfin_reorder_loops (loop_info loops
, FILE *dump_file
)
4194 cfg_layout_initialize (0);
4196 for (loop
= loops
; loop
; loop
= loop
->next
)
4206 /* Recreate an index for basic blocks that represents their order. */
4207 for (bb
= ENTRY_BLOCK_PTR
->next_bb
, index
= 0;
4208 bb
!= EXIT_BLOCK_PTR
;
4209 bb
= bb
->next_bb
, index
++)
4210 bb
->aux
= (PTR
) index
;
4212 if (BB_AUX_INDEX (loop
->head
) < BB_AUX_INDEX (loop
->tail
))
4215 FOR_EACH_EDGE (e
, ei
, loop
->head
->succs
)
4217 if (bitmap_bit_p (loop
->block_bitmap
, e
->dest
->index
)
4218 && BB_AUX_INDEX (e
->dest
) < BB_AUX_INDEX (loop
->tail
))
4220 basic_block start_bb
= e
->dest
;
4221 basic_block start_prev_bb
= start_bb
->prev_bb
;
4224 fprintf (dump_file
, ";; Moving block %d before block %d\n",
4225 loop
->head
->index
, start_bb
->index
);
4226 loop
->head
->prev_bb
->next_bb
= loop
->head
->next_bb
;
4227 loop
->head
->next_bb
->prev_bb
= loop
->head
->prev_bb
;
4229 loop
->head
->prev_bb
= start_prev_bb
;
4230 loop
->head
->next_bb
= start_bb
;
4231 start_prev_bb
->next_bb
= start_bb
->prev_bb
= loop
->head
;
4235 loops
= loops
->next
;
4240 if (bb
->next_bb
!= EXIT_BLOCK_PTR
)
4241 bb
->aux
= bb
->next_bb
;
4245 cfg_layout_finalize ();
4249 /* Run from machine_dependent_reorg, this pass looks for doloop_end insns
4250 and tries to rewrite the RTL of these loops so that proper Blackfin
4251 hardware loops are generated. */
4254 bfin_reorg_loops (FILE *dump_file
)
4256 loop_info loops
= NULL
;
4259 bitmap_obstack stack
;
4261 bitmap_obstack_initialize (&stack
);
4264 fprintf (dump_file
, ";; Find loops, first pass\n\n");
4266 loops
= bfin_discover_loops (&stack
, dump_file
);
4269 bfin_dump_loops (loops
);
4271 bfin_reorder_loops (loops
, dump_file
);
4275 fprintf (dump_file
, ";; Find loops, second pass\n\n");
4277 loops
= bfin_discover_loops (&stack
, dump_file
);
4280 fprintf (dump_file
, ";; All loops found:\n\n");
4281 bfin_dump_loops (loops
);
4284 /* Now apply the optimizations. */
4285 for (loop
= loops
; loop
; loop
= loop
->next
)
4286 bfin_optimize_loop (loop
);
4290 fprintf (dump_file
, ";; After hardware loops optimization:\n\n");
4291 bfin_dump_loops (loops
);
4297 print_rtl (dump_file
, get_insns ());
4303 /* Possibly generate a SEQUENCE out of three insns found in SLOT.
4304 Returns true if we modified the insn chain, false otherwise. */
4306 gen_one_bundle (rtx slot
[3])
4308 gcc_assert (slot
[1] != NULL_RTX
);
4310 /* Verify that we really can do the multi-issue. */
4313 rtx t
= NEXT_INSN (slot
[0]);
4314 while (t
!= slot
[1])
4316 if (GET_CODE (t
) != NOTE
4317 || NOTE_KIND (t
) != NOTE_INSN_DELETED
)
4324 rtx t
= NEXT_INSN (slot
[1]);
4325 while (t
!= slot
[2])
4327 if (GET_CODE (t
) != NOTE
4328 || NOTE_KIND (t
) != NOTE_INSN_DELETED
)
4334 if (slot
[0] == NULL_RTX
)
4336 slot
[0] = emit_insn_before (gen_mnop (), slot
[1]);
4337 df_insn_rescan (slot
[0]);
4339 if (slot
[2] == NULL_RTX
)
4341 slot
[2] = emit_insn_after (gen_forced_nop (), slot
[1]);
4342 df_insn_rescan (slot
[2]);
4345 /* Avoid line number information being printed inside one bundle. */
4346 if (INSN_LOCATOR (slot
[1])
4347 && INSN_LOCATOR (slot
[1]) != INSN_LOCATOR (slot
[0]))
4348 INSN_LOCATOR (slot
[1]) = INSN_LOCATOR (slot
[0]);
4349 if (INSN_LOCATOR (slot
[2])
4350 && INSN_LOCATOR (slot
[2]) != INSN_LOCATOR (slot
[0]))
4351 INSN_LOCATOR (slot
[2]) = INSN_LOCATOR (slot
[0]);
4353 /* Terminate them with "|| " instead of ";" in the output. */
4354 PUT_MODE (slot
[0], SImode
);
4355 PUT_MODE (slot
[1], SImode
);
4356 /* Terminate the bundle, for the benefit of reorder_var_tracking_notes. */
4357 PUT_MODE (slot
[2], QImode
);
4361 /* Go through all insns, and use the information generated during scheduling
4362 to generate SEQUENCEs to represent bundles of instructions issued
4366 bfin_gen_bundles (void)
4375 slot
[0] = slot
[1] = slot
[2] = NULL_RTX
;
4376 for (insn
= BB_HEAD (bb
);; insn
= next
)
4381 if (get_attr_type (insn
) == TYPE_DSP32
)
4383 else if (slot
[1] == NULL_RTX
)
4390 next
= NEXT_INSN (insn
);
4391 while (next
&& insn
!= BB_END (bb
)
4393 && GET_CODE (PATTERN (next
)) != USE
4394 && GET_CODE (PATTERN (next
)) != CLOBBER
))
4397 next
= NEXT_INSN (insn
);
4400 /* BB_END can change due to emitting extra NOPs, so check here. */
4401 at_end
= insn
== BB_END (bb
);
4402 if (at_end
|| GET_MODE (next
) == TImode
)
4405 || !gen_one_bundle (slot
))
4406 && slot
[0] != NULL_RTX
)
4408 rtx pat
= PATTERN (slot
[0]);
4409 if (GET_CODE (pat
) == SET
4410 && GET_CODE (SET_SRC (pat
)) == UNSPEC
4411 && XINT (SET_SRC (pat
), 1) == UNSPEC_32BIT
)
4413 SET_SRC (pat
) = XVECEXP (SET_SRC (pat
), 0, 0);
4414 INSN_CODE (slot
[0]) = -1;
4415 df_insn_rescan (slot
[0]);
4419 slot
[0] = slot
[1] = slot
[2] = NULL_RTX
;
4427 /* Ensure that no var tracking notes are emitted in the middle of a
4428 three-instruction bundle. */
4431 reorder_var_tracking_notes (void)
4437 rtx queue
= NULL_RTX
;
4438 bool in_bundle
= false;
4440 for (insn
= BB_HEAD (bb
); insn
!= BB_END (bb
); insn
= next
)
4442 next
= NEXT_INSN (insn
);
4446 /* Emit queued up notes at the last instruction of a bundle. */
4447 if (GET_MODE (insn
) == QImode
)
4451 rtx next_queue
= PREV_INSN (queue
);
4452 PREV_INSN (NEXT_INSN (insn
)) = queue
;
4453 NEXT_INSN (queue
) = NEXT_INSN (insn
);
4454 NEXT_INSN (insn
) = queue
;
4455 PREV_INSN (queue
) = insn
;
4460 else if (GET_MODE (insn
) == SImode
)
4463 else if (NOTE_P (insn
) && NOTE_KIND (insn
) == NOTE_INSN_VAR_LOCATION
)
4467 rtx prev
= PREV_INSN (insn
);
4468 PREV_INSN (next
) = prev
;
4469 NEXT_INSN (prev
) = next
;
4471 PREV_INSN (insn
) = queue
;
4479 /* Return an insn type for INSN that can be used by the caller for anomaly
4480 workarounds. This differs from plain get_attr_type in that it handles
4483 static enum attr_type
4484 type_for_anomaly (rtx insn
)
4486 rtx pat
= PATTERN (insn
);
4487 if (GET_CODE (pat
) == SEQUENCE
)
4490 t
= get_attr_type (XVECEXP (pat
, 0, 1));
4493 t
= get_attr_type (XVECEXP (pat
, 0, 2));
4499 return get_attr_type (insn
);
4502 /* Return nonzero if INSN contains any loads that may trap. It handles
4503 SEQUENCEs correctly. */
4506 trapping_loads_p (rtx insn
)
4508 rtx pat
= PATTERN (insn
);
4509 if (GET_CODE (pat
) == SEQUENCE
)
4512 t
= get_attr_type (XVECEXP (pat
, 0, 1));
4514 && may_trap_p (SET_SRC (PATTERN (XVECEXP (pat
, 0, 1)))))
4516 t
= get_attr_type (XVECEXP (pat
, 0, 2));
4518 && may_trap_p (SET_SRC (PATTERN (XVECEXP (pat
, 0, 2)))))
4523 return may_trap_p (SET_SRC (single_set (insn
)));
4526 /* This function acts like NEXT_INSN, but is aware of three-insn bundles and
4527 skips all subsequent parallel instructions if INSN is the start of such
4530 find_next_insn_start (rtx insn
)
4532 if (GET_MODE (insn
) == SImode
)
4534 while (GET_MODE (insn
) != QImode
)
4535 insn
= NEXT_INSN (insn
);
4537 return NEXT_INSN (insn
);
4540 /* Return INSN if it is of TYPE_MCLD. Alternatively, if INSN is the start of
4541 a three-insn bundle, see if one of them is a load and return that if so.
4542 Return NULL_RTX if the insn does not contain loads. */
4544 find_load (rtx insn
)
4546 if (get_attr_type (insn
) == TYPE_MCLD
)
4548 if (GET_MODE (insn
) != SImode
)
4551 insn
= NEXT_INSN (insn
);
4552 if ((GET_MODE (insn
) == SImode
|| GET_MODE (insn
) == QImode
)
4553 && get_attr_type (insn
) == TYPE_MCLD
)
4555 } while (GET_MODE (insn
) != QImode
);
4559 /* We use the machine specific reorg pass for emitting CSYNC instructions
4560 after conditional branches as needed.
4562 The Blackfin is unusual in that a code sequence like
4565 may speculatively perform the load even if the condition isn't true. This
4566 happens for a branch that is predicted not taken, because the pipeline
4567 isn't flushed or stalled, so the early stages of the following instructions,
4568 which perform the memory reference, are allowed to execute before the
4569 jump condition is evaluated.
4570 Therefore, we must insert additional instructions in all places where this
4571 could lead to incorrect behavior. The manual recommends CSYNC, while
4572 VDSP seems to use NOPs (even though its corresponding compiler option is
4575 When optimizing for speed, we emit NOPs, which seems faster than a CSYNC.
4576 When optimizing for size, we turn the branch into a predicted taken one.
4577 This may be slower due to mispredicts, but saves code size. */
4583 rtx last_condjump
= NULL_RTX
;
4584 int cycles_since_jump
= INT_MAX
;
4586 /* We are freeing block_for_insn in the toplev to keep compatibility
4587 with old MDEP_REORGS that are not CFG based. Recompute it now. */
4588 compute_bb_for_insn ();
4590 if (bfin_flag_schedule_insns2
)
4592 splitting_for_sched
= 1;
4594 splitting_for_sched
= 0;
4596 timevar_push (TV_SCHED2
);
4598 timevar_pop (TV_SCHED2
);
4600 /* Examine the schedule and insert nops as necessary for 64-bit parallel
4602 bfin_gen_bundles ();
4607 /* Doloop optimization */
4608 if (cfun
->machine
->has_hardware_loops
)
4609 bfin_reorg_loops (dump_file
);
4611 if (! ENABLE_WA_SPECULATIVE_LOADS
&& ! ENABLE_WA_SPECULATIVE_SYNCS
)
4614 /* First pass: find predicted-false branches; if something after them
4615 needs nops, insert them or change the branch to predict true. */
4616 for (insn
= get_insns (); insn
; insn
= next
)
4620 next
= find_next_insn_start (insn
);
4622 if (NOTE_P (insn
) || BARRIER_P (insn
) || LABEL_P (insn
))
4625 pat
= PATTERN (insn
);
4626 if (GET_CODE (pat
) == USE
|| GET_CODE (pat
) == CLOBBER
4627 || GET_CODE (pat
) == ASM_INPUT
|| GET_CODE (pat
) == ADDR_VEC
4628 || GET_CODE (pat
) == ADDR_DIFF_VEC
|| asm_noperands (pat
) >= 0)
4633 if (any_condjump_p (insn
)
4634 && ! cbranch_predicted_taken_p (insn
))
4636 last_condjump
= insn
;
4637 cycles_since_jump
= 0;
4640 cycles_since_jump
= INT_MAX
;
4642 else if (INSN_P (insn
))
4644 rtx load_insn
= find_load (insn
);
4645 enum attr_type type
= type_for_anomaly (insn
);
4646 int delay_needed
= 0;
4647 if (cycles_since_jump
< INT_MAX
)
4648 cycles_since_jump
++;
4650 if (load_insn
&& ENABLE_WA_SPECULATIVE_LOADS
)
4652 if (trapping_loads_p (load_insn
))
4655 else if (type
== TYPE_SYNC
&& ENABLE_WA_SPECULATIVE_SYNCS
)
4658 if (delay_needed
> cycles_since_jump
)
4662 rtx
*op
= recog_data
.operand
;
4664 delay_needed
-= cycles_since_jump
;
4666 extract_insn (last_condjump
);
4669 pat
= gen_cbranch_predicted_taken (op
[0], op
[1], op
[2],
4671 cycles_since_jump
= INT_MAX
;
4674 /* Do not adjust cycles_since_jump in this case, so that
4675 we'll increase the number of NOPs for a subsequent insn
4677 pat
= gen_cbranch_with_nops (op
[0], op
[1], op
[2], op
[3],
4678 GEN_INT (delay_needed
));
4679 PATTERN (last_condjump
) = pat
;
4680 INSN_CODE (last_condjump
) = recog (pat
, insn
, &num_clobbers
);
4684 /* Second pass: for predicted-true branches, see if anything at the
4685 branch destination needs extra nops. */
4686 if (! ENABLE_WA_SPECULATIVE_SYNCS
)
4689 for (insn
= get_insns (); insn
; insn
= NEXT_INSN (insn
))
4692 && any_condjump_p (insn
)
4693 && (INSN_CODE (insn
) == CODE_FOR_cbranch_predicted_taken
4694 || cbranch_predicted_taken_p (insn
)))
4696 rtx target
= JUMP_LABEL (insn
);
4698 cycles_since_jump
= 0;
4699 for (; target
&& cycles_since_jump
< 3; target
= NEXT_INSN (target
))
4703 if (NOTE_P (target
) || BARRIER_P (target
) || LABEL_P (target
))
4706 pat
= PATTERN (target
);
4707 if (GET_CODE (pat
) == USE
|| GET_CODE (pat
) == CLOBBER
4708 || GET_CODE (pat
) == ASM_INPUT
|| GET_CODE (pat
) == ADDR_VEC
4709 || GET_CODE (pat
) == ADDR_DIFF_VEC
|| asm_noperands (pat
) >= 0)
4712 if (INSN_P (target
))
4714 enum attr_type type
= type_for_anomaly (target
);
4715 int delay_needed
= 0;
4716 if (cycles_since_jump
< INT_MAX
)
4717 cycles_since_jump
++;
4719 if (type
== TYPE_SYNC
&& ENABLE_WA_SPECULATIVE_SYNCS
)
4722 if (delay_needed
> cycles_since_jump
)
4724 rtx prev
= prev_real_insn (label
);
4725 delay_needed
-= cycles_since_jump
;
4727 fprintf (dump_file
, "Adding %d nops after %d\n",
4728 delay_needed
, INSN_UID (label
));
4730 && INSN_CODE (prev
) == CODE_FOR_cbranch_with_nops
)
4737 "Reducing nops on insn %d.\n",
4740 x
= XVECEXP (x
, 0, 1);
4741 v
= INTVAL (XVECEXP (x
, 0, 0)) - delay_needed
;
4742 XVECEXP (x
, 0, 0) = GEN_INT (v
);
4744 while (delay_needed
-- > 0)
4745 emit_insn_after (gen_nop (), label
);
4753 if (bfin_flag_var_tracking
)
4755 timevar_push (TV_VAR_TRACKING
);
4756 variable_tracking_main ();
4757 reorder_var_tracking_notes ();
4758 timevar_pop (TV_VAR_TRACKING
);
4760 df_finish_pass (false);
4763 /* Handle interrupt_handler, exception_handler and nmi_handler function
4764 attributes; arguments as in struct attribute_spec.handler. */
4767 handle_int_attribute (tree
*node
, tree name
,
4768 tree args ATTRIBUTE_UNUSED
,
4769 int flags ATTRIBUTE_UNUSED
,
4773 if (TREE_CODE (x
) == FUNCTION_DECL
)
4776 if (TREE_CODE (x
) != FUNCTION_TYPE
)
4778 warning (OPT_Wattributes
, "%qs attribute only applies to functions",
4779 IDENTIFIER_POINTER (name
));
4780 *no_add_attrs
= true;
4782 else if (funkind (x
) != SUBROUTINE
)
4783 error ("multiple function type attributes specified");
4788 /* Return 0 if the attributes for two types are incompatible, 1 if they
4789 are compatible, and 2 if they are nearly compatible (which causes a
4790 warning to be generated). */
4793 bfin_comp_type_attributes (const_tree type1
, const_tree type2
)
4795 e_funkind kind1
, kind2
;
4797 if (TREE_CODE (type1
) != FUNCTION_TYPE
)
4800 kind1
= funkind (type1
);
4801 kind2
= funkind (type2
);
4806 /* Check for mismatched modifiers */
4807 if (!lookup_attribute ("nesting", TYPE_ATTRIBUTES (type1
))
4808 != !lookup_attribute ("nesting", TYPE_ATTRIBUTES (type2
)))
4811 if (!lookup_attribute ("saveall", TYPE_ATTRIBUTES (type1
))
4812 != !lookup_attribute ("saveall", TYPE_ATTRIBUTES (type2
)))
4815 if (!lookup_attribute ("kspisusp", TYPE_ATTRIBUTES (type1
))
4816 != !lookup_attribute ("kspisusp", TYPE_ATTRIBUTES (type2
)))
4819 if (!lookup_attribute ("longcall", TYPE_ATTRIBUTES (type1
))
4820 != !lookup_attribute ("longcall", TYPE_ATTRIBUTES (type2
)))
4826 /* Handle a "longcall" or "shortcall" attribute; arguments as in
4827 struct attribute_spec.handler. */
4830 bfin_handle_longcall_attribute (tree
*node
, tree name
,
4831 tree args ATTRIBUTE_UNUSED
,
4832 int flags ATTRIBUTE_UNUSED
,
4835 if (TREE_CODE (*node
) != FUNCTION_TYPE
4836 && TREE_CODE (*node
) != FIELD_DECL
4837 && TREE_CODE (*node
) != TYPE_DECL
)
4839 warning (OPT_Wattributes
, "`%s' attribute only applies to functions",
4840 IDENTIFIER_POINTER (name
));
4841 *no_add_attrs
= true;
4844 if ((strcmp (IDENTIFIER_POINTER (name
), "longcall") == 0
4845 && lookup_attribute ("shortcall", TYPE_ATTRIBUTES (*node
)))
4846 || (strcmp (IDENTIFIER_POINTER (name
), "shortcall") == 0
4847 && lookup_attribute ("longcall", TYPE_ATTRIBUTES (*node
))))
4849 warning (OPT_Wattributes
,
4850 "can't apply both longcall and shortcall attributes to the same function");
4851 *no_add_attrs
= true;
4857 /* Handle a "l1_text" attribute; arguments as in
4858 struct attribute_spec.handler. */
4861 bfin_handle_l1_text_attribute (tree
*node
, tree name
, tree
ARG_UNUSED (args
),
4862 int ARG_UNUSED (flags
), bool *no_add_attrs
)
4866 if (TREE_CODE (decl
) != FUNCTION_DECL
)
4868 error ("`%s' attribute only applies to functions",
4869 IDENTIFIER_POINTER (name
));
4870 *no_add_attrs
= true;
4873 /* The decl may have already been given a section attribute
4874 from a previous declaration. Ensure they match. */
4875 else if (DECL_SECTION_NAME (decl
) != NULL_TREE
4876 && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl
)),
4879 error ("section of %q+D conflicts with previous declaration",
4881 *no_add_attrs
= true;
4884 DECL_SECTION_NAME (decl
) = build_string (9, ".l1.text");
4889 /* Handle a "l1_data", "l1_data_A" or "l1_data_B" attribute;
4890 arguments as in struct attribute_spec.handler. */
4893 bfin_handle_l1_data_attribute (tree
*node
, tree name
, tree
ARG_UNUSED (args
),
4894 int ARG_UNUSED (flags
), bool *no_add_attrs
)
4898 if (TREE_CODE (decl
) != VAR_DECL
)
4900 error ("`%s' attribute only applies to variables",
4901 IDENTIFIER_POINTER (name
));
4902 *no_add_attrs
= true;
4904 else if (current_function_decl
!= NULL_TREE
4905 && !TREE_STATIC (decl
))
4907 error ("`%s' attribute cannot be specified for local variables",
4908 IDENTIFIER_POINTER (name
));
4909 *no_add_attrs
= true;
4913 const char *section_name
;
4915 if (strcmp (IDENTIFIER_POINTER (name
), "l1_data") == 0)
4916 section_name
= ".l1.data";
4917 else if (strcmp (IDENTIFIER_POINTER (name
), "l1_data_A") == 0)
4918 section_name
= ".l1.data.A";
4919 else if (strcmp (IDENTIFIER_POINTER (name
), "l1_data_B") == 0)
4920 section_name
= ".l1.data.B";
4924 /* The decl may have already been given a section attribute
4925 from a previous declaration. Ensure they match. */
4926 if (DECL_SECTION_NAME (decl
) != NULL_TREE
4927 && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl
)),
4930 error ("section of %q+D conflicts with previous declaration",
4932 *no_add_attrs
= true;
4935 DECL_SECTION_NAME (decl
)
4936 = build_string (strlen (section_name
) + 1, section_name
);
4942 /* Table of valid machine attributes. */
4943 const struct attribute_spec bfin_attribute_table
[] =
4945 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
4946 { "interrupt_handler", 0, 0, false, true, true, handle_int_attribute
},
4947 { "exception_handler", 0, 0, false, true, true, handle_int_attribute
},
4948 { "nmi_handler", 0, 0, false, true, true, handle_int_attribute
},
4949 { "nesting", 0, 0, false, true, true, NULL
},
4950 { "kspisusp", 0, 0, false, true, true, NULL
},
4951 { "saveall", 0, 0, false, true, true, NULL
},
4952 { "longcall", 0, 0, false, true, true, bfin_handle_longcall_attribute
},
4953 { "shortcall", 0, 0, false, true, true, bfin_handle_longcall_attribute
},
4954 { "l1_text", 0, 0, true, false, false, bfin_handle_l1_text_attribute
},
4955 { "l1_data", 0, 0, true, false, false, bfin_handle_l1_data_attribute
},
4956 { "l1_data_A", 0, 0, true, false, false, bfin_handle_l1_data_attribute
},
4957 { "l1_data_B", 0, 0, true, false, false, bfin_handle_l1_data_attribute
},
4958 { NULL
, 0, 0, false, false, false, NULL
}
4961 /* Implementation of TARGET_ASM_INTEGER. When using FD-PIC, we need to
4962 tell the assembler to generate pointers to function descriptors in
4966 bfin_assemble_integer (rtx value
, unsigned int size
, int aligned_p
)
4968 if (TARGET_FDPIC
&& size
== UNITS_PER_WORD
)
4970 if (GET_CODE (value
) == SYMBOL_REF
4971 && SYMBOL_REF_FUNCTION_P (value
))
4973 fputs ("\t.picptr\tfuncdesc(", asm_out_file
);
4974 output_addr_const (asm_out_file
, value
);
4975 fputs (")\n", asm_out_file
);
4980 /* We've set the unaligned SI op to NULL, so we always have to
4981 handle the unaligned case here. */
4982 assemble_integer_with_op ("\t.4byte\t", value
);
4986 return default_assemble_integer (value
, size
, aligned_p
);
4989 /* Output the assembler code for a thunk function. THUNK_DECL is the
4990 declaration for the thunk function itself, FUNCTION is the decl for
4991 the target function. DELTA is an immediate constant offset to be
4992 added to THIS. If VCALL_OFFSET is nonzero, the word at
4993 *(*this + vcall_offset) should be added to THIS. */
4996 bfin_output_mi_thunk (FILE *file ATTRIBUTE_UNUSED
,
4997 tree thunk ATTRIBUTE_UNUSED
, HOST_WIDE_INT delta
,
4998 HOST_WIDE_INT vcall_offset
, tree function
)
5001 /* The this parameter is passed as the first argument. */
5002 rtx
this = gen_rtx_REG (Pmode
, REG_R0
);
5004 /* Adjust the this parameter by a fixed constant. */
5008 if (delta
>= -64 && delta
<= 63)
5010 xops
[0] = GEN_INT (delta
);
5011 output_asm_insn ("%1 += %0;", xops
);
5013 else if (delta
>= -128 && delta
< -64)
5015 xops
[0] = GEN_INT (delta
+ 64);
5016 output_asm_insn ("%1 += -64; %1 += %0;", xops
);
5018 else if (delta
> 63 && delta
<= 126)
5020 xops
[0] = GEN_INT (delta
- 63);
5021 output_asm_insn ("%1 += 63; %1 += %0;", xops
);
5025 xops
[0] = GEN_INT (delta
);
5026 output_asm_insn ("r3.l = %h0; r3.h = %d0; %1 = %1 + r3;", xops
);
5030 /* Adjust the this parameter by a value stored in the vtable. */
5033 rtx p2tmp
= gen_rtx_REG (Pmode
, REG_P2
);
5034 rtx tmp
= gen_rtx_REG (Pmode
, REG_R3
);
5038 output_asm_insn ("%2 = r0; %2 = [%2];", xops
);
5040 /* Adjust the this parameter. */
5041 xops
[0] = gen_rtx_MEM (Pmode
, plus_constant (p2tmp
, vcall_offset
));
5042 if (!memory_operand (xops
[0], Pmode
))
5044 rtx tmp2
= gen_rtx_REG (Pmode
, REG_P1
);
5045 xops
[0] = GEN_INT (vcall_offset
);
5047 output_asm_insn ("%h1 = %h0; %d1 = %d0; %2 = %2 + %1", xops
);
5048 xops
[0] = gen_rtx_MEM (Pmode
, p2tmp
);
5051 output_asm_insn ("%1 = %0; %2 = %2 + %1;", xops
);
5054 xops
[0] = XEXP (DECL_RTL (function
), 0);
5055 if (1 || !flag_pic
|| (*targetm
.binds_local_p
) (function
))
5056 output_asm_insn ("jump.l\t%P0", xops
);
5059 /* Codes for all the Blackfin builtins. */
5065 BFIN_BUILTIN_COMPOSE_2X16
,
5066 BFIN_BUILTIN_EXTRACTLO
,
5067 BFIN_BUILTIN_EXTRACTHI
,
5069 BFIN_BUILTIN_SSADD_2X16
,
5070 BFIN_BUILTIN_SSSUB_2X16
,
5071 BFIN_BUILTIN_SSADDSUB_2X16
,
5072 BFIN_BUILTIN_SSSUBADD_2X16
,
5073 BFIN_BUILTIN_MULT_2X16
,
5074 BFIN_BUILTIN_MULTR_2X16
,
5075 BFIN_BUILTIN_NEG_2X16
,
5076 BFIN_BUILTIN_ABS_2X16
,
5077 BFIN_BUILTIN_MIN_2X16
,
5078 BFIN_BUILTIN_MAX_2X16
,
5080 BFIN_BUILTIN_SSADD_1X16
,
5081 BFIN_BUILTIN_SSSUB_1X16
,
5082 BFIN_BUILTIN_MULT_1X16
,
5083 BFIN_BUILTIN_MULTR_1X16
,
5084 BFIN_BUILTIN_NORM_1X16
,
5085 BFIN_BUILTIN_NEG_1X16
,
5086 BFIN_BUILTIN_ABS_1X16
,
5087 BFIN_BUILTIN_MIN_1X16
,
5088 BFIN_BUILTIN_MAX_1X16
,
5090 BFIN_BUILTIN_SUM_2X16
,
5091 BFIN_BUILTIN_DIFFHL_2X16
,
5092 BFIN_BUILTIN_DIFFLH_2X16
,
5094 BFIN_BUILTIN_SSADD_1X32
,
5095 BFIN_BUILTIN_SSSUB_1X32
,
5096 BFIN_BUILTIN_NORM_1X32
,
5097 BFIN_BUILTIN_ROUND_1X32
,
5098 BFIN_BUILTIN_NEG_1X32
,
5099 BFIN_BUILTIN_ABS_1X32
,
5100 BFIN_BUILTIN_MIN_1X32
,
5101 BFIN_BUILTIN_MAX_1X32
,
5102 BFIN_BUILTIN_MULT_1X32
,
5103 BFIN_BUILTIN_MULT_1X32X32
,
5104 BFIN_BUILTIN_MULT_1X32X32NS
,
5106 BFIN_BUILTIN_MULHISILL
,
5107 BFIN_BUILTIN_MULHISILH
,
5108 BFIN_BUILTIN_MULHISIHL
,
5109 BFIN_BUILTIN_MULHISIHH
,
5111 BFIN_BUILTIN_LSHIFT_1X16
,
5112 BFIN_BUILTIN_LSHIFT_2X16
,
5113 BFIN_BUILTIN_SSASHIFT_1X16
,
5114 BFIN_BUILTIN_SSASHIFT_2X16
,
5115 BFIN_BUILTIN_SSASHIFT_1X32
,
5117 BFIN_BUILTIN_CPLX_MUL_16
,
5118 BFIN_BUILTIN_CPLX_MAC_16
,
5119 BFIN_BUILTIN_CPLX_MSU_16
,
5121 BFIN_BUILTIN_CPLX_MUL_16_S40
,
5122 BFIN_BUILTIN_CPLX_MAC_16_S40
,
5123 BFIN_BUILTIN_CPLX_MSU_16_S40
,
5125 BFIN_BUILTIN_CPLX_SQU
,
5130 #define def_builtin(NAME, TYPE, CODE) \
5132 add_builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD, \
5136 /* Set up all builtin functions for this target. */
5138 bfin_init_builtins (void)
5140 tree V2HI_type_node
= build_vector_type_for_mode (intHI_type_node
, V2HImode
);
5141 tree void_ftype_void
5142 = build_function_type (void_type_node
, void_list_node
);
5143 tree short_ftype_short
5144 = build_function_type_list (short_integer_type_node
, short_integer_type_node
,
5146 tree short_ftype_int_int
5147 = build_function_type_list (short_integer_type_node
, integer_type_node
,
5148 integer_type_node
, NULL_TREE
);
5149 tree int_ftype_int_int
5150 = build_function_type_list (integer_type_node
, integer_type_node
,
5151 integer_type_node
, NULL_TREE
);
5153 = build_function_type_list (integer_type_node
, integer_type_node
,
5155 tree short_ftype_int
5156 = build_function_type_list (short_integer_type_node
, integer_type_node
,
5158 tree int_ftype_v2hi_v2hi
5159 = build_function_type_list (integer_type_node
, V2HI_type_node
,
5160 V2HI_type_node
, NULL_TREE
);
5161 tree v2hi_ftype_v2hi_v2hi
5162 = build_function_type_list (V2HI_type_node
, V2HI_type_node
,
5163 V2HI_type_node
, NULL_TREE
);
5164 tree v2hi_ftype_v2hi_v2hi_v2hi
5165 = build_function_type_list (V2HI_type_node
, V2HI_type_node
,
5166 V2HI_type_node
, V2HI_type_node
, NULL_TREE
);
5167 tree v2hi_ftype_int_int
5168 = build_function_type_list (V2HI_type_node
, integer_type_node
,
5169 integer_type_node
, NULL_TREE
);
5170 tree v2hi_ftype_v2hi_int
5171 = build_function_type_list (V2HI_type_node
, V2HI_type_node
,
5172 integer_type_node
, NULL_TREE
);
5173 tree int_ftype_short_short
5174 = build_function_type_list (integer_type_node
, short_integer_type_node
,
5175 short_integer_type_node
, NULL_TREE
);
5176 tree v2hi_ftype_v2hi
5177 = build_function_type_list (V2HI_type_node
, V2HI_type_node
, NULL_TREE
);
5178 tree short_ftype_v2hi
5179 = build_function_type_list (short_integer_type_node
, V2HI_type_node
,
5182 /* Add the remaining MMX insns with somewhat more complicated types. */
5183 def_builtin ("__builtin_bfin_csync", void_ftype_void
, BFIN_BUILTIN_CSYNC
);
5184 def_builtin ("__builtin_bfin_ssync", void_ftype_void
, BFIN_BUILTIN_SSYNC
);
5186 def_builtin ("__builtin_bfin_ones", short_ftype_int
, BFIN_BUILTIN_ONES
);
5188 def_builtin ("__builtin_bfin_compose_2x16", v2hi_ftype_int_int
,
5189 BFIN_BUILTIN_COMPOSE_2X16
);
5190 def_builtin ("__builtin_bfin_extract_hi", short_ftype_v2hi
,
5191 BFIN_BUILTIN_EXTRACTHI
);
5192 def_builtin ("__builtin_bfin_extract_lo", short_ftype_v2hi
,
5193 BFIN_BUILTIN_EXTRACTLO
);
5195 def_builtin ("__builtin_bfin_min_fr2x16", v2hi_ftype_v2hi_v2hi
,
5196 BFIN_BUILTIN_MIN_2X16
);
5197 def_builtin ("__builtin_bfin_max_fr2x16", v2hi_ftype_v2hi_v2hi
,
5198 BFIN_BUILTIN_MAX_2X16
);
5200 def_builtin ("__builtin_bfin_add_fr2x16", v2hi_ftype_v2hi_v2hi
,
5201 BFIN_BUILTIN_SSADD_2X16
);
5202 def_builtin ("__builtin_bfin_sub_fr2x16", v2hi_ftype_v2hi_v2hi
,
5203 BFIN_BUILTIN_SSSUB_2X16
);
5204 def_builtin ("__builtin_bfin_dspaddsubsat", v2hi_ftype_v2hi_v2hi
,
5205 BFIN_BUILTIN_SSADDSUB_2X16
);
5206 def_builtin ("__builtin_bfin_dspsubaddsat", v2hi_ftype_v2hi_v2hi
,
5207 BFIN_BUILTIN_SSSUBADD_2X16
);
5208 def_builtin ("__builtin_bfin_mult_fr2x16", v2hi_ftype_v2hi_v2hi
,
5209 BFIN_BUILTIN_MULT_2X16
);
5210 def_builtin ("__builtin_bfin_multr_fr2x16", v2hi_ftype_v2hi_v2hi
,
5211 BFIN_BUILTIN_MULTR_2X16
);
5212 def_builtin ("__builtin_bfin_negate_fr2x16", v2hi_ftype_v2hi
,
5213 BFIN_BUILTIN_NEG_2X16
);
5214 def_builtin ("__builtin_bfin_abs_fr2x16", v2hi_ftype_v2hi
,
5215 BFIN_BUILTIN_ABS_2X16
);
5217 def_builtin ("__builtin_bfin_min_fr1x16", short_ftype_int_int
,
5218 BFIN_BUILTIN_MIN_1X16
);
5219 def_builtin ("__builtin_bfin_max_fr1x16", short_ftype_int_int
,
5220 BFIN_BUILTIN_MAX_1X16
);
5222 def_builtin ("__builtin_bfin_add_fr1x16", short_ftype_int_int
,
5223 BFIN_BUILTIN_SSADD_1X16
);
5224 def_builtin ("__builtin_bfin_sub_fr1x16", short_ftype_int_int
,
5225 BFIN_BUILTIN_SSSUB_1X16
);
5226 def_builtin ("__builtin_bfin_mult_fr1x16", short_ftype_int_int
,
5227 BFIN_BUILTIN_MULT_1X16
);
5228 def_builtin ("__builtin_bfin_multr_fr1x16", short_ftype_int_int
,
5229 BFIN_BUILTIN_MULTR_1X16
);
5230 def_builtin ("__builtin_bfin_negate_fr1x16", short_ftype_short
,
5231 BFIN_BUILTIN_NEG_1X16
);
5232 def_builtin ("__builtin_bfin_abs_fr1x16", short_ftype_short
,
5233 BFIN_BUILTIN_ABS_1X16
);
5234 def_builtin ("__builtin_bfin_norm_fr1x16", short_ftype_int
,
5235 BFIN_BUILTIN_NORM_1X16
);
5237 def_builtin ("__builtin_bfin_sum_fr2x16", short_ftype_v2hi
,
5238 BFIN_BUILTIN_SUM_2X16
);
5239 def_builtin ("__builtin_bfin_diff_hl_fr2x16", short_ftype_v2hi
,
5240 BFIN_BUILTIN_DIFFHL_2X16
);
5241 def_builtin ("__builtin_bfin_diff_lh_fr2x16", short_ftype_v2hi
,
5242 BFIN_BUILTIN_DIFFLH_2X16
);
5244 def_builtin ("__builtin_bfin_mulhisill", int_ftype_v2hi_v2hi
,
5245 BFIN_BUILTIN_MULHISILL
);
5246 def_builtin ("__builtin_bfin_mulhisihl", int_ftype_v2hi_v2hi
,
5247 BFIN_BUILTIN_MULHISIHL
);
5248 def_builtin ("__builtin_bfin_mulhisilh", int_ftype_v2hi_v2hi
,
5249 BFIN_BUILTIN_MULHISILH
);
5250 def_builtin ("__builtin_bfin_mulhisihh", int_ftype_v2hi_v2hi
,
5251 BFIN_BUILTIN_MULHISIHH
);
5253 def_builtin ("__builtin_bfin_min_fr1x32", int_ftype_int_int
,
5254 BFIN_BUILTIN_MIN_1X32
);
5255 def_builtin ("__builtin_bfin_max_fr1x32", int_ftype_int_int
,
5256 BFIN_BUILTIN_MAX_1X32
);
5258 def_builtin ("__builtin_bfin_add_fr1x32", int_ftype_int_int
,
5259 BFIN_BUILTIN_SSADD_1X32
);
5260 def_builtin ("__builtin_bfin_sub_fr1x32", int_ftype_int_int
,
5261 BFIN_BUILTIN_SSSUB_1X32
);
5262 def_builtin ("__builtin_bfin_negate_fr1x32", int_ftype_int
,
5263 BFIN_BUILTIN_NEG_1X32
);
5264 def_builtin ("__builtin_bfin_abs_fr1x32", int_ftype_int
,
5265 BFIN_BUILTIN_ABS_1X32
);
5266 def_builtin ("__builtin_bfin_norm_fr1x32", short_ftype_int
,
5267 BFIN_BUILTIN_NORM_1X32
);
5268 def_builtin ("__builtin_bfin_round_fr1x32", short_ftype_int
,
5269 BFIN_BUILTIN_ROUND_1X32
);
5270 def_builtin ("__builtin_bfin_mult_fr1x32", int_ftype_short_short
,
5271 BFIN_BUILTIN_MULT_1X32
);
5272 def_builtin ("__builtin_bfin_mult_fr1x32x32", int_ftype_int_int
,
5273 BFIN_BUILTIN_MULT_1X32X32
);
5274 def_builtin ("__builtin_bfin_mult_fr1x32x32NS", int_ftype_int_int
,
5275 BFIN_BUILTIN_MULT_1X32X32NS
);
5278 def_builtin ("__builtin_bfin_shl_fr1x16", short_ftype_int_int
,
5279 BFIN_BUILTIN_SSASHIFT_1X16
);
5280 def_builtin ("__builtin_bfin_shl_fr2x16", v2hi_ftype_v2hi_int
,
5281 BFIN_BUILTIN_SSASHIFT_2X16
);
5282 def_builtin ("__builtin_bfin_lshl_fr1x16", short_ftype_int_int
,
5283 BFIN_BUILTIN_LSHIFT_1X16
);
5284 def_builtin ("__builtin_bfin_lshl_fr2x16", v2hi_ftype_v2hi_int
,
5285 BFIN_BUILTIN_LSHIFT_2X16
);
5286 def_builtin ("__builtin_bfin_shl_fr1x32", int_ftype_int_int
,
5287 BFIN_BUILTIN_SSASHIFT_1X32
);
5289 /* Complex numbers. */
5290 def_builtin ("__builtin_bfin_cmplx_add", v2hi_ftype_v2hi_v2hi
,
5291 BFIN_BUILTIN_SSADD_2X16
);
5292 def_builtin ("__builtin_bfin_cmplx_sub", v2hi_ftype_v2hi_v2hi
,
5293 BFIN_BUILTIN_SSSUB_2X16
);
5294 def_builtin ("__builtin_bfin_cmplx_mul", v2hi_ftype_v2hi_v2hi
,
5295 BFIN_BUILTIN_CPLX_MUL_16
);
5296 def_builtin ("__builtin_bfin_cmplx_mac", v2hi_ftype_v2hi_v2hi_v2hi
,
5297 BFIN_BUILTIN_CPLX_MAC_16
);
5298 def_builtin ("__builtin_bfin_cmplx_msu", v2hi_ftype_v2hi_v2hi_v2hi
,
5299 BFIN_BUILTIN_CPLX_MSU_16
);
5300 def_builtin ("__builtin_bfin_cmplx_mul_s40", v2hi_ftype_v2hi_v2hi
,
5301 BFIN_BUILTIN_CPLX_MUL_16_S40
);
5302 def_builtin ("__builtin_bfin_cmplx_mac_s40", v2hi_ftype_v2hi_v2hi_v2hi
,
5303 BFIN_BUILTIN_CPLX_MAC_16_S40
);
5304 def_builtin ("__builtin_bfin_cmplx_msu_s40", v2hi_ftype_v2hi_v2hi_v2hi
,
5305 BFIN_BUILTIN_CPLX_MSU_16_S40
);
5306 def_builtin ("__builtin_bfin_csqu_fr16", v2hi_ftype_v2hi
,
5307 BFIN_BUILTIN_CPLX_SQU
);
5311 struct builtin_description
5313 const enum insn_code icode
;
5314 const char *const name
;
5315 const enum bfin_builtins code
;
5319 static const struct builtin_description bdesc_2arg
[] =
5321 { CODE_FOR_composev2hi
, "__builtin_bfin_compose_2x16", BFIN_BUILTIN_COMPOSE_2X16
, -1 },
5323 { CODE_FOR_ssashiftv2hi3
, "__builtin_bfin_shl_fr2x16", BFIN_BUILTIN_SSASHIFT_2X16
, -1 },
5324 { CODE_FOR_ssashifthi3
, "__builtin_bfin_shl_fr1x16", BFIN_BUILTIN_SSASHIFT_1X16
, -1 },
5325 { CODE_FOR_lshiftv2hi3
, "__builtin_bfin_lshl_fr2x16", BFIN_BUILTIN_LSHIFT_2X16
, -1 },
5326 { CODE_FOR_lshifthi3
, "__builtin_bfin_lshl_fr1x16", BFIN_BUILTIN_LSHIFT_1X16
, -1 },
5327 { CODE_FOR_ssashiftsi3
, "__builtin_bfin_shl_fr1x32", BFIN_BUILTIN_SSASHIFT_1X32
, -1 },
5329 { CODE_FOR_sminhi3
, "__builtin_bfin_min_fr1x16", BFIN_BUILTIN_MIN_1X16
, -1 },
5330 { CODE_FOR_smaxhi3
, "__builtin_bfin_max_fr1x16", BFIN_BUILTIN_MAX_1X16
, -1 },
5331 { CODE_FOR_ssaddhi3
, "__builtin_bfin_add_fr1x16", BFIN_BUILTIN_SSADD_1X16
, -1 },
5332 { CODE_FOR_sssubhi3
, "__builtin_bfin_sub_fr1x16", BFIN_BUILTIN_SSSUB_1X16
, -1 },
5334 { CODE_FOR_sminsi3
, "__builtin_bfin_min_fr1x32", BFIN_BUILTIN_MIN_1X32
, -1 },
5335 { CODE_FOR_smaxsi3
, "__builtin_bfin_max_fr1x32", BFIN_BUILTIN_MAX_1X32
, -1 },
5336 { CODE_FOR_ssaddsi3
, "__builtin_bfin_add_fr1x32", BFIN_BUILTIN_SSADD_1X32
, -1 },
5337 { CODE_FOR_sssubsi3
, "__builtin_bfin_sub_fr1x32", BFIN_BUILTIN_SSSUB_1X32
, -1 },
5339 { CODE_FOR_sminv2hi3
, "__builtin_bfin_min_fr2x16", BFIN_BUILTIN_MIN_2X16
, -1 },
5340 { CODE_FOR_smaxv2hi3
, "__builtin_bfin_max_fr2x16", BFIN_BUILTIN_MAX_2X16
, -1 },
5341 { CODE_FOR_ssaddv2hi3
, "__builtin_bfin_add_fr2x16", BFIN_BUILTIN_SSADD_2X16
, -1 },
5342 { CODE_FOR_sssubv2hi3
, "__builtin_bfin_sub_fr2x16", BFIN_BUILTIN_SSSUB_2X16
, -1 },
5343 { CODE_FOR_ssaddsubv2hi3
, "__builtin_bfin_dspaddsubsat", BFIN_BUILTIN_SSADDSUB_2X16
, -1 },
5344 { CODE_FOR_sssubaddv2hi3
, "__builtin_bfin_dspsubaddsat", BFIN_BUILTIN_SSSUBADD_2X16
, -1 },
5346 { CODE_FOR_flag_mulhisi
, "__builtin_bfin_mult_fr1x32", BFIN_BUILTIN_MULT_1X32
, MACFLAG_NONE
},
5347 { CODE_FOR_flag_mulhi
, "__builtin_bfin_mult_fr1x16", BFIN_BUILTIN_MULT_1X16
, MACFLAG_T
},
5348 { CODE_FOR_flag_mulhi
, "__builtin_bfin_multr_fr1x16", BFIN_BUILTIN_MULTR_1X16
, MACFLAG_NONE
},
5349 { CODE_FOR_flag_mulv2hi
, "__builtin_bfin_mult_fr2x16", BFIN_BUILTIN_MULT_2X16
, MACFLAG_T
},
5350 { CODE_FOR_flag_mulv2hi
, "__builtin_bfin_multr_fr2x16", BFIN_BUILTIN_MULTR_2X16
, MACFLAG_NONE
}
5353 static const struct builtin_description bdesc_1arg
[] =
5355 { CODE_FOR_ones
, "__builtin_bfin_ones", BFIN_BUILTIN_ONES
, 0 },
5357 { CODE_FOR_signbitshi2
, "__builtin_bfin_norm_fr1x16", BFIN_BUILTIN_NORM_1X16
, 0 },
5358 { CODE_FOR_ssneghi2
, "__builtin_bfin_negate_fr1x16", BFIN_BUILTIN_NEG_1X16
, 0 },
5359 { CODE_FOR_abshi2
, "__builtin_bfin_abs_fr1x16", BFIN_BUILTIN_ABS_1X16
, 0 },
5361 { CODE_FOR_signbitssi2
, "__builtin_bfin_norm_fr1x32", BFIN_BUILTIN_NORM_1X32
, 0 },
5362 { CODE_FOR_ssroundsi2
, "__builtin_bfin_round_fr1x32", BFIN_BUILTIN_ROUND_1X32
, 0 },
5363 { CODE_FOR_ssnegsi2
, "__builtin_bfin_negate_fr1x32", BFIN_BUILTIN_NEG_1X32
, 0 },
5364 { CODE_FOR_ssabssi2
, "__builtin_bfin_abs_fr1x32", BFIN_BUILTIN_ABS_1X32
, 0 },
5366 { CODE_FOR_movv2hi_hi_low
, "__builtin_bfin_extract_lo", BFIN_BUILTIN_EXTRACTLO
, 0 },
5367 { CODE_FOR_movv2hi_hi_high
, "__builtin_bfin_extract_hi", BFIN_BUILTIN_EXTRACTHI
, 0 },
5368 { CODE_FOR_ssnegv2hi2
, "__builtin_bfin_negate_fr2x16", BFIN_BUILTIN_NEG_2X16
, 0 },
5369 { CODE_FOR_ssabsv2hi2
, "__builtin_bfin_abs_fr2x16", BFIN_BUILTIN_ABS_2X16
, 0 }
5372 /* Errors in the source file can cause expand_expr to return const0_rtx
5373 where we expect a vector. To avoid crashing, use one of the vector
5374 clear instructions. */
5376 safe_vector_operand (rtx x
, enum machine_mode mode
)
5378 if (x
!= const0_rtx
)
5380 x
= gen_reg_rtx (SImode
);
5382 emit_insn (gen_movsi (x
, CONST0_RTX (SImode
)));
5383 return gen_lowpart (mode
, x
);
5386 /* Subroutine of bfin_expand_builtin to take care of binop insns. MACFLAG is -1
5387 if this is a normal binary op, or one of the MACFLAG_xxx constants. */
5390 bfin_expand_binop_builtin (enum insn_code icode
, tree exp
, rtx target
,
5394 tree arg0
= CALL_EXPR_ARG (exp
, 0);
5395 tree arg1
= CALL_EXPR_ARG (exp
, 1);
5396 rtx op0
= expand_expr (arg0
, NULL_RTX
, VOIDmode
, 0);
5397 rtx op1
= expand_expr (arg1
, NULL_RTX
, VOIDmode
, 0);
5398 enum machine_mode op0mode
= GET_MODE (op0
);
5399 enum machine_mode op1mode
= GET_MODE (op1
);
5400 enum machine_mode tmode
= insn_data
[icode
].operand
[0].mode
;
5401 enum machine_mode mode0
= insn_data
[icode
].operand
[1].mode
;
5402 enum machine_mode mode1
= insn_data
[icode
].operand
[2].mode
;
5404 if (VECTOR_MODE_P (mode0
))
5405 op0
= safe_vector_operand (op0
, mode0
);
5406 if (VECTOR_MODE_P (mode1
))
5407 op1
= safe_vector_operand (op1
, mode1
);
5410 || GET_MODE (target
) != tmode
5411 || ! (*insn_data
[icode
].operand
[0].predicate
) (target
, tmode
))
5412 target
= gen_reg_rtx (tmode
);
5414 if ((op0mode
== SImode
|| op0mode
== VOIDmode
) && mode0
== HImode
)
5417 op0
= gen_lowpart (HImode
, op0
);
5419 if ((op1mode
== SImode
|| op1mode
== VOIDmode
) && mode1
== HImode
)
5422 op1
= gen_lowpart (HImode
, op1
);
5424 /* In case the insn wants input operands in modes different from
5425 the result, abort. */
5426 gcc_assert ((op0mode
== mode0
|| op0mode
== VOIDmode
)
5427 && (op1mode
== mode1
|| op1mode
== VOIDmode
));
5429 if (! (*insn_data
[icode
].operand
[1].predicate
) (op0
, mode0
))
5430 op0
= copy_to_mode_reg (mode0
, op0
);
5431 if (! (*insn_data
[icode
].operand
[2].predicate
) (op1
, mode1
))
5432 op1
= copy_to_mode_reg (mode1
, op1
);
5435 pat
= GEN_FCN (icode
) (target
, op0
, op1
);
5437 pat
= GEN_FCN (icode
) (target
, op0
, op1
, GEN_INT (macflag
));
5445 /* Subroutine of bfin_expand_builtin to take care of unop insns. */
5448 bfin_expand_unop_builtin (enum insn_code icode
, tree exp
,
5452 tree arg0
= CALL_EXPR_ARG (exp
, 0);
5453 rtx op0
= expand_expr (arg0
, NULL_RTX
, VOIDmode
, 0);
5454 enum machine_mode op0mode
= GET_MODE (op0
);
5455 enum machine_mode tmode
= insn_data
[icode
].operand
[0].mode
;
5456 enum machine_mode mode0
= insn_data
[icode
].operand
[1].mode
;
5459 || GET_MODE (target
) != tmode
5460 || ! (*insn_data
[icode
].operand
[0].predicate
) (target
, tmode
))
5461 target
= gen_reg_rtx (tmode
);
5463 if (VECTOR_MODE_P (mode0
))
5464 op0
= safe_vector_operand (op0
, mode0
);
5466 if (op0mode
== SImode
&& mode0
== HImode
)
5469 op0
= gen_lowpart (HImode
, op0
);
5471 gcc_assert (op0mode
== mode0
|| op0mode
== VOIDmode
);
5473 if (! (*insn_data
[icode
].operand
[1].predicate
) (op0
, mode0
))
5474 op0
= copy_to_mode_reg (mode0
, op0
);
5476 pat
= GEN_FCN (icode
) (target
, op0
);
5483 /* Expand an expression EXP that calls a built-in function,
5484 with result going to TARGET if that's convenient
5485 (and in mode MODE if that's convenient).
5486 SUBTARGET may be used as the target for computing one of EXP's operands.
5487 IGNORE is nonzero if the value is to be ignored. */
5490 bfin_expand_builtin (tree exp
, rtx target ATTRIBUTE_UNUSED
,
5491 rtx subtarget ATTRIBUTE_UNUSED
,
5492 enum machine_mode mode ATTRIBUTE_UNUSED
,
5493 int ignore ATTRIBUTE_UNUSED
)
5496 enum insn_code icode
;
5497 const struct builtin_description
*d
;
5498 tree fndecl
= TREE_OPERAND (CALL_EXPR_FN (exp
), 0);
5499 unsigned int fcode
= DECL_FUNCTION_CODE (fndecl
);
5500 tree arg0
, arg1
, arg2
;
5501 rtx op0
, op1
, op2
, accvec
, pat
, tmp1
, tmp2
, a0reg
, a1reg
;
5502 enum machine_mode tmode
, mode0
;
5506 case BFIN_BUILTIN_CSYNC
:
5507 emit_insn (gen_csync ());
5509 case BFIN_BUILTIN_SSYNC
:
5510 emit_insn (gen_ssync ());
5513 case BFIN_BUILTIN_DIFFHL_2X16
:
5514 case BFIN_BUILTIN_DIFFLH_2X16
:
5515 case BFIN_BUILTIN_SUM_2X16
:
5516 arg0
= CALL_EXPR_ARG (exp
, 0);
5517 op0
= expand_expr (arg0
, NULL_RTX
, VOIDmode
, 0);
5518 icode
= (fcode
== BFIN_BUILTIN_DIFFHL_2X16
? CODE_FOR_subhilov2hi3
5519 : fcode
== BFIN_BUILTIN_DIFFLH_2X16
? CODE_FOR_sublohiv2hi3
5520 : CODE_FOR_ssaddhilov2hi3
);
5521 tmode
= insn_data
[icode
].operand
[0].mode
;
5522 mode0
= insn_data
[icode
].operand
[1].mode
;
5525 || GET_MODE (target
) != tmode
5526 || ! (*insn_data
[icode
].operand
[0].predicate
) (target
, tmode
))
5527 target
= gen_reg_rtx (tmode
);
5529 if (VECTOR_MODE_P (mode0
))
5530 op0
= safe_vector_operand (op0
, mode0
);
5532 if (! (*insn_data
[icode
].operand
[1].predicate
) (op0
, mode0
))
5533 op0
= copy_to_mode_reg (mode0
, op0
);
5535 pat
= GEN_FCN (icode
) (target
, op0
, op0
);
5541 case BFIN_BUILTIN_MULT_1X32X32
:
5542 case BFIN_BUILTIN_MULT_1X32X32NS
:
5543 arg0
= CALL_EXPR_ARG (exp
, 0);
5544 arg1
= CALL_EXPR_ARG (exp
, 1);
5545 op0
= expand_expr (arg0
, NULL_RTX
, VOIDmode
, 0);
5546 op1
= expand_expr (arg1
, NULL_RTX
, VOIDmode
, 0);
5548 || !register_operand (target
, SImode
))
5549 target
= gen_reg_rtx (SImode
);
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_expr (arg0
, NULL_RTX
, VOIDmode
, 0);
5601 op1
= expand_expr (arg1
, NULL_RTX
, VOIDmode
, 0);
5602 accvec
= gen_reg_rtx (V2PDImode
);
5605 || GET_MODE (target
) != V2HImode
5606 || ! (*insn_data
[icode
].operand
[0].predicate
) (target
, V2HImode
))
5607 target
= gen_reg_rtx (tmode
);
5608 if (! register_operand (op0
, GET_MODE (op0
)))
5609 op0
= copy_to_mode_reg (GET_MODE (op0
), op0
);
5610 if (! register_operand (op1
, GET_MODE (op1
)))
5611 op1
= copy_to_mode_reg (GET_MODE (op1
), op1
);
5613 if (fcode
== BFIN_BUILTIN_CPLX_MUL_16
)
5614 emit_insn (gen_flag_macinit1v2hi_parts (accvec
, op0
, op1
, const0_rtx
,
5615 const0_rtx
, const0_rtx
,
5616 const1_rtx
, GEN_INT (MACFLAG_W32
)));
5618 emit_insn (gen_flag_macinit1v2hi_parts (accvec
, op0
, op1
, const0_rtx
,
5619 const0_rtx
, const0_rtx
,
5620 const1_rtx
, GEN_INT (MACFLAG_NONE
)));
5621 emit_insn (gen_flag_macv2hi_parts (target
, op0
, op1
, const1_rtx
,
5622 const1_rtx
, const1_rtx
,
5623 const0_rtx
, accvec
, const1_rtx
, const0_rtx
,
5624 GEN_INT (MACFLAG_NONE
), accvec
));
5628 case BFIN_BUILTIN_CPLX_MAC_16
:
5629 case BFIN_BUILTIN_CPLX_MSU_16
:
5630 case BFIN_BUILTIN_CPLX_MAC_16_S40
:
5631 case BFIN_BUILTIN_CPLX_MSU_16_S40
:
5632 arg0
= CALL_EXPR_ARG (exp
, 0);
5633 arg1
= CALL_EXPR_ARG (exp
, 1);
5634 arg2
= CALL_EXPR_ARG (exp
, 2);
5635 op0
= expand_expr (arg0
, NULL_RTX
, VOIDmode
, 0);
5636 op1
= expand_expr (arg1
, NULL_RTX
, VOIDmode
, 0);
5637 op2
= expand_expr (arg2
, NULL_RTX
, VOIDmode
, 0);
5638 accvec
= gen_reg_rtx (V2PDImode
);
5641 || GET_MODE (target
) != V2HImode
5642 || ! (*insn_data
[icode
].operand
[0].predicate
) (target
, V2HImode
))
5643 target
= gen_reg_rtx (tmode
);
5644 if (! register_operand (op1
, GET_MODE (op1
)))
5645 op1
= copy_to_mode_reg (GET_MODE (op1
), op1
);
5646 if (! register_operand (op2
, GET_MODE (op2
)))
5647 op2
= copy_to_mode_reg (GET_MODE (op2
), op2
);
5649 tmp1
= gen_reg_rtx (SImode
);
5650 tmp2
= gen_reg_rtx (SImode
);
5651 emit_insn (gen_ashlsi3 (tmp1
, gen_lowpart (SImode
, op0
), GEN_INT (16)));
5652 emit_move_insn (tmp2
, gen_lowpart (SImode
, op0
));
5653 emit_insn (gen_movstricthi_1 (gen_lowpart (HImode
, tmp2
), const0_rtx
));
5654 emit_insn (gen_load_accumulator_pair (accvec
, tmp1
, tmp2
));
5655 if (fcode
== BFIN_BUILTIN_CPLX_MAC_16
5656 || fcode
== BFIN_BUILTIN_CPLX_MSU_16
)
5657 emit_insn (gen_flag_macv2hi_parts_acconly (accvec
, op1
, op2
, const0_rtx
,
5658 const0_rtx
, const0_rtx
,
5659 const1_rtx
, accvec
, const0_rtx
,
5661 GEN_INT (MACFLAG_W32
)));
5663 emit_insn (gen_flag_macv2hi_parts_acconly (accvec
, op1
, op2
, const0_rtx
,
5664 const0_rtx
, const0_rtx
,
5665 const1_rtx
, accvec
, const0_rtx
,
5667 GEN_INT (MACFLAG_NONE
)));
5668 if (fcode
== BFIN_BUILTIN_CPLX_MAC_16
5669 || fcode
== BFIN_BUILTIN_CPLX_MAC_16_S40
)
5679 emit_insn (gen_flag_macv2hi_parts (target
, op1
, op2
, const1_rtx
,
5680 const1_rtx
, const1_rtx
,
5681 const0_rtx
, accvec
, tmp1
, tmp2
,
5682 GEN_INT (MACFLAG_NONE
), accvec
));
5686 case BFIN_BUILTIN_CPLX_SQU
:
5687 arg0
= CALL_EXPR_ARG (exp
, 0);
5688 op0
= expand_expr (arg0
, NULL_RTX
, VOIDmode
, 0);
5689 accvec
= gen_reg_rtx (V2PDImode
);
5690 icode
= CODE_FOR_flag_mulv2hi
;
5691 tmp1
= gen_reg_rtx (V2HImode
);
5692 tmp2
= gen_reg_rtx (V2HImode
);
5695 || GET_MODE (target
) != V2HImode
5696 || ! (*insn_data
[icode
].operand
[0].predicate
) (target
, V2HImode
))
5697 target
= gen_reg_rtx (V2HImode
);
5698 if (! register_operand (op0
, GET_MODE (op0
)))
5699 op0
= copy_to_mode_reg (GET_MODE (op0
), op0
);
5701 emit_insn (gen_flag_mulv2hi (tmp1
, op0
, op0
, GEN_INT (MACFLAG_NONE
)));
5703 emit_insn (gen_flag_mulhi_parts (tmp2
, op0
, op0
, const0_rtx
,
5704 const0_rtx
, const1_rtx
,
5705 GEN_INT (MACFLAG_NONE
)));
5707 emit_insn (gen_ssaddhi3_parts (target
, tmp2
, tmp2
, const1_rtx
,
5708 const0_rtx
, const0_rtx
));
5710 emit_insn (gen_sssubhi3_parts (target
, tmp1
, tmp1
, const0_rtx
,
5711 const0_rtx
, const1_rtx
));
5719 for (i
= 0, d
= bdesc_2arg
; i
< ARRAY_SIZE (bdesc_2arg
); i
++, d
++)
5720 if (d
->code
== fcode
)
5721 return bfin_expand_binop_builtin (d
->icode
, exp
, target
,
5724 for (i
= 0, d
= bdesc_1arg
; i
< ARRAY_SIZE (bdesc_1arg
); i
++, d
++)
5725 if (d
->code
== fcode
)
5726 return bfin_expand_unop_builtin (d
->icode
, exp
, target
);
5731 #undef TARGET_INIT_BUILTINS
5732 #define TARGET_INIT_BUILTINS bfin_init_builtins
5734 #undef TARGET_EXPAND_BUILTIN
5735 #define TARGET_EXPAND_BUILTIN bfin_expand_builtin
5737 #undef TARGET_ASM_GLOBALIZE_LABEL
5738 #define TARGET_ASM_GLOBALIZE_LABEL bfin_globalize_label
5740 #undef TARGET_ASM_FILE_START
5741 #define TARGET_ASM_FILE_START output_file_start
5743 #undef TARGET_ATTRIBUTE_TABLE
5744 #define TARGET_ATTRIBUTE_TABLE bfin_attribute_table
5746 #undef TARGET_COMP_TYPE_ATTRIBUTES
5747 #define TARGET_COMP_TYPE_ATTRIBUTES bfin_comp_type_attributes
5749 #undef TARGET_RTX_COSTS
5750 #define TARGET_RTX_COSTS bfin_rtx_costs
5752 #undef TARGET_ADDRESS_COST
5753 #define TARGET_ADDRESS_COST bfin_address_cost
5755 #undef TARGET_ASM_INTEGER
5756 #define TARGET_ASM_INTEGER bfin_assemble_integer
5758 #undef TARGET_MACHINE_DEPENDENT_REORG
5759 #define TARGET_MACHINE_DEPENDENT_REORG bfin_reorg
5761 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
5762 #define TARGET_FUNCTION_OK_FOR_SIBCALL bfin_function_ok_for_sibcall
5764 #undef TARGET_ASM_OUTPUT_MI_THUNK
5765 #define TARGET_ASM_OUTPUT_MI_THUNK bfin_output_mi_thunk
5766 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
5767 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true
5769 #undef TARGET_SCHED_ADJUST_COST
5770 #define TARGET_SCHED_ADJUST_COST bfin_adjust_cost
5772 #undef TARGET_SCHED_ISSUE_RATE
5773 #define TARGET_SCHED_ISSUE_RATE bfin_issue_rate
5775 #undef TARGET_PROMOTE_PROTOTYPES
5776 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
5777 #undef TARGET_PROMOTE_FUNCTION_ARGS
5778 #define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_const_tree_true
5779 #undef TARGET_PROMOTE_FUNCTION_RETURN
5780 #define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_const_tree_true
5782 #undef TARGET_ARG_PARTIAL_BYTES
5783 #define TARGET_ARG_PARTIAL_BYTES bfin_arg_partial_bytes
5785 #undef TARGET_PASS_BY_REFERENCE
5786 #define TARGET_PASS_BY_REFERENCE bfin_pass_by_reference
5788 #undef TARGET_SETUP_INCOMING_VARARGS
5789 #define TARGET_SETUP_INCOMING_VARARGS setup_incoming_varargs
5791 #undef TARGET_STRUCT_VALUE_RTX
5792 #define TARGET_STRUCT_VALUE_RTX bfin_struct_value_rtx
5794 #undef TARGET_VECTOR_MODE_SUPPORTED_P
5795 #define TARGET_VECTOR_MODE_SUPPORTED_P bfin_vector_mode_supported_p
5797 #undef TARGET_HANDLE_OPTION
5798 #define TARGET_HANDLE_OPTION bfin_handle_option
5800 #undef TARGET_DEFAULT_TARGET_FLAGS
5801 #define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
5803 #undef TARGET_SECONDARY_RELOAD
5804 #define TARGET_SECONDARY_RELOAD bfin_secondary_reload
5806 #undef TARGET_DELEGITIMIZE_ADDRESS
5807 #define TARGET_DELEGITIMIZE_ADDRESS bfin_delegitimize_address
5809 #undef TARGET_CANNOT_FORCE_CONST_MEM
5810 #define TARGET_CANNOT_FORCE_CONST_MEM bfin_cannot_force_const_mem
5812 struct gcc_target targetm
= TARGET_INITIALIZER
;