1 /* Subroutines used for code generation on Xilinx MicroBlaze.
2    Copyright (C) 2009-2016 Free Software Foundation, Inc.
3 
4    Contributed by Michael Eager <eager@eagercon.com>.
5 
6    This file is part of GCC.
7 
8    GCC is free software; you can redistribute it and/or modify it
9    under the terms of the GNU General Public License as published
10    by the Free Software Foundation; either version 3, or (at your
11    option) any later version.
12 
13    GCC is distributed in the hope that it will be useful, but WITHOUT
14    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
16    License for more details.
17 
18    You should have received a copy of the GNU General Public License
19    along with GCC; see the file COPYING3.  If not see
20    <http://www.gnu.org/licenses/>.  */
21 
22 #include "config.h"
23 #include "system.h"
24 #include "coretypes.h"
25 #include "backend.h"
26 #include "target.h"
27 #include "rtl.h"
28 #include "tree.h"
29 #include "df.h"
30 #include "tm_p.h"
31 #include "optabs.h"
32 #include "regs.h"
33 #include "emit-rtl.h"
34 #include "recog.h"
35 #include "cgraph.h"
36 #include "diagnostic-core.h"
37 #include "varasm.h"
38 #include "stor-layout.h"
39 #include "calls.h"
40 #include "explow.h"
41 #include "expr.h"
42 #include "reload.h"
43 #include "output.h"
44 #include "builtins.h"
45 #include "rtl-iter.h"
46 #include "cfgloop.h"
47 #include "insn-addr.h"
48 #include "cfgrtl.h"
49 
50 /* This file should be included last.  */
51 #include "target-def.h"
52 
53 #define MICROBLAZE_VERSION_COMPARE(VA,VB) strcasecmp (VA, VB)
54 
55 /* Classifies an address.
56 
57 ADDRESS_INVALID
58 An invalid address.
59 
60 ADDRESS_REG
61 
62 A natural register or a register + const_int offset address.
63 The register satisfies microblaze_valid_base_register_p and the
64 offset is a const_arith_operand.
65 
66 ADDRESS_REG_INDEX
67 
68 A natural register offset by the index contained in an index register. The base
69 register satisfies microblaze_valid_base_register_p and the index register
70 satisfies microblaze_valid_index_register_p
71 
72 ADDRESS_CONST_INT
73 
74 A signed 16/32-bit constant address.
75 
76 ADDRESS_SYMBOLIC:
77 
78 A constant symbolic address or a (register + symbol).  */
79 
80 enum microblaze_address_type
81 {
82   ADDRESS_INVALID,
83   ADDRESS_REG,
84   ADDRESS_REG_INDEX,
85   ADDRESS_CONST_INT,
86   ADDRESS_SYMBOLIC,
87   ADDRESS_GOTOFF,
88   ADDRESS_PLT,
89   ADDRESS_TLS
90 };
91 
92 /* Classifies symbols
93 
94 SYMBOL_TYPE_GENERAL
95 
96 A general symbol.  */
97 enum microblaze_symbol_type
98 {
99   SYMBOL_TYPE_INVALID,
100   SYMBOL_TYPE_GENERAL
101 };
102 
103 /* TLS Address Type.  */
104 enum tls_reloc {
105   TLS_GD,
106   TLS_LDM,
107   TLS_DTPREL,
108   TLS_IE,
109   TLS_LE
110 };
111 
112 /* Classification of a MicroBlaze address.  */
113 struct microblaze_address_info
114 {
115   enum microblaze_address_type type;
116   rtx regA; 	/* Contains valid values on ADDRESS_REG, ADDRESS_REG_INDEX,
117      		   ADDRESS_SYMBOLIC.  */
118   rtx regB; 	/* Contains valid values on ADDRESS_REG_INDEX.  */
119   rtx offset; 	/* Contains valid values on ADDRESS_CONST_INT and ADDRESS_REG.  */
120   rtx symbol; 	/* Contains valid values on ADDRESS_SYMBOLIC.  */
121   enum microblaze_symbol_type symbol_type;
122   enum tls_reloc tls_type;
123 };
124 
125 /* Structure to be filled in by compute_frame_size with register
126    save masks, and offsets for the current function.  */
127 
128 struct GTY(()) microblaze_frame_info {
129   long total_size;		/* # bytes that the entire frame takes up.  */
130   long var_size;		/* # bytes that variables take up.  */
131   long args_size;		/* # bytes that outgoing arguments take up.  */
132   int link_debug_size;		/* # bytes for the link reg and back pointer.  */
133   int gp_reg_size;		/* # bytes needed to store gp regs.  */
134   long gp_offset;		/* offset from new sp to store gp registers.  */
135   long mask;			/* mask of saved gp registers.  */
136   int initialized;		/* != 0 if frame size already calculated.  */
137   int num_gp;			/* number of gp registers saved.  */
138   long insns_len;		/* length of insns.  */
139   int alloc_stack;		/* Flag to indicate if the current function
140 				   must not create stack space. (As an optimization).  */
141 };
142 
143 /* Global variables for machine-dependent things.  */
144 
145 /* Toggle which pipleline interface to use.  */
146 static GTY(()) int microblaze_sched_use_dfa = 0;
147 
148 /* Threshold for data being put into the small data/bss area, instead
149    of the normal data area (references to the small data/bss area take
150    1 instruction, and use the global pointer, references to the normal
151    data area takes 2 instructions).  */
152 int microblaze_section_threshold = -1;
153 
154 /* Prevent scheduling potentially exception causing instructions in
155    delay slots.  -mcpu=v3.00.a or v4.00.a turns this on.  */
156 int microblaze_no_unsafe_delay;
157 
158 /* Set to one if the targeted core has the CLZ insn.  */
159 int microblaze_has_clz = 0;
160 
161 /* Which CPU pipeline do we use. We haven't really standardized on a CPU
162    version having only a particular type of pipeline. There can still be
163    options on the CPU to scale pipeline features up or down. :(
164    Bad Presentation (??), so we let the MD file rely on the value of
165    this variable instead Making PIPE_5 the default. It should be backward
166    optimal with PIPE_3 MicroBlazes.  */
167 enum pipeline_type microblaze_pipe = MICROBLAZE_PIPE_5;
168 
169 /* High and low marks for floating point values which we will accept
170    as legitimate constants for TARGET_LEGITIMATE_CONSTANT_P.  These are
171    initialized in override_options.  */
172 REAL_VALUE_TYPE dfhigh, dflow, sfhigh, sflow;
173 
174 /* Array giving truth value on whether or not a given hard register
175    can support a given mode.  */
176 char microblaze_hard_regno_mode_ok[(int)MAX_MACHINE_MODE]
177 				  [FIRST_PSEUDO_REGISTER];
178 
179 /* Current frame information calculated by compute_frame_size.  */
180 struct microblaze_frame_info current_frame_info;
181 
182 /* Zero structure to initialize current_frame_info.  */
183 struct microblaze_frame_info zero_frame_info;
184 
185 /* List of all MICROBLAZE punctuation characters used by print_operand.  */
186 char microblaze_print_operand_punct[256];
187 
188 /* Map GCC register number to debugger register number.  */
189 int microblaze_dbx_regno[FIRST_PSEUDO_REGISTER];
190 
191 /* Map hard register number to register class.  */
192 enum reg_class microblaze_regno_to_class[] =
193 {
194   GR_REGS,	GR_REGS,	GR_REGS,	GR_REGS,
195   GR_REGS,	GR_REGS,	GR_REGS,	GR_REGS,
196   GR_REGS,	GR_REGS,	GR_REGS,	GR_REGS,
197   GR_REGS,	GR_REGS,	GR_REGS,	GR_REGS,
198   GR_REGS,	GR_REGS,	GR_REGS,	GR_REGS,
199   GR_REGS,	GR_REGS,	GR_REGS,	GR_REGS,
200   GR_REGS,	GR_REGS,	GR_REGS,	GR_REGS,
201   GR_REGS,	GR_REGS,	GR_REGS,	GR_REGS,
202   ST_REGS,	GR_REGS,	GR_REGS,	GR_REGS
203 };
204 
205 /* MicroBlaze specific machine attributes.
206    interrupt_handler - Interrupt handler attribute to add interrupt prologue
207 		       and epilogue and use appropriate interrupt return.
208    save_volatiles    - Similar to interrupt handler, but use normal return.  */
209 int interrupt_handler;
210 int break_handler;
211 int fast_interrupt;
212 int save_volatiles;
213 
214 const struct attribute_spec microblaze_attribute_table[] = {
215   /* name         min_len, max_len, decl_req, type_req, fn_type, req_handler,
216      affects_type_identity */
217   {"interrupt_handler", 0,       0,     true,    false,   false,        NULL,
218     false },
219   {"break_handler",     0,       0,     true,    false,   false,        NULL,
220     false },
221   {"fast_interrupt",    0,       0,     true,    false,   false,        NULL,
222     false },
223   {"save_volatiles"   , 0,       0,     true,    false,   false,        NULL,
224     false },
225   { NULL,        	0,       0,    false,    false,   false,        NULL,
226     false }
227 };
228 
229 static int microblaze_interrupt_function_p (tree);
230 
231 static void microblaze_elf_asm_constructor (rtx, int) ATTRIBUTE_UNUSED;
232 static void microblaze_elf_asm_destructor (rtx, int) ATTRIBUTE_UNUSED;
233 
234 section *sdata2_section;
235 
236 #ifdef HAVE_AS_TLS
237 #undef TARGET_HAVE_TLS
238 #define TARGET_HAVE_TLS true
239 #endif
240 
241 /* Return truth value if a CONST_DOUBLE is ok to be a legitimate constant.  */
242 static bool
microblaze_const_double_ok(rtx op,machine_mode mode)243 microblaze_const_double_ok (rtx op, machine_mode mode)
244 {
245   REAL_VALUE_TYPE d;
246 
247   if (GET_CODE (op) != CONST_DOUBLE)
248     return 0;
249 
250   if (GET_MODE (op) == VOIDmode)
251     return 1;
252 
253   if (mode != SFmode && mode != DFmode)
254     return 0;
255 
256   if (op == CONST0_RTX (mode))
257     return 1;
258 
259   d = *CONST_DOUBLE_REAL_VALUE (op);
260 
261   if (REAL_VALUE_ISNAN (d))
262     return FALSE;
263 
264   if (REAL_VALUE_NEGATIVE (d))
265     d = real_value_negate (&d);
266 
267   if (mode == DFmode)
268     {
269       if (real_less (&d, &dfhigh) && real_less (&dflow, &d))
270 	return 1;
271     }
272   else
273     {
274       if (real_less (&d, &sfhigh) && real_less (&sflow, &d))
275 	return 1;
276     }
277 
278   return 0;
279 }
280 
281 /* Return truth value if a memory operand fits in a single instruction
282    (ie, register + small offset) or (register + register).  */
283 
284 int
simple_memory_operand(rtx op,machine_mode mode ATTRIBUTE_UNUSED)285 simple_memory_operand (rtx op, machine_mode mode ATTRIBUTE_UNUSED)
286 {
287   rtx addr, plus0, plus1;
288 
289   /* Eliminate non-memory operations.  */
290   if (GET_CODE (op) != MEM)
291     return 0;
292 
293   /* dword operations really put out 2 instructions, so eliminate them.  */
294   /* ??? This isn't strictly correct.  It is OK to accept multiword modes
295      here, since the length attributes are being set correctly, but only
296      if the address is offsettable.  */
297   if (GET_MODE_SIZE (GET_MODE (op)) > UNITS_PER_WORD)
298     return 0;
299 
300 
301   /* Decode the address now.  */
302   addr = XEXP (op, 0);
303   switch (GET_CODE (addr))
304 
305     {
306     case REG:
307       return 1;
308 
309     case PLUS:
310       plus0 = XEXP (addr, 0);
311       plus1 = XEXP (addr, 1);
312 
313       if (GET_CODE (plus0) != REG)
314         return 0;
315 
316       if (GET_CODE (plus0) == REG && GET_CODE (plus1) == CONST_INT
317 	  && SMALL_INT (plus1))
318 	{
319 	  return 1;
320 	}
321       else if (GET_CODE (plus1) == REG && GET_CODE (plus0) == CONST_INT)
322 	{
323 	  return 1;
324 	}
325       else if (GET_CODE (plus0) == REG && GET_CODE (plus1) == REG)
326 	{
327 	  return 1;
328 	}
329       else
330 	return 0;
331 
332     case SYMBOL_REF:
333       return 0;
334 
335     default:
336       break;
337     }
338 
339   return 0;
340 }
341 
342 /* Return nonzero for a memory address that can be used to load or store
343    a doubleword.  */
344 
345 int
double_memory_operand(rtx op,machine_mode mode)346 double_memory_operand (rtx op, machine_mode mode)
347 {
348   rtx addr;
349 
350   if (GET_CODE (op) != MEM || !memory_operand (op, mode))
351     {
352       /* During reload, we accept a pseudo register if it has an
353          appropriate memory address.  If we don't do this, we will
354          wind up reloading into a register, and then reloading that
355          register from memory, when we could just reload directly from
356          memory.  */
357       if (reload_in_progress
358 	  && GET_CODE (op) == REG
359 	  && REGNO (op) >= FIRST_PSEUDO_REGISTER
360 	  && reg_renumber[REGNO (op)] < 0
361 	  && reg_equiv_mem (REGNO (op)) != 0
362 	  && double_memory_operand (reg_equiv_mem (REGNO (op)), mode))
363 	return 1;
364       return 0;
365     }
366 
367   /* Make sure that 4 added to the address is a valid memory address.
368      This essentially just checks for overflow in an added constant.  */
369 
370   addr = XEXP (op, 0);
371 
372   if (CONSTANT_ADDRESS_P (addr))
373     return 1;
374 
375   return memory_address_p ((GET_MODE_CLASS (mode) == MODE_INT
376 			    ? SImode : SFmode),
377 			   plus_constant (Pmode, addr, 4));
378 }
379 
380 /* Implement REG_OK_FOR_BASE_P -and- REG_OK_FOR_INDEX_P.  */
381 int
microblaze_regno_ok_for_base_p(int regno,int strict)382 microblaze_regno_ok_for_base_p (int regno, int strict)
383 {
384   if (regno >= FIRST_PSEUDO_REGISTER)
385     {
386       if (!strict)
387 	return true;
388       regno = reg_renumber[regno];
389     }
390 
391   /* These fake registers will be eliminated to either the stack or
392      hard frame pointer, both of which are usually valid base registers.
393      Reload deals with the cases where the eliminated form isn't valid.  */
394   if (regno == ARG_POINTER_REGNUM || regno == FRAME_POINTER_REGNUM)
395     return true;
396 
397   return GP_REG_P (regno);
398 }
399 
400 /* Return true if X is a valid base register for the given mode.
401    Allow only hard registers if STRICT.  */
402 
403 static bool
microblaze_valid_base_register_p(rtx x,machine_mode mode ATTRIBUTE_UNUSED,int strict)404 microblaze_valid_base_register_p (rtx x,
405 				  machine_mode mode ATTRIBUTE_UNUSED,
406 				  int strict)
407 {
408   if (!strict && GET_CODE (x) == SUBREG)
409     x = SUBREG_REG (x);
410 
411   return (GET_CODE (x) == REG
412 	  && microblaze_regno_ok_for_base_p (REGNO (x), strict));
413 }
414 
415 /* Build the SYMBOL_REF for __tls_get_addr.  */
416 
417 static GTY(()) rtx tls_get_addr_libfunc;
418 
419 static rtx
get_tls_get_addr(void)420 get_tls_get_addr (void)
421 {
422   if (!tls_get_addr_libfunc)
423     tls_get_addr_libfunc = init_one_libfunc ("__tls_get_addr");
424   return tls_get_addr_libfunc;
425 }
426 
427 /* Return TRUE if X is a thread-local symbol.  */
428 bool
microblaze_tls_symbol_p(rtx x)429 microblaze_tls_symbol_p (rtx x)
430 {
431   if (!TARGET_HAVE_TLS)
432     return false;
433 
434   if (GET_CODE (x) != SYMBOL_REF)
435     return false;
436 
437   return SYMBOL_REF_TLS_MODEL (x) != 0;
438 }
439 
440 /* Return TRUE if X contains any TLS symbol references.  */
441 
442 bool
microblaze_tls_referenced_p(rtx x)443 microblaze_tls_referenced_p (rtx x)
444 {
445   if (!TARGET_HAVE_TLS)
446     return false;
447   subrtx_iterator::array_type array;
448   FOR_EACH_SUBRTX (iter, array, x, ALL)
449     {
450       const_rtx x = *iter;
451       if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (x) != 0)
452 	return true;
453       /* Don't recurse into UNSPEC_TLS looking for TLS symbols; these are
454 	 TLS offsets, not real symbol references.  */
455       if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLS)
456 	iter.skip_subrtxes ();
457     }
458   return false;
459 }
460 
461 bool
microblaze_cannot_force_const_mem(machine_mode mode ATTRIBUTE_UNUSED,rtx x)462 microblaze_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED, rtx x)
463 {
464   return microblaze_tls_referenced_p(x);
465 }
466 
467 /* Return TRUE if X references a SYMBOL_REF.  */
468 int
symbol_mentioned_p(rtx x)469 symbol_mentioned_p (rtx x)
470 {
471   const char * fmt;
472   int i;
473 
474   if (GET_CODE (x) == SYMBOL_REF)
475     return 1;
476 
477   /* UNSPEC entries for a symbol include the SYMBOL_REF, but they
478      are constant offsets, not symbols.  */
479   if (GET_CODE (x) == UNSPEC)
480     return 0;
481 
482   fmt = GET_RTX_FORMAT (GET_CODE (x));
483 
484   for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
485     {
486       if (fmt[i] == 'E')
487         {
488           int j;
489 
490           for (j = XVECLEN (x, i) - 1; j >= 0; j--)
491             if (symbol_mentioned_p (XVECEXP (x, i, j)))
492               return 1;
493         }
494       else if (fmt[i] == 'e' && symbol_mentioned_p (XEXP (x, i)))
495         return 1;
496     }
497 
498   return 0;
499 }
500 
501 /* Return TRUE if X references a LABEL_REF.  */
502 int
label_mentioned_p(rtx x)503 label_mentioned_p (rtx x)
504 {
505   const char * fmt;
506   int i;
507 
508   if (GET_CODE (x) == LABEL_REF)
509     return 1;
510 
511   /* UNSPEC entries for a symbol include a LABEL_REF for the referencing
512      instruction, but they are constant offsets, not symbols.  */
513   if (GET_CODE (x) == UNSPEC)
514     return 0;
515 
516   fmt = GET_RTX_FORMAT (GET_CODE (x));
517   for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
518     {
519       if (fmt[i] == 'E')
520         {
521           int j;
522 
523           for (j = XVECLEN (x, i) - 1; j >= 0; j--)
524             if (label_mentioned_p (XVECEXP (x, i, j)))
525               return 1;
526         }
527       else if (fmt[i] == 'e' && label_mentioned_p (XEXP (x, i)))
528         return 1;
529     }
530 
531   return 0;
532 }
533 
534 int
tls_mentioned_p(rtx x)535 tls_mentioned_p (rtx x)
536 {
537   switch (GET_CODE (x))
538     {
539       case CONST:
540         return tls_mentioned_p (XEXP (x, 0));
541 
542       case UNSPEC:
543         if (XINT (x, 1) == UNSPEC_TLS)
544           return 1;
545 
546       default:
547         return 0;
548     }
549 }
550 
551 static rtx
load_tls_operand(rtx x,rtx reg)552 load_tls_operand (rtx x, rtx reg)
553 {
554   rtx tmp;
555 
556   if (reg == NULL_RTX)
557     reg = gen_reg_rtx (Pmode);
558 
559   tmp = gen_rtx_CONST (Pmode, x);
560 
561   emit_insn (gen_rtx_SET (reg,
562                           gen_rtx_PLUS (Pmode, pic_offset_table_rtx, tmp)));
563 
564   return reg;
565 }
566 
567 static rtx_insn *
microblaze_call_tls_get_addr(rtx x,rtx reg,rtx * valuep,int reloc)568 microblaze_call_tls_get_addr (rtx x, rtx reg, rtx *valuep, int reloc)
569 {
570   rtx_insn *insns;
571   rtx tls_entry;
572 
573   df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
574 
575   start_sequence ();
576 
577   tls_entry = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, x, GEN_INT (reloc)),
578                               UNSPEC_TLS);
579 
580   reg = load_tls_operand (tls_entry, reg);
581 
582   *valuep = emit_library_call_value (get_tls_get_addr (), NULL_RTX,
583                                      LCT_PURE, /* LCT_CONST?  */
584                                      Pmode, 1, reg, Pmode);
585 
586   insns = get_insns ();
587   end_sequence ();
588 
589   return insns;
590 }
591 
592 rtx
microblaze_legitimize_tls_address(rtx x,rtx reg)593 microblaze_legitimize_tls_address(rtx x, rtx reg)
594 {
595   rtx dest, ret, eqv, addend;
596   rtx_insn *insns;
597   enum tls_model model;
598   model = SYMBOL_REF_TLS_MODEL (x);
599 
600   switch (model)
601     {
602        case TLS_MODEL_LOCAL_DYNAMIC:
603        case TLS_MODEL_GLOBAL_DYNAMIC:
604        case TLS_MODEL_INITIAL_EXEC:
605          insns = microblaze_call_tls_get_addr (x, reg, &ret, TLS_GD);
606          dest = gen_reg_rtx (Pmode);
607          emit_libcall_block (insns, dest, ret, x);
608          break;
609 
610        case TLS_MODEL_LOCAL_EXEC:
611          insns = microblaze_call_tls_get_addr (x, reg, &ret, TLS_LDM);
612 
613          /* Attach a unique REG_EQUIV, to allow the RTL optimizers to
614             share the LDM result with other LD model accesses.  */
615          eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const1_rtx), UNSPEC_TLS);
616          dest = gen_reg_rtx (Pmode);
617          emit_libcall_block (insns, dest, ret, eqv);
618 
619          /* Load the addend.  */
620          addend = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, x, GEN_INT (TLS_DTPREL)),
621 				  UNSPEC_TLS);
622          addend = force_reg (SImode, gen_rtx_CONST (SImode, addend));
623          dest = gen_rtx_PLUS (Pmode, dest, addend);
624          break;
625 
626        default:
627          gcc_unreachable ();
628     }
629   return dest;
630 }
631 
632 static bool
microblaze_classify_unspec(struct microblaze_address_info * info,rtx x)633 microblaze_classify_unspec (struct microblaze_address_info *info, rtx x)
634 {
635   info->symbol_type = SYMBOL_TYPE_GENERAL;
636   info->symbol = XVECEXP (x, 0, 0);
637 
638   if (XINT (x, 1) == UNSPEC_GOTOFF)
639     {
640       info->regA = gen_rtx_REG (SImode, PIC_OFFSET_TABLE_REGNUM);
641       info->type = ADDRESS_GOTOFF;
642     }
643   else if (XINT (x, 1) == UNSPEC_PLT)
644     {
645       info->type = ADDRESS_PLT;
646     }
647   else if (XINT (x, 1) == UNSPEC_TLS)
648     {
649       info->type = ADDRESS_TLS;
650       info->tls_type = tls_reloc (INTVAL (XVECEXP (x, 0, 1)));
651     }
652   else
653     {
654       return false;
655     }
656   return true;
657 }
658 
659 
660 /* Return true if X is a valid index register for the given mode.
661    Allow only hard registers if STRICT.  */
662 
663 static bool
microblaze_valid_index_register_p(rtx x,machine_mode mode ATTRIBUTE_UNUSED,int strict)664 microblaze_valid_index_register_p (rtx x,
665 				   machine_mode mode ATTRIBUTE_UNUSED,
666 				   int strict)
667 {
668   if (!strict && GET_CODE (x) == SUBREG)
669     x = SUBREG_REG (x);
670 
671   return (GET_CODE (x) == REG
672 	  /* A base register is good enough to be an index register on MicroBlaze.  */
673 	  && microblaze_regno_ok_for_base_p (REGNO (x), strict));
674 }
675 
676 /* Get the base register for accessing a value from the memory or
677    Symbol ref. Used for MicroBlaze Small Data Area Pointer Optimization.  */
678 static int
get_base_reg(rtx x)679 get_base_reg (rtx x)
680 {
681   tree decl;
682   int base_reg;
683 
684   if (!flag_pic || microblaze_tls_symbol_p(x))
685     base_reg = MB_ABI_BASE_REGNUM;
686   else if (flag_pic)
687     base_reg = MB_ABI_PIC_ADDR_REGNUM;
688 
689   if (TARGET_XLGPOPT
690       && GET_CODE (x) == SYMBOL_REF
691       && SYMBOL_REF_SMALL_P (x) && (decl = SYMBOL_REF_DECL (x)) != NULL)
692     {
693       if (TREE_READONLY (decl))
694 	base_reg = MB_ABI_GPRO_REGNUM;
695       else
696 	base_reg = MB_ABI_GPRW_REGNUM;
697     }
698 
699   return base_reg;
700 }
701 
702 /* Return true if X is a valid address for machine mode MODE.  If it is,
703    fill in INFO appropriately.  STRICT is true if we should only accept
704    hard base registers.
705 
706       type                     regA      regB    offset      symbol
707 
708    ADDRESS_INVALID             NULL      NULL     NULL        NULL
709 
710    ADDRESS_REG                 %0        NULL     const_0 /   NULL
711                                                   const_int
712    ADDRESS_REG_INDEX           %0        %1       NULL        NULL
713 
714    ADDRESS_SYMBOLIC            r0 /      NULL     NULL        symbol
715                            sda_base_reg
716 
717    ADDRESS_CONST_INT           r0       NULL      const       NULL
718 
719    For modes spanning multiple registers (DFmode in 32-bit GPRs,
720    DImode, TImode), indexed addressing cannot be used because
721    adjacent memory cells are accessed by adding word-sized offsets
722    during assembly output.  */
723 
724 static bool
microblaze_classify_address(struct microblaze_address_info * info,rtx x,machine_mode mode,int strict)725 microblaze_classify_address (struct microblaze_address_info *info, rtx x,
726 			     machine_mode mode, int strict)
727 {
728   rtx xplus0;
729   rtx xplus1;
730 
731   info->type = ADDRESS_INVALID;
732   info->regA = NULL;
733   info->regB = NULL;
734   info->offset = NULL;
735   info->symbol = NULL;
736   info->symbol_type = SYMBOL_TYPE_INVALID;
737 
738   switch (GET_CODE (x))
739     {
740     case REG:
741     case SUBREG:
742       {
743 	info->type = ADDRESS_REG;
744 	info->regA = x;
745 	info->offset = const0_rtx;
746 	return microblaze_valid_base_register_p (info->regA, mode, strict);
747       }
748     case PLUS:
749       {
750 	xplus0 = XEXP (x, 0);
751 	xplus1 = XEXP (x, 1);
752 
753 	if (microblaze_valid_base_register_p (xplus0, mode, strict))
754 	  {
755 	    info->type = ADDRESS_REG;
756 	    info->regA = xplus0;
757 
758 	    if (GET_CODE (xplus1) == CONST_INT)
759 	      {
760 		info->offset = xplus1;
761 		return true;
762 	      }
763 	    else if (GET_CODE (xplus1) == UNSPEC)
764 	      {
765 		/* Need offsettable address.  */
766 		if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
767 		  return false;
768 
769 		return microblaze_classify_unspec (info, xplus1);
770 	      }
771 	    else if ((GET_CODE (xplus1) == SYMBOL_REF ||
772 		      GET_CODE (xplus1) == LABEL_REF))
773 	      {
774 		if (flag_pic == 2 || microblaze_tls_symbol_p(xplus1))
775 		  return false;
776 		info->type = ADDRESS_SYMBOLIC;
777 		info->symbol = xplus1;
778 		info->symbol_type = SYMBOL_TYPE_GENERAL;
779 		return true;
780 	      }
781 	    else if (GET_CODE (xplus1) == CONST)
782 	      {
783 		rtx xconst0 = XEXP(xplus1, 0);
784 
785 		/* base + unspec.  */
786 		if (GET_CODE (xconst0) == UNSPEC)
787 		  {
788 		    /* Need offsettable address.  */
789 		    if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
790 		      return false;
791 		    return microblaze_classify_unspec(info, xconst0);
792 		  }
793 
794 		/* for (plus x const_int) just look at x.  */
795 		if (GET_CODE (xconst0) == PLUS
796 		    && GET_CODE (XEXP (xconst0, 1)) == CONST_INT
797 		    && SMALL_INT (XEXP (xconst0, 1)))
798 		  {
799 		    /* This is ok as info->symbol is set to xplus1 the full
800 		       const-expression below.  */
801 		    xconst0 = XEXP (xconst0, 0);
802 		  }
803 
804 		if (GET_CODE (xconst0) == SYMBOL_REF
805 		    || GET_CODE (xconst0) == LABEL_REF)
806 		  {
807 		    if (flag_pic == 2 || microblaze_tls_symbol_p(xconst0))
808 		      return false;
809 
810 		    info->type = ADDRESS_SYMBOLIC;
811 		    info->symbol = xplus1;
812 		    info->symbol_type = SYMBOL_TYPE_GENERAL;
813 		    return true;
814 		  }
815 
816 		/* Not base + symbol || base + UNSPEC.  */
817 		return false;
818 
819 	      }
820 	    else if (GET_CODE (xplus1) == REG
821 		     && microblaze_valid_index_register_p (xplus1, mode,
822 							   strict)
823 		     && (GET_MODE_SIZE (mode) <= UNITS_PER_WORD))
824 	      {
825 		/* Restrict larger than word-width modes from using an index register.  */
826 		info->type = ADDRESS_REG_INDEX;
827 		info->regB = xplus1;
828 		return true;
829 	      }
830 	  }
831 	break;
832       }
833     case CONST_INT:
834       {
835 	info->regA = gen_raw_REG (mode, 0);
836 	info->type = ADDRESS_CONST_INT;
837 	info->offset = x;
838 	return true;
839       }
840     case CONST:
841     case LABEL_REF:
842     case SYMBOL_REF:
843       {
844 	info->type = ADDRESS_SYMBOLIC;
845 	info->symbol_type = SYMBOL_TYPE_GENERAL;
846 	info->symbol = x;
847 	info->regA = gen_raw_REG (mode, get_base_reg (x));
848 
849 	if (GET_CODE (x) == CONST)
850 	  {
851 	    if (GET_CODE (XEXP (x, 0)) == UNSPEC)
852 	     {
853 		info->regA = gen_raw_REG (mode,
854 				  get_base_reg (XVECEXP (XEXP (x,0), 0, 0)));
855 		return microblaze_classify_unspec (info, XEXP (x, 0));
856 	     }
857 	     return !(flag_pic && pic_address_needs_scratch (x));
858 	  }
859 
860 	if (flag_pic == 2)
861 	  return false;
862 	else if (microblaze_tls_symbol_p(x))
863 	  return false;
864 
865 	return true;
866       }
867 
868     case UNSPEC:
869       {
870 	if (reload_in_progress)
871 	  df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
872 	return microblaze_classify_unspec (info, x);
873       }
874 
875     default:
876       return false;
877     }
878 
879   return false;
880 }
881 
882 /* This function is used to implement GO_IF_LEGITIMATE_ADDRESS.  It
883    returns a nonzero value if X is a legitimate address for a memory
884    operand of the indicated MODE.  STRICT is nonzero if this function
885    is called during reload.  */
886 
887 bool
microblaze_legitimate_address_p(machine_mode mode,rtx x,bool strict)888 microblaze_legitimate_address_p (machine_mode mode, rtx x, bool strict)
889 {
890   struct microblaze_address_info addr;
891 
892   return microblaze_classify_address (&addr, x, mode, strict);
893 }
894 
895 int
microblaze_valid_pic_const(rtx x)896 microblaze_valid_pic_const (rtx x)
897 {
898   switch (GET_CODE (x))
899     {
900     case CONST:
901     case CONST_INT:
902     case CONST_DOUBLE:
903       return true;
904     default:
905       return false;
906     }
907 }
908 
909 int
microblaze_legitimate_pic_operand(rtx x)910 microblaze_legitimate_pic_operand (rtx x)
911 {
912   if (flag_pic == 2 && (symbol_mentioned_p(x) || label_mentioned_p(x)))
913     return 0;
914 
915   if (microblaze_tls_referenced_p(x))
916     return 0;
917 
918   return 1;
919 }
920 
921 /* Try machine-dependent ways of modifying an illegitimate address
922    to be legitimate.  If we find one, return the new, valid address.
923    This is used from only one place: `memory_address' in explow.c.
924 
925    OLDX is the address as it was before break_out_memory_refs was
926    called.  In some cases it is useful to look at this to decide what
927    needs to be done.
928 
929    It is always safe for this function to do nothing.  It exists to
930    recognize opportunities to optimize the output.
931 
932    For the MicroBlaze, transform:
933 
934    memory(X + <large int>)
935 
936    into:
937 
938    Y = <large int> & ~0x7fff;
939    Z = X + Y
940    memory (Z + (<large int> & 0x7fff));
941 
942    This is for CSE to find several similar references, and only use one Z.
943 
944    When PIC, convert addresses of the form memory (symbol+large int) to
945    memory (reg+large int).  */
946 
947 static rtx
microblaze_legitimize_address(rtx x,rtx oldx ATTRIBUTE_UNUSED,machine_mode mode ATTRIBUTE_UNUSED)948 microblaze_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
949 			       machine_mode mode ATTRIBUTE_UNUSED)
950 {
951   register rtx xinsn = x, result;
952 
953   if (GET_CODE (xinsn) == CONST
954       && flag_pic && pic_address_needs_scratch (xinsn))
955     {
956       rtx ptr_reg = gen_reg_rtx (Pmode);
957       rtx constant = XEXP (XEXP (xinsn, 0), 1);
958 
959       emit_move_insn (ptr_reg, XEXP (XEXP (xinsn, 0), 0));
960 
961       result = gen_rtx_PLUS (Pmode, ptr_reg, constant);
962       if (SMALL_INT (constant))
963 	return result;
964       /* Otherwise we fall through so the code below will fix the
965          constant.  */
966       xinsn = result;
967     }
968 
969   if (GET_CODE (xinsn) == PLUS)
970     {
971       register rtx xplus0 = XEXP (xinsn, 0);
972       register rtx xplus1 = XEXP (xinsn, 1);
973       register enum rtx_code code0 = GET_CODE (xplus0);
974       register enum rtx_code code1 = GET_CODE (xplus1);
975 
976       if (code0 != REG && code1 == REG)
977 	{
978 	  xplus0 = XEXP (xinsn, 1);
979 	  xplus1 = XEXP (xinsn, 0);
980 	  code0 = GET_CODE (xplus0);
981 	  code1 = GET_CODE (xplus1);
982 	}
983 
984       if (code0 == REG && REG_OK_FOR_BASE_P (xplus0)
985 	  && code1 == CONST_INT && !SMALL_INT (xplus1))
986 	{
987 	  rtx int_reg = gen_reg_rtx (Pmode);
988 	  rtx ptr_reg = gen_reg_rtx (Pmode);
989 
990 	  emit_move_insn (int_reg, GEN_INT (INTVAL (xplus1) & ~0x7fff));
991 
992 	  emit_insn (gen_rtx_SET (ptr_reg,
993 				  gen_rtx_PLUS (Pmode, xplus0, int_reg)));
994 
995 	  result = gen_rtx_PLUS (Pmode, ptr_reg,
996 				 GEN_INT (INTVAL (xplus1) & 0x7fff));
997 	  return result;
998 	}
999 
1000       if (code0 == REG && REG_OK_FOR_BASE_P (xplus0))
1001 	{
1002 	  if (reload_in_progress)
1003 	    df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
1004 	  if (code1 == CONST)
1005 	    {
1006 	      xplus1 = XEXP (xplus1, 0);
1007 	      code1 = GET_CODE (xplus1);
1008 	    }
1009 	  if (code1 == SYMBOL_REF)
1010 	    {
1011 	      if (microblaze_tls_symbol_p(xplus1))
1012 		{
1013 		  rtx tls_ref, reg;
1014 		  reg = gen_reg_rtx (Pmode);
1015 
1016 		  tls_ref = microblaze_legitimize_tls_address (xplus1,
1017 							       NULL_RTX);
1018 		  emit_move_insn (reg, tls_ref);
1019 
1020 		  result = gen_rtx_PLUS (Pmode, xplus0, reg);
1021 
1022 		  return result;
1023 		}
1024 	      else if (flag_pic == 2)
1025 		{
1026 		  rtx pic_ref, reg;
1027 		  reg = gen_reg_rtx (Pmode);
1028 
1029 		  pic_ref = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, xplus1),
1030 					    UNSPEC_GOTOFF);
1031 		  pic_ref = gen_rtx_CONST (Pmode, pic_ref);
1032 		  pic_ref = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, pic_ref);
1033 		  pic_ref = gen_const_mem (Pmode, pic_ref);
1034 		  emit_move_insn (reg, pic_ref);
1035 		  result = gen_rtx_PLUS (Pmode, xplus0, reg);
1036 		  return result;
1037 		}
1038 	    }
1039 	}
1040     }
1041 
1042   if (GET_CODE (xinsn) == SYMBOL_REF)
1043     {
1044       rtx reg;
1045       if (microblaze_tls_symbol_p(xinsn))
1046         {
1047           reg = microblaze_legitimize_tls_address (xinsn, NULL_RTX);
1048         }
1049       else
1050         {
1051           rtx pic_ref;
1052 
1053           if (reload_in_progress)
1054             df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
1055 
1056           pic_ref = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, xinsn), UNSPEC_GOTOFF);
1057           pic_ref = gen_rtx_CONST (Pmode, pic_ref);
1058           pic_ref = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, pic_ref);
1059           pic_ref = gen_const_mem (Pmode, pic_ref);
1060           reg = pic_ref;
1061         }
1062       return reg;
1063     }
1064 
1065   return x;
1066 }
1067 
1068 /* Block Moves.  */
1069 
1070 #define MAX_MOVE_REGS 8
1071 #define MAX_MOVE_BYTES (MAX_MOVE_REGS * UNITS_PER_WORD)
1072 
1073 /* Emit straight-line code to move LENGTH bytes from SRC to DEST.
1074    Assume that the areas do not overlap.  */
1075 
1076 static void
microblaze_block_move_straight(rtx dest,rtx src,HOST_WIDE_INT length)1077 microblaze_block_move_straight (rtx dest, rtx src, HOST_WIDE_INT length)
1078 {
1079   HOST_WIDE_INT offset, delta;
1080   unsigned HOST_WIDE_INT bits;
1081   int i;
1082   machine_mode mode;
1083   rtx *regs;
1084 
1085   bits = BITS_PER_WORD;
1086   mode = mode_for_size (bits, MODE_INT, 0);
1087   delta = bits / BITS_PER_UNIT;
1088 
1089   /* Allocate a buffer for the temporary registers.  */
1090   regs = XALLOCAVEC (rtx, length / delta);
1091 
1092   /* Load as many BITS-sized chunks as possible.  Use a normal load if
1093      the source has enough alignment, otherwise use left/right pairs.  */
1094   for (offset = 0, i = 0; offset + delta <= length; offset += delta, i++)
1095     {
1096       regs[i] = gen_reg_rtx (mode);
1097       emit_move_insn (regs[i], adjust_address (src, mode, offset));
1098     }
1099 
1100   /* Copy the chunks to the destination.  */
1101   for (offset = 0, i = 0; offset + delta <= length; offset += delta, i++)
1102     emit_move_insn (adjust_address (dest, mode, offset), regs[i]);
1103 
1104   /* Mop up any left-over bytes.  */
1105   if (offset < length)
1106     {
1107       src = adjust_address (src, BLKmode, offset);
1108       dest = adjust_address (dest, BLKmode, offset);
1109       move_by_pieces (dest, src, length - offset,
1110 		      MIN (MEM_ALIGN (src), MEM_ALIGN (dest)), 0);
1111     }
1112 }
1113 
1114 /* Helper function for doing a loop-based block operation on memory
1115    reference MEM.  Each iteration of the loop will operate on LENGTH
1116    bytes of MEM.
1117 
1118    Create a new base register for use within the loop and point it to
1119    the start of MEM.  Create a new memory reference that uses this
1120    register.  Store them in *LOOP_REG and *LOOP_MEM respectively.  */
1121 
1122 static void
microblaze_adjust_block_mem(rtx mem,HOST_WIDE_INT length,rtx * loop_reg,rtx * loop_mem)1123 microblaze_adjust_block_mem (rtx mem, HOST_WIDE_INT length,
1124 			     rtx * loop_reg, rtx * loop_mem)
1125 {
1126   *loop_reg = copy_addr_to_reg (XEXP (mem, 0));
1127 
1128   /* Although the new mem does not refer to a known location,
1129      it does keep up to LENGTH bytes of alignment.  */
1130   *loop_mem = change_address (mem, BLKmode, *loop_reg);
1131   set_mem_align (*loop_mem,
1132 		 MIN ((HOST_WIDE_INT) MEM_ALIGN (mem),
1133 		      length * BITS_PER_UNIT));
1134 }
1135 
1136 
1137 /* Move LENGTH bytes from SRC to DEST using a loop that moves MAX_MOVE_BYTES
1138    per iteration.  LENGTH must be at least MAX_MOVE_BYTES.  Assume that the
1139    memory regions do not overlap.  */
1140 
1141 static void
microblaze_block_move_loop(rtx dest,rtx src,HOST_WIDE_INT length)1142 microblaze_block_move_loop (rtx dest, rtx src, HOST_WIDE_INT length)
1143 {
1144   rtx_code_label *label;
1145   rtx src_reg, dest_reg, final_src;
1146   HOST_WIDE_INT leftover;
1147 
1148   leftover = length % MAX_MOVE_BYTES;
1149   length -= leftover;
1150 
1151   /* Create registers and memory references for use within the loop.  */
1152   microblaze_adjust_block_mem (src, MAX_MOVE_BYTES, &src_reg, &src);
1153   microblaze_adjust_block_mem (dest, MAX_MOVE_BYTES, &dest_reg, &dest);
1154 
1155   /* Calculate the value that SRC_REG should have after the last iteration
1156      of the loop.  */
1157   final_src = expand_simple_binop (Pmode, PLUS, src_reg, GEN_INT (length),
1158 				   0, 0, OPTAB_WIDEN);
1159 
1160   /* Emit the start of the loop.  */
1161   label = gen_label_rtx ();
1162   emit_label (label);
1163 
1164   /* Emit the loop body.  */
1165   microblaze_block_move_straight (dest, src, MAX_MOVE_BYTES);
1166 
1167   /* Move on to the next block.  */
1168   emit_move_insn (src_reg, plus_constant (Pmode, src_reg, MAX_MOVE_BYTES));
1169   emit_move_insn (dest_reg, plus_constant (Pmode, dest_reg, MAX_MOVE_BYTES));
1170 
1171   /* Emit the test & branch.  */
1172   emit_insn (gen_cbranchsi4 (gen_rtx_NE (SImode, src_reg, final_src),
1173 			     src_reg, final_src, label));
1174 
1175   /* Mop up any left-over bytes.  */
1176   if (leftover)
1177     microblaze_block_move_straight (dest, src, leftover);
1178 }
1179 
1180 /* Expand a movmemsi instruction.  */
1181 
1182 bool
microblaze_expand_block_move(rtx dest,rtx src,rtx length,rtx align_rtx)1183 microblaze_expand_block_move (rtx dest, rtx src, rtx length, rtx align_rtx)
1184 {
1185 
1186   if (GET_CODE (length) == CONST_INT)
1187     {
1188       HOST_WIDE_INT bytes = INTVAL (length);
1189       int align = INTVAL (align_rtx);
1190 
1191       if (align > UNITS_PER_WORD)
1192 	{
1193 	  align = UNITS_PER_WORD;	/* We can't do any better.  */
1194 	}
1195       else if (align < UNITS_PER_WORD)
1196 	{
1197 	  if (INTVAL (length) <= MAX_MOVE_BYTES)
1198 	    {
1199 	      move_by_pieces (dest, src, bytes, align, 0);
1200 	      return true;
1201 	    }
1202 	  else
1203 	    return false;
1204 	}
1205 
1206       if (INTVAL (length) <= 2 * MAX_MOVE_BYTES)
1207 	{
1208 	  microblaze_block_move_straight (dest, src, INTVAL (length));
1209 	  return true;
1210 	}
1211       else if (optimize)
1212 	{
1213 	  microblaze_block_move_loop (dest, src, INTVAL (length));
1214 	  return true;
1215 	}
1216     }
1217   return false;
1218 }
1219 
1220 static bool
microblaze_rtx_costs(rtx x,machine_mode mode,int outer_code ATTRIBUTE_UNUSED,int opno ATTRIBUTE_UNUSED,int * total,bool speed ATTRIBUTE_UNUSED)1221 microblaze_rtx_costs (rtx x, machine_mode mode, int outer_code ATTRIBUTE_UNUSED,
1222 		      int opno ATTRIBUTE_UNUSED, int *total,
1223 		      bool speed ATTRIBUTE_UNUSED)
1224 {
1225   int code = GET_CODE (x);
1226 
1227   switch (code)
1228     {
1229     case MEM:
1230       {
1231 	int num_words = (GET_MODE_SIZE (mode) > UNITS_PER_WORD) ? 2 : 1;
1232 	if (simple_memory_operand (x, mode))
1233 	  *total = COSTS_N_INSNS (2 * num_words);
1234 	else
1235 	  *total = COSTS_N_INSNS (2 * (2 * num_words));
1236 
1237 	return true;
1238       }
1239     case NOT:
1240       {
1241 	if (mode == DImode)
1242 	  {
1243 	    *total = COSTS_N_INSNS (2);
1244 	  }
1245 	else
1246 	  *total = COSTS_N_INSNS (1);
1247 	return false;
1248       }
1249     case AND:
1250     case IOR:
1251     case XOR:
1252       {
1253 	if (mode == DImode)
1254 	  {
1255 	    *total = COSTS_N_INSNS (2);
1256 	  }
1257 	else
1258 	  *total = COSTS_N_INSNS (1);
1259 
1260 	return false;
1261       }
1262     case ASHIFT:
1263     case ASHIFTRT:
1264     case LSHIFTRT:
1265       {
1266 	if (TARGET_BARREL_SHIFT)
1267 	  {
1268 	    if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v5.00.a")
1269 		>= 0)
1270 	      *total = COSTS_N_INSNS (1);
1271 	    else
1272 	      *total = COSTS_N_INSNS (2);
1273 	  }
1274 	else if (!TARGET_SOFT_MUL)
1275 	  *total = COSTS_N_INSNS (1);
1276 	else if (GET_CODE (XEXP (x, 1)) == CONST_INT)
1277 	  {
1278 	    /* Add 1 to make shift slightly more expensive than add.  */
1279 	    *total = COSTS_N_INSNS (INTVAL (XEXP (x, 1))) + 1;
1280 	    /* Reduce shift costs for special circumstances.  */
1281 	    if (optimize_size && INTVAL (XEXP (x, 1)) > 5)
1282 	      *total -= 2;
1283 	    if (!optimize_size && INTVAL (XEXP (x, 1)) > 17)
1284 	      *total -= 2;
1285 	  }
1286 	else
1287 	  /* Double the worst cost of shifts when there is no barrel shifter and
1288 	     the shift amount is in a reg.  */
1289 	  *total = COSTS_N_INSNS (32 * 4);
1290 	return true;
1291       }
1292     case PLUS:
1293     case MINUS:
1294       {
1295 	if (mode == SFmode || mode == DFmode)
1296 	  {
1297 	    if (TARGET_HARD_FLOAT)
1298 	      *total = COSTS_N_INSNS (6);
1299 	    return true;
1300 	  }
1301 	else if (mode == DImode)
1302 	  {
1303 	    *total = COSTS_N_INSNS (4);
1304 	    return true;
1305 	  }
1306 	else
1307 	  {
1308 	    *total = COSTS_N_INSNS (1);
1309 	    return true;
1310 	  }
1311 
1312 	return false;
1313       }
1314     case NEG:
1315       {
1316 	if (mode == DImode)
1317 	  *total = COSTS_N_INSNS (4);
1318 
1319 	return false;
1320       }
1321     case MULT:
1322       {
1323 	if (mode == SFmode)
1324 	  {
1325 	    if (TARGET_HARD_FLOAT)
1326 	      *total = COSTS_N_INSNS (6);
1327 	  }
1328 	else if (!TARGET_SOFT_MUL)
1329 	  {
1330 	    if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v5.00.a")
1331 		>= 0)
1332 	      *total = COSTS_N_INSNS (1);
1333 	    else
1334 	      *total = COSTS_N_INSNS (3);
1335 	  }
1336 	else
1337 	  *total = COSTS_N_INSNS (10);
1338 	return true;
1339       }
1340     case DIV:
1341     case UDIV:
1342       {
1343 	if (mode == SFmode)
1344 	  {
1345 	    if (TARGET_HARD_FLOAT)
1346 	      *total = COSTS_N_INSNS (23);
1347 	  }
1348 	return false;
1349       }
1350     case SIGN_EXTEND:
1351       {
1352 	*total = COSTS_N_INSNS (1);
1353 	return false;
1354       }
1355     case ZERO_EXTEND:
1356       {
1357 	*total = COSTS_N_INSNS (1);
1358 	return false;
1359       }
1360     }
1361 
1362   return false;
1363 }
1364 
1365 /* Return the number of instructions needed to load or store a value
1366    of mode MODE at X.  Return 0 if X isn't valid for MODE.  */
1367 
1368 static int
microblaze_address_insns(rtx x,machine_mode mode)1369 microblaze_address_insns (rtx x, machine_mode mode)
1370 {
1371   struct microblaze_address_info addr;
1372 
1373   if (microblaze_classify_address (&addr, x, mode, false))
1374     {
1375       switch (addr.type)
1376 	{
1377 	case ADDRESS_REG:
1378 	  if (SMALL_INT (addr.offset))
1379 	    return 1;
1380 	  else
1381 	    return 2;
1382 	case ADDRESS_CONST_INT:
1383 	  if (SMALL_INT (x))
1384 	    return 1;
1385 	  else
1386 	    return 2;
1387 	case ADDRESS_REG_INDEX:
1388 	  return 1;
1389 	case ADDRESS_SYMBOLIC:
1390 	case ADDRESS_GOTOFF:
1391 	  return 2;
1392 	case ADDRESS_TLS:
1393 	  switch (addr.tls_type)
1394 	    {
1395 	      case TLS_GD:
1396 		return 2;
1397 	      case TLS_LDM:
1398 		return 2;
1399 	      case TLS_DTPREL:
1400 		return 1;
1401 	      default :
1402 		abort();
1403 	    }
1404 	default:
1405 	  break;
1406 	}
1407     }
1408   return 0;
1409 }
1410 
1411 /* Provide the costs of an addressing mode that contains ADDR.
1412    If ADDR is not a valid address, its cost is irrelevant.  */
1413 static int
microblaze_address_cost(rtx addr,machine_mode mode ATTRIBUTE_UNUSED,addr_space_t as ATTRIBUTE_UNUSED,bool speed ATTRIBUTE_UNUSED)1414 microblaze_address_cost (rtx addr, machine_mode mode ATTRIBUTE_UNUSED,
1415 			 addr_space_t as ATTRIBUTE_UNUSED,
1416 			 bool speed ATTRIBUTE_UNUSED)
1417 {
1418   return COSTS_N_INSNS (microblaze_address_insns (addr, GET_MODE (addr)));
1419 }
1420 
1421 /* Return nonzero if X is an address which needs a temporary register when
1422    reloaded while generating PIC code.  */
1423 
1424 int
pic_address_needs_scratch(rtx x)1425 pic_address_needs_scratch (rtx x)
1426 {
1427   if (GET_CODE (x) == CONST && GET_CODE (XEXP (x,0)) == PLUS)
1428     {
1429      rtx p0, p1;
1430 
1431       p0 = XEXP (XEXP (x, 0), 0);
1432       p1 = XEXP (XEXP (x, 0), 1);
1433 
1434       if ((GET_CODE (p0) == SYMBOL_REF || GET_CODE (p0) == LABEL_REF)
1435           && (GET_CODE (p1) == CONST_INT)
1436           && (flag_pic == 2 || microblaze_tls_symbol_p (p0) || !SMALL_INT (p1)))
1437         return 1;
1438     }
1439   return 0;
1440 }
1441 
1442 /* Argument support functions.  */
1443 /* Initialize CUMULATIVE_ARGS for a function.  */
1444 
1445 void
init_cumulative_args(CUMULATIVE_ARGS * cum,tree fntype,rtx libname ATTRIBUTE_UNUSED)1446 init_cumulative_args (CUMULATIVE_ARGS * cum, tree fntype,
1447 		      rtx libname ATTRIBUTE_UNUSED)
1448 {
1449   static CUMULATIVE_ARGS zero_cum;
1450   tree param, next_param;
1451 
1452   *cum = zero_cum;
1453 
1454   /* Determine if this function has variable arguments.  This is
1455      indicated by the last argument being 'void_type_mode' if there
1456      are no variable arguments.  The standard MicroBlaze calling sequence
1457      passes all arguments in the general purpose registers in this case. */
1458 
1459   for (param = fntype ? TYPE_ARG_TYPES (fntype) : 0;
1460        param != 0; param = next_param)
1461     {
1462       next_param = TREE_CHAIN (param);
1463       if (next_param == 0 && TREE_VALUE (param) != void_type_node)
1464 	cum->gp_reg_found = 1;
1465     }
1466 }
1467 
1468 /* Advance the argument to the next argument position.  */
1469 
1470 static void
microblaze_function_arg_advance(cumulative_args_t cum_v,machine_mode mode,const_tree type,bool named ATTRIBUTE_UNUSED)1471 microblaze_function_arg_advance (cumulative_args_t cum_v,
1472 				 machine_mode mode,
1473 				 const_tree type, bool named ATTRIBUTE_UNUSED)
1474 {
1475   CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
1476 
1477   cum->arg_number++;
1478   switch (mode)
1479     {
1480     case VOIDmode:
1481       break;
1482 
1483     default:
1484       gcc_assert (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
1485 	  || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT);
1486 
1487       cum->gp_reg_found = 1;
1488       cum->arg_words += ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1)
1489 			 / UNITS_PER_WORD);
1490       break;
1491 
1492     case BLKmode:
1493       cum->gp_reg_found = 1;
1494       cum->arg_words += ((int_size_in_bytes (type) + UNITS_PER_WORD - 1)
1495 			 / UNITS_PER_WORD);
1496       break;
1497 
1498     case SFmode:
1499       cum->arg_words++;
1500       if (!cum->gp_reg_found && cum->arg_number <= 2)
1501 	cum->fp_code += 1 << ((cum->arg_number - 1) * 2);
1502       break;
1503 
1504     case DFmode:
1505       cum->arg_words += 2;
1506       if (!cum->gp_reg_found && cum->arg_number <= 2)
1507 	cum->fp_code += 2 << ((cum->arg_number - 1) * 2);
1508       break;
1509 
1510     case DImode:
1511       cum->gp_reg_found = 1;
1512       cum->arg_words += 2;
1513       break;
1514 
1515     case QImode:
1516     case HImode:
1517     case SImode:
1518     case TImode:
1519       cum->gp_reg_found = 1;
1520       cum->arg_words++;
1521       break;
1522     }
1523 }
1524 
1525 /* Return an RTL expression containing the register for the given mode,
1526    or 0 if the argument is to be passed on the stack.  */
1527 
1528 static rtx
microblaze_function_arg(cumulative_args_t cum_v,machine_mode mode,const_tree type ATTRIBUTE_UNUSED,bool named ATTRIBUTE_UNUSED)1529 microblaze_function_arg (cumulative_args_t cum_v, machine_mode mode,
1530 			 const_tree type ATTRIBUTE_UNUSED,
1531 			 bool named ATTRIBUTE_UNUSED)
1532 {
1533   CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
1534 
1535   rtx ret;
1536   int regbase = -1;
1537   int *arg_words = &cum->arg_words;
1538 
1539   cum->last_arg_fp = 0;
1540   switch (mode)
1541     {
1542     case SFmode:
1543     case DFmode:
1544     case VOIDmode:
1545     case QImode:
1546     case HImode:
1547     case SImode:
1548     case DImode:
1549     case TImode:
1550       regbase = GP_ARG_FIRST;
1551       break;
1552     default:
1553       gcc_assert (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
1554 	  || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT);
1555       /* Drops through.  */
1556     case BLKmode:
1557       regbase = GP_ARG_FIRST;
1558       break;
1559     }
1560 
1561   if (*arg_words >= MAX_ARGS_IN_REGISTERS)
1562     ret = 0;
1563   else
1564     {
1565       gcc_assert (regbase != -1);
1566 
1567       ret = gen_rtx_REG (mode, regbase + *arg_words);
1568     }
1569 
1570   if (mode == VOIDmode)
1571     {
1572       if (cum->num_adjusts > 0)
1573 	ret = gen_rtx_PARALLEL ((machine_mode) cum->fp_code,
1574 				gen_rtvec_v (cum->num_adjusts, cum->adjust));
1575     }
1576 
1577   return ret;
1578 }
1579 
1580 /* Return number of bytes of argument to put in registers. */
1581 static int
function_arg_partial_bytes(cumulative_args_t cum_v,machine_mode mode,tree type,bool named ATTRIBUTE_UNUSED)1582 function_arg_partial_bytes (cumulative_args_t cum_v, machine_mode mode,
1583 			    tree type, bool named ATTRIBUTE_UNUSED)
1584 {
1585   CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
1586 
1587   if ((mode == BLKmode
1588        || GET_MODE_CLASS (mode) != MODE_COMPLEX_INT
1589        || GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT)
1590       && cum->arg_words < MAX_ARGS_IN_REGISTERS)
1591     {
1592       int words;
1593       if (mode == BLKmode)
1594 	words = ((int_size_in_bytes (type) + UNITS_PER_WORD - 1)
1595 		 / UNITS_PER_WORD);
1596       else
1597 	words = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
1598 
1599       if (words + cum->arg_words <= MAX_ARGS_IN_REGISTERS)
1600 	return 0;		/* structure fits in registers */
1601 
1602       return (MAX_ARGS_IN_REGISTERS - cum->arg_words) * UNITS_PER_WORD;
1603     }
1604 
1605   else if (mode == DImode && cum->arg_words == MAX_ARGS_IN_REGISTERS - 1)
1606     return UNITS_PER_WORD;
1607 
1608   return 0;
1609 }
1610 
1611 /*  Convert a version number of the form "vX.YY.Z" to an integer encoding
1612     for easier range comparison.  */
1613 static int
microblaze_version_to_int(const char * version)1614 microblaze_version_to_int (const char *version)
1615 {
1616   const char *p, *v;
1617   const char *tmpl = "vXX.YY.Z";
1618   int iver = 0;
1619 
1620   p = version;
1621   v = tmpl;
1622 
1623   while (*p)
1624     {
1625       if (*v == 'X')
1626 	{			/* Looking for major  */
1627           if (*p == '.')
1628             {
1629               v++;
1630             }
1631           else
1632             {
1633 	      if (!(*p >= '0' && *p <= '9'))
1634 	        return -1;
1635 	      iver += (int) (*p - '0');
1636               iver *= 10;
1637 	     }
1638         }
1639       else if (*v == 'Y')
1640 	{			/* Looking for minor  */
1641 	  if (!(*p >= '0' && *p <= '9'))
1642 	    return -1;
1643 	  iver += (int) (*p - '0');
1644 	  iver *= 10;
1645 	}
1646       else if (*v == 'Z')
1647 	{			/* Looking for compat  */
1648 	  if (!(*p >= 'a' && *p <= 'z'))
1649 	    return -1;
1650 	  iver *= 10;
1651 	  iver += (int) (*p - 'a');
1652 	}
1653       else
1654 	{
1655 	  if (*p != *v)
1656 	    return -1;
1657 	}
1658 
1659       v++;
1660       p++;
1661     }
1662 
1663   if (*p)
1664     return -1;
1665 
1666   return iver;
1667 }
1668 
1669 
1670 static void
microblaze_option_override(void)1671 microblaze_option_override (void)
1672 {
1673   register int i, start;
1674   register int regno;
1675   register machine_mode mode;
1676   int ver;
1677 
1678   microblaze_section_threshold = (global_options_set.x_g_switch_value
1679 				  ? g_switch_value
1680 				  : MICROBLAZE_DEFAULT_GVALUE);
1681 
1682   if (flag_pic)
1683     {
1684       /* Make sure it's 2, we only support one kind of PIC.  */
1685       flag_pic = 2;
1686       if (!TARGET_SUPPORTS_PIC)
1687         {
1688           error ("-fPIC/-fpic not supported for this target");
1689           /* Clear it to avoid further errors.  */
1690           flag_pic = 0;
1691         }
1692     }
1693 
1694   /* Check the MicroBlaze CPU version for any special action to be done.  */
1695   if (microblaze_select_cpu == NULL)
1696     microblaze_select_cpu = MICROBLAZE_DEFAULT_CPU;
1697   ver = microblaze_version_to_int (microblaze_select_cpu);
1698   if (ver == -1)
1699     {
1700       error ("%qs is an invalid argument to -mcpu=", microblaze_select_cpu);
1701     }
1702 
1703   ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v3.00.a");
1704   if (ver < 0)
1705     {
1706       /* No hardware exceptions in earlier versions. So no worries.  */
1707 #if 0
1708       microblaze_select_flags &= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY);
1709 #endif
1710       microblaze_no_unsafe_delay = 0;
1711       microblaze_pipe = MICROBLAZE_PIPE_3;
1712     }
1713   else if (ver == 0
1714 	   || (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v4.00.b")
1715 	       == 0))
1716     {
1717 #if 0
1718       microblaze_select_flags |= (MICROBLAZE_MASK_NO_UNSAFE_DELAY);
1719 #endif
1720       microblaze_no_unsafe_delay = 1;
1721       microblaze_pipe = MICROBLAZE_PIPE_3;
1722     }
1723   else
1724     {
1725       /* We agree to use 5 pipe-stage model even on area optimized 3
1726          pipe-stage variants.  */
1727 #if 0
1728       microblaze_select_flags &= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY);
1729 #endif
1730       microblaze_no_unsafe_delay = 0;
1731       microblaze_pipe = MICROBLAZE_PIPE_5;
1732       if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v5.00.a") == 0
1733 	  || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu,
1734 					 "v5.00.b") == 0
1735 	  || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu,
1736 					 "v5.00.c") == 0)
1737 	{
1738 	  /* Pattern compares are to be turned on by default only when
1739  	     compiling for MB v5.00.'z'.  */
1740 	  target_flags |= MASK_PATTERN_COMPARE;
1741 	}
1742     }
1743 
1744   ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v6.00.a");
1745   if (ver < 0)
1746     {
1747       if (TARGET_MULTIPLY_HIGH)
1748 	warning (0,
1749 		 "-mxl-multiply-high can be used only with -mcpu=v6.00.a or greater");
1750     }
1751 
1752   ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v8.10.a");
1753   microblaze_has_clz = 1;
1754   if (ver < 0)
1755     {
1756         /* MicroBlaze prior to 8.10.a didn't have clz.  */
1757         microblaze_has_clz = 0;
1758     }
1759 
1760   /* TARGET_REORDER defaults to 2 if -mxl-reorder not specified.  */
1761   ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v8.30.a");
1762   if (ver < 0)
1763     {
1764         if (TARGET_REORDER == 1)
1765           warning (0, "-mxl-reorder can be used only with -mcpu=v8.30.a or greater");
1766         TARGET_REORDER = 0;
1767     }
1768   else if ((ver == 0) && !TARGET_PATTERN_COMPARE)
1769     {
1770         if (TARGET_REORDER == 1)
1771           warning (0, "-mxl-reorder requires -mxl-pattern-compare for -mcpu=v8.30.a");
1772         TARGET_REORDER = 0;
1773     }
1774 
1775   if (TARGET_MULTIPLY_HIGH && TARGET_SOFT_MUL)
1776     error ("-mxl-multiply-high requires -mno-xl-soft-mul");
1777 
1778   /* Always use DFA scheduler.  */
1779   microblaze_sched_use_dfa = 1;
1780 
1781 #if 0
1782   microblaze_abicalls = MICROBLAZE_ABICALLS_NO;
1783 #endif
1784 
1785   /* Initialize the high, low values for legit floating point constants.  */
1786   real_maxval (&dfhigh, 0, DFmode);
1787   real_maxval (&dflow, 1, DFmode);
1788   real_maxval (&sfhigh, 0, SFmode);
1789   real_maxval (&sflow, 1, SFmode);
1790 
1791   microblaze_print_operand_punct['?'] = 1;
1792   microblaze_print_operand_punct['#'] = 1;
1793   microblaze_print_operand_punct['&'] = 1;
1794   microblaze_print_operand_punct['!'] = 1;
1795   microblaze_print_operand_punct['*'] = 1;
1796   microblaze_print_operand_punct['@'] = 1;
1797   microblaze_print_operand_punct['.'] = 1;
1798   microblaze_print_operand_punct['('] = 1;
1799   microblaze_print_operand_punct[')'] = 1;
1800   microblaze_print_operand_punct['['] = 1;
1801   microblaze_print_operand_punct[']'] = 1;
1802   microblaze_print_operand_punct['<'] = 1;
1803   microblaze_print_operand_punct['>'] = 1;
1804   microblaze_print_operand_punct['{'] = 1;
1805   microblaze_print_operand_punct['}'] = 1;
1806   microblaze_print_operand_punct['^'] = 1;
1807   microblaze_print_operand_punct['$'] = 1;
1808   microblaze_print_operand_punct['+'] = 1;
1809 
1810   /* Set up array to map GCC register number to debug register number.
1811      Ignore the special purpose register numbers.  */
1812 
1813   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
1814     microblaze_dbx_regno[i] = -1;
1815 
1816   start = GP_DBX_FIRST - GP_REG_FIRST;
1817   for (i = GP_REG_FIRST; i <= GP_REG_LAST; i++)
1818     microblaze_dbx_regno[i] = i + start;
1819 
1820   /* Set up array giving whether a given register can hold a given mode.   */
1821 
1822   for (mode = VOIDmode;
1823        mode != MAX_MACHINE_MODE; mode = (machine_mode) ((int) mode + 1))
1824     {
1825       register int size = GET_MODE_SIZE (mode);
1826 
1827       for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
1828 	{
1829 	  register int ok;
1830 
1831 	  if (mode == CCmode)
1832 	    {
1833 	      ok = (ST_REG_P (regno) || GP_REG_P (regno));
1834 	    }
1835 	  else if (GP_REG_P (regno))
1836 	    ok = ((regno & 1) == 0 || size <= UNITS_PER_WORD);
1837 	  else
1838 	    ok = 0;
1839 
1840 	  microblaze_hard_regno_mode_ok[(int) mode][regno] = ok;
1841 	}
1842     }
1843 }
1844 
1845 /* Return true if FUNC is an interrupt function as specified
1846    by the "interrupt_handler" attribute.  */
1847 
1848 static int
microblaze_interrupt_function_p(tree func)1849 microblaze_interrupt_function_p (tree func)
1850 {
1851   tree a;
1852 
1853   if (TREE_CODE (func) != FUNCTION_DECL)
1854     return 0;
1855 
1856   a = lookup_attribute ("interrupt_handler", DECL_ATTRIBUTES (func));
1857   return a != NULL_TREE;
1858 }
1859 
1860 static int
microblaze_fast_interrupt_function_p(tree func)1861 microblaze_fast_interrupt_function_p (tree func)
1862 {
1863   tree a;
1864 
1865   if (TREE_CODE (func) != FUNCTION_DECL)
1866     return 0;
1867 
1868   a = lookup_attribute ("fast_interrupt", DECL_ATTRIBUTES (func));
1869   return a != NULL_TREE;
1870 }
1871 int
microblaze_break_function_p(tree func)1872 microblaze_break_function_p (tree func)
1873 {
1874   tree a;
1875   if (!func)
1876     return 0;
1877   if (TREE_CODE (func) != FUNCTION_DECL)
1878     return 0;
1879 
1880   a = lookup_attribute ("break_handler", DECL_ATTRIBUTES (func));
1881   return a != NULL_TREE;
1882 }
1883 /* Return true if FUNC is an interrupt function which uses
1884    normal return, indicated by the "save_volatiles" attribute.  */
1885 
1886 static int
microblaze_save_volatiles(tree func)1887 microblaze_save_volatiles (tree func)
1888 {
1889   tree a;
1890 
1891   if (TREE_CODE (func) != FUNCTION_DECL)
1892     return 0;
1893 
1894   a = lookup_attribute ("save_volatiles", DECL_ATTRIBUTES (func));
1895   return a != NULL_TREE;
1896 }
1897 
1898 /* Return whether function is tagged with 'interrupt_handler'
1899    or 'fast_interrupt' attribute.  Return true if function
1900    should use return from interrupt rather than normal
1901    function return.  */
1902 int
microblaze_is_interrupt_variant(void)1903 microblaze_is_interrupt_variant (void)
1904 {
1905   return (interrupt_handler || fast_interrupt);
1906 }
1907 int
microblaze_is_break_handler(void)1908 microblaze_is_break_handler (void)
1909 {
1910   return break_handler;
1911 }
1912 
1913 /* Determine of register must be saved/restored in call.  */
1914 static int
microblaze_must_save_register(int regno)1915 microblaze_must_save_register (int regno)
1916 {
1917   if (pic_offset_table_rtx &&
1918       (regno == MB_ABI_PIC_ADDR_REGNUM) && df_regs_ever_live_p (regno))
1919     return 1;
1920 
1921   if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
1922     return 1;
1923 
1924   if (frame_pointer_needed && (regno == HARD_FRAME_POINTER_REGNUM))
1925     return 1;
1926 
1927   if (!crtl->is_leaf)
1928     {
1929       if (regno == MB_ABI_SUB_RETURN_ADDR_REGNUM)
1930 	return 1;
1931       if ((microblaze_is_interrupt_variant () || save_volatiles) &&
1932 	  (regno >= 3 && regno <= 12))
1933 	return 1;
1934     }
1935 
1936   if (microblaze_is_interrupt_variant ())
1937     {
1938       if (df_regs_ever_live_p (regno)
1939 	  || regno == MB_ABI_MSR_SAVE_REG
1940 	  || (interrupt_handler
1941               && (regno == MB_ABI_ASM_TEMP_REGNUM
1942 	          || regno == MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM)))
1943 	return 1;
1944     }
1945 
1946   if (save_volatiles)
1947     {
1948       if (df_regs_ever_live_p (regno)
1949 	  || regno == MB_ABI_ASM_TEMP_REGNUM
1950 	  || regno == MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM)
1951 	return 1;
1952     }
1953 
1954   return 0;
1955 }
1956 
1957 /* Return the bytes needed to compute the frame pointer from the current
1958    stack pointer.
1959 
1960    MicroBlaze stack frames look like:
1961 
1962 
1963 
1964              Before call		        After call
1965         +-----------------------+	+-----------------------+
1966    high |			|       |      			|
1967    mem. |  local variables,     |	|  local variables,	|
1968         |  callee saved and     |       |  callee saved and    	|
1969 	|  temps     		|       |  temps     	        |
1970         +-----------------------+	+-----------------------+
1971         |  arguments for called	|       |  arguments for called |
1972 	|  subroutines		|	|  subroutines  	|
1973         |  (optional)           |       |  (optional)           |
1974         +-----------------------+	+-----------------------+
1975 	|  Link register 	|	|  Link register        |
1976     SP->|                       |       |                       |
1977 	+-----------------------+       +-----------------------+
1978 					|		        |
1979                                         |  local variables,     |
1980                                         |  callee saved and     |
1981                                         |  temps                |
1982 					+-----------------------+
1983                                         |   MSR (optional if,   |
1984                                         |   interrupt handler)  |
1985 					+-----------------------+
1986 					|			|
1987                                         |  alloca allocations   |
1988         				|			|
1989 					+-----------------------+
1990 					|			|
1991                                         |  arguments for called |
1992                                         |  subroutines          |
1993                                         |  (optional)           |
1994         				|		        |
1995 					+-----------------------+
1996                                         |  Link register        |
1997    low                           FP,SP->|                       |
1998    memory        			+-----------------------+
1999 
2000 */
2001 
2002 static HOST_WIDE_INT
compute_frame_size(HOST_WIDE_INT size)2003 compute_frame_size (HOST_WIDE_INT size)
2004 {
2005   int regno;
2006   HOST_WIDE_INT total_size;	/* # bytes that the entire frame takes up.  */
2007   HOST_WIDE_INT var_size;	/* # bytes that local variables take up.  */
2008   HOST_WIDE_INT args_size;	/* # bytes that outgoing arguments take up.  */
2009   int link_debug_size;		/* # bytes for link register.  */
2010   HOST_WIDE_INT gp_reg_size;	/* # bytes needed to store calle-saved gp regs.  */
2011   long mask;			/* mask of saved gp registers.  */
2012 
2013   interrupt_handler =
2014     microblaze_interrupt_function_p (current_function_decl);
2015   break_handler =
2016     microblaze_break_function_p (current_function_decl);
2017 
2018   fast_interrupt =
2019     microblaze_fast_interrupt_function_p (current_function_decl);
2020   save_volatiles = microblaze_save_volatiles (current_function_decl);
2021   if (break_handler)
2022     interrupt_handler = break_handler;
2023 
2024   gp_reg_size = 0;
2025   mask = 0;
2026   var_size = size;
2027   args_size = crtl->outgoing_args_size;
2028 
2029   if ((args_size == 0) && cfun->calls_alloca)
2030     args_size = NUM_OF_ARGS * UNITS_PER_WORD;
2031 
2032   total_size = var_size + args_size;
2033 
2034   if (flag_pic == 2)
2035     /* force setting GOT.  */
2036     df_set_regs_ever_live (MB_ABI_PIC_ADDR_REGNUM, true);
2037 
2038   /* Calculate space needed for gp registers.  */
2039   for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
2040     {
2041       if (microblaze_must_save_register (regno))
2042 	{
2043 
2044 	  if (regno != MB_ABI_SUB_RETURN_ADDR_REGNUM)
2045 	    /* Don't account for link register. It is accounted specially below.  */
2046 	    gp_reg_size += GET_MODE_SIZE (SImode);
2047 
2048 	  mask |= (1L << (regno - GP_REG_FIRST));
2049 	}
2050     }
2051 
2052   total_size += gp_reg_size;
2053 
2054   /* Add 4 bytes for MSR.  */
2055   if (microblaze_is_interrupt_variant ())
2056     total_size += 4;
2057 
2058   /* No space to be allocated for link register in leaf functions with no other
2059      stack requirements.  */
2060   if (total_size == 0 && crtl->is_leaf)
2061     link_debug_size = 0;
2062   else
2063     link_debug_size = UNITS_PER_WORD;
2064 
2065   total_size += link_debug_size;
2066 
2067   /* Save other computed information.  */
2068   current_frame_info.total_size = total_size;
2069   current_frame_info.var_size = var_size;
2070   current_frame_info.args_size = args_size;
2071   current_frame_info.gp_reg_size = gp_reg_size;
2072   current_frame_info.mask = mask;
2073   current_frame_info.initialized = reload_completed;
2074   current_frame_info.num_gp = gp_reg_size / UNITS_PER_WORD;
2075   current_frame_info.link_debug_size = link_debug_size;
2076 
2077   if (mask)
2078     /* Offset from which to callee-save GP regs.  */
2079     current_frame_info.gp_offset = (total_size - gp_reg_size);
2080   else
2081     current_frame_info.gp_offset = 0;
2082 
2083   /* Ok, we're done.  */
2084   return total_size;
2085 }
2086 
2087 /* Make sure that we're not trying to eliminate to the wrong hard frame
2088    pointer.  */
2089 
2090 static bool
microblaze_can_eliminate(const int from,const int to)2091 microblaze_can_eliminate (const int from, const int to)
2092 {
2093   return ((from == RETURN_ADDRESS_POINTER_REGNUM && !leaf_function_p())
2094    	  || (to == MB_ABI_SUB_RETURN_ADDR_REGNUM && leaf_function_p())
2095   	  || (from != RETURN_ADDRESS_POINTER_REGNUM
2096    	      && (to == HARD_FRAME_POINTER_REGNUM
2097 		  || (to == STACK_POINTER_REGNUM && !frame_pointer_needed))));
2098 }
2099 
2100 /* Implement INITIAL_ELIMINATION_OFFSET.  FROM is either the frame
2101    pointer or argument pointer or the return address pointer.  TO is either
2102    the stack pointer or hard frame pointer.  */
2103 
2104 HOST_WIDE_INT
microblaze_initial_elimination_offset(int from,int to)2105 microblaze_initial_elimination_offset (int from, int to)
2106 {
2107   HOST_WIDE_INT offset;
2108 
2109   switch (from)
2110     {
2111     case FRAME_POINTER_REGNUM:
2112       offset = 0;
2113       break;
2114     case ARG_POINTER_REGNUM:
2115       if (to == STACK_POINTER_REGNUM || to == HARD_FRAME_POINTER_REGNUM)
2116 	offset = compute_frame_size (get_frame_size ());
2117       else
2118 	gcc_unreachable ();
2119       break;
2120     case RETURN_ADDRESS_POINTER_REGNUM:
2121       if (crtl->is_leaf)
2122 	offset = 0;
2123       else
2124 	offset = current_frame_info.gp_offset +
2125 	  ((UNITS_PER_WORD - (POINTER_SIZE / BITS_PER_UNIT)));
2126       break;
2127     default:
2128       gcc_unreachable ();
2129     }
2130   return offset;
2131 }
2132 
2133 /* Print operands using format code.
2134 
2135    The MicroBlaze specific codes are:
2136 
2137    'X'  X is CONST_INT, prints 32 bits in hexadecimal format = "0x%08x",
2138    'x'  X is CONST_INT, prints 16 bits in hexadecimal format = "0x%04x",
2139    'F'  op is CONST_DOUBLE, print 32 bits in hex,
2140    'd'  output integer constant in decimal,
2141    'z'	if the operand is 0, use $0 instead of normal operand.
2142    'D'  print second register of double-word register operand.
2143    'L'  print low-order register of double-word register operand.
2144    'M'  print high-order register of double-word register operand.
2145    'C'  print part of opcode for a branch condition.
2146    'N'  print part of opcode for a branch condition, inverted.
2147    'S'  X is CODE_LABEL, print with prefix of "LS" (for embedded switch).
2148    'B'  print 'z' for EQ, 'n' for NE
2149    'b'  print 'n' for EQ, 'z' for NE
2150    'T'  print 'f' for EQ, 't' for NE
2151    't'  print 't' for EQ, 'f' for NE
2152    'm'  Print 1<<operand.
2153    'i'  Print 'i' if MEM operand has immediate value
2154    'y'  Print 'y' if MEM operand is single register
2155    'o'	Print operand address+4
2156    '?'	Print 'd' if we use a branch with delay slot instead of normal branch.
2157    'h'  Print high word of const_double (int or float) value as hex
2158    'j'  Print low word of const_double (int or float) value as hex
2159    's'  Print -1 if operand is negative, 0 if positive (sign extend)
2160    '@'	Print the name of the temporary register (rMB_ABI_ASM_TEMP_REGNUM).
2161    '#'	Print nop if the delay slot of a branch is not filled.
2162 */
2163 
2164 void
print_operand(FILE * file,rtx op,int letter)2165 print_operand (FILE * file, rtx op, int letter)
2166 {
2167   register enum rtx_code code;
2168 
2169   if (PRINT_OPERAND_PUNCT_VALID_P (letter))
2170     {
2171       switch (letter)
2172 	{
2173 	case '?':
2174 	  /* Conditionally add a 'd' to indicate filled delay slot.  */
2175 	  if (final_sequence != NULL)
2176 	    fputs ("d", file);
2177 	  break;
2178 
2179 	case '#':
2180 	  /* Conditionally add a nop in unfilled delay slot.  */
2181 	  if (final_sequence == NULL)
2182 	    fputs ("nop\t\t# Unfilled delay slot\n", file);
2183 	  break;
2184 
2185 	case '@':
2186 	  fputs (reg_names[GP_REG_FIRST + MB_ABI_ASM_TEMP_REGNUM], file);
2187 	  break;
2188 
2189 	default:
2190 	  output_operand_lossage ("unknown punctuation '%c'", letter);
2191 	  break;
2192 	}
2193 
2194       return;
2195     }
2196 
2197   if (!op)
2198     {
2199       output_operand_lossage ("null pointer");
2200       return;
2201     }
2202 
2203   code = GET_CODE (op);
2204 
2205   if (code == SIGN_EXTEND)
2206     op = XEXP (op, 0), code = GET_CODE (op);
2207 
2208   if (letter == 'C')
2209     switch (code)
2210       {
2211       case EQ:
2212 	fputs ("eq", file);
2213 	break;
2214       case NE:
2215 	fputs ("ne", file);
2216 	break;
2217       case GT:
2218       case GTU:
2219 	fputs ("gt", file);
2220 	break;
2221       case GE:
2222       case GEU:
2223 	fputs ("ge", file);
2224 	break;
2225       case LT:
2226       case LTU:
2227 	fputs ("lt", file);
2228 	break;
2229       case LE:
2230       case LEU:
2231 	fputs ("le", file);
2232 	break;
2233       default:
2234 	fatal_insn ("PRINT_OPERAND, invalid insn for %%C", op);
2235       }
2236 
2237   else if (letter == 'N')
2238     switch (code)
2239       {
2240       case EQ:
2241 	fputs ("ne", file);
2242 	break;
2243       case NE:
2244 	fputs ("eq", file);
2245 	break;
2246       case GT:
2247       case GTU:
2248 	fputs ("le", file);
2249 	break;
2250       case GE:
2251       case GEU:
2252 	fputs ("lt", file);
2253 	break;
2254       case LT:
2255       case LTU:
2256 	fputs ("ge", file);
2257 	break;
2258       case LE:
2259       case LEU:
2260 	fputs ("gt", file);
2261 	break;
2262       default:
2263 	fatal_insn ("PRINT_OPERAND, invalid insn for %%N", op);
2264       }
2265 
2266   else if (letter == 'S')
2267     {
2268       char buffer[100];
2269 
2270       ASM_GENERATE_INTERNAL_LABEL (buffer, "LS", CODE_LABEL_NUMBER (op));
2271       assemble_name (file, buffer);
2272     }
2273 
2274   /* Print 'i' for memory operands which have immediate values.  */
2275   else if (letter == 'i')
2276     {
2277       if (code == MEM)
2278 	{
2279 	  struct microblaze_address_info info;
2280 
2281 	  if (!microblaze_classify_address
2282 	      (&info, XEXP (op, 0), GET_MODE (op), 1))
2283 	    fatal_insn ("insn contains an invalid address !", op);
2284 
2285 	  switch (info.type)
2286 	    {
2287 	    case ADDRESS_REG:
2288 	    case ADDRESS_CONST_INT:
2289 	    case ADDRESS_SYMBOLIC:
2290 	    case ADDRESS_GOTOFF:
2291 	    case ADDRESS_TLS:
2292 	      fputs ("i", file);
2293 	      break;
2294 	    case ADDRESS_REG_INDEX:
2295 	      break;
2296 	    case ADDRESS_INVALID:
2297 	    case ADDRESS_PLT:
2298 	      fatal_insn ("invalid address", op);
2299 	    }
2300 	}
2301     }
2302 
2303   else if (code == REG || code == SUBREG)
2304     {
2305       register int regnum;
2306 
2307       if (code == REG)
2308 	regnum = REGNO (op);
2309       else
2310 	regnum = true_regnum (op);
2311 
2312       if ((letter == 'M' && !WORDS_BIG_ENDIAN)
2313 	  || (letter == 'L' && WORDS_BIG_ENDIAN) || letter == 'D')
2314 	regnum++;
2315 
2316       fprintf (file, "%s", reg_names[regnum]);
2317     }
2318 
2319   else if (code == MEM)
2320     if (letter == 'o')
2321       {
2322 	rtx op4 = adjust_address (op, GET_MODE (op), 4);
2323 	output_address (GET_MODE (op), XEXP (op4, 0));
2324       }
2325     else if (letter == 'y')
2326       {
2327         rtx mem_reg = XEXP (op, 0);
2328         if (GET_CODE (mem_reg) == REG)
2329         {
2330             register int regnum = REGNO (mem_reg);
2331             fprintf (file, "%s", reg_names[regnum]);
2332         }
2333       }
2334     else
2335       output_address (GET_MODE (op), XEXP (op, 0));
2336 
2337   else if (letter == 'h' || letter == 'j')
2338     {
2339       long val[2];
2340       if (code == CONST_DOUBLE)
2341 	{
2342 	  if (GET_MODE (op) == DFmode)
2343 	    REAL_VALUE_TO_TARGET_DOUBLE (*CONST_DOUBLE_REAL_VALUE (op), val);
2344 	  else
2345 	    {
2346 	      val[0] = CONST_DOUBLE_HIGH (op);
2347 	      val[1] = CONST_DOUBLE_LOW (op);
2348 	    }
2349 	}
2350       else if (code == CONST_INT)
2351         {
2352 	  val[0] = (INTVAL (op) & 0xffffffff00000000LL) >> 32;
2353 	  val[1] = INTVAL (op) & 0x00000000ffffffffLL;
2354 	  if (val[0] == 0 && val[1] < 0)
2355 	    val[0] = -1;
2356 
2357         }
2358       fprintf (file, "0x%8.8lx", (letter == 'h') ? val[0] : val[1]);
2359     }
2360   else if (code == CONST_DOUBLE)
2361     {
2362       if (letter == 'F')
2363 	{
2364 	  unsigned long value_long;
2365 	  REAL_VALUE_TO_TARGET_SINGLE (*CONST_DOUBLE_REAL_VALUE (op),
2366 				       value_long);
2367 	  fprintf (file, HOST_WIDE_INT_PRINT_HEX, value_long);
2368 	}
2369       else
2370 	{
2371 	  char s[60];
2372 	  real_to_decimal (s, CONST_DOUBLE_REAL_VALUE (op), sizeof (s), 0, 1);
2373 	  fputs (s, file);
2374 	}
2375     }
2376 
2377   else if (code == UNSPEC)
2378     {
2379       print_operand_address (file, op);
2380     }
2381 
2382   else if (letter == 'x' && GET_CODE (op) == CONST_INT)
2383     fprintf (file, HOST_WIDE_INT_PRINT_HEX, 0xffff & INTVAL (op));
2384 
2385   else if (letter == 'X' && GET_CODE (op) == CONST_INT)
2386     fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (op));
2387 
2388   else if (letter == 'd' && GET_CODE (op) == CONST_INT)
2389     fprintf (file, HOST_WIDE_INT_PRINT_DEC, (INTVAL (op)));
2390 
2391   else if (letter == 'z' && GET_CODE (op) == CONST_INT && INTVAL (op) == 0)
2392     fputs (reg_names[GP_REG_FIRST], file);
2393 
2394   else if (letter == 's' && GET_CODE (op) == CONST_INT)
2395     if (INTVAL (op) < 0)
2396       fputs ("-1", file);
2397     else
2398       fputs ("0", file);
2399 
2400   else if (letter == 'd' || letter == 'x' || letter == 'X' || letter == 's')
2401     output_operand_lossage ("letter %c was found & insn was not CONST_INT", letter);
2402 
2403   else if (letter == 'B')
2404     fputs (code == EQ ? "z" : "n", file);
2405   else if (letter == 'b')
2406     fputs (code == EQ ? "n" : "z", file);
2407   else if (letter == 'T')
2408     fputs (code == EQ ? "f" : "t", file);
2409   else if (letter == 't')
2410     fputs (code == EQ ? "t" : "f", file);
2411 
2412   else if (code == CONST
2413            && ((GET_CODE (XEXP (op, 0)) == REG)
2414                || (GET_CODE (XEXP (op, 0)) == UNSPEC)))
2415     {
2416       print_operand (file, XEXP (op, 0), letter);
2417     }
2418   else if (code == CONST
2419            && (GET_CODE (XEXP (op, 0)) == PLUS)
2420            && (GET_CODE (XEXP (XEXP (op, 0), 0)) == REG)
2421            && (GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST))
2422     {
2423       print_operand_address (file, XEXP (op, 0));
2424     }
2425   else if (letter == 'm')
2426     fprintf (file, HOST_WIDE_INT_PRINT_DEC, (1L << INTVAL (op)));
2427   else
2428     output_addr_const (file, op);
2429 }
2430 
2431 /* A C compound statement to output to stdio stream STREAM the
2432    assembler syntax for an instruction operand that is a memory
2433    reference whose address is ADDR.  ADDR is an RTL expression.
2434 
2435    Possible address classifications and output formats are,
2436 
2437    ADDRESS_REG                  "%0, r0"
2438 
2439    ADDRESS_REG with non-zero    "%0, <addr_const>"
2440    offset
2441 
2442    ADDRESS_REG_INDEX            "rA, RB"
2443                                 (if rA is r0, rA and rB are swapped)
2444 
2445    ADDRESS_CONST_INT            "r0, <addr_const>"
2446 
2447    ADDRESS_SYMBOLIC             "rBase, <addr_const>"
2448                                 (rBase is a base register suitable for the
2449 				 symbol's type)
2450 */
2451 
2452 void
print_operand_address(FILE * file,rtx addr)2453 print_operand_address (FILE * file, rtx addr)
2454 {
2455   struct microblaze_address_info info;
2456   enum microblaze_address_type type;
2457   if (!microblaze_classify_address (&info, addr, GET_MODE (addr), 1))
2458     fatal_insn ("insn contains an invalid address !", addr);
2459 
2460   type = info.type;
2461   switch (info.type)
2462     {
2463     case ADDRESS_REG:
2464       fprintf (file, "%s,", reg_names[REGNO (info.regA)]);
2465       output_addr_const (file, info.offset);
2466       break;
2467     case ADDRESS_REG_INDEX:
2468       if (REGNO (info.regA) == 0)
2469 	/* Make rB == r0 instead of rA == r0. This helps reduce read port
2470            congestion.  */
2471 	fprintf (file, "%s,%s", reg_names[REGNO (info.regB)],
2472 		 reg_names[REGNO (info.regA)]);
2473       else if (REGNO (info.regB) != 0)
2474 	/* This is a silly swap to help Dhrystone.  */
2475 	fprintf (file, "%s,%s", reg_names[REGNO (info.regB)],
2476 		 reg_names[REGNO (info.regA)]);
2477       break;
2478     case ADDRESS_CONST_INT:
2479       fprintf (file, "%s,", reg_names[REGNO (info.regA)]);
2480       output_addr_const (file, info.offset);
2481       break;
2482     case ADDRESS_SYMBOLIC:
2483     case ADDRESS_GOTOFF:
2484     case ADDRESS_PLT:
2485     case ADDRESS_TLS:
2486       if (info.regA)
2487 	fprintf (file, "%s,", reg_names[REGNO (info.regA)]);
2488       output_addr_const (file, info.symbol);
2489       if (type == ADDRESS_GOTOFF)
2490 	{
2491 	  fputs ("@GOT", file);
2492 	}
2493       else if (type == ADDRESS_PLT)
2494 	{
2495 	  fputs ("@PLT", file);
2496 	}
2497       else if (type == ADDRESS_TLS)
2498 	{
2499 	  switch (info.tls_type)
2500 	    {
2501 	      case TLS_GD:
2502 		fputs ("@TLSGD", file);
2503 		break;
2504 	      case TLS_LDM:
2505 		fputs ("@TLSLDM", file);
2506 		break;
2507 	      case TLS_DTPREL:
2508 		fputs ("@TLSDTPREL", file);
2509 		break;
2510 	      default :
2511 		abort();
2512 		break;
2513 	    }
2514 	}
2515       break;
2516     case ADDRESS_INVALID:
2517       fatal_insn ("invalid address", addr);
2518       break;
2519     }
2520 }
2521 
2522 /* Emit either a label, .comm, or .lcomm directive, and mark that the symbol
2523    is used, so that we don't emit an .extern for it in
2524    microblaze_asm_file_end.  */
2525 
2526 void
microblaze_declare_object(FILE * stream,const char * name,const char * section,const char * fmt,int size)2527 microblaze_declare_object (FILE * stream, const char *name,
2528 			   const char *section, const char *fmt, int size)
2529 {
2530 
2531   fputs (section, stream);
2532   assemble_name (stream, name);
2533   fprintf (stream, fmt, size);
2534 }
2535 
2536 /* Common code to emit the insns (or to write the instructions to a file)
2537    to save/restore registers.
2538 
2539    Other parts of the code assume that MICROBLAZE_TEMP1_REGNUM (aka large_reg)
2540    is not modified within save_restore_insns.  */
2541 
2542 #define BITSET_P(VALUE,BIT) (((VALUE) & (1L << (BIT))) != 0)
2543 
2544 /* Save or restore instructions based on whether this is the prologue or
2545    epilogue.  prologue is 1 for the prologue.  */
2546 static void
save_restore_insns(int prologue)2547 save_restore_insns (int prologue)
2548 {
2549   rtx base_reg_rtx, reg_rtx, mem_rtx, /* msr_rtx, */ isr_reg_rtx =
2550     0, isr_mem_rtx = 0;
2551   rtx isr_msr_rtx = 0, insn;
2552   long mask = current_frame_info.mask;
2553   HOST_WIDE_INT gp_offset;
2554   int regno;
2555 
2556   if (frame_pointer_needed
2557       && !BITSET_P (mask, HARD_FRAME_POINTER_REGNUM - GP_REG_FIRST))
2558     gcc_unreachable ();
2559 
2560   if (mask == 0)
2561     return;
2562 
2563   /* Save registers starting from high to low.  The debuggers prefer at least
2564      the return register be stored at func+4, and also it allows us not to
2565      need a nop in the epilog if at least one register is reloaded in
2566      addition to return address.  */
2567 
2568   /* Pick which pointer to use as a base register.  For small frames, just
2569      use the stack pointer.  Otherwise, use a temporary register.  Save 2
2570      cycles if the save area is near the end of a large frame, by reusing
2571      the constant created in the prologue/epilogue to adjust the stack
2572      frame.  */
2573 
2574   gp_offset = current_frame_info.gp_offset;
2575 
2576   gcc_assert (gp_offset > 0);
2577 
2578   base_reg_rtx = stack_pointer_rtx;
2579 
2580   /* For interrupt_handlers, need to save/restore the MSR.  */
2581   if (microblaze_is_interrupt_variant ())
2582     {
2583       isr_mem_rtx = gen_rtx_MEM (SImode,
2584 				 gen_rtx_PLUS (Pmode, base_reg_rtx,
2585 					       GEN_INT (current_frame_info.
2586 							gp_offset -
2587 							UNITS_PER_WORD)));
2588 
2589       /* Do not optimize in flow analysis.  */
2590       MEM_VOLATILE_P (isr_mem_rtx) = 1;
2591       isr_reg_rtx = gen_rtx_REG (SImode, MB_ABI_MSR_SAVE_REG);
2592       isr_msr_rtx = gen_rtx_REG (SImode, ST_REG);
2593     }
2594 
2595   if (microblaze_is_interrupt_variant () && !prologue)
2596     {
2597       emit_move_insn (isr_reg_rtx, isr_mem_rtx);
2598       emit_move_insn (isr_msr_rtx, isr_reg_rtx);
2599       /* Do not optimize in flow analysis.  */
2600       emit_insn (gen_rtx_USE (SImode, isr_reg_rtx));
2601       emit_insn (gen_rtx_USE (SImode, isr_msr_rtx));
2602     }
2603 
2604   for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
2605     {
2606       if (BITSET_P (mask, regno - GP_REG_FIRST))
2607 	{
2608 	  if (regno == MB_ABI_SUB_RETURN_ADDR_REGNUM)
2609 	    /* Don't handle here. Already handled as the first register.  */
2610 	    continue;
2611 
2612 	  reg_rtx = gen_rtx_REG (SImode, regno);
2613 	  insn = gen_rtx_PLUS (Pmode, base_reg_rtx, GEN_INT (gp_offset));
2614 	  mem_rtx = gen_rtx_MEM (SImode, insn);
2615 	  if (microblaze_is_interrupt_variant () || save_volatiles)
2616 	    /* Do not optimize in flow analysis.  */
2617 	    MEM_VOLATILE_P (mem_rtx) = 1;
2618 
2619 	  if (prologue)
2620 	    {
2621 	      insn = emit_move_insn (mem_rtx, reg_rtx);
2622 	      RTX_FRAME_RELATED_P (insn) = 1;
2623 	    }
2624 	  else
2625 	    {
2626 	      insn = emit_move_insn (reg_rtx, mem_rtx);
2627 	    }
2628 
2629 	  gp_offset += GET_MODE_SIZE (SImode);
2630 	}
2631     }
2632 
2633   if (microblaze_is_interrupt_variant () && prologue)
2634     {
2635       emit_move_insn (isr_reg_rtx, isr_msr_rtx);
2636       emit_move_insn (isr_mem_rtx, isr_reg_rtx);
2637 
2638       /* Do not optimize in flow analysis.  */
2639       emit_insn (gen_rtx_USE (SImode, isr_reg_rtx));
2640       emit_insn (gen_rtx_USE (SImode, isr_msr_rtx));
2641     }
2642 
2643   /* Done saving and restoring */
2644 }
2645 
2646 
2647 /* Set up the stack and frame (if desired) for the function.  */
2648 static void
microblaze_function_prologue(FILE * file,HOST_WIDE_INT size ATTRIBUTE_UNUSED)2649 microblaze_function_prologue (FILE * file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
2650 {
2651   const char *fnname;
2652   long fsiz = current_frame_info.total_size;
2653 
2654   /* Get the function name the same way that toplev.c does before calling
2655      assemble_start_function.  This is needed so that the name used here
2656      exactly matches the name used in ASM_DECLARE_FUNCTION_NAME.  */
2657   fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
2658   if (!flag_inhibit_size_directive)
2659     {
2660       fputs ("\t.ent\t", file);
2661       if (interrupt_handler && strcmp (INTERRUPT_HANDLER_NAME, fnname))
2662         fputs ("_interrupt_handler", file);
2663       else if (break_handler && strcmp (BREAK_HANDLER_NAME, fnname))
2664 	fputs ("_break_handler", file);
2665       else if (fast_interrupt && strcmp (FAST_INTERRUPT_NAME, fnname))
2666         fputs ("_fast_interrupt", file);
2667       else
2668 	assemble_name (file, fnname);
2669       fputs ("\n", file);
2670       if (!microblaze_is_interrupt_variant ())
2671 	ASM_OUTPUT_TYPE_DIRECTIVE (file, fnname, "function");
2672     }
2673 
2674   assemble_name (file, fnname);
2675   fputs (":\n", file);
2676 
2677   if (interrupt_handler && strcmp (INTERRUPT_HANDLER_NAME, fnname))
2678     fputs ("_interrupt_handler:\n", file);
2679   if (break_handler && strcmp (BREAK_HANDLER_NAME, fnname))
2680     fputs ("_break_handler:\n", file);
2681   if (!flag_inhibit_size_directive)
2682     {
2683       /* .frame FRAMEREG, FRAMESIZE, RETREG.  */
2684       fprintf (file,
2685 	       "\t.frame\t%s,%ld,%s\t\t# vars= %ld, regs= %d, args= %d\n",
2686 	       (reg_names[(frame_pointer_needed)
2687 			  ? HARD_FRAME_POINTER_REGNUM :
2688 			  STACK_POINTER_REGNUM]), fsiz,
2689 	       reg_names[MB_ABI_SUB_RETURN_ADDR_REGNUM + GP_REG_FIRST],
2690 	       current_frame_info.var_size, current_frame_info.num_gp,
2691 	       crtl->outgoing_args_size);
2692       fprintf (file, "\t.mask\t0x%08lx\n", current_frame_info.mask);
2693     }
2694 }
2695 
2696 /* Output extra assembler code at the end of a prologue.  */
2697 static void
microblaze_function_end_prologue(FILE * file)2698 microblaze_function_end_prologue (FILE * file)
2699 {
2700   if (TARGET_STACK_CHECK)
2701     {
2702       fprintf (file, "\t# Stack Check Stub -- Start.\n\t");
2703       fprintf (file, "ori\tr18,r0,_stack_end\n\t");
2704       fprintf (file, "cmpu\tr18,r1,r18\n\t");
2705       fprintf (file, "bgei\tr18,_stack_overflow_exit\n\t");
2706       fprintf (file, "# Stack Check Stub -- End.\n");
2707     }
2708 }
2709 
2710 static void
microblaze_elf_asm_cdtor(rtx symbol,int priority,bool is_ctor)2711 microblaze_elf_asm_cdtor (rtx symbol, int priority, bool is_ctor)
2712 {
2713   section *s;
2714 
2715   if (priority != DEFAULT_INIT_PRIORITY)
2716     {
2717       char buf[18];
2718       sprintf (buf, "%s.%.5u",
2719                is_ctor ? ".ctors" : ".dtors",
2720                MAX_INIT_PRIORITY - priority);
2721       s = get_section (buf, SECTION_WRITE, NULL_TREE);
2722     }
2723   else if (is_ctor)
2724     s = ctors_section;
2725   else
2726     s = dtors_section;
2727 
2728   switch_to_section (s);
2729   assemble_align (POINTER_SIZE);
2730   fputs ("\t.word\t", asm_out_file);
2731   output_addr_const (asm_out_file, symbol);
2732   fputs ("\n", asm_out_file);
2733 }
2734 
2735 /* Add a function to the list of static constructors.  */
2736 
2737 static void
microblaze_elf_asm_constructor(rtx symbol,int priority)2738 microblaze_elf_asm_constructor (rtx symbol, int priority)
2739 {
2740   microblaze_elf_asm_cdtor (symbol, priority, /*is_ctor=*/true);
2741 }
2742 
2743 /* Add a function to the list of static destructors.  */
2744 
2745 static void
microblaze_elf_asm_destructor(rtx symbol,int priority)2746 microblaze_elf_asm_destructor (rtx symbol, int priority)
2747 {
2748   microblaze_elf_asm_cdtor (symbol, priority, /*is_ctor=*/false);
2749 }
2750 
2751 /* Expand the prologue into a bunch of separate insns.  */
2752 
2753 void
microblaze_expand_prologue(void)2754 microblaze_expand_prologue (void)
2755 {
2756   int regno;
2757   HOST_WIDE_INT fsiz;
2758   const char *arg_name = 0;
2759   tree fndecl = current_function_decl;
2760   tree fntype = TREE_TYPE (fndecl);
2761   tree fnargs = DECL_ARGUMENTS (fndecl);
2762   rtx next_arg_reg;
2763   int i;
2764   tree next_arg;
2765   tree cur_arg;
2766   CUMULATIVE_ARGS args_so_far_v;
2767   cumulative_args_t args_so_far;
2768   rtx mem_rtx, reg_rtx;
2769 
2770   /* If struct value address is treated as the first argument, make it so.  */
2771   if (aggregate_value_p (DECL_RESULT (fndecl), fntype)
2772       && !cfun->returns_pcc_struct)
2773     {
2774       tree type = build_pointer_type (fntype);
2775       tree function_result_decl = build_decl (BUILTINS_LOCATION, PARM_DECL,
2776 					      NULL_TREE, type);
2777 
2778       DECL_ARG_TYPE (function_result_decl) = type;
2779       TREE_CHAIN (function_result_decl) = fnargs;
2780       fnargs = function_result_decl;
2781     }
2782 
2783   /* Determine the last argument, and get its name.  */
2784 
2785   INIT_CUMULATIVE_ARGS (args_so_far_v, fntype, NULL_RTX, 0, 0);
2786   args_so_far = pack_cumulative_args (&args_so_far_v);
2787   regno = GP_ARG_FIRST;
2788 
2789   for (cur_arg = fnargs; cur_arg != 0; cur_arg = next_arg)
2790     {
2791       tree passed_type = DECL_ARG_TYPE (cur_arg);
2792       machine_mode passed_mode = TYPE_MODE (passed_type);
2793       rtx entry_parm;
2794 
2795       if (TREE_ADDRESSABLE (passed_type))
2796 	{
2797 	  passed_type = build_pointer_type (passed_type);
2798 	  passed_mode = Pmode;
2799 	}
2800 
2801       entry_parm = targetm.calls.function_arg (args_so_far, passed_mode,
2802 					       passed_type, true);
2803 
2804       if (entry_parm)
2805 	{
2806 	  int words;
2807 
2808 	  /* passed in a register, so will get homed automatically.  */
2809 	  if (GET_MODE (entry_parm) == BLKmode)
2810 	    words = (int_size_in_bytes (passed_type) + 3) / 4;
2811 	  else
2812 	    words = (GET_MODE_SIZE (GET_MODE (entry_parm)) + 3) / 4;
2813 
2814 	  regno = REGNO (entry_parm) + words - 1;
2815 	}
2816       else
2817 	{
2818 	  regno = GP_ARG_LAST + 1;
2819 	  break;
2820 	}
2821 
2822       targetm.calls.function_arg_advance (args_so_far, passed_mode,
2823 					  passed_type, true);
2824 
2825       next_arg = TREE_CHAIN (cur_arg);
2826       if (next_arg == 0)
2827 	{
2828 	  if (DECL_NAME (cur_arg))
2829 	    arg_name = IDENTIFIER_POINTER (DECL_NAME (cur_arg));
2830 
2831 	  break;
2832 	}
2833     }
2834 
2835   /* Split parallel insn into a sequence of insns.  */
2836 
2837   next_arg_reg = targetm.calls.function_arg (args_so_far, VOIDmode,
2838 					     void_type_node, true);
2839   if (next_arg_reg != 0 && GET_CODE (next_arg_reg) == PARALLEL)
2840     {
2841       rtvec adjust = XVEC (next_arg_reg, 0);
2842       int num = GET_NUM_ELEM (adjust);
2843 
2844       for (i = 0; i < num; i++)
2845 	{
2846 	  rtx pattern = RTVEC_ELT (adjust, i);
2847 	  emit_insn (pattern);
2848 	}
2849     }
2850 
2851   fsiz = compute_frame_size (get_frame_size ());
2852 
2853   if (flag_stack_usage_info)
2854     current_function_static_stack_size = fsiz;
2855 
2856 
2857   /* If this function is a varargs function, store any registers that
2858      would normally hold arguments ($5 - $10) on the stack.  */
2859   if (((TYPE_ARG_TYPES (fntype) != 0
2860 	&& (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
2861 	    != void_type_node))
2862        || (arg_name != 0
2863 	   && ((arg_name[0] == '_'
2864 		&& strcmp (arg_name, "__builtin_va_alist") == 0)
2865 	       || (arg_name[0] == 'v'
2866 		   && strcmp (arg_name, "va_alist") == 0)))))
2867     {
2868       int offset = (regno - GP_ARG_FIRST + 1) * UNITS_PER_WORD;
2869       rtx ptr = stack_pointer_rtx;
2870 
2871       /* If we are doing svr4-abi, sp has already been decremented by fsiz. */
2872       for (; regno <= GP_ARG_LAST; regno++)
2873 	{
2874 	  if (offset != 0)
2875 	    ptr = gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (offset));
2876 	  emit_move_insn (gen_rtx_MEM (SImode, ptr),
2877 			  gen_rtx_REG (SImode, regno));
2878 
2879 	  offset += GET_MODE_SIZE (SImode);
2880 	}
2881 
2882     }
2883 
2884   if (fsiz > 0)
2885     {
2886       rtx fsiz_rtx = GEN_INT (fsiz);
2887 
2888       rtx_insn *insn = NULL;
2889       insn = emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx,
2890 				    fsiz_rtx));
2891       if (insn)
2892 	RTX_FRAME_RELATED_P (insn) = 1;
2893 
2894       /* Handle SUB_RETURN_ADDR_REGNUM specially at first.  */
2895       if (!crtl->is_leaf || interrupt_handler)
2896 	{
2897 	  mem_rtx = gen_rtx_MEM (SImode,
2898 				 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
2899 					       const0_rtx));
2900 
2901 	  if (interrupt_handler)
2902 	    /* Do not optimize in flow analysis.  */
2903 	    MEM_VOLATILE_P (mem_rtx) = 1;
2904 
2905 	  reg_rtx = gen_rtx_REG (SImode, MB_ABI_SUB_RETURN_ADDR_REGNUM);
2906 	  insn = emit_move_insn (mem_rtx, reg_rtx);
2907 	  RTX_FRAME_RELATED_P (insn) = 1;
2908 	}
2909 
2910       /* _save_ registers for prologue.  */
2911       save_restore_insns (1);
2912 
2913       if (frame_pointer_needed)
2914 	{
2915 	  rtx_insn *insn = 0;
2916 
2917 	  insn = emit_insn (gen_movsi (hard_frame_pointer_rtx,
2918 				       stack_pointer_rtx));
2919 
2920 	  if (insn)
2921 	    RTX_FRAME_RELATED_P (insn) = 1;
2922 	}
2923     }
2924 
2925   if ((flag_pic == 2 || TLS_NEEDS_GOT )
2926       && df_regs_ever_live_p (MB_ABI_PIC_ADDR_REGNUM))
2927     {
2928       SET_REGNO (pic_offset_table_rtx, MB_ABI_PIC_ADDR_REGNUM);
2929       emit_insn (gen_set_got (pic_offset_table_rtx));	/* setting GOT.  */
2930     }
2931 
2932   /* If we are profiling, make sure no instructions are scheduled before
2933      the call to mcount.  */
2934 
2935   if (profile_flag)
2936     emit_insn (gen_blockage ());
2937 }
2938 
2939 /* Do necessary cleanup after a function to restore stack, frame, and regs.  */
2940 
2941 #define RA_MASK ((long) 0x80000000)	/* 1 << 31 */
2942 #define PIC_OFFSET_TABLE_MASK (1 << (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST))
2943 
2944 static void
microblaze_function_epilogue(FILE * file ATTRIBUTE_UNUSED,HOST_WIDE_INT size ATTRIBUTE_UNUSED)2945 microblaze_function_epilogue (FILE * file ATTRIBUTE_UNUSED,
2946 			      HOST_WIDE_INT size ATTRIBUTE_UNUSED)
2947 {
2948   const char *fnname;
2949 
2950   /* Get the function name the same way that toplev.c does before calling
2951      assemble_start_function.  This is needed so that the name used here
2952      exactly matches the name used in ASM_DECLARE_FUNCTION_NAME.  */
2953   fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
2954 
2955   if (!flag_inhibit_size_directive)
2956     {
2957       fputs ("\t.end\t", file);
2958       if (interrupt_handler && !break_handler)
2959 	fputs ("_interrupt_handler", file);
2960       else if (break_handler)
2961         fputs ("_break_handler", file);
2962       else
2963 	assemble_name (file, fnname);
2964       fputs ("\n", file);
2965     }
2966 
2967   /* Reset state info for each function.  */
2968   current_frame_info = zero_frame_info;
2969 
2970   /* Restore the output file if optimizing the GP (optimizing the GP causes
2971      the text to be diverted to a tempfile, so that data decls come before
2972      references to the data).  */
2973 }
2974 
2975 /* Expand the epilogue into a bunch of separate insns.  */
2976 
2977 void
microblaze_expand_epilogue(void)2978 microblaze_expand_epilogue (void)
2979 {
2980   HOST_WIDE_INT fsiz = current_frame_info.total_size;
2981   rtx fsiz_rtx = GEN_INT (fsiz);
2982   rtx reg_rtx;
2983   rtx mem_rtx;
2984 
2985   /* In case of interrupt handlers use addki instead of addi for changing the
2986      stack pointer value.  */
2987 
2988   if (microblaze_can_use_return_insn ())
2989     {
2990       emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode,
2991 							GP_REG_FIRST +
2992 							MB_ABI_SUB_RETURN_ADDR_REGNUM)));
2993       return;
2994     }
2995 
2996   if (fsiz > 0)
2997     {
2998       /* Restore SUB_RETURN_ADDR_REGNUM at first. This is to prevent the
2999          sequence of load-followed by a use (in rtsd) in every prologue. Saves
3000          a load-use stall cycle  :)   This is also important to handle alloca.
3001          (See comments for if (frame_pointer_needed) below.  */
3002 
3003       if (!crtl->is_leaf || interrupt_handler)
3004 	{
3005 	  mem_rtx =
3006 	    gen_rtx_MEM (SImode,
3007 			 gen_rtx_PLUS (Pmode, stack_pointer_rtx, const0_rtx));
3008 	  if (interrupt_handler)
3009 	    /* Do not optimize in flow analysis.  */
3010 	    MEM_VOLATILE_P (mem_rtx) = 1;
3011 	  reg_rtx = gen_rtx_REG (SImode, MB_ABI_SUB_RETURN_ADDR_REGNUM);
3012 	  emit_move_insn (reg_rtx, mem_rtx);
3013 	}
3014 
3015       /* It is important that this is done after we restore the return address
3016          register (above).  When alloca is used, we want to restore the
3017 	 sub-routine return address only from the current stack top and not
3018 	 from the frame pointer (which we restore below). (frame_pointer + 0)
3019 	 might have been over-written since alloca allocates memory on the
3020 	 current stack.  */
3021       if (frame_pointer_needed)
3022 	emit_insn (gen_movsi (stack_pointer_rtx, hard_frame_pointer_rtx));
3023 
3024       /* _restore_ registers for epilogue.  */
3025       save_restore_insns (0);
3026       emit_insn (gen_blockage ());
3027       emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, fsiz_rtx));
3028     }
3029 
3030   emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode, GP_REG_FIRST +
3031 						    MB_ABI_SUB_RETURN_ADDR_REGNUM)));
3032 }
3033 
3034 
3035 /* Return nonzero if this function is known to have a null epilogue.
3036    This allows the optimizer to omit jumps to jumps if no stack
3037    was created.  */
3038 
3039 int
microblaze_can_use_return_insn(void)3040 microblaze_can_use_return_insn (void)
3041 {
3042   if (!reload_completed)
3043     return 0;
3044 
3045   if (df_regs_ever_live_p (MB_ABI_SUB_RETURN_ADDR_REGNUM) || profile_flag)
3046     return 0;
3047 
3048   if (current_frame_info.initialized)
3049     return current_frame_info.total_size == 0;
3050 
3051   return compute_frame_size (get_frame_size ()) == 0;
3052 }
3053 
3054 /* Implement TARGET_SECONDARY_RELOAD.  */
3055 
3056 static reg_class_t
microblaze_secondary_reload(bool in_p ATTRIBUTE_UNUSED,rtx x ATTRIBUTE_UNUSED,reg_class_t rclass,machine_mode mode ATTRIBUTE_UNUSED,secondary_reload_info * sri ATTRIBUTE_UNUSED)3057 microblaze_secondary_reload (bool in_p ATTRIBUTE_UNUSED, rtx x ATTRIBUTE_UNUSED,
3058 			     reg_class_t rclass, machine_mode mode ATTRIBUTE_UNUSED,
3059 			     secondary_reload_info *sri ATTRIBUTE_UNUSED)
3060 {
3061   if (rclass == ST_REGS)
3062     return GR_REGS;
3063 
3064   return NO_REGS;
3065 }
3066 
3067 static void
microblaze_globalize_label(FILE * stream,const char * name)3068 microblaze_globalize_label (FILE * stream, const char *name)
3069 {
3070   fputs ("\t.globl\t", stream);
3071   if (microblaze_is_interrupt_variant ())
3072     {
3073       if (interrupt_handler && strcmp (name, INTERRUPT_HANDLER_NAME))
3074         fputs (INTERRUPT_HANDLER_NAME, stream);
3075       else if (break_handler && strcmp (name, BREAK_HANDLER_NAME))
3076         fputs (BREAK_HANDLER_NAME, stream);
3077       else if (fast_interrupt && strcmp (name, FAST_INTERRUPT_NAME))
3078         fputs (FAST_INTERRUPT_NAME, stream);
3079       fputs ("\n\t.globl\t", stream);
3080     }
3081   assemble_name (stream, name);
3082   fputs ("\n", stream);
3083 }
3084 
3085 /* Returns true if decl should be placed into a "small data" section.  */
3086 static bool
microblaze_elf_in_small_data_p(const_tree decl)3087 microblaze_elf_in_small_data_p (const_tree decl)
3088 {
3089   HOST_WIDE_INT size;
3090 
3091   if (!TARGET_XLGPOPT)
3092     return false;
3093 
3094   /* We want to merge strings, so we never consider them small data.  */
3095   if (TREE_CODE (decl) == STRING_CST)
3096     return false;
3097 
3098   /* Functions are never in the small data area.  */
3099   if (TREE_CODE (decl) == FUNCTION_DECL)
3100     return false;
3101 
3102   if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl))
3103     {
3104       const char *section = DECL_SECTION_NAME (decl);
3105       if (strcmp (section, ".sdata") == 0
3106 	  || strcmp (section, ".sdata2") == 0
3107 	  || strcmp (section, ".sbss") == 0
3108 	  || strcmp (section, ".sbss2") == 0)
3109 	return true;
3110     }
3111 
3112   size = int_size_in_bytes (TREE_TYPE (decl));
3113 
3114   return (size > 0 && size <= microblaze_section_threshold);
3115 }
3116 
3117 
3118 static section *
microblaze_select_section(tree decl,int reloc,unsigned HOST_WIDE_INT align)3119 microblaze_select_section (tree decl, int reloc, unsigned HOST_WIDE_INT align)
3120 {
3121   switch (categorize_decl_for_section (decl, reloc))
3122     {
3123     case SECCAT_RODATA_MERGE_STR:
3124     case SECCAT_RODATA_MERGE_STR_INIT:
3125       /* MB binutils have various issues with mergeable string sections and
3126          relaxation/relocation. Currently, turning mergeable sections
3127          into regular readonly sections.  */
3128 
3129       return readonly_data_section;
3130     default:
3131       return default_elf_select_section (decl, reloc, align);
3132     }
3133 }
3134 
3135 /*
3136   Encode info about sections into the RTL based on a symbol's declaration.
3137   The default definition of this hook, default_encode_section_info in
3138   `varasm.c', sets a number of commonly-useful bits in SYMBOL_REF_FLAGS. */
3139 
3140 static void
microblaze_encode_section_info(tree decl,rtx rtl,int first)3141 microblaze_encode_section_info (tree decl, rtx rtl, int first)
3142 {
3143   default_encode_section_info (decl, rtl, first);
3144 }
3145 
3146 static rtx
expand_pic_symbol_ref(machine_mode mode ATTRIBUTE_UNUSED,rtx op)3147 expand_pic_symbol_ref (machine_mode mode ATTRIBUTE_UNUSED, rtx op)
3148 {
3149   rtx result;
3150   result = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op), UNSPEC_GOTOFF);
3151   result = gen_rtx_CONST (Pmode, result);
3152   result = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, result);
3153   result = gen_const_mem (Pmode, result);
3154   return result;
3155 }
3156 
3157 static void
microblaze_asm_output_mi_thunk(FILE * file,tree thunk_fndecl ATTRIBUTE_UNUSED,HOST_WIDE_INT delta,HOST_WIDE_INT vcall_offset,tree function)3158 microblaze_asm_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
3159         HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
3160         tree function)
3161 {
3162   rtx this_rtx, funexp;
3163   rtx_insn *insn;
3164 
3165   reload_completed = 1;
3166   epilogue_completed = 1;
3167 
3168   /* Mark the end of the (empty) prologue.  */
3169   emit_note (NOTE_INSN_PROLOGUE_END);
3170 
3171   /* Find the "this" pointer.  If the function returns a structure,
3172      the structure return pointer is in MB_ABI_FIRST_ARG_REGNUM.  */
3173   if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
3174     this_rtx = gen_rtx_REG (Pmode, (MB_ABI_FIRST_ARG_REGNUM + 1));
3175   else
3176     this_rtx = gen_rtx_REG (Pmode, MB_ABI_FIRST_ARG_REGNUM);
3177 
3178   /* Apply the constant offset, if required.  */
3179   if (delta)
3180     emit_insn (gen_addsi3 (this_rtx, this_rtx, GEN_INT (delta)));
3181 
3182   /* Apply the offset from the vtable, if required.  */
3183   if (vcall_offset)
3184   {
3185     rtx vcall_offset_rtx = GEN_INT (vcall_offset);
3186     rtx temp1 = gen_rtx_REG (Pmode, MB_ABI_TEMP1_REGNUM);
3187 
3188     emit_move_insn (temp1, gen_rtx_MEM (Pmode, this_rtx));
3189 
3190     rtx loc = gen_rtx_PLUS (Pmode, temp1, vcall_offset_rtx);
3191     emit_move_insn (temp1, gen_rtx_MEM (Pmode, loc));
3192 
3193     emit_insn (gen_addsi3 (this_rtx, this_rtx, temp1));
3194   }
3195 
3196   /* Generate a tail call to the target function.  */
3197   if (!TREE_USED (function))
3198   {
3199     assemble_external (function);
3200     TREE_USED (function) = 1;
3201   }
3202 
3203   funexp = XEXP (DECL_RTL (function), 0);
3204   rtx temp2 = gen_rtx_REG (Pmode, MB_ABI_TEMP2_REGNUM);
3205 
3206   if (flag_pic)
3207     emit_move_insn (temp2, expand_pic_symbol_ref (Pmode, funexp));
3208   else
3209     emit_move_insn (temp2, funexp);
3210 
3211   emit_insn (gen_indirect_jump (temp2));
3212 
3213   /* Run just enough of rest_of_compilation.  This sequence was
3214      "borrowed" from rs6000.c.  */
3215   insn = get_insns ();
3216   shorten_branches (insn);
3217   final_start_function (insn, file, 1);
3218   final (insn, file, 1);
3219   final_end_function ();
3220 
3221   reload_completed = 0;
3222   epilogue_completed = 0;
3223 }
3224 
3225 bool
microblaze_expand_move(machine_mode mode,rtx operands[])3226 microblaze_expand_move (machine_mode mode, rtx operands[])
3227 {
3228   rtx op0, op1;
3229 
3230   op0 = operands[0];
3231   op1 = operands[1];
3232 
3233   if (!register_operand (op0, SImode)
3234       && !register_operand (op1, SImode)
3235       && (GET_CODE (op1) != CONST_INT || INTVAL (op1) != 0))
3236     {
3237       rtx temp = force_reg (SImode, op1);
3238       emit_move_insn (op0, temp);
3239       return true;
3240     }
3241   /* If operands[1] is a constant address invalid for pic, then we need to
3242      handle it just like LEGITIMIZE_ADDRESS does.  */
3243   if (GET_CODE (op1) == SYMBOL_REF || GET_CODE (op1) == LABEL_REF)
3244     {
3245       rtx result;
3246       if (microblaze_tls_symbol_p(op1))
3247 	{
3248 	  result = microblaze_legitimize_tls_address (op1, NULL_RTX);
3249 	  emit_move_insn (op0, result);
3250 	  return true;
3251 	}
3252       else if (flag_pic)
3253 	{
3254 	  if (reload_in_progress)
3255 	    df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
3256 	  result = expand_pic_symbol_ref (mode, op1);
3257 	  emit_move_insn (op0, result);
3258 	  return true;
3259 	}
3260     }
3261   /* Handle Case of (const (plus symbol const_int)).  */
3262   if (GET_CODE (op1) == CONST && GET_CODE (XEXP (op1,0)) == PLUS)
3263     {
3264       rtx p0, p1;
3265 
3266       p0 = XEXP (XEXP (op1, 0), 0);
3267       p1 = XEXP (XEXP (op1, 0), 1);
3268 
3269       if ((GET_CODE (p1) == CONST_INT)
3270 	  && ((GET_CODE (p0) == UNSPEC)
3271 	      || ((GET_CODE (p0) == SYMBOL_REF || GET_CODE (p0) == LABEL_REF)
3272 	          && (flag_pic == 2 || microblaze_tls_symbol_p (p0)
3273 		      || !SMALL_INT (p1)))))
3274 	{
3275 	  rtx temp = force_reg (SImode, p0);
3276 	  rtx temp2 = p1;
3277 
3278 	  if (flag_pic && reload_in_progress)
3279 	    df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
3280 	  emit_move_insn (op0, gen_rtx_PLUS (SImode, temp, temp2));
3281 	  return true;
3282 	}
3283     }
3284   return false;
3285 }
3286 
3287 /* Expand shift operations.  */
3288 int
microblaze_expand_shift(rtx operands[])3289 microblaze_expand_shift (rtx operands[])
3290 {
3291   gcc_assert ((GET_CODE (operands[2]) == CONST_INT)
3292 	      || (GET_CODE (operands[2]) == REG)
3293 	      || (GET_CODE (operands[2]) == SUBREG));
3294 
3295   /* Shift by one -- generate pattern.  */
3296   if ((GET_CODE (operands[2]) == CONST_INT) && (INTVAL (operands[2]) == 1))
3297     return 0;
3298 
3299   /* Have barrel shifter and shift > 1: use it.  */
3300   if (TARGET_BARREL_SHIFT)
3301     return 0;
3302 
3303   gcc_assert ((GET_CODE (operands[0]) == REG)
3304 	      || (GET_CODE (operands[0]) == SUBREG)
3305 	      || (GET_CODE (operands[1]) == REG)
3306 	      || (GET_CODE (operands[1]) == SUBREG));
3307 
3308   /* Shift by zero -- copy regs if necessary.  */
3309   if ((GET_CODE (operands[2]) == CONST_INT) && (INTVAL (operands[2]) == 0))
3310     {
3311       if (REGNO (operands[0]) != REGNO (operands[1]))
3312 	emit_insn (gen_movsi (operands[0], operands[1]));
3313       return 1;
3314     }
3315 
3316   return 0;
3317 }
3318 
3319 /* Return an RTX indicating where the return address to the
3320    calling function can be found.  */
3321 rtx
microblaze_return_addr(int count,rtx frame ATTRIBUTE_UNUSED)3322 microblaze_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
3323 {
3324   if (count != 0)
3325     return NULL_RTX;
3326 
3327   return gen_rtx_PLUS (Pmode,
3328 		       get_hard_reg_initial_val (Pmode,
3329 						 MB_ABI_SUB_RETURN_ADDR_REGNUM),
3330 		       GEN_INT (8));
3331 }
3332 
3333 /* Queue an .ident string in the queue of top-level asm statements.
3334    If the string size is below the threshold, put it into .sdata2.
3335    If the front-end is done, we must be being called from toplev.c.
3336    In that case, do nothing.  */
3337 void
microblaze_asm_output_ident(const char * string)3338 microblaze_asm_output_ident (const char *string)
3339 {
3340   const char *section_asm_op;
3341   int size;
3342   char *buf;
3343 
3344   if (symtab->state != PARSING)
3345     return;
3346 
3347   size = strlen (string) + 1;
3348   if (size <= microblaze_section_threshold)
3349     section_asm_op = SDATA2_SECTION_ASM_OP;
3350   else
3351     section_asm_op = READONLY_DATA_SECTION_ASM_OP;
3352 
3353   buf = ACONCAT ((section_asm_op, "\n\t.ascii \"", string, "\\0\"\n", NULL));
3354   symtab->finalize_toplevel_asm (build_string (strlen (buf), buf));
3355 }
3356 
3357 static void
microblaze_elf_asm_init_sections(void)3358 microblaze_elf_asm_init_sections (void)
3359 {
3360   sdata2_section
3361     = get_unnamed_section (SECTION_WRITE, output_section_asm_op,
3362 			   SDATA2_SECTION_ASM_OP);
3363 }
3364 
3365 /*  Generate assembler code for constant parts of a trampoline.  */
3366 
3367 static void
microblaze_asm_trampoline_template(FILE * f)3368 microblaze_asm_trampoline_template (FILE *f)
3369 {
3370   fprintf (f, "\tmfs r18, rpc\n");
3371   fprintf (f, "\tlwi r3, r18, 16\n");
3372   fprintf (f, "\tlwi r18, r18, 20\n");
3373   fprintf (f, "\tbra r18\n");
3374   /* fprintf (f, "\t.word\t0x00000000\t\t# <function address>\n");  */
3375   /* fprintf (f, "\t.word\t0x00000000\t\t# <static chain value>\n");  */
3376 }
3377 
3378 /* Implement TARGET_TRAMPOLINE_INIT.  */
3379 
3380 static void
microblaze_trampoline_init(rtx m_tramp,tree fndecl,rtx chain_value)3381 microblaze_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
3382 {
3383   rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
3384   rtx mem;
3385 
3386   emit_block_move (m_tramp, assemble_trampoline_template (),
3387 		   GEN_INT (6*UNITS_PER_WORD), BLOCK_OP_NORMAL);
3388 
3389   mem = adjust_address (m_tramp, SImode, 16);
3390   emit_move_insn (mem, chain_value);
3391   mem = adjust_address (m_tramp, SImode, 20);
3392   emit_move_insn (mem, fnaddr);
3393 }
3394 
3395 /* Generate conditional branch -- first, generate test condition,
3396    second, generate correct branch instruction.  */
3397 
3398 void
microblaze_expand_conditional_branch(machine_mode mode,rtx operands[])3399 microblaze_expand_conditional_branch (machine_mode mode, rtx operands[])
3400 {
3401   enum rtx_code code = GET_CODE (operands[0]);
3402   rtx cmp_op0 = operands[1];
3403   rtx cmp_op1 = operands[2];
3404   rtx label1 = operands[3];
3405   rtx comp_reg = gen_reg_rtx (SImode);
3406   rtx condition;
3407 
3408   gcc_assert ((GET_CODE (cmp_op0) == REG) || (GET_CODE (cmp_op0) == SUBREG));
3409 
3410   /* If comparing against zero, just test source reg.  */
3411   if (cmp_op1 == const0_rtx)
3412     {
3413       comp_reg = cmp_op0;
3414       condition = gen_rtx_fmt_ee (signed_condition (code), SImode, comp_reg, const0_rtx);
3415       emit_jump_insn (gen_condjump (condition, label1));
3416     }
3417 
3418   else if (code == EQ || code == NE)
3419     {
3420       /* Use xor for equal/not-equal comparison.  */
3421       emit_insn (gen_xorsi3 (comp_reg, cmp_op0, cmp_op1));
3422       condition = gen_rtx_fmt_ee (signed_condition (code), SImode, comp_reg, const0_rtx);
3423       emit_jump_insn (gen_condjump (condition, label1));
3424     }
3425   else
3426     {
3427       /* Generate compare and branch in single instruction. */
3428       cmp_op1 = force_reg (mode, cmp_op1);
3429       condition = gen_rtx_fmt_ee (code, mode, cmp_op0, cmp_op1);
3430       emit_jump_insn (gen_branch_compare(condition, cmp_op0, cmp_op1, label1));
3431     }
3432 }
3433 
3434 void
microblaze_expand_conditional_branch_reg(enum machine_mode mode,rtx operands[])3435 microblaze_expand_conditional_branch_reg (enum machine_mode mode,
3436                                           rtx operands[])
3437 {
3438   enum rtx_code code = GET_CODE (operands[0]);
3439   rtx cmp_op0 = operands[1];
3440   rtx cmp_op1 = operands[2];
3441   rtx label1 = operands[3];
3442   rtx comp_reg = gen_reg_rtx (SImode);
3443   rtx condition;
3444 
3445   gcc_assert ((GET_CODE (cmp_op0) == REG)
3446                || (GET_CODE (cmp_op0) == SUBREG));
3447 
3448   /* If comparing against zero, just test source reg.  */
3449   if (cmp_op1 == const0_rtx)
3450     {
3451       comp_reg = cmp_op0;
3452       condition = gen_rtx_fmt_ee (signed_condition (code),
3453                                   SImode, comp_reg, const0_rtx);
3454       emit_jump_insn (gen_condjump (condition, label1));
3455     }
3456   else if (code == EQ)
3457     {
3458       emit_insn (gen_seq_internal_pat (comp_reg,
3459                                        cmp_op0, cmp_op1));
3460       condition = gen_rtx_EQ (SImode, comp_reg, const0_rtx);
3461       emit_jump_insn (gen_condjump (condition, label1));
3462     }
3463   else if (code == NE)
3464     {
3465       emit_insn (gen_sne_internal_pat (comp_reg, cmp_op0,
3466                                        cmp_op1));
3467       condition = gen_rtx_NE (SImode, comp_reg, const0_rtx);
3468       emit_jump_insn (gen_condjump (condition, label1));
3469     }
3470   else
3471     {
3472       /* Generate compare and branch in single instruction. */
3473       cmp_op1 = force_reg (mode, cmp_op1);
3474       condition = gen_rtx_fmt_ee (code, mode, cmp_op0, cmp_op1);
3475       emit_jump_insn (gen_branch_compare (condition, cmp_op0,
3476                                          cmp_op1, label1));
3477     }
3478 }
3479 
3480 void
microblaze_expand_conditional_branch_sf(rtx operands[])3481 microblaze_expand_conditional_branch_sf (rtx operands[])
3482 {
3483   rtx condition;
3484   rtx cmp_op0 = XEXP (operands[0], 0);
3485   rtx cmp_op1 = XEXP (operands[0], 1);
3486   rtx comp_reg = gen_reg_rtx (SImode);
3487 
3488   emit_insn (gen_cstoresf4 (comp_reg, operands[0], cmp_op0, cmp_op1));
3489   condition = gen_rtx_NE (SImode, comp_reg, const0_rtx);
3490   emit_jump_insn (gen_condjump (condition, operands[3]));
3491 }
3492 
3493 /* Implement TARGET_FRAME_POINTER_REQUIRED.  */
3494 
3495 static bool
microblaze_frame_pointer_required(void)3496 microblaze_frame_pointer_required (void)
3497 {
3498   /* If the function contains dynamic stack allocations, we need to
3499      use the frame pointer to access the static parts of the frame.  */
3500   if (cfun->calls_alloca)
3501     return true;
3502   return false;
3503 }
3504 
3505 void
microblaze_expand_divide(rtx operands[])3506 microblaze_expand_divide (rtx operands[])
3507 {
3508   /* Table lookup software divides. Works for all (nr/dr) where (0 <= nr,dr <= 15).  */
3509 
3510   rtx regt1 = gen_reg_rtx (SImode);
3511   rtx reg18 = gen_rtx_REG (SImode, R_TMP);
3512   rtx regqi = gen_reg_rtx (QImode);
3513   rtx_code_label *div_label = gen_label_rtx ();
3514   rtx_code_label *div_end_label = gen_label_rtx ();
3515   rtx div_table_rtx = gen_rtx_SYMBOL_REF (QImode,"_divsi3_table");
3516   rtx mem_rtx;
3517   rtx ret;
3518   rtx_insn *jump, *cjump, *insn;
3519 
3520   insn = emit_insn (gen_iorsi3 (regt1, operands[1], operands[2]));
3521   cjump = emit_jump_insn_after (gen_cbranchsi4 (
3522 					gen_rtx_GTU (SImode, regt1, GEN_INT (15)),
3523 					regt1, GEN_INT (15), div_label), insn);
3524   LABEL_NUSES (div_label) = 1;
3525   JUMP_LABEL (cjump) = div_label;
3526   emit_insn (gen_rtx_CLOBBER (SImode, reg18));
3527 
3528   emit_insn (gen_ashlsi3_bshift (regt1, operands[1], GEN_INT(4)));
3529   emit_insn (gen_addsi3 (regt1, regt1, operands[2]));
3530   mem_rtx = gen_rtx_MEM (QImode,
3531                             gen_rtx_PLUS (Pmode, regt1, div_table_rtx));
3532 
3533   insn = emit_insn (gen_movqi (regqi, mem_rtx));
3534   insn = emit_insn (gen_movsi (operands[0], gen_rtx_SUBREG (SImode, regqi, 0)));
3535   jump = emit_jump_insn_after (gen_jump (div_end_label), insn);
3536   JUMP_LABEL (jump) = div_end_label;
3537   LABEL_NUSES (div_end_label) = 1;
3538   emit_barrier ();
3539 
3540   emit_label (div_label);
3541   ret = emit_library_call_value (gen_rtx_SYMBOL_REF (Pmode, "__divsi3"),
3542 				       operands[0], LCT_NORMAL,
3543 				       GET_MODE (operands[0]), 2, operands[1],
3544 				       GET_MODE (operands[1]), operands[2],
3545 				       GET_MODE (operands[2]));
3546   if (ret != operands[0])
3547                 emit_move_insn (operands[0], ret);
3548 
3549   emit_label (div_end_label);
3550   emit_insn (gen_blockage ());
3551 }
3552 
3553 /* Implement TARGET_FUNCTION_VALUE.  */
3554 static rtx
microblaze_function_value(const_tree valtype,const_tree func ATTRIBUTE_UNUSED,bool outgoing ATTRIBUTE_UNUSED)3555 microblaze_function_value (const_tree valtype,
3556 			   const_tree func ATTRIBUTE_UNUSED,
3557 			   bool outgoing ATTRIBUTE_UNUSED)
3558 {
3559   return LIBCALL_VALUE (TYPE_MODE (valtype));
3560 }
3561 
3562 /* Implement TARGET_SCHED_ADJUST_COST.  */
3563 static int
microblaze_adjust_cost(rtx_insn * insn ATTRIBUTE_UNUSED,rtx link,rtx_insn * dep ATTRIBUTE_UNUSED,int cost)3564 microblaze_adjust_cost (rtx_insn *insn ATTRIBUTE_UNUSED, rtx link,
3565 			rtx_insn *dep ATTRIBUTE_UNUSED, int cost)
3566 {
3567   if (REG_NOTE_KIND (link) == REG_DEP_OUTPUT)
3568     return cost;
3569   if (REG_NOTE_KIND (link) != 0)
3570     return 0;
3571   return cost;
3572 }
3573 
3574 /* Implement TARGET_LEGITIMATE_CONSTANT_P.
3575 
3576    At present, GAS doesn't understand li.[sd], so don't allow it
3577    to be generated at present.  */
3578 static bool
microblaze_legitimate_constant_p(machine_mode mode ATTRIBUTE_UNUSED,rtx x)3579 microblaze_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED, rtx x)
3580 {
3581 
3582   if (microblaze_cannot_force_const_mem(mode, x))
3583         return false;
3584 
3585   if (GET_CODE (x) == CONST_DOUBLE)
3586     {
3587       return microblaze_const_double_ok (x, GET_MODE (x));
3588     }
3589 
3590    /* Handle Case of (const (plus unspec const_int)).  */
3591    if (GET_CODE (x) == CONST && GET_CODE (XEXP (x,0)) == PLUS)
3592      {
3593         rtx p0, p1;
3594 
3595         p0 = XEXP (XEXP (x, 0), 0);
3596         p1 = XEXP (XEXP (x, 0), 1);
3597 
3598         if (GET_CODE(p1) == CONST_INT)
3599           {
3600             /* Const offset from UNSPEC is not supported.  */
3601             if ((GET_CODE (p0) == UNSPEC))
3602               return false;
3603 
3604             if ((GET_CODE (p0) == SYMBOL_REF || GET_CODE (p0) == LABEL_REF)
3605                  && (microblaze_tls_symbol_p (p0) || !SMALL_INT (p1)))
3606               return false;
3607           }
3608       }
3609 
3610   return true;
3611 }
3612 
3613 static rtx
get_branch_target(rtx branch)3614 get_branch_target (rtx branch)
3615 {
3616   if (CALL_P (branch))
3617     {
3618       rtx call;
3619 
3620       call = XVECEXP (PATTERN (branch), 0, 0);
3621       if (GET_CODE (call) == SET)
3622         call = SET_SRC (call);
3623       if (GET_CODE (call) != CALL)
3624         abort ();
3625       return XEXP (XEXP (call, 0), 0);
3626     }
3627 }
3628 
3629 /* Heuristics to identify where to insert at the
3630    fall through path of the caller function. If there
3631    is a call after the caller branch delay slot then
3632    we dont generate the instruction prefetch instruction.
3633 
3634    Scan up to 32 instructions after the call and checks
3635    for the JUMP and call instruction . If there is a call
3636    or JUMP instruction in the range of 32 instruction "wic"
3637    instruction wont be generated. Otherwise insert the "wic"
3638    instruction in the fall through of the call instruction
3639    four instruction after the call. before_4 is used for
3640    the position to insert "wic" instructions. before_16 is
3641    used to check for call and JUMP instruction for first
3642    15 insns.  */
3643 
3644 static void
insert_wic_for_ilb_runout(rtx_insn * first)3645 insert_wic_for_ilb_runout (rtx_insn *first)
3646 {
3647   rtx_insn *insn;
3648   rtx_insn *before_4 = 0;
3649   rtx_insn *before_16 = 0;
3650   int addr_offset = 0;
3651   int length;
3652   int wic_addr0 = 128 * 4;
3653   int wic_addr1 = 128 * 4;
3654 
3655   int first_addr = INSN_ADDRESSES (INSN_UID (first));
3656 
3657   for (insn = first; insn; insn = NEXT_INSN (insn))
3658     if (INSN_P (insn))
3659       {
3660         addr_offset = INSN_ADDRESSES (INSN_UID (insn)) - first_addr;
3661         length = get_attr_length (insn);
3662         if (before_4 == 0 && addr_offset + length >= 4 * 4)
3663           before_4 = insn;
3664 
3665         if (JUMP_P(insn))
3666           return;
3667         if (before_16 == 0 && addr_offset + length >= 14 * 4)
3668           before_16 = insn;
3669         if (CALL_P (insn) || tablejump_p (insn, 0, 0))
3670           return;
3671         if (addr_offset + length >= 32 * 4)
3672           {
3673             gcc_assert (before_4 && before_16);
3674             if (wic_addr0 > 4 * 4)
3675               {
3676                 insn =
3677                   emit_insn_before (gen_iprefetch
3678                                     (gen_int_mode (addr_offset, SImode)),
3679                                     before_4);
3680                 recog_memoized (insn);
3681                 INSN_LOCATION (insn) = INSN_LOCATION (before_4);
3682                 INSN_ADDRESSES_NEW (insn, INSN_ADDRESSES (INSN_UID (before_4)));
3683                 return;
3684               }
3685            }
3686        }
3687 }
3688 
3689 /* Insert instruction prefetch instruction at the fall
3690    through path of the function call.  */
3691 
3692 static void
insert_wic(void)3693 insert_wic (void)
3694 {
3695   rtx_insn *insn;
3696   int i, j;
3697   basic_block bb, prev = 0;
3698   rtx branch_target = 0;
3699 
3700   shorten_branches (get_insns ());
3701 
3702   for (i = 0; i < n_basic_blocks_for_fn (cfun) - 1; i++)
3703      {
3704        edge e;
3705        edge_iterator ei;
3706        bool simple_loop = false;
3707 
3708        bb = BASIC_BLOCK_FOR_FN (cfun, i);
3709 
3710        if (bb == NULL)
3711          continue;
3712 
3713        if ((prev != 0) && (prev != bb))
3714          continue;
3715        else
3716          prev = 0;
3717 
3718        FOR_EACH_EDGE (e, ei, bb->preds)
3719          if (e->src == bb)
3720            {
3721              simple_loop = true;
3722              prev= e->dest;
3723              break;
3724            }
3725 
3726        for (insn = BB_END (bb); insn; insn = PREV_INSN (insn))
3727           {
3728             if (INSN_P (insn) && !simple_loop
3729                && CALL_P(insn))
3730               {
3731                 if ((branch_target = get_branch_target (insn)))
3732                   insert_wic_for_ilb_runout (
3733                     next_active_insn (next_active_insn (insn)));
3734               }
3735               if (insn == BB_HEAD (bb))
3736                 break;
3737            }
3738       }
3739 }
3740 
3741 /* The reorg function defined through the macro
3742    TARGET_MACHINE_DEPENDENT_REORG.  */
3743 
3744 static void
microblaze_machine_dependent_reorg(void)3745 microblaze_machine_dependent_reorg (void)
3746 {
3747   if (TARGET_PREFETCH)
3748     {
3749       compute_bb_for_insn ();
3750       loop_optimizer_init (AVOID_CFG_MODIFICATIONS);
3751       shorten_branches (get_insns ());
3752       insert_wic ();
3753       loop_optimizer_finalize ();
3754       free_bb_for_insn ();
3755       return;
3756     }
3757 }
3758 
3759 #undef TARGET_ENCODE_SECTION_INFO
3760 #define TARGET_ENCODE_SECTION_INFO      microblaze_encode_section_info
3761 
3762 #undef TARGET_ASM_GLOBALIZE_LABEL
3763 #define TARGET_ASM_GLOBALIZE_LABEL      microblaze_globalize_label
3764 
3765 #undef TARGET_ASM_FUNCTION_PROLOGUE
3766 #define TARGET_ASM_FUNCTION_PROLOGUE    microblaze_function_prologue
3767 
3768 #undef TARGET_ASM_FUNCTION_EPILOGUE
3769 #define TARGET_ASM_FUNCTION_EPILOGUE    microblaze_function_epilogue
3770 
3771 #undef TARGET_RTX_COSTS
3772 #define TARGET_RTX_COSTS                microblaze_rtx_costs
3773 
3774 #undef TARGET_CANNOT_FORCE_CONST_MEM
3775 #define TARGET_CANNOT_FORCE_CONST_MEM   microblaze_cannot_force_const_mem
3776 
3777 #undef TARGET_ADDRESS_COST
3778 #define TARGET_ADDRESS_COST             microblaze_address_cost
3779 
3780 #undef TARGET_ATTRIBUTE_TABLE
3781 #define TARGET_ATTRIBUTE_TABLE          microblaze_attribute_table
3782 
3783 #undef TARGET_IN_SMALL_DATA_P
3784 #define TARGET_IN_SMALL_DATA_P          microblaze_elf_in_small_data_p
3785 
3786 #undef TARGET_ASM_SELECT_SECTION
3787 #define TARGET_ASM_SELECT_SECTION       microblaze_select_section
3788 
3789 #undef TARGET_HAVE_SRODATA_SECTION
3790 #define TARGET_HAVE_SRODATA_SECTION     true
3791 
3792 #undef TARGET_ASM_FUNCTION_END_PROLOGUE
3793 #define TARGET_ASM_FUNCTION_END_PROLOGUE \
3794                                         microblaze_function_end_prologue
3795 
3796 #undef TARGET_ARG_PARTIAL_BYTES
3797 #define TARGET_ARG_PARTIAL_BYTES	function_arg_partial_bytes
3798 
3799 #undef TARGET_FUNCTION_ARG
3800 #define TARGET_FUNCTION_ARG		microblaze_function_arg
3801 
3802 #undef TARGET_FUNCTION_ARG_ADVANCE
3803 #define TARGET_FUNCTION_ARG_ADVANCE	microblaze_function_arg_advance
3804 
3805 #undef TARGET_CAN_ELIMINATE
3806 #define TARGET_CAN_ELIMINATE 		microblaze_can_eliminate
3807 
3808 #undef TARGET_LEGITIMIZE_ADDRESS
3809 #define TARGET_LEGITIMIZE_ADDRESS 	microblaze_legitimize_address
3810 
3811 #undef TARGET_LEGITIMATE_ADDRESS_P
3812 #define TARGET_LEGITIMATE_ADDRESS_P 	microblaze_legitimate_address_p
3813 
3814 #undef TARGET_FRAME_POINTER_REQUIRED
3815 #define TARGET_FRAME_POINTER_REQUIRED	microblaze_frame_pointer_required
3816 
3817 #undef  TARGET_ASM_TRAMPOLINE_TEMPLATE
3818 #define TARGET_ASM_TRAMPOLINE_TEMPLATE	microblaze_asm_trampoline_template
3819 
3820 #undef  TARGET_TRAMPOLINE_INIT
3821 #define TARGET_TRAMPOLINE_INIT		microblaze_trampoline_init
3822 
3823 #undef  TARGET_PROMOTE_FUNCTION_MODE
3824 #define TARGET_PROMOTE_FUNCTION_MODE 	default_promote_function_mode_always_promote
3825 
3826 #undef TARGET_FUNCTION_VALUE
3827 #define TARGET_FUNCTION_VALUE		microblaze_function_value
3828 
3829 #undef TARGET_SECONDARY_RELOAD
3830 #define TARGET_SECONDARY_RELOAD		microblaze_secondary_reload
3831 
3832 #undef  TARGET_ASM_OUTPUT_MI_THUNK
3833 #define TARGET_ASM_OUTPUT_MI_THUNK      microblaze_asm_output_mi_thunk
3834 
3835 #undef  TARGET_ASM_CAN_OUTPUT_MI_THUNK
3836 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK  hook_bool_const_tree_hwi_hwi_const_tree_true
3837 
3838 #undef TARGET_SCHED_ADJUST_COST
3839 #define TARGET_SCHED_ADJUST_COST	microblaze_adjust_cost
3840 
3841 #undef TARGET_ASM_INIT_SECTIONS
3842 #define TARGET_ASM_INIT_SECTIONS	microblaze_elf_asm_init_sections
3843 
3844 #undef  TARGET_OPTION_OVERRIDE
3845 #define TARGET_OPTION_OVERRIDE		microblaze_option_override
3846 
3847 #undef TARGET_LEGITIMATE_CONSTANT_P
3848 #define TARGET_LEGITIMATE_CONSTANT_P microblaze_legitimate_constant_p
3849 
3850 #undef TARGET_MACHINE_DEPENDENT_REORG
3851 #define TARGET_MACHINE_DEPENDENT_REORG microblaze_machine_dependent_reorg
3852 
3853 struct gcc_target targetm = TARGET_INITIALIZER;
3854 
3855 #include "gt-microblaze.h"
3856