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"
52 #include "tm-constrs.h"
54 #include "basic-block.h"
55 #include "cfglayout.h"
59 /* A C structure for machine-specific, per-function data.
60 This is added to the cfun structure. */
61 struct machine_function
GTY(())
63 /* Set if we are notified by the doloop pass that a hardware loop
65 int has_hardware_loops
;
66 /* Set if we create a memcpy pattern that uses loop registers. */
67 int has_loopreg_clobber
;
70 /* Test and compare insns in bfin.md store the information needed to
71 generate branch and scc insns here. */
72 rtx bfin_compare_op0
, bfin_compare_op1
;
74 /* RTX for condition code flag register and RETS register */
75 extern GTY(()) rtx bfin_cc_rtx
;
76 extern GTY(()) rtx bfin_rets_rtx
;
77 rtx bfin_cc_rtx
, bfin_rets_rtx
;
79 int max_arg_registers
= 0;
81 /* Arrays used when emitting register names. */
82 const char *short_reg_names
[] = SHORT_REGISTER_NAMES
;
83 const char *high_reg_names
[] = HIGH_REGISTER_NAMES
;
84 const char *dregs_pair_names
[] = DREGS_PAIR_NAMES
;
85 const char *byte_reg_names
[] = BYTE_REGISTER_NAMES
;
87 static int arg_regs
[] = FUNCTION_ARG_REGISTERS
;
89 /* Nonzero if -mshared-library-id was given. */
90 static int bfin_lib_id_given
;
92 /* Nonzero if -fschedule-insns2 was given. We override it and
93 call the scheduler ourselves during reorg. */
94 static int bfin_flag_schedule_insns2
;
96 /* Determines whether we run variable tracking in machine dependent
98 static int bfin_flag_var_tracking
;
101 bfin_cpu_t bfin_cpu_type
= BFIN_CPU_UNKNOWN
;
103 /* -msi-revision support. There are three special values:
104 -1 -msi-revision=none.
105 0xffff -msi-revision=any. */
106 int bfin_si_revision
;
108 /* The workarounds enabled */
109 unsigned int bfin_workarounds
= 0;
116 unsigned int workarounds
;
119 struct bfin_cpu bfin_cpus
[] =
121 {"bf512", BFIN_CPU_BF512
, 0x0000,
122 WA_SPECULATIVE_LOADS
},
124 {"bf514", BFIN_CPU_BF514
, 0x0000,
125 WA_SPECULATIVE_LOADS
},
127 {"bf516", BFIN_CPU_BF516
, 0x0000,
128 WA_SPECULATIVE_LOADS
},
130 {"bf518", BFIN_CPU_BF518
, 0x0000,
131 WA_SPECULATIVE_LOADS
},
133 {"bf522", BFIN_CPU_BF522
, 0x0002,
134 WA_SPECULATIVE_LOADS
},
135 {"bf522", BFIN_CPU_BF522
, 0x0001,
136 WA_SPECULATIVE_LOADS
| WA_RETS
},
137 {"bf522", BFIN_CPU_BF522
, 0x0000,
138 WA_SPECULATIVE_LOADS
| WA_RETS
},
140 {"bf523", BFIN_CPU_BF523
, 0x0002,
141 WA_SPECULATIVE_LOADS
},
142 {"bf523", BFIN_CPU_BF523
, 0x0001,
143 WA_SPECULATIVE_LOADS
| WA_RETS
},
144 {"bf523", BFIN_CPU_BF523
, 0x0000,
145 WA_SPECULATIVE_LOADS
| WA_RETS
},
147 {"bf524", BFIN_CPU_BF524
, 0x0002,
148 WA_SPECULATIVE_LOADS
},
149 {"bf524", BFIN_CPU_BF524
, 0x0001,
150 WA_SPECULATIVE_LOADS
| WA_RETS
},
151 {"bf524", BFIN_CPU_BF524
, 0x0000,
152 WA_SPECULATIVE_LOADS
| WA_RETS
},
154 {"bf525", BFIN_CPU_BF525
, 0x0002,
155 WA_SPECULATIVE_LOADS
},
156 {"bf525", BFIN_CPU_BF525
, 0x0001,
157 WA_SPECULATIVE_LOADS
| WA_RETS
},
158 {"bf525", BFIN_CPU_BF525
, 0x0000,
159 WA_SPECULATIVE_LOADS
| WA_RETS
},
161 {"bf526", BFIN_CPU_BF526
, 0x0002,
162 WA_SPECULATIVE_LOADS
},
163 {"bf526", BFIN_CPU_BF526
, 0x0001,
164 WA_SPECULATIVE_LOADS
| WA_RETS
},
165 {"bf526", BFIN_CPU_BF526
, 0x0000,
166 WA_SPECULATIVE_LOADS
| WA_RETS
},
168 {"bf527", BFIN_CPU_BF527
, 0x0002,
169 WA_SPECULATIVE_LOADS
},
170 {"bf527", BFIN_CPU_BF527
, 0x0001,
171 WA_SPECULATIVE_LOADS
| WA_RETS
},
172 {"bf527", BFIN_CPU_BF527
, 0x0000,
173 WA_SPECULATIVE_LOADS
| WA_RETS
},
175 {"bf531", BFIN_CPU_BF531
, 0x0006,
176 WA_SPECULATIVE_LOADS
},
177 {"bf531", BFIN_CPU_BF531
, 0x0005,
178 WA_SPECULATIVE_LOADS
| WA_RETS
| WA_05000283
| WA_05000315
},
179 {"bf531", BFIN_CPU_BF531
, 0x0004,
180 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
| WA_RETS
181 | WA_05000283
| WA_05000257
| WA_05000315
},
182 {"bf531", BFIN_CPU_BF531
, 0x0003,
183 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
| WA_RETS
184 | WA_05000283
| WA_05000257
| WA_05000315
},
186 {"bf532", BFIN_CPU_BF532
, 0x0006,
187 WA_SPECULATIVE_LOADS
},
188 {"bf532", BFIN_CPU_BF532
, 0x0005,
189 WA_SPECULATIVE_LOADS
| WA_RETS
| WA_05000283
| WA_05000315
},
190 {"bf532", BFIN_CPU_BF532
, 0x0004,
191 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
| WA_RETS
192 | WA_05000283
| WA_05000257
| WA_05000315
},
193 {"bf532", BFIN_CPU_BF532
, 0x0003,
194 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
| WA_RETS
195 | WA_05000283
| WA_05000257
| WA_05000315
},
197 {"bf533", BFIN_CPU_BF533
, 0x0006,
198 WA_SPECULATIVE_LOADS
},
199 {"bf533", BFIN_CPU_BF533
, 0x0005,
200 WA_SPECULATIVE_LOADS
| WA_RETS
| WA_05000283
| WA_05000315
},
201 {"bf533", BFIN_CPU_BF533
, 0x0004,
202 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
| WA_RETS
203 | WA_05000283
| WA_05000257
| WA_05000315
},
204 {"bf533", BFIN_CPU_BF533
, 0x0003,
205 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
| WA_RETS
206 | WA_05000283
| WA_05000257
| WA_05000315
},
208 {"bf534", BFIN_CPU_BF534
, 0x0003,
209 WA_SPECULATIVE_LOADS
| WA_RETS
},
210 {"bf534", BFIN_CPU_BF534
, 0x0002,
211 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
| WA_RETS
212 | WA_05000283
| WA_05000257
| WA_05000315
},
213 {"bf534", BFIN_CPU_BF534
, 0x0001,
214 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
| WA_RETS
215 | WA_05000283
| WA_05000257
| WA_05000315
},
217 {"bf536", BFIN_CPU_BF536
, 0x0003,
218 WA_SPECULATIVE_LOADS
| WA_RETS
},
219 {"bf536", BFIN_CPU_BF536
, 0x0002,
220 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
| WA_RETS
221 | WA_05000283
| WA_05000257
| WA_05000315
},
222 {"bf536", BFIN_CPU_BF536
, 0x0001,
223 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
| WA_RETS
224 | WA_05000283
| WA_05000257
| WA_05000315
},
226 {"bf537", BFIN_CPU_BF537
, 0x0003,
227 WA_SPECULATIVE_LOADS
| WA_RETS
},
228 {"bf537", BFIN_CPU_BF537
, 0x0002,
229 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
| WA_RETS
230 | WA_05000283
| WA_05000257
| WA_05000315
},
231 {"bf537", BFIN_CPU_BF537
, 0x0001,
232 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
| WA_RETS
233 | WA_05000283
| WA_05000257
| WA_05000315
},
235 {"bf538", BFIN_CPU_BF538
, 0x0005,
236 WA_SPECULATIVE_LOADS
},
237 {"bf538", BFIN_CPU_BF538
, 0x0004,
238 WA_SPECULATIVE_LOADS
| WA_RETS
},
239 {"bf538", BFIN_CPU_BF538
, 0x0003,
240 WA_SPECULATIVE_LOADS
| WA_RETS
241 | WA_05000283
| WA_05000315
},
242 {"bf538", BFIN_CPU_BF538
, 0x0002,
243 WA_SPECULATIVE_LOADS
| WA_RETS
| WA_05000283
| WA_05000257
| WA_05000315
},
245 {"bf539", BFIN_CPU_BF539
, 0x0005,
246 WA_SPECULATIVE_LOADS
},
247 {"bf539", BFIN_CPU_BF539
, 0x0004,
248 WA_SPECULATIVE_LOADS
| WA_RETS
},
249 {"bf539", BFIN_CPU_BF539
, 0x0003,
250 WA_SPECULATIVE_LOADS
| WA_RETS
251 | WA_05000283
| WA_05000315
},
252 {"bf539", BFIN_CPU_BF539
, 0x0002,
253 WA_SPECULATIVE_LOADS
| WA_RETS
254 | WA_05000283
| WA_05000257
| WA_05000315
},
256 {"bf542", BFIN_CPU_BF542
, 0x0002,
257 WA_SPECULATIVE_LOADS
| WA_INDIRECT_CALLS
},
258 {"bf542", BFIN_CPU_BF542
, 0x0001,
259 WA_SPECULATIVE_LOADS
| WA_RETS
| WA_INDIRECT_CALLS
},
260 {"bf542", BFIN_CPU_BF542
, 0x0000,
261 WA_SPECULATIVE_LOADS
| WA_RETS
| WA_INDIRECT_CALLS
},
263 {"bf544", BFIN_CPU_BF544
, 0x0002,
264 WA_SPECULATIVE_LOADS
| WA_INDIRECT_CALLS
},
265 {"bf544", BFIN_CPU_BF544
, 0x0001,
266 WA_SPECULATIVE_LOADS
| WA_RETS
| WA_INDIRECT_CALLS
},
267 {"bf544", BFIN_CPU_BF544
, 0x0000,
268 WA_SPECULATIVE_LOADS
| WA_RETS
| WA_INDIRECT_CALLS
},
270 {"bf547", BFIN_CPU_BF547
, 0x0002,
271 WA_SPECULATIVE_LOADS
| WA_INDIRECT_CALLS
},
272 {"bf547", BFIN_CPU_BF547
, 0x0001,
273 WA_SPECULATIVE_LOADS
| WA_RETS
| WA_INDIRECT_CALLS
},
274 {"bf547", BFIN_CPU_BF547
, 0x0000,
275 WA_SPECULATIVE_LOADS
| WA_RETS
| WA_INDIRECT_CALLS
},
277 {"bf548", BFIN_CPU_BF548
, 0x0002,
278 WA_SPECULATIVE_LOADS
| WA_INDIRECT_CALLS
},
279 {"bf548", BFIN_CPU_BF548
, 0x0001,
280 WA_SPECULATIVE_LOADS
| WA_RETS
| WA_INDIRECT_CALLS
},
281 {"bf548", BFIN_CPU_BF548
, 0x0000,
282 WA_SPECULATIVE_LOADS
| WA_RETS
| WA_INDIRECT_CALLS
},
284 {"bf549", BFIN_CPU_BF549
, 0x0002,
285 WA_SPECULATIVE_LOADS
| WA_INDIRECT_CALLS
},
286 {"bf549", BFIN_CPU_BF549
, 0x0001,
287 WA_SPECULATIVE_LOADS
| WA_RETS
| WA_INDIRECT_CALLS
},
288 {"bf549", BFIN_CPU_BF549
, 0x0000,
289 WA_SPECULATIVE_LOADS
| WA_RETS
| WA_INDIRECT_CALLS
},
291 {"bf561", BFIN_CPU_BF561
, 0x0005, WA_RETS
292 | WA_05000283
| WA_05000315
},
293 {"bf561", BFIN_CPU_BF561
, 0x0003,
294 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
| WA_RETS
295 | WA_05000283
| WA_05000257
| WA_05000315
},
296 {"bf561", BFIN_CPU_BF561
, 0x0002,
297 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
| WA_RETS
298 | WA_05000283
| WA_05000257
| WA_05000315
},
303 int splitting_for_sched
;
306 bfin_globalize_label (FILE *stream
, const char *name
)
308 fputs (".global ", stream
);
309 assemble_name (stream
, name
);
315 output_file_start (void)
317 FILE *file
= asm_out_file
;
320 /* Variable tracking should be run after all optimizations which change order
321 of insns. It also needs a valid CFG. This can't be done in
322 override_options, because flag_var_tracking is finalized after
324 bfin_flag_var_tracking
= flag_var_tracking
;
325 flag_var_tracking
= 0;
327 fprintf (file
, ".file \"%s\";\n", input_filename
);
329 for (i
= 0; arg_regs
[i
] >= 0; i
++)
331 max_arg_registers
= i
; /* how many arg reg used */
334 /* Called early in the compilation to conditionally modify
335 fixed_regs/call_used_regs. */
338 conditional_register_usage (void)
340 /* initialize condition code flag register rtx */
341 bfin_cc_rtx
= gen_rtx_REG (BImode
, REG_CC
);
342 bfin_rets_rtx
= gen_rtx_REG (Pmode
, REG_RETS
);
345 /* Examine machine-dependent attributes of function type FUNTYPE and return its
346 type. See the definition of E_FUNKIND. */
349 funkind (const_tree funtype
)
351 tree attrs
= TYPE_ATTRIBUTES (funtype
);
352 if (lookup_attribute ("interrupt_handler", attrs
))
353 return INTERRUPT_HANDLER
;
354 else if (lookup_attribute ("exception_handler", attrs
))
355 return EXCPT_HANDLER
;
356 else if (lookup_attribute ("nmi_handler", attrs
))
362 /* Legitimize PIC addresses. If the address is already position-independent,
363 we return ORIG. Newly generated position-independent addresses go into a
364 reg. This is REG if nonzero, otherwise we allocate register(s) as
365 necessary. PICREG is the register holding the pointer to the PIC offset
369 legitimize_pic_address (rtx orig
, rtx reg
, rtx picreg
)
374 if (GET_CODE (addr
) == SYMBOL_REF
|| GET_CODE (addr
) == LABEL_REF
)
379 if (TARGET_ID_SHARED_LIBRARY
)
380 unspec
= UNSPEC_MOVE_PIC
;
381 else if (GET_CODE (addr
) == SYMBOL_REF
382 && SYMBOL_REF_FUNCTION_P (addr
))
383 unspec
= UNSPEC_FUNCDESC_GOT17M4
;
385 unspec
= UNSPEC_MOVE_FDPIC
;
389 gcc_assert (can_create_pseudo_p ());
390 reg
= gen_reg_rtx (Pmode
);
393 tmp
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, addr
), unspec
);
394 new_rtx
= gen_const_mem (Pmode
, gen_rtx_PLUS (Pmode
, picreg
, tmp
));
396 emit_move_insn (reg
, new_rtx
);
397 if (picreg
== pic_offset_table_rtx
)
398 crtl
->uses_pic_offset_table
= 1;
402 else if (GET_CODE (addr
) == CONST
|| GET_CODE (addr
) == PLUS
)
406 if (GET_CODE (addr
) == CONST
)
408 addr
= XEXP (addr
, 0);
409 gcc_assert (GET_CODE (addr
) == PLUS
);
412 if (XEXP (addr
, 0) == picreg
)
417 gcc_assert (can_create_pseudo_p ());
418 reg
= gen_reg_rtx (Pmode
);
421 base
= legitimize_pic_address (XEXP (addr
, 0), reg
, picreg
);
422 addr
= legitimize_pic_address (XEXP (addr
, 1),
423 base
== reg
? NULL_RTX
: reg
,
426 if (GET_CODE (addr
) == CONST_INT
)
428 gcc_assert (! reload_in_progress
&& ! reload_completed
);
429 addr
= force_reg (Pmode
, addr
);
432 if (GET_CODE (addr
) == PLUS
&& CONSTANT_P (XEXP (addr
, 1)))
434 base
= gen_rtx_PLUS (Pmode
, base
, XEXP (addr
, 0));
435 addr
= XEXP (addr
, 1);
438 return gen_rtx_PLUS (Pmode
, base
, addr
);
444 /* Stack frame layout. */
446 /* For a given REGNO, determine whether it must be saved in the function
447 prologue. IS_INTHANDLER specifies whether we're generating a normal
448 prologue or an interrupt/exception one. */
450 must_save_p (bool is_inthandler
, unsigned regno
)
452 if (D_REGNO_P (regno
))
454 bool is_eh_return_reg
= false;
455 if (crtl
->calls_eh_return
)
460 unsigned test
= EH_RETURN_DATA_REGNO (j
);
461 if (test
== INVALID_REGNUM
)
464 is_eh_return_reg
= true;
468 return (is_eh_return_reg
469 || (df_regs_ever_live_p (regno
)
470 && !fixed_regs
[regno
]
471 && (is_inthandler
|| !call_used_regs
[regno
])));
473 else if (P_REGNO_P (regno
))
475 return ((df_regs_ever_live_p (regno
)
476 && !fixed_regs
[regno
]
477 && (is_inthandler
|| !call_used_regs
[regno
]))
479 && (ENABLE_WA_05000283
|| ENABLE_WA_05000315
)
482 && regno
== PIC_OFFSET_TABLE_REGNUM
483 && (crtl
->uses_pic_offset_table
484 || (TARGET_ID_SHARED_LIBRARY
&& !current_function_is_leaf
))));
487 return ((is_inthandler
|| !call_used_regs
[regno
])
488 && (df_regs_ever_live_p (regno
)
489 || (!leaf_function_p () && call_used_regs
[regno
])));
493 /* Compute the number of DREGS to save with a push_multiple operation.
494 This could include registers that aren't modified in the function,
495 since push_multiple only takes a range of registers.
496 If IS_INTHANDLER, then everything that is live must be saved, even
497 if normally call-clobbered.
498 If CONSECUTIVE, return the number of registers we can save in one
499 instruction with a push/pop multiple instruction. */
502 n_dregs_to_save (bool is_inthandler
, bool consecutive
)
507 for (i
= REG_R7
+ 1; i
-- != REG_R0
;)
509 if (must_save_p (is_inthandler
, i
))
511 else if (consecutive
)
517 /* Like n_dregs_to_save, but compute number of PREGS to save. */
520 n_pregs_to_save (bool is_inthandler
, bool consecutive
)
525 for (i
= REG_P5
+ 1; i
-- != REG_P0
;)
526 if (must_save_p (is_inthandler
, i
))
528 else if (consecutive
)
533 /* Determine if we are going to save the frame pointer in the prologue. */
536 must_save_fp_p (void)
538 return frame_pointer_needed
|| df_regs_ever_live_p (REG_FP
);
542 stack_frame_needed_p (void)
544 /* EH return puts a new return address into the frame using an
545 address relative to the frame pointer. */
546 if (crtl
->calls_eh_return
)
548 return frame_pointer_needed
;
551 /* Emit code to save registers in the prologue. SAVEALL is nonzero if we
552 must save all registers; this is used for interrupt handlers.
553 SPREG contains (reg:SI REG_SP). IS_INTHANDLER is true if we're doing
554 this for an interrupt (or exception) handler. */
557 expand_prologue_reg_save (rtx spreg
, int saveall
, bool is_inthandler
)
559 rtx predec1
= gen_rtx_PRE_DEC (SImode
, spreg
);
560 rtx predec
= gen_rtx_MEM (SImode
, predec1
);
561 int ndregs
= saveall
? 8 : n_dregs_to_save (is_inthandler
, false);
562 int npregs
= saveall
? 6 : n_pregs_to_save (is_inthandler
, false);
563 int ndregs_consec
= saveall
? 8 : n_dregs_to_save (is_inthandler
, true);
564 int npregs_consec
= saveall
? 6 : n_pregs_to_save (is_inthandler
, true);
566 int total_consec
= ndregs_consec
+ npregs_consec
;
569 if (saveall
|| is_inthandler
)
571 rtx insn
= emit_move_insn (predec
, gen_rtx_REG (SImode
, REG_ASTAT
));
573 RTX_FRAME_RELATED_P (insn
) = 1;
574 for (dregno
= REG_LT0
; dregno
<= REG_LB1
; dregno
++)
575 if (! current_function_is_leaf
576 || cfun
->machine
->has_hardware_loops
577 || cfun
->machine
->has_loopreg_clobber
578 || (ENABLE_WA_05000257
579 && (dregno
== REG_LC0
|| dregno
== REG_LC1
)))
581 insn
= emit_move_insn (predec
, gen_rtx_REG (SImode
, dregno
));
582 RTX_FRAME_RELATED_P (insn
) = 1;
586 if (total_consec
!= 0)
589 rtx val
= GEN_INT (-total_consec
* 4);
590 rtx pat
= gen_rtx_PARALLEL (VOIDmode
, rtvec_alloc (total_consec
+ 2));
592 XVECEXP (pat
, 0, 0) = gen_rtx_UNSPEC (VOIDmode
, gen_rtvec (1, val
),
593 UNSPEC_PUSH_MULTIPLE
);
594 XVECEXP (pat
, 0, total_consec
+ 1) = gen_rtx_SET (VOIDmode
, spreg
,
598 RTX_FRAME_RELATED_P (XVECEXP (pat
, 0, total_consec
+ 1)) = 1;
599 d_to_save
= ndregs_consec
;
600 dregno
= REG_R7
+ 1 - ndregs_consec
;
601 pregno
= REG_P5
+ 1 - npregs_consec
;
602 for (i
= 0; i
< total_consec
; i
++)
604 rtx memref
= gen_rtx_MEM (word_mode
,
605 gen_rtx_PLUS (Pmode
, spreg
,
606 GEN_INT (- i
* 4 - 4)));
610 subpat
= gen_rtx_SET (VOIDmode
, memref
, gen_rtx_REG (word_mode
,
616 subpat
= gen_rtx_SET (VOIDmode
, memref
, gen_rtx_REG (word_mode
,
619 XVECEXP (pat
, 0, i
+ 1) = subpat
;
620 RTX_FRAME_RELATED_P (subpat
) = 1;
622 insn
= emit_insn (pat
);
623 RTX_FRAME_RELATED_P (insn
) = 1;
626 for (dregno
= REG_R0
; ndregs
!= ndregs_consec
; dregno
++)
628 if (must_save_p (is_inthandler
, dregno
))
630 rtx insn
= emit_move_insn (predec
, gen_rtx_REG (word_mode
, dregno
));
631 RTX_FRAME_RELATED_P (insn
) = 1;
635 for (pregno
= REG_P0
; npregs
!= npregs_consec
; pregno
++)
637 if (must_save_p (is_inthandler
, pregno
))
639 rtx insn
= emit_move_insn (predec
, gen_rtx_REG (word_mode
, pregno
));
640 RTX_FRAME_RELATED_P (insn
) = 1;
644 for (i
= REG_P7
+ 1; i
< REG_CC
; i
++)
647 && (df_regs_ever_live_p (i
)
648 || (!leaf_function_p () && call_used_regs
[i
]))))
651 if (i
== REG_A0
|| i
== REG_A1
)
652 insn
= emit_move_insn (gen_rtx_MEM (PDImode
, predec1
),
653 gen_rtx_REG (PDImode
, i
));
655 insn
= emit_move_insn (predec
, gen_rtx_REG (SImode
, i
));
656 RTX_FRAME_RELATED_P (insn
) = 1;
660 /* Emit code to restore registers in the epilogue. SAVEALL is nonzero if we
661 must save all registers; this is used for interrupt handlers.
662 SPREG contains (reg:SI REG_SP). IS_INTHANDLER is true if we're doing
663 this for an interrupt (or exception) handler. */
666 expand_epilogue_reg_restore (rtx spreg
, bool saveall
, bool is_inthandler
)
668 rtx postinc1
= gen_rtx_POST_INC (SImode
, spreg
);
669 rtx postinc
= gen_rtx_MEM (SImode
, postinc1
);
671 int ndregs
= saveall
? 8 : n_dregs_to_save (is_inthandler
, false);
672 int npregs
= saveall
? 6 : n_pregs_to_save (is_inthandler
, false);
673 int ndregs_consec
= saveall
? 8 : n_dregs_to_save (is_inthandler
, true);
674 int npregs_consec
= saveall
? 6 : n_pregs_to_save (is_inthandler
, true);
675 int total_consec
= ndregs_consec
+ npregs_consec
;
679 /* A slightly crude technique to stop flow from trying to delete "dead"
681 MEM_VOLATILE_P (postinc
) = 1;
683 for (i
= REG_CC
- 1; i
> REG_P7
; i
--)
686 && (df_regs_ever_live_p (i
)
687 || (!leaf_function_p () && call_used_regs
[i
]))))
689 if (i
== REG_A0
|| i
== REG_A1
)
691 rtx mem
= gen_rtx_MEM (PDImode
, postinc1
);
692 MEM_VOLATILE_P (mem
) = 1;
693 emit_move_insn (gen_rtx_REG (PDImode
, i
), mem
);
696 emit_move_insn (gen_rtx_REG (SImode
, i
), postinc
);
699 regno
= REG_P5
- npregs_consec
;
700 for (; npregs
!= npregs_consec
; regno
--)
702 if (must_save_p (is_inthandler
, regno
))
704 emit_move_insn (gen_rtx_REG (word_mode
, regno
), postinc
);
708 regno
= REG_R7
- ndregs_consec
;
709 for (; ndregs
!= ndregs_consec
; regno
--)
711 if (must_save_p (is_inthandler
, regno
))
713 emit_move_insn (gen_rtx_REG (word_mode
, regno
), postinc
);
718 if (total_consec
!= 0)
720 rtx pat
= gen_rtx_PARALLEL (VOIDmode
, rtvec_alloc (total_consec
+ 1));
722 = gen_rtx_SET (VOIDmode
, spreg
,
723 gen_rtx_PLUS (Pmode
, spreg
,
724 GEN_INT (total_consec
* 4)));
726 if (npregs_consec
> 0)
731 for (i
= 0; i
< total_consec
; i
++)
734 ? gen_rtx_PLUS (Pmode
, spreg
, GEN_INT (i
* 4))
736 rtx memref
= gen_rtx_MEM (word_mode
, addr
);
739 XVECEXP (pat
, 0, i
+ 1)
740 = gen_rtx_SET (VOIDmode
, gen_rtx_REG (word_mode
, regno
), memref
);
742 if (npregs_consec
> 0)
744 if (--npregs_consec
== 0)
749 insn
= emit_insn (pat
);
750 RTX_FRAME_RELATED_P (insn
) = 1;
752 if (saveall
|| is_inthandler
)
754 for (regno
= REG_LB1
; regno
>= REG_LT0
; regno
--)
755 if (! current_function_is_leaf
756 || cfun
->machine
->has_hardware_loops
757 || cfun
->machine
->has_loopreg_clobber
758 || (ENABLE_WA_05000257
&& (regno
== REG_LC0
|| regno
== REG_LC1
)))
759 emit_move_insn (gen_rtx_REG (SImode
, regno
), postinc
);
761 emit_move_insn (gen_rtx_REG (SImode
, REG_ASTAT
), postinc
);
765 /* Perform any needed actions needed for a function that is receiving a
766 variable number of arguments.
770 MODE and TYPE are the mode and type of the current parameter.
772 PRETEND_SIZE is a variable that should be set to the amount of stack
773 that must be pushed by the prolog to pretend that our caller pushed
776 Normally, this macro will push all remaining incoming registers on the
777 stack and set PRETEND_SIZE to the length of the registers pushed.
780 - VDSP C compiler manual (our ABI) says that a variable args function
781 should save the R0, R1 and R2 registers in the stack.
782 - The caller will always leave space on the stack for the
783 arguments that are passed in registers, so we dont have
784 to leave any extra space.
785 - now, the vastart pointer can access all arguments from the stack. */
788 setup_incoming_varargs (CUMULATIVE_ARGS
*cum
,
789 enum machine_mode mode ATTRIBUTE_UNUSED
,
790 tree type ATTRIBUTE_UNUSED
, int *pretend_size
,
799 /* The move for named arguments will be generated automatically by the
800 compiler. We need to generate the move rtx for the unnamed arguments
801 if they are in the first 3 words. We assume at least 1 named argument
802 exists, so we never generate [ARGP] = R0 here. */
804 for (i
= cum
->words
+ 1; i
< max_arg_registers
; i
++)
806 mem
= gen_rtx_MEM (Pmode
,
807 plus_constant (arg_pointer_rtx
, (i
* UNITS_PER_WORD
)));
808 emit_move_insn (mem
, gen_rtx_REG (Pmode
, i
));
814 /* Value should be nonzero if functions must have frame pointers.
815 Zero means the frame pointer need not be set up (and parms may
816 be accessed via the stack pointer) in functions that seem suitable. */
819 bfin_frame_pointer_required (void)
821 e_funkind fkind
= funkind (TREE_TYPE (current_function_decl
));
823 if (fkind
!= SUBROUTINE
)
826 /* We turn on -fomit-frame-pointer if -momit-leaf-frame-pointer is used,
827 so we have to override it for non-leaf functions. */
828 if (TARGET_OMIT_LEAF_FRAME_POINTER
&& ! current_function_is_leaf
)
834 /* Return the number of registers pushed during the prologue. */
837 n_regs_saved_by_prologue (void)
839 e_funkind fkind
= funkind (TREE_TYPE (current_function_decl
));
840 bool is_inthandler
= fkind
!= SUBROUTINE
;
841 tree attrs
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
842 bool all
= (lookup_attribute ("saveall", attrs
) != NULL_TREE
843 || (is_inthandler
&& !current_function_is_leaf
));
844 int ndregs
= all
? 8 : n_dregs_to_save (is_inthandler
, false);
845 int npregs
= all
? 6 : n_pregs_to_save (is_inthandler
, false);
846 int n
= ndregs
+ npregs
;
849 if (all
|| stack_frame_needed_p ())
850 /* We use a LINK instruction in this case. */
854 if (must_save_fp_p ())
856 if (! current_function_is_leaf
)
860 if (fkind
!= SUBROUTINE
|| all
)
862 /* Increment once for ASTAT. */
864 if (! current_function_is_leaf
865 || cfun
->machine
->has_hardware_loops
866 || cfun
->machine
->has_loopreg_clobber
)
872 if (fkind
!= SUBROUTINE
)
875 if (lookup_attribute ("nesting", attrs
))
879 for (i
= REG_P7
+ 1; i
< REG_CC
; i
++)
881 || (fkind
!= SUBROUTINE
882 && (df_regs_ever_live_p (i
)
883 || (!leaf_function_p () && call_used_regs
[i
]))))
884 n
+= i
== REG_A0
|| i
== REG_A1
? 2 : 1;
889 /* Return the offset between two registers, one to be eliminated, and the other
890 its replacement, at the start of a routine. */
893 bfin_initial_elimination_offset (int from
, int to
)
895 HOST_WIDE_INT offset
= 0;
897 if (from
== ARG_POINTER_REGNUM
)
898 offset
= n_regs_saved_by_prologue () * 4;
900 if (to
== STACK_POINTER_REGNUM
)
902 if (crtl
->outgoing_args_size
>= FIXED_STACK_AREA
)
903 offset
+= crtl
->outgoing_args_size
;
904 else if (crtl
->outgoing_args_size
)
905 offset
+= FIXED_STACK_AREA
;
907 offset
+= get_frame_size ();
913 /* Emit code to load a constant CONSTANT into register REG; setting
914 RTX_FRAME_RELATED_P on all insns we generate if RELATED is true.
915 Make sure that the insns we generate need not be split. */
918 frame_related_constant_load (rtx reg
, HOST_WIDE_INT constant
, bool related
)
921 rtx cst
= GEN_INT (constant
);
923 if (constant
>= -32768 && constant
< 65536)
924 insn
= emit_move_insn (reg
, cst
);
927 /* We don't call split_load_immediate here, since dwarf2out.c can get
928 confused about some of the more clever sequences it can generate. */
929 insn
= emit_insn (gen_movsi_high (reg
, cst
));
931 RTX_FRAME_RELATED_P (insn
) = 1;
932 insn
= emit_insn (gen_movsi_low (reg
, reg
, cst
));
935 RTX_FRAME_RELATED_P (insn
) = 1;
938 /* Generate efficient code to add a value to a P register.
939 Set RTX_FRAME_RELATED_P on the generated insns if FRAME is nonzero.
940 EPILOGUE_P is zero if this function is called for prologue,
941 otherwise it's nonzero. And it's less than zero if this is for
945 add_to_reg (rtx reg
, HOST_WIDE_INT value
, int frame
, int epilogue_p
)
950 /* Choose whether to use a sequence using a temporary register, or
951 a sequence with multiple adds. We can add a signed 7-bit value
952 in one instruction. */
953 if (value
> 120 || value
< -120)
961 /* For prologue or normal epilogue, P1 can be safely used
962 as the temporary register. For sibcall epilogue, we try to find
963 a call used P register, which will be restored in epilogue.
964 If we cannot find such a P register, we have to use one I register
968 tmpreg
= gen_rtx_REG (SImode
, REG_P1
);
972 for (i
= REG_P0
; i
<= REG_P5
; i
++)
973 if ((df_regs_ever_live_p (i
) && ! call_used_regs
[i
])
975 && i
== PIC_OFFSET_TABLE_REGNUM
976 && (crtl
->uses_pic_offset_table
977 || (TARGET_ID_SHARED_LIBRARY
978 && ! current_function_is_leaf
))))
981 tmpreg
= gen_rtx_REG (SImode
, i
);
984 tmpreg
= gen_rtx_REG (SImode
, REG_P1
);
985 tmpreg2
= gen_rtx_REG (SImode
, REG_I0
);
986 emit_move_insn (tmpreg2
, tmpreg
);
991 frame_related_constant_load (tmpreg
, value
, TRUE
);
993 insn
= emit_move_insn (tmpreg
, GEN_INT (value
));
995 insn
= emit_insn (gen_addsi3 (reg
, reg
, tmpreg
));
997 RTX_FRAME_RELATED_P (insn
) = 1;
999 if (tmpreg2
!= NULL_RTX
)
1000 emit_move_insn (tmpreg
, tmpreg2
);
1010 else if (size
< -60)
1011 /* We could use -62, but that would leave the stack unaligned, so
1015 insn
= emit_insn (gen_addsi3 (reg
, reg
, GEN_INT (size
)));
1017 RTX_FRAME_RELATED_P (insn
) = 1;
1023 /* Generate a LINK insn for a frame sized FRAME_SIZE. If this constant
1024 is too large, generate a sequence of insns that has the same effect.
1025 SPREG contains (reg:SI REG_SP). */
1028 emit_link_insn (rtx spreg
, HOST_WIDE_INT frame_size
)
1030 HOST_WIDE_INT link_size
= frame_size
;
1034 if (link_size
> 262140)
1037 /* Use a LINK insn with as big a constant as possible, then subtract
1038 any remaining size from the SP. */
1039 insn
= emit_insn (gen_link (GEN_INT (-8 - link_size
)));
1040 RTX_FRAME_RELATED_P (insn
) = 1;
1042 for (i
= 0; i
< XVECLEN (PATTERN (insn
), 0); i
++)
1044 rtx set
= XVECEXP (PATTERN (insn
), 0, i
);
1045 gcc_assert (GET_CODE (set
) == SET
);
1046 RTX_FRAME_RELATED_P (set
) = 1;
1049 frame_size
-= link_size
;
1053 /* Must use a call-clobbered PREG that isn't the static chain. */
1054 rtx tmpreg
= gen_rtx_REG (Pmode
, REG_P1
);
1056 frame_related_constant_load (tmpreg
, -frame_size
, TRUE
);
1057 insn
= emit_insn (gen_addsi3 (spreg
, spreg
, tmpreg
));
1058 RTX_FRAME_RELATED_P (insn
) = 1;
1062 /* Return the number of bytes we must reserve for outgoing arguments
1063 in the current function's stack frame. */
1065 static HOST_WIDE_INT
1066 arg_area_size (void)
1068 if (crtl
->outgoing_args_size
)
1070 if (crtl
->outgoing_args_size
>= FIXED_STACK_AREA
)
1071 return crtl
->outgoing_args_size
;
1073 return FIXED_STACK_AREA
;
1078 /* Save RETS and FP, and allocate a stack frame. ALL is true if the
1079 function must save all its registers (true only for certain interrupt
1083 do_link (rtx spreg
, HOST_WIDE_INT frame_size
, bool all
)
1085 frame_size
+= arg_area_size ();
1087 if (all
|| stack_frame_needed_p ()
1088 || (must_save_fp_p () && ! current_function_is_leaf
))
1089 emit_link_insn (spreg
, frame_size
);
1092 if (! current_function_is_leaf
)
1094 rtx pat
= gen_movsi (gen_rtx_MEM (Pmode
,
1095 gen_rtx_PRE_DEC (Pmode
, spreg
)),
1097 rtx insn
= emit_insn (pat
);
1098 RTX_FRAME_RELATED_P (insn
) = 1;
1100 if (must_save_fp_p ())
1102 rtx pat
= gen_movsi (gen_rtx_MEM (Pmode
,
1103 gen_rtx_PRE_DEC (Pmode
, spreg
)),
1104 gen_rtx_REG (Pmode
, REG_FP
));
1105 rtx insn
= emit_insn (pat
);
1106 RTX_FRAME_RELATED_P (insn
) = 1;
1108 add_to_reg (spreg
, -frame_size
, 1, 0);
1112 /* Like do_link, but used for epilogues to deallocate the stack frame.
1113 EPILOGUE_P is zero if this function is called for prologue,
1114 otherwise it's nonzero. And it's less than zero if this is for
1115 sibcall epilogue. */
1118 do_unlink (rtx spreg
, HOST_WIDE_INT frame_size
, bool all
, int epilogue_p
)
1120 frame_size
+= arg_area_size ();
1122 if (all
|| stack_frame_needed_p ())
1123 emit_insn (gen_unlink ());
1126 rtx postinc
= gen_rtx_MEM (Pmode
, gen_rtx_POST_INC (Pmode
, spreg
));
1128 add_to_reg (spreg
, frame_size
, 0, epilogue_p
);
1129 if (must_save_fp_p ())
1131 rtx fpreg
= gen_rtx_REG (Pmode
, REG_FP
);
1132 emit_move_insn (fpreg
, postinc
);
1135 if (! current_function_is_leaf
)
1137 emit_move_insn (bfin_rets_rtx
, postinc
);
1138 emit_use (bfin_rets_rtx
);
1143 /* Generate a prologue suitable for a function of kind FKIND. This is
1144 called for interrupt and exception handler prologues.
1145 SPREG contains (reg:SI REG_SP). */
1148 expand_interrupt_handler_prologue (rtx spreg
, e_funkind fkind
, bool all
)
1150 HOST_WIDE_INT frame_size
= get_frame_size ();
1151 rtx predec1
= gen_rtx_PRE_DEC (SImode
, spreg
);
1152 rtx predec
= gen_rtx_MEM (SImode
, predec1
);
1154 tree attrs
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
1155 tree kspisusp
= lookup_attribute ("kspisusp", attrs
);
1159 insn
= emit_move_insn (spreg
, gen_rtx_REG (Pmode
, REG_USP
));
1160 RTX_FRAME_RELATED_P (insn
) = 1;
1163 /* We need space on the stack in case we need to save the argument
1165 if (fkind
== EXCPT_HANDLER
)
1167 insn
= emit_insn (gen_addsi3 (spreg
, spreg
, GEN_INT (-12)));
1168 RTX_FRAME_RELATED_P (insn
) = 1;
1171 /* If we're calling other functions, they won't save their call-clobbered
1172 registers, so we must save everything here. */
1173 if (!current_function_is_leaf
)
1175 expand_prologue_reg_save (spreg
, all
, true);
1177 if (ENABLE_WA_05000283
|| ENABLE_WA_05000315
)
1179 rtx chipid
= GEN_INT (trunc_int_for_mode (0xFFC00014, SImode
));
1180 rtx p5reg
= gen_rtx_REG (Pmode
, REG_P5
);
1181 emit_insn (gen_movbi (bfin_cc_rtx
, const1_rtx
));
1182 emit_insn (gen_movsi_high (p5reg
, chipid
));
1183 emit_insn (gen_movsi_low (p5reg
, p5reg
, chipid
));
1184 emit_insn (gen_dummy_load (p5reg
, bfin_cc_rtx
));
1187 if (lookup_attribute ("nesting", attrs
))
1189 rtx srcreg
= gen_rtx_REG (Pmode
, (fkind
== EXCPT_HANDLER
? REG_RETX
1190 : fkind
== NMI_HANDLER
? REG_RETN
1192 insn
= emit_move_insn (predec
, srcreg
);
1193 RTX_FRAME_RELATED_P (insn
) = 1;
1196 do_link (spreg
, frame_size
, all
);
1198 if (fkind
== EXCPT_HANDLER
)
1200 rtx r0reg
= gen_rtx_REG (SImode
, REG_R0
);
1201 rtx r1reg
= gen_rtx_REG (SImode
, REG_R1
);
1202 rtx r2reg
= gen_rtx_REG (SImode
, REG_R2
);
1205 insn
= emit_move_insn (r0reg
, gen_rtx_REG (SImode
, REG_SEQSTAT
));
1206 insn
= emit_insn (gen_ashrsi3 (r0reg
, r0reg
, GEN_INT (26)));
1207 insn
= emit_insn (gen_ashlsi3 (r0reg
, r0reg
, GEN_INT (26)));
1208 insn
= emit_move_insn (r1reg
, spreg
);
1209 insn
= emit_move_insn (r2reg
, gen_rtx_REG (Pmode
, REG_FP
));
1210 insn
= emit_insn (gen_addsi3 (r2reg
, r2reg
, GEN_INT (8)));
1214 /* Generate an epilogue suitable for a function of kind FKIND. This is
1215 called for interrupt and exception handler epilogues.
1216 SPREG contains (reg:SI REG_SP). */
1219 expand_interrupt_handler_epilogue (rtx spreg
, e_funkind fkind
, bool all
)
1221 tree attrs
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
1222 rtx postinc1
= gen_rtx_POST_INC (SImode
, spreg
);
1223 rtx postinc
= gen_rtx_MEM (SImode
, postinc1
);
1225 /* A slightly crude technique to stop flow from trying to delete "dead"
1227 MEM_VOLATILE_P (postinc
) = 1;
1229 do_unlink (spreg
, get_frame_size (), all
, 1);
1231 if (lookup_attribute ("nesting", attrs
))
1233 rtx srcreg
= gen_rtx_REG (Pmode
, (fkind
== EXCPT_HANDLER
? REG_RETX
1234 : fkind
== NMI_HANDLER
? REG_RETN
1236 emit_move_insn (srcreg
, postinc
);
1239 /* If we're calling other functions, they won't save their call-clobbered
1240 registers, so we must save (and restore) everything here. */
1241 if (!current_function_is_leaf
)
1244 expand_epilogue_reg_restore (spreg
, all
, true);
1246 /* Deallocate any space we left on the stack in case we needed to save the
1247 argument registers. */
1248 if (fkind
== EXCPT_HANDLER
)
1249 emit_insn (gen_addsi3 (spreg
, spreg
, GEN_INT (12)));
1251 emit_jump_insn (gen_return_internal (GEN_INT (fkind
)));
1254 /* Used while emitting the prologue to generate code to load the correct value
1255 into the PIC register, which is passed in DEST. */
1258 bfin_load_pic_reg (rtx dest
)
1260 struct cgraph_local_info
*i
= NULL
;
1263 i
= cgraph_local_info (current_function_decl
);
1265 /* Functions local to the translation unit don't need to reload the
1266 pic reg, since the caller always passes a usable one. */
1268 return pic_offset_table_rtx
;
1270 if (bfin_lib_id_given
)
1271 addr
= plus_constant (pic_offset_table_rtx
, -4 - bfin_library_id
* 4);
1273 addr
= gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
,
1274 gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, const0_rtx
),
1275 UNSPEC_LIBRARY_OFFSET
));
1276 insn
= emit_insn (gen_movsi (dest
, gen_rtx_MEM (Pmode
, addr
)));
1280 /* Generate RTL for the prologue of the current function. */
1283 bfin_expand_prologue (void)
1285 HOST_WIDE_INT frame_size
= get_frame_size ();
1286 rtx spreg
= gen_rtx_REG (Pmode
, REG_SP
);
1287 e_funkind fkind
= funkind (TREE_TYPE (current_function_decl
));
1288 rtx pic_reg_loaded
= NULL_RTX
;
1289 tree attrs
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
1290 bool all
= lookup_attribute ("saveall", attrs
) != NULL_TREE
;
1292 if (fkind
!= SUBROUTINE
)
1294 expand_interrupt_handler_prologue (spreg
, fkind
, all
);
1298 if (crtl
->limit_stack
1299 || (TARGET_STACK_CHECK_L1
1300 && !DECL_NO_LIMIT_STACK (current_function_decl
)))
1302 HOST_WIDE_INT offset
1303 = bfin_initial_elimination_offset (ARG_POINTER_REGNUM
,
1304 STACK_POINTER_REGNUM
);
1305 rtx lim
= crtl
->limit_stack
? stack_limit_rtx
: NULL_RTX
;
1306 rtx p2reg
= gen_rtx_REG (Pmode
, REG_P2
);
1310 emit_move_insn (p2reg
, gen_int_mode (0xFFB00000, SImode
));
1311 emit_move_insn (p2reg
, gen_rtx_MEM (Pmode
, p2reg
));
1314 if (GET_CODE (lim
) == SYMBOL_REF
)
1316 if (TARGET_ID_SHARED_LIBRARY
)
1318 rtx p1reg
= gen_rtx_REG (Pmode
, REG_P1
);
1320 pic_reg_loaded
= bfin_load_pic_reg (p2reg
);
1321 val
= legitimize_pic_address (stack_limit_rtx
, p1reg
,
1323 emit_move_insn (p1reg
, val
);
1324 frame_related_constant_load (p2reg
, offset
, FALSE
);
1325 emit_insn (gen_addsi3 (p2reg
, p2reg
, p1reg
));
1330 rtx limit
= plus_constant (lim
, offset
);
1331 emit_move_insn (p2reg
, limit
);
1338 emit_move_insn (p2reg
, lim
);
1339 add_to_reg (p2reg
, offset
, 0, 0);
1342 emit_insn (gen_compare_lt (bfin_cc_rtx
, spreg
, lim
));
1343 emit_insn (gen_trapifcc ());
1345 expand_prologue_reg_save (spreg
, all
, false);
1347 do_link (spreg
, frame_size
, false);
1349 if (TARGET_ID_SHARED_LIBRARY
1351 && (crtl
->uses_pic_offset_table
1352 || !current_function_is_leaf
))
1353 bfin_load_pic_reg (pic_offset_table_rtx
);
1356 /* Generate RTL for the epilogue of the current function. NEED_RETURN is zero
1357 if this is for a sibcall. EH_RETURN is nonzero if we're expanding an
1358 eh_return pattern. SIBCALL_P is true if this is a sibcall epilogue,
1362 bfin_expand_epilogue (int need_return
, int eh_return
, bool sibcall_p
)
1364 rtx spreg
= gen_rtx_REG (Pmode
, REG_SP
);
1365 e_funkind fkind
= funkind (TREE_TYPE (current_function_decl
));
1366 int e
= sibcall_p
? -1 : 1;
1367 tree attrs
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
1368 bool all
= lookup_attribute ("saveall", attrs
) != NULL_TREE
;
1370 if (fkind
!= SUBROUTINE
)
1372 expand_interrupt_handler_epilogue (spreg
, fkind
, all
);
1376 do_unlink (spreg
, get_frame_size (), false, e
);
1378 expand_epilogue_reg_restore (spreg
, all
, false);
1380 /* Omit the return insn if this is for a sibcall. */
1385 emit_insn (gen_addsi3 (spreg
, spreg
, gen_rtx_REG (Pmode
, REG_P2
)));
1387 emit_jump_insn (gen_return_internal (GEN_INT (SUBROUTINE
)));
1390 /* Return nonzero if register OLD_REG can be renamed to register NEW_REG. */
1393 bfin_hard_regno_rename_ok (unsigned int old_reg ATTRIBUTE_UNUSED
,
1394 unsigned int new_reg
)
1396 /* Interrupt functions can only use registers that have already been
1397 saved by the prologue, even if they would normally be
1400 if (funkind (TREE_TYPE (current_function_decl
)) != SUBROUTINE
1401 && !df_regs_ever_live_p (new_reg
))
1407 /* Return the value of the return address for the frame COUNT steps up
1408 from the current frame, after the prologue.
1409 We punt for everything but the current frame by returning const0_rtx. */
1412 bfin_return_addr_rtx (int count
)
1417 return get_hard_reg_initial_val (Pmode
, REG_RETS
);
1420 /* Try machine-dependent ways of modifying an illegitimate address X
1421 to be legitimate. If we find one, return the new, valid address,
1422 otherwise return NULL_RTX.
1424 OLDX is the address as it was before break_out_memory_refs was called.
1425 In some cases it is useful to look at this to decide what needs to be done.
1427 MODE is the mode of the memory reference. */
1430 legitimize_address (rtx x ATTRIBUTE_UNUSED
, rtx oldx ATTRIBUTE_UNUSED
,
1431 enum machine_mode mode ATTRIBUTE_UNUSED
)
1437 bfin_delegitimize_address (rtx orig_x
)
1441 if (GET_CODE (x
) != MEM
)
1445 if (GET_CODE (x
) == PLUS
1446 && GET_CODE (XEXP (x
, 1)) == UNSPEC
1447 && XINT (XEXP (x
, 1), 1) == UNSPEC_MOVE_PIC
1448 && GET_CODE (XEXP (x
, 0)) == REG
1449 && REGNO (XEXP (x
, 0)) == PIC_OFFSET_TABLE_REGNUM
)
1450 return XVECEXP (XEXP (x
, 1), 0, 0);
1455 /* This predicate is used to compute the length of a load/store insn.
1456 OP is a MEM rtx, we return nonzero if its addressing mode requires a
1457 32-bit instruction. */
1460 effective_address_32bit_p (rtx op
, enum machine_mode mode
)
1462 HOST_WIDE_INT offset
;
1464 mode
= GET_MODE (op
);
1467 if (GET_CODE (op
) != PLUS
)
1469 gcc_assert (REG_P (op
) || GET_CODE (op
) == POST_INC
1470 || GET_CODE (op
) == PRE_DEC
|| GET_CODE (op
) == POST_DEC
);
1474 if (GET_CODE (XEXP (op
, 1)) == UNSPEC
)
1477 offset
= INTVAL (XEXP (op
, 1));
1479 /* All byte loads use a 16-bit offset. */
1480 if (GET_MODE_SIZE (mode
) == 1)
1483 if (GET_MODE_SIZE (mode
) == 4)
1485 /* Frame pointer relative loads can use a negative offset, all others
1486 are restricted to a small positive one. */
1487 if (XEXP (op
, 0) == frame_pointer_rtx
)
1488 return offset
< -128 || offset
> 60;
1489 return offset
< 0 || offset
> 60;
1492 /* Must be HImode now. */
1493 return offset
< 0 || offset
> 30;
1496 /* Returns true if X is a memory reference using an I register. */
1498 bfin_dsp_memref_p (rtx x
)
1503 if (GET_CODE (x
) == POST_INC
|| GET_CODE (x
) == PRE_INC
1504 || GET_CODE (x
) == POST_DEC
|| GET_CODE (x
) == PRE_DEC
)
1509 /* Return cost of the memory address ADDR.
1510 All addressing modes are equally cheap on the Blackfin. */
1513 bfin_address_cost (rtx addr ATTRIBUTE_UNUSED
, bool speed ATTRIBUTE_UNUSED
)
1518 /* Subroutine of print_operand; used to print a memory reference X to FILE. */
1521 print_address_operand (FILE *file
, rtx x
)
1523 switch (GET_CODE (x
))
1526 output_address (XEXP (x
, 0));
1527 fprintf (file
, "+");
1528 output_address (XEXP (x
, 1));
1532 fprintf (file
, "--");
1533 output_address (XEXP (x
, 0));
1536 output_address (XEXP (x
, 0));
1537 fprintf (file
, "++");
1540 output_address (XEXP (x
, 0));
1541 fprintf (file
, "--");
1545 gcc_assert (GET_CODE (x
) != MEM
);
1546 print_operand (file
, x
, 0);
1551 /* Adding intp DImode support by Tony
1557 print_operand (FILE *file
, rtx x
, char code
)
1559 enum machine_mode mode
;
1563 if (GET_MODE (current_output_insn
) == SImode
)
1564 fprintf (file
, " ||");
1566 fprintf (file
, ";");
1570 mode
= GET_MODE (x
);
1575 switch (GET_CODE (x
))
1578 fprintf (file
, "e");
1581 fprintf (file
, "ne");
1584 fprintf (file
, "g");
1587 fprintf (file
, "l");
1590 fprintf (file
, "ge");
1593 fprintf (file
, "le");
1596 fprintf (file
, "g");
1599 fprintf (file
, "l");
1602 fprintf (file
, "ge");
1605 fprintf (file
, "le");
1608 output_operand_lossage ("invalid %%j value");
1612 case 'J': /* reverse logic */
1613 switch (GET_CODE(x
))
1616 fprintf (file
, "ne");
1619 fprintf (file
, "e");
1622 fprintf (file
, "le");
1625 fprintf (file
, "ge");
1628 fprintf (file
, "l");
1631 fprintf (file
, "g");
1634 fprintf (file
, "le");
1637 fprintf (file
, "ge");
1640 fprintf (file
, "l");
1643 fprintf (file
, "g");
1646 output_operand_lossage ("invalid %%J value");
1651 switch (GET_CODE (x
))
1657 fprintf (file
, "%s", short_reg_names
[REGNO (x
)]);
1659 output_operand_lossage ("invalid operand for code '%c'", code
);
1661 else if (code
== 'd')
1664 fprintf (file
, "%s", high_reg_names
[REGNO (x
)]);
1666 output_operand_lossage ("invalid operand for code '%c'", code
);
1668 else if (code
== 'w')
1670 if (REGNO (x
) == REG_A0
|| REGNO (x
) == REG_A1
)
1671 fprintf (file
, "%s.w", reg_names
[REGNO (x
)]);
1673 output_operand_lossage ("invalid operand for code '%c'", code
);
1675 else if (code
== 'x')
1677 if (REGNO (x
) == REG_A0
|| REGNO (x
) == REG_A1
)
1678 fprintf (file
, "%s.x", reg_names
[REGNO (x
)]);
1680 output_operand_lossage ("invalid operand for code '%c'", code
);
1682 else if (code
== 'v')
1684 if (REGNO (x
) == REG_A0
)
1685 fprintf (file
, "AV0");
1686 else if (REGNO (x
) == REG_A1
)
1687 fprintf (file
, "AV1");
1689 output_operand_lossage ("invalid operand for code '%c'", code
);
1691 else if (code
== 'D')
1693 if (D_REGNO_P (REGNO (x
)))
1694 fprintf (file
, "%s", dregs_pair_names
[REGNO (x
)]);
1696 output_operand_lossage ("invalid operand for code '%c'", code
);
1698 else if (code
== 'H')
1700 if ((mode
== DImode
|| mode
== DFmode
) && REG_P (x
))
1701 fprintf (file
, "%s", reg_names
[REGNO (x
) + 1]);
1703 output_operand_lossage ("invalid operand for code '%c'", code
);
1705 else if (code
== 'T')
1707 if (D_REGNO_P (REGNO (x
)))
1708 fprintf (file
, "%s", byte_reg_names
[REGNO (x
)]);
1710 output_operand_lossage ("invalid operand for code '%c'", code
);
1713 fprintf (file
, "%s", reg_names
[REGNO (x
)]);
1719 print_address_operand (file
, x
);
1731 fputs ("(FU)", file
);
1734 fputs ("(T)", file
);
1737 fputs ("(TFU)", file
);
1740 fputs ("(W32)", file
);
1743 fputs ("(IS)", file
);
1746 fputs ("(IU)", file
);
1749 fputs ("(IH)", file
);
1752 fputs ("(M)", file
);
1755 fputs ("(IS,M)", file
);
1758 fputs ("(ISS2)", file
);
1761 fputs ("(S2RND)", file
);
1768 else if (code
== 'b')
1770 if (INTVAL (x
) == 0)
1772 else if (INTVAL (x
) == 1)
1778 /* Moves to half registers with d or h modifiers always use unsigned
1780 else if (code
== 'd')
1781 x
= GEN_INT ((INTVAL (x
) >> 16) & 0xffff);
1782 else if (code
== 'h')
1783 x
= GEN_INT (INTVAL (x
) & 0xffff);
1784 else if (code
== 'N')
1785 x
= GEN_INT (-INTVAL (x
));
1786 else if (code
== 'X')
1787 x
= GEN_INT (exact_log2 (0xffffffff & INTVAL (x
)));
1788 else if (code
== 'Y')
1789 x
= GEN_INT (exact_log2 (0xffffffff & ~INTVAL (x
)));
1790 else if (code
== 'Z')
1791 /* Used for LINK insns. */
1792 x
= GEN_INT (-8 - INTVAL (x
));
1797 output_addr_const (file
, x
);
1801 output_operand_lossage ("invalid const_double operand");
1805 switch (XINT (x
, 1))
1807 case UNSPEC_MOVE_PIC
:
1808 output_addr_const (file
, XVECEXP (x
, 0, 0));
1809 fprintf (file
, "@GOT");
1812 case UNSPEC_MOVE_FDPIC
:
1813 output_addr_const (file
, XVECEXP (x
, 0, 0));
1814 fprintf (file
, "@GOT17M4");
1817 case UNSPEC_FUNCDESC_GOT17M4
:
1818 output_addr_const (file
, XVECEXP (x
, 0, 0));
1819 fprintf (file
, "@FUNCDESC_GOT17M4");
1822 case UNSPEC_LIBRARY_OFFSET
:
1823 fprintf (file
, "_current_shared_library_p5_offset_");
1832 output_addr_const (file
, x
);
1837 /* Argument support functions. */
1839 /* Initialize a variable CUM of type CUMULATIVE_ARGS
1840 for a call to a function whose data type is FNTYPE.
1841 For a library call, FNTYPE is 0.
1842 VDSP C Compiler manual, our ABI says that
1843 first 3 words of arguments will use R0, R1 and R2.
1847 init_cumulative_args (CUMULATIVE_ARGS
*cum
, tree fntype
,
1848 rtx libname ATTRIBUTE_UNUSED
)
1850 static CUMULATIVE_ARGS zero_cum
;
1854 /* Set up the number of registers to use for passing arguments. */
1856 cum
->nregs
= max_arg_registers
;
1857 cum
->arg_regs
= arg_regs
;
1859 cum
->call_cookie
= CALL_NORMAL
;
1860 /* Check for a longcall attribute. */
1861 if (fntype
&& lookup_attribute ("shortcall", TYPE_ATTRIBUTES (fntype
)))
1862 cum
->call_cookie
|= CALL_SHORT
;
1863 else if (fntype
&& lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype
)))
1864 cum
->call_cookie
|= CALL_LONG
;
1869 /* Update the data in CUM to advance over an argument
1870 of mode MODE and data type TYPE.
1871 (TYPE is null for libcalls where that information may not be available.) */
1874 function_arg_advance (CUMULATIVE_ARGS
*cum
, enum machine_mode mode
, tree type
,
1875 int named ATTRIBUTE_UNUSED
)
1877 int count
, bytes
, words
;
1879 bytes
= (mode
== BLKmode
) ? int_size_in_bytes (type
) : GET_MODE_SIZE (mode
);
1880 words
= (bytes
+ UNITS_PER_WORD
- 1) / UNITS_PER_WORD
;
1882 cum
->words
+= words
;
1883 cum
->nregs
-= words
;
1885 if (cum
->nregs
<= 0)
1888 cum
->arg_regs
= NULL
;
1892 for (count
= 1; count
<= words
; count
++)
1899 /* Define where to put the arguments to a function.
1900 Value is zero to push the argument on the stack,
1901 or a hard register in which to store the argument.
1903 MODE is the argument's machine mode.
1904 TYPE is the data type of the argument (as a tree).
1905 This is null for libcalls where that information may
1907 CUM is a variable of type CUMULATIVE_ARGS which gives info about
1908 the preceding args and about the function being called.
1909 NAMED is nonzero if this argument is a named parameter
1910 (otherwise it is an extra parameter matching an ellipsis). */
1913 function_arg (CUMULATIVE_ARGS
*cum
, enum machine_mode mode
, tree type
,
1914 int named ATTRIBUTE_UNUSED
)
1917 = (mode
== BLKmode
) ? int_size_in_bytes (type
) : GET_MODE_SIZE (mode
);
1919 if (mode
== VOIDmode
)
1920 /* Compute operand 2 of the call insn. */
1921 return GEN_INT (cum
->call_cookie
);
1927 return gen_rtx_REG (mode
, *(cum
->arg_regs
));
1932 /* For an arg passed partly in registers and partly in memory,
1933 this is the number of bytes passed in registers.
1934 For args passed entirely in registers or entirely in memory, zero.
1936 Refer VDSP C Compiler manual, our ABI.
1937 First 3 words are in registers. So, if an argument is larger
1938 than the registers available, it will span the register and
1942 bfin_arg_partial_bytes (CUMULATIVE_ARGS
*cum
, enum machine_mode mode
,
1943 tree type ATTRIBUTE_UNUSED
,
1944 bool named ATTRIBUTE_UNUSED
)
1947 = (mode
== BLKmode
) ? int_size_in_bytes (type
) : GET_MODE_SIZE (mode
);
1948 int bytes_left
= cum
->nregs
* UNITS_PER_WORD
;
1953 if (bytes_left
== 0)
1955 if (bytes
> bytes_left
)
1960 /* Variable sized types are passed by reference. */
1963 bfin_pass_by_reference (CUMULATIVE_ARGS
*cum ATTRIBUTE_UNUSED
,
1964 enum machine_mode mode ATTRIBUTE_UNUSED
,
1965 const_tree type
, bool named ATTRIBUTE_UNUSED
)
1967 return type
&& TREE_CODE (TYPE_SIZE (type
)) != INTEGER_CST
;
1970 /* Decide whether a type should be returned in memory (true)
1971 or in a register (false). This is called by the macro
1972 TARGET_RETURN_IN_MEMORY. */
1975 bfin_return_in_memory (const_tree type
, const_tree fntype ATTRIBUTE_UNUSED
)
1977 int size
= int_size_in_bytes (type
);
1978 return size
> 2 * UNITS_PER_WORD
|| size
== -1;
1981 /* Register in which address to store a structure value
1982 is passed to a function. */
1984 bfin_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED
,
1985 int incoming ATTRIBUTE_UNUSED
)
1987 return gen_rtx_REG (Pmode
, REG_P0
);
1990 /* Return true when register may be used to pass function parameters. */
1993 function_arg_regno_p (int n
)
1996 for (i
= 0; arg_regs
[i
] != -1; i
++)
1997 if (n
== arg_regs
[i
])
2002 /* Returns 1 if OP contains a symbol reference */
2005 symbolic_reference_mentioned_p (rtx op
)
2007 register const char *fmt
;
2010 if (GET_CODE (op
) == SYMBOL_REF
|| GET_CODE (op
) == LABEL_REF
)
2013 fmt
= GET_RTX_FORMAT (GET_CODE (op
));
2014 for (i
= GET_RTX_LENGTH (GET_CODE (op
)) - 1; i
>= 0; i
--)
2020 for (j
= XVECLEN (op
, i
) - 1; j
>= 0; j
--)
2021 if (symbolic_reference_mentioned_p (XVECEXP (op
, i
, j
)))
2025 else if (fmt
[i
] == 'e' && symbolic_reference_mentioned_p (XEXP (op
, i
)))
2032 /* Decide whether we can make a sibling call to a function. DECL is the
2033 declaration of the function being targeted by the call and EXP is the
2034 CALL_EXPR representing the call. */
2037 bfin_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED
,
2038 tree exp ATTRIBUTE_UNUSED
)
2040 struct cgraph_local_info
*this_func
, *called_func
;
2041 e_funkind fkind
= funkind (TREE_TYPE (current_function_decl
));
2042 if (fkind
!= SUBROUTINE
)
2044 if (!TARGET_ID_SHARED_LIBRARY
|| TARGET_SEP_DATA
)
2047 /* When compiling for ID shared libraries, can't sibcall a local function
2048 from a non-local function, because the local function thinks it does
2049 not need to reload P5 in the prologue, but the sibcall wil pop P5 in the
2050 sibcall epilogue, and we end up with the wrong value in P5. */
2053 /* Not enough information. */
2056 this_func
= cgraph_local_info (current_function_decl
);
2057 called_func
= cgraph_local_info (decl
);
2058 return !called_func
->local
|| this_func
->local
;
2061 /* Emit RTL insns to initialize the variable parts of a trampoline at
2062 TRAMP. FNADDR is an RTX for the address of the function's pure
2063 code. CXT is an RTX for the static chain value for the function. */
2066 initialize_trampoline (rtx tramp
, rtx fnaddr
, rtx cxt
)
2068 rtx t1
= copy_to_reg (fnaddr
);
2069 rtx t2
= copy_to_reg (cxt
);
2075 rtx a
= memory_address (Pmode
, plus_constant (tramp
, 8));
2076 addr
= memory_address (Pmode
, tramp
);
2077 emit_move_insn (gen_rtx_MEM (SImode
, addr
), a
);
2081 addr
= memory_address (Pmode
, plus_constant (tramp
, i
+ 2));
2082 emit_move_insn (gen_rtx_MEM (HImode
, addr
), gen_lowpart (HImode
, t1
));
2083 emit_insn (gen_ashrsi3 (t1
, t1
, GEN_INT (16)));
2084 addr
= memory_address (Pmode
, plus_constant (tramp
, i
+ 6));
2085 emit_move_insn (gen_rtx_MEM (HImode
, addr
), gen_lowpart (HImode
, t1
));
2087 addr
= memory_address (Pmode
, plus_constant (tramp
, i
+ 10));
2088 emit_move_insn (gen_rtx_MEM (HImode
, addr
), gen_lowpart (HImode
, t2
));
2089 emit_insn (gen_ashrsi3 (t2
, t2
, GEN_INT (16)));
2090 addr
= memory_address (Pmode
, plus_constant (tramp
, i
+ 14));
2091 emit_move_insn (gen_rtx_MEM (HImode
, addr
), gen_lowpart (HImode
, t2
));
2094 /* Emit insns to move operands[1] into operands[0]. */
2097 emit_pic_move (rtx
*operands
, enum machine_mode mode ATTRIBUTE_UNUSED
)
2099 rtx temp
= reload_in_progress
? operands
[0] : gen_reg_rtx (Pmode
);
2101 gcc_assert (!TARGET_FDPIC
|| !(reload_in_progress
|| reload_completed
));
2102 if (GET_CODE (operands
[0]) == MEM
&& SYMBOLIC_CONST (operands
[1]))
2103 operands
[1] = force_reg (SImode
, operands
[1]);
2105 operands
[1] = legitimize_pic_address (operands
[1], temp
,
2106 TARGET_FDPIC
? OUR_FDPIC_REG
2107 : pic_offset_table_rtx
);
2110 /* Expand a move operation in mode MODE. The operands are in OPERANDS.
2111 Returns true if no further code must be generated, false if the caller
2112 should generate an insn to move OPERANDS[1] to OPERANDS[0]. */
2115 expand_move (rtx
*operands
, enum machine_mode mode
)
2117 rtx op
= operands
[1];
2118 if ((TARGET_ID_SHARED_LIBRARY
|| TARGET_FDPIC
)
2119 && SYMBOLIC_CONST (op
))
2120 emit_pic_move (operands
, mode
);
2121 else if (mode
== SImode
&& GET_CODE (op
) == CONST
2122 && GET_CODE (XEXP (op
, 0)) == PLUS
2123 && GET_CODE (XEXP (XEXP (op
, 0), 0)) == SYMBOL_REF
2124 && !bfin_legitimate_constant_p (op
))
2126 rtx dest
= operands
[0];
2128 gcc_assert (!reload_in_progress
&& !reload_completed
);
2130 op0
= force_reg (mode
, XEXP (op
, 0));
2132 if (!insn_data
[CODE_FOR_addsi3
].operand
[2].predicate (op1
, mode
))
2133 op1
= force_reg (mode
, op1
);
2134 if (GET_CODE (dest
) == MEM
)
2135 dest
= gen_reg_rtx (mode
);
2136 emit_insn (gen_addsi3 (dest
, op0
, op1
));
2137 if (dest
== operands
[0])
2141 /* Don't generate memory->memory or constant->memory moves, go through a
2143 else if ((reload_in_progress
| reload_completed
) == 0
2144 && GET_CODE (operands
[0]) == MEM
2145 && GET_CODE (operands
[1]) != REG
)
2146 operands
[1] = force_reg (mode
, operands
[1]);
2150 /* Split one or more DImode RTL references into pairs of SImode
2151 references. The RTL can be REG, offsettable MEM, integer constant, or
2152 CONST_DOUBLE. "operands" is a pointer to an array of DImode RTL to
2153 split and "num" is its length. lo_half and hi_half are output arrays
2154 that parallel "operands". */
2157 split_di (rtx operands
[], int num
, rtx lo_half
[], rtx hi_half
[])
2161 rtx op
= operands
[num
];
2163 /* simplify_subreg refuse to split volatile memory addresses,
2164 but we still have to handle it. */
2165 if (GET_CODE (op
) == MEM
)
2167 lo_half
[num
] = adjust_address (op
, SImode
, 0);
2168 hi_half
[num
] = adjust_address (op
, SImode
, 4);
2172 lo_half
[num
] = simplify_gen_subreg (SImode
, op
,
2173 GET_MODE (op
) == VOIDmode
2174 ? DImode
: GET_MODE (op
), 0);
2175 hi_half
[num
] = simplify_gen_subreg (SImode
, op
,
2176 GET_MODE (op
) == VOIDmode
2177 ? DImode
: GET_MODE (op
), 4);
2183 bfin_longcall_p (rtx op
, int call_cookie
)
2185 gcc_assert (GET_CODE (op
) == SYMBOL_REF
);
2186 if (call_cookie
& CALL_SHORT
)
2188 if (call_cookie
& CALL_LONG
)
2190 if (TARGET_LONG_CALLS
)
2195 /* Expand a call instruction. FNADDR is the call target, RETVAL the return value.
2196 COOKIE is a CONST_INT holding the call_cookie prepared init_cumulative_args.
2197 SIBCALL is nonzero if this is a sibling call. */
2200 bfin_expand_call (rtx retval
, rtx fnaddr
, rtx callarg1
, rtx cookie
, int sibcall
)
2202 rtx use
= NULL
, call
;
2203 rtx callee
= XEXP (fnaddr
, 0);
2204 int nelts
= 2 + !!sibcall
;
2206 rtx picreg
= get_hard_reg_initial_val (SImode
, FDPIC_REGNO
);
2209 /* In an untyped call, we can get NULL for operand 2. */
2210 if (cookie
== NULL_RTX
)
2211 cookie
= const0_rtx
;
2213 /* Static functions and indirect calls don't need the pic register. */
2214 if (!TARGET_FDPIC
&& flag_pic
2215 && GET_CODE (callee
) == SYMBOL_REF
2216 && !SYMBOL_REF_LOCAL_P (callee
))
2217 use_reg (&use
, pic_offset_table_rtx
);
2221 int caller_has_l1_text
, callee_has_l1_text
;
2223 caller_has_l1_text
= callee_has_l1_text
= 0;
2225 if (lookup_attribute ("l1_text",
2226 DECL_ATTRIBUTES (cfun
->decl
)) != NULL_TREE
)
2227 caller_has_l1_text
= 1;
2229 if (GET_CODE (callee
) == SYMBOL_REF
2230 && SYMBOL_REF_DECL (callee
) && DECL_P (SYMBOL_REF_DECL (callee
))
2233 DECL_ATTRIBUTES (SYMBOL_REF_DECL (callee
))) != NULL_TREE
)
2234 callee_has_l1_text
= 1;
2236 if (GET_CODE (callee
) != SYMBOL_REF
2237 || bfin_longcall_p (callee
, INTVAL (cookie
))
2238 || (GET_CODE (callee
) == SYMBOL_REF
2239 && !SYMBOL_REF_LOCAL_P (callee
)
2240 && TARGET_INLINE_PLT
)
2241 || caller_has_l1_text
!= callee_has_l1_text
2242 || (caller_has_l1_text
&& callee_has_l1_text
2243 && (GET_CODE (callee
) != SYMBOL_REF
2244 || !SYMBOL_REF_LOCAL_P (callee
))))
2247 if (! address_operand (addr
, Pmode
))
2248 addr
= force_reg (Pmode
, addr
);
2250 fnaddr
= gen_reg_rtx (SImode
);
2251 emit_insn (gen_load_funcdescsi (fnaddr
, addr
));
2252 fnaddr
= gen_rtx_MEM (Pmode
, fnaddr
);
2254 picreg
= gen_reg_rtx (SImode
);
2255 emit_insn (gen_load_funcdescsi (picreg
,
2256 plus_constant (addr
, 4)));
2261 else if ((!register_no_elim_operand (callee
, Pmode
)
2262 && GET_CODE (callee
) != SYMBOL_REF
)
2263 || (GET_CODE (callee
) == SYMBOL_REF
2264 && ((TARGET_ID_SHARED_LIBRARY
&& !TARGET_LEAF_ID_SHARED_LIBRARY
)
2265 || bfin_longcall_p (callee
, INTVAL (cookie
)))))
2267 callee
= copy_to_mode_reg (Pmode
, callee
);
2268 fnaddr
= gen_rtx_MEM (Pmode
, callee
);
2270 call
= gen_rtx_CALL (VOIDmode
, fnaddr
, callarg1
);
2273 call
= gen_rtx_SET (VOIDmode
, retval
, call
);
2275 pat
= gen_rtx_PARALLEL (VOIDmode
, rtvec_alloc (nelts
));
2277 XVECEXP (pat
, 0, n
++) = call
;
2279 XVECEXP (pat
, 0, n
++) = gen_rtx_USE (VOIDmode
, picreg
);
2280 XVECEXP (pat
, 0, n
++) = gen_rtx_USE (VOIDmode
, cookie
);
2282 XVECEXP (pat
, 0, n
++) = gen_rtx_RETURN (VOIDmode
);
2283 call
= emit_call_insn (pat
);
2285 CALL_INSN_FUNCTION_USAGE (call
) = use
;
2288 /* Return 1 if hard register REGNO can hold a value of machine-mode MODE. */
2291 hard_regno_mode_ok (int regno
, enum machine_mode mode
)
2293 /* Allow only dregs to store value of mode HI or QI */
2294 enum reg_class rclass
= REGNO_REG_CLASS (regno
);
2299 if (mode
== V2HImode
)
2300 return D_REGNO_P (regno
);
2301 if (rclass
== CCREGS
)
2302 return mode
== BImode
;
2303 if (mode
== PDImode
|| mode
== V2PDImode
)
2304 return regno
== REG_A0
|| regno
== REG_A1
;
2306 /* Allow all normal 32-bit regs, except REG_M3, in case regclass ever comes
2307 up with a bad register class (such as ALL_REGS) for DImode. */
2309 return regno
< REG_M3
;
2312 && TEST_HARD_REG_BIT (reg_class_contents
[PROLOGUE_REGS
], regno
))
2315 return TEST_HARD_REG_BIT (reg_class_contents
[MOST_REGS
], regno
);
2318 /* Implements target hook vector_mode_supported_p. */
2321 bfin_vector_mode_supported_p (enum machine_mode mode
)
2323 return mode
== V2HImode
;
2326 /* Return the cost of moving data from a register in class CLASS1 to
2327 one in class CLASS2. A cost of 2 is the default. */
2330 bfin_register_move_cost (enum machine_mode mode
,
2331 enum reg_class class1
, enum reg_class class2
)
2333 /* These need secondary reloads, so they're more expensive. */
2334 if ((class1
== CCREGS
&& class2
!= DREGS
)
2335 || (class1
!= DREGS
&& class2
== CCREGS
))
2338 /* If optimizing for size, always prefer reg-reg over reg-memory moves. */
2342 /* There are some stalls involved when moving from a DREG to a different
2343 class reg, and using the value in one of the following instructions.
2344 Attempt to model this by slightly discouraging such moves. */
2345 if (class1
== DREGS
&& class2
!= DREGS
)
2348 if (GET_MODE_CLASS (mode
) == MODE_INT
)
2350 /* Discourage trying to use the accumulators. */
2351 if (TEST_HARD_REG_BIT (reg_class_contents
[class1
], REG_A0
)
2352 || TEST_HARD_REG_BIT (reg_class_contents
[class1
], REG_A1
)
2353 || TEST_HARD_REG_BIT (reg_class_contents
[class2
], REG_A0
)
2354 || TEST_HARD_REG_BIT (reg_class_contents
[class2
], REG_A1
))
2360 /* Return the cost of moving data of mode M between a
2361 register and memory. A value of 2 is the default; this cost is
2362 relative to those in `REGISTER_MOVE_COST'.
2364 ??? In theory L1 memory has single-cycle latency. We should add a switch
2365 that tells the compiler whether we expect to use only L1 memory for the
2366 program; it'll make the costs more accurate. */
2369 bfin_memory_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED
,
2370 enum reg_class rclass
,
2371 int in ATTRIBUTE_UNUSED
)
2373 /* Make memory accesses slightly more expensive than any register-register
2374 move. Also, penalize non-DP registers, since they need secondary
2375 reloads to load and store. */
2376 if (! reg_class_subset_p (rclass
, DPREGS
))
2382 /* Inform reload about cases where moving X with a mode MODE to a register in
2383 RCLASS requires an extra scratch register. Return the class needed for the
2384 scratch register. */
2386 static enum reg_class
2387 bfin_secondary_reload (bool in_p
, rtx x
, enum reg_class rclass
,
2388 enum machine_mode mode
, secondary_reload_info
*sri
)
2390 /* If we have HImode or QImode, we can only use DREGS as secondary registers;
2391 in most other cases we can also use PREGS. */
2392 enum reg_class default_class
= GET_MODE_SIZE (mode
) >= 4 ? DPREGS
: DREGS
;
2393 enum reg_class x_class
= NO_REGS
;
2394 enum rtx_code code
= GET_CODE (x
);
2397 x
= SUBREG_REG (x
), code
= GET_CODE (x
);
2400 int regno
= REGNO (x
);
2401 if (regno
>= FIRST_PSEUDO_REGISTER
)
2402 regno
= reg_renumber
[regno
];
2407 x_class
= REGNO_REG_CLASS (regno
);
2410 /* We can be asked to reload (plus (FP) (large_constant)) into a DREG.
2411 This happens as a side effect of register elimination, and we need
2412 a scratch register to do it. */
2413 if (fp_plus_const_operand (x
, mode
))
2415 rtx op2
= XEXP (x
, 1);
2416 int large_constant_p
= ! satisfies_constraint_Ks7 (op2
);
2418 if (rclass
== PREGS
|| rclass
== PREGS_CLOBBERED
)
2420 /* If destination is a DREG, we can do this without a scratch register
2421 if the constant is valid for an add instruction. */
2422 if ((rclass
== DREGS
|| rclass
== DPREGS
)
2423 && ! large_constant_p
)
2425 /* Reloading to anything other than a DREG? Use a PREG scratch
2427 sri
->icode
= CODE_FOR_reload_insi
;
2431 /* Data can usually be moved freely between registers of most classes.
2432 AREGS are an exception; they can only move to or from another register
2433 in AREGS or one in DREGS. They can also be assigned the constant 0. */
2434 if (x_class
== AREGS
|| x_class
== EVEN_AREGS
|| x_class
== ODD_AREGS
)
2435 return (rclass
== DREGS
|| rclass
== AREGS
|| rclass
== EVEN_AREGS
2436 || rclass
== ODD_AREGS
2439 if (rclass
== AREGS
|| rclass
== EVEN_AREGS
|| rclass
== ODD_AREGS
)
2443 sri
->icode
= in_p
? CODE_FOR_reload_inpdi
: CODE_FOR_reload_outpdi
;
2447 if (x
!= const0_rtx
&& x_class
!= DREGS
)
2455 /* CCREGS can only be moved from/to DREGS. */
2456 if (rclass
== CCREGS
&& x_class
!= DREGS
)
2458 if (x_class
== CCREGS
&& rclass
!= DREGS
)
2461 /* All registers other than AREGS can load arbitrary constants. The only
2462 case that remains is MEM. */
2464 if (! reg_class_subset_p (rclass
, default_class
))
2465 return default_class
;
2470 /* Implement TARGET_HANDLE_OPTION. */
2473 bfin_handle_option (size_t code
, const char *arg
, int value
)
2477 case OPT_mshared_library_id_
:
2478 if (value
> MAX_LIBRARY_ID
)
2479 error ("-mshared-library-id=%s is not between 0 and %d",
2480 arg
, MAX_LIBRARY_ID
);
2481 bfin_lib_id_given
= 1;
2490 while ((p
= bfin_cpus
[i
].name
) != NULL
)
2492 if (strncmp (arg
, p
, strlen (p
)) == 0)
2499 error ("-mcpu=%s is not valid", arg
);
2503 bfin_cpu_type
= bfin_cpus
[i
].type
;
2505 q
= arg
+ strlen (p
);
2509 bfin_si_revision
= bfin_cpus
[i
].si_revision
;
2510 bfin_workarounds
|= bfin_cpus
[i
].workarounds
;
2512 else if (strcmp (q
, "-none") == 0)
2513 bfin_si_revision
= -1;
2514 else if (strcmp (q
, "-any") == 0)
2516 bfin_si_revision
= 0xffff;
2517 while (bfin_cpus
[i
].type
== bfin_cpu_type
)
2519 bfin_workarounds
|= bfin_cpus
[i
].workarounds
;
2525 unsigned int si_major
, si_minor
;
2528 rev_len
= strlen (q
);
2530 if (sscanf (q
, "-%u.%u%n", &si_major
, &si_minor
, &n
) != 2
2532 || si_major
> 0xff || si_minor
> 0xff)
2534 invalid_silicon_revision
:
2535 error ("-mcpu=%s has invalid silicon revision", arg
);
2539 bfin_si_revision
= (si_major
<< 8) | si_minor
;
2541 while (bfin_cpus
[i
].type
== bfin_cpu_type
2542 && bfin_cpus
[i
].si_revision
!= bfin_si_revision
)
2545 if (bfin_cpus
[i
].type
!= bfin_cpu_type
)
2546 goto invalid_silicon_revision
;
2548 bfin_workarounds
|= bfin_cpus
[i
].workarounds
;
2559 static struct machine_function
*
2560 bfin_init_machine_status (void)
2562 struct machine_function
*f
;
2564 f
= GGC_CNEW (struct machine_function
);
2569 /* Implement the macro OVERRIDE_OPTIONS. */
2572 override_options (void)
2574 /* If processor type is not specified, enable all workarounds. */
2575 if (bfin_cpu_type
== BFIN_CPU_UNKNOWN
)
2579 for (i
= 0; bfin_cpus
[i
].name
!= NULL
; i
++)
2580 bfin_workarounds
|= bfin_cpus
[i
].workarounds
;
2582 bfin_si_revision
= 0xffff;
2585 if (bfin_csync_anomaly
== 1)
2586 bfin_workarounds
|= WA_SPECULATIVE_SYNCS
;
2587 else if (bfin_csync_anomaly
== 0)
2588 bfin_workarounds
&= ~WA_SPECULATIVE_SYNCS
;
2590 if (bfin_specld_anomaly
== 1)
2591 bfin_workarounds
|= WA_SPECULATIVE_LOADS
;
2592 else if (bfin_specld_anomaly
== 0)
2593 bfin_workarounds
&= ~WA_SPECULATIVE_LOADS
;
2595 if (TARGET_OMIT_LEAF_FRAME_POINTER
)
2596 flag_omit_frame_pointer
= 1;
2598 /* Library identification */
2599 if (bfin_lib_id_given
&& ! TARGET_ID_SHARED_LIBRARY
)
2600 error ("-mshared-library-id= specified without -mid-shared-library");
2602 if (stack_limit_rtx
&& TARGET_STACK_CHECK_L1
)
2603 error ("Can't use multiple stack checking methods together.");
2605 if (TARGET_ID_SHARED_LIBRARY
&& TARGET_FDPIC
)
2606 error ("ID shared libraries and FD-PIC mode can't be used together.");
2608 /* Don't allow the user to specify -mid-shared-library and -msep-data
2609 together, as it makes little sense from a user's point of view... */
2610 if (TARGET_SEP_DATA
&& TARGET_ID_SHARED_LIBRARY
)
2611 error ("cannot specify both -msep-data and -mid-shared-library");
2612 /* ... internally, however, it's nearly the same. */
2613 if (TARGET_SEP_DATA
)
2614 target_flags
|= MASK_ID_SHARED_LIBRARY
| MASK_LEAF_ID_SHARED_LIBRARY
;
2616 if (TARGET_ID_SHARED_LIBRARY
&& flag_pic
== 0)
2619 /* There is no single unaligned SI op for PIC code. Sometimes we
2620 need to use ".4byte" and sometimes we need to use ".picptr".
2621 See bfin_assemble_integer for details. */
2623 targetm
.asm_out
.unaligned_op
.si
= 0;
2625 /* Silently turn off flag_pic if not doing FDPIC or ID shared libraries,
2626 since we don't support it and it'll just break. */
2627 if (flag_pic
&& !TARGET_FDPIC
&& !TARGET_ID_SHARED_LIBRARY
)
2630 if (TARGET_MULTICORE
&& bfin_cpu_type
!= BFIN_CPU_BF561
)
2631 error ("-mmulticore can only be used with BF561");
2633 if (TARGET_COREA
&& !TARGET_MULTICORE
)
2634 error ("-mcorea should be used with -mmulticore");
2636 if (TARGET_COREB
&& !TARGET_MULTICORE
)
2637 error ("-mcoreb should be used with -mmulticore");
2639 if (TARGET_COREA
&& TARGET_COREB
)
2640 error ("-mcorea and -mcoreb can't be used together");
2642 flag_schedule_insns
= 0;
2644 /* Passes after sched2 can break the helpful TImode annotations that
2645 haifa-sched puts on every insn. Just do scheduling in reorg. */
2646 bfin_flag_schedule_insns2
= flag_schedule_insns_after_reload
;
2647 flag_schedule_insns_after_reload
= 0;
2649 init_machine_status
= bfin_init_machine_status
;
2652 /* Return the destination address of BRANCH.
2653 We need to use this instead of get_attr_length, because the
2654 cbranch_with_nops pattern conservatively sets its length to 6, and
2655 we still prefer to use shorter sequences. */
2658 branch_dest (rtx branch
)
2662 rtx pat
= PATTERN (branch
);
2663 if (GET_CODE (pat
) == PARALLEL
)
2664 pat
= XVECEXP (pat
, 0, 0);
2665 dest
= SET_SRC (pat
);
2666 if (GET_CODE (dest
) == IF_THEN_ELSE
)
2667 dest
= XEXP (dest
, 1);
2668 dest
= XEXP (dest
, 0);
2669 dest_uid
= INSN_UID (dest
);
2670 return INSN_ADDRESSES (dest_uid
);
2673 /* Return nonzero if INSN is annotated with a REG_BR_PROB note that indicates
2674 it's a branch that's predicted taken. */
2677 cbranch_predicted_taken_p (rtx insn
)
2679 rtx x
= find_reg_note (insn
, REG_BR_PROB
, 0);
2683 int pred_val
= INTVAL (XEXP (x
, 0));
2685 return pred_val
>= REG_BR_PROB_BASE
/ 2;
2691 /* Templates for use by asm_conditional_branch. */
2693 static const char *ccbranch_templates
[][3] = {
2694 { "if !cc jump %3;", "if cc jump 4 (bp); jump.s %3;", "if cc jump 6 (bp); jump.l %3;" },
2695 { "if cc jump %3;", "if !cc jump 4 (bp); jump.s %3;", "if !cc jump 6 (bp); jump.l %3;" },
2696 { "if !cc jump %3 (bp);", "if cc jump 4; jump.s %3;", "if cc jump 6; jump.l %3;" },
2697 { "if cc jump %3 (bp);", "if !cc jump 4; jump.s %3;", "if !cc jump 6; jump.l %3;" },
2700 /* Output INSN, which is a conditional branch instruction with operands
2703 We deal with the various forms of conditional branches that can be generated
2704 by bfin_reorg to prevent the hardware from doing speculative loads, by
2705 - emitting a sufficient number of nops, if N_NOPS is nonzero, or
2706 - always emitting the branch as predicted taken, if PREDICT_TAKEN is true.
2707 Either of these is only necessary if the branch is short, otherwise the
2708 template we use ends in an unconditional jump which flushes the pipeline
2712 asm_conditional_branch (rtx insn
, rtx
*operands
, int n_nops
, int predict_taken
)
2714 int offset
= branch_dest (insn
) - INSN_ADDRESSES (INSN_UID (insn
));
2715 /* Note : offset for instructions like if cc jmp; jump.[sl] offset
2716 is to be taken from start of if cc rather than jump.
2717 Range for jump.s is (-4094, 4096) instead of (-4096, 4094)
2719 int len
= (offset
>= -1024 && offset
<= 1022 ? 0
2720 : offset
>= -4094 && offset
<= 4096 ? 1
2722 int bp
= predict_taken
&& len
== 0 ? 1 : cbranch_predicted_taken_p (insn
);
2723 int idx
= (bp
<< 1) | (GET_CODE (operands
[0]) == EQ
? BRF
: BRT
);
2724 output_asm_insn (ccbranch_templates
[idx
][len
], operands
);
2725 gcc_assert (n_nops
== 0 || !bp
);
2727 while (n_nops
-- > 0)
2728 output_asm_insn ("nop;", NULL
);
2731 /* Emit rtl for a comparison operation CMP in mode MODE. Operands have been
2732 stored in bfin_compare_op0 and bfin_compare_op1 already. */
2735 bfin_gen_compare (rtx cmp
, enum machine_mode mode ATTRIBUTE_UNUSED
)
2737 enum rtx_code code1
, code2
;
2738 rtx op0
= bfin_compare_op0
, op1
= bfin_compare_op1
;
2739 rtx tem
= bfin_cc_rtx
;
2740 enum rtx_code code
= GET_CODE (cmp
);
2742 /* If we have a BImode input, then we already have a compare result, and
2743 do not need to emit another comparison. */
2744 if (GET_MODE (op0
) == BImode
)
2746 gcc_assert ((code
== NE
|| code
== EQ
) && op1
== const0_rtx
);
2747 tem
= op0
, code2
= code
;
2752 /* bfin has these conditions */
2762 code1
= reverse_condition (code
);
2766 emit_insn (gen_rtx_SET (BImode
, tem
,
2767 gen_rtx_fmt_ee (code1
, BImode
, op0
, op1
)));
2770 return gen_rtx_fmt_ee (code2
, BImode
, tem
, CONST0_RTX (BImode
));
2773 /* Return nonzero iff C has exactly one bit set if it is interpreted
2774 as a 32-bit constant. */
2777 log2constp (unsigned HOST_WIDE_INT c
)
2780 return c
!= 0 && (c
& (c
-1)) == 0;
2783 /* Returns the number of consecutive least significant zeros in the binary
2784 representation of *V.
2785 We modify *V to contain the original value arithmetically shifted right by
2786 the number of zeroes. */
2789 shiftr_zero (HOST_WIDE_INT
*v
)
2791 unsigned HOST_WIDE_INT tmp
= *v
;
2792 unsigned HOST_WIDE_INT sgn
;
2798 sgn
= tmp
& ((unsigned HOST_WIDE_INT
) 1 << (HOST_BITS_PER_WIDE_INT
- 1));
2799 while ((tmp
& 0x1) == 0 && n
<= 32)
2801 tmp
= (tmp
>> 1) | sgn
;
2808 /* After reload, split the load of an immediate constant. OPERANDS are the
2809 operands of the movsi_insn pattern which we are splitting. We return
2810 nonzero if we emitted a sequence to load the constant, zero if we emitted
2811 nothing because we want to use the splitter's default sequence. */
2814 split_load_immediate (rtx operands
[])
2816 HOST_WIDE_INT val
= INTVAL (operands
[1]);
2818 HOST_WIDE_INT shifted
= val
;
2819 HOST_WIDE_INT shifted_compl
= ~val
;
2820 int num_zero
= shiftr_zero (&shifted
);
2821 int num_compl_zero
= shiftr_zero (&shifted_compl
);
2822 unsigned int regno
= REGNO (operands
[0]);
2824 /* This case takes care of single-bit set/clear constants, which we could
2825 also implement with BITSET/BITCLR. */
2827 && shifted
>= -32768 && shifted
< 65536
2828 && (D_REGNO_P (regno
)
2829 || (regno
>= REG_P0
&& regno
<= REG_P7
&& num_zero
<= 2)))
2831 emit_insn (gen_movsi (operands
[0], GEN_INT (shifted
)));
2832 emit_insn (gen_ashlsi3 (operands
[0], operands
[0], GEN_INT (num_zero
)));
2837 tmp
|= -(tmp
& 0x8000);
2839 /* If high word has one bit set or clear, try to use a bit operation. */
2840 if (D_REGNO_P (regno
))
2842 if (log2constp (val
& 0xFFFF0000))
2844 emit_insn (gen_movsi (operands
[0], GEN_INT (val
& 0xFFFF)));
2845 emit_insn (gen_iorsi3 (operands
[0], operands
[0], GEN_INT (val
& 0xFFFF0000)));
2848 else if (log2constp (val
| 0xFFFF) && (val
& 0x8000) != 0)
2850 emit_insn (gen_movsi (operands
[0], GEN_INT (tmp
)));
2851 emit_insn (gen_andsi3 (operands
[0], operands
[0], GEN_INT (val
| 0xFFFF)));
2855 if (D_REGNO_P (regno
))
2857 if (tmp
>= -64 && tmp
<= 63)
2859 emit_insn (gen_movsi (operands
[0], GEN_INT (tmp
)));
2860 emit_insn (gen_movstricthi_high (operands
[0], GEN_INT (val
& -65536)));
2864 if ((val
& 0xFFFF0000) == 0)
2866 emit_insn (gen_movsi (operands
[0], const0_rtx
));
2867 emit_insn (gen_movsi_low (operands
[0], operands
[0], operands
[1]));
2871 if ((val
& 0xFFFF0000) == 0xFFFF0000)
2873 emit_insn (gen_movsi (operands
[0], constm1_rtx
));
2874 emit_insn (gen_movsi_low (operands
[0], operands
[0], operands
[1]));
2879 /* Need DREGs for the remaining case. */
2884 && num_compl_zero
&& shifted_compl
>= -64 && shifted_compl
<= 63)
2886 /* If optimizing for size, generate a sequence that has more instructions
2888 emit_insn (gen_movsi (operands
[0], GEN_INT (shifted_compl
)));
2889 emit_insn (gen_ashlsi3 (operands
[0], operands
[0],
2890 GEN_INT (num_compl_zero
)));
2891 emit_insn (gen_one_cmplsi2 (operands
[0], operands
[0]));
2897 /* Return true if the legitimate memory address for a memory operand of mode
2898 MODE. Return false if not. */
2901 bfin_valid_add (enum machine_mode mode
, HOST_WIDE_INT value
)
2903 unsigned HOST_WIDE_INT v
= value
> 0 ? value
: -value
;
2904 int sz
= GET_MODE_SIZE (mode
);
2905 int shift
= sz
== 1 ? 0 : sz
== 2 ? 1 : 2;
2906 /* The usual offsettable_memref machinery doesn't work so well for this
2907 port, so we deal with the problem here. */
2908 if (value
> 0 && sz
== 8)
2910 return (v
& ~(0x7fff << shift
)) == 0;
2914 bfin_valid_reg_p (unsigned int regno
, int strict
, enum machine_mode mode
,
2915 enum rtx_code outer_code
)
2918 return REGNO_OK_FOR_BASE_STRICT_P (regno
, mode
, outer_code
, SCRATCH
);
2920 return REGNO_OK_FOR_BASE_NONSTRICT_P (regno
, mode
, outer_code
, SCRATCH
);
2924 bfin_legitimate_address_p (enum machine_mode mode
, rtx x
, int strict
)
2926 switch (GET_CODE (x
)) {
2928 if (bfin_valid_reg_p (REGNO (x
), strict
, mode
, MEM
))
2932 if (REG_P (XEXP (x
, 0))
2933 && bfin_valid_reg_p (REGNO (XEXP (x
, 0)), strict
, mode
, PLUS
)
2934 && ((GET_CODE (XEXP (x
, 1)) == UNSPEC
&& mode
== SImode
)
2935 || (GET_CODE (XEXP (x
, 1)) == CONST_INT
2936 && bfin_valid_add (mode
, INTVAL (XEXP (x
, 1))))))
2941 if (LEGITIMATE_MODE_FOR_AUTOINC_P (mode
)
2942 && REG_P (XEXP (x
, 0))
2943 && bfin_valid_reg_p (REGNO (XEXP (x
, 0)), strict
, mode
, POST_INC
))
2946 if (LEGITIMATE_MODE_FOR_AUTOINC_P (mode
)
2947 && XEXP (x
, 0) == stack_pointer_rtx
2948 && REG_P (XEXP (x
, 0))
2949 && bfin_valid_reg_p (REGNO (XEXP (x
, 0)), strict
, mode
, PRE_DEC
))
2958 /* Decide whether we can force certain constants to memory. If we
2959 decide we can't, the caller should be able to cope with it in
2963 bfin_cannot_force_const_mem (rtx x ATTRIBUTE_UNUSED
)
2965 /* We have only one class of non-legitimate constants, and our movsi
2966 expander knows how to handle them. Dropping these constants into the
2967 data section would only shift the problem - we'd still get relocs
2968 outside the object, in the data section rather than the text section. */
2972 /* Ensure that for any constant of the form symbol + offset, the offset
2973 remains within the object. Any other constants are ok.
2974 This ensures that flat binaries never have to deal with relocations
2975 crossing section boundaries. */
2978 bfin_legitimate_constant_p (rtx x
)
2981 HOST_WIDE_INT offset
;
2983 if (GET_CODE (x
) != CONST
)
2987 gcc_assert (GET_CODE (x
) == PLUS
);
2991 if (GET_CODE (sym
) != SYMBOL_REF
2992 || GET_CODE (x
) != CONST_INT
)
2994 offset
= INTVAL (x
);
2996 if (SYMBOL_REF_DECL (sym
) == 0)
2999 || offset
>= int_size_in_bytes (TREE_TYPE (SYMBOL_REF_DECL (sym
))))
3006 bfin_rtx_costs (rtx x
, int code
, int outer_code
, int *total
, bool speed
)
3008 int cost2
= COSTS_N_INSNS (1);
3014 if (outer_code
== SET
|| outer_code
== PLUS
)
3015 *total
= satisfies_constraint_Ks7 (x
) ? 0 : cost2
;
3016 else if (outer_code
== AND
)
3017 *total
= log2constp (~INTVAL (x
)) ? 0 : cost2
;
3018 else if (outer_code
== LE
|| outer_code
== LT
|| outer_code
== EQ
)
3019 *total
= (INTVAL (x
) >= -4 && INTVAL (x
) <= 3) ? 0 : cost2
;
3020 else if (outer_code
== LEU
|| outer_code
== LTU
)
3021 *total
= (INTVAL (x
) >= 0 && INTVAL (x
) <= 7) ? 0 : cost2
;
3022 else if (outer_code
== MULT
)
3023 *total
= (INTVAL (x
) == 2 || INTVAL (x
) == 4) ? 0 : cost2
;
3024 else if (outer_code
== ASHIFT
&& (INTVAL (x
) == 1 || INTVAL (x
) == 2))
3026 else if (outer_code
== ASHIFT
|| outer_code
== ASHIFTRT
3027 || outer_code
== LSHIFTRT
)
3028 *total
= (INTVAL (x
) >= 0 && INTVAL (x
) <= 31) ? 0 : cost2
;
3029 else if (outer_code
== IOR
|| outer_code
== XOR
)
3030 *total
= (INTVAL (x
) & (INTVAL (x
) - 1)) == 0 ? 0 : cost2
;
3039 *total
= COSTS_N_INSNS (2);
3045 if (GET_MODE (x
) == SImode
)
3047 if (GET_CODE (op0
) == MULT
3048 && GET_CODE (XEXP (op0
, 1)) == CONST_INT
)
3050 HOST_WIDE_INT val
= INTVAL (XEXP (op0
, 1));
3051 if (val
== 2 || val
== 4)
3054 *total
+= rtx_cost (XEXP (op0
, 0), outer_code
, speed
);
3055 *total
+= rtx_cost (op1
, outer_code
, speed
);
3060 if (GET_CODE (op0
) != REG
3061 && (GET_CODE (op0
) != SUBREG
|| GET_CODE (SUBREG_REG (op0
)) != REG
))
3062 *total
+= rtx_cost (op0
, SET
, speed
);
3063 #if 0 /* We'd like to do this for accuracy, but it biases the loop optimizer
3064 towards creating too many induction variables. */
3065 if (!reg_or_7bit_operand (op1
, SImode
))
3066 *total
+= rtx_cost (op1
, SET
, speed
);
3069 else if (GET_MODE (x
) == DImode
)
3072 if (GET_CODE (op1
) != CONST_INT
3073 || !satisfies_constraint_Ks7 (op1
))
3074 *total
+= rtx_cost (op1
, PLUS
, speed
);
3075 if (GET_CODE (op0
) != REG
3076 && (GET_CODE (op0
) != SUBREG
|| GET_CODE (SUBREG_REG (op0
)) != REG
))
3077 *total
+= rtx_cost (op0
, PLUS
, speed
);
3082 if (GET_MODE (x
) == DImode
)
3091 if (GET_MODE (x
) == DImode
)
3098 if (GET_CODE (op0
) != REG
3099 && (GET_CODE (op0
) != SUBREG
|| GET_CODE (SUBREG_REG (op0
)) != REG
))
3100 *total
+= rtx_cost (op0
, code
, speed
);
3110 /* Handle special cases of IOR: rotates, ALIGN insns, movstricthi_high. */
3113 if ((GET_CODE (op0
) == LSHIFTRT
&& GET_CODE (op1
) == ASHIFT
)
3114 || (GET_CODE (op0
) == ASHIFT
&& GET_CODE (op1
) == ZERO_EXTEND
)
3115 || (GET_CODE (op0
) == ASHIFT
&& GET_CODE (op1
) == LSHIFTRT
)
3116 || (GET_CODE (op0
) == AND
&& GET_CODE (op1
) == CONST_INT
))
3123 if (GET_CODE (op0
) != REG
3124 && (GET_CODE (op0
) != SUBREG
|| GET_CODE (SUBREG_REG (op0
)) != REG
))
3125 *total
+= rtx_cost (op0
, code
, speed
);
3127 if (GET_MODE (x
) == DImode
)
3133 if (GET_MODE (x
) != SImode
)
3138 if (! rhs_andsi3_operand (XEXP (x
, 1), SImode
))
3139 *total
+= rtx_cost (XEXP (x
, 1), code
, speed
);
3143 if (! regorlog2_operand (XEXP (x
, 1), SImode
))
3144 *total
+= rtx_cost (XEXP (x
, 1), code
, speed
);
3151 if (outer_code
== SET
3152 && XEXP (x
, 1) == const1_rtx
3153 && GET_CODE (XEXP (x
, 2)) == CONST_INT
)
3169 if (GET_CODE (op0
) == GET_CODE (op1
)
3170 && (GET_CODE (op0
) == ZERO_EXTEND
3171 || GET_CODE (op0
) == SIGN_EXTEND
))
3173 *total
= COSTS_N_INSNS (1);
3174 op0
= XEXP (op0
, 0);
3175 op1
= XEXP (op1
, 0);
3178 *total
= COSTS_N_INSNS (1);
3180 *total
= COSTS_N_INSNS (3);
3182 if (GET_CODE (op0
) != REG
3183 && (GET_CODE (op0
) != SUBREG
|| GET_CODE (SUBREG_REG (op0
)) != REG
))
3184 *total
+= rtx_cost (op0
, MULT
, speed
);
3185 if (GET_CODE (op1
) != REG
3186 && (GET_CODE (op1
) != SUBREG
|| GET_CODE (SUBREG_REG (op1
)) != REG
))
3187 *total
+= rtx_cost (op1
, MULT
, speed
);
3193 *total
= COSTS_N_INSNS (32);
3198 if (outer_code
== SET
)
3207 /* Used for communication between {push,pop}_multiple_operation (which
3208 we use not only as a predicate) and the corresponding output functions. */
3209 static int first_preg_to_save
, first_dreg_to_save
;
3210 static int n_regs_to_save
;
3213 push_multiple_operation (rtx op
, enum machine_mode mode ATTRIBUTE_UNUSED
)
3215 int lastdreg
= 8, lastpreg
= 6;
3218 first_preg_to_save
= lastpreg
;
3219 first_dreg_to_save
= lastdreg
;
3220 for (i
= 1, group
= 0; i
< XVECLEN (op
, 0) - 1; i
++)
3222 rtx t
= XVECEXP (op
, 0, i
);
3226 if (GET_CODE (t
) != SET
)
3230 dest
= SET_DEST (t
);
3231 if (GET_CODE (dest
) != MEM
|| ! REG_P (src
))
3233 dest
= XEXP (dest
, 0);
3234 if (GET_CODE (dest
) != PLUS
3235 || ! REG_P (XEXP (dest
, 0))
3236 || REGNO (XEXP (dest
, 0)) != REG_SP
3237 || GET_CODE (XEXP (dest
, 1)) != CONST_INT
3238 || INTVAL (XEXP (dest
, 1)) != -i
* 4)
3241 regno
= REGNO (src
);
3244 if (D_REGNO_P (regno
))
3247 first_dreg_to_save
= lastdreg
= regno
- REG_R0
;
3249 else if (regno
>= REG_P0
&& regno
<= REG_P7
)
3252 first_preg_to_save
= lastpreg
= regno
- REG_P0
;
3262 if (regno
>= REG_P0
&& regno
<= REG_P7
)
3265 first_preg_to_save
= lastpreg
= regno
- REG_P0
;
3267 else if (regno
!= REG_R0
+ lastdreg
+ 1)
3272 else if (group
== 2)
3274 if (regno
!= REG_P0
+ lastpreg
+ 1)
3279 n_regs_to_save
= 8 - first_dreg_to_save
+ 6 - first_preg_to_save
;
3284 pop_multiple_operation (rtx op
, enum machine_mode mode ATTRIBUTE_UNUSED
)
3286 int lastdreg
= 8, lastpreg
= 6;
3289 for (i
= 1, group
= 0; i
< XVECLEN (op
, 0); i
++)
3291 rtx t
= XVECEXP (op
, 0, i
);
3295 if (GET_CODE (t
) != SET
)
3299 dest
= SET_DEST (t
);
3300 if (GET_CODE (src
) != MEM
|| ! REG_P (dest
))
3302 src
= XEXP (src
, 0);
3306 if (! REG_P (src
) || REGNO (src
) != REG_SP
)
3309 else if (GET_CODE (src
) != PLUS
3310 || ! REG_P (XEXP (src
, 0))
3311 || REGNO (XEXP (src
, 0)) != REG_SP
3312 || GET_CODE (XEXP (src
, 1)) != CONST_INT
3313 || INTVAL (XEXP (src
, 1)) != (i
- 1) * 4)
3316 regno
= REGNO (dest
);
3319 if (regno
== REG_R7
)
3324 else if (regno
!= REG_P0
+ lastpreg
- 1)
3329 else if (group
== 1)
3331 if (regno
!= REG_R0
+ lastdreg
- 1)
3337 first_dreg_to_save
= lastdreg
;
3338 first_preg_to_save
= lastpreg
;
3339 n_regs_to_save
= 8 - first_dreg_to_save
+ 6 - first_preg_to_save
;
3343 /* Emit assembly code for one multi-register push described by INSN, with
3344 operands in OPERANDS. */
3347 output_push_multiple (rtx insn
, rtx
*operands
)
3352 /* Validate the insn again, and compute first_[dp]reg_to_save. */
3353 ok
= push_multiple_operation (PATTERN (insn
), VOIDmode
);
3356 if (first_dreg_to_save
== 8)
3357 sprintf (buf
, "[--sp] = ( p5:%d );\n", first_preg_to_save
);
3358 else if (first_preg_to_save
== 6)
3359 sprintf (buf
, "[--sp] = ( r7:%d );\n", first_dreg_to_save
);
3361 sprintf (buf
, "[--sp] = ( r7:%d, p5:%d );\n",
3362 first_dreg_to_save
, first_preg_to_save
);
3364 output_asm_insn (buf
, operands
);
3367 /* Emit assembly code for one multi-register pop described by INSN, with
3368 operands in OPERANDS. */
3371 output_pop_multiple (rtx insn
, rtx
*operands
)
3376 /* Validate the insn again, and compute first_[dp]reg_to_save. */
3377 ok
= pop_multiple_operation (PATTERN (insn
), VOIDmode
);
3380 if (first_dreg_to_save
== 8)
3381 sprintf (buf
, "( p5:%d ) = [sp++];\n", first_preg_to_save
);
3382 else if (first_preg_to_save
== 6)
3383 sprintf (buf
, "( r7:%d ) = [sp++];\n", first_dreg_to_save
);
3385 sprintf (buf
, "( r7:%d, p5:%d ) = [sp++];\n",
3386 first_dreg_to_save
, first_preg_to_save
);
3388 output_asm_insn (buf
, operands
);
3391 /* Adjust DST and SRC by OFFSET bytes, and generate one move in mode MODE. */
3394 single_move_for_movmem (rtx dst
, rtx src
, enum machine_mode mode
, HOST_WIDE_INT offset
)
3396 rtx scratch
= gen_reg_rtx (mode
);
3399 srcmem
= adjust_address_nv (src
, mode
, offset
);
3400 dstmem
= adjust_address_nv (dst
, mode
, offset
);
3401 emit_move_insn (scratch
, srcmem
);
3402 emit_move_insn (dstmem
, scratch
);
3405 /* Expand a string move operation of COUNT_EXP bytes from SRC to DST, with
3406 alignment ALIGN_EXP. Return true if successful, false if we should fall
3407 back on a different method. */
3410 bfin_expand_movmem (rtx dst
, rtx src
, rtx count_exp
, rtx align_exp
)
3412 rtx srcreg
, destreg
, countreg
;
3413 HOST_WIDE_INT align
= 0;
3414 unsigned HOST_WIDE_INT count
= 0;
3416 if (GET_CODE (align_exp
) == CONST_INT
)
3417 align
= INTVAL (align_exp
);
3418 if (GET_CODE (count_exp
) == CONST_INT
)
3420 count
= INTVAL (count_exp
);
3422 if (!TARGET_INLINE_ALL_STRINGOPS
&& count
> 64)
3427 /* If optimizing for size, only do single copies inline. */
3430 if (count
== 2 && align
< 2)
3432 if (count
== 4 && align
< 4)
3434 if (count
!= 1 && count
!= 2 && count
!= 4)
3437 if (align
< 2 && count
!= 1)
3440 destreg
= copy_to_mode_reg (Pmode
, XEXP (dst
, 0));
3441 if (destreg
!= XEXP (dst
, 0))
3442 dst
= replace_equiv_address_nv (dst
, destreg
);
3443 srcreg
= copy_to_mode_reg (Pmode
, XEXP (src
, 0));
3444 if (srcreg
!= XEXP (src
, 0))
3445 src
= replace_equiv_address_nv (src
, srcreg
);
3447 if (count
!= 0 && align
>= 2)
3449 unsigned HOST_WIDE_INT offset
= 0;
3453 if ((count
& ~3) == 4)
3455 single_move_for_movmem (dst
, src
, SImode
, offset
);
3458 else if (count
& ~3)
3460 HOST_WIDE_INT new_count
= ((count
>> 2) & 0x3fffffff) - 1;
3461 countreg
= copy_to_mode_reg (Pmode
, GEN_INT (new_count
));
3463 emit_insn (gen_rep_movsi (destreg
, srcreg
, countreg
, destreg
, srcreg
));
3464 cfun
->machine
->has_loopreg_clobber
= true;
3468 single_move_for_movmem (dst
, src
, HImode
, offset
);
3474 if ((count
& ~1) == 2)
3476 single_move_for_movmem (dst
, src
, HImode
, offset
);
3479 else if (count
& ~1)
3481 HOST_WIDE_INT new_count
= ((count
>> 1) & 0x7fffffff) - 1;
3482 countreg
= copy_to_mode_reg (Pmode
, GEN_INT (new_count
));
3484 emit_insn (gen_rep_movhi (destreg
, srcreg
, countreg
, destreg
, srcreg
));
3485 cfun
->machine
->has_loopreg_clobber
= true;
3490 single_move_for_movmem (dst
, src
, QImode
, offset
);
3497 /* Compute the alignment for a local variable.
3498 TYPE is the data type, and ALIGN is the alignment that
3499 the object would ordinarily have. The value of this macro is used
3500 instead of that alignment to align the object. */
3503 bfin_local_alignment (tree type
, int align
)
3505 /* Increasing alignment for (relatively) big types allows the builtin
3506 memcpy can use 32 bit loads/stores. */
3507 if (TYPE_SIZE (type
)
3508 && TREE_CODE (TYPE_SIZE (type
)) == INTEGER_CST
3509 && (TREE_INT_CST_LOW (TYPE_SIZE (type
)) > 8
3510 || TREE_INT_CST_HIGH (TYPE_SIZE (type
))) && align
< 32)
3515 /* Implement TARGET_SCHED_ISSUE_RATE. */
3518 bfin_issue_rate (void)
3524 bfin_adjust_cost (rtx insn
, rtx link
, rtx dep_insn
, int cost
)
3526 enum attr_type insn_type
, dep_insn_type
;
3527 int dep_insn_code_number
;
3529 /* Anti and output dependencies have zero cost. */
3530 if (REG_NOTE_KIND (link
) != 0)
3533 dep_insn_code_number
= recog_memoized (dep_insn
);
3535 /* If we can't recognize the insns, we can't really do anything. */
3536 if (dep_insn_code_number
< 0 || recog_memoized (insn
) < 0)
3539 insn_type
= get_attr_type (insn
);
3540 dep_insn_type
= get_attr_type (dep_insn
);
3542 if (dep_insn_type
== TYPE_MOVE
|| dep_insn_type
== TYPE_MCLD
)
3544 rtx pat
= PATTERN (dep_insn
);
3545 if (GET_CODE (pat
) == PARALLEL
)
3546 pat
= XVECEXP (pat
, 0, 0);
3547 rtx dest
= SET_DEST (pat
);
3548 rtx src
= SET_SRC (pat
);
3549 if (! ADDRESS_REGNO_P (REGNO (dest
))
3550 || ! (MEM_P (src
) || D_REGNO_P (REGNO (src
))))
3552 return cost
+ (dep_insn_type
== TYPE_MOVE
? 4 : 3);
3559 /* Increment the counter for the number of loop instructions in the
3560 current function. */
3563 bfin_hardware_loop (void)
3565 cfun
->machine
->has_hardware_loops
++;
3568 /* Maximum loop nesting depth. */
3569 #define MAX_LOOP_DEPTH 2
3571 /* Maximum size of a loop. */
3572 #define MAX_LOOP_LENGTH 2042
3574 /* Maximum distance of the LSETUP instruction from the loop start. */
3575 #define MAX_LSETUP_DISTANCE 30
3577 /* We need to keep a vector of loops */
3578 typedef struct loop_info
*loop_info
;
3579 DEF_VEC_P (loop_info
);
3580 DEF_VEC_ALLOC_P (loop_info
,heap
);
3582 /* Information about a loop we have found (or are in the process of
3584 struct loop_info
GTY (())
3586 /* loop number, for dumps */
3589 /* All edges that jump into and out of the loop. */
3590 VEC(edge
,gc
) *incoming
;
3592 /* We can handle two cases: all incoming edges have the same destination
3593 block, or all incoming edges have the same source block. These two
3594 members are set to the common source or destination we found, or NULL
3595 if different blocks were found. If both are NULL the loop can't be
3597 basic_block incoming_src
;
3598 basic_block incoming_dest
;
3600 /* First block in the loop. This is the one branched to by the loop_end
3604 /* Last block in the loop (the one with the loop_end insn). */
3607 /* The successor block of the loop. This is the one the loop_end insn
3609 basic_block successor
;
3611 /* The last instruction in the tail. */
3614 /* The loop_end insn. */
3617 /* The iteration register. */
3620 /* The new initialization insn. */
3623 /* The new initialization instruction. */
3626 /* The new label placed at the beginning of the loop. */
3629 /* The new label placed at the end of the loop. */
3632 /* The length of the loop. */
3635 /* The nesting depth of the loop. */
3638 /* Nonzero if we can't optimize this loop. */
3641 /* True if we have visited this loop. */
3644 /* True if this loop body clobbers any of LC0, LT0, or LB0. */
3647 /* True if this loop body clobbers any of LC1, LT1, or LB1. */
3650 /* Next loop in the graph. */
3651 struct loop_info
*next
;
3653 /* Immediate outer loop of this loop. */
3654 struct loop_info
*outer
;
3656 /* Vector of blocks only within the loop, including those within
3658 VEC (basic_block
,heap
) *blocks
;
3660 /* Same information in a bitmap. */
3661 bitmap block_bitmap
;
3663 /* Vector of inner loops within this loop */
3664 VEC (loop_info
,heap
) *loops
;
3668 bfin_dump_loops (loop_info loops
)
3672 for (loop
= loops
; loop
; loop
= loop
->next
)
3678 fprintf (dump_file
, ";; loop %d: ", loop
->loop_no
);
3680 fprintf (dump_file
, "(bad) ");
3681 fprintf (dump_file
, "{head:%d, depth:%d}", loop
->head
->index
, loop
->depth
);
3683 fprintf (dump_file
, " blocks: [ ");
3684 for (ix
= 0; VEC_iterate (basic_block
, loop
->blocks
, ix
, b
); ix
++)
3685 fprintf (dump_file
, "%d ", b
->index
);
3686 fprintf (dump_file
, "] ");
3688 fprintf (dump_file
, " inner loops: [ ");
3689 for (ix
= 0; VEC_iterate (loop_info
, loop
->loops
, ix
, i
); ix
++)
3690 fprintf (dump_file
, "%d ", i
->loop_no
);
3691 fprintf (dump_file
, "]\n");
3693 fprintf (dump_file
, "\n");
3696 /* Scan the blocks of LOOP (and its inferiors) looking for basic block
3697 BB. Return true, if we find it. */
3700 bfin_bb_in_loop (loop_info loop
, basic_block bb
)
3702 return bitmap_bit_p (loop
->block_bitmap
, bb
->index
);
3705 /* Scan the blocks of LOOP (and its inferiors) looking for uses of
3706 REG. Return true, if we find any. Don't count the loop's loop_end
3707 insn if it matches LOOP_END. */
3710 bfin_scan_loop (loop_info loop
, rtx reg
, rtx loop_end
)
3715 for (ix
= 0; VEC_iterate (basic_block
, loop
->blocks
, ix
, bb
); ix
++)
3719 for (insn
= BB_HEAD (bb
);
3720 insn
!= NEXT_INSN (BB_END (bb
));
3721 insn
= NEXT_INSN (insn
))
3725 if (insn
== loop_end
)
3727 if (reg_mentioned_p (reg
, PATTERN (insn
)))
3734 /* Estimate the length of INSN conservatively. */
3737 length_for_loop (rtx insn
)
3740 if (JUMP_P (insn
) && any_condjump_p (insn
) && !optimize_size
)
3742 if (ENABLE_WA_SPECULATIVE_SYNCS
)
3744 else if (ENABLE_WA_SPECULATIVE_LOADS
)
3747 else if (LABEL_P (insn
))
3749 if (ENABLE_WA_SPECULATIVE_SYNCS
)
3754 length
+= get_attr_length (insn
);
3759 /* Optimize LOOP. */
3762 bfin_optimize_loop (loop_info loop
)
3766 rtx insn
, init_insn
, last_insn
, nop_insn
;
3767 rtx loop_init
, start_label
, end_label
;
3768 rtx reg_lc0
, reg_lc1
, reg_lt0
, reg_lt1
, reg_lb0
, reg_lb1
;
3770 rtx lc_reg
, lt_reg
, lb_reg
;
3774 int inner_depth
= 0;
3784 fprintf (dump_file
, ";; loop %d bad when found\n", loop
->loop_no
);
3788 /* Every loop contains in its list of inner loops every loop nested inside
3789 it, even if there are intermediate loops. This works because we're doing
3790 a depth-first search here and never visit a loop more than once. */
3791 for (ix
= 0; VEC_iterate (loop_info
, loop
->loops
, ix
, inner
); ix
++)
3793 bfin_optimize_loop (inner
);
3795 if (!inner
->bad
&& inner_depth
< inner
->depth
)
3797 inner_depth
= inner
->depth
;
3799 loop
->clobber_loop0
|= inner
->clobber_loop0
;
3800 loop
->clobber_loop1
|= inner
->clobber_loop1
;
3804 loop
->depth
= inner_depth
+ 1;
3805 if (loop
->depth
> MAX_LOOP_DEPTH
)
3808 fprintf (dump_file
, ";; loop %d too deep\n", loop
->loop_no
);
3812 /* Get the loop iteration register. */
3813 iter_reg
= loop
->iter_reg
;
3815 if (!DPREG_P (iter_reg
))
3818 fprintf (dump_file
, ";; loop %d iteration count NOT in PREG or DREG\n",
3823 if (loop
->incoming_src
)
3825 /* Make sure the predecessor is before the loop start label, as required by
3826 the LSETUP instruction. */
3828 for (insn
= BB_END (loop
->incoming_src
);
3829 insn
&& insn
!= loop
->start_label
;
3830 insn
= NEXT_INSN (insn
))
3831 length
+= length_for_loop (insn
);
3836 fprintf (dump_file
, ";; loop %d lsetup not before loop_start\n",
3841 if (length
> MAX_LSETUP_DISTANCE
)
3844 fprintf (dump_file
, ";; loop %d lsetup too far away\n", loop
->loop_no
);
3849 /* Check if start_label appears before loop_end and calculate the
3850 offset between them. We calculate the length of instructions
3853 for (insn
= loop
->start_label
;
3854 insn
&& insn
!= loop
->loop_end
;
3855 insn
= NEXT_INSN (insn
))
3856 length
+= length_for_loop (insn
);
3861 fprintf (dump_file
, ";; loop %d start_label not before loop_end\n",
3866 loop
->length
= length
;
3867 if (loop
->length
> MAX_LOOP_LENGTH
)
3870 fprintf (dump_file
, ";; loop %d too long\n", loop
->loop_no
);
3874 /* Scan all the blocks to make sure they don't use iter_reg. */
3875 if (bfin_scan_loop (loop
, iter_reg
, loop
->loop_end
))
3878 fprintf (dump_file
, ";; loop %d uses iterator\n", loop
->loop_no
);
3882 /* Scan all the insns to see if the loop body clobber
3883 any hardware loop registers. */
3885 reg_lc0
= gen_rtx_REG (SImode
, REG_LC0
);
3886 reg_lc1
= gen_rtx_REG (SImode
, REG_LC1
);
3887 reg_lt0
= gen_rtx_REG (SImode
, REG_LT0
);
3888 reg_lt1
= gen_rtx_REG (SImode
, REG_LT1
);
3889 reg_lb0
= gen_rtx_REG (SImode
, REG_LB0
);
3890 reg_lb1
= gen_rtx_REG (SImode
, REG_LB1
);
3892 for (ix
= 0; VEC_iterate (basic_block
, loop
->blocks
, ix
, bb
); ix
++)
3896 for (insn
= BB_HEAD (bb
);
3897 insn
!= NEXT_INSN (BB_END (bb
));
3898 insn
= NEXT_INSN (insn
))
3903 if (reg_set_p (reg_lc0
, insn
)
3904 || reg_set_p (reg_lt0
, insn
)
3905 || reg_set_p (reg_lb0
, insn
))
3906 loop
->clobber_loop0
= 1;
3908 if (reg_set_p (reg_lc1
, insn
)
3909 || reg_set_p (reg_lt1
, insn
)
3910 || reg_set_p (reg_lb1
, insn
))
3911 loop
->clobber_loop1
|= 1;
3915 if ((loop
->clobber_loop0
&& loop
->clobber_loop1
)
3916 || (loop
->depth
== MAX_LOOP_DEPTH
&& loop
->clobber_loop0
))
3918 loop
->depth
= MAX_LOOP_DEPTH
+ 1;
3920 fprintf (dump_file
, ";; loop %d no loop reg available\n",
3925 /* There should be an instruction before the loop_end instruction
3926 in the same basic block. And the instruction must not be
3928 - CONDITIONAL BRANCH
3932 - Returns (RTS, RTN, etc.) */
3935 last_insn
= PREV_INSN (loop
->loop_end
);
3939 for (; last_insn
!= PREV_INSN (BB_HEAD (bb
));
3940 last_insn
= PREV_INSN (last_insn
))
3941 if (INSN_P (last_insn
))
3944 if (last_insn
!= PREV_INSN (BB_HEAD (bb
)))
3947 if (single_pred_p (bb
)
3948 && single_pred (bb
) != ENTRY_BLOCK_PTR
)
3950 bb
= single_pred (bb
);
3951 last_insn
= BB_END (bb
);
3956 last_insn
= NULL_RTX
;
3964 fprintf (dump_file
, ";; loop %d has no last instruction\n",
3969 if (JUMP_P (last_insn
))
3971 loop_info inner
= (loop_info
) bb
->aux
;
3973 && inner
->outer
== loop
3974 && inner
->loop_end
== last_insn
3975 && inner
->depth
== 1)
3976 /* This jump_insn is the exact loop_end of an inner loop
3977 and to be optimized away. So use the inner's last_insn. */
3978 last_insn
= inner
->last_insn
;
3982 fprintf (dump_file
, ";; loop %d has bad last instruction\n",
3987 else if (CALL_P (last_insn
)
3988 || (GET_CODE (PATTERN (last_insn
)) != SEQUENCE
3989 && get_attr_type (last_insn
) == TYPE_SYNC
)
3990 || recog_memoized (last_insn
) == CODE_FOR_return_internal
)
3993 fprintf (dump_file
, ";; loop %d has bad last instruction\n",
3998 if (GET_CODE (PATTERN (last_insn
)) == ASM_INPUT
3999 || asm_noperands (PATTERN (last_insn
)) >= 0
4000 || (GET_CODE (PATTERN (last_insn
)) != SEQUENCE
4001 && get_attr_seq_insns (last_insn
) == SEQ_INSNS_MULTI
))
4003 nop_insn
= emit_insn_after (gen_nop (), last_insn
);
4004 last_insn
= nop_insn
;
4007 loop
->last_insn
= last_insn
;
4009 /* The loop is good for replacement. */
4010 start_label
= loop
->start_label
;
4011 end_label
= gen_label_rtx ();
4012 iter_reg
= loop
->iter_reg
;
4014 if (loop
->depth
== 1 && !loop
->clobber_loop1
)
4019 loop
->clobber_loop1
= 1;
4026 loop
->clobber_loop0
= 1;
4029 /* If iter_reg is a DREG, we need generate an instruction to load
4030 the loop count into LC register. */
4031 if (D_REGNO_P (REGNO (iter_reg
)))
4033 init_insn
= gen_movsi (lc_reg
, iter_reg
);
4034 loop_init
= gen_lsetup_without_autoinit (lt_reg
, start_label
,
4038 else if (P_REGNO_P (REGNO (iter_reg
)))
4040 init_insn
= NULL_RTX
;
4041 loop_init
= gen_lsetup_with_autoinit (lt_reg
, start_label
,
4048 loop
->init
= init_insn
;
4049 loop
->end_label
= end_label
;
4050 loop
->loop_init
= loop_init
;
4054 fprintf (dump_file
, ";; replacing loop %d initializer with\n",
4056 print_rtl_single (dump_file
, loop
->loop_init
);
4057 fprintf (dump_file
, ";; replacing loop %d terminator with\n",
4059 print_rtl_single (dump_file
, loop
->loop_end
);
4062 /* Create a sequence containing the loop setup. */
4065 if (loop
->init
!= NULL_RTX
)
4066 emit_insn (loop
->init
);
4067 seq_end
= emit_insn (loop
->loop_init
);
4069 /* If the loop isn't entered at the top, also create a jump to the entry
4071 if (!loop
->incoming_src
&& loop
->head
!= loop
->incoming_dest
)
4073 rtx label
= BB_HEAD (loop
->incoming_dest
);
4074 /* If we're jumping to the final basic block in the loop, and there's
4075 only one cheap instruction before the end (typically an increment of
4076 an induction variable), we can just emit a copy here instead of a
4078 if (loop
->incoming_dest
== loop
->tail
4079 && next_real_insn (label
) == last_insn
4080 && asm_noperands (last_insn
) < 0
4081 && GET_CODE (PATTERN (last_insn
)) == SET
)
4083 seq_end
= emit_insn (copy_rtx (PATTERN (last_insn
)));
4086 seq_end
= emit_insn (gen_jump (label
));
4092 if (loop
->incoming_src
)
4094 rtx prev
= BB_END (loop
->incoming_src
);
4095 if (VEC_length (edge
, loop
->incoming
) > 1
4096 || !(VEC_last (edge
, loop
->incoming
)->flags
& EDGE_FALLTHRU
))
4098 gcc_assert (JUMP_P (prev
));
4099 prev
= PREV_INSN (prev
);
4101 emit_insn_after (seq
, prev
);
4109 #ifdef ENABLE_CHECKING
4110 if (loop
->head
!= loop
->incoming_dest
)
4112 /* We aren't entering the loop at the top. Since we've established
4113 that the loop is entered only at one point, this means there
4114 can't be fallthru edges into the head. Any such fallthru edges
4115 would become invalid when we insert the new block, so verify
4116 that this does not in fact happen. */
4117 FOR_EACH_EDGE (e
, ei
, loop
->head
->preds
)
4118 gcc_assert (!(e
->flags
& EDGE_FALLTHRU
));
4122 emit_insn_before (seq
, BB_HEAD (loop
->head
));
4123 seq
= emit_label_before (gen_label_rtx (), seq
);
4125 new_bb
= create_basic_block (seq
, seq_end
, loop
->head
->prev_bb
);
4126 FOR_EACH_EDGE (e
, ei
, loop
->incoming
)
4128 if (!(e
->flags
& EDGE_FALLTHRU
)
4129 || e
->dest
!= loop
->head
)
4130 redirect_edge_and_branch_force (e
, new_bb
);
4132 redirect_edge_succ (e
, new_bb
);
4136 delete_insn (loop
->loop_end
);
4137 /* Insert the loop end label before the last instruction of the loop. */
4138 emit_label_before (loop
->end_label
, loop
->last_insn
);
4145 fprintf (dump_file
, ";; loop %d is bad\n", loop
->loop_no
);
4149 if (DPREG_P (loop
->iter_reg
))
4151 /* If loop->iter_reg is a DREG or PREG, we can split it here
4152 without scratch register. */
4155 emit_insn_before (gen_addsi3 (loop
->iter_reg
,
4160 emit_insn_before (gen_cmpsi (loop
->iter_reg
, const0_rtx
),
4163 insn
= emit_jump_insn_before (gen_bne (loop
->start_label
),
4166 JUMP_LABEL (insn
) = loop
->start_label
;
4167 LABEL_NUSES (loop
->start_label
)++;
4168 delete_insn (loop
->loop_end
);
4172 /* Called from bfin_reorg_loops when a potential loop end is found. LOOP is
4173 a newly set up structure describing the loop, it is this function's
4174 responsibility to fill most of it. TAIL_BB and TAIL_INSN point to the
4175 loop_end insn and its enclosing basic block. */
4178 bfin_discover_loop (loop_info loop
, basic_block tail_bb
, rtx tail_insn
)
4182 VEC (basic_block
,heap
) *works
= VEC_alloc (basic_block
,heap
,20);
4184 loop
->tail
= tail_bb
;
4185 loop
->head
= BRANCH_EDGE (tail_bb
)->dest
;
4186 loop
->successor
= FALLTHRU_EDGE (tail_bb
)->dest
;
4187 loop
->loop_end
= tail_insn
;
4188 loop
->last_insn
= NULL_RTX
;
4189 loop
->iter_reg
= SET_DEST (XVECEXP (PATTERN (tail_insn
), 0, 1));
4190 loop
->depth
= loop
->length
= 0;
4192 loop
->clobber_loop0
= loop
->clobber_loop1
= 0;
4195 loop
->incoming
= VEC_alloc (edge
, gc
, 2);
4196 loop
->init
= loop
->loop_init
= NULL_RTX
;
4197 loop
->start_label
= XEXP (XEXP (SET_SRC (XVECEXP (PATTERN (tail_insn
), 0, 0)), 1), 0);
4198 loop
->end_label
= NULL_RTX
;
4201 VEC_safe_push (basic_block
, heap
, works
, loop
->head
);
4203 while (VEC_iterate (basic_block
, works
, dwork
++, bb
))
4207 if (bb
== EXIT_BLOCK_PTR
)
4209 /* We've reached the exit block. The loop must be bad. */
4212 ";; Loop is bad - reached exit block while scanning\n");
4217 if (bitmap_bit_p (loop
->block_bitmap
, bb
->index
))
4220 /* We've not seen this block before. Add it to the loop's
4221 list and then add each successor to the work list. */
4223 VEC_safe_push (basic_block
, heap
, loop
->blocks
, bb
);
4224 bitmap_set_bit (loop
->block_bitmap
, bb
->index
);
4228 FOR_EACH_EDGE (e
, ei
, bb
->succs
)
4230 basic_block succ
= EDGE_SUCC (bb
, ei
.index
)->dest
;
4231 if (!REGNO_REG_SET_P (df_get_live_in (succ
),
4232 REGNO (loop
->iter_reg
)))
4234 if (!VEC_space (basic_block
, works
, 1))
4238 VEC_block_remove (basic_block
, works
, 0, dwork
);
4242 VEC_reserve (basic_block
, heap
, works
, 1);
4244 VEC_quick_push (basic_block
, works
, succ
);
4249 /* Find the predecessor, and make sure nothing else jumps into this loop. */
4253 for (dwork
= 0; VEC_iterate (basic_block
, loop
->blocks
, dwork
, bb
); dwork
++)
4257 FOR_EACH_EDGE (e
, ei
, bb
->preds
)
4259 basic_block pred
= e
->src
;
4261 if (!bfin_bb_in_loop (loop
, pred
))
4264 fprintf (dump_file
, ";; Loop %d: incoming edge %d -> %d\n",
4265 loop
->loop_no
, pred
->index
,
4267 VEC_safe_push (edge
, gc
, loop
->incoming
, e
);
4272 for (pass
= 0, retry
= 1; retry
&& pass
< 2; pass
++)
4279 FOR_EACH_EDGE (e
, ei
, loop
->incoming
)
4283 loop
->incoming_src
= e
->src
;
4284 loop
->incoming_dest
= e
->dest
;
4289 if (e
->dest
!= loop
->incoming_dest
)
4290 loop
->incoming_dest
= NULL
;
4291 if (e
->src
!= loop
->incoming_src
)
4292 loop
->incoming_src
= NULL
;
4294 if (loop
->incoming_src
== NULL
&& loop
->incoming_dest
== NULL
)
4300 ";; retrying loop %d with forwarder blocks\n",
4308 ";; can't find suitable entry for loop %d\n",
4316 FOR_EACH_EDGE (e
, ei
, loop
->incoming
)
4318 if (forwarder_block_p (e
->src
))
4325 ";; Adding forwarder block %d to loop %d and retrying\n",
4326 e
->src
->index
, loop
->loop_no
);
4327 VEC_safe_push (basic_block
, heap
, loop
->blocks
, e
->src
);
4328 bitmap_set_bit (loop
->block_bitmap
, e
->src
->index
);
4329 FOR_EACH_EDGE (e2
, ei2
, e
->src
->preds
)
4330 VEC_safe_push (edge
, gc
, loop
->incoming
, e2
);
4331 VEC_unordered_remove (edge
, loop
->incoming
, ei
.index
);
4341 VEC_free (basic_block
, heap
, works
);
4344 /* Analyze the structure of the loops in the current function. Use STACK
4345 for bitmap allocations. Returns all the valid candidates for hardware
4346 loops found in this function. */
4348 bfin_discover_loops (bitmap_obstack
*stack
, FILE *dump_file
)
4350 loop_info loops
= NULL
;
4356 /* Find all the possible loop tails. This means searching for every
4357 loop_end instruction. For each one found, create a loop_info
4358 structure and add the head block to the work list. */
4361 rtx tail
= BB_END (bb
);
4363 while (GET_CODE (tail
) == NOTE
)
4364 tail
= PREV_INSN (tail
);
4368 if (INSN_P (tail
) && recog_memoized (tail
) == CODE_FOR_loop_end
)
4371 /* A possible loop end */
4373 /* There's a degenerate case we can handle - an empty loop consisting
4374 of only a back branch. Handle that by deleting the branch. */
4375 insn
= BB_HEAD (BRANCH_EDGE (bb
)->dest
);
4376 if (next_real_insn (insn
) == tail
)
4380 fprintf (dump_file
, ";; degenerate loop ending at\n");
4381 print_rtl_single (dump_file
, tail
);
4383 delete_insn_and_edges (tail
);
4387 loop
= XNEW (struct loop_info
);
4390 loop
->loop_no
= nloops
++;
4391 loop
->blocks
= VEC_alloc (basic_block
, heap
, 20);
4392 loop
->block_bitmap
= BITMAP_ALLOC (stack
);
4397 fprintf (dump_file
, ";; potential loop %d ending at\n",
4399 print_rtl_single (dump_file
, tail
);
4402 bfin_discover_loop (loop
, bb
, tail
);
4406 tmp_bitmap
= BITMAP_ALLOC (stack
);
4407 /* Compute loop nestings. */
4408 for (loop
= loops
; loop
; loop
= loop
->next
)
4414 for (other
= loop
->next
; other
; other
= other
->next
)
4419 bitmap_and (tmp_bitmap
, other
->block_bitmap
, loop
->block_bitmap
);
4420 if (bitmap_empty_p (tmp_bitmap
))
4422 if (bitmap_equal_p (tmp_bitmap
, other
->block_bitmap
))
4424 other
->outer
= loop
;
4425 VEC_safe_push (loop_info
, heap
, loop
->loops
, other
);
4427 else if (bitmap_equal_p (tmp_bitmap
, loop
->block_bitmap
))
4429 loop
->outer
= other
;
4430 VEC_safe_push (loop_info
, heap
, other
->loops
, loop
);
4436 ";; can't find suitable nesting for loops %d and %d\n",
4437 loop
->loop_no
, other
->loop_no
);
4438 loop
->bad
= other
->bad
= 1;
4442 BITMAP_FREE (tmp_bitmap
);
4447 /* Free up the loop structures in LOOPS. */
4449 free_loops (loop_info loops
)
4453 loop_info loop
= loops
;
4455 VEC_free (loop_info
, heap
, loop
->loops
);
4456 VEC_free (basic_block
, heap
, loop
->blocks
);
4457 BITMAP_FREE (loop
->block_bitmap
);
4462 #define BB_AUX_INDEX(BB) ((unsigned)(BB)->aux)
4464 /* The taken-branch edge from the loop end can actually go forward. Since the
4465 Blackfin's LSETUP instruction requires that the loop end be after the loop
4466 start, try to reorder a loop's basic blocks when we find such a case. */
4468 bfin_reorder_loops (loop_info loops
, FILE *dump_file
)
4475 cfg_layout_initialize (0);
4477 for (loop
= loops
; loop
; loop
= loop
->next
)
4487 /* Recreate an index for basic blocks that represents their order. */
4488 for (bb
= ENTRY_BLOCK_PTR
->next_bb
, index
= 0;
4489 bb
!= EXIT_BLOCK_PTR
;
4490 bb
= bb
->next_bb
, index
++)
4491 bb
->aux
= (PTR
) index
;
4493 if (BB_AUX_INDEX (loop
->head
) < BB_AUX_INDEX (loop
->tail
))
4496 FOR_EACH_EDGE (e
, ei
, loop
->head
->succs
)
4498 if (bitmap_bit_p (loop
->block_bitmap
, e
->dest
->index
)
4499 && BB_AUX_INDEX (e
->dest
) < BB_AUX_INDEX (loop
->tail
))
4501 basic_block start_bb
= e
->dest
;
4502 basic_block start_prev_bb
= start_bb
->prev_bb
;
4505 fprintf (dump_file
, ";; Moving block %d before block %d\n",
4506 loop
->head
->index
, start_bb
->index
);
4507 loop
->head
->prev_bb
->next_bb
= loop
->head
->next_bb
;
4508 loop
->head
->next_bb
->prev_bb
= loop
->head
->prev_bb
;
4510 loop
->head
->prev_bb
= start_prev_bb
;
4511 loop
->head
->next_bb
= start_bb
;
4512 start_prev_bb
->next_bb
= start_bb
->prev_bb
= loop
->head
;
4516 loops
= loops
->next
;
4521 if (bb
->next_bb
!= EXIT_BLOCK_PTR
)
4522 bb
->aux
= bb
->next_bb
;
4526 cfg_layout_finalize ();
4530 /* Run from machine_dependent_reorg, this pass looks for doloop_end insns
4531 and tries to rewrite the RTL of these loops so that proper Blackfin
4532 hardware loops are generated. */
4535 bfin_reorg_loops (FILE *dump_file
)
4537 loop_info loops
= NULL
;
4540 bitmap_obstack stack
;
4542 bitmap_obstack_initialize (&stack
);
4545 fprintf (dump_file
, ";; Find loops, first pass\n\n");
4547 loops
= bfin_discover_loops (&stack
, dump_file
);
4550 bfin_dump_loops (loops
);
4552 bfin_reorder_loops (loops
, dump_file
);
4556 fprintf (dump_file
, ";; Find loops, second pass\n\n");
4558 loops
= bfin_discover_loops (&stack
, dump_file
);
4561 fprintf (dump_file
, ";; All loops found:\n\n");
4562 bfin_dump_loops (loops
);
4565 /* Now apply the optimizations. */
4566 for (loop
= loops
; loop
; loop
= loop
->next
)
4567 bfin_optimize_loop (loop
);
4571 fprintf (dump_file
, ";; After hardware loops optimization:\n\n");
4572 bfin_dump_loops (loops
);
4578 print_rtl (dump_file
, get_insns ());
4584 /* Possibly generate a SEQUENCE out of three insns found in SLOT.
4585 Returns true if we modified the insn chain, false otherwise. */
4587 gen_one_bundle (rtx slot
[3])
4589 gcc_assert (slot
[1] != NULL_RTX
);
4591 /* Don't add extra NOPs if optimizing for size. */
4593 && (slot
[0] == NULL_RTX
|| slot
[2] == NULL_RTX
))
4596 /* Verify that we really can do the multi-issue. */
4599 rtx t
= NEXT_INSN (slot
[0]);
4600 while (t
!= slot
[1])
4602 if (GET_CODE (t
) != NOTE
4603 || NOTE_KIND (t
) != NOTE_INSN_DELETED
)
4610 rtx t
= NEXT_INSN (slot
[1]);
4611 while (t
!= slot
[2])
4613 if (GET_CODE (t
) != NOTE
4614 || NOTE_KIND (t
) != NOTE_INSN_DELETED
)
4620 if (slot
[0] == NULL_RTX
)
4622 slot
[0] = emit_insn_before (gen_mnop (), slot
[1]);
4623 df_insn_rescan (slot
[0]);
4625 if (slot
[2] == NULL_RTX
)
4627 slot
[2] = emit_insn_after (gen_forced_nop (), slot
[1]);
4628 df_insn_rescan (slot
[2]);
4631 /* Avoid line number information being printed inside one bundle. */
4632 if (INSN_LOCATOR (slot
[1])
4633 && INSN_LOCATOR (slot
[1]) != INSN_LOCATOR (slot
[0]))
4634 INSN_LOCATOR (slot
[1]) = INSN_LOCATOR (slot
[0]);
4635 if (INSN_LOCATOR (slot
[2])
4636 && INSN_LOCATOR (slot
[2]) != INSN_LOCATOR (slot
[0]))
4637 INSN_LOCATOR (slot
[2]) = INSN_LOCATOR (slot
[0]);
4639 /* Terminate them with "|| " instead of ";" in the output. */
4640 PUT_MODE (slot
[0], SImode
);
4641 PUT_MODE (slot
[1], SImode
);
4642 /* Terminate the bundle, for the benefit of reorder_var_tracking_notes. */
4643 PUT_MODE (slot
[2], QImode
);
4647 /* Go through all insns, and use the information generated during scheduling
4648 to generate SEQUENCEs to represent bundles of instructions issued
4652 bfin_gen_bundles (void)
4661 slot
[0] = slot
[1] = slot
[2] = NULL_RTX
;
4662 for (insn
= BB_HEAD (bb
);; insn
= next
)
4667 if (get_attr_type (insn
) == TYPE_DSP32
)
4669 else if (slot
[1] == NULL_RTX
)
4676 next
= NEXT_INSN (insn
);
4677 while (next
&& insn
!= BB_END (bb
)
4679 && GET_CODE (PATTERN (next
)) != USE
4680 && GET_CODE (PATTERN (next
)) != CLOBBER
))
4683 next
= NEXT_INSN (insn
);
4686 /* BB_END can change due to emitting extra NOPs, so check here. */
4687 at_end
= insn
== BB_END (bb
);
4688 if (at_end
|| GET_MODE (next
) == TImode
)
4691 || !gen_one_bundle (slot
))
4692 && slot
[0] != NULL_RTX
)
4694 rtx pat
= PATTERN (slot
[0]);
4695 if (GET_CODE (pat
) == SET
4696 && GET_CODE (SET_SRC (pat
)) == UNSPEC
4697 && XINT (SET_SRC (pat
), 1) == UNSPEC_32BIT
)
4699 SET_SRC (pat
) = XVECEXP (SET_SRC (pat
), 0, 0);
4700 INSN_CODE (slot
[0]) = -1;
4701 df_insn_rescan (slot
[0]);
4705 slot
[0] = slot
[1] = slot
[2] = NULL_RTX
;
4713 /* Ensure that no var tracking notes are emitted in the middle of a
4714 three-instruction bundle. */
4717 reorder_var_tracking_notes (void)
4723 rtx queue
= NULL_RTX
;
4724 bool in_bundle
= false;
4726 for (insn
= BB_HEAD (bb
); insn
!= BB_END (bb
); insn
= next
)
4728 next
= NEXT_INSN (insn
);
4732 /* Emit queued up notes at the last instruction of a bundle. */
4733 if (GET_MODE (insn
) == QImode
)
4737 rtx next_queue
= PREV_INSN (queue
);
4738 PREV_INSN (NEXT_INSN (insn
)) = queue
;
4739 NEXT_INSN (queue
) = NEXT_INSN (insn
);
4740 NEXT_INSN (insn
) = queue
;
4741 PREV_INSN (queue
) = insn
;
4746 else if (GET_MODE (insn
) == SImode
)
4749 else if (NOTE_P (insn
) && NOTE_KIND (insn
) == NOTE_INSN_VAR_LOCATION
)
4753 rtx prev
= PREV_INSN (insn
);
4754 PREV_INSN (next
) = prev
;
4755 NEXT_INSN (prev
) = next
;
4757 PREV_INSN (insn
) = queue
;
4765 /* On some silicon revisions, functions shorter than a certain number of cycles
4766 can cause unpredictable behaviour. Work around this by adding NOPs as
4769 workaround_rts_anomaly (void)
4771 rtx insn
, first_insn
= NULL_RTX
;
4774 if (! ENABLE_WA_RETS
)
4777 for (insn
= get_insns (); insn
; insn
= NEXT_INSN (insn
))
4781 if (BARRIER_P (insn
))
4784 if (NOTE_P (insn
) || LABEL_P (insn
))
4787 if (first_insn
== NULL_RTX
)
4789 pat
= PATTERN (insn
);
4790 if (GET_CODE (pat
) == USE
|| GET_CODE (pat
) == CLOBBER
4791 || GET_CODE (pat
) == ASM_INPUT
|| GET_CODE (pat
) == ADDR_VEC
4792 || GET_CODE (pat
) == ADDR_DIFF_VEC
|| asm_noperands (pat
) >= 0)
4800 if (recog_memoized (insn
) == CODE_FOR_return_internal
)
4803 /* Nothing to worry about for direct jumps. */
4804 if (!any_condjump_p (insn
))
4810 else if (INSN_P (insn
))
4812 rtx pat
= PATTERN (insn
);
4813 int this_cycles
= 1;
4815 if (GET_CODE (pat
) == PARALLEL
)
4817 if (push_multiple_operation (pat
, VOIDmode
)
4818 || pop_multiple_operation (pat
, VOIDmode
))
4819 this_cycles
= n_regs_to_save
;
4823 enum insn_code icode
= recog_memoized (insn
);
4824 if (icode
== CODE_FOR_link
)
4826 else if (icode
== CODE_FOR_unlink
)
4828 else if (icode
== CODE_FOR_mulsi3
)
4831 if (this_cycles
>= cycles
)
4834 cycles
-= this_cycles
;
4839 emit_insn_before (gen_nop (), first_insn
);
4844 /* Return an insn type for INSN that can be used by the caller for anomaly
4845 workarounds. This differs from plain get_attr_type in that it handles
4848 static enum attr_type
4849 type_for_anomaly (rtx insn
)
4851 rtx pat
= PATTERN (insn
);
4852 if (GET_CODE (pat
) == SEQUENCE
)
4855 t
= get_attr_type (XVECEXP (pat
, 0, 1));
4858 t
= get_attr_type (XVECEXP (pat
, 0, 2));
4864 return get_attr_type (insn
);
4867 /* Return nonzero if INSN contains any loads that may trap. It handles
4868 SEQUENCEs correctly. */
4871 trapping_loads_p (rtx insn
)
4873 rtx pat
= PATTERN (insn
);
4874 if (GET_CODE (pat
) == SEQUENCE
)
4877 t
= get_attr_type (XVECEXP (pat
, 0, 1));
4879 && may_trap_p (SET_SRC (PATTERN (XVECEXP (pat
, 0, 1)))))
4881 t
= get_attr_type (XVECEXP (pat
, 0, 2));
4883 && may_trap_p (SET_SRC (PATTERN (XVECEXP (pat
, 0, 2)))))
4888 return may_trap_p (SET_SRC (single_set (insn
)));
4891 /* This function acts like NEXT_INSN, but is aware of three-insn bundles and
4892 skips all subsequent parallel instructions if INSN is the start of such
4895 find_next_insn_start (rtx insn
)
4897 if (GET_MODE (insn
) == SImode
)
4899 while (GET_MODE (insn
) != QImode
)
4900 insn
= NEXT_INSN (insn
);
4902 return NEXT_INSN (insn
);
4905 /* Return INSN if it is of TYPE_MCLD. Alternatively, if INSN is the start of
4906 a three-insn bundle, see if one of them is a load and return that if so.
4907 Return NULL_RTX if the insn does not contain loads. */
4909 find_load (rtx insn
)
4911 if (get_attr_type (insn
) == TYPE_MCLD
)
4913 if (GET_MODE (insn
) != SImode
)
4916 insn
= NEXT_INSN (insn
);
4917 if ((GET_MODE (insn
) == SImode
|| GET_MODE (insn
) == QImode
)
4918 && get_attr_type (insn
) == TYPE_MCLD
)
4920 } while (GET_MODE (insn
) != QImode
);
4924 /* Determine whether PAT is an indirect call pattern. */
4926 indirect_call_p (rtx pat
)
4928 if (GET_CODE (pat
) == PARALLEL
)
4929 pat
= XVECEXP (pat
, 0, 0);
4930 if (GET_CODE (pat
) == SET
)
4931 pat
= SET_SRC (pat
);
4932 gcc_assert (GET_CODE (pat
) == CALL
);
4933 pat
= XEXP (pat
, 0);
4934 gcc_assert (GET_CODE (pat
) == MEM
);
4935 pat
= XEXP (pat
, 0);
4941 workaround_speculation (void)
4944 rtx last_condjump
= NULL_RTX
;
4945 int cycles_since_jump
= INT_MAX
;
4946 int delay_added
= 0;
4948 if (! ENABLE_WA_SPECULATIVE_LOADS
&& ! ENABLE_WA_SPECULATIVE_SYNCS
4949 && ! ENABLE_WA_INDIRECT_CALLS
)
4952 /* First pass: find predicted-false branches; if something after them
4953 needs nops, insert them or change the branch to predict true. */
4954 for (insn
= get_insns (); insn
; insn
= next
)
4957 int delay_needed
= 0;
4959 next
= find_next_insn_start (insn
);
4961 if (NOTE_P (insn
) || BARRIER_P (insn
) || LABEL_P (insn
))
4964 pat
= PATTERN (insn
);
4965 if (GET_CODE (pat
) == USE
|| GET_CODE (pat
) == CLOBBER
4966 || GET_CODE (pat
) == ASM_INPUT
|| GET_CODE (pat
) == ADDR_VEC
4967 || GET_CODE (pat
) == ADDR_DIFF_VEC
|| asm_noperands (pat
) >= 0)
4972 if (any_condjump_p (insn
)
4973 && ! cbranch_predicted_taken_p (insn
))
4975 last_condjump
= insn
;
4977 cycles_since_jump
= 0;
4980 cycles_since_jump
= INT_MAX
;
4982 else if (CALL_P (insn
))
4984 if (cycles_since_jump
< INT_MAX
)
4985 cycles_since_jump
++;
4986 if (indirect_call_p (pat
) && ENABLE_WA_INDIRECT_CALLS
)
4991 else if (INSN_P (insn
))
4993 rtx load_insn
= find_load (insn
);
4994 enum attr_type type
= type_for_anomaly (insn
);
4996 if (cycles_since_jump
< INT_MAX
)
4997 cycles_since_jump
++;
4999 if (load_insn
&& ENABLE_WA_SPECULATIVE_LOADS
)
5001 if (trapping_loads_p (load_insn
))
5004 else if (type
== TYPE_SYNC
&& ENABLE_WA_SPECULATIVE_SYNCS
)
5008 if (delay_needed
> cycles_since_jump
5009 && (delay_needed
- cycles_since_jump
) > delay_added
)
5013 rtx
*op
= recog_data
.operand
;
5015 delay_needed
-= cycles_since_jump
;
5017 extract_insn (last_condjump
);
5020 pat1
= gen_cbranch_predicted_taken (op
[0], op
[1], op
[2],
5022 cycles_since_jump
= INT_MAX
;
5026 /* Do not adjust cycles_since_jump in this case, so that
5027 we'll increase the number of NOPs for a subsequent insn
5029 pat1
= gen_cbranch_with_nops (op
[0], op
[1], op
[2], op
[3],
5030 GEN_INT (delay_needed
));
5031 delay_added
= delay_needed
;
5033 PATTERN (last_condjump
) = pat1
;
5034 INSN_CODE (last_condjump
) = recog (pat1
, insn
, &num_clobbers
);
5038 cycles_since_jump
= INT_MAX
;
5043 /* Second pass: for predicted-true branches, see if anything at the
5044 branch destination needs extra nops. */
5045 for (insn
= get_insns (); insn
; insn
= NEXT_INSN (insn
))
5047 int cycles_since_jump
;
5049 && any_condjump_p (insn
)
5050 && (INSN_CODE (insn
) == CODE_FOR_cbranch_predicted_taken
5051 || cbranch_predicted_taken_p (insn
)))
5053 rtx target
= JUMP_LABEL (insn
);
5057 cycles_since_jump
= 0;
5058 for (; target
&& cycles_since_jump
< 3; target
= next_tgt
)
5062 next_tgt
= find_next_insn_start (target
);
5064 if (NOTE_P (target
) || BARRIER_P (target
) || LABEL_P (target
))
5067 pat
= PATTERN (target
);
5068 if (GET_CODE (pat
) == USE
|| GET_CODE (pat
) == CLOBBER
5069 || GET_CODE (pat
) == ASM_INPUT
|| GET_CODE (pat
) == ADDR_VEC
5070 || GET_CODE (pat
) == ADDR_DIFF_VEC
|| asm_noperands (pat
) >= 0)
5073 if (INSN_P (target
))
5075 rtx load_insn
= find_load (target
);
5076 enum attr_type type
= type_for_anomaly (target
);
5077 int delay_needed
= 0;
5078 if (cycles_since_jump
< INT_MAX
)
5079 cycles_since_jump
++;
5081 if (load_insn
&& ENABLE_WA_SPECULATIVE_LOADS
)
5083 if (trapping_loads_p (load_insn
))
5086 else if (type
== TYPE_SYNC
&& ENABLE_WA_SPECULATIVE_SYNCS
)
5089 if (delay_needed
> cycles_since_jump
)
5091 rtx prev
= prev_real_insn (label
);
5092 delay_needed
-= cycles_since_jump
;
5094 fprintf (dump_file
, "Adding %d nops after %d\n",
5095 delay_needed
, INSN_UID (label
));
5097 && INSN_CODE (prev
) == CODE_FOR_cbranch_with_nops
)
5104 "Reducing nops on insn %d.\n",
5107 x
= XVECEXP (x
, 0, 1);
5108 v
= INTVAL (XVECEXP (x
, 0, 0)) - delay_needed
;
5109 XVECEXP (x
, 0, 0) = GEN_INT (v
);
5111 while (delay_needed
-- > 0)
5112 emit_insn_after (gen_nop (), label
);
5121 /* We use the machine specific reorg pass for emitting CSYNC instructions
5122 after conditional branches as needed.
5124 The Blackfin is unusual in that a code sequence like
5127 may speculatively perform the load even if the condition isn't true. This
5128 happens for a branch that is predicted not taken, because the pipeline
5129 isn't flushed or stalled, so the early stages of the following instructions,
5130 which perform the memory reference, are allowed to execute before the
5131 jump condition is evaluated.
5132 Therefore, we must insert additional instructions in all places where this
5133 could lead to incorrect behavior. The manual recommends CSYNC, while
5134 VDSP seems to use NOPs (even though its corresponding compiler option is
5137 When optimizing for speed, we emit NOPs, which seems faster than a CSYNC.
5138 When optimizing for size, we turn the branch into a predicted taken one.
5139 This may be slower due to mispredicts, but saves code size. */
5144 /* We are freeing block_for_insn in the toplev to keep compatibility
5145 with old MDEP_REORGS that are not CFG based. Recompute it now. */
5146 compute_bb_for_insn ();
5148 if (bfin_flag_schedule_insns2
)
5150 splitting_for_sched
= 1;
5152 splitting_for_sched
= 0;
5154 timevar_push (TV_SCHED2
);
5156 timevar_pop (TV_SCHED2
);
5158 /* Examine the schedule and insert nops as necessary for 64-bit parallel
5160 bfin_gen_bundles ();
5165 /* Doloop optimization */
5166 if (cfun
->machine
->has_hardware_loops
)
5167 bfin_reorg_loops (dump_file
);
5169 workaround_speculation ();
5171 if (bfin_flag_var_tracking
)
5173 timevar_push (TV_VAR_TRACKING
);
5174 variable_tracking_main ();
5175 reorder_var_tracking_notes ();
5176 timevar_pop (TV_VAR_TRACKING
);
5179 df_finish_pass (false);
5181 workaround_rts_anomaly ();
5184 /* Handle interrupt_handler, exception_handler and nmi_handler function
5185 attributes; arguments as in struct attribute_spec.handler. */
5188 handle_int_attribute (tree
*node
, tree name
,
5189 tree args ATTRIBUTE_UNUSED
,
5190 int flags ATTRIBUTE_UNUSED
,
5194 if (TREE_CODE (x
) == FUNCTION_DECL
)
5197 if (TREE_CODE (x
) != FUNCTION_TYPE
)
5199 warning (OPT_Wattributes
, "%qs attribute only applies to functions",
5200 IDENTIFIER_POINTER (name
));
5201 *no_add_attrs
= true;
5203 else if (funkind (x
) != SUBROUTINE
)
5204 error ("multiple function type attributes specified");
5209 /* Return 0 if the attributes for two types are incompatible, 1 if they
5210 are compatible, and 2 if they are nearly compatible (which causes a
5211 warning to be generated). */
5214 bfin_comp_type_attributes (const_tree type1
, const_tree type2
)
5216 e_funkind kind1
, kind2
;
5218 if (TREE_CODE (type1
) != FUNCTION_TYPE
)
5221 kind1
= funkind (type1
);
5222 kind2
= funkind (type2
);
5227 /* Check for mismatched modifiers */
5228 if (!lookup_attribute ("nesting", TYPE_ATTRIBUTES (type1
))
5229 != !lookup_attribute ("nesting", TYPE_ATTRIBUTES (type2
)))
5232 if (!lookup_attribute ("saveall", TYPE_ATTRIBUTES (type1
))
5233 != !lookup_attribute ("saveall", TYPE_ATTRIBUTES (type2
)))
5236 if (!lookup_attribute ("kspisusp", TYPE_ATTRIBUTES (type1
))
5237 != !lookup_attribute ("kspisusp", TYPE_ATTRIBUTES (type2
)))
5240 if (!lookup_attribute ("longcall", TYPE_ATTRIBUTES (type1
))
5241 != !lookup_attribute ("longcall", TYPE_ATTRIBUTES (type2
)))
5247 /* Handle a "longcall" or "shortcall" attribute; arguments as in
5248 struct attribute_spec.handler. */
5251 bfin_handle_longcall_attribute (tree
*node
, tree name
,
5252 tree args ATTRIBUTE_UNUSED
,
5253 int flags ATTRIBUTE_UNUSED
,
5256 if (TREE_CODE (*node
) != FUNCTION_TYPE
5257 && TREE_CODE (*node
) != FIELD_DECL
5258 && TREE_CODE (*node
) != TYPE_DECL
)
5260 warning (OPT_Wattributes
, "`%s' attribute only applies to functions",
5261 IDENTIFIER_POINTER (name
));
5262 *no_add_attrs
= true;
5265 if ((strcmp (IDENTIFIER_POINTER (name
), "longcall") == 0
5266 && lookup_attribute ("shortcall", TYPE_ATTRIBUTES (*node
)))
5267 || (strcmp (IDENTIFIER_POINTER (name
), "shortcall") == 0
5268 && lookup_attribute ("longcall", TYPE_ATTRIBUTES (*node
))))
5270 warning (OPT_Wattributes
,
5271 "can't apply both longcall and shortcall attributes to the same function");
5272 *no_add_attrs
= true;
5278 /* Handle a "l1_text" attribute; arguments as in
5279 struct attribute_spec.handler. */
5282 bfin_handle_l1_text_attribute (tree
*node
, tree name
, tree
ARG_UNUSED (args
),
5283 int ARG_UNUSED (flags
), bool *no_add_attrs
)
5287 if (TREE_CODE (decl
) != FUNCTION_DECL
)
5289 error ("`%s' attribute only applies to functions",
5290 IDENTIFIER_POINTER (name
));
5291 *no_add_attrs
= true;
5294 /* The decl may have already been given a section attribute
5295 from a previous declaration. Ensure they match. */
5296 else if (DECL_SECTION_NAME (decl
) != NULL_TREE
5297 && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl
)),
5300 error ("section of %q+D conflicts with previous declaration",
5302 *no_add_attrs
= true;
5305 DECL_SECTION_NAME (decl
) = build_string (9, ".l1.text");
5310 /* Handle a "l1_data", "l1_data_A" or "l1_data_B" attribute;
5311 arguments as in struct attribute_spec.handler. */
5314 bfin_handle_l1_data_attribute (tree
*node
, tree name
, tree
ARG_UNUSED (args
),
5315 int ARG_UNUSED (flags
), bool *no_add_attrs
)
5319 if (TREE_CODE (decl
) != VAR_DECL
)
5321 error ("`%s' attribute only applies to variables",
5322 IDENTIFIER_POINTER (name
));
5323 *no_add_attrs
= true;
5325 else if (current_function_decl
!= NULL_TREE
5326 && !TREE_STATIC (decl
))
5328 error ("`%s' attribute cannot be specified for local variables",
5329 IDENTIFIER_POINTER (name
));
5330 *no_add_attrs
= true;
5334 const char *section_name
;
5336 if (strcmp (IDENTIFIER_POINTER (name
), "l1_data") == 0)
5337 section_name
= ".l1.data";
5338 else if (strcmp (IDENTIFIER_POINTER (name
), "l1_data_A") == 0)
5339 section_name
= ".l1.data.A";
5340 else if (strcmp (IDENTIFIER_POINTER (name
), "l1_data_B") == 0)
5341 section_name
= ".l1.data.B";
5345 /* The decl may have already been given a section attribute
5346 from a previous declaration. Ensure they match. */
5347 if (DECL_SECTION_NAME (decl
) != NULL_TREE
5348 && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl
)),
5351 error ("section of %q+D conflicts with previous declaration",
5353 *no_add_attrs
= true;
5356 DECL_SECTION_NAME (decl
)
5357 = build_string (strlen (section_name
) + 1, section_name
);
5363 /* Table of valid machine attributes. */
5364 const struct attribute_spec bfin_attribute_table
[] =
5366 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
5367 { "interrupt_handler", 0, 0, false, true, true, handle_int_attribute
},
5368 { "exception_handler", 0, 0, false, true, true, handle_int_attribute
},
5369 { "nmi_handler", 0, 0, false, true, true, handle_int_attribute
},
5370 { "nesting", 0, 0, false, true, true, NULL
},
5371 { "kspisusp", 0, 0, false, true, true, NULL
},
5372 { "saveall", 0, 0, false, true, true, NULL
},
5373 { "longcall", 0, 0, false, true, true, bfin_handle_longcall_attribute
},
5374 { "shortcall", 0, 0, false, true, true, bfin_handle_longcall_attribute
},
5375 { "l1_text", 0, 0, true, false, false, bfin_handle_l1_text_attribute
},
5376 { "l1_data", 0, 0, true, false, false, bfin_handle_l1_data_attribute
},
5377 { "l1_data_A", 0, 0, true, false, false, bfin_handle_l1_data_attribute
},
5378 { "l1_data_B", 0, 0, true, false, false, bfin_handle_l1_data_attribute
},
5379 { NULL
, 0, 0, false, false, false, NULL
}
5382 /* Implementation of TARGET_ASM_INTEGER. When using FD-PIC, we need to
5383 tell the assembler to generate pointers to function descriptors in
5387 bfin_assemble_integer (rtx value
, unsigned int size
, int aligned_p
)
5389 if (TARGET_FDPIC
&& size
== UNITS_PER_WORD
)
5391 if (GET_CODE (value
) == SYMBOL_REF
5392 && SYMBOL_REF_FUNCTION_P (value
))
5394 fputs ("\t.picptr\tfuncdesc(", asm_out_file
);
5395 output_addr_const (asm_out_file
, value
);
5396 fputs (")\n", asm_out_file
);
5401 /* We've set the unaligned SI op to NULL, so we always have to
5402 handle the unaligned case here. */
5403 assemble_integer_with_op ("\t.4byte\t", value
);
5407 return default_assemble_integer (value
, size
, aligned_p
);
5410 /* Output the assembler code for a thunk function. THUNK_DECL is the
5411 declaration for the thunk function itself, FUNCTION is the decl for
5412 the target function. DELTA is an immediate constant offset to be
5413 added to THIS. If VCALL_OFFSET is nonzero, the word at
5414 *(*this + vcall_offset) should be added to THIS. */
5417 bfin_output_mi_thunk (FILE *file ATTRIBUTE_UNUSED
,
5418 tree thunk ATTRIBUTE_UNUSED
, HOST_WIDE_INT delta
,
5419 HOST_WIDE_INT vcall_offset
, tree function
)
5422 /* The this parameter is passed as the first argument. */
5423 rtx this_rtx
= gen_rtx_REG (Pmode
, REG_R0
);
5425 /* Adjust the this parameter by a fixed constant. */
5429 if (delta
>= -64 && delta
<= 63)
5431 xops
[0] = GEN_INT (delta
);
5432 output_asm_insn ("%1 += %0;", xops
);
5434 else if (delta
>= -128 && delta
< -64)
5436 xops
[0] = GEN_INT (delta
+ 64);
5437 output_asm_insn ("%1 += -64; %1 += %0;", xops
);
5439 else if (delta
> 63 && delta
<= 126)
5441 xops
[0] = GEN_INT (delta
- 63);
5442 output_asm_insn ("%1 += 63; %1 += %0;", xops
);
5446 xops
[0] = GEN_INT (delta
);
5447 output_asm_insn ("r3.l = %h0; r3.h = %d0; %1 = %1 + r3;", xops
);
5451 /* Adjust the this parameter by a value stored in the vtable. */
5454 rtx p2tmp
= gen_rtx_REG (Pmode
, REG_P2
);
5455 rtx tmp
= gen_rtx_REG (Pmode
, REG_R3
);
5459 output_asm_insn ("%2 = r0; %2 = [%2];", xops
);
5461 /* Adjust the this parameter. */
5462 xops
[0] = gen_rtx_MEM (Pmode
, plus_constant (p2tmp
, vcall_offset
));
5463 if (!memory_operand (xops
[0], Pmode
))
5465 rtx tmp2
= gen_rtx_REG (Pmode
, REG_P1
);
5466 xops
[0] = GEN_INT (vcall_offset
);
5468 output_asm_insn ("%h1 = %h0; %d1 = %d0; %2 = %2 + %1", xops
);
5469 xops
[0] = gen_rtx_MEM (Pmode
, p2tmp
);
5472 output_asm_insn ("%1 = %0; %2 = %2 + %1;", xops
);
5475 xops
[0] = XEXP (DECL_RTL (function
), 0);
5476 if (1 || !flag_pic
|| (*targetm
.binds_local_p
) (function
))
5477 output_asm_insn ("jump.l\t%P0", xops
);
5480 /* Codes for all the Blackfin builtins. */
5486 BFIN_BUILTIN_COMPOSE_2X16
,
5487 BFIN_BUILTIN_EXTRACTLO
,
5488 BFIN_BUILTIN_EXTRACTHI
,
5490 BFIN_BUILTIN_SSADD_2X16
,
5491 BFIN_BUILTIN_SSSUB_2X16
,
5492 BFIN_BUILTIN_SSADDSUB_2X16
,
5493 BFIN_BUILTIN_SSSUBADD_2X16
,
5494 BFIN_BUILTIN_MULT_2X16
,
5495 BFIN_BUILTIN_MULTR_2X16
,
5496 BFIN_BUILTIN_NEG_2X16
,
5497 BFIN_BUILTIN_ABS_2X16
,
5498 BFIN_BUILTIN_MIN_2X16
,
5499 BFIN_BUILTIN_MAX_2X16
,
5501 BFIN_BUILTIN_SSADD_1X16
,
5502 BFIN_BUILTIN_SSSUB_1X16
,
5503 BFIN_BUILTIN_MULT_1X16
,
5504 BFIN_BUILTIN_MULTR_1X16
,
5505 BFIN_BUILTIN_NORM_1X16
,
5506 BFIN_BUILTIN_NEG_1X16
,
5507 BFIN_BUILTIN_ABS_1X16
,
5508 BFIN_BUILTIN_MIN_1X16
,
5509 BFIN_BUILTIN_MAX_1X16
,
5511 BFIN_BUILTIN_SUM_2X16
,
5512 BFIN_BUILTIN_DIFFHL_2X16
,
5513 BFIN_BUILTIN_DIFFLH_2X16
,
5515 BFIN_BUILTIN_SSADD_1X32
,
5516 BFIN_BUILTIN_SSSUB_1X32
,
5517 BFIN_BUILTIN_NORM_1X32
,
5518 BFIN_BUILTIN_ROUND_1X32
,
5519 BFIN_BUILTIN_NEG_1X32
,
5520 BFIN_BUILTIN_ABS_1X32
,
5521 BFIN_BUILTIN_MIN_1X32
,
5522 BFIN_BUILTIN_MAX_1X32
,
5523 BFIN_BUILTIN_MULT_1X32
,
5524 BFIN_BUILTIN_MULT_1X32X32
,
5525 BFIN_BUILTIN_MULT_1X32X32NS
,
5527 BFIN_BUILTIN_MULHISILL
,
5528 BFIN_BUILTIN_MULHISILH
,
5529 BFIN_BUILTIN_MULHISIHL
,
5530 BFIN_BUILTIN_MULHISIHH
,
5532 BFIN_BUILTIN_LSHIFT_1X16
,
5533 BFIN_BUILTIN_LSHIFT_2X16
,
5534 BFIN_BUILTIN_SSASHIFT_1X16
,
5535 BFIN_BUILTIN_SSASHIFT_2X16
,
5536 BFIN_BUILTIN_SSASHIFT_1X32
,
5538 BFIN_BUILTIN_CPLX_MUL_16
,
5539 BFIN_BUILTIN_CPLX_MAC_16
,
5540 BFIN_BUILTIN_CPLX_MSU_16
,
5542 BFIN_BUILTIN_CPLX_MUL_16_S40
,
5543 BFIN_BUILTIN_CPLX_MAC_16_S40
,
5544 BFIN_BUILTIN_CPLX_MSU_16_S40
,
5546 BFIN_BUILTIN_CPLX_SQU
,
5548 BFIN_BUILTIN_LOADBYTES
,
5553 #define def_builtin(NAME, TYPE, CODE) \
5555 add_builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD, \
5559 /* Set up all builtin functions for this target. */
5561 bfin_init_builtins (void)
5563 tree V2HI_type_node
= build_vector_type_for_mode (intHI_type_node
, V2HImode
);
5564 tree void_ftype_void
5565 = build_function_type (void_type_node
, void_list_node
);
5566 tree short_ftype_short
5567 = build_function_type_list (short_integer_type_node
, short_integer_type_node
,
5569 tree short_ftype_int_int
5570 = build_function_type_list (short_integer_type_node
, integer_type_node
,
5571 integer_type_node
, NULL_TREE
);
5572 tree int_ftype_int_int
5573 = build_function_type_list (integer_type_node
, integer_type_node
,
5574 integer_type_node
, NULL_TREE
);
5576 = build_function_type_list (integer_type_node
, integer_type_node
,
5578 tree short_ftype_int
5579 = build_function_type_list (short_integer_type_node
, integer_type_node
,
5581 tree int_ftype_v2hi_v2hi
5582 = build_function_type_list (integer_type_node
, V2HI_type_node
,
5583 V2HI_type_node
, NULL_TREE
);
5584 tree v2hi_ftype_v2hi_v2hi
5585 = build_function_type_list (V2HI_type_node
, V2HI_type_node
,
5586 V2HI_type_node
, NULL_TREE
);
5587 tree v2hi_ftype_v2hi_v2hi_v2hi
5588 = build_function_type_list (V2HI_type_node
, V2HI_type_node
,
5589 V2HI_type_node
, V2HI_type_node
, NULL_TREE
);
5590 tree v2hi_ftype_int_int
5591 = build_function_type_list (V2HI_type_node
, integer_type_node
,
5592 integer_type_node
, NULL_TREE
);
5593 tree v2hi_ftype_v2hi_int
5594 = build_function_type_list (V2HI_type_node
, V2HI_type_node
,
5595 integer_type_node
, NULL_TREE
);
5596 tree int_ftype_short_short
5597 = build_function_type_list (integer_type_node
, short_integer_type_node
,
5598 short_integer_type_node
, NULL_TREE
);
5599 tree v2hi_ftype_v2hi
5600 = build_function_type_list (V2HI_type_node
, V2HI_type_node
, NULL_TREE
);
5601 tree short_ftype_v2hi
5602 = build_function_type_list (short_integer_type_node
, V2HI_type_node
,
5605 = build_function_type_list (integer_type_node
,
5606 build_pointer_type (integer_type_node
),
5609 /* Add the remaining MMX insns with somewhat more complicated types. */
5610 def_builtin ("__builtin_bfin_csync", void_ftype_void
, BFIN_BUILTIN_CSYNC
);
5611 def_builtin ("__builtin_bfin_ssync", void_ftype_void
, BFIN_BUILTIN_SSYNC
);
5613 def_builtin ("__builtin_bfin_ones", short_ftype_int
, BFIN_BUILTIN_ONES
);
5615 def_builtin ("__builtin_bfin_compose_2x16", v2hi_ftype_int_int
,
5616 BFIN_BUILTIN_COMPOSE_2X16
);
5617 def_builtin ("__builtin_bfin_extract_hi", short_ftype_v2hi
,
5618 BFIN_BUILTIN_EXTRACTHI
);
5619 def_builtin ("__builtin_bfin_extract_lo", short_ftype_v2hi
,
5620 BFIN_BUILTIN_EXTRACTLO
);
5622 def_builtin ("__builtin_bfin_min_fr2x16", v2hi_ftype_v2hi_v2hi
,
5623 BFIN_BUILTIN_MIN_2X16
);
5624 def_builtin ("__builtin_bfin_max_fr2x16", v2hi_ftype_v2hi_v2hi
,
5625 BFIN_BUILTIN_MAX_2X16
);
5627 def_builtin ("__builtin_bfin_add_fr2x16", v2hi_ftype_v2hi_v2hi
,
5628 BFIN_BUILTIN_SSADD_2X16
);
5629 def_builtin ("__builtin_bfin_sub_fr2x16", v2hi_ftype_v2hi_v2hi
,
5630 BFIN_BUILTIN_SSSUB_2X16
);
5631 def_builtin ("__builtin_bfin_dspaddsubsat", v2hi_ftype_v2hi_v2hi
,
5632 BFIN_BUILTIN_SSADDSUB_2X16
);
5633 def_builtin ("__builtin_bfin_dspsubaddsat", v2hi_ftype_v2hi_v2hi
,
5634 BFIN_BUILTIN_SSSUBADD_2X16
);
5635 def_builtin ("__builtin_bfin_mult_fr2x16", v2hi_ftype_v2hi_v2hi
,
5636 BFIN_BUILTIN_MULT_2X16
);
5637 def_builtin ("__builtin_bfin_multr_fr2x16", v2hi_ftype_v2hi_v2hi
,
5638 BFIN_BUILTIN_MULTR_2X16
);
5639 def_builtin ("__builtin_bfin_negate_fr2x16", v2hi_ftype_v2hi
,
5640 BFIN_BUILTIN_NEG_2X16
);
5641 def_builtin ("__builtin_bfin_abs_fr2x16", v2hi_ftype_v2hi
,
5642 BFIN_BUILTIN_ABS_2X16
);
5644 def_builtin ("__builtin_bfin_min_fr1x16", short_ftype_int_int
,
5645 BFIN_BUILTIN_MIN_1X16
);
5646 def_builtin ("__builtin_bfin_max_fr1x16", short_ftype_int_int
,
5647 BFIN_BUILTIN_MAX_1X16
);
5649 def_builtin ("__builtin_bfin_add_fr1x16", short_ftype_int_int
,
5650 BFIN_BUILTIN_SSADD_1X16
);
5651 def_builtin ("__builtin_bfin_sub_fr1x16", short_ftype_int_int
,
5652 BFIN_BUILTIN_SSSUB_1X16
);
5653 def_builtin ("__builtin_bfin_mult_fr1x16", short_ftype_int_int
,
5654 BFIN_BUILTIN_MULT_1X16
);
5655 def_builtin ("__builtin_bfin_multr_fr1x16", short_ftype_int_int
,
5656 BFIN_BUILTIN_MULTR_1X16
);
5657 def_builtin ("__builtin_bfin_negate_fr1x16", short_ftype_short
,
5658 BFIN_BUILTIN_NEG_1X16
);
5659 def_builtin ("__builtin_bfin_abs_fr1x16", short_ftype_short
,
5660 BFIN_BUILTIN_ABS_1X16
);
5661 def_builtin ("__builtin_bfin_norm_fr1x16", short_ftype_int
,
5662 BFIN_BUILTIN_NORM_1X16
);
5664 def_builtin ("__builtin_bfin_sum_fr2x16", short_ftype_v2hi
,
5665 BFIN_BUILTIN_SUM_2X16
);
5666 def_builtin ("__builtin_bfin_diff_hl_fr2x16", short_ftype_v2hi
,
5667 BFIN_BUILTIN_DIFFHL_2X16
);
5668 def_builtin ("__builtin_bfin_diff_lh_fr2x16", short_ftype_v2hi
,
5669 BFIN_BUILTIN_DIFFLH_2X16
);
5671 def_builtin ("__builtin_bfin_mulhisill", int_ftype_v2hi_v2hi
,
5672 BFIN_BUILTIN_MULHISILL
);
5673 def_builtin ("__builtin_bfin_mulhisihl", int_ftype_v2hi_v2hi
,
5674 BFIN_BUILTIN_MULHISIHL
);
5675 def_builtin ("__builtin_bfin_mulhisilh", int_ftype_v2hi_v2hi
,
5676 BFIN_BUILTIN_MULHISILH
);
5677 def_builtin ("__builtin_bfin_mulhisihh", int_ftype_v2hi_v2hi
,
5678 BFIN_BUILTIN_MULHISIHH
);
5680 def_builtin ("__builtin_bfin_min_fr1x32", int_ftype_int_int
,
5681 BFIN_BUILTIN_MIN_1X32
);
5682 def_builtin ("__builtin_bfin_max_fr1x32", int_ftype_int_int
,
5683 BFIN_BUILTIN_MAX_1X32
);
5685 def_builtin ("__builtin_bfin_add_fr1x32", int_ftype_int_int
,
5686 BFIN_BUILTIN_SSADD_1X32
);
5687 def_builtin ("__builtin_bfin_sub_fr1x32", int_ftype_int_int
,
5688 BFIN_BUILTIN_SSSUB_1X32
);
5689 def_builtin ("__builtin_bfin_negate_fr1x32", int_ftype_int
,
5690 BFIN_BUILTIN_NEG_1X32
);
5691 def_builtin ("__builtin_bfin_abs_fr1x32", int_ftype_int
,
5692 BFIN_BUILTIN_ABS_1X32
);
5693 def_builtin ("__builtin_bfin_norm_fr1x32", short_ftype_int
,
5694 BFIN_BUILTIN_NORM_1X32
);
5695 def_builtin ("__builtin_bfin_round_fr1x32", short_ftype_int
,
5696 BFIN_BUILTIN_ROUND_1X32
);
5697 def_builtin ("__builtin_bfin_mult_fr1x32", int_ftype_short_short
,
5698 BFIN_BUILTIN_MULT_1X32
);
5699 def_builtin ("__builtin_bfin_mult_fr1x32x32", int_ftype_int_int
,
5700 BFIN_BUILTIN_MULT_1X32X32
);
5701 def_builtin ("__builtin_bfin_mult_fr1x32x32NS", int_ftype_int_int
,
5702 BFIN_BUILTIN_MULT_1X32X32NS
);
5705 def_builtin ("__builtin_bfin_shl_fr1x16", short_ftype_int_int
,
5706 BFIN_BUILTIN_SSASHIFT_1X16
);
5707 def_builtin ("__builtin_bfin_shl_fr2x16", v2hi_ftype_v2hi_int
,
5708 BFIN_BUILTIN_SSASHIFT_2X16
);
5709 def_builtin ("__builtin_bfin_lshl_fr1x16", short_ftype_int_int
,
5710 BFIN_BUILTIN_LSHIFT_1X16
);
5711 def_builtin ("__builtin_bfin_lshl_fr2x16", v2hi_ftype_v2hi_int
,
5712 BFIN_BUILTIN_LSHIFT_2X16
);
5713 def_builtin ("__builtin_bfin_shl_fr1x32", int_ftype_int_int
,
5714 BFIN_BUILTIN_SSASHIFT_1X32
);
5716 /* Complex numbers. */
5717 def_builtin ("__builtin_bfin_cmplx_add", v2hi_ftype_v2hi_v2hi
,
5718 BFIN_BUILTIN_SSADD_2X16
);
5719 def_builtin ("__builtin_bfin_cmplx_sub", v2hi_ftype_v2hi_v2hi
,
5720 BFIN_BUILTIN_SSSUB_2X16
);
5721 def_builtin ("__builtin_bfin_cmplx_mul", v2hi_ftype_v2hi_v2hi
,
5722 BFIN_BUILTIN_CPLX_MUL_16
);
5723 def_builtin ("__builtin_bfin_cmplx_mac", v2hi_ftype_v2hi_v2hi_v2hi
,
5724 BFIN_BUILTIN_CPLX_MAC_16
);
5725 def_builtin ("__builtin_bfin_cmplx_msu", v2hi_ftype_v2hi_v2hi_v2hi
,
5726 BFIN_BUILTIN_CPLX_MSU_16
);
5727 def_builtin ("__builtin_bfin_cmplx_mul_s40", v2hi_ftype_v2hi_v2hi
,
5728 BFIN_BUILTIN_CPLX_MUL_16_S40
);
5729 def_builtin ("__builtin_bfin_cmplx_mac_s40", v2hi_ftype_v2hi_v2hi_v2hi
,
5730 BFIN_BUILTIN_CPLX_MAC_16_S40
);
5731 def_builtin ("__builtin_bfin_cmplx_msu_s40", v2hi_ftype_v2hi_v2hi_v2hi
,
5732 BFIN_BUILTIN_CPLX_MSU_16_S40
);
5733 def_builtin ("__builtin_bfin_csqu_fr16", v2hi_ftype_v2hi
,
5734 BFIN_BUILTIN_CPLX_SQU
);
5736 /* "Unaligned" load. */
5737 def_builtin ("__builtin_bfin_loadbytes", int_ftype_pint
,
5738 BFIN_BUILTIN_LOADBYTES
);
5743 struct builtin_description
5745 const enum insn_code icode
;
5746 const char *const name
;
5747 const enum bfin_builtins code
;
5751 static const struct builtin_description bdesc_2arg
[] =
5753 { CODE_FOR_composev2hi
, "__builtin_bfin_compose_2x16", BFIN_BUILTIN_COMPOSE_2X16
, -1 },
5755 { CODE_FOR_ssashiftv2hi3
, "__builtin_bfin_shl_fr2x16", BFIN_BUILTIN_SSASHIFT_2X16
, -1 },
5756 { CODE_FOR_ssashifthi3
, "__builtin_bfin_shl_fr1x16", BFIN_BUILTIN_SSASHIFT_1X16
, -1 },
5757 { CODE_FOR_lshiftv2hi3
, "__builtin_bfin_lshl_fr2x16", BFIN_BUILTIN_LSHIFT_2X16
, -1 },
5758 { CODE_FOR_lshifthi3
, "__builtin_bfin_lshl_fr1x16", BFIN_BUILTIN_LSHIFT_1X16
, -1 },
5759 { CODE_FOR_ssashiftsi3
, "__builtin_bfin_shl_fr1x32", BFIN_BUILTIN_SSASHIFT_1X32
, -1 },
5761 { CODE_FOR_sminhi3
, "__builtin_bfin_min_fr1x16", BFIN_BUILTIN_MIN_1X16
, -1 },
5762 { CODE_FOR_smaxhi3
, "__builtin_bfin_max_fr1x16", BFIN_BUILTIN_MAX_1X16
, -1 },
5763 { CODE_FOR_ssaddhi3
, "__builtin_bfin_add_fr1x16", BFIN_BUILTIN_SSADD_1X16
, -1 },
5764 { CODE_FOR_sssubhi3
, "__builtin_bfin_sub_fr1x16", BFIN_BUILTIN_SSSUB_1X16
, -1 },
5766 { CODE_FOR_sminsi3
, "__builtin_bfin_min_fr1x32", BFIN_BUILTIN_MIN_1X32
, -1 },
5767 { CODE_FOR_smaxsi3
, "__builtin_bfin_max_fr1x32", BFIN_BUILTIN_MAX_1X32
, -1 },
5768 { CODE_FOR_ssaddsi3
, "__builtin_bfin_add_fr1x32", BFIN_BUILTIN_SSADD_1X32
, -1 },
5769 { CODE_FOR_sssubsi3
, "__builtin_bfin_sub_fr1x32", BFIN_BUILTIN_SSSUB_1X32
, -1 },
5771 { CODE_FOR_sminv2hi3
, "__builtin_bfin_min_fr2x16", BFIN_BUILTIN_MIN_2X16
, -1 },
5772 { CODE_FOR_smaxv2hi3
, "__builtin_bfin_max_fr2x16", BFIN_BUILTIN_MAX_2X16
, -1 },
5773 { CODE_FOR_ssaddv2hi3
, "__builtin_bfin_add_fr2x16", BFIN_BUILTIN_SSADD_2X16
, -1 },
5774 { CODE_FOR_sssubv2hi3
, "__builtin_bfin_sub_fr2x16", BFIN_BUILTIN_SSSUB_2X16
, -1 },
5775 { CODE_FOR_ssaddsubv2hi3
, "__builtin_bfin_dspaddsubsat", BFIN_BUILTIN_SSADDSUB_2X16
, -1 },
5776 { CODE_FOR_sssubaddv2hi3
, "__builtin_bfin_dspsubaddsat", BFIN_BUILTIN_SSSUBADD_2X16
, -1 },
5778 { CODE_FOR_flag_mulhisi
, "__builtin_bfin_mult_fr1x32", BFIN_BUILTIN_MULT_1X32
, MACFLAG_NONE
},
5779 { CODE_FOR_flag_mulhi
, "__builtin_bfin_mult_fr1x16", BFIN_BUILTIN_MULT_1X16
, MACFLAG_T
},
5780 { CODE_FOR_flag_mulhi
, "__builtin_bfin_multr_fr1x16", BFIN_BUILTIN_MULTR_1X16
, MACFLAG_NONE
},
5781 { CODE_FOR_flag_mulv2hi
, "__builtin_bfin_mult_fr2x16", BFIN_BUILTIN_MULT_2X16
, MACFLAG_T
},
5782 { CODE_FOR_flag_mulv2hi
, "__builtin_bfin_multr_fr2x16", BFIN_BUILTIN_MULTR_2X16
, MACFLAG_NONE
},
5784 { CODE_FOR_mulhisi_ll
, "__builtin_bfin_mulhisill", BFIN_BUILTIN_MULHISILL
, -1 },
5785 { CODE_FOR_mulhisi_lh
, "__builtin_bfin_mulhisilh", BFIN_BUILTIN_MULHISILH
, -1 },
5786 { CODE_FOR_mulhisi_hl
, "__builtin_bfin_mulhisihl", BFIN_BUILTIN_MULHISIHL
, -1 },
5787 { CODE_FOR_mulhisi_hh
, "__builtin_bfin_mulhisihh", BFIN_BUILTIN_MULHISIHH
, -1 }
5791 static const struct builtin_description bdesc_1arg
[] =
5793 { CODE_FOR_loadbytes
, "__builtin_bfin_loadbytes", BFIN_BUILTIN_LOADBYTES
, 0 },
5795 { CODE_FOR_ones
, "__builtin_bfin_ones", BFIN_BUILTIN_ONES
, 0 },
5797 { CODE_FOR_signbitshi2
, "__builtin_bfin_norm_fr1x16", BFIN_BUILTIN_NORM_1X16
, 0 },
5798 { CODE_FOR_ssneghi2
, "__builtin_bfin_negate_fr1x16", BFIN_BUILTIN_NEG_1X16
, 0 },
5799 { CODE_FOR_abshi2
, "__builtin_bfin_abs_fr1x16", BFIN_BUILTIN_ABS_1X16
, 0 },
5801 { CODE_FOR_signbitssi2
, "__builtin_bfin_norm_fr1x32", BFIN_BUILTIN_NORM_1X32
, 0 },
5802 { CODE_FOR_ssroundsi2
, "__builtin_bfin_round_fr1x32", BFIN_BUILTIN_ROUND_1X32
, 0 },
5803 { CODE_FOR_ssnegsi2
, "__builtin_bfin_negate_fr1x32", BFIN_BUILTIN_NEG_1X32
, 0 },
5804 { CODE_FOR_ssabssi2
, "__builtin_bfin_abs_fr1x32", BFIN_BUILTIN_ABS_1X32
, 0 },
5806 { CODE_FOR_movv2hi_hi_low
, "__builtin_bfin_extract_lo", BFIN_BUILTIN_EXTRACTLO
, 0 },
5807 { CODE_FOR_movv2hi_hi_high
, "__builtin_bfin_extract_hi", BFIN_BUILTIN_EXTRACTHI
, 0 },
5808 { CODE_FOR_ssnegv2hi2
, "__builtin_bfin_negate_fr2x16", BFIN_BUILTIN_NEG_2X16
, 0 },
5809 { CODE_FOR_ssabsv2hi2
, "__builtin_bfin_abs_fr2x16", BFIN_BUILTIN_ABS_2X16
, 0 }
5812 /* Errors in the source file can cause expand_expr to return const0_rtx
5813 where we expect a vector. To avoid crashing, use one of the vector
5814 clear instructions. */
5816 safe_vector_operand (rtx x
, enum machine_mode mode
)
5818 if (x
!= const0_rtx
)
5820 x
= gen_reg_rtx (SImode
);
5822 emit_insn (gen_movsi (x
, CONST0_RTX (SImode
)));
5823 return gen_lowpart (mode
, x
);
5826 /* Subroutine of bfin_expand_builtin to take care of binop insns. MACFLAG is -1
5827 if this is a normal binary op, or one of the MACFLAG_xxx constants. */
5830 bfin_expand_binop_builtin (enum insn_code icode
, tree exp
, rtx target
,
5834 tree arg0
= CALL_EXPR_ARG (exp
, 0);
5835 tree arg1
= CALL_EXPR_ARG (exp
, 1);
5836 rtx op0
= expand_expr (arg0
, NULL_RTX
, VOIDmode
, 0);
5837 rtx op1
= expand_expr (arg1
, NULL_RTX
, VOIDmode
, 0);
5838 enum machine_mode op0mode
= GET_MODE (op0
);
5839 enum machine_mode op1mode
= GET_MODE (op1
);
5840 enum machine_mode tmode
= insn_data
[icode
].operand
[0].mode
;
5841 enum machine_mode mode0
= insn_data
[icode
].operand
[1].mode
;
5842 enum machine_mode mode1
= insn_data
[icode
].operand
[2].mode
;
5844 if (VECTOR_MODE_P (mode0
))
5845 op0
= safe_vector_operand (op0
, mode0
);
5846 if (VECTOR_MODE_P (mode1
))
5847 op1
= safe_vector_operand (op1
, mode1
);
5850 || GET_MODE (target
) != tmode
5851 || ! (*insn_data
[icode
].operand
[0].predicate
) (target
, tmode
))
5852 target
= gen_reg_rtx (tmode
);
5854 if ((op0mode
== SImode
|| op0mode
== VOIDmode
) && mode0
== HImode
)
5857 op0
= gen_lowpart (HImode
, op0
);
5859 if ((op1mode
== SImode
|| op1mode
== VOIDmode
) && mode1
== HImode
)
5862 op1
= gen_lowpart (HImode
, op1
);
5864 /* In case the insn wants input operands in modes different from
5865 the result, abort. */
5866 gcc_assert ((op0mode
== mode0
|| op0mode
== VOIDmode
)
5867 && (op1mode
== mode1
|| op1mode
== VOIDmode
));
5869 if (! (*insn_data
[icode
].operand
[1].predicate
) (op0
, mode0
))
5870 op0
= copy_to_mode_reg (mode0
, op0
);
5871 if (! (*insn_data
[icode
].operand
[2].predicate
) (op1
, mode1
))
5872 op1
= copy_to_mode_reg (mode1
, op1
);
5875 pat
= GEN_FCN (icode
) (target
, op0
, op1
);
5877 pat
= GEN_FCN (icode
) (target
, op0
, op1
, GEN_INT (macflag
));
5885 /* Subroutine of bfin_expand_builtin to take care of unop insns. */
5888 bfin_expand_unop_builtin (enum insn_code icode
, tree exp
,
5892 tree arg0
= CALL_EXPR_ARG (exp
, 0);
5893 rtx op0
= expand_expr (arg0
, NULL_RTX
, VOIDmode
, 0);
5894 enum machine_mode op0mode
= GET_MODE (op0
);
5895 enum machine_mode tmode
= insn_data
[icode
].operand
[0].mode
;
5896 enum machine_mode mode0
= insn_data
[icode
].operand
[1].mode
;
5899 || GET_MODE (target
) != tmode
5900 || ! (*insn_data
[icode
].operand
[0].predicate
) (target
, tmode
))
5901 target
= gen_reg_rtx (tmode
);
5903 if (VECTOR_MODE_P (mode0
))
5904 op0
= safe_vector_operand (op0
, mode0
);
5906 if (op0mode
== SImode
&& mode0
== HImode
)
5909 op0
= gen_lowpart (HImode
, op0
);
5911 gcc_assert (op0mode
== mode0
|| op0mode
== VOIDmode
);
5913 if (! (*insn_data
[icode
].operand
[1].predicate
) (op0
, mode0
))
5914 op0
= copy_to_mode_reg (mode0
, op0
);
5916 pat
= GEN_FCN (icode
) (target
, op0
);
5923 /* Expand an expression EXP that calls a built-in function,
5924 with result going to TARGET if that's convenient
5925 (and in mode MODE if that's convenient).
5926 SUBTARGET may be used as the target for computing one of EXP's operands.
5927 IGNORE is nonzero if the value is to be ignored. */
5930 bfin_expand_builtin (tree exp
, rtx target ATTRIBUTE_UNUSED
,
5931 rtx subtarget ATTRIBUTE_UNUSED
,
5932 enum machine_mode mode ATTRIBUTE_UNUSED
,
5933 int ignore ATTRIBUTE_UNUSED
)
5936 enum insn_code icode
;
5937 const struct builtin_description
*d
;
5938 tree fndecl
= TREE_OPERAND (CALL_EXPR_FN (exp
), 0);
5939 unsigned int fcode
= DECL_FUNCTION_CODE (fndecl
);
5940 tree arg0
, arg1
, arg2
;
5941 rtx op0
, op1
, op2
, accvec
, pat
, tmp1
, tmp2
, a0reg
, a1reg
;
5942 enum machine_mode tmode
, mode0
;
5946 case BFIN_BUILTIN_CSYNC
:
5947 emit_insn (gen_csync ());
5949 case BFIN_BUILTIN_SSYNC
:
5950 emit_insn (gen_ssync ());
5953 case BFIN_BUILTIN_DIFFHL_2X16
:
5954 case BFIN_BUILTIN_DIFFLH_2X16
:
5955 case BFIN_BUILTIN_SUM_2X16
:
5956 arg0
= CALL_EXPR_ARG (exp
, 0);
5957 op0
= expand_expr (arg0
, NULL_RTX
, VOIDmode
, 0);
5958 icode
= (fcode
== BFIN_BUILTIN_DIFFHL_2X16
? CODE_FOR_subhilov2hi3
5959 : fcode
== BFIN_BUILTIN_DIFFLH_2X16
? CODE_FOR_sublohiv2hi3
5960 : CODE_FOR_ssaddhilov2hi3
);
5961 tmode
= insn_data
[icode
].operand
[0].mode
;
5962 mode0
= insn_data
[icode
].operand
[1].mode
;
5965 || GET_MODE (target
) != tmode
5966 || ! (*insn_data
[icode
].operand
[0].predicate
) (target
, tmode
))
5967 target
= gen_reg_rtx (tmode
);
5969 if (VECTOR_MODE_P (mode0
))
5970 op0
= safe_vector_operand (op0
, mode0
);
5972 if (! (*insn_data
[icode
].operand
[1].predicate
) (op0
, mode0
))
5973 op0
= copy_to_mode_reg (mode0
, op0
);
5975 pat
= GEN_FCN (icode
) (target
, op0
, op0
);
5981 case BFIN_BUILTIN_MULT_1X32X32
:
5982 case BFIN_BUILTIN_MULT_1X32X32NS
:
5983 arg0
= CALL_EXPR_ARG (exp
, 0);
5984 arg1
= CALL_EXPR_ARG (exp
, 1);
5985 op0
= expand_expr (arg0
, NULL_RTX
, VOIDmode
, 0);
5986 op1
= expand_expr (arg1
, NULL_RTX
, VOIDmode
, 0);
5988 || !register_operand (target
, SImode
))
5989 target
= gen_reg_rtx (SImode
);
5991 a1reg
= gen_rtx_REG (PDImode
, REG_A1
);
5992 a0reg
= gen_rtx_REG (PDImode
, REG_A0
);
5993 tmp1
= gen_lowpart (V2HImode
, op0
);
5994 tmp2
= gen_lowpart (V2HImode
, op1
);
5995 emit_insn (gen_flag_macinit1hi (a1reg
,
5996 gen_lowpart (HImode
, op0
),
5997 gen_lowpart (HImode
, op1
),
5998 GEN_INT (MACFLAG_FU
)));
5999 emit_insn (gen_lshrpdi3 (a1reg
, a1reg
, GEN_INT (16)));
6001 if (fcode
== BFIN_BUILTIN_MULT_1X32X32
)
6002 emit_insn (gen_flag_mul_macv2hi_parts_acconly (a0reg
, a1reg
, tmp1
, tmp2
,
6003 const1_rtx
, const1_rtx
,
6004 const1_rtx
, const0_rtx
, a1reg
,
6005 const0_rtx
, GEN_INT (MACFLAG_NONE
),
6006 GEN_INT (MACFLAG_M
)));
6009 /* For saturating multiplication, there's exactly one special case
6010 to be handled: multiplying the smallest negative value with
6011 itself. Due to shift correction in fractional multiplies, this
6012 can overflow. Iff this happens, OP2 will contain 1, which, when
6013 added in 32 bits to the smallest negative, wraps to the largest
6014 positive, which is the result we want. */
6015 op2
= gen_reg_rtx (V2HImode
);
6016 emit_insn (gen_packv2hi (op2
, tmp1
, tmp2
, const0_rtx
, const0_rtx
));
6017 emit_insn (gen_movsibi (gen_rtx_REG (BImode
, REG_CC
),
6018 gen_lowpart (SImode
, op2
)));
6019 emit_insn (gen_flag_mul_macv2hi_parts_acconly_andcc0 (a0reg
, a1reg
, tmp1
, tmp2
,
6020 const1_rtx
, const1_rtx
,
6021 const1_rtx
, const0_rtx
, a1reg
,
6022 const0_rtx
, GEN_INT (MACFLAG_NONE
),
6023 GEN_INT (MACFLAG_M
)));
6024 op2
= gen_reg_rtx (SImode
);
6025 emit_insn (gen_movbisi (op2
, gen_rtx_REG (BImode
, REG_CC
)));
6027 emit_insn (gen_flag_machi_parts_acconly (a1reg
, tmp2
, tmp1
,
6028 const1_rtx
, const0_rtx
,
6029 a1reg
, const0_rtx
, GEN_INT (MACFLAG_M
)));
6030 emit_insn (gen_ashrpdi3 (a1reg
, a1reg
, GEN_INT (15)));
6031 emit_insn (gen_sum_of_accumulators (target
, a0reg
, a0reg
, a1reg
));
6032 if (fcode
== BFIN_BUILTIN_MULT_1X32X32NS
)
6033 emit_insn (gen_addsi3 (target
, target
, op2
));
6036 case BFIN_BUILTIN_CPLX_MUL_16
:
6037 case BFIN_BUILTIN_CPLX_MUL_16_S40
:
6038 arg0
= CALL_EXPR_ARG (exp
, 0);
6039 arg1
= CALL_EXPR_ARG (exp
, 1);
6040 op0
= expand_expr (arg0
, NULL_RTX
, VOIDmode
, 0);
6041 op1
= expand_expr (arg1
, NULL_RTX
, VOIDmode
, 0);
6042 accvec
= gen_reg_rtx (V2PDImode
);
6045 || GET_MODE (target
) != V2HImode
6046 || ! (*insn_data
[icode
].operand
[0].predicate
) (target
, V2HImode
))
6047 target
= gen_reg_rtx (tmode
);
6048 if (! register_operand (op0
, GET_MODE (op0
)))
6049 op0
= copy_to_mode_reg (GET_MODE (op0
), op0
);
6050 if (! register_operand (op1
, GET_MODE (op1
)))
6051 op1
= copy_to_mode_reg (GET_MODE (op1
), op1
);
6053 if (fcode
== BFIN_BUILTIN_CPLX_MUL_16
)
6054 emit_insn (gen_flag_macinit1v2hi_parts (accvec
, op0
, op1
, const0_rtx
,
6055 const0_rtx
, const0_rtx
,
6056 const1_rtx
, GEN_INT (MACFLAG_W32
)));
6058 emit_insn (gen_flag_macinit1v2hi_parts (accvec
, op0
, op1
, const0_rtx
,
6059 const0_rtx
, const0_rtx
,
6060 const1_rtx
, GEN_INT (MACFLAG_NONE
)));
6061 emit_insn (gen_flag_macv2hi_parts (target
, op0
, op1
, const1_rtx
,
6062 const1_rtx
, const1_rtx
,
6063 const0_rtx
, accvec
, const1_rtx
, const0_rtx
,
6064 GEN_INT (MACFLAG_NONE
), accvec
));
6068 case BFIN_BUILTIN_CPLX_MAC_16
:
6069 case BFIN_BUILTIN_CPLX_MSU_16
:
6070 case BFIN_BUILTIN_CPLX_MAC_16_S40
:
6071 case BFIN_BUILTIN_CPLX_MSU_16_S40
:
6072 arg0
= CALL_EXPR_ARG (exp
, 0);
6073 arg1
= CALL_EXPR_ARG (exp
, 1);
6074 arg2
= CALL_EXPR_ARG (exp
, 2);
6075 op0
= expand_expr (arg0
, NULL_RTX
, VOIDmode
, 0);
6076 op1
= expand_expr (arg1
, NULL_RTX
, VOIDmode
, 0);
6077 op2
= expand_expr (arg2
, NULL_RTX
, VOIDmode
, 0);
6078 accvec
= gen_reg_rtx (V2PDImode
);
6081 || GET_MODE (target
) != V2HImode
6082 || ! (*insn_data
[icode
].operand
[0].predicate
) (target
, V2HImode
))
6083 target
= gen_reg_rtx (tmode
);
6084 if (! register_operand (op1
, GET_MODE (op1
)))
6085 op1
= copy_to_mode_reg (GET_MODE (op1
), op1
);
6086 if (! register_operand (op2
, GET_MODE (op2
)))
6087 op2
= copy_to_mode_reg (GET_MODE (op2
), op2
);
6089 tmp1
= gen_reg_rtx (SImode
);
6090 tmp2
= gen_reg_rtx (SImode
);
6091 emit_insn (gen_ashlsi3 (tmp1
, gen_lowpart (SImode
, op0
), GEN_INT (16)));
6092 emit_move_insn (tmp2
, gen_lowpart (SImode
, op0
));
6093 emit_insn (gen_movstricthi_1 (gen_lowpart (HImode
, tmp2
), const0_rtx
));
6094 emit_insn (gen_load_accumulator_pair (accvec
, tmp1
, tmp2
));
6095 if (fcode
== BFIN_BUILTIN_CPLX_MAC_16
6096 || fcode
== BFIN_BUILTIN_CPLX_MSU_16
)
6097 emit_insn (gen_flag_macv2hi_parts_acconly (accvec
, op1
, op2
, const0_rtx
,
6098 const0_rtx
, const0_rtx
,
6099 const1_rtx
, accvec
, const0_rtx
,
6101 GEN_INT (MACFLAG_W32
)));
6103 emit_insn (gen_flag_macv2hi_parts_acconly (accvec
, op1
, op2
, const0_rtx
,
6104 const0_rtx
, const0_rtx
,
6105 const1_rtx
, accvec
, const0_rtx
,
6107 GEN_INT (MACFLAG_NONE
)));
6108 if (fcode
== BFIN_BUILTIN_CPLX_MAC_16
6109 || fcode
== BFIN_BUILTIN_CPLX_MAC_16_S40
)
6119 emit_insn (gen_flag_macv2hi_parts (target
, op1
, op2
, const1_rtx
,
6120 const1_rtx
, const1_rtx
,
6121 const0_rtx
, accvec
, tmp1
, tmp2
,
6122 GEN_INT (MACFLAG_NONE
), accvec
));
6126 case BFIN_BUILTIN_CPLX_SQU
:
6127 arg0
= CALL_EXPR_ARG (exp
, 0);
6128 op0
= expand_expr (arg0
, NULL_RTX
, VOIDmode
, 0);
6129 accvec
= gen_reg_rtx (V2PDImode
);
6130 icode
= CODE_FOR_flag_mulv2hi
;
6131 tmp1
= gen_reg_rtx (V2HImode
);
6132 tmp2
= gen_reg_rtx (V2HImode
);
6135 || GET_MODE (target
) != V2HImode
6136 || ! (*insn_data
[icode
].operand
[0].predicate
) (target
, V2HImode
))
6137 target
= gen_reg_rtx (V2HImode
);
6138 if (! register_operand (op0
, GET_MODE (op0
)))
6139 op0
= copy_to_mode_reg (GET_MODE (op0
), op0
);
6141 emit_insn (gen_flag_mulv2hi (tmp1
, op0
, op0
, GEN_INT (MACFLAG_NONE
)));
6143 emit_insn (gen_flag_mulhi_parts (tmp2
, op0
, op0
, const0_rtx
,
6144 const0_rtx
, const1_rtx
,
6145 GEN_INT (MACFLAG_NONE
)));
6147 emit_insn (gen_ssaddhi3_parts (target
, tmp2
, tmp2
, const1_rtx
,
6148 const0_rtx
, const0_rtx
));
6150 emit_insn (gen_sssubhi3_parts (target
, tmp1
, tmp1
, const0_rtx
,
6151 const0_rtx
, const1_rtx
));
6159 for (i
= 0, d
= bdesc_2arg
; i
< ARRAY_SIZE (bdesc_2arg
); i
++, d
++)
6160 if (d
->code
== fcode
)
6161 return bfin_expand_binop_builtin (d
->icode
, exp
, target
,
6164 for (i
= 0, d
= bdesc_1arg
; i
< ARRAY_SIZE (bdesc_1arg
); i
++, d
++)
6165 if (d
->code
== fcode
)
6166 return bfin_expand_unop_builtin (d
->icode
, exp
, target
);
6171 #undef TARGET_INIT_BUILTINS
6172 #define TARGET_INIT_BUILTINS bfin_init_builtins
6174 #undef TARGET_EXPAND_BUILTIN
6175 #define TARGET_EXPAND_BUILTIN bfin_expand_builtin
6177 #undef TARGET_ASM_GLOBALIZE_LABEL
6178 #define TARGET_ASM_GLOBALIZE_LABEL bfin_globalize_label
6180 #undef TARGET_ASM_FILE_START
6181 #define TARGET_ASM_FILE_START output_file_start
6183 #undef TARGET_ATTRIBUTE_TABLE
6184 #define TARGET_ATTRIBUTE_TABLE bfin_attribute_table
6186 #undef TARGET_COMP_TYPE_ATTRIBUTES
6187 #define TARGET_COMP_TYPE_ATTRIBUTES bfin_comp_type_attributes
6189 #undef TARGET_RTX_COSTS
6190 #define TARGET_RTX_COSTS bfin_rtx_costs
6192 #undef TARGET_ADDRESS_COST
6193 #define TARGET_ADDRESS_COST bfin_address_cost
6195 #undef TARGET_ASM_INTEGER
6196 #define TARGET_ASM_INTEGER bfin_assemble_integer
6198 #undef TARGET_MACHINE_DEPENDENT_REORG
6199 #define TARGET_MACHINE_DEPENDENT_REORG bfin_reorg
6201 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
6202 #define TARGET_FUNCTION_OK_FOR_SIBCALL bfin_function_ok_for_sibcall
6204 #undef TARGET_ASM_OUTPUT_MI_THUNK
6205 #define TARGET_ASM_OUTPUT_MI_THUNK bfin_output_mi_thunk
6206 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
6207 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true
6209 #undef TARGET_SCHED_ADJUST_COST
6210 #define TARGET_SCHED_ADJUST_COST bfin_adjust_cost
6212 #undef TARGET_SCHED_ISSUE_RATE
6213 #define TARGET_SCHED_ISSUE_RATE bfin_issue_rate
6215 #undef TARGET_PROMOTE_PROTOTYPES
6216 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
6217 #undef TARGET_PROMOTE_FUNCTION_ARGS
6218 #define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_const_tree_true
6219 #undef TARGET_PROMOTE_FUNCTION_RETURN
6220 #define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_const_tree_true
6222 #undef TARGET_ARG_PARTIAL_BYTES
6223 #define TARGET_ARG_PARTIAL_BYTES bfin_arg_partial_bytes
6225 #undef TARGET_PASS_BY_REFERENCE
6226 #define TARGET_PASS_BY_REFERENCE bfin_pass_by_reference
6228 #undef TARGET_SETUP_INCOMING_VARARGS
6229 #define TARGET_SETUP_INCOMING_VARARGS setup_incoming_varargs
6231 #undef TARGET_STRUCT_VALUE_RTX
6232 #define TARGET_STRUCT_VALUE_RTX bfin_struct_value_rtx
6234 #undef TARGET_VECTOR_MODE_SUPPORTED_P
6235 #define TARGET_VECTOR_MODE_SUPPORTED_P bfin_vector_mode_supported_p
6237 #undef TARGET_HANDLE_OPTION
6238 #define TARGET_HANDLE_OPTION bfin_handle_option
6240 #undef TARGET_DEFAULT_TARGET_FLAGS
6241 #define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
6243 #undef TARGET_SECONDARY_RELOAD
6244 #define TARGET_SECONDARY_RELOAD bfin_secondary_reload
6246 #undef TARGET_DELEGITIMIZE_ADDRESS
6247 #define TARGET_DELEGITIMIZE_ADDRESS bfin_delegitimize_address
6249 #undef TARGET_CANNOT_FORCE_CONST_MEM
6250 #define TARGET_CANNOT_FORCE_CONST_MEM bfin_cannot_force_const_mem
6252 #undef TARGET_RETURN_IN_MEMORY
6253 #define TARGET_RETURN_IN_MEMORY bfin_return_in_memory
6255 struct gcc_target targetm
= TARGET_INITIALIZER
;