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
;
67 /* Set if we create a memcpy pattern that uses loop registers. */
68 int has_loopreg_clobber
;
71 /* RTX for condition code flag register and RETS register */
72 extern GTY(()) rtx bfin_cc_rtx
;
73 extern GTY(()) rtx bfin_rets_rtx
;
74 rtx bfin_cc_rtx
, bfin_rets_rtx
;
76 int max_arg_registers
= 0;
78 /* Arrays used when emitting register names. */
79 const char *short_reg_names
[] = SHORT_REGISTER_NAMES
;
80 const char *high_reg_names
[] = HIGH_REGISTER_NAMES
;
81 const char *dregs_pair_names
[] = DREGS_PAIR_NAMES
;
82 const char *byte_reg_names
[] = BYTE_REGISTER_NAMES
;
84 static int arg_regs
[] = FUNCTION_ARG_REGISTERS
;
85 static int ret_regs
[] = FUNCTION_RETURN_REGISTERS
;
87 /* Nonzero if -mshared-library-id was given. */
88 static int bfin_lib_id_given
;
90 /* Nonzero if -fschedule-insns2 was given. We override it and
91 call the scheduler ourselves during reorg. */
92 static int bfin_flag_schedule_insns2
;
94 /* Determines whether we run variable tracking in machine dependent
96 static int bfin_flag_var_tracking
;
99 bfin_cpu_t bfin_cpu_type
= BFIN_CPU_UNKNOWN
;
101 /* -msi-revision support. There are three special values:
102 -1 -msi-revision=none.
103 0xffff -msi-revision=any. */
104 int bfin_si_revision
;
106 /* The workarounds enabled */
107 unsigned int bfin_workarounds
= 0;
114 unsigned int workarounds
;
117 struct bfin_cpu bfin_cpus
[] =
119 {"bf512", BFIN_CPU_BF512
, 0x0000,
120 WA_SPECULATIVE_LOADS
| WA_05000074
},
122 {"bf514", BFIN_CPU_BF514
, 0x0000,
123 WA_SPECULATIVE_LOADS
| WA_05000074
},
125 {"bf516", BFIN_CPU_BF516
, 0x0000,
126 WA_SPECULATIVE_LOADS
| WA_05000074
},
128 {"bf518", BFIN_CPU_BF518
, 0x0000,
129 WA_SPECULATIVE_LOADS
| WA_05000074
},
131 {"bf522", BFIN_CPU_BF522
, 0x0002,
132 WA_SPECULATIVE_LOADS
| WA_05000074
},
133 {"bf522", BFIN_CPU_BF522
, 0x0001,
134 WA_SPECULATIVE_LOADS
| WA_RETS
| WA_05000074
},
135 {"bf522", BFIN_CPU_BF522
, 0x0000,
136 WA_SPECULATIVE_LOADS
| WA_RETS
| WA_05000074
},
138 {"bf523", BFIN_CPU_BF523
, 0x0002,
139 WA_SPECULATIVE_LOADS
| WA_05000074
},
140 {"bf523", BFIN_CPU_BF523
, 0x0001,
141 WA_SPECULATIVE_LOADS
| WA_RETS
| WA_05000074
},
142 {"bf523", BFIN_CPU_BF523
, 0x0000,
143 WA_SPECULATIVE_LOADS
| WA_RETS
| WA_05000074
},
145 {"bf524", BFIN_CPU_BF524
, 0x0002,
146 WA_SPECULATIVE_LOADS
| WA_05000074
},
147 {"bf524", BFIN_CPU_BF524
, 0x0001,
148 WA_SPECULATIVE_LOADS
| WA_RETS
| WA_05000074
},
149 {"bf524", BFIN_CPU_BF524
, 0x0000,
150 WA_SPECULATIVE_LOADS
| WA_RETS
| WA_05000074
},
152 {"bf525", BFIN_CPU_BF525
, 0x0002,
153 WA_SPECULATIVE_LOADS
| WA_05000074
},
154 {"bf525", BFIN_CPU_BF525
, 0x0001,
155 WA_SPECULATIVE_LOADS
| WA_RETS
| WA_05000074
},
156 {"bf525", BFIN_CPU_BF525
, 0x0000,
157 WA_SPECULATIVE_LOADS
| WA_RETS
| WA_05000074
},
159 {"bf526", BFIN_CPU_BF526
, 0x0002,
160 WA_SPECULATIVE_LOADS
| WA_05000074
},
161 {"bf526", BFIN_CPU_BF526
, 0x0001,
162 WA_SPECULATIVE_LOADS
| WA_RETS
| WA_05000074
},
163 {"bf526", BFIN_CPU_BF526
, 0x0000,
164 WA_SPECULATIVE_LOADS
| WA_RETS
| WA_05000074
},
166 {"bf527", BFIN_CPU_BF527
, 0x0002,
167 WA_SPECULATIVE_LOADS
| WA_05000074
},
168 {"bf527", BFIN_CPU_BF527
, 0x0001,
169 WA_SPECULATIVE_LOADS
| WA_RETS
| WA_05000074
},
170 {"bf527", BFIN_CPU_BF527
, 0x0000,
171 WA_SPECULATIVE_LOADS
| WA_RETS
| WA_05000074
},
173 {"bf531", BFIN_CPU_BF531
, 0x0006,
174 WA_SPECULATIVE_LOADS
| WA_LOAD_LCREGS
| WA_05000074
},
175 {"bf531", BFIN_CPU_BF531
, 0x0005,
176 WA_SPECULATIVE_LOADS
| WA_RETS
| WA_05000283
| WA_05000315
177 | WA_LOAD_LCREGS
| WA_05000074
},
178 {"bf531", BFIN_CPU_BF531
, 0x0004,
179 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
| WA_RETS
180 | 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
187 {"bf532", BFIN_CPU_BF532
, 0x0006,
188 WA_SPECULATIVE_LOADS
| WA_LOAD_LCREGS
| WA_05000074
},
189 {"bf532", BFIN_CPU_BF532
, 0x0005,
190 WA_SPECULATIVE_LOADS
| WA_RETS
| WA_05000283
| WA_05000315
191 | WA_LOAD_LCREGS
| WA_05000074
},
192 {"bf532", BFIN_CPU_BF532
, 0x0004,
193 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
| WA_RETS
194 | WA_05000283
| WA_05000257
| WA_05000315
| WA_LOAD_LCREGS
196 {"bf532", BFIN_CPU_BF532
, 0x0003,
197 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
| WA_RETS
198 | WA_05000283
| WA_05000257
| WA_05000315
| WA_LOAD_LCREGS
201 {"bf533", BFIN_CPU_BF533
, 0x0006,
202 WA_SPECULATIVE_LOADS
| WA_LOAD_LCREGS
| WA_05000074
},
203 {"bf533", BFIN_CPU_BF533
, 0x0005,
204 WA_SPECULATIVE_LOADS
| WA_RETS
| WA_05000283
| WA_05000315
205 | WA_LOAD_LCREGS
| WA_05000074
},
206 {"bf533", BFIN_CPU_BF533
, 0x0004,
207 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
| WA_RETS
208 | WA_05000283
| WA_05000257
| WA_05000315
| WA_LOAD_LCREGS
210 {"bf533", BFIN_CPU_BF533
, 0x0003,
211 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
| WA_RETS
212 | WA_05000283
| WA_05000257
| WA_05000315
| WA_LOAD_LCREGS
215 {"bf534", BFIN_CPU_BF534
, 0x0003,
216 WA_SPECULATIVE_LOADS
| WA_RETS
| WA_LOAD_LCREGS
| WA_05000074
},
217 {"bf534", BFIN_CPU_BF534
, 0x0002,
218 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
| WA_RETS
219 | WA_05000283
| WA_05000257
| WA_05000315
| WA_LOAD_LCREGS
221 {"bf534", BFIN_CPU_BF534
, 0x0001,
222 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
| WA_RETS
223 | WA_05000283
| WA_05000257
| WA_05000315
| WA_LOAD_LCREGS
226 {"bf536", BFIN_CPU_BF536
, 0x0003,
227 WA_SPECULATIVE_LOADS
| WA_RETS
| WA_LOAD_LCREGS
| WA_05000074
},
228 {"bf536", BFIN_CPU_BF536
, 0x0002,
229 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
| WA_RETS
230 | WA_05000283
| WA_05000257
| WA_05000315
| WA_LOAD_LCREGS
232 {"bf536", BFIN_CPU_BF536
, 0x0001,
233 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
| WA_RETS
234 | WA_05000283
| WA_05000257
| WA_05000315
| WA_LOAD_LCREGS
237 {"bf537", BFIN_CPU_BF537
, 0x0003,
238 WA_SPECULATIVE_LOADS
| WA_RETS
| WA_LOAD_LCREGS
| WA_05000074
},
239 {"bf537", BFIN_CPU_BF537
, 0x0002,
240 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
| WA_RETS
241 | WA_05000283
| WA_05000257
| WA_05000315
| WA_LOAD_LCREGS
243 {"bf537", BFIN_CPU_BF537
, 0x0001,
244 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
| WA_RETS
245 | WA_05000283
| WA_05000257
| WA_05000315
| WA_LOAD_LCREGS
248 {"bf538", BFIN_CPU_BF538
, 0x0005,
249 WA_SPECULATIVE_LOADS
| WA_LOAD_LCREGS
| WA_05000074
},
250 {"bf538", BFIN_CPU_BF538
, 0x0004,
251 WA_SPECULATIVE_LOADS
| WA_RETS
| WA_LOAD_LCREGS
| WA_05000074
},
252 {"bf538", BFIN_CPU_BF538
, 0x0003,
253 WA_SPECULATIVE_LOADS
| WA_RETS
254 | WA_05000283
| WA_05000315
| WA_LOAD_LCREGS
| WA_05000074
},
255 {"bf538", BFIN_CPU_BF538
, 0x0002,
256 WA_SPECULATIVE_LOADS
| WA_RETS
257 | WA_05000283
| WA_05000257
| WA_05000315
| WA_LOAD_LCREGS
260 {"bf539", BFIN_CPU_BF539
, 0x0005,
261 WA_SPECULATIVE_LOADS
| WA_LOAD_LCREGS
| WA_05000074
},
262 {"bf539", BFIN_CPU_BF539
, 0x0004,
263 WA_SPECULATIVE_LOADS
| WA_RETS
| WA_LOAD_LCREGS
| WA_05000074
},
264 {"bf539", BFIN_CPU_BF539
, 0x0003,
265 WA_SPECULATIVE_LOADS
| WA_RETS
266 | WA_05000283
| WA_05000315
| WA_LOAD_LCREGS
| WA_05000074
},
267 {"bf539", BFIN_CPU_BF539
, 0x0002,
268 WA_SPECULATIVE_LOADS
| WA_RETS
269 | WA_05000283
| WA_05000257
| WA_05000315
| WA_LOAD_LCREGS
272 {"bf542m", BFIN_CPU_BF542M
, 0x0003,
273 WA_SPECULATIVE_LOADS
| WA_INDIRECT_CALLS
| WA_05000074
},
275 {"bf542", BFIN_CPU_BF542
, 0x0002,
276 WA_SPECULATIVE_LOADS
| WA_INDIRECT_CALLS
| WA_05000074
},
277 {"bf542", BFIN_CPU_BF542
, 0x0001,
278 WA_SPECULATIVE_LOADS
| WA_RETS
| WA_INDIRECT_CALLS
| WA_05000074
},
279 {"bf542", BFIN_CPU_BF542
, 0x0000,
280 WA_SPECULATIVE_LOADS
| WA_RETS
| WA_INDIRECT_CALLS
| WA_LOAD_LCREGS
283 {"bf544m", BFIN_CPU_BF544M
, 0x0003,
284 WA_SPECULATIVE_LOADS
| WA_INDIRECT_CALLS
| WA_05000074
},
286 {"bf544", BFIN_CPU_BF544
, 0x0002,
287 WA_SPECULATIVE_LOADS
| WA_INDIRECT_CALLS
| WA_05000074
},
288 {"bf544", BFIN_CPU_BF544
, 0x0001,
289 WA_SPECULATIVE_LOADS
| WA_RETS
| WA_INDIRECT_CALLS
| WA_05000074
},
290 {"bf544", BFIN_CPU_BF544
, 0x0000,
291 WA_SPECULATIVE_LOADS
| WA_RETS
| WA_INDIRECT_CALLS
| WA_LOAD_LCREGS
294 {"bf547m", BFIN_CPU_BF547M
, 0x0003,
295 WA_SPECULATIVE_LOADS
| WA_INDIRECT_CALLS
| WA_05000074
},
297 {"bf547", BFIN_CPU_BF547
, 0x0002,
298 WA_SPECULATIVE_LOADS
| WA_INDIRECT_CALLS
| WA_05000074
},
299 {"bf547", BFIN_CPU_BF547
, 0x0001,
300 WA_SPECULATIVE_LOADS
| WA_RETS
| WA_INDIRECT_CALLS
| WA_05000074
},
301 {"bf547", BFIN_CPU_BF547
, 0x0000,
302 WA_SPECULATIVE_LOADS
| WA_RETS
| WA_INDIRECT_CALLS
| WA_LOAD_LCREGS
305 {"bf548m", BFIN_CPU_BF548M
, 0x0003,
306 WA_SPECULATIVE_LOADS
| WA_INDIRECT_CALLS
| WA_05000074
},
308 {"bf548", BFIN_CPU_BF548
, 0x0002,
309 WA_SPECULATIVE_LOADS
| WA_INDIRECT_CALLS
| WA_05000074
},
310 {"bf548", BFIN_CPU_BF548
, 0x0001,
311 WA_SPECULATIVE_LOADS
| WA_RETS
| WA_INDIRECT_CALLS
| WA_05000074
},
312 {"bf548", BFIN_CPU_BF548
, 0x0000,
313 WA_SPECULATIVE_LOADS
| WA_RETS
| WA_INDIRECT_CALLS
| WA_LOAD_LCREGS
316 {"bf549m", BFIN_CPU_BF549M
, 0x0003,
317 WA_SPECULATIVE_LOADS
| WA_INDIRECT_CALLS
| WA_05000074
},
319 {"bf549", BFIN_CPU_BF549
, 0x0002,
320 WA_SPECULATIVE_LOADS
| WA_INDIRECT_CALLS
| WA_05000074
},
321 {"bf549", BFIN_CPU_BF549
, 0x0001,
322 WA_SPECULATIVE_LOADS
| WA_RETS
| WA_INDIRECT_CALLS
| WA_05000074
},
323 {"bf549", BFIN_CPU_BF549
, 0x0000,
324 WA_SPECULATIVE_LOADS
| WA_RETS
| WA_INDIRECT_CALLS
| WA_LOAD_LCREGS
327 {"bf561", BFIN_CPU_BF561
, 0x0005, WA_RETS
328 | WA_05000283
| WA_05000315
| WA_LOAD_LCREGS
| WA_05000074
},
329 {"bf561", BFIN_CPU_BF561
, 0x0003,
330 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
| WA_RETS
331 | WA_05000283
| WA_05000257
| WA_05000315
| WA_LOAD_LCREGS
333 {"bf561", BFIN_CPU_BF561
, 0x0002,
334 WA_SPECULATIVE_LOADS
| WA_SPECULATIVE_SYNCS
| WA_RETS
335 | WA_05000283
| WA_05000257
| WA_05000315
| WA_LOAD_LCREGS
341 int splitting_for_sched
, splitting_loops
;
344 bfin_globalize_label (FILE *stream
, const char *name
)
346 fputs (".global ", stream
);
347 assemble_name (stream
, name
);
353 output_file_start (void)
355 FILE *file
= asm_out_file
;
358 /* Variable tracking should be run after all optimizations which change order
359 of insns. It also needs a valid CFG. This can't be done in
360 override_options, because flag_var_tracking is finalized after
362 bfin_flag_var_tracking
= flag_var_tracking
;
363 flag_var_tracking
= 0;
365 fprintf (file
, ".file \"%s\";\n", input_filename
);
367 for (i
= 0; arg_regs
[i
] >= 0; i
++)
369 max_arg_registers
= i
; /* how many arg reg used */
372 /* Called early in the compilation to conditionally modify
373 fixed_regs/call_used_regs. */
376 conditional_register_usage (void)
378 /* initialize condition code flag register rtx */
379 bfin_cc_rtx
= gen_rtx_REG (BImode
, REG_CC
);
380 bfin_rets_rtx
= gen_rtx_REG (Pmode
, REG_RETS
);
383 /* Examine machine-dependent attributes of function type FUNTYPE and return its
384 type. See the definition of E_FUNKIND. */
387 funkind (const_tree funtype
)
389 tree attrs
= TYPE_ATTRIBUTES (funtype
);
390 if (lookup_attribute ("interrupt_handler", attrs
))
391 return INTERRUPT_HANDLER
;
392 else if (lookup_attribute ("exception_handler", attrs
))
393 return EXCPT_HANDLER
;
394 else if (lookup_attribute ("nmi_handler", attrs
))
400 /* Legitimize PIC addresses. If the address is already position-independent,
401 we return ORIG. Newly generated position-independent addresses go into a
402 reg. This is REG if nonzero, otherwise we allocate register(s) as
403 necessary. PICREG is the register holding the pointer to the PIC offset
407 legitimize_pic_address (rtx orig
, rtx reg
, rtx picreg
)
412 if (GET_CODE (addr
) == SYMBOL_REF
|| GET_CODE (addr
) == LABEL_REF
)
417 if (TARGET_ID_SHARED_LIBRARY
)
418 unspec
= UNSPEC_MOVE_PIC
;
419 else if (GET_CODE (addr
) == SYMBOL_REF
420 && SYMBOL_REF_FUNCTION_P (addr
))
421 unspec
= UNSPEC_FUNCDESC_GOT17M4
;
423 unspec
= UNSPEC_MOVE_FDPIC
;
427 gcc_assert (can_create_pseudo_p ());
428 reg
= gen_reg_rtx (Pmode
);
431 tmp
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, addr
), unspec
);
432 new_rtx
= gen_const_mem (Pmode
, gen_rtx_PLUS (Pmode
, picreg
, tmp
));
434 emit_move_insn (reg
, new_rtx
);
435 if (picreg
== pic_offset_table_rtx
)
436 crtl
->uses_pic_offset_table
= 1;
440 else if (GET_CODE (addr
) == CONST
|| GET_CODE (addr
) == PLUS
)
444 if (GET_CODE (addr
) == CONST
)
446 addr
= XEXP (addr
, 0);
447 gcc_assert (GET_CODE (addr
) == PLUS
);
450 if (XEXP (addr
, 0) == picreg
)
455 gcc_assert (can_create_pseudo_p ());
456 reg
= gen_reg_rtx (Pmode
);
459 base
= legitimize_pic_address (XEXP (addr
, 0), reg
, picreg
);
460 addr
= legitimize_pic_address (XEXP (addr
, 1),
461 base
== reg
? NULL_RTX
: reg
,
464 if (GET_CODE (addr
) == CONST_INT
)
466 gcc_assert (! reload_in_progress
&& ! reload_completed
);
467 addr
= force_reg (Pmode
, addr
);
470 if (GET_CODE (addr
) == PLUS
&& CONSTANT_P (XEXP (addr
, 1)))
472 base
= gen_rtx_PLUS (Pmode
, base
, XEXP (addr
, 0));
473 addr
= XEXP (addr
, 1);
476 return gen_rtx_PLUS (Pmode
, base
, addr
);
482 /* Stack frame layout. */
484 /* For a given REGNO, determine whether it must be saved in the function
485 prologue. IS_INTHANDLER specifies whether we're generating a normal
486 prologue or an interrupt/exception one. */
488 must_save_p (bool is_inthandler
, unsigned regno
)
490 if (D_REGNO_P (regno
))
492 bool is_eh_return_reg
= false;
493 if (crtl
->calls_eh_return
)
498 unsigned test
= EH_RETURN_DATA_REGNO (j
);
499 if (test
== INVALID_REGNUM
)
502 is_eh_return_reg
= true;
506 return (is_eh_return_reg
507 || (df_regs_ever_live_p (regno
)
508 && !fixed_regs
[regno
]
509 && (is_inthandler
|| !call_used_regs
[regno
])));
511 else if (P_REGNO_P (regno
))
513 return ((df_regs_ever_live_p (regno
)
514 && !fixed_regs
[regno
]
515 && (is_inthandler
|| !call_used_regs
[regno
]))
517 && (ENABLE_WA_05000283
|| ENABLE_WA_05000315
)
520 && regno
== PIC_OFFSET_TABLE_REGNUM
521 && (crtl
->uses_pic_offset_table
522 || (TARGET_ID_SHARED_LIBRARY
&& !current_function_is_leaf
))));
525 return ((is_inthandler
|| !call_used_regs
[regno
])
526 && (df_regs_ever_live_p (regno
)
527 || (!leaf_function_p () && call_used_regs
[regno
])));
531 /* Compute the number of DREGS to save with a push_multiple operation.
532 This could include registers that aren't modified in the function,
533 since push_multiple only takes a range of registers.
534 If IS_INTHANDLER, then everything that is live must be saved, even
535 if normally call-clobbered.
536 If CONSECUTIVE, return the number of registers we can save in one
537 instruction with a push/pop multiple instruction. */
540 n_dregs_to_save (bool is_inthandler
, bool consecutive
)
545 for (i
= REG_R7
+ 1; i
-- != REG_R0
;)
547 if (must_save_p (is_inthandler
, i
))
549 else if (consecutive
)
555 /* Like n_dregs_to_save, but compute number of PREGS to save. */
558 n_pregs_to_save (bool is_inthandler
, bool consecutive
)
563 for (i
= REG_P5
+ 1; i
-- != REG_P0
;)
564 if (must_save_p (is_inthandler
, i
))
566 else if (consecutive
)
571 /* Determine if we are going to save the frame pointer in the prologue. */
574 must_save_fp_p (void)
576 return df_regs_ever_live_p (REG_FP
);
579 /* Determine if we are going to save the RETS register. */
581 must_save_rets_p (void)
583 return df_regs_ever_live_p (REG_RETS
);
587 stack_frame_needed_p (void)
589 /* EH return puts a new return address into the frame using an
590 address relative to the frame pointer. */
591 if (crtl
->calls_eh_return
)
593 return frame_pointer_needed
;
596 /* Emit code to save registers in the prologue. SAVEALL is nonzero if we
597 must save all registers; this is used for interrupt handlers.
598 SPREG contains (reg:SI REG_SP). IS_INTHANDLER is true if we're doing
599 this for an interrupt (or exception) handler. */
602 expand_prologue_reg_save (rtx spreg
, int saveall
, bool is_inthandler
)
604 rtx predec1
= gen_rtx_PRE_DEC (SImode
, spreg
);
605 rtx predec
= gen_rtx_MEM (SImode
, predec1
);
606 int ndregs
= saveall
? 8 : n_dregs_to_save (is_inthandler
, false);
607 int npregs
= saveall
? 6 : n_pregs_to_save (is_inthandler
, false);
608 int ndregs_consec
= saveall
? 8 : n_dregs_to_save (is_inthandler
, true);
609 int npregs_consec
= saveall
? 6 : n_pregs_to_save (is_inthandler
, true);
611 int total_consec
= ndregs_consec
+ npregs_consec
;
614 if (saveall
|| is_inthandler
)
616 rtx insn
= emit_move_insn (predec
, gen_rtx_REG (SImode
, REG_ASTAT
));
618 RTX_FRAME_RELATED_P (insn
) = 1;
619 for (dregno
= REG_LT0
; dregno
<= REG_LB1
; dregno
++)
620 if (! current_function_is_leaf
621 || cfun
->machine
->has_hardware_loops
622 || cfun
->machine
->has_loopreg_clobber
623 || (ENABLE_WA_05000257
624 && (dregno
== REG_LC0
|| dregno
== REG_LC1
)))
626 insn
= emit_move_insn (predec
, gen_rtx_REG (SImode
, dregno
));
627 RTX_FRAME_RELATED_P (insn
) = 1;
631 if (total_consec
!= 0)
634 rtx val
= GEN_INT (-total_consec
* 4);
635 rtx pat
= gen_rtx_PARALLEL (VOIDmode
, rtvec_alloc (total_consec
+ 2));
637 XVECEXP (pat
, 0, 0) = gen_rtx_UNSPEC (VOIDmode
, gen_rtvec (1, val
),
638 UNSPEC_PUSH_MULTIPLE
);
639 XVECEXP (pat
, 0, total_consec
+ 1) = gen_rtx_SET (VOIDmode
, spreg
,
643 RTX_FRAME_RELATED_P (XVECEXP (pat
, 0, total_consec
+ 1)) = 1;
644 d_to_save
= ndregs_consec
;
645 dregno
= REG_R7
+ 1 - ndregs_consec
;
646 pregno
= REG_P5
+ 1 - npregs_consec
;
647 for (i
= 0; i
< total_consec
; i
++)
649 rtx memref
= gen_rtx_MEM (word_mode
,
650 gen_rtx_PLUS (Pmode
, spreg
,
651 GEN_INT (- i
* 4 - 4)));
655 subpat
= gen_rtx_SET (VOIDmode
, memref
, gen_rtx_REG (word_mode
,
661 subpat
= gen_rtx_SET (VOIDmode
, memref
, gen_rtx_REG (word_mode
,
664 XVECEXP (pat
, 0, i
+ 1) = subpat
;
665 RTX_FRAME_RELATED_P (subpat
) = 1;
667 insn
= emit_insn (pat
);
668 RTX_FRAME_RELATED_P (insn
) = 1;
671 for (dregno
= REG_R0
; ndregs
!= ndregs_consec
; dregno
++)
673 if (must_save_p (is_inthandler
, dregno
))
675 rtx insn
= emit_move_insn (predec
, gen_rtx_REG (word_mode
, dregno
));
676 RTX_FRAME_RELATED_P (insn
) = 1;
680 for (pregno
= REG_P0
; npregs
!= npregs_consec
; pregno
++)
682 if (must_save_p (is_inthandler
, pregno
))
684 rtx insn
= emit_move_insn (predec
, gen_rtx_REG (word_mode
, pregno
));
685 RTX_FRAME_RELATED_P (insn
) = 1;
689 for (i
= REG_P7
+ 1; i
< REG_CC
; i
++)
692 && (df_regs_ever_live_p (i
)
693 || (!leaf_function_p () && call_used_regs
[i
]))))
696 if (i
== REG_A0
|| i
== REG_A1
)
697 insn
= emit_move_insn (gen_rtx_MEM (PDImode
, predec1
),
698 gen_rtx_REG (PDImode
, i
));
700 insn
= emit_move_insn (predec
, gen_rtx_REG (SImode
, i
));
701 RTX_FRAME_RELATED_P (insn
) = 1;
705 /* Emit code to restore registers in the epilogue. SAVEALL is nonzero if we
706 must save all registers; this is used for interrupt handlers.
707 SPREG contains (reg:SI REG_SP). IS_INTHANDLER is true if we're doing
708 this for an interrupt (or exception) handler. */
711 expand_epilogue_reg_restore (rtx spreg
, bool saveall
, bool is_inthandler
)
713 rtx postinc1
= gen_rtx_POST_INC (SImode
, spreg
);
714 rtx postinc
= gen_rtx_MEM (SImode
, postinc1
);
716 int ndregs
= saveall
? 8 : n_dregs_to_save (is_inthandler
, false);
717 int npregs
= saveall
? 6 : n_pregs_to_save (is_inthandler
, false);
718 int ndregs_consec
= saveall
? 8 : n_dregs_to_save (is_inthandler
, true);
719 int npregs_consec
= saveall
? 6 : n_pregs_to_save (is_inthandler
, true);
720 int total_consec
= ndregs_consec
+ npregs_consec
;
724 /* A slightly crude technique to stop flow from trying to delete "dead"
726 MEM_VOLATILE_P (postinc
) = 1;
728 for (i
= REG_CC
- 1; i
> REG_P7
; i
--)
731 && (df_regs_ever_live_p (i
)
732 || (!leaf_function_p () && call_used_regs
[i
]))))
734 if (i
== REG_A0
|| i
== REG_A1
)
736 rtx mem
= gen_rtx_MEM (PDImode
, postinc1
);
737 MEM_VOLATILE_P (mem
) = 1;
738 emit_move_insn (gen_rtx_REG (PDImode
, i
), mem
);
741 emit_move_insn (gen_rtx_REG (SImode
, i
), postinc
);
744 regno
= REG_P5
- npregs_consec
;
745 for (; npregs
!= npregs_consec
; regno
--)
747 if (must_save_p (is_inthandler
, regno
))
749 emit_move_insn (gen_rtx_REG (word_mode
, regno
), postinc
);
753 regno
= REG_R7
- ndregs_consec
;
754 for (; ndregs
!= ndregs_consec
; regno
--)
756 if (must_save_p (is_inthandler
, regno
))
758 emit_move_insn (gen_rtx_REG (word_mode
, regno
), postinc
);
763 if (total_consec
!= 0)
765 rtx pat
= gen_rtx_PARALLEL (VOIDmode
, rtvec_alloc (total_consec
+ 1));
767 = gen_rtx_SET (VOIDmode
, spreg
,
768 gen_rtx_PLUS (Pmode
, spreg
,
769 GEN_INT (total_consec
* 4)));
771 if (npregs_consec
> 0)
776 for (i
= 0; i
< total_consec
; i
++)
779 ? gen_rtx_PLUS (Pmode
, spreg
, GEN_INT (i
* 4))
781 rtx memref
= gen_rtx_MEM (word_mode
, addr
);
784 XVECEXP (pat
, 0, i
+ 1)
785 = gen_rtx_SET (VOIDmode
, gen_rtx_REG (word_mode
, regno
), memref
);
787 if (npregs_consec
> 0)
789 if (--npregs_consec
== 0)
794 insn
= emit_insn (pat
);
795 RTX_FRAME_RELATED_P (insn
) = 1;
797 if (saveall
|| is_inthandler
)
799 for (regno
= REG_LB1
; regno
>= REG_LT0
; regno
--)
800 if (! current_function_is_leaf
801 || cfun
->machine
->has_hardware_loops
802 || cfun
->machine
->has_loopreg_clobber
803 || (ENABLE_WA_05000257
&& (regno
== REG_LC0
|| regno
== REG_LC1
)))
804 emit_move_insn (gen_rtx_REG (SImode
, regno
), postinc
);
806 emit_move_insn (gen_rtx_REG (SImode
, REG_ASTAT
), postinc
);
810 /* Perform any needed actions needed for a function that is receiving a
811 variable number of arguments.
815 MODE and TYPE are the mode and type of the current parameter.
817 PRETEND_SIZE is a variable that should be set to the amount of stack
818 that must be pushed by the prolog to pretend that our caller pushed
821 Normally, this macro will push all remaining incoming registers on the
822 stack and set PRETEND_SIZE to the length of the registers pushed.
825 - VDSP C compiler manual (our ABI) says that a variable args function
826 should save the R0, R1 and R2 registers in the stack.
827 - The caller will always leave space on the stack for the
828 arguments that are passed in registers, so we dont have
829 to leave any extra space.
830 - now, the vastart pointer can access all arguments from the stack. */
833 setup_incoming_varargs (CUMULATIVE_ARGS
*cum
,
834 enum machine_mode mode ATTRIBUTE_UNUSED
,
835 tree type ATTRIBUTE_UNUSED
, int *pretend_size
,
844 /* The move for named arguments will be generated automatically by the
845 compiler. We need to generate the move rtx for the unnamed arguments
846 if they are in the first 3 words. We assume at least 1 named argument
847 exists, so we never generate [ARGP] = R0 here. */
849 for (i
= cum
->words
+ 1; i
< max_arg_registers
; i
++)
851 mem
= gen_rtx_MEM (Pmode
,
852 plus_constant (arg_pointer_rtx
, (i
* UNITS_PER_WORD
)));
853 emit_move_insn (mem
, gen_rtx_REG (Pmode
, i
));
859 /* Value should be nonzero if functions must have frame pointers.
860 Zero means the frame pointer need not be set up (and parms may
861 be accessed via the stack pointer) in functions that seem suitable. */
864 bfin_frame_pointer_required (void)
866 e_funkind fkind
= funkind (TREE_TYPE (current_function_decl
));
868 if (fkind
!= SUBROUTINE
)
871 /* We turn on -fomit-frame-pointer if -momit-leaf-frame-pointer is used,
872 so we have to override it for non-leaf functions. */
873 if (TARGET_OMIT_LEAF_FRAME_POINTER
&& ! current_function_is_leaf
)
879 /* Return the number of registers pushed during the prologue. */
882 n_regs_saved_by_prologue (void)
884 e_funkind fkind
= funkind (TREE_TYPE (current_function_decl
));
885 bool is_inthandler
= fkind
!= SUBROUTINE
;
886 tree attrs
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
887 bool all
= (lookup_attribute ("saveall", attrs
) != NULL_TREE
888 || (is_inthandler
&& !current_function_is_leaf
));
889 int ndregs
= all
? 8 : n_dregs_to_save (is_inthandler
, false);
890 int npregs
= all
? 6 : n_pregs_to_save (is_inthandler
, false);
891 int n
= ndregs
+ npregs
;
894 if (all
|| stack_frame_needed_p ())
898 if (must_save_fp_p ())
900 if (must_save_rets_p ())
904 if (fkind
!= SUBROUTINE
|| all
)
906 /* Increment once for ASTAT. */
908 if (! current_function_is_leaf
909 || cfun
->machine
->has_hardware_loops
910 || cfun
->machine
->has_loopreg_clobber
)
916 if (fkind
!= SUBROUTINE
)
919 if (lookup_attribute ("nesting", attrs
))
923 for (i
= REG_P7
+ 1; i
< REG_CC
; i
++)
925 || (fkind
!= SUBROUTINE
926 && (df_regs_ever_live_p (i
)
927 || (!leaf_function_p () && call_used_regs
[i
]))))
928 n
+= i
== REG_A0
|| i
== REG_A1
? 2 : 1;
933 /* Given FROM and TO register numbers, say whether this elimination is
934 allowed. Frame pointer elimination is automatically handled.
936 All other eliminations are valid. */
939 bfin_can_eliminate (const int from ATTRIBUTE_UNUSED
, const int to
)
941 return (to
== STACK_POINTER_REGNUM
? ! frame_pointer_needed
: true);
944 /* Return the offset between two registers, one to be eliminated, and the other
945 its replacement, at the start of a routine. */
948 bfin_initial_elimination_offset (int from
, int to
)
950 HOST_WIDE_INT offset
= 0;
952 if (from
== ARG_POINTER_REGNUM
)
953 offset
= n_regs_saved_by_prologue () * 4;
955 if (to
== STACK_POINTER_REGNUM
)
957 if (crtl
->outgoing_args_size
>= FIXED_STACK_AREA
)
958 offset
+= crtl
->outgoing_args_size
;
959 else if (crtl
->outgoing_args_size
)
960 offset
+= FIXED_STACK_AREA
;
962 offset
+= get_frame_size ();
968 /* Emit code to load a constant CONSTANT into register REG; setting
969 RTX_FRAME_RELATED_P on all insns we generate if RELATED is true.
970 Make sure that the insns we generate need not be split. */
973 frame_related_constant_load (rtx reg
, HOST_WIDE_INT constant
, bool related
)
976 rtx cst
= GEN_INT (constant
);
978 if (constant
>= -32768 && constant
< 65536)
979 insn
= emit_move_insn (reg
, cst
);
982 /* We don't call split_load_immediate here, since dwarf2out.c can get
983 confused about some of the more clever sequences it can generate. */
984 insn
= emit_insn (gen_movsi_high (reg
, cst
));
986 RTX_FRAME_RELATED_P (insn
) = 1;
987 insn
= emit_insn (gen_movsi_low (reg
, reg
, cst
));
990 RTX_FRAME_RELATED_P (insn
) = 1;
993 /* Generate efficient code to add a value to a P register.
994 Set RTX_FRAME_RELATED_P on the generated insns if FRAME is nonzero.
995 EPILOGUE_P is zero if this function is called for prologue,
996 otherwise it's nonzero. And it's less than zero if this is for
1000 add_to_reg (rtx reg
, HOST_WIDE_INT value
, int frame
, int epilogue_p
)
1005 /* Choose whether to use a sequence using a temporary register, or
1006 a sequence with multiple adds. We can add a signed 7-bit value
1007 in one instruction. */
1008 if (value
> 120 || value
< -120)
1016 /* For prologue or normal epilogue, P1 can be safely used
1017 as the temporary register. For sibcall epilogue, we try to find
1018 a call used P register, which will be restored in epilogue.
1019 If we cannot find such a P register, we have to use one I register
1022 if (epilogue_p
>= 0)
1023 tmpreg
= gen_rtx_REG (SImode
, REG_P1
);
1027 for (i
= REG_P0
; i
<= REG_P5
; i
++)
1028 if ((df_regs_ever_live_p (i
) && ! call_used_regs
[i
])
1030 && i
== PIC_OFFSET_TABLE_REGNUM
1031 && (crtl
->uses_pic_offset_table
1032 || (TARGET_ID_SHARED_LIBRARY
1033 && ! current_function_is_leaf
))))
1036 tmpreg
= gen_rtx_REG (SImode
, i
);
1039 tmpreg
= gen_rtx_REG (SImode
, REG_P1
);
1040 tmpreg2
= gen_rtx_REG (SImode
, REG_I0
);
1041 emit_move_insn (tmpreg2
, tmpreg
);
1046 frame_related_constant_load (tmpreg
, value
, TRUE
);
1048 insn
= emit_move_insn (tmpreg
, GEN_INT (value
));
1050 insn
= emit_insn (gen_addsi3 (reg
, reg
, tmpreg
));
1052 RTX_FRAME_RELATED_P (insn
) = 1;
1054 if (tmpreg2
!= NULL_RTX
)
1055 emit_move_insn (tmpreg
, tmpreg2
);
1065 else if (size
< -60)
1066 /* We could use -62, but that would leave the stack unaligned, so
1070 insn
= emit_insn (gen_addsi3 (reg
, reg
, GEN_INT (size
)));
1072 RTX_FRAME_RELATED_P (insn
) = 1;
1078 /* Generate a LINK insn for a frame sized FRAME_SIZE. If this constant
1079 is too large, generate a sequence of insns that has the same effect.
1080 SPREG contains (reg:SI REG_SP). */
1083 emit_link_insn (rtx spreg
, HOST_WIDE_INT frame_size
)
1085 HOST_WIDE_INT link_size
= frame_size
;
1089 if (link_size
> 262140)
1092 /* Use a LINK insn with as big a constant as possible, then subtract
1093 any remaining size from the SP. */
1094 insn
= emit_insn (gen_link (GEN_INT (-8 - link_size
)));
1095 RTX_FRAME_RELATED_P (insn
) = 1;
1097 for (i
= 0; i
< XVECLEN (PATTERN (insn
), 0); i
++)
1099 rtx set
= XVECEXP (PATTERN (insn
), 0, i
);
1100 gcc_assert (GET_CODE (set
) == SET
);
1101 RTX_FRAME_RELATED_P (set
) = 1;
1104 frame_size
-= link_size
;
1108 /* Must use a call-clobbered PREG that isn't the static chain. */
1109 rtx tmpreg
= gen_rtx_REG (Pmode
, REG_P1
);
1111 frame_related_constant_load (tmpreg
, -frame_size
, TRUE
);
1112 insn
= emit_insn (gen_addsi3 (spreg
, spreg
, tmpreg
));
1113 RTX_FRAME_RELATED_P (insn
) = 1;
1117 /* Return the number of bytes we must reserve for outgoing arguments
1118 in the current function's stack frame. */
1120 static HOST_WIDE_INT
1121 arg_area_size (void)
1123 if (crtl
->outgoing_args_size
)
1125 if (crtl
->outgoing_args_size
>= FIXED_STACK_AREA
)
1126 return crtl
->outgoing_args_size
;
1128 return FIXED_STACK_AREA
;
1133 /* Save RETS and FP, and allocate a stack frame. ALL is true if the
1134 function must save all its registers (true only for certain interrupt
1138 do_link (rtx spreg
, HOST_WIDE_INT frame_size
, bool all
)
1140 frame_size
+= arg_area_size ();
1143 || stack_frame_needed_p ()
1144 || (must_save_rets_p () && must_save_fp_p ()))
1145 emit_link_insn (spreg
, frame_size
);
1148 if (must_save_rets_p ())
1150 rtx pat
= gen_movsi (gen_rtx_MEM (Pmode
,
1151 gen_rtx_PRE_DEC (Pmode
, spreg
)),
1153 rtx insn
= emit_insn (pat
);
1154 RTX_FRAME_RELATED_P (insn
) = 1;
1156 if (must_save_fp_p ())
1158 rtx pat
= gen_movsi (gen_rtx_MEM (Pmode
,
1159 gen_rtx_PRE_DEC (Pmode
, spreg
)),
1160 gen_rtx_REG (Pmode
, REG_FP
));
1161 rtx insn
= emit_insn (pat
);
1162 RTX_FRAME_RELATED_P (insn
) = 1;
1164 add_to_reg (spreg
, -frame_size
, 1, 0);
1168 /* Like do_link, but used for epilogues to deallocate the stack frame.
1169 EPILOGUE_P is zero if this function is called for prologue,
1170 otherwise it's nonzero. And it's less than zero if this is for
1171 sibcall epilogue. */
1174 do_unlink (rtx spreg
, HOST_WIDE_INT frame_size
, bool all
, int epilogue_p
)
1176 frame_size
+= arg_area_size ();
1178 if (stack_frame_needed_p ())
1179 emit_insn (gen_unlink ());
1182 rtx postinc
= gen_rtx_MEM (Pmode
, gen_rtx_POST_INC (Pmode
, spreg
));
1184 add_to_reg (spreg
, frame_size
, 0, epilogue_p
);
1185 if (all
|| must_save_fp_p ())
1187 rtx fpreg
= gen_rtx_REG (Pmode
, REG_FP
);
1188 emit_move_insn (fpreg
, postinc
);
1191 if (all
|| must_save_rets_p ())
1193 emit_move_insn (bfin_rets_rtx
, postinc
);
1194 emit_use (bfin_rets_rtx
);
1199 /* Generate a prologue suitable for a function of kind FKIND. This is
1200 called for interrupt and exception handler prologues.
1201 SPREG contains (reg:SI REG_SP). */
1204 expand_interrupt_handler_prologue (rtx spreg
, e_funkind fkind
, bool all
)
1206 HOST_WIDE_INT frame_size
= get_frame_size ();
1207 rtx predec1
= gen_rtx_PRE_DEC (SImode
, spreg
);
1208 rtx predec
= gen_rtx_MEM (SImode
, predec1
);
1210 tree attrs
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
1211 tree kspisusp
= lookup_attribute ("kspisusp", attrs
);
1215 insn
= emit_move_insn (spreg
, gen_rtx_REG (Pmode
, REG_USP
));
1216 RTX_FRAME_RELATED_P (insn
) = 1;
1219 /* We need space on the stack in case we need to save the argument
1221 if (fkind
== EXCPT_HANDLER
)
1223 insn
= emit_insn (gen_addsi3 (spreg
, spreg
, GEN_INT (-12)));
1224 RTX_FRAME_RELATED_P (insn
) = 1;
1227 /* If we're calling other functions, they won't save their call-clobbered
1228 registers, so we must save everything here. */
1229 if (!current_function_is_leaf
)
1231 expand_prologue_reg_save (spreg
, all
, true);
1233 if (ENABLE_WA_05000283
|| ENABLE_WA_05000315
)
1235 rtx chipid
= GEN_INT (trunc_int_for_mode (0xFFC00014, SImode
));
1236 rtx p5reg
= gen_rtx_REG (Pmode
, REG_P5
);
1237 emit_insn (gen_movbi (bfin_cc_rtx
, const1_rtx
));
1238 emit_insn (gen_movsi_high (p5reg
, chipid
));
1239 emit_insn (gen_movsi_low (p5reg
, p5reg
, chipid
));
1240 emit_insn (gen_dummy_load (p5reg
, bfin_cc_rtx
));
1243 if (lookup_attribute ("nesting", attrs
))
1245 rtx srcreg
= gen_rtx_REG (Pmode
, ret_regs
[fkind
]);
1246 insn
= emit_move_insn (predec
, srcreg
);
1247 RTX_FRAME_RELATED_P (insn
) = 1;
1250 do_link (spreg
, frame_size
, all
);
1252 if (fkind
== EXCPT_HANDLER
)
1254 rtx r0reg
= gen_rtx_REG (SImode
, REG_R0
);
1255 rtx r1reg
= gen_rtx_REG (SImode
, REG_R1
);
1256 rtx r2reg
= gen_rtx_REG (SImode
, REG_R2
);
1259 insn
= emit_move_insn (r0reg
, gen_rtx_REG (SImode
, REG_SEQSTAT
));
1260 insn
= emit_insn (gen_ashrsi3 (r0reg
, r0reg
, GEN_INT (26)));
1261 insn
= emit_insn (gen_ashlsi3 (r0reg
, r0reg
, GEN_INT (26)));
1262 insn
= emit_move_insn (r1reg
, spreg
);
1263 insn
= emit_move_insn (r2reg
, gen_rtx_REG (Pmode
, REG_FP
));
1264 insn
= emit_insn (gen_addsi3 (r2reg
, r2reg
, GEN_INT (8)));
1268 /* Generate an epilogue suitable for a function of kind FKIND. This is
1269 called for interrupt and exception handler epilogues.
1270 SPREG contains (reg:SI REG_SP). */
1273 expand_interrupt_handler_epilogue (rtx spreg
, e_funkind fkind
, bool all
)
1275 tree attrs
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
1276 rtx postinc1
= gen_rtx_POST_INC (SImode
, spreg
);
1277 rtx postinc
= gen_rtx_MEM (SImode
, postinc1
);
1279 /* A slightly crude technique to stop flow from trying to delete "dead"
1281 MEM_VOLATILE_P (postinc
) = 1;
1283 do_unlink (spreg
, get_frame_size (), all
, 1);
1285 if (lookup_attribute ("nesting", attrs
))
1287 rtx srcreg
= gen_rtx_REG (Pmode
, ret_regs
[fkind
]);
1288 emit_move_insn (srcreg
, postinc
);
1291 /* If we're calling other functions, they won't save their call-clobbered
1292 registers, so we must save (and restore) everything here. */
1293 if (!current_function_is_leaf
)
1296 expand_epilogue_reg_restore (spreg
, all
, true);
1298 /* Deallocate any space we left on the stack in case we needed to save the
1299 argument registers. */
1300 if (fkind
== EXCPT_HANDLER
)
1301 emit_insn (gen_addsi3 (spreg
, spreg
, GEN_INT (12)));
1303 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode
, ret_regs
[fkind
])));
1306 /* Used while emitting the prologue to generate code to load the correct value
1307 into the PIC register, which is passed in DEST. */
1310 bfin_load_pic_reg (rtx dest
)
1312 struct cgraph_local_info
*i
= NULL
;
1315 i
= cgraph_local_info (current_function_decl
);
1317 /* Functions local to the translation unit don't need to reload the
1318 pic reg, since the caller always passes a usable one. */
1320 return pic_offset_table_rtx
;
1322 if (bfin_lib_id_given
)
1323 addr
= plus_constant (pic_offset_table_rtx
, -4 - bfin_library_id
* 4);
1325 addr
= gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
,
1326 gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, const0_rtx
),
1327 UNSPEC_LIBRARY_OFFSET
));
1328 insn
= emit_insn (gen_movsi (dest
, gen_rtx_MEM (Pmode
, addr
)));
1332 /* Generate RTL for the prologue of the current function. */
1335 bfin_expand_prologue (void)
1337 HOST_WIDE_INT frame_size
= get_frame_size ();
1338 rtx spreg
= gen_rtx_REG (Pmode
, REG_SP
);
1339 e_funkind fkind
= funkind (TREE_TYPE (current_function_decl
));
1340 rtx pic_reg_loaded
= NULL_RTX
;
1341 tree attrs
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
1342 bool all
= lookup_attribute ("saveall", attrs
) != NULL_TREE
;
1344 if (fkind
!= SUBROUTINE
)
1346 expand_interrupt_handler_prologue (spreg
, fkind
, all
);
1350 if (crtl
->limit_stack
1351 || (TARGET_STACK_CHECK_L1
1352 && !DECL_NO_LIMIT_STACK (current_function_decl
)))
1354 HOST_WIDE_INT offset
1355 = bfin_initial_elimination_offset (ARG_POINTER_REGNUM
,
1356 STACK_POINTER_REGNUM
);
1357 rtx lim
= crtl
->limit_stack
? stack_limit_rtx
: NULL_RTX
;
1358 rtx p2reg
= gen_rtx_REG (Pmode
, REG_P2
);
1362 emit_move_insn (p2reg
, gen_int_mode (0xFFB00000, SImode
));
1363 emit_move_insn (p2reg
, gen_rtx_MEM (Pmode
, p2reg
));
1366 if (GET_CODE (lim
) == SYMBOL_REF
)
1368 if (TARGET_ID_SHARED_LIBRARY
)
1370 rtx p1reg
= gen_rtx_REG (Pmode
, REG_P1
);
1372 pic_reg_loaded
= bfin_load_pic_reg (p2reg
);
1373 val
= legitimize_pic_address (stack_limit_rtx
, p1reg
,
1375 emit_move_insn (p1reg
, val
);
1376 frame_related_constant_load (p2reg
, offset
, FALSE
);
1377 emit_insn (gen_addsi3 (p2reg
, p2reg
, p1reg
));
1382 rtx limit
= plus_constant (lim
, offset
);
1383 emit_move_insn (p2reg
, limit
);
1390 emit_move_insn (p2reg
, lim
);
1391 add_to_reg (p2reg
, offset
, 0, 0);
1394 emit_insn (gen_compare_lt (bfin_cc_rtx
, spreg
, lim
));
1395 emit_insn (gen_trapifcc ());
1397 expand_prologue_reg_save (spreg
, all
, false);
1399 do_link (spreg
, frame_size
, all
);
1401 if (TARGET_ID_SHARED_LIBRARY
1403 && (crtl
->uses_pic_offset_table
1404 || !current_function_is_leaf
))
1405 bfin_load_pic_reg (pic_offset_table_rtx
);
1408 /* Generate RTL for the epilogue of the current function. NEED_RETURN is zero
1409 if this is for a sibcall. EH_RETURN is nonzero if we're expanding an
1410 eh_return pattern. SIBCALL_P is true if this is a sibcall epilogue,
1414 bfin_expand_epilogue (int need_return
, int eh_return
, bool sibcall_p
)
1416 rtx spreg
= gen_rtx_REG (Pmode
, REG_SP
);
1417 e_funkind fkind
= funkind (TREE_TYPE (current_function_decl
));
1418 int e
= sibcall_p
? -1 : 1;
1419 tree attrs
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
1420 bool all
= lookup_attribute ("saveall", attrs
) != NULL_TREE
;
1422 if (fkind
!= SUBROUTINE
)
1424 expand_interrupt_handler_epilogue (spreg
, fkind
, all
);
1428 do_unlink (spreg
, get_frame_size (), all
, e
);
1430 expand_epilogue_reg_restore (spreg
, all
, false);
1432 /* Omit the return insn if this is for a sibcall. */
1437 emit_insn (gen_addsi3 (spreg
, spreg
, gen_rtx_REG (Pmode
, REG_P2
)));
1439 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode
, REG_RETS
)));
1442 /* Return nonzero if register OLD_REG can be renamed to register NEW_REG. */
1445 bfin_hard_regno_rename_ok (unsigned int old_reg ATTRIBUTE_UNUSED
,
1446 unsigned int new_reg
)
1448 /* Interrupt functions can only use registers that have already been
1449 saved by the prologue, even if they would normally be
1452 if (funkind (TREE_TYPE (current_function_decl
)) != SUBROUTINE
1453 && !df_regs_ever_live_p (new_reg
))
1459 /* Return the value of the return address for the frame COUNT steps up
1460 from the current frame, after the prologue.
1461 We punt for everything but the current frame by returning const0_rtx. */
1464 bfin_return_addr_rtx (int count
)
1469 return get_hard_reg_initial_val (Pmode
, REG_RETS
);
1473 bfin_delegitimize_address (rtx orig_x
)
1477 if (GET_CODE (x
) != MEM
)
1481 if (GET_CODE (x
) == PLUS
1482 && GET_CODE (XEXP (x
, 1)) == UNSPEC
1483 && XINT (XEXP (x
, 1), 1) == UNSPEC_MOVE_PIC
1484 && GET_CODE (XEXP (x
, 0)) == REG
1485 && REGNO (XEXP (x
, 0)) == PIC_OFFSET_TABLE_REGNUM
)
1486 return XVECEXP (XEXP (x
, 1), 0, 0);
1491 /* This predicate is used to compute the length of a load/store insn.
1492 OP is a MEM rtx, we return nonzero if its addressing mode requires a
1493 32-bit instruction. */
1496 effective_address_32bit_p (rtx op
, enum machine_mode mode
)
1498 HOST_WIDE_INT offset
;
1500 mode
= GET_MODE (op
);
1503 if (GET_CODE (op
) != PLUS
)
1505 gcc_assert (REG_P (op
) || GET_CODE (op
) == POST_INC
1506 || GET_CODE (op
) == PRE_DEC
|| GET_CODE (op
) == POST_DEC
);
1510 if (GET_CODE (XEXP (op
, 1)) == UNSPEC
)
1513 offset
= INTVAL (XEXP (op
, 1));
1515 /* All byte loads use a 16-bit offset. */
1516 if (GET_MODE_SIZE (mode
) == 1)
1519 if (GET_MODE_SIZE (mode
) == 4)
1521 /* Frame pointer relative loads can use a negative offset, all others
1522 are restricted to a small positive one. */
1523 if (XEXP (op
, 0) == frame_pointer_rtx
)
1524 return offset
< -128 || offset
> 60;
1525 return offset
< 0 || offset
> 60;
1528 /* Must be HImode now. */
1529 return offset
< 0 || offset
> 30;
1532 /* Returns true if X is a memory reference using an I register. */
1534 bfin_dsp_memref_p (rtx x
)
1539 if (GET_CODE (x
) == POST_INC
|| GET_CODE (x
) == PRE_INC
1540 || GET_CODE (x
) == POST_DEC
|| GET_CODE (x
) == PRE_DEC
)
1545 /* Return cost of the memory address ADDR.
1546 All addressing modes are equally cheap on the Blackfin. */
1549 bfin_address_cost (rtx addr ATTRIBUTE_UNUSED
, bool speed ATTRIBUTE_UNUSED
)
1554 /* Subroutine of print_operand; used to print a memory reference X to FILE. */
1557 print_address_operand (FILE *file
, rtx x
)
1559 switch (GET_CODE (x
))
1562 output_address (XEXP (x
, 0));
1563 fprintf (file
, "+");
1564 output_address (XEXP (x
, 1));
1568 fprintf (file
, "--");
1569 output_address (XEXP (x
, 0));
1572 output_address (XEXP (x
, 0));
1573 fprintf (file
, "++");
1576 output_address (XEXP (x
, 0));
1577 fprintf (file
, "--");
1581 gcc_assert (GET_CODE (x
) != MEM
);
1582 print_operand (file
, x
, 0);
1587 /* Adding intp DImode support by Tony
1593 print_operand (FILE *file
, rtx x
, char code
)
1595 enum machine_mode mode
;
1599 if (GET_MODE (current_output_insn
) == SImode
)
1600 fprintf (file
, " ||");
1602 fprintf (file
, ";");
1606 mode
= GET_MODE (x
);
1611 switch (GET_CODE (x
))
1614 fprintf (file
, "e");
1617 fprintf (file
, "ne");
1620 fprintf (file
, "g");
1623 fprintf (file
, "l");
1626 fprintf (file
, "ge");
1629 fprintf (file
, "le");
1632 fprintf (file
, "g");
1635 fprintf (file
, "l");
1638 fprintf (file
, "ge");
1641 fprintf (file
, "le");
1644 output_operand_lossage ("invalid %%j value");
1648 case 'J': /* reverse logic */
1649 switch (GET_CODE(x
))
1652 fprintf (file
, "ne");
1655 fprintf (file
, "e");
1658 fprintf (file
, "le");
1661 fprintf (file
, "ge");
1664 fprintf (file
, "l");
1667 fprintf (file
, "g");
1670 fprintf (file
, "le");
1673 fprintf (file
, "ge");
1676 fprintf (file
, "l");
1679 fprintf (file
, "g");
1682 output_operand_lossage ("invalid %%J value");
1687 switch (GET_CODE (x
))
1693 fprintf (file
, "%s", short_reg_names
[REGNO (x
)]);
1695 output_operand_lossage ("invalid operand for code '%c'", code
);
1697 else if (code
== 'd')
1700 fprintf (file
, "%s", high_reg_names
[REGNO (x
)]);
1702 output_operand_lossage ("invalid operand for code '%c'", code
);
1704 else if (code
== 'w')
1706 if (REGNO (x
) == REG_A0
|| REGNO (x
) == REG_A1
)
1707 fprintf (file
, "%s.w", reg_names
[REGNO (x
)]);
1709 output_operand_lossage ("invalid operand for code '%c'", code
);
1711 else if (code
== 'x')
1713 if (REGNO (x
) == REG_A0
|| REGNO (x
) == REG_A1
)
1714 fprintf (file
, "%s.x", reg_names
[REGNO (x
)]);
1716 output_operand_lossage ("invalid operand for code '%c'", code
);
1718 else if (code
== 'v')
1720 if (REGNO (x
) == REG_A0
)
1721 fprintf (file
, "AV0");
1722 else if (REGNO (x
) == REG_A1
)
1723 fprintf (file
, "AV1");
1725 output_operand_lossage ("invalid operand for code '%c'", code
);
1727 else if (code
== 'D')
1729 if (D_REGNO_P (REGNO (x
)))
1730 fprintf (file
, "%s", dregs_pair_names
[REGNO (x
)]);
1732 output_operand_lossage ("invalid operand for code '%c'", code
);
1734 else if (code
== 'H')
1736 if ((mode
== DImode
|| mode
== DFmode
) && REG_P (x
))
1737 fprintf (file
, "%s", reg_names
[REGNO (x
) + 1]);
1739 output_operand_lossage ("invalid operand for code '%c'", code
);
1741 else if (code
== 'T')
1743 if (D_REGNO_P (REGNO (x
)))
1744 fprintf (file
, "%s", byte_reg_names
[REGNO (x
)]);
1746 output_operand_lossage ("invalid operand for code '%c'", code
);
1749 fprintf (file
, "%s", reg_names
[REGNO (x
)]);
1755 print_address_operand (file
, x
);
1767 fputs ("(FU)", file
);
1770 fputs ("(T)", file
);
1773 fputs ("(TFU)", file
);
1776 fputs ("(W32)", file
);
1779 fputs ("(IS)", file
);
1782 fputs ("(IU)", file
);
1785 fputs ("(IH)", file
);
1788 fputs ("(M)", file
);
1791 fputs ("(IS,M)", file
);
1794 fputs ("(ISS2)", file
);
1797 fputs ("(S2RND)", file
);
1804 else if (code
== 'b')
1806 if (INTVAL (x
) == 0)
1808 else if (INTVAL (x
) == 1)
1814 /* Moves to half registers with d or h modifiers always use unsigned
1816 else if (code
== 'd')
1817 x
= GEN_INT ((INTVAL (x
) >> 16) & 0xffff);
1818 else if (code
== 'h')
1819 x
= GEN_INT (INTVAL (x
) & 0xffff);
1820 else if (code
== 'N')
1821 x
= GEN_INT (-INTVAL (x
));
1822 else if (code
== 'X')
1823 x
= GEN_INT (exact_log2 (0xffffffff & INTVAL (x
)));
1824 else if (code
== 'Y')
1825 x
= GEN_INT (exact_log2 (0xffffffff & ~INTVAL (x
)));
1826 else if (code
== 'Z')
1827 /* Used for LINK insns. */
1828 x
= GEN_INT (-8 - INTVAL (x
));
1833 output_addr_const (file
, x
);
1837 output_operand_lossage ("invalid const_double operand");
1841 switch (XINT (x
, 1))
1843 case UNSPEC_MOVE_PIC
:
1844 output_addr_const (file
, XVECEXP (x
, 0, 0));
1845 fprintf (file
, "@GOT");
1848 case UNSPEC_MOVE_FDPIC
:
1849 output_addr_const (file
, XVECEXP (x
, 0, 0));
1850 fprintf (file
, "@GOT17M4");
1853 case UNSPEC_FUNCDESC_GOT17M4
:
1854 output_addr_const (file
, XVECEXP (x
, 0, 0));
1855 fprintf (file
, "@FUNCDESC_GOT17M4");
1858 case UNSPEC_LIBRARY_OFFSET
:
1859 fprintf (file
, "_current_shared_library_p5_offset_");
1868 output_addr_const (file
, x
);
1873 /* Argument support functions. */
1875 /* Initialize a variable CUM of type CUMULATIVE_ARGS
1876 for a call to a function whose data type is FNTYPE.
1877 For a library call, FNTYPE is 0.
1878 VDSP C Compiler manual, our ABI says that
1879 first 3 words of arguments will use R0, R1 and R2.
1883 init_cumulative_args (CUMULATIVE_ARGS
*cum
, tree fntype
,
1884 rtx libname ATTRIBUTE_UNUSED
)
1886 static CUMULATIVE_ARGS zero_cum
;
1890 /* Set up the number of registers to use for passing arguments. */
1892 cum
->nregs
= max_arg_registers
;
1893 cum
->arg_regs
= arg_regs
;
1895 cum
->call_cookie
= CALL_NORMAL
;
1896 /* Check for a longcall attribute. */
1897 if (fntype
&& lookup_attribute ("shortcall", TYPE_ATTRIBUTES (fntype
)))
1898 cum
->call_cookie
|= CALL_SHORT
;
1899 else if (fntype
&& lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype
)))
1900 cum
->call_cookie
|= CALL_LONG
;
1905 /* Update the data in CUM to advance over an argument
1906 of mode MODE and data type TYPE.
1907 (TYPE is null for libcalls where that information may not be available.) */
1910 function_arg_advance (CUMULATIVE_ARGS
*cum
, enum machine_mode mode
, tree type
,
1911 int named ATTRIBUTE_UNUSED
)
1913 int count
, bytes
, words
;
1915 bytes
= (mode
== BLKmode
) ? int_size_in_bytes (type
) : GET_MODE_SIZE (mode
);
1916 words
= (bytes
+ UNITS_PER_WORD
- 1) / UNITS_PER_WORD
;
1918 cum
->words
+= words
;
1919 cum
->nregs
-= words
;
1921 if (cum
->nregs
<= 0)
1924 cum
->arg_regs
= NULL
;
1928 for (count
= 1; count
<= words
; count
++)
1935 /* Define where to put the arguments to a function.
1936 Value is zero to push the argument on the stack,
1937 or a hard register in which to store the argument.
1939 MODE is the argument's machine mode.
1940 TYPE is the data type of the argument (as a tree).
1941 This is null for libcalls where that information may
1943 CUM is a variable of type CUMULATIVE_ARGS which gives info about
1944 the preceding args and about the function being called.
1945 NAMED is nonzero if this argument is a named parameter
1946 (otherwise it is an extra parameter matching an ellipsis). */
1949 function_arg (CUMULATIVE_ARGS
*cum
, enum machine_mode mode
, tree type
,
1950 int named ATTRIBUTE_UNUSED
)
1953 = (mode
== BLKmode
) ? int_size_in_bytes (type
) : GET_MODE_SIZE (mode
);
1955 if (mode
== VOIDmode
)
1956 /* Compute operand 2 of the call insn. */
1957 return GEN_INT (cum
->call_cookie
);
1963 return gen_rtx_REG (mode
, *(cum
->arg_regs
));
1968 /* For an arg passed partly in registers and partly in memory,
1969 this is the number of bytes passed in registers.
1970 For args passed entirely in registers or entirely in memory, zero.
1972 Refer VDSP C Compiler manual, our ABI.
1973 First 3 words are in registers. So, if an argument is larger
1974 than the registers available, it will span the register and
1978 bfin_arg_partial_bytes (CUMULATIVE_ARGS
*cum
, enum machine_mode mode
,
1979 tree type ATTRIBUTE_UNUSED
,
1980 bool named ATTRIBUTE_UNUSED
)
1983 = (mode
== BLKmode
) ? int_size_in_bytes (type
) : GET_MODE_SIZE (mode
);
1984 int bytes_left
= cum
->nregs
* UNITS_PER_WORD
;
1989 if (bytes_left
== 0)
1991 if (bytes
> bytes_left
)
1996 /* Variable sized types are passed by reference. */
1999 bfin_pass_by_reference (CUMULATIVE_ARGS
*cum ATTRIBUTE_UNUSED
,
2000 enum machine_mode mode ATTRIBUTE_UNUSED
,
2001 const_tree type
, bool named ATTRIBUTE_UNUSED
)
2003 return type
&& TREE_CODE (TYPE_SIZE (type
)) != INTEGER_CST
;
2006 /* Decide whether a type should be returned in memory (true)
2007 or in a register (false). This is called by the macro
2008 TARGET_RETURN_IN_MEMORY. */
2011 bfin_return_in_memory (const_tree type
, const_tree fntype ATTRIBUTE_UNUSED
)
2013 int size
= int_size_in_bytes (type
);
2014 return size
> 2 * UNITS_PER_WORD
|| size
== -1;
2017 /* Register in which address to store a structure value
2018 is passed to a function. */
2020 bfin_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED
,
2021 int incoming ATTRIBUTE_UNUSED
)
2023 return gen_rtx_REG (Pmode
, REG_P0
);
2026 /* Return true when register may be used to pass function parameters. */
2029 function_arg_regno_p (int n
)
2032 for (i
= 0; arg_regs
[i
] != -1; i
++)
2033 if (n
== arg_regs
[i
])
2038 /* Returns 1 if OP contains a symbol reference */
2041 symbolic_reference_mentioned_p (rtx op
)
2043 register const char *fmt
;
2046 if (GET_CODE (op
) == SYMBOL_REF
|| GET_CODE (op
) == LABEL_REF
)
2049 fmt
= GET_RTX_FORMAT (GET_CODE (op
));
2050 for (i
= GET_RTX_LENGTH (GET_CODE (op
)) - 1; i
>= 0; i
--)
2056 for (j
= XVECLEN (op
, i
) - 1; j
>= 0; j
--)
2057 if (symbolic_reference_mentioned_p (XVECEXP (op
, i
, j
)))
2061 else if (fmt
[i
] == 'e' && symbolic_reference_mentioned_p (XEXP (op
, i
)))
2068 /* Decide whether we can make a sibling call to a function. DECL is the
2069 declaration of the function being targeted by the call and EXP is the
2070 CALL_EXPR representing the call. */
2073 bfin_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED
,
2074 tree exp ATTRIBUTE_UNUSED
)
2076 struct cgraph_local_info
*this_func
, *called_func
;
2077 e_funkind fkind
= funkind (TREE_TYPE (current_function_decl
));
2078 if (fkind
!= SUBROUTINE
)
2080 if (!TARGET_ID_SHARED_LIBRARY
|| TARGET_SEP_DATA
)
2083 /* When compiling for ID shared libraries, can't sibcall a local function
2084 from a non-local function, because the local function thinks it does
2085 not need to reload P5 in the prologue, but the sibcall wil pop P5 in the
2086 sibcall epilogue, and we end up with the wrong value in P5. */
2089 /* Not enough information. */
2092 this_func
= cgraph_local_info (current_function_decl
);
2093 called_func
= cgraph_local_info (decl
);
2094 return !called_func
->local
|| this_func
->local
;
2097 /* Emit RTL insns to initialize the variable parts of a trampoline at
2098 TRAMP. FNADDR is an RTX for the address of the function's pure
2099 code. CXT is an RTX for the static chain value for the function. */
2102 initialize_trampoline (rtx tramp
, rtx fnaddr
, rtx cxt
)
2104 rtx t1
= copy_to_reg (fnaddr
);
2105 rtx t2
= copy_to_reg (cxt
);
2111 rtx a
= memory_address (Pmode
, plus_constant (tramp
, 8));
2112 addr
= memory_address (Pmode
, tramp
);
2113 emit_move_insn (gen_rtx_MEM (SImode
, addr
), a
);
2117 addr
= memory_address (Pmode
, plus_constant (tramp
, i
+ 2));
2118 emit_move_insn (gen_rtx_MEM (HImode
, addr
), gen_lowpart (HImode
, t1
));
2119 emit_insn (gen_ashrsi3 (t1
, t1
, GEN_INT (16)));
2120 addr
= memory_address (Pmode
, plus_constant (tramp
, i
+ 6));
2121 emit_move_insn (gen_rtx_MEM (HImode
, addr
), gen_lowpart (HImode
, t1
));
2123 addr
= memory_address (Pmode
, plus_constant (tramp
, i
+ 10));
2124 emit_move_insn (gen_rtx_MEM (HImode
, addr
), gen_lowpart (HImode
, t2
));
2125 emit_insn (gen_ashrsi3 (t2
, t2
, GEN_INT (16)));
2126 addr
= memory_address (Pmode
, plus_constant (tramp
, i
+ 14));
2127 emit_move_insn (gen_rtx_MEM (HImode
, addr
), gen_lowpart (HImode
, t2
));
2130 /* Emit insns to move operands[1] into operands[0]. */
2133 emit_pic_move (rtx
*operands
, enum machine_mode mode ATTRIBUTE_UNUSED
)
2135 rtx temp
= reload_in_progress
? operands
[0] : gen_reg_rtx (Pmode
);
2137 gcc_assert (!TARGET_FDPIC
|| !(reload_in_progress
|| reload_completed
));
2138 if (GET_CODE (operands
[0]) == MEM
&& SYMBOLIC_CONST (operands
[1]))
2139 operands
[1] = force_reg (SImode
, operands
[1]);
2141 operands
[1] = legitimize_pic_address (operands
[1], temp
,
2142 TARGET_FDPIC
? OUR_FDPIC_REG
2143 : pic_offset_table_rtx
);
2146 /* Expand a move operation in mode MODE. The operands are in OPERANDS.
2147 Returns true if no further code must be generated, false if the caller
2148 should generate an insn to move OPERANDS[1] to OPERANDS[0]. */
2151 expand_move (rtx
*operands
, enum machine_mode mode
)
2153 rtx op
= operands
[1];
2154 if ((TARGET_ID_SHARED_LIBRARY
|| TARGET_FDPIC
)
2155 && SYMBOLIC_CONST (op
))
2156 emit_pic_move (operands
, mode
);
2157 else if (mode
== SImode
&& GET_CODE (op
) == CONST
2158 && GET_CODE (XEXP (op
, 0)) == PLUS
2159 && GET_CODE (XEXP (XEXP (op
, 0), 0)) == SYMBOL_REF
2160 && !bfin_legitimate_constant_p (op
))
2162 rtx dest
= operands
[0];
2164 gcc_assert (!reload_in_progress
&& !reload_completed
);
2166 op0
= force_reg (mode
, XEXP (op
, 0));
2168 if (!insn_data
[CODE_FOR_addsi3
].operand
[2].predicate (op1
, mode
))
2169 op1
= force_reg (mode
, op1
);
2170 if (GET_CODE (dest
) == MEM
)
2171 dest
= gen_reg_rtx (mode
);
2172 emit_insn (gen_addsi3 (dest
, op0
, op1
));
2173 if (dest
== operands
[0])
2177 /* Don't generate memory->memory or constant->memory moves, go through a
2179 else if ((reload_in_progress
| reload_completed
) == 0
2180 && GET_CODE (operands
[0]) == MEM
2181 && GET_CODE (operands
[1]) != REG
)
2182 operands
[1] = force_reg (mode
, operands
[1]);
2186 /* Split one or more DImode RTL references into pairs of SImode
2187 references. The RTL can be REG, offsettable MEM, integer constant, or
2188 CONST_DOUBLE. "operands" is a pointer to an array of DImode RTL to
2189 split and "num" is its length. lo_half and hi_half are output arrays
2190 that parallel "operands". */
2193 split_di (rtx operands
[], int num
, rtx lo_half
[], rtx hi_half
[])
2197 rtx op
= operands
[num
];
2199 /* simplify_subreg refuse to split volatile memory addresses,
2200 but we still have to handle it. */
2201 if (GET_CODE (op
) == MEM
)
2203 lo_half
[num
] = adjust_address (op
, SImode
, 0);
2204 hi_half
[num
] = adjust_address (op
, SImode
, 4);
2208 lo_half
[num
] = simplify_gen_subreg (SImode
, op
,
2209 GET_MODE (op
) == VOIDmode
2210 ? DImode
: GET_MODE (op
), 0);
2211 hi_half
[num
] = simplify_gen_subreg (SImode
, op
,
2212 GET_MODE (op
) == VOIDmode
2213 ? DImode
: GET_MODE (op
), 4);
2219 bfin_longcall_p (rtx op
, int call_cookie
)
2221 gcc_assert (GET_CODE (op
) == SYMBOL_REF
);
2222 if (SYMBOL_REF_WEAK (op
))
2224 if (call_cookie
& CALL_SHORT
)
2226 if (call_cookie
& CALL_LONG
)
2228 if (TARGET_LONG_CALLS
)
2233 /* Expand a call instruction. FNADDR is the call target, RETVAL the return value.
2234 COOKIE is a CONST_INT holding the call_cookie prepared init_cumulative_args.
2235 SIBCALL is nonzero if this is a sibling call. */
2238 bfin_expand_call (rtx retval
, rtx fnaddr
, rtx callarg1
, rtx cookie
, int sibcall
)
2240 rtx use
= NULL
, call
;
2241 rtx callee
= XEXP (fnaddr
, 0);
2244 rtx picreg
= get_hard_reg_initial_val (SImode
, FDPIC_REGNO
);
2245 rtx retsreg
= gen_rtx_REG (Pmode
, REG_RETS
);
2248 /* In an untyped call, we can get NULL for operand 2. */
2249 if (cookie
== NULL_RTX
)
2250 cookie
= const0_rtx
;
2252 /* Static functions and indirect calls don't need the pic register. */
2253 if (!TARGET_FDPIC
&& flag_pic
2254 && GET_CODE (callee
) == SYMBOL_REF
2255 && !SYMBOL_REF_LOCAL_P (callee
))
2256 use_reg (&use
, pic_offset_table_rtx
);
2260 int caller_in_sram
, callee_in_sram
;
2262 /* 0 is not in sram, 1 is in L1 sram, 2 is in L2 sram. */
2263 caller_in_sram
= callee_in_sram
= 0;
2265 if (lookup_attribute ("l1_text",
2266 DECL_ATTRIBUTES (cfun
->decl
)) != NULL_TREE
)
2268 else if (lookup_attribute ("l2",
2269 DECL_ATTRIBUTES (cfun
->decl
)) != NULL_TREE
)
2272 if (GET_CODE (callee
) == SYMBOL_REF
2273 && SYMBOL_REF_DECL (callee
) && DECL_P (SYMBOL_REF_DECL (callee
)))
2275 if (lookup_attribute
2277 DECL_ATTRIBUTES (SYMBOL_REF_DECL (callee
))) != NULL_TREE
)
2279 else if (lookup_attribute
2281 DECL_ATTRIBUTES (SYMBOL_REF_DECL (callee
))) != NULL_TREE
)
2285 if (GET_CODE (callee
) != SYMBOL_REF
2286 || bfin_longcall_p (callee
, INTVAL (cookie
))
2287 || (GET_CODE (callee
) == SYMBOL_REF
2288 && !SYMBOL_REF_LOCAL_P (callee
)
2289 && TARGET_INLINE_PLT
)
2290 || caller_in_sram
!= callee_in_sram
2291 || (caller_in_sram
&& callee_in_sram
2292 && (GET_CODE (callee
) != SYMBOL_REF
2293 || !SYMBOL_REF_LOCAL_P (callee
))))
2296 if (! address_operand (addr
, Pmode
))
2297 addr
= force_reg (Pmode
, addr
);
2299 fnaddr
= gen_reg_rtx (SImode
);
2300 emit_insn (gen_load_funcdescsi (fnaddr
, addr
));
2301 fnaddr
= gen_rtx_MEM (Pmode
, fnaddr
);
2303 picreg
= gen_reg_rtx (SImode
);
2304 emit_insn (gen_load_funcdescsi (picreg
,
2305 plus_constant (addr
, 4)));
2310 else if ((!register_no_elim_operand (callee
, Pmode
)
2311 && GET_CODE (callee
) != SYMBOL_REF
)
2312 || (GET_CODE (callee
) == SYMBOL_REF
2313 && ((TARGET_ID_SHARED_LIBRARY
&& !TARGET_LEAF_ID_SHARED_LIBRARY
)
2314 || bfin_longcall_p (callee
, INTVAL (cookie
)))))
2316 callee
= copy_to_mode_reg (Pmode
, callee
);
2317 fnaddr
= gen_rtx_MEM (Pmode
, callee
);
2319 call
= gen_rtx_CALL (VOIDmode
, fnaddr
, callarg1
);
2322 call
= gen_rtx_SET (VOIDmode
, retval
, call
);
2324 pat
= gen_rtx_PARALLEL (VOIDmode
, rtvec_alloc (nelts
));
2326 XVECEXP (pat
, 0, n
++) = call
;
2328 XVECEXP (pat
, 0, n
++) = gen_rtx_USE (VOIDmode
, picreg
);
2329 XVECEXP (pat
, 0, n
++) = gen_rtx_USE (VOIDmode
, cookie
);
2331 XVECEXP (pat
, 0, n
++) = gen_rtx_RETURN (VOIDmode
);
2333 XVECEXP (pat
, 0, n
++) = gen_rtx_CLOBBER (VOIDmode
, retsreg
);
2334 call
= emit_call_insn (pat
);
2336 CALL_INSN_FUNCTION_USAGE (call
) = use
;
2339 /* Return 1 if hard register REGNO can hold a value of machine-mode MODE. */
2342 hard_regno_mode_ok (int regno
, enum machine_mode mode
)
2344 /* Allow only dregs to store value of mode HI or QI */
2345 enum reg_class rclass
= REGNO_REG_CLASS (regno
);
2350 if (mode
== V2HImode
)
2351 return D_REGNO_P (regno
);
2352 if (rclass
== CCREGS
)
2353 return mode
== BImode
;
2354 if (mode
== PDImode
|| mode
== V2PDImode
)
2355 return regno
== REG_A0
|| regno
== REG_A1
;
2357 /* Allow all normal 32-bit regs, except REG_M3, in case regclass ever comes
2358 up with a bad register class (such as ALL_REGS) for DImode. */
2360 return regno
< REG_M3
;
2363 && TEST_HARD_REG_BIT (reg_class_contents
[PROLOGUE_REGS
], regno
))
2366 return TEST_HARD_REG_BIT (reg_class_contents
[MOST_REGS
], regno
);
2369 /* Implements target hook vector_mode_supported_p. */
2372 bfin_vector_mode_supported_p (enum machine_mode mode
)
2374 return mode
== V2HImode
;
2377 /* Return the cost of moving data from a register in class CLASS1 to
2378 one in class CLASS2. A cost of 2 is the default. */
2381 bfin_register_move_cost (enum machine_mode mode
,
2382 enum reg_class class1
, enum reg_class class2
)
2384 /* These need secondary reloads, so they're more expensive. */
2385 if ((class1
== CCREGS
&& !reg_class_subset_p (class2
, DREGS
))
2386 || (class2
== CCREGS
&& !reg_class_subset_p (class1
, DREGS
)))
2389 /* If optimizing for size, always prefer reg-reg over reg-memory moves. */
2393 if (GET_MODE_CLASS (mode
) == MODE_INT
)
2395 /* Discourage trying to use the accumulators. */
2396 if (TEST_HARD_REG_BIT (reg_class_contents
[class1
], REG_A0
)
2397 || TEST_HARD_REG_BIT (reg_class_contents
[class1
], REG_A1
)
2398 || TEST_HARD_REG_BIT (reg_class_contents
[class2
], REG_A0
)
2399 || TEST_HARD_REG_BIT (reg_class_contents
[class2
], REG_A1
))
2405 /* Return the cost of moving data of mode M between a
2406 register and memory. A value of 2 is the default; this cost is
2407 relative to those in `REGISTER_MOVE_COST'.
2409 ??? In theory L1 memory has single-cycle latency. We should add a switch
2410 that tells the compiler whether we expect to use only L1 memory for the
2411 program; it'll make the costs more accurate. */
2414 bfin_memory_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED
,
2415 enum reg_class rclass
,
2416 int in ATTRIBUTE_UNUSED
)
2418 /* Make memory accesses slightly more expensive than any register-register
2419 move. Also, penalize non-DP registers, since they need secondary
2420 reloads to load and store. */
2421 if (! reg_class_subset_p (rclass
, DPREGS
))
2427 /* Inform reload about cases where moving X with a mode MODE to a register in
2428 RCLASS requires an extra scratch register. Return the class needed for the
2429 scratch register. */
2431 static enum reg_class
2432 bfin_secondary_reload (bool in_p
, rtx x
, enum reg_class rclass
,
2433 enum machine_mode mode
, secondary_reload_info
*sri
)
2435 /* If we have HImode or QImode, we can only use DREGS as secondary registers;
2436 in most other cases we can also use PREGS. */
2437 enum reg_class default_class
= GET_MODE_SIZE (mode
) >= 4 ? DPREGS
: DREGS
;
2438 enum reg_class x_class
= NO_REGS
;
2439 enum rtx_code code
= GET_CODE (x
);
2442 x
= SUBREG_REG (x
), code
= GET_CODE (x
);
2445 int regno
= REGNO (x
);
2446 if (regno
>= FIRST_PSEUDO_REGISTER
)
2447 regno
= reg_renumber
[regno
];
2452 x_class
= REGNO_REG_CLASS (regno
);
2455 /* We can be asked to reload (plus (FP) (large_constant)) into a DREG.
2456 This happens as a side effect of register elimination, and we need
2457 a scratch register to do it. */
2458 if (fp_plus_const_operand (x
, mode
))
2460 rtx op2
= XEXP (x
, 1);
2461 int large_constant_p
= ! satisfies_constraint_Ks7 (op2
);
2463 if (rclass
== PREGS
|| rclass
== PREGS_CLOBBERED
)
2465 /* If destination is a DREG, we can do this without a scratch register
2466 if the constant is valid for an add instruction. */
2467 if ((rclass
== DREGS
|| rclass
== DPREGS
)
2468 && ! large_constant_p
)
2470 /* Reloading to anything other than a DREG? Use a PREG scratch
2472 sri
->icode
= CODE_FOR_reload_insi
;
2476 /* Data can usually be moved freely between registers of most classes.
2477 AREGS are an exception; they can only move to or from another register
2478 in AREGS or one in DREGS. They can also be assigned the constant 0. */
2479 if (x_class
== AREGS
|| x_class
== EVEN_AREGS
|| x_class
== ODD_AREGS
)
2480 return (rclass
== DREGS
|| rclass
== AREGS
|| rclass
== EVEN_AREGS
2481 || rclass
== ODD_AREGS
2484 if (rclass
== AREGS
|| rclass
== EVEN_AREGS
|| rclass
== ODD_AREGS
)
2488 sri
->icode
= in_p
? CODE_FOR_reload_inpdi
: CODE_FOR_reload_outpdi
;
2492 if (x
!= const0_rtx
&& x_class
!= DREGS
)
2500 /* CCREGS can only be moved from/to DREGS. */
2501 if (rclass
== CCREGS
&& x_class
!= DREGS
)
2503 if (x_class
== CCREGS
&& rclass
!= DREGS
)
2506 /* All registers other than AREGS can load arbitrary constants. The only
2507 case that remains is MEM. */
2509 if (! reg_class_subset_p (rclass
, default_class
))
2510 return default_class
;
2515 /* Implement TARGET_HANDLE_OPTION. */
2518 bfin_handle_option (size_t code
, const char *arg
, int value
)
2522 case OPT_mshared_library_id_
:
2523 if (value
> MAX_LIBRARY_ID
)
2524 error ("-mshared-library-id=%s is not between 0 and %d",
2525 arg
, MAX_LIBRARY_ID
);
2526 bfin_lib_id_given
= 1;
2535 while ((p
= bfin_cpus
[i
].name
) != NULL
)
2537 if (strncmp (arg
, p
, strlen (p
)) == 0)
2544 error ("-mcpu=%s is not valid", arg
);
2548 bfin_cpu_type
= bfin_cpus
[i
].type
;
2550 q
= arg
+ strlen (p
);
2554 bfin_si_revision
= bfin_cpus
[i
].si_revision
;
2555 bfin_workarounds
|= bfin_cpus
[i
].workarounds
;
2557 else if (strcmp (q
, "-none") == 0)
2558 bfin_si_revision
= -1;
2559 else if (strcmp (q
, "-any") == 0)
2561 bfin_si_revision
= 0xffff;
2562 while (bfin_cpus
[i
].type
== bfin_cpu_type
)
2564 bfin_workarounds
|= bfin_cpus
[i
].workarounds
;
2570 unsigned int si_major
, si_minor
;
2573 rev_len
= strlen (q
);
2575 if (sscanf (q
, "-%u.%u%n", &si_major
, &si_minor
, &n
) != 2
2577 || si_major
> 0xff || si_minor
> 0xff)
2579 invalid_silicon_revision
:
2580 error ("-mcpu=%s has invalid silicon revision", arg
);
2584 bfin_si_revision
= (si_major
<< 8) | si_minor
;
2586 while (bfin_cpus
[i
].type
== bfin_cpu_type
2587 && bfin_cpus
[i
].si_revision
!= bfin_si_revision
)
2590 if (bfin_cpus
[i
].type
!= bfin_cpu_type
)
2591 goto invalid_silicon_revision
;
2593 bfin_workarounds
|= bfin_cpus
[i
].workarounds
;
2604 static struct machine_function
*
2605 bfin_init_machine_status (void)
2607 struct machine_function
*f
;
2609 f
= GGC_CNEW (struct machine_function
);
2614 /* Implement the macro OVERRIDE_OPTIONS. */
2617 override_options (void)
2619 /* If processor type is not specified, enable all workarounds. */
2620 if (bfin_cpu_type
== BFIN_CPU_UNKNOWN
)
2624 for (i
= 0; bfin_cpus
[i
].name
!= NULL
; i
++)
2625 bfin_workarounds
|= bfin_cpus
[i
].workarounds
;
2627 bfin_si_revision
= 0xffff;
2630 if (bfin_csync_anomaly
== 1)
2631 bfin_workarounds
|= WA_SPECULATIVE_SYNCS
;
2632 else if (bfin_csync_anomaly
== 0)
2633 bfin_workarounds
&= ~WA_SPECULATIVE_SYNCS
;
2635 if (bfin_specld_anomaly
== 1)
2636 bfin_workarounds
|= WA_SPECULATIVE_LOADS
;
2637 else if (bfin_specld_anomaly
== 0)
2638 bfin_workarounds
&= ~WA_SPECULATIVE_LOADS
;
2640 if (TARGET_OMIT_LEAF_FRAME_POINTER
)
2641 flag_omit_frame_pointer
= 1;
2643 /* Library identification */
2644 if (bfin_lib_id_given
&& ! TARGET_ID_SHARED_LIBRARY
)
2645 error ("-mshared-library-id= specified without -mid-shared-library");
2647 if (stack_limit_rtx
&& TARGET_STACK_CHECK_L1
)
2648 error ("Can't use multiple stack checking methods together.");
2650 if (TARGET_ID_SHARED_LIBRARY
&& TARGET_FDPIC
)
2651 error ("ID shared libraries and FD-PIC mode can't be used together.");
2653 /* Don't allow the user to specify -mid-shared-library and -msep-data
2654 together, as it makes little sense from a user's point of view... */
2655 if (TARGET_SEP_DATA
&& TARGET_ID_SHARED_LIBRARY
)
2656 error ("cannot specify both -msep-data and -mid-shared-library");
2657 /* ... internally, however, it's nearly the same. */
2658 if (TARGET_SEP_DATA
)
2659 target_flags
|= MASK_ID_SHARED_LIBRARY
| MASK_LEAF_ID_SHARED_LIBRARY
;
2661 if (TARGET_ID_SHARED_LIBRARY
&& flag_pic
== 0)
2664 /* There is no single unaligned SI op for PIC code. Sometimes we
2665 need to use ".4byte" and sometimes we need to use ".picptr".
2666 See bfin_assemble_integer for details. */
2668 targetm
.asm_out
.unaligned_op
.si
= 0;
2670 /* Silently turn off flag_pic if not doing FDPIC or ID shared libraries,
2671 since we don't support it and it'll just break. */
2672 if (flag_pic
&& !TARGET_FDPIC
&& !TARGET_ID_SHARED_LIBRARY
)
2675 if (TARGET_MULTICORE
&& bfin_cpu_type
!= BFIN_CPU_BF561
)
2676 error ("-mmulticore can only be used with BF561");
2678 if (TARGET_COREA
&& !TARGET_MULTICORE
)
2679 error ("-mcorea should be used with -mmulticore");
2681 if (TARGET_COREB
&& !TARGET_MULTICORE
)
2682 error ("-mcoreb should be used with -mmulticore");
2684 if (TARGET_COREA
&& TARGET_COREB
)
2685 error ("-mcorea and -mcoreb can't be used together");
2687 flag_schedule_insns
= 0;
2689 /* Passes after sched2 can break the helpful TImode annotations that
2690 haifa-sched puts on every insn. Just do scheduling in reorg. */
2691 bfin_flag_schedule_insns2
= flag_schedule_insns_after_reload
;
2692 flag_schedule_insns_after_reload
= 0;
2694 init_machine_status
= bfin_init_machine_status
;
2697 /* Return the destination address of BRANCH.
2698 We need to use this instead of get_attr_length, because the
2699 cbranch_with_nops pattern conservatively sets its length to 6, and
2700 we still prefer to use shorter sequences. */
2703 branch_dest (rtx branch
)
2707 rtx pat
= PATTERN (branch
);
2708 if (GET_CODE (pat
) == PARALLEL
)
2709 pat
= XVECEXP (pat
, 0, 0);
2710 dest
= SET_SRC (pat
);
2711 if (GET_CODE (dest
) == IF_THEN_ELSE
)
2712 dest
= XEXP (dest
, 1);
2713 dest
= XEXP (dest
, 0);
2714 dest_uid
= INSN_UID (dest
);
2715 return INSN_ADDRESSES (dest_uid
);
2718 /* Return nonzero if INSN is annotated with a REG_BR_PROB note that indicates
2719 it's a branch that's predicted taken. */
2722 cbranch_predicted_taken_p (rtx insn
)
2724 rtx x
= find_reg_note (insn
, REG_BR_PROB
, 0);
2728 int pred_val
= INTVAL (XEXP (x
, 0));
2730 return pred_val
>= REG_BR_PROB_BASE
/ 2;
2736 /* Templates for use by asm_conditional_branch. */
2738 static const char *ccbranch_templates
[][3] = {
2739 { "if !cc jump %3;", "if cc jump 4 (bp); jump.s %3;", "if cc jump 6 (bp); jump.l %3;" },
2740 { "if cc jump %3;", "if !cc jump 4 (bp); jump.s %3;", "if !cc jump 6 (bp); jump.l %3;" },
2741 { "if !cc jump %3 (bp);", "if cc jump 4; jump.s %3;", "if cc jump 6; jump.l %3;" },
2742 { "if cc jump %3 (bp);", "if !cc jump 4; jump.s %3;", "if !cc jump 6; jump.l %3;" },
2745 /* Output INSN, which is a conditional branch instruction with operands
2748 We deal with the various forms of conditional branches that can be generated
2749 by bfin_reorg to prevent the hardware from doing speculative loads, by
2750 - emitting a sufficient number of nops, if N_NOPS is nonzero, or
2751 - always emitting the branch as predicted taken, if PREDICT_TAKEN is true.
2752 Either of these is only necessary if the branch is short, otherwise the
2753 template we use ends in an unconditional jump which flushes the pipeline
2757 asm_conditional_branch (rtx insn
, rtx
*operands
, int n_nops
, int predict_taken
)
2759 int offset
= branch_dest (insn
) - INSN_ADDRESSES (INSN_UID (insn
));
2760 /* Note : offset for instructions like if cc jmp; jump.[sl] offset
2761 is to be taken from start of if cc rather than jump.
2762 Range for jump.s is (-4094, 4096) instead of (-4096, 4094)
2764 int len
= (offset
>= -1024 && offset
<= 1022 ? 0
2765 : offset
>= -4094 && offset
<= 4096 ? 1
2767 int bp
= predict_taken
&& len
== 0 ? 1 : cbranch_predicted_taken_p (insn
);
2768 int idx
= (bp
<< 1) | (GET_CODE (operands
[0]) == EQ
? BRF
: BRT
);
2769 output_asm_insn (ccbranch_templates
[idx
][len
], operands
);
2770 gcc_assert (n_nops
== 0 || !bp
);
2772 while (n_nops
-- > 0)
2773 output_asm_insn ("nop;", NULL
);
2776 /* Emit rtl for a comparison operation CMP in mode MODE. Operands have been
2777 stored in bfin_compare_op0 and bfin_compare_op1 already. */
2780 bfin_gen_compare (rtx cmp
, enum machine_mode mode ATTRIBUTE_UNUSED
)
2782 enum rtx_code code1
, code2
;
2783 rtx op0
= XEXP (cmp
, 0), op1
= XEXP (cmp
, 1);
2784 rtx tem
= bfin_cc_rtx
;
2785 enum rtx_code code
= GET_CODE (cmp
);
2787 /* If we have a BImode input, then we already have a compare result, and
2788 do not need to emit another comparison. */
2789 if (GET_MODE (op0
) == BImode
)
2791 gcc_assert ((code
== NE
|| code
== EQ
) && op1
== const0_rtx
);
2792 tem
= op0
, code2
= code
;
2797 /* bfin has these conditions */
2807 code1
= reverse_condition (code
);
2811 emit_insn (gen_rtx_SET (VOIDmode
, tem
,
2812 gen_rtx_fmt_ee (code1
, BImode
, op0
, op1
)));
2815 return gen_rtx_fmt_ee (code2
, BImode
, tem
, CONST0_RTX (BImode
));
2818 /* Return nonzero iff C has exactly one bit set if it is interpreted
2819 as a 32-bit constant. */
2822 log2constp (unsigned HOST_WIDE_INT c
)
2825 return c
!= 0 && (c
& (c
-1)) == 0;
2828 /* Returns the number of consecutive least significant zeros in the binary
2829 representation of *V.
2830 We modify *V to contain the original value arithmetically shifted right by
2831 the number of zeroes. */
2834 shiftr_zero (HOST_WIDE_INT
*v
)
2836 unsigned HOST_WIDE_INT tmp
= *v
;
2837 unsigned HOST_WIDE_INT sgn
;
2843 sgn
= tmp
& ((unsigned HOST_WIDE_INT
) 1 << (HOST_BITS_PER_WIDE_INT
- 1));
2844 while ((tmp
& 0x1) == 0 && n
<= 32)
2846 tmp
= (tmp
>> 1) | sgn
;
2853 /* After reload, split the load of an immediate constant. OPERANDS are the
2854 operands of the movsi_insn pattern which we are splitting. We return
2855 nonzero if we emitted a sequence to load the constant, zero if we emitted
2856 nothing because we want to use the splitter's default sequence. */
2859 split_load_immediate (rtx operands
[])
2861 HOST_WIDE_INT val
= INTVAL (operands
[1]);
2863 HOST_WIDE_INT shifted
= val
;
2864 HOST_WIDE_INT shifted_compl
= ~val
;
2865 int num_zero
= shiftr_zero (&shifted
);
2866 int num_compl_zero
= shiftr_zero (&shifted_compl
);
2867 unsigned int regno
= REGNO (operands
[0]);
2869 /* This case takes care of single-bit set/clear constants, which we could
2870 also implement with BITSET/BITCLR. */
2872 && shifted
>= -32768 && shifted
< 65536
2873 && (D_REGNO_P (regno
)
2874 || (regno
>= REG_P0
&& regno
<= REG_P7
&& num_zero
<= 2)))
2876 emit_insn (gen_movsi (operands
[0], GEN_INT (shifted
)));
2877 emit_insn (gen_ashlsi3 (operands
[0], operands
[0], GEN_INT (num_zero
)));
2882 tmp
|= -(tmp
& 0x8000);
2884 /* If high word has one bit set or clear, try to use a bit operation. */
2885 if (D_REGNO_P (regno
))
2887 if (log2constp (val
& 0xFFFF0000))
2889 emit_insn (gen_movsi (operands
[0], GEN_INT (val
& 0xFFFF)));
2890 emit_insn (gen_iorsi3 (operands
[0], operands
[0], GEN_INT (val
& 0xFFFF0000)));
2893 else if (log2constp (val
| 0xFFFF) && (val
& 0x8000) != 0)
2895 emit_insn (gen_movsi (operands
[0], GEN_INT (tmp
)));
2896 emit_insn (gen_andsi3 (operands
[0], operands
[0], GEN_INT (val
| 0xFFFF)));
2900 if (D_REGNO_P (regno
))
2902 if (tmp
>= -64 && tmp
<= 63)
2904 emit_insn (gen_movsi (operands
[0], GEN_INT (tmp
)));
2905 emit_insn (gen_movstricthi_high (operands
[0], GEN_INT (val
& -65536)));
2909 if ((val
& 0xFFFF0000) == 0)
2911 emit_insn (gen_movsi (operands
[0], const0_rtx
));
2912 emit_insn (gen_movsi_low (operands
[0], operands
[0], operands
[1]));
2916 if ((val
& 0xFFFF0000) == 0xFFFF0000)
2918 emit_insn (gen_movsi (operands
[0], constm1_rtx
));
2919 emit_insn (gen_movsi_low (operands
[0], operands
[0], operands
[1]));
2924 /* Need DREGs for the remaining case. */
2929 && num_compl_zero
&& shifted_compl
>= -64 && shifted_compl
<= 63)
2931 /* If optimizing for size, generate a sequence that has more instructions
2933 emit_insn (gen_movsi (operands
[0], GEN_INT (shifted_compl
)));
2934 emit_insn (gen_ashlsi3 (operands
[0], operands
[0],
2935 GEN_INT (num_compl_zero
)));
2936 emit_insn (gen_one_cmplsi2 (operands
[0], operands
[0]));
2942 /* Return true if the legitimate memory address for a memory operand of mode
2943 MODE. Return false if not. */
2946 bfin_valid_add (enum machine_mode mode
, HOST_WIDE_INT value
)
2948 unsigned HOST_WIDE_INT v
= value
> 0 ? value
: -value
;
2949 int sz
= GET_MODE_SIZE (mode
);
2950 int shift
= sz
== 1 ? 0 : sz
== 2 ? 1 : 2;
2951 /* The usual offsettable_memref machinery doesn't work so well for this
2952 port, so we deal with the problem here. */
2953 if (value
> 0 && sz
== 8)
2955 return (v
& ~(0x7fff << shift
)) == 0;
2959 bfin_valid_reg_p (unsigned int regno
, int strict
, enum machine_mode mode
,
2960 enum rtx_code outer_code
)
2963 return REGNO_OK_FOR_BASE_STRICT_P (regno
, mode
, outer_code
, SCRATCH
);
2965 return REGNO_OK_FOR_BASE_NONSTRICT_P (regno
, mode
, outer_code
, SCRATCH
);
2968 /* Recognize an RTL expression that is a valid memory address for an
2969 instruction. The MODE argument is the machine mode for the MEM expression
2970 that wants to use this address.
2972 Blackfin addressing modes are as follows:
2978 W [ Preg + uimm16m2 ]
2987 bfin_legitimate_address_p (enum machine_mode mode
, rtx x
, bool strict
)
2989 switch (GET_CODE (x
)) {
2991 if (bfin_valid_reg_p (REGNO (x
), strict
, mode
, MEM
))
2995 if (REG_P (XEXP (x
, 0))
2996 && bfin_valid_reg_p (REGNO (XEXP (x
, 0)), strict
, mode
, PLUS
)
2997 && ((GET_CODE (XEXP (x
, 1)) == UNSPEC
&& mode
== SImode
)
2998 || (GET_CODE (XEXP (x
, 1)) == CONST_INT
2999 && bfin_valid_add (mode
, INTVAL (XEXP (x
, 1))))))
3004 if (LEGITIMATE_MODE_FOR_AUTOINC_P (mode
)
3005 && REG_P (XEXP (x
, 0))
3006 && bfin_valid_reg_p (REGNO (XEXP (x
, 0)), strict
, mode
, POST_INC
))
3009 if (LEGITIMATE_MODE_FOR_AUTOINC_P (mode
)
3010 && XEXP (x
, 0) == stack_pointer_rtx
3011 && REG_P (XEXP (x
, 0))
3012 && bfin_valid_reg_p (REGNO (XEXP (x
, 0)), strict
, mode
, PRE_DEC
))
3021 /* Decide whether we can force certain constants to memory. If we
3022 decide we can't, the caller should be able to cope with it in
3026 bfin_cannot_force_const_mem (rtx x ATTRIBUTE_UNUSED
)
3028 /* We have only one class of non-legitimate constants, and our movsi
3029 expander knows how to handle them. Dropping these constants into the
3030 data section would only shift the problem - we'd still get relocs
3031 outside the object, in the data section rather than the text section. */
3035 /* Ensure that for any constant of the form symbol + offset, the offset
3036 remains within the object. Any other constants are ok.
3037 This ensures that flat binaries never have to deal with relocations
3038 crossing section boundaries. */
3041 bfin_legitimate_constant_p (rtx x
)
3044 HOST_WIDE_INT offset
;
3046 if (GET_CODE (x
) != CONST
)
3050 gcc_assert (GET_CODE (x
) == PLUS
);
3054 if (GET_CODE (sym
) != SYMBOL_REF
3055 || GET_CODE (x
) != CONST_INT
)
3057 offset
= INTVAL (x
);
3059 if (SYMBOL_REF_DECL (sym
) == 0)
3062 || offset
>= int_size_in_bytes (TREE_TYPE (SYMBOL_REF_DECL (sym
))))
3069 bfin_rtx_costs (rtx x
, int code
, int outer_code
, int *total
, bool speed
)
3071 int cost2
= COSTS_N_INSNS (1);
3077 if (outer_code
== SET
|| outer_code
== PLUS
)
3078 *total
= satisfies_constraint_Ks7 (x
) ? 0 : cost2
;
3079 else if (outer_code
== AND
)
3080 *total
= log2constp (~INTVAL (x
)) ? 0 : cost2
;
3081 else if (outer_code
== LE
|| outer_code
== LT
|| outer_code
== EQ
)
3082 *total
= (INTVAL (x
) >= -4 && INTVAL (x
) <= 3) ? 0 : cost2
;
3083 else if (outer_code
== LEU
|| outer_code
== LTU
)
3084 *total
= (INTVAL (x
) >= 0 && INTVAL (x
) <= 7) ? 0 : cost2
;
3085 else if (outer_code
== MULT
)
3086 *total
= (INTVAL (x
) == 2 || INTVAL (x
) == 4) ? 0 : cost2
;
3087 else if (outer_code
== ASHIFT
&& (INTVAL (x
) == 1 || INTVAL (x
) == 2))
3089 else if (outer_code
== ASHIFT
|| outer_code
== ASHIFTRT
3090 || outer_code
== LSHIFTRT
)
3091 *total
= (INTVAL (x
) >= 0 && INTVAL (x
) <= 31) ? 0 : cost2
;
3092 else if (outer_code
== IOR
|| outer_code
== XOR
)
3093 *total
= (INTVAL (x
) & (INTVAL (x
) - 1)) == 0 ? 0 : cost2
;
3102 *total
= COSTS_N_INSNS (2);
3108 if (GET_MODE (x
) == SImode
)
3110 if (GET_CODE (op0
) == MULT
3111 && GET_CODE (XEXP (op0
, 1)) == CONST_INT
)
3113 HOST_WIDE_INT val
= INTVAL (XEXP (op0
, 1));
3114 if (val
== 2 || val
== 4)
3117 *total
+= rtx_cost (XEXP (op0
, 0), outer_code
, speed
);
3118 *total
+= rtx_cost (op1
, outer_code
, speed
);
3123 if (GET_CODE (op0
) != REG
3124 && (GET_CODE (op0
) != SUBREG
|| GET_CODE (SUBREG_REG (op0
)) != REG
))
3125 *total
+= rtx_cost (op0
, SET
, speed
);
3126 #if 0 /* We'd like to do this for accuracy, but it biases the loop optimizer
3127 towards creating too many induction variables. */
3128 if (!reg_or_7bit_operand (op1
, SImode
))
3129 *total
+= rtx_cost (op1
, SET
, speed
);
3132 else if (GET_MODE (x
) == DImode
)
3135 if (GET_CODE (op1
) != CONST_INT
3136 || !satisfies_constraint_Ks7 (op1
))
3137 *total
+= rtx_cost (op1
, PLUS
, speed
);
3138 if (GET_CODE (op0
) != REG
3139 && (GET_CODE (op0
) != SUBREG
|| GET_CODE (SUBREG_REG (op0
)) != REG
))
3140 *total
+= rtx_cost (op0
, PLUS
, speed
);
3145 if (GET_MODE (x
) == DImode
)
3154 if (GET_MODE (x
) == DImode
)
3161 if (GET_CODE (op0
) != REG
3162 && (GET_CODE (op0
) != SUBREG
|| GET_CODE (SUBREG_REG (op0
)) != REG
))
3163 *total
+= rtx_cost (op0
, code
, speed
);
3173 /* Handle special cases of IOR: rotates, ALIGN insns, movstricthi_high. */
3176 if ((GET_CODE (op0
) == LSHIFTRT
&& GET_CODE (op1
) == ASHIFT
)
3177 || (GET_CODE (op0
) == ASHIFT
&& GET_CODE (op1
) == ZERO_EXTEND
)
3178 || (GET_CODE (op0
) == ASHIFT
&& GET_CODE (op1
) == LSHIFTRT
)
3179 || (GET_CODE (op0
) == AND
&& GET_CODE (op1
) == CONST_INT
))
3186 if (GET_CODE (op0
) != REG
3187 && (GET_CODE (op0
) != SUBREG
|| GET_CODE (SUBREG_REG (op0
)) != REG
))
3188 *total
+= rtx_cost (op0
, code
, speed
);
3190 if (GET_MODE (x
) == DImode
)
3196 if (GET_MODE (x
) != SImode
)
3201 if (! rhs_andsi3_operand (XEXP (x
, 1), SImode
))
3202 *total
+= rtx_cost (XEXP (x
, 1), code
, speed
);
3206 if (! regorlog2_operand (XEXP (x
, 1), SImode
))
3207 *total
+= rtx_cost (XEXP (x
, 1), code
, speed
);
3214 if (outer_code
== SET
3215 && XEXP (x
, 1) == const1_rtx
3216 && GET_CODE (XEXP (x
, 2)) == CONST_INT
)
3232 if (GET_CODE (op0
) == GET_CODE (op1
)
3233 && (GET_CODE (op0
) == ZERO_EXTEND
3234 || GET_CODE (op0
) == SIGN_EXTEND
))
3236 *total
= COSTS_N_INSNS (1);
3237 op0
= XEXP (op0
, 0);
3238 op1
= XEXP (op1
, 0);
3241 *total
= COSTS_N_INSNS (1);
3243 *total
= COSTS_N_INSNS (3);
3245 if (GET_CODE (op0
) != REG
3246 && (GET_CODE (op0
) != SUBREG
|| GET_CODE (SUBREG_REG (op0
)) != REG
))
3247 *total
+= rtx_cost (op0
, MULT
, speed
);
3248 if (GET_CODE (op1
) != REG
3249 && (GET_CODE (op1
) != SUBREG
|| GET_CODE (SUBREG_REG (op1
)) != REG
))
3250 *total
+= rtx_cost (op1
, MULT
, speed
);
3256 *total
= COSTS_N_INSNS (32);
3261 if (outer_code
== SET
)
3270 /* Used for communication between {push,pop}_multiple_operation (which
3271 we use not only as a predicate) and the corresponding output functions. */
3272 static int first_preg_to_save
, first_dreg_to_save
;
3273 static int n_regs_to_save
;
3276 push_multiple_operation (rtx op
, enum machine_mode mode ATTRIBUTE_UNUSED
)
3278 int lastdreg
= 8, lastpreg
= 6;
3281 first_preg_to_save
= lastpreg
;
3282 first_dreg_to_save
= lastdreg
;
3283 for (i
= 1, group
= 0; i
< XVECLEN (op
, 0) - 1; i
++)
3285 rtx t
= XVECEXP (op
, 0, i
);
3289 if (GET_CODE (t
) != SET
)
3293 dest
= SET_DEST (t
);
3294 if (GET_CODE (dest
) != MEM
|| ! REG_P (src
))
3296 dest
= XEXP (dest
, 0);
3297 if (GET_CODE (dest
) != PLUS
3298 || ! REG_P (XEXP (dest
, 0))
3299 || REGNO (XEXP (dest
, 0)) != REG_SP
3300 || GET_CODE (XEXP (dest
, 1)) != CONST_INT
3301 || INTVAL (XEXP (dest
, 1)) != -i
* 4)
3304 regno
= REGNO (src
);
3307 if (D_REGNO_P (regno
))
3310 first_dreg_to_save
= lastdreg
= regno
- REG_R0
;
3312 else if (regno
>= REG_P0
&& regno
<= REG_P7
)
3315 first_preg_to_save
= lastpreg
= regno
- REG_P0
;
3325 if (regno
>= REG_P0
&& regno
<= REG_P7
)
3328 first_preg_to_save
= lastpreg
= regno
- REG_P0
;
3330 else if (regno
!= REG_R0
+ lastdreg
+ 1)
3335 else if (group
== 2)
3337 if (regno
!= REG_P0
+ lastpreg
+ 1)
3342 n_regs_to_save
= 8 - first_dreg_to_save
+ 6 - first_preg_to_save
;
3347 pop_multiple_operation (rtx op
, enum machine_mode mode ATTRIBUTE_UNUSED
)
3349 int lastdreg
= 8, lastpreg
= 6;
3352 for (i
= 1, group
= 0; i
< XVECLEN (op
, 0); i
++)
3354 rtx t
= XVECEXP (op
, 0, i
);
3358 if (GET_CODE (t
) != SET
)
3362 dest
= SET_DEST (t
);
3363 if (GET_CODE (src
) != MEM
|| ! REG_P (dest
))
3365 src
= XEXP (src
, 0);
3369 if (! REG_P (src
) || REGNO (src
) != REG_SP
)
3372 else if (GET_CODE (src
) != PLUS
3373 || ! REG_P (XEXP (src
, 0))
3374 || REGNO (XEXP (src
, 0)) != REG_SP
3375 || GET_CODE (XEXP (src
, 1)) != CONST_INT
3376 || INTVAL (XEXP (src
, 1)) != (i
- 1) * 4)
3379 regno
= REGNO (dest
);
3382 if (regno
== REG_R7
)
3387 else if (regno
!= REG_P0
+ lastpreg
- 1)
3392 else if (group
== 1)
3394 if (regno
!= REG_R0
+ lastdreg
- 1)
3400 first_dreg_to_save
= lastdreg
;
3401 first_preg_to_save
= lastpreg
;
3402 n_regs_to_save
= 8 - first_dreg_to_save
+ 6 - first_preg_to_save
;
3406 /* Emit assembly code for one multi-register push described by INSN, with
3407 operands in OPERANDS. */
3410 output_push_multiple (rtx insn
, rtx
*operands
)
3415 /* Validate the insn again, and compute first_[dp]reg_to_save. */
3416 ok
= push_multiple_operation (PATTERN (insn
), VOIDmode
);
3419 if (first_dreg_to_save
== 8)
3420 sprintf (buf
, "[--sp] = ( p5:%d );\n", first_preg_to_save
);
3421 else if (first_preg_to_save
== 6)
3422 sprintf (buf
, "[--sp] = ( r7:%d );\n", first_dreg_to_save
);
3424 sprintf (buf
, "[--sp] = ( r7:%d, p5:%d );\n",
3425 first_dreg_to_save
, first_preg_to_save
);
3427 output_asm_insn (buf
, operands
);
3430 /* Emit assembly code for one multi-register pop described by INSN, with
3431 operands in OPERANDS. */
3434 output_pop_multiple (rtx insn
, rtx
*operands
)
3439 /* Validate the insn again, and compute first_[dp]reg_to_save. */
3440 ok
= pop_multiple_operation (PATTERN (insn
), VOIDmode
);
3443 if (first_dreg_to_save
== 8)
3444 sprintf (buf
, "( p5:%d ) = [sp++];\n", first_preg_to_save
);
3445 else if (first_preg_to_save
== 6)
3446 sprintf (buf
, "( r7:%d ) = [sp++];\n", first_dreg_to_save
);
3448 sprintf (buf
, "( r7:%d, p5:%d ) = [sp++];\n",
3449 first_dreg_to_save
, first_preg_to_save
);
3451 output_asm_insn (buf
, operands
);
3454 /* Adjust DST and SRC by OFFSET bytes, and generate one move in mode MODE. */
3457 single_move_for_movmem (rtx dst
, rtx src
, enum machine_mode mode
, HOST_WIDE_INT offset
)
3459 rtx scratch
= gen_reg_rtx (mode
);
3462 srcmem
= adjust_address_nv (src
, mode
, offset
);
3463 dstmem
= adjust_address_nv (dst
, mode
, offset
);
3464 emit_move_insn (scratch
, srcmem
);
3465 emit_move_insn (dstmem
, scratch
);
3468 /* Expand a string move operation of COUNT_EXP bytes from SRC to DST, with
3469 alignment ALIGN_EXP. Return true if successful, false if we should fall
3470 back on a different method. */
3473 bfin_expand_movmem (rtx dst
, rtx src
, rtx count_exp
, rtx align_exp
)
3475 rtx srcreg
, destreg
, countreg
;
3476 HOST_WIDE_INT align
= 0;
3477 unsigned HOST_WIDE_INT count
= 0;
3479 if (GET_CODE (align_exp
) == CONST_INT
)
3480 align
= INTVAL (align_exp
);
3481 if (GET_CODE (count_exp
) == CONST_INT
)
3483 count
= INTVAL (count_exp
);
3485 if (!TARGET_INLINE_ALL_STRINGOPS
&& count
> 64)
3490 /* If optimizing for size, only do single copies inline. */
3493 if (count
== 2 && align
< 2)
3495 if (count
== 4 && align
< 4)
3497 if (count
!= 1 && count
!= 2 && count
!= 4)
3500 if (align
< 2 && count
!= 1)
3503 destreg
= copy_to_mode_reg (Pmode
, XEXP (dst
, 0));
3504 if (destreg
!= XEXP (dst
, 0))
3505 dst
= replace_equiv_address_nv (dst
, destreg
);
3506 srcreg
= copy_to_mode_reg (Pmode
, XEXP (src
, 0));
3507 if (srcreg
!= XEXP (src
, 0))
3508 src
= replace_equiv_address_nv (src
, srcreg
);
3510 if (count
!= 0 && align
>= 2)
3512 unsigned HOST_WIDE_INT offset
= 0;
3516 if ((count
& ~3) == 4)
3518 single_move_for_movmem (dst
, src
, SImode
, offset
);
3521 else if (count
& ~3)
3523 HOST_WIDE_INT new_count
= ((count
>> 2) & 0x3fffffff) - 1;
3524 countreg
= copy_to_mode_reg (Pmode
, GEN_INT (new_count
));
3526 emit_insn (gen_rep_movsi (destreg
, srcreg
, countreg
, destreg
, srcreg
));
3527 cfun
->machine
->has_loopreg_clobber
= true;
3531 single_move_for_movmem (dst
, src
, HImode
, offset
);
3537 if ((count
& ~1) == 2)
3539 single_move_for_movmem (dst
, src
, HImode
, offset
);
3542 else if (count
& ~1)
3544 HOST_WIDE_INT new_count
= ((count
>> 1) & 0x7fffffff) - 1;
3545 countreg
= copy_to_mode_reg (Pmode
, GEN_INT (new_count
));
3547 emit_insn (gen_rep_movhi (destreg
, srcreg
, countreg
, destreg
, srcreg
));
3548 cfun
->machine
->has_loopreg_clobber
= true;
3553 single_move_for_movmem (dst
, src
, QImode
, offset
);
3560 /* Compute the alignment for a local variable.
3561 TYPE is the data type, and ALIGN is the alignment that
3562 the object would ordinarily have. The value of this macro is used
3563 instead of that alignment to align the object. */
3566 bfin_local_alignment (tree type
, int align
)
3568 /* Increasing alignment for (relatively) big types allows the builtin
3569 memcpy can use 32 bit loads/stores. */
3570 if (TYPE_SIZE (type
)
3571 && TREE_CODE (TYPE_SIZE (type
)) == INTEGER_CST
3572 && (TREE_INT_CST_LOW (TYPE_SIZE (type
)) > 8
3573 || TREE_INT_CST_HIGH (TYPE_SIZE (type
))) && align
< 32)
3578 /* Implement TARGET_SCHED_ISSUE_RATE. */
3581 bfin_issue_rate (void)
3587 bfin_adjust_cost (rtx insn
, rtx link
, rtx dep_insn
, int cost
)
3589 enum attr_type insn_type
, dep_insn_type
;
3590 int dep_insn_code_number
;
3592 /* Anti and output dependencies have zero cost. */
3593 if (REG_NOTE_KIND (link
) != 0)
3596 dep_insn_code_number
= recog_memoized (dep_insn
);
3598 /* If we can't recognize the insns, we can't really do anything. */
3599 if (dep_insn_code_number
< 0 || recog_memoized (insn
) < 0)
3602 insn_type
= get_attr_type (insn
);
3603 dep_insn_type
= get_attr_type (dep_insn
);
3605 if (dep_insn_type
== TYPE_MOVE
|| dep_insn_type
== TYPE_MCLD
)
3607 rtx pat
= PATTERN (dep_insn
);
3608 if (GET_CODE (pat
) == PARALLEL
)
3609 pat
= XVECEXP (pat
, 0, 0);
3610 rtx dest
= SET_DEST (pat
);
3611 rtx src
= SET_SRC (pat
);
3612 if (! ADDRESS_REGNO_P (REGNO (dest
))
3613 || ! (MEM_P (src
) || D_REGNO_P (REGNO (src
))))
3615 return cost
+ (dep_insn_type
== TYPE_MOVE
? 4 : 3);
3621 /* This function acts like NEXT_INSN, but is aware of three-insn bundles and
3622 skips all subsequent parallel instructions if INSN is the start of such
3625 find_next_insn_start (rtx insn
)
3627 if (GET_MODE (insn
) == SImode
)
3629 while (GET_MODE (insn
) != QImode
)
3630 insn
= NEXT_INSN (insn
);
3632 return NEXT_INSN (insn
);
3635 /* This function acts like PREV_INSN, but is aware of three-insn bundles and
3636 skips all subsequent parallel instructions if INSN is the start of such
3639 find_prev_insn_start (rtx insn
)
3641 insn
= PREV_INSN (insn
);
3642 gcc_assert (GET_MODE (insn
) != SImode
);
3643 if (GET_MODE (insn
) == QImode
)
3645 while (GET_MODE (PREV_INSN (insn
)) == SImode
)
3646 insn
= PREV_INSN (insn
);
3651 /* Increment the counter for the number of loop instructions in the
3652 current function. */
3655 bfin_hardware_loop (void)
3657 cfun
->machine
->has_hardware_loops
++;
3660 /* Maximum loop nesting depth. */
3661 #define MAX_LOOP_DEPTH 2
3663 /* Maximum size of a loop. */
3664 #define MAX_LOOP_LENGTH 2042
3666 /* Maximum distance of the LSETUP instruction from the loop start. */
3667 #define MAX_LSETUP_DISTANCE 30
3669 /* We need to keep a vector of loops */
3670 typedef struct loop_info
*loop_info
;
3671 DEF_VEC_P (loop_info
);
3672 DEF_VEC_ALLOC_P (loop_info
,heap
);
3674 /* Information about a loop we have found (or are in the process of
3676 struct GTY (()) loop_info
3678 /* loop number, for dumps */
3681 /* All edges that jump into and out of the loop. */
3682 VEC(edge
,gc
) *incoming
;
3684 /* We can handle two cases: all incoming edges have the same destination
3685 block, or all incoming edges have the same source block. These two
3686 members are set to the common source or destination we found, or NULL
3687 if different blocks were found. If both are NULL the loop can't be
3689 basic_block incoming_src
;
3690 basic_block incoming_dest
;
3692 /* First block in the loop. This is the one branched to by the loop_end
3696 /* Last block in the loop (the one with the loop_end insn). */
3699 /* The successor block of the loop. This is the one the loop_end insn
3701 basic_block successor
;
3703 /* The last instruction in the tail. */
3706 /* The loop_end insn. */
3709 /* The iteration register. */
3712 /* The new label placed at the beginning of the loop. */
3715 /* The new label placed at the end of the loop. */
3718 /* The length of the loop. */
3721 /* The nesting depth of the loop. */
3724 /* Nonzero if we can't optimize this loop. */
3727 /* True if we have visited this loop. */
3730 /* True if this loop body clobbers any of LC0, LT0, or LB0. */
3733 /* True if this loop body clobbers any of LC1, LT1, or LB1. */
3736 /* Next loop in the graph. */
3737 struct loop_info
*next
;
3739 /* Immediate outer loop of this loop. */
3740 struct loop_info
*outer
;
3742 /* Vector of blocks only within the loop, including those within
3744 VEC (basic_block
,heap
) *blocks
;
3746 /* Same information in a bitmap. */
3747 bitmap block_bitmap
;
3749 /* Vector of inner loops within this loop */
3750 VEC (loop_info
,heap
) *loops
;
3754 bfin_dump_loops (loop_info loops
)
3758 for (loop
= loops
; loop
; loop
= loop
->next
)
3764 fprintf (dump_file
, ";; loop %d: ", loop
->loop_no
);
3766 fprintf (dump_file
, "(bad) ");
3767 fprintf (dump_file
, "{head:%d, depth:%d}", loop
->head
->index
, loop
->depth
);
3769 fprintf (dump_file
, " blocks: [ ");
3770 for (ix
= 0; VEC_iterate (basic_block
, loop
->blocks
, ix
, b
); ix
++)
3771 fprintf (dump_file
, "%d ", b
->index
);
3772 fprintf (dump_file
, "] ");
3774 fprintf (dump_file
, " inner loops: [ ");
3775 for (ix
= 0; VEC_iterate (loop_info
, loop
->loops
, ix
, i
); ix
++)
3776 fprintf (dump_file
, "%d ", i
->loop_no
);
3777 fprintf (dump_file
, "]\n");
3779 fprintf (dump_file
, "\n");
3782 /* Scan the blocks of LOOP (and its inferiors) looking for basic block
3783 BB. Return true, if we find it. */
3786 bfin_bb_in_loop (loop_info loop
, basic_block bb
)
3788 return bitmap_bit_p (loop
->block_bitmap
, bb
->index
);
3791 /* Scan the blocks of LOOP (and its inferiors) looking for uses of
3792 REG. Return true, if we find any. Don't count the loop's loop_end
3793 insn if it matches LOOP_END. */
3796 bfin_scan_loop (loop_info loop
, rtx reg
, rtx loop_end
)
3801 for (ix
= 0; VEC_iterate (basic_block
, loop
->blocks
, ix
, bb
); ix
++)
3805 for (insn
= BB_HEAD (bb
);
3806 insn
!= NEXT_INSN (BB_END (bb
));
3807 insn
= NEXT_INSN (insn
))
3811 if (insn
== loop_end
)
3813 if (reg_mentioned_p (reg
, PATTERN (insn
)))
3820 /* Estimate the length of INSN conservatively. */
3823 length_for_loop (rtx insn
)
3826 if (JUMP_P (insn
) && any_condjump_p (insn
) && !optimize_size
)
3828 if (ENABLE_WA_SPECULATIVE_SYNCS
)
3830 else if (ENABLE_WA_SPECULATIVE_LOADS
)
3833 else if (LABEL_P (insn
))
3835 if (ENABLE_WA_SPECULATIVE_SYNCS
)
3839 if (NONDEBUG_INSN_P (insn
))
3840 length
+= get_attr_length (insn
);
3845 /* Optimize LOOP. */
3848 bfin_optimize_loop (loop_info loop
)
3852 rtx insn
, last_insn
;
3853 rtx loop_init
, start_label
, end_label
;
3854 rtx reg_lc0
, reg_lc1
, reg_lt0
, reg_lt1
, reg_lb0
, reg_lb1
;
3855 rtx iter_reg
, scratchreg
, scratch_init
, scratch_init_insn
;
3856 rtx lc_reg
, lt_reg
, lb_reg
;
3860 int inner_depth
= 0;
3870 fprintf (dump_file
, ";; loop %d bad when found\n", loop
->loop_no
);
3874 /* Every loop contains in its list of inner loops every loop nested inside
3875 it, even if there are intermediate loops. This works because we're doing
3876 a depth-first search here and never visit a loop more than once. */
3877 for (ix
= 0; VEC_iterate (loop_info
, loop
->loops
, ix
, inner
); ix
++)
3879 bfin_optimize_loop (inner
);
3881 if (!inner
->bad
&& inner_depth
< inner
->depth
)
3883 inner_depth
= inner
->depth
;
3885 loop
->clobber_loop0
|= inner
->clobber_loop0
;
3886 loop
->clobber_loop1
|= inner
->clobber_loop1
;
3890 loop
->depth
= inner_depth
+ 1;
3891 if (loop
->depth
> MAX_LOOP_DEPTH
)
3894 fprintf (dump_file
, ";; loop %d too deep\n", loop
->loop_no
);
3898 /* Get the loop iteration register. */
3899 iter_reg
= loop
->iter_reg
;
3901 if (!REG_P (iter_reg
))
3904 fprintf (dump_file
, ";; loop %d iteration count not in a register\n",
3908 scratchreg
= NULL_RTX
;
3909 scratch_init
= iter_reg
;
3910 scratch_init_insn
= NULL_RTX
;
3911 if (!PREG_P (iter_reg
) && loop
->incoming_src
)
3913 basic_block bb_in
= loop
->incoming_src
;
3915 for (i
= REG_P0
; i
<= REG_P5
; i
++)
3916 if ((df_regs_ever_live_p (i
)
3917 || (funkind (TREE_TYPE (current_function_decl
)) == SUBROUTINE
3918 && call_used_regs
[i
]))
3919 && !REGNO_REG_SET_P (df_get_live_out (bb_in
), i
))
3921 scratchreg
= gen_rtx_REG (SImode
, i
);
3924 for (insn
= BB_END (bb_in
); insn
!= BB_HEAD (bb_in
);
3925 insn
= PREV_INSN (insn
))
3928 if (NOTE_P (insn
) || BARRIER_P (insn
))
3930 set
= single_set (insn
);
3931 if (set
&& rtx_equal_p (SET_DEST (set
), iter_reg
))
3933 if (CONSTANT_P (SET_SRC (set
)))
3935 scratch_init
= SET_SRC (set
);
3936 scratch_init_insn
= insn
;
3940 else if (reg_mentioned_p (iter_reg
, PATTERN (insn
)))
3945 if (loop
->incoming_src
)
3947 /* Make sure the predecessor is before the loop start label, as required by
3948 the LSETUP instruction. */
3950 insn
= BB_END (loop
->incoming_src
);
3951 /* If we have to insert the LSETUP before a jump, count that jump in the
3953 if (VEC_length (edge
, loop
->incoming
) > 1
3954 || !(VEC_last (edge
, loop
->incoming
)->flags
& EDGE_FALLTHRU
))
3956 gcc_assert (JUMP_P (insn
));
3957 insn
= PREV_INSN (insn
);
3960 for (; insn
&& insn
!= loop
->start_label
; insn
= NEXT_INSN (insn
))
3961 length
+= length_for_loop (insn
);
3966 fprintf (dump_file
, ";; loop %d lsetup not before loop_start\n",
3971 /* Account for the pop of a scratch register where necessary. */
3972 if (!PREG_P (iter_reg
) && scratchreg
== NULL_RTX
3973 && ENABLE_WA_LOAD_LCREGS
)
3976 if (length
> MAX_LSETUP_DISTANCE
)
3979 fprintf (dump_file
, ";; loop %d lsetup too far away\n", loop
->loop_no
);
3984 /* Check if start_label appears before loop_end and calculate the
3985 offset between them. We calculate the length of instructions
3988 for (insn
= loop
->start_label
;
3989 insn
&& insn
!= loop
->loop_end
;
3990 insn
= NEXT_INSN (insn
))
3991 length
+= length_for_loop (insn
);
3996 fprintf (dump_file
, ";; loop %d start_label not before loop_end\n",
4001 loop
->length
= length
;
4002 if (loop
->length
> MAX_LOOP_LENGTH
)
4005 fprintf (dump_file
, ";; loop %d too long\n", loop
->loop_no
);
4009 /* Scan all the blocks to make sure they don't use iter_reg. */
4010 if (bfin_scan_loop (loop
, iter_reg
, loop
->loop_end
))
4013 fprintf (dump_file
, ";; loop %d uses iterator\n", loop
->loop_no
);
4017 /* Scan all the insns to see if the loop body clobber
4018 any hardware loop registers. */
4020 reg_lc0
= gen_rtx_REG (SImode
, REG_LC0
);
4021 reg_lc1
= gen_rtx_REG (SImode
, REG_LC1
);
4022 reg_lt0
= gen_rtx_REG (SImode
, REG_LT0
);
4023 reg_lt1
= gen_rtx_REG (SImode
, REG_LT1
);
4024 reg_lb0
= gen_rtx_REG (SImode
, REG_LB0
);
4025 reg_lb1
= gen_rtx_REG (SImode
, REG_LB1
);
4027 for (ix
= 0; VEC_iterate (basic_block
, loop
->blocks
, ix
, bb
); ix
++)
4031 for (insn
= BB_HEAD (bb
);
4032 insn
!= NEXT_INSN (BB_END (bb
));
4033 insn
= NEXT_INSN (insn
))
4038 if (reg_set_p (reg_lc0
, insn
)
4039 || reg_set_p (reg_lt0
, insn
)
4040 || reg_set_p (reg_lb0
, insn
))
4041 loop
->clobber_loop0
= 1;
4043 if (reg_set_p (reg_lc1
, insn
)
4044 || reg_set_p (reg_lt1
, insn
)
4045 || reg_set_p (reg_lb1
, insn
))
4046 loop
->clobber_loop1
|= 1;
4050 if ((loop
->clobber_loop0
&& loop
->clobber_loop1
)
4051 || (loop
->depth
== MAX_LOOP_DEPTH
&& loop
->clobber_loop0
))
4053 loop
->depth
= MAX_LOOP_DEPTH
+ 1;
4055 fprintf (dump_file
, ";; loop %d no loop reg available\n",
4060 /* There should be an instruction before the loop_end instruction
4061 in the same basic block. And the instruction must not be
4063 - CONDITIONAL BRANCH
4067 - Returns (RTS, RTN, etc.) */
4070 last_insn
= find_prev_insn_start (loop
->loop_end
);
4074 for (; last_insn
!= BB_HEAD (bb
);
4075 last_insn
= find_prev_insn_start (last_insn
))
4076 if (NONDEBUG_INSN_P (last_insn
))
4079 if (last_insn
!= BB_HEAD (bb
))
4082 if (single_pred_p (bb
)
4083 && single_pred_edge (bb
)->flags
& EDGE_FALLTHRU
4084 && single_pred (bb
) != ENTRY_BLOCK_PTR
)
4086 bb
= single_pred (bb
);
4087 last_insn
= BB_END (bb
);
4092 last_insn
= NULL_RTX
;
4100 fprintf (dump_file
, ";; loop %d has no last instruction\n",
4105 if (JUMP_P (last_insn
) && !any_condjump_p (last_insn
))
4108 fprintf (dump_file
, ";; loop %d has bad last instruction\n",
4112 /* In all other cases, try to replace a bad last insn with a nop. */
4113 else if (JUMP_P (last_insn
)
4114 || CALL_P (last_insn
)
4115 || get_attr_type (last_insn
) == TYPE_SYNC
4116 || get_attr_type (last_insn
) == TYPE_CALL
4117 || get_attr_seq_insns (last_insn
) == SEQ_INSNS_MULTI
4118 || recog_memoized (last_insn
) == CODE_FOR_return_internal
4119 || GET_CODE (PATTERN (last_insn
)) == ASM_INPUT
4120 || asm_noperands (PATTERN (last_insn
)) >= 0)
4122 if (loop
->length
+ 2 > MAX_LOOP_LENGTH
)
4125 fprintf (dump_file
, ";; loop %d too long\n", loop
->loop_no
);
4129 fprintf (dump_file
, ";; loop %d has bad last insn; replace with nop\n",
4132 last_insn
= emit_insn_after (gen_forced_nop (), last_insn
);
4135 loop
->last_insn
= last_insn
;
4137 /* The loop is good for replacement. */
4138 start_label
= loop
->start_label
;
4139 end_label
= gen_label_rtx ();
4140 iter_reg
= loop
->iter_reg
;
4142 if (loop
->depth
== 1 && !loop
->clobber_loop1
)
4147 loop
->clobber_loop1
= 1;
4154 loop
->clobber_loop0
= 1;
4157 loop
->end_label
= end_label
;
4159 /* Create a sequence containing the loop setup. */
4162 /* LSETUP only accepts P registers. If we have one, we can use it,
4163 otherwise there are several ways of working around the problem.
4164 If we're not affected by anomaly 312, we can load the LC register
4165 from any iteration register, and use LSETUP without initialization.
4166 If we've found a P scratch register that's not live here, we can
4167 instead copy the iter_reg into that and use an initializing LSETUP.
4168 If all else fails, push and pop P0 and use it as a scratch. */
4169 if (P_REGNO_P (REGNO (iter_reg
)))
4171 loop_init
= gen_lsetup_with_autoinit (lt_reg
, start_label
,
4174 seq_end
= emit_insn (loop_init
);
4176 else if (!ENABLE_WA_LOAD_LCREGS
&& DPREG_P (iter_reg
))
4178 emit_insn (gen_movsi (lc_reg
, iter_reg
));
4179 loop_init
= gen_lsetup_without_autoinit (lt_reg
, start_label
,
4182 seq_end
= emit_insn (loop_init
);
4184 else if (scratchreg
!= NULL_RTX
)
4186 emit_insn (gen_movsi (scratchreg
, scratch_init
));
4187 loop_init
= gen_lsetup_with_autoinit (lt_reg
, start_label
,
4189 lc_reg
, scratchreg
);
4190 seq_end
= emit_insn (loop_init
);
4191 if (scratch_init_insn
!= NULL_RTX
)
4192 delete_insn (scratch_init_insn
);
4196 rtx p0reg
= gen_rtx_REG (SImode
, REG_P0
);
4197 rtx push
= gen_frame_mem (SImode
,
4198 gen_rtx_PRE_DEC (SImode
, stack_pointer_rtx
));
4199 rtx pop
= gen_frame_mem (SImode
,
4200 gen_rtx_POST_INC (SImode
, stack_pointer_rtx
));
4201 emit_insn (gen_movsi (push
, p0reg
));
4202 emit_insn (gen_movsi (p0reg
, scratch_init
));
4203 loop_init
= gen_lsetup_with_autoinit (lt_reg
, start_label
,
4206 emit_insn (loop_init
);
4207 seq_end
= emit_insn (gen_movsi (p0reg
, pop
));
4208 if (scratch_init_insn
!= NULL_RTX
)
4209 delete_insn (scratch_init_insn
);
4214 fprintf (dump_file
, ";; replacing loop %d initializer with\n",
4216 print_rtl_single (dump_file
, loop_init
);
4217 fprintf (dump_file
, ";; replacing loop %d terminator with\n",
4219 print_rtl_single (dump_file
, loop
->loop_end
);
4222 /* If the loop isn't entered at the top, also create a jump to the entry
4224 if (!loop
->incoming_src
&& loop
->head
!= loop
->incoming_dest
)
4226 rtx label
= BB_HEAD (loop
->incoming_dest
);
4227 /* If we're jumping to the final basic block in the loop, and there's
4228 only one cheap instruction before the end (typically an increment of
4229 an induction variable), we can just emit a copy here instead of a
4231 if (loop
->incoming_dest
== loop
->tail
4232 && next_real_insn (label
) == last_insn
4233 && asm_noperands (last_insn
) < 0
4234 && GET_CODE (PATTERN (last_insn
)) == SET
)
4236 seq_end
= emit_insn (copy_rtx (PATTERN (last_insn
)));
4240 emit_jump_insn (gen_jump (label
));
4241 seq_end
= emit_barrier ();
4248 if (loop
->incoming_src
)
4250 rtx prev
= BB_END (loop
->incoming_src
);
4251 if (VEC_length (edge
, loop
->incoming
) > 1
4252 || !(VEC_last (edge
, loop
->incoming
)->flags
& EDGE_FALLTHRU
))
4254 gcc_assert (JUMP_P (prev
));
4255 prev
= PREV_INSN (prev
);
4257 emit_insn_after (seq
, prev
);
4265 #ifdef ENABLE_CHECKING
4266 if (loop
->head
!= loop
->incoming_dest
)
4268 /* We aren't entering the loop at the top. Since we've established
4269 that the loop is entered only at one point, this means there
4270 can't be fallthru edges into the head. Any such fallthru edges
4271 would become invalid when we insert the new block, so verify
4272 that this does not in fact happen. */
4273 FOR_EACH_EDGE (e
, ei
, loop
->head
->preds
)
4274 gcc_assert (!(e
->flags
& EDGE_FALLTHRU
));
4278 emit_insn_before (seq
, BB_HEAD (loop
->head
));
4279 seq
= emit_label_before (gen_label_rtx (), seq
);
4281 new_bb
= create_basic_block (seq
, seq_end
, loop
->head
->prev_bb
);
4282 FOR_EACH_EDGE (e
, ei
, loop
->incoming
)
4284 if (!(e
->flags
& EDGE_FALLTHRU
)
4285 || e
->dest
!= loop
->head
)
4286 redirect_edge_and_branch_force (e
, new_bb
);
4288 redirect_edge_succ (e
, new_bb
);
4290 e
= make_edge (new_bb
, loop
->head
, 0);
4293 delete_insn (loop
->loop_end
);
4294 /* Insert the loop end label before the last instruction of the loop. */
4295 emit_label_before (loop
->end_label
, loop
->last_insn
);
4302 fprintf (dump_file
, ";; loop %d is bad\n", loop
->loop_no
);
4306 if (DPREG_P (loop
->iter_reg
))
4308 /* If loop->iter_reg is a DREG or PREG, we can split it here
4309 without scratch register. */
4312 emit_insn_before (gen_addsi3 (loop
->iter_reg
,
4317 test
= gen_rtx_NE (VOIDmode
, loop
->iter_reg
, const0_rtx
);
4318 insn
= emit_jump_insn_before (gen_cbranchsi4 (test
,
4319 loop
->iter_reg
, const0_rtx
,
4323 JUMP_LABEL (insn
) = loop
->start_label
;
4324 LABEL_NUSES (loop
->start_label
)++;
4325 delete_insn (loop
->loop_end
);
4329 /* Called from bfin_reorg_loops when a potential loop end is found. LOOP is
4330 a newly set up structure describing the loop, it is this function's
4331 responsibility to fill most of it. TAIL_BB and TAIL_INSN point to the
4332 loop_end insn and its enclosing basic block. */
4335 bfin_discover_loop (loop_info loop
, basic_block tail_bb
, rtx tail_insn
)
4339 VEC (basic_block
,heap
) *works
= VEC_alloc (basic_block
,heap
,20);
4341 loop
->tail
= tail_bb
;
4342 loop
->head
= BRANCH_EDGE (tail_bb
)->dest
;
4343 loop
->successor
= FALLTHRU_EDGE (tail_bb
)->dest
;
4344 loop
->loop_end
= tail_insn
;
4345 loop
->last_insn
= NULL_RTX
;
4346 loop
->iter_reg
= SET_DEST (XVECEXP (PATTERN (tail_insn
), 0, 1));
4347 loop
->depth
= loop
->length
= 0;
4349 loop
->clobber_loop0
= loop
->clobber_loop1
= 0;
4352 loop
->incoming
= VEC_alloc (edge
, gc
, 2);
4353 loop
->start_label
= XEXP (XEXP (SET_SRC (XVECEXP (PATTERN (tail_insn
), 0, 0)), 1), 0);
4354 loop
->end_label
= NULL_RTX
;
4357 VEC_safe_push (basic_block
, heap
, works
, loop
->head
);
4359 while (VEC_iterate (basic_block
, works
, dwork
++, bb
))
4363 if (bb
== EXIT_BLOCK_PTR
)
4365 /* We've reached the exit block. The loop must be bad. */
4368 ";; Loop is bad - reached exit block while scanning\n");
4373 if (bitmap_bit_p (loop
->block_bitmap
, bb
->index
))
4376 /* We've not seen this block before. Add it to the loop's
4377 list and then add each successor to the work list. */
4379 VEC_safe_push (basic_block
, heap
, loop
->blocks
, bb
);
4380 bitmap_set_bit (loop
->block_bitmap
, bb
->index
);
4384 FOR_EACH_EDGE (e
, ei
, bb
->succs
)
4386 basic_block succ
= EDGE_SUCC (bb
, ei
.index
)->dest
;
4387 if (!REGNO_REG_SET_P (df_get_live_in (succ
),
4388 REGNO (loop
->iter_reg
)))
4390 if (!VEC_space (basic_block
, works
, 1))
4394 VEC_block_remove (basic_block
, works
, 0, dwork
);
4398 VEC_reserve (basic_block
, heap
, works
, 1);
4400 VEC_quick_push (basic_block
, works
, succ
);
4405 /* Find the predecessor, and make sure nothing else jumps into this loop. */
4409 for (dwork
= 0; VEC_iterate (basic_block
, loop
->blocks
, dwork
, bb
); dwork
++)
4413 FOR_EACH_EDGE (e
, ei
, bb
->preds
)
4415 basic_block pred
= e
->src
;
4417 if (!bfin_bb_in_loop (loop
, pred
))
4420 fprintf (dump_file
, ";; Loop %d: incoming edge %d -> %d\n",
4421 loop
->loop_no
, pred
->index
,
4423 VEC_safe_push (edge
, gc
, loop
->incoming
, e
);
4428 for (pass
= 0, retry
= 1; retry
&& pass
< 2; pass
++)
4435 FOR_EACH_EDGE (e
, ei
, loop
->incoming
)
4439 loop
->incoming_src
= e
->src
;
4440 loop
->incoming_dest
= e
->dest
;
4445 if (e
->dest
!= loop
->incoming_dest
)
4446 loop
->incoming_dest
= NULL
;
4447 if (e
->src
!= loop
->incoming_src
)
4448 loop
->incoming_src
= NULL
;
4450 if (loop
->incoming_src
== NULL
&& loop
->incoming_dest
== NULL
)
4456 ";; retrying loop %d with forwarder blocks\n",
4464 ";; can't find suitable entry for loop %d\n",
4472 FOR_EACH_EDGE (e
, ei
, loop
->incoming
)
4474 if (forwarder_block_p (e
->src
))
4481 ";; Adding forwarder block %d to loop %d and retrying\n",
4482 e
->src
->index
, loop
->loop_no
);
4483 VEC_safe_push (basic_block
, heap
, loop
->blocks
, e
->src
);
4484 bitmap_set_bit (loop
->block_bitmap
, e
->src
->index
);
4485 FOR_EACH_EDGE (e2
, ei2
, e
->src
->preds
)
4486 VEC_safe_push (edge
, gc
, loop
->incoming
, e2
);
4487 VEC_unordered_remove (edge
, loop
->incoming
, ei
.index
);
4495 fprintf (dump_file
, ";; No forwarder blocks found\n");
4503 VEC_free (basic_block
, heap
, works
);
4506 /* Analyze the structure of the loops in the current function. Use STACK
4507 for bitmap allocations. Returns all the valid candidates for hardware
4508 loops found in this function. */
4510 bfin_discover_loops (bitmap_obstack
*stack
, FILE *dump_file
)
4512 loop_info loops
= NULL
;
4518 /* Find all the possible loop tails. This means searching for every
4519 loop_end instruction. For each one found, create a loop_info
4520 structure and add the head block to the work list. */
4523 rtx tail
= BB_END (bb
);
4525 while (GET_CODE (tail
) == NOTE
)
4526 tail
= PREV_INSN (tail
);
4530 if (INSN_P (tail
) && recog_memoized (tail
) == CODE_FOR_loop_end
)
4533 /* A possible loop end */
4535 /* There's a degenerate case we can handle - an empty loop consisting
4536 of only a back branch. Handle that by deleting the branch. */
4537 insn
= BB_HEAD (BRANCH_EDGE (bb
)->dest
);
4538 if (next_real_insn (insn
) == tail
)
4542 fprintf (dump_file
, ";; degenerate loop ending at\n");
4543 print_rtl_single (dump_file
, tail
);
4545 delete_insn_and_edges (tail
);
4549 loop
= XNEW (struct loop_info
);
4552 loop
->loop_no
= nloops
++;
4553 loop
->blocks
= VEC_alloc (basic_block
, heap
, 20);
4554 loop
->block_bitmap
= BITMAP_ALLOC (stack
);
4559 fprintf (dump_file
, ";; potential loop %d ending at\n",
4561 print_rtl_single (dump_file
, tail
);
4564 bfin_discover_loop (loop
, bb
, tail
);
4568 tmp_bitmap
= BITMAP_ALLOC (stack
);
4569 /* Compute loop nestings. */
4570 for (loop
= loops
; loop
; loop
= loop
->next
)
4576 for (other
= loop
->next
; other
; other
= other
->next
)
4581 bitmap_and (tmp_bitmap
, other
->block_bitmap
, loop
->block_bitmap
);
4582 if (bitmap_empty_p (tmp_bitmap
))
4584 if (bitmap_equal_p (tmp_bitmap
, other
->block_bitmap
))
4586 other
->outer
= loop
;
4587 VEC_safe_push (loop_info
, heap
, loop
->loops
, other
);
4589 else if (bitmap_equal_p (tmp_bitmap
, loop
->block_bitmap
))
4591 loop
->outer
= other
;
4592 VEC_safe_push (loop_info
, heap
, other
->loops
, loop
);
4598 ";; can't find suitable nesting for loops %d and %d\n",
4599 loop
->loop_no
, other
->loop_no
);
4600 loop
->bad
= other
->bad
= 1;
4604 BITMAP_FREE (tmp_bitmap
);
4609 /* Free up the loop structures in LOOPS. */
4611 free_loops (loop_info loops
)
4615 loop_info loop
= loops
;
4617 VEC_free (loop_info
, heap
, loop
->loops
);
4618 VEC_free (basic_block
, heap
, loop
->blocks
);
4619 BITMAP_FREE (loop
->block_bitmap
);
4624 #define BB_AUX_INDEX(BB) ((unsigned)(BB)->aux)
4626 /* The taken-branch edge from the loop end can actually go forward. Since the
4627 Blackfin's LSETUP instruction requires that the loop end be after the loop
4628 start, try to reorder a loop's basic blocks when we find such a case. */
4630 bfin_reorder_loops (loop_info loops
, FILE *dump_file
)
4637 cfg_layout_initialize (0);
4639 for (loop
= loops
; loop
; loop
= loop
->next
)
4649 /* Recreate an index for basic blocks that represents their order. */
4650 for (bb
= ENTRY_BLOCK_PTR
->next_bb
, index
= 0;
4651 bb
!= EXIT_BLOCK_PTR
;
4652 bb
= bb
->next_bb
, index
++)
4653 bb
->aux
= (PTR
) index
;
4655 if (BB_AUX_INDEX (loop
->head
) < BB_AUX_INDEX (loop
->tail
))
4658 FOR_EACH_EDGE (e
, ei
, loop
->head
->succs
)
4660 if (bitmap_bit_p (loop
->block_bitmap
, e
->dest
->index
)
4661 && BB_AUX_INDEX (e
->dest
) < BB_AUX_INDEX (loop
->tail
))
4663 basic_block start_bb
= e
->dest
;
4664 basic_block start_prev_bb
= start_bb
->prev_bb
;
4667 fprintf (dump_file
, ";; Moving block %d before block %d\n",
4668 loop
->head
->index
, start_bb
->index
);
4669 loop
->head
->prev_bb
->next_bb
= loop
->head
->next_bb
;
4670 loop
->head
->next_bb
->prev_bb
= loop
->head
->prev_bb
;
4672 loop
->head
->prev_bb
= start_prev_bb
;
4673 loop
->head
->next_bb
= start_bb
;
4674 start_prev_bb
->next_bb
= start_bb
->prev_bb
= loop
->head
;
4678 loops
= loops
->next
;
4683 if (bb
->next_bb
!= EXIT_BLOCK_PTR
)
4684 bb
->aux
= bb
->next_bb
;
4688 cfg_layout_finalize ();
4692 /* Run from machine_dependent_reorg, this pass looks for doloop_end insns
4693 and tries to rewrite the RTL of these loops so that proper Blackfin
4694 hardware loops are generated. */
4697 bfin_reorg_loops (FILE *dump_file
)
4699 loop_info loops
= NULL
;
4702 bitmap_obstack stack
;
4704 bitmap_obstack_initialize (&stack
);
4707 fprintf (dump_file
, ";; Find loops, first pass\n\n");
4709 loops
= bfin_discover_loops (&stack
, dump_file
);
4712 bfin_dump_loops (loops
);
4714 bfin_reorder_loops (loops
, dump_file
);
4718 fprintf (dump_file
, ";; Find loops, second pass\n\n");
4720 loops
= bfin_discover_loops (&stack
, dump_file
);
4723 fprintf (dump_file
, ";; All loops found:\n\n");
4724 bfin_dump_loops (loops
);
4727 /* Now apply the optimizations. */
4728 for (loop
= loops
; loop
; loop
= loop
->next
)
4729 bfin_optimize_loop (loop
);
4733 fprintf (dump_file
, ";; After hardware loops optimization:\n\n");
4734 bfin_dump_loops (loops
);
4740 print_rtl (dump_file
, get_insns ());
4745 splitting_loops
= 1;
4748 rtx insn
= BB_END (bb
);
4752 try_split (PATTERN (insn
), insn
, 1);
4754 splitting_loops
= 0;
4757 /* Possibly generate a SEQUENCE out of three insns found in SLOT.
4758 Returns true if we modified the insn chain, false otherwise. */
4760 gen_one_bundle (rtx slot
[3])
4762 gcc_assert (slot
[1] != NULL_RTX
);
4764 /* Don't add extra NOPs if optimizing for size. */
4766 && (slot
[0] == NULL_RTX
|| slot
[2] == NULL_RTX
))
4769 /* Verify that we really can do the multi-issue. */
4772 rtx t
= NEXT_INSN (slot
[0]);
4773 while (t
!= slot
[1])
4775 if (GET_CODE (t
) != NOTE
4776 || NOTE_KIND (t
) != NOTE_INSN_DELETED
)
4783 rtx t
= NEXT_INSN (slot
[1]);
4784 while (t
!= slot
[2])
4786 if (GET_CODE (t
) != NOTE
4787 || NOTE_KIND (t
) != NOTE_INSN_DELETED
)
4793 if (slot
[0] == NULL_RTX
)
4795 slot
[0] = emit_insn_before (gen_mnop (), slot
[1]);
4796 df_insn_rescan (slot
[0]);
4798 if (slot
[2] == NULL_RTX
)
4800 slot
[2] = emit_insn_after (gen_forced_nop (), slot
[1]);
4801 df_insn_rescan (slot
[2]);
4804 /* Avoid line number information being printed inside one bundle. */
4805 if (INSN_LOCATOR (slot
[1])
4806 && INSN_LOCATOR (slot
[1]) != INSN_LOCATOR (slot
[0]))
4807 INSN_LOCATOR (slot
[1]) = INSN_LOCATOR (slot
[0]);
4808 if (INSN_LOCATOR (slot
[2])
4809 && INSN_LOCATOR (slot
[2]) != INSN_LOCATOR (slot
[0]))
4810 INSN_LOCATOR (slot
[2]) = INSN_LOCATOR (slot
[0]);
4812 /* Terminate them with "|| " instead of ";" in the output. */
4813 PUT_MODE (slot
[0], SImode
);
4814 PUT_MODE (slot
[1], SImode
);
4815 /* Terminate the bundle, for the benefit of reorder_var_tracking_notes. */
4816 PUT_MODE (slot
[2], QImode
);
4820 /* Go through all insns, and use the information generated during scheduling
4821 to generate SEQUENCEs to represent bundles of instructions issued
4825 bfin_gen_bundles (void)
4834 slot
[0] = slot
[1] = slot
[2] = NULL_RTX
;
4835 for (insn
= BB_HEAD (bb
);; insn
= next
)
4838 rtx delete_this
= NULL_RTX
;
4840 if (NONDEBUG_INSN_P (insn
))
4842 enum attr_type type
= get_attr_type (insn
);
4844 if (type
== TYPE_STALL
)
4846 gcc_assert (n_filled
== 0);
4851 if (type
== TYPE_DSP32
|| type
== TYPE_DSP32SHIFTIMM
)
4853 else if (slot
[1] == NULL_RTX
)
4861 next
= NEXT_INSN (insn
);
4862 while (next
&& insn
!= BB_END (bb
)
4864 && GET_CODE (PATTERN (next
)) != USE
4865 && GET_CODE (PATTERN (next
)) != CLOBBER
))
4868 next
= NEXT_INSN (insn
);
4871 /* BB_END can change due to emitting extra NOPs, so check here. */
4872 at_end
= insn
== BB_END (bb
);
4873 if (delete_this
== NULL_RTX
&& (at_end
|| GET_MODE (next
) == TImode
))
4876 || !gen_one_bundle (slot
))
4877 && slot
[0] != NULL_RTX
)
4879 rtx pat
= PATTERN (slot
[0]);
4880 if (GET_CODE (pat
) == SET
4881 && GET_CODE (SET_SRC (pat
)) == UNSPEC
4882 && XINT (SET_SRC (pat
), 1) == UNSPEC_32BIT
)
4884 SET_SRC (pat
) = XVECEXP (SET_SRC (pat
), 0, 0);
4885 INSN_CODE (slot
[0]) = -1;
4886 df_insn_rescan (slot
[0]);
4890 slot
[0] = slot
[1] = slot
[2] = NULL_RTX
;
4892 if (delete_this
!= NULL_RTX
)
4893 delete_insn (delete_this
);
4900 /* Ensure that no var tracking notes are emitted in the middle of a
4901 three-instruction bundle. */
4904 reorder_var_tracking_notes (void)
4910 rtx queue
= NULL_RTX
;
4911 bool in_bundle
= false;
4913 for (insn
= BB_HEAD (bb
); insn
!= BB_END (bb
); insn
= next
)
4915 next
= NEXT_INSN (insn
);
4919 /* Emit queued up notes at the last instruction of a bundle. */
4920 if (GET_MODE (insn
) == QImode
)
4924 rtx next_queue
= PREV_INSN (queue
);
4925 PREV_INSN (NEXT_INSN (insn
)) = queue
;
4926 NEXT_INSN (queue
) = NEXT_INSN (insn
);
4927 NEXT_INSN (insn
) = queue
;
4928 PREV_INSN (queue
) = insn
;
4933 else if (GET_MODE (insn
) == SImode
)
4936 else if (NOTE_P (insn
) && NOTE_KIND (insn
) == NOTE_INSN_VAR_LOCATION
)
4940 rtx prev
= PREV_INSN (insn
);
4941 PREV_INSN (next
) = prev
;
4942 NEXT_INSN (prev
) = next
;
4944 PREV_INSN (insn
) = queue
;
4952 /* On some silicon revisions, functions shorter than a certain number of cycles
4953 can cause unpredictable behaviour. Work around this by adding NOPs as
4956 workaround_rts_anomaly (void)
4958 rtx insn
, first_insn
= NULL_RTX
;
4961 if (! ENABLE_WA_RETS
)
4964 for (insn
= get_insns (); insn
; insn
= NEXT_INSN (insn
))
4968 if (BARRIER_P (insn
))
4971 if (NOTE_P (insn
) || LABEL_P (insn
))
4974 if (first_insn
== NULL_RTX
)
4976 pat
= PATTERN (insn
);
4977 if (GET_CODE (pat
) == USE
|| GET_CODE (pat
) == CLOBBER
4978 || GET_CODE (pat
) == ASM_INPUT
|| GET_CODE (pat
) == ADDR_VEC
4979 || GET_CODE (pat
) == ADDR_DIFF_VEC
|| asm_noperands (pat
) >= 0)
4987 if (recog_memoized (insn
) == CODE_FOR_return_internal
)
4990 /* Nothing to worry about for direct jumps. */
4991 if (!any_condjump_p (insn
))
4997 else if (INSN_P (insn
))
4999 rtx pat
= PATTERN (insn
);
5000 int this_cycles
= 1;
5002 if (GET_CODE (pat
) == PARALLEL
)
5004 if (push_multiple_operation (pat
, VOIDmode
)
5005 || pop_multiple_operation (pat
, VOIDmode
))
5006 this_cycles
= n_regs_to_save
;
5010 enum insn_code icode
= recog_memoized (insn
);
5011 if (icode
== CODE_FOR_link
)
5013 else if (icode
== CODE_FOR_unlink
)
5015 else if (icode
== CODE_FOR_mulsi3
)
5018 if (this_cycles
>= cycles
)
5021 cycles
-= this_cycles
;
5026 emit_insn_before (gen_nop (), first_insn
);
5031 /* Return an insn type for INSN that can be used by the caller for anomaly
5032 workarounds. This differs from plain get_attr_type in that it handles
5035 static enum attr_type
5036 type_for_anomaly (rtx insn
)
5038 rtx pat
= PATTERN (insn
);
5039 if (GET_CODE (pat
) == SEQUENCE
)
5042 t
= get_attr_type (XVECEXP (pat
, 0, 1));
5045 t
= get_attr_type (XVECEXP (pat
, 0, 2));
5051 return get_attr_type (insn
);
5054 /* Return true iff the address found in MEM is based on the register
5055 NP_REG and optionally has a positive offset. */
5057 harmless_null_pointer_p (rtx mem
, int np_reg
)
5059 mem
= XEXP (mem
, 0);
5060 if (GET_CODE (mem
) == POST_INC
|| GET_CODE (mem
) == POST_DEC
)
5061 mem
= XEXP (mem
, 0);
5062 if (REG_P (mem
) && REGNO (mem
) == np_reg
)
5064 if (GET_CODE (mem
) == PLUS
5065 && REG_P (XEXP (mem
, 0)) && REGNO (XEXP (mem
, 0)) == np_reg
)
5067 mem
= XEXP (mem
, 1);
5068 if (GET_CODE (mem
) == CONST_INT
&& INTVAL (mem
) > 0)
5074 /* Return nonzero if INSN contains any loads that may trap. */
5077 trapping_loads_p (rtx insn
, int np_reg
, bool after_np_branch
)
5079 rtx pat
= PATTERN (insn
);
5080 rtx mem
= SET_SRC (single_set (insn
));
5082 if (!after_np_branch
)
5084 return ((np_reg
== -1 || !harmless_null_pointer_p (mem
, np_reg
))
5085 && may_trap_p (mem
));
5088 /* Return INSN if it is of TYPE_MCLD. Alternatively, if INSN is the start of
5089 a three-insn bundle, see if one of them is a load and return that if so.
5090 Return NULL_RTX if the insn does not contain loads. */
5092 find_load (rtx insn
)
5094 if (!NONDEBUG_INSN_P (insn
))
5096 if (get_attr_type (insn
) == TYPE_MCLD
)
5098 if (GET_MODE (insn
) != SImode
)
5101 insn
= NEXT_INSN (insn
);
5102 if ((GET_MODE (insn
) == SImode
|| GET_MODE (insn
) == QImode
)
5103 && get_attr_type (insn
) == TYPE_MCLD
)
5105 } while (GET_MODE (insn
) != QImode
);
5109 /* Determine whether PAT is an indirect call pattern. */
5111 indirect_call_p (rtx pat
)
5113 if (GET_CODE (pat
) == PARALLEL
)
5114 pat
= XVECEXP (pat
, 0, 0);
5115 if (GET_CODE (pat
) == SET
)
5116 pat
= SET_SRC (pat
);
5117 gcc_assert (GET_CODE (pat
) == CALL
);
5118 pat
= XEXP (pat
, 0);
5119 gcc_assert (GET_CODE (pat
) == MEM
);
5120 pat
= XEXP (pat
, 0);
5125 /* During workaround_speculation, track whether we're in the shadow of a
5126 conditional branch that tests a P register for NULL. If so, we can omit
5127 emitting NOPs if we see a load from that P register, since a speculative
5128 access at address 0 isn't a problem, and the load is executed in all other
5130 Global for communication with note_np_check_stores through note_stores.
5132 int np_check_regno
= -1;
5133 bool np_after_branch
= false;
5135 /* Subroutine of workaround_speculation, called through note_stores. */
5137 note_np_check_stores (rtx x
, const_rtx pat
, void *data ATTRIBUTE_UNUSED
)
5139 if (REG_P (x
) && (REGNO (x
) == REG_CC
|| REGNO (x
) == np_check_regno
))
5140 np_check_regno
= -1;
5144 workaround_speculation (void)
5147 rtx last_condjump
= NULL_RTX
;
5148 int cycles_since_jump
= INT_MAX
;
5149 int delay_added
= 0;
5151 if (! ENABLE_WA_SPECULATIVE_LOADS
&& ! ENABLE_WA_SPECULATIVE_SYNCS
5152 && ! ENABLE_WA_INDIRECT_CALLS
)
5155 /* First pass: find predicted-false branches; if something after them
5156 needs nops, insert them or change the branch to predict true. */
5157 for (insn
= get_insns (); insn
; insn
= next
)
5160 int delay_needed
= 0;
5162 next
= find_next_insn_start (insn
);
5164 if (NOTE_P (insn
) || BARRIER_P (insn
))
5169 np_check_regno
= -1;
5173 pat
= PATTERN (insn
);
5174 if (GET_CODE (pat
) == USE
|| GET_CODE (pat
) == CLOBBER
5175 || GET_CODE (pat
) == ADDR_VEC
|| GET_CODE (pat
) == ADDR_DIFF_VEC
)
5178 if (GET_CODE (pat
) == ASM_INPUT
|| asm_noperands (pat
) >= 0)
5180 np_check_regno
= -1;
5186 /* Is this a condjump based on a null pointer comparison we saw
5188 if (np_check_regno
!= -1
5189 && recog_memoized (insn
) == CODE_FOR_cbranchbi4
)
5191 rtx op
= XEXP (SET_SRC (PATTERN (insn
)), 0);
5192 gcc_assert (GET_CODE (op
) == EQ
|| GET_CODE (op
) == NE
);
5193 if (GET_CODE (op
) == NE
)
5194 np_after_branch
= true;
5196 if (any_condjump_p (insn
)
5197 && ! cbranch_predicted_taken_p (insn
))
5199 last_condjump
= insn
;
5201 cycles_since_jump
= 0;
5204 cycles_since_jump
= INT_MAX
;
5206 else if (CALL_P (insn
))
5208 np_check_regno
= -1;
5209 if (cycles_since_jump
< INT_MAX
)
5210 cycles_since_jump
++;
5211 if (indirect_call_p (pat
) && ENABLE_WA_INDIRECT_CALLS
)
5216 else if (NONDEBUG_INSN_P (insn
))
5218 rtx load_insn
= find_load (insn
);
5219 enum attr_type type
= type_for_anomaly (insn
);
5221 if (cycles_since_jump
< INT_MAX
)
5222 cycles_since_jump
++;
5224 /* Detect a comparison of a P register with zero. If we later
5225 see a condjump based on it, we have found a null pointer
5227 if (recog_memoized (insn
) == CODE_FOR_compare_eq
)
5229 rtx src
= SET_SRC (PATTERN (insn
));
5230 if (REG_P (XEXP (src
, 0))
5231 && P_REGNO_P (REGNO (XEXP (src
, 0)))
5232 && XEXP (src
, 1) == const0_rtx
)
5234 np_check_regno
= REGNO (XEXP (src
, 0));
5235 np_after_branch
= false;
5238 np_check_regno
= -1;
5241 if (load_insn
&& ENABLE_WA_SPECULATIVE_LOADS
)
5243 if (trapping_loads_p (load_insn
, np_check_regno
,
5247 else if (type
== TYPE_SYNC
&& ENABLE_WA_SPECULATIVE_SYNCS
)
5250 /* See if we need to forget about a null pointer comparison
5251 we found earlier. */
5252 if (recog_memoized (insn
) != CODE_FOR_compare_eq
)
5254 note_stores (PATTERN (insn
), note_np_check_stores
, NULL
);
5255 if (np_check_regno
!= -1)
5257 if (find_regno_note (insn
, REG_INC
, np_check_regno
))
5258 np_check_regno
= -1;
5264 if (delay_needed
> cycles_since_jump
5265 && (delay_needed
- cycles_since_jump
) > delay_added
)
5269 rtx
*op
= recog_data
.operand
;
5271 delay_needed
-= cycles_since_jump
;
5273 extract_insn (last_condjump
);
5276 pat1
= gen_cbranch_predicted_taken (op
[0], op
[1], op
[2],
5278 cycles_since_jump
= INT_MAX
;
5282 /* Do not adjust cycles_since_jump in this case, so that
5283 we'll increase the number of NOPs for a subsequent insn
5285 pat1
= gen_cbranch_with_nops (op
[0], op
[1], op
[2], op
[3],
5286 GEN_INT (delay_needed
));
5287 delay_added
= delay_needed
;
5289 PATTERN (last_condjump
) = pat1
;
5290 INSN_CODE (last_condjump
) = recog (pat1
, insn
, &num_clobbers
);
5294 cycles_since_jump
= INT_MAX
;
5299 /* Second pass: for predicted-true branches, see if anything at the
5300 branch destination needs extra nops. */
5301 for (insn
= get_insns (); insn
; insn
= NEXT_INSN (insn
))
5303 int cycles_since_jump
;
5305 && any_condjump_p (insn
)
5306 && (INSN_CODE (insn
) == CODE_FOR_cbranch_predicted_taken
5307 || cbranch_predicted_taken_p (insn
)))
5309 rtx target
= JUMP_LABEL (insn
);
5313 cycles_since_jump
= 0;
5314 for (; target
&& cycles_since_jump
< 3; target
= next_tgt
)
5318 next_tgt
= find_next_insn_start (target
);
5320 if (NOTE_P (target
) || BARRIER_P (target
) || LABEL_P (target
))
5323 pat
= PATTERN (target
);
5324 if (GET_CODE (pat
) == USE
|| GET_CODE (pat
) == CLOBBER
5325 || GET_CODE (pat
) == ASM_INPUT
|| GET_CODE (pat
) == ADDR_VEC
5326 || GET_CODE (pat
) == ADDR_DIFF_VEC
|| asm_noperands (pat
) >= 0)
5329 if (NONDEBUG_INSN_P (target
))
5331 rtx load_insn
= find_load (target
);
5332 enum attr_type type
= type_for_anomaly (target
);
5333 int delay_needed
= 0;
5334 if (cycles_since_jump
< INT_MAX
)
5335 cycles_since_jump
++;
5337 if (load_insn
&& ENABLE_WA_SPECULATIVE_LOADS
)
5339 if (trapping_loads_p (load_insn
, -1, false))
5342 else if (type
== TYPE_SYNC
&& ENABLE_WA_SPECULATIVE_SYNCS
)
5345 if (delay_needed
> cycles_since_jump
)
5347 rtx prev
= prev_real_insn (label
);
5348 delay_needed
-= cycles_since_jump
;
5350 fprintf (dump_file
, "Adding %d nops after %d\n",
5351 delay_needed
, INSN_UID (label
));
5353 && INSN_CODE (prev
) == CODE_FOR_cbranch_with_nops
)
5360 "Reducing nops on insn %d.\n",
5363 x
= XVECEXP (x
, 0, 1);
5364 v
= INTVAL (XVECEXP (x
, 0, 0)) - delay_needed
;
5365 XVECEXP (x
, 0, 0) = GEN_INT (v
);
5367 while (delay_needed
-- > 0)
5368 emit_insn_after (gen_nop (), label
);
5377 /* Called just before the final scheduling pass. If we need to insert NOPs
5378 later on to work around speculative loads, insert special placeholder
5379 insns that cause loads to be delayed for as many cycles as necessary
5380 (and possible). This reduces the number of NOPs we need to add.
5381 The dummy insns we generate are later removed by bfin_gen_bundles. */
5383 add_sched_insns_for_speculation (void)
5387 if (! ENABLE_WA_SPECULATIVE_LOADS
&& ! ENABLE_WA_SPECULATIVE_SYNCS
5388 && ! ENABLE_WA_INDIRECT_CALLS
)
5391 /* First pass: find predicted-false branches; if something after them
5392 needs nops, insert them or change the branch to predict true. */
5393 for (insn
= get_insns (); insn
; insn
= NEXT_INSN (insn
))
5397 if (NOTE_P (insn
) || BARRIER_P (insn
) || LABEL_P (insn
))
5400 pat
= PATTERN (insn
);
5401 if (GET_CODE (pat
) == USE
|| GET_CODE (pat
) == CLOBBER
5402 || GET_CODE (pat
) == ASM_INPUT
|| GET_CODE (pat
) == ADDR_VEC
5403 || GET_CODE (pat
) == ADDR_DIFF_VEC
|| asm_noperands (pat
) >= 0)
5408 if (any_condjump_p (insn
)
5409 && !cbranch_predicted_taken_p (insn
))
5411 rtx n
= next_real_insn (insn
);
5412 emit_insn_before (gen_stall (GEN_INT (3)), n
);
5417 /* Second pass: for predicted-true branches, see if anything at the
5418 branch destination needs extra nops. */
5419 for (insn
= get_insns (); insn
; insn
= NEXT_INSN (insn
))
5422 && any_condjump_p (insn
)
5423 && (cbranch_predicted_taken_p (insn
)))
5425 rtx target
= JUMP_LABEL (insn
);
5426 rtx next
= next_real_insn (target
);
5428 if (GET_CODE (PATTERN (next
)) == UNSPEC_VOLATILE
5429 && get_attr_type (next
) == TYPE_STALL
)
5431 emit_insn_before (gen_stall (GEN_INT (1)), next
);
5436 /* We use the machine specific reorg pass for emitting CSYNC instructions
5437 after conditional branches as needed.
5439 The Blackfin is unusual in that a code sequence like
5442 may speculatively perform the load even if the condition isn't true. This
5443 happens for a branch that is predicted not taken, because the pipeline
5444 isn't flushed or stalled, so the early stages of the following instructions,
5445 which perform the memory reference, are allowed to execute before the
5446 jump condition is evaluated.
5447 Therefore, we must insert additional instructions in all places where this
5448 could lead to incorrect behavior. The manual recommends CSYNC, while
5449 VDSP seems to use NOPs (even though its corresponding compiler option is
5452 When optimizing for speed, we emit NOPs, which seems faster than a CSYNC.
5453 When optimizing for size, we turn the branch into a predicted taken one.
5454 This may be slower due to mispredicts, but saves code size. */
5459 /* We are freeing block_for_insn in the toplev to keep compatibility
5460 with old MDEP_REORGS that are not CFG based. Recompute it now. */
5461 compute_bb_for_insn ();
5463 if (bfin_flag_schedule_insns2
)
5465 splitting_for_sched
= 1;
5467 splitting_for_sched
= 0;
5469 add_sched_insns_for_speculation ();
5471 timevar_push (TV_SCHED2
);
5473 timevar_pop (TV_SCHED2
);
5475 /* Examine the schedule and insert nops as necessary for 64-bit parallel
5477 bfin_gen_bundles ();
5482 /* Doloop optimization */
5483 if (cfun
->machine
->has_hardware_loops
)
5484 bfin_reorg_loops (dump_file
);
5486 workaround_speculation ();
5488 if (bfin_flag_var_tracking
)
5490 timevar_push (TV_VAR_TRACKING
);
5491 variable_tracking_main ();
5492 reorder_var_tracking_notes ();
5493 timevar_pop (TV_VAR_TRACKING
);
5496 df_finish_pass (false);
5498 workaround_rts_anomaly ();
5501 /* Handle interrupt_handler, exception_handler and nmi_handler function
5502 attributes; arguments as in struct attribute_spec.handler. */
5505 handle_int_attribute (tree
*node
, tree name
,
5506 tree args ATTRIBUTE_UNUSED
,
5507 int flags ATTRIBUTE_UNUSED
,
5511 if (TREE_CODE (x
) == FUNCTION_DECL
)
5514 if (TREE_CODE (x
) != FUNCTION_TYPE
)
5516 warning (OPT_Wattributes
, "%qE attribute only applies to functions",
5518 *no_add_attrs
= true;
5520 else if (funkind (x
) != SUBROUTINE
)
5521 error ("multiple function type attributes specified");
5526 /* Return 0 if the attributes for two types are incompatible, 1 if they
5527 are compatible, and 2 if they are nearly compatible (which causes a
5528 warning to be generated). */
5531 bfin_comp_type_attributes (const_tree type1
, const_tree type2
)
5533 e_funkind kind1
, kind2
;
5535 if (TREE_CODE (type1
) != FUNCTION_TYPE
)
5538 kind1
= funkind (type1
);
5539 kind2
= funkind (type2
);
5544 /* Check for mismatched modifiers */
5545 if (!lookup_attribute ("nesting", TYPE_ATTRIBUTES (type1
))
5546 != !lookup_attribute ("nesting", TYPE_ATTRIBUTES (type2
)))
5549 if (!lookup_attribute ("saveall", TYPE_ATTRIBUTES (type1
))
5550 != !lookup_attribute ("saveall", TYPE_ATTRIBUTES (type2
)))
5553 if (!lookup_attribute ("kspisusp", TYPE_ATTRIBUTES (type1
))
5554 != !lookup_attribute ("kspisusp", TYPE_ATTRIBUTES (type2
)))
5557 if (!lookup_attribute ("longcall", TYPE_ATTRIBUTES (type1
))
5558 != !lookup_attribute ("longcall", TYPE_ATTRIBUTES (type2
)))
5564 /* Handle a "longcall" or "shortcall" attribute; arguments as in
5565 struct attribute_spec.handler. */
5568 bfin_handle_longcall_attribute (tree
*node
, tree name
,
5569 tree args ATTRIBUTE_UNUSED
,
5570 int flags ATTRIBUTE_UNUSED
,
5573 if (TREE_CODE (*node
) != FUNCTION_TYPE
5574 && TREE_CODE (*node
) != FIELD_DECL
5575 && TREE_CODE (*node
) != TYPE_DECL
)
5577 warning (OPT_Wattributes
, "%qE attribute only applies to functions",
5579 *no_add_attrs
= true;
5582 if ((strcmp (IDENTIFIER_POINTER (name
), "longcall") == 0
5583 && lookup_attribute ("shortcall", TYPE_ATTRIBUTES (*node
)))
5584 || (strcmp (IDENTIFIER_POINTER (name
), "shortcall") == 0
5585 && lookup_attribute ("longcall", TYPE_ATTRIBUTES (*node
))))
5587 warning (OPT_Wattributes
,
5588 "can't apply both longcall and shortcall attributes to the same function");
5589 *no_add_attrs
= true;
5595 /* Handle a "l1_text" attribute; arguments as in
5596 struct attribute_spec.handler. */
5599 bfin_handle_l1_text_attribute (tree
*node
, tree name
, tree
ARG_UNUSED (args
),
5600 int ARG_UNUSED (flags
), bool *no_add_attrs
)
5604 if (TREE_CODE (decl
) != FUNCTION_DECL
)
5606 error ("%qE attribute only applies to functions",
5608 *no_add_attrs
= true;
5611 /* The decl may have already been given a section attribute
5612 from a previous declaration. Ensure they match. */
5613 else if (DECL_SECTION_NAME (decl
) != NULL_TREE
5614 && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl
)),
5617 error ("section of %q+D conflicts with previous declaration",
5619 *no_add_attrs
= true;
5622 DECL_SECTION_NAME (decl
) = build_string (9, ".l1.text");
5627 /* Handle a "l1_data", "l1_data_A" or "l1_data_B" attribute;
5628 arguments as in struct attribute_spec.handler. */
5631 bfin_handle_l1_data_attribute (tree
*node
, tree name
, tree
ARG_UNUSED (args
),
5632 int ARG_UNUSED (flags
), bool *no_add_attrs
)
5636 if (TREE_CODE (decl
) != VAR_DECL
)
5638 error ("%qE attribute only applies to variables",
5640 *no_add_attrs
= true;
5642 else if (current_function_decl
!= NULL_TREE
5643 && !TREE_STATIC (decl
))
5645 error ("%qE attribute cannot be specified for local variables",
5647 *no_add_attrs
= true;
5651 const char *section_name
;
5653 if (strcmp (IDENTIFIER_POINTER (name
), "l1_data") == 0)
5654 section_name
= ".l1.data";
5655 else if (strcmp (IDENTIFIER_POINTER (name
), "l1_data_A") == 0)
5656 section_name
= ".l1.data.A";
5657 else if (strcmp (IDENTIFIER_POINTER (name
), "l1_data_B") == 0)
5658 section_name
= ".l1.data.B";
5662 /* The decl may have already been given a section attribute
5663 from a previous declaration. Ensure they match. */
5664 if (DECL_SECTION_NAME (decl
) != NULL_TREE
5665 && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl
)),
5668 error ("section of %q+D conflicts with previous declaration",
5670 *no_add_attrs
= true;
5673 DECL_SECTION_NAME (decl
)
5674 = build_string (strlen (section_name
) + 1, section_name
);
5680 /* Handle a "l2" attribute; arguments as in struct attribute_spec.handler. */
5683 bfin_handle_l2_attribute (tree
*node
, tree
ARG_UNUSED (name
),
5684 tree
ARG_UNUSED (args
), int ARG_UNUSED (flags
),
5689 if (TREE_CODE (decl
) == FUNCTION_DECL
)
5691 if (DECL_SECTION_NAME (decl
) != NULL_TREE
5692 && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl
)),
5695 error ("section of %q+D conflicts with previous declaration",
5697 *no_add_attrs
= true;
5700 DECL_SECTION_NAME (decl
) = build_string (9, ".l2.text");
5702 else if (TREE_CODE (decl
) == VAR_DECL
)
5704 if (DECL_SECTION_NAME (decl
) != NULL_TREE
5705 && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl
)),
5708 error ("section of %q+D conflicts with previous declaration",
5710 *no_add_attrs
= true;
5713 DECL_SECTION_NAME (decl
) = build_string (9, ".l2.data");
5719 /* Table of valid machine attributes. */
5720 static const struct attribute_spec bfin_attribute_table
[] =
5722 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
5723 { "interrupt_handler", 0, 0, false, true, true, handle_int_attribute
},
5724 { "exception_handler", 0, 0, false, true, true, handle_int_attribute
},
5725 { "nmi_handler", 0, 0, false, true, true, handle_int_attribute
},
5726 { "nesting", 0, 0, false, true, true, NULL
},
5727 { "kspisusp", 0, 0, false, true, true, NULL
},
5728 { "saveall", 0, 0, false, true, true, NULL
},
5729 { "longcall", 0, 0, false, true, true, bfin_handle_longcall_attribute
},
5730 { "shortcall", 0, 0, false, true, true, bfin_handle_longcall_attribute
},
5731 { "l1_text", 0, 0, true, false, false, bfin_handle_l1_text_attribute
},
5732 { "l1_data", 0, 0, true, false, false, bfin_handle_l1_data_attribute
},
5733 { "l1_data_A", 0, 0, true, false, false, bfin_handle_l1_data_attribute
},
5734 { "l1_data_B", 0, 0, true, false, false, bfin_handle_l1_data_attribute
},
5735 { "l2", 0, 0, true, false, false, bfin_handle_l2_attribute
},
5736 { NULL
, 0, 0, false, false, false, NULL
}
5739 /* Implementation of TARGET_ASM_INTEGER. When using FD-PIC, we need to
5740 tell the assembler to generate pointers to function descriptors in
5744 bfin_assemble_integer (rtx value
, unsigned int size
, int aligned_p
)
5746 if (TARGET_FDPIC
&& size
== UNITS_PER_WORD
)
5748 if (GET_CODE (value
) == SYMBOL_REF
5749 && SYMBOL_REF_FUNCTION_P (value
))
5751 fputs ("\t.picptr\tfuncdesc(", asm_out_file
);
5752 output_addr_const (asm_out_file
, value
);
5753 fputs (")\n", asm_out_file
);
5758 /* We've set the unaligned SI op to NULL, so we always have to
5759 handle the unaligned case here. */
5760 assemble_integer_with_op ("\t.4byte\t", value
);
5764 return default_assemble_integer (value
, size
, aligned_p
);
5767 /* Output the assembler code for a thunk function. THUNK_DECL is the
5768 declaration for the thunk function itself, FUNCTION is the decl for
5769 the target function. DELTA is an immediate constant offset to be
5770 added to THIS. If VCALL_OFFSET is nonzero, the word at
5771 *(*this + vcall_offset) should be added to THIS. */
5774 bfin_output_mi_thunk (FILE *file ATTRIBUTE_UNUSED
,
5775 tree thunk ATTRIBUTE_UNUSED
, HOST_WIDE_INT delta
,
5776 HOST_WIDE_INT vcall_offset
, tree function
)
5779 /* The this parameter is passed as the first argument. */
5780 rtx this_rtx
= gen_rtx_REG (Pmode
, REG_R0
);
5782 /* Adjust the this parameter by a fixed constant. */
5786 if (delta
>= -64 && delta
<= 63)
5788 xops
[0] = GEN_INT (delta
);
5789 output_asm_insn ("%1 += %0;", xops
);
5791 else if (delta
>= -128 && delta
< -64)
5793 xops
[0] = GEN_INT (delta
+ 64);
5794 output_asm_insn ("%1 += -64; %1 += %0;", xops
);
5796 else if (delta
> 63 && delta
<= 126)
5798 xops
[0] = GEN_INT (delta
- 63);
5799 output_asm_insn ("%1 += 63; %1 += %0;", xops
);
5803 xops
[0] = GEN_INT (delta
);
5804 output_asm_insn ("r3.l = %h0; r3.h = %d0; %1 = %1 + r3;", xops
);
5808 /* Adjust the this parameter by a value stored in the vtable. */
5811 rtx p2tmp
= gen_rtx_REG (Pmode
, REG_P2
);
5812 rtx tmp
= gen_rtx_REG (Pmode
, REG_R3
);
5816 output_asm_insn ("%2 = r0; %2 = [%2];", xops
);
5818 /* Adjust the this parameter. */
5819 xops
[0] = gen_rtx_MEM (Pmode
, plus_constant (p2tmp
, vcall_offset
));
5820 if (!memory_operand (xops
[0], Pmode
))
5822 rtx tmp2
= gen_rtx_REG (Pmode
, REG_P1
);
5823 xops
[0] = GEN_INT (vcall_offset
);
5825 output_asm_insn ("%h1 = %h0; %d1 = %d0; %2 = %2 + %1", xops
);
5826 xops
[0] = gen_rtx_MEM (Pmode
, p2tmp
);
5829 output_asm_insn ("%1 = %0; %2 = %2 + %1;", xops
);
5832 xops
[0] = XEXP (DECL_RTL (function
), 0);
5833 if (1 || !flag_pic
|| (*targetm
.binds_local_p
) (function
))
5834 output_asm_insn ("jump.l\t%P0", xops
);
5837 /* Codes for all the Blackfin builtins. */
5843 BFIN_BUILTIN_COMPOSE_2X16
,
5844 BFIN_BUILTIN_EXTRACTLO
,
5845 BFIN_BUILTIN_EXTRACTHI
,
5847 BFIN_BUILTIN_SSADD_2X16
,
5848 BFIN_BUILTIN_SSSUB_2X16
,
5849 BFIN_BUILTIN_SSADDSUB_2X16
,
5850 BFIN_BUILTIN_SSSUBADD_2X16
,
5851 BFIN_BUILTIN_MULT_2X16
,
5852 BFIN_BUILTIN_MULTR_2X16
,
5853 BFIN_BUILTIN_NEG_2X16
,
5854 BFIN_BUILTIN_ABS_2X16
,
5855 BFIN_BUILTIN_MIN_2X16
,
5856 BFIN_BUILTIN_MAX_2X16
,
5858 BFIN_BUILTIN_SSADD_1X16
,
5859 BFIN_BUILTIN_SSSUB_1X16
,
5860 BFIN_BUILTIN_MULT_1X16
,
5861 BFIN_BUILTIN_MULTR_1X16
,
5862 BFIN_BUILTIN_NORM_1X16
,
5863 BFIN_BUILTIN_NEG_1X16
,
5864 BFIN_BUILTIN_ABS_1X16
,
5865 BFIN_BUILTIN_MIN_1X16
,
5866 BFIN_BUILTIN_MAX_1X16
,
5868 BFIN_BUILTIN_SUM_2X16
,
5869 BFIN_BUILTIN_DIFFHL_2X16
,
5870 BFIN_BUILTIN_DIFFLH_2X16
,
5872 BFIN_BUILTIN_SSADD_1X32
,
5873 BFIN_BUILTIN_SSSUB_1X32
,
5874 BFIN_BUILTIN_NORM_1X32
,
5875 BFIN_BUILTIN_ROUND_1X32
,
5876 BFIN_BUILTIN_NEG_1X32
,
5877 BFIN_BUILTIN_ABS_1X32
,
5878 BFIN_BUILTIN_MIN_1X32
,
5879 BFIN_BUILTIN_MAX_1X32
,
5880 BFIN_BUILTIN_MULT_1X32
,
5881 BFIN_BUILTIN_MULT_1X32X32
,
5882 BFIN_BUILTIN_MULT_1X32X32NS
,
5884 BFIN_BUILTIN_MULHISILL
,
5885 BFIN_BUILTIN_MULHISILH
,
5886 BFIN_BUILTIN_MULHISIHL
,
5887 BFIN_BUILTIN_MULHISIHH
,
5889 BFIN_BUILTIN_LSHIFT_1X16
,
5890 BFIN_BUILTIN_LSHIFT_2X16
,
5891 BFIN_BUILTIN_SSASHIFT_1X16
,
5892 BFIN_BUILTIN_SSASHIFT_2X16
,
5893 BFIN_BUILTIN_SSASHIFT_1X32
,
5895 BFIN_BUILTIN_CPLX_MUL_16
,
5896 BFIN_BUILTIN_CPLX_MAC_16
,
5897 BFIN_BUILTIN_CPLX_MSU_16
,
5899 BFIN_BUILTIN_CPLX_MUL_16_S40
,
5900 BFIN_BUILTIN_CPLX_MAC_16_S40
,
5901 BFIN_BUILTIN_CPLX_MSU_16_S40
,
5903 BFIN_BUILTIN_CPLX_SQU
,
5905 BFIN_BUILTIN_LOADBYTES
,
5910 #define def_builtin(NAME, TYPE, CODE) \
5912 add_builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD, \
5916 /* Set up all builtin functions for this target. */
5918 bfin_init_builtins (void)
5920 tree V2HI_type_node
= build_vector_type_for_mode (intHI_type_node
, V2HImode
);
5921 tree void_ftype_void
5922 = build_function_type (void_type_node
, void_list_node
);
5923 tree short_ftype_short
5924 = build_function_type_list (short_integer_type_node
, short_integer_type_node
,
5926 tree short_ftype_int_int
5927 = build_function_type_list (short_integer_type_node
, integer_type_node
,
5928 integer_type_node
, NULL_TREE
);
5929 tree int_ftype_int_int
5930 = build_function_type_list (integer_type_node
, integer_type_node
,
5931 integer_type_node
, NULL_TREE
);
5933 = build_function_type_list (integer_type_node
, integer_type_node
,
5935 tree short_ftype_int
5936 = build_function_type_list (short_integer_type_node
, integer_type_node
,
5938 tree int_ftype_v2hi_v2hi
5939 = build_function_type_list (integer_type_node
, V2HI_type_node
,
5940 V2HI_type_node
, NULL_TREE
);
5941 tree v2hi_ftype_v2hi_v2hi
5942 = build_function_type_list (V2HI_type_node
, V2HI_type_node
,
5943 V2HI_type_node
, NULL_TREE
);
5944 tree v2hi_ftype_v2hi_v2hi_v2hi
5945 = build_function_type_list (V2HI_type_node
, V2HI_type_node
,
5946 V2HI_type_node
, V2HI_type_node
, NULL_TREE
);
5947 tree v2hi_ftype_int_int
5948 = build_function_type_list (V2HI_type_node
, integer_type_node
,
5949 integer_type_node
, NULL_TREE
);
5950 tree v2hi_ftype_v2hi_int
5951 = build_function_type_list (V2HI_type_node
, V2HI_type_node
,
5952 integer_type_node
, NULL_TREE
);
5953 tree int_ftype_short_short
5954 = build_function_type_list (integer_type_node
, short_integer_type_node
,
5955 short_integer_type_node
, NULL_TREE
);
5956 tree v2hi_ftype_v2hi
5957 = build_function_type_list (V2HI_type_node
, V2HI_type_node
, NULL_TREE
);
5958 tree short_ftype_v2hi
5959 = build_function_type_list (short_integer_type_node
, V2HI_type_node
,
5962 = build_function_type_list (integer_type_node
,
5963 build_pointer_type (integer_type_node
),
5966 /* Add the remaining MMX insns with somewhat more complicated types. */
5967 def_builtin ("__builtin_bfin_csync", void_ftype_void
, BFIN_BUILTIN_CSYNC
);
5968 def_builtin ("__builtin_bfin_ssync", void_ftype_void
, BFIN_BUILTIN_SSYNC
);
5970 def_builtin ("__builtin_bfin_ones", short_ftype_int
, BFIN_BUILTIN_ONES
);
5972 def_builtin ("__builtin_bfin_compose_2x16", v2hi_ftype_int_int
,
5973 BFIN_BUILTIN_COMPOSE_2X16
);
5974 def_builtin ("__builtin_bfin_extract_hi", short_ftype_v2hi
,
5975 BFIN_BUILTIN_EXTRACTHI
);
5976 def_builtin ("__builtin_bfin_extract_lo", short_ftype_v2hi
,
5977 BFIN_BUILTIN_EXTRACTLO
);
5979 def_builtin ("__builtin_bfin_min_fr2x16", v2hi_ftype_v2hi_v2hi
,
5980 BFIN_BUILTIN_MIN_2X16
);
5981 def_builtin ("__builtin_bfin_max_fr2x16", v2hi_ftype_v2hi_v2hi
,
5982 BFIN_BUILTIN_MAX_2X16
);
5984 def_builtin ("__builtin_bfin_add_fr2x16", v2hi_ftype_v2hi_v2hi
,
5985 BFIN_BUILTIN_SSADD_2X16
);
5986 def_builtin ("__builtin_bfin_sub_fr2x16", v2hi_ftype_v2hi_v2hi
,
5987 BFIN_BUILTIN_SSSUB_2X16
);
5988 def_builtin ("__builtin_bfin_dspaddsubsat", v2hi_ftype_v2hi_v2hi
,
5989 BFIN_BUILTIN_SSADDSUB_2X16
);
5990 def_builtin ("__builtin_bfin_dspsubaddsat", v2hi_ftype_v2hi_v2hi
,
5991 BFIN_BUILTIN_SSSUBADD_2X16
);
5992 def_builtin ("__builtin_bfin_mult_fr2x16", v2hi_ftype_v2hi_v2hi
,
5993 BFIN_BUILTIN_MULT_2X16
);
5994 def_builtin ("__builtin_bfin_multr_fr2x16", v2hi_ftype_v2hi_v2hi
,
5995 BFIN_BUILTIN_MULTR_2X16
);
5996 def_builtin ("__builtin_bfin_negate_fr2x16", v2hi_ftype_v2hi
,
5997 BFIN_BUILTIN_NEG_2X16
);
5998 def_builtin ("__builtin_bfin_abs_fr2x16", v2hi_ftype_v2hi
,
5999 BFIN_BUILTIN_ABS_2X16
);
6001 def_builtin ("__builtin_bfin_min_fr1x16", short_ftype_int_int
,
6002 BFIN_BUILTIN_MIN_1X16
);
6003 def_builtin ("__builtin_bfin_max_fr1x16", short_ftype_int_int
,
6004 BFIN_BUILTIN_MAX_1X16
);
6006 def_builtin ("__builtin_bfin_add_fr1x16", short_ftype_int_int
,
6007 BFIN_BUILTIN_SSADD_1X16
);
6008 def_builtin ("__builtin_bfin_sub_fr1x16", short_ftype_int_int
,
6009 BFIN_BUILTIN_SSSUB_1X16
);
6010 def_builtin ("__builtin_bfin_mult_fr1x16", short_ftype_int_int
,
6011 BFIN_BUILTIN_MULT_1X16
);
6012 def_builtin ("__builtin_bfin_multr_fr1x16", short_ftype_int_int
,
6013 BFIN_BUILTIN_MULTR_1X16
);
6014 def_builtin ("__builtin_bfin_negate_fr1x16", short_ftype_short
,
6015 BFIN_BUILTIN_NEG_1X16
);
6016 def_builtin ("__builtin_bfin_abs_fr1x16", short_ftype_short
,
6017 BFIN_BUILTIN_ABS_1X16
);
6018 def_builtin ("__builtin_bfin_norm_fr1x16", short_ftype_int
,
6019 BFIN_BUILTIN_NORM_1X16
);
6021 def_builtin ("__builtin_bfin_sum_fr2x16", short_ftype_v2hi
,
6022 BFIN_BUILTIN_SUM_2X16
);
6023 def_builtin ("__builtin_bfin_diff_hl_fr2x16", short_ftype_v2hi
,
6024 BFIN_BUILTIN_DIFFHL_2X16
);
6025 def_builtin ("__builtin_bfin_diff_lh_fr2x16", short_ftype_v2hi
,
6026 BFIN_BUILTIN_DIFFLH_2X16
);
6028 def_builtin ("__builtin_bfin_mulhisill", int_ftype_v2hi_v2hi
,
6029 BFIN_BUILTIN_MULHISILL
);
6030 def_builtin ("__builtin_bfin_mulhisihl", int_ftype_v2hi_v2hi
,
6031 BFIN_BUILTIN_MULHISIHL
);
6032 def_builtin ("__builtin_bfin_mulhisilh", int_ftype_v2hi_v2hi
,
6033 BFIN_BUILTIN_MULHISILH
);
6034 def_builtin ("__builtin_bfin_mulhisihh", int_ftype_v2hi_v2hi
,
6035 BFIN_BUILTIN_MULHISIHH
);
6037 def_builtin ("__builtin_bfin_min_fr1x32", int_ftype_int_int
,
6038 BFIN_BUILTIN_MIN_1X32
);
6039 def_builtin ("__builtin_bfin_max_fr1x32", int_ftype_int_int
,
6040 BFIN_BUILTIN_MAX_1X32
);
6042 def_builtin ("__builtin_bfin_add_fr1x32", int_ftype_int_int
,
6043 BFIN_BUILTIN_SSADD_1X32
);
6044 def_builtin ("__builtin_bfin_sub_fr1x32", int_ftype_int_int
,
6045 BFIN_BUILTIN_SSSUB_1X32
);
6046 def_builtin ("__builtin_bfin_negate_fr1x32", int_ftype_int
,
6047 BFIN_BUILTIN_NEG_1X32
);
6048 def_builtin ("__builtin_bfin_abs_fr1x32", int_ftype_int
,
6049 BFIN_BUILTIN_ABS_1X32
);
6050 def_builtin ("__builtin_bfin_norm_fr1x32", short_ftype_int
,
6051 BFIN_BUILTIN_NORM_1X32
);
6052 def_builtin ("__builtin_bfin_round_fr1x32", short_ftype_int
,
6053 BFIN_BUILTIN_ROUND_1X32
);
6054 def_builtin ("__builtin_bfin_mult_fr1x32", int_ftype_short_short
,
6055 BFIN_BUILTIN_MULT_1X32
);
6056 def_builtin ("__builtin_bfin_mult_fr1x32x32", int_ftype_int_int
,
6057 BFIN_BUILTIN_MULT_1X32X32
);
6058 def_builtin ("__builtin_bfin_mult_fr1x32x32NS", int_ftype_int_int
,
6059 BFIN_BUILTIN_MULT_1X32X32NS
);
6062 def_builtin ("__builtin_bfin_shl_fr1x16", short_ftype_int_int
,
6063 BFIN_BUILTIN_SSASHIFT_1X16
);
6064 def_builtin ("__builtin_bfin_shl_fr2x16", v2hi_ftype_v2hi_int
,
6065 BFIN_BUILTIN_SSASHIFT_2X16
);
6066 def_builtin ("__builtin_bfin_lshl_fr1x16", short_ftype_int_int
,
6067 BFIN_BUILTIN_LSHIFT_1X16
);
6068 def_builtin ("__builtin_bfin_lshl_fr2x16", v2hi_ftype_v2hi_int
,
6069 BFIN_BUILTIN_LSHIFT_2X16
);
6070 def_builtin ("__builtin_bfin_shl_fr1x32", int_ftype_int_int
,
6071 BFIN_BUILTIN_SSASHIFT_1X32
);
6073 /* Complex numbers. */
6074 def_builtin ("__builtin_bfin_cmplx_add", v2hi_ftype_v2hi_v2hi
,
6075 BFIN_BUILTIN_SSADD_2X16
);
6076 def_builtin ("__builtin_bfin_cmplx_sub", v2hi_ftype_v2hi_v2hi
,
6077 BFIN_BUILTIN_SSSUB_2X16
);
6078 def_builtin ("__builtin_bfin_cmplx_mul", v2hi_ftype_v2hi_v2hi
,
6079 BFIN_BUILTIN_CPLX_MUL_16
);
6080 def_builtin ("__builtin_bfin_cmplx_mac", v2hi_ftype_v2hi_v2hi_v2hi
,
6081 BFIN_BUILTIN_CPLX_MAC_16
);
6082 def_builtin ("__builtin_bfin_cmplx_msu", v2hi_ftype_v2hi_v2hi_v2hi
,
6083 BFIN_BUILTIN_CPLX_MSU_16
);
6084 def_builtin ("__builtin_bfin_cmplx_mul_s40", v2hi_ftype_v2hi_v2hi
,
6085 BFIN_BUILTIN_CPLX_MUL_16_S40
);
6086 def_builtin ("__builtin_bfin_cmplx_mac_s40", v2hi_ftype_v2hi_v2hi_v2hi
,
6087 BFIN_BUILTIN_CPLX_MAC_16_S40
);
6088 def_builtin ("__builtin_bfin_cmplx_msu_s40", v2hi_ftype_v2hi_v2hi_v2hi
,
6089 BFIN_BUILTIN_CPLX_MSU_16_S40
);
6090 def_builtin ("__builtin_bfin_csqu_fr16", v2hi_ftype_v2hi
,
6091 BFIN_BUILTIN_CPLX_SQU
);
6093 /* "Unaligned" load. */
6094 def_builtin ("__builtin_bfin_loadbytes", int_ftype_pint
,
6095 BFIN_BUILTIN_LOADBYTES
);
6100 struct builtin_description
6102 const enum insn_code icode
;
6103 const char *const name
;
6104 const enum bfin_builtins code
;
6108 static const struct builtin_description bdesc_2arg
[] =
6110 { CODE_FOR_composev2hi
, "__builtin_bfin_compose_2x16", BFIN_BUILTIN_COMPOSE_2X16
, -1 },
6112 { CODE_FOR_ssashiftv2hi3
, "__builtin_bfin_shl_fr2x16", BFIN_BUILTIN_SSASHIFT_2X16
, -1 },
6113 { CODE_FOR_ssashifthi3
, "__builtin_bfin_shl_fr1x16", BFIN_BUILTIN_SSASHIFT_1X16
, -1 },
6114 { CODE_FOR_lshiftv2hi3
, "__builtin_bfin_lshl_fr2x16", BFIN_BUILTIN_LSHIFT_2X16
, -1 },
6115 { CODE_FOR_lshifthi3
, "__builtin_bfin_lshl_fr1x16", BFIN_BUILTIN_LSHIFT_1X16
, -1 },
6116 { CODE_FOR_ssashiftsi3
, "__builtin_bfin_shl_fr1x32", BFIN_BUILTIN_SSASHIFT_1X32
, -1 },
6118 { CODE_FOR_sminhi3
, "__builtin_bfin_min_fr1x16", BFIN_BUILTIN_MIN_1X16
, -1 },
6119 { CODE_FOR_smaxhi3
, "__builtin_bfin_max_fr1x16", BFIN_BUILTIN_MAX_1X16
, -1 },
6120 { CODE_FOR_ssaddhi3
, "__builtin_bfin_add_fr1x16", BFIN_BUILTIN_SSADD_1X16
, -1 },
6121 { CODE_FOR_sssubhi3
, "__builtin_bfin_sub_fr1x16", BFIN_BUILTIN_SSSUB_1X16
, -1 },
6123 { CODE_FOR_sminsi3
, "__builtin_bfin_min_fr1x32", BFIN_BUILTIN_MIN_1X32
, -1 },
6124 { CODE_FOR_smaxsi3
, "__builtin_bfin_max_fr1x32", BFIN_BUILTIN_MAX_1X32
, -1 },
6125 { CODE_FOR_ssaddsi3
, "__builtin_bfin_add_fr1x32", BFIN_BUILTIN_SSADD_1X32
, -1 },
6126 { CODE_FOR_sssubsi3
, "__builtin_bfin_sub_fr1x32", BFIN_BUILTIN_SSSUB_1X32
, -1 },
6128 { CODE_FOR_sminv2hi3
, "__builtin_bfin_min_fr2x16", BFIN_BUILTIN_MIN_2X16
, -1 },
6129 { CODE_FOR_smaxv2hi3
, "__builtin_bfin_max_fr2x16", BFIN_BUILTIN_MAX_2X16
, -1 },
6130 { CODE_FOR_ssaddv2hi3
, "__builtin_bfin_add_fr2x16", BFIN_BUILTIN_SSADD_2X16
, -1 },
6131 { CODE_FOR_sssubv2hi3
, "__builtin_bfin_sub_fr2x16", BFIN_BUILTIN_SSSUB_2X16
, -1 },
6132 { CODE_FOR_ssaddsubv2hi3
, "__builtin_bfin_dspaddsubsat", BFIN_BUILTIN_SSADDSUB_2X16
, -1 },
6133 { CODE_FOR_sssubaddv2hi3
, "__builtin_bfin_dspsubaddsat", BFIN_BUILTIN_SSSUBADD_2X16
, -1 },
6135 { CODE_FOR_flag_mulhisi
, "__builtin_bfin_mult_fr1x32", BFIN_BUILTIN_MULT_1X32
, MACFLAG_NONE
},
6136 { CODE_FOR_flag_mulhi
, "__builtin_bfin_mult_fr1x16", BFIN_BUILTIN_MULT_1X16
, MACFLAG_T
},
6137 { CODE_FOR_flag_mulhi
, "__builtin_bfin_multr_fr1x16", BFIN_BUILTIN_MULTR_1X16
, MACFLAG_NONE
},
6138 { CODE_FOR_flag_mulv2hi
, "__builtin_bfin_mult_fr2x16", BFIN_BUILTIN_MULT_2X16
, MACFLAG_T
},
6139 { CODE_FOR_flag_mulv2hi
, "__builtin_bfin_multr_fr2x16", BFIN_BUILTIN_MULTR_2X16
, MACFLAG_NONE
},
6141 { CODE_FOR_mulhisi_ll
, "__builtin_bfin_mulhisill", BFIN_BUILTIN_MULHISILL
, -1 },
6142 { CODE_FOR_mulhisi_lh
, "__builtin_bfin_mulhisilh", BFIN_BUILTIN_MULHISILH
, -1 },
6143 { CODE_FOR_mulhisi_hl
, "__builtin_bfin_mulhisihl", BFIN_BUILTIN_MULHISIHL
, -1 },
6144 { CODE_FOR_mulhisi_hh
, "__builtin_bfin_mulhisihh", BFIN_BUILTIN_MULHISIHH
, -1 }
6148 static const struct builtin_description bdesc_1arg
[] =
6150 { CODE_FOR_loadbytes
, "__builtin_bfin_loadbytes", BFIN_BUILTIN_LOADBYTES
, 0 },
6152 { CODE_FOR_ones
, "__builtin_bfin_ones", BFIN_BUILTIN_ONES
, 0 },
6154 { CODE_FOR_signbitshi2
, "__builtin_bfin_norm_fr1x16", BFIN_BUILTIN_NORM_1X16
, 0 },
6155 { CODE_FOR_ssneghi2
, "__builtin_bfin_negate_fr1x16", BFIN_BUILTIN_NEG_1X16
, 0 },
6156 { CODE_FOR_abshi2
, "__builtin_bfin_abs_fr1x16", BFIN_BUILTIN_ABS_1X16
, 0 },
6158 { CODE_FOR_signbitssi2
, "__builtin_bfin_norm_fr1x32", BFIN_BUILTIN_NORM_1X32
, 0 },
6159 { CODE_FOR_ssroundsi2
, "__builtin_bfin_round_fr1x32", BFIN_BUILTIN_ROUND_1X32
, 0 },
6160 { CODE_FOR_ssnegsi2
, "__builtin_bfin_negate_fr1x32", BFIN_BUILTIN_NEG_1X32
, 0 },
6161 { CODE_FOR_ssabssi2
, "__builtin_bfin_abs_fr1x32", BFIN_BUILTIN_ABS_1X32
, 0 },
6163 { CODE_FOR_movv2hi_hi_low
, "__builtin_bfin_extract_lo", BFIN_BUILTIN_EXTRACTLO
, 0 },
6164 { CODE_FOR_movv2hi_hi_high
, "__builtin_bfin_extract_hi", BFIN_BUILTIN_EXTRACTHI
, 0 },
6165 { CODE_FOR_ssnegv2hi2
, "__builtin_bfin_negate_fr2x16", BFIN_BUILTIN_NEG_2X16
, 0 },
6166 { CODE_FOR_ssabsv2hi2
, "__builtin_bfin_abs_fr2x16", BFIN_BUILTIN_ABS_2X16
, 0 }
6169 /* Errors in the source file can cause expand_expr to return const0_rtx
6170 where we expect a vector. To avoid crashing, use one of the vector
6171 clear instructions. */
6173 safe_vector_operand (rtx x
, enum machine_mode mode
)
6175 if (x
!= const0_rtx
)
6177 x
= gen_reg_rtx (SImode
);
6179 emit_insn (gen_movsi (x
, CONST0_RTX (SImode
)));
6180 return gen_lowpart (mode
, x
);
6183 /* Subroutine of bfin_expand_builtin to take care of binop insns. MACFLAG is -1
6184 if this is a normal binary op, or one of the MACFLAG_xxx constants. */
6187 bfin_expand_binop_builtin (enum insn_code icode
, tree exp
, rtx target
,
6191 tree arg0
= CALL_EXPR_ARG (exp
, 0);
6192 tree arg1
= CALL_EXPR_ARG (exp
, 1);
6193 rtx op0
= expand_expr (arg0
, NULL_RTX
, VOIDmode
, 0);
6194 rtx op1
= expand_expr (arg1
, NULL_RTX
, VOIDmode
, 0);
6195 enum machine_mode op0mode
= GET_MODE (op0
);
6196 enum machine_mode op1mode
= GET_MODE (op1
);
6197 enum machine_mode tmode
= insn_data
[icode
].operand
[0].mode
;
6198 enum machine_mode mode0
= insn_data
[icode
].operand
[1].mode
;
6199 enum machine_mode mode1
= insn_data
[icode
].operand
[2].mode
;
6201 if (VECTOR_MODE_P (mode0
))
6202 op0
= safe_vector_operand (op0
, mode0
);
6203 if (VECTOR_MODE_P (mode1
))
6204 op1
= safe_vector_operand (op1
, mode1
);
6207 || GET_MODE (target
) != tmode
6208 || ! (*insn_data
[icode
].operand
[0].predicate
) (target
, tmode
))
6209 target
= gen_reg_rtx (tmode
);
6211 if ((op0mode
== SImode
|| op0mode
== VOIDmode
) && mode0
== HImode
)
6214 op0
= gen_lowpart (HImode
, op0
);
6216 if ((op1mode
== SImode
|| op1mode
== VOIDmode
) && mode1
== HImode
)
6219 op1
= gen_lowpart (HImode
, op1
);
6221 /* In case the insn wants input operands in modes different from
6222 the result, abort. */
6223 gcc_assert ((op0mode
== mode0
|| op0mode
== VOIDmode
)
6224 && (op1mode
== mode1
|| op1mode
== VOIDmode
));
6226 if (! (*insn_data
[icode
].operand
[1].predicate
) (op0
, mode0
))
6227 op0
= copy_to_mode_reg (mode0
, op0
);
6228 if (! (*insn_data
[icode
].operand
[2].predicate
) (op1
, mode1
))
6229 op1
= copy_to_mode_reg (mode1
, op1
);
6232 pat
= GEN_FCN (icode
) (target
, op0
, op1
);
6234 pat
= GEN_FCN (icode
) (target
, op0
, op1
, GEN_INT (macflag
));
6242 /* Subroutine of bfin_expand_builtin to take care of unop insns. */
6245 bfin_expand_unop_builtin (enum insn_code icode
, tree exp
,
6249 tree arg0
= CALL_EXPR_ARG (exp
, 0);
6250 rtx op0
= expand_expr (arg0
, NULL_RTX
, VOIDmode
, 0);
6251 enum machine_mode op0mode
= GET_MODE (op0
);
6252 enum machine_mode tmode
= insn_data
[icode
].operand
[0].mode
;
6253 enum machine_mode mode0
= insn_data
[icode
].operand
[1].mode
;
6256 || GET_MODE (target
) != tmode
6257 || ! (*insn_data
[icode
].operand
[0].predicate
) (target
, tmode
))
6258 target
= gen_reg_rtx (tmode
);
6260 if (VECTOR_MODE_P (mode0
))
6261 op0
= safe_vector_operand (op0
, mode0
);
6263 if (op0mode
== SImode
&& mode0
== HImode
)
6266 op0
= gen_lowpart (HImode
, op0
);
6268 gcc_assert (op0mode
== mode0
|| op0mode
== VOIDmode
);
6270 if (! (*insn_data
[icode
].operand
[1].predicate
) (op0
, mode0
))
6271 op0
= copy_to_mode_reg (mode0
, op0
);
6273 pat
= GEN_FCN (icode
) (target
, op0
);
6280 /* Expand an expression EXP that calls a built-in function,
6281 with result going to TARGET if that's convenient
6282 (and in mode MODE if that's convenient).
6283 SUBTARGET may be used as the target for computing one of EXP's operands.
6284 IGNORE is nonzero if the value is to be ignored. */
6287 bfin_expand_builtin (tree exp
, rtx target ATTRIBUTE_UNUSED
,
6288 rtx subtarget ATTRIBUTE_UNUSED
,
6289 enum machine_mode mode ATTRIBUTE_UNUSED
,
6290 int ignore ATTRIBUTE_UNUSED
)
6293 enum insn_code icode
;
6294 const struct builtin_description
*d
;
6295 tree fndecl
= TREE_OPERAND (CALL_EXPR_FN (exp
), 0);
6296 unsigned int fcode
= DECL_FUNCTION_CODE (fndecl
);
6297 tree arg0
, arg1
, arg2
;
6298 rtx op0
, op1
, op2
, accvec
, pat
, tmp1
, tmp2
, a0reg
, a1reg
;
6299 enum machine_mode tmode
, mode0
;
6303 case BFIN_BUILTIN_CSYNC
:
6304 emit_insn (gen_csync ());
6306 case BFIN_BUILTIN_SSYNC
:
6307 emit_insn (gen_ssync ());
6310 case BFIN_BUILTIN_DIFFHL_2X16
:
6311 case BFIN_BUILTIN_DIFFLH_2X16
:
6312 case BFIN_BUILTIN_SUM_2X16
:
6313 arg0
= CALL_EXPR_ARG (exp
, 0);
6314 op0
= expand_expr (arg0
, NULL_RTX
, VOIDmode
, 0);
6315 icode
= (fcode
== BFIN_BUILTIN_DIFFHL_2X16
? CODE_FOR_subhilov2hi3
6316 : fcode
== BFIN_BUILTIN_DIFFLH_2X16
? CODE_FOR_sublohiv2hi3
6317 : CODE_FOR_ssaddhilov2hi3
);
6318 tmode
= insn_data
[icode
].operand
[0].mode
;
6319 mode0
= insn_data
[icode
].operand
[1].mode
;
6322 || GET_MODE (target
) != tmode
6323 || ! (*insn_data
[icode
].operand
[0].predicate
) (target
, tmode
))
6324 target
= gen_reg_rtx (tmode
);
6326 if (VECTOR_MODE_P (mode0
))
6327 op0
= safe_vector_operand (op0
, mode0
);
6329 if (! (*insn_data
[icode
].operand
[1].predicate
) (op0
, mode0
))
6330 op0
= copy_to_mode_reg (mode0
, op0
);
6332 pat
= GEN_FCN (icode
) (target
, op0
, op0
);
6338 case BFIN_BUILTIN_MULT_1X32X32
:
6339 case BFIN_BUILTIN_MULT_1X32X32NS
:
6340 arg0
= CALL_EXPR_ARG (exp
, 0);
6341 arg1
= CALL_EXPR_ARG (exp
, 1);
6342 op0
= expand_expr (arg0
, NULL_RTX
, VOIDmode
, 0);
6343 op1
= expand_expr (arg1
, NULL_RTX
, VOIDmode
, 0);
6345 || !register_operand (target
, SImode
))
6346 target
= gen_reg_rtx (SImode
);
6347 if (! register_operand (op0
, SImode
))
6348 op0
= copy_to_mode_reg (SImode
, op0
);
6349 if (! register_operand (op1
, SImode
))
6350 op1
= copy_to_mode_reg (SImode
, op1
);
6352 a1reg
= gen_rtx_REG (PDImode
, REG_A1
);
6353 a0reg
= gen_rtx_REG (PDImode
, REG_A0
);
6354 tmp1
= gen_lowpart (V2HImode
, op0
);
6355 tmp2
= gen_lowpart (V2HImode
, op1
);
6356 emit_insn (gen_flag_macinit1hi (a1reg
,
6357 gen_lowpart (HImode
, op0
),
6358 gen_lowpart (HImode
, op1
),
6359 GEN_INT (MACFLAG_FU
)));
6360 emit_insn (gen_lshrpdi3 (a1reg
, a1reg
, GEN_INT (16)));
6362 if (fcode
== BFIN_BUILTIN_MULT_1X32X32
)
6363 emit_insn (gen_flag_mul_macv2hi_parts_acconly (a0reg
, a1reg
, tmp1
, tmp2
,
6364 const1_rtx
, const1_rtx
,
6365 const1_rtx
, const0_rtx
, a1reg
,
6366 const0_rtx
, GEN_INT (MACFLAG_NONE
),
6367 GEN_INT (MACFLAG_M
)));
6370 /* For saturating multiplication, there's exactly one special case
6371 to be handled: multiplying the smallest negative value with
6372 itself. Due to shift correction in fractional multiplies, this
6373 can overflow. Iff this happens, OP2 will contain 1, which, when
6374 added in 32 bits to the smallest negative, wraps to the largest
6375 positive, which is the result we want. */
6376 op2
= gen_reg_rtx (V2HImode
);
6377 emit_insn (gen_packv2hi (op2
, tmp1
, tmp2
, const0_rtx
, const0_rtx
));
6378 emit_insn (gen_movsibi (gen_rtx_REG (BImode
, REG_CC
),
6379 gen_lowpart (SImode
, op2
)));
6380 emit_insn (gen_flag_mul_macv2hi_parts_acconly_andcc0 (a0reg
, a1reg
, tmp1
, tmp2
,
6381 const1_rtx
, const1_rtx
,
6382 const1_rtx
, const0_rtx
, a1reg
,
6383 const0_rtx
, GEN_INT (MACFLAG_NONE
),
6384 GEN_INT (MACFLAG_M
)));
6385 op2
= gen_reg_rtx (SImode
);
6386 emit_insn (gen_movbisi (op2
, gen_rtx_REG (BImode
, REG_CC
)));
6388 emit_insn (gen_flag_machi_parts_acconly (a1reg
, tmp2
, tmp1
,
6389 const1_rtx
, const0_rtx
,
6390 a1reg
, const0_rtx
, GEN_INT (MACFLAG_M
)));
6391 emit_insn (gen_ashrpdi3 (a1reg
, a1reg
, GEN_INT (15)));
6392 emit_insn (gen_sum_of_accumulators (target
, a0reg
, a0reg
, a1reg
));
6393 if (fcode
== BFIN_BUILTIN_MULT_1X32X32NS
)
6394 emit_insn (gen_addsi3 (target
, target
, op2
));
6397 case BFIN_BUILTIN_CPLX_MUL_16
:
6398 case BFIN_BUILTIN_CPLX_MUL_16_S40
:
6399 arg0
= CALL_EXPR_ARG (exp
, 0);
6400 arg1
= CALL_EXPR_ARG (exp
, 1);
6401 op0
= expand_expr (arg0
, NULL_RTX
, VOIDmode
, 0);
6402 op1
= expand_expr (arg1
, NULL_RTX
, VOIDmode
, 0);
6403 accvec
= gen_reg_rtx (V2PDImode
);
6404 icode
= CODE_FOR_flag_macv2hi_parts
;
6407 || GET_MODE (target
) != V2HImode
6408 || ! (*insn_data
[icode
].operand
[0].predicate
) (target
, V2HImode
))
6409 target
= gen_reg_rtx (tmode
);
6410 if (! register_operand (op0
, GET_MODE (op0
)))
6411 op0
= copy_to_mode_reg (GET_MODE (op0
), op0
);
6412 if (! register_operand (op1
, GET_MODE (op1
)))
6413 op1
= copy_to_mode_reg (GET_MODE (op1
), op1
);
6415 if (fcode
== BFIN_BUILTIN_CPLX_MUL_16
)
6416 emit_insn (gen_flag_macinit1v2hi_parts (accvec
, op0
, op1
, const0_rtx
,
6417 const0_rtx
, const0_rtx
,
6418 const1_rtx
, GEN_INT (MACFLAG_W32
)));
6420 emit_insn (gen_flag_macinit1v2hi_parts (accvec
, op0
, op1
, const0_rtx
,
6421 const0_rtx
, const0_rtx
,
6422 const1_rtx
, GEN_INT (MACFLAG_NONE
)));
6423 emit_insn (gen_flag_macv2hi_parts (target
, op0
, op1
, const1_rtx
,
6424 const1_rtx
, const1_rtx
,
6425 const0_rtx
, accvec
, const1_rtx
, const0_rtx
,
6426 GEN_INT (MACFLAG_NONE
), accvec
));
6430 case BFIN_BUILTIN_CPLX_MAC_16
:
6431 case BFIN_BUILTIN_CPLX_MSU_16
:
6432 case BFIN_BUILTIN_CPLX_MAC_16_S40
:
6433 case BFIN_BUILTIN_CPLX_MSU_16_S40
:
6434 arg0
= CALL_EXPR_ARG (exp
, 0);
6435 arg1
= CALL_EXPR_ARG (exp
, 1);
6436 arg2
= CALL_EXPR_ARG (exp
, 2);
6437 op0
= expand_expr (arg0
, NULL_RTX
, VOIDmode
, 0);
6438 op1
= expand_expr (arg1
, NULL_RTX
, VOIDmode
, 0);
6439 op2
= expand_expr (arg2
, NULL_RTX
, VOIDmode
, 0);
6440 accvec
= gen_reg_rtx (V2PDImode
);
6441 icode
= CODE_FOR_flag_macv2hi_parts
;
6444 || GET_MODE (target
) != V2HImode
6445 || ! (*insn_data
[icode
].operand
[0].predicate
) (target
, V2HImode
))
6446 target
= gen_reg_rtx (tmode
);
6447 if (! register_operand (op1
, GET_MODE (op1
)))
6448 op1
= copy_to_mode_reg (GET_MODE (op1
), op1
);
6449 if (! register_operand (op2
, GET_MODE (op2
)))
6450 op2
= copy_to_mode_reg (GET_MODE (op2
), op2
);
6452 tmp1
= gen_reg_rtx (SImode
);
6453 tmp2
= gen_reg_rtx (SImode
);
6454 emit_insn (gen_ashlsi3 (tmp1
, gen_lowpart (SImode
, op0
), GEN_INT (16)));
6455 emit_move_insn (tmp2
, gen_lowpart (SImode
, op0
));
6456 emit_insn (gen_movstricthi_1 (gen_lowpart (HImode
, tmp2
), const0_rtx
));
6457 emit_insn (gen_load_accumulator_pair (accvec
, tmp1
, tmp2
));
6458 if (fcode
== BFIN_BUILTIN_CPLX_MAC_16
6459 || fcode
== BFIN_BUILTIN_CPLX_MSU_16
)
6460 emit_insn (gen_flag_macv2hi_parts_acconly (accvec
, op1
, op2
, const0_rtx
,
6461 const0_rtx
, const0_rtx
,
6462 const1_rtx
, accvec
, const0_rtx
,
6464 GEN_INT (MACFLAG_W32
)));
6466 emit_insn (gen_flag_macv2hi_parts_acconly (accvec
, op1
, op2
, const0_rtx
,
6467 const0_rtx
, const0_rtx
,
6468 const1_rtx
, accvec
, const0_rtx
,
6470 GEN_INT (MACFLAG_NONE
)));
6471 if (fcode
== BFIN_BUILTIN_CPLX_MAC_16
6472 || fcode
== BFIN_BUILTIN_CPLX_MAC_16_S40
)
6482 emit_insn (gen_flag_macv2hi_parts (target
, op1
, op2
, const1_rtx
,
6483 const1_rtx
, const1_rtx
,
6484 const0_rtx
, accvec
, tmp1
, tmp2
,
6485 GEN_INT (MACFLAG_NONE
), accvec
));
6489 case BFIN_BUILTIN_CPLX_SQU
:
6490 arg0
= CALL_EXPR_ARG (exp
, 0);
6491 op0
= expand_expr (arg0
, NULL_RTX
, VOIDmode
, 0);
6492 accvec
= gen_reg_rtx (V2PDImode
);
6493 icode
= CODE_FOR_flag_mulv2hi
;
6494 tmp1
= gen_reg_rtx (V2HImode
);
6495 tmp2
= gen_reg_rtx (V2HImode
);
6498 || GET_MODE (target
) != V2HImode
6499 || ! (*insn_data
[icode
].operand
[0].predicate
) (target
, V2HImode
))
6500 target
= gen_reg_rtx (V2HImode
);
6501 if (! register_operand (op0
, GET_MODE (op0
)))
6502 op0
= copy_to_mode_reg (GET_MODE (op0
), op0
);
6504 emit_insn (gen_flag_mulv2hi (tmp1
, op0
, op0
, GEN_INT (MACFLAG_NONE
)));
6506 emit_insn (gen_flag_mulhi_parts (gen_lowpart (HImode
, tmp2
), op0
, op0
,
6507 const0_rtx
, const1_rtx
,
6508 GEN_INT (MACFLAG_NONE
)));
6510 emit_insn (gen_ssaddhi3_high_parts (target
, tmp2
, tmp2
, tmp2
, const0_rtx
,
6512 emit_insn (gen_sssubhi3_low_parts (target
, target
, tmp1
, tmp1
,
6513 const0_rtx
, const1_rtx
));
6521 for (i
= 0, d
= bdesc_2arg
; i
< ARRAY_SIZE (bdesc_2arg
); i
++, d
++)
6522 if (d
->code
== fcode
)
6523 return bfin_expand_binop_builtin (d
->icode
, exp
, target
,
6526 for (i
= 0, d
= bdesc_1arg
; i
< ARRAY_SIZE (bdesc_1arg
); i
++, d
++)
6527 if (d
->code
== fcode
)
6528 return bfin_expand_unop_builtin (d
->icode
, exp
, target
);
6533 #undef TARGET_INIT_BUILTINS
6534 #define TARGET_INIT_BUILTINS bfin_init_builtins
6536 #undef TARGET_EXPAND_BUILTIN
6537 #define TARGET_EXPAND_BUILTIN bfin_expand_builtin
6539 #undef TARGET_ASM_GLOBALIZE_LABEL
6540 #define TARGET_ASM_GLOBALIZE_LABEL bfin_globalize_label
6542 #undef TARGET_ASM_FILE_START
6543 #define TARGET_ASM_FILE_START output_file_start
6545 #undef TARGET_ATTRIBUTE_TABLE
6546 #define TARGET_ATTRIBUTE_TABLE bfin_attribute_table
6548 #undef TARGET_COMP_TYPE_ATTRIBUTES
6549 #define TARGET_COMP_TYPE_ATTRIBUTES bfin_comp_type_attributes
6551 #undef TARGET_RTX_COSTS
6552 #define TARGET_RTX_COSTS bfin_rtx_costs
6554 #undef TARGET_ADDRESS_COST
6555 #define TARGET_ADDRESS_COST bfin_address_cost
6557 #undef TARGET_ASM_INTEGER
6558 #define TARGET_ASM_INTEGER bfin_assemble_integer
6560 #undef TARGET_MACHINE_DEPENDENT_REORG
6561 #define TARGET_MACHINE_DEPENDENT_REORG bfin_reorg
6563 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
6564 #define TARGET_FUNCTION_OK_FOR_SIBCALL bfin_function_ok_for_sibcall
6566 #undef TARGET_ASM_OUTPUT_MI_THUNK
6567 #define TARGET_ASM_OUTPUT_MI_THUNK bfin_output_mi_thunk
6568 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
6569 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true
6571 #undef TARGET_SCHED_ADJUST_COST
6572 #define TARGET_SCHED_ADJUST_COST bfin_adjust_cost
6574 #undef TARGET_SCHED_ISSUE_RATE
6575 #define TARGET_SCHED_ISSUE_RATE bfin_issue_rate
6577 #undef TARGET_PROMOTE_FUNCTION_MODE
6578 #define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
6580 #undef TARGET_ARG_PARTIAL_BYTES
6581 #define TARGET_ARG_PARTIAL_BYTES bfin_arg_partial_bytes
6583 #undef TARGET_PASS_BY_REFERENCE
6584 #define TARGET_PASS_BY_REFERENCE bfin_pass_by_reference
6586 #undef TARGET_SETUP_INCOMING_VARARGS
6587 #define TARGET_SETUP_INCOMING_VARARGS setup_incoming_varargs
6589 #undef TARGET_STRUCT_VALUE_RTX
6590 #define TARGET_STRUCT_VALUE_RTX bfin_struct_value_rtx
6592 #undef TARGET_VECTOR_MODE_SUPPORTED_P
6593 #define TARGET_VECTOR_MODE_SUPPORTED_P bfin_vector_mode_supported_p
6595 #undef TARGET_HANDLE_OPTION
6596 #define TARGET_HANDLE_OPTION bfin_handle_option
6598 #undef TARGET_DEFAULT_TARGET_FLAGS
6599 #define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
6601 #undef TARGET_SECONDARY_RELOAD
6602 #define TARGET_SECONDARY_RELOAD bfin_secondary_reload
6604 #undef TARGET_DELEGITIMIZE_ADDRESS
6605 #define TARGET_DELEGITIMIZE_ADDRESS bfin_delegitimize_address
6607 #undef TARGET_CANNOT_FORCE_CONST_MEM
6608 #define TARGET_CANNOT_FORCE_CONST_MEM bfin_cannot_force_const_mem
6610 #undef TARGET_RETURN_IN_MEMORY
6611 #define TARGET_RETURN_IN_MEMORY bfin_return_in_memory
6613 #undef TARGET_LEGITIMATE_ADDRESS_P
6614 #define TARGET_LEGITIMATE_ADDRESS_P bfin_legitimate_address_p
6616 #undef TARGET_FRAME_POINTER_REQUIRED
6617 #define TARGET_FRAME_POINTER_REQUIRED bfin_frame_pointer_required
6619 #undef TARGET_CAN_ELIMINATE
6620 #define TARGET_CAN_ELIMINATE bfin_can_eliminate
6622 struct gcc_target targetm
= TARGET_INITIALIZER
;