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