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