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