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