Convert STARTING_FRAME_OFFSET to a hook
[official-gcc.git] / gcc / config / microblaze / microblaze.c
blob74875238774f0d806e400b4996ebcecb58ff75e7
1 /* Subroutines used for code generation on Xilinx MicroBlaze.
2 Copyright (C) 2009-2017 Free Software Foundation, Inc.
4 Contributed by Michael Eager <eager@eagercon.com>.
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published
10 by the Free Software Foundation; either version 3, or (at your
11 option) any later version.
13 GCC is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16 License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. */
22 #include "config.h"
23 #include "system.h"
24 #include "coretypes.h"
25 #include "backend.h"
26 #include "target.h"
27 #include "rtl.h"
28 #include "tree.h"
29 #include "stringpool.h"
30 #include "attribs.h"
31 #include "df.h"
32 #include "memmodel.h"
33 #include "tm_p.h"
34 #include "optabs.h"
35 #include "regs.h"
36 #include "emit-rtl.h"
37 #include "recog.h"
38 #include "cgraph.h"
39 #include "diagnostic-core.h"
40 #include "varasm.h"
41 #include "stor-layout.h"
42 #include "calls.h"
43 #include "explow.h"
44 #include "expr.h"
45 #include "reload.h"
46 #include "output.h"
47 #include "builtins.h"
48 #include "rtl-iter.h"
49 #include "cfgloop.h"
50 #include "insn-addr.h"
51 #include "cfgrtl.h"
53 /* This file should be included last. */
54 #include "target-def.h"
56 #define MICROBLAZE_VERSION_COMPARE(VA,VB) strcasecmp (VA, VB)
58 /* Classifies an address.
60 ADDRESS_INVALID
61 An invalid address.
63 ADDRESS_REG
65 A natural register or a register + const_int offset address.
66 The register satisfies microblaze_valid_base_register_p and the
67 offset is a const_arith_operand.
69 ADDRESS_REG_INDEX
71 A natural register offset by the index contained in an index register. The base
72 register satisfies microblaze_valid_base_register_p and the index register
73 satisfies microblaze_valid_index_register_p
75 ADDRESS_CONST_INT
77 A signed 16/32-bit constant address.
79 ADDRESS_SYMBOLIC:
81 A constant symbolic address or a (register + symbol). */
83 enum microblaze_address_type
85 ADDRESS_INVALID,
86 ADDRESS_REG,
87 ADDRESS_REG_INDEX,
88 ADDRESS_CONST_INT,
89 ADDRESS_SYMBOLIC,
90 ADDRESS_GOTOFF,
91 ADDRESS_PLT,
92 ADDRESS_TLS
95 /* Classifies symbols
97 SYMBOL_TYPE_GENERAL
99 A general symbol. */
100 enum microblaze_symbol_type
102 SYMBOL_TYPE_INVALID,
103 SYMBOL_TYPE_GENERAL
106 /* TLS Address Type. */
107 enum tls_reloc {
108 TLS_GD,
109 TLS_LDM,
110 TLS_DTPREL,
111 TLS_IE,
112 TLS_LE
115 /* Classification of a MicroBlaze address. */
116 struct microblaze_address_info
118 enum microblaze_address_type type;
119 rtx regA; /* Contains valid values on ADDRESS_REG, ADDRESS_REG_INDEX,
120 ADDRESS_SYMBOLIC. */
121 rtx regB; /* Contains valid values on ADDRESS_REG_INDEX. */
122 rtx offset; /* Contains valid values on ADDRESS_CONST_INT and ADDRESS_REG. */
123 rtx symbol; /* Contains valid values on ADDRESS_SYMBOLIC. */
124 enum microblaze_symbol_type symbol_type;
125 enum tls_reloc tls_type;
128 /* Structure to be filled in by compute_frame_size with register
129 save masks, and offsets for the current function. */
131 struct GTY(()) microblaze_frame_info {
132 long total_size; /* # bytes that the entire frame takes up. */
133 long var_size; /* # bytes that variables take up. */
134 long args_size; /* # bytes that outgoing arguments take up. */
135 int link_debug_size; /* # bytes for the link reg and back pointer. */
136 int gp_reg_size; /* # bytes needed to store gp regs. */
137 long gp_offset; /* offset from new sp to store gp registers. */
138 long mask; /* mask of saved gp registers. */
139 int initialized; /* != 0 if frame size already calculated. */
140 int num_gp; /* number of gp registers saved. */
141 long insns_len; /* length of insns. */
142 int alloc_stack; /* Flag to indicate if the current function
143 must not create stack space. (As an optimization). */
146 /* Global variables for machine-dependent things. */
148 /* Toggle which pipleline interface to use. */
149 static GTY(()) int microblaze_sched_use_dfa = 0;
151 /* Threshold for data being put into the small data/bss area, instead
152 of the normal data area (references to the small data/bss area take
153 1 instruction, and use the global pointer, references to the normal
154 data area takes 2 instructions). */
155 int microblaze_section_threshold = -1;
157 /* Prevent scheduling potentially exception causing instructions in
158 delay slots. -mcpu=v3.00.a or v4.00.a turns this on. */
159 int microblaze_no_unsafe_delay;
161 /* Set to one if the targeted core has the CLZ insn. */
162 int microblaze_has_clz = 0;
164 /* Which CPU pipeline do we use. We haven't really standardized on a CPU
165 version having only a particular type of pipeline. There can still be
166 options on the CPU to scale pipeline features up or down. :(
167 Bad Presentation (??), so we let the MD file rely on the value of
168 this variable instead Making PIPE_5 the default. It should be backward
169 optimal with PIPE_3 MicroBlazes. */
170 enum pipeline_type microblaze_pipe = MICROBLAZE_PIPE_5;
172 /* High and low marks for floating point values which we will accept
173 as legitimate constants for TARGET_LEGITIMATE_CONSTANT_P. These are
174 initialized in override_options. */
175 REAL_VALUE_TYPE dfhigh, dflow, sfhigh, sflow;
177 /* Array giving truth value on whether or not a given hard register
178 can support a given mode. */
179 static char microblaze_hard_regno_mode_ok_p[(int)MAX_MACHINE_MODE]
180 [FIRST_PSEUDO_REGISTER];
182 /* Current frame information calculated by compute_frame_size. */
183 struct microblaze_frame_info current_frame_info;
185 /* Zero structure to initialize current_frame_info. */
186 struct microblaze_frame_info zero_frame_info;
188 /* List of all MICROBLAZE punctuation characters used by print_operand. */
189 char microblaze_print_operand_punct[256];
191 /* Map GCC register number to debugger register number. */
192 int microblaze_dbx_regno[FIRST_PSEUDO_REGISTER];
194 /* Map hard register number to register class. */
195 enum reg_class microblaze_regno_to_class[] =
197 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
198 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
199 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
200 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
201 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
202 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
203 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
204 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
205 ST_REGS, GR_REGS, GR_REGS, GR_REGS
208 /* MicroBlaze specific machine attributes.
209 interrupt_handler - Interrupt handler attribute to add interrupt prologue
210 and epilogue and use appropriate interrupt return.
211 save_volatiles - Similar to interrupt handler, but use normal return. */
212 int interrupt_handler;
213 int break_handler;
214 int fast_interrupt;
215 int save_volatiles;
217 const struct attribute_spec microblaze_attribute_table[] = {
218 /* name min_len, max_len, decl_req, type_req, fn_type, req_handler,
219 affects_type_identity */
220 {"interrupt_handler", 0, 0, true, false, false, NULL,
221 false },
222 {"break_handler", 0, 0, true, false, false, NULL,
223 false },
224 {"fast_interrupt", 0, 0, true, false, false, NULL,
225 false },
226 {"save_volatiles" , 0, 0, true, false, false, NULL,
227 false },
228 { NULL, 0, 0, false, false, false, NULL,
229 false }
232 static int microblaze_interrupt_function_p (tree);
234 static void microblaze_elf_asm_constructor (rtx, int) ATTRIBUTE_UNUSED;
235 static void microblaze_elf_asm_destructor (rtx, int) ATTRIBUTE_UNUSED;
237 section *sdata2_section;
239 #ifdef HAVE_AS_TLS
240 #undef TARGET_HAVE_TLS
241 #define TARGET_HAVE_TLS true
242 #endif
244 /* Return truth value if a CONST_DOUBLE is ok to be a legitimate constant. */
245 static bool
246 microblaze_const_double_ok (rtx op, machine_mode mode)
248 REAL_VALUE_TYPE d;
250 if (GET_CODE (op) != CONST_DOUBLE)
251 return 0;
253 if (GET_MODE (op) == VOIDmode)
254 return 1;
256 if (mode != SFmode && mode != DFmode)
257 return 0;
259 if (op == CONST0_RTX (mode))
260 return 1;
262 d = *CONST_DOUBLE_REAL_VALUE (op);
264 if (REAL_VALUE_ISNAN (d))
265 return FALSE;
267 if (REAL_VALUE_NEGATIVE (d))
268 d = real_value_negate (&d);
270 if (mode == DFmode)
272 if (real_less (&d, &dfhigh) && real_less (&dflow, &d))
273 return 1;
275 else
277 if (real_less (&d, &sfhigh) && real_less (&sflow, &d))
278 return 1;
281 return 0;
284 /* Return truth value if a memory operand fits in a single instruction
285 (ie, register + small offset) or (register + register). */
288 simple_memory_operand (rtx op, machine_mode mode ATTRIBUTE_UNUSED)
290 rtx addr, plus0, plus1;
292 /* Eliminate non-memory operations. */
293 if (GET_CODE (op) != MEM)
294 return 0;
296 /* dword operations really put out 2 instructions, so eliminate them. */
297 /* ??? This isn't strictly correct. It is OK to accept multiword modes
298 here, since the length attributes are being set correctly, but only
299 if the address is offsettable. */
300 if (GET_MODE_SIZE (GET_MODE (op)) > UNITS_PER_WORD)
301 return 0;
304 /* Decode the address now. */
305 addr = XEXP (op, 0);
306 switch (GET_CODE (addr))
309 case REG:
310 return 1;
312 case PLUS:
313 plus0 = XEXP (addr, 0);
314 plus1 = XEXP (addr, 1);
316 if (GET_CODE (plus0) != REG)
317 return 0;
319 if (GET_CODE (plus0) == REG && GET_CODE (plus1) == CONST_INT
320 && SMALL_INT (plus1))
322 return 1;
324 else if (GET_CODE (plus1) == REG && GET_CODE (plus0) == CONST_INT)
326 return 1;
328 else if (GET_CODE (plus0) == REG && GET_CODE (plus1) == REG)
330 return 1;
332 else
333 return 0;
335 case SYMBOL_REF:
336 return 0;
338 default:
339 break;
342 return 0;
345 /* Return nonzero for a memory address that can be used to load or store
346 a doubleword. */
349 double_memory_operand (rtx op, machine_mode mode)
351 rtx addr;
353 if (GET_CODE (op) != MEM || !memory_operand (op, mode))
355 /* During reload, we accept a pseudo register if it has an
356 appropriate memory address. If we don't do this, we will
357 wind up reloading into a register, and then reloading that
358 register from memory, when we could just reload directly from
359 memory. */
360 if (reload_in_progress
361 && GET_CODE (op) == REG
362 && REGNO (op) >= FIRST_PSEUDO_REGISTER
363 && reg_renumber[REGNO (op)] < 0
364 && reg_equiv_mem (REGNO (op)) != 0
365 && double_memory_operand (reg_equiv_mem (REGNO (op)), mode))
366 return 1;
367 return 0;
370 /* Make sure that 4 added to the address is a valid memory address.
371 This essentially just checks for overflow in an added constant. */
373 addr = XEXP (op, 0);
375 if (CONSTANT_ADDRESS_P (addr))
376 return 1;
378 return memory_address_p ((GET_MODE_CLASS (mode) == MODE_INT
379 ? E_SImode : E_SFmode),
380 plus_constant (Pmode, addr, 4));
383 /* Implement REG_OK_FOR_BASE_P -and- REG_OK_FOR_INDEX_P. */
385 microblaze_regno_ok_for_base_p (int regno, int strict)
387 if (regno >= FIRST_PSEUDO_REGISTER)
389 if (!strict)
390 return true;
391 regno = reg_renumber[regno];
394 /* These fake registers will be eliminated to either the stack or
395 hard frame pointer, both of which are usually valid base registers.
396 Reload deals with the cases where the eliminated form isn't valid. */
397 if (regno == ARG_POINTER_REGNUM || regno == FRAME_POINTER_REGNUM)
398 return true;
400 return GP_REG_P (regno);
403 /* Return true if X is a valid base register for the given mode.
404 Allow only hard registers if STRICT. */
406 static bool
407 microblaze_valid_base_register_p (rtx x,
408 machine_mode mode ATTRIBUTE_UNUSED,
409 int strict)
411 if (!strict && GET_CODE (x) == SUBREG)
412 x = SUBREG_REG (x);
414 return (GET_CODE (x) == REG
415 && microblaze_regno_ok_for_base_p (REGNO (x), strict));
418 /* Build the SYMBOL_REF for __tls_get_addr. */
420 static GTY(()) rtx tls_get_addr_libfunc;
422 static rtx
423 get_tls_get_addr (void)
425 if (!tls_get_addr_libfunc)
426 tls_get_addr_libfunc = init_one_libfunc ("__tls_get_addr");
427 return tls_get_addr_libfunc;
430 /* Return TRUE if X is a thread-local symbol. */
431 bool
432 microblaze_tls_symbol_p (rtx x)
434 if (!TARGET_HAVE_TLS)
435 return false;
437 if (GET_CODE (x) != SYMBOL_REF)
438 return false;
440 return SYMBOL_REF_TLS_MODEL (x) != 0;
443 /* Return TRUE if X contains any TLS symbol references. */
445 bool
446 microblaze_tls_referenced_p (rtx x)
448 if (!TARGET_HAVE_TLS)
449 return false;
450 subrtx_iterator::array_type array;
451 FOR_EACH_SUBRTX (iter, array, x, ALL)
453 const_rtx x = *iter;
454 if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (x) != 0)
455 return true;
456 /* Don't recurse into UNSPEC_TLS looking for TLS symbols; these are
457 TLS offsets, not real symbol references. */
458 if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLS)
459 iter.skip_subrtxes ();
461 return false;
464 bool
465 microblaze_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED, rtx x)
467 return microblaze_tls_referenced_p(x);
470 /* Return TRUE if X references a SYMBOL_REF. */
472 symbol_mentioned_p (rtx x)
474 const char * fmt;
475 int i;
477 if (GET_CODE (x) == SYMBOL_REF)
478 return 1;
480 /* UNSPEC entries for a symbol include the SYMBOL_REF, but they
481 are constant offsets, not symbols. */
482 if (GET_CODE (x) == UNSPEC)
483 return 0;
485 fmt = GET_RTX_FORMAT (GET_CODE (x));
487 for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
489 if (fmt[i] == 'E')
491 int j;
493 for (j = XVECLEN (x, i) - 1; j >= 0; j--)
494 if (symbol_mentioned_p (XVECEXP (x, i, j)))
495 return 1;
497 else if (fmt[i] == 'e' && symbol_mentioned_p (XEXP (x, i)))
498 return 1;
501 return 0;
504 /* Return TRUE if X references a LABEL_REF. */
506 label_mentioned_p (rtx x)
508 const char * fmt;
509 int i;
511 if (GET_CODE (x) == LABEL_REF)
512 return 1;
514 /* UNSPEC entries for a symbol include a LABEL_REF for the referencing
515 instruction, but they are constant offsets, not symbols. */
516 if (GET_CODE (x) == UNSPEC)
517 return 0;
519 fmt = GET_RTX_FORMAT (GET_CODE (x));
520 for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
522 if (fmt[i] == 'E')
524 int j;
526 for (j = XVECLEN (x, i) - 1; j >= 0; j--)
527 if (label_mentioned_p (XVECEXP (x, i, j)))
528 return 1;
530 else if (fmt[i] == 'e' && label_mentioned_p (XEXP (x, i)))
531 return 1;
534 return 0;
538 tls_mentioned_p (rtx x)
540 switch (GET_CODE (x))
542 case CONST:
543 return tls_mentioned_p (XEXP (x, 0));
545 case UNSPEC:
546 if (XINT (x, 1) == UNSPEC_TLS)
547 return 1;
548 return 0;
550 default:
551 return 0;
555 static rtx
556 load_tls_operand (rtx x, rtx reg)
558 rtx tmp;
560 if (reg == NULL_RTX)
561 reg = gen_reg_rtx (Pmode);
563 tmp = gen_rtx_CONST (Pmode, x);
565 emit_insn (gen_rtx_SET (reg,
566 gen_rtx_PLUS (Pmode, pic_offset_table_rtx, tmp)));
568 return reg;
571 static rtx_insn *
572 microblaze_call_tls_get_addr (rtx x, rtx reg, rtx *valuep, int reloc)
574 rtx_insn *insns;
575 rtx tls_entry;
577 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
579 start_sequence ();
581 tls_entry = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, x, GEN_INT (reloc)),
582 UNSPEC_TLS);
584 reg = load_tls_operand (tls_entry, reg);
586 *valuep = emit_library_call_value (get_tls_get_addr (), NULL_RTX,
587 LCT_PURE, /* LCT_CONST? */
588 Pmode, reg, Pmode);
590 insns = get_insns ();
591 end_sequence ();
593 return insns;
597 microblaze_legitimize_tls_address(rtx x, rtx reg)
599 rtx dest, ret, eqv, addend;
600 rtx_insn *insns;
601 enum tls_model model;
602 model = SYMBOL_REF_TLS_MODEL (x);
604 switch (model)
606 case TLS_MODEL_LOCAL_DYNAMIC:
607 case TLS_MODEL_GLOBAL_DYNAMIC:
608 case TLS_MODEL_INITIAL_EXEC:
609 insns = microblaze_call_tls_get_addr (x, reg, &ret, TLS_GD);
610 dest = gen_reg_rtx (Pmode);
611 emit_libcall_block (insns, dest, ret, x);
612 break;
614 case TLS_MODEL_LOCAL_EXEC:
615 insns = microblaze_call_tls_get_addr (x, reg, &ret, TLS_LDM);
617 /* Attach a unique REG_EQUIV, to allow the RTL optimizers to
618 share the LDM result with other LD model accesses. */
619 eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const1_rtx), UNSPEC_TLS);
620 dest = gen_reg_rtx (Pmode);
621 emit_libcall_block (insns, dest, ret, eqv);
623 /* Load the addend. */
624 addend = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, x, GEN_INT (TLS_DTPREL)),
625 UNSPEC_TLS);
626 addend = force_reg (SImode, gen_rtx_CONST (SImode, addend));
627 dest = gen_rtx_PLUS (Pmode, dest, addend);
628 break;
630 default:
631 gcc_unreachable ();
633 return dest;
636 static bool
637 microblaze_classify_unspec (struct microblaze_address_info *info, rtx x)
639 info->symbol_type = SYMBOL_TYPE_GENERAL;
640 info->symbol = XVECEXP (x, 0, 0);
642 if (XINT (x, 1) == UNSPEC_GOTOFF)
644 info->regA = gen_rtx_REG (SImode, PIC_OFFSET_TABLE_REGNUM);
645 info->type = ADDRESS_GOTOFF;
647 else if (XINT (x, 1) == UNSPEC_PLT)
649 info->type = ADDRESS_PLT;
651 else if (XINT (x, 1) == UNSPEC_TLS)
653 info->type = ADDRESS_TLS;
654 info->tls_type = tls_reloc (INTVAL (XVECEXP (x, 0, 1)));
656 else
658 return false;
660 return true;
664 /* Return true if X is a valid index register for the given mode.
665 Allow only hard registers if STRICT. */
667 static bool
668 microblaze_valid_index_register_p (rtx x,
669 machine_mode mode ATTRIBUTE_UNUSED,
670 int strict)
672 if (!strict && GET_CODE (x) == SUBREG)
673 x = SUBREG_REG (x);
675 return (GET_CODE (x) == REG
676 /* A base register is good enough to be an index register on MicroBlaze. */
677 && microblaze_regno_ok_for_base_p (REGNO (x), strict));
680 /* Get the base register for accessing a value from the memory or
681 Symbol ref. Used for MicroBlaze Small Data Area Pointer Optimization. */
682 static int
683 get_base_reg (rtx x)
685 tree decl;
686 int base_reg;
688 if (!flag_pic || microblaze_tls_symbol_p(x))
689 base_reg = MB_ABI_BASE_REGNUM;
690 else if (flag_pic)
691 base_reg = MB_ABI_PIC_ADDR_REGNUM;
693 if (TARGET_XLGPOPT
694 && GET_CODE (x) == SYMBOL_REF
695 && SYMBOL_REF_SMALL_P (x) && (decl = SYMBOL_REF_DECL (x)) != NULL)
697 if (TREE_READONLY (decl))
698 base_reg = MB_ABI_GPRO_REGNUM;
699 else
700 base_reg = MB_ABI_GPRW_REGNUM;
703 return base_reg;
706 /* Return true if X is a valid address for machine mode MODE. If it is,
707 fill in INFO appropriately. STRICT is true if we should only accept
708 hard base registers.
710 type regA regB offset symbol
712 ADDRESS_INVALID NULL NULL NULL NULL
714 ADDRESS_REG %0 NULL const_0 / NULL
715 const_int
716 ADDRESS_REG_INDEX %0 %1 NULL NULL
718 ADDRESS_SYMBOLIC r0 / NULL NULL symbol
719 sda_base_reg
721 ADDRESS_CONST_INT r0 NULL const NULL
723 For modes spanning multiple registers (DFmode in 32-bit GPRs,
724 DImode, TImode), indexed addressing cannot be used because
725 adjacent memory cells are accessed by adding word-sized offsets
726 during assembly output. */
728 static bool
729 microblaze_classify_address (struct microblaze_address_info *info, rtx x,
730 machine_mode mode, int strict)
732 rtx xplus0;
733 rtx xplus1;
735 info->type = ADDRESS_INVALID;
736 info->regA = NULL;
737 info->regB = NULL;
738 info->offset = NULL;
739 info->symbol = NULL;
740 info->symbol_type = SYMBOL_TYPE_INVALID;
742 switch (GET_CODE (x))
744 case REG:
745 case SUBREG:
747 info->type = ADDRESS_REG;
748 info->regA = x;
749 info->offset = const0_rtx;
750 return microblaze_valid_base_register_p (info->regA, mode, strict);
752 case PLUS:
754 xplus0 = XEXP (x, 0);
755 xplus1 = XEXP (x, 1);
757 if (microblaze_valid_base_register_p (xplus0, mode, strict))
759 info->type = ADDRESS_REG;
760 info->regA = xplus0;
762 if (GET_CODE (xplus1) == CONST_INT)
764 info->offset = xplus1;
765 return true;
767 else if (GET_CODE (xplus1) == UNSPEC)
769 /* Need offsettable address. */
770 if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
771 return false;
773 return microblaze_classify_unspec (info, xplus1);
775 else if ((GET_CODE (xplus1) == SYMBOL_REF ||
776 GET_CODE (xplus1) == LABEL_REF))
778 if (flag_pic == 2 || microblaze_tls_symbol_p(xplus1))
779 return false;
780 info->type = ADDRESS_SYMBOLIC;
781 info->symbol = xplus1;
782 info->symbol_type = SYMBOL_TYPE_GENERAL;
783 return true;
785 else if (GET_CODE (xplus1) == CONST)
787 rtx xconst0 = XEXP(xplus1, 0);
789 /* base + unspec. */
790 if (GET_CODE (xconst0) == UNSPEC)
792 /* Need offsettable address. */
793 if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
794 return false;
795 return microblaze_classify_unspec(info, xconst0);
798 /* for (plus x const_int) just look at x. */
799 if (GET_CODE (xconst0) == PLUS
800 && GET_CODE (XEXP (xconst0, 1)) == CONST_INT
801 && SMALL_INT (XEXP (xconst0, 1)))
803 /* This is ok as info->symbol is set to xplus1 the full
804 const-expression below. */
805 xconst0 = XEXP (xconst0, 0);
808 if (GET_CODE (xconst0) == SYMBOL_REF
809 || GET_CODE (xconst0) == LABEL_REF)
811 if (flag_pic == 2 || microblaze_tls_symbol_p(xconst0))
812 return false;
814 info->type = ADDRESS_SYMBOLIC;
815 info->symbol = xplus1;
816 info->symbol_type = SYMBOL_TYPE_GENERAL;
817 return true;
820 /* Not base + symbol || base + UNSPEC. */
821 return false;
824 else if (GET_CODE (xplus1) == REG
825 && microblaze_valid_index_register_p (xplus1, mode,
826 strict)
827 && (GET_MODE_SIZE (mode) <= UNITS_PER_WORD))
829 /* Restrict larger than word-width modes from using an index register. */
830 info->type = ADDRESS_REG_INDEX;
831 info->regB = xplus1;
832 return true;
835 break;
837 case CONST_INT:
839 info->regA = gen_raw_REG (mode, 0);
840 info->type = ADDRESS_CONST_INT;
841 info->offset = x;
842 return true;
844 case CONST:
845 case LABEL_REF:
846 case SYMBOL_REF:
848 info->type = ADDRESS_SYMBOLIC;
849 info->symbol_type = SYMBOL_TYPE_GENERAL;
850 info->symbol = x;
851 info->regA = gen_raw_REG (mode, get_base_reg (x));
853 if (GET_CODE (x) == CONST)
855 if (GET_CODE (XEXP (x, 0)) == UNSPEC)
857 info->regA = gen_raw_REG (mode,
858 get_base_reg (XVECEXP (XEXP (x,0), 0, 0)));
859 return microblaze_classify_unspec (info, XEXP (x, 0));
861 return !(flag_pic && pic_address_needs_scratch (x));
864 if (flag_pic == 2)
865 return false;
866 else if (microblaze_tls_symbol_p(x))
867 return false;
869 return true;
872 case UNSPEC:
874 if (reload_in_progress)
875 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
876 return microblaze_classify_unspec (info, x);
879 default:
880 return false;
883 return false;
886 /* This function is used to implement GO_IF_LEGITIMATE_ADDRESS. It
887 returns a nonzero value if X is a legitimate address for a memory
888 operand of the indicated MODE. STRICT is nonzero if this function
889 is called during reload. */
891 bool
892 microblaze_legitimate_address_p (machine_mode mode, rtx x, bool strict)
894 struct microblaze_address_info addr;
896 return microblaze_classify_address (&addr, x, mode, strict);
900 microblaze_valid_pic_const (rtx x)
902 switch (GET_CODE (x))
904 case CONST:
905 case CONST_INT:
906 case CONST_DOUBLE:
907 return true;
908 default:
909 return false;
914 microblaze_legitimate_pic_operand (rtx x)
916 if (flag_pic == 2 && (symbol_mentioned_p(x) || label_mentioned_p(x)))
917 return 0;
919 if (microblaze_tls_referenced_p(x))
920 return 0;
922 return 1;
925 /* Try machine-dependent ways of modifying an illegitimate address
926 to be legitimate. If we find one, return the new, valid address.
927 This is used from only one place: `memory_address' in explow.c.
929 OLDX is the address as it was before break_out_memory_refs was
930 called. In some cases it is useful to look at this to decide what
931 needs to be done.
933 It is always safe for this function to do nothing. It exists to
934 recognize opportunities to optimize the output.
936 For the MicroBlaze, transform:
938 memory(X + <large int>)
940 into:
942 Y = <large int> & ~0x7fff;
943 Z = X + Y
944 memory (Z + (<large int> & 0x7fff));
946 This is for CSE to find several similar references, and only use one Z.
948 When PIC, convert addresses of the form memory (symbol+large int) to
949 memory (reg+large int). */
951 static rtx
952 microblaze_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
953 machine_mode mode ATTRIBUTE_UNUSED)
955 register rtx xinsn = x, result;
957 if (GET_CODE (xinsn) == CONST
958 && flag_pic && pic_address_needs_scratch (xinsn))
960 rtx ptr_reg = gen_reg_rtx (Pmode);
961 rtx constant = XEXP (XEXP (xinsn, 0), 1);
963 emit_move_insn (ptr_reg, XEXP (XEXP (xinsn, 0), 0));
965 result = gen_rtx_PLUS (Pmode, ptr_reg, constant);
966 if (SMALL_INT (constant))
967 return result;
968 /* Otherwise we fall through so the code below will fix the
969 constant. */
970 xinsn = result;
973 if (GET_CODE (xinsn) == PLUS)
975 register rtx xplus0 = XEXP (xinsn, 0);
976 register rtx xplus1 = XEXP (xinsn, 1);
977 register enum rtx_code code0 = GET_CODE (xplus0);
978 register enum rtx_code code1 = GET_CODE (xplus1);
980 if (code0 != REG && code1 == REG)
982 xplus0 = XEXP (xinsn, 1);
983 xplus1 = XEXP (xinsn, 0);
984 code0 = GET_CODE (xplus0);
985 code1 = GET_CODE (xplus1);
988 if (code0 == REG && REG_OK_FOR_BASE_P (xplus0)
989 && code1 == CONST_INT && !SMALL_INT (xplus1))
991 rtx int_reg = gen_reg_rtx (Pmode);
992 rtx ptr_reg = gen_reg_rtx (Pmode);
994 emit_move_insn (int_reg, GEN_INT (INTVAL (xplus1) & ~0x7fff));
996 emit_insn (gen_rtx_SET (ptr_reg,
997 gen_rtx_PLUS (Pmode, xplus0, int_reg)));
999 result = gen_rtx_PLUS (Pmode, ptr_reg,
1000 GEN_INT (INTVAL (xplus1) & 0x7fff));
1001 return result;
1004 if (code0 == REG && REG_OK_FOR_BASE_P (xplus0))
1006 if (reload_in_progress)
1007 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
1008 if (code1 == CONST)
1010 xplus1 = XEXP (xplus1, 0);
1011 code1 = GET_CODE (xplus1);
1013 if (code1 == SYMBOL_REF)
1015 if (microblaze_tls_symbol_p(xplus1))
1017 rtx tls_ref, reg;
1018 reg = gen_reg_rtx (Pmode);
1020 tls_ref = microblaze_legitimize_tls_address (xplus1,
1021 NULL_RTX);
1022 emit_move_insn (reg, tls_ref);
1024 result = gen_rtx_PLUS (Pmode, xplus0, reg);
1026 return result;
1028 else if (flag_pic == 2)
1030 rtx pic_ref, reg;
1031 reg = gen_reg_rtx (Pmode);
1033 pic_ref = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, xplus1),
1034 UNSPEC_GOTOFF);
1035 pic_ref = gen_rtx_CONST (Pmode, pic_ref);
1036 pic_ref = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, pic_ref);
1037 pic_ref = gen_const_mem (Pmode, pic_ref);
1038 emit_move_insn (reg, pic_ref);
1039 result = gen_rtx_PLUS (Pmode, xplus0, reg);
1040 return result;
1046 if (GET_CODE (xinsn) == SYMBOL_REF)
1048 rtx reg;
1049 if (microblaze_tls_symbol_p(xinsn))
1051 reg = microblaze_legitimize_tls_address (xinsn, NULL_RTX);
1053 else
1055 rtx pic_ref;
1057 if (reload_in_progress)
1058 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
1060 pic_ref = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, xinsn), UNSPEC_GOTOFF);
1061 pic_ref = gen_rtx_CONST (Pmode, pic_ref);
1062 pic_ref = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, pic_ref);
1063 pic_ref = gen_const_mem (Pmode, pic_ref);
1064 reg = pic_ref;
1066 return reg;
1069 return x;
1072 /* Block Moves. */
1074 #define MAX_MOVE_REGS 8
1075 #define MAX_MOVE_BYTES (MAX_MOVE_REGS * UNITS_PER_WORD)
1077 /* Emit straight-line code to move LENGTH bytes from SRC to DEST.
1078 Assume that the areas do not overlap. */
1080 static void
1081 microblaze_block_move_straight (rtx dest, rtx src, HOST_WIDE_INT length)
1083 HOST_WIDE_INT offset, delta;
1084 unsigned HOST_WIDE_INT bits;
1085 int i;
1086 machine_mode mode;
1087 rtx *regs;
1089 bits = BITS_PER_WORD;
1090 mode = int_mode_for_size (bits, 0).require ();
1091 delta = bits / BITS_PER_UNIT;
1093 /* Allocate a buffer for the temporary registers. */
1094 regs = XALLOCAVEC (rtx, length / delta);
1096 /* Load as many BITS-sized chunks as possible. Use a normal load if
1097 the source has enough alignment, otherwise use left/right pairs. */
1098 for (offset = 0, i = 0; offset + delta <= length; offset += delta, i++)
1100 regs[i] = gen_reg_rtx (mode);
1101 emit_move_insn (regs[i], adjust_address (src, mode, offset));
1104 /* Copy the chunks to the destination. */
1105 for (offset = 0, i = 0; offset + delta <= length; offset += delta, i++)
1106 emit_move_insn (adjust_address (dest, mode, offset), regs[i]);
1108 /* Mop up any left-over bytes. */
1109 if (offset < length)
1111 src = adjust_address (src, BLKmode, offset);
1112 dest = adjust_address (dest, BLKmode, offset);
1113 move_by_pieces (dest, src, length - offset,
1114 MIN (MEM_ALIGN (src), MEM_ALIGN (dest)), 0);
1118 /* Helper function for doing a loop-based block operation on memory
1119 reference MEM. Each iteration of the loop will operate on LENGTH
1120 bytes of MEM.
1122 Create a new base register for use within the loop and point it to
1123 the start of MEM. Create a new memory reference that uses this
1124 register. Store them in *LOOP_REG and *LOOP_MEM respectively. */
1126 static void
1127 microblaze_adjust_block_mem (rtx mem, HOST_WIDE_INT length,
1128 rtx * loop_reg, rtx * loop_mem)
1130 *loop_reg = copy_addr_to_reg (XEXP (mem, 0));
1132 /* Although the new mem does not refer to a known location,
1133 it does keep up to LENGTH bytes of alignment. */
1134 *loop_mem = change_address (mem, BLKmode, *loop_reg);
1135 set_mem_align (*loop_mem,
1136 MIN ((HOST_WIDE_INT) MEM_ALIGN (mem),
1137 length * BITS_PER_UNIT));
1141 /* Move LENGTH bytes from SRC to DEST using a loop that moves MAX_MOVE_BYTES
1142 per iteration. LENGTH must be at least MAX_MOVE_BYTES. Assume that the
1143 memory regions do not overlap. */
1145 static void
1146 microblaze_block_move_loop (rtx dest, rtx src, HOST_WIDE_INT length)
1148 rtx_code_label *label;
1149 rtx src_reg, dest_reg, final_src;
1150 HOST_WIDE_INT leftover;
1152 leftover = length % MAX_MOVE_BYTES;
1153 length -= leftover;
1155 /* Create registers and memory references for use within the loop. */
1156 microblaze_adjust_block_mem (src, MAX_MOVE_BYTES, &src_reg, &src);
1157 microblaze_adjust_block_mem (dest, MAX_MOVE_BYTES, &dest_reg, &dest);
1159 /* Calculate the value that SRC_REG should have after the last iteration
1160 of the loop. */
1161 final_src = expand_simple_binop (Pmode, PLUS, src_reg, GEN_INT (length),
1162 0, 0, OPTAB_WIDEN);
1164 /* Emit the start of the loop. */
1165 label = gen_label_rtx ();
1166 emit_label (label);
1168 /* Emit the loop body. */
1169 microblaze_block_move_straight (dest, src, MAX_MOVE_BYTES);
1171 /* Move on to the next block. */
1172 emit_move_insn (src_reg, plus_constant (Pmode, src_reg, MAX_MOVE_BYTES));
1173 emit_move_insn (dest_reg, plus_constant (Pmode, dest_reg, MAX_MOVE_BYTES));
1175 /* Emit the test & branch. */
1176 emit_insn (gen_cbranchsi4 (gen_rtx_NE (SImode, src_reg, final_src),
1177 src_reg, final_src, label));
1179 /* Mop up any left-over bytes. */
1180 if (leftover)
1181 microblaze_block_move_straight (dest, src, leftover);
1184 /* Expand a movmemsi instruction. */
1186 bool
1187 microblaze_expand_block_move (rtx dest, rtx src, rtx length, rtx align_rtx)
1190 if (GET_CODE (length) == CONST_INT)
1192 HOST_WIDE_INT bytes = INTVAL (length);
1193 int align = INTVAL (align_rtx);
1195 if (align > UNITS_PER_WORD)
1197 align = UNITS_PER_WORD; /* We can't do any better. */
1199 else if (align < UNITS_PER_WORD)
1201 if (INTVAL (length) <= MAX_MOVE_BYTES)
1203 move_by_pieces (dest, src, bytes, align, 0);
1204 return true;
1206 else
1207 return false;
1210 if (INTVAL (length) <= 2 * MAX_MOVE_BYTES)
1212 microblaze_block_move_straight (dest, src, INTVAL (length));
1213 return true;
1215 else if (optimize)
1217 microblaze_block_move_loop (dest, src, INTVAL (length));
1218 return true;
1221 return false;
1224 static bool
1225 microblaze_rtx_costs (rtx x, machine_mode mode, int outer_code ATTRIBUTE_UNUSED,
1226 int opno ATTRIBUTE_UNUSED, int *total,
1227 bool speed ATTRIBUTE_UNUSED)
1229 int code = GET_CODE (x);
1231 switch (code)
1233 case MEM:
1235 int num_words = (GET_MODE_SIZE (mode) > UNITS_PER_WORD) ? 2 : 1;
1236 if (simple_memory_operand (x, mode))
1237 *total = COSTS_N_INSNS (2 * num_words);
1238 else
1239 *total = COSTS_N_INSNS (2 * (2 * num_words));
1241 return true;
1243 case NOT:
1245 if (mode == DImode)
1247 *total = COSTS_N_INSNS (2);
1249 else
1250 *total = COSTS_N_INSNS (1);
1251 return false;
1253 case AND:
1254 case IOR:
1255 case XOR:
1257 if (mode == DImode)
1259 *total = COSTS_N_INSNS (2);
1261 else
1262 *total = COSTS_N_INSNS (1);
1264 return false;
1266 case ASHIFT:
1267 case ASHIFTRT:
1268 case LSHIFTRT:
1270 if (TARGET_BARREL_SHIFT)
1272 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v5.00.a")
1273 >= 0)
1274 *total = COSTS_N_INSNS (1);
1275 else
1276 *total = COSTS_N_INSNS (2);
1278 else if (!TARGET_SOFT_MUL)
1279 *total = COSTS_N_INSNS (1);
1280 else if (GET_CODE (XEXP (x, 1)) == CONST_INT)
1282 /* Add 1 to make shift slightly more expensive than add. */
1283 *total = COSTS_N_INSNS (INTVAL (XEXP (x, 1))) + 1;
1284 /* Reduce shift costs for special circumstances. */
1285 if (optimize_size && INTVAL (XEXP (x, 1)) > 5)
1286 *total -= 2;
1287 if (!optimize_size && INTVAL (XEXP (x, 1)) > 17)
1288 *total -= 2;
1290 else
1291 /* Double the worst cost of shifts when there is no barrel shifter and
1292 the shift amount is in a reg. */
1293 *total = COSTS_N_INSNS (32 * 4);
1294 return true;
1296 case PLUS:
1297 case MINUS:
1299 if (mode == SFmode || mode == DFmode)
1301 if (TARGET_HARD_FLOAT)
1302 *total = COSTS_N_INSNS (6);
1303 return true;
1305 else if (mode == DImode)
1307 *total = COSTS_N_INSNS (4);
1308 return true;
1310 else
1312 *total = COSTS_N_INSNS (1);
1313 return true;
1316 return false;
1318 case NEG:
1320 if (mode == DImode)
1321 *total = COSTS_N_INSNS (4);
1323 return false;
1325 case MULT:
1327 if (mode == SFmode)
1329 if (TARGET_HARD_FLOAT)
1330 *total = COSTS_N_INSNS (6);
1332 else if (!TARGET_SOFT_MUL)
1334 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v5.00.a")
1335 >= 0)
1336 *total = COSTS_N_INSNS (1);
1337 else
1338 *total = COSTS_N_INSNS (3);
1340 else
1341 *total = COSTS_N_INSNS (10);
1342 return true;
1344 case DIV:
1345 case UDIV:
1347 if (mode == SFmode)
1349 if (TARGET_HARD_FLOAT)
1350 *total = COSTS_N_INSNS (23);
1352 return false;
1354 case SIGN_EXTEND:
1356 *total = COSTS_N_INSNS (1);
1357 return false;
1359 case ZERO_EXTEND:
1361 *total = COSTS_N_INSNS (1);
1362 return false;
1366 return false;
1369 /* Return the number of instructions needed to load or store a value
1370 of mode MODE at X. Return 0 if X isn't valid for MODE. */
1372 static int
1373 microblaze_address_insns (rtx x, machine_mode mode)
1375 struct microblaze_address_info addr;
1377 if (microblaze_classify_address (&addr, x, mode, false))
1379 switch (addr.type)
1381 case ADDRESS_REG:
1382 if (SMALL_INT (addr.offset))
1383 return 1;
1384 else
1385 return 2;
1386 case ADDRESS_CONST_INT:
1387 if (SMALL_INT (x))
1388 return 1;
1389 else
1390 return 2;
1391 case ADDRESS_REG_INDEX:
1392 return 1;
1393 case ADDRESS_SYMBOLIC:
1394 case ADDRESS_GOTOFF:
1395 return 2;
1396 case ADDRESS_TLS:
1397 switch (addr.tls_type)
1399 case TLS_GD:
1400 return 2;
1401 case TLS_LDM:
1402 return 2;
1403 case TLS_DTPREL:
1404 return 1;
1405 default :
1406 abort();
1408 default:
1409 break;
1412 return 0;
1415 /* Provide the costs of an addressing mode that contains ADDR.
1416 If ADDR is not a valid address, its cost is irrelevant. */
1417 static int
1418 microblaze_address_cost (rtx addr, machine_mode mode ATTRIBUTE_UNUSED,
1419 addr_space_t as ATTRIBUTE_UNUSED,
1420 bool speed ATTRIBUTE_UNUSED)
1422 return COSTS_N_INSNS (microblaze_address_insns (addr, GET_MODE (addr)));
1425 /* Return nonzero if X is an address which needs a temporary register when
1426 reloaded while generating PIC code. */
1429 pic_address_needs_scratch (rtx x)
1431 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x,0)) == PLUS)
1433 rtx p0, p1;
1435 p0 = XEXP (XEXP (x, 0), 0);
1436 p1 = XEXP (XEXP (x, 0), 1);
1438 if ((GET_CODE (p0) == SYMBOL_REF || GET_CODE (p0) == LABEL_REF)
1439 && (GET_CODE (p1) == CONST_INT)
1440 && (flag_pic == 2 || microblaze_tls_symbol_p (p0) || !SMALL_INT (p1)))
1441 return 1;
1443 return 0;
1446 /* Argument support functions. */
1447 /* Initialize CUMULATIVE_ARGS for a function. */
1449 void
1450 init_cumulative_args (CUMULATIVE_ARGS * cum, tree fntype,
1451 rtx libname ATTRIBUTE_UNUSED)
1453 static CUMULATIVE_ARGS zero_cum;
1454 tree param, next_param;
1456 *cum = zero_cum;
1458 /* Determine if this function has variable arguments. This is
1459 indicated by the last argument being 'void_type_mode' if there
1460 are no variable arguments. The standard MicroBlaze calling sequence
1461 passes all arguments in the general purpose registers in this case. */
1463 for (param = fntype ? TYPE_ARG_TYPES (fntype) : 0;
1464 param != 0; param = next_param)
1466 next_param = TREE_CHAIN (param);
1467 if (next_param == 0 && TREE_VALUE (param) != void_type_node)
1468 cum->gp_reg_found = 1;
1472 /* Advance the argument to the next argument position. */
1474 static void
1475 microblaze_function_arg_advance (cumulative_args_t cum_v,
1476 machine_mode mode,
1477 const_tree type, bool named ATTRIBUTE_UNUSED)
1479 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
1481 cum->arg_number++;
1482 switch (mode)
1484 case E_VOIDmode:
1485 break;
1487 default:
1488 gcc_assert (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
1489 || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT);
1491 cum->gp_reg_found = 1;
1492 cum->arg_words += ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1)
1493 / UNITS_PER_WORD);
1494 break;
1496 case E_BLKmode:
1497 cum->gp_reg_found = 1;
1498 cum->arg_words += ((int_size_in_bytes (type) + UNITS_PER_WORD - 1)
1499 / UNITS_PER_WORD);
1500 break;
1502 case E_SFmode:
1503 cum->arg_words++;
1504 if (!cum->gp_reg_found && cum->arg_number <= 2)
1505 cum->fp_code += 1 << ((cum->arg_number - 1) * 2);
1506 break;
1508 case E_DFmode:
1509 cum->arg_words += 2;
1510 if (!cum->gp_reg_found && cum->arg_number <= 2)
1511 cum->fp_code += 2 << ((cum->arg_number - 1) * 2);
1512 break;
1514 case E_DImode:
1515 cum->gp_reg_found = 1;
1516 cum->arg_words += 2;
1517 break;
1519 case E_QImode:
1520 case E_HImode:
1521 case E_SImode:
1522 case E_TImode:
1523 cum->gp_reg_found = 1;
1524 cum->arg_words++;
1525 break;
1529 /* Return an RTL expression containing the register for the given mode,
1530 or 0 if the argument is to be passed on the stack. */
1532 static rtx
1533 microblaze_function_arg (cumulative_args_t cum_v, machine_mode mode,
1534 const_tree type ATTRIBUTE_UNUSED,
1535 bool named ATTRIBUTE_UNUSED)
1537 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
1539 rtx ret;
1540 int regbase = -1;
1541 int *arg_words = &cum->arg_words;
1543 cum->last_arg_fp = 0;
1544 switch (mode)
1546 case E_SFmode:
1547 case E_DFmode:
1548 case E_VOIDmode:
1549 case E_QImode:
1550 case E_HImode:
1551 case E_SImode:
1552 case E_DImode:
1553 case E_TImode:
1554 regbase = GP_ARG_FIRST;
1555 break;
1556 default:
1557 gcc_assert (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
1558 || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT);
1559 /* FALLTHRU */
1560 case E_BLKmode:
1561 regbase = GP_ARG_FIRST;
1562 break;
1565 if (*arg_words >= MAX_ARGS_IN_REGISTERS)
1566 ret = 0;
1567 else
1569 gcc_assert (regbase != -1);
1571 ret = gen_rtx_REG (mode, regbase + *arg_words);
1574 if (mode == VOIDmode)
1576 if (cum->num_adjusts > 0)
1577 ret = gen_rtx_PARALLEL ((machine_mode) cum->fp_code,
1578 gen_rtvec_v (cum->num_adjusts, cum->adjust));
1581 return ret;
1584 /* Return number of bytes of argument to put in registers. */
1585 static int
1586 function_arg_partial_bytes (cumulative_args_t cum_v, machine_mode mode,
1587 tree type, bool named ATTRIBUTE_UNUSED)
1589 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
1591 if ((mode == BLKmode
1592 || GET_MODE_CLASS (mode) != MODE_COMPLEX_INT
1593 || GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT)
1594 && cum->arg_words < MAX_ARGS_IN_REGISTERS)
1596 int words;
1597 if (mode == BLKmode)
1598 words = ((int_size_in_bytes (type) + UNITS_PER_WORD - 1)
1599 / UNITS_PER_WORD);
1600 else
1601 words = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
1603 if (words + cum->arg_words <= MAX_ARGS_IN_REGISTERS)
1604 return 0; /* structure fits in registers */
1606 return (MAX_ARGS_IN_REGISTERS - cum->arg_words) * UNITS_PER_WORD;
1609 else if (mode == DImode && cum->arg_words == MAX_ARGS_IN_REGISTERS - 1)
1610 return UNITS_PER_WORD;
1612 return 0;
1615 /* Convert a version number of the form "vX.YY.Z" to an integer encoding
1616 for easier range comparison. */
1617 static int
1618 microblaze_version_to_int (const char *version)
1620 const char *p, *v;
1621 const char *tmpl = "vXX.YY.Z";
1622 int iver = 0;
1624 p = version;
1625 v = tmpl;
1627 while (*p)
1629 if (*v == 'X')
1630 { /* Looking for major */
1631 if (*p == '.')
1633 v++;
1635 else
1637 if (!(*p >= '0' && *p <= '9'))
1638 return -1;
1639 iver += (int) (*p - '0');
1640 iver *= 10;
1643 else if (*v == 'Y')
1644 { /* Looking for minor */
1645 if (!(*p >= '0' && *p <= '9'))
1646 return -1;
1647 iver += (int) (*p - '0');
1648 iver *= 10;
1650 else if (*v == 'Z')
1651 { /* Looking for compat */
1652 if (!(*p >= 'a' && *p <= 'z'))
1653 return -1;
1654 iver *= 10;
1655 iver += (int) (*p - 'a');
1657 else
1659 if (*p != *v)
1660 return -1;
1663 v++;
1664 p++;
1667 if (*p)
1668 return -1;
1670 return iver;
1674 static void
1675 microblaze_option_override (void)
1677 register int i, start;
1678 register int regno;
1679 register machine_mode mode;
1680 int ver;
1682 microblaze_section_threshold = (global_options_set.x_g_switch_value
1683 ? g_switch_value
1684 : MICROBLAZE_DEFAULT_GVALUE);
1686 if (flag_pic)
1688 /* Make sure it's 2, we only support one kind of PIC. */
1689 flag_pic = 2;
1690 if (!TARGET_SUPPORTS_PIC)
1692 error ("-fPIC/-fpic not supported for this target");
1693 /* Clear it to avoid further errors. */
1694 flag_pic = 0;
1698 /* Check the MicroBlaze CPU version for any special action to be done. */
1699 if (microblaze_select_cpu == NULL)
1700 microblaze_select_cpu = MICROBLAZE_DEFAULT_CPU;
1701 ver = microblaze_version_to_int (microblaze_select_cpu);
1702 if (ver == -1)
1704 error ("%qs is an invalid argument to -mcpu=", microblaze_select_cpu);
1707 ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v3.00.a");
1708 if (ver < 0)
1710 /* No hardware exceptions in earlier versions. So no worries. */
1711 #if 0
1712 microblaze_select_flags &= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY);
1713 #endif
1714 microblaze_no_unsafe_delay = 0;
1715 microblaze_pipe = MICROBLAZE_PIPE_3;
1717 else if (ver == 0
1718 || (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v4.00.b")
1719 == 0))
1721 #if 0
1722 microblaze_select_flags |= (MICROBLAZE_MASK_NO_UNSAFE_DELAY);
1723 #endif
1724 microblaze_no_unsafe_delay = 1;
1725 microblaze_pipe = MICROBLAZE_PIPE_3;
1727 else
1729 /* We agree to use 5 pipe-stage model even on area optimized 3
1730 pipe-stage variants. */
1731 #if 0
1732 microblaze_select_flags &= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY);
1733 #endif
1734 microblaze_no_unsafe_delay = 0;
1735 microblaze_pipe = MICROBLAZE_PIPE_5;
1736 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v5.00.a") == 0
1737 || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu,
1738 "v5.00.b") == 0
1739 || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu,
1740 "v5.00.c") == 0)
1742 /* Pattern compares are to be turned on by default only when
1743 compiling for MB v5.00.'z'. */
1744 target_flags |= MASK_PATTERN_COMPARE;
1748 ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v6.00.a");
1749 if (ver < 0)
1751 if (TARGET_MULTIPLY_HIGH)
1752 warning (0,
1753 "-mxl-multiply-high can be used only with -mcpu=v6.00.a or greater");
1756 ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v8.10.a");
1757 microblaze_has_clz = 1;
1758 if (ver < 0)
1760 /* MicroBlaze prior to 8.10.a didn't have clz. */
1761 microblaze_has_clz = 0;
1764 /* TARGET_REORDER defaults to 2 if -mxl-reorder not specified. */
1765 ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v8.30.a");
1766 if (ver < 0)
1768 if (TARGET_REORDER == 1)
1769 warning (0, "-mxl-reorder can be used only with -mcpu=v8.30.a or greater");
1770 TARGET_REORDER = 0;
1772 else if ((ver == 0) && !TARGET_PATTERN_COMPARE)
1774 if (TARGET_REORDER == 1)
1775 warning (0, "-mxl-reorder requires -mxl-pattern-compare for -mcpu=v8.30.a");
1776 TARGET_REORDER = 0;
1779 if (TARGET_MULTIPLY_HIGH && TARGET_SOFT_MUL)
1780 error ("-mxl-multiply-high requires -mno-xl-soft-mul");
1782 /* Always use DFA scheduler. */
1783 microblaze_sched_use_dfa = 1;
1785 #if 0
1786 microblaze_abicalls = MICROBLAZE_ABICALLS_NO;
1787 #endif
1789 /* Initialize the high, low values for legit floating point constants. */
1790 real_maxval (&dfhigh, 0, DFmode);
1791 real_maxval (&dflow, 1, DFmode);
1792 real_maxval (&sfhigh, 0, SFmode);
1793 real_maxval (&sflow, 1, SFmode);
1795 microblaze_print_operand_punct['?'] = 1;
1796 microblaze_print_operand_punct['#'] = 1;
1797 microblaze_print_operand_punct['&'] = 1;
1798 microblaze_print_operand_punct['!'] = 1;
1799 microblaze_print_operand_punct['*'] = 1;
1800 microblaze_print_operand_punct['@'] = 1;
1801 microblaze_print_operand_punct['.'] = 1;
1802 microblaze_print_operand_punct['('] = 1;
1803 microblaze_print_operand_punct[')'] = 1;
1804 microblaze_print_operand_punct['['] = 1;
1805 microblaze_print_operand_punct[']'] = 1;
1806 microblaze_print_operand_punct['<'] = 1;
1807 microblaze_print_operand_punct['>'] = 1;
1808 microblaze_print_operand_punct['{'] = 1;
1809 microblaze_print_operand_punct['}'] = 1;
1810 microblaze_print_operand_punct['^'] = 1;
1811 microblaze_print_operand_punct['$'] = 1;
1812 microblaze_print_operand_punct['+'] = 1;
1814 /* Set up array to map GCC register number to debug register number.
1815 Ignore the special purpose register numbers. */
1817 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
1818 microblaze_dbx_regno[i] = -1;
1820 start = GP_DBX_FIRST - GP_REG_FIRST;
1821 for (i = GP_REG_FIRST; i <= GP_REG_LAST; i++)
1822 microblaze_dbx_regno[i] = i + start;
1824 /* Set up array giving whether a given register can hold a given mode. */
1826 for (mode = VOIDmode;
1827 mode != MAX_MACHINE_MODE; mode = (machine_mode) ((int) mode + 1))
1829 register int size = GET_MODE_SIZE (mode);
1831 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
1833 register int ok;
1835 if (mode == CCmode)
1837 ok = (ST_REG_P (regno) || GP_REG_P (regno));
1839 else if (GP_REG_P (regno))
1840 ok = ((regno & 1) == 0 || size <= UNITS_PER_WORD);
1841 else
1842 ok = 0;
1844 microblaze_hard_regno_mode_ok_p[(int) mode][regno] = ok;
1849 /* Implement TARGET_HARD_REGNO_MODE_OK. In 32 bit mode, require that
1850 DImode and DFmode be in even registers. For DImode, this makes some
1851 of the insns easier to write, since you don't have to worry about a
1852 DImode value in registers 3 & 4, producing a result in 4 & 5.
1854 To make the code simpler, the hook now just references an
1855 array built in override_options. */
1857 static bool
1858 microblaze_hard_regno_mode_ok (unsigned int regno, machine_mode mode)
1860 return microblaze_hard_regno_mode_ok_p[mode][regno];
1863 /* Implement TARGET_MODES_TIEABLE_P. */
1865 static bool
1866 microblaze_modes_tieable_p (machine_mode mode1, machine_mode mode2)
1868 return ((GET_MODE_CLASS (mode1) == MODE_FLOAT
1869 || GET_MODE_CLASS (mode1) == MODE_COMPLEX_FLOAT)
1870 == (GET_MODE_CLASS (mode2) == MODE_FLOAT
1871 || GET_MODE_CLASS (mode2) == MODE_COMPLEX_FLOAT));
1874 /* Return true if FUNC is an interrupt function as specified
1875 by the "interrupt_handler" attribute. */
1877 static int
1878 microblaze_interrupt_function_p (tree func)
1880 tree a;
1882 if (TREE_CODE (func) != FUNCTION_DECL)
1883 return 0;
1885 a = lookup_attribute ("interrupt_handler", DECL_ATTRIBUTES (func));
1886 return a != NULL_TREE;
1889 static int
1890 microblaze_fast_interrupt_function_p (tree func)
1892 tree a;
1894 if (TREE_CODE (func) != FUNCTION_DECL)
1895 return 0;
1897 a = lookup_attribute ("fast_interrupt", DECL_ATTRIBUTES (func));
1898 return a != NULL_TREE;
1901 microblaze_break_function_p (tree func)
1903 tree a;
1904 if (!func)
1905 return 0;
1906 if (TREE_CODE (func) != FUNCTION_DECL)
1907 return 0;
1909 a = lookup_attribute ("break_handler", DECL_ATTRIBUTES (func));
1910 return a != NULL_TREE;
1912 /* Return true if FUNC is an interrupt function which uses
1913 normal return, indicated by the "save_volatiles" attribute. */
1915 static int
1916 microblaze_save_volatiles (tree func)
1918 tree a;
1920 if (TREE_CODE (func) != FUNCTION_DECL)
1921 return 0;
1923 a = lookup_attribute ("save_volatiles", DECL_ATTRIBUTES (func));
1924 return a != NULL_TREE;
1927 /* Return whether function is tagged with 'interrupt_handler'
1928 or 'fast_interrupt' attribute. Return true if function
1929 should use return from interrupt rather than normal
1930 function return. */
1932 microblaze_is_interrupt_variant (void)
1934 return (interrupt_handler || fast_interrupt);
1937 microblaze_is_break_handler (void)
1939 return break_handler;
1942 /* Determine of register must be saved/restored in call. */
1943 static int
1944 microblaze_must_save_register (int regno)
1946 if (pic_offset_table_rtx &&
1947 (regno == MB_ABI_PIC_ADDR_REGNUM) && df_regs_ever_live_p (regno))
1948 return 1;
1950 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
1951 return 1;
1953 if (frame_pointer_needed && (regno == HARD_FRAME_POINTER_REGNUM))
1954 return 1;
1956 if (crtl->calls_eh_return
1957 && regno == MB_ABI_SUB_RETURN_ADDR_REGNUM)
1958 return 1;
1960 if (!crtl->is_leaf)
1962 if (regno == MB_ABI_SUB_RETURN_ADDR_REGNUM)
1963 return 1;
1964 if ((microblaze_is_interrupt_variant () || save_volatiles) &&
1965 (regno >= 3 && regno <= 12))
1966 return 1;
1969 if (microblaze_is_interrupt_variant ())
1971 if (df_regs_ever_live_p (regno)
1972 || regno == MB_ABI_MSR_SAVE_REG
1973 || (interrupt_handler
1974 && (regno == MB_ABI_ASM_TEMP_REGNUM
1975 || regno == MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM)))
1976 return 1;
1979 if (save_volatiles)
1981 if (df_regs_ever_live_p (regno)
1982 || regno == MB_ABI_ASM_TEMP_REGNUM
1983 || regno == MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM)
1984 return 1;
1987 if (crtl->calls_eh_return
1988 && (regno == EH_RETURN_DATA_REGNO (0)
1989 || regno == EH_RETURN_DATA_REGNO (1)))
1990 return 1;
1992 return 0;
1995 /* Return the bytes needed to compute the frame pointer from the current
1996 stack pointer.
1998 MicroBlaze stack frames look like:
2002 Before call After call
2003 +-----------------------+ +-----------------------+
2004 high | | | |
2005 mem. | local variables, | | local variables, |
2006 | callee saved and | | callee saved and |
2007 | temps | | temps |
2008 +-----------------------+ +-----------------------+
2009 | arguments for called | | arguments for called |
2010 | subroutines | | subroutines |
2011 | (optional) | | (optional) |
2012 +-----------------------+ +-----------------------+
2013 | Link register | | Link register |
2014 SP->| | | |
2015 +-----------------------+ +-----------------------+
2017 | local variables, |
2018 | callee saved and |
2019 | temps |
2020 +-----------------------+
2021 | MSR (optional if, |
2022 | interrupt handler) |
2023 +-----------------------+
2025 | alloca allocations |
2027 +-----------------------+
2029 | arguments for called |
2030 | subroutines |
2031 | (optional) |
2033 +-----------------------+
2034 | Link register |
2035 low FP,SP->| |
2036 memory +-----------------------+
2040 static HOST_WIDE_INT
2041 compute_frame_size (HOST_WIDE_INT size)
2043 int regno;
2044 HOST_WIDE_INT total_size; /* # bytes that the entire frame takes up. */
2045 HOST_WIDE_INT var_size; /* # bytes that local variables take up. */
2046 HOST_WIDE_INT args_size; /* # bytes that outgoing arguments take up. */
2047 int link_debug_size; /* # bytes for link register. */
2048 HOST_WIDE_INT gp_reg_size; /* # bytes needed to store calle-saved gp regs. */
2049 long mask; /* mask of saved gp registers. */
2051 interrupt_handler =
2052 microblaze_interrupt_function_p (current_function_decl);
2053 break_handler =
2054 microblaze_break_function_p (current_function_decl);
2056 fast_interrupt =
2057 microblaze_fast_interrupt_function_p (current_function_decl);
2058 save_volatiles = microblaze_save_volatiles (current_function_decl);
2059 if (break_handler)
2060 interrupt_handler = break_handler;
2062 gp_reg_size = 0;
2063 mask = 0;
2064 var_size = size;
2065 args_size = crtl->outgoing_args_size;
2067 if ((args_size == 0) && cfun->calls_alloca)
2068 args_size = NUM_OF_ARGS * UNITS_PER_WORD;
2070 total_size = var_size + args_size;
2072 if (flag_pic == 2)
2073 /* force setting GOT. */
2074 df_set_regs_ever_live (MB_ABI_PIC_ADDR_REGNUM, true);
2076 /* Calculate space needed for gp registers. */
2077 for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
2079 if (microblaze_must_save_register (regno))
2082 if (regno != MB_ABI_SUB_RETURN_ADDR_REGNUM)
2083 /* Don't account for link register. It is accounted specially below. */
2084 gp_reg_size += GET_MODE_SIZE (SImode);
2086 mask |= (1L << (regno - GP_REG_FIRST));
2090 total_size += gp_reg_size;
2092 /* Add 4 bytes for MSR. */
2093 if (microblaze_is_interrupt_variant ())
2094 total_size += 4;
2096 /* No space to be allocated for link register in leaf functions with no other
2097 stack requirements. */
2098 if (total_size == 0 && crtl->is_leaf)
2099 link_debug_size = 0;
2100 else
2101 link_debug_size = UNITS_PER_WORD;
2103 total_size += link_debug_size;
2105 /* Save other computed information. */
2106 current_frame_info.total_size = total_size;
2107 current_frame_info.var_size = var_size;
2108 current_frame_info.args_size = args_size;
2109 current_frame_info.gp_reg_size = gp_reg_size;
2110 current_frame_info.mask = mask;
2111 current_frame_info.initialized = reload_completed;
2112 current_frame_info.num_gp = gp_reg_size / UNITS_PER_WORD;
2113 current_frame_info.link_debug_size = link_debug_size;
2115 if (mask)
2116 /* Offset from which to callee-save GP regs. */
2117 current_frame_info.gp_offset = (total_size - gp_reg_size);
2118 else
2119 current_frame_info.gp_offset = 0;
2121 /* Ok, we're done. */
2122 return total_size;
2125 /* Make sure that we're not trying to eliminate to the wrong hard frame
2126 pointer. */
2128 static bool
2129 microblaze_can_eliminate (const int from, const int to)
2131 return ((from == RETURN_ADDRESS_POINTER_REGNUM && !leaf_function_p())
2132 || (to == MB_ABI_SUB_RETURN_ADDR_REGNUM && leaf_function_p())
2133 || (from != RETURN_ADDRESS_POINTER_REGNUM
2134 && (to == HARD_FRAME_POINTER_REGNUM
2135 || (to == STACK_POINTER_REGNUM && !frame_pointer_needed))));
2138 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
2139 pointer or argument pointer or the return address pointer. TO is either
2140 the stack pointer or hard frame pointer. */
2142 HOST_WIDE_INT
2143 microblaze_initial_elimination_offset (int from, int to)
2145 HOST_WIDE_INT offset;
2147 switch (from)
2149 case FRAME_POINTER_REGNUM:
2150 offset = 0;
2151 break;
2152 case ARG_POINTER_REGNUM:
2153 if (to == STACK_POINTER_REGNUM || to == HARD_FRAME_POINTER_REGNUM)
2154 offset = compute_frame_size (get_frame_size ());
2155 else
2156 gcc_unreachable ();
2157 break;
2158 case RETURN_ADDRESS_POINTER_REGNUM:
2159 if (crtl->is_leaf)
2160 offset = 0;
2161 else
2162 offset = current_frame_info.gp_offset +
2163 ((UNITS_PER_WORD - (POINTER_SIZE / BITS_PER_UNIT)));
2164 break;
2165 default:
2166 gcc_unreachable ();
2168 return offset;
2171 /* Print operands using format code.
2173 The MicroBlaze specific codes are:
2175 'X' X is CONST_INT, prints 32 bits in hexadecimal format = "0x%08x",
2176 'x' X is CONST_INT, prints 16 bits in hexadecimal format = "0x%04x",
2177 'F' op is CONST_DOUBLE, print 32 bits in hex,
2178 'd' output integer constant in decimal,
2179 'z' if the operand is 0, use $0 instead of normal operand.
2180 'D' print second register of double-word register operand.
2181 'L' print low-order register of double-word register operand.
2182 'M' print high-order register of double-word register operand.
2183 'C' print part of opcode for a branch condition.
2184 'N' print part of opcode for a branch condition, inverted.
2185 'S' X is CODE_LABEL, print with prefix of "LS" (for embedded switch).
2186 'B' print 'z' for EQ, 'n' for NE
2187 'b' print 'n' for EQ, 'z' for NE
2188 'T' print 'f' for EQ, 't' for NE
2189 't' print 't' for EQ, 'f' for NE
2190 'm' Print 1<<operand.
2191 'i' Print 'i' if MEM operand has immediate value
2192 'y' Print 'y' if MEM operand is single register
2193 'o' Print operand address+4
2194 '?' Print 'd' if we use a branch with delay slot instead of normal branch.
2195 'h' Print high word of const_double (int or float) value as hex
2196 'j' Print low word of const_double (int or float) value as hex
2197 's' Print -1 if operand is negative, 0 if positive (sign extend)
2198 '@' Print the name of the temporary register (rMB_ABI_ASM_TEMP_REGNUM).
2199 '#' Print nop if the delay slot of a branch is not filled.
2202 void
2203 print_operand (FILE * file, rtx op, int letter)
2205 register enum rtx_code code;
2207 if (PRINT_OPERAND_PUNCT_VALID_P (letter))
2209 switch (letter)
2211 case '?':
2212 /* Conditionally add a 'd' to indicate filled delay slot. */
2213 if (final_sequence != NULL)
2214 fputs ("d", file);
2215 break;
2217 case '#':
2218 /* Conditionally add a nop in unfilled delay slot. */
2219 if (final_sequence == NULL)
2220 fputs ("nop\t\t# Unfilled delay slot\n", file);
2221 break;
2223 case '@':
2224 fputs (reg_names[GP_REG_FIRST + MB_ABI_ASM_TEMP_REGNUM], file);
2225 break;
2227 default:
2228 output_operand_lossage ("unknown punctuation '%c'", letter);
2229 break;
2232 return;
2235 if (!op)
2237 output_operand_lossage ("null pointer");
2238 return;
2241 code = GET_CODE (op);
2243 if (code == SIGN_EXTEND)
2244 op = XEXP (op, 0), code = GET_CODE (op);
2246 if (letter == 'C')
2247 switch (code)
2249 case EQ:
2250 fputs ("eq", file);
2251 break;
2252 case NE:
2253 fputs ("ne", file);
2254 break;
2255 case GT:
2256 case GTU:
2257 fputs ("gt", file);
2258 break;
2259 case GE:
2260 case GEU:
2261 fputs ("ge", file);
2262 break;
2263 case LT:
2264 case LTU:
2265 fputs ("lt", file);
2266 break;
2267 case LE:
2268 case LEU:
2269 fputs ("le", file);
2270 break;
2271 default:
2272 fatal_insn ("PRINT_OPERAND, invalid insn for %%C", op);
2275 else if (letter == 'N')
2276 switch (code)
2278 case EQ:
2279 fputs ("ne", file);
2280 break;
2281 case NE:
2282 fputs ("eq", file);
2283 break;
2284 case GT:
2285 case GTU:
2286 fputs ("le", file);
2287 break;
2288 case GE:
2289 case GEU:
2290 fputs ("lt", file);
2291 break;
2292 case LT:
2293 case LTU:
2294 fputs ("ge", file);
2295 break;
2296 case LE:
2297 case LEU:
2298 fputs ("gt", file);
2299 break;
2300 default:
2301 fatal_insn ("PRINT_OPERAND, invalid insn for %%N", op);
2304 else if (letter == 'S')
2306 char buffer[100];
2308 ASM_GENERATE_INTERNAL_LABEL (buffer, "LS", CODE_LABEL_NUMBER (op));
2309 assemble_name (file, buffer);
2312 /* Print 'i' for memory operands which have immediate values. */
2313 else if (letter == 'i')
2315 if (code == MEM)
2317 struct microblaze_address_info info;
2319 if (!microblaze_classify_address
2320 (&info, XEXP (op, 0), GET_MODE (op), 1))
2321 fatal_insn ("insn contains an invalid address !", op);
2323 switch (info.type)
2325 case ADDRESS_REG:
2326 case ADDRESS_CONST_INT:
2327 case ADDRESS_SYMBOLIC:
2328 case ADDRESS_GOTOFF:
2329 case ADDRESS_TLS:
2330 fputs ("i", file);
2331 break;
2332 case ADDRESS_REG_INDEX:
2333 break;
2334 case ADDRESS_INVALID:
2335 case ADDRESS_PLT:
2336 fatal_insn ("invalid address", op);
2341 else if (code == REG || code == SUBREG)
2343 register int regnum;
2345 if (code == REG)
2346 regnum = REGNO (op);
2347 else
2348 regnum = true_regnum (op);
2350 if ((letter == 'M' && !WORDS_BIG_ENDIAN)
2351 || (letter == 'L' && WORDS_BIG_ENDIAN) || letter == 'D')
2352 regnum++;
2354 fprintf (file, "%s", reg_names[regnum]);
2357 else if (code == MEM)
2358 if (letter == 'o')
2360 rtx op4 = adjust_address (op, GET_MODE (op), 4);
2361 output_address (GET_MODE (op), XEXP (op4, 0));
2363 else if (letter == 'y')
2365 rtx mem_reg = XEXP (op, 0);
2366 if (GET_CODE (mem_reg) == REG)
2368 register int regnum = REGNO (mem_reg);
2369 fprintf (file, "%s", reg_names[regnum]);
2372 else
2373 output_address (GET_MODE (op), XEXP (op, 0));
2375 else if (letter == 'h' || letter == 'j')
2377 long val[2];
2378 if (code == CONST_DOUBLE)
2380 if (GET_MODE (op) == DFmode)
2381 REAL_VALUE_TO_TARGET_DOUBLE (*CONST_DOUBLE_REAL_VALUE (op), val);
2382 else
2384 val[0] = CONST_DOUBLE_HIGH (op);
2385 val[1] = CONST_DOUBLE_LOW (op);
2388 else if (code == CONST_INT)
2390 val[0] = (INTVAL (op) & 0xffffffff00000000LL) >> 32;
2391 val[1] = INTVAL (op) & 0x00000000ffffffffLL;
2392 if (val[0] == 0 && val[1] < 0)
2393 val[0] = -1;
2396 fprintf (file, "0x%8.8lx", (letter == 'h') ? val[0] : val[1]);
2398 else if (code == CONST_DOUBLE)
2400 if (letter == 'F')
2402 unsigned long value_long;
2403 REAL_VALUE_TO_TARGET_SINGLE (*CONST_DOUBLE_REAL_VALUE (op),
2404 value_long);
2405 fprintf (file, HOST_WIDE_INT_PRINT_HEX, value_long);
2407 else
2409 char s[60];
2410 real_to_decimal (s, CONST_DOUBLE_REAL_VALUE (op), sizeof (s), 0, 1);
2411 fputs (s, file);
2415 else if (code == UNSPEC)
2417 print_operand_address (file, op);
2420 else if (letter == 'x' && GET_CODE (op) == CONST_INT)
2421 fprintf (file, HOST_WIDE_INT_PRINT_HEX, 0xffff & INTVAL (op));
2423 else if (letter == 'X' && GET_CODE (op) == CONST_INT)
2424 fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (op));
2426 else if (letter == 'd' && GET_CODE (op) == CONST_INT)
2427 fprintf (file, HOST_WIDE_INT_PRINT_DEC, (INTVAL (op)));
2429 else if (letter == 'z' && GET_CODE (op) == CONST_INT && INTVAL (op) == 0)
2430 fputs (reg_names[GP_REG_FIRST], file);
2432 else if (letter == 's' && GET_CODE (op) == CONST_INT)
2433 if (INTVAL (op) < 0)
2434 fputs ("-1", file);
2435 else
2436 fputs ("0", file);
2438 else if (letter == 'd' || letter == 'x' || letter == 'X' || letter == 's')
2439 output_operand_lossage ("letter %c was found & insn was not CONST_INT", letter);
2441 else if (letter == 'B')
2442 fputs (code == EQ ? "z" : "n", file);
2443 else if (letter == 'b')
2444 fputs (code == EQ ? "n" : "z", file);
2445 else if (letter == 'T')
2446 fputs (code == EQ ? "f" : "t", file);
2447 else if (letter == 't')
2448 fputs (code == EQ ? "t" : "f", file);
2450 else if (code == CONST
2451 && ((GET_CODE (XEXP (op, 0)) == REG)
2452 || (GET_CODE (XEXP (op, 0)) == UNSPEC)))
2454 print_operand (file, XEXP (op, 0), letter);
2456 else if (code == CONST
2457 && (GET_CODE (XEXP (op, 0)) == PLUS)
2458 && (GET_CODE (XEXP (XEXP (op, 0), 0)) == REG)
2459 && (GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST))
2461 print_operand_address (file, XEXP (op, 0));
2463 else if (letter == 'm')
2464 fprintf (file, HOST_WIDE_INT_PRINT_DEC, (1L << INTVAL (op)));
2465 else
2466 output_addr_const (file, op);
2469 /* A C compound statement to output to stdio stream STREAM the
2470 assembler syntax for an instruction operand that is a memory
2471 reference whose address is ADDR. ADDR is an RTL expression.
2473 Possible address classifications and output formats are,
2475 ADDRESS_REG "%0, r0"
2477 ADDRESS_REG with non-zero "%0, <addr_const>"
2478 offset
2480 ADDRESS_REG_INDEX "rA, RB"
2481 (if rA is r0, rA and rB are swapped)
2483 ADDRESS_CONST_INT "r0, <addr_const>"
2485 ADDRESS_SYMBOLIC "rBase, <addr_const>"
2486 (rBase is a base register suitable for the
2487 symbol's type)
2490 void
2491 print_operand_address (FILE * file, rtx addr)
2493 struct microblaze_address_info info;
2494 enum microblaze_address_type type;
2495 if (!microblaze_classify_address (&info, addr, GET_MODE (addr), 1))
2496 fatal_insn ("insn contains an invalid address !", addr);
2498 type = info.type;
2499 switch (info.type)
2501 case ADDRESS_REG:
2502 fprintf (file, "%s,", reg_names[REGNO (info.regA)]);
2503 output_addr_const (file, info.offset);
2504 break;
2505 case ADDRESS_REG_INDEX:
2506 if (REGNO (info.regA) == 0)
2507 /* Make rB == r0 instead of rA == r0. This helps reduce read port
2508 congestion. */
2509 fprintf (file, "%s,%s", reg_names[REGNO (info.regB)],
2510 reg_names[REGNO (info.regA)]);
2511 else if (REGNO (info.regB) != 0)
2512 /* This is a silly swap to help Dhrystone. */
2513 fprintf (file, "%s,%s", reg_names[REGNO (info.regB)],
2514 reg_names[REGNO (info.regA)]);
2515 break;
2516 case ADDRESS_CONST_INT:
2517 fprintf (file, "%s,", reg_names[REGNO (info.regA)]);
2518 output_addr_const (file, info.offset);
2519 break;
2520 case ADDRESS_SYMBOLIC:
2521 case ADDRESS_GOTOFF:
2522 case ADDRESS_PLT:
2523 case ADDRESS_TLS:
2524 if (info.regA)
2525 fprintf (file, "%s,", reg_names[REGNO (info.regA)]);
2526 output_addr_const (file, info.symbol);
2527 if (type == ADDRESS_GOTOFF)
2529 fputs ("@GOT", file);
2531 else if (type == ADDRESS_PLT)
2533 fputs ("@PLT", file);
2535 else if (type == ADDRESS_TLS)
2537 switch (info.tls_type)
2539 case TLS_GD:
2540 fputs ("@TLSGD", file);
2541 break;
2542 case TLS_LDM:
2543 fputs ("@TLSLDM", file);
2544 break;
2545 case TLS_DTPREL:
2546 fputs ("@TLSDTPREL", file);
2547 break;
2548 default :
2549 abort();
2550 break;
2553 break;
2554 case ADDRESS_INVALID:
2555 fatal_insn ("invalid address", addr);
2556 break;
2560 /* Emit either a label, .comm, or .lcomm directive, and mark that the symbol
2561 is used, so that we don't emit an .extern for it in
2562 microblaze_asm_file_end. */
2564 void
2565 microblaze_declare_object (FILE * stream, const char *name,
2566 const char *section, const char *fmt, int size)
2569 fputs (section, stream);
2570 assemble_name (stream, name);
2571 fprintf (stream, fmt, size);
2574 /* Common code to emit the insns (or to write the instructions to a file)
2575 to save/restore registers.
2577 Other parts of the code assume that MICROBLAZE_TEMP1_REGNUM (aka large_reg)
2578 is not modified within save_restore_insns. */
2580 #define BITSET_P(VALUE,BIT) (((VALUE) & (1L << (BIT))) != 0)
2582 /* Save or restore instructions based on whether this is the prologue or
2583 epilogue. prologue is 1 for the prologue. */
2584 static void
2585 save_restore_insns (int prologue)
2587 rtx base_reg_rtx, reg_rtx, mem_rtx, /* msr_rtx, */ isr_reg_rtx =
2588 0, isr_mem_rtx = 0;
2589 rtx isr_msr_rtx = 0, insn;
2590 long mask = current_frame_info.mask;
2591 HOST_WIDE_INT gp_offset;
2592 int regno;
2594 if (frame_pointer_needed
2595 && !BITSET_P (mask, HARD_FRAME_POINTER_REGNUM - GP_REG_FIRST))
2596 gcc_unreachable ();
2598 if (mask == 0)
2599 return;
2601 /* Save registers starting from high to low. The debuggers prefer at least
2602 the return register be stored at func+4, and also it allows us not to
2603 need a nop in the epilog if at least one register is reloaded in
2604 addition to return address. */
2606 /* Pick which pointer to use as a base register. For small frames, just
2607 use the stack pointer. Otherwise, use a temporary register. Save 2
2608 cycles if the save area is near the end of a large frame, by reusing
2609 the constant created in the prologue/epilogue to adjust the stack
2610 frame. */
2612 gp_offset = current_frame_info.gp_offset;
2614 gcc_assert (gp_offset > 0);
2616 base_reg_rtx = stack_pointer_rtx;
2618 /* For interrupt_handlers, need to save/restore the MSR. */
2619 if (microblaze_is_interrupt_variant ())
2621 isr_mem_rtx = gen_rtx_MEM (SImode,
2622 gen_rtx_PLUS (Pmode, base_reg_rtx,
2623 GEN_INT (current_frame_info.
2624 gp_offset -
2625 UNITS_PER_WORD)));
2627 /* Do not optimize in flow analysis. */
2628 MEM_VOLATILE_P (isr_mem_rtx) = 1;
2629 isr_reg_rtx = gen_rtx_REG (SImode, MB_ABI_MSR_SAVE_REG);
2630 isr_msr_rtx = gen_rtx_REG (SImode, ST_REG);
2633 if (microblaze_is_interrupt_variant () && !prologue)
2635 emit_move_insn (isr_reg_rtx, isr_mem_rtx);
2636 emit_move_insn (isr_msr_rtx, isr_reg_rtx);
2637 /* Do not optimize in flow analysis. */
2638 emit_insn (gen_rtx_USE (SImode, isr_reg_rtx));
2639 emit_insn (gen_rtx_USE (SImode, isr_msr_rtx));
2642 for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
2644 if (BITSET_P (mask, regno - GP_REG_FIRST))
2646 if (regno == MB_ABI_SUB_RETURN_ADDR_REGNUM)
2647 /* Don't handle here. Already handled as the first register. */
2648 continue;
2650 reg_rtx = gen_rtx_REG (SImode, regno);
2651 insn = gen_rtx_PLUS (Pmode, base_reg_rtx, GEN_INT (gp_offset));
2652 mem_rtx = gen_rtx_MEM (SImode, insn);
2653 if (microblaze_is_interrupt_variant () || save_volatiles)
2654 /* Do not optimize in flow analysis. */
2655 MEM_VOLATILE_P (mem_rtx) = 1;
2657 if (prologue)
2659 insn = emit_move_insn (mem_rtx, reg_rtx);
2660 RTX_FRAME_RELATED_P (insn) = 1;
2662 else
2664 insn = emit_move_insn (reg_rtx, mem_rtx);
2667 gp_offset += GET_MODE_SIZE (SImode);
2671 if (microblaze_is_interrupt_variant () && prologue)
2673 emit_move_insn (isr_reg_rtx, isr_msr_rtx);
2674 emit_move_insn (isr_mem_rtx, isr_reg_rtx);
2676 /* Do not optimize in flow analysis. */
2677 emit_insn (gen_rtx_USE (SImode, isr_reg_rtx));
2678 emit_insn (gen_rtx_USE (SImode, isr_msr_rtx));
2681 /* Done saving and restoring */
2685 /* Set up the stack and frame (if desired) for the function. */
2686 static void
2687 microblaze_function_prologue (FILE * file)
2689 const char *fnname;
2690 long fsiz = current_frame_info.total_size;
2692 /* Get the function name the same way that toplev.c does before calling
2693 assemble_start_function. This is needed so that the name used here
2694 exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */
2695 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
2696 if (!flag_inhibit_size_directive)
2698 fputs ("\t.ent\t", file);
2699 if (interrupt_handler && strcmp (INTERRUPT_HANDLER_NAME, fnname))
2700 fputs ("_interrupt_handler", file);
2701 else if (break_handler && strcmp (BREAK_HANDLER_NAME, fnname))
2702 fputs ("_break_handler", file);
2703 else if (fast_interrupt && strcmp (FAST_INTERRUPT_NAME, fnname))
2704 fputs ("_fast_interrupt", file);
2705 else
2706 assemble_name (file, fnname);
2707 fputs ("\n", file);
2708 if (!microblaze_is_interrupt_variant ())
2709 ASM_OUTPUT_TYPE_DIRECTIVE (file, fnname, "function");
2712 assemble_name (file, fnname);
2713 fputs (":\n", file);
2715 if (interrupt_handler && strcmp (INTERRUPT_HANDLER_NAME, fnname))
2716 fputs ("_interrupt_handler:\n", file);
2717 if (break_handler && strcmp (BREAK_HANDLER_NAME, fnname))
2718 fputs ("_break_handler:\n", file);
2719 if (!flag_inhibit_size_directive)
2721 /* .frame FRAMEREG, FRAMESIZE, RETREG. */
2722 fprintf (file,
2723 "\t.frame\t%s,%ld,%s\t\t# vars= %ld, regs= %d, args= %d\n",
2724 (reg_names[(frame_pointer_needed)
2725 ? HARD_FRAME_POINTER_REGNUM :
2726 STACK_POINTER_REGNUM]), fsiz,
2727 reg_names[MB_ABI_SUB_RETURN_ADDR_REGNUM + GP_REG_FIRST],
2728 current_frame_info.var_size, current_frame_info.num_gp,
2729 crtl->outgoing_args_size);
2730 fprintf (file, "\t.mask\t0x%08lx\n", current_frame_info.mask);
2734 /* Output extra assembler code at the end of a prologue. */
2735 static void
2736 microblaze_function_end_prologue (FILE * file)
2738 if (TARGET_STACK_CHECK)
2740 fprintf (file, "\t# Stack Check Stub -- Start.\n\t");
2741 fprintf (file, "ori\tr18,r0,_stack_end\n\t");
2742 fprintf (file, "cmpu\tr18,r1,r18\n\t");
2743 fprintf (file, "bgei\tr18,_stack_overflow_exit\n\t");
2744 fprintf (file, "# Stack Check Stub -- End.\n");
2748 static void
2749 microblaze_elf_asm_cdtor (rtx symbol, int priority, bool is_ctor)
2751 section *s;
2753 if (priority != DEFAULT_INIT_PRIORITY)
2755 char buf[18];
2756 sprintf (buf, "%s.%.5u",
2757 is_ctor ? ".ctors" : ".dtors",
2758 MAX_INIT_PRIORITY - priority);
2759 s = get_section (buf, SECTION_WRITE, NULL_TREE);
2761 else if (is_ctor)
2762 s = ctors_section;
2763 else
2764 s = dtors_section;
2766 switch_to_section (s);
2767 assemble_align (POINTER_SIZE);
2768 fputs ("\t.word\t", asm_out_file);
2769 output_addr_const (asm_out_file, symbol);
2770 fputs ("\n", asm_out_file);
2773 /* Add a function to the list of static constructors. */
2775 static void
2776 microblaze_elf_asm_constructor (rtx symbol, int priority)
2778 microblaze_elf_asm_cdtor (symbol, priority, /*is_ctor=*/true);
2781 /* Add a function to the list of static destructors. */
2783 static void
2784 microblaze_elf_asm_destructor (rtx symbol, int priority)
2786 microblaze_elf_asm_cdtor (symbol, priority, /*is_ctor=*/false);
2789 /* Expand the prologue into a bunch of separate insns. */
2791 void
2792 microblaze_expand_prologue (void)
2794 int regno;
2795 HOST_WIDE_INT fsiz;
2796 const char *arg_name = 0;
2797 tree fndecl = current_function_decl;
2798 tree fntype = TREE_TYPE (fndecl);
2799 tree fnargs = DECL_ARGUMENTS (fndecl);
2800 rtx next_arg_reg;
2801 int i;
2802 tree next_arg;
2803 tree cur_arg;
2804 CUMULATIVE_ARGS args_so_far_v;
2805 cumulative_args_t args_so_far;
2806 rtx mem_rtx, reg_rtx;
2808 /* If struct value address is treated as the first argument, make it so. */
2809 if (aggregate_value_p (DECL_RESULT (fndecl), fntype)
2810 && !cfun->returns_pcc_struct)
2812 tree type = build_pointer_type (fntype);
2813 tree function_result_decl = build_decl (BUILTINS_LOCATION, PARM_DECL,
2814 NULL_TREE, type);
2816 DECL_ARG_TYPE (function_result_decl) = type;
2817 TREE_CHAIN (function_result_decl) = fnargs;
2818 fnargs = function_result_decl;
2821 /* Determine the last argument, and get its name. */
2823 INIT_CUMULATIVE_ARGS (args_so_far_v, fntype, NULL_RTX, 0, 0);
2824 args_so_far = pack_cumulative_args (&args_so_far_v);
2825 regno = GP_ARG_FIRST;
2827 for (cur_arg = fnargs; cur_arg != 0; cur_arg = next_arg)
2829 tree passed_type = DECL_ARG_TYPE (cur_arg);
2830 machine_mode passed_mode = TYPE_MODE (passed_type);
2831 rtx entry_parm;
2833 if (TREE_ADDRESSABLE (passed_type))
2835 passed_type = build_pointer_type (passed_type);
2836 passed_mode = Pmode;
2839 entry_parm = targetm.calls.function_arg (args_so_far, passed_mode,
2840 passed_type, true);
2842 if (entry_parm)
2844 int words;
2846 /* passed in a register, so will get homed automatically. */
2847 if (GET_MODE (entry_parm) == BLKmode)
2848 words = (int_size_in_bytes (passed_type) + 3) / 4;
2849 else
2850 words = (GET_MODE_SIZE (GET_MODE (entry_parm)) + 3) / 4;
2852 regno = REGNO (entry_parm) + words - 1;
2854 else
2856 regno = GP_ARG_LAST + 1;
2857 break;
2860 targetm.calls.function_arg_advance (args_so_far, passed_mode,
2861 passed_type, true);
2863 next_arg = TREE_CHAIN (cur_arg);
2864 if (next_arg == 0)
2866 if (DECL_NAME (cur_arg))
2867 arg_name = IDENTIFIER_POINTER (DECL_NAME (cur_arg));
2869 break;
2873 /* Split parallel insn into a sequence of insns. */
2875 next_arg_reg = targetm.calls.function_arg (args_so_far, VOIDmode,
2876 void_type_node, true);
2877 if (next_arg_reg != 0 && GET_CODE (next_arg_reg) == PARALLEL)
2879 rtvec adjust = XVEC (next_arg_reg, 0);
2880 int num = GET_NUM_ELEM (adjust);
2882 for (i = 0; i < num; i++)
2884 rtx pattern = RTVEC_ELT (adjust, i);
2885 emit_insn (pattern);
2889 fsiz = compute_frame_size (get_frame_size ());
2891 if (flag_stack_usage_info)
2892 current_function_static_stack_size = fsiz;
2895 /* If this function is a varargs function, store any registers that
2896 would normally hold arguments ($5 - $10) on the stack. */
2897 if (((TYPE_ARG_TYPES (fntype) != 0
2898 && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
2899 != void_type_node))
2900 || (arg_name != 0
2901 && ((arg_name[0] == '_'
2902 && strcmp (arg_name, "__builtin_va_alist") == 0)
2903 || (arg_name[0] == 'v'
2904 && strcmp (arg_name, "va_alist") == 0)))))
2906 int offset = (regno - GP_ARG_FIRST + 1) * UNITS_PER_WORD;
2907 rtx ptr = stack_pointer_rtx;
2909 /* If we are doing svr4-abi, sp has already been decremented by fsiz. */
2910 for (; regno <= GP_ARG_LAST; regno++)
2912 if (offset != 0)
2913 ptr = gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (offset));
2914 emit_move_insn (gen_rtx_MEM (SImode, ptr),
2915 gen_rtx_REG (SImode, regno));
2917 offset += GET_MODE_SIZE (SImode);
2922 if (fsiz > 0)
2924 rtx fsiz_rtx = GEN_INT (fsiz);
2926 rtx_insn *insn = NULL;
2927 insn = emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx,
2928 fsiz_rtx));
2929 if (insn)
2930 RTX_FRAME_RELATED_P (insn) = 1;
2932 /* Handle SUB_RETURN_ADDR_REGNUM specially at first. */
2933 if (!crtl->is_leaf || interrupt_handler)
2935 mem_rtx = gen_rtx_MEM (SImode,
2936 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
2937 const0_rtx));
2939 if (interrupt_handler)
2940 /* Do not optimize in flow analysis. */
2941 MEM_VOLATILE_P (mem_rtx) = 1;
2943 reg_rtx = gen_rtx_REG (SImode, MB_ABI_SUB_RETURN_ADDR_REGNUM);
2944 insn = emit_move_insn (mem_rtx, reg_rtx);
2945 RTX_FRAME_RELATED_P (insn) = 1;
2948 /* _save_ registers for prologue. */
2949 save_restore_insns (1);
2951 if (frame_pointer_needed)
2953 rtx_insn *insn = 0;
2955 insn = emit_insn (gen_movsi (hard_frame_pointer_rtx,
2956 stack_pointer_rtx));
2958 if (insn)
2959 RTX_FRAME_RELATED_P (insn) = 1;
2963 if ((flag_pic == 2 || TLS_NEEDS_GOT )
2964 && df_regs_ever_live_p (MB_ABI_PIC_ADDR_REGNUM))
2966 SET_REGNO (pic_offset_table_rtx, MB_ABI_PIC_ADDR_REGNUM);
2967 emit_insn (gen_set_got (pic_offset_table_rtx)); /* setting GOT. */
2970 /* If we are profiling, make sure no instructions are scheduled before
2971 the call to mcount. */
2973 if (profile_flag)
2974 emit_insn (gen_blockage ());
2977 /* Do necessary cleanup after a function to restore stack, frame, and regs. */
2979 #define RA_MASK ((long) 0x80000000) /* 1 << 31 */
2980 #define PIC_OFFSET_TABLE_MASK (1 << (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST))
2982 static void
2983 microblaze_function_epilogue (FILE *file)
2985 const char *fnname;
2987 /* Get the function name the same way that toplev.c does before calling
2988 assemble_start_function. This is needed so that the name used here
2989 exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */
2990 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
2992 if (!flag_inhibit_size_directive)
2994 fputs ("\t.end\t", file);
2995 if (interrupt_handler && !break_handler)
2996 fputs ("_interrupt_handler", file);
2997 else if (break_handler)
2998 fputs ("_break_handler", file);
2999 else
3000 assemble_name (file, fnname);
3001 fputs ("\n", file);
3004 /* Reset state info for each function. */
3005 current_frame_info = zero_frame_info;
3007 /* Restore the output file if optimizing the GP (optimizing the GP causes
3008 the text to be diverted to a tempfile, so that data decls come before
3009 references to the data). */
3012 /* Expand the epilogue into a bunch of separate insns. */
3014 void
3015 microblaze_expand_epilogue (void)
3017 HOST_WIDE_INT fsiz = current_frame_info.total_size;
3018 rtx fsiz_rtx = GEN_INT (fsiz);
3019 rtx reg_rtx;
3020 rtx mem_rtx;
3022 /* In case of interrupt handlers use addki instead of addi for changing the
3023 stack pointer value. */
3025 if (microblaze_can_use_return_insn ())
3027 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode,
3028 GP_REG_FIRST +
3029 MB_ABI_SUB_RETURN_ADDR_REGNUM)));
3030 return;
3033 if (fsiz > 0)
3035 /* Restore SUB_RETURN_ADDR_REGNUM at first. This is to prevent the
3036 sequence of load-followed by a use (in rtsd) in every prologue. Saves
3037 a load-use stall cycle :) This is also important to handle alloca.
3038 (See comments for if (frame_pointer_needed) below. */
3040 if (!crtl->is_leaf || interrupt_handler)
3042 mem_rtx =
3043 gen_rtx_MEM (SImode,
3044 gen_rtx_PLUS (Pmode, stack_pointer_rtx, const0_rtx));
3045 if (interrupt_handler)
3046 /* Do not optimize in flow analysis. */
3047 MEM_VOLATILE_P (mem_rtx) = 1;
3048 reg_rtx = gen_rtx_REG (SImode, MB_ABI_SUB_RETURN_ADDR_REGNUM);
3049 emit_move_insn (reg_rtx, mem_rtx);
3052 /* It is important that this is done after we restore the return address
3053 register (above). When alloca is used, we want to restore the
3054 sub-routine return address only from the current stack top and not
3055 from the frame pointer (which we restore below). (frame_pointer + 0)
3056 might have been over-written since alloca allocates memory on the
3057 current stack. */
3058 if (frame_pointer_needed)
3059 emit_insn (gen_movsi (stack_pointer_rtx, hard_frame_pointer_rtx));
3061 /* _restore_ registers for epilogue. */
3062 save_restore_insns (0);
3063 emit_insn (gen_blockage ());
3064 emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, fsiz_rtx));
3067 if (crtl->calls_eh_return)
3068 emit_insn (gen_addsi3 (stack_pointer_rtx,
3069 stack_pointer_rtx,
3070 gen_raw_REG (SImode,
3071 MB_EH_STACKADJ_REGNUM)));
3073 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode, GP_REG_FIRST +
3074 MB_ABI_SUB_RETURN_ADDR_REGNUM)));
3078 /* Return nonzero if this function is known to have a null epilogue.
3079 This allows the optimizer to omit jumps to jumps if no stack
3080 was created. */
3083 microblaze_can_use_return_insn (void)
3085 if (!reload_completed)
3086 return 0;
3088 if (df_regs_ever_live_p (MB_ABI_SUB_RETURN_ADDR_REGNUM) || profile_flag)
3089 return 0;
3091 if (current_frame_info.initialized)
3092 return current_frame_info.total_size == 0;
3094 return compute_frame_size (get_frame_size ()) == 0;
3097 /* Implement TARGET_SECONDARY_RELOAD. */
3099 static reg_class_t
3100 microblaze_secondary_reload (bool in_p ATTRIBUTE_UNUSED, rtx x ATTRIBUTE_UNUSED,
3101 reg_class_t rclass, machine_mode mode ATTRIBUTE_UNUSED,
3102 secondary_reload_info *sri ATTRIBUTE_UNUSED)
3104 if (rclass == ST_REGS)
3105 return GR_REGS;
3107 return NO_REGS;
3110 static void
3111 microblaze_globalize_label (FILE * stream, const char *name)
3113 fputs ("\t.globl\t", stream);
3114 if (microblaze_is_interrupt_variant ())
3116 if (interrupt_handler && strcmp (name, INTERRUPT_HANDLER_NAME))
3117 fputs (INTERRUPT_HANDLER_NAME, stream);
3118 else if (break_handler && strcmp (name, BREAK_HANDLER_NAME))
3119 fputs (BREAK_HANDLER_NAME, stream);
3120 else if (fast_interrupt && strcmp (name, FAST_INTERRUPT_NAME))
3121 fputs (FAST_INTERRUPT_NAME, stream);
3122 fputs ("\n\t.globl\t", stream);
3124 assemble_name (stream, name);
3125 fputs ("\n", stream);
3128 /* Returns true if decl should be placed into a "small data" section. */
3129 static bool
3130 microblaze_elf_in_small_data_p (const_tree decl)
3132 HOST_WIDE_INT size;
3134 if (!TARGET_XLGPOPT)
3135 return false;
3137 /* We want to merge strings, so we never consider them small data. */
3138 if (TREE_CODE (decl) == STRING_CST)
3139 return false;
3141 /* Functions are never in the small data area. */
3142 if (TREE_CODE (decl) == FUNCTION_DECL)
3143 return false;
3145 if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl))
3147 const char *section = DECL_SECTION_NAME (decl);
3148 if (strcmp (section, ".sdata") == 0
3149 || strcmp (section, ".sdata2") == 0
3150 || strcmp (section, ".sbss") == 0
3151 || strcmp (section, ".sbss2") == 0)
3152 return true;
3155 size = int_size_in_bytes (TREE_TYPE (decl));
3157 return (size > 0 && size <= microblaze_section_threshold);
3161 static section *
3162 microblaze_select_section (tree decl, int reloc, unsigned HOST_WIDE_INT align)
3164 switch (categorize_decl_for_section (decl, reloc))
3166 case SECCAT_RODATA_MERGE_STR:
3167 case SECCAT_RODATA_MERGE_STR_INIT:
3168 /* MB binutils have various issues with mergeable string sections and
3169 relaxation/relocation. Currently, turning mergeable sections
3170 into regular readonly sections. */
3172 return readonly_data_section;
3173 default:
3174 return default_elf_select_section (decl, reloc, align);
3179 Encode info about sections into the RTL based on a symbol's declaration.
3180 The default definition of this hook, default_encode_section_info in
3181 `varasm.c', sets a number of commonly-useful bits in SYMBOL_REF_FLAGS. */
3183 static void
3184 microblaze_encode_section_info (tree decl, rtx rtl, int first)
3186 default_encode_section_info (decl, rtl, first);
3189 static rtx
3190 expand_pic_symbol_ref (machine_mode mode ATTRIBUTE_UNUSED, rtx op)
3192 rtx result;
3193 result = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op), UNSPEC_GOTOFF);
3194 result = gen_rtx_CONST (Pmode, result);
3195 result = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, result);
3196 result = gen_const_mem (Pmode, result);
3197 return result;
3200 static void
3201 microblaze_asm_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
3202 HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
3203 tree function)
3205 rtx this_rtx, funexp;
3206 rtx_insn *insn;
3208 reload_completed = 1;
3209 epilogue_completed = 1;
3211 /* Mark the end of the (empty) prologue. */
3212 emit_note (NOTE_INSN_PROLOGUE_END);
3214 /* Find the "this" pointer. If the function returns a structure,
3215 the structure return pointer is in MB_ABI_FIRST_ARG_REGNUM. */
3216 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
3217 this_rtx = gen_rtx_REG (Pmode, (MB_ABI_FIRST_ARG_REGNUM + 1));
3218 else
3219 this_rtx = gen_rtx_REG (Pmode, MB_ABI_FIRST_ARG_REGNUM);
3221 /* Apply the constant offset, if required. */
3222 if (delta)
3223 emit_insn (gen_addsi3 (this_rtx, this_rtx, GEN_INT (delta)));
3225 /* Apply the offset from the vtable, if required. */
3226 if (vcall_offset)
3228 rtx vcall_offset_rtx = GEN_INT (vcall_offset);
3229 rtx temp1 = gen_rtx_REG (Pmode, MB_ABI_TEMP1_REGNUM);
3231 emit_move_insn (temp1, gen_rtx_MEM (Pmode, this_rtx));
3233 rtx loc = gen_rtx_PLUS (Pmode, temp1, vcall_offset_rtx);
3234 emit_move_insn (temp1, gen_rtx_MEM (Pmode, loc));
3236 emit_insn (gen_addsi3 (this_rtx, this_rtx, temp1));
3239 /* Generate a tail call to the target function. */
3240 if (!TREE_USED (function))
3242 assemble_external (function);
3243 TREE_USED (function) = 1;
3246 funexp = XEXP (DECL_RTL (function), 0);
3247 rtx temp2 = gen_rtx_REG (Pmode, MB_ABI_TEMP2_REGNUM);
3249 if (flag_pic)
3250 emit_move_insn (temp2, expand_pic_symbol_ref (Pmode, funexp));
3251 else
3252 emit_move_insn (temp2, funexp);
3254 emit_insn (gen_indirect_jump (temp2));
3256 /* Run just enough of rest_of_compilation. This sequence was
3257 "borrowed" from rs6000.c. */
3258 insn = get_insns ();
3259 shorten_branches (insn);
3260 final_start_function (insn, file, 1);
3261 final (insn, file, 1);
3262 final_end_function ();
3264 reload_completed = 0;
3265 epilogue_completed = 0;
3268 bool
3269 microblaze_expand_move (machine_mode mode, rtx operands[])
3271 rtx op0, op1;
3273 op0 = operands[0];
3274 op1 = operands[1];
3276 if (!register_operand (op0, SImode)
3277 && !register_operand (op1, SImode)
3278 && (GET_CODE (op1) != CONST_INT || INTVAL (op1) != 0))
3280 rtx temp = force_reg (SImode, op1);
3281 emit_move_insn (op0, temp);
3282 return true;
3284 /* If operands[1] is a constant address invalid for pic, then we need to
3285 handle it just like LEGITIMIZE_ADDRESS does. */
3286 if (GET_CODE (op1) == SYMBOL_REF || GET_CODE (op1) == LABEL_REF)
3288 rtx result;
3289 if (microblaze_tls_symbol_p(op1))
3291 result = microblaze_legitimize_tls_address (op1, NULL_RTX);
3292 emit_move_insn (op0, result);
3293 return true;
3295 else if (flag_pic)
3297 if (reload_in_progress)
3298 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
3299 result = expand_pic_symbol_ref (mode, op1);
3300 emit_move_insn (op0, result);
3301 return true;
3304 /* Handle Case of (const (plus symbol const_int)). */
3305 if (GET_CODE (op1) == CONST && GET_CODE (XEXP (op1,0)) == PLUS)
3307 rtx p0, p1;
3309 p0 = XEXP (XEXP (op1, 0), 0);
3310 p1 = XEXP (XEXP (op1, 0), 1);
3312 if ((GET_CODE (p1) == CONST_INT)
3313 && ((GET_CODE (p0) == UNSPEC)
3314 || ((GET_CODE (p0) == SYMBOL_REF || GET_CODE (p0) == LABEL_REF)
3315 && (flag_pic == 2 || microblaze_tls_symbol_p (p0)
3316 || !SMALL_INT (p1)))))
3318 rtx temp = force_reg (SImode, p0);
3319 rtx temp2 = p1;
3321 if (flag_pic && reload_in_progress)
3322 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
3323 emit_move_insn (op0, gen_rtx_PLUS (SImode, temp, temp2));
3324 return true;
3327 return false;
3330 /* Expand shift operations. */
3332 microblaze_expand_shift (rtx operands[])
3334 gcc_assert ((GET_CODE (operands[2]) == CONST_INT)
3335 || (GET_CODE (operands[2]) == REG)
3336 || (GET_CODE (operands[2]) == SUBREG));
3338 /* Shift by one -- generate pattern. */
3339 if ((GET_CODE (operands[2]) == CONST_INT) && (INTVAL (operands[2]) == 1))
3340 return 0;
3342 /* Have barrel shifter and shift > 1: use it. */
3343 if (TARGET_BARREL_SHIFT)
3344 return 0;
3346 gcc_assert ((GET_CODE (operands[0]) == REG)
3347 || (GET_CODE (operands[0]) == SUBREG)
3348 || (GET_CODE (operands[1]) == REG)
3349 || (GET_CODE (operands[1]) == SUBREG));
3351 /* Shift by zero -- copy regs if necessary. */
3352 if (operands[2] == const0_rtx
3353 && !rtx_equal_p (operands[0], operands[1]))
3355 emit_insn (gen_movsi (operands[0], operands[1]));
3356 return 1;
3359 return 0;
3362 /* Return an RTX indicating where the return address to the
3363 calling function can be found. */
3365 microblaze_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
3367 if (count != 0)
3368 return NULL_RTX;
3370 return get_hard_reg_initial_val (Pmode,
3371 MB_ABI_SUB_RETURN_ADDR_REGNUM);
3374 void
3375 microblaze_eh_return (rtx op0)
3377 emit_insn (gen_movsi (gen_rtx_MEM (Pmode, stack_pointer_rtx), op0));
3380 /* Queue an .ident string in the queue of top-level asm statements.
3381 If the string size is below the threshold, put it into .sdata2.
3382 If the front-end is done, we must be being called from toplev.c.
3383 In that case, do nothing. */
3384 void
3385 microblaze_asm_output_ident (const char *string)
3387 const char *section_asm_op;
3388 int size;
3389 char *buf;
3391 if (symtab->state != PARSING)
3392 return;
3394 size = strlen (string) + 1;
3395 if (size <= microblaze_section_threshold)
3396 section_asm_op = SDATA2_SECTION_ASM_OP;
3397 else
3398 section_asm_op = READONLY_DATA_SECTION_ASM_OP;
3400 buf = ACONCAT ((section_asm_op, "\n\t.ascii \"", string, "\\0\"\n", NULL));
3401 symtab->finalize_toplevel_asm (build_string (strlen (buf), buf));
3404 static void
3405 microblaze_elf_asm_init_sections (void)
3407 sdata2_section
3408 = get_unnamed_section (SECTION_WRITE, output_section_asm_op,
3409 SDATA2_SECTION_ASM_OP);
3412 /* Generate assembler code for constant parts of a trampoline. */
3414 static void
3415 microblaze_asm_trampoline_template (FILE *f)
3417 fprintf (f, "\tmfs r18, rpc\n");
3418 fprintf (f, "\tlwi r3, r18, 16\n");
3419 fprintf (f, "\tlwi r18, r18, 20\n");
3420 fprintf (f, "\tbra r18\n");
3421 /* fprintf (f, "\t.word\t0x00000000\t\t# <function address>\n"); */
3422 /* fprintf (f, "\t.word\t0x00000000\t\t# <static chain value>\n"); */
3425 /* Implement TARGET_TRAMPOLINE_INIT. */
3427 static void
3428 microblaze_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
3430 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
3431 rtx mem;
3433 emit_block_move (m_tramp, assemble_trampoline_template (),
3434 GEN_INT (6*UNITS_PER_WORD), BLOCK_OP_NORMAL);
3436 mem = adjust_address (m_tramp, SImode, 16);
3437 emit_move_insn (mem, chain_value);
3438 mem = adjust_address (m_tramp, SImode, 20);
3439 emit_move_insn (mem, fnaddr);
3442 /* Generate conditional branch -- first, generate test condition,
3443 second, generate correct branch instruction. */
3445 void
3446 microblaze_expand_conditional_branch (machine_mode mode, rtx operands[])
3448 enum rtx_code code = GET_CODE (operands[0]);
3449 rtx cmp_op0 = operands[1];
3450 rtx cmp_op1 = operands[2];
3451 rtx label1 = operands[3];
3452 rtx comp_reg = gen_reg_rtx (SImode);
3453 rtx condition;
3455 gcc_assert ((GET_CODE (cmp_op0) == REG) || (GET_CODE (cmp_op0) == SUBREG));
3457 /* If comparing against zero, just test source reg. */
3458 if (cmp_op1 == const0_rtx)
3460 comp_reg = cmp_op0;
3461 condition = gen_rtx_fmt_ee (signed_condition (code), SImode, comp_reg, const0_rtx);
3462 emit_jump_insn (gen_condjump (condition, label1));
3465 else if (code == EQ || code == NE)
3467 /* Use xor for equal/not-equal comparison. */
3468 emit_insn (gen_xorsi3 (comp_reg, cmp_op0, cmp_op1));
3469 condition = gen_rtx_fmt_ee (signed_condition (code), SImode, comp_reg, const0_rtx);
3470 emit_jump_insn (gen_condjump (condition, label1));
3472 else
3474 /* Generate compare and branch in single instruction. */
3475 cmp_op1 = force_reg (mode, cmp_op1);
3476 condition = gen_rtx_fmt_ee (code, mode, cmp_op0, cmp_op1);
3477 emit_jump_insn (gen_branch_compare(condition, cmp_op0, cmp_op1, label1));
3481 void
3482 microblaze_expand_conditional_branch_reg (machine_mode mode, rtx operands[])
3484 enum rtx_code code = GET_CODE (operands[0]);
3485 rtx cmp_op0 = operands[1];
3486 rtx cmp_op1 = operands[2];
3487 rtx label1 = operands[3];
3488 rtx comp_reg = gen_reg_rtx (SImode);
3489 rtx condition;
3491 gcc_assert ((GET_CODE (cmp_op0) == REG)
3492 || (GET_CODE (cmp_op0) == SUBREG));
3494 /* If comparing against zero, just test source reg. */
3495 if (cmp_op1 == const0_rtx)
3497 comp_reg = cmp_op0;
3498 condition = gen_rtx_fmt_ee (signed_condition (code),
3499 SImode, comp_reg, const0_rtx);
3500 emit_jump_insn (gen_condjump (condition, label1));
3502 else if (code == EQ)
3504 emit_insn (gen_seq_internal_pat (comp_reg,
3505 cmp_op0, cmp_op1));
3506 condition = gen_rtx_EQ (SImode, comp_reg, const0_rtx);
3507 emit_jump_insn (gen_condjump (condition, label1));
3509 else if (code == NE)
3511 emit_insn (gen_sne_internal_pat (comp_reg, cmp_op0,
3512 cmp_op1));
3513 condition = gen_rtx_NE (SImode, comp_reg, const0_rtx);
3514 emit_jump_insn (gen_condjump (condition, label1));
3516 else
3518 /* Generate compare and branch in single instruction. */
3519 cmp_op1 = force_reg (mode, cmp_op1);
3520 condition = gen_rtx_fmt_ee (code, mode, cmp_op0, cmp_op1);
3521 emit_jump_insn (gen_branch_compare (condition, cmp_op0,
3522 cmp_op1, label1));
3526 void
3527 microblaze_expand_conditional_branch_sf (rtx operands[])
3529 rtx condition;
3530 rtx cmp_op0 = XEXP (operands[0], 0);
3531 rtx cmp_op1 = XEXP (operands[0], 1);
3532 rtx comp_reg = gen_reg_rtx (SImode);
3534 emit_insn (gen_cstoresf4 (comp_reg, operands[0], cmp_op0, cmp_op1));
3535 condition = gen_rtx_NE (SImode, comp_reg, const0_rtx);
3536 emit_jump_insn (gen_condjump (condition, operands[3]));
3539 /* Implement TARGET_FRAME_POINTER_REQUIRED. */
3541 static bool
3542 microblaze_frame_pointer_required (void)
3544 /* If the function contains dynamic stack allocations, we need to
3545 use the frame pointer to access the static parts of the frame. */
3546 if (cfun->calls_alloca)
3547 return true;
3548 return false;
3551 void
3552 microblaze_expand_divide (rtx operands[])
3554 /* Table lookup software divides. Works for all (nr/dr) where (0 <= nr,dr <= 15). */
3556 rtx regt1 = gen_reg_rtx (SImode);
3557 rtx reg18 = gen_rtx_REG (SImode, R_TMP);
3558 rtx regqi = gen_reg_rtx (QImode);
3559 rtx_code_label *div_label = gen_label_rtx ();
3560 rtx_code_label *div_end_label = gen_label_rtx ();
3561 rtx div_table_rtx = gen_rtx_SYMBOL_REF (QImode,"_divsi3_table");
3562 rtx mem_rtx;
3563 rtx ret;
3564 rtx_insn *jump, *cjump, *insn;
3566 insn = emit_insn (gen_iorsi3 (regt1, operands[1], operands[2]));
3567 cjump = emit_jump_insn_after (gen_cbranchsi4 (
3568 gen_rtx_GTU (SImode, regt1, GEN_INT (15)),
3569 regt1, GEN_INT (15), div_label), insn);
3570 LABEL_NUSES (div_label) = 1;
3571 JUMP_LABEL (cjump) = div_label;
3572 emit_insn (gen_rtx_CLOBBER (SImode, reg18));
3574 emit_insn (gen_ashlsi3_bshift (regt1, operands[1], GEN_INT(4)));
3575 emit_insn (gen_addsi3 (regt1, regt1, operands[2]));
3576 mem_rtx = gen_rtx_MEM (QImode,
3577 gen_rtx_PLUS (Pmode, regt1, div_table_rtx));
3579 insn = emit_insn (gen_movqi (regqi, mem_rtx));
3580 insn = emit_insn (gen_movsi (operands[0], gen_rtx_SUBREG (SImode, regqi, 0)));
3581 jump = emit_jump_insn_after (gen_jump (div_end_label), insn);
3582 JUMP_LABEL (jump) = div_end_label;
3583 LABEL_NUSES (div_end_label) = 1;
3584 emit_barrier ();
3586 emit_label (div_label);
3587 ret = emit_library_call_value (gen_rtx_SYMBOL_REF (Pmode, "__divsi3"),
3588 operands[0], LCT_NORMAL,
3589 GET_MODE (operands[0]),
3590 operands[1], GET_MODE (operands[1]),
3591 operands[2], GET_MODE (operands[2]));
3592 if (ret != operands[0])
3593 emit_move_insn (operands[0], ret);
3595 emit_label (div_end_label);
3596 emit_insn (gen_blockage ());
3599 /* Implement TARGET_FUNCTION_VALUE. */
3600 static rtx
3601 microblaze_function_value (const_tree valtype,
3602 const_tree func ATTRIBUTE_UNUSED,
3603 bool outgoing ATTRIBUTE_UNUSED)
3605 return LIBCALL_VALUE (TYPE_MODE (valtype));
3608 /* Implement TARGET_SCHED_ADJUST_COST. */
3609 static int
3610 microblaze_adjust_cost (rtx_insn *, int dep_type, rtx_insn *, int cost,
3611 unsigned int)
3613 if (dep_type == REG_DEP_OUTPUT || dep_type == 0)
3614 return cost;
3615 return 0;
3618 /* Implement TARGET_LEGITIMATE_CONSTANT_P.
3620 At present, GAS doesn't understand li.[sd], so don't allow it
3621 to be generated at present. */
3622 static bool
3623 microblaze_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED, rtx x)
3626 if (microblaze_cannot_force_const_mem(mode, x))
3627 return false;
3629 if (GET_CODE (x) == CONST_DOUBLE)
3631 return microblaze_const_double_ok (x, GET_MODE (x));
3634 /* Handle Case of (const (plus unspec const_int)). */
3635 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x,0)) == PLUS)
3637 rtx p0, p1;
3639 p0 = XEXP (XEXP (x, 0), 0);
3640 p1 = XEXP (XEXP (x, 0), 1);
3642 if (GET_CODE(p1) == CONST_INT)
3644 /* Const offset from UNSPEC is not supported. */
3645 if ((GET_CODE (p0) == UNSPEC))
3646 return false;
3648 if ((GET_CODE (p0) == SYMBOL_REF || GET_CODE (p0) == LABEL_REF)
3649 && (microblaze_tls_symbol_p (p0) || !SMALL_INT (p1)))
3650 return false;
3654 return true;
3657 static rtx
3658 get_branch_target (rtx branch)
3660 if (CALL_P (branch))
3662 rtx call;
3664 call = XVECEXP (PATTERN (branch), 0, 0);
3665 if (GET_CODE (call) == SET)
3666 call = SET_SRC (call);
3667 if (GET_CODE (call) != CALL)
3668 abort ();
3669 return XEXP (XEXP (call, 0), 0);
3672 return NULL_RTX;
3675 /* Heuristics to identify where to insert at the
3676 fall through path of the caller function. If there
3677 is a call after the caller branch delay slot then
3678 we dont generate the instruction prefetch instruction.
3680 Scan up to 32 instructions after the call and checks
3681 for the JUMP and call instruction . If there is a call
3682 or JUMP instruction in the range of 32 instruction "wic"
3683 instruction wont be generated. Otherwise insert the "wic"
3684 instruction in the fall through of the call instruction
3685 four instruction after the call. before_4 is used for
3686 the position to insert "wic" instructions. before_16 is
3687 used to check for call and JUMP instruction for first
3688 15 insns. */
3690 static void
3691 insert_wic_for_ilb_runout (rtx_insn *first)
3693 rtx_insn *insn;
3694 rtx_insn *before_4 = 0;
3695 rtx_insn *before_16 = 0;
3696 int addr_offset = 0;
3697 int length;
3698 int wic_addr0 = 128 * 4;
3700 int first_addr = INSN_ADDRESSES (INSN_UID (first));
3702 for (insn = first; insn; insn = NEXT_INSN (insn))
3703 if (INSN_P (insn))
3705 addr_offset = INSN_ADDRESSES (INSN_UID (insn)) - first_addr;
3706 length = get_attr_length (insn);
3707 if (before_4 == 0 && addr_offset + length >= 4 * 4)
3708 before_4 = insn;
3710 if (JUMP_P(insn))
3711 return;
3712 if (before_16 == 0 && addr_offset + length >= 14 * 4)
3713 before_16 = insn;
3714 if (CALL_P (insn) || tablejump_p (insn, 0, 0))
3715 return;
3716 if (addr_offset + length >= 32 * 4)
3718 gcc_assert (before_4 && before_16);
3719 if (wic_addr0 > 4 * 4)
3721 insn =
3722 emit_insn_before (gen_iprefetch
3723 (gen_int_mode (addr_offset, SImode)),
3724 before_4);
3725 recog_memoized (insn);
3726 INSN_LOCATION (insn) = INSN_LOCATION (before_4);
3727 INSN_ADDRESSES_NEW (insn, INSN_ADDRESSES (INSN_UID (before_4)));
3728 return;
3734 /* Insert instruction prefetch instruction at the fall
3735 through path of the function call. */
3737 static void
3738 insert_wic (void)
3740 rtx_insn *insn;
3741 int i;
3742 basic_block bb, prev = 0;
3743 rtx branch_target = 0;
3745 shorten_branches (get_insns ());
3747 for (i = 0; i < n_basic_blocks_for_fn (cfun) - 1; i++)
3749 edge e;
3750 edge_iterator ei;
3751 bool simple_loop = false;
3753 bb = BASIC_BLOCK_FOR_FN (cfun, i);
3755 if (bb == NULL)
3756 continue;
3758 if ((prev != 0) && (prev != bb))
3759 continue;
3760 else
3761 prev = 0;
3763 FOR_EACH_EDGE (e, ei, bb->preds)
3764 if (e->src == bb)
3766 simple_loop = true;
3767 prev= e->dest;
3768 break;
3771 for (insn = BB_END (bb); insn; insn = PREV_INSN (insn))
3773 if (INSN_P (insn) && !simple_loop
3774 && CALL_P(insn))
3776 if ((branch_target = get_branch_target (insn)))
3777 insert_wic_for_ilb_runout (
3778 next_active_insn (next_active_insn (insn)));
3780 if (insn == BB_HEAD (bb))
3781 break;
3786 /* The reorg function defined through the macro
3787 TARGET_MACHINE_DEPENDENT_REORG. */
3789 static void
3790 microblaze_machine_dependent_reorg (void)
3792 if (TARGET_PREFETCH)
3794 compute_bb_for_insn ();
3795 loop_optimizer_init (AVOID_CFG_MODIFICATIONS);
3796 shorten_branches (get_insns ());
3797 insert_wic ();
3798 loop_optimizer_finalize ();
3799 free_bb_for_insn ();
3800 return;
3804 /* Implement TARGET_CONSTANT_ALIGNMENT. */
3806 static HOST_WIDE_INT
3807 microblaze_constant_alignment (const_tree exp, HOST_WIDE_INT align)
3809 if (TREE_CODE (exp) == STRING_CST || TREE_CODE (exp) == CONSTRUCTOR)
3810 return MAX (align, BITS_PER_WORD);
3811 return align;
3814 /* Implement TARGET_STARTING_FRAME_OFFSET. */
3816 static HOST_WIDE_INT
3817 microblaze_starting_frame_offset (void)
3819 return (crtl->outgoing_args_size + FIRST_PARM_OFFSET(FNDECL));
3822 #undef TARGET_ENCODE_SECTION_INFO
3823 #define TARGET_ENCODE_SECTION_INFO microblaze_encode_section_info
3825 #undef TARGET_ASM_GLOBALIZE_LABEL
3826 #define TARGET_ASM_GLOBALIZE_LABEL microblaze_globalize_label
3828 #undef TARGET_ASM_FUNCTION_PROLOGUE
3829 #define TARGET_ASM_FUNCTION_PROLOGUE microblaze_function_prologue
3831 #undef TARGET_ASM_FUNCTION_EPILOGUE
3832 #define TARGET_ASM_FUNCTION_EPILOGUE microblaze_function_epilogue
3834 #undef TARGET_RTX_COSTS
3835 #define TARGET_RTX_COSTS microblaze_rtx_costs
3837 #undef TARGET_CANNOT_FORCE_CONST_MEM
3838 #define TARGET_CANNOT_FORCE_CONST_MEM microblaze_cannot_force_const_mem
3840 #undef TARGET_ADDRESS_COST
3841 #define TARGET_ADDRESS_COST microblaze_address_cost
3843 #undef TARGET_ATTRIBUTE_TABLE
3844 #define TARGET_ATTRIBUTE_TABLE microblaze_attribute_table
3846 #undef TARGET_IN_SMALL_DATA_P
3847 #define TARGET_IN_SMALL_DATA_P microblaze_elf_in_small_data_p
3849 #undef TARGET_ASM_SELECT_SECTION
3850 #define TARGET_ASM_SELECT_SECTION microblaze_select_section
3852 #undef TARGET_HAVE_SRODATA_SECTION
3853 #define TARGET_HAVE_SRODATA_SECTION true
3855 #undef TARGET_ASM_FUNCTION_END_PROLOGUE
3856 #define TARGET_ASM_FUNCTION_END_PROLOGUE \
3857 microblaze_function_end_prologue
3859 #undef TARGET_ARG_PARTIAL_BYTES
3860 #define TARGET_ARG_PARTIAL_BYTES function_arg_partial_bytes
3862 #undef TARGET_FUNCTION_ARG
3863 #define TARGET_FUNCTION_ARG microblaze_function_arg
3865 #undef TARGET_FUNCTION_ARG_ADVANCE
3866 #define TARGET_FUNCTION_ARG_ADVANCE microblaze_function_arg_advance
3868 #undef TARGET_CAN_ELIMINATE
3869 #define TARGET_CAN_ELIMINATE microblaze_can_eliminate
3871 #undef TARGET_LEGITIMIZE_ADDRESS
3872 #define TARGET_LEGITIMIZE_ADDRESS microblaze_legitimize_address
3874 #undef TARGET_LEGITIMATE_ADDRESS_P
3875 #define TARGET_LEGITIMATE_ADDRESS_P microblaze_legitimate_address_p
3877 #undef TARGET_LRA_P
3878 #define TARGET_LRA_P hook_bool_void_false
3880 #undef TARGET_FRAME_POINTER_REQUIRED
3881 #define TARGET_FRAME_POINTER_REQUIRED microblaze_frame_pointer_required
3883 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
3884 #define TARGET_ASM_TRAMPOLINE_TEMPLATE microblaze_asm_trampoline_template
3886 #undef TARGET_TRAMPOLINE_INIT
3887 #define TARGET_TRAMPOLINE_INIT microblaze_trampoline_init
3889 #undef TARGET_PROMOTE_FUNCTION_MODE
3890 #define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
3892 #undef TARGET_FUNCTION_VALUE
3893 #define TARGET_FUNCTION_VALUE microblaze_function_value
3895 #undef TARGET_SECONDARY_RELOAD
3896 #define TARGET_SECONDARY_RELOAD microblaze_secondary_reload
3898 #undef TARGET_ASM_OUTPUT_MI_THUNK
3899 #define TARGET_ASM_OUTPUT_MI_THUNK microblaze_asm_output_mi_thunk
3901 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
3902 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true
3904 #undef TARGET_SCHED_ADJUST_COST
3905 #define TARGET_SCHED_ADJUST_COST microblaze_adjust_cost
3907 #undef TARGET_ASM_INIT_SECTIONS
3908 #define TARGET_ASM_INIT_SECTIONS microblaze_elf_asm_init_sections
3910 #undef TARGET_OPTION_OVERRIDE
3911 #define TARGET_OPTION_OVERRIDE microblaze_option_override
3913 #undef TARGET_LEGITIMATE_CONSTANT_P
3914 #define TARGET_LEGITIMATE_CONSTANT_P microblaze_legitimate_constant_p
3916 #undef TARGET_MACHINE_DEPENDENT_REORG
3917 #define TARGET_MACHINE_DEPENDENT_REORG microblaze_machine_dependent_reorg
3919 #undef TARGET_HARD_REGNO_MODE_OK
3920 #define TARGET_HARD_REGNO_MODE_OK microblaze_hard_regno_mode_ok
3922 #undef TARGET_MODES_TIEABLE_P
3923 #define TARGET_MODES_TIEABLE_P microblaze_modes_tieable_p
3925 #undef TARGET_CONSTANT_ALIGNMENT
3926 #define TARGET_CONSTANT_ALIGNMENT microblaze_constant_alignment
3928 #undef TARGET_STARTING_FRAME_OFFSET
3929 #define TARGET_STARTING_FRAME_OFFSET microblaze_starting_frame_offset
3931 struct gcc_target targetm = TARGET_INITIALIZER;
3933 #include "gt-microblaze.h"