]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/config/bfin/bfin.c
* decl.c, dump-parse-tree.c, gfortran.texi, intrinsic.texi,
[thirdparty/gcc.git] / gcc / config / bfin / bfin.c
CommitLineData
fe24f256 1/* The Blackfin code generation auxiliary output file.
9e6a0967 2 Copyright (C) 2005 Free Software Foundation, Inc.
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"
46#include "ggc.h"
47#include "integrate.h"
684389d2 48#include "langhooks.h"
9e6a0967 49#include "bfin-protos.h"
50#include "tm-preds.h"
51#include "gt-bfin.h"
52
53/* Test and compare insns in bfin.md store the information needed to
54 generate branch and scc insns here. */
55rtx bfin_compare_op0, bfin_compare_op1;
56
57/* RTX for condition code flag register and RETS register */
58extern GTY(()) rtx bfin_cc_rtx;
59extern GTY(()) rtx bfin_rets_rtx;
60rtx bfin_cc_rtx, bfin_rets_rtx;
61
62int max_arg_registers = 0;
63
64/* Arrays used when emitting register names. */
65const char *short_reg_names[] = SHORT_REGISTER_NAMES;
66const char *high_reg_names[] = HIGH_REGISTER_NAMES;
67const char *dregs_pair_names[] = DREGS_PAIR_NAMES;
68const char *byte_reg_names[] = BYTE_REGISTER_NAMES;
69
70static int arg_regs[] = FUNCTION_ARG_REGISTERS;
71
354bd282 72/* Nonzero if -mshared-library-id was given. */
73static int bfin_lib_id_given;
9e6a0967 74
75static void
76bfin_globalize_label (FILE *stream, const char *name)
77{
78 fputs (".global ", stream);
79 assemble_name (stream, name);
80 fputc (';',stream);
81 fputc ('\n',stream);
82}
83
84static void
85output_file_start (void)
86{
87 FILE *file = asm_out_file;
88 int i;
89
90 fprintf (file, ".file \"%s\";\n", input_filename);
91
92 for (i = 0; arg_regs[i] >= 0; i++)
93 ;
94 max_arg_registers = i; /* how many arg reg used */
95}
96
97/* Called early in the compilation to conditionally modify
98 fixed_regs/call_used_regs. */
99
100void
101conditional_register_usage (void)
102{
103 /* initialize condition code flag register rtx */
104 bfin_cc_rtx = gen_rtx_REG (BImode, REG_CC);
105 bfin_rets_rtx = gen_rtx_REG (Pmode, REG_RETS);
106}
107
108/* Examine machine-dependent attributes of function type FUNTYPE and return its
109 type. See the definition of E_FUNKIND. */
110
111static e_funkind funkind (tree funtype)
112{
113 tree attrs = TYPE_ATTRIBUTES (funtype);
114 if (lookup_attribute ("interrupt_handler", attrs))
115 return INTERRUPT_HANDLER;
116 else if (lookup_attribute ("exception_handler", attrs))
117 return EXCPT_HANDLER;
118 else if (lookup_attribute ("nmi_handler", attrs))
119 return NMI_HANDLER;
120 else
121 return SUBROUTINE;
122}
123\f
b90ce3c3 124/* Legitimize PIC addresses. If the address is already position-independent,
125 we return ORIG. Newly generated position-independent addresses go into a
126 reg. This is REG if nonzero, otherwise we allocate register(s) as
127 necessary. PICREG is the register holding the pointer to the PIC offset
128 table. */
129
130rtx
131legitimize_pic_address (rtx orig, rtx reg, rtx picreg)
132{
133 rtx addr = orig;
134 rtx new = orig;
135
136 if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == LABEL_REF)
137 {
138 if (GET_CODE (addr) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (addr))
139 reg = new = orig;
140 else
141 {
142 if (reg == 0)
143 {
144 gcc_assert (!no_new_pseudos);
145 reg = gen_reg_rtx (Pmode);
146 }
147
148 if (flag_pic == 2)
149 {
150 emit_insn (gen_movsi_high_pic (reg, addr));
151 emit_insn (gen_movsi_low_pic (reg, reg, addr));
152 emit_insn (gen_addsi3 (reg, reg, picreg));
153 new = gen_rtx_MEM (Pmode, reg);
154 }
155 else
156 {
157 rtx tmp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr),
158 UNSPEC_MOVE_PIC);
159 new = gen_rtx_MEM (Pmode,
160 gen_rtx_PLUS (Pmode, picreg, tmp));
161 }
162 emit_move_insn (reg, new);
163 }
164 if (picreg == pic_offset_table_rtx)
165 current_function_uses_pic_offset_table = 1;
166 return reg;
167 }
168
169 else if (GET_CODE (addr) == CONST || GET_CODE (addr) == PLUS)
170 {
171 rtx base;
172
173 if (GET_CODE (addr) == CONST)
174 {
175 addr = XEXP (addr, 0);
176 gcc_assert (GET_CODE (addr) == PLUS);
177 }
178
179 if (XEXP (addr, 0) == picreg)
180 return orig;
181
182 if (reg == 0)
183 {
184 gcc_assert (!no_new_pseudos);
185 reg = gen_reg_rtx (Pmode);
186 }
187
188 base = legitimize_pic_address (XEXP (addr, 0), reg, picreg);
189 addr = legitimize_pic_address (XEXP (addr, 1),
190 base == reg ? NULL_RTX : reg,
191 picreg);
192
193 if (GET_CODE (addr) == CONST_INT)
194 {
195 gcc_assert (! reload_in_progress && ! reload_completed);
196 addr = force_reg (Pmode, addr);
197 }
198
199 if (GET_CODE (addr) == PLUS && CONSTANT_P (XEXP (addr, 1)))
200 {
201 base = gen_rtx_PLUS (Pmode, base, XEXP (addr, 0));
202 addr = XEXP (addr, 1);
203 }
204
205 return gen_rtx_PLUS (Pmode, base, addr);
206 }
207
208 return new;
209}
210\f
9e6a0967 211/* Stack frame layout. */
212
213/* Compute the number of DREGS to save with a push_multiple operation.
214 This could include registers that aren't modified in the function,
215 since push_multiple only takes a range of registers. */
216
217static int
218n_dregs_to_save (void)
219{
220 unsigned i;
221
222 for (i = REG_R0; i <= REG_R7; i++)
223 {
224 if (regs_ever_live[i] && ! call_used_regs[i])
225 return REG_R7 - i + 1;
226
227 if (current_function_calls_eh_return)
228 {
229 unsigned j;
230 for (j = 0; ; j++)
231 {
232 unsigned test = EH_RETURN_DATA_REGNO (j);
233 if (test == INVALID_REGNUM)
234 break;
235 if (test == i)
236 return REG_R7 - i + 1;
237 }
238 }
239
240 }
241 return 0;
242}
243
244/* Like n_dregs_to_save, but compute number of PREGS to save. */
245
246static int
247n_pregs_to_save (void)
248{
249 unsigned i;
250
251 for (i = REG_P0; i <= REG_P5; i++)
252 if ((regs_ever_live[i] && ! call_used_regs[i])
253 || (i == PIC_OFFSET_TABLE_REGNUM
254 && (current_function_uses_pic_offset_table
255 || (TARGET_ID_SHARED_LIBRARY && ! current_function_is_leaf))))
256 return REG_P5 - i + 1;
257 return 0;
258}
259
260/* Determine if we are going to save the frame pointer in the prologue. */
261
262static bool
263must_save_fp_p (void)
264{
265 return (frame_pointer_needed || regs_ever_live[REG_FP]);
266}
267
268static bool
269stack_frame_needed_p (void)
270{
271 /* EH return puts a new return address into the frame using an
272 address relative to the frame pointer. */
273 if (current_function_calls_eh_return)
274 return true;
275 return frame_pointer_needed;
276}
277
278/* Emit code to save registers in the prologue. SAVEALL is nonzero if we
279 must save all registers; this is used for interrupt handlers.
280 SPREG contains (reg:SI REG_SP). */
281
282static void
283expand_prologue_reg_save (rtx spreg, int saveall)
284{
285 int ndregs = saveall ? 8 : n_dregs_to_save ();
286 int npregs = saveall ? 6 : n_pregs_to_save ();
287 int dregno = REG_R7 + 1 - ndregs;
288 int pregno = REG_P5 + 1 - npregs;
289 int total = ndregs + npregs;
290 int i;
291 rtx pat, insn, val;
292
293 if (total == 0)
294 return;
295
296 val = GEN_INT (-total * 4);
297 pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total + 2));
298 XVECEXP (pat, 0, 0) = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, val),
299 UNSPEC_PUSH_MULTIPLE);
300 XVECEXP (pat, 0, total + 1) = gen_rtx_SET (VOIDmode, spreg,
301 gen_rtx_PLUS (Pmode, spreg,
302 val));
303 RTX_FRAME_RELATED_P (XVECEXP (pat, 0, total + 1)) = 1;
304 for (i = 0; i < total; i++)
305 {
306 rtx memref = gen_rtx_MEM (word_mode,
307 gen_rtx_PLUS (Pmode, spreg,
308 GEN_INT (- i * 4 - 4)));
309 rtx subpat;
310 if (ndregs > 0)
311 {
312 subpat = gen_rtx_SET (VOIDmode, memref, gen_rtx_REG (word_mode,
313 dregno++));
314 ndregs--;
315 }
316 else
317 {
318 subpat = gen_rtx_SET (VOIDmode, memref, gen_rtx_REG (word_mode,
319 pregno++));
320 npregs++;
321 }
322 XVECEXP (pat, 0, i + 1) = subpat;
323 RTX_FRAME_RELATED_P (subpat) = 1;
324 }
325 insn = emit_insn (pat);
326 RTX_FRAME_RELATED_P (insn) = 1;
327}
328
329/* Emit code to restore registers in the epilogue. SAVEALL is nonzero if we
330 must save all registers; this is used for interrupt handlers.
331 SPREG contains (reg:SI REG_SP). */
332
333static void
334expand_epilogue_reg_restore (rtx spreg, int saveall)
335{
336 int ndregs = saveall ? 8 : n_dregs_to_save ();
337 int npregs = saveall ? 6 : n_pregs_to_save ();
338 int total = ndregs + npregs;
339 int i, regno;
340 rtx pat, insn;
341
342 if (total == 0)
343 return;
344
345 pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total + 1));
346 XVECEXP (pat, 0, 0) = gen_rtx_SET (VOIDmode, spreg,
347 gen_rtx_PLUS (Pmode, spreg,
348 GEN_INT (total * 4)));
349
350 if (npregs > 0)
351 regno = REG_P5 + 1;
352 else
353 regno = REG_R7 + 1;
354
355 for (i = 0; i < total; i++)
356 {
357 rtx addr = (i > 0
358 ? gen_rtx_PLUS (Pmode, spreg, GEN_INT (i * 4))
359 : spreg);
360 rtx memref = gen_rtx_MEM (word_mode, addr);
361
362 regno--;
363 XVECEXP (pat, 0, i + 1)
364 = gen_rtx_SET (VOIDmode, gen_rtx_REG (word_mode, regno), memref);
365
366 if (npregs > 0)
367 {
368 if (--npregs == 0)
369 regno = REG_R7 + 1;
370 }
371 }
372
373 insn = emit_insn (pat);
374 RTX_FRAME_RELATED_P (insn) = 1;
375}
376
377/* Perform any needed actions needed for a function that is receiving a
378 variable number of arguments.
379
380 CUM is as above.
381
382 MODE and TYPE are the mode and type of the current parameter.
383
384 PRETEND_SIZE is a variable that should be set to the amount of stack
385 that must be pushed by the prolog to pretend that our caller pushed
386 it.
387
388 Normally, this macro will push all remaining incoming registers on the
389 stack and set PRETEND_SIZE to the length of the registers pushed.
390
391 Blackfin specific :
392 - VDSP C compiler manual (our ABI) says that a variable args function
393 should save the R0, R1 and R2 registers in the stack.
394 - The caller will always leave space on the stack for the
395 arguments that are passed in registers, so we dont have
396 to leave any extra space.
397 - now, the vastart pointer can access all arguments from the stack. */
398
399static void
400setup_incoming_varargs (CUMULATIVE_ARGS *cum,
401 enum machine_mode mode ATTRIBUTE_UNUSED,
402 tree type ATTRIBUTE_UNUSED, int *pretend_size,
403 int no_rtl)
404{
405 rtx mem;
406 int i;
407
408 if (no_rtl)
409 return;
410
411 /* The move for named arguments will be generated automatically by the
412 compiler. We need to generate the move rtx for the unnamed arguments
fe24f256 413 if they are in the first 3 words. We assume at least 1 named argument
9e6a0967 414 exists, so we never generate [ARGP] = R0 here. */
415
416 for (i = cum->words + 1; i < max_arg_registers; i++)
417 {
418 mem = gen_rtx_MEM (Pmode,
419 plus_constant (arg_pointer_rtx, (i * UNITS_PER_WORD)));
420 emit_move_insn (mem, gen_rtx_REG (Pmode, i));
421 }
422
423 *pretend_size = 0;
424}
425
426/* Value should be nonzero if functions must have frame pointers.
427 Zero means the frame pointer need not be set up (and parms may
428 be accessed via the stack pointer) in functions that seem suitable. */
429
430int
431bfin_frame_pointer_required (void)
432{
433 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
434
435 if (fkind != SUBROUTINE)
436 return 1;
437
438 /* We turn on on -fomit-frame-pointer if -momit-leaf-frame-pointer is used,
439 so we have to override it for non-leaf functions. */
440 if (TARGET_OMIT_LEAF_FRAME_POINTER && ! current_function_is_leaf)
441 return 1;
442
443 return 0;
444}
445
446/* Return the number of registers pushed during the prologue. */
447
448static int
449n_regs_saved_by_prologue (void)
450{
451 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
452 int n = n_dregs_to_save () + n_pregs_to_save ();
453
454 if (stack_frame_needed_p ())
455 /* We use a LINK instruction in this case. */
456 n += 2;
457 else
458 {
459 if (must_save_fp_p ())
460 n++;
461 if (! current_function_is_leaf)
462 n++;
463 }
464
465 if (fkind != SUBROUTINE)
466 {
467 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
468 tree all = lookup_attribute ("saveall", attrs);
469 int i;
470
471 /* Increment once for ASTAT. */
472 n++;
473
474 /* RETE/X/N. */
475 if (lookup_attribute ("nesting", attrs))
476 n++;
477
478 for (i = REG_P7 + 1; i < REG_CC; i++)
479 if (all
480 || regs_ever_live[i]
481 || (!leaf_function_p () && call_used_regs[i]))
482 n += i == REG_A0 || i == REG_A1 ? 2 : 1;
483 }
484 return n;
485}
486
487/* Return the offset between two registers, one to be eliminated, and the other
488 its replacement, at the start of a routine. */
489
490HOST_WIDE_INT
491bfin_initial_elimination_offset (int from, int to)
492{
493 HOST_WIDE_INT offset = 0;
494
495 if (from == ARG_POINTER_REGNUM)
496 offset = n_regs_saved_by_prologue () * 4;
497
498 if (to == STACK_POINTER_REGNUM)
499 {
500 if (current_function_outgoing_args_size >= FIXED_STACK_AREA)
501 offset += current_function_outgoing_args_size;
502 else if (current_function_outgoing_args_size)
503 offset += FIXED_STACK_AREA;
504
505 offset += get_frame_size ();
506 }
507
508 return offset;
509}
510
511/* Emit code to load a constant CONSTANT into register REG; setting
b90ce3c3 512 RTX_FRAME_RELATED_P on all insns we generate if RELATED is true.
513 Make sure that the insns we generate need not be split. */
9e6a0967 514
515static void
b90ce3c3 516frame_related_constant_load (rtx reg, HOST_WIDE_INT constant, bool related)
9e6a0967 517{
518 rtx insn;
519 rtx cst = GEN_INT (constant);
520
521 if (constant >= -32768 && constant < 65536)
522 insn = emit_move_insn (reg, cst);
523 else
524 {
525 /* We don't call split_load_immediate here, since dwarf2out.c can get
526 confused about some of the more clever sequences it can generate. */
527 insn = emit_insn (gen_movsi_high (reg, cst));
b90ce3c3 528 if (related)
529 RTX_FRAME_RELATED_P (insn) = 1;
9e6a0967 530 insn = emit_insn (gen_movsi_low (reg, reg, cst));
531 }
b90ce3c3 532 if (related)
533 RTX_FRAME_RELATED_P (insn) = 1;
9e6a0967 534}
535
536/* Generate efficient code to add a value to the frame pointer. We
537 can use P1 as a scratch register. Set RTX_FRAME_RELATED_P on the
538 generated insns if FRAME is nonzero. */
539
540static void
541add_to_sp (rtx spreg, HOST_WIDE_INT value, int frame)
542{
543 if (value == 0)
544 return;
545
546 /* Choose whether to use a sequence using a temporary register, or
547 a sequence with multiple adds. We can add a signed 7 bit value
548 in one instruction. */
549 if (value > 120 || value < -120)
550 {
551 rtx tmpreg = gen_rtx_REG (SImode, REG_P1);
552 rtx insn;
553
554 if (frame)
b90ce3c3 555 frame_related_constant_load (tmpreg, value, TRUE);
9e6a0967 556 else
557 {
558 insn = emit_move_insn (tmpreg, GEN_INT (value));
559 if (frame)
560 RTX_FRAME_RELATED_P (insn) = 1;
561 }
562
563 insn = emit_insn (gen_addsi3 (spreg, spreg, tmpreg));
564 if (frame)
565 RTX_FRAME_RELATED_P (insn) = 1;
566 }
567 else
568 do
569 {
570 int size = value;
571 rtx insn;
572
573 if (size > 60)
574 size = 60;
575 else if (size < -60)
576 /* We could use -62, but that would leave the stack unaligned, so
577 it's no good. */
578 size = -60;
579
580 insn = emit_insn (gen_addsi3 (spreg, spreg, GEN_INT (size)));
581 if (frame)
582 RTX_FRAME_RELATED_P (insn) = 1;
583 value -= size;
584 }
585 while (value != 0);
586}
587
588/* Generate a LINK insn for a frame sized FRAME_SIZE. If this constant
589 is too large, generate a sequence of insns that has the same effect.
590 SPREG contains (reg:SI REG_SP). */
591
592static void
593emit_link_insn (rtx spreg, HOST_WIDE_INT frame_size)
594{
595 HOST_WIDE_INT link_size = frame_size;
596 rtx insn;
597 int i;
598
599 if (link_size > 262140)
600 link_size = 262140;
601
602 /* Use a LINK insn with as big a constant as possible, then subtract
603 any remaining size from the SP. */
604 insn = emit_insn (gen_link (GEN_INT (-8 - link_size)));
605 RTX_FRAME_RELATED_P (insn) = 1;
606
607 for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
608 {
609 rtx set = XVECEXP (PATTERN (insn), 0, i);
2115ae11 610 gcc_assert (GET_CODE (set) == SET);
9e6a0967 611 RTX_FRAME_RELATED_P (set) = 1;
612 }
613
614 frame_size -= link_size;
615
616 if (frame_size > 0)
617 {
618 /* Must use a call-clobbered PREG that isn't the static chain. */
619 rtx tmpreg = gen_rtx_REG (Pmode, REG_P1);
620
b90ce3c3 621 frame_related_constant_load (tmpreg, -frame_size, TRUE);
9e6a0967 622 insn = emit_insn (gen_addsi3 (spreg, spreg, tmpreg));
623 RTX_FRAME_RELATED_P (insn) = 1;
624 }
625}
626
627/* Return the number of bytes we must reserve for outgoing arguments
628 in the current function's stack frame. */
629
630static HOST_WIDE_INT
631arg_area_size (void)
632{
633 if (current_function_outgoing_args_size)
634 {
635 if (current_function_outgoing_args_size >= FIXED_STACK_AREA)
636 return current_function_outgoing_args_size;
637 else
638 return FIXED_STACK_AREA;
639 }
640 return 0;
641}
642
643/* Save RETS and FP, and allocate a stack frame. */
644
645static void
646do_link (rtx spreg, HOST_WIDE_INT frame_size)
647{
648 frame_size += arg_area_size ();
649
650 if (stack_frame_needed_p ()
651 || (must_save_fp_p () && ! current_function_is_leaf))
652 emit_link_insn (spreg, frame_size);
653 else
654 {
655 if (! current_function_is_leaf)
656 {
657 rtx pat = gen_movsi (gen_rtx_MEM (Pmode,
658 gen_rtx_PRE_DEC (Pmode, spreg)),
659 bfin_rets_rtx);
660 rtx insn = emit_insn (pat);
661 RTX_FRAME_RELATED_P (insn) = 1;
662 }
663 if (must_save_fp_p ())
664 {
665 rtx pat = gen_movsi (gen_rtx_MEM (Pmode,
666 gen_rtx_PRE_DEC (Pmode, spreg)),
667 gen_rtx_REG (Pmode, REG_FP));
668 rtx insn = emit_insn (pat);
669 RTX_FRAME_RELATED_P (insn) = 1;
670 }
671 add_to_sp (spreg, -frame_size, 1);
672 }
673}
674
675/* Like do_link, but used for epilogues to deallocate the stack frame. */
676
677static void
678do_unlink (rtx spreg, HOST_WIDE_INT frame_size)
679{
680 frame_size += arg_area_size ();
681
682 if (stack_frame_needed_p ())
683 emit_insn (gen_unlink ());
684 else
685 {
686 rtx postinc = gen_rtx_MEM (Pmode, gen_rtx_POST_INC (Pmode, spreg));
687
688 add_to_sp (spreg, frame_size, 0);
689 if (must_save_fp_p ())
690 {
691 rtx fpreg = gen_rtx_REG (Pmode, REG_FP);
692 emit_move_insn (fpreg, postinc);
693 emit_insn (gen_rtx_USE (VOIDmode, fpreg));
694 }
695 if (! current_function_is_leaf)
696 {
697 emit_move_insn (bfin_rets_rtx, postinc);
698 emit_insn (gen_rtx_USE (VOIDmode, bfin_rets_rtx));
699 }
700 }
701}
702
703/* Generate a prologue suitable for a function of kind FKIND. This is
704 called for interrupt and exception handler prologues.
705 SPREG contains (reg:SI REG_SP). */
706
707static void
708expand_interrupt_handler_prologue (rtx spreg, e_funkind fkind)
709{
710 int i;
711 HOST_WIDE_INT frame_size = get_frame_size ();
712 rtx predec1 = gen_rtx_PRE_DEC (SImode, spreg);
713 rtx predec = gen_rtx_MEM (SImode, predec1);
714 rtx insn;
715 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
716 tree all = lookup_attribute ("saveall", attrs);
717 tree kspisusp = lookup_attribute ("kspisusp", attrs);
718
719 if (kspisusp)
720 {
721 insn = emit_move_insn (spreg, gen_rtx_REG (Pmode, REG_USP));
722 RTX_FRAME_RELATED_P (insn) = 1;
723 }
724
725 /* We need space on the stack in case we need to save the argument
726 registers. */
727 if (fkind == EXCPT_HANDLER)
728 {
729 insn = emit_insn (gen_addsi3 (spreg, spreg, GEN_INT (-12)));
730 RTX_FRAME_RELATED_P (insn) = 1;
731 }
732
733 insn = emit_move_insn (predec, gen_rtx_REG (SImode, REG_ASTAT));
734 RTX_FRAME_RELATED_P (insn) = 1;
735
736 expand_prologue_reg_save (spreg, all != NULL_TREE);
737
738 for (i = REG_P7 + 1; i < REG_CC; i++)
739 if (all
740 || regs_ever_live[i]
741 || (!leaf_function_p () && call_used_regs[i]))
742 {
743 if (i == REG_A0 || i == REG_A1)
744 insn = emit_move_insn (gen_rtx_MEM (PDImode, predec1),
745 gen_rtx_REG (PDImode, i));
746 else
747 insn = emit_move_insn (predec, gen_rtx_REG (SImode, i));
748 RTX_FRAME_RELATED_P (insn) = 1;
749 }
750
751 if (lookup_attribute ("nesting", attrs))
752 {
753 rtx srcreg = gen_rtx_REG (Pmode, (fkind == EXCPT_HANDLER ? REG_RETX
754 : fkind == NMI_HANDLER ? REG_RETN
755 : REG_RETI));
756 insn = emit_move_insn (predec, srcreg);
757 RTX_FRAME_RELATED_P (insn) = 1;
758 }
759
760 do_link (spreg, frame_size);
761
762 if (fkind == EXCPT_HANDLER)
763 {
764 rtx r0reg = gen_rtx_REG (SImode, REG_R0);
765 rtx r1reg = gen_rtx_REG (SImode, REG_R1);
766 rtx r2reg = gen_rtx_REG (SImode, REG_R2);
767 rtx insn;
768
769 insn = emit_move_insn (r0reg, gen_rtx_REG (SImode, REG_SEQSTAT));
770 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx,
771 NULL_RTX);
772 insn = emit_insn (gen_ashrsi3 (r0reg, r0reg, GEN_INT (26)));
773 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx,
774 NULL_RTX);
775 insn = emit_insn (gen_ashlsi3 (r0reg, r0reg, GEN_INT (26)));
776 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx,
777 NULL_RTX);
778 insn = emit_move_insn (r1reg, spreg);
779 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx,
780 NULL_RTX);
781 insn = emit_move_insn (r2reg, gen_rtx_REG (Pmode, REG_FP));
782 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx,
783 NULL_RTX);
784 insn = emit_insn (gen_addsi3 (r2reg, r2reg, GEN_INT (8)));
785 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx,
786 NULL_RTX);
787 }
788}
789
790/* Generate an epilogue suitable for a function of kind FKIND. This is
791 called for interrupt and exception handler epilogues.
792 SPREG contains (reg:SI REG_SP). */
793
794static void
795expand_interrupt_handler_epilogue (rtx spreg, e_funkind fkind)
796{
797 int i;
798 rtx postinc1 = gen_rtx_POST_INC (SImode, spreg);
799 rtx postinc = gen_rtx_MEM (SImode, postinc1);
800 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
801 tree all = lookup_attribute ("saveall", attrs);
802
803 /* A slightly crude technique to stop flow from trying to delete "dead"
804 insns. */
805 MEM_VOLATILE_P (postinc) = 1;
806
807 do_unlink (spreg, get_frame_size ());
808
809 if (lookup_attribute ("nesting", attrs))
810 {
811 rtx srcreg = gen_rtx_REG (Pmode, (fkind == EXCPT_HANDLER ? REG_RETX
812 : fkind == NMI_HANDLER ? REG_RETN
813 : REG_RETI));
814 emit_move_insn (srcreg, postinc);
815 }
816
817 for (i = REG_CC - 1; i > REG_P7; i--)
818 if (all
819 || regs_ever_live[i]
820 || (!leaf_function_p () && call_used_regs[i]))
821 {
822 if (i == REG_A0 || i == REG_A1)
823 {
824 rtx mem = gen_rtx_MEM (PDImode, postinc1);
825 MEM_VOLATILE_P (mem) = 1;
826 emit_move_insn (gen_rtx_REG (PDImode, i), mem);
827 }
828 else
829 emit_move_insn (gen_rtx_REG (SImode, i), postinc);
830 }
831
832 expand_epilogue_reg_restore (spreg, all != NULL_TREE);
833
834 emit_move_insn (gen_rtx_REG (SImode, REG_ASTAT), postinc);
835
836 /* Deallocate any space we left on the stack in case we needed to save the
837 argument registers. */
838 if (fkind == EXCPT_HANDLER)
839 emit_insn (gen_addsi3 (spreg, spreg, GEN_INT (12)));
840
841 emit_jump_insn (gen_return_internal (GEN_INT (fkind)));
842}
843
b90ce3c3 844/* Used while emitting the prologue to generate code to load the correct value
845 into the PIC register, which is passed in DEST. */
846
847static void
848bfin_load_pic_reg (rtx dest)
849{
850 rtx addr, insn;
851
852 if (bfin_lib_id_given)
853 addr = plus_constant (pic_offset_table_rtx, -4 - bfin_library_id * 4);
854 else
855 addr = gen_rtx_PLUS (Pmode, pic_offset_table_rtx,
856 gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx),
857 UNSPEC_LIBRARY_OFFSET));
858 insn = emit_insn (gen_movsi (dest, gen_rtx_MEM (Pmode, addr)));
859 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx, NULL);
860}
861
9e6a0967 862/* Generate RTL for the prologue of the current function. */
863
864void
865bfin_expand_prologue (void)
866{
867 rtx insn;
868 HOST_WIDE_INT frame_size = get_frame_size ();
869 rtx spreg = gen_rtx_REG (Pmode, REG_SP);
870 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
b90ce3c3 871 rtx pic_reg_loaded = NULL_RTX;
9e6a0967 872
873 if (fkind != SUBROUTINE)
874 {
875 expand_interrupt_handler_prologue (spreg, fkind);
876 return;
877 }
878
b90ce3c3 879 if (current_function_limit_stack)
880 {
881 HOST_WIDE_INT offset
882 = bfin_initial_elimination_offset (ARG_POINTER_REGNUM,
883 STACK_POINTER_REGNUM);
884 rtx lim = stack_limit_rtx;
885
886 if (GET_CODE (lim) == SYMBOL_REF)
887 {
888 rtx p2reg = gen_rtx_REG (Pmode, REG_P2);
889 if (TARGET_ID_SHARED_LIBRARY)
890 {
891 rtx p1reg = gen_rtx_REG (Pmode, REG_P1);
892 rtx r3reg = gen_rtx_REG (Pmode, REG_R3);
893 rtx val;
894 pic_reg_loaded = p2reg;
895 bfin_load_pic_reg (pic_reg_loaded);
896 val = legitimize_pic_address (stack_limit_rtx, p1reg, p2reg);
897 emit_move_insn (p1reg, val);
898 frame_related_constant_load (p2reg, offset, FALSE);
899 emit_insn (gen_addsi3 (p2reg, p2reg, p1reg));
900 lim = p2reg;
901 }
902 else
903 {
904 rtx limit = plus_constant (stack_limit_rtx, offset);
905 emit_move_insn (p2reg, limit);
906 lim = p2reg;
907 }
908 }
909 emit_insn (gen_compare_lt (bfin_cc_rtx, spreg, lim));
910 emit_insn (gen_trapifcc ());
911 }
9e6a0967 912 expand_prologue_reg_save (spreg, 0);
913
914 do_link (spreg, frame_size);
915
916 if (TARGET_ID_SHARED_LIBRARY
917 && (current_function_uses_pic_offset_table
918 || !current_function_is_leaf))
b90ce3c3 919 bfin_load_pic_reg (pic_offset_table_rtx);
9e6a0967 920}
921
922/* Generate RTL for the epilogue of the current function. NEED_RETURN is zero
923 if this is for a sibcall. EH_RETURN is nonzero if we're expanding an
924 eh_return pattern. */
925
926void
927bfin_expand_epilogue (int need_return, int eh_return)
928{
929 rtx spreg = gen_rtx_REG (Pmode, REG_SP);
930 e_funkind fkind = funkind (TREE_TYPE (current_function_decl));
931
932 if (fkind != SUBROUTINE)
933 {
934 expand_interrupt_handler_epilogue (spreg, fkind);
935 return;
936 }
937
938 do_unlink (spreg, get_frame_size ());
939
940 expand_epilogue_reg_restore (spreg, 0);
941
942 /* Omit the return insn if this is for a sibcall. */
943 if (! need_return)
944 return;
945
946 if (eh_return)
947 emit_insn (gen_addsi3 (spreg, spreg, gen_rtx_REG (Pmode, REG_P2)));
948
949 emit_jump_insn (gen_return_internal (GEN_INT (SUBROUTINE)));
950}
951\f
952/* Return nonzero if register OLD_REG can be renamed to register NEW_REG. */
953
954int
955bfin_hard_regno_rename_ok (unsigned int old_reg ATTRIBUTE_UNUSED,
956 unsigned int new_reg)
957{
958 /* Interrupt functions can only use registers that have already been
959 saved by the prologue, even if they would normally be
960 call-clobbered. */
961
962 if (funkind (TREE_TYPE (current_function_decl)) != SUBROUTINE
963 && !regs_ever_live[new_reg])
964 return 0;
965
966 return 1;
967}
968
969/* Return the value of the return address for the frame COUNT steps up
970 from the current frame, after the prologue.
971 We punt for everything but the current frame by returning const0_rtx. */
972
973rtx
974bfin_return_addr_rtx (int count)
975{
976 if (count != 0)
977 return const0_rtx;
978
979 return get_hard_reg_initial_val (Pmode, REG_RETS);
980}
981
982/* Try machine-dependent ways of modifying an illegitimate address X
983 to be legitimate. If we find one, return the new, valid address,
984 otherwise return NULL_RTX.
985
986 OLDX is the address as it was before break_out_memory_refs was called.
987 In some cases it is useful to look at this to decide what needs to be done.
988
989 MODE is the mode of the memory reference. */
990
991rtx
992legitimize_address (rtx x ATTRIBUTE_UNUSED, rtx oldx ATTRIBUTE_UNUSED,
993 enum machine_mode mode ATTRIBUTE_UNUSED)
994{
995 return NULL_RTX;
996}
997
998/* This predicate is used to compute the length of a load/store insn.
999 OP is a MEM rtx, we return nonzero if its addressing mode requires a
1000 32 bit instruction. */
1001
1002int
1003effective_address_32bit_p (rtx op, enum machine_mode mode)
1004{
1005 HOST_WIDE_INT offset;
1006
1007 mode = GET_MODE (op);
1008 op = XEXP (op, 0);
1009
9e6a0967 1010 if (GET_CODE (op) != PLUS)
2115ae11 1011 {
1012 gcc_assert (REG_P (op) || GET_CODE (op) == POST_INC
1013 || GET_CODE (op) == PRE_DEC || GET_CODE (op) == POST_DEC);
1014 return 0;
1015 }
9e6a0967 1016
1017 offset = INTVAL (XEXP (op, 1));
1018
1019 /* All byte loads use a 16 bit offset. */
1020 if (GET_MODE_SIZE (mode) == 1)
1021 return 1;
1022
1023 if (GET_MODE_SIZE (mode) == 4)
1024 {
1025 /* Frame pointer relative loads can use a negative offset, all others
1026 are restricted to a small positive one. */
1027 if (XEXP (op, 0) == frame_pointer_rtx)
1028 return offset < -128 || offset > 60;
1029 return offset < 0 || offset > 60;
1030 }
1031
1032 /* Must be HImode now. */
1033 return offset < 0 || offset > 30;
1034}
1035
1036/* Return cost of the memory address ADDR.
1037 All addressing modes are equally cheap on the Blackfin. */
1038
1039static int
1040bfin_address_cost (rtx addr ATTRIBUTE_UNUSED)
1041{
1042 return 1;
1043}
1044
1045/* Subroutine of print_operand; used to print a memory reference X to FILE. */
1046
1047void
1048print_address_operand (FILE *file, rtx x)
1049{
9e6a0967 1050 switch (GET_CODE (x))
1051 {
1052 case PLUS:
1053 output_address (XEXP (x, 0));
1054 fprintf (file, "+");
1055 output_address (XEXP (x, 1));
1056 break;
1057
1058 case PRE_DEC:
1059 fprintf (file, "--");
1060 output_address (XEXP (x, 0));
1061 break;
1062 case POST_INC:
1063 output_address (XEXP (x, 0));
1064 fprintf (file, "++");
1065 break;
1066 case POST_DEC:
1067 output_address (XEXP (x, 0));
1068 fprintf (file, "--");
1069 break;
1070
1071 default:
2115ae11 1072 gcc_assert (GET_CODE (x) != MEM);
9e6a0967 1073 print_operand (file, x, 0);
2115ae11 1074 break;
9e6a0967 1075 }
1076}
1077
1078/* Adding intp DImode support by Tony
1079 * -- Q: (low word)
1080 * -- R: (high word)
1081 */
1082
1083void
1084print_operand (FILE *file, rtx x, char code)
1085{
1086 enum machine_mode mode = GET_MODE (x);
1087
1088 switch (code)
1089 {
1090 case 'j':
1091 switch (GET_CODE (x))
1092 {
1093 case EQ:
1094 fprintf (file, "e");
1095 break;
1096 case NE:
1097 fprintf (file, "ne");
1098 break;
1099 case GT:
1100 fprintf (file, "g");
1101 break;
1102 case LT:
1103 fprintf (file, "l");
1104 break;
1105 case GE:
1106 fprintf (file, "ge");
1107 break;
1108 case LE:
1109 fprintf (file, "le");
1110 break;
1111 case GTU:
1112 fprintf (file, "g");
1113 break;
1114 case LTU:
1115 fprintf (file, "l");
1116 break;
1117 case GEU:
1118 fprintf (file, "ge");
1119 break;
1120 case LEU:
1121 fprintf (file, "le");
1122 break;
1123 default:
1124 output_operand_lossage ("invalid %%j value");
1125 }
1126 break;
1127
1128 case 'J': /* reverse logic */
1129 switch (GET_CODE(x))
1130 {
1131 case EQ:
1132 fprintf (file, "ne");
1133 break;
1134 case NE:
1135 fprintf (file, "e");
1136 break;
1137 case GT:
1138 fprintf (file, "le");
1139 break;
1140 case LT:
1141 fprintf (file, "ge");
1142 break;
1143 case GE:
1144 fprintf (file, "l");
1145 break;
1146 case LE:
1147 fprintf (file, "g");
1148 break;
1149 case GTU:
1150 fprintf (file, "le");
1151 break;
1152 case LTU:
1153 fprintf (file, "ge");
1154 break;
1155 case GEU:
1156 fprintf (file, "l");
1157 break;
1158 case LEU:
1159 fprintf (file, "g");
1160 break;
1161 default:
1162 output_operand_lossage ("invalid %%J value");
1163 }
1164 break;
1165
1166 default:
1167 switch (GET_CODE (x))
1168 {
1169 case REG:
1170 if (code == 'h')
1171 {
1172 gcc_assert (REGNO (x) < 32);
1173 fprintf (file, "%s", short_reg_names[REGNO (x)]);
1174 /*fprintf (file, "\n%d\n ", REGNO (x));*/
1175 break;
1176 }
1177 else if (code == 'd')
1178 {
1179 gcc_assert (REGNO (x) < 32);
1180 fprintf (file, "%s", high_reg_names[REGNO (x)]);
1181 break;
1182 }
1183 else if (code == 'w')
1184 {
1185 gcc_assert (REGNO (x) == REG_A0 || REGNO (x) == REG_A1);
1186 fprintf (file, "%s.w", reg_names[REGNO (x)]);
1187 }
1188 else if (code == 'x')
1189 {
1190 gcc_assert (REGNO (x) == REG_A0 || REGNO (x) == REG_A1);
1191 fprintf (file, "%s.x", reg_names[REGNO (x)]);
1192 }
1193 else if (code == 'D')
1194 {
1195 fprintf (file, "%s", dregs_pair_names[REGNO (x)]);
1196 }
1197 else if (code == 'H')
1198 {
1199 gcc_assert (mode == DImode || mode == DFmode);
1200 gcc_assert (REG_P (x));
1201 fprintf (file, "%s", reg_names[REGNO (x) + 1]);
1202 }
1203 else if (code == 'T')
1204 {
2115ae11 1205 gcc_assert (D_REGNO_P (REGNO (x)));
9e6a0967 1206 fprintf (file, "%s", byte_reg_names[REGNO (x)]);
1207 }
1208 else
1209 fprintf (file, "%s", reg_names[REGNO (x)]);
1210 break;
1211
1212 case MEM:
1213 fputc ('[', file);
1214 x = XEXP (x,0);
1215 print_address_operand (file, x);
1216 fputc (']', file);
1217 break;
1218
1219 case CONST_INT:
1220 /* Moves to half registers with d or h modifiers always use unsigned
1221 constants. */
1222 if (code == 'd')
1223 x = GEN_INT ((INTVAL (x) >> 16) & 0xffff);
1224 else if (code == 'h')
1225 x = GEN_INT (INTVAL (x) & 0xffff);
1226 else if (code == 'X')
1227 x = GEN_INT (exact_log2 (0xffffffff & INTVAL (x)));
1228 else if (code == 'Y')
1229 x = GEN_INT (exact_log2 (0xffffffff & ~INTVAL (x)));
1230 else if (code == 'Z')
1231 /* Used for LINK insns. */
1232 x = GEN_INT (-8 - INTVAL (x));
1233
1234 /* fall through */
1235
1236 case SYMBOL_REF:
1237 output_addr_const (file, x);
1238 if (code == 'G' && flag_pic)
1239 fprintf (file, "@GOT");
1240 break;
1241
1242 case CONST_DOUBLE:
1243 output_operand_lossage ("invalid const_double operand");
1244 break;
1245
1246 case UNSPEC:
2115ae11 1247 switch (XINT (x, 1))
9e6a0967 1248 {
2115ae11 1249 case UNSPEC_MOVE_PIC:
9e6a0967 1250 output_addr_const (file, XVECEXP (x, 0, 0));
1251 fprintf (file, "@GOT");
2115ae11 1252 break;
1253
1254 case UNSPEC_LIBRARY_OFFSET:
1255 fprintf (file, "_current_shared_library_p5_offset_");
1256 break;
1257
1258 default:
1259 gcc_unreachable ();
9e6a0967 1260 }
9e6a0967 1261 break;
1262
1263 default:
1264 output_addr_const (file, x);
1265 }
1266 }
1267}
1268\f
1269/* Argument support functions. */
1270
1271/* Initialize a variable CUM of type CUMULATIVE_ARGS
1272 for a call to a function whose data type is FNTYPE.
1273 For a library call, FNTYPE is 0.
1274 VDSP C Compiler manual, our ABI says that
1275 first 3 words of arguments will use R0, R1 and R2.
1276*/
1277
1278void
7b6ef6dd 1279init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype,
9e6a0967 1280 rtx libname ATTRIBUTE_UNUSED)
1281{
1282 static CUMULATIVE_ARGS zero_cum;
1283
1284 *cum = zero_cum;
1285
1286 /* Set up the number of registers to use for passing arguments. */
1287
1288 cum->nregs = max_arg_registers;
1289 cum->arg_regs = arg_regs;
1290
7b6ef6dd 1291 cum->call_cookie = CALL_NORMAL;
1292 /* Check for a longcall attribute. */
1293 if (fntype && lookup_attribute ("shortcall", TYPE_ATTRIBUTES (fntype)))
1294 cum->call_cookie |= CALL_SHORT;
1295 else if (fntype && lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype)))
1296 cum->call_cookie |= CALL_LONG;
1297
9e6a0967 1298 return;
1299}
1300
1301/* Update the data in CUM to advance over an argument
1302 of mode MODE and data type TYPE.
1303 (TYPE is null for libcalls where that information may not be available.) */
1304
1305void
1306function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
1307 int named ATTRIBUTE_UNUSED)
1308{
1309 int count, bytes, words;
1310
1311 bytes = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
1312 words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
1313
1314 cum->words += words;
1315 cum->nregs -= words;
1316
1317 if (cum->nregs <= 0)
1318 {
1319 cum->nregs = 0;
1320 cum->arg_regs = NULL;
1321 }
1322 else
1323 {
1324 for (count = 1; count <= words; count++)
1325 cum->arg_regs++;
1326 }
1327
1328 return;
1329}
1330
1331/* Define where to put the arguments to a function.
1332 Value is zero to push the argument on the stack,
1333 or a hard register in which to store the argument.
1334
1335 MODE is the argument's machine mode.
1336 TYPE is the data type of the argument (as a tree).
1337 This is null for libcalls where that information may
1338 not be available.
1339 CUM is a variable of type CUMULATIVE_ARGS which gives info about
1340 the preceding args and about the function being called.
1341 NAMED is nonzero if this argument is a named parameter
1342 (otherwise it is an extra parameter matching an ellipsis). */
1343
1344struct rtx_def *
1345function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
1346 int named ATTRIBUTE_UNUSED)
1347{
1348 int bytes
1349 = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
1350
7b6ef6dd 1351 if (mode == VOIDmode)
1352 /* Compute operand 2 of the call insn. */
1353 return GEN_INT (cum->call_cookie);
1354
9e6a0967 1355 if (bytes == -1)
1356 return NULL_RTX;
1357
1358 if (cum->nregs)
1359 return gen_rtx_REG (mode, *(cum->arg_regs));
1360
1361 return NULL_RTX;
1362}
1363
1364/* For an arg passed partly in registers and partly in memory,
1365 this is the number of bytes passed in registers.
1366 For args passed entirely in registers or entirely in memory, zero.
1367
1368 Refer VDSP C Compiler manual, our ABI.
1369 First 3 words are in registers. So, if a an argument is larger
1370 than the registers available, it will span the register and
1371 stack. */
1372
1373static int
1374bfin_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode,
1375 tree type ATTRIBUTE_UNUSED,
1376 bool named ATTRIBUTE_UNUSED)
1377{
1378 int bytes
1379 = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
1380 int bytes_left = cum->nregs * UNITS_PER_WORD;
1381
1382 if (bytes == -1)
1383 return 0;
1384
1385 if (bytes_left == 0)
1386 return 0;
1387 if (bytes > bytes_left)
1388 return bytes_left;
1389 return 0;
1390}
1391
1392/* Variable sized types are passed by reference. */
1393
1394static bool
1395bfin_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
1396 enum machine_mode mode ATTRIBUTE_UNUSED,
1397 tree type, bool named ATTRIBUTE_UNUSED)
1398{
1399 return type && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST;
1400}
1401
1402/* Decide whether a type should be returned in memory (true)
1403 or in a register (false). This is called by the macro
1404 RETURN_IN_MEMORY. */
1405
1406int
1407bfin_return_in_memory (tree type)
1408{
1409 int size;
1410 enum machine_mode mode = TYPE_MODE (type);
1411
1412 if (mode == BLKmode)
1413 return 1;
1414 size = int_size_in_bytes (type);
9e6a0967 1415
4d3aaef8 1416 return size > 8;
9e6a0967 1417}
1418
1419/* Register in which address to store a structure value
1420 is passed to a function. */
1421static rtx
1422bfin_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
1423 int incoming ATTRIBUTE_UNUSED)
1424{
1425 return gen_rtx_REG (Pmode, REG_P0);
1426}
1427
1428/* Return true when register may be used to pass function parameters. */
1429
1430bool
1431function_arg_regno_p (int n)
1432{
1433 int i;
1434 for (i = 0; arg_regs[i] != -1; i++)
1435 if (n == arg_regs[i])
1436 return true;
1437 return false;
1438}
1439
1440/* Returns 1 if OP contains a symbol reference */
1441
1442int
1443symbolic_reference_mentioned_p (rtx op)
1444{
1445 register const char *fmt;
1446 register int i;
1447
1448 if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF)
1449 return 1;
1450
1451 fmt = GET_RTX_FORMAT (GET_CODE (op));
1452 for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
1453 {
1454 if (fmt[i] == 'E')
1455 {
1456 register int j;
1457
1458 for (j = XVECLEN (op, i) - 1; j >= 0; j--)
1459 if (symbolic_reference_mentioned_p (XVECEXP (op, i, j)))
1460 return 1;
1461 }
1462
1463 else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i)))
1464 return 1;
1465 }
1466
1467 return 0;
1468}
1469
1470/* Decide whether we can make a sibling call to a function. DECL is the
1471 declaration of the function being targeted by the call and EXP is the
1472 CALL_EXPR representing the call. */
1473
1474static bool
1475bfin_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED,
1476 tree exp ATTRIBUTE_UNUSED)
1477{
1478 return true;
1479}
1480\f
1481/* Emit RTL insns to initialize the variable parts of a trampoline at
1482 TRAMP. FNADDR is an RTX for the address of the function's pure
1483 code. CXT is an RTX for the static chain value for the function. */
1484
1485void
1486initialize_trampoline (tramp, fnaddr, cxt)
1487 rtx tramp, fnaddr, cxt;
1488{
1489 rtx t1 = copy_to_reg (fnaddr);
1490 rtx t2 = copy_to_reg (cxt);
1491 rtx addr;
1492
1493 addr = memory_address (Pmode, plus_constant (tramp, 2));
1494 emit_move_insn (gen_rtx_MEM (HImode, addr), gen_lowpart (HImode, t1));
1495 emit_insn (gen_ashrsi3 (t1, t1, GEN_INT (16)));
1496 addr = memory_address (Pmode, plus_constant (tramp, 6));
1497 emit_move_insn (gen_rtx_MEM (HImode, addr), gen_lowpart (HImode, t1));
1498
1499 addr = memory_address (Pmode, plus_constant (tramp, 10));
1500 emit_move_insn (gen_rtx_MEM (HImode, addr), gen_lowpart (HImode, t2));
1501 emit_insn (gen_ashrsi3 (t2, t2, GEN_INT (16)));
1502 addr = memory_address (Pmode, plus_constant (tramp, 14));
1503 emit_move_insn (gen_rtx_MEM (HImode, addr), gen_lowpart (HImode, t2));
1504}
1505
9e6a0967 1506/* Emit insns to move operands[1] into operands[0]. */
1507
1508void
1509emit_pic_move (rtx *operands, enum machine_mode mode ATTRIBUTE_UNUSED)
1510{
1511 rtx temp = reload_in_progress ? operands[0] : gen_reg_rtx (Pmode);
1512
1513 if (GET_CODE (operands[0]) == MEM && SYMBOLIC_CONST (operands[1]))
1514 operands[1] = force_reg (SImode, operands[1]);
1515 else
b90ce3c3 1516 operands[1] = legitimize_pic_address (operands[1], temp,
1517 pic_offset_table_rtx);
9e6a0967 1518}
1519
1520/* Expand a move operation in mode MODE. The operands are in OPERANDS. */
1521
1522void
1523expand_move (rtx *operands, enum machine_mode mode)
1524{
1525 if (flag_pic && SYMBOLIC_CONST (operands[1]))
1526 emit_pic_move (operands, mode);
1527
1528 /* Don't generate memory->memory or constant->memory moves, go through a
1529 register */
1530 else if ((reload_in_progress | reload_completed) == 0
1531 && GET_CODE (operands[0]) == MEM
1532 && GET_CODE (operands[1]) != REG)
1533 operands[1] = force_reg (mode, operands[1]);
1534}
1535\f
1536/* Split one or more DImode RTL references into pairs of SImode
1537 references. The RTL can be REG, offsettable MEM, integer constant, or
1538 CONST_DOUBLE. "operands" is a pointer to an array of DImode RTL to
1539 split and "num" is its length. lo_half and hi_half are output arrays
1540 that parallel "operands". */
1541
1542void
1543split_di (rtx operands[], int num, rtx lo_half[], rtx hi_half[])
1544{
1545 while (num--)
1546 {
1547 rtx op = operands[num];
1548
1549 /* simplify_subreg refuse to split volatile memory addresses,
1550 but we still have to handle it. */
1551 if (GET_CODE (op) == MEM)
1552 {
1553 lo_half[num] = adjust_address (op, SImode, 0);
1554 hi_half[num] = adjust_address (op, SImode, 4);
1555 }
1556 else
1557 {
1558 lo_half[num] = simplify_gen_subreg (SImode, op,
1559 GET_MODE (op) == VOIDmode
1560 ? DImode : GET_MODE (op), 0);
1561 hi_half[num] = simplify_gen_subreg (SImode, op,
1562 GET_MODE (op) == VOIDmode
1563 ? DImode : GET_MODE (op), 4);
1564 }
1565 }
1566}
1567\f
7b6ef6dd 1568bool
1569bfin_longcall_p (rtx op, int call_cookie)
1570{
1571 gcc_assert (GET_CODE (op) == SYMBOL_REF);
1572 if (call_cookie & CALL_SHORT)
1573 return 0;
1574 if (call_cookie & CALL_LONG)
1575 return 1;
1576 if (TARGET_LONG_CALLS)
1577 return 1;
1578 return 0;
1579}
1580
9e6a0967 1581/* Expand a call instruction. FNADDR is the call target, RETVAL the return value.
7b6ef6dd 1582 COOKIE is a CONST_INT holding the call_cookie prepared init_cumulative_args.
9e6a0967 1583 SIBCALL is nonzero if this is a sibling call. */
1584
1585void
7b6ef6dd 1586bfin_expand_call (rtx retval, rtx fnaddr, rtx callarg1, rtx cookie, int sibcall)
9e6a0967 1587{
1588 rtx use = NULL, call;
7b6ef6dd 1589 rtx callee = XEXP (fnaddr, 0);
1590 rtx pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (sibcall ? 3 : 2));
1591
1592 /* In an untyped call, we can get NULL for operand 2. */
1593 if (cookie == NULL_RTX)
1594 cookie = const0_rtx;
9e6a0967 1595
1596 /* Static functions and indirect calls don't need the pic register. */
1597 if (flag_pic
7b6ef6dd 1598 && GET_CODE (callee) == SYMBOL_REF
1599 && !SYMBOL_REF_LOCAL_P (callee))
9e6a0967 1600 use_reg (&use, pic_offset_table_rtx);
1601
7b6ef6dd 1602 if ((!register_no_elim_operand (callee, Pmode)
1603 && GET_CODE (callee) != SYMBOL_REF)
1604 || (GET_CODE (callee) == SYMBOL_REF
1605 && (flag_pic
1606 || bfin_longcall_p (callee, INTVAL (cookie)))))
9e6a0967 1607 {
7b6ef6dd 1608 callee = copy_to_mode_reg (Pmode, callee);
1609 fnaddr = gen_rtx_MEM (Pmode, callee);
9e6a0967 1610 }
1611 call = gen_rtx_CALL (VOIDmode, fnaddr, callarg1);
1612
1613 if (retval)
1614 call = gen_rtx_SET (VOIDmode, retval, call);
7b6ef6dd 1615
1616 XVECEXP (pat, 0, 0) = call;
1617 XVECEXP (pat, 0, 1) = gen_rtx_USE (VOIDmode, cookie);
9e6a0967 1618 if (sibcall)
7b6ef6dd 1619 XVECEXP (pat, 0, 2) = gen_rtx_RETURN (VOIDmode);
1620 call = emit_call_insn (pat);
9e6a0967 1621 if (use)
1622 CALL_INSN_FUNCTION_USAGE (call) = use;
1623}
1624\f
1625/* Return 1 if hard register REGNO can hold a value of machine-mode MODE. */
1626
1627int
1628hard_regno_mode_ok (int regno, enum machine_mode mode)
1629{
1630 /* Allow only dregs to store value of mode HI or QI */
1631 enum reg_class class = REGNO_REG_CLASS (regno);
1632
1633 if (mode == CCmode)
1634 return 0;
1635
1636 if (mode == V2HImode)
1637 return D_REGNO_P (regno);
1638 if (class == CCREGS)
1639 return mode == BImode;
1640 if (mode == PDImode)
1641 return regno == REG_A0 || regno == REG_A1;
1642 if (mode == SImode
1643 && TEST_HARD_REG_BIT (reg_class_contents[PROLOGUE_REGS], regno))
1644 return 1;
1645
1646 return TEST_HARD_REG_BIT (reg_class_contents[MOST_REGS], regno);
1647}
1648
1649/* Implements target hook vector_mode_supported_p. */
1650
1651static bool
1652bfin_vector_mode_supported_p (enum machine_mode mode)
1653{
1654 return mode == V2HImode;
1655}
1656
1657/* Return the cost of moving data from a register in class CLASS1 to
1658 one in class CLASS2. A cost of 2 is the default. */
1659
1660int
1661bfin_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
1662 enum reg_class class1, enum reg_class class2)
1663{
1664 /* If optimizing for size, always prefer reg-reg over reg-memory moves. */
1665 if (optimize_size)
1666 return 2;
1667
1668 /* There are some stalls involved when moving from a DREG to a different
1669 class reg, and using the value in one of the following instructions.
1670 Attempt to model this by slightly discouraging such moves. */
1671 if (class1 == DREGS && class2 != DREGS)
1672 return 2 * 2;
1673
1674 return 2;
1675}
1676
1677/* Return the cost of moving data of mode M between a
1678 register and memory. A value of 2 is the default; this cost is
1679 relative to those in `REGISTER_MOVE_COST'.
1680
1681 ??? In theory L1 memory has single-cycle latency. We should add a switch
1682 that tells the compiler whether we expect to use only L1 memory for the
1683 program; it'll make the costs more accurate. */
1684
1685int
1686bfin_memory_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
1687 enum reg_class class,
1688 int in ATTRIBUTE_UNUSED)
1689{
1690 /* Make memory accesses slightly more expensive than any register-register
1691 move. Also, penalize non-DP registers, since they need secondary
1692 reloads to load and store. */
1693 if (! reg_class_subset_p (class, DPREGS))
1694 return 10;
1695
1696 return 8;
1697}
1698
1699/* Inform reload about cases where moving X with a mode MODE to a register in
1700 CLASS requires an extra scratch register. Return the class needed for the
1701 scratch register. */
1702
1703enum reg_class
1704secondary_input_reload_class (enum reg_class class, enum machine_mode mode,
1705 rtx x)
1706{
1707 /* If we have HImode or QImode, we can only use DREGS as secondary registers;
1708 in most other cases we can also use PREGS. */
1709 enum reg_class default_class = GET_MODE_SIZE (mode) >= 4 ? DPREGS : DREGS;
1710 enum reg_class x_class = NO_REGS;
1711 enum rtx_code code = GET_CODE (x);
1712
1713 if (code == SUBREG)
1714 x = SUBREG_REG (x), code = GET_CODE (x);
1715 if (REG_P (x))
1716 {
1717 int regno = REGNO (x);
1718 if (regno >= FIRST_PSEUDO_REGISTER)
1719 regno = reg_renumber[regno];
1720
1721 if (regno == -1)
1722 code = MEM;
1723 else
1724 x_class = REGNO_REG_CLASS (regno);
1725 }
1726
1727 /* We can be asked to reload (plus (FP) (large_constant)) into a DREG.
1728 This happens as a side effect of register elimination, and we need
1729 a scratch register to do it. */
1730 if (fp_plus_const_operand (x, mode))
1731 {
1732 rtx op2 = XEXP (x, 1);
1733 int large_constant_p = ! CONST_7BIT_IMM_P (INTVAL (op2));
1734
1735 if (class == PREGS || class == PREGS_CLOBBERED)
1736 return NO_REGS;
1737 /* If destination is a DREG, we can do this without a scratch register
1738 if the constant is valid for an add instruction. */
1739 if (class == DREGS || class == DPREGS)
1740 return large_constant_p ? PREGS : NO_REGS;
1741 /* Reloading to anything other than a DREG? Use a PREG scratch
1742 register. */
1743 return PREGS;
1744 }
1745
1746 /* Data can usually be moved freely between registers of most classes.
1747 AREGS are an exception; they can only move to or from another register
1748 in AREGS or one in DREGS. They can also be assigned the constant 0. */
1749 if (x_class == AREGS)
1750 return class == DREGS || class == AREGS ? NO_REGS : DREGS;
1751
1752 if (class == AREGS)
1753 {
1754 if (x != const0_rtx && x_class != DREGS)
1755 return DREGS;
1756 else
1757 return NO_REGS;
1758 }
1759
1760 /* CCREGS can only be moved from/to DREGS. */
1761 if (class == CCREGS && x_class != DREGS)
1762 return DREGS;
1763 if (x_class == CCREGS && class != DREGS)
1764 return DREGS;
1765 /* All registers other than AREGS can load arbitrary constants. The only
1766 case that remains is MEM. */
1767 if (code == MEM)
1768 if (! reg_class_subset_p (class, default_class))
1769 return default_class;
1770 return NO_REGS;
1771}
1772
1773/* Like secondary_input_reload_class; and all we do is call that function. */
1774
1775enum reg_class
1776secondary_output_reload_class (enum reg_class class, enum machine_mode mode,
1777 rtx x)
1778{
1779 return secondary_input_reload_class (class, mode, x);
1780}
1781\f
f2a5d439 1782/* Implement TARGET_HANDLE_OPTION. */
1783
1784static bool
1785bfin_handle_option (size_t code, const char *arg, int value)
1786{
1787 switch (code)
1788 {
1789 case OPT_mshared_library_id_:
1790 if (value > MAX_LIBRARY_ID)
1791 error ("-mshared-library-id=%s is not between 0 and %d",
1792 arg, MAX_LIBRARY_ID);
354bd282 1793 bfin_lib_id_given = 1;
f2a5d439 1794 return true;
1795
1796 default:
1797 return true;
1798 }
1799}
1800
9e6a0967 1801/* Implement the macro OVERRIDE_OPTIONS. */
1802
1803void
1804override_options (void)
1805{
1806 if (TARGET_OMIT_LEAF_FRAME_POINTER)
1807 flag_omit_frame_pointer = 1;
1808
1809 /* Library identification */
f2a5d439 1810 if (bfin_lib_id_given && ! TARGET_ID_SHARED_LIBRARY)
1811 error ("-mshared-library-id= specified without -mid-shared-library");
9e6a0967 1812
1813 if (TARGET_ID_SHARED_LIBRARY)
1814 /* ??? Provide a way to use a bigger GOT. */
1815 flag_pic = 1;
1816
1817 flag_schedule_insns = 0;
1818}
1819
b03ddc8f 1820/* Return the destination address of BRANCH.
1821 We need to use this instead of get_attr_length, because the
1822 cbranch_with_nops pattern conservatively sets its length to 6, and
1823 we still prefer to use shorter sequences. */
9e6a0967 1824
1825static int
1826branch_dest (rtx branch)
1827{
1828 rtx dest;
1829 int dest_uid;
1830 rtx pat = PATTERN (branch);
1831 if (GET_CODE (pat) == PARALLEL)
1832 pat = XVECEXP (pat, 0, 0);
1833 dest = SET_SRC (pat);
1834 if (GET_CODE (dest) == IF_THEN_ELSE)
1835 dest = XEXP (dest, 1);
1836 dest = XEXP (dest, 0);
1837 dest_uid = INSN_UID (dest);
1838 return INSN_ADDRESSES (dest_uid);
1839}
1840
1841/* Return nonzero if INSN is annotated with a REG_BR_PROB note that indicates
1842 it's a branch that's predicted taken. */
1843
1844static int
1845cbranch_predicted_taken_p (rtx insn)
1846{
1847 rtx x = find_reg_note (insn, REG_BR_PROB, 0);
1848
1849 if (x)
1850 {
1851 int pred_val = INTVAL (XEXP (x, 0));
1852
1853 return pred_val >= REG_BR_PROB_BASE / 2;
1854 }
1855
1856 return 0;
1857}
1858
1859/* Templates for use by asm_conditional_branch. */
1860
1861static const char *ccbranch_templates[][3] = {
1862 { "if !cc jump %3;", "if cc jump 4 (bp); jump.s %3;", "if cc jump 6 (bp); jump.l %3;" },
1863 { "if cc jump %3;", "if !cc jump 4 (bp); jump.s %3;", "if !cc jump 6 (bp); jump.l %3;" },
1864 { "if !cc jump %3 (bp);", "if cc jump 4; jump.s %3;", "if cc jump 6; jump.l %3;" },
1865 { "if cc jump %3 (bp);", "if !cc jump 4; jump.s %3;", "if !cc jump 6; jump.l %3;" },
1866};
1867
1868/* Output INSN, which is a conditional branch instruction with operands
1869 OPERANDS.
1870
1871 We deal with the various forms of conditional branches that can be generated
1872 by bfin_reorg to prevent the hardware from doing speculative loads, by
1873 - emitting a sufficient number of nops, if N_NOPS is nonzero, or
1874 - always emitting the branch as predicted taken, if PREDICT_TAKEN is true.
1875 Either of these is only necessary if the branch is short, otherwise the
1876 template we use ends in an unconditional jump which flushes the pipeline
1877 anyway. */
1878
1879void
1880asm_conditional_branch (rtx insn, rtx *operands, int n_nops, int predict_taken)
1881{
1882 int offset = branch_dest (insn) - INSN_ADDRESSES (INSN_UID (insn));
1883 /* Note : offset for instructions like if cc jmp; jump.[sl] offset
1884 is to be taken from start of if cc rather than jump.
1885 Range for jump.s is (-4094, 4096) instead of (-4096, 4094)
1886 */
1887 int len = (offset >= -1024 && offset <= 1022 ? 0
1888 : offset >= -4094 && offset <= 4096 ? 1
1889 : 2);
1890 int bp = predict_taken && len == 0 ? 1 : cbranch_predicted_taken_p (insn);
1891 int idx = (bp << 1) | (GET_CODE (operands[0]) == EQ ? BRF : BRT);
1892 output_asm_insn (ccbranch_templates[idx][len], operands);
2115ae11 1893 gcc_assert (n_nops == 0 || !bp);
9e6a0967 1894 if (len == 0)
1895 while (n_nops-- > 0)
1896 output_asm_insn ("nop;", NULL);
1897}
1898
1899/* Emit rtl for a comparison operation CMP in mode MODE. Operands have been
1900 stored in bfin_compare_op0 and bfin_compare_op1 already. */
1901
1902rtx
1903bfin_gen_compare (rtx cmp, enum machine_mode mode ATTRIBUTE_UNUSED)
1904{
1905 enum rtx_code code1, code2;
1906 rtx op0 = bfin_compare_op0, op1 = bfin_compare_op1;
1907 rtx tem = bfin_cc_rtx;
1908 enum rtx_code code = GET_CODE (cmp);
1909
1910 /* If we have a BImode input, then we already have a compare result, and
1911 do not need to emit another comparison. */
1912 if (GET_MODE (op0) == BImode)
1913 {
2115ae11 1914 gcc_assert ((code == NE || code == EQ) && op1 == const0_rtx);
1915 tem = op0, code2 = code;
9e6a0967 1916 }
1917 else
1918 {
1919 switch (code) {
1920 /* bfin has these conditions */
1921 case EQ:
1922 case LT:
1923 case LE:
1924 case LEU:
1925 case LTU:
1926 code1 = code;
1927 code2 = NE;
1928 break;
1929 default:
1930 code1 = reverse_condition (code);
1931 code2 = EQ;
1932 break;
1933 }
1934 emit_insn (gen_rtx_SET (BImode, tem,
1935 gen_rtx_fmt_ee (code1, BImode, op0, op1)));
1936 }
1937
1938 return gen_rtx_fmt_ee (code2, BImode, tem, CONST0_RTX (BImode));
1939}
1940\f
1941/* Return nonzero iff C has exactly one bit set if it is interpreted
1942 as a 32 bit constant. */
1943
1944int
1945log2constp (unsigned HOST_WIDE_INT c)
1946{
1947 c &= 0xFFFFFFFF;
1948 return c != 0 && (c & (c-1)) == 0;
1949}
1950
1951/* Returns the number of consecutive least significant zeros in the binary
1952 representation of *V.
1953 We modify *V to contain the original value arithmetically shifted right by
1954 the number of zeroes. */
1955
1956static int
1957shiftr_zero (HOST_WIDE_INT *v)
1958{
1959 unsigned HOST_WIDE_INT tmp = *v;
1960 unsigned HOST_WIDE_INT sgn;
1961 int n = 0;
1962
1963 if (tmp == 0)
1964 return 0;
1965
1966 sgn = tmp & ((unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1));
1967 while ((tmp & 0x1) == 0 && n <= 32)
1968 {
1969 tmp = (tmp >> 1) | sgn;
1970 n++;
1971 }
1972 *v = tmp;
1973 return n;
1974}
1975
1976/* After reload, split the load of an immediate constant. OPERANDS are the
1977 operands of the movsi_insn pattern which we are splitting. We return
1978 nonzero if we emitted a sequence to load the constant, zero if we emitted
1979 nothing because we want to use the splitter's default sequence. */
1980
1981int
1982split_load_immediate (rtx operands[])
1983{
1984 HOST_WIDE_INT val = INTVAL (operands[1]);
1985 HOST_WIDE_INT tmp;
1986 HOST_WIDE_INT shifted = val;
1987 HOST_WIDE_INT shifted_compl = ~val;
1988 int num_zero = shiftr_zero (&shifted);
1989 int num_compl_zero = shiftr_zero (&shifted_compl);
1990 unsigned int regno = REGNO (operands[0]);
1991 enum reg_class class1 = REGNO_REG_CLASS (regno);
1992
1993 /* This case takes care of single-bit set/clear constants, which we could
1994 also implement with BITSET/BITCLR. */
1995 if (num_zero
1996 && shifted >= -32768 && shifted < 65536
1997 && (D_REGNO_P (regno)
1998 || (regno >= REG_P0 && regno <= REG_P7 && num_zero <= 2)))
1999 {
2000 emit_insn (gen_movsi (operands[0], GEN_INT (shifted)));
2001 emit_insn (gen_ashlsi3 (operands[0], operands[0], GEN_INT (num_zero)));
2002 return 1;
2003 }
2004
2005 tmp = val & 0xFFFF;
2006 tmp |= -(tmp & 0x8000);
2007
2008 /* If high word has one bit set or clear, try to use a bit operation. */
2009 if (D_REGNO_P (regno))
2010 {
2011 if (log2constp (val & 0xFFFF0000))
2012 {
2013 emit_insn (gen_movsi (operands[0], GEN_INT (val & 0xFFFF)));
2014 emit_insn (gen_iorsi3 (operands[0], operands[0], GEN_INT (val & 0xFFFF0000)));
2015 return 1;
2016 }
2017 else if (log2constp (val | 0xFFFF) && (val & 0x8000) != 0)
2018 {
2019 emit_insn (gen_movsi (operands[0], GEN_INT (tmp)));
2020 emit_insn (gen_andsi3 (operands[0], operands[0], GEN_INT (val | 0xFFFF)));
2021 }
2022 }
2023
2024 if (D_REGNO_P (regno))
2025 {
2026 if (CONST_7BIT_IMM_P (tmp))
2027 {
2028 emit_insn (gen_movsi (operands[0], GEN_INT (tmp)));
2029 emit_insn (gen_movstricthi_high (operands[0], GEN_INT (val & -65536)));
2030 return 1;
2031 }
2032
2033 if ((val & 0xFFFF0000) == 0)
2034 {
2035 emit_insn (gen_movsi (operands[0], const0_rtx));
2036 emit_insn (gen_movsi_low (operands[0], operands[0], operands[1]));
2037 return 1;
2038 }
2039
2040 if ((val & 0xFFFF0000) == 0xFFFF0000)
2041 {
2042 emit_insn (gen_movsi (operands[0], constm1_rtx));
2043 emit_insn (gen_movsi_low (operands[0], operands[0], operands[1]));
2044 return 1;
2045 }
2046 }
2047
2048 /* Need DREGs for the remaining case. */
2049 if (regno > REG_R7)
2050 return 0;
2051
2052 if (optimize_size
2053 && num_compl_zero && CONST_7BIT_IMM_P (shifted_compl))
2054 {
2055 /* If optimizing for size, generate a sequence that has more instructions
2056 but is shorter. */
2057 emit_insn (gen_movsi (operands[0], GEN_INT (shifted_compl)));
2058 emit_insn (gen_ashlsi3 (operands[0], operands[0],
2059 GEN_INT (num_compl_zero)));
2060 emit_insn (gen_one_cmplsi2 (operands[0], operands[0]));
2061 return 1;
2062 }
2063 return 0;
2064}
2065\f
2066/* Return true if the legitimate memory address for a memory operand of mode
2067 MODE. Return false if not. */
2068
2069static bool
2070bfin_valid_add (enum machine_mode mode, HOST_WIDE_INT value)
2071{
2072 unsigned HOST_WIDE_INT v = value > 0 ? value : -value;
2073 int sz = GET_MODE_SIZE (mode);
2074 int shift = sz == 1 ? 0 : sz == 2 ? 1 : 2;
2075 /* The usual offsettable_memref machinery doesn't work so well for this
2076 port, so we deal with the problem here. */
2077 unsigned HOST_WIDE_INT mask = sz == 8 ? 0x7ffe : 0x7fff;
2078 return (v & ~(mask << shift)) == 0;
2079}
2080
2081static bool
2082bfin_valid_reg_p (unsigned int regno, int strict)
2083{
2084 return ((strict && REGNO_OK_FOR_BASE_STRICT_P (regno))
2085 || (!strict && REGNO_OK_FOR_BASE_NONSTRICT_P (regno)));
2086}
2087
2088bool
2089bfin_legitimate_address_p (enum machine_mode mode, rtx x, int strict)
2090{
2091 switch (GET_CODE (x)) {
2092 case REG:
2093 if (bfin_valid_reg_p (REGNO (x), strict))
2094 return true;
2095 break;
2096 case PLUS:
2097 if (REG_P (XEXP (x, 0))
2098 && bfin_valid_reg_p (REGNO (XEXP (x, 0)), strict)
2099 && (GET_CODE (XEXP (x, 1)) == UNSPEC
2100 || (GET_CODE (XEXP (x, 1)) == CONST_INT
2101 && bfin_valid_add (mode, INTVAL (XEXP (x, 1))))))
2102 return true;
2103 break;
2104 case POST_INC:
2105 case POST_DEC:
2106 if (LEGITIMATE_MODE_FOR_AUTOINC_P (mode)
2107 && REG_P (XEXP (x, 0))
2108 && bfin_valid_reg_p (REGNO (XEXP (x, 0)), strict))
2109 return true;
2110 case PRE_DEC:
2111 if (LEGITIMATE_MODE_FOR_AUTOINC_P (mode)
2112 && XEXP (x, 0) == stack_pointer_rtx
2113 && REG_P (XEXP (x, 0))
2114 && bfin_valid_reg_p (REGNO (XEXP (x, 0)), strict))
2115 return true;
2116 break;
2117 default:
2118 break;
2119 }
2120 return false;
2121}
2122
2123static bool
2124bfin_rtx_costs (rtx x, int code, int outer_code, int *total)
2125{
2126 int cost2 = COSTS_N_INSNS (1);
2127
2128 switch (code)
2129 {
2130 case CONST_INT:
2131 if (outer_code == SET || outer_code == PLUS)
2132 *total = CONST_7BIT_IMM_P (INTVAL (x)) ? 0 : cost2;
2133 else if (outer_code == AND)
2134 *total = log2constp (~INTVAL (x)) ? 0 : cost2;
2135 else if (outer_code == LE || outer_code == LT || outer_code == EQ)
2136 *total = (INTVAL (x) >= -4 && INTVAL (x) <= 3) ? 0 : cost2;
2137 else if (outer_code == LEU || outer_code == LTU)
2138 *total = (INTVAL (x) >= 0 && INTVAL (x) <= 7) ? 0 : cost2;
2139 else if (outer_code == MULT)
2140 *total = (INTVAL (x) == 2 || INTVAL (x) == 4) ? 0 : cost2;
2141 else if (outer_code == ASHIFT && (INTVAL (x) == 1 || INTVAL (x) == 2))
2142 *total = 0;
2143 else if (outer_code == ASHIFT || outer_code == ASHIFTRT
2144 || outer_code == LSHIFTRT)
2145 *total = (INTVAL (x) >= 0 && INTVAL (x) <= 31) ? 0 : cost2;
2146 else if (outer_code == IOR || outer_code == XOR)
2147 *total = (INTVAL (x) & (INTVAL (x) - 1)) == 0 ? 0 : cost2;
2148 else
2149 *total = cost2;
2150 return true;
2151
2152 case CONST:
2153 case LABEL_REF:
2154 case SYMBOL_REF:
2155 case CONST_DOUBLE:
2156 *total = COSTS_N_INSNS (2);
2157 return true;
2158
2159 case PLUS:
2160 if (GET_MODE (x) == Pmode)
2161 {
2162 if (GET_CODE (XEXP (x, 0)) == MULT
2163 && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)
2164 {
2165 HOST_WIDE_INT val = INTVAL (XEXP (XEXP (x, 0), 1));
2166 if (val == 2 || val == 4)
2167 {
2168 *total = cost2;
2169 *total += rtx_cost (XEXP (XEXP (x, 0), 0), outer_code);
2170 *total += rtx_cost (XEXP (x, 1), outer_code);
2171 return true;
2172 }
2173 }
2174 }
2175
2176 /* fall through */
2177
2178 case MINUS:
2179 case ASHIFT:
2180 case ASHIFTRT:
2181 case LSHIFTRT:
2182 if (GET_MODE (x) == DImode)
2183 *total = 6 * cost2;
2184 return false;
2185
2186 case AND:
2187 case IOR:
2188 case XOR:
2189 if (GET_MODE (x) == DImode)
2190 *total = 2 * cost2;
2191 return false;
2192
2193 case MULT:
2194 if (GET_MODE_SIZE (GET_MODE (x)) <= UNITS_PER_WORD)
2195 *total = COSTS_N_INSNS (3);
2196 return false;
2197
2198 default:
2199 return false;
2200 }
2201}
2202
2203static void
2204bfin_internal_label (FILE *stream, const char *prefix, unsigned long num)
2205{
2206 fprintf (stream, "%s%s$%ld:\n", LOCAL_LABEL_PREFIX, prefix, num);
2207}
2208\f
2209/* Used for communication between {push,pop}_multiple_operation (which
2210 we use not only as a predicate) and the corresponding output functions. */
2211static int first_preg_to_save, first_dreg_to_save;
2212
2213int
2214push_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
2215{
2216 int lastdreg = 8, lastpreg = 6;
2217 int i, group;
2218
2219 first_preg_to_save = lastpreg;
2220 first_dreg_to_save = lastdreg;
2221 for (i = 1, group = 0; i < XVECLEN (op, 0) - 1; i++)
2222 {
2223 rtx t = XVECEXP (op, 0, i);
2224 rtx src, dest;
2225 int regno;
2226
2227 if (GET_CODE (t) != SET)
2228 return 0;
2229
2230 src = SET_SRC (t);
2231 dest = SET_DEST (t);
2232 if (GET_CODE (dest) != MEM || ! REG_P (src))
2233 return 0;
2234 dest = XEXP (dest, 0);
2235 if (GET_CODE (dest) != PLUS
2236 || ! REG_P (XEXP (dest, 0))
2237 || REGNO (XEXP (dest, 0)) != REG_SP
2238 || GET_CODE (XEXP (dest, 1)) != CONST_INT
2239 || INTVAL (XEXP (dest, 1)) != -i * 4)
2240 return 0;
2241
2242 regno = REGNO (src);
2243 if (group == 0)
2244 {
2245 if (D_REGNO_P (regno))
2246 {
2247 group = 1;
2248 first_dreg_to_save = lastdreg = regno - REG_R0;
2249 }
2250 else if (regno >= REG_P0 && regno <= REG_P7)
2251 {
2252 group = 2;
2253 first_preg_to_save = lastpreg = regno - REG_P0;
2254 }
2255 else
2256 return 0;
2257
2258 continue;
2259 }
2260
2261 if (group == 1)
2262 {
2263 if (regno >= REG_P0 && regno <= REG_P7)
2264 {
2265 group = 2;
2266 first_preg_to_save = lastpreg = regno - REG_P0;
2267 }
2268 else if (regno != REG_R0 + lastdreg + 1)
2269 return 0;
2270 else
2271 lastdreg++;
2272 }
2273 else if (group == 2)
2274 {
2275 if (regno != REG_P0 + lastpreg + 1)
2276 return 0;
2277 lastpreg++;
2278 }
2279 }
2280 return 1;
2281}
2282
2283int
2284pop_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
2285{
2286 int lastdreg = 8, lastpreg = 6;
2287 int i, group;
2288
2289 for (i = 1, group = 0; i < XVECLEN (op, 0); i++)
2290 {
2291 rtx t = XVECEXP (op, 0, i);
2292 rtx src, dest;
2293 int regno;
2294
2295 if (GET_CODE (t) != SET)
2296 return 0;
2297
2298 src = SET_SRC (t);
2299 dest = SET_DEST (t);
2300 if (GET_CODE (src) != MEM || ! REG_P (dest))
2301 return 0;
2302 src = XEXP (src, 0);
2303
2304 if (i == 1)
2305 {
2306 if (! REG_P (src) || REGNO (src) != REG_SP)
2307 return 0;
2308 }
2309 else if (GET_CODE (src) != PLUS
2310 || ! REG_P (XEXP (src, 0))
2311 || REGNO (XEXP (src, 0)) != REG_SP
2312 || GET_CODE (XEXP (src, 1)) != CONST_INT
2313 || INTVAL (XEXP (src, 1)) != (i - 1) * 4)
2314 return 0;
2315
2316 regno = REGNO (dest);
2317 if (group == 0)
2318 {
2319 if (regno == REG_R7)
2320 {
2321 group = 1;
2322 lastdreg = 7;
2323 }
2324 else if (regno != REG_P0 + lastpreg - 1)
2325 return 0;
2326 else
2327 lastpreg--;
2328 }
2329 else if (group == 1)
2330 {
2331 if (regno != REG_R0 + lastdreg - 1)
2332 return 0;
2333 else
2334 lastdreg--;
2335 }
2336 }
2337 first_dreg_to_save = lastdreg;
2338 first_preg_to_save = lastpreg;
2339 return 1;
2340}
2341
2342/* Emit assembly code for one multi-register push described by INSN, with
2343 operands in OPERANDS. */
2344
2345void
2346output_push_multiple (rtx insn, rtx *operands)
2347{
2348 char buf[80];
2115ae11 2349 int ok;
2350
9e6a0967 2351 /* Validate the insn again, and compute first_[dp]reg_to_save. */
2115ae11 2352 ok = push_multiple_operation (PATTERN (insn), VOIDmode);
2353 gcc_assert (ok);
2354
9e6a0967 2355 if (first_dreg_to_save == 8)
2356 sprintf (buf, "[--sp] = ( p5:%d );\n", first_preg_to_save);
2357 else if (first_preg_to_save == 6)
2358 sprintf (buf, "[--sp] = ( r7:%d );\n", first_dreg_to_save);
2359 else
2115ae11 2360 sprintf (buf, "[--sp] = ( r7:%d, p5:%d );\n",
2361 first_dreg_to_save, first_preg_to_save);
9e6a0967 2362
2363 output_asm_insn (buf, operands);
2364}
2365
2366/* Emit assembly code for one multi-register pop described by INSN, with
2367 operands in OPERANDS. */
2368
2369void
2370output_pop_multiple (rtx insn, rtx *operands)
2371{
2372 char buf[80];
2115ae11 2373 int ok;
2374
9e6a0967 2375 /* Validate the insn again, and compute first_[dp]reg_to_save. */
2115ae11 2376 ok = pop_multiple_operation (PATTERN (insn), VOIDmode);
2377 gcc_assert (ok);
9e6a0967 2378
2379 if (first_dreg_to_save == 8)
2380 sprintf (buf, "( p5:%d ) = [sp++];\n", first_preg_to_save);
2381 else if (first_preg_to_save == 6)
2382 sprintf (buf, "( r7:%d ) = [sp++];\n", first_dreg_to_save);
2383 else
2115ae11 2384 sprintf (buf, "( r7:%d, p5:%d ) = [sp++];\n",
2385 first_dreg_to_save, first_preg_to_save);
9e6a0967 2386
2387 output_asm_insn (buf, operands);
2388}
2389
2390/* Adjust DST and SRC by OFFSET bytes, and generate one move in mode MODE. */
2391
2392static void
2393single_move_for_strmov (rtx dst, rtx src, enum machine_mode mode, HOST_WIDE_INT offset)
2394{
2395 rtx scratch = gen_reg_rtx (mode);
2396 rtx srcmem, dstmem;
2397
2398 srcmem = adjust_address_nv (src, mode, offset);
2399 dstmem = adjust_address_nv (dst, mode, offset);
2400 emit_move_insn (scratch, srcmem);
2401 emit_move_insn (dstmem, scratch);
2402}
2403
2404/* Expand a string move operation of COUNT_EXP bytes from SRC to DST, with
2405 alignment ALIGN_EXP. Return true if successful, false if we should fall
2406 back on a different method. */
2407
2408bool
2409bfin_expand_strmov (rtx dst, rtx src, rtx count_exp, rtx align_exp)
2410{
2411 rtx srcreg, destreg, countreg;
2412 HOST_WIDE_INT align = 0;
2413 unsigned HOST_WIDE_INT count = 0;
2414
2415 if (GET_CODE (align_exp) == CONST_INT)
2416 align = INTVAL (align_exp);
2417 if (GET_CODE (count_exp) == CONST_INT)
2418 {
2419 count = INTVAL (count_exp);
2420#if 0
2421 if (!TARGET_INLINE_ALL_STRINGOPS && count > 64)
2422 return false;
2423#endif
2424 }
2425
2426 /* If optimizing for size, only do single copies inline. */
2427 if (optimize_size)
2428 {
2429 if (count == 2 && align < 2)
2430 return false;
2431 if (count == 4 && align < 4)
2432 return false;
2433 if (count != 1 && count != 2 && count != 4)
2434 return false;
2435 }
2436 if (align < 2 && count != 1)
2437 return false;
2438
2439 destreg = copy_to_mode_reg (Pmode, XEXP (dst, 0));
2440 if (destreg != XEXP (dst, 0))
2441 dst = replace_equiv_address_nv (dst, destreg);
2442 srcreg = copy_to_mode_reg (Pmode, XEXP (src, 0));
2443 if (srcreg != XEXP (src, 0))
2444 src = replace_equiv_address_nv (src, srcreg);
2445
2446 if (count != 0 && align >= 2)
2447 {
2448 unsigned HOST_WIDE_INT offset = 0;
2449
2450 if (align >= 4)
2451 {
2452 if ((count & ~3) == 4)
2453 {
2454 single_move_for_strmov (dst, src, SImode, offset);
2455 offset = 4;
2456 }
2457 else if (count & ~3)
2458 {
2459 HOST_WIDE_INT new_count = ((count >> 2) & 0x3fffffff) - 1;
2460 countreg = copy_to_mode_reg (Pmode, GEN_INT (new_count));
2461
2462 emit_insn (gen_rep_movsi (destreg, srcreg, countreg, destreg, srcreg));
2463 }
2464 }
2465 else
2466 {
2467 if ((count & ~1) == 2)
2468 {
2469 single_move_for_strmov (dst, src, HImode, offset);
2470 offset = 2;
2471 }
2472 else if (count & ~1)
2473 {
2474 HOST_WIDE_INT new_count = ((count >> 1) & 0x7fffffff) - 1;
2475 countreg = copy_to_mode_reg (Pmode, GEN_INT (new_count));
2476
2477 emit_insn (gen_rep_movhi (destreg, srcreg, countreg, destreg, srcreg));
2478 }
2479 }
2480 if (count & 2)
2481 {
2482 single_move_for_strmov (dst, src, HImode, offset);
2483 offset += 2;
2484 }
2485 if (count & 1)
2486 {
2487 single_move_for_strmov (dst, src, QImode, offset);
2488 }
2489 return true;
2490 }
2491 return false;
2492}
2493
2494\f
2495static int
2496bfin_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
2497{
2498 enum attr_type insn_type, dep_insn_type;
2499 int dep_insn_code_number;
2500
2501 /* Anti and output dependencies have zero cost. */
2502 if (REG_NOTE_KIND (link) != 0)
2503 return 0;
2504
2505 dep_insn_code_number = recog_memoized (dep_insn);
2506
2507 /* If we can't recognize the insns, we can't really do anything. */
2508 if (dep_insn_code_number < 0 || recog_memoized (insn) < 0)
2509 return cost;
2510
2511 insn_type = get_attr_type (insn);
2512 dep_insn_type = get_attr_type (dep_insn);
2513
2514 if (dep_insn_type == TYPE_MOVE || dep_insn_type == TYPE_MCLD)
2515 {
2516 rtx pat = PATTERN (dep_insn);
2517 rtx dest = SET_DEST (pat);
2518 rtx src = SET_SRC (pat);
2519 if (! ADDRESS_REGNO_P (REGNO (dest)) || ! D_REGNO_P (REGNO (src)))
2520 return cost;
2521 return cost + (dep_insn_type == TYPE_MOVE ? 4 : 3);
2522 }
2523
2524 return cost;
2525}
2526\f
2527/* We use the machine specific reorg pass for emitting CSYNC instructions
2528 after conditional branches as needed.
2529
2530 The Blackfin is unusual in that a code sequence like
2531 if cc jump label
2532 r0 = (p0)
2533 may speculatively perform the load even if the condition isn't true. This
2534 happens for a branch that is predicted not taken, because the pipeline
2535 isn't flushed or stalled, so the early stages of the following instructions,
2536 which perform the memory reference, are allowed to execute before the
2537 jump condition is evaluated.
2538 Therefore, we must insert additional instructions in all places where this
442e3cb9 2539 could lead to incorrect behavior. The manual recommends CSYNC, while
9e6a0967 2540 VDSP seems to use NOPs (even though its corresponding compiler option is
2541 named CSYNC).
2542
2543 When optimizing for speed, we emit NOPs, which seems faster than a CSYNC.
2544 When optimizing for size, we turn the branch into a predicted taken one.
2545 This may be slower due to mispredicts, but saves code size. */
2546
2547static void
2548bfin_reorg (void)
2549{
2550 rtx insn, last_condjump = NULL_RTX;
2551 int cycles_since_jump = INT_MAX;
2552
b00f0d99 2553 if (! TARGET_SPECLD_ANOMALY || ! TARGET_CSYNC_ANOMALY)
9e6a0967 2554 return;
2555
b00f0d99 2556 /* First pass: find predicted-false branches; if something after them
2557 needs nops, insert them or change the branch to predict true. */
9e6a0967 2558 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
2559 {
2560 rtx pat;
2561
2562 if (NOTE_P (insn) || BARRIER_P (insn) || LABEL_P (insn))
2563 continue;
2564
2565 pat = PATTERN (insn);
2566 if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER
2567 || GET_CODE (pat) == ASM_INPUT || GET_CODE (pat) == ADDR_VEC
2568 || GET_CODE (pat) == ADDR_DIFF_VEC || asm_noperands (pat) >= 0)
2569 continue;
2570
2571 if (JUMP_P (insn))
2572 {
2573 if (any_condjump_p (insn)
2574 && ! cbranch_predicted_taken_p (insn))
2575 {
2576 last_condjump = insn;
2577 cycles_since_jump = 0;
2578 }
2579 else
2580 cycles_since_jump = INT_MAX;
2581 }
2582 else if (INSN_P (insn))
2583 {
2584 enum attr_type type = get_attr_type (insn);
b00f0d99 2585 int delay_needed = 0;
9e6a0967 2586 if (cycles_since_jump < INT_MAX)
2587 cycles_since_jump++;
2588
b00f0d99 2589 if (type == TYPE_MCLD && TARGET_SPECLD_ANOMALY)
2590 {
2591 rtx pat = single_set (insn);
2592 if (may_trap_p (SET_SRC (pat)))
2593 delay_needed = 3;
2594 }
2595 else if (type == TYPE_SYNC && TARGET_CSYNC_ANOMALY)
2596 delay_needed = 4;
2597
2598 if (delay_needed > cycles_since_jump)
9e6a0967 2599 {
2600 rtx pat;
b00f0d99 2601 int num_clobbers;
2602 rtx *op = recog_data.operand;
9e6a0967 2603
b00f0d99 2604 delay_needed -= cycles_since_jump;
2605
2606 extract_insn (last_condjump);
2607 if (optimize_size)
9e6a0967 2608 {
b00f0d99 2609 pat = gen_cbranch_predicted_taken (op[0], op[1], op[2],
2610 op[3]);
9e6a0967 2611 cycles_since_jump = INT_MAX;
2612 }
b00f0d99 2613 else
2614 /* Do not adjust cycles_since_jump in this case, so that
2615 we'll increase the number of NOPs for a subsequent insn
2616 if necessary. */
2617 pat = gen_cbranch_with_nops (op[0], op[1], op[2], op[3],
2618 GEN_INT (delay_needed));
2619 PATTERN (last_condjump) = pat;
2620 INSN_CODE (last_condjump) = recog (pat, insn, &num_clobbers);
2621 }
2622 }
2623 }
2624 /* Second pass: for predicted-true branches, see if anything at the
2625 branch destination needs extra nops. */
2626 if (! TARGET_CSYNC_ANOMALY)
2627 return;
2628
2629 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
2630 {
2631 if (JUMP_P (insn)
2632 && any_condjump_p (insn)
2633 && (INSN_CODE (insn) == CODE_FOR_cbranch_predicted_taken
2634 || cbranch_predicted_taken_p (insn)))
2635 {
2636 rtx target = JUMP_LABEL (insn);
2637 rtx label = target;
2638 cycles_since_jump = 0;
2639 for (; target && cycles_since_jump < 3; target = NEXT_INSN (target))
2640 {
2641 rtx pat;
2642
2643 if (NOTE_P (target) || BARRIER_P (target) || LABEL_P (target))
2644 continue;
2645
2646 pat = PATTERN (target);
2647 if (GET_CODE (pat) == USE || GET_CODE (pat) == CLOBBER
2648 || GET_CODE (pat) == ASM_INPUT || GET_CODE (pat) == ADDR_VEC
2649 || GET_CODE (pat) == ADDR_DIFF_VEC || asm_noperands (pat) >= 0)
2650 continue;
2651
2652 if (INSN_P (target))
2653 {
2654 enum attr_type type = get_attr_type (target);
2655 int delay_needed = 0;
2656 if (cycles_since_jump < INT_MAX)
2657 cycles_since_jump++;
2658
2659 if (type == TYPE_SYNC && TARGET_CSYNC_ANOMALY)
2660 delay_needed = 2;
2661
2662 if (delay_needed > cycles_since_jump)
2663 {
2664 rtx prev = prev_real_insn (label);
2665 delay_needed -= cycles_since_jump;
2666 if (dump_file)
2667 fprintf (dump_file, "Adding %d nops after %d\n",
2668 delay_needed, INSN_UID (label));
2669 if (JUMP_P (prev)
2670 && INSN_CODE (prev) == CODE_FOR_cbranch_with_nops)
2671 {
2672 rtx x;
2673 HOST_WIDE_INT v;
2674
2675 if (dump_file)
2676 fprintf (dump_file,
2677 "Reducing nops on insn %d.\n",
2678 INSN_UID (prev));
2679 x = PATTERN (prev);
2680 x = XVECEXP (x, 0, 1);
2681 v = INTVAL (XVECEXP (x, 0, 0)) - delay_needed;
2682 XVECEXP (x, 0, 0) = GEN_INT (v);
2683 }
2684 while (delay_needed-- > 0)
2685 emit_insn_after (gen_nop (), label);
2686 break;
2687 }
2688 }
9e6a0967 2689 }
2690 }
2691 }
2692}
2693\f
2694/* Handle interrupt_handler, exception_handler and nmi_handler function
2695 attributes; arguments as in struct attribute_spec.handler. */
2696
2697static tree
2698handle_int_attribute (tree *node, tree name,
2699 tree args ATTRIBUTE_UNUSED,
2700 int flags ATTRIBUTE_UNUSED,
2701 bool *no_add_attrs)
2702{
2703 tree x = *node;
2704 if (TREE_CODE (x) == FUNCTION_DECL)
2705 x = TREE_TYPE (x);
2706
2707 if (TREE_CODE (x) != FUNCTION_TYPE)
2708 {
9b2d6d13 2709 warning (OPT_Wattributes, "%qs attribute only applies to functions",
9e6a0967 2710 IDENTIFIER_POINTER (name));
2711 *no_add_attrs = true;
2712 }
2713 else if (funkind (x) != SUBROUTINE)
2714 error ("multiple function type attributes specified");
2715
2716 return NULL_TREE;
2717}
2718
2719/* Return 0 if the attributes for two types are incompatible, 1 if they
2720 are compatible, and 2 if they are nearly compatible (which causes a
2721 warning to be generated). */
2722
2723static int
2724bfin_comp_type_attributes (tree type1, tree type2)
2725{
2726 e_funkind kind1, kind2;
2727
2728 if (TREE_CODE (type1) != FUNCTION_TYPE)
2729 return 1;
2730
2731 kind1 = funkind (type1);
2732 kind2 = funkind (type2);
2733
2734 if (kind1 != kind2)
2735 return 0;
2736
2737 /* Check for mismatched modifiers */
2738 if (!lookup_attribute ("nesting", TYPE_ATTRIBUTES (type1))
2739 != !lookup_attribute ("nesting", TYPE_ATTRIBUTES (type2)))
2740 return 0;
2741
2742 if (!lookup_attribute ("saveall", TYPE_ATTRIBUTES (type1))
2743 != !lookup_attribute ("saveall", TYPE_ATTRIBUTES (type2)))
2744 return 0;
2745
2746 if (!lookup_attribute ("kspisusp", TYPE_ATTRIBUTES (type1))
2747 != !lookup_attribute ("kspisusp", TYPE_ATTRIBUTES (type2)))
2748 return 0;
2749
7b6ef6dd 2750 if (!lookup_attribute ("longcall", TYPE_ATTRIBUTES (type1))
2751 != !lookup_attribute ("longcall", TYPE_ATTRIBUTES (type2)))
2752 return 0;
2753
9e6a0967 2754 return 1;
2755}
2756
7b6ef6dd 2757/* Handle a "longcall" or "shortcall" attribute; arguments as in
2758 struct attribute_spec.handler. */
2759
2760static tree
2761bfin_handle_longcall_attribute (tree *node, tree name,
2762 tree args ATTRIBUTE_UNUSED,
2763 int flags ATTRIBUTE_UNUSED,
2764 bool *no_add_attrs)
2765{
2766 if (TREE_CODE (*node) != FUNCTION_TYPE
2767 && TREE_CODE (*node) != FIELD_DECL
2768 && TREE_CODE (*node) != TYPE_DECL)
2769 {
2770 warning (OPT_Wattributes, "`%s' attribute only applies to functions",
2771 IDENTIFIER_POINTER (name));
2772 *no_add_attrs = true;
2773 }
2774
2775 if ((strcmp (IDENTIFIER_POINTER (name), "longcall") == 0
2776 && lookup_attribute ("shortcall", TYPE_ATTRIBUTES (*node)))
2777 || (strcmp (IDENTIFIER_POINTER (name), "shortcall") == 0
2778 && lookup_attribute ("longcall", TYPE_ATTRIBUTES (*node))))
2779 {
2780 warning (OPT_Wattributes,
2781 "can't apply both longcall and shortcall attributes to the same function");
2782 *no_add_attrs = true;
2783 }
2784
2785 return NULL_TREE;
2786}
2787
9e6a0967 2788/* Table of valid machine attributes. */
2789const struct attribute_spec bfin_attribute_table[] =
2790{
2791 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
2792 { "interrupt_handler", 0, 0, false, true, true, handle_int_attribute },
2793 { "exception_handler", 0, 0, false, true, true, handle_int_attribute },
2794 { "nmi_handler", 0, 0, false, true, true, handle_int_attribute },
2795 { "nesting", 0, 0, false, true, true, NULL },
2796 { "kspisusp", 0, 0, false, true, true, NULL },
2797 { "saveall", 0, 0, false, true, true, NULL },
7b6ef6dd 2798 { "longcall", 0, 0, false, true, true, bfin_handle_longcall_attribute },
2799 { "shortcall", 0, 0, false, true, true, bfin_handle_longcall_attribute },
9e6a0967 2800 { NULL, 0, 0, false, false, false, NULL }
2801};
2802\f
2803/* Output the assembler code for a thunk function. THUNK_DECL is the
2804 declaration for the thunk function itself, FUNCTION is the decl for
2805 the target function. DELTA is an immediate constant offset to be
2806 added to THIS. If VCALL_OFFSET is nonzero, the word at
2807 *(*this + vcall_offset) should be added to THIS. */
2808
2809static void
2810bfin_output_mi_thunk (FILE *file ATTRIBUTE_UNUSED,
2811 tree thunk ATTRIBUTE_UNUSED, HOST_WIDE_INT delta,
2812 HOST_WIDE_INT vcall_offset, tree function)
2813{
2814 rtx xops[3];
2815 /* The this parameter is passed as the first argument. */
2816 rtx this = gen_rtx_REG (Pmode, REG_R0);
2817
2818 /* Adjust the this parameter by a fixed constant. */
2819 if (delta)
2820 {
2821 xops[1] = this;
2822 if (delta >= -64 && delta <= 63)
2823 {
2824 xops[0] = GEN_INT (delta);
2825 output_asm_insn ("%1 += %0;", xops);
2826 }
2827 else if (delta >= -128 && delta < -64)
2828 {
2829 xops[0] = GEN_INT (delta + 64);
2830 output_asm_insn ("%1 += -64; %1 += %0;", xops);
2831 }
2832 else if (delta > 63 && delta <= 126)
2833 {
2834 xops[0] = GEN_INT (delta - 63);
2835 output_asm_insn ("%1 += 63; %1 += %0;", xops);
2836 }
2837 else
2838 {
2839 xops[0] = GEN_INT (delta);
2840 output_asm_insn ("r3.l = %h0; r3.h = %d0; %1 = %1 + r3;", xops);
2841 }
2842 }
2843
2844 /* Adjust the this parameter by a value stored in the vtable. */
2845 if (vcall_offset)
2846 {
2847 rtx p2tmp = gen_rtx_REG (Pmode, REG_P2);
2848 rtx tmp = gen_rtx_REG (Pmode, REG_R2);
2849
2850 xops[1] = tmp;
2851 xops[2] = p2tmp;
2852 output_asm_insn ("%2 = r0; %2 = [%2];", xops);
2853
2854 /* Adjust the this parameter. */
2855 xops[0] = gen_rtx_MEM (Pmode, plus_constant (p2tmp, vcall_offset));
2856 if (!memory_operand (xops[0], Pmode))
2857 {
2858 rtx tmp2 = gen_rtx_REG (Pmode, REG_P1);
2859 xops[0] = GEN_INT (vcall_offset);
2860 xops[1] = tmp2;
2861 output_asm_insn ("%h1 = %h0; %d1 = %d0; %2 = %2 + %1", xops);
2862 xops[0] = gen_rtx_MEM (Pmode, p2tmp);
2863 }
2864 xops[2] = this;
2865 output_asm_insn ("%1 = %0; %2 = %2 + %1;", xops);
2866 }
2867
2868 xops[0] = XEXP (DECL_RTL (function), 0);
2869 if (1 || !flag_pic || (*targetm.binds_local_p) (function))
2870 output_asm_insn ("jump.l\t%P0", xops);
2871}
2872\f
6e6ce962 2873/* Codes for all the Blackfin builtins. */
2874enum bfin_builtins
2875{
2876 BFIN_BUILTIN_CSYNC,
2877 BFIN_BUILTIN_SSYNC,
2878 BFIN_BUILTIN_MAX
2879};
2880
684389d2 2881#define def_builtin(NAME, TYPE, CODE) \
2882do { \
2883 lang_hooks.builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD, \
2884 NULL, NULL_TREE); \
e43914a7 2885} while (0)
2886
2887/* Set up all builtin functions for this target. */
2888static void
2889bfin_init_builtins (void)
2890{
2891 tree void_ftype_void
2892 = build_function_type (void_type_node, void_list_node);
2893
2894 /* Add the remaining MMX insns with somewhat more complicated types. */
2895 def_builtin ("__builtin_bfin_csync", void_ftype_void, BFIN_BUILTIN_CSYNC);
2896 def_builtin ("__builtin_bfin_ssync", void_ftype_void, BFIN_BUILTIN_SSYNC);
2897}
2898
2899/* Expand an expression EXP that calls a built-in function,
2900 with result going to TARGET if that's convenient
2901 (and in mode MODE if that's convenient).
2902 SUBTARGET may be used as the target for computing one of EXP's operands.
2903 IGNORE is nonzero if the value is to be ignored. */
2904
2905static rtx
2906bfin_expand_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
2907 rtx subtarget ATTRIBUTE_UNUSED,
2908 enum machine_mode mode ATTRIBUTE_UNUSED,
2909 int ignore ATTRIBUTE_UNUSED)
2910{
2911 tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
2912 unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
2913
2914 switch (fcode)
2915 {
2916 case BFIN_BUILTIN_CSYNC:
2917 emit_insn (gen_csync ());
2918 return 0;
2919 case BFIN_BUILTIN_SSYNC:
2920 emit_insn (gen_ssync ());
2921 return 0;
2922
2923 default:
2924 gcc_unreachable ();
2925 }
2926}
2927\f
2928#undef TARGET_INIT_BUILTINS
2929#define TARGET_INIT_BUILTINS bfin_init_builtins
2930
2931#undef TARGET_EXPAND_BUILTIN
2932#define TARGET_EXPAND_BUILTIN bfin_expand_builtin
2933
9e6a0967 2934#undef TARGET_ASM_GLOBALIZE_LABEL
2935#define TARGET_ASM_GLOBALIZE_LABEL bfin_globalize_label
2936
2937#undef TARGET_ASM_FILE_START
2938#define TARGET_ASM_FILE_START output_file_start
2939
2940#undef TARGET_ATTRIBUTE_TABLE
2941#define TARGET_ATTRIBUTE_TABLE bfin_attribute_table
2942
2943#undef TARGET_COMP_TYPE_ATTRIBUTES
2944#define TARGET_COMP_TYPE_ATTRIBUTES bfin_comp_type_attributes
2945
2946#undef TARGET_RTX_COSTS
2947#define TARGET_RTX_COSTS bfin_rtx_costs
2948
2949#undef TARGET_ADDRESS_COST
2950#define TARGET_ADDRESS_COST bfin_address_cost
2951
2952#undef TARGET_ASM_INTERNAL_LABEL
2953#define TARGET_ASM_INTERNAL_LABEL bfin_internal_label
2954
2955#undef TARGET_MACHINE_DEPENDENT_REORG
2956#define TARGET_MACHINE_DEPENDENT_REORG bfin_reorg
2957
2958#undef TARGET_FUNCTION_OK_FOR_SIBCALL
2959#define TARGET_FUNCTION_OK_FOR_SIBCALL bfin_function_ok_for_sibcall
2960
2961#undef TARGET_ASM_OUTPUT_MI_THUNK
2962#define TARGET_ASM_OUTPUT_MI_THUNK bfin_output_mi_thunk
2963#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
2964#define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_tree_hwi_hwi_tree_true
2965
2966#undef TARGET_SCHED_ADJUST_COST
2967#define TARGET_SCHED_ADJUST_COST bfin_adjust_cost
2968
2969#undef TARGET_PROMOTE_PROTOTYPES
2970#define TARGET_PROMOTE_PROTOTYPES hook_bool_tree_true
2971#undef TARGET_PROMOTE_FUNCTION_ARGS
2972#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true
2973#undef TARGET_PROMOTE_FUNCTION_RETURN
2974#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true
2975
2976#undef TARGET_ARG_PARTIAL_BYTES
2977#define TARGET_ARG_PARTIAL_BYTES bfin_arg_partial_bytes
2978
2979#undef TARGET_PASS_BY_REFERENCE
2980#define TARGET_PASS_BY_REFERENCE bfin_pass_by_reference
2981
2982#undef TARGET_SETUP_INCOMING_VARARGS
2983#define TARGET_SETUP_INCOMING_VARARGS setup_incoming_varargs
2984
2985#undef TARGET_STRUCT_VALUE_RTX
2986#define TARGET_STRUCT_VALUE_RTX bfin_struct_value_rtx
2987
2988#undef TARGET_VECTOR_MODE_SUPPORTED_P
2989#define TARGET_VECTOR_MODE_SUPPORTED_P bfin_vector_mode_supported_p
2990
f2a5d439 2991#undef TARGET_HANDLE_OPTION
2992#define TARGET_HANDLE_OPTION bfin_handle_option
2993
b00f0d99 2994#undef TARGET_DEFAULT_TARGET_FLAGS
2995#define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
2996
9e6a0967 2997struct gcc_target targetm = TARGET_INITIALIZER;