gcc/
[official-gcc.git] / gcc / config / microblaze / microblaze.c
blob55be2d11674986a28f875b757d9058fdb214ee33
1 /* Subroutines used for code generation on Xilinx MicroBlaze.
2 Copyright (C) 2009-2015 Free Software Foundation, Inc.
4 Contributed by Michael Eager <eager@eagercon.com>.
6 This file is part of GCC.
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.
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.
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/>. */
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 "hash-set.h"
36 #include "machmode.h"
37 #include "vec.h"
38 #include "double-int.h"
39 #include "input.h"
40 #include "alias.h"
41 #include "symtab.h"
42 #include "wide-int.h"
43 #include "inchash.h"
44 #include "tree.h"
45 #include "varasm.h"
46 #include "stor-layout.h"
47 #include "calls.h"
48 #include "function.h"
49 #include "hashtab.h"
50 #include "flags.h"
51 #include "statistics.h"
52 #include "fixed-value.h"
53 #include "expmed.h"
54 #include "dojump.h"
55 #include "explow.h"
56 #include "emit-rtl.h"
57 #include "stmt.h"
58 #include "expr.h"
59 #include "reload.h"
60 #include "output.h"
61 #include "ggc.h"
62 #include "target.h"
63 #include "target-def.h"
64 #include "tm_p.h"
65 #include "gstab.h"
66 #include "dominance.h"
67 #include "cfg.h"
68 #include "cfgrtl.h"
69 #include "cfganal.h"
70 #include "lcm.h"
71 #include "cfgbuild.h"
72 #include "cfgcleanup.h"
73 #include "predict.h"
74 #include "basic-block.h"
75 #include "df.h"
76 #include "insn-codes.h"
77 #include "optabs.h"
78 #include "diagnostic-core.h"
79 #include "hash-map.h"
80 #include "is-a.h"
81 #include "plugin-api.h"
82 #include "ipa-ref.h"
83 #include "cgraph.h"
84 #include "builtins.h"
85 #include "rtl-iter.h"
87 #define MICROBLAZE_VERSION_COMPARE(VA,VB) strcasecmp (VA, VB)
89 /* Classifies an address.
91 ADDRESS_INVALID
92 An invalid address.
94 ADDRESS_REG
96 A natural register or a register + const_int offset address.
97 The register satisfies microblaze_valid_base_register_p and the
98 offset is a const_arith_operand.
100 ADDRESS_REG_INDEX
102 A natural register offset by the index contained in an index register. The base
103 register satisfies microblaze_valid_base_register_p and the index register
104 satisfies microblaze_valid_index_register_p
106 ADDRESS_CONST_INT
108 A signed 16/32-bit constant address.
110 ADDRESS_SYMBOLIC:
112 A constant symbolic address or a (register + symbol). */
114 enum microblaze_address_type
116 ADDRESS_INVALID,
117 ADDRESS_REG,
118 ADDRESS_REG_INDEX,
119 ADDRESS_CONST_INT,
120 ADDRESS_SYMBOLIC,
121 ADDRESS_GOTOFF,
122 ADDRESS_PLT,
123 ADDRESS_TLS
126 /* Classifies symbols
128 SYMBOL_TYPE_GENERAL
130 A general symbol. */
131 enum microblaze_symbol_type
133 SYMBOL_TYPE_INVALID,
134 SYMBOL_TYPE_GENERAL
137 /* TLS Address Type. */
138 enum tls_reloc {
139 TLS_GD,
140 TLS_LDM,
141 TLS_DTPREL,
142 TLS_IE,
143 TLS_LE
146 /* Classification of a MicroBlaze address. */
147 struct microblaze_address_info
149 enum microblaze_address_type type;
150 rtx regA; /* Contains valid values on ADDRESS_REG, ADDRESS_REG_INDEX,
151 ADDRESS_SYMBOLIC. */
152 rtx regB; /* Contains valid values on ADDRESS_REG_INDEX. */
153 rtx offset; /* Contains valid values on ADDRESS_CONST_INT and ADDRESS_REG. */
154 rtx symbol; /* Contains valid values on ADDRESS_SYMBOLIC. */
155 enum microblaze_symbol_type symbol_type;
156 enum tls_reloc tls_type;
159 /* Structure to be filled in by compute_frame_size with register
160 save masks, and offsets for the current function. */
162 struct GTY(()) microblaze_frame_info {
163 long total_size; /* # bytes that the entire frame takes up. */
164 long var_size; /* # bytes that variables take up. */
165 long args_size; /* # bytes that outgoing arguments take up. */
166 int link_debug_size; /* # bytes for the link reg and back pointer. */
167 int gp_reg_size; /* # bytes needed to store gp regs. */
168 long gp_offset; /* offset from new sp to store gp registers. */
169 long mask; /* mask of saved gp registers. */
170 int initialized; /* != 0 if frame size already calculated. */
171 int num_gp; /* number of gp registers saved. */
172 long insns_len; /* length of insns. */
173 int alloc_stack; /* Flag to indicate if the current function
174 must not create stack space. (As an optimization). */
177 /* Global variables for machine-dependent things. */
179 /* Toggle which pipleline interface to use. */
180 static GTY(()) int microblaze_sched_use_dfa = 0;
182 /* Threshold for data being put into the small data/bss area, instead
183 of the normal data area (references to the small data/bss area take
184 1 instruction, and use the global pointer, references to the normal
185 data area takes 2 instructions). */
186 int microblaze_section_threshold = -1;
188 /* Prevent scheduling potentially exception causing instructions in
189 delay slots. -mcpu=v3.00.a or v4.00.a turns this on. */
190 int microblaze_no_unsafe_delay;
192 /* Set to one if the targeted core has the CLZ insn. */
193 int microblaze_has_clz = 0;
195 /* Which CPU pipeline do we use. We haven't really standardized on a CPU
196 version having only a particular type of pipeline. There can still be
197 options on the CPU to scale pipeline features up or down. :(
198 Bad Presentation (??), so we let the MD file rely on the value of
199 this variable instead Making PIPE_5 the default. It should be backward
200 optimal with PIPE_3 MicroBlazes. */
201 enum pipeline_type microblaze_pipe = MICROBLAZE_PIPE_5;
203 /* High and low marks for floating point values which we will accept
204 as legitimate constants for TARGET_LEGITIMATE_CONSTANT_P. These are
205 initialized in override_options. */
206 REAL_VALUE_TYPE dfhigh, dflow, sfhigh, sflow;
208 /* Array giving truth value on whether or not a given hard register
209 can support a given mode. */
210 char microblaze_hard_regno_mode_ok[(int)MAX_MACHINE_MODE]
211 [FIRST_PSEUDO_REGISTER];
213 /* Current frame information calculated by compute_frame_size. */
214 struct microblaze_frame_info current_frame_info;
216 /* Zero structure to initialize current_frame_info. */
217 struct microblaze_frame_info zero_frame_info;
219 /* List of all MICROBLAZE punctuation characters used by print_operand. */
220 char microblaze_print_operand_punct[256];
222 /* Map GCC register number to debugger register number. */
223 int microblaze_dbx_regno[FIRST_PSEUDO_REGISTER];
225 /* Map hard register number to register class. */
226 enum reg_class microblaze_regno_to_class[] =
228 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
229 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
230 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
231 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
232 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
233 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
234 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
235 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
236 ST_REGS, GR_REGS, GR_REGS, GR_REGS
239 /* MicroBlaze specific machine attributes.
240 interrupt_handler - Interrupt handler attribute to add interrupt prologue
241 and epilogue and use appropriate interrupt return.
242 save_volatiles - Similar to interrupt handler, but use normal return. */
243 int interrupt_handler;
244 int break_handler;
245 int fast_interrupt;
246 int save_volatiles;
248 const struct attribute_spec microblaze_attribute_table[] = {
249 /* name min_len, max_len, decl_req, type_req, fn_type, req_handler,
250 affects_type_identity */
251 {"interrupt_handler", 0, 0, true, false, false, NULL,
252 false },
253 {"break_handler", 0, 0, true, false, false, NULL,
254 false },
255 {"fast_interrupt", 0, 0, true, false, false, NULL,
256 false },
257 {"save_volatiles" , 0, 0, true, false, false, NULL,
258 false },
259 { NULL, 0, 0, false, false, false, NULL,
260 false }
263 static int microblaze_interrupt_function_p (tree);
265 static void microblaze_elf_asm_constructor (rtx, int) ATTRIBUTE_UNUSED;
266 static void microblaze_elf_asm_destructor (rtx, int) ATTRIBUTE_UNUSED;
268 section *sdata2_section;
270 #ifdef HAVE_AS_TLS
271 #undef TARGET_HAVE_TLS
272 #define TARGET_HAVE_TLS true
273 #endif
275 /* Return truth value if a CONST_DOUBLE is ok to be a legitimate constant. */
276 static bool
277 microblaze_const_double_ok (rtx op, machine_mode mode)
279 REAL_VALUE_TYPE d;
281 if (GET_CODE (op) != CONST_DOUBLE)
282 return 0;
284 if (GET_MODE (op) == VOIDmode)
285 return 1;
287 if (mode != SFmode && mode != DFmode)
288 return 0;
290 if (op == CONST0_RTX (mode))
291 return 1;
293 REAL_VALUE_FROM_CONST_DOUBLE (d, op);
295 if (REAL_VALUE_ISNAN (d))
296 return FALSE;
298 if (REAL_VALUE_NEGATIVE (d))
299 d = real_value_negate (&d);
301 if (mode == DFmode)
303 if (REAL_VALUES_LESS (d, dfhigh) && REAL_VALUES_LESS (dflow, d))
304 return 1;
306 else
308 if (REAL_VALUES_LESS (d, sfhigh) && REAL_VALUES_LESS (sflow, d))
309 return 1;
312 return 0;
315 /* Return truth value if a memory operand fits in a single instruction
316 (ie, register + small offset) or (register + register). */
319 simple_memory_operand (rtx op, machine_mode mode ATTRIBUTE_UNUSED)
321 rtx addr, plus0, plus1;
323 /* Eliminate non-memory operations. */
324 if (GET_CODE (op) != MEM)
325 return 0;
327 /* dword operations really put out 2 instructions, so eliminate them. */
328 /* ??? This isn't strictly correct. It is OK to accept multiword modes
329 here, since the length attributes are being set correctly, but only
330 if the address is offsettable. */
331 if (GET_MODE_SIZE (GET_MODE (op)) > UNITS_PER_WORD)
332 return 0;
335 /* Decode the address now. */
336 addr = XEXP (op, 0);
337 switch (GET_CODE (addr))
340 case REG:
341 return 1;
343 case PLUS:
344 plus0 = XEXP (addr, 0);
345 plus1 = XEXP (addr, 1);
347 if (GET_CODE (plus0) != REG)
348 return 0;
350 if (GET_CODE (plus0) == REG && GET_CODE (plus1) == CONST_INT
351 && SMALL_INT (plus1))
353 return 1;
355 else if (GET_CODE (plus1) == REG && GET_CODE (plus0) == CONST_INT)
357 return 1;
359 else if (GET_CODE (plus0) == REG && GET_CODE (plus1) == REG)
361 return 1;
363 else
364 return 0;
366 case SYMBOL_REF:
367 return 0;
369 default:
370 break;
373 return 0;
376 /* Return nonzero for a memory address that can be used to load or store
377 a doubleword. */
380 double_memory_operand (rtx op, machine_mode mode)
382 rtx addr;
384 if (GET_CODE (op) != MEM || !memory_operand (op, mode))
386 /* During reload, we accept a pseudo register if it has an
387 appropriate memory address. If we don't do this, we will
388 wind up reloading into a register, and then reloading that
389 register from memory, when we could just reload directly from
390 memory. */
391 if (reload_in_progress
392 && GET_CODE (op) == REG
393 && REGNO (op) >= FIRST_PSEUDO_REGISTER
394 && reg_renumber[REGNO (op)] < 0
395 && reg_equiv_mem (REGNO (op)) != 0
396 && double_memory_operand (reg_equiv_mem (REGNO (op)), mode))
397 return 1;
398 return 0;
401 /* Make sure that 4 added to the address is a valid memory address.
402 This essentially just checks for overflow in an added constant. */
404 addr = XEXP (op, 0);
406 if (CONSTANT_ADDRESS_P (addr))
407 return 1;
409 return memory_address_p ((GET_MODE_CLASS (mode) == MODE_INT
410 ? SImode : SFmode),
411 plus_constant (Pmode, addr, 4));
414 /* Implement REG_OK_FOR_BASE_P -and- REG_OK_FOR_INDEX_P. */
416 microblaze_regno_ok_for_base_p (int regno, int strict)
418 if (regno >= FIRST_PSEUDO_REGISTER)
420 if (!strict)
421 return true;
422 regno = reg_renumber[regno];
425 /* These fake registers will be eliminated to either the stack or
426 hard frame pointer, both of which are usually valid base registers.
427 Reload deals with the cases where the eliminated form isn't valid. */
428 if (regno == ARG_POINTER_REGNUM || regno == FRAME_POINTER_REGNUM)
429 return true;
431 return GP_REG_P (regno);
434 /* Return true if X is a valid base register for the given mode.
435 Allow only hard registers if STRICT. */
437 static bool
438 microblaze_valid_base_register_p (rtx x,
439 machine_mode mode ATTRIBUTE_UNUSED,
440 int strict)
442 if (!strict && GET_CODE (x) == SUBREG)
443 x = SUBREG_REG (x);
445 return (GET_CODE (x) == REG
446 && microblaze_regno_ok_for_base_p (REGNO (x), strict));
449 /* Build the SYMBOL_REF for __tls_get_addr. */
451 static GTY(()) rtx tls_get_addr_libfunc;
453 static rtx
454 get_tls_get_addr (void)
456 if (!tls_get_addr_libfunc)
457 tls_get_addr_libfunc = init_one_libfunc ("__tls_get_addr");
458 return tls_get_addr_libfunc;
461 /* Return TRUE if X is a thread-local symbol. */
462 bool
463 microblaze_tls_symbol_p (rtx x)
465 if (!TARGET_HAVE_TLS)
466 return false;
468 if (GET_CODE (x) != SYMBOL_REF)
469 return false;
471 return SYMBOL_REF_TLS_MODEL (x) != 0;
474 /* Return TRUE if X contains any TLS symbol references. */
476 bool
477 microblaze_tls_referenced_p (rtx x)
479 if (!TARGET_HAVE_TLS)
480 return false;
481 subrtx_iterator::array_type array;
482 FOR_EACH_SUBRTX (iter, array, x, ALL)
484 const_rtx x = *iter;
485 if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (x) != 0)
486 return true;
487 /* Don't recurse into UNSPEC_TLS looking for TLS symbols; these are
488 TLS offsets, not real symbol references. */
489 if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLS)
490 iter.skip_subrtxes ();
492 return false;
495 bool
496 microblaze_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED, rtx x)
498 return microblaze_tls_referenced_p(x);
501 /* Return TRUE if X references a SYMBOL_REF. */
503 symbol_mentioned_p (rtx x)
505 const char * fmt;
506 int i;
508 if (GET_CODE (x) == SYMBOL_REF)
509 return 1;
511 /* UNSPEC entries for a symbol include the SYMBOL_REF, but they
512 are constant offsets, not symbols. */
513 if (GET_CODE (x) == UNSPEC)
514 return 0;
516 fmt = GET_RTX_FORMAT (GET_CODE (x));
518 for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
520 if (fmt[i] == 'E')
522 int j;
524 for (j = XVECLEN (x, i) - 1; j >= 0; j--)
525 if (symbol_mentioned_p (XVECEXP (x, i, j)))
526 return 1;
528 else if (fmt[i] == 'e' && symbol_mentioned_p (XEXP (x, i)))
529 return 1;
532 return 0;
535 /* Return TRUE if X references a LABEL_REF. */
537 label_mentioned_p (rtx x)
539 const char * fmt;
540 int i;
542 if (GET_CODE (x) == LABEL_REF)
543 return 1;
545 /* UNSPEC entries for a symbol include a LABEL_REF for the referencing
546 instruction, but they are constant offsets, not symbols. */
547 if (GET_CODE (x) == UNSPEC)
548 return 0;
550 fmt = GET_RTX_FORMAT (GET_CODE (x));
551 for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
553 if (fmt[i] == 'E')
555 int j;
557 for (j = XVECLEN (x, i) - 1; j >= 0; j--)
558 if (label_mentioned_p (XVECEXP (x, i, j)))
559 return 1;
561 else if (fmt[i] == 'e' && label_mentioned_p (XEXP (x, i)))
562 return 1;
565 return 0;
569 tls_mentioned_p (rtx x)
571 switch (GET_CODE (x))
573 case CONST:
574 return tls_mentioned_p (XEXP (x, 0));
576 case UNSPEC:
577 if (XINT (x, 1) == UNSPEC_TLS)
578 return 1;
580 default:
581 return 0;
585 static rtx
586 load_tls_operand (rtx x, rtx reg)
588 rtx tmp;
590 if (reg == NULL_RTX)
591 reg = gen_reg_rtx (Pmode);
593 tmp = gen_rtx_CONST (Pmode, x);
595 emit_insn (gen_rtx_SET (reg,
596 gen_rtx_PLUS (Pmode, pic_offset_table_rtx, tmp)));
598 return reg;
601 static rtx_insn *
602 microblaze_call_tls_get_addr (rtx x, rtx reg, rtx *valuep, int reloc)
604 rtx_insn *insns;
605 rtx tls_entry;
607 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
609 start_sequence ();
611 tls_entry = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, x, GEN_INT (reloc)),
612 UNSPEC_TLS);
614 reg = load_tls_operand (tls_entry, reg);
616 *valuep = emit_library_call_value (get_tls_get_addr (), NULL_RTX,
617 LCT_PURE, /* LCT_CONST? */
618 Pmode, 1, reg, Pmode);
620 insns = get_insns ();
621 end_sequence ();
623 return insns;
627 microblaze_legitimize_tls_address(rtx x, rtx reg)
629 rtx dest, ret, eqv, addend;
630 rtx_insn *insns;
631 enum tls_model model;
632 model = SYMBOL_REF_TLS_MODEL (x);
634 switch (model)
636 case TLS_MODEL_LOCAL_DYNAMIC:
637 case TLS_MODEL_GLOBAL_DYNAMIC:
638 case TLS_MODEL_INITIAL_EXEC:
639 insns = microblaze_call_tls_get_addr (x, reg, &ret, TLS_GD);
640 dest = gen_reg_rtx (Pmode);
641 emit_libcall_block (insns, dest, ret, x);
642 break;
644 case TLS_MODEL_LOCAL_EXEC:
645 insns = microblaze_call_tls_get_addr (x, reg, &ret, TLS_LDM);
647 /* Attach a unique REG_EQUIV, to allow the RTL optimizers to
648 share the LDM result with other LD model accesses. */
649 eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const1_rtx), UNSPEC_TLS);
650 dest = gen_reg_rtx (Pmode);
651 emit_libcall_block (insns, dest, ret, eqv);
653 /* Load the addend. */
654 addend = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, x, GEN_INT (TLS_DTPREL)),
655 UNSPEC_TLS);
656 addend = force_reg (SImode, gen_rtx_CONST (SImode, addend));
657 dest = gen_rtx_PLUS (Pmode, dest, addend);
658 break;
660 default:
661 gcc_unreachable ();
663 return dest;
666 static bool
667 microblaze_classify_unspec (struct microblaze_address_info *info, rtx x)
669 info->symbol_type = SYMBOL_TYPE_GENERAL;
670 info->symbol = XVECEXP (x, 0, 0);
672 if (XINT (x, 1) == UNSPEC_GOTOFF)
674 info->regA = gen_rtx_REG (SImode, PIC_OFFSET_TABLE_REGNUM);
675 info->type = ADDRESS_GOTOFF;
677 else if (XINT (x, 1) == UNSPEC_PLT)
679 info->type = ADDRESS_PLT;
681 else if (XINT (x, 1) == UNSPEC_TLS)
683 info->type = ADDRESS_TLS;
684 info->tls_type = tls_reloc INTVAL(XVECEXP(x, 0, 1));
686 else
688 return false;
690 return true;
694 /* Return true if X is a valid index register for the given mode.
695 Allow only hard registers if STRICT. */
697 static bool
698 microblaze_valid_index_register_p (rtx x,
699 machine_mode mode ATTRIBUTE_UNUSED,
700 int strict)
702 if (!strict && GET_CODE (x) == SUBREG)
703 x = SUBREG_REG (x);
705 return (GET_CODE (x) == REG
706 /* A base register is good enough to be an index register on MicroBlaze. */
707 && microblaze_regno_ok_for_base_p (REGNO (x), strict));
710 /* Get the base register for accessing a value from the memory or
711 Symbol ref. Used for MicroBlaze Small Data Area Pointer Optimization. */
712 static int
713 get_base_reg (rtx x)
715 tree decl;
716 int base_reg;
718 if (!flag_pic || microblaze_tls_symbol_p(x))
719 base_reg = MB_ABI_BASE_REGNUM;
720 else if (flag_pic)
721 base_reg = MB_ABI_PIC_ADDR_REGNUM;
723 if (TARGET_XLGPOPT
724 && GET_CODE (x) == SYMBOL_REF
725 && SYMBOL_REF_SMALL_P (x) && (decl = SYMBOL_REF_DECL (x)) != NULL)
727 if (TREE_READONLY (decl))
728 base_reg = MB_ABI_GPRO_REGNUM;
729 else
730 base_reg = MB_ABI_GPRW_REGNUM;
733 return base_reg;
736 /* Return true if X is a valid address for machine mode MODE. If it is,
737 fill in INFO appropriately. STRICT is true if we should only accept
738 hard base registers.
740 type regA regB offset symbol
742 ADDRESS_INVALID NULL NULL NULL NULL
744 ADDRESS_REG %0 NULL const_0 / NULL
745 const_int
746 ADDRESS_REG_INDEX %0 %1 NULL NULL
748 ADDRESS_SYMBOLIC r0 / NULL NULL symbol
749 sda_base_reg
751 ADDRESS_CONST_INT r0 NULL const NULL
753 For modes spanning multiple registers (DFmode in 32-bit GPRs,
754 DImode, TImode), indexed addressing cannot be used because
755 adjacent memory cells are accessed by adding word-sized offsets
756 during assembly output. */
758 static bool
759 microblaze_classify_address (struct microblaze_address_info *info, rtx x,
760 machine_mode mode, int strict)
762 rtx xplus0;
763 rtx xplus1;
765 info->type = ADDRESS_INVALID;
766 info->regA = NULL;
767 info->regB = NULL;
768 info->offset = NULL;
769 info->symbol = NULL;
770 info->symbol_type = SYMBOL_TYPE_INVALID;
772 switch (GET_CODE (x))
774 case REG:
775 case SUBREG:
777 info->type = ADDRESS_REG;
778 info->regA = x;
779 info->offset = const0_rtx;
780 return microblaze_valid_base_register_p (info->regA, mode, strict);
782 case PLUS:
784 xplus0 = XEXP (x, 0);
785 xplus1 = XEXP (x, 1);
787 if (microblaze_valid_base_register_p (xplus0, mode, strict))
789 info->type = ADDRESS_REG;
790 info->regA = xplus0;
792 if (GET_CODE (xplus1) == CONST_INT)
794 info->offset = xplus1;
795 return true;
797 else if (GET_CODE (xplus1) == UNSPEC)
799 /* Need offsettable address. */
800 if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
801 return false;
803 return microblaze_classify_unspec (info, xplus1);
805 else if ((GET_CODE (xplus1) == SYMBOL_REF ||
806 GET_CODE (xplus1) == LABEL_REF))
808 if (flag_pic == 2 || microblaze_tls_symbol_p(xplus1))
809 return false;
810 info->type = ADDRESS_SYMBOLIC;
811 info->symbol = xplus1;
812 info->symbol_type = SYMBOL_TYPE_GENERAL;
813 return true;
815 else if (GET_CODE (xplus1) == CONST)
817 rtx xconst0 = XEXP(xplus1, 0);
819 /* base + unspec. */
820 if (GET_CODE (xconst0) == UNSPEC)
822 /* Need offsettable address. */
823 if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
824 return false;
825 return microblaze_classify_unspec(info, xconst0);
828 /* for (plus x const_int) just look at x. */
829 if (GET_CODE (xconst0) == PLUS
830 && GET_CODE (XEXP (xconst0, 1)) == CONST_INT
831 && SMALL_INT (XEXP (xconst0, 1)))
833 /* This is ok as info->symbol is set to xplus1 the full
834 const-expression below. */
835 xconst0 = XEXP (xconst0, 0);
838 if (GET_CODE (xconst0) == SYMBOL_REF
839 || GET_CODE (xconst0) == LABEL_REF)
841 if (flag_pic == 2 || microblaze_tls_symbol_p(xconst0))
842 return false;
844 info->type = ADDRESS_SYMBOLIC;
845 info->symbol = xplus1;
846 info->symbol_type = SYMBOL_TYPE_GENERAL;
847 return true;
850 /* Not base + symbol || base + UNSPEC. */
851 return false;
854 else if (GET_CODE (xplus1) == REG
855 && microblaze_valid_index_register_p (xplus1, mode,
856 strict)
857 && (GET_MODE_SIZE (mode) <= UNITS_PER_WORD))
859 /* Restrict larger than word-width modes from using an index register. */
860 info->type = ADDRESS_REG_INDEX;
861 info->regB = xplus1;
862 return true;
865 break;
867 case CONST_INT:
869 info->regA = gen_rtx_raw_REG (mode, 0);
870 info->type = ADDRESS_CONST_INT;
871 info->offset = x;
872 return true;
874 case CONST:
875 case LABEL_REF:
876 case SYMBOL_REF:
878 info->type = ADDRESS_SYMBOLIC;
879 info->symbol_type = SYMBOL_TYPE_GENERAL;
880 info->symbol = x;
881 info->regA = gen_rtx_raw_REG (mode, get_base_reg (x));
883 if (GET_CODE (x) == CONST)
885 if (GET_CODE (XEXP (x, 0)) == UNSPEC)
887 info->regA = gen_rtx_raw_REG (mode,
888 get_base_reg (XVECEXP (XEXP (x,0), 0, 0)));
889 return microblaze_classify_unspec (info, XEXP (x, 0));
891 return !(flag_pic && pic_address_needs_scratch (x));
894 if (flag_pic == 2)
895 return false;
896 else if (microblaze_tls_symbol_p(x))
897 return false;
899 return true;
902 case UNSPEC:
904 if (reload_in_progress)
905 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
906 return microblaze_classify_unspec (info, x);
909 default:
910 return false;
913 return false;
916 /* This function is used to implement GO_IF_LEGITIMATE_ADDRESS. It
917 returns a nonzero value if X is a legitimate address for a memory
918 operand of the indicated MODE. STRICT is nonzero if this function
919 is called during reload. */
921 bool
922 microblaze_legitimate_address_p (machine_mode mode, rtx x, bool strict)
924 struct microblaze_address_info addr;
926 return microblaze_classify_address (&addr, x, mode, strict);
930 microblaze_valid_pic_const (rtx x)
932 switch (GET_CODE (x))
934 case CONST:
935 case CONST_INT:
936 case CONST_DOUBLE:
937 return true;
938 default:
939 return false;
944 microblaze_legitimate_pic_operand (rtx x)
946 if (flag_pic == 2 && (symbol_mentioned_p(x) || label_mentioned_p(x)))
947 return 0;
949 if (microblaze_tls_referenced_p(x))
950 return 0;
952 return 1;
955 /* Try machine-dependent ways of modifying an illegitimate address
956 to be legitimate. If we find one, return the new, valid address.
957 This is used from only one place: `memory_address' in explow.c.
959 OLDX is the address as it was before break_out_memory_refs was
960 called. In some cases it is useful to look at this to decide what
961 needs to be done.
963 It is always safe for this function to do nothing. It exists to
964 recognize opportunities to optimize the output.
966 For the MicroBlaze, transform:
968 memory(X + <large int>)
970 into:
972 Y = <large int> & ~0x7fff;
973 Z = X + Y
974 memory (Z + (<large int> & 0x7fff));
976 This is for CSE to find several similar references, and only use one Z.
978 When PIC, convert addresses of the form memory (symbol+large int) to
979 memory (reg+large int). */
981 static rtx
982 microblaze_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
983 machine_mode mode ATTRIBUTE_UNUSED)
985 register rtx xinsn = x, result;
987 if (GET_CODE (xinsn) == CONST
988 && flag_pic && pic_address_needs_scratch (xinsn))
990 rtx ptr_reg = gen_reg_rtx (Pmode);
991 rtx constant = XEXP (XEXP (xinsn, 0), 1);
993 emit_move_insn (ptr_reg, XEXP (XEXP (xinsn, 0), 0));
995 result = gen_rtx_PLUS (Pmode, ptr_reg, constant);
996 if (SMALL_INT (constant))
997 return result;
998 /* Otherwise we fall through so the code below will fix the
999 constant. */
1000 xinsn = result;
1003 if (GET_CODE (xinsn) == PLUS)
1005 register rtx xplus0 = XEXP (xinsn, 0);
1006 register rtx xplus1 = XEXP (xinsn, 1);
1007 register enum rtx_code code0 = GET_CODE (xplus0);
1008 register enum rtx_code code1 = GET_CODE (xplus1);
1010 if (code0 != REG && code1 == REG)
1012 xplus0 = XEXP (xinsn, 1);
1013 xplus1 = XEXP (xinsn, 0);
1014 code0 = GET_CODE (xplus0);
1015 code1 = GET_CODE (xplus1);
1018 if (code0 == REG && REG_OK_FOR_BASE_P (xplus0)
1019 && code1 == CONST_INT && !SMALL_INT (xplus1))
1021 rtx int_reg = gen_reg_rtx (Pmode);
1022 rtx ptr_reg = gen_reg_rtx (Pmode);
1024 emit_move_insn (int_reg, GEN_INT (INTVAL (xplus1) & ~0x7fff));
1026 emit_insn (gen_rtx_SET (ptr_reg,
1027 gen_rtx_PLUS (Pmode, xplus0, int_reg)));
1029 result = gen_rtx_PLUS (Pmode, ptr_reg,
1030 GEN_INT (INTVAL (xplus1) & 0x7fff));
1031 return result;
1034 if (code0 == REG && REG_OK_FOR_BASE_P (xplus0))
1036 if (reload_in_progress)
1037 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
1038 if (code1 == CONST)
1040 xplus1 = XEXP (xplus1, 0);
1041 code1 = GET_CODE (xplus1);
1043 if (code1 == SYMBOL_REF)
1045 if (microblaze_tls_symbol_p(xplus1))
1047 rtx tls_ref, reg;
1048 reg = gen_reg_rtx (Pmode);
1050 tls_ref = microblaze_legitimize_tls_address (xplus1,
1051 NULL_RTX);
1052 emit_move_insn (reg, tls_ref);
1054 result = gen_rtx_PLUS (Pmode, xplus0, reg);
1056 return result;
1058 else if (flag_pic == 2)
1060 rtx pic_ref, reg;
1061 reg = gen_reg_rtx (Pmode);
1063 pic_ref = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, xplus1),
1064 UNSPEC_GOTOFF);
1065 pic_ref = gen_rtx_CONST (Pmode, pic_ref);
1066 pic_ref = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, pic_ref);
1067 pic_ref = gen_const_mem (Pmode, pic_ref);
1068 emit_move_insn (reg, pic_ref);
1069 result = gen_rtx_PLUS (Pmode, xplus0, reg);
1070 return result;
1076 if (GET_CODE (xinsn) == SYMBOL_REF)
1078 rtx reg;
1079 if (microblaze_tls_symbol_p(xinsn))
1081 reg = microblaze_legitimize_tls_address (xinsn, NULL_RTX);
1083 else
1085 rtx pic_ref;
1087 if (reload_in_progress)
1088 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
1090 pic_ref = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, xinsn), UNSPEC_GOTOFF);
1091 pic_ref = gen_rtx_CONST (Pmode, pic_ref);
1092 pic_ref = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, pic_ref);
1093 pic_ref = gen_const_mem (Pmode, pic_ref);
1094 reg = pic_ref;
1096 return reg;
1099 return x;
1102 /* Block Moves. */
1104 #define MAX_MOVE_REGS 8
1105 #define MAX_MOVE_BYTES (MAX_MOVE_REGS * UNITS_PER_WORD)
1107 /* Emit straight-line code to move LENGTH bytes from SRC to DEST.
1108 Assume that the areas do not overlap. */
1110 static void
1111 microblaze_block_move_straight (rtx dest, rtx src, HOST_WIDE_INT length)
1113 HOST_WIDE_INT offset, delta;
1114 unsigned HOST_WIDE_INT bits;
1115 int i;
1116 machine_mode mode;
1117 rtx *regs;
1119 bits = BITS_PER_WORD;
1120 mode = mode_for_size (bits, MODE_INT, 0);
1121 delta = bits / BITS_PER_UNIT;
1123 /* Allocate a buffer for the temporary registers. */
1124 regs = XALLOCAVEC (rtx, length / delta);
1126 /* Load as many BITS-sized chunks as possible. Use a normal load if
1127 the source has enough alignment, otherwise use left/right pairs. */
1128 for (offset = 0, i = 0; offset + delta <= length; offset += delta, i++)
1130 regs[i] = gen_reg_rtx (mode);
1131 emit_move_insn (regs[i], adjust_address (src, mode, offset));
1134 /* Copy the chunks to the destination. */
1135 for (offset = 0, i = 0; offset + delta <= length; offset += delta, i++)
1136 emit_move_insn (adjust_address (dest, mode, offset), regs[i]);
1138 /* Mop up any left-over bytes. */
1139 if (offset < length)
1141 src = adjust_address (src, BLKmode, offset);
1142 dest = adjust_address (dest, BLKmode, offset);
1143 move_by_pieces (dest, src, length - offset,
1144 MIN (MEM_ALIGN (src), MEM_ALIGN (dest)), 0);
1148 /* Helper function for doing a loop-based block operation on memory
1149 reference MEM. Each iteration of the loop will operate on LENGTH
1150 bytes of MEM.
1152 Create a new base register for use within the loop and point it to
1153 the start of MEM. Create a new memory reference that uses this
1154 register. Store them in *LOOP_REG and *LOOP_MEM respectively. */
1156 static void
1157 microblaze_adjust_block_mem (rtx mem, HOST_WIDE_INT length,
1158 rtx * loop_reg, rtx * loop_mem)
1160 *loop_reg = copy_addr_to_reg (XEXP (mem, 0));
1162 /* Although the new mem does not refer to a known location,
1163 it does keep up to LENGTH bytes of alignment. */
1164 *loop_mem = change_address (mem, BLKmode, *loop_reg);
1165 set_mem_align (*loop_mem,
1166 MIN ((HOST_WIDE_INT) MEM_ALIGN (mem),
1167 length * BITS_PER_UNIT));
1171 /* Move LENGTH bytes from SRC to DEST using a loop that moves MAX_MOVE_BYTES
1172 per iteration. LENGTH must be at least MAX_MOVE_BYTES. Assume that the
1173 memory regions do not overlap. */
1175 static void
1176 microblaze_block_move_loop (rtx dest, rtx src, HOST_WIDE_INT length)
1178 rtx_code_label *label;
1179 rtx src_reg, dest_reg, final_src;
1180 HOST_WIDE_INT leftover;
1182 leftover = length % MAX_MOVE_BYTES;
1183 length -= leftover;
1185 /* Create registers and memory references for use within the loop. */
1186 microblaze_adjust_block_mem (src, MAX_MOVE_BYTES, &src_reg, &src);
1187 microblaze_adjust_block_mem (dest, MAX_MOVE_BYTES, &dest_reg, &dest);
1189 /* Calculate the value that SRC_REG should have after the last iteration
1190 of the loop. */
1191 final_src = expand_simple_binop (Pmode, PLUS, src_reg, GEN_INT (length),
1192 0, 0, OPTAB_WIDEN);
1194 /* Emit the start of the loop. */
1195 label = gen_label_rtx ();
1196 emit_label (label);
1198 /* Emit the loop body. */
1199 microblaze_block_move_straight (dest, src, MAX_MOVE_BYTES);
1201 /* Move on to the next block. */
1202 emit_move_insn (src_reg, plus_constant (Pmode, src_reg, MAX_MOVE_BYTES));
1203 emit_move_insn (dest_reg, plus_constant (Pmode, dest_reg, MAX_MOVE_BYTES));
1205 /* Emit the test & branch. */
1206 emit_insn (gen_cbranchsi4 (gen_rtx_NE (SImode, src_reg, final_src),
1207 src_reg, final_src, label));
1209 /* Mop up any left-over bytes. */
1210 if (leftover)
1211 microblaze_block_move_straight (dest, src, leftover);
1214 /* Expand a movmemsi instruction. */
1216 bool
1217 microblaze_expand_block_move (rtx dest, rtx src, rtx length, rtx align_rtx)
1220 if (GET_CODE (length) == CONST_INT)
1222 HOST_WIDE_INT bytes = INTVAL (length);
1223 int align = INTVAL (align_rtx);
1225 if (align > UNITS_PER_WORD)
1227 align = UNITS_PER_WORD; /* We can't do any better. */
1229 else if (align < UNITS_PER_WORD)
1231 if (INTVAL (length) <= MAX_MOVE_BYTES)
1233 move_by_pieces (dest, src, bytes, align, 0);
1234 return true;
1236 else
1237 return false;
1240 if (INTVAL (length) <= 2 * MAX_MOVE_BYTES)
1242 microblaze_block_move_straight (dest, src, INTVAL (length));
1243 return true;
1245 else if (optimize)
1247 microblaze_block_move_loop (dest, src, INTVAL (length));
1248 return true;
1251 return false;
1254 static bool
1255 microblaze_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED,
1256 int opno ATTRIBUTE_UNUSED, int *total,
1257 bool speed ATTRIBUTE_UNUSED)
1259 machine_mode mode = GET_MODE (x);
1261 switch (code)
1263 case MEM:
1265 int num_words = (GET_MODE_SIZE (mode) > UNITS_PER_WORD) ? 2 : 1;
1266 if (simple_memory_operand (x, mode))
1267 *total = COSTS_N_INSNS (2 * num_words);
1268 else
1269 *total = COSTS_N_INSNS (2 * (2 * num_words));
1271 return true;
1273 case NOT:
1275 if (mode == DImode)
1277 *total = COSTS_N_INSNS (2);
1279 else
1280 *total = COSTS_N_INSNS (1);
1281 return false;
1283 case AND:
1284 case IOR:
1285 case XOR:
1287 if (mode == DImode)
1289 *total = COSTS_N_INSNS (2);
1291 else
1292 *total = COSTS_N_INSNS (1);
1294 return false;
1296 case ASHIFT:
1297 case ASHIFTRT:
1298 case LSHIFTRT:
1300 if (TARGET_BARREL_SHIFT)
1302 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v5.00.a")
1303 >= 0)
1304 *total = COSTS_N_INSNS (1);
1305 else
1306 *total = COSTS_N_INSNS (2);
1308 else if (!TARGET_SOFT_MUL)
1309 *total = COSTS_N_INSNS (1);
1310 else if (GET_CODE (XEXP (x, 1)) == CONST_INT)
1312 /* Add 1 to make shift slightly more expensive than add. */
1313 *total = COSTS_N_INSNS (INTVAL (XEXP (x, 1))) + 1;
1314 /* Reduce shift costs for special circumstances. */
1315 if (optimize_size && INTVAL (XEXP (x, 1)) > 5)
1316 *total -= 2;
1317 if (!optimize_size && INTVAL (XEXP (x, 1)) > 17)
1318 *total -= 2;
1320 else
1321 /* Double the worst cost of shifts when there is no barrel shifter and
1322 the shift amount is in a reg. */
1323 *total = COSTS_N_INSNS (32 * 4);
1324 return true;
1326 case PLUS:
1327 case MINUS:
1329 if (mode == SFmode || mode == DFmode)
1331 if (TARGET_HARD_FLOAT)
1332 *total = COSTS_N_INSNS (6);
1333 return true;
1335 else if (mode == DImode)
1337 *total = COSTS_N_INSNS (4);
1338 return true;
1340 else
1342 *total = COSTS_N_INSNS (1);
1343 return true;
1346 return false;
1348 case NEG:
1350 if (mode == DImode)
1351 *total = COSTS_N_INSNS (4);
1353 return false;
1355 case MULT:
1357 if (mode == SFmode)
1359 if (TARGET_HARD_FLOAT)
1360 *total = COSTS_N_INSNS (6);
1362 else if (!TARGET_SOFT_MUL)
1364 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v5.00.a")
1365 >= 0)
1366 *total = COSTS_N_INSNS (1);
1367 else
1368 *total = COSTS_N_INSNS (3);
1370 else
1371 *total = COSTS_N_INSNS (10);
1372 return true;
1374 case DIV:
1375 case UDIV:
1377 if (mode == SFmode)
1379 if (TARGET_HARD_FLOAT)
1380 *total = COSTS_N_INSNS (23);
1382 return false;
1384 case SIGN_EXTEND:
1386 *total = COSTS_N_INSNS (1);
1387 return false;
1389 case ZERO_EXTEND:
1391 *total = COSTS_N_INSNS (1);
1392 return false;
1396 return false;
1399 /* Return the number of instructions needed to load or store a value
1400 of mode MODE at X. Return 0 if X isn't valid for MODE. */
1402 static int
1403 microblaze_address_insns (rtx x, machine_mode mode)
1405 struct microblaze_address_info addr;
1407 if (microblaze_classify_address (&addr, x, mode, false))
1409 switch (addr.type)
1411 case ADDRESS_REG:
1412 if (SMALL_INT (addr.offset))
1413 return 1;
1414 else
1415 return 2;
1416 case ADDRESS_CONST_INT:
1417 if (SMALL_INT (x))
1418 return 1;
1419 else
1420 return 2;
1421 case ADDRESS_REG_INDEX:
1422 return 1;
1423 case ADDRESS_SYMBOLIC:
1424 case ADDRESS_GOTOFF:
1425 return 2;
1426 case ADDRESS_TLS:
1427 switch (addr.tls_type)
1429 case TLS_GD:
1430 return 2;
1431 case TLS_LDM:
1432 return 2;
1433 case TLS_DTPREL:
1434 return 1;
1435 default :
1436 abort();
1438 default:
1439 break;
1442 return 0;
1445 /* Provide the costs of an addressing mode that contains ADDR.
1446 If ADDR is not a valid address, its cost is irrelevant. */
1447 static int
1448 microblaze_address_cost (rtx addr, machine_mode mode ATTRIBUTE_UNUSED,
1449 addr_space_t as ATTRIBUTE_UNUSED,
1450 bool speed ATTRIBUTE_UNUSED)
1452 return COSTS_N_INSNS (microblaze_address_insns (addr, GET_MODE (addr)));
1455 /* Return nonzero if X is an address which needs a temporary register when
1456 reloaded while generating PIC code. */
1459 pic_address_needs_scratch (rtx x)
1461 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x,0)) == PLUS)
1463 rtx p0, p1;
1465 p0 = XEXP (XEXP (x, 0), 0);
1466 p1 = XEXP (XEXP (x, 0), 1);
1468 if ((GET_CODE (p0) == SYMBOL_REF || GET_CODE (p0) == LABEL_REF)
1469 && (GET_CODE (p1) == CONST_INT)
1470 && (flag_pic == 2 || microblaze_tls_symbol_p (p0) || !SMALL_INT (p1)))
1471 return 1;
1473 return 0;
1476 /* Argument support functions. */
1477 /* Initialize CUMULATIVE_ARGS for a function. */
1479 void
1480 init_cumulative_args (CUMULATIVE_ARGS * cum, tree fntype,
1481 rtx libname ATTRIBUTE_UNUSED)
1483 static CUMULATIVE_ARGS zero_cum;
1484 tree param, next_param;
1486 *cum = zero_cum;
1488 /* Determine if this function has variable arguments. This is
1489 indicated by the last argument being 'void_type_mode' if there
1490 are no variable arguments. The standard MicroBlaze calling sequence
1491 passes all arguments in the general purpose registers in this case. */
1493 for (param = fntype ? TYPE_ARG_TYPES (fntype) : 0;
1494 param != 0; param = next_param)
1496 next_param = TREE_CHAIN (param);
1497 if (next_param == 0 && TREE_VALUE (param) != void_type_node)
1498 cum->gp_reg_found = 1;
1502 /* Advance the argument to the next argument position. */
1504 static void
1505 microblaze_function_arg_advance (cumulative_args_t cum_v,
1506 machine_mode mode,
1507 const_tree type, bool named ATTRIBUTE_UNUSED)
1509 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
1511 cum->arg_number++;
1512 switch (mode)
1514 case VOIDmode:
1515 break;
1517 default:
1518 gcc_assert (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
1519 || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT);
1521 cum->gp_reg_found = 1;
1522 cum->arg_words += ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1)
1523 / UNITS_PER_WORD);
1524 break;
1526 case BLKmode:
1527 cum->gp_reg_found = 1;
1528 cum->arg_words += ((int_size_in_bytes (type) + UNITS_PER_WORD - 1)
1529 / UNITS_PER_WORD);
1530 break;
1532 case SFmode:
1533 cum->arg_words++;
1534 if (!cum->gp_reg_found && cum->arg_number <= 2)
1535 cum->fp_code += 1 << ((cum->arg_number - 1) * 2);
1536 break;
1538 case DFmode:
1539 cum->arg_words += 2;
1540 if (!cum->gp_reg_found && cum->arg_number <= 2)
1541 cum->fp_code += 2 << ((cum->arg_number - 1) * 2);
1542 break;
1544 case DImode:
1545 cum->gp_reg_found = 1;
1546 cum->arg_words += 2;
1547 break;
1549 case QImode:
1550 case HImode:
1551 case SImode:
1552 case TImode:
1553 cum->gp_reg_found = 1;
1554 cum->arg_words++;
1555 break;
1559 /* Return an RTL expression containing the register for the given mode,
1560 or 0 if the argument is to be passed on the stack. */
1562 static rtx
1563 microblaze_function_arg (cumulative_args_t cum_v, machine_mode mode,
1564 const_tree type ATTRIBUTE_UNUSED,
1565 bool named ATTRIBUTE_UNUSED)
1567 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
1569 rtx ret;
1570 int regbase = -1;
1571 int *arg_words = &cum->arg_words;
1573 cum->last_arg_fp = 0;
1574 switch (mode)
1576 case SFmode:
1577 case DFmode:
1578 case VOIDmode:
1579 case QImode:
1580 case HImode:
1581 case SImode:
1582 case DImode:
1583 case TImode:
1584 regbase = GP_ARG_FIRST;
1585 break;
1586 default:
1587 gcc_assert (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
1588 || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT);
1589 /* Drops through. */
1590 case BLKmode:
1591 regbase = GP_ARG_FIRST;
1592 break;
1595 if (*arg_words >= MAX_ARGS_IN_REGISTERS)
1596 ret = 0;
1597 else
1599 gcc_assert (regbase != -1);
1601 ret = gen_rtx_REG (mode, regbase + *arg_words);
1604 if (mode == VOIDmode)
1606 if (cum->num_adjusts > 0)
1607 ret = gen_rtx_PARALLEL ((machine_mode) cum->fp_code,
1608 gen_rtvec_v (cum->num_adjusts, cum->adjust));
1611 return ret;
1614 /* Return number of bytes of argument to put in registers. */
1615 static int
1616 function_arg_partial_bytes (cumulative_args_t cum_v, machine_mode mode,
1617 tree type, bool named ATTRIBUTE_UNUSED)
1619 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
1621 if ((mode == BLKmode
1622 || GET_MODE_CLASS (mode) != MODE_COMPLEX_INT
1623 || GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT)
1624 && cum->arg_words < MAX_ARGS_IN_REGISTERS)
1626 int words;
1627 if (mode == BLKmode)
1628 words = ((int_size_in_bytes (type) + UNITS_PER_WORD - 1)
1629 / UNITS_PER_WORD);
1630 else
1631 words = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
1633 if (words + cum->arg_words <= MAX_ARGS_IN_REGISTERS)
1634 return 0; /* structure fits in registers */
1636 return (MAX_ARGS_IN_REGISTERS - cum->arg_words) * UNITS_PER_WORD;
1639 else if (mode == DImode && cum->arg_words == MAX_ARGS_IN_REGISTERS - 1)
1640 return UNITS_PER_WORD;
1642 return 0;
1645 /* Convert a version number of the form "vX.YY.Z" to an integer encoding
1646 for easier range comparison. */
1647 static int
1648 microblaze_version_to_int (const char *version)
1650 const char *p, *v;
1651 const char *tmpl = "vXX.YY.Z";
1652 int iver = 0;
1654 p = version;
1655 v = tmpl;
1657 while (*p)
1659 if (*v == 'X')
1660 { /* Looking for major */
1661 if (*p == '.')
1663 *v++;
1665 else
1667 if (!(*p >= '0' && *p <= '9'))
1668 return -1;
1669 iver += (int) (*p - '0');
1670 iver *= 10;
1673 else if (*v == 'Y')
1674 { /* Looking for minor */
1675 if (!(*p >= '0' && *p <= '9'))
1676 return -1;
1677 iver += (int) (*p - '0');
1678 iver *= 10;
1680 else if (*v == 'Z')
1681 { /* Looking for compat */
1682 if (!(*p >= 'a' && *p <= 'z'))
1683 return -1;
1684 iver *= 10;
1685 iver += (int) (*p - 'a');
1687 else
1689 if (*p != *v)
1690 return -1;
1693 v++;
1694 p++;
1697 if (*p)
1698 return -1;
1700 return iver;
1704 static void
1705 microblaze_option_override (void)
1707 register int i, start;
1708 register int regno;
1709 register machine_mode mode;
1710 int ver;
1712 microblaze_section_threshold = (global_options_set.x_g_switch_value
1713 ? g_switch_value
1714 : MICROBLAZE_DEFAULT_GVALUE);
1716 if (flag_pic)
1718 /* Make sure it's 2, we only support one kind of PIC. */
1719 flag_pic = 2;
1720 if (!TARGET_SUPPORTS_PIC)
1722 error ("-fPIC/-fpic not supported for this target");
1723 /* Clear it to avoid further errors. */
1724 flag_pic = 0;
1728 /* Check the MicroBlaze CPU version for any special action to be done. */
1729 if (microblaze_select_cpu == NULL)
1730 microblaze_select_cpu = MICROBLAZE_DEFAULT_CPU;
1731 ver = microblaze_version_to_int (microblaze_select_cpu);
1732 if (ver == -1)
1734 error ("%qs is an invalid argument to -mcpu=", microblaze_select_cpu);
1737 ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v3.00.a");
1738 if (ver < 0)
1740 /* No hardware exceptions in earlier versions. So no worries. */
1741 #if 0
1742 microblaze_select_flags &= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY);
1743 #endif
1744 microblaze_no_unsafe_delay = 0;
1745 microblaze_pipe = MICROBLAZE_PIPE_3;
1747 else if (ver == 0
1748 || (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v4.00.b")
1749 == 0))
1751 #if 0
1752 microblaze_select_flags |= (MICROBLAZE_MASK_NO_UNSAFE_DELAY);
1753 #endif
1754 microblaze_no_unsafe_delay = 1;
1755 microblaze_pipe = MICROBLAZE_PIPE_3;
1757 else
1759 /* We agree to use 5 pipe-stage model even on area optimized 3
1760 pipe-stage variants. */
1761 #if 0
1762 microblaze_select_flags &= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY);
1763 #endif
1764 microblaze_no_unsafe_delay = 0;
1765 microblaze_pipe = MICROBLAZE_PIPE_5;
1766 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v5.00.a") == 0
1767 || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu,
1768 "v5.00.b") == 0
1769 || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu,
1770 "v5.00.c") == 0)
1772 /* Pattern compares are to be turned on by default only when
1773 compiling for MB v5.00.'z'. */
1774 target_flags |= MASK_PATTERN_COMPARE;
1778 ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v6.00.a");
1779 if (ver < 0)
1781 if (TARGET_MULTIPLY_HIGH)
1782 warning (0,
1783 "-mxl-multiply-high can be used only with -mcpu=v6.00.a or greater");
1786 ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v8.10.a");
1787 microblaze_has_clz = 1;
1788 if (ver < 0)
1790 /* MicroBlaze prior to 8.10.a didn't have clz. */
1791 microblaze_has_clz = 0;
1794 /* TARGET_REORDER defaults to 2 if -mxl-reorder not specified. */
1795 ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v8.30.a");
1796 if (ver < 0)
1798 if (TARGET_REORDER == 1)
1799 warning (0, "-mxl-reorder can be used only with -mcpu=v8.30.a or greater");
1800 TARGET_REORDER = 0;
1802 else if ((ver == 0) && !TARGET_PATTERN_COMPARE)
1804 if (TARGET_REORDER == 1)
1805 warning (0, "-mxl-reorder requires -mxl-pattern-compare for -mcpu=v8.30.a");
1806 TARGET_REORDER = 0;
1809 if (TARGET_MULTIPLY_HIGH && TARGET_SOFT_MUL)
1810 error ("-mxl-multiply-high requires -mno-xl-soft-mul");
1812 /* Always use DFA scheduler. */
1813 microblaze_sched_use_dfa = 1;
1815 #if 0
1816 microblaze_abicalls = MICROBLAZE_ABICALLS_NO;
1817 #endif
1819 /* Initialize the high, low values for legit floating point constants. */
1820 real_maxval (&dfhigh, 0, DFmode);
1821 real_maxval (&dflow, 1, DFmode);
1822 real_maxval (&sfhigh, 0, SFmode);
1823 real_maxval (&sflow, 1, SFmode);
1825 microblaze_print_operand_punct['?'] = 1;
1826 microblaze_print_operand_punct['#'] = 1;
1827 microblaze_print_operand_punct['&'] = 1;
1828 microblaze_print_operand_punct['!'] = 1;
1829 microblaze_print_operand_punct['*'] = 1;
1830 microblaze_print_operand_punct['@'] = 1;
1831 microblaze_print_operand_punct['.'] = 1;
1832 microblaze_print_operand_punct['('] = 1;
1833 microblaze_print_operand_punct[')'] = 1;
1834 microblaze_print_operand_punct['['] = 1;
1835 microblaze_print_operand_punct[']'] = 1;
1836 microblaze_print_operand_punct['<'] = 1;
1837 microblaze_print_operand_punct['>'] = 1;
1838 microblaze_print_operand_punct['{'] = 1;
1839 microblaze_print_operand_punct['}'] = 1;
1840 microblaze_print_operand_punct['^'] = 1;
1841 microblaze_print_operand_punct['$'] = 1;
1842 microblaze_print_operand_punct['+'] = 1;
1844 /* Set up array to map GCC register number to debug register number.
1845 Ignore the special purpose register numbers. */
1847 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
1848 microblaze_dbx_regno[i] = -1;
1850 start = GP_DBX_FIRST - GP_REG_FIRST;
1851 for (i = GP_REG_FIRST; i <= GP_REG_LAST; i++)
1852 microblaze_dbx_regno[i] = i + start;
1854 /* Set up array giving whether a given register can hold a given mode. */
1856 for (mode = VOIDmode;
1857 mode != MAX_MACHINE_MODE; mode = (machine_mode) ((int) mode + 1))
1859 register int size = GET_MODE_SIZE (mode);
1861 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
1863 register int ok;
1865 if (mode == CCmode)
1867 ok = (ST_REG_P (regno) || GP_REG_P (regno));
1869 else if (GP_REG_P (regno))
1870 ok = ((regno & 1) == 0 || size <= UNITS_PER_WORD);
1871 else
1872 ok = 0;
1874 microblaze_hard_regno_mode_ok[(int) mode][regno] = ok;
1879 /* Return true if FUNC is an interrupt function as specified
1880 by the "interrupt_handler" attribute. */
1882 static int
1883 microblaze_interrupt_function_p (tree func)
1885 tree a;
1887 if (TREE_CODE (func) != FUNCTION_DECL)
1888 return 0;
1890 a = lookup_attribute ("interrupt_handler", DECL_ATTRIBUTES (func));
1891 return a != NULL_TREE;
1894 static int
1895 microblaze_fast_interrupt_function_p (tree func)
1897 tree a;
1899 if (TREE_CODE (func) != FUNCTION_DECL)
1900 return 0;
1902 a = lookup_attribute ("fast_interrupt", DECL_ATTRIBUTES (func));
1903 return a != NULL_TREE;
1906 microblaze_break_function_p (tree func)
1908 tree a;
1909 if (!func)
1910 return 0;
1911 if (TREE_CODE (func) != FUNCTION_DECL)
1912 return 0;
1914 a = lookup_attribute ("break_handler", DECL_ATTRIBUTES (func));
1915 return a != NULL_TREE;
1917 /* Return true if FUNC is an interrupt function which uses
1918 normal return, indicated by the "save_volatiles" attribute. */
1920 static int
1921 microblaze_save_volatiles (tree func)
1923 tree a;
1925 if (TREE_CODE (func) != FUNCTION_DECL)
1926 return 0;
1928 a = lookup_attribute ("save_volatiles", DECL_ATTRIBUTES (func));
1929 return a != NULL_TREE;
1932 /* Return whether function is tagged with 'interrupt_handler'
1933 or 'fast_interrupt' attribute. Return true if function
1934 should use return from interrupt rather than normal
1935 function return. */
1937 microblaze_is_interrupt_variant (void)
1939 return (interrupt_handler || fast_interrupt);
1942 microblaze_is_break_handler (void)
1944 return break_handler;
1947 /* Determine of register must be saved/restored in call. */
1948 static int
1949 microblaze_must_save_register (int regno)
1951 if (pic_offset_table_rtx &&
1952 (regno == MB_ABI_PIC_ADDR_REGNUM) && df_regs_ever_live_p (regno))
1953 return 1;
1955 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
1956 return 1;
1958 if (frame_pointer_needed && (regno == HARD_FRAME_POINTER_REGNUM))
1959 return 1;
1961 if (!crtl->is_leaf)
1963 if (regno == MB_ABI_SUB_RETURN_ADDR_REGNUM)
1964 return 1;
1965 if ((microblaze_is_interrupt_variant () || save_volatiles) &&
1966 (regno >= 3 && regno <= 12))
1967 return 1;
1970 if (microblaze_is_interrupt_variant ())
1972 if (df_regs_ever_live_p (regno)
1973 || regno == MB_ABI_MSR_SAVE_REG
1974 || (interrupt_handler
1975 && (regno == MB_ABI_ASM_TEMP_REGNUM
1976 || regno == MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM)))
1977 return 1;
1980 if (save_volatiles)
1982 if (df_regs_ever_live_p (regno)
1983 || regno == MB_ABI_ASM_TEMP_REGNUM
1984 || regno == MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM)
1985 return 1;
1988 return 0;
1991 /* Return the bytes needed to compute the frame pointer from the current
1992 stack pointer.
1994 MicroBlaze stack frames look like:
1998 Before call After call
1999 +-----------------------+ +-----------------------+
2000 high | | | |
2001 mem. | local variables, | | local variables, |
2002 | callee saved and | | callee saved and |
2003 | temps | | temps |
2004 +-----------------------+ +-----------------------+
2005 | arguments for called | | arguments for called |
2006 | subroutines | | subroutines |
2007 | (optional) | | (optional) |
2008 +-----------------------+ +-----------------------+
2009 | Link register | | Link register |
2010 SP->| | | |
2011 +-----------------------+ +-----------------------+
2013 | local variables, |
2014 | callee saved and |
2015 | temps |
2016 +-----------------------+
2017 | MSR (optional if, |
2018 | interrupt handler) |
2019 +-----------------------+
2021 | alloca allocations |
2023 +-----------------------+
2025 | arguments for called |
2026 | subroutines |
2027 | (optional) |
2029 +-----------------------+
2030 | Link register |
2031 low FP,SP->| |
2032 memory +-----------------------+
2036 static HOST_WIDE_INT
2037 compute_frame_size (HOST_WIDE_INT size)
2039 int regno;
2040 HOST_WIDE_INT total_size; /* # bytes that the entire frame takes up. */
2041 HOST_WIDE_INT var_size; /* # bytes that local variables take up. */
2042 HOST_WIDE_INT args_size; /* # bytes that outgoing arguments take up. */
2043 int link_debug_size; /* # bytes for link register. */
2044 HOST_WIDE_INT gp_reg_size; /* # bytes needed to store calle-saved gp regs. */
2045 long mask; /* mask of saved gp registers. */
2047 interrupt_handler =
2048 microblaze_interrupt_function_p (current_function_decl);
2049 break_handler =
2050 microblaze_break_function_p (current_function_decl);
2052 fast_interrupt =
2053 microblaze_fast_interrupt_function_p (current_function_decl);
2054 save_volatiles = microblaze_save_volatiles (current_function_decl);
2055 if (break_handler)
2056 interrupt_handler = break_handler;
2058 gp_reg_size = 0;
2059 mask = 0;
2060 var_size = size;
2061 args_size = crtl->outgoing_args_size;
2063 if ((args_size == 0) && cfun->calls_alloca)
2064 args_size = NUM_OF_ARGS * UNITS_PER_WORD;
2066 total_size = var_size + args_size;
2068 if (flag_pic == 2)
2069 /* force setting GOT. */
2070 df_set_regs_ever_live (MB_ABI_PIC_ADDR_REGNUM, true);
2072 /* Calculate space needed for gp registers. */
2073 for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
2075 if (microblaze_must_save_register (regno))
2078 if (regno != MB_ABI_SUB_RETURN_ADDR_REGNUM)
2079 /* Don't account for link register. It is accounted specially below. */
2080 gp_reg_size += GET_MODE_SIZE (SImode);
2082 mask |= (1L << (regno - GP_REG_FIRST));
2086 total_size += gp_reg_size;
2088 /* Add 4 bytes for MSR. */
2089 if (microblaze_is_interrupt_variant ())
2090 total_size += 4;
2092 /* No space to be allocated for link register in leaf functions with no other
2093 stack requirements. */
2094 if (total_size == 0 && crtl->is_leaf)
2095 link_debug_size = 0;
2096 else
2097 link_debug_size = UNITS_PER_WORD;
2099 total_size += link_debug_size;
2101 /* Save other computed information. */
2102 current_frame_info.total_size = total_size;
2103 current_frame_info.var_size = var_size;
2104 current_frame_info.args_size = args_size;
2105 current_frame_info.gp_reg_size = gp_reg_size;
2106 current_frame_info.mask = mask;
2107 current_frame_info.initialized = reload_completed;
2108 current_frame_info.num_gp = gp_reg_size / UNITS_PER_WORD;
2109 current_frame_info.link_debug_size = link_debug_size;
2111 if (mask)
2112 /* Offset from which to callee-save GP regs. */
2113 current_frame_info.gp_offset = (total_size - gp_reg_size);
2114 else
2115 current_frame_info.gp_offset = 0;
2117 /* Ok, we're done. */
2118 return total_size;
2121 /* Make sure that we're not trying to eliminate to the wrong hard frame
2122 pointer. */
2124 static bool
2125 microblaze_can_eliminate (const int from, const int to)
2127 return ((from == RETURN_ADDRESS_POINTER_REGNUM && !leaf_function_p())
2128 || (to == MB_ABI_SUB_RETURN_ADDR_REGNUM && leaf_function_p())
2129 || (from != RETURN_ADDRESS_POINTER_REGNUM
2130 && (to == HARD_FRAME_POINTER_REGNUM
2131 || (to == STACK_POINTER_REGNUM && !frame_pointer_needed))));
2134 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
2135 pointer or argument pointer or the return address pointer. TO is either
2136 the stack pointer or hard frame pointer. */
2138 HOST_WIDE_INT
2139 microblaze_initial_elimination_offset (int from, int to)
2141 HOST_WIDE_INT offset;
2143 switch (from)
2145 case FRAME_POINTER_REGNUM:
2146 offset = 0;
2147 break;
2148 case ARG_POINTER_REGNUM:
2149 if (to == STACK_POINTER_REGNUM || to == HARD_FRAME_POINTER_REGNUM)
2150 offset = compute_frame_size (get_frame_size ());
2151 else
2152 gcc_unreachable ();
2153 break;
2154 case RETURN_ADDRESS_POINTER_REGNUM:
2155 if (crtl->is_leaf)
2156 offset = 0;
2157 else
2158 offset = current_frame_info.gp_offset +
2159 ((UNITS_PER_WORD - (POINTER_SIZE / BITS_PER_UNIT)));
2160 break;
2161 default:
2162 gcc_unreachable ();
2164 return offset;
2167 /* Print operands using format code.
2169 The MicroBlaze specific codes are:
2171 'X' X is CONST_INT, prints 32 bits in hexadecimal format = "0x%08x",
2172 'x' X is CONST_INT, prints 16 bits in hexadecimal format = "0x%04x",
2173 'F' op is CONST_DOUBLE, print 32 bits in hex,
2174 'd' output integer constant in decimal,
2175 'z' if the operand is 0, use $0 instead of normal operand.
2176 'D' print second register of double-word register operand.
2177 'L' print low-order register of double-word register operand.
2178 'M' print high-order register of double-word register operand.
2179 'C' print part of opcode for a branch condition.
2180 'N' print part of opcode for a branch condition, inverted.
2181 'S' X is CODE_LABEL, print with prefix of "LS" (for embedded switch).
2182 'B' print 'z' for EQ, 'n' for NE
2183 'b' print 'n' for EQ, 'z' for NE
2184 'T' print 'f' for EQ, 't' for NE
2185 't' print 't' for EQ, 'f' for NE
2186 'm' Print 1<<operand.
2187 'i' Print 'i' if MEM operand has immediate value
2188 'y' Print 'y' if MEM operand is single register
2189 'o' Print operand address+4
2190 '?' Print 'd' if we use a branch with delay slot instead of normal branch.
2191 'h' Print high word of const_double (int or float) value as hex
2192 'j' Print low word of const_double (int or float) value as hex
2193 's' Print -1 if operand is negative, 0 if positive (sign extend)
2194 '@' Print the name of the temporary register (rMB_ABI_ASM_TEMP_REGNUM).
2195 '#' Print nop if the delay slot of a branch is not filled.
2198 void
2199 print_operand (FILE * file, rtx op, int letter)
2201 register enum rtx_code code;
2203 if (PRINT_OPERAND_PUNCT_VALID_P (letter))
2205 switch (letter)
2207 case '?':
2208 /* Conditionally add a 'd' to indicate filled delay slot. */
2209 if (final_sequence != NULL)
2210 fputs ("d", file);
2211 break;
2213 case '#':
2214 /* Conditionally add a nop in unfilled delay slot. */
2215 if (final_sequence == NULL)
2216 fputs ("nop\t\t# Unfilled delay slot\n", file);
2217 break;
2219 case '@':
2220 fputs (reg_names[GP_REG_FIRST + MB_ABI_ASM_TEMP_REGNUM], file);
2221 break;
2223 default:
2224 output_operand_lossage ("unknown punctuation '%c'", letter);
2225 break;
2228 return;
2231 if (!op)
2233 output_operand_lossage ("null pointer");
2234 return;
2237 code = GET_CODE (op);
2239 if (code == SIGN_EXTEND)
2240 op = XEXP (op, 0), code = GET_CODE (op);
2242 if (letter == 'C')
2243 switch (code)
2245 case EQ:
2246 fputs ("eq", file);
2247 break;
2248 case NE:
2249 fputs ("ne", file);
2250 break;
2251 case GT:
2252 case GTU:
2253 fputs ("gt", file);
2254 break;
2255 case GE:
2256 case GEU:
2257 fputs ("ge", file);
2258 break;
2259 case LT:
2260 case LTU:
2261 fputs ("lt", file);
2262 break;
2263 case LE:
2264 case LEU:
2265 fputs ("le", file);
2266 break;
2267 default:
2268 fatal_insn ("PRINT_OPERAND, invalid insn for %%C", op);
2271 else if (letter == 'N')
2272 switch (code)
2274 case EQ:
2275 fputs ("ne", file);
2276 break;
2277 case NE:
2278 fputs ("eq", file);
2279 break;
2280 case GT:
2281 case GTU:
2282 fputs ("le", file);
2283 break;
2284 case GE:
2285 case GEU:
2286 fputs ("lt", file);
2287 break;
2288 case LT:
2289 case LTU:
2290 fputs ("ge", file);
2291 break;
2292 case LE:
2293 case LEU:
2294 fputs ("gt", file);
2295 break;
2296 default:
2297 fatal_insn ("PRINT_OPERAND, invalid insn for %%N", op);
2300 else if (letter == 'S')
2302 char buffer[100];
2304 ASM_GENERATE_INTERNAL_LABEL (buffer, "LS", CODE_LABEL_NUMBER (op));
2305 assemble_name (file, buffer);
2308 /* Print 'i' for memory operands which have immediate values. */
2309 else if (letter == 'i')
2311 if (code == MEM)
2313 struct microblaze_address_info info;
2315 if (!microblaze_classify_address
2316 (&info, XEXP (op, 0), GET_MODE (op), 1))
2317 fatal_insn ("insn contains an invalid address !", op);
2319 switch (info.type)
2321 case ADDRESS_REG:
2322 case ADDRESS_CONST_INT:
2323 case ADDRESS_SYMBOLIC:
2324 case ADDRESS_GOTOFF:
2325 case ADDRESS_TLS:
2326 fputs ("i", file);
2327 break;
2328 case ADDRESS_REG_INDEX:
2329 break;
2330 case ADDRESS_INVALID:
2331 case ADDRESS_PLT:
2332 fatal_insn ("invalid address", op);
2337 else if (code == REG || code == SUBREG)
2339 register int regnum;
2341 if (code == REG)
2342 regnum = REGNO (op);
2343 else
2344 regnum = true_regnum (op);
2346 if ((letter == 'M' && !WORDS_BIG_ENDIAN)
2347 || (letter == 'L' && WORDS_BIG_ENDIAN) || letter == 'D')
2348 regnum++;
2350 fprintf (file, "%s", reg_names[regnum]);
2353 else if (code == MEM)
2354 if (letter == 'o')
2356 rtx op4 = adjust_address (op, GET_MODE (op), 4);
2357 output_address (XEXP (op4, 0));
2359 else if (letter == 'y')
2361 rtx mem_reg = XEXP (op, 0);
2362 if (GET_CODE (mem_reg) == REG)
2364 register int regnum = REGNO (mem_reg);
2365 fprintf (file, "%s", reg_names[regnum]);
2368 else
2369 output_address (XEXP (op, 0));
2371 else if (letter == 'h' || letter == 'j')
2373 long val[2];
2374 if (code == CONST_DOUBLE)
2376 if (GET_MODE (op) == DFmode)
2378 REAL_VALUE_TYPE value;
2379 REAL_VALUE_FROM_CONST_DOUBLE (value, op);
2380 REAL_VALUE_TO_TARGET_DOUBLE (value, val);
2382 else
2384 val[0] = CONST_DOUBLE_HIGH (op);
2385 val[1] = CONST_DOUBLE_LOW (op);
2388 else if (code == CONST_INT)
2390 val[0] = (INTVAL (op) & 0xffffffff00000000LL) >> 32;
2391 val[1] = INTVAL (op) & 0x00000000ffffffffLL;
2392 if (val[0] == 0 && val[1] < 0)
2393 val[0] = -1;
2396 fprintf (file, "0x%8.8lx", (letter == 'h') ? val[0] : val[1]);
2398 else if (code == CONST_DOUBLE)
2400 if (letter == 'F')
2402 unsigned long value_long;
2403 REAL_VALUE_TYPE value;
2404 REAL_VALUE_FROM_CONST_DOUBLE (value, op);
2405 REAL_VALUE_TO_TARGET_SINGLE (value, value_long);
2406 fprintf (file, HOST_WIDE_INT_PRINT_HEX, value_long);
2408 else
2410 char s[60];
2411 real_to_decimal (s, CONST_DOUBLE_REAL_VALUE (op), sizeof (s), 0, 1);
2412 fputs (s, file);
2416 else if (code == UNSPEC)
2418 print_operand_address (file, op);
2421 else if (letter == 'x' && GET_CODE (op) == CONST_INT)
2422 fprintf (file, HOST_WIDE_INT_PRINT_HEX, 0xffff & INTVAL (op));
2424 else if (letter == 'X' && GET_CODE (op) == CONST_INT)
2425 fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (op));
2427 else if (letter == 'd' && GET_CODE (op) == CONST_INT)
2428 fprintf (file, HOST_WIDE_INT_PRINT_DEC, (INTVAL (op)));
2430 else if (letter == 'z' && GET_CODE (op) == CONST_INT && INTVAL (op) == 0)
2431 fputs (reg_names[GP_REG_FIRST], file);
2433 else if (letter == 's' && GET_CODE (op) == CONST_INT)
2434 if (INTVAL (op) < 0)
2435 fputs ("-1", file);
2436 else
2437 fputs ("0", file);
2439 else if (letter == 'd' || letter == 'x' || letter == 'X' || letter == 's')
2440 output_operand_lossage ("letter %c was found & insn was not CONST_INT", letter);
2442 else if (letter == 'B')
2443 fputs (code == EQ ? "z" : "n", file);
2444 else if (letter == 'b')
2445 fputs (code == EQ ? "n" : "z", file);
2446 else if (letter == 'T')
2447 fputs (code == EQ ? "f" : "t", file);
2448 else if (letter == 't')
2449 fputs (code == EQ ? "t" : "f", file);
2451 else if (code == CONST
2452 && ((GET_CODE (XEXP (op, 0)) == REG)
2453 || (GET_CODE (XEXP (op, 0)) == UNSPEC)))
2455 print_operand (file, XEXP (op, 0), letter);
2457 else if (code == CONST
2458 && (GET_CODE (XEXP (op, 0)) == PLUS)
2459 && (GET_CODE (XEXP (XEXP (op, 0), 0)) == REG)
2460 && (GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST))
2462 print_operand_address (file, XEXP (op, 0));
2464 else if (letter == 'm')
2465 fprintf (file, HOST_WIDE_INT_PRINT_DEC, (1L << INTVAL (op)));
2466 else
2467 output_addr_const (file, op);
2470 /* A C compound statement to output to stdio stream STREAM the
2471 assembler syntax for an instruction operand that is a memory
2472 reference whose address is ADDR. ADDR is an RTL expression.
2474 Possible address classifications and output formats are,
2476 ADDRESS_REG "%0, r0"
2478 ADDRESS_REG with non-zero "%0, <addr_const>"
2479 offset
2481 ADDRESS_REG_INDEX "rA, RB"
2482 (if rA is r0, rA and rB are swapped)
2484 ADDRESS_CONST_INT "r0, <addr_const>"
2486 ADDRESS_SYMBOLIC "rBase, <addr_const>"
2487 (rBase is a base register suitable for the
2488 symbol's type)
2491 void
2492 print_operand_address (FILE * file, rtx addr)
2494 struct microblaze_address_info info;
2495 enum microblaze_address_type type;
2496 if (!microblaze_classify_address (&info, addr, GET_MODE (addr), 1))
2497 fatal_insn ("insn contains an invalid address !", addr);
2499 type = info.type;
2500 switch (info.type)
2502 case ADDRESS_REG:
2503 fprintf (file, "%s,", reg_names[REGNO (info.regA)]);
2504 output_addr_const (file, info.offset);
2505 break;
2506 case ADDRESS_REG_INDEX:
2507 if (REGNO (info.regA) == 0)
2508 /* Make rB == r0 instead of rA == r0. This helps reduce read port
2509 congestion. */
2510 fprintf (file, "%s,%s", reg_names[REGNO (info.regB)],
2511 reg_names[REGNO (info.regA)]);
2512 else if (REGNO (info.regB) != 0)
2513 /* This is a silly swap to help Dhrystone. */
2514 fprintf (file, "%s,%s", reg_names[REGNO (info.regB)],
2515 reg_names[REGNO (info.regA)]);
2516 break;
2517 case ADDRESS_CONST_INT:
2518 fprintf (file, "%s,", reg_names[REGNO (info.regA)]);
2519 output_addr_const (file, info.offset);
2520 break;
2521 case ADDRESS_SYMBOLIC:
2522 case ADDRESS_GOTOFF:
2523 case ADDRESS_PLT:
2524 case ADDRESS_TLS:
2525 if (info.regA)
2526 fprintf (file, "%s,", reg_names[REGNO (info.regA)]);
2527 output_addr_const (file, info.symbol);
2528 if (type == ADDRESS_GOTOFF)
2530 fputs ("@GOT", file);
2532 else if (type == ADDRESS_PLT)
2534 fputs ("@PLT", file);
2536 else if (type == ADDRESS_TLS)
2538 switch (info.tls_type)
2540 case TLS_GD:
2541 fputs ("@TLSGD", file);
2542 break;
2543 case TLS_LDM:
2544 fputs ("@TLSLDM", file);
2545 break;
2546 case TLS_DTPREL:
2547 fputs ("@TLSDTPREL", file);
2548 break;
2549 default :
2550 abort();
2551 break;
2554 break;
2555 case ADDRESS_INVALID:
2556 fatal_insn ("invalid address", addr);
2557 break;
2561 /* Emit either a label, .comm, or .lcomm directive, and mark that the symbol
2562 is used, so that we don't emit an .extern for it in
2563 microblaze_asm_file_end. */
2565 void
2566 microblaze_declare_object (FILE * stream, const char *name,
2567 const char *section, const char *fmt, int size)
2570 fputs (section, stream);
2571 assemble_name (stream, name);
2572 fprintf (stream, fmt, size);
2575 /* Common code to emit the insns (or to write the instructions to a file)
2576 to save/restore registers.
2578 Other parts of the code assume that MICROBLAZE_TEMP1_REGNUM (aka large_reg)
2579 is not modified within save_restore_insns. */
2581 #define BITSET_P(VALUE,BIT) (((VALUE) & (1L << (BIT))) != 0)
2583 /* Save or restore instructions based on whether this is the prologue or
2584 epilogue. prologue is 1 for the prologue. */
2585 static void
2586 save_restore_insns (int prologue)
2588 rtx base_reg_rtx, reg_rtx, mem_rtx, /* msr_rtx, */ isr_reg_rtx =
2589 0, isr_mem_rtx = 0;
2590 rtx isr_msr_rtx = 0, insn;
2591 long mask = current_frame_info.mask;
2592 HOST_WIDE_INT gp_offset;
2593 int regno;
2595 if (frame_pointer_needed
2596 && !BITSET_P (mask, HARD_FRAME_POINTER_REGNUM - GP_REG_FIRST))
2597 gcc_unreachable ();
2599 if (mask == 0)
2600 return;
2602 /* Save registers starting from high to low. The debuggers prefer at least
2603 the return register be stored at func+4, and also it allows us not to
2604 need a nop in the epilog if at least one register is reloaded in
2605 addition to return address. */
2607 /* Pick which pointer to use as a base register. For small frames, just
2608 use the stack pointer. Otherwise, use a temporary register. Save 2
2609 cycles if the save area is near the end of a large frame, by reusing
2610 the constant created in the prologue/epilogue to adjust the stack
2611 frame. */
2613 gp_offset = current_frame_info.gp_offset;
2615 gcc_assert (gp_offset > 0);
2617 base_reg_rtx = stack_pointer_rtx;
2619 /* For interrupt_handlers, need to save/restore the MSR. */
2620 if (microblaze_is_interrupt_variant ())
2622 isr_mem_rtx = gen_rtx_MEM (SImode,
2623 gen_rtx_PLUS (Pmode, base_reg_rtx,
2624 GEN_INT (current_frame_info.
2625 gp_offset -
2626 UNITS_PER_WORD)));
2628 /* Do not optimize in flow analysis. */
2629 MEM_VOLATILE_P (isr_mem_rtx) = 1;
2630 isr_reg_rtx = gen_rtx_REG (SImode, MB_ABI_MSR_SAVE_REG);
2631 isr_msr_rtx = gen_rtx_REG (SImode, ST_REG);
2634 if (microblaze_is_interrupt_variant () && !prologue)
2636 emit_move_insn (isr_reg_rtx, isr_mem_rtx);
2637 emit_move_insn (isr_msr_rtx, isr_reg_rtx);
2638 /* Do not optimize in flow analysis. */
2639 emit_insn (gen_rtx_USE (SImode, isr_reg_rtx));
2640 emit_insn (gen_rtx_USE (SImode, isr_msr_rtx));
2643 for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
2645 if (BITSET_P (mask, regno - GP_REG_FIRST))
2647 if (regno == MB_ABI_SUB_RETURN_ADDR_REGNUM)
2648 /* Don't handle here. Already handled as the first register. */
2649 continue;
2651 reg_rtx = gen_rtx_REG (SImode, regno);
2652 insn = gen_rtx_PLUS (Pmode, base_reg_rtx, GEN_INT (gp_offset));
2653 mem_rtx = gen_rtx_MEM (SImode, insn);
2654 if (microblaze_is_interrupt_variant () || save_volatiles)
2655 /* Do not optimize in flow analysis. */
2656 MEM_VOLATILE_P (mem_rtx) = 1;
2658 if (prologue)
2660 insn = emit_move_insn (mem_rtx, reg_rtx);
2661 RTX_FRAME_RELATED_P (insn) = 1;
2663 else
2665 insn = emit_move_insn (reg_rtx, mem_rtx);
2668 gp_offset += GET_MODE_SIZE (SImode);
2672 if (microblaze_is_interrupt_variant () && prologue)
2674 emit_move_insn (isr_reg_rtx, isr_msr_rtx);
2675 emit_move_insn (isr_mem_rtx, isr_reg_rtx);
2677 /* Do not optimize in flow analysis. */
2678 emit_insn (gen_rtx_USE (SImode, isr_reg_rtx));
2679 emit_insn (gen_rtx_USE (SImode, isr_msr_rtx));
2682 /* Done saving and restoring */
2686 /* Set up the stack and frame (if desired) for the function. */
2687 static void
2688 microblaze_function_prologue (FILE * file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
2690 const char *fnname;
2691 long fsiz = current_frame_info.total_size;
2693 /* Get the function name the same way that toplev.c does before calling
2694 assemble_start_function. This is needed so that the name used here
2695 exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */
2696 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
2697 if (!flag_inhibit_size_directive)
2699 fputs ("\t.ent\t", file);
2700 if (interrupt_handler && strcmp (INTERRUPT_HANDLER_NAME, fnname))
2701 fputs ("_interrupt_handler", file);
2702 else if (break_handler && strcmp (BREAK_HANDLER_NAME, fnname))
2703 fputs ("_break_handler", file);
2704 else if (fast_interrupt && strcmp (FAST_INTERRUPT_NAME, fnname))
2705 fputs ("_fast_interrupt", file);
2706 else
2707 assemble_name (file, fnname);
2708 fputs ("\n", file);
2709 if (!microblaze_is_interrupt_variant ())
2710 ASM_OUTPUT_TYPE_DIRECTIVE (file, fnname, "function");
2713 assemble_name (file, fnname);
2714 fputs (":\n", file);
2716 if (interrupt_handler && strcmp (INTERRUPT_HANDLER_NAME, fnname))
2717 fputs ("_interrupt_handler:\n", file);
2718 if (break_handler && strcmp (BREAK_HANDLER_NAME, fnname))
2719 fputs ("_break_handler:\n", file);
2720 if (!flag_inhibit_size_directive)
2722 /* .frame FRAMEREG, FRAMESIZE, RETREG. */
2723 fprintf (file,
2724 "\t.frame\t%s,%ld,%s\t\t# vars= %ld, regs= %d, args= %d\n",
2725 (reg_names[(frame_pointer_needed)
2726 ? HARD_FRAME_POINTER_REGNUM :
2727 STACK_POINTER_REGNUM]), fsiz,
2728 reg_names[MB_ABI_SUB_RETURN_ADDR_REGNUM + GP_REG_FIRST],
2729 current_frame_info.var_size, current_frame_info.num_gp,
2730 crtl->outgoing_args_size);
2731 fprintf (file, "\t.mask\t0x%08lx\n", current_frame_info.mask);
2735 /* Output extra assembler code at the end of a prologue. */
2736 static void
2737 microblaze_function_end_prologue (FILE * file)
2739 if (TARGET_STACK_CHECK)
2741 fprintf (file, "\t# Stack Check Stub -- Start.\n\t");
2742 fprintf (file, "ori\tr18,r0,_stack_end\n\t");
2743 fprintf (file, "cmpu\tr18,r1,r18\n\t");
2744 fprintf (file, "bgei\tr18,_stack_overflow_exit\n\t");
2745 fprintf (file, "# Stack Check Stub -- End.\n");
2749 static void
2750 microblaze_elf_asm_cdtor (rtx symbol, int priority, bool is_ctor)
2752 section *s;
2754 if (priority != DEFAULT_INIT_PRIORITY)
2756 char buf[18];
2757 sprintf (buf, "%s.%.5u",
2758 is_ctor ? ".ctors" : ".dtors",
2759 MAX_INIT_PRIORITY - priority);
2760 s = get_section (buf, SECTION_WRITE, NULL_TREE);
2762 else if (is_ctor)
2763 s = ctors_section;
2764 else
2765 s = dtors_section;
2767 switch_to_section (s);
2768 assemble_align (POINTER_SIZE);
2769 fputs ("\t.word\t", asm_out_file);
2770 output_addr_const (asm_out_file, symbol);
2771 fputs ("\n", asm_out_file);
2774 /* Add a function to the list of static constructors. */
2776 static void
2777 microblaze_elf_asm_constructor (rtx symbol, int priority)
2779 microblaze_elf_asm_cdtor (symbol, priority, /*is_ctor=*/true);
2782 /* Add a function to the list of static destructors. */
2784 static void
2785 microblaze_elf_asm_destructor (rtx symbol, int priority)
2787 microblaze_elf_asm_cdtor (symbol, priority, /*is_ctor=*/false);
2790 /* Expand the prologue into a bunch of separate insns. */
2792 void
2793 microblaze_expand_prologue (void)
2795 int regno;
2796 HOST_WIDE_INT fsiz;
2797 const char *arg_name = 0;
2798 tree fndecl = current_function_decl;
2799 tree fntype = TREE_TYPE (fndecl);
2800 tree fnargs = DECL_ARGUMENTS (fndecl);
2801 rtx next_arg_reg;
2802 int i;
2803 tree next_arg;
2804 tree cur_arg;
2805 CUMULATIVE_ARGS args_so_far_v;
2806 cumulative_args_t args_so_far;
2807 rtx mem_rtx, reg_rtx;
2809 /* If struct value address is treated as the first argument, make it so. */
2810 if (aggregate_value_p (DECL_RESULT (fndecl), fntype)
2811 && !cfun->returns_pcc_struct)
2813 tree type = build_pointer_type (fntype);
2814 tree function_result_decl = build_decl (BUILTINS_LOCATION, PARM_DECL,
2815 NULL_TREE, type);
2817 DECL_ARG_TYPE (function_result_decl) = type;
2818 TREE_CHAIN (function_result_decl) = fnargs;
2819 fnargs = function_result_decl;
2822 /* Determine the last argument, and get its name. */
2824 INIT_CUMULATIVE_ARGS (args_so_far_v, fntype, NULL_RTX, 0, 0);
2825 args_so_far = pack_cumulative_args (&args_so_far_v);
2826 regno = GP_ARG_FIRST;
2828 for (cur_arg = fnargs; cur_arg != 0; cur_arg = next_arg)
2830 tree passed_type = DECL_ARG_TYPE (cur_arg);
2831 machine_mode passed_mode = TYPE_MODE (passed_type);
2832 rtx entry_parm;
2834 if (TREE_ADDRESSABLE (passed_type))
2836 passed_type = build_pointer_type (passed_type);
2837 passed_mode = Pmode;
2840 entry_parm = targetm.calls.function_arg (args_so_far, passed_mode,
2841 passed_type, true);
2843 if (entry_parm)
2845 int words;
2847 /* passed in a register, so will get homed automatically. */
2848 if (GET_MODE (entry_parm) == BLKmode)
2849 words = (int_size_in_bytes (passed_type) + 3) / 4;
2850 else
2851 words = (GET_MODE_SIZE (GET_MODE (entry_parm)) + 3) / 4;
2853 regno = REGNO (entry_parm) + words - 1;
2855 else
2857 regno = GP_ARG_LAST + 1;
2858 break;
2861 targetm.calls.function_arg_advance (args_so_far, passed_mode,
2862 passed_type, true);
2864 next_arg = TREE_CHAIN (cur_arg);
2865 if (next_arg == 0)
2867 if (DECL_NAME (cur_arg))
2868 arg_name = IDENTIFIER_POINTER (DECL_NAME (cur_arg));
2870 break;
2874 /* Split parallel insn into a sequence of insns. */
2876 next_arg_reg = targetm.calls.function_arg (args_so_far, VOIDmode,
2877 void_type_node, true);
2878 if (next_arg_reg != 0 && GET_CODE (next_arg_reg) == PARALLEL)
2880 rtvec adjust = XVEC (next_arg_reg, 0);
2881 int num = GET_NUM_ELEM (adjust);
2883 for (i = 0; i < num; i++)
2885 rtx pattern = RTVEC_ELT (adjust, i);
2886 emit_insn (pattern);
2890 fsiz = compute_frame_size (get_frame_size ());
2892 if (flag_stack_usage_info)
2893 current_function_static_stack_size = fsiz;
2896 /* If this function is a varargs function, store any registers that
2897 would normally hold arguments ($5 - $10) on the stack. */
2898 if (((TYPE_ARG_TYPES (fntype) != 0
2899 && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
2900 != void_type_node))
2901 || (arg_name != 0
2902 && ((arg_name[0] == '_'
2903 && strcmp (arg_name, "__builtin_va_alist") == 0)
2904 || (arg_name[0] == 'v'
2905 && strcmp (arg_name, "va_alist") == 0)))))
2907 int offset = (regno - GP_ARG_FIRST + 1) * UNITS_PER_WORD;
2908 rtx ptr = stack_pointer_rtx;
2910 /* If we are doing svr4-abi, sp has already been decremented by fsiz. */
2911 for (; regno <= GP_ARG_LAST; regno++)
2913 if (offset != 0)
2914 ptr = gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (offset));
2915 emit_move_insn (gen_rtx_MEM (SImode, ptr),
2916 gen_rtx_REG (SImode, regno));
2918 offset += GET_MODE_SIZE (SImode);
2923 if (fsiz > 0)
2925 rtx fsiz_rtx = GEN_INT (fsiz);
2927 rtx_insn *insn = NULL;
2928 insn = emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx,
2929 fsiz_rtx));
2930 if (insn)
2931 RTX_FRAME_RELATED_P (insn) = 1;
2933 /* Handle SUB_RETURN_ADDR_REGNUM specially at first. */
2934 if (!crtl->is_leaf || interrupt_handler)
2936 mem_rtx = gen_rtx_MEM (SImode,
2937 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
2938 const0_rtx));
2940 if (interrupt_handler)
2941 /* Do not optimize in flow analysis. */
2942 MEM_VOLATILE_P (mem_rtx) = 1;
2944 reg_rtx = gen_rtx_REG (SImode, MB_ABI_SUB_RETURN_ADDR_REGNUM);
2945 insn = emit_move_insn (mem_rtx, reg_rtx);
2946 RTX_FRAME_RELATED_P (insn) = 1;
2949 /* _save_ registers for prologue. */
2950 save_restore_insns (1);
2952 if (frame_pointer_needed)
2954 rtx_insn *insn = 0;
2956 insn = emit_insn (gen_movsi (hard_frame_pointer_rtx,
2957 stack_pointer_rtx));
2959 if (insn)
2960 RTX_FRAME_RELATED_P (insn) = 1;
2964 if ((flag_pic == 2 || TLS_NEEDS_GOT )
2965 && df_regs_ever_live_p (MB_ABI_PIC_ADDR_REGNUM))
2967 SET_REGNO (pic_offset_table_rtx, MB_ABI_PIC_ADDR_REGNUM);
2968 emit_insn (gen_set_got (pic_offset_table_rtx)); /* setting GOT. */
2971 /* If we are profiling, make sure no instructions are scheduled before
2972 the call to mcount. */
2974 if (profile_flag)
2975 emit_insn (gen_blockage ());
2978 /* Do necessary cleanup after a function to restore stack, frame, and regs. */
2980 #define RA_MASK ((long) 0x80000000) /* 1 << 31 */
2981 #define PIC_OFFSET_TABLE_MASK (1 << (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST))
2983 static void
2984 microblaze_function_epilogue (FILE * file ATTRIBUTE_UNUSED,
2985 HOST_WIDE_INT size ATTRIBUTE_UNUSED)
2987 const char *fnname;
2989 /* Get the function name the same way that toplev.c does before calling
2990 assemble_start_function. This is needed so that the name used here
2991 exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */
2992 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
2994 if (!flag_inhibit_size_directive)
2996 fputs ("\t.end\t", file);
2997 if (interrupt_handler && !break_handler)
2998 fputs ("_interrupt_handler", file);
2999 else if (break_handler)
3000 fputs ("_break_handler", file);
3001 else
3002 assemble_name (file, fnname);
3003 fputs ("\n", file);
3006 /* Reset state info for each function. */
3007 current_frame_info = zero_frame_info;
3009 /* Restore the output file if optimizing the GP (optimizing the GP causes
3010 the text to be diverted to a tempfile, so that data decls come before
3011 references to the data). */
3014 /* Expand the epilogue into a bunch of separate insns. */
3016 void
3017 microblaze_expand_epilogue (void)
3019 HOST_WIDE_INT fsiz = current_frame_info.total_size;
3020 rtx fsiz_rtx = GEN_INT (fsiz);
3021 rtx reg_rtx;
3022 rtx mem_rtx;
3024 /* In case of interrupt handlers use addki instead of addi for changing the
3025 stack pointer value. */
3027 if (microblaze_can_use_return_insn ())
3029 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode,
3030 GP_REG_FIRST +
3031 MB_ABI_SUB_RETURN_ADDR_REGNUM)));
3032 return;
3035 if (fsiz > 0)
3037 /* Restore SUB_RETURN_ADDR_REGNUM at first. This is to prevent the
3038 sequence of load-followed by a use (in rtsd) in every prologue. Saves
3039 a load-use stall cycle :) This is also important to handle alloca.
3040 (See comments for if (frame_pointer_needed) below. */
3042 if (!crtl->is_leaf || interrupt_handler)
3044 mem_rtx =
3045 gen_rtx_MEM (SImode,
3046 gen_rtx_PLUS (Pmode, stack_pointer_rtx, const0_rtx));
3047 if (interrupt_handler)
3048 /* Do not optimize in flow analysis. */
3049 MEM_VOLATILE_P (mem_rtx) = 1;
3050 reg_rtx = gen_rtx_REG (SImode, MB_ABI_SUB_RETURN_ADDR_REGNUM);
3051 emit_move_insn (reg_rtx, mem_rtx);
3054 /* It is important that this is done after we restore the return address
3055 register (above). When alloca is used, we want to restore the
3056 sub-routine return address only from the current stack top and not
3057 from the frame pointer (which we restore below). (frame_pointer + 0)
3058 might have been over-written since alloca allocates memory on the
3059 current stack. */
3060 if (frame_pointer_needed)
3061 emit_insn (gen_movsi (stack_pointer_rtx, hard_frame_pointer_rtx));
3063 /* _restore_ registers for epilogue. */
3064 save_restore_insns (0);
3065 emit_insn (gen_blockage ());
3066 emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, fsiz_rtx));
3069 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode, GP_REG_FIRST +
3070 MB_ABI_SUB_RETURN_ADDR_REGNUM)));
3074 /* Return nonzero if this function is known to have a null epilogue.
3075 This allows the optimizer to omit jumps to jumps if no stack
3076 was created. */
3079 microblaze_can_use_return_insn (void)
3081 if (!reload_completed)
3082 return 0;
3084 if (df_regs_ever_live_p (MB_ABI_SUB_RETURN_ADDR_REGNUM) || profile_flag)
3085 return 0;
3087 if (current_frame_info.initialized)
3088 return current_frame_info.total_size == 0;
3090 return compute_frame_size (get_frame_size ()) == 0;
3093 /* Implement TARGET_SECONDARY_RELOAD. */
3095 static reg_class_t
3096 microblaze_secondary_reload (bool in_p ATTRIBUTE_UNUSED, rtx x ATTRIBUTE_UNUSED,
3097 reg_class_t rclass, machine_mode mode ATTRIBUTE_UNUSED,
3098 secondary_reload_info *sri ATTRIBUTE_UNUSED)
3100 if (rclass == ST_REGS)
3101 return GR_REGS;
3103 return NO_REGS;
3106 static void
3107 microblaze_globalize_label (FILE * stream, const char *name)
3109 fputs ("\t.globl\t", stream);
3110 if (microblaze_is_interrupt_variant ())
3112 if (interrupt_handler && strcmp (name, INTERRUPT_HANDLER_NAME))
3113 fputs (INTERRUPT_HANDLER_NAME, stream);
3114 else if (break_handler && strcmp (name, BREAK_HANDLER_NAME))
3115 fputs (BREAK_HANDLER_NAME, stream);
3116 else if (fast_interrupt && strcmp (name, FAST_INTERRUPT_NAME))
3117 fputs (FAST_INTERRUPT_NAME, stream);
3118 fputs ("\n\t.globl\t", stream);
3120 assemble_name (stream, name);
3121 fputs ("\n", stream);
3124 /* Returns true if decl should be placed into a "small data" section. */
3125 static bool
3126 microblaze_elf_in_small_data_p (const_tree decl)
3128 HOST_WIDE_INT size;
3130 if (!TARGET_XLGPOPT)
3131 return false;
3133 /* We want to merge strings, so we never consider them small data. */
3134 if (TREE_CODE (decl) == STRING_CST)
3135 return false;
3137 /* Functions are never in the small data area. */
3138 if (TREE_CODE (decl) == FUNCTION_DECL)
3139 return false;
3141 if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl))
3143 const char *section = DECL_SECTION_NAME (decl);
3144 if (strcmp (section, ".sdata") == 0
3145 || strcmp (section, ".sdata2") == 0
3146 || strcmp (section, ".sbss") == 0
3147 || strcmp (section, ".sbss2") == 0)
3148 return true;
3151 size = int_size_in_bytes (TREE_TYPE (decl));
3153 return (size > 0 && size <= microblaze_section_threshold);
3157 static section *
3158 microblaze_select_section (tree decl, int reloc, unsigned HOST_WIDE_INT align)
3160 switch (categorize_decl_for_section (decl, reloc))
3162 case SECCAT_RODATA_MERGE_STR:
3163 case SECCAT_RODATA_MERGE_STR_INIT:
3164 /* MB binutils have various issues with mergeable string sections and
3165 relaxation/relocation. Currently, turning mergeable sections
3166 into regular readonly sections. */
3168 return readonly_data_section;
3169 default:
3170 return default_elf_select_section (decl, reloc, align);
3175 Encode info about sections into the RTL based on a symbol's declaration.
3176 The default definition of this hook, default_encode_section_info in
3177 `varasm.c', sets a number of commonly-useful bits in SYMBOL_REF_FLAGS. */
3179 static void
3180 microblaze_encode_section_info (tree decl, rtx rtl, int first)
3182 default_encode_section_info (decl, rtl, first);
3185 static rtx
3186 expand_pic_symbol_ref (machine_mode mode ATTRIBUTE_UNUSED, rtx op)
3188 rtx result;
3189 result = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op), UNSPEC_GOTOFF);
3190 result = gen_rtx_CONST (Pmode, result);
3191 result = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, result);
3192 result = gen_const_mem (Pmode, result);
3193 return result;
3196 static void
3197 microblaze_asm_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
3198 HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
3199 tree function)
3201 rtx this_rtx, funexp;
3202 rtx_insn *insn;
3204 reload_completed = 1;
3205 epilogue_completed = 1;
3207 /* Mark the end of the (empty) prologue. */
3208 emit_note (NOTE_INSN_PROLOGUE_END);
3210 /* Find the "this" pointer. If the function returns a structure,
3211 the structure return pointer is in MB_ABI_FIRST_ARG_REGNUM. */
3212 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
3213 this_rtx = gen_rtx_REG (Pmode, (MB_ABI_FIRST_ARG_REGNUM + 1));
3214 else
3215 this_rtx = gen_rtx_REG (Pmode, MB_ABI_FIRST_ARG_REGNUM);
3217 /* Apply the constant offset, if required. */
3218 if (delta)
3219 emit_insn (gen_addsi3 (this_rtx, this_rtx, GEN_INT (delta)));
3221 /* Apply the offset from the vtable, if required. */
3222 if (vcall_offset)
3224 rtx vcall_offset_rtx = GEN_INT (vcall_offset);
3225 rtx temp1 = gen_rtx_REG (Pmode, MB_ABI_TEMP1_REGNUM);
3227 emit_move_insn (temp1, gen_rtx_MEM (Pmode, this_rtx));
3229 rtx loc = gen_rtx_PLUS (Pmode, temp1, vcall_offset_rtx);
3230 emit_move_insn (temp1, gen_rtx_MEM (Pmode, loc));
3232 emit_insn (gen_addsi3 (this_rtx, this_rtx, temp1));
3235 /* Generate a tail call to the target function. */
3236 if (!TREE_USED (function))
3238 assemble_external (function);
3239 TREE_USED (function) = 1;
3242 funexp = XEXP (DECL_RTL (function), 0);
3243 rtx temp2 = gen_rtx_REG (Pmode, MB_ABI_TEMP2_REGNUM);
3245 if (flag_pic)
3246 emit_move_insn (temp2, expand_pic_symbol_ref (Pmode, funexp));
3247 else
3248 emit_move_insn (temp2, funexp);
3250 emit_insn (gen_indirect_jump (temp2));
3252 /* Run just enough of rest_of_compilation. This sequence was
3253 "borrowed" from rs6000.c. */
3254 insn = get_insns ();
3255 shorten_branches (insn);
3256 final_start_function (insn, file, 1);
3257 final (insn, file, 1);
3258 final_end_function ();
3260 reload_completed = 0;
3261 epilogue_completed = 0;
3264 bool
3265 microblaze_expand_move (machine_mode mode, rtx operands[])
3267 rtx op0, op1;
3269 op0 = operands[0];
3270 op1 = operands[1];
3272 if (!register_operand (op0, SImode)
3273 && !register_operand (op1, SImode)
3274 && (GET_CODE (op1) != CONST_INT || INTVAL (op1) != 0))
3276 rtx temp = force_reg (SImode, op1);
3277 emit_move_insn (op0, temp);
3278 return true;
3280 /* If operands[1] is a constant address invalid for pic, then we need to
3281 handle it just like LEGITIMIZE_ADDRESS does. */
3282 if (GET_CODE (op1) == SYMBOL_REF || GET_CODE (op1) == LABEL_REF)
3284 rtx result;
3285 if (microblaze_tls_symbol_p(op1))
3287 result = microblaze_legitimize_tls_address (op1, NULL_RTX);
3288 emit_move_insn (op0, result);
3289 return true;
3291 else if (flag_pic)
3293 if (reload_in_progress)
3294 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
3295 result = expand_pic_symbol_ref (mode, op1);
3296 emit_move_insn (op0, result);
3297 return true;
3300 /* Handle Case of (const (plus symbol const_int)). */
3301 if (GET_CODE (op1) == CONST && GET_CODE (XEXP (op1,0)) == PLUS)
3303 rtx p0, p1;
3305 p0 = XEXP (XEXP (op1, 0), 0);
3306 p1 = XEXP (XEXP (op1, 0), 1);
3308 if ((GET_CODE (p1) == CONST_INT)
3309 && ((GET_CODE (p0) == UNSPEC)
3310 || ((GET_CODE (p0) == SYMBOL_REF || GET_CODE (p0) == LABEL_REF)
3311 && (flag_pic == 2 || microblaze_tls_symbol_p (p0)
3312 || !SMALL_INT (p1)))))
3314 rtx temp = force_reg (SImode, p0);
3315 rtx temp2 = p1;
3317 if (flag_pic && reload_in_progress)
3318 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
3319 emit_move_insn (op0, gen_rtx_PLUS (SImode, temp, temp2));
3320 return true;
3323 return false;
3326 /* Expand shift operations. */
3328 microblaze_expand_shift (rtx operands[])
3330 gcc_assert ((GET_CODE (operands[2]) == CONST_INT)
3331 || (GET_CODE (operands[2]) == REG)
3332 || (GET_CODE (operands[2]) == SUBREG));
3334 /* Shift by one -- generate pattern. */
3335 if ((GET_CODE (operands[2]) == CONST_INT) && (INTVAL (operands[2]) == 1))
3336 return 0;
3338 /* Have barrel shifter and shift > 1: use it. */
3339 if (TARGET_BARREL_SHIFT)
3340 return 0;
3342 gcc_assert ((GET_CODE (operands[0]) == REG)
3343 || (GET_CODE (operands[0]) == SUBREG)
3344 || (GET_CODE (operands[1]) == REG)
3345 || (GET_CODE (operands[1]) == SUBREG));
3347 /* Shift by zero -- copy regs if necessary. */
3348 if ((GET_CODE (operands[2]) == CONST_INT) && (INTVAL (operands[2]) == 0))
3350 if (REGNO (operands[0]) != REGNO (operands[1]))
3351 emit_insn (gen_movsi (operands[0], operands[1]));
3352 return 1;
3355 return 0;
3358 /* Return an RTX indicating where the return address to the
3359 calling function can be found. */
3361 microblaze_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
3363 if (count != 0)
3364 return NULL_RTX;
3366 return gen_rtx_PLUS (Pmode,
3367 get_hard_reg_initial_val (Pmode,
3368 MB_ABI_SUB_RETURN_ADDR_REGNUM),
3369 GEN_INT (8));
3372 /* Queue an .ident string in the queue of top-level asm statements.
3373 If the string size is below the threshold, put it into .sdata2.
3374 If the front-end is done, we must be being called from toplev.c.
3375 In that case, do nothing. */
3376 void
3377 microblaze_asm_output_ident (const char *string)
3379 const char *section_asm_op;
3380 int size;
3381 char *buf;
3383 if (symtab->state != PARSING)
3384 return;
3386 size = strlen (string) + 1;
3387 if (size <= microblaze_section_threshold)
3388 section_asm_op = SDATA2_SECTION_ASM_OP;
3389 else
3390 section_asm_op = READONLY_DATA_SECTION_ASM_OP;
3392 buf = ACONCAT ((section_asm_op, "\n\t.ascii \"", string, "\\0\"\n", NULL));
3393 symtab->finalize_toplevel_asm (build_string (strlen (buf), buf));
3396 static void
3397 microblaze_elf_asm_init_sections (void)
3399 sdata2_section
3400 = get_unnamed_section (SECTION_WRITE, output_section_asm_op,
3401 SDATA2_SECTION_ASM_OP);
3404 /* Generate assembler code for constant parts of a trampoline. */
3406 static void
3407 microblaze_asm_trampoline_template (FILE *f)
3409 fprintf (f, "\tmfs r18, rpc\n");
3410 fprintf (f, "\tlwi r3, r18, 16\n");
3411 fprintf (f, "\tlwi r18, r18, 20\n");
3412 fprintf (f, "\tbra r18\n");
3413 /* fprintf (f, "\t.word\t0x00000000\t\t# <function address>\n"); */
3414 /* fprintf (f, "\t.word\t0x00000000\t\t# <static chain value>\n"); */
3417 /* Implement TARGET_TRAMPOLINE_INIT. */
3419 static void
3420 microblaze_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
3422 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
3423 rtx mem;
3425 emit_block_move (m_tramp, assemble_trampoline_template (),
3426 GEN_INT (6*UNITS_PER_WORD), BLOCK_OP_NORMAL);
3428 mem = adjust_address (m_tramp, SImode, 16);
3429 emit_move_insn (mem, chain_value);
3430 mem = adjust_address (m_tramp, SImode, 20);
3431 emit_move_insn (mem, fnaddr);
3434 /* Generate conditional branch -- first, generate test condition,
3435 second, generate correct branch instruction. */
3437 void
3438 microblaze_expand_conditional_branch (machine_mode mode, rtx operands[])
3440 enum rtx_code code = GET_CODE (operands[0]);
3441 rtx cmp_op0 = operands[1];
3442 rtx cmp_op1 = operands[2];
3443 rtx label1 = operands[3];
3444 rtx comp_reg = gen_reg_rtx (SImode);
3445 rtx condition;
3447 gcc_assert ((GET_CODE (cmp_op0) == REG) || (GET_CODE (cmp_op0) == SUBREG));
3449 /* If comparing against zero, just test source reg. */
3450 if (cmp_op1 == const0_rtx)
3452 comp_reg = cmp_op0;
3453 condition = gen_rtx_fmt_ee (signed_condition (code), SImode, comp_reg, const0_rtx);
3454 emit_jump_insn (gen_condjump (condition, label1));
3457 else if (code == EQ || code == NE)
3459 /* Use xor for equal/not-equal comparison. */
3460 emit_insn (gen_xorsi3 (comp_reg, cmp_op0, cmp_op1));
3461 condition = gen_rtx_fmt_ee (signed_condition (code), SImode, comp_reg, const0_rtx);
3462 emit_jump_insn (gen_condjump (condition, label1));
3464 else
3466 /* Generate compare and branch in single instruction. */
3467 cmp_op1 = force_reg (mode, cmp_op1);
3468 condition = gen_rtx_fmt_ee (code, mode, cmp_op0, cmp_op1);
3469 emit_jump_insn (gen_branch_compare(condition, cmp_op0, cmp_op1, label1));
3473 void
3474 microblaze_expand_conditional_branch_reg (enum machine_mode mode,
3475 rtx operands[])
3477 enum rtx_code code = GET_CODE (operands[0]);
3478 rtx cmp_op0 = operands[1];
3479 rtx cmp_op1 = operands[2];
3480 rtx label1 = operands[3];
3481 rtx comp_reg = gen_reg_rtx (SImode);
3482 rtx condition;
3484 gcc_assert ((GET_CODE (cmp_op0) == REG)
3485 || (GET_CODE (cmp_op0) == SUBREG));
3487 /* If comparing against zero, just test source reg. */
3488 if (cmp_op1 == const0_rtx)
3490 comp_reg = cmp_op0;
3491 condition = gen_rtx_fmt_ee (signed_condition (code),
3492 SImode, comp_reg, const0_rtx);
3493 emit_jump_insn (gen_condjump (condition, label1));
3495 else if (code == EQ)
3497 emit_insn (gen_seq_internal_pat (comp_reg,
3498 cmp_op0, cmp_op1));
3499 condition = gen_rtx_EQ (SImode, comp_reg, const0_rtx);
3500 emit_jump_insn (gen_condjump (condition, label1));
3502 else if (code == NE)
3504 emit_insn (gen_sne_internal_pat (comp_reg, cmp_op0,
3505 cmp_op1));
3506 condition = gen_rtx_NE (SImode, comp_reg, const0_rtx);
3507 emit_jump_insn (gen_condjump (condition, label1));
3509 else
3511 /* Generate compare and branch in single instruction. */
3512 cmp_op1 = force_reg (mode, cmp_op1);
3513 condition = gen_rtx_fmt_ee (code, mode, cmp_op0, cmp_op1);
3514 emit_jump_insn (gen_branch_compare (condition, cmp_op0,
3515 cmp_op1, label1));
3519 void
3520 microblaze_expand_conditional_branch_sf (rtx operands[])
3522 rtx condition;
3523 rtx cmp_op0 = XEXP (operands[0], 0);
3524 rtx cmp_op1 = XEXP (operands[0], 1);
3525 rtx comp_reg = gen_reg_rtx (SImode);
3527 emit_insn (gen_cstoresf4 (comp_reg, operands[0], cmp_op0, cmp_op1));
3528 condition = gen_rtx_NE (SImode, comp_reg, const0_rtx);
3529 emit_jump_insn (gen_condjump (condition, operands[3]));
3532 /* Implement TARGET_FRAME_POINTER_REQUIRED. */
3534 static bool
3535 microblaze_frame_pointer_required (void)
3537 /* If the function contains dynamic stack allocations, we need to
3538 use the frame pointer to access the static parts of the frame. */
3539 if (cfun->calls_alloca)
3540 return true;
3541 return false;
3544 void
3545 microblaze_expand_divide (rtx operands[])
3547 /* Table lookup software divides. Works for all (nr/dr) where (0 <= nr,dr <= 15). */
3549 rtx regt1 = gen_reg_rtx (SImode);
3550 rtx reg18 = gen_rtx_REG (SImode, R_TMP);
3551 rtx regqi = gen_reg_rtx (QImode);
3552 rtx_code_label *div_label = gen_label_rtx ();
3553 rtx_code_label *div_end_label = gen_label_rtx ();
3554 rtx div_table_rtx = gen_rtx_SYMBOL_REF (QImode,"_divsi3_table");
3555 rtx mem_rtx;
3556 rtx ret;
3557 rtx_insn *jump, *cjump, *insn;
3559 insn = emit_insn (gen_iorsi3 (regt1, operands[1], operands[2]));
3560 cjump = emit_jump_insn_after (gen_cbranchsi4 (
3561 gen_rtx_GTU (SImode, regt1, GEN_INT (15)),
3562 regt1, GEN_INT (15), div_label), insn);
3563 LABEL_NUSES (div_label) = 1;
3564 JUMP_LABEL (cjump) = div_label;
3565 emit_insn (gen_rtx_CLOBBER (SImode, reg18));
3567 emit_insn (gen_ashlsi3_bshift (regt1, operands[1], GEN_INT(4)));
3568 emit_insn (gen_addsi3 (regt1, regt1, operands[2]));
3569 mem_rtx = gen_rtx_MEM (QImode,
3570 gen_rtx_PLUS (Pmode, regt1, div_table_rtx));
3572 insn = emit_insn (gen_movqi (regqi, mem_rtx));
3573 insn = emit_insn (gen_movsi (operands[0], gen_rtx_SUBREG (SImode, regqi, 0)));
3574 jump = emit_jump_insn_after (gen_jump (div_end_label), insn);
3575 JUMP_LABEL (jump) = div_end_label;
3576 LABEL_NUSES (div_end_label) = 1;
3577 emit_barrier ();
3579 emit_label (div_label);
3580 ret = emit_library_call_value (gen_rtx_SYMBOL_REF (Pmode, "__divsi3"),
3581 operands[0], LCT_NORMAL,
3582 GET_MODE (operands[0]), 2, operands[1],
3583 GET_MODE (operands[1]), operands[2],
3584 GET_MODE (operands[2]));
3585 if (ret != operands[0])
3586 emit_move_insn (operands[0], ret);
3588 emit_label (div_end_label);
3589 emit_insn (gen_blockage ());
3592 /* Implement TARGET_FUNCTION_VALUE. */
3593 static rtx
3594 microblaze_function_value (const_tree valtype,
3595 const_tree func ATTRIBUTE_UNUSED,
3596 bool outgoing ATTRIBUTE_UNUSED)
3598 return LIBCALL_VALUE (TYPE_MODE (valtype));
3601 /* Implement TARGET_SCHED_ADJUST_COST. */
3602 static int
3603 microblaze_adjust_cost (rtx_insn *insn ATTRIBUTE_UNUSED, rtx link,
3604 rtx_insn *dep ATTRIBUTE_UNUSED, int cost)
3606 if (REG_NOTE_KIND (link) == REG_DEP_OUTPUT)
3607 return cost;
3608 if (REG_NOTE_KIND (link) != 0)
3609 return 0;
3610 return cost;
3613 /* Implement TARGET_LEGITIMATE_CONSTANT_P.
3615 At present, GAS doesn't understand li.[sd], so don't allow it
3616 to be generated at present. */
3617 static bool
3618 microblaze_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED, rtx x)
3621 if (microblaze_cannot_force_const_mem(mode, x))
3622 return false;
3624 if (GET_CODE (x) == CONST_DOUBLE)
3626 return microblaze_const_double_ok (x, GET_MODE (x));
3629 /* Handle Case of (const (plus unspec const_int)). */
3630 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x,0)) == PLUS)
3632 rtx p0, p1;
3634 p0 = XEXP (XEXP (x, 0), 0);
3635 p1 = XEXP (XEXP (x, 0), 1);
3637 if (GET_CODE(p1) == CONST_INT)
3639 /* Const offset from UNSPEC is not supported. */
3640 if ((GET_CODE (p0) == UNSPEC))
3641 return false;
3643 if ((GET_CODE (p0) == SYMBOL_REF || GET_CODE (p0) == LABEL_REF)
3644 && (microblaze_tls_symbol_p (p0) || !SMALL_INT (p1)))
3645 return false;
3649 return true;
3653 #undef TARGET_ENCODE_SECTION_INFO
3654 #define TARGET_ENCODE_SECTION_INFO microblaze_encode_section_info
3656 #undef TARGET_ASM_GLOBALIZE_LABEL
3657 #define TARGET_ASM_GLOBALIZE_LABEL microblaze_globalize_label
3659 #undef TARGET_ASM_FUNCTION_PROLOGUE
3660 #define TARGET_ASM_FUNCTION_PROLOGUE microblaze_function_prologue
3662 #undef TARGET_ASM_FUNCTION_EPILOGUE
3663 #define TARGET_ASM_FUNCTION_EPILOGUE microblaze_function_epilogue
3665 #undef TARGET_RTX_COSTS
3666 #define TARGET_RTX_COSTS microblaze_rtx_costs
3668 #undef TARGET_CANNOT_FORCE_CONST_MEM
3669 #define TARGET_CANNOT_FORCE_CONST_MEM microblaze_cannot_force_const_mem
3671 #undef TARGET_ADDRESS_COST
3672 #define TARGET_ADDRESS_COST microblaze_address_cost
3674 #undef TARGET_ATTRIBUTE_TABLE
3675 #define TARGET_ATTRIBUTE_TABLE microblaze_attribute_table
3677 #undef TARGET_IN_SMALL_DATA_P
3678 #define TARGET_IN_SMALL_DATA_P microblaze_elf_in_small_data_p
3680 #undef TARGET_ASM_SELECT_SECTION
3681 #define TARGET_ASM_SELECT_SECTION microblaze_select_section
3683 #undef TARGET_HAVE_SRODATA_SECTION
3684 #define TARGET_HAVE_SRODATA_SECTION true
3686 #undef TARGET_ASM_FUNCTION_END_PROLOGUE
3687 #define TARGET_ASM_FUNCTION_END_PROLOGUE \
3688 microblaze_function_end_prologue
3690 #undef TARGET_ARG_PARTIAL_BYTES
3691 #define TARGET_ARG_PARTIAL_BYTES function_arg_partial_bytes
3693 #undef TARGET_FUNCTION_ARG
3694 #define TARGET_FUNCTION_ARG microblaze_function_arg
3696 #undef TARGET_FUNCTION_ARG_ADVANCE
3697 #define TARGET_FUNCTION_ARG_ADVANCE microblaze_function_arg_advance
3699 #undef TARGET_CAN_ELIMINATE
3700 #define TARGET_CAN_ELIMINATE microblaze_can_eliminate
3702 #undef TARGET_LEGITIMIZE_ADDRESS
3703 #define TARGET_LEGITIMIZE_ADDRESS microblaze_legitimize_address
3705 #undef TARGET_LEGITIMATE_ADDRESS_P
3706 #define TARGET_LEGITIMATE_ADDRESS_P microblaze_legitimate_address_p
3708 #undef TARGET_FRAME_POINTER_REQUIRED
3709 #define TARGET_FRAME_POINTER_REQUIRED microblaze_frame_pointer_required
3711 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
3712 #define TARGET_ASM_TRAMPOLINE_TEMPLATE microblaze_asm_trampoline_template
3714 #undef TARGET_TRAMPOLINE_INIT
3715 #define TARGET_TRAMPOLINE_INIT microblaze_trampoline_init
3717 #undef TARGET_PROMOTE_FUNCTION_MODE
3718 #define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
3720 #undef TARGET_FUNCTION_VALUE
3721 #define TARGET_FUNCTION_VALUE microblaze_function_value
3723 #undef TARGET_SECONDARY_RELOAD
3724 #define TARGET_SECONDARY_RELOAD microblaze_secondary_reload
3726 #undef TARGET_ASM_OUTPUT_MI_THUNK
3727 #define TARGET_ASM_OUTPUT_MI_THUNK microblaze_asm_output_mi_thunk
3729 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
3730 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true
3732 #undef TARGET_SCHED_ADJUST_COST
3733 #define TARGET_SCHED_ADJUST_COST microblaze_adjust_cost
3735 #undef TARGET_ASM_INIT_SECTIONS
3736 #define TARGET_ASM_INIT_SECTIONS microblaze_elf_asm_init_sections
3738 #undef TARGET_OPTION_OVERRIDE
3739 #define TARGET_OPTION_OVERRIDE microblaze_option_override
3741 #undef TARGET_LEGITIMATE_CONSTANT_P
3742 #define TARGET_LEGITIMATE_CONSTANT_P microblaze_legitimate_constant_p
3744 struct gcc_target targetm = TARGET_INITIALIZER;
3746 #include "gt-microblaze.h"