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