1 /* The Blackfin code generation auxiliary output file.
2 Copyright (C) 2005, 2006, 2007, 2008, 2009 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 GTY(()) machine_function
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 | WA_LOAD_LCREGS},
177 {"bf531", BFIN_CPU_BF531, 0x0005,
178 WA_SPECULATIVE_LOADS | WA_RETS | WA_05000283 | WA_05000315 | WA_LOAD_LCREGS},
179 {"bf531", BFIN_CPU_BF531, 0x0004,
180 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
181 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS},
182 {"bf531", BFIN_CPU_BF531, 0x0003,
183 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
184 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS},
186 {"bf532", BFIN_CPU_BF532, 0x0006,
187 WA_SPECULATIVE_LOADS | WA_LOAD_LCREGS},
188 {"bf532", BFIN_CPU_BF532, 0x0005,
189 WA_SPECULATIVE_LOADS | WA_RETS | WA_05000283 | WA_05000315 | WA_LOAD_LCREGS},
190 {"bf532", BFIN_CPU_BF532, 0x0004,
191 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
192 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS},
193 {"bf532", BFIN_CPU_BF532, 0x0003,
194 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
195 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS},
197 {"bf533", BFIN_CPU_BF533, 0x0006,
198 WA_SPECULATIVE_LOADS | WA_LOAD_LCREGS},
199 {"bf533", BFIN_CPU_BF533, 0x0005,
200 WA_SPECULATIVE_LOADS | WA_RETS | WA_05000283 | WA_05000315 | WA_LOAD_LCREGS},
201 {"bf533", BFIN_CPU_BF533, 0x0004,
202 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
203 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS},
204 {"bf533", BFIN_CPU_BF533, 0x0003,
205 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
206 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS},
208 {"bf534", BFIN_CPU_BF534, 0x0003,
209 WA_SPECULATIVE_LOADS | WA_RETS | WA_LOAD_LCREGS},
210 {"bf534", BFIN_CPU_BF534, 0x0002,
211 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
212 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS},
213 {"bf534", BFIN_CPU_BF534, 0x0001,
214 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
215 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS},
217 {"bf536", BFIN_CPU_BF536, 0x0003,
218 WA_SPECULATIVE_LOADS | WA_RETS | WA_LOAD_LCREGS},
219 {"bf536", BFIN_CPU_BF536, 0x0002,
220 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
221 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS},
222 {"bf536", BFIN_CPU_BF536, 0x0001,
223 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
224 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS},
226 {"bf537", BFIN_CPU_BF537, 0x0003,
227 WA_SPECULATIVE_LOADS | WA_RETS | WA_LOAD_LCREGS},
228 {"bf537", BFIN_CPU_BF537, 0x0002,
229 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
230 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS},
231 {"bf537", BFIN_CPU_BF537, 0x0001,
232 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
233 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS},
235 {"bf538", BFIN_CPU_BF538, 0x0005,
236 WA_SPECULATIVE_LOADS | WA_LOAD_LCREGS},
237 {"bf538", BFIN_CPU_BF538, 0x0004,
238 WA_SPECULATIVE_LOADS | WA_RETS | WA_LOAD_LCREGS},
239 {"bf538", BFIN_CPU_BF538, 0x0003,
240 WA_SPECULATIVE_LOADS | WA_RETS
241 | WA_05000283 | WA_05000315 | WA_LOAD_LCREGS},
242 {"bf538", BFIN_CPU_BF538, 0x0002,
243 WA_SPECULATIVE_LOADS | WA_RETS
244 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS},
246 {"bf539", BFIN_CPU_BF539, 0x0005,
247 WA_SPECULATIVE_LOADS | WA_LOAD_LCREGS},
248 {"bf539", BFIN_CPU_BF539, 0x0004,
249 WA_SPECULATIVE_LOADS | WA_RETS | WA_LOAD_LCREGS},
250 {"bf539", BFIN_CPU_BF539, 0x0003,
251 WA_SPECULATIVE_LOADS | WA_RETS
252 | WA_05000283 | WA_05000315 | WA_LOAD_LCREGS},
253 {"bf539", BFIN_CPU_BF539, 0x0002,
254 WA_SPECULATIVE_LOADS | WA_RETS
255 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS},
257 {"bf542", BFIN_CPU_BF542, 0x0002,
258 WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS},
259 {"bf542", BFIN_CPU_BF542, 0x0001,
260 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS},
261 {"bf542", BFIN_CPU_BF542, 0x0000,
262 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS | WA_LOAD_LCREGS},
264 {"bf544", BFIN_CPU_BF544, 0x0002,
265 WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS},
266 {"bf544", BFIN_CPU_BF544, 0x0001,
267 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS},
268 {"bf544", BFIN_CPU_BF544, 0x0000,
269 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS | WA_LOAD_LCREGS},
271 {"bf547", BFIN_CPU_BF547, 0x0002,
272 WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS},
273 {"bf547", BFIN_CPU_BF547, 0x0001,
274 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS},
275 {"bf547", BFIN_CPU_BF547, 0x0000,
276 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS | WA_LOAD_LCREGS},
278 {"bf548", BFIN_CPU_BF548, 0x0002,
279 WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS},
280 {"bf548", BFIN_CPU_BF548, 0x0001,
281 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS},
282 {"bf548", BFIN_CPU_BF548, 0x0000,
283 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS | WA_LOAD_LCREGS},
285 {"bf549", BFIN_CPU_BF549, 0x0002,
286 WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS},
287 {"bf549", BFIN_CPU_BF549, 0x0001,
288 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS},
289 {"bf549", BFIN_CPU_BF549, 0x0000,
290 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS | WA_LOAD_LCREGS},
292 {"bf561", BFIN_CPU_BF561, 0x0005, WA_RETS
293 | WA_05000283 | WA_05000315 | WA_LOAD_LCREGS},
294 {"bf561", BFIN_CPU_BF561, 0x0003,
295 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
296 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS},
297 {"bf561", BFIN_CPU_BF561, 0x0002,
298 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
299 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS},
304 int splitting_for_sched, splitting_loops;
307 bfin_globalize_label (FILE *stream, const char *name)
309 fputs (".global ", stream);
310 assemble_name (stream, name);
316 output_file_start (void)
318 FILE *file = asm_out_file;
321 /* Variable tracking should be run after all optimizations which change order
322 of insns. It also needs a valid CFG. This can't be done in
323 override_options, because flag_var_tracking is finalized after
325 bfin_flag_var_tracking = flag_var_tracking;
326 flag_var_tracking = 0;
328 fprintf (file, ".file \"%s\";\n", input_filename);
330 for (i = 0; arg_regs[i] >= 0; i++)
332 max_arg_registers = i; /* how many arg reg used */
335 /* Called early in the compilation to conditionally modify
336 fixed_regs/call_used_regs. */
339 conditional_register_usage (void)
341 /* initialize condition code flag register rtx */
342 bfin_cc_rtx = gen_rtx_REG (BImode, REG_CC);
343 bfin_rets_rtx = gen_rtx_REG (Pmode, REG_RETS);
346 /* Examine machine-dependent attributes of function type FUNTYPE and return its
347 type. See the definition of E_FUNKIND. */
350 funkind (const_tree funtype)
352 tree attrs = TYPE_ATTRIBUTES (funtype);
353 if (lookup_attribute ("interrupt_handler", attrs))
354 return INTERRUPT_HANDLER;
355 else if (lookup_attribute ("exception_handler", attrs))
356 return EXCPT_HANDLER;
357 else if (lookup_attribute ("nmi_handler", attrs))
363 /* Legitimize PIC addresses. If the address is already position-independent,
364 we return ORIG. Newly generated position-independent addresses go into a
365 reg. This is REG if nonzero, otherwise we allocate register(s) as
366 necessary. PICREG is the register holding the pointer to the PIC offset
370 legitimize_pic_address (rtx orig, rtx reg, rtx picreg)
375 if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == LABEL_REF)
380 if (TARGET_ID_SHARED_LIBRARY)
381 unspec = UNSPEC_MOVE_PIC;
382 else if (GET_CODE (addr) == SYMBOL_REF
383 && SYMBOL_REF_FUNCTION_P (addr))
384 unspec = UNSPEC_FUNCDESC_GOT17M4;
386 unspec = UNSPEC_MOVE_FDPIC;
390 gcc_assert (can_create_pseudo_p ());
391 reg = gen_reg_rtx (Pmode);
394 tmp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), unspec);
395 new_rtx = gen_const_mem (Pmode, gen_rtx_PLUS (Pmode, picreg, tmp));
397 emit_move_insn (reg, new_rtx);
398 if (picreg == pic_offset_table_rtx)
399 crtl->uses_pic_offset_table = 1;
403 else if (GET_CODE (addr) == CONST || GET_CODE (addr) == PLUS)
407 if (GET_CODE (addr) == CONST)
409 addr = XEXP (addr, 0);
410 gcc_assert (GET_CODE (addr) == PLUS);
413 if (XEXP (addr, 0) == picreg)
418 gcc_assert (can_create_pseudo_p ());
419 reg = gen_reg_rtx (Pmode);
422 base = legitimize_pic_address (XEXP (addr, 0), reg, picreg);
423 addr = legitimize_pic_address (XEXP (addr, 1),
424 base == reg ? NULL_RTX : reg,
427 if (GET_CODE (addr) == CONST_INT)
429 gcc_assert (! reload_in_progress && ! reload_completed);
430 addr = force_reg (Pmode, addr);
433 if (GET_CODE (addr) == PLUS && CONSTANT_P (XEXP (addr, 1)))
435 base = gen_rtx_PLUS (Pmode, base, XEXP (addr, 0));
436 addr = XEXP (addr, 1);
439 return gen_rtx_PLUS (Pmode, base, addr);
445 /* Stack frame layout. */
447 /* For a given REGNO, determine whether it must be saved in the function
448 prologue. IS_INTHANDLER specifies whether we're generating a normal
449 prologue or an interrupt/exception one. */
451 must_save_p (bool is_inthandler, unsigned regno)
453 if (D_REGNO_P (regno))
455 bool is_eh_return_reg = false;
456 if (crtl->calls_eh_return)
461 unsigned test = EH_RETURN_DATA_REGNO (j);
462 if (test == INVALID_REGNUM)
465 is_eh_return_reg = true;
469 return (is_eh_return_reg
470 || (df_regs_ever_live_p (regno)
471 && !fixed_regs[regno]
472 && (is_inthandler || !call_used_regs[regno])));
474 else if (P_REGNO_P (regno))
476 return ((df_regs_ever_live_p (regno)
477 && !fixed_regs[regno]
478 && (is_inthandler || !call_used_regs[regno]))
480 && (ENABLE_WA_05000283 || ENABLE_WA_05000315)
483 && regno == PIC_OFFSET_TABLE_REGNUM
484 && (crtl->uses_pic_offset_table
485 || (TARGET_ID_SHARED_LIBRARY && !current_function_is_leaf))));
488 return ((is_inthandler || !call_used_regs[regno])
489 && (df_regs_ever_live_p (regno)
490 || (!leaf_function_p () && call_used_regs[regno])));
494 /* Compute the number of DREGS to save with a push_multiple operation.
495 This could include registers that aren't modified in the function,
496 since push_multiple only takes a range of registers.
497 If IS_INTHANDLER, then everything that is live must be saved, even
498 if normally call-clobbered.
499 If CONSECUTIVE, return the number of registers we can save in one
500 instruction with a push/pop multiple instruction. */
503 n_dregs_to_save (bool is_inthandler, bool consecutive)
508 for (i = REG_R7 + 1; i-- != REG_R0;)
510 if (must_save_p (is_inthandler, i))
512 else if (consecutive)
518 /* Like n_dregs_to_save, but compute number of PREGS to save. */
521 n_pregs_to_save (bool is_inthandler, bool consecutive)
526 for (i = REG_P5 + 1; i-- != REG_P0;)
527 if (must_save_p (is_inthandler, i))
529 else if (consecutive)
534 /* Determine if we are going to save the frame pointer in the prologue. */
537 must_save_fp_p (void)
539 return frame_pointer_needed || df_regs_ever_live_p (REG_FP);
543 stack_frame_needed_p (void)
545 /* EH return puts a new return address into the frame using an
546 address relative to the frame pointer. */
547 if (crtl->calls_eh_return)
549 return frame_pointer_needed;
552 /* Emit code to save registers in the prologue. SAVEALL is nonzero if we
553 must save all registers; this is used for interrupt handlers.
554 SPREG contains (reg:SI REG_SP). IS_INTHANDLER is true if we're doing
555 this for an interrupt (or exception) handler. */
558 expand_prologue_reg_save (rtx spreg, int saveall, bool is_inthandler)
560 rtx predec1 = gen_rtx_PRE_DEC (SImode, spreg);
561 rtx predec = gen_rtx_MEM (SImode, predec1);
562 int ndregs = saveall ? 8 : n_dregs_to_save (is_inthandler, false);
563 int npregs = saveall ? 6 : n_pregs_to_save (is_inthandler, false);
564 int ndregs_consec = saveall ? 8 : n_dregs_to_save (is_inthandler, true);
565 int npregs_consec = saveall ? 6 : n_pregs_to_save (is_inthandler, true);
567 int total_consec = ndregs_consec + npregs_consec;
570 if (saveall || is_inthandler)
572 rtx insn = emit_move_insn (predec, gen_rtx_REG (SImode, REG_ASTAT));
574 RTX_FRAME_RELATED_P (insn) = 1;
575 for (dregno = REG_LT0; dregno <= REG_LB1; dregno++)
576 if (! current_function_is_leaf
577 || cfun->machine->has_hardware_loops
578 || cfun->machine->has_loopreg_clobber
579 || (ENABLE_WA_05000257
580 && (dregno == REG_LC0 || dregno == REG_LC1)))
582 insn = emit_move_insn (predec, gen_rtx_REG (SImode, dregno));
583 RTX_FRAME_RELATED_P (insn) = 1;
587 if (total_consec != 0)
590 rtx val = GEN_INT (-total_consec * 4);
591 rtx pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total_consec + 2));
593 XVECEXP (pat, 0, 0) = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, val),
594 UNSPEC_PUSH_MULTIPLE);
595 XVECEXP (pat, 0, total_consec + 1) = gen_rtx_SET (VOIDmode, spreg,
599 RTX_FRAME_RELATED_P (XVECEXP (pat, 0, total_consec + 1)) = 1;
600 d_to_save = ndregs_consec;
601 dregno = REG_R7 + 1 - ndregs_consec;
602 pregno = REG_P5 + 1 - npregs_consec;
603 for (i = 0; i < total_consec; i++)
605 rtx memref = gen_rtx_MEM (word_mode,
606 gen_rtx_PLUS (Pmode, spreg,
607 GEN_INT (- i * 4 - 4)));
611 subpat = gen_rtx_SET (VOIDmode, memref, gen_rtx_REG (word_mode,
617 subpat = gen_rtx_SET (VOIDmode, memref, gen_rtx_REG (word_mode,
620 XVECEXP (pat, 0, i + 1) = subpat;
621 RTX_FRAME_RELATED_P (subpat) = 1;
623 insn = emit_insn (pat);
624 RTX_FRAME_RELATED_P (insn) = 1;
627 for (dregno = REG_R0; ndregs != ndregs_consec; dregno++)
629 if (must_save_p (is_inthandler, dregno))
631 rtx insn = emit_move_insn (predec, gen_rtx_REG (word_mode, dregno));
632 RTX_FRAME_RELATED_P (insn) = 1;
636 for (pregno = REG_P0; npregs != npregs_consec; pregno++)
638 if (must_save_p (is_inthandler, pregno))
640 rtx insn = emit_move_insn (predec, gen_rtx_REG (word_mode, pregno));
641 RTX_FRAME_RELATED_P (insn) = 1;
645 for (i = REG_P7 + 1; i < REG_CC; i++)
648 && (df_regs_ever_live_p (i)
649 || (!leaf_function_p () && call_used_regs[i]))))
652 if (i == REG_A0 || i == REG_A1)
653 insn = emit_move_insn (gen_rtx_MEM (PDImode, predec1),
654 gen_rtx_REG (PDImode, i));
656 insn = emit_move_insn (predec, gen_rtx_REG (SImode, i));
657 RTX_FRAME_RELATED_P (insn) = 1;
661 /* Emit code to restore registers in the epilogue. SAVEALL is nonzero if we
662 must save all registers; this is used for interrupt handlers.
663 SPREG contains (reg:SI REG_SP). IS_INTHANDLER is true if we're doing
664 this for an interrupt (or exception) handler. */
667 expand_epilogue_reg_restore (rtx spreg, bool saveall, bool is_inthandler)
669 rtx postinc1 = gen_rtx_POST_INC (SImode, spreg);
670 rtx postinc = gen_rtx_MEM (SImode, postinc1);
672 int ndregs = saveall ? 8 : n_dregs_to_save (is_inthandler, false);
673 int npregs = saveall ? 6 : n_pregs_to_save (is_inthandler, false);
674 int ndregs_consec = saveall ? 8 : n_dregs_to_save (is_inthandler, true);
675 int npregs_consec = saveall ? 6 : n_pregs_to_save (is_inthandler, true);
676 int total_consec = ndregs_consec + npregs_consec;
680 /* A slightly crude technique to stop flow from trying to delete "dead"
682 MEM_VOLATILE_P (postinc) = 1;
684 for (i = REG_CC - 1; i > REG_P7; i--)
687 && (df_regs_ever_live_p (i)
688 || (!leaf_function_p () && call_used_regs[i]))))
690 if (i == REG_A0 || i == REG_A1)
692 rtx mem = gen_rtx_MEM (PDImode, postinc1);
693 MEM_VOLATILE_P (mem) = 1;
694 emit_move_insn (gen_rtx_REG (PDImode, i), mem);
697 emit_move_insn (gen_rtx_REG (SImode, i), postinc);
700 regno = REG_P5 - npregs_consec;
701 for (; npregs != npregs_consec; regno--)
703 if (must_save_p (is_inthandler, regno))
705 emit_move_insn (gen_rtx_REG (word_mode, regno), postinc);
709 regno = REG_R7 - ndregs_consec;
710 for (; ndregs != ndregs_consec; regno--)
712 if (must_save_p (is_inthandler, regno))
714 emit_move_insn (gen_rtx_REG (word_mode, regno), postinc);
719 if (total_consec != 0)
721 rtx pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total_consec + 1));
723 = gen_rtx_SET (VOIDmode, spreg,
724 gen_rtx_PLUS (Pmode, spreg,
725 GEN_INT (total_consec * 4)));
727 if (npregs_consec > 0)
732 for (i = 0; i < total_consec; i++)
735 ? gen_rtx_PLUS (Pmode, spreg, GEN_INT (i * 4))
737 rtx memref = gen_rtx_MEM (word_mode, addr);
740 XVECEXP (pat, 0, i + 1)
741 = gen_rtx_SET (VOIDmode, gen_rtx_REG (word_mode, regno), memref);
743 if (npregs_consec > 0)
745 if (--npregs_consec == 0)
750 insn = emit_insn (pat);
751 RTX_FRAME_RELATED_P (insn) = 1;
753 if (saveall || is_inthandler)
755 for (regno = REG_LB1; regno >= REG_LT0; regno--)
756 if (! current_function_is_leaf
757 || cfun->machine->has_hardware_loops
758 || cfun->machine->has_loopreg_clobber
759 || (ENABLE_WA_05000257 && (regno == REG_LC0 || regno == REG_LC1)))
760 emit_move_insn (gen_rtx_REG (SImode, regno), postinc);
762 emit_move_insn (gen_rtx_REG (SImode, REG_ASTAT), postinc);
766 /* Perform any needed actions needed for a function that is receiving a
767 variable number of arguments.
771 MODE and TYPE are the mode and type of the current parameter.
773 PRETEND_SIZE is a variable that should be set to the amount of stack
774 that must be pushed by the prolog to pretend that our caller pushed
777 Normally, this macro will push all remaining incoming registers on the
778 stack and set PRETEND_SIZE to the length of the registers pushed.
781 - VDSP C compiler manual (our ABI) says that a variable args function
782 should save the R0, R1 and R2 registers in the stack.
783 - The caller will always leave space on the stack for the
784 arguments that are passed in registers, so we dont have
785 to leave any extra space.
786 - now, the vastart pointer can access all arguments from the stack. */
789 setup_incoming_varargs (CUMULATIVE_ARGS *cum,
790 enum machine_mode mode ATTRIBUTE_UNUSED,
791 tree type ATTRIBUTE_UNUSED, int *pretend_size,
800 /* The move for named arguments will be generated automatically by the
801 compiler. We need to generate the move rtx for the unnamed arguments
802 if they are in the first 3 words. We assume at least 1 named argument
803 exists, so we never generate [ARGP] = R0 here. */
805 for (i = cum->words + 1; i < max_arg_registers; i++)
807 mem = gen_rtx_MEM (Pmode,
808 plus_constant (arg_pointer_rtx, (i * UNITS_PER_WORD)));
809 emit_move_insn (mem, gen_rtx_REG (Pmode, i));
815 /* Value should be nonzero if functions must have frame pointers.
816 Zero means the frame pointer need not be set up (and parms may
817 be accessed via the stack pointer) in functions that seem suitable. */
820 bfin_frame_pointer_required (void)
822 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
824 if (fkind != SUBROUTINE)
827 /* We turn on -fomit-frame-pointer if -momit-leaf-frame-pointer is used,
828 so we have to override it for non-leaf functions. */
829 if (TARGET_OMIT_LEAF_FRAME_POINTER && ! current_function_is_leaf)
835 /* Return the number of registers pushed during the prologue. */
838 n_regs_saved_by_prologue (void)
840 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
841 bool is_inthandler = fkind != SUBROUTINE;
842 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
843 bool all = (lookup_attribute ("saveall", attrs) != NULL_TREE
844 || (is_inthandler && !current_function_is_leaf));
845 int ndregs = all ? 8 : n_dregs_to_save (is_inthandler, false);
846 int npregs = all ? 6 : n_pregs_to_save (is_inthandler, false);
847 int n = ndregs + npregs;
850 if (all || stack_frame_needed_p ())
851 /* We use a LINK instruction in this case. */
855 if (must_save_fp_p ())
857 if (! current_function_is_leaf)
861 if (fkind != SUBROUTINE || all)
863 /* Increment once for ASTAT. */
865 if (! current_function_is_leaf
866 || cfun->machine->has_hardware_loops
867 || cfun->machine->has_loopreg_clobber)
873 if (fkind != SUBROUTINE)
876 if (lookup_attribute ("nesting", attrs))
880 for (i = REG_P7 + 1; i < REG_CC; i++)
882 || (fkind != SUBROUTINE
883 && (df_regs_ever_live_p (i)
884 || (!leaf_function_p () && call_used_regs[i]))))
885 n += i == REG_A0 || i == REG_A1 ? 2 : 1;
890 /* Return the offset between two registers, one to be eliminated, and the other
891 its replacement, at the start of a routine. */
894 bfin_initial_elimination_offset (int from, int to)
896 HOST_WIDE_INT offset = 0;
898 if (from == ARG_POINTER_REGNUM)
899 offset = n_regs_saved_by_prologue () * 4;
901 if (to == STACK_POINTER_REGNUM)
903 if (crtl->outgoing_args_size >= FIXED_STACK_AREA)
904 offset += crtl->outgoing_args_size;
905 else if (crtl->outgoing_args_size)
906 offset += FIXED_STACK_AREA;
908 offset += get_frame_size ();
914 /* Emit code to load a constant CONSTANT into register REG; setting
915 RTX_FRAME_RELATED_P on all insns we generate if RELATED is true.
916 Make sure that the insns we generate need not be split. */
919 frame_related_constant_load (rtx reg, HOST_WIDE_INT constant, bool related)
922 rtx cst = GEN_INT (constant);
924 if (constant >= -32768 && constant < 65536)
925 insn = emit_move_insn (reg, cst);
928 /* We don't call split_load_immediate here, since dwarf2out.c can get
929 confused about some of the more clever sequences it can generate. */
930 insn = emit_insn (gen_movsi_high (reg, cst));
932 RTX_FRAME_RELATED_P (insn) = 1;
933 insn = emit_insn (gen_movsi_low (reg, reg, cst));
936 RTX_FRAME_RELATED_P (insn) = 1;
939 /* Generate efficient code to add a value to a P register.
940 Set RTX_FRAME_RELATED_P on the generated insns if FRAME is nonzero.
941 EPILOGUE_P is zero if this function is called for prologue,
942 otherwise it's nonzero. And it's less than zero if this is for
946 add_to_reg (rtx reg, HOST_WIDE_INT value, int frame, int epilogue_p)
951 /* Choose whether to use a sequence using a temporary register, or
952 a sequence with multiple adds. We can add a signed 7-bit value
953 in one instruction. */
954 if (value > 120 || value < -120)
962 /* For prologue or normal epilogue, P1 can be safely used
963 as the temporary register. For sibcall epilogue, we try to find
964 a call used P register, which will be restored in epilogue.
965 If we cannot find such a P register, we have to use one I register
969 tmpreg = gen_rtx_REG (SImode, REG_P1);
973 for (i = REG_P0; i <= REG_P5; i++)
974 if ((df_regs_ever_live_p (i) && ! call_used_regs[i])
976 && i == PIC_OFFSET_TABLE_REGNUM
977 && (crtl->uses_pic_offset_table
978 || (TARGET_ID_SHARED_LIBRARY
979 && ! current_function_is_leaf))))
982 tmpreg = gen_rtx_REG (SImode, i);
985 tmpreg = gen_rtx_REG (SImode, REG_P1);
986 tmpreg2 = gen_rtx_REG (SImode, REG_I0);
987 emit_move_insn (tmpreg2, tmpreg);
992 frame_related_constant_load (tmpreg, value, TRUE);
994 insn = emit_move_insn (tmpreg, GEN_INT (value));
996 insn = emit_insn (gen_addsi3 (reg, reg, tmpreg));
998 RTX_FRAME_RELATED_P (insn) = 1;
1000 if (tmpreg2 != NULL_RTX)
1001 emit_move_insn (tmpreg, tmpreg2);
1011 else if (size < -60)
1012 /* We could use -62, but that would leave the stack unaligned, so
1016 insn = emit_insn (gen_addsi3 (reg, reg, GEN_INT (size)));
1018 RTX_FRAME_RELATED_P (insn) = 1;
1024 /* Generate a LINK insn for a frame sized FRAME_SIZE. If this constant
1025 is too large, generate a sequence of insns that has the same effect.
1026 SPREG contains (reg:SI REG_SP). */
1029 emit_link_insn (rtx spreg, HOST_WIDE_INT frame_size)
1031 HOST_WIDE_INT link_size = frame_size;
1035 if (link_size > 262140)
1038 /* Use a LINK insn with as big a constant as possible, then subtract
1039 any remaining size from the SP. */
1040 insn = emit_insn (gen_link (GEN_INT (-8 - link_size)));
1041 RTX_FRAME_RELATED_P (insn) = 1;
1043 for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
1045 rtx set = XVECEXP (PATTERN (insn), 0, i);
1046 gcc_assert (GET_CODE (set) == SET);
1047 RTX_FRAME_RELATED_P (set) = 1;
1050 frame_size -= link_size;
1054 /* Must use a call-clobbered PREG that isn't the static chain. */
1055 rtx tmpreg = gen_rtx_REG (Pmode, REG_P1);
1057 frame_related_constant_load (tmpreg, -frame_size, TRUE);
1058 insn = emit_insn (gen_addsi3 (spreg, spreg, tmpreg));
1059 RTX_FRAME_RELATED_P (insn) = 1;
1063 /* Return the number of bytes we must reserve for outgoing arguments
1064 in the current function's stack frame. */
1066 static HOST_WIDE_INT
1067 arg_area_size (void)
1069 if (crtl->outgoing_args_size)
1071 if (crtl->outgoing_args_size >= FIXED_STACK_AREA)
1072 return crtl->outgoing_args_size;
1074 return FIXED_STACK_AREA;
1079 /* Save RETS and FP, and allocate a stack frame. ALL is true if the
1080 function must save all its registers (true only for certain interrupt
1084 do_link (rtx spreg, HOST_WIDE_INT frame_size, bool all)
1086 frame_size += arg_area_size ();
1088 if (all || stack_frame_needed_p ()
1089 || (must_save_fp_p () && ! current_function_is_leaf))
1090 emit_link_insn (spreg, frame_size);
1093 if (! current_function_is_leaf)
1095 rtx pat = gen_movsi (gen_rtx_MEM (Pmode,
1096 gen_rtx_PRE_DEC (Pmode, spreg)),
1098 rtx insn = emit_insn (pat);
1099 RTX_FRAME_RELATED_P (insn) = 1;
1101 if (must_save_fp_p ())
1103 rtx pat = gen_movsi (gen_rtx_MEM (Pmode,
1104 gen_rtx_PRE_DEC (Pmode, spreg)),
1105 gen_rtx_REG (Pmode, REG_FP));
1106 rtx insn = emit_insn (pat);
1107 RTX_FRAME_RELATED_P (insn) = 1;
1109 add_to_reg (spreg, -frame_size, 1, 0);
1113 /* Like do_link, but used for epilogues to deallocate the stack frame.
1114 EPILOGUE_P is zero if this function is called for prologue,
1115 otherwise it's nonzero. And it's less than zero if this is for
1116 sibcall epilogue. */
1119 do_unlink (rtx spreg, HOST_WIDE_INT frame_size, bool all, int epilogue_p)
1121 frame_size += arg_area_size ();
1123 if (all || stack_frame_needed_p ())
1124 emit_insn (gen_unlink ());
1127 rtx postinc = gen_rtx_MEM (Pmode, gen_rtx_POST_INC (Pmode, spreg));
1129 add_to_reg (spreg, frame_size, 0, epilogue_p);
1130 if (must_save_fp_p ())
1132 rtx fpreg = gen_rtx_REG (Pmode, REG_FP);
1133 emit_move_insn (fpreg, postinc);
1136 if (! current_function_is_leaf)
1138 emit_move_insn (bfin_rets_rtx, postinc);
1139 emit_use (bfin_rets_rtx);
1144 /* Generate a prologue suitable for a function of kind FKIND. This is
1145 called for interrupt and exception handler prologues.
1146 SPREG contains (reg:SI REG_SP). */
1149 expand_interrupt_handler_prologue (rtx spreg, e_funkind fkind, bool all)
1151 HOST_WIDE_INT frame_size = get_frame_size ();
1152 rtx predec1 = gen_rtx_PRE_DEC (SImode, spreg);
1153 rtx predec = gen_rtx_MEM (SImode, predec1);
1155 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1156 tree kspisusp = lookup_attribute ("kspisusp", attrs);
1160 insn = emit_move_insn (spreg, gen_rtx_REG (Pmode, REG_USP));
1161 RTX_FRAME_RELATED_P (insn) = 1;
1164 /* We need space on the stack in case we need to save the argument
1166 if (fkind == EXCPT_HANDLER)
1168 insn = emit_insn (gen_addsi3 (spreg, spreg, GEN_INT (-12)));
1169 RTX_FRAME_RELATED_P (insn) = 1;
1172 /* If we're calling other functions, they won't save their call-clobbered
1173 registers, so we must save everything here. */
1174 if (!current_function_is_leaf)
1176 expand_prologue_reg_save (spreg, all, true);
1178 if (ENABLE_WA_05000283 || ENABLE_WA_05000315)
1180 rtx chipid = GEN_INT (trunc_int_for_mode (0xFFC00014, SImode));
1181 rtx p5reg = gen_rtx_REG (Pmode, REG_P5);
1182 emit_insn (gen_movbi (bfin_cc_rtx, const1_rtx));
1183 emit_insn (gen_movsi_high (p5reg, chipid));
1184 emit_insn (gen_movsi_low (p5reg, p5reg, chipid));
1185 emit_insn (gen_dummy_load (p5reg, bfin_cc_rtx));
1188 if (lookup_attribute ("nesting", attrs))
1190 rtx srcreg = gen_rtx_REG (Pmode, (fkind == EXCPT_HANDLER ? REG_RETX
1191 : fkind == NMI_HANDLER ? REG_RETN
1193 insn = emit_move_insn (predec, srcreg);
1194 RTX_FRAME_RELATED_P (insn) = 1;
1197 do_link (spreg, frame_size, all);
1199 if (fkind == EXCPT_HANDLER)
1201 rtx r0reg = gen_rtx_REG (SImode, REG_R0);
1202 rtx r1reg = gen_rtx_REG (SImode, REG_R1);
1203 rtx r2reg = gen_rtx_REG (SImode, REG_R2);
1206 insn = emit_move_insn (r0reg, gen_rtx_REG (SImode, REG_SEQSTAT));
1207 insn = emit_insn (gen_ashrsi3 (r0reg, r0reg, GEN_INT (26)));
1208 insn = emit_insn (gen_ashlsi3 (r0reg, r0reg, GEN_INT (26)));
1209 insn = emit_move_insn (r1reg, spreg);
1210 insn = emit_move_insn (r2reg, gen_rtx_REG (Pmode, REG_FP));
1211 insn = emit_insn (gen_addsi3 (r2reg, r2reg, GEN_INT (8)));
1215 /* Generate an epilogue suitable for a function of kind FKIND. This is
1216 called for interrupt and exception handler epilogues.
1217 SPREG contains (reg:SI REG_SP). */
1220 expand_interrupt_handler_epilogue (rtx spreg, e_funkind fkind, bool all)
1222 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1223 rtx postinc1 = gen_rtx_POST_INC (SImode, spreg);
1224 rtx postinc = gen_rtx_MEM (SImode, postinc1);
1226 /* A slightly crude technique to stop flow from trying to delete "dead"
1228 MEM_VOLATILE_P (postinc) = 1;
1230 do_unlink (spreg, get_frame_size (), all, 1);
1232 if (lookup_attribute ("nesting", attrs))
1234 rtx srcreg = gen_rtx_REG (Pmode, (fkind == EXCPT_HANDLER ? REG_RETX
1235 : fkind == NMI_HANDLER ? REG_RETN
1237 emit_move_insn (srcreg, postinc);
1240 /* If we're calling other functions, they won't save their call-clobbered
1241 registers, so we must save (and restore) everything here. */
1242 if (!current_function_is_leaf)
1245 expand_epilogue_reg_restore (spreg, all, true);
1247 /* Deallocate any space we left on the stack in case we needed to save the
1248 argument registers. */
1249 if (fkind == EXCPT_HANDLER)
1250 emit_insn (gen_addsi3 (spreg, spreg, GEN_INT (12)));
1252 emit_jump_insn (gen_return_internal (GEN_INT (fkind)));
1255 /* Used while emitting the prologue to generate code to load the correct value
1256 into the PIC register, which is passed in DEST. */
1259 bfin_load_pic_reg (rtx dest)
1261 struct cgraph_local_info *i = NULL;
1264 i = cgraph_local_info (current_function_decl);
1266 /* Functions local to the translation unit don't need to reload the
1267 pic reg, since the caller always passes a usable one. */
1269 return pic_offset_table_rtx;
1271 if (bfin_lib_id_given)
1272 addr = plus_constant (pic_offset_table_rtx, -4 - bfin_library_id * 4);
1274 addr = gen_rtx_PLUS (Pmode, pic_offset_table_rtx,
1275 gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx),
1276 UNSPEC_LIBRARY_OFFSET));
1277 insn = emit_insn (gen_movsi (dest, gen_rtx_MEM (Pmode, addr)));
1281 /* Generate RTL for the prologue of the current function. */
1284 bfin_expand_prologue (void)
1286 HOST_WIDE_INT frame_size = get_frame_size ();
1287 rtx spreg = gen_rtx_REG (Pmode, REG_SP);
1288 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
1289 rtx pic_reg_loaded = NULL_RTX;
1290 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1291 bool all = lookup_attribute ("saveall", attrs) != NULL_TREE;
1293 if (fkind != SUBROUTINE)
1295 expand_interrupt_handler_prologue (spreg, fkind, all);
1299 if (crtl->limit_stack
1300 || (TARGET_STACK_CHECK_L1
1301 && !DECL_NO_LIMIT_STACK (current_function_decl)))
1303 HOST_WIDE_INT offset
1304 = bfin_initial_elimination_offset (ARG_POINTER_REGNUM,
1305 STACK_POINTER_REGNUM);
1306 rtx lim = crtl->limit_stack ? stack_limit_rtx : NULL_RTX;
1307 rtx p2reg = gen_rtx_REG (Pmode, REG_P2);
1311 emit_move_insn (p2reg, gen_int_mode (0xFFB00000, SImode));
1312 emit_move_insn (p2reg, gen_rtx_MEM (Pmode, p2reg));
1315 if (GET_CODE (lim) == SYMBOL_REF)
1317 if (TARGET_ID_SHARED_LIBRARY)
1319 rtx p1reg = gen_rtx_REG (Pmode, REG_P1);
1321 pic_reg_loaded = bfin_load_pic_reg (p2reg);
1322 val = legitimize_pic_address (stack_limit_rtx, p1reg,
1324 emit_move_insn (p1reg, val);
1325 frame_related_constant_load (p2reg, offset, FALSE);
1326 emit_insn (gen_addsi3 (p2reg, p2reg, p1reg));
1331 rtx limit = plus_constant (lim, offset);
1332 emit_move_insn (p2reg, limit);
1339 emit_move_insn (p2reg, lim);
1340 add_to_reg (p2reg, offset, 0, 0);
1343 emit_insn (gen_compare_lt (bfin_cc_rtx, spreg, lim));
1344 emit_insn (gen_trapifcc ());
1346 expand_prologue_reg_save (spreg, all, false);
1348 do_link (spreg, frame_size, false);
1350 if (TARGET_ID_SHARED_LIBRARY
1352 && (crtl->uses_pic_offset_table
1353 || !current_function_is_leaf))
1354 bfin_load_pic_reg (pic_offset_table_rtx);
1357 /* Generate RTL for the epilogue of the current function. NEED_RETURN is zero
1358 if this is for a sibcall. EH_RETURN is nonzero if we're expanding an
1359 eh_return pattern. SIBCALL_P is true if this is a sibcall epilogue,
1363 bfin_expand_epilogue (int need_return, int eh_return, bool sibcall_p)
1365 rtx spreg = gen_rtx_REG (Pmode, REG_SP);
1366 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
1367 int e = sibcall_p ? -1 : 1;
1368 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1369 bool all = lookup_attribute ("saveall", attrs) != NULL_TREE;
1371 if (fkind != SUBROUTINE)
1373 expand_interrupt_handler_epilogue (spreg, fkind, all);
1377 do_unlink (spreg, get_frame_size (), false, e);
1379 expand_epilogue_reg_restore (spreg, all, false);
1381 /* Omit the return insn if this is for a sibcall. */
1386 emit_insn (gen_addsi3 (spreg, spreg, gen_rtx_REG (Pmode, REG_P2)));
1388 emit_jump_insn (gen_return_internal (GEN_INT (SUBROUTINE)));
1391 /* Return nonzero if register OLD_REG can be renamed to register NEW_REG. */
1394 bfin_hard_regno_rename_ok (unsigned int old_reg ATTRIBUTE_UNUSED,
1395 unsigned int new_reg)
1397 /* Interrupt functions can only use registers that have already been
1398 saved by the prologue, even if they would normally be
1401 if (funkind (TREE_TYPE (current_function_decl)) != SUBROUTINE
1402 && !df_regs_ever_live_p (new_reg))
1408 /* Return the value of the return address for the frame COUNT steps up
1409 from the current frame, after the prologue.
1410 We punt for everything but the current frame by returning const0_rtx. */
1413 bfin_return_addr_rtx (int count)
1418 return get_hard_reg_initial_val (Pmode, REG_RETS);
1421 /* Try machine-dependent ways of modifying an illegitimate address X
1422 to be legitimate. If we find one, return the new, valid address,
1423 otherwise return NULL_RTX.
1425 OLDX is the address as it was before break_out_memory_refs was called.
1426 In some cases it is useful to look at this to decide what needs to be done.
1428 MODE is the mode of the memory reference. */
1431 legitimize_address (rtx x ATTRIBUTE_UNUSED, rtx oldx ATTRIBUTE_UNUSED,
1432 enum machine_mode mode ATTRIBUTE_UNUSED)
1438 bfin_delegitimize_address (rtx orig_x)
1442 if (GET_CODE (x) != MEM)
1446 if (GET_CODE (x) == PLUS
1447 && GET_CODE (XEXP (x, 1)) == UNSPEC
1448 && XINT (XEXP (x, 1), 1) == UNSPEC_MOVE_PIC
1449 && GET_CODE (XEXP (x, 0)) == REG
1450 && REGNO (XEXP (x, 0)) == PIC_OFFSET_TABLE_REGNUM)
1451 return XVECEXP (XEXP (x, 1), 0, 0);
1456 /* This predicate is used to compute the length of a load/store insn.
1457 OP is a MEM rtx, we return nonzero if its addressing mode requires a
1458 32-bit instruction. */
1461 effective_address_32bit_p (rtx op, enum machine_mode mode)
1463 HOST_WIDE_INT offset;
1465 mode = GET_MODE (op);
1468 if (GET_CODE (op) != PLUS)
1470 gcc_assert (REG_P (op) || GET_CODE (op) == POST_INC
1471 || GET_CODE (op) == PRE_DEC || GET_CODE (op) == POST_DEC);
1475 if (GET_CODE (XEXP (op, 1)) == UNSPEC)
1478 offset = INTVAL (XEXP (op, 1));
1480 /* All byte loads use a 16-bit offset. */
1481 if (GET_MODE_SIZE (mode) == 1)
1484 if (GET_MODE_SIZE (mode) == 4)
1486 /* Frame pointer relative loads can use a negative offset, all others
1487 are restricted to a small positive one. */
1488 if (XEXP (op, 0) == frame_pointer_rtx)
1489 return offset < -128 || offset > 60;
1490 return offset < 0 || offset > 60;
1493 /* Must be HImode now. */
1494 return offset < 0 || offset > 30;
1497 /* Returns true if X is a memory reference using an I register. */
1499 bfin_dsp_memref_p (rtx x)
1504 if (GET_CODE (x) == POST_INC || GET_CODE (x) == PRE_INC
1505 || GET_CODE (x) == POST_DEC || GET_CODE (x) == PRE_DEC)
1510 /* Return cost of the memory address ADDR.
1511 All addressing modes are equally cheap on the Blackfin. */
1514 bfin_address_cost (rtx addr ATTRIBUTE_UNUSED, bool speed ATTRIBUTE_UNUSED)
1519 /* Subroutine of print_operand; used to print a memory reference X to FILE. */
1522 print_address_operand (FILE *file, rtx x)
1524 switch (GET_CODE (x))
1527 output_address (XEXP (x, 0));
1528 fprintf (file, "+");
1529 output_address (XEXP (x, 1));
1533 fprintf (file, "--");
1534 output_address (XEXP (x, 0));
1537 output_address (XEXP (x, 0));
1538 fprintf (file, "++");
1541 output_address (XEXP (x, 0));
1542 fprintf (file, "--");
1546 gcc_assert (GET_CODE (x) != MEM);
1547 print_operand (file, x, 0);
1552 /* Adding intp DImode support by Tony
1558 print_operand (FILE *file, rtx x, char code)
1560 enum machine_mode mode;
1564 if (GET_MODE (current_output_insn) == SImode)
1565 fprintf (file, " ||");
1567 fprintf (file, ";");
1571 mode = GET_MODE (x);
1576 switch (GET_CODE (x))
1579 fprintf (file, "e");
1582 fprintf (file, "ne");
1585 fprintf (file, "g");
1588 fprintf (file, "l");
1591 fprintf (file, "ge");
1594 fprintf (file, "le");
1597 fprintf (file, "g");
1600 fprintf (file, "l");
1603 fprintf (file, "ge");
1606 fprintf (file, "le");
1609 output_operand_lossage ("invalid %%j value");
1613 case 'J': /* reverse logic */
1614 switch (GET_CODE(x))
1617 fprintf (file, "ne");
1620 fprintf (file, "e");
1623 fprintf (file, "le");
1626 fprintf (file, "ge");
1629 fprintf (file, "l");
1632 fprintf (file, "g");
1635 fprintf (file, "le");
1638 fprintf (file, "ge");
1641 fprintf (file, "l");
1644 fprintf (file, "g");
1647 output_operand_lossage ("invalid %%J value");
1652 switch (GET_CODE (x))
1658 fprintf (file, "%s", short_reg_names[REGNO (x)]);
1660 output_operand_lossage ("invalid operand for code '%c'", code);
1662 else if (code == 'd')
1665 fprintf (file, "%s", high_reg_names[REGNO (x)]);
1667 output_operand_lossage ("invalid operand for code '%c'", code);
1669 else if (code == 'w')
1671 if (REGNO (x) == REG_A0 || REGNO (x) == REG_A1)
1672 fprintf (file, "%s.w", reg_names[REGNO (x)]);
1674 output_operand_lossage ("invalid operand for code '%c'", code);
1676 else if (code == 'x')
1678 if (REGNO (x) == REG_A0 || REGNO (x) == REG_A1)
1679 fprintf (file, "%s.x", reg_names[REGNO (x)]);
1681 output_operand_lossage ("invalid operand for code '%c'", code);
1683 else if (code == 'v')
1685 if (REGNO (x) == REG_A0)
1686 fprintf (file, "AV0");
1687 else if (REGNO (x) == REG_A1)
1688 fprintf (file, "AV1");
1690 output_operand_lossage ("invalid operand for code '%c'", code);
1692 else if (code == 'D')
1694 if (D_REGNO_P (REGNO (x)))
1695 fprintf (file, "%s", dregs_pair_names[REGNO (x)]);
1697 output_operand_lossage ("invalid operand for code '%c'", code);
1699 else if (code == 'H')
1701 if ((mode == DImode || mode == DFmode) && REG_P (x))
1702 fprintf (file, "%s", reg_names[REGNO (x) + 1]);
1704 output_operand_lossage ("invalid operand for code '%c'", code);
1706 else if (code == 'T')
1708 if (D_REGNO_P (REGNO (x)))
1709 fprintf (file, "%s", byte_reg_names[REGNO (x)]);
1711 output_operand_lossage ("invalid operand for code '%c'", code);
1714 fprintf (file, "%s", reg_names[REGNO (x)]);
1720 print_address_operand (file, x);
1732 fputs ("(FU)", file);
1735 fputs ("(T)", file);
1738 fputs ("(TFU)", file);
1741 fputs ("(W32)", file);
1744 fputs ("(IS)", file);
1747 fputs ("(IU)", file);
1750 fputs ("(IH)", file);
1753 fputs ("(M)", file);
1756 fputs ("(IS,M)", file);
1759 fputs ("(ISS2)", file);
1762 fputs ("(S2RND)", file);
1769 else if (code == 'b')
1771 if (INTVAL (x) == 0)
1773 else if (INTVAL (x) == 1)
1779 /* Moves to half registers with d or h modifiers always use unsigned
1781 else if (code == 'd')
1782 x = GEN_INT ((INTVAL (x) >> 16) & 0xffff);
1783 else if (code == 'h')
1784 x = GEN_INT (INTVAL (x) & 0xffff);
1785 else if (code == 'N')
1786 x = GEN_INT (-INTVAL (x));
1787 else if (code == 'X')
1788 x = GEN_INT (exact_log2 (0xffffffff & INTVAL (x)));
1789 else if (code == 'Y')
1790 x = GEN_INT (exact_log2 (0xffffffff & ~INTVAL (x)));
1791 else if (code == 'Z')
1792 /* Used for LINK insns. */
1793 x = GEN_INT (-8 - INTVAL (x));
1798 output_addr_const (file, x);
1802 output_operand_lossage ("invalid const_double operand");
1806 switch (XINT (x, 1))
1808 case UNSPEC_MOVE_PIC:
1809 output_addr_const (file, XVECEXP (x, 0, 0));
1810 fprintf (file, "@GOT");
1813 case UNSPEC_MOVE_FDPIC:
1814 output_addr_const (file, XVECEXP (x, 0, 0));
1815 fprintf (file, "@GOT17M4");
1818 case UNSPEC_FUNCDESC_GOT17M4:
1819 output_addr_const (file, XVECEXP (x, 0, 0));
1820 fprintf (file, "@FUNCDESC_GOT17M4");
1823 case UNSPEC_LIBRARY_OFFSET:
1824 fprintf (file, "_current_shared_library_p5_offset_");
1833 output_addr_const (file, x);
1838 /* Argument support functions. */
1840 /* Initialize a variable CUM of type CUMULATIVE_ARGS
1841 for a call to a function whose data type is FNTYPE.
1842 For a library call, FNTYPE is 0.
1843 VDSP C Compiler manual, our ABI says that
1844 first 3 words of arguments will use R0, R1 and R2.
1848 init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype,
1849 rtx libname ATTRIBUTE_UNUSED)
1851 static CUMULATIVE_ARGS zero_cum;
1855 /* Set up the number of registers to use for passing arguments. */
1857 cum->nregs = max_arg_registers;
1858 cum->arg_regs = arg_regs;
1860 cum->call_cookie = CALL_NORMAL;
1861 /* Check for a longcall attribute. */
1862 if (fntype && lookup_attribute ("shortcall", TYPE_ATTRIBUTES (fntype)))
1863 cum->call_cookie |= CALL_SHORT;
1864 else if (fntype && lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype)))
1865 cum->call_cookie |= CALL_LONG;
1870 /* Update the data in CUM to advance over an argument
1871 of mode MODE and data type TYPE.
1872 (TYPE is null for libcalls where that information may not be available.) */
1875 function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
1876 int named ATTRIBUTE_UNUSED)
1878 int count, bytes, words;
1880 bytes = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
1881 words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
1883 cum->words += words;
1884 cum->nregs -= words;
1886 if (cum->nregs <= 0)
1889 cum->arg_regs = NULL;
1893 for (count = 1; count <= words; count++)
1900 /* Define where to put the arguments to a function.
1901 Value is zero to push the argument on the stack,
1902 or a hard register in which to store the argument.
1904 MODE is the argument's machine mode.
1905 TYPE is the data type of the argument (as a tree).
1906 This is null for libcalls where that information may
1908 CUM is a variable of type CUMULATIVE_ARGS which gives info about
1909 the preceding args and about the function being called.
1910 NAMED is nonzero if this argument is a named parameter
1911 (otherwise it is an extra parameter matching an ellipsis). */
1914 function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
1915 int named ATTRIBUTE_UNUSED)
1918 = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
1920 if (mode == VOIDmode)
1921 /* Compute operand 2 of the call insn. */
1922 return GEN_INT (cum->call_cookie);
1928 return gen_rtx_REG (mode, *(cum->arg_regs));
1933 /* For an arg passed partly in registers and partly in memory,
1934 this is the number of bytes passed in registers.
1935 For args passed entirely in registers or entirely in memory, zero.
1937 Refer VDSP C Compiler manual, our ABI.
1938 First 3 words are in registers. So, if an argument is larger
1939 than the registers available, it will span the register and
1943 bfin_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode,
1944 tree type ATTRIBUTE_UNUSED,
1945 bool named ATTRIBUTE_UNUSED)
1948 = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
1949 int bytes_left = cum->nregs * UNITS_PER_WORD;
1954 if (bytes_left == 0)
1956 if (bytes > bytes_left)
1961 /* Variable sized types are passed by reference. */
1964 bfin_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
1965 enum machine_mode mode ATTRIBUTE_UNUSED,
1966 const_tree type, bool named ATTRIBUTE_UNUSED)
1968 return type && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST;
1971 /* Decide whether a type should be returned in memory (true)
1972 or in a register (false). This is called by the macro
1973 TARGET_RETURN_IN_MEMORY. */
1976 bfin_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
1978 int size = int_size_in_bytes (type);
1979 return size > 2 * UNITS_PER_WORD || size == -1;
1982 /* Register in which address to store a structure value
1983 is passed to a function. */
1985 bfin_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
1986 int incoming ATTRIBUTE_UNUSED)
1988 return gen_rtx_REG (Pmode, REG_P0);
1991 /* Return true when register may be used to pass function parameters. */
1994 function_arg_regno_p (int n)
1997 for (i = 0; arg_regs[i] != -1; i++)
1998 if (n == arg_regs[i])
2003 /* Returns 1 if OP contains a symbol reference */
2006 symbolic_reference_mentioned_p (rtx op)
2008 register const char *fmt;
2011 if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF)
2014 fmt = GET_RTX_FORMAT (GET_CODE (op));
2015 for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
2021 for (j = XVECLEN (op, i) - 1; j >= 0; j--)
2022 if (symbolic_reference_mentioned_p (XVECEXP (op, i, j)))
2026 else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i)))
2033 /* Decide whether we can make a sibling call to a function. DECL is the
2034 declaration of the function being targeted by the call and EXP is the
2035 CALL_EXPR representing the call. */
2038 bfin_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED,
2039 tree exp ATTRIBUTE_UNUSED)
2041 struct cgraph_local_info *this_func, *called_func;
2042 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
2043 if (fkind != SUBROUTINE)
2045 if (!TARGET_ID_SHARED_LIBRARY || TARGET_SEP_DATA)
2048 /* When compiling for ID shared libraries, can't sibcall a local function
2049 from a non-local function, because the local function thinks it does
2050 not need to reload P5 in the prologue, but the sibcall wil pop P5 in the
2051 sibcall epilogue, and we end up with the wrong value in P5. */
2054 /* Not enough information. */
2057 this_func = cgraph_local_info (current_function_decl);
2058 called_func = cgraph_local_info (decl);
2059 return !called_func->local || this_func->local;
2062 /* Emit RTL insns to initialize the variable parts of a trampoline at
2063 TRAMP. FNADDR is an RTX for the address of the function's pure
2064 code. CXT is an RTX for the static chain value for the function. */
2067 initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt)
2069 rtx t1 = copy_to_reg (fnaddr);
2070 rtx t2 = copy_to_reg (cxt);
2076 rtx a = memory_address (Pmode, plus_constant (tramp, 8));
2077 addr = memory_address (Pmode, tramp);
2078 emit_move_insn (gen_rtx_MEM (SImode, addr), a);
2082 addr = memory_address (Pmode, plus_constant (tramp, i + 2));
2083 emit_move_insn (gen_rtx_MEM (HImode, addr), gen_lowpart (HImode, t1));
2084 emit_insn (gen_ashrsi3 (t1, t1, GEN_INT (16)));
2085 addr = memory_address (Pmode, plus_constant (tramp, i + 6));
2086 emit_move_insn (gen_rtx_MEM (HImode, addr), gen_lowpart (HImode, t1));
2088 addr = memory_address (Pmode, plus_constant (tramp, i + 10));
2089 emit_move_insn (gen_rtx_MEM (HImode, addr), gen_lowpart (HImode, t2));
2090 emit_insn (gen_ashrsi3 (t2, t2, GEN_INT (16)));
2091 addr = memory_address (Pmode, plus_constant (tramp, i + 14));
2092 emit_move_insn (gen_rtx_MEM (HImode, addr), gen_lowpart (HImode, t2));
2095 /* Emit insns to move operands[1] into operands[0]. */
2098 emit_pic_move (rtx *operands, enum machine_mode mode ATTRIBUTE_UNUSED)
2100 rtx temp = reload_in_progress ? operands[0] : gen_reg_rtx (Pmode);
2102 gcc_assert (!TARGET_FDPIC || !(reload_in_progress || reload_completed));
2103 if (GET_CODE (operands[0]) == MEM && SYMBOLIC_CONST (operands[1]))
2104 operands[1] = force_reg (SImode, operands[1]);
2106 operands[1] = legitimize_pic_address (operands[1], temp,
2107 TARGET_FDPIC ? OUR_FDPIC_REG
2108 : pic_offset_table_rtx);
2111 /* Expand a move operation in mode MODE. The operands are in OPERANDS.
2112 Returns true if no further code must be generated, false if the caller
2113 should generate an insn to move OPERANDS[1] to OPERANDS[0]. */
2116 expand_move (rtx *operands, enum machine_mode mode)
2118 rtx op = operands[1];
2119 if ((TARGET_ID_SHARED_LIBRARY || TARGET_FDPIC)
2120 && SYMBOLIC_CONST (op))
2121 emit_pic_move (operands, mode);
2122 else if (mode == SImode && GET_CODE (op) == CONST
2123 && GET_CODE (XEXP (op, 0)) == PLUS
2124 && GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF
2125 && !bfin_legitimate_constant_p (op))
2127 rtx dest = operands[0];
2129 gcc_assert (!reload_in_progress && !reload_completed);
2131 op0 = force_reg (mode, XEXP (op, 0));
2133 if (!insn_data[CODE_FOR_addsi3].operand[2].predicate (op1, mode))
2134 op1 = force_reg (mode, op1);
2135 if (GET_CODE (dest) == MEM)
2136 dest = gen_reg_rtx (mode);
2137 emit_insn (gen_addsi3 (dest, op0, op1));
2138 if (dest == operands[0])
2142 /* Don't generate memory->memory or constant->memory moves, go through a
2144 else if ((reload_in_progress | reload_completed) == 0
2145 && GET_CODE (operands[0]) == MEM
2146 && GET_CODE (operands[1]) != REG)
2147 operands[1] = force_reg (mode, operands[1]);
2151 /* Split one or more DImode RTL references into pairs of SImode
2152 references. The RTL can be REG, offsettable MEM, integer constant, or
2153 CONST_DOUBLE. "operands" is a pointer to an array of DImode RTL to
2154 split and "num" is its length. lo_half and hi_half are output arrays
2155 that parallel "operands". */
2158 split_di (rtx operands[], int num, rtx lo_half[], rtx hi_half[])
2162 rtx op = operands[num];
2164 /* simplify_subreg refuse to split volatile memory addresses,
2165 but we still have to handle it. */
2166 if (GET_CODE (op) == MEM)
2168 lo_half[num] = adjust_address (op, SImode, 0);
2169 hi_half[num] = adjust_address (op, SImode, 4);
2173 lo_half[num] = simplify_gen_subreg (SImode, op,
2174 GET_MODE (op) == VOIDmode
2175 ? DImode : GET_MODE (op), 0);
2176 hi_half[num] = simplify_gen_subreg (SImode, op,
2177 GET_MODE (op) == VOIDmode
2178 ? DImode : GET_MODE (op), 4);
2184 bfin_longcall_p (rtx op, int call_cookie)
2186 gcc_assert (GET_CODE (op) == SYMBOL_REF);
2187 if (call_cookie & CALL_SHORT)
2189 if (call_cookie & CALL_LONG)
2191 if (TARGET_LONG_CALLS)
2196 /* Expand a call instruction. FNADDR is the call target, RETVAL the return value.
2197 COOKIE is a CONST_INT holding the call_cookie prepared init_cumulative_args.
2198 SIBCALL is nonzero if this is a sibling call. */
2201 bfin_expand_call (rtx retval, rtx fnaddr, rtx callarg1, rtx cookie, int sibcall)
2203 rtx use = NULL, call;
2204 rtx callee = XEXP (fnaddr, 0);
2205 int nelts = 2 + !!sibcall;
2207 rtx picreg = get_hard_reg_initial_val (SImode, FDPIC_REGNO);
2210 /* In an untyped call, we can get NULL for operand 2. */
2211 if (cookie == NULL_RTX)
2212 cookie = const0_rtx;
2214 /* Static functions and indirect calls don't need the pic register. */
2215 if (!TARGET_FDPIC && flag_pic
2216 && GET_CODE (callee) == SYMBOL_REF
2217 && !SYMBOL_REF_LOCAL_P (callee))
2218 use_reg (&use, pic_offset_table_rtx);
2222 int caller_has_l1_text, callee_has_l1_text;
2224 caller_has_l1_text = callee_has_l1_text = 0;
2226 if (lookup_attribute ("l1_text",
2227 DECL_ATTRIBUTES (cfun->decl)) != NULL_TREE)
2228 caller_has_l1_text = 1;
2230 if (GET_CODE (callee) == SYMBOL_REF
2231 && SYMBOL_REF_DECL (callee) && DECL_P (SYMBOL_REF_DECL (callee))
2234 DECL_ATTRIBUTES (SYMBOL_REF_DECL (callee))) != NULL_TREE)
2235 callee_has_l1_text = 1;
2237 if (GET_CODE (callee) != SYMBOL_REF
2238 || bfin_longcall_p (callee, INTVAL (cookie))
2239 || (GET_CODE (callee) == SYMBOL_REF
2240 && !SYMBOL_REF_LOCAL_P (callee)
2241 && TARGET_INLINE_PLT)
2242 || caller_has_l1_text != callee_has_l1_text
2243 || (caller_has_l1_text && callee_has_l1_text
2244 && (GET_CODE (callee) != SYMBOL_REF
2245 || !SYMBOL_REF_LOCAL_P (callee))))
2248 if (! address_operand (addr, Pmode))
2249 addr = force_reg (Pmode, addr);
2251 fnaddr = gen_reg_rtx (SImode);
2252 emit_insn (gen_load_funcdescsi (fnaddr, addr));
2253 fnaddr = gen_rtx_MEM (Pmode, fnaddr);
2255 picreg = gen_reg_rtx (SImode);
2256 emit_insn (gen_load_funcdescsi (picreg,
2257 plus_constant (addr, 4)));
2262 else if ((!register_no_elim_operand (callee, Pmode)
2263 && GET_CODE (callee) != SYMBOL_REF)
2264 || (GET_CODE (callee) == SYMBOL_REF
2265 && ((TARGET_ID_SHARED_LIBRARY && !TARGET_LEAF_ID_SHARED_LIBRARY)
2266 || bfin_longcall_p (callee, INTVAL (cookie)))))
2268 callee = copy_to_mode_reg (Pmode, callee);
2269 fnaddr = gen_rtx_MEM (Pmode, callee);
2271 call = gen_rtx_CALL (VOIDmode, fnaddr, callarg1);
2274 call = gen_rtx_SET (VOIDmode, retval, call);
2276 pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (nelts));
2278 XVECEXP (pat, 0, n++) = call;
2280 XVECEXP (pat, 0, n++) = gen_rtx_USE (VOIDmode, picreg);
2281 XVECEXP (pat, 0, n++) = gen_rtx_USE (VOIDmode, cookie);
2283 XVECEXP (pat, 0, n++) = gen_rtx_RETURN (VOIDmode);
2284 call = emit_call_insn (pat);
2286 CALL_INSN_FUNCTION_USAGE (call) = use;
2289 /* Return 1 if hard register REGNO can hold a value of machine-mode MODE. */
2292 hard_regno_mode_ok (int regno, enum machine_mode mode)
2294 /* Allow only dregs to store value of mode HI or QI */
2295 enum reg_class rclass = REGNO_REG_CLASS (regno);
2300 if (mode == V2HImode)
2301 return D_REGNO_P (regno);
2302 if (rclass == CCREGS)
2303 return mode == BImode;
2304 if (mode == PDImode || mode == V2PDImode)
2305 return regno == REG_A0 || regno == REG_A1;
2307 /* Allow all normal 32-bit regs, except REG_M3, in case regclass ever comes
2308 up with a bad register class (such as ALL_REGS) for DImode. */
2310 return regno < REG_M3;
2313 && TEST_HARD_REG_BIT (reg_class_contents[PROLOGUE_REGS], regno))
2316 return TEST_HARD_REG_BIT (reg_class_contents[MOST_REGS], regno);
2319 /* Implements target hook vector_mode_supported_p. */
2322 bfin_vector_mode_supported_p (enum machine_mode mode)
2324 return mode == V2HImode;
2327 /* Return the cost of moving data from a register in class CLASS1 to
2328 one in class CLASS2. A cost of 2 is the default. */
2331 bfin_register_move_cost (enum machine_mode mode,
2332 enum reg_class class1, enum reg_class class2)
2334 /* These need secondary reloads, so they're more expensive. */
2335 if ((class1 == CCREGS && !reg_class_subset_p (class2, DREGS))
2336 || (class2 == CCREGS && !reg_class_subset_p (class1, DREGS)))
2339 /* If optimizing for size, always prefer reg-reg over reg-memory moves. */
2343 if (GET_MODE_CLASS (mode) == MODE_INT)
2345 /* Discourage trying to use the accumulators. */
2346 if (TEST_HARD_REG_BIT (reg_class_contents[class1], REG_A0)
2347 || TEST_HARD_REG_BIT (reg_class_contents[class1], REG_A1)
2348 || TEST_HARD_REG_BIT (reg_class_contents[class2], REG_A0)
2349 || TEST_HARD_REG_BIT (reg_class_contents[class2], REG_A1))
2355 /* Return the cost of moving data of mode M between a
2356 register and memory. A value of 2 is the default; this cost is
2357 relative to those in `REGISTER_MOVE_COST'.
2359 ??? In theory L1 memory has single-cycle latency. We should add a switch
2360 that tells the compiler whether we expect to use only L1 memory for the
2361 program; it'll make the costs more accurate. */
2364 bfin_memory_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
2365 enum reg_class rclass,
2366 int in ATTRIBUTE_UNUSED)
2368 /* Make memory accesses slightly more expensive than any register-register
2369 move. Also, penalize non-DP registers, since they need secondary
2370 reloads to load and store. */
2371 if (! reg_class_subset_p (rclass, DPREGS))
2377 /* Inform reload about cases where moving X with a mode MODE to a register in
2378 RCLASS requires an extra scratch register. Return the class needed for the
2379 scratch register. */
2381 static enum reg_class
2382 bfin_secondary_reload (bool in_p, rtx x, enum reg_class rclass,
2383 enum machine_mode mode, secondary_reload_info *sri)
2385 /* If we have HImode or QImode, we can only use DREGS as secondary registers;
2386 in most other cases we can also use PREGS. */
2387 enum reg_class default_class = GET_MODE_SIZE (mode) >= 4 ? DPREGS : DREGS;
2388 enum reg_class x_class = NO_REGS;
2389 enum rtx_code code = GET_CODE (x);
2392 x = SUBREG_REG (x), code = GET_CODE (x);
2395 int regno = REGNO (x);
2396 if (regno >= FIRST_PSEUDO_REGISTER)
2397 regno = reg_renumber[regno];
2402 x_class = REGNO_REG_CLASS (regno);
2405 /* We can be asked to reload (plus (FP) (large_constant)) into a DREG.
2406 This happens as a side effect of register elimination, and we need
2407 a scratch register to do it. */
2408 if (fp_plus_const_operand (x, mode))
2410 rtx op2 = XEXP (x, 1);
2411 int large_constant_p = ! satisfies_constraint_Ks7 (op2);
2413 if (rclass == PREGS || rclass == PREGS_CLOBBERED)
2415 /* If destination is a DREG, we can do this without a scratch register
2416 if the constant is valid for an add instruction. */
2417 if ((rclass == DREGS || rclass == DPREGS)
2418 && ! large_constant_p)
2420 /* Reloading to anything other than a DREG? Use a PREG scratch
2422 sri->icode = CODE_FOR_reload_insi;
2426 /* Data can usually be moved freely between registers of most classes.
2427 AREGS are an exception; they can only move to or from another register
2428 in AREGS or one in DREGS. They can also be assigned the constant 0. */
2429 if (x_class == AREGS || x_class == EVEN_AREGS || x_class == ODD_AREGS)
2430 return (rclass == DREGS || rclass == AREGS || rclass == EVEN_AREGS
2431 || rclass == ODD_AREGS
2434 if (rclass == AREGS || rclass == EVEN_AREGS || rclass == ODD_AREGS)
2438 sri->icode = in_p ? CODE_FOR_reload_inpdi : CODE_FOR_reload_outpdi;
2442 if (x != const0_rtx && x_class != DREGS)
2450 /* CCREGS can only be moved from/to DREGS. */
2451 if (rclass == CCREGS && x_class != DREGS)
2453 if (x_class == CCREGS && rclass != DREGS)
2456 /* All registers other than AREGS can load arbitrary constants. The only
2457 case that remains is MEM. */
2459 if (! reg_class_subset_p (rclass, default_class))
2460 return default_class;
2465 /* Implement TARGET_HANDLE_OPTION. */
2468 bfin_handle_option (size_t code, const char *arg, int value)
2472 case OPT_mshared_library_id_:
2473 if (value > MAX_LIBRARY_ID)
2474 error ("-mshared-library-id=%s is not between 0 and %d",
2475 arg, MAX_LIBRARY_ID);
2476 bfin_lib_id_given = 1;
2485 while ((p = bfin_cpus[i].name) != NULL)
2487 if (strncmp (arg, p, strlen (p)) == 0)
2494 error ("-mcpu=%s is not valid", arg);
2498 bfin_cpu_type = bfin_cpus[i].type;
2500 q = arg + strlen (p);
2504 bfin_si_revision = bfin_cpus[i].si_revision;
2505 bfin_workarounds |= bfin_cpus[i].workarounds;
2507 else if (strcmp (q, "-none") == 0)
2508 bfin_si_revision = -1;
2509 else if (strcmp (q, "-any") == 0)
2511 bfin_si_revision = 0xffff;
2512 while (bfin_cpus[i].type == bfin_cpu_type)
2514 bfin_workarounds |= bfin_cpus[i].workarounds;
2520 unsigned int si_major, si_minor;
2523 rev_len = strlen (q);
2525 if (sscanf (q, "-%u.%u%n", &si_major, &si_minor, &n) != 2
2527 || si_major > 0xff || si_minor > 0xff)
2529 invalid_silicon_revision:
2530 error ("-mcpu=%s has invalid silicon revision", arg);
2534 bfin_si_revision = (si_major << 8) | si_minor;
2536 while (bfin_cpus[i].type == bfin_cpu_type
2537 && bfin_cpus[i].si_revision != bfin_si_revision)
2540 if (bfin_cpus[i].type != bfin_cpu_type)
2541 goto invalid_silicon_revision;
2543 bfin_workarounds |= bfin_cpus[i].workarounds;
2554 static struct machine_function *
2555 bfin_init_machine_status (void)
2557 struct machine_function *f;
2559 f = GGC_CNEW (struct machine_function);
2564 /* Implement the macro OVERRIDE_OPTIONS. */
2567 override_options (void)
2569 /* If processor type is not specified, enable all workarounds. */
2570 if (bfin_cpu_type == BFIN_CPU_UNKNOWN)
2574 for (i = 0; bfin_cpus[i].name != NULL; i++)
2575 bfin_workarounds |= bfin_cpus[i].workarounds;
2577 bfin_si_revision = 0xffff;
2580 if (bfin_csync_anomaly == 1)
2581 bfin_workarounds |= WA_SPECULATIVE_SYNCS;
2582 else if (bfin_csync_anomaly == 0)
2583 bfin_workarounds &= ~WA_SPECULATIVE_SYNCS;
2585 if (bfin_specld_anomaly == 1)
2586 bfin_workarounds |= WA_SPECULATIVE_LOADS;
2587 else if (bfin_specld_anomaly == 0)
2588 bfin_workarounds &= ~WA_SPECULATIVE_LOADS;
2590 if (TARGET_OMIT_LEAF_FRAME_POINTER)
2591 flag_omit_frame_pointer = 1;
2593 /* Library identification */
2594 if (bfin_lib_id_given && ! TARGET_ID_SHARED_LIBRARY)
2595 error ("-mshared-library-id= specified without -mid-shared-library");
2597 if (stack_limit_rtx && TARGET_STACK_CHECK_L1)
2598 error ("Can't use multiple stack checking methods together.");
2600 if (TARGET_ID_SHARED_LIBRARY && TARGET_FDPIC)
2601 error ("ID shared libraries and FD-PIC mode can't be used together.");
2603 /* Don't allow the user to specify -mid-shared-library and -msep-data
2604 together, as it makes little sense from a user's point of view... */
2605 if (TARGET_SEP_DATA && TARGET_ID_SHARED_LIBRARY)
2606 error ("cannot specify both -msep-data and -mid-shared-library");
2607 /* ... internally, however, it's nearly the same. */
2608 if (TARGET_SEP_DATA)
2609 target_flags |= MASK_ID_SHARED_LIBRARY | MASK_LEAF_ID_SHARED_LIBRARY;
2611 if (TARGET_ID_SHARED_LIBRARY && flag_pic == 0)
2614 /* There is no single unaligned SI op for PIC code. Sometimes we
2615 need to use ".4byte" and sometimes we need to use ".picptr".
2616 See bfin_assemble_integer for details. */
2618 targetm.asm_out.unaligned_op.si = 0;
2620 /* Silently turn off flag_pic if not doing FDPIC or ID shared libraries,
2621 since we don't support it and it'll just break. */
2622 if (flag_pic && !TARGET_FDPIC && !TARGET_ID_SHARED_LIBRARY)
2625 if (TARGET_MULTICORE && bfin_cpu_type != BFIN_CPU_BF561)
2626 error ("-mmulticore can only be used with BF561");
2628 if (TARGET_COREA && !TARGET_MULTICORE)
2629 error ("-mcorea should be used with -mmulticore");
2631 if (TARGET_COREB && !TARGET_MULTICORE)
2632 error ("-mcoreb should be used with -mmulticore");
2634 if (TARGET_COREA && TARGET_COREB)
2635 error ("-mcorea and -mcoreb can't be used together");
2637 flag_schedule_insns = 0;
2639 /* Passes after sched2 can break the helpful TImode annotations that
2640 haifa-sched puts on every insn. Just do scheduling in reorg. */
2641 bfin_flag_schedule_insns2 = flag_schedule_insns_after_reload;
2642 flag_schedule_insns_after_reload = 0;
2644 init_machine_status = bfin_init_machine_status;
2647 /* Return the destination address of BRANCH.
2648 We need to use this instead of get_attr_length, because the
2649 cbranch_with_nops pattern conservatively sets its length to 6, and
2650 we still prefer to use shorter sequences. */
2653 branch_dest (rtx branch)
2657 rtx pat = PATTERN (branch);
2658 if (GET_CODE (pat) == PARALLEL)
2659 pat = XVECEXP (pat, 0, 0);
2660 dest = SET_SRC (pat);
2661 if (GET_CODE (dest) == IF_THEN_ELSE)
2662 dest = XEXP (dest, 1);
2663 dest = XEXP (dest, 0);
2664 dest_uid = INSN_UID (dest);
2665 return INSN_ADDRESSES (dest_uid);
2668 /* Return nonzero if INSN is annotated with a REG_BR_PROB note that indicates
2669 it's a branch that's predicted taken. */
2672 cbranch_predicted_taken_p (rtx insn)
2674 rtx x = find_reg_note (insn, REG_BR_PROB, 0);
2678 int pred_val = INTVAL (XEXP (x, 0));
2680 return pred_val >= REG_BR_PROB_BASE / 2;
2686 /* Templates for use by asm_conditional_branch. */
2688 static const char *ccbranch_templates[][3] = {
2689 { "if !cc jump %3;", "if cc jump 4 (bp); jump.s %3;", "if cc jump 6 (bp); jump.l %3;" },
2690 { "if cc jump %3;", "if !cc jump 4 (bp); jump.s %3;", "if !cc jump 6 (bp); jump.l %3;" },
2691 { "if !cc jump %3 (bp);", "if cc jump 4; jump.s %3;", "if cc jump 6; jump.l %3;" },
2692 { "if cc jump %3 (bp);", "if !cc jump 4; jump.s %3;", "if !cc jump 6; jump.l %3;" },
2695 /* Output INSN, which is a conditional branch instruction with operands
2698 We deal with the various forms of conditional branches that can be generated
2699 by bfin_reorg to prevent the hardware from doing speculative loads, by
2700 - emitting a sufficient number of nops, if N_NOPS is nonzero, or
2701 - always emitting the branch as predicted taken, if PREDICT_TAKEN is true.
2702 Either of these is only necessary if the branch is short, otherwise the
2703 template we use ends in an unconditional jump which flushes the pipeline
2707 asm_conditional_branch (rtx insn, rtx *operands, int n_nops, int predict_taken)
2709 int offset = branch_dest (insn) - INSN_ADDRESSES (INSN_UID (insn));
2710 /* Note : offset for instructions like if cc jmp; jump.[sl] offset
2711 is to be taken from start of if cc rather than jump.
2712 Range for jump.s is (-4094, 4096) instead of (-4096, 4094)
2714 int len = (offset >= -1024 && offset <= 1022 ? 0
2715 : offset >= -4094 && offset <= 4096 ? 1
2717 int bp = predict_taken && len == 0 ? 1 : cbranch_predicted_taken_p (insn);
2718 int idx = (bp << 1) | (GET_CODE (operands[0]) == EQ ? BRF : BRT);
2719 output_asm_insn (ccbranch_templates[idx][len], operands);
2720 gcc_assert (n_nops == 0 || !bp);
2722 while (n_nops-- > 0)
2723 output_asm_insn ("nop;", NULL);
2726 /* Emit rtl for a comparison operation CMP in mode MODE. Operands have been
2727 stored in bfin_compare_op0 and bfin_compare_op1 already. */
2730 bfin_gen_compare (rtx cmp, enum machine_mode mode ATTRIBUTE_UNUSED)
2732 enum rtx_code code1, code2;
2733 rtx op0 = bfin_compare_op0, op1 = bfin_compare_op1;
2734 rtx tem = bfin_cc_rtx;
2735 enum rtx_code code = GET_CODE (cmp);
2737 /* If we have a BImode input, then we already have a compare result, and
2738 do not need to emit another comparison. */
2739 if (GET_MODE (op0) == BImode)
2741 gcc_assert ((code == NE || code == EQ) && op1 == const0_rtx);
2742 tem = op0, code2 = code;
2747 /* bfin has these conditions */
2757 code1 = reverse_condition (code);
2761 emit_insn (gen_rtx_SET (BImode, tem,
2762 gen_rtx_fmt_ee (code1, BImode, op0, op1)));
2765 return gen_rtx_fmt_ee (code2, BImode, tem, CONST0_RTX (BImode));
2768 /* Return nonzero iff C has exactly one bit set if it is interpreted
2769 as a 32-bit constant. */
2772 log2constp (unsigned HOST_WIDE_INT c)
2775 return c != 0 && (c & (c-1)) == 0;
2778 /* Returns the number of consecutive least significant zeros in the binary
2779 representation of *V.
2780 We modify *V to contain the original value arithmetically shifted right by
2781 the number of zeroes. */
2784 shiftr_zero (HOST_WIDE_INT *v)
2786 unsigned HOST_WIDE_INT tmp = *v;
2787 unsigned HOST_WIDE_INT sgn;
2793 sgn = tmp & ((unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1));
2794 while ((tmp & 0x1) == 0 && n <= 32)
2796 tmp = (tmp >> 1) | sgn;
2803 /* After reload, split the load of an immediate constant. OPERANDS are the
2804 operands of the movsi_insn pattern which we are splitting. We return
2805 nonzero if we emitted a sequence to load the constant, zero if we emitted
2806 nothing because we want to use the splitter's default sequence. */
2809 split_load_immediate (rtx operands[])
2811 HOST_WIDE_INT val = INTVAL (operands[1]);
2813 HOST_WIDE_INT shifted = val;
2814 HOST_WIDE_INT shifted_compl = ~val;
2815 int num_zero = shiftr_zero (&shifted);
2816 int num_compl_zero = shiftr_zero (&shifted_compl);
2817 unsigned int regno = REGNO (operands[0]);
2819 /* This case takes care of single-bit set/clear constants, which we could
2820 also implement with BITSET/BITCLR. */
2822 && shifted >= -32768 && shifted < 65536
2823 && (D_REGNO_P (regno)
2824 || (regno >= REG_P0 && regno <= REG_P7 && num_zero <= 2)))
2826 emit_insn (gen_movsi (operands[0], GEN_INT (shifted)));
2827 emit_insn (gen_ashlsi3 (operands[0], operands[0], GEN_INT (num_zero)));
2832 tmp |= -(tmp & 0x8000);
2834 /* If high word has one bit set or clear, try to use a bit operation. */
2835 if (D_REGNO_P (regno))
2837 if (log2constp (val & 0xFFFF0000))
2839 emit_insn (gen_movsi (operands[0], GEN_INT (val & 0xFFFF)));
2840 emit_insn (gen_iorsi3 (operands[0], operands[0], GEN_INT (val & 0xFFFF0000)));
2843 else if (log2constp (val | 0xFFFF) && (val & 0x8000) != 0)
2845 emit_insn (gen_movsi (operands[0], GEN_INT (tmp)));
2846 emit_insn (gen_andsi3 (operands[0], operands[0], GEN_INT (val | 0xFFFF)));
2850 if (D_REGNO_P (regno))
2852 if (tmp >= -64 && tmp <= 63)
2854 emit_insn (gen_movsi (operands[0], GEN_INT (tmp)));
2855 emit_insn (gen_movstricthi_high (operands[0], GEN_INT (val & -65536)));
2859 if ((val & 0xFFFF0000) == 0)
2861 emit_insn (gen_movsi (operands[0], const0_rtx));
2862 emit_insn (gen_movsi_low (operands[0], operands[0], operands[1]));
2866 if ((val & 0xFFFF0000) == 0xFFFF0000)
2868 emit_insn (gen_movsi (operands[0], constm1_rtx));
2869 emit_insn (gen_movsi_low (operands[0], operands[0], operands[1]));
2874 /* Need DREGs for the remaining case. */
2879 && num_compl_zero && shifted_compl >= -64 && shifted_compl <= 63)
2881 /* If optimizing for size, generate a sequence that has more instructions
2883 emit_insn (gen_movsi (operands[0], GEN_INT (shifted_compl)));
2884 emit_insn (gen_ashlsi3 (operands[0], operands[0],
2885 GEN_INT (num_compl_zero)));
2886 emit_insn (gen_one_cmplsi2 (operands[0], operands[0]));
2892 /* Return true if the legitimate memory address for a memory operand of mode
2893 MODE. Return false if not. */
2896 bfin_valid_add (enum machine_mode mode, HOST_WIDE_INT value)
2898 unsigned HOST_WIDE_INT v = value > 0 ? value : -value;
2899 int sz = GET_MODE_SIZE (mode);
2900 int shift = sz == 1 ? 0 : sz == 2 ? 1 : 2;
2901 /* The usual offsettable_memref machinery doesn't work so well for this
2902 port, so we deal with the problem here. */
2903 if (value > 0 && sz == 8)
2905 return (v & ~(0x7fff << shift)) == 0;
2909 bfin_valid_reg_p (unsigned int regno, int strict, enum machine_mode mode,
2910 enum rtx_code outer_code)
2913 return REGNO_OK_FOR_BASE_STRICT_P (regno, mode, outer_code, SCRATCH);
2915 return REGNO_OK_FOR_BASE_NONSTRICT_P (regno, mode, outer_code, SCRATCH);
2919 bfin_legitimate_address_p (enum machine_mode mode, rtx x, int strict)
2921 switch (GET_CODE (x)) {
2923 if (bfin_valid_reg_p (REGNO (x), strict, mode, MEM))
2927 if (REG_P (XEXP (x, 0))
2928 && bfin_valid_reg_p (REGNO (XEXP (x, 0)), strict, mode, PLUS)
2929 && ((GET_CODE (XEXP (x, 1)) == UNSPEC && mode == SImode)
2930 || (GET_CODE (XEXP (x, 1)) == CONST_INT
2931 && bfin_valid_add (mode, INTVAL (XEXP (x, 1))))))
2936 if (LEGITIMATE_MODE_FOR_AUTOINC_P (mode)
2937 && REG_P (XEXP (x, 0))
2938 && bfin_valid_reg_p (REGNO (XEXP (x, 0)), strict, mode, POST_INC))
2941 if (LEGITIMATE_MODE_FOR_AUTOINC_P (mode)
2942 && XEXP (x, 0) == stack_pointer_rtx
2943 && REG_P (XEXP (x, 0))
2944 && bfin_valid_reg_p (REGNO (XEXP (x, 0)), strict, mode, PRE_DEC))
2953 /* Decide whether we can force certain constants to memory. If we
2954 decide we can't, the caller should be able to cope with it in
2958 bfin_cannot_force_const_mem (rtx x ATTRIBUTE_UNUSED)
2960 /* We have only one class of non-legitimate constants, and our movsi
2961 expander knows how to handle them. Dropping these constants into the
2962 data section would only shift the problem - we'd still get relocs
2963 outside the object, in the data section rather than the text section. */
2967 /* Ensure that for any constant of the form symbol + offset, the offset
2968 remains within the object. Any other constants are ok.
2969 This ensures that flat binaries never have to deal with relocations
2970 crossing section boundaries. */
2973 bfin_legitimate_constant_p (rtx x)
2976 HOST_WIDE_INT offset;
2978 if (GET_CODE (x) != CONST)
2982 gcc_assert (GET_CODE (x) == PLUS);
2986 if (GET_CODE (sym) != SYMBOL_REF
2987 || GET_CODE (x) != CONST_INT)
2989 offset = INTVAL (x);
2991 if (SYMBOL_REF_DECL (sym) == 0)
2994 || offset >= int_size_in_bytes (TREE_TYPE (SYMBOL_REF_DECL (sym))))
3001 bfin_rtx_costs (rtx x, int code, int outer_code, int *total, bool speed)
3003 int cost2 = COSTS_N_INSNS (1);
3009 if (outer_code == SET || outer_code == PLUS)
3010 *total = satisfies_constraint_Ks7 (x) ? 0 : cost2;
3011 else if (outer_code == AND)
3012 *total = log2constp (~INTVAL (x)) ? 0 : cost2;
3013 else if (outer_code == LE || outer_code == LT || outer_code == EQ)
3014 *total = (INTVAL (x) >= -4 && INTVAL (x) <= 3) ? 0 : cost2;
3015 else if (outer_code == LEU || outer_code == LTU)
3016 *total = (INTVAL (x) >= 0 && INTVAL (x) <= 7) ? 0 : cost2;
3017 else if (outer_code == MULT)
3018 *total = (INTVAL (x) == 2 || INTVAL (x) == 4) ? 0 : cost2;
3019 else if (outer_code == ASHIFT && (INTVAL (x) == 1 || INTVAL (x) == 2))
3021 else if (outer_code == ASHIFT || outer_code == ASHIFTRT
3022 || outer_code == LSHIFTRT)
3023 *total = (INTVAL (x) >= 0 && INTVAL (x) <= 31) ? 0 : cost2;
3024 else if (outer_code == IOR || outer_code == XOR)
3025 *total = (INTVAL (x) & (INTVAL (x) - 1)) == 0 ? 0 : cost2;
3034 *total = COSTS_N_INSNS (2);
3040 if (GET_MODE (x) == SImode)
3042 if (GET_CODE (op0) == MULT
3043 && GET_CODE (XEXP (op0, 1)) == CONST_INT)
3045 HOST_WIDE_INT val = INTVAL (XEXP (op0, 1));
3046 if (val == 2 || val == 4)
3049 *total += rtx_cost (XEXP (op0, 0), outer_code, speed);
3050 *total += rtx_cost (op1, outer_code, speed);
3055 if (GET_CODE (op0) != REG
3056 && (GET_CODE (op0) != SUBREG || GET_CODE (SUBREG_REG (op0)) != REG))
3057 *total += rtx_cost (op0, SET, speed);
3058 #if 0 /* We'd like to do this for accuracy, but it biases the loop optimizer
3059 towards creating too many induction variables. */
3060 if (!reg_or_7bit_operand (op1, SImode))
3061 *total += rtx_cost (op1, SET, speed);
3064 else if (GET_MODE (x) == DImode)
3067 if (GET_CODE (op1) != CONST_INT
3068 || !satisfies_constraint_Ks7 (op1))
3069 *total += rtx_cost (op1, PLUS, speed);
3070 if (GET_CODE (op0) != REG
3071 && (GET_CODE (op0) != SUBREG || GET_CODE (SUBREG_REG (op0)) != REG))
3072 *total += rtx_cost (op0, PLUS, speed);
3077 if (GET_MODE (x) == DImode)
3086 if (GET_MODE (x) == DImode)
3093 if (GET_CODE (op0) != REG
3094 && (GET_CODE (op0) != SUBREG || GET_CODE (SUBREG_REG (op0)) != REG))
3095 *total += rtx_cost (op0, code, speed);
3105 /* Handle special cases of IOR: rotates, ALIGN insns, movstricthi_high. */
3108 if ((GET_CODE (op0) == LSHIFTRT && GET_CODE (op1) == ASHIFT)
3109 || (GET_CODE (op0) == ASHIFT && GET_CODE (op1) == ZERO_EXTEND)
3110 || (GET_CODE (op0) == ASHIFT && GET_CODE (op1) == LSHIFTRT)
3111 || (GET_CODE (op0) == AND && GET_CODE (op1) == CONST_INT))
3118 if (GET_CODE (op0) != REG
3119 && (GET_CODE (op0) != SUBREG || GET_CODE (SUBREG_REG (op0)) != REG))
3120 *total += rtx_cost (op0, code, speed);
3122 if (GET_MODE (x) == DImode)
3128 if (GET_MODE (x) != SImode)
3133 if (! rhs_andsi3_operand (XEXP (x, 1), SImode))
3134 *total += rtx_cost (XEXP (x, 1), code, speed);
3138 if (! regorlog2_operand (XEXP (x, 1), SImode))
3139 *total += rtx_cost (XEXP (x, 1), code, speed);
3146 if (outer_code == SET
3147 && XEXP (x, 1) == const1_rtx
3148 && GET_CODE (XEXP (x, 2)) == CONST_INT)
3164 if (GET_CODE (op0) == GET_CODE (op1)
3165 && (GET_CODE (op0) == ZERO_EXTEND
3166 || GET_CODE (op0) == SIGN_EXTEND))
3168 *total = COSTS_N_INSNS (1);
3169 op0 = XEXP (op0, 0);
3170 op1 = XEXP (op1, 0);
3173 *total = COSTS_N_INSNS (1);
3175 *total = COSTS_N_INSNS (3);
3177 if (GET_CODE (op0) != REG
3178 && (GET_CODE (op0) != SUBREG || GET_CODE (SUBREG_REG (op0)) != REG))
3179 *total += rtx_cost (op0, MULT, speed);
3180 if (GET_CODE (op1) != REG
3181 && (GET_CODE (op1) != SUBREG || GET_CODE (SUBREG_REG (op1)) != REG))
3182 *total += rtx_cost (op1, MULT, speed);
3188 *total = COSTS_N_INSNS (32);
3193 if (outer_code == SET)
3202 /* Used for communication between {push,pop}_multiple_operation (which
3203 we use not only as a predicate) and the corresponding output functions. */
3204 static int first_preg_to_save, first_dreg_to_save;
3205 static int n_regs_to_save;
3208 push_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
3210 int lastdreg = 8, lastpreg = 6;
3213 first_preg_to_save = lastpreg;
3214 first_dreg_to_save = lastdreg;
3215 for (i = 1, group = 0; i < XVECLEN (op, 0) - 1; i++)
3217 rtx t = XVECEXP (op, 0, i);
3221 if (GET_CODE (t) != SET)
3225 dest = SET_DEST (t);
3226 if (GET_CODE (dest) != MEM || ! REG_P (src))
3228 dest = XEXP (dest, 0);
3229 if (GET_CODE (dest) != PLUS
3230 || ! REG_P (XEXP (dest, 0))
3231 || REGNO (XEXP (dest, 0)) != REG_SP
3232 || GET_CODE (XEXP (dest, 1)) != CONST_INT
3233 || INTVAL (XEXP (dest, 1)) != -i * 4)
3236 regno = REGNO (src);
3239 if (D_REGNO_P (regno))
3242 first_dreg_to_save = lastdreg = regno - REG_R0;
3244 else if (regno >= REG_P0 && regno <= REG_P7)
3247 first_preg_to_save = lastpreg = regno - REG_P0;
3257 if (regno >= REG_P0 && regno <= REG_P7)
3260 first_preg_to_save = lastpreg = regno - REG_P0;
3262 else if (regno != REG_R0 + lastdreg + 1)
3267 else if (group == 2)
3269 if (regno != REG_P0 + lastpreg + 1)
3274 n_regs_to_save = 8 - first_dreg_to_save + 6 - first_preg_to_save;
3279 pop_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
3281 int lastdreg = 8, lastpreg = 6;
3284 for (i = 1, group = 0; i < XVECLEN (op, 0); i++)
3286 rtx t = XVECEXP (op, 0, i);
3290 if (GET_CODE (t) != SET)
3294 dest = SET_DEST (t);
3295 if (GET_CODE (src) != MEM || ! REG_P (dest))
3297 src = XEXP (src, 0);
3301 if (! REG_P (src) || REGNO (src) != REG_SP)
3304 else if (GET_CODE (src) != PLUS
3305 || ! REG_P (XEXP (src, 0))
3306 || REGNO (XEXP (src, 0)) != REG_SP
3307 || GET_CODE (XEXP (src, 1)) != CONST_INT
3308 || INTVAL (XEXP (src, 1)) != (i - 1) * 4)
3311 regno = REGNO (dest);
3314 if (regno == REG_R7)
3319 else if (regno != REG_P0 + lastpreg - 1)
3324 else if (group == 1)
3326 if (regno != REG_R0 + lastdreg - 1)
3332 first_dreg_to_save = lastdreg;
3333 first_preg_to_save = lastpreg;
3334 n_regs_to_save = 8 - first_dreg_to_save + 6 - first_preg_to_save;
3338 /* Emit assembly code for one multi-register push described by INSN, with
3339 operands in OPERANDS. */
3342 output_push_multiple (rtx insn, rtx *operands)
3347 /* Validate the insn again, and compute first_[dp]reg_to_save. */
3348 ok = push_multiple_operation (PATTERN (insn), VOIDmode);
3351 if (first_dreg_to_save == 8)
3352 sprintf (buf, "[--sp] = ( p5:%d );\n", first_preg_to_save);
3353 else if (first_preg_to_save == 6)
3354 sprintf (buf, "[--sp] = ( r7:%d );\n", first_dreg_to_save);
3356 sprintf (buf, "[--sp] = ( r7:%d, p5:%d );\n",
3357 first_dreg_to_save, first_preg_to_save);
3359 output_asm_insn (buf, operands);
3362 /* Emit assembly code for one multi-register pop described by INSN, with
3363 operands in OPERANDS. */
3366 output_pop_multiple (rtx insn, rtx *operands)
3371 /* Validate the insn again, and compute first_[dp]reg_to_save. */
3372 ok = pop_multiple_operation (PATTERN (insn), VOIDmode);
3375 if (first_dreg_to_save == 8)
3376 sprintf (buf, "( p5:%d ) = [sp++];\n", first_preg_to_save);
3377 else if (first_preg_to_save == 6)
3378 sprintf (buf, "( r7:%d ) = [sp++];\n", first_dreg_to_save);
3380 sprintf (buf, "( r7:%d, p5:%d ) = [sp++];\n",
3381 first_dreg_to_save, first_preg_to_save);
3383 output_asm_insn (buf, operands);
3386 /* Adjust DST and SRC by OFFSET bytes, and generate one move in mode MODE. */
3389 single_move_for_movmem (rtx dst, rtx src, enum machine_mode mode, HOST_WIDE_INT offset)
3391 rtx scratch = gen_reg_rtx (mode);
3394 srcmem = adjust_address_nv (src, mode, offset);
3395 dstmem = adjust_address_nv (dst, mode, offset);
3396 emit_move_insn (scratch, srcmem);
3397 emit_move_insn (dstmem, scratch);
3400 /* Expand a string move operation of COUNT_EXP bytes from SRC to DST, with
3401 alignment ALIGN_EXP. Return true if successful, false if we should fall
3402 back on a different method. */
3405 bfin_expand_movmem (rtx dst, rtx src, rtx count_exp, rtx align_exp)
3407 rtx srcreg, destreg, countreg;
3408 HOST_WIDE_INT align = 0;
3409 unsigned HOST_WIDE_INT count = 0;
3411 if (GET_CODE (align_exp) == CONST_INT)
3412 align = INTVAL (align_exp);
3413 if (GET_CODE (count_exp) == CONST_INT)
3415 count = INTVAL (count_exp);
3417 if (!TARGET_INLINE_ALL_STRINGOPS && count > 64)
3422 /* If optimizing for size, only do single copies inline. */
3425 if (count == 2 && align < 2)
3427 if (count == 4 && align < 4)
3429 if (count != 1 && count != 2 && count != 4)
3432 if (align < 2 && count != 1)
3435 destreg = copy_to_mode_reg (Pmode, XEXP (dst, 0));
3436 if (destreg != XEXP (dst, 0))
3437 dst = replace_equiv_address_nv (dst, destreg);
3438 srcreg = copy_to_mode_reg (Pmode, XEXP (src, 0));
3439 if (srcreg != XEXP (src, 0))
3440 src = replace_equiv_address_nv (src, srcreg);
3442 if (count != 0 && align >= 2)
3444 unsigned HOST_WIDE_INT offset = 0;
3448 if ((count & ~3) == 4)
3450 single_move_for_movmem (dst, src, SImode, offset);
3453 else if (count & ~3)
3455 HOST_WIDE_INT new_count = ((count >> 2) & 0x3fffffff) - 1;
3456 countreg = copy_to_mode_reg (Pmode, GEN_INT (new_count));
3458 emit_insn (gen_rep_movsi (destreg, srcreg, countreg, destreg, srcreg));
3459 cfun->machine->has_loopreg_clobber = true;
3463 single_move_for_movmem (dst, src, HImode, offset);
3469 if ((count & ~1) == 2)
3471 single_move_for_movmem (dst, src, HImode, offset);
3474 else if (count & ~1)
3476 HOST_WIDE_INT new_count = ((count >> 1) & 0x7fffffff) - 1;
3477 countreg = copy_to_mode_reg (Pmode, GEN_INT (new_count));
3479 emit_insn (gen_rep_movhi (destreg, srcreg, countreg, destreg, srcreg));
3480 cfun->machine->has_loopreg_clobber = true;
3485 single_move_for_movmem (dst, src, QImode, offset);
3492 /* Compute the alignment for a local variable.
3493 TYPE is the data type, and ALIGN is the alignment that
3494 the object would ordinarily have. The value of this macro is used
3495 instead of that alignment to align the object. */
3498 bfin_local_alignment (tree type, int align)
3500 /* Increasing alignment for (relatively) big types allows the builtin
3501 memcpy can use 32 bit loads/stores. */
3502 if (TYPE_SIZE (type)
3503 && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
3504 && (TREE_INT_CST_LOW (TYPE_SIZE (type)) > 8
3505 || TREE_INT_CST_HIGH (TYPE_SIZE (type))) && align < 32)
3510 /* Implement TARGET_SCHED_ISSUE_RATE. */
3513 bfin_issue_rate (void)
3519 bfin_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
3521 enum attr_type insn_type, dep_insn_type;
3522 int dep_insn_code_number;
3524 /* Anti and output dependencies have zero cost. */
3525 if (REG_NOTE_KIND (link) != 0)
3528 dep_insn_code_number = recog_memoized (dep_insn);
3530 /* If we can't recognize the insns, we can't really do anything. */
3531 if (dep_insn_code_number < 0 || recog_memoized (insn) < 0)
3534 insn_type = get_attr_type (insn);
3535 dep_insn_type = get_attr_type (dep_insn);
3537 if (dep_insn_type == TYPE_MOVE || dep_insn_type == TYPE_MCLD)
3539 rtx pat = PATTERN (dep_insn);
3540 if (GET_CODE (pat) == PARALLEL)
3541 pat = XVECEXP (pat, 0, 0);
3542 rtx dest = SET_DEST (pat);
3543 rtx src = SET_SRC (pat);
3544 if (! ADDRESS_REGNO_P (REGNO (dest))
3545 || ! (MEM_P (src) || D_REGNO_P (REGNO (src))))
3547 return cost + (dep_insn_type == TYPE_MOVE ? 4 : 3);
3553 /* This function acts like NEXT_INSN, but is aware of three-insn bundles and
3554 skips all subsequent parallel instructions if INSN is the start of such
3557 find_next_insn_start (rtx insn)
3559 if (GET_MODE (insn) == SImode)
3561 while (GET_MODE (insn) != QImode)
3562 insn = NEXT_INSN (insn);
3564 return NEXT_INSN (insn);
3567 /* This function acts like PREV_INSN, but is aware of three-insn bundles and
3568 skips all subsequent parallel instructions if INSN is the start of such
3571 find_prev_insn_start (rtx insn)
3573 insn = PREV_INSN (insn);
3574 gcc_assert (GET_MODE (insn) != SImode);
3575 if (GET_MODE (insn) == QImode)
3577 while (GET_MODE (PREV_INSN (insn)) == SImode)
3578 insn = PREV_INSN (insn);
3583 /* Increment the counter for the number of loop instructions in the
3584 current function. */
3587 bfin_hardware_loop (void)
3589 cfun->machine->has_hardware_loops++;
3592 /* Maximum loop nesting depth. */
3593 #define MAX_LOOP_DEPTH 2
3595 /* Maximum size of a loop. */
3596 #define MAX_LOOP_LENGTH 2042
3598 /* Maximum distance of the LSETUP instruction from the loop start. */
3599 #define MAX_LSETUP_DISTANCE 30
3601 /* We need to keep a vector of loops */
3602 typedef struct loop_info *loop_info;
3603 DEF_VEC_P (loop_info);
3604 DEF_VEC_ALLOC_P (loop_info,heap);
3606 /* Information about a loop we have found (or are in the process of
3608 struct GTY (()) loop_info
3610 /* loop number, for dumps */
3613 /* All edges that jump into and out of the loop. */
3614 VEC(edge,gc) *incoming;
3616 /* We can handle two cases: all incoming edges have the same destination
3617 block, or all incoming edges have the same source block. These two
3618 members are set to the common source or destination we found, or NULL
3619 if different blocks were found. If both are NULL the loop can't be
3621 basic_block incoming_src;
3622 basic_block incoming_dest;
3624 /* First block in the loop. This is the one branched to by the loop_end
3628 /* Last block in the loop (the one with the loop_end insn). */
3631 /* The successor block of the loop. This is the one the loop_end insn
3633 basic_block successor;
3635 /* The last instruction in the tail. */
3638 /* The loop_end insn. */
3641 /* The iteration register. */
3644 /* The new label placed at the beginning of the loop. */
3647 /* The new label placed at the end of the loop. */
3650 /* The length of the loop. */
3653 /* The nesting depth of the loop. */
3656 /* Nonzero if we can't optimize this loop. */
3659 /* True if we have visited this loop. */
3662 /* True if this loop body clobbers any of LC0, LT0, or LB0. */
3665 /* True if this loop body clobbers any of LC1, LT1, or LB1. */
3668 /* Next loop in the graph. */
3669 struct loop_info *next;
3671 /* Immediate outer loop of this loop. */
3672 struct loop_info *outer;
3674 /* Vector of blocks only within the loop, including those within
3676 VEC (basic_block,heap) *blocks;
3678 /* Same information in a bitmap. */
3679 bitmap block_bitmap;
3681 /* Vector of inner loops within this loop */
3682 VEC (loop_info,heap) *loops;
3686 bfin_dump_loops (loop_info loops)
3690 for (loop = loops; loop; loop = loop->next)
3696 fprintf (dump_file, ";; loop %d: ", loop->loop_no);
3698 fprintf (dump_file, "(bad) ");
3699 fprintf (dump_file, "{head:%d, depth:%d}", loop->head->index, loop->depth);
3701 fprintf (dump_file, " blocks: [ ");
3702 for (ix = 0; VEC_iterate (basic_block, loop->blocks, ix, b); ix++)
3703 fprintf (dump_file, "%d ", b->index);
3704 fprintf (dump_file, "] ");
3706 fprintf (dump_file, " inner loops: [ ");
3707 for (ix = 0; VEC_iterate (loop_info, loop->loops, ix, i); ix++)
3708 fprintf (dump_file, "%d ", i->loop_no);
3709 fprintf (dump_file, "]\n");
3711 fprintf (dump_file, "\n");
3714 /* Scan the blocks of LOOP (and its inferiors) looking for basic block
3715 BB. Return true, if we find it. */
3718 bfin_bb_in_loop (loop_info loop, basic_block bb)
3720 return bitmap_bit_p (loop->block_bitmap, bb->index);
3723 /* Scan the blocks of LOOP (and its inferiors) looking for uses of
3724 REG. Return true, if we find any. Don't count the loop's loop_end
3725 insn if it matches LOOP_END. */
3728 bfin_scan_loop (loop_info loop, rtx reg, rtx loop_end)
3733 for (ix = 0; VEC_iterate (basic_block, loop->blocks, ix, bb); ix++)
3737 for (insn = BB_HEAD (bb);
3738 insn != NEXT_INSN (BB_END (bb));
3739 insn = NEXT_INSN (insn))
3743 if (insn == loop_end)
3745 if (reg_mentioned_p (reg, PATTERN (insn)))
3752 /* Estimate the length of INSN conservatively. */
3755 length_for_loop (rtx insn)
3758 if (JUMP_P (insn) && any_condjump_p (insn) && !optimize_size)
3760 if (ENABLE_WA_SPECULATIVE_SYNCS)
3762 else if (ENABLE_WA_SPECULATIVE_LOADS)
3765 else if (LABEL_P (insn))
3767 if (ENABLE_WA_SPECULATIVE_SYNCS)
3772 length += get_attr_length (insn);
3777 /* Optimize LOOP. */
3780 bfin_optimize_loop (loop_info loop)
3784 rtx insn, last_insn;
3785 rtx loop_init, start_label, end_label;
3786 rtx reg_lc0, reg_lc1, reg_lt0, reg_lt1, reg_lb0, reg_lb1;
3787 rtx iter_reg, scratchreg, scratch_init, scratch_init_insn;
3788 rtx lc_reg, lt_reg, lb_reg;
3792 int inner_depth = 0;
3802 fprintf (dump_file, ";; loop %d bad when found\n", loop->loop_no);
3806 /* Every loop contains in its list of inner loops every loop nested inside
3807 it, even if there are intermediate loops. This works because we're doing
3808 a depth-first search here and never visit a loop more than once. */
3809 for (ix = 0; VEC_iterate (loop_info, loop->loops, ix, inner); ix++)
3811 bfin_optimize_loop (inner);
3813 if (!inner->bad && inner_depth < inner->depth)
3815 inner_depth = inner->depth;
3817 loop->clobber_loop0 |= inner->clobber_loop0;
3818 loop->clobber_loop1 |= inner->clobber_loop1;
3822 loop->depth = inner_depth + 1;
3823 if (loop->depth > MAX_LOOP_DEPTH)
3826 fprintf (dump_file, ";; loop %d too deep\n", loop->loop_no);
3830 /* Get the loop iteration register. */
3831 iter_reg = loop->iter_reg;
3833 if (!REG_P (iter_reg))
3836 fprintf (dump_file, ";; loop %d iteration count not in a register\n",
3840 scratchreg = NULL_RTX;
3841 scratch_init = iter_reg;
3842 scratch_init_insn = NULL_RTX;
3843 if (!PREG_P (iter_reg) && loop->incoming_src)
3845 basic_block bb_in = loop->incoming_src;
3847 for (i = REG_P0; i <= REG_P5; i++)
3848 if ((df_regs_ever_live_p (i)
3849 || (funkind (TREE_TYPE (current_function_decl)) == SUBROUTINE
3850 && call_used_regs[i]))
3851 && !REGNO_REG_SET_P (df_get_live_out (bb_in), i))
3853 scratchreg = gen_rtx_REG (SImode, i);
3856 for (insn = BB_END (bb_in); insn != BB_HEAD (bb_in);
3857 insn = PREV_INSN (insn))
3860 if (NOTE_P (insn) || BARRIER_P (insn))
3862 set = single_set (insn);
3863 if (set && rtx_equal_p (SET_DEST (set), iter_reg))
3865 if (CONSTANT_P (SET_SRC (set)))
3867 scratch_init = SET_SRC (set);
3868 scratch_init_insn = insn;
3872 else if (reg_mentioned_p (iter_reg, PATTERN (insn)))
3877 if (loop->incoming_src)
3879 /* Make sure the predecessor is before the loop start label, as required by
3880 the LSETUP instruction. */
3882 insn = BB_END (loop->incoming_src);
3883 /* If we have to insert the LSETUP before a jump, count that jump in the
3885 if (VEC_length (edge, loop->incoming) > 1
3886 || !(VEC_last (edge, loop->incoming)->flags & EDGE_FALLTHRU))
3888 gcc_assert (JUMP_P (insn));
3889 insn = PREV_INSN (insn);
3892 for (; insn && insn != loop->start_label; insn = NEXT_INSN (insn))
3893 length += length_for_loop (insn);
3898 fprintf (dump_file, ";; loop %d lsetup not before loop_start\n",
3903 /* Account for the pop of a scratch register where necessary. */
3904 if (!PREG_P (iter_reg) && scratchreg == NULL_RTX
3905 && ENABLE_WA_LOAD_LCREGS)
3908 if (length > MAX_LSETUP_DISTANCE)
3911 fprintf (dump_file, ";; loop %d lsetup too far away\n", loop->loop_no);
3916 /* Check if start_label appears before loop_end and calculate the
3917 offset between them. We calculate the length of instructions
3920 for (insn = loop->start_label;
3921 insn && insn != loop->loop_end;
3922 insn = NEXT_INSN (insn))
3923 length += length_for_loop (insn);
3928 fprintf (dump_file, ";; loop %d start_label not before loop_end\n",
3933 loop->length = length;
3934 if (loop->length > MAX_LOOP_LENGTH)
3937 fprintf (dump_file, ";; loop %d too long\n", loop->loop_no);
3941 /* Scan all the blocks to make sure they don't use iter_reg. */
3942 if (bfin_scan_loop (loop, iter_reg, loop->loop_end))
3945 fprintf (dump_file, ";; loop %d uses iterator\n", loop->loop_no);
3949 /* Scan all the insns to see if the loop body clobber
3950 any hardware loop registers. */
3952 reg_lc0 = gen_rtx_REG (SImode, REG_LC0);
3953 reg_lc1 = gen_rtx_REG (SImode, REG_LC1);
3954 reg_lt0 = gen_rtx_REG (SImode, REG_LT0);
3955 reg_lt1 = gen_rtx_REG (SImode, REG_LT1);
3956 reg_lb0 = gen_rtx_REG (SImode, REG_LB0);
3957 reg_lb1 = gen_rtx_REG (SImode, REG_LB1);
3959 for (ix = 0; VEC_iterate (basic_block, loop->blocks, ix, bb); ix++)
3963 for (insn = BB_HEAD (bb);
3964 insn != NEXT_INSN (BB_END (bb));
3965 insn = NEXT_INSN (insn))
3970 if (reg_set_p (reg_lc0, insn)
3971 || reg_set_p (reg_lt0, insn)
3972 || reg_set_p (reg_lb0, insn))
3973 loop->clobber_loop0 = 1;
3975 if (reg_set_p (reg_lc1, insn)
3976 || reg_set_p (reg_lt1, insn)
3977 || reg_set_p (reg_lb1, insn))
3978 loop->clobber_loop1 |= 1;
3982 if ((loop->clobber_loop0 && loop->clobber_loop1)
3983 || (loop->depth == MAX_LOOP_DEPTH && loop->clobber_loop0))
3985 loop->depth = MAX_LOOP_DEPTH + 1;
3987 fprintf (dump_file, ";; loop %d no loop reg available\n",
3992 /* There should be an instruction before the loop_end instruction
3993 in the same basic block. And the instruction must not be
3995 - CONDITIONAL BRANCH
3999 - Returns (RTS, RTN, etc.) */
4002 last_insn = find_prev_insn_start (loop->loop_end);
4006 for (; last_insn != BB_HEAD (bb);
4007 last_insn = find_prev_insn_start (last_insn))
4008 if (INSN_P (last_insn))
4011 if (last_insn != BB_HEAD (bb))
4014 if (single_pred_p (bb)
4015 && single_pred_edge (bb)->flags & EDGE_FALLTHRU
4016 && single_pred (bb) != ENTRY_BLOCK_PTR)
4018 bb = single_pred (bb);
4019 last_insn = BB_END (bb);
4024 last_insn = NULL_RTX;
4032 fprintf (dump_file, ";; loop %d has no last instruction\n",
4037 if (JUMP_P (last_insn) && !any_condjump_p (last_insn))
4040 fprintf (dump_file, ";; loop %d has bad last instruction\n",
4044 /* In all other cases, try to replace a bad last insn with a nop. */
4045 else if (JUMP_P (last_insn)
4046 || CALL_P (last_insn)
4047 || get_attr_type (last_insn) == TYPE_SYNC
4048 || get_attr_type (last_insn) == TYPE_CALL
4049 || get_attr_seq_insns (last_insn) == SEQ_INSNS_MULTI
4050 || recog_memoized (last_insn) == CODE_FOR_return_internal
4051 || GET_CODE (PATTERN (last_insn)) == ASM_INPUT
4052 || asm_noperands (PATTERN (last_insn)) >= 0)
4054 if (loop->length + 2 > MAX_LOOP_LENGTH)
4057 fprintf (dump_file, ";; loop %d too long\n", loop->loop_no);
4061 fprintf (dump_file, ";; loop %d has bad last insn; replace with nop\n",
4064 last_insn = emit_insn_after (gen_forced_nop (), last_insn);
4067 loop->last_insn = last_insn;
4069 /* The loop is good for replacement. */
4070 start_label = loop->start_label;
4071 end_label = gen_label_rtx ();
4072 iter_reg = loop->iter_reg;
4074 if (loop->depth == 1 && !loop->clobber_loop1)
4079 loop->clobber_loop1 = 1;
4086 loop->clobber_loop0 = 1;
4089 loop->end_label = end_label;
4091 /* Create a sequence containing the loop setup. */
4094 /* LSETUP only accepts P registers. If we have one, we can use it,
4095 otherwise there are several ways of working around the problem.
4096 If we're not affected by anomaly 312, we can load the LC register
4097 from any iteration register, and use LSETUP without initialization.
4098 If we've found a P scratch register that's not live here, we can
4099 instead copy the iter_reg into that and use an initializing LSETUP.
4100 If all else fails, push and pop P0 and use it as a scratch. */
4101 if (P_REGNO_P (REGNO (iter_reg)))
4103 loop_init = gen_lsetup_with_autoinit (lt_reg, start_label,
4106 seq_end = emit_insn (loop_init);
4108 else if (!ENABLE_WA_LOAD_LCREGS && DPREG_P (iter_reg))
4110 emit_insn (gen_movsi (lc_reg, iter_reg));
4111 loop_init = gen_lsetup_without_autoinit (lt_reg, start_label,
4114 seq_end = emit_insn (loop_init);
4116 else if (scratchreg != NULL_RTX)
4118 emit_insn (gen_movsi (scratchreg, scratch_init));
4119 loop_init = gen_lsetup_with_autoinit (lt_reg, start_label,
4121 lc_reg, scratchreg);
4122 seq_end = emit_insn (loop_init);
4123 if (scratch_init_insn != NULL_RTX)
4124 delete_insn (scratch_init_insn);
4128 rtx p0reg = gen_rtx_REG (SImode, REG_P0);
4129 rtx push = gen_frame_mem (SImode,
4130 gen_rtx_PRE_DEC (SImode, stack_pointer_rtx));
4131 rtx pop = gen_frame_mem (SImode,
4132 gen_rtx_POST_INC (SImode, stack_pointer_rtx));
4133 emit_insn (gen_movsi (push, p0reg));
4134 emit_insn (gen_movsi (p0reg, scratch_init));
4135 loop_init = gen_lsetup_with_autoinit (lt_reg, start_label,
4138 emit_insn (loop_init);
4139 seq_end = emit_insn (gen_movsi (p0reg, pop));
4140 if (scratch_init_insn != NULL_RTX)
4141 delete_insn (scratch_init_insn);
4146 fprintf (dump_file, ";; replacing loop %d initializer with\n",
4148 print_rtl_single (dump_file, loop_init);
4149 fprintf (dump_file, ";; replacing loop %d terminator with\n",
4151 print_rtl_single (dump_file, loop->loop_end);
4154 /* If the loop isn't entered at the top, also create a jump to the entry
4156 if (!loop->incoming_src && loop->head != loop->incoming_dest)
4158 rtx label = BB_HEAD (loop->incoming_dest);
4159 /* If we're jumping to the final basic block in the loop, and there's
4160 only one cheap instruction before the end (typically an increment of
4161 an induction variable), we can just emit a copy here instead of a
4163 if (loop->incoming_dest == loop->tail
4164 && next_real_insn (label) == last_insn
4165 && asm_noperands (last_insn) < 0
4166 && GET_CODE (PATTERN (last_insn)) == SET)
4168 seq_end = emit_insn (copy_rtx (PATTERN (last_insn)));
4171 seq_end = emit_jump_insn (gen_jump (label));
4177 if (loop->incoming_src)
4179 rtx prev = BB_END (loop->incoming_src);
4180 if (VEC_length (edge, loop->incoming) > 1
4181 || !(VEC_last (edge, loop->incoming)->flags & EDGE_FALLTHRU))
4183 gcc_assert (JUMP_P (prev));
4184 prev = PREV_INSN (prev);
4186 emit_insn_after (seq, prev);
4194 #ifdef ENABLE_CHECKING
4195 if (loop->head != loop->incoming_dest)
4197 /* We aren't entering the loop at the top. Since we've established
4198 that the loop is entered only at one point, this means there
4199 can't be fallthru edges into the head. Any such fallthru edges
4200 would become invalid when we insert the new block, so verify
4201 that this does not in fact happen. */
4202 FOR_EACH_EDGE (e, ei, loop->head->preds)
4203 gcc_assert (!(e->flags & EDGE_FALLTHRU));
4207 emit_insn_before (seq, BB_HEAD (loop->head));
4208 seq = emit_label_before (gen_label_rtx (), seq);
4210 new_bb = create_basic_block (seq, seq_end, loop->head->prev_bb);
4211 FOR_EACH_EDGE (e, ei, loop->incoming)
4213 if (!(e->flags & EDGE_FALLTHRU)
4214 || e->dest != loop->head)
4215 redirect_edge_and_branch_force (e, new_bb);
4217 redirect_edge_succ (e, new_bb);
4221 delete_insn (loop->loop_end);
4222 /* Insert the loop end label before the last instruction of the loop. */
4223 emit_label_before (loop->end_label, loop->last_insn);
4230 fprintf (dump_file, ";; loop %d is bad\n", loop->loop_no);
4234 if (DPREG_P (loop->iter_reg))
4236 /* If loop->iter_reg is a DREG or PREG, we can split it here
4237 without scratch register. */
4240 emit_insn_before (gen_addsi3 (loop->iter_reg,
4245 emit_insn_before (gen_cmpsi (loop->iter_reg, const0_rtx),
4248 insn = emit_jump_insn_before (gen_bne (loop->start_label),
4251 JUMP_LABEL (insn) = loop->start_label;
4252 LABEL_NUSES (loop->start_label)++;
4253 delete_insn (loop->loop_end);
4257 /* Called from bfin_reorg_loops when a potential loop end is found. LOOP is
4258 a newly set up structure describing the loop, it is this function's
4259 responsibility to fill most of it. TAIL_BB and TAIL_INSN point to the
4260 loop_end insn and its enclosing basic block. */
4263 bfin_discover_loop (loop_info loop, basic_block tail_bb, rtx tail_insn)
4267 VEC (basic_block,heap) *works = VEC_alloc (basic_block,heap,20);
4269 loop->tail = tail_bb;
4270 loop->head = BRANCH_EDGE (tail_bb)->dest;
4271 loop->successor = FALLTHRU_EDGE (tail_bb)->dest;
4272 loop->loop_end = tail_insn;
4273 loop->last_insn = NULL_RTX;
4274 loop->iter_reg = SET_DEST (XVECEXP (PATTERN (tail_insn), 0, 1));
4275 loop->depth = loop->length = 0;
4277 loop->clobber_loop0 = loop->clobber_loop1 = 0;
4280 loop->incoming = VEC_alloc (edge, gc, 2);
4281 loop->start_label = XEXP (XEXP (SET_SRC (XVECEXP (PATTERN (tail_insn), 0, 0)), 1), 0);
4282 loop->end_label = NULL_RTX;
4285 VEC_safe_push (basic_block, heap, works, loop->head);
4287 while (VEC_iterate (basic_block, works, dwork++, bb))
4291 if (bb == EXIT_BLOCK_PTR)
4293 /* We've reached the exit block. The loop must be bad. */
4296 ";; Loop is bad - reached exit block while scanning\n");
4301 if (bitmap_bit_p (loop->block_bitmap, bb->index))
4304 /* We've not seen this block before. Add it to the loop's
4305 list and then add each successor to the work list. */
4307 VEC_safe_push (basic_block, heap, loop->blocks, bb);
4308 bitmap_set_bit (loop->block_bitmap, bb->index);
4312 FOR_EACH_EDGE (e, ei, bb->succs)
4314 basic_block succ = EDGE_SUCC (bb, ei.index)->dest;
4315 if (!REGNO_REG_SET_P (df_get_live_in (succ),
4316 REGNO (loop->iter_reg)))
4318 if (!VEC_space (basic_block, works, 1))
4322 VEC_block_remove (basic_block, works, 0, dwork);
4326 VEC_reserve (basic_block, heap, works, 1);
4328 VEC_quick_push (basic_block, works, succ);
4333 /* Find the predecessor, and make sure nothing else jumps into this loop. */
4337 for (dwork = 0; VEC_iterate (basic_block, loop->blocks, dwork, bb); dwork++)
4341 FOR_EACH_EDGE (e, ei, bb->preds)
4343 basic_block pred = e->src;
4345 if (!bfin_bb_in_loop (loop, pred))
4348 fprintf (dump_file, ";; Loop %d: incoming edge %d -> %d\n",
4349 loop->loop_no, pred->index,
4351 VEC_safe_push (edge, gc, loop->incoming, e);
4356 for (pass = 0, retry = 1; retry && pass < 2; pass++)
4363 FOR_EACH_EDGE (e, ei, loop->incoming)
4367 loop->incoming_src = e->src;
4368 loop->incoming_dest = e->dest;
4373 if (e->dest != loop->incoming_dest)
4374 loop->incoming_dest = NULL;
4375 if (e->src != loop->incoming_src)
4376 loop->incoming_src = NULL;
4378 if (loop->incoming_src == NULL && loop->incoming_dest == NULL)
4384 ";; retrying loop %d with forwarder blocks\n",
4392 ";; can't find suitable entry for loop %d\n",
4400 FOR_EACH_EDGE (e, ei, loop->incoming)
4402 if (forwarder_block_p (e->src))
4409 ";; Adding forwarder block %d to loop %d and retrying\n",
4410 e->src->index, loop->loop_no);
4411 VEC_safe_push (basic_block, heap, loop->blocks, e->src);
4412 bitmap_set_bit (loop->block_bitmap, e->src->index);
4413 FOR_EACH_EDGE (e2, ei2, e->src->preds)
4414 VEC_safe_push (edge, gc, loop->incoming, e2);
4415 VEC_unordered_remove (edge, loop->incoming, ei.index);
4423 fprintf (dump_file, ";; No forwarder blocks found\n");
4431 VEC_free (basic_block, heap, works);
4434 /* Analyze the structure of the loops in the current function. Use STACK
4435 for bitmap allocations. Returns all the valid candidates for hardware
4436 loops found in this function. */
4438 bfin_discover_loops (bitmap_obstack *stack, FILE *dump_file)
4440 loop_info loops = NULL;
4446 /* Find all the possible loop tails. This means searching for every
4447 loop_end instruction. For each one found, create a loop_info
4448 structure and add the head block to the work list. */
4451 rtx tail = BB_END (bb);
4453 while (GET_CODE (tail) == NOTE)
4454 tail = PREV_INSN (tail);
4458 if (INSN_P (tail) && recog_memoized (tail) == CODE_FOR_loop_end)
4461 /* A possible loop end */
4463 /* There's a degenerate case we can handle - an empty loop consisting
4464 of only a back branch. Handle that by deleting the branch. */
4465 insn = BB_HEAD (BRANCH_EDGE (bb)->dest);
4466 if (next_real_insn (insn) == tail)
4470 fprintf (dump_file, ";; degenerate loop ending at\n");
4471 print_rtl_single (dump_file, tail);
4473 delete_insn_and_edges (tail);
4477 loop = XNEW (struct loop_info);
4480 loop->loop_no = nloops++;
4481 loop->blocks = VEC_alloc (basic_block, heap, 20);
4482 loop->block_bitmap = BITMAP_ALLOC (stack);
4487 fprintf (dump_file, ";; potential loop %d ending at\n",
4489 print_rtl_single (dump_file, tail);
4492 bfin_discover_loop (loop, bb, tail);
4496 tmp_bitmap = BITMAP_ALLOC (stack);
4497 /* Compute loop nestings. */
4498 for (loop = loops; loop; loop = loop->next)
4504 for (other = loop->next; other; other = other->next)
4509 bitmap_and (tmp_bitmap, other->block_bitmap, loop->block_bitmap);
4510 if (bitmap_empty_p (tmp_bitmap))
4512 if (bitmap_equal_p (tmp_bitmap, other->block_bitmap))
4514 other->outer = loop;
4515 VEC_safe_push (loop_info, heap, loop->loops, other);
4517 else if (bitmap_equal_p (tmp_bitmap, loop->block_bitmap))
4519 loop->outer = other;
4520 VEC_safe_push (loop_info, heap, other->loops, loop);
4526 ";; can't find suitable nesting for loops %d and %d\n",
4527 loop->loop_no, other->loop_no);
4528 loop->bad = other->bad = 1;
4532 BITMAP_FREE (tmp_bitmap);
4537 /* Free up the loop structures in LOOPS. */
4539 free_loops (loop_info loops)
4543 loop_info loop = loops;
4545 VEC_free (loop_info, heap, loop->loops);
4546 VEC_free (basic_block, heap, loop->blocks);
4547 BITMAP_FREE (loop->block_bitmap);
4552 #define BB_AUX_INDEX(BB) ((unsigned)(BB)->aux)
4554 /* The taken-branch edge from the loop end can actually go forward. Since the
4555 Blackfin's LSETUP instruction requires that the loop end be after the loop
4556 start, try to reorder a loop's basic blocks when we find such a case. */
4558 bfin_reorder_loops (loop_info loops, FILE *dump_file)
4565 cfg_layout_initialize (0);
4567 for (loop = loops; loop; loop = loop->next)
4577 /* Recreate an index for basic blocks that represents their order. */
4578 for (bb = ENTRY_BLOCK_PTR->next_bb, index = 0;
4579 bb != EXIT_BLOCK_PTR;
4580 bb = bb->next_bb, index++)
4581 bb->aux = (PTR) index;
4583 if (BB_AUX_INDEX (loop->head) < BB_AUX_INDEX (loop->tail))
4586 FOR_EACH_EDGE (e, ei, loop->head->succs)
4588 if (bitmap_bit_p (loop->block_bitmap, e->dest->index)
4589 && BB_AUX_INDEX (e->dest) < BB_AUX_INDEX (loop->tail))
4591 basic_block start_bb = e->dest;
4592 basic_block start_prev_bb = start_bb->prev_bb;
4595 fprintf (dump_file, ";; Moving block %d before block %d\n",
4596 loop->head->index, start_bb->index);
4597 loop->head->prev_bb->next_bb = loop->head->next_bb;
4598 loop->head->next_bb->prev_bb = loop->head->prev_bb;
4600 loop->head->prev_bb = start_prev_bb;
4601 loop->head->next_bb = start_bb;
4602 start_prev_bb->next_bb = start_bb->prev_bb = loop->head;
4606 loops = loops->next;
4611 if (bb->next_bb != EXIT_BLOCK_PTR)
4612 bb->aux = bb->next_bb;
4616 cfg_layout_finalize ();
4620 /* Run from machine_dependent_reorg, this pass looks for doloop_end insns
4621 and tries to rewrite the RTL of these loops so that proper Blackfin
4622 hardware loops are generated. */
4625 bfin_reorg_loops (FILE *dump_file)
4627 loop_info loops = NULL;
4630 bitmap_obstack stack;
4632 bitmap_obstack_initialize (&stack);
4635 fprintf (dump_file, ";; Find loops, first pass\n\n");
4637 loops = bfin_discover_loops (&stack, dump_file);
4640 bfin_dump_loops (loops);
4642 bfin_reorder_loops (loops, dump_file);
4646 fprintf (dump_file, ";; Find loops, second pass\n\n");
4648 loops = bfin_discover_loops (&stack, dump_file);
4651 fprintf (dump_file, ";; All loops found:\n\n");
4652 bfin_dump_loops (loops);
4655 /* Now apply the optimizations. */
4656 for (loop = loops; loop; loop = loop->next)
4657 bfin_optimize_loop (loop);
4661 fprintf (dump_file, ";; After hardware loops optimization:\n\n");
4662 bfin_dump_loops (loops);
4668 print_rtl (dump_file, get_insns ());
4673 splitting_loops = 1;
4676 rtx insn = BB_END (bb);
4680 try_split (PATTERN (insn), insn, 1);
4682 splitting_loops = 0;
4685 /* Possibly generate a SEQUENCE out of three insns found in SLOT.
4686 Returns true if we modified the insn chain, false otherwise. */
4688 gen_one_bundle (rtx slot[3])
4690 gcc_assert (slot[1] != NULL_RTX);
4692 /* Don't add extra NOPs if optimizing for size. */
4694 && (slot[0] == NULL_RTX || slot[2] == NULL_RTX))
4697 /* Verify that we really can do the multi-issue. */
4700 rtx t = NEXT_INSN (slot[0]);
4701 while (t != slot[1])
4703 if (GET_CODE (t) != NOTE
4704 || NOTE_KIND (t) != NOTE_INSN_DELETED)
4711 rtx t = NEXT_INSN (slot[1]);
4712 while (t != slot[2])
4714 if (GET_CODE (t) != NOTE
4715 || NOTE_KIND (t) != NOTE_INSN_DELETED)
4721 if (slot[0] == NULL_RTX)
4723 slot[0] = emit_insn_before (gen_mnop (), slot[1]);
4724 df_insn_rescan (slot[0]);
4726 if (slot[2] == NULL_RTX)
4728 slot[2] = emit_insn_after (gen_forced_nop (), slot[1]);
4729 df_insn_rescan (slot[2]);
4732 /* Avoid line number information being printed inside one bundle. */
4733 if (INSN_LOCATOR (slot[1])
4734 && INSN_LOCATOR (slot[1]) != INSN_LOCATOR (slot[0]))
4735 INSN_LOCATOR (slot[1]) = INSN_LOCATOR (slot[0]);
4736 if (INSN_LOCATOR (slot[2])
4737 && INSN_LOCATOR (slot[2]) != INSN_LOCATOR (slot[0]))
4738 INSN_LOCATOR (slot[2]) = INSN_LOCATOR (slot[0]);
4740 /* Terminate them with "|| " instead of ";" in the output. */
4741 PUT_MODE (slot[0], SImode);
4742 PUT_MODE (slot[1], SImode);
4743 /* Terminate the bundle, for the benefit of reorder_var_tracking_notes. */
4744 PUT_MODE (slot[2], QImode);
4748 /* Go through all insns, and use the information generated during scheduling
4749 to generate SEQUENCEs to represent bundles of instructions issued
4753 bfin_gen_bundles (void)
4762 slot[0] = slot[1] = slot[2] = NULL_RTX;
4763 for (insn = BB_HEAD (bb);; insn = next)
4768 if (get_attr_type (insn) == TYPE_DSP32)
4770 else if (slot[1] == NULL_RTX)
4777 next = NEXT_INSN (insn);
4778 while (next && insn != BB_END (bb)
4780 && GET_CODE (PATTERN (next)) != USE
4781 && GET_CODE (PATTERN (next)) != CLOBBER))
4784 next = NEXT_INSN (insn);
4787 /* BB_END can change due to emitting extra NOPs, so check here. */
4788 at_end = insn == BB_END (bb);
4789 if (at_end || GET_MODE (next) == TImode)
4792 || !gen_one_bundle (slot))
4793 && slot[0] != NULL_RTX)
4795 rtx pat = PATTERN (slot[0]);
4796 if (GET_CODE (pat) == SET
4797 && GET_CODE (SET_SRC (pat)) == UNSPEC
4798 && XINT (SET_SRC (pat), 1) == UNSPEC_32BIT)
4800 SET_SRC (pat) = XVECEXP (SET_SRC (pat), 0, 0);
4801 INSN_CODE (slot[0]) = -1;
4802 df_insn_rescan (slot[0]);
4806 slot[0] = slot[1] = slot[2] = NULL_RTX;
4814 /* Ensure that no var tracking notes are emitted in the middle of a
4815 three-instruction bundle. */
4818 reorder_var_tracking_notes (void)
4824 rtx queue = NULL_RTX;
4825 bool in_bundle = false;
4827 for (insn = BB_HEAD (bb); insn != BB_END (bb); insn = next)
4829 next = NEXT_INSN (insn);
4833 /* Emit queued up notes at the last instruction of a bundle. */
4834 if (GET_MODE (insn) == QImode)
4838 rtx next_queue = PREV_INSN (queue);
4839 PREV_INSN (NEXT_INSN (insn)) = queue;
4840 NEXT_INSN (queue) = NEXT_INSN (insn);
4841 NEXT_INSN (insn) = queue;
4842 PREV_INSN (queue) = insn;
4847 else if (GET_MODE (insn) == SImode)
4850 else if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION)
4854 rtx prev = PREV_INSN (insn);
4855 PREV_INSN (next) = prev;
4856 NEXT_INSN (prev) = next;
4858 PREV_INSN (insn) = queue;
4866 /* On some silicon revisions, functions shorter than a certain number of cycles
4867 can cause unpredictable behaviour. Work around this by adding NOPs as
4870 workaround_rts_anomaly (void)
4872 rtx insn, first_insn = NULL_RTX;
4875 if (! ENABLE_WA_RETS)
4878 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
4882 if (BARRIER_P (insn))
4885 if (NOTE_P (insn) || LABEL_P (insn))
4888 if (first_insn == NULL_RTX)
4890 pat = PATTERN (insn);
4891 if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER
4892 || GET_CODE (pat) == ASM_INPUT || GET_CODE (pat) == ADDR_VEC
4893 || GET_CODE (pat) == ADDR_DIFF_VEC || asm_noperands (pat) >= 0)
4901 if (recog_memoized (insn) == CODE_FOR_return_internal)
4904 /* Nothing to worry about for direct jumps. */
4905 if (!any_condjump_p (insn))
4911 else if (INSN_P (insn))
4913 rtx pat = PATTERN (insn);
4914 int this_cycles = 1;
4916 if (GET_CODE (pat) == PARALLEL)
4918 if (push_multiple_operation (pat, VOIDmode)
4919 || pop_multiple_operation (pat, VOIDmode))
4920 this_cycles = n_regs_to_save;
4924 enum insn_code icode = recog_memoized (insn);
4925 if (icode == CODE_FOR_link)
4927 else if (icode == CODE_FOR_unlink)
4929 else if (icode == CODE_FOR_mulsi3)
4932 if (this_cycles >= cycles)
4935 cycles -= this_cycles;
4940 emit_insn_before (gen_nop (), first_insn);
4945 /* Return an insn type for INSN that can be used by the caller for anomaly
4946 workarounds. This differs from plain get_attr_type in that it handles
4949 static enum attr_type
4950 type_for_anomaly (rtx insn)
4952 rtx pat = PATTERN (insn);
4953 if (GET_CODE (pat) == SEQUENCE)
4956 t = get_attr_type (XVECEXP (pat, 0, 1));
4959 t = get_attr_type (XVECEXP (pat, 0, 2));
4965 return get_attr_type (insn);
4968 /* Return nonzero if INSN contains any loads that may trap. It handles
4969 SEQUENCEs correctly. */
4972 trapping_loads_p (rtx insn)
4974 rtx pat = PATTERN (insn);
4975 if (GET_CODE (pat) == SEQUENCE)
4978 t = get_attr_type (XVECEXP (pat, 0, 1));
4980 && may_trap_p (SET_SRC (PATTERN (XVECEXP (pat, 0, 1)))))
4982 t = get_attr_type (XVECEXP (pat, 0, 2));
4984 && may_trap_p (SET_SRC (PATTERN (XVECEXP (pat, 0, 2)))))
4989 return may_trap_p (SET_SRC (single_set (insn)));
4992 /* Return INSN if it is of TYPE_MCLD. Alternatively, if INSN is the start of
4993 a three-insn bundle, see if one of them is a load and return that if so.
4994 Return NULL_RTX if the insn does not contain loads. */
4996 find_load (rtx insn)
4998 if (get_attr_type (insn) == TYPE_MCLD)
5000 if (GET_MODE (insn) != SImode)
5003 insn = NEXT_INSN (insn);
5004 if ((GET_MODE (insn) == SImode || GET_MODE (insn) == QImode)
5005 && get_attr_type (insn) == TYPE_MCLD)
5007 } while (GET_MODE (insn) != QImode);
5011 /* Determine whether PAT is an indirect call pattern. */
5013 indirect_call_p (rtx pat)
5015 if (GET_CODE (pat) == PARALLEL)
5016 pat = XVECEXP (pat, 0, 0);
5017 if (GET_CODE (pat) == SET)
5018 pat = SET_SRC (pat);
5019 gcc_assert (GET_CODE (pat) == CALL);
5020 pat = XEXP (pat, 0);
5021 gcc_assert (GET_CODE (pat) == MEM);
5022 pat = XEXP (pat, 0);
5028 workaround_speculation (void)
5031 rtx last_condjump = NULL_RTX;
5032 int cycles_since_jump = INT_MAX;
5033 int delay_added = 0;
5035 if (! ENABLE_WA_SPECULATIVE_LOADS && ! ENABLE_WA_SPECULATIVE_SYNCS
5036 && ! ENABLE_WA_INDIRECT_CALLS)
5039 /* First pass: find predicted-false branches; if something after them
5040 needs nops, insert them or change the branch to predict true. */
5041 for (insn = get_insns (); insn; insn = next)
5044 int delay_needed = 0;
5046 next = find_next_insn_start (insn);
5048 if (NOTE_P (insn) || BARRIER_P (insn) || LABEL_P (insn))
5051 pat = PATTERN (insn);
5052 if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER
5053 || GET_CODE (pat) == ASM_INPUT || GET_CODE (pat) == ADDR_VEC
5054 || GET_CODE (pat) == ADDR_DIFF_VEC || asm_noperands (pat) >= 0)
5059 if (any_condjump_p (insn)
5060 && ! cbranch_predicted_taken_p (insn))
5062 last_condjump = insn;
5064 cycles_since_jump = 0;
5067 cycles_since_jump = INT_MAX;
5069 else if (CALL_P (insn))
5071 if (cycles_since_jump < INT_MAX)
5072 cycles_since_jump++;
5073 if (indirect_call_p (pat) && ENABLE_WA_INDIRECT_CALLS)
5078 else if (INSN_P (insn))
5080 rtx load_insn = find_load (insn);
5081 enum attr_type type = type_for_anomaly (insn);
5083 if (cycles_since_jump < INT_MAX)
5084 cycles_since_jump++;
5086 if (load_insn && ENABLE_WA_SPECULATIVE_LOADS)
5088 if (trapping_loads_p (load_insn))
5091 else if (type == TYPE_SYNC && ENABLE_WA_SPECULATIVE_SYNCS)
5095 if (delay_needed > cycles_since_jump
5096 && (delay_needed - cycles_since_jump) > delay_added)
5100 rtx *op = recog_data.operand;
5102 delay_needed -= cycles_since_jump;
5104 extract_insn (last_condjump);
5107 pat1 = gen_cbranch_predicted_taken (op[0], op[1], op[2],
5109 cycles_since_jump = INT_MAX;
5113 /* Do not adjust cycles_since_jump in this case, so that
5114 we'll increase the number of NOPs for a subsequent insn
5116 pat1 = gen_cbranch_with_nops (op[0], op[1], op[2], op[3],
5117 GEN_INT (delay_needed));
5118 delay_added = delay_needed;
5120 PATTERN (last_condjump) = pat1;
5121 INSN_CODE (last_condjump) = recog (pat1, insn, &num_clobbers);
5125 cycles_since_jump = INT_MAX;
5130 /* Second pass: for predicted-true branches, see if anything at the
5131 branch destination needs extra nops. */
5132 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
5134 int cycles_since_jump;
5136 && any_condjump_p (insn)
5137 && (INSN_CODE (insn) == CODE_FOR_cbranch_predicted_taken
5138 || cbranch_predicted_taken_p (insn)))
5140 rtx target = JUMP_LABEL (insn);
5144 cycles_since_jump = 0;
5145 for (; target && cycles_since_jump < 3; target = next_tgt)
5149 next_tgt = find_next_insn_start (target);
5151 if (NOTE_P (target) || BARRIER_P (target) || LABEL_P (target))
5154 pat = PATTERN (target);
5155 if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER
5156 || GET_CODE (pat) == ASM_INPUT || GET_CODE (pat) == ADDR_VEC
5157 || GET_CODE (pat) == ADDR_DIFF_VEC || asm_noperands (pat) >= 0)
5160 if (INSN_P (target))
5162 rtx load_insn = find_load (target);
5163 enum attr_type type = type_for_anomaly (target);
5164 int delay_needed = 0;
5165 if (cycles_since_jump < INT_MAX)
5166 cycles_since_jump++;
5168 if (load_insn && ENABLE_WA_SPECULATIVE_LOADS)
5170 if (trapping_loads_p (load_insn))
5173 else if (type == TYPE_SYNC && ENABLE_WA_SPECULATIVE_SYNCS)
5176 if (delay_needed > cycles_since_jump)
5178 rtx prev = prev_real_insn (label);
5179 delay_needed -= cycles_since_jump;
5181 fprintf (dump_file, "Adding %d nops after %d\n",
5182 delay_needed, INSN_UID (label));
5184 && INSN_CODE (prev) == CODE_FOR_cbranch_with_nops)
5191 "Reducing nops on insn %d.\n",
5194 x = XVECEXP (x, 0, 1);
5195 v = INTVAL (XVECEXP (x, 0, 0)) - delay_needed;
5196 XVECEXP (x, 0, 0) = GEN_INT (v);
5198 while (delay_needed-- > 0)
5199 emit_insn_after (gen_nop (), label);
5208 /* We use the machine specific reorg pass for emitting CSYNC instructions
5209 after conditional branches as needed.
5211 The Blackfin is unusual in that a code sequence like
5214 may speculatively perform the load even if the condition isn't true. This
5215 happens for a branch that is predicted not taken, because the pipeline
5216 isn't flushed or stalled, so the early stages of the following instructions,
5217 which perform the memory reference, are allowed to execute before the
5218 jump condition is evaluated.
5219 Therefore, we must insert additional instructions in all places where this
5220 could lead to incorrect behavior. The manual recommends CSYNC, while
5221 VDSP seems to use NOPs (even though its corresponding compiler option is
5224 When optimizing for speed, we emit NOPs, which seems faster than a CSYNC.
5225 When optimizing for size, we turn the branch into a predicted taken one.
5226 This may be slower due to mispredicts, but saves code size. */
5231 /* We are freeing block_for_insn in the toplev to keep compatibility
5232 with old MDEP_REORGS that are not CFG based. Recompute it now. */
5233 compute_bb_for_insn ();
5235 if (bfin_flag_schedule_insns2)
5237 splitting_for_sched = 1;
5239 splitting_for_sched = 0;
5241 timevar_push (TV_SCHED2);
5243 timevar_pop (TV_SCHED2);
5245 /* Examine the schedule and insert nops as necessary for 64-bit parallel
5247 bfin_gen_bundles ();
5252 /* Doloop optimization */
5253 if (cfun->machine->has_hardware_loops)
5254 bfin_reorg_loops (dump_file);
5256 workaround_speculation ();
5258 if (bfin_flag_var_tracking)
5260 timevar_push (TV_VAR_TRACKING);
5261 variable_tracking_main ();
5262 reorder_var_tracking_notes ();
5263 timevar_pop (TV_VAR_TRACKING);
5266 df_finish_pass (false);
5268 workaround_rts_anomaly ();
5271 /* Handle interrupt_handler, exception_handler and nmi_handler function
5272 attributes; arguments as in struct attribute_spec.handler. */
5275 handle_int_attribute (tree *node, tree name,
5276 tree args ATTRIBUTE_UNUSED,
5277 int flags ATTRIBUTE_UNUSED,
5281 if (TREE_CODE (x) == FUNCTION_DECL)
5284 if (TREE_CODE (x) != FUNCTION_TYPE)
5286 warning (OPT_Wattributes, "%qs attribute only applies to functions",
5287 IDENTIFIER_POINTER (name));
5288 *no_add_attrs = true;
5290 else if (funkind (x) != SUBROUTINE)
5291 error ("multiple function type attributes specified");
5296 /* Return 0 if the attributes for two types are incompatible, 1 if they
5297 are compatible, and 2 if they are nearly compatible (which causes a
5298 warning to be generated). */
5301 bfin_comp_type_attributes (const_tree type1, const_tree type2)
5303 e_funkind kind1, kind2;
5305 if (TREE_CODE (type1) != FUNCTION_TYPE)
5308 kind1 = funkind (type1);
5309 kind2 = funkind (type2);
5314 /* Check for mismatched modifiers */
5315 if (!lookup_attribute ("nesting", TYPE_ATTRIBUTES (type1))
5316 != !lookup_attribute ("nesting", TYPE_ATTRIBUTES (type2)))
5319 if (!lookup_attribute ("saveall", TYPE_ATTRIBUTES (type1))
5320 != !lookup_attribute ("saveall", TYPE_ATTRIBUTES (type2)))
5323 if (!lookup_attribute ("kspisusp", TYPE_ATTRIBUTES (type1))
5324 != !lookup_attribute ("kspisusp", TYPE_ATTRIBUTES (type2)))
5327 if (!lookup_attribute ("longcall", TYPE_ATTRIBUTES (type1))
5328 != !lookup_attribute ("longcall", TYPE_ATTRIBUTES (type2)))
5334 /* Handle a "longcall" or "shortcall" attribute; arguments as in
5335 struct attribute_spec.handler. */
5338 bfin_handle_longcall_attribute (tree *node, tree name,
5339 tree args ATTRIBUTE_UNUSED,
5340 int flags ATTRIBUTE_UNUSED,
5343 if (TREE_CODE (*node) != FUNCTION_TYPE
5344 && TREE_CODE (*node) != FIELD_DECL
5345 && TREE_CODE (*node) != TYPE_DECL)
5347 warning (OPT_Wattributes, "`%s' attribute only applies to functions",
5348 IDENTIFIER_POINTER (name));
5349 *no_add_attrs = true;
5352 if ((strcmp (IDENTIFIER_POINTER (name), "longcall") == 0
5353 && lookup_attribute ("shortcall", TYPE_ATTRIBUTES (*node)))
5354 || (strcmp (IDENTIFIER_POINTER (name), "shortcall") == 0
5355 && lookup_attribute ("longcall", TYPE_ATTRIBUTES (*node))))
5357 warning (OPT_Wattributes,
5358 "can't apply both longcall and shortcall attributes to the same function");
5359 *no_add_attrs = true;
5365 /* Handle a "l1_text" attribute; arguments as in
5366 struct attribute_spec.handler. */
5369 bfin_handle_l1_text_attribute (tree *node, tree name, tree ARG_UNUSED (args),
5370 int ARG_UNUSED (flags), bool *no_add_attrs)
5374 if (TREE_CODE (decl) != FUNCTION_DECL)
5376 error ("`%s' attribute only applies to functions",
5377 IDENTIFIER_POINTER (name));
5378 *no_add_attrs = true;
5381 /* The decl may have already been given a section attribute
5382 from a previous declaration. Ensure they match. */
5383 else if (DECL_SECTION_NAME (decl) != NULL_TREE
5384 && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
5387 error ("section of %q+D conflicts with previous declaration",
5389 *no_add_attrs = true;
5392 DECL_SECTION_NAME (decl) = build_string (9, ".l1.text");
5397 /* Handle a "l1_data", "l1_data_A" or "l1_data_B" attribute;
5398 arguments as in struct attribute_spec.handler. */
5401 bfin_handle_l1_data_attribute (tree *node, tree name, tree ARG_UNUSED (args),
5402 int ARG_UNUSED (flags), bool *no_add_attrs)
5406 if (TREE_CODE (decl) != VAR_DECL)
5408 error ("`%s' attribute only applies to variables",
5409 IDENTIFIER_POINTER (name));
5410 *no_add_attrs = true;
5412 else if (current_function_decl != NULL_TREE
5413 && !TREE_STATIC (decl))
5415 error ("`%s' attribute cannot be specified for local variables",
5416 IDENTIFIER_POINTER (name));
5417 *no_add_attrs = true;
5421 const char *section_name;
5423 if (strcmp (IDENTIFIER_POINTER (name), "l1_data") == 0)
5424 section_name = ".l1.data";
5425 else if (strcmp (IDENTIFIER_POINTER (name), "l1_data_A") == 0)
5426 section_name = ".l1.data.A";
5427 else if (strcmp (IDENTIFIER_POINTER (name), "l1_data_B") == 0)
5428 section_name = ".l1.data.B";
5432 /* The decl may have already been given a section attribute
5433 from a previous declaration. Ensure they match. */
5434 if (DECL_SECTION_NAME (decl) != NULL_TREE
5435 && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
5438 error ("section of %q+D conflicts with previous declaration",
5440 *no_add_attrs = true;
5443 DECL_SECTION_NAME (decl)
5444 = build_string (strlen (section_name) + 1, section_name);
5450 /* Table of valid machine attributes. */
5451 const struct attribute_spec bfin_attribute_table[] =
5453 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
5454 { "interrupt_handler", 0, 0, false, true, true, handle_int_attribute },
5455 { "exception_handler", 0, 0, false, true, true, handle_int_attribute },
5456 { "nmi_handler", 0, 0, false, true, true, handle_int_attribute },
5457 { "nesting", 0, 0, false, true, true, NULL },
5458 { "kspisusp", 0, 0, false, true, true, NULL },
5459 { "saveall", 0, 0, false, true, true, NULL },
5460 { "longcall", 0, 0, false, true, true, bfin_handle_longcall_attribute },
5461 { "shortcall", 0, 0, false, true, true, bfin_handle_longcall_attribute },
5462 { "l1_text", 0, 0, true, false, false, bfin_handle_l1_text_attribute },
5463 { "l1_data", 0, 0, true, false, false, bfin_handle_l1_data_attribute },
5464 { "l1_data_A", 0, 0, true, false, false, bfin_handle_l1_data_attribute },
5465 { "l1_data_B", 0, 0, true, false, false, bfin_handle_l1_data_attribute },
5466 { NULL, 0, 0, false, false, false, NULL }
5469 /* Implementation of TARGET_ASM_INTEGER. When using FD-PIC, we need to
5470 tell the assembler to generate pointers to function descriptors in
5474 bfin_assemble_integer (rtx value, unsigned int size, int aligned_p)
5476 if (TARGET_FDPIC && size == UNITS_PER_WORD)
5478 if (GET_CODE (value) == SYMBOL_REF
5479 && SYMBOL_REF_FUNCTION_P (value))
5481 fputs ("\t.picptr\tfuncdesc(", asm_out_file);
5482 output_addr_const (asm_out_file, value);
5483 fputs (")\n", asm_out_file);
5488 /* We've set the unaligned SI op to NULL, so we always have to
5489 handle the unaligned case here. */
5490 assemble_integer_with_op ("\t.4byte\t", value);
5494 return default_assemble_integer (value, size, aligned_p);
5497 /* Output the assembler code for a thunk function. THUNK_DECL is the
5498 declaration for the thunk function itself, FUNCTION is the decl for
5499 the target function. DELTA is an immediate constant offset to be
5500 added to THIS. If VCALL_OFFSET is nonzero, the word at
5501 *(*this + vcall_offset) should be added to THIS. */
5504 bfin_output_mi_thunk (FILE *file ATTRIBUTE_UNUSED,
5505 tree thunk ATTRIBUTE_UNUSED, HOST_WIDE_INT delta,
5506 HOST_WIDE_INT vcall_offset, tree function)
5509 /* The this parameter is passed as the first argument. */
5510 rtx this_rtx = gen_rtx_REG (Pmode, REG_R0);
5512 /* Adjust the this parameter by a fixed constant. */
5516 if (delta >= -64 && delta <= 63)
5518 xops[0] = GEN_INT (delta);
5519 output_asm_insn ("%1 += %0;", xops);
5521 else if (delta >= -128 && delta < -64)
5523 xops[0] = GEN_INT (delta + 64);
5524 output_asm_insn ("%1 += -64; %1 += %0;", xops);
5526 else if (delta > 63 && delta <= 126)
5528 xops[0] = GEN_INT (delta - 63);
5529 output_asm_insn ("%1 += 63; %1 += %0;", xops);
5533 xops[0] = GEN_INT (delta);
5534 output_asm_insn ("r3.l = %h0; r3.h = %d0; %1 = %1 + r3;", xops);
5538 /* Adjust the this parameter by a value stored in the vtable. */
5541 rtx p2tmp = gen_rtx_REG (Pmode, REG_P2);
5542 rtx tmp = gen_rtx_REG (Pmode, REG_R3);
5546 output_asm_insn ("%2 = r0; %2 = [%2];", xops);
5548 /* Adjust the this parameter. */
5549 xops[0] = gen_rtx_MEM (Pmode, plus_constant (p2tmp, vcall_offset));
5550 if (!memory_operand (xops[0], Pmode))
5552 rtx tmp2 = gen_rtx_REG (Pmode, REG_P1);
5553 xops[0] = GEN_INT (vcall_offset);
5555 output_asm_insn ("%h1 = %h0; %d1 = %d0; %2 = %2 + %1", xops);
5556 xops[0] = gen_rtx_MEM (Pmode, p2tmp);
5559 output_asm_insn ("%1 = %0; %2 = %2 + %1;", xops);
5562 xops[0] = XEXP (DECL_RTL (function), 0);
5563 if (1 || !flag_pic || (*targetm.binds_local_p) (function))
5564 output_asm_insn ("jump.l\t%P0", xops);
5567 /* Codes for all the Blackfin builtins. */
5573 BFIN_BUILTIN_COMPOSE_2X16,
5574 BFIN_BUILTIN_EXTRACTLO,
5575 BFIN_BUILTIN_EXTRACTHI,
5577 BFIN_BUILTIN_SSADD_2X16,
5578 BFIN_BUILTIN_SSSUB_2X16,
5579 BFIN_BUILTIN_SSADDSUB_2X16,
5580 BFIN_BUILTIN_SSSUBADD_2X16,
5581 BFIN_BUILTIN_MULT_2X16,
5582 BFIN_BUILTIN_MULTR_2X16,
5583 BFIN_BUILTIN_NEG_2X16,
5584 BFIN_BUILTIN_ABS_2X16,
5585 BFIN_BUILTIN_MIN_2X16,
5586 BFIN_BUILTIN_MAX_2X16,
5588 BFIN_BUILTIN_SSADD_1X16,
5589 BFIN_BUILTIN_SSSUB_1X16,
5590 BFIN_BUILTIN_MULT_1X16,
5591 BFIN_BUILTIN_MULTR_1X16,
5592 BFIN_BUILTIN_NORM_1X16,
5593 BFIN_BUILTIN_NEG_1X16,
5594 BFIN_BUILTIN_ABS_1X16,
5595 BFIN_BUILTIN_MIN_1X16,
5596 BFIN_BUILTIN_MAX_1X16,
5598 BFIN_BUILTIN_SUM_2X16,
5599 BFIN_BUILTIN_DIFFHL_2X16,
5600 BFIN_BUILTIN_DIFFLH_2X16,
5602 BFIN_BUILTIN_SSADD_1X32,
5603 BFIN_BUILTIN_SSSUB_1X32,
5604 BFIN_BUILTIN_NORM_1X32,
5605 BFIN_BUILTIN_ROUND_1X32,
5606 BFIN_BUILTIN_NEG_1X32,
5607 BFIN_BUILTIN_ABS_1X32,
5608 BFIN_BUILTIN_MIN_1X32,
5609 BFIN_BUILTIN_MAX_1X32,
5610 BFIN_BUILTIN_MULT_1X32,
5611 BFIN_BUILTIN_MULT_1X32X32,
5612 BFIN_BUILTIN_MULT_1X32X32NS,
5614 BFIN_BUILTIN_MULHISILL,
5615 BFIN_BUILTIN_MULHISILH,
5616 BFIN_BUILTIN_MULHISIHL,
5617 BFIN_BUILTIN_MULHISIHH,
5619 BFIN_BUILTIN_LSHIFT_1X16,
5620 BFIN_BUILTIN_LSHIFT_2X16,
5621 BFIN_BUILTIN_SSASHIFT_1X16,
5622 BFIN_BUILTIN_SSASHIFT_2X16,
5623 BFIN_BUILTIN_SSASHIFT_1X32,
5625 BFIN_BUILTIN_CPLX_MUL_16,
5626 BFIN_BUILTIN_CPLX_MAC_16,
5627 BFIN_BUILTIN_CPLX_MSU_16,
5629 BFIN_BUILTIN_CPLX_MUL_16_S40,
5630 BFIN_BUILTIN_CPLX_MAC_16_S40,
5631 BFIN_BUILTIN_CPLX_MSU_16_S40,
5633 BFIN_BUILTIN_CPLX_SQU,
5635 BFIN_BUILTIN_LOADBYTES,
5640 #define def_builtin(NAME, TYPE, CODE) \
5642 add_builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD, \
5646 /* Set up all builtin functions for this target. */
5648 bfin_init_builtins (void)
5650 tree V2HI_type_node = build_vector_type_for_mode (intHI_type_node, V2HImode);
5651 tree void_ftype_void
5652 = build_function_type (void_type_node, void_list_node);
5653 tree short_ftype_short
5654 = build_function_type_list (short_integer_type_node, short_integer_type_node,
5656 tree short_ftype_int_int
5657 = build_function_type_list (short_integer_type_node, integer_type_node,
5658 integer_type_node, NULL_TREE);
5659 tree int_ftype_int_int
5660 = build_function_type_list (integer_type_node, integer_type_node,
5661 integer_type_node, NULL_TREE);
5663 = build_function_type_list (integer_type_node, integer_type_node,
5665 tree short_ftype_int
5666 = build_function_type_list (short_integer_type_node, integer_type_node,
5668 tree int_ftype_v2hi_v2hi
5669 = build_function_type_list (integer_type_node, V2HI_type_node,
5670 V2HI_type_node, NULL_TREE);
5671 tree v2hi_ftype_v2hi_v2hi
5672 = build_function_type_list (V2HI_type_node, V2HI_type_node,
5673 V2HI_type_node, NULL_TREE);
5674 tree v2hi_ftype_v2hi_v2hi_v2hi
5675 = build_function_type_list (V2HI_type_node, V2HI_type_node,
5676 V2HI_type_node, V2HI_type_node, NULL_TREE);
5677 tree v2hi_ftype_int_int
5678 = build_function_type_list (V2HI_type_node, integer_type_node,
5679 integer_type_node, NULL_TREE);
5680 tree v2hi_ftype_v2hi_int
5681 = build_function_type_list (V2HI_type_node, V2HI_type_node,
5682 integer_type_node, NULL_TREE);
5683 tree int_ftype_short_short
5684 = build_function_type_list (integer_type_node, short_integer_type_node,
5685 short_integer_type_node, NULL_TREE);
5686 tree v2hi_ftype_v2hi
5687 = build_function_type_list (V2HI_type_node, V2HI_type_node, NULL_TREE);
5688 tree short_ftype_v2hi
5689 = build_function_type_list (short_integer_type_node, V2HI_type_node,
5692 = build_function_type_list (integer_type_node,
5693 build_pointer_type (integer_type_node),
5696 /* Add the remaining MMX insns with somewhat more complicated types. */
5697 def_builtin ("__builtin_bfin_csync", void_ftype_void, BFIN_BUILTIN_CSYNC);
5698 def_builtin ("__builtin_bfin_ssync", void_ftype_void, BFIN_BUILTIN_SSYNC);
5700 def_builtin ("__builtin_bfin_ones", short_ftype_int, BFIN_BUILTIN_ONES);
5702 def_builtin ("__builtin_bfin_compose_2x16", v2hi_ftype_int_int,
5703 BFIN_BUILTIN_COMPOSE_2X16);
5704 def_builtin ("__builtin_bfin_extract_hi", short_ftype_v2hi,
5705 BFIN_BUILTIN_EXTRACTHI);
5706 def_builtin ("__builtin_bfin_extract_lo", short_ftype_v2hi,
5707 BFIN_BUILTIN_EXTRACTLO);
5709 def_builtin ("__builtin_bfin_min_fr2x16", v2hi_ftype_v2hi_v2hi,
5710 BFIN_BUILTIN_MIN_2X16);
5711 def_builtin ("__builtin_bfin_max_fr2x16", v2hi_ftype_v2hi_v2hi,
5712 BFIN_BUILTIN_MAX_2X16);
5714 def_builtin ("__builtin_bfin_add_fr2x16", v2hi_ftype_v2hi_v2hi,
5715 BFIN_BUILTIN_SSADD_2X16);
5716 def_builtin ("__builtin_bfin_sub_fr2x16", v2hi_ftype_v2hi_v2hi,
5717 BFIN_BUILTIN_SSSUB_2X16);
5718 def_builtin ("__builtin_bfin_dspaddsubsat", v2hi_ftype_v2hi_v2hi,
5719 BFIN_BUILTIN_SSADDSUB_2X16);
5720 def_builtin ("__builtin_bfin_dspsubaddsat", v2hi_ftype_v2hi_v2hi,
5721 BFIN_BUILTIN_SSSUBADD_2X16);
5722 def_builtin ("__builtin_bfin_mult_fr2x16", v2hi_ftype_v2hi_v2hi,
5723 BFIN_BUILTIN_MULT_2X16);
5724 def_builtin ("__builtin_bfin_multr_fr2x16", v2hi_ftype_v2hi_v2hi,
5725 BFIN_BUILTIN_MULTR_2X16);
5726 def_builtin ("__builtin_bfin_negate_fr2x16", v2hi_ftype_v2hi,
5727 BFIN_BUILTIN_NEG_2X16);
5728 def_builtin ("__builtin_bfin_abs_fr2x16", v2hi_ftype_v2hi,
5729 BFIN_BUILTIN_ABS_2X16);
5731 def_builtin ("__builtin_bfin_min_fr1x16", short_ftype_int_int,
5732 BFIN_BUILTIN_MIN_1X16);
5733 def_builtin ("__builtin_bfin_max_fr1x16", short_ftype_int_int,
5734 BFIN_BUILTIN_MAX_1X16);
5736 def_builtin ("__builtin_bfin_add_fr1x16", short_ftype_int_int,
5737 BFIN_BUILTIN_SSADD_1X16);
5738 def_builtin ("__builtin_bfin_sub_fr1x16", short_ftype_int_int,
5739 BFIN_BUILTIN_SSSUB_1X16);
5740 def_builtin ("__builtin_bfin_mult_fr1x16", short_ftype_int_int,
5741 BFIN_BUILTIN_MULT_1X16);
5742 def_builtin ("__builtin_bfin_multr_fr1x16", short_ftype_int_int,
5743 BFIN_BUILTIN_MULTR_1X16);
5744 def_builtin ("__builtin_bfin_negate_fr1x16", short_ftype_short,
5745 BFIN_BUILTIN_NEG_1X16);
5746 def_builtin ("__builtin_bfin_abs_fr1x16", short_ftype_short,
5747 BFIN_BUILTIN_ABS_1X16);
5748 def_builtin ("__builtin_bfin_norm_fr1x16", short_ftype_int,
5749 BFIN_BUILTIN_NORM_1X16);
5751 def_builtin ("__builtin_bfin_sum_fr2x16", short_ftype_v2hi,
5752 BFIN_BUILTIN_SUM_2X16);
5753 def_builtin ("__builtin_bfin_diff_hl_fr2x16", short_ftype_v2hi,
5754 BFIN_BUILTIN_DIFFHL_2X16);
5755 def_builtin ("__builtin_bfin_diff_lh_fr2x16", short_ftype_v2hi,
5756 BFIN_BUILTIN_DIFFLH_2X16);
5758 def_builtin ("__builtin_bfin_mulhisill", int_ftype_v2hi_v2hi,
5759 BFIN_BUILTIN_MULHISILL);
5760 def_builtin ("__builtin_bfin_mulhisihl", int_ftype_v2hi_v2hi,
5761 BFIN_BUILTIN_MULHISIHL);
5762 def_builtin ("__builtin_bfin_mulhisilh", int_ftype_v2hi_v2hi,
5763 BFIN_BUILTIN_MULHISILH);
5764 def_builtin ("__builtin_bfin_mulhisihh", int_ftype_v2hi_v2hi,
5765 BFIN_BUILTIN_MULHISIHH);
5767 def_builtin ("__builtin_bfin_min_fr1x32", int_ftype_int_int,
5768 BFIN_BUILTIN_MIN_1X32);
5769 def_builtin ("__builtin_bfin_max_fr1x32", int_ftype_int_int,
5770 BFIN_BUILTIN_MAX_1X32);
5772 def_builtin ("__builtin_bfin_add_fr1x32", int_ftype_int_int,
5773 BFIN_BUILTIN_SSADD_1X32);
5774 def_builtin ("__builtin_bfin_sub_fr1x32", int_ftype_int_int,
5775 BFIN_BUILTIN_SSSUB_1X32);
5776 def_builtin ("__builtin_bfin_negate_fr1x32", int_ftype_int,
5777 BFIN_BUILTIN_NEG_1X32);
5778 def_builtin ("__builtin_bfin_abs_fr1x32", int_ftype_int,
5779 BFIN_BUILTIN_ABS_1X32);
5780 def_builtin ("__builtin_bfin_norm_fr1x32", short_ftype_int,
5781 BFIN_BUILTIN_NORM_1X32);
5782 def_builtin ("__builtin_bfin_round_fr1x32", short_ftype_int,
5783 BFIN_BUILTIN_ROUND_1X32);
5784 def_builtin ("__builtin_bfin_mult_fr1x32", int_ftype_short_short,
5785 BFIN_BUILTIN_MULT_1X32);
5786 def_builtin ("__builtin_bfin_mult_fr1x32x32", int_ftype_int_int,
5787 BFIN_BUILTIN_MULT_1X32X32);
5788 def_builtin ("__builtin_bfin_mult_fr1x32x32NS", int_ftype_int_int,
5789 BFIN_BUILTIN_MULT_1X32X32NS);
5792 def_builtin ("__builtin_bfin_shl_fr1x16", short_ftype_int_int,
5793 BFIN_BUILTIN_SSASHIFT_1X16);
5794 def_builtin ("__builtin_bfin_shl_fr2x16", v2hi_ftype_v2hi_int,
5795 BFIN_BUILTIN_SSASHIFT_2X16);
5796 def_builtin ("__builtin_bfin_lshl_fr1x16", short_ftype_int_int,
5797 BFIN_BUILTIN_LSHIFT_1X16);
5798 def_builtin ("__builtin_bfin_lshl_fr2x16", v2hi_ftype_v2hi_int,
5799 BFIN_BUILTIN_LSHIFT_2X16);
5800 def_builtin ("__builtin_bfin_shl_fr1x32", int_ftype_int_int,
5801 BFIN_BUILTIN_SSASHIFT_1X32);
5803 /* Complex numbers. */
5804 def_builtin ("__builtin_bfin_cmplx_add", v2hi_ftype_v2hi_v2hi,
5805 BFIN_BUILTIN_SSADD_2X16);
5806 def_builtin ("__builtin_bfin_cmplx_sub", v2hi_ftype_v2hi_v2hi,
5807 BFIN_BUILTIN_SSSUB_2X16);
5808 def_builtin ("__builtin_bfin_cmplx_mul", v2hi_ftype_v2hi_v2hi,
5809 BFIN_BUILTIN_CPLX_MUL_16);
5810 def_builtin ("__builtin_bfin_cmplx_mac", v2hi_ftype_v2hi_v2hi_v2hi,
5811 BFIN_BUILTIN_CPLX_MAC_16);
5812 def_builtin ("__builtin_bfin_cmplx_msu", v2hi_ftype_v2hi_v2hi_v2hi,
5813 BFIN_BUILTIN_CPLX_MSU_16);
5814 def_builtin ("__builtin_bfin_cmplx_mul_s40", v2hi_ftype_v2hi_v2hi,
5815 BFIN_BUILTIN_CPLX_MUL_16_S40);
5816 def_builtin ("__builtin_bfin_cmplx_mac_s40", v2hi_ftype_v2hi_v2hi_v2hi,
5817 BFIN_BUILTIN_CPLX_MAC_16_S40);
5818 def_builtin ("__builtin_bfin_cmplx_msu_s40", v2hi_ftype_v2hi_v2hi_v2hi,
5819 BFIN_BUILTIN_CPLX_MSU_16_S40);
5820 def_builtin ("__builtin_bfin_csqu_fr16", v2hi_ftype_v2hi,
5821 BFIN_BUILTIN_CPLX_SQU);
5823 /* "Unaligned" load. */
5824 def_builtin ("__builtin_bfin_loadbytes", int_ftype_pint,
5825 BFIN_BUILTIN_LOADBYTES);
5830 struct builtin_description
5832 const enum insn_code icode;
5833 const char *const name;
5834 const enum bfin_builtins code;
5838 static const struct builtin_description bdesc_2arg[] =
5840 { CODE_FOR_composev2hi, "__builtin_bfin_compose_2x16", BFIN_BUILTIN_COMPOSE_2X16, -1 },
5842 { CODE_FOR_ssashiftv2hi3, "__builtin_bfin_shl_fr2x16", BFIN_BUILTIN_SSASHIFT_2X16, -1 },
5843 { CODE_FOR_ssashifthi3, "__builtin_bfin_shl_fr1x16", BFIN_BUILTIN_SSASHIFT_1X16, -1 },
5844 { CODE_FOR_lshiftv2hi3, "__builtin_bfin_lshl_fr2x16", BFIN_BUILTIN_LSHIFT_2X16, -1 },
5845 { CODE_FOR_lshifthi3, "__builtin_bfin_lshl_fr1x16", BFIN_BUILTIN_LSHIFT_1X16, -1 },
5846 { CODE_FOR_ssashiftsi3, "__builtin_bfin_shl_fr1x32", BFIN_BUILTIN_SSASHIFT_1X32, -1 },
5848 { CODE_FOR_sminhi3, "__builtin_bfin_min_fr1x16", BFIN_BUILTIN_MIN_1X16, -1 },
5849 { CODE_FOR_smaxhi3, "__builtin_bfin_max_fr1x16", BFIN_BUILTIN_MAX_1X16, -1 },
5850 { CODE_FOR_ssaddhi3, "__builtin_bfin_add_fr1x16", BFIN_BUILTIN_SSADD_1X16, -1 },
5851 { CODE_FOR_sssubhi3, "__builtin_bfin_sub_fr1x16", BFIN_BUILTIN_SSSUB_1X16, -1 },
5853 { CODE_FOR_sminsi3, "__builtin_bfin_min_fr1x32", BFIN_BUILTIN_MIN_1X32, -1 },
5854 { CODE_FOR_smaxsi3, "__builtin_bfin_max_fr1x32", BFIN_BUILTIN_MAX_1X32, -1 },
5855 { CODE_FOR_ssaddsi3, "__builtin_bfin_add_fr1x32", BFIN_BUILTIN_SSADD_1X32, -1 },
5856 { CODE_FOR_sssubsi3, "__builtin_bfin_sub_fr1x32", BFIN_BUILTIN_SSSUB_1X32, -1 },
5858 { CODE_FOR_sminv2hi3, "__builtin_bfin_min_fr2x16", BFIN_BUILTIN_MIN_2X16, -1 },
5859 { CODE_FOR_smaxv2hi3, "__builtin_bfin_max_fr2x16", BFIN_BUILTIN_MAX_2X16, -1 },
5860 { CODE_FOR_ssaddv2hi3, "__builtin_bfin_add_fr2x16", BFIN_BUILTIN_SSADD_2X16, -1 },
5861 { CODE_FOR_sssubv2hi3, "__builtin_bfin_sub_fr2x16", BFIN_BUILTIN_SSSUB_2X16, -1 },
5862 { CODE_FOR_ssaddsubv2hi3, "__builtin_bfin_dspaddsubsat", BFIN_BUILTIN_SSADDSUB_2X16, -1 },
5863 { CODE_FOR_sssubaddv2hi3, "__builtin_bfin_dspsubaddsat", BFIN_BUILTIN_SSSUBADD_2X16, -1 },
5865 { CODE_FOR_flag_mulhisi, "__builtin_bfin_mult_fr1x32", BFIN_BUILTIN_MULT_1X32, MACFLAG_NONE },
5866 { CODE_FOR_flag_mulhi, "__builtin_bfin_mult_fr1x16", BFIN_BUILTIN_MULT_1X16, MACFLAG_T },
5867 { CODE_FOR_flag_mulhi, "__builtin_bfin_multr_fr1x16", BFIN_BUILTIN_MULTR_1X16, MACFLAG_NONE },
5868 { CODE_FOR_flag_mulv2hi, "__builtin_bfin_mult_fr2x16", BFIN_BUILTIN_MULT_2X16, MACFLAG_T },
5869 { CODE_FOR_flag_mulv2hi, "__builtin_bfin_multr_fr2x16", BFIN_BUILTIN_MULTR_2X16, MACFLAG_NONE },
5871 { CODE_FOR_mulhisi_ll, "__builtin_bfin_mulhisill", BFIN_BUILTIN_MULHISILL, -1 },
5872 { CODE_FOR_mulhisi_lh, "__builtin_bfin_mulhisilh", BFIN_BUILTIN_MULHISILH, -1 },
5873 { CODE_FOR_mulhisi_hl, "__builtin_bfin_mulhisihl", BFIN_BUILTIN_MULHISIHL, -1 },
5874 { CODE_FOR_mulhisi_hh, "__builtin_bfin_mulhisihh", BFIN_BUILTIN_MULHISIHH, -1 }
5878 static const struct builtin_description bdesc_1arg[] =
5880 { CODE_FOR_loadbytes, "__builtin_bfin_loadbytes", BFIN_BUILTIN_LOADBYTES, 0 },
5882 { CODE_FOR_ones, "__builtin_bfin_ones", BFIN_BUILTIN_ONES, 0 },
5884 { CODE_FOR_signbitshi2, "__builtin_bfin_norm_fr1x16", BFIN_BUILTIN_NORM_1X16, 0 },
5885 { CODE_FOR_ssneghi2, "__builtin_bfin_negate_fr1x16", BFIN_BUILTIN_NEG_1X16, 0 },
5886 { CODE_FOR_abshi2, "__builtin_bfin_abs_fr1x16", BFIN_BUILTIN_ABS_1X16, 0 },
5888 { CODE_FOR_signbitssi2, "__builtin_bfin_norm_fr1x32", BFIN_BUILTIN_NORM_1X32, 0 },
5889 { CODE_FOR_ssroundsi2, "__builtin_bfin_round_fr1x32", BFIN_BUILTIN_ROUND_1X32, 0 },
5890 { CODE_FOR_ssnegsi2, "__builtin_bfin_negate_fr1x32", BFIN_BUILTIN_NEG_1X32, 0 },
5891 { CODE_FOR_ssabssi2, "__builtin_bfin_abs_fr1x32", BFIN_BUILTIN_ABS_1X32, 0 },
5893 { CODE_FOR_movv2hi_hi_low, "__builtin_bfin_extract_lo", BFIN_BUILTIN_EXTRACTLO, 0 },
5894 { CODE_FOR_movv2hi_hi_high, "__builtin_bfin_extract_hi", BFIN_BUILTIN_EXTRACTHI, 0 },
5895 { CODE_FOR_ssnegv2hi2, "__builtin_bfin_negate_fr2x16", BFIN_BUILTIN_NEG_2X16, 0 },
5896 { CODE_FOR_ssabsv2hi2, "__builtin_bfin_abs_fr2x16", BFIN_BUILTIN_ABS_2X16, 0 }
5899 /* Errors in the source file can cause expand_expr to return const0_rtx
5900 where we expect a vector. To avoid crashing, use one of the vector
5901 clear instructions. */
5903 safe_vector_operand (rtx x, enum machine_mode mode)
5905 if (x != const0_rtx)
5907 x = gen_reg_rtx (SImode);
5909 emit_insn (gen_movsi (x, CONST0_RTX (SImode)));
5910 return gen_lowpart (mode, x);
5913 /* Subroutine of bfin_expand_builtin to take care of binop insns. MACFLAG is -1
5914 if this is a normal binary op, or one of the MACFLAG_xxx constants. */
5917 bfin_expand_binop_builtin (enum insn_code icode, tree exp, rtx target,
5921 tree arg0 = CALL_EXPR_ARG (exp, 0);
5922 tree arg1 = CALL_EXPR_ARG (exp, 1);
5923 rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
5924 rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
5925 enum machine_mode op0mode = GET_MODE (op0);
5926 enum machine_mode op1mode = GET_MODE (op1);
5927 enum machine_mode tmode = insn_data[icode].operand[0].mode;
5928 enum machine_mode mode0 = insn_data[icode].operand[1].mode;
5929 enum machine_mode mode1 = insn_data[icode].operand[2].mode;
5931 if (VECTOR_MODE_P (mode0))
5932 op0 = safe_vector_operand (op0, mode0);
5933 if (VECTOR_MODE_P (mode1))
5934 op1 = safe_vector_operand (op1, mode1);
5937 || GET_MODE (target) != tmode
5938 || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
5939 target = gen_reg_rtx (tmode);
5941 if ((op0mode == SImode || op0mode == VOIDmode) && mode0 == HImode)
5944 op0 = gen_lowpart (HImode, op0);
5946 if ((op1mode == SImode || op1mode == VOIDmode) && mode1 == HImode)
5949 op1 = gen_lowpart (HImode, op1);
5951 /* In case the insn wants input operands in modes different from
5952 the result, abort. */
5953 gcc_assert ((op0mode == mode0 || op0mode == VOIDmode)
5954 && (op1mode == mode1 || op1mode == VOIDmode));
5956 if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
5957 op0 = copy_to_mode_reg (mode0, op0);
5958 if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
5959 op1 = copy_to_mode_reg (mode1, op1);
5962 pat = GEN_FCN (icode) (target, op0, op1);
5964 pat = GEN_FCN (icode) (target, op0, op1, GEN_INT (macflag));
5972 /* Subroutine of bfin_expand_builtin to take care of unop insns. */
5975 bfin_expand_unop_builtin (enum insn_code icode, tree exp,
5979 tree arg0 = CALL_EXPR_ARG (exp, 0);
5980 rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
5981 enum machine_mode op0mode = GET_MODE (op0);
5982 enum machine_mode tmode = insn_data[icode].operand[0].mode;
5983 enum machine_mode mode0 = insn_data[icode].operand[1].mode;
5986 || GET_MODE (target) != tmode
5987 || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
5988 target = gen_reg_rtx (tmode);
5990 if (VECTOR_MODE_P (mode0))
5991 op0 = safe_vector_operand (op0, mode0);
5993 if (op0mode == SImode && mode0 == HImode)
5996 op0 = gen_lowpart (HImode, op0);
5998 gcc_assert (op0mode == mode0 || op0mode == VOIDmode);
6000 if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
6001 op0 = copy_to_mode_reg (mode0, op0);
6003 pat = GEN_FCN (icode) (target, op0);
6010 /* Expand an expression EXP that calls a built-in function,
6011 with result going to TARGET if that's convenient
6012 (and in mode MODE if that's convenient).
6013 SUBTARGET may be used as the target for computing one of EXP's operands.
6014 IGNORE is nonzero if the value is to be ignored. */
6017 bfin_expand_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
6018 rtx subtarget ATTRIBUTE_UNUSED,
6019 enum machine_mode mode ATTRIBUTE_UNUSED,
6020 int ignore ATTRIBUTE_UNUSED)
6023 enum insn_code icode;
6024 const struct builtin_description *d;
6025 tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
6026 unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
6027 tree arg0, arg1, arg2;
6028 rtx op0, op1, op2, accvec, pat, tmp1, tmp2, a0reg, a1reg;
6029 enum machine_mode tmode, mode0;
6033 case BFIN_BUILTIN_CSYNC:
6034 emit_insn (gen_csync ());
6036 case BFIN_BUILTIN_SSYNC:
6037 emit_insn (gen_ssync ());
6040 case BFIN_BUILTIN_DIFFHL_2X16:
6041 case BFIN_BUILTIN_DIFFLH_2X16:
6042 case BFIN_BUILTIN_SUM_2X16:
6043 arg0 = CALL_EXPR_ARG (exp, 0);
6044 op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6045 icode = (fcode == BFIN_BUILTIN_DIFFHL_2X16 ? CODE_FOR_subhilov2hi3
6046 : fcode == BFIN_BUILTIN_DIFFLH_2X16 ? CODE_FOR_sublohiv2hi3
6047 : CODE_FOR_ssaddhilov2hi3);
6048 tmode = insn_data[icode].operand[0].mode;
6049 mode0 = insn_data[icode].operand[1].mode;
6052 || GET_MODE (target) != tmode
6053 || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
6054 target = gen_reg_rtx (tmode);
6056 if (VECTOR_MODE_P (mode0))
6057 op0 = safe_vector_operand (op0, mode0);
6059 if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
6060 op0 = copy_to_mode_reg (mode0, op0);
6062 pat = GEN_FCN (icode) (target, op0, op0);
6068 case BFIN_BUILTIN_MULT_1X32X32:
6069 case BFIN_BUILTIN_MULT_1X32X32NS:
6070 arg0 = CALL_EXPR_ARG (exp, 0);
6071 arg1 = CALL_EXPR_ARG (exp, 1);
6072 op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6073 op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
6075 || !register_operand (target, SImode))
6076 target = gen_reg_rtx (SImode);
6078 a1reg = gen_rtx_REG (PDImode, REG_A1);
6079 a0reg = gen_rtx_REG (PDImode, REG_A0);
6080 tmp1 = gen_lowpart (V2HImode, op0);
6081 tmp2 = gen_lowpart (V2HImode, op1);
6082 emit_insn (gen_flag_macinit1hi (a1reg,
6083 gen_lowpart (HImode, op0),
6084 gen_lowpart (HImode, op1),
6085 GEN_INT (MACFLAG_FU)));
6086 emit_insn (gen_lshrpdi3 (a1reg, a1reg, GEN_INT (16)));
6088 if (fcode == BFIN_BUILTIN_MULT_1X32X32)
6089 emit_insn (gen_flag_mul_macv2hi_parts_acconly (a0reg, a1reg, tmp1, tmp2,
6090 const1_rtx, const1_rtx,
6091 const1_rtx, const0_rtx, a1reg,
6092 const0_rtx, GEN_INT (MACFLAG_NONE),
6093 GEN_INT (MACFLAG_M)));
6096 /* For saturating multiplication, there's exactly one special case
6097 to be handled: multiplying the smallest negative value with
6098 itself. Due to shift correction in fractional multiplies, this
6099 can overflow. Iff this happens, OP2 will contain 1, which, when
6100 added in 32 bits to the smallest negative, wraps to the largest
6101 positive, which is the result we want. */
6102 op2 = gen_reg_rtx (V2HImode);
6103 emit_insn (gen_packv2hi (op2, tmp1, tmp2, const0_rtx, const0_rtx));
6104 emit_insn (gen_movsibi (gen_rtx_REG (BImode, REG_CC),
6105 gen_lowpart (SImode, op2)));
6106 emit_insn (gen_flag_mul_macv2hi_parts_acconly_andcc0 (a0reg, a1reg, tmp1, tmp2,
6107 const1_rtx, const1_rtx,
6108 const1_rtx, const0_rtx, a1reg,
6109 const0_rtx, GEN_INT (MACFLAG_NONE),
6110 GEN_INT (MACFLAG_M)));
6111 op2 = gen_reg_rtx (SImode);
6112 emit_insn (gen_movbisi (op2, gen_rtx_REG (BImode, REG_CC)));
6114 emit_insn (gen_flag_machi_parts_acconly (a1reg, tmp2, tmp1,
6115 const1_rtx, const0_rtx,
6116 a1reg, const0_rtx, GEN_INT (MACFLAG_M)));
6117 emit_insn (gen_ashrpdi3 (a1reg, a1reg, GEN_INT (15)));
6118 emit_insn (gen_sum_of_accumulators (target, a0reg, a0reg, a1reg));
6119 if (fcode == BFIN_BUILTIN_MULT_1X32X32NS)
6120 emit_insn (gen_addsi3 (target, target, op2));
6123 case BFIN_BUILTIN_CPLX_MUL_16:
6124 case BFIN_BUILTIN_CPLX_MUL_16_S40:
6125 arg0 = CALL_EXPR_ARG (exp, 0);
6126 arg1 = CALL_EXPR_ARG (exp, 1);
6127 op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6128 op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
6129 accvec = gen_reg_rtx (V2PDImode);
6132 || GET_MODE (target) != V2HImode
6133 || ! (*insn_data[icode].operand[0].predicate) (target, V2HImode))
6134 target = gen_reg_rtx (tmode);
6135 if (! register_operand (op0, GET_MODE (op0)))
6136 op0 = copy_to_mode_reg (GET_MODE (op0), op0);
6137 if (! register_operand (op1, GET_MODE (op1)))
6138 op1 = copy_to_mode_reg (GET_MODE (op1), op1);
6140 if (fcode == BFIN_BUILTIN_CPLX_MUL_16)
6141 emit_insn (gen_flag_macinit1v2hi_parts (accvec, op0, op1, const0_rtx,
6142 const0_rtx, const0_rtx,
6143 const1_rtx, GEN_INT (MACFLAG_W32)));
6145 emit_insn (gen_flag_macinit1v2hi_parts (accvec, op0, op1, const0_rtx,
6146 const0_rtx, const0_rtx,
6147 const1_rtx, GEN_INT (MACFLAG_NONE)));
6148 emit_insn (gen_flag_macv2hi_parts (target, op0, op1, const1_rtx,
6149 const1_rtx, const1_rtx,
6150 const0_rtx, accvec, const1_rtx, const0_rtx,
6151 GEN_INT (MACFLAG_NONE), accvec));
6155 case BFIN_BUILTIN_CPLX_MAC_16:
6156 case BFIN_BUILTIN_CPLX_MSU_16:
6157 case BFIN_BUILTIN_CPLX_MAC_16_S40:
6158 case BFIN_BUILTIN_CPLX_MSU_16_S40:
6159 arg0 = CALL_EXPR_ARG (exp, 0);
6160 arg1 = CALL_EXPR_ARG (exp, 1);
6161 arg2 = CALL_EXPR_ARG (exp, 2);
6162 op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6163 op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
6164 op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
6165 accvec = gen_reg_rtx (V2PDImode);
6168 || GET_MODE (target) != V2HImode
6169 || ! (*insn_data[icode].operand[0].predicate) (target, V2HImode))
6170 target = gen_reg_rtx (tmode);
6171 if (! register_operand (op1, GET_MODE (op1)))
6172 op1 = copy_to_mode_reg (GET_MODE (op1), op1);
6173 if (! register_operand (op2, GET_MODE (op2)))
6174 op2 = copy_to_mode_reg (GET_MODE (op2), op2);
6176 tmp1 = gen_reg_rtx (SImode);
6177 tmp2 = gen_reg_rtx (SImode);
6178 emit_insn (gen_ashlsi3 (tmp1, gen_lowpart (SImode, op0), GEN_INT (16)));
6179 emit_move_insn (tmp2, gen_lowpart (SImode, op0));
6180 emit_insn (gen_movstricthi_1 (gen_lowpart (HImode, tmp2), const0_rtx));
6181 emit_insn (gen_load_accumulator_pair (accvec, tmp1, tmp2));
6182 if (fcode == BFIN_BUILTIN_CPLX_MAC_16
6183 || fcode == BFIN_BUILTIN_CPLX_MSU_16)
6184 emit_insn (gen_flag_macv2hi_parts_acconly (accvec, op1, op2, const0_rtx,
6185 const0_rtx, const0_rtx,
6186 const1_rtx, accvec, const0_rtx,
6188 GEN_INT (MACFLAG_W32)));
6190 emit_insn (gen_flag_macv2hi_parts_acconly (accvec, op1, op2, const0_rtx,
6191 const0_rtx, const0_rtx,
6192 const1_rtx, accvec, const0_rtx,
6194 GEN_INT (MACFLAG_NONE)));
6195 if (fcode == BFIN_BUILTIN_CPLX_MAC_16
6196 || fcode == BFIN_BUILTIN_CPLX_MAC_16_S40)
6206 emit_insn (gen_flag_macv2hi_parts (target, op1, op2, const1_rtx,
6207 const1_rtx, const1_rtx,
6208 const0_rtx, accvec, tmp1, tmp2,
6209 GEN_INT (MACFLAG_NONE), accvec));
6213 case BFIN_BUILTIN_CPLX_SQU:
6214 arg0 = CALL_EXPR_ARG (exp, 0);
6215 op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6216 accvec = gen_reg_rtx (V2PDImode);
6217 icode = CODE_FOR_flag_mulv2hi;
6218 tmp1 = gen_reg_rtx (V2HImode);
6219 tmp2 = gen_reg_rtx (V2HImode);
6222 || GET_MODE (target) != V2HImode
6223 || ! (*insn_data[icode].operand[0].predicate) (target, V2HImode))
6224 target = gen_reg_rtx (V2HImode);
6225 if (! register_operand (op0, GET_MODE (op0)))
6226 op0 = copy_to_mode_reg (GET_MODE (op0), op0);
6228 emit_insn (gen_flag_mulv2hi (tmp1, op0, op0, GEN_INT (MACFLAG_NONE)));
6230 emit_insn (gen_flag_mulhi_parts (gen_lowpart (HImode, tmp2), op0, op0,
6231 const0_rtx, const1_rtx,
6232 GEN_INT (MACFLAG_NONE)));
6234 emit_insn (gen_ssaddhi3_high_parts (target, tmp2, tmp2, tmp2, const0_rtx,
6236 emit_insn (gen_sssubhi3_low_parts (target, target, tmp1, tmp1,
6237 const0_rtx, const1_rtx));
6245 for (i = 0, d = bdesc_2arg; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
6246 if (d->code == fcode)
6247 return bfin_expand_binop_builtin (d->icode, exp, target,
6250 for (i = 0, d = bdesc_1arg; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
6251 if (d->code == fcode)
6252 return bfin_expand_unop_builtin (d->icode, exp, target);
6257 #undef TARGET_INIT_BUILTINS
6258 #define TARGET_INIT_BUILTINS bfin_init_builtins
6260 #undef TARGET_EXPAND_BUILTIN
6261 #define TARGET_EXPAND_BUILTIN bfin_expand_builtin
6263 #undef TARGET_ASM_GLOBALIZE_LABEL
6264 #define TARGET_ASM_GLOBALIZE_LABEL bfin_globalize_label
6266 #undef TARGET_ASM_FILE_START
6267 #define TARGET_ASM_FILE_START output_file_start
6269 #undef TARGET_ATTRIBUTE_TABLE
6270 #define TARGET_ATTRIBUTE_TABLE bfin_attribute_table
6272 #undef TARGET_COMP_TYPE_ATTRIBUTES
6273 #define TARGET_COMP_TYPE_ATTRIBUTES bfin_comp_type_attributes
6275 #undef TARGET_RTX_COSTS
6276 #define TARGET_RTX_COSTS bfin_rtx_costs
6278 #undef TARGET_ADDRESS_COST
6279 #define TARGET_ADDRESS_COST bfin_address_cost
6281 #undef TARGET_ASM_INTEGER
6282 #define TARGET_ASM_INTEGER bfin_assemble_integer
6284 #undef TARGET_MACHINE_DEPENDENT_REORG
6285 #define TARGET_MACHINE_DEPENDENT_REORG bfin_reorg
6287 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
6288 #define TARGET_FUNCTION_OK_FOR_SIBCALL bfin_function_ok_for_sibcall
6290 #undef TARGET_ASM_OUTPUT_MI_THUNK
6291 #define TARGET_ASM_OUTPUT_MI_THUNK bfin_output_mi_thunk
6292 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
6293 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true
6295 #undef TARGET_SCHED_ADJUST_COST
6296 #define TARGET_SCHED_ADJUST_COST bfin_adjust_cost
6298 #undef TARGET_SCHED_ISSUE_RATE
6299 #define TARGET_SCHED_ISSUE_RATE bfin_issue_rate
6301 #undef TARGET_PROMOTE_PROTOTYPES
6302 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
6303 #undef TARGET_PROMOTE_FUNCTION_ARGS
6304 #define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_const_tree_true
6305 #undef TARGET_PROMOTE_FUNCTION_RETURN
6306 #define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_const_tree_true
6308 #undef TARGET_ARG_PARTIAL_BYTES
6309 #define TARGET_ARG_PARTIAL_BYTES bfin_arg_partial_bytes
6311 #undef TARGET_PASS_BY_REFERENCE
6312 #define TARGET_PASS_BY_REFERENCE bfin_pass_by_reference
6314 #undef TARGET_SETUP_INCOMING_VARARGS
6315 #define TARGET_SETUP_INCOMING_VARARGS setup_incoming_varargs
6317 #undef TARGET_STRUCT_VALUE_RTX
6318 #define TARGET_STRUCT_VALUE_RTX bfin_struct_value_rtx
6320 #undef TARGET_VECTOR_MODE_SUPPORTED_P
6321 #define TARGET_VECTOR_MODE_SUPPORTED_P bfin_vector_mode_supported_p
6323 #undef TARGET_HANDLE_OPTION
6324 #define TARGET_HANDLE_OPTION bfin_handle_option
6326 #undef TARGET_DEFAULT_TARGET_FLAGS
6327 #define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
6329 #undef TARGET_SECONDARY_RELOAD
6330 #define TARGET_SECONDARY_RELOAD bfin_secondary_reload
6332 #undef TARGET_DELEGITIMIZE_ADDRESS
6333 #define TARGET_DELEGITIMIZE_ADDRESS bfin_delegitimize_address
6335 #undef TARGET_CANNOT_FORCE_CONST_MEM
6336 #define TARGET_CANNOT_FORCE_CONST_MEM bfin_cannot_force_const_mem
6338 #undef TARGET_RETURN_IN_MEMORY
6339 #define TARGET_RETURN_IN_MEMORY bfin_return_in_memory
6341 struct gcc_target targetm = TARGET_INITIALIZER;