1 /* The Blackfin code generation auxiliary output file.
2 Copyright (C) 2005, 2006, 2007, 2008 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 {"bf523", BFIN_CPU_BF523
, 0x0000,
120 WA_SPECULATIVE_LOADS
},
122 {"bf524", BFIN_CPU_BF524
, 0x0000,
123 WA_SPECULATIVE_LOADS
},
125 {"bf525", BFIN_CPU_BF525
, 0x0000,
126 WA_SPECULATIVE_LOADS
},
128 {"bf526", BFIN_CPU_BF526
, 0x0000,
129 WA_SPECULATIVE_LOADS
},
131 {"bf527", BFIN_CPU_BF527
, 0x0000,
132 WA_SPECULATIVE_LOADS
},
134 {"bf531", BFIN_CPU_BF531
, 0x0005,
135 WA_SPECULATIVE_LOADS
},
136 {"bf531", BFIN_CPU_BF531
, 0x0004,
137 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
},
138 {"bf531", BFIN_CPU_BF531
, 0x0003,
139 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
},
141 {"bf532", BFIN_CPU_BF532
, 0x0005,
142 WA_SPECULATIVE_LOADS
},
143 {"bf532", BFIN_CPU_BF532
, 0x0004,
144 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
},
145 {"bf532", BFIN_CPU_BF532
, 0x0003,
146 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
},
148 {"bf533", BFIN_CPU_BF533
, 0x0005,
149 WA_SPECULATIVE_LOADS
},
150 {"bf533", BFIN_CPU_BF533
, 0x0004,
151 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
},
152 {"bf533", BFIN_CPU_BF533
, 0x0003,
153 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
},
155 {"bf534", BFIN_CPU_BF534
, 0x0003,
156 WA_SPECULATIVE_LOADS
},
157 {"bf534", BFIN_CPU_BF534
, 0x0002,
158 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
},
159 {"bf534", BFIN_CPU_BF534
, 0x0001,
160 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
},
162 {"bf536", BFIN_CPU_BF536
, 0x0003,
163 WA_SPECULATIVE_LOADS
},
164 {"bf536", BFIN_CPU_BF536
, 0x0002,
165 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
},
166 {"bf536", BFIN_CPU_BF536
, 0x0001,
167 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
},
169 {"bf537", BFIN_CPU_BF537
, 0x0003,
170 WA_SPECULATIVE_LOADS
},
171 {"bf537", BFIN_CPU_BF537
, 0x0002,
172 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
},
173 {"bf537", BFIN_CPU_BF537
, 0x0001,
174 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
},
176 {"bf538", BFIN_CPU_BF538
, 0x0004,
177 WA_SPECULATIVE_LOADS
},
178 {"bf538", BFIN_CPU_BF538
, 0x0003,
179 WA_SPECULATIVE_LOADS
},
181 {"bf539", BFIN_CPU_BF539
, 0x0004,
182 WA_SPECULATIVE_LOADS
},
183 {"bf539", BFIN_CPU_BF539
, 0x0003,
184 WA_SPECULATIVE_LOADS
},
185 {"bf539", BFIN_CPU_BF539
, 0x0002,
186 WA_SPECULATIVE_LOADS
},
188 {"bf542", BFIN_CPU_BF542
, 0x0000,
189 WA_SPECULATIVE_LOADS
},
191 {"bf544", BFIN_CPU_BF544
, 0x0000,
192 WA_SPECULATIVE_LOADS
},
194 {"bf547", BFIN_CPU_BF547
, 0x0000,
195 WA_SPECULATIVE_LOADS
},
197 {"bf548", BFIN_CPU_BF548
, 0x0000,
198 WA_SPECULATIVE_LOADS
},
200 {"bf549", BFIN_CPU_BF549
, 0x0000,
201 WA_SPECULATIVE_LOADS
},
203 {"bf561", BFIN_CPU_BF561
, 0x0005, 0},
204 {"bf561", BFIN_CPU_BF561
, 0x0003,
205 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
},
206 {"bf561", BFIN_CPU_BF561
, 0x0002,
207 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
},
212 int splitting_for_sched
;
215 bfin_globalize_label (FILE *stream
, const char *name
)
217 fputs (".global ", stream
);
218 assemble_name (stream
, name
);
224 output_file_start (void)
226 FILE *file
= asm_out_file
;
229 /* Variable tracking should be run after all optimizations which change order
230 of insns. It also needs a valid CFG. This can't be done in
231 override_options, because flag_var_tracking is finalized after
233 bfin_flag_var_tracking
= flag_var_tracking
;
234 flag_var_tracking
= 0;
236 fprintf (file
, ".file \"%s\";\n", input_filename
);
238 for (i
= 0; arg_regs
[i
] >= 0; i
++)
240 max_arg_registers
= i
; /* how many arg reg used */
243 /* Called early in the compilation to conditionally modify
244 fixed_regs/call_used_regs. */
247 conditional_register_usage (void)
249 /* initialize condition code flag register rtx */
250 bfin_cc_rtx
= gen_rtx_REG (BImode
, REG_CC
);
251 bfin_rets_rtx
= gen_rtx_REG (Pmode
, REG_RETS
);
254 /* Examine machine-dependent attributes of function type FUNTYPE and return its
255 type. See the definition of E_FUNKIND. */
258 funkind (const_tree funtype
)
260 tree attrs
= TYPE_ATTRIBUTES (funtype
);
261 if (lookup_attribute ("interrupt_handler", attrs
))
262 return INTERRUPT_HANDLER
;
263 else if (lookup_attribute ("exception_handler", attrs
))
264 return EXCPT_HANDLER
;
265 else if (lookup_attribute ("nmi_handler", attrs
))
271 /* Legitimize PIC addresses. If the address is already position-independent,
272 we return ORIG. Newly generated position-independent addresses go into a
273 reg. This is REG if nonzero, otherwise we allocate register(s) as
274 necessary. PICREG is the register holding the pointer to the PIC offset
278 legitimize_pic_address (rtx orig
, rtx reg
, rtx picreg
)
283 if (GET_CODE (addr
) == SYMBOL_REF
|| GET_CODE (addr
) == LABEL_REF
)
288 if (TARGET_ID_SHARED_LIBRARY
)
289 unspec
= UNSPEC_MOVE_PIC
;
290 else if (GET_CODE (addr
) == SYMBOL_REF
291 && SYMBOL_REF_FUNCTION_P (addr
))
292 unspec
= UNSPEC_FUNCDESC_GOT17M4
;
294 unspec
= UNSPEC_MOVE_FDPIC
;
298 gcc_assert (can_create_pseudo_p ());
299 reg
= gen_reg_rtx (Pmode
);
302 tmp
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, addr
), unspec
);
303 new = gen_const_mem (Pmode
, gen_rtx_PLUS (Pmode
, picreg
, tmp
));
305 emit_move_insn (reg
, new);
306 if (picreg
== pic_offset_table_rtx
)
307 current_function_uses_pic_offset_table
= 1;
311 else if (GET_CODE (addr
) == CONST
|| GET_CODE (addr
) == PLUS
)
315 if (GET_CODE (addr
) == CONST
)
317 addr
= XEXP (addr
, 0);
318 gcc_assert (GET_CODE (addr
) == PLUS
);
321 if (XEXP (addr
, 0) == picreg
)
326 gcc_assert (can_create_pseudo_p ());
327 reg
= gen_reg_rtx (Pmode
);
330 base
= legitimize_pic_address (XEXP (addr
, 0), reg
, picreg
);
331 addr
= legitimize_pic_address (XEXP (addr
, 1),
332 base
== reg
? NULL_RTX
: reg
,
335 if (GET_CODE (addr
) == CONST_INT
)
337 gcc_assert (! reload_in_progress
&& ! reload_completed
);
338 addr
= force_reg (Pmode
, addr
);
341 if (GET_CODE (addr
) == PLUS
&& CONSTANT_P (XEXP (addr
, 1)))
343 base
= gen_rtx_PLUS (Pmode
, base
, XEXP (addr
, 0));
344 addr
= XEXP (addr
, 1);
347 return gen_rtx_PLUS (Pmode
, base
, addr
);
353 /* Stack frame layout. */
355 /* For a given REGNO, determine whether it must be saved in the function
356 prologue. IS_INTHANDLER specifies whether we're generating a normal
357 prologue or an interrupt/exception one. */
359 must_save_p (bool is_inthandler
, unsigned regno
)
361 if (D_REGNO_P (regno
))
363 bool is_eh_return_reg
= false;
364 if (current_function_calls_eh_return
)
369 unsigned test
= EH_RETURN_DATA_REGNO (j
);
370 if (test
== INVALID_REGNUM
)
373 is_eh_return_reg
= true;
377 return (is_eh_return_reg
378 || (df_regs_ever_live_p (regno
)
379 && !fixed_regs
[regno
]
380 && (is_inthandler
|| !call_used_regs
[regno
])));
382 else if (P_REGNO_P (regno
))
384 return ((df_regs_ever_live_p (regno
)
385 && !fixed_regs
[regno
]
386 && (is_inthandler
|| !call_used_regs
[regno
]))
388 && regno
== PIC_OFFSET_TABLE_REGNUM
389 && (current_function_uses_pic_offset_table
390 || (TARGET_ID_SHARED_LIBRARY
&& !current_function_is_leaf
))));
393 return ((is_inthandler
|| !call_used_regs
[regno
])
394 && (df_regs_ever_live_p (regno
)
395 || (!leaf_function_p () && call_used_regs
[regno
])));
399 /* Compute the number of DREGS to save with a push_multiple operation.
400 This could include registers that aren't modified in the function,
401 since push_multiple only takes a range of registers.
402 If IS_INTHANDLER, then everything that is live must be saved, even
403 if normally call-clobbered.
404 If CONSECUTIVE, return the number of registers we can save in one
405 instruction with a push/pop multiple instruction. */
408 n_dregs_to_save (bool is_inthandler
, bool consecutive
)
413 for (i
= REG_R7
+ 1; i
-- != REG_R0
;)
415 if (must_save_p (is_inthandler
, i
))
417 else if (consecutive
)
423 /* Like n_dregs_to_save, but compute number of PREGS to save. */
426 n_pregs_to_save (bool is_inthandler
, bool consecutive
)
431 for (i
= REG_P5
+ 1; i
-- != REG_P0
;)
432 if (must_save_p (is_inthandler
, i
))
434 else if (consecutive
)
439 /* Determine if we are going to save the frame pointer in the prologue. */
442 must_save_fp_p (void)
444 return frame_pointer_needed
|| df_regs_ever_live_p (REG_FP
);
448 stack_frame_needed_p (void)
450 /* EH return puts a new return address into the frame using an
451 address relative to the frame pointer. */
452 if (current_function_calls_eh_return
)
454 return frame_pointer_needed
;
457 /* Emit code to save registers in the prologue. SAVEALL is nonzero if we
458 must save all registers; this is used for interrupt handlers.
459 SPREG contains (reg:SI REG_SP). IS_INTHANDLER is true if we're doing
460 this for an interrupt (or exception) handler. */
463 expand_prologue_reg_save (rtx spreg
, int saveall
, bool is_inthandler
)
465 rtx predec1
= gen_rtx_PRE_DEC (SImode
, spreg
);
466 rtx predec
= gen_rtx_MEM (SImode
, predec1
);
467 int ndregs
= saveall
? 8 : n_dregs_to_save (is_inthandler
, false);
468 int npregs
= saveall
? 6 : n_pregs_to_save (is_inthandler
, false);
469 int ndregs_consec
= saveall
? 8 : n_dregs_to_save (is_inthandler
, true);
470 int npregs_consec
= saveall
? 6 : n_pregs_to_save (is_inthandler
, true);
472 int total_consec
= ndregs_consec
+ npregs_consec
;
475 if (saveall
|| is_inthandler
)
477 rtx insn
= emit_move_insn (predec
, gen_rtx_REG (SImode
, REG_ASTAT
));
478 RTX_FRAME_RELATED_P (insn
) = 1;
481 if (total_consec
!= 0)
484 rtx val
= GEN_INT (-total_consec
* 4);
485 rtx pat
= gen_rtx_PARALLEL (VOIDmode
, rtvec_alloc (total_consec
+ 2));
487 XVECEXP (pat
, 0, 0) = gen_rtx_UNSPEC (VOIDmode
, gen_rtvec (1, val
),
488 UNSPEC_PUSH_MULTIPLE
);
489 XVECEXP (pat
, 0, total_consec
+ 1) = gen_rtx_SET (VOIDmode
, spreg
,
493 RTX_FRAME_RELATED_P (XVECEXP (pat
, 0, total_consec
+ 1)) = 1;
494 d_to_save
= ndregs_consec
;
495 dregno
= REG_R7
+ 1 - ndregs_consec
;
496 pregno
= REG_P5
+ 1 - npregs_consec
;
497 for (i
= 0; i
< total_consec
; i
++)
499 rtx memref
= gen_rtx_MEM (word_mode
,
500 gen_rtx_PLUS (Pmode
, spreg
,
501 GEN_INT (- i
* 4 - 4)));
505 subpat
= gen_rtx_SET (VOIDmode
, memref
, gen_rtx_REG (word_mode
,
511 subpat
= gen_rtx_SET (VOIDmode
, memref
, gen_rtx_REG (word_mode
,
514 XVECEXP (pat
, 0, i
+ 1) = subpat
;
515 RTX_FRAME_RELATED_P (subpat
) = 1;
517 insn
= emit_insn (pat
);
518 RTX_FRAME_RELATED_P (insn
) = 1;
521 for (dregno
= REG_R0
; ndregs
!= ndregs_consec
; dregno
++)
523 if (must_save_p (is_inthandler
, dregno
))
525 rtx insn
= emit_move_insn (predec
, gen_rtx_REG (word_mode
, dregno
));
526 RTX_FRAME_RELATED_P (insn
) = 1;
530 for (pregno
= REG_P0
; npregs
!= npregs_consec
; pregno
++)
532 if (must_save_p (is_inthandler
, pregno
))
534 rtx insn
= emit_move_insn (predec
, gen_rtx_REG (word_mode
, pregno
));
535 RTX_FRAME_RELATED_P (insn
) = 1;
539 for (i
= REG_P7
+ 1; i
< REG_CC
; i
++)
542 && (df_regs_ever_live_p (i
)
543 || (!leaf_function_p () && call_used_regs
[i
]))))
546 if (i
== REG_A0
|| i
== REG_A1
)
547 insn
= emit_move_insn (gen_rtx_MEM (PDImode
, predec1
),
548 gen_rtx_REG (PDImode
, i
));
550 insn
= emit_move_insn (predec
, gen_rtx_REG (SImode
, i
));
551 RTX_FRAME_RELATED_P (insn
) = 1;
555 /* Emit code to restore registers in the epilogue. SAVEALL is nonzero if we
556 must save all registers; this is used for interrupt handlers.
557 SPREG contains (reg:SI REG_SP). IS_INTHANDLER is true if we're doing
558 this for an interrupt (or exception) handler. */
561 expand_epilogue_reg_restore (rtx spreg
, bool saveall
, bool is_inthandler
)
563 rtx postinc1
= gen_rtx_POST_INC (SImode
, spreg
);
564 rtx postinc
= gen_rtx_MEM (SImode
, postinc1
);
566 int ndregs
= saveall
? 8 : n_dregs_to_save (is_inthandler
, false);
567 int npregs
= saveall
? 6 : n_pregs_to_save (is_inthandler
, false);
568 int ndregs_consec
= saveall
? 8 : n_dregs_to_save (is_inthandler
, true);
569 int npregs_consec
= saveall
? 6 : n_pregs_to_save (is_inthandler
, true);
570 int total_consec
= ndregs_consec
+ npregs_consec
;
574 /* A slightly crude technique to stop flow from trying to delete "dead"
576 MEM_VOLATILE_P (postinc
) = 1;
578 for (i
= REG_CC
- 1; i
> REG_P7
; i
--)
581 && (df_regs_ever_live_p (i
)
582 || (!leaf_function_p () && call_used_regs
[i
]))))
584 if (i
== REG_A0
|| i
== REG_A1
)
586 rtx mem
= gen_rtx_MEM (PDImode
, postinc1
);
587 MEM_VOLATILE_P (mem
) = 1;
588 emit_move_insn (gen_rtx_REG (PDImode
, i
), mem
);
591 emit_move_insn (gen_rtx_REG (SImode
, i
), postinc
);
594 regno
= REG_P5
- npregs_consec
;
595 for (; npregs
!= npregs_consec
; regno
--)
597 if (must_save_p (is_inthandler
, regno
))
599 emit_move_insn (gen_rtx_REG (word_mode
, regno
), postinc
);
603 regno
= REG_R7
- ndregs_consec
;
604 for (; ndregs
!= ndregs_consec
; regno
--)
606 if (must_save_p (is_inthandler
, regno
))
608 emit_move_insn (gen_rtx_REG (word_mode
, regno
), postinc
);
613 if (total_consec
!= 0)
615 rtx pat
= gen_rtx_PARALLEL (VOIDmode
, rtvec_alloc (total_consec
+ 1));
617 = gen_rtx_SET (VOIDmode
, spreg
,
618 gen_rtx_PLUS (Pmode
, spreg
,
619 GEN_INT (total_consec
* 4)));
621 if (npregs_consec
> 0)
626 for (i
= 0; i
< total_consec
; i
++)
629 ? gen_rtx_PLUS (Pmode
, spreg
, GEN_INT (i
* 4))
631 rtx memref
= gen_rtx_MEM (word_mode
, addr
);
634 XVECEXP (pat
, 0, i
+ 1)
635 = gen_rtx_SET (VOIDmode
, gen_rtx_REG (word_mode
, regno
), memref
);
637 if (npregs_consec
> 0)
639 if (--npregs_consec
== 0)
644 insn
= emit_insn (pat
);
645 RTX_FRAME_RELATED_P (insn
) = 1;
647 if (saveall
|| is_inthandler
)
648 emit_move_insn (gen_rtx_REG (SImode
, REG_ASTAT
), postinc
);
651 /* Perform any needed actions needed for a function that is receiving a
652 variable number of arguments.
656 MODE and TYPE are the mode and type of the current parameter.
658 PRETEND_SIZE is a variable that should be set to the amount of stack
659 that must be pushed by the prolog to pretend that our caller pushed
662 Normally, this macro will push all remaining incoming registers on the
663 stack and set PRETEND_SIZE to the length of the registers pushed.
666 - VDSP C compiler manual (our ABI) says that a variable args function
667 should save the R0, R1 and R2 registers in the stack.
668 - The caller will always leave space on the stack for the
669 arguments that are passed in registers, so we dont have
670 to leave any extra space.
671 - now, the vastart pointer can access all arguments from the stack. */
674 setup_incoming_varargs (CUMULATIVE_ARGS
*cum
,
675 enum machine_mode mode ATTRIBUTE_UNUSED
,
676 tree type ATTRIBUTE_UNUSED
, int *pretend_size
,
685 /* The move for named arguments will be generated automatically by the
686 compiler. We need to generate the move rtx for the unnamed arguments
687 if they are in the first 3 words. We assume at least 1 named argument
688 exists, so we never generate [ARGP] = R0 here. */
690 for (i
= cum
->words
+ 1; i
< max_arg_registers
; i
++)
692 mem
= gen_rtx_MEM (Pmode
,
693 plus_constant (arg_pointer_rtx
, (i
* UNITS_PER_WORD
)));
694 emit_move_insn (mem
, gen_rtx_REG (Pmode
, i
));
700 /* Value should be nonzero if functions must have frame pointers.
701 Zero means the frame pointer need not be set up (and parms may
702 be accessed via the stack pointer) in functions that seem suitable. */
705 bfin_frame_pointer_required (void)
707 e_funkind fkind
= funkind (TREE_TYPE (current_function_decl
));
709 if (fkind
!= SUBROUTINE
)
712 /* We turn on -fomit-frame-pointer if -momit-leaf-frame-pointer is used,
713 so we have to override it for non-leaf functions. */
714 if (TARGET_OMIT_LEAF_FRAME_POINTER
&& ! current_function_is_leaf
)
720 /* Return the number of registers pushed during the prologue. */
723 n_regs_saved_by_prologue (void)
725 e_funkind fkind
= funkind (TREE_TYPE (current_function_decl
));
726 bool is_inthandler
= fkind
!= SUBROUTINE
;
727 tree attrs
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
728 bool all
= (lookup_attribute ("saveall", attrs
) != NULL_TREE
729 || (is_inthandler
&& !current_function_is_leaf
));
730 int ndregs
= all
? 8 : n_dregs_to_save (is_inthandler
, false);
731 int npregs
= all
? 6 : n_pregs_to_save (is_inthandler
, false);
732 int n
= ndregs
+ npregs
;
735 if (all
|| stack_frame_needed_p ())
736 /* We use a LINK instruction in this case. */
740 if (must_save_fp_p ())
742 if (! current_function_is_leaf
)
746 if (fkind
!= SUBROUTINE
|| all
)
747 /* Increment once for ASTAT. */
750 if (fkind
!= SUBROUTINE
)
753 if (lookup_attribute ("nesting", attrs
))
757 for (i
= REG_P7
+ 1; i
< REG_CC
; i
++)
759 || (fkind
!= SUBROUTINE
760 && (df_regs_ever_live_p (i
)
761 || (!leaf_function_p () && call_used_regs
[i
]))))
762 n
+= i
== REG_A0
|| i
== REG_A1
? 2 : 1;
767 /* Return the offset between two registers, one to be eliminated, and the other
768 its replacement, at the start of a routine. */
771 bfin_initial_elimination_offset (int from
, int to
)
773 HOST_WIDE_INT offset
= 0;
775 if (from
== ARG_POINTER_REGNUM
)
776 offset
= n_regs_saved_by_prologue () * 4;
778 if (to
== STACK_POINTER_REGNUM
)
780 if (current_function_outgoing_args_size
>= FIXED_STACK_AREA
)
781 offset
+= current_function_outgoing_args_size
;
782 else if (current_function_outgoing_args_size
)
783 offset
+= FIXED_STACK_AREA
;
785 offset
+= get_frame_size ();
791 /* Emit code to load a constant CONSTANT into register REG; setting
792 RTX_FRAME_RELATED_P on all insns we generate if RELATED is true.
793 Make sure that the insns we generate need not be split. */
796 frame_related_constant_load (rtx reg
, HOST_WIDE_INT constant
, bool related
)
799 rtx cst
= GEN_INT (constant
);
801 if (constant
>= -32768 && constant
< 65536)
802 insn
= emit_move_insn (reg
, cst
);
805 /* We don't call split_load_immediate here, since dwarf2out.c can get
806 confused about some of the more clever sequences it can generate. */
807 insn
= emit_insn (gen_movsi_high (reg
, cst
));
809 RTX_FRAME_RELATED_P (insn
) = 1;
810 insn
= emit_insn (gen_movsi_low (reg
, reg
, cst
));
813 RTX_FRAME_RELATED_P (insn
) = 1;
816 /* Generate efficient code to add a value to a P register.
817 Set RTX_FRAME_RELATED_P on the generated insns if FRAME is nonzero.
818 EPILOGUE_P is zero if this function is called for prologue,
819 otherwise it's nonzero. And it's less than zero if this is for
823 add_to_reg (rtx reg
, HOST_WIDE_INT value
, int frame
, int epilogue_p
)
828 /* Choose whether to use a sequence using a temporary register, or
829 a sequence with multiple adds. We can add a signed 7-bit value
830 in one instruction. */
831 if (value
> 120 || value
< -120)
839 /* For prologue or normal epilogue, P1 can be safely used
840 as the temporary register. For sibcall epilogue, we try to find
841 a call used P register, which will be restored in epilogue.
842 If we cannot find such a P register, we have to use one I register
846 tmpreg
= gen_rtx_REG (SImode
, REG_P1
);
850 for (i
= REG_P0
; i
<= REG_P5
; i
++)
851 if ((df_regs_ever_live_p (i
) && ! call_used_regs
[i
])
853 && i
== PIC_OFFSET_TABLE_REGNUM
854 && (current_function_uses_pic_offset_table
855 || (TARGET_ID_SHARED_LIBRARY
856 && ! current_function_is_leaf
))))
859 tmpreg
= gen_rtx_REG (SImode
, i
);
862 tmpreg
= gen_rtx_REG (SImode
, REG_P1
);
863 tmpreg2
= gen_rtx_REG (SImode
, REG_I0
);
864 emit_move_insn (tmpreg2
, tmpreg
);
869 frame_related_constant_load (tmpreg
, value
, TRUE
);
871 insn
= emit_move_insn (tmpreg
, GEN_INT (value
));
873 insn
= emit_insn (gen_addsi3 (reg
, reg
, tmpreg
));
875 RTX_FRAME_RELATED_P (insn
) = 1;
877 if (tmpreg2
!= NULL_RTX
)
878 emit_move_insn (tmpreg
, tmpreg2
);
889 /* We could use -62, but that would leave the stack unaligned, so
893 insn
= emit_insn (gen_addsi3 (reg
, reg
, GEN_INT (size
)));
895 RTX_FRAME_RELATED_P (insn
) = 1;
901 /* Generate a LINK insn for a frame sized FRAME_SIZE. If this constant
902 is too large, generate a sequence of insns that has the same effect.
903 SPREG contains (reg:SI REG_SP). */
906 emit_link_insn (rtx spreg
, HOST_WIDE_INT frame_size
)
908 HOST_WIDE_INT link_size
= frame_size
;
912 if (link_size
> 262140)
915 /* Use a LINK insn with as big a constant as possible, then subtract
916 any remaining size from the SP. */
917 insn
= emit_insn (gen_link (GEN_INT (-8 - link_size
)));
918 RTX_FRAME_RELATED_P (insn
) = 1;
920 for (i
= 0; i
< XVECLEN (PATTERN (insn
), 0); i
++)
922 rtx set
= XVECEXP (PATTERN (insn
), 0, i
);
923 gcc_assert (GET_CODE (set
) == SET
);
924 RTX_FRAME_RELATED_P (set
) = 1;
927 frame_size
-= link_size
;
931 /* Must use a call-clobbered PREG that isn't the static chain. */
932 rtx tmpreg
= gen_rtx_REG (Pmode
, REG_P1
);
934 frame_related_constant_load (tmpreg
, -frame_size
, TRUE
);
935 insn
= emit_insn (gen_addsi3 (spreg
, spreg
, tmpreg
));
936 RTX_FRAME_RELATED_P (insn
) = 1;
940 /* Return the number of bytes we must reserve for outgoing arguments
941 in the current function's stack frame. */
946 if (current_function_outgoing_args_size
)
948 if (current_function_outgoing_args_size
>= FIXED_STACK_AREA
)
949 return current_function_outgoing_args_size
;
951 return FIXED_STACK_AREA
;
956 /* Save RETS and FP, and allocate a stack frame. ALL is true if the
957 function must save all its registers (true only for certain interrupt
961 do_link (rtx spreg
, HOST_WIDE_INT frame_size
, bool all
)
963 frame_size
+= arg_area_size ();
965 if (all
|| stack_frame_needed_p ()
966 || (must_save_fp_p () && ! current_function_is_leaf
))
967 emit_link_insn (spreg
, frame_size
);
970 if (! current_function_is_leaf
)
972 rtx pat
= gen_movsi (gen_rtx_MEM (Pmode
,
973 gen_rtx_PRE_DEC (Pmode
, spreg
)),
975 rtx insn
= emit_insn (pat
);
976 RTX_FRAME_RELATED_P (insn
) = 1;
978 if (must_save_fp_p ())
980 rtx pat
= gen_movsi (gen_rtx_MEM (Pmode
,
981 gen_rtx_PRE_DEC (Pmode
, spreg
)),
982 gen_rtx_REG (Pmode
, REG_FP
));
983 rtx insn
= emit_insn (pat
);
984 RTX_FRAME_RELATED_P (insn
) = 1;
986 add_to_reg (spreg
, -frame_size
, 1, 0);
990 /* Like do_link, but used for epilogues to deallocate the stack frame.
991 EPILOGUE_P is zero if this function is called for prologue,
992 otherwise it's nonzero. And it's less than zero if this is for
996 do_unlink (rtx spreg
, HOST_WIDE_INT frame_size
, bool all
, int epilogue_p
)
998 frame_size
+= arg_area_size ();
1000 if (all
|| stack_frame_needed_p ())
1001 emit_insn (gen_unlink ());
1004 rtx postinc
= gen_rtx_MEM (Pmode
, gen_rtx_POST_INC (Pmode
, spreg
));
1006 add_to_reg (spreg
, frame_size
, 0, epilogue_p
);
1007 if (must_save_fp_p ())
1009 rtx fpreg
= gen_rtx_REG (Pmode
, REG_FP
);
1010 emit_move_insn (fpreg
, postinc
);
1011 emit_insn (gen_rtx_USE (VOIDmode
, fpreg
));
1013 if (! current_function_is_leaf
)
1015 emit_move_insn (bfin_rets_rtx
, postinc
);
1016 emit_insn (gen_rtx_USE (VOIDmode
, bfin_rets_rtx
));
1021 /* Generate a prologue suitable for a function of kind FKIND. This is
1022 called for interrupt and exception handler prologues.
1023 SPREG contains (reg:SI REG_SP). */
1026 expand_interrupt_handler_prologue (rtx spreg
, e_funkind fkind
, bool all
)
1028 HOST_WIDE_INT frame_size
= get_frame_size ();
1029 rtx predec1
= gen_rtx_PRE_DEC (SImode
, spreg
);
1030 rtx predec
= gen_rtx_MEM (SImode
, predec1
);
1032 tree attrs
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
1033 tree kspisusp
= lookup_attribute ("kspisusp", attrs
);
1037 insn
= emit_move_insn (spreg
, gen_rtx_REG (Pmode
, REG_USP
));
1038 RTX_FRAME_RELATED_P (insn
) = 1;
1041 /* We need space on the stack in case we need to save the argument
1043 if (fkind
== EXCPT_HANDLER
)
1045 insn
= emit_insn (gen_addsi3 (spreg
, spreg
, GEN_INT (-12)));
1046 RTX_FRAME_RELATED_P (insn
) = 1;
1049 /* If we're calling other functions, they won't save their call-clobbered
1050 registers, so we must save everything here. */
1051 if (!current_function_is_leaf
)
1053 expand_prologue_reg_save (spreg
, all
, true);
1055 if (lookup_attribute ("nesting", attrs
))
1057 rtx srcreg
= gen_rtx_REG (Pmode
, (fkind
== EXCPT_HANDLER
? REG_RETX
1058 : fkind
== NMI_HANDLER
? REG_RETN
1060 insn
= emit_move_insn (predec
, srcreg
);
1061 RTX_FRAME_RELATED_P (insn
) = 1;
1064 do_link (spreg
, frame_size
, all
);
1066 if (fkind
== EXCPT_HANDLER
)
1068 rtx r0reg
= gen_rtx_REG (SImode
, REG_R0
);
1069 rtx r1reg
= gen_rtx_REG (SImode
, REG_R1
);
1070 rtx r2reg
= gen_rtx_REG (SImode
, REG_R2
);
1073 insn
= emit_move_insn (r0reg
, gen_rtx_REG (SImode
, REG_SEQSTAT
));
1074 insn
= emit_insn (gen_ashrsi3 (r0reg
, r0reg
, GEN_INT (26)));
1075 insn
= emit_insn (gen_ashlsi3 (r0reg
, r0reg
, GEN_INT (26)));
1076 insn
= emit_move_insn (r1reg
, spreg
);
1077 insn
= emit_move_insn (r2reg
, gen_rtx_REG (Pmode
, REG_FP
));
1078 insn
= emit_insn (gen_addsi3 (r2reg
, r2reg
, GEN_INT (8)));
1082 /* Generate an epilogue suitable for a function of kind FKIND. This is
1083 called for interrupt and exception handler epilogues.
1084 SPREG contains (reg:SI REG_SP). */
1087 expand_interrupt_handler_epilogue (rtx spreg
, e_funkind fkind
, bool all
)
1089 tree attrs
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
1090 rtx postinc1
= gen_rtx_POST_INC (SImode
, spreg
);
1091 rtx postinc
= gen_rtx_MEM (SImode
, postinc1
);
1093 /* A slightly crude technique to stop flow from trying to delete "dead"
1095 MEM_VOLATILE_P (postinc
) = 1;
1097 do_unlink (spreg
, get_frame_size (), all
, 1);
1099 if (lookup_attribute ("nesting", attrs
))
1101 rtx srcreg
= gen_rtx_REG (Pmode
, (fkind
== EXCPT_HANDLER
? REG_RETX
1102 : fkind
== NMI_HANDLER
? REG_RETN
1104 emit_move_insn (srcreg
, postinc
);
1107 /* If we're calling other functions, they won't save their call-clobbered
1108 registers, so we must save (and restore) everything here. */
1109 if (!current_function_is_leaf
)
1112 expand_epilogue_reg_restore (spreg
, all
, true);
1114 /* Deallocate any space we left on the stack in case we needed to save the
1115 argument registers. */
1116 if (fkind
== EXCPT_HANDLER
)
1117 emit_insn (gen_addsi3 (spreg
, spreg
, GEN_INT (12)));
1119 emit_jump_insn (gen_return_internal (GEN_INT (fkind
)));
1122 /* Used while emitting the prologue to generate code to load the correct value
1123 into the PIC register, which is passed in DEST. */
1126 bfin_load_pic_reg (rtx dest
)
1128 struct cgraph_local_info
*i
= NULL
;
1131 if (flag_unit_at_a_time
)
1132 i
= cgraph_local_info (current_function_decl
);
1134 /* Functions local to the translation unit don't need to reload the
1135 pic reg, since the caller always passes a usable one. */
1137 return pic_offset_table_rtx
;
1139 if (bfin_lib_id_given
)
1140 addr
= plus_constant (pic_offset_table_rtx
, -4 - bfin_library_id
* 4);
1142 addr
= gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
,
1143 gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, const0_rtx
),
1144 UNSPEC_LIBRARY_OFFSET
));
1145 insn
= emit_insn (gen_movsi (dest
, gen_rtx_MEM (Pmode
, addr
)));
1149 /* Generate RTL for the prologue of the current function. */
1152 bfin_expand_prologue (void)
1154 HOST_WIDE_INT frame_size
= get_frame_size ();
1155 rtx spreg
= gen_rtx_REG (Pmode
, REG_SP
);
1156 e_funkind fkind
= funkind (TREE_TYPE (current_function_decl
));
1157 rtx pic_reg_loaded
= NULL_RTX
;
1158 tree attrs
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
1159 bool all
= lookup_attribute ("saveall", attrs
) != NULL_TREE
;
1161 if (fkind
!= SUBROUTINE
)
1163 expand_interrupt_handler_prologue (spreg
, fkind
, all
);
1167 if (current_function_limit_stack
1168 || TARGET_STACK_CHECK_L1
)
1170 HOST_WIDE_INT offset
1171 = bfin_initial_elimination_offset (ARG_POINTER_REGNUM
,
1172 STACK_POINTER_REGNUM
);
1173 rtx lim
= current_function_limit_stack
? stack_limit_rtx
: NULL_RTX
;
1174 rtx p2reg
= gen_rtx_REG (Pmode
, REG_P2
);
1178 emit_move_insn (p2reg
, gen_int_mode (0xFFB00000, SImode
));
1179 emit_move_insn (p2reg
, gen_rtx_MEM (Pmode
, p2reg
));
1182 if (GET_CODE (lim
) == SYMBOL_REF
)
1184 if (TARGET_ID_SHARED_LIBRARY
)
1186 rtx p1reg
= gen_rtx_REG (Pmode
, REG_P1
);
1188 pic_reg_loaded
= bfin_load_pic_reg (p2reg
);
1189 val
= legitimize_pic_address (stack_limit_rtx
, p1reg
,
1191 emit_move_insn (p1reg
, val
);
1192 frame_related_constant_load (p2reg
, offset
, FALSE
);
1193 emit_insn (gen_addsi3 (p2reg
, p2reg
, p1reg
));
1198 rtx limit
= plus_constant (lim
, offset
);
1199 emit_move_insn (p2reg
, limit
);
1206 emit_move_insn (p2reg
, lim
);
1207 add_to_reg (p2reg
, offset
, 0, 0);
1210 emit_insn (gen_compare_lt (bfin_cc_rtx
, spreg
, lim
));
1211 emit_insn (gen_trapifcc ());
1213 expand_prologue_reg_save (spreg
, all
, false);
1215 do_link (spreg
, frame_size
, false);
1217 if (TARGET_ID_SHARED_LIBRARY
1219 && (current_function_uses_pic_offset_table
1220 || !current_function_is_leaf
))
1221 bfin_load_pic_reg (pic_offset_table_rtx
);
1224 /* Generate RTL for the epilogue of the current function. NEED_RETURN is zero
1225 if this is for a sibcall. EH_RETURN is nonzero if we're expanding an
1226 eh_return pattern. SIBCALL_P is true if this is a sibcall epilogue,
1230 bfin_expand_epilogue (int need_return
, int eh_return
, bool sibcall_p
)
1232 rtx spreg
= gen_rtx_REG (Pmode
, REG_SP
);
1233 e_funkind fkind
= funkind (TREE_TYPE (current_function_decl
));
1234 int e
= sibcall_p
? -1 : 1;
1235 tree attrs
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
1236 bool all
= lookup_attribute ("saveall", attrs
) != NULL_TREE
;
1238 if (fkind
!= SUBROUTINE
)
1240 expand_interrupt_handler_epilogue (spreg
, fkind
, all
);
1244 do_unlink (spreg
, get_frame_size (), false, e
);
1246 expand_epilogue_reg_restore (spreg
, all
, false);
1248 /* Omit the return insn if this is for a sibcall. */
1253 emit_insn (gen_addsi3 (spreg
, spreg
, gen_rtx_REG (Pmode
, REG_P2
)));
1255 emit_jump_insn (gen_return_internal (GEN_INT (SUBROUTINE
)));
1258 /* Return nonzero if register OLD_REG can be renamed to register NEW_REG. */
1261 bfin_hard_regno_rename_ok (unsigned int old_reg ATTRIBUTE_UNUSED
,
1262 unsigned int new_reg
)
1264 /* Interrupt functions can only use registers that have already been
1265 saved by the prologue, even if they would normally be
1268 if (funkind (TREE_TYPE (current_function_decl
)) != SUBROUTINE
1269 && !df_regs_ever_live_p (new_reg
))
1275 /* Return the value of the return address for the frame COUNT steps up
1276 from the current frame, after the prologue.
1277 We punt for everything but the current frame by returning const0_rtx. */
1280 bfin_return_addr_rtx (int count
)
1285 return get_hard_reg_initial_val (Pmode
, REG_RETS
);
1288 /* Try machine-dependent ways of modifying an illegitimate address X
1289 to be legitimate. If we find one, return the new, valid address,
1290 otherwise return NULL_RTX.
1292 OLDX is the address as it was before break_out_memory_refs was called.
1293 In some cases it is useful to look at this to decide what needs to be done.
1295 MODE is the mode of the memory reference. */
1298 legitimize_address (rtx x ATTRIBUTE_UNUSED
, rtx oldx ATTRIBUTE_UNUSED
,
1299 enum machine_mode mode ATTRIBUTE_UNUSED
)
1305 bfin_delegitimize_address (rtx orig_x
)
1309 if (GET_CODE (x
) != MEM
)
1313 if (GET_CODE (x
) == PLUS
1314 && GET_CODE (XEXP (x
, 1)) == UNSPEC
1315 && XINT (XEXP (x
, 1), 1) == UNSPEC_MOVE_PIC
1316 && GET_CODE (XEXP (x
, 0)) == REG
1317 && REGNO (XEXP (x
, 0)) == PIC_OFFSET_TABLE_REGNUM
)
1318 return XVECEXP (XEXP (x
, 1), 0, 0);
1323 /* This predicate is used to compute the length of a load/store insn.
1324 OP is a MEM rtx, we return nonzero if its addressing mode requires a
1325 32-bit instruction. */
1328 effective_address_32bit_p (rtx op
, enum machine_mode mode
)
1330 HOST_WIDE_INT offset
;
1332 mode
= GET_MODE (op
);
1335 if (GET_CODE (op
) != PLUS
)
1337 gcc_assert (REG_P (op
) || GET_CODE (op
) == POST_INC
1338 || GET_CODE (op
) == PRE_DEC
|| GET_CODE (op
) == POST_DEC
);
1342 if (GET_CODE (XEXP (op
, 1)) == UNSPEC
)
1345 offset
= INTVAL (XEXP (op
, 1));
1347 /* All byte loads use a 16-bit offset. */
1348 if (GET_MODE_SIZE (mode
) == 1)
1351 if (GET_MODE_SIZE (mode
) == 4)
1353 /* Frame pointer relative loads can use a negative offset, all others
1354 are restricted to a small positive one. */
1355 if (XEXP (op
, 0) == frame_pointer_rtx
)
1356 return offset
< -128 || offset
> 60;
1357 return offset
< 0 || offset
> 60;
1360 /* Must be HImode now. */
1361 return offset
< 0 || offset
> 30;
1364 /* Returns true if X is a memory reference using an I register. */
1366 bfin_dsp_memref_p (rtx x
)
1371 if (GET_CODE (x
) == POST_INC
|| GET_CODE (x
) == PRE_INC
1372 || GET_CODE (x
) == POST_DEC
|| GET_CODE (x
) == PRE_DEC
)
1377 /* Return cost of the memory address ADDR.
1378 All addressing modes are equally cheap on the Blackfin. */
1381 bfin_address_cost (rtx addr ATTRIBUTE_UNUSED
)
1386 /* Subroutine of print_operand; used to print a memory reference X to FILE. */
1389 print_address_operand (FILE *file
, rtx x
)
1391 switch (GET_CODE (x
))
1394 output_address (XEXP (x
, 0));
1395 fprintf (file
, "+");
1396 output_address (XEXP (x
, 1));
1400 fprintf (file
, "--");
1401 output_address (XEXP (x
, 0));
1404 output_address (XEXP (x
, 0));
1405 fprintf (file
, "++");
1408 output_address (XEXP (x
, 0));
1409 fprintf (file
, "--");
1413 gcc_assert (GET_CODE (x
) != MEM
);
1414 print_operand (file
, x
, 0);
1419 /* Adding intp DImode support by Tony
1425 print_operand (FILE *file
, rtx x
, char code
)
1427 enum machine_mode mode
;
1431 if (GET_MODE (current_output_insn
) == SImode
)
1432 fprintf (file
, " ||");
1434 fprintf (file
, ";");
1438 mode
= GET_MODE (x
);
1443 switch (GET_CODE (x
))
1446 fprintf (file
, "e");
1449 fprintf (file
, "ne");
1452 fprintf (file
, "g");
1455 fprintf (file
, "l");
1458 fprintf (file
, "ge");
1461 fprintf (file
, "le");
1464 fprintf (file
, "g");
1467 fprintf (file
, "l");
1470 fprintf (file
, "ge");
1473 fprintf (file
, "le");
1476 output_operand_lossage ("invalid %%j value");
1480 case 'J': /* reverse logic */
1481 switch (GET_CODE(x
))
1484 fprintf (file
, "ne");
1487 fprintf (file
, "e");
1490 fprintf (file
, "le");
1493 fprintf (file
, "ge");
1496 fprintf (file
, "l");
1499 fprintf (file
, "g");
1502 fprintf (file
, "le");
1505 fprintf (file
, "ge");
1508 fprintf (file
, "l");
1511 fprintf (file
, "g");
1514 output_operand_lossage ("invalid %%J value");
1519 switch (GET_CODE (x
))
1525 fprintf (file
, "%s", short_reg_names
[REGNO (x
)]);
1527 output_operand_lossage ("invalid operand for code '%c'", code
);
1529 else if (code
== 'd')
1532 fprintf (file
, "%s", high_reg_names
[REGNO (x
)]);
1534 output_operand_lossage ("invalid operand for code '%c'", code
);
1536 else if (code
== 'w')
1538 if (REGNO (x
) == REG_A0
|| REGNO (x
) == REG_A1
)
1539 fprintf (file
, "%s.w", reg_names
[REGNO (x
)]);
1541 output_operand_lossage ("invalid operand for code '%c'", code
);
1543 else if (code
== 'x')
1545 if (REGNO (x
) == REG_A0
|| REGNO (x
) == REG_A1
)
1546 fprintf (file
, "%s.x", reg_names
[REGNO (x
)]);
1548 output_operand_lossage ("invalid operand for code '%c'", code
);
1550 else if (code
== 'v')
1552 if (REGNO (x
) == REG_A0
)
1553 fprintf (file
, "AV0");
1554 else if (REGNO (x
) == REG_A1
)
1555 fprintf (file
, "AV1");
1557 output_operand_lossage ("invalid operand for code '%c'", code
);
1559 else if (code
== 'D')
1561 if (D_REGNO_P (REGNO (x
)))
1562 fprintf (file
, "%s", dregs_pair_names
[REGNO (x
)]);
1564 output_operand_lossage ("invalid operand for code '%c'", code
);
1566 else if (code
== 'H')
1568 if ((mode
== DImode
|| mode
== DFmode
) && REG_P (x
))
1569 fprintf (file
, "%s", reg_names
[REGNO (x
) + 1]);
1571 output_operand_lossage ("invalid operand for code '%c'", code
);
1573 else if (code
== 'T')
1575 if (D_REGNO_P (REGNO (x
)))
1576 fprintf (file
, "%s", byte_reg_names
[REGNO (x
)]);
1578 output_operand_lossage ("invalid operand for code '%c'", code
);
1581 fprintf (file
, "%s", reg_names
[REGNO (x
)]);
1587 print_address_operand (file
, x
);
1599 fputs ("(FU)", file
);
1602 fputs ("(T)", file
);
1605 fputs ("(TFU)", file
);
1608 fputs ("(W32)", file
);
1611 fputs ("(IS)", file
);
1614 fputs ("(IU)", file
);
1617 fputs ("(IH)", file
);
1620 fputs ("(M)", file
);
1623 fputs ("(IS,M)", file
);
1626 fputs ("(ISS2)", file
);
1629 fputs ("(S2RND)", file
);
1636 else if (code
== 'b')
1638 if (INTVAL (x
) == 0)
1640 else if (INTVAL (x
) == 1)
1646 /* Moves to half registers with d or h modifiers always use unsigned
1648 else if (code
== 'd')
1649 x
= GEN_INT ((INTVAL (x
) >> 16) & 0xffff);
1650 else if (code
== 'h')
1651 x
= GEN_INT (INTVAL (x
) & 0xffff);
1652 else if (code
== 'N')
1653 x
= GEN_INT (-INTVAL (x
));
1654 else if (code
== 'X')
1655 x
= GEN_INT (exact_log2 (0xffffffff & INTVAL (x
)));
1656 else if (code
== 'Y')
1657 x
= GEN_INT (exact_log2 (0xffffffff & ~INTVAL (x
)));
1658 else if (code
== 'Z')
1659 /* Used for LINK insns. */
1660 x
= GEN_INT (-8 - INTVAL (x
));
1665 output_addr_const (file
, x
);
1669 output_operand_lossage ("invalid const_double operand");
1673 switch (XINT (x
, 1))
1675 case UNSPEC_MOVE_PIC
:
1676 output_addr_const (file
, XVECEXP (x
, 0, 0));
1677 fprintf (file
, "@GOT");
1680 case UNSPEC_MOVE_FDPIC
:
1681 output_addr_const (file
, XVECEXP (x
, 0, 0));
1682 fprintf (file
, "@GOT17M4");
1685 case UNSPEC_FUNCDESC_GOT17M4
:
1686 output_addr_const (file
, XVECEXP (x
, 0, 0));
1687 fprintf (file
, "@FUNCDESC_GOT17M4");
1690 case UNSPEC_LIBRARY_OFFSET
:
1691 fprintf (file
, "_current_shared_library_p5_offset_");
1700 output_addr_const (file
, x
);
1705 /* Argument support functions. */
1707 /* Initialize a variable CUM of type CUMULATIVE_ARGS
1708 for a call to a function whose data type is FNTYPE.
1709 For a library call, FNTYPE is 0.
1710 VDSP C Compiler manual, our ABI says that
1711 first 3 words of arguments will use R0, R1 and R2.
1715 init_cumulative_args (CUMULATIVE_ARGS
*cum
, tree fntype
,
1716 rtx libname ATTRIBUTE_UNUSED
)
1718 static CUMULATIVE_ARGS zero_cum
;
1722 /* Set up the number of registers to use for passing arguments. */
1724 cum
->nregs
= max_arg_registers
;
1725 cum
->arg_regs
= arg_regs
;
1727 cum
->call_cookie
= CALL_NORMAL
;
1728 /* Check for a longcall attribute. */
1729 if (fntype
&& lookup_attribute ("shortcall", TYPE_ATTRIBUTES (fntype
)))
1730 cum
->call_cookie
|= CALL_SHORT
;
1731 else if (fntype
&& lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype
)))
1732 cum
->call_cookie
|= CALL_LONG
;
1737 /* Update the data in CUM to advance over an argument
1738 of mode MODE and data type TYPE.
1739 (TYPE is null for libcalls where that information may not be available.) */
1742 function_arg_advance (CUMULATIVE_ARGS
*cum
, enum machine_mode mode
, tree type
,
1743 int named ATTRIBUTE_UNUSED
)
1745 int count
, bytes
, words
;
1747 bytes
= (mode
== BLKmode
) ? int_size_in_bytes (type
) : GET_MODE_SIZE (mode
);
1748 words
= (bytes
+ UNITS_PER_WORD
- 1) / UNITS_PER_WORD
;
1750 cum
->words
+= words
;
1751 cum
->nregs
-= words
;
1753 if (cum
->nregs
<= 0)
1756 cum
->arg_regs
= NULL
;
1760 for (count
= 1; count
<= words
; count
++)
1767 /* Define where to put the arguments to a function.
1768 Value is zero to push the argument on the stack,
1769 or a hard register in which to store the argument.
1771 MODE is the argument's machine mode.
1772 TYPE is the data type of the argument (as a tree).
1773 This is null for libcalls where that information may
1775 CUM is a variable of type CUMULATIVE_ARGS which gives info about
1776 the preceding args and about the function being called.
1777 NAMED is nonzero if this argument is a named parameter
1778 (otherwise it is an extra parameter matching an ellipsis). */
1781 function_arg (CUMULATIVE_ARGS
*cum
, enum machine_mode mode
, tree type
,
1782 int named ATTRIBUTE_UNUSED
)
1785 = (mode
== BLKmode
) ? int_size_in_bytes (type
) : GET_MODE_SIZE (mode
);
1787 if (mode
== VOIDmode
)
1788 /* Compute operand 2 of the call insn. */
1789 return GEN_INT (cum
->call_cookie
);
1795 return gen_rtx_REG (mode
, *(cum
->arg_regs
));
1800 /* For an arg passed partly in registers and partly in memory,
1801 this is the number of bytes passed in registers.
1802 For args passed entirely in registers or entirely in memory, zero.
1804 Refer VDSP C Compiler manual, our ABI.
1805 First 3 words are in registers. So, if an argument is larger
1806 than the registers available, it will span the register and
1810 bfin_arg_partial_bytes (CUMULATIVE_ARGS
*cum
, enum machine_mode mode
,
1811 tree type ATTRIBUTE_UNUSED
,
1812 bool named ATTRIBUTE_UNUSED
)
1815 = (mode
== BLKmode
) ? int_size_in_bytes (type
) : GET_MODE_SIZE (mode
);
1816 int bytes_left
= cum
->nregs
* UNITS_PER_WORD
;
1821 if (bytes_left
== 0)
1823 if (bytes
> bytes_left
)
1828 /* Variable sized types are passed by reference. */
1831 bfin_pass_by_reference (CUMULATIVE_ARGS
*cum ATTRIBUTE_UNUSED
,
1832 enum machine_mode mode ATTRIBUTE_UNUSED
,
1833 const_tree type
, bool named ATTRIBUTE_UNUSED
)
1835 return type
&& TREE_CODE (TYPE_SIZE (type
)) != INTEGER_CST
;
1838 /* Decide whether a type should be returned in memory (true)
1839 or in a register (false). This is called by the macro
1840 RETURN_IN_MEMORY. */
1843 bfin_return_in_memory (const_tree type
)
1845 int size
= int_size_in_bytes (type
);
1846 return size
> 2 * UNITS_PER_WORD
|| size
== -1;
1849 /* Register in which address to store a structure value
1850 is passed to a function. */
1852 bfin_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED
,
1853 int incoming ATTRIBUTE_UNUSED
)
1855 return gen_rtx_REG (Pmode
, REG_P0
);
1858 /* Return true when register may be used to pass function parameters. */
1861 function_arg_regno_p (int n
)
1864 for (i
= 0; arg_regs
[i
] != -1; i
++)
1865 if (n
== arg_regs
[i
])
1870 /* Returns 1 if OP contains a symbol reference */
1873 symbolic_reference_mentioned_p (rtx op
)
1875 register const char *fmt
;
1878 if (GET_CODE (op
) == SYMBOL_REF
|| GET_CODE (op
) == LABEL_REF
)
1881 fmt
= GET_RTX_FORMAT (GET_CODE (op
));
1882 for (i
= GET_RTX_LENGTH (GET_CODE (op
)) - 1; i
>= 0; i
--)
1888 for (j
= XVECLEN (op
, i
) - 1; j
>= 0; j
--)
1889 if (symbolic_reference_mentioned_p (XVECEXP (op
, i
, j
)))
1893 else if (fmt
[i
] == 'e' && symbolic_reference_mentioned_p (XEXP (op
, i
)))
1900 /* Decide whether we can make a sibling call to a function. DECL is the
1901 declaration of the function being targeted by the call and EXP is the
1902 CALL_EXPR representing the call. */
1905 bfin_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED
,
1906 tree exp ATTRIBUTE_UNUSED
)
1908 e_funkind fkind
= funkind (TREE_TYPE (current_function_decl
));
1909 if (fkind
!= SUBROUTINE
)
1911 if (!TARGET_ID_SHARED_LIBRARY
|| TARGET_SEP_DATA
)
1914 /* When compiling for ID shared libraries, can't sibcall a local function
1915 from a non-local function, because the local function thinks it does
1916 not need to reload P5 in the prologue, but the sibcall wil pop P5 in the
1917 sibcall epilogue, and we end up with the wrong value in P5. */
1919 if (!flag_unit_at_a_time
|| decl
== NULL
)
1920 /* Not enough information. */
1924 struct cgraph_local_info
*this_func
, *called_func
;
1926 this_func
= cgraph_local_info (current_function_decl
);
1927 called_func
= cgraph_local_info (decl
);
1928 return !called_func
->local
|| this_func
->local
;
1932 /* Emit RTL insns to initialize the variable parts of a trampoline at
1933 TRAMP. FNADDR is an RTX for the address of the function's pure
1934 code. CXT is an RTX for the static chain value for the function. */
1937 initialize_trampoline (rtx tramp
, rtx fnaddr
, rtx cxt
)
1939 rtx t1
= copy_to_reg (fnaddr
);
1940 rtx t2
= copy_to_reg (cxt
);
1946 rtx a
= memory_address (Pmode
, plus_constant (tramp
, 8));
1947 addr
= memory_address (Pmode
, tramp
);
1948 emit_move_insn (gen_rtx_MEM (SImode
, addr
), a
);
1952 addr
= memory_address (Pmode
, plus_constant (tramp
, i
+ 2));
1953 emit_move_insn (gen_rtx_MEM (HImode
, addr
), gen_lowpart (HImode
, t1
));
1954 emit_insn (gen_ashrsi3 (t1
, t1
, GEN_INT (16)));
1955 addr
= memory_address (Pmode
, plus_constant (tramp
, i
+ 6));
1956 emit_move_insn (gen_rtx_MEM (HImode
, addr
), gen_lowpart (HImode
, t1
));
1958 addr
= memory_address (Pmode
, plus_constant (tramp
, i
+ 10));
1959 emit_move_insn (gen_rtx_MEM (HImode
, addr
), gen_lowpart (HImode
, t2
));
1960 emit_insn (gen_ashrsi3 (t2
, t2
, GEN_INT (16)));
1961 addr
= memory_address (Pmode
, plus_constant (tramp
, i
+ 14));
1962 emit_move_insn (gen_rtx_MEM (HImode
, addr
), gen_lowpart (HImode
, t2
));
1965 /* Emit insns to move operands[1] into operands[0]. */
1968 emit_pic_move (rtx
*operands
, enum machine_mode mode ATTRIBUTE_UNUSED
)
1970 rtx temp
= reload_in_progress
? operands
[0] : gen_reg_rtx (Pmode
);
1972 gcc_assert (!TARGET_FDPIC
|| !(reload_in_progress
|| reload_completed
));
1973 if (GET_CODE (operands
[0]) == MEM
&& SYMBOLIC_CONST (operands
[1]))
1974 operands
[1] = force_reg (SImode
, operands
[1]);
1976 operands
[1] = legitimize_pic_address (operands
[1], temp
,
1977 TARGET_FDPIC
? OUR_FDPIC_REG
1978 : pic_offset_table_rtx
);
1981 /* Expand a move operation in mode MODE. The operands are in OPERANDS.
1982 Returns true if no further code must be generated, false if the caller
1983 should generate an insn to move OPERANDS[1] to OPERANDS[0]. */
1986 expand_move (rtx
*operands
, enum machine_mode mode
)
1988 rtx op
= operands
[1];
1989 if ((TARGET_ID_SHARED_LIBRARY
|| TARGET_FDPIC
)
1990 && SYMBOLIC_CONST (op
))
1991 emit_pic_move (operands
, mode
);
1992 else if (mode
== SImode
&& GET_CODE (op
) == CONST
1993 && GET_CODE (XEXP (op
, 0)) == PLUS
1994 && GET_CODE (XEXP (XEXP (op
, 0), 0)) == SYMBOL_REF
1995 && !bfin_legitimate_constant_p (op
))
1997 rtx dest
= operands
[0];
1999 gcc_assert (!reload_in_progress
&& !reload_completed
);
2001 op0
= force_reg (mode
, XEXP (op
, 0));
2003 if (!insn_data
[CODE_FOR_addsi3
].operand
[2].predicate (op1
, mode
))
2004 op1
= force_reg (mode
, op1
);
2005 if (GET_CODE (dest
) == MEM
)
2006 dest
= gen_reg_rtx (mode
);
2007 emit_insn (gen_addsi3 (dest
, op0
, op1
));
2008 if (dest
== operands
[0])
2012 /* Don't generate memory->memory or constant->memory moves, go through a
2014 else if ((reload_in_progress
| reload_completed
) == 0
2015 && GET_CODE (operands
[0]) == MEM
2016 && GET_CODE (operands
[1]) != REG
)
2017 operands
[1] = force_reg (mode
, operands
[1]);
2021 /* Split one or more DImode RTL references into pairs of SImode
2022 references. The RTL can be REG, offsettable MEM, integer constant, or
2023 CONST_DOUBLE. "operands" is a pointer to an array of DImode RTL to
2024 split and "num" is its length. lo_half and hi_half are output arrays
2025 that parallel "operands". */
2028 split_di (rtx operands
[], int num
, rtx lo_half
[], rtx hi_half
[])
2032 rtx op
= operands
[num
];
2034 /* simplify_subreg refuse to split volatile memory addresses,
2035 but we still have to handle it. */
2036 if (GET_CODE (op
) == MEM
)
2038 lo_half
[num
] = adjust_address (op
, SImode
, 0);
2039 hi_half
[num
] = adjust_address (op
, SImode
, 4);
2043 lo_half
[num
] = simplify_gen_subreg (SImode
, op
,
2044 GET_MODE (op
) == VOIDmode
2045 ? DImode
: GET_MODE (op
), 0);
2046 hi_half
[num
] = simplify_gen_subreg (SImode
, op
,
2047 GET_MODE (op
) == VOIDmode
2048 ? DImode
: GET_MODE (op
), 4);
2054 bfin_longcall_p (rtx op
, int call_cookie
)
2056 gcc_assert (GET_CODE (op
) == SYMBOL_REF
);
2057 if (call_cookie
& CALL_SHORT
)
2059 if (call_cookie
& CALL_LONG
)
2061 if (TARGET_LONG_CALLS
)
2066 /* Expand a call instruction. FNADDR is the call target, RETVAL the return value.
2067 COOKIE is a CONST_INT holding the call_cookie prepared init_cumulative_args.
2068 SIBCALL is nonzero if this is a sibling call. */
2071 bfin_expand_call (rtx retval
, rtx fnaddr
, rtx callarg1
, rtx cookie
, int sibcall
)
2073 rtx use
= NULL
, call
;
2074 rtx callee
= XEXP (fnaddr
, 0);
2075 int nelts
= 2 + !!sibcall
;
2077 rtx picreg
= get_hard_reg_initial_val (SImode
, FDPIC_REGNO
);
2080 /* In an untyped call, we can get NULL for operand 2. */
2081 if (cookie
== NULL_RTX
)
2082 cookie
= const0_rtx
;
2084 /* Static functions and indirect calls don't need the pic register. */
2085 if (!TARGET_FDPIC
&& flag_pic
2086 && GET_CODE (callee
) == SYMBOL_REF
2087 && !SYMBOL_REF_LOCAL_P (callee
))
2088 use_reg (&use
, pic_offset_table_rtx
);
2092 int caller_has_l1_text
, callee_has_l1_text
;
2094 caller_has_l1_text
= callee_has_l1_text
= 0;
2096 if (lookup_attribute ("l1_text",
2097 DECL_ATTRIBUTES (cfun
->decl
)) != NULL_TREE
)
2098 caller_has_l1_text
= 1;
2100 if (GET_CODE (callee
) == SYMBOL_REF
2101 && SYMBOL_REF_DECL (callee
) && DECL_P (SYMBOL_REF_DECL (callee
))
2104 DECL_ATTRIBUTES (SYMBOL_REF_DECL (callee
))) != NULL_TREE
)
2105 callee_has_l1_text
= 1;
2107 if (GET_CODE (callee
) != SYMBOL_REF
2108 || bfin_longcall_p (callee
, INTVAL (cookie
))
2109 || (GET_CODE (callee
) == SYMBOL_REF
2110 && !SYMBOL_REF_LOCAL_P (callee
)
2111 && TARGET_INLINE_PLT
)
2112 || caller_has_l1_text
!= callee_has_l1_text
2113 || (caller_has_l1_text
&& callee_has_l1_text
2114 && (GET_CODE (callee
) != SYMBOL_REF
2115 || !SYMBOL_REF_LOCAL_P (callee
))))
2118 if (! address_operand (addr
, Pmode
))
2119 addr
= force_reg (Pmode
, addr
);
2121 fnaddr
= gen_reg_rtx (SImode
);
2122 emit_insn (gen_load_funcdescsi (fnaddr
, addr
));
2123 fnaddr
= gen_rtx_MEM (Pmode
, fnaddr
);
2125 picreg
= gen_reg_rtx (SImode
);
2126 emit_insn (gen_load_funcdescsi (picreg
,
2127 plus_constant (addr
, 4)));
2132 else if ((!register_no_elim_operand (callee
, Pmode
)
2133 && GET_CODE (callee
) != SYMBOL_REF
)
2134 || (GET_CODE (callee
) == SYMBOL_REF
2135 && ((TARGET_ID_SHARED_LIBRARY
&& !TARGET_LEAF_ID_SHARED_LIBRARY
)
2136 || bfin_longcall_p (callee
, INTVAL (cookie
)))))
2138 callee
= copy_to_mode_reg (Pmode
, callee
);
2139 fnaddr
= gen_rtx_MEM (Pmode
, callee
);
2141 call
= gen_rtx_CALL (VOIDmode
, fnaddr
, callarg1
);
2144 call
= gen_rtx_SET (VOIDmode
, retval
, call
);
2146 pat
= gen_rtx_PARALLEL (VOIDmode
, rtvec_alloc (nelts
));
2148 XVECEXP (pat
, 0, n
++) = call
;
2150 XVECEXP (pat
, 0, n
++) = gen_rtx_USE (VOIDmode
, picreg
);
2151 XVECEXP (pat
, 0, n
++) = gen_rtx_USE (VOIDmode
, cookie
);
2153 XVECEXP (pat
, 0, n
++) = gen_rtx_RETURN (VOIDmode
);
2154 call
= emit_call_insn (pat
);
2156 CALL_INSN_FUNCTION_USAGE (call
) = use
;
2159 /* Return 1 if hard register REGNO can hold a value of machine-mode MODE. */
2162 hard_regno_mode_ok (int regno
, enum machine_mode mode
)
2164 /* Allow only dregs to store value of mode HI or QI */
2165 enum reg_class
class = REGNO_REG_CLASS (regno
);
2170 if (mode
== V2HImode
)
2171 return D_REGNO_P (regno
);
2172 if (class == CCREGS
)
2173 return mode
== BImode
;
2174 if (mode
== PDImode
|| mode
== V2PDImode
)
2175 return regno
== REG_A0
|| regno
== REG_A1
;
2177 /* Allow all normal 32-bit regs, except REG_M3, in case regclass ever comes
2178 up with a bad register class (such as ALL_REGS) for DImode. */
2180 return regno
< REG_M3
;
2183 && TEST_HARD_REG_BIT (reg_class_contents
[PROLOGUE_REGS
], regno
))
2186 return TEST_HARD_REG_BIT (reg_class_contents
[MOST_REGS
], regno
);
2189 /* Implements target hook vector_mode_supported_p. */
2192 bfin_vector_mode_supported_p (enum machine_mode mode
)
2194 return mode
== V2HImode
;
2197 /* Return the cost of moving data from a register in class CLASS1 to
2198 one in class CLASS2. A cost of 2 is the default. */
2201 bfin_register_move_cost (enum machine_mode mode
,
2202 enum reg_class class1
, enum reg_class class2
)
2204 /* These need secondary reloads, so they're more expensive. */
2205 if ((class1
== CCREGS
&& class2
!= DREGS
)
2206 || (class1
!= DREGS
&& class2
== CCREGS
))
2209 /* If optimizing for size, always prefer reg-reg over reg-memory moves. */
2213 /* There are some stalls involved when moving from a DREG to a different
2214 class reg, and using the value in one of the following instructions.
2215 Attempt to model this by slightly discouraging such moves. */
2216 if (class1
== DREGS
&& class2
!= DREGS
)
2219 if (GET_MODE_CLASS (mode
) == MODE_INT
)
2221 /* Discourage trying to use the accumulators. */
2222 if (TEST_HARD_REG_BIT (reg_class_contents
[class1
], REG_A0
)
2223 || TEST_HARD_REG_BIT (reg_class_contents
[class1
], REG_A1
)
2224 || TEST_HARD_REG_BIT (reg_class_contents
[class2
], REG_A0
)
2225 || TEST_HARD_REG_BIT (reg_class_contents
[class2
], REG_A1
))
2231 /* Return the cost of moving data of mode M between a
2232 register and memory. A value of 2 is the default; this cost is
2233 relative to those in `REGISTER_MOVE_COST'.
2235 ??? In theory L1 memory has single-cycle latency. We should add a switch
2236 that tells the compiler whether we expect to use only L1 memory for the
2237 program; it'll make the costs more accurate. */
2240 bfin_memory_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED
,
2241 enum reg_class
class,
2242 int in ATTRIBUTE_UNUSED
)
2244 /* Make memory accesses slightly more expensive than any register-register
2245 move. Also, penalize non-DP registers, since they need secondary
2246 reloads to load and store. */
2247 if (! reg_class_subset_p (class, DPREGS
))
2253 /* Inform reload about cases where moving X with a mode MODE to a register in
2254 CLASS requires an extra scratch register. Return the class needed for the
2255 scratch register. */
2257 static enum reg_class
2258 bfin_secondary_reload (bool in_p
, rtx x
, enum reg_class
class,
2259 enum machine_mode mode
, secondary_reload_info
*sri
)
2261 /* If we have HImode or QImode, we can only use DREGS as secondary registers;
2262 in most other cases we can also use PREGS. */
2263 enum reg_class default_class
= GET_MODE_SIZE (mode
) >= 4 ? DPREGS
: DREGS
;
2264 enum reg_class x_class
= NO_REGS
;
2265 enum rtx_code code
= GET_CODE (x
);
2268 x
= SUBREG_REG (x
), code
= GET_CODE (x
);
2271 int regno
= REGNO (x
);
2272 if (regno
>= FIRST_PSEUDO_REGISTER
)
2273 regno
= reg_renumber
[regno
];
2278 x_class
= REGNO_REG_CLASS (regno
);
2281 /* We can be asked to reload (plus (FP) (large_constant)) into a DREG.
2282 This happens as a side effect of register elimination, and we need
2283 a scratch register to do it. */
2284 if (fp_plus_const_operand (x
, mode
))
2286 rtx op2
= XEXP (x
, 1);
2287 int large_constant_p
= ! CONST_7BIT_IMM_P (INTVAL (op2
));
2289 if (class == PREGS
|| class == PREGS_CLOBBERED
)
2291 /* If destination is a DREG, we can do this without a scratch register
2292 if the constant is valid for an add instruction. */
2293 if ((class == DREGS
|| class == DPREGS
)
2294 && ! large_constant_p
)
2296 /* Reloading to anything other than a DREG? Use a PREG scratch
2298 sri
->icode
= CODE_FOR_reload_insi
;
2302 /* Data can usually be moved freely between registers of most classes.
2303 AREGS are an exception; they can only move to or from another register
2304 in AREGS or one in DREGS. They can also be assigned the constant 0. */
2305 if (x_class
== AREGS
|| x_class
== EVEN_AREGS
|| x_class
== ODD_AREGS
)
2306 return (class == DREGS
|| class == AREGS
|| class == EVEN_AREGS
2307 || class == ODD_AREGS
2310 if (class == AREGS
|| class == EVEN_AREGS
|| class == ODD_AREGS
)
2314 sri
->icode
= in_p
? CODE_FOR_reload_inpdi
: CODE_FOR_reload_outpdi
;
2318 if (x
!= const0_rtx
&& x_class
!= DREGS
)
2326 /* CCREGS can only be moved from/to DREGS. */
2327 if (class == CCREGS
&& x_class
!= DREGS
)
2329 if (x_class
== CCREGS
&& class != DREGS
)
2332 /* All registers other than AREGS can load arbitrary constants. The only
2333 case that remains is MEM. */
2335 if (! reg_class_subset_p (class, default_class
))
2336 return default_class
;
2341 /* Implement TARGET_HANDLE_OPTION. */
2344 bfin_handle_option (size_t code
, const char *arg
, int value
)
2348 case OPT_mshared_library_id_
:
2349 if (value
> MAX_LIBRARY_ID
)
2350 error ("-mshared-library-id=%s is not between 0 and %d",
2351 arg
, MAX_LIBRARY_ID
);
2352 bfin_lib_id_given
= 1;
2361 while ((p
= bfin_cpus
[i
].name
) != NULL
)
2363 if (strncmp (arg
, p
, strlen (p
)) == 0)
2370 error ("-mcpu=%s is not valid", arg
);
2374 bfin_cpu_type
= bfin_cpus
[i
].type
;
2376 q
= arg
+ strlen (p
);
2380 bfin_si_revision
= bfin_cpus
[i
].si_revision
;
2381 bfin_workarounds
|= bfin_cpus
[i
].workarounds
;
2383 else if (strcmp (q
, "-none") == 0)
2384 bfin_si_revision
= -1;
2385 else if (strcmp (q
, "-any") == 0)
2387 bfin_si_revision
= 0xffff;
2388 while (bfin_cpus
[i
].type
== bfin_cpu_type
)
2390 bfin_workarounds
|= bfin_cpus
[i
].workarounds
;
2396 unsigned int si_major
, si_minor
;
2399 rev_len
= strlen (q
);
2401 if (sscanf (q
, "-%u.%u%n", &si_major
, &si_minor
, &n
) != 2
2403 || si_major
> 0xff || si_minor
> 0xff)
2405 invalid_silicon_revision
:
2406 error ("-mcpu=%s has invalid silicon revision", arg
);
2410 bfin_si_revision
= (si_major
<< 8) | si_minor
;
2412 while (bfin_cpus
[i
].type
== bfin_cpu_type
2413 && bfin_cpus
[i
].si_revision
!= bfin_si_revision
)
2416 if (bfin_cpus
[i
].type
!= bfin_cpu_type
)
2417 goto invalid_silicon_revision
;
2419 bfin_workarounds
|= bfin_cpus
[i
].workarounds
;
2422 if (bfin_cpu_type
== BFIN_CPU_BF561
)
2423 warning (0, "bf561 support is incomplete yet.");
2433 static struct machine_function
*
2434 bfin_init_machine_status (void)
2436 struct machine_function
*f
;
2438 f
= ggc_alloc_cleared (sizeof (struct machine_function
));
2443 /* Implement the macro OVERRIDE_OPTIONS. */
2446 override_options (void)
2448 if (bfin_csync_anomaly
== 1)
2449 bfin_workarounds
|= WA_SPECULATIVE_SYNCS
;
2450 else if (bfin_csync_anomaly
== 0)
2451 bfin_workarounds
&= ~WA_SPECULATIVE_SYNCS
;
2453 if (bfin_specld_anomaly
== 1)
2454 bfin_workarounds
|= WA_SPECULATIVE_LOADS
;
2455 else if (bfin_specld_anomaly
== 0)
2456 bfin_workarounds
&= ~WA_SPECULATIVE_LOADS
;
2458 if (TARGET_OMIT_LEAF_FRAME_POINTER
)
2459 flag_omit_frame_pointer
= 1;
2461 /* Library identification */
2462 if (bfin_lib_id_given
&& ! TARGET_ID_SHARED_LIBRARY
)
2463 error ("-mshared-library-id= specified without -mid-shared-library");
2465 if (TARGET_ID_SHARED_LIBRARY
&& flag_pic
== 0)
2468 if (stack_limit_rtx
&& TARGET_STACK_CHECK_L1
)
2469 error ("Can't use multiple stack checking methods together.");
2471 if (TARGET_ID_SHARED_LIBRARY
&& TARGET_FDPIC
)
2472 error ("ID shared libraries and FD-PIC mode can't be used together.");
2474 /* Don't allow the user to specify -mid-shared-library and -msep-data
2475 together, as it makes little sense from a user's point of view... */
2476 if (TARGET_SEP_DATA
&& TARGET_ID_SHARED_LIBRARY
)
2477 error ("cannot specify both -msep-data and -mid-shared-library");
2478 /* ... internally, however, it's nearly the same. */
2479 if (TARGET_SEP_DATA
)
2480 target_flags
|= MASK_ID_SHARED_LIBRARY
| MASK_LEAF_ID_SHARED_LIBRARY
;
2482 /* There is no single unaligned SI op for PIC code. Sometimes we
2483 need to use ".4byte" and sometimes we need to use ".picptr".
2484 See bfin_assemble_integer for details. */
2486 targetm
.asm_out
.unaligned_op
.si
= 0;
2488 /* Silently turn off flag_pic if not doing FDPIC or ID shared libraries,
2489 since we don't support it and it'll just break. */
2490 if (flag_pic
&& !TARGET_FDPIC
&& !TARGET_ID_SHARED_LIBRARY
)
2493 flag_schedule_insns
= 0;
2495 /* Passes after sched2 can break the helpful TImode annotations that
2496 haifa-sched puts on every insn. Just do scheduling in reorg. */
2497 bfin_flag_schedule_insns2
= flag_schedule_insns_after_reload
;
2498 flag_schedule_insns_after_reload
= 0;
2500 init_machine_status
= bfin_init_machine_status
;
2503 /* Return the destination address of BRANCH.
2504 We need to use this instead of get_attr_length, because the
2505 cbranch_with_nops pattern conservatively sets its length to 6, and
2506 we still prefer to use shorter sequences. */
2509 branch_dest (rtx branch
)
2513 rtx pat
= PATTERN (branch
);
2514 if (GET_CODE (pat
) == PARALLEL
)
2515 pat
= XVECEXP (pat
, 0, 0);
2516 dest
= SET_SRC (pat
);
2517 if (GET_CODE (dest
) == IF_THEN_ELSE
)
2518 dest
= XEXP (dest
, 1);
2519 dest
= XEXP (dest
, 0);
2520 dest_uid
= INSN_UID (dest
);
2521 return INSN_ADDRESSES (dest_uid
);
2524 /* Return nonzero if INSN is annotated with a REG_BR_PROB note that indicates
2525 it's a branch that's predicted taken. */
2528 cbranch_predicted_taken_p (rtx insn
)
2530 rtx x
= find_reg_note (insn
, REG_BR_PROB
, 0);
2534 int pred_val
= INTVAL (XEXP (x
, 0));
2536 return pred_val
>= REG_BR_PROB_BASE
/ 2;
2542 /* Templates for use by asm_conditional_branch. */
2544 static const char *ccbranch_templates
[][3] = {
2545 { "if !cc jump %3;", "if cc jump 4 (bp); jump.s %3;", "if cc jump 6 (bp); jump.l %3;" },
2546 { "if cc jump %3;", "if !cc jump 4 (bp); jump.s %3;", "if !cc jump 6 (bp); jump.l %3;" },
2547 { "if !cc jump %3 (bp);", "if cc jump 4; jump.s %3;", "if cc jump 6; jump.l %3;" },
2548 { "if cc jump %3 (bp);", "if !cc jump 4; jump.s %3;", "if !cc jump 6; jump.l %3;" },
2551 /* Output INSN, which is a conditional branch instruction with operands
2554 We deal with the various forms of conditional branches that can be generated
2555 by bfin_reorg to prevent the hardware from doing speculative loads, by
2556 - emitting a sufficient number of nops, if N_NOPS is nonzero, or
2557 - always emitting the branch as predicted taken, if PREDICT_TAKEN is true.
2558 Either of these is only necessary if the branch is short, otherwise the
2559 template we use ends in an unconditional jump which flushes the pipeline
2563 asm_conditional_branch (rtx insn
, rtx
*operands
, int n_nops
, int predict_taken
)
2565 int offset
= branch_dest (insn
) - INSN_ADDRESSES (INSN_UID (insn
));
2566 /* Note : offset for instructions like if cc jmp; jump.[sl] offset
2567 is to be taken from start of if cc rather than jump.
2568 Range for jump.s is (-4094, 4096) instead of (-4096, 4094)
2570 int len
= (offset
>= -1024 && offset
<= 1022 ? 0
2571 : offset
>= -4094 && offset
<= 4096 ? 1
2573 int bp
= predict_taken
&& len
== 0 ? 1 : cbranch_predicted_taken_p (insn
);
2574 int idx
= (bp
<< 1) | (GET_CODE (operands
[0]) == EQ
? BRF
: BRT
);
2575 output_asm_insn (ccbranch_templates
[idx
][len
], operands
);
2576 gcc_assert (n_nops
== 0 || !bp
);
2578 while (n_nops
-- > 0)
2579 output_asm_insn ("nop;", NULL
);
2582 /* Emit rtl for a comparison operation CMP in mode MODE. Operands have been
2583 stored in bfin_compare_op0 and bfin_compare_op1 already. */
2586 bfin_gen_compare (rtx cmp
, enum machine_mode mode ATTRIBUTE_UNUSED
)
2588 enum rtx_code code1
, code2
;
2589 rtx op0
= bfin_compare_op0
, op1
= bfin_compare_op1
;
2590 rtx tem
= bfin_cc_rtx
;
2591 enum rtx_code code
= GET_CODE (cmp
);
2593 /* If we have a BImode input, then we already have a compare result, and
2594 do not need to emit another comparison. */
2595 if (GET_MODE (op0
) == BImode
)
2597 gcc_assert ((code
== NE
|| code
== EQ
) && op1
== const0_rtx
);
2598 tem
= op0
, code2
= code
;
2603 /* bfin has these conditions */
2613 code1
= reverse_condition (code
);
2617 emit_insn (gen_rtx_SET (BImode
, tem
,
2618 gen_rtx_fmt_ee (code1
, BImode
, op0
, op1
)));
2621 return gen_rtx_fmt_ee (code2
, BImode
, tem
, CONST0_RTX (BImode
));
2624 /* Return nonzero iff C has exactly one bit set if it is interpreted
2625 as a 32-bit constant. */
2628 log2constp (unsigned HOST_WIDE_INT c
)
2631 return c
!= 0 && (c
& (c
-1)) == 0;
2634 /* Returns the number of consecutive least significant zeros in the binary
2635 representation of *V.
2636 We modify *V to contain the original value arithmetically shifted right by
2637 the number of zeroes. */
2640 shiftr_zero (HOST_WIDE_INT
*v
)
2642 unsigned HOST_WIDE_INT tmp
= *v
;
2643 unsigned HOST_WIDE_INT sgn
;
2649 sgn
= tmp
& ((unsigned HOST_WIDE_INT
) 1 << (HOST_BITS_PER_WIDE_INT
- 1));
2650 while ((tmp
& 0x1) == 0 && n
<= 32)
2652 tmp
= (tmp
>> 1) | sgn
;
2659 /* After reload, split the load of an immediate constant. OPERANDS are the
2660 operands of the movsi_insn pattern which we are splitting. We return
2661 nonzero if we emitted a sequence to load the constant, zero if we emitted
2662 nothing because we want to use the splitter's default sequence. */
2665 split_load_immediate (rtx operands
[])
2667 HOST_WIDE_INT val
= INTVAL (operands
[1]);
2669 HOST_WIDE_INT shifted
= val
;
2670 HOST_WIDE_INT shifted_compl
= ~val
;
2671 int num_zero
= shiftr_zero (&shifted
);
2672 int num_compl_zero
= shiftr_zero (&shifted_compl
);
2673 unsigned int regno
= REGNO (operands
[0]);
2675 /* This case takes care of single-bit set/clear constants, which we could
2676 also implement with BITSET/BITCLR. */
2678 && shifted
>= -32768 && shifted
< 65536
2679 && (D_REGNO_P (regno
)
2680 || (regno
>= REG_P0
&& regno
<= REG_P7
&& num_zero
<= 2)))
2682 emit_insn (gen_movsi (operands
[0], GEN_INT (shifted
)));
2683 emit_insn (gen_ashlsi3 (operands
[0], operands
[0], GEN_INT (num_zero
)));
2688 tmp
|= -(tmp
& 0x8000);
2690 /* If high word has one bit set or clear, try to use a bit operation. */
2691 if (D_REGNO_P (regno
))
2693 if (log2constp (val
& 0xFFFF0000))
2695 emit_insn (gen_movsi (operands
[0], GEN_INT (val
& 0xFFFF)));
2696 emit_insn (gen_iorsi3 (operands
[0], operands
[0], GEN_INT (val
& 0xFFFF0000)));
2699 else if (log2constp (val
| 0xFFFF) && (val
& 0x8000) != 0)
2701 emit_insn (gen_movsi (operands
[0], GEN_INT (tmp
)));
2702 emit_insn (gen_andsi3 (operands
[0], operands
[0], GEN_INT (val
| 0xFFFF)));
2706 if (D_REGNO_P (regno
))
2708 if (CONST_7BIT_IMM_P (tmp
))
2710 emit_insn (gen_movsi (operands
[0], GEN_INT (tmp
)));
2711 emit_insn (gen_movstricthi_high (operands
[0], GEN_INT (val
& -65536)));
2715 if ((val
& 0xFFFF0000) == 0)
2717 emit_insn (gen_movsi (operands
[0], const0_rtx
));
2718 emit_insn (gen_movsi_low (operands
[0], operands
[0], operands
[1]));
2722 if ((val
& 0xFFFF0000) == 0xFFFF0000)
2724 emit_insn (gen_movsi (operands
[0], constm1_rtx
));
2725 emit_insn (gen_movsi_low (operands
[0], operands
[0], operands
[1]));
2730 /* Need DREGs for the remaining case. */
2735 && num_compl_zero
&& CONST_7BIT_IMM_P (shifted_compl
))
2737 /* If optimizing for size, generate a sequence that has more instructions
2739 emit_insn (gen_movsi (operands
[0], GEN_INT (shifted_compl
)));
2740 emit_insn (gen_ashlsi3 (operands
[0], operands
[0],
2741 GEN_INT (num_compl_zero
)));
2742 emit_insn (gen_one_cmplsi2 (operands
[0], operands
[0]));
2748 /* Return true if the legitimate memory address for a memory operand of mode
2749 MODE. Return false if not. */
2752 bfin_valid_add (enum machine_mode mode
, HOST_WIDE_INT value
)
2754 unsigned HOST_WIDE_INT v
= value
> 0 ? value
: -value
;
2755 int sz
= GET_MODE_SIZE (mode
);
2756 int shift
= sz
== 1 ? 0 : sz
== 2 ? 1 : 2;
2757 /* The usual offsettable_memref machinery doesn't work so well for this
2758 port, so we deal with the problem here. */
2759 if (value
> 0 && sz
== 8)
2761 return (v
& ~(0x7fff << shift
)) == 0;
2765 bfin_valid_reg_p (unsigned int regno
, int strict
, enum machine_mode mode
,
2766 enum rtx_code outer_code
)
2769 return REGNO_OK_FOR_BASE_STRICT_P (regno
, mode
, outer_code
, SCRATCH
);
2771 return REGNO_OK_FOR_BASE_NONSTRICT_P (regno
, mode
, outer_code
, SCRATCH
);
2775 bfin_legitimate_address_p (enum machine_mode mode
, rtx x
, int strict
)
2777 switch (GET_CODE (x
)) {
2779 if (bfin_valid_reg_p (REGNO (x
), strict
, mode
, MEM
))
2783 if (REG_P (XEXP (x
, 0))
2784 && bfin_valid_reg_p (REGNO (XEXP (x
, 0)), strict
, mode
, PLUS
)
2785 && ((GET_CODE (XEXP (x
, 1)) == UNSPEC
&& mode
== SImode
)
2786 || (GET_CODE (XEXP (x
, 1)) == CONST_INT
2787 && bfin_valid_add (mode
, INTVAL (XEXP (x
, 1))))))
2792 if (LEGITIMATE_MODE_FOR_AUTOINC_P (mode
)
2793 && REG_P (XEXP (x
, 0))
2794 && bfin_valid_reg_p (REGNO (XEXP (x
, 0)), strict
, mode
, POST_INC
))
2797 if (LEGITIMATE_MODE_FOR_AUTOINC_P (mode
)
2798 && XEXP (x
, 0) == stack_pointer_rtx
2799 && REG_P (XEXP (x
, 0))
2800 && bfin_valid_reg_p (REGNO (XEXP (x
, 0)), strict
, mode
, PRE_DEC
))
2809 /* Decide whether we can force certain constants to memory. If we
2810 decide we can't, the caller should be able to cope with it in
2814 bfin_cannot_force_const_mem (rtx x ATTRIBUTE_UNUSED
)
2816 /* We have only one class of non-legitimate constants, and our movsi
2817 expander knows how to handle them. Dropping these constants into the
2818 data section would only shift the problem - we'd still get relocs
2819 outside the object, in the data section rather than the text section. */
2823 /* Ensure that for any constant of the form symbol + offset, the offset
2824 remains within the object. Any other constants are ok.
2825 This ensures that flat binaries never have to deal with relocations
2826 crossing section boundaries. */
2829 bfin_legitimate_constant_p (rtx x
)
2832 HOST_WIDE_INT offset
;
2834 if (GET_CODE (x
) != CONST
)
2838 gcc_assert (GET_CODE (x
) == PLUS
);
2842 if (GET_CODE (sym
) != SYMBOL_REF
2843 || GET_CODE (x
) != CONST_INT
)
2845 offset
= INTVAL (x
);
2847 if (SYMBOL_REF_DECL (sym
) == 0)
2850 || offset
>= int_size_in_bytes (TREE_TYPE (SYMBOL_REF_DECL (sym
))))
2857 bfin_rtx_costs (rtx x
, int code
, int outer_code
, int *total
)
2859 int cost2
= COSTS_N_INSNS (1);
2865 if (outer_code
== SET
|| outer_code
== PLUS
)
2866 *total
= CONST_7BIT_IMM_P (INTVAL (x
)) ? 0 : cost2
;
2867 else if (outer_code
== AND
)
2868 *total
= log2constp (~INTVAL (x
)) ? 0 : cost2
;
2869 else if (outer_code
== LE
|| outer_code
== LT
|| outer_code
== EQ
)
2870 *total
= (INTVAL (x
) >= -4 && INTVAL (x
) <= 3) ? 0 : cost2
;
2871 else if (outer_code
== LEU
|| outer_code
== LTU
)
2872 *total
= (INTVAL (x
) >= 0 && INTVAL (x
) <= 7) ? 0 : cost2
;
2873 else if (outer_code
== MULT
)
2874 *total
= (INTVAL (x
) == 2 || INTVAL (x
) == 4) ? 0 : cost2
;
2875 else if (outer_code
== ASHIFT
&& (INTVAL (x
) == 1 || INTVAL (x
) == 2))
2877 else if (outer_code
== ASHIFT
|| outer_code
== ASHIFTRT
2878 || outer_code
== LSHIFTRT
)
2879 *total
= (INTVAL (x
) >= 0 && INTVAL (x
) <= 31) ? 0 : cost2
;
2880 else if (outer_code
== IOR
|| outer_code
== XOR
)
2881 *total
= (INTVAL (x
) & (INTVAL (x
) - 1)) == 0 ? 0 : cost2
;
2890 *total
= COSTS_N_INSNS (2);
2896 if (GET_MODE (x
) == SImode
)
2898 if (GET_CODE (op0
) == MULT
2899 && GET_CODE (XEXP (op0
, 1)) == CONST_INT
)
2901 HOST_WIDE_INT val
= INTVAL (XEXP (op0
, 1));
2902 if (val
== 2 || val
== 4)
2905 *total
+= rtx_cost (XEXP (op0
, 0), outer_code
);
2906 *total
+= rtx_cost (op1
, outer_code
);
2911 if (GET_CODE (op0
) != REG
2912 && (GET_CODE (op0
) != SUBREG
|| GET_CODE (SUBREG_REG (op0
)) != REG
))
2913 *total
+= rtx_cost (op0
, SET
);
2914 #if 0 /* We'd like to do this for accuracy, but it biases the loop optimizer
2915 towards creating too many induction variables. */
2916 if (!reg_or_7bit_operand (op1
, SImode
))
2917 *total
+= rtx_cost (op1
, SET
);
2920 else if (GET_MODE (x
) == DImode
)
2923 if (GET_CODE (op1
) != CONST_INT
2924 || !CONST_7BIT_IMM_P (INTVAL (op1
)))
2925 *total
+= rtx_cost (op1
, PLUS
);
2926 if (GET_CODE (op0
) != REG
2927 && (GET_CODE (op0
) != SUBREG
|| GET_CODE (SUBREG_REG (op0
)) != REG
))
2928 *total
+= rtx_cost (op0
, PLUS
);
2933 if (GET_MODE (x
) == DImode
)
2942 if (GET_MODE (x
) == DImode
)
2949 if (GET_CODE (op0
) != REG
2950 && (GET_CODE (op0
) != SUBREG
|| GET_CODE (SUBREG_REG (op0
)) != REG
))
2951 *total
+= rtx_cost (op0
, code
);
2961 /* Handle special cases of IOR: rotates, ALIGN insns, movstricthi_high. */
2964 if ((GET_CODE (op0
) == LSHIFTRT
&& GET_CODE (op1
) == ASHIFT
)
2965 || (GET_CODE (op0
) == ASHIFT
&& GET_CODE (op1
) == ZERO_EXTEND
)
2966 || (GET_CODE (op0
) == ASHIFT
&& GET_CODE (op1
) == LSHIFTRT
)
2967 || (GET_CODE (op0
) == AND
&& GET_CODE (op1
) == CONST_INT
))
2974 if (GET_CODE (op0
) != REG
2975 && (GET_CODE (op0
) != SUBREG
|| GET_CODE (SUBREG_REG (op0
)) != REG
))
2976 *total
+= rtx_cost (op0
, code
);
2978 if (GET_MODE (x
) == DImode
)
2984 if (GET_MODE (x
) != SImode
)
2989 if (! rhs_andsi3_operand (XEXP (x
, 1), SImode
))
2990 *total
+= rtx_cost (XEXP (x
, 1), code
);
2994 if (! regorlog2_operand (XEXP (x
, 1), SImode
))
2995 *total
+= rtx_cost (XEXP (x
, 1), code
);
3002 if (outer_code
== SET
3003 && XEXP (x
, 1) == const1_rtx
3004 && GET_CODE (XEXP (x
, 2)) == CONST_INT
)
3020 if (GET_CODE (op0
) == GET_CODE (op1
)
3021 && (GET_CODE (op0
) == ZERO_EXTEND
3022 || GET_CODE (op0
) == SIGN_EXTEND
))
3024 *total
= COSTS_N_INSNS (1);
3025 op0
= XEXP (op0
, 0);
3026 op1
= XEXP (op1
, 0);
3028 else if (optimize_size
)
3029 *total
= COSTS_N_INSNS (1);
3031 *total
= COSTS_N_INSNS (3);
3033 if (GET_CODE (op0
) != REG
3034 && (GET_CODE (op0
) != SUBREG
|| GET_CODE (SUBREG_REG (op0
)) != REG
))
3035 *total
+= rtx_cost (op0
, MULT
);
3036 if (GET_CODE (op1
) != REG
3037 && (GET_CODE (op1
) != SUBREG
|| GET_CODE (SUBREG_REG (op1
)) != REG
))
3038 *total
+= rtx_cost (op1
, MULT
);
3044 *total
= COSTS_N_INSNS (32);
3049 if (outer_code
== SET
)
3058 /* Used for communication between {push,pop}_multiple_operation (which
3059 we use not only as a predicate) and the corresponding output functions. */
3060 static int first_preg_to_save
, first_dreg_to_save
;
3063 push_multiple_operation (rtx op
, enum machine_mode mode ATTRIBUTE_UNUSED
)
3065 int lastdreg
= 8, lastpreg
= 6;
3068 first_preg_to_save
= lastpreg
;
3069 first_dreg_to_save
= lastdreg
;
3070 for (i
= 1, group
= 0; i
< XVECLEN (op
, 0) - 1; i
++)
3072 rtx t
= XVECEXP (op
, 0, i
);
3076 if (GET_CODE (t
) != SET
)
3080 dest
= SET_DEST (t
);
3081 if (GET_CODE (dest
) != MEM
|| ! REG_P (src
))
3083 dest
= XEXP (dest
, 0);
3084 if (GET_CODE (dest
) != PLUS
3085 || ! REG_P (XEXP (dest
, 0))
3086 || REGNO (XEXP (dest
, 0)) != REG_SP
3087 || GET_CODE (XEXP (dest
, 1)) != CONST_INT
3088 || INTVAL (XEXP (dest
, 1)) != -i
* 4)
3091 regno
= REGNO (src
);
3094 if (D_REGNO_P (regno
))
3097 first_dreg_to_save
= lastdreg
= regno
- REG_R0
;
3099 else if (regno
>= REG_P0
&& regno
<= REG_P7
)
3102 first_preg_to_save
= lastpreg
= regno
- REG_P0
;
3112 if (regno
>= REG_P0
&& regno
<= REG_P7
)
3115 first_preg_to_save
= lastpreg
= regno
- REG_P0
;
3117 else if (regno
!= REG_R0
+ lastdreg
+ 1)
3122 else if (group
== 2)
3124 if (regno
!= REG_P0
+ lastpreg
+ 1)
3133 pop_multiple_operation (rtx op
, enum machine_mode mode ATTRIBUTE_UNUSED
)
3135 int lastdreg
= 8, lastpreg
= 6;
3138 for (i
= 1, group
= 0; i
< XVECLEN (op
, 0); i
++)
3140 rtx t
= XVECEXP (op
, 0, i
);
3144 if (GET_CODE (t
) != SET
)
3148 dest
= SET_DEST (t
);
3149 if (GET_CODE (src
) != MEM
|| ! REG_P (dest
))
3151 src
= XEXP (src
, 0);
3155 if (! REG_P (src
) || REGNO (src
) != REG_SP
)
3158 else if (GET_CODE (src
) != PLUS
3159 || ! REG_P (XEXP (src
, 0))
3160 || REGNO (XEXP (src
, 0)) != REG_SP
3161 || GET_CODE (XEXP (src
, 1)) != CONST_INT
3162 || INTVAL (XEXP (src
, 1)) != (i
- 1) * 4)
3165 regno
= REGNO (dest
);
3168 if (regno
== REG_R7
)
3173 else if (regno
!= REG_P0
+ lastpreg
- 1)
3178 else if (group
== 1)
3180 if (regno
!= REG_R0
+ lastdreg
- 1)
3186 first_dreg_to_save
= lastdreg
;
3187 first_preg_to_save
= lastpreg
;
3191 /* Emit assembly code for one multi-register push described by INSN, with
3192 operands in OPERANDS. */
3195 output_push_multiple (rtx insn
, rtx
*operands
)
3200 /* Validate the insn again, and compute first_[dp]reg_to_save. */
3201 ok
= push_multiple_operation (PATTERN (insn
), VOIDmode
);
3204 if (first_dreg_to_save
== 8)
3205 sprintf (buf
, "[--sp] = ( p5:%d );\n", first_preg_to_save
);
3206 else if (first_preg_to_save
== 6)
3207 sprintf (buf
, "[--sp] = ( r7:%d );\n", first_dreg_to_save
);
3209 sprintf (buf
, "[--sp] = ( r7:%d, p5:%d );\n",
3210 first_dreg_to_save
, first_preg_to_save
);
3212 output_asm_insn (buf
, operands
);
3215 /* Emit assembly code for one multi-register pop described by INSN, with
3216 operands in OPERANDS. */
3219 output_pop_multiple (rtx insn
, rtx
*operands
)
3224 /* Validate the insn again, and compute first_[dp]reg_to_save. */
3225 ok
= pop_multiple_operation (PATTERN (insn
), VOIDmode
);
3228 if (first_dreg_to_save
== 8)
3229 sprintf (buf
, "( p5:%d ) = [sp++];\n", first_preg_to_save
);
3230 else if (first_preg_to_save
== 6)
3231 sprintf (buf
, "( r7:%d ) = [sp++];\n", first_dreg_to_save
);
3233 sprintf (buf
, "( r7:%d, p5:%d ) = [sp++];\n",
3234 first_dreg_to_save
, first_preg_to_save
);
3236 output_asm_insn (buf
, operands
);
3239 /* Adjust DST and SRC by OFFSET bytes, and generate one move in mode MODE. */
3242 single_move_for_movmem (rtx dst
, rtx src
, enum machine_mode mode
, HOST_WIDE_INT offset
)
3244 rtx scratch
= gen_reg_rtx (mode
);
3247 srcmem
= adjust_address_nv (src
, mode
, offset
);
3248 dstmem
= adjust_address_nv (dst
, mode
, offset
);
3249 emit_move_insn (scratch
, srcmem
);
3250 emit_move_insn (dstmem
, scratch
);
3253 /* Expand a string move operation of COUNT_EXP bytes from SRC to DST, with
3254 alignment ALIGN_EXP. Return true if successful, false if we should fall
3255 back on a different method. */
3258 bfin_expand_movmem (rtx dst
, rtx src
, rtx count_exp
, rtx align_exp
)
3260 rtx srcreg
, destreg
, countreg
;
3261 HOST_WIDE_INT align
= 0;
3262 unsigned HOST_WIDE_INT count
= 0;
3264 if (GET_CODE (align_exp
) == CONST_INT
)
3265 align
= INTVAL (align_exp
);
3266 if (GET_CODE (count_exp
) == CONST_INT
)
3268 count
= INTVAL (count_exp
);
3270 if (!TARGET_INLINE_ALL_STRINGOPS
&& count
> 64)
3275 /* If optimizing for size, only do single copies inline. */
3278 if (count
== 2 && align
< 2)
3280 if (count
== 4 && align
< 4)
3282 if (count
!= 1 && count
!= 2 && count
!= 4)
3285 if (align
< 2 && count
!= 1)
3288 destreg
= copy_to_mode_reg (Pmode
, XEXP (dst
, 0));
3289 if (destreg
!= XEXP (dst
, 0))
3290 dst
= replace_equiv_address_nv (dst
, destreg
);
3291 srcreg
= copy_to_mode_reg (Pmode
, XEXP (src
, 0));
3292 if (srcreg
!= XEXP (src
, 0))
3293 src
= replace_equiv_address_nv (src
, srcreg
);
3295 if (count
!= 0 && align
>= 2)
3297 unsigned HOST_WIDE_INT offset
= 0;
3301 if ((count
& ~3) == 4)
3303 single_move_for_movmem (dst
, src
, SImode
, offset
);
3306 else if (count
& ~3)
3308 HOST_WIDE_INT new_count
= ((count
>> 2) & 0x3fffffff) - 1;
3309 countreg
= copy_to_mode_reg (Pmode
, GEN_INT (new_count
));
3311 emit_insn (gen_rep_movsi (destreg
, srcreg
, countreg
, destreg
, srcreg
));
3315 single_move_for_movmem (dst
, src
, HImode
, offset
);
3321 if ((count
& ~1) == 2)
3323 single_move_for_movmem (dst
, src
, HImode
, offset
);
3326 else if (count
& ~1)
3328 HOST_WIDE_INT new_count
= ((count
>> 1) & 0x7fffffff) - 1;
3329 countreg
= copy_to_mode_reg (Pmode
, GEN_INT (new_count
));
3331 emit_insn (gen_rep_movhi (destreg
, srcreg
, countreg
, destreg
, srcreg
));
3336 single_move_for_movmem (dst
, src
, QImode
, offset
);
3343 /* Compute the alignment for a local variable.
3344 TYPE is the data type, and ALIGN is the alignment that
3345 the object would ordinarily have. The value of this macro is used
3346 instead of that alignment to align the object. */
3349 bfin_local_alignment (tree type
, int align
)
3351 /* Increasing alignment for (relatively) big types allows the builtin
3352 memcpy can use 32 bit loads/stores. */
3353 if (TYPE_SIZE (type
)
3354 && TREE_CODE (TYPE_SIZE (type
)) == INTEGER_CST
3355 && (TREE_INT_CST_LOW (TYPE_SIZE (type
)) > 8
3356 || TREE_INT_CST_HIGH (TYPE_SIZE (type
))) && align
< 32)
3361 /* Implement TARGET_SCHED_ISSUE_RATE. */
3364 bfin_issue_rate (void)
3370 bfin_adjust_cost (rtx insn
, rtx link
, rtx dep_insn
, int cost
)
3372 enum attr_type insn_type
, dep_insn_type
;
3373 int dep_insn_code_number
;
3375 /* Anti and output dependencies have zero cost. */
3376 if (REG_NOTE_KIND (link
) != 0)
3379 dep_insn_code_number
= recog_memoized (dep_insn
);
3381 /* If we can't recognize the insns, we can't really do anything. */
3382 if (dep_insn_code_number
< 0 || recog_memoized (insn
) < 0)
3385 insn_type
= get_attr_type (insn
);
3386 dep_insn_type
= get_attr_type (dep_insn
);
3388 if (dep_insn_type
== TYPE_MOVE
|| dep_insn_type
== TYPE_MCLD
)
3390 rtx pat
= PATTERN (dep_insn
);
3391 if (GET_CODE (pat
) == PARALLEL
)
3392 pat
= XVECEXP (pat
, 0, 0);
3393 rtx dest
= SET_DEST (pat
);
3394 rtx src
= SET_SRC (pat
);
3395 if (! ADDRESS_REGNO_P (REGNO (dest
))
3396 || ! (MEM_P (src
) || D_REGNO_P (REGNO (src
))))
3398 return cost
+ (dep_insn_type
== TYPE_MOVE
? 4 : 3);
3405 /* Increment the counter for the number of loop instructions in the
3406 current function. */
3409 bfin_hardware_loop (void)
3411 cfun
->machine
->has_hardware_loops
++;
3414 /* Maximum loop nesting depth. */
3415 #define MAX_LOOP_DEPTH 2
3417 /* Maximum size of a loop. */
3418 #define MAX_LOOP_LENGTH 2042
3420 /* Maximum distance of the LSETUP instruction from the loop start. */
3421 #define MAX_LSETUP_DISTANCE 30
3423 /* We need to keep a vector of loops */
3424 typedef struct loop_info
*loop_info
;
3425 DEF_VEC_P (loop_info
);
3426 DEF_VEC_ALLOC_P (loop_info
,heap
);
3428 /* Information about a loop we have found (or are in the process of
3430 struct loop_info
GTY (())
3432 /* loop number, for dumps */
3435 /* All edges that jump into and out of the loop. */
3436 VEC(edge
,gc
) *incoming
;
3438 /* We can handle two cases: all incoming edges have the same destination
3439 block, or all incoming edges have the same source block. These two
3440 members are set to the common source or destination we found, or NULL
3441 if different blocks were found. If both are NULL the loop can't be
3443 basic_block incoming_src
;
3444 basic_block incoming_dest
;
3446 /* First block in the loop. This is the one branched to by the loop_end
3450 /* Last block in the loop (the one with the loop_end insn). */
3453 /* The successor block of the loop. This is the one the loop_end insn
3455 basic_block successor
;
3457 /* The last instruction in the tail. */
3460 /* The loop_end insn. */
3463 /* The iteration register. */
3466 /* The new initialization insn. */
3469 /* The new initialization instruction. */
3472 /* The new label placed at the beginning of the loop. */
3475 /* The new label placed at the end of the loop. */
3478 /* The length of the loop. */
3481 /* The nesting depth of the loop. */
3484 /* Nonzero if we can't optimize this loop. */
3487 /* True if we have visited this loop. */
3490 /* True if this loop body clobbers any of LC0, LT0, or LB0. */
3493 /* True if this loop body clobbers any of LC1, LT1, or LB1. */
3496 /* Next loop in the graph. */
3497 struct loop_info
*next
;
3499 /* Immediate outer loop of this loop. */
3500 struct loop_info
*outer
;
3502 /* Vector of blocks only within the loop, including those within
3504 VEC (basic_block
,heap
) *blocks
;
3506 /* Same information in a bitmap. */
3507 bitmap block_bitmap
;
3509 /* Vector of inner loops within this loop */
3510 VEC (loop_info
,heap
) *loops
;
3514 bfin_dump_loops (loop_info loops
)
3518 for (loop
= loops
; loop
; loop
= loop
->next
)
3524 fprintf (dump_file
, ";; loop %d: ", loop
->loop_no
);
3526 fprintf (dump_file
, "(bad) ");
3527 fprintf (dump_file
, "{head:%d, depth:%d}", loop
->head
->index
, loop
->depth
);
3529 fprintf (dump_file
, " blocks: [ ");
3530 for (ix
= 0; VEC_iterate (basic_block
, loop
->blocks
, ix
, b
); ix
++)
3531 fprintf (dump_file
, "%d ", b
->index
);
3532 fprintf (dump_file
, "] ");
3534 fprintf (dump_file
, " inner loops: [ ");
3535 for (ix
= 0; VEC_iterate (loop_info
, loop
->loops
, ix
, i
); ix
++)
3536 fprintf (dump_file
, "%d ", i
->loop_no
);
3537 fprintf (dump_file
, "]\n");
3539 fprintf (dump_file
, "\n");
3542 /* Scan the blocks of LOOP (and its inferiors) looking for basic block
3543 BB. Return true, if we find it. */
3546 bfin_bb_in_loop (loop_info loop
, basic_block bb
)
3548 return bitmap_bit_p (loop
->block_bitmap
, bb
->index
);
3551 /* Scan the blocks of LOOP (and its inferiors) looking for uses of
3552 REG. Return true, if we find any. Don't count the loop's loop_end
3553 insn if it matches LOOP_END. */
3556 bfin_scan_loop (loop_info loop
, rtx reg
, rtx loop_end
)
3561 for (ix
= 0; VEC_iterate (basic_block
, loop
->blocks
, ix
, bb
); ix
++)
3565 for (insn
= BB_HEAD (bb
);
3566 insn
!= NEXT_INSN (BB_END (bb
));
3567 insn
= NEXT_INSN (insn
))
3571 if (insn
== loop_end
)
3573 if (reg_mentioned_p (reg
, PATTERN (insn
)))
3580 /* Estimate the length of INSN conservatively. */
3583 length_for_loop (rtx insn
)
3586 if (JUMP_P (insn
) && any_condjump_p (insn
) && !optimize_size
)
3588 if (ENABLE_WA_SPECULATIVE_SYNCS
)
3590 else if (ENABLE_WA_SPECULATIVE_LOADS
)
3593 else if (LABEL_P (insn
))
3595 if (ENABLE_WA_SPECULATIVE_SYNCS
)
3600 length
+= get_attr_length (insn
);
3605 /* Optimize LOOP. */
3608 bfin_optimize_loop (loop_info loop
)
3612 rtx insn
, init_insn
, last_insn
, nop_insn
;
3613 rtx loop_init
, start_label
, end_label
;
3614 rtx reg_lc0
, reg_lc1
, reg_lt0
, reg_lt1
, reg_lb0
, reg_lb1
;
3616 rtx lc_reg
, lt_reg
, lb_reg
;
3620 int inner_depth
= 0;
3630 fprintf (dump_file
, ";; loop %d bad when found\n", loop
->loop_no
);
3634 /* Every loop contains in its list of inner loops every loop nested inside
3635 it, even if there are intermediate loops. This works because we're doing
3636 a depth-first search here and never visit a loop more than once. */
3637 for (ix
= 0; VEC_iterate (loop_info
, loop
->loops
, ix
, inner
); ix
++)
3639 bfin_optimize_loop (inner
);
3641 if (!inner
->bad
&& inner_depth
< inner
->depth
)
3643 inner_depth
= inner
->depth
;
3645 loop
->clobber_loop0
|= inner
->clobber_loop0
;
3646 loop
->clobber_loop1
|= inner
->clobber_loop1
;
3650 loop
->depth
= inner_depth
+ 1;
3651 if (loop
->depth
> MAX_LOOP_DEPTH
)
3654 fprintf (dump_file
, ";; loop %d too deep\n", loop
->loop_no
);
3658 /* Get the loop iteration register. */
3659 iter_reg
= loop
->iter_reg
;
3661 if (!DPREG_P (iter_reg
))
3664 fprintf (dump_file
, ";; loop %d iteration count NOT in PREG or DREG\n",
3669 if (loop
->incoming_src
)
3671 /* Make sure the predecessor is before the loop start label, as required by
3672 the LSETUP instruction. */
3674 for (insn
= BB_END (loop
->incoming_src
);
3675 insn
&& insn
!= loop
->start_label
;
3676 insn
= NEXT_INSN (insn
))
3677 length
+= length_for_loop (insn
);
3682 fprintf (dump_file
, ";; loop %d lsetup not before loop_start\n",
3687 if (length
> MAX_LSETUP_DISTANCE
)
3690 fprintf (dump_file
, ";; loop %d lsetup too far away\n", loop
->loop_no
);
3695 /* Check if start_label appears before loop_end and calculate the
3696 offset between them. We calculate the length of instructions
3699 for (insn
= loop
->start_label
;
3700 insn
&& insn
!= loop
->loop_end
;
3701 insn
= NEXT_INSN (insn
))
3702 length
+= length_for_loop (insn
);
3707 fprintf (dump_file
, ";; loop %d start_label not before loop_end\n",
3712 loop
->length
= length
;
3713 if (loop
->length
> MAX_LOOP_LENGTH
)
3716 fprintf (dump_file
, ";; loop %d too long\n", loop
->loop_no
);
3720 /* Scan all the blocks to make sure they don't use iter_reg. */
3721 if (bfin_scan_loop (loop
, iter_reg
, loop
->loop_end
))
3724 fprintf (dump_file
, ";; loop %d uses iterator\n", loop
->loop_no
);
3728 /* Scan all the insns to see if the loop body clobber
3729 any hardware loop registers. */
3731 reg_lc0
= gen_rtx_REG (SImode
, REG_LC0
);
3732 reg_lc1
= gen_rtx_REG (SImode
, REG_LC1
);
3733 reg_lt0
= gen_rtx_REG (SImode
, REG_LT0
);
3734 reg_lt1
= gen_rtx_REG (SImode
, REG_LT1
);
3735 reg_lb0
= gen_rtx_REG (SImode
, REG_LB0
);
3736 reg_lb1
= gen_rtx_REG (SImode
, REG_LB1
);
3738 for (ix
= 0; VEC_iterate (basic_block
, loop
->blocks
, ix
, bb
); ix
++)
3742 for (insn
= BB_HEAD (bb
);
3743 insn
!= NEXT_INSN (BB_END (bb
));
3744 insn
= NEXT_INSN (insn
))
3749 if (reg_set_p (reg_lc0
, insn
)
3750 || reg_set_p (reg_lt0
, insn
)
3751 || reg_set_p (reg_lb0
, insn
))
3752 loop
->clobber_loop0
= 1;
3754 if (reg_set_p (reg_lc1
, insn
)
3755 || reg_set_p (reg_lt1
, insn
)
3756 || reg_set_p (reg_lb1
, insn
))
3757 loop
->clobber_loop1
|= 1;
3761 if ((loop
->clobber_loop0
&& loop
->clobber_loop1
)
3762 || (loop
->depth
== MAX_LOOP_DEPTH
&& loop
->clobber_loop0
))
3764 loop
->depth
= MAX_LOOP_DEPTH
+ 1;
3766 fprintf (dump_file
, ";; loop %d no loop reg available\n",
3771 /* There should be an instruction before the loop_end instruction
3772 in the same basic block. And the instruction must not be
3774 - CONDITIONAL BRANCH
3778 - Returns (RTS, RTN, etc.) */
3781 last_insn
= PREV_INSN (loop
->loop_end
);
3785 for (; last_insn
!= PREV_INSN (BB_HEAD (bb
));
3786 last_insn
= PREV_INSN (last_insn
))
3787 if (INSN_P (last_insn
))
3790 if (last_insn
!= PREV_INSN (BB_HEAD (bb
)))
3793 if (single_pred_p (bb
)
3794 && single_pred (bb
) != ENTRY_BLOCK_PTR
)
3796 bb
= single_pred (bb
);
3797 last_insn
= BB_END (bb
);
3802 last_insn
= NULL_RTX
;
3810 fprintf (dump_file
, ";; loop %d has no last instruction\n",
3815 if (JUMP_P (last_insn
))
3817 loop_info inner
= bb
->aux
;
3819 && inner
->outer
== loop
3820 && inner
->loop_end
== last_insn
3821 && inner
->depth
== 1)
3822 /* This jump_insn is the exact loop_end of an inner loop
3823 and to be optimized away. So use the inner's last_insn. */
3824 last_insn
= inner
->last_insn
;
3828 fprintf (dump_file
, ";; loop %d has bad last instruction\n",
3833 else if (CALL_P (last_insn
)
3834 || (GET_CODE (PATTERN (last_insn
)) != SEQUENCE
3835 && get_attr_type (last_insn
) == TYPE_SYNC
)
3836 || recog_memoized (last_insn
) == CODE_FOR_return_internal
)
3839 fprintf (dump_file
, ";; loop %d has bad last instruction\n",
3844 if (GET_CODE (PATTERN (last_insn
)) == ASM_INPUT
3845 || asm_noperands (PATTERN (last_insn
)) >= 0
3846 || (GET_CODE (PATTERN (last_insn
)) != SEQUENCE
3847 && get_attr_seq_insns (last_insn
) == SEQ_INSNS_MULTI
))
3849 nop_insn
= emit_insn_after (gen_nop (), last_insn
);
3850 last_insn
= nop_insn
;
3853 loop
->last_insn
= last_insn
;
3855 /* The loop is good for replacement. */
3856 start_label
= loop
->start_label
;
3857 end_label
= gen_label_rtx ();
3858 iter_reg
= loop
->iter_reg
;
3860 if (loop
->depth
== 1 && !loop
->clobber_loop1
)
3865 loop
->clobber_loop1
= 1;
3872 loop
->clobber_loop0
= 1;
3875 /* If iter_reg is a DREG, we need generate an instruction to load
3876 the loop count into LC register. */
3877 if (D_REGNO_P (REGNO (iter_reg
)))
3879 init_insn
= gen_movsi (lc_reg
, iter_reg
);
3880 loop_init
= gen_lsetup_without_autoinit (lt_reg
, start_label
,
3884 else if (P_REGNO_P (REGNO (iter_reg
)))
3886 init_insn
= NULL_RTX
;
3887 loop_init
= gen_lsetup_with_autoinit (lt_reg
, start_label
,
3894 loop
->init
= init_insn
;
3895 loop
->end_label
= end_label
;
3896 loop
->loop_init
= loop_init
;
3900 fprintf (dump_file
, ";; replacing loop %d initializer with\n",
3902 print_rtl_single (dump_file
, loop
->loop_init
);
3903 fprintf (dump_file
, ";; replacing loop %d terminator with\n",
3905 print_rtl_single (dump_file
, loop
->loop_end
);
3910 if (loop
->init
!= NULL_RTX
)
3911 emit_insn (loop
->init
);
3912 seq_end
= emit_insn (loop
->loop_init
);
3917 if (loop
->incoming_src
)
3919 rtx prev
= BB_END (loop
->incoming_src
);
3920 if (VEC_length (edge
, loop
->incoming
) > 1
3921 || !(VEC_last (edge
, loop
->incoming
)->flags
& EDGE_FALLTHRU
))
3923 gcc_assert (JUMP_P (prev
));
3924 prev
= PREV_INSN (prev
);
3926 emit_insn_after (seq
, prev
);
3934 if (loop
->head
!= loop
->incoming_dest
)
3936 FOR_EACH_EDGE (e
, ei
, loop
->head
->preds
)
3938 if (e
->flags
& EDGE_FALLTHRU
)
3940 rtx newjump
= gen_jump (loop
->start_label
);
3941 emit_insn_before (newjump
, BB_HEAD (loop
->head
));
3942 new_bb
= create_basic_block (newjump
, newjump
, loop
->head
->prev_bb
);
3943 gcc_assert (new_bb
= loop
->head
->prev_bb
);
3949 emit_insn_before (seq
, BB_HEAD (loop
->head
));
3950 seq
= emit_label_before (gen_label_rtx (), seq
);
3952 new_bb
= create_basic_block (seq
, seq_end
, loop
->head
->prev_bb
);
3953 FOR_EACH_EDGE (e
, ei
, loop
->incoming
)
3955 if (!(e
->flags
& EDGE_FALLTHRU
)
3956 || e
->dest
!= loop
->head
)
3957 redirect_edge_and_branch_force (e
, new_bb
);
3959 redirect_edge_succ (e
, new_bb
);
3963 delete_insn (loop
->loop_end
);
3964 /* Insert the loop end label before the last instruction of the loop. */
3965 emit_label_before (loop
->end_label
, loop
->last_insn
);
3972 fprintf (dump_file
, ";; loop %d is bad\n", loop
->loop_no
);
3976 if (DPREG_P (loop
->iter_reg
))
3978 /* If loop->iter_reg is a DREG or PREG, we can split it here
3979 without scratch register. */
3982 emit_insn_before (gen_addsi3 (loop
->iter_reg
,
3987 emit_insn_before (gen_cmpsi (loop
->iter_reg
, const0_rtx
),
3990 insn
= emit_jump_insn_before (gen_bne (loop
->start_label
),
3993 JUMP_LABEL (insn
) = loop
->start_label
;
3994 LABEL_NUSES (loop
->start_label
)++;
3995 delete_insn (loop
->loop_end
);
3999 /* Called from bfin_reorg_loops when a potential loop end is found. LOOP is
4000 a newly set up structure describing the loop, it is this function's
4001 responsibility to fill most of it. TAIL_BB and TAIL_INSN point to the
4002 loop_end insn and its enclosing basic block. */
4005 bfin_discover_loop (loop_info loop
, basic_block tail_bb
, rtx tail_insn
)
4009 VEC (basic_block
,heap
) *works
= VEC_alloc (basic_block
,heap
,20);
4011 loop
->tail
= tail_bb
;
4012 loop
->head
= BRANCH_EDGE (tail_bb
)->dest
;
4013 loop
->successor
= FALLTHRU_EDGE (tail_bb
)->dest
;
4014 loop
->loop_end
= tail_insn
;
4015 loop
->last_insn
= NULL_RTX
;
4016 loop
->iter_reg
= SET_DEST (XVECEXP (PATTERN (tail_insn
), 0, 1));
4017 loop
->depth
= loop
->length
= 0;
4019 loop
->clobber_loop0
= loop
->clobber_loop1
= 0;
4022 loop
->incoming
= VEC_alloc (edge
, gc
, 2);
4023 loop
->init
= loop
->loop_init
= NULL_RTX
;
4024 loop
->start_label
= XEXP (XEXP (SET_SRC (XVECEXP (PATTERN (tail_insn
), 0, 0)), 1), 0);
4025 loop
->end_label
= NULL_RTX
;
4028 VEC_safe_push (basic_block
, heap
, works
, loop
->head
);
4030 while (VEC_iterate (basic_block
, works
, dwork
++, bb
))
4034 if (bb
== EXIT_BLOCK_PTR
)
4036 /* We've reached the exit block. The loop must be bad. */
4039 ";; Loop is bad - reached exit block while scanning\n");
4044 if (bitmap_bit_p (loop
->block_bitmap
, bb
->index
))
4047 /* We've not seen this block before. Add it to the loop's
4048 list and then add each successor to the work list. */
4050 VEC_safe_push (basic_block
, heap
, loop
->blocks
, bb
);
4051 bitmap_set_bit (loop
->block_bitmap
, bb
->index
);
4055 FOR_EACH_EDGE (e
, ei
, bb
->succs
)
4057 basic_block succ
= EDGE_SUCC (bb
, ei
.index
)->dest
;
4058 if (!REGNO_REG_SET_P (df_get_live_in (succ
),
4059 REGNO (loop
->iter_reg
)))
4061 if (!VEC_space (basic_block
, works
, 1))
4065 VEC_block_remove (basic_block
, works
, 0, dwork
);
4069 VEC_reserve (basic_block
, heap
, works
, 1);
4071 VEC_quick_push (basic_block
, works
, succ
);
4076 /* Find the predecessor, and make sure nothing else jumps into this loop. */
4080 for (dwork
= 0; VEC_iterate (basic_block
, loop
->blocks
, dwork
, bb
); dwork
++)
4084 FOR_EACH_EDGE (e
, ei
, bb
->preds
)
4086 basic_block pred
= e
->src
;
4088 if (!bfin_bb_in_loop (loop
, pred
))
4091 fprintf (dump_file
, ";; Loop %d: incoming edge %d -> %d\n",
4092 loop
->loop_no
, pred
->index
,
4094 VEC_safe_push (edge
, gc
, loop
->incoming
, e
);
4099 for (pass
= 0, retry
= 1; retry
&& pass
< 2; pass
++)
4106 FOR_EACH_EDGE (e
, ei
, loop
->incoming
)
4110 loop
->incoming_src
= e
->src
;
4111 loop
->incoming_dest
= e
->dest
;
4116 if (e
->dest
!= loop
->incoming_dest
)
4117 loop
->incoming_dest
= NULL
;
4118 if (e
->src
!= loop
->incoming_src
)
4119 loop
->incoming_src
= NULL
;
4121 if (loop
->incoming_src
== NULL
&& loop
->incoming_dest
== NULL
)
4127 ";; retrying loop %d with forwarder blocks\n",
4135 ";; can't find suitable entry for loop %d\n",
4143 FOR_EACH_EDGE (e
, ei
, loop
->incoming
)
4145 if (forwarder_block_p (e
->src
))
4152 ";; Adding forwarder block %d to loop %d and retrying\n",
4153 e
->src
->index
, loop
->loop_no
);
4154 VEC_safe_push (basic_block
, heap
, loop
->blocks
, e
->src
);
4155 bitmap_set_bit (loop
->block_bitmap
, e
->src
->index
);
4156 FOR_EACH_EDGE (e2
, ei2
, e
->src
->preds
)
4157 VEC_safe_push (edge
, gc
, loop
->incoming
, e2
);
4158 VEC_unordered_remove (edge
, loop
->incoming
, ei
.index
);
4168 VEC_free (basic_block
, heap
, works
);
4171 /* Analyze the structure of the loops in the current function. Use STACK
4172 for bitmap allocations. Returns all the valid candidates for hardware
4173 loops found in this function. */
4175 bfin_discover_loops (bitmap_obstack
*stack
, FILE *dump_file
)
4177 loop_info loops
= NULL
;
4183 /* Find all the possible loop tails. This means searching for every
4184 loop_end instruction. For each one found, create a loop_info
4185 structure and add the head block to the work list. */
4188 rtx tail
= BB_END (bb
);
4190 while (GET_CODE (tail
) == NOTE
)
4191 tail
= PREV_INSN (tail
);
4195 if (INSN_P (tail
) && recog_memoized (tail
) == CODE_FOR_loop_end
)
4197 /* A possible loop end */
4199 loop
= XNEW (struct loop_info
);
4202 loop
->loop_no
= nloops
++;
4203 loop
->blocks
= VEC_alloc (basic_block
, heap
, 20);
4204 loop
->block_bitmap
= BITMAP_ALLOC (stack
);
4209 fprintf (dump_file
, ";; potential loop %d ending at\n",
4211 print_rtl_single (dump_file
, tail
);
4214 bfin_discover_loop (loop
, bb
, tail
);
4218 tmp_bitmap
= BITMAP_ALLOC (stack
);
4219 /* Compute loop nestings. */
4220 for (loop
= loops
; loop
; loop
= loop
->next
)
4226 for (other
= loop
->next
; other
; other
= other
->next
)
4231 bitmap_and (tmp_bitmap
, other
->block_bitmap
, loop
->block_bitmap
);
4232 if (bitmap_empty_p (tmp_bitmap
))
4234 if (bitmap_equal_p (tmp_bitmap
, other
->block_bitmap
))
4236 other
->outer
= loop
;
4237 VEC_safe_push (loop_info
, heap
, loop
->loops
, other
);
4239 else if (bitmap_equal_p (tmp_bitmap
, loop
->block_bitmap
))
4241 loop
->outer
= other
;
4242 VEC_safe_push (loop_info
, heap
, other
->loops
, loop
);
4248 ";; can't find suitable nesting for loops %d and %d\n",
4249 loop
->loop_no
, other
->loop_no
);
4250 loop
->bad
= other
->bad
= 1;
4254 BITMAP_FREE (tmp_bitmap
);
4259 /* Free up the loop structures in LOOPS. */
4261 free_loops (loop_info loops
)
4265 loop_info loop
= loops
;
4267 VEC_free (loop_info
, heap
, loop
->loops
);
4268 VEC_free (basic_block
, heap
, loop
->blocks
);
4269 BITMAP_FREE (loop
->block_bitmap
);
4274 #define BB_AUX_INDEX(BB) ((unsigned)(BB)->aux)
4276 /* The taken-branch edge from the loop end can actually go forward. Since the
4277 Blackfin's LSETUP instruction requires that the loop end be after the loop
4278 start, try to reorder a loop's basic blocks when we find such a case. */
4280 bfin_reorder_loops (loop_info loops
, FILE *dump_file
)
4287 cfg_layout_initialize (0);
4289 for (loop
= loops
; loop
; loop
= loop
->next
)
4299 /* Recreate an index for basic blocks that represents their order. */
4300 for (bb
= ENTRY_BLOCK_PTR
->next_bb
, index
= 0;
4301 bb
!= EXIT_BLOCK_PTR
;
4302 bb
= bb
->next_bb
, index
++)
4303 bb
->aux
= (PTR
) index
;
4305 if (BB_AUX_INDEX (loop
->head
) < BB_AUX_INDEX (loop
->tail
))
4308 FOR_EACH_EDGE (e
, ei
, loop
->head
->succs
)
4310 if (bitmap_bit_p (loop
->block_bitmap
, e
->dest
->index
)
4311 && BB_AUX_INDEX (e
->dest
) < BB_AUX_INDEX (loop
->tail
))
4313 basic_block start_bb
= e
->dest
;
4314 basic_block start_prev_bb
= start_bb
->prev_bb
;
4317 fprintf (dump_file
, ";; Moving block %d before block %d\n",
4318 loop
->head
->index
, start_bb
->index
);
4319 loop
->head
->prev_bb
->next_bb
= loop
->head
->next_bb
;
4320 loop
->head
->next_bb
->prev_bb
= loop
->head
->prev_bb
;
4322 loop
->head
->prev_bb
= start_prev_bb
;
4323 loop
->head
->next_bb
= start_bb
;
4324 start_prev_bb
->next_bb
= start_bb
->prev_bb
= loop
->head
;
4328 loops
= loops
->next
;
4333 if (bb
->next_bb
!= EXIT_BLOCK_PTR
)
4334 bb
->aux
= bb
->next_bb
;
4338 cfg_layout_finalize ();
4342 /* Run from machine_dependent_reorg, this pass looks for doloop_end insns
4343 and tries to rewrite the RTL of these loops so that proper Blackfin
4344 hardware loops are generated. */
4347 bfin_reorg_loops (FILE *dump_file
)
4349 loop_info loops
= NULL
;
4352 bitmap_obstack stack
;
4354 bitmap_obstack_initialize (&stack
);
4357 fprintf (dump_file
, ";; Find loops, first pass\n\n");
4359 loops
= bfin_discover_loops (&stack
, dump_file
);
4362 bfin_dump_loops (loops
);
4364 bfin_reorder_loops (loops
, dump_file
);
4368 fprintf (dump_file
, ";; Find loops, second pass\n\n");
4370 loops
= bfin_discover_loops (&stack
, dump_file
);
4373 fprintf (dump_file
, ";; All loops found:\n\n");
4374 bfin_dump_loops (loops
);
4377 /* Now apply the optimizations. */
4378 for (loop
= loops
; loop
; loop
= loop
->next
)
4379 bfin_optimize_loop (loop
);
4383 fprintf (dump_file
, ";; After hardware loops optimization:\n\n");
4384 bfin_dump_loops (loops
);
4390 print_rtl (dump_file
, get_insns ());
4396 /* Possibly generate a SEQUENCE out of three insns found in SLOT.
4397 Returns true if we modified the insn chain, false otherwise. */
4399 gen_one_bundle (rtx slot
[3])
4401 gcc_assert (slot
[1] != NULL_RTX
);
4403 /* Verify that we really can do the multi-issue. */
4406 rtx t
= NEXT_INSN (slot
[0]);
4407 while (t
!= slot
[1])
4409 if (GET_CODE (t
) != NOTE
4410 || NOTE_KIND (t
) != NOTE_INSN_DELETED
)
4417 rtx t
= NEXT_INSN (slot
[1]);
4418 while (t
!= slot
[2])
4420 if (GET_CODE (t
) != NOTE
4421 || NOTE_KIND (t
) != NOTE_INSN_DELETED
)
4427 if (slot
[0] == NULL_RTX
)
4429 slot
[0] = emit_insn_before (gen_mnop (), slot
[1]);
4430 df_insn_rescan (slot
[0]);
4432 if (slot
[2] == NULL_RTX
)
4434 slot
[2] = emit_insn_after (gen_forced_nop (), slot
[1]);
4435 df_insn_rescan (slot
[2]);
4438 /* Avoid line number information being printed inside one bundle. */
4439 if (INSN_LOCATOR (slot
[1])
4440 && INSN_LOCATOR (slot
[1]) != INSN_LOCATOR (slot
[0]))
4441 INSN_LOCATOR (slot
[1]) = INSN_LOCATOR (slot
[0]);
4442 if (INSN_LOCATOR (slot
[2])
4443 && INSN_LOCATOR (slot
[2]) != INSN_LOCATOR (slot
[0]))
4444 INSN_LOCATOR (slot
[2]) = INSN_LOCATOR (slot
[0]);
4446 /* Terminate them with "|| " instead of ";" in the output. */
4447 PUT_MODE (slot
[0], SImode
);
4448 PUT_MODE (slot
[1], SImode
);
4449 /* Terminate the bundle, for the benefit of reorder_var_tracking_notes. */
4450 PUT_MODE (slot
[2], QImode
);
4454 /* Go through all insns, and use the information generated during scheduling
4455 to generate SEQUENCEs to represent bundles of instructions issued
4459 bfin_gen_bundles (void)
4468 slot
[0] = slot
[1] = slot
[2] = NULL_RTX
;
4469 for (insn
= BB_HEAD (bb
);; insn
= next
)
4474 if (get_attr_type (insn
) == TYPE_DSP32
)
4476 else if (slot
[1] == NULL_RTX
)
4483 next
= NEXT_INSN (insn
);
4484 while (next
&& insn
!= BB_END (bb
)
4486 && GET_CODE (PATTERN (next
)) != USE
4487 && GET_CODE (PATTERN (next
)) != CLOBBER
))
4490 next
= NEXT_INSN (insn
);
4493 /* BB_END can change due to emitting extra NOPs, so check here. */
4494 at_end
= insn
== BB_END (bb
);
4495 if (at_end
|| GET_MODE (next
) == TImode
)
4498 || !gen_one_bundle (slot
))
4499 && slot
[0] != NULL_RTX
)
4501 rtx pat
= PATTERN (slot
[0]);
4502 if (GET_CODE (pat
) == SET
4503 && GET_CODE (SET_SRC (pat
)) == UNSPEC
4504 && XINT (SET_SRC (pat
), 1) == UNSPEC_32BIT
)
4506 SET_SRC (pat
) = XVECEXP (SET_SRC (pat
), 0, 0);
4507 INSN_CODE (slot
[0]) = -1;
4508 df_insn_rescan (slot
[0]);
4512 slot
[0] = slot
[1] = slot
[2] = NULL_RTX
;
4520 /* Ensure that no var tracking notes are emitted in the middle of a
4521 three-instruction bundle. */
4524 reorder_var_tracking_notes (void)
4530 rtx queue
= NULL_RTX
;
4531 bool in_bundle
= false;
4533 for (insn
= BB_HEAD (bb
); insn
!= BB_END (bb
); insn
= next
)
4535 next
= NEXT_INSN (insn
);
4539 /* Emit queued up notes at the last instruction of a bundle. */
4540 if (GET_MODE (insn
) == QImode
)
4544 rtx next_queue
= PREV_INSN (queue
);
4545 PREV_INSN (NEXT_INSN (insn
)) = queue
;
4546 NEXT_INSN (queue
) = NEXT_INSN (insn
);
4547 NEXT_INSN (insn
) = queue
;
4548 PREV_INSN (queue
) = insn
;
4553 else if (GET_MODE (insn
) == SImode
)
4556 else if (NOTE_P (insn
) && NOTE_KIND (insn
) == NOTE_INSN_VAR_LOCATION
)
4560 rtx prev
= PREV_INSN (insn
);
4561 PREV_INSN (next
) = prev
;
4562 NEXT_INSN (prev
) = next
;
4564 PREV_INSN (insn
) = queue
;
4572 /* Return an insn type for INSN that can be used by the caller for anomaly
4573 workarounds. This differs from plain get_attr_type in that it handles
4576 static enum attr_type
4577 type_for_anomaly (rtx insn
)
4579 rtx pat
= PATTERN (insn
);
4580 if (GET_CODE (pat
) == SEQUENCE
)
4583 t
= get_attr_type (XVECEXP (pat
, 0, 1));
4586 t
= get_attr_type (XVECEXP (pat
, 0, 2));
4592 return get_attr_type (insn
);
4595 /* Return nonzero if INSN contains any loads that may trap. It handles
4596 SEQUENCEs correctly. */
4599 trapping_loads_p (rtx insn
)
4601 rtx pat
= PATTERN (insn
);
4602 if (GET_CODE (pat
) == SEQUENCE
)
4605 t
= get_attr_type (XVECEXP (pat
, 0, 1));
4607 && may_trap_p (SET_SRC (PATTERN (XVECEXP (pat
, 0, 1)))))
4609 t
= get_attr_type (XVECEXP (pat
, 0, 2));
4611 && may_trap_p (SET_SRC (PATTERN (XVECEXP (pat
, 0, 2)))))
4616 return may_trap_p (SET_SRC (single_set (insn
)));
4619 /* This function acts like NEXT_INSN, but is aware of three-insn bundles and
4620 skips all subsequent parallel instructions if INSN is the start of such
4623 find_next_insn_start (rtx insn
)
4625 if (GET_MODE (insn
) == SImode
)
4627 while (GET_MODE (insn
) != QImode
)
4628 insn
= NEXT_INSN (insn
);
4630 return NEXT_INSN (insn
);
4633 /* Return INSN if it is of TYPE_MCLD. Alternatively, if INSN is the start of
4634 a three-insn bundle, see if one of them is a load and return that if so.
4635 Return NULL_RTX if the insn does not contain loads. */
4637 find_load (rtx insn
)
4639 if (get_attr_type (insn
) == TYPE_MCLD
)
4641 if (GET_MODE (insn
) != SImode
)
4644 insn
= NEXT_INSN (insn
);
4645 if ((GET_MODE (insn
) == SImode
|| GET_MODE (insn
) == QImode
)
4646 && get_attr_type (insn
) == TYPE_MCLD
)
4648 } while (GET_MODE (insn
) != QImode
);
4652 /* We use the machine specific reorg pass for emitting CSYNC instructions
4653 after conditional branches as needed.
4655 The Blackfin is unusual in that a code sequence like
4658 may speculatively perform the load even if the condition isn't true. This
4659 happens for a branch that is predicted not taken, because the pipeline
4660 isn't flushed or stalled, so the early stages of the following instructions,
4661 which perform the memory reference, are allowed to execute before the
4662 jump condition is evaluated.
4663 Therefore, we must insert additional instructions in all places where this
4664 could lead to incorrect behavior. The manual recommends CSYNC, while
4665 VDSP seems to use NOPs (even though its corresponding compiler option is
4668 When optimizing for speed, we emit NOPs, which seems faster than a CSYNC.
4669 When optimizing for size, we turn the branch into a predicted taken one.
4670 This may be slower due to mispredicts, but saves code size. */
4676 rtx last_condjump
= NULL_RTX
;
4677 int cycles_since_jump
= INT_MAX
;
4679 /* We are freeing block_for_insn in the toplev to keep compatibility
4680 with old MDEP_REORGS that are not CFG based. Recompute it now. */
4681 compute_bb_for_insn ();
4683 if (bfin_flag_schedule_insns2
)
4685 splitting_for_sched
= 1;
4687 splitting_for_sched
= 0;
4689 timevar_push (TV_SCHED2
);
4691 timevar_pop (TV_SCHED2
);
4693 /* Examine the schedule and insert nops as necessary for 64-bit parallel
4695 bfin_gen_bundles ();
4700 /* Doloop optimization */
4701 if (cfun
->machine
->has_hardware_loops
)
4702 bfin_reorg_loops (dump_file
);
4704 if (! ENABLE_WA_SPECULATIVE_LOADS
&& ! ENABLE_WA_SPECULATIVE_SYNCS
)
4707 /* First pass: find predicted-false branches; if something after them
4708 needs nops, insert them or change the branch to predict true. */
4709 for (insn
= get_insns (); insn
; insn
= next
)
4713 next
= find_next_insn_start (insn
);
4715 if (NOTE_P (insn
) || BARRIER_P (insn
) || LABEL_P (insn
))
4718 pat
= PATTERN (insn
);
4719 if (GET_CODE (pat
) == USE
|| GET_CODE (pat
) == CLOBBER
4720 || GET_CODE (pat
) == ASM_INPUT
|| GET_CODE (pat
) == ADDR_VEC
4721 || GET_CODE (pat
) == ADDR_DIFF_VEC
|| asm_noperands (pat
) >= 0)
4726 if (any_condjump_p (insn
)
4727 && ! cbranch_predicted_taken_p (insn
))
4729 last_condjump
= insn
;
4730 cycles_since_jump
= 0;
4733 cycles_since_jump
= INT_MAX
;
4735 else if (INSN_P (insn
))
4737 rtx load_insn
= find_load (insn
);
4738 enum attr_type type
= type_for_anomaly (insn
);
4739 int delay_needed
= 0;
4740 if (cycles_since_jump
< INT_MAX
)
4741 cycles_since_jump
++;
4743 if (load_insn
&& ENABLE_WA_SPECULATIVE_LOADS
)
4745 if (trapping_loads_p (load_insn
))
4748 else if (type
== TYPE_SYNC
&& ENABLE_WA_SPECULATIVE_SYNCS
)
4751 if (delay_needed
> cycles_since_jump
)
4755 rtx
*op
= recog_data
.operand
;
4757 delay_needed
-= cycles_since_jump
;
4759 extract_insn (last_condjump
);
4762 pat
= gen_cbranch_predicted_taken (op
[0], op
[1], op
[2],
4764 cycles_since_jump
= INT_MAX
;
4767 /* Do not adjust cycles_since_jump in this case, so that
4768 we'll increase the number of NOPs for a subsequent insn
4770 pat
= gen_cbranch_with_nops (op
[0], op
[1], op
[2], op
[3],
4771 GEN_INT (delay_needed
));
4772 PATTERN (last_condjump
) = pat
;
4773 INSN_CODE (last_condjump
) = recog (pat
, insn
, &num_clobbers
);
4777 /* Second pass: for predicted-true branches, see if anything at the
4778 branch destination needs extra nops. */
4779 if (! ENABLE_WA_SPECULATIVE_SYNCS
)
4782 for (insn
= get_insns (); insn
; insn
= NEXT_INSN (insn
))
4785 && any_condjump_p (insn
)
4786 && (INSN_CODE (insn
) == CODE_FOR_cbranch_predicted_taken
4787 || cbranch_predicted_taken_p (insn
)))
4789 rtx target
= JUMP_LABEL (insn
);
4791 cycles_since_jump
= 0;
4792 for (; target
&& cycles_since_jump
< 3; target
= NEXT_INSN (target
))
4796 if (NOTE_P (target
) || BARRIER_P (target
) || LABEL_P (target
))
4799 pat
= PATTERN (target
);
4800 if (GET_CODE (pat
) == USE
|| GET_CODE (pat
) == CLOBBER
4801 || GET_CODE (pat
) == ASM_INPUT
|| GET_CODE (pat
) == ADDR_VEC
4802 || GET_CODE (pat
) == ADDR_DIFF_VEC
|| asm_noperands (pat
) >= 0)
4805 if (INSN_P (target
))
4807 enum attr_type type
= type_for_anomaly (target
);
4808 int delay_needed
= 0;
4809 if (cycles_since_jump
< INT_MAX
)
4810 cycles_since_jump
++;
4812 if (type
== TYPE_SYNC
&& ENABLE_WA_SPECULATIVE_SYNCS
)
4815 if (delay_needed
> cycles_since_jump
)
4817 rtx prev
= prev_real_insn (label
);
4818 delay_needed
-= cycles_since_jump
;
4820 fprintf (dump_file
, "Adding %d nops after %d\n",
4821 delay_needed
, INSN_UID (label
));
4823 && INSN_CODE (prev
) == CODE_FOR_cbranch_with_nops
)
4830 "Reducing nops on insn %d.\n",
4833 x
= XVECEXP (x
, 0, 1);
4834 v
= INTVAL (XVECEXP (x
, 0, 0)) - delay_needed
;
4835 XVECEXP (x
, 0, 0) = GEN_INT (v
);
4837 while (delay_needed
-- > 0)
4838 emit_insn_after (gen_nop (), label
);
4846 if (bfin_flag_var_tracking
)
4848 timevar_push (TV_VAR_TRACKING
);
4849 variable_tracking_main ();
4850 reorder_var_tracking_notes ();
4851 timevar_pop (TV_VAR_TRACKING
);
4853 df_finish_pass (false);
4856 /* Handle interrupt_handler, exception_handler and nmi_handler function
4857 attributes; arguments as in struct attribute_spec.handler. */
4860 handle_int_attribute (tree
*node
, tree name
,
4861 tree args ATTRIBUTE_UNUSED
,
4862 int flags ATTRIBUTE_UNUSED
,
4866 if (TREE_CODE (x
) == FUNCTION_DECL
)
4869 if (TREE_CODE (x
) != FUNCTION_TYPE
)
4871 warning (OPT_Wattributes
, "%qs attribute only applies to functions",
4872 IDENTIFIER_POINTER (name
));
4873 *no_add_attrs
= true;
4875 else if (funkind (x
) != SUBROUTINE
)
4876 error ("multiple function type attributes specified");
4881 /* Return 0 if the attributes for two types are incompatible, 1 if they
4882 are compatible, and 2 if they are nearly compatible (which causes a
4883 warning to be generated). */
4886 bfin_comp_type_attributes (const_tree type1
, const_tree type2
)
4888 e_funkind kind1
, kind2
;
4890 if (TREE_CODE (type1
) != FUNCTION_TYPE
)
4893 kind1
= funkind (type1
);
4894 kind2
= funkind (type2
);
4899 /* Check for mismatched modifiers */
4900 if (!lookup_attribute ("nesting", TYPE_ATTRIBUTES (type1
))
4901 != !lookup_attribute ("nesting", TYPE_ATTRIBUTES (type2
)))
4904 if (!lookup_attribute ("saveall", TYPE_ATTRIBUTES (type1
))
4905 != !lookup_attribute ("saveall", TYPE_ATTRIBUTES (type2
)))
4908 if (!lookup_attribute ("kspisusp", TYPE_ATTRIBUTES (type1
))
4909 != !lookup_attribute ("kspisusp", TYPE_ATTRIBUTES (type2
)))
4912 if (!lookup_attribute ("longcall", TYPE_ATTRIBUTES (type1
))
4913 != !lookup_attribute ("longcall", TYPE_ATTRIBUTES (type2
)))
4919 /* Handle a "longcall" or "shortcall" attribute; arguments as in
4920 struct attribute_spec.handler. */
4923 bfin_handle_longcall_attribute (tree
*node
, tree name
,
4924 tree args ATTRIBUTE_UNUSED
,
4925 int flags ATTRIBUTE_UNUSED
,
4928 if (TREE_CODE (*node
) != FUNCTION_TYPE
4929 && TREE_CODE (*node
) != FIELD_DECL
4930 && TREE_CODE (*node
) != TYPE_DECL
)
4932 warning (OPT_Wattributes
, "`%s' attribute only applies to functions",
4933 IDENTIFIER_POINTER (name
));
4934 *no_add_attrs
= true;
4937 if ((strcmp (IDENTIFIER_POINTER (name
), "longcall") == 0
4938 && lookup_attribute ("shortcall", TYPE_ATTRIBUTES (*node
)))
4939 || (strcmp (IDENTIFIER_POINTER (name
), "shortcall") == 0
4940 && lookup_attribute ("longcall", TYPE_ATTRIBUTES (*node
))))
4942 warning (OPT_Wattributes
,
4943 "can't apply both longcall and shortcall attributes to the same function");
4944 *no_add_attrs
= true;
4950 /* Handle a "l1_text" attribute; arguments as in
4951 struct attribute_spec.handler. */
4954 bfin_handle_l1_text_attribute (tree
*node
, tree name
, tree
ARG_UNUSED (args
),
4955 int ARG_UNUSED (flags
), bool *no_add_attrs
)
4959 if (TREE_CODE (decl
) != FUNCTION_DECL
)
4961 error ("`%s' attribute only applies to functions",
4962 IDENTIFIER_POINTER (name
));
4963 *no_add_attrs
= true;
4966 /* The decl may have already been given a section attribute
4967 from a previous declaration. Ensure they match. */
4968 else if (DECL_SECTION_NAME (decl
) != NULL_TREE
4969 && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl
)),
4972 error ("section of %q+D conflicts with previous declaration",
4974 *no_add_attrs
= true;
4977 DECL_SECTION_NAME (decl
) = build_string (9, ".l1.text");
4982 /* Handle a "l1_data", "l1_data_A" or "l1_data_B" attribute;
4983 arguments as in struct attribute_spec.handler. */
4986 bfin_handle_l1_data_attribute (tree
*node
, tree name
, tree
ARG_UNUSED (args
),
4987 int ARG_UNUSED (flags
), bool *no_add_attrs
)
4991 if (TREE_CODE (decl
) != VAR_DECL
)
4993 error ("`%s' attribute only applies to variables",
4994 IDENTIFIER_POINTER (name
));
4995 *no_add_attrs
= true;
4997 else if (current_function_decl
!= NULL_TREE
4998 && !TREE_STATIC (decl
))
5000 error ("`%s' attribute cannot be specified for local variables",
5001 IDENTIFIER_POINTER (name
));
5002 *no_add_attrs
= true;
5006 const char *section_name
;
5008 if (strcmp (IDENTIFIER_POINTER (name
), "l1_data") == 0)
5009 section_name
= ".l1.data";
5010 else if (strcmp (IDENTIFIER_POINTER (name
), "l1_data_A") == 0)
5011 section_name
= ".l1.data.A";
5012 else if (strcmp (IDENTIFIER_POINTER (name
), "l1_data_B") == 0)
5013 section_name
= ".l1.data.B";
5017 /* The decl may have already been given a section attribute
5018 from a previous declaration. Ensure they match. */
5019 if (DECL_SECTION_NAME (decl
) != NULL_TREE
5020 && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl
)),
5023 error ("section of %q+D conflicts with previous declaration",
5025 *no_add_attrs
= true;
5028 DECL_SECTION_NAME (decl
)
5029 = build_string (strlen (section_name
) + 1, section_name
);
5035 /* Table of valid machine attributes. */
5036 const struct attribute_spec bfin_attribute_table
[] =
5038 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
5039 { "interrupt_handler", 0, 0, false, true, true, handle_int_attribute
},
5040 { "exception_handler", 0, 0, false, true, true, handle_int_attribute
},
5041 { "nmi_handler", 0, 0, false, true, true, handle_int_attribute
},
5042 { "nesting", 0, 0, false, true, true, NULL
},
5043 { "kspisusp", 0, 0, false, true, true, NULL
},
5044 { "saveall", 0, 0, false, true, true, NULL
},
5045 { "longcall", 0, 0, false, true, true, bfin_handle_longcall_attribute
},
5046 { "shortcall", 0, 0, false, true, true, bfin_handle_longcall_attribute
},
5047 { "l1_text", 0, 0, true, false, false, bfin_handle_l1_text_attribute
},
5048 { "l1_data", 0, 0, true, false, false, bfin_handle_l1_data_attribute
},
5049 { "l1_data_A", 0, 0, true, false, false, bfin_handle_l1_data_attribute
},
5050 { "l1_data_B", 0, 0, true, false, false, bfin_handle_l1_data_attribute
},
5051 { NULL
, 0, 0, false, false, false, NULL
}
5054 /* Implementation of TARGET_ASM_INTEGER. When using FD-PIC, we need to
5055 tell the assembler to generate pointers to function descriptors in
5059 bfin_assemble_integer (rtx value
, unsigned int size
, int aligned_p
)
5061 if (TARGET_FDPIC
&& size
== UNITS_PER_WORD
)
5063 if (GET_CODE (value
) == SYMBOL_REF
5064 && SYMBOL_REF_FUNCTION_P (value
))
5066 fputs ("\t.picptr\tfuncdesc(", asm_out_file
);
5067 output_addr_const (asm_out_file
, value
);
5068 fputs (")\n", asm_out_file
);
5073 /* We've set the unaligned SI op to NULL, so we always have to
5074 handle the unaligned case here. */
5075 assemble_integer_with_op ("\t.4byte\t", value
);
5079 return default_assemble_integer (value
, size
, aligned_p
);
5082 /* Output the assembler code for a thunk function. THUNK_DECL is the
5083 declaration for the thunk function itself, FUNCTION is the decl for
5084 the target function. DELTA is an immediate constant offset to be
5085 added to THIS. If VCALL_OFFSET is nonzero, the word at
5086 *(*this + vcall_offset) should be added to THIS. */
5089 bfin_output_mi_thunk (FILE *file ATTRIBUTE_UNUSED
,
5090 tree thunk ATTRIBUTE_UNUSED
, HOST_WIDE_INT delta
,
5091 HOST_WIDE_INT vcall_offset
, tree function
)
5094 /* The this parameter is passed as the first argument. */
5095 rtx
this = gen_rtx_REG (Pmode
, REG_R0
);
5097 /* Adjust the this parameter by a fixed constant. */
5101 if (delta
>= -64 && delta
<= 63)
5103 xops
[0] = GEN_INT (delta
);
5104 output_asm_insn ("%1 += %0;", xops
);
5106 else if (delta
>= -128 && delta
< -64)
5108 xops
[0] = GEN_INT (delta
+ 64);
5109 output_asm_insn ("%1 += -64; %1 += %0;", xops
);
5111 else if (delta
> 63 && delta
<= 126)
5113 xops
[0] = GEN_INT (delta
- 63);
5114 output_asm_insn ("%1 += 63; %1 += %0;", xops
);
5118 xops
[0] = GEN_INT (delta
);
5119 output_asm_insn ("r3.l = %h0; r3.h = %d0; %1 = %1 + r3;", xops
);
5123 /* Adjust the this parameter by a value stored in the vtable. */
5126 rtx p2tmp
= gen_rtx_REG (Pmode
, REG_P2
);
5127 rtx tmp
= gen_rtx_REG (Pmode
, REG_R3
);
5131 output_asm_insn ("%2 = r0; %2 = [%2];", xops
);
5133 /* Adjust the this parameter. */
5134 xops
[0] = gen_rtx_MEM (Pmode
, plus_constant (p2tmp
, vcall_offset
));
5135 if (!memory_operand (xops
[0], Pmode
))
5137 rtx tmp2
= gen_rtx_REG (Pmode
, REG_P1
);
5138 xops
[0] = GEN_INT (vcall_offset
);
5140 output_asm_insn ("%h1 = %h0; %d1 = %d0; %2 = %2 + %1", xops
);
5141 xops
[0] = gen_rtx_MEM (Pmode
, p2tmp
);
5144 output_asm_insn ("%1 = %0; %2 = %2 + %1;", xops
);
5147 xops
[0] = XEXP (DECL_RTL (function
), 0);
5148 if (1 || !flag_pic
|| (*targetm
.binds_local_p
) (function
))
5149 output_asm_insn ("jump.l\t%P0", xops
);
5152 /* Codes for all the Blackfin builtins. */
5158 BFIN_BUILTIN_COMPOSE_2X16
,
5159 BFIN_BUILTIN_EXTRACTLO
,
5160 BFIN_BUILTIN_EXTRACTHI
,
5162 BFIN_BUILTIN_SSADD_2X16
,
5163 BFIN_BUILTIN_SSSUB_2X16
,
5164 BFIN_BUILTIN_SSADDSUB_2X16
,
5165 BFIN_BUILTIN_SSSUBADD_2X16
,
5166 BFIN_BUILTIN_MULT_2X16
,
5167 BFIN_BUILTIN_MULTR_2X16
,
5168 BFIN_BUILTIN_NEG_2X16
,
5169 BFIN_BUILTIN_ABS_2X16
,
5170 BFIN_BUILTIN_MIN_2X16
,
5171 BFIN_BUILTIN_MAX_2X16
,
5173 BFIN_BUILTIN_SSADD_1X16
,
5174 BFIN_BUILTIN_SSSUB_1X16
,
5175 BFIN_BUILTIN_MULT_1X16
,
5176 BFIN_BUILTIN_MULTR_1X16
,
5177 BFIN_BUILTIN_NORM_1X16
,
5178 BFIN_BUILTIN_NEG_1X16
,
5179 BFIN_BUILTIN_ABS_1X16
,
5180 BFIN_BUILTIN_MIN_1X16
,
5181 BFIN_BUILTIN_MAX_1X16
,
5183 BFIN_BUILTIN_SUM_2X16
,
5184 BFIN_BUILTIN_DIFFHL_2X16
,
5185 BFIN_BUILTIN_DIFFLH_2X16
,
5187 BFIN_BUILTIN_SSADD_1X32
,
5188 BFIN_BUILTIN_SSSUB_1X32
,
5189 BFIN_BUILTIN_NORM_1X32
,
5190 BFIN_BUILTIN_ROUND_1X32
,
5191 BFIN_BUILTIN_NEG_1X32
,
5192 BFIN_BUILTIN_ABS_1X32
,
5193 BFIN_BUILTIN_MIN_1X32
,
5194 BFIN_BUILTIN_MAX_1X32
,
5195 BFIN_BUILTIN_MULT_1X32
,
5196 BFIN_BUILTIN_MULT_1X32X32
,
5197 BFIN_BUILTIN_MULT_1X32X32NS
,
5199 BFIN_BUILTIN_MULHISILL
,
5200 BFIN_BUILTIN_MULHISILH
,
5201 BFIN_BUILTIN_MULHISIHL
,
5202 BFIN_BUILTIN_MULHISIHH
,
5204 BFIN_BUILTIN_LSHIFT_1X16
,
5205 BFIN_BUILTIN_LSHIFT_2X16
,
5206 BFIN_BUILTIN_SSASHIFT_1X16
,
5207 BFIN_BUILTIN_SSASHIFT_2X16
,
5208 BFIN_BUILTIN_SSASHIFT_1X32
,
5210 BFIN_BUILTIN_CPLX_MUL_16
,
5211 BFIN_BUILTIN_CPLX_MAC_16
,
5212 BFIN_BUILTIN_CPLX_MSU_16
,
5214 BFIN_BUILTIN_CPLX_MUL_16_S40
,
5215 BFIN_BUILTIN_CPLX_MAC_16_S40
,
5216 BFIN_BUILTIN_CPLX_MSU_16_S40
,
5218 BFIN_BUILTIN_CPLX_SQU
,
5223 #define def_builtin(NAME, TYPE, CODE) \
5225 add_builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD, \
5229 /* Set up all builtin functions for this target. */
5231 bfin_init_builtins (void)
5233 tree V2HI_type_node
= build_vector_type_for_mode (intHI_type_node
, V2HImode
);
5234 tree void_ftype_void
5235 = build_function_type (void_type_node
, void_list_node
);
5236 tree short_ftype_short
5237 = build_function_type_list (short_integer_type_node
, short_integer_type_node
,
5239 tree short_ftype_int_int
5240 = build_function_type_list (short_integer_type_node
, integer_type_node
,
5241 integer_type_node
, NULL_TREE
);
5242 tree int_ftype_int_int
5243 = build_function_type_list (integer_type_node
, integer_type_node
,
5244 integer_type_node
, NULL_TREE
);
5246 = build_function_type_list (integer_type_node
, integer_type_node
,
5248 tree short_ftype_int
5249 = build_function_type_list (short_integer_type_node
, integer_type_node
,
5251 tree int_ftype_v2hi_v2hi
5252 = build_function_type_list (integer_type_node
, V2HI_type_node
,
5253 V2HI_type_node
, NULL_TREE
);
5254 tree v2hi_ftype_v2hi_v2hi
5255 = build_function_type_list (V2HI_type_node
, V2HI_type_node
,
5256 V2HI_type_node
, NULL_TREE
);
5257 tree v2hi_ftype_v2hi_v2hi_v2hi
5258 = build_function_type_list (V2HI_type_node
, V2HI_type_node
,
5259 V2HI_type_node
, V2HI_type_node
, NULL_TREE
);
5260 tree v2hi_ftype_int_int
5261 = build_function_type_list (V2HI_type_node
, integer_type_node
,
5262 integer_type_node
, NULL_TREE
);
5263 tree v2hi_ftype_v2hi_int
5264 = build_function_type_list (V2HI_type_node
, V2HI_type_node
,
5265 integer_type_node
, NULL_TREE
);
5266 tree int_ftype_short_short
5267 = build_function_type_list (integer_type_node
, short_integer_type_node
,
5268 short_integer_type_node
, NULL_TREE
);
5269 tree v2hi_ftype_v2hi
5270 = build_function_type_list (V2HI_type_node
, V2HI_type_node
, NULL_TREE
);
5271 tree short_ftype_v2hi
5272 = build_function_type_list (short_integer_type_node
, V2HI_type_node
,
5275 /* Add the remaining MMX insns with somewhat more complicated types. */
5276 def_builtin ("__builtin_bfin_csync", void_ftype_void
, BFIN_BUILTIN_CSYNC
);
5277 def_builtin ("__builtin_bfin_ssync", void_ftype_void
, BFIN_BUILTIN_SSYNC
);
5279 def_builtin ("__builtin_bfin_ones", short_ftype_int
, BFIN_BUILTIN_ONES
);
5281 def_builtin ("__builtin_bfin_compose_2x16", v2hi_ftype_int_int
,
5282 BFIN_BUILTIN_COMPOSE_2X16
);
5283 def_builtin ("__builtin_bfin_extract_hi", short_ftype_v2hi
,
5284 BFIN_BUILTIN_EXTRACTHI
);
5285 def_builtin ("__builtin_bfin_extract_lo", short_ftype_v2hi
,
5286 BFIN_BUILTIN_EXTRACTLO
);
5288 def_builtin ("__builtin_bfin_min_fr2x16", v2hi_ftype_v2hi_v2hi
,
5289 BFIN_BUILTIN_MIN_2X16
);
5290 def_builtin ("__builtin_bfin_max_fr2x16", v2hi_ftype_v2hi_v2hi
,
5291 BFIN_BUILTIN_MAX_2X16
);
5293 def_builtin ("__builtin_bfin_add_fr2x16", v2hi_ftype_v2hi_v2hi
,
5294 BFIN_BUILTIN_SSADD_2X16
);
5295 def_builtin ("__builtin_bfin_sub_fr2x16", v2hi_ftype_v2hi_v2hi
,
5296 BFIN_BUILTIN_SSSUB_2X16
);
5297 def_builtin ("__builtin_bfin_dspaddsubsat", v2hi_ftype_v2hi_v2hi
,
5298 BFIN_BUILTIN_SSADDSUB_2X16
);
5299 def_builtin ("__builtin_bfin_dspsubaddsat", v2hi_ftype_v2hi_v2hi
,
5300 BFIN_BUILTIN_SSSUBADD_2X16
);
5301 def_builtin ("__builtin_bfin_mult_fr2x16", v2hi_ftype_v2hi_v2hi
,
5302 BFIN_BUILTIN_MULT_2X16
);
5303 def_builtin ("__builtin_bfin_multr_fr2x16", v2hi_ftype_v2hi_v2hi
,
5304 BFIN_BUILTIN_MULTR_2X16
);
5305 def_builtin ("__builtin_bfin_negate_fr2x16", v2hi_ftype_v2hi
,
5306 BFIN_BUILTIN_NEG_2X16
);
5307 def_builtin ("__builtin_bfin_abs_fr2x16", v2hi_ftype_v2hi
,
5308 BFIN_BUILTIN_ABS_2X16
);
5310 def_builtin ("__builtin_bfin_min_fr1x16", short_ftype_int_int
,
5311 BFIN_BUILTIN_MIN_1X16
);
5312 def_builtin ("__builtin_bfin_max_fr1x16", short_ftype_int_int
,
5313 BFIN_BUILTIN_MAX_1X16
);
5315 def_builtin ("__builtin_bfin_add_fr1x16", short_ftype_int_int
,
5316 BFIN_BUILTIN_SSADD_1X16
);
5317 def_builtin ("__builtin_bfin_sub_fr1x16", short_ftype_int_int
,
5318 BFIN_BUILTIN_SSSUB_1X16
);
5319 def_builtin ("__builtin_bfin_mult_fr1x16", short_ftype_int_int
,
5320 BFIN_BUILTIN_MULT_1X16
);
5321 def_builtin ("__builtin_bfin_multr_fr1x16", short_ftype_int_int
,
5322 BFIN_BUILTIN_MULTR_1X16
);
5323 def_builtin ("__builtin_bfin_negate_fr1x16", short_ftype_short
,
5324 BFIN_BUILTIN_NEG_1X16
);
5325 def_builtin ("__builtin_bfin_abs_fr1x16", short_ftype_short
,
5326 BFIN_BUILTIN_ABS_1X16
);
5327 def_builtin ("__builtin_bfin_norm_fr1x16", short_ftype_int
,
5328 BFIN_BUILTIN_NORM_1X16
);
5330 def_builtin ("__builtin_bfin_sum_fr2x16", short_ftype_v2hi
,
5331 BFIN_BUILTIN_SUM_2X16
);
5332 def_builtin ("__builtin_bfin_diff_hl_fr2x16", short_ftype_v2hi
,
5333 BFIN_BUILTIN_DIFFHL_2X16
);
5334 def_builtin ("__builtin_bfin_diff_lh_fr2x16", short_ftype_v2hi
,
5335 BFIN_BUILTIN_DIFFLH_2X16
);
5337 def_builtin ("__builtin_bfin_mulhisill", int_ftype_v2hi_v2hi
,
5338 BFIN_BUILTIN_MULHISILL
);
5339 def_builtin ("__builtin_bfin_mulhisihl", int_ftype_v2hi_v2hi
,
5340 BFIN_BUILTIN_MULHISIHL
);
5341 def_builtin ("__builtin_bfin_mulhisilh", int_ftype_v2hi_v2hi
,
5342 BFIN_BUILTIN_MULHISILH
);
5343 def_builtin ("__builtin_bfin_mulhisihh", int_ftype_v2hi_v2hi
,
5344 BFIN_BUILTIN_MULHISIHH
);
5346 def_builtin ("__builtin_bfin_min_fr1x32", int_ftype_int_int
,
5347 BFIN_BUILTIN_MIN_1X32
);
5348 def_builtin ("__builtin_bfin_max_fr1x32", int_ftype_int_int
,
5349 BFIN_BUILTIN_MAX_1X32
);
5351 def_builtin ("__builtin_bfin_add_fr1x32", int_ftype_int_int
,
5352 BFIN_BUILTIN_SSADD_1X32
);
5353 def_builtin ("__builtin_bfin_sub_fr1x32", int_ftype_int_int
,
5354 BFIN_BUILTIN_SSSUB_1X32
);
5355 def_builtin ("__builtin_bfin_negate_fr1x32", int_ftype_int
,
5356 BFIN_BUILTIN_NEG_1X32
);
5357 def_builtin ("__builtin_bfin_abs_fr1x32", int_ftype_int
,
5358 BFIN_BUILTIN_ABS_1X32
);
5359 def_builtin ("__builtin_bfin_norm_fr1x32", short_ftype_int
,
5360 BFIN_BUILTIN_NORM_1X32
);
5361 def_builtin ("__builtin_bfin_round_fr1x32", short_ftype_int
,
5362 BFIN_BUILTIN_ROUND_1X32
);
5363 def_builtin ("__builtin_bfin_mult_fr1x32", int_ftype_short_short
,
5364 BFIN_BUILTIN_MULT_1X32
);
5365 def_builtin ("__builtin_bfin_mult_fr1x32x32", int_ftype_int_int
,
5366 BFIN_BUILTIN_MULT_1X32X32
);
5367 def_builtin ("__builtin_bfin_mult_fr1x32x32NS", int_ftype_int_int
,
5368 BFIN_BUILTIN_MULT_1X32X32NS
);
5371 def_builtin ("__builtin_bfin_shl_fr1x16", short_ftype_int_int
,
5372 BFIN_BUILTIN_SSASHIFT_1X16
);
5373 def_builtin ("__builtin_bfin_shl_fr2x16", v2hi_ftype_v2hi_int
,
5374 BFIN_BUILTIN_SSASHIFT_2X16
);
5375 def_builtin ("__builtin_bfin_lshl_fr1x16", short_ftype_int_int
,
5376 BFIN_BUILTIN_LSHIFT_1X16
);
5377 def_builtin ("__builtin_bfin_lshl_fr2x16", v2hi_ftype_v2hi_int
,
5378 BFIN_BUILTIN_LSHIFT_2X16
);
5379 def_builtin ("__builtin_bfin_shl_fr1x32", int_ftype_int_int
,
5380 BFIN_BUILTIN_SSASHIFT_1X32
);
5382 /* Complex numbers. */
5383 def_builtin ("__builtin_bfin_cmplx_add", v2hi_ftype_v2hi_v2hi
,
5384 BFIN_BUILTIN_SSADD_2X16
);
5385 def_builtin ("__builtin_bfin_cmplx_sub", v2hi_ftype_v2hi_v2hi
,
5386 BFIN_BUILTIN_SSSUB_2X16
);
5387 def_builtin ("__builtin_bfin_cmplx_mul", v2hi_ftype_v2hi_v2hi
,
5388 BFIN_BUILTIN_CPLX_MUL_16
);
5389 def_builtin ("__builtin_bfin_cmplx_mac", v2hi_ftype_v2hi_v2hi_v2hi
,
5390 BFIN_BUILTIN_CPLX_MAC_16
);
5391 def_builtin ("__builtin_bfin_cmplx_msu", v2hi_ftype_v2hi_v2hi_v2hi
,
5392 BFIN_BUILTIN_CPLX_MSU_16
);
5393 def_builtin ("__builtin_bfin_cmplx_mul_s40", v2hi_ftype_v2hi_v2hi
,
5394 BFIN_BUILTIN_CPLX_MUL_16_S40
);
5395 def_builtin ("__builtin_bfin_cmplx_mac_s40", v2hi_ftype_v2hi_v2hi_v2hi
,
5396 BFIN_BUILTIN_CPLX_MAC_16_S40
);
5397 def_builtin ("__builtin_bfin_cmplx_msu_s40", v2hi_ftype_v2hi_v2hi_v2hi
,
5398 BFIN_BUILTIN_CPLX_MSU_16_S40
);
5399 def_builtin ("__builtin_bfin_csqu_fr16", v2hi_ftype_v2hi
,
5400 BFIN_BUILTIN_CPLX_SQU
);
5404 struct builtin_description
5406 const enum insn_code icode
;
5407 const char *const name
;
5408 const enum bfin_builtins code
;
5412 static const struct builtin_description bdesc_2arg
[] =
5414 { CODE_FOR_composev2hi
, "__builtin_bfin_compose_2x16", BFIN_BUILTIN_COMPOSE_2X16
, -1 },
5416 { CODE_FOR_ssashiftv2hi3
, "__builtin_bfin_shl_fr2x16", BFIN_BUILTIN_SSASHIFT_2X16
, -1 },
5417 { CODE_FOR_ssashifthi3
, "__builtin_bfin_shl_fr1x16", BFIN_BUILTIN_SSASHIFT_1X16
, -1 },
5418 { CODE_FOR_lshiftv2hi3
, "__builtin_bfin_lshl_fr2x16", BFIN_BUILTIN_LSHIFT_2X16
, -1 },
5419 { CODE_FOR_lshifthi3
, "__builtin_bfin_lshl_fr1x16", BFIN_BUILTIN_LSHIFT_1X16
, -1 },
5420 { CODE_FOR_ssashiftsi3
, "__builtin_bfin_shl_fr1x32", BFIN_BUILTIN_SSASHIFT_1X32
, -1 },
5422 { CODE_FOR_sminhi3
, "__builtin_bfin_min_fr1x16", BFIN_BUILTIN_MIN_1X16
, -1 },
5423 { CODE_FOR_smaxhi3
, "__builtin_bfin_max_fr1x16", BFIN_BUILTIN_MAX_1X16
, -1 },
5424 { CODE_FOR_ssaddhi3
, "__builtin_bfin_add_fr1x16", BFIN_BUILTIN_SSADD_1X16
, -1 },
5425 { CODE_FOR_sssubhi3
, "__builtin_bfin_sub_fr1x16", BFIN_BUILTIN_SSSUB_1X16
, -1 },
5427 { CODE_FOR_sminsi3
, "__builtin_bfin_min_fr1x32", BFIN_BUILTIN_MIN_1X32
, -1 },
5428 { CODE_FOR_smaxsi3
, "__builtin_bfin_max_fr1x32", BFIN_BUILTIN_MAX_1X32
, -1 },
5429 { CODE_FOR_ssaddsi3
, "__builtin_bfin_add_fr1x32", BFIN_BUILTIN_SSADD_1X32
, -1 },
5430 { CODE_FOR_sssubsi3
, "__builtin_bfin_sub_fr1x32", BFIN_BUILTIN_SSSUB_1X32
, -1 },
5432 { CODE_FOR_sminv2hi3
, "__builtin_bfin_min_fr2x16", BFIN_BUILTIN_MIN_2X16
, -1 },
5433 { CODE_FOR_smaxv2hi3
, "__builtin_bfin_max_fr2x16", BFIN_BUILTIN_MAX_2X16
, -1 },
5434 { CODE_FOR_ssaddv2hi3
, "__builtin_bfin_add_fr2x16", BFIN_BUILTIN_SSADD_2X16
, -1 },
5435 { CODE_FOR_sssubv2hi3
, "__builtin_bfin_sub_fr2x16", BFIN_BUILTIN_SSSUB_2X16
, -1 },
5436 { CODE_FOR_ssaddsubv2hi3
, "__builtin_bfin_dspaddsubsat", BFIN_BUILTIN_SSADDSUB_2X16
, -1 },
5437 { CODE_FOR_sssubaddv2hi3
, "__builtin_bfin_dspsubaddsat", BFIN_BUILTIN_SSSUBADD_2X16
, -1 },
5439 { CODE_FOR_flag_mulhisi
, "__builtin_bfin_mult_fr1x32", BFIN_BUILTIN_MULT_1X32
, MACFLAG_NONE
},
5440 { CODE_FOR_flag_mulhi
, "__builtin_bfin_mult_fr1x16", BFIN_BUILTIN_MULT_1X16
, MACFLAG_T
},
5441 { CODE_FOR_flag_mulhi
, "__builtin_bfin_multr_fr1x16", BFIN_BUILTIN_MULTR_1X16
, MACFLAG_NONE
},
5442 { CODE_FOR_flag_mulv2hi
, "__builtin_bfin_mult_fr2x16", BFIN_BUILTIN_MULT_2X16
, MACFLAG_T
},
5443 { CODE_FOR_flag_mulv2hi
, "__builtin_bfin_multr_fr2x16", BFIN_BUILTIN_MULTR_2X16
, MACFLAG_NONE
}
5446 static const struct builtin_description bdesc_1arg
[] =
5448 { CODE_FOR_ones
, "__builtin_bfin_ones", BFIN_BUILTIN_ONES
, 0 },
5450 { CODE_FOR_signbitshi2
, "__builtin_bfin_norm_fr1x16", BFIN_BUILTIN_NORM_1X16
, 0 },
5451 { CODE_FOR_ssneghi2
, "__builtin_bfin_negate_fr1x16", BFIN_BUILTIN_NEG_1X16
, 0 },
5452 { CODE_FOR_abshi2
, "__builtin_bfin_abs_fr1x16", BFIN_BUILTIN_ABS_1X16
, 0 },
5454 { CODE_FOR_signbitssi2
, "__builtin_bfin_norm_fr1x32", BFIN_BUILTIN_NORM_1X32
, 0 },
5455 { CODE_FOR_ssroundsi2
, "__builtin_bfin_round_fr1x32", BFIN_BUILTIN_ROUND_1X32
, 0 },
5456 { CODE_FOR_ssnegsi2
, "__builtin_bfin_negate_fr1x32", BFIN_BUILTIN_NEG_1X32
, 0 },
5457 { CODE_FOR_ssabssi2
, "__builtin_bfin_abs_fr1x32", BFIN_BUILTIN_ABS_1X32
, 0 },
5459 { CODE_FOR_movv2hi_hi_low
, "__builtin_bfin_extract_lo", BFIN_BUILTIN_EXTRACTLO
, 0 },
5460 { CODE_FOR_movv2hi_hi_high
, "__builtin_bfin_extract_hi", BFIN_BUILTIN_EXTRACTHI
, 0 },
5461 { CODE_FOR_ssnegv2hi2
, "__builtin_bfin_negate_fr2x16", BFIN_BUILTIN_NEG_2X16
, 0 },
5462 { CODE_FOR_ssabsv2hi2
, "__builtin_bfin_abs_fr2x16", BFIN_BUILTIN_ABS_2X16
, 0 }
5465 /* Errors in the source file can cause expand_expr to return const0_rtx
5466 where we expect a vector. To avoid crashing, use one of the vector
5467 clear instructions. */
5469 safe_vector_operand (rtx x
, enum machine_mode mode
)
5471 if (x
!= const0_rtx
)
5473 x
= gen_reg_rtx (SImode
);
5475 emit_insn (gen_movsi (x
, CONST0_RTX (SImode
)));
5476 return gen_lowpart (mode
, x
);
5479 /* Subroutine of bfin_expand_builtin to take care of binop insns. MACFLAG is -1
5480 if this is a normal binary op, or one of the MACFLAG_xxx constants. */
5483 bfin_expand_binop_builtin (enum insn_code icode
, tree exp
, rtx target
,
5487 tree arg0
= CALL_EXPR_ARG (exp
, 0);
5488 tree arg1
= CALL_EXPR_ARG (exp
, 1);
5489 rtx op0
= expand_expr (arg0
, NULL_RTX
, VOIDmode
, 0);
5490 rtx op1
= expand_expr (arg1
, NULL_RTX
, VOIDmode
, 0);
5491 enum machine_mode op0mode
= GET_MODE (op0
);
5492 enum machine_mode op1mode
= GET_MODE (op1
);
5493 enum machine_mode tmode
= insn_data
[icode
].operand
[0].mode
;
5494 enum machine_mode mode0
= insn_data
[icode
].operand
[1].mode
;
5495 enum machine_mode mode1
= insn_data
[icode
].operand
[2].mode
;
5497 if (VECTOR_MODE_P (mode0
))
5498 op0
= safe_vector_operand (op0
, mode0
);
5499 if (VECTOR_MODE_P (mode1
))
5500 op1
= safe_vector_operand (op1
, mode1
);
5503 || GET_MODE (target
) != tmode
5504 || ! (*insn_data
[icode
].operand
[0].predicate
) (target
, tmode
))
5505 target
= gen_reg_rtx (tmode
);
5507 if ((op0mode
== SImode
|| op0mode
== VOIDmode
) && mode0
== HImode
)
5510 op0
= gen_lowpart (HImode
, op0
);
5512 if ((op1mode
== SImode
|| op1mode
== VOIDmode
) && mode1
== HImode
)
5515 op1
= gen_lowpart (HImode
, op1
);
5517 /* In case the insn wants input operands in modes different from
5518 the result, abort. */
5519 gcc_assert ((op0mode
== mode0
|| op0mode
== VOIDmode
)
5520 && (op1mode
== mode1
|| op1mode
== VOIDmode
));
5522 if (! (*insn_data
[icode
].operand
[1].predicate
) (op0
, mode0
))
5523 op0
= copy_to_mode_reg (mode0
, op0
);
5524 if (! (*insn_data
[icode
].operand
[2].predicate
) (op1
, mode1
))
5525 op1
= copy_to_mode_reg (mode1
, op1
);
5528 pat
= GEN_FCN (icode
) (target
, op0
, op1
);
5530 pat
= GEN_FCN (icode
) (target
, op0
, op1
, GEN_INT (macflag
));
5538 /* Subroutine of bfin_expand_builtin to take care of unop insns. */
5541 bfin_expand_unop_builtin (enum insn_code icode
, tree exp
,
5545 tree arg0
= CALL_EXPR_ARG (exp
, 0);
5546 rtx op0
= expand_expr (arg0
, NULL_RTX
, VOIDmode
, 0);
5547 enum machine_mode op0mode
= GET_MODE (op0
);
5548 enum machine_mode tmode
= insn_data
[icode
].operand
[0].mode
;
5549 enum machine_mode mode0
= insn_data
[icode
].operand
[1].mode
;
5552 || GET_MODE (target
) != tmode
5553 || ! (*insn_data
[icode
].operand
[0].predicate
) (target
, tmode
))
5554 target
= gen_reg_rtx (tmode
);
5556 if (VECTOR_MODE_P (mode0
))
5557 op0
= safe_vector_operand (op0
, mode0
);
5559 if (op0mode
== SImode
&& mode0
== HImode
)
5562 op0
= gen_lowpart (HImode
, op0
);
5564 gcc_assert (op0mode
== mode0
|| op0mode
== VOIDmode
);
5566 if (! (*insn_data
[icode
].operand
[1].predicate
) (op0
, mode0
))
5567 op0
= copy_to_mode_reg (mode0
, op0
);
5569 pat
= GEN_FCN (icode
) (target
, op0
);
5576 /* Expand an expression EXP that calls a built-in function,
5577 with result going to TARGET if that's convenient
5578 (and in mode MODE if that's convenient).
5579 SUBTARGET may be used as the target for computing one of EXP's operands.
5580 IGNORE is nonzero if the value is to be ignored. */
5583 bfin_expand_builtin (tree exp
, rtx target ATTRIBUTE_UNUSED
,
5584 rtx subtarget ATTRIBUTE_UNUSED
,
5585 enum machine_mode mode ATTRIBUTE_UNUSED
,
5586 int ignore ATTRIBUTE_UNUSED
)
5589 enum insn_code icode
;
5590 const struct builtin_description
*d
;
5591 tree fndecl
= TREE_OPERAND (CALL_EXPR_FN (exp
), 0);
5592 unsigned int fcode
= DECL_FUNCTION_CODE (fndecl
);
5593 tree arg0
, arg1
, arg2
;
5594 rtx op0
, op1
, op2
, accvec
, pat
, tmp1
, tmp2
, a0reg
, a1reg
;
5595 enum machine_mode tmode
, mode0
;
5599 case BFIN_BUILTIN_CSYNC
:
5600 emit_insn (gen_csync ());
5602 case BFIN_BUILTIN_SSYNC
:
5603 emit_insn (gen_ssync ());
5606 case BFIN_BUILTIN_DIFFHL_2X16
:
5607 case BFIN_BUILTIN_DIFFLH_2X16
:
5608 case BFIN_BUILTIN_SUM_2X16
:
5609 arg0
= CALL_EXPR_ARG (exp
, 0);
5610 op0
= expand_expr (arg0
, NULL_RTX
, VOIDmode
, 0);
5611 icode
= (fcode
== BFIN_BUILTIN_DIFFHL_2X16
? CODE_FOR_subhilov2hi3
5612 : fcode
== BFIN_BUILTIN_DIFFLH_2X16
? CODE_FOR_sublohiv2hi3
5613 : CODE_FOR_ssaddhilov2hi3
);
5614 tmode
= insn_data
[icode
].operand
[0].mode
;
5615 mode0
= insn_data
[icode
].operand
[1].mode
;
5618 || GET_MODE (target
) != tmode
5619 || ! (*insn_data
[icode
].operand
[0].predicate
) (target
, tmode
))
5620 target
= gen_reg_rtx (tmode
);
5622 if (VECTOR_MODE_P (mode0
))
5623 op0
= safe_vector_operand (op0
, mode0
);
5625 if (! (*insn_data
[icode
].operand
[1].predicate
) (op0
, mode0
))
5626 op0
= copy_to_mode_reg (mode0
, op0
);
5628 pat
= GEN_FCN (icode
) (target
, op0
, op0
);
5634 case BFIN_BUILTIN_MULT_1X32X32
:
5635 case BFIN_BUILTIN_MULT_1X32X32NS
:
5636 arg0
= CALL_EXPR_ARG (exp
, 0);
5637 arg1
= CALL_EXPR_ARG (exp
, 1);
5638 op0
= expand_expr (arg0
, NULL_RTX
, VOIDmode
, 0);
5639 op1
= expand_expr (arg1
, NULL_RTX
, VOIDmode
, 0);
5641 || !register_operand (target
, SImode
))
5642 target
= gen_reg_rtx (SImode
);
5644 a1reg
= gen_rtx_REG (PDImode
, REG_A1
);
5645 a0reg
= gen_rtx_REG (PDImode
, REG_A0
);
5646 tmp1
= gen_lowpart (V2HImode
, op0
);
5647 tmp2
= gen_lowpart (V2HImode
, op1
);
5648 emit_insn (gen_flag_macinit1hi (a1reg
,
5649 gen_lowpart (HImode
, op0
),
5650 gen_lowpart (HImode
, op1
),
5651 GEN_INT (MACFLAG_FU
)));
5652 emit_insn (gen_lshrpdi3 (a1reg
, a1reg
, GEN_INT (16)));
5654 if (fcode
== BFIN_BUILTIN_MULT_1X32X32
)
5655 emit_insn (gen_flag_mul_macv2hi_parts_acconly (a0reg
, a1reg
, tmp1
, tmp2
,
5656 const1_rtx
, const1_rtx
,
5657 const1_rtx
, const0_rtx
, a1reg
,
5658 const0_rtx
, GEN_INT (MACFLAG_NONE
),
5659 GEN_INT (MACFLAG_M
)));
5662 /* For saturating multiplication, there's exactly one special case
5663 to be handled: multiplying the smallest negative value with
5664 itself. Due to shift correction in fractional multiplies, this
5665 can overflow. Iff this happens, OP2 will contain 1, which, when
5666 added in 32 bits to the smallest negative, wraps to the largest
5667 positive, which is the result we want. */
5668 op2
= gen_reg_rtx (V2HImode
);
5669 emit_insn (gen_packv2hi (op2
, tmp1
, tmp2
, const0_rtx
, const0_rtx
));
5670 emit_insn (gen_movsibi (gen_rtx_REG (BImode
, REG_CC
),
5671 gen_lowpart (SImode
, op2
)));
5672 emit_insn (gen_flag_mul_macv2hi_parts_acconly_andcc0 (a0reg
, a1reg
, tmp1
, tmp2
,
5673 const1_rtx
, const1_rtx
,
5674 const1_rtx
, const0_rtx
, a1reg
,
5675 const0_rtx
, GEN_INT (MACFLAG_NONE
),
5676 GEN_INT (MACFLAG_M
)));
5677 op2
= gen_reg_rtx (SImode
);
5678 emit_insn (gen_movbisi (op2
, gen_rtx_REG (BImode
, REG_CC
)));
5680 emit_insn (gen_flag_machi_parts_acconly (a1reg
, tmp2
, tmp1
,
5681 const1_rtx
, const0_rtx
,
5682 a1reg
, const0_rtx
, GEN_INT (MACFLAG_M
)));
5683 emit_insn (gen_ashrpdi3 (a1reg
, a1reg
, GEN_INT (15)));
5684 emit_insn (gen_sum_of_accumulators (target
, a0reg
, a0reg
, a1reg
));
5685 if (fcode
== BFIN_BUILTIN_MULT_1X32X32NS
)
5686 emit_insn (gen_addsi3 (target
, target
, op2
));
5689 case BFIN_BUILTIN_CPLX_MUL_16
:
5690 case BFIN_BUILTIN_CPLX_MUL_16_S40
:
5691 arg0
= CALL_EXPR_ARG (exp
, 0);
5692 arg1
= CALL_EXPR_ARG (exp
, 1);
5693 op0
= expand_expr (arg0
, NULL_RTX
, VOIDmode
, 0);
5694 op1
= expand_expr (arg1
, NULL_RTX
, VOIDmode
, 0);
5695 accvec
= gen_reg_rtx (V2PDImode
);
5698 || GET_MODE (target
) != V2HImode
5699 || ! (*insn_data
[icode
].operand
[0].predicate
) (target
, V2HImode
))
5700 target
= gen_reg_rtx (tmode
);
5701 if (! register_operand (op0
, GET_MODE (op0
)))
5702 op0
= copy_to_mode_reg (GET_MODE (op0
), op0
);
5703 if (! register_operand (op1
, GET_MODE (op1
)))
5704 op1
= copy_to_mode_reg (GET_MODE (op1
), op1
);
5706 if (fcode
== BFIN_BUILTIN_CPLX_MUL_16
)
5707 emit_insn (gen_flag_macinit1v2hi_parts (accvec
, op0
, op1
, const0_rtx
,
5708 const0_rtx
, const0_rtx
,
5709 const1_rtx
, GEN_INT (MACFLAG_W32
)));
5711 emit_insn (gen_flag_macinit1v2hi_parts (accvec
, op0
, op1
, const0_rtx
,
5712 const0_rtx
, const0_rtx
,
5713 const1_rtx
, GEN_INT (MACFLAG_NONE
)));
5714 emit_insn (gen_flag_macv2hi_parts (target
, op0
, op1
, const1_rtx
,
5715 const1_rtx
, const1_rtx
,
5716 const0_rtx
, accvec
, const1_rtx
, const0_rtx
,
5717 GEN_INT (MACFLAG_NONE
), accvec
));
5721 case BFIN_BUILTIN_CPLX_MAC_16
:
5722 case BFIN_BUILTIN_CPLX_MSU_16
:
5723 case BFIN_BUILTIN_CPLX_MAC_16_S40
:
5724 case BFIN_BUILTIN_CPLX_MSU_16_S40
:
5725 arg0
= CALL_EXPR_ARG (exp
, 0);
5726 arg1
= CALL_EXPR_ARG (exp
, 1);
5727 arg2
= CALL_EXPR_ARG (exp
, 2);
5728 op0
= expand_expr (arg0
, NULL_RTX
, VOIDmode
, 0);
5729 op1
= expand_expr (arg1
, NULL_RTX
, VOIDmode
, 0);
5730 op2
= expand_expr (arg2
, NULL_RTX
, VOIDmode
, 0);
5731 accvec
= gen_reg_rtx (V2PDImode
);
5734 || GET_MODE (target
) != V2HImode
5735 || ! (*insn_data
[icode
].operand
[0].predicate
) (target
, V2HImode
))
5736 target
= gen_reg_rtx (tmode
);
5737 if (! register_operand (op1
, GET_MODE (op1
)))
5738 op1
= copy_to_mode_reg (GET_MODE (op1
), op1
);
5739 if (! register_operand (op2
, GET_MODE (op2
)))
5740 op2
= copy_to_mode_reg (GET_MODE (op2
), op2
);
5742 tmp1
= gen_reg_rtx (SImode
);
5743 tmp2
= gen_reg_rtx (SImode
);
5744 emit_insn (gen_ashlsi3 (tmp1
, gen_lowpart (SImode
, op0
), GEN_INT (16)));
5745 emit_move_insn (tmp2
, gen_lowpart (SImode
, op0
));
5746 emit_insn (gen_movstricthi_1 (gen_lowpart (HImode
, tmp2
), const0_rtx
));
5747 emit_insn (gen_load_accumulator_pair (accvec
, tmp1
, tmp2
));
5748 if (fcode
== BFIN_BUILTIN_CPLX_MAC_16
5749 || fcode
== BFIN_BUILTIN_CPLX_MSU_16
)
5750 emit_insn (gen_flag_macv2hi_parts_acconly (accvec
, op1
, op2
, const0_rtx
,
5751 const0_rtx
, const0_rtx
,
5752 const1_rtx
, accvec
, const0_rtx
,
5754 GEN_INT (MACFLAG_W32
)));
5756 emit_insn (gen_flag_macv2hi_parts_acconly (accvec
, op1
, op2
, const0_rtx
,
5757 const0_rtx
, const0_rtx
,
5758 const1_rtx
, accvec
, const0_rtx
,
5760 GEN_INT (MACFLAG_NONE
)));
5761 if (fcode
== BFIN_BUILTIN_CPLX_MAC_16
5762 || fcode
== BFIN_BUILTIN_CPLX_MAC_16_S40
)
5772 emit_insn (gen_flag_macv2hi_parts (target
, op1
, op2
, const1_rtx
,
5773 const1_rtx
, const1_rtx
,
5774 const0_rtx
, accvec
, tmp1
, tmp2
,
5775 GEN_INT (MACFLAG_NONE
), accvec
));
5779 case BFIN_BUILTIN_CPLX_SQU
:
5780 arg0
= CALL_EXPR_ARG (exp
, 0);
5781 op0
= expand_expr (arg0
, NULL_RTX
, VOIDmode
, 0);
5782 accvec
= gen_reg_rtx (V2PDImode
);
5783 icode
= CODE_FOR_flag_mulv2hi
;
5784 tmp1
= gen_reg_rtx (V2HImode
);
5785 tmp2
= gen_reg_rtx (V2HImode
);
5788 || GET_MODE (target
) != V2HImode
5789 || ! (*insn_data
[icode
].operand
[0].predicate
) (target
, V2HImode
))
5790 target
= gen_reg_rtx (V2HImode
);
5791 if (! register_operand (op0
, GET_MODE (op0
)))
5792 op0
= copy_to_mode_reg (GET_MODE (op0
), op0
);
5794 emit_insn (gen_flag_mulv2hi (tmp1
, op0
, op0
, GEN_INT (MACFLAG_NONE
)));
5796 emit_insn (gen_flag_mulhi_parts (tmp2
, op0
, op0
, const0_rtx
,
5797 const0_rtx
, const1_rtx
,
5798 GEN_INT (MACFLAG_NONE
)));
5800 emit_insn (gen_ssaddhi3_parts (target
, tmp2
, tmp2
, const1_rtx
,
5801 const0_rtx
, const0_rtx
));
5803 emit_insn (gen_sssubhi3_parts (target
, tmp1
, tmp1
, const0_rtx
,
5804 const0_rtx
, const1_rtx
));
5812 for (i
= 0, d
= bdesc_2arg
; i
< ARRAY_SIZE (bdesc_2arg
); i
++, d
++)
5813 if (d
->code
== fcode
)
5814 return bfin_expand_binop_builtin (d
->icode
, exp
, target
,
5817 for (i
= 0, d
= bdesc_1arg
; i
< ARRAY_SIZE (bdesc_1arg
); i
++, d
++)
5818 if (d
->code
== fcode
)
5819 return bfin_expand_unop_builtin (d
->icode
, exp
, target
);
5824 #undef TARGET_INIT_BUILTINS
5825 #define TARGET_INIT_BUILTINS bfin_init_builtins
5827 #undef TARGET_EXPAND_BUILTIN
5828 #define TARGET_EXPAND_BUILTIN bfin_expand_builtin
5830 #undef TARGET_ASM_GLOBALIZE_LABEL
5831 #define TARGET_ASM_GLOBALIZE_LABEL bfin_globalize_label
5833 #undef TARGET_ASM_FILE_START
5834 #define TARGET_ASM_FILE_START output_file_start
5836 #undef TARGET_ATTRIBUTE_TABLE
5837 #define TARGET_ATTRIBUTE_TABLE bfin_attribute_table
5839 #undef TARGET_COMP_TYPE_ATTRIBUTES
5840 #define TARGET_COMP_TYPE_ATTRIBUTES bfin_comp_type_attributes
5842 #undef TARGET_RTX_COSTS
5843 #define TARGET_RTX_COSTS bfin_rtx_costs
5845 #undef TARGET_ADDRESS_COST
5846 #define TARGET_ADDRESS_COST bfin_address_cost
5848 #undef TARGET_ASM_INTEGER
5849 #define TARGET_ASM_INTEGER bfin_assemble_integer
5851 #undef TARGET_MACHINE_DEPENDENT_REORG
5852 #define TARGET_MACHINE_DEPENDENT_REORG bfin_reorg
5854 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
5855 #define TARGET_FUNCTION_OK_FOR_SIBCALL bfin_function_ok_for_sibcall
5857 #undef TARGET_ASM_OUTPUT_MI_THUNK
5858 #define TARGET_ASM_OUTPUT_MI_THUNK bfin_output_mi_thunk
5859 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
5860 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true
5862 #undef TARGET_SCHED_ADJUST_COST
5863 #define TARGET_SCHED_ADJUST_COST bfin_adjust_cost
5865 #undef TARGET_SCHED_ISSUE_RATE
5866 #define TARGET_SCHED_ISSUE_RATE bfin_issue_rate
5868 #undef TARGET_PROMOTE_PROTOTYPES
5869 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
5870 #undef TARGET_PROMOTE_FUNCTION_ARGS
5871 #define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_const_tree_true
5872 #undef TARGET_PROMOTE_FUNCTION_RETURN
5873 #define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_const_tree_true
5875 #undef TARGET_ARG_PARTIAL_BYTES
5876 #define TARGET_ARG_PARTIAL_BYTES bfin_arg_partial_bytes
5878 #undef TARGET_PASS_BY_REFERENCE
5879 #define TARGET_PASS_BY_REFERENCE bfin_pass_by_reference
5881 #undef TARGET_SETUP_INCOMING_VARARGS
5882 #define TARGET_SETUP_INCOMING_VARARGS setup_incoming_varargs
5884 #undef TARGET_STRUCT_VALUE_RTX
5885 #define TARGET_STRUCT_VALUE_RTX bfin_struct_value_rtx
5887 #undef TARGET_VECTOR_MODE_SUPPORTED_P
5888 #define TARGET_VECTOR_MODE_SUPPORTED_P bfin_vector_mode_supported_p
5890 #undef TARGET_HANDLE_OPTION
5891 #define TARGET_HANDLE_OPTION bfin_handle_option
5893 #undef TARGET_DEFAULT_TARGET_FLAGS
5894 #define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
5896 #undef TARGET_SECONDARY_RELOAD
5897 #define TARGET_SECONDARY_RELOAD bfin_secondary_reload
5899 #undef TARGET_DELEGITIMIZE_ADDRESS
5900 #define TARGET_DELEGITIMIZE_ADDRESS bfin_delegitimize_address
5902 #undef TARGET_CANNOT_FORCE_CONST_MEM
5903 #define TARGET_CANNOT_FORCE_CONST_MEM bfin_cannot_force_const_mem
5905 struct gcc_target targetm
= TARGET_INITIALIZER
;