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