1 /* Subroutines used for code generation on Xilinx MicroBlaze.
2 Copyright 2009, 2010 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/>. */
24 #include "coretypes.h"
29 #include "hard-reg-set.h"
31 #include "insn-config.h"
32 #include "conditions.h"
33 #include "insn-flags.h"
34 #include "insn-attr.h"
35 #include "integrate.h"
47 #include "target-def.h"
52 #include "diagnostic-core.h"
54 #define MICROBLAZE_VERSION_COMPARE(VA,VB) strcasecmp (VA, VB)
56 /* Classifies an address.
63 A natural register or a register + const_int offset address.
64 The register satisfies microblaze_valid_base_register_p and the
65 offset is a const_arith_operand.
69 A natural register offset by the index contained in an index register. The base
70 register satisfies microblaze_valid_base_register_p and the index register
71 satisfies microblaze_valid_index_register_p
75 A signed 16/32-bit constant address.
79 A constant symbolic address or a (register + symbol). */
81 enum microblaze_address_type
97 enum microblaze_symbol_type
103 /* Classification of a MicroBlaze address. */
104 struct microblaze_address_info
106 enum microblaze_address_type type;
107 rtx regA; /* Contains valid values on ADDRESS_REG, ADDRESS_REG_INDEX,
109 rtx regB; /* Contains valid values on ADDRESS_REG_INDEX. */
110 rtx offset; /* Contains valid values on ADDRESS_CONST_INT and ADDRESS_REG. */
111 rtx symbol; /* Contains valid values on ADDRESS_SYMBOLIC. */
112 enum microblaze_symbol_type symbol_type;
115 /* Structure to be filled in by compute_frame_size with register
116 save masks, and offsets for the current function. */
118 struct GTY(()) microblaze_frame_info {
119 long total_size; /* # bytes that the entire frame takes up. */
120 long var_size; /* # bytes that variables take up. */
121 long args_size; /* # bytes that outgoing arguments take up. */
122 int link_debug_size; /* # bytes for the link reg and back pointer. */
123 int gp_reg_size; /* # bytes needed to store gp regs. */
124 long gp_offset; /* offset from new sp to store gp registers. */
125 long mask; /* mask of saved gp registers. */
126 int initialized; /* != 0 if frame size already calculated. */
127 int num_gp; /* number of gp registers saved. */
128 long insns_len; /* length of insns. */
129 int alloc_stack; /* Flag to indicate if the current function
130 must not create stack space. (As an optimization). */
133 /* Global variables for machine-dependent things. */
135 /* Toggle which pipleline interface to use. */
136 static GTY(()) int microblaze_sched_use_dfa = 0;
138 /* Threshold for data being put into the small data/bss area, instead
139 of the normal data area (references to the small data/bss area take
140 1 instruction, and use the global pointer, references to the normal
141 data area takes 2 instructions). */
142 int microblaze_section_threshold = -1;
144 /* Prevent scheduling potentially exception causing instructions in
145 delay slots. -mcpu=v3.00.a or v4.00.a turns this on. */
146 int microblaze_no_unsafe_delay;
148 /* Which CPU pipeline do we use. We haven't really standardized on a CPU
149 version having only a particular type of pipeline. There can still be
150 options on the CPU to scale pipeline features up or down. :(
151 Bad Presentation (??), so we let the MD file rely on the value of
152 this variable instead Making PIPE_5 the default. It should be backward
153 optimal with PIPE_3 MicroBlazes. */
154 enum pipeline_type microblaze_pipe = MICROBLAZE_PIPE_5;
156 /* High and low marks for floating point values which we will accept
157 as legitimate constants for LEGITIMATE_CONSTANT_P. These are
158 initialized in override_options. */
159 REAL_VALUE_TYPE dfhigh, dflow, sfhigh, sflow;
161 /* Array giving truth value on whether or not a given hard register
162 can support a given mode. */
163 char microblaze_hard_regno_mode_ok[(int)MAX_MACHINE_MODE]
164 [FIRST_PSEUDO_REGISTER];
166 /* Current frame information calculated by compute_frame_size. */
167 struct microblaze_frame_info current_frame_info;
169 /* Zero structure to initialize current_frame_info. */
170 struct microblaze_frame_info zero_frame_info;
172 /* List of all MICROBLAZE punctuation characters used by print_operand. */
173 char microblaze_print_operand_punct[256];
175 /* Map GCC register number to debugger register number. */
176 int microblaze_dbx_regno[FIRST_PSEUDO_REGISTER];
178 /* Map hard register number to register class. */
179 enum reg_class microblaze_regno_to_class[] =
181 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
182 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
183 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
184 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
185 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
186 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
187 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
188 GR_REGS, GR_REGS, GR_REGS, GR_REGS,
189 ST_REGS, GR_REGS, GR_REGS, GR_REGS
192 /* MicroBlaze specific machine attributes.
193 interrupt_handler - Interrupt handler attribute to add interrupt prologue
194 and epilogue and use appropriate interrupt return.
195 save_volatiles - Similiar to interrupt handler, but use normal return. */
196 int interrupt_handler;
199 const struct attribute_spec microblaze_attribute_table[] = {
200 /* name min_len, max_len, decl_req, type_req, fn_type, req_handler */
201 {"interrupt_handler", 0, 0, true, false, false, NULL},
202 {"save_volatiles" , 0, 0, true, false, false, NULL},
203 { NULL, 0, 0, false, false, false, NULL}
206 static int microblaze_interrupt_function_p (tree);
208 section *sdata2_section;
210 /* Return truth value if a CONST_DOUBLE is ok to be a legitimate constant. */
212 microblaze_const_double_ok (rtx op, enum machine_mode mode)
216 if (GET_CODE (op) != CONST_DOUBLE)
219 if (mode == VOIDmode)
222 if (mode != SFmode && mode != DFmode)
225 if (op == CONST0_RTX (mode))
228 REAL_VALUE_FROM_CONST_DOUBLE (d, op);
230 if (REAL_VALUE_ISNAN (d))
233 if (REAL_VALUE_NEGATIVE (d))
234 d = real_value_negate (&d);
238 if (REAL_VALUES_LESS (d, dfhigh) && REAL_VALUES_LESS (dflow, d))
243 if (REAL_VALUES_LESS (d, sfhigh) && REAL_VALUES_LESS (sflow, d))
250 /* Return truth value if a memory operand fits in a single instruction
251 (ie, register + small offset) or (register + register). */
254 simple_memory_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
256 rtx addr, plus0, plus1;
258 /* Eliminate non-memory operations. */
259 if (GET_CODE (op) != MEM)
262 /* dword operations really put out 2 instructions, so eliminate them. */
263 /* ??? This isn't strictly correct. It is OK to accept multiword modes
264 here, since the length attributes are being set correctly, but only
265 if the address is offsettable. */
266 if (GET_MODE_SIZE (GET_MODE (op)) > UNITS_PER_WORD)
270 /* Decode the address now. */
272 switch (GET_CODE (addr))
279 plus0 = XEXP (addr, 0);
280 plus1 = XEXP (addr, 1);
282 if (GET_CODE (plus0) == REG && GET_CODE (plus1) == CONST_INT
283 && SMALL_INT (plus1))
287 else if (GET_CODE (plus1) == REG && GET_CODE (plus0) == CONST_INT)
291 else if (GET_CODE (plus0) == REG && GET_CODE (plus1) == REG)
308 /* Return nonzero for a memory address that can be used to load or store
312 double_memory_operand (rtx op, enum machine_mode mode)
316 if (GET_CODE (op) != MEM || !memory_operand (op, mode))
318 /* During reload, we accept a pseudo register if it has an
319 appropriate memory address. If we don't do this, we will
320 wind up reloading into a register, and then reloading that
321 register from memory, when we could just reload directly from
323 if (reload_in_progress
324 && GET_CODE (op) == REG
325 && REGNO (op) >= FIRST_PSEUDO_REGISTER
326 && reg_renumber[REGNO (op)] < 0
327 && reg_equiv_mem[REGNO (op)] != 0
328 && double_memory_operand (reg_equiv_mem[REGNO (op)], mode))
333 /* Make sure that 4 added to the address is a valid memory address.
334 This essentially just checks for overflow in an added constant. */
338 if (CONSTANT_ADDRESS_P (addr))
341 return memory_address_p ((GET_MODE_CLASS (mode) == MODE_INT
342 ? SImode : SFmode), plus_constant (addr, 4));
345 /* Implement REG_OK_FOR_BASE_P -and- REG_OK_FOR_INDEX_P. */
347 microblaze_regno_ok_for_base_p (int regno, int strict)
349 if (regno >= FIRST_PSEUDO_REGISTER)
353 regno = reg_renumber[regno];
356 /* These fake registers will be eliminated to either the stack or
357 hard frame pointer, both of which are usually valid base registers.
358 Reload deals with the cases where the eliminated form isn't valid. */
359 if (regno == ARG_POINTER_REGNUM || regno == FRAME_POINTER_REGNUM)
362 return GP_REG_P (regno);
365 /* Return true if X is a valid base register for the given mode.
366 Allow only hard registers if STRICT. */
369 microblaze_valid_base_register_p (rtx x,
370 enum machine_mode mode ATTRIBUTE_UNUSED,
373 if (!strict && GET_CODE (x) == SUBREG)
376 return (GET_CODE (x) == REG
377 && microblaze_regno_ok_for_base_p (REGNO (x), strict));
381 microblaze_classify_unspec (struct microblaze_address_info *info, rtx x)
383 info->symbol_type = SYMBOL_TYPE_GENERAL;
384 info->symbol = XVECEXP (x, 0, 0);
386 if (XINT (x, 1) == UNSPEC_GOTOFF)
388 info->regA = gen_rtx_REG (SImode, PIC_OFFSET_TABLE_REGNUM);
389 info->type = ADDRESS_GOTOFF;
391 else if (XINT (x, 1) == UNSPEC_PLT)
393 info->type = ADDRESS_PLT;
403 /* Return true if X is a valid index register for the given mode.
404 Allow only hard registers if STRICT. */
407 microblaze_valid_index_register_p (rtx x,
408 enum machine_mode mode ATTRIBUTE_UNUSED,
411 if (!strict && GET_CODE (x) == SUBREG)
414 return (GET_CODE (x) == REG
415 /* A base register is good enough to be an index register on MicroBlaze. */
416 && microblaze_regno_ok_for_base_p (REGNO (x), strict));
419 /* Get the base register for accessing a value from the memory or
420 Symbol ref. Used for MicroBlaze Small Data Area Pointer Optimization. */
425 int base_reg = (flag_pic ? MB_ABI_PIC_ADDR_REGNUM : MB_ABI_BASE_REGNUM);
428 && GET_CODE (x) == SYMBOL_REF
429 && SYMBOL_REF_SMALL_P (x) && (decl = SYMBOL_REF_DECL (x)) != NULL)
431 if (TREE_READONLY (decl))
432 base_reg = MB_ABI_GPRO_REGNUM;
434 base_reg = MB_ABI_GPRW_REGNUM;
440 /* Return true if X is a valid address for machine mode MODE. If it is,
441 fill in INFO appropriately. STRICT is true if we should only accept
444 type regA regB offset symbol
446 ADDRESS_INVALID NULL NULL NULL NULL
448 ADDRESS_REG %0 NULL const_0 / NULL
450 ADDRESS_REG_INDEX %0 %1 NULL NULL
452 ADDRESS_SYMBOLIC r0 / NULL NULL symbol
455 ADDRESS_CONST_INT r0 NULL const NULL
457 For modes spanning multiple registers (DFmode in 32-bit GPRs,
458 DImode, TImode), indexed addressing cannot be used because
459 adjacent memory cells are accessed by adding word-sized offsets
460 during assembly output. */
463 microblaze_classify_address (struct microblaze_address_info *info, rtx x,
464 enum machine_mode mode, int strict)
469 info->type = ADDRESS_INVALID;
474 info->symbol_type = SYMBOL_TYPE_INVALID;
476 switch (GET_CODE (x))
481 info->type = ADDRESS_REG;
483 info->offset = const0_rtx;
484 return microblaze_valid_base_register_p (info->regA, mode, strict);
488 xplus0 = XEXP (x, 0);
489 xplus1 = XEXP (x, 1);
491 if (microblaze_valid_base_register_p (xplus0, mode, strict))
493 info->type = ADDRESS_REG;
496 if (GET_CODE (xplus1) == CONST_INT)
498 info->offset = xplus1;
501 else if (GET_CODE (xplus1) == UNSPEC)
503 return microblaze_classify_unspec (info, xplus1);
505 else if ((GET_CODE (xplus1) == SYMBOL_REF ||
506 GET_CODE (xplus1) == LABEL_REF) && flag_pic == 2)
510 else if (GET_CODE (xplus1) == SYMBOL_REF ||
511 GET_CODE (xplus1) == LABEL_REF ||
512 GET_CODE (xplus1) == CONST)
514 if (GET_CODE (XEXP (xplus1, 0)) == UNSPEC)
515 return microblaze_classify_unspec (info, XEXP (xplus1, 0));
516 else if (flag_pic == 2)
520 info->type = ADDRESS_SYMBOLIC;
521 info->symbol = xplus1;
522 info->symbol_type = SYMBOL_TYPE_GENERAL;
525 else if (GET_CODE (xplus1) == REG
526 && microblaze_valid_index_register_p (xplus1, mode,
528 && (GET_MODE_SIZE (mode) <= UNITS_PER_WORD))
530 /* Restrict larger than word-width modes from using an index register. */
531 info->type = ADDRESS_REG_INDEX;
540 info->regA = gen_rtx_raw_REG (mode, 0);
541 info->type = ADDRESS_CONST_INT;
549 info->type = ADDRESS_SYMBOLIC;
550 info->symbol_type = SYMBOL_TYPE_GENERAL;
552 info->regA = gen_rtx_raw_REG (mode, get_base_reg (x));
554 if (GET_CODE (x) == CONST)
556 return !(flag_pic && pic_address_needs_scratch (x));
558 else if (flag_pic == 2)
568 if (reload_in_progress)
569 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
570 return microblaze_classify_unspec (info, x);
580 /* This function is used to implement GO_IF_LEGITIMATE_ADDRESS. It
581 returns a nonzero value if X is a legitimate address for a memory
582 operand of the indicated MODE. STRICT is nonzero if this function
583 is called during reload. */
586 microblaze_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
588 struct microblaze_address_info addr;
590 return microblaze_classify_address (&addr, x, mode, strict);
594 /* Try machine-dependent ways of modifying an illegitimate address
595 to be legitimate. If we find one, return the new, valid address.
596 This is used from only one place: `memory_address' in explow.c.
598 OLDX is the address as it was before break_out_memory_refs was
599 called. In some cases it is useful to look at this to decide what
602 It is always safe for this function to do nothing. It exists to
603 recognize opportunities to optimize the output.
605 For the MicroBlaze, transform:
607 memory(X + <large int>)
611 Y = <large int> & ~0x7fff;
613 memory (Z + (<large int> & 0x7fff));
615 This is for CSE to find several similar references, and only use one Z.
617 When PIC, convert addresses of the form memory (symbol+large int) to
618 memory (reg+large int). */
621 microblaze_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
622 enum machine_mode mode ATTRIBUTE_UNUSED)
624 register rtx xinsn = x, result;
626 if (GET_CODE (xinsn) == CONST
627 && flag_pic && pic_address_needs_scratch (xinsn))
629 rtx ptr_reg = gen_reg_rtx (Pmode);
630 rtx constant = XEXP (XEXP (xinsn, 0), 1);
632 emit_move_insn (ptr_reg, XEXP (XEXP (xinsn, 0), 0));
634 result = gen_rtx_PLUS (Pmode, ptr_reg, constant);
635 if (SMALL_INT (constant))
637 /* Otherwise we fall through so the code below will fix the
642 if (GET_CODE (xinsn) == PLUS)
644 register rtx xplus0 = XEXP (xinsn, 0);
645 register rtx xplus1 = XEXP (xinsn, 1);
646 register enum rtx_code code0 = GET_CODE (xplus0);
647 register enum rtx_code code1 = GET_CODE (xplus1);
649 if (code0 != REG && code1 == REG)
651 xplus0 = XEXP (xinsn, 1);
652 xplus1 = XEXP (xinsn, 0);
653 code0 = GET_CODE (xplus0);
654 code1 = GET_CODE (xplus1);
657 if (code0 == REG && REG_OK_FOR_BASE_P (xplus0)
658 && code1 == CONST_INT && !SMALL_INT (xplus1))
660 rtx int_reg = gen_reg_rtx (Pmode);
661 rtx ptr_reg = gen_reg_rtx (Pmode);
663 emit_move_insn (int_reg, GEN_INT (INTVAL (xplus1) & ~0x7fff));
665 emit_insn (gen_rtx_SET (VOIDmode,
667 gen_rtx_PLUS (Pmode, xplus0, int_reg)));
669 result = gen_rtx_PLUS (Pmode, ptr_reg,
670 GEN_INT (INTVAL (xplus1) & 0x7fff));
674 if (code0 == REG && REG_OK_FOR_BASE_P (xplus0) && flag_pic == 2)
676 if (reload_in_progress)
677 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
680 xplus1 = XEXP (xplus1, 0);
681 code1 = GET_CODE (xplus1);
683 if (code1 == SYMBOL_REF)
686 gen_rtx_UNSPEC (Pmode, gen_rtvec (1, xplus1), UNSPEC_GOTOFF);
687 result = gen_rtx_CONST (Pmode, result);
688 result = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, result);
689 result = gen_const_mem (Pmode, result);
690 result = gen_rtx_PLUS (Pmode, xplus0, result);
696 if (GET_CODE (xinsn) == SYMBOL_REF)
698 if (reload_in_progress)
699 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
700 result = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, xinsn), UNSPEC_GOTOFF);
701 result = gen_rtx_CONST (Pmode, result);
702 result = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, result);
703 result = gen_const_mem (Pmode, result);
712 #define MAX_MOVE_REGS 8
713 #define MAX_MOVE_BYTES (MAX_MOVE_REGS * UNITS_PER_WORD)
715 /* Emit straight-line code to move LENGTH bytes from SRC to DEST.
716 Assume that the areas do not overlap. */
719 microblaze_block_move_straight (rtx dest, rtx src, HOST_WIDE_INT length)
721 HOST_WIDE_INT offset, delta;
722 unsigned HOST_WIDE_INT bits;
724 enum machine_mode mode;
727 bits = BITS_PER_WORD;
728 mode = mode_for_size (bits, MODE_INT, 0);
729 delta = bits / BITS_PER_UNIT;
731 /* Allocate a buffer for the temporary registers. */
732 regs = XALLOCAVEC (rtx, length / delta);
734 /* Load as many BITS-sized chunks as possible. Use a normal load if
735 the source has enough alignment, otherwise use left/right pairs. */
736 for (offset = 0, i = 0; offset + delta <= length; offset += delta, i++)
738 regs[i] = gen_reg_rtx (mode);
739 emit_move_insn (regs[i], adjust_address (src, mode, offset));
742 /* Copy the chunks to the destination. */
743 for (offset = 0, i = 0; offset + delta <= length; offset += delta, i++)
744 emit_move_insn (adjust_address (dest, mode, offset), regs[i]);
746 /* Mop up any left-over bytes. */
749 src = adjust_address (src, BLKmode, offset);
750 dest = adjust_address (dest, BLKmode, offset);
751 move_by_pieces (dest, src, length - offset,
752 MIN (MEM_ALIGN (src), MEM_ALIGN (dest)), 0);
756 /* Helper function for doing a loop-based block operation on memory
757 reference MEM. Each iteration of the loop will operate on LENGTH
760 Create a new base register for use within the loop and point it to
761 the start of MEM. Create a new memory reference that uses this
762 register. Store them in *LOOP_REG and *LOOP_MEM respectively. */
765 microblaze_adjust_block_mem (rtx mem, HOST_WIDE_INT length,
766 rtx * loop_reg, rtx * loop_mem)
768 *loop_reg = copy_addr_to_reg (XEXP (mem, 0));
770 /* Although the new mem does not refer to a known location,
771 it does keep up to LENGTH bytes of alignment. */
772 *loop_mem = change_address (mem, BLKmode, *loop_reg);
773 set_mem_align (*loop_mem,
774 MIN ((HOST_WIDE_INT) MEM_ALIGN (mem),
775 length * BITS_PER_UNIT));
779 /* Move LENGTH bytes from SRC to DEST using a loop that moves MAX_MOVE_BYTES
780 per iteration. LENGTH must be at least MAX_MOVE_BYTES. Assume that the
781 memory regions do not overlap. */
784 microblaze_block_move_loop (rtx dest, rtx src, HOST_WIDE_INT length)
786 rtx label, src_reg, dest_reg, final_src;
787 HOST_WIDE_INT leftover;
789 leftover = length % MAX_MOVE_BYTES;
792 /* Create registers and memory references for use within the loop. */
793 microblaze_adjust_block_mem (src, MAX_MOVE_BYTES, &src_reg, &src);
794 microblaze_adjust_block_mem (dest, MAX_MOVE_BYTES, &dest_reg, &dest);
796 /* Calculate the value that SRC_REG should have after the last iteration
798 final_src = expand_simple_binop (Pmode, PLUS, src_reg, GEN_INT (length),
801 /* Emit the start of the loop. */
802 label = gen_label_rtx ();
805 /* Emit the loop body. */
806 microblaze_block_move_straight (dest, src, MAX_MOVE_BYTES);
808 /* Move on to the next block. */
809 emit_move_insn (src_reg, plus_constant (src_reg, MAX_MOVE_BYTES));
810 emit_move_insn (dest_reg, plus_constant (dest_reg, MAX_MOVE_BYTES));
812 /* Emit the test & branch. */
813 emit_insn (gen_cbranchsi4 (gen_rtx_NE (SImode, src_reg, final_src),
814 src_reg, final_src, label));
816 /* Mop up any left-over bytes. */
818 microblaze_block_move_straight (dest, src, leftover);
821 /* Expand a movmemsi instruction. */
824 microblaze_expand_block_move (rtx dest, rtx src, rtx length, rtx align_rtx)
827 if (GET_CODE (length) == CONST_INT)
829 HOST_WIDE_INT bytes = INTVAL (length);
830 int align = INTVAL (align_rtx);
832 if (align > UNITS_PER_WORD)
834 align = UNITS_PER_WORD; /* We can't do any better. */
836 else if (align < UNITS_PER_WORD)
838 if (INTVAL (length) <= MAX_MOVE_BYTES)
840 move_by_pieces (dest, src, bytes, align, 0);
847 if (INTVAL (length) <= 2 * MAX_MOVE_BYTES)
849 microblaze_block_move_straight (dest, src, INTVAL (length));
854 microblaze_block_move_loop (dest, src, INTVAL (length));
862 microblaze_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total,
863 bool speed ATTRIBUTE_UNUSED)
865 enum machine_mode mode = GET_MODE (x);
871 int num_words = (GET_MODE_SIZE (mode) > UNITS_PER_WORD) ? 2 : 1;
872 if (simple_memory_operand (x, mode))
873 *total = COSTS_N_INSNS (2 * num_words);
875 *total = COSTS_N_INSNS (2 * (2 * num_words));
883 *total = COSTS_N_INSNS (2);
886 *total = COSTS_N_INSNS (1);
895 *total = COSTS_N_INSNS (2);
898 *total = COSTS_N_INSNS (1);
906 if (TARGET_BARREL_SHIFT)
908 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v5.00.a")
910 *total = COSTS_N_INSNS (1);
912 *total = COSTS_N_INSNS (2);
914 else if (!TARGET_SOFT_MUL)
915 *total = COSTS_N_INSNS (1);
916 else if (GET_CODE (XEXP (x, 1)) == CONST_INT)
918 /* Add 1 to make shift slightly more expensive than add. */
919 *total = COSTS_N_INSNS (INTVAL (XEXP (x, 1))) + 1;
920 /* Reduce shift costs for for special circumstances. */
921 if (optimize_size && INTVAL (XEXP (x, 1)) > 5)
923 if (!optimize_size && INTVAL (XEXP (x, 1)) > 17)
927 /* Double the worst cost of shifts when there is no barrel shifter and
928 the shift amount is in a reg. */
929 *total = COSTS_N_INSNS (32 * 4);
935 if (mode == SFmode || mode == DFmode)
937 if (TARGET_HARD_FLOAT)
938 *total = COSTS_N_INSNS (6);
941 else if (mode == DImode)
943 *total = COSTS_N_INSNS (4);
948 *total = COSTS_N_INSNS (1);
957 *total = COSTS_N_INSNS (4);
965 if (TARGET_HARD_FLOAT)
966 *total = COSTS_N_INSNS (6);
968 else if (!TARGET_SOFT_MUL)
970 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v5.00.a")
972 *total = COSTS_N_INSNS (1);
974 *total = COSTS_N_INSNS (3);
977 *total = COSTS_N_INSNS (10);
985 if (TARGET_HARD_FLOAT)
986 *total = COSTS_N_INSNS (23);
992 *total = COSTS_N_INSNS (1);
997 *total = COSTS_N_INSNS (1);
1005 /* Return the number of instructions needed to load or store a value
1006 of mode MODE at X. Return 0 if X isn't valid for MODE. */
1009 microblaze_address_insns (rtx x, enum machine_mode mode)
1011 struct microblaze_address_info addr;
1013 if (microblaze_classify_address (&addr, x, mode, false))
1018 if (SMALL_INT (addr.offset))
1022 case ADDRESS_CONST_INT:
1027 case ADDRESS_REG_INDEX:
1028 case ADDRESS_SYMBOLIC:
1030 case ADDRESS_GOTOFF:
1039 /* Provide the costs of an addressing mode that contains ADDR.
1040 If ADDR is not a valid address, its cost is irrelevant. */
1042 microblaze_address_cost (rtx addr, bool speed ATTRIBUTE_UNUSED)
1044 return COSTS_N_INSNS (microblaze_address_insns (addr, GET_MODE (addr)));
1047 /* Return nonzero if X is an address which needs a temporary register when
1048 reloaded while generating PIC code. */
1051 pic_address_needs_scratch (rtx x)
1053 /* An address which is a symbolic plus a non SMALL_INT needs a temp reg. */
1054 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS
1055 && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF
1056 && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
1057 && (flag_pic == 2 || !SMALL_INT (XEXP (XEXP (x, 0), 1))))
1063 /* Argument support functions. */
1064 /* Initialize CUMULATIVE_ARGS for a function. */
1067 init_cumulative_args (CUMULATIVE_ARGS * cum, tree fntype,
1068 rtx libname ATTRIBUTE_UNUSED)
1070 static CUMULATIVE_ARGS zero_cum;
1071 tree param, next_param;
1075 /* Determine if this function has variable arguments. This is
1076 indicated by the last argument being 'void_type_mode' if there
1077 are no variable arguments. The standard MicroBlaze calling sequence
1078 passes all arguments in the general purpose registers in this case. */
1080 for (param = fntype ? TYPE_ARG_TYPES (fntype) : 0;
1081 param != 0; param = next_param)
1083 next_param = TREE_CHAIN (param);
1084 if (next_param == 0 && TREE_VALUE (param) != void_type_node)
1085 cum->gp_reg_found = 1;
1089 /* Advance the argument to the next argument position. */
1092 microblaze_function_arg_advance (CUMULATIVE_ARGS * cum, enum machine_mode mode,
1093 const_tree type, bool named ATTRIBUTE_UNUSED)
1102 gcc_assert (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
1103 || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT);
1105 cum->gp_reg_found = 1;
1106 cum->arg_words += ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1)
1111 cum->gp_reg_found = 1;
1112 cum->arg_words += ((int_size_in_bytes (type) + UNITS_PER_WORD - 1)
1118 if (!cum->gp_reg_found && cum->arg_number <= 2)
1119 cum->fp_code += 1 << ((cum->arg_number - 1) * 2);
1123 cum->arg_words += 2;
1124 if (!cum->gp_reg_found && cum->arg_number <= 2)
1125 cum->fp_code += 2 << ((cum->arg_number - 1) * 2);
1129 cum->gp_reg_found = 1;
1130 cum->arg_words += 2;
1137 cum->gp_reg_found = 1;
1143 /* Return an RTL expression containing the register for the given mode,
1144 or 0 if the argument is to be passed on the stack. */
1147 microblaze_function_arg (CUMULATIVE_ARGS * cum, enum machine_mode mode,
1148 const_tree type ATTRIBUTE_UNUSED,
1149 bool named ATTRIBUTE_UNUSED)
1153 int *arg_words = &cum->arg_words;
1155 cum->last_arg_fp = 0;
1166 regbase = GP_ARG_FIRST;
1169 gcc_assert (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
1170 || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT);
1171 /* Drops through. */
1173 regbase = GP_ARG_FIRST;
1177 if (*arg_words >= MAX_ARGS_IN_REGISTERS)
1181 gcc_assert (regbase != -1);
1183 ret = gen_rtx_REG (mode, regbase + *arg_words);
1186 if (mode == VOIDmode)
1188 if (cum->num_adjusts > 0)
1189 ret = gen_rtx_PARALLEL ((enum machine_mode) cum->fp_code,
1190 gen_rtvec_v (cum->num_adjusts, cum->adjust));
1196 /* Return number of bytes of argument to put in registers. */
1198 function_arg_partial_bytes (CUMULATIVE_ARGS * cum, enum machine_mode mode,
1199 tree type, bool named ATTRIBUTE_UNUSED)
1201 if ((mode == BLKmode
1202 || GET_MODE_CLASS (mode) != MODE_COMPLEX_INT
1203 || GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT)
1204 && cum->arg_words < MAX_ARGS_IN_REGISTERS)
1207 if (mode == BLKmode)
1208 words = ((int_size_in_bytes (type) + UNITS_PER_WORD - 1)
1211 words = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
1213 if (words + cum->arg_words <= MAX_ARGS_IN_REGISTERS)
1214 return 0; /* structure fits in registers */
1216 return (MAX_ARGS_IN_REGISTERS - cum->arg_words) * UNITS_PER_WORD;
1219 else if (mode == DImode && cum->arg_words == MAX_ARGS_IN_REGISTERS - 1)
1220 return UNITS_PER_WORD;
1225 /* Convert a version number of the form "vX.YY.Z" to an integer encoding
1226 for easier range comparison. */
1228 microblaze_version_to_int (const char *version)
1231 const char *tmpl = "vX.YY.Z";
1240 { /* Looking for major */
1241 if (!(*p >= '0' && *p <= '9'))
1243 iver += (int) (*p - '0');
1247 { /* Looking for minor */
1248 if (!(*p >= '0' && *p <= '9'))
1250 iver += (int) (*p - '0');
1254 { /* Looking for compat */
1255 if (!(*p >= 'a' && *p <= 'z'))
1258 iver += (int) (*p - 'a');
1277 microblaze_handle_option (size_t code,
1278 const char *arg ATTRIBUTE_UNUSED,
1279 int value ATTRIBUTE_UNUSED)
1283 case OPT_mno_clearbss:
1284 flag_zero_initialized_in_bss = 0;
1285 warning (0, "-mno-clearbss is deprecated; use -fno-zero-initialized-in-bss");
1287 case OPT_mxl_stack_check:
1288 warning (0, "-mxl_stack_check is deprecated; use -fstack-check");
1296 microblaze_option_override (void)
1298 register int i, start;
1300 register enum machine_mode mode;
1303 microblaze_section_threshold = (global_options_set.x_g_switch_value
1305 : MICROBLAZE_DEFAULT_GVALUE);
1307 /* Check the MicroBlaze CPU version for any special action to be done. */
1308 if (microblaze_select_cpu == NULL)
1309 microblaze_select_cpu = MICROBLAZE_DEFAULT_CPU;
1310 ver = microblaze_version_to_int (microblaze_select_cpu);
1313 error ("%qs is an invalid argument to -mcpu=", microblaze_select_cpu);
1316 ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v3.00.a");
1319 /* No hardware exceptions in earlier versions. So no worries. */
1321 microblaze_select_flags &= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY);
1323 microblaze_no_unsafe_delay = 0;
1324 microblaze_pipe = MICROBLAZE_PIPE_3;
1327 || (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v4.00.b")
1331 microblaze_select_flags |= (MICROBLAZE_MASK_NO_UNSAFE_DELAY);
1333 microblaze_no_unsafe_delay = 1;
1334 microblaze_pipe = MICROBLAZE_PIPE_3;
1338 /* We agree to use 5 pipe-stage model even on area optimized 3
1339 pipe-stage variants. */
1341 microblaze_select_flags &= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY);
1343 microblaze_no_unsafe_delay = 0;
1344 microblaze_pipe = MICROBLAZE_PIPE_5;
1345 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v5.00.a") == 0
1346 || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu,
1348 || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu,
1351 /* Pattern compares are to be turned on by default only when
1352 compiling for MB v5.00.'z'. */
1353 target_flags |= MASK_PATTERN_COMPARE;
1357 ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v6.00.a");
1360 if (TARGET_MULTIPLY_HIGH)
1362 "-mxl-multiply-high can be used only with -mcpu=v6.00.a or greater");
1365 if (TARGET_MULTIPLY_HIGH && TARGET_SOFT_MUL)
1366 error ("-mxl-multiply-high requires -mno-xl-soft-mul");
1368 /* Always use DFA scheduler. */
1369 microblaze_sched_use_dfa = 1;
1372 microblaze_abicalls = MICROBLAZE_ABICALLS_NO;
1375 /* Initialize the high, low values for legit floating point constants. */
1376 real_maxval (&dfhigh, 0, DFmode);
1377 real_maxval (&dflow, 1, DFmode);
1378 real_maxval (&sfhigh, 0, SFmode);
1379 real_maxval (&sflow, 1, SFmode);
1381 microblaze_print_operand_punct['?'] = 1;
1382 microblaze_print_operand_punct['#'] = 1;
1383 microblaze_print_operand_punct['&'] = 1;
1384 microblaze_print_operand_punct['!'] = 1;
1385 microblaze_print_operand_punct['*'] = 1;
1386 microblaze_print_operand_punct['@'] = 1;
1387 microblaze_print_operand_punct['.'] = 1;
1388 microblaze_print_operand_punct['('] = 1;
1389 microblaze_print_operand_punct[')'] = 1;
1390 microblaze_print_operand_punct['['] = 1;
1391 microblaze_print_operand_punct[']'] = 1;
1392 microblaze_print_operand_punct['<'] = 1;
1393 microblaze_print_operand_punct['>'] = 1;
1394 microblaze_print_operand_punct['{'] = 1;
1395 microblaze_print_operand_punct['}'] = 1;
1396 microblaze_print_operand_punct['^'] = 1;
1397 microblaze_print_operand_punct['$'] = 1;
1398 microblaze_print_operand_punct['+'] = 1;
1400 /* Set up array to map GCC register number to debug register number.
1401 Ignore the special purpose register numbers. */
1403 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
1404 microblaze_dbx_regno[i] = -1;
1406 start = GP_DBX_FIRST - GP_REG_FIRST;
1407 for (i = GP_REG_FIRST; i <= GP_REG_LAST; i++)
1408 microblaze_dbx_regno[i] = i + start;
1410 /* Set up array giving whether a given register can hold a given mode. */
1412 for (mode = VOIDmode;
1413 mode != MAX_MACHINE_MODE; mode = (enum machine_mode) ((int) mode + 1))
1415 register int size = GET_MODE_SIZE (mode);
1417 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
1423 ok = (ST_REG_P (regno) || GP_REG_P (regno));
1425 else if (GP_REG_P (regno))
1426 ok = ((regno & 1) == 0 || size <= UNITS_PER_WORD);
1430 microblaze_hard_regno_mode_ok[(int) mode][regno] = ok;
1435 /* Implement TARGET_OPTION_OPTIMIZATION_TABLE. */
1436 static const struct default_options microblaze_option_optimization_table[] =
1438 { OPT_LEVELS_1_PLUS, OPT_fomit_frame_pointer, NULL, 1 },
1439 { OPT_LEVELS_NONE, 0, NULL, 0 }
1442 /* Return true if FUNC is an interrupt function as specified
1443 by the "interrupt_handler" attribute. */
1446 microblaze_interrupt_function_p (tree func)
1450 if (TREE_CODE (func) != FUNCTION_DECL)
1453 a = lookup_attribute ("interrupt_handler", DECL_ATTRIBUTES (func));
1454 return a != NULL_TREE;
1457 /* Return true if FUNC is an interrupt function which uses
1458 normal return, indicated by the "save_volatiles" attribute. */
1461 microblaze_save_volatiles (tree func)
1465 if (TREE_CODE (func) != FUNCTION_DECL)
1468 a = lookup_attribute ("save_volatiles", DECL_ATTRIBUTES (func));
1469 return a != NULL_TREE;
1472 /* Return whether function is tagged with 'interrupt_handler'
1473 attribute. Return true if function should use return from
1474 interrupt rather than normal function return. */
1476 microblaze_is_interrupt_handler (void)
1478 return interrupt_handler;
1481 /* Determine of register must be saved/restored in call. */
1483 microblaze_must_save_register (int regno)
1485 if (pic_offset_table_rtx &&
1486 (regno == MB_ABI_PIC_ADDR_REGNUM) && df_regs_ever_live_p (regno))
1489 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
1492 if (frame_pointer_needed && (regno == HARD_FRAME_POINTER_REGNUM))
1495 if (!current_function_is_leaf)
1497 if (regno == MB_ABI_SUB_RETURN_ADDR_REGNUM)
1499 if ((interrupt_handler || save_volatiles) &&
1500 (regno >= 3 && regno <= 12))
1504 if (interrupt_handler)
1506 if (df_regs_ever_live_p (regno)
1507 || regno == MB_ABI_MSR_SAVE_REG
1508 || regno == MB_ABI_ASM_TEMP_REGNUM
1509 || regno == MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM)
1515 if (df_regs_ever_live_p (regno)
1516 || regno == MB_ABI_ASM_TEMP_REGNUM
1517 || regno == MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM)
1524 /* Return the bytes needed to compute the frame pointer from the current
1527 MicroBlaze stack frames look like:
1531 Before call After call
1532 +-----------------------+ +-----------------------+
1534 mem. | local variables, | | local variables, |
1535 | callee saved and | | callee saved and |
1537 +-----------------------+ +-----------------------+
1538 | arguments for called | | arguments for called |
1539 | subroutines | | subroutines |
1540 | (optional) | | (optional) |
1541 +-----------------------+ +-----------------------+
1542 | Link register | | Link register |
1544 +-----------------------+ +-----------------------+
1546 | local variables, |
1547 | callee saved and |
1549 +-----------------------+
1550 | MSR (optional if, |
1551 | interrupt handler) |
1552 +-----------------------+
1554 | alloca allocations |
1556 +-----------------------+
1558 | arguments for called |
1562 +-----------------------+
1565 memory +-----------------------+
1569 static HOST_WIDE_INT
1570 compute_frame_size (HOST_WIDE_INT size)
1573 HOST_WIDE_INT total_size; /* # bytes that the entire frame takes up. */
1574 HOST_WIDE_INT var_size; /* # bytes that local variables take up. */
1575 HOST_WIDE_INT args_size; /* # bytes that outgoing arguments take up. */
1576 int link_debug_size; /* # bytes for link register. */
1577 HOST_WIDE_INT gp_reg_size; /* # bytes needed to store calle-saved gp regs. */
1578 long mask; /* mask of saved gp registers. */
1581 microblaze_interrupt_function_p (current_function_decl);
1582 save_volatiles = microblaze_save_volatiles (current_function_decl);
1587 args_size = crtl->outgoing_args_size;
1589 if ((args_size == 0) && cfun->calls_alloca)
1590 args_size = NUM_OF_ARGS * UNITS_PER_WORD;
1592 total_size = var_size + args_size;
1595 /* force setting GOT. */
1596 df_set_regs_ever_live (MB_ABI_PIC_ADDR_REGNUM, true);
1598 /* Calculate space needed for gp registers. */
1599 for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
1601 if (microblaze_must_save_register (regno))
1604 if (regno != MB_ABI_SUB_RETURN_ADDR_REGNUM)
1605 /* Don't account for link register. It is accounted specially below. */
1606 gp_reg_size += GET_MODE_SIZE (SImode);
1608 mask |= (1L << (regno - GP_REG_FIRST));
1612 total_size += gp_reg_size;
1614 /* Add 4 bytes for MSR. */
1615 if (interrupt_handler)
1618 /* No space to be allocated for link register in leaf functions with no other
1619 stack requirements. */
1620 if (total_size == 0 && current_function_is_leaf)
1621 link_debug_size = 0;
1623 link_debug_size = UNITS_PER_WORD;
1625 total_size += link_debug_size;
1627 /* Save other computed information. */
1628 current_frame_info.total_size = total_size;
1629 current_frame_info.var_size = var_size;
1630 current_frame_info.args_size = args_size;
1631 current_frame_info.gp_reg_size = gp_reg_size;
1632 current_frame_info.mask = mask;
1633 current_frame_info.initialized = reload_completed;
1634 current_frame_info.num_gp = gp_reg_size / UNITS_PER_WORD;
1635 current_frame_info.link_debug_size = link_debug_size;
1638 /* Offset from which to callee-save GP regs. */
1639 current_frame_info.gp_offset = (total_size - gp_reg_size);
1641 current_frame_info.gp_offset = 0;
1643 /* Ok, we're done. */
1647 /* Make sure that we're not trying to eliminate to the wrong hard frame
1651 microblaze_can_eliminate (const int from, const int to)
1653 return ((from == RETURN_ADDRESS_POINTER_REGNUM && !leaf_function_p())
1654 || (to == MB_ABI_SUB_RETURN_ADDR_REGNUM && leaf_function_p())
1655 || (from != RETURN_ADDRESS_POINTER_REGNUM
1656 && (to == HARD_FRAME_POINTER_REGNUM
1657 || (to == STACK_POINTER_REGNUM && !frame_pointer_needed))));
1660 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
1661 pointer or argument pointer or the return address pointer. TO is either
1662 the stack pointer or hard frame pointer. */
1665 microblaze_initial_elimination_offset (int from, int to)
1667 HOST_WIDE_INT offset;
1671 case FRAME_POINTER_REGNUM:
1674 case ARG_POINTER_REGNUM:
1675 if (to == STACK_POINTER_REGNUM || to == HARD_FRAME_POINTER_REGNUM)
1676 offset = compute_frame_size (get_frame_size ());
1680 case RETURN_ADDRESS_POINTER_REGNUM:
1681 if (current_function_is_leaf)
1684 offset = current_frame_info.gp_offset +
1685 ((UNITS_PER_WORD - (POINTER_SIZE / BITS_PER_UNIT)));
1693 /* Print operands using format code.
1695 The MicroBlaze specific codes are:
1697 'X' X is CONST_INT, prints 32 bits in hexadecimal format = "0x%08x",
1698 'x' X is CONST_INT, prints 16 bits in hexadecimal format = "0x%04x",
1699 'F' op is CONST_DOUBLE, print 32 bits in hex,
1700 'd' output integer constant in decimal,
1701 'z' if the operand is 0, use $0 instead of normal operand.
1702 'D' print second register of double-word register operand.
1703 'L' print low-order register of double-word register operand.
1704 'M' print high-order register of double-word register operand.
1705 'C' print part of opcode for a branch condition.
1706 'N' print part of opcode for a branch condition, inverted.
1707 'S' X is CODE_LABEL, print with prefix of "LS" (for embedded switch).
1708 'B' print 'z' for EQ, 'n' for NE
1709 'b' print 'n' for EQ, 'z' for NE
1710 'T' print 'f' for EQ, 't' for NE
1711 't' print 't' for EQ, 'f' for NE
1712 'm' Print 1<<operand.
1713 'i' Print 'i' if MEM operand has immediate value
1714 'o' Print operand address+4
1715 '?' Print 'd' if we use a branch with delay slot instead of normal branch.
1716 'h' Print high word of const_double (int or float) value as hex
1717 'j' Print low word of const_double (int or float) value as hex
1718 's' Print -1 if operand is negative, 0 if positive (sign extend)
1719 '@' Print the name of the temporary register (rMB_ABI_ASM_TEMP_REGNUM).
1720 '#' Print nop if the delay slot of a branch is not filled.
1724 print_operand (FILE * file, rtx op, int letter)
1726 register enum rtx_code code;
1728 if (PRINT_OPERAND_PUNCT_VALID_P (letter))
1733 /* Conditionally add a 'd' to indicate filled delay slot. */
1734 if (final_sequence != NULL)
1739 /* Conditionally add a nop in unfilled delay slot. */
1740 if (final_sequence == NULL)
1741 fputs ("nop\t\t# Unfilled delay slot\n", file);
1745 fputs (reg_names[GP_REG_FIRST + MB_ABI_ASM_TEMP_REGNUM], file);
1749 output_operand_lossage ("unknown punctuation '%c'", letter);
1758 output_operand_lossage ("null pointer");
1762 code = GET_CODE (op);
1764 if (code == SIGN_EXTEND)
1765 op = XEXP (op, 0), code = GET_CODE (op);
1793 fatal_insn ("PRINT_OPERAND, invalid insn for %%C", op);
1796 else if (letter == 'N')
1822 fatal_insn ("PRINT_OPERAND, invalid insn for %%N", op);
1825 else if (letter == 'S')
1829 ASM_GENERATE_INTERNAL_LABEL (buffer, "LS", CODE_LABEL_NUMBER (op));
1830 assemble_name (file, buffer);
1833 /* Print 'i' for memory operands which have immediate values. */
1834 else if (letter == 'i')
1838 struct microblaze_address_info info;
1840 if (!microblaze_classify_address
1841 (&info, XEXP (op, 0), GET_MODE (op), 1))
1842 fatal_insn ("insn contains an invalid address !", op);
1847 case ADDRESS_CONST_INT:
1848 case ADDRESS_SYMBOLIC:
1849 case ADDRESS_GOTOFF:
1852 case ADDRESS_REG_INDEX:
1854 case ADDRESS_INVALID:
1856 fatal_insn ("invalid address", op);
1861 else if (code == REG || code == SUBREG)
1863 register int regnum;
1866 regnum = REGNO (op);
1868 regnum = true_regnum (op);
1870 if ((letter == 'M' && !WORDS_BIG_ENDIAN)
1871 || (letter == 'L' && WORDS_BIG_ENDIAN) || letter == 'D')
1874 fprintf (file, "%s", reg_names[regnum]);
1877 else if (code == MEM)
1880 rtx op4 = adjust_address (op, GET_MODE (op), 4);
1881 output_address (XEXP (op4, 0));
1884 output_address (XEXP (op, 0));
1886 else if (letter == 'h' || letter == 'j')
1889 if (code == CONST_DOUBLE)
1891 if (GET_MODE (op) == DFmode)
1893 REAL_VALUE_TYPE value;
1894 REAL_VALUE_FROM_CONST_DOUBLE (value, op);
1895 REAL_VALUE_TO_TARGET_DOUBLE (value, val);
1899 val[0] = CONST_DOUBLE_HIGH (op);
1900 val[1] = CONST_DOUBLE_LOW (op);
1903 else if (code == CONST_INT)
1905 val[0] = (INTVAL (op) & 0xffffffff00000000LL) >> 32;
1906 val[1] = INTVAL (op) & 0x00000000ffffffffLL;
1907 if (val[0] == 0 && val[1] < 0)
1911 fprintf (file, "0x%8.8lx", (letter == 'h') ? val[0] : val[1]);
1913 else if (code == CONST_DOUBLE)
1917 unsigned long value_long;
1918 REAL_VALUE_TYPE value;
1919 REAL_VALUE_FROM_CONST_DOUBLE (value, op);
1920 REAL_VALUE_TO_TARGET_SINGLE (value, value_long);
1921 fprintf (file, HOST_WIDE_INT_PRINT_HEX, value_long);
1926 real_to_decimal (s, CONST_DOUBLE_REAL_VALUE (op), sizeof (s), 0, 1);
1931 else if (code == UNSPEC)
1933 print_operand_address (file, op);
1936 else if (letter == 'x' && GET_CODE (op) == CONST_INT)
1937 fprintf (file, HOST_WIDE_INT_PRINT_HEX, 0xffff & INTVAL (op));
1939 else if (letter == 'X' && GET_CODE (op) == CONST_INT)
1940 fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (op));
1942 else if (letter == 'd' && GET_CODE (op) == CONST_INT)
1943 fprintf (file, HOST_WIDE_INT_PRINT_DEC, (INTVAL (op)));
1945 else if (letter == 'z' && GET_CODE (op) == CONST_INT && INTVAL (op) == 0)
1946 fputs (reg_names[GP_REG_FIRST], file);
1948 else if (letter == 's' && GET_CODE (op) == CONST_INT)
1949 if (INTVAL (op) < 0)
1954 else if (letter == 'd' || letter == 'x' || letter == 'X' || letter == 's')
1955 output_operand_lossage ("letter %c was found & insn was not CONST_INT", letter);
1957 else if (letter == 'B')
1958 fputs (code == EQ ? "z" : "n", file);
1959 else if (letter == 'b')
1960 fputs (code == EQ ? "n" : "z", file);
1961 else if (letter == 'T')
1962 fputs (code == EQ ? "f" : "t", file);
1963 else if (letter == 't')
1964 fputs (code == EQ ? "t" : "f", file);
1966 else if (code == CONST && GET_CODE (XEXP (op, 0)) == REG)
1968 print_operand (file, XEXP (op, 0), letter);
1970 else if (letter == 'm')
1971 fprintf (file, HOST_WIDE_INT_PRINT_DEC, (1L << INTVAL (op)));
1973 output_addr_const (file, op);
1976 /* A C compound statement to output to stdio stream STREAM the
1977 assembler syntax for an instruction operand that is a memory
1978 reference whose address is ADDR. ADDR is an RTL expression.
1980 Possible address classifications and output formats are,
1982 ADDRESS_REG "%0, r0"
1984 ADDRESS_REG with non-zero "%0, <addr_const>"
1987 ADDRESS_REG_INDEX "rA, RB"
1988 (if rA is r0, rA and rB are swapped)
1990 ADDRESS_CONST_INT "r0, <addr_const>"
1992 ADDRESS_SYMBOLIC "rBase, <addr_const>"
1993 (rBase is a base register suitable for the
1998 print_operand_address (FILE * file, rtx addr)
2000 struct microblaze_address_info info;
2001 enum microblaze_address_type type;
2002 if (!microblaze_classify_address (&info, addr, GET_MODE (addr), 1))
2003 fatal_insn ("insn contains an invalid address !", addr);
2009 fprintf (file, "%s,", reg_names[REGNO (info.regA)]);
2010 output_addr_const (file, info.offset);
2012 case ADDRESS_REG_INDEX:
2013 if (REGNO (info.regA) == 0)
2014 /* Make rB == r0 instead of rA == r0. This helps reduce read port
2016 fprintf (file, "%s,%s", reg_names[REGNO (info.regB)],
2017 reg_names[REGNO (info.regA)]);
2018 else if (REGNO (info.regB) != 0)
2019 /* This is a silly swap to help Dhrystone. */
2020 fprintf (file, "%s,%s", reg_names[REGNO (info.regB)],
2021 reg_names[REGNO (info.regA)]);
2023 case ADDRESS_CONST_INT:
2024 fprintf (file, "%s,", reg_names[REGNO (info.regA)]);
2025 output_addr_const (file, info.offset);
2027 case ADDRESS_SYMBOLIC:
2028 case ADDRESS_GOTOFF:
2031 fprintf (file, "%s,", reg_names[REGNO (info.regA)]);
2032 output_addr_const (file, info.symbol);
2033 if (type == ADDRESS_GOTOFF)
2035 fputs ("@GOT", file);
2037 else if (type == ADDRESS_PLT)
2039 fputs ("@PLT", file);
2042 case ADDRESS_INVALID:
2043 fatal_insn ("invalid address", addr);
2048 /* Emit either a label, .comm, or .lcomm directive, and mark that the symbol
2049 is used, so that we don't emit an .extern for it in
2050 microblaze_asm_file_end. */
2053 microblaze_declare_object (FILE * stream, const char *name,
2054 const char *section, const char *fmt, int size)
2057 fputs (section, stream);
2058 assemble_name (stream, name);
2059 fprintf (stream, fmt, size);
2062 /* Common code to emit the insns (or to write the instructions to a file)
2063 to save/restore registers.
2065 Other parts of the code assume that MICROBLAZE_TEMP1_REGNUM (aka large_reg)
2066 is not modified within save_restore_insns. */
2068 #define BITSET_P(VALUE,BIT) (((VALUE) & (1L << (BIT))) != 0)
2070 /* Save or restore instructions based on whether this is the prologue or
2071 epilogue. prologue is 1 for the prologue. */
2073 save_restore_insns (int prologue)
2075 rtx base_reg_rtx, reg_rtx, mem_rtx, /* msr_rtx, */ isr_reg_rtx =
2077 rtx isr_msr_rtx = 0, insn;
2078 long mask = current_frame_info.mask;
2079 HOST_WIDE_INT gp_offset;
2082 if (frame_pointer_needed
2083 && !BITSET_P (mask, HARD_FRAME_POINTER_REGNUM - GP_REG_FIRST))
2089 /* Save registers starting from high to low. The debuggers prefer at least
2090 the return register be stored at func+4, and also it allows us not to
2091 need a nop in the epilog if at least one register is reloaded in
2092 addition to return address. */
2094 /* Pick which pointer to use as a base register. For small frames, just
2095 use the stack pointer. Otherwise, use a temporary register. Save 2
2096 cycles if the save area is near the end of a large frame, by reusing
2097 the constant created in the prologue/epilogue to adjust the stack
2100 gp_offset = current_frame_info.gp_offset;
2102 gcc_assert (gp_offset > 0);
2104 base_reg_rtx = stack_pointer_rtx;
2106 /* For interrupt_handlers, need to save/restore the MSR. */
2107 if (interrupt_handler)
2109 isr_mem_rtx = gen_rtx_MEM (SImode,
2110 gen_rtx_PLUS (Pmode, base_reg_rtx,
2111 GEN_INT (current_frame_info.
2115 /* Do not optimize in flow analysis. */
2116 MEM_VOLATILE_P (isr_mem_rtx) = 1;
2117 isr_reg_rtx = gen_rtx_REG (SImode, MB_ABI_MSR_SAVE_REG);
2118 isr_msr_rtx = gen_rtx_REG (SImode, ST_REG);
2121 if (interrupt_handler && !prologue)
2123 emit_move_insn (isr_reg_rtx, isr_mem_rtx);
2124 emit_move_insn (isr_msr_rtx, isr_reg_rtx);
2125 /* Do not optimize in flow analysis. */
2126 emit_insn (gen_rtx_USE (SImode, isr_reg_rtx));
2127 emit_insn (gen_rtx_USE (SImode, isr_msr_rtx));
2130 for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
2132 if (BITSET_P (mask, regno - GP_REG_FIRST))
2134 if (regno == MB_ABI_SUB_RETURN_ADDR_REGNUM)
2135 /* Don't handle here. Already handled as the first register. */
2138 reg_rtx = gen_rtx_REG (SImode, regno);
2139 insn = gen_rtx_PLUS (Pmode, base_reg_rtx, GEN_INT (gp_offset));
2140 mem_rtx = gen_rtx_MEM (SImode, insn);
2141 if (interrupt_handler || save_volatiles)
2142 /* Do not optimize in flow analysis. */
2143 MEM_VOLATILE_P (mem_rtx) = 1;
2147 insn = emit_move_insn (mem_rtx, reg_rtx);
2148 RTX_FRAME_RELATED_P (insn) = 1;
2152 insn = emit_move_insn (reg_rtx, mem_rtx);
2155 gp_offset += GET_MODE_SIZE (SImode);
2159 if (interrupt_handler && prologue)
2161 emit_move_insn (isr_reg_rtx, isr_msr_rtx);
2162 emit_move_insn (isr_mem_rtx, isr_reg_rtx);
2164 /* Do not optimize in flow analysis. */
2165 emit_insn (gen_rtx_USE (SImode, isr_reg_rtx));
2166 emit_insn (gen_rtx_USE (SImode, isr_msr_rtx));
2169 /* Done saving and restoring */
2173 /* Set up the stack and frame (if desired) for the function. */
2175 microblaze_function_prologue (FILE * file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
2178 long fsiz = current_frame_info.total_size;
2180 /* Get the function name the same way that toplev.c does before calling
2181 assemble_start_function. This is needed so that the name used here
2182 exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */
2183 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
2184 if (!flag_inhibit_size_directive)
2186 fputs ("\t.ent\t", file);
2187 if (interrupt_handler && strcmp (INTERRUPT_HANDLER_NAME, fnname))
2188 fputs ("_interrupt_handler", file);
2190 assemble_name (file, fnname);
2192 if (!interrupt_handler)
2193 ASM_OUTPUT_TYPE_DIRECTIVE (file, fnname, "function");
2196 assemble_name (file, fnname);
2197 fputs (":\n", file);
2199 if (interrupt_handler && strcmp (INTERRUPT_HANDLER_NAME, fnname))
2200 fputs ("_interrupt_handler:\n", file);
2202 if (!flag_inhibit_size_directive)
2204 /* .frame FRAMEREG, FRAMESIZE, RETREG. */
2206 "\t.frame\t%s,%ld,%s\t\t# vars= %ld, regs= %d, args= %d\n",
2207 (reg_names[(frame_pointer_needed)
2208 ? HARD_FRAME_POINTER_REGNUM :
2209 STACK_POINTER_REGNUM]), fsiz,
2210 reg_names[MB_ABI_SUB_RETURN_ADDR_REGNUM + GP_REG_FIRST],
2211 current_frame_info.var_size, current_frame_info.num_gp,
2212 crtl->outgoing_args_size);
2213 fprintf (file, "\t.mask\t0x%08lx\n", current_frame_info.mask);
2217 /* Output extra assembler code at the end of a prologue. */
2219 microblaze_function_end_prologue (FILE * file)
2221 if (TARGET_STACK_CHECK)
2223 fprintf (file, "\t# Stack Check Stub -- Start.\n\t");
2224 fprintf (file, "ori\tr18,r0,_stack_end\n\t");
2225 fprintf (file, "cmpu\tr18,r1,r18\n\t");
2226 fprintf (file, "bgei\tr18,_stack_overflow_exit\n\t");
2227 fprintf (file, "# Stack Check Stub -- End.\n");
2231 /* Expand the prologue into a bunch of separate insns. */
2234 microblaze_expand_prologue (void)
2238 const char *arg_name = 0;
2239 tree fndecl = current_function_decl;
2240 tree fntype = TREE_TYPE (fndecl);
2241 tree fnargs = DECL_ARGUMENTS (fndecl);
2246 CUMULATIVE_ARGS args_so_far;
2247 rtx mem_rtx, reg_rtx;
2249 /* If struct value address is treated as the first argument, make it so. */
2250 if (aggregate_value_p (DECL_RESULT (fndecl), fntype)
2251 && !cfun->returns_pcc_struct)
2253 tree type = build_pointer_type (fntype);
2254 tree function_result_decl = build_decl (BUILTINS_LOCATION, PARM_DECL,
2257 DECL_ARG_TYPE (function_result_decl) = type;
2258 TREE_CHAIN (function_result_decl) = fnargs;
2259 fnargs = function_result_decl;
2262 /* Determine the last argument, and get its name. */
2264 INIT_CUMULATIVE_ARGS (args_so_far, fntype, NULL_RTX, 0, 0);
2265 regno = GP_ARG_FIRST;
2267 for (cur_arg = fnargs; cur_arg != 0; cur_arg = next_arg)
2269 tree passed_type = DECL_ARG_TYPE (cur_arg);
2270 enum machine_mode passed_mode = TYPE_MODE (passed_type);
2273 if (TREE_ADDRESSABLE (passed_type))
2275 passed_type = build_pointer_type (passed_type);
2276 passed_mode = Pmode;
2279 entry_parm = targetm.calls.function_arg (&args_so_far, passed_mode,
2286 /* passed in a register, so will get homed automatically. */
2287 if (GET_MODE (entry_parm) == BLKmode)
2288 words = (int_size_in_bytes (passed_type) + 3) / 4;
2290 words = (GET_MODE_SIZE (GET_MODE (entry_parm)) + 3) / 4;
2292 regno = REGNO (entry_parm) + words - 1;
2296 regno = GP_ARG_LAST + 1;
2300 targetm.calls.function_arg_advance (&args_so_far, passed_mode,
2303 next_arg = TREE_CHAIN (cur_arg);
2306 if (DECL_NAME (cur_arg))
2307 arg_name = IDENTIFIER_POINTER (DECL_NAME (cur_arg));
2313 /* Split parallel insn into a sequence of insns. */
2315 next_arg_reg = targetm.calls.function_arg (&args_so_far, VOIDmode,
2316 void_type_node, true);
2317 if (next_arg_reg != 0 && GET_CODE (next_arg_reg) == PARALLEL)
2319 rtvec adjust = XVEC (next_arg_reg, 0);
2320 int num = GET_NUM_ELEM (adjust);
2322 for (i = 0; i < num; i++)
2324 rtx pattern = RTVEC_ELT (adjust, i);
2325 emit_insn (pattern);
2329 fsiz = compute_frame_size (get_frame_size ());
2331 /* If this function is a varargs function, store any registers that
2332 would normally hold arguments ($5 - $10) on the stack. */
2333 if (((TYPE_ARG_TYPES (fntype) != 0
2334 && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
2337 && ((arg_name[0] == '_'
2338 && strcmp (arg_name, "__builtin_va_alist") == 0)
2339 || (arg_name[0] == 'v'
2340 && strcmp (arg_name, "va_alist") == 0)))))
2342 int offset = (regno - GP_ARG_FIRST + 1) * UNITS_PER_WORD;
2343 rtx ptr = stack_pointer_rtx;
2345 /* If we are doing svr4-abi, sp has already been decremented by fsiz. */
2346 for (; regno <= GP_ARG_LAST; regno++)
2349 ptr = gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (offset));
2350 emit_move_insn (gen_rtx_MEM (SImode, ptr),
2351 gen_rtx_REG (SImode, regno));
2353 offset += GET_MODE_SIZE (SImode);
2360 rtx fsiz_rtx = GEN_INT (fsiz);
2363 insn = emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx,
2366 RTX_FRAME_RELATED_P (insn) = 1;
2368 /* Handle SUB_RETURN_ADDR_REGNUM specially at first. */
2369 if (!current_function_is_leaf || interrupt_handler)
2371 mem_rtx = gen_rtx_MEM (SImode,
2372 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
2375 if (interrupt_handler)
2376 /* Do not optimize in flow analysis. */
2377 MEM_VOLATILE_P (mem_rtx) = 1;
2379 reg_rtx = gen_rtx_REG (SImode, MB_ABI_SUB_RETURN_ADDR_REGNUM);
2380 insn = emit_move_insn (mem_rtx, reg_rtx);
2381 RTX_FRAME_RELATED_P (insn) = 1;
2384 /* _save_ registers for prologue. */
2385 save_restore_insns (1);
2387 if (frame_pointer_needed)
2391 insn = emit_insn (gen_movsi (hard_frame_pointer_rtx,
2392 stack_pointer_rtx));
2395 RTX_FRAME_RELATED_P (insn) = 1;
2399 if (flag_pic == 2 && df_regs_ever_live_p (MB_ABI_PIC_ADDR_REGNUM))
2401 SET_REGNO (pic_offset_table_rtx, MB_ABI_PIC_ADDR_REGNUM);
2402 emit_insn (gen_set_got (pic_offset_table_rtx)); /* setting GOT. */
2405 /* If we are profiling, make sure no instructions are scheduled before
2406 the call to mcount. */
2409 emit_insn (gen_blockage ());
2412 /* Do necessary cleanup after a function to restore stack, frame, and regs. */
2414 #define RA_MASK ((long) 0x80000000) /* 1 << 31 */
2415 #define PIC_OFFSET_TABLE_MASK (1 << (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST))
2418 microblaze_function_epilogue (FILE * file ATTRIBUTE_UNUSED,
2419 HOST_WIDE_INT size ATTRIBUTE_UNUSED)
2423 /* Get the function name the same way that toplev.c does before calling
2424 assemble_start_function. This is needed so that the name used here
2425 exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */
2426 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
2428 if (!flag_inhibit_size_directive)
2430 fputs ("\t.end\t", file);
2431 if (interrupt_handler)
2432 fputs ("_interrupt_handler", file);
2434 assemble_name (file, fnname);
2438 /* Reset state info for each function. */
2439 current_frame_info = zero_frame_info;
2441 /* Restore the output file if optimizing the GP (optimizing the GP causes
2442 the text to be diverted to a tempfile, so that data decls come before
2443 references to the data). */
2446 /* Expand the epilogue into a bunch of separate insns. */
2449 microblaze_expand_epilogue (void)
2451 HOST_WIDE_INT fsiz = current_frame_info.total_size;
2452 rtx fsiz_rtx = GEN_INT (fsiz);
2456 /* In case of interrupt handlers use addki instead of addi for changing the
2457 stack pointer value. */
2459 if (microblaze_can_use_return_insn ())
2461 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode,
2463 MB_ABI_SUB_RETURN_ADDR_REGNUM)));
2469 /* Restore SUB_RETURN_ADDR_REGNUM at first. This is to prevent the
2470 sequence of load-followed by a use (in rtsd) in every prologue. Saves
2471 a load-use stall cycle :) This is also important to handle alloca.
2472 (See comments for if (frame_pointer_needed) below. */
2474 if (!current_function_is_leaf || interrupt_handler)
2477 gen_rtx_MEM (SImode,
2478 gen_rtx_PLUS (Pmode, stack_pointer_rtx, const0_rtx));
2479 if (interrupt_handler)
2480 /* Do not optimize in flow analysis. */
2481 MEM_VOLATILE_P (mem_rtx) = 1;
2482 reg_rtx = gen_rtx_REG (SImode, MB_ABI_SUB_RETURN_ADDR_REGNUM);
2483 emit_move_insn (reg_rtx, mem_rtx);
2486 /* It is important that this is done after we restore the return address
2487 register (above). When alloca is used, we want to restore the
2488 sub-routine return address only from the current stack top and not
2489 from the frame pointer (which we restore below). (frame_pointer + 0)
2490 might have been over-written since alloca allocates memory on the
2492 if (frame_pointer_needed)
2493 emit_insn (gen_movsi (stack_pointer_rtx, hard_frame_pointer_rtx));
2495 /* _restore_ registers for epilogue. */
2496 save_restore_insns (0);
2497 emit_insn (gen_blockage ());
2498 emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, fsiz_rtx));
2501 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode, GP_REG_FIRST +
2502 MB_ABI_SUB_RETURN_ADDR_REGNUM)));
2506 /* Return nonzero if this function is known to have a null epilogue.
2507 This allows the optimizer to omit jumps to jumps if no stack
2511 microblaze_can_use_return_insn (void)
2513 if (!reload_completed)
2516 if (df_regs_ever_live_p (MB_ABI_SUB_RETURN_ADDR_REGNUM) || profile_flag)
2519 if (current_frame_info.initialized)
2520 return current_frame_info.total_size == 0;
2522 return compute_frame_size (get_frame_size ()) == 0;
2525 /* Implement TARGET_SECONDARY_RELOAD. */
2528 microblaze_secondary_reload (bool in_p ATTRIBUTE_UNUSED, rtx x ATTRIBUTE_UNUSED,
2529 reg_class_t rclass, enum machine_mode mode ATTRIBUTE_UNUSED,
2530 secondary_reload_info *sri ATTRIBUTE_UNUSED)
2532 if (rclass == ST_REGS)
2539 microblaze_globalize_label (FILE * stream, const char *name)
2541 fputs ("\t.globl\t", stream);
2542 if (interrupt_handler && strcmp (name, INTERRUPT_HANDLER_NAME))
2544 fputs (INTERRUPT_HANDLER_NAME, stream);
2545 fputs ("\n\t.globl\t", stream);
2547 assemble_name (stream, name);
2548 fputs ("\n", stream);
2551 /* Returns true if decl should be placed into a "small data" section. */
2553 microblaze_elf_in_small_data_p (const_tree decl)
2557 if (!TARGET_XLGPOPT)
2560 /* We want to merge strings, so we never consider them small data. */
2561 if (TREE_CODE (decl) == STRING_CST)
2564 /* Functions are never in the small data area. */
2565 if (TREE_CODE (decl) == FUNCTION_DECL)
2568 if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl))
2570 const char *section = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
2571 if (strcmp (section, ".sdata") == 0
2572 || strcmp (section, ".sdata2") == 0
2573 || strcmp (section, ".sbss") == 0
2574 || strcmp (section, ".sbss2") == 0)
2578 size = int_size_in_bytes (TREE_TYPE (decl));
2580 return (size > 0 && size <= microblaze_section_threshold);
2585 microblaze_select_section (tree decl, int reloc, unsigned HOST_WIDE_INT align)
2587 switch (categorize_decl_for_section (decl, reloc))
2589 case SECCAT_RODATA_MERGE_STR:
2590 case SECCAT_RODATA_MERGE_STR_INIT:
2591 /* MB binutils have various issues with mergeable string sections and
2592 relaxation/relocation. Currently, turning mergeable sections
2593 into regular readonly sections. */
2595 return readonly_data_section;
2597 return default_elf_select_section (decl, reloc, align);
2602 Encode info about sections into the RTL based on a symbol's declaration.
2603 The default definition of this hook, default_encode_section_info in
2604 `varasm.c', sets a number of commonly-useful bits in SYMBOL_REF_FLAGS. */
2607 microblaze_encode_section_info (tree decl, rtx rtl, int first)
2609 default_encode_section_info (decl, rtl, first);
2613 expand_pic_symbol_ref (enum machine_mode mode ATTRIBUTE_UNUSED, rtx op)
2616 result = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op), UNSPEC_GOTOFF);
2617 result = gen_rtx_CONST (Pmode, result);
2618 result = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, result);
2619 result = gen_const_mem (Pmode, result);
2624 microblaze_expand_move (enum machine_mode mode, rtx operands[])
2626 /* If operands[1] is a constant address invalid for pic, then we need to
2627 handle it just like LEGITIMIZE_ADDRESS does. */
2630 if (GET_CODE (operands[0]) == MEM)
2632 rtx addr = XEXP (operands[0], 0);
2633 if (GET_CODE (addr) == SYMBOL_REF)
2635 rtx ptr_reg, result;
2637 if (reload_in_progress)
2638 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
2640 addr = expand_pic_symbol_ref (mode, addr);
2641 ptr_reg = gen_reg_rtx (Pmode);
2642 emit_move_insn (ptr_reg, addr);
2643 result = gen_rtx_MEM (mode, ptr_reg);
2644 operands[0] = result;
2647 if (GET_CODE (operands[1]) == SYMBOL_REF
2648 || GET_CODE (operands[1]) == LABEL_REF)
2651 if (reload_in_progress)
2652 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
2653 result = expand_pic_symbol_ref (mode, operands[1]);
2654 if (GET_CODE (operands[0]) != REG)
2656 rtx ptr_reg = gen_reg_rtx (Pmode);
2657 emit_move_insn (ptr_reg, result);
2658 emit_move_insn (operands[0], ptr_reg);
2662 emit_move_insn (operands[0], result);
2666 else if (GET_CODE (operands[1]) == MEM &&
2667 GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF)
2671 if (reload_in_progress)
2672 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
2673 result = expand_pic_symbol_ref (mode, XEXP (operands[1], 0));
2675 ptr_reg = gen_reg_rtx (Pmode);
2677 emit_move_insn (ptr_reg, result);
2678 result = gen_rtx_MEM (mode, ptr_reg);
2679 emit_move_insn (operands[0], result);
2682 else if (pic_address_needs_scratch (operands[1]))
2684 rtx temp = force_reg (SImode, XEXP (XEXP (operands[1], 0), 0));
2685 rtx temp2 = XEXP (XEXP (operands[1], 0), 1);
2687 if (reload_in_progress)
2688 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
2689 emit_move_insn (operands[0], gen_rtx_PLUS (SImode, temp, temp2));
2694 if ((reload_in_progress | reload_completed) == 0
2695 && !register_operand (operands[0], SImode)
2696 && !register_operand (operands[1], SImode)
2697 && (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 0))
2699 rtx temp = force_reg (SImode, operands[1]);
2700 emit_move_insn (operands[0], temp);
2706 /* Expand shift operations. */
2708 microblaze_expand_shift (rtx operands[])
2710 gcc_assert ((GET_CODE (operands[2]) == CONST_INT)
2711 || (GET_CODE (operands[2]) == REG)
2712 || (GET_CODE (operands[2]) == SUBREG));
2714 /* Shift by one -- generate pattern. */
2715 if ((GET_CODE (operands[2]) == CONST_INT) && (INTVAL (operands[2]) == 1))
2718 /* Have barrel shifter and shift > 1: use it. */
2719 if (TARGET_BARREL_SHIFT)
2722 gcc_assert ((GET_CODE (operands[0]) == REG)
2723 || (GET_CODE (operands[0]) == SUBREG)
2724 || (GET_CODE (operands[1]) == REG)
2725 || (GET_CODE (operands[1]) == SUBREG));
2727 /* Shift by zero -- copy regs if necessary. */
2728 if ((GET_CODE (operands[2]) == CONST_INT) && (INTVAL (operands[2]) == 0))
2730 if (REGNO (operands[0]) != REGNO (operands[1]))
2731 emit_insn (gen_movsi (operands[0], operands[1]));
2738 /* Return an RTX indicating where the return address to the
2739 calling function can be found. */
2741 microblaze_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
2746 return gen_rtx_PLUS (Pmode,
2747 get_hard_reg_initial_val (Pmode,
2748 MB_ABI_SUB_RETURN_ADDR_REGNUM),
2752 /* Put string into .sdata2 if below threashold. */
2754 microblaze_asm_output_ident (FILE *file ATTRIBUTE_UNUSED, const char *string)
2756 int size = strlen (string) + 1;
2757 if (size <= microblaze_section_threshold)
2758 switch_to_section (sdata2_section);
2760 switch_to_section (readonly_data_section);
2761 assemble_string (string, size);
2765 microblaze_elf_asm_init_sections (void)
2768 = get_unnamed_section (SECTION_WRITE, output_section_asm_op,
2769 SDATA2_SECTION_ASM_OP);
2772 /* Generate assembler code for constant parts of a trampoline. */
2775 microblaze_asm_trampoline_template (FILE *f)
2777 fprintf (f, "\t.word\t0x03e00821\t\t# move $1,$31\n");
2778 fprintf (f, "\t.word\t0x04110001\t\t# bgezal $0,.+8\n");
2779 fprintf (f, "\t.word\t0x00000000\t\t# nop\n");
2780 fprintf (f, "\t.word\t0x8fe30014\t\t# lw $3,20($31)\n");
2781 fprintf (f, "\t.word\t0x8fe20018\t\t# lw $2,24($31)\n");
2782 fprintf (f, "\t.word\t0x0060c821\t\t# move $25,$3 (abicalls)\n");
2783 fprintf (f, "\t.word\t0x00600008\t\t# jr $3\n");
2784 fprintf (f, "\t.word\t0x0020f821\t\t# move $31,$1\n");
2785 /* fprintf (f, "\t.word\t0x00000000\t\t# <function address>\n"); */
2786 /* fprintf (f, "\t.word\t0x00000000\t\t# <static chain value>\n"); */
2789 /* Implement TARGET_TRAMPOLINE_INIT. */
2792 microblaze_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
2794 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
2797 emit_block_move (m_tramp, assemble_trampoline_template (),
2798 GEN_INT (8*UNITS_PER_WORD), BLOCK_OP_NORMAL);
2800 mem = adjust_address (m_tramp, SImode, 8);
2801 emit_move_insn (mem, chain_value);
2802 mem = adjust_address (m_tramp, SImode, 12);
2803 emit_move_insn (mem, fnaddr);
2806 /* Emit instruction to perform compare.
2807 cmp is (compare_op op0 op1). */
2809 microblaze_emit_compare (enum machine_mode mode, rtx cmp, enum rtx_code *cmp_code)
2811 rtx cmp_op0 = XEXP (cmp, 0);
2812 rtx cmp_op1 = XEXP (cmp, 1);
2813 rtx comp_reg = gen_reg_rtx (SImode);
2814 enum rtx_code code = *cmp_code;
2816 gcc_assert ((GET_CODE (cmp_op0) == REG) || (GET_CODE (cmp_op0) == SUBREG));
2818 /* If comparing against zero, just test source reg. */
2819 if (cmp_op1 == const0_rtx)
2822 if (code == EQ || code == NE)
2824 if (TARGET_PATTERN_COMPARE && GET_CODE(cmp_op1) == REG)
2827 emit_insn (gen_seq_internal_pat (comp_reg, cmp_op0, cmp_op1));
2830 emit_insn (gen_sne_internal_pat (comp_reg, cmp_op0, cmp_op1));
2835 /* Use xor for equal/not-equal comparison. */
2836 emit_insn (gen_xorsi3 (comp_reg, cmp_op0, cmp_op1));
2838 else if (code == GT || code == GTU || code == LE || code == LEU)
2840 /* MicroBlaze compare is not symmetrical. */
2841 /* Swap argument order. */
2842 cmp_op1 = force_reg (mode, cmp_op1);
2843 if (code == GT || code == LE)
2844 emit_insn (gen_signed_compare (comp_reg, cmp_op0, cmp_op1));
2846 emit_insn (gen_unsigned_compare (comp_reg, cmp_op0, cmp_op1));
2847 /* Translate test condition. */
2848 *cmp_code = swap_condition (code);
2850 else /* if (code == GE || code == GEU || code == LT || code == LTU) */
2852 cmp_op1 = force_reg (mode, cmp_op1);
2853 if (code == GE || code == LT)
2854 emit_insn (gen_signed_compare (comp_reg, cmp_op1, cmp_op0));
2856 emit_insn (gen_unsigned_compare (comp_reg, cmp_op1, cmp_op0));
2862 /* Generate conditional branch -- first, generate test condition,
2863 second, generate correct branch instruction. */
2866 microblaze_expand_conditional_branch (enum machine_mode mode, rtx operands[])
2868 enum rtx_code code = GET_CODE (operands[0]);
2872 comp = microblaze_emit_compare (mode, operands[0], &code);
2873 condition = gen_rtx_fmt_ee (signed_condition (code), SImode, comp, const0_rtx);
2874 emit_jump_insn (gen_condjump (condition, operands[3]));
2878 microblaze_expand_conditional_branch_sf (rtx operands[])
2881 rtx cmp_op0 = XEXP (operands[0], 0);
2882 rtx cmp_op1 = XEXP (operands[0], 1);
2883 rtx comp_reg = gen_reg_rtx (SImode);
2885 emit_insn (gen_cstoresf4 (comp_reg, operands[0], cmp_op0, cmp_op1));
2886 condition = gen_rtx_NE (SImode, comp_reg, const0_rtx);
2887 emit_jump_insn (gen_condjump (condition, operands[3]));
2890 /* Implement TARGET_FRAME_POINTER_REQUIRED. */
2893 microblaze_frame_pointer_required (void)
2895 /* If the function contains dynamic stack allocations, we need to
2896 use the frame pointer to access the static parts of the frame. */
2897 if (cfun->calls_alloca)
2903 microblaze_expand_divide (rtx operands[])
2905 /* Table lookup software divides. Works for all (nr/dr) where (0 <= nr,dr <= 15). */
2907 rtx regt1 = gen_reg_rtx (SImode);
2908 rtx reg18 = gen_rtx_REG (SImode, R_TMP);
2909 rtx regqi = gen_reg_rtx (QImode);
2910 rtx div_label = gen_label_rtx ();
2911 rtx div_end_label = gen_label_rtx ();
2912 rtx div_table_rtx = gen_rtx_SYMBOL_REF (QImode,"_divsi3_table");
2915 rtx jump, cjump, insn;
2917 insn = emit_insn (gen_iorsi3 (regt1, operands[1], operands[2]));
2918 cjump = emit_jump_insn_after (gen_cbranchsi4 (
2919 gen_rtx_GTU (SImode, regt1, GEN_INT (15)),
2920 regt1, GEN_INT (15), div_label), insn);
2921 LABEL_NUSES (div_label) = 1;
2922 JUMP_LABEL (cjump) = div_label;
2923 emit_insn (gen_rtx_CLOBBER (SImode, reg18));
2925 emit_insn (gen_ashlsi3_bshift (regt1, operands[1], GEN_INT(4)));
2926 emit_insn (gen_addsi3 (regt1, regt1, operands[2]));
2927 mem_rtx = gen_rtx_MEM (QImode,
2928 gen_rtx_PLUS (Pmode, regt1, div_table_rtx));
2930 insn = emit_insn (gen_movqi (regqi, mem_rtx));
2931 insn = emit_insn (gen_movsi (operands[0], gen_rtx_SUBREG (SImode, regqi, 0)));
2932 jump = emit_jump_insn_after (gen_jump (div_end_label), insn);
2933 JUMP_LABEL (jump) = div_end_label;
2934 LABEL_NUSES (div_end_label) = 1;
2937 emit_label (div_label);
2938 ret = emit_library_call_value (gen_rtx_SYMBOL_REF (Pmode, "__divsi3"),
2939 operands[0], LCT_NORMAL,
2940 GET_MODE (operands[0]), 2, operands[1],
2941 GET_MODE (operands[1]), operands[2],
2942 GET_MODE (operands[2]));
2943 if (ret != operands[0])
2944 emit_move_insn (operands[0], ret);
2946 emit_label (div_end_label);
2947 emit_insn (gen_blockage ());
2950 /* Implement TARGET_FUNCTION_VALUE. */
2952 microblaze_function_value (const_tree valtype,
2953 const_tree func ATTRIBUTE_UNUSED,
2954 bool outgoing ATTRIBUTE_UNUSED)
2956 return LIBCALL_VALUE (TYPE_MODE (valtype));
2959 /* Implement TARGET_SCHED_ADJUST_COST. */
2961 microblaze_adjust_cost (rtx insn ATTRIBUTE_UNUSED, rtx link,
2962 rtx dep ATTRIBUTE_UNUSED, int cost)
2964 if (REG_NOTE_KIND (link) == REG_DEP_OUTPUT)
2966 if (REG_NOTE_KIND (link) != 0)
2971 #undef TARGET_ENCODE_SECTION_INFO
2972 #define TARGET_ENCODE_SECTION_INFO microblaze_encode_section_info
2974 #undef TARGET_ASM_GLOBALIZE_LABEL
2975 #define TARGET_ASM_GLOBALIZE_LABEL microblaze_globalize_label
2977 #undef TARGET_ASM_FUNCTION_PROLOGUE
2978 #define TARGET_ASM_FUNCTION_PROLOGUE microblaze_function_prologue
2980 #undef TARGET_ASM_FUNCTION_EPILOGUE
2981 #define TARGET_ASM_FUNCTION_EPILOGUE microblaze_function_epilogue
2983 #undef TARGET_RTX_COSTS
2984 #define TARGET_RTX_COSTS microblaze_rtx_costs
2986 #undef TARGET_ADDRESS_COST
2987 #define TARGET_ADDRESS_COST microblaze_address_cost
2989 #undef TARGET_ATTRIBUTE_TABLE
2990 #define TARGET_ATTRIBUTE_TABLE microblaze_attribute_table
2992 #undef TARGET_IN_SMALL_DATA_P
2993 #define TARGET_IN_SMALL_DATA_P microblaze_elf_in_small_data_p
2995 #undef TARGET_ASM_SELECT_SECTION
2996 #define TARGET_ASM_SELECT_SECTION microblaze_select_section
2998 #undef TARGET_HAVE_SRODATA_SECTION
2999 #define TARGET_HAVE_SRODATA_SECTION true
3001 #undef TARGET_ASM_FUNCTION_END_PROLOGUE
3002 #define TARGET_ASM_FUNCTION_END_PROLOGUE \
3003 microblaze_function_end_prologue
3005 #undef TARGET_HANDLE_OPTION
3006 #define TARGET_HANDLE_OPTION microblaze_handle_option
3008 #undef TARGET_DEFAULT_TARGET_FLAGS
3009 #define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
3011 #undef TARGET_ARG_PARTIAL_BYTES
3012 #define TARGET_ARG_PARTIAL_BYTES function_arg_partial_bytes
3014 #undef TARGET_FUNCTION_ARG
3015 #define TARGET_FUNCTION_ARG microblaze_function_arg
3017 #undef TARGET_FUNCTION_ARG_ADVANCE
3018 #define TARGET_FUNCTION_ARG_ADVANCE microblaze_function_arg_advance
3020 #undef TARGET_CAN_ELIMINATE
3021 #define TARGET_CAN_ELIMINATE microblaze_can_eliminate
3023 #undef TARGET_LEGITIMIZE_ADDRESS
3024 #define TARGET_LEGITIMIZE_ADDRESS microblaze_legitimize_address
3026 #undef TARGET_LEGITIMATE_ADDRESS_P
3027 #define TARGET_LEGITIMATE_ADDRESS_P microblaze_legitimate_address_p
3029 #undef TARGET_FRAME_POINTER_REQUIRED
3030 #define TARGET_FRAME_POINTER_REQUIRED microblaze_frame_pointer_required
3032 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
3033 #define TARGET_ASM_TRAMPOLINE_TEMPLATE microblaze_asm_trampoline_template
3035 #undef TARGET_TRAMPOLINE_INIT
3036 #define TARGET_TRAMPOLINE_INIT microblaze_trampoline_init
3038 #undef TARGET_PROMOTE_FUNCTION_MODE
3039 #define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
3041 #undef TARGET_FUNCTION_VALUE
3042 #define TARGET_FUNCTION_VALUE microblaze_function_value
3044 #undef TARGET_SECONDARY_RELOAD
3045 #define TARGET_SECONDARY_RELOAD microblaze_secondary_reload
3047 #undef TARGET_SCHED_ADJUST_COST
3048 #define TARGET_SCHED_ADJUST_COST microblaze_adjust_cost
3050 #undef TARGET_ASM_INIT_SECTIONS
3051 #define TARGET_ASM_INIT_SECTIONS microblaze_elf_asm_init_sections
3053 #undef TARGET_OPTION_OVERRIDE
3054 #define TARGET_OPTION_OVERRIDE microblaze_option_override
3056 #undef TARGET_OPTION_OPTIMIZATION_TABLE
3057 #define TARGET_OPTION_OPTIMIZATION_TABLE microblaze_option_optimization_table
3059 #undef TARGET_EXCEPT_UNWIND_INFO
3060 #define TARGET_EXCEPT_UNWIND_INFO sjlj_except_unwind_info
3062 struct gcc_target targetm = TARGET_INITIALIZER;
3064 #include "gt-microblaze.h"