]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/config/bfin/bfin.c
rtl.h (emit_clobber, [...]): Declare.
[thirdparty/gcc.git] / gcc / config / bfin / bfin.c
CommitLineData
f652d14b 1/* The Blackfin code generation auxiliary output file.
64882649 2 Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
0d4a78eb
BS
3 Contributed by Analog Devices.
4
5 This file is part of GCC.
6
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
2f83c7d6 9 by the Free Software Foundation; either version 3, or (at your
0d4a78eb
BS
10 option) any later version.
11
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.
16
17 You should have received a copy of the GNU General Public License
2f83c7d6
NC
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
0d4a78eb
BS
20
21#include "config.h"
22#include "system.h"
23#include "coretypes.h"
24#include "tm.h"
25#include "rtl.h"
26#include "regs.h"
27#include "hard-reg-set.h"
28#include "real.h"
29#include "insn-config.h"
3fb192d2 30#include "insn-codes.h"
0d4a78eb
BS
31#include "conditions.h"
32#include "insn-flags.h"
33#include "output.h"
34#include "insn-attr.h"
35#include "tree.h"
36#include "flags.h"
37#include "except.h"
38#include "function.h"
39#include "input.h"
40#include "target.h"
41#include "target-def.h"
42#include "expr.h"
43#include "toplev.h"
44#include "recog.h"
42da70b7 45#include "optabs.h"
0d4a78eb
BS
46#include "ggc.h"
47#include "integrate.h"
9fc023cc 48#include "cgraph.h"
05905337 49#include "langhooks.h"
0d4a78eb
BS
50#include "bfin-protos.h"
51#include "tm-preds.h"
9fdd7520 52#include "tm-constrs.h"
0d4a78eb 53#include "gt-bfin.h"
b03149e1 54#include "basic-block.h"
ce27ef3d 55#include "cfglayout.h"
bbbc206e 56#include "timevar.h"
b18e284e 57#include "df.h"
b03149e1
JZ
58
59/* A C structure for machine-specific, per-function data.
60 This is added to the cfun structure. */
61struct machine_function GTY(())
62{
63 int has_hardware_loops;
64};
0d4a78eb
BS
65
66/* Test and compare insns in bfin.md store the information needed to
67 generate branch and scc insns here. */
68rtx bfin_compare_op0, bfin_compare_op1;
69
70/* RTX for condition code flag register and RETS register */
71extern GTY(()) rtx bfin_cc_rtx;
72extern GTY(()) rtx bfin_rets_rtx;
73rtx bfin_cc_rtx, bfin_rets_rtx;
74
75int max_arg_registers = 0;
76
77/* Arrays used when emitting register names. */
78const char *short_reg_names[] = SHORT_REGISTER_NAMES;
79const char *high_reg_names[] = HIGH_REGISTER_NAMES;
80const char *dregs_pair_names[] = DREGS_PAIR_NAMES;
81const char *byte_reg_names[] = BYTE_REGISTER_NAMES;
82
83static int arg_regs[] = FUNCTION_ARG_REGISTERS;
84
c8de0f3b
BS
85/* Nonzero if -mshared-library-id was given. */
86static int bfin_lib_id_given;
0d4a78eb 87
bbbc206e
BS
88/* Nonzero if -fschedule-insns2 was given. We override it and
89 call the scheduler ourselves during reorg. */
90static int bfin_flag_schedule_insns2;
91
92/* Determines whether we run variable tracking in machine dependent
93 reorganization. */
94static int bfin_flag_var_tracking;
95
9d3f9aa3 96/* -mcpu support */
16869606 97bfin_cpu_t bfin_cpu_type = BFIN_CPU_UNKNOWN;
9d3f9aa3 98
ea2382be
JZ
99/* -msi-revision support. There are three special values:
100 -1 -msi-revision=none.
101 0xffff -msi-revision=any. */
102int bfin_si_revision;
103
104/* The workarounds enabled */
105unsigned int bfin_workarounds = 0;
106
107struct bfin_cpu
108{
109 const char *name;
110 bfin_cpu_t type;
111 int si_revision;
112 unsigned int workarounds;
113};
114
115struct bfin_cpu bfin_cpus[] =
116{
117 {"bf522", BFIN_CPU_BF522, 0x0000,
fa8d4a0f 118 WA_SPECULATIVE_LOADS | WA_RETS},
ea2382be 119
64882649 120 {"bf523", BFIN_CPU_BF523, 0x0000,
fa8d4a0f 121 WA_SPECULATIVE_LOADS | WA_RETS},
64882649
BS
122
123 {"bf524", BFIN_CPU_BF524, 0x0000,
fa8d4a0f 124 WA_SPECULATIVE_LOADS | WA_RETS},
64882649 125
ea2382be 126 {"bf525", BFIN_CPU_BF525, 0x0000,
fa8d4a0f 127 WA_SPECULATIVE_LOADS | WA_RETS},
ea2382be 128
64882649 129 {"bf526", BFIN_CPU_BF526, 0x0000,
fa8d4a0f 130 WA_SPECULATIVE_LOADS | WA_RETS},
64882649 131
ea2382be 132 {"bf527", BFIN_CPU_BF527, 0x0000,
fa8d4a0f 133 WA_SPECULATIVE_LOADS | WA_RETS},
ea2382be
JZ
134
135 {"bf531", BFIN_CPU_BF531, 0x0005,
fa8d4a0f 136 WA_SPECULATIVE_LOADS | WA_RETS},
ea2382be 137 {"bf531", BFIN_CPU_BF531, 0x0004,
fa8d4a0f 138 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS},
ea2382be 139 {"bf531", BFIN_CPU_BF531, 0x0003,
fa8d4a0f 140 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS},
ea2382be
JZ
141
142 {"bf532", BFIN_CPU_BF532, 0x0005,
fa8d4a0f 143 WA_SPECULATIVE_LOADS | WA_RETS},
ea2382be 144 {"bf532", BFIN_CPU_BF532, 0x0004,
fa8d4a0f 145 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS},
ea2382be 146 {"bf532", BFIN_CPU_BF532, 0x0003,
fa8d4a0f 147 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS},
ea2382be
JZ
148
149 {"bf533", BFIN_CPU_BF533, 0x0005,
fa8d4a0f 150 WA_SPECULATIVE_LOADS | WA_RETS},
ea2382be 151 {"bf533", BFIN_CPU_BF533, 0x0004,
fa8d4a0f 152 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS},
ea2382be 153 {"bf533", BFIN_CPU_BF533, 0x0003,
fa8d4a0f 154 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS},
ea2382be
JZ
155
156 {"bf534", BFIN_CPU_BF534, 0x0003,
fa8d4a0f 157 WA_SPECULATIVE_LOADS | WA_RETS},
ea2382be 158 {"bf534", BFIN_CPU_BF534, 0x0002,
fa8d4a0f 159 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS},
ea2382be 160 {"bf534", BFIN_CPU_BF534, 0x0001,
fa8d4a0f 161 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS},
ea2382be
JZ
162
163 {"bf536", BFIN_CPU_BF536, 0x0003,
fa8d4a0f 164 WA_SPECULATIVE_LOADS | WA_RETS},
ea2382be 165 {"bf536", BFIN_CPU_BF536, 0x0002,
fa8d4a0f 166 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS},
ea2382be 167 {"bf536", BFIN_CPU_BF536, 0x0001,
fa8d4a0f 168 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS},
ea2382be
JZ
169
170 {"bf537", BFIN_CPU_BF537, 0x0003,
fa8d4a0f 171 WA_SPECULATIVE_LOADS | WA_RETS},
ea2382be 172 {"bf537", BFIN_CPU_BF537, 0x0002,
fa8d4a0f 173 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS},
ea2382be 174 {"bf537", BFIN_CPU_BF537, 0x0001,
fa8d4a0f 175 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS},
ea2382be
JZ
176
177 {"bf538", BFIN_CPU_BF538, 0x0004,
fa8d4a0f 178 WA_SPECULATIVE_LOADS | WA_RETS},
ea2382be 179 {"bf538", BFIN_CPU_BF538, 0x0003,
fa8d4a0f 180 WA_SPECULATIVE_LOADS | WA_RETS},
ea2382be
JZ
181
182 {"bf539", BFIN_CPU_BF539, 0x0004,
fa8d4a0f 183 WA_SPECULATIVE_LOADS | WA_RETS},
ea2382be 184 {"bf539", BFIN_CPU_BF539, 0x0003,
fa8d4a0f 185 WA_SPECULATIVE_LOADS | WA_RETS},
ea2382be 186 {"bf539", BFIN_CPU_BF539, 0x0002,
fa8d4a0f 187 WA_SPECULATIVE_LOADS | WA_RETS},
ea2382be
JZ
188
189 {"bf542", BFIN_CPU_BF542, 0x0000,
fa8d4a0f 190 WA_SPECULATIVE_LOADS | WA_RETS},
ea2382be
JZ
191
192 {"bf544", BFIN_CPU_BF544, 0x0000,
fa8d4a0f 193 WA_SPECULATIVE_LOADS | WA_RETS},
ea2382be 194
64882649 195 {"bf547", BFIN_CPU_BF547, 0x0000,
fa8d4a0f 196 WA_SPECULATIVE_LOADS | WA_RETS},
64882649 197
ea2382be 198 {"bf548", BFIN_CPU_BF548, 0x0000,
fa8d4a0f 199 WA_SPECULATIVE_LOADS | WA_RETS},
ea2382be
JZ
200
201 {"bf549", BFIN_CPU_BF549, 0x0000,
fa8d4a0f 202 WA_SPECULATIVE_LOADS | WA_RETS},
ea2382be 203
fa8d4a0f 204 {"bf561", BFIN_CPU_BF561, 0x0005, WA_RETS},
ea2382be 205 {"bf561", BFIN_CPU_BF561, 0x0003,
fa8d4a0f 206 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS},
ea2382be 207 {"bf561", BFIN_CPU_BF561, 0x0002,
fa8d4a0f 208 WA_SPECULATIVE_LOADS | WA_SPECULATIVE_SYNCS | WA_RETS},
ea2382be
JZ
209
210 {NULL, 0, 0, 0}
211};
212
bbbc206e
BS
213int splitting_for_sched;
214
0d4a78eb
BS
215static void
216bfin_globalize_label (FILE *stream, const char *name)
217{
218 fputs (".global ", stream);
219 assemble_name (stream, name);
220 fputc (';',stream);
221 fputc ('\n',stream);
222}
223
224static void
225output_file_start (void)
226{
227 FILE *file = asm_out_file;
228 int i;
229
bbbc206e
BS
230 /* Variable tracking should be run after all optimizations which change order
231 of insns. It also needs a valid CFG. This can't be done in
708f30d6 232 override_options, because flag_var_tracking is finalized after
bbbc206e
BS
233 that. */
234 bfin_flag_var_tracking = flag_var_tracking;
235 flag_var_tracking = 0;
236
0d4a78eb
BS
237 fprintf (file, ".file \"%s\";\n", input_filename);
238
239 for (i = 0; arg_regs[i] >= 0; i++)
240 ;
241 max_arg_registers = i; /* how many arg reg used */
242}
243
244/* Called early in the compilation to conditionally modify
245 fixed_regs/call_used_regs. */
246
247void
248conditional_register_usage (void)
249{
250 /* initialize condition code flag register rtx */
251 bfin_cc_rtx = gen_rtx_REG (BImode, REG_CC);
252 bfin_rets_rtx = gen_rtx_REG (Pmode, REG_RETS);
253}
254
255/* Examine machine-dependent attributes of function type FUNTYPE and return its
256 type. See the definition of E_FUNKIND. */
257
3101faab
KG
258static e_funkind
259funkind (const_tree funtype)
0d4a78eb
BS
260{
261 tree attrs = TYPE_ATTRIBUTES (funtype);
262 if (lookup_attribute ("interrupt_handler", attrs))
263 return INTERRUPT_HANDLER;
264 else if (lookup_attribute ("exception_handler", attrs))
265 return EXCPT_HANDLER;
266 else if (lookup_attribute ("nmi_handler", attrs))
267 return NMI_HANDLER;
268 else
269 return SUBROUTINE;
270}
271\f
09350e36
BS
272/* Legitimize PIC addresses. If the address is already position-independent,
273 we return ORIG. Newly generated position-independent addresses go into a
274 reg. This is REG if nonzero, otherwise we allocate register(s) as
275 necessary. PICREG is the register holding the pointer to the PIC offset
276 table. */
277
6614f9f5 278static rtx
09350e36
BS
279legitimize_pic_address (rtx orig, rtx reg, rtx picreg)
280{
281 rtx addr = orig;
282 rtx new = orig;
283
284 if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == LABEL_REF)
285 {
6b97a439
BS
286 int unspec;
287 rtx tmp;
288
289 if (TARGET_ID_SHARED_LIBRARY)
290 unspec = UNSPEC_MOVE_PIC;
291 else if (GET_CODE (addr) == SYMBOL_REF
292 && SYMBOL_REF_FUNCTION_P (addr))
293 unspec = UNSPEC_FUNCDESC_GOT17M4;
09350e36 294 else
6b97a439
BS
295 unspec = UNSPEC_MOVE_FDPIC;
296
297 if (reg == 0)
09350e36 298 {
b3a13419 299 gcc_assert (can_create_pseudo_p ());
6b97a439 300 reg = gen_reg_rtx (Pmode);
09350e36 301 }
6b97a439
BS
302
303 tmp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), unspec);
304 new = gen_const_mem (Pmode, gen_rtx_PLUS (Pmode, picreg, tmp));
305
306 emit_move_insn (reg, new);
09350e36 307 if (picreg == pic_offset_table_rtx)
e3b5732b 308 crtl->uses_pic_offset_table = 1;
09350e36
BS
309 return reg;
310 }
311
312 else if (GET_CODE (addr) == CONST || GET_CODE (addr) == PLUS)
313 {
314 rtx base;
315
316 if (GET_CODE (addr) == CONST)
317 {
318 addr = XEXP (addr, 0);
319 gcc_assert (GET_CODE (addr) == PLUS);
320 }
321
322 if (XEXP (addr, 0) == picreg)
323 return orig;
324
325 if (reg == 0)
326 {
b3a13419 327 gcc_assert (can_create_pseudo_p ());
09350e36
BS
328 reg = gen_reg_rtx (Pmode);
329 }
330
331 base = legitimize_pic_address (XEXP (addr, 0), reg, picreg);
332 addr = legitimize_pic_address (XEXP (addr, 1),
333 base == reg ? NULL_RTX : reg,
334 picreg);
335
336 if (GET_CODE (addr) == CONST_INT)
337 {
338 gcc_assert (! reload_in_progress && ! reload_completed);
339 addr = force_reg (Pmode, addr);
340 }
341
342 if (GET_CODE (addr) == PLUS && CONSTANT_P (XEXP (addr, 1)))
343 {
344 base = gen_rtx_PLUS (Pmode, base, XEXP (addr, 0));
345 addr = XEXP (addr, 1);
346 }
347
348 return gen_rtx_PLUS (Pmode, base, addr);
349 }
350
351 return new;
352}
353\f
0d4a78eb
BS
354/* Stack frame layout. */
355
4d82f261
BS
356/* For a given REGNO, determine whether it must be saved in the function
357 prologue. IS_INTHANDLER specifies whether we're generating a normal
358 prologue or an interrupt/exception one. */
359static bool
360must_save_p (bool is_inthandler, unsigned regno)
0d4a78eb 361{
4d82f261 362 if (D_REGNO_P (regno))
0d4a78eb 363 {
4d82f261 364 bool is_eh_return_reg = false;
e3b5732b 365 if (crtl->calls_eh_return)
0d4a78eb
BS
366 {
367 unsigned j;
368 for (j = 0; ; j++)
369 {
370 unsigned test = EH_RETURN_DATA_REGNO (j);
371 if (test == INVALID_REGNUM)
372 break;
4d82f261
BS
373 if (test == regno)
374 is_eh_return_reg = true;
0d4a78eb
BS
375 }
376 }
377
4d82f261
BS
378 return (is_eh_return_reg
379 || (df_regs_ever_live_p (regno)
380 && !fixed_regs[regno]
381 && (is_inthandler || !call_used_regs[regno])));
0d4a78eb 382 }
4d82f261
BS
383 else if (P_REGNO_P (regno))
384 {
385 return ((df_regs_ever_live_p (regno)
386 && !fixed_regs[regno]
387 && (is_inthandler || !call_used_regs[regno]))
388 || (!TARGET_FDPIC
389 && regno == PIC_OFFSET_TABLE_REGNUM
e3b5732b 390 && (crtl->uses_pic_offset_table
4d82f261
BS
391 || (TARGET_ID_SHARED_LIBRARY && !current_function_is_leaf))));
392 }
393 else
394 return ((is_inthandler || !call_used_regs[regno])
395 && (df_regs_ever_live_p (regno)
396 || (!leaf_function_p () && call_used_regs[regno])));
397
398}
399
400/* Compute the number of DREGS to save with a push_multiple operation.
401 This could include registers that aren't modified in the function,
402 since push_multiple only takes a range of registers.
403 If IS_INTHANDLER, then everything that is live must be saved, even
404 if normally call-clobbered.
405 If CONSECUTIVE, return the number of registers we can save in one
406 instruction with a push/pop multiple instruction. */
407
408static int
409n_dregs_to_save (bool is_inthandler, bool consecutive)
410{
411 int count = 0;
412 unsigned i;
413
414 for (i = REG_R7 + 1; i-- != REG_R0;)
415 {
416 if (must_save_p (is_inthandler, i))
417 count++;
418 else if (consecutive)
419 return count;
420 }
421 return count;
0d4a78eb
BS
422}
423
424/* Like n_dregs_to_save, but compute number of PREGS to save. */
425
426static int
4d82f261 427n_pregs_to_save (bool is_inthandler, bool consecutive)
0d4a78eb 428{
4d82f261 429 int count = 0;
0d4a78eb
BS
430 unsigned i;
431
4d82f261
BS
432 for (i = REG_P5 + 1; i-- != REG_P0;)
433 if (must_save_p (is_inthandler, i))
434 count++;
435 else if (consecutive)
436 return count;
437 return count;
0d4a78eb
BS
438}
439
440/* Determine if we are going to save the frame pointer in the prologue. */
441
442static bool
443must_save_fp_p (void)
444{
6fb5fa3c 445 return frame_pointer_needed || df_regs_ever_live_p (REG_FP);
0d4a78eb
BS
446}
447
448static bool
449stack_frame_needed_p (void)
450{
451 /* EH return puts a new return address into the frame using an
452 address relative to the frame pointer. */
e3b5732b 453 if (crtl->calls_eh_return)
0d4a78eb
BS
454 return true;
455 return frame_pointer_needed;
456}
457
458/* Emit code to save registers in the prologue. SAVEALL is nonzero if we
459 must save all registers; this is used for interrupt handlers.
e989202f
BS
460 SPREG contains (reg:SI REG_SP). IS_INTHANDLER is true if we're doing
461 this for an interrupt (or exception) handler. */
0d4a78eb
BS
462
463static void
e989202f 464expand_prologue_reg_save (rtx spreg, int saveall, bool is_inthandler)
0d4a78eb 465{
bf3f9581
BS
466 rtx predec1 = gen_rtx_PRE_DEC (SImode, spreg);
467 rtx predec = gen_rtx_MEM (SImode, predec1);
4d82f261
BS
468 int ndregs = saveall ? 8 : n_dregs_to_save (is_inthandler, false);
469 int npregs = saveall ? 6 : n_pregs_to_save (is_inthandler, false);
470 int ndregs_consec = saveall ? 8 : n_dregs_to_save (is_inthandler, true);
471 int npregs_consec = saveall ? 6 : n_pregs_to_save (is_inthandler, true);
472 int dregno, pregno;
473 int total_consec = ndregs_consec + npregs_consec;
474 int i, d_to_save;
0d4a78eb 475
bf3f9581
BS
476 if (saveall || is_inthandler)
477 {
4d82f261 478 rtx insn = emit_move_insn (predec, gen_rtx_REG (SImode, REG_ASTAT));
bf3f9581
BS
479 RTX_FRAME_RELATED_P (insn) = 1;
480 }
481
4d82f261
BS
482 if (total_consec != 0)
483 {
484 rtx insn;
485 rtx val = GEN_INT (-total_consec * 4);
486 rtx pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total_consec + 2));
487
488 XVECEXP (pat, 0, 0) = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, val),
489 UNSPEC_PUSH_MULTIPLE);
490 XVECEXP (pat, 0, total_consec + 1) = gen_rtx_SET (VOIDmode, spreg,
491 gen_rtx_PLUS (Pmode,
492 spreg,
493 val));
494 RTX_FRAME_RELATED_P (XVECEXP (pat, 0, total_consec + 1)) = 1;
495 d_to_save = ndregs_consec;
496 dregno = REG_R7 + 1 - ndregs_consec;
497 pregno = REG_P5 + 1 - npregs_consec;
498 for (i = 0; i < total_consec; i++)
499 {
500 rtx memref = gen_rtx_MEM (word_mode,
501 gen_rtx_PLUS (Pmode, spreg,
502 GEN_INT (- i * 4 - 4)));
503 rtx subpat;
504 if (d_to_save > 0)
505 {
506 subpat = gen_rtx_SET (VOIDmode, memref, gen_rtx_REG (word_mode,
507 dregno++));
508 d_to_save--;
509 }
510 else
511 {
512 subpat = gen_rtx_SET (VOIDmode, memref, gen_rtx_REG (word_mode,
513 pregno++));
514 }
515 XVECEXP (pat, 0, i + 1) = subpat;
516 RTX_FRAME_RELATED_P (subpat) = 1;
517 }
518 insn = emit_insn (pat);
519 RTX_FRAME_RELATED_P (insn) = 1;
520 }
0d4a78eb 521
4d82f261 522 for (dregno = REG_R0; ndregs != ndregs_consec; dregno++)
0d4a78eb 523 {
4d82f261 524 if (must_save_p (is_inthandler, dregno))
0d4a78eb 525 {
4d82f261
BS
526 rtx insn = emit_move_insn (predec, gen_rtx_REG (word_mode, dregno));
527 RTX_FRAME_RELATED_P (insn) = 1;
0d4a78eb
BS
528 ndregs--;
529 }
4d82f261
BS
530 }
531 for (pregno = REG_P0; npregs != npregs_consec; pregno++)
532 {
533 if (must_save_p (is_inthandler, pregno))
0d4a78eb 534 {
4d82f261
BS
535 rtx insn = emit_move_insn (predec, gen_rtx_REG (word_mode, pregno));
536 RTX_FRAME_RELATED_P (insn) = 1;
537 npregs--;
0d4a78eb 538 }
0d4a78eb 539 }
bf3f9581
BS
540 for (i = REG_P7 + 1; i < REG_CC; i++)
541 if (saveall
542 || (is_inthandler
543 && (df_regs_ever_live_p (i)
544 || (!leaf_function_p () && call_used_regs[i]))))
545 {
4d82f261 546 rtx insn;
bf3f9581
BS
547 if (i == REG_A0 || i == REG_A1)
548 insn = emit_move_insn (gen_rtx_MEM (PDImode, predec1),
549 gen_rtx_REG (PDImode, i));
550 else
551 insn = emit_move_insn (predec, gen_rtx_REG (SImode, i));
552 RTX_FRAME_RELATED_P (insn) = 1;
553 }
0d4a78eb
BS
554}
555
556/* Emit code to restore registers in the epilogue. SAVEALL is nonzero if we
557 must save all registers; this is used for interrupt handlers.
e989202f
BS
558 SPREG contains (reg:SI REG_SP). IS_INTHANDLER is true if we're doing
559 this for an interrupt (or exception) handler. */
0d4a78eb
BS
560
561static void
e989202f 562expand_epilogue_reg_restore (rtx spreg, bool saveall, bool is_inthandler)
0d4a78eb 563{
bf3f9581
BS
564 rtx postinc1 = gen_rtx_POST_INC (SImode, spreg);
565 rtx postinc = gen_rtx_MEM (SImode, postinc1);
566
4d82f261
BS
567 int ndregs = saveall ? 8 : n_dregs_to_save (is_inthandler, false);
568 int npregs = saveall ? 6 : n_pregs_to_save (is_inthandler, false);
569 int ndregs_consec = saveall ? 8 : n_dregs_to_save (is_inthandler, true);
570 int npregs_consec = saveall ? 6 : n_pregs_to_save (is_inthandler, true);
571 int total_consec = ndregs_consec + npregs_consec;
0d4a78eb 572 int i, regno;
4d82f261 573 rtx insn;
0d4a78eb 574
bf3f9581
BS
575 /* A slightly crude technique to stop flow from trying to delete "dead"
576 insns. */
577 MEM_VOLATILE_P (postinc) = 1;
578
579 for (i = REG_CC - 1; i > REG_P7; i--)
580 if (saveall
581 || (is_inthandler
582 && (df_regs_ever_live_p (i)
583 || (!leaf_function_p () && call_used_regs[i]))))
584 {
585 if (i == REG_A0 || i == REG_A1)
586 {
587 rtx mem = gen_rtx_MEM (PDImode, postinc1);
588 MEM_VOLATILE_P (mem) = 1;
589 emit_move_insn (gen_rtx_REG (PDImode, i), mem);
590 }
591 else
592 emit_move_insn (gen_rtx_REG (SImode, i), postinc);
593 }
594
4d82f261
BS
595 regno = REG_P5 - npregs_consec;
596 for (; npregs != npregs_consec; regno--)
0d4a78eb 597 {
4d82f261 598 if (must_save_p (is_inthandler, regno))
0d4a78eb 599 {
4d82f261
BS
600 emit_move_insn (gen_rtx_REG (word_mode, regno), postinc);
601 npregs--;
0d4a78eb
BS
602 }
603 }
4d82f261
BS
604 regno = REG_R7 - ndregs_consec;
605 for (; ndregs != ndregs_consec; regno--)
606 {
607 if (must_save_p (is_inthandler, regno))
608 {
609 emit_move_insn (gen_rtx_REG (word_mode, regno), postinc);
610 ndregs--;
611 }
612 }
613
614 if (total_consec != 0)
615 {
616 rtx pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total_consec + 1));
617 XVECEXP (pat, 0, 0)
618 = gen_rtx_SET (VOIDmode, spreg,
619 gen_rtx_PLUS (Pmode, spreg,
620 GEN_INT (total_consec * 4)));
621
622 if (npregs_consec > 0)
623 regno = REG_P5 + 1;
624 else
625 regno = REG_R7 + 1;
0d4a78eb 626
4d82f261
BS
627 for (i = 0; i < total_consec; i++)
628 {
629 rtx addr = (i > 0
630 ? gen_rtx_PLUS (Pmode, spreg, GEN_INT (i * 4))
631 : spreg);
632 rtx memref = gen_rtx_MEM (word_mode, addr);
633
634 regno--;
635 XVECEXP (pat, 0, i + 1)
636 = gen_rtx_SET (VOIDmode, gen_rtx_REG (word_mode, regno), memref);
637
638 if (npregs_consec > 0)
639 {
640 if (--npregs_consec == 0)
641 regno = REG_R7 + 1;
642 }
643 }
bf3f9581 644
4d82f261
BS
645 insn = emit_insn (pat);
646 RTX_FRAME_RELATED_P (insn) = 1;
647 }
bf3f9581
BS
648 if (saveall || is_inthandler)
649 emit_move_insn (gen_rtx_REG (SImode, REG_ASTAT), postinc);
0d4a78eb
BS
650}
651
652/* Perform any needed actions needed for a function that is receiving a
653 variable number of arguments.
654
655 CUM is as above.
656
657 MODE and TYPE are the mode and type of the current parameter.
658
659 PRETEND_SIZE is a variable that should be set to the amount of stack
660 that must be pushed by the prolog to pretend that our caller pushed
661 it.
662
663 Normally, this macro will push all remaining incoming registers on the
664 stack and set PRETEND_SIZE to the length of the registers pushed.
665
666 Blackfin specific :
667 - VDSP C compiler manual (our ABI) says that a variable args function
668 should save the R0, R1 and R2 registers in the stack.
669 - The caller will always leave space on the stack for the
670 arguments that are passed in registers, so we dont have
671 to leave any extra space.
672 - now, the vastart pointer can access all arguments from the stack. */
673
674static void
675setup_incoming_varargs (CUMULATIVE_ARGS *cum,
676 enum machine_mode mode ATTRIBUTE_UNUSED,
677 tree type ATTRIBUTE_UNUSED, int *pretend_size,
678 int no_rtl)
679{
680 rtx mem;
681 int i;
682
683 if (no_rtl)
684 return;
685
686 /* The move for named arguments will be generated automatically by the
687 compiler. We need to generate the move rtx for the unnamed arguments
f652d14b 688 if they are in the first 3 words. We assume at least 1 named argument
0d4a78eb
BS
689 exists, so we never generate [ARGP] = R0 here. */
690
691 for (i = cum->words + 1; i < max_arg_registers; i++)
692 {
693 mem = gen_rtx_MEM (Pmode,
694 plus_constant (arg_pointer_rtx, (i * UNITS_PER_WORD)));
695 emit_move_insn (mem, gen_rtx_REG (Pmode, i));
696 }
697
698 *pretend_size = 0;
699}
700
701/* Value should be nonzero if functions must have frame pointers.
702 Zero means the frame pointer need not be set up (and parms may
703 be accessed via the stack pointer) in functions that seem suitable. */
704
705int
706bfin_frame_pointer_required (void)
707{
708 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
709
710 if (fkind != SUBROUTINE)
711 return 1;
712
a4d05547 713 /* We turn on -fomit-frame-pointer if -momit-leaf-frame-pointer is used,
0d4a78eb
BS
714 so we have to override it for non-leaf functions. */
715 if (TARGET_OMIT_LEAF_FRAME_POINTER && ! current_function_is_leaf)
716 return 1;
717
718 return 0;
719}
720
721/* Return the number of registers pushed during the prologue. */
722
723static int
724n_regs_saved_by_prologue (void)
725{
726 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
e989202f
BS
727 bool is_inthandler = fkind != SUBROUTINE;
728 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
729 bool all = (lookup_attribute ("saveall", attrs) != NULL_TREE
730 || (is_inthandler && !current_function_is_leaf));
4d82f261
BS
731 int ndregs = all ? 8 : n_dregs_to_save (is_inthandler, false);
732 int npregs = all ? 6 : n_pregs_to_save (is_inthandler, false);
e989202f 733 int n = ndregs + npregs;
bf3f9581 734 int i;
0d4a78eb 735
e989202f 736 if (all || stack_frame_needed_p ())
0d4a78eb
BS
737 /* We use a LINK instruction in this case. */
738 n += 2;
739 else
740 {
741 if (must_save_fp_p ())
742 n++;
743 if (! current_function_is_leaf)
744 n++;
745 }
746
bf3f9581
BS
747 if (fkind != SUBROUTINE || all)
748 /* Increment once for ASTAT. */
749 n++;
750
0d4a78eb
BS
751 if (fkind != SUBROUTINE)
752 {
0d4a78eb
BS
753 /* RETE/X/N. */
754 if (lookup_attribute ("nesting", attrs))
755 n++;
0d4a78eb 756 }
bf3f9581
BS
757
758 for (i = REG_P7 + 1; i < REG_CC; i++)
759 if (all
760 || (fkind != SUBROUTINE
761 && (df_regs_ever_live_p (i)
762 || (!leaf_function_p () && call_used_regs[i]))))
763 n += i == REG_A0 || i == REG_A1 ? 2 : 1;
764
0d4a78eb
BS
765 return n;
766}
767
768/* Return the offset between two registers, one to be eliminated, and the other
769 its replacement, at the start of a routine. */
770
771HOST_WIDE_INT
772bfin_initial_elimination_offset (int from, int to)
773{
774 HOST_WIDE_INT offset = 0;
775
776 if (from == ARG_POINTER_REGNUM)
777 offset = n_regs_saved_by_prologue () * 4;
778
779 if (to == STACK_POINTER_REGNUM)
780 {
38173d38
JH
781 if (crtl->outgoing_args_size >= FIXED_STACK_AREA)
782 offset += crtl->outgoing_args_size;
783 else if (crtl->outgoing_args_size)
0d4a78eb
BS
784 offset += FIXED_STACK_AREA;
785
786 offset += get_frame_size ();
787 }
788
789 return offset;
790}
791
792/* Emit code to load a constant CONSTANT into register REG; setting
09350e36
BS
793 RTX_FRAME_RELATED_P on all insns we generate if RELATED is true.
794 Make sure that the insns we generate need not be split. */
0d4a78eb
BS
795
796static void
09350e36 797frame_related_constant_load (rtx reg, HOST_WIDE_INT constant, bool related)
0d4a78eb
BS
798{
799 rtx insn;
800 rtx cst = GEN_INT (constant);
801
802 if (constant >= -32768 && constant < 65536)
803 insn = emit_move_insn (reg, cst);
804 else
805 {
806 /* We don't call split_load_immediate here, since dwarf2out.c can get
807 confused about some of the more clever sequences it can generate. */
808 insn = emit_insn (gen_movsi_high (reg, cst));
09350e36
BS
809 if (related)
810 RTX_FRAME_RELATED_P (insn) = 1;
0d4a78eb
BS
811 insn = emit_insn (gen_movsi_low (reg, reg, cst));
812 }
09350e36
BS
813 if (related)
814 RTX_FRAME_RELATED_P (insn) = 1;
0d4a78eb
BS
815}
816
1f9e4ca1
JZ
817/* Generate efficient code to add a value to a P register.
818 Set RTX_FRAME_RELATED_P on the generated insns if FRAME is nonzero.
819 EPILOGUE_P is zero if this function is called for prologue,
820 otherwise it's nonzero. And it's less than zero if this is for
821 sibcall epilogue. */
0d4a78eb
BS
822
823static void
1f9e4ca1 824add_to_reg (rtx reg, HOST_WIDE_INT value, int frame, int epilogue_p)
0d4a78eb
BS
825{
826 if (value == 0)
827 return;
828
829 /* Choose whether to use a sequence using a temporary register, or
942fd98f 830 a sequence with multiple adds. We can add a signed 7-bit value
0d4a78eb
BS
831 in one instruction. */
832 if (value > 120 || value < -120)
833 {
1f9e4ca1
JZ
834 rtx tmpreg;
835 rtx tmpreg2;
0d4a78eb
BS
836 rtx insn;
837
1f9e4ca1
JZ
838 tmpreg2 = NULL_RTX;
839
840 /* For prologue or normal epilogue, P1 can be safely used
841 as the temporary register. For sibcall epilogue, we try to find
842 a call used P register, which will be restored in epilogue.
843 If we cannot find such a P register, we have to use one I register
844 to help us. */
845
846 if (epilogue_p >= 0)
847 tmpreg = gen_rtx_REG (SImode, REG_P1);
848 else
849 {
850 int i;
851 for (i = REG_P0; i <= REG_P5; i++)
b18e284e 852 if ((df_regs_ever_live_p (i) && ! call_used_regs[i])
1f9e4ca1
JZ
853 || (!TARGET_FDPIC
854 && i == PIC_OFFSET_TABLE_REGNUM
e3b5732b 855 && (crtl->uses_pic_offset_table
1f9e4ca1
JZ
856 || (TARGET_ID_SHARED_LIBRARY
857 && ! current_function_is_leaf))))
858 break;
859 if (i <= REG_P5)
860 tmpreg = gen_rtx_REG (SImode, i);
861 else
862 {
863 tmpreg = gen_rtx_REG (SImode, REG_P1);
864 tmpreg2 = gen_rtx_REG (SImode, REG_I0);
865 emit_move_insn (tmpreg2, tmpreg);
866 }
867 }
868
0d4a78eb 869 if (frame)
09350e36 870 frame_related_constant_load (tmpreg, value, TRUE);
0d4a78eb 871 else
d6eb07dc 872 insn = emit_move_insn (tmpreg, GEN_INT (value));
0d4a78eb 873
d6eb07dc 874 insn = emit_insn (gen_addsi3 (reg, reg, tmpreg));
0d4a78eb
BS
875 if (frame)
876 RTX_FRAME_RELATED_P (insn) = 1;
1f9e4ca1
JZ
877
878 if (tmpreg2 != NULL_RTX)
879 emit_move_insn (tmpreg, tmpreg2);
0d4a78eb
BS
880 }
881 else
882 do
883 {
884 int size = value;
885 rtx insn;
886
887 if (size > 60)
888 size = 60;
889 else if (size < -60)
890 /* We could use -62, but that would leave the stack unaligned, so
891 it's no good. */
892 size = -60;
893
d6eb07dc 894 insn = emit_insn (gen_addsi3 (reg, reg, GEN_INT (size)));
0d4a78eb
BS
895 if (frame)
896 RTX_FRAME_RELATED_P (insn) = 1;
897 value -= size;
898 }
899 while (value != 0);
900}
901
902/* Generate a LINK insn for a frame sized FRAME_SIZE. If this constant
903 is too large, generate a sequence of insns that has the same effect.
904 SPREG contains (reg:SI REG_SP). */
905
906static void
907emit_link_insn (rtx spreg, HOST_WIDE_INT frame_size)
908{
909 HOST_WIDE_INT link_size = frame_size;
910 rtx insn;
911 int i;
912
913 if (link_size > 262140)
914 link_size = 262140;
915
916 /* Use a LINK insn with as big a constant as possible, then subtract
917 any remaining size from the SP. */
918 insn = emit_insn (gen_link (GEN_INT (-8 - link_size)));
919 RTX_FRAME_RELATED_P (insn) = 1;
920
921 for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
922 {
923 rtx set = XVECEXP (PATTERN (insn), 0, i);
3b9dd769 924 gcc_assert (GET_CODE (set) == SET);
0d4a78eb
BS
925 RTX_FRAME_RELATED_P (set) = 1;
926 }
927
928 frame_size -= link_size;
929
930 if (frame_size > 0)
931 {
932 /* Must use a call-clobbered PREG that isn't the static chain. */
933 rtx tmpreg = gen_rtx_REG (Pmode, REG_P1);
934
09350e36 935 frame_related_constant_load (tmpreg, -frame_size, TRUE);
0d4a78eb
BS
936 insn = emit_insn (gen_addsi3 (spreg, spreg, tmpreg));
937 RTX_FRAME_RELATED_P (insn) = 1;
938 }
939}
940
941/* Return the number of bytes we must reserve for outgoing arguments
942 in the current function's stack frame. */
943
944static HOST_WIDE_INT
945arg_area_size (void)
946{
38173d38 947 if (crtl->outgoing_args_size)
0d4a78eb 948 {
38173d38
JH
949 if (crtl->outgoing_args_size >= FIXED_STACK_AREA)
950 return crtl->outgoing_args_size;
0d4a78eb
BS
951 else
952 return FIXED_STACK_AREA;
953 }
954 return 0;
955}
956
e989202f
BS
957/* Save RETS and FP, and allocate a stack frame. ALL is true if the
958 function must save all its registers (true only for certain interrupt
959 handlers). */
0d4a78eb
BS
960
961static void
e989202f 962do_link (rtx spreg, HOST_WIDE_INT frame_size, bool all)
0d4a78eb
BS
963{
964 frame_size += arg_area_size ();
965
e989202f 966 if (all || stack_frame_needed_p ()
0d4a78eb
BS
967 || (must_save_fp_p () && ! current_function_is_leaf))
968 emit_link_insn (spreg, frame_size);
969 else
970 {
971 if (! current_function_is_leaf)
972 {
973 rtx pat = gen_movsi (gen_rtx_MEM (Pmode,
974 gen_rtx_PRE_DEC (Pmode, spreg)),
975 bfin_rets_rtx);
976 rtx insn = emit_insn (pat);
977 RTX_FRAME_RELATED_P (insn) = 1;
978 }
979 if (must_save_fp_p ())
980 {
981 rtx pat = gen_movsi (gen_rtx_MEM (Pmode,
982 gen_rtx_PRE_DEC (Pmode, spreg)),
983 gen_rtx_REG (Pmode, REG_FP));
984 rtx insn = emit_insn (pat);
985 RTX_FRAME_RELATED_P (insn) = 1;
986 }
1f9e4ca1 987 add_to_reg (spreg, -frame_size, 1, 0);
0d4a78eb
BS
988 }
989}
990
1f9e4ca1
JZ
991/* Like do_link, but used for epilogues to deallocate the stack frame.
992 EPILOGUE_P is zero if this function is called for prologue,
993 otherwise it's nonzero. And it's less than zero if this is for
994 sibcall epilogue. */
0d4a78eb
BS
995
996static void
1f9e4ca1 997do_unlink (rtx spreg, HOST_WIDE_INT frame_size, bool all, int epilogue_p)
0d4a78eb
BS
998{
999 frame_size += arg_area_size ();
1000
e989202f 1001 if (all || stack_frame_needed_p ())
0d4a78eb
BS
1002 emit_insn (gen_unlink ());
1003 else
1004 {
1005 rtx postinc = gen_rtx_MEM (Pmode, gen_rtx_POST_INC (Pmode, spreg));
1006
1f9e4ca1 1007 add_to_reg (spreg, frame_size, 0, epilogue_p);
0d4a78eb
BS
1008 if (must_save_fp_p ())
1009 {
1010 rtx fpreg = gen_rtx_REG (Pmode, REG_FP);
1011 emit_move_insn (fpreg, postinc);
c41c1387 1012 emit_use (fpreg);
0d4a78eb
BS
1013 }
1014 if (! current_function_is_leaf)
1015 {
1016 emit_move_insn (bfin_rets_rtx, postinc);
c41c1387 1017 emit_use (bfin_rets_rtx);
0d4a78eb
BS
1018 }
1019 }
1020}
1021
1022/* Generate a prologue suitable for a function of kind FKIND. This is
1023 called for interrupt and exception handler prologues.
1024 SPREG contains (reg:SI REG_SP). */
1025
1026static void
bf3f9581 1027expand_interrupt_handler_prologue (rtx spreg, e_funkind fkind, bool all)
0d4a78eb 1028{
0d4a78eb
BS
1029 HOST_WIDE_INT frame_size = get_frame_size ();
1030 rtx predec1 = gen_rtx_PRE_DEC (SImode, spreg);
1031 rtx predec = gen_rtx_MEM (SImode, predec1);
1032 rtx insn;
1033 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
0d4a78eb
BS
1034 tree kspisusp = lookup_attribute ("kspisusp", attrs);
1035
1036 if (kspisusp)
1037 {
1038 insn = emit_move_insn (spreg, gen_rtx_REG (Pmode, REG_USP));
1039 RTX_FRAME_RELATED_P (insn) = 1;
1040 }
1041
1042 /* We need space on the stack in case we need to save the argument
1043 registers. */
1044 if (fkind == EXCPT_HANDLER)
1045 {
1046 insn = emit_insn (gen_addsi3 (spreg, spreg, GEN_INT (-12)));
1047 RTX_FRAME_RELATED_P (insn) = 1;
1048 }
1049
e989202f
BS
1050 /* If we're calling other functions, they won't save their call-clobbered
1051 registers, so we must save everything here. */
1052 if (!current_function_is_leaf)
1053 all = true;
1054 expand_prologue_reg_save (spreg, all, true);
0d4a78eb 1055
0d4a78eb
BS
1056 if (lookup_attribute ("nesting", attrs))
1057 {
1058 rtx srcreg = gen_rtx_REG (Pmode, (fkind == EXCPT_HANDLER ? REG_RETX
1059 : fkind == NMI_HANDLER ? REG_RETN
1060 : REG_RETI));
1061 insn = emit_move_insn (predec, srcreg);
1062 RTX_FRAME_RELATED_P (insn) = 1;
1063 }
1064
e989202f 1065 do_link (spreg, frame_size, all);
0d4a78eb
BS
1066
1067 if (fkind == EXCPT_HANDLER)
1068 {
1069 rtx r0reg = gen_rtx_REG (SImode, REG_R0);
1070 rtx r1reg = gen_rtx_REG (SImode, REG_R1);
1071 rtx r2reg = gen_rtx_REG (SImode, REG_R2);
1072 rtx insn;
1073
1074 insn = emit_move_insn (r0reg, gen_rtx_REG (SImode, REG_SEQSTAT));
0d4a78eb 1075 insn = emit_insn (gen_ashrsi3 (r0reg, r0reg, GEN_INT (26)));
0d4a78eb 1076 insn = emit_insn (gen_ashlsi3 (r0reg, r0reg, GEN_INT (26)));
0d4a78eb 1077 insn = emit_move_insn (r1reg, spreg);
0d4a78eb 1078 insn = emit_move_insn (r2reg, gen_rtx_REG (Pmode, REG_FP));
0d4a78eb 1079 insn = emit_insn (gen_addsi3 (r2reg, r2reg, GEN_INT (8)));
0d4a78eb
BS
1080 }
1081}
1082
1083/* Generate an epilogue suitable for a function of kind FKIND. This is
1084 called for interrupt and exception handler epilogues.
1085 SPREG contains (reg:SI REG_SP). */
1086
1087static void
bf3f9581 1088expand_interrupt_handler_epilogue (rtx spreg, e_funkind fkind, bool all)
0d4a78eb 1089{
bf3f9581 1090 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
0d4a78eb
BS
1091 rtx postinc1 = gen_rtx_POST_INC (SImode, spreg);
1092 rtx postinc = gen_rtx_MEM (SImode, postinc1);
0d4a78eb
BS
1093
1094 /* A slightly crude technique to stop flow from trying to delete "dead"
1095 insns. */
1096 MEM_VOLATILE_P (postinc) = 1;
1097
1f9e4ca1 1098 do_unlink (spreg, get_frame_size (), all, 1);
0d4a78eb
BS
1099
1100 if (lookup_attribute ("nesting", attrs))
1101 {
1102 rtx srcreg = gen_rtx_REG (Pmode, (fkind == EXCPT_HANDLER ? REG_RETX
1103 : fkind == NMI_HANDLER ? REG_RETN
1104 : REG_RETI));
1105 emit_move_insn (srcreg, postinc);
1106 }
1107
e989202f
BS
1108 /* If we're calling other functions, they won't save their call-clobbered
1109 registers, so we must save (and restore) everything here. */
1110 if (!current_function_is_leaf)
1111 all = true;
1112
e989202f 1113 expand_epilogue_reg_restore (spreg, all, true);
0d4a78eb 1114
0d4a78eb
BS
1115 /* Deallocate any space we left on the stack in case we needed to save the
1116 argument registers. */
1117 if (fkind == EXCPT_HANDLER)
1118 emit_insn (gen_addsi3 (spreg, spreg, GEN_INT (12)));
1119
1120 emit_jump_insn (gen_return_internal (GEN_INT (fkind)));
1121}
1122
09350e36
BS
1123/* Used while emitting the prologue to generate code to load the correct value
1124 into the PIC register, which is passed in DEST. */
1125
9fc023cc 1126static rtx
09350e36
BS
1127bfin_load_pic_reg (rtx dest)
1128{
9fc023cc 1129 struct cgraph_local_info *i = NULL;
09350e36 1130 rtx addr, insn;
9fc023cc
BS
1131
1132 if (flag_unit_at_a_time)
1133 i = cgraph_local_info (current_function_decl);
1134
1135 /* Functions local to the translation unit don't need to reload the
1136 pic reg, since the caller always passes a usable one. */
1137 if (i && i->local)
1138 return pic_offset_table_rtx;
09350e36
BS
1139
1140 if (bfin_lib_id_given)
1141 addr = plus_constant (pic_offset_table_rtx, -4 - bfin_library_id * 4);
1142 else
1143 addr = gen_rtx_PLUS (Pmode, pic_offset_table_rtx,
1144 gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx),
1145 UNSPEC_LIBRARY_OFFSET));
1146 insn = emit_insn (gen_movsi (dest, gen_rtx_MEM (Pmode, addr)));
9fc023cc 1147 return dest;
09350e36
BS
1148}
1149
0d4a78eb
BS
1150/* Generate RTL for the prologue of the current function. */
1151
1152void
1153bfin_expand_prologue (void)
1154{
0d4a78eb
BS
1155 HOST_WIDE_INT frame_size = get_frame_size ();
1156 rtx spreg = gen_rtx_REG (Pmode, REG_SP);
1157 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
09350e36 1158 rtx pic_reg_loaded = NULL_RTX;
bf3f9581
BS
1159 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1160 bool all = lookup_attribute ("saveall", attrs) != NULL_TREE;
0d4a78eb
BS
1161
1162 if (fkind != SUBROUTINE)
1163 {
bf3f9581 1164 expand_interrupt_handler_prologue (spreg, fkind, all);
0d4a78eb
BS
1165 return;
1166 }
1167
e3b5732b 1168 if (crtl->limit_stack
d6eb07dc 1169 || TARGET_STACK_CHECK_L1)
09350e36
BS
1170 {
1171 HOST_WIDE_INT offset
1172 = bfin_initial_elimination_offset (ARG_POINTER_REGNUM,
1173 STACK_POINTER_REGNUM);
e3b5732b 1174 rtx lim = crtl->limit_stack ? stack_limit_rtx : NULL_RTX;
d6eb07dc 1175 rtx p2reg = gen_rtx_REG (Pmode, REG_P2);
09350e36 1176
d6eb07dc
BS
1177 if (!lim)
1178 {
d6eb07dc
BS
1179 emit_move_insn (p2reg, gen_int_mode (0xFFB00000, SImode));
1180 emit_move_insn (p2reg, gen_rtx_MEM (Pmode, p2reg));
1181 lim = p2reg;
1182 }
09350e36
BS
1183 if (GET_CODE (lim) == SYMBOL_REF)
1184 {
09350e36
BS
1185 if (TARGET_ID_SHARED_LIBRARY)
1186 {
1187 rtx p1reg = gen_rtx_REG (Pmode, REG_P1);
09350e36 1188 rtx val;
9fc023cc
BS
1189 pic_reg_loaded = bfin_load_pic_reg (p2reg);
1190 val = legitimize_pic_address (stack_limit_rtx, p1reg,
1191 pic_reg_loaded);
09350e36
BS
1192 emit_move_insn (p1reg, val);
1193 frame_related_constant_load (p2reg, offset, FALSE);
1194 emit_insn (gen_addsi3 (p2reg, p2reg, p1reg));
1195 lim = p2reg;
1196 }
1197 else
1198 {
d6eb07dc 1199 rtx limit = plus_constant (lim, offset);
09350e36
BS
1200 emit_move_insn (p2reg, limit);
1201 lim = p2reg;
1202 }
1203 }
d6eb07dc
BS
1204 else
1205 {
1206 if (lim != p2reg)
1207 emit_move_insn (p2reg, lim);
1f9e4ca1 1208 add_to_reg (p2reg, offset, 0, 0);
d6eb07dc
BS
1209 lim = p2reg;
1210 }
09350e36
BS
1211 emit_insn (gen_compare_lt (bfin_cc_rtx, spreg, lim));
1212 emit_insn (gen_trapifcc ());
1213 }
bf3f9581 1214 expand_prologue_reg_save (spreg, all, false);
0d4a78eb 1215
e989202f 1216 do_link (spreg, frame_size, false);
0d4a78eb
BS
1217
1218 if (TARGET_ID_SHARED_LIBRARY
93147119 1219 && !TARGET_SEP_DATA
e3b5732b 1220 && (crtl->uses_pic_offset_table
0d4a78eb 1221 || !current_function_is_leaf))
09350e36 1222 bfin_load_pic_reg (pic_offset_table_rtx);
0d4a78eb
BS
1223}
1224
1225/* Generate RTL for the epilogue of the current function. NEED_RETURN is zero
1226 if this is for a sibcall. EH_RETURN is nonzero if we're expanding an
1f9e4ca1
JZ
1227 eh_return pattern. SIBCALL_P is true if this is a sibcall epilogue,
1228 false otherwise. */
0d4a78eb
BS
1229
1230void
1f9e4ca1 1231bfin_expand_epilogue (int need_return, int eh_return, bool sibcall_p)
0d4a78eb
BS
1232{
1233 rtx spreg = gen_rtx_REG (Pmode, REG_SP);
1234 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
1f9e4ca1 1235 int e = sibcall_p ? -1 : 1;
bf3f9581
BS
1236 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1237 bool all = lookup_attribute ("saveall", attrs) != NULL_TREE;
0d4a78eb
BS
1238
1239 if (fkind != SUBROUTINE)
1240 {
bf3f9581 1241 expand_interrupt_handler_epilogue (spreg, fkind, all);
0d4a78eb
BS
1242 return;
1243 }
1244
1f9e4ca1 1245 do_unlink (spreg, get_frame_size (), false, e);
0d4a78eb 1246
bf3f9581 1247 expand_epilogue_reg_restore (spreg, all, false);
0d4a78eb
BS
1248
1249 /* Omit the return insn if this is for a sibcall. */
1250 if (! need_return)
1251 return;
1252
1253 if (eh_return)
1254 emit_insn (gen_addsi3 (spreg, spreg, gen_rtx_REG (Pmode, REG_P2)));
1255
1256 emit_jump_insn (gen_return_internal (GEN_INT (SUBROUTINE)));
1257}
1258\f
1259/* Return nonzero if register OLD_REG can be renamed to register NEW_REG. */
1260
1261int
1262bfin_hard_regno_rename_ok (unsigned int old_reg ATTRIBUTE_UNUSED,
1263 unsigned int new_reg)
1264{
1265 /* Interrupt functions can only use registers that have already been
1266 saved by the prologue, even if they would normally be
1267 call-clobbered. */
1268
1269 if (funkind (TREE_TYPE (current_function_decl)) != SUBROUTINE
6fb5fa3c 1270 && !df_regs_ever_live_p (new_reg))
0d4a78eb
BS
1271 return 0;
1272
1273 return 1;
1274}
1275
1276/* Return the value of the return address for the frame COUNT steps up
1277 from the current frame, after the prologue.
1278 We punt for everything but the current frame by returning const0_rtx. */
1279
1280rtx
1281bfin_return_addr_rtx (int count)
1282{
1283 if (count != 0)
1284 return const0_rtx;
1285
1286 return get_hard_reg_initial_val (Pmode, REG_RETS);
1287}
1288
1289/* Try machine-dependent ways of modifying an illegitimate address X
1290 to be legitimate. If we find one, return the new, valid address,
1291 otherwise return NULL_RTX.
1292
1293 OLDX is the address as it was before break_out_memory_refs was called.
1294 In some cases it is useful to look at this to decide what needs to be done.
1295
1296 MODE is the mode of the memory reference. */
1297
1298rtx
1299legitimize_address (rtx x ATTRIBUTE_UNUSED, rtx oldx ATTRIBUTE_UNUSED,
1300 enum machine_mode mode ATTRIBUTE_UNUSED)
1301{
1302 return NULL_RTX;
1303}
1304
54aefc36
JZ
1305static rtx
1306bfin_delegitimize_address (rtx orig_x)
1307{
266d11d8 1308 rtx x = orig_x;
54aefc36
JZ
1309
1310 if (GET_CODE (x) != MEM)
1311 return orig_x;
1312
1313 x = XEXP (x, 0);
1314 if (GET_CODE (x) == PLUS
1315 && GET_CODE (XEXP (x, 1)) == UNSPEC
1316 && XINT (XEXP (x, 1), 1) == UNSPEC_MOVE_PIC
1317 && GET_CODE (XEXP (x, 0)) == REG
1318 && REGNO (XEXP (x, 0)) == PIC_OFFSET_TABLE_REGNUM)
1319 return XVECEXP (XEXP (x, 1), 0, 0);
1320
1321 return orig_x;
1322}
1323
0d4a78eb
BS
1324/* This predicate is used to compute the length of a load/store insn.
1325 OP is a MEM rtx, we return nonzero if its addressing mode requires a
942fd98f 1326 32-bit instruction. */
0d4a78eb
BS
1327
1328int
1329effective_address_32bit_p (rtx op, enum machine_mode mode)
1330{
1331 HOST_WIDE_INT offset;
1332
1333 mode = GET_MODE (op);
1334 op = XEXP (op, 0);
1335
0d4a78eb 1336 if (GET_CODE (op) != PLUS)
3b9dd769
NS
1337 {
1338 gcc_assert (REG_P (op) || GET_CODE (op) == POST_INC
1339 || GET_CODE (op) == PRE_DEC || GET_CODE (op) == POST_DEC);
1340 return 0;
1341 }
0d4a78eb 1342
96f46444
BS
1343 if (GET_CODE (XEXP (op, 1)) == UNSPEC)
1344 return 1;
1345
0d4a78eb
BS
1346 offset = INTVAL (XEXP (op, 1));
1347
942fd98f 1348 /* All byte loads use a 16-bit offset. */
0d4a78eb
BS
1349 if (GET_MODE_SIZE (mode) == 1)
1350 return 1;
1351
1352 if (GET_MODE_SIZE (mode) == 4)
1353 {
1354 /* Frame pointer relative loads can use a negative offset, all others
1355 are restricted to a small positive one. */
1356 if (XEXP (op, 0) == frame_pointer_rtx)
1357 return offset < -128 || offset > 60;
1358 return offset < 0 || offset > 60;
1359 }
1360
1361 /* Must be HImode now. */
1362 return offset < 0 || offset > 30;
1363}
1364
c4963a0a
BS
1365/* Returns true if X is a memory reference using an I register. */
1366bool
1367bfin_dsp_memref_p (rtx x)
1368{
1369 if (! MEM_P (x))
1370 return false;
1371 x = XEXP (x, 0);
1372 if (GET_CODE (x) == POST_INC || GET_CODE (x) == PRE_INC
1373 || GET_CODE (x) == POST_DEC || GET_CODE (x) == PRE_DEC)
1374 x = XEXP (x, 0);
1375 return IREG_P (x);
1376}
1377
0d4a78eb
BS
1378/* Return cost of the memory address ADDR.
1379 All addressing modes are equally cheap on the Blackfin. */
1380
1381static int
1382bfin_address_cost (rtx addr ATTRIBUTE_UNUSED)
1383{
1384 return 1;
1385}
1386
1387/* Subroutine of print_operand; used to print a memory reference X to FILE. */
1388
1389void
1390print_address_operand (FILE *file, rtx x)
1391{
0d4a78eb
BS
1392 switch (GET_CODE (x))
1393 {
1394 case PLUS:
1395 output_address (XEXP (x, 0));
1396 fprintf (file, "+");
1397 output_address (XEXP (x, 1));
1398 break;
1399
1400 case PRE_DEC:
1401 fprintf (file, "--");
1402 output_address (XEXP (x, 0));
1403 break;
1404 case POST_INC:
1405 output_address (XEXP (x, 0));
1406 fprintf (file, "++");
1407 break;
1408 case POST_DEC:
1409 output_address (XEXP (x, 0));
1410 fprintf (file, "--");
1411 break;
1412
1413 default:
3b9dd769 1414 gcc_assert (GET_CODE (x) != MEM);
0d4a78eb 1415 print_operand (file, x, 0);
3b9dd769 1416 break;
0d4a78eb
BS
1417 }
1418}
1419
1420/* Adding intp DImode support by Tony
1421 * -- Q: (low word)
1422 * -- R: (high word)
1423 */
1424
1425void
1426print_operand (FILE *file, rtx x, char code)
1427{
bbbc206e
BS
1428 enum machine_mode mode;
1429
1430 if (code == '!')
1431 {
1432 if (GET_MODE (current_output_insn) == SImode)
1433 fprintf (file, " ||");
1434 else
1435 fprintf (file, ";");
1436 return;
1437 }
1438
1439 mode = GET_MODE (x);
0d4a78eb
BS
1440
1441 switch (code)
1442 {
1443 case 'j':
1444 switch (GET_CODE (x))
1445 {
1446 case EQ:
1447 fprintf (file, "e");
1448 break;
1449 case NE:
1450 fprintf (file, "ne");
1451 break;
1452 case GT:
1453 fprintf (file, "g");
1454 break;
1455 case LT:
1456 fprintf (file, "l");
1457 break;
1458 case GE:
1459 fprintf (file, "ge");
1460 break;
1461 case LE:
1462 fprintf (file, "le");
1463 break;
1464 case GTU:
1465 fprintf (file, "g");
1466 break;
1467 case LTU:
1468 fprintf (file, "l");
1469 break;
1470 case GEU:
1471 fprintf (file, "ge");
1472 break;
1473 case LEU:
1474 fprintf (file, "le");
1475 break;
1476 default:
1477 output_operand_lossage ("invalid %%j value");
1478 }
1479 break;
1480
1481 case 'J': /* reverse logic */
1482 switch (GET_CODE(x))
1483 {
1484 case EQ:
1485 fprintf (file, "ne");
1486 break;
1487 case NE:
1488 fprintf (file, "e");
1489 break;
1490 case GT:
1491 fprintf (file, "le");
1492 break;
1493 case LT:
1494 fprintf (file, "ge");
1495 break;
1496 case GE:
1497 fprintf (file, "l");
1498 break;
1499 case LE:
1500 fprintf (file, "g");
1501 break;
1502 case GTU:
1503 fprintf (file, "le");
1504 break;
1505 case LTU:
1506 fprintf (file, "ge");
1507 break;
1508 case GEU:
1509 fprintf (file, "l");
1510 break;
1511 case LEU:
1512 fprintf (file, "g");
1513 break;
1514 default:
1515 output_operand_lossage ("invalid %%J value");
1516 }
1517 break;
1518
1519 default:
1520 switch (GET_CODE (x))
1521 {
1522 case REG:
1523 if (code == 'h')
1524 {
b570063a
JZ
1525 if (REGNO (x) < 32)
1526 fprintf (file, "%s", short_reg_names[REGNO (x)]);
1527 else
1528 output_operand_lossage ("invalid operand for code '%c'", code);
0d4a78eb
BS
1529 }
1530 else if (code == 'd')
1531 {
b570063a
JZ
1532 if (REGNO (x) < 32)
1533 fprintf (file, "%s", high_reg_names[REGNO (x)]);
1534 else
1535 output_operand_lossage ("invalid operand for code '%c'", code);
0d4a78eb
BS
1536 }
1537 else if (code == 'w')
1538 {
b570063a
JZ
1539 if (REGNO (x) == REG_A0 || REGNO (x) == REG_A1)
1540 fprintf (file, "%s.w", reg_names[REGNO (x)]);
1541 else
1542 output_operand_lossage ("invalid operand for code '%c'", code);
0d4a78eb
BS
1543 }
1544 else if (code == 'x')
1545 {
b570063a
JZ
1546 if (REGNO (x) == REG_A0 || REGNO (x) == REG_A1)
1547 fprintf (file, "%s.x", reg_names[REGNO (x)]);
1548 else
1549 output_operand_lossage ("invalid operand for code '%c'", code);
0d4a78eb 1550 }
26c5953d
BS
1551 else if (code == 'v')
1552 {
1553 if (REGNO (x) == REG_A0)
1554 fprintf (file, "AV0");
1555 else if (REGNO (x) == REG_A1)
1556 fprintf (file, "AV1");
1557 else
1558 output_operand_lossage ("invalid operand for code '%c'", code);
1559 }
0d4a78eb
BS
1560 else if (code == 'D')
1561 {
b570063a
JZ
1562 if (D_REGNO_P (REGNO (x)))
1563 fprintf (file, "%s", dregs_pair_names[REGNO (x)]);
1564 else
1565 output_operand_lossage ("invalid operand for code '%c'", code);
0d4a78eb
BS
1566 }
1567 else if (code == 'H')
1568 {
b570063a
JZ
1569 if ((mode == DImode || mode == DFmode) && REG_P (x))
1570 fprintf (file, "%s", reg_names[REGNO (x) + 1]);
1571 else
1572 output_operand_lossage ("invalid operand for code '%c'", code);
0d4a78eb
BS
1573 }
1574 else if (code == 'T')
1575 {
b570063a
JZ
1576 if (D_REGNO_P (REGNO (x)))
1577 fprintf (file, "%s", byte_reg_names[REGNO (x)]);
1578 else
1579 output_operand_lossage ("invalid operand for code '%c'", code);
0d4a78eb
BS
1580 }
1581 else
1582 fprintf (file, "%s", reg_names[REGNO (x)]);
1583 break;
1584
1585 case MEM:
1586 fputc ('[', file);
1587 x = XEXP (x,0);
1588 print_address_operand (file, x);
1589 fputc (']', file);
1590 break;
1591
1592 case CONST_INT:
75d8b2d0
BS
1593 if (code == 'M')
1594 {
1595 switch (INTVAL (x))
1596 {
1597 case MACFLAG_NONE:
1598 break;
1599 case MACFLAG_FU:
1600 fputs ("(FU)", file);
1601 break;
1602 case MACFLAG_T:
1603 fputs ("(T)", file);
1604 break;
1605 case MACFLAG_TFU:
1606 fputs ("(TFU)", file);
1607 break;
1608 case MACFLAG_W32:
1609 fputs ("(W32)", file);
1610 break;
1611 case MACFLAG_IS:
1612 fputs ("(IS)", file);
1613 break;
1614 case MACFLAG_IU:
1615 fputs ("(IU)", file);
1616 break;
1617 case MACFLAG_IH:
1618 fputs ("(IH)", file);
1619 break;
1620 case MACFLAG_M:
1621 fputs ("(M)", file);
1622 break;
3efd5670
BS
1623 case MACFLAG_IS_M:
1624 fputs ("(IS,M)", file);
1625 break;
75d8b2d0
BS
1626 case MACFLAG_ISS2:
1627 fputs ("(ISS2)", file);
1628 break;
1629 case MACFLAG_S2RND:
1630 fputs ("(S2RND)", file);
1631 break;
1632 default:
1633 gcc_unreachable ();
1634 }
1635 break;
1636 }
1637 else if (code == 'b')
1638 {
1639 if (INTVAL (x) == 0)
1640 fputs ("+=", file);
1641 else if (INTVAL (x) == 1)
1642 fputs ("-=", file);
1643 else
1644 gcc_unreachable ();
1645 break;
1646 }
0d4a78eb
BS
1647 /* Moves to half registers with d or h modifiers always use unsigned
1648 constants. */
75d8b2d0 1649 else if (code == 'd')
0d4a78eb
BS
1650 x = GEN_INT ((INTVAL (x) >> 16) & 0xffff);
1651 else if (code == 'h')
1652 x = GEN_INT (INTVAL (x) & 0xffff);
58f76679
BS
1653 else if (code == 'N')
1654 x = GEN_INT (-INTVAL (x));
0d4a78eb
BS
1655 else if (code == 'X')
1656 x = GEN_INT (exact_log2 (0xffffffff & INTVAL (x)));
1657 else if (code == 'Y')
1658 x = GEN_INT (exact_log2 (0xffffffff & ~INTVAL (x)));
1659 else if (code == 'Z')
1660 /* Used for LINK insns. */
1661 x = GEN_INT (-8 - INTVAL (x));
1662
1663 /* fall through */
1664
1665 case SYMBOL_REF:
1666 output_addr_const (file, x);
0d4a78eb
BS
1667 break;
1668
1669 case CONST_DOUBLE:
1670 output_operand_lossage ("invalid const_double operand");
1671 break;
1672
1673 case UNSPEC:
3b9dd769 1674 switch (XINT (x, 1))
0d4a78eb 1675 {
3b9dd769 1676 case UNSPEC_MOVE_PIC:
0d4a78eb
BS
1677 output_addr_const (file, XVECEXP (x, 0, 0));
1678 fprintf (file, "@GOT");
3b9dd769
NS
1679 break;
1680
6614f9f5
BS
1681 case UNSPEC_MOVE_FDPIC:
1682 output_addr_const (file, XVECEXP (x, 0, 0));
1683 fprintf (file, "@GOT17M4");
1684 break;
1685
1686 case UNSPEC_FUNCDESC_GOT17M4:
1687 output_addr_const (file, XVECEXP (x, 0, 0));
1688 fprintf (file, "@FUNCDESC_GOT17M4");
1689 break;
1690
3b9dd769
NS
1691 case UNSPEC_LIBRARY_OFFSET:
1692 fprintf (file, "_current_shared_library_p5_offset_");
1693 break;
1694
1695 default:
1696 gcc_unreachable ();
0d4a78eb 1697 }
0d4a78eb
BS
1698 break;
1699
1700 default:
1701 output_addr_const (file, x);
1702 }
1703 }
1704}
1705\f
1706/* Argument support functions. */
1707
1708/* Initialize a variable CUM of type CUMULATIVE_ARGS
1709 for a call to a function whose data type is FNTYPE.
1710 For a library call, FNTYPE is 0.
1711 VDSP C Compiler manual, our ABI says that
1712 first 3 words of arguments will use R0, R1 and R2.
1713*/
1714
1715void
6d459e2b 1716init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype,
0d4a78eb
BS
1717 rtx libname ATTRIBUTE_UNUSED)
1718{
1719 static CUMULATIVE_ARGS zero_cum;
1720
1721 *cum = zero_cum;
1722
1723 /* Set up the number of registers to use for passing arguments. */
1724
1725 cum->nregs = max_arg_registers;
1726 cum->arg_regs = arg_regs;
1727
6d459e2b
BS
1728 cum->call_cookie = CALL_NORMAL;
1729 /* Check for a longcall attribute. */
1730 if (fntype && lookup_attribute ("shortcall", TYPE_ATTRIBUTES (fntype)))
1731 cum->call_cookie |= CALL_SHORT;
1732 else if (fntype && lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype)))
1733 cum->call_cookie |= CALL_LONG;
1734
0d4a78eb
BS
1735 return;
1736}
1737
1738/* Update the data in CUM to advance over an argument
1739 of mode MODE and data type TYPE.
1740 (TYPE is null for libcalls where that information may not be available.) */
1741
1742void
1743function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
1744 int named ATTRIBUTE_UNUSED)
1745{
1746 int count, bytes, words;
1747
1748 bytes = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
1749 words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
1750
1751 cum->words += words;
1752 cum->nregs -= words;
1753
1754 if (cum->nregs <= 0)
1755 {
1756 cum->nregs = 0;
1757 cum->arg_regs = NULL;
1758 }
1759 else
1760 {
1761 for (count = 1; count <= words; count++)
1762 cum->arg_regs++;
1763 }
1764
1765 return;
1766}
1767
1768/* Define where to put the arguments to a function.
1769 Value is zero to push the argument on the stack,
1770 or a hard register in which to store the argument.
1771
1772 MODE is the argument's machine mode.
1773 TYPE is the data type of the argument (as a tree).
1774 This is null for libcalls where that information may
1775 not be available.
1776 CUM is a variable of type CUMULATIVE_ARGS which gives info about
1777 the preceding args and about the function being called.
1778 NAMED is nonzero if this argument is a named parameter
1779 (otherwise it is an extra parameter matching an ellipsis). */
1780
1781struct rtx_def *
1782function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
1783 int named ATTRIBUTE_UNUSED)
1784{
1785 int bytes
1786 = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
1787
6d459e2b
BS
1788 if (mode == VOIDmode)
1789 /* Compute operand 2 of the call insn. */
1790 return GEN_INT (cum->call_cookie);
1791
0d4a78eb
BS
1792 if (bytes == -1)
1793 return NULL_RTX;
1794
1795 if (cum->nregs)
1796 return gen_rtx_REG (mode, *(cum->arg_regs));
1797
1798 return NULL_RTX;
1799}
1800
1801/* For an arg passed partly in registers and partly in memory,
1802 this is the number of bytes passed in registers.
1803 For args passed entirely in registers or entirely in memory, zero.
1804
1805 Refer VDSP C Compiler manual, our ABI.
ea2c620c 1806 First 3 words are in registers. So, if an argument is larger
0d4a78eb
BS
1807 than the registers available, it will span the register and
1808 stack. */
1809
1810static int
1811bfin_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode,
1812 tree type ATTRIBUTE_UNUSED,
1813 bool named ATTRIBUTE_UNUSED)
1814{
1815 int bytes
1816 = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
1817 int bytes_left = cum->nregs * UNITS_PER_WORD;
1818
1819 if (bytes == -1)
1820 return 0;
1821
1822 if (bytes_left == 0)
1823 return 0;
1824 if (bytes > bytes_left)
1825 return bytes_left;
1826 return 0;
1827}
1828
1829/* Variable sized types are passed by reference. */
1830
1831static bool
1832bfin_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
1833 enum machine_mode mode ATTRIBUTE_UNUSED,
586de218 1834 const_tree type, bool named ATTRIBUTE_UNUSED)
0d4a78eb
BS
1835{
1836 return type && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST;
1837}
1838
1839/* Decide whether a type should be returned in memory (true)
1840 or in a register (false). This is called by the macro
81464b2c 1841 TARGET_RETURN_IN_MEMORY. */
0d4a78eb 1842
7ba20e60 1843static bool
81464b2c 1844bfin_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
0d4a78eb 1845{
07da68fd
JZ
1846 int size = int_size_in_bytes (type);
1847 return size > 2 * UNITS_PER_WORD || size == -1;
0d4a78eb
BS
1848}
1849
1850/* Register in which address to store a structure value
1851 is passed to a function. */
1852static rtx
1853bfin_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
1854 int incoming ATTRIBUTE_UNUSED)
1855{
1856 return gen_rtx_REG (Pmode, REG_P0);
1857}
1858
1859/* Return true when register may be used to pass function parameters. */
1860
1861bool
1862function_arg_regno_p (int n)
1863{
1864 int i;
1865 for (i = 0; arg_regs[i] != -1; i++)
1866 if (n == arg_regs[i])
1867 return true;
1868 return false;
1869}
1870
1871/* Returns 1 if OP contains a symbol reference */
1872
1873int
1874symbolic_reference_mentioned_p (rtx op)
1875{
1876 register const char *fmt;
1877 register int i;
1878
1879 if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF)
1880 return 1;
1881
1882 fmt = GET_RTX_FORMAT (GET_CODE (op));
1883 for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
1884 {
1885 if (fmt[i] == 'E')
1886 {
1887 register int j;
1888
1889 for (j = XVECLEN (op, i) - 1; j >= 0; j--)
1890 if (symbolic_reference_mentioned_p (XVECEXP (op, i, j)))
1891 return 1;
1892 }
1893
1894 else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i)))
1895 return 1;
1896 }
1897
1898 return 0;
1899}
1900
1901/* Decide whether we can make a sibling call to a function. DECL is the
1902 declaration of the function being targeted by the call and EXP is the
1903 CALL_EXPR representing the call. */
1904
1905static bool
1906bfin_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED,
1907 tree exp ATTRIBUTE_UNUSED)
1908{
e989202f 1909 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
bcbb974d
BS
1910 if (fkind != SUBROUTINE)
1911 return false;
1912 if (!TARGET_ID_SHARED_LIBRARY || TARGET_SEP_DATA)
1913 return true;
1914
1915 /* When compiling for ID shared libraries, can't sibcall a local function
1916 from a non-local function, because the local function thinks it does
1917 not need to reload P5 in the prologue, but the sibcall wil pop P5 in the
1918 sibcall epilogue, and we end up with the wrong value in P5. */
1919
1920 if (!flag_unit_at_a_time || decl == NULL)
1921 /* Not enough information. */
1922 return false;
1923
1924 {
1925 struct cgraph_local_info *this_func, *called_func;
bcbb974d
BS
1926
1927 this_func = cgraph_local_info (current_function_decl);
1928 called_func = cgraph_local_info (decl);
1929 return !called_func->local || this_func->local;
1930 }
0d4a78eb
BS
1931}
1932\f
1933/* Emit RTL insns to initialize the variable parts of a trampoline at
1934 TRAMP. FNADDR is an RTX for the address of the function's pure
1935 code. CXT is an RTX for the static chain value for the function. */
1936
1937void
266d11d8 1938initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt)
0d4a78eb
BS
1939{
1940 rtx t1 = copy_to_reg (fnaddr);
1941 rtx t2 = copy_to_reg (cxt);
1942 rtx addr;
6614f9f5
BS
1943 int i = 0;
1944
1945 if (TARGET_FDPIC)
1946 {
1947 rtx a = memory_address (Pmode, plus_constant (tramp, 8));
1948 addr = memory_address (Pmode, tramp);
1949 emit_move_insn (gen_rtx_MEM (SImode, addr), a);
1950 i = 8;
1951 }
0d4a78eb 1952
6614f9f5 1953 addr = memory_address (Pmode, plus_constant (tramp, i + 2));
0d4a78eb
BS
1954 emit_move_insn (gen_rtx_MEM (HImode, addr), gen_lowpart (HImode, t1));
1955 emit_insn (gen_ashrsi3 (t1, t1, GEN_INT (16)));
6614f9f5 1956 addr = memory_address (Pmode, plus_constant (tramp, i + 6));
0d4a78eb
BS
1957 emit_move_insn (gen_rtx_MEM (HImode, addr), gen_lowpart (HImode, t1));
1958
6614f9f5 1959 addr = memory_address (Pmode, plus_constant (tramp, i + 10));
0d4a78eb
BS
1960 emit_move_insn (gen_rtx_MEM (HImode, addr), gen_lowpart (HImode, t2));
1961 emit_insn (gen_ashrsi3 (t2, t2, GEN_INT (16)));
6614f9f5 1962 addr = memory_address (Pmode, plus_constant (tramp, i + 14));
0d4a78eb
BS
1963 emit_move_insn (gen_rtx_MEM (HImode, addr), gen_lowpart (HImode, t2));
1964}
1965
0d4a78eb
BS
1966/* Emit insns to move operands[1] into operands[0]. */
1967
1968void
1969emit_pic_move (rtx *operands, enum machine_mode mode ATTRIBUTE_UNUSED)
1970{
1971 rtx temp = reload_in_progress ? operands[0] : gen_reg_rtx (Pmode);
1972
6614f9f5 1973 gcc_assert (!TARGET_FDPIC || !(reload_in_progress || reload_completed));
0d4a78eb
BS
1974 if (GET_CODE (operands[0]) == MEM && SYMBOLIC_CONST (operands[1]))
1975 operands[1] = force_reg (SImode, operands[1]);
1976 else
09350e36 1977 operands[1] = legitimize_pic_address (operands[1], temp,
6614f9f5
BS
1978 TARGET_FDPIC ? OUR_FDPIC_REG
1979 : pic_offset_table_rtx);
0d4a78eb
BS
1980}
1981
d6f6753e
BS
1982/* Expand a move operation in mode MODE. The operands are in OPERANDS.
1983 Returns true if no further code must be generated, false if the caller
1984 should generate an insn to move OPERANDS[1] to OPERANDS[0]. */
0d4a78eb 1985
d6f6753e 1986bool
0d4a78eb
BS
1987expand_move (rtx *operands, enum machine_mode mode)
1988{
6614f9f5
BS
1989 rtx op = operands[1];
1990 if ((TARGET_ID_SHARED_LIBRARY || TARGET_FDPIC)
1991 && SYMBOLIC_CONST (op))
0d4a78eb 1992 emit_pic_move (operands, mode);
d6f6753e
BS
1993 else if (mode == SImode && GET_CODE (op) == CONST
1994 && GET_CODE (XEXP (op, 0)) == PLUS
1995 && GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF
1996 && !bfin_legitimate_constant_p (op))
1997 {
1998 rtx dest = operands[0];
1999 rtx op0, op1;
2000 gcc_assert (!reload_in_progress && !reload_completed);
2001 op = XEXP (op, 0);
2002 op0 = force_reg (mode, XEXP (op, 0));
2003 op1 = XEXP (op, 1);
2004 if (!insn_data[CODE_FOR_addsi3].operand[2].predicate (op1, mode))
2005 op1 = force_reg (mode, op1);
2006 if (GET_CODE (dest) == MEM)
2007 dest = gen_reg_rtx (mode);
2008 emit_insn (gen_addsi3 (dest, op0, op1));
2009 if (dest == operands[0])
2010 return true;
2011 operands[1] = dest;
2012 }
0d4a78eb
BS
2013 /* Don't generate memory->memory or constant->memory moves, go through a
2014 register */
2015 else if ((reload_in_progress | reload_completed) == 0
2016 && GET_CODE (operands[0]) == MEM
2017 && GET_CODE (operands[1]) != REG)
2018 operands[1] = force_reg (mode, operands[1]);
d6f6753e 2019 return false;
0d4a78eb
BS
2020}
2021\f
2022/* Split one or more DImode RTL references into pairs of SImode
2023 references. The RTL can be REG, offsettable MEM, integer constant, or
2024 CONST_DOUBLE. "operands" is a pointer to an array of DImode RTL to
2025 split and "num" is its length. lo_half and hi_half are output arrays
2026 that parallel "operands". */
2027
2028void
2029split_di (rtx operands[], int num, rtx lo_half[], rtx hi_half[])
2030{
2031 while (num--)
2032 {
2033 rtx op = operands[num];
2034
2035 /* simplify_subreg refuse to split volatile memory addresses,
2036 but we still have to handle it. */
2037 if (GET_CODE (op) == MEM)
2038 {
2039 lo_half[num] = adjust_address (op, SImode, 0);
2040 hi_half[num] = adjust_address (op, SImode, 4);
2041 }
2042 else
2043 {
2044 lo_half[num] = simplify_gen_subreg (SImode, op,
2045 GET_MODE (op) == VOIDmode
2046 ? DImode : GET_MODE (op), 0);
2047 hi_half[num] = simplify_gen_subreg (SImode, op,
2048 GET_MODE (op) == VOIDmode
2049 ? DImode : GET_MODE (op), 4);
2050 }
2051 }
2052}
2053\f
6d459e2b
BS
2054bool
2055bfin_longcall_p (rtx op, int call_cookie)
2056{
2057 gcc_assert (GET_CODE (op) == SYMBOL_REF);
2058 if (call_cookie & CALL_SHORT)
2059 return 0;
2060 if (call_cookie & CALL_LONG)
2061 return 1;
2062 if (TARGET_LONG_CALLS)
2063 return 1;
2064 return 0;
2065}
2066
0d4a78eb 2067/* Expand a call instruction. FNADDR is the call target, RETVAL the return value.
6d459e2b 2068 COOKIE is a CONST_INT holding the call_cookie prepared init_cumulative_args.
0d4a78eb
BS
2069 SIBCALL is nonzero if this is a sibling call. */
2070
2071void
6d459e2b 2072bfin_expand_call (rtx retval, rtx fnaddr, rtx callarg1, rtx cookie, int sibcall)
0d4a78eb
BS
2073{
2074 rtx use = NULL, call;
6d459e2b 2075 rtx callee = XEXP (fnaddr, 0);
6614f9f5
BS
2076 int nelts = 2 + !!sibcall;
2077 rtx pat;
2078 rtx picreg = get_hard_reg_initial_val (SImode, FDPIC_REGNO);
2079 int n;
6d459e2b
BS
2080
2081 /* In an untyped call, we can get NULL for operand 2. */
2082 if (cookie == NULL_RTX)
2083 cookie = const0_rtx;
0d4a78eb
BS
2084
2085 /* Static functions and indirect calls don't need the pic register. */
6614f9f5 2086 if (!TARGET_FDPIC && flag_pic
6d459e2b
BS
2087 && GET_CODE (callee) == SYMBOL_REF
2088 && !SYMBOL_REF_LOCAL_P (callee))
0d4a78eb
BS
2089 use_reg (&use, pic_offset_table_rtx);
2090
6614f9f5
BS
2091 if (TARGET_FDPIC)
2092 {
4af797b5
JZ
2093 int caller_has_l1_text, callee_has_l1_text;
2094
2095 caller_has_l1_text = callee_has_l1_text = 0;
2096
2097 if (lookup_attribute ("l1_text",
2098 DECL_ATTRIBUTES (cfun->decl)) != NULL_TREE)
2099 caller_has_l1_text = 1;
2100
2101 if (GET_CODE (callee) == SYMBOL_REF
2102 && SYMBOL_REF_DECL (callee) && DECL_P (SYMBOL_REF_DECL (callee))
2103 && lookup_attribute
2104 ("l1_text",
2105 DECL_ATTRIBUTES (SYMBOL_REF_DECL (callee))) != NULL_TREE)
2106 callee_has_l1_text = 1;
2107
6614f9f5 2108 if (GET_CODE (callee) != SYMBOL_REF
e874e49f
JZ
2109 || bfin_longcall_p (callee, INTVAL (cookie))
2110 || (GET_CODE (callee) == SYMBOL_REF
2111 && !SYMBOL_REF_LOCAL_P (callee)
4af797b5
JZ
2112 && TARGET_INLINE_PLT)
2113 || caller_has_l1_text != callee_has_l1_text
2114 || (caller_has_l1_text && callee_has_l1_text
2115 && (GET_CODE (callee) != SYMBOL_REF
2116 || !SYMBOL_REF_LOCAL_P (callee))))
6614f9f5
BS
2117 {
2118 rtx addr = callee;
2119 if (! address_operand (addr, Pmode))
2120 addr = force_reg (Pmode, addr);
2121
2122 fnaddr = gen_reg_rtx (SImode);
2123 emit_insn (gen_load_funcdescsi (fnaddr, addr));
2124 fnaddr = gen_rtx_MEM (Pmode, fnaddr);
2125
2126 picreg = gen_reg_rtx (SImode);
2127 emit_insn (gen_load_funcdescsi (picreg,
2128 plus_constant (addr, 4)));
2129 }
2130
2131 nelts++;
2132 }
2133 else if ((!register_no_elim_operand (callee, Pmode)
2134 && GET_CODE (callee) != SYMBOL_REF)
2135 || (GET_CODE (callee) == SYMBOL_REF
93147119 2136 && ((TARGET_ID_SHARED_LIBRARY && !TARGET_LEAF_ID_SHARED_LIBRARY)
6614f9f5 2137 || bfin_longcall_p (callee, INTVAL (cookie)))))
0d4a78eb 2138 {
6d459e2b
BS
2139 callee = copy_to_mode_reg (Pmode, callee);
2140 fnaddr = gen_rtx_MEM (Pmode, callee);
0d4a78eb
BS
2141 }
2142 call = gen_rtx_CALL (VOIDmode, fnaddr, callarg1);
2143
2144 if (retval)
2145 call = gen_rtx_SET (VOIDmode, retval, call);
6d459e2b 2146
6614f9f5
BS
2147 pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (nelts));
2148 n = 0;
2149 XVECEXP (pat, 0, n++) = call;
2150 if (TARGET_FDPIC)
2151 XVECEXP (pat, 0, n++) = gen_rtx_USE (VOIDmode, picreg);
2152 XVECEXP (pat, 0, n++) = gen_rtx_USE (VOIDmode, cookie);
0d4a78eb 2153 if (sibcall)
6614f9f5 2154 XVECEXP (pat, 0, n++) = gen_rtx_RETURN (VOIDmode);
6d459e2b 2155 call = emit_call_insn (pat);
0d4a78eb
BS
2156 if (use)
2157 CALL_INSN_FUNCTION_USAGE (call) = use;
2158}
2159\f
2160/* Return 1 if hard register REGNO can hold a value of machine-mode MODE. */
2161
2162int
2163hard_regno_mode_ok (int regno, enum machine_mode mode)
2164{
2165 /* Allow only dregs to store value of mode HI or QI */
2166 enum reg_class class = REGNO_REG_CLASS (regno);
2167
2168 if (mode == CCmode)
2169 return 0;
2170
2171 if (mode == V2HImode)
2172 return D_REGNO_P (regno);
2173 if (class == CCREGS)
2174 return mode == BImode;
75d8b2d0 2175 if (mode == PDImode || mode == V2PDImode)
0d4a78eb 2176 return regno == REG_A0 || regno == REG_A1;
84e32cbb 2177
942fd98f 2178 /* Allow all normal 32-bit regs, except REG_M3, in case regclass ever comes
84e32cbb
BS
2179 up with a bad register class (such as ALL_REGS) for DImode. */
2180 if (mode == DImode)
2181 return regno < REG_M3;
2182
0d4a78eb
BS
2183 if (mode == SImode
2184 && TEST_HARD_REG_BIT (reg_class_contents[PROLOGUE_REGS], regno))
2185 return 1;
84e32cbb 2186
0d4a78eb
BS
2187 return TEST_HARD_REG_BIT (reg_class_contents[MOST_REGS], regno);
2188}
2189
2190/* Implements target hook vector_mode_supported_p. */
2191
2192static bool
2193bfin_vector_mode_supported_p (enum machine_mode mode)
2194{
2195 return mode == V2HImode;
2196}
2197
2198/* Return the cost of moving data from a register in class CLASS1 to
2199 one in class CLASS2. A cost of 2 is the default. */
2200
2201int
84e32cbb 2202bfin_register_move_cost (enum machine_mode mode,
0d4a78eb
BS
2203 enum reg_class class1, enum reg_class class2)
2204{
4729dc92
BS
2205 /* These need secondary reloads, so they're more expensive. */
2206 if ((class1 == CCREGS && class2 != DREGS)
2207 || (class1 != DREGS && class2 == CCREGS))
2208 return 4;
2209
0d4a78eb
BS
2210 /* If optimizing for size, always prefer reg-reg over reg-memory moves. */
2211 if (optimize_size)
2212 return 2;
2213
2214 /* There are some stalls involved when moving from a DREG to a different
2215 class reg, and using the value in one of the following instructions.
2216 Attempt to model this by slightly discouraging such moves. */
2217 if (class1 == DREGS && class2 != DREGS)
2218 return 2 * 2;
2219
84e32cbb
BS
2220 if (GET_MODE_CLASS (mode) == MODE_INT)
2221 {
2222 /* Discourage trying to use the accumulators. */
2223 if (TEST_HARD_REG_BIT (reg_class_contents[class1], REG_A0)
2224 || TEST_HARD_REG_BIT (reg_class_contents[class1], REG_A1)
2225 || TEST_HARD_REG_BIT (reg_class_contents[class2], REG_A0)
2226 || TEST_HARD_REG_BIT (reg_class_contents[class2], REG_A1))
2227 return 20;
2228 }
0d4a78eb
BS
2229 return 2;
2230}
2231
2232/* Return the cost of moving data of mode M between a
2233 register and memory. A value of 2 is the default; this cost is
2234 relative to those in `REGISTER_MOVE_COST'.
2235
2236 ??? In theory L1 memory has single-cycle latency. We should add a switch
2237 that tells the compiler whether we expect to use only L1 memory for the
2238 program; it'll make the costs more accurate. */
2239
2240int
2241bfin_memory_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
2242 enum reg_class class,
2243 int in ATTRIBUTE_UNUSED)
2244{
2245 /* Make memory accesses slightly more expensive than any register-register
2246 move. Also, penalize non-DP registers, since they need secondary
2247 reloads to load and store. */
2248 if (! reg_class_subset_p (class, DPREGS))
2249 return 10;
2250
2251 return 8;
2252}
2253
2254/* Inform reload about cases where moving X with a mode MODE to a register in
2255 CLASS requires an extra scratch register. Return the class needed for the
2256 scratch register. */
2257
e97f2058 2258static enum reg_class
6ed44ca1
BS
2259bfin_secondary_reload (bool in_p, rtx x, enum reg_class class,
2260 enum machine_mode mode, secondary_reload_info *sri)
0d4a78eb
BS
2261{
2262 /* If we have HImode or QImode, we can only use DREGS as secondary registers;
2263 in most other cases we can also use PREGS. */
2264 enum reg_class default_class = GET_MODE_SIZE (mode) >= 4 ? DPREGS : DREGS;
2265 enum reg_class x_class = NO_REGS;
2266 enum rtx_code code = GET_CODE (x);
2267
2268 if (code == SUBREG)
2269 x = SUBREG_REG (x), code = GET_CODE (x);
2270 if (REG_P (x))
2271 {
2272 int regno = REGNO (x);
2273 if (regno >= FIRST_PSEUDO_REGISTER)
2274 regno = reg_renumber[regno];
2275
2276 if (regno == -1)
2277 code = MEM;
2278 else
2279 x_class = REGNO_REG_CLASS (regno);
2280 }
2281
2282 /* We can be asked to reload (plus (FP) (large_constant)) into a DREG.
2283 This happens as a side effect of register elimination, and we need
2284 a scratch register to do it. */
2285 if (fp_plus_const_operand (x, mode))
2286 {
2287 rtx op2 = XEXP (x, 1);
9fdd7520 2288 int large_constant_p = ! satisfies_constraint_Ks7 (op2);
0d4a78eb
BS
2289
2290 if (class == PREGS || class == PREGS_CLOBBERED)
2291 return NO_REGS;
2292 /* If destination is a DREG, we can do this without a scratch register
2293 if the constant is valid for an add instruction. */
e97f2058
BS
2294 if ((class == DREGS || class == DPREGS)
2295 && ! large_constant_p)
2296 return NO_REGS;
0d4a78eb
BS
2297 /* Reloading to anything other than a DREG? Use a PREG scratch
2298 register. */
e97f2058
BS
2299 sri->icode = CODE_FOR_reload_insi;
2300 return NO_REGS;
0d4a78eb
BS
2301 }
2302
2303 /* Data can usually be moved freely between registers of most classes.
2304 AREGS are an exception; they can only move to or from another register
2305 in AREGS or one in DREGS. They can also be assigned the constant 0. */
3efd5670
BS
2306 if (x_class == AREGS || x_class == EVEN_AREGS || x_class == ODD_AREGS)
2307 return (class == DREGS || class == AREGS || class == EVEN_AREGS
2308 || class == ODD_AREGS
2309 ? NO_REGS : DREGS);
0d4a78eb 2310
3efd5670 2311 if (class == AREGS || class == EVEN_AREGS || class == ODD_AREGS)
0d4a78eb 2312 {
6ed44ca1
BS
2313 if (code == MEM)
2314 {
2315 sri->icode = in_p ? CODE_FOR_reload_inpdi : CODE_FOR_reload_outpdi;
2316 return NO_REGS;
2317 }
2318
0d4a78eb 2319 if (x != const0_rtx && x_class != DREGS)
6ed44ca1
BS
2320 {
2321 return DREGS;
2322 }
0d4a78eb
BS
2323 else
2324 return NO_REGS;
2325 }
2326
2327 /* CCREGS can only be moved from/to DREGS. */
2328 if (class == CCREGS && x_class != DREGS)
2329 return DREGS;
2330 if (x_class == CCREGS && class != DREGS)
2331 return DREGS;
4729dc92 2332
0d4a78eb
BS
2333 /* All registers other than AREGS can load arbitrary constants. The only
2334 case that remains is MEM. */
2335 if (code == MEM)
2336 if (! reg_class_subset_p (class, default_class))
2337 return default_class;
6ed44ca1 2338
0d4a78eb
BS
2339 return NO_REGS;
2340}
0d4a78eb 2341\f
f02a5d0e
BS
2342/* Implement TARGET_HANDLE_OPTION. */
2343
2344static bool
2345bfin_handle_option (size_t code, const char *arg, int value)
2346{
2347 switch (code)
2348 {
2349 case OPT_mshared_library_id_:
2350 if (value > MAX_LIBRARY_ID)
2351 error ("-mshared-library-id=%s is not between 0 and %d",
2352 arg, MAX_LIBRARY_ID);
c8de0f3b 2353 bfin_lib_id_given = 1;
f02a5d0e
BS
2354 return true;
2355
9d3f9aa3 2356 case OPT_mcpu_:
ea2382be
JZ
2357 {
2358 const char *p, *q;
2359 int i;
2360
2361 i = 0;
2362 while ((p = bfin_cpus[i].name) != NULL)
2363 {
2364 if (strncmp (arg, p, strlen (p)) == 0)
2365 break;
2366 i++;
2367 }
2368
2369 if (p == NULL)
2370 {
2371 error ("-mcpu=%s is not valid", arg);
2372 return false;
2373 }
2374
2375 bfin_cpu_type = bfin_cpus[i].type;
2376
2377 q = arg + strlen (p);
2378
2379 if (*q == '\0')
2380 {
2381 bfin_si_revision = bfin_cpus[i].si_revision;
2382 bfin_workarounds |= bfin_cpus[i].workarounds;
2383 }
2384 else if (strcmp (q, "-none") == 0)
2385 bfin_si_revision = -1;
2386 else if (strcmp (q, "-any") == 0)
2387 {
2388 bfin_si_revision = 0xffff;
2389 while (bfin_cpus[i].type == bfin_cpu_type)
2390 {
2391 bfin_workarounds |= bfin_cpus[i].workarounds;
2392 i++;
2393 }
2394 }
2395 else
2396 {
2397 unsigned int si_major, si_minor;
2398 int rev_len, n;
2399
2400 rev_len = strlen (q);
2401
2402 if (sscanf (q, "-%u.%u%n", &si_major, &si_minor, &n) != 2
2403 || n != rev_len
2404 || si_major > 0xff || si_minor > 0xff)
2405 {
2406 invalid_silicon_revision:
2407 error ("-mcpu=%s has invalid silicon revision", arg);
2408 return false;
2409 }
2410
2411 bfin_si_revision = (si_major << 8) | si_minor;
2412
2413 while (bfin_cpus[i].type == bfin_cpu_type
2414 && bfin_cpus[i].si_revision != bfin_si_revision)
2415 i++;
2416
2417 if (bfin_cpus[i].type != bfin_cpu_type)
2418 goto invalid_silicon_revision;
2419
2420 bfin_workarounds |= bfin_cpus[i].workarounds;
2421 }
2422
2423 if (bfin_cpu_type == BFIN_CPU_BF561)
28f601ff 2424 warning (0, "bf561 support is incomplete yet.");
ea2382be
JZ
2425
2426 return true;
2427 }
9d3f9aa3 2428
f02a5d0e
BS
2429 default:
2430 return true;
2431 }
2432}
2433
b03149e1
JZ
2434static struct machine_function *
2435bfin_init_machine_status (void)
2436{
2437 struct machine_function *f;
2438
2439 f = ggc_alloc_cleared (sizeof (struct machine_function));
2440
2441 return f;
2442}
2443
0d4a78eb
BS
2444/* Implement the macro OVERRIDE_OPTIONS. */
2445
2446void
2447override_options (void)
2448{
16869606
BS
2449 /* If processor type is not specified, enable all workarounds. */
2450 if (bfin_cpu_type == BFIN_CPU_UNKNOWN)
2451 {
2452 int i;
2453
2454 for (i = 0; bfin_cpus[i].name != NULL; i++)
2455 bfin_workarounds |= bfin_cpus[i].workarounds;
2456
2457 bfin_si_revision = 0xffff;
2458 }
2459
ea2382be
JZ
2460 if (bfin_csync_anomaly == 1)
2461 bfin_workarounds |= WA_SPECULATIVE_SYNCS;
2462 else if (bfin_csync_anomaly == 0)
2463 bfin_workarounds &= ~WA_SPECULATIVE_SYNCS;
2464
2465 if (bfin_specld_anomaly == 1)
2466 bfin_workarounds |= WA_SPECULATIVE_LOADS;
2467 else if (bfin_specld_anomaly == 0)
2468 bfin_workarounds &= ~WA_SPECULATIVE_LOADS;
2469
0d4a78eb
BS
2470 if (TARGET_OMIT_LEAF_FRAME_POINTER)
2471 flag_omit_frame_pointer = 1;
2472
2473 /* Library identification */
f02a5d0e
BS
2474 if (bfin_lib_id_given && ! TARGET_ID_SHARED_LIBRARY)
2475 error ("-mshared-library-id= specified without -mid-shared-library");
0d4a78eb 2476
d6eb07dc
BS
2477 if (stack_limit_rtx && TARGET_STACK_CHECK_L1)
2478 error ("Can't use multiple stack checking methods together.");
2479
6614f9f5 2480 if (TARGET_ID_SHARED_LIBRARY && TARGET_FDPIC)
d6eb07dc 2481 error ("ID shared libraries and FD-PIC mode can't be used together.");
6614f9f5 2482
93147119
BS
2483 /* Don't allow the user to specify -mid-shared-library and -msep-data
2484 together, as it makes little sense from a user's point of view... */
2485 if (TARGET_SEP_DATA && TARGET_ID_SHARED_LIBRARY)
2486 error ("cannot specify both -msep-data and -mid-shared-library");
2487 /* ... internally, however, it's nearly the same. */
2488 if (TARGET_SEP_DATA)
2489 target_flags |= MASK_ID_SHARED_LIBRARY | MASK_LEAF_ID_SHARED_LIBRARY;
2490
fb7c3b05
BS
2491 if (TARGET_ID_SHARED_LIBRARY && flag_pic == 0)
2492 flag_pic = 1;
2493
6614f9f5
BS
2494 /* There is no single unaligned SI op for PIC code. Sometimes we
2495 need to use ".4byte" and sometimes we need to use ".picptr".
2496 See bfin_assemble_integer for details. */
2497 if (TARGET_FDPIC)
2498 targetm.asm_out.unaligned_op.si = 0;
2499
2500 /* Silently turn off flag_pic if not doing FDPIC or ID shared libraries,
2501 since we don't support it and it'll just break. */
2502 if (flag_pic && !TARGET_FDPIC && !TARGET_ID_SHARED_LIBRARY)
2503 flag_pic = 0;
2504
16869606
BS
2505 if (TARGET_MULTICORE && bfin_cpu_type != BFIN_CPU_BF561)
2506 error ("-mmulticore can only be used with BF561");
2507
2508 if (TARGET_COREA && !TARGET_MULTICORE)
2509 error ("-mcorea should be used with -mmulticore");
2510
2511 if (TARGET_COREB && !TARGET_MULTICORE)
2512 error ("-mcoreb should be used with -mmulticore");
2513
2514 if (TARGET_COREA && TARGET_COREB)
2515 error ("-mcorea and -mcoreb can't be used together");
2516
0d4a78eb 2517 flag_schedule_insns = 0;
b03149e1 2518
bbbc206e
BS
2519 /* Passes after sched2 can break the helpful TImode annotations that
2520 haifa-sched puts on every insn. Just do scheduling in reorg. */
2521 bfin_flag_schedule_insns2 = flag_schedule_insns_after_reload;
2522 flag_schedule_insns_after_reload = 0;
2523
b03149e1 2524 init_machine_status = bfin_init_machine_status;
0d4a78eb
BS
2525}
2526
a2391c6a
JZ
2527/* Return the destination address of BRANCH.
2528 We need to use this instead of get_attr_length, because the
2529 cbranch_with_nops pattern conservatively sets its length to 6, and
2530 we still prefer to use shorter sequences. */
0d4a78eb
BS
2531
2532static int
2533branch_dest (rtx branch)
2534{
2535 rtx dest;
2536 int dest_uid;
2537 rtx pat = PATTERN (branch);
2538 if (GET_CODE (pat) == PARALLEL)
2539 pat = XVECEXP (pat, 0, 0);
2540 dest = SET_SRC (pat);
2541 if (GET_CODE (dest) == IF_THEN_ELSE)
2542 dest = XEXP (dest, 1);
2543 dest = XEXP (dest, 0);
2544 dest_uid = INSN_UID (dest);
2545 return INSN_ADDRESSES (dest_uid);
2546}
2547
2548/* Return nonzero if INSN is annotated with a REG_BR_PROB note that indicates
2549 it's a branch that's predicted taken. */
2550
2551static int
2552cbranch_predicted_taken_p (rtx insn)
2553{
2554 rtx x = find_reg_note (insn, REG_BR_PROB, 0);
2555
2556 if (x)
2557 {
2558 int pred_val = INTVAL (XEXP (x, 0));
2559
2560 return pred_val >= REG_BR_PROB_BASE / 2;
2561 }
2562
2563 return 0;
2564}
2565
2566/* Templates for use by asm_conditional_branch. */
2567
2568static const char *ccbranch_templates[][3] = {
2569 { "if !cc jump %3;", "if cc jump 4 (bp); jump.s %3;", "if cc jump 6 (bp); jump.l %3;" },
2570 { "if cc jump %3;", "if !cc jump 4 (bp); jump.s %3;", "if !cc jump 6 (bp); jump.l %3;" },
2571 { "if !cc jump %3 (bp);", "if cc jump 4; jump.s %3;", "if cc jump 6; jump.l %3;" },
2572 { "if cc jump %3 (bp);", "if !cc jump 4; jump.s %3;", "if !cc jump 6; jump.l %3;" },
2573};
2574
2575/* Output INSN, which is a conditional branch instruction with operands
2576 OPERANDS.
2577
2578 We deal with the various forms of conditional branches that can be generated
2579 by bfin_reorg to prevent the hardware from doing speculative loads, by
2580 - emitting a sufficient number of nops, if N_NOPS is nonzero, or
2581 - always emitting the branch as predicted taken, if PREDICT_TAKEN is true.
2582 Either of these is only necessary if the branch is short, otherwise the
2583 template we use ends in an unconditional jump which flushes the pipeline
2584 anyway. */
2585
2586void
2587asm_conditional_branch (rtx insn, rtx *operands, int n_nops, int predict_taken)
2588{
2589 int offset = branch_dest (insn) - INSN_ADDRESSES (INSN_UID (insn));
2590 /* Note : offset for instructions like if cc jmp; jump.[sl] offset
2591 is to be taken from start of if cc rather than jump.
2592 Range for jump.s is (-4094, 4096) instead of (-4096, 4094)
2593 */
2594 int len = (offset >= -1024 && offset <= 1022 ? 0
2595 : offset >= -4094 && offset <= 4096 ? 1
2596 : 2);
2597 int bp = predict_taken && len == 0 ? 1 : cbranch_predicted_taken_p (insn);
2598 int idx = (bp << 1) | (GET_CODE (operands[0]) == EQ ? BRF : BRT);
2599 output_asm_insn (ccbranch_templates[idx][len], operands);
3b9dd769 2600 gcc_assert (n_nops == 0 || !bp);
0d4a78eb
BS
2601 if (len == 0)
2602 while (n_nops-- > 0)
2603 output_asm_insn ("nop;", NULL);
2604}
2605
2606/* Emit rtl for a comparison operation CMP in mode MODE. Operands have been
2607 stored in bfin_compare_op0 and bfin_compare_op1 already. */
2608
2609rtx
2610bfin_gen_compare (rtx cmp, enum machine_mode mode ATTRIBUTE_UNUSED)
2611{
2612 enum rtx_code code1, code2;
2613 rtx op0 = bfin_compare_op0, op1 = bfin_compare_op1;
2614 rtx tem = bfin_cc_rtx;
2615 enum rtx_code code = GET_CODE (cmp);
2616
2617 /* If we have a BImode input, then we already have a compare result, and
2618 do not need to emit another comparison. */
2619 if (GET_MODE (op0) == BImode)
2620 {
3b9dd769
NS
2621 gcc_assert ((code == NE || code == EQ) && op1 == const0_rtx);
2622 tem = op0, code2 = code;
0d4a78eb
BS
2623 }
2624 else
2625 {
2626 switch (code) {
2627 /* bfin has these conditions */
2628 case EQ:
2629 case LT:
2630 case LE:
2631 case LEU:
2632 case LTU:
2633 code1 = code;
2634 code2 = NE;
2635 break;
2636 default:
2637 code1 = reverse_condition (code);
2638 code2 = EQ;
2639 break;
2640 }
2641 emit_insn (gen_rtx_SET (BImode, tem,
2642 gen_rtx_fmt_ee (code1, BImode, op0, op1)));
2643 }
2644
2645 return gen_rtx_fmt_ee (code2, BImode, tem, CONST0_RTX (BImode));
2646}
2647\f
2648/* Return nonzero iff C has exactly one bit set if it is interpreted
942fd98f 2649 as a 32-bit constant. */
0d4a78eb
BS
2650
2651int
2652log2constp (unsigned HOST_WIDE_INT c)
2653{
2654 c &= 0xFFFFFFFF;
2655 return c != 0 && (c & (c-1)) == 0;
2656}
2657
2658/* Returns the number of consecutive least significant zeros in the binary
2659 representation of *V.
2660 We modify *V to contain the original value arithmetically shifted right by
2661 the number of zeroes. */
2662
2663static int
2664shiftr_zero (HOST_WIDE_INT *v)
2665{
2666 unsigned HOST_WIDE_INT tmp = *v;
2667 unsigned HOST_WIDE_INT sgn;
2668 int n = 0;
2669
2670 if (tmp == 0)
2671 return 0;
2672
2673 sgn = tmp & ((unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1));
2674 while ((tmp & 0x1) == 0 && n <= 32)
2675 {
2676 tmp = (tmp >> 1) | sgn;
2677 n++;
2678 }
2679 *v = tmp;
2680 return n;
2681}
2682
2683/* After reload, split the load of an immediate constant. OPERANDS are the
2684 operands of the movsi_insn pattern which we are splitting. We return
2685 nonzero if we emitted a sequence to load the constant, zero if we emitted
2686 nothing because we want to use the splitter's default sequence. */
2687
2688int
2689split_load_immediate (rtx operands[])
2690{
2691 HOST_WIDE_INT val = INTVAL (operands[1]);
2692 HOST_WIDE_INT tmp;
2693 HOST_WIDE_INT shifted = val;
2694 HOST_WIDE_INT shifted_compl = ~val;
2695 int num_zero = shiftr_zero (&shifted);
2696 int num_compl_zero = shiftr_zero (&shifted_compl);
2697 unsigned int regno = REGNO (operands[0]);
0d4a78eb
BS
2698
2699 /* This case takes care of single-bit set/clear constants, which we could
2700 also implement with BITSET/BITCLR. */
2701 if (num_zero
2702 && shifted >= -32768 && shifted < 65536
2703 && (D_REGNO_P (regno)
2704 || (regno >= REG_P0 && regno <= REG_P7 && num_zero <= 2)))
2705 {
2706 emit_insn (gen_movsi (operands[0], GEN_INT (shifted)));
2707 emit_insn (gen_ashlsi3 (operands[0], operands[0], GEN_INT (num_zero)));
2708 return 1;
2709 }
2710
2711 tmp = val & 0xFFFF;
2712 tmp |= -(tmp & 0x8000);
2713
2714 /* If high word has one bit set or clear, try to use a bit operation. */
2715 if (D_REGNO_P (regno))
2716 {
2717 if (log2constp (val & 0xFFFF0000))
2718 {
2719 emit_insn (gen_movsi (operands[0], GEN_INT (val & 0xFFFF)));
2720 emit_insn (gen_iorsi3 (operands[0], operands[0], GEN_INT (val & 0xFFFF0000)));
2721 return 1;
2722 }
2723 else if (log2constp (val | 0xFFFF) && (val & 0x8000) != 0)
2724 {
2725 emit_insn (gen_movsi (operands[0], GEN_INT (tmp)));
2726 emit_insn (gen_andsi3 (operands[0], operands[0], GEN_INT (val | 0xFFFF)));
2727 }
2728 }
2729
2730 if (D_REGNO_P (regno))
2731 {
9fdd7520 2732 if (tmp >= -64 && tmp <= 63)
0d4a78eb
BS
2733 {
2734 emit_insn (gen_movsi (operands[0], GEN_INT (tmp)));
2735 emit_insn (gen_movstricthi_high (operands[0], GEN_INT (val & -65536)));
2736 return 1;
2737 }
2738
2739 if ((val & 0xFFFF0000) == 0)
2740 {
2741 emit_insn (gen_movsi (operands[0], const0_rtx));
2742 emit_insn (gen_movsi_low (operands[0], operands[0], operands[1]));
2743 return 1;
2744 }
2745
2746 if ((val & 0xFFFF0000) == 0xFFFF0000)
2747 {
2748 emit_insn (gen_movsi (operands[0], constm1_rtx));
2749 emit_insn (gen_movsi_low (operands[0], operands[0], operands[1]));
2750 return 1;
2751 }
2752 }
2753
2754 /* Need DREGs for the remaining case. */
2755 if (regno > REG_R7)
2756 return 0;
2757
2758 if (optimize_size
9fdd7520 2759 && num_compl_zero && shifted_compl >= -64 && shifted_compl <= 63)
0d4a78eb
BS
2760 {
2761 /* If optimizing for size, generate a sequence that has more instructions
2762 but is shorter. */
2763 emit_insn (gen_movsi (operands[0], GEN_INT (shifted_compl)));
2764 emit_insn (gen_ashlsi3 (operands[0], operands[0],
2765 GEN_INT (num_compl_zero)));
2766 emit_insn (gen_one_cmplsi2 (operands[0], operands[0]));
2767 return 1;
2768 }
2769 return 0;
2770}
2771\f
2772/* Return true if the legitimate memory address for a memory operand of mode
2773 MODE. Return false if not. */
2774
2775static bool
2776bfin_valid_add (enum machine_mode mode, HOST_WIDE_INT value)
2777{
2778 unsigned HOST_WIDE_INT v = value > 0 ? value : -value;
2779 int sz = GET_MODE_SIZE (mode);
2780 int shift = sz == 1 ? 0 : sz == 2 ? 1 : 2;
2781 /* The usual offsettable_memref machinery doesn't work so well for this
2782 port, so we deal with the problem here. */
5308e943
BS
2783 if (value > 0 && sz == 8)
2784 v += 4;
2785 return (v & ~(0x7fff << shift)) == 0;
0d4a78eb
BS
2786}
2787
2788static bool
c4963a0a
BS
2789bfin_valid_reg_p (unsigned int regno, int strict, enum machine_mode mode,
2790 enum rtx_code outer_code)
0d4a78eb 2791{
c4963a0a
BS
2792 if (strict)
2793 return REGNO_OK_FOR_BASE_STRICT_P (regno, mode, outer_code, SCRATCH);
2794 else
2795 return REGNO_OK_FOR_BASE_NONSTRICT_P (regno, mode, outer_code, SCRATCH);
0d4a78eb
BS
2796}
2797
2798bool
2799bfin_legitimate_address_p (enum machine_mode mode, rtx x, int strict)
2800{
2801 switch (GET_CODE (x)) {
2802 case REG:
c4963a0a 2803 if (bfin_valid_reg_p (REGNO (x), strict, mode, MEM))
0d4a78eb
BS
2804 return true;
2805 break;
2806 case PLUS:
2807 if (REG_P (XEXP (x, 0))
c4963a0a 2808 && bfin_valid_reg_p (REGNO (XEXP (x, 0)), strict, mode, PLUS)
300adfc2 2809 && ((GET_CODE (XEXP (x, 1)) == UNSPEC && mode == SImode)
0d4a78eb
BS
2810 || (GET_CODE (XEXP (x, 1)) == CONST_INT
2811 && bfin_valid_add (mode, INTVAL (XEXP (x, 1))))))
2812 return true;
2813 break;
2814 case POST_INC:
2815 case POST_DEC:
2816 if (LEGITIMATE_MODE_FOR_AUTOINC_P (mode)
2817 && REG_P (XEXP (x, 0))
c4963a0a 2818 && bfin_valid_reg_p (REGNO (XEXP (x, 0)), strict, mode, POST_INC))
0d4a78eb
BS
2819 return true;
2820 case PRE_DEC:
2821 if (LEGITIMATE_MODE_FOR_AUTOINC_P (mode)
2822 && XEXP (x, 0) == stack_pointer_rtx
2823 && REG_P (XEXP (x, 0))
c4963a0a 2824 && bfin_valid_reg_p (REGNO (XEXP (x, 0)), strict, mode, PRE_DEC))
0d4a78eb
BS
2825 return true;
2826 break;
2827 default:
2828 break;
2829 }
2830 return false;
2831}
2832
d6f6753e
BS
2833/* Decide whether we can force certain constants to memory. If we
2834 decide we can't, the caller should be able to cope with it in
2835 another way. */
2836
2837static bool
2838bfin_cannot_force_const_mem (rtx x ATTRIBUTE_UNUSED)
2839{
2840 /* We have only one class of non-legitimate constants, and our movsi
2841 expander knows how to handle them. Dropping these constants into the
2842 data section would only shift the problem - we'd still get relocs
2843 outside the object, in the data section rather than the text section. */
2844 return true;
2845}
2846
2847/* Ensure that for any constant of the form symbol + offset, the offset
2848 remains within the object. Any other constants are ok.
2849 This ensures that flat binaries never have to deal with relocations
2850 crossing section boundaries. */
2851
2852bool
2853bfin_legitimate_constant_p (rtx x)
2854{
2855 rtx sym;
2856 HOST_WIDE_INT offset;
2857
2858 if (GET_CODE (x) != CONST)
2859 return true;
2860
2861 x = XEXP (x, 0);
2862 gcc_assert (GET_CODE (x) == PLUS);
2863
2864 sym = XEXP (x, 0);
2865 x = XEXP (x, 1);
2866 if (GET_CODE (sym) != SYMBOL_REF
2867 || GET_CODE (x) != CONST_INT)
2868 return true;
2869 offset = INTVAL (x);
2870
2871 if (SYMBOL_REF_DECL (sym) == 0)
2872 return true;
2873 if (offset < 0
2874 || offset >= int_size_in_bytes (TREE_TYPE (SYMBOL_REF_DECL (sym))))
2875 return false;
2876
2877 return true;
2878}
2879
0d4a78eb
BS
2880static bool
2881bfin_rtx_costs (rtx x, int code, int outer_code, int *total)
2882{
2883 int cost2 = COSTS_N_INSNS (1);
4b53c508 2884 rtx op0, op1;
0d4a78eb
BS
2885
2886 switch (code)
2887 {
2888 case CONST_INT:
2889 if (outer_code == SET || outer_code == PLUS)
9fdd7520 2890 *total = satisfies_constraint_Ks7 (x) ? 0 : cost2;
0d4a78eb
BS
2891 else if (outer_code == AND)
2892 *total = log2constp (~INTVAL (x)) ? 0 : cost2;
2893 else if (outer_code == LE || outer_code == LT || outer_code == EQ)
2894 *total = (INTVAL (x) >= -4 && INTVAL (x) <= 3) ? 0 : cost2;
2895 else if (outer_code == LEU || outer_code == LTU)
2896 *total = (INTVAL (x) >= 0 && INTVAL (x) <= 7) ? 0 : cost2;
2897 else if (outer_code == MULT)
2898 *total = (INTVAL (x) == 2 || INTVAL (x) == 4) ? 0 : cost2;
2899 else if (outer_code == ASHIFT && (INTVAL (x) == 1 || INTVAL (x) == 2))
2900 *total = 0;
2901 else if (outer_code == ASHIFT || outer_code == ASHIFTRT
2902 || outer_code == LSHIFTRT)
2903 *total = (INTVAL (x) >= 0 && INTVAL (x) <= 31) ? 0 : cost2;
2904 else if (outer_code == IOR || outer_code == XOR)
2905 *total = (INTVAL (x) & (INTVAL (x) - 1)) == 0 ? 0 : cost2;
2906 else
2907 *total = cost2;
2908 return true;
2909
2910 case CONST:
2911 case LABEL_REF:
2912 case SYMBOL_REF:
2913 case CONST_DOUBLE:
2914 *total = COSTS_N_INSNS (2);
2915 return true;
2916
2917 case PLUS:
4b53c508
BS
2918 op0 = XEXP (x, 0);
2919 op1 = XEXP (x, 1);
2920 if (GET_MODE (x) == SImode)
0d4a78eb 2921 {
4b53c508
BS
2922 if (GET_CODE (op0) == MULT
2923 && GET_CODE (XEXP (op0, 1)) == CONST_INT)
0d4a78eb 2924 {
4b53c508 2925 HOST_WIDE_INT val = INTVAL (XEXP (op0, 1));
0d4a78eb
BS
2926 if (val == 2 || val == 4)
2927 {
2928 *total = cost2;
4b53c508
BS
2929 *total += rtx_cost (XEXP (op0, 0), outer_code);
2930 *total += rtx_cost (op1, outer_code);
0d4a78eb
BS
2931 return true;
2932 }
2933 }
4b53c508
BS
2934 *total = cost2;
2935 if (GET_CODE (op0) != REG
2936 && (GET_CODE (op0) != SUBREG || GET_CODE (SUBREG_REG (op0)) != REG))
2937 *total += rtx_cost (op0, SET);
2938#if 0 /* We'd like to do this for accuracy, but it biases the loop optimizer
2939 towards creating too many induction variables. */
2940 if (!reg_or_7bit_operand (op1, SImode))
2941 *total += rtx_cost (op1, SET);
2942#endif
0d4a78eb 2943 }
4b53c508
BS
2944 else if (GET_MODE (x) == DImode)
2945 {
2946 *total = 6 * cost2;
2947 if (GET_CODE (op1) != CONST_INT
9fdd7520 2948 || !satisfies_constraint_Ks7 (op1))
4b53c508
BS
2949 *total += rtx_cost (op1, PLUS);
2950 if (GET_CODE (op0) != REG
2951 && (GET_CODE (op0) != SUBREG || GET_CODE (SUBREG_REG (op0)) != REG))
2952 *total += rtx_cost (op0, PLUS);
2953 }
2954 return true;
0d4a78eb
BS
2955
2956 case MINUS:
4b53c508
BS
2957 if (GET_MODE (x) == DImode)
2958 *total = 6 * cost2;
2959 else
2960 *total = cost2;
2961 return true;
2962
0d4a78eb
BS
2963 case ASHIFT:
2964 case ASHIFTRT:
2965 case LSHIFTRT:
2966 if (GET_MODE (x) == DImode)
2967 *total = 6 * cost2;
4b53c508
BS
2968 else
2969 *total = cost2;
2970
2971 op0 = XEXP (x, 0);
2972 op1 = XEXP (x, 1);
2973 if (GET_CODE (op0) != REG
2974 && (GET_CODE (op0) != SUBREG || GET_CODE (SUBREG_REG (op0)) != REG))
2975 *total += rtx_cost (op0, code);
2976
2977 return true;
0d4a78eb 2978
0d4a78eb 2979 case IOR:
4b53c508 2980 case AND:
0d4a78eb 2981 case XOR:
4b53c508
BS
2982 op0 = XEXP (x, 0);
2983 op1 = XEXP (x, 1);
2984
2985 /* Handle special cases of IOR: rotates, ALIGN insns, movstricthi_high. */
2986 if (code == IOR)
2987 {
2988 if ((GET_CODE (op0) == LSHIFTRT && GET_CODE (op1) == ASHIFT)
2989 || (GET_CODE (op0) == ASHIFT && GET_CODE (op1) == ZERO_EXTEND)
2990 || (GET_CODE (op0) == ASHIFT && GET_CODE (op1) == LSHIFTRT)
2991 || (GET_CODE (op0) == AND && GET_CODE (op1) == CONST_INT))
2992 {
2993 *total = cost2;
2994 return true;
2995 }
2996 }
2997
2998 if (GET_CODE (op0) != REG
2999 && (GET_CODE (op0) != SUBREG || GET_CODE (SUBREG_REG (op0)) != REG))
3000 *total += rtx_cost (op0, code);
3001
0d4a78eb 3002 if (GET_MODE (x) == DImode)
4b53c508
BS
3003 {
3004 *total = 2 * cost2;
3005 return true;
3006 }
3007 *total = cost2;
3008 if (GET_MODE (x) != SImode)
3009 return true;
3010
3011 if (code == AND)
3012 {
3013 if (! rhs_andsi3_operand (XEXP (x, 1), SImode))
3014 *total += rtx_cost (XEXP (x, 1), code);
3015 }
3016 else
3017 {
3018 if (! regorlog2_operand (XEXP (x, 1), SImode))
3019 *total += rtx_cost (XEXP (x, 1), code);
3020 }
3021
3022 return true;
3023
3024 case ZERO_EXTRACT:
3025 case SIGN_EXTRACT:
3026 if (outer_code == SET
3027 && XEXP (x, 1) == const1_rtx
3028 && GET_CODE (XEXP (x, 2)) == CONST_INT)
3029 {
3030 *total = 2 * cost2;
3031 return true;
3032 }
3033 /* fall through */
3034
3035 case SIGN_EXTEND:
3036 case ZERO_EXTEND:
3037 *total = cost2;
3038 return true;
0d4a78eb
BS
3039
3040 case MULT:
4b53c508
BS
3041 {
3042 op0 = XEXP (x, 0);
3043 op1 = XEXP (x, 1);
3044 if (GET_CODE (op0) == GET_CODE (op1)
3045 && (GET_CODE (op0) == ZERO_EXTEND
3046 || GET_CODE (op0) == SIGN_EXTEND))
3047 {
3048 *total = COSTS_N_INSNS (1);
3049 op0 = XEXP (op0, 0);
3050 op1 = XEXP (op1, 0);
3051 }
3052 else if (optimize_size)
3053 *total = COSTS_N_INSNS (1);
3054 else
3055 *total = COSTS_N_INSNS (3);
3056
3057 if (GET_CODE (op0) != REG
3058 && (GET_CODE (op0) != SUBREG || GET_CODE (SUBREG_REG (op0)) != REG))
3059 *total += rtx_cost (op0, MULT);
3060 if (GET_CODE (op1) != REG
3061 && (GET_CODE (op1) != SUBREG || GET_CODE (SUBREG_REG (op1)) != REG))
3062 *total += rtx_cost (op1, MULT);
3063 }
3064 return true;
0d4a78eb 3065
61066abf
BS
3066 case UDIV:
3067 case UMOD:
3068 *total = COSTS_N_INSNS (32);
3069 return true;
3070
42da70b7
BS
3071 case VEC_CONCAT:
3072 case VEC_SELECT:
3073 if (outer_code == SET)
3074 *total = cost2;
3075 return true;
3076
0d4a78eb
BS
3077 default:
3078 return false;
3079 }
3080}
0d4a78eb
BS
3081\f
3082/* Used for communication between {push,pop}_multiple_operation (which
3083 we use not only as a predicate) and the corresponding output functions. */
3084static int first_preg_to_save, first_dreg_to_save;
3085
3086int
3087push_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
3088{
3089 int lastdreg = 8, lastpreg = 6;
3090 int i, group;
3091
3092 first_preg_to_save = lastpreg;
3093 first_dreg_to_save = lastdreg;
3094 for (i = 1, group = 0; i < XVECLEN (op, 0) - 1; i++)
3095 {
3096 rtx t = XVECEXP (op, 0, i);
3097 rtx src, dest;
3098 int regno;
3099
3100 if (GET_CODE (t) != SET)
3101 return 0;
3102
3103 src = SET_SRC (t);
3104 dest = SET_DEST (t);
3105 if (GET_CODE (dest) != MEM || ! REG_P (src))
3106 return 0;
3107 dest = XEXP (dest, 0);
3108 if (GET_CODE (dest) != PLUS
3109 || ! REG_P (XEXP (dest, 0))
3110 || REGNO (XEXP (dest, 0)) != REG_SP
3111 || GET_CODE (XEXP (dest, 1)) != CONST_INT
3112 || INTVAL (XEXP (dest, 1)) != -i * 4)
3113 return 0;
3114
3115 regno = REGNO (src);
3116 if (group == 0)
3117 {
3118 if (D_REGNO_P (regno))
3119 {
3120 group = 1;
3121 first_dreg_to_save = lastdreg = regno - REG_R0;
3122 }
3123 else if (regno >= REG_P0 && regno <= REG_P7)
3124 {
3125 group = 2;
3126 first_preg_to_save = lastpreg = regno - REG_P0;
3127 }
3128 else
3129 return 0;
3130
3131 continue;
3132 }
3133
3134 if (group == 1)
3135 {
3136 if (regno >= REG_P0 && regno <= REG_P7)
3137 {
3138 group = 2;
3139 first_preg_to_save = lastpreg = regno - REG_P0;
3140 }
3141 else if (regno != REG_R0 + lastdreg + 1)
3142 return 0;
3143 else
3144 lastdreg++;
3145 }
3146 else if (group == 2)
3147 {
3148 if (regno != REG_P0 + lastpreg + 1)
3149 return 0;
3150 lastpreg++;
3151 }
3152 }
3153 return 1;
3154}
3155
3156int
3157pop_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
3158{
3159 int lastdreg = 8, lastpreg = 6;
3160 int i, group;
3161
3162 for (i = 1, group = 0; i < XVECLEN (op, 0); i++)
3163 {
3164 rtx t = XVECEXP (op, 0, i);
3165 rtx src, dest;
3166 int regno;
3167
3168 if (GET_CODE (t) != SET)
3169 return 0;
3170
3171 src = SET_SRC (t);
3172 dest = SET_DEST (t);
3173 if (GET_CODE (src) != MEM || ! REG_P (dest))
3174 return 0;
3175 src = XEXP (src, 0);
3176
3177 if (i == 1)
3178 {
3179 if (! REG_P (src) || REGNO (src) != REG_SP)
3180 return 0;
3181 }
3182 else if (GET_CODE (src) != PLUS
3183 || ! REG_P (XEXP (src, 0))
3184 || REGNO (XEXP (src, 0)) != REG_SP
3185 || GET_CODE (XEXP (src, 1)) != CONST_INT
3186 || INTVAL (XEXP (src, 1)) != (i - 1) * 4)
3187 return 0;
3188
3189 regno = REGNO (dest);
3190 if (group == 0)
3191 {
3192 if (regno == REG_R7)
3193 {
3194 group = 1;
3195 lastdreg = 7;
3196 }
3197 else if (regno != REG_P0 + lastpreg - 1)
3198 return 0;
3199 else
3200 lastpreg--;
3201 }
3202 else if (group == 1)
3203 {
3204 if (regno != REG_R0 + lastdreg - 1)
3205 return 0;
3206 else
3207 lastdreg--;
3208 }
3209 }
3210 first_dreg_to_save = lastdreg;
3211 first_preg_to_save = lastpreg;
3212 return 1;
3213}
3214
3215/* Emit assembly code for one multi-register push described by INSN, with
3216 operands in OPERANDS. */
3217
3218void
3219output_push_multiple (rtx insn, rtx *operands)
3220{
3221 char buf[80];
3b9dd769
NS
3222 int ok;
3223
0d4a78eb 3224 /* Validate the insn again, and compute first_[dp]reg_to_save. */
3b9dd769
NS
3225 ok = push_multiple_operation (PATTERN (insn), VOIDmode);
3226 gcc_assert (ok);
3227
0d4a78eb
BS
3228 if (first_dreg_to_save == 8)
3229 sprintf (buf, "[--sp] = ( p5:%d );\n", first_preg_to_save);
3230 else if (first_preg_to_save == 6)
3231 sprintf (buf, "[--sp] = ( r7:%d );\n", first_dreg_to_save);
3232 else
3b9dd769
NS
3233 sprintf (buf, "[--sp] = ( r7:%d, p5:%d );\n",
3234 first_dreg_to_save, first_preg_to_save);
0d4a78eb
BS
3235
3236 output_asm_insn (buf, operands);
3237}
3238
3239/* Emit assembly code for one multi-register pop described by INSN, with
3240 operands in OPERANDS. */
3241
3242void
3243output_pop_multiple (rtx insn, rtx *operands)
3244{
3245 char buf[80];
3b9dd769
NS
3246 int ok;
3247
0d4a78eb 3248 /* Validate the insn again, and compute first_[dp]reg_to_save. */
3b9dd769
NS
3249 ok = pop_multiple_operation (PATTERN (insn), VOIDmode);
3250 gcc_assert (ok);
0d4a78eb
BS
3251
3252 if (first_dreg_to_save == 8)
3253 sprintf (buf, "( p5:%d ) = [sp++];\n", first_preg_to_save);
3254 else if (first_preg_to_save == 6)
3255 sprintf (buf, "( r7:%d ) = [sp++];\n", first_dreg_to_save);
3256 else
3b9dd769
NS
3257 sprintf (buf, "( r7:%d, p5:%d ) = [sp++];\n",
3258 first_dreg_to_save, first_preg_to_save);
0d4a78eb
BS
3259
3260 output_asm_insn (buf, operands);
3261}
3262
3263/* Adjust DST and SRC by OFFSET bytes, and generate one move in mode MODE. */
3264
3265static void
144f8315 3266single_move_for_movmem (rtx dst, rtx src, enum machine_mode mode, HOST_WIDE_INT offset)
0d4a78eb
BS
3267{
3268 rtx scratch = gen_reg_rtx (mode);
3269 rtx srcmem, dstmem;
3270
3271 srcmem = adjust_address_nv (src, mode, offset);
3272 dstmem = adjust_address_nv (dst, mode, offset);
3273 emit_move_insn (scratch, srcmem);
3274 emit_move_insn (dstmem, scratch);
3275}
3276
3277/* Expand a string move operation of COUNT_EXP bytes from SRC to DST, with
3278 alignment ALIGN_EXP. Return true if successful, false if we should fall
3279 back on a different method. */
3280
3281bool
144f8315 3282bfin_expand_movmem (rtx dst, rtx src, rtx count_exp, rtx align_exp)
0d4a78eb
BS
3283{
3284 rtx srcreg, destreg, countreg;
3285 HOST_WIDE_INT align = 0;
3286 unsigned HOST_WIDE_INT count = 0;
3287
3288 if (GET_CODE (align_exp) == CONST_INT)
3289 align = INTVAL (align_exp);
3290 if (GET_CODE (count_exp) == CONST_INT)
3291 {
3292 count = INTVAL (count_exp);
3293#if 0
3294 if (!TARGET_INLINE_ALL_STRINGOPS && count > 64)
3295 return false;
3296#endif
3297 }
3298
3299 /* If optimizing for size, only do single copies inline. */
3300 if (optimize_size)
3301 {
3302 if (count == 2 && align < 2)
3303 return false;
3304 if (count == 4 && align < 4)
3305 return false;
3306 if (count != 1 && count != 2 && count != 4)
3307 return false;
3308 }
3309 if (align < 2 && count != 1)
3310 return false;
3311
3312 destreg = copy_to_mode_reg (Pmode, XEXP (dst, 0));
3313 if (destreg != XEXP (dst, 0))
3314 dst = replace_equiv_address_nv (dst, destreg);
3315 srcreg = copy_to_mode_reg (Pmode, XEXP (src, 0));
3316 if (srcreg != XEXP (src, 0))
3317 src = replace_equiv_address_nv (src, srcreg);
3318
3319 if (count != 0 && align >= 2)
3320 {
3321 unsigned HOST_WIDE_INT offset = 0;
3322
3323 if (align >= 4)
3324 {
3325 if ((count & ~3) == 4)
3326 {
144f8315 3327 single_move_for_movmem (dst, src, SImode, offset);
0d4a78eb
BS
3328 offset = 4;
3329 }
3330 else if (count & ~3)
3331 {
3332 HOST_WIDE_INT new_count = ((count >> 2) & 0x3fffffff) - 1;
3333 countreg = copy_to_mode_reg (Pmode, GEN_INT (new_count));
3334
3335 emit_insn (gen_rep_movsi (destreg, srcreg, countreg, destreg, srcreg));
3336 }
51a641fd
JZ
3337 if (count & 2)
3338 {
144f8315 3339 single_move_for_movmem (dst, src, HImode, offset);
51a641fd
JZ
3340 offset += 2;
3341 }
0d4a78eb
BS
3342 }
3343 else
3344 {
3345 if ((count & ~1) == 2)
3346 {
144f8315 3347 single_move_for_movmem (dst, src, HImode, offset);
0d4a78eb
BS
3348 offset = 2;
3349 }
3350 else if (count & ~1)
3351 {
3352 HOST_WIDE_INT new_count = ((count >> 1) & 0x7fffffff) - 1;
3353 countreg = copy_to_mode_reg (Pmode, GEN_INT (new_count));
3354
3355 emit_insn (gen_rep_movhi (destreg, srcreg, countreg, destreg, srcreg));
3356 }
3357 }
0d4a78eb
BS
3358 if (count & 1)
3359 {
144f8315 3360 single_move_for_movmem (dst, src, QImode, offset);
0d4a78eb
BS
3361 }
3362 return true;
3363 }
3364 return false;
3365}
0d4a78eb 3366\f
520c62ad
BS
3367/* Compute the alignment for a local variable.
3368 TYPE is the data type, and ALIGN is the alignment that
3369 the object would ordinarily have. The value of this macro is used
3370 instead of that alignment to align the object. */
3371
3372int
3373bfin_local_alignment (tree type, int align)
3374{
3375 /* Increasing alignment for (relatively) big types allows the builtin
3376 memcpy can use 32 bit loads/stores. */
3377 if (TYPE_SIZE (type)
3378 && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
3379 && (TREE_INT_CST_LOW (TYPE_SIZE (type)) > 8
3380 || TREE_INT_CST_HIGH (TYPE_SIZE (type))) && align < 32)
3381 return 32;
3382 return align;
3383}
3384\f
36662eb1
BS
3385/* Implement TARGET_SCHED_ISSUE_RATE. */
3386
3387static int
3388bfin_issue_rate (void)
3389{
3390 return 3;
3391}
3392
0d4a78eb
BS
3393static int
3394bfin_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
3395{
3396 enum attr_type insn_type, dep_insn_type;
3397 int dep_insn_code_number;
3398
3399 /* Anti and output dependencies have zero cost. */
3400 if (REG_NOTE_KIND (link) != 0)
3401 return 0;
3402
3403 dep_insn_code_number = recog_memoized (dep_insn);
3404
3405 /* If we can't recognize the insns, we can't really do anything. */
3406 if (dep_insn_code_number < 0 || recog_memoized (insn) < 0)
3407 return cost;
3408
3409 insn_type = get_attr_type (insn);
3410 dep_insn_type = get_attr_type (dep_insn);
3411
3412 if (dep_insn_type == TYPE_MOVE || dep_insn_type == TYPE_MCLD)
3413 {
3414 rtx pat = PATTERN (dep_insn);
86636093
RIL
3415 if (GET_CODE (pat) == PARALLEL)
3416 pat = XVECEXP (pat, 0, 0);
0d4a78eb
BS
3417 rtx dest = SET_DEST (pat);
3418 rtx src = SET_SRC (pat);
96f46444
BS
3419 if (! ADDRESS_REGNO_P (REGNO (dest))
3420 || ! (MEM_P (src) || D_REGNO_P (REGNO (src))))
0d4a78eb
BS
3421 return cost;
3422 return cost + (dep_insn_type == TYPE_MOVE ? 4 : 3);
3423 }
3424
3425 return cost;
3426}
b03149e1
JZ
3427
3428\f
3429/* Increment the counter for the number of loop instructions in the
3430 current function. */
3431
3432void
3433bfin_hardware_loop (void)
3434{
3435 cfun->machine->has_hardware_loops++;
3436}
3437
aab26080 3438/* Maximum loop nesting depth. */
b03149e1
JZ
3439#define MAX_LOOP_DEPTH 2
3440
aab26080 3441/* Maximum size of a loop. */
40327e03 3442#define MAX_LOOP_LENGTH 2042
b03149e1 3443
ce27ef3d
BS
3444/* Maximum distance of the LSETUP instruction from the loop start. */
3445#define MAX_LSETUP_DISTANCE 30
3446
b03149e1
JZ
3447/* We need to keep a vector of loops */
3448typedef struct loop_info *loop_info;
3449DEF_VEC_P (loop_info);
3450DEF_VEC_ALLOC_P (loop_info,heap);
3451
3452/* Information about a loop we have found (or are in the process of
3453 finding). */
3454struct loop_info GTY (())
3455{
3456 /* loop number, for dumps */
3457 int loop_no;
3458
ce27ef3d
BS
3459 /* All edges that jump into and out of the loop. */
3460 VEC(edge,gc) *incoming;
3461
3462 /* We can handle two cases: all incoming edges have the same destination
3463 block, or all incoming edges have the same source block. These two
3464 members are set to the common source or destination we found, or NULL
3465 if different blocks were found. If both are NULL the loop can't be
3466 optimized. */
3467 basic_block incoming_src;
3468 basic_block incoming_dest;
b03149e1
JZ
3469
3470 /* First block in the loop. This is the one branched to by the loop_end
3471 insn. */
3472 basic_block head;
3473
3474 /* Last block in the loop (the one with the loop_end insn). */
3475 basic_block tail;
3476
3477 /* The successor block of the loop. This is the one the loop_end insn
3478 falls into. */
3479 basic_block successor;
3480
3481 /* The last instruction in the tail. */
3482 rtx last_insn;
3483
3484 /* The loop_end insn. */
3485 rtx loop_end;
3486
3487 /* The iteration register. */
3488 rtx iter_reg;
3489
3490 /* The new initialization insn. */
3491 rtx init;
3492
3493 /* The new initialization instruction. */
3494 rtx loop_init;
3495
3496 /* The new label placed at the beginning of the loop. */
3497 rtx start_label;
3498
3499 /* The new label placed at the end of the loop. */
3500 rtx end_label;
3501
3502 /* The length of the loop. */
3503 int length;
3504
e54273eb 3505 /* The nesting depth of the loop. */
b03149e1
JZ
3506 int depth;
3507
e54273eb
BS
3508 /* Nonzero if we can't optimize this loop. */
3509 int bad;
3510
b03149e1
JZ
3511 /* True if we have visited this loop. */
3512 int visited;
3513
3514 /* True if this loop body clobbers any of LC0, LT0, or LB0. */
3515 int clobber_loop0;
3516
3517 /* True if this loop body clobbers any of LC1, LT1, or LB1. */
3518 int clobber_loop1;
3519
3520 /* Next loop in the graph. */
3521 struct loop_info *next;
3522
3523 /* Immediate outer loop of this loop. */
3524 struct loop_info *outer;
3525
e54273eb
BS
3526 /* Vector of blocks only within the loop, including those within
3527 inner loops. */
b03149e1
JZ
3528 VEC (basic_block,heap) *blocks;
3529
e54273eb
BS
3530 /* Same information in a bitmap. */
3531 bitmap block_bitmap;
3532
b03149e1
JZ
3533 /* Vector of inner loops within this loop */
3534 VEC (loop_info,heap) *loops;
3535};
3536
b03149e1
JZ
3537static void
3538bfin_dump_loops (loop_info loops)
3539{
3540 loop_info loop;
3541
3542 for (loop = loops; loop; loop = loop->next)
3543 {
3544 loop_info i;
3545 basic_block b;
3546 unsigned ix;
3547
3548 fprintf (dump_file, ";; loop %d: ", loop->loop_no);
e54273eb
BS
3549 if (loop->bad)
3550 fprintf (dump_file, "(bad) ");
b03149e1
JZ
3551 fprintf (dump_file, "{head:%d, depth:%d}", loop->head->index, loop->depth);
3552
3553 fprintf (dump_file, " blocks: [ ");
3554 for (ix = 0; VEC_iterate (basic_block, loop->blocks, ix, b); ix++)
3555 fprintf (dump_file, "%d ", b->index);
3556 fprintf (dump_file, "] ");
3557
3558 fprintf (dump_file, " inner loops: [ ");
3559 for (ix = 0; VEC_iterate (loop_info, loop->loops, ix, i); ix++)
3560 fprintf (dump_file, "%d ", i->loop_no);
3561 fprintf (dump_file, "]\n");
3562 }
3563 fprintf (dump_file, "\n");
3564}
3565
3566/* Scan the blocks of LOOP (and its inferiors) looking for basic block
3567 BB. Return true, if we find it. */
3568
3569static bool
3570bfin_bb_in_loop (loop_info loop, basic_block bb)
3571{
e54273eb 3572 return bitmap_bit_p (loop->block_bitmap, bb->index);
b03149e1
JZ
3573}
3574
3575/* Scan the blocks of LOOP (and its inferiors) looking for uses of
3576 REG. Return true, if we find any. Don't count the loop's loop_end
3577 insn if it matches LOOP_END. */
3578
3579static bool
3580bfin_scan_loop (loop_info loop, rtx reg, rtx loop_end)
3581{
3582 unsigned ix;
b03149e1
JZ
3583 basic_block bb;
3584
3585 for (ix = 0; VEC_iterate (basic_block, loop->blocks, ix, bb); ix++)
3586 {
3587 rtx insn;
3588
3589 for (insn = BB_HEAD (bb);
3590 insn != NEXT_INSN (BB_END (bb));
3591 insn = NEXT_INSN (insn))
3592 {
3593 if (!INSN_P (insn))
3594 continue;
3595 if (insn == loop_end)
3596 continue;
3597 if (reg_mentioned_p (reg, PATTERN (insn)))
3598 return true;
3599 }
3600 }
b03149e1
JZ
3601 return false;
3602}
3603
ce27ef3d
BS
3604/* Estimate the length of INSN conservatively. */
3605
3606static int
3607length_for_loop (rtx insn)
3608{
3609 int length = 0;
3610 if (JUMP_P (insn) && any_condjump_p (insn) && !optimize_size)
3611 {
ea2382be 3612 if (ENABLE_WA_SPECULATIVE_SYNCS)
ce27ef3d 3613 length = 8;
ea2382be 3614 else if (ENABLE_WA_SPECULATIVE_LOADS)
ce27ef3d
BS
3615 length = 6;
3616 }
3617 else if (LABEL_P (insn))
3618 {
ea2382be 3619 if (ENABLE_WA_SPECULATIVE_SYNCS)
ce27ef3d
BS
3620 length = 4;
3621 }
3622
3623 if (INSN_P (insn))
3624 length += get_attr_length (insn);
3625
3626 return length;
3627}
3628
b03149e1
JZ
3629/* Optimize LOOP. */
3630
3631static void
3632bfin_optimize_loop (loop_info loop)
3633{
3634 basic_block bb;
e54273eb 3635 loop_info inner;
b03149e1
JZ
3636 rtx insn, init_insn, last_insn, nop_insn;
3637 rtx loop_init, start_label, end_label;
3638 rtx reg_lc0, reg_lc1, reg_lt0, reg_lt1, reg_lb0, reg_lb1;
3639 rtx iter_reg;
3640 rtx lc_reg, lt_reg, lb_reg;
ce27ef3d 3641 rtx seq, seq_end;
b03149e1
JZ
3642 int length;
3643 unsigned ix;
3644 int inner_depth = 0;
b03149e1
JZ
3645
3646 if (loop->visited)
3647 return;
3648
3649 loop->visited = 1;
3650
e54273eb 3651 if (loop->bad)
b03149e1
JZ
3652 {
3653 if (dump_file)
3654 fprintf (dump_file, ";; loop %d bad when found\n", loop->loop_no);
3655 goto bad_loop;
3656 }
3657
e54273eb
BS
3658 /* Every loop contains in its list of inner loops every loop nested inside
3659 it, even if there are intermediate loops. This works because we're doing
3660 a depth-first search here and never visit a loop more than once. */
3661 for (ix = 0; VEC_iterate (loop_info, loop->loops, ix, inner); ix++)
b03149e1 3662 {
e54273eb 3663 bfin_optimize_loop (inner);
b03149e1 3664
e54273eb
BS
3665 if (!inner->bad && inner_depth < inner->depth)
3666 {
3667 inner_depth = inner->depth;
b03149e1 3668
e54273eb
BS
3669 loop->clobber_loop0 |= inner->clobber_loop0;
3670 loop->clobber_loop1 |= inner->clobber_loop1;
3671 }
b03149e1
JZ
3672 }
3673
e54273eb
BS
3674 loop->depth = inner_depth + 1;
3675 if (loop->depth > MAX_LOOP_DEPTH)
b03149e1
JZ
3676 {
3677 if (dump_file)
e54273eb 3678 fprintf (dump_file, ";; loop %d too deep\n", loop->loop_no);
b03149e1
JZ
3679 goto bad_loop;
3680 }
3681
3682 /* Get the loop iteration register. */
3683 iter_reg = loop->iter_reg;
3684
3685 if (!DPREG_P (iter_reg))
3686 {
3687 if (dump_file)
3688 fprintf (dump_file, ";; loop %d iteration count NOT in PREG or DREG\n",
3689 loop->loop_no);
3690 goto bad_loop;
3691 }
3692
ce27ef3d
BS
3693 if (loop->incoming_src)
3694 {
3695 /* Make sure the predecessor is before the loop start label, as required by
3696 the LSETUP instruction. */
3697 length = 0;
3698 for (insn = BB_END (loop->incoming_src);
3699 insn && insn != loop->start_label;
3700 insn = NEXT_INSN (insn))
3701 length += length_for_loop (insn);
3702
3703 if (!insn)
3704 {
3705 if (dump_file)
3706 fprintf (dump_file, ";; loop %d lsetup not before loop_start\n",
3707 loop->loop_no);
3708 goto bad_loop;
3709 }
3710
3711 if (length > MAX_LSETUP_DISTANCE)
3712 {
3713 if (dump_file)
3714 fprintf (dump_file, ";; loop %d lsetup too far away\n", loop->loop_no);
3715 goto bad_loop;
3716 }
3717 }
3718
b03149e1
JZ
3719 /* Check if start_label appears before loop_end and calculate the
3720 offset between them. We calculate the length of instructions
3721 conservatively. */
3722 length = 0;
3723 for (insn = loop->start_label;
3724 insn && insn != loop->loop_end;
3725 insn = NEXT_INSN (insn))
ce27ef3d 3726 length += length_for_loop (insn);
b03149e1
JZ
3727
3728 if (!insn)
3729 {
3730 if (dump_file)
3731 fprintf (dump_file, ";; loop %d start_label not before loop_end\n",
3732 loop->loop_no);
3733 goto bad_loop;
3734 }
3735
3736 loop->length = length;
3737 if (loop->length > MAX_LOOP_LENGTH)
3738 {
3739 if (dump_file)
3740 fprintf (dump_file, ";; loop %d too long\n", loop->loop_no);
3741 goto bad_loop;
3742 }
3743
3744 /* Scan all the blocks to make sure they don't use iter_reg. */
3745 if (bfin_scan_loop (loop, iter_reg, loop->loop_end))
3746 {
3747 if (dump_file)
3748 fprintf (dump_file, ";; loop %d uses iterator\n", loop->loop_no);
3749 goto bad_loop;
3750 }
3751
3752 /* Scan all the insns to see if the loop body clobber
3753 any hardware loop registers. */
3754
3755 reg_lc0 = gen_rtx_REG (SImode, REG_LC0);
3756 reg_lc1 = gen_rtx_REG (SImode, REG_LC1);
3757 reg_lt0 = gen_rtx_REG (SImode, REG_LT0);
3758 reg_lt1 = gen_rtx_REG (SImode, REG_LT1);
3759 reg_lb0 = gen_rtx_REG (SImode, REG_LB0);
3760 reg_lb1 = gen_rtx_REG (SImode, REG_LB1);
3761
3762 for (ix = 0; VEC_iterate (basic_block, loop->blocks, ix, bb); ix++)
3763 {
3764 rtx insn;
3765
3766 for (insn = BB_HEAD (bb);
3767 insn != NEXT_INSN (BB_END (bb));
3768 insn = NEXT_INSN (insn))
3769 {
3770 if (!INSN_P (insn))
3771 continue;
3772
3773 if (reg_set_p (reg_lc0, insn)
3774 || reg_set_p (reg_lt0, insn)
3775 || reg_set_p (reg_lb0, insn))
3776 loop->clobber_loop0 = 1;
3777
3778 if (reg_set_p (reg_lc1, insn)
3779 || reg_set_p (reg_lt1, insn)
3780 || reg_set_p (reg_lb1, insn))
3781 loop->clobber_loop1 |= 1;
3782 }
3783 }
3784
3785 if ((loop->clobber_loop0 && loop->clobber_loop1)
3786 || (loop->depth == MAX_LOOP_DEPTH && loop->clobber_loop0))
3787 {
3788 loop->depth = MAX_LOOP_DEPTH + 1;
3789 if (dump_file)
3790 fprintf (dump_file, ";; loop %d no loop reg available\n",
3791 loop->loop_no);
3792 goto bad_loop;
3793 }
3794
3795 /* There should be an instruction before the loop_end instruction
3796 in the same basic block. And the instruction must not be
3797 - JUMP
3798 - CONDITIONAL BRANCH
3799 - CALL
3800 - CSYNC
3801 - SSYNC
3802 - Returns (RTS, RTN, etc.) */
3803
3804 bb = loop->tail;
3805 last_insn = PREV_INSN (loop->loop_end);
3806
3807 while (1)
3808 {
3809 for (; last_insn != PREV_INSN (BB_HEAD (bb));
3810 last_insn = PREV_INSN (last_insn))
3811 if (INSN_P (last_insn))
3812 break;
3813
3814 if (last_insn != PREV_INSN (BB_HEAD (bb)))
3815 break;
3816
3817 if (single_pred_p (bb)
3818 && single_pred (bb) != ENTRY_BLOCK_PTR)
3819 {
3820 bb = single_pred (bb);
3821 last_insn = BB_END (bb);
3822 continue;
3823 }
3824 else
3825 {
3826 last_insn = NULL_RTX;
3827 break;
3828 }
3829 }
3830
3831 if (!last_insn)
3832 {
3833 if (dump_file)
3834 fprintf (dump_file, ";; loop %d has no last instruction\n",
3835 loop->loop_no);
3836 goto bad_loop;
3837 }
3838
3839 if (JUMP_P (last_insn))
3840 {
3841 loop_info inner = bb->aux;
3842 if (inner
3843 && inner->outer == loop
3844 && inner->loop_end == last_insn
3845 && inner->depth == 1)
3846 /* This jump_insn is the exact loop_end of an inner loop
3847 and to be optimized away. So use the inner's last_insn. */
3848 last_insn = inner->last_insn;
3849 else
3850 {
3851 if (dump_file)
3852 fprintf (dump_file, ";; loop %d has bad last instruction\n",
3853 loop->loop_no);
3854 goto bad_loop;
3855 }
3856 }
3857 else if (CALL_P (last_insn)
bbbc206e
BS
3858 || (GET_CODE (PATTERN (last_insn)) != SEQUENCE
3859 && get_attr_type (last_insn) == TYPE_SYNC)
b03149e1
JZ
3860 || recog_memoized (last_insn) == CODE_FOR_return_internal)
3861 {
3862 if (dump_file)
3863 fprintf (dump_file, ";; loop %d has bad last instruction\n",
3864 loop->loop_no);
3865 goto bad_loop;
3866 }
3867
3868 if (GET_CODE (PATTERN (last_insn)) == ASM_INPUT
3869 || asm_noperands (PATTERN (last_insn)) >= 0
bbbc206e
BS
3870 || (GET_CODE (PATTERN (last_insn)) != SEQUENCE
3871 && get_attr_seq_insns (last_insn) == SEQ_INSNS_MULTI))
b03149e1
JZ
3872 {
3873 nop_insn = emit_insn_after (gen_nop (), last_insn);
3874 last_insn = nop_insn;
3875 }
3876
3877 loop->last_insn = last_insn;
3878
3879 /* The loop is good for replacement. */
3880 start_label = loop->start_label;
3881 end_label = gen_label_rtx ();
3882 iter_reg = loop->iter_reg;
3883
3884 if (loop->depth == 1 && !loop->clobber_loop1)
3885 {
3886 lc_reg = reg_lc1;
3887 lt_reg = reg_lt1;
3888 lb_reg = reg_lb1;
3889 loop->clobber_loop1 = 1;
3890 }
3891 else
3892 {
3893 lc_reg = reg_lc0;
3894 lt_reg = reg_lt0;
3895 lb_reg = reg_lb0;
3896 loop->clobber_loop0 = 1;
3897 }
3898
3899 /* If iter_reg is a DREG, we need generate an instruction to load
3900 the loop count into LC register. */
3901 if (D_REGNO_P (REGNO (iter_reg)))
3902 {
3903 init_insn = gen_movsi (lc_reg, iter_reg);
3904 loop_init = gen_lsetup_without_autoinit (lt_reg, start_label,
3905 lb_reg, end_label,
3906 lc_reg);
3907 }
3908 else if (P_REGNO_P (REGNO (iter_reg)))
3909 {
3910 init_insn = NULL_RTX;
3911 loop_init = gen_lsetup_with_autoinit (lt_reg, start_label,
3912 lb_reg, end_label,
3913 lc_reg, iter_reg);
3914 }
3915 else
3916 gcc_unreachable ();
3917
3918 loop->init = init_insn;
3919 loop->end_label = end_label;
3920 loop->loop_init = loop_init;
3921
3922 if (dump_file)
3923 {
3924 fprintf (dump_file, ";; replacing loop %d initializer with\n",
3925 loop->loop_no);
3926 print_rtl_single (dump_file, loop->loop_init);
3927 fprintf (dump_file, ";; replacing loop %d terminator with\n",
3928 loop->loop_no);
3929 print_rtl_single (dump_file, loop->loop_end);
3930 }
3931
3932 start_sequence ();
3933
3934 if (loop->init != NULL_RTX)
3935 emit_insn (loop->init);
ce27ef3d 3936 seq_end = emit_insn (loop->loop_init);
b03149e1
JZ
3937
3938 seq = get_insns ();
3939 end_sequence ();
3940
ce27ef3d
BS
3941 if (loop->incoming_src)
3942 {
3943 rtx prev = BB_END (loop->incoming_src);
3944 if (VEC_length (edge, loop->incoming) > 1
3945 || !(VEC_last (edge, loop->incoming)->flags & EDGE_FALLTHRU))
3946 {
3947 gcc_assert (JUMP_P (prev));
3948 prev = PREV_INSN (prev);
3949 }
3950 emit_insn_after (seq, prev);
3951 }
3952 else
3953 {
3954 basic_block new_bb;
3955 edge e;
3956 edge_iterator ei;
3957
3958 if (loop->head != loop->incoming_dest)
3959 {
3960 FOR_EACH_EDGE (e, ei, loop->head->preds)
3961 {
3962 if (e->flags & EDGE_FALLTHRU)
3963 {
3964 rtx newjump = gen_jump (loop->start_label);
3965 emit_insn_before (newjump, BB_HEAD (loop->head));
3966 new_bb = create_basic_block (newjump, newjump, loop->head->prev_bb);
3967 gcc_assert (new_bb = loop->head->prev_bb);
3968 break;
3969 }
3970 }
3971 }
3972
3973 emit_insn_before (seq, BB_HEAD (loop->head));
3974 seq = emit_label_before (gen_label_rtx (), seq);
b03149e1 3975
ce27ef3d
BS
3976 new_bb = create_basic_block (seq, seq_end, loop->head->prev_bb);
3977 FOR_EACH_EDGE (e, ei, loop->incoming)
3978 {
3979 if (!(e->flags & EDGE_FALLTHRU)
3980 || e->dest != loop->head)
3981 redirect_edge_and_branch_force (e, new_bb);
3982 else
3983 redirect_edge_succ (e, new_bb);
3984 }
3985 }
3986
3987 delete_insn (loop->loop_end);
b03149e1
JZ
3988 /* Insert the loop end label before the last instruction of the loop. */
3989 emit_label_before (loop->end_label, loop->last_insn);
3990
3991 return;
3992
ce27ef3d 3993 bad_loop:
b03149e1
JZ
3994
3995 if (dump_file)
3996 fprintf (dump_file, ";; loop %d is bad\n", loop->loop_no);
3997
e54273eb 3998 loop->bad = 1;
b03149e1
JZ
3999
4000 if (DPREG_P (loop->iter_reg))
4001 {
4002 /* If loop->iter_reg is a DREG or PREG, we can split it here
4003 without scratch register. */
4004 rtx insn;
4005
4006 emit_insn_before (gen_addsi3 (loop->iter_reg,
4007 loop->iter_reg,
4008 constm1_rtx),
4009 loop->loop_end);
4010
4011 emit_insn_before (gen_cmpsi (loop->iter_reg, const0_rtx),
4012 loop->loop_end);
4013
4014 insn = emit_jump_insn_before (gen_bne (loop->start_label),
4015 loop->loop_end);
4016
4017 JUMP_LABEL (insn) = loop->start_label;
4018 LABEL_NUSES (loop->start_label)++;
4019 delete_insn (loop->loop_end);
4020 }
4021}
4022
e54273eb
BS
4023/* Called from bfin_reorg_loops when a potential loop end is found. LOOP is
4024 a newly set up structure describing the loop, it is this function's
4025 responsibility to fill most of it. TAIL_BB and TAIL_INSN point to the
4026 loop_end insn and its enclosing basic block. */
4027
4028static void
4029bfin_discover_loop (loop_info loop, basic_block tail_bb, rtx tail_insn)
4030{
4031 unsigned dwork = 0;
4032 basic_block bb;
4033 VEC (basic_block,heap) *works = VEC_alloc (basic_block,heap,20);
4034
4035 loop->tail = tail_bb;
4036 loop->head = BRANCH_EDGE (tail_bb)->dest;
4037 loop->successor = FALLTHRU_EDGE (tail_bb)->dest;
e54273eb
BS
4038 loop->loop_end = tail_insn;
4039 loop->last_insn = NULL_RTX;
4040 loop->iter_reg = SET_DEST (XVECEXP (PATTERN (tail_insn), 0, 1));
4041 loop->depth = loop->length = 0;
4042 loop->visited = 0;
4043 loop->clobber_loop0 = loop->clobber_loop1 = 0;
4044 loop->outer = NULL;
4045 loop->loops = NULL;
ce27ef3d 4046 loop->incoming = VEC_alloc (edge, gc, 2);
e54273eb
BS
4047 loop->init = loop->loop_init = NULL_RTX;
4048 loop->start_label = XEXP (XEXP (SET_SRC (XVECEXP (PATTERN (tail_insn), 0, 0)), 1), 0);
4049 loop->end_label = NULL_RTX;
4050 loop->bad = 0;
4051
4052 VEC_safe_push (basic_block, heap, works, loop->head);
4053
4054 while (VEC_iterate (basic_block, works, dwork++, bb))
4055 {
4056 edge e;
4057 edge_iterator ei;
4058 if (bb == EXIT_BLOCK_PTR)
4059 {
4060 /* We've reached the exit block. The loop must be bad. */
4061 if (dump_file)
4062 fprintf (dump_file,
4063 ";; Loop is bad - reached exit block while scanning\n");
4064 loop->bad = 1;
4065 break;
4066 }
4067
4068 if (bitmap_bit_p (loop->block_bitmap, bb->index))
4069 continue;
4070
4071 /* We've not seen this block before. Add it to the loop's
4072 list and then add each successor to the work list. */
4073
4074 VEC_safe_push (basic_block, heap, loop->blocks, bb);
4075 bitmap_set_bit (loop->block_bitmap, bb->index);
4076
4077 if (bb != tail_bb)
4078 {
4079 FOR_EACH_EDGE (e, ei, bb->succs)
4080 {
4081 basic_block succ = EDGE_SUCC (bb, ei.index)->dest;
b18e284e 4082 if (!REGNO_REG_SET_P (df_get_live_in (succ),
e54273eb
BS
4083 REGNO (loop->iter_reg)))
4084 continue;
4085 if (!VEC_space (basic_block, works, 1))
4086 {
4087 if (dwork)
4088 {
4089 VEC_block_remove (basic_block, works, 0, dwork);
4090 dwork = 0;
4091 }
4092 else
4093 VEC_reserve (basic_block, heap, works, 1);
4094 }
4095 VEC_quick_push (basic_block, works, succ);
4096 }
4097 }
4098 }
4099
ce27ef3d 4100 /* Find the predecessor, and make sure nothing else jumps into this loop. */
e54273eb
BS
4101 if (!loop->bad)
4102 {
ce27ef3d
BS
4103 int pass, retry;
4104 for (dwork = 0; VEC_iterate (basic_block, loop->blocks, dwork, bb); dwork++)
e54273eb 4105 {
ce27ef3d
BS
4106 edge e;
4107 edge_iterator ei;
4108 FOR_EACH_EDGE (e, ei, bb->preds)
4109 {
4110 basic_block pred = e->src;
4111
4112 if (!bfin_bb_in_loop (loop, pred))
4113 {
4114 if (dump_file)
4115 fprintf (dump_file, ";; Loop %d: incoming edge %d -> %d\n",
4116 loop->loop_no, pred->index,
4117 e->dest->index);
4118 VEC_safe_push (edge, gc, loop->incoming, e);
4119 }
4120 }
e54273eb
BS
4121 }
4122
ce27ef3d 4123 for (pass = 0, retry = 1; retry && pass < 2; pass++)
e54273eb 4124 {
ce27ef3d
BS
4125 edge e;
4126 edge_iterator ei;
4127 bool first = true;
4128 retry = 0;
4129
4130 FOR_EACH_EDGE (e, ei, loop->incoming)
4131 {
4132 if (first)
4133 {
4134 loop->incoming_src = e->src;
4135 loop->incoming_dest = e->dest;
4136 first = false;
4137 }
4138 else
4139 {
4140 if (e->dest != loop->incoming_dest)
4141 loop->incoming_dest = NULL;
4142 if (e->src != loop->incoming_src)
4143 loop->incoming_src = NULL;
4144 }
4145 if (loop->incoming_src == NULL && loop->incoming_dest == NULL)
4146 {
4147 if (pass == 0)
4148 {
4149 if (dump_file)
4150 fprintf (dump_file,
4151 ";; retrying loop %d with forwarder blocks\n",
4152 loop->loop_no);
4153 retry = 1;
4154 break;
4155 }
4156 loop->bad = 1;
4157 if (dump_file)
4158 fprintf (dump_file,
4159 ";; can't find suitable entry for loop %d\n",
4160 loop->loop_no);
4161 goto out;
4162 }
4163 }
4164 if (retry)
4165 {
4166 retry = 0;
4167 FOR_EACH_EDGE (e, ei, loop->incoming)
4168 {
4169 if (forwarder_block_p (e->src))
4170 {
4171 edge e2;
4172 edge_iterator ei2;
4173
4174 if (dump_file)
4175 fprintf (dump_file,
4176 ";; Adding forwarder block %d to loop %d and retrying\n",
4177 e->src->index, loop->loop_no);
4178 VEC_safe_push (basic_block, heap, loop->blocks, e->src);
4179 bitmap_set_bit (loop->block_bitmap, e->src->index);
4180 FOR_EACH_EDGE (e2, ei2, e->src->preds)
4181 VEC_safe_push (edge, gc, loop->incoming, e2);
4182 VEC_unordered_remove (edge, loop->incoming, ei.index);
4183 retry = 1;
4184 break;
4185 }
4186 }
4187 }
e54273eb
BS
4188 }
4189 }
4190
ce27ef3d 4191 out:
e54273eb
BS
4192 VEC_free (basic_block, heap, works);
4193}
4194
ce27ef3d
BS
4195/* Analyze the structure of the loops in the current function. Use STACK
4196 for bitmap allocations. Returns all the valid candidates for hardware
4197 loops found in this function. */
4198static loop_info
4199bfin_discover_loops (bitmap_obstack *stack, FILE *dump_file)
b03149e1 4200{
b03149e1
JZ
4201 loop_info loops = NULL;
4202 loop_info loop;
ce27ef3d
BS
4203 basic_block bb;
4204 bitmap tmp_bitmap;
b03149e1 4205 int nloops = 0;
e54273eb 4206
b03149e1
JZ
4207 /* Find all the possible loop tails. This means searching for every
4208 loop_end instruction. For each one found, create a loop_info
4209 structure and add the head block to the work list. */
4210 FOR_EACH_BB (bb)
4211 {
4212 rtx tail = BB_END (bb);
4213
4214 while (GET_CODE (tail) == NOTE)
4215 tail = PREV_INSN (tail);
4216
4217 bb->aux = NULL;
e54273eb 4218
f0f1c408 4219 if (INSN_P (tail) && recog_memoized (tail) == CODE_FOR_loop_end)
b03149e1 4220 {
4fc4d850 4221 rtx insn;
b03149e1
JZ
4222 /* A possible loop end */
4223
4fc4d850
BS
4224 /* There's a degenerate case we can handle - an empty loop consisting
4225 of only a back branch. Handle that by deleting the branch. */
4226 insn = BB_HEAD (BRANCH_EDGE (bb)->dest);
4227 if (next_real_insn (insn) == tail)
4228 {
4229 if (dump_file)
4230 {
4231 fprintf (dump_file, ";; degenerate loop ending at\n");
4232 print_rtl_single (dump_file, tail);
4233 }
4234 delete_insn_and_edges (tail);
4235 continue;
4236 }
4237
b03149e1
JZ
4238 loop = XNEW (struct loop_info);
4239 loop->next = loops;
4240 loops = loop;
b03149e1 4241 loop->loop_no = nloops++;
e54273eb 4242 loop->blocks = VEC_alloc (basic_block, heap, 20);
ce27ef3d 4243 loop->block_bitmap = BITMAP_ALLOC (stack);
b03149e1
JZ
4244 bb->aux = loop;
4245
4246 if (dump_file)
4247 {
4248 fprintf (dump_file, ";; potential loop %d ending at\n",
4249 loop->loop_no);
4250 print_rtl_single (dump_file, tail);
4251 }
e54273eb
BS
4252
4253 bfin_discover_loop (loop, bb, tail);
b03149e1
JZ
4254 }
4255 }
4256
ce27ef3d 4257 tmp_bitmap = BITMAP_ALLOC (stack);
e54273eb
BS
4258 /* Compute loop nestings. */
4259 for (loop = loops; loop; loop = loop->next)
4260 {
4261 loop_info other;
4262 if (loop->bad)
4263 continue;
4264
4265 for (other = loop->next; other; other = other->next)
b03149e1 4266 {
e54273eb
BS
4267 if (other->bad)
4268 continue;
4269
4270 bitmap_and (tmp_bitmap, other->block_bitmap, loop->block_bitmap);
4271 if (bitmap_empty_p (tmp_bitmap))
4272 continue;
4273 if (bitmap_equal_p (tmp_bitmap, other->block_bitmap))
b03149e1 4274 {
e54273eb
BS
4275 other->outer = loop;
4276 VEC_safe_push (loop_info, heap, loop->loops, other);
4277 }
4278 else if (bitmap_equal_p (tmp_bitmap, loop->block_bitmap))
4279 {
4280 loop->outer = other;
4281 VEC_safe_push (loop_info, heap, other->loops, loop);
b03149e1 4282 }
b03149e1
JZ
4283 else
4284 {
ce27ef3d
BS
4285 if (dump_file)
4286 fprintf (dump_file,
4287 ";; can't find suitable nesting for loops %d and %d\n",
4288 loop->loop_no, other->loop_no);
e54273eb 4289 loop->bad = other->bad = 1;
b03149e1
JZ
4290 }
4291 }
4292 }
e54273eb 4293 BITMAP_FREE (tmp_bitmap);
b03149e1 4294
ce27ef3d
BS
4295 return loops;
4296}
4297
4298/* Free up the loop structures in LOOPS. */
4299static void
4300free_loops (loop_info loops)
4301{
4302 while (loops)
4303 {
4304 loop_info loop = loops;
4305 loops = loop->next;
4306 VEC_free (loop_info, heap, loop->loops);
4307 VEC_free (basic_block, heap, loop->blocks);
4308 BITMAP_FREE (loop->block_bitmap);
4309 XDELETE (loop);
4310 }
4311}
4312
4313#define BB_AUX_INDEX(BB) ((unsigned)(BB)->aux)
4314
4315/* The taken-branch edge from the loop end can actually go forward. Since the
4316 Blackfin's LSETUP instruction requires that the loop end be after the loop
4317 start, try to reorder a loop's basic blocks when we find such a case. */
4318static void
4319bfin_reorder_loops (loop_info loops, FILE *dump_file)
4320{
4321 basic_block bb;
4322 loop_info loop;
4323
4324 FOR_EACH_BB (bb)
4325 bb->aux = NULL;
b18e284e 4326 cfg_layout_initialize (0);
ce27ef3d
BS
4327
4328 for (loop = loops; loop; loop = loop->next)
4329 {
4330 unsigned index;
4331 basic_block bb;
4332 edge e;
4333 edge_iterator ei;
4334
4335 if (loop->bad)
4336 continue;
4337
4338 /* Recreate an index for basic blocks that represents their order. */
4339 for (bb = ENTRY_BLOCK_PTR->next_bb, index = 0;
4340 bb != EXIT_BLOCK_PTR;
4341 bb = bb->next_bb, index++)
4342 bb->aux = (PTR) index;
4343
4344 if (BB_AUX_INDEX (loop->head) < BB_AUX_INDEX (loop->tail))
4345 continue;
4346
4347 FOR_EACH_EDGE (e, ei, loop->head->succs)
4348 {
4349 if (bitmap_bit_p (loop->block_bitmap, e->dest->index)
4350 && BB_AUX_INDEX (e->dest) < BB_AUX_INDEX (loop->tail))
4351 {
4352 basic_block start_bb = e->dest;
4353 basic_block start_prev_bb = start_bb->prev_bb;
4354
4355 if (dump_file)
4356 fprintf (dump_file, ";; Moving block %d before block %d\n",
4357 loop->head->index, start_bb->index);
4358 loop->head->prev_bb->next_bb = loop->head->next_bb;
4359 loop->head->next_bb->prev_bb = loop->head->prev_bb;
4360
4361 loop->head->prev_bb = start_prev_bb;
4362 loop->head->next_bb = start_bb;
4363 start_prev_bb->next_bb = start_bb->prev_bb = loop->head;
4364 break;
4365 }
4366 }
4367 loops = loops->next;
4368 }
4369
4370 FOR_EACH_BB (bb)
4371 {
4372 if (bb->next_bb != EXIT_BLOCK_PTR)
4373 bb->aux = bb->next_bb;
4374 else
4375 bb->aux = NULL;
4376 }
4377 cfg_layout_finalize ();
b18e284e 4378 df_analyze ();
ce27ef3d
BS
4379}
4380
4381/* Run from machine_dependent_reorg, this pass looks for doloop_end insns
4382 and tries to rewrite the RTL of these loops so that proper Blackfin
4383 hardware loops are generated. */
4384
4385static void
4386bfin_reorg_loops (FILE *dump_file)
4387{
4388 loop_info loops = NULL;
4389 loop_info loop;
4390 basic_block bb;
4391 bitmap_obstack stack;
4392
4393 bitmap_obstack_initialize (&stack);
4394
4395 if (dump_file)
4396 fprintf (dump_file, ";; Find loops, first pass\n\n");
4397
4398 loops = bfin_discover_loops (&stack, dump_file);
4399
4400 if (dump_file)
4401 bfin_dump_loops (loops);
4402
4403 bfin_reorder_loops (loops, dump_file);
4404 free_loops (loops);
4405
4406 if (dump_file)
4407 fprintf (dump_file, ";; Find loops, second pass\n\n");
4408
4409 loops = bfin_discover_loops (&stack, dump_file);
b03149e1
JZ
4410 if (dump_file)
4411 {
4412 fprintf (dump_file, ";; All loops found:\n\n");
4413 bfin_dump_loops (loops);
4414 }
4415
4416 /* Now apply the optimizations. */
4417 for (loop = loops; loop; loop = loop->next)
4418 bfin_optimize_loop (loop);
4419
4420 if (dump_file)
4421 {
4422 fprintf (dump_file, ";; After hardware loops optimization:\n\n");
4423 bfin_dump_loops (loops);
4424 }
4425
ce27ef3d 4426 free_loops (loops);
b03149e1
JZ
4427
4428 if (dump_file)
4429 print_rtl (dump_file, get_insns ());
bbbc206e
BS
4430
4431 FOR_EACH_BB (bb)
4432 bb->aux = NULL;
b03149e1 4433}
bbbc206e
BS
4434\f
4435/* Possibly generate a SEQUENCE out of three insns found in SLOT.
4436 Returns true if we modified the insn chain, false otherwise. */
4437static bool
4438gen_one_bundle (rtx slot[3])
4439{
bbbc206e
BS
4440 gcc_assert (slot[1] != NULL_RTX);
4441
4442 /* Verify that we really can do the multi-issue. */
4443 if (slot[0])
4444 {
4445 rtx t = NEXT_INSN (slot[0]);
4446 while (t != slot[1])
4447 {
4448 if (GET_CODE (t) != NOTE
a38e7aa5 4449 || NOTE_KIND (t) != NOTE_INSN_DELETED)
bbbc206e
BS
4450 return false;
4451 t = NEXT_INSN (t);
4452 }
4453 }
4454 if (slot[2])
4455 {
4456 rtx t = NEXT_INSN (slot[1]);
4457 while (t != slot[2])
4458 {
4459 if (GET_CODE (t) != NOTE
a38e7aa5 4460 || NOTE_KIND (t) != NOTE_INSN_DELETED)
bbbc206e
BS
4461 return false;
4462 t = NEXT_INSN (t);
4463 }
4464 }
4465
4466 if (slot[0] == NULL_RTX)
b18e284e
BS
4467 {
4468 slot[0] = emit_insn_before (gen_mnop (), slot[1]);
4469 df_insn_rescan (slot[0]);
4470 }
bbbc206e 4471 if (slot[2] == NULL_RTX)
b18e284e
BS
4472 {
4473 slot[2] = emit_insn_after (gen_forced_nop (), slot[1]);
4474 df_insn_rescan (slot[2]);
4475 }
bbbc206e
BS
4476
4477 /* Avoid line number information being printed inside one bundle. */
4478 if (INSN_LOCATOR (slot[1])
4479 && INSN_LOCATOR (slot[1]) != INSN_LOCATOR (slot[0]))
4480 INSN_LOCATOR (slot[1]) = INSN_LOCATOR (slot[0]);
4481 if (INSN_LOCATOR (slot[2])
4482 && INSN_LOCATOR (slot[2]) != INSN_LOCATOR (slot[0]))
4483 INSN_LOCATOR (slot[2]) = INSN_LOCATOR (slot[0]);
4484
4485 /* Terminate them with "|| " instead of ";" in the output. */
4486 PUT_MODE (slot[0], SImode);
4487 PUT_MODE (slot[1], SImode);
b18e284e
BS
4488 /* Terminate the bundle, for the benefit of reorder_var_tracking_notes. */
4489 PUT_MODE (slot[2], QImode);
bbbc206e
BS
4490 return true;
4491}
4492
4493/* Go through all insns, and use the information generated during scheduling
4494 to generate SEQUENCEs to represent bundles of instructions issued
4495 simultaneously. */
4496
4497static void
4498bfin_gen_bundles (void)
4499{
4500 basic_block bb;
4501 FOR_EACH_BB (bb)
4502 {
4503 rtx insn, next;
4504 rtx slot[3];
4505 int n_filled = 0;
4506
4507 slot[0] = slot[1] = slot[2] = NULL_RTX;
4508 for (insn = BB_HEAD (bb);; insn = next)
4509 {
4510 int at_end;
4511 if (INSN_P (insn))
4512 {
4513 if (get_attr_type (insn) == TYPE_DSP32)
4514 slot[0] = insn;
4515 else if (slot[1] == NULL_RTX)
4516 slot[1] = insn;
4517 else
4518 slot[2] = insn;
4519 n_filled++;
4520 }
4521
4522 next = NEXT_INSN (insn);
4523 while (next && insn != BB_END (bb)
4524 && !(INSN_P (next)
4525 && GET_CODE (PATTERN (next)) != USE
4526 && GET_CODE (PATTERN (next)) != CLOBBER))
4527 {
4528 insn = next;
4529 next = NEXT_INSN (insn);
4530 }
b03149e1 4531
bbbc206e
BS
4532 /* BB_END can change due to emitting extra NOPs, so check here. */
4533 at_end = insn == BB_END (bb);
4534 if (at_end || GET_MODE (next) == TImode)
4535 {
4536 if ((n_filled < 2
4537 || !gen_one_bundle (slot))
4538 && slot[0] != NULL_RTX)
4539 {
4540 rtx pat = PATTERN (slot[0]);
4541 if (GET_CODE (pat) == SET
4542 && GET_CODE (SET_SRC (pat)) == UNSPEC
4543 && XINT (SET_SRC (pat), 1) == UNSPEC_32BIT)
4544 {
4545 SET_SRC (pat) = XVECEXP (SET_SRC (pat), 0, 0);
4546 INSN_CODE (slot[0]) = -1;
b18e284e 4547 df_insn_rescan (slot[0]);
bbbc206e
BS
4548 }
4549 }
4550 n_filled = 0;
4551 slot[0] = slot[1] = slot[2] = NULL_RTX;
4552 }
4553 if (at_end)
4554 break;
4555 }
4556 }
4557}
b18e284e
BS
4558
4559/* Ensure that no var tracking notes are emitted in the middle of a
4560 three-instruction bundle. */
4561
4562static void
4563reorder_var_tracking_notes (void)
4564{
4565 basic_block bb;
4566 FOR_EACH_BB (bb)
4567 {
4568 rtx insn, next;
4569 rtx queue = NULL_RTX;
4570 bool in_bundle = false;
4571
4572 for (insn = BB_HEAD (bb); insn != BB_END (bb); insn = next)
4573 {
4574 next = NEXT_INSN (insn);
4575
4576 if (INSN_P (insn))
4577 {
4578 /* Emit queued up notes at the last instruction of a bundle. */
4579 if (GET_MODE (insn) == QImode)
4580 {
4581 while (queue)
4582 {
4583 rtx next_queue = PREV_INSN (queue);
4584 PREV_INSN (NEXT_INSN (insn)) = queue;
4585 NEXT_INSN (queue) = NEXT_INSN (insn);
4586 NEXT_INSN (insn) = queue;
4587 PREV_INSN (queue) = insn;
4588 queue = next_queue;
4589 }
4590 in_bundle = false;
4591 }
4592 else if (GET_MODE (insn) == SImode)
4593 in_bundle = true;
4594 }
4595 else if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_VAR_LOCATION)
4596 {
4597 if (in_bundle)
4598 {
4599 rtx prev = PREV_INSN (insn);
4600 PREV_INSN (next) = prev;
4601 NEXT_INSN (prev) = next;
4602
4603 PREV_INSN (insn) = queue;
4604 queue = insn;
4605 }
4606 }
4607 }
4608 }
4609}
0d4a78eb 4610\f
bbbc206e
BS
4611/* Return an insn type for INSN that can be used by the caller for anomaly
4612 workarounds. This differs from plain get_attr_type in that it handles
4613 SEQUENCEs. */
4614
4615static enum attr_type
4616type_for_anomaly (rtx insn)
4617{
4618 rtx pat = PATTERN (insn);
4619 if (GET_CODE (pat) == SEQUENCE)
4620 {
4621 enum attr_type t;
4622 t = get_attr_type (XVECEXP (pat, 0, 1));
4623 if (t == TYPE_MCLD)
4624 return t;
4625 t = get_attr_type (XVECEXP (pat, 0, 2));
4626 if (t == TYPE_MCLD)
4627 return t;
4628 return TYPE_MCST;
4629 }
4630 else
4631 return get_attr_type (insn);
4632}
4633
4634/* Return nonzero if INSN contains any loads that may trap. It handles
4635 SEQUENCEs correctly. */
4636
4637static bool
4638trapping_loads_p (rtx insn)
4639{
4640 rtx pat = PATTERN (insn);
4641 if (GET_CODE (pat) == SEQUENCE)
4642 {
4643 enum attr_type t;
4644 t = get_attr_type (XVECEXP (pat, 0, 1));
96f46444
BS
4645 if (t == TYPE_MCLD
4646 && may_trap_p (SET_SRC (PATTERN (XVECEXP (pat, 0, 1)))))
bbbc206e
BS
4647 return true;
4648 t = get_attr_type (XVECEXP (pat, 0, 2));
96f46444
BS
4649 if (t == TYPE_MCLD
4650 && may_trap_p (SET_SRC (PATTERN (XVECEXP (pat, 0, 2)))))
bbbc206e
BS
4651 return true;
4652 return false;
4653 }
4654 else
4655 return may_trap_p (SET_SRC (single_set (insn)));
4656}
4657
44017a45
BS
4658/* This function acts like NEXT_INSN, but is aware of three-insn bundles and
4659 skips all subsequent parallel instructions if INSN is the start of such
4660 a group. */
4661static rtx
4662find_next_insn_start (rtx insn)
4663{
4664 if (GET_MODE (insn) == SImode)
4665 {
4666 while (GET_MODE (insn) != QImode)
4667 insn = NEXT_INSN (insn);
4668 }
4669 return NEXT_INSN (insn);
4670}
4671
4672/* Return INSN if it is of TYPE_MCLD. Alternatively, if INSN is the start of
4673 a three-insn bundle, see if one of them is a load and return that if so.
4674 Return NULL_RTX if the insn does not contain loads. */
4675static rtx
4676find_load (rtx insn)
4677{
4678 if (get_attr_type (insn) == TYPE_MCLD)
4679 return insn;
4680 if (GET_MODE (insn) != SImode)
4681 return NULL_RTX;
4682 do {
4683 insn = NEXT_INSN (insn);
4684 if ((GET_MODE (insn) == SImode || GET_MODE (insn) == QImode)
4685 && get_attr_type (insn) == TYPE_MCLD)
4686 return insn;
4687 } while (GET_MODE (insn) != QImode);
4688 return NULL_RTX;
4689}
4690
0d4a78eb
BS
4691/* We use the machine specific reorg pass for emitting CSYNC instructions
4692 after conditional branches as needed.
4693
4694 The Blackfin is unusual in that a code sequence like
4695 if cc jump label
4696 r0 = (p0)
4697 may speculatively perform the load even if the condition isn't true. This
4698 happens for a branch that is predicted not taken, because the pipeline
4699 isn't flushed or stalled, so the early stages of the following instructions,
4700 which perform the memory reference, are allowed to execute before the
4701 jump condition is evaluated.
4702 Therefore, we must insert additional instructions in all places where this
0fa2e4df 4703 could lead to incorrect behavior. The manual recommends CSYNC, while
0d4a78eb
BS
4704 VDSP seems to use NOPs (even though its corresponding compiler option is
4705 named CSYNC).
4706
4707 When optimizing for speed, we emit NOPs, which seems faster than a CSYNC.
4708 When optimizing for size, we turn the branch into a predicted taken one.
4709 This may be slower due to mispredicts, but saves code size. */
4710
4711static void
4712bfin_reorg (void)
4713{
44017a45
BS
4714 rtx insn, next;
4715 rtx last_condjump = NULL_RTX;
0d4a78eb
BS
4716 int cycles_since_jump = INT_MAX;
4717
bbbc206e
BS
4718 /* We are freeing block_for_insn in the toplev to keep compatibility
4719 with old MDEP_REORGS that are not CFG based. Recompute it now. */
4720 compute_bb_for_insn ();
4721
4722 if (bfin_flag_schedule_insns2)
4723 {
4724 splitting_for_sched = 1;
b18e284e 4725 split_all_insns ();
bbbc206e
BS
4726 splitting_for_sched = 0;
4727
bbbc206e
BS
4728 timevar_push (TV_SCHED2);
4729 schedule_insns ();
4730 timevar_pop (TV_SCHED2);
4731
942fd98f 4732 /* Examine the schedule and insert nops as necessary for 64-bit parallel
bbbc206e
BS
4733 instructions. */
4734 bfin_gen_bundles ();
4735 }
4736
b18e284e
BS
4737 df_analyze ();
4738
b03149e1
JZ
4739 /* Doloop optimization */
4740 if (cfun->machine->has_hardware_loops)
4741 bfin_reorg_loops (dump_file);
4742
ea2382be 4743 if (! ENABLE_WA_SPECULATIVE_LOADS && ! ENABLE_WA_SPECULATIVE_SYNCS)
0d4a78eb
BS
4744 return;
4745
3fb192d2
BS
4746 /* First pass: find predicted-false branches; if something after them
4747 needs nops, insert them or change the branch to predict true. */
44017a45 4748 for (insn = get_insns (); insn; insn = next)
0d4a78eb
BS
4749 {
4750 rtx pat;
4751
44017a45
BS
4752 next = find_next_insn_start (insn);
4753
0d4a78eb
BS
4754 if (NOTE_P (insn) || BARRIER_P (insn) || LABEL_P (insn))
4755 continue;
4756
4757 pat = PATTERN (insn);
4758 if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER
4759 || GET_CODE (pat) == ASM_INPUT || GET_CODE (pat) == ADDR_VEC
4760 || GET_CODE (pat) == ADDR_DIFF_VEC || asm_noperands (pat) >= 0)
4761 continue;
4762
4763 if (JUMP_P (insn))
4764 {
4765 if (any_condjump_p (insn)
4766 && ! cbranch_predicted_taken_p (insn))
4767 {
4768 last_condjump = insn;
4769 cycles_since_jump = 0;
4770 }
4771 else
4772 cycles_since_jump = INT_MAX;
4773 }
4774 else if (INSN_P (insn))
4775 {
44017a45 4776 rtx load_insn = find_load (insn);
bbbc206e 4777 enum attr_type type = type_for_anomaly (insn);
3fb192d2 4778 int delay_needed = 0;
0d4a78eb
BS
4779 if (cycles_since_jump < INT_MAX)
4780 cycles_since_jump++;
4781
ea2382be 4782 if (load_insn && ENABLE_WA_SPECULATIVE_LOADS)
3fb192d2 4783 {
44017a45 4784 if (trapping_loads_p (load_insn))
3fb192d2
BS
4785 delay_needed = 3;
4786 }
ea2382be 4787 else if (type == TYPE_SYNC && ENABLE_WA_SPECULATIVE_SYNCS)
3fb192d2
BS
4788 delay_needed = 4;
4789
4790 if (delay_needed > cycles_since_jump)
0d4a78eb
BS
4791 {
4792 rtx pat;
3fb192d2
BS
4793 int num_clobbers;
4794 rtx *op = recog_data.operand;
0d4a78eb 4795
3fb192d2
BS
4796 delay_needed -= cycles_since_jump;
4797
4798 extract_insn (last_condjump);
4799 if (optimize_size)
0d4a78eb 4800 {
3fb192d2
BS
4801 pat = gen_cbranch_predicted_taken (op[0], op[1], op[2],
4802 op[3]);
0d4a78eb
BS
4803 cycles_since_jump = INT_MAX;
4804 }
3fb192d2
BS
4805 else
4806 /* Do not adjust cycles_since_jump in this case, so that
4807 we'll increase the number of NOPs for a subsequent insn
4808 if necessary. */
4809 pat = gen_cbranch_with_nops (op[0], op[1], op[2], op[3],
4810 GEN_INT (delay_needed));
4811 PATTERN (last_condjump) = pat;
4812 INSN_CODE (last_condjump) = recog (pat, insn, &num_clobbers);
4813 }
4814 }
4815 }
4816 /* Second pass: for predicted-true branches, see if anything at the
4817 branch destination needs extra nops. */
ea2382be 4818 if (! ENABLE_WA_SPECULATIVE_SYNCS)
3fb192d2
BS
4819 return;
4820
fa8d4a0f
BS
4821 if (! ENABLE_WA_RETS)
4822 return;
4823
3fb192d2
BS
4824 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
4825 {
4826 if (JUMP_P (insn)
4827 && any_condjump_p (insn)
4828 && (INSN_CODE (insn) == CODE_FOR_cbranch_predicted_taken
4829 || cbranch_predicted_taken_p (insn)))
4830 {
4831 rtx target = JUMP_LABEL (insn);
4832 rtx label = target;
4833 cycles_since_jump = 0;
4834 for (; target && cycles_since_jump < 3; target = NEXT_INSN (target))
4835 {
4836 rtx pat;
4837
4838 if (NOTE_P (target) || BARRIER_P (target) || LABEL_P (target))
4839 continue;
4840
4841 pat = PATTERN (target);
4842 if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER
4843 || GET_CODE (pat) == ASM_INPUT || GET_CODE (pat) == ADDR_VEC
4844 || GET_CODE (pat) == ADDR_DIFF_VEC || asm_noperands (pat) >= 0)
4845 continue;
4846
4847 if (INSN_P (target))
4848 {
bbbc206e 4849 enum attr_type type = type_for_anomaly (target);
3fb192d2
BS
4850 int delay_needed = 0;
4851 if (cycles_since_jump < INT_MAX)
4852 cycles_since_jump++;
4853
ea2382be 4854 if (type == TYPE_SYNC && ENABLE_WA_SPECULATIVE_SYNCS)
3fb192d2
BS
4855 delay_needed = 2;
4856
4857 if (delay_needed > cycles_since_jump)
4858 {
4859 rtx prev = prev_real_insn (label);
4860 delay_needed -= cycles_since_jump;
4861 if (dump_file)
4862 fprintf (dump_file, "Adding %d nops after %d\n",
4863 delay_needed, INSN_UID (label));
4864 if (JUMP_P (prev)
4865 && INSN_CODE (prev) == CODE_FOR_cbranch_with_nops)
4866 {
4867 rtx x;
4868 HOST_WIDE_INT v;
4869
4870 if (dump_file)
4871 fprintf (dump_file,
4872 "Reducing nops on insn %d.\n",
4873 INSN_UID (prev));
4874 x = PATTERN (prev);
4875 x = XVECEXP (x, 0, 1);
4876 v = INTVAL (XVECEXP (x, 0, 0)) - delay_needed;
4877 XVECEXP (x, 0, 0) = GEN_INT (v);
4878 }
4879 while (delay_needed-- > 0)
4880 emit_insn_after (gen_nop (), label);
4881 break;
4882 }
4883 }
0d4a78eb
BS
4884 }
4885 }
4886 }
bbbc206e
BS
4887
4888 if (bfin_flag_var_tracking)
4889 {
4890 timevar_push (TV_VAR_TRACKING);
4891 variable_tracking_main ();
b18e284e 4892 reorder_var_tracking_notes ();
bbbc206e
BS
4893 timevar_pop (TV_VAR_TRACKING);
4894 }
0d475361 4895 df_finish_pass (false);
0d4a78eb
BS
4896}
4897\f
4898/* Handle interrupt_handler, exception_handler and nmi_handler function
4899 attributes; arguments as in struct attribute_spec.handler. */
4900
4901static tree
4902handle_int_attribute (tree *node, tree name,
4903 tree args ATTRIBUTE_UNUSED,
4904 int flags ATTRIBUTE_UNUSED,
4905 bool *no_add_attrs)
4906{
4907 tree x = *node;
4908 if (TREE_CODE (x) == FUNCTION_DECL)
4909 x = TREE_TYPE (x);
4910
4911 if (TREE_CODE (x) != FUNCTION_TYPE)
4912 {
5c498b10 4913 warning (OPT_Wattributes, "%qs attribute only applies to functions",
0d4a78eb
BS
4914 IDENTIFIER_POINTER (name));
4915 *no_add_attrs = true;
4916 }
4917 else if (funkind (x) != SUBROUTINE)
4918 error ("multiple function type attributes specified");
4919
4920 return NULL_TREE;
4921}
4922
4923/* Return 0 if the attributes for two types are incompatible, 1 if they
4924 are compatible, and 2 if they are nearly compatible (which causes a
4925 warning to be generated). */
4926
4927static int
3101faab 4928bfin_comp_type_attributes (const_tree type1, const_tree type2)
0d4a78eb
BS
4929{
4930 e_funkind kind1, kind2;
4931
4932 if (TREE_CODE (type1) != FUNCTION_TYPE)
4933 return 1;
4934
4935 kind1 = funkind (type1);
4936 kind2 = funkind (type2);
4937
4938 if (kind1 != kind2)
4939 return 0;
4940
4941 /* Check for mismatched modifiers */
4942 if (!lookup_attribute ("nesting", TYPE_ATTRIBUTES (type1))
4943 != !lookup_attribute ("nesting", TYPE_ATTRIBUTES (type2)))
4944 return 0;
4945
4946 if (!lookup_attribute ("saveall", TYPE_ATTRIBUTES (type1))
4947 != !lookup_attribute ("saveall", TYPE_ATTRIBUTES (type2)))
4948 return 0;
4949
4950 if (!lookup_attribute ("kspisusp", TYPE_ATTRIBUTES (type1))
4951 != !lookup_attribute ("kspisusp", TYPE_ATTRIBUTES (type2)))
4952 return 0;
4953
6d459e2b
BS
4954 if (!lookup_attribute ("longcall", TYPE_ATTRIBUTES (type1))
4955 != !lookup_attribute ("longcall", TYPE_ATTRIBUTES (type2)))
4956 return 0;
4957
0d4a78eb
BS
4958 return 1;
4959}
4960
6d459e2b
BS
4961/* Handle a "longcall" or "shortcall" attribute; arguments as in
4962 struct attribute_spec.handler. */
4963
4964static tree
4965bfin_handle_longcall_attribute (tree *node, tree name,
4966 tree args ATTRIBUTE_UNUSED,
4967 int flags ATTRIBUTE_UNUSED,
4968 bool *no_add_attrs)
4969{
4970 if (TREE_CODE (*node) != FUNCTION_TYPE
4971 && TREE_CODE (*node) != FIELD_DECL
4972 && TREE_CODE (*node) != TYPE_DECL)
4973 {
4974 warning (OPT_Wattributes, "`%s' attribute only applies to functions",
4975 IDENTIFIER_POINTER (name));
4976 *no_add_attrs = true;
4977 }
4978
4979 if ((strcmp (IDENTIFIER_POINTER (name), "longcall") == 0
4980 && lookup_attribute ("shortcall", TYPE_ATTRIBUTES (*node)))
4981 || (strcmp (IDENTIFIER_POINTER (name), "shortcall") == 0
4982 && lookup_attribute ("longcall", TYPE_ATTRIBUTES (*node))))
4983 {
4984 warning (OPT_Wattributes,
4985 "can't apply both longcall and shortcall attributes to the same function");
4986 *no_add_attrs = true;
4987 }
4988
4989 return NULL_TREE;
4990}
4991
4af797b5
JZ
4992/* Handle a "l1_text" attribute; arguments as in
4993 struct attribute_spec.handler. */
4994
4995static tree
4996bfin_handle_l1_text_attribute (tree *node, tree name, tree ARG_UNUSED (args),
4997 int ARG_UNUSED (flags), bool *no_add_attrs)
4998{
4999 tree decl = *node;
5000
5001 if (TREE_CODE (decl) != FUNCTION_DECL)
5002 {
5003 error ("`%s' attribute only applies to functions",
5004 IDENTIFIER_POINTER (name));
5005 *no_add_attrs = true;
5006 }
5007
5008 /* The decl may have already been given a section attribute
5009 from a previous declaration. Ensure they match. */
5010 else if (DECL_SECTION_NAME (decl) != NULL_TREE
5011 && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
5012 ".l1.text") != 0)
5013 {
5014 error ("section of %q+D conflicts with previous declaration",
5015 decl);
5016 *no_add_attrs = true;
5017 }
5018 else
5019 DECL_SECTION_NAME (decl) = build_string (9, ".l1.text");
5020
5021 return NULL_TREE;
5022}
5023
5024/* Handle a "l1_data", "l1_data_A" or "l1_data_B" attribute;
5025 arguments as in struct attribute_spec.handler. */
5026
5027static tree
5028bfin_handle_l1_data_attribute (tree *node, tree name, tree ARG_UNUSED (args),
5029 int ARG_UNUSED (flags), bool *no_add_attrs)
5030{
5031 tree decl = *node;
5032
5033 if (TREE_CODE (decl) != VAR_DECL)
5034 {
5035 error ("`%s' attribute only applies to variables",
5036 IDENTIFIER_POINTER (name));
5037 *no_add_attrs = true;
5038 }
5039 else if (current_function_decl != NULL_TREE
5040 && !TREE_STATIC (decl))
5041 {
5042 error ("`%s' attribute cannot be specified for local variables",
5043 IDENTIFIER_POINTER (name));
5044 *no_add_attrs = true;
5045 }
5046 else
5047 {
5048 const char *section_name;
5049
5050 if (strcmp (IDENTIFIER_POINTER (name), "l1_data") == 0)
5051 section_name = ".l1.data";
5052 else if (strcmp (IDENTIFIER_POINTER (name), "l1_data_A") == 0)
5053 section_name = ".l1.data.A";
5054 else if (strcmp (IDENTIFIER_POINTER (name), "l1_data_B") == 0)
5055 section_name = ".l1.data.B";
5056 else
5057 gcc_unreachable ();
5058
5059 /* The decl may have already been given a section attribute
5060 from a previous declaration. Ensure they match. */
5061 if (DECL_SECTION_NAME (decl) != NULL_TREE
5062 && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
5063 section_name) != 0)
5064 {
5065 error ("section of %q+D conflicts with previous declaration",
5066 decl);
5067 *no_add_attrs = true;
5068 }
5069 else
5070 DECL_SECTION_NAME (decl)
5071 = build_string (strlen (section_name) + 1, section_name);
5072 }
5073
5074 return NULL_TREE;
5075}
5076
0d4a78eb
BS
5077/* Table of valid machine attributes. */
5078const struct attribute_spec bfin_attribute_table[] =
5079{
5080 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
5081 { "interrupt_handler", 0, 0, false, true, true, handle_int_attribute },
5082 { "exception_handler", 0, 0, false, true, true, handle_int_attribute },
5083 { "nmi_handler", 0, 0, false, true, true, handle_int_attribute },
5084 { "nesting", 0, 0, false, true, true, NULL },
5085 { "kspisusp", 0, 0, false, true, true, NULL },
5086 { "saveall", 0, 0, false, true, true, NULL },
6d459e2b
BS
5087 { "longcall", 0, 0, false, true, true, bfin_handle_longcall_attribute },
5088 { "shortcall", 0, 0, false, true, true, bfin_handle_longcall_attribute },
4af797b5
JZ
5089 { "l1_text", 0, 0, true, false, false, bfin_handle_l1_text_attribute },
5090 { "l1_data", 0, 0, true, false, false, bfin_handle_l1_data_attribute },
5091 { "l1_data_A", 0, 0, true, false, false, bfin_handle_l1_data_attribute },
5092 { "l1_data_B", 0, 0, true, false, false, bfin_handle_l1_data_attribute },
0d4a78eb
BS
5093 { NULL, 0, 0, false, false, false, NULL }
5094};
5095\f
6614f9f5
BS
5096/* Implementation of TARGET_ASM_INTEGER. When using FD-PIC, we need to
5097 tell the assembler to generate pointers to function descriptors in
5098 some cases. */
5099
5100static bool
5101bfin_assemble_integer (rtx value, unsigned int size, int aligned_p)
5102{
5103 if (TARGET_FDPIC && size == UNITS_PER_WORD)
5104 {
5105 if (GET_CODE (value) == SYMBOL_REF
5106 && SYMBOL_REF_FUNCTION_P (value))
5107 {
5108 fputs ("\t.picptr\tfuncdesc(", asm_out_file);
5109 output_addr_const (asm_out_file, value);
5110 fputs (")\n", asm_out_file);
5111 return true;
5112 }
5113 if (!aligned_p)
5114 {
5115 /* We've set the unaligned SI op to NULL, so we always have to
5116 handle the unaligned case here. */
5117 assemble_integer_with_op ("\t.4byte\t", value);
5118 return true;
5119 }
5120 }
5121 return default_assemble_integer (value, size, aligned_p);
5122}
5123\f
0d4a78eb
BS
5124/* Output the assembler code for a thunk function. THUNK_DECL is the
5125 declaration for the thunk function itself, FUNCTION is the decl for
5126 the target function. DELTA is an immediate constant offset to be
5127 added to THIS. If VCALL_OFFSET is nonzero, the word at
5128 *(*this + vcall_offset) should be added to THIS. */
5129
5130static void
5131bfin_output_mi_thunk (FILE *file ATTRIBUTE_UNUSED,
5132 tree thunk ATTRIBUTE_UNUSED, HOST_WIDE_INT delta,
5133 HOST_WIDE_INT vcall_offset, tree function)
5134{
5135 rtx xops[3];
5136 /* The this parameter is passed as the first argument. */
5137 rtx this = gen_rtx_REG (Pmode, REG_R0);
5138
5139 /* Adjust the this parameter by a fixed constant. */
5140 if (delta)
5141 {
5142 xops[1] = this;
5143 if (delta >= -64 && delta <= 63)
5144 {
5145 xops[0] = GEN_INT (delta);
5146 output_asm_insn ("%1 += %0;", xops);
5147 }
5148 else if (delta >= -128 && delta < -64)
5149 {
5150 xops[0] = GEN_INT (delta + 64);
5151 output_asm_insn ("%1 += -64; %1 += %0;", xops);
5152 }
5153 else if (delta > 63 && delta <= 126)
5154 {
5155 xops[0] = GEN_INT (delta - 63);
5156 output_asm_insn ("%1 += 63; %1 += %0;", xops);
5157 }
5158 else
5159 {
5160 xops[0] = GEN_INT (delta);
5161 output_asm_insn ("r3.l = %h0; r3.h = %d0; %1 = %1 + r3;", xops);
5162 }
5163 }
5164
5165 /* Adjust the this parameter by a value stored in the vtable. */
5166 if (vcall_offset)
5167 {
5168 rtx p2tmp = gen_rtx_REG (Pmode, REG_P2);
6ce986b9 5169 rtx tmp = gen_rtx_REG (Pmode, REG_R3);
0d4a78eb
BS
5170
5171 xops[1] = tmp;
5172 xops[2] = p2tmp;
5173 output_asm_insn ("%2 = r0; %2 = [%2];", xops);
5174
5175 /* Adjust the this parameter. */
5176 xops[0] = gen_rtx_MEM (Pmode, plus_constant (p2tmp, vcall_offset));
5177 if (!memory_operand (xops[0], Pmode))
5178 {
5179 rtx tmp2 = gen_rtx_REG (Pmode, REG_P1);
5180 xops[0] = GEN_INT (vcall_offset);
5181 xops[1] = tmp2;
5182 output_asm_insn ("%h1 = %h0; %d1 = %d0; %2 = %2 + %1", xops);
5183 xops[0] = gen_rtx_MEM (Pmode, p2tmp);
5184 }
5185 xops[2] = this;
5186 output_asm_insn ("%1 = %0; %2 = %2 + %1;", xops);
5187 }
5188
5189 xops[0] = XEXP (DECL_RTL (function), 0);
5190 if (1 || !flag_pic || (*targetm.binds_local_p) (function))
5191 output_asm_insn ("jump.l\t%P0", xops);
5192}
5193\f
9df3d545
BS
5194/* Codes for all the Blackfin builtins. */
5195enum bfin_builtins
5196{
5197 BFIN_BUILTIN_CSYNC,
5198 BFIN_BUILTIN_SSYNC,
1d7d5ac4 5199 BFIN_BUILTIN_ONES,
42da70b7
BS
5200 BFIN_BUILTIN_COMPOSE_2X16,
5201 BFIN_BUILTIN_EXTRACTLO,
5202 BFIN_BUILTIN_EXTRACTHI,
5203
5204 BFIN_BUILTIN_SSADD_2X16,
5205 BFIN_BUILTIN_SSSUB_2X16,
5206 BFIN_BUILTIN_SSADDSUB_2X16,
5207 BFIN_BUILTIN_SSSUBADD_2X16,
5208 BFIN_BUILTIN_MULT_2X16,
5209 BFIN_BUILTIN_MULTR_2X16,
5210 BFIN_BUILTIN_NEG_2X16,
5211 BFIN_BUILTIN_ABS_2X16,
5212 BFIN_BUILTIN_MIN_2X16,
5213 BFIN_BUILTIN_MAX_2X16,
5214
5215 BFIN_BUILTIN_SSADD_1X16,
5216 BFIN_BUILTIN_SSSUB_1X16,
5217 BFIN_BUILTIN_MULT_1X16,
5218 BFIN_BUILTIN_MULTR_1X16,
5219 BFIN_BUILTIN_NORM_1X16,
5220 BFIN_BUILTIN_NEG_1X16,
5221 BFIN_BUILTIN_ABS_1X16,
5222 BFIN_BUILTIN_MIN_1X16,
5223 BFIN_BUILTIN_MAX_1X16,
5224
26c5953d 5225 BFIN_BUILTIN_SUM_2X16,
42da70b7
BS
5226 BFIN_BUILTIN_DIFFHL_2X16,
5227 BFIN_BUILTIN_DIFFLH_2X16,
5228
5229 BFIN_BUILTIN_SSADD_1X32,
5230 BFIN_BUILTIN_SSSUB_1X32,
5231 BFIN_BUILTIN_NORM_1X32,
26c5953d 5232 BFIN_BUILTIN_ROUND_1X32,
42da70b7 5233 BFIN_BUILTIN_NEG_1X32,
26c5953d 5234 BFIN_BUILTIN_ABS_1X32,
42da70b7
BS
5235 BFIN_BUILTIN_MIN_1X32,
5236 BFIN_BUILTIN_MAX_1X32,
5237 BFIN_BUILTIN_MULT_1X32,
26c5953d
BS
5238 BFIN_BUILTIN_MULT_1X32X32,
5239 BFIN_BUILTIN_MULT_1X32X32NS,
42da70b7
BS
5240
5241 BFIN_BUILTIN_MULHISILL,
5242 BFIN_BUILTIN_MULHISILH,
5243 BFIN_BUILTIN_MULHISIHL,
5244 BFIN_BUILTIN_MULHISIHH,
5245
5246 BFIN_BUILTIN_LSHIFT_1X16,
5247 BFIN_BUILTIN_LSHIFT_2X16,
5248 BFIN_BUILTIN_SSASHIFT_1X16,
5249 BFIN_BUILTIN_SSASHIFT_2X16,
26c5953d 5250 BFIN_BUILTIN_SSASHIFT_1X32,
42da70b7
BS
5251
5252 BFIN_BUILTIN_CPLX_MUL_16,
5253 BFIN_BUILTIN_CPLX_MAC_16,
5254 BFIN_BUILTIN_CPLX_MSU_16,
5255
1d7d5ac4
BS
5256 BFIN_BUILTIN_CPLX_MUL_16_S40,
5257 BFIN_BUILTIN_CPLX_MAC_16_S40,
5258 BFIN_BUILTIN_CPLX_MSU_16_S40,
5259
5260 BFIN_BUILTIN_CPLX_SQU,
5261
8fa477f7
BS
5262 BFIN_BUILTIN_LOADBYTES,
5263
9df3d545
BS
5264 BFIN_BUILTIN_MAX
5265};
5266
05905337
BS
5267#define def_builtin(NAME, TYPE, CODE) \
5268do { \
c79efc4d
RÁE
5269 add_builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD, \
5270 NULL, NULL_TREE); \
5fcead21
BS
5271} while (0)
5272
5273/* Set up all builtin functions for this target. */
5274static void
5275bfin_init_builtins (void)
5276{
42da70b7 5277 tree V2HI_type_node = build_vector_type_for_mode (intHI_type_node, V2HImode);
5fcead21
BS
5278 tree void_ftype_void
5279 = build_function_type (void_type_node, void_list_node);
42da70b7
BS
5280 tree short_ftype_short
5281 = build_function_type_list (short_integer_type_node, short_integer_type_node,
5282 NULL_TREE);
5283 tree short_ftype_int_int
5284 = build_function_type_list (short_integer_type_node, integer_type_node,
5285 integer_type_node, NULL_TREE);
5286 tree int_ftype_int_int
5287 = build_function_type_list (integer_type_node, integer_type_node,
5288 integer_type_node, NULL_TREE);
5289 tree int_ftype_int
5290 = build_function_type_list (integer_type_node, integer_type_node,
5291 NULL_TREE);
5292 tree short_ftype_int
5293 = build_function_type_list (short_integer_type_node, integer_type_node,
5294 NULL_TREE);
5295 tree int_ftype_v2hi_v2hi
5296 = build_function_type_list (integer_type_node, V2HI_type_node,
5297 V2HI_type_node, NULL_TREE);
5298 tree v2hi_ftype_v2hi_v2hi
5299 = build_function_type_list (V2HI_type_node, V2HI_type_node,
5300 V2HI_type_node, NULL_TREE);
5301 tree v2hi_ftype_v2hi_v2hi_v2hi
5302 = build_function_type_list (V2HI_type_node, V2HI_type_node,
5303 V2HI_type_node, V2HI_type_node, NULL_TREE);
5304 tree v2hi_ftype_int_int
5305 = build_function_type_list (V2HI_type_node, integer_type_node,
5306 integer_type_node, NULL_TREE);
5307 tree v2hi_ftype_v2hi_int
5308 = build_function_type_list (V2HI_type_node, V2HI_type_node,
5309 integer_type_node, NULL_TREE);
5310 tree int_ftype_short_short
5311 = build_function_type_list (integer_type_node, short_integer_type_node,
5312 short_integer_type_node, NULL_TREE);
5313 tree v2hi_ftype_v2hi
5314 = build_function_type_list (V2HI_type_node, V2HI_type_node, NULL_TREE);
5315 tree short_ftype_v2hi
5316 = build_function_type_list (short_integer_type_node, V2HI_type_node,
5317 NULL_TREE);
8fa477f7
BS
5318 tree int_ftype_pint
5319 = build_function_type_list (integer_type_node,
5320 build_pointer_type (integer_type_node),
5321 NULL_TREE);
5322
5fcead21
BS
5323 /* Add the remaining MMX insns with somewhat more complicated types. */
5324 def_builtin ("__builtin_bfin_csync", void_ftype_void, BFIN_BUILTIN_CSYNC);
5325 def_builtin ("__builtin_bfin_ssync", void_ftype_void, BFIN_BUILTIN_SSYNC);
42da70b7 5326
1d7d5ac4
BS
5327 def_builtin ("__builtin_bfin_ones", short_ftype_int, BFIN_BUILTIN_ONES);
5328
42da70b7
BS
5329 def_builtin ("__builtin_bfin_compose_2x16", v2hi_ftype_int_int,
5330 BFIN_BUILTIN_COMPOSE_2X16);
5331 def_builtin ("__builtin_bfin_extract_hi", short_ftype_v2hi,
5332 BFIN_BUILTIN_EXTRACTHI);
5333 def_builtin ("__builtin_bfin_extract_lo", short_ftype_v2hi,
5334 BFIN_BUILTIN_EXTRACTLO);
5335
5336 def_builtin ("__builtin_bfin_min_fr2x16", v2hi_ftype_v2hi_v2hi,
5337 BFIN_BUILTIN_MIN_2X16);
5338 def_builtin ("__builtin_bfin_max_fr2x16", v2hi_ftype_v2hi_v2hi,
5339 BFIN_BUILTIN_MAX_2X16);
5340
5341 def_builtin ("__builtin_bfin_add_fr2x16", v2hi_ftype_v2hi_v2hi,
5342 BFIN_BUILTIN_SSADD_2X16);
5343 def_builtin ("__builtin_bfin_sub_fr2x16", v2hi_ftype_v2hi_v2hi,
5344 BFIN_BUILTIN_SSSUB_2X16);
5345 def_builtin ("__builtin_bfin_dspaddsubsat", v2hi_ftype_v2hi_v2hi,
5346 BFIN_BUILTIN_SSADDSUB_2X16);
5347 def_builtin ("__builtin_bfin_dspsubaddsat", v2hi_ftype_v2hi_v2hi,
5348 BFIN_BUILTIN_SSSUBADD_2X16);
5349 def_builtin ("__builtin_bfin_mult_fr2x16", v2hi_ftype_v2hi_v2hi,
5350 BFIN_BUILTIN_MULT_2X16);
5351 def_builtin ("__builtin_bfin_multr_fr2x16", v2hi_ftype_v2hi_v2hi,
5352 BFIN_BUILTIN_MULTR_2X16);
5353 def_builtin ("__builtin_bfin_negate_fr2x16", v2hi_ftype_v2hi,
5354 BFIN_BUILTIN_NEG_2X16);
5355 def_builtin ("__builtin_bfin_abs_fr2x16", v2hi_ftype_v2hi,
5356 BFIN_BUILTIN_ABS_2X16);
5357
1d7d5ac4
BS
5358 def_builtin ("__builtin_bfin_min_fr1x16", short_ftype_int_int,
5359 BFIN_BUILTIN_MIN_1X16);
5360 def_builtin ("__builtin_bfin_max_fr1x16", short_ftype_int_int,
5361 BFIN_BUILTIN_MAX_1X16);
5362
42da70b7
BS
5363 def_builtin ("__builtin_bfin_add_fr1x16", short_ftype_int_int,
5364 BFIN_BUILTIN_SSADD_1X16);
5365 def_builtin ("__builtin_bfin_sub_fr1x16", short_ftype_int_int,
5366 BFIN_BUILTIN_SSSUB_1X16);
5367 def_builtin ("__builtin_bfin_mult_fr1x16", short_ftype_int_int,
5368 BFIN_BUILTIN_MULT_1X16);
5369 def_builtin ("__builtin_bfin_multr_fr1x16", short_ftype_int_int,
5370 BFIN_BUILTIN_MULTR_1X16);
5371 def_builtin ("__builtin_bfin_negate_fr1x16", short_ftype_short,
5372 BFIN_BUILTIN_NEG_1X16);
5373 def_builtin ("__builtin_bfin_abs_fr1x16", short_ftype_short,
5374 BFIN_BUILTIN_ABS_1X16);
5375 def_builtin ("__builtin_bfin_norm_fr1x16", short_ftype_int,
5376 BFIN_BUILTIN_NORM_1X16);
5377
26c5953d
BS
5378 def_builtin ("__builtin_bfin_sum_fr2x16", short_ftype_v2hi,
5379 BFIN_BUILTIN_SUM_2X16);
42da70b7
BS
5380 def_builtin ("__builtin_bfin_diff_hl_fr2x16", short_ftype_v2hi,
5381 BFIN_BUILTIN_DIFFHL_2X16);
5382 def_builtin ("__builtin_bfin_diff_lh_fr2x16", short_ftype_v2hi,
5383 BFIN_BUILTIN_DIFFLH_2X16);
5384
5385 def_builtin ("__builtin_bfin_mulhisill", int_ftype_v2hi_v2hi,
5386 BFIN_BUILTIN_MULHISILL);
5387 def_builtin ("__builtin_bfin_mulhisihl", int_ftype_v2hi_v2hi,
5388 BFIN_BUILTIN_MULHISIHL);
5389 def_builtin ("__builtin_bfin_mulhisilh", int_ftype_v2hi_v2hi,
5390 BFIN_BUILTIN_MULHISILH);
5391 def_builtin ("__builtin_bfin_mulhisihh", int_ftype_v2hi_v2hi,
5392 BFIN_BUILTIN_MULHISIHH);
5393
1d7d5ac4
BS
5394 def_builtin ("__builtin_bfin_min_fr1x32", int_ftype_int_int,
5395 BFIN_BUILTIN_MIN_1X32);
5396 def_builtin ("__builtin_bfin_max_fr1x32", int_ftype_int_int,
5397 BFIN_BUILTIN_MAX_1X32);
5398
42da70b7
BS
5399 def_builtin ("__builtin_bfin_add_fr1x32", int_ftype_int_int,
5400 BFIN_BUILTIN_SSADD_1X32);
5401 def_builtin ("__builtin_bfin_sub_fr1x32", int_ftype_int_int,
5402 BFIN_BUILTIN_SSSUB_1X32);
5403 def_builtin ("__builtin_bfin_negate_fr1x32", int_ftype_int,
5404 BFIN_BUILTIN_NEG_1X32);
26c5953d
BS
5405 def_builtin ("__builtin_bfin_abs_fr1x32", int_ftype_int,
5406 BFIN_BUILTIN_ABS_1X32);
42da70b7
BS
5407 def_builtin ("__builtin_bfin_norm_fr1x32", short_ftype_int,
5408 BFIN_BUILTIN_NORM_1X32);
26c5953d
BS
5409 def_builtin ("__builtin_bfin_round_fr1x32", short_ftype_int,
5410 BFIN_BUILTIN_ROUND_1X32);
42da70b7
BS
5411 def_builtin ("__builtin_bfin_mult_fr1x32", int_ftype_short_short,
5412 BFIN_BUILTIN_MULT_1X32);
26c5953d
BS
5413 def_builtin ("__builtin_bfin_mult_fr1x32x32", int_ftype_int_int,
5414 BFIN_BUILTIN_MULT_1X32X32);
5415 def_builtin ("__builtin_bfin_mult_fr1x32x32NS", int_ftype_int_int,
5416 BFIN_BUILTIN_MULT_1X32X32NS);
42da70b7
BS
5417
5418 /* Shifts. */
5419 def_builtin ("__builtin_bfin_shl_fr1x16", short_ftype_int_int,
5420 BFIN_BUILTIN_SSASHIFT_1X16);
5421 def_builtin ("__builtin_bfin_shl_fr2x16", v2hi_ftype_v2hi_int,
5422 BFIN_BUILTIN_SSASHIFT_2X16);
5423 def_builtin ("__builtin_bfin_lshl_fr1x16", short_ftype_int_int,
5424 BFIN_BUILTIN_LSHIFT_1X16);
5425 def_builtin ("__builtin_bfin_lshl_fr2x16", v2hi_ftype_v2hi_int,
5426 BFIN_BUILTIN_LSHIFT_2X16);
26c5953d
BS
5427 def_builtin ("__builtin_bfin_shl_fr1x32", int_ftype_int_int,
5428 BFIN_BUILTIN_SSASHIFT_1X32);
42da70b7
BS
5429
5430 /* Complex numbers. */
1d7d5ac4
BS
5431 def_builtin ("__builtin_bfin_cmplx_add", v2hi_ftype_v2hi_v2hi,
5432 BFIN_BUILTIN_SSADD_2X16);
5433 def_builtin ("__builtin_bfin_cmplx_sub", v2hi_ftype_v2hi_v2hi,
5434 BFIN_BUILTIN_SSSUB_2X16);
42da70b7
BS
5435 def_builtin ("__builtin_bfin_cmplx_mul", v2hi_ftype_v2hi_v2hi,
5436 BFIN_BUILTIN_CPLX_MUL_16);
5437 def_builtin ("__builtin_bfin_cmplx_mac", v2hi_ftype_v2hi_v2hi_v2hi,
5438 BFIN_BUILTIN_CPLX_MAC_16);
5439 def_builtin ("__builtin_bfin_cmplx_msu", v2hi_ftype_v2hi_v2hi_v2hi,
5440 BFIN_BUILTIN_CPLX_MSU_16);
1d7d5ac4
BS
5441 def_builtin ("__builtin_bfin_cmplx_mul_s40", v2hi_ftype_v2hi_v2hi,
5442 BFIN_BUILTIN_CPLX_MUL_16_S40);
5443 def_builtin ("__builtin_bfin_cmplx_mac_s40", v2hi_ftype_v2hi_v2hi_v2hi,
5444 BFIN_BUILTIN_CPLX_MAC_16_S40);
5445 def_builtin ("__builtin_bfin_cmplx_msu_s40", v2hi_ftype_v2hi_v2hi_v2hi,
5446 BFIN_BUILTIN_CPLX_MSU_16_S40);
5447 def_builtin ("__builtin_bfin_csqu_fr16", v2hi_ftype_v2hi,
5448 BFIN_BUILTIN_CPLX_SQU);
8fa477f7
BS
5449
5450 /* "Unaligned" load. */
5451 def_builtin ("__builtin_bfin_loadbytes", int_ftype_pint,
5452 BFIN_BUILTIN_LOADBYTES);
5453
42da70b7
BS
5454}
5455
5456
5457struct builtin_description
5458{
5459 const enum insn_code icode;
5460 const char *const name;
5461 const enum bfin_builtins code;
5462 int macflag;
5463};
5464
5465static const struct builtin_description bdesc_2arg[] =
5466{
5467 { CODE_FOR_composev2hi, "__builtin_bfin_compose_2x16", BFIN_BUILTIN_COMPOSE_2X16, -1 },
5468
5469 { CODE_FOR_ssashiftv2hi3, "__builtin_bfin_shl_fr2x16", BFIN_BUILTIN_SSASHIFT_2X16, -1 },
5470 { CODE_FOR_ssashifthi3, "__builtin_bfin_shl_fr1x16", BFIN_BUILTIN_SSASHIFT_1X16, -1 },
5471 { CODE_FOR_lshiftv2hi3, "__builtin_bfin_lshl_fr2x16", BFIN_BUILTIN_LSHIFT_2X16, -1 },
5472 { CODE_FOR_lshifthi3, "__builtin_bfin_lshl_fr1x16", BFIN_BUILTIN_LSHIFT_1X16, -1 },
26c5953d 5473 { CODE_FOR_ssashiftsi3, "__builtin_bfin_shl_fr1x32", BFIN_BUILTIN_SSASHIFT_1X32, -1 },
42da70b7
BS
5474
5475 { CODE_FOR_sminhi3, "__builtin_bfin_min_fr1x16", BFIN_BUILTIN_MIN_1X16, -1 },
5476 { CODE_FOR_smaxhi3, "__builtin_bfin_max_fr1x16", BFIN_BUILTIN_MAX_1X16, -1 },
5477 { CODE_FOR_ssaddhi3, "__builtin_bfin_add_fr1x16", BFIN_BUILTIN_SSADD_1X16, -1 },
5478 { CODE_FOR_sssubhi3, "__builtin_bfin_sub_fr1x16", BFIN_BUILTIN_SSSUB_1X16, -1 },
5479
5480 { CODE_FOR_sminsi3, "__builtin_bfin_min_fr1x32", BFIN_BUILTIN_MIN_1X32, -1 },
5481 { CODE_FOR_smaxsi3, "__builtin_bfin_max_fr1x32", BFIN_BUILTIN_MAX_1X32, -1 },
5482 { CODE_FOR_ssaddsi3, "__builtin_bfin_add_fr1x32", BFIN_BUILTIN_SSADD_1X32, -1 },
5483 { CODE_FOR_sssubsi3, "__builtin_bfin_sub_fr1x32", BFIN_BUILTIN_SSSUB_1X32, -1 },
5484
5485 { CODE_FOR_sminv2hi3, "__builtin_bfin_min_fr2x16", BFIN_BUILTIN_MIN_2X16, -1 },
5486 { CODE_FOR_smaxv2hi3, "__builtin_bfin_max_fr2x16", BFIN_BUILTIN_MAX_2X16, -1 },
5487 { CODE_FOR_ssaddv2hi3, "__builtin_bfin_add_fr2x16", BFIN_BUILTIN_SSADD_2X16, -1 },
5488 { CODE_FOR_sssubv2hi3, "__builtin_bfin_sub_fr2x16", BFIN_BUILTIN_SSSUB_2X16, -1 },
5489 { CODE_FOR_ssaddsubv2hi3, "__builtin_bfin_dspaddsubsat", BFIN_BUILTIN_SSADDSUB_2X16, -1 },
5490 { CODE_FOR_sssubaddv2hi3, "__builtin_bfin_dspsubaddsat", BFIN_BUILTIN_SSSUBADD_2X16, -1 },
5491
5492 { CODE_FOR_flag_mulhisi, "__builtin_bfin_mult_fr1x32", BFIN_BUILTIN_MULT_1X32, MACFLAG_NONE },
5493 { CODE_FOR_flag_mulhi, "__builtin_bfin_mult_fr1x16", BFIN_BUILTIN_MULT_1X16, MACFLAG_T },
5494 { CODE_FOR_flag_mulhi, "__builtin_bfin_multr_fr1x16", BFIN_BUILTIN_MULTR_1X16, MACFLAG_NONE },
5495 { CODE_FOR_flag_mulv2hi, "__builtin_bfin_mult_fr2x16", BFIN_BUILTIN_MULT_2X16, MACFLAG_T },
5496 { CODE_FOR_flag_mulv2hi, "__builtin_bfin_multr_fr2x16", BFIN_BUILTIN_MULTR_2X16, MACFLAG_NONE }
5497};
5498
5499static const struct builtin_description bdesc_1arg[] =
5500{
8fa477f7
BS
5501 { CODE_FOR_loadbytes, "__builtin_bfin_loadbytes", BFIN_BUILTIN_LOADBYTES, 0 },
5502
1d7d5ac4
BS
5503 { CODE_FOR_ones, "__builtin_bfin_ones", BFIN_BUILTIN_ONES, 0 },
5504
42da70b7
BS
5505 { CODE_FOR_signbitshi2, "__builtin_bfin_norm_fr1x16", BFIN_BUILTIN_NORM_1X16, 0 },
5506 { CODE_FOR_ssneghi2, "__builtin_bfin_negate_fr1x16", BFIN_BUILTIN_NEG_1X16, 0 },
5507 { CODE_FOR_abshi2, "__builtin_bfin_abs_fr1x16", BFIN_BUILTIN_ABS_1X16, 0 },
5508
5509 { CODE_FOR_signbitssi2, "__builtin_bfin_norm_fr1x32", BFIN_BUILTIN_NORM_1X32, 0 },
26c5953d 5510 { CODE_FOR_ssroundsi2, "__builtin_bfin_round_fr1x32", BFIN_BUILTIN_ROUND_1X32, 0 },
42da70b7 5511 { CODE_FOR_ssnegsi2, "__builtin_bfin_negate_fr1x32", BFIN_BUILTIN_NEG_1X32, 0 },
26c5953d 5512 { CODE_FOR_ssabssi2, "__builtin_bfin_abs_fr1x32", BFIN_BUILTIN_ABS_1X32, 0 },
42da70b7
BS
5513
5514 { CODE_FOR_movv2hi_hi_low, "__builtin_bfin_extract_lo", BFIN_BUILTIN_EXTRACTLO, 0 },
5515 { CODE_FOR_movv2hi_hi_high, "__builtin_bfin_extract_hi", BFIN_BUILTIN_EXTRACTHI, 0 },
5516 { CODE_FOR_ssnegv2hi2, "__builtin_bfin_negate_fr2x16", BFIN_BUILTIN_NEG_2X16, 0 },
26c5953d 5517 { CODE_FOR_ssabsv2hi2, "__builtin_bfin_abs_fr2x16", BFIN_BUILTIN_ABS_2X16, 0 }
42da70b7
BS
5518};
5519
5520/* Errors in the source file can cause expand_expr to return const0_rtx
5521 where we expect a vector. To avoid crashing, use one of the vector
5522 clear instructions. */
5523static rtx
5524safe_vector_operand (rtx x, enum machine_mode mode)
5525{
5526 if (x != const0_rtx)
5527 return x;
5528 x = gen_reg_rtx (SImode);
5529
5530 emit_insn (gen_movsi (x, CONST0_RTX (SImode)));
5531 return gen_lowpart (mode, x);
5532}
5533
5534/* Subroutine of bfin_expand_builtin to take care of binop insns. MACFLAG is -1
5535 if this is a normal binary op, or one of the MACFLAG_xxx constants. */
5536
5537static rtx
5039610b 5538bfin_expand_binop_builtin (enum insn_code icode, tree exp, rtx target,
42da70b7
BS
5539 int macflag)
5540{
5541 rtx pat;
5039610b
SL
5542 tree arg0 = CALL_EXPR_ARG (exp, 0);
5543 tree arg1 = CALL_EXPR_ARG (exp, 1);
42da70b7
BS
5544 rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
5545 rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
5546 enum machine_mode op0mode = GET_MODE (op0);
5547 enum machine_mode op1mode = GET_MODE (op1);
5548 enum machine_mode tmode = insn_data[icode].operand[0].mode;
5549 enum machine_mode mode0 = insn_data[icode].operand[1].mode;
5550 enum machine_mode mode1 = insn_data[icode].operand[2].mode;
5551
5552 if (VECTOR_MODE_P (mode0))
5553 op0 = safe_vector_operand (op0, mode0);
5554 if (VECTOR_MODE_P (mode1))
5555 op1 = safe_vector_operand (op1, mode1);
5556
5557 if (! target
5558 || GET_MODE (target) != tmode
5559 || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
5560 target = gen_reg_rtx (tmode);
5561
5562 if ((op0mode == SImode || op0mode == VOIDmode) && mode0 == HImode)
5563 {
5564 op0mode = HImode;
5565 op0 = gen_lowpart (HImode, op0);
5566 }
5567 if ((op1mode == SImode || op1mode == VOIDmode) && mode1 == HImode)
5568 {
5569 op1mode = HImode;
5570 op1 = gen_lowpart (HImode, op1);
5571 }
5572 /* In case the insn wants input operands in modes different from
5573 the result, abort. */
5574 gcc_assert ((op0mode == mode0 || op0mode == VOIDmode)
5575 && (op1mode == mode1 || op1mode == VOIDmode));
5576
5577 if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
5578 op0 = copy_to_mode_reg (mode0, op0);
5579 if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
5580 op1 = copy_to_mode_reg (mode1, op1);
5581
5582 if (macflag == -1)
5583 pat = GEN_FCN (icode) (target, op0, op1);
5584 else
5585 pat = GEN_FCN (icode) (target, op0, op1, GEN_INT (macflag));
5586 if (! pat)
5587 return 0;
5588
5589 emit_insn (pat);
5590 return target;
5591}
5592
5593/* Subroutine of bfin_expand_builtin to take care of unop insns. */
5594
5595static rtx
5039610b 5596bfin_expand_unop_builtin (enum insn_code icode, tree exp,
42da70b7
BS
5597 rtx target)
5598{
5599 rtx pat;
5039610b 5600 tree arg0 = CALL_EXPR_ARG (exp, 0);
42da70b7
BS
5601 rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
5602 enum machine_mode op0mode = GET_MODE (op0);
5603 enum machine_mode tmode = insn_data[icode].operand[0].mode;
5604 enum machine_mode mode0 = insn_data[icode].operand[1].mode;
5605
5606 if (! target
5607 || GET_MODE (target) != tmode
5608 || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
5609 target = gen_reg_rtx (tmode);
5610
5611 if (VECTOR_MODE_P (mode0))
5612 op0 = safe_vector_operand (op0, mode0);
5613
5614 if (op0mode == SImode && mode0 == HImode)
5615 {
5616 op0mode = HImode;
5617 op0 = gen_lowpart (HImode, op0);
5618 }
5619 gcc_assert (op0mode == mode0 || op0mode == VOIDmode);
5620
5621 if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
5622 op0 = copy_to_mode_reg (mode0, op0);
5623
5624 pat = GEN_FCN (icode) (target, op0);
5625 if (! pat)
5626 return 0;
5627 emit_insn (pat);
5628 return target;
5fcead21
BS
5629}
5630
5631/* Expand an expression EXP that calls a built-in function,
5632 with result going to TARGET if that's convenient
5633 (and in mode MODE if that's convenient).
5634 SUBTARGET may be used as the target for computing one of EXP's operands.
5635 IGNORE is nonzero if the value is to be ignored. */
5636
5637static rtx
5638bfin_expand_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
5639 rtx subtarget ATTRIBUTE_UNUSED,
5640 enum machine_mode mode ATTRIBUTE_UNUSED,
5641 int ignore ATTRIBUTE_UNUSED)
5642{
42da70b7
BS
5643 size_t i;
5644 enum insn_code icode;
5645 const struct builtin_description *d;
5039610b 5646 tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
5fcead21 5647 unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
42da70b7 5648 tree arg0, arg1, arg2;
26c5953d 5649 rtx op0, op1, op2, accvec, pat, tmp1, tmp2, a0reg, a1reg;
42da70b7 5650 enum machine_mode tmode, mode0;
5fcead21
BS
5651
5652 switch (fcode)
5653 {
5654 case BFIN_BUILTIN_CSYNC:
5655 emit_insn (gen_csync ());
5656 return 0;
5657 case BFIN_BUILTIN_SSYNC:
5658 emit_insn (gen_ssync ());
5659 return 0;
5660
42da70b7
BS
5661 case BFIN_BUILTIN_DIFFHL_2X16:
5662 case BFIN_BUILTIN_DIFFLH_2X16:
26c5953d 5663 case BFIN_BUILTIN_SUM_2X16:
5039610b 5664 arg0 = CALL_EXPR_ARG (exp, 0);
42da70b7 5665 op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
26c5953d
BS
5666 icode = (fcode == BFIN_BUILTIN_DIFFHL_2X16 ? CODE_FOR_subhilov2hi3
5667 : fcode == BFIN_BUILTIN_DIFFLH_2X16 ? CODE_FOR_sublohiv2hi3
5668 : CODE_FOR_ssaddhilov2hi3);
42da70b7
BS
5669 tmode = insn_data[icode].operand[0].mode;
5670 mode0 = insn_data[icode].operand[1].mode;
5671
5672 if (! target
5673 || GET_MODE (target) != tmode
5674 || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
5675 target = gen_reg_rtx (tmode);
5676
5677 if (VECTOR_MODE_P (mode0))
5678 op0 = safe_vector_operand (op0, mode0);
5679
5680 if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
5681 op0 = copy_to_mode_reg (mode0, op0);
5682
5683 pat = GEN_FCN (icode) (target, op0, op0);
5684 if (! pat)
5685 return 0;
5686 emit_insn (pat);
5687 return target;
5688
26c5953d
BS
5689 case BFIN_BUILTIN_MULT_1X32X32:
5690 case BFIN_BUILTIN_MULT_1X32X32NS:
5691 arg0 = CALL_EXPR_ARG (exp, 0);
5692 arg1 = CALL_EXPR_ARG (exp, 1);
5693 op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
5694 op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
5695 if (! target
5696 || !register_operand (target, SImode))
5697 target = gen_reg_rtx (SImode);
5698
5699 a1reg = gen_rtx_REG (PDImode, REG_A1);
5700 a0reg = gen_rtx_REG (PDImode, REG_A0);
5701 tmp1 = gen_lowpart (V2HImode, op0);
5702 tmp2 = gen_lowpart (V2HImode, op1);
5703 emit_insn (gen_flag_macinit1hi (a1reg,
5704 gen_lowpart (HImode, op0),
5705 gen_lowpart (HImode, op1),
5706 GEN_INT (MACFLAG_FU)));
5707 emit_insn (gen_lshrpdi3 (a1reg, a1reg, GEN_INT (16)));
5708
5709 if (fcode == BFIN_BUILTIN_MULT_1X32X32)
5710 emit_insn (gen_flag_mul_macv2hi_parts_acconly (a0reg, a1reg, tmp1, tmp2,
5711 const1_rtx, const1_rtx,
5712 const1_rtx, const0_rtx, a1reg,
5713 const0_rtx, GEN_INT (MACFLAG_NONE),
5714 GEN_INT (MACFLAG_M)));
5715 else
5716 {
5717 /* For saturating multiplication, there's exactly one special case
5718 to be handled: multiplying the smallest negative value with
5719 itself. Due to shift correction in fractional multiplies, this
5720 can overflow. Iff this happens, OP2 will contain 1, which, when
5721 added in 32 bits to the smallest negative, wraps to the largest
5722 positive, which is the result we want. */
5723 op2 = gen_reg_rtx (V2HImode);
5724 emit_insn (gen_packv2hi (op2, tmp1, tmp2, const0_rtx, const0_rtx));
5725 emit_insn (gen_movsibi (gen_rtx_REG (BImode, REG_CC),
5726 gen_lowpart (SImode, op2)));
5727 emit_insn (gen_flag_mul_macv2hi_parts_acconly_andcc0 (a0reg, a1reg, tmp1, tmp2,
5728 const1_rtx, const1_rtx,
5729 const1_rtx, const0_rtx, a1reg,
5730 const0_rtx, GEN_INT (MACFLAG_NONE),
5731 GEN_INT (MACFLAG_M)));
5732 op2 = gen_reg_rtx (SImode);
5733 emit_insn (gen_movbisi (op2, gen_rtx_REG (BImode, REG_CC)));
5734 }
5735 emit_insn (gen_flag_machi_parts_acconly (a1reg, tmp2, tmp1,
5736 const1_rtx, const0_rtx,
5737 a1reg, const0_rtx, GEN_INT (MACFLAG_M)));
5738 emit_insn (gen_ashrpdi3 (a1reg, a1reg, GEN_INT (15)));
5739 emit_insn (gen_sum_of_accumulators (target, a0reg, a0reg, a1reg));
5740 if (fcode == BFIN_BUILTIN_MULT_1X32X32NS)
5741 emit_insn (gen_addsi3 (target, target, op2));
5742 return target;
5743
42da70b7 5744 case BFIN_BUILTIN_CPLX_MUL_16:
1d7d5ac4 5745 case BFIN_BUILTIN_CPLX_MUL_16_S40:
5039610b
SL
5746 arg0 = CALL_EXPR_ARG (exp, 0);
5747 arg1 = CALL_EXPR_ARG (exp, 1);
42da70b7
BS
5748 op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
5749 op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
5750 accvec = gen_reg_rtx (V2PDImode);
5751
5752 if (! target
5753 || GET_MODE (target) != V2HImode
5754 || ! (*insn_data[icode].operand[0].predicate) (target, V2HImode))
5755 target = gen_reg_rtx (tmode);
5756 if (! register_operand (op0, GET_MODE (op0)))
5757 op0 = copy_to_mode_reg (GET_MODE (op0), op0);
5758 if (! register_operand (op1, GET_MODE (op1)))
5759 op1 = copy_to_mode_reg (GET_MODE (op1), op1);
5760
1d7d5ac4
BS
5761 if (fcode == BFIN_BUILTIN_CPLX_MUL_16)
5762 emit_insn (gen_flag_macinit1v2hi_parts (accvec, op0, op1, const0_rtx,
5763 const0_rtx, const0_rtx,
5764 const1_rtx, GEN_INT (MACFLAG_W32)));
5765 else
5766 emit_insn (gen_flag_macinit1v2hi_parts (accvec, op0, op1, const0_rtx,
5767 const0_rtx, const0_rtx,
5768 const1_rtx, GEN_INT (MACFLAG_NONE)));
42da70b7
BS
5769 emit_insn (gen_flag_macv2hi_parts (target, op0, op1, const1_rtx,
5770 const1_rtx, const1_rtx,
5771 const0_rtx, accvec, const1_rtx, const0_rtx,
5772 GEN_INT (MACFLAG_NONE), accvec));
5773
5774 return target;
5775
5776 case BFIN_BUILTIN_CPLX_MAC_16:
5777 case BFIN_BUILTIN_CPLX_MSU_16:
1d7d5ac4
BS
5778 case BFIN_BUILTIN_CPLX_MAC_16_S40:
5779 case BFIN_BUILTIN_CPLX_MSU_16_S40:
5039610b
SL
5780 arg0 = CALL_EXPR_ARG (exp, 0);
5781 arg1 = CALL_EXPR_ARG (exp, 1);
5782 arg2 = CALL_EXPR_ARG (exp, 2);
42da70b7
BS
5783 op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
5784 op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
5785 op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
5786 accvec = gen_reg_rtx (V2PDImode);
5787
5788 if (! target
5789 || GET_MODE (target) != V2HImode
5790 || ! (*insn_data[icode].operand[0].predicate) (target, V2HImode))
5791 target = gen_reg_rtx (tmode);
42da70b7
BS
5792 if (! register_operand (op1, GET_MODE (op1)))
5793 op1 = copy_to_mode_reg (GET_MODE (op1), op1);
48ccf012
JZ
5794 if (! register_operand (op2, GET_MODE (op2)))
5795 op2 = copy_to_mode_reg (GET_MODE (op2), op2);
42da70b7
BS
5796
5797 tmp1 = gen_reg_rtx (SImode);
5798 tmp2 = gen_reg_rtx (SImode);
48ccf012
JZ
5799 emit_insn (gen_ashlsi3 (tmp1, gen_lowpart (SImode, op0), GEN_INT (16)));
5800 emit_move_insn (tmp2, gen_lowpart (SImode, op0));
42da70b7
BS
5801 emit_insn (gen_movstricthi_1 (gen_lowpart (HImode, tmp2), const0_rtx));
5802 emit_insn (gen_load_accumulator_pair (accvec, tmp1, tmp2));
1d7d5ac4
BS
5803 if (fcode == BFIN_BUILTIN_CPLX_MAC_16
5804 || fcode == BFIN_BUILTIN_CPLX_MSU_16)
5805 emit_insn (gen_flag_macv2hi_parts_acconly (accvec, op1, op2, const0_rtx,
5806 const0_rtx, const0_rtx,
5807 const1_rtx, accvec, const0_rtx,
5808 const0_rtx,
5809 GEN_INT (MACFLAG_W32)));
5810 else
5811 emit_insn (gen_flag_macv2hi_parts_acconly (accvec, op1, op2, const0_rtx,
5812 const0_rtx, const0_rtx,
5813 const1_rtx, accvec, const0_rtx,
5814 const0_rtx,
5815 GEN_INT (MACFLAG_NONE)));
5816 if (fcode == BFIN_BUILTIN_CPLX_MAC_16
5817 || fcode == BFIN_BUILTIN_CPLX_MAC_16_S40)
5818 {
5819 tmp1 = const1_rtx;
5820 tmp2 = const0_rtx;
5821 }
5822 else
5823 {
5824 tmp1 = const0_rtx;
5825 tmp2 = const1_rtx;
5826 }
48ccf012 5827 emit_insn (gen_flag_macv2hi_parts (target, op1, op2, const1_rtx,
42da70b7
BS
5828 const1_rtx, const1_rtx,
5829 const0_rtx, accvec, tmp1, tmp2,
5830 GEN_INT (MACFLAG_NONE), accvec));
5831
5832 return target;
5833
1d7d5ac4
BS
5834 case BFIN_BUILTIN_CPLX_SQU:
5835 arg0 = CALL_EXPR_ARG (exp, 0);
5836 op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
5837 accvec = gen_reg_rtx (V2PDImode);
5838 icode = CODE_FOR_flag_mulv2hi;
5839 tmp1 = gen_reg_rtx (V2HImode);
5840 tmp2 = gen_reg_rtx (V2HImode);
5841
5842 if (! target
5843 || GET_MODE (target) != V2HImode
5844 || ! (*insn_data[icode].operand[0].predicate) (target, V2HImode))
5845 target = gen_reg_rtx (V2HImode);
5846 if (! register_operand (op0, GET_MODE (op0)))
5847 op0 = copy_to_mode_reg (GET_MODE (op0), op0);
5848
5849 emit_insn (gen_flag_mulv2hi (tmp1, op0, op0, GEN_INT (MACFLAG_NONE)));
5850
5851 emit_insn (gen_flag_mulhi_parts (tmp2, op0, op0, const0_rtx,
5852 const0_rtx, const1_rtx,
5853 GEN_INT (MACFLAG_NONE)));
5854
5855 emit_insn (gen_ssaddhi3_parts (target, tmp2, tmp2, const1_rtx,
5856 const0_rtx, const0_rtx));
5857
5858 emit_insn (gen_sssubhi3_parts (target, tmp1, tmp1, const0_rtx,
5859 const0_rtx, const1_rtx));
5860
5861 return target;
5862
5fcead21 5863 default:
42da70b7 5864 break;
5fcead21 5865 }
42da70b7
BS
5866
5867 for (i = 0, d = bdesc_2arg; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
5868 if (d->code == fcode)
5039610b 5869 return bfin_expand_binop_builtin (d->icode, exp, target,
42da70b7
BS
5870 d->macflag);
5871
5872 for (i = 0, d = bdesc_1arg; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
5873 if (d->code == fcode)
5039610b 5874 return bfin_expand_unop_builtin (d->icode, exp, target);
42da70b7
BS
5875
5876 gcc_unreachable ();
5fcead21
BS
5877}
5878\f
5879#undef TARGET_INIT_BUILTINS
5880#define TARGET_INIT_BUILTINS bfin_init_builtins
5881
5882#undef TARGET_EXPAND_BUILTIN
5883#define TARGET_EXPAND_BUILTIN bfin_expand_builtin
5884
0d4a78eb
BS
5885#undef TARGET_ASM_GLOBALIZE_LABEL
5886#define TARGET_ASM_GLOBALIZE_LABEL bfin_globalize_label
5887
5888#undef TARGET_ASM_FILE_START
5889#define TARGET_ASM_FILE_START output_file_start
5890
5891#undef TARGET_ATTRIBUTE_TABLE
5892#define TARGET_ATTRIBUTE_TABLE bfin_attribute_table
5893
5894#undef TARGET_COMP_TYPE_ATTRIBUTES
5895#define TARGET_COMP_TYPE_ATTRIBUTES bfin_comp_type_attributes
5896
5897#undef TARGET_RTX_COSTS
5898#define TARGET_RTX_COSTS bfin_rtx_costs
5899
5900#undef TARGET_ADDRESS_COST
5901#define TARGET_ADDRESS_COST bfin_address_cost
5902
6614f9f5
BS
5903#undef TARGET_ASM_INTEGER
5904#define TARGET_ASM_INTEGER bfin_assemble_integer
5905
0d4a78eb
BS
5906#undef TARGET_MACHINE_DEPENDENT_REORG
5907#define TARGET_MACHINE_DEPENDENT_REORG bfin_reorg
5908
5909#undef TARGET_FUNCTION_OK_FOR_SIBCALL
5910#define TARGET_FUNCTION_OK_FOR_SIBCALL bfin_function_ok_for_sibcall
5911
5912#undef TARGET_ASM_OUTPUT_MI_THUNK
5913#define TARGET_ASM_OUTPUT_MI_THUNK bfin_output_mi_thunk
5914#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
3101faab 5915#define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true
0d4a78eb
BS
5916
5917#undef TARGET_SCHED_ADJUST_COST
5918#define TARGET_SCHED_ADJUST_COST bfin_adjust_cost
5919
36662eb1
BS
5920#undef TARGET_SCHED_ISSUE_RATE
5921#define TARGET_SCHED_ISSUE_RATE bfin_issue_rate
5922
0d4a78eb 5923#undef TARGET_PROMOTE_PROTOTYPES
586de218 5924#define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
0d4a78eb 5925#undef TARGET_PROMOTE_FUNCTION_ARGS
586de218 5926#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_const_tree_true
0d4a78eb 5927#undef TARGET_PROMOTE_FUNCTION_RETURN
586de218 5928#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_const_tree_true
0d4a78eb
BS
5929
5930#undef TARGET_ARG_PARTIAL_BYTES
5931#define TARGET_ARG_PARTIAL_BYTES bfin_arg_partial_bytes
5932
5933#undef TARGET_PASS_BY_REFERENCE
5934#define TARGET_PASS_BY_REFERENCE bfin_pass_by_reference
5935
5936#undef TARGET_SETUP_INCOMING_VARARGS
5937#define TARGET_SETUP_INCOMING_VARARGS setup_incoming_varargs
5938
5939#undef TARGET_STRUCT_VALUE_RTX
5940#define TARGET_STRUCT_VALUE_RTX bfin_struct_value_rtx
5941
5942#undef TARGET_VECTOR_MODE_SUPPORTED_P
5943#define TARGET_VECTOR_MODE_SUPPORTED_P bfin_vector_mode_supported_p
5944
f02a5d0e
BS
5945#undef TARGET_HANDLE_OPTION
5946#define TARGET_HANDLE_OPTION bfin_handle_option
5947
3fb192d2
BS
5948#undef TARGET_DEFAULT_TARGET_FLAGS
5949#define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
5950
e97f2058
BS
5951#undef TARGET_SECONDARY_RELOAD
5952#define TARGET_SECONDARY_RELOAD bfin_secondary_reload
5953
54aefc36
JZ
5954#undef TARGET_DELEGITIMIZE_ADDRESS
5955#define TARGET_DELEGITIMIZE_ADDRESS bfin_delegitimize_address
5956
d6f6753e
BS
5957#undef TARGET_CANNOT_FORCE_CONST_MEM
5958#define TARGET_CANNOT_FORCE_CONST_MEM bfin_cannot_force_const_mem
5959
7ba20e60
BS
5960#undef TARGET_RETURN_IN_MEMORY
5961#define TARGET_RETURN_IN_MEMORY bfin_return_in_memory
5962
0d4a78eb 5963struct gcc_target targetm = TARGET_INITIALIZER;