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