1 /* The Blackfin code generation auxiliary output file.
2    Copyright (C) 2005-2022 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.cc 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 ("cannot use multiple stack checking methods together");
2386 
2387   if (TARGET_ID_SHARED_LIBRARY && TARGET_FDPIC)
2388     error ("ID shared libraries and FD-PIC mode cannot 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%> cannot 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                  "cannot apply both %<longcall%> and %<shortcall%> attributes "
4767                  "to the same function");
4768       *no_add_attrs = true;
4769     }
4770 
4771   return NULL_TREE;
4772 }
4773 
4774 /* Handle a "l1_text" attribute; arguments as in
4775    struct attribute_spec.handler.  */
4776 
4777 static tree
bfin_handle_l1_text_attribute(tree * node,tree name,tree ARG_UNUSED (args),int ARG_UNUSED (flags),bool * no_add_attrs)4778 bfin_handle_l1_text_attribute (tree *node, tree name, tree ARG_UNUSED (args),
4779                                      int ARG_UNUSED (flags), bool *no_add_attrs)
4780 {
4781   tree decl = *node;
4782 
4783   if (TREE_CODE (decl) != FUNCTION_DECL)
4784     {
4785       error ("%qE attribute only applies to functions",
4786                name);
4787       *no_add_attrs = true;
4788     }
4789 
4790   /* The decl may have already been given a section attribute
4791      from a previous declaration. Ensure they match.  */
4792   else if (DECL_SECTION_NAME (decl) != NULL
4793              && strcmp (DECL_SECTION_NAME (decl),
4794                           ".l1.text") != 0)
4795     {
4796       error ("section of %q+D conflicts with previous declaration",
4797                decl);
4798       *no_add_attrs = true;
4799     }
4800   else
4801     set_decl_section_name (decl, ".l1.text");
4802 
4803   return NULL_TREE;
4804 }
4805 
4806 /* Handle a "l1_data", "l1_data_A" or "l1_data_B" attribute;
4807    arguments as in struct attribute_spec.handler.  */
4808 
4809 static tree
bfin_handle_l1_data_attribute(tree * node,tree name,tree ARG_UNUSED (args),int ARG_UNUSED (flags),bool * no_add_attrs)4810 bfin_handle_l1_data_attribute (tree *node, tree name, tree ARG_UNUSED (args),
4811                                      int ARG_UNUSED (flags), bool *no_add_attrs)
4812 {
4813   tree decl = *node;
4814 
4815   if (TREE_CODE (decl) != VAR_DECL)
4816     {
4817       error ("%qE attribute only applies to variables",
4818                name);
4819       *no_add_attrs = true;
4820     }
4821   else if (current_function_decl != NULL_TREE
4822              && !TREE_STATIC (decl))
4823     {
4824       error ("%qE attribute cannot be specified for local variables",
4825                name);
4826       *no_add_attrs = true;
4827     }
4828   else
4829     {
4830       const char *section_name;
4831 
4832       if (strcmp (IDENTIFIER_POINTER (name), "l1_data") == 0)
4833           section_name = ".l1.data";
4834       else if (strcmp (IDENTIFIER_POINTER (name), "l1_data_A") == 0)
4835           section_name = ".l1.data.A";
4836       else if (strcmp (IDENTIFIER_POINTER (name), "l1_data_B") == 0)
4837           section_name = ".l1.data.B";
4838       else
4839           gcc_unreachable ();
4840 
4841       /* The decl may have already been given a section attribute
4842            from a previous declaration. Ensure they match.  */
4843       if (DECL_SECTION_NAME (decl) != NULL
4844             && strcmp (DECL_SECTION_NAME (decl),
4845                          section_name) != 0)
4846           {
4847             error ("section of %q+D conflicts with previous declaration",
4848                      decl);
4849             *no_add_attrs = true;
4850           }
4851       else
4852           set_decl_section_name (decl, section_name);
4853     }
4854 
4855  return NULL_TREE;
4856 }
4857 
4858 /* Handle a "l2" attribute; arguments as in struct attribute_spec.handler.  */
4859 
4860 static tree
bfin_handle_l2_attribute(tree * node,tree ARG_UNUSED (name),tree ARG_UNUSED (args),int ARG_UNUSED (flags),bool * no_add_attrs)4861 bfin_handle_l2_attribute (tree *node, tree ARG_UNUSED (name),
4862                                 tree ARG_UNUSED (args), int ARG_UNUSED (flags),
4863                                 bool *no_add_attrs)
4864 {
4865   tree decl = *node;
4866 
4867   if (TREE_CODE (decl) == FUNCTION_DECL)
4868     {
4869       if (DECL_SECTION_NAME (decl) != NULL
4870             && strcmp (DECL_SECTION_NAME (decl),
4871                          ".l2.text") != 0)
4872           {
4873             error ("section of %q+D conflicts with previous declaration",
4874                      decl);
4875             *no_add_attrs = true;
4876           }
4877       else
4878           set_decl_section_name (decl, ".l2.text");
4879     }
4880   else if (TREE_CODE (decl) == VAR_DECL)
4881     {
4882       if (DECL_SECTION_NAME (decl) != NULL
4883             && strcmp (DECL_SECTION_NAME (decl),
4884                          ".l2.data") != 0)
4885           {
4886             error ("section of %q+D conflicts with previous declaration",
4887                      decl);
4888             *no_add_attrs = true;
4889           }
4890       else
4891           set_decl_section_name (decl, ".l2.data");
4892     }
4893 
4894   return NULL_TREE;
4895 }
4896 
4897 /* Table of valid machine attributes.  */
4898 static const struct attribute_spec bfin_attribute_table[] =
4899 {
4900   /* { name, min_len, max_len, decl_req, type_req, fn_type_req,
4901        affects_type_identity, handler, exclude } */
4902   { "interrupt_handler", 0, 0, false, true,  true, false,
4903     handle_int_attribute, NULL },
4904   { "exception_handler", 0, 0, false, true,  true, false,
4905     handle_int_attribute, NULL },
4906   { "nmi_handler", 0, 0, false, true,  true, false, handle_int_attribute,
4907     NULL },
4908   { "nesting", 0, 0, false, true,  true, false, NULL, NULL },
4909   { "kspisusp", 0, 0, false, true,  true, false, NULL, NULL },
4910   { "saveall", 0, 0, false, true,  true, false, NULL, NULL },
4911   { "longcall",  0, 0, false, true,  true, false,
4912     bfin_handle_longcall_attribute, NULL },
4913   { "shortcall", 0, 0, false, true,  true, false,
4914     bfin_handle_longcall_attribute, NULL },
4915   { "l1_text", 0, 0, true, false, false, false,
4916     bfin_handle_l1_text_attribute, NULL },
4917   { "l1_data", 0, 0, true, false, false, false,
4918     bfin_handle_l1_data_attribute, NULL },
4919   { "l1_data_A", 0, 0, true, false, false, false,
4920     bfin_handle_l1_data_attribute, NULL },
4921   { "l1_data_B", 0, 0, true, false, false, false,
4922     bfin_handle_l1_data_attribute, NULL },
4923   { "l2", 0, 0, true, false, false, false, bfin_handle_l2_attribute, NULL },
4924   { NULL, 0, 0, false, false, false, false, NULL, NULL }
4925 };
4926 
4927 /* Implementation of TARGET_ASM_INTEGER.  When using FD-PIC, we need to
4928    tell the assembler to generate pointers to function descriptors in
4929    some cases.  */
4930 
4931 static bool
bfin_assemble_integer(rtx value,unsigned int size,int aligned_p)4932 bfin_assemble_integer (rtx value, unsigned int size, int aligned_p)
4933 {
4934   if (TARGET_FDPIC && size == UNITS_PER_WORD)
4935     {
4936       if (GET_CODE (value) == SYMBOL_REF
4937             && SYMBOL_REF_FUNCTION_P (value))
4938           {
4939             fputs ("\t.picptr\tfuncdesc(", asm_out_file);
4940             output_addr_const (asm_out_file, value);
4941             fputs (")\n", asm_out_file);
4942             return true;
4943           }
4944       if (!aligned_p)
4945           {
4946             /* We've set the unaligned SI op to NULL, so we always have to
4947                handle the unaligned case here.  */
4948             assemble_integer_with_op ("\t.4byte\t", value);
4949             return true;
4950           }
4951     }
4952   return default_assemble_integer (value, size, aligned_p);
4953 }
4954 
4955 /* Output the assembler code for a thunk function.  THUNK_DECL is the
4956    declaration for the thunk function itself, FUNCTION is the decl for
4957    the target function.  DELTA is an immediate constant offset to be
4958    added to THIS.  If VCALL_OFFSET is nonzero, the word at
4959    *(*this + vcall_offset) should be added to THIS.  */
4960 
4961 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)4962 bfin_output_mi_thunk (FILE *file ATTRIBUTE_UNUSED,
4963                           tree thunk ATTRIBUTE_UNUSED, HOST_WIDE_INT delta,
4964                           HOST_WIDE_INT vcall_offset, tree function)
4965 {
4966   const char *fnname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (thunk));
4967   rtx xops[3];
4968   /* The this parameter is passed as the first argument.  */
4969   rtx this_rtx = gen_rtx_REG (Pmode, REG_R0);
4970 
4971   assemble_start_function (thunk, fnname);
4972   /* Adjust the this parameter by a fixed constant.  */
4973   if (delta)
4974     {
4975       xops[1] = this_rtx;
4976       if (delta >= -64 && delta <= 63)
4977           {
4978             xops[0] = GEN_INT (delta);
4979             output_asm_insn ("%1 += %0;", xops);
4980           }
4981       else if (delta >= -128 && delta < -64)
4982           {
4983             xops[0] = GEN_INT (delta + 64);
4984             output_asm_insn ("%1 += -64; %1 += %0;", xops);
4985           }
4986       else if (delta > 63 && delta <= 126)
4987           {
4988             xops[0] = GEN_INT (delta - 63);
4989             output_asm_insn ("%1 += 63; %1 += %0;", xops);
4990           }
4991       else
4992           {
4993             xops[0] = GEN_INT (delta);
4994             output_asm_insn ("r3.l = %h0; r3.h = %d0; %1 = %1 + r3;", xops);
4995           }
4996     }
4997 
4998   /* Adjust the this parameter by a value stored in the vtable.  */
4999   if (vcall_offset)
5000     {
5001       rtx p2tmp = gen_rtx_REG (Pmode, REG_P2);
5002       rtx tmp = gen_rtx_REG (Pmode, REG_R3);
5003 
5004       xops[1] = tmp;
5005       xops[2] = p2tmp;
5006       output_asm_insn ("%2 = r0; %2 = [%2];", xops);
5007 
5008       /* Adjust the this parameter.  */
5009       xops[0] = gen_rtx_MEM (Pmode, plus_constant (Pmode, p2tmp,
5010                                                                vcall_offset));
5011       if (!memory_operand (xops[0], Pmode))
5012           {
5013             rtx tmp2 = gen_rtx_REG (Pmode, REG_P1);
5014             xops[0] = GEN_INT (vcall_offset);
5015             xops[1] = tmp2;
5016             output_asm_insn ("%h1 = %h0; %d1 = %d0; %2 = %2 + %1", xops);
5017             xops[0] = gen_rtx_MEM (Pmode, p2tmp);
5018           }
5019       xops[2] = this_rtx;
5020       output_asm_insn ("%1 = %0; %2 = %2 + %1;", xops);
5021     }
5022 
5023   xops[0] = XEXP (DECL_RTL (function), 0);
5024   if (1 || !flag_pic || (*targetm.binds_local_p) (function))
5025     output_asm_insn ("jump.l\t%P0", xops);
5026   assemble_end_function (thunk, fnname);
5027 }
5028 
5029 /* Codes for all the Blackfin builtins.  */
5030 enum bfin_builtins
5031 {
5032   BFIN_BUILTIN_CSYNC,
5033   BFIN_BUILTIN_SSYNC,
5034   BFIN_BUILTIN_ONES,
5035   BFIN_BUILTIN_COMPOSE_2X16,
5036   BFIN_BUILTIN_EXTRACTLO,
5037   BFIN_BUILTIN_EXTRACTHI,
5038 
5039   BFIN_BUILTIN_SSADD_2X16,
5040   BFIN_BUILTIN_SSSUB_2X16,
5041   BFIN_BUILTIN_SSADDSUB_2X16,
5042   BFIN_BUILTIN_SSSUBADD_2X16,
5043   BFIN_BUILTIN_MULT_2X16,
5044   BFIN_BUILTIN_MULTR_2X16,
5045   BFIN_BUILTIN_NEG_2X16,
5046   BFIN_BUILTIN_ABS_2X16,
5047   BFIN_BUILTIN_MIN_2X16,
5048   BFIN_BUILTIN_MAX_2X16,
5049 
5050   BFIN_BUILTIN_SSADD_1X16,
5051   BFIN_BUILTIN_SSSUB_1X16,
5052   BFIN_BUILTIN_MULT_1X16,
5053   BFIN_BUILTIN_MULTR_1X16,
5054   BFIN_BUILTIN_NORM_1X16,
5055   BFIN_BUILTIN_NEG_1X16,
5056   BFIN_BUILTIN_ABS_1X16,
5057   BFIN_BUILTIN_MIN_1X16,
5058   BFIN_BUILTIN_MAX_1X16,
5059 
5060   BFIN_BUILTIN_SUM_2X16,
5061   BFIN_BUILTIN_DIFFHL_2X16,
5062   BFIN_BUILTIN_DIFFLH_2X16,
5063 
5064   BFIN_BUILTIN_SSADD_1X32,
5065   BFIN_BUILTIN_SSSUB_1X32,
5066   BFIN_BUILTIN_NORM_1X32,
5067   BFIN_BUILTIN_ROUND_1X32,
5068   BFIN_BUILTIN_NEG_1X32,
5069   BFIN_BUILTIN_ABS_1X32,
5070   BFIN_BUILTIN_MIN_1X32,
5071   BFIN_BUILTIN_MAX_1X32,
5072   BFIN_BUILTIN_MULT_1X32,
5073   BFIN_BUILTIN_MULT_1X32X32,
5074   BFIN_BUILTIN_MULT_1X32X32NS,
5075 
5076   BFIN_BUILTIN_MULHISILL,
5077   BFIN_BUILTIN_MULHISILH,
5078   BFIN_BUILTIN_MULHISIHL,
5079   BFIN_BUILTIN_MULHISIHH,
5080 
5081   BFIN_BUILTIN_LSHIFT_1X16,
5082   BFIN_BUILTIN_LSHIFT_2X16,
5083   BFIN_BUILTIN_SSASHIFT_1X16,
5084   BFIN_BUILTIN_SSASHIFT_2X16,
5085   BFIN_BUILTIN_SSASHIFT_1X32,
5086 
5087   BFIN_BUILTIN_CPLX_MUL_16,
5088   BFIN_BUILTIN_CPLX_MAC_16,
5089   BFIN_BUILTIN_CPLX_MSU_16,
5090 
5091   BFIN_BUILTIN_CPLX_MUL_16_S40,
5092   BFIN_BUILTIN_CPLX_MAC_16_S40,
5093   BFIN_BUILTIN_CPLX_MSU_16_S40,
5094 
5095   BFIN_BUILTIN_CPLX_SQU,
5096 
5097   BFIN_BUILTIN_LOADBYTES,
5098 
5099   BFIN_BUILTIN_MAX
5100 };
5101 
5102 #define def_builtin(NAME, TYPE, CODE)                                           \
5103 do {                                                                                      \
5104   add_builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD,                    \
5105                            NULL, NULL_TREE);                                    \
5106 } while (0)
5107 
5108 /* Set up all builtin functions for this target.  */
5109 static void
bfin_init_builtins(void)5110 bfin_init_builtins (void)
5111 {
5112   tree V2HI_type_node = build_vector_type_for_mode (intHI_type_node, V2HImode);
5113   tree void_ftype_void
5114     = build_function_type_list (void_type_node, NULL_TREE);
5115   tree short_ftype_short
5116     = build_function_type_list (short_integer_type_node, short_integer_type_node,
5117                                         NULL_TREE);
5118   tree short_ftype_int_int
5119     = build_function_type_list (short_integer_type_node, integer_type_node,
5120                                         integer_type_node, NULL_TREE);
5121   tree int_ftype_int_int
5122     = build_function_type_list (integer_type_node, integer_type_node,
5123                                         integer_type_node, NULL_TREE);
5124   tree int_ftype_int
5125     = build_function_type_list (integer_type_node, integer_type_node,
5126                                         NULL_TREE);
5127   tree short_ftype_int
5128     = build_function_type_list (short_integer_type_node, integer_type_node,
5129                                         NULL_TREE);
5130   tree int_ftype_v2hi_v2hi
5131     = build_function_type_list (integer_type_node, V2HI_type_node,
5132                                         V2HI_type_node, NULL_TREE);
5133   tree v2hi_ftype_v2hi_v2hi
5134     = build_function_type_list (V2HI_type_node, V2HI_type_node,
5135                                         V2HI_type_node, NULL_TREE);
5136   tree v2hi_ftype_v2hi_v2hi_v2hi
5137     = build_function_type_list (V2HI_type_node, V2HI_type_node,
5138                                         V2HI_type_node, V2HI_type_node, NULL_TREE);
5139   tree v2hi_ftype_int_int
5140     = build_function_type_list (V2HI_type_node, integer_type_node,
5141                                         integer_type_node, NULL_TREE);
5142   tree v2hi_ftype_v2hi_int
5143     = build_function_type_list (V2HI_type_node, V2HI_type_node,
5144                                         integer_type_node, NULL_TREE);
5145   tree int_ftype_short_short
5146     = build_function_type_list (integer_type_node, short_integer_type_node,
5147                                         short_integer_type_node, NULL_TREE);
5148   tree v2hi_ftype_v2hi
5149     = build_function_type_list (V2HI_type_node, V2HI_type_node, NULL_TREE);
5150   tree short_ftype_v2hi
5151     = build_function_type_list (short_integer_type_node, V2HI_type_node,
5152                                         NULL_TREE);
5153   tree int_ftype_pint
5154     = build_function_type_list (integer_type_node,
5155                                         build_pointer_type (integer_type_node),
5156                                         NULL_TREE);
5157 
5158   /* Add the remaining MMX insns with somewhat more complicated types.  */
5159   def_builtin ("__builtin_bfin_csync", void_ftype_void, BFIN_BUILTIN_CSYNC);
5160   def_builtin ("__builtin_bfin_ssync", void_ftype_void, BFIN_BUILTIN_SSYNC);
5161 
5162   def_builtin ("__builtin_bfin_ones", short_ftype_int, BFIN_BUILTIN_ONES);
5163 
5164   def_builtin ("__builtin_bfin_compose_2x16", v2hi_ftype_int_int,
5165                  BFIN_BUILTIN_COMPOSE_2X16);
5166   def_builtin ("__builtin_bfin_extract_hi", short_ftype_v2hi,
5167                  BFIN_BUILTIN_EXTRACTHI);
5168   def_builtin ("__builtin_bfin_extract_lo", short_ftype_v2hi,
5169                  BFIN_BUILTIN_EXTRACTLO);
5170 
5171   def_builtin ("__builtin_bfin_min_fr2x16", v2hi_ftype_v2hi_v2hi,
5172                  BFIN_BUILTIN_MIN_2X16);
5173   def_builtin ("__builtin_bfin_max_fr2x16", v2hi_ftype_v2hi_v2hi,
5174                  BFIN_BUILTIN_MAX_2X16);
5175 
5176   def_builtin ("__builtin_bfin_add_fr2x16", v2hi_ftype_v2hi_v2hi,
5177                  BFIN_BUILTIN_SSADD_2X16);
5178   def_builtin ("__builtin_bfin_sub_fr2x16", v2hi_ftype_v2hi_v2hi,
5179                  BFIN_BUILTIN_SSSUB_2X16);
5180   def_builtin ("__builtin_bfin_dspaddsubsat", v2hi_ftype_v2hi_v2hi,
5181                  BFIN_BUILTIN_SSADDSUB_2X16);
5182   def_builtin ("__builtin_bfin_dspsubaddsat", v2hi_ftype_v2hi_v2hi,
5183                  BFIN_BUILTIN_SSSUBADD_2X16);
5184   def_builtin ("__builtin_bfin_mult_fr2x16", v2hi_ftype_v2hi_v2hi,
5185                  BFIN_BUILTIN_MULT_2X16);
5186   def_builtin ("__builtin_bfin_multr_fr2x16", v2hi_ftype_v2hi_v2hi,
5187                  BFIN_BUILTIN_MULTR_2X16);
5188   def_builtin ("__builtin_bfin_negate_fr2x16", v2hi_ftype_v2hi,
5189                  BFIN_BUILTIN_NEG_2X16);
5190   def_builtin ("__builtin_bfin_abs_fr2x16", v2hi_ftype_v2hi,
5191                  BFIN_BUILTIN_ABS_2X16);
5192 
5193   def_builtin ("__builtin_bfin_min_fr1x16", short_ftype_int_int,
5194                  BFIN_BUILTIN_MIN_1X16);
5195   def_builtin ("__builtin_bfin_max_fr1x16", short_ftype_int_int,
5196                  BFIN_BUILTIN_MAX_1X16);
5197 
5198   def_builtin ("__builtin_bfin_add_fr1x16", short_ftype_int_int,
5199                  BFIN_BUILTIN_SSADD_1X16);
5200   def_builtin ("__builtin_bfin_sub_fr1x16", short_ftype_int_int,
5201                  BFIN_BUILTIN_SSSUB_1X16);
5202   def_builtin ("__builtin_bfin_mult_fr1x16", short_ftype_int_int,
5203                  BFIN_BUILTIN_MULT_1X16);
5204   def_builtin ("__builtin_bfin_multr_fr1x16", short_ftype_int_int,
5205                  BFIN_BUILTIN_MULTR_1X16);
5206   def_builtin ("__builtin_bfin_negate_fr1x16", short_ftype_short,
5207                  BFIN_BUILTIN_NEG_1X16);
5208   def_builtin ("__builtin_bfin_abs_fr1x16", short_ftype_short,
5209                  BFIN_BUILTIN_ABS_1X16);
5210   def_builtin ("__builtin_bfin_norm_fr1x16", short_ftype_int,
5211                  BFIN_BUILTIN_NORM_1X16);
5212 
5213   def_builtin ("__builtin_bfin_sum_fr2x16", short_ftype_v2hi,
5214                  BFIN_BUILTIN_SUM_2X16);
5215   def_builtin ("__builtin_bfin_diff_hl_fr2x16", short_ftype_v2hi,
5216                  BFIN_BUILTIN_DIFFHL_2X16);
5217   def_builtin ("__builtin_bfin_diff_lh_fr2x16", short_ftype_v2hi,
5218                  BFIN_BUILTIN_DIFFLH_2X16);
5219 
5220   def_builtin ("__builtin_bfin_mulhisill", int_ftype_v2hi_v2hi,
5221                  BFIN_BUILTIN_MULHISILL);
5222   def_builtin ("__builtin_bfin_mulhisihl", int_ftype_v2hi_v2hi,
5223                  BFIN_BUILTIN_MULHISIHL);
5224   def_builtin ("__builtin_bfin_mulhisilh", int_ftype_v2hi_v2hi,
5225                  BFIN_BUILTIN_MULHISILH);
5226   def_builtin ("__builtin_bfin_mulhisihh", int_ftype_v2hi_v2hi,
5227                  BFIN_BUILTIN_MULHISIHH);
5228 
5229   def_builtin ("__builtin_bfin_min_fr1x32", int_ftype_int_int,
5230                  BFIN_BUILTIN_MIN_1X32);
5231   def_builtin ("__builtin_bfin_max_fr1x32", int_ftype_int_int,
5232                  BFIN_BUILTIN_MAX_1X32);
5233 
5234   def_builtin ("__builtin_bfin_add_fr1x32", int_ftype_int_int,
5235                  BFIN_BUILTIN_SSADD_1X32);
5236   def_builtin ("__builtin_bfin_sub_fr1x32", int_ftype_int_int,
5237                  BFIN_BUILTIN_SSSUB_1X32);
5238   def_builtin ("__builtin_bfin_negate_fr1x32", int_ftype_int,
5239                  BFIN_BUILTIN_NEG_1X32);
5240   def_builtin ("__builtin_bfin_abs_fr1x32", int_ftype_int,
5241                  BFIN_BUILTIN_ABS_1X32);
5242   def_builtin ("__builtin_bfin_norm_fr1x32", short_ftype_int,
5243                  BFIN_BUILTIN_NORM_1X32);
5244   def_builtin ("__builtin_bfin_round_fr1x32", short_ftype_int,
5245                  BFIN_BUILTIN_ROUND_1X32);
5246   def_builtin ("__builtin_bfin_mult_fr1x32", int_ftype_short_short,
5247                  BFIN_BUILTIN_MULT_1X32);
5248   def_builtin ("__builtin_bfin_mult_fr1x32x32", int_ftype_int_int,
5249                  BFIN_BUILTIN_MULT_1X32X32);
5250   def_builtin ("__builtin_bfin_mult_fr1x32x32NS", int_ftype_int_int,
5251                  BFIN_BUILTIN_MULT_1X32X32NS);
5252 
5253   /* Shifts.  */
5254   def_builtin ("__builtin_bfin_shl_fr1x16", short_ftype_int_int,
5255                  BFIN_BUILTIN_SSASHIFT_1X16);
5256   def_builtin ("__builtin_bfin_shl_fr2x16", v2hi_ftype_v2hi_int,
5257                  BFIN_BUILTIN_SSASHIFT_2X16);
5258   def_builtin ("__builtin_bfin_lshl_fr1x16", short_ftype_int_int,
5259                  BFIN_BUILTIN_LSHIFT_1X16);
5260   def_builtin ("__builtin_bfin_lshl_fr2x16", v2hi_ftype_v2hi_int,
5261                  BFIN_BUILTIN_LSHIFT_2X16);
5262   def_builtin ("__builtin_bfin_shl_fr1x32", int_ftype_int_int,
5263                  BFIN_BUILTIN_SSASHIFT_1X32);
5264 
5265   /* Complex numbers.  */
5266   def_builtin ("__builtin_bfin_cmplx_add", v2hi_ftype_v2hi_v2hi,
5267                  BFIN_BUILTIN_SSADD_2X16);
5268   def_builtin ("__builtin_bfin_cmplx_sub", v2hi_ftype_v2hi_v2hi,
5269                  BFIN_BUILTIN_SSSUB_2X16);
5270   def_builtin ("__builtin_bfin_cmplx_mul", v2hi_ftype_v2hi_v2hi,
5271                  BFIN_BUILTIN_CPLX_MUL_16);
5272   def_builtin ("__builtin_bfin_cmplx_mac", v2hi_ftype_v2hi_v2hi_v2hi,
5273                  BFIN_BUILTIN_CPLX_MAC_16);
5274   def_builtin ("__builtin_bfin_cmplx_msu", v2hi_ftype_v2hi_v2hi_v2hi,
5275                  BFIN_BUILTIN_CPLX_MSU_16);
5276   def_builtin ("__builtin_bfin_cmplx_mul_s40", v2hi_ftype_v2hi_v2hi,
5277                  BFIN_BUILTIN_CPLX_MUL_16_S40);
5278   def_builtin ("__builtin_bfin_cmplx_mac_s40", v2hi_ftype_v2hi_v2hi_v2hi,
5279                  BFIN_BUILTIN_CPLX_MAC_16_S40);
5280   def_builtin ("__builtin_bfin_cmplx_msu_s40", v2hi_ftype_v2hi_v2hi_v2hi,
5281                  BFIN_BUILTIN_CPLX_MSU_16_S40);
5282   def_builtin ("__builtin_bfin_csqu_fr16", v2hi_ftype_v2hi,
5283                  BFIN_BUILTIN_CPLX_SQU);
5284 
5285   /* "Unaligned" load.  */
5286   def_builtin ("__builtin_bfin_loadbytes", int_ftype_pint,
5287                  BFIN_BUILTIN_LOADBYTES);
5288 
5289 }
5290 
5291 
5292 struct builtin_description
5293 {
5294   const enum insn_code icode;
5295   const char *const name;
5296   const enum bfin_builtins code;
5297   int macflag;
5298 };
5299 
5300 static const struct builtin_description bdesc_2arg[] =
5301 {
5302   { CODE_FOR_composev2hi, "__builtin_bfin_compose_2x16", BFIN_BUILTIN_COMPOSE_2X16, -1 },
5303 
5304   { CODE_FOR_ssashiftv2hi3, "__builtin_bfin_shl_fr2x16", BFIN_BUILTIN_SSASHIFT_2X16, -1 },
5305   { CODE_FOR_ssashifthi3, "__builtin_bfin_shl_fr1x16", BFIN_BUILTIN_SSASHIFT_1X16, -1 },
5306   { CODE_FOR_lshiftv2hi3, "__builtin_bfin_lshl_fr2x16", BFIN_BUILTIN_LSHIFT_2X16, -1 },
5307   { CODE_FOR_lshifthi3, "__builtin_bfin_lshl_fr1x16", BFIN_BUILTIN_LSHIFT_1X16, -1 },
5308   { CODE_FOR_ssashiftsi3, "__builtin_bfin_shl_fr1x32", BFIN_BUILTIN_SSASHIFT_1X32, -1 },
5309 
5310   { CODE_FOR_sminhi3, "__builtin_bfin_min_fr1x16", BFIN_BUILTIN_MIN_1X16, -1 },
5311   { CODE_FOR_smaxhi3, "__builtin_bfin_max_fr1x16", BFIN_BUILTIN_MAX_1X16, -1 },
5312   { CODE_FOR_ssaddhi3, "__builtin_bfin_add_fr1x16", BFIN_BUILTIN_SSADD_1X16, -1 },
5313   { CODE_FOR_sssubhi3, "__builtin_bfin_sub_fr1x16", BFIN_BUILTIN_SSSUB_1X16, -1 },
5314 
5315   { CODE_FOR_sminsi3, "__builtin_bfin_min_fr1x32", BFIN_BUILTIN_MIN_1X32, -1 },
5316   { CODE_FOR_smaxsi3, "__builtin_bfin_max_fr1x32", BFIN_BUILTIN_MAX_1X32, -1 },
5317   { CODE_FOR_ssaddsi3, "__builtin_bfin_add_fr1x32", BFIN_BUILTIN_SSADD_1X32, -1 },
5318   { CODE_FOR_sssubsi3, "__builtin_bfin_sub_fr1x32", BFIN_BUILTIN_SSSUB_1X32, -1 },
5319 
5320   { CODE_FOR_sminv2hi3, "__builtin_bfin_min_fr2x16", BFIN_BUILTIN_MIN_2X16, -1 },
5321   { CODE_FOR_smaxv2hi3, "__builtin_bfin_max_fr2x16", BFIN_BUILTIN_MAX_2X16, -1 },
5322   { CODE_FOR_ssaddv2hi3, "__builtin_bfin_add_fr2x16", BFIN_BUILTIN_SSADD_2X16, -1 },
5323   { CODE_FOR_sssubv2hi3, "__builtin_bfin_sub_fr2x16", BFIN_BUILTIN_SSSUB_2X16, -1 },
5324   { CODE_FOR_ssaddsubv2hi3, "__builtin_bfin_dspaddsubsat", BFIN_BUILTIN_SSADDSUB_2X16, -1 },
5325   { CODE_FOR_sssubaddv2hi3, "__builtin_bfin_dspsubaddsat", BFIN_BUILTIN_SSSUBADD_2X16, -1 },
5326 
5327   { CODE_FOR_flag_mulhisi, "__builtin_bfin_mult_fr1x32", BFIN_BUILTIN_MULT_1X32, MACFLAG_NONE },
5328   { CODE_FOR_flag_mulhi, "__builtin_bfin_mult_fr1x16", BFIN_BUILTIN_MULT_1X16, MACFLAG_T },
5329   { CODE_FOR_flag_mulhi, "__builtin_bfin_multr_fr1x16", BFIN_BUILTIN_MULTR_1X16, MACFLAG_NONE },
5330   { CODE_FOR_flag_mulv2hi, "__builtin_bfin_mult_fr2x16", BFIN_BUILTIN_MULT_2X16, MACFLAG_T },
5331   { CODE_FOR_flag_mulv2hi, "__builtin_bfin_multr_fr2x16", BFIN_BUILTIN_MULTR_2X16, MACFLAG_NONE },
5332 
5333   { CODE_FOR_mulhisi_ll, "__builtin_bfin_mulhisill", BFIN_BUILTIN_MULHISILL, -1 },
5334   { CODE_FOR_mulhisi_lh, "__builtin_bfin_mulhisilh", BFIN_BUILTIN_MULHISILH, -1 },
5335   { CODE_FOR_mulhisi_hl, "__builtin_bfin_mulhisihl", BFIN_BUILTIN_MULHISIHL, -1 },
5336   { CODE_FOR_mulhisi_hh, "__builtin_bfin_mulhisihh", BFIN_BUILTIN_MULHISIHH, -1 }
5337 
5338 };
5339 
5340 static const struct builtin_description bdesc_1arg[] =
5341 {
5342   { CODE_FOR_loadbytes, "__builtin_bfin_loadbytes", BFIN_BUILTIN_LOADBYTES, 0 },
5343 
5344   { CODE_FOR_ones, "__builtin_bfin_ones", BFIN_BUILTIN_ONES, 0 },
5345 
5346   { CODE_FOR_clrsbhi2, "__builtin_bfin_norm_fr1x16", BFIN_BUILTIN_NORM_1X16, 0 },
5347   { CODE_FOR_ssneghi2, "__builtin_bfin_negate_fr1x16", BFIN_BUILTIN_NEG_1X16, 0 },
5348   { CODE_FOR_abshi2, "__builtin_bfin_abs_fr1x16", BFIN_BUILTIN_ABS_1X16, 0 },
5349 
5350   { CODE_FOR_clrsbsi2, "__builtin_bfin_norm_fr1x32", BFIN_BUILTIN_NORM_1X32, 0 },
5351   { CODE_FOR_ssroundsi2, "__builtin_bfin_round_fr1x32", BFIN_BUILTIN_ROUND_1X32, 0 },
5352   { CODE_FOR_ssnegsi2, "__builtin_bfin_negate_fr1x32", BFIN_BUILTIN_NEG_1X32, 0 },
5353   { CODE_FOR_ssabssi2, "__builtin_bfin_abs_fr1x32", BFIN_BUILTIN_ABS_1X32, 0 },
5354 
5355   { CODE_FOR_movv2hi_hi_low, "__builtin_bfin_extract_lo", BFIN_BUILTIN_EXTRACTLO, 0 },
5356   { CODE_FOR_movv2hi_hi_high, "__builtin_bfin_extract_hi", BFIN_BUILTIN_EXTRACTHI, 0 },
5357   { CODE_FOR_ssnegv2hi2, "__builtin_bfin_negate_fr2x16", BFIN_BUILTIN_NEG_2X16, 0 },
5358   { CODE_FOR_ssabsv2hi2, "__builtin_bfin_abs_fr2x16", BFIN_BUILTIN_ABS_2X16, 0 }
5359 };
5360 
5361 /* Errors in the source file can cause expand_expr to return const0_rtx
5362    where we expect a vector.  To avoid crashing, use one of the vector
5363    clear instructions.  */
5364 static rtx
safe_vector_operand(rtx x,machine_mode mode)5365 safe_vector_operand (rtx x, machine_mode mode)
5366 {
5367   if (x != const0_rtx)
5368     return x;
5369   x = gen_reg_rtx (SImode);
5370 
5371   emit_insn (gen_movsi (x, CONST0_RTX (SImode)));
5372   return gen_lowpart (mode, x);
5373 }
5374 
5375 /* Subroutine of bfin_expand_builtin to take care of binop insns.  MACFLAG is -1
5376    if this is a normal binary op, or one of the MACFLAG_xxx constants.  */
5377 
5378 static rtx
bfin_expand_binop_builtin(enum insn_code icode,tree exp,rtx target,int macflag)5379 bfin_expand_binop_builtin (enum insn_code icode, tree exp, rtx target,
5380                                  int macflag)
5381 {
5382   rtx pat;
5383   tree arg0 = CALL_EXPR_ARG (exp, 0);
5384   tree arg1 = CALL_EXPR_ARG (exp, 1);
5385   rtx op0 = expand_normal (arg0);
5386   rtx op1 = expand_normal (arg1);
5387   machine_mode op0mode = GET_MODE (op0);
5388   machine_mode op1mode = GET_MODE (op1);
5389   machine_mode tmode = insn_data[icode].operand[0].mode;
5390   machine_mode mode0 = insn_data[icode].operand[1].mode;
5391   machine_mode mode1 = insn_data[icode].operand[2].mode;
5392 
5393   if (VECTOR_MODE_P (mode0))
5394     op0 = safe_vector_operand (op0, mode0);
5395   if (VECTOR_MODE_P (mode1))
5396     op1 = safe_vector_operand (op1, mode1);
5397 
5398   if (! target
5399       || GET_MODE (target) != tmode
5400       || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
5401     target = gen_reg_rtx (tmode);
5402 
5403   if ((op0mode == SImode || op0mode == VOIDmode) && mode0 == HImode)
5404     {
5405       op0mode = HImode;
5406       op0 = gen_lowpart (HImode, op0);
5407     }
5408   if ((op1mode == SImode || op1mode == VOIDmode) && mode1 == HImode)
5409     {
5410       op1mode = HImode;
5411       op1 = gen_lowpart (HImode, op1);
5412     }
5413   /* In case the insn wants input operands in modes different from
5414      the result, abort.  */
5415   gcc_assert ((op0mode == mode0 || op0mode == VOIDmode)
5416                 && (op1mode == mode1 || op1mode == VOIDmode));
5417 
5418   if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
5419     op0 = copy_to_mode_reg (mode0, op0);
5420   if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
5421     op1 = copy_to_mode_reg (mode1, op1);
5422 
5423   if (macflag == -1)
5424     pat = GEN_FCN (icode) (target, op0, op1);
5425   else
5426     pat = GEN_FCN (icode) (target, op0, op1, GEN_INT (macflag));
5427   if (! pat)
5428     return 0;
5429 
5430   emit_insn (pat);
5431   return target;
5432 }
5433 
5434 /* Subroutine of bfin_expand_builtin to take care of unop insns.  */
5435 
5436 static rtx
bfin_expand_unop_builtin(enum insn_code icode,tree exp,rtx target)5437 bfin_expand_unop_builtin (enum insn_code icode, tree exp,
5438                                 rtx target)
5439 {
5440   rtx pat;
5441   tree arg0 = CALL_EXPR_ARG (exp, 0);
5442   rtx op0 = expand_normal (arg0);
5443   machine_mode op0mode = GET_MODE (op0);
5444   machine_mode tmode = insn_data[icode].operand[0].mode;
5445   machine_mode mode0 = insn_data[icode].operand[1].mode;
5446 
5447   if (! target
5448       || GET_MODE (target) != tmode
5449       || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
5450     target = gen_reg_rtx (tmode);
5451 
5452   if (VECTOR_MODE_P (mode0))
5453     op0 = safe_vector_operand (op0, mode0);
5454 
5455   if (op0mode == SImode && mode0 == HImode)
5456     {
5457       op0mode = HImode;
5458       op0 = gen_lowpart (HImode, op0);
5459     }
5460   gcc_assert (op0mode == mode0 || op0mode == VOIDmode);
5461 
5462   if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
5463     op0 = copy_to_mode_reg (mode0, op0);
5464 
5465   pat = GEN_FCN (icode) (target, op0);
5466   if (! pat)
5467     return 0;
5468   emit_insn (pat);
5469   return target;
5470 }
5471 
5472 /* Expand an expression EXP that calls a built-in function,
5473    with result going to TARGET if that's convenient
5474    (and in mode MODE if that's convenient).
5475    SUBTARGET may be used as the target for computing one of EXP's operands.
5476    IGNORE is nonzero if the value is to be ignored.  */
5477 
5478 static rtx
bfin_expand_builtin(tree exp,rtx target ATTRIBUTE_UNUSED,rtx subtarget ATTRIBUTE_UNUSED,machine_mode mode ATTRIBUTE_UNUSED,int ignore ATTRIBUTE_UNUSED)5479 bfin_expand_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
5480                          rtx subtarget ATTRIBUTE_UNUSED,
5481                          machine_mode mode ATTRIBUTE_UNUSED,
5482                          int ignore ATTRIBUTE_UNUSED)
5483 {
5484   size_t i;
5485   enum insn_code icode;
5486   const struct builtin_description *d;
5487   tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
5488   unsigned int fcode = DECL_MD_FUNCTION_CODE (fndecl);
5489   tree arg0, arg1, arg2;
5490   rtx op0, op1, op2, accvec, pat, tmp1, tmp2, a0reg, a1reg;
5491   machine_mode tmode, mode0;
5492 
5493   switch (fcode)
5494     {
5495     case BFIN_BUILTIN_CSYNC:
5496       emit_insn (gen_csync ());
5497       return 0;
5498     case BFIN_BUILTIN_SSYNC:
5499       emit_insn (gen_ssync ());
5500       return 0;
5501 
5502     case BFIN_BUILTIN_DIFFHL_2X16:
5503     case BFIN_BUILTIN_DIFFLH_2X16:
5504     case BFIN_BUILTIN_SUM_2X16:
5505       arg0 = CALL_EXPR_ARG (exp, 0);
5506       op0 = expand_normal (arg0);
5507       icode = (fcode == BFIN_BUILTIN_DIFFHL_2X16 ? CODE_FOR_subhilov2hi3
5508                  : fcode == BFIN_BUILTIN_DIFFLH_2X16 ? CODE_FOR_sublohiv2hi3
5509                  : CODE_FOR_ssaddhilov2hi3);
5510       tmode = insn_data[icode].operand[0].mode;
5511       mode0 = insn_data[icode].operand[1].mode;
5512 
5513       if (! target
5514             || GET_MODE (target) != tmode
5515             || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
5516           target = gen_reg_rtx (tmode);
5517 
5518       if (VECTOR_MODE_P (mode0))
5519           op0 = safe_vector_operand (op0, mode0);
5520 
5521       if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
5522           op0 = copy_to_mode_reg (mode0, op0);
5523 
5524       pat = GEN_FCN (icode) (target, op0, op0);
5525       if (! pat)
5526           return 0;
5527       emit_insn (pat);
5528       return target;
5529 
5530     case BFIN_BUILTIN_MULT_1X32X32:
5531     case BFIN_BUILTIN_MULT_1X32X32NS:
5532       arg0 = CALL_EXPR_ARG (exp, 0);
5533       arg1 = CALL_EXPR_ARG (exp, 1);
5534       op0 = expand_normal (arg0);
5535       op1 = expand_normal (arg1);
5536       if (! target
5537             || !register_operand (target, SImode))
5538           target = gen_reg_rtx (SImode);
5539       if (! register_operand (op0, SImode))
5540           op0 = copy_to_mode_reg (SImode, op0);
5541       if (! register_operand (op1, SImode))
5542           op1 = copy_to_mode_reg (SImode, op1);
5543 
5544       a1reg = gen_rtx_REG (PDImode, REG_A1);
5545       a0reg = gen_rtx_REG (PDImode, REG_A0);
5546       tmp1 = gen_lowpart (V2HImode, op0);
5547       tmp2 = gen_lowpart (V2HImode, op1);
5548       emit_insn (gen_flag_macinit1hi (a1reg,
5549                                               gen_lowpart (HImode, op0),
5550                                               gen_lowpart (HImode, op1),
5551                                               GEN_INT (MACFLAG_FU)));
5552       emit_insn (gen_lshrpdi3 (a1reg, a1reg, GEN_INT (16)));
5553 
5554       if (fcode == BFIN_BUILTIN_MULT_1X32X32)
5555           emit_insn (gen_flag_mul_macv2hi_parts_acconly (a0reg, a1reg, tmp1, tmp2,
5556                                                                    const1_rtx, const1_rtx,
5557                                                                    const1_rtx, const0_rtx, a1reg,
5558                                                                    const0_rtx, GEN_INT (MACFLAG_NONE),
5559                                                                    GEN_INT (MACFLAG_M)));
5560       else
5561           {
5562             /* For saturating multiplication, there's exactly one special case
5563                to be handled: multiplying the smallest negative value with
5564                itself.  Due to shift correction in fractional multiplies, this
5565                can overflow.  Iff this happens, OP2 will contain 1, which, when
5566                added in 32 bits to the smallest negative, wraps to the largest
5567                positive, which is the result we want.  */
5568             op2 = gen_reg_rtx (V2HImode);
5569             emit_insn (gen_packv2hi (op2, tmp1, tmp2, const0_rtx, const0_rtx));
5570             emit_insn (gen_movsibi (gen_rtx_REG (BImode, REG_CC),
5571                                           gen_lowpart (SImode, op2)));
5572             emit_insn (gen_flag_mul_macv2hi_parts_acconly_andcc0 (a0reg, a1reg, tmp1, tmp2,
5573                                                                                 const1_rtx, const1_rtx,
5574                                                                                 const1_rtx, const0_rtx, a1reg,
5575                                                                                 const0_rtx, GEN_INT (MACFLAG_NONE),
5576                                                                                 GEN_INT (MACFLAG_M)));
5577             op2 = gen_reg_rtx (SImode);
5578             emit_insn (gen_movbisi (op2, gen_rtx_REG (BImode, REG_CC)));
5579           }
5580       emit_insn (gen_flag_machi_parts_acconly (a1reg, tmp2, tmp1,
5581                                                          const1_rtx, const0_rtx,
5582                                                          a1reg, const0_rtx, GEN_INT (MACFLAG_M)));
5583       emit_insn (gen_ashrpdi3 (a1reg, a1reg, GEN_INT (15)));
5584       emit_insn (gen_sum_of_accumulators (target, a0reg, a0reg, a1reg));
5585       if (fcode == BFIN_BUILTIN_MULT_1X32X32NS)
5586           emit_insn (gen_addsi3 (target, target, op2));
5587       return target;
5588 
5589     case BFIN_BUILTIN_CPLX_MUL_16:
5590     case BFIN_BUILTIN_CPLX_MUL_16_S40:
5591       arg0 = CALL_EXPR_ARG (exp, 0);
5592       arg1 = CALL_EXPR_ARG (exp, 1);
5593       op0 = expand_normal (arg0);
5594       op1 = expand_normal (arg1);
5595       accvec = gen_reg_rtx (V2PDImode);
5596       icode = CODE_FOR_flag_macv2hi_parts;
5597       tmode = insn_data[icode].operand[0].mode;
5598 
5599       if (! target
5600             || GET_MODE (target) != V2HImode
5601             || ! (*insn_data[icode].operand[0].predicate) (target, V2HImode))
5602           target = gen_reg_rtx (tmode);
5603       if (! register_operand (op0, GET_MODE (op0)))
5604           op0 = copy_to_mode_reg (GET_MODE (op0), op0);
5605       if (! register_operand (op1, GET_MODE (op1)))
5606           op1 = copy_to_mode_reg (GET_MODE (op1), op1);
5607 
5608       if (fcode == BFIN_BUILTIN_CPLX_MUL_16)
5609           emit_insn (gen_flag_macinit1v2hi_parts (accvec, op0, op1, const0_rtx,
5610                                                             const0_rtx, const0_rtx,
5611                                                             const1_rtx, GEN_INT (MACFLAG_W32)));
5612       else
5613           emit_insn (gen_flag_macinit1v2hi_parts (accvec, op0, op1, const0_rtx,
5614                                                             const0_rtx, const0_rtx,
5615                                                             const1_rtx, GEN_INT (MACFLAG_NONE)));
5616       emit_insn (gen_flag_macv2hi_parts (target, op0, op1, const1_rtx,
5617                                                    const1_rtx, const1_rtx,
5618                                                    const0_rtx, accvec, const1_rtx, const0_rtx,
5619                                                    GEN_INT (MACFLAG_NONE), accvec));
5620 
5621       return target;
5622 
5623     case BFIN_BUILTIN_CPLX_MAC_16:
5624     case BFIN_BUILTIN_CPLX_MSU_16:
5625     case BFIN_BUILTIN_CPLX_MAC_16_S40:
5626     case BFIN_BUILTIN_CPLX_MSU_16_S40:
5627       arg0 = CALL_EXPR_ARG (exp, 0);
5628       arg1 = CALL_EXPR_ARG (exp, 1);
5629       arg2 = CALL_EXPR_ARG (exp, 2);
5630       op0 = expand_normal (arg0);
5631       op1 = expand_normal (arg1);
5632       op2 = expand_normal (arg2);
5633       accvec = gen_reg_rtx (V2PDImode);
5634       icode = CODE_FOR_flag_macv2hi_parts;
5635       tmode = insn_data[icode].operand[0].mode;
5636 
5637       if (! target
5638             || GET_MODE (target) != V2HImode
5639             || ! (*insn_data[icode].operand[0].predicate) (target, V2HImode))
5640           target = gen_reg_rtx (tmode);
5641       if (! register_operand (op1, GET_MODE (op1)))
5642           op1 = copy_to_mode_reg (GET_MODE (op1), op1);
5643       if (! register_operand (op2, GET_MODE (op2)))
5644           op2 = copy_to_mode_reg (GET_MODE (op2), op2);
5645 
5646       tmp1 = gen_reg_rtx (SImode);
5647       tmp2 = gen_reg_rtx (SImode);
5648       emit_insn (gen_ashlsi3 (tmp1, gen_lowpart (SImode, op0), GEN_INT (16)));
5649       emit_move_insn (tmp2, gen_lowpart (SImode, op0));
5650       emit_insn (gen_movstricthi_1 (gen_lowpart (HImode, tmp2), const0_rtx));
5651       emit_insn (gen_load_accumulator_pair (accvec, tmp1, tmp2));
5652       if (fcode == BFIN_BUILTIN_CPLX_MAC_16
5653             || fcode == BFIN_BUILTIN_CPLX_MSU_16)
5654           emit_insn (gen_flag_macv2hi_parts_acconly (accvec, op1, op2, const0_rtx,
5655                                                                const0_rtx, const0_rtx,
5656                                                                const1_rtx, accvec, const0_rtx,
5657                                                                const0_rtx,
5658                                                                GEN_INT (MACFLAG_W32)));
5659       else
5660           emit_insn (gen_flag_macv2hi_parts_acconly (accvec, op1, op2, const0_rtx,
5661                                                                const0_rtx, const0_rtx,
5662                                                                const1_rtx, accvec, const0_rtx,
5663                                                                const0_rtx,
5664                                                                GEN_INT (MACFLAG_NONE)));
5665       if (fcode == BFIN_BUILTIN_CPLX_MAC_16
5666             || fcode == BFIN_BUILTIN_CPLX_MAC_16_S40)
5667           {
5668             tmp1 = const1_rtx;
5669             tmp2 = const0_rtx;
5670           }
5671       else
5672           {
5673             tmp1 = const0_rtx;
5674             tmp2 = const1_rtx;
5675           }
5676       emit_insn (gen_flag_macv2hi_parts (target, op1, op2, const1_rtx,
5677                                                    const1_rtx, const1_rtx,
5678                                                    const0_rtx, accvec, tmp1, tmp2,
5679                                                    GEN_INT (MACFLAG_NONE), accvec));
5680 
5681       return target;
5682 
5683     case BFIN_BUILTIN_CPLX_SQU:
5684       arg0 = CALL_EXPR_ARG (exp, 0);
5685       op0 = expand_normal (arg0);
5686       accvec = gen_reg_rtx (V2PDImode);
5687       icode = CODE_FOR_flag_mulv2hi;
5688       tmp1 = gen_reg_rtx (V2HImode);
5689       tmp2 = gen_reg_rtx (V2HImode);
5690 
5691       if (! target
5692             || GET_MODE (target) != V2HImode
5693             || ! (*insn_data[icode].operand[0].predicate) (target, V2HImode))
5694           target = gen_reg_rtx (V2HImode);
5695       if (! register_operand (op0, GET_MODE (op0)))
5696           op0 = copy_to_mode_reg (GET_MODE (op0), op0);
5697 
5698       emit_insn (gen_flag_mulv2hi (tmp1, op0, op0, GEN_INT (MACFLAG_NONE)));
5699 
5700       emit_insn (gen_flag_mulhi_parts (gen_lowpart (HImode, tmp2), op0, op0,
5701                                                const0_rtx, const1_rtx,
5702                                                GEN_INT (MACFLAG_NONE)));
5703 
5704       emit_insn (gen_ssaddhi3_high_parts (target, tmp2, tmp2, tmp2, const0_rtx,
5705                                                     const0_rtx));
5706       emit_insn (gen_sssubhi3_low_parts (target, target, tmp1, tmp1,
5707                                                    const0_rtx, const1_rtx));
5708 
5709       return target;
5710 
5711     default:
5712       break;
5713     }
5714 
5715   for (i = 0, d = bdesc_2arg; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
5716     if (d->code == fcode)
5717       return bfin_expand_binop_builtin (d->icode, exp, target,
5718                                                   d->macflag);
5719 
5720   for (i = 0, d = bdesc_1arg; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
5721     if (d->code == fcode)
5722       return bfin_expand_unop_builtin (d->icode, exp, target);
5723 
5724   gcc_unreachable ();
5725 }
5726 
5727 static void
bfin_conditional_register_usage(void)5728 bfin_conditional_register_usage (void)
5729 {
5730   /* initialize condition code flag register rtx */
5731   bfin_cc_rtx = gen_rtx_REG (BImode, REG_CC);
5732   bfin_rets_rtx = gen_rtx_REG (Pmode, REG_RETS);
5733   if (TARGET_FDPIC)
5734     call_used_regs[FDPIC_REGNO] = 1;
5735   if (!TARGET_FDPIC && flag_pic)
5736     {
5737       fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
5738       call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
5739     }
5740 }
5741 
5742 #undef TARGET_INIT_BUILTINS
5743 #define TARGET_INIT_BUILTINS bfin_init_builtins
5744 
5745 #undef TARGET_EXPAND_BUILTIN
5746 #define TARGET_EXPAND_BUILTIN bfin_expand_builtin
5747 
5748 #undef TARGET_ASM_GLOBALIZE_LABEL
5749 #define TARGET_ASM_GLOBALIZE_LABEL bfin_globalize_label
5750 
5751 #undef TARGET_ASM_FILE_START
5752 #define TARGET_ASM_FILE_START output_file_start
5753 
5754 #undef TARGET_ATTRIBUTE_TABLE
5755 #define TARGET_ATTRIBUTE_TABLE bfin_attribute_table
5756 
5757 #undef TARGET_COMP_TYPE_ATTRIBUTES
5758 #define TARGET_COMP_TYPE_ATTRIBUTES bfin_comp_type_attributes
5759 
5760 #undef TARGET_RTX_COSTS
5761 #define TARGET_RTX_COSTS bfin_rtx_costs
5762 
5763 #undef  TARGET_ADDRESS_COST
5764 #define TARGET_ADDRESS_COST bfin_address_cost
5765 
5766 #undef TARGET_REGISTER_MOVE_COST
5767 #define TARGET_REGISTER_MOVE_COST bfin_register_move_cost
5768 
5769 #undef TARGET_MEMORY_MOVE_COST
5770 #define TARGET_MEMORY_MOVE_COST bfin_memory_move_cost
5771 
5772 #undef  TARGET_ASM_INTEGER
5773 #define TARGET_ASM_INTEGER bfin_assemble_integer
5774 
5775 #undef TARGET_MACHINE_DEPENDENT_REORG
5776 #define TARGET_MACHINE_DEPENDENT_REORG bfin_reorg
5777 
5778 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
5779 #define TARGET_FUNCTION_OK_FOR_SIBCALL bfin_function_ok_for_sibcall
5780 
5781 #undef TARGET_ASM_OUTPUT_MI_THUNK
5782 #define TARGET_ASM_OUTPUT_MI_THUNK bfin_output_mi_thunk
5783 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
5784 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true
5785 
5786 #undef TARGET_SCHED_ADJUST_COST
5787 #define TARGET_SCHED_ADJUST_COST bfin_adjust_cost
5788 
5789 #undef TARGET_SCHED_ISSUE_RATE
5790 #define TARGET_SCHED_ISSUE_RATE bfin_issue_rate
5791 
5792 #undef TARGET_PROMOTE_FUNCTION_MODE
5793 #define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
5794 
5795 #undef TARGET_ARG_PARTIAL_BYTES
5796 #define TARGET_ARG_PARTIAL_BYTES bfin_arg_partial_bytes
5797 
5798 #undef TARGET_FUNCTION_ARG
5799 #define TARGET_FUNCTION_ARG bfin_function_arg
5800 
5801 #undef TARGET_FUNCTION_ARG_ADVANCE
5802 #define TARGET_FUNCTION_ARG_ADVANCE bfin_function_arg_advance
5803 
5804 #undef TARGET_PASS_BY_REFERENCE
5805 #define TARGET_PASS_BY_REFERENCE bfin_pass_by_reference
5806 
5807 #undef TARGET_SETUP_INCOMING_VARARGS
5808 #define TARGET_SETUP_INCOMING_VARARGS setup_incoming_varargs
5809 
5810 #undef TARGET_STRUCT_VALUE_RTX
5811 #define TARGET_STRUCT_VALUE_RTX bfin_struct_value_rtx
5812 
5813 #undef TARGET_VECTOR_MODE_SUPPORTED_P
5814 #define TARGET_VECTOR_MODE_SUPPORTED_P bfin_vector_mode_supported_p
5815 
5816 #undef TARGET_OPTION_OVERRIDE
5817 #define TARGET_OPTION_OVERRIDE bfin_option_override
5818 
5819 #undef TARGET_SECONDARY_RELOAD
5820 #define TARGET_SECONDARY_RELOAD bfin_secondary_reload
5821 
5822 #undef TARGET_CLASS_LIKELY_SPILLED_P
5823 #define TARGET_CLASS_LIKELY_SPILLED_P bfin_class_likely_spilled_p
5824 
5825 #undef TARGET_DELEGITIMIZE_ADDRESS
5826 #define TARGET_DELEGITIMIZE_ADDRESS bfin_delegitimize_address
5827 
5828 #undef TARGET_LEGITIMATE_CONSTANT_P
5829 #define TARGET_LEGITIMATE_CONSTANT_P bfin_legitimate_constant_p
5830 
5831 #undef TARGET_CANNOT_FORCE_CONST_MEM
5832 #define TARGET_CANNOT_FORCE_CONST_MEM bfin_cannot_force_const_mem
5833 
5834 #undef TARGET_RETURN_IN_MEMORY
5835 #define TARGET_RETURN_IN_MEMORY bfin_return_in_memory
5836 
5837 #undef TARGET_LRA_P
5838 #define TARGET_LRA_P hook_bool_void_false
5839 
5840 #undef TARGET_LEGITIMATE_ADDRESS_P
5841 #define TARGET_LEGITIMATE_ADDRESS_P     bfin_legitimate_address_p
5842 
5843 #undef TARGET_FRAME_POINTER_REQUIRED
5844 #define TARGET_FRAME_POINTER_REQUIRED bfin_frame_pointer_required
5845 
5846 #undef TARGET_CAN_ELIMINATE
5847 #define TARGET_CAN_ELIMINATE bfin_can_eliminate
5848 
5849 #undef TARGET_CONDITIONAL_REGISTER_USAGE
5850 #define TARGET_CONDITIONAL_REGISTER_USAGE bfin_conditional_register_usage
5851 
5852 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
5853 #define TARGET_ASM_TRAMPOLINE_TEMPLATE bfin_asm_trampoline_template
5854 #undef TARGET_TRAMPOLINE_INIT
5855 #define TARGET_TRAMPOLINE_INIT bfin_trampoline_init
5856 
5857 #undef TARGET_EXTRA_LIVE_ON_ENTRY
5858 #define TARGET_EXTRA_LIVE_ON_ENTRY bfin_extra_live_on_entry
5859 
5860 /* Passes after sched2 can break the helpful TImode annotations that
5861    haifa-sched puts on every insn.  Just do scheduling in reorg.  */
5862 #undef TARGET_DELAY_SCHED2
5863 #define TARGET_DELAY_SCHED2 true
5864 
5865 /* Variable tracking should be run after all optimizations which
5866    change order of insns.  It also needs a valid CFG.  */
5867 #undef TARGET_DELAY_VARTRACK
5868 #define TARGET_DELAY_VARTRACK true
5869 
5870 #undef TARGET_CAN_USE_DOLOOP_P
5871 #define TARGET_CAN_USE_DOLOOP_P bfin_can_use_doloop_p
5872 
5873 #undef TARGET_HARD_REGNO_NREGS
5874 #define TARGET_HARD_REGNO_NREGS bfin_hard_regno_nregs
5875 #undef TARGET_HARD_REGNO_MODE_OK
5876 #define TARGET_HARD_REGNO_MODE_OK bfin_hard_regno_mode_ok
5877 
5878 #undef TARGET_MODES_TIEABLE_P
5879 #define TARGET_MODES_TIEABLE_P bfin_modes_tieable_p
5880 
5881 #undef TARGET_CONSTANT_ALIGNMENT
5882 #define TARGET_CONSTANT_ALIGNMENT constant_alignment_word_strings
5883 
5884 struct gcc_target targetm = TARGET_INITIALIZER;
5885