1 /* The Blackfin code generation auxiliary output file.
2 Copyright (C) 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
3 Contributed by Analog Devices.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published
9 by the Free Software Foundation; either version 3, or (at your
10 option) any later version.
12 GCC is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
15 License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
23 #include "coretypes.h"
27 #include "hard-reg-set.h"
29 #include "insn-config.h"
30 #include "insn-codes.h"
31 #include "conditions.h"
32 #include "insn-flags.h"
34 #include "insn-attr.h"
41 #include "target-def.h"
47 #include "integrate.h"
49 #include "langhooks.h"
50 #include "bfin-protos.h"
52 #include "tm-constrs.h"
54 #include "basic-block.h"
55 #include "cfglayout.h"
59 /* A C structure for machine-specific, per-function data.
60 This is added to the cfun structure. */
61 struct GTY(()) machine_function
63 /* Set if we are notified by the doloop pass that a hardware loop
65 int has_hardware_loops;
66 /* Set if we create a memcpy pattern that uses loop registers. */
67 int has_loopreg_clobber;
70 /* Test and compare insns in bfin.md store the information needed to
71 generate branch and scc insns here. */
72 rtx bfin_compare_op0, bfin_compare_op1;
74 /* RTX for condition code flag register and RETS register */
75 extern GTY(()) rtx bfin_cc_rtx;
76 extern GTY(()) rtx bfin_rets_rtx;
77 rtx bfin_cc_rtx, bfin_rets_rtx;
79 int max_arg_registers = 0;
81 /* Arrays used when emitting register names. */
82 const char *short_reg_names[] = SHORT_REGISTER_NAMES;
83 const char *high_reg_names[] = HIGH_REGISTER_NAMES;
84 const char *dregs_pair_names[] = DREGS_PAIR_NAMES;
85 const char *byte_reg_names[] = BYTE_REGISTER_NAMES;
87 static int arg_regs[] = FUNCTION_ARG_REGISTERS;
89 /* Nonzero if -mshared-library-id was given. */
90 static int bfin_lib_id_given;
92 /* Nonzero if -fschedule-insns2 was given. We override it and
93 call the scheduler ourselves during reorg. */
94 static int bfin_flag_schedule_insns2;
96 /* Determines whether we run variable tracking in machine dependent
98 static int bfin_flag_var_tracking;
101 bfin_cpu_t bfin_cpu_type = BFIN_CPU_UNKNOWN;
103 /* -msi-revision support. There are three special values:
104 -1 -msi-revision=none.
105 0xffff -msi-revision=any. */
106 int bfin_si_revision;
108 /* The workarounds enabled */
109 unsigned int bfin_workarounds = 0;
116 unsigned int workarounds;
119 struct bfin_cpu bfin_cpus[] =
121 {"bf512", BFIN_CPU_BF512, 0x0000,
122 WA_SPECULATIVE_LOADS},
124 {"bf514", BFIN_CPU_BF514, 0x0000,
125 WA_SPECULATIVE_LOADS},
127 {"bf516", BFIN_CPU_BF516, 0x0000,
128 WA_SPECULATIVE_LOADS},
130 {"bf518", BFIN_CPU_BF518, 0x0000,
131 WA_SPECULATIVE_LOADS},
133 {"bf522", BFIN_CPU_BF522, 0x0002,
134 WA_SPECULATIVE_LOADS},
135 {"bf522", BFIN_CPU_BF522, 0x0001,
136 WA_SPECULATIVE_LOADS | WA_RETS},
137 {"bf522", BFIN_CPU_BF522, 0x0000,
138 WA_SPECULATIVE_LOADS | WA_RETS},
140 {"bf523", BFIN_CPU_BF523, 0x0002,
141 WA_SPECULATIVE_LOADS},
142 {"bf523", BFIN_CPU_BF523, 0x0001,
143 WA_SPECULATIVE_LOADS | WA_RETS},
144 {"bf523", BFIN_CPU_BF523, 0x0000,
145 WA_SPECULATIVE_LOADS | WA_RETS},
147 {"bf524", BFIN_CPU_BF524, 0x0002,
148 WA_SPECULATIVE_LOADS},
149 {"bf524", BFIN_CPU_BF524, 0x0001,
150 WA_SPECULATIVE_LOADS | WA_RETS},
151 {"bf524", BFIN_CPU_BF524, 0x0000,
152 WA_SPECULATIVE_LOADS | WA_RETS},
154 {"bf525", BFIN_CPU_BF525, 0x0002,
155 WA_SPECULATIVE_LOADS},
156 {"bf525", BFIN_CPU_BF525, 0x0001,
157 WA_SPECULATIVE_LOADS | WA_RETS},
158 {"bf525", BFIN_CPU_BF525, 0x0000,
159 WA_SPECULATIVE_LOADS | WA_RETS},
161 {"bf526", BFIN_CPU_BF526, 0x0002,
162 WA_SPECULATIVE_LOADS},
163 {"bf526", BFIN_CPU_BF526, 0x0001,
164 WA_SPECULATIVE_LOADS | WA_RETS},
165 {"bf526", BFIN_CPU_BF526, 0x0000,
166 WA_SPECULATIVE_LOADS | WA_RETS},
168 {"bf527", BFIN_CPU_BF527, 0x0002,
169 WA_SPECULATIVE_LOADS},
170 {"bf527", BFIN_CPU_BF527, 0x0001,
171 WA_SPECULATIVE_LOADS | WA_RETS},
172 {"bf527", BFIN_CPU_BF527, 0x0000,
173 WA_SPECULATIVE_LOADS | WA_RETS},
175 {"bf531", BFIN_CPU_BF531, 0x0006,
176 WA_SPECULATIVE_LOADS | WA_LOAD_LCREGS},
177 {"bf531", BFIN_CPU_BF531, 0x0005,
178 WA_SPECULATIVE_LOADS | WA_RETS | WA_05000283 | WA_05000315 | WA_LOAD_LCREGS},
179 {"bf531", BFIN_CPU_BF531, 0x0004,
180 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
181 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS},
182 {"bf531", BFIN_CPU_BF531, 0x0003,
183 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
184 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS},
186 {"bf532", BFIN_CPU_BF532, 0x0006,
187 WA_SPECULATIVE_LOADS | WA_LOAD_LCREGS},
188 {"bf532", BFIN_CPU_BF532, 0x0005,
189 WA_SPECULATIVE_LOADS | WA_RETS | WA_05000283 | WA_05000315 | WA_LOAD_LCREGS},
190 {"bf532", BFIN_CPU_BF532, 0x0004,
191 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
192 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS},
193 {"bf532", BFIN_CPU_BF532, 0x0003,
194 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
195 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS},
197 {"bf533", BFIN_CPU_BF533, 0x0006,
198 WA_SPECULATIVE_LOADS | WA_LOAD_LCREGS},
199 {"bf533", BFIN_CPU_BF533, 0x0005,
200 WA_SPECULATIVE_LOADS | WA_RETS | WA_05000283 | WA_05000315 | WA_LOAD_LCREGS},
201 {"bf533", BFIN_CPU_BF533, 0x0004,
202 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
203 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS},
204 {"bf533", BFIN_CPU_BF533, 0x0003,
205 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
206 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS},
208 {"bf534", BFIN_CPU_BF534, 0x0003,
209 WA_SPECULATIVE_LOADS | WA_RETS | WA_LOAD_LCREGS},
210 {"bf534", BFIN_CPU_BF534, 0x0002,
211 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
212 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS},
213 {"bf534", BFIN_CPU_BF534, 0x0001,
214 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
215 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS},
217 {"bf536", BFIN_CPU_BF536, 0x0003,
218 WA_SPECULATIVE_LOADS | WA_RETS | WA_LOAD_LCREGS},
219 {"bf536", BFIN_CPU_BF536, 0x0002,
220 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
221 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS},
222 {"bf536", BFIN_CPU_BF536, 0x0001,
223 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
224 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS},
226 {"bf537", BFIN_CPU_BF537, 0x0003,
227 WA_SPECULATIVE_LOADS | WA_RETS | WA_LOAD_LCREGS},
228 {"bf537", BFIN_CPU_BF537, 0x0002,
229 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
230 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS},
231 {"bf537", BFIN_CPU_BF537, 0x0001,
232 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
233 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS},
235 {"bf538", BFIN_CPU_BF538, 0x0005,
236 WA_SPECULATIVE_LOADS | WA_LOAD_LCREGS},
237 {"bf538", BFIN_CPU_BF538, 0x0004,
238 WA_SPECULATIVE_LOADS | WA_RETS | WA_LOAD_LCREGS},
239 {"bf538", BFIN_CPU_BF538, 0x0003,
240 WA_SPECULATIVE_LOADS | WA_RETS
241 | WA_05000283 | WA_05000315 | WA_LOAD_LCREGS},
242 {"bf538", BFIN_CPU_BF538, 0x0002,
243 WA_SPECULATIVE_LOADS | WA_RETS
244 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS},
246 {"bf539", BFIN_CPU_BF539, 0x0005,
247 WA_SPECULATIVE_LOADS | WA_LOAD_LCREGS},
248 {"bf539", BFIN_CPU_BF539, 0x0004,
249 WA_SPECULATIVE_LOADS | WA_RETS | WA_LOAD_LCREGS},
250 {"bf539", BFIN_CPU_BF539, 0x0003,
251 WA_SPECULATIVE_LOADS | WA_RETS
252 | WA_05000283 | WA_05000315 | WA_LOAD_LCREGS},
253 {"bf539", BFIN_CPU_BF539, 0x0002,
254 WA_SPECULATIVE_LOADS | WA_RETS
255 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS},
257 {"bf542", BFIN_CPU_BF542, 0x0002,
258 WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS},
259 {"bf542", BFIN_CPU_BF542, 0x0001,
260 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS},
261 {"bf542", BFIN_CPU_BF542, 0x0000,
262 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS | WA_LOAD_LCREGS},
264 {"bf544", BFIN_CPU_BF544, 0x0002,
265 WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS},
266 {"bf544", BFIN_CPU_BF544, 0x0001,
267 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS},
268 {"bf544", BFIN_CPU_BF544, 0x0000,
269 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS | WA_LOAD_LCREGS},
271 {"bf547", BFIN_CPU_BF547, 0x0002,
272 WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS},
273 {"bf547", BFIN_CPU_BF547, 0x0001,
274 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS},
275 {"bf547", BFIN_CPU_BF547, 0x0000,
276 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS | WA_LOAD_LCREGS},
278 {"bf548", BFIN_CPU_BF548, 0x0002,
279 WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS},
280 {"bf548", BFIN_CPU_BF548, 0x0001,
281 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS},
282 {"bf548", BFIN_CPU_BF548, 0x0000,
283 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS | WA_LOAD_LCREGS},
285 {"bf549", BFIN_CPU_BF549, 0x0002,
286 WA_SPECULATIVE_LOADS | WA_INDIRECT_CALLS},
287 {"bf549", BFIN_CPU_BF549, 0x0001,
288 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS},
289 {"bf549", BFIN_CPU_BF549, 0x0000,
290 WA_SPECULATIVE_LOADS | WA_RETS | WA_INDIRECT_CALLS | WA_LOAD_LCREGS},
292 {"bf561", BFIN_CPU_BF561, 0x0005, WA_RETS
293 | WA_05000283 | WA_05000315 | WA_LOAD_LCREGS},
294 {"bf561", BFIN_CPU_BF561, 0x0003,
295 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
296 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS},
297 {"bf561", BFIN_CPU_BF561, 0x0002,
298 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS
299 | WA_05000283 | WA_05000257 | WA_05000315 | WA_LOAD_LCREGS},
304 int splitting_for_sched, splitting_loops;
307 bfin_globalize_label (FILE *stream, const char *name)
309 fputs (".global ", stream);
310 assemble_name (stream, name);
316 output_file_start (void)
318 FILE *file = asm_out_file;
321 /* Variable tracking should be run after all optimizations which change order
322 of insns. It also needs a valid CFG. This can't be done in
323 override_options, because flag_var_tracking is finalized after
325 bfin_flag_var_tracking = flag_var_tracking;
326 flag_var_tracking = 0;
328 fprintf (file, ".file \"%s\";\n", input_filename);
330 for (i = 0; arg_regs[i] >= 0; i++)
332 max_arg_registers = i; /* how many arg reg used */
335 /* Called early in the compilation to conditionally modify
336 fixed_regs/call_used_regs. */
339 conditional_register_usage (void)
341 /* initialize condition code flag register rtx */
342 bfin_cc_rtx = gen_rtx_REG (BImode, REG_CC);
343 bfin_rets_rtx = gen_rtx_REG (Pmode, REG_RETS);
346 /* Examine machine-dependent attributes of function type FUNTYPE and return its
347 type. See the definition of E_FUNKIND. */
350 funkind (const_tree funtype)
352 tree attrs = TYPE_ATTRIBUTES (funtype);
353 if (lookup_attribute ("interrupt_handler", attrs))
354 return INTERRUPT_HANDLER;
355 else if (lookup_attribute ("exception_handler", attrs))
356 return EXCPT_HANDLER;
357 else if (lookup_attribute ("nmi_handler", attrs))
363 /* Legitimize PIC addresses. If the address is already position-independent,
364 we return ORIG. Newly generated position-independent addresses go into a
365 reg. This is REG if nonzero, otherwise we allocate register(s) as
366 necessary. PICREG is the register holding the pointer to the PIC offset
370 legitimize_pic_address (rtx orig, rtx reg, rtx picreg)
375 if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == LABEL_REF)
380 if (TARGET_ID_SHARED_LIBRARY)
381 unspec = UNSPEC_MOVE_PIC;
382 else if (GET_CODE (addr) == SYMBOL_REF
383 && SYMBOL_REF_FUNCTION_P (addr))
384 unspec = UNSPEC_FUNCDESC_GOT17M4;
386 unspec = UNSPEC_MOVE_FDPIC;
390 gcc_assert (can_create_pseudo_p ());
391 reg = gen_reg_rtx (Pmode);
394 tmp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), unspec);
395 new_rtx = gen_const_mem (Pmode, gen_rtx_PLUS (Pmode, picreg, tmp));
397 emit_move_insn (reg, new_rtx);
398 if (picreg == pic_offset_table_rtx)
399 crtl->uses_pic_offset_table = 1;
403 else if (GET_CODE (addr) == CONST || GET_CODE (addr) == PLUS)
407 if (GET_CODE (addr) == CONST)
409 addr = XEXP (addr, 0);
410 gcc_assert (GET_CODE (addr) == PLUS);
413 if (XEXP (addr, 0) == picreg)
418 gcc_assert (can_create_pseudo_p ());
419 reg = gen_reg_rtx (Pmode);
422 base = legitimize_pic_address (XEXP (addr, 0), reg, picreg);
423 addr = legitimize_pic_address (XEXP (addr, 1),
424 base == reg ? NULL_RTX : reg,
427 if (GET_CODE (addr) == CONST_INT)
429 gcc_assert (! reload_in_progress && ! reload_completed);
430 addr = force_reg (Pmode, addr);
433 if (GET_CODE (addr) == PLUS && CONSTANT_P (XEXP (addr, 1)))
435 base = gen_rtx_PLUS (Pmode, base, XEXP (addr, 0));
436 addr = XEXP (addr, 1);
439 return gen_rtx_PLUS (Pmode, base, addr);
445 /* Stack frame layout. */
447 /* For a given REGNO, determine whether it must be saved in the function
448 prologue. IS_INTHANDLER specifies whether we're generating a normal
449 prologue or an interrupt/exception one. */
451 must_save_p (bool is_inthandler, unsigned regno)
453 if (D_REGNO_P (regno))
455 bool is_eh_return_reg = false;
456 if (crtl->calls_eh_return)
461 unsigned test = EH_RETURN_DATA_REGNO (j);
462 if (test == INVALID_REGNUM)
465 is_eh_return_reg = true;
469 return (is_eh_return_reg
470 || (df_regs_ever_live_p (regno)
471 && !fixed_regs[regno]
472 && (is_inthandler || !call_used_regs[regno])));
474 else if (P_REGNO_P (regno))
476 return ((df_regs_ever_live_p (regno)
477 && !fixed_regs[regno]
478 && (is_inthandler || !call_used_regs[regno]))
480 && (ENABLE_WA_05000283 || ENABLE_WA_05000315)
483 && regno == PIC_OFFSET_TABLE_REGNUM
484 && (crtl->uses_pic_offset_table
485 || (TARGET_ID_SHARED_LIBRARY && !current_function_is_leaf))));
488 return ((is_inthandler || !call_used_regs[regno])
489 && (df_regs_ever_live_p (regno)
490 || (!leaf_function_p () && call_used_regs[regno])));
494 /* Compute the number of DREGS to save with a push_multiple operation.
495 This could include registers that aren't modified in the function,
496 since push_multiple only takes a range of registers.
497 If IS_INTHANDLER, then everything that is live must be saved, even
498 if normally call-clobbered.
499 If CONSECUTIVE, return the number of registers we can save in one
500 instruction with a push/pop multiple instruction. */
503 n_dregs_to_save (bool is_inthandler, bool consecutive)
508 for (i = REG_R7 + 1; i-- != REG_R0;)
510 if (must_save_p (is_inthandler, i))
512 else if (consecutive)
518 /* Like n_dregs_to_save, but compute number of PREGS to save. */
521 n_pregs_to_save (bool is_inthandler, bool consecutive)
526 for (i = REG_P5 + 1; i-- != REG_P0;)
527 if (must_save_p (is_inthandler, i))
529 else if (consecutive)
534 /* Determine if we are going to save the frame pointer in the prologue. */
537 must_save_fp_p (void)
539 return frame_pointer_needed || df_regs_ever_live_p (REG_FP);
543 stack_frame_needed_p (void)
545 /* EH return puts a new return address into the frame using an
546 address relative to the frame pointer. */
547 if (crtl->calls_eh_return)
549 return frame_pointer_needed;
552 /* Emit code to save registers in the prologue. SAVEALL is nonzero if we
553 must save all registers; this is used for interrupt handlers.
554 SPREG contains (reg:SI REG_SP). IS_INTHANDLER is true if we're doing
555 this for an interrupt (or exception) handler. */
558 expand_prologue_reg_save (rtx spreg, int saveall, bool is_inthandler)
560 rtx predec1 = gen_rtx_PRE_DEC (SImode, spreg);
561 rtx predec = gen_rtx_MEM (SImode, predec1);
562 int ndregs = saveall ? 8 : n_dregs_to_save (is_inthandler, false);
563 int npregs = saveall ? 6 : n_pregs_to_save (is_inthandler, false);
564 int ndregs_consec = saveall ? 8 : n_dregs_to_save (is_inthandler, true);
565 int npregs_consec = saveall ? 6 : n_pregs_to_save (is_inthandler, true);
567 int total_consec = ndregs_consec + npregs_consec;
570 if (saveall || is_inthandler)
572 rtx insn = emit_move_insn (predec, gen_rtx_REG (SImode, REG_ASTAT));
574 RTX_FRAME_RELATED_P (insn) = 1;
575 for (dregno = REG_LT0; dregno <= REG_LB1; dregno++)
576 if (! current_function_is_leaf
577 || cfun->machine->has_hardware_loops
578 || cfun->machine->has_loopreg_clobber
579 || (ENABLE_WA_05000257
580 && (dregno == REG_LC0 || dregno == REG_LC1)))
582 insn = emit_move_insn (predec, gen_rtx_REG (SImode, dregno));
583 RTX_FRAME_RELATED_P (insn) = 1;
587 if (total_consec != 0)
590 rtx val = GEN_INT (-total_consec * 4);
591 rtx pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total_consec + 2));
593 XVECEXP (pat, 0, 0) = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, val),
594 UNSPEC_PUSH_MULTIPLE);
595 XVECEXP (pat, 0, total_consec + 1) = gen_rtx_SET (VOIDmode, spreg,
599 RTX_FRAME_RELATED_P (XVECEXP (pat, 0, total_consec + 1)) = 1;
600 d_to_save = ndregs_consec;
601 dregno = REG_R7 + 1 - ndregs_consec;
602 pregno = REG_P5 + 1 - npregs_consec;
603 for (i = 0; i < total_consec; i++)
605 rtx memref = gen_rtx_MEM (word_mode,
606 gen_rtx_PLUS (Pmode, spreg,
607 GEN_INT (- i * 4 - 4)));
611 subpat = gen_rtx_SET (VOIDmode, memref, gen_rtx_REG (word_mode,
617 subpat = gen_rtx_SET (VOIDmode, memref, gen_rtx_REG (word_mode,
620 XVECEXP (pat, 0, i + 1) = subpat;
621 RTX_FRAME_RELATED_P (subpat) = 1;
623 insn = emit_insn (pat);
624 RTX_FRAME_RELATED_P (insn) = 1;
627 for (dregno = REG_R0; ndregs != ndregs_consec; dregno++)
629 if (must_save_p (is_inthandler, dregno))
631 rtx insn = emit_move_insn (predec, gen_rtx_REG (word_mode, dregno));
632 RTX_FRAME_RELATED_P (insn) = 1;
636 for (pregno = REG_P0; npregs != npregs_consec; pregno++)
638 if (must_save_p (is_inthandler, pregno))
640 rtx insn = emit_move_insn (predec, gen_rtx_REG (word_mode, pregno));
641 RTX_FRAME_RELATED_P (insn) = 1;
645 for (i = REG_P7 + 1; i < REG_CC; i++)
648 && (df_regs_ever_live_p (i)
649 || (!leaf_function_p () && call_used_regs[i]))))
652 if (i == REG_A0 || i == REG_A1)
653 insn = emit_move_insn (gen_rtx_MEM (PDImode, predec1),
654 gen_rtx_REG (PDImode, i));
656 insn = emit_move_insn (predec, gen_rtx_REG (SImode, i));
657 RTX_FRAME_RELATED_P (insn) = 1;
661 /* Emit code to restore registers in the epilogue. SAVEALL is nonzero if we
662 must save all registers; this is used for interrupt handlers.
663 SPREG contains (reg:SI REG_SP). IS_INTHANDLER is true if we're doing
664 this for an interrupt (or exception) handler. */
667 expand_epilogue_reg_restore (rtx spreg, bool saveall, bool is_inthandler)
669 rtx postinc1 = gen_rtx_POST_INC (SImode, spreg);
670 rtx postinc = gen_rtx_MEM (SImode, postinc1);
672 int ndregs = saveall ? 8 : n_dregs_to_save (is_inthandler, false);
673 int npregs = saveall ? 6 : n_pregs_to_save (is_inthandler, false);
674 int ndregs_consec = saveall ? 8 : n_dregs_to_save (is_inthandler, true);
675 int npregs_consec = saveall ? 6 : n_pregs_to_save (is_inthandler, true);
676 int total_consec = ndregs_consec + npregs_consec;
680 /* A slightly crude technique to stop flow from trying to delete "dead"
682 MEM_VOLATILE_P (postinc) = 1;
684 for (i = REG_CC - 1; i > REG_P7; i--)
687 && (df_regs_ever_live_p (i)
688 || (!leaf_function_p () && call_used_regs[i]))))
690 if (i == REG_A0 || i == REG_A1)
692 rtx mem = gen_rtx_MEM (PDImode, postinc1);
693 MEM_VOLATILE_P (mem) = 1;
694 emit_move_insn (gen_rtx_REG (PDImode, i), mem);
697 emit_move_insn (gen_rtx_REG (SImode, i), postinc);
700 regno = REG_P5 - npregs_consec;
701 for (; npregs != npregs_consec; regno--)
703 if (must_save_p (is_inthandler, regno))
705 emit_move_insn (gen_rtx_REG (word_mode, regno), postinc);
709 regno = REG_R7 - ndregs_consec;
710 for (; ndregs != ndregs_consec; regno--)
712 if (must_save_p (is_inthandler, regno))
714 emit_move_insn (gen_rtx_REG (word_mode, regno), postinc);
719 if (total_consec != 0)
721 rtx pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total_consec + 1));
723 = gen_rtx_SET (VOIDmode, spreg,
724 gen_rtx_PLUS (Pmode, spreg,
725 GEN_INT (total_consec * 4)));
727 if (npregs_consec > 0)
732 for (i = 0; i < total_consec; i++)
735 ? gen_rtx_PLUS (Pmode, spreg, GEN_INT (i * 4))
737 rtx memref = gen_rtx_MEM (word_mode, addr);
740 XVECEXP (pat, 0, i + 1)
741 = gen_rtx_SET (VOIDmode, gen_rtx_REG (word_mode, regno), memref);
743 if (npregs_consec > 0)
745 if (--npregs_consec == 0)
750 insn = emit_insn (pat);
751 RTX_FRAME_RELATED_P (insn) = 1;
753 if (saveall || is_inthandler)
755 for (regno = REG_LB1; regno >= REG_LT0; regno--)
756 if (! current_function_is_leaf
757 || cfun->machine->has_hardware_loops
758 || cfun->machine->has_loopreg_clobber
759 || (ENABLE_WA_05000257 && (regno == REG_LC0 || regno == REG_LC1)))
760 emit_move_insn (gen_rtx_REG (SImode, regno), postinc);
762 emit_move_insn (gen_rtx_REG (SImode, REG_ASTAT), postinc);
766 /* Perform any needed actions needed for a function that is receiving a
767 variable number of arguments.
771 MODE and TYPE are the mode and type of the current parameter.
773 PRETEND_SIZE is a variable that should be set to the amount of stack
774 that must be pushed by the prolog to pretend that our caller pushed
777 Normally, this macro will push all remaining incoming registers on the
778 stack and set PRETEND_SIZE to the length of the registers pushed.
781 - VDSP C compiler manual (our ABI) says that a variable args function
782 should save the R0, R1 and R2 registers in the stack.
783 - The caller will always leave space on the stack for the
784 arguments that are passed in registers, so we dont have
785 to leave any extra space.
786 - now, the vastart pointer can access all arguments from the stack. */
789 setup_incoming_varargs (CUMULATIVE_ARGS *cum,
790 enum machine_mode mode ATTRIBUTE_UNUSED,
791 tree type ATTRIBUTE_UNUSED, int *pretend_size,
800 /* The move for named arguments will be generated automatically by the
801 compiler. We need to generate the move rtx for the unnamed arguments
802 if they are in the first 3 words. We assume at least 1 named argument
803 exists, so we never generate [ARGP] = R0 here. */
805 for (i = cum->words + 1; i < max_arg_registers; i++)
807 mem = gen_rtx_MEM (Pmode,
808 plus_constant (arg_pointer_rtx, (i * UNITS_PER_WORD)));
809 emit_move_insn (mem, gen_rtx_REG (Pmode, i));
815 /* Value should be nonzero if functions must have frame pointers.
816 Zero means the frame pointer need not be set up (and parms may
817 be accessed via the stack pointer) in functions that seem suitable. */
820 bfin_frame_pointer_required (void)
822 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
824 if (fkind != SUBROUTINE)
827 /* We turn on -fomit-frame-pointer if -momit-leaf-frame-pointer is used,
828 so we have to override it for non-leaf functions. */
829 if (TARGET_OMIT_LEAF_FRAME_POINTER && ! current_function_is_leaf)
835 /* Return the number of registers pushed during the prologue. */
838 n_regs_saved_by_prologue (void)
840 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
841 bool is_inthandler = fkind != SUBROUTINE;
842 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
843 bool all = (lookup_attribute ("saveall", attrs) != NULL_TREE
844 || (is_inthandler && !current_function_is_leaf));
845 int ndregs = all ? 8 : n_dregs_to_save (is_inthandler, false);
846 int npregs = all ? 6 : n_pregs_to_save (is_inthandler, false);
847 int n = ndregs + npregs;
850 if (all || stack_frame_needed_p ())
851 /* We use a LINK instruction in this case. */
855 if (must_save_fp_p ())
857 if (! current_function_is_leaf)
861 if (fkind != SUBROUTINE || all)
863 /* Increment once for ASTAT. */
865 if (! current_function_is_leaf
866 || cfun->machine->has_hardware_loops
867 || cfun->machine->has_loopreg_clobber)
873 if (fkind != SUBROUTINE)
876 if (lookup_attribute ("nesting", attrs))
880 for (i = REG_P7 + 1; i < REG_CC; i++)
882 || (fkind != SUBROUTINE
883 && (df_regs_ever_live_p (i)
884 || (!leaf_function_p () && call_used_regs[i]))))
885 n += i == REG_A0 || i == REG_A1 ? 2 : 1;
890 /* Return the offset between two registers, one to be eliminated, and the other
891 its replacement, at the start of a routine. */
894 bfin_initial_elimination_offset (int from, int to)
896 HOST_WIDE_INT offset = 0;
898 if (from == ARG_POINTER_REGNUM)
899 offset = n_regs_saved_by_prologue () * 4;
901 if (to == STACK_POINTER_REGNUM)
903 if (crtl->outgoing_args_size >= FIXED_STACK_AREA)
904 offset += crtl->outgoing_args_size;
905 else if (crtl->outgoing_args_size)
906 offset += FIXED_STACK_AREA;
908 offset += get_frame_size ();
914 /* Emit code to load a constant CONSTANT into register REG; setting
915 RTX_FRAME_RELATED_P on all insns we generate if RELATED is true.
916 Make sure that the insns we generate need not be split. */
919 frame_related_constant_load (rtx reg, HOST_WIDE_INT constant, bool related)
922 rtx cst = GEN_INT (constant);
924 if (constant >= -32768 && constant < 65536)
925 insn = emit_move_insn (reg, cst);
928 /* We don't call split_load_immediate here, since dwarf2out.c can get
929 confused about some of the more clever sequences it can generate. */
930 insn = emit_insn (gen_movsi_high (reg, cst));
932 RTX_FRAME_RELATED_P (insn) = 1;
933 insn = emit_insn (gen_movsi_low (reg, reg, cst));
936 RTX_FRAME_RELATED_P (insn) = 1;
939 /* Generate efficient code to add a value to a P register.
940 Set RTX_FRAME_RELATED_P on the generated insns if FRAME is nonzero.
941 EPILOGUE_P is zero if this function is called for prologue,
942 otherwise it's nonzero. And it's less than zero if this is for
946 add_to_reg (rtx reg, HOST_WIDE_INT value, int frame, int epilogue_p)
951 /* Choose whether to use a sequence using a temporary register, or
952 a sequence with multiple adds. We can add a signed 7-bit value
953 in one instruction. */
954 if (value > 120 || value < -120)
962 /* For prologue or normal epilogue, P1 can be safely used
963 as the temporary register. For sibcall epilogue, we try to find
964 a call used P register, which will be restored in epilogue.
965 If we cannot find such a P register, we have to use one I register
969 tmpreg = gen_rtx_REG (SImode, REG_P1);
973 for (i = REG_P0; i <= REG_P5; i++)
974 if ((df_regs_ever_live_p (i) && ! call_used_regs[i])
976 && i == PIC_OFFSET_TABLE_REGNUM
977 && (crtl->uses_pic_offset_table
978 || (TARGET_ID_SHARED_LIBRARY
979 && ! current_function_is_leaf))))
982 tmpreg = gen_rtx_REG (SImode, i);
985 tmpreg = gen_rtx_REG (SImode, REG_P1);
986 tmpreg2 = gen_rtx_REG (SImode, REG_I0);
987 emit_move_insn (tmpreg2, tmpreg);
992 frame_related_constant_load (tmpreg, value, TRUE);
994 insn = emit_move_insn (tmpreg, GEN_INT (value));
996 insn = emit_insn (gen_addsi3 (reg, reg, tmpreg));
998 RTX_FRAME_RELATED_P (insn) = 1;
1000 if (tmpreg2 != NULL_RTX)
1001 emit_move_insn (tmpreg, tmpreg2);
1011 else if (size < -60)
1012 /* We could use -62, but that would leave the stack unaligned, so
1016 insn = emit_insn (gen_addsi3 (reg, reg, GEN_INT (size)));
1018 RTX_FRAME_RELATED_P (insn) = 1;
1024 /* Generate a LINK insn for a frame sized FRAME_SIZE. If this constant
1025 is too large, generate a sequence of insns that has the same effect.
1026 SPREG contains (reg:SI REG_SP). */
1029 emit_link_insn (rtx spreg, HOST_WIDE_INT frame_size)
1031 HOST_WIDE_INT link_size = frame_size;
1035 if (link_size > 262140)
1038 /* Use a LINK insn with as big a constant as possible, then subtract
1039 any remaining size from the SP. */
1040 insn = emit_insn (gen_link (GEN_INT (-8 - link_size)));
1041 RTX_FRAME_RELATED_P (insn) = 1;
1043 for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
1045 rtx set = XVECEXP (PATTERN (insn), 0, i);
1046 gcc_assert (GET_CODE (set) == SET);
1047 RTX_FRAME_RELATED_P (set) = 1;
1050 frame_size -= link_size;
1054 /* Must use a call-clobbered PREG that isn't the static chain. */
1055 rtx tmpreg = gen_rtx_REG (Pmode, REG_P1);
1057 frame_related_constant_load (tmpreg, -frame_size, TRUE);
1058 insn = emit_insn (gen_addsi3 (spreg, spreg, tmpreg));
1059 RTX_FRAME_RELATED_P (insn) = 1;
1063 /* Return the number of bytes we must reserve for outgoing arguments
1064 in the current function's stack frame. */
1066 static HOST_WIDE_INT
1067 arg_area_size (void)
1069 if (crtl->outgoing_args_size)
1071 if (crtl->outgoing_args_size >= FIXED_STACK_AREA)
1072 return crtl->outgoing_args_size;
1074 return FIXED_STACK_AREA;
1079 /* Save RETS and FP, and allocate a stack frame. ALL is true if the
1080 function must save all its registers (true only for certain interrupt
1084 do_link (rtx spreg, HOST_WIDE_INT frame_size, bool all)
1086 frame_size += arg_area_size ();
1088 if (all || stack_frame_needed_p ()
1089 || (must_save_fp_p () && ! current_function_is_leaf))
1090 emit_link_insn (spreg, frame_size);
1093 if (! current_function_is_leaf)
1095 rtx pat = gen_movsi (gen_rtx_MEM (Pmode,
1096 gen_rtx_PRE_DEC (Pmode, spreg)),
1098 rtx insn = emit_insn (pat);
1099 RTX_FRAME_RELATED_P (insn) = 1;
1101 if (must_save_fp_p ())
1103 rtx pat = gen_movsi (gen_rtx_MEM (Pmode,
1104 gen_rtx_PRE_DEC (Pmode, spreg)),
1105 gen_rtx_REG (Pmode, REG_FP));
1106 rtx insn = emit_insn (pat);
1107 RTX_FRAME_RELATED_P (insn) = 1;
1109 add_to_reg (spreg, -frame_size, 1, 0);
1113 /* Like do_link, but used for epilogues to deallocate the stack frame.
1114 EPILOGUE_P is zero if this function is called for prologue,
1115 otherwise it's nonzero. And it's less than zero if this is for
1116 sibcall epilogue. */
1119 do_unlink (rtx spreg, HOST_WIDE_INT frame_size, bool all, int epilogue_p)
1121 frame_size += arg_area_size ();
1123 if (all || stack_frame_needed_p ())
1124 emit_insn (gen_unlink ());
1127 rtx postinc = gen_rtx_MEM (Pmode, gen_rtx_POST_INC (Pmode, spreg));
1129 add_to_reg (spreg, frame_size, 0, epilogue_p);
1130 if (must_save_fp_p ())
1132 rtx fpreg = gen_rtx_REG (Pmode, REG_FP);
1133 emit_move_insn (fpreg, postinc);
1136 if (! current_function_is_leaf)
1138 emit_move_insn (bfin_rets_rtx, postinc);
1139 emit_use (bfin_rets_rtx);
1144 /* Generate a prologue suitable for a function of kind FKIND. This is
1145 called for interrupt and exception handler prologues.
1146 SPREG contains (reg:SI REG_SP). */
1149 expand_interrupt_handler_prologue (rtx spreg, e_funkind fkind, bool all)
1151 HOST_WIDE_INT frame_size = get_frame_size ();
1152 rtx predec1 = gen_rtx_PRE_DEC (SImode, spreg);
1153 rtx predec = gen_rtx_MEM (SImode, predec1);
1155 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1156 tree kspisusp = lookup_attribute ("kspisusp", attrs);
1160 insn = emit_move_insn (spreg, gen_rtx_REG (Pmode, REG_USP));
1161 RTX_FRAME_RELATED_P (insn) = 1;
1164 /* We need space on the stack in case we need to save the argument
1166 if (fkind == EXCPT_HANDLER)
1168 insn = emit_insn (gen_addsi3 (spreg, spreg, GEN_INT (-12)));
1169 RTX_FRAME_RELATED_P (insn) = 1;
1172 /* If we're calling other functions, they won't save their call-clobbered
1173 registers, so we must save everything here. */
1174 if (!current_function_is_leaf)
1176 expand_prologue_reg_save (spreg, all, true);
1178 if (ENABLE_WA_05000283 || ENABLE_WA_05000315)
1180 rtx chipid = GEN_INT (trunc_int_for_mode (0xFFC00014, SImode));
1181 rtx p5reg = gen_rtx_REG (Pmode, REG_P5);
1182 emit_insn (gen_movbi (bfin_cc_rtx, const1_rtx));
1183 emit_insn (gen_movsi_high (p5reg, chipid));
1184 emit_insn (gen_movsi_low (p5reg, p5reg, chipid));
1185 emit_insn (gen_dummy_load (p5reg, bfin_cc_rtx));
1188 if (lookup_attribute ("nesting", attrs))
1190 rtx srcreg = gen_rtx_REG (Pmode, (fkind == EXCPT_HANDLER ? REG_RETX
1191 : fkind == NMI_HANDLER ? REG_RETN
1193 insn = emit_move_insn (predec, srcreg);
1194 RTX_FRAME_RELATED_P (insn) = 1;
1197 do_link (spreg, frame_size, all);
1199 if (fkind == EXCPT_HANDLER)
1201 rtx r0reg = gen_rtx_REG (SImode, REG_R0);
1202 rtx r1reg = gen_rtx_REG (SImode, REG_R1);
1203 rtx r2reg = gen_rtx_REG (SImode, REG_R2);
1206 insn = emit_move_insn (r0reg, gen_rtx_REG (SImode, REG_SEQSTAT));
1207 insn = emit_insn (gen_ashrsi3 (r0reg, r0reg, GEN_INT (26)));
1208 insn = emit_insn (gen_ashlsi3 (r0reg, r0reg, GEN_INT (26)));
1209 insn = emit_move_insn (r1reg, spreg);
1210 insn = emit_move_insn (r2reg, gen_rtx_REG (Pmode, REG_FP));
1211 insn = emit_insn (gen_addsi3 (r2reg, r2reg, GEN_INT (8)));
1215 /* Generate an epilogue suitable for a function of kind FKIND. This is
1216 called for interrupt and exception handler epilogues.
1217 SPREG contains (reg:SI REG_SP). */
1220 expand_interrupt_handler_epilogue (rtx spreg, e_funkind fkind, bool all)
1222 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1223 rtx postinc1 = gen_rtx_POST_INC (SImode, spreg);
1224 rtx postinc = gen_rtx_MEM (SImode, postinc1);
1226 /* A slightly crude technique to stop flow from trying to delete "dead"
1228 MEM_VOLATILE_P (postinc) = 1;
1230 do_unlink (spreg, get_frame_size (), all, 1);
1232 if (lookup_attribute ("nesting", attrs))
1234 rtx srcreg = gen_rtx_REG (Pmode, (fkind == EXCPT_HANDLER ? REG_RETX
1235 : fkind == NMI_HANDLER ? REG_RETN
1237 emit_move_insn (srcreg, postinc);
1240 /* If we're calling other functions, they won't save their call-clobbered
1241 registers, so we must save (and restore) everything here. */
1242 if (!current_function_is_leaf)
1245 expand_epilogue_reg_restore (spreg, all, true);
1247 /* Deallocate any space we left on the stack in case we needed to save the
1248 argument registers. */
1249 if (fkind == EXCPT_HANDLER)
1250 emit_insn (gen_addsi3 (spreg, spreg, GEN_INT (12)));
1252 emit_jump_insn (gen_return_internal (GEN_INT (fkind)));
1255 /* Used while emitting the prologue to generate code to load the correct value
1256 into the PIC register, which is passed in DEST. */
1259 bfin_load_pic_reg (rtx dest)
1261 struct cgraph_local_info *i = NULL;
1264 i = cgraph_local_info (current_function_decl);
1266 /* Functions local to the translation unit don't need to reload the
1267 pic reg, since the caller always passes a usable one. */
1269 return pic_offset_table_rtx;
1271 if (bfin_lib_id_given)
1272 addr = plus_constant (pic_offset_table_rtx, -4 - bfin_library_id * 4);
1274 addr = gen_rtx_PLUS (Pmode, pic_offset_table_rtx,
1275 gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx),
1276 UNSPEC_LIBRARY_OFFSET));
1277 insn = emit_insn (gen_movsi (dest, gen_rtx_MEM (Pmode, addr)));
1281 /* Generate RTL for the prologue of the current function. */
1284 bfin_expand_prologue (void)
1286 HOST_WIDE_INT frame_size = get_frame_size ();
1287 rtx spreg = gen_rtx_REG (Pmode, REG_SP);
1288 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
1289 rtx pic_reg_loaded = NULL_RTX;
1290 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1291 bool all = lookup_attribute ("saveall", attrs) != NULL_TREE;
1293 if (fkind != SUBROUTINE)
1295 expand_interrupt_handler_prologue (spreg, fkind, all);
1299 if (crtl->limit_stack
1300 || (TARGET_STACK_CHECK_L1
1301 && !DECL_NO_LIMIT_STACK (current_function_decl)))
1303 HOST_WIDE_INT offset
1304 = bfin_initial_elimination_offset (ARG_POINTER_REGNUM,
1305 STACK_POINTER_REGNUM);
1306 rtx lim = crtl->limit_stack ? stack_limit_rtx : NULL_RTX;
1307 rtx p2reg = gen_rtx_REG (Pmode, REG_P2);
1311 emit_move_insn (p2reg, gen_int_mode (0xFFB00000, SImode));
1312 emit_move_insn (p2reg, gen_rtx_MEM (Pmode, p2reg));
1315 if (GET_CODE (lim) == SYMBOL_REF)
1317 if (TARGET_ID_SHARED_LIBRARY)
1319 rtx p1reg = gen_rtx_REG (Pmode, REG_P1);
1321 pic_reg_loaded = bfin_load_pic_reg (p2reg);
1322 val = legitimize_pic_address (stack_limit_rtx, p1reg,
1324 emit_move_insn (p1reg, val);
1325 frame_related_constant_load (p2reg, offset, FALSE);
1326 emit_insn (gen_addsi3 (p2reg, p2reg, p1reg));
1331 rtx limit = plus_constant (lim, offset);
1332 emit_move_insn (p2reg, limit);
1339 emit_move_insn (p2reg, lim);
1340 add_to_reg (p2reg, offset, 0, 0);
1343 emit_insn (gen_compare_lt (bfin_cc_rtx, spreg, lim));
1344 emit_insn (gen_trapifcc ());
1346 expand_prologue_reg_save (spreg, all, false);
1348 do_link (spreg, frame_size, false);
1350 if (TARGET_ID_SHARED_LIBRARY
1352 && (crtl->uses_pic_offset_table
1353 || !current_function_is_leaf))
1354 bfin_load_pic_reg (pic_offset_table_rtx);
1357 /* Generate RTL for the epilogue of the current function. NEED_RETURN is zero
1358 if this is for a sibcall. EH_RETURN is nonzero if we're expanding an
1359 eh_return pattern. SIBCALL_P is true if this is a sibcall epilogue,
1363 bfin_expand_epilogue (int need_return, int eh_return, bool sibcall_p)
1365 rtx spreg = gen_rtx_REG (Pmode, REG_SP);
1366 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
1367 int e = sibcall_p ? -1 : 1;
1368 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1369 bool all = lookup_attribute ("saveall", attrs) != NULL_TREE;
1371 if (fkind != SUBROUTINE)
1373 expand_interrupt_handler_epilogue (spreg, fkind, all);
1377 do_unlink (spreg, get_frame_size (), false, e);
1379 expand_epilogue_reg_restore (spreg, all, false);
1381 /* Omit the return insn if this is for a sibcall. */
1386 emit_insn (gen_addsi3 (spreg, spreg, gen_rtx_REG (Pmode, REG_P2)));
1388 emit_jump_insn (gen_return_internal (GEN_INT (SUBROUTINE)));
1391 /* Return nonzero if register OLD_REG can be renamed to register NEW_REG. */
1394 bfin_hard_regno_rename_ok (unsigned int old_reg ATTRIBUTE_UNUSED,
1395 unsigned int new_reg)
1397 /* Interrupt functions can only use registers that have already been
1398 saved by the prologue, even if they would normally be
1401 if (funkind (TREE_TYPE (current_function_decl)) != SUBROUTINE
1402 && !df_regs_ever_live_p (new_reg))
1408 /* Return the value of the return address for the frame COUNT steps up
1409 from the current frame, after the prologue.
1410 We punt for everything but the current frame by returning const0_rtx. */
1413 bfin_return_addr_rtx (int count)
1418 return get_hard_reg_initial_val (Pmode, REG_RETS);
1422 bfin_delegitimize_address (rtx orig_x)
1426 if (GET_CODE (x) != MEM)
1430 if (GET_CODE (x) == PLUS
1431 && GET_CODE (XEXP (x, 1)) == UNSPEC
1432 && XINT (XEXP (x, 1), 1) == UNSPEC_MOVE_PIC
1433 && GET_CODE (XEXP (x, 0)) == REG
1434 && REGNO (XEXP (x, 0)) == PIC_OFFSET_TABLE_REGNUM)
1435 return XVECEXP (XEXP (x, 1), 0, 0);
1440 /* This predicate is used to compute the length of a load/store insn.
1441 OP is a MEM rtx, we return nonzero if its addressing mode requires a
1442 32-bit instruction. */
1445 effective_address_32bit_p (rtx op, enum machine_mode mode)
1447 HOST_WIDE_INT offset;
1449 mode = GET_MODE (op);
1452 if (GET_CODE (op) != PLUS)
1454 gcc_assert (REG_P (op) || GET_CODE (op) == POST_INC
1455 || GET_CODE (op) == PRE_DEC || GET_CODE (op) == POST_DEC);
1459 if (GET_CODE (XEXP (op, 1)) == UNSPEC)
1462 offset = INTVAL (XEXP (op, 1));
1464 /* All byte loads use a 16-bit offset. */
1465 if (GET_MODE_SIZE (mode) == 1)
1468 if (GET_MODE_SIZE (mode) == 4)
1470 /* Frame pointer relative loads can use a negative offset, all others
1471 are restricted to a small positive one. */
1472 if (XEXP (op, 0) == frame_pointer_rtx)
1473 return offset < -128 || offset > 60;
1474 return offset < 0 || offset > 60;
1477 /* Must be HImode now. */
1478 return offset < 0 || offset > 30;
1481 /* Returns true if X is a memory reference using an I register. */
1483 bfin_dsp_memref_p (rtx x)
1488 if (GET_CODE (x) == POST_INC || GET_CODE (x) == PRE_INC
1489 || GET_CODE (x) == POST_DEC || GET_CODE (x) == PRE_DEC)
1494 /* Return cost of the memory address ADDR.
1495 All addressing modes are equally cheap on the Blackfin. */
1498 bfin_address_cost (rtx addr ATTRIBUTE_UNUSED, bool speed ATTRIBUTE_UNUSED)
1503 /* Subroutine of print_operand; used to print a memory reference X to FILE. */
1506 print_address_operand (FILE *file, rtx x)
1508 switch (GET_CODE (x))
1511 output_address (XEXP (x, 0));
1512 fprintf (file, "+");
1513 output_address (XEXP (x, 1));
1517 fprintf (file, "--");
1518 output_address (XEXP (x, 0));
1521 output_address (XEXP (x, 0));
1522 fprintf (file, "++");
1525 output_address (XEXP (x, 0));
1526 fprintf (file, "--");
1530 gcc_assert (GET_CODE (x) != MEM);
1531 print_operand (file, x, 0);
1536 /* Adding intp DImode support by Tony
1542 print_operand (FILE *file, rtx x, char code)
1544 enum machine_mode mode;
1548 if (GET_MODE (current_output_insn) == SImode)
1549 fprintf (file, " ||");
1551 fprintf (file, ";");
1555 mode = GET_MODE (x);
1560 switch (GET_CODE (x))
1563 fprintf (file, "e");
1566 fprintf (file, "ne");
1569 fprintf (file, "g");
1572 fprintf (file, "l");
1575 fprintf (file, "ge");
1578 fprintf (file, "le");
1581 fprintf (file, "g");
1584 fprintf (file, "l");
1587 fprintf (file, "ge");
1590 fprintf (file, "le");
1593 output_operand_lossage ("invalid %%j value");
1597 case 'J': /* reverse logic */
1598 switch (GET_CODE(x))
1601 fprintf (file, "ne");
1604 fprintf (file, "e");
1607 fprintf (file, "le");
1610 fprintf (file, "ge");
1613 fprintf (file, "l");
1616 fprintf (file, "g");
1619 fprintf (file, "le");
1622 fprintf (file, "ge");
1625 fprintf (file, "l");
1628 fprintf (file, "g");
1631 output_operand_lossage ("invalid %%J value");
1636 switch (GET_CODE (x))
1642 fprintf (file, "%s", short_reg_names[REGNO (x)]);
1644 output_operand_lossage ("invalid operand for code '%c'", code);
1646 else if (code == 'd')
1649 fprintf (file, "%s", high_reg_names[REGNO (x)]);
1651 output_operand_lossage ("invalid operand for code '%c'", code);
1653 else if (code == 'w')
1655 if (REGNO (x) == REG_A0 || REGNO (x) == REG_A1)
1656 fprintf (file, "%s.w", reg_names[REGNO (x)]);
1658 output_operand_lossage ("invalid operand for code '%c'", code);
1660 else if (code == 'x')
1662 if (REGNO (x) == REG_A0 || REGNO (x) == REG_A1)
1663 fprintf (file, "%s.x", reg_names[REGNO (x)]);
1665 output_operand_lossage ("invalid operand for code '%c'", code);
1667 else if (code == 'v')
1669 if (REGNO (x) == REG_A0)
1670 fprintf (file, "AV0");
1671 else if (REGNO (x) == REG_A1)
1672 fprintf (file, "AV1");
1674 output_operand_lossage ("invalid operand for code '%c'", code);
1676 else if (code == 'D')
1678 if (D_REGNO_P (REGNO (x)))
1679 fprintf (file, "%s", dregs_pair_names[REGNO (x)]);
1681 output_operand_lossage ("invalid operand for code '%c'", code);
1683 else if (code == 'H')
1685 if ((mode == DImode || mode == DFmode) && REG_P (x))
1686 fprintf (file, "%s", reg_names[REGNO (x) + 1]);
1688 output_operand_lossage ("invalid operand for code '%c'", code);
1690 else if (code == 'T')
1692 if (D_REGNO_P (REGNO (x)))
1693 fprintf (file, "%s", byte_reg_names[REGNO (x)]);
1695 output_operand_lossage ("invalid operand for code '%c'", code);
1698 fprintf (file, "%s", reg_names[REGNO (x)]);
1704 print_address_operand (file, x);
1716 fputs ("(FU)", file);
1719 fputs ("(T)", file);
1722 fputs ("(TFU)", file);
1725 fputs ("(W32)", file);
1728 fputs ("(IS)", file);
1731 fputs ("(IU)", file);
1734 fputs ("(IH)", file);
1737 fputs ("(M)", file);
1740 fputs ("(IS,M)", file);
1743 fputs ("(ISS2)", file);
1746 fputs ("(S2RND)", file);
1753 else if (code == 'b')
1755 if (INTVAL (x) == 0)
1757 else if (INTVAL (x) == 1)
1763 /* Moves to half registers with d or h modifiers always use unsigned
1765 else if (code == 'd')
1766 x = GEN_INT ((INTVAL (x) >> 16) & 0xffff);
1767 else if (code == 'h')
1768 x = GEN_INT (INTVAL (x) & 0xffff);
1769 else if (code == 'N')
1770 x = GEN_INT (-INTVAL (x));
1771 else if (code == 'X')
1772 x = GEN_INT (exact_log2 (0xffffffff & INTVAL (x)));
1773 else if (code == 'Y')
1774 x = GEN_INT (exact_log2 (0xffffffff & ~INTVAL (x)));
1775 else if (code == 'Z')
1776 /* Used for LINK insns. */
1777 x = GEN_INT (-8 - INTVAL (x));
1782 output_addr_const (file, x);
1786 output_operand_lossage ("invalid const_double operand");
1790 switch (XINT (x, 1))
1792 case UNSPEC_MOVE_PIC:
1793 output_addr_const (file, XVECEXP (x, 0, 0));
1794 fprintf (file, "@GOT");
1797 case UNSPEC_MOVE_FDPIC:
1798 output_addr_const (file, XVECEXP (x, 0, 0));
1799 fprintf (file, "@GOT17M4");
1802 case UNSPEC_FUNCDESC_GOT17M4:
1803 output_addr_const (file, XVECEXP (x, 0, 0));
1804 fprintf (file, "@FUNCDESC_GOT17M4");
1807 case UNSPEC_LIBRARY_OFFSET:
1808 fprintf (file, "_current_shared_library_p5_offset_");
1817 output_addr_const (file, x);
1822 /* Argument support functions. */
1824 /* Initialize a variable CUM of type CUMULATIVE_ARGS
1825 for a call to a function whose data type is FNTYPE.
1826 For a library call, FNTYPE is 0.
1827 VDSP C Compiler manual, our ABI says that
1828 first 3 words of arguments will use R0, R1 and R2.
1832 init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype,
1833 rtx libname ATTRIBUTE_UNUSED)
1835 static CUMULATIVE_ARGS zero_cum;
1839 /* Set up the number of registers to use for passing arguments. */
1841 cum->nregs = max_arg_registers;
1842 cum->arg_regs = arg_regs;
1844 cum->call_cookie = CALL_NORMAL;
1845 /* Check for a longcall attribute. */
1846 if (fntype && lookup_attribute ("shortcall", TYPE_ATTRIBUTES (fntype)))
1847 cum->call_cookie |= CALL_SHORT;
1848 else if (fntype && lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype)))
1849 cum->call_cookie |= CALL_LONG;
1854 /* Update the data in CUM to advance over an argument
1855 of mode MODE and data type TYPE.
1856 (TYPE is null for libcalls where that information may not be available.) */
1859 function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
1860 int named ATTRIBUTE_UNUSED)
1862 int count, bytes, words;
1864 bytes = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
1865 words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
1867 cum->words += words;
1868 cum->nregs -= words;
1870 if (cum->nregs <= 0)
1873 cum->arg_regs = NULL;
1877 for (count = 1; count <= words; count++)
1884 /* Define where to put the arguments to a function.
1885 Value is zero to push the argument on the stack,
1886 or a hard register in which to store the argument.
1888 MODE is the argument's machine mode.
1889 TYPE is the data type of the argument (as a tree).
1890 This is null for libcalls where that information may
1892 CUM is a variable of type CUMULATIVE_ARGS which gives info about
1893 the preceding args and about the function being called.
1894 NAMED is nonzero if this argument is a named parameter
1895 (otherwise it is an extra parameter matching an ellipsis). */
1898 function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
1899 int named ATTRIBUTE_UNUSED)
1902 = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
1904 if (mode == VOIDmode)
1905 /* Compute operand 2 of the call insn. */
1906 return GEN_INT (cum->call_cookie);
1912 return gen_rtx_REG (mode, *(cum->arg_regs));
1917 /* For an arg passed partly in registers and partly in memory,
1918 this is the number of bytes passed in registers.
1919 For args passed entirely in registers or entirely in memory, zero.
1921 Refer VDSP C Compiler manual, our ABI.
1922 First 3 words are in registers. So, if an argument is larger
1923 than the registers available, it will span the register and
1927 bfin_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode,
1928 tree type ATTRIBUTE_UNUSED,
1929 bool named ATTRIBUTE_UNUSED)
1932 = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
1933 int bytes_left = cum->nregs * UNITS_PER_WORD;
1938 if (bytes_left == 0)
1940 if (bytes > bytes_left)
1945 /* Variable sized types are passed by reference. */
1948 bfin_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
1949 enum machine_mode mode ATTRIBUTE_UNUSED,
1950 const_tree type, bool named ATTRIBUTE_UNUSED)
1952 return type && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST;
1955 /* Decide whether a type should be returned in memory (true)
1956 or in a register (false). This is called by the macro
1957 TARGET_RETURN_IN_MEMORY. */
1960 bfin_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
1962 int size = int_size_in_bytes (type);
1963 return size > 2 * UNITS_PER_WORD || size == -1;
1966 /* Register in which address to store a structure value
1967 is passed to a function. */
1969 bfin_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
1970 int incoming ATTRIBUTE_UNUSED)
1972 return gen_rtx_REG (Pmode, REG_P0);
1975 /* Return true when register may be used to pass function parameters. */
1978 function_arg_regno_p (int n)
1981 for (i = 0; arg_regs[i] != -1; i++)
1982 if (n == arg_regs[i])
1987 /* Returns 1 if OP contains a symbol reference */
1990 symbolic_reference_mentioned_p (rtx op)
1992 register const char *fmt;
1995 if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF)
1998 fmt = GET_RTX_FORMAT (GET_CODE (op));
1999 for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
2005 for (j = XVECLEN (op, i) - 1; j >= 0; j--)
2006 if (symbolic_reference_mentioned_p (XVECEXP (op, i, j)))
2010 else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i)))
2017 /* Decide whether we can make a sibling call to a function. DECL is the
2018 declaration of the function being targeted by the call and EXP is the
2019 CALL_EXPR representing the call. */
2022 bfin_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED,
2023 tree exp ATTRIBUTE_UNUSED)
2025 struct cgraph_local_info *this_func, *called_func;
2026 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
2027 if (fkind != SUBROUTINE)
2029 if (!TARGET_ID_SHARED_LIBRARY || TARGET_SEP_DATA)
2032 /* When compiling for ID shared libraries, can't sibcall a local function
2033 from a non-local function, because the local function thinks it does
2034 not need to reload P5 in the prologue, but the sibcall wil pop P5 in the
2035 sibcall epilogue, and we end up with the wrong value in P5. */
2038 /* Not enough information. */
2041 this_func = cgraph_local_info (current_function_decl);
2042 called_func = cgraph_local_info (decl);
2043 return !called_func->local || this_func->local;
2046 /* Emit RTL insns to initialize the variable parts of a trampoline at
2047 TRAMP. FNADDR is an RTX for the address of the function's pure
2048 code. CXT is an RTX for the static chain value for the function. */
2051 initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt)
2053 rtx t1 = copy_to_reg (fnaddr);
2054 rtx t2 = copy_to_reg (cxt);
2060 rtx a = memory_address (Pmode, plus_constant (tramp, 8));
2061 addr = memory_address (Pmode, tramp);
2062 emit_move_insn (gen_rtx_MEM (SImode, addr), a);
2066 addr = memory_address (Pmode, plus_constant (tramp, i + 2));
2067 emit_move_insn (gen_rtx_MEM (HImode, addr), gen_lowpart (HImode, t1));
2068 emit_insn (gen_ashrsi3 (t1, t1, GEN_INT (16)));
2069 addr = memory_address (Pmode, plus_constant (tramp, i + 6));
2070 emit_move_insn (gen_rtx_MEM (HImode, addr), gen_lowpart (HImode, t1));
2072 addr = memory_address (Pmode, plus_constant (tramp, i + 10));
2073 emit_move_insn (gen_rtx_MEM (HImode, addr), gen_lowpart (HImode, t2));
2074 emit_insn (gen_ashrsi3 (t2, t2, GEN_INT (16)));
2075 addr = memory_address (Pmode, plus_constant (tramp, i + 14));
2076 emit_move_insn (gen_rtx_MEM (HImode, addr), gen_lowpart (HImode, t2));
2079 /* Emit insns to move operands[1] into operands[0]. */
2082 emit_pic_move (rtx *operands, enum machine_mode mode ATTRIBUTE_UNUSED)
2084 rtx temp = reload_in_progress ? operands[0] : gen_reg_rtx (Pmode);
2086 gcc_assert (!TARGET_FDPIC || !(reload_in_progress || reload_completed));
2087 if (GET_CODE (operands[0]) == MEM && SYMBOLIC_CONST (operands[1]))
2088 operands[1] = force_reg (SImode, operands[1]);
2090 operands[1] = legitimize_pic_address (operands[1], temp,
2091 TARGET_FDPIC ? OUR_FDPIC_REG
2092 : pic_offset_table_rtx);
2095 /* Expand a move operation in mode MODE. The operands are in OPERANDS.
2096 Returns true if no further code must be generated, false if the caller
2097 should generate an insn to move OPERANDS[1] to OPERANDS[0]. */
2100 expand_move (rtx *operands, enum machine_mode mode)
2102 rtx op = operands[1];
2103 if ((TARGET_ID_SHARED_LIBRARY || TARGET_FDPIC)
2104 && SYMBOLIC_CONST (op))
2105 emit_pic_move (operands, mode);
2106 else if (mode == SImode && GET_CODE (op) == CONST
2107 && GET_CODE (XEXP (op, 0)) == PLUS
2108 && GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF
2109 && !bfin_legitimate_constant_p (op))
2111 rtx dest = operands[0];
2113 gcc_assert (!reload_in_progress && !reload_completed);
2115 op0 = force_reg (mode, XEXP (op, 0));
2117 if (!insn_data[CODE_FOR_addsi3].operand[2].predicate (op1, mode))
2118 op1 = force_reg (mode, op1);
2119 if (GET_CODE (dest) == MEM)
2120 dest = gen_reg_rtx (mode);
2121 emit_insn (gen_addsi3 (dest, op0, op1));
2122 if (dest == operands[0])
2126 /* Don't generate memory->memory or constant->memory moves, go through a
2128 else if ((reload_in_progress | reload_completed) == 0
2129 && GET_CODE (operands[0]) == MEM
2130 && GET_CODE (operands[1]) != REG)
2131 operands[1] = force_reg (mode, operands[1]);
2135 /* Split one or more DImode RTL references into pairs of SImode
2136 references. The RTL can be REG, offsettable MEM, integer constant, or
2137 CONST_DOUBLE. "operands" is a pointer to an array of DImode RTL to
2138 split and "num" is its length. lo_half and hi_half are output arrays
2139 that parallel "operands". */
2142 split_di (rtx operands[], int num, rtx lo_half[], rtx hi_half[])
2146 rtx op = operands[num];
2148 /* simplify_subreg refuse to split volatile memory addresses,
2149 but we still have to handle it. */
2150 if (GET_CODE (op) == MEM)
2152 lo_half[num] = adjust_address (op, SImode, 0);
2153 hi_half[num] = adjust_address (op, SImode, 4);
2157 lo_half[num] = simplify_gen_subreg (SImode, op,
2158 GET_MODE (op) == VOIDmode
2159 ? DImode : GET_MODE (op), 0);
2160 hi_half[num] = simplify_gen_subreg (SImode, op,
2161 GET_MODE (op) == VOIDmode
2162 ? DImode : GET_MODE (op), 4);
2168 bfin_longcall_p (rtx op, int call_cookie)
2170 gcc_assert (GET_CODE (op) == SYMBOL_REF);
2171 if (call_cookie & CALL_SHORT)
2173 if (call_cookie & CALL_LONG)
2175 if (TARGET_LONG_CALLS)
2180 /* Expand a call instruction. FNADDR is the call target, RETVAL the return value.
2181 COOKIE is a CONST_INT holding the call_cookie prepared init_cumulative_args.
2182 SIBCALL is nonzero if this is a sibling call. */
2185 bfin_expand_call (rtx retval, rtx fnaddr, rtx callarg1, rtx cookie, int sibcall)
2187 rtx use = NULL, call;
2188 rtx callee = XEXP (fnaddr, 0);
2189 int nelts = 2 + !!sibcall;
2191 rtx picreg = get_hard_reg_initial_val (SImode, FDPIC_REGNO);
2194 /* In an untyped call, we can get NULL for operand 2. */
2195 if (cookie == NULL_RTX)
2196 cookie = const0_rtx;
2198 /* Static functions and indirect calls don't need the pic register. */
2199 if (!TARGET_FDPIC && flag_pic
2200 && GET_CODE (callee) == SYMBOL_REF
2201 && !SYMBOL_REF_LOCAL_P (callee))
2202 use_reg (&use, pic_offset_table_rtx);
2206 int caller_has_l1_text, callee_has_l1_text;
2208 caller_has_l1_text = callee_has_l1_text = 0;
2210 if (lookup_attribute ("l1_text",
2211 DECL_ATTRIBUTES (cfun->decl)) != NULL_TREE)
2212 caller_has_l1_text = 1;
2214 if (GET_CODE (callee) == SYMBOL_REF
2215 && SYMBOL_REF_DECL (callee) && DECL_P (SYMBOL_REF_DECL (callee))
2218 DECL_ATTRIBUTES (SYMBOL_REF_DECL (callee))) != NULL_TREE)
2219 callee_has_l1_text = 1;
2221 if (GET_CODE (callee) != SYMBOL_REF
2222 || bfin_longcall_p (callee, INTVAL (cookie))
2223 || (GET_CODE (callee) == SYMBOL_REF
2224 && !SYMBOL_REF_LOCAL_P (callee)
2225 && TARGET_INLINE_PLT)
2226 || caller_has_l1_text != callee_has_l1_text
2227 || (caller_has_l1_text && callee_has_l1_text
2228 && (GET_CODE (callee) != SYMBOL_REF
2229 || !SYMBOL_REF_LOCAL_P (callee))))
2232 if (! address_operand (addr, Pmode))
2233 addr = force_reg (Pmode, addr);
2235 fnaddr = gen_reg_rtx (SImode);
2236 emit_insn (gen_load_funcdescsi (fnaddr, addr));
2237 fnaddr = gen_rtx_MEM (Pmode, fnaddr);
2239 picreg = gen_reg_rtx (SImode);
2240 emit_insn (gen_load_funcdescsi (picreg,
2241 plus_constant (addr, 4)));
2246 else if ((!register_no_elim_operand (callee, Pmode)
2247 && GET_CODE (callee) != SYMBOL_REF)
2248 || (GET_CODE (callee) == SYMBOL_REF
2249 && ((TARGET_ID_SHARED_LIBRARY && !TARGET_LEAF_ID_SHARED_LIBRARY)
2250 || bfin_longcall_p (callee, INTVAL (cookie)))))
2252 callee = copy_to_mode_reg (Pmode, callee);
2253 fnaddr = gen_rtx_MEM (Pmode, callee);
2255 call = gen_rtx_CALL (VOIDmode, fnaddr, callarg1);
2258 call = gen_rtx_SET (VOIDmode, retval, call);
2260 pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (nelts));
2262 XVECEXP (pat, 0, n++) = call;
2264 XVECEXP (pat, 0, n++) = gen_rtx_USE (VOIDmode, picreg);
2265 XVECEXP (pat, 0, n++) = gen_rtx_USE (VOIDmode, cookie);
2267 XVECEXP (pat, 0, n++) = gen_rtx_RETURN (VOIDmode);
2268 call = emit_call_insn (pat);
2270 CALL_INSN_FUNCTION_USAGE (call) = use;
2273 /* Return 1 if hard register REGNO can hold a value of machine-mode MODE. */
2276 hard_regno_mode_ok (int regno, enum machine_mode mode)
2278 /* Allow only dregs to store value of mode HI or QI */
2279 enum reg_class rclass = REGNO_REG_CLASS (regno);
2284 if (mode == V2HImode)
2285 return D_REGNO_P (regno);
2286 if (rclass == CCREGS)
2287 return mode == BImode;
2288 if (mode == PDImode || mode == V2PDImode)
2289 return regno == REG_A0 || regno == REG_A1;
2291 /* Allow all normal 32-bit regs, except REG_M3, in case regclass ever comes
2292 up with a bad register class (such as ALL_REGS) for DImode. */
2294 return regno < REG_M3;
2297 && TEST_HARD_REG_BIT (reg_class_contents[PROLOGUE_REGS], regno))
2300 return TEST_HARD_REG_BIT (reg_class_contents[MOST_REGS], regno);
2303 /* Implements target hook vector_mode_supported_p. */
2306 bfin_vector_mode_supported_p (enum machine_mode mode)
2308 return mode == V2HImode;
2311 /* Return the cost of moving data from a register in class CLASS1 to
2312 one in class CLASS2. A cost of 2 is the default. */
2315 bfin_register_move_cost (enum machine_mode mode,
2316 enum reg_class class1, enum reg_class class2)
2318 /* These need secondary reloads, so they're more expensive. */
2319 if ((class1 == CCREGS && !reg_class_subset_p (class2, DREGS))
2320 || (class2 == CCREGS && !reg_class_subset_p (class1, DREGS)))
2323 /* If optimizing for size, always prefer reg-reg over reg-memory moves. */
2327 if (GET_MODE_CLASS (mode) == MODE_INT)
2329 /* Discourage trying to use the accumulators. */
2330 if (TEST_HARD_REG_BIT (reg_class_contents[class1], REG_A0)
2331 || TEST_HARD_REG_BIT (reg_class_contents[class1], REG_A1)
2332 || TEST_HARD_REG_BIT (reg_class_contents[class2], REG_A0)
2333 || TEST_HARD_REG_BIT (reg_class_contents[class2], REG_A1))
2339 /* Return the cost of moving data of mode M between a
2340 register and memory. A value of 2 is the default; this cost is
2341 relative to those in `REGISTER_MOVE_COST'.
2343 ??? In theory L1 memory has single-cycle latency. We should add a switch
2344 that tells the compiler whether we expect to use only L1 memory for the
2345 program; it'll make the costs more accurate. */
2348 bfin_memory_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
2349 enum reg_class rclass,
2350 int in ATTRIBUTE_UNUSED)
2352 /* Make memory accesses slightly more expensive than any register-register
2353 move. Also, penalize non-DP registers, since they need secondary
2354 reloads to load and store. */
2355 if (! reg_class_subset_p (rclass, DPREGS))
2361 /* Inform reload about cases where moving X with a mode MODE to a register in
2362 RCLASS requires an extra scratch register. Return the class needed for the
2363 scratch register. */
2365 static enum reg_class
2366 bfin_secondary_reload (bool in_p, rtx x, enum reg_class rclass,
2367 enum machine_mode mode, secondary_reload_info *sri)
2369 /* If we have HImode or QImode, we can only use DREGS as secondary registers;
2370 in most other cases we can also use PREGS. */
2371 enum reg_class default_class = GET_MODE_SIZE (mode) >= 4 ? DPREGS : DREGS;
2372 enum reg_class x_class = NO_REGS;
2373 enum rtx_code code = GET_CODE (x);
2376 x = SUBREG_REG (x), code = GET_CODE (x);
2379 int regno = REGNO (x);
2380 if (regno >= FIRST_PSEUDO_REGISTER)
2381 regno = reg_renumber[regno];
2386 x_class = REGNO_REG_CLASS (regno);
2389 /* We can be asked to reload (plus (FP) (large_constant)) into a DREG.
2390 This happens as a side effect of register elimination, and we need
2391 a scratch register to do it. */
2392 if (fp_plus_const_operand (x, mode))
2394 rtx op2 = XEXP (x, 1);
2395 int large_constant_p = ! satisfies_constraint_Ks7 (op2);
2397 if (rclass == PREGS || rclass == PREGS_CLOBBERED)
2399 /* If destination is a DREG, we can do this without a scratch register
2400 if the constant is valid for an add instruction. */
2401 if ((rclass == DREGS || rclass == DPREGS)
2402 && ! large_constant_p)
2404 /* Reloading to anything other than a DREG? Use a PREG scratch
2406 sri->icode = CODE_FOR_reload_insi;
2410 /* Data can usually be moved freely between registers of most classes.
2411 AREGS are an exception; they can only move to or from another register
2412 in AREGS or one in DREGS. They can also be assigned the constant 0. */
2413 if (x_class == AREGS || x_class == EVEN_AREGS || x_class == ODD_AREGS)
2414 return (rclass == DREGS || rclass == AREGS || rclass == EVEN_AREGS
2415 || rclass == ODD_AREGS
2418 if (rclass == AREGS || rclass == EVEN_AREGS || rclass == ODD_AREGS)
2422 sri->icode = in_p ? CODE_FOR_reload_inpdi : CODE_FOR_reload_outpdi;
2426 if (x != const0_rtx && x_class != DREGS)
2434 /* CCREGS can only be moved from/to DREGS. */
2435 if (rclass == CCREGS && x_class != DREGS)
2437 if (x_class == CCREGS && rclass != DREGS)
2440 /* All registers other than AREGS can load arbitrary constants. The only
2441 case that remains is MEM. */
2443 if (! reg_class_subset_p (rclass, default_class))
2444 return default_class;
2449 /* Implement TARGET_HANDLE_OPTION. */
2452 bfin_handle_option (size_t code, const char *arg, int value)
2456 case OPT_mshared_library_id_:
2457 if (value > MAX_LIBRARY_ID)
2458 error ("-mshared-library-id=%s is not between 0 and %d",
2459 arg, MAX_LIBRARY_ID);
2460 bfin_lib_id_given = 1;
2469 while ((p = bfin_cpus[i].name) != NULL)
2471 if (strncmp (arg, p, strlen (p)) == 0)
2478 error ("-mcpu=%s is not valid", arg);
2482 bfin_cpu_type = bfin_cpus[i].type;
2484 q = arg + strlen (p);
2488 bfin_si_revision = bfin_cpus[i].si_revision;
2489 bfin_workarounds |= bfin_cpus[i].workarounds;
2491 else if (strcmp (q, "-none") == 0)
2492 bfin_si_revision = -1;
2493 else if (strcmp (q, "-any") == 0)
2495 bfin_si_revision = 0xffff;
2496 while (bfin_cpus[i].type == bfin_cpu_type)
2498 bfin_workarounds |= bfin_cpus[i].workarounds;
2504 unsigned int si_major, si_minor;
2507 rev_len = strlen (q);
2509 if (sscanf (q, "-%u.%u%n", &si_major, &si_minor, &n) != 2
2511 || si_major > 0xff || si_minor > 0xff)
2513 invalid_silicon_revision:
2514 error ("-mcpu=%s has invalid silicon revision", arg);
2518 bfin_si_revision = (si_major << 8) | si_minor;
2520 while (bfin_cpus[i].type == bfin_cpu_type
2521 && bfin_cpus[i].si_revision != bfin_si_revision)
2524 if (bfin_cpus[i].type != bfin_cpu_type)
2525 goto invalid_silicon_revision;
2527 bfin_workarounds |= bfin_cpus[i].workarounds;
2538 static struct machine_function *
2539 bfin_init_machine_status (void)
2541 struct machine_function *f;
2543 f = GGC_CNEW (struct machine_function);
2548 /* Implement the macro OVERRIDE_OPTIONS. */
2551 override_options (void)
2553 /* If processor type is not specified, enable all workarounds. */
2554 if (bfin_cpu_type == BFIN_CPU_UNKNOWN)
2558 for (i = 0; bfin_cpus[i].name != NULL; i++)
2559 bfin_workarounds |= bfin_cpus[i].workarounds;
2561 bfin_si_revision = 0xffff;
2564 if (bfin_csync_anomaly == 1)
2565 bfin_workarounds |= WA_SPECULATIVE_SYNCS;
2566 else if (bfin_csync_anomaly == 0)
2567 bfin_workarounds &= ~WA_SPECULATIVE_SYNCS;
2569 if (bfin_specld_anomaly == 1)
2570 bfin_workarounds |= WA_SPECULATIVE_LOADS;
2571 else if (bfin_specld_anomaly == 0)
2572 bfin_workarounds &= ~WA_SPECULATIVE_LOADS;
2574 if (TARGET_OMIT_LEAF_FRAME_POINTER)
2575 flag_omit_frame_pointer = 1;
2577 /* Library identification */
2578 if (bfin_lib_id_given && ! TARGET_ID_SHARED_LIBRARY)
2579 error ("-mshared-library-id= specified without -mid-shared-library");
2581 if (stack_limit_rtx && TARGET_STACK_CHECK_L1)
2582 error ("Can't use multiple stack checking methods together.");
2584 if (TARGET_ID_SHARED_LIBRARY && TARGET_FDPIC)
2585 error ("ID shared libraries and FD-PIC mode can't be used together.");
2587 /* Don't allow the user to specify -mid-shared-library and -msep-data
2588 together, as it makes little sense from a user's point of view... */
2589 if (TARGET_SEP_DATA && TARGET_ID_SHARED_LIBRARY)
2590 error ("cannot specify both -msep-data and -mid-shared-library");
2591 /* ... internally, however, it's nearly the same. */
2592 if (TARGET_SEP_DATA)
2593 target_flags |= MASK_ID_SHARED_LIBRARY | MASK_LEAF_ID_SHARED_LIBRARY;
2595 if (TARGET_ID_SHARED_LIBRARY && flag_pic == 0)
2598 /* There is no single unaligned SI op for PIC code. Sometimes we
2599 need to use ".4byte" and sometimes we need to use ".picptr".
2600 See bfin_assemble_integer for details. */
2602 targetm.asm_out.unaligned_op.si = 0;
2604 /* Silently turn off flag_pic if not doing FDPIC or ID shared libraries,
2605 since we don't support it and it'll just break. */
2606 if (flag_pic && !TARGET_FDPIC && !TARGET_ID_SHARED_LIBRARY)
2609 if (TARGET_MULTICORE && bfin_cpu_type != BFIN_CPU_BF561)
2610 error ("-mmulticore can only be used with BF561");
2612 if (TARGET_COREA && !TARGET_MULTICORE)
2613 error ("-mcorea should be used with -mmulticore");
2615 if (TARGET_COREB && !TARGET_MULTICORE)
2616 error ("-mcoreb should be used with -mmulticore");
2618 if (TARGET_COREA && TARGET_COREB)
2619 error ("-mcorea and -mcoreb can't be used together");
2621 flag_schedule_insns = 0;
2623 /* Passes after sched2 can break the helpful TImode annotations that
2624 haifa-sched puts on every insn. Just do scheduling in reorg. */
2625 bfin_flag_schedule_insns2 = flag_schedule_insns_after_reload;
2626 flag_schedule_insns_after_reload = 0;
2628 init_machine_status = bfin_init_machine_status;
2631 /* Return the destination address of BRANCH.
2632 We need to use this instead of get_attr_length, because the
2633 cbranch_with_nops pattern conservatively sets its length to 6, and
2634 we still prefer to use shorter sequences. */
2637 branch_dest (rtx branch)
2641 rtx pat = PATTERN (branch);
2642 if (GET_CODE (pat) == PARALLEL)
2643 pat = XVECEXP (pat, 0, 0);
2644 dest = SET_SRC (pat);
2645 if (GET_CODE (dest) == IF_THEN_ELSE)
2646 dest = XEXP (dest, 1);
2647 dest = XEXP (dest, 0);
2648 dest_uid = INSN_UID (dest);
2649 return INSN_ADDRESSES (dest_uid);
2652 /* Return nonzero if INSN is annotated with a REG_BR_PROB note that indicates
2653 it's a branch that's predicted taken. */
2656 cbranch_predicted_taken_p (rtx insn)
2658 rtx x = find_reg_note (insn, REG_BR_PROB, 0);
2662 int pred_val = INTVAL (XEXP (x, 0));
2664 return pred_val >= REG_BR_PROB_BASE / 2;
2670 /* Templates for use by asm_conditional_branch. */
2672 static const char *ccbranch_templates[][3] = {
2673 { "if !cc jump %3;", "if cc jump 4 (bp); jump.s %3;", "if cc jump 6 (bp); jump.l %3;" },
2674 { "if cc jump %3;", "if !cc jump 4 (bp); jump.s %3;", "if !cc jump 6 (bp); jump.l %3;" },
2675 { "if !cc jump %3 (bp);", "if cc jump 4; jump.s %3;", "if cc jump 6; jump.l %3;" },
2676 { "if cc jump %3 (bp);", "if !cc jump 4; jump.s %3;", "if !cc jump 6; jump.l %3;" },
2679 /* Output INSN, which is a conditional branch instruction with operands
2682 We deal with the various forms of conditional branches that can be generated
2683 by bfin_reorg to prevent the hardware from doing speculative loads, by
2684 - emitting a sufficient number of nops, if N_NOPS is nonzero, or
2685 - always emitting the branch as predicted taken, if PREDICT_TAKEN is true.
2686 Either of these is only necessary if the branch is short, otherwise the
2687 template we use ends in an unconditional jump which flushes the pipeline
2691 asm_conditional_branch (rtx insn, rtx *operands, int n_nops, int predict_taken)
2693 int offset = branch_dest (insn) - INSN_ADDRESSES (INSN_UID (insn));
2694 /* Note : offset for instructions like if cc jmp; jump.[sl] offset
2695 is to be taken from start of if cc rather than jump.
2696 Range for jump.s is (-4094, 4096) instead of (-4096, 4094)
2698 int len = (offset >= -1024 && offset <= 1022 ? 0
2699 : offset >= -4094 && offset <= 4096 ? 1
2701 int bp = predict_taken && len == 0 ? 1 : cbranch_predicted_taken_p (insn);
2702 int idx = (bp << 1) | (GET_CODE (operands[0]) == EQ ? BRF : BRT);
2703 output_asm_insn (ccbranch_templates[idx][len], operands);
2704 gcc_assert (n_nops == 0 || !bp);
2706 while (n_nops-- > 0)
2707 output_asm_insn ("nop;", NULL);
2710 /* Emit rtl for a comparison operation CMP in mode MODE. Operands have been
2711 stored in bfin_compare_op0 and bfin_compare_op1 already. */
2714 bfin_gen_compare (rtx cmp, enum machine_mode mode ATTRIBUTE_UNUSED)
2716 enum rtx_code code1, code2;
2717 rtx op0 = bfin_compare_op0, op1 = bfin_compare_op1;
2718 rtx tem = bfin_cc_rtx;
2719 enum rtx_code code = GET_CODE (cmp);
2721 /* If we have a BImode input, then we already have a compare result, and
2722 do not need to emit another comparison. */
2723 if (GET_MODE (op0) == BImode)
2725 gcc_assert ((code == NE || code == EQ) && op1 == const0_rtx);
2726 tem = op0, code2 = code;
2731 /* bfin has these conditions */
2741 code1 = reverse_condition (code);
2745 emit_insn (gen_rtx_SET (BImode, tem,
2746 gen_rtx_fmt_ee (code1, BImode, op0, op1)));
2749 return gen_rtx_fmt_ee (code2, BImode, tem, CONST0_RTX (BImode));
2752 /* Return nonzero iff C has exactly one bit set if it is interpreted
2753 as a 32-bit constant. */
2756 log2constp (unsigned HOST_WIDE_INT c)
2759 return c != 0 && (c & (c-1)) == 0;
2762 /* Returns the number of consecutive least significant zeros in the binary
2763 representation of *V.
2764 We modify *V to contain the original value arithmetically shifted right by
2765 the number of zeroes. */
2768 shiftr_zero (HOST_WIDE_INT *v)
2770 unsigned HOST_WIDE_INT tmp = *v;
2771 unsigned HOST_WIDE_INT sgn;
2777 sgn = tmp & ((unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1));
2778 while ((tmp & 0x1) == 0 && n <= 32)
2780 tmp = (tmp >> 1) | sgn;
2787 /* After reload, split the load of an immediate constant. OPERANDS are the
2788 operands of the movsi_insn pattern which we are splitting. We return
2789 nonzero if we emitted a sequence to load the constant, zero if we emitted
2790 nothing because we want to use the splitter's default sequence. */
2793 split_load_immediate (rtx operands[])
2795 HOST_WIDE_INT val = INTVAL (operands[1]);
2797 HOST_WIDE_INT shifted = val;
2798 HOST_WIDE_INT shifted_compl = ~val;
2799 int num_zero = shiftr_zero (&shifted);
2800 int num_compl_zero = shiftr_zero (&shifted_compl);
2801 unsigned int regno = REGNO (operands[0]);
2803 /* This case takes care of single-bit set/clear constants, which we could
2804 also implement with BITSET/BITCLR. */
2806 && shifted >= -32768 && shifted < 65536
2807 && (D_REGNO_P (regno)
2808 || (regno >= REG_P0 && regno <= REG_P7 && num_zero <= 2)))
2810 emit_insn (gen_movsi (operands[0], GEN_INT (shifted)));
2811 emit_insn (gen_ashlsi3 (operands[0], operands[0], GEN_INT (num_zero)));
2816 tmp |= -(tmp & 0x8000);
2818 /* If high word has one bit set or clear, try to use a bit operation. */
2819 if (D_REGNO_P (regno))
2821 if (log2constp (val & 0xFFFF0000))
2823 emit_insn (gen_movsi (operands[0], GEN_INT (val & 0xFFFF)));
2824 emit_insn (gen_iorsi3 (operands[0], operands[0], GEN_INT (val & 0xFFFF0000)));
2827 else if (log2constp (val | 0xFFFF) && (val & 0x8000) != 0)
2829 emit_insn (gen_movsi (operands[0], GEN_INT (tmp)));
2830 emit_insn (gen_andsi3 (operands[0], operands[0], GEN_INT (val | 0xFFFF)));
2834 if (D_REGNO_P (regno))
2836 if (tmp >= -64 && tmp <= 63)
2838 emit_insn (gen_movsi (operands[0], GEN_INT (tmp)));
2839 emit_insn (gen_movstricthi_high (operands[0], GEN_INT (val & -65536)));
2843 if ((val & 0xFFFF0000) == 0)
2845 emit_insn (gen_movsi (operands[0], const0_rtx));
2846 emit_insn (gen_movsi_low (operands[0], operands[0], operands[1]));
2850 if ((val & 0xFFFF0000) == 0xFFFF0000)
2852 emit_insn (gen_movsi (operands[0], constm1_rtx));
2853 emit_insn (gen_movsi_low (operands[0], operands[0], operands[1]));
2858 /* Need DREGs for the remaining case. */
2863 && num_compl_zero && shifted_compl >= -64 && shifted_compl <= 63)
2865 /* If optimizing for size, generate a sequence that has more instructions
2867 emit_insn (gen_movsi (operands[0], GEN_INT (shifted_compl)));
2868 emit_insn (gen_ashlsi3 (operands[0], operands[0],
2869 GEN_INT (num_compl_zero)));
2870 emit_insn (gen_one_cmplsi2 (operands[0], operands[0]));
2876 /* Return true if the legitimate memory address for a memory operand of mode
2877 MODE. Return false if not. */
2880 bfin_valid_add (enum machine_mode mode, HOST_WIDE_INT value)
2882 unsigned HOST_WIDE_INT v = value > 0 ? value : -value;
2883 int sz = GET_MODE_SIZE (mode);
2884 int shift = sz == 1 ? 0 : sz == 2 ? 1 : 2;
2885 /* The usual offsettable_memref machinery doesn't work so well for this
2886 port, so we deal with the problem here. */
2887 if (value > 0 && sz == 8)
2889 return (v & ~(0x7fff << shift)) == 0;
2893 bfin_valid_reg_p (unsigned int regno, int strict, enum machine_mode mode,
2894 enum rtx_code outer_code)
2897 return REGNO_OK_FOR_BASE_STRICT_P (regno, mode, outer_code, SCRATCH);
2899 return REGNO_OK_FOR_BASE_NONSTRICT_P (regno, mode, outer_code, SCRATCH);
2903 bfin_legitimate_address_p (enum machine_mode mode, rtx x, int strict)
2905 switch (GET_CODE (x)) {
2907 if (bfin_valid_reg_p (REGNO (x), strict, mode, MEM))
2911 if (REG_P (XEXP (x, 0))
2912 && bfin_valid_reg_p (REGNO (XEXP (x, 0)), strict, mode, PLUS)
2913 && ((GET_CODE (XEXP (x, 1)) == UNSPEC && mode == SImode)
2914 || (GET_CODE (XEXP (x, 1)) == CONST_INT
2915 && bfin_valid_add (mode, INTVAL (XEXP (x, 1))))))
2920 if (LEGITIMATE_MODE_FOR_AUTOINC_P (mode)
2921 && REG_P (XEXP (x, 0))
2922 && bfin_valid_reg_p (REGNO (XEXP (x, 0)), strict, mode, POST_INC))
2925 if (LEGITIMATE_MODE_FOR_AUTOINC_P (mode)
2926 && XEXP (x, 0) == stack_pointer_rtx
2927 && REG_P (XEXP (x, 0))
2928 && bfin_valid_reg_p (REGNO (XEXP (x, 0)), strict, mode, PRE_DEC))
2937 /* Decide whether we can force certain constants to memory. If we
2938 decide we can't, the caller should be able to cope with it in
2942 bfin_cannot_force_const_mem (rtx x ATTRIBUTE_UNUSED)
2944 /* We have only one class of non-legitimate constants, and our movsi
2945 expander knows how to handle them. Dropping these constants into the
2946 data section would only shift the problem - we'd still get relocs
2947 outside the object, in the data section rather than the text section. */
2951 /* Ensure that for any constant of the form symbol + offset, the offset
2952 remains within the object. Any other constants are ok.
2953 This ensures that flat binaries never have to deal with relocations
2954 crossing section boundaries. */
2957 bfin_legitimate_constant_p (rtx x)
2960 HOST_WIDE_INT offset;
2962 if (GET_CODE (x) != CONST)
2966 gcc_assert (GET_CODE (x) == PLUS);
2970 if (GET_CODE (sym) != SYMBOL_REF
2971 || GET_CODE (x) != CONST_INT)
2973 offset = INTVAL (x);
2975 if (SYMBOL_REF_DECL (sym) == 0)
2978 || offset >= int_size_in_bytes (TREE_TYPE (SYMBOL_REF_DECL (sym))))
2985 bfin_rtx_costs (rtx x, int code, int outer_code, int *total, bool speed)
2987 int cost2 = COSTS_N_INSNS (1);
2993 if (outer_code == SET || outer_code == PLUS)
2994 *total = satisfies_constraint_Ks7 (x) ? 0 : cost2;
2995 else if (outer_code == AND)
2996 *total = log2constp (~INTVAL (x)) ? 0 : cost2;
2997 else if (outer_code == LE || outer_code == LT || outer_code == EQ)
2998 *total = (INTVAL (x) >= -4 && INTVAL (x) <= 3) ? 0 : cost2;
2999 else if (outer_code == LEU || outer_code == LTU)
3000 *total = (INTVAL (x) >= 0 && INTVAL (x) <= 7) ? 0 : cost2;
3001 else if (outer_code == MULT)
3002 *total = (INTVAL (x) == 2 || INTVAL (x) == 4) ? 0 : cost2;
3003 else if (outer_code == ASHIFT && (INTVAL (x) == 1 || INTVAL (x) == 2))
3005 else if (outer_code == ASHIFT || outer_code == ASHIFTRT
3006 || outer_code == LSHIFTRT)
3007 *total = (INTVAL (x) >= 0 && INTVAL (x) <= 31) ? 0 : cost2;
3008 else if (outer_code == IOR || outer_code == XOR)
3009 *total = (INTVAL (x) & (INTVAL (x) - 1)) == 0 ? 0 : cost2;
3018 *total = COSTS_N_INSNS (2);
3024 if (GET_MODE (x) == SImode)
3026 if (GET_CODE (op0) == MULT
3027 && GET_CODE (XEXP (op0, 1)) == CONST_INT)
3029 HOST_WIDE_INT val = INTVAL (XEXP (op0, 1));
3030 if (val == 2 || val == 4)
3033 *total += rtx_cost (XEXP (op0, 0), outer_code, speed);
3034 *total += rtx_cost (op1, outer_code, speed);
3039 if (GET_CODE (op0) != REG
3040 && (GET_CODE (op0) != SUBREG || GET_CODE (SUBREG_REG (op0)) != REG))
3041 *total += rtx_cost (op0, SET, speed);
3042 #if 0 /* We'd like to do this for accuracy, but it biases the loop optimizer
3043 towards creating too many induction variables. */
3044 if (!reg_or_7bit_operand (op1, SImode))
3045 *total += rtx_cost (op1, SET, speed);
3048 else if (GET_MODE (x) == DImode)
3051 if (GET_CODE (op1) != CONST_INT
3052 || !satisfies_constraint_Ks7 (op1))
3053 *total += rtx_cost (op1, PLUS, speed);
3054 if (GET_CODE (op0) != REG
3055 && (GET_CODE (op0) != SUBREG || GET_CODE (SUBREG_REG (op0)) != REG))
3056 *total += rtx_cost (op0, PLUS, speed);
3061 if (GET_MODE (x) == DImode)
3070 if (GET_MODE (x) == DImode)
3077 if (GET_CODE (op0) != REG
3078 && (GET_CODE (op0) != SUBREG || GET_CODE (SUBREG_REG (op0)) != REG))
3079 *total += rtx_cost (op0, code, speed);
3089 /* Handle special cases of IOR: rotates, ALIGN insns, movstricthi_high. */
3092 if ((GET_CODE (op0) == LSHIFTRT && GET_CODE (op1) == ASHIFT)
3093 || (GET_CODE (op0) == ASHIFT && GET_CODE (op1) == ZERO_EXTEND)
3094 || (GET_CODE (op0) == ASHIFT && GET_CODE (op1) == LSHIFTRT)
3095 || (GET_CODE (op0) == AND && GET_CODE (op1) == CONST_INT))
3102 if (GET_CODE (op0) != REG
3103 && (GET_CODE (op0) != SUBREG || GET_CODE (SUBREG_REG (op0)) != REG))
3104 *total += rtx_cost (op0, code, speed);
3106 if (GET_MODE (x) == DImode)
3112 if (GET_MODE (x) != SImode)
3117 if (! rhs_andsi3_operand (XEXP (x, 1), SImode))
3118 *total += rtx_cost (XEXP (x, 1), code, speed);
3122 if (! regorlog2_operand (XEXP (x, 1), SImode))
3123 *total += rtx_cost (XEXP (x, 1), code, speed);
3130 if (outer_code == SET
3131 && XEXP (x, 1) == const1_rtx
3132 && GET_CODE (XEXP (x, 2)) == CONST_INT)
3148 if (GET_CODE (op0) == GET_CODE (op1)
3149 && (GET_CODE (op0) == ZERO_EXTEND
3150 || GET_CODE (op0) == SIGN_EXTEND))
3152 *total = COSTS_N_INSNS (1);
3153 op0 = XEXP (op0, 0);
3154 op1 = XEXP (op1, 0);
3157 *total = COSTS_N_INSNS (1);
3159 *total = COSTS_N_INSNS (3);
3161 if (GET_CODE (op0) != REG
3162 && (GET_CODE (op0) != SUBREG || GET_CODE (SUBREG_REG (op0)) != REG))
3163 *total += rtx_cost (op0, MULT, speed);
3164 if (GET_CODE (op1) != REG
3165 && (GET_CODE (op1) != SUBREG || GET_CODE (SUBREG_REG (op1)) != REG))
3166 *total += rtx_cost (op1, MULT, speed);
3172 *total = COSTS_N_INSNS (32);
3177 if (outer_code == SET)
3186 /* Used for communication between {push,pop}_multiple_operation (which
3187 we use not only as a predicate) and the corresponding output functions. */
3188 static int first_preg_to_save, first_dreg_to_save;
3189 static int n_regs_to_save;
3192 push_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
3194 int lastdreg = 8, lastpreg = 6;
3197 first_preg_to_save = lastpreg;
3198 first_dreg_to_save = lastdreg;
3199 for (i = 1, group = 0; i < XVECLEN (op, 0) - 1; i++)
3201 rtx t = XVECEXP (op, 0, i);
3205 if (GET_CODE (t) != SET)
3209 dest = SET_DEST (t);
3210 if (GET_CODE (dest) != MEM || ! REG_P (src))
3212 dest = XEXP (dest, 0);
3213 if (GET_CODE (dest) != PLUS
3214 || ! REG_P (XEXP (dest, 0))
3215 || REGNO (XEXP (dest, 0)) != REG_SP
3216 || GET_CODE (XEXP (dest, 1)) != CONST_INT
3217 || INTVAL (XEXP (dest, 1)) != -i * 4)
3220 regno = REGNO (src);
3223 if (D_REGNO_P (regno))
3226 first_dreg_to_save = lastdreg = regno - REG_R0;
3228 else if (regno >= REG_P0 && regno <= REG_P7)
3231 first_preg_to_save = lastpreg = regno - REG_P0;
3241 if (regno >= REG_P0 && regno <= REG_P7)
3244 first_preg_to_save = lastpreg = regno - REG_P0;
3246 else if (regno != REG_R0 + lastdreg + 1)
3251 else if (group == 2)
3253 if (regno != REG_P0 + lastpreg + 1)
3258 n_regs_to_save = 8 - first_dreg_to_save + 6 - first_preg_to_save;
3263 pop_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
3265 int lastdreg = 8, lastpreg = 6;
3268 for (i = 1, group = 0; i < XVECLEN (op, 0); i++)
3270 rtx t = XVECEXP (op, 0, i);
3274 if (GET_CODE (t) != SET)
3278 dest = SET_DEST (t);
3279 if (GET_CODE (src) != MEM || ! REG_P (dest))
3281 src = XEXP (src, 0);
3285 if (! REG_P (src) || REGNO (src) != REG_SP)
3288 else if (GET_CODE (src) != PLUS
3289 || ! REG_P (XEXP (src, 0))
3290 || REGNO (XEXP (src, 0)) != REG_SP
3291 || GET_CODE (XEXP (src, 1)) != CONST_INT
3292 || INTVAL (XEXP (src, 1)) != (i - 1) * 4)
3295 regno = REGNO (dest);
3298 if (regno == REG_R7)
3303 else if (regno != REG_P0 + lastpreg - 1)
3308 else if (group == 1)
3310 if (regno != REG_R0 + lastdreg - 1)
3316 first_dreg_to_save = lastdreg;
3317 first_preg_to_save = lastpreg;
3318 n_regs_to_save = 8 - first_dreg_to_save + 6 - first_preg_to_save;
3322 /* Emit assembly code for one multi-register push described by INSN, with
3323 operands in OPERANDS. */
3326 output_push_multiple (rtx insn, rtx *operands)
3331 /* Validate the insn again, and compute first_[dp]reg_to_save. */
3332 ok = push_multiple_operation (PATTERN (insn), VOIDmode);
3335 if (first_dreg_to_save == 8)
3336 sprintf (buf, "[--sp] = ( p5:%d );\n", first_preg_to_save);
3337 else if (first_preg_to_save == 6)
3338 sprintf (buf, "[--sp] = ( r7:%d );\n", first_dreg_to_save);
3340 sprintf (buf, "[--sp] = ( r7:%d, p5:%d );\n",
3341 first_dreg_to_save, first_preg_to_save);
3343 output_asm_insn (buf, operands);
3346 /* Emit assembly code for one multi-register pop described by INSN, with
3347 operands in OPERANDS. */
3350 output_pop_multiple (rtx insn, rtx *operands)
3355 /* Validate the insn again, and compute first_[dp]reg_to_save. */
3356 ok = pop_multiple_operation (PATTERN (insn), VOIDmode);
3359 if (first_dreg_to_save == 8)
3360 sprintf (buf, "( p5:%d ) = [sp++];\n", first_preg_to_save);
3361 else if (first_preg_to_save == 6)
3362 sprintf (buf, "( r7:%d ) = [sp++];\n", first_dreg_to_save);
3364 sprintf (buf, "( r7:%d, p5:%d ) = [sp++];\n",
3365 first_dreg_to_save, first_preg_to_save);
3367 output_asm_insn (buf, operands);
3370 /* Adjust DST and SRC by OFFSET bytes, and generate one move in mode MODE. */
3373 single_move_for_movmem (rtx dst, rtx src, enum machine_mode mode, HOST_WIDE_INT offset)
3375 rtx scratch = gen_reg_rtx (mode);
3378 srcmem = adjust_address_nv (src, mode, offset);
3379 dstmem = adjust_address_nv (dst, mode, offset);
3380 emit_move_insn (scratch, srcmem);
3381 emit_move_insn (dstmem, scratch);
3384 /* Expand a string move operation of COUNT_EXP bytes from SRC to DST, with
3385 alignment ALIGN_EXP. Return true if successful, false if we should fall
3386 back on a different method. */
3389 bfin_expand_movmem (rtx dst, rtx src, rtx count_exp, rtx align_exp)
3391 rtx srcreg, destreg, countreg;
3392 HOST_WIDE_INT align = 0;
3393 unsigned HOST_WIDE_INT count = 0;
3395 if (GET_CODE (align_exp) == CONST_INT)
3396 align = INTVAL (align_exp);
3397 if (GET_CODE (count_exp) == CONST_INT)
3399 count = INTVAL (count_exp);
3401 if (!TARGET_INLINE_ALL_STRINGOPS && count > 64)
3406 /* If optimizing for size, only do single copies inline. */
3409 if (count == 2 && align < 2)
3411 if (count == 4 && align < 4)
3413 if (count != 1 && count != 2 && count != 4)
3416 if (align < 2 && count != 1)
3419 destreg = copy_to_mode_reg (Pmode, XEXP (dst, 0));
3420 if (destreg != XEXP (dst, 0))
3421 dst = replace_equiv_address_nv (dst, destreg);
3422 srcreg = copy_to_mode_reg (Pmode, XEXP (src, 0));
3423 if (srcreg != XEXP (src, 0))
3424 src = replace_equiv_address_nv (src, srcreg);
3426 if (count != 0 && align >= 2)
3428 unsigned HOST_WIDE_INT offset = 0;
3432 if ((count & ~3) == 4)
3434 single_move_for_movmem (dst, src, SImode, offset);
3437 else if (count & ~3)
3439 HOST_WIDE_INT new_count = ((count >> 2) & 0x3fffffff) - 1;
3440 countreg = copy_to_mode_reg (Pmode, GEN_INT (new_count));
3442 emit_insn (gen_rep_movsi (destreg, srcreg, countreg, destreg, srcreg));
3443 cfun->machine->has_loopreg_clobber = true;
3447 single_move_for_movmem (dst, src, HImode, offset);
3453 if ((count & ~1) == 2)
3455 single_move_for_movmem (dst, src, HImode, offset);
3458 else if (count & ~1)
3460 HOST_WIDE_INT new_count = ((count >> 1) & 0x7fffffff) - 1;
3461 countreg = copy_to_mode_reg (Pmode, GEN_INT (new_count));
3463 emit_insn (gen_rep_movhi (destreg, srcreg, countreg, destreg, srcreg));
3464 cfun->machine->has_loopreg_clobber = true;
3469 single_move_for_movmem (dst, src, QImode, offset);
3476 /* Compute the alignment for a local variable.
3477 TYPE is the data type, and ALIGN is the alignment that
3478 the object would ordinarily have. The value of this macro is used
3479 instead of that alignment to align the object. */
3482 bfin_local_alignment (tree type, int align)
3484 /* Increasing alignment for (relatively) big types allows the builtin
3485 memcpy can use 32 bit loads/stores. */
3486 if (TYPE_SIZE (type)
3487 && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
3488 && (TREE_INT_CST_LOW (TYPE_SIZE (type)) > 8
3489 || TREE_INT_CST_HIGH (TYPE_SIZE (type))) && align < 32)
3494 /* Implement TARGET_SCHED_ISSUE_RATE. */
3497 bfin_issue_rate (void)
3503 bfin_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
3505 enum attr_type insn_type, dep_insn_type;
3506 int dep_insn_code_number;
3508 /* Anti and output dependencies have zero cost. */
3509 if (REG_NOTE_KIND (link) != 0)
3512 dep_insn_code_number = recog_memoized (dep_insn);
3514 /* If we can't recognize the insns, we can't really do anything. */
3515 if (dep_insn_code_number < 0 || recog_memoized (insn) < 0)
3518 insn_type = get_attr_type (insn);
3519 dep_insn_type = get_attr_type (dep_insn);
3521 if (dep_insn_type == TYPE_MOVE || dep_insn_type == TYPE_MCLD)
3523 rtx pat = PATTERN (dep_insn);
3524 if (GET_CODE (pat) == PARALLEL)
3525 pat = XVECEXP (pat, 0, 0);
3526 rtx dest = SET_DEST (pat);
3527 rtx src = SET_SRC (pat);
3528 if (! ADDRESS_REGNO_P (REGNO (dest))
3529 || ! (MEM_P (src) || D_REGNO_P (REGNO (src))))
3531 return cost + (dep_insn_type == TYPE_MOVE ? 4 : 3);
3537 /* This function acts like NEXT_INSN, but is aware of three-insn bundles and
3538 skips all subsequent parallel instructions if INSN is the start of such
3541 find_next_insn_start (rtx insn)
3543 if (GET_MODE (insn) == SImode)
3545 while (GET_MODE (insn) != QImode)
3546 insn = NEXT_INSN (insn);
3548 return NEXT_INSN (insn);
3551 /* This function acts like PREV_INSN, but is aware of three-insn bundles and
3552 skips all subsequent parallel instructions if INSN is the start of such
3555 find_prev_insn_start (rtx insn)
3557 insn = PREV_INSN (insn);
3558 gcc_assert (GET_MODE (insn) != SImode);
3559 if (GET_MODE (insn) == QImode)
3561 while (GET_MODE (PREV_INSN (insn)) == SImode)
3562 insn = PREV_INSN (insn);
3567 /* Increment the counter for the number of loop instructions in the
3568 current function. */
3571 bfin_hardware_loop (void)
3573 cfun->machine->has_hardware_loops++;
3576 /* Maximum loop nesting depth. */
3577 #define MAX_LOOP_DEPTH 2
3579 /* Maximum size of a loop. */
3580 #define MAX_LOOP_LENGTH 2042
3582 /* Maximum distance of the LSETUP instruction from the loop start. */
3583 #define MAX_LSETUP_DISTANCE 30
3585 /* We need to keep a vector of loops */
3586 typedef struct loop_info *loop_info;
3587 DEF_VEC_P (loop_info);
3588 DEF_VEC_ALLOC_P (loop_info,heap);
3590 /* Information about a loop we have found (or are in the process of
3592 struct GTY (()) loop_info
3594 /* loop number, for dumps */
3597 /* All edges that jump into and out of the loop. */
3598 VEC(edge,gc) *incoming;
3600 /* We can handle two cases: all incoming edges have the same destination
3601 block, or all incoming edges have the same source block. These two
3602 members are set to the common source or destination we found, or NULL
3603 if different blocks were found. If both are NULL the loop can't be
3605 basic_block incoming_src;
3606 basic_block incoming_dest;
3608 /* First block in the loop. This is the one branched to by the loop_end
3612 /* Last block in the loop (the one with the loop_end insn). */
3615 /* The successor block of the loop. This is the one the loop_end insn
3617 basic_block successor;
3619 /* The last instruction in the tail. */
3622 /* The loop_end insn. */
3625 /* The iteration register. */
3628 /* The new label placed at the beginning of the loop. */
3631 /* The new label placed at the end of the loop. */
3634 /* The length of the loop. */
3637 /* The nesting depth of the loop. */
3640 /* Nonzero if we can't optimize this loop. */
3643 /* True if we have visited this loop. */
3646 /* True if this loop body clobbers any of LC0, LT0, or LB0. */
3649 /* True if this loop body clobbers any of LC1, LT1, or LB1. */
3652 /* Next loop in the graph. */
3653 struct loop_info *next;
3655 /* Immediate outer loop of this loop. */
3656 struct loop_info *outer;
3658 /* Vector of blocks only within the loop, including those within
3660 VEC (basic_block,heap) *blocks;
3662 /* Same information in a bitmap. */
3663 bitmap block_bitmap;
3665 /* Vector of inner loops within this loop */
3666 VEC (loop_info,heap) *loops;
3670 bfin_dump_loops (loop_info loops)
3674 for (loop = loops; loop; loop = loop->next)
3680 fprintf (dump_file, ";; loop %d: ", loop->loop_no);
3682 fprintf (dump_file, "(bad) ");
3683 fprintf (dump_file, "{head:%d, depth:%d}", loop->head->index, loop->depth);
3685 fprintf (dump_file, " blocks: [ ");
3686 for (ix = 0; VEC_iterate (basic_block, loop->blocks, ix, b); ix++)
3687 fprintf (dump_file, "%d ", b->index);
3688 fprintf (dump_file, "] ");
3690 fprintf (dump_file, " inner loops: [ ");
3691 for (ix = 0; VEC_iterate (loop_info, loop->loops, ix, i); ix++)
3692 fprintf (dump_file, "%d ", i->loop_no);
3693 fprintf (dump_file, "]\n");
3695 fprintf (dump_file, "\n");
3698 /* Scan the blocks of LOOP (and its inferiors) looking for basic block
3699 BB. Return true, if we find it. */
3702 bfin_bb_in_loop (loop_info loop, basic_block bb)
3704 return bitmap_bit_p (loop->block_bitmap, bb->index);
3707 /* Scan the blocks of LOOP (and its inferiors) looking for uses of
3708 REG. Return true, if we find any. Don't count the loop's loop_end
3709 insn if it matches LOOP_END. */
3712 bfin_scan_loop (loop_info loop, rtx reg, rtx loop_end)
3717 for (ix = 0; VEC_iterate (basic_block, loop->blocks, ix, bb); ix++)
3721 for (insn = BB_HEAD (bb);
3722 insn != NEXT_INSN (BB_END (bb));
3723 insn = NEXT_INSN (insn))
3727 if (insn == loop_end)
3729 if (reg_mentioned_p (reg, PATTERN (insn)))
3736 /* Estimate the length of INSN conservatively. */
3739 length_for_loop (rtx insn)
3742 if (JUMP_P (insn) && any_condjump_p (insn) && !optimize_size)
3744 if (ENABLE_WA_SPECULATIVE_SYNCS)
3746 else if (ENABLE_WA_SPECULATIVE_LOADS)
3749 else if (LABEL_P (insn))
3751 if (ENABLE_WA_SPECULATIVE_SYNCS)
3756 length += get_attr_length (insn);
3761 /* Optimize LOOP. */
3764 bfin_optimize_loop (loop_info loop)
3768 rtx insn, last_insn;
3769 rtx loop_init, start_label, end_label;
3770 rtx reg_lc0, reg_lc1, reg_lt0, reg_lt1, reg_lb0, reg_lb1;
3771 rtx iter_reg, scratchreg, scratch_init, scratch_init_insn;
3772 rtx lc_reg, lt_reg, lb_reg;
3776 int inner_depth = 0;
3786 fprintf (dump_file, ";; loop %d bad when found\n", loop->loop_no);
3790 /* Every loop contains in its list of inner loops every loop nested inside
3791 it, even if there are intermediate loops. This works because we're doing
3792 a depth-first search here and never visit a loop more than once. */
3793 for (ix = 0; VEC_iterate (loop_info, loop->loops, ix, inner); ix++)
3795 bfin_optimize_loop (inner);
3797 if (!inner->bad && inner_depth < inner->depth)
3799 inner_depth = inner->depth;
3801 loop->clobber_loop0 |= inner->clobber_loop0;
3802 loop->clobber_loop1 |= inner->clobber_loop1;
3806 loop->depth = inner_depth + 1;
3807 if (loop->depth > MAX_LOOP_DEPTH)
3810 fprintf (dump_file, ";; loop %d too deep\n", loop->loop_no);
3814 /* Get the loop iteration register. */
3815 iter_reg = loop->iter_reg;
3817 if (!REG_P (iter_reg))
3820 fprintf (dump_file, ";; loop %d iteration count not in a register\n",
3824 scratchreg = NULL_RTX;
3825 scratch_init = iter_reg;
3826 scratch_init_insn = NULL_RTX;
3827 if (!PREG_P (iter_reg) && loop->incoming_src)
3829 basic_block bb_in = loop->incoming_src;
3831 for (i = REG_P0; i <= REG_P5; i++)
3832 if ((df_regs_ever_live_p (i)
3833 || (funkind (TREE_TYPE (current_function_decl)) == SUBROUTINE
3834 && call_used_regs[i]))
3835 && !REGNO_REG_SET_P (df_get_live_out (bb_in), i))
3837 scratchreg = gen_rtx_REG (SImode, i);
3840 for (insn = BB_END (bb_in); insn != BB_HEAD (bb_in);
3841 insn = PREV_INSN (insn))
3844 if (NOTE_P (insn) || BARRIER_P (insn))
3846 set = single_set (insn);
3847 if (set && rtx_equal_p (SET_DEST (set), iter_reg))
3849 if (CONSTANT_P (SET_SRC (set)))
3851 scratch_init = SET_SRC (set);
3852 scratch_init_insn = insn;
3856 else if (reg_mentioned_p (iter_reg, PATTERN (insn)))
3861 if (loop->incoming_src)
3863 /* Make sure the predecessor is before the loop start label, as required by
3864 the LSETUP instruction. */
3866 insn = BB_END (loop->incoming_src);
3867 /* If we have to insert the LSETUP before a jump, count that jump in the
3869 if (VEC_length (edge, loop->incoming) > 1
3870 || !(VEC_last (edge, loop->incoming)->flags & EDGE_FALLTHRU))
3872 gcc_assert (JUMP_P (insn));
3873 insn = PREV_INSN (insn);
3876 for (; insn && insn != loop->start_label; insn = NEXT_INSN (insn))
3877 length += length_for_loop (insn);
3882 fprintf (dump_file, ";; loop %d lsetup not before loop_start\n",
3887 /* Account for the pop of a scratch register where necessary. */
3888 if (!PREG_P (iter_reg) && scratchreg == NULL_RTX
3889 && ENABLE_WA_LOAD_LCREGS)
3892 if (length > MAX_LSETUP_DISTANCE)
3895 fprintf (dump_file, ";; loop %d lsetup too far away\n", loop->loop_no);
3900 /* Check if start_label appears before loop_end and calculate the
3901 offset between them. We calculate the length of instructions
3904 for (insn = loop->start_label;
3905 insn && insn != loop->loop_end;
3906 insn = NEXT_INSN (insn))
3907 length += length_for_loop (insn);
3912 fprintf (dump_file, ";; loop %d start_label not before loop_end\n",
3917 loop->length = length;
3918 if (loop->length > MAX_LOOP_LENGTH)
3921 fprintf (dump_file, ";; loop %d too long\n", loop->loop_no);
3925 /* Scan all the blocks to make sure they don't use iter_reg. */
3926 if (bfin_scan_loop (loop, iter_reg, loop->loop_end))
3929 fprintf (dump_file, ";; loop %d uses iterator\n", loop->loop_no);
3933 /* Scan all the insns to see if the loop body clobber
3934 any hardware loop registers. */
3936 reg_lc0 = gen_rtx_REG (SImode, REG_LC0);
3937 reg_lc1 = gen_rtx_REG (SImode, REG_LC1);
3938 reg_lt0 = gen_rtx_REG (SImode, REG_LT0);
3939 reg_lt1 = gen_rtx_REG (SImode, REG_LT1);
3940 reg_lb0 = gen_rtx_REG (SImode, REG_LB0);
3941 reg_lb1 = gen_rtx_REG (SImode, REG_LB1);
3943 for (ix = 0; VEC_iterate (basic_block, loop->blocks, ix, bb); ix++)
3947 for (insn = BB_HEAD (bb);
3948 insn != NEXT_INSN (BB_END (bb));
3949 insn = NEXT_INSN (insn))
3954 if (reg_set_p (reg_lc0, insn)
3955 || reg_set_p (reg_lt0, insn)
3956 || reg_set_p (reg_lb0, insn))
3957 loop->clobber_loop0 = 1;
3959 if (reg_set_p (reg_lc1, insn)
3960 || reg_set_p (reg_lt1, insn)
3961 || reg_set_p (reg_lb1, insn))
3962 loop->clobber_loop1 |= 1;
3966 if ((loop->clobber_loop0 && loop->clobber_loop1)
3967 || (loop->depth == MAX_LOOP_DEPTH && loop->clobber_loop0))
3969 loop->depth = MAX_LOOP_DEPTH + 1;
3971 fprintf (dump_file, ";; loop %d no loop reg available\n",
3976 /* There should be an instruction before the loop_end instruction
3977 in the same basic block. And the instruction must not be
3979 - CONDITIONAL BRANCH
3983 - Returns (RTS, RTN, etc.) */
3986 last_insn = find_prev_insn_start (loop->loop_end);
3990 for (; last_insn != BB_HEAD (bb);
3991 last_insn = find_prev_insn_start (last_insn))
3992 if (INSN_P (last_insn))
3995 if (last_insn != BB_HEAD (bb))
3998 if (single_pred_p (bb)
3999 && single_pred_edge (bb)->flags & EDGE_FALLTHRU
4000 && single_pred (bb) != ENTRY_BLOCK_PTR)
4002 bb = single_pred (bb);
4003 last_insn = BB_END (bb);
4008 last_insn = NULL_RTX;
4016 fprintf (dump_file, ";; loop %d has no last instruction\n",
4021 if (JUMP_P (last_insn) && !any_condjump_p (last_insn))
4024 fprintf (dump_file, ";; loop %d has bad last instruction\n",
4028 /* In all other cases, try to replace a bad last insn with a nop. */
4029 else if (JUMP_P (last_insn)
4030 || CALL_P (last_insn)
4031 || get_attr_type (last_insn) == TYPE_SYNC
4032 || get_attr_type (last_insn) == TYPE_CALL
4033 || get_attr_seq_insns (last_insn) == SEQ_INSNS_MULTI
4034 || recog_memoized (last_insn) == CODE_FOR_return_internal
4035 || GET_CODE (PATTERN (last_insn)) == ASM_INPUT
4036 || asm_noperands (PATTERN (last_insn)) >= 0)
4038 if (loop->length + 2 > MAX_LOOP_LENGTH)
4041 fprintf (dump_file, ";; loop %d too long\n", loop->loop_no);
4045 fprintf (dump_file, ";; loop %d has bad last insn; replace with nop\n",
4048 last_insn = emit_insn_after (gen_forced_nop (), last_insn);
4051 loop->last_insn = last_insn;
4053 /* The loop is good for replacement. */
4054 start_label = loop->start_label;
4055 end_label = gen_label_rtx ();
4056 iter_reg = loop->iter_reg;
4058 if (loop->depth == 1 && !loop->clobber_loop1)
4063 loop->clobber_loop1 = 1;
4070 loop->clobber_loop0 = 1;
4073 loop->end_label = end_label;
4075 /* Create a sequence containing the loop setup. */
4078 /* LSETUP only accepts P registers. If we have one, we can use it,
4079 otherwise there are several ways of working around the problem.
4080 If we're not affected by anomaly 312, we can load the LC register
4081 from any iteration register, and use LSETUP without initialization.
4082 If we've found a P scratch register that's not live here, we can
4083 instead copy the iter_reg into that and use an initializing LSETUP.
4084 If all else fails, push and pop P0 and use it as a scratch. */
4085 if (P_REGNO_P (REGNO (iter_reg)))
4087 loop_init = gen_lsetup_with_autoinit (lt_reg, start_label,
4090 seq_end = emit_insn (loop_init);
4092 else if (!ENABLE_WA_LOAD_LCREGS && DPREG_P (iter_reg))
4094 emit_insn (gen_movsi (lc_reg, iter_reg));
4095 loop_init = gen_lsetup_without_autoinit (lt_reg, start_label,
4098 seq_end = emit_insn (loop_init);
4100 else if (scratchreg != NULL_RTX)
4102 emit_insn (gen_movsi (scratchreg, scratch_init));
4103 loop_init = gen_lsetup_with_autoinit (lt_reg, start_label,
4105 lc_reg, scratchreg);
4106 seq_end = emit_insn (loop_init);
4107 if (scratch_init_insn != NULL_RTX)
4108 delete_insn (scratch_init_insn);
4112 rtx p0reg = gen_rtx_REG (SImode, REG_P0);
4113 rtx push = gen_frame_mem (SImode,
4114 gen_rtx_PRE_DEC (SImode, stack_pointer_rtx));
4115 rtx pop = gen_frame_mem (SImode,
4116 gen_rtx_POST_INC (SImode, stack_pointer_rtx));
4117 emit_insn (gen_movsi (push, p0reg));
4118 emit_insn (gen_movsi (p0reg, scratch_init));
4119 loop_init = gen_lsetup_with_autoinit (lt_reg, start_label,
4122 emit_insn (loop_init);
4123 seq_end = emit_insn (gen_movsi (p0reg, pop));
4124 if (scratch_init_insn != NULL_RTX)
4125 delete_insn (scratch_init_insn);
4130 fprintf (dump_file, ";; replacing loop %d initializer with\n",
4132 print_rtl_single (dump_file, loop_init);
4133 fprintf (dump_file, ";; replacing loop %d terminator with\n",
4135 print_rtl_single (dump_file, loop->loop_end);
4138 /* If the loop isn't entered at the top, also create a jump to the entry
4140 if (!loop->incoming_src && loop->head != loop->incoming_dest)
4142 rtx label = BB_HEAD (loop->incoming_dest);
4143 /* If we're jumping to the final basic block in the loop, and there's
4144 only one cheap instruction before the end (typically an increment of
4145 an induction variable), we can just emit a copy here instead of a
4147 if (loop->incoming_dest == loop->tail
4148 && next_real_insn (label) == last_insn
4149 && asm_noperands (last_insn) < 0
4150 && GET_CODE (PATTERN (last_insn)) == SET)
4152 seq_end = emit_insn (copy_rtx (PATTERN (last_insn)));
4155 seq_end = emit_jump_insn (gen_jump (label));
4161 if (loop->incoming_src)
4163 rtx prev = BB_END (loop->incoming_src);
4164 if (VEC_length (edge, loop->incoming) > 1
4165 || !(VEC_last (edge, loop->incoming)->flags & EDGE_FALLTHRU))
4167 gcc_assert (JUMP_P (prev));
4168 prev = PREV_INSN (prev);
4170 emit_insn_after (seq, prev);
4178 #ifdef ENABLE_CHECKING
4179 if (loop->head != loop->incoming_dest)
4181 /* We aren't entering the loop at the top. Since we've established
4182 that the loop is entered only at one point, this means there
4183 can't be fallthru edges into the head. Any such fallthru edges
4184 would become invalid when we insert the new block, so verify
4185 that this does not in fact happen. */
4186 FOR_EACH_EDGE (e, ei, loop->head->preds)
4187 gcc_assert (!(e->flags & EDGE_FALLTHRU));
4191 emit_insn_before (seq, BB_HEAD (loop->head));
4192 seq = emit_label_before (gen_label_rtx (), seq);
4194 new_bb = create_basic_block (seq, seq_end, loop->head->prev_bb);
4195 FOR_EACH_EDGE (e, ei, loop->incoming)
4197 if (!(e->flags & EDGE_FALLTHRU)
4198 || e->dest != loop->head)
4199 redirect_edge_and_branch_force (e, new_bb);
4201 redirect_edge_succ (e, new_bb);
4205 delete_insn (loop->loop_end);
4206 /* Insert the loop end label before the last instruction of the loop. */
4207 emit_label_before (loop->end_label, loop->last_insn);
4214 fprintf (dump_file, ";; loop %d is bad\n", loop->loop_no);
4218 if (DPREG_P (loop->iter_reg))
4220 /* If loop->iter_reg is a DREG or PREG, we can split it here
4221 without scratch register. */
4224 emit_insn_before (gen_addsi3 (loop->iter_reg,
4229 emit_insn_before (gen_cmpsi (loop->iter_reg, const0_rtx),
4232 insn = emit_jump_insn_before (gen_bne (loop->start_label),
4235 JUMP_LABEL (insn) = loop->start_label;
4236 LABEL_NUSES (loop->start_label)++;
4237 delete_insn (loop->loop_end);
4241 /* Called from bfin_reorg_loops when a potential loop end is found. LOOP is
4242 a newly set up structure describing the loop, it is this function's
4243 responsibility to fill most of it. TAIL_BB and TAIL_INSN point to the
4244 loop_end insn and its enclosing basic block. */
4247 bfin_discover_loop (loop_info loop, basic_block tail_bb, rtx tail_insn)
4251 VEC (basic_block,heap) *works = VEC_alloc (basic_block,heap,20);
4253 loop->tail = tail_bb;
4254 loop->head = BRANCH_EDGE (tail_bb)->dest;
4255 loop->successor = FALLTHRU_EDGE (tail_bb)->dest;
4256 loop->loop_end = tail_insn;
4257 loop->last_insn = NULL_RTX;
4258 loop->iter_reg = SET_DEST (XVECEXP (PATTERN (tail_insn), 0, 1));
4259 loop->depth = loop->length = 0;
4261 loop->clobber_loop0 = loop->clobber_loop1 = 0;
4264 loop->incoming = VEC_alloc (edge, gc, 2);
4265 loop->start_label = XEXP (XEXP (SET_SRC (XVECEXP (PATTERN (tail_insn), 0, 0)), 1), 0);
4266 loop->end_label = NULL_RTX;
4269 VEC_safe_push (basic_block, heap, works, loop->head);
4271 while (VEC_iterate (basic_block, works, dwork++, bb))
4275 if (bb == EXIT_BLOCK_PTR)
4277 /* We've reached the exit block. The loop must be bad. */
4280 ";; Loop is bad - reached exit block while scanning\n");
4285 if (bitmap_bit_p (loop->block_bitmap, bb->index))
4288 /* We've not seen this block before. Add it to the loop's
4289 list and then add each successor to the work list. */
4291 VEC_safe_push (basic_block, heap, loop->blocks, bb);
4292 bitmap_set_bit (loop->block_bitmap, bb->index);
4296 FOR_EACH_EDGE (e, ei, bb->succs)
4298 basic_block succ = EDGE_SUCC (bb, ei.index)->dest;
4299 if (!REGNO_REG_SET_P (df_get_live_in (succ),
4300 REGNO (loop->iter_reg)))
4302 if (!VEC_space (basic_block, works, 1))
4306 VEC_block_remove (basic_block, works, 0, dwork);
4310 VEC_reserve (basic_block, heap, works, 1);
4312 VEC_quick_push (basic_block, works, succ);
4317 /* Find the predecessor, and make sure nothing else jumps into this loop. */
4321 for (dwork = 0; VEC_iterate (basic_block, loop->blocks, dwork, bb); dwork++)
4325 FOR_EACH_EDGE (e, ei, bb->preds)
4327 basic_block pred = e->src;
4329 if (!bfin_bb_in_loop (loop, pred))
4332 fprintf (dump_file, ";; Loop %d: incoming edge %d -> %d\n",
4333 loop->loop_no, pred->index,
4335 VEC_safe_push (edge, gc, loop->incoming, e);
4340 for (pass = 0, retry = 1; retry && pass < 2; pass++)
4347 FOR_EACH_EDGE (e, ei, loop->incoming)
4351 loop->incoming_src = e->src;
4352 loop->incoming_dest = e->dest;
4357 if (e->dest != loop->incoming_dest)
4358 loop->incoming_dest = NULL;
4359 if (e->src != loop->incoming_src)
4360 loop->incoming_src = NULL;
4362 if (loop->incoming_src == NULL && loop->incoming_dest == NULL)
4368 ";; retrying loop %d with forwarder blocks\n",
4376 ";; can't find suitable entry for loop %d\n",
4384 FOR_EACH_EDGE (e, ei, loop->incoming)
4386 if (forwarder_block_p (e->src))
4393 ";; Adding forwarder block %d to loop %d and retrying\n",
4394 e->src->index, loop->loop_no);
4395 VEC_safe_push (basic_block, heap, loop->blocks, e->src);
4396 bitmap_set_bit (loop->block_bitmap, e->src->index);
4397 FOR_EACH_EDGE (e2, ei2, e->src->preds)
4398 VEC_safe_push (edge, gc, loop->incoming, e2);
4399 VEC_unordered_remove (edge, loop->incoming, ei.index);
4407 fprintf (dump_file, ";; No forwarder blocks found\n");
4415 VEC_free (basic_block, heap, works);
4418 /* Analyze the structure of the loops in the current function. Use STACK
4419 for bitmap allocations. Returns all the valid candidates for hardware
4420 loops found in this function. */
4422 bfin_discover_loops (bitmap_obstack *stack, FILE *dump_file)
4424 loop_info loops = NULL;
4430 /* Find all the possible loop tails. This means searching for every
4431 loop_end instruction. For each one found, create a loop_info
4432 structure and add the head block to the work list. */
4435 rtx tail = BB_END (bb);
4437 while (GET_CODE (tail) == NOTE)
4438 tail = PREV_INSN (tail);
4442 if (INSN_P (tail) && recog_memoized (tail) == CODE_FOR_loop_end)
4445 /* A possible loop end */
4447 /* There's a degenerate case we can handle - an empty loop consisting
4448 of only a back branch. Handle that by deleting the branch. */
4449 insn = BB_HEAD (BRANCH_EDGE (bb)->dest);
4450 if (next_real_insn (insn) == tail)
4454 fprintf (dump_file, ";; degenerate loop ending at\n");
4455 print_rtl_single (dump_file, tail);
4457 delete_insn_and_edges (tail);
4461 loop = XNEW (struct loop_info);
4464 loop->loop_no = nloops++;
4465 loop->blocks = VEC_alloc (basic_block, heap, 20);
4466 loop->block_bitmap = BITMAP_ALLOC (stack);
4471 fprintf (dump_file, ";; potential loop %d ending at\n",
4473 print_rtl_single (dump_file, tail);
4476 bfin_discover_loop (loop, bb, tail);
4480 tmp_bitmap = BITMAP_ALLOC (stack);
4481 /* Compute loop nestings. */
4482 for (loop = loops; loop; loop = loop->next)
4488 for (other = loop->next; other; other = other->next)
4493 bitmap_and (tmp_bitmap, other->block_bitmap, loop->block_bitmap);
4494 if (bitmap_empty_p (tmp_bitmap))
4496 if (bitmap_equal_p (tmp_bitmap, other->block_bitmap))
4498 other->outer = loop;
4499 VEC_safe_push (loop_info, heap, loop->loops, other);
4501 else if (bitmap_equal_p (tmp_bitmap, loop->block_bitmap))
4503 loop->outer = other;
4504 VEC_safe_push (loop_info, heap, other->loops, loop);
4510 ";; can't find suitable nesting for loops %d and %d\n",
4511 loop->loop_no, other->loop_no);
4512 loop->bad = other->bad = 1;
4516 BITMAP_FREE (tmp_bitmap);
4521 /* Free up the loop structures in LOOPS. */
4523 free_loops (loop_info loops)
4527 loop_info loop = loops;
4529 VEC_free (loop_info, heap, loop->loops);
4530 VEC_free (basic_block, heap, loop->blocks);
4531 BITMAP_FREE (loop->block_bitmap);
4536 #define BB_AUX_INDEX(BB) ((unsigned)(BB)->aux)
4538 /* The taken-branch edge from the loop end can actually go forward. Since the
4539 Blackfin's LSETUP instruction requires that the loop end be after the loop
4540 start, try to reorder a loop's basic blocks when we find such a case. */
4542 bfin_reorder_loops (loop_info loops, FILE *dump_file)
4549 cfg_layout_initialize (0);
4551 for (loop = loops; loop; loop = loop->next)
4561 /* Recreate an index for basic blocks that represents their order. */
4562 for (bb = ENTRY_BLOCK_PTR->next_bb, index = 0;
4563 bb != EXIT_BLOCK_PTR;
4564 bb = bb->next_bb, index++)
4565 bb->aux = (PTR) index;
4567 if (BB_AUX_INDEX (loop->head) < BB_AUX_INDEX (loop->tail))
4570 FOR_EACH_EDGE (e, ei, loop->head->succs)
4572 if (bitmap_bit_p (loop->block_bitmap, e->dest->index)
4573 && BB_AUX_INDEX (e->dest) < BB_AUX_INDEX (loop->tail))
4575 basic_block start_bb = e->dest;
4576 basic_block start_prev_bb = start_bb->prev_bb;
4579 fprintf (dump_file, ";; Moving block %d before block %d\n",
4580 loop->head->index, start_bb->index);
4581 loop->head->prev_bb->next_bb = loop->head->next_bb;
4582 loop->head->next_bb->prev_bb = loop->head->prev_bb;
4584 loop->head->prev_bb = start_prev_bb;
4585 loop->head->next_bb = start_bb;
4586 start_prev_bb->next_bb = start_bb->prev_bb = loop->head;
4590 loops = loops->next;
4595 if (bb->next_bb != EXIT_BLOCK_PTR)
4596 bb->aux = bb->next_bb;
4600 cfg_layout_finalize ();
4604 /* Run from machine_dependent_reorg, this pass looks for doloop_end insns
4605 and tries to rewrite the RTL of these loops so that proper Blackfin
4606 hardware loops are generated. */
4609 bfin_reorg_loops (FILE *dump_file)
4611 loop_info loops = NULL;
4614 bitmap_obstack stack;
4616 bitmap_obstack_initialize (&stack);
4619 fprintf (dump_file, ";; Find loops, first pass\n\n");
4621 loops = bfin_discover_loops (&stack, dump_file);
4624 bfin_dump_loops (loops);
4626 bfin_reorder_loops (loops, dump_file);
4630 fprintf (dump_file, ";; Find loops, second pass\n\n");
4632 loops = bfin_discover_loops (&stack, dump_file);
4635 fprintf (dump_file, ";; All loops found:\n\n");
4636 bfin_dump_loops (loops);
4639 /* Now apply the optimizations. */
4640 for (loop = loops; loop; loop = loop->next)
4641 bfin_optimize_loop (loop);
4645 fprintf (dump_file, ";; After hardware loops optimization:\n\n");
4646 bfin_dump_loops (loops);
4652 print_rtl (dump_file, get_insns ());
4657 splitting_loops = 1;
4660 rtx insn = BB_END (bb);
4664 try_split (PATTERN (insn), insn, 1);
4666 splitting_loops = 0;
4669 /* Possibly generate a SEQUENCE out of three insns found in SLOT.
4670 Returns true if we modified the insn chain, false otherwise. */
4672 gen_one_bundle (rtx slot[3])
4674 gcc_assert (slot[1] != NULL_RTX);
4676 /* Don't add extra NOPs if optimizing for size. */
4678 && (slot[0] == NULL_RTX || slot[2] == NULL_RTX))
4681 /* Verify that we really can do the multi-issue. */
4684 rtx t = NEXT_INSN (slot[0]);
4685 while (t != slot[1])
4687 if (GET_CODE (t) != NOTE
4688 || NOTE_KIND (t) != NOTE_INSN_DELETED)
4695 rtx t = NEXT_INSN (slot[1]);
4696 while (t != slot[2])
4698 if (GET_CODE (t) != NOTE
4699 || NOTE_KIND (t) != NOTE_INSN_DELETED)
4705 if (slot[0] == NULL_RTX)
4707 slot[0] = emit_insn_before (gen_mnop (), slot[1]);
4708 df_insn_rescan (slot[0]);
4710 if (slot[2] == NULL_RTX)
4712 slot[2] = emit_insn_after (gen_forced_nop (), slot[1]);
4713 df_insn_rescan (slot[2]);
4716 /* Avoid line number information being printed inside one bundle. */
4717 if (INSN_LOCATOR (slot[1])
4718 && INSN_LOCATOR (slot[1]) != INSN_LOCATOR (slot[0]))
4719 INSN_LOCATOR (slot[1]) = INSN_LOCATOR (slot[0]);
4720 if (INSN_LOCATOR (slot[2])
4721 && INSN_LOCATOR (slot[2]) != INSN_LOCATOR (slot[0]))
4722 INSN_LOCATOR (slot[2]) = INSN_LOCATOR (slot[0]);
4724 /* Terminate them with "|| " instead of ";" in the output. */
4725 PUT_MODE (slot[0], SImode);
4726 PUT_MODE (slot[1], SImode);
4727 /* Terminate the bundle, for the benefit of reorder_var_tracking_notes. */
4728 PUT_MODE (slot[2], QImode);
4732 /* Go through all insns, and use the information generated during scheduling
4733 to generate SEQUENCEs to represent bundles of instructions issued
4737 bfin_gen_bundles (void)
4746 slot[0] = slot[1] = slot[2] = NULL_RTX;
4747 for (insn = BB_HEAD (bb);; insn = next)
4752 if (get_attr_type (insn) == TYPE_DSP32)
4754 else if (slot[1] == NULL_RTX)
4761 next = NEXT_INSN (insn);
4762 while (next && insn != BB_END (bb)
4764 && GET_CODE (PATTERN (next)) != USE
4765 && GET_CODE (PATTERN (next)) != CLOBBER))
4768 next = NEXT_INSN (insn);
4771 /* BB_END can change due to emitting extra NOPs, so check here. */
4772 at_end = insn == BB_END (bb);
4773 if (at_end || GET_MODE (next) == TImode)
4776 || !gen_one_bundle (slot))
4777 && slot[0] != NULL_RTX)
4779 rtx pat = PATTERN (slot[0]);
4780 if (GET_CODE (pat) == SET
4781 && GET_CODE (SET_SRC (pat)) == UNSPEC
4782 && XINT (SET_SRC (pat), 1) == UNSPEC_32BIT)
4784 SET_SRC (pat) = XVECEXP (SET_SRC (pat), 0, 0);
4785 INSN_CODE (slot[0]) = -1;
4786 df_insn_rescan (slot[0]);
4790 slot[0] = slot[1] = slot[2] = NULL_RTX;
4798 /* Ensure that no var tracking notes are emitted in the middle of a
4799 three-instruction bundle. */
4802 reorder_var_tracking_notes (void)
4808 rtx queue = NULL_RTX;
4809 bool in_bundle = false;
4811 for (insn = BB_HEAD (bb); insn != BB_END (bb); insn = next)
4813 next = NEXT_INSN (insn);
4817 /* Emit queued up notes at the last instruction of a bundle. */
4818 if (GET_MODE (insn) == QImode)
4822 rtx next_queue = PREV_INSN (queue);
4823 PREV_INSN (NEXT_INSN (insn)) = queue;
4824 NEXT_INSN (queue) = NEXT_INSN (insn);
4825 NEXT_INSN (insn) = queue;
4826 PREV_INSN (queue) = insn;
4831 else if (GET_MODE (insn) == SImode)
4834 else if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION)
4838 rtx prev = PREV_INSN (insn);
4839 PREV_INSN (next) = prev;
4840 NEXT_INSN (prev) = next;
4842 PREV_INSN (insn) = queue;
4850 /* On some silicon revisions, functions shorter than a certain number of cycles
4851 can cause unpredictable behaviour. Work around this by adding NOPs as
4854 workaround_rts_anomaly (void)
4856 rtx insn, first_insn = NULL_RTX;
4859 if (! ENABLE_WA_RETS)
4862 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
4866 if (BARRIER_P (insn))
4869 if (NOTE_P (insn) || LABEL_P (insn))
4872 if (first_insn == NULL_RTX)
4874 pat = PATTERN (insn);
4875 if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER
4876 || GET_CODE (pat) == ASM_INPUT || GET_CODE (pat) == ADDR_VEC
4877 || GET_CODE (pat) == ADDR_DIFF_VEC || asm_noperands (pat) >= 0)
4885 if (recog_memoized (insn) == CODE_FOR_return_internal)
4888 /* Nothing to worry about for direct jumps. */
4889 if (!any_condjump_p (insn))
4895 else if (INSN_P (insn))
4897 rtx pat = PATTERN (insn);
4898 int this_cycles = 1;
4900 if (GET_CODE (pat) == PARALLEL)
4902 if (push_multiple_operation (pat, VOIDmode)
4903 || pop_multiple_operation (pat, VOIDmode))
4904 this_cycles = n_regs_to_save;
4908 enum insn_code icode = recog_memoized (insn);
4909 if (icode == CODE_FOR_link)
4911 else if (icode == CODE_FOR_unlink)
4913 else if (icode == CODE_FOR_mulsi3)
4916 if (this_cycles >= cycles)
4919 cycles -= this_cycles;
4924 emit_insn_before (gen_nop (), first_insn);
4929 /* Return an insn type for INSN that can be used by the caller for anomaly
4930 workarounds. This differs from plain get_attr_type in that it handles
4933 static enum attr_type
4934 type_for_anomaly (rtx insn)
4936 rtx pat = PATTERN (insn);
4937 if (GET_CODE (pat) == SEQUENCE)
4940 t = get_attr_type (XVECEXP (pat, 0, 1));
4943 t = get_attr_type (XVECEXP (pat, 0, 2));
4949 return get_attr_type (insn);
4952 /* Return nonzero if INSN contains any loads that may trap. It handles
4953 SEQUENCEs correctly. */
4956 trapping_loads_p (rtx insn)
4958 rtx pat = PATTERN (insn);
4959 if (GET_CODE (pat) == SEQUENCE)
4962 t = get_attr_type (XVECEXP (pat, 0, 1));
4964 && may_trap_p (SET_SRC (PATTERN (XVECEXP (pat, 0, 1)))))
4966 t = get_attr_type (XVECEXP (pat, 0, 2));
4968 && may_trap_p (SET_SRC (PATTERN (XVECEXP (pat, 0, 2)))))
4973 return may_trap_p (SET_SRC (single_set (insn)));
4976 /* Return INSN if it is of TYPE_MCLD. Alternatively, if INSN is the start of
4977 a three-insn bundle, see if one of them is a load and return that if so.
4978 Return NULL_RTX if the insn does not contain loads. */
4980 find_load (rtx insn)
4982 if (get_attr_type (insn) == TYPE_MCLD)
4984 if (GET_MODE (insn) != SImode)
4987 insn = NEXT_INSN (insn);
4988 if ((GET_MODE (insn) == SImode || GET_MODE (insn) == QImode)
4989 && get_attr_type (insn) == TYPE_MCLD)
4991 } while (GET_MODE (insn) != QImode);
4995 /* Determine whether PAT is an indirect call pattern. */
4997 indirect_call_p (rtx pat)
4999 if (GET_CODE (pat) == PARALLEL)
5000 pat = XVECEXP (pat, 0, 0);
5001 if (GET_CODE (pat) == SET)
5002 pat = SET_SRC (pat);
5003 gcc_assert (GET_CODE (pat) == CALL);
5004 pat = XEXP (pat, 0);
5005 gcc_assert (GET_CODE (pat) == MEM);
5006 pat = XEXP (pat, 0);
5012 workaround_speculation (void)
5015 rtx last_condjump = NULL_RTX;
5016 int cycles_since_jump = INT_MAX;
5017 int delay_added = 0;
5019 if (! ENABLE_WA_SPECULATIVE_LOADS && ! ENABLE_WA_SPECULATIVE_SYNCS
5020 && ! ENABLE_WA_INDIRECT_CALLS)
5023 /* First pass: find predicted-false branches; if something after them
5024 needs nops, insert them or change the branch to predict true. */
5025 for (insn = get_insns (); insn; insn = next)
5028 int delay_needed = 0;
5030 next = find_next_insn_start (insn);
5032 if (NOTE_P (insn) || BARRIER_P (insn) || LABEL_P (insn))
5035 pat = PATTERN (insn);
5036 if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER
5037 || GET_CODE (pat) == ASM_INPUT || GET_CODE (pat) == ADDR_VEC
5038 || GET_CODE (pat) == ADDR_DIFF_VEC || asm_noperands (pat) >= 0)
5043 if (any_condjump_p (insn)
5044 && ! cbranch_predicted_taken_p (insn))
5046 last_condjump = insn;
5048 cycles_since_jump = 0;
5051 cycles_since_jump = INT_MAX;
5053 else if (CALL_P (insn))
5055 if (cycles_since_jump < INT_MAX)
5056 cycles_since_jump++;
5057 if (indirect_call_p (pat) && ENABLE_WA_INDIRECT_CALLS)
5062 else if (INSN_P (insn))
5064 rtx load_insn = find_load (insn);
5065 enum attr_type type = type_for_anomaly (insn);
5067 if (cycles_since_jump < INT_MAX)
5068 cycles_since_jump++;
5070 if (load_insn && ENABLE_WA_SPECULATIVE_LOADS)
5072 if (trapping_loads_p (load_insn))
5075 else if (type == TYPE_SYNC && ENABLE_WA_SPECULATIVE_SYNCS)
5079 if (delay_needed > cycles_since_jump
5080 && (delay_needed - cycles_since_jump) > delay_added)
5084 rtx *op = recog_data.operand;
5086 delay_needed -= cycles_since_jump;
5088 extract_insn (last_condjump);
5091 pat1 = gen_cbranch_predicted_taken (op[0], op[1], op[2],
5093 cycles_since_jump = INT_MAX;
5097 /* Do not adjust cycles_since_jump in this case, so that
5098 we'll increase the number of NOPs for a subsequent insn
5100 pat1 = gen_cbranch_with_nops (op[0], op[1], op[2], op[3],
5101 GEN_INT (delay_needed));
5102 delay_added = delay_needed;
5104 PATTERN (last_condjump) = pat1;
5105 INSN_CODE (last_condjump) = recog (pat1, insn, &num_clobbers);
5109 cycles_since_jump = INT_MAX;
5114 /* Second pass: for predicted-true branches, see if anything at the
5115 branch destination needs extra nops. */
5116 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
5118 int cycles_since_jump;
5120 && any_condjump_p (insn)
5121 && (INSN_CODE (insn) == CODE_FOR_cbranch_predicted_taken
5122 || cbranch_predicted_taken_p (insn)))
5124 rtx target = JUMP_LABEL (insn);
5128 cycles_since_jump = 0;
5129 for (; target && cycles_since_jump < 3; target = next_tgt)
5133 next_tgt = find_next_insn_start (target);
5135 if (NOTE_P (target) || BARRIER_P (target) || LABEL_P (target))
5138 pat = PATTERN (target);
5139 if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER
5140 || GET_CODE (pat) == ASM_INPUT || GET_CODE (pat) == ADDR_VEC
5141 || GET_CODE (pat) == ADDR_DIFF_VEC || asm_noperands (pat) >= 0)
5144 if (INSN_P (target))
5146 rtx load_insn = find_load (target);
5147 enum attr_type type = type_for_anomaly (target);
5148 int delay_needed = 0;
5149 if (cycles_since_jump < INT_MAX)
5150 cycles_since_jump++;
5152 if (load_insn && ENABLE_WA_SPECULATIVE_LOADS)
5154 if (trapping_loads_p (load_insn))
5157 else if (type == TYPE_SYNC && ENABLE_WA_SPECULATIVE_SYNCS)
5160 if (delay_needed > cycles_since_jump)
5162 rtx prev = prev_real_insn (label);
5163 delay_needed -= cycles_since_jump;
5165 fprintf (dump_file, "Adding %d nops after %d\n",
5166 delay_needed, INSN_UID (label));
5168 && INSN_CODE (prev) == CODE_FOR_cbranch_with_nops)
5175 "Reducing nops on insn %d.\n",
5178 x = XVECEXP (x, 0, 1);
5179 v = INTVAL (XVECEXP (x, 0, 0)) - delay_needed;
5180 XVECEXP (x, 0, 0) = GEN_INT (v);
5182 while (delay_needed-- > 0)
5183 emit_insn_after (gen_nop (), label);
5192 /* We use the machine specific reorg pass for emitting CSYNC instructions
5193 after conditional branches as needed.
5195 The Blackfin is unusual in that a code sequence like
5198 may speculatively perform the load even if the condition isn't true. This
5199 happens for a branch that is predicted not taken, because the pipeline
5200 isn't flushed or stalled, so the early stages of the following instructions,
5201 which perform the memory reference, are allowed to execute before the
5202 jump condition is evaluated.
5203 Therefore, we must insert additional instructions in all places where this
5204 could lead to incorrect behavior. The manual recommends CSYNC, while
5205 VDSP seems to use NOPs (even though its corresponding compiler option is
5208 When optimizing for speed, we emit NOPs, which seems faster than a CSYNC.
5209 When optimizing for size, we turn the branch into a predicted taken one.
5210 This may be slower due to mispredicts, but saves code size. */
5215 /* We are freeing block_for_insn in the toplev to keep compatibility
5216 with old MDEP_REORGS that are not CFG based. Recompute it now. */
5217 compute_bb_for_insn ();
5219 if (bfin_flag_schedule_insns2)
5221 splitting_for_sched = 1;
5223 splitting_for_sched = 0;
5225 timevar_push (TV_SCHED2);
5227 timevar_pop (TV_SCHED2);
5229 /* Examine the schedule and insert nops as necessary for 64-bit parallel
5231 bfin_gen_bundles ();
5236 /* Doloop optimization */
5237 if (cfun->machine->has_hardware_loops)
5238 bfin_reorg_loops (dump_file);
5240 workaround_speculation ();
5242 if (bfin_flag_var_tracking)
5244 timevar_push (TV_VAR_TRACKING);
5245 variable_tracking_main ();
5246 reorder_var_tracking_notes ();
5247 timevar_pop (TV_VAR_TRACKING);
5250 df_finish_pass (false);
5252 workaround_rts_anomaly ();
5255 /* Handle interrupt_handler, exception_handler and nmi_handler function
5256 attributes; arguments as in struct attribute_spec.handler. */
5259 handle_int_attribute (tree *node, tree name,
5260 tree args ATTRIBUTE_UNUSED,
5261 int flags ATTRIBUTE_UNUSED,
5265 if (TREE_CODE (x) == FUNCTION_DECL)
5268 if (TREE_CODE (x) != FUNCTION_TYPE)
5270 warning (OPT_Wattributes, "%qs attribute only applies to functions",
5271 IDENTIFIER_POINTER (name));
5272 *no_add_attrs = true;
5274 else if (funkind (x) != SUBROUTINE)
5275 error ("multiple function type attributes specified");
5280 /* Return 0 if the attributes for two types are incompatible, 1 if they
5281 are compatible, and 2 if they are nearly compatible (which causes a
5282 warning to be generated). */
5285 bfin_comp_type_attributes (const_tree type1, const_tree type2)
5287 e_funkind kind1, kind2;
5289 if (TREE_CODE (type1) != FUNCTION_TYPE)
5292 kind1 = funkind (type1);
5293 kind2 = funkind (type2);
5298 /* Check for mismatched modifiers */
5299 if (!lookup_attribute ("nesting", TYPE_ATTRIBUTES (type1))
5300 != !lookup_attribute ("nesting", TYPE_ATTRIBUTES (type2)))
5303 if (!lookup_attribute ("saveall", TYPE_ATTRIBUTES (type1))
5304 != !lookup_attribute ("saveall", TYPE_ATTRIBUTES (type2)))
5307 if (!lookup_attribute ("kspisusp", TYPE_ATTRIBUTES (type1))
5308 != !lookup_attribute ("kspisusp", TYPE_ATTRIBUTES (type2)))
5311 if (!lookup_attribute ("longcall", TYPE_ATTRIBUTES (type1))
5312 != !lookup_attribute ("longcall", TYPE_ATTRIBUTES (type2)))
5318 /* Handle a "longcall" or "shortcall" attribute; arguments as in
5319 struct attribute_spec.handler. */
5322 bfin_handle_longcall_attribute (tree *node, tree name,
5323 tree args ATTRIBUTE_UNUSED,
5324 int flags ATTRIBUTE_UNUSED,
5327 if (TREE_CODE (*node) != FUNCTION_TYPE
5328 && TREE_CODE (*node) != FIELD_DECL
5329 && TREE_CODE (*node) != TYPE_DECL)
5331 warning (OPT_Wattributes, "`%s' attribute only applies to functions",
5332 IDENTIFIER_POINTER (name));
5333 *no_add_attrs = true;
5336 if ((strcmp (IDENTIFIER_POINTER (name), "longcall") == 0
5337 && lookup_attribute ("shortcall", TYPE_ATTRIBUTES (*node)))
5338 || (strcmp (IDENTIFIER_POINTER (name), "shortcall") == 0
5339 && lookup_attribute ("longcall", TYPE_ATTRIBUTES (*node))))
5341 warning (OPT_Wattributes,
5342 "can't apply both longcall and shortcall attributes to the same function");
5343 *no_add_attrs = true;
5349 /* Handle a "l1_text" attribute; arguments as in
5350 struct attribute_spec.handler. */
5353 bfin_handle_l1_text_attribute (tree *node, tree name, tree ARG_UNUSED (args),
5354 int ARG_UNUSED (flags), bool *no_add_attrs)
5358 if (TREE_CODE (decl) != FUNCTION_DECL)
5360 error ("`%s' attribute only applies to functions",
5361 IDENTIFIER_POINTER (name));
5362 *no_add_attrs = true;
5365 /* The decl may have already been given a section attribute
5366 from a previous declaration. Ensure they match. */
5367 else if (DECL_SECTION_NAME (decl) != NULL_TREE
5368 && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
5371 error ("section of %q+D conflicts with previous declaration",
5373 *no_add_attrs = true;
5376 DECL_SECTION_NAME (decl) = build_string (9, ".l1.text");
5381 /* Handle a "l1_data", "l1_data_A" or "l1_data_B" attribute;
5382 arguments as in struct attribute_spec.handler. */
5385 bfin_handle_l1_data_attribute (tree *node, tree name, tree ARG_UNUSED (args),
5386 int ARG_UNUSED (flags), bool *no_add_attrs)
5390 if (TREE_CODE (decl) != VAR_DECL)
5392 error ("`%s' attribute only applies to variables",
5393 IDENTIFIER_POINTER (name));
5394 *no_add_attrs = true;
5396 else if (current_function_decl != NULL_TREE
5397 && !TREE_STATIC (decl))
5399 error ("`%s' attribute cannot be specified for local variables",
5400 IDENTIFIER_POINTER (name));
5401 *no_add_attrs = true;
5405 const char *section_name;
5407 if (strcmp (IDENTIFIER_POINTER (name), "l1_data") == 0)
5408 section_name = ".l1.data";
5409 else if (strcmp (IDENTIFIER_POINTER (name), "l1_data_A") == 0)
5410 section_name = ".l1.data.A";
5411 else if (strcmp (IDENTIFIER_POINTER (name), "l1_data_B") == 0)
5412 section_name = ".l1.data.B";
5416 /* The decl may have already been given a section attribute
5417 from a previous declaration. Ensure they match. */
5418 if (DECL_SECTION_NAME (decl) != NULL_TREE
5419 && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
5422 error ("section of %q+D conflicts with previous declaration",
5424 *no_add_attrs = true;
5427 DECL_SECTION_NAME (decl)
5428 = build_string (strlen (section_name) + 1, section_name);
5434 /* Table of valid machine attributes. */
5435 const struct attribute_spec bfin_attribute_table[] =
5437 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
5438 { "interrupt_handler", 0, 0, false, true, true, handle_int_attribute },
5439 { "exception_handler", 0, 0, false, true, true, handle_int_attribute },
5440 { "nmi_handler", 0, 0, false, true, true, handle_int_attribute },
5441 { "nesting", 0, 0, false, true, true, NULL },
5442 { "kspisusp", 0, 0, false, true, true, NULL },
5443 { "saveall", 0, 0, false, true, true, NULL },
5444 { "longcall", 0, 0, false, true, true, bfin_handle_longcall_attribute },
5445 { "shortcall", 0, 0, false, true, true, bfin_handle_longcall_attribute },
5446 { "l1_text", 0, 0, true, false, false, bfin_handle_l1_text_attribute },
5447 { "l1_data", 0, 0, true, false, false, bfin_handle_l1_data_attribute },
5448 { "l1_data_A", 0, 0, true, false, false, bfin_handle_l1_data_attribute },
5449 { "l1_data_B", 0, 0, true, false, false, bfin_handle_l1_data_attribute },
5450 { NULL, 0, 0, false, false, false, NULL }
5453 /* Implementation of TARGET_ASM_INTEGER. When using FD-PIC, we need to
5454 tell the assembler to generate pointers to function descriptors in
5458 bfin_assemble_integer (rtx value, unsigned int size, int aligned_p)
5460 if (TARGET_FDPIC && size == UNITS_PER_WORD)
5462 if (GET_CODE (value) == SYMBOL_REF
5463 && SYMBOL_REF_FUNCTION_P (value))
5465 fputs ("\t.picptr\tfuncdesc(", asm_out_file);
5466 output_addr_const (asm_out_file, value);
5467 fputs (")\n", asm_out_file);
5472 /* We've set the unaligned SI op to NULL, so we always have to
5473 handle the unaligned case here. */
5474 assemble_integer_with_op ("\t.4byte\t", value);
5478 return default_assemble_integer (value, size, aligned_p);
5481 /* Output the assembler code for a thunk function. THUNK_DECL is the
5482 declaration for the thunk function itself, FUNCTION is the decl for
5483 the target function. DELTA is an immediate constant offset to be
5484 added to THIS. If VCALL_OFFSET is nonzero, the word at
5485 *(*this + vcall_offset) should be added to THIS. */
5488 bfin_output_mi_thunk (FILE *file ATTRIBUTE_UNUSED,
5489 tree thunk ATTRIBUTE_UNUSED, HOST_WIDE_INT delta,
5490 HOST_WIDE_INT vcall_offset, tree function)
5493 /* The this parameter is passed as the first argument. */
5494 rtx this_rtx = gen_rtx_REG (Pmode, REG_R0);
5496 /* Adjust the this parameter by a fixed constant. */
5500 if (delta >= -64 && delta <= 63)
5502 xops[0] = GEN_INT (delta);
5503 output_asm_insn ("%1 += %0;", xops);
5505 else if (delta >= -128 && delta < -64)
5507 xops[0] = GEN_INT (delta + 64);
5508 output_asm_insn ("%1 += -64; %1 += %0;", xops);
5510 else if (delta > 63 && delta <= 126)
5512 xops[0] = GEN_INT (delta - 63);
5513 output_asm_insn ("%1 += 63; %1 += %0;", xops);
5517 xops[0] = GEN_INT (delta);
5518 output_asm_insn ("r3.l = %h0; r3.h = %d0; %1 = %1 + r3;", xops);
5522 /* Adjust the this parameter by a value stored in the vtable. */
5525 rtx p2tmp = gen_rtx_REG (Pmode, REG_P2);
5526 rtx tmp = gen_rtx_REG (Pmode, REG_R3);
5530 output_asm_insn ("%2 = r0; %2 = [%2];", xops);
5532 /* Adjust the this parameter. */
5533 xops[0] = gen_rtx_MEM (Pmode, plus_constant (p2tmp, vcall_offset));
5534 if (!memory_operand (xops[0], Pmode))
5536 rtx tmp2 = gen_rtx_REG (Pmode, REG_P1);
5537 xops[0] = GEN_INT (vcall_offset);
5539 output_asm_insn ("%h1 = %h0; %d1 = %d0; %2 = %2 + %1", xops);
5540 xops[0] = gen_rtx_MEM (Pmode, p2tmp);
5543 output_asm_insn ("%1 = %0; %2 = %2 + %1;", xops);
5546 xops[0] = XEXP (DECL_RTL (function), 0);
5547 if (1 || !flag_pic || (*targetm.binds_local_p) (function))
5548 output_asm_insn ("jump.l\t%P0", xops);
5551 /* Codes for all the Blackfin builtins. */
5557 BFIN_BUILTIN_COMPOSE_2X16,
5558 BFIN_BUILTIN_EXTRACTLO,
5559 BFIN_BUILTIN_EXTRACTHI,
5561 BFIN_BUILTIN_SSADD_2X16,
5562 BFIN_BUILTIN_SSSUB_2X16,
5563 BFIN_BUILTIN_SSADDSUB_2X16,
5564 BFIN_BUILTIN_SSSUBADD_2X16,
5565 BFIN_BUILTIN_MULT_2X16,
5566 BFIN_BUILTIN_MULTR_2X16,
5567 BFIN_BUILTIN_NEG_2X16,
5568 BFIN_BUILTIN_ABS_2X16,
5569 BFIN_BUILTIN_MIN_2X16,
5570 BFIN_BUILTIN_MAX_2X16,
5572 BFIN_BUILTIN_SSADD_1X16,
5573 BFIN_BUILTIN_SSSUB_1X16,
5574 BFIN_BUILTIN_MULT_1X16,
5575 BFIN_BUILTIN_MULTR_1X16,
5576 BFIN_BUILTIN_NORM_1X16,
5577 BFIN_BUILTIN_NEG_1X16,
5578 BFIN_BUILTIN_ABS_1X16,
5579 BFIN_BUILTIN_MIN_1X16,
5580 BFIN_BUILTIN_MAX_1X16,
5582 BFIN_BUILTIN_SUM_2X16,
5583 BFIN_BUILTIN_DIFFHL_2X16,
5584 BFIN_BUILTIN_DIFFLH_2X16,
5586 BFIN_BUILTIN_SSADD_1X32,
5587 BFIN_BUILTIN_SSSUB_1X32,
5588 BFIN_BUILTIN_NORM_1X32,
5589 BFIN_BUILTIN_ROUND_1X32,
5590 BFIN_BUILTIN_NEG_1X32,
5591 BFIN_BUILTIN_ABS_1X32,
5592 BFIN_BUILTIN_MIN_1X32,
5593 BFIN_BUILTIN_MAX_1X32,
5594 BFIN_BUILTIN_MULT_1X32,
5595 BFIN_BUILTIN_MULT_1X32X32,
5596 BFIN_BUILTIN_MULT_1X32X32NS,
5598 BFIN_BUILTIN_MULHISILL,
5599 BFIN_BUILTIN_MULHISILH,
5600 BFIN_BUILTIN_MULHISIHL,
5601 BFIN_BUILTIN_MULHISIHH,
5603 BFIN_BUILTIN_LSHIFT_1X16,
5604 BFIN_BUILTIN_LSHIFT_2X16,
5605 BFIN_BUILTIN_SSASHIFT_1X16,
5606 BFIN_BUILTIN_SSASHIFT_2X16,
5607 BFIN_BUILTIN_SSASHIFT_1X32,
5609 BFIN_BUILTIN_CPLX_MUL_16,
5610 BFIN_BUILTIN_CPLX_MAC_16,
5611 BFIN_BUILTIN_CPLX_MSU_16,
5613 BFIN_BUILTIN_CPLX_MUL_16_S40,
5614 BFIN_BUILTIN_CPLX_MAC_16_S40,
5615 BFIN_BUILTIN_CPLX_MSU_16_S40,
5617 BFIN_BUILTIN_CPLX_SQU,
5619 BFIN_BUILTIN_LOADBYTES,
5624 #define def_builtin(NAME, TYPE, CODE) \
5626 add_builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD, \
5630 /* Set up all builtin functions for this target. */
5632 bfin_init_builtins (void)
5634 tree V2HI_type_node = build_vector_type_for_mode (intHI_type_node, V2HImode);
5635 tree void_ftype_void
5636 = build_function_type (void_type_node, void_list_node);
5637 tree short_ftype_short
5638 = build_function_type_list (short_integer_type_node, short_integer_type_node,
5640 tree short_ftype_int_int
5641 = build_function_type_list (short_integer_type_node, integer_type_node,
5642 integer_type_node, NULL_TREE);
5643 tree int_ftype_int_int
5644 = build_function_type_list (integer_type_node, integer_type_node,
5645 integer_type_node, NULL_TREE);
5647 = build_function_type_list (integer_type_node, integer_type_node,
5649 tree short_ftype_int
5650 = build_function_type_list (short_integer_type_node, integer_type_node,
5652 tree int_ftype_v2hi_v2hi
5653 = build_function_type_list (integer_type_node, V2HI_type_node,
5654 V2HI_type_node, NULL_TREE);
5655 tree v2hi_ftype_v2hi_v2hi
5656 = build_function_type_list (V2HI_type_node, V2HI_type_node,
5657 V2HI_type_node, NULL_TREE);
5658 tree v2hi_ftype_v2hi_v2hi_v2hi
5659 = build_function_type_list (V2HI_type_node, V2HI_type_node,
5660 V2HI_type_node, V2HI_type_node, NULL_TREE);
5661 tree v2hi_ftype_int_int
5662 = build_function_type_list (V2HI_type_node, integer_type_node,
5663 integer_type_node, NULL_TREE);
5664 tree v2hi_ftype_v2hi_int
5665 = build_function_type_list (V2HI_type_node, V2HI_type_node,
5666 integer_type_node, NULL_TREE);
5667 tree int_ftype_short_short
5668 = build_function_type_list (integer_type_node, short_integer_type_node,
5669 short_integer_type_node, NULL_TREE);
5670 tree v2hi_ftype_v2hi
5671 = build_function_type_list (V2HI_type_node, V2HI_type_node, NULL_TREE);
5672 tree short_ftype_v2hi
5673 = build_function_type_list (short_integer_type_node, V2HI_type_node,
5676 = build_function_type_list (integer_type_node,
5677 build_pointer_type (integer_type_node),
5680 /* Add the remaining MMX insns with somewhat more complicated types. */
5681 def_builtin ("__builtin_bfin_csync", void_ftype_void, BFIN_BUILTIN_CSYNC);
5682 def_builtin ("__builtin_bfin_ssync", void_ftype_void, BFIN_BUILTIN_SSYNC);
5684 def_builtin ("__builtin_bfin_ones", short_ftype_int, BFIN_BUILTIN_ONES);
5686 def_builtin ("__builtin_bfin_compose_2x16", v2hi_ftype_int_int,
5687 BFIN_BUILTIN_COMPOSE_2X16);
5688 def_builtin ("__builtin_bfin_extract_hi", short_ftype_v2hi,
5689 BFIN_BUILTIN_EXTRACTHI);
5690 def_builtin ("__builtin_bfin_extract_lo", short_ftype_v2hi,
5691 BFIN_BUILTIN_EXTRACTLO);
5693 def_builtin ("__builtin_bfin_min_fr2x16", v2hi_ftype_v2hi_v2hi,
5694 BFIN_BUILTIN_MIN_2X16);
5695 def_builtin ("__builtin_bfin_max_fr2x16", v2hi_ftype_v2hi_v2hi,
5696 BFIN_BUILTIN_MAX_2X16);
5698 def_builtin ("__builtin_bfin_add_fr2x16", v2hi_ftype_v2hi_v2hi,
5699 BFIN_BUILTIN_SSADD_2X16);
5700 def_builtin ("__builtin_bfin_sub_fr2x16", v2hi_ftype_v2hi_v2hi,
5701 BFIN_BUILTIN_SSSUB_2X16);
5702 def_builtin ("__builtin_bfin_dspaddsubsat", v2hi_ftype_v2hi_v2hi,
5703 BFIN_BUILTIN_SSADDSUB_2X16);
5704 def_builtin ("__builtin_bfin_dspsubaddsat", v2hi_ftype_v2hi_v2hi,
5705 BFIN_BUILTIN_SSSUBADD_2X16);
5706 def_builtin ("__builtin_bfin_mult_fr2x16", v2hi_ftype_v2hi_v2hi,
5707 BFIN_BUILTIN_MULT_2X16);
5708 def_builtin ("__builtin_bfin_multr_fr2x16", v2hi_ftype_v2hi_v2hi,
5709 BFIN_BUILTIN_MULTR_2X16);
5710 def_builtin ("__builtin_bfin_negate_fr2x16", v2hi_ftype_v2hi,
5711 BFIN_BUILTIN_NEG_2X16);
5712 def_builtin ("__builtin_bfin_abs_fr2x16", v2hi_ftype_v2hi,
5713 BFIN_BUILTIN_ABS_2X16);
5715 def_builtin ("__builtin_bfin_min_fr1x16", short_ftype_int_int,
5716 BFIN_BUILTIN_MIN_1X16);
5717 def_builtin ("__builtin_bfin_max_fr1x16", short_ftype_int_int,
5718 BFIN_BUILTIN_MAX_1X16);
5720 def_builtin ("__builtin_bfin_add_fr1x16", short_ftype_int_int,
5721 BFIN_BUILTIN_SSADD_1X16);
5722 def_builtin ("__builtin_bfin_sub_fr1x16", short_ftype_int_int,
5723 BFIN_BUILTIN_SSSUB_1X16);
5724 def_builtin ("__builtin_bfin_mult_fr1x16", short_ftype_int_int,
5725 BFIN_BUILTIN_MULT_1X16);
5726 def_builtin ("__builtin_bfin_multr_fr1x16", short_ftype_int_int,
5727 BFIN_BUILTIN_MULTR_1X16);
5728 def_builtin ("__builtin_bfin_negate_fr1x16", short_ftype_short,
5729 BFIN_BUILTIN_NEG_1X16);
5730 def_builtin ("__builtin_bfin_abs_fr1x16", short_ftype_short,
5731 BFIN_BUILTIN_ABS_1X16);
5732 def_builtin ("__builtin_bfin_norm_fr1x16", short_ftype_int,
5733 BFIN_BUILTIN_NORM_1X16);
5735 def_builtin ("__builtin_bfin_sum_fr2x16", short_ftype_v2hi,
5736 BFIN_BUILTIN_SUM_2X16);
5737 def_builtin ("__builtin_bfin_diff_hl_fr2x16", short_ftype_v2hi,
5738 BFIN_BUILTIN_DIFFHL_2X16);
5739 def_builtin ("__builtin_bfin_diff_lh_fr2x16", short_ftype_v2hi,
5740 BFIN_BUILTIN_DIFFLH_2X16);
5742 def_builtin ("__builtin_bfin_mulhisill", int_ftype_v2hi_v2hi,
5743 BFIN_BUILTIN_MULHISILL);
5744 def_builtin ("__builtin_bfin_mulhisihl", int_ftype_v2hi_v2hi,
5745 BFIN_BUILTIN_MULHISIHL);
5746 def_builtin ("__builtin_bfin_mulhisilh", int_ftype_v2hi_v2hi,
5747 BFIN_BUILTIN_MULHISILH);
5748 def_builtin ("__builtin_bfin_mulhisihh", int_ftype_v2hi_v2hi,
5749 BFIN_BUILTIN_MULHISIHH);
5751 def_builtin ("__builtin_bfin_min_fr1x32", int_ftype_int_int,
5752 BFIN_BUILTIN_MIN_1X32);
5753 def_builtin ("__builtin_bfin_max_fr1x32", int_ftype_int_int,
5754 BFIN_BUILTIN_MAX_1X32);
5756 def_builtin ("__builtin_bfin_add_fr1x32", int_ftype_int_int,
5757 BFIN_BUILTIN_SSADD_1X32);
5758 def_builtin ("__builtin_bfin_sub_fr1x32", int_ftype_int_int,
5759 BFIN_BUILTIN_SSSUB_1X32);
5760 def_builtin ("__builtin_bfin_negate_fr1x32", int_ftype_int,
5761 BFIN_BUILTIN_NEG_1X32);
5762 def_builtin ("__builtin_bfin_abs_fr1x32", int_ftype_int,
5763 BFIN_BUILTIN_ABS_1X32);
5764 def_builtin ("__builtin_bfin_norm_fr1x32", short_ftype_int,
5765 BFIN_BUILTIN_NORM_1X32);
5766 def_builtin ("__builtin_bfin_round_fr1x32", short_ftype_int,
5767 BFIN_BUILTIN_ROUND_1X32);
5768 def_builtin ("__builtin_bfin_mult_fr1x32", int_ftype_short_short,
5769 BFIN_BUILTIN_MULT_1X32);
5770 def_builtin ("__builtin_bfin_mult_fr1x32x32", int_ftype_int_int,
5771 BFIN_BUILTIN_MULT_1X32X32);
5772 def_builtin ("__builtin_bfin_mult_fr1x32x32NS", int_ftype_int_int,
5773 BFIN_BUILTIN_MULT_1X32X32NS);
5776 def_builtin ("__builtin_bfin_shl_fr1x16", short_ftype_int_int,
5777 BFIN_BUILTIN_SSASHIFT_1X16);
5778 def_builtin ("__builtin_bfin_shl_fr2x16", v2hi_ftype_v2hi_int,
5779 BFIN_BUILTIN_SSASHIFT_2X16);
5780 def_builtin ("__builtin_bfin_lshl_fr1x16", short_ftype_int_int,
5781 BFIN_BUILTIN_LSHIFT_1X16);
5782 def_builtin ("__builtin_bfin_lshl_fr2x16", v2hi_ftype_v2hi_int,
5783 BFIN_BUILTIN_LSHIFT_2X16);
5784 def_builtin ("__builtin_bfin_shl_fr1x32", int_ftype_int_int,
5785 BFIN_BUILTIN_SSASHIFT_1X32);
5787 /* Complex numbers. */
5788 def_builtin ("__builtin_bfin_cmplx_add", v2hi_ftype_v2hi_v2hi,
5789 BFIN_BUILTIN_SSADD_2X16);
5790 def_builtin ("__builtin_bfin_cmplx_sub", v2hi_ftype_v2hi_v2hi,
5791 BFIN_BUILTIN_SSSUB_2X16);
5792 def_builtin ("__builtin_bfin_cmplx_mul", v2hi_ftype_v2hi_v2hi,
5793 BFIN_BUILTIN_CPLX_MUL_16);
5794 def_builtin ("__builtin_bfin_cmplx_mac", v2hi_ftype_v2hi_v2hi_v2hi,
5795 BFIN_BUILTIN_CPLX_MAC_16);
5796 def_builtin ("__builtin_bfin_cmplx_msu", v2hi_ftype_v2hi_v2hi_v2hi,
5797 BFIN_BUILTIN_CPLX_MSU_16);
5798 def_builtin ("__builtin_bfin_cmplx_mul_s40", v2hi_ftype_v2hi_v2hi,
5799 BFIN_BUILTIN_CPLX_MUL_16_S40);
5800 def_builtin ("__builtin_bfin_cmplx_mac_s40", v2hi_ftype_v2hi_v2hi_v2hi,
5801 BFIN_BUILTIN_CPLX_MAC_16_S40);
5802 def_builtin ("__builtin_bfin_cmplx_msu_s40", v2hi_ftype_v2hi_v2hi_v2hi,
5803 BFIN_BUILTIN_CPLX_MSU_16_S40);
5804 def_builtin ("__builtin_bfin_csqu_fr16", v2hi_ftype_v2hi,
5805 BFIN_BUILTIN_CPLX_SQU);
5807 /* "Unaligned" load. */
5808 def_builtin ("__builtin_bfin_loadbytes", int_ftype_pint,
5809 BFIN_BUILTIN_LOADBYTES);
5814 struct builtin_description
5816 const enum insn_code icode;
5817 const char *const name;
5818 const enum bfin_builtins code;
5822 static const struct builtin_description bdesc_2arg[] =
5824 { CODE_FOR_composev2hi, "__builtin_bfin_compose_2x16", BFIN_BUILTIN_COMPOSE_2X16, -1 },
5826 { CODE_FOR_ssashiftv2hi3, "__builtin_bfin_shl_fr2x16", BFIN_BUILTIN_SSASHIFT_2X16, -1 },
5827 { CODE_FOR_ssashifthi3, "__builtin_bfin_shl_fr1x16", BFIN_BUILTIN_SSASHIFT_1X16, -1 },
5828 { CODE_FOR_lshiftv2hi3, "__builtin_bfin_lshl_fr2x16", BFIN_BUILTIN_LSHIFT_2X16, -1 },
5829 { CODE_FOR_lshifthi3, "__builtin_bfin_lshl_fr1x16", BFIN_BUILTIN_LSHIFT_1X16, -1 },
5830 { CODE_FOR_ssashiftsi3, "__builtin_bfin_shl_fr1x32", BFIN_BUILTIN_SSASHIFT_1X32, -1 },
5832 { CODE_FOR_sminhi3, "__builtin_bfin_min_fr1x16", BFIN_BUILTIN_MIN_1X16, -1 },
5833 { CODE_FOR_smaxhi3, "__builtin_bfin_max_fr1x16", BFIN_BUILTIN_MAX_1X16, -1 },
5834 { CODE_FOR_ssaddhi3, "__builtin_bfin_add_fr1x16", BFIN_BUILTIN_SSADD_1X16, -1 },
5835 { CODE_FOR_sssubhi3, "__builtin_bfin_sub_fr1x16", BFIN_BUILTIN_SSSUB_1X16, -1 },
5837 { CODE_FOR_sminsi3, "__builtin_bfin_min_fr1x32", BFIN_BUILTIN_MIN_1X32, -1 },
5838 { CODE_FOR_smaxsi3, "__builtin_bfin_max_fr1x32", BFIN_BUILTIN_MAX_1X32, -1 },
5839 { CODE_FOR_ssaddsi3, "__builtin_bfin_add_fr1x32", BFIN_BUILTIN_SSADD_1X32, -1 },
5840 { CODE_FOR_sssubsi3, "__builtin_bfin_sub_fr1x32", BFIN_BUILTIN_SSSUB_1X32, -1 },
5842 { CODE_FOR_sminv2hi3, "__builtin_bfin_min_fr2x16", BFIN_BUILTIN_MIN_2X16, -1 },
5843 { CODE_FOR_smaxv2hi3, "__builtin_bfin_max_fr2x16", BFIN_BUILTIN_MAX_2X16, -1 },
5844 { CODE_FOR_ssaddv2hi3, "__builtin_bfin_add_fr2x16", BFIN_BUILTIN_SSADD_2X16, -1 },
5845 { CODE_FOR_sssubv2hi3, "__builtin_bfin_sub_fr2x16", BFIN_BUILTIN_SSSUB_2X16, -1 },
5846 { CODE_FOR_ssaddsubv2hi3, "__builtin_bfin_dspaddsubsat", BFIN_BUILTIN_SSADDSUB_2X16, -1 },
5847 { CODE_FOR_sssubaddv2hi3, "__builtin_bfin_dspsubaddsat", BFIN_BUILTIN_SSSUBADD_2X16, -1 },
5849 { CODE_FOR_flag_mulhisi, "__builtin_bfin_mult_fr1x32", BFIN_BUILTIN_MULT_1X32, MACFLAG_NONE },
5850 { CODE_FOR_flag_mulhi, "__builtin_bfin_mult_fr1x16", BFIN_BUILTIN_MULT_1X16, MACFLAG_T },
5851 { CODE_FOR_flag_mulhi, "__builtin_bfin_multr_fr1x16", BFIN_BUILTIN_MULTR_1X16, MACFLAG_NONE },
5852 { CODE_FOR_flag_mulv2hi, "__builtin_bfin_mult_fr2x16", BFIN_BUILTIN_MULT_2X16, MACFLAG_T },
5853 { CODE_FOR_flag_mulv2hi, "__builtin_bfin_multr_fr2x16", BFIN_BUILTIN_MULTR_2X16, MACFLAG_NONE },
5855 { CODE_FOR_mulhisi_ll, "__builtin_bfin_mulhisill", BFIN_BUILTIN_MULHISILL, -1 },
5856 { CODE_FOR_mulhisi_lh, "__builtin_bfin_mulhisilh", BFIN_BUILTIN_MULHISILH, -1 },
5857 { CODE_FOR_mulhisi_hl, "__builtin_bfin_mulhisihl", BFIN_BUILTIN_MULHISIHL, -1 },
5858 { CODE_FOR_mulhisi_hh, "__builtin_bfin_mulhisihh", BFIN_BUILTIN_MULHISIHH, -1 }
5862 static const struct builtin_description bdesc_1arg[] =
5864 { CODE_FOR_loadbytes, "__builtin_bfin_loadbytes", BFIN_BUILTIN_LOADBYTES, 0 },
5866 { CODE_FOR_ones, "__builtin_bfin_ones", BFIN_BUILTIN_ONES, 0 },
5868 { CODE_FOR_signbitshi2, "__builtin_bfin_norm_fr1x16", BFIN_BUILTIN_NORM_1X16, 0 },
5869 { CODE_FOR_ssneghi2, "__builtin_bfin_negate_fr1x16", BFIN_BUILTIN_NEG_1X16, 0 },
5870 { CODE_FOR_abshi2, "__builtin_bfin_abs_fr1x16", BFIN_BUILTIN_ABS_1X16, 0 },
5872 { CODE_FOR_signbitssi2, "__builtin_bfin_norm_fr1x32", BFIN_BUILTIN_NORM_1X32, 0 },
5873 { CODE_FOR_ssroundsi2, "__builtin_bfin_round_fr1x32", BFIN_BUILTIN_ROUND_1X32, 0 },
5874 { CODE_FOR_ssnegsi2, "__builtin_bfin_negate_fr1x32", BFIN_BUILTIN_NEG_1X32, 0 },
5875 { CODE_FOR_ssabssi2, "__builtin_bfin_abs_fr1x32", BFIN_BUILTIN_ABS_1X32, 0 },
5877 { CODE_FOR_movv2hi_hi_low, "__builtin_bfin_extract_lo", BFIN_BUILTIN_EXTRACTLO, 0 },
5878 { CODE_FOR_movv2hi_hi_high, "__builtin_bfin_extract_hi", BFIN_BUILTIN_EXTRACTHI, 0 },
5879 { CODE_FOR_ssnegv2hi2, "__builtin_bfin_negate_fr2x16", BFIN_BUILTIN_NEG_2X16, 0 },
5880 { CODE_FOR_ssabsv2hi2, "__builtin_bfin_abs_fr2x16", BFIN_BUILTIN_ABS_2X16, 0 }
5883 /* Errors in the source file can cause expand_expr to return const0_rtx
5884 where we expect a vector. To avoid crashing, use one of the vector
5885 clear instructions. */
5887 safe_vector_operand (rtx x, enum machine_mode mode)
5889 if (x != const0_rtx)
5891 x = gen_reg_rtx (SImode);
5893 emit_insn (gen_movsi (x, CONST0_RTX (SImode)));
5894 return gen_lowpart (mode, x);
5897 /* Subroutine of bfin_expand_builtin to take care of binop insns. MACFLAG is -1
5898 if this is a normal binary op, or one of the MACFLAG_xxx constants. */
5901 bfin_expand_binop_builtin (enum insn_code icode, tree exp, rtx target,
5905 tree arg0 = CALL_EXPR_ARG (exp, 0);
5906 tree arg1 = CALL_EXPR_ARG (exp, 1);
5907 rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
5908 rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
5909 enum machine_mode op0mode = GET_MODE (op0);
5910 enum machine_mode op1mode = GET_MODE (op1);
5911 enum machine_mode tmode = insn_data[icode].operand[0].mode;
5912 enum machine_mode mode0 = insn_data[icode].operand[1].mode;
5913 enum machine_mode mode1 = insn_data[icode].operand[2].mode;
5915 if (VECTOR_MODE_P (mode0))
5916 op0 = safe_vector_operand (op0, mode0);
5917 if (VECTOR_MODE_P (mode1))
5918 op1 = safe_vector_operand (op1, mode1);
5921 || GET_MODE (target) != tmode
5922 || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
5923 target = gen_reg_rtx (tmode);
5925 if ((op0mode == SImode || op0mode == VOIDmode) && mode0 == HImode)
5928 op0 = gen_lowpart (HImode, op0);
5930 if ((op1mode == SImode || op1mode == VOIDmode) && mode1 == HImode)
5933 op1 = gen_lowpart (HImode, op1);
5935 /* In case the insn wants input operands in modes different from
5936 the result, abort. */
5937 gcc_assert ((op0mode == mode0 || op0mode == VOIDmode)
5938 && (op1mode == mode1 || op1mode == VOIDmode));
5940 if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
5941 op0 = copy_to_mode_reg (mode0, op0);
5942 if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
5943 op1 = copy_to_mode_reg (mode1, op1);
5946 pat = GEN_FCN (icode) (target, op0, op1);
5948 pat = GEN_FCN (icode) (target, op0, op1, GEN_INT (macflag));
5956 /* Subroutine of bfin_expand_builtin to take care of unop insns. */
5959 bfin_expand_unop_builtin (enum insn_code icode, tree exp,
5963 tree arg0 = CALL_EXPR_ARG (exp, 0);
5964 rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
5965 enum machine_mode op0mode = GET_MODE (op0);
5966 enum machine_mode tmode = insn_data[icode].operand[0].mode;
5967 enum machine_mode mode0 = insn_data[icode].operand[1].mode;
5970 || GET_MODE (target) != tmode
5971 || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
5972 target = gen_reg_rtx (tmode);
5974 if (VECTOR_MODE_P (mode0))
5975 op0 = safe_vector_operand (op0, mode0);
5977 if (op0mode == SImode && mode0 == HImode)
5980 op0 = gen_lowpart (HImode, op0);
5982 gcc_assert (op0mode == mode0 || op0mode == VOIDmode);
5984 if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
5985 op0 = copy_to_mode_reg (mode0, op0);
5987 pat = GEN_FCN (icode) (target, op0);
5994 /* Expand an expression EXP that calls a built-in function,
5995 with result going to TARGET if that's convenient
5996 (and in mode MODE if that's convenient).
5997 SUBTARGET may be used as the target for computing one of EXP's operands.
5998 IGNORE is nonzero if the value is to be ignored. */
6001 bfin_expand_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
6002 rtx subtarget ATTRIBUTE_UNUSED,
6003 enum machine_mode mode ATTRIBUTE_UNUSED,
6004 int ignore ATTRIBUTE_UNUSED)
6007 enum insn_code icode;
6008 const struct builtin_description *d;
6009 tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
6010 unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
6011 tree arg0, arg1, arg2;
6012 rtx op0, op1, op2, accvec, pat, tmp1, tmp2, a0reg, a1reg;
6013 enum machine_mode tmode, mode0;
6017 case BFIN_BUILTIN_CSYNC:
6018 emit_insn (gen_csync ());
6020 case BFIN_BUILTIN_SSYNC:
6021 emit_insn (gen_ssync ());
6024 case BFIN_BUILTIN_DIFFHL_2X16:
6025 case BFIN_BUILTIN_DIFFLH_2X16:
6026 case BFIN_BUILTIN_SUM_2X16:
6027 arg0 = CALL_EXPR_ARG (exp, 0);
6028 op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6029 icode = (fcode == BFIN_BUILTIN_DIFFHL_2X16 ? CODE_FOR_subhilov2hi3
6030 : fcode == BFIN_BUILTIN_DIFFLH_2X16 ? CODE_FOR_sublohiv2hi3
6031 : CODE_FOR_ssaddhilov2hi3);
6032 tmode = insn_data[icode].operand[0].mode;
6033 mode0 = insn_data[icode].operand[1].mode;
6036 || GET_MODE (target) != tmode
6037 || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
6038 target = gen_reg_rtx (tmode);
6040 if (VECTOR_MODE_P (mode0))
6041 op0 = safe_vector_operand (op0, mode0);
6043 if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
6044 op0 = copy_to_mode_reg (mode0, op0);
6046 pat = GEN_FCN (icode) (target, op0, op0);
6052 case BFIN_BUILTIN_MULT_1X32X32:
6053 case BFIN_BUILTIN_MULT_1X32X32NS:
6054 arg0 = CALL_EXPR_ARG (exp, 0);
6055 arg1 = CALL_EXPR_ARG (exp, 1);
6056 op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6057 op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
6059 || !register_operand (target, SImode))
6060 target = gen_reg_rtx (SImode);
6062 a1reg = gen_rtx_REG (PDImode, REG_A1);
6063 a0reg = gen_rtx_REG (PDImode, REG_A0);
6064 tmp1 = gen_lowpart (V2HImode, op0);
6065 tmp2 = gen_lowpart (V2HImode, op1);
6066 emit_insn (gen_flag_macinit1hi (a1reg,
6067 gen_lowpart (HImode, op0),
6068 gen_lowpart (HImode, op1),
6069 GEN_INT (MACFLAG_FU)));
6070 emit_insn (gen_lshrpdi3 (a1reg, a1reg, GEN_INT (16)));
6072 if (fcode == BFIN_BUILTIN_MULT_1X32X32)
6073 emit_insn (gen_flag_mul_macv2hi_parts_acconly (a0reg, a1reg, tmp1, tmp2,
6074 const1_rtx, const1_rtx,
6075 const1_rtx, const0_rtx, a1reg,
6076 const0_rtx, GEN_INT (MACFLAG_NONE),
6077 GEN_INT (MACFLAG_M)));
6080 /* For saturating multiplication, there's exactly one special case
6081 to be handled: multiplying the smallest negative value with
6082 itself. Due to shift correction in fractional multiplies, this
6083 can overflow. Iff this happens, OP2 will contain 1, which, when
6084 added in 32 bits to the smallest negative, wraps to the largest
6085 positive, which is the result we want. */
6086 op2 = gen_reg_rtx (V2HImode);
6087 emit_insn (gen_packv2hi (op2, tmp1, tmp2, const0_rtx, const0_rtx));
6088 emit_insn (gen_movsibi (gen_rtx_REG (BImode, REG_CC),
6089 gen_lowpart (SImode, op2)));
6090 emit_insn (gen_flag_mul_macv2hi_parts_acconly_andcc0 (a0reg, a1reg, tmp1, tmp2,
6091 const1_rtx, const1_rtx,
6092 const1_rtx, const0_rtx, a1reg,
6093 const0_rtx, GEN_INT (MACFLAG_NONE),
6094 GEN_INT (MACFLAG_M)));
6095 op2 = gen_reg_rtx (SImode);
6096 emit_insn (gen_movbisi (op2, gen_rtx_REG (BImode, REG_CC)));
6098 emit_insn (gen_flag_machi_parts_acconly (a1reg, tmp2, tmp1,
6099 const1_rtx, const0_rtx,
6100 a1reg, const0_rtx, GEN_INT (MACFLAG_M)));
6101 emit_insn (gen_ashrpdi3 (a1reg, a1reg, GEN_INT (15)));
6102 emit_insn (gen_sum_of_accumulators (target, a0reg, a0reg, a1reg));
6103 if (fcode == BFIN_BUILTIN_MULT_1X32X32NS)
6104 emit_insn (gen_addsi3 (target, target, op2));
6107 case BFIN_BUILTIN_CPLX_MUL_16:
6108 case BFIN_BUILTIN_CPLX_MUL_16_S40:
6109 arg0 = CALL_EXPR_ARG (exp, 0);
6110 arg1 = CALL_EXPR_ARG (exp, 1);
6111 op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6112 op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
6113 accvec = gen_reg_rtx (V2PDImode);
6116 || GET_MODE (target) != V2HImode
6117 || ! (*insn_data[icode].operand[0].predicate) (target, V2HImode))
6118 target = gen_reg_rtx (tmode);
6119 if (! register_operand (op0, GET_MODE (op0)))
6120 op0 = copy_to_mode_reg (GET_MODE (op0), op0);
6121 if (! register_operand (op1, GET_MODE (op1)))
6122 op1 = copy_to_mode_reg (GET_MODE (op1), op1);
6124 if (fcode == BFIN_BUILTIN_CPLX_MUL_16)
6125 emit_insn (gen_flag_macinit1v2hi_parts (accvec, op0, op1, const0_rtx,
6126 const0_rtx, const0_rtx,
6127 const1_rtx, GEN_INT (MACFLAG_W32)));
6129 emit_insn (gen_flag_macinit1v2hi_parts (accvec, op0, op1, const0_rtx,
6130 const0_rtx, const0_rtx,
6131 const1_rtx, GEN_INT (MACFLAG_NONE)));
6132 emit_insn (gen_flag_macv2hi_parts (target, op0, op1, const1_rtx,
6133 const1_rtx, const1_rtx,
6134 const0_rtx, accvec, const1_rtx, const0_rtx,
6135 GEN_INT (MACFLAG_NONE), accvec));
6139 case BFIN_BUILTIN_CPLX_MAC_16:
6140 case BFIN_BUILTIN_CPLX_MSU_16:
6141 case BFIN_BUILTIN_CPLX_MAC_16_S40:
6142 case BFIN_BUILTIN_CPLX_MSU_16_S40:
6143 arg0 = CALL_EXPR_ARG (exp, 0);
6144 arg1 = CALL_EXPR_ARG (exp, 1);
6145 arg2 = CALL_EXPR_ARG (exp, 2);
6146 op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6147 op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
6148 op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
6149 accvec = gen_reg_rtx (V2PDImode);
6152 || GET_MODE (target) != V2HImode
6153 || ! (*insn_data[icode].operand[0].predicate) (target, V2HImode))
6154 target = gen_reg_rtx (tmode);
6155 if (! register_operand (op1, GET_MODE (op1)))
6156 op1 = copy_to_mode_reg (GET_MODE (op1), op1);
6157 if (! register_operand (op2, GET_MODE (op2)))
6158 op2 = copy_to_mode_reg (GET_MODE (op2), op2);
6160 tmp1 = gen_reg_rtx (SImode);
6161 tmp2 = gen_reg_rtx (SImode);
6162 emit_insn (gen_ashlsi3 (tmp1, gen_lowpart (SImode, op0), GEN_INT (16)));
6163 emit_move_insn (tmp2, gen_lowpart (SImode, op0));
6164 emit_insn (gen_movstricthi_1 (gen_lowpart (HImode, tmp2), const0_rtx));
6165 emit_insn (gen_load_accumulator_pair (accvec, tmp1, tmp2));
6166 if (fcode == BFIN_BUILTIN_CPLX_MAC_16
6167 || fcode == BFIN_BUILTIN_CPLX_MSU_16)
6168 emit_insn (gen_flag_macv2hi_parts_acconly (accvec, op1, op2, const0_rtx,
6169 const0_rtx, const0_rtx,
6170 const1_rtx, accvec, const0_rtx,
6172 GEN_INT (MACFLAG_W32)));
6174 emit_insn (gen_flag_macv2hi_parts_acconly (accvec, op1, op2, const0_rtx,
6175 const0_rtx, const0_rtx,
6176 const1_rtx, accvec, const0_rtx,
6178 GEN_INT (MACFLAG_NONE)));
6179 if (fcode == BFIN_BUILTIN_CPLX_MAC_16
6180 || fcode == BFIN_BUILTIN_CPLX_MAC_16_S40)
6190 emit_insn (gen_flag_macv2hi_parts (target, op1, op2, const1_rtx,
6191 const1_rtx, const1_rtx,
6192 const0_rtx, accvec, tmp1, tmp2,
6193 GEN_INT (MACFLAG_NONE), accvec));
6197 case BFIN_BUILTIN_CPLX_SQU:
6198 arg0 = CALL_EXPR_ARG (exp, 0);
6199 op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
6200 accvec = gen_reg_rtx (V2PDImode);
6201 icode = CODE_FOR_flag_mulv2hi;
6202 tmp1 = gen_reg_rtx (V2HImode);
6203 tmp2 = gen_reg_rtx (V2HImode);
6206 || GET_MODE (target) != V2HImode
6207 || ! (*insn_data[icode].operand[0].predicate) (target, V2HImode))
6208 target = gen_reg_rtx (V2HImode);
6209 if (! register_operand (op0, GET_MODE (op0)))
6210 op0 = copy_to_mode_reg (GET_MODE (op0), op0);
6212 emit_insn (gen_flag_mulv2hi (tmp1, op0, op0, GEN_INT (MACFLAG_NONE)));
6214 emit_insn (gen_flag_mulhi_parts (gen_lowpart (HImode, tmp2), op0, op0,
6215 const0_rtx, const1_rtx,
6216 GEN_INT (MACFLAG_NONE)));
6218 emit_insn (gen_ssaddhi3_high_parts (target, tmp2, tmp2, tmp2, const0_rtx,
6220 emit_insn (gen_sssubhi3_low_parts (target, target, tmp1, tmp1,
6221 const0_rtx, const1_rtx));
6229 for (i = 0, d = bdesc_2arg; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
6230 if (d->code == fcode)
6231 return bfin_expand_binop_builtin (d->icode, exp, target,
6234 for (i = 0, d = bdesc_1arg; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
6235 if (d->code == fcode)
6236 return bfin_expand_unop_builtin (d->icode, exp, target);
6241 #undef TARGET_INIT_BUILTINS
6242 #define TARGET_INIT_BUILTINS bfin_init_builtins
6244 #undef TARGET_EXPAND_BUILTIN
6245 #define TARGET_EXPAND_BUILTIN bfin_expand_builtin
6247 #undef TARGET_ASM_GLOBALIZE_LABEL
6248 #define TARGET_ASM_GLOBALIZE_LABEL bfin_globalize_label
6250 #undef TARGET_ASM_FILE_START
6251 #define TARGET_ASM_FILE_START output_file_start
6253 #undef TARGET_ATTRIBUTE_TABLE
6254 #define TARGET_ATTRIBUTE_TABLE bfin_attribute_table
6256 #undef TARGET_COMP_TYPE_ATTRIBUTES
6257 #define TARGET_COMP_TYPE_ATTRIBUTES bfin_comp_type_attributes
6259 #undef TARGET_RTX_COSTS
6260 #define TARGET_RTX_COSTS bfin_rtx_costs
6262 #undef TARGET_ADDRESS_COST
6263 #define TARGET_ADDRESS_COST bfin_address_cost
6265 #undef TARGET_ASM_INTEGER
6266 #define TARGET_ASM_INTEGER bfin_assemble_integer
6268 #undef TARGET_MACHINE_DEPENDENT_REORG
6269 #define TARGET_MACHINE_DEPENDENT_REORG bfin_reorg
6271 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
6272 #define TARGET_FUNCTION_OK_FOR_SIBCALL bfin_function_ok_for_sibcall
6274 #undef TARGET_ASM_OUTPUT_MI_THUNK
6275 #define TARGET_ASM_OUTPUT_MI_THUNK bfin_output_mi_thunk
6276 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
6277 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true
6279 #undef TARGET_SCHED_ADJUST_COST
6280 #define TARGET_SCHED_ADJUST_COST bfin_adjust_cost
6282 #undef TARGET_SCHED_ISSUE_RATE
6283 #define TARGET_SCHED_ISSUE_RATE bfin_issue_rate
6285 #undef TARGET_PROMOTE_PROTOTYPES
6286 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
6287 #undef TARGET_PROMOTE_FUNCTION_ARGS
6288 #define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_const_tree_true
6289 #undef TARGET_PROMOTE_FUNCTION_RETURN
6290 #define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_const_tree_true
6292 #undef TARGET_ARG_PARTIAL_BYTES
6293 #define TARGET_ARG_PARTIAL_BYTES bfin_arg_partial_bytes
6295 #undef TARGET_PASS_BY_REFERENCE
6296 #define TARGET_PASS_BY_REFERENCE bfin_pass_by_reference
6298 #undef TARGET_SETUP_INCOMING_VARARGS
6299 #define TARGET_SETUP_INCOMING_VARARGS setup_incoming_varargs
6301 #undef TARGET_STRUCT_VALUE_RTX
6302 #define TARGET_STRUCT_VALUE_RTX bfin_struct_value_rtx
6304 #undef TARGET_VECTOR_MODE_SUPPORTED_P
6305 #define TARGET_VECTOR_MODE_SUPPORTED_P bfin_vector_mode_supported_p
6307 #undef TARGET_HANDLE_OPTION
6308 #define TARGET_HANDLE_OPTION bfin_handle_option
6310 #undef TARGET_DEFAULT_TARGET_FLAGS
6311 #define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
6313 #undef TARGET_SECONDARY_RELOAD
6314 #define TARGET_SECONDARY_RELOAD bfin_secondary_reload
6316 #undef TARGET_DELEGITIMIZE_ADDRESS
6317 #define TARGET_DELEGITIMIZE_ADDRESS bfin_delegitimize_address
6319 #undef TARGET_CANNOT_FORCE_CONST_MEM
6320 #define TARGET_CANNOT_FORCE_CONST_MEM bfin_cannot_force_const_mem
6322 #undef TARGET_RETURN_IN_MEMORY
6323 #define TARGET_RETURN_IN_MEMORY bfin_return_in_memory
6325 struct gcc_target targetm = TARGET_INITIALIZER;