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