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