gcc/ada/
[official-gcc.git] / gcc / config / microblaze / microblaze.c
blob48ebf861c5aa9ac1e7f32988e00fff1ddccd2db1
1 /* Subroutines used for code generation on Xilinx MicroBlaze.
2 Copyright (C) 2009-2014 Free Software Foundation, Inc.
4 Contributed by Michael Eager <eager@eagercon.com>.
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published
10 by the Free Software Foundation; either version 3, or (at your
11 option) any later version.
13 GCC is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16 License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. */
22 #include "config.h"
23 #include "system.h"
24 #include "coretypes.h"
25 #include "tm.h"
26 #include "rtl.h"
27 #include "regs.h"
28 #include "hard-reg-set.h"
29 #include "real.h"
30 #include "insn-config.h"
31 #include "conditions.h"
32 #include "insn-flags.h"
33 #include "insn-attr.h"
34 #include "recog.h"
35 #include "tree.h"
36 #include "varasm.h"
37 #include "stor-layout.h"
38 #include "calls.h"
39 #include "hashtab.h"
40 #include "hash-set.h"
41 #include "vec.h"
42 #include "machmode.h"
43 #include "input.h"
44 #include "function.h"
45 #include "expr.h"
46 #include "flags.h"
47 #include "reload.h"
48 #include "output.h"
49 #include "ggc.h"
50 #include "target.h"
51 #include "target-def.h"
52 #include "tm_p.h"
53 #include "gstab.h"
54 #include "dominance.h"
55 #include "cfg.h"
56 #include "cfgrtl.h"
57 #include "cfganal.h"
58 #include "lcm.h"
59 #include "cfgbuild.h"
60 #include "cfgcleanup.h"
61 #include "predict.h"
62 #include "basic-block.h"
63 #include "df.h"
64 #include "optabs.h"
65 #include "diagnostic-core.h"
66 #include "hash-map.h"
67 #include "is-a.h"
68 #include "plugin-api.h"
69 #include "ipa-ref.h"
70 #include "cgraph.h"
71 #include "builtins.h"
72 #include "rtl-iter.h"
74 #define MICROBLAZE_VERSION_COMPARE(VA,VB) strcasecmp (VA, VB)
76 /* Classifies an address.
78 ADDRESS_INVALID
79 An invalid address.
81 ADDRESS_REG
83 A natural register or a register + const_int offset address.
84 The register satisfies microblaze_valid_base_register_p and the
85 offset is a const_arith_operand.
87 ADDRESS_REG_INDEX
89 A natural register offset by the index contained in an index register. The base
90 register satisfies microblaze_valid_base_register_p and the index register
91 satisfies microblaze_valid_index_register_p
93 ADDRESS_CONST_INT
95 A signed 16/32-bit constant address.
97 ADDRESS_SYMBOLIC:
99 A constant symbolic address or a (register + symbol). */
101 enum microblaze_address_type
103 ADDRESS_INVALID,
104 ADDRESS_REG,
105 ADDRESS_REG_INDEX,
106 ADDRESS_CONST_INT,
107 ADDRESS_SYMBOLIC,
108 ADDRESS_GOTOFF,
109 ADDRESS_PLT,
110 ADDRESS_TLS
113 /* Classifies symbols
115 SYMBOL_TYPE_GENERAL
117 A general symbol. */
118 enum microblaze_symbol_type
120 SYMBOL_TYPE_INVALID,
121 SYMBOL_TYPE_GENERAL
124 /* TLS Address Type. */
125 enum tls_reloc {
126 TLS_GD,
127 TLS_LDM,
128 TLS_DTPREL,
129 TLS_IE,
130 TLS_LE
133 /* Classification of a MicroBlaze address. */
134 struct microblaze_address_info
136 enum microblaze_address_type type;
137 rtx regA; /* Contains valid values on ADDRESS_REG, ADDRESS_REG_INDEX,
138 ADDRESS_SYMBOLIC. */
139 rtx regB; /* Contains valid values on ADDRESS_REG_INDEX. */
140 rtx offset; /* Contains valid values on ADDRESS_CONST_INT and ADDRESS_REG. */
141 rtx symbol; /* Contains valid values on ADDRESS_SYMBOLIC. */
142 enum microblaze_symbol_type symbol_type;
143 enum tls_reloc tls_type;
146 /* Structure to be filled in by compute_frame_size with register
147 save masks, and offsets for the current function. */
149 struct GTY(()) microblaze_frame_info {
150 long total_size; /* # bytes that the entire frame takes up. */
151 long var_size; /* # bytes that variables take up. */
152 long args_size; /* # bytes that outgoing arguments take up. */
153 int link_debug_size; /* # bytes for the link reg and back pointer. */
154 int gp_reg_size; /* # bytes needed to store gp regs. */
155 long gp_offset; /* offset from new sp to store gp registers. */
156 long mask; /* mask of saved gp registers. */
157 int initialized; /* != 0 if frame size already calculated. */
158 int num_gp; /* number of gp registers saved. */
159 long insns_len; /* length of insns. */
160 int alloc_stack; /* Flag to indicate if the current function
161 must not create stack space. (As an optimization). */
164 /* Global variables for machine-dependent things. */
166 /* Toggle which pipleline interface to use. */
167 static GTY(()) int microblaze_sched_use_dfa = 0;
169 /* Threshold for data being put into the small data/bss area, instead
170 of the normal data area (references to the small data/bss area take
171 1 instruction, and use the global pointer, references to the normal
172 data area takes 2 instructions). */
173 int microblaze_section_threshold = -1;
175 /* Prevent scheduling potentially exception causing instructions in
176 delay slots. -mcpu=v3.00.a or v4.00.a turns this on. */
177 int microblaze_no_unsafe_delay;
179 /* Set to one if the targeted core has the CLZ insn. */
180 int microblaze_has_clz = 0;
182 /* Which CPU pipeline do we use. We haven't really standardized on a CPU
183 version having only a particular type of pipeline. There can still be
184 options on the CPU to scale pipeline features up or down. :(
185 Bad Presentation (??), so we let the MD file rely on the value of
186 this variable instead Making PIPE_5 the default. It should be backward
187 optimal with PIPE_3 MicroBlazes. */
188 enum pipeline_type microblaze_pipe = MICROBLAZE_PIPE_5;
190 /* High and low marks for floating point values which we will accept
191 as legitimate constants for TARGET_LEGITIMATE_CONSTANT_P. These are
192 initialized in override_options. */
193 REAL_VALUE_TYPE dfhigh, dflow, sfhigh, sflow;
195 /* Array giving truth value on whether or not a given hard register
196 can support a given mode. */
197 char microblaze_hard_regno_mode_ok[(int)MAX_MACHINE_MODE]
198 [FIRST_PSEUDO_REGISTER];
200 /* Current frame information calculated by compute_frame_size. */
201 struct microblaze_frame_info current_frame_info;
203 /* Zero structure to initialize current_frame_info. */
204 struct microblaze_frame_info zero_frame_info;
206 /* List of all MICROBLAZE punctuation characters used by print_operand. */
207 char microblaze_print_operand_punct[256];
209 /* Map GCC register number to debugger register number. */
210 int microblaze_dbx_regno[FIRST_PSEUDO_REGISTER];
212 /* Map hard register number to register class. */
213 enum reg_class microblaze_regno_to_class[] =
215 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
216 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
217 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
218 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
219 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
220 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
221 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
222 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
223 ST_REGS, GR_REGS, GR_REGS, GR_REGS
226 /* MicroBlaze specific machine attributes.
227 interrupt_handler - Interrupt handler attribute to add interrupt prologue
228 and epilogue and use appropriate interrupt return.
229 save_volatiles - Similar to interrupt handler, but use normal return. */
230 int interrupt_handler;
231 int break_handler;
232 int fast_interrupt;
233 int save_volatiles;
235 const struct attribute_spec microblaze_attribute_table[] = {
236 /* name min_len, max_len, decl_req, type_req, fn_type, req_handler,
237 affects_type_identity */
238 {"interrupt_handler", 0, 0, true, false, false, NULL,
239 false },
240 {"break_handler", 0, 0, true, false, false, NULL,
241 false },
242 {"fast_interrupt", 0, 0, true, false, false, NULL,
243 false },
244 {"save_volatiles" , 0, 0, true, false, false, NULL,
245 false },
246 { NULL, 0, 0, false, false, false, NULL,
247 false }
250 static int microblaze_interrupt_function_p (tree);
252 static void microblaze_elf_asm_constructor (rtx, int) ATTRIBUTE_UNUSED;
253 static void microblaze_elf_asm_destructor (rtx, int) ATTRIBUTE_UNUSED;
255 section *sdata2_section;
257 #ifdef HAVE_AS_TLS
258 #undef TARGET_HAVE_TLS
259 #define TARGET_HAVE_TLS true
260 #endif
262 /* Return truth value if a CONST_DOUBLE is ok to be a legitimate constant. */
263 static bool
264 microblaze_const_double_ok (rtx op, machine_mode mode)
266 REAL_VALUE_TYPE d;
268 if (GET_CODE (op) != CONST_DOUBLE)
269 return 0;
271 if (GET_MODE (op) == VOIDmode)
272 return 1;
274 if (mode != SFmode && mode != DFmode)
275 return 0;
277 if (op == CONST0_RTX (mode))
278 return 1;
280 REAL_VALUE_FROM_CONST_DOUBLE (d, op);
282 if (REAL_VALUE_ISNAN (d))
283 return FALSE;
285 if (REAL_VALUE_NEGATIVE (d))
286 d = real_value_negate (&d);
288 if (mode == DFmode)
290 if (REAL_VALUES_LESS (d, dfhigh) && REAL_VALUES_LESS (dflow, d))
291 return 1;
293 else
295 if (REAL_VALUES_LESS (d, sfhigh) && REAL_VALUES_LESS (sflow, d))
296 return 1;
299 return 0;
302 /* Return truth value if a memory operand fits in a single instruction
303 (ie, register + small offset) or (register + register). */
306 simple_memory_operand (rtx op, machine_mode mode ATTRIBUTE_UNUSED)
308 rtx addr, plus0, plus1;
310 /* Eliminate non-memory operations. */
311 if (GET_CODE (op) != MEM)
312 return 0;
314 /* dword operations really put out 2 instructions, so eliminate them. */
315 /* ??? This isn't strictly correct. It is OK to accept multiword modes
316 here, since the length attributes are being set correctly, but only
317 if the address is offsettable. */
318 if (GET_MODE_SIZE (GET_MODE (op)) > UNITS_PER_WORD)
319 return 0;
322 /* Decode the address now. */
323 addr = XEXP (op, 0);
324 switch (GET_CODE (addr))
327 case REG:
328 return 1;
330 case PLUS:
331 plus0 = XEXP (addr, 0);
332 plus1 = XEXP (addr, 1);
334 if (GET_CODE (plus0) != REG)
335 return 0;
337 if (GET_CODE (plus0) == REG && GET_CODE (plus1) == CONST_INT
338 && SMALL_INT (plus1))
340 return 1;
342 else if (GET_CODE (plus1) == REG && GET_CODE (plus0) == CONST_INT)
344 return 1;
346 else if (GET_CODE (plus0) == REG && GET_CODE (plus1) == REG)
348 return 1;
350 else
351 return 0;
353 case SYMBOL_REF:
354 return 0;
356 default:
357 break;
360 return 0;
363 /* Return nonzero for a memory address that can be used to load or store
364 a doubleword. */
367 double_memory_operand (rtx op, machine_mode mode)
369 rtx addr;
371 if (GET_CODE (op) != MEM || !memory_operand (op, mode))
373 /* During reload, we accept a pseudo register if it has an
374 appropriate memory address. If we don't do this, we will
375 wind up reloading into a register, and then reloading that
376 register from memory, when we could just reload directly from
377 memory. */
378 if (reload_in_progress
379 && GET_CODE (op) == REG
380 && REGNO (op) >= FIRST_PSEUDO_REGISTER
381 && reg_renumber[REGNO (op)] < 0
382 && reg_equiv_mem (REGNO (op)) != 0
383 && double_memory_operand (reg_equiv_mem (REGNO (op)), mode))
384 return 1;
385 return 0;
388 /* Make sure that 4 added to the address is a valid memory address.
389 This essentially just checks for overflow in an added constant. */
391 addr = XEXP (op, 0);
393 if (CONSTANT_ADDRESS_P (addr))
394 return 1;
396 return memory_address_p ((GET_MODE_CLASS (mode) == MODE_INT
397 ? SImode : SFmode),
398 plus_constant (Pmode, addr, 4));
401 /* Implement REG_OK_FOR_BASE_P -and- REG_OK_FOR_INDEX_P. */
403 microblaze_regno_ok_for_base_p (int regno, int strict)
405 if (regno >= FIRST_PSEUDO_REGISTER)
407 if (!strict)
408 return true;
409 regno = reg_renumber[regno];
412 /* These fake registers will be eliminated to either the stack or
413 hard frame pointer, both of which are usually valid base registers.
414 Reload deals with the cases where the eliminated form isn't valid. */
415 if (regno == ARG_POINTER_REGNUM || regno == FRAME_POINTER_REGNUM)
416 return true;
418 return GP_REG_P (regno);
421 /* Return true if X is a valid base register for the given mode.
422 Allow only hard registers if STRICT. */
424 static bool
425 microblaze_valid_base_register_p (rtx x,
426 machine_mode mode ATTRIBUTE_UNUSED,
427 int strict)
429 if (!strict && GET_CODE (x) == SUBREG)
430 x = SUBREG_REG (x);
432 return (GET_CODE (x) == REG
433 && microblaze_regno_ok_for_base_p (REGNO (x), strict));
436 /* Build the SYMBOL_REF for __tls_get_addr. */
438 static GTY(()) rtx tls_get_addr_libfunc;
440 static rtx
441 get_tls_get_addr (void)
443 if (!tls_get_addr_libfunc)
444 tls_get_addr_libfunc = init_one_libfunc ("__tls_get_addr");
445 return tls_get_addr_libfunc;
448 /* Return TRUE if X is a thread-local symbol. */
449 bool
450 microblaze_tls_symbol_p (rtx x)
452 if (!TARGET_HAVE_TLS)
453 return false;
455 if (GET_CODE (x) != SYMBOL_REF)
456 return false;
458 return SYMBOL_REF_TLS_MODEL (x) != 0;
461 /* Return TRUE if X contains any TLS symbol references. */
463 bool
464 microblaze_tls_referenced_p (rtx x)
466 if (!TARGET_HAVE_TLS)
467 return false;
468 subrtx_iterator::array_type array;
469 FOR_EACH_SUBRTX (iter, array, x, ALL)
471 const_rtx x = *iter;
472 if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (x) != 0)
473 return true;
474 /* Don't recurse into UNSPEC_TLS looking for TLS symbols; these are
475 TLS offsets, not real symbol references. */
476 if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLS)
477 iter.skip_subrtxes ();
479 return false;
482 bool
483 microblaze_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED, rtx x)
485 return microblaze_tls_referenced_p(x);
488 /* Return TRUE if X references a SYMBOL_REF. */
490 symbol_mentioned_p (rtx x)
492 const char * fmt;
493 int i;
495 if (GET_CODE (x) == SYMBOL_REF)
496 return 1;
498 /* UNSPEC entries for a symbol include the SYMBOL_REF, but they
499 are constant offsets, not symbols. */
500 if (GET_CODE (x) == UNSPEC)
501 return 0;
503 fmt = GET_RTX_FORMAT (GET_CODE (x));
505 for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
507 if (fmt[i] == 'E')
509 int j;
511 for (j = XVECLEN (x, i) - 1; j >= 0; j--)
512 if (symbol_mentioned_p (XVECEXP (x, i, j)))
513 return 1;
515 else if (fmt[i] == 'e' && symbol_mentioned_p (XEXP (x, i)))
516 return 1;
519 return 0;
522 /* Return TRUE if X references a LABEL_REF. */
524 label_mentioned_p (rtx x)
526 const char * fmt;
527 int i;
529 if (GET_CODE (x) == LABEL_REF)
530 return 1;
532 /* UNSPEC entries for a symbol include a LABEL_REF for the referencing
533 instruction, but they are constant offsets, not symbols. */
534 if (GET_CODE (x) == UNSPEC)
535 return 0;
537 fmt = GET_RTX_FORMAT (GET_CODE (x));
538 for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
540 if (fmt[i] == 'E')
542 int j;
544 for (j = XVECLEN (x, i) - 1; j >= 0; j--)
545 if (label_mentioned_p (XVECEXP (x, i, j)))
546 return 1;
548 else if (fmt[i] == 'e' && label_mentioned_p (XEXP (x, i)))
549 return 1;
552 return 0;
556 tls_mentioned_p (rtx x)
558 switch (GET_CODE (x))
560 case CONST:
561 return tls_mentioned_p (XEXP (x, 0));
563 case UNSPEC:
564 if (XINT (x, 1) == UNSPEC_TLS)
565 return 1;
567 default:
568 return 0;
572 static rtx
573 load_tls_operand (rtx x, rtx reg)
575 rtx tmp;
577 if (reg == NULL_RTX)
578 reg = gen_reg_rtx (Pmode);
580 tmp = gen_rtx_CONST (Pmode, x);
582 emit_insn (gen_rtx_SET (VOIDmode, reg,
583 gen_rtx_PLUS (Pmode, pic_offset_table_rtx, tmp)));
585 return reg;
588 static rtx_insn *
589 microblaze_call_tls_get_addr (rtx x, rtx reg, rtx *valuep, int reloc)
591 rtx_insn *insns;
592 rtx tls_entry;
594 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
596 start_sequence ();
598 tls_entry = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, x, GEN_INT (reloc)),
599 UNSPEC_TLS);
601 reg = load_tls_operand (tls_entry, reg);
603 *valuep = emit_library_call_value (get_tls_get_addr (), NULL_RTX,
604 LCT_PURE, /* LCT_CONST? */
605 Pmode, 1, reg, Pmode);
607 insns = get_insns ();
608 end_sequence ();
610 return insns;
614 microblaze_legitimize_tls_address(rtx x, rtx reg)
616 rtx dest, ret, eqv, addend;
617 rtx_insn *insns;
618 enum tls_model model;
619 model = SYMBOL_REF_TLS_MODEL (x);
621 switch (model)
623 case TLS_MODEL_LOCAL_DYNAMIC:
624 case TLS_MODEL_GLOBAL_DYNAMIC:
625 case TLS_MODEL_INITIAL_EXEC:
626 insns = microblaze_call_tls_get_addr (x, reg, &ret, TLS_GD);
627 dest = gen_reg_rtx (Pmode);
628 emit_libcall_block (insns, dest, ret, x);
629 break;
631 case TLS_MODEL_LOCAL_EXEC:
632 insns = microblaze_call_tls_get_addr (x, reg, &ret, TLS_LDM);
634 /* Attach a unique REG_EQUIV, to allow the RTL optimizers to
635 share the LDM result with other LD model accesses. */
636 eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const1_rtx), UNSPEC_TLS);
637 dest = gen_reg_rtx (Pmode);
638 emit_libcall_block (insns, dest, ret, eqv);
640 /* Load the addend. */
641 addend = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, x, GEN_INT (TLS_DTPREL)),
642 UNSPEC_TLS);
643 addend = force_reg (SImode, gen_rtx_CONST (SImode, addend));
644 dest = gen_rtx_PLUS (Pmode, dest, addend);
645 break;
647 default:
648 gcc_unreachable ();
650 return dest;
653 static bool
654 microblaze_classify_unspec (struct microblaze_address_info *info, rtx x)
656 info->symbol_type = SYMBOL_TYPE_GENERAL;
657 info->symbol = XVECEXP (x, 0, 0);
659 if (XINT (x, 1) == UNSPEC_GOTOFF)
661 info->regA = gen_rtx_REG (SImode, PIC_OFFSET_TABLE_REGNUM);
662 info->type = ADDRESS_GOTOFF;
664 else if (XINT (x, 1) == UNSPEC_PLT)
666 info->type = ADDRESS_PLT;
668 else if (XINT (x, 1) == UNSPEC_TLS)
670 info->type = ADDRESS_TLS;
671 info->tls_type = tls_reloc INTVAL(XVECEXP(x, 0, 1));
673 else
675 return false;
677 return true;
681 /* Return true if X is a valid index register for the given mode.
682 Allow only hard registers if STRICT. */
684 static bool
685 microblaze_valid_index_register_p (rtx x,
686 machine_mode mode ATTRIBUTE_UNUSED,
687 int strict)
689 if (!strict && GET_CODE (x) == SUBREG)
690 x = SUBREG_REG (x);
692 return (GET_CODE (x) == REG
693 /* A base register is good enough to be an index register on MicroBlaze. */
694 && microblaze_regno_ok_for_base_p (REGNO (x), strict));
697 /* Get the base register for accessing a value from the memory or
698 Symbol ref. Used for MicroBlaze Small Data Area Pointer Optimization. */
699 static int
700 get_base_reg (rtx x)
702 tree decl;
703 int base_reg;
705 if (!flag_pic || microblaze_tls_symbol_p(x))
706 base_reg = MB_ABI_BASE_REGNUM;
707 else if (flag_pic)
708 base_reg = MB_ABI_PIC_ADDR_REGNUM;
710 if (TARGET_XLGPOPT
711 && GET_CODE (x) == SYMBOL_REF
712 && SYMBOL_REF_SMALL_P (x) && (decl = SYMBOL_REF_DECL (x)) != NULL)
714 if (TREE_READONLY (decl))
715 base_reg = MB_ABI_GPRO_REGNUM;
716 else
717 base_reg = MB_ABI_GPRW_REGNUM;
720 return base_reg;
723 /* Return true if X is a valid address for machine mode MODE. If it is,
724 fill in INFO appropriately. STRICT is true if we should only accept
725 hard base registers.
727 type regA regB offset symbol
729 ADDRESS_INVALID NULL NULL NULL NULL
731 ADDRESS_REG %0 NULL const_0 / NULL
732 const_int
733 ADDRESS_REG_INDEX %0 %1 NULL NULL
735 ADDRESS_SYMBOLIC r0 / NULL NULL symbol
736 sda_base_reg
738 ADDRESS_CONST_INT r0 NULL const NULL
740 For modes spanning multiple registers (DFmode in 32-bit GPRs,
741 DImode, TImode), indexed addressing cannot be used because
742 adjacent memory cells are accessed by adding word-sized offsets
743 during assembly output. */
745 static bool
746 microblaze_classify_address (struct microblaze_address_info *info, rtx x,
747 machine_mode mode, int strict)
749 rtx xplus0;
750 rtx xplus1;
752 info->type = ADDRESS_INVALID;
753 info->regA = NULL;
754 info->regB = NULL;
755 info->offset = NULL;
756 info->symbol = NULL;
757 info->symbol_type = SYMBOL_TYPE_INVALID;
759 switch (GET_CODE (x))
761 case REG:
762 case SUBREG:
764 info->type = ADDRESS_REG;
765 info->regA = x;
766 info->offset = const0_rtx;
767 return microblaze_valid_base_register_p (info->regA, mode, strict);
769 case PLUS:
771 xplus0 = XEXP (x, 0);
772 xplus1 = XEXP (x, 1);
774 if (microblaze_valid_base_register_p (xplus0, mode, strict))
776 info->type = ADDRESS_REG;
777 info->regA = xplus0;
779 if (GET_CODE (xplus1) == CONST_INT)
781 info->offset = xplus1;
782 return true;
784 else if (GET_CODE (xplus1) == UNSPEC)
786 /* Need offsettable address. */
787 if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
788 return false;
790 return microblaze_classify_unspec (info, xplus1);
792 else if ((GET_CODE (xplus1) == SYMBOL_REF ||
793 GET_CODE (xplus1) == LABEL_REF))
795 if (flag_pic == 2 || microblaze_tls_symbol_p(xplus1))
796 return false;
797 info->type = ADDRESS_SYMBOLIC;
798 info->symbol = xplus1;
799 info->symbol_type = SYMBOL_TYPE_GENERAL;
800 return true;
802 else if (GET_CODE (xplus1) == CONST)
804 rtx xconst0 = XEXP(xplus1, 0);
806 /* base + unspec. */
807 if (GET_CODE (xconst0) == UNSPEC)
809 /* Need offsettable address. */
810 if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
811 return false;
812 return microblaze_classify_unspec(info, xconst0);
815 /* for (plus x const_int) just look at x. */
816 if (GET_CODE (xconst0) == PLUS
817 && GET_CODE (XEXP (xconst0, 1)) == CONST_INT
818 && SMALL_INT (XEXP (xconst0, 1)))
820 /* This is ok as info->symbol is set to xplus1 the full
821 const-expression below. */
822 xconst0 = XEXP (xconst0, 0);
825 if (GET_CODE (xconst0) == SYMBOL_REF
826 || GET_CODE (xconst0) == LABEL_REF)
828 if (flag_pic == 2 || microblaze_tls_symbol_p(xconst0))
829 return false;
831 info->type = ADDRESS_SYMBOLIC;
832 info->symbol = xplus1;
833 info->symbol_type = SYMBOL_TYPE_GENERAL;
834 return true;
837 /* Not base + symbol || base + UNSPEC. */
838 return false;
841 else if (GET_CODE (xplus1) == REG
842 && microblaze_valid_index_register_p (xplus1, mode,
843 strict)
844 && (GET_MODE_SIZE (mode) <= UNITS_PER_WORD))
846 /* Restrict larger than word-width modes from using an index register. */
847 info->type = ADDRESS_REG_INDEX;
848 info->regB = xplus1;
849 return true;
852 break;
854 case CONST_INT:
856 info->regA = gen_rtx_raw_REG (mode, 0);
857 info->type = ADDRESS_CONST_INT;
858 info->offset = x;
859 return true;
861 case CONST:
862 case LABEL_REF:
863 case SYMBOL_REF:
865 info->type = ADDRESS_SYMBOLIC;
866 info->symbol_type = SYMBOL_TYPE_GENERAL;
867 info->symbol = x;
868 info->regA = gen_rtx_raw_REG (mode, get_base_reg (x));
870 if (GET_CODE (x) == CONST)
872 if (GET_CODE (XEXP (x, 0)) == UNSPEC)
874 info->regA = gen_rtx_raw_REG (mode,
875 get_base_reg (XVECEXP (XEXP (x,0), 0, 0)));
876 return microblaze_classify_unspec (info, XEXP (x, 0));
878 return !(flag_pic && pic_address_needs_scratch (x));
881 if (flag_pic == 2)
882 return false;
883 else if (microblaze_tls_symbol_p(x))
884 return false;
886 return true;
889 case UNSPEC:
891 if (reload_in_progress)
892 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
893 return microblaze_classify_unspec (info, x);
896 default:
897 return false;
900 return false;
903 /* This function is used to implement GO_IF_LEGITIMATE_ADDRESS. It
904 returns a nonzero value if X is a legitimate address for a memory
905 operand of the indicated MODE. STRICT is nonzero if this function
906 is called during reload. */
908 bool
909 microblaze_legitimate_address_p (machine_mode mode, rtx x, bool strict)
911 struct microblaze_address_info addr;
913 return microblaze_classify_address (&addr, x, mode, strict);
917 microblaze_valid_pic_const (rtx x)
919 switch (GET_CODE (x))
921 case CONST:
922 case CONST_INT:
923 case CONST_DOUBLE:
924 return true;
925 default:
926 return false;
931 microblaze_legitimate_pic_operand (rtx x)
933 if (flag_pic == 2 && (symbol_mentioned_p(x) || label_mentioned_p(x)))
934 return 0;
936 if (microblaze_tls_referenced_p(x))
937 return 0;
939 return 1;
942 /* Try machine-dependent ways of modifying an illegitimate address
943 to be legitimate. If we find one, return the new, valid address.
944 This is used from only one place: `memory_address' in explow.c.
946 OLDX is the address as it was before break_out_memory_refs was
947 called. In some cases it is useful to look at this to decide what
948 needs to be done.
950 It is always safe for this function to do nothing. It exists to
951 recognize opportunities to optimize the output.
953 For the MicroBlaze, transform:
955 memory(X + <large int>)
957 into:
959 Y = <large int> & ~0x7fff;
960 Z = X + Y
961 memory (Z + (<large int> & 0x7fff));
963 This is for CSE to find several similar references, and only use one Z.
965 When PIC, convert addresses of the form memory (symbol+large int) to
966 memory (reg+large int). */
968 static rtx
969 microblaze_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
970 machine_mode mode ATTRIBUTE_UNUSED)
972 register rtx xinsn = x, result;
974 if (GET_CODE (xinsn) == CONST
975 && flag_pic && pic_address_needs_scratch (xinsn))
977 rtx ptr_reg = gen_reg_rtx (Pmode);
978 rtx constant = XEXP (XEXP (xinsn, 0), 1);
980 emit_move_insn (ptr_reg, XEXP (XEXP (xinsn, 0), 0));
982 result = gen_rtx_PLUS (Pmode, ptr_reg, constant);
983 if (SMALL_INT (constant))
984 return result;
985 /* Otherwise we fall through so the code below will fix the
986 constant. */
987 xinsn = result;
990 if (GET_CODE (xinsn) == PLUS)
992 register rtx xplus0 = XEXP (xinsn, 0);
993 register rtx xplus1 = XEXP (xinsn, 1);
994 register enum rtx_code code0 = GET_CODE (xplus0);
995 register enum rtx_code code1 = GET_CODE (xplus1);
997 if (code0 != REG && code1 == REG)
999 xplus0 = XEXP (xinsn, 1);
1000 xplus1 = XEXP (xinsn, 0);
1001 code0 = GET_CODE (xplus0);
1002 code1 = GET_CODE (xplus1);
1005 if (code0 == REG && REG_OK_FOR_BASE_P (xplus0)
1006 && code1 == CONST_INT && !SMALL_INT (xplus1))
1008 rtx int_reg = gen_reg_rtx (Pmode);
1009 rtx ptr_reg = gen_reg_rtx (Pmode);
1011 emit_move_insn (int_reg, GEN_INT (INTVAL (xplus1) & ~0x7fff));
1013 emit_insn (gen_rtx_SET (VOIDmode,
1014 ptr_reg,
1015 gen_rtx_PLUS (Pmode, xplus0, int_reg)));
1017 result = gen_rtx_PLUS (Pmode, ptr_reg,
1018 GEN_INT (INTVAL (xplus1) & 0x7fff));
1019 return result;
1022 if (code0 == REG && REG_OK_FOR_BASE_P (xplus0))
1024 if (reload_in_progress)
1025 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
1026 if (code1 == CONST)
1028 xplus1 = XEXP (xplus1, 0);
1029 code1 = GET_CODE (xplus1);
1031 if (code1 == SYMBOL_REF)
1033 if (microblaze_tls_symbol_p(xplus1))
1035 rtx tls_ref, reg;
1036 reg = gen_reg_rtx (Pmode);
1038 tls_ref = microblaze_legitimize_tls_address (xplus1,
1039 NULL_RTX);
1040 emit_move_insn (reg, tls_ref);
1042 result = gen_rtx_PLUS (Pmode, xplus0, reg);
1044 return result;
1046 else if (flag_pic == 2)
1048 rtx pic_ref, reg;
1049 reg = gen_reg_rtx (Pmode);
1051 pic_ref = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, xplus1),
1052 UNSPEC_GOTOFF);
1053 pic_ref = gen_rtx_CONST (Pmode, pic_ref);
1054 pic_ref = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, pic_ref);
1055 pic_ref = gen_const_mem (Pmode, pic_ref);
1056 emit_move_insn (reg, pic_ref);
1057 result = gen_rtx_PLUS (Pmode, xplus0, reg);
1058 return result;
1064 if (GET_CODE (xinsn) == SYMBOL_REF)
1066 rtx reg;
1067 if (microblaze_tls_symbol_p(xinsn))
1069 reg = microblaze_legitimize_tls_address (xinsn, NULL_RTX);
1071 else
1073 rtx pic_ref;
1075 if (reload_in_progress)
1076 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
1078 pic_ref = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, xinsn), UNSPEC_GOTOFF);
1079 pic_ref = gen_rtx_CONST (Pmode, pic_ref);
1080 pic_ref = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, pic_ref);
1081 pic_ref = gen_const_mem (Pmode, pic_ref);
1082 reg = pic_ref;
1084 return reg;
1087 return x;
1090 /* Block Moves. */
1092 #define MAX_MOVE_REGS 8
1093 #define MAX_MOVE_BYTES (MAX_MOVE_REGS * UNITS_PER_WORD)
1095 /* Emit straight-line code to move LENGTH bytes from SRC to DEST.
1096 Assume that the areas do not overlap. */
1098 static void
1099 microblaze_block_move_straight (rtx dest, rtx src, HOST_WIDE_INT length)
1101 HOST_WIDE_INT offset, delta;
1102 unsigned HOST_WIDE_INT bits;
1103 int i;
1104 machine_mode mode;
1105 rtx *regs;
1107 bits = BITS_PER_WORD;
1108 mode = mode_for_size (bits, MODE_INT, 0);
1109 delta = bits / BITS_PER_UNIT;
1111 /* Allocate a buffer for the temporary registers. */
1112 regs = XALLOCAVEC (rtx, length / delta);
1114 /* Load as many BITS-sized chunks as possible. Use a normal load if
1115 the source has enough alignment, otherwise use left/right pairs. */
1116 for (offset = 0, i = 0; offset + delta <= length; offset += delta, i++)
1118 regs[i] = gen_reg_rtx (mode);
1119 emit_move_insn (regs[i], adjust_address (src, mode, offset));
1122 /* Copy the chunks to the destination. */
1123 for (offset = 0, i = 0; offset + delta <= length; offset += delta, i++)
1124 emit_move_insn (adjust_address (dest, mode, offset), regs[i]);
1126 /* Mop up any left-over bytes. */
1127 if (offset < length)
1129 src = adjust_address (src, BLKmode, offset);
1130 dest = adjust_address (dest, BLKmode, offset);
1131 move_by_pieces (dest, src, length - offset,
1132 MIN (MEM_ALIGN (src), MEM_ALIGN (dest)), 0);
1136 /* Helper function for doing a loop-based block operation on memory
1137 reference MEM. Each iteration of the loop will operate on LENGTH
1138 bytes of MEM.
1140 Create a new base register for use within the loop and point it to
1141 the start of MEM. Create a new memory reference that uses this
1142 register. Store them in *LOOP_REG and *LOOP_MEM respectively. */
1144 static void
1145 microblaze_adjust_block_mem (rtx mem, HOST_WIDE_INT length,
1146 rtx * loop_reg, rtx * loop_mem)
1148 *loop_reg = copy_addr_to_reg (XEXP (mem, 0));
1150 /* Although the new mem does not refer to a known location,
1151 it does keep up to LENGTH bytes of alignment. */
1152 *loop_mem = change_address (mem, BLKmode, *loop_reg);
1153 set_mem_align (*loop_mem,
1154 MIN ((HOST_WIDE_INT) MEM_ALIGN (mem),
1155 length * BITS_PER_UNIT));
1159 /* Move LENGTH bytes from SRC to DEST using a loop that moves MAX_MOVE_BYTES
1160 per iteration. LENGTH must be at least MAX_MOVE_BYTES. Assume that the
1161 memory regions do not overlap. */
1163 static void
1164 microblaze_block_move_loop (rtx dest, rtx src, HOST_WIDE_INT length)
1166 rtx_code_label *label;
1167 rtx src_reg, dest_reg, final_src;
1168 HOST_WIDE_INT leftover;
1170 leftover = length % MAX_MOVE_BYTES;
1171 length -= leftover;
1173 /* Create registers and memory references for use within the loop. */
1174 microblaze_adjust_block_mem (src, MAX_MOVE_BYTES, &src_reg, &src);
1175 microblaze_adjust_block_mem (dest, MAX_MOVE_BYTES, &dest_reg, &dest);
1177 /* Calculate the value that SRC_REG should have after the last iteration
1178 of the loop. */
1179 final_src = expand_simple_binop (Pmode, PLUS, src_reg, GEN_INT (length),
1180 0, 0, OPTAB_WIDEN);
1182 /* Emit the start of the loop. */
1183 label = gen_label_rtx ();
1184 emit_label (label);
1186 /* Emit the loop body. */
1187 microblaze_block_move_straight (dest, src, MAX_MOVE_BYTES);
1189 /* Move on to the next block. */
1190 emit_move_insn (src_reg, plus_constant (Pmode, src_reg, MAX_MOVE_BYTES));
1191 emit_move_insn (dest_reg, plus_constant (Pmode, dest_reg, MAX_MOVE_BYTES));
1193 /* Emit the test & branch. */
1194 emit_insn (gen_cbranchsi4 (gen_rtx_NE (SImode, src_reg, final_src),
1195 src_reg, final_src, label));
1197 /* Mop up any left-over bytes. */
1198 if (leftover)
1199 microblaze_block_move_straight (dest, src, leftover);
1202 /* Expand a movmemsi instruction. */
1204 bool
1205 microblaze_expand_block_move (rtx dest, rtx src, rtx length, rtx align_rtx)
1208 if (GET_CODE (length) == CONST_INT)
1210 HOST_WIDE_INT bytes = INTVAL (length);
1211 int align = INTVAL (align_rtx);
1213 if (align > UNITS_PER_WORD)
1215 align = UNITS_PER_WORD; /* We can't do any better. */
1217 else if (align < UNITS_PER_WORD)
1219 if (INTVAL (length) <= MAX_MOVE_BYTES)
1221 move_by_pieces (dest, src, bytes, align, 0);
1222 return true;
1224 else
1225 return false;
1228 if (INTVAL (length) <= 2 * MAX_MOVE_BYTES)
1230 microblaze_block_move_straight (dest, src, INTVAL (length));
1231 return true;
1233 else if (optimize)
1235 microblaze_block_move_loop (dest, src, INTVAL (length));
1236 return true;
1239 return false;
1242 static bool
1243 microblaze_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED,
1244 int opno ATTRIBUTE_UNUSED, int *total,
1245 bool speed ATTRIBUTE_UNUSED)
1247 machine_mode mode = GET_MODE (x);
1249 switch (code)
1251 case MEM:
1253 int num_words = (GET_MODE_SIZE (mode) > UNITS_PER_WORD) ? 2 : 1;
1254 if (simple_memory_operand (x, mode))
1255 *total = COSTS_N_INSNS (2 * num_words);
1256 else
1257 *total = COSTS_N_INSNS (2 * (2 * num_words));
1259 return true;
1261 case NOT:
1263 if (mode == DImode)
1265 *total = COSTS_N_INSNS (2);
1267 else
1268 *total = COSTS_N_INSNS (1);
1269 return false;
1271 case AND:
1272 case IOR:
1273 case XOR:
1275 if (mode == DImode)
1277 *total = COSTS_N_INSNS (2);
1279 else
1280 *total = COSTS_N_INSNS (1);
1282 return false;
1284 case ASHIFT:
1285 case ASHIFTRT:
1286 case LSHIFTRT:
1288 if (TARGET_BARREL_SHIFT)
1290 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v5.00.a")
1291 >= 0)
1292 *total = COSTS_N_INSNS (1);
1293 else
1294 *total = COSTS_N_INSNS (2);
1296 else if (!TARGET_SOFT_MUL)
1297 *total = COSTS_N_INSNS (1);
1298 else if (GET_CODE (XEXP (x, 1)) == CONST_INT)
1300 /* Add 1 to make shift slightly more expensive than add. */
1301 *total = COSTS_N_INSNS (INTVAL (XEXP (x, 1))) + 1;
1302 /* Reduce shift costs for special circumstances. */
1303 if (optimize_size && INTVAL (XEXP (x, 1)) > 5)
1304 *total -= 2;
1305 if (!optimize_size && INTVAL (XEXP (x, 1)) > 17)
1306 *total -= 2;
1308 else
1309 /* Double the worst cost of shifts when there is no barrel shifter and
1310 the shift amount is in a reg. */
1311 *total = COSTS_N_INSNS (32 * 4);
1312 return true;
1314 case PLUS:
1315 case MINUS:
1317 if (mode == SFmode || mode == DFmode)
1319 if (TARGET_HARD_FLOAT)
1320 *total = COSTS_N_INSNS (6);
1321 return true;
1323 else if (mode == DImode)
1325 *total = COSTS_N_INSNS (4);
1326 return true;
1328 else
1330 *total = COSTS_N_INSNS (1);
1331 return true;
1334 return false;
1336 case NEG:
1338 if (mode == DImode)
1339 *total = COSTS_N_INSNS (4);
1341 return false;
1343 case MULT:
1345 if (mode == SFmode)
1347 if (TARGET_HARD_FLOAT)
1348 *total = COSTS_N_INSNS (6);
1350 else if (!TARGET_SOFT_MUL)
1352 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v5.00.a")
1353 >= 0)
1354 *total = COSTS_N_INSNS (1);
1355 else
1356 *total = COSTS_N_INSNS (3);
1358 else
1359 *total = COSTS_N_INSNS (10);
1360 return true;
1362 case DIV:
1363 case UDIV:
1365 if (mode == SFmode)
1367 if (TARGET_HARD_FLOAT)
1368 *total = COSTS_N_INSNS (23);
1370 return false;
1372 case SIGN_EXTEND:
1374 *total = COSTS_N_INSNS (1);
1375 return false;
1377 case ZERO_EXTEND:
1379 *total = COSTS_N_INSNS (1);
1380 return false;
1384 return false;
1387 /* Return the number of instructions needed to load or store a value
1388 of mode MODE at X. Return 0 if X isn't valid for MODE. */
1390 static int
1391 microblaze_address_insns (rtx x, machine_mode mode)
1393 struct microblaze_address_info addr;
1395 if (microblaze_classify_address (&addr, x, mode, false))
1397 switch (addr.type)
1399 case ADDRESS_REG:
1400 if (SMALL_INT (addr.offset))
1401 return 1;
1402 else
1403 return 2;
1404 case ADDRESS_CONST_INT:
1405 if (SMALL_INT (x))
1406 return 1;
1407 else
1408 return 2;
1409 case ADDRESS_REG_INDEX:
1410 return 1;
1411 case ADDRESS_SYMBOLIC:
1412 case ADDRESS_GOTOFF:
1413 return 2;
1414 case ADDRESS_TLS:
1415 switch (addr.tls_type)
1417 case TLS_GD:
1418 return 2;
1419 case TLS_LDM:
1420 return 2;
1421 case TLS_DTPREL:
1422 return 1;
1423 default :
1424 abort();
1426 default:
1427 break;
1430 return 0;
1433 /* Provide the costs of an addressing mode that contains ADDR.
1434 If ADDR is not a valid address, its cost is irrelevant. */
1435 static int
1436 microblaze_address_cost (rtx addr, machine_mode mode ATTRIBUTE_UNUSED,
1437 addr_space_t as ATTRIBUTE_UNUSED,
1438 bool speed ATTRIBUTE_UNUSED)
1440 return COSTS_N_INSNS (microblaze_address_insns (addr, GET_MODE (addr)));
1443 /* Return nonzero if X is an address which needs a temporary register when
1444 reloaded while generating PIC code. */
1447 pic_address_needs_scratch (rtx x)
1449 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x,0)) == PLUS)
1451 rtx p0, p1;
1453 p0 = XEXP (XEXP (x, 0), 0);
1454 p1 = XEXP (XEXP (x, 0), 1);
1456 if ((GET_CODE (p0) == SYMBOL_REF || GET_CODE (p0) == LABEL_REF)
1457 && (GET_CODE (p1) == CONST_INT)
1458 && (flag_pic == 2 || microblaze_tls_symbol_p (p0) || !SMALL_INT (p1)))
1459 return 1;
1461 return 0;
1464 /* Argument support functions. */
1465 /* Initialize CUMULATIVE_ARGS for a function. */
1467 void
1468 init_cumulative_args (CUMULATIVE_ARGS * cum, tree fntype,
1469 rtx libname ATTRIBUTE_UNUSED)
1471 static CUMULATIVE_ARGS zero_cum;
1472 tree param, next_param;
1474 *cum = zero_cum;
1476 /* Determine if this function has variable arguments. This is
1477 indicated by the last argument being 'void_type_mode' if there
1478 are no variable arguments. The standard MicroBlaze calling sequence
1479 passes all arguments in the general purpose registers in this case. */
1481 for (param = fntype ? TYPE_ARG_TYPES (fntype) : 0;
1482 param != 0; param = next_param)
1484 next_param = TREE_CHAIN (param);
1485 if (next_param == 0 && TREE_VALUE (param) != void_type_node)
1486 cum->gp_reg_found = 1;
1490 /* Advance the argument to the next argument position. */
1492 static void
1493 microblaze_function_arg_advance (cumulative_args_t cum_v,
1494 machine_mode mode,
1495 const_tree type, bool named ATTRIBUTE_UNUSED)
1497 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
1499 cum->arg_number++;
1500 switch (mode)
1502 case VOIDmode:
1503 break;
1505 default:
1506 gcc_assert (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
1507 || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT);
1509 cum->gp_reg_found = 1;
1510 cum->arg_words += ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1)
1511 / UNITS_PER_WORD);
1512 break;
1514 case BLKmode:
1515 cum->gp_reg_found = 1;
1516 cum->arg_words += ((int_size_in_bytes (type) + UNITS_PER_WORD - 1)
1517 / UNITS_PER_WORD);
1518 break;
1520 case SFmode:
1521 cum->arg_words++;
1522 if (!cum->gp_reg_found && cum->arg_number <= 2)
1523 cum->fp_code += 1 << ((cum->arg_number - 1) * 2);
1524 break;
1526 case DFmode:
1527 cum->arg_words += 2;
1528 if (!cum->gp_reg_found && cum->arg_number <= 2)
1529 cum->fp_code += 2 << ((cum->arg_number - 1) * 2);
1530 break;
1532 case DImode:
1533 cum->gp_reg_found = 1;
1534 cum->arg_words += 2;
1535 break;
1537 case QImode:
1538 case HImode:
1539 case SImode:
1540 case TImode:
1541 cum->gp_reg_found = 1;
1542 cum->arg_words++;
1543 break;
1547 /* Return an RTL expression containing the register for the given mode,
1548 or 0 if the argument is to be passed on the stack. */
1550 static rtx
1551 microblaze_function_arg (cumulative_args_t cum_v, machine_mode mode,
1552 const_tree type ATTRIBUTE_UNUSED,
1553 bool named ATTRIBUTE_UNUSED)
1555 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
1557 rtx ret;
1558 int regbase = -1;
1559 int *arg_words = &cum->arg_words;
1561 cum->last_arg_fp = 0;
1562 switch (mode)
1564 case SFmode:
1565 case DFmode:
1566 case VOIDmode:
1567 case QImode:
1568 case HImode:
1569 case SImode:
1570 case DImode:
1571 case TImode:
1572 regbase = GP_ARG_FIRST;
1573 break;
1574 default:
1575 gcc_assert (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
1576 || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT);
1577 /* Drops through. */
1578 case BLKmode:
1579 regbase = GP_ARG_FIRST;
1580 break;
1583 if (*arg_words >= MAX_ARGS_IN_REGISTERS)
1584 ret = 0;
1585 else
1587 gcc_assert (regbase != -1);
1589 ret = gen_rtx_REG (mode, regbase + *arg_words);
1592 if (mode == VOIDmode)
1594 if (cum->num_adjusts > 0)
1595 ret = gen_rtx_PARALLEL ((machine_mode) cum->fp_code,
1596 gen_rtvec_v (cum->num_adjusts, cum->adjust));
1599 return ret;
1602 /* Return number of bytes of argument to put in registers. */
1603 static int
1604 function_arg_partial_bytes (cumulative_args_t cum_v, machine_mode mode,
1605 tree type, bool named ATTRIBUTE_UNUSED)
1607 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
1609 if ((mode == BLKmode
1610 || GET_MODE_CLASS (mode) != MODE_COMPLEX_INT
1611 || GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT)
1612 && cum->arg_words < MAX_ARGS_IN_REGISTERS)
1614 int words;
1615 if (mode == BLKmode)
1616 words = ((int_size_in_bytes (type) + UNITS_PER_WORD - 1)
1617 / UNITS_PER_WORD);
1618 else
1619 words = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
1621 if (words + cum->arg_words <= MAX_ARGS_IN_REGISTERS)
1622 return 0; /* structure fits in registers */
1624 return (MAX_ARGS_IN_REGISTERS - cum->arg_words) * UNITS_PER_WORD;
1627 else if (mode == DImode && cum->arg_words == MAX_ARGS_IN_REGISTERS - 1)
1628 return UNITS_PER_WORD;
1630 return 0;
1633 /* Convert a version number of the form "vX.YY.Z" to an integer encoding
1634 for easier range comparison. */
1635 static int
1636 microblaze_version_to_int (const char *version)
1638 const char *p, *v;
1639 const char *tmpl = "vXX.YY.Z";
1640 int iver = 0;
1642 p = version;
1643 v = tmpl;
1645 while (*p)
1647 if (*v == 'X')
1648 { /* Looking for major */
1649 if (*p == '.')
1651 *v++;
1653 else
1655 if (!(*p >= '0' && *p <= '9'))
1656 return -1;
1657 iver += (int) (*p - '0');
1658 iver *= 10;
1661 else if (*v == 'Y')
1662 { /* Looking for minor */
1663 if (!(*p >= '0' && *p <= '9'))
1664 return -1;
1665 iver += (int) (*p - '0');
1666 iver *= 10;
1668 else if (*v == 'Z')
1669 { /* Looking for compat */
1670 if (!(*p >= 'a' && *p <= 'z'))
1671 return -1;
1672 iver *= 10;
1673 iver += (int) (*p - 'a');
1675 else
1677 if (*p != *v)
1678 return -1;
1681 v++;
1682 p++;
1685 if (*p)
1686 return -1;
1688 return iver;
1692 static void
1693 microblaze_option_override (void)
1695 register int i, start;
1696 register int regno;
1697 register machine_mode mode;
1698 int ver;
1700 microblaze_section_threshold = (global_options_set.x_g_switch_value
1701 ? g_switch_value
1702 : MICROBLAZE_DEFAULT_GVALUE);
1704 if (flag_pic)
1706 /* Make sure it's 2, we only support one kind of PIC. */
1707 flag_pic = 2;
1708 if (!TARGET_SUPPORTS_PIC)
1710 error ("-fPIC/-fpic not supported for this target");
1711 /* Clear it to avoid further errors. */
1712 flag_pic = 0;
1716 /* Check the MicroBlaze CPU version for any special action to be done. */
1717 if (microblaze_select_cpu == NULL)
1718 microblaze_select_cpu = MICROBLAZE_DEFAULT_CPU;
1719 ver = microblaze_version_to_int (microblaze_select_cpu);
1720 if (ver == -1)
1722 error ("%qs is an invalid argument to -mcpu=", microblaze_select_cpu);
1725 ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v3.00.a");
1726 if (ver < 0)
1728 /* No hardware exceptions in earlier versions. So no worries. */
1729 #if 0
1730 microblaze_select_flags &= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY);
1731 #endif
1732 microblaze_no_unsafe_delay = 0;
1733 microblaze_pipe = MICROBLAZE_PIPE_3;
1735 else if (ver == 0
1736 || (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v4.00.b")
1737 == 0))
1739 #if 0
1740 microblaze_select_flags |= (MICROBLAZE_MASK_NO_UNSAFE_DELAY);
1741 #endif
1742 microblaze_no_unsafe_delay = 1;
1743 microblaze_pipe = MICROBLAZE_PIPE_3;
1745 else
1747 /* We agree to use 5 pipe-stage model even on area optimized 3
1748 pipe-stage variants. */
1749 #if 0
1750 microblaze_select_flags &= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY);
1751 #endif
1752 microblaze_no_unsafe_delay = 0;
1753 microblaze_pipe = MICROBLAZE_PIPE_5;
1754 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v5.00.a") == 0
1755 || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu,
1756 "v5.00.b") == 0
1757 || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu,
1758 "v5.00.c") == 0)
1760 /* Pattern compares are to be turned on by default only when
1761 compiling for MB v5.00.'z'. */
1762 target_flags |= MASK_PATTERN_COMPARE;
1766 ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v6.00.a");
1767 if (ver < 0)
1769 if (TARGET_MULTIPLY_HIGH)
1770 warning (0,
1771 "-mxl-multiply-high can be used only with -mcpu=v6.00.a or greater");
1774 ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v8.10.a");
1775 microblaze_has_clz = 1;
1776 if (ver < 0)
1778 /* MicroBlaze prior to 8.10.a didn't have clz. */
1779 microblaze_has_clz = 0;
1782 /* TARGET_REORDER defaults to 2 if -mxl-reorder not specified. */
1783 ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v8.30.a");
1784 if (ver < 0)
1786 if (TARGET_REORDER == 1)
1787 warning (0, "-mxl-reorder can be used only with -mcpu=v8.30.a or greater");
1788 TARGET_REORDER = 0;
1790 else if ((ver == 0) && !TARGET_PATTERN_COMPARE)
1792 if (TARGET_REORDER == 1)
1793 warning (0, "-mxl-reorder requires -mxl-pattern-compare for -mcpu=v8.30.a");
1794 TARGET_REORDER = 0;
1797 if (TARGET_MULTIPLY_HIGH && TARGET_SOFT_MUL)
1798 error ("-mxl-multiply-high requires -mno-xl-soft-mul");
1800 /* Always use DFA scheduler. */
1801 microblaze_sched_use_dfa = 1;
1803 #if 0
1804 microblaze_abicalls = MICROBLAZE_ABICALLS_NO;
1805 #endif
1807 /* Initialize the high, low values for legit floating point constants. */
1808 real_maxval (&dfhigh, 0, DFmode);
1809 real_maxval (&dflow, 1, DFmode);
1810 real_maxval (&sfhigh, 0, SFmode);
1811 real_maxval (&sflow, 1, SFmode);
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;
1823 microblaze_print_operand_punct[']'] = 1;
1824 microblaze_print_operand_punct['<'] = 1;
1825 microblaze_print_operand_punct['>'] = 1;
1826 microblaze_print_operand_punct['{'] = 1;
1827 microblaze_print_operand_punct['}'] = 1;
1828 microblaze_print_operand_punct['^'] = 1;
1829 microblaze_print_operand_punct['$'] = 1;
1830 microblaze_print_operand_punct['+'] = 1;
1832 /* Set up array to map GCC register number to debug register number.
1833 Ignore the special purpose register numbers. */
1835 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
1836 microblaze_dbx_regno[i] = -1;
1838 start = GP_DBX_FIRST - GP_REG_FIRST;
1839 for (i = GP_REG_FIRST; i <= GP_REG_LAST; i++)
1840 microblaze_dbx_regno[i] = i + start;
1842 /* Set up array giving whether a given register can hold a given mode. */
1844 for (mode = VOIDmode;
1845 mode != MAX_MACHINE_MODE; mode = (machine_mode) ((int) mode + 1))
1847 register int size = GET_MODE_SIZE (mode);
1849 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
1851 register int ok;
1853 if (mode == CCmode)
1855 ok = (ST_REG_P (regno) || GP_REG_P (regno));
1857 else if (GP_REG_P (regno))
1858 ok = ((regno & 1) == 0 || size <= UNITS_PER_WORD);
1859 else
1860 ok = 0;
1862 microblaze_hard_regno_mode_ok[(int) mode][regno] = ok;
1867 /* Return true if FUNC is an interrupt function as specified
1868 by the "interrupt_handler" attribute. */
1870 static int
1871 microblaze_interrupt_function_p (tree func)
1873 tree a;
1875 if (TREE_CODE (func) != FUNCTION_DECL)
1876 return 0;
1878 a = lookup_attribute ("interrupt_handler", DECL_ATTRIBUTES (func));
1879 return a != NULL_TREE;
1882 static int
1883 microblaze_fast_interrupt_function_p (tree func)
1885 tree a;
1887 if (TREE_CODE (func) != FUNCTION_DECL)
1888 return 0;
1890 a = lookup_attribute ("fast_interrupt", DECL_ATTRIBUTES (func));
1891 return a != NULL_TREE;
1894 microblaze_break_function_p (tree func)
1896 tree a;
1897 if (!func)
1898 return 0;
1899 if (TREE_CODE (func) != FUNCTION_DECL)
1900 return 0;
1902 a = lookup_attribute ("break_handler", DECL_ATTRIBUTES (func));
1903 return a != NULL_TREE;
1905 /* Return true if FUNC is an interrupt function which uses
1906 normal return, indicated by the "save_volatiles" attribute. */
1908 static int
1909 microblaze_save_volatiles (tree func)
1911 tree a;
1913 if (TREE_CODE (func) != FUNCTION_DECL)
1914 return 0;
1916 a = lookup_attribute ("save_volatiles", DECL_ATTRIBUTES (func));
1917 return a != NULL_TREE;
1920 /* Return whether function is tagged with 'interrupt_handler'
1921 or 'fast_interrupt' attribute. Return true if function
1922 should use return from interrupt rather than normal
1923 function return. */
1925 microblaze_is_interrupt_variant (void)
1927 return (interrupt_handler || fast_interrupt);
1930 microblaze_is_break_handler (void)
1932 return break_handler;
1935 /* Determine of register must be saved/restored in call. */
1936 static int
1937 microblaze_must_save_register (int regno)
1939 if (pic_offset_table_rtx &&
1940 (regno == MB_ABI_PIC_ADDR_REGNUM) && df_regs_ever_live_p (regno))
1941 return 1;
1943 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
1944 return 1;
1946 if (frame_pointer_needed && (regno == HARD_FRAME_POINTER_REGNUM))
1947 return 1;
1949 if (!crtl->is_leaf)
1951 if (regno == MB_ABI_SUB_RETURN_ADDR_REGNUM)
1952 return 1;
1953 if ((microblaze_is_interrupt_variant () || save_volatiles) &&
1954 (regno >= 3 && regno <= 12))
1955 return 1;
1958 if (microblaze_is_interrupt_variant ())
1960 if (df_regs_ever_live_p (regno)
1961 || regno == MB_ABI_MSR_SAVE_REG
1962 || (interrupt_handler
1963 && (regno == MB_ABI_ASM_TEMP_REGNUM
1964 || regno == MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM)))
1965 return 1;
1968 if (save_volatiles)
1970 if (df_regs_ever_live_p (regno)
1971 || regno == MB_ABI_ASM_TEMP_REGNUM
1972 || regno == MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM)
1973 return 1;
1976 return 0;
1979 /* Return the bytes needed to compute the frame pointer from the current
1980 stack pointer.
1982 MicroBlaze stack frames look like:
1986 Before call After call
1987 +-----------------------+ +-----------------------+
1988 high | | | |
1989 mem. | local variables, | | local variables, |
1990 | callee saved and | | callee saved and |
1991 | temps | | temps |
1992 +-----------------------+ +-----------------------+
1993 | arguments for called | | arguments for called |
1994 | subroutines | | subroutines |
1995 | (optional) | | (optional) |
1996 +-----------------------+ +-----------------------+
1997 | Link register | | Link register |
1998 SP->| | | |
1999 +-----------------------+ +-----------------------+
2001 | local variables, |
2002 | callee saved and |
2003 | temps |
2004 +-----------------------+
2005 | MSR (optional if, |
2006 | interrupt handler) |
2007 +-----------------------+
2009 | alloca allocations |
2011 +-----------------------+
2013 | arguments for called |
2014 | subroutines |
2015 | (optional) |
2017 +-----------------------+
2018 | Link register |
2019 low FP,SP->| |
2020 memory +-----------------------+
2024 static HOST_WIDE_INT
2025 compute_frame_size (HOST_WIDE_INT size)
2027 int regno;
2028 HOST_WIDE_INT total_size; /* # bytes that the entire frame takes up. */
2029 HOST_WIDE_INT var_size; /* # bytes that local variables take up. */
2030 HOST_WIDE_INT args_size; /* # bytes that outgoing arguments take up. */
2031 int link_debug_size; /* # bytes for link register. */
2032 HOST_WIDE_INT gp_reg_size; /* # bytes needed to store calle-saved gp regs. */
2033 long mask; /* mask of saved gp registers. */
2035 interrupt_handler =
2036 microblaze_interrupt_function_p (current_function_decl);
2037 break_handler =
2038 microblaze_break_function_p (current_function_decl);
2040 fast_interrupt =
2041 microblaze_fast_interrupt_function_p (current_function_decl);
2042 save_volatiles = microblaze_save_volatiles (current_function_decl);
2043 if (break_handler)
2044 interrupt_handler = break_handler;
2046 gp_reg_size = 0;
2047 mask = 0;
2048 var_size = size;
2049 args_size = crtl->outgoing_args_size;
2051 if ((args_size == 0) && cfun->calls_alloca)
2052 args_size = NUM_OF_ARGS * UNITS_PER_WORD;
2054 total_size = var_size + args_size;
2056 if (flag_pic == 2)
2057 /* force setting GOT. */
2058 df_set_regs_ever_live (MB_ABI_PIC_ADDR_REGNUM, true);
2060 /* Calculate space needed for gp registers. */
2061 for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
2063 if (microblaze_must_save_register (regno))
2066 if (regno != MB_ABI_SUB_RETURN_ADDR_REGNUM)
2067 /* Don't account for link register. It is accounted specially below. */
2068 gp_reg_size += GET_MODE_SIZE (SImode);
2070 mask |= (1L << (regno - GP_REG_FIRST));
2074 total_size += gp_reg_size;
2076 /* Add 4 bytes for MSR. */
2077 if (microblaze_is_interrupt_variant ())
2078 total_size += 4;
2080 /* No space to be allocated for link register in leaf functions with no other
2081 stack requirements. */
2082 if (total_size == 0 && crtl->is_leaf)
2083 link_debug_size = 0;
2084 else
2085 link_debug_size = UNITS_PER_WORD;
2087 total_size += link_debug_size;
2089 /* Save other computed information. */
2090 current_frame_info.total_size = total_size;
2091 current_frame_info.var_size = var_size;
2092 current_frame_info.args_size = args_size;
2093 current_frame_info.gp_reg_size = gp_reg_size;
2094 current_frame_info.mask = mask;
2095 current_frame_info.initialized = reload_completed;
2096 current_frame_info.num_gp = gp_reg_size / UNITS_PER_WORD;
2097 current_frame_info.link_debug_size = link_debug_size;
2099 if (mask)
2100 /* Offset from which to callee-save GP regs. */
2101 current_frame_info.gp_offset = (total_size - gp_reg_size);
2102 else
2103 current_frame_info.gp_offset = 0;
2105 /* Ok, we're done. */
2106 return total_size;
2109 /* Make sure that we're not trying to eliminate to the wrong hard frame
2110 pointer. */
2112 static bool
2113 microblaze_can_eliminate (const int from, const int to)
2115 return ((from == RETURN_ADDRESS_POINTER_REGNUM && !leaf_function_p())
2116 || (to == MB_ABI_SUB_RETURN_ADDR_REGNUM && leaf_function_p())
2117 || (from != RETURN_ADDRESS_POINTER_REGNUM
2118 && (to == HARD_FRAME_POINTER_REGNUM
2119 || (to == STACK_POINTER_REGNUM && !frame_pointer_needed))));
2122 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
2123 pointer or argument pointer or the return address pointer. TO is either
2124 the stack pointer or hard frame pointer. */
2126 HOST_WIDE_INT
2127 microblaze_initial_elimination_offset (int from, int to)
2129 HOST_WIDE_INT offset;
2131 switch (from)
2133 case FRAME_POINTER_REGNUM:
2134 offset = 0;
2135 break;
2136 case ARG_POINTER_REGNUM:
2137 if (to == STACK_POINTER_REGNUM || to == HARD_FRAME_POINTER_REGNUM)
2138 offset = compute_frame_size (get_frame_size ());
2139 else
2140 gcc_unreachable ();
2141 break;
2142 case RETURN_ADDRESS_POINTER_REGNUM:
2143 if (crtl->is_leaf)
2144 offset = 0;
2145 else
2146 offset = current_frame_info.gp_offset +
2147 ((UNITS_PER_WORD - (POINTER_SIZE / BITS_PER_UNIT)));
2148 break;
2149 default:
2150 gcc_unreachable ();
2152 return offset;
2155 /* Print operands using format code.
2157 The MicroBlaze specific codes are:
2159 'X' X is CONST_INT, prints 32 bits in hexadecimal format = "0x%08x",
2160 'x' X is CONST_INT, prints 16 bits in hexadecimal format = "0x%04x",
2161 'F' op is CONST_DOUBLE, print 32 bits in hex,
2162 'd' output integer constant in decimal,
2163 'z' if the operand is 0, use $0 instead of normal operand.
2164 'D' print second register of double-word register operand.
2165 'L' print low-order register of double-word register operand.
2166 'M' print high-order register of double-word register operand.
2167 'C' print part of opcode for a branch condition.
2168 'N' print part of opcode for a branch condition, inverted.
2169 'S' X is CODE_LABEL, print with prefix of "LS" (for embedded switch).
2170 'B' print 'z' for EQ, 'n' for NE
2171 'b' print 'n' for EQ, 'z' for NE
2172 'T' print 'f' for EQ, 't' for NE
2173 't' print 't' for EQ, 'f' for NE
2174 'm' Print 1<<operand.
2175 'i' Print 'i' if MEM operand has immediate value
2176 'y' Print 'y' if MEM operand is single register
2177 'o' Print operand address+4
2178 '?' Print 'd' if we use a branch with delay slot instead of normal branch.
2179 'h' Print high word of const_double (int or float) value as hex
2180 'j' Print low word of const_double (int or float) value as hex
2181 's' Print -1 if operand is negative, 0 if positive (sign extend)
2182 '@' Print the name of the temporary register (rMB_ABI_ASM_TEMP_REGNUM).
2183 '#' Print nop if the delay slot of a branch is not filled.
2186 void
2187 print_operand (FILE * file, rtx op, int letter)
2189 register enum rtx_code code;
2191 if (PRINT_OPERAND_PUNCT_VALID_P (letter))
2193 switch (letter)
2195 case '?':
2196 /* Conditionally add a 'd' to indicate filled delay slot. */
2197 if (final_sequence != NULL)
2198 fputs ("d", file);
2199 break;
2201 case '#':
2202 /* Conditionally add a nop in unfilled delay slot. */
2203 if (final_sequence == NULL)
2204 fputs ("nop\t\t# Unfilled delay slot\n", file);
2205 break;
2207 case '@':
2208 fputs (reg_names[GP_REG_FIRST + MB_ABI_ASM_TEMP_REGNUM], file);
2209 break;
2211 default:
2212 output_operand_lossage ("unknown punctuation '%c'", letter);
2213 break;
2216 return;
2219 if (!op)
2221 output_operand_lossage ("null pointer");
2222 return;
2225 code = GET_CODE (op);
2227 if (code == SIGN_EXTEND)
2228 op = XEXP (op, 0), code = GET_CODE (op);
2230 if (letter == 'C')
2231 switch (code)
2233 case EQ:
2234 fputs ("eq", file);
2235 break;
2236 case NE:
2237 fputs ("ne", file);
2238 break;
2239 case GT:
2240 case GTU:
2241 fputs ("gt", file);
2242 break;
2243 case GE:
2244 case GEU:
2245 fputs ("ge", file);
2246 break;
2247 case LT:
2248 case LTU:
2249 fputs ("lt", file);
2250 break;
2251 case LE:
2252 case LEU:
2253 fputs ("le", file);
2254 break;
2255 default:
2256 fatal_insn ("PRINT_OPERAND, invalid insn for %%C", op);
2259 else if (letter == 'N')
2260 switch (code)
2262 case EQ:
2263 fputs ("ne", file);
2264 break;
2265 case NE:
2266 fputs ("eq", file);
2267 break;
2268 case GT:
2269 case GTU:
2270 fputs ("le", file);
2271 break;
2272 case GE:
2273 case GEU:
2274 fputs ("lt", file);
2275 break;
2276 case LT:
2277 case LTU:
2278 fputs ("ge", file);
2279 break;
2280 case LE:
2281 case LEU:
2282 fputs ("gt", file);
2283 break;
2284 default:
2285 fatal_insn ("PRINT_OPERAND, invalid insn for %%N", op);
2288 else if (letter == 'S')
2290 char buffer[100];
2292 ASM_GENERATE_INTERNAL_LABEL (buffer, "LS", CODE_LABEL_NUMBER (op));
2293 assemble_name (file, buffer);
2296 /* Print 'i' for memory operands which have immediate values. */
2297 else if (letter == 'i')
2299 if (code == MEM)
2301 struct microblaze_address_info info;
2303 if (!microblaze_classify_address
2304 (&info, XEXP (op, 0), GET_MODE (op), 1))
2305 fatal_insn ("insn contains an invalid address !", op);
2307 switch (info.type)
2309 case ADDRESS_REG:
2310 case ADDRESS_CONST_INT:
2311 case ADDRESS_SYMBOLIC:
2312 case ADDRESS_GOTOFF:
2313 case ADDRESS_TLS:
2314 fputs ("i", file);
2315 break;
2316 case ADDRESS_REG_INDEX:
2317 break;
2318 case ADDRESS_INVALID:
2319 case ADDRESS_PLT:
2320 fatal_insn ("invalid address", op);
2325 else if (code == REG || code == SUBREG)
2327 register int regnum;
2329 if (code == REG)
2330 regnum = REGNO (op);
2331 else
2332 regnum = true_regnum (op);
2334 if ((letter == 'M' && !WORDS_BIG_ENDIAN)
2335 || (letter == 'L' && WORDS_BIG_ENDIAN) || letter == 'D')
2336 regnum++;
2338 fprintf (file, "%s", reg_names[regnum]);
2341 else if (code == MEM)
2342 if (letter == 'o')
2344 rtx op4 = adjust_address (op, GET_MODE (op), 4);
2345 output_address (XEXP (op4, 0));
2347 else if (letter == 'y')
2349 rtx mem_reg = XEXP (op, 0);
2350 if (GET_CODE (mem_reg) == REG)
2352 register int regnum = REGNO (mem_reg);
2353 fprintf (file, "%s", reg_names[regnum]);
2356 else
2357 output_address (XEXP (op, 0));
2359 else if (letter == 'h' || letter == 'j')
2361 long val[2];
2362 if (code == CONST_DOUBLE)
2364 if (GET_MODE (op) == DFmode)
2366 REAL_VALUE_TYPE value;
2367 REAL_VALUE_FROM_CONST_DOUBLE (value, op);
2368 REAL_VALUE_TO_TARGET_DOUBLE (value, val);
2370 else
2372 val[0] = CONST_DOUBLE_HIGH (op);
2373 val[1] = CONST_DOUBLE_LOW (op);
2376 else if (code == CONST_INT)
2378 val[0] = (INTVAL (op) & 0xffffffff00000000LL) >> 32;
2379 val[1] = INTVAL (op) & 0x00000000ffffffffLL;
2380 if (val[0] == 0 && val[1] < 0)
2381 val[0] = -1;
2384 fprintf (file, "0x%8.8lx", (letter == 'h') ? val[0] : val[1]);
2386 else if (code == CONST_DOUBLE)
2388 if (letter == 'F')
2390 unsigned long value_long;
2391 REAL_VALUE_TYPE value;
2392 REAL_VALUE_FROM_CONST_DOUBLE (value, op);
2393 REAL_VALUE_TO_TARGET_SINGLE (value, value_long);
2394 fprintf (file, HOST_WIDE_INT_PRINT_HEX, value_long);
2396 else
2398 char s[60];
2399 real_to_decimal (s, CONST_DOUBLE_REAL_VALUE (op), sizeof (s), 0, 1);
2400 fputs (s, file);
2404 else if (code == UNSPEC)
2406 print_operand_address (file, op);
2409 else if (letter == 'x' && GET_CODE (op) == CONST_INT)
2410 fprintf (file, HOST_WIDE_INT_PRINT_HEX, 0xffff & INTVAL (op));
2412 else if (letter == 'X' && GET_CODE (op) == CONST_INT)
2413 fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (op));
2415 else if (letter == 'd' && GET_CODE (op) == CONST_INT)
2416 fprintf (file, HOST_WIDE_INT_PRINT_DEC, (INTVAL (op)));
2418 else if (letter == 'z' && GET_CODE (op) == CONST_INT && INTVAL (op) == 0)
2419 fputs (reg_names[GP_REG_FIRST], file);
2421 else if (letter == 's' && GET_CODE (op) == CONST_INT)
2422 if (INTVAL (op) < 0)
2423 fputs ("-1", file);
2424 else
2425 fputs ("0", file);
2427 else if (letter == 'd' || letter == 'x' || letter == 'X' || letter == 's')
2428 output_operand_lossage ("letter %c was found & insn was not CONST_INT", letter);
2430 else if (letter == 'B')
2431 fputs (code == EQ ? "z" : "n", file);
2432 else if (letter == 'b')
2433 fputs (code == EQ ? "n" : "z", file);
2434 else if (letter == 'T')
2435 fputs (code == EQ ? "f" : "t", file);
2436 else if (letter == 't')
2437 fputs (code == EQ ? "t" : "f", file);
2439 else if (code == CONST
2440 && ((GET_CODE (XEXP (op, 0)) == REG)
2441 || (GET_CODE (XEXP (op, 0)) == UNSPEC)))
2443 print_operand (file, XEXP (op, 0), letter);
2445 else if (code == CONST
2446 && (GET_CODE (XEXP (op, 0)) == PLUS)
2447 && (GET_CODE (XEXP (XEXP (op, 0), 0)) == REG)
2448 && (GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST))
2450 print_operand_address (file, XEXP (op, 0));
2452 else if (letter == 'm')
2453 fprintf (file, HOST_WIDE_INT_PRINT_DEC, (1L << INTVAL (op)));
2454 else
2455 output_addr_const (file, op);
2458 /* A C compound statement to output to stdio stream STREAM the
2459 assembler syntax for an instruction operand that is a memory
2460 reference whose address is ADDR. ADDR is an RTL expression.
2462 Possible address classifications and output formats are,
2464 ADDRESS_REG "%0, r0"
2466 ADDRESS_REG with non-zero "%0, <addr_const>"
2467 offset
2469 ADDRESS_REG_INDEX "rA, RB"
2470 (if rA is r0, rA and rB are swapped)
2472 ADDRESS_CONST_INT "r0, <addr_const>"
2474 ADDRESS_SYMBOLIC "rBase, <addr_const>"
2475 (rBase is a base register suitable for the
2476 symbol's type)
2479 void
2480 print_operand_address (FILE * file, rtx addr)
2482 struct microblaze_address_info info;
2483 enum microblaze_address_type type;
2484 if (!microblaze_classify_address (&info, addr, GET_MODE (addr), 1))
2485 fatal_insn ("insn contains an invalid address !", addr);
2487 type = info.type;
2488 switch (info.type)
2490 case ADDRESS_REG:
2491 fprintf (file, "%s,", reg_names[REGNO (info.regA)]);
2492 output_addr_const (file, info.offset);
2493 break;
2494 case ADDRESS_REG_INDEX:
2495 if (REGNO (info.regA) == 0)
2496 /* Make rB == r0 instead of rA == r0. This helps reduce read port
2497 congestion. */
2498 fprintf (file, "%s,%s", reg_names[REGNO (info.regB)],
2499 reg_names[REGNO (info.regA)]);
2500 else if (REGNO (info.regB) != 0)
2501 /* This is a silly swap to help Dhrystone. */
2502 fprintf (file, "%s,%s", reg_names[REGNO (info.regB)],
2503 reg_names[REGNO (info.regA)]);
2504 break;
2505 case ADDRESS_CONST_INT:
2506 fprintf (file, "%s,", reg_names[REGNO (info.regA)]);
2507 output_addr_const (file, info.offset);
2508 break;
2509 case ADDRESS_SYMBOLIC:
2510 case ADDRESS_GOTOFF:
2511 case ADDRESS_PLT:
2512 case ADDRESS_TLS:
2513 if (info.regA)
2514 fprintf (file, "%s,", reg_names[REGNO (info.regA)]);
2515 output_addr_const (file, info.symbol);
2516 if (type == ADDRESS_GOTOFF)
2518 fputs ("@GOT", file);
2520 else if (type == ADDRESS_PLT)
2522 fputs ("@PLT", file);
2524 else if (type == ADDRESS_TLS)
2526 switch (info.tls_type)
2528 case TLS_GD:
2529 fputs ("@TLSGD", file);
2530 break;
2531 case TLS_LDM:
2532 fputs ("@TLSLDM", file);
2533 break;
2534 case TLS_DTPREL:
2535 fputs ("@TLSDTPREL", file);
2536 break;
2537 default :
2538 abort();
2539 break;
2542 break;
2543 case ADDRESS_INVALID:
2544 fatal_insn ("invalid address", addr);
2545 break;
2549 /* Emit either a label, .comm, or .lcomm directive, and mark that the symbol
2550 is used, so that we don't emit an .extern for it in
2551 microblaze_asm_file_end. */
2553 void
2554 microblaze_declare_object (FILE * stream, const char *name,
2555 const char *section, const char *fmt, int size)
2558 fputs (section, stream);
2559 assemble_name (stream, name);
2560 fprintf (stream, fmt, size);
2563 /* Common code to emit the insns (or to write the instructions to a file)
2564 to save/restore registers.
2566 Other parts of the code assume that MICROBLAZE_TEMP1_REGNUM (aka large_reg)
2567 is not modified within save_restore_insns. */
2569 #define BITSET_P(VALUE,BIT) (((VALUE) & (1L << (BIT))) != 0)
2571 /* Save or restore instructions based on whether this is the prologue or
2572 epilogue. prologue is 1 for the prologue. */
2573 static void
2574 save_restore_insns (int prologue)
2576 rtx base_reg_rtx, reg_rtx, mem_rtx, /* msr_rtx, */ isr_reg_rtx =
2577 0, isr_mem_rtx = 0;
2578 rtx isr_msr_rtx = 0, insn;
2579 long mask = current_frame_info.mask;
2580 HOST_WIDE_INT gp_offset;
2581 int regno;
2583 if (frame_pointer_needed
2584 && !BITSET_P (mask, HARD_FRAME_POINTER_REGNUM - GP_REG_FIRST))
2585 gcc_unreachable ();
2587 if (mask == 0)
2588 return;
2590 /* Save registers starting from high to low. The debuggers prefer at least
2591 the return register be stored at func+4, and also it allows us not to
2592 need a nop in the epilog if at least one register is reloaded in
2593 addition to return address. */
2595 /* Pick which pointer to use as a base register. For small frames, just
2596 use the stack pointer. Otherwise, use a temporary register. Save 2
2597 cycles if the save area is near the end of a large frame, by reusing
2598 the constant created in the prologue/epilogue to adjust the stack
2599 frame. */
2601 gp_offset = current_frame_info.gp_offset;
2603 gcc_assert (gp_offset > 0);
2605 base_reg_rtx = stack_pointer_rtx;
2607 /* For interrupt_handlers, need to save/restore the MSR. */
2608 if (microblaze_is_interrupt_variant ())
2610 isr_mem_rtx = gen_rtx_MEM (SImode,
2611 gen_rtx_PLUS (Pmode, base_reg_rtx,
2612 GEN_INT (current_frame_info.
2613 gp_offset -
2614 UNITS_PER_WORD)));
2616 /* Do not optimize in flow analysis. */
2617 MEM_VOLATILE_P (isr_mem_rtx) = 1;
2618 isr_reg_rtx = gen_rtx_REG (SImode, MB_ABI_MSR_SAVE_REG);
2619 isr_msr_rtx = gen_rtx_REG (SImode, ST_REG);
2622 if (microblaze_is_interrupt_variant () && !prologue)
2624 emit_move_insn (isr_reg_rtx, isr_mem_rtx);
2625 emit_move_insn (isr_msr_rtx, isr_reg_rtx);
2626 /* Do not optimize in flow analysis. */
2627 emit_insn (gen_rtx_USE (SImode, isr_reg_rtx));
2628 emit_insn (gen_rtx_USE (SImode, isr_msr_rtx));
2631 for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
2633 if (BITSET_P (mask, regno - GP_REG_FIRST))
2635 if (regno == MB_ABI_SUB_RETURN_ADDR_REGNUM)
2636 /* Don't handle here. Already handled as the first register. */
2637 continue;
2639 reg_rtx = gen_rtx_REG (SImode, regno);
2640 insn = gen_rtx_PLUS (Pmode, base_reg_rtx, GEN_INT (gp_offset));
2641 mem_rtx = gen_rtx_MEM (SImode, insn);
2642 if (microblaze_is_interrupt_variant () || save_volatiles)
2643 /* Do not optimize in flow analysis. */
2644 MEM_VOLATILE_P (mem_rtx) = 1;
2646 if (prologue)
2648 insn = emit_move_insn (mem_rtx, reg_rtx);
2649 RTX_FRAME_RELATED_P (insn) = 1;
2651 else
2653 insn = emit_move_insn (reg_rtx, mem_rtx);
2656 gp_offset += GET_MODE_SIZE (SImode);
2660 if (microblaze_is_interrupt_variant () && prologue)
2662 emit_move_insn (isr_reg_rtx, isr_msr_rtx);
2663 emit_move_insn (isr_mem_rtx, isr_reg_rtx);
2665 /* Do not optimize in flow analysis. */
2666 emit_insn (gen_rtx_USE (SImode, isr_reg_rtx));
2667 emit_insn (gen_rtx_USE (SImode, isr_msr_rtx));
2670 /* Done saving and restoring */
2674 /* Set up the stack and frame (if desired) for the function. */
2675 static void
2676 microblaze_function_prologue (FILE * file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
2678 const char *fnname;
2679 long fsiz = current_frame_info.total_size;
2681 /* Get the function name the same way that toplev.c does before calling
2682 assemble_start_function. This is needed so that the name used here
2683 exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */
2684 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
2685 if (!flag_inhibit_size_directive)
2687 fputs ("\t.ent\t", file);
2688 if (interrupt_handler && strcmp (INTERRUPT_HANDLER_NAME, fnname))
2689 fputs ("_interrupt_handler", file);
2690 else if (break_handler && strcmp (BREAK_HANDLER_NAME, fnname))
2691 fputs ("_break_handler", file);
2692 else if (fast_interrupt && strcmp (FAST_INTERRUPT_NAME, fnname))
2693 fputs ("_fast_interrupt", file);
2694 else
2695 assemble_name (file, fnname);
2696 fputs ("\n", file);
2697 if (!microblaze_is_interrupt_variant ())
2698 ASM_OUTPUT_TYPE_DIRECTIVE (file, fnname, "function");
2701 assemble_name (file, fnname);
2702 fputs (":\n", file);
2704 if (interrupt_handler && strcmp (INTERRUPT_HANDLER_NAME, fnname))
2705 fputs ("_interrupt_handler:\n", file);
2706 if (break_handler && strcmp (BREAK_HANDLER_NAME, fnname))
2707 fputs ("_break_handler:\n", file);
2708 if (!flag_inhibit_size_directive)
2710 /* .frame FRAMEREG, FRAMESIZE, RETREG. */
2711 fprintf (file,
2712 "\t.frame\t%s,%ld,%s\t\t# vars= %ld, regs= %d, args= %d\n",
2713 (reg_names[(frame_pointer_needed)
2714 ? HARD_FRAME_POINTER_REGNUM :
2715 STACK_POINTER_REGNUM]), fsiz,
2716 reg_names[MB_ABI_SUB_RETURN_ADDR_REGNUM + GP_REG_FIRST],
2717 current_frame_info.var_size, current_frame_info.num_gp,
2718 crtl->outgoing_args_size);
2719 fprintf (file, "\t.mask\t0x%08lx\n", current_frame_info.mask);
2723 /* Output extra assembler code at the end of a prologue. */
2724 static void
2725 microblaze_function_end_prologue (FILE * file)
2727 if (TARGET_STACK_CHECK)
2729 fprintf (file, "\t# Stack Check Stub -- Start.\n\t");
2730 fprintf (file, "ori\tr18,r0,_stack_end\n\t");
2731 fprintf (file, "cmpu\tr18,r1,r18\n\t");
2732 fprintf (file, "bgei\tr18,_stack_overflow_exit\n\t");
2733 fprintf (file, "# Stack Check Stub -- End.\n");
2737 static void
2738 microblaze_elf_asm_cdtor (rtx symbol, int priority, bool is_ctor)
2740 section *s;
2742 if (priority != DEFAULT_INIT_PRIORITY)
2744 char buf[18];
2745 sprintf (buf, "%s.%.5u",
2746 is_ctor ? ".ctors" : ".dtors",
2747 MAX_INIT_PRIORITY - priority);
2748 s = get_section (buf, SECTION_WRITE, NULL_TREE);
2750 else if (is_ctor)
2751 s = ctors_section;
2752 else
2753 s = dtors_section;
2755 switch_to_section (s);
2756 assemble_align (POINTER_SIZE);
2757 fputs ("\t.word\t", asm_out_file);
2758 output_addr_const (asm_out_file, symbol);
2759 fputs ("\n", asm_out_file);
2762 /* Add a function to the list of static constructors. */
2764 static void
2765 microblaze_elf_asm_constructor (rtx symbol, int priority)
2767 microblaze_elf_asm_cdtor (symbol, priority, /*is_ctor=*/true);
2770 /* Add a function to the list of static destructors. */
2772 static void
2773 microblaze_elf_asm_destructor (rtx symbol, int priority)
2775 microblaze_elf_asm_cdtor (symbol, priority, /*is_ctor=*/false);
2778 /* Expand the prologue into a bunch of separate insns. */
2780 void
2781 microblaze_expand_prologue (void)
2783 int regno;
2784 HOST_WIDE_INT fsiz;
2785 const char *arg_name = 0;
2786 tree fndecl = current_function_decl;
2787 tree fntype = TREE_TYPE (fndecl);
2788 tree fnargs = DECL_ARGUMENTS (fndecl);
2789 rtx next_arg_reg;
2790 int i;
2791 tree next_arg;
2792 tree cur_arg;
2793 CUMULATIVE_ARGS args_so_far_v;
2794 cumulative_args_t args_so_far;
2795 rtx mem_rtx, reg_rtx;
2797 /* If struct value address is treated as the first argument, make it so. */
2798 if (aggregate_value_p (DECL_RESULT (fndecl), fntype)
2799 && !cfun->returns_pcc_struct)
2801 tree type = build_pointer_type (fntype);
2802 tree function_result_decl = build_decl (BUILTINS_LOCATION, PARM_DECL,
2803 NULL_TREE, type);
2805 DECL_ARG_TYPE (function_result_decl) = type;
2806 TREE_CHAIN (function_result_decl) = fnargs;
2807 fnargs = function_result_decl;
2810 /* Determine the last argument, and get its name. */
2812 INIT_CUMULATIVE_ARGS (args_so_far_v, fntype, NULL_RTX, 0, 0);
2813 args_so_far = pack_cumulative_args (&args_so_far_v);
2814 regno = GP_ARG_FIRST;
2816 for (cur_arg = fnargs; cur_arg != 0; cur_arg = next_arg)
2818 tree passed_type = DECL_ARG_TYPE (cur_arg);
2819 machine_mode passed_mode = TYPE_MODE (passed_type);
2820 rtx entry_parm;
2822 if (TREE_ADDRESSABLE (passed_type))
2824 passed_type = build_pointer_type (passed_type);
2825 passed_mode = Pmode;
2828 entry_parm = targetm.calls.function_arg (args_so_far, passed_mode,
2829 passed_type, true);
2831 if (entry_parm)
2833 int words;
2835 /* passed in a register, so will get homed automatically. */
2836 if (GET_MODE (entry_parm) == BLKmode)
2837 words = (int_size_in_bytes (passed_type) + 3) / 4;
2838 else
2839 words = (GET_MODE_SIZE (GET_MODE (entry_parm)) + 3) / 4;
2841 regno = REGNO (entry_parm) + words - 1;
2843 else
2845 regno = GP_ARG_LAST + 1;
2846 break;
2849 targetm.calls.function_arg_advance (args_so_far, passed_mode,
2850 passed_type, true);
2852 next_arg = TREE_CHAIN (cur_arg);
2853 if (next_arg == 0)
2855 if (DECL_NAME (cur_arg))
2856 arg_name = IDENTIFIER_POINTER (DECL_NAME (cur_arg));
2858 break;
2862 /* Split parallel insn into a sequence of insns. */
2864 next_arg_reg = targetm.calls.function_arg (args_so_far, VOIDmode,
2865 void_type_node, true);
2866 if (next_arg_reg != 0 && GET_CODE (next_arg_reg) == PARALLEL)
2868 rtvec adjust = XVEC (next_arg_reg, 0);
2869 int num = GET_NUM_ELEM (adjust);
2871 for (i = 0; i < num; i++)
2873 rtx pattern = RTVEC_ELT (adjust, i);
2874 emit_insn (pattern);
2878 fsiz = compute_frame_size (get_frame_size ());
2880 if (flag_stack_usage_info)
2881 current_function_static_stack_size = fsiz;
2884 /* If this function is a varargs function, store any registers that
2885 would normally hold arguments ($5 - $10) on the stack. */
2886 if (((TYPE_ARG_TYPES (fntype) != 0
2887 && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
2888 != void_type_node))
2889 || (arg_name != 0
2890 && ((arg_name[0] == '_'
2891 && strcmp (arg_name, "__builtin_va_alist") == 0)
2892 || (arg_name[0] == 'v'
2893 && strcmp (arg_name, "va_alist") == 0)))))
2895 int offset = (regno - GP_ARG_FIRST + 1) * UNITS_PER_WORD;
2896 rtx ptr = stack_pointer_rtx;
2898 /* If we are doing svr4-abi, sp has already been decremented by fsiz. */
2899 for (; regno <= GP_ARG_LAST; regno++)
2901 if (offset != 0)
2902 ptr = gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (offset));
2903 emit_move_insn (gen_rtx_MEM (SImode, ptr),
2904 gen_rtx_REG (SImode, regno));
2906 offset += GET_MODE_SIZE (SImode);
2911 if (fsiz > 0)
2913 rtx fsiz_rtx = GEN_INT (fsiz);
2915 rtx_insn *insn = NULL;
2916 insn = emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx,
2917 fsiz_rtx));
2918 if (insn)
2919 RTX_FRAME_RELATED_P (insn) = 1;
2921 /* Handle SUB_RETURN_ADDR_REGNUM specially at first. */
2922 if (!crtl->is_leaf || interrupt_handler)
2924 mem_rtx = gen_rtx_MEM (SImode,
2925 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
2926 const0_rtx));
2928 if (interrupt_handler)
2929 /* Do not optimize in flow analysis. */
2930 MEM_VOLATILE_P (mem_rtx) = 1;
2932 reg_rtx = gen_rtx_REG (SImode, MB_ABI_SUB_RETURN_ADDR_REGNUM);
2933 insn = emit_move_insn (mem_rtx, reg_rtx);
2934 RTX_FRAME_RELATED_P (insn) = 1;
2937 /* _save_ registers for prologue. */
2938 save_restore_insns (1);
2940 if (frame_pointer_needed)
2942 rtx_insn *insn = 0;
2944 insn = emit_insn (gen_movsi (hard_frame_pointer_rtx,
2945 stack_pointer_rtx));
2947 if (insn)
2948 RTX_FRAME_RELATED_P (insn) = 1;
2952 if ((flag_pic == 2 || TLS_NEEDS_GOT )
2953 && df_regs_ever_live_p (MB_ABI_PIC_ADDR_REGNUM))
2955 SET_REGNO (pic_offset_table_rtx, MB_ABI_PIC_ADDR_REGNUM);
2956 emit_insn (gen_set_got (pic_offset_table_rtx)); /* setting GOT. */
2959 /* If we are profiling, make sure no instructions are scheduled before
2960 the call to mcount. */
2962 if (profile_flag)
2963 emit_insn (gen_blockage ());
2966 /* Do necessary cleanup after a function to restore stack, frame, and regs. */
2968 #define RA_MASK ((long) 0x80000000) /* 1 << 31 */
2969 #define PIC_OFFSET_TABLE_MASK (1 << (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST))
2971 static void
2972 microblaze_function_epilogue (FILE * file ATTRIBUTE_UNUSED,
2973 HOST_WIDE_INT size ATTRIBUTE_UNUSED)
2975 const char *fnname;
2977 /* Get the function name the same way that toplev.c does before calling
2978 assemble_start_function. This is needed so that the name used here
2979 exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */
2980 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
2982 if (!flag_inhibit_size_directive)
2984 fputs ("\t.end\t", file);
2985 if (interrupt_handler && !break_handler)
2986 fputs ("_interrupt_handler", file);
2987 else if (break_handler)
2988 fputs ("_break_handler", file);
2989 else
2990 assemble_name (file, fnname);
2991 fputs ("\n", file);
2994 /* Reset state info for each function. */
2995 current_frame_info = zero_frame_info;
2997 /* Restore the output file if optimizing the GP (optimizing the GP causes
2998 the text to be diverted to a tempfile, so that data decls come before
2999 references to the data). */
3002 /* Expand the epilogue into a bunch of separate insns. */
3004 void
3005 microblaze_expand_epilogue (void)
3007 HOST_WIDE_INT fsiz = current_frame_info.total_size;
3008 rtx fsiz_rtx = GEN_INT (fsiz);
3009 rtx reg_rtx;
3010 rtx mem_rtx;
3012 /* In case of interrupt handlers use addki instead of addi for changing the
3013 stack pointer value. */
3015 if (microblaze_can_use_return_insn ())
3017 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode,
3018 GP_REG_FIRST +
3019 MB_ABI_SUB_RETURN_ADDR_REGNUM)));
3020 return;
3023 if (fsiz > 0)
3025 /* Restore SUB_RETURN_ADDR_REGNUM at first. This is to prevent the
3026 sequence of load-followed by a use (in rtsd) in every prologue. Saves
3027 a load-use stall cycle :) This is also important to handle alloca.
3028 (See comments for if (frame_pointer_needed) below. */
3030 if (!crtl->is_leaf || interrupt_handler)
3032 mem_rtx =
3033 gen_rtx_MEM (SImode,
3034 gen_rtx_PLUS (Pmode, stack_pointer_rtx, const0_rtx));
3035 if (interrupt_handler)
3036 /* Do not optimize in flow analysis. */
3037 MEM_VOLATILE_P (mem_rtx) = 1;
3038 reg_rtx = gen_rtx_REG (SImode, MB_ABI_SUB_RETURN_ADDR_REGNUM);
3039 emit_move_insn (reg_rtx, mem_rtx);
3042 /* It is important that this is done after we restore the return address
3043 register (above). When alloca is used, we want to restore the
3044 sub-routine return address only from the current stack top and not
3045 from the frame pointer (which we restore below). (frame_pointer + 0)
3046 might have been over-written since alloca allocates memory on the
3047 current stack. */
3048 if (frame_pointer_needed)
3049 emit_insn (gen_movsi (stack_pointer_rtx, hard_frame_pointer_rtx));
3051 /* _restore_ registers for epilogue. */
3052 save_restore_insns (0);
3053 emit_insn (gen_blockage ());
3054 emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, fsiz_rtx));
3057 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode, GP_REG_FIRST +
3058 MB_ABI_SUB_RETURN_ADDR_REGNUM)));
3062 /* Return nonzero if this function is known to have a null epilogue.
3063 This allows the optimizer to omit jumps to jumps if no stack
3064 was created. */
3067 microblaze_can_use_return_insn (void)
3069 if (!reload_completed)
3070 return 0;
3072 if (df_regs_ever_live_p (MB_ABI_SUB_RETURN_ADDR_REGNUM) || profile_flag)
3073 return 0;
3075 if (current_frame_info.initialized)
3076 return current_frame_info.total_size == 0;
3078 return compute_frame_size (get_frame_size ()) == 0;
3081 /* Implement TARGET_SECONDARY_RELOAD. */
3083 static reg_class_t
3084 microblaze_secondary_reload (bool in_p ATTRIBUTE_UNUSED, rtx x ATTRIBUTE_UNUSED,
3085 reg_class_t rclass, machine_mode mode ATTRIBUTE_UNUSED,
3086 secondary_reload_info *sri ATTRIBUTE_UNUSED)
3088 if (rclass == ST_REGS)
3089 return GR_REGS;
3091 return NO_REGS;
3094 static void
3095 microblaze_globalize_label (FILE * stream, const char *name)
3097 fputs ("\t.globl\t", stream);
3098 if (microblaze_is_interrupt_variant ())
3100 if (interrupt_handler && strcmp (name, INTERRUPT_HANDLER_NAME))
3101 fputs (INTERRUPT_HANDLER_NAME, stream);
3102 else if (break_handler && strcmp (name, BREAK_HANDLER_NAME))
3103 fputs (BREAK_HANDLER_NAME, stream);
3104 else if (fast_interrupt && strcmp (name, FAST_INTERRUPT_NAME))
3105 fputs (FAST_INTERRUPT_NAME, stream);
3106 fputs ("\n\t.globl\t", stream);
3108 assemble_name (stream, name);
3109 fputs ("\n", stream);
3112 /* Returns true if decl should be placed into a "small data" section. */
3113 static bool
3114 microblaze_elf_in_small_data_p (const_tree decl)
3116 HOST_WIDE_INT size;
3118 if (!TARGET_XLGPOPT)
3119 return false;
3121 /* We want to merge strings, so we never consider them small data. */
3122 if (TREE_CODE (decl) == STRING_CST)
3123 return false;
3125 /* Functions are never in the small data area. */
3126 if (TREE_CODE (decl) == FUNCTION_DECL)
3127 return false;
3129 if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl))
3131 const char *section = DECL_SECTION_NAME (decl);
3132 if (strcmp (section, ".sdata") == 0
3133 || strcmp (section, ".sdata2") == 0
3134 || strcmp (section, ".sbss") == 0
3135 || strcmp (section, ".sbss2") == 0)
3136 return true;
3139 size = int_size_in_bytes (TREE_TYPE (decl));
3141 return (size > 0 && size <= microblaze_section_threshold);
3145 static section *
3146 microblaze_select_section (tree decl, int reloc, unsigned HOST_WIDE_INT align)
3148 switch (categorize_decl_for_section (decl, reloc))
3150 case SECCAT_RODATA_MERGE_STR:
3151 case SECCAT_RODATA_MERGE_STR_INIT:
3152 /* MB binutils have various issues with mergeable string sections and
3153 relaxation/relocation. Currently, turning mergeable sections
3154 into regular readonly sections. */
3156 return readonly_data_section;
3157 default:
3158 return default_elf_select_section (decl, reloc, align);
3163 Encode info about sections into the RTL based on a symbol's declaration.
3164 The default definition of this hook, default_encode_section_info in
3165 `varasm.c', sets a number of commonly-useful bits in SYMBOL_REF_FLAGS. */
3167 static void
3168 microblaze_encode_section_info (tree decl, rtx rtl, int first)
3170 default_encode_section_info (decl, rtl, first);
3173 static rtx
3174 expand_pic_symbol_ref (machine_mode mode ATTRIBUTE_UNUSED, rtx op)
3176 rtx result;
3177 result = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op), UNSPEC_GOTOFF);
3178 result = gen_rtx_CONST (Pmode, result);
3179 result = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, result);
3180 result = gen_const_mem (Pmode, result);
3181 return result;
3184 static void
3185 microblaze_asm_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
3186 HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
3187 tree function)
3189 rtx this_rtx, funexp;
3190 rtx_insn *insn;
3192 reload_completed = 1;
3193 epilogue_completed = 1;
3195 /* Mark the end of the (empty) prologue. */
3196 emit_note (NOTE_INSN_PROLOGUE_END);
3198 /* Find the "this" pointer. If the function returns a structure,
3199 the structure return pointer is in MB_ABI_FIRST_ARG_REGNUM. */
3200 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
3201 this_rtx = gen_rtx_REG (Pmode, (MB_ABI_FIRST_ARG_REGNUM + 1));
3202 else
3203 this_rtx = gen_rtx_REG (Pmode, MB_ABI_FIRST_ARG_REGNUM);
3205 /* Apply the constant offset, if required. */
3206 if (delta)
3207 emit_insn (gen_addsi3 (this_rtx, this_rtx, GEN_INT (delta)));
3209 /* Apply the offset from the vtable, if required. */
3210 if (vcall_offset)
3212 rtx vcall_offset_rtx = GEN_INT (vcall_offset);
3213 rtx temp1 = gen_rtx_REG (Pmode, MB_ABI_TEMP1_REGNUM);
3215 emit_move_insn (temp1, gen_rtx_MEM (Pmode, this_rtx));
3217 rtx loc = gen_rtx_PLUS (Pmode, temp1, vcall_offset_rtx);
3218 emit_move_insn (temp1, gen_rtx_MEM (Pmode, loc));
3220 emit_insn (gen_addsi3 (this_rtx, this_rtx, temp1));
3223 /* Generate a tail call to the target function. */
3224 if (!TREE_USED (function))
3226 assemble_external (function);
3227 TREE_USED (function) = 1;
3230 funexp = XEXP (DECL_RTL (function), 0);
3231 rtx temp2 = gen_rtx_REG (Pmode, MB_ABI_TEMP2_REGNUM);
3233 if (flag_pic)
3234 emit_move_insn (temp2, expand_pic_symbol_ref (Pmode, funexp));
3235 else
3236 emit_move_insn (temp2, funexp);
3238 emit_insn (gen_indirect_jump (temp2));
3240 /* Run just enough of rest_of_compilation. This sequence was
3241 "borrowed" from rs6000.c. */
3242 insn = get_insns ();
3243 shorten_branches (insn);
3244 final_start_function (insn, file, 1);
3245 final (insn, file, 1);
3246 final_end_function ();
3248 reload_completed = 0;
3249 epilogue_completed = 0;
3252 bool
3253 microblaze_expand_move (machine_mode mode, rtx operands[])
3255 rtx op0, op1;
3257 op0 = operands[0];
3258 op1 = operands[1];
3260 if (!register_operand (op0, SImode)
3261 && !register_operand (op1, SImode)
3262 && (GET_CODE (op1) != CONST_INT || INTVAL (op1) != 0))
3264 rtx temp = force_reg (SImode, op1);
3265 emit_move_insn (op0, temp);
3266 return true;
3268 /* If operands[1] is a constant address invalid for pic, then we need to
3269 handle it just like LEGITIMIZE_ADDRESS does. */
3270 if (GET_CODE (op1) == SYMBOL_REF || GET_CODE (op1) == LABEL_REF)
3272 rtx result;
3273 if (microblaze_tls_symbol_p(op1))
3275 result = microblaze_legitimize_tls_address (op1, NULL_RTX);
3276 emit_move_insn (op0, result);
3277 return true;
3279 else if (flag_pic)
3281 if (reload_in_progress)
3282 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
3283 result = expand_pic_symbol_ref (mode, op1);
3284 emit_move_insn (op0, result);
3285 return true;
3288 /* Handle Case of (const (plus symbol const_int)). */
3289 if (GET_CODE (op1) == CONST && GET_CODE (XEXP (op1,0)) == PLUS)
3291 rtx p0, p1;
3293 p0 = XEXP (XEXP (op1, 0), 0);
3294 p1 = XEXP (XEXP (op1, 0), 1);
3296 if ((GET_CODE (p1) == CONST_INT)
3297 && ((GET_CODE (p0) == UNSPEC)
3298 || ((GET_CODE (p0) == SYMBOL_REF || GET_CODE (p0) == LABEL_REF)
3299 && (flag_pic == 2 || microblaze_tls_symbol_p (p0)
3300 || !SMALL_INT (p1)))))
3302 rtx temp = force_reg (SImode, p0);
3303 rtx temp2 = p1;
3305 if (flag_pic && reload_in_progress)
3306 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
3307 emit_move_insn (op0, gen_rtx_PLUS (SImode, temp, temp2));
3308 return true;
3311 return false;
3314 /* Expand shift operations. */
3316 microblaze_expand_shift (rtx operands[])
3318 gcc_assert ((GET_CODE (operands[2]) == CONST_INT)
3319 || (GET_CODE (operands[2]) == REG)
3320 || (GET_CODE (operands[2]) == SUBREG));
3322 /* Shift by one -- generate pattern. */
3323 if ((GET_CODE (operands[2]) == CONST_INT) && (INTVAL (operands[2]) == 1))
3324 return 0;
3326 /* Have barrel shifter and shift > 1: use it. */
3327 if (TARGET_BARREL_SHIFT)
3328 return 0;
3330 gcc_assert ((GET_CODE (operands[0]) == REG)
3331 || (GET_CODE (operands[0]) == SUBREG)
3332 || (GET_CODE (operands[1]) == REG)
3333 || (GET_CODE (operands[1]) == SUBREG));
3335 /* Shift by zero -- copy regs if necessary. */
3336 if ((GET_CODE (operands[2]) == CONST_INT) && (INTVAL (operands[2]) == 0))
3338 if (REGNO (operands[0]) != REGNO (operands[1]))
3339 emit_insn (gen_movsi (operands[0], operands[1]));
3340 return 1;
3343 return 0;
3346 /* Return an RTX indicating where the return address to the
3347 calling function can be found. */
3349 microblaze_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
3351 if (count != 0)
3352 return NULL_RTX;
3354 return gen_rtx_PLUS (Pmode,
3355 get_hard_reg_initial_val (Pmode,
3356 MB_ABI_SUB_RETURN_ADDR_REGNUM),
3357 GEN_INT (8));
3360 /* Queue an .ident string in the queue of top-level asm statements.
3361 If the string size is below the threshold, put it into .sdata2.
3362 If the front-end is done, we must be being called from toplev.c.
3363 In that case, do nothing. */
3364 void
3365 microblaze_asm_output_ident (const char *string)
3367 const char *section_asm_op;
3368 int size;
3369 char *buf;
3371 if (symtab->state != PARSING)
3372 return;
3374 size = strlen (string) + 1;
3375 if (size <= microblaze_section_threshold)
3376 section_asm_op = SDATA2_SECTION_ASM_OP;
3377 else
3378 section_asm_op = READONLY_DATA_SECTION_ASM_OP;
3380 buf = ACONCAT ((section_asm_op, "\n\t.ascii \"", string, "\\0\"\n", NULL));
3381 symtab->finalize_toplevel_asm (build_string (strlen (buf), buf));
3384 static void
3385 microblaze_elf_asm_init_sections (void)
3387 sdata2_section
3388 = get_unnamed_section (SECTION_WRITE, output_section_asm_op,
3389 SDATA2_SECTION_ASM_OP);
3392 /* Generate assembler code for constant parts of a trampoline. */
3394 static void
3395 microblaze_asm_trampoline_template (FILE *f)
3397 fprintf (f, "\tmfs r18, rpc\n");
3398 fprintf (f, "\tlwi r3, r18, 16\n");
3399 fprintf (f, "\tlwi r18, r18, 20\n");
3400 fprintf (f, "\tbra r18\n");
3401 /* fprintf (f, "\t.word\t0x00000000\t\t# <function address>\n"); */
3402 /* fprintf (f, "\t.word\t0x00000000\t\t# <static chain value>\n"); */
3405 /* Implement TARGET_TRAMPOLINE_INIT. */
3407 static void
3408 microblaze_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
3410 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
3411 rtx mem;
3413 emit_block_move (m_tramp, assemble_trampoline_template (),
3414 GEN_INT (6*UNITS_PER_WORD), BLOCK_OP_NORMAL);
3416 mem = adjust_address (m_tramp, SImode, 16);
3417 emit_move_insn (mem, chain_value);
3418 mem = adjust_address (m_tramp, SImode, 20);
3419 emit_move_insn (mem, fnaddr);
3422 /* Generate conditional branch -- first, generate test condition,
3423 second, generate correct branch instruction. */
3425 void
3426 microblaze_expand_conditional_branch (machine_mode mode, rtx operands[])
3428 enum rtx_code code = GET_CODE (operands[0]);
3429 rtx cmp_op0 = operands[1];
3430 rtx cmp_op1 = operands[2];
3431 rtx label1 = operands[3];
3432 rtx comp_reg = gen_reg_rtx (SImode);
3433 rtx condition;
3435 gcc_assert ((GET_CODE (cmp_op0) == REG) || (GET_CODE (cmp_op0) == SUBREG));
3437 /* If comparing against zero, just test source reg. */
3438 if (cmp_op1 == const0_rtx)
3440 comp_reg = cmp_op0;
3441 condition = gen_rtx_fmt_ee (signed_condition (code), SImode, comp_reg, const0_rtx);
3442 emit_jump_insn (gen_condjump (condition, label1));
3445 else if (code == EQ || code == NE)
3447 /* Use xor for equal/not-equal comparison. */
3448 emit_insn (gen_xorsi3 (comp_reg, cmp_op0, cmp_op1));
3449 condition = gen_rtx_fmt_ee (signed_condition (code), SImode, comp_reg, const0_rtx);
3450 emit_jump_insn (gen_condjump (condition, label1));
3452 else
3454 /* Generate compare and branch in single instruction. */
3455 cmp_op1 = force_reg (mode, cmp_op1);
3456 condition = gen_rtx_fmt_ee (code, mode, cmp_op0, cmp_op1);
3457 emit_jump_insn (gen_branch_compare(condition, cmp_op0, cmp_op1, label1));
3462 void
3463 microblaze_expand_conditional_branch_sf (rtx operands[])
3465 rtx condition;
3466 rtx cmp_op0 = XEXP (operands[0], 0);
3467 rtx cmp_op1 = XEXP (operands[0], 1);
3468 rtx comp_reg = gen_reg_rtx (SImode);
3470 emit_insn (gen_cstoresf4 (comp_reg, operands[0], cmp_op0, cmp_op1));
3471 condition = gen_rtx_NE (SImode, comp_reg, const0_rtx);
3472 emit_jump_insn (gen_condjump (condition, operands[3]));
3475 /* Implement TARGET_FRAME_POINTER_REQUIRED. */
3477 static bool
3478 microblaze_frame_pointer_required (void)
3480 /* If the function contains dynamic stack allocations, we need to
3481 use the frame pointer to access the static parts of the frame. */
3482 if (cfun->calls_alloca)
3483 return true;
3484 return false;
3487 void
3488 microblaze_expand_divide (rtx operands[])
3490 /* Table lookup software divides. Works for all (nr/dr) where (0 <= nr,dr <= 15). */
3492 rtx regt1 = gen_reg_rtx (SImode);
3493 rtx reg18 = gen_rtx_REG (SImode, R_TMP);
3494 rtx regqi = gen_reg_rtx (QImode);
3495 rtx_code_label *div_label = gen_label_rtx ();
3496 rtx_code_label *div_end_label = gen_label_rtx ();
3497 rtx div_table_rtx = gen_rtx_SYMBOL_REF (QImode,"_divsi3_table");
3498 rtx mem_rtx;
3499 rtx ret;
3500 rtx_insn *jump, *cjump, *insn;
3502 insn = emit_insn (gen_iorsi3 (regt1, operands[1], operands[2]));
3503 cjump = emit_jump_insn_after (gen_cbranchsi4 (
3504 gen_rtx_GTU (SImode, regt1, GEN_INT (15)),
3505 regt1, GEN_INT (15), div_label), insn);
3506 LABEL_NUSES (div_label) = 1;
3507 JUMP_LABEL (cjump) = div_label;
3508 emit_insn (gen_rtx_CLOBBER (SImode, reg18));
3510 emit_insn (gen_ashlsi3_bshift (regt1, operands[1], GEN_INT(4)));
3511 emit_insn (gen_addsi3 (regt1, regt1, operands[2]));
3512 mem_rtx = gen_rtx_MEM (QImode,
3513 gen_rtx_PLUS (Pmode, regt1, div_table_rtx));
3515 insn = emit_insn (gen_movqi (regqi, mem_rtx));
3516 insn = emit_insn (gen_movsi (operands[0], gen_rtx_SUBREG (SImode, regqi, 0)));
3517 jump = emit_jump_insn_after (gen_jump (div_end_label), insn);
3518 JUMP_LABEL (jump) = div_end_label;
3519 LABEL_NUSES (div_end_label) = 1;
3520 emit_barrier ();
3522 emit_label (div_label);
3523 ret = emit_library_call_value (gen_rtx_SYMBOL_REF (Pmode, "__divsi3"),
3524 operands[0], LCT_NORMAL,
3525 GET_MODE (operands[0]), 2, operands[1],
3526 GET_MODE (operands[1]), operands[2],
3527 GET_MODE (operands[2]));
3528 if (ret != operands[0])
3529 emit_move_insn (operands[0], ret);
3531 emit_label (div_end_label);
3532 emit_insn (gen_blockage ());
3535 /* Implement TARGET_FUNCTION_VALUE. */
3536 static rtx
3537 microblaze_function_value (const_tree valtype,
3538 const_tree func ATTRIBUTE_UNUSED,
3539 bool outgoing ATTRIBUTE_UNUSED)
3541 return LIBCALL_VALUE (TYPE_MODE (valtype));
3544 /* Implement TARGET_SCHED_ADJUST_COST. */
3545 static int
3546 microblaze_adjust_cost (rtx_insn *insn ATTRIBUTE_UNUSED, rtx link,
3547 rtx_insn *dep ATTRIBUTE_UNUSED, int cost)
3549 if (REG_NOTE_KIND (link) == REG_DEP_OUTPUT)
3550 return cost;
3551 if (REG_NOTE_KIND (link) != 0)
3552 return 0;
3553 return cost;
3556 /* Implement TARGET_LEGITIMATE_CONSTANT_P.
3558 At present, GAS doesn't understand li.[sd], so don't allow it
3559 to be generated at present. */
3560 static bool
3561 microblaze_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED, rtx x)
3564 if (microblaze_cannot_force_const_mem(mode, x))
3565 return false;
3567 if (GET_CODE (x) == CONST_DOUBLE)
3569 return microblaze_const_double_ok (x, GET_MODE (x));
3572 /* Handle Case of (const (plus unspec const_int)). */
3573 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x,0)) == PLUS)
3575 rtx p0, p1;
3577 p0 = XEXP (XEXP (x, 0), 0);
3578 p1 = XEXP (XEXP (x, 0), 1);
3580 if (GET_CODE(p1) == CONST_INT)
3582 /* Const offset from UNSPEC is not supported. */
3583 if ((GET_CODE (p0) == UNSPEC))
3584 return false;
3586 if ((GET_CODE (p0) == SYMBOL_REF || GET_CODE (p0) == LABEL_REF)
3587 && (microblaze_tls_symbol_p (p0) || !SMALL_INT (p1)))
3588 return false;
3592 return true;
3596 #undef TARGET_ENCODE_SECTION_INFO
3597 #define TARGET_ENCODE_SECTION_INFO microblaze_encode_section_info
3599 #undef TARGET_ASM_GLOBALIZE_LABEL
3600 #define TARGET_ASM_GLOBALIZE_LABEL microblaze_globalize_label
3602 #undef TARGET_ASM_FUNCTION_PROLOGUE
3603 #define TARGET_ASM_FUNCTION_PROLOGUE microblaze_function_prologue
3605 #undef TARGET_ASM_FUNCTION_EPILOGUE
3606 #define TARGET_ASM_FUNCTION_EPILOGUE microblaze_function_epilogue
3608 #undef TARGET_RTX_COSTS
3609 #define TARGET_RTX_COSTS microblaze_rtx_costs
3611 #undef TARGET_CANNOT_FORCE_CONST_MEM
3612 #define TARGET_CANNOT_FORCE_CONST_MEM microblaze_cannot_force_const_mem
3614 #undef TARGET_ADDRESS_COST
3615 #define TARGET_ADDRESS_COST microblaze_address_cost
3617 #undef TARGET_ATTRIBUTE_TABLE
3618 #define TARGET_ATTRIBUTE_TABLE microblaze_attribute_table
3620 #undef TARGET_IN_SMALL_DATA_P
3621 #define TARGET_IN_SMALL_DATA_P microblaze_elf_in_small_data_p
3623 #undef TARGET_ASM_SELECT_SECTION
3624 #define TARGET_ASM_SELECT_SECTION microblaze_select_section
3626 #undef TARGET_HAVE_SRODATA_SECTION
3627 #define TARGET_HAVE_SRODATA_SECTION true
3629 #undef TARGET_ASM_FUNCTION_END_PROLOGUE
3630 #define TARGET_ASM_FUNCTION_END_PROLOGUE \
3631 microblaze_function_end_prologue
3633 #undef TARGET_ARG_PARTIAL_BYTES
3634 #define TARGET_ARG_PARTIAL_BYTES function_arg_partial_bytes
3636 #undef TARGET_FUNCTION_ARG
3637 #define TARGET_FUNCTION_ARG microblaze_function_arg
3639 #undef TARGET_FUNCTION_ARG_ADVANCE
3640 #define TARGET_FUNCTION_ARG_ADVANCE microblaze_function_arg_advance
3642 #undef TARGET_CAN_ELIMINATE
3643 #define TARGET_CAN_ELIMINATE microblaze_can_eliminate
3645 #undef TARGET_LEGITIMIZE_ADDRESS
3646 #define TARGET_LEGITIMIZE_ADDRESS microblaze_legitimize_address
3648 #undef TARGET_LEGITIMATE_ADDRESS_P
3649 #define TARGET_LEGITIMATE_ADDRESS_P microblaze_legitimate_address_p
3651 #undef TARGET_FRAME_POINTER_REQUIRED
3652 #define TARGET_FRAME_POINTER_REQUIRED microblaze_frame_pointer_required
3654 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
3655 #define TARGET_ASM_TRAMPOLINE_TEMPLATE microblaze_asm_trampoline_template
3657 #undef TARGET_TRAMPOLINE_INIT
3658 #define TARGET_TRAMPOLINE_INIT microblaze_trampoline_init
3660 #undef TARGET_PROMOTE_FUNCTION_MODE
3661 #define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
3663 #undef TARGET_FUNCTION_VALUE
3664 #define TARGET_FUNCTION_VALUE microblaze_function_value
3666 #undef TARGET_SECONDARY_RELOAD
3667 #define TARGET_SECONDARY_RELOAD microblaze_secondary_reload
3669 #undef TARGET_ASM_OUTPUT_MI_THUNK
3670 #define TARGET_ASM_OUTPUT_MI_THUNK microblaze_asm_output_mi_thunk
3672 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
3673 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true
3675 #undef TARGET_SCHED_ADJUST_COST
3676 #define TARGET_SCHED_ADJUST_COST microblaze_adjust_cost
3678 #undef TARGET_ASM_INIT_SECTIONS
3679 #define TARGET_ASM_INIT_SECTIONS microblaze_elf_asm_init_sections
3681 #undef TARGET_OPTION_OVERRIDE
3682 #define TARGET_OPTION_OVERRIDE microblaze_option_override
3684 #undef TARGET_LEGITIMATE_CONSTANT_P
3685 #define TARGET_LEGITIMATE_CONSTANT_P microblaze_legitimate_constant_p
3687 struct gcc_target targetm = TARGET_INITIALIZER;
3689 #include "gt-microblaze.h"