c++: Fix ICE on constexpr placement new [PR115754]
[official-gcc.git] / gcc / config / microblaze / microblaze.cc
blob98ec6116ffda1664ba7d6f43f9070b49a1ef25d4
1 /* Subroutines used for code generation on Xilinx MicroBlaze.
2 Copyright (C) 2009-2024 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"
54 #include "opts.h"
56 /* This file should be included last. */
57 #include "target-def.h"
59 #define MICROBLAZE_VERSION_COMPARE(VA,VB) strverscmp (VA, VB)
61 /* Classifies an address.
63 ADDRESS_INVALID
64 An invalid address.
66 ADDRESS_REG
68 A natural register or a register + const_int offset address.
69 The register satisfies microblaze_valid_base_register_p and the
70 offset is a const_arith_operand.
72 ADDRESS_REG_INDEX
74 A natural register offset by the index contained in an index register. The base
75 register satisfies microblaze_valid_base_register_p and the index register
76 satisfies microblaze_valid_index_register_p
78 ADDRESS_CONST_INT
80 A signed 16/32-bit constant address.
82 ADDRESS_SYMBOLIC:
84 A constant symbolic address or a (register + symbol). */
86 enum microblaze_address_type
88 ADDRESS_INVALID,
89 ADDRESS_REG,
90 ADDRESS_REG_INDEX,
91 ADDRESS_CONST_INT,
92 ADDRESS_SYMBOLIC,
93 ADDRESS_GOTOFF,
94 ADDRESS_PLT,
95 ADDRESS_TLS,
96 ADDRESS_SYMBOLIC_TXT_REL
99 /* Classifies symbols
101 SYMBOL_TYPE_GENERAL
103 A general symbol. */
104 enum microblaze_symbol_type
106 SYMBOL_TYPE_INVALID,
107 SYMBOL_TYPE_GENERAL
110 /* TLS Address Type. */
111 enum tls_reloc {
112 TLS_GD,
113 TLS_LDM,
114 TLS_DTPREL,
115 TLS_IE,
116 TLS_LE
119 /* Classification of a MicroBlaze address. */
120 struct microblaze_address_info
122 enum microblaze_address_type type;
123 rtx regA; /* Contains valid values on ADDRESS_REG, ADDRESS_REG_INDEX,
124 ADDRESS_SYMBOLIC. */
125 rtx regB; /* Contains valid values on ADDRESS_REG_INDEX. */
126 rtx offset; /* Contains valid values on ADDRESS_CONST_INT and ADDRESS_REG. */
127 rtx symbol; /* Contains valid values on ADDRESS_SYMBOLIC. */
128 enum microblaze_symbol_type symbol_type;
129 enum tls_reloc tls_type;
132 /* Structure to be filled in by compute_frame_size with register
133 save masks, and offsets for the current function. */
135 struct GTY(()) microblaze_frame_info {
136 long total_size; /* # bytes that the entire frame takes up. */
137 long var_size; /* # bytes that variables take up. */
138 long args_size; /* # bytes that outgoing arguments take up. */
139 int link_debug_size; /* # bytes for the link reg and back pointer. */
140 int gp_reg_size; /* # bytes needed to store gp regs. */
141 long gp_offset; /* offset from new sp to store gp registers. */
142 long mask; /* mask of saved gp registers. */
143 int initialized; /* != 0 if frame size already calculated. */
144 int num_gp; /* number of gp registers saved. */
145 long insns_len; /* length of insns. */
146 int alloc_stack; /* Flag to indicate if the current function
147 must not create stack space. (As an optimization). */
150 /* Global variables for machine-dependent things. */
152 /* Toggle which pipleline interface to use. */
153 static GTY(()) int microblaze_sched_use_dfa = 0;
155 /* Threshold for data being put into the small data/bss area, instead
156 of the normal data area (references to the small data/bss area take
157 1 instruction, and use the global pointer, references to the normal
158 data area takes 2 instructions). */
159 int microblaze_section_threshold = -1;
161 /* Prevent scheduling potentially exception causing instructions in
162 delay slots. -mcpu=v3.00.a or v4.00.a turns this on. */
163 int microblaze_no_unsafe_delay;
165 /* Set to one if the targeted core has the CLZ insn. */
166 int microblaze_has_clz = 0;
168 /* Which CPU pipeline do we use. We haven't really standardized on a CPU
169 version having only a particular type of pipeline. There can still be
170 options on the CPU to scale pipeline features up or down. :(
171 Bad Presentation (??), so we let the MD file rely on the value of
172 this variable instead Making PIPE_5 the default. It should be backward
173 optimal with PIPE_3 MicroBlazes. */
174 enum pipeline_type microblaze_pipe = MICROBLAZE_PIPE_5;
176 /* High and low marks for floating point values which we will accept
177 as legitimate constants for TARGET_LEGITIMATE_CONSTANT_P. These are
178 initialized in override_options. */
179 REAL_VALUE_TYPE dfhigh, dflow, sfhigh, sflow;
181 /* Array giving truth value on whether or not a given hard register
182 can support a given mode. */
183 static char microblaze_hard_regno_mode_ok_p[(int)MAX_MACHINE_MODE]
184 [FIRST_PSEUDO_REGISTER];
186 /* Current frame information calculated by compute_frame_size. */
187 struct microblaze_frame_info current_frame_info;
189 /* Zero structure to initialize current_frame_info. */
190 struct microblaze_frame_info zero_frame_info;
192 /* List of all MICROBLAZE punctuation characters used by print_operand. */
193 char microblaze_print_operand_punct[256];
195 /* Map GCC register number to debugger register number. */
196 int microblaze_debugger_regno[FIRST_PSEUDO_REGISTER];
198 /* Map hard register number to register class. */
199 enum reg_class microblaze_regno_to_class[] =
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 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
208 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
209 ST_REGS, GR_REGS, GR_REGS, GR_REGS
212 /* MicroBlaze specific machine attributes.
213 interrupt_handler - Interrupt handler attribute to add interrupt prologue
214 and epilogue and use appropriate interrupt return.
215 save_volatiles - Similar to interrupt handler, but use normal return. */
216 int interrupt_handler;
217 int break_handler;
218 int fast_interrupt;
219 int save_volatiles;
221 TARGET_GNU_ATTRIBUTES (microblaze_attribute_table, {
222 /* name min_len, max_len, decl_req, type_req, fn_type_req,
223 affects_type_identity, handler, exclude */
224 {"interrupt_handler", 0, 0, true, false, false, false, NULL, NULL },
225 {"break_handler", 0, 0, true, false, false, false, NULL, NULL },
226 {"fast_interrupt", 0, 0, true, false, false, false, NULL, NULL },
227 {"save_volatiles", 0, 0, true, false, false, false, NULL, NULL }
230 static int microblaze_interrupt_function_p (tree);
232 static void microblaze_elf_asm_constructor (rtx, int) ATTRIBUTE_UNUSED;
233 static void microblaze_elf_asm_destructor (rtx, int) ATTRIBUTE_UNUSED;
235 section *sdata2_section;
237 #ifdef HAVE_AS_TLS
238 #undef TARGET_HAVE_TLS
239 #define TARGET_HAVE_TLS true
240 #endif
242 /* Return truth value if a CONST_DOUBLE is ok to be a legitimate constant. */
243 static bool
244 microblaze_const_double_ok (rtx op, machine_mode mode)
246 REAL_VALUE_TYPE d;
248 if (GET_CODE (op) != CONST_DOUBLE)
249 return 0;
251 if (GET_MODE (op) == VOIDmode)
252 return 1;
254 if (mode != SFmode && mode != DFmode)
255 return 0;
257 if (op == CONST0_RTX (mode))
258 return 1;
260 d = *CONST_DOUBLE_REAL_VALUE (op);
262 if (REAL_VALUE_ISNAN (d))
263 return FALSE;
265 if (REAL_VALUE_NEGATIVE (d))
266 d = real_value_negate (&d);
268 if (mode == DFmode)
270 if (real_less (&d, &dfhigh) && real_less (&dflow, &d))
271 return 1;
273 else
275 if (real_less (&d, &sfhigh) && real_less (&sflow, &d))
276 return 1;
279 return 0;
282 /* Return truth value if a memory operand fits in a single instruction
283 (ie, register + small offset) or (register + register). */
286 simple_memory_operand (rtx op, machine_mode mode ATTRIBUTE_UNUSED)
288 rtx addr, plus0, plus1;
290 /* Eliminate non-memory operations. */
291 if (GET_CODE (op) != MEM)
292 return 0;
294 /* dword operations really put out 2 instructions, so eliminate them. */
295 /* ??? This isn't strictly correct. It is OK to accept multiword modes
296 here, since the length attributes are being set correctly, but only
297 if the address is offsettable. */
298 if (GET_MODE_SIZE (GET_MODE (op)) > UNITS_PER_WORD)
299 return 0;
302 /* Decode the address now. */
303 addr = XEXP (op, 0);
304 switch (GET_CODE (addr))
307 case REG:
308 return 1;
310 case PLUS:
311 plus0 = XEXP (addr, 0);
312 plus1 = XEXP (addr, 1);
314 if (GET_CODE (plus0) != REG)
315 return 0;
317 if (GET_CODE (plus0) == REG && GET_CODE (plus1) == CONST_INT
318 && SMALL_INT (plus1))
320 return 1;
322 else if (GET_CODE (plus1) == REG && GET_CODE (plus0) == CONST_INT)
324 return 1;
326 else if (GET_CODE (plus0) == REG && GET_CODE (plus1) == REG)
328 return 1;
330 else
331 return 0;
333 case SYMBOL_REF:
334 return 0;
336 default:
337 break;
340 return 0;
343 /* Return nonzero for a memory address that can be used to load or store
344 a doubleword. */
347 double_memory_operand (rtx op, machine_mode mode)
349 rtx addr;
351 if (GET_CODE (op) != MEM || !memory_operand (op, mode))
353 /* During reload, we accept a pseudo register if it has an
354 appropriate memory address. If we don't do this, we will
355 wind up reloading into a register, and then reloading that
356 register from memory, when we could just reload directly from
357 memory. */
358 if (reload_in_progress
359 && GET_CODE (op) == REG
360 && REGNO (op) >= FIRST_PSEUDO_REGISTER
361 && reg_renumber[REGNO (op)] < 0
362 && reg_equiv_mem (REGNO (op)) != 0
363 && double_memory_operand (reg_equiv_mem (REGNO (op)), mode))
364 return 1;
365 return 0;
368 /* Make sure that 4 added to the address is a valid memory address.
369 This essentially just checks for overflow in an added constant. */
371 addr = XEXP (op, 0);
373 if (CONSTANT_ADDRESS_P (addr))
374 return 1;
376 return memory_address_p ((GET_MODE_CLASS (mode) == MODE_INT
377 ? E_SImode : E_SFmode),
378 plus_constant (Pmode, addr, 4));
381 /* Implement REG_OK_FOR_BASE_P -and- REG_OK_FOR_INDEX_P. */
383 microblaze_regno_ok_for_base_p (int regno, int strict)
385 if (regno >= FIRST_PSEUDO_REGISTER)
387 if (!strict)
388 return true;
389 regno = reg_renumber[regno];
392 /* These fake registers will be eliminated to either the stack or
393 hard frame pointer, both of which are usually valid base registers.
394 Reload deals with the cases where the eliminated form isn't valid. */
395 if (regno == ARG_POINTER_REGNUM || regno == FRAME_POINTER_REGNUM)
396 return true;
398 return GP_REG_P (regno);
401 /* Return true if X is a valid base register for the given mode.
402 Allow only hard registers if STRICT. */
404 static bool
405 microblaze_valid_base_register_p (rtx x,
406 machine_mode mode ATTRIBUTE_UNUSED,
407 int strict)
409 if (!strict && GET_CODE (x) == SUBREG)
410 x = SUBREG_REG (x);
412 return (GET_CODE (x) == REG
413 && microblaze_regno_ok_for_base_p (REGNO (x), strict));
416 /* Build the SYMBOL_REF for __tls_get_addr. */
418 static GTY(()) rtx tls_get_addr_libfunc;
420 static rtx
421 get_tls_get_addr (void)
423 if (!tls_get_addr_libfunc)
424 tls_get_addr_libfunc = init_one_libfunc ("__tls_get_addr");
425 return tls_get_addr_libfunc;
428 /* Return TRUE if X is a thread-local symbol. */
429 bool
430 microblaze_tls_symbol_p (rtx x)
432 if (!TARGET_HAVE_TLS)
433 return false;
435 if (GET_CODE (x) != SYMBOL_REF)
436 return false;
438 return SYMBOL_REF_TLS_MODEL (x) != 0;
441 /* Return TRUE if X contains any TLS symbol references. */
443 bool
444 microblaze_tls_referenced_p (rtx x)
446 if (!TARGET_HAVE_TLS)
447 return false;
448 subrtx_iterator::array_type array;
449 FOR_EACH_SUBRTX (iter, array, x, ALL)
451 const_rtx x = *iter;
452 if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (x) != 0)
453 return true;
454 /* Don't recurse into UNSPEC_TLS looking for TLS symbols; these are
455 TLS offsets, not real symbol references. */
456 if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLS)
457 iter.skip_subrtxes ();
459 return false;
462 bool
463 microblaze_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED, rtx x)
465 return microblaze_tls_referenced_p(x);
468 /* Return TRUE if X references a SYMBOL_REF. */
470 symbol_mentioned_p (rtx x)
472 const char * fmt;
473 int i;
475 if (GET_CODE (x) == SYMBOL_REF)
476 return 1;
478 /* UNSPEC entries for a symbol include the SYMBOL_REF, but they
479 are constant offsets, not symbols. */
480 if (GET_CODE (x) == UNSPEC)
481 return 0;
483 fmt = GET_RTX_FORMAT (GET_CODE (x));
485 for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
487 if (fmt[i] == 'E')
489 int j;
491 for (j = XVECLEN (x, i) - 1; j >= 0; j--)
492 if (symbol_mentioned_p (XVECEXP (x, i, j)))
493 return 1;
495 else if (fmt[i] == 'e' && symbol_mentioned_p (XEXP (x, i)))
496 return 1;
499 return 0;
502 /* Return TRUE if X references a LABEL_REF. */
504 label_mentioned_p (rtx x)
506 const char * fmt;
507 int i;
509 if (GET_CODE (x) == LABEL_REF)
510 return 1;
512 /* UNSPEC entries for a symbol include a LABEL_REF for the referencing
513 instruction, but they are constant offsets, not symbols. */
514 if (GET_CODE (x) == UNSPEC)
515 return 0;
517 fmt = GET_RTX_FORMAT (GET_CODE (x));
518 for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
520 if (fmt[i] == 'E')
522 int j;
524 for (j = XVECLEN (x, i) - 1; j >= 0; j--)
525 if (label_mentioned_p (XVECEXP (x, i, j)))
526 return 1;
528 else if (fmt[i] == 'e' && label_mentioned_p (XEXP (x, i)))
529 return 1;
532 return 0;
536 tls_mentioned_p (rtx x)
538 switch (GET_CODE (x))
540 case CONST:
541 return tls_mentioned_p (XEXP (x, 0));
543 case UNSPEC:
544 if (XINT (x, 1) == UNSPEC_TLS)
545 return 1;
546 return 0;
548 default:
549 return 0;
553 static rtx
554 load_tls_operand (rtx x, rtx reg)
556 rtx tmp;
558 if (reg == NULL_RTX)
559 reg = gen_reg_rtx (Pmode);
561 tmp = gen_rtx_CONST (Pmode, x);
563 emit_insn (gen_rtx_SET (reg,
564 gen_rtx_PLUS (Pmode, pic_offset_table_rtx, tmp)));
566 return reg;
569 static rtx_insn *
570 microblaze_call_tls_get_addr (rtx x, rtx reg, rtx *valuep, int reloc)
572 rtx_insn *insns;
573 rtx tls_entry;
575 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
577 start_sequence ();
579 tls_entry = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, x, GEN_INT (reloc)),
580 UNSPEC_TLS);
582 reg = load_tls_operand (tls_entry, reg);
584 *valuep = emit_library_call_value (get_tls_get_addr (), NULL_RTX,
585 LCT_PURE, /* LCT_CONST? */
586 Pmode, reg, Pmode);
588 insns = get_insns ();
589 end_sequence ();
591 return insns;
595 microblaze_legitimize_tls_address(rtx x, rtx reg)
597 rtx dest, ret, eqv, addend;
598 rtx_insn *insns;
599 enum tls_model model;
600 model = SYMBOL_REF_TLS_MODEL (x);
602 switch (model)
604 case TLS_MODEL_LOCAL_DYNAMIC:
605 case TLS_MODEL_GLOBAL_DYNAMIC:
606 case TLS_MODEL_INITIAL_EXEC:
607 insns = microblaze_call_tls_get_addr (x, reg, &ret, TLS_GD);
608 dest = gen_reg_rtx (Pmode);
609 emit_libcall_block (insns, dest, ret, x);
610 break;
612 case TLS_MODEL_LOCAL_EXEC:
613 insns = microblaze_call_tls_get_addr (x, reg, &ret, TLS_LDM);
615 /* Attach a unique REG_EQUIV, to allow the RTL optimizers to
616 share the LDM result with other LD model accesses. */
617 eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const1_rtx), UNSPEC_TLS);
618 dest = gen_reg_rtx (Pmode);
619 emit_libcall_block (insns, dest, ret, eqv);
621 /* Load the addend. */
622 addend = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, x, GEN_INT (TLS_DTPREL)),
623 UNSPEC_TLS);
624 addend = force_reg (SImode, gen_rtx_CONST (SImode, addend));
625 dest = gen_rtx_PLUS (Pmode, dest, addend);
626 break;
628 default:
629 gcc_unreachable ();
631 return dest;
634 static bool
635 microblaze_classify_unspec (struct microblaze_address_info *info, rtx x)
637 info->symbol_type = SYMBOL_TYPE_GENERAL;
638 info->symbol = XVECEXP (x, 0, 0);
640 if (XINT (x, 1) == UNSPEC_GOTOFF)
642 info->regA = gen_rtx_REG (SImode, PIC_OFFSET_TABLE_REGNUM);
643 info->type = ADDRESS_GOTOFF;
645 else if (XINT (x, 1) == UNSPEC_PLT)
647 info->type = ADDRESS_PLT;
649 else if (XINT (x, 1) == UNSPEC_TLS)
651 info->type = ADDRESS_TLS;
652 info->tls_type = tls_reloc (INTVAL (XVECEXP (x, 0, 1)));
654 else if (XINT (x, 1) == UNSPEC_TEXT)
656 info->type = ADDRESS_SYMBOLIC_TXT_REL;
658 else
660 return false;
662 return true;
666 /* Return true if X is a valid index register for the given mode.
667 Allow only hard registers if STRICT. */
669 static bool
670 microblaze_valid_index_register_p (rtx x,
671 machine_mode mode ATTRIBUTE_UNUSED,
672 int strict)
674 if (!strict && GET_CODE (x) == SUBREG)
675 x = SUBREG_REG (x);
677 return (GET_CODE (x) == REG
678 /* A base register is good enough to be an index register on MicroBlaze. */
679 && microblaze_regno_ok_for_base_p (REGNO (x), strict));
682 /* Get the base register for accessing a value from the memory or
683 Symbol ref. Used for MicroBlaze Small Data Area Pointer Optimization. */
684 static int
685 get_base_reg (rtx x)
687 tree decl;
688 int base_reg;
690 if (!flag_pic || microblaze_tls_symbol_p(x))
691 base_reg = MB_ABI_BASE_REGNUM;
692 else if (flag_pic)
693 base_reg = MB_ABI_PIC_ADDR_REGNUM;
695 if (TARGET_XLGPOPT
696 && GET_CODE (x) == SYMBOL_REF
697 && SYMBOL_REF_SMALL_P (x) && (decl = SYMBOL_REF_DECL (x)) != NULL)
699 if (TREE_READONLY (decl))
700 base_reg = MB_ABI_GPRO_REGNUM;
701 else
702 base_reg = MB_ABI_GPRW_REGNUM;
705 return base_reg;
708 /* Return true if X is a valid address for machine mode MODE. If it is,
709 fill in INFO appropriately.
710 STRICT > 0 if we should only accept hard base registers.
711 STRICT = 2 if the operand address is being printed thus
712 function has been called by print_operand_address.
714 type regA regB offset symbol
716 ADDRESS_INVALID NULL NULL NULL NULL
718 ADDRESS_REG %0 NULL const_0 / NULL
719 const_int
720 ADDRESS_REG_INDEX %0 %1 NULL NULL
722 ADDRESS_SYMBOLIC r0 / NULL NULL symbol
723 sda_base_reg
725 ADDRESS_CONST_INT r0 NULL const NULL
727 For modes spanning multiple registers (DFmode in 32-bit GPRs,
728 DImode, TImode), indexed addressing cannot be used because
729 adjacent memory cells are accessed by adding word-sized offsets
730 during assembly output. */
732 static bool
733 microblaze_classify_address (struct microblaze_address_info *info, rtx x,
734 machine_mode mode, int strict)
736 rtx xplus0;
737 rtx xplus1;
738 rtx offset;
740 info->type = ADDRESS_INVALID;
741 info->regA = NULL;
742 info->regB = NULL;
743 info->offset = NULL;
744 info->symbol = NULL;
745 info->symbol_type = SYMBOL_TYPE_INVALID;
746 offset = NULL;
748 switch (GET_CODE (x))
750 case REG:
751 case SUBREG:
753 info->type = ADDRESS_REG;
754 info->regA = x;
755 info->offset = const0_rtx;
756 return microblaze_valid_base_register_p (info->regA, mode, strict);
758 case PLUS:
760 xplus0 = XEXP (x, 0);
761 xplus1 = XEXP (x, 1);
763 if (microblaze_valid_base_register_p (xplus0, mode, strict))
765 info->type = ADDRESS_REG;
766 info->regA = xplus0;
768 if (GET_CODE (xplus1) == CONST_INT)
770 info->offset = xplus1;
771 return true;
773 else if (GET_CODE (xplus1) == UNSPEC)
775 /* Need offsettable address. */
776 if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
777 return false;
779 return microblaze_classify_unspec (info, xplus1);
781 else if ((GET_CODE (xplus1) == SYMBOL_REF ||
782 GET_CODE (xplus1) == LABEL_REF))
784 if (flag_pic == 2 || microblaze_tls_symbol_p(xplus1))
785 return false;
786 info->type = ADDRESS_SYMBOLIC;
787 info->symbol = xplus1;
788 info->symbol_type = SYMBOL_TYPE_GENERAL;
789 return true;
791 else if (GET_CODE (xplus1) == CONST)
793 rtx xconst0 = XEXP(xplus1, 0);
795 /* base + unspec. */
796 if (GET_CODE (xconst0) == UNSPEC)
798 /* Need offsettable address. */
799 if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
800 return false;
801 return microblaze_classify_unspec(info, xconst0);
804 /* for (plus x const_int) just look at x. */
805 if (GET_CODE (xconst0) == PLUS
806 && GET_CODE (XEXP (xconst0, 1)) == CONST_INT
807 && (SMALL_INT (XEXP (xconst0, 1))
808 || GET_CODE (XEXP (xconst0, 0)) == UNSPEC))
810 /* Hold CONST_INT Value in offset in case of
811 UNSPEC + CONST_INT. */
812 offset = XEXP (xconst0, 1);
814 /* This is ok as info->symbol is set to xplus1 the full
815 const-expression below. */
816 xconst0 = XEXP (xconst0, 0);
819 if (GET_CODE (xconst0) == SYMBOL_REF
820 || GET_CODE (xconst0) == LABEL_REF)
822 if (flag_pic == 2 || microblaze_tls_symbol_p(xconst0))
823 return false;
825 info->type = ADDRESS_SYMBOLIC;
826 info->symbol = xplus1;
827 info->symbol_type = SYMBOL_TYPE_GENERAL;
828 return true;
831 if (GET_CODE (xconst0) == UNSPEC && TARGET_PIC_DATA_TEXT_REL)
833 if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
834 return false;
836 info->offset = offset;
837 return microblaze_classify_unspec (info, xconst0);
840 /* Not base + symbol || base + UNSPEC. */
841 return false;
844 else if (GET_CODE (xplus1) == REG
845 && microblaze_valid_index_register_p (xplus1, mode,
846 strict)
847 && (GET_MODE_SIZE (mode) <= UNITS_PER_WORD))
849 /* Restrict larger than word-width modes from using an index register. */
850 info->type = ADDRESS_REG_INDEX;
851 info->regB = xplus1;
852 return true;
855 break;
857 case CONST_INT:
859 info->regA = gen_raw_REG (mode, 0);
860 info->type = ADDRESS_CONST_INT;
861 info->offset = x;
862 return true;
864 case CONST:
865 case LABEL_REF:
866 case SYMBOL_REF:
868 info->type = ADDRESS_SYMBOLIC;
869 info->symbol_type = SYMBOL_TYPE_GENERAL;
870 info->symbol = x;
871 info->regA = gen_raw_REG (mode, get_base_reg (x));
873 if (GET_CODE (x) == CONST)
875 if (GET_CODE (XEXP (x, 0)) == UNSPEC)
877 info->regA = gen_raw_REG (mode,
878 get_base_reg (XVECEXP (XEXP (x,0), 0, 0)));
879 return microblaze_classify_unspec (info, XEXP (x, 0));
881 return !(flag_pic && pic_address_needs_scratch (x));
884 /* Avoid error in print_operand_address in case UNSPEC
885 is removed from SYMBOL or LABEL REFS during optimization. */
886 if ((GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF)
887 && flag_pic && TARGET_PIC_DATA_TEXT_REL && strict == 2)
889 info->type = ADDRESS_SYMBOLIC_TXT_REL;
890 return true;
893 if (flag_pic == 2)
894 return false;
895 else if (microblaze_tls_symbol_p(x))
896 return false;
898 return true;
901 case UNSPEC:
903 if (reload_in_progress)
904 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
905 return microblaze_classify_unspec (info, x);
908 default:
909 return false;
912 return false;
915 /* This function is used to implement GO_IF_LEGITIMATE_ADDRESS. It
916 returns a nonzero value if X is a legitimate address for a memory
917 operand of the indicated MODE. STRICT is nonzero if this function
918 is called during reload. */
920 bool
921 microblaze_legitimate_address_p (machine_mode mode, rtx x, bool strict,
922 code_helper)
924 struct microblaze_address_info addr;
926 return microblaze_classify_address (&addr, x, mode, strict);
929 bool
930 microblaze_constant_address_p (rtx x)
932 return ((GET_CODE (x) == LABEL_REF) || (GET_CODE (x) == SYMBOL_REF)
933 || GET_CODE (x) == CONST_INT
934 || (GET_CODE (x) == CONST
935 && ! (flag_pic && pic_address_needs_scratch (x))));
939 microblaze_valid_pic_const (rtx x)
941 switch (GET_CODE (x))
943 case CONST:
944 case CONST_INT:
945 case CONST_DOUBLE:
946 return true;
947 default:
948 return false;
953 microblaze_legitimate_pic_operand (rtx x)
955 if (flag_pic == 2 && (symbol_mentioned_p (x) || label_mentioned_p (x))
956 && !(TARGET_PIC_DATA_TEXT_REL && call_insn_operand (x,VOIDmode)))
957 return 0;
959 if (microblaze_tls_referenced_p(x))
960 return 0;
962 return 1;
965 /* Try machine-dependent ways of modifying an illegitimate address
966 to be legitimate. If we find one, return the new, valid address.
967 This is used from only one place: `memory_address' in explow.cc.
969 OLDX is the address as it was before break_out_memory_refs was
970 called. In some cases it is useful to look at this to decide what
971 needs to be done.
973 It is always safe for this function to do nothing. It exists to
974 recognize opportunities to optimize the output.
976 For the MicroBlaze, transform:
978 memory(X + <large int>)
980 into:
982 Y = <large int> & ~0x7fff;
983 Z = X + Y
984 memory (Z + (<large int> & 0x7fff));
986 This is for CSE to find several similar references, and only use one Z.
988 When PIC, convert addresses of the form memory (symbol+large int) to
989 memory (reg+large int). */
991 static rtx
992 microblaze_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
993 machine_mode mode ATTRIBUTE_UNUSED)
995 rtx xinsn = x, result;
997 if (GET_CODE (xinsn) == CONST
998 && flag_pic && pic_address_needs_scratch (xinsn))
1000 rtx ptr_reg = gen_reg_rtx (Pmode);
1001 rtx constant = XEXP (XEXP (xinsn, 0), 1);
1003 emit_move_insn (ptr_reg, XEXP (XEXP (xinsn, 0), 0));
1005 result = gen_rtx_PLUS (Pmode, ptr_reg, constant);
1006 if (SMALL_INT (constant))
1007 return result;
1008 /* Otherwise we fall through so the code below will fix the
1009 constant. */
1010 xinsn = result;
1013 if (GET_CODE (xinsn) == PLUS)
1015 rtx xplus0 = XEXP (xinsn, 0);
1016 rtx xplus1 = XEXP (xinsn, 1);
1017 enum rtx_code code0 = GET_CODE (xplus0);
1018 enum rtx_code code1 = GET_CODE (xplus1);
1020 if (code0 != REG && code1 == REG)
1022 xplus0 = XEXP (xinsn, 1);
1023 xplus1 = XEXP (xinsn, 0);
1024 code0 = GET_CODE (xplus0);
1025 code1 = GET_CODE (xplus1);
1028 if (code0 == REG && REG_OK_FOR_BASE_P (xplus0)
1029 && code1 == CONST_INT && !SMALL_INT (xplus1))
1031 rtx int_reg = gen_reg_rtx (Pmode);
1032 rtx ptr_reg = gen_reg_rtx (Pmode);
1034 emit_move_insn (int_reg, GEN_INT (INTVAL (xplus1) & ~0x7fff));
1036 emit_insn (gen_rtx_SET (ptr_reg,
1037 gen_rtx_PLUS (Pmode, xplus0, int_reg)));
1039 result = gen_rtx_PLUS (Pmode, ptr_reg,
1040 GEN_INT (INTVAL (xplus1) & 0x7fff));
1041 return result;
1044 if (code0 == REG && REG_OK_FOR_BASE_P (xplus0))
1046 if (reload_in_progress)
1047 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
1048 if (code1 == CONST)
1050 xplus1 = XEXP (xplus1, 0);
1051 code1 = GET_CODE (xplus1);
1053 if (code1 == SYMBOL_REF)
1055 if (microblaze_tls_symbol_p(xplus1))
1057 rtx tls_ref, reg;
1058 reg = gen_reg_rtx (Pmode);
1060 tls_ref = microblaze_legitimize_tls_address (xplus1,
1061 NULL_RTX);
1062 emit_move_insn (reg, tls_ref);
1064 result = gen_rtx_PLUS (Pmode, xplus0, reg);
1066 return result;
1068 else if (flag_pic == 2)
1070 if (!TARGET_PIC_DATA_TEXT_REL)
1072 rtx pic_ref, reg;
1073 reg = gen_reg_rtx (Pmode);
1075 pic_ref = gen_rtx_UNSPEC (Pmode,
1076 gen_rtvec (1, xplus1),
1077 UNSPEC_GOTOFF);
1078 pic_ref = gen_rtx_CONST (Pmode, pic_ref);
1079 pic_ref = gen_rtx_PLUS (Pmode,
1080 pic_offset_table_rtx, pic_ref);
1081 pic_ref = gen_const_mem (Pmode, pic_ref);
1082 emit_move_insn (reg, pic_ref);
1083 result = gen_rtx_PLUS (Pmode, xplus0, reg);
1084 return result;
1086 else
1088 rtx pic_ref, reg;
1089 reg = gen_reg_rtx (Pmode);
1090 pic_ref = gen_rtx_UNSPEC (Pmode,
1091 gen_rtvec (1, xplus1),
1092 UNSPEC_TEXT);
1093 pic_ref = gen_rtx_CONST (Pmode, pic_ref);
1094 emit_insn (gen_addsi3 (reg,
1095 pic_offset_table_rtx, xplus0));
1096 result = gen_rtx_PLUS (Pmode, reg, pic_ref);
1097 return result;
1104 if (GET_CODE (xinsn) == SYMBOL_REF)
1106 rtx reg = NULL;
1107 if (microblaze_tls_symbol_p(xinsn))
1109 reg = microblaze_legitimize_tls_address (xinsn, NULL_RTX);
1111 else if (flag_pic == 2)
1113 if (reload_in_progress)
1114 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
1116 if (!TARGET_PIC_DATA_TEXT_REL)
1118 rtx pic_ref;
1120 pic_ref = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, xinsn), UNSPEC_GOTOFF);
1121 pic_ref = gen_rtx_CONST (Pmode, pic_ref);
1122 pic_ref = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, pic_ref);
1123 pic_ref = gen_const_mem (Pmode, pic_ref);
1124 reg = pic_ref;
1126 else
1128 rtx pic_ref;
1130 pic_ref = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, xinsn), UNSPEC_TEXT);
1131 pic_ref = gen_rtx_CONST (Pmode, pic_ref);
1132 pic_ref = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, pic_ref);
1133 reg = pic_ref;
1136 else
1138 /* This should never happen. */
1139 gcc_unreachable ();
1141 return reg;
1144 return x;
1147 /* Block Moves. */
1149 #define MAX_MOVE_REGS 8
1150 #define MAX_MOVE_BYTES (MAX_MOVE_REGS * UNITS_PER_WORD)
1152 /* Emit straight-line code to move LENGTH bytes from SRC to DEST.
1153 Assume that the areas do not overlap. */
1155 static void
1156 microblaze_block_move_straight (rtx dest, rtx src, HOST_WIDE_INT length)
1158 HOST_WIDE_INT offset, delta;
1159 unsigned HOST_WIDE_INT bits;
1160 int i;
1161 machine_mode mode;
1162 rtx *regs;
1164 bits = BITS_PER_WORD;
1165 mode = int_mode_for_size (bits, 0).require ();
1166 delta = bits / BITS_PER_UNIT;
1168 /* Allocate a buffer for the temporary registers. */
1169 regs = XALLOCAVEC (rtx, length / delta);
1171 /* Load as many BITS-sized chunks as possible. Use a normal load if
1172 the source has enough alignment, otherwise use left/right pairs. */
1173 for (offset = 0, i = 0; offset + delta <= length; offset += delta, i++)
1175 regs[i] = gen_reg_rtx (mode);
1176 emit_move_insn (regs[i], adjust_address (src, mode, offset));
1179 /* Copy the chunks to the destination. */
1180 for (offset = 0, i = 0; offset + delta <= length; offset += delta, i++)
1181 emit_move_insn (adjust_address (dest, mode, offset), regs[i]);
1183 /* Mop up any left-over bytes. */
1184 if (offset < length)
1186 src = adjust_address (src, BLKmode, offset);
1187 dest = adjust_address (dest, BLKmode, offset);
1188 move_by_pieces (dest, src, length - offset,
1189 MIN (MEM_ALIGN (src), MEM_ALIGN (dest)), RETURN_BEGIN);
1193 /* Helper function for doing a loop-based block operation on memory
1194 reference MEM. Each iteration of the loop will operate on LENGTH
1195 bytes of MEM.
1197 Create a new base register for use within the loop and point it to
1198 the start of MEM. Create a new memory reference that uses this
1199 register. Store them in *LOOP_REG and *LOOP_MEM respectively. */
1201 static void
1202 microblaze_adjust_block_mem (rtx mem, HOST_WIDE_INT length,
1203 rtx * loop_reg, rtx * loop_mem)
1205 *loop_reg = copy_addr_to_reg (XEXP (mem, 0));
1207 /* Although the new mem does not refer to a known location,
1208 it does keep up to LENGTH bytes of alignment. */
1209 *loop_mem = change_address (mem, BLKmode, *loop_reg);
1210 set_mem_align (*loop_mem,
1211 MIN ((HOST_WIDE_INT) MEM_ALIGN (mem),
1212 length * BITS_PER_UNIT));
1216 /* Move LENGTH bytes from SRC to DEST using a loop that moves MAX_MOVE_BYTES
1217 per iteration. LENGTH must be at least MAX_MOVE_BYTES. Assume that the
1218 memory regions do not overlap. */
1220 static void
1221 microblaze_block_move_loop (rtx dest, rtx src, HOST_WIDE_INT length)
1223 rtx_code_label *label;
1224 rtx src_reg, dest_reg, final_src;
1225 HOST_WIDE_INT leftover;
1227 leftover = length % MAX_MOVE_BYTES;
1228 length -= leftover;
1230 /* Create registers and memory references for use within the loop. */
1231 microblaze_adjust_block_mem (src, MAX_MOVE_BYTES, &src_reg, &src);
1232 microblaze_adjust_block_mem (dest, MAX_MOVE_BYTES, &dest_reg, &dest);
1234 /* Calculate the value that SRC_REG should have after the last iteration
1235 of the loop. */
1236 final_src = expand_simple_binop (Pmode, PLUS, src_reg, GEN_INT (length),
1237 0, 0, OPTAB_WIDEN);
1239 /* Emit the start of the loop. */
1240 label = gen_label_rtx ();
1241 emit_label (label);
1243 /* Emit the loop body. */
1244 microblaze_block_move_straight (dest, src, MAX_MOVE_BYTES);
1246 /* Move on to the next block. */
1247 emit_move_insn (src_reg, plus_constant (Pmode, src_reg, MAX_MOVE_BYTES));
1248 emit_move_insn (dest_reg, plus_constant (Pmode, dest_reg, MAX_MOVE_BYTES));
1250 /* Emit the test & branch. */
1251 emit_insn (gen_cbranchsi4 (gen_rtx_NE (SImode, src_reg, final_src),
1252 src_reg, final_src, label));
1254 /* Mop up any left-over bytes. */
1255 if (leftover)
1256 microblaze_block_move_straight (dest, src, leftover);
1259 /* Expand a cpymemsi instruction. */
1261 bool
1262 microblaze_expand_block_move (rtx dest, rtx src, rtx length, rtx align_rtx)
1265 if (GET_CODE (length) == CONST_INT)
1267 unsigned HOST_WIDE_INT bytes = UINTVAL (length);
1268 unsigned int align = UINTVAL (align_rtx);
1270 if (align > UNITS_PER_WORD)
1272 align = UNITS_PER_WORD; /* We can't do any better. */
1274 else if (align < UNITS_PER_WORD)
1276 if (UINTVAL (length) <= MAX_MOVE_BYTES)
1278 move_by_pieces (dest, src, bytes, align, RETURN_BEGIN);
1279 return true;
1281 else
1282 return false;
1285 if (UINTVAL (length) <= 2 * MAX_MOVE_BYTES)
1287 microblaze_block_move_straight (dest, src, UINTVAL (length));
1288 return true;
1290 else if (optimize)
1292 microblaze_block_move_loop (dest, src, UINTVAL (length));
1293 return true;
1296 return false;
1299 static bool
1300 microblaze_rtx_costs (rtx x, machine_mode mode, int outer_code ATTRIBUTE_UNUSED,
1301 int opno ATTRIBUTE_UNUSED, int *total,
1302 bool speed ATTRIBUTE_UNUSED)
1304 int code = GET_CODE (x);
1306 switch (code)
1308 case MEM:
1310 int num_words = (GET_MODE_SIZE (mode) > UNITS_PER_WORD) ? 2 : 1;
1311 if (simple_memory_operand (x, mode))
1312 *total = COSTS_N_INSNS (2 * num_words);
1313 else
1314 *total = COSTS_N_INSNS (2 * (2 * num_words));
1316 return true;
1318 case NOT:
1320 if (mode == DImode)
1322 *total = COSTS_N_INSNS (2);
1324 else
1325 *total = COSTS_N_INSNS (1);
1326 return false;
1328 case AND:
1329 case IOR:
1330 case XOR:
1332 if (mode == DImode)
1334 *total = COSTS_N_INSNS (2);
1336 else
1337 *total = COSTS_N_INSNS (1);
1339 return false;
1341 case ASHIFT:
1342 case ASHIFTRT:
1343 case LSHIFTRT:
1345 if (TARGET_BARREL_SHIFT)
1347 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v5.00.a")
1348 >= 0)
1349 *total = COSTS_N_INSNS (1);
1350 else
1351 *total = COSTS_N_INSNS (2);
1353 else if (!TARGET_SOFT_MUL)
1354 *total = COSTS_N_INSNS (1);
1355 else if (GET_CODE (XEXP (x, 1)) == CONST_INT)
1357 /* Add 1 to make shift slightly more expensive than add. */
1358 *total = COSTS_N_INSNS (INTVAL (XEXP (x, 1))) + 1;
1359 /* Reduce shift costs for special circumstances. */
1360 if (optimize_size && INTVAL (XEXP (x, 1)) > 5)
1361 *total -= 2;
1362 if (!optimize_size && INTVAL (XEXP (x, 1)) > 17)
1363 *total -= 2;
1365 else
1366 /* Double the worst cost of shifts when there is no barrel shifter and
1367 the shift amount is in a reg. */
1368 *total = COSTS_N_INSNS (32 * 4);
1369 return true;
1371 case PLUS:
1372 case MINUS:
1374 if (mode == SFmode || mode == DFmode)
1376 if (TARGET_HARD_FLOAT)
1377 *total = COSTS_N_INSNS (6);
1378 return true;
1380 else if (mode == DImode)
1382 *total = COSTS_N_INSNS (4);
1383 return true;
1385 else
1387 *total = COSTS_N_INSNS (1);
1388 return true;
1391 return false;
1393 case NEG:
1395 if (mode == DImode)
1396 *total = COSTS_N_INSNS (4);
1398 return false;
1400 case MULT:
1402 if (mode == SFmode)
1404 if (TARGET_HARD_FLOAT)
1405 *total = COSTS_N_INSNS (6);
1407 else if (!TARGET_SOFT_MUL)
1409 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v5.00.a")
1410 >= 0)
1411 *total = COSTS_N_INSNS (1);
1412 else
1413 *total = COSTS_N_INSNS (3);
1415 else
1416 *total = COSTS_N_INSNS (10);
1417 return true;
1419 case DIV:
1420 case UDIV:
1422 if (mode == SFmode)
1424 if (TARGET_HARD_FLOAT)
1425 *total = COSTS_N_INSNS (23);
1427 return false;
1429 case SIGN_EXTEND:
1431 *total = COSTS_N_INSNS (1);
1432 return false;
1434 case ZERO_EXTEND:
1436 *total = COSTS_N_INSNS (1);
1437 return false;
1441 return false;
1444 /* Return the number of instructions needed to load or store a value
1445 of mode MODE at X. Return 0 if X isn't valid for MODE. */
1447 static int
1448 microblaze_address_insns (rtx x, machine_mode mode)
1450 struct microblaze_address_info addr;
1452 if (microblaze_classify_address (&addr, x, mode, false))
1454 switch (addr.type)
1456 case ADDRESS_REG:
1457 if (SMALL_INT (addr.offset))
1458 return 1;
1459 else
1460 return 2;
1461 case ADDRESS_CONST_INT:
1462 if (SMALL_INT (x))
1463 return 1;
1464 else
1465 return 2;
1466 case ADDRESS_REG_INDEX:
1467 return 1;
1468 case ADDRESS_SYMBOLIC:
1469 case ADDRESS_SYMBOLIC_TXT_REL:
1470 case ADDRESS_GOTOFF:
1471 return 2;
1472 case ADDRESS_TLS:
1473 switch (addr.tls_type)
1475 case TLS_GD:
1476 return 2;
1477 case TLS_LDM:
1478 return 2;
1479 case TLS_DTPREL:
1480 return 1;
1481 default :
1482 gcc_unreachable ();
1484 default:
1485 break;
1488 return 0;
1491 /* Provide the costs of an addressing mode that contains ADDR.
1492 If ADDR is not a valid address, its cost is irrelevant. */
1493 static int
1494 microblaze_address_cost (rtx addr, machine_mode mode ATTRIBUTE_UNUSED,
1495 addr_space_t as ATTRIBUTE_UNUSED,
1496 bool speed ATTRIBUTE_UNUSED)
1498 return COSTS_N_INSNS (microblaze_address_insns (addr, GET_MODE (addr)));
1501 /* Return nonzero if X is an address which needs a temporary register when
1502 reloaded while generating PIC code. */
1505 pic_address_needs_scratch (rtx x)
1507 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x,0)) == PLUS)
1509 rtx p0, p1;
1511 p0 = XEXP (XEXP (x, 0), 0);
1512 p1 = XEXP (XEXP (x, 0), 1);
1514 if ((GET_CODE (p0) == SYMBOL_REF || GET_CODE (p0) == LABEL_REF)
1515 && (GET_CODE (p1) == CONST_INT)
1516 && (flag_pic == 2 || microblaze_tls_symbol_p (p0) || !SMALL_INT (p1)))
1517 return 1;
1519 return 0;
1522 /* Argument support functions. */
1523 /* Initialize CUMULATIVE_ARGS for a function. */
1525 void
1526 init_cumulative_args (CUMULATIVE_ARGS * cum, tree fntype,
1527 rtx libname ATTRIBUTE_UNUSED)
1529 static CUMULATIVE_ARGS zero_cum;
1530 tree param, next_param;
1532 *cum = zero_cum;
1534 /* Determine if this function has variable arguments. This is
1535 indicated by the last argument being 'void_type_mode' if there
1536 are no variable arguments. The standard MicroBlaze calling sequence
1537 passes all arguments in the general purpose registers in this case. */
1539 for (param = fntype ? TYPE_ARG_TYPES (fntype) : 0;
1540 param != 0; param = next_param)
1542 next_param = TREE_CHAIN (param);
1543 if (next_param == 0 && TREE_VALUE (param) != void_type_node)
1544 cum->gp_reg_found = 1;
1548 /* Advance the argument to the next argument position. */
1550 static void
1551 microblaze_function_arg_advance (cumulative_args_t cum_v,
1552 const function_arg_info &arg)
1554 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
1556 cum->arg_number++;
1557 switch (arg.mode)
1559 case E_VOIDmode:
1560 break;
1562 default:
1563 gcc_assert (GET_MODE_CLASS (arg.mode) == MODE_COMPLEX_INT
1564 || GET_MODE_CLASS (arg.mode) == MODE_COMPLEX_FLOAT);
1566 cum->gp_reg_found = 1;
1567 cum->arg_words += ((GET_MODE_SIZE (arg.mode) + UNITS_PER_WORD - 1)
1568 / UNITS_PER_WORD);
1569 break;
1571 case E_BLKmode:
1572 cum->gp_reg_found = 1;
1573 cum->arg_words += ((int_size_in_bytes (arg.type) + UNITS_PER_WORD - 1)
1574 / UNITS_PER_WORD);
1575 break;
1577 case E_SFmode:
1578 cum->arg_words++;
1579 if (!cum->gp_reg_found && cum->arg_number <= 2)
1580 cum->fp_code += 1 << ((cum->arg_number - 1) * 2);
1581 break;
1583 case E_DFmode:
1584 cum->arg_words += 2;
1585 if (!cum->gp_reg_found && cum->arg_number <= 2)
1586 cum->fp_code += 2 << ((cum->arg_number - 1) * 2);
1587 break;
1589 case E_DImode:
1590 cum->gp_reg_found = 1;
1591 cum->arg_words += 2;
1592 break;
1594 case E_QImode:
1595 case E_HImode:
1596 case E_SImode:
1597 case E_TImode:
1598 cum->gp_reg_found = 1;
1599 cum->arg_words++;
1600 break;
1604 /* Return an RTL expression containing the register for the given argument
1605 or 0 if the argument is to be passed on the stack. */
1607 static rtx
1608 microblaze_function_arg (cumulative_args_t cum_v, const function_arg_info &arg)
1610 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
1612 rtx ret;
1613 int regbase = -1;
1614 int *arg_words = &cum->arg_words;
1616 cum->last_arg_fp = 0;
1617 switch (arg.mode)
1619 case E_SFmode:
1620 case E_DFmode:
1621 case E_VOIDmode:
1622 case E_QImode:
1623 case E_HImode:
1624 case E_SImode:
1625 case E_DImode:
1626 case E_TImode:
1627 regbase = GP_ARG_FIRST;
1628 break;
1629 default:
1630 gcc_assert (GET_MODE_CLASS (arg.mode) == MODE_COMPLEX_INT
1631 || GET_MODE_CLASS (arg.mode) == MODE_COMPLEX_FLOAT);
1632 /* FALLTHRU */
1633 case E_BLKmode:
1634 regbase = GP_ARG_FIRST;
1635 break;
1638 if (*arg_words >= MAX_ARGS_IN_REGISTERS)
1639 ret = 0;
1640 else
1642 gcc_assert (regbase != -1);
1644 ret = gen_rtx_REG (arg.mode, regbase + *arg_words);
1647 if (arg.end_marker_p ())
1649 if (cum->num_adjusts > 0)
1650 ret = gen_rtx_PARALLEL ((machine_mode) cum->fp_code,
1651 gen_rtvec_v (cum->num_adjusts, cum->adjust));
1654 return ret;
1657 /* Return number of bytes of argument to put in registers. */
1658 static int
1659 function_arg_partial_bytes (cumulative_args_t cum_v,
1660 const function_arg_info &arg)
1662 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
1664 if ((arg.mode == BLKmode
1665 || GET_MODE_CLASS (arg.mode) != MODE_COMPLEX_INT
1666 || GET_MODE_CLASS (arg.mode) != MODE_COMPLEX_FLOAT)
1667 && cum->arg_words < MAX_ARGS_IN_REGISTERS)
1669 int words = ((arg.promoted_size_in_bytes () + UNITS_PER_WORD - 1)
1670 / UNITS_PER_WORD);
1671 if (words + cum->arg_words <= MAX_ARGS_IN_REGISTERS)
1672 return 0; /* structure fits in registers */
1674 return (MAX_ARGS_IN_REGISTERS - cum->arg_words) * UNITS_PER_WORD;
1677 else if (arg.mode == DImode && cum->arg_words == MAX_ARGS_IN_REGISTERS - 1)
1678 return UNITS_PER_WORD;
1680 return 0;
1683 /* Convert a version number of the form "vX.YY.Z" to an integer encoding
1684 for easier range comparison. */
1685 static int
1686 microblaze_version_to_int (const char *version)
1688 const char *p, *v;
1689 const char *tmpl = "vXX.YY.Z";
1690 int iver = 0;
1692 p = version;
1693 v = tmpl;
1695 while (*p)
1697 if (*v == 'X')
1698 { /* Looking for major */
1699 if (*p == '.')
1701 v++;
1703 else
1705 if (!(*p >= '0' && *p <= '9'))
1706 return -1;
1707 iver += (int) (*p - '0');
1708 iver *= 10;
1711 else if (*v == 'Y')
1712 { /* Looking for minor */
1713 if (!(*p >= '0' && *p <= '9'))
1714 return -1;
1715 iver += (int) (*p - '0');
1716 iver *= 10;
1718 else if (*v == 'Z')
1719 { /* Looking for compat */
1720 if (!(*p >= 'a' && *p <= 'z'))
1721 return -1;
1722 iver *= 10;
1723 iver += (int) (*p - 'a');
1725 else
1727 if (*p != *v)
1728 return -1;
1731 v++;
1732 p++;
1735 if (*p)
1736 return -1;
1738 return iver;
1742 static void
1743 microblaze_option_override (void)
1745 int i, start;
1746 int regno;
1747 machine_mode mode;
1748 int ver;
1750 microblaze_section_threshold = (OPTION_SET_P (g_switch_value)
1751 ? g_switch_value
1752 : MICROBLAZE_DEFAULT_GVALUE);
1754 if (flag_pic)
1756 /* Make sure it's 2, we only support one kind of PIC. */
1757 flag_pic = 2;
1758 if (!TARGET_SUPPORTS_PIC)
1760 error ("%<-fPIC%>/%<-fpic%> not supported for this target");
1761 /* Clear it to avoid further errors. */
1762 flag_pic = 0;
1766 /* Check the MicroBlaze CPU version for any special action to be done. */
1767 if (microblaze_select_cpu == NULL)
1768 microblaze_select_cpu = MICROBLAZE_DEFAULT_CPU;
1769 ver = microblaze_version_to_int (microblaze_select_cpu);
1770 if (ver == -1)
1772 error ("%qs is an invalid argument to %<-mcpu=%>", microblaze_select_cpu);
1775 ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v3.00.a");
1776 if (ver < 0)
1778 /* No hardware exceptions in earlier versions. So no worries. */
1779 #if 0
1780 microblaze_select_flags &= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY);
1781 #endif
1782 microblaze_no_unsafe_delay = 0;
1783 microblaze_pipe = MICROBLAZE_PIPE_3;
1785 else if (ver == 0
1786 || (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v4.00.b")
1787 == 0))
1789 #if 0
1790 microblaze_select_flags |= (MICROBLAZE_MASK_NO_UNSAFE_DELAY);
1791 #endif
1792 microblaze_no_unsafe_delay = 1;
1793 microblaze_pipe = MICROBLAZE_PIPE_3;
1795 else
1797 /* We agree to use 5 pipe-stage model even on area optimized 3
1798 pipe-stage variants. */
1799 #if 0
1800 microblaze_select_flags &= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY);
1801 #endif
1802 microblaze_no_unsafe_delay = 0;
1803 microblaze_pipe = MICROBLAZE_PIPE_5;
1804 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v5.00.a") == 0
1805 || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu,
1806 "v5.00.b") == 0
1807 || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu,
1808 "v5.00.c") == 0)
1810 /* Pattern compares are to be turned on by default only when
1811 compiling for MB v5.00.'z'. */
1812 target_flags |= MASK_PATTERN_COMPARE;
1816 ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v6.00.a");
1817 if (ver < 0)
1819 if (TARGET_MULTIPLY_HIGH)
1820 warning (0,
1821 "%<-mxl-multiply-high%> can be used only with "
1822 "%<-mcpu=v6.00.a%> or greater");
1825 ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v8.10.a");
1826 microblaze_has_clz = 1;
1827 if (ver < 0)
1829 /* MicroBlaze prior to 8.10.a didn't have clz. */
1830 microblaze_has_clz = 0;
1833 /* TARGET_REORDER defaults to 2 if -mxl-reorder not specified. */
1834 ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v8.30.a");
1835 if (ver < 0)
1837 if (TARGET_REORDER == 1)
1838 warning (0, "%<-mxl-reorder%> can be used only with "
1839 "%<-mcpu=v8.30.a%> or greater");
1840 TARGET_REORDER = 0;
1842 else if ((ver == 0) && !TARGET_PATTERN_COMPARE)
1844 if (TARGET_REORDER == 1)
1845 warning (0, "%<-mxl-reorder%> requires %<-mxl-pattern-compare%> for "
1846 "%<-mcpu=v8.30.a%>");
1847 TARGET_REORDER = 0;
1850 if (TARGET_MULTIPLY_HIGH && TARGET_SOFT_MUL)
1851 error ("%<-mxl-multiply-high%> requires %<-mno-xl-soft-mul%>");
1853 /* Always use DFA scheduler. */
1854 microblaze_sched_use_dfa = 1;
1856 #if 0
1857 microblaze_abicalls = MICROBLAZE_ABICALLS_NO;
1858 #endif
1860 /* Initialize the high, low values for legit floating point constants. */
1861 real_maxval (&dfhigh, 0, DFmode);
1862 real_maxval (&dflow, 1, DFmode);
1863 real_maxval (&sfhigh, 0, SFmode);
1864 real_maxval (&sflow, 1, SFmode);
1866 microblaze_print_operand_punct['?'] = 1;
1867 microblaze_print_operand_punct['#'] = 1;
1868 microblaze_print_operand_punct['&'] = 1;
1869 microblaze_print_operand_punct['!'] = 1;
1870 microblaze_print_operand_punct['*'] = 1;
1871 microblaze_print_operand_punct['@'] = 1;
1872 microblaze_print_operand_punct['.'] = 1;
1873 microblaze_print_operand_punct['('] = 1;
1874 microblaze_print_operand_punct[')'] = 1;
1875 microblaze_print_operand_punct['['] = 1;
1876 microblaze_print_operand_punct[']'] = 1;
1877 microblaze_print_operand_punct['<'] = 1;
1878 microblaze_print_operand_punct['>'] = 1;
1879 microblaze_print_operand_punct['{'] = 1;
1880 microblaze_print_operand_punct['}'] = 1;
1881 microblaze_print_operand_punct['^'] = 1;
1882 microblaze_print_operand_punct['$'] = 1;
1883 microblaze_print_operand_punct['+'] = 1;
1885 /* Set up array to map GCC register number to debug register number.
1886 Ignore the special purpose register numbers. */
1888 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
1889 microblaze_debugger_regno[i] = -1;
1891 start = GP_DEBUGGER_FIRST - GP_REG_FIRST;
1892 for (i = GP_REG_FIRST; i <= GP_REG_LAST; i++)
1893 microblaze_debugger_regno[i] = i + start;
1895 /* Set up array giving whether a given register can hold a given mode. */
1897 for (mode = VOIDmode;
1898 mode != MAX_MACHINE_MODE; mode = (machine_mode) ((int) mode + 1))
1900 int size = GET_MODE_SIZE (mode);
1902 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
1904 int ok;
1906 if (mode == CCmode)
1908 ok = (ST_REG_P (regno) || GP_REG_P (regno));
1910 else if (GP_REG_P (regno))
1911 ok = ((regno & 1) == 0 || size <= UNITS_PER_WORD);
1912 else
1913 ok = 0;
1915 microblaze_hard_regno_mode_ok_p[(int) mode][regno] = ok;
1920 /* Implement TARGET_HARD_REGNO_MODE_OK. In 32 bit mode, require that
1921 DImode and DFmode be in even registers. For DImode, this makes some
1922 of the insns easier to write, since you don't have to worry about a
1923 DImode value in registers 3 & 4, producing a result in 4 & 5.
1925 To make the code simpler, the hook now just references an
1926 array built in override_options. */
1928 static bool
1929 microblaze_hard_regno_mode_ok (unsigned int regno, machine_mode mode)
1931 return microblaze_hard_regno_mode_ok_p[mode][regno];
1934 /* Implement TARGET_MODES_TIEABLE_P. */
1936 static bool
1937 microblaze_modes_tieable_p (machine_mode mode1, machine_mode mode2)
1939 return ((GET_MODE_CLASS (mode1) == MODE_FLOAT
1940 || GET_MODE_CLASS (mode1) == MODE_COMPLEX_FLOAT)
1941 == (GET_MODE_CLASS (mode2) == MODE_FLOAT
1942 || GET_MODE_CLASS (mode2) == MODE_COMPLEX_FLOAT));
1945 /* Return true if FUNC is an interrupt function as specified
1946 by the "interrupt_handler" attribute. */
1948 static int
1949 microblaze_interrupt_function_p (tree func)
1951 tree a;
1953 if (TREE_CODE (func) != FUNCTION_DECL)
1954 return 0;
1956 a = lookup_attribute ("interrupt_handler", DECL_ATTRIBUTES (func));
1957 return a != NULL_TREE;
1960 static int
1961 microblaze_fast_interrupt_function_p (tree func)
1963 tree a;
1965 if (TREE_CODE (func) != FUNCTION_DECL)
1966 return 0;
1968 a = lookup_attribute ("fast_interrupt", DECL_ATTRIBUTES (func));
1969 return a != NULL_TREE;
1972 microblaze_break_function_p (tree func)
1974 tree a;
1975 if (!func)
1976 return 0;
1977 if (TREE_CODE (func) != FUNCTION_DECL)
1978 return 0;
1980 a = lookup_attribute ("break_handler", DECL_ATTRIBUTES (func));
1981 return a != NULL_TREE;
1983 /* Return true if FUNC is an interrupt function which uses
1984 normal return, indicated by the "save_volatiles" attribute. */
1986 static int
1987 microblaze_save_volatiles (tree func)
1989 tree a;
1991 if (TREE_CODE (func) != FUNCTION_DECL)
1992 return 0;
1994 a = lookup_attribute ("save_volatiles", DECL_ATTRIBUTES (func));
1995 return a != NULL_TREE;
1998 /* Return whether function is tagged with 'interrupt_handler'
1999 or 'fast_interrupt' attribute. Return true if function
2000 should use return from interrupt rather than normal
2001 function return. */
2003 microblaze_is_interrupt_variant (void)
2005 return (interrupt_handler || fast_interrupt);
2008 microblaze_is_break_handler (void)
2010 return break_handler;
2013 /* Determine of register must be saved/restored in call. */
2014 static int
2015 microblaze_must_save_register (int regno)
2017 if (pic_offset_table_rtx &&
2018 (regno == MB_ABI_PIC_ADDR_REGNUM) && df_regs_ever_live_p (regno))
2019 return 1;
2021 if (df_regs_ever_live_p (regno) && !call_used_or_fixed_reg_p (regno))
2022 return 1;
2024 if (frame_pointer_needed && (regno == HARD_FRAME_POINTER_REGNUM))
2025 return 1;
2027 if (crtl->calls_eh_return
2028 && regno == MB_ABI_SUB_RETURN_ADDR_REGNUM)
2029 return 1;
2031 if (!crtl->is_leaf)
2033 if (regno == MB_ABI_SUB_RETURN_ADDR_REGNUM)
2034 return 1;
2035 if ((microblaze_is_interrupt_variant () || save_volatiles) &&
2036 (regno >= 3 && regno <= 12))
2037 return 1;
2040 if (microblaze_is_interrupt_variant ())
2042 if (df_regs_ever_live_p (regno)
2043 || regno == MB_ABI_MSR_SAVE_REG
2044 || ((interrupt_handler || fast_interrupt)
2045 && (regno == MB_ABI_ASM_TEMP_REGNUM
2046 || regno == MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM)))
2047 return 1;
2050 if (save_volatiles)
2052 if (df_regs_ever_live_p (regno)
2053 || regno == MB_ABI_ASM_TEMP_REGNUM
2054 || regno == MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM)
2055 return 1;
2058 if (crtl->calls_eh_return
2059 && (regno == EH_RETURN_DATA_REGNO (0)
2060 || regno == EH_RETURN_DATA_REGNO (1)))
2061 return 1;
2063 return 0;
2066 /* Return the bytes needed to compute the frame pointer from the current
2067 stack pointer.
2069 MicroBlaze stack frames look like:
2073 Before call After call
2074 +-----------------------+ +-----------------------+
2075 high | | | |
2076 mem. | local variables, | | local variables, |
2077 | callee saved and | | callee saved and |
2078 | temps | | temps |
2079 +-----------------------+ +-----------------------+
2080 | arguments for called | | arguments for called |
2081 | subroutines | | subroutines |
2082 | (optional) | | (optional) |
2083 +-----------------------+ +-----------------------+
2084 | Link register | | Link register |
2085 SP->| | | |
2086 +-----------------------+ +-----------------------+
2088 | local variables, |
2089 | callee saved and |
2090 | temps |
2091 +-----------------------+
2092 | MSR (optional if, |
2093 | interrupt handler) |
2094 +-----------------------+
2096 | alloca allocations |
2098 +-----------------------+
2100 | arguments for called |
2101 | subroutines |
2102 | (optional) |
2104 +-----------------------+
2105 | Link register |
2106 low FP,SP->| |
2107 memory +-----------------------+
2111 static HOST_WIDE_INT
2112 compute_frame_size (HOST_WIDE_INT size)
2114 int regno;
2115 HOST_WIDE_INT total_size; /* # bytes that the entire frame takes up. */
2116 HOST_WIDE_INT var_size; /* # bytes that local variables take up. */
2117 HOST_WIDE_INT args_size; /* # bytes that outgoing arguments take up. */
2118 int link_debug_size; /* # bytes for link register. */
2119 HOST_WIDE_INT gp_reg_size; /* # bytes needed to store calle-saved gp regs. */
2120 long mask; /* mask of saved gp registers. */
2122 interrupt_handler =
2123 microblaze_interrupt_function_p (current_function_decl);
2124 break_handler =
2125 microblaze_break_function_p (current_function_decl);
2127 fast_interrupt =
2128 microblaze_fast_interrupt_function_p (current_function_decl);
2129 save_volatiles = microblaze_save_volatiles (current_function_decl);
2130 if (break_handler)
2131 interrupt_handler = break_handler;
2133 gp_reg_size = 0;
2134 mask = 0;
2135 var_size = size;
2136 args_size = crtl->outgoing_args_size;
2138 if ((args_size == 0) && cfun->calls_alloca)
2139 args_size = NUM_OF_ARGS * UNITS_PER_WORD;
2141 total_size = var_size + args_size;
2143 if (flag_pic == 2 && !TARGET_PIC_DATA_TEXT_REL)
2144 /* force setting GOT. */
2145 df_set_regs_ever_live (MB_ABI_PIC_ADDR_REGNUM, true);
2147 /* Calculate space needed for gp registers. */
2148 for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
2150 if (microblaze_must_save_register (regno))
2153 if (regno != MB_ABI_SUB_RETURN_ADDR_REGNUM)
2154 /* Don't account for link register. It is accounted specially below. */
2155 gp_reg_size += GET_MODE_SIZE (SImode);
2157 mask |= (1L << (regno - GP_REG_FIRST));
2161 total_size += gp_reg_size;
2163 /* Add 4 bytes for MSR. */
2164 if (microblaze_is_interrupt_variant ())
2165 total_size += 4;
2167 /* No space to be allocated for link register in leaf functions with no other
2168 stack requirements. */
2169 if (total_size == 0 && crtl->is_leaf)
2170 link_debug_size = 0;
2171 else
2172 link_debug_size = UNITS_PER_WORD;
2174 total_size += link_debug_size;
2176 /* Save other computed information. */
2177 current_frame_info.total_size = total_size;
2178 current_frame_info.var_size = var_size;
2179 current_frame_info.args_size = args_size;
2180 current_frame_info.gp_reg_size = gp_reg_size;
2181 current_frame_info.mask = mask;
2182 current_frame_info.initialized = reload_completed;
2183 current_frame_info.num_gp = gp_reg_size / UNITS_PER_WORD;
2184 current_frame_info.link_debug_size = link_debug_size;
2186 if (mask)
2187 /* Offset from which to callee-save GP regs. */
2188 current_frame_info.gp_offset = (total_size - gp_reg_size);
2189 else
2190 current_frame_info.gp_offset = 0;
2192 /* Ok, we're done. */
2193 return total_size;
2196 /* Make sure that we're not trying to eliminate to the wrong hard frame
2197 pointer. */
2199 static bool
2200 microblaze_can_eliminate (const int from, const int to)
2202 return ((from == RETURN_ADDRESS_POINTER_REGNUM && !leaf_function_p())
2203 || (to == MB_ABI_SUB_RETURN_ADDR_REGNUM && leaf_function_p())
2204 || (from != RETURN_ADDRESS_POINTER_REGNUM
2205 && (to == HARD_FRAME_POINTER_REGNUM
2206 || (to == STACK_POINTER_REGNUM && !frame_pointer_needed))));
2209 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
2210 pointer or argument pointer or the return address pointer. TO is either
2211 the stack pointer or hard frame pointer. */
2213 HOST_WIDE_INT
2214 microblaze_initial_elimination_offset (int from, int to)
2216 HOST_WIDE_INT offset;
2218 switch (from)
2220 case FRAME_POINTER_REGNUM:
2221 offset = 0;
2222 break;
2223 case ARG_POINTER_REGNUM:
2224 if (to == STACK_POINTER_REGNUM || to == HARD_FRAME_POINTER_REGNUM)
2225 offset = compute_frame_size (get_frame_size ());
2226 else
2227 gcc_unreachable ();
2228 break;
2229 case RETURN_ADDRESS_POINTER_REGNUM:
2230 if (crtl->is_leaf)
2231 offset = 0;
2232 else
2233 offset = current_frame_info.gp_offset +
2234 ((UNITS_PER_WORD - (POINTER_SIZE / BITS_PER_UNIT)));
2235 break;
2236 default:
2237 gcc_unreachable ();
2239 return offset;
2242 /* Print operands using format code.
2244 The MicroBlaze specific codes are:
2246 'X' X is CONST_INT, prints 32 bits in hexadecimal format = "0x%08x",
2247 'x' X is CONST_INT, prints 16 bits in hexadecimal format = "0x%04x",
2248 'F' op is CONST_DOUBLE, print 32 bits in hex,
2249 'd' output integer constant in decimal,
2250 'z' if the operand is 0, use $0 instead of normal operand.
2251 'D' print second register of double-word register operand.
2252 'L' print low-order register of double-word register operand.
2253 'M' print high-order register of double-word register operand.
2254 'C' print part of opcode for a branch condition.
2255 'N' print part of opcode for a branch condition, inverted.
2256 'S' X is CODE_LABEL, print with prefix of "LS" (for embedded switch).
2257 'B' print 'z' for EQ, 'n' for NE
2258 'b' print 'n' for EQ, 'z' for NE
2259 'T' print 'f' for EQ, 't' for NE
2260 't' print 't' for EQ, 'f' for NE
2261 'm' Print 1<<operand.
2262 'i' Print 'i' if MEM operand has immediate value
2263 'y' Print 'y' if MEM operand is single register
2264 'o' Print operand address+4
2265 '?' Print 'd' if we use a branch with delay slot instead of normal branch.
2266 'h' Print high word of const_double (int or float) value as hex
2267 'j' Print low word of const_double (int or float) value as hex
2268 's' Print -1 if operand is negative, 0 if positive (sign extend)
2269 '@' Print the name of the temporary register (rMB_ABI_ASM_TEMP_REGNUM).
2270 '#' Print nop if the delay slot of a branch is not filled.
2273 void
2274 print_operand (FILE * file, rtx op, int letter)
2276 enum rtx_code code;
2278 if (PRINT_OPERAND_PUNCT_VALID_P (letter))
2280 switch (letter)
2282 case '?':
2283 /* Conditionally add a 'd' to indicate filled delay slot. */
2284 if (final_sequence != NULL)
2285 fputs ("d", file);
2286 break;
2288 case '#':
2289 /* Conditionally add a nop in unfilled delay slot. */
2290 if (final_sequence == NULL)
2291 fputs ("nop\t\t# Unfilled delay slot\n", file);
2292 break;
2294 case '@':
2295 fputs (reg_names[GP_REG_FIRST + MB_ABI_ASM_TEMP_REGNUM], file);
2296 break;
2298 default:
2299 output_operand_lossage ("unknown punctuation '%c'", letter);
2300 break;
2303 return;
2306 if (!op)
2308 output_operand_lossage ("null pointer");
2309 return;
2312 code = GET_CODE (op);
2314 if (code == SIGN_EXTEND)
2315 op = XEXP (op, 0), code = GET_CODE (op);
2317 if (letter == 'C')
2318 switch (code)
2320 case EQ:
2321 fputs ("eq", file);
2322 break;
2323 case NE:
2324 fputs ("ne", file);
2325 break;
2326 case GT:
2327 case GTU:
2328 fputs ("gt", file);
2329 break;
2330 case GE:
2331 case GEU:
2332 fputs ("ge", file);
2333 break;
2334 case LT:
2335 case LTU:
2336 fputs ("lt", file);
2337 break;
2338 case LE:
2339 case LEU:
2340 fputs ("le", file);
2341 break;
2342 default:
2343 fatal_insn ("PRINT_OPERAND, invalid insn for %%C", op);
2346 else if (letter == 'N')
2347 switch (code)
2349 case EQ:
2350 fputs ("ne", file);
2351 break;
2352 case NE:
2353 fputs ("eq", file);
2354 break;
2355 case GT:
2356 case GTU:
2357 fputs ("le", file);
2358 break;
2359 case GE:
2360 case GEU:
2361 fputs ("lt", file);
2362 break;
2363 case LT:
2364 case LTU:
2365 fputs ("ge", file);
2366 break;
2367 case LE:
2368 case LEU:
2369 fputs ("gt", file);
2370 break;
2371 default:
2372 fatal_insn ("PRINT_OPERAND, invalid insn for %%N", op);
2375 else if (letter == 'S')
2377 char buffer[100];
2379 ASM_GENERATE_INTERNAL_LABEL (buffer, "LS", CODE_LABEL_NUMBER (op));
2380 assemble_name (file, buffer);
2383 /* Print 'i' for memory operands which have immediate values. */
2384 else if (letter == 'i')
2386 if (code == MEM)
2388 struct microblaze_address_info info;
2390 if (!microblaze_classify_address
2391 (&info, XEXP (op, 0), GET_MODE (op), 1))
2392 fatal_insn ("insn contains an invalid address !", op);
2394 switch (info.type)
2396 case ADDRESS_REG:
2397 case ADDRESS_CONST_INT:
2398 case ADDRESS_SYMBOLIC:
2399 case ADDRESS_SYMBOLIC_TXT_REL:
2400 case ADDRESS_GOTOFF:
2401 case ADDRESS_TLS:
2402 fputs ("i", file);
2403 break;
2404 case ADDRESS_REG_INDEX:
2405 break;
2406 case ADDRESS_INVALID:
2407 case ADDRESS_PLT:
2408 fatal_insn ("invalid address", op);
2413 else if (code == REG || code == SUBREG)
2415 int regnum;
2417 if (code == REG)
2418 regnum = REGNO (op);
2419 else
2420 regnum = true_regnum (op);
2422 if ((letter == 'M' && !WORDS_BIG_ENDIAN)
2423 || (letter == 'L' && WORDS_BIG_ENDIAN) || letter == 'D')
2424 regnum++;
2426 fprintf (file, "%s", reg_names[regnum]);
2429 else if (code == MEM)
2430 if (letter == 'o')
2432 rtx op4 = adjust_address (op, GET_MODE (op), 4);
2433 output_address (GET_MODE (op), XEXP (op4, 0));
2435 else if (letter == 'y')
2437 rtx mem_reg = XEXP (op, 0);
2438 if (GET_CODE (mem_reg) == REG)
2440 int regnum = REGNO (mem_reg);
2441 fprintf (file, "%s", reg_names[regnum]);
2444 else
2445 output_address (GET_MODE (op), XEXP (op, 0));
2447 else if (letter == 'h' || letter == 'j')
2449 long val[2];
2450 if (code == CONST_DOUBLE)
2452 if (GET_MODE (op) == DFmode)
2453 REAL_VALUE_TO_TARGET_DOUBLE (*CONST_DOUBLE_REAL_VALUE (op), val);
2454 else
2456 val[0] = CONST_DOUBLE_HIGH (op);
2457 val[1] = CONST_DOUBLE_LOW (op);
2460 else if (code == CONST_INT)
2462 val[0] = (INTVAL (op) & 0xffffffff00000000LL) >> 32;
2463 val[1] = INTVAL (op) & 0x00000000ffffffffLL;
2464 if (val[0] == 0 && val[1] < 0)
2465 val[0] = -1;
2468 fprintf (file, "0x%8.8lx", (letter == 'h') ? val[0] : val[1]);
2470 else if (code == CONST_DOUBLE)
2472 if (letter == 'F')
2474 unsigned long value_long;
2475 REAL_VALUE_TO_TARGET_SINGLE (*CONST_DOUBLE_REAL_VALUE (op),
2476 value_long);
2477 fprintf (file, "0x%lx", value_long);
2479 else
2481 char s[60];
2482 real_to_decimal (s, CONST_DOUBLE_REAL_VALUE (op), sizeof (s), 0, 1);
2483 fputs (s, file);
2487 else if (code == UNSPEC)
2489 print_operand_address (file, op);
2492 else if (letter == 'x' && GET_CODE (op) == CONST_INT)
2493 fprintf (file, HOST_WIDE_INT_PRINT_HEX, 0xffff & INTVAL (op));
2495 else if (letter == 'X' && GET_CODE (op) == CONST_INT)
2496 fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (op));
2498 else if (letter == 'd' && GET_CODE (op) == CONST_INT)
2499 fprintf (file, HOST_WIDE_INT_PRINT_DEC, (INTVAL (op)));
2501 else if (letter == 'z' && GET_CODE (op) == CONST_INT && INTVAL (op) == 0)
2502 fputs (reg_names[GP_REG_FIRST], file);
2504 else if (letter == 's' && GET_CODE (op) == CONST_INT)
2505 if (INTVAL (op) < 0)
2506 fputs ("-1", file);
2507 else
2508 fputs ("0", file);
2510 else if (letter == 'd' || letter == 'x' || letter == 'X' || letter == 's')
2511 output_operand_lossage ("letter %c was found & insn was not CONST_INT", letter);
2513 else if (letter == 'B')
2514 fputs (code == EQ ? "z" : "n", file);
2515 else if (letter == 'b')
2516 fputs (code == EQ ? "n" : "z", file);
2517 else if (letter == 'T')
2518 fputs (code == EQ ? "f" : "t", file);
2519 else if (letter == 't')
2520 fputs (code == EQ ? "t" : "f", file);
2522 else if (code == CONST
2523 && ((GET_CODE (XEXP (op, 0)) == REG)
2524 || (GET_CODE (XEXP (op, 0)) == UNSPEC)))
2526 print_operand (file, XEXP (op, 0), letter);
2528 else if (code == CONST
2529 && (GET_CODE (XEXP (op, 0)) == PLUS)
2530 && (GET_CODE (XEXP (XEXP (op, 0), 0)) == REG)
2531 && (GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST))
2533 print_operand_address (file, XEXP (op, 0));
2535 else if (letter == 'm')
2536 fprintf (file, "%ld", (1L << INTVAL (op)));
2537 else
2538 output_addr_const (file, op);
2541 /* A C compound statement to output to stdio stream STREAM the
2542 assembler syntax for an instruction operand that is a memory
2543 reference whose address is ADDR. ADDR is an RTL expression.
2545 Possible address classifications and output formats are,
2547 ADDRESS_REG "%0, r0"
2549 ADDRESS_REG with non-zero "%0, <addr_const>"
2550 offset
2552 ADDRESS_REG_INDEX "rA, RB"
2553 (if rA is r0, rA and rB are swapped)
2555 ADDRESS_CONST_INT "r0, <addr_const>"
2557 ADDRESS_SYMBOLIC "rBase, <addr_const>"
2558 (rBase is a base register suitable for the
2559 symbol's type)
2562 void
2563 print_operand_address (FILE * file, rtx addr)
2565 struct microblaze_address_info info;
2566 enum microblaze_address_type type;
2567 if (!microblaze_classify_address (&info, addr, GET_MODE (addr), 2))
2568 fatal_insn ("insn contains an invalid address !", addr);
2570 type = info.type;
2571 switch (info.type)
2573 case ADDRESS_REG:
2574 fprintf (file, "%s,", reg_names[REGNO (info.regA)]);
2575 output_addr_const (file, info.offset);
2576 break;
2577 case ADDRESS_REG_INDEX:
2578 if (REGNO (info.regA) == 0)
2579 /* Make rB == r0 instead of rA == r0. This helps reduce read port
2580 congestion. */
2581 fprintf (file, "%s,%s", reg_names[REGNO (info.regB)],
2582 reg_names[REGNO (info.regA)]);
2583 else if (REGNO (info.regB) != 0)
2584 /* This is a silly swap to help Dhrystone. */
2585 fprintf (file, "%s,%s", reg_names[REGNO (info.regB)],
2586 reg_names[REGNO (info.regA)]);
2587 break;
2588 case ADDRESS_CONST_INT:
2589 fprintf (file, "%s,", reg_names[REGNO (info.regA)]);
2590 output_addr_const (file, info.offset);
2591 break;
2592 case ADDRESS_SYMBOLIC:
2593 case ADDRESS_SYMBOLIC_TXT_REL:
2594 case ADDRESS_GOTOFF:
2595 case ADDRESS_PLT:
2596 case ADDRESS_TLS:
2597 if (info.regA)
2598 fprintf (file, "%s,", reg_names[REGNO (info.regA)]);
2599 output_addr_const (file, info.symbol);
2600 if (type == ADDRESS_GOTOFF)
2602 fputs ("@GOT", file);
2604 else if (type == ADDRESS_PLT)
2606 fputs ("@PLT", file);
2608 else if (type == ADDRESS_SYMBOLIC_TXT_REL)
2610 if (info.offset != NULL && CONST_INT_P (info.offset)
2611 && INTVAL (info.offset) > 0)
2613 fprintf (file, "+");
2614 output_addr_const (file, info.offset);
2616 fputs ("@TXTREL", file);
2618 else if (type == ADDRESS_TLS)
2620 switch (info.tls_type)
2622 case TLS_GD:
2623 fputs ("@TLSGD", file);
2624 break;
2625 case TLS_LDM:
2626 fputs ("@TLSLDM", file);
2627 break;
2628 case TLS_DTPREL:
2629 fputs ("@TLSDTPREL", file);
2630 break;
2631 default :
2632 gcc_unreachable ();
2633 break;
2636 break;
2637 case ADDRESS_INVALID:
2638 fatal_insn ("invalid address", addr);
2639 break;
2643 /* Emit either a label, .comm, or .lcomm directive, and mark that the symbol
2644 is used, so that we don't emit an .extern for it in
2645 microblaze_asm_file_end. */
2647 void
2648 microblaze_declare_object (FILE * stream, const char *name,
2649 const char *section, const char *fmt, int size)
2652 fputs (section, stream);
2653 assemble_name (stream, name);
2654 fprintf (stream, fmt, size);
2657 /* Common code to emit the insns (or to write the instructions to a file)
2658 to save/restore registers.
2660 Other parts of the code assume that MICROBLAZE_TEMP1_REGNUM (aka large_reg)
2661 is not modified within save_restore_insns. */
2663 #define BITSET_P(VALUE,BIT) (((VALUE) & (1L << (BIT))) != 0)
2665 /* Save or restore instructions based on whether this is the prologue or
2666 epilogue. prologue is 1 for the prologue. */
2667 static void
2668 save_restore_insns (int prologue)
2670 rtx base_reg_rtx, reg_rtx, mem_rtx, /* msr_rtx, */ isr_reg_rtx =
2671 0, isr_mem_rtx = 0;
2672 rtx isr_msr_rtx = 0, insn;
2673 long mask = current_frame_info.mask;
2674 HOST_WIDE_INT gp_offset;
2675 int regno;
2677 if (frame_pointer_needed
2678 && !BITSET_P (mask, HARD_FRAME_POINTER_REGNUM - GP_REG_FIRST))
2679 gcc_unreachable ();
2681 if (mask == 0)
2682 return;
2684 /* Save registers starting from high to low. The debuggers prefer at least
2685 the return register be stored at func+4, and also it allows us not to
2686 need a nop in the epilog if at least one register is reloaded in
2687 addition to return address. */
2689 /* Pick which pointer to use as a base register. For small frames, just
2690 use the stack pointer. Otherwise, use a temporary register. Save 2
2691 cycles if the save area is near the end of a large frame, by reusing
2692 the constant created in the prologue/epilogue to adjust the stack
2693 frame. */
2695 gp_offset = current_frame_info.gp_offset;
2697 gcc_assert (gp_offset > 0);
2699 base_reg_rtx = stack_pointer_rtx;
2701 /* For interrupt_handlers, need to save/restore the MSR. */
2702 if (microblaze_is_interrupt_variant ())
2704 isr_mem_rtx = gen_rtx_MEM (SImode,
2705 gen_rtx_PLUS (Pmode, base_reg_rtx,
2706 GEN_INT (current_frame_info.
2707 gp_offset -
2708 UNITS_PER_WORD)));
2710 /* Do not optimize in flow analysis. */
2711 MEM_VOLATILE_P (isr_mem_rtx) = 1;
2712 isr_reg_rtx = gen_rtx_REG (SImode, MB_ABI_MSR_SAVE_REG);
2713 isr_msr_rtx = gen_rtx_REG (SImode, ST_REG);
2716 if (microblaze_is_interrupt_variant () && !prologue)
2718 emit_move_insn (isr_reg_rtx, isr_mem_rtx);
2719 emit_move_insn (isr_msr_rtx, isr_reg_rtx);
2720 /* Do not optimize in flow analysis. */
2721 emit_insn (gen_rtx_USE (SImode, isr_reg_rtx));
2722 emit_insn (gen_rtx_USE (SImode, isr_msr_rtx));
2725 for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
2727 if (BITSET_P (mask, regno - GP_REG_FIRST))
2729 if (regno == MB_ABI_SUB_RETURN_ADDR_REGNUM)
2730 /* Don't handle here. Already handled as the first register. */
2731 continue;
2733 reg_rtx = gen_rtx_REG (SImode, regno);
2734 insn = gen_rtx_PLUS (Pmode, base_reg_rtx, GEN_INT (gp_offset));
2735 mem_rtx = gen_rtx_MEM (SImode, insn);
2736 if (microblaze_is_interrupt_variant () || save_volatiles)
2737 /* Do not optimize in flow analysis. */
2738 MEM_VOLATILE_P (mem_rtx) = 1;
2740 if (prologue)
2742 insn = emit_move_insn (mem_rtx, reg_rtx);
2743 RTX_FRAME_RELATED_P (insn) = 1;
2745 else
2747 insn = emit_move_insn (reg_rtx, mem_rtx);
2750 gp_offset += GET_MODE_SIZE (SImode);
2754 if (microblaze_is_interrupt_variant () && prologue)
2756 emit_move_insn (isr_reg_rtx, isr_msr_rtx);
2757 emit_move_insn (isr_mem_rtx, isr_reg_rtx);
2759 /* Do not optimize in flow analysis. */
2760 emit_insn (gen_rtx_USE (SImode, isr_reg_rtx));
2761 emit_insn (gen_rtx_USE (SImode, isr_msr_rtx));
2764 /* Done saving and restoring */
2768 /* Set up the stack and frame (if desired) for the function. */
2769 static void
2770 microblaze_function_prologue (FILE * file)
2772 const char *fnname;
2773 long fsiz = current_frame_info.total_size;
2775 /* Get the function name the same way that toplev.cc does before calling
2776 assemble_start_function. This is needed so that the name used here
2777 exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */
2778 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
2779 if (!flag_inhibit_size_directive)
2781 fputs ("\t.ent\t", file);
2782 if (interrupt_handler && strcmp (INTERRUPT_HANDLER_NAME, fnname))
2783 fputs ("_interrupt_handler", file);
2784 else if (break_handler && strcmp (BREAK_HANDLER_NAME, fnname))
2785 fputs ("_break_handler", file);
2786 else if (fast_interrupt && strcmp (FAST_INTERRUPT_NAME, fnname))
2787 fputs ("_fast_interrupt", file);
2788 else
2789 assemble_name (file, fnname);
2790 fputs ("\n", file);
2791 if (!microblaze_is_interrupt_variant ())
2792 ASM_OUTPUT_TYPE_DIRECTIVE (file, fnname, "function");
2795 ASM_OUTPUT_FUNCTION_LABEL (file, fnname, current_function_decl);
2797 if (interrupt_handler && strcmp (INTERRUPT_HANDLER_NAME, fnname))
2798 fputs ("_interrupt_handler:\n", file);
2799 if (break_handler && strcmp (BREAK_HANDLER_NAME, fnname))
2800 fputs ("_break_handler:\n", file);
2801 if (!flag_inhibit_size_directive)
2803 /* .frame FRAMEREG, FRAMESIZE, RETREG. */
2804 fprintf (file,
2805 "\t.frame\t%s,%ld,%s\t\t# vars= %ld, regs= %d, args= %d\n",
2806 (reg_names[(frame_pointer_needed)
2807 ? HARD_FRAME_POINTER_REGNUM :
2808 STACK_POINTER_REGNUM]), fsiz,
2809 reg_names[MB_ABI_SUB_RETURN_ADDR_REGNUM + GP_REG_FIRST],
2810 current_frame_info.var_size, current_frame_info.num_gp,
2811 (int) crtl->outgoing_args_size);
2812 fprintf (file, "\t.mask\t0x%08lx\n", current_frame_info.mask);
2816 /* Output extra assembler code at the end of a prologue. */
2817 static void
2818 microblaze_function_end_prologue (FILE * file)
2820 if (TARGET_STACK_CHECK)
2822 fprintf (file, "\t# Stack Check Stub -- Start.\n\t");
2823 fprintf (file, "ori\tr18,r0,_stack_end\n\t");
2824 fprintf (file, "cmpu\tr18,r1,r18\n\t");
2825 fprintf (file, "bgei\tr18,_stack_overflow_exit\n\t");
2826 fprintf (file, "# Stack Check Stub -- End.\n");
2830 static void
2831 microblaze_elf_asm_cdtor (rtx symbol, int priority, bool is_ctor)
2833 section *s;
2835 if (priority != DEFAULT_INIT_PRIORITY)
2837 char buf[18];
2838 sprintf (buf, "%s.%.5u",
2839 is_ctor ? ".ctors" : ".dtors",
2840 MAX_INIT_PRIORITY - priority);
2841 s = get_section (buf, SECTION_WRITE, NULL_TREE);
2843 else if (is_ctor)
2844 s = ctors_section;
2845 else
2846 s = dtors_section;
2848 switch_to_section (s);
2849 assemble_align (POINTER_SIZE);
2850 fputs ("\t.word\t", asm_out_file);
2851 output_addr_const (asm_out_file, symbol);
2852 fputs ("\n", asm_out_file);
2855 /* Add a function to the list of static constructors. */
2857 static void
2858 microblaze_elf_asm_constructor (rtx symbol, int priority)
2860 microblaze_elf_asm_cdtor (symbol, priority, /*is_ctor=*/true);
2863 /* Add a function to the list of static destructors. */
2865 static void
2866 microblaze_elf_asm_destructor (rtx symbol, int priority)
2868 microblaze_elf_asm_cdtor (symbol, priority, /*is_ctor=*/false);
2871 /* Expand the prologue into a bunch of separate insns. */
2873 void
2874 microblaze_expand_prologue (void)
2876 int regno;
2877 HOST_WIDE_INT fsiz;
2878 const char *arg_name = 0;
2879 tree fndecl = current_function_decl;
2880 tree fntype = TREE_TYPE (fndecl);
2881 tree fnargs = DECL_ARGUMENTS (fndecl);
2882 rtx next_arg_reg;
2883 int i;
2884 tree next_arg;
2885 tree cur_arg;
2886 CUMULATIVE_ARGS args_so_far_v;
2887 cumulative_args_t args_so_far;
2888 rtx mem_rtx, reg_rtx;
2890 /* If struct value address is treated as the first argument, make it so. */
2891 if (aggregate_value_p (DECL_RESULT (fndecl), fntype)
2892 && !cfun->returns_pcc_struct)
2894 tree type = build_pointer_type (fntype);
2895 tree function_result_decl = build_decl (BUILTINS_LOCATION, PARM_DECL,
2896 NULL_TREE, type);
2898 DECL_ARG_TYPE (function_result_decl) = type;
2899 TREE_CHAIN (function_result_decl) = fnargs;
2900 fnargs = function_result_decl;
2903 /* Determine the last argument, and get its name. */
2905 INIT_CUMULATIVE_ARGS (args_so_far_v, fntype, NULL_RTX, 0, 0);
2906 args_so_far = pack_cumulative_args (&args_so_far_v);
2907 regno = GP_ARG_FIRST;
2909 for (cur_arg = fnargs; cur_arg != 0; cur_arg = next_arg)
2911 tree passed_type = DECL_ARG_TYPE (cur_arg);
2912 machine_mode passed_mode = TYPE_MODE (passed_type);
2913 rtx entry_parm;
2915 if (TREE_ADDRESSABLE (passed_type))
2917 passed_type = build_pointer_type (passed_type);
2918 passed_mode = Pmode;
2921 function_arg_info arg (passed_type, passed_mode, /*named=*/true);
2922 entry_parm = targetm.calls.function_arg (args_so_far, arg);
2924 if (entry_parm)
2926 int words;
2928 /* passed in a register, so will get homed automatically. */
2929 if (GET_MODE (entry_parm) == BLKmode)
2930 words = (int_size_in_bytes (passed_type) + 3) / 4;
2931 else
2932 words = (GET_MODE_SIZE (GET_MODE (entry_parm)) + 3) / 4;
2934 regno = REGNO (entry_parm) + words - 1;
2936 else
2938 regno = GP_ARG_LAST + 1;
2939 break;
2942 targetm.calls.function_arg_advance (args_so_far, arg);
2944 next_arg = TREE_CHAIN (cur_arg);
2945 if (next_arg == 0)
2947 if (DECL_NAME (cur_arg))
2948 arg_name = IDENTIFIER_POINTER (DECL_NAME (cur_arg));
2950 break;
2954 /* Split parallel insn into a sequence of insns. */
2956 next_arg_reg = targetm.calls.function_arg (args_so_far,
2957 function_arg_info::end_marker ());
2958 if (next_arg_reg != 0 && GET_CODE (next_arg_reg) == PARALLEL)
2960 rtvec adjust = XVEC (next_arg_reg, 0);
2961 int num = GET_NUM_ELEM (adjust);
2963 for (i = 0; i < num; i++)
2965 rtx pattern = RTVEC_ELT (adjust, i);
2966 emit_insn (pattern);
2970 fsiz = compute_frame_size (get_frame_size ());
2972 if (flag_stack_usage_info)
2973 current_function_static_stack_size = fsiz;
2975 /* If this function is a varargs function, store any registers that
2976 would normally hold arguments ($5 - $10) on the stack. */
2977 if (((TYPE_ARG_TYPES (fntype) != 0
2978 && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
2979 != void_type_node))
2980 || (arg_name != 0
2981 && ((arg_name[0] == '_'
2982 && strcmp (arg_name, "__builtin_va_alist") == 0)
2983 || (arg_name[0] == 'v'
2984 && strcmp (arg_name, "va_alist") == 0)))))
2986 int offset = (regno - GP_ARG_FIRST + 1) * UNITS_PER_WORD;
2987 rtx ptr = stack_pointer_rtx;
2989 /* If we are doing svr4-abi, sp has already been decremented by fsiz. */
2990 for (; regno <= GP_ARG_LAST; regno++)
2992 if (offset != 0)
2993 ptr = gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (offset));
2994 emit_move_insn (gen_rtx_MEM (SImode, ptr),
2995 gen_rtx_REG (SImode, regno));
2997 offset += GET_MODE_SIZE (SImode);
3001 if (fsiz > 0)
3003 rtx fsiz_rtx = GEN_INT (fsiz);
3005 rtx_insn *insn = NULL;
3006 insn = emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx,
3007 fsiz_rtx));
3008 if (insn)
3009 RTX_FRAME_RELATED_P (insn) = 1;
3011 /* Handle SUB_RETURN_ADDR_REGNUM specially at first. */
3012 if (!crtl->is_leaf || interrupt_handler)
3014 mem_rtx = gen_rtx_MEM (SImode,
3015 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
3016 const0_rtx));
3018 if (interrupt_handler)
3019 /* Do not optimize in flow analysis. */
3020 MEM_VOLATILE_P (mem_rtx) = 1;
3022 reg_rtx = gen_rtx_REG (SImode, MB_ABI_SUB_RETURN_ADDR_REGNUM);
3023 insn = emit_move_insn (mem_rtx, reg_rtx);
3024 RTX_FRAME_RELATED_P (insn) = 1;
3027 /* _save_ registers for prologue. */
3028 save_restore_insns (1);
3030 if (frame_pointer_needed)
3032 rtx_insn *insn = 0;
3034 insn = emit_insn (gen_movsi (hard_frame_pointer_rtx,
3035 stack_pointer_rtx));
3037 if (insn)
3038 RTX_FRAME_RELATED_P (insn) = 1;
3042 if ((flag_pic == 2 || TLS_NEEDS_GOT )
3043 && df_regs_ever_live_p (MB_ABI_PIC_ADDR_REGNUM))
3045 if ((flag_pic == 2 && !TARGET_PIC_DATA_TEXT_REL) || TLS_NEEDS_GOT)
3047 SET_REGNO (pic_offset_table_rtx, MB_ABI_PIC_ADDR_REGNUM);
3048 /* setting GOT. */
3049 emit_insn (gen_set_got (pic_offset_table_rtx));
3051 else
3053 SET_REGNO (pic_offset_table_rtx, MB_ABI_PIC_ADDR_REGNUM);
3054 /* setting start of text. */
3055 emit_insn (gen_set_text (pic_offset_table_rtx));
3059 /* If we are profiling, make sure no instructions are scheduled before
3060 the call to mcount. */
3062 if (profile_flag)
3063 emit_insn (gen_blockage ());
3066 /* Do necessary cleanup after a function to restore stack, frame, and regs. */
3068 #define RA_MASK ((long) 0x80000000) /* 1 << 31 */
3069 #define PIC_OFFSET_TABLE_MASK (1 << (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST))
3071 static void
3072 microblaze_function_epilogue (FILE *file)
3074 const char *fnname;
3076 /* Get the function name the same way that toplev.cc does before calling
3077 assemble_start_function. This is needed so that the name used here
3078 exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */
3079 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
3081 if (!flag_inhibit_size_directive)
3083 fputs ("\t.end\t", file);
3084 if (interrupt_handler && !break_handler)
3085 fputs ("_interrupt_handler", file);
3086 else if (break_handler)
3087 fputs ("_break_handler", file);
3088 else
3089 assemble_name (file, fnname);
3090 fputs ("\n", file);
3093 /* Reset state info for each function. */
3094 current_frame_info = zero_frame_info;
3096 /* Restore the output file if optimizing the GP (optimizing the GP causes
3097 the text to be diverted to a tempfile, so that data decls come before
3098 references to the data). */
3101 /* Expand the epilogue into a bunch of separate insns. */
3103 void
3104 microblaze_expand_epilogue (void)
3106 HOST_WIDE_INT fsiz = current_frame_info.total_size;
3107 rtx fsiz_rtx = GEN_INT (fsiz);
3108 rtx reg_rtx;
3109 rtx mem_rtx;
3111 /* In case of interrupt handlers use addki instead of addi for changing the
3112 stack pointer value. */
3114 if (microblaze_can_use_return_insn ())
3116 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode,
3117 GP_REG_FIRST +
3118 MB_ABI_SUB_RETURN_ADDR_REGNUM)));
3119 return;
3122 if (fsiz > 0)
3124 /* Restore SUB_RETURN_ADDR_REGNUM at first. This is to prevent the
3125 sequence of load-followed by a use (in rtsd) in every prologue. Saves
3126 a load-use stall cycle :) This is also important to handle alloca.
3127 (See comments for if (frame_pointer_needed) below. */
3129 if (!crtl->is_leaf || interrupt_handler)
3131 mem_rtx =
3132 gen_rtx_MEM (SImode,
3133 gen_rtx_PLUS (Pmode, stack_pointer_rtx, const0_rtx));
3134 if (interrupt_handler)
3135 /* Do not optimize in flow analysis. */
3136 MEM_VOLATILE_P (mem_rtx) = 1;
3137 reg_rtx = gen_rtx_REG (SImode, MB_ABI_SUB_RETURN_ADDR_REGNUM);
3138 emit_move_insn (reg_rtx, mem_rtx);
3141 /* It is important that this is done after we restore the return address
3142 register (above). When alloca is used, we want to restore the
3143 sub-routine return address only from the current stack top and not
3144 from the frame pointer (which we restore below). (frame_pointer + 0)
3145 might have been over-written since alloca allocates memory on the
3146 current stack. */
3147 if (frame_pointer_needed)
3148 emit_insn (gen_movsi (stack_pointer_rtx, hard_frame_pointer_rtx));
3150 /* _restore_ registers for epilogue. */
3151 save_restore_insns (0);
3152 emit_insn (gen_blockage ());
3153 emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, fsiz_rtx));
3156 if (crtl->calls_eh_return)
3157 emit_insn (gen_addsi3 (stack_pointer_rtx,
3158 stack_pointer_rtx,
3159 gen_raw_REG (SImode,
3160 MB_EH_STACKADJ_REGNUM)));
3162 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode, GP_REG_FIRST +
3163 MB_ABI_SUB_RETURN_ADDR_REGNUM)));
3167 /* Return nonzero if this function is known to have a null epilogue.
3168 This allows the optimizer to omit jumps to jumps if no stack
3169 was created. */
3172 microblaze_can_use_return_insn (void)
3174 if (!reload_completed)
3175 return 0;
3177 if (df_regs_ever_live_p (MB_ABI_SUB_RETURN_ADDR_REGNUM) || profile_flag)
3178 return 0;
3180 if (current_frame_info.initialized)
3181 return current_frame_info.total_size == 0;
3183 return compute_frame_size (get_frame_size ()) == 0;
3186 /* Implement TARGET_SECONDARY_RELOAD. */
3188 static reg_class_t
3189 microblaze_secondary_reload (bool in_p ATTRIBUTE_UNUSED, rtx x ATTRIBUTE_UNUSED,
3190 reg_class_t rclass, machine_mode mode ATTRIBUTE_UNUSED,
3191 secondary_reload_info *sri ATTRIBUTE_UNUSED)
3193 if (rclass == ST_REGS)
3194 return GR_REGS;
3196 return NO_REGS;
3199 static void
3200 microblaze_globalize_label (FILE * stream, const char *name)
3202 fputs ("\t.globl\t", stream);
3203 if (microblaze_is_interrupt_variant ())
3205 if (interrupt_handler && strcmp (name, INTERRUPT_HANDLER_NAME))
3206 fputs (INTERRUPT_HANDLER_NAME, stream);
3207 else if (break_handler && strcmp (name, BREAK_HANDLER_NAME))
3208 fputs (BREAK_HANDLER_NAME, stream);
3209 else if (fast_interrupt && strcmp (name, FAST_INTERRUPT_NAME))
3210 fputs (FAST_INTERRUPT_NAME, stream);
3211 fputs ("\n\t.globl\t", stream);
3213 assemble_name (stream, name);
3214 fputs ("\n", stream);
3217 /* Returns true if decl should be placed into a "small data" section. */
3218 static bool
3219 microblaze_elf_in_small_data_p (const_tree decl)
3221 HOST_WIDE_INT size;
3223 if (!TARGET_XLGPOPT)
3224 return false;
3226 /* We want to merge strings, so we never consider them small data. */
3227 if (TREE_CODE (decl) == STRING_CST)
3228 return false;
3230 /* Functions are never in the small data area. */
3231 if (TREE_CODE (decl) == FUNCTION_DECL)
3232 return false;
3234 if (VAR_P (decl) && DECL_SECTION_NAME (decl))
3236 const char *section = DECL_SECTION_NAME (decl);
3237 if (strcmp (section, ".sdata") == 0
3238 || strcmp (section, ".sdata2") == 0
3239 || strcmp (section, ".sbss") == 0
3240 || strcmp (section, ".sbss2") == 0)
3241 return true;
3244 size = int_size_in_bytes (TREE_TYPE (decl));
3246 return (size > 0 && size <= microblaze_section_threshold);
3249 /* We need to disable address diff vectors in
3250 case of pic data text relative mode. */
3252 static bool
3253 microblaze_gen_pic_addr_dif_vec (void)
3255 return (flag_pic && !TARGET_PIC_DATA_TEXT_REL);
3258 static section *
3259 microblaze_select_section (tree decl, int reloc, unsigned HOST_WIDE_INT align)
3261 switch (categorize_decl_for_section (decl, reloc))
3263 case SECCAT_RODATA_MERGE_STR:
3264 case SECCAT_RODATA_MERGE_STR_INIT:
3265 /* MB binutils have various issues with mergeable string sections and
3266 relaxation/relocation. Currently, turning mergeable sections
3267 into regular readonly sections. */
3269 return readonly_data_section;
3270 default:
3271 return default_elf_select_section (decl, reloc, align);
3276 Encode info about sections into the RTL based on a symbol's declaration.
3277 The default definition of this hook, default_encode_section_info in
3278 `varasm.cc', sets a number of commonly-useful bits in SYMBOL_REF_FLAGS. */
3280 static void
3281 microblaze_encode_section_info (tree decl, rtx rtl, int first)
3283 default_encode_section_info (decl, rtl, first);
3286 static rtx
3287 expand_pic_symbol_ref (machine_mode mode ATTRIBUTE_UNUSED, rtx op)
3289 rtx result;
3290 bool isFunc = (GET_CODE (op) == SYMBOL_REF
3291 && (SYMBOL_REF_FLAGS (op) & SYMBOL_FLAG_FUNCTION));
3292 result = (!TARGET_PIC_DATA_TEXT_REL)
3293 ? gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op), UNSPEC_GOTOFF)
3294 : gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op), UNSPEC_TEXT);
3295 result = gen_rtx_CONST (Pmode, result);
3296 result = (TARGET_PIC_DATA_TEXT_REL && isFunc)
3297 ? gen_rtx_PLUS (Pmode, gen_raw_REG (Pmode,
3298 get_base_reg (op)), result)
3299 : gen_rtx_PLUS (Pmode, pic_offset_table_rtx, result);
3300 result = (!TARGET_PIC_DATA_TEXT_REL)
3301 ? gen_const_mem (Pmode, result) : result;
3303 return result;
3306 static void
3307 microblaze_asm_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
3308 HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
3309 tree function)
3311 const char *fnname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (thunk_fndecl));
3312 rtx this_rtx, funexp;
3313 rtx_insn *insn;
3315 reload_completed = 1;
3316 epilogue_completed = 1;
3318 /* Mark the end of the (empty) prologue. */
3319 emit_note (NOTE_INSN_PROLOGUE_END);
3321 /* Find the "this" pointer. If the function returns a structure,
3322 the structure return pointer is in MB_ABI_FIRST_ARG_REGNUM. */
3323 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
3324 this_rtx = gen_rtx_REG (Pmode, (MB_ABI_FIRST_ARG_REGNUM + 1));
3325 else
3326 this_rtx = gen_rtx_REG (Pmode, MB_ABI_FIRST_ARG_REGNUM);
3328 /* Apply the constant offset, if required. */
3329 if (delta)
3330 emit_insn (gen_addsi3 (this_rtx, this_rtx, GEN_INT (delta)));
3332 /* Apply the offset from the vtable, if required. */
3333 if (vcall_offset)
3335 rtx vcall_offset_rtx = GEN_INT (vcall_offset);
3336 rtx temp1 = gen_rtx_REG (Pmode, MB_ABI_TEMP1_REGNUM);
3338 emit_move_insn (temp1, gen_rtx_MEM (Pmode, this_rtx));
3340 rtx loc = gen_rtx_PLUS (Pmode, temp1, vcall_offset_rtx);
3341 emit_move_insn (temp1, gen_rtx_MEM (Pmode, loc));
3343 emit_insn (gen_addsi3 (this_rtx, this_rtx, temp1));
3346 /* Generate a tail call to the target function. */
3347 if (!TREE_USED (function))
3349 assemble_external (function);
3350 TREE_USED (function) = 1;
3353 funexp = XEXP (DECL_RTL (function), 0);
3354 rtx temp2 = gen_rtx_REG (Pmode, MB_ABI_TEMP2_REGNUM);
3356 if (flag_pic)
3357 emit_move_insn (temp2, expand_pic_symbol_ref (Pmode, funexp));
3358 else
3359 emit_move_insn (temp2, funexp);
3361 emit_insn (gen_indirect_jump (temp2));
3363 /* Run just enough of rest_of_compilation. This sequence was
3364 "borrowed" from rs6000.cc. */
3365 insn = get_insns ();
3366 shorten_branches (insn);
3367 assemble_start_function (thunk_fndecl, fnname);
3368 final_start_function (insn, file, 1);
3369 final (insn, file, 1);
3370 final_end_function ();
3371 assemble_end_function (thunk_fndecl, fnname);
3373 reload_completed = 0;
3374 epilogue_completed = 0;
3377 bool
3378 microblaze_expand_move (machine_mode mode, rtx operands[])
3380 rtx op0, op1;
3382 op0 = operands[0];
3383 op1 = operands[1];
3385 if (!register_operand (op0, SImode)
3386 && !register_operand (op1, SImode)
3387 && (GET_CODE (op1) != CONST_INT || INTVAL (op1) != 0))
3389 rtx temp = force_reg (SImode, op1);
3390 emit_move_insn (op0, temp);
3391 return true;
3393 /* If operands[1] is a constant address invalid for pic, then we need to
3394 handle it just like LEGITIMIZE_ADDRESS does. */
3395 if (GET_CODE (op1) == SYMBOL_REF || GET_CODE (op1) == LABEL_REF)
3397 rtx result;
3398 if (microblaze_tls_symbol_p(op1))
3400 result = microblaze_legitimize_tls_address (op1, NULL_RTX);
3401 emit_move_insn (op0, result);
3402 return true;
3404 else if (flag_pic)
3406 if (reload_in_progress)
3407 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
3408 result = expand_pic_symbol_ref (mode, op1);
3410 if (TARGET_PIC_DATA_TEXT_REL && GET_CODE (op0) == REG
3411 && REGNO (op0) >= FIRST_PSEUDO_REGISTER)
3412 result = force_reg (SImode, result);
3414 emit_move_insn (op0, result);
3415 return true;
3418 if (GET_CODE (op1) == PLUS && GET_CODE (XEXP (op1,1)) == CONST)
3420 rtx p0, p1 = NULL, result, temp;
3422 p0 = XEXP (XEXP (op1,1), 0);
3424 if (GET_CODE (p0) == PLUS)
3426 p1 = XEXP (p0, 1);
3427 p0 = XEXP (p0, 0);
3430 /* This should never happen. */
3431 if (p1 == NULL)
3432 gcc_unreachable ();
3434 if (GET_CODE (p0) == UNSPEC && GET_CODE (p1) == CONST_INT
3435 && flag_pic && TARGET_PIC_DATA_TEXT_REL)
3437 result = gen_rtx_CONST (Pmode, p0);
3438 result = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, result);
3439 temp = force_reg (SImode, result);
3440 emit_move_insn (op0, gen_rtx_PLUS (SImode, temp, p1));
3441 return true;
3444 /* Handle Case of (const (plus symbol const_int)). */
3445 if (GET_CODE (op1) == CONST && GET_CODE (XEXP (op1,0)) == PLUS)
3447 rtx p0, p1;
3449 p0 = XEXP (XEXP (op1, 0), 0);
3450 p1 = XEXP (XEXP (op1, 0), 1);
3452 if ((GET_CODE (p1) == CONST_INT)
3453 && ((GET_CODE (p0) == UNSPEC)
3454 || ((GET_CODE (p0) == SYMBOL_REF || GET_CODE (p0) == LABEL_REF)
3455 && (flag_pic == 2 || microblaze_tls_symbol_p (p0)
3456 || !SMALL_INT (p1)))))
3458 rtx temp = force_reg (SImode, p0);
3459 rtx temp2 = p1;
3461 if (flag_pic && reload_in_progress)
3462 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
3463 emit_move_insn (op0, gen_rtx_PLUS (SImode, temp, temp2));
3464 return true;
3467 return false;
3470 /* Expand shift operations. */
3472 microblaze_expand_shift (rtx operands[])
3474 gcc_assert ((GET_CODE (operands[2]) == CONST_INT)
3475 || (GET_CODE (operands[2]) == REG)
3476 || (GET_CODE (operands[2]) == SUBREG));
3478 /* Shift by one -- generate pattern. */
3479 if ((GET_CODE (operands[2]) == CONST_INT) && (INTVAL (operands[2]) == 1))
3480 return 0;
3482 /* Have barrel shifter and shift > 1: use it. */
3483 if (TARGET_BARREL_SHIFT)
3484 return 0;
3486 gcc_assert ((GET_CODE (operands[0]) == REG)
3487 || (GET_CODE (operands[0]) == SUBREG)
3488 || (GET_CODE (operands[1]) == REG)
3489 || (GET_CODE (operands[1]) == SUBREG));
3491 /* Shift by zero -- copy regs if necessary. */
3492 if (operands[2] == const0_rtx
3493 && !rtx_equal_p (operands[0], operands[1]))
3495 emit_insn (gen_movsi (operands[0], operands[1]));
3496 return 1;
3499 return 0;
3502 /* Return an RTX indicating where the return address to the
3503 calling function can be found. */
3505 microblaze_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
3507 if (count != 0)
3508 return NULL_RTX;
3510 return get_hard_reg_initial_val (Pmode,
3511 MB_ABI_SUB_RETURN_ADDR_REGNUM);
3514 void
3515 microblaze_eh_return (rtx op0)
3517 emit_insn (gen_movsi (gen_rtx_MEM (Pmode, stack_pointer_rtx), op0));
3520 /* Queue an .ident string in the queue of top-level asm statements.
3521 If the string size is below the threshold, put it into .sdata2.
3522 If the front-end is done, we must be being called from toplev.cc.
3523 In that case, do nothing. */
3524 void
3525 microblaze_asm_output_ident (const char *string)
3527 const char *section_asm_op;
3528 int size;
3529 char *buf;
3531 if (symtab->state != PARSING)
3532 return;
3534 size = strlen (string) + 1;
3535 if (size <= microblaze_section_threshold)
3536 section_asm_op = SDATA2_SECTION_ASM_OP;
3537 else
3538 section_asm_op = READONLY_DATA_SECTION_ASM_OP;
3540 buf = ACONCAT (("\t.pushsection", section_asm_op,
3541 "\n\t.ascii \"", string, "\\0\"\n",
3542 "\t.popsection\n", NULL));
3543 symtab->finalize_toplevel_asm (build_string (strlen (buf), buf));
3546 static void
3547 microblaze_elf_asm_init_sections (void)
3549 sdata2_section
3550 = get_unnamed_section (SECTION_WRITE, output_section_asm_op,
3551 SDATA2_SECTION_ASM_OP);
3554 /* Generate assembler code for constant parts of a trampoline. */
3556 static void
3557 microblaze_asm_trampoline_template (FILE *f)
3559 fprintf (f, "\tmfs r18, rpc\n");
3560 fprintf (f, "\tlwi r3, r18, 16\n");
3561 fprintf (f, "\tlwi r18, r18, 20\n");
3562 fprintf (f, "\tbra r18\n");
3563 /* fprintf (f, "\t.word\t0x00000000\t\t# <function address>\n"); */
3564 /* fprintf (f, "\t.word\t0x00000000\t\t# <static chain value>\n"); */
3567 /* Implement TARGET_TRAMPOLINE_INIT. */
3569 static void
3570 microblaze_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
3572 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
3573 rtx mem;
3575 emit_block_move (m_tramp, assemble_trampoline_template (),
3576 GEN_INT (6*UNITS_PER_WORD), BLOCK_OP_NORMAL);
3578 mem = adjust_address (m_tramp, SImode, 16);
3579 emit_move_insn (mem, chain_value);
3580 mem = adjust_address (m_tramp, SImode, 20);
3581 emit_move_insn (mem, fnaddr);
3584 /* Generate conditional branch -- first, generate test condition,
3585 second, generate correct branch instruction. */
3587 void
3588 microblaze_expand_conditional_branch (machine_mode mode, rtx operands[])
3590 enum rtx_code code = GET_CODE (operands[0]);
3591 rtx cmp_op0 = operands[1];
3592 rtx cmp_op1 = operands[2];
3593 rtx label1 = operands[3];
3594 rtx comp_reg = gen_reg_rtx (SImode);
3595 rtx condition;
3597 gcc_assert ((GET_CODE (cmp_op0) == REG) || (GET_CODE (cmp_op0) == SUBREG));
3599 /* If comparing against zero, just test source reg. */
3600 if (cmp_op1 == const0_rtx)
3602 comp_reg = cmp_op0;
3603 condition = gen_rtx_fmt_ee (signed_condition (code), SImode, comp_reg, const0_rtx);
3604 emit_jump_insn (gen_condjump (condition, label1));
3607 else if (code == EQ || code == NE)
3609 /* Use xor for equal/not-equal comparison. */
3610 emit_insn (gen_xorsi3 (comp_reg, cmp_op0, cmp_op1));
3611 condition = gen_rtx_fmt_ee (signed_condition (code), SImode, comp_reg, const0_rtx);
3612 emit_jump_insn (gen_condjump (condition, label1));
3614 else
3616 /* Generate compare and branch in single instruction. */
3617 cmp_op1 = force_reg (mode, cmp_op1);
3618 condition = gen_rtx_fmt_ee (code, mode, cmp_op0, cmp_op1);
3619 emit_jump_insn (gen_branch_compare(condition, cmp_op0, cmp_op1, label1));
3623 void
3624 microblaze_expand_conditional_branch_reg (machine_mode mode, rtx operands[])
3626 enum rtx_code code = GET_CODE (operands[0]);
3627 rtx cmp_op0 = operands[1];
3628 rtx cmp_op1 = operands[2];
3629 rtx label1 = operands[3];
3630 rtx comp_reg = gen_reg_rtx (SImode);
3631 rtx condition;
3633 gcc_assert ((GET_CODE (cmp_op0) == REG)
3634 || (GET_CODE (cmp_op0) == SUBREG));
3636 /* If comparing against zero, just test source reg. */
3637 if (cmp_op1 == const0_rtx)
3639 comp_reg = cmp_op0;
3640 condition = gen_rtx_fmt_ee (signed_condition (code),
3641 SImode, comp_reg, const0_rtx);
3642 emit_jump_insn (gen_condjump (condition, label1));
3644 else if (code == EQ)
3646 emit_insn (gen_seq_internal_pat (comp_reg,
3647 cmp_op0, cmp_op1));
3648 condition = gen_rtx_EQ (SImode, comp_reg, const0_rtx);
3649 emit_jump_insn (gen_condjump (condition, label1));
3651 else if (code == NE)
3653 emit_insn (gen_sne_internal_pat (comp_reg, cmp_op0,
3654 cmp_op1));
3655 condition = gen_rtx_NE (SImode, comp_reg, const0_rtx);
3656 emit_jump_insn (gen_condjump (condition, label1));
3658 else
3660 /* Generate compare and branch in single instruction. */
3661 cmp_op1 = force_reg (mode, cmp_op1);
3662 condition = gen_rtx_fmt_ee (code, mode, cmp_op0, cmp_op1);
3663 emit_jump_insn (gen_branch_compare (condition, cmp_op0,
3664 cmp_op1, label1));
3668 void
3669 microblaze_expand_conditional_branch_sf (rtx operands[])
3671 rtx condition;
3672 rtx cmp_op0 = XEXP (operands[0], 0);
3673 rtx cmp_op1 = XEXP (operands[0], 1);
3674 rtx comp_reg = gen_reg_rtx (SImode);
3676 emit_insn (gen_cstoresf4 (comp_reg, operands[0], cmp_op0, cmp_op1));
3677 condition = gen_rtx_NE (SImode, comp_reg, const0_rtx);
3678 emit_jump_insn (gen_condjump (condition, operands[3]));
3681 /* Implement TARGET_FRAME_POINTER_REQUIRED. */
3683 static bool
3684 microblaze_frame_pointer_required (void)
3686 /* If the function contains dynamic stack allocations, we need to
3687 use the frame pointer to access the static parts of the frame. */
3688 if (cfun->calls_alloca)
3689 return true;
3690 return false;
3693 void
3694 microblaze_expand_divide (rtx operands[])
3696 /* Table lookup software divides. Works for all (nr/dr) where (0 <= nr,dr <= 15). */
3698 rtx regt1 = gen_reg_rtx (SImode);
3699 rtx reg18 = gen_rtx_REG (SImode, R_TMP);
3700 rtx regqi = gen_reg_rtx (QImode);
3701 rtx_code_label *div_label = gen_label_rtx ();
3702 rtx_code_label *div_end_label = gen_label_rtx ();
3703 rtx div_table_rtx = gen_rtx_SYMBOL_REF (QImode,"_divsi3_table");
3704 rtx mem_rtx;
3705 rtx ret;
3706 rtx_insn *jump, *cjump, *insn;
3708 insn = emit_insn (gen_iorsi3 (regt1, operands[1], operands[2]));
3709 cjump = emit_jump_insn_after (gen_cbranchsi4 (
3710 gen_rtx_GTU (SImode, regt1, GEN_INT (15)),
3711 regt1, GEN_INT (15), div_label), insn);
3712 LABEL_NUSES (div_label) = 1;
3713 JUMP_LABEL (cjump) = div_label;
3714 emit_insn (gen_rtx_CLOBBER (SImode, reg18));
3716 emit_insn (gen_ashlsi3_bshift (regt1, operands[1], GEN_INT(4)));
3717 emit_insn (gen_addsi3 (regt1, regt1, operands[2]));
3718 mem_rtx = gen_rtx_MEM (QImode,
3719 gen_rtx_PLUS (Pmode, regt1, div_table_rtx));
3721 insn = emit_insn (gen_movqi (regqi, mem_rtx));
3722 insn = emit_insn (gen_movsi (operands[0], gen_rtx_SUBREG (SImode, regqi, 0)));
3723 jump = emit_jump_insn_after (gen_jump (div_end_label), insn);
3724 JUMP_LABEL (jump) = div_end_label;
3725 LABEL_NUSES (div_end_label) = 1;
3726 emit_barrier ();
3728 emit_label (div_label);
3729 ret = emit_library_call_value (gen_rtx_SYMBOL_REF (Pmode, "__divsi3"),
3730 operands[0], LCT_NORMAL,
3731 GET_MODE (operands[0]),
3732 operands[1], GET_MODE (operands[1]),
3733 operands[2], GET_MODE (operands[2]));
3734 if (ret != operands[0])
3735 emit_move_insn (operands[0], ret);
3737 emit_label (div_end_label);
3738 emit_insn (gen_blockage ());
3741 /* Implement TARGET_FUNCTION_VALUE. */
3742 static rtx
3743 microblaze_function_value (const_tree valtype,
3744 const_tree func ATTRIBUTE_UNUSED,
3745 bool outgoing ATTRIBUTE_UNUSED)
3747 return LIBCALL_VALUE (TYPE_MODE (valtype));
3750 /* Implement TARGET_SCHED_ADJUST_COST. */
3751 static int
3752 microblaze_adjust_cost (rtx_insn *, int dep_type, rtx_insn *, int cost,
3753 unsigned int)
3755 if (dep_type == REG_DEP_OUTPUT || dep_type == 0)
3756 return cost;
3757 return 0;
3760 /* Implement TARGET_LEGITIMATE_CONSTANT_P.
3762 At present, GAS doesn't understand li.[sd], so don't allow it
3763 to be generated at present. */
3764 static bool
3765 microblaze_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED, rtx x)
3768 if (microblaze_cannot_force_const_mem(mode, x))
3769 return false;
3771 if (GET_CODE (x) == CONST_DOUBLE)
3773 return microblaze_const_double_ok (x, GET_MODE (x));
3776 /* Handle Case of (const (plus unspec const_int)). */
3777 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x,0)) == PLUS)
3779 rtx p0, p1;
3781 p0 = XEXP (XEXP (x, 0), 0);
3782 p1 = XEXP (XEXP (x, 0), 1);
3784 if (GET_CODE(p1) == CONST_INT)
3786 /* Const offset from UNSPEC is not supported. */
3787 if ((GET_CODE (p0) == UNSPEC))
3788 return false;
3790 if ((GET_CODE (p0) == SYMBOL_REF || GET_CODE (p0) == LABEL_REF)
3791 && (microblaze_tls_symbol_p (p0) || !SMALL_INT (p1)))
3792 return false;
3796 return true;
3799 static rtx
3800 get_branch_target (rtx branch)
3802 if (CALL_P (branch))
3804 rtx call;
3806 call = XVECEXP (PATTERN (branch), 0, 0);
3807 if (GET_CODE (call) == SET)
3808 call = SET_SRC (call);
3809 if (GET_CODE (call) != CALL)
3810 gcc_unreachable ();
3811 return XEXP (XEXP (call, 0), 0);
3814 return NULL_RTX;
3817 /* Heuristics to identify where to insert at the
3818 fall through path of the caller function. If there
3819 is a call after the caller branch delay slot then
3820 we dont generate the instruction prefetch instruction.
3822 Scan up to 32 instructions after the call and checks
3823 for the JUMP and call instruction . If there is a call
3824 or JUMP instruction in the range of 32 instruction "wic"
3825 instruction wont be generated. Otherwise insert the "wic"
3826 instruction in the fall through of the call instruction
3827 four instruction after the call. before_4 is used for
3828 the position to insert "wic" instructions. before_16 is
3829 used to check for call and JUMP instruction for first
3830 15 insns. */
3832 static void
3833 insert_wic_for_ilb_runout (rtx_insn *first)
3835 rtx_insn *insn;
3836 rtx_insn *before_4 = 0;
3837 rtx_insn *before_16 = 0;
3838 int addr_offset = 0;
3839 int length;
3840 int wic_addr0 = 128 * 4;
3842 int first_addr = INSN_ADDRESSES (INSN_UID (first));
3844 for (insn = first; insn; insn = NEXT_INSN (insn))
3845 if (INSN_P (insn))
3847 addr_offset = INSN_ADDRESSES (INSN_UID (insn)) - first_addr;
3848 length = get_attr_length (insn);
3849 if (before_4 == 0 && addr_offset + length >= 4 * 4)
3850 before_4 = insn;
3852 if (JUMP_P(insn))
3853 return;
3854 if (before_16 == 0 && addr_offset + length >= 14 * 4)
3855 before_16 = insn;
3856 if (CALL_P (insn) || tablejump_p (insn, 0, 0))
3857 return;
3858 if (addr_offset + length >= 32 * 4)
3860 gcc_assert (before_4 && before_16);
3861 if (wic_addr0 > 4 * 4)
3863 insn =
3864 emit_insn_before (gen_iprefetch
3865 (gen_int_mode (addr_offset, SImode)),
3866 before_4);
3867 recog_memoized (insn);
3868 INSN_LOCATION (insn) = INSN_LOCATION (before_4);
3869 INSN_ADDRESSES_NEW (insn, INSN_ADDRESSES (INSN_UID (before_4)));
3870 return;
3876 /* Insert instruction prefetch instruction at the fall
3877 through path of the function call. */
3879 static void
3880 insert_wic (void)
3882 rtx_insn *insn;
3883 int i;
3884 basic_block bb, prev = 0;
3885 rtx branch_target = 0;
3887 shorten_branches (get_insns ());
3889 for (i = 0; i < n_basic_blocks_for_fn (cfun) - 1; i++)
3891 edge e;
3892 edge_iterator ei;
3893 bool simple_loop = false;
3895 bb = BASIC_BLOCK_FOR_FN (cfun, i);
3897 if (bb == NULL)
3898 continue;
3900 if ((prev != 0) && (prev != bb))
3901 continue;
3902 else
3903 prev = 0;
3905 FOR_EACH_EDGE (e, ei, bb->preds)
3906 if (e->src == bb)
3908 simple_loop = true;
3909 prev= e->dest;
3910 break;
3913 for (insn = BB_END (bb); insn; insn = PREV_INSN (insn))
3915 if (INSN_P (insn) && !simple_loop
3916 && CALL_P(insn))
3918 if ((branch_target = get_branch_target (insn)))
3919 insert_wic_for_ilb_runout (
3920 next_active_insn (next_active_insn (insn)));
3922 if (insn == BB_HEAD (bb))
3923 break;
3928 /* The reorg function defined through the macro
3929 TARGET_MACHINE_DEPENDENT_REORG. */
3931 static void
3932 microblaze_machine_dependent_reorg (void)
3934 if (TARGET_PREFETCH)
3936 compute_bb_for_insn ();
3937 loop_optimizer_init (AVOID_CFG_MODIFICATIONS);
3938 shorten_branches (get_insns ());
3939 insert_wic ();
3940 loop_optimizer_finalize ();
3941 free_bb_for_insn ();
3942 return;
3946 /* Implement TARGET_CONSTANT_ALIGNMENT. */
3948 static HOST_WIDE_INT
3949 microblaze_constant_alignment (const_tree exp, HOST_WIDE_INT align)
3951 if (TREE_CODE (exp) == STRING_CST || TREE_CODE (exp) == CONSTRUCTOR)
3952 return MAX (align, BITS_PER_WORD);
3953 return align;
3956 /* Implement TARGET_STARTING_FRAME_OFFSET. */
3958 static HOST_WIDE_INT
3959 microblaze_starting_frame_offset (void)
3961 return (crtl->outgoing_args_size + FIRST_PARM_OFFSET(FNDECL));
3964 #undef TARGET_ENCODE_SECTION_INFO
3965 #define TARGET_ENCODE_SECTION_INFO microblaze_encode_section_info
3967 #undef TARGET_ASM_GLOBALIZE_LABEL
3968 #define TARGET_ASM_GLOBALIZE_LABEL microblaze_globalize_label
3970 #undef TARGET_ASM_FUNCTION_PROLOGUE
3971 #define TARGET_ASM_FUNCTION_PROLOGUE microblaze_function_prologue
3973 #undef TARGET_ASM_FUNCTION_EPILOGUE
3974 #define TARGET_ASM_FUNCTION_EPILOGUE microblaze_function_epilogue
3976 #undef TARGET_RTX_COSTS
3977 #define TARGET_RTX_COSTS microblaze_rtx_costs
3979 #undef TARGET_CANNOT_FORCE_CONST_MEM
3980 #define TARGET_CANNOT_FORCE_CONST_MEM microblaze_cannot_force_const_mem
3982 #undef TARGET_ADDRESS_COST
3983 #define TARGET_ADDRESS_COST microblaze_address_cost
3985 #undef TARGET_ATTRIBUTE_TABLE
3986 #define TARGET_ATTRIBUTE_TABLE microblaze_attribute_table
3988 #undef TARGET_IN_SMALL_DATA_P
3989 #define TARGET_IN_SMALL_DATA_P microblaze_elf_in_small_data_p
3991 #undef TARGET_ASM_SELECT_SECTION
3992 #define TARGET_ASM_SELECT_SECTION microblaze_select_section
3994 #undef TARGET_HAVE_SRODATA_SECTION
3995 #define TARGET_HAVE_SRODATA_SECTION true
3997 #undef TARGET_ASM_FUNCTION_END_PROLOGUE
3998 #define TARGET_ASM_FUNCTION_END_PROLOGUE \
3999 microblaze_function_end_prologue
4001 #undef TARGET_ARG_PARTIAL_BYTES
4002 #define TARGET_ARG_PARTIAL_BYTES function_arg_partial_bytes
4004 #undef TARGET_FUNCTION_ARG
4005 #define TARGET_FUNCTION_ARG microblaze_function_arg
4007 #undef TARGET_FUNCTION_ARG_ADVANCE
4008 #define TARGET_FUNCTION_ARG_ADVANCE microblaze_function_arg_advance
4010 #undef TARGET_CAN_ELIMINATE
4011 #define TARGET_CAN_ELIMINATE microblaze_can_eliminate
4013 #undef TARGET_LEGITIMIZE_ADDRESS
4014 #define TARGET_LEGITIMIZE_ADDRESS microblaze_legitimize_address
4016 #undef TARGET_LEGITIMATE_ADDRESS_P
4017 #define TARGET_LEGITIMATE_ADDRESS_P microblaze_legitimate_address_p
4019 #undef TARGET_FRAME_POINTER_REQUIRED
4020 #define TARGET_FRAME_POINTER_REQUIRED microblaze_frame_pointer_required
4022 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
4023 #define TARGET_ASM_TRAMPOLINE_TEMPLATE microblaze_asm_trampoline_template
4025 #undef TARGET_TRAMPOLINE_INIT
4026 #define TARGET_TRAMPOLINE_INIT microblaze_trampoline_init
4028 #undef TARGET_PROMOTE_FUNCTION_MODE
4029 #define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
4031 #undef TARGET_FUNCTION_VALUE
4032 #define TARGET_FUNCTION_VALUE microblaze_function_value
4034 #undef TARGET_SECONDARY_RELOAD
4035 #define TARGET_SECONDARY_RELOAD microblaze_secondary_reload
4037 #undef TARGET_ASM_OUTPUT_MI_THUNK
4038 #define TARGET_ASM_OUTPUT_MI_THUNK microblaze_asm_output_mi_thunk
4040 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
4041 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true
4043 #undef TARGET_SCHED_ADJUST_COST
4044 #define TARGET_SCHED_ADJUST_COST microblaze_adjust_cost
4046 #undef TARGET_ASM_INIT_SECTIONS
4047 #define TARGET_ASM_INIT_SECTIONS microblaze_elf_asm_init_sections
4049 #undef TARGET_OPTION_OVERRIDE
4050 #define TARGET_OPTION_OVERRIDE microblaze_option_override
4052 #undef TARGET_LEGITIMATE_CONSTANT_P
4053 #define TARGET_LEGITIMATE_CONSTANT_P microblaze_legitimate_constant_p
4055 #undef TARGET_ASM_GENERATE_PIC_ADDR_DIFF_VEC
4056 #define TARGET_ASM_GENERATE_PIC_ADDR_DIFF_VEC microblaze_gen_pic_addr_dif_vec
4058 #undef TARGET_MACHINE_DEPENDENT_REORG
4059 #define TARGET_MACHINE_DEPENDENT_REORG microblaze_machine_dependent_reorg
4061 #undef TARGET_HARD_REGNO_MODE_OK
4062 #define TARGET_HARD_REGNO_MODE_OK microblaze_hard_regno_mode_ok
4064 #undef TARGET_MODES_TIEABLE_P
4065 #define TARGET_MODES_TIEABLE_P microblaze_modes_tieable_p
4067 #undef TARGET_CONSTANT_ALIGNMENT
4068 #define TARGET_CONSTANT_ALIGNMENT microblaze_constant_alignment
4070 #undef TARGET_STARTING_FRAME_OFFSET
4071 #define TARGET_STARTING_FRAME_OFFSET microblaze_starting_frame_offset
4073 struct gcc_target targetm = TARGET_INITIALIZER;
4075 #include "gt-microblaze.h"