[PATCH] Fix building microblaze targets with trunk
[official-gcc.git] / gcc / config / microblaze / microblaze.c
blobebcf65a371d2aa0db5bf41c264eb478263d7401d
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 "backend.h"
26 #include "cfghooks.h"
27 #include "tree.h"
28 #include "rtl.h"
29 #include "df.h"
30 #include "regs.h"
31 #include "insn-config.h"
32 #include "conditions.h"
33 #include "insn-flags.h"
34 #include "insn-attr.h"
35 #include "recog.h"
36 #include "alias.h"
37 #include "varasm.h"
38 #include "stor-layout.h"
39 #include "calls.h"
40 #include "flags.h"
41 #include "expmed.h"
42 #include "dojump.h"
43 #include "explow.h"
44 #include "emit-rtl.h"
45 #include "stmt.h"
46 #include "expr.h"
47 #include "reload.h"
48 #include "output.h"
49 #include "target.h"
50 #include "tm_p.h"
51 #include "gstab.h"
52 #include "cfgrtl.h"
53 #include "cfganal.h"
54 #include "lcm.h"
55 #include "cfgbuild.h"
56 #include "cfgcleanup.h"
57 #include "insn-codes.h"
58 #include "optabs.h"
59 #include "diagnostic-core.h"
60 #include "cgraph.h"
61 #include "builtins.h"
62 #include "rtl-iter.h"
64 /* This file should be included last. */
65 #include "target-def.h"
67 #define MICROBLAZE_VERSION_COMPARE(VA,VB) strcasecmp (VA, VB)
69 /* Classifies an address.
71 ADDRESS_INVALID
72 An invalid address.
74 ADDRESS_REG
76 A natural register or a register + const_int offset address.
77 The register satisfies microblaze_valid_base_register_p and the
78 offset is a const_arith_operand.
80 ADDRESS_REG_INDEX
82 A natural register offset by the index contained in an index register. The base
83 register satisfies microblaze_valid_base_register_p and the index register
84 satisfies microblaze_valid_index_register_p
86 ADDRESS_CONST_INT
88 A signed 16/32-bit constant address.
90 ADDRESS_SYMBOLIC:
92 A constant symbolic address or a (register + symbol). */
94 enum microblaze_address_type
96 ADDRESS_INVALID,
97 ADDRESS_REG,
98 ADDRESS_REG_INDEX,
99 ADDRESS_CONST_INT,
100 ADDRESS_SYMBOLIC,
101 ADDRESS_GOTOFF,
102 ADDRESS_PLT,
103 ADDRESS_TLS
106 /* Classifies symbols
108 SYMBOL_TYPE_GENERAL
110 A general symbol. */
111 enum microblaze_symbol_type
113 SYMBOL_TYPE_INVALID,
114 SYMBOL_TYPE_GENERAL
117 /* TLS Address Type. */
118 enum tls_reloc {
119 TLS_GD,
120 TLS_LDM,
121 TLS_DTPREL,
122 TLS_IE,
123 TLS_LE
126 /* Classification of a MicroBlaze address. */
127 struct microblaze_address_info
129 enum microblaze_address_type type;
130 rtx regA; /* Contains valid values on ADDRESS_REG, ADDRESS_REG_INDEX,
131 ADDRESS_SYMBOLIC. */
132 rtx regB; /* Contains valid values on ADDRESS_REG_INDEX. */
133 rtx offset; /* Contains valid values on ADDRESS_CONST_INT and ADDRESS_REG. */
134 rtx symbol; /* Contains valid values on ADDRESS_SYMBOLIC. */
135 enum microblaze_symbol_type symbol_type;
136 enum tls_reloc tls_type;
139 /* Structure to be filled in by compute_frame_size with register
140 save masks, and offsets for the current function. */
142 struct GTY(()) microblaze_frame_info {
143 long total_size; /* # bytes that the entire frame takes up. */
144 long var_size; /* # bytes that variables take up. */
145 long args_size; /* # bytes that outgoing arguments take up. */
146 int link_debug_size; /* # bytes for the link reg and back pointer. */
147 int gp_reg_size; /* # bytes needed to store gp regs. */
148 long gp_offset; /* offset from new sp to store gp registers. */
149 long mask; /* mask of saved gp registers. */
150 int initialized; /* != 0 if frame size already calculated. */
151 int num_gp; /* number of gp registers saved. */
152 long insns_len; /* length of insns. */
153 int alloc_stack; /* Flag to indicate if the current function
154 must not create stack space. (As an optimization). */
157 /* Global variables for machine-dependent things. */
159 /* Toggle which pipleline interface to use. */
160 static GTY(()) int microblaze_sched_use_dfa = 0;
162 /* Threshold for data being put into the small data/bss area, instead
163 of the normal data area (references to the small data/bss area take
164 1 instruction, and use the global pointer, references to the normal
165 data area takes 2 instructions). */
166 int microblaze_section_threshold = -1;
168 /* Prevent scheduling potentially exception causing instructions in
169 delay slots. -mcpu=v3.00.a or v4.00.a turns this on. */
170 int microblaze_no_unsafe_delay;
172 /* Set to one if the targeted core has the CLZ insn. */
173 int microblaze_has_clz = 0;
175 /* Which CPU pipeline do we use. We haven't really standardized on a CPU
176 version having only a particular type of pipeline. There can still be
177 options on the CPU to scale pipeline features up or down. :(
178 Bad Presentation (??), so we let the MD file rely on the value of
179 this variable instead Making PIPE_5 the default. It should be backward
180 optimal with PIPE_3 MicroBlazes. */
181 enum pipeline_type microblaze_pipe = MICROBLAZE_PIPE_5;
183 /* High and low marks for floating point values which we will accept
184 as legitimate constants for TARGET_LEGITIMATE_CONSTANT_P. These are
185 initialized in override_options. */
186 REAL_VALUE_TYPE dfhigh, dflow, sfhigh, sflow;
188 /* Array giving truth value on whether or not a given hard register
189 can support a given mode. */
190 char microblaze_hard_regno_mode_ok[(int)MAX_MACHINE_MODE]
191 [FIRST_PSEUDO_REGISTER];
193 /* Current frame information calculated by compute_frame_size. */
194 struct microblaze_frame_info current_frame_info;
196 /* Zero structure to initialize current_frame_info. */
197 struct microblaze_frame_info zero_frame_info;
199 /* List of all MICROBLAZE punctuation characters used by print_operand. */
200 char microblaze_print_operand_punct[256];
202 /* Map GCC register number to debugger register number. */
203 int microblaze_dbx_regno[FIRST_PSEUDO_REGISTER];
205 /* Map hard register number to register class. */
206 enum reg_class microblaze_regno_to_class[] =
208 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
209 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
210 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
211 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
212 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
213 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
214 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
215 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
216 ST_REGS, GR_REGS, GR_REGS, GR_REGS
219 /* MicroBlaze specific machine attributes.
220 interrupt_handler - Interrupt handler attribute to add interrupt prologue
221 and epilogue and use appropriate interrupt return.
222 save_volatiles - Similar to interrupt handler, but use normal return. */
223 int interrupt_handler;
224 int break_handler;
225 int fast_interrupt;
226 int save_volatiles;
228 const struct attribute_spec microblaze_attribute_table[] = {
229 /* name min_len, max_len, decl_req, type_req, fn_type, req_handler,
230 affects_type_identity */
231 {"interrupt_handler", 0, 0, true, false, false, NULL,
232 false },
233 {"break_handler", 0, 0, true, false, false, NULL,
234 false },
235 {"fast_interrupt", 0, 0, true, false, false, NULL,
236 false },
237 {"save_volatiles" , 0, 0, true, false, false, NULL,
238 false },
239 { NULL, 0, 0, false, false, false, NULL,
240 false }
243 static int microblaze_interrupt_function_p (tree);
245 static void microblaze_elf_asm_constructor (rtx, int) ATTRIBUTE_UNUSED;
246 static void microblaze_elf_asm_destructor (rtx, int) ATTRIBUTE_UNUSED;
248 section *sdata2_section;
250 #ifdef HAVE_AS_TLS
251 #undef TARGET_HAVE_TLS
252 #define TARGET_HAVE_TLS true
253 #endif
255 /* Return truth value if a CONST_DOUBLE is ok to be a legitimate constant. */
256 static bool
257 microblaze_const_double_ok (rtx op, machine_mode mode)
259 REAL_VALUE_TYPE d;
261 if (GET_CODE (op) != CONST_DOUBLE)
262 return 0;
264 if (GET_MODE (op) == VOIDmode)
265 return 1;
267 if (mode != SFmode && mode != DFmode)
268 return 0;
270 if (op == CONST0_RTX (mode))
271 return 1;
273 REAL_VALUE_FROM_CONST_DOUBLE (d, op);
275 if (REAL_VALUE_ISNAN (d))
276 return FALSE;
278 if (REAL_VALUE_NEGATIVE (d))
279 d = real_value_negate (&d);
281 if (mode == DFmode)
283 if (REAL_VALUES_LESS (d, dfhigh) && REAL_VALUES_LESS (dflow, d))
284 return 1;
286 else
288 if (REAL_VALUES_LESS (d, sfhigh) && REAL_VALUES_LESS (sflow, d))
289 return 1;
292 return 0;
295 /* Return truth value if a memory operand fits in a single instruction
296 (ie, register + small offset) or (register + register). */
299 simple_memory_operand (rtx op, machine_mode mode ATTRIBUTE_UNUSED)
301 rtx addr, plus0, plus1;
303 /* Eliminate non-memory operations. */
304 if (GET_CODE (op) != MEM)
305 return 0;
307 /* dword operations really put out 2 instructions, so eliminate them. */
308 /* ??? This isn't strictly correct. It is OK to accept multiword modes
309 here, since the length attributes are being set correctly, but only
310 if the address is offsettable. */
311 if (GET_MODE_SIZE (GET_MODE (op)) > UNITS_PER_WORD)
312 return 0;
315 /* Decode the address now. */
316 addr = XEXP (op, 0);
317 switch (GET_CODE (addr))
320 case REG:
321 return 1;
323 case PLUS:
324 plus0 = XEXP (addr, 0);
325 plus1 = XEXP (addr, 1);
327 if (GET_CODE (plus0) != REG)
328 return 0;
330 if (GET_CODE (plus0) == REG && GET_CODE (plus1) == CONST_INT
331 && SMALL_INT (plus1))
333 return 1;
335 else if (GET_CODE (plus1) == REG && GET_CODE (plus0) == CONST_INT)
337 return 1;
339 else if (GET_CODE (plus0) == REG && GET_CODE (plus1) == REG)
341 return 1;
343 else
344 return 0;
346 case SYMBOL_REF:
347 return 0;
349 default:
350 break;
353 return 0;
356 /* Return nonzero for a memory address that can be used to load or store
357 a doubleword. */
360 double_memory_operand (rtx op, machine_mode mode)
362 rtx addr;
364 if (GET_CODE (op) != MEM || !memory_operand (op, mode))
366 /* During reload, we accept a pseudo register if it has an
367 appropriate memory address. If we don't do this, we will
368 wind up reloading into a register, and then reloading that
369 register from memory, when we could just reload directly from
370 memory. */
371 if (reload_in_progress
372 && GET_CODE (op) == REG
373 && REGNO (op) >= FIRST_PSEUDO_REGISTER
374 && reg_renumber[REGNO (op)] < 0
375 && reg_equiv_mem (REGNO (op)) != 0
376 && double_memory_operand (reg_equiv_mem (REGNO (op)), mode))
377 return 1;
378 return 0;
381 /* Make sure that 4 added to the address is a valid memory address.
382 This essentially just checks for overflow in an added constant. */
384 addr = XEXP (op, 0);
386 if (CONSTANT_ADDRESS_P (addr))
387 return 1;
389 return memory_address_p ((GET_MODE_CLASS (mode) == MODE_INT
390 ? SImode : SFmode),
391 plus_constant (Pmode, addr, 4));
394 /* Implement REG_OK_FOR_BASE_P -and- REG_OK_FOR_INDEX_P. */
396 microblaze_regno_ok_for_base_p (int regno, int strict)
398 if (regno >= FIRST_PSEUDO_REGISTER)
400 if (!strict)
401 return true;
402 regno = reg_renumber[regno];
405 /* These fake registers will be eliminated to either the stack or
406 hard frame pointer, both of which are usually valid base registers.
407 Reload deals with the cases where the eliminated form isn't valid. */
408 if (regno == ARG_POINTER_REGNUM || regno == FRAME_POINTER_REGNUM)
409 return true;
411 return GP_REG_P (regno);
414 /* Return true if X is a valid base register for the given mode.
415 Allow only hard registers if STRICT. */
417 static bool
418 microblaze_valid_base_register_p (rtx x,
419 machine_mode mode ATTRIBUTE_UNUSED,
420 int strict)
422 if (!strict && GET_CODE (x) == SUBREG)
423 x = SUBREG_REG (x);
425 return (GET_CODE (x) == REG
426 && microblaze_regno_ok_for_base_p (REGNO (x), strict));
429 /* Build the SYMBOL_REF for __tls_get_addr. */
431 static GTY(()) rtx tls_get_addr_libfunc;
433 static rtx
434 get_tls_get_addr (void)
436 if (!tls_get_addr_libfunc)
437 tls_get_addr_libfunc = init_one_libfunc ("__tls_get_addr");
438 return tls_get_addr_libfunc;
441 /* Return TRUE if X is a thread-local symbol. */
442 bool
443 microblaze_tls_symbol_p (rtx x)
445 if (!TARGET_HAVE_TLS)
446 return false;
448 if (GET_CODE (x) != SYMBOL_REF)
449 return false;
451 return SYMBOL_REF_TLS_MODEL (x) != 0;
454 /* Return TRUE if X contains any TLS symbol references. */
456 bool
457 microblaze_tls_referenced_p (rtx x)
459 if (!TARGET_HAVE_TLS)
460 return false;
461 subrtx_iterator::array_type array;
462 FOR_EACH_SUBRTX (iter, array, x, ALL)
464 const_rtx x = *iter;
465 if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (x) != 0)
466 return true;
467 /* Don't recurse into UNSPEC_TLS looking for TLS symbols; these are
468 TLS offsets, not real symbol references. */
469 if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLS)
470 iter.skip_subrtxes ();
472 return false;
475 bool
476 microblaze_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED, rtx x)
478 return microblaze_tls_referenced_p(x);
481 /* Return TRUE if X references a SYMBOL_REF. */
483 symbol_mentioned_p (rtx x)
485 const char * fmt;
486 int i;
488 if (GET_CODE (x) == SYMBOL_REF)
489 return 1;
491 /* UNSPEC entries for a symbol include the SYMBOL_REF, but they
492 are constant offsets, not symbols. */
493 if (GET_CODE (x) == UNSPEC)
494 return 0;
496 fmt = GET_RTX_FORMAT (GET_CODE (x));
498 for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
500 if (fmt[i] == 'E')
502 int j;
504 for (j = XVECLEN (x, i) - 1; j >= 0; j--)
505 if (symbol_mentioned_p (XVECEXP (x, i, j)))
506 return 1;
508 else if (fmt[i] == 'e' && symbol_mentioned_p (XEXP (x, i)))
509 return 1;
512 return 0;
515 /* Return TRUE if X references a LABEL_REF. */
517 label_mentioned_p (rtx x)
519 const char * fmt;
520 int i;
522 if (GET_CODE (x) == LABEL_REF)
523 return 1;
525 /* UNSPEC entries for a symbol include a LABEL_REF for the referencing
526 instruction, but they are constant offsets, not symbols. */
527 if (GET_CODE (x) == UNSPEC)
528 return 0;
530 fmt = GET_RTX_FORMAT (GET_CODE (x));
531 for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
533 if (fmt[i] == 'E')
535 int j;
537 for (j = XVECLEN (x, i) - 1; j >= 0; j--)
538 if (label_mentioned_p (XVECEXP (x, i, j)))
539 return 1;
541 else if (fmt[i] == 'e' && label_mentioned_p (XEXP (x, i)))
542 return 1;
545 return 0;
549 tls_mentioned_p (rtx x)
551 switch (GET_CODE (x))
553 case CONST:
554 return tls_mentioned_p (XEXP (x, 0));
556 case UNSPEC:
557 if (XINT (x, 1) == UNSPEC_TLS)
558 return 1;
560 default:
561 return 0;
565 static rtx
566 load_tls_operand (rtx x, rtx reg)
568 rtx tmp;
570 if (reg == NULL_RTX)
571 reg = gen_reg_rtx (Pmode);
573 tmp = gen_rtx_CONST (Pmode, x);
575 emit_insn (gen_rtx_SET (reg,
576 gen_rtx_PLUS (Pmode, pic_offset_table_rtx, tmp)));
578 return reg;
581 static rtx_insn *
582 microblaze_call_tls_get_addr (rtx x, rtx reg, rtx *valuep, int reloc)
584 rtx_insn *insns;
585 rtx tls_entry;
587 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
589 start_sequence ();
591 tls_entry = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, x, GEN_INT (reloc)),
592 UNSPEC_TLS);
594 reg = load_tls_operand (tls_entry, reg);
596 *valuep = emit_library_call_value (get_tls_get_addr (), NULL_RTX,
597 LCT_PURE, /* LCT_CONST? */
598 Pmode, 1, reg, Pmode);
600 insns = get_insns ();
601 end_sequence ();
603 return insns;
607 microblaze_legitimize_tls_address(rtx x, rtx reg)
609 rtx dest, ret, eqv, addend;
610 rtx_insn *insns;
611 enum tls_model model;
612 model = SYMBOL_REF_TLS_MODEL (x);
614 switch (model)
616 case TLS_MODEL_LOCAL_DYNAMIC:
617 case TLS_MODEL_GLOBAL_DYNAMIC:
618 case TLS_MODEL_INITIAL_EXEC:
619 insns = microblaze_call_tls_get_addr (x, reg, &ret, TLS_GD);
620 dest = gen_reg_rtx (Pmode);
621 emit_libcall_block (insns, dest, ret, x);
622 break;
624 case TLS_MODEL_LOCAL_EXEC:
625 insns = microblaze_call_tls_get_addr (x, reg, &ret, TLS_LDM);
627 /* Attach a unique REG_EQUIV, to allow the RTL optimizers to
628 share the LDM result with other LD model accesses. */
629 eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const1_rtx), UNSPEC_TLS);
630 dest = gen_reg_rtx (Pmode);
631 emit_libcall_block (insns, dest, ret, eqv);
633 /* Load the addend. */
634 addend = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, x, GEN_INT (TLS_DTPREL)),
635 UNSPEC_TLS);
636 addend = force_reg (SImode, gen_rtx_CONST (SImode, addend));
637 dest = gen_rtx_PLUS (Pmode, dest, addend);
638 break;
640 default:
641 gcc_unreachable ();
643 return dest;
646 static bool
647 microblaze_classify_unspec (struct microblaze_address_info *info, rtx x)
649 info->symbol_type = SYMBOL_TYPE_GENERAL;
650 info->symbol = XVECEXP (x, 0, 0);
652 if (XINT (x, 1) == UNSPEC_GOTOFF)
654 info->regA = gen_rtx_REG (SImode, PIC_OFFSET_TABLE_REGNUM);
655 info->type = ADDRESS_GOTOFF;
657 else if (XINT (x, 1) == UNSPEC_PLT)
659 info->type = ADDRESS_PLT;
661 else if (XINT (x, 1) == UNSPEC_TLS)
663 info->type = ADDRESS_TLS;
664 info->tls_type = tls_reloc (INTVAL (XVECEXP (x, 0, 1)));
666 else
668 return false;
670 return true;
674 /* Return true if X is a valid index register for the given mode.
675 Allow only hard registers if STRICT. */
677 static bool
678 microblaze_valid_index_register_p (rtx x,
679 machine_mode mode ATTRIBUTE_UNUSED,
680 int strict)
682 if (!strict && GET_CODE (x) == SUBREG)
683 x = SUBREG_REG (x);
685 return (GET_CODE (x) == REG
686 /* A base register is good enough to be an index register on MicroBlaze. */
687 && microblaze_regno_ok_for_base_p (REGNO (x), strict));
690 /* Get the base register for accessing a value from the memory or
691 Symbol ref. Used for MicroBlaze Small Data Area Pointer Optimization. */
692 static int
693 get_base_reg (rtx x)
695 tree decl;
696 int base_reg;
698 if (!flag_pic || microblaze_tls_symbol_p(x))
699 base_reg = MB_ABI_BASE_REGNUM;
700 else if (flag_pic)
701 base_reg = MB_ABI_PIC_ADDR_REGNUM;
703 if (TARGET_XLGPOPT
704 && GET_CODE (x) == SYMBOL_REF
705 && SYMBOL_REF_SMALL_P (x) && (decl = SYMBOL_REF_DECL (x)) != NULL)
707 if (TREE_READONLY (decl))
708 base_reg = MB_ABI_GPRO_REGNUM;
709 else
710 base_reg = MB_ABI_GPRW_REGNUM;
713 return base_reg;
716 /* Return true if X is a valid address for machine mode MODE. If it is,
717 fill in INFO appropriately. STRICT is true if we should only accept
718 hard base registers.
720 type regA regB offset symbol
722 ADDRESS_INVALID NULL NULL NULL NULL
724 ADDRESS_REG %0 NULL const_0 / NULL
725 const_int
726 ADDRESS_REG_INDEX %0 %1 NULL NULL
728 ADDRESS_SYMBOLIC r0 / NULL NULL symbol
729 sda_base_reg
731 ADDRESS_CONST_INT r0 NULL const NULL
733 For modes spanning multiple registers (DFmode in 32-bit GPRs,
734 DImode, TImode), indexed addressing cannot be used because
735 adjacent memory cells are accessed by adding word-sized offsets
736 during assembly output. */
738 static bool
739 microblaze_classify_address (struct microblaze_address_info *info, rtx x,
740 machine_mode mode, int strict)
742 rtx xplus0;
743 rtx xplus1;
745 info->type = ADDRESS_INVALID;
746 info->regA = NULL;
747 info->regB = NULL;
748 info->offset = NULL;
749 info->symbol = NULL;
750 info->symbol_type = SYMBOL_TYPE_INVALID;
752 switch (GET_CODE (x))
754 case REG:
755 case SUBREG:
757 info->type = ADDRESS_REG;
758 info->regA = x;
759 info->offset = const0_rtx;
760 return microblaze_valid_base_register_p (info->regA, mode, strict);
762 case PLUS:
764 xplus0 = XEXP (x, 0);
765 xplus1 = XEXP (x, 1);
767 if (microblaze_valid_base_register_p (xplus0, mode, strict))
769 info->type = ADDRESS_REG;
770 info->regA = xplus0;
772 if (GET_CODE (xplus1) == CONST_INT)
774 info->offset = xplus1;
775 return true;
777 else if (GET_CODE (xplus1) == UNSPEC)
779 /* Need offsettable address. */
780 if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
781 return false;
783 return microblaze_classify_unspec (info, xplus1);
785 else if ((GET_CODE (xplus1) == SYMBOL_REF ||
786 GET_CODE (xplus1) == LABEL_REF))
788 if (flag_pic == 2 || microblaze_tls_symbol_p(xplus1))
789 return false;
790 info->type = ADDRESS_SYMBOLIC;
791 info->symbol = xplus1;
792 info->symbol_type = SYMBOL_TYPE_GENERAL;
793 return true;
795 else if (GET_CODE (xplus1) == CONST)
797 rtx xconst0 = XEXP(xplus1, 0);
799 /* base + unspec. */
800 if (GET_CODE (xconst0) == UNSPEC)
802 /* Need offsettable address. */
803 if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
804 return false;
805 return microblaze_classify_unspec(info, xconst0);
808 /* for (plus x const_int) just look at x. */
809 if (GET_CODE (xconst0) == PLUS
810 && GET_CODE (XEXP (xconst0, 1)) == CONST_INT
811 && SMALL_INT (XEXP (xconst0, 1)))
813 /* This is ok as info->symbol is set to xplus1 the full
814 const-expression below. */
815 xconst0 = XEXP (xconst0, 0);
818 if (GET_CODE (xconst0) == SYMBOL_REF
819 || GET_CODE (xconst0) == LABEL_REF)
821 if (flag_pic == 2 || microblaze_tls_symbol_p(xconst0))
822 return false;
824 info->type = ADDRESS_SYMBOLIC;
825 info->symbol = xplus1;
826 info->symbol_type = SYMBOL_TYPE_GENERAL;
827 return true;
830 /* Not base + symbol || base + UNSPEC. */
831 return false;
834 else if (GET_CODE (xplus1) == REG
835 && microblaze_valid_index_register_p (xplus1, mode,
836 strict)
837 && (GET_MODE_SIZE (mode) <= UNITS_PER_WORD))
839 /* Restrict larger than word-width modes from using an index register. */
840 info->type = ADDRESS_REG_INDEX;
841 info->regB = xplus1;
842 return true;
845 break;
847 case CONST_INT:
849 info->regA = gen_raw_REG (mode, 0);
850 info->type = ADDRESS_CONST_INT;
851 info->offset = x;
852 return true;
854 case CONST:
855 case LABEL_REF:
856 case SYMBOL_REF:
858 info->type = ADDRESS_SYMBOLIC;
859 info->symbol_type = SYMBOL_TYPE_GENERAL;
860 info->symbol = x;
861 info->regA = gen_raw_REG (mode, get_base_reg (x));
863 if (GET_CODE (x) == CONST)
865 if (GET_CODE (XEXP (x, 0)) == UNSPEC)
867 info->regA = gen_raw_REG (mode,
868 get_base_reg (XVECEXP (XEXP (x,0), 0, 0)));
869 return microblaze_classify_unspec (info, XEXP (x, 0));
871 return !(flag_pic && pic_address_needs_scratch (x));
874 if (flag_pic == 2)
875 return false;
876 else if (microblaze_tls_symbol_p(x))
877 return false;
879 return true;
882 case UNSPEC:
884 if (reload_in_progress)
885 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
886 return microblaze_classify_unspec (info, x);
889 default:
890 return false;
893 return false;
896 /* This function is used to implement GO_IF_LEGITIMATE_ADDRESS. It
897 returns a nonzero value if X is a legitimate address for a memory
898 operand of the indicated MODE. STRICT is nonzero if this function
899 is called during reload. */
901 bool
902 microblaze_legitimate_address_p (machine_mode mode, rtx x, bool strict)
904 struct microblaze_address_info addr;
906 return microblaze_classify_address (&addr, x, mode, strict);
910 microblaze_valid_pic_const (rtx x)
912 switch (GET_CODE (x))
914 case CONST:
915 case CONST_INT:
916 case CONST_DOUBLE:
917 return true;
918 default:
919 return false;
924 microblaze_legitimate_pic_operand (rtx x)
926 if (flag_pic == 2 && (symbol_mentioned_p(x) || label_mentioned_p(x)))
927 return 0;
929 if (microblaze_tls_referenced_p(x))
930 return 0;
932 return 1;
935 /* Try machine-dependent ways of modifying an illegitimate address
936 to be legitimate. If we find one, return the new, valid address.
937 This is used from only one place: `memory_address' in explow.c.
939 OLDX is the address as it was before break_out_memory_refs was
940 called. In some cases it is useful to look at this to decide what
941 needs to be done.
943 It is always safe for this function to do nothing. It exists to
944 recognize opportunities to optimize the output.
946 For the MicroBlaze, transform:
948 memory(X + <large int>)
950 into:
952 Y = <large int> & ~0x7fff;
953 Z = X + Y
954 memory (Z + (<large int> & 0x7fff));
956 This is for CSE to find several similar references, and only use one Z.
958 When PIC, convert addresses of the form memory (symbol+large int) to
959 memory (reg+large int). */
961 static rtx
962 microblaze_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
963 machine_mode mode ATTRIBUTE_UNUSED)
965 register rtx xinsn = x, result;
967 if (GET_CODE (xinsn) == CONST
968 && flag_pic && pic_address_needs_scratch (xinsn))
970 rtx ptr_reg = gen_reg_rtx (Pmode);
971 rtx constant = XEXP (XEXP (xinsn, 0), 1);
973 emit_move_insn (ptr_reg, XEXP (XEXP (xinsn, 0), 0));
975 result = gen_rtx_PLUS (Pmode, ptr_reg, constant);
976 if (SMALL_INT (constant))
977 return result;
978 /* Otherwise we fall through so the code below will fix the
979 constant. */
980 xinsn = result;
983 if (GET_CODE (xinsn) == PLUS)
985 register rtx xplus0 = XEXP (xinsn, 0);
986 register rtx xplus1 = XEXP (xinsn, 1);
987 register enum rtx_code code0 = GET_CODE (xplus0);
988 register enum rtx_code code1 = GET_CODE (xplus1);
990 if (code0 != REG && code1 == REG)
992 xplus0 = XEXP (xinsn, 1);
993 xplus1 = XEXP (xinsn, 0);
994 code0 = GET_CODE (xplus0);
995 code1 = GET_CODE (xplus1);
998 if (code0 == REG && REG_OK_FOR_BASE_P (xplus0)
999 && code1 == CONST_INT && !SMALL_INT (xplus1))
1001 rtx int_reg = gen_reg_rtx (Pmode);
1002 rtx ptr_reg = gen_reg_rtx (Pmode);
1004 emit_move_insn (int_reg, GEN_INT (INTVAL (xplus1) & ~0x7fff));
1006 emit_insn (gen_rtx_SET (ptr_reg,
1007 gen_rtx_PLUS (Pmode, xplus0, int_reg)));
1009 result = gen_rtx_PLUS (Pmode, ptr_reg,
1010 GEN_INT (INTVAL (xplus1) & 0x7fff));
1011 return result;
1014 if (code0 == REG && REG_OK_FOR_BASE_P (xplus0))
1016 if (reload_in_progress)
1017 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
1018 if (code1 == CONST)
1020 xplus1 = XEXP (xplus1, 0);
1021 code1 = GET_CODE (xplus1);
1023 if (code1 == SYMBOL_REF)
1025 if (microblaze_tls_symbol_p(xplus1))
1027 rtx tls_ref, reg;
1028 reg = gen_reg_rtx (Pmode);
1030 tls_ref = microblaze_legitimize_tls_address (xplus1,
1031 NULL_RTX);
1032 emit_move_insn (reg, tls_ref);
1034 result = gen_rtx_PLUS (Pmode, xplus0, reg);
1036 return result;
1038 else if (flag_pic == 2)
1040 rtx pic_ref, reg;
1041 reg = gen_reg_rtx (Pmode);
1043 pic_ref = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, xplus1),
1044 UNSPEC_GOTOFF);
1045 pic_ref = gen_rtx_CONST (Pmode, pic_ref);
1046 pic_ref = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, pic_ref);
1047 pic_ref = gen_const_mem (Pmode, pic_ref);
1048 emit_move_insn (reg, pic_ref);
1049 result = gen_rtx_PLUS (Pmode, xplus0, reg);
1050 return result;
1056 if (GET_CODE (xinsn) == SYMBOL_REF)
1058 rtx reg;
1059 if (microblaze_tls_symbol_p(xinsn))
1061 reg = microblaze_legitimize_tls_address (xinsn, NULL_RTX);
1063 else
1065 rtx pic_ref;
1067 if (reload_in_progress)
1068 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
1070 pic_ref = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, xinsn), UNSPEC_GOTOFF);
1071 pic_ref = gen_rtx_CONST (Pmode, pic_ref);
1072 pic_ref = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, pic_ref);
1073 pic_ref = gen_const_mem (Pmode, pic_ref);
1074 reg = pic_ref;
1076 return reg;
1079 return x;
1082 /* Block Moves. */
1084 #define MAX_MOVE_REGS 8
1085 #define MAX_MOVE_BYTES (MAX_MOVE_REGS * UNITS_PER_WORD)
1087 /* Emit straight-line code to move LENGTH bytes from SRC to DEST.
1088 Assume that the areas do not overlap. */
1090 static void
1091 microblaze_block_move_straight (rtx dest, rtx src, HOST_WIDE_INT length)
1093 HOST_WIDE_INT offset, delta;
1094 unsigned HOST_WIDE_INT bits;
1095 int i;
1096 machine_mode mode;
1097 rtx *regs;
1099 bits = BITS_PER_WORD;
1100 mode = mode_for_size (bits, MODE_INT, 0);
1101 delta = bits / BITS_PER_UNIT;
1103 /* Allocate a buffer for the temporary registers. */
1104 regs = XALLOCAVEC (rtx, length / delta);
1106 /* Load as many BITS-sized chunks as possible. Use a normal load if
1107 the source has enough alignment, otherwise use left/right pairs. */
1108 for (offset = 0, i = 0; offset + delta <= length; offset += delta, i++)
1110 regs[i] = gen_reg_rtx (mode);
1111 emit_move_insn (regs[i], adjust_address (src, mode, offset));
1114 /* Copy the chunks to the destination. */
1115 for (offset = 0, i = 0; offset + delta <= length; offset += delta, i++)
1116 emit_move_insn (adjust_address (dest, mode, offset), regs[i]);
1118 /* Mop up any left-over bytes. */
1119 if (offset < length)
1121 src = adjust_address (src, BLKmode, offset);
1122 dest = adjust_address (dest, BLKmode, offset);
1123 move_by_pieces (dest, src, length - offset,
1124 MIN (MEM_ALIGN (src), MEM_ALIGN (dest)), 0);
1128 /* Helper function for doing a loop-based block operation on memory
1129 reference MEM. Each iteration of the loop will operate on LENGTH
1130 bytes of MEM.
1132 Create a new base register for use within the loop and point it to
1133 the start of MEM. Create a new memory reference that uses this
1134 register. Store them in *LOOP_REG and *LOOP_MEM respectively. */
1136 static void
1137 microblaze_adjust_block_mem (rtx mem, HOST_WIDE_INT length,
1138 rtx * loop_reg, rtx * loop_mem)
1140 *loop_reg = copy_addr_to_reg (XEXP (mem, 0));
1142 /* Although the new mem does not refer to a known location,
1143 it does keep up to LENGTH bytes of alignment. */
1144 *loop_mem = change_address (mem, BLKmode, *loop_reg);
1145 set_mem_align (*loop_mem,
1146 MIN ((HOST_WIDE_INT) MEM_ALIGN (mem),
1147 length * BITS_PER_UNIT));
1151 /* Move LENGTH bytes from SRC to DEST using a loop that moves MAX_MOVE_BYTES
1152 per iteration. LENGTH must be at least MAX_MOVE_BYTES. Assume that the
1153 memory regions do not overlap. */
1155 static void
1156 microblaze_block_move_loop (rtx dest, rtx src, HOST_WIDE_INT length)
1158 rtx_code_label *label;
1159 rtx src_reg, dest_reg, final_src;
1160 HOST_WIDE_INT leftover;
1162 leftover = length % MAX_MOVE_BYTES;
1163 length -= leftover;
1165 /* Create registers and memory references for use within the loop. */
1166 microblaze_adjust_block_mem (src, MAX_MOVE_BYTES, &src_reg, &src);
1167 microblaze_adjust_block_mem (dest, MAX_MOVE_BYTES, &dest_reg, &dest);
1169 /* Calculate the value that SRC_REG should have after the last iteration
1170 of the loop. */
1171 final_src = expand_simple_binop (Pmode, PLUS, src_reg, GEN_INT (length),
1172 0, 0, OPTAB_WIDEN);
1174 /* Emit the start of the loop. */
1175 label = gen_label_rtx ();
1176 emit_label (label);
1178 /* Emit the loop body. */
1179 microblaze_block_move_straight (dest, src, MAX_MOVE_BYTES);
1181 /* Move on to the next block. */
1182 emit_move_insn (src_reg, plus_constant (Pmode, src_reg, MAX_MOVE_BYTES));
1183 emit_move_insn (dest_reg, plus_constant (Pmode, dest_reg, MAX_MOVE_BYTES));
1185 /* Emit the test & branch. */
1186 emit_insn (gen_cbranchsi4 (gen_rtx_NE (SImode, src_reg, final_src),
1187 src_reg, final_src, label));
1189 /* Mop up any left-over bytes. */
1190 if (leftover)
1191 microblaze_block_move_straight (dest, src, leftover);
1194 /* Expand a movmemsi instruction. */
1196 bool
1197 microblaze_expand_block_move (rtx dest, rtx src, rtx length, rtx align_rtx)
1200 if (GET_CODE (length) == CONST_INT)
1202 HOST_WIDE_INT bytes = INTVAL (length);
1203 int align = INTVAL (align_rtx);
1205 if (align > UNITS_PER_WORD)
1207 align = UNITS_PER_WORD; /* We can't do any better. */
1209 else if (align < UNITS_PER_WORD)
1211 if (INTVAL (length) <= MAX_MOVE_BYTES)
1213 move_by_pieces (dest, src, bytes, align, 0);
1214 return true;
1216 else
1217 return false;
1220 if (INTVAL (length) <= 2 * MAX_MOVE_BYTES)
1222 microblaze_block_move_straight (dest, src, INTVAL (length));
1223 return true;
1225 else if (optimize)
1227 microblaze_block_move_loop (dest, src, INTVAL (length));
1228 return true;
1231 return false;
1234 static bool
1235 microblaze_rtx_costs (rtx x, machine_mode mode, int outer_code ATTRIBUTE_UNUSED,
1236 int opno ATTRIBUTE_UNUSED, int *total,
1237 bool speed ATTRIBUTE_UNUSED)
1239 int code = GET_CODE (x);
1241 switch (code)
1243 case MEM:
1245 int num_words = (GET_MODE_SIZE (mode) > UNITS_PER_WORD) ? 2 : 1;
1246 if (simple_memory_operand (x, mode))
1247 *total = COSTS_N_INSNS (2 * num_words);
1248 else
1249 *total = COSTS_N_INSNS (2 * (2 * num_words));
1251 return true;
1253 case NOT:
1255 if (mode == DImode)
1257 *total = COSTS_N_INSNS (2);
1259 else
1260 *total = COSTS_N_INSNS (1);
1261 return false;
1263 case AND:
1264 case IOR:
1265 case XOR:
1267 if (mode == DImode)
1269 *total = COSTS_N_INSNS (2);
1271 else
1272 *total = COSTS_N_INSNS (1);
1274 return false;
1276 case ASHIFT:
1277 case ASHIFTRT:
1278 case LSHIFTRT:
1280 if (TARGET_BARREL_SHIFT)
1282 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v5.00.a")
1283 >= 0)
1284 *total = COSTS_N_INSNS (1);
1285 else
1286 *total = COSTS_N_INSNS (2);
1288 else if (!TARGET_SOFT_MUL)
1289 *total = COSTS_N_INSNS (1);
1290 else if (GET_CODE (XEXP (x, 1)) == CONST_INT)
1292 /* Add 1 to make shift slightly more expensive than add. */
1293 *total = COSTS_N_INSNS (INTVAL (XEXP (x, 1))) + 1;
1294 /* Reduce shift costs for special circumstances. */
1295 if (optimize_size && INTVAL (XEXP (x, 1)) > 5)
1296 *total -= 2;
1297 if (!optimize_size && INTVAL (XEXP (x, 1)) > 17)
1298 *total -= 2;
1300 else
1301 /* Double the worst cost of shifts when there is no barrel shifter and
1302 the shift amount is in a reg. */
1303 *total = COSTS_N_INSNS (32 * 4);
1304 return true;
1306 case PLUS:
1307 case MINUS:
1309 if (mode == SFmode || mode == DFmode)
1311 if (TARGET_HARD_FLOAT)
1312 *total = COSTS_N_INSNS (6);
1313 return true;
1315 else if (mode == DImode)
1317 *total = COSTS_N_INSNS (4);
1318 return true;
1320 else
1322 *total = COSTS_N_INSNS (1);
1323 return true;
1326 return false;
1328 case NEG:
1330 if (mode == DImode)
1331 *total = COSTS_N_INSNS (4);
1333 return false;
1335 case MULT:
1337 if (mode == SFmode)
1339 if (TARGET_HARD_FLOAT)
1340 *total = COSTS_N_INSNS (6);
1342 else if (!TARGET_SOFT_MUL)
1344 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v5.00.a")
1345 >= 0)
1346 *total = COSTS_N_INSNS (1);
1347 else
1348 *total = COSTS_N_INSNS (3);
1350 else
1351 *total = COSTS_N_INSNS (10);
1352 return true;
1354 case DIV:
1355 case UDIV:
1357 if (mode == SFmode)
1359 if (TARGET_HARD_FLOAT)
1360 *total = COSTS_N_INSNS (23);
1362 return false;
1364 case SIGN_EXTEND:
1366 *total = COSTS_N_INSNS (1);
1367 return false;
1369 case ZERO_EXTEND:
1371 *total = COSTS_N_INSNS (1);
1372 return false;
1376 return false;
1379 /* Return the number of instructions needed to load or store a value
1380 of mode MODE at X. Return 0 if X isn't valid for MODE. */
1382 static int
1383 microblaze_address_insns (rtx x, machine_mode mode)
1385 struct microblaze_address_info addr;
1387 if (microblaze_classify_address (&addr, x, mode, false))
1389 switch (addr.type)
1391 case ADDRESS_REG:
1392 if (SMALL_INT (addr.offset))
1393 return 1;
1394 else
1395 return 2;
1396 case ADDRESS_CONST_INT:
1397 if (SMALL_INT (x))
1398 return 1;
1399 else
1400 return 2;
1401 case ADDRESS_REG_INDEX:
1402 return 1;
1403 case ADDRESS_SYMBOLIC:
1404 case ADDRESS_GOTOFF:
1405 return 2;
1406 case ADDRESS_TLS:
1407 switch (addr.tls_type)
1409 case TLS_GD:
1410 return 2;
1411 case TLS_LDM:
1412 return 2;
1413 case TLS_DTPREL:
1414 return 1;
1415 default :
1416 abort();
1418 default:
1419 break;
1422 return 0;
1425 /* Provide the costs of an addressing mode that contains ADDR.
1426 If ADDR is not a valid address, its cost is irrelevant. */
1427 static int
1428 microblaze_address_cost (rtx addr, machine_mode mode ATTRIBUTE_UNUSED,
1429 addr_space_t as ATTRIBUTE_UNUSED,
1430 bool speed ATTRIBUTE_UNUSED)
1432 return COSTS_N_INSNS (microblaze_address_insns (addr, GET_MODE (addr)));
1435 /* Return nonzero if X is an address which needs a temporary register when
1436 reloaded while generating PIC code. */
1439 pic_address_needs_scratch (rtx x)
1441 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x,0)) == PLUS)
1443 rtx p0, p1;
1445 p0 = XEXP (XEXP (x, 0), 0);
1446 p1 = XEXP (XEXP (x, 0), 1);
1448 if ((GET_CODE (p0) == SYMBOL_REF || GET_CODE (p0) == LABEL_REF)
1449 && (GET_CODE (p1) == CONST_INT)
1450 && (flag_pic == 2 || microblaze_tls_symbol_p (p0) || !SMALL_INT (p1)))
1451 return 1;
1453 return 0;
1456 /* Argument support functions. */
1457 /* Initialize CUMULATIVE_ARGS for a function. */
1459 void
1460 init_cumulative_args (CUMULATIVE_ARGS * cum, tree fntype,
1461 rtx libname ATTRIBUTE_UNUSED)
1463 static CUMULATIVE_ARGS zero_cum;
1464 tree param, next_param;
1466 *cum = zero_cum;
1468 /* Determine if this function has variable arguments. This is
1469 indicated by the last argument being 'void_type_mode' if there
1470 are no variable arguments. The standard MicroBlaze calling sequence
1471 passes all arguments in the general purpose registers in this case. */
1473 for (param = fntype ? TYPE_ARG_TYPES (fntype) : 0;
1474 param != 0; param = next_param)
1476 next_param = TREE_CHAIN (param);
1477 if (next_param == 0 && TREE_VALUE (param) != void_type_node)
1478 cum->gp_reg_found = 1;
1482 /* Advance the argument to the next argument position. */
1484 static void
1485 microblaze_function_arg_advance (cumulative_args_t cum_v,
1486 machine_mode mode,
1487 const_tree type, bool named ATTRIBUTE_UNUSED)
1489 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
1491 cum->arg_number++;
1492 switch (mode)
1494 case VOIDmode:
1495 break;
1497 default:
1498 gcc_assert (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
1499 || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT);
1501 cum->gp_reg_found = 1;
1502 cum->arg_words += ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1)
1503 / UNITS_PER_WORD);
1504 break;
1506 case BLKmode:
1507 cum->gp_reg_found = 1;
1508 cum->arg_words += ((int_size_in_bytes (type) + UNITS_PER_WORD - 1)
1509 / UNITS_PER_WORD);
1510 break;
1512 case SFmode:
1513 cum->arg_words++;
1514 if (!cum->gp_reg_found && cum->arg_number <= 2)
1515 cum->fp_code += 1 << ((cum->arg_number - 1) * 2);
1516 break;
1518 case DFmode:
1519 cum->arg_words += 2;
1520 if (!cum->gp_reg_found && cum->arg_number <= 2)
1521 cum->fp_code += 2 << ((cum->arg_number - 1) * 2);
1522 break;
1524 case DImode:
1525 cum->gp_reg_found = 1;
1526 cum->arg_words += 2;
1527 break;
1529 case QImode:
1530 case HImode:
1531 case SImode:
1532 case TImode:
1533 cum->gp_reg_found = 1;
1534 cum->arg_words++;
1535 break;
1539 /* Return an RTL expression containing the register for the given mode,
1540 or 0 if the argument is to be passed on the stack. */
1542 static rtx
1543 microblaze_function_arg (cumulative_args_t cum_v, machine_mode mode,
1544 const_tree type ATTRIBUTE_UNUSED,
1545 bool named ATTRIBUTE_UNUSED)
1547 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
1549 rtx ret;
1550 int regbase = -1;
1551 int *arg_words = &cum->arg_words;
1553 cum->last_arg_fp = 0;
1554 switch (mode)
1556 case SFmode:
1557 case DFmode:
1558 case VOIDmode:
1559 case QImode:
1560 case HImode:
1561 case SImode:
1562 case DImode:
1563 case TImode:
1564 regbase = GP_ARG_FIRST;
1565 break;
1566 default:
1567 gcc_assert (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
1568 || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT);
1569 /* Drops through. */
1570 case BLKmode:
1571 regbase = GP_ARG_FIRST;
1572 break;
1575 if (*arg_words >= MAX_ARGS_IN_REGISTERS)
1576 ret = 0;
1577 else
1579 gcc_assert (regbase != -1);
1581 ret = gen_rtx_REG (mode, regbase + *arg_words);
1584 if (mode == VOIDmode)
1586 if (cum->num_adjusts > 0)
1587 ret = gen_rtx_PARALLEL ((machine_mode) cum->fp_code,
1588 gen_rtvec_v (cum->num_adjusts, cum->adjust));
1591 return ret;
1594 /* Return number of bytes of argument to put in registers. */
1595 static int
1596 function_arg_partial_bytes (cumulative_args_t cum_v, machine_mode mode,
1597 tree type, bool named ATTRIBUTE_UNUSED)
1599 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
1601 if ((mode == BLKmode
1602 || GET_MODE_CLASS (mode) != MODE_COMPLEX_INT
1603 || GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT)
1604 && cum->arg_words < MAX_ARGS_IN_REGISTERS)
1606 int words;
1607 if (mode == BLKmode)
1608 words = ((int_size_in_bytes (type) + UNITS_PER_WORD - 1)
1609 / UNITS_PER_WORD);
1610 else
1611 words = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
1613 if (words + cum->arg_words <= MAX_ARGS_IN_REGISTERS)
1614 return 0; /* structure fits in registers */
1616 return (MAX_ARGS_IN_REGISTERS - cum->arg_words) * UNITS_PER_WORD;
1619 else if (mode == DImode && cum->arg_words == MAX_ARGS_IN_REGISTERS - 1)
1620 return UNITS_PER_WORD;
1622 return 0;
1625 /* Convert a version number of the form "vX.YY.Z" to an integer encoding
1626 for easier range comparison. */
1627 static int
1628 microblaze_version_to_int (const char *version)
1630 const char *p, *v;
1631 const char *tmpl = "vXX.YY.Z";
1632 int iver = 0;
1634 p = version;
1635 v = tmpl;
1637 while (*p)
1639 if (*v == 'X')
1640 { /* Looking for major */
1641 if (*p == '.')
1643 v++;
1645 else
1647 if (!(*p >= '0' && *p <= '9'))
1648 return -1;
1649 iver += (int) (*p - '0');
1650 iver *= 10;
1653 else if (*v == 'Y')
1654 { /* Looking for minor */
1655 if (!(*p >= '0' && *p <= '9'))
1656 return -1;
1657 iver += (int) (*p - '0');
1658 iver *= 10;
1660 else if (*v == 'Z')
1661 { /* Looking for compat */
1662 if (!(*p >= 'a' && *p <= 'z'))
1663 return -1;
1664 iver *= 10;
1665 iver += (int) (*p - 'a');
1667 else
1669 if (*p != *v)
1670 return -1;
1673 v++;
1674 p++;
1677 if (*p)
1678 return -1;
1680 return iver;
1684 static void
1685 microblaze_option_override (void)
1687 register int i, start;
1688 register int regno;
1689 register machine_mode mode;
1690 int ver;
1692 microblaze_section_threshold = (global_options_set.x_g_switch_value
1693 ? g_switch_value
1694 : MICROBLAZE_DEFAULT_GVALUE);
1696 if (flag_pic)
1698 /* Make sure it's 2, we only support one kind of PIC. */
1699 flag_pic = 2;
1700 if (!TARGET_SUPPORTS_PIC)
1702 error ("-fPIC/-fpic not supported for this target");
1703 /* Clear it to avoid further errors. */
1704 flag_pic = 0;
1708 /* Check the MicroBlaze CPU version for any special action to be done. */
1709 if (microblaze_select_cpu == NULL)
1710 microblaze_select_cpu = MICROBLAZE_DEFAULT_CPU;
1711 ver = microblaze_version_to_int (microblaze_select_cpu);
1712 if (ver == -1)
1714 error ("%qs is an invalid argument to -mcpu=", microblaze_select_cpu);
1717 ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v3.00.a");
1718 if (ver < 0)
1720 /* No hardware exceptions in earlier versions. So no worries. */
1721 #if 0
1722 microblaze_select_flags &= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY);
1723 #endif
1724 microblaze_no_unsafe_delay = 0;
1725 microblaze_pipe = MICROBLAZE_PIPE_3;
1727 else if (ver == 0
1728 || (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v4.00.b")
1729 == 0))
1731 #if 0
1732 microblaze_select_flags |= (MICROBLAZE_MASK_NO_UNSAFE_DELAY);
1733 #endif
1734 microblaze_no_unsafe_delay = 1;
1735 microblaze_pipe = MICROBLAZE_PIPE_3;
1737 else
1739 /* We agree to use 5 pipe-stage model even on area optimized 3
1740 pipe-stage variants. */
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_5;
1746 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v5.00.a") == 0
1747 || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu,
1748 "v5.00.b") == 0
1749 || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu,
1750 "v5.00.c") == 0)
1752 /* Pattern compares are to be turned on by default only when
1753 compiling for MB v5.00.'z'. */
1754 target_flags |= MASK_PATTERN_COMPARE;
1758 ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v6.00.a");
1759 if (ver < 0)
1761 if (TARGET_MULTIPLY_HIGH)
1762 warning (0,
1763 "-mxl-multiply-high can be used only with -mcpu=v6.00.a or greater");
1766 ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v8.10.a");
1767 microblaze_has_clz = 1;
1768 if (ver < 0)
1770 /* MicroBlaze prior to 8.10.a didn't have clz. */
1771 microblaze_has_clz = 0;
1774 /* TARGET_REORDER defaults to 2 if -mxl-reorder not specified. */
1775 ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v8.30.a");
1776 if (ver < 0)
1778 if (TARGET_REORDER == 1)
1779 warning (0, "-mxl-reorder can be used only with -mcpu=v8.30.a or greater");
1780 TARGET_REORDER = 0;
1782 else if ((ver == 0) && !TARGET_PATTERN_COMPARE)
1784 if (TARGET_REORDER == 1)
1785 warning (0, "-mxl-reorder requires -mxl-pattern-compare for -mcpu=v8.30.a");
1786 TARGET_REORDER = 0;
1789 if (TARGET_MULTIPLY_HIGH && TARGET_SOFT_MUL)
1790 error ("-mxl-multiply-high requires -mno-xl-soft-mul");
1792 /* Always use DFA scheduler. */
1793 microblaze_sched_use_dfa = 1;
1795 #if 0
1796 microblaze_abicalls = MICROBLAZE_ABICALLS_NO;
1797 #endif
1799 /* Initialize the high, low values for legit floating point constants. */
1800 real_maxval (&dfhigh, 0, DFmode);
1801 real_maxval (&dflow, 1, DFmode);
1802 real_maxval (&sfhigh, 0, SFmode);
1803 real_maxval (&sflow, 1, SFmode);
1805 microblaze_print_operand_punct['?'] = 1;
1806 microblaze_print_operand_punct['#'] = 1;
1807 microblaze_print_operand_punct['&'] = 1;
1808 microblaze_print_operand_punct['!'] = 1;
1809 microblaze_print_operand_punct['*'] = 1;
1810 microblaze_print_operand_punct['@'] = 1;
1811 microblaze_print_operand_punct['.'] = 1;
1812 microblaze_print_operand_punct['('] = 1;
1813 microblaze_print_operand_punct[')'] = 1;
1814 microblaze_print_operand_punct['['] = 1;
1815 microblaze_print_operand_punct[']'] = 1;
1816 microblaze_print_operand_punct['<'] = 1;
1817 microblaze_print_operand_punct['>'] = 1;
1818 microblaze_print_operand_punct['{'] = 1;
1819 microblaze_print_operand_punct['}'] = 1;
1820 microblaze_print_operand_punct['^'] = 1;
1821 microblaze_print_operand_punct['$'] = 1;
1822 microblaze_print_operand_punct['+'] = 1;
1824 /* Set up array to map GCC register number to debug register number.
1825 Ignore the special purpose register numbers. */
1827 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
1828 microblaze_dbx_regno[i] = -1;
1830 start = GP_DBX_FIRST - GP_REG_FIRST;
1831 for (i = GP_REG_FIRST; i <= GP_REG_LAST; i++)
1832 microblaze_dbx_regno[i] = i + start;
1834 /* Set up array giving whether a given register can hold a given mode. */
1836 for (mode = VOIDmode;
1837 mode != MAX_MACHINE_MODE; mode = (machine_mode) ((int) mode + 1))
1839 register int size = GET_MODE_SIZE (mode);
1841 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
1843 register int ok;
1845 if (mode == CCmode)
1847 ok = (ST_REG_P (regno) || GP_REG_P (regno));
1849 else if (GP_REG_P (regno))
1850 ok = ((regno & 1) == 0 || size <= UNITS_PER_WORD);
1851 else
1852 ok = 0;
1854 microblaze_hard_regno_mode_ok[(int) mode][regno] = ok;
1859 /* Return true if FUNC is an interrupt function as specified
1860 by the "interrupt_handler" attribute. */
1862 static int
1863 microblaze_interrupt_function_p (tree func)
1865 tree a;
1867 if (TREE_CODE (func) != FUNCTION_DECL)
1868 return 0;
1870 a = lookup_attribute ("interrupt_handler", DECL_ATTRIBUTES (func));
1871 return a != NULL_TREE;
1874 static int
1875 microblaze_fast_interrupt_function_p (tree func)
1877 tree a;
1879 if (TREE_CODE (func) != FUNCTION_DECL)
1880 return 0;
1882 a = lookup_attribute ("fast_interrupt", DECL_ATTRIBUTES (func));
1883 return a != NULL_TREE;
1886 microblaze_break_function_p (tree func)
1888 tree a;
1889 if (!func)
1890 return 0;
1891 if (TREE_CODE (func) != FUNCTION_DECL)
1892 return 0;
1894 a = lookup_attribute ("break_handler", DECL_ATTRIBUTES (func));
1895 return a != NULL_TREE;
1897 /* Return true if FUNC is an interrupt function which uses
1898 normal return, indicated by the "save_volatiles" attribute. */
1900 static int
1901 microblaze_save_volatiles (tree func)
1903 tree a;
1905 if (TREE_CODE (func) != FUNCTION_DECL)
1906 return 0;
1908 a = lookup_attribute ("save_volatiles", DECL_ATTRIBUTES (func));
1909 return a != NULL_TREE;
1912 /* Return whether function is tagged with 'interrupt_handler'
1913 or 'fast_interrupt' attribute. Return true if function
1914 should use return from interrupt rather than normal
1915 function return. */
1917 microblaze_is_interrupt_variant (void)
1919 return (interrupt_handler || fast_interrupt);
1922 microblaze_is_break_handler (void)
1924 return break_handler;
1927 /* Determine of register must be saved/restored in call. */
1928 static int
1929 microblaze_must_save_register (int regno)
1931 if (pic_offset_table_rtx &&
1932 (regno == MB_ABI_PIC_ADDR_REGNUM) && df_regs_ever_live_p (regno))
1933 return 1;
1935 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
1936 return 1;
1938 if (frame_pointer_needed && (regno == HARD_FRAME_POINTER_REGNUM))
1939 return 1;
1941 if (!crtl->is_leaf)
1943 if (regno == MB_ABI_SUB_RETURN_ADDR_REGNUM)
1944 return 1;
1945 if ((microblaze_is_interrupt_variant () || save_volatiles) &&
1946 (regno >= 3 && regno <= 12))
1947 return 1;
1950 if (microblaze_is_interrupt_variant ())
1952 if (df_regs_ever_live_p (regno)
1953 || regno == MB_ABI_MSR_SAVE_REG
1954 || (interrupt_handler
1955 && (regno == MB_ABI_ASM_TEMP_REGNUM
1956 || regno == MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM)))
1957 return 1;
1960 if (save_volatiles)
1962 if (df_regs_ever_live_p (regno)
1963 || regno == MB_ABI_ASM_TEMP_REGNUM
1964 || regno == MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM)
1965 return 1;
1968 return 0;
1971 /* Return the bytes needed to compute the frame pointer from the current
1972 stack pointer.
1974 MicroBlaze stack frames look like:
1978 Before call After call
1979 +-----------------------+ +-----------------------+
1980 high | | | |
1981 mem. | local variables, | | local variables, |
1982 | callee saved and | | callee saved and |
1983 | temps | | temps |
1984 +-----------------------+ +-----------------------+
1985 | arguments for called | | arguments for called |
1986 | subroutines | | subroutines |
1987 | (optional) | | (optional) |
1988 +-----------------------+ +-----------------------+
1989 | Link register | | Link register |
1990 SP->| | | |
1991 +-----------------------+ +-----------------------+
1993 | local variables, |
1994 | callee saved and |
1995 | temps |
1996 +-----------------------+
1997 | MSR (optional if, |
1998 | interrupt handler) |
1999 +-----------------------+
2001 | alloca allocations |
2003 +-----------------------+
2005 | arguments for called |
2006 | subroutines |
2007 | (optional) |
2009 +-----------------------+
2010 | Link register |
2011 low FP,SP->| |
2012 memory +-----------------------+
2016 static HOST_WIDE_INT
2017 compute_frame_size (HOST_WIDE_INT size)
2019 int regno;
2020 HOST_WIDE_INT total_size; /* # bytes that the entire frame takes up. */
2021 HOST_WIDE_INT var_size; /* # bytes that local variables take up. */
2022 HOST_WIDE_INT args_size; /* # bytes that outgoing arguments take up. */
2023 int link_debug_size; /* # bytes for link register. */
2024 HOST_WIDE_INT gp_reg_size; /* # bytes needed to store calle-saved gp regs. */
2025 long mask; /* mask of saved gp registers. */
2027 interrupt_handler =
2028 microblaze_interrupt_function_p (current_function_decl);
2029 break_handler =
2030 microblaze_break_function_p (current_function_decl);
2032 fast_interrupt =
2033 microblaze_fast_interrupt_function_p (current_function_decl);
2034 save_volatiles = microblaze_save_volatiles (current_function_decl);
2035 if (break_handler)
2036 interrupt_handler = break_handler;
2038 gp_reg_size = 0;
2039 mask = 0;
2040 var_size = size;
2041 args_size = crtl->outgoing_args_size;
2043 if ((args_size == 0) && cfun->calls_alloca)
2044 args_size = NUM_OF_ARGS * UNITS_PER_WORD;
2046 total_size = var_size + args_size;
2048 if (flag_pic == 2)
2049 /* force setting GOT. */
2050 df_set_regs_ever_live (MB_ABI_PIC_ADDR_REGNUM, true);
2052 /* Calculate space needed for gp registers. */
2053 for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
2055 if (microblaze_must_save_register (regno))
2058 if (regno != MB_ABI_SUB_RETURN_ADDR_REGNUM)
2059 /* Don't account for link register. It is accounted specially below. */
2060 gp_reg_size += GET_MODE_SIZE (SImode);
2062 mask |= (1L << (regno - GP_REG_FIRST));
2066 total_size += gp_reg_size;
2068 /* Add 4 bytes for MSR. */
2069 if (microblaze_is_interrupt_variant ())
2070 total_size += 4;
2072 /* No space to be allocated for link register in leaf functions with no other
2073 stack requirements. */
2074 if (total_size == 0 && crtl->is_leaf)
2075 link_debug_size = 0;
2076 else
2077 link_debug_size = UNITS_PER_WORD;
2079 total_size += link_debug_size;
2081 /* Save other computed information. */
2082 current_frame_info.total_size = total_size;
2083 current_frame_info.var_size = var_size;
2084 current_frame_info.args_size = args_size;
2085 current_frame_info.gp_reg_size = gp_reg_size;
2086 current_frame_info.mask = mask;
2087 current_frame_info.initialized = reload_completed;
2088 current_frame_info.num_gp = gp_reg_size / UNITS_PER_WORD;
2089 current_frame_info.link_debug_size = link_debug_size;
2091 if (mask)
2092 /* Offset from which to callee-save GP regs. */
2093 current_frame_info.gp_offset = (total_size - gp_reg_size);
2094 else
2095 current_frame_info.gp_offset = 0;
2097 /* Ok, we're done. */
2098 return total_size;
2101 /* Make sure that we're not trying to eliminate to the wrong hard frame
2102 pointer. */
2104 static bool
2105 microblaze_can_eliminate (const int from, const int to)
2107 return ((from == RETURN_ADDRESS_POINTER_REGNUM && !leaf_function_p())
2108 || (to == MB_ABI_SUB_RETURN_ADDR_REGNUM && leaf_function_p())
2109 || (from != RETURN_ADDRESS_POINTER_REGNUM
2110 && (to == HARD_FRAME_POINTER_REGNUM
2111 || (to == STACK_POINTER_REGNUM && !frame_pointer_needed))));
2114 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
2115 pointer or argument pointer or the return address pointer. TO is either
2116 the stack pointer or hard frame pointer. */
2118 HOST_WIDE_INT
2119 microblaze_initial_elimination_offset (int from, int to)
2121 HOST_WIDE_INT offset;
2123 switch (from)
2125 case FRAME_POINTER_REGNUM:
2126 offset = 0;
2127 break;
2128 case ARG_POINTER_REGNUM:
2129 if (to == STACK_POINTER_REGNUM || to == HARD_FRAME_POINTER_REGNUM)
2130 offset = compute_frame_size (get_frame_size ());
2131 else
2132 gcc_unreachable ();
2133 break;
2134 case RETURN_ADDRESS_POINTER_REGNUM:
2135 if (crtl->is_leaf)
2136 offset = 0;
2137 else
2138 offset = current_frame_info.gp_offset +
2139 ((UNITS_PER_WORD - (POINTER_SIZE / BITS_PER_UNIT)));
2140 break;
2141 default:
2142 gcc_unreachable ();
2144 return offset;
2147 /* Print operands using format code.
2149 The MicroBlaze specific codes are:
2151 'X' X is CONST_INT, prints 32 bits in hexadecimal format = "0x%08x",
2152 'x' X is CONST_INT, prints 16 bits in hexadecimal format = "0x%04x",
2153 'F' op is CONST_DOUBLE, print 32 bits in hex,
2154 'd' output integer constant in decimal,
2155 'z' if the operand is 0, use $0 instead of normal operand.
2156 'D' print second register of double-word register operand.
2157 'L' print low-order register of double-word register operand.
2158 'M' print high-order register of double-word register operand.
2159 'C' print part of opcode for a branch condition.
2160 'N' print part of opcode for a branch condition, inverted.
2161 'S' X is CODE_LABEL, print with prefix of "LS" (for embedded switch).
2162 'B' print 'z' for EQ, 'n' for NE
2163 'b' print 'n' for EQ, 'z' for NE
2164 'T' print 'f' for EQ, 't' for NE
2165 't' print 't' for EQ, 'f' for NE
2166 'm' Print 1<<operand.
2167 'i' Print 'i' if MEM operand has immediate value
2168 'y' Print 'y' if MEM operand is single register
2169 'o' Print operand address+4
2170 '?' Print 'd' if we use a branch with delay slot instead of normal branch.
2171 'h' Print high word of const_double (int or float) value as hex
2172 'j' Print low word of const_double (int or float) value as hex
2173 's' Print -1 if operand is negative, 0 if positive (sign extend)
2174 '@' Print the name of the temporary register (rMB_ABI_ASM_TEMP_REGNUM).
2175 '#' Print nop if the delay slot of a branch is not filled.
2178 void
2179 print_operand (FILE * file, rtx op, int letter)
2181 register enum rtx_code code;
2183 if (PRINT_OPERAND_PUNCT_VALID_P (letter))
2185 switch (letter)
2187 case '?':
2188 /* Conditionally add a 'd' to indicate filled delay slot. */
2189 if (final_sequence != NULL)
2190 fputs ("d", file);
2191 break;
2193 case '#':
2194 /* Conditionally add a nop in unfilled delay slot. */
2195 if (final_sequence == NULL)
2196 fputs ("nop\t\t# Unfilled delay slot\n", file);
2197 break;
2199 case '@':
2200 fputs (reg_names[GP_REG_FIRST + MB_ABI_ASM_TEMP_REGNUM], file);
2201 break;
2203 default:
2204 output_operand_lossage ("unknown punctuation '%c'", letter);
2205 break;
2208 return;
2211 if (!op)
2213 output_operand_lossage ("null pointer");
2214 return;
2217 code = GET_CODE (op);
2219 if (code == SIGN_EXTEND)
2220 op = XEXP (op, 0), code = GET_CODE (op);
2222 if (letter == 'C')
2223 switch (code)
2225 case EQ:
2226 fputs ("eq", file);
2227 break;
2228 case NE:
2229 fputs ("ne", file);
2230 break;
2231 case GT:
2232 case GTU:
2233 fputs ("gt", file);
2234 break;
2235 case GE:
2236 case GEU:
2237 fputs ("ge", file);
2238 break;
2239 case LT:
2240 case LTU:
2241 fputs ("lt", file);
2242 break;
2243 case LE:
2244 case LEU:
2245 fputs ("le", file);
2246 break;
2247 default:
2248 fatal_insn ("PRINT_OPERAND, invalid insn for %%C", op);
2251 else if (letter == 'N')
2252 switch (code)
2254 case EQ:
2255 fputs ("ne", file);
2256 break;
2257 case NE:
2258 fputs ("eq", file);
2259 break;
2260 case GT:
2261 case GTU:
2262 fputs ("le", file);
2263 break;
2264 case GE:
2265 case GEU:
2266 fputs ("lt", file);
2267 break;
2268 case LT:
2269 case LTU:
2270 fputs ("ge", file);
2271 break;
2272 case LE:
2273 case LEU:
2274 fputs ("gt", file);
2275 break;
2276 default:
2277 fatal_insn ("PRINT_OPERAND, invalid insn for %%N", op);
2280 else if (letter == 'S')
2282 char buffer[100];
2284 ASM_GENERATE_INTERNAL_LABEL (buffer, "LS", CODE_LABEL_NUMBER (op));
2285 assemble_name (file, buffer);
2288 /* Print 'i' for memory operands which have immediate values. */
2289 else if (letter == 'i')
2291 if (code == MEM)
2293 struct microblaze_address_info info;
2295 if (!microblaze_classify_address
2296 (&info, XEXP (op, 0), GET_MODE (op), 1))
2297 fatal_insn ("insn contains an invalid address !", op);
2299 switch (info.type)
2301 case ADDRESS_REG:
2302 case ADDRESS_CONST_INT:
2303 case ADDRESS_SYMBOLIC:
2304 case ADDRESS_GOTOFF:
2305 case ADDRESS_TLS:
2306 fputs ("i", file);
2307 break;
2308 case ADDRESS_REG_INDEX:
2309 break;
2310 case ADDRESS_INVALID:
2311 case ADDRESS_PLT:
2312 fatal_insn ("invalid address", op);
2317 else if (code == REG || code == SUBREG)
2319 register int regnum;
2321 if (code == REG)
2322 regnum = REGNO (op);
2323 else
2324 regnum = true_regnum (op);
2326 if ((letter == 'M' && !WORDS_BIG_ENDIAN)
2327 || (letter == 'L' && WORDS_BIG_ENDIAN) || letter == 'D')
2328 regnum++;
2330 fprintf (file, "%s", reg_names[regnum]);
2333 else if (code == MEM)
2334 if (letter == 'o')
2336 rtx op4 = adjust_address (op, GET_MODE (op), 4);
2337 output_address (XEXP (op4, 0));
2339 else if (letter == 'y')
2341 rtx mem_reg = XEXP (op, 0);
2342 if (GET_CODE (mem_reg) == REG)
2344 register int regnum = REGNO (mem_reg);
2345 fprintf (file, "%s", reg_names[regnum]);
2348 else
2349 output_address (XEXP (op, 0));
2351 else if (letter == 'h' || letter == 'j')
2353 long val[2];
2354 if (code == CONST_DOUBLE)
2356 if (GET_MODE (op) == DFmode)
2358 REAL_VALUE_TYPE value;
2359 REAL_VALUE_FROM_CONST_DOUBLE (value, op);
2360 REAL_VALUE_TO_TARGET_DOUBLE (value, val);
2362 else
2364 val[0] = CONST_DOUBLE_HIGH (op);
2365 val[1] = CONST_DOUBLE_LOW (op);
2368 else if (code == CONST_INT)
2370 val[0] = (INTVAL (op) & 0xffffffff00000000LL) >> 32;
2371 val[1] = INTVAL (op) & 0x00000000ffffffffLL;
2372 if (val[0] == 0 && val[1] < 0)
2373 val[0] = -1;
2376 fprintf (file, "0x%8.8lx", (letter == 'h') ? val[0] : val[1]);
2378 else if (code == CONST_DOUBLE)
2380 if (letter == 'F')
2382 unsigned long value_long;
2383 REAL_VALUE_TYPE value;
2384 REAL_VALUE_FROM_CONST_DOUBLE (value, op);
2385 REAL_VALUE_TO_TARGET_SINGLE (value, value_long);
2386 fprintf (file, HOST_WIDE_INT_PRINT_HEX, value_long);
2388 else
2390 char s[60];
2391 real_to_decimal (s, CONST_DOUBLE_REAL_VALUE (op), sizeof (s), 0, 1);
2392 fputs (s, file);
2396 else if (code == UNSPEC)
2398 print_operand_address (file, op);
2401 else if (letter == 'x' && GET_CODE (op) == CONST_INT)
2402 fprintf (file, HOST_WIDE_INT_PRINT_HEX, 0xffff & INTVAL (op));
2404 else if (letter == 'X' && GET_CODE (op) == CONST_INT)
2405 fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (op));
2407 else if (letter == 'd' && GET_CODE (op) == CONST_INT)
2408 fprintf (file, HOST_WIDE_INT_PRINT_DEC, (INTVAL (op)));
2410 else if (letter == 'z' && GET_CODE (op) == CONST_INT && INTVAL (op) == 0)
2411 fputs (reg_names[GP_REG_FIRST], file);
2413 else if (letter == 's' && GET_CODE (op) == CONST_INT)
2414 if (INTVAL (op) < 0)
2415 fputs ("-1", file);
2416 else
2417 fputs ("0", file);
2419 else if (letter == 'd' || letter == 'x' || letter == 'X' || letter == 's')
2420 output_operand_lossage ("letter %c was found & insn was not CONST_INT", letter);
2422 else if (letter == 'B')
2423 fputs (code == EQ ? "z" : "n", file);
2424 else if (letter == 'b')
2425 fputs (code == EQ ? "n" : "z", file);
2426 else if (letter == 'T')
2427 fputs (code == EQ ? "f" : "t", file);
2428 else if (letter == 't')
2429 fputs (code == EQ ? "t" : "f", file);
2431 else if (code == CONST
2432 && ((GET_CODE (XEXP (op, 0)) == REG)
2433 || (GET_CODE (XEXP (op, 0)) == UNSPEC)))
2435 print_operand (file, XEXP (op, 0), letter);
2437 else if (code == CONST
2438 && (GET_CODE (XEXP (op, 0)) == PLUS)
2439 && (GET_CODE (XEXP (XEXP (op, 0), 0)) == REG)
2440 && (GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST))
2442 print_operand_address (file, XEXP (op, 0));
2444 else if (letter == 'm')
2445 fprintf (file, HOST_WIDE_INT_PRINT_DEC, (1L << INTVAL (op)));
2446 else
2447 output_addr_const (file, op);
2450 /* A C compound statement to output to stdio stream STREAM the
2451 assembler syntax for an instruction operand that is a memory
2452 reference whose address is ADDR. ADDR is an RTL expression.
2454 Possible address classifications and output formats are,
2456 ADDRESS_REG "%0, r0"
2458 ADDRESS_REG with non-zero "%0, <addr_const>"
2459 offset
2461 ADDRESS_REG_INDEX "rA, RB"
2462 (if rA is r0, rA and rB are swapped)
2464 ADDRESS_CONST_INT "r0, <addr_const>"
2466 ADDRESS_SYMBOLIC "rBase, <addr_const>"
2467 (rBase is a base register suitable for the
2468 symbol's type)
2471 void
2472 print_operand_address (FILE * file, rtx addr)
2474 struct microblaze_address_info info;
2475 enum microblaze_address_type type;
2476 if (!microblaze_classify_address (&info, addr, GET_MODE (addr), 1))
2477 fatal_insn ("insn contains an invalid address !", addr);
2479 type = info.type;
2480 switch (info.type)
2482 case ADDRESS_REG:
2483 fprintf (file, "%s,", reg_names[REGNO (info.regA)]);
2484 output_addr_const (file, info.offset);
2485 break;
2486 case ADDRESS_REG_INDEX:
2487 if (REGNO (info.regA) == 0)
2488 /* Make rB == r0 instead of rA == r0. This helps reduce read port
2489 congestion. */
2490 fprintf (file, "%s,%s", reg_names[REGNO (info.regB)],
2491 reg_names[REGNO (info.regA)]);
2492 else if (REGNO (info.regB) != 0)
2493 /* This is a silly swap to help Dhrystone. */
2494 fprintf (file, "%s,%s", reg_names[REGNO (info.regB)],
2495 reg_names[REGNO (info.regA)]);
2496 break;
2497 case ADDRESS_CONST_INT:
2498 fprintf (file, "%s,", reg_names[REGNO (info.regA)]);
2499 output_addr_const (file, info.offset);
2500 break;
2501 case ADDRESS_SYMBOLIC:
2502 case ADDRESS_GOTOFF:
2503 case ADDRESS_PLT:
2504 case ADDRESS_TLS:
2505 if (info.regA)
2506 fprintf (file, "%s,", reg_names[REGNO (info.regA)]);
2507 output_addr_const (file, info.symbol);
2508 if (type == ADDRESS_GOTOFF)
2510 fputs ("@GOT", file);
2512 else if (type == ADDRESS_PLT)
2514 fputs ("@PLT", file);
2516 else if (type == ADDRESS_TLS)
2518 switch (info.tls_type)
2520 case TLS_GD:
2521 fputs ("@TLSGD", file);
2522 break;
2523 case TLS_LDM:
2524 fputs ("@TLSLDM", file);
2525 break;
2526 case TLS_DTPREL:
2527 fputs ("@TLSDTPREL", file);
2528 break;
2529 default :
2530 abort();
2531 break;
2534 break;
2535 case ADDRESS_INVALID:
2536 fatal_insn ("invalid address", addr);
2537 break;
2541 /* Emit either a label, .comm, or .lcomm directive, and mark that the symbol
2542 is used, so that we don't emit an .extern for it in
2543 microblaze_asm_file_end. */
2545 void
2546 microblaze_declare_object (FILE * stream, const char *name,
2547 const char *section, const char *fmt, int size)
2550 fputs (section, stream);
2551 assemble_name (stream, name);
2552 fprintf (stream, fmt, size);
2555 /* Common code to emit the insns (or to write the instructions to a file)
2556 to save/restore registers.
2558 Other parts of the code assume that MICROBLAZE_TEMP1_REGNUM (aka large_reg)
2559 is not modified within save_restore_insns. */
2561 #define BITSET_P(VALUE,BIT) (((VALUE) & (1L << (BIT))) != 0)
2563 /* Save or restore instructions based on whether this is the prologue or
2564 epilogue. prologue is 1 for the prologue. */
2565 static void
2566 save_restore_insns (int prologue)
2568 rtx base_reg_rtx, reg_rtx, mem_rtx, /* msr_rtx, */ isr_reg_rtx =
2569 0, isr_mem_rtx = 0;
2570 rtx isr_msr_rtx = 0, insn;
2571 long mask = current_frame_info.mask;
2572 HOST_WIDE_INT gp_offset;
2573 int regno;
2575 if (frame_pointer_needed
2576 && !BITSET_P (mask, HARD_FRAME_POINTER_REGNUM - GP_REG_FIRST))
2577 gcc_unreachable ();
2579 if (mask == 0)
2580 return;
2582 /* Save registers starting from high to low. The debuggers prefer at least
2583 the return register be stored at func+4, and also it allows us not to
2584 need a nop in the epilog if at least one register is reloaded in
2585 addition to return address. */
2587 /* Pick which pointer to use as a base register. For small frames, just
2588 use the stack pointer. Otherwise, use a temporary register. Save 2
2589 cycles if the save area is near the end of a large frame, by reusing
2590 the constant created in the prologue/epilogue to adjust the stack
2591 frame. */
2593 gp_offset = current_frame_info.gp_offset;
2595 gcc_assert (gp_offset > 0);
2597 base_reg_rtx = stack_pointer_rtx;
2599 /* For interrupt_handlers, need to save/restore the MSR. */
2600 if (microblaze_is_interrupt_variant ())
2602 isr_mem_rtx = gen_rtx_MEM (SImode,
2603 gen_rtx_PLUS (Pmode, base_reg_rtx,
2604 GEN_INT (current_frame_info.
2605 gp_offset -
2606 UNITS_PER_WORD)));
2608 /* Do not optimize in flow analysis. */
2609 MEM_VOLATILE_P (isr_mem_rtx) = 1;
2610 isr_reg_rtx = gen_rtx_REG (SImode, MB_ABI_MSR_SAVE_REG);
2611 isr_msr_rtx = gen_rtx_REG (SImode, ST_REG);
2614 if (microblaze_is_interrupt_variant () && !prologue)
2616 emit_move_insn (isr_reg_rtx, isr_mem_rtx);
2617 emit_move_insn (isr_msr_rtx, isr_reg_rtx);
2618 /* Do not optimize in flow analysis. */
2619 emit_insn (gen_rtx_USE (SImode, isr_reg_rtx));
2620 emit_insn (gen_rtx_USE (SImode, isr_msr_rtx));
2623 for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
2625 if (BITSET_P (mask, regno - GP_REG_FIRST))
2627 if (regno == MB_ABI_SUB_RETURN_ADDR_REGNUM)
2628 /* Don't handle here. Already handled as the first register. */
2629 continue;
2631 reg_rtx = gen_rtx_REG (SImode, regno);
2632 insn = gen_rtx_PLUS (Pmode, base_reg_rtx, GEN_INT (gp_offset));
2633 mem_rtx = gen_rtx_MEM (SImode, insn);
2634 if (microblaze_is_interrupt_variant () || save_volatiles)
2635 /* Do not optimize in flow analysis. */
2636 MEM_VOLATILE_P (mem_rtx) = 1;
2638 if (prologue)
2640 insn = emit_move_insn (mem_rtx, reg_rtx);
2641 RTX_FRAME_RELATED_P (insn) = 1;
2643 else
2645 insn = emit_move_insn (reg_rtx, mem_rtx);
2648 gp_offset += GET_MODE_SIZE (SImode);
2652 if (microblaze_is_interrupt_variant () && prologue)
2654 emit_move_insn (isr_reg_rtx, isr_msr_rtx);
2655 emit_move_insn (isr_mem_rtx, isr_reg_rtx);
2657 /* Do not optimize in flow analysis. */
2658 emit_insn (gen_rtx_USE (SImode, isr_reg_rtx));
2659 emit_insn (gen_rtx_USE (SImode, isr_msr_rtx));
2662 /* Done saving and restoring */
2666 /* Set up the stack and frame (if desired) for the function. */
2667 static void
2668 microblaze_function_prologue (FILE * file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
2670 const char *fnname;
2671 long fsiz = current_frame_info.total_size;
2673 /* Get the function name the same way that toplev.c does before calling
2674 assemble_start_function. This is needed so that the name used here
2675 exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */
2676 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
2677 if (!flag_inhibit_size_directive)
2679 fputs ("\t.ent\t", file);
2680 if (interrupt_handler && strcmp (INTERRUPT_HANDLER_NAME, fnname))
2681 fputs ("_interrupt_handler", file);
2682 else if (break_handler && strcmp (BREAK_HANDLER_NAME, fnname))
2683 fputs ("_break_handler", file);
2684 else if (fast_interrupt && strcmp (FAST_INTERRUPT_NAME, fnname))
2685 fputs ("_fast_interrupt", file);
2686 else
2687 assemble_name (file, fnname);
2688 fputs ("\n", file);
2689 if (!microblaze_is_interrupt_variant ())
2690 ASM_OUTPUT_TYPE_DIRECTIVE (file, fnname, "function");
2693 assemble_name (file, fnname);
2694 fputs (":\n", file);
2696 if (interrupt_handler && strcmp (INTERRUPT_HANDLER_NAME, fnname))
2697 fputs ("_interrupt_handler:\n", file);
2698 if (break_handler && strcmp (BREAK_HANDLER_NAME, fnname))
2699 fputs ("_break_handler:\n", file);
2700 if (!flag_inhibit_size_directive)
2702 /* .frame FRAMEREG, FRAMESIZE, RETREG. */
2703 fprintf (file,
2704 "\t.frame\t%s,%ld,%s\t\t# vars= %ld, regs= %d, args= %d\n",
2705 (reg_names[(frame_pointer_needed)
2706 ? HARD_FRAME_POINTER_REGNUM :
2707 STACK_POINTER_REGNUM]), fsiz,
2708 reg_names[MB_ABI_SUB_RETURN_ADDR_REGNUM + GP_REG_FIRST],
2709 current_frame_info.var_size, current_frame_info.num_gp,
2710 crtl->outgoing_args_size);
2711 fprintf (file, "\t.mask\t0x%08lx\n", current_frame_info.mask);
2715 /* Output extra assembler code at the end of a prologue. */
2716 static void
2717 microblaze_function_end_prologue (FILE * file)
2719 if (TARGET_STACK_CHECK)
2721 fprintf (file, "\t# Stack Check Stub -- Start.\n\t");
2722 fprintf (file, "ori\tr18,r0,_stack_end\n\t");
2723 fprintf (file, "cmpu\tr18,r1,r18\n\t");
2724 fprintf (file, "bgei\tr18,_stack_overflow_exit\n\t");
2725 fprintf (file, "# Stack Check Stub -- End.\n");
2729 static void
2730 microblaze_elf_asm_cdtor (rtx symbol, int priority, bool is_ctor)
2732 section *s;
2734 if (priority != DEFAULT_INIT_PRIORITY)
2736 char buf[18];
2737 sprintf (buf, "%s.%.5u",
2738 is_ctor ? ".ctors" : ".dtors",
2739 MAX_INIT_PRIORITY - priority);
2740 s = get_section (buf, SECTION_WRITE, NULL_TREE);
2742 else if (is_ctor)
2743 s = ctors_section;
2744 else
2745 s = dtors_section;
2747 switch_to_section (s);
2748 assemble_align (POINTER_SIZE);
2749 fputs ("\t.word\t", asm_out_file);
2750 output_addr_const (asm_out_file, symbol);
2751 fputs ("\n", asm_out_file);
2754 /* Add a function to the list of static constructors. */
2756 static void
2757 microblaze_elf_asm_constructor (rtx symbol, int priority)
2759 microblaze_elf_asm_cdtor (symbol, priority, /*is_ctor=*/true);
2762 /* Add a function to the list of static destructors. */
2764 static void
2765 microblaze_elf_asm_destructor (rtx symbol, int priority)
2767 microblaze_elf_asm_cdtor (symbol, priority, /*is_ctor=*/false);
2770 /* Expand the prologue into a bunch of separate insns. */
2772 void
2773 microblaze_expand_prologue (void)
2775 int regno;
2776 HOST_WIDE_INT fsiz;
2777 const char *arg_name = 0;
2778 tree fndecl = current_function_decl;
2779 tree fntype = TREE_TYPE (fndecl);
2780 tree fnargs = DECL_ARGUMENTS (fndecl);
2781 rtx next_arg_reg;
2782 int i;
2783 tree next_arg;
2784 tree cur_arg;
2785 CUMULATIVE_ARGS args_so_far_v;
2786 cumulative_args_t args_so_far;
2787 rtx mem_rtx, reg_rtx;
2789 /* If struct value address is treated as the first argument, make it so. */
2790 if (aggregate_value_p (DECL_RESULT (fndecl), fntype)
2791 && !cfun->returns_pcc_struct)
2793 tree type = build_pointer_type (fntype);
2794 tree function_result_decl = build_decl (BUILTINS_LOCATION, PARM_DECL,
2795 NULL_TREE, type);
2797 DECL_ARG_TYPE (function_result_decl) = type;
2798 TREE_CHAIN (function_result_decl) = fnargs;
2799 fnargs = function_result_decl;
2802 /* Determine the last argument, and get its name. */
2804 INIT_CUMULATIVE_ARGS (args_so_far_v, fntype, NULL_RTX, 0, 0);
2805 args_so_far = pack_cumulative_args (&args_so_far_v);
2806 regno = GP_ARG_FIRST;
2808 for (cur_arg = fnargs; cur_arg != 0; cur_arg = next_arg)
2810 tree passed_type = DECL_ARG_TYPE (cur_arg);
2811 machine_mode passed_mode = TYPE_MODE (passed_type);
2812 rtx entry_parm;
2814 if (TREE_ADDRESSABLE (passed_type))
2816 passed_type = build_pointer_type (passed_type);
2817 passed_mode = Pmode;
2820 entry_parm = targetm.calls.function_arg (args_so_far, passed_mode,
2821 passed_type, true);
2823 if (entry_parm)
2825 int words;
2827 /* passed in a register, so will get homed automatically. */
2828 if (GET_MODE (entry_parm) == BLKmode)
2829 words = (int_size_in_bytes (passed_type) + 3) / 4;
2830 else
2831 words = (GET_MODE_SIZE (GET_MODE (entry_parm)) + 3) / 4;
2833 regno = REGNO (entry_parm) + words - 1;
2835 else
2837 regno = GP_ARG_LAST + 1;
2838 break;
2841 targetm.calls.function_arg_advance (args_so_far, passed_mode,
2842 passed_type, true);
2844 next_arg = TREE_CHAIN (cur_arg);
2845 if (next_arg == 0)
2847 if (DECL_NAME (cur_arg))
2848 arg_name = IDENTIFIER_POINTER (DECL_NAME (cur_arg));
2850 break;
2854 /* Split parallel insn into a sequence of insns. */
2856 next_arg_reg = targetm.calls.function_arg (args_so_far, VOIDmode,
2857 void_type_node, true);
2858 if (next_arg_reg != 0 && GET_CODE (next_arg_reg) == PARALLEL)
2860 rtvec adjust = XVEC (next_arg_reg, 0);
2861 int num = GET_NUM_ELEM (adjust);
2863 for (i = 0; i < num; i++)
2865 rtx pattern = RTVEC_ELT (adjust, i);
2866 emit_insn (pattern);
2870 fsiz = compute_frame_size (get_frame_size ());
2872 if (flag_stack_usage_info)
2873 current_function_static_stack_size = fsiz;
2876 /* If this function is a varargs function, store any registers that
2877 would normally hold arguments ($5 - $10) on the stack. */
2878 if (((TYPE_ARG_TYPES (fntype) != 0
2879 && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
2880 != void_type_node))
2881 || (arg_name != 0
2882 && ((arg_name[0] == '_'
2883 && strcmp (arg_name, "__builtin_va_alist") == 0)
2884 || (arg_name[0] == 'v'
2885 && strcmp (arg_name, "va_alist") == 0)))))
2887 int offset = (regno - GP_ARG_FIRST + 1) * UNITS_PER_WORD;
2888 rtx ptr = stack_pointer_rtx;
2890 /* If we are doing svr4-abi, sp has already been decremented by fsiz. */
2891 for (; regno <= GP_ARG_LAST; regno++)
2893 if (offset != 0)
2894 ptr = gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (offset));
2895 emit_move_insn (gen_rtx_MEM (SImode, ptr),
2896 gen_rtx_REG (SImode, regno));
2898 offset += GET_MODE_SIZE (SImode);
2903 if (fsiz > 0)
2905 rtx fsiz_rtx = GEN_INT (fsiz);
2907 rtx_insn *insn = NULL;
2908 insn = emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx,
2909 fsiz_rtx));
2910 if (insn)
2911 RTX_FRAME_RELATED_P (insn) = 1;
2913 /* Handle SUB_RETURN_ADDR_REGNUM specially at first. */
2914 if (!crtl->is_leaf || interrupt_handler)
2916 mem_rtx = gen_rtx_MEM (SImode,
2917 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
2918 const0_rtx));
2920 if (interrupt_handler)
2921 /* Do not optimize in flow analysis. */
2922 MEM_VOLATILE_P (mem_rtx) = 1;
2924 reg_rtx = gen_rtx_REG (SImode, MB_ABI_SUB_RETURN_ADDR_REGNUM);
2925 insn = emit_move_insn (mem_rtx, reg_rtx);
2926 RTX_FRAME_RELATED_P (insn) = 1;
2929 /* _save_ registers for prologue. */
2930 save_restore_insns (1);
2932 if (frame_pointer_needed)
2934 rtx_insn *insn = 0;
2936 insn = emit_insn (gen_movsi (hard_frame_pointer_rtx,
2937 stack_pointer_rtx));
2939 if (insn)
2940 RTX_FRAME_RELATED_P (insn) = 1;
2944 if ((flag_pic == 2 || TLS_NEEDS_GOT )
2945 && df_regs_ever_live_p (MB_ABI_PIC_ADDR_REGNUM))
2947 SET_REGNO (pic_offset_table_rtx, MB_ABI_PIC_ADDR_REGNUM);
2948 emit_insn (gen_set_got (pic_offset_table_rtx)); /* setting GOT. */
2951 /* If we are profiling, make sure no instructions are scheduled before
2952 the call to mcount. */
2954 if (profile_flag)
2955 emit_insn (gen_blockage ());
2958 /* Do necessary cleanup after a function to restore stack, frame, and regs. */
2960 #define RA_MASK ((long) 0x80000000) /* 1 << 31 */
2961 #define PIC_OFFSET_TABLE_MASK (1 << (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST))
2963 static void
2964 microblaze_function_epilogue (FILE * file ATTRIBUTE_UNUSED,
2965 HOST_WIDE_INT size ATTRIBUTE_UNUSED)
2967 const char *fnname;
2969 /* Get the function name the same way that toplev.c does before calling
2970 assemble_start_function. This is needed so that the name used here
2971 exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */
2972 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
2974 if (!flag_inhibit_size_directive)
2976 fputs ("\t.end\t", file);
2977 if (interrupt_handler && !break_handler)
2978 fputs ("_interrupt_handler", file);
2979 else if (break_handler)
2980 fputs ("_break_handler", file);
2981 else
2982 assemble_name (file, fnname);
2983 fputs ("\n", file);
2986 /* Reset state info for each function. */
2987 current_frame_info = zero_frame_info;
2989 /* Restore the output file if optimizing the GP (optimizing the GP causes
2990 the text to be diverted to a tempfile, so that data decls come before
2991 references to the data). */
2994 /* Expand the epilogue into a bunch of separate insns. */
2996 void
2997 microblaze_expand_epilogue (void)
2999 HOST_WIDE_INT fsiz = current_frame_info.total_size;
3000 rtx fsiz_rtx = GEN_INT (fsiz);
3001 rtx reg_rtx;
3002 rtx mem_rtx;
3004 /* In case of interrupt handlers use addki instead of addi for changing the
3005 stack pointer value. */
3007 if (microblaze_can_use_return_insn ())
3009 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode,
3010 GP_REG_FIRST +
3011 MB_ABI_SUB_RETURN_ADDR_REGNUM)));
3012 return;
3015 if (fsiz > 0)
3017 /* Restore SUB_RETURN_ADDR_REGNUM at first. This is to prevent the
3018 sequence of load-followed by a use (in rtsd) in every prologue. Saves
3019 a load-use stall cycle :) This is also important to handle alloca.
3020 (See comments for if (frame_pointer_needed) below. */
3022 if (!crtl->is_leaf || interrupt_handler)
3024 mem_rtx =
3025 gen_rtx_MEM (SImode,
3026 gen_rtx_PLUS (Pmode, stack_pointer_rtx, const0_rtx));
3027 if (interrupt_handler)
3028 /* Do not optimize in flow analysis. */
3029 MEM_VOLATILE_P (mem_rtx) = 1;
3030 reg_rtx = gen_rtx_REG (SImode, MB_ABI_SUB_RETURN_ADDR_REGNUM);
3031 emit_move_insn (reg_rtx, mem_rtx);
3034 /* It is important that this is done after we restore the return address
3035 register (above). When alloca is used, we want to restore the
3036 sub-routine return address only from the current stack top and not
3037 from the frame pointer (which we restore below). (frame_pointer + 0)
3038 might have been over-written since alloca allocates memory on the
3039 current stack. */
3040 if (frame_pointer_needed)
3041 emit_insn (gen_movsi (stack_pointer_rtx, hard_frame_pointer_rtx));
3043 /* _restore_ registers for epilogue. */
3044 save_restore_insns (0);
3045 emit_insn (gen_blockage ());
3046 emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, fsiz_rtx));
3049 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode, GP_REG_FIRST +
3050 MB_ABI_SUB_RETURN_ADDR_REGNUM)));
3054 /* Return nonzero if this function is known to have a null epilogue.
3055 This allows the optimizer to omit jumps to jumps if no stack
3056 was created. */
3059 microblaze_can_use_return_insn (void)
3061 if (!reload_completed)
3062 return 0;
3064 if (df_regs_ever_live_p (MB_ABI_SUB_RETURN_ADDR_REGNUM) || profile_flag)
3065 return 0;
3067 if (current_frame_info.initialized)
3068 return current_frame_info.total_size == 0;
3070 return compute_frame_size (get_frame_size ()) == 0;
3073 /* Implement TARGET_SECONDARY_RELOAD. */
3075 static reg_class_t
3076 microblaze_secondary_reload (bool in_p ATTRIBUTE_UNUSED, rtx x ATTRIBUTE_UNUSED,
3077 reg_class_t rclass, machine_mode mode ATTRIBUTE_UNUSED,
3078 secondary_reload_info *sri ATTRIBUTE_UNUSED)
3080 if (rclass == ST_REGS)
3081 return GR_REGS;
3083 return NO_REGS;
3086 static void
3087 microblaze_globalize_label (FILE * stream, const char *name)
3089 fputs ("\t.globl\t", stream);
3090 if (microblaze_is_interrupt_variant ())
3092 if (interrupt_handler && strcmp (name, INTERRUPT_HANDLER_NAME))
3093 fputs (INTERRUPT_HANDLER_NAME, stream);
3094 else if (break_handler && strcmp (name, BREAK_HANDLER_NAME))
3095 fputs (BREAK_HANDLER_NAME, stream);
3096 else if (fast_interrupt && strcmp (name, FAST_INTERRUPT_NAME))
3097 fputs (FAST_INTERRUPT_NAME, stream);
3098 fputs ("\n\t.globl\t", stream);
3100 assemble_name (stream, name);
3101 fputs ("\n", stream);
3104 /* Returns true if decl should be placed into a "small data" section. */
3105 static bool
3106 microblaze_elf_in_small_data_p (const_tree decl)
3108 HOST_WIDE_INT size;
3110 if (!TARGET_XLGPOPT)
3111 return false;
3113 /* We want to merge strings, so we never consider them small data. */
3114 if (TREE_CODE (decl) == STRING_CST)
3115 return false;
3117 /* Functions are never in the small data area. */
3118 if (TREE_CODE (decl) == FUNCTION_DECL)
3119 return false;
3121 if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl))
3123 const char *section = DECL_SECTION_NAME (decl);
3124 if (strcmp (section, ".sdata") == 0
3125 || strcmp (section, ".sdata2") == 0
3126 || strcmp (section, ".sbss") == 0
3127 || strcmp (section, ".sbss2") == 0)
3128 return true;
3131 size = int_size_in_bytes (TREE_TYPE (decl));
3133 return (size > 0 && size <= microblaze_section_threshold);
3137 static section *
3138 microblaze_select_section (tree decl, int reloc, unsigned HOST_WIDE_INT align)
3140 switch (categorize_decl_for_section (decl, reloc))
3142 case SECCAT_RODATA_MERGE_STR:
3143 case SECCAT_RODATA_MERGE_STR_INIT:
3144 /* MB binutils have various issues with mergeable string sections and
3145 relaxation/relocation. Currently, turning mergeable sections
3146 into regular readonly sections. */
3148 return readonly_data_section;
3149 default:
3150 return default_elf_select_section (decl, reloc, align);
3155 Encode info about sections into the RTL based on a symbol's declaration.
3156 The default definition of this hook, default_encode_section_info in
3157 `varasm.c', sets a number of commonly-useful bits in SYMBOL_REF_FLAGS. */
3159 static void
3160 microblaze_encode_section_info (tree decl, rtx rtl, int first)
3162 default_encode_section_info (decl, rtl, first);
3165 static rtx
3166 expand_pic_symbol_ref (machine_mode mode ATTRIBUTE_UNUSED, rtx op)
3168 rtx result;
3169 result = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op), UNSPEC_GOTOFF);
3170 result = gen_rtx_CONST (Pmode, result);
3171 result = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, result);
3172 result = gen_const_mem (Pmode, result);
3173 return result;
3176 static void
3177 microblaze_asm_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
3178 HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
3179 tree function)
3181 rtx this_rtx, funexp;
3182 rtx_insn *insn;
3184 reload_completed = 1;
3185 epilogue_completed = 1;
3187 /* Mark the end of the (empty) prologue. */
3188 emit_note (NOTE_INSN_PROLOGUE_END);
3190 /* Find the "this" pointer. If the function returns a structure,
3191 the structure return pointer is in MB_ABI_FIRST_ARG_REGNUM. */
3192 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
3193 this_rtx = gen_rtx_REG (Pmode, (MB_ABI_FIRST_ARG_REGNUM + 1));
3194 else
3195 this_rtx = gen_rtx_REG (Pmode, MB_ABI_FIRST_ARG_REGNUM);
3197 /* Apply the constant offset, if required. */
3198 if (delta)
3199 emit_insn (gen_addsi3 (this_rtx, this_rtx, GEN_INT (delta)));
3201 /* Apply the offset from the vtable, if required. */
3202 if (vcall_offset)
3204 rtx vcall_offset_rtx = GEN_INT (vcall_offset);
3205 rtx temp1 = gen_rtx_REG (Pmode, MB_ABI_TEMP1_REGNUM);
3207 emit_move_insn (temp1, gen_rtx_MEM (Pmode, this_rtx));
3209 rtx loc = gen_rtx_PLUS (Pmode, temp1, vcall_offset_rtx);
3210 emit_move_insn (temp1, gen_rtx_MEM (Pmode, loc));
3212 emit_insn (gen_addsi3 (this_rtx, this_rtx, temp1));
3215 /* Generate a tail call to the target function. */
3216 if (!TREE_USED (function))
3218 assemble_external (function);
3219 TREE_USED (function) = 1;
3222 funexp = XEXP (DECL_RTL (function), 0);
3223 rtx temp2 = gen_rtx_REG (Pmode, MB_ABI_TEMP2_REGNUM);
3225 if (flag_pic)
3226 emit_move_insn (temp2, expand_pic_symbol_ref (Pmode, funexp));
3227 else
3228 emit_move_insn (temp2, funexp);
3230 emit_insn (gen_indirect_jump (temp2));
3232 /* Run just enough of rest_of_compilation. This sequence was
3233 "borrowed" from rs6000.c. */
3234 insn = get_insns ();
3235 shorten_branches (insn);
3236 final_start_function (insn, file, 1);
3237 final (insn, file, 1);
3238 final_end_function ();
3240 reload_completed = 0;
3241 epilogue_completed = 0;
3244 bool
3245 microblaze_expand_move (machine_mode mode, rtx operands[])
3247 rtx op0, op1;
3249 op0 = operands[0];
3250 op1 = operands[1];
3252 if (!register_operand (op0, SImode)
3253 && !register_operand (op1, SImode)
3254 && (GET_CODE (op1) != CONST_INT || INTVAL (op1) != 0))
3256 rtx temp = force_reg (SImode, op1);
3257 emit_move_insn (op0, temp);
3258 return true;
3260 /* If operands[1] is a constant address invalid for pic, then we need to
3261 handle it just like LEGITIMIZE_ADDRESS does. */
3262 if (GET_CODE (op1) == SYMBOL_REF || GET_CODE (op1) == LABEL_REF)
3264 rtx result;
3265 if (microblaze_tls_symbol_p(op1))
3267 result = microblaze_legitimize_tls_address (op1, NULL_RTX);
3268 emit_move_insn (op0, result);
3269 return true;
3271 else if (flag_pic)
3273 if (reload_in_progress)
3274 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
3275 result = expand_pic_symbol_ref (mode, op1);
3276 emit_move_insn (op0, result);
3277 return true;
3280 /* Handle Case of (const (plus symbol const_int)). */
3281 if (GET_CODE (op1) == CONST && GET_CODE (XEXP (op1,0)) == PLUS)
3283 rtx p0, p1;
3285 p0 = XEXP (XEXP (op1, 0), 0);
3286 p1 = XEXP (XEXP (op1, 0), 1);
3288 if ((GET_CODE (p1) == CONST_INT)
3289 && ((GET_CODE (p0) == UNSPEC)
3290 || ((GET_CODE (p0) == SYMBOL_REF || GET_CODE (p0) == LABEL_REF)
3291 && (flag_pic == 2 || microblaze_tls_symbol_p (p0)
3292 || !SMALL_INT (p1)))))
3294 rtx temp = force_reg (SImode, p0);
3295 rtx temp2 = p1;
3297 if (flag_pic && reload_in_progress)
3298 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
3299 emit_move_insn (op0, gen_rtx_PLUS (SImode, temp, temp2));
3300 return true;
3303 return false;
3306 /* Expand shift operations. */
3308 microblaze_expand_shift (rtx operands[])
3310 gcc_assert ((GET_CODE (operands[2]) == CONST_INT)
3311 || (GET_CODE (operands[2]) == REG)
3312 || (GET_CODE (operands[2]) == SUBREG));
3314 /* Shift by one -- generate pattern. */
3315 if ((GET_CODE (operands[2]) == CONST_INT) && (INTVAL (operands[2]) == 1))
3316 return 0;
3318 /* Have barrel shifter and shift > 1: use it. */
3319 if (TARGET_BARREL_SHIFT)
3320 return 0;
3322 gcc_assert ((GET_CODE (operands[0]) == REG)
3323 || (GET_CODE (operands[0]) == SUBREG)
3324 || (GET_CODE (operands[1]) == REG)
3325 || (GET_CODE (operands[1]) == SUBREG));
3327 /* Shift by zero -- copy regs if necessary. */
3328 if ((GET_CODE (operands[2]) == CONST_INT) && (INTVAL (operands[2]) == 0))
3330 if (REGNO (operands[0]) != REGNO (operands[1]))
3331 emit_insn (gen_movsi (operands[0], operands[1]));
3332 return 1;
3335 return 0;
3338 /* Return an RTX indicating where the return address to the
3339 calling function can be found. */
3341 microblaze_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
3343 if (count != 0)
3344 return NULL_RTX;
3346 return gen_rtx_PLUS (Pmode,
3347 get_hard_reg_initial_val (Pmode,
3348 MB_ABI_SUB_RETURN_ADDR_REGNUM),
3349 GEN_INT (8));
3352 /* Queue an .ident string in the queue of top-level asm statements.
3353 If the string size is below the threshold, put it into .sdata2.
3354 If the front-end is done, we must be being called from toplev.c.
3355 In that case, do nothing. */
3356 void
3357 microblaze_asm_output_ident (const char *string)
3359 const char *section_asm_op;
3360 int size;
3361 char *buf;
3363 if (symtab->state != PARSING)
3364 return;
3366 size = strlen (string) + 1;
3367 if (size <= microblaze_section_threshold)
3368 section_asm_op = SDATA2_SECTION_ASM_OP;
3369 else
3370 section_asm_op = READONLY_DATA_SECTION_ASM_OP;
3372 buf = ACONCAT ((section_asm_op, "\n\t.ascii \"", string, "\\0\"\n", NULL));
3373 symtab->finalize_toplevel_asm (build_string (strlen (buf), buf));
3376 static void
3377 microblaze_elf_asm_init_sections (void)
3379 sdata2_section
3380 = get_unnamed_section (SECTION_WRITE, output_section_asm_op,
3381 SDATA2_SECTION_ASM_OP);
3384 /* Generate assembler code for constant parts of a trampoline. */
3386 static void
3387 microblaze_asm_trampoline_template (FILE *f)
3389 fprintf (f, "\tmfs r18, rpc\n");
3390 fprintf (f, "\tlwi r3, r18, 16\n");
3391 fprintf (f, "\tlwi r18, r18, 20\n");
3392 fprintf (f, "\tbra r18\n");
3393 /* fprintf (f, "\t.word\t0x00000000\t\t# <function address>\n"); */
3394 /* fprintf (f, "\t.word\t0x00000000\t\t# <static chain value>\n"); */
3397 /* Implement TARGET_TRAMPOLINE_INIT. */
3399 static void
3400 microblaze_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
3402 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
3403 rtx mem;
3405 emit_block_move (m_tramp, assemble_trampoline_template (),
3406 GEN_INT (6*UNITS_PER_WORD), BLOCK_OP_NORMAL);
3408 mem = adjust_address (m_tramp, SImode, 16);
3409 emit_move_insn (mem, chain_value);
3410 mem = adjust_address (m_tramp, SImode, 20);
3411 emit_move_insn (mem, fnaddr);
3414 /* Generate conditional branch -- first, generate test condition,
3415 second, generate correct branch instruction. */
3417 void
3418 microblaze_expand_conditional_branch (machine_mode mode, rtx operands[])
3420 enum rtx_code code = GET_CODE (operands[0]);
3421 rtx cmp_op0 = operands[1];
3422 rtx cmp_op1 = operands[2];
3423 rtx label1 = operands[3];
3424 rtx comp_reg = gen_reg_rtx (SImode);
3425 rtx condition;
3427 gcc_assert ((GET_CODE (cmp_op0) == REG) || (GET_CODE (cmp_op0) == SUBREG));
3429 /* If comparing against zero, just test source reg. */
3430 if (cmp_op1 == const0_rtx)
3432 comp_reg = cmp_op0;
3433 condition = gen_rtx_fmt_ee (signed_condition (code), SImode, comp_reg, const0_rtx);
3434 emit_jump_insn (gen_condjump (condition, label1));
3437 else if (code == EQ || code == NE)
3439 /* Use xor for equal/not-equal comparison. */
3440 emit_insn (gen_xorsi3 (comp_reg, cmp_op0, cmp_op1));
3441 condition = gen_rtx_fmt_ee (signed_condition (code), SImode, comp_reg, const0_rtx);
3442 emit_jump_insn (gen_condjump (condition, label1));
3444 else
3446 /* Generate compare and branch in single instruction. */
3447 cmp_op1 = force_reg (mode, cmp_op1);
3448 condition = gen_rtx_fmt_ee (code, mode, cmp_op0, cmp_op1);
3449 emit_jump_insn (gen_branch_compare(condition, cmp_op0, cmp_op1, label1));
3453 void
3454 microblaze_expand_conditional_branch_reg (enum machine_mode mode,
3455 rtx operands[])
3457 enum rtx_code code = GET_CODE (operands[0]);
3458 rtx cmp_op0 = operands[1];
3459 rtx cmp_op1 = operands[2];
3460 rtx label1 = operands[3];
3461 rtx comp_reg = gen_reg_rtx (SImode);
3462 rtx condition;
3464 gcc_assert ((GET_CODE (cmp_op0) == REG)
3465 || (GET_CODE (cmp_op0) == SUBREG));
3467 /* If comparing against zero, just test source reg. */
3468 if (cmp_op1 == const0_rtx)
3470 comp_reg = cmp_op0;
3471 condition = gen_rtx_fmt_ee (signed_condition (code),
3472 SImode, comp_reg, const0_rtx);
3473 emit_jump_insn (gen_condjump (condition, label1));
3475 else if (code == EQ)
3477 emit_insn (gen_seq_internal_pat (comp_reg,
3478 cmp_op0, cmp_op1));
3479 condition = gen_rtx_EQ (SImode, comp_reg, const0_rtx);
3480 emit_jump_insn (gen_condjump (condition, label1));
3482 else if (code == NE)
3484 emit_insn (gen_sne_internal_pat (comp_reg, cmp_op0,
3485 cmp_op1));
3486 condition = gen_rtx_NE (SImode, comp_reg, const0_rtx);
3487 emit_jump_insn (gen_condjump (condition, label1));
3489 else
3491 /* Generate compare and branch in single instruction. */
3492 cmp_op1 = force_reg (mode, cmp_op1);
3493 condition = gen_rtx_fmt_ee (code, mode, cmp_op0, cmp_op1);
3494 emit_jump_insn (gen_branch_compare (condition, cmp_op0,
3495 cmp_op1, label1));
3499 void
3500 microblaze_expand_conditional_branch_sf (rtx operands[])
3502 rtx condition;
3503 rtx cmp_op0 = XEXP (operands[0], 0);
3504 rtx cmp_op1 = XEXP (operands[0], 1);
3505 rtx comp_reg = gen_reg_rtx (SImode);
3507 emit_insn (gen_cstoresf4 (comp_reg, operands[0], cmp_op0, cmp_op1));
3508 condition = gen_rtx_NE (SImode, comp_reg, const0_rtx);
3509 emit_jump_insn (gen_condjump (condition, operands[3]));
3512 /* Implement TARGET_FRAME_POINTER_REQUIRED. */
3514 static bool
3515 microblaze_frame_pointer_required (void)
3517 /* If the function contains dynamic stack allocations, we need to
3518 use the frame pointer to access the static parts of the frame. */
3519 if (cfun->calls_alloca)
3520 return true;
3521 return false;
3524 void
3525 microblaze_expand_divide (rtx operands[])
3527 /* Table lookup software divides. Works for all (nr/dr) where (0 <= nr,dr <= 15). */
3529 rtx regt1 = gen_reg_rtx (SImode);
3530 rtx reg18 = gen_rtx_REG (SImode, R_TMP);
3531 rtx regqi = gen_reg_rtx (QImode);
3532 rtx_code_label *div_label = gen_label_rtx ();
3533 rtx_code_label *div_end_label = gen_label_rtx ();
3534 rtx div_table_rtx = gen_rtx_SYMBOL_REF (QImode,"_divsi3_table");
3535 rtx mem_rtx;
3536 rtx ret;
3537 rtx_insn *jump, *cjump, *insn;
3539 insn = emit_insn (gen_iorsi3 (regt1, operands[1], operands[2]));
3540 cjump = emit_jump_insn_after (gen_cbranchsi4 (
3541 gen_rtx_GTU (SImode, regt1, GEN_INT (15)),
3542 regt1, GEN_INT (15), div_label), insn);
3543 LABEL_NUSES (div_label) = 1;
3544 JUMP_LABEL (cjump) = div_label;
3545 emit_insn (gen_rtx_CLOBBER (SImode, reg18));
3547 emit_insn (gen_ashlsi3_bshift (regt1, operands[1], GEN_INT(4)));
3548 emit_insn (gen_addsi3 (regt1, regt1, operands[2]));
3549 mem_rtx = gen_rtx_MEM (QImode,
3550 gen_rtx_PLUS (Pmode, regt1, div_table_rtx));
3552 insn = emit_insn (gen_movqi (regqi, mem_rtx));
3553 insn = emit_insn (gen_movsi (operands[0], gen_rtx_SUBREG (SImode, regqi, 0)));
3554 jump = emit_jump_insn_after (gen_jump (div_end_label), insn);
3555 JUMP_LABEL (jump) = div_end_label;
3556 LABEL_NUSES (div_end_label) = 1;
3557 emit_barrier ();
3559 emit_label (div_label);
3560 ret = emit_library_call_value (gen_rtx_SYMBOL_REF (Pmode, "__divsi3"),
3561 operands[0], LCT_NORMAL,
3562 GET_MODE (operands[0]), 2, operands[1],
3563 GET_MODE (operands[1]), operands[2],
3564 GET_MODE (operands[2]));
3565 if (ret != operands[0])
3566 emit_move_insn (operands[0], ret);
3568 emit_label (div_end_label);
3569 emit_insn (gen_blockage ());
3572 /* Implement TARGET_FUNCTION_VALUE. */
3573 static rtx
3574 microblaze_function_value (const_tree valtype,
3575 const_tree func ATTRIBUTE_UNUSED,
3576 bool outgoing ATTRIBUTE_UNUSED)
3578 return LIBCALL_VALUE (TYPE_MODE (valtype));
3581 /* Implement TARGET_SCHED_ADJUST_COST. */
3582 static int
3583 microblaze_adjust_cost (rtx_insn *insn ATTRIBUTE_UNUSED, rtx link,
3584 rtx_insn *dep ATTRIBUTE_UNUSED, int cost)
3586 if (REG_NOTE_KIND (link) == REG_DEP_OUTPUT)
3587 return cost;
3588 if (REG_NOTE_KIND (link) != 0)
3589 return 0;
3590 return cost;
3593 /* Implement TARGET_LEGITIMATE_CONSTANT_P.
3595 At present, GAS doesn't understand li.[sd], so don't allow it
3596 to be generated at present. */
3597 static bool
3598 microblaze_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED, rtx x)
3601 if (microblaze_cannot_force_const_mem(mode, x))
3602 return false;
3604 if (GET_CODE (x) == CONST_DOUBLE)
3606 return microblaze_const_double_ok (x, GET_MODE (x));
3609 /* Handle Case of (const (plus unspec const_int)). */
3610 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x,0)) == PLUS)
3612 rtx p0, p1;
3614 p0 = XEXP (XEXP (x, 0), 0);
3615 p1 = XEXP (XEXP (x, 0), 1);
3617 if (GET_CODE(p1) == CONST_INT)
3619 /* Const offset from UNSPEC is not supported. */
3620 if ((GET_CODE (p0) == UNSPEC))
3621 return false;
3623 if ((GET_CODE (p0) == SYMBOL_REF || GET_CODE (p0) == LABEL_REF)
3624 && (microblaze_tls_symbol_p (p0) || !SMALL_INT (p1)))
3625 return false;
3629 return true;
3633 #undef TARGET_ENCODE_SECTION_INFO
3634 #define TARGET_ENCODE_SECTION_INFO microblaze_encode_section_info
3636 #undef TARGET_ASM_GLOBALIZE_LABEL
3637 #define TARGET_ASM_GLOBALIZE_LABEL microblaze_globalize_label
3639 #undef TARGET_ASM_FUNCTION_PROLOGUE
3640 #define TARGET_ASM_FUNCTION_PROLOGUE microblaze_function_prologue
3642 #undef TARGET_ASM_FUNCTION_EPILOGUE
3643 #define TARGET_ASM_FUNCTION_EPILOGUE microblaze_function_epilogue
3645 #undef TARGET_RTX_COSTS
3646 #define TARGET_RTX_COSTS microblaze_rtx_costs
3648 #undef TARGET_CANNOT_FORCE_CONST_MEM
3649 #define TARGET_CANNOT_FORCE_CONST_MEM microblaze_cannot_force_const_mem
3651 #undef TARGET_ADDRESS_COST
3652 #define TARGET_ADDRESS_COST microblaze_address_cost
3654 #undef TARGET_ATTRIBUTE_TABLE
3655 #define TARGET_ATTRIBUTE_TABLE microblaze_attribute_table
3657 #undef TARGET_IN_SMALL_DATA_P
3658 #define TARGET_IN_SMALL_DATA_P microblaze_elf_in_small_data_p
3660 #undef TARGET_ASM_SELECT_SECTION
3661 #define TARGET_ASM_SELECT_SECTION microblaze_select_section
3663 #undef TARGET_HAVE_SRODATA_SECTION
3664 #define TARGET_HAVE_SRODATA_SECTION true
3666 #undef TARGET_ASM_FUNCTION_END_PROLOGUE
3667 #define TARGET_ASM_FUNCTION_END_PROLOGUE \
3668 microblaze_function_end_prologue
3670 #undef TARGET_ARG_PARTIAL_BYTES
3671 #define TARGET_ARG_PARTIAL_BYTES function_arg_partial_bytes
3673 #undef TARGET_FUNCTION_ARG
3674 #define TARGET_FUNCTION_ARG microblaze_function_arg
3676 #undef TARGET_FUNCTION_ARG_ADVANCE
3677 #define TARGET_FUNCTION_ARG_ADVANCE microblaze_function_arg_advance
3679 #undef TARGET_CAN_ELIMINATE
3680 #define TARGET_CAN_ELIMINATE microblaze_can_eliminate
3682 #undef TARGET_LEGITIMIZE_ADDRESS
3683 #define TARGET_LEGITIMIZE_ADDRESS microblaze_legitimize_address
3685 #undef TARGET_LEGITIMATE_ADDRESS_P
3686 #define TARGET_LEGITIMATE_ADDRESS_P microblaze_legitimate_address_p
3688 #undef TARGET_FRAME_POINTER_REQUIRED
3689 #define TARGET_FRAME_POINTER_REQUIRED microblaze_frame_pointer_required
3691 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
3692 #define TARGET_ASM_TRAMPOLINE_TEMPLATE microblaze_asm_trampoline_template
3694 #undef TARGET_TRAMPOLINE_INIT
3695 #define TARGET_TRAMPOLINE_INIT microblaze_trampoline_init
3697 #undef TARGET_PROMOTE_FUNCTION_MODE
3698 #define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
3700 #undef TARGET_FUNCTION_VALUE
3701 #define TARGET_FUNCTION_VALUE microblaze_function_value
3703 #undef TARGET_SECONDARY_RELOAD
3704 #define TARGET_SECONDARY_RELOAD microblaze_secondary_reload
3706 #undef TARGET_ASM_OUTPUT_MI_THUNK
3707 #define TARGET_ASM_OUTPUT_MI_THUNK microblaze_asm_output_mi_thunk
3709 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
3710 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true
3712 #undef TARGET_SCHED_ADJUST_COST
3713 #define TARGET_SCHED_ADJUST_COST microblaze_adjust_cost
3715 #undef TARGET_ASM_INIT_SECTIONS
3716 #define TARGET_ASM_INIT_SECTIONS microblaze_elf_asm_init_sections
3718 #undef TARGET_OPTION_OVERRIDE
3719 #define TARGET_OPTION_OVERRIDE microblaze_option_override
3721 #undef TARGET_LEGITIMATE_CONSTANT_P
3722 #define TARGET_LEGITIMATE_CONSTANT_P microblaze_legitimate_constant_p
3724 struct gcc_target targetm = TARGET_INITIALIZER;
3726 #include "gt-microblaze.h"