PR tree-optimization/84480 - bogus -Wstringop-truncation despite assignment with...
[official-gcc.git] / gcc / config / microblaze / microblaze.c
blob9a4a287be2345b544421180a888e3d13ff8dffc2
1 /* Subroutines used for code generation on Xilinx MicroBlaze.
2 Copyright (C) 2009-2018 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 #define IN_TARGET_CODE 1
24 #include "config.h"
25 #include "system.h"
26 #include "coretypes.h"
27 #include "backend.h"
28 #include "target.h"
29 #include "rtl.h"
30 #include "tree.h"
31 #include "stringpool.h"
32 #include "attribs.h"
33 #include "df.h"
34 #include "memmodel.h"
35 #include "tm_p.h"
36 #include "optabs.h"
37 #include "regs.h"
38 #include "emit-rtl.h"
39 #include "recog.h"
40 #include "cgraph.h"
41 #include "diagnostic-core.h"
42 #include "varasm.h"
43 #include "stor-layout.h"
44 #include "calls.h"
45 #include "explow.h"
46 #include "expr.h"
47 #include "reload.h"
48 #include "output.h"
49 #include "builtins.h"
50 #include "rtl-iter.h"
51 #include "cfgloop.h"
52 #include "insn-addr.h"
53 #include "cfgrtl.h"
55 /* This file should be included last. */
56 #include "target-def.h"
58 #define MICROBLAZE_VERSION_COMPARE(VA,VB) strcasecmp (VA, VB)
60 /* Classifies an address.
62 ADDRESS_INVALID
63 An invalid address.
65 ADDRESS_REG
67 A natural register or a register + const_int offset address.
68 The register satisfies microblaze_valid_base_register_p and the
69 offset is a const_arith_operand.
71 ADDRESS_REG_INDEX
73 A natural register offset by the index contained in an index register. The base
74 register satisfies microblaze_valid_base_register_p and the index register
75 satisfies microblaze_valid_index_register_p
77 ADDRESS_CONST_INT
79 A signed 16/32-bit constant address.
81 ADDRESS_SYMBOLIC:
83 A constant symbolic address or a (register + symbol). */
85 enum microblaze_address_type
87 ADDRESS_INVALID,
88 ADDRESS_REG,
89 ADDRESS_REG_INDEX,
90 ADDRESS_CONST_INT,
91 ADDRESS_SYMBOLIC,
92 ADDRESS_GOTOFF,
93 ADDRESS_PLT,
94 ADDRESS_TLS
97 /* Classifies symbols
99 SYMBOL_TYPE_GENERAL
101 A general symbol. */
102 enum microblaze_symbol_type
104 SYMBOL_TYPE_INVALID,
105 SYMBOL_TYPE_GENERAL
108 /* TLS Address Type. */
109 enum tls_reloc {
110 TLS_GD,
111 TLS_LDM,
112 TLS_DTPREL,
113 TLS_IE,
114 TLS_LE
117 /* Classification of a MicroBlaze address. */
118 struct microblaze_address_info
120 enum microblaze_address_type type;
121 rtx regA; /* Contains valid values on ADDRESS_REG, ADDRESS_REG_INDEX,
122 ADDRESS_SYMBOLIC. */
123 rtx regB; /* Contains valid values on ADDRESS_REG_INDEX. */
124 rtx offset; /* Contains valid values on ADDRESS_CONST_INT and ADDRESS_REG. */
125 rtx symbol; /* Contains valid values on ADDRESS_SYMBOLIC. */
126 enum microblaze_symbol_type symbol_type;
127 enum tls_reloc tls_type;
130 /* Structure to be filled in by compute_frame_size with register
131 save masks, and offsets for the current function. */
133 struct GTY(()) microblaze_frame_info {
134 long total_size; /* # bytes that the entire frame takes up. */
135 long var_size; /* # bytes that variables take up. */
136 long args_size; /* # bytes that outgoing arguments take up. */
137 int link_debug_size; /* # bytes for the link reg and back pointer. */
138 int gp_reg_size; /* # bytes needed to store gp regs. */
139 long gp_offset; /* offset from new sp to store gp registers. */
140 long mask; /* mask of saved gp registers. */
141 int initialized; /* != 0 if frame size already calculated. */
142 int num_gp; /* number of gp registers saved. */
143 long insns_len; /* length of insns. */
144 int alloc_stack; /* Flag to indicate if the current function
145 must not create stack space. (As an optimization). */
148 /* Global variables for machine-dependent things. */
150 /* Toggle which pipleline interface to use. */
151 static GTY(()) int microblaze_sched_use_dfa = 0;
153 /* Threshold for data being put into the small data/bss area, instead
154 of the normal data area (references to the small data/bss area take
155 1 instruction, and use the global pointer, references to the normal
156 data area takes 2 instructions). */
157 int microblaze_section_threshold = -1;
159 /* Prevent scheduling potentially exception causing instructions in
160 delay slots. -mcpu=v3.00.a or v4.00.a turns this on. */
161 int microblaze_no_unsafe_delay;
163 /* Set to one if the targeted core has the CLZ insn. */
164 int microblaze_has_clz = 0;
166 /* Which CPU pipeline do we use. We haven't really standardized on a CPU
167 version having only a particular type of pipeline. There can still be
168 options on the CPU to scale pipeline features up or down. :(
169 Bad Presentation (??), so we let the MD file rely on the value of
170 this variable instead Making PIPE_5 the default. It should be backward
171 optimal with PIPE_3 MicroBlazes. */
172 enum pipeline_type microblaze_pipe = MICROBLAZE_PIPE_5;
174 /* High and low marks for floating point values which we will accept
175 as legitimate constants for TARGET_LEGITIMATE_CONSTANT_P. These are
176 initialized in override_options. */
177 REAL_VALUE_TYPE dfhigh, dflow, sfhigh, sflow;
179 /* Array giving truth value on whether or not a given hard register
180 can support a given mode. */
181 static char microblaze_hard_regno_mode_ok_p[(int)MAX_MACHINE_MODE]
182 [FIRST_PSEUDO_REGISTER];
184 /* Current frame information calculated by compute_frame_size. */
185 struct microblaze_frame_info current_frame_info;
187 /* Zero structure to initialize current_frame_info. */
188 struct microblaze_frame_info zero_frame_info;
190 /* List of all MICROBLAZE punctuation characters used by print_operand. */
191 char microblaze_print_operand_punct[256];
193 /* Map GCC register number to debugger register number. */
194 int microblaze_dbx_regno[FIRST_PSEUDO_REGISTER];
196 /* Map hard register number to register class. */
197 enum reg_class microblaze_regno_to_class[] =
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 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
206 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
207 ST_REGS, GR_REGS, GR_REGS, GR_REGS
210 /* MicroBlaze specific machine attributes.
211 interrupt_handler - Interrupt handler attribute to add interrupt prologue
212 and epilogue and use appropriate interrupt return.
213 save_volatiles - Similar to interrupt handler, but use normal return. */
214 int interrupt_handler;
215 int break_handler;
216 int fast_interrupt;
217 int save_volatiles;
219 const struct attribute_spec microblaze_attribute_table[] = {
220 /* name min_len, max_len, decl_req, type_req, fn_type_req,
221 affects_type_identity, handler, exclude */
222 {"interrupt_handler", 0, 0, true, false, false, false, NULL, NULL },
223 {"break_handler", 0, 0, true, false, false, false, NULL, NULL },
224 {"fast_interrupt", 0, 0, true, false, false, false, NULL, NULL },
225 {"save_volatiles", 0, 0, true, false, false, false, NULL, NULL },
226 { NULL, 0, 0, false, false, false, false, NULL, NULL }
229 static int microblaze_interrupt_function_p (tree);
231 static void microblaze_elf_asm_constructor (rtx, int) ATTRIBUTE_UNUSED;
232 static void microblaze_elf_asm_destructor (rtx, int) ATTRIBUTE_UNUSED;
234 section *sdata2_section;
236 #ifdef HAVE_AS_TLS
237 #undef TARGET_HAVE_TLS
238 #define TARGET_HAVE_TLS true
239 #endif
241 /* Return truth value if a CONST_DOUBLE is ok to be a legitimate constant. */
242 static bool
243 microblaze_const_double_ok (rtx op, machine_mode mode)
245 REAL_VALUE_TYPE d;
247 if (GET_CODE (op) != CONST_DOUBLE)
248 return 0;
250 if (GET_MODE (op) == VOIDmode)
251 return 1;
253 if (mode != SFmode && mode != DFmode)
254 return 0;
256 if (op == CONST0_RTX (mode))
257 return 1;
259 d = *CONST_DOUBLE_REAL_VALUE (op);
261 if (REAL_VALUE_ISNAN (d))
262 return FALSE;
264 if (REAL_VALUE_NEGATIVE (d))
265 d = real_value_negate (&d);
267 if (mode == DFmode)
269 if (real_less (&d, &dfhigh) && real_less (&dflow, &d))
270 return 1;
272 else
274 if (real_less (&d, &sfhigh) && real_less (&sflow, &d))
275 return 1;
278 return 0;
281 /* Return truth value if a memory operand fits in a single instruction
282 (ie, register + small offset) or (register + register). */
285 simple_memory_operand (rtx op, machine_mode mode ATTRIBUTE_UNUSED)
287 rtx addr, plus0, plus1;
289 /* Eliminate non-memory operations. */
290 if (GET_CODE (op) != MEM)
291 return 0;
293 /* dword operations really put out 2 instructions, so eliminate them. */
294 /* ??? This isn't strictly correct. It is OK to accept multiword modes
295 here, since the length attributes are being set correctly, but only
296 if the address is offsettable. */
297 if (GET_MODE_SIZE (GET_MODE (op)) > UNITS_PER_WORD)
298 return 0;
301 /* Decode the address now. */
302 addr = XEXP (op, 0);
303 switch (GET_CODE (addr))
306 case REG:
307 return 1;
309 case PLUS:
310 plus0 = XEXP (addr, 0);
311 plus1 = XEXP (addr, 1);
313 if (GET_CODE (plus0) != REG)
314 return 0;
316 if (GET_CODE (plus0) == REG && GET_CODE (plus1) == CONST_INT
317 && SMALL_INT (plus1))
319 return 1;
321 else if (GET_CODE (plus1) == REG && GET_CODE (plus0) == CONST_INT)
323 return 1;
325 else if (GET_CODE (plus0) == REG && GET_CODE (plus1) == REG)
327 return 1;
329 else
330 return 0;
332 case SYMBOL_REF:
333 return 0;
335 default:
336 break;
339 return 0;
342 /* Return nonzero for a memory address that can be used to load or store
343 a doubleword. */
346 double_memory_operand (rtx op, machine_mode mode)
348 rtx addr;
350 if (GET_CODE (op) != MEM || !memory_operand (op, mode))
352 /* During reload, we accept a pseudo register if it has an
353 appropriate memory address. If we don't do this, we will
354 wind up reloading into a register, and then reloading that
355 register from memory, when we could just reload directly from
356 memory. */
357 if (reload_in_progress
358 && GET_CODE (op) == REG
359 && REGNO (op) >= FIRST_PSEUDO_REGISTER
360 && reg_renumber[REGNO (op)] < 0
361 && reg_equiv_mem (REGNO (op)) != 0
362 && double_memory_operand (reg_equiv_mem (REGNO (op)), mode))
363 return 1;
364 return 0;
367 /* Make sure that 4 added to the address is a valid memory address.
368 This essentially just checks for overflow in an added constant. */
370 addr = XEXP (op, 0);
372 if (CONSTANT_ADDRESS_P (addr))
373 return 1;
375 return memory_address_p ((GET_MODE_CLASS (mode) == MODE_INT
376 ? E_SImode : E_SFmode),
377 plus_constant (Pmode, addr, 4));
380 /* Implement REG_OK_FOR_BASE_P -and- REG_OK_FOR_INDEX_P. */
382 microblaze_regno_ok_for_base_p (int regno, int strict)
384 if (regno >= FIRST_PSEUDO_REGISTER)
386 if (!strict)
387 return true;
388 regno = reg_renumber[regno];
391 /* These fake registers will be eliminated to either the stack or
392 hard frame pointer, both of which are usually valid base registers.
393 Reload deals with the cases where the eliminated form isn't valid. */
394 if (regno == ARG_POINTER_REGNUM || regno == FRAME_POINTER_REGNUM)
395 return true;
397 return GP_REG_P (regno);
400 /* Return true if X is a valid base register for the given mode.
401 Allow only hard registers if STRICT. */
403 static bool
404 microblaze_valid_base_register_p (rtx x,
405 machine_mode mode ATTRIBUTE_UNUSED,
406 int strict)
408 if (!strict && GET_CODE (x) == SUBREG)
409 x = SUBREG_REG (x);
411 return (GET_CODE (x) == REG
412 && microblaze_regno_ok_for_base_p (REGNO (x), strict));
415 /* Build the SYMBOL_REF for __tls_get_addr. */
417 static GTY(()) rtx tls_get_addr_libfunc;
419 static rtx
420 get_tls_get_addr (void)
422 if (!tls_get_addr_libfunc)
423 tls_get_addr_libfunc = init_one_libfunc ("__tls_get_addr");
424 return tls_get_addr_libfunc;
427 /* Return TRUE if X is a thread-local symbol. */
428 bool
429 microblaze_tls_symbol_p (rtx x)
431 if (!TARGET_HAVE_TLS)
432 return false;
434 if (GET_CODE (x) != SYMBOL_REF)
435 return false;
437 return SYMBOL_REF_TLS_MODEL (x) != 0;
440 /* Return TRUE if X contains any TLS symbol references. */
442 bool
443 microblaze_tls_referenced_p (rtx x)
445 if (!TARGET_HAVE_TLS)
446 return false;
447 subrtx_iterator::array_type array;
448 FOR_EACH_SUBRTX (iter, array, x, ALL)
450 const_rtx x = *iter;
451 if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (x) != 0)
452 return true;
453 /* Don't recurse into UNSPEC_TLS looking for TLS symbols; these are
454 TLS offsets, not real symbol references. */
455 if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLS)
456 iter.skip_subrtxes ();
458 return false;
461 bool
462 microblaze_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED, rtx x)
464 return microblaze_tls_referenced_p(x);
467 /* Return TRUE if X references a SYMBOL_REF. */
469 symbol_mentioned_p (rtx x)
471 const char * fmt;
472 int i;
474 if (GET_CODE (x) == SYMBOL_REF)
475 return 1;
477 /* UNSPEC entries for a symbol include the SYMBOL_REF, but they
478 are constant offsets, not symbols. */
479 if (GET_CODE (x) == UNSPEC)
480 return 0;
482 fmt = GET_RTX_FORMAT (GET_CODE (x));
484 for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
486 if (fmt[i] == 'E')
488 int j;
490 for (j = XVECLEN (x, i) - 1; j >= 0; j--)
491 if (symbol_mentioned_p (XVECEXP (x, i, j)))
492 return 1;
494 else if (fmt[i] == 'e' && symbol_mentioned_p (XEXP (x, i)))
495 return 1;
498 return 0;
501 /* Return TRUE if X references a LABEL_REF. */
503 label_mentioned_p (rtx x)
505 const char * fmt;
506 int i;
508 if (GET_CODE (x) == LABEL_REF)
509 return 1;
511 /* UNSPEC entries for a symbol include a LABEL_REF for the referencing
512 instruction, but they are constant offsets, not symbols. */
513 if (GET_CODE (x) == UNSPEC)
514 return 0;
516 fmt = GET_RTX_FORMAT (GET_CODE (x));
517 for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
519 if (fmt[i] == 'E')
521 int j;
523 for (j = XVECLEN (x, i) - 1; j >= 0; j--)
524 if (label_mentioned_p (XVECEXP (x, i, j)))
525 return 1;
527 else if (fmt[i] == 'e' && label_mentioned_p (XEXP (x, i)))
528 return 1;
531 return 0;
535 tls_mentioned_p (rtx x)
537 switch (GET_CODE (x))
539 case CONST:
540 return tls_mentioned_p (XEXP (x, 0));
542 case UNSPEC:
543 if (XINT (x, 1) == UNSPEC_TLS)
544 return 1;
545 return 0;
547 default:
548 return 0;
552 static rtx
553 load_tls_operand (rtx x, rtx reg)
555 rtx tmp;
557 if (reg == NULL_RTX)
558 reg = gen_reg_rtx (Pmode);
560 tmp = gen_rtx_CONST (Pmode, x);
562 emit_insn (gen_rtx_SET (reg,
563 gen_rtx_PLUS (Pmode, pic_offset_table_rtx, tmp)));
565 return reg;
568 static rtx_insn *
569 microblaze_call_tls_get_addr (rtx x, rtx reg, rtx *valuep, int reloc)
571 rtx_insn *insns;
572 rtx tls_entry;
574 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
576 start_sequence ();
578 tls_entry = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, x, GEN_INT (reloc)),
579 UNSPEC_TLS);
581 reg = load_tls_operand (tls_entry, reg);
583 *valuep = emit_library_call_value (get_tls_get_addr (), NULL_RTX,
584 LCT_PURE, /* LCT_CONST? */
585 Pmode, reg, Pmode);
587 insns = get_insns ();
588 end_sequence ();
590 return insns;
594 microblaze_legitimize_tls_address(rtx x, rtx reg)
596 rtx dest, ret, eqv, addend;
597 rtx_insn *insns;
598 enum tls_model model;
599 model = SYMBOL_REF_TLS_MODEL (x);
601 switch (model)
603 case TLS_MODEL_LOCAL_DYNAMIC:
604 case TLS_MODEL_GLOBAL_DYNAMIC:
605 case TLS_MODEL_INITIAL_EXEC:
606 insns = microblaze_call_tls_get_addr (x, reg, &ret, TLS_GD);
607 dest = gen_reg_rtx (Pmode);
608 emit_libcall_block (insns, dest, ret, x);
609 break;
611 case TLS_MODEL_LOCAL_EXEC:
612 insns = microblaze_call_tls_get_addr (x, reg, &ret, TLS_LDM);
614 /* Attach a unique REG_EQUIV, to allow the RTL optimizers to
615 share the LDM result with other LD model accesses. */
616 eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const1_rtx), UNSPEC_TLS);
617 dest = gen_reg_rtx (Pmode);
618 emit_libcall_block (insns, dest, ret, eqv);
620 /* Load the addend. */
621 addend = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, x, GEN_INT (TLS_DTPREL)),
622 UNSPEC_TLS);
623 addend = force_reg (SImode, gen_rtx_CONST (SImode, addend));
624 dest = gen_rtx_PLUS (Pmode, dest, addend);
625 break;
627 default:
628 gcc_unreachable ();
630 return dest;
633 static bool
634 microblaze_classify_unspec (struct microblaze_address_info *info, rtx x)
636 info->symbol_type = SYMBOL_TYPE_GENERAL;
637 info->symbol = XVECEXP (x, 0, 0);
639 if (XINT (x, 1) == UNSPEC_GOTOFF)
641 info->regA = gen_rtx_REG (SImode, PIC_OFFSET_TABLE_REGNUM);
642 info->type = ADDRESS_GOTOFF;
644 else if (XINT (x, 1) == UNSPEC_PLT)
646 info->type = ADDRESS_PLT;
648 else if (XINT (x, 1) == UNSPEC_TLS)
650 info->type = ADDRESS_TLS;
651 info->tls_type = tls_reloc (INTVAL (XVECEXP (x, 0, 1)));
653 else
655 return false;
657 return true;
661 /* Return true if X is a valid index register for the given mode.
662 Allow only hard registers if STRICT. */
664 static bool
665 microblaze_valid_index_register_p (rtx x,
666 machine_mode mode ATTRIBUTE_UNUSED,
667 int strict)
669 if (!strict && GET_CODE (x) == SUBREG)
670 x = SUBREG_REG (x);
672 return (GET_CODE (x) == REG
673 /* A base register is good enough to be an index register on MicroBlaze. */
674 && microblaze_regno_ok_for_base_p (REGNO (x), strict));
677 /* Get the base register for accessing a value from the memory or
678 Symbol ref. Used for MicroBlaze Small Data Area Pointer Optimization. */
679 static int
680 get_base_reg (rtx x)
682 tree decl;
683 int base_reg;
685 if (!flag_pic || microblaze_tls_symbol_p(x))
686 base_reg = MB_ABI_BASE_REGNUM;
687 else if (flag_pic)
688 base_reg = MB_ABI_PIC_ADDR_REGNUM;
690 if (TARGET_XLGPOPT
691 && GET_CODE (x) == SYMBOL_REF
692 && SYMBOL_REF_SMALL_P (x) && (decl = SYMBOL_REF_DECL (x)) != NULL)
694 if (TREE_READONLY (decl))
695 base_reg = MB_ABI_GPRO_REGNUM;
696 else
697 base_reg = MB_ABI_GPRW_REGNUM;
700 return base_reg;
703 /* Return true if X is a valid address for machine mode MODE. If it is,
704 fill in INFO appropriately. STRICT is true if we should only accept
705 hard base registers.
707 type regA regB offset symbol
709 ADDRESS_INVALID NULL NULL NULL NULL
711 ADDRESS_REG %0 NULL const_0 / NULL
712 const_int
713 ADDRESS_REG_INDEX %0 %1 NULL NULL
715 ADDRESS_SYMBOLIC r0 / NULL NULL symbol
716 sda_base_reg
718 ADDRESS_CONST_INT r0 NULL const NULL
720 For modes spanning multiple registers (DFmode in 32-bit GPRs,
721 DImode, TImode), indexed addressing cannot be used because
722 adjacent memory cells are accessed by adding word-sized offsets
723 during assembly output. */
725 static bool
726 microblaze_classify_address (struct microblaze_address_info *info, rtx x,
727 machine_mode mode, int strict)
729 rtx xplus0;
730 rtx xplus1;
732 info->type = ADDRESS_INVALID;
733 info->regA = NULL;
734 info->regB = NULL;
735 info->offset = NULL;
736 info->symbol = NULL;
737 info->symbol_type = SYMBOL_TYPE_INVALID;
739 switch (GET_CODE (x))
741 case REG:
742 case SUBREG:
744 info->type = ADDRESS_REG;
745 info->regA = x;
746 info->offset = const0_rtx;
747 return microblaze_valid_base_register_p (info->regA, mode, strict);
749 case PLUS:
751 xplus0 = XEXP (x, 0);
752 xplus1 = XEXP (x, 1);
754 if (microblaze_valid_base_register_p (xplus0, mode, strict))
756 info->type = ADDRESS_REG;
757 info->regA = xplus0;
759 if (GET_CODE (xplus1) == CONST_INT)
761 info->offset = xplus1;
762 return true;
764 else if (GET_CODE (xplus1) == UNSPEC)
766 /* Need offsettable address. */
767 if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
768 return false;
770 return microblaze_classify_unspec (info, xplus1);
772 else if ((GET_CODE (xplus1) == SYMBOL_REF ||
773 GET_CODE (xplus1) == LABEL_REF))
775 if (flag_pic == 2 || microblaze_tls_symbol_p(xplus1))
776 return false;
777 info->type = ADDRESS_SYMBOLIC;
778 info->symbol = xplus1;
779 info->symbol_type = SYMBOL_TYPE_GENERAL;
780 return true;
782 else if (GET_CODE (xplus1) == CONST)
784 rtx xconst0 = XEXP(xplus1, 0);
786 /* base + unspec. */
787 if (GET_CODE (xconst0) == UNSPEC)
789 /* Need offsettable address. */
790 if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
791 return false;
792 return microblaze_classify_unspec(info, xconst0);
795 /* for (plus x const_int) just look at x. */
796 if (GET_CODE (xconst0) == PLUS
797 && GET_CODE (XEXP (xconst0, 1)) == CONST_INT
798 && SMALL_INT (XEXP (xconst0, 1)))
800 /* This is ok as info->symbol is set to xplus1 the full
801 const-expression below. */
802 xconst0 = XEXP (xconst0, 0);
805 if (GET_CODE (xconst0) == SYMBOL_REF
806 || GET_CODE (xconst0) == LABEL_REF)
808 if (flag_pic == 2 || microblaze_tls_symbol_p(xconst0))
809 return false;
811 info->type = ADDRESS_SYMBOLIC;
812 info->symbol = xplus1;
813 info->symbol_type = SYMBOL_TYPE_GENERAL;
814 return true;
817 /* Not base + symbol || base + UNSPEC. */
818 return false;
821 else if (GET_CODE (xplus1) == REG
822 && microblaze_valid_index_register_p (xplus1, mode,
823 strict)
824 && (GET_MODE_SIZE (mode) <= UNITS_PER_WORD))
826 /* Restrict larger than word-width modes from using an index register. */
827 info->type = ADDRESS_REG_INDEX;
828 info->regB = xplus1;
829 return true;
832 break;
834 case CONST_INT:
836 info->regA = gen_raw_REG (mode, 0);
837 info->type = ADDRESS_CONST_INT;
838 info->offset = x;
839 return true;
841 case CONST:
842 case LABEL_REF:
843 case SYMBOL_REF:
845 info->type = ADDRESS_SYMBOLIC;
846 info->symbol_type = SYMBOL_TYPE_GENERAL;
847 info->symbol = x;
848 info->regA = gen_raw_REG (mode, get_base_reg (x));
850 if (GET_CODE (x) == CONST)
852 if (GET_CODE (XEXP (x, 0)) == UNSPEC)
854 info->regA = gen_raw_REG (mode,
855 get_base_reg (XVECEXP (XEXP (x,0), 0, 0)));
856 return microblaze_classify_unspec (info, XEXP (x, 0));
858 return !(flag_pic && pic_address_needs_scratch (x));
861 if (flag_pic == 2)
862 return false;
863 else if (microblaze_tls_symbol_p(x))
864 return false;
866 return true;
869 case UNSPEC:
871 if (reload_in_progress)
872 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
873 return microblaze_classify_unspec (info, x);
876 default:
877 return false;
880 return false;
883 /* This function is used to implement GO_IF_LEGITIMATE_ADDRESS. It
884 returns a nonzero value if X is a legitimate address for a memory
885 operand of the indicated MODE. STRICT is nonzero if this function
886 is called during reload. */
888 bool
889 microblaze_legitimate_address_p (machine_mode mode, rtx x, bool strict)
891 struct microblaze_address_info addr;
893 return microblaze_classify_address (&addr, x, mode, strict);
897 microblaze_valid_pic_const (rtx x)
899 switch (GET_CODE (x))
901 case CONST:
902 case CONST_INT:
903 case CONST_DOUBLE:
904 return true;
905 default:
906 return false;
911 microblaze_legitimate_pic_operand (rtx x)
913 if (flag_pic == 2 && (symbol_mentioned_p(x) || label_mentioned_p(x)))
914 return 0;
916 if (microblaze_tls_referenced_p(x))
917 return 0;
919 return 1;
922 /* Try machine-dependent ways of modifying an illegitimate address
923 to be legitimate. If we find one, return the new, valid address.
924 This is used from only one place: `memory_address' in explow.c.
926 OLDX is the address as it was before break_out_memory_refs was
927 called. In some cases it is useful to look at this to decide what
928 needs to be done.
930 It is always safe for this function to do nothing. It exists to
931 recognize opportunities to optimize the output.
933 For the MicroBlaze, transform:
935 memory(X + <large int>)
937 into:
939 Y = <large int> & ~0x7fff;
940 Z = X + Y
941 memory (Z + (<large int> & 0x7fff));
943 This is for CSE to find several similar references, and only use one Z.
945 When PIC, convert addresses of the form memory (symbol+large int) to
946 memory (reg+large int). */
948 static rtx
949 microblaze_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
950 machine_mode mode ATTRIBUTE_UNUSED)
952 register rtx xinsn = x, result;
954 if (GET_CODE (xinsn) == CONST
955 && flag_pic && pic_address_needs_scratch (xinsn))
957 rtx ptr_reg = gen_reg_rtx (Pmode);
958 rtx constant = XEXP (XEXP (xinsn, 0), 1);
960 emit_move_insn (ptr_reg, XEXP (XEXP (xinsn, 0), 0));
962 result = gen_rtx_PLUS (Pmode, ptr_reg, constant);
963 if (SMALL_INT (constant))
964 return result;
965 /* Otherwise we fall through so the code below will fix the
966 constant. */
967 xinsn = result;
970 if (GET_CODE (xinsn) == PLUS)
972 register rtx xplus0 = XEXP (xinsn, 0);
973 register rtx xplus1 = XEXP (xinsn, 1);
974 register enum rtx_code code0 = GET_CODE (xplus0);
975 register enum rtx_code code1 = GET_CODE (xplus1);
977 if (code0 != REG && code1 == REG)
979 xplus0 = XEXP (xinsn, 1);
980 xplus1 = XEXP (xinsn, 0);
981 code0 = GET_CODE (xplus0);
982 code1 = GET_CODE (xplus1);
985 if (code0 == REG && REG_OK_FOR_BASE_P (xplus0)
986 && code1 == CONST_INT && !SMALL_INT (xplus1))
988 rtx int_reg = gen_reg_rtx (Pmode);
989 rtx ptr_reg = gen_reg_rtx (Pmode);
991 emit_move_insn (int_reg, GEN_INT (INTVAL (xplus1) & ~0x7fff));
993 emit_insn (gen_rtx_SET (ptr_reg,
994 gen_rtx_PLUS (Pmode, xplus0, int_reg)));
996 result = gen_rtx_PLUS (Pmode, ptr_reg,
997 GEN_INT (INTVAL (xplus1) & 0x7fff));
998 return result;
1001 if (code0 == REG && REG_OK_FOR_BASE_P (xplus0))
1003 if (reload_in_progress)
1004 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
1005 if (code1 == CONST)
1007 xplus1 = XEXP (xplus1, 0);
1008 code1 = GET_CODE (xplus1);
1010 if (code1 == SYMBOL_REF)
1012 if (microblaze_tls_symbol_p(xplus1))
1014 rtx tls_ref, reg;
1015 reg = gen_reg_rtx (Pmode);
1017 tls_ref = microblaze_legitimize_tls_address (xplus1,
1018 NULL_RTX);
1019 emit_move_insn (reg, tls_ref);
1021 result = gen_rtx_PLUS (Pmode, xplus0, reg);
1023 return result;
1025 else if (flag_pic == 2)
1027 rtx pic_ref, reg;
1028 reg = gen_reg_rtx (Pmode);
1030 pic_ref = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, xplus1),
1031 UNSPEC_GOTOFF);
1032 pic_ref = gen_rtx_CONST (Pmode, pic_ref);
1033 pic_ref = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, pic_ref);
1034 pic_ref = gen_const_mem (Pmode, pic_ref);
1035 emit_move_insn (reg, pic_ref);
1036 result = gen_rtx_PLUS (Pmode, xplus0, reg);
1037 return result;
1043 if (GET_CODE (xinsn) == SYMBOL_REF)
1045 rtx reg;
1046 if (microblaze_tls_symbol_p(xinsn))
1048 reg = microblaze_legitimize_tls_address (xinsn, NULL_RTX);
1050 else
1052 rtx pic_ref;
1054 if (reload_in_progress)
1055 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
1057 pic_ref = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, xinsn), UNSPEC_GOTOFF);
1058 pic_ref = gen_rtx_CONST (Pmode, pic_ref);
1059 pic_ref = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, pic_ref);
1060 pic_ref = gen_const_mem (Pmode, pic_ref);
1061 reg = pic_ref;
1063 return reg;
1066 return x;
1069 /* Block Moves. */
1071 #define MAX_MOVE_REGS 8
1072 #define MAX_MOVE_BYTES (MAX_MOVE_REGS * UNITS_PER_WORD)
1074 /* Emit straight-line code to move LENGTH bytes from SRC to DEST.
1075 Assume that the areas do not overlap. */
1077 static void
1078 microblaze_block_move_straight (rtx dest, rtx src, HOST_WIDE_INT length)
1080 HOST_WIDE_INT offset, delta;
1081 unsigned HOST_WIDE_INT bits;
1082 int i;
1083 machine_mode mode;
1084 rtx *regs;
1086 bits = BITS_PER_WORD;
1087 mode = int_mode_for_size (bits, 0).require ();
1088 delta = bits / BITS_PER_UNIT;
1090 /* Allocate a buffer for the temporary registers. */
1091 regs = XALLOCAVEC (rtx, length / delta);
1093 /* Load as many BITS-sized chunks as possible. Use a normal load if
1094 the source has enough alignment, otherwise use left/right pairs. */
1095 for (offset = 0, i = 0; offset + delta <= length; offset += delta, i++)
1097 regs[i] = gen_reg_rtx (mode);
1098 emit_move_insn (regs[i], adjust_address (src, mode, offset));
1101 /* Copy the chunks to the destination. */
1102 for (offset = 0, i = 0; offset + delta <= length; offset += delta, i++)
1103 emit_move_insn (adjust_address (dest, mode, offset), regs[i]);
1105 /* Mop up any left-over bytes. */
1106 if (offset < length)
1108 src = adjust_address (src, BLKmode, offset);
1109 dest = adjust_address (dest, BLKmode, offset);
1110 move_by_pieces (dest, src, length - offset,
1111 MIN (MEM_ALIGN (src), MEM_ALIGN (dest)), 0);
1115 /* Helper function for doing a loop-based block operation on memory
1116 reference MEM. Each iteration of the loop will operate on LENGTH
1117 bytes of MEM.
1119 Create a new base register for use within the loop and point it to
1120 the start of MEM. Create a new memory reference that uses this
1121 register. Store them in *LOOP_REG and *LOOP_MEM respectively. */
1123 static void
1124 microblaze_adjust_block_mem (rtx mem, HOST_WIDE_INT length,
1125 rtx * loop_reg, rtx * loop_mem)
1127 *loop_reg = copy_addr_to_reg (XEXP (mem, 0));
1129 /* Although the new mem does not refer to a known location,
1130 it does keep up to LENGTH bytes of alignment. */
1131 *loop_mem = change_address (mem, BLKmode, *loop_reg);
1132 set_mem_align (*loop_mem,
1133 MIN ((HOST_WIDE_INT) MEM_ALIGN (mem),
1134 length * BITS_PER_UNIT));
1138 /* Move LENGTH bytes from SRC to DEST using a loop that moves MAX_MOVE_BYTES
1139 per iteration. LENGTH must be at least MAX_MOVE_BYTES. Assume that the
1140 memory regions do not overlap. */
1142 static void
1143 microblaze_block_move_loop (rtx dest, rtx src, HOST_WIDE_INT length)
1145 rtx_code_label *label;
1146 rtx src_reg, dest_reg, final_src;
1147 HOST_WIDE_INT leftover;
1149 leftover = length % MAX_MOVE_BYTES;
1150 length -= leftover;
1152 /* Create registers and memory references for use within the loop. */
1153 microblaze_adjust_block_mem (src, MAX_MOVE_BYTES, &src_reg, &src);
1154 microblaze_adjust_block_mem (dest, MAX_MOVE_BYTES, &dest_reg, &dest);
1156 /* Calculate the value that SRC_REG should have after the last iteration
1157 of the loop. */
1158 final_src = expand_simple_binop (Pmode, PLUS, src_reg, GEN_INT (length),
1159 0, 0, OPTAB_WIDEN);
1161 /* Emit the start of the loop. */
1162 label = gen_label_rtx ();
1163 emit_label (label);
1165 /* Emit the loop body. */
1166 microblaze_block_move_straight (dest, src, MAX_MOVE_BYTES);
1168 /* Move on to the next block. */
1169 emit_move_insn (src_reg, plus_constant (Pmode, src_reg, MAX_MOVE_BYTES));
1170 emit_move_insn (dest_reg, plus_constant (Pmode, dest_reg, MAX_MOVE_BYTES));
1172 /* Emit the test & branch. */
1173 emit_insn (gen_cbranchsi4 (gen_rtx_NE (SImode, src_reg, final_src),
1174 src_reg, final_src, label));
1176 /* Mop up any left-over bytes. */
1177 if (leftover)
1178 microblaze_block_move_straight (dest, src, leftover);
1181 /* Expand a movmemsi instruction. */
1183 bool
1184 microblaze_expand_block_move (rtx dest, rtx src, rtx length, rtx align_rtx)
1187 if (GET_CODE (length) == CONST_INT)
1189 HOST_WIDE_INT bytes = INTVAL (length);
1190 int align = INTVAL (align_rtx);
1192 if (align > UNITS_PER_WORD)
1194 align = UNITS_PER_WORD; /* We can't do any better. */
1196 else if (align < UNITS_PER_WORD)
1198 if (INTVAL (length) <= MAX_MOVE_BYTES)
1200 move_by_pieces (dest, src, bytes, align, 0);
1201 return true;
1203 else
1204 return false;
1207 if (INTVAL (length) <= 2 * MAX_MOVE_BYTES)
1209 microblaze_block_move_straight (dest, src, INTVAL (length));
1210 return true;
1212 else if (optimize)
1214 microblaze_block_move_loop (dest, src, INTVAL (length));
1215 return true;
1218 return false;
1221 static bool
1222 microblaze_rtx_costs (rtx x, machine_mode mode, int outer_code ATTRIBUTE_UNUSED,
1223 int opno ATTRIBUTE_UNUSED, int *total,
1224 bool speed ATTRIBUTE_UNUSED)
1226 int code = GET_CODE (x);
1228 switch (code)
1230 case MEM:
1232 int num_words = (GET_MODE_SIZE (mode) > UNITS_PER_WORD) ? 2 : 1;
1233 if (simple_memory_operand (x, mode))
1234 *total = COSTS_N_INSNS (2 * num_words);
1235 else
1236 *total = COSTS_N_INSNS (2 * (2 * num_words));
1238 return true;
1240 case NOT:
1242 if (mode == DImode)
1244 *total = COSTS_N_INSNS (2);
1246 else
1247 *total = COSTS_N_INSNS (1);
1248 return false;
1250 case AND:
1251 case IOR:
1252 case XOR:
1254 if (mode == DImode)
1256 *total = COSTS_N_INSNS (2);
1258 else
1259 *total = COSTS_N_INSNS (1);
1261 return false;
1263 case ASHIFT:
1264 case ASHIFTRT:
1265 case LSHIFTRT:
1267 if (TARGET_BARREL_SHIFT)
1269 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v5.00.a")
1270 >= 0)
1271 *total = COSTS_N_INSNS (1);
1272 else
1273 *total = COSTS_N_INSNS (2);
1275 else if (!TARGET_SOFT_MUL)
1276 *total = COSTS_N_INSNS (1);
1277 else if (GET_CODE (XEXP (x, 1)) == CONST_INT)
1279 /* Add 1 to make shift slightly more expensive than add. */
1280 *total = COSTS_N_INSNS (INTVAL (XEXP (x, 1))) + 1;
1281 /* Reduce shift costs for special circumstances. */
1282 if (optimize_size && INTVAL (XEXP (x, 1)) > 5)
1283 *total -= 2;
1284 if (!optimize_size && INTVAL (XEXP (x, 1)) > 17)
1285 *total -= 2;
1287 else
1288 /* Double the worst cost of shifts when there is no barrel shifter and
1289 the shift amount is in a reg. */
1290 *total = COSTS_N_INSNS (32 * 4);
1291 return true;
1293 case PLUS:
1294 case MINUS:
1296 if (mode == SFmode || mode == DFmode)
1298 if (TARGET_HARD_FLOAT)
1299 *total = COSTS_N_INSNS (6);
1300 return true;
1302 else if (mode == DImode)
1304 *total = COSTS_N_INSNS (4);
1305 return true;
1307 else
1309 *total = COSTS_N_INSNS (1);
1310 return true;
1313 return false;
1315 case NEG:
1317 if (mode == DImode)
1318 *total = COSTS_N_INSNS (4);
1320 return false;
1322 case MULT:
1324 if (mode == SFmode)
1326 if (TARGET_HARD_FLOAT)
1327 *total = COSTS_N_INSNS (6);
1329 else if (!TARGET_SOFT_MUL)
1331 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v5.00.a")
1332 >= 0)
1333 *total = COSTS_N_INSNS (1);
1334 else
1335 *total = COSTS_N_INSNS (3);
1337 else
1338 *total = COSTS_N_INSNS (10);
1339 return true;
1341 case DIV:
1342 case UDIV:
1344 if (mode == SFmode)
1346 if (TARGET_HARD_FLOAT)
1347 *total = COSTS_N_INSNS (23);
1349 return false;
1351 case SIGN_EXTEND:
1353 *total = COSTS_N_INSNS (1);
1354 return false;
1356 case ZERO_EXTEND:
1358 *total = COSTS_N_INSNS (1);
1359 return false;
1363 return false;
1366 /* Return the number of instructions needed to load or store a value
1367 of mode MODE at X. Return 0 if X isn't valid for MODE. */
1369 static int
1370 microblaze_address_insns (rtx x, machine_mode mode)
1372 struct microblaze_address_info addr;
1374 if (microblaze_classify_address (&addr, x, mode, false))
1376 switch (addr.type)
1378 case ADDRESS_REG:
1379 if (SMALL_INT (addr.offset))
1380 return 1;
1381 else
1382 return 2;
1383 case ADDRESS_CONST_INT:
1384 if (SMALL_INT (x))
1385 return 1;
1386 else
1387 return 2;
1388 case ADDRESS_REG_INDEX:
1389 return 1;
1390 case ADDRESS_SYMBOLIC:
1391 case ADDRESS_GOTOFF:
1392 return 2;
1393 case ADDRESS_TLS:
1394 switch (addr.tls_type)
1396 case TLS_GD:
1397 return 2;
1398 case TLS_LDM:
1399 return 2;
1400 case TLS_DTPREL:
1401 return 1;
1402 default :
1403 abort();
1405 default:
1406 break;
1409 return 0;
1412 /* Provide the costs of an addressing mode that contains ADDR.
1413 If ADDR is not a valid address, its cost is irrelevant. */
1414 static int
1415 microblaze_address_cost (rtx addr, machine_mode mode ATTRIBUTE_UNUSED,
1416 addr_space_t as ATTRIBUTE_UNUSED,
1417 bool speed ATTRIBUTE_UNUSED)
1419 return COSTS_N_INSNS (microblaze_address_insns (addr, GET_MODE (addr)));
1422 /* Return nonzero if X is an address which needs a temporary register when
1423 reloaded while generating PIC code. */
1426 pic_address_needs_scratch (rtx x)
1428 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x,0)) == PLUS)
1430 rtx p0, p1;
1432 p0 = XEXP (XEXP (x, 0), 0);
1433 p1 = XEXP (XEXP (x, 0), 1);
1435 if ((GET_CODE (p0) == SYMBOL_REF || GET_CODE (p0) == LABEL_REF)
1436 && (GET_CODE (p1) == CONST_INT)
1437 && (flag_pic == 2 || microblaze_tls_symbol_p (p0) || !SMALL_INT (p1)))
1438 return 1;
1440 return 0;
1443 /* Argument support functions. */
1444 /* Initialize CUMULATIVE_ARGS for a function. */
1446 void
1447 init_cumulative_args (CUMULATIVE_ARGS * cum, tree fntype,
1448 rtx libname ATTRIBUTE_UNUSED)
1450 static CUMULATIVE_ARGS zero_cum;
1451 tree param, next_param;
1453 *cum = zero_cum;
1455 /* Determine if this function has variable arguments. This is
1456 indicated by the last argument being 'void_type_mode' if there
1457 are no variable arguments. The standard MicroBlaze calling sequence
1458 passes all arguments in the general purpose registers in this case. */
1460 for (param = fntype ? TYPE_ARG_TYPES (fntype) : 0;
1461 param != 0; param = next_param)
1463 next_param = TREE_CHAIN (param);
1464 if (next_param == 0 && TREE_VALUE (param) != void_type_node)
1465 cum->gp_reg_found = 1;
1469 /* Advance the argument to the next argument position. */
1471 static void
1472 microblaze_function_arg_advance (cumulative_args_t cum_v,
1473 machine_mode mode,
1474 const_tree type, bool named ATTRIBUTE_UNUSED)
1476 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
1478 cum->arg_number++;
1479 switch (mode)
1481 case E_VOIDmode:
1482 break;
1484 default:
1485 gcc_assert (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
1486 || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT);
1488 cum->gp_reg_found = 1;
1489 cum->arg_words += ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1)
1490 / UNITS_PER_WORD);
1491 break;
1493 case E_BLKmode:
1494 cum->gp_reg_found = 1;
1495 cum->arg_words += ((int_size_in_bytes (type) + UNITS_PER_WORD - 1)
1496 / UNITS_PER_WORD);
1497 break;
1499 case E_SFmode:
1500 cum->arg_words++;
1501 if (!cum->gp_reg_found && cum->arg_number <= 2)
1502 cum->fp_code += 1 << ((cum->arg_number - 1) * 2);
1503 break;
1505 case E_DFmode:
1506 cum->arg_words += 2;
1507 if (!cum->gp_reg_found && cum->arg_number <= 2)
1508 cum->fp_code += 2 << ((cum->arg_number - 1) * 2);
1509 break;
1511 case E_DImode:
1512 cum->gp_reg_found = 1;
1513 cum->arg_words += 2;
1514 break;
1516 case E_QImode:
1517 case E_HImode:
1518 case E_SImode:
1519 case E_TImode:
1520 cum->gp_reg_found = 1;
1521 cum->arg_words++;
1522 break;
1526 /* Return an RTL expression containing the register for the given mode,
1527 or 0 if the argument is to be passed on the stack. */
1529 static rtx
1530 microblaze_function_arg (cumulative_args_t cum_v, machine_mode mode,
1531 const_tree type ATTRIBUTE_UNUSED,
1532 bool named ATTRIBUTE_UNUSED)
1534 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
1536 rtx ret;
1537 int regbase = -1;
1538 int *arg_words = &cum->arg_words;
1540 cum->last_arg_fp = 0;
1541 switch (mode)
1543 case E_SFmode:
1544 case E_DFmode:
1545 case E_VOIDmode:
1546 case E_QImode:
1547 case E_HImode:
1548 case E_SImode:
1549 case E_DImode:
1550 case E_TImode:
1551 regbase = GP_ARG_FIRST;
1552 break;
1553 default:
1554 gcc_assert (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
1555 || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT);
1556 /* FALLTHRU */
1557 case E_BLKmode:
1558 regbase = GP_ARG_FIRST;
1559 break;
1562 if (*arg_words >= MAX_ARGS_IN_REGISTERS)
1563 ret = 0;
1564 else
1566 gcc_assert (regbase != -1);
1568 ret = gen_rtx_REG (mode, regbase + *arg_words);
1571 if (mode == VOIDmode)
1573 if (cum->num_adjusts > 0)
1574 ret = gen_rtx_PARALLEL ((machine_mode) cum->fp_code,
1575 gen_rtvec_v (cum->num_adjusts, cum->adjust));
1578 return ret;
1581 /* Return number of bytes of argument to put in registers. */
1582 static int
1583 function_arg_partial_bytes (cumulative_args_t cum_v, machine_mode mode,
1584 tree type, bool named ATTRIBUTE_UNUSED)
1586 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
1588 if ((mode == BLKmode
1589 || GET_MODE_CLASS (mode) != MODE_COMPLEX_INT
1590 || GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT)
1591 && cum->arg_words < MAX_ARGS_IN_REGISTERS)
1593 int words;
1594 if (mode == BLKmode)
1595 words = ((int_size_in_bytes (type) + UNITS_PER_WORD - 1)
1596 / UNITS_PER_WORD);
1597 else
1598 words = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
1600 if (words + cum->arg_words <= MAX_ARGS_IN_REGISTERS)
1601 return 0; /* structure fits in registers */
1603 return (MAX_ARGS_IN_REGISTERS - cum->arg_words) * UNITS_PER_WORD;
1606 else if (mode == DImode && cum->arg_words == MAX_ARGS_IN_REGISTERS - 1)
1607 return UNITS_PER_WORD;
1609 return 0;
1612 /* Convert a version number of the form "vX.YY.Z" to an integer encoding
1613 for easier range comparison. */
1614 static int
1615 microblaze_version_to_int (const char *version)
1617 const char *p, *v;
1618 const char *tmpl = "vXX.YY.Z";
1619 int iver = 0;
1621 p = version;
1622 v = tmpl;
1624 while (*p)
1626 if (*v == 'X')
1627 { /* Looking for major */
1628 if (*p == '.')
1630 v++;
1632 else
1634 if (!(*p >= '0' && *p <= '9'))
1635 return -1;
1636 iver += (int) (*p - '0');
1637 iver *= 10;
1640 else if (*v == 'Y')
1641 { /* Looking for minor */
1642 if (!(*p >= '0' && *p <= '9'))
1643 return -1;
1644 iver += (int) (*p - '0');
1645 iver *= 10;
1647 else if (*v == 'Z')
1648 { /* Looking for compat */
1649 if (!(*p >= 'a' && *p <= 'z'))
1650 return -1;
1651 iver *= 10;
1652 iver += (int) (*p - 'a');
1654 else
1656 if (*p != *v)
1657 return -1;
1660 v++;
1661 p++;
1664 if (*p)
1665 return -1;
1667 return iver;
1671 static void
1672 microblaze_option_override (void)
1674 register int i, start;
1675 register int regno;
1676 register machine_mode mode;
1677 int ver;
1679 microblaze_section_threshold = (global_options_set.x_g_switch_value
1680 ? g_switch_value
1681 : MICROBLAZE_DEFAULT_GVALUE);
1683 if (flag_pic)
1685 /* Make sure it's 2, we only support one kind of PIC. */
1686 flag_pic = 2;
1687 if (!TARGET_SUPPORTS_PIC)
1689 error ("-fPIC/-fpic not supported for this target");
1690 /* Clear it to avoid further errors. */
1691 flag_pic = 0;
1695 /* Check the MicroBlaze CPU version for any special action to be done. */
1696 if (microblaze_select_cpu == NULL)
1697 microblaze_select_cpu = MICROBLAZE_DEFAULT_CPU;
1698 ver = microblaze_version_to_int (microblaze_select_cpu);
1699 if (ver == -1)
1701 error ("%qs is an invalid argument to -mcpu=", microblaze_select_cpu);
1704 ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v3.00.a");
1705 if (ver < 0)
1707 /* No hardware exceptions in earlier versions. So no worries. */
1708 #if 0
1709 microblaze_select_flags &= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY);
1710 #endif
1711 microblaze_no_unsafe_delay = 0;
1712 microblaze_pipe = MICROBLAZE_PIPE_3;
1714 else if (ver == 0
1715 || (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v4.00.b")
1716 == 0))
1718 #if 0
1719 microblaze_select_flags |= (MICROBLAZE_MASK_NO_UNSAFE_DELAY);
1720 #endif
1721 microblaze_no_unsafe_delay = 1;
1722 microblaze_pipe = MICROBLAZE_PIPE_3;
1724 else
1726 /* We agree to use 5 pipe-stage model even on area optimized 3
1727 pipe-stage variants. */
1728 #if 0
1729 microblaze_select_flags &= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY);
1730 #endif
1731 microblaze_no_unsafe_delay = 0;
1732 microblaze_pipe = MICROBLAZE_PIPE_5;
1733 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v5.00.a") == 0
1734 || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu,
1735 "v5.00.b") == 0
1736 || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu,
1737 "v5.00.c") == 0)
1739 /* Pattern compares are to be turned on by default only when
1740 compiling for MB v5.00.'z'. */
1741 target_flags |= MASK_PATTERN_COMPARE;
1745 ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v6.00.a");
1746 if (ver < 0)
1748 if (TARGET_MULTIPLY_HIGH)
1749 warning (0,
1750 "-mxl-multiply-high can be used only with -mcpu=v6.00.a or greater");
1753 ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v8.10.a");
1754 microblaze_has_clz = 1;
1755 if (ver < 0)
1757 /* MicroBlaze prior to 8.10.a didn't have clz. */
1758 microblaze_has_clz = 0;
1761 /* TARGET_REORDER defaults to 2 if -mxl-reorder not specified. */
1762 ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v8.30.a");
1763 if (ver < 0)
1765 if (TARGET_REORDER == 1)
1766 warning (0, "-mxl-reorder can be used only with -mcpu=v8.30.a or greater");
1767 TARGET_REORDER = 0;
1769 else if ((ver == 0) && !TARGET_PATTERN_COMPARE)
1771 if (TARGET_REORDER == 1)
1772 warning (0, "-mxl-reorder requires -mxl-pattern-compare for -mcpu=v8.30.a");
1773 TARGET_REORDER = 0;
1776 if (TARGET_MULTIPLY_HIGH && TARGET_SOFT_MUL)
1777 error ("-mxl-multiply-high requires -mno-xl-soft-mul");
1779 /* Always use DFA scheduler. */
1780 microblaze_sched_use_dfa = 1;
1782 #if 0
1783 microblaze_abicalls = MICROBLAZE_ABICALLS_NO;
1784 #endif
1786 /* Initialize the high, low values for legit floating point constants. */
1787 real_maxval (&dfhigh, 0, DFmode);
1788 real_maxval (&dflow, 1, DFmode);
1789 real_maxval (&sfhigh, 0, SFmode);
1790 real_maxval (&sflow, 1, SFmode);
1792 microblaze_print_operand_punct['?'] = 1;
1793 microblaze_print_operand_punct['#'] = 1;
1794 microblaze_print_operand_punct['&'] = 1;
1795 microblaze_print_operand_punct['!'] = 1;
1796 microblaze_print_operand_punct['*'] = 1;
1797 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;
1811 /* Set up array to map GCC register number to debug register number.
1812 Ignore the special purpose register numbers. */
1814 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
1815 microblaze_dbx_regno[i] = -1;
1817 start = GP_DBX_FIRST - GP_REG_FIRST;
1818 for (i = GP_REG_FIRST; i <= GP_REG_LAST; i++)
1819 microblaze_dbx_regno[i] = i + start;
1821 /* Set up array giving whether a given register can hold a given mode. */
1823 for (mode = VOIDmode;
1824 mode != MAX_MACHINE_MODE; mode = (machine_mode) ((int) mode + 1))
1826 register int size = GET_MODE_SIZE (mode);
1828 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
1830 register int ok;
1832 if (mode == CCmode)
1834 ok = (ST_REG_P (regno) || GP_REG_P (regno));
1836 else if (GP_REG_P (regno))
1837 ok = ((regno & 1) == 0 || size <= UNITS_PER_WORD);
1838 else
1839 ok = 0;
1841 microblaze_hard_regno_mode_ok_p[(int) mode][regno] = ok;
1846 /* Implement TARGET_HARD_REGNO_MODE_OK. In 32 bit mode, require that
1847 DImode and DFmode be in even registers. For DImode, this makes some
1848 of the insns easier to write, since you don't have to worry about a
1849 DImode value in registers 3 & 4, producing a result in 4 & 5.
1851 To make the code simpler, the hook now just references an
1852 array built in override_options. */
1854 static bool
1855 microblaze_hard_regno_mode_ok (unsigned int regno, machine_mode mode)
1857 return microblaze_hard_regno_mode_ok_p[mode][regno];
1860 /* Implement TARGET_MODES_TIEABLE_P. */
1862 static bool
1863 microblaze_modes_tieable_p (machine_mode mode1, machine_mode mode2)
1865 return ((GET_MODE_CLASS (mode1) == MODE_FLOAT
1866 || GET_MODE_CLASS (mode1) == MODE_COMPLEX_FLOAT)
1867 == (GET_MODE_CLASS (mode2) == MODE_FLOAT
1868 || GET_MODE_CLASS (mode2) == MODE_COMPLEX_FLOAT));
1871 /* Return true if FUNC is an interrupt function as specified
1872 by the "interrupt_handler" attribute. */
1874 static int
1875 microblaze_interrupt_function_p (tree func)
1877 tree a;
1879 if (TREE_CODE (func) != FUNCTION_DECL)
1880 return 0;
1882 a = lookup_attribute ("interrupt_handler", DECL_ATTRIBUTES (func));
1883 return a != NULL_TREE;
1886 static int
1887 microblaze_fast_interrupt_function_p (tree func)
1889 tree a;
1891 if (TREE_CODE (func) != FUNCTION_DECL)
1892 return 0;
1894 a = lookup_attribute ("fast_interrupt", DECL_ATTRIBUTES (func));
1895 return a != NULL_TREE;
1898 microblaze_break_function_p (tree func)
1900 tree a;
1901 if (!func)
1902 return 0;
1903 if (TREE_CODE (func) != FUNCTION_DECL)
1904 return 0;
1906 a = lookup_attribute ("break_handler", DECL_ATTRIBUTES (func));
1907 return a != NULL_TREE;
1909 /* Return true if FUNC is an interrupt function which uses
1910 normal return, indicated by the "save_volatiles" attribute. */
1912 static int
1913 microblaze_save_volatiles (tree func)
1915 tree a;
1917 if (TREE_CODE (func) != FUNCTION_DECL)
1918 return 0;
1920 a = lookup_attribute ("save_volatiles", DECL_ATTRIBUTES (func));
1921 return a != NULL_TREE;
1924 /* Return whether function is tagged with 'interrupt_handler'
1925 or 'fast_interrupt' attribute. Return true if function
1926 should use return from interrupt rather than normal
1927 function return. */
1929 microblaze_is_interrupt_variant (void)
1931 return (interrupt_handler || fast_interrupt);
1934 microblaze_is_break_handler (void)
1936 return break_handler;
1939 /* Determine of register must be saved/restored in call. */
1940 static int
1941 microblaze_must_save_register (int regno)
1943 if (pic_offset_table_rtx &&
1944 (regno == MB_ABI_PIC_ADDR_REGNUM) && df_regs_ever_live_p (regno))
1945 return 1;
1947 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
1948 return 1;
1950 if (frame_pointer_needed && (regno == HARD_FRAME_POINTER_REGNUM))
1951 return 1;
1953 if (crtl->calls_eh_return
1954 && regno == MB_ABI_SUB_RETURN_ADDR_REGNUM)
1955 return 1;
1957 if (!crtl->is_leaf)
1959 if (regno == MB_ABI_SUB_RETURN_ADDR_REGNUM)
1960 return 1;
1961 if ((microblaze_is_interrupt_variant () || save_volatiles) &&
1962 (regno >= 3 && regno <= 12))
1963 return 1;
1966 if (microblaze_is_interrupt_variant ())
1968 if (df_regs_ever_live_p (regno)
1969 || regno == MB_ABI_MSR_SAVE_REG
1970 || (interrupt_handler
1971 && (regno == MB_ABI_ASM_TEMP_REGNUM
1972 || regno == MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM)))
1973 return 1;
1976 if (save_volatiles)
1978 if (df_regs_ever_live_p (regno)
1979 || regno == MB_ABI_ASM_TEMP_REGNUM
1980 || regno == MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM)
1981 return 1;
1984 if (crtl->calls_eh_return
1985 && (regno == EH_RETURN_DATA_REGNO (0)
1986 || regno == EH_RETURN_DATA_REGNO (1)))
1987 return 1;
1989 return 0;
1992 /* Return the bytes needed to compute the frame pointer from the current
1993 stack pointer.
1995 MicroBlaze stack frames look like:
1999 Before call After call
2000 +-----------------------+ +-----------------------+
2001 high | | | |
2002 mem. | local variables, | | local variables, |
2003 | callee saved and | | callee saved and |
2004 | temps | | temps |
2005 +-----------------------+ +-----------------------+
2006 | arguments for called | | arguments for called |
2007 | subroutines | | subroutines |
2008 | (optional) | | (optional) |
2009 +-----------------------+ +-----------------------+
2010 | Link register | | Link register |
2011 SP->| | | |
2012 +-----------------------+ +-----------------------+
2014 | local variables, |
2015 | callee saved and |
2016 | temps |
2017 +-----------------------+
2018 | MSR (optional if, |
2019 | interrupt handler) |
2020 +-----------------------+
2022 | alloca allocations |
2024 +-----------------------+
2026 | arguments for called |
2027 | subroutines |
2028 | (optional) |
2030 +-----------------------+
2031 | Link register |
2032 low FP,SP->| |
2033 memory +-----------------------+
2037 static HOST_WIDE_INT
2038 compute_frame_size (HOST_WIDE_INT size)
2040 int regno;
2041 HOST_WIDE_INT total_size; /* # bytes that the entire frame takes up. */
2042 HOST_WIDE_INT var_size; /* # bytes that local variables take up. */
2043 HOST_WIDE_INT args_size; /* # bytes that outgoing arguments take up. */
2044 int link_debug_size; /* # bytes for link register. */
2045 HOST_WIDE_INT gp_reg_size; /* # bytes needed to store calle-saved gp regs. */
2046 long mask; /* mask of saved gp registers. */
2048 interrupt_handler =
2049 microblaze_interrupt_function_p (current_function_decl);
2050 break_handler =
2051 microblaze_break_function_p (current_function_decl);
2053 fast_interrupt =
2054 microblaze_fast_interrupt_function_p (current_function_decl);
2055 save_volatiles = microblaze_save_volatiles (current_function_decl);
2056 if (break_handler)
2057 interrupt_handler = break_handler;
2059 gp_reg_size = 0;
2060 mask = 0;
2061 var_size = size;
2062 args_size = crtl->outgoing_args_size;
2064 if ((args_size == 0) && cfun->calls_alloca)
2065 args_size = NUM_OF_ARGS * UNITS_PER_WORD;
2067 total_size = var_size + args_size;
2069 if (flag_pic == 2)
2070 /* force setting GOT. */
2071 df_set_regs_ever_live (MB_ABI_PIC_ADDR_REGNUM, true);
2073 /* Calculate space needed for gp registers. */
2074 for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
2076 if (microblaze_must_save_register (regno))
2079 if (regno != MB_ABI_SUB_RETURN_ADDR_REGNUM)
2080 /* Don't account for link register. It is accounted specially below. */
2081 gp_reg_size += GET_MODE_SIZE (SImode);
2083 mask |= (1L << (regno - GP_REG_FIRST));
2087 total_size += gp_reg_size;
2089 /* Add 4 bytes for MSR. */
2090 if (microblaze_is_interrupt_variant ())
2091 total_size += 4;
2093 /* No space to be allocated for link register in leaf functions with no other
2094 stack requirements. */
2095 if (total_size == 0 && crtl->is_leaf)
2096 link_debug_size = 0;
2097 else
2098 link_debug_size = UNITS_PER_WORD;
2100 total_size += link_debug_size;
2102 /* Save other computed information. */
2103 current_frame_info.total_size = total_size;
2104 current_frame_info.var_size = var_size;
2105 current_frame_info.args_size = args_size;
2106 current_frame_info.gp_reg_size = gp_reg_size;
2107 current_frame_info.mask = mask;
2108 current_frame_info.initialized = reload_completed;
2109 current_frame_info.num_gp = gp_reg_size / UNITS_PER_WORD;
2110 current_frame_info.link_debug_size = link_debug_size;
2112 if (mask)
2113 /* Offset from which to callee-save GP regs. */
2114 current_frame_info.gp_offset = (total_size - gp_reg_size);
2115 else
2116 current_frame_info.gp_offset = 0;
2118 /* Ok, we're done. */
2119 return total_size;
2122 /* Make sure that we're not trying to eliminate to the wrong hard frame
2123 pointer. */
2125 static bool
2126 microblaze_can_eliminate (const int from, const int to)
2128 return ((from == RETURN_ADDRESS_POINTER_REGNUM && !leaf_function_p())
2129 || (to == MB_ABI_SUB_RETURN_ADDR_REGNUM && leaf_function_p())
2130 || (from != RETURN_ADDRESS_POINTER_REGNUM
2131 && (to == HARD_FRAME_POINTER_REGNUM
2132 || (to == STACK_POINTER_REGNUM && !frame_pointer_needed))));
2135 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
2136 pointer or argument pointer or the return address pointer. TO is either
2137 the stack pointer or hard frame pointer. */
2139 HOST_WIDE_INT
2140 microblaze_initial_elimination_offset (int from, int to)
2142 HOST_WIDE_INT offset;
2144 switch (from)
2146 case FRAME_POINTER_REGNUM:
2147 offset = 0;
2148 break;
2149 case ARG_POINTER_REGNUM:
2150 if (to == STACK_POINTER_REGNUM || to == HARD_FRAME_POINTER_REGNUM)
2151 offset = compute_frame_size (get_frame_size ());
2152 else
2153 gcc_unreachable ();
2154 break;
2155 case RETURN_ADDRESS_POINTER_REGNUM:
2156 if (crtl->is_leaf)
2157 offset = 0;
2158 else
2159 offset = current_frame_info.gp_offset +
2160 ((UNITS_PER_WORD - (POINTER_SIZE / BITS_PER_UNIT)));
2161 break;
2162 default:
2163 gcc_unreachable ();
2165 return offset;
2168 /* Print operands using format code.
2170 The MicroBlaze specific codes are:
2172 'X' X is CONST_INT, prints 32 bits in hexadecimal format = "0x%08x",
2173 'x' X is CONST_INT, prints 16 bits in hexadecimal format = "0x%04x",
2174 'F' op is CONST_DOUBLE, print 32 bits in hex,
2175 'd' output integer constant in decimal,
2176 'z' if the operand is 0, use $0 instead of normal operand.
2177 'D' print second register of double-word register operand.
2178 'L' print low-order register of double-word register operand.
2179 'M' print high-order register of double-word register operand.
2180 'C' print part of opcode for a branch condition.
2181 'N' print part of opcode for a branch condition, inverted.
2182 'S' X is CODE_LABEL, print with prefix of "LS" (for embedded switch).
2183 'B' print 'z' for EQ, 'n' for NE
2184 'b' print 'n' for EQ, 'z' for NE
2185 'T' print 'f' for EQ, 't' for NE
2186 't' print 't' for EQ, 'f' for NE
2187 'm' Print 1<<operand.
2188 'i' Print 'i' if MEM operand has immediate value
2189 'y' Print 'y' if MEM operand is single register
2190 'o' Print operand address+4
2191 '?' Print 'd' if we use a branch with delay slot instead of normal branch.
2192 'h' Print high word of const_double (int or float) value as hex
2193 'j' Print low word of const_double (int or float) value as hex
2194 's' Print -1 if operand is negative, 0 if positive (sign extend)
2195 '@' Print the name of the temporary register (rMB_ABI_ASM_TEMP_REGNUM).
2196 '#' Print nop if the delay slot of a branch is not filled.
2199 void
2200 print_operand (FILE * file, rtx op, int letter)
2202 register enum rtx_code code;
2204 if (PRINT_OPERAND_PUNCT_VALID_P (letter))
2206 switch (letter)
2208 case '?':
2209 /* Conditionally add a 'd' to indicate filled delay slot. */
2210 if (final_sequence != NULL)
2211 fputs ("d", file);
2212 break;
2214 case '#':
2215 /* Conditionally add a nop in unfilled delay slot. */
2216 if (final_sequence == NULL)
2217 fputs ("nop\t\t# Unfilled delay slot\n", file);
2218 break;
2220 case '@':
2221 fputs (reg_names[GP_REG_FIRST + MB_ABI_ASM_TEMP_REGNUM], file);
2222 break;
2224 default:
2225 output_operand_lossage ("unknown punctuation '%c'", letter);
2226 break;
2229 return;
2232 if (!op)
2234 output_operand_lossage ("null pointer");
2235 return;
2238 code = GET_CODE (op);
2240 if (code == SIGN_EXTEND)
2241 op = XEXP (op, 0), code = GET_CODE (op);
2243 if (letter == 'C')
2244 switch (code)
2246 case EQ:
2247 fputs ("eq", file);
2248 break;
2249 case NE:
2250 fputs ("ne", file);
2251 break;
2252 case GT:
2253 case GTU:
2254 fputs ("gt", file);
2255 break;
2256 case GE:
2257 case GEU:
2258 fputs ("ge", file);
2259 break;
2260 case LT:
2261 case LTU:
2262 fputs ("lt", file);
2263 break;
2264 case LE:
2265 case LEU:
2266 fputs ("le", file);
2267 break;
2268 default:
2269 fatal_insn ("PRINT_OPERAND, invalid insn for %%C", op);
2272 else if (letter == 'N')
2273 switch (code)
2275 case EQ:
2276 fputs ("ne", file);
2277 break;
2278 case NE:
2279 fputs ("eq", file);
2280 break;
2281 case GT:
2282 case GTU:
2283 fputs ("le", file);
2284 break;
2285 case GE:
2286 case GEU:
2287 fputs ("lt", file);
2288 break;
2289 case LT:
2290 case LTU:
2291 fputs ("ge", file);
2292 break;
2293 case LE:
2294 case LEU:
2295 fputs ("gt", file);
2296 break;
2297 default:
2298 fatal_insn ("PRINT_OPERAND, invalid insn for %%N", op);
2301 else if (letter == 'S')
2303 char buffer[100];
2305 ASM_GENERATE_INTERNAL_LABEL (buffer, "LS", CODE_LABEL_NUMBER (op));
2306 assemble_name (file, buffer);
2309 /* Print 'i' for memory operands which have immediate values. */
2310 else if (letter == 'i')
2312 if (code == MEM)
2314 struct microblaze_address_info info;
2316 if (!microblaze_classify_address
2317 (&info, XEXP (op, 0), GET_MODE (op), 1))
2318 fatal_insn ("insn contains an invalid address !", op);
2320 switch (info.type)
2322 case ADDRESS_REG:
2323 case ADDRESS_CONST_INT:
2324 case ADDRESS_SYMBOLIC:
2325 case ADDRESS_GOTOFF:
2326 case ADDRESS_TLS:
2327 fputs ("i", file);
2328 break;
2329 case ADDRESS_REG_INDEX:
2330 break;
2331 case ADDRESS_INVALID:
2332 case ADDRESS_PLT:
2333 fatal_insn ("invalid address", op);
2338 else if (code == REG || code == SUBREG)
2340 register int regnum;
2342 if (code == REG)
2343 regnum = REGNO (op);
2344 else
2345 regnum = true_regnum (op);
2347 if ((letter == 'M' && !WORDS_BIG_ENDIAN)
2348 || (letter == 'L' && WORDS_BIG_ENDIAN) || letter == 'D')
2349 regnum++;
2351 fprintf (file, "%s", reg_names[regnum]);
2354 else if (code == MEM)
2355 if (letter == 'o')
2357 rtx op4 = adjust_address (op, GET_MODE (op), 4);
2358 output_address (GET_MODE (op), XEXP (op4, 0));
2360 else if (letter == 'y')
2362 rtx mem_reg = XEXP (op, 0);
2363 if (GET_CODE (mem_reg) == REG)
2365 register int regnum = REGNO (mem_reg);
2366 fprintf (file, "%s", reg_names[regnum]);
2369 else
2370 output_address (GET_MODE (op), XEXP (op, 0));
2372 else if (letter == 'h' || letter == 'j')
2374 long val[2];
2375 if (code == CONST_DOUBLE)
2377 if (GET_MODE (op) == DFmode)
2378 REAL_VALUE_TO_TARGET_DOUBLE (*CONST_DOUBLE_REAL_VALUE (op), val);
2379 else
2381 val[0] = CONST_DOUBLE_HIGH (op);
2382 val[1] = CONST_DOUBLE_LOW (op);
2385 else if (code == CONST_INT)
2387 val[0] = (INTVAL (op) & 0xffffffff00000000LL) >> 32;
2388 val[1] = INTVAL (op) & 0x00000000ffffffffLL;
2389 if (val[0] == 0 && val[1] < 0)
2390 val[0] = -1;
2393 fprintf (file, "0x%8.8lx", (letter == 'h') ? val[0] : val[1]);
2395 else if (code == CONST_DOUBLE)
2397 if (letter == 'F')
2399 unsigned long value_long;
2400 REAL_VALUE_TO_TARGET_SINGLE (*CONST_DOUBLE_REAL_VALUE (op),
2401 value_long);
2402 fprintf (file, HOST_WIDE_INT_PRINT_HEX, value_long);
2404 else
2406 char s[60];
2407 real_to_decimal (s, CONST_DOUBLE_REAL_VALUE (op), sizeof (s), 0, 1);
2408 fputs (s, file);
2412 else if (code == UNSPEC)
2414 print_operand_address (file, op);
2417 else if (letter == 'x' && GET_CODE (op) == CONST_INT)
2418 fprintf (file, HOST_WIDE_INT_PRINT_HEX, 0xffff & INTVAL (op));
2420 else if (letter == 'X' && GET_CODE (op) == CONST_INT)
2421 fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (op));
2423 else if (letter == 'd' && GET_CODE (op) == CONST_INT)
2424 fprintf (file, HOST_WIDE_INT_PRINT_DEC, (INTVAL (op)));
2426 else if (letter == 'z' && GET_CODE (op) == CONST_INT && INTVAL (op) == 0)
2427 fputs (reg_names[GP_REG_FIRST], file);
2429 else if (letter == 's' && GET_CODE (op) == CONST_INT)
2430 if (INTVAL (op) < 0)
2431 fputs ("-1", file);
2432 else
2433 fputs ("0", file);
2435 else if (letter == 'd' || letter == 'x' || letter == 'X' || letter == 's')
2436 output_operand_lossage ("letter %c was found & insn was not CONST_INT", letter);
2438 else if (letter == 'B')
2439 fputs (code == EQ ? "z" : "n", file);
2440 else if (letter == 'b')
2441 fputs (code == EQ ? "n" : "z", file);
2442 else if (letter == 'T')
2443 fputs (code == EQ ? "f" : "t", file);
2444 else if (letter == 't')
2445 fputs (code == EQ ? "t" : "f", file);
2447 else if (code == CONST
2448 && ((GET_CODE (XEXP (op, 0)) == REG)
2449 || (GET_CODE (XEXP (op, 0)) == UNSPEC)))
2451 print_operand (file, XEXP (op, 0), letter);
2453 else if (code == CONST
2454 && (GET_CODE (XEXP (op, 0)) == PLUS)
2455 && (GET_CODE (XEXP (XEXP (op, 0), 0)) == REG)
2456 && (GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST))
2458 print_operand_address (file, XEXP (op, 0));
2460 else if (letter == 'm')
2461 fprintf (file, HOST_WIDE_INT_PRINT_DEC, (1L << INTVAL (op)));
2462 else
2463 output_addr_const (file, op);
2466 /* A C compound statement to output to stdio stream STREAM the
2467 assembler syntax for an instruction operand that is a memory
2468 reference whose address is ADDR. ADDR is an RTL expression.
2470 Possible address classifications and output formats are,
2472 ADDRESS_REG "%0, r0"
2474 ADDRESS_REG with non-zero "%0, <addr_const>"
2475 offset
2477 ADDRESS_REG_INDEX "rA, RB"
2478 (if rA is r0, rA and rB are swapped)
2480 ADDRESS_CONST_INT "r0, <addr_const>"
2482 ADDRESS_SYMBOLIC "rBase, <addr_const>"
2483 (rBase is a base register suitable for the
2484 symbol's type)
2487 void
2488 print_operand_address (FILE * file, rtx addr)
2490 struct microblaze_address_info info;
2491 enum microblaze_address_type type;
2492 if (!microblaze_classify_address (&info, addr, GET_MODE (addr), 1))
2493 fatal_insn ("insn contains an invalid address !", addr);
2495 type = info.type;
2496 switch (info.type)
2498 case ADDRESS_REG:
2499 fprintf (file, "%s,", reg_names[REGNO (info.regA)]);
2500 output_addr_const (file, info.offset);
2501 break;
2502 case ADDRESS_REG_INDEX:
2503 if (REGNO (info.regA) == 0)
2504 /* Make rB == r0 instead of rA == r0. This helps reduce read port
2505 congestion. */
2506 fprintf (file, "%s,%s", reg_names[REGNO (info.regB)],
2507 reg_names[REGNO (info.regA)]);
2508 else if (REGNO (info.regB) != 0)
2509 /* This is a silly swap to help Dhrystone. */
2510 fprintf (file, "%s,%s", reg_names[REGNO (info.regB)],
2511 reg_names[REGNO (info.regA)]);
2512 break;
2513 case ADDRESS_CONST_INT:
2514 fprintf (file, "%s,", reg_names[REGNO (info.regA)]);
2515 output_addr_const (file, info.offset);
2516 break;
2517 case ADDRESS_SYMBOLIC:
2518 case ADDRESS_GOTOFF:
2519 case ADDRESS_PLT:
2520 case ADDRESS_TLS:
2521 if (info.regA)
2522 fprintf (file, "%s,", reg_names[REGNO (info.regA)]);
2523 output_addr_const (file, info.symbol);
2524 if (type == ADDRESS_GOTOFF)
2526 fputs ("@GOT", file);
2528 else if (type == ADDRESS_PLT)
2530 fputs ("@PLT", file);
2532 else if (type == ADDRESS_TLS)
2534 switch (info.tls_type)
2536 case TLS_GD:
2537 fputs ("@TLSGD", file);
2538 break;
2539 case TLS_LDM:
2540 fputs ("@TLSLDM", file);
2541 break;
2542 case TLS_DTPREL:
2543 fputs ("@TLSDTPREL", file);
2544 break;
2545 default :
2546 abort();
2547 break;
2550 break;
2551 case ADDRESS_INVALID:
2552 fatal_insn ("invalid address", addr);
2553 break;
2557 /* Emit either a label, .comm, or .lcomm directive, and mark that the symbol
2558 is used, so that we don't emit an .extern for it in
2559 microblaze_asm_file_end. */
2561 void
2562 microblaze_declare_object (FILE * stream, const char *name,
2563 const char *section, const char *fmt, int size)
2566 fputs (section, stream);
2567 assemble_name (stream, name);
2568 fprintf (stream, fmt, size);
2571 /* Common code to emit the insns (or to write the instructions to a file)
2572 to save/restore registers.
2574 Other parts of the code assume that MICROBLAZE_TEMP1_REGNUM (aka large_reg)
2575 is not modified within save_restore_insns. */
2577 #define BITSET_P(VALUE,BIT) (((VALUE) & (1L << (BIT))) != 0)
2579 /* Save or restore instructions based on whether this is the prologue or
2580 epilogue. prologue is 1 for the prologue. */
2581 static void
2582 save_restore_insns (int prologue)
2584 rtx base_reg_rtx, reg_rtx, mem_rtx, /* msr_rtx, */ isr_reg_rtx =
2585 0, isr_mem_rtx = 0;
2586 rtx isr_msr_rtx = 0, insn;
2587 long mask = current_frame_info.mask;
2588 HOST_WIDE_INT gp_offset;
2589 int regno;
2591 if (frame_pointer_needed
2592 && !BITSET_P (mask, HARD_FRAME_POINTER_REGNUM - GP_REG_FIRST))
2593 gcc_unreachable ();
2595 if (mask == 0)
2596 return;
2598 /* Save registers starting from high to low. The debuggers prefer at least
2599 the return register be stored at func+4, and also it allows us not to
2600 need a nop in the epilog if at least one register is reloaded in
2601 addition to return address. */
2603 /* Pick which pointer to use as a base register. For small frames, just
2604 use the stack pointer. Otherwise, use a temporary register. Save 2
2605 cycles if the save area is near the end of a large frame, by reusing
2606 the constant created in the prologue/epilogue to adjust the stack
2607 frame. */
2609 gp_offset = current_frame_info.gp_offset;
2611 gcc_assert (gp_offset > 0);
2613 base_reg_rtx = stack_pointer_rtx;
2615 /* For interrupt_handlers, need to save/restore the MSR. */
2616 if (microblaze_is_interrupt_variant ())
2618 isr_mem_rtx = gen_rtx_MEM (SImode,
2619 gen_rtx_PLUS (Pmode, base_reg_rtx,
2620 GEN_INT (current_frame_info.
2621 gp_offset -
2622 UNITS_PER_WORD)));
2624 /* Do not optimize in flow analysis. */
2625 MEM_VOLATILE_P (isr_mem_rtx) = 1;
2626 isr_reg_rtx = gen_rtx_REG (SImode, MB_ABI_MSR_SAVE_REG);
2627 isr_msr_rtx = gen_rtx_REG (SImode, ST_REG);
2630 if (microblaze_is_interrupt_variant () && !prologue)
2632 emit_move_insn (isr_reg_rtx, isr_mem_rtx);
2633 emit_move_insn (isr_msr_rtx, isr_reg_rtx);
2634 /* Do not optimize in flow analysis. */
2635 emit_insn (gen_rtx_USE (SImode, isr_reg_rtx));
2636 emit_insn (gen_rtx_USE (SImode, isr_msr_rtx));
2639 for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
2641 if (BITSET_P (mask, regno - GP_REG_FIRST))
2643 if (regno == MB_ABI_SUB_RETURN_ADDR_REGNUM)
2644 /* Don't handle here. Already handled as the first register. */
2645 continue;
2647 reg_rtx = gen_rtx_REG (SImode, regno);
2648 insn = gen_rtx_PLUS (Pmode, base_reg_rtx, GEN_INT (gp_offset));
2649 mem_rtx = gen_rtx_MEM (SImode, insn);
2650 if (microblaze_is_interrupt_variant () || save_volatiles)
2651 /* Do not optimize in flow analysis. */
2652 MEM_VOLATILE_P (mem_rtx) = 1;
2654 if (prologue)
2656 insn = emit_move_insn (mem_rtx, reg_rtx);
2657 RTX_FRAME_RELATED_P (insn) = 1;
2659 else
2661 insn = emit_move_insn (reg_rtx, mem_rtx);
2664 gp_offset += GET_MODE_SIZE (SImode);
2668 if (microblaze_is_interrupt_variant () && prologue)
2670 emit_move_insn (isr_reg_rtx, isr_msr_rtx);
2671 emit_move_insn (isr_mem_rtx, isr_reg_rtx);
2673 /* Do not optimize in flow analysis. */
2674 emit_insn (gen_rtx_USE (SImode, isr_reg_rtx));
2675 emit_insn (gen_rtx_USE (SImode, isr_msr_rtx));
2678 /* Done saving and restoring */
2682 /* Set up the stack and frame (if desired) for the function. */
2683 static void
2684 microblaze_function_prologue (FILE * file)
2686 const char *fnname;
2687 long fsiz = current_frame_info.total_size;
2689 /* Get the function name the same way that toplev.c does before calling
2690 assemble_start_function. This is needed so that the name used here
2691 exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */
2692 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
2693 if (!flag_inhibit_size_directive)
2695 fputs ("\t.ent\t", file);
2696 if (interrupt_handler && strcmp (INTERRUPT_HANDLER_NAME, fnname))
2697 fputs ("_interrupt_handler", file);
2698 else if (break_handler && strcmp (BREAK_HANDLER_NAME, fnname))
2699 fputs ("_break_handler", file);
2700 else if (fast_interrupt && strcmp (FAST_INTERRUPT_NAME, fnname))
2701 fputs ("_fast_interrupt", file);
2702 else
2703 assemble_name (file, fnname);
2704 fputs ("\n", file);
2705 if (!microblaze_is_interrupt_variant ())
2706 ASM_OUTPUT_TYPE_DIRECTIVE (file, fnname, "function");
2709 assemble_name (file, fnname);
2710 fputs (":\n", file);
2712 if (interrupt_handler && strcmp (INTERRUPT_HANDLER_NAME, fnname))
2713 fputs ("_interrupt_handler:\n", file);
2714 if (break_handler && strcmp (BREAK_HANDLER_NAME, fnname))
2715 fputs ("_break_handler:\n", file);
2716 if (!flag_inhibit_size_directive)
2718 /* .frame FRAMEREG, FRAMESIZE, RETREG. */
2719 fprintf (file,
2720 "\t.frame\t%s,%ld,%s\t\t# vars= %ld, regs= %d, args= %d\n",
2721 (reg_names[(frame_pointer_needed)
2722 ? HARD_FRAME_POINTER_REGNUM :
2723 STACK_POINTER_REGNUM]), fsiz,
2724 reg_names[MB_ABI_SUB_RETURN_ADDR_REGNUM + GP_REG_FIRST],
2725 current_frame_info.var_size, current_frame_info.num_gp,
2726 (int) crtl->outgoing_args_size);
2727 fprintf (file, "\t.mask\t0x%08lx\n", current_frame_info.mask);
2731 /* Output extra assembler code at the end of a prologue. */
2732 static void
2733 microblaze_function_end_prologue (FILE * file)
2735 if (TARGET_STACK_CHECK)
2737 fprintf (file, "\t# Stack Check Stub -- Start.\n\t");
2738 fprintf (file, "ori\tr18,r0,_stack_end\n\t");
2739 fprintf (file, "cmpu\tr18,r1,r18\n\t");
2740 fprintf (file, "bgei\tr18,_stack_overflow_exit\n\t");
2741 fprintf (file, "# Stack Check Stub -- End.\n");
2745 static void
2746 microblaze_elf_asm_cdtor (rtx symbol, int priority, bool is_ctor)
2748 section *s;
2750 if (priority != DEFAULT_INIT_PRIORITY)
2752 char buf[18];
2753 sprintf (buf, "%s.%.5u",
2754 is_ctor ? ".ctors" : ".dtors",
2755 MAX_INIT_PRIORITY - priority);
2756 s = get_section (buf, SECTION_WRITE, NULL_TREE);
2758 else if (is_ctor)
2759 s = ctors_section;
2760 else
2761 s = dtors_section;
2763 switch_to_section (s);
2764 assemble_align (POINTER_SIZE);
2765 fputs ("\t.word\t", asm_out_file);
2766 output_addr_const (asm_out_file, symbol);
2767 fputs ("\n", asm_out_file);
2770 /* Add a function to the list of static constructors. */
2772 static void
2773 microblaze_elf_asm_constructor (rtx symbol, int priority)
2775 microblaze_elf_asm_cdtor (symbol, priority, /*is_ctor=*/true);
2778 /* Add a function to the list of static destructors. */
2780 static void
2781 microblaze_elf_asm_destructor (rtx symbol, int priority)
2783 microblaze_elf_asm_cdtor (symbol, priority, /*is_ctor=*/false);
2786 /* Expand the prologue into a bunch of separate insns. */
2788 void
2789 microblaze_expand_prologue (void)
2791 int regno;
2792 HOST_WIDE_INT fsiz;
2793 const char *arg_name = 0;
2794 tree fndecl = current_function_decl;
2795 tree fntype = TREE_TYPE (fndecl);
2796 tree fnargs = DECL_ARGUMENTS (fndecl);
2797 rtx next_arg_reg;
2798 int i;
2799 tree next_arg;
2800 tree cur_arg;
2801 CUMULATIVE_ARGS args_so_far_v;
2802 cumulative_args_t args_so_far;
2803 rtx mem_rtx, reg_rtx;
2805 /* If struct value address is treated as the first argument, make it so. */
2806 if (aggregate_value_p (DECL_RESULT (fndecl), fntype)
2807 && !cfun->returns_pcc_struct)
2809 tree type = build_pointer_type (fntype);
2810 tree function_result_decl = build_decl (BUILTINS_LOCATION, PARM_DECL,
2811 NULL_TREE, type);
2813 DECL_ARG_TYPE (function_result_decl) = type;
2814 TREE_CHAIN (function_result_decl) = fnargs;
2815 fnargs = function_result_decl;
2818 /* Determine the last argument, and get its name. */
2820 INIT_CUMULATIVE_ARGS (args_so_far_v, fntype, NULL_RTX, 0, 0);
2821 args_so_far = pack_cumulative_args (&args_so_far_v);
2822 regno = GP_ARG_FIRST;
2824 for (cur_arg = fnargs; cur_arg != 0; cur_arg = next_arg)
2826 tree passed_type = DECL_ARG_TYPE (cur_arg);
2827 machine_mode passed_mode = TYPE_MODE (passed_type);
2828 rtx entry_parm;
2830 if (TREE_ADDRESSABLE (passed_type))
2832 passed_type = build_pointer_type (passed_type);
2833 passed_mode = Pmode;
2836 entry_parm = targetm.calls.function_arg (args_so_far, passed_mode,
2837 passed_type, true);
2839 if (entry_parm)
2841 int words;
2843 /* passed in a register, so will get homed automatically. */
2844 if (GET_MODE (entry_parm) == BLKmode)
2845 words = (int_size_in_bytes (passed_type) + 3) / 4;
2846 else
2847 words = (GET_MODE_SIZE (GET_MODE (entry_parm)) + 3) / 4;
2849 regno = REGNO (entry_parm) + words - 1;
2851 else
2853 regno = GP_ARG_LAST + 1;
2854 break;
2857 targetm.calls.function_arg_advance (args_so_far, passed_mode,
2858 passed_type, true);
2860 next_arg = TREE_CHAIN (cur_arg);
2861 if (next_arg == 0)
2863 if (DECL_NAME (cur_arg))
2864 arg_name = IDENTIFIER_POINTER (DECL_NAME (cur_arg));
2866 break;
2870 /* Split parallel insn into a sequence of insns. */
2872 next_arg_reg = targetm.calls.function_arg (args_so_far, VOIDmode,
2873 void_type_node, true);
2874 if (next_arg_reg != 0 && GET_CODE (next_arg_reg) == PARALLEL)
2876 rtvec adjust = XVEC (next_arg_reg, 0);
2877 int num = GET_NUM_ELEM (adjust);
2879 for (i = 0; i < num; i++)
2881 rtx pattern = RTVEC_ELT (adjust, i);
2882 emit_insn (pattern);
2886 fsiz = compute_frame_size (get_frame_size ());
2888 if (flag_stack_usage_info)
2889 current_function_static_stack_size = fsiz;
2892 /* If this function is a varargs function, store any registers that
2893 would normally hold arguments ($5 - $10) on the stack. */
2894 if (((TYPE_ARG_TYPES (fntype) != 0
2895 && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
2896 != void_type_node))
2897 || (arg_name != 0
2898 && ((arg_name[0] == '_'
2899 && strcmp (arg_name, "__builtin_va_alist") == 0)
2900 || (arg_name[0] == 'v'
2901 && strcmp (arg_name, "va_alist") == 0)))))
2903 int offset = (regno - GP_ARG_FIRST + 1) * UNITS_PER_WORD;
2904 rtx ptr = stack_pointer_rtx;
2906 /* If we are doing svr4-abi, sp has already been decremented by fsiz. */
2907 for (; regno <= GP_ARG_LAST; regno++)
2909 if (offset != 0)
2910 ptr = gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (offset));
2911 emit_move_insn (gen_rtx_MEM (SImode, ptr),
2912 gen_rtx_REG (SImode, regno));
2914 offset += GET_MODE_SIZE (SImode);
2919 if (fsiz > 0)
2921 rtx fsiz_rtx = GEN_INT (fsiz);
2923 rtx_insn *insn = NULL;
2924 insn = emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx,
2925 fsiz_rtx));
2926 if (insn)
2927 RTX_FRAME_RELATED_P (insn) = 1;
2929 /* Handle SUB_RETURN_ADDR_REGNUM specially at first. */
2930 if (!crtl->is_leaf || interrupt_handler)
2932 mem_rtx = gen_rtx_MEM (SImode,
2933 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
2934 const0_rtx));
2936 if (interrupt_handler)
2937 /* Do not optimize in flow analysis. */
2938 MEM_VOLATILE_P (mem_rtx) = 1;
2940 reg_rtx = gen_rtx_REG (SImode, MB_ABI_SUB_RETURN_ADDR_REGNUM);
2941 insn = emit_move_insn (mem_rtx, reg_rtx);
2942 RTX_FRAME_RELATED_P (insn) = 1;
2945 /* _save_ registers for prologue. */
2946 save_restore_insns (1);
2948 if (frame_pointer_needed)
2950 rtx_insn *insn = 0;
2952 insn = emit_insn (gen_movsi (hard_frame_pointer_rtx,
2953 stack_pointer_rtx));
2955 if (insn)
2956 RTX_FRAME_RELATED_P (insn) = 1;
2960 if ((flag_pic == 2 || TLS_NEEDS_GOT )
2961 && df_regs_ever_live_p (MB_ABI_PIC_ADDR_REGNUM))
2963 SET_REGNO (pic_offset_table_rtx, MB_ABI_PIC_ADDR_REGNUM);
2964 emit_insn (gen_set_got (pic_offset_table_rtx)); /* setting GOT. */
2967 /* If we are profiling, make sure no instructions are scheduled before
2968 the call to mcount. */
2970 if (profile_flag)
2971 emit_insn (gen_blockage ());
2974 /* Do necessary cleanup after a function to restore stack, frame, and regs. */
2976 #define RA_MASK ((long) 0x80000000) /* 1 << 31 */
2977 #define PIC_OFFSET_TABLE_MASK (1 << (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST))
2979 static void
2980 microblaze_function_epilogue (FILE *file)
2982 const char *fnname;
2984 /* Get the function name the same way that toplev.c does before calling
2985 assemble_start_function. This is needed so that the name used here
2986 exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */
2987 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
2989 if (!flag_inhibit_size_directive)
2991 fputs ("\t.end\t", file);
2992 if (interrupt_handler && !break_handler)
2993 fputs ("_interrupt_handler", file);
2994 else if (break_handler)
2995 fputs ("_break_handler", file);
2996 else
2997 assemble_name (file, fnname);
2998 fputs ("\n", file);
3001 /* Reset state info for each function. */
3002 current_frame_info = zero_frame_info;
3004 /* Restore the output file if optimizing the GP (optimizing the GP causes
3005 the text to be diverted to a tempfile, so that data decls come before
3006 references to the data). */
3009 /* Expand the epilogue into a bunch of separate insns. */
3011 void
3012 microblaze_expand_epilogue (void)
3014 HOST_WIDE_INT fsiz = current_frame_info.total_size;
3015 rtx fsiz_rtx = GEN_INT (fsiz);
3016 rtx reg_rtx;
3017 rtx mem_rtx;
3019 /* In case of interrupt handlers use addki instead of addi for changing the
3020 stack pointer value. */
3022 if (microblaze_can_use_return_insn ())
3024 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode,
3025 GP_REG_FIRST +
3026 MB_ABI_SUB_RETURN_ADDR_REGNUM)));
3027 return;
3030 if (fsiz > 0)
3032 /* Restore SUB_RETURN_ADDR_REGNUM at first. This is to prevent the
3033 sequence of load-followed by a use (in rtsd) in every prologue. Saves
3034 a load-use stall cycle :) This is also important to handle alloca.
3035 (See comments for if (frame_pointer_needed) below. */
3037 if (!crtl->is_leaf || interrupt_handler)
3039 mem_rtx =
3040 gen_rtx_MEM (SImode,
3041 gen_rtx_PLUS (Pmode, stack_pointer_rtx, const0_rtx));
3042 if (interrupt_handler)
3043 /* Do not optimize in flow analysis. */
3044 MEM_VOLATILE_P (mem_rtx) = 1;
3045 reg_rtx = gen_rtx_REG (SImode, MB_ABI_SUB_RETURN_ADDR_REGNUM);
3046 emit_move_insn (reg_rtx, mem_rtx);
3049 /* It is important that this is done after we restore the return address
3050 register (above). When alloca is used, we want to restore the
3051 sub-routine return address only from the current stack top and not
3052 from the frame pointer (which we restore below). (frame_pointer + 0)
3053 might have been over-written since alloca allocates memory on the
3054 current stack. */
3055 if (frame_pointer_needed)
3056 emit_insn (gen_movsi (stack_pointer_rtx, hard_frame_pointer_rtx));
3058 /* _restore_ registers for epilogue. */
3059 save_restore_insns (0);
3060 emit_insn (gen_blockage ());
3061 emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, fsiz_rtx));
3064 if (crtl->calls_eh_return)
3065 emit_insn (gen_addsi3 (stack_pointer_rtx,
3066 stack_pointer_rtx,
3067 gen_raw_REG (SImode,
3068 MB_EH_STACKADJ_REGNUM)));
3070 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode, GP_REG_FIRST +
3071 MB_ABI_SUB_RETURN_ADDR_REGNUM)));
3075 /* Return nonzero if this function is known to have a null epilogue.
3076 This allows the optimizer to omit jumps to jumps if no stack
3077 was created. */
3080 microblaze_can_use_return_insn (void)
3082 if (!reload_completed)
3083 return 0;
3085 if (df_regs_ever_live_p (MB_ABI_SUB_RETURN_ADDR_REGNUM) || profile_flag)
3086 return 0;
3088 if (current_frame_info.initialized)
3089 return current_frame_info.total_size == 0;
3091 return compute_frame_size (get_frame_size ()) == 0;
3094 /* Implement TARGET_SECONDARY_RELOAD. */
3096 static reg_class_t
3097 microblaze_secondary_reload (bool in_p ATTRIBUTE_UNUSED, rtx x ATTRIBUTE_UNUSED,
3098 reg_class_t rclass, machine_mode mode ATTRIBUTE_UNUSED,
3099 secondary_reload_info *sri ATTRIBUTE_UNUSED)
3101 if (rclass == ST_REGS)
3102 return GR_REGS;
3104 return NO_REGS;
3107 static void
3108 microblaze_globalize_label (FILE * stream, const char *name)
3110 fputs ("\t.globl\t", stream);
3111 if (microblaze_is_interrupt_variant ())
3113 if (interrupt_handler && strcmp (name, INTERRUPT_HANDLER_NAME))
3114 fputs (INTERRUPT_HANDLER_NAME, stream);
3115 else if (break_handler && strcmp (name, BREAK_HANDLER_NAME))
3116 fputs (BREAK_HANDLER_NAME, stream);
3117 else if (fast_interrupt && strcmp (name, FAST_INTERRUPT_NAME))
3118 fputs (FAST_INTERRUPT_NAME, stream);
3119 fputs ("\n\t.globl\t", stream);
3121 assemble_name (stream, name);
3122 fputs ("\n", stream);
3125 /* Returns true if decl should be placed into a "small data" section. */
3126 static bool
3127 microblaze_elf_in_small_data_p (const_tree decl)
3129 HOST_WIDE_INT size;
3131 if (!TARGET_XLGPOPT)
3132 return false;
3134 /* We want to merge strings, so we never consider them small data. */
3135 if (TREE_CODE (decl) == STRING_CST)
3136 return false;
3138 /* Functions are never in the small data area. */
3139 if (TREE_CODE (decl) == FUNCTION_DECL)
3140 return false;
3142 if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl))
3144 const char *section = DECL_SECTION_NAME (decl);
3145 if (strcmp (section, ".sdata") == 0
3146 || strcmp (section, ".sdata2") == 0
3147 || strcmp (section, ".sbss") == 0
3148 || strcmp (section, ".sbss2") == 0)
3149 return true;
3152 size = int_size_in_bytes (TREE_TYPE (decl));
3154 return (size > 0 && size <= microblaze_section_threshold);
3158 static section *
3159 microblaze_select_section (tree decl, int reloc, unsigned HOST_WIDE_INT align)
3161 switch (categorize_decl_for_section (decl, reloc))
3163 case SECCAT_RODATA_MERGE_STR:
3164 case SECCAT_RODATA_MERGE_STR_INIT:
3165 /* MB binutils have various issues with mergeable string sections and
3166 relaxation/relocation. Currently, turning mergeable sections
3167 into regular readonly sections. */
3169 return readonly_data_section;
3170 default:
3171 return default_elf_select_section (decl, reloc, align);
3176 Encode info about sections into the RTL based on a symbol's declaration.
3177 The default definition of this hook, default_encode_section_info in
3178 `varasm.c', sets a number of commonly-useful bits in SYMBOL_REF_FLAGS. */
3180 static void
3181 microblaze_encode_section_info (tree decl, rtx rtl, int first)
3183 default_encode_section_info (decl, rtl, first);
3186 static rtx
3187 expand_pic_symbol_ref (machine_mode mode ATTRIBUTE_UNUSED, rtx op)
3189 rtx result;
3190 result = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op), UNSPEC_GOTOFF);
3191 result = gen_rtx_CONST (Pmode, result);
3192 result = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, result);
3193 result = gen_const_mem (Pmode, result);
3194 return result;
3197 static void
3198 microblaze_asm_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
3199 HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
3200 tree function)
3202 rtx this_rtx, funexp;
3203 rtx_insn *insn;
3205 reload_completed = 1;
3206 epilogue_completed = 1;
3208 /* Mark the end of the (empty) prologue. */
3209 emit_note (NOTE_INSN_PROLOGUE_END);
3211 /* Find the "this" pointer. If the function returns a structure,
3212 the structure return pointer is in MB_ABI_FIRST_ARG_REGNUM. */
3213 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
3214 this_rtx = gen_rtx_REG (Pmode, (MB_ABI_FIRST_ARG_REGNUM + 1));
3215 else
3216 this_rtx = gen_rtx_REG (Pmode, MB_ABI_FIRST_ARG_REGNUM);
3218 /* Apply the constant offset, if required. */
3219 if (delta)
3220 emit_insn (gen_addsi3 (this_rtx, this_rtx, GEN_INT (delta)));
3222 /* Apply the offset from the vtable, if required. */
3223 if (vcall_offset)
3225 rtx vcall_offset_rtx = GEN_INT (vcall_offset);
3226 rtx temp1 = gen_rtx_REG (Pmode, MB_ABI_TEMP1_REGNUM);
3228 emit_move_insn (temp1, gen_rtx_MEM (Pmode, this_rtx));
3230 rtx loc = gen_rtx_PLUS (Pmode, temp1, vcall_offset_rtx);
3231 emit_move_insn (temp1, gen_rtx_MEM (Pmode, loc));
3233 emit_insn (gen_addsi3 (this_rtx, this_rtx, temp1));
3236 /* Generate a tail call to the target function. */
3237 if (!TREE_USED (function))
3239 assemble_external (function);
3240 TREE_USED (function) = 1;
3243 funexp = XEXP (DECL_RTL (function), 0);
3244 rtx temp2 = gen_rtx_REG (Pmode, MB_ABI_TEMP2_REGNUM);
3246 if (flag_pic)
3247 emit_move_insn (temp2, expand_pic_symbol_ref (Pmode, funexp));
3248 else
3249 emit_move_insn (temp2, funexp);
3251 emit_insn (gen_indirect_jump (temp2));
3253 /* Run just enough of rest_of_compilation. This sequence was
3254 "borrowed" from rs6000.c. */
3255 insn = get_insns ();
3256 shorten_branches (insn);
3257 final_start_function (insn, file, 1);
3258 final (insn, file, 1);
3259 final_end_function ();
3261 reload_completed = 0;
3262 epilogue_completed = 0;
3265 bool
3266 microblaze_expand_move (machine_mode mode, rtx operands[])
3268 rtx op0, op1;
3270 op0 = operands[0];
3271 op1 = operands[1];
3273 if (!register_operand (op0, SImode)
3274 && !register_operand (op1, SImode)
3275 && (GET_CODE (op1) != CONST_INT || INTVAL (op1) != 0))
3277 rtx temp = force_reg (SImode, op1);
3278 emit_move_insn (op0, temp);
3279 return true;
3281 /* If operands[1] is a constant address invalid for pic, then we need to
3282 handle it just like LEGITIMIZE_ADDRESS does. */
3283 if (GET_CODE (op1) == SYMBOL_REF || GET_CODE (op1) == LABEL_REF)
3285 rtx result;
3286 if (microblaze_tls_symbol_p(op1))
3288 result = microblaze_legitimize_tls_address (op1, NULL_RTX);
3289 emit_move_insn (op0, result);
3290 return true;
3292 else if (flag_pic)
3294 if (reload_in_progress)
3295 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
3296 result = expand_pic_symbol_ref (mode, op1);
3297 emit_move_insn (op0, result);
3298 return true;
3301 /* Handle Case of (const (plus symbol const_int)). */
3302 if (GET_CODE (op1) == CONST && GET_CODE (XEXP (op1,0)) == PLUS)
3304 rtx p0, p1;
3306 p0 = XEXP (XEXP (op1, 0), 0);
3307 p1 = XEXP (XEXP (op1, 0), 1);
3309 if ((GET_CODE (p1) == CONST_INT)
3310 && ((GET_CODE (p0) == UNSPEC)
3311 || ((GET_CODE (p0) == SYMBOL_REF || GET_CODE (p0) == LABEL_REF)
3312 && (flag_pic == 2 || microblaze_tls_symbol_p (p0)
3313 || !SMALL_INT (p1)))))
3315 rtx temp = force_reg (SImode, p0);
3316 rtx temp2 = p1;
3318 if (flag_pic && reload_in_progress)
3319 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
3320 emit_move_insn (op0, gen_rtx_PLUS (SImode, temp, temp2));
3321 return true;
3324 return false;
3327 /* Expand shift operations. */
3329 microblaze_expand_shift (rtx operands[])
3331 gcc_assert ((GET_CODE (operands[2]) == CONST_INT)
3332 || (GET_CODE (operands[2]) == REG)
3333 || (GET_CODE (operands[2]) == SUBREG));
3335 /* Shift by one -- generate pattern. */
3336 if ((GET_CODE (operands[2]) == CONST_INT) && (INTVAL (operands[2]) == 1))
3337 return 0;
3339 /* Have barrel shifter and shift > 1: use it. */
3340 if (TARGET_BARREL_SHIFT)
3341 return 0;
3343 gcc_assert ((GET_CODE (operands[0]) == REG)
3344 || (GET_CODE (operands[0]) == SUBREG)
3345 || (GET_CODE (operands[1]) == REG)
3346 || (GET_CODE (operands[1]) == SUBREG));
3348 /* Shift by zero -- copy regs if necessary. */
3349 if (operands[2] == const0_rtx
3350 && !rtx_equal_p (operands[0], operands[1]))
3352 emit_insn (gen_movsi (operands[0], operands[1]));
3353 return 1;
3356 return 0;
3359 /* Return an RTX indicating where the return address to the
3360 calling function can be found. */
3362 microblaze_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
3364 if (count != 0)
3365 return NULL_RTX;
3367 return get_hard_reg_initial_val (Pmode,
3368 MB_ABI_SUB_RETURN_ADDR_REGNUM);
3371 void
3372 microblaze_eh_return (rtx op0)
3374 emit_insn (gen_movsi (gen_rtx_MEM (Pmode, stack_pointer_rtx), op0));
3377 /* Queue an .ident string in the queue of top-level asm statements.
3378 If the string size is below the threshold, put it into .sdata2.
3379 If the front-end is done, we must be being called from toplev.c.
3380 In that case, do nothing. */
3381 void
3382 microblaze_asm_output_ident (const char *string)
3384 const char *section_asm_op;
3385 int size;
3386 char *buf;
3388 if (symtab->state != PARSING)
3389 return;
3391 size = strlen (string) + 1;
3392 if (size <= microblaze_section_threshold)
3393 section_asm_op = SDATA2_SECTION_ASM_OP;
3394 else
3395 section_asm_op = READONLY_DATA_SECTION_ASM_OP;
3397 buf = ACONCAT (("\t.pushsection", section_asm_op,
3398 "\n\t.ascii \"", string, "\\0\"\n",
3399 "\t.popsection\n", NULL));
3400 symtab->finalize_toplevel_asm (build_string (strlen (buf), buf));
3403 static void
3404 microblaze_elf_asm_init_sections (void)
3406 sdata2_section
3407 = get_unnamed_section (SECTION_WRITE, output_section_asm_op,
3408 SDATA2_SECTION_ASM_OP);
3411 /* Generate assembler code for constant parts of a trampoline. */
3413 static void
3414 microblaze_asm_trampoline_template (FILE *f)
3416 fprintf (f, "\tmfs r18, rpc\n");
3417 fprintf (f, "\tlwi r3, r18, 16\n");
3418 fprintf (f, "\tlwi r18, r18, 20\n");
3419 fprintf (f, "\tbra r18\n");
3420 /* fprintf (f, "\t.word\t0x00000000\t\t# <function address>\n"); */
3421 /* fprintf (f, "\t.word\t0x00000000\t\t# <static chain value>\n"); */
3424 /* Implement TARGET_TRAMPOLINE_INIT. */
3426 static void
3427 microblaze_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
3429 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
3430 rtx mem;
3432 emit_block_move (m_tramp, assemble_trampoline_template (),
3433 GEN_INT (6*UNITS_PER_WORD), BLOCK_OP_NORMAL);
3435 mem = adjust_address (m_tramp, SImode, 16);
3436 emit_move_insn (mem, chain_value);
3437 mem = adjust_address (m_tramp, SImode, 20);
3438 emit_move_insn (mem, fnaddr);
3441 /* Generate conditional branch -- first, generate test condition,
3442 second, generate correct branch instruction. */
3444 void
3445 microblaze_expand_conditional_branch (machine_mode mode, rtx operands[])
3447 enum rtx_code code = GET_CODE (operands[0]);
3448 rtx cmp_op0 = operands[1];
3449 rtx cmp_op1 = operands[2];
3450 rtx label1 = operands[3];
3451 rtx comp_reg = gen_reg_rtx (SImode);
3452 rtx condition;
3454 gcc_assert ((GET_CODE (cmp_op0) == REG) || (GET_CODE (cmp_op0) == SUBREG));
3456 /* If comparing against zero, just test source reg. */
3457 if (cmp_op1 == const0_rtx)
3459 comp_reg = cmp_op0;
3460 condition = gen_rtx_fmt_ee (signed_condition (code), SImode, comp_reg, const0_rtx);
3461 emit_jump_insn (gen_condjump (condition, label1));
3464 else if (code == EQ || code == NE)
3466 /* Use xor for equal/not-equal comparison. */
3467 emit_insn (gen_xorsi3 (comp_reg, cmp_op0, cmp_op1));
3468 condition = gen_rtx_fmt_ee (signed_condition (code), SImode, comp_reg, const0_rtx);
3469 emit_jump_insn (gen_condjump (condition, label1));
3471 else
3473 /* Generate compare and branch in single instruction. */
3474 cmp_op1 = force_reg (mode, cmp_op1);
3475 condition = gen_rtx_fmt_ee (code, mode, cmp_op0, cmp_op1);
3476 emit_jump_insn (gen_branch_compare(condition, cmp_op0, cmp_op1, label1));
3480 void
3481 microblaze_expand_conditional_branch_reg (machine_mode mode, rtx operands[])
3483 enum rtx_code code = GET_CODE (operands[0]);
3484 rtx cmp_op0 = operands[1];
3485 rtx cmp_op1 = operands[2];
3486 rtx label1 = operands[3];
3487 rtx comp_reg = gen_reg_rtx (SImode);
3488 rtx condition;
3490 gcc_assert ((GET_CODE (cmp_op0) == REG)
3491 || (GET_CODE (cmp_op0) == SUBREG));
3493 /* If comparing against zero, just test source reg. */
3494 if (cmp_op1 == const0_rtx)
3496 comp_reg = cmp_op0;
3497 condition = gen_rtx_fmt_ee (signed_condition (code),
3498 SImode, comp_reg, const0_rtx);
3499 emit_jump_insn (gen_condjump (condition, label1));
3501 else if (code == EQ)
3503 emit_insn (gen_seq_internal_pat (comp_reg,
3504 cmp_op0, cmp_op1));
3505 condition = gen_rtx_EQ (SImode, comp_reg, const0_rtx);
3506 emit_jump_insn (gen_condjump (condition, label1));
3508 else if (code == NE)
3510 emit_insn (gen_sne_internal_pat (comp_reg, cmp_op0,
3511 cmp_op1));
3512 condition = gen_rtx_NE (SImode, comp_reg, const0_rtx);
3513 emit_jump_insn (gen_condjump (condition, label1));
3515 else
3517 /* Generate compare and branch in single instruction. */
3518 cmp_op1 = force_reg (mode, cmp_op1);
3519 condition = gen_rtx_fmt_ee (code, mode, cmp_op0, cmp_op1);
3520 emit_jump_insn (gen_branch_compare (condition, cmp_op0,
3521 cmp_op1, label1));
3525 void
3526 microblaze_expand_conditional_branch_sf (rtx operands[])
3528 rtx condition;
3529 rtx cmp_op0 = XEXP (operands[0], 0);
3530 rtx cmp_op1 = XEXP (operands[0], 1);
3531 rtx comp_reg = gen_reg_rtx (SImode);
3533 emit_insn (gen_cstoresf4 (comp_reg, operands[0], cmp_op0, cmp_op1));
3534 condition = gen_rtx_NE (SImode, comp_reg, const0_rtx);
3535 emit_jump_insn (gen_condjump (condition, operands[3]));
3538 /* Implement TARGET_FRAME_POINTER_REQUIRED. */
3540 static bool
3541 microblaze_frame_pointer_required (void)
3543 /* If the function contains dynamic stack allocations, we need to
3544 use the frame pointer to access the static parts of the frame. */
3545 if (cfun->calls_alloca)
3546 return true;
3547 return false;
3550 void
3551 microblaze_expand_divide (rtx operands[])
3553 /* Table lookup software divides. Works for all (nr/dr) where (0 <= nr,dr <= 15). */
3555 rtx regt1 = gen_reg_rtx (SImode);
3556 rtx reg18 = gen_rtx_REG (SImode, R_TMP);
3557 rtx regqi = gen_reg_rtx (QImode);
3558 rtx_code_label *div_label = gen_label_rtx ();
3559 rtx_code_label *div_end_label = gen_label_rtx ();
3560 rtx div_table_rtx = gen_rtx_SYMBOL_REF (QImode,"_divsi3_table");
3561 rtx mem_rtx;
3562 rtx ret;
3563 rtx_insn *jump, *cjump, *insn;
3565 insn = emit_insn (gen_iorsi3 (regt1, operands[1], operands[2]));
3566 cjump = emit_jump_insn_after (gen_cbranchsi4 (
3567 gen_rtx_GTU (SImode, regt1, GEN_INT (15)),
3568 regt1, GEN_INT (15), div_label), insn);
3569 LABEL_NUSES (div_label) = 1;
3570 JUMP_LABEL (cjump) = div_label;
3571 emit_insn (gen_rtx_CLOBBER (SImode, reg18));
3573 emit_insn (gen_ashlsi3_bshift (regt1, operands[1], GEN_INT(4)));
3574 emit_insn (gen_addsi3 (regt1, regt1, operands[2]));
3575 mem_rtx = gen_rtx_MEM (QImode,
3576 gen_rtx_PLUS (Pmode, regt1, div_table_rtx));
3578 insn = emit_insn (gen_movqi (regqi, mem_rtx));
3579 insn = emit_insn (gen_movsi (operands[0], gen_rtx_SUBREG (SImode, regqi, 0)));
3580 jump = emit_jump_insn_after (gen_jump (div_end_label), insn);
3581 JUMP_LABEL (jump) = div_end_label;
3582 LABEL_NUSES (div_end_label) = 1;
3583 emit_barrier ();
3585 emit_label (div_label);
3586 ret = emit_library_call_value (gen_rtx_SYMBOL_REF (Pmode, "__divsi3"),
3587 operands[0], LCT_NORMAL,
3588 GET_MODE (operands[0]),
3589 operands[1], GET_MODE (operands[1]),
3590 operands[2], GET_MODE (operands[2]));
3591 if (ret != operands[0])
3592 emit_move_insn (operands[0], ret);
3594 emit_label (div_end_label);
3595 emit_insn (gen_blockage ());
3598 /* Implement TARGET_FUNCTION_VALUE. */
3599 static rtx
3600 microblaze_function_value (const_tree valtype,
3601 const_tree func ATTRIBUTE_UNUSED,
3602 bool outgoing ATTRIBUTE_UNUSED)
3604 return LIBCALL_VALUE (TYPE_MODE (valtype));
3607 /* Implement TARGET_SCHED_ADJUST_COST. */
3608 static int
3609 microblaze_adjust_cost (rtx_insn *, int dep_type, rtx_insn *, int cost,
3610 unsigned int)
3612 if (dep_type == REG_DEP_OUTPUT || dep_type == 0)
3613 return cost;
3614 return 0;
3617 /* Implement TARGET_LEGITIMATE_CONSTANT_P.
3619 At present, GAS doesn't understand li.[sd], so don't allow it
3620 to be generated at present. */
3621 static bool
3622 microblaze_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED, rtx x)
3625 if (microblaze_cannot_force_const_mem(mode, x))
3626 return false;
3628 if (GET_CODE (x) == CONST_DOUBLE)
3630 return microblaze_const_double_ok (x, GET_MODE (x));
3633 /* Handle Case of (const (plus unspec const_int)). */
3634 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x,0)) == PLUS)
3636 rtx p0, p1;
3638 p0 = XEXP (XEXP (x, 0), 0);
3639 p1 = XEXP (XEXP (x, 0), 1);
3641 if (GET_CODE(p1) == CONST_INT)
3643 /* Const offset from UNSPEC is not supported. */
3644 if ((GET_CODE (p0) == UNSPEC))
3645 return false;
3647 if ((GET_CODE (p0) == SYMBOL_REF || GET_CODE (p0) == LABEL_REF)
3648 && (microblaze_tls_symbol_p (p0) || !SMALL_INT (p1)))
3649 return false;
3653 return true;
3656 static rtx
3657 get_branch_target (rtx branch)
3659 if (CALL_P (branch))
3661 rtx call;
3663 call = XVECEXP (PATTERN (branch), 0, 0);
3664 if (GET_CODE (call) == SET)
3665 call = SET_SRC (call);
3666 if (GET_CODE (call) != CALL)
3667 abort ();
3668 return XEXP (XEXP (call, 0), 0);
3671 return NULL_RTX;
3674 /* Heuristics to identify where to insert at the
3675 fall through path of the caller function. If there
3676 is a call after the caller branch delay slot then
3677 we dont generate the instruction prefetch instruction.
3679 Scan up to 32 instructions after the call and checks
3680 for the JUMP and call instruction . If there is a call
3681 or JUMP instruction in the range of 32 instruction "wic"
3682 instruction wont be generated. Otherwise insert the "wic"
3683 instruction in the fall through of the call instruction
3684 four instruction after the call. before_4 is used for
3685 the position to insert "wic" instructions. before_16 is
3686 used to check for call and JUMP instruction for first
3687 15 insns. */
3689 static void
3690 insert_wic_for_ilb_runout (rtx_insn *first)
3692 rtx_insn *insn;
3693 rtx_insn *before_4 = 0;
3694 rtx_insn *before_16 = 0;
3695 int addr_offset = 0;
3696 int length;
3697 int wic_addr0 = 128 * 4;
3699 int first_addr = INSN_ADDRESSES (INSN_UID (first));
3701 for (insn = first; insn; insn = NEXT_INSN (insn))
3702 if (INSN_P (insn))
3704 addr_offset = INSN_ADDRESSES (INSN_UID (insn)) - first_addr;
3705 length = get_attr_length (insn);
3706 if (before_4 == 0 && addr_offset + length >= 4 * 4)
3707 before_4 = insn;
3709 if (JUMP_P(insn))
3710 return;
3711 if (before_16 == 0 && addr_offset + length >= 14 * 4)
3712 before_16 = insn;
3713 if (CALL_P (insn) || tablejump_p (insn, 0, 0))
3714 return;
3715 if (addr_offset + length >= 32 * 4)
3717 gcc_assert (before_4 && before_16);
3718 if (wic_addr0 > 4 * 4)
3720 insn =
3721 emit_insn_before (gen_iprefetch
3722 (gen_int_mode (addr_offset, SImode)),
3723 before_4);
3724 recog_memoized (insn);
3725 INSN_LOCATION (insn) = INSN_LOCATION (before_4);
3726 INSN_ADDRESSES_NEW (insn, INSN_ADDRESSES (INSN_UID (before_4)));
3727 return;
3733 /* Insert instruction prefetch instruction at the fall
3734 through path of the function call. */
3736 static void
3737 insert_wic (void)
3739 rtx_insn *insn;
3740 int i;
3741 basic_block bb, prev = 0;
3742 rtx branch_target = 0;
3744 shorten_branches (get_insns ());
3746 for (i = 0; i < n_basic_blocks_for_fn (cfun) - 1; i++)
3748 edge e;
3749 edge_iterator ei;
3750 bool simple_loop = false;
3752 bb = BASIC_BLOCK_FOR_FN (cfun, i);
3754 if (bb == NULL)
3755 continue;
3757 if ((prev != 0) && (prev != bb))
3758 continue;
3759 else
3760 prev = 0;
3762 FOR_EACH_EDGE (e, ei, bb->preds)
3763 if (e->src == bb)
3765 simple_loop = true;
3766 prev= e->dest;
3767 break;
3770 for (insn = BB_END (bb); insn; insn = PREV_INSN (insn))
3772 if (INSN_P (insn) && !simple_loop
3773 && CALL_P(insn))
3775 if ((branch_target = get_branch_target (insn)))
3776 insert_wic_for_ilb_runout (
3777 next_active_insn (next_active_insn (insn)));
3779 if (insn == BB_HEAD (bb))
3780 break;
3785 /* The reorg function defined through the macro
3786 TARGET_MACHINE_DEPENDENT_REORG. */
3788 static void
3789 microblaze_machine_dependent_reorg (void)
3791 if (TARGET_PREFETCH)
3793 compute_bb_for_insn ();
3794 loop_optimizer_init (AVOID_CFG_MODIFICATIONS);
3795 shorten_branches (get_insns ());
3796 insert_wic ();
3797 loop_optimizer_finalize ();
3798 free_bb_for_insn ();
3799 return;
3803 /* Implement TARGET_CONSTANT_ALIGNMENT. */
3805 static HOST_WIDE_INT
3806 microblaze_constant_alignment (const_tree exp, HOST_WIDE_INT align)
3808 if (TREE_CODE (exp) == STRING_CST || TREE_CODE (exp) == CONSTRUCTOR)
3809 return MAX (align, BITS_PER_WORD);
3810 return align;
3813 /* Implement TARGET_STARTING_FRAME_OFFSET. */
3815 static HOST_WIDE_INT
3816 microblaze_starting_frame_offset (void)
3818 return (crtl->outgoing_args_size + FIRST_PARM_OFFSET(FNDECL));
3821 #undef TARGET_ENCODE_SECTION_INFO
3822 #define TARGET_ENCODE_SECTION_INFO microblaze_encode_section_info
3824 #undef TARGET_ASM_GLOBALIZE_LABEL
3825 #define TARGET_ASM_GLOBALIZE_LABEL microblaze_globalize_label
3827 #undef TARGET_ASM_FUNCTION_PROLOGUE
3828 #define TARGET_ASM_FUNCTION_PROLOGUE microblaze_function_prologue
3830 #undef TARGET_ASM_FUNCTION_EPILOGUE
3831 #define TARGET_ASM_FUNCTION_EPILOGUE microblaze_function_epilogue
3833 #undef TARGET_RTX_COSTS
3834 #define TARGET_RTX_COSTS microblaze_rtx_costs
3836 #undef TARGET_CANNOT_FORCE_CONST_MEM
3837 #define TARGET_CANNOT_FORCE_CONST_MEM microblaze_cannot_force_const_mem
3839 #undef TARGET_ADDRESS_COST
3840 #define TARGET_ADDRESS_COST microblaze_address_cost
3842 #undef TARGET_ATTRIBUTE_TABLE
3843 #define TARGET_ATTRIBUTE_TABLE microblaze_attribute_table
3845 #undef TARGET_IN_SMALL_DATA_P
3846 #define TARGET_IN_SMALL_DATA_P microblaze_elf_in_small_data_p
3848 #undef TARGET_ASM_SELECT_SECTION
3849 #define TARGET_ASM_SELECT_SECTION microblaze_select_section
3851 #undef TARGET_HAVE_SRODATA_SECTION
3852 #define TARGET_HAVE_SRODATA_SECTION true
3854 #undef TARGET_ASM_FUNCTION_END_PROLOGUE
3855 #define TARGET_ASM_FUNCTION_END_PROLOGUE \
3856 microblaze_function_end_prologue
3858 #undef TARGET_ARG_PARTIAL_BYTES
3859 #define TARGET_ARG_PARTIAL_BYTES function_arg_partial_bytes
3861 #undef TARGET_FUNCTION_ARG
3862 #define TARGET_FUNCTION_ARG microblaze_function_arg
3864 #undef TARGET_FUNCTION_ARG_ADVANCE
3865 #define TARGET_FUNCTION_ARG_ADVANCE microblaze_function_arg_advance
3867 #undef TARGET_CAN_ELIMINATE
3868 #define TARGET_CAN_ELIMINATE microblaze_can_eliminate
3870 #undef TARGET_LEGITIMIZE_ADDRESS
3871 #define TARGET_LEGITIMIZE_ADDRESS microblaze_legitimize_address
3873 #undef TARGET_LEGITIMATE_ADDRESS_P
3874 #define TARGET_LEGITIMATE_ADDRESS_P microblaze_legitimate_address_p
3876 #undef TARGET_LRA_P
3877 #define TARGET_LRA_P hook_bool_void_false
3879 #undef TARGET_FRAME_POINTER_REQUIRED
3880 #define TARGET_FRAME_POINTER_REQUIRED microblaze_frame_pointer_required
3882 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
3883 #define TARGET_ASM_TRAMPOLINE_TEMPLATE microblaze_asm_trampoline_template
3885 #undef TARGET_TRAMPOLINE_INIT
3886 #define TARGET_TRAMPOLINE_INIT microblaze_trampoline_init
3888 #undef TARGET_PROMOTE_FUNCTION_MODE
3889 #define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
3891 #undef TARGET_FUNCTION_VALUE
3892 #define TARGET_FUNCTION_VALUE microblaze_function_value
3894 #undef TARGET_SECONDARY_RELOAD
3895 #define TARGET_SECONDARY_RELOAD microblaze_secondary_reload
3897 #undef TARGET_ASM_OUTPUT_MI_THUNK
3898 #define TARGET_ASM_OUTPUT_MI_THUNK microblaze_asm_output_mi_thunk
3900 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
3901 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true
3903 #undef TARGET_SCHED_ADJUST_COST
3904 #define TARGET_SCHED_ADJUST_COST microblaze_adjust_cost
3906 #undef TARGET_ASM_INIT_SECTIONS
3907 #define TARGET_ASM_INIT_SECTIONS microblaze_elf_asm_init_sections
3909 #undef TARGET_OPTION_OVERRIDE
3910 #define TARGET_OPTION_OVERRIDE microblaze_option_override
3912 #undef TARGET_LEGITIMATE_CONSTANT_P
3913 #define TARGET_LEGITIMATE_CONSTANT_P microblaze_legitimate_constant_p
3915 #undef TARGET_MACHINE_DEPENDENT_REORG
3916 #define TARGET_MACHINE_DEPENDENT_REORG microblaze_machine_dependent_reorg
3918 #undef TARGET_HARD_REGNO_MODE_OK
3919 #define TARGET_HARD_REGNO_MODE_OK microblaze_hard_regno_mode_ok
3921 #undef TARGET_MODES_TIEABLE_P
3922 #define TARGET_MODES_TIEABLE_P microblaze_modes_tieable_p
3924 #undef TARGET_CONSTANT_ALIGNMENT
3925 #define TARGET_CONSTANT_ALIGNMENT microblaze_constant_alignment
3927 #undef TARGET_STARTING_FRAME_OFFSET
3928 #define TARGET_STARTING_FRAME_OFFSET microblaze_starting_frame_offset
3930 struct gcc_target targetm = TARGET_INITIALIZER;
3932 #include "gt-microblaze.h"