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