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 = alloca (sizeof (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. */
1320 // microblaze_select_flags &= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY);
1321 microblaze_no_unsafe_delay = 0;
1322 microblaze_pipe = MICROBLAZE_PIPE_3;
1325 || (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v4.00.b")
1328 // microblaze_select_flags |= (MICROBLAZE_MASK_NO_UNSAFE_DELAY);
1329 microblaze_no_unsafe_delay = 1;
1330 microblaze_pipe = MICROBLAZE_PIPE_3;
1334 /* We agree to use 5 pipe-stage model even on area optimized 3
1335 pipe-stage variants. */
1336 // microblaze_select_flags &= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY);
1337 microblaze_no_unsafe_delay = 0;
1338 microblaze_pipe = MICROBLAZE_PIPE_5;
1339 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v5.00.a") == 0
1340 || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu,
1342 || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu,
1345 /* Pattern compares are to be turned on by default only when
1346 compiling for MB v5.00.'z'. */
1347 target_flags |= MASK_PATTERN_COMPARE;
1351 ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v6.00.a");
1354 if (TARGET_MULTIPLY_HIGH)
1356 "-mxl-multiply-high can be used only with -mcpu=v6.00.a or greater");
1359 if (TARGET_MULTIPLY_HIGH && TARGET_SOFT_MUL)
1360 error ("-mxl-multiply-high requires -mno-xl-soft-mul");
1362 /* Always use DFA scheduler. */
1363 microblaze_sched_use_dfa = 1;
1365 // microblaze_abicalls = MICROBLAZE_ABICALLS_NO;
1367 /* Initialize the high, low values for legit floating point constants. */
1368 real_maxval (&dfhigh, 0, DFmode);
1369 real_maxval (&dflow, 1, DFmode);
1370 real_maxval (&sfhigh, 0, SFmode);
1371 real_maxval (&sflow, 1, SFmode);
1373 microblaze_print_operand_punct['?'] = 1;
1374 microblaze_print_operand_punct['#'] = 1;
1375 microblaze_print_operand_punct['&'] = 1;
1376 microblaze_print_operand_punct['!'] = 1;
1377 microblaze_print_operand_punct['*'] = 1;
1378 microblaze_print_operand_punct['@'] = 1;
1379 microblaze_print_operand_punct['.'] = 1;
1380 microblaze_print_operand_punct['('] = 1;
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;
1392 /* Set up array to map GCC register number to debug register number.
1393 Ignore the special purpose register numbers. */
1395 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
1396 microblaze_dbx_regno[i] = -1;
1398 start = GP_DBX_FIRST - GP_REG_FIRST;
1399 for (i = GP_REG_FIRST; i <= GP_REG_LAST; i++)
1400 microblaze_dbx_regno[i] = i + start;
1402 /* Set up array giving whether a given register can hold a given mode. */
1404 for (mode = VOIDmode;
1405 mode != MAX_MACHINE_MODE; mode = (enum machine_mode) ((int) mode + 1))
1407 register int size = GET_MODE_SIZE (mode);
1409 for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
1415 ok = (ST_REG_P (regno) || GP_REG_P (regno));
1417 else if (GP_REG_P (regno))
1418 ok = ((regno & 1) == 0 || size <= UNITS_PER_WORD);
1422 microblaze_hard_regno_mode_ok[(int) mode][regno] = ok;
1427 /* Implement TARGET_OPTION_OPTIMIZATION_TABLE. */
1428 static const struct default_options microblaze_option_optimization_table[] =
1430 { OPT_LEVELS_1_PLUS, OPT_fomit_frame_pointer, NULL, 1 },
1431 { OPT_LEVELS_NONE, 0, NULL, 0 }
1434 /* Return true if FUNC is an interrupt function as specified
1435 by the "interrupt_handler" attribute. */
1438 microblaze_interrupt_function_p (tree func)
1442 if (TREE_CODE (func) != FUNCTION_DECL)
1445 a = lookup_attribute ("interrupt_handler", DECL_ATTRIBUTES (func));
1446 return a != NULL_TREE;
1449 /* Return true if FUNC is an interrupt function which uses
1450 normal return, indicated by the "save_volatiles" attribute. */
1453 microblaze_save_volatiles (tree func)
1457 if (TREE_CODE (func) != FUNCTION_DECL)
1460 a = lookup_attribute ("save_volatiles", DECL_ATTRIBUTES (func));
1461 return a != NULL_TREE;
1464 /* Return whether function is tagged with 'interrupt_handler'
1465 attribute. Return true if function should use return from
1466 interrupt rather than normal function return. */
1468 microblaze_is_interrupt_handler (void)
1470 return interrupt_handler;
1473 /* Determine of register must be saved/restored in call. */
1475 microblaze_must_save_register (int regno)
1477 if (pic_offset_table_rtx &&
1478 (regno == MB_ABI_PIC_ADDR_REGNUM) && df_regs_ever_live_p (regno))
1481 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
1484 if (frame_pointer_needed && (regno == HARD_FRAME_POINTER_REGNUM))
1487 if (!current_function_is_leaf)
1489 if (regno == MB_ABI_SUB_RETURN_ADDR_REGNUM)
1491 if ((interrupt_handler || save_volatiles) &&
1492 (regno >= 3 && regno <= 12))
1496 if (interrupt_handler)
1498 if (df_regs_ever_live_p (regno)
1499 || regno == MB_ABI_MSR_SAVE_REG
1500 || regno == MB_ABI_ASM_TEMP_REGNUM
1501 || regno == MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM)
1507 if (df_regs_ever_live_p (regno)
1508 || regno == MB_ABI_ASM_TEMP_REGNUM
1509 || regno == MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM)
1516 /* Return the bytes needed to compute the frame pointer from the current
1519 MicroBlaze stack frames look like:
1523 Before call After call
1524 +-----------------------+ +-----------------------+
1526 mem. | local variables, | | local variables, |
1527 | callee saved and | | callee saved and |
1529 +-----------------------+ +-----------------------+
1530 | arguments for called | | arguments for called |
1531 | subroutines | | subroutines |
1532 | (optional) | | (optional) |
1533 +-----------------------+ +-----------------------+
1534 | Link register | | Link register |
1536 +-----------------------+ +-----------------------+
1538 | local variables, |
1539 | callee saved and |
1541 +-----------------------+
1542 | MSR (optional if, |
1543 | interrupt handler) |
1544 +-----------------------+
1546 | alloca allocations |
1548 +-----------------------+
1550 | arguments for called |
1554 +-----------------------+
1557 memory +-----------------------+
1561 static HOST_WIDE_INT
1562 compute_frame_size (HOST_WIDE_INT size)
1565 HOST_WIDE_INT total_size; /* # bytes that the entire frame takes up. */
1566 HOST_WIDE_INT var_size; /* # bytes that local variables take up. */
1567 HOST_WIDE_INT args_size; /* # bytes that outgoing arguments take up. */
1568 int link_debug_size; /* # bytes for link register. */
1569 HOST_WIDE_INT gp_reg_size; /* # bytes needed to store calle-saved gp regs. */
1570 long mask; /* mask of saved gp registers. */
1573 microblaze_interrupt_function_p (current_function_decl);
1574 save_volatiles = microblaze_save_volatiles (current_function_decl);
1579 args_size = crtl->outgoing_args_size;
1581 if ((args_size == 0) && cfun->calls_alloca)
1582 args_size = NUM_OF_ARGS * UNITS_PER_WORD;
1584 total_size = var_size + args_size;
1587 /* force setting GOT. */
1588 df_set_regs_ever_live (MB_ABI_PIC_ADDR_REGNUM, true);
1590 /* Calculate space needed for gp registers. */
1591 for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
1593 if (microblaze_must_save_register (regno))
1596 if (regno != MB_ABI_SUB_RETURN_ADDR_REGNUM)
1597 /* Don't account for link register. It is accounted specially below. */
1598 gp_reg_size += GET_MODE_SIZE (SImode);
1600 mask |= (1L << (regno - GP_REG_FIRST));
1604 total_size += gp_reg_size;
1606 /* Add 4 bytes for MSR. */
1607 if (interrupt_handler)
1610 /* No space to be allocated for link register in leaf functions with no other
1611 stack requirements. */
1612 if (total_size == 0 && current_function_is_leaf)
1613 link_debug_size = 0;
1615 link_debug_size = UNITS_PER_WORD;
1617 total_size += link_debug_size;
1619 /* Save other computed information. */
1620 current_frame_info.total_size = total_size;
1621 current_frame_info.var_size = var_size;
1622 current_frame_info.args_size = args_size;
1623 current_frame_info.gp_reg_size = gp_reg_size;
1624 current_frame_info.mask = mask;
1625 current_frame_info.initialized = reload_completed;
1626 current_frame_info.num_gp = gp_reg_size / UNITS_PER_WORD;
1627 current_frame_info.link_debug_size = link_debug_size;
1630 /* Offset from which to callee-save GP regs. */
1631 current_frame_info.gp_offset = (total_size - gp_reg_size);
1633 current_frame_info.gp_offset = 0;
1635 /* Ok, we're done. */
1639 /* Make sure that we're not trying to eliminate to the wrong hard frame
1643 microblaze_can_eliminate (const int from, const int to)
1645 return ((from == RETURN_ADDRESS_POINTER_REGNUM && !leaf_function_p())
1646 || (to == MB_ABI_SUB_RETURN_ADDR_REGNUM && leaf_function_p())
1647 || (from != RETURN_ADDRESS_POINTER_REGNUM
1648 && (to == HARD_FRAME_POINTER_REGNUM
1649 || (to == STACK_POINTER_REGNUM && !frame_pointer_needed))));
1652 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
1653 pointer or argument pointer or the return address pointer. TO is either
1654 the stack pointer or hard frame pointer. */
1657 microblaze_initial_elimination_offset (int from, int to)
1659 HOST_WIDE_INT offset;
1663 case FRAME_POINTER_REGNUM:
1666 case ARG_POINTER_REGNUM:
1667 if (to == STACK_POINTER_REGNUM || to == HARD_FRAME_POINTER_REGNUM)
1668 offset = compute_frame_size (get_frame_size ());
1672 case RETURN_ADDRESS_POINTER_REGNUM:
1673 if (current_function_is_leaf)
1676 offset = current_frame_info.gp_offset +
1677 ((UNITS_PER_WORD - (POINTER_SIZE / BITS_PER_UNIT)));
1685 /* Print operands using format code.
1687 The MicroBlaze specific codes are:
1689 'X' X is CONST_INT, prints 32 bits in hexadecimal format = "0x%08x",
1690 'x' X is CONST_INT, prints 16 bits in hexadecimal format = "0x%04x",
1691 'F' op is CONST_DOUBLE, print 32 bits in hex,
1692 'd' output integer constant in decimal,
1693 'z' if the operand is 0, use $0 instead of normal operand.
1694 'D' print second register of double-word register operand.
1695 'L' print low-order register of double-word register operand.
1696 'M' print high-order register of double-word register operand.
1697 'C' print part of opcode for a branch condition.
1698 'N' print part of opcode for a branch condition, inverted.
1699 'S' X is CODE_LABEL, print with prefix of "LS" (for embedded switch).
1700 'B' print 'z' for EQ, 'n' for NE
1701 'b' print 'n' for EQ, 'z' for NE
1702 'T' print 'f' for EQ, 't' for NE
1703 't' print 't' for EQ, 'f' for NE
1704 'm' Print 1<<operand.
1705 'i' Print 'i' if MEM operand has immediate value
1706 'o' Print operand address+4
1707 '?' Print 'd' if we use a branch with delay slot instead of normal branch.
1708 'h' Print high word of const_double (int or float) value as hex
1709 'j' Print low word of const_double (int or float) value as hex
1710 's' Print -1 if operand is negative, 0 if positive (sign extend)
1711 '@' Print the name of the temporary register (rMB_ABI_ASM_TEMP_REGNUM).
1712 '#' Print nop if the delay slot of a branch is not filled.
1716 print_operand (FILE * file, rtx op, int letter)
1718 register enum rtx_code code;
1720 if (PRINT_OPERAND_PUNCT_VALID_P (letter))
1725 /* Conditionally add a 'd' to indicate filled delay slot. */
1726 if (final_sequence != NULL)
1731 /* Conditionally add a nop in unfilled delay slot. */
1732 if (final_sequence == NULL)
1733 fputs ("nop\t\t# Unfilled delay slot\n", file);
1737 fputs (reg_names[GP_REG_FIRST + MB_ABI_ASM_TEMP_REGNUM], file);
1741 output_operand_lossage ("unknown punctuation '%c'", letter);
1750 output_operand_lossage ("null pointer");
1754 code = GET_CODE (op);
1756 if (code == SIGN_EXTEND)
1757 op = XEXP (op, 0), code = GET_CODE (op);
1785 fatal_insn ("PRINT_OPERAND, invalid insn for %%C", op);
1788 else if (letter == 'N')
1814 fatal_insn ("PRINT_OPERAND, invalid insn for %%N", op);
1817 else if (letter == 'S')
1821 ASM_GENERATE_INTERNAL_LABEL (buffer, "LS", CODE_LABEL_NUMBER (op));
1822 assemble_name (file, buffer);
1825 /* Print 'i' for memory operands which have immediate values. */
1826 else if (letter == 'i')
1830 struct microblaze_address_info info;
1832 if (!microblaze_classify_address
1833 (&info, XEXP (op, 0), GET_MODE (op), 1))
1834 fatal_insn ("insn contains an invalid address !", op);
1839 case ADDRESS_CONST_INT:
1840 case ADDRESS_SYMBOLIC:
1841 case ADDRESS_GOTOFF:
1844 case ADDRESS_REG_INDEX:
1846 case ADDRESS_INVALID:
1848 fatal_insn ("invalid address", op);
1853 else if (code == REG || code == SUBREG)
1855 register int regnum;
1858 regnum = REGNO (op);
1860 regnum = true_regnum (op);
1862 if ((letter == 'M' && !WORDS_BIG_ENDIAN)
1863 || (letter == 'L' && WORDS_BIG_ENDIAN) || letter == 'D')
1866 fprintf (file, "%s", reg_names[regnum]);
1869 else if (code == MEM)
1872 rtx op4 = adjust_address (op, GET_MODE (op), 4);
1873 output_address (XEXP (op4, 0));
1876 output_address (XEXP (op, 0));
1878 else if (letter == 'h' || letter == 'j')
1881 if (code == CONST_DOUBLE)
1883 if (GET_MODE (op) == DFmode)
1885 REAL_VALUE_TYPE value;
1886 REAL_VALUE_FROM_CONST_DOUBLE (value, op);
1887 REAL_VALUE_TO_TARGET_DOUBLE (value, val);
1891 val[0] = CONST_DOUBLE_HIGH (op);
1892 val[1] = CONST_DOUBLE_LOW (op);
1895 else if (code == CONST_INT)
1897 val[0] = (INTVAL (op) & 0xffffffff00000000LL) >> 32;
1898 val[1] = INTVAL (op) & 0x00000000ffffffffLL;
1899 if (val[0] == 0 && val[1] < 0)
1903 fprintf (file, "0x%8.8lx", (letter == 'h') ? val[0] : val[1]);
1905 else if (code == CONST_DOUBLE)
1909 unsigned long value_long;
1910 REAL_VALUE_TYPE value;
1911 REAL_VALUE_FROM_CONST_DOUBLE (value, op);
1912 REAL_VALUE_TO_TARGET_SINGLE (value, value_long);
1913 fprintf (file, HOST_WIDE_INT_PRINT_HEX, value_long);
1918 real_to_decimal (s, CONST_DOUBLE_REAL_VALUE (op), sizeof (s), 0, 1);
1923 else if (code == UNSPEC)
1925 print_operand_address (file, op);
1928 else if (letter == 'x' && GET_CODE (op) == CONST_INT)
1929 fprintf (file, HOST_WIDE_INT_PRINT_HEX, 0xffff & INTVAL (op));
1931 else if (letter == 'X' && GET_CODE (op) == CONST_INT)
1932 fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (op));
1934 else if (letter == 'd' && GET_CODE (op) == CONST_INT)
1935 fprintf (file, HOST_WIDE_INT_PRINT_DEC, (INTVAL (op)));
1937 else if (letter == 'z' && GET_CODE (op) == CONST_INT && INTVAL (op) == 0)
1938 fputs (reg_names[GP_REG_FIRST], file);
1940 else if (letter == 's' && GET_CODE (op) == CONST_INT)
1941 if (INTVAL (op) < 0)
1946 else if (letter == 'd' || letter == 'x' || letter == 'X' || letter == 's')
1947 output_operand_lossage ("letter %c was found & insn was not CONST_INT", letter);
1949 else if (letter == 'B')
1950 fputs (code == EQ ? "z" : "n", file);
1951 else if (letter == 'b')
1952 fputs (code == EQ ? "n" : "z", file);
1953 else if (letter == 'T')
1954 fputs (code == EQ ? "f" : "t", file);
1955 else if (letter == 't')
1956 fputs (code == EQ ? "t" : "f", file);
1958 else if (code == CONST && GET_CODE (XEXP (op, 0)) == REG)
1960 print_operand (file, XEXP (op, 0), letter);
1962 else if (letter == 'm')
1963 fprintf (file, HOST_WIDE_INT_PRINT_DEC, (1L << INTVAL (op)));
1965 output_addr_const (file, op);
1968 /* A C compound statement to output to stdio stream STREAM the
1969 assembler syntax for an instruction operand that is a memory
1970 reference whose address is ADDR. ADDR is an RTL expression.
1972 Possible address classifications and output formats are,
1974 ADDRESS_REG "%0, r0"
1976 ADDRESS_REG with non-zero "%0, <addr_const>"
1979 ADDRESS_REG_INDEX "rA, RB"
1980 (if rA is r0, rA and rB are swapped)
1982 ADDRESS_CONST_INT "r0, <addr_const>"
1984 ADDRESS_SYMBOLIC "rBase, <addr_const>"
1985 (rBase is a base register suitable for the
1990 print_operand_address (FILE * file, rtx addr)
1992 struct microblaze_address_info info;
1993 enum microblaze_address_type type;
1994 if (!microblaze_classify_address (&info, addr, GET_MODE (addr), 1))
1995 fatal_insn ("insn contains an invalid address !", addr);
2001 fprintf (file, "%s,", reg_names[REGNO (info.regA)]);
2002 output_addr_const (file, info.offset);
2004 case ADDRESS_REG_INDEX:
2005 if (REGNO (info.regA) == 0)
2006 /* Make rB == r0 instead of rA == r0. This helps reduce read port
2008 fprintf (file, "%s,%s", reg_names[REGNO (info.regB)],
2009 reg_names[REGNO (info.regA)]);
2010 else if (REGNO (info.regB) != 0)
2011 /* This is a silly swap to help Dhrystone. */
2012 fprintf (file, "%s,%s", reg_names[REGNO (info.regB)],
2013 reg_names[REGNO (info.regA)]);
2015 case ADDRESS_CONST_INT:
2016 fprintf (file, "%s,", reg_names[REGNO (info.regA)]);
2017 output_addr_const (file, info.offset);
2019 case ADDRESS_SYMBOLIC:
2020 case ADDRESS_GOTOFF:
2023 fprintf (file, "%s,", reg_names[REGNO (info.regA)]);
2024 output_addr_const (file, info.symbol);
2025 if (type == ADDRESS_GOTOFF)
2027 fputs ("@GOT", file);
2029 else if (type == ADDRESS_PLT)
2031 fputs ("@PLT", file);
2034 case ADDRESS_INVALID:
2035 fatal_insn ("invalid address", addr);
2040 /* Emit either a label, .comm, or .lcomm directive, and mark that the symbol
2041 is used, so that we don't emit an .extern for it in
2042 microblaze_asm_file_end. */
2045 microblaze_declare_object (FILE * stream, const char *name,
2046 const char *section, const char *fmt, int size)
2049 fputs (section, stream);
2050 assemble_name (stream, name);
2051 fprintf (stream, fmt, size);
2054 /* Common code to emit the insns (or to write the instructions to a file)
2055 to save/restore registers.
2057 Other parts of the code assume that MICROBLAZE_TEMP1_REGNUM (aka large_reg)
2058 is not modified within save_restore_insns. */
2060 #define BITSET_P(VALUE,BIT) (((VALUE) & (1L << (BIT))) != 0)
2062 /* Save or restore instructions based on whether this is the prologue or
2063 epilogue. prologue is 1 for the prologue. */
2065 save_restore_insns (int prologue)
2067 rtx base_reg_rtx, reg_rtx, mem_rtx, /* msr_rtx, */ isr_reg_rtx =
2069 rtx isr_msr_rtx = 0, insn;
2070 long mask = current_frame_info.mask;
2071 HOST_WIDE_INT base_offset, gp_offset;
2074 if (frame_pointer_needed
2075 && !BITSET_P (mask, HARD_FRAME_POINTER_REGNUM - GP_REG_FIRST))
2081 /* Save registers starting from high to low. The debuggers prefer at least
2082 the return register be stored at func+4, and also it allows us not to
2083 need a nop in the epilog if at least one register is reloaded in
2084 addition to return address. */
2086 /* Pick which pointer to use as a base register. For small frames, just
2087 use the stack pointer. Otherwise, use a temporary register. Save 2
2088 cycles if the save area is near the end of a large frame, by reusing
2089 the constant created in the prologue/epilogue to adjust the stack
2092 gp_offset = current_frame_info.gp_offset;
2094 gcc_assert (gp_offset > 0);
2096 base_reg_rtx = stack_pointer_rtx;
2099 /* For interrupt_handlers, need to save/restore the MSR. */
2100 if (interrupt_handler)
2102 isr_mem_rtx = gen_rtx_MEM (SImode,
2103 gen_rtx_PLUS (Pmode, base_reg_rtx,
2104 GEN_INT (current_frame_info.
2108 /* Do not optimize in flow analysis. */
2109 MEM_VOLATILE_P (isr_mem_rtx) = 1;
2110 isr_reg_rtx = gen_rtx_REG (SImode, MB_ABI_MSR_SAVE_REG);
2111 isr_msr_rtx = gen_rtx_REG (SImode, ST_REG);
2114 if (interrupt_handler && !prologue)
2116 emit_move_insn (isr_reg_rtx, isr_mem_rtx);
2117 emit_move_insn (isr_msr_rtx, isr_reg_rtx);
2118 /* Do not optimize in flow analysis. */
2119 emit_insn (gen_rtx_USE (SImode, isr_reg_rtx));
2120 emit_insn (gen_rtx_USE (SImode, isr_msr_rtx));
2123 for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
2125 if (BITSET_P (mask, regno - GP_REG_FIRST))
2127 if (regno == MB_ABI_SUB_RETURN_ADDR_REGNUM)
2128 /* Don't handle here. Already handled as the first register. */
2131 reg_rtx = gen_rtx_REG (SImode, regno);
2132 insn = gen_rtx_PLUS (Pmode, base_reg_rtx, GEN_INT (gp_offset));
2133 mem_rtx = gen_rtx_MEM (SImode, insn);
2134 if (interrupt_handler || save_volatiles)
2135 /* Do not optimize in flow analysis. */
2136 MEM_VOLATILE_P (mem_rtx) = 1;
2140 insn = emit_move_insn (mem_rtx, reg_rtx);
2141 RTX_FRAME_RELATED_P (insn) = 1;
2145 insn = emit_move_insn (reg_rtx, mem_rtx);
2148 gp_offset += GET_MODE_SIZE (SImode);
2152 if (interrupt_handler && prologue)
2154 emit_move_insn (isr_reg_rtx, isr_msr_rtx);
2155 emit_move_insn (isr_mem_rtx, isr_reg_rtx);
2157 /* Do not optimize in flow analysis. */
2158 emit_insn (gen_rtx_USE (SImode, isr_reg_rtx));
2159 emit_insn (gen_rtx_USE (SImode, isr_msr_rtx));
2162 /* Done saving and restoring */
2166 /* Set up the stack and frame (if desired) for the function. */
2168 microblaze_function_prologue (FILE * file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
2171 long fsiz = current_frame_info.total_size;
2173 /* Get the function name the same way that toplev.c does before calling
2174 assemble_start_function. This is needed so that the name used here
2175 exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */
2176 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
2177 if (!flag_inhibit_size_directive)
2179 fputs ("\t.ent\t", file);
2180 if (interrupt_handler && strcmp (INTERRUPT_HANDLER_NAME, fnname))
2181 fputs ("_interrupt_handler", file);
2183 assemble_name (file, fnname);
2185 if (!interrupt_handler)
2186 ASM_OUTPUT_TYPE_DIRECTIVE (file, fnname, "function");
2189 assemble_name (file, fnname);
2190 fputs (":\n", file);
2192 if (interrupt_handler && strcmp (INTERRUPT_HANDLER_NAME, fnname))
2193 fputs ("_interrupt_handler:\n", file);
2195 if (!flag_inhibit_size_directive)
2197 /* .frame FRAMEREG, FRAMESIZE, RETREG. */
2199 "\t.frame\t%s,%ld,%s\t\t# vars= %ld, regs= %d, args= %d\n",
2200 (reg_names[(frame_pointer_needed)
2201 ? HARD_FRAME_POINTER_REGNUM :
2202 STACK_POINTER_REGNUM]), fsiz,
2203 reg_names[MB_ABI_SUB_RETURN_ADDR_REGNUM + GP_REG_FIRST],
2204 current_frame_info.var_size, current_frame_info.num_gp,
2205 crtl->outgoing_args_size);
2206 fprintf (file, "\t.mask\t0x%08lx\n", current_frame_info.mask);
2210 /* Output extra assembler code at the end of a prologue. */
2212 microblaze_function_end_prologue (FILE * file)
2214 if (TARGET_STACK_CHECK)
2216 fprintf (file, "\t# Stack Check Stub -- Start.\n\t");
2217 fprintf (file, "ori\tr18,r0,_stack_end\n\t");
2218 fprintf (file, "cmpu\tr18,r1,r18\n\t");
2219 fprintf (file, "bgei\tr18,_stack_overflow_exit\n\t");
2220 fprintf (file, "# Stack Check Stub -- End.\n");
2224 /* Expand the prologue into a bunch of separate insns. */
2227 microblaze_expand_prologue (void)
2231 const char *arg_name = 0;
2232 tree fndecl = current_function_decl;
2233 tree fntype = TREE_TYPE (fndecl);
2234 tree fnargs = DECL_ARGUMENTS (fndecl);
2239 CUMULATIVE_ARGS args_so_far;
2240 rtx mem_rtx, reg_rtx;
2242 /* If struct value address is treated as the first argument, make it so. */
2243 if (aggregate_value_p (DECL_RESULT (fndecl), fntype)
2244 && !cfun->returns_pcc_struct)
2246 tree type = build_pointer_type (fntype);
2247 tree function_result_decl = build_decl (BUILTINS_LOCATION, PARM_DECL,
2250 DECL_ARG_TYPE (function_result_decl) = type;
2251 TREE_CHAIN (function_result_decl) = fnargs;
2252 fnargs = function_result_decl;
2255 /* Determine the last argument, and get its name. */
2257 INIT_CUMULATIVE_ARGS (args_so_far, fntype, NULL_RTX, 0, 0);
2258 regno = GP_ARG_FIRST;
2260 for (cur_arg = fnargs; cur_arg != 0; cur_arg = next_arg)
2262 tree passed_type = DECL_ARG_TYPE (cur_arg);
2263 enum machine_mode passed_mode = TYPE_MODE (passed_type);
2266 if (TREE_ADDRESSABLE (passed_type))
2268 passed_type = build_pointer_type (passed_type);
2269 passed_mode = Pmode;
2272 entry_parm = targetm.calls.function_arg (&args_so_far, passed_mode,
2279 /* passed in a register, so will get homed automatically. */
2280 if (GET_MODE (entry_parm) == BLKmode)
2281 words = (int_size_in_bytes (passed_type) + 3) / 4;
2283 words = (GET_MODE_SIZE (GET_MODE (entry_parm)) + 3) / 4;
2285 regno = REGNO (entry_parm) + words - 1;
2289 regno = GP_ARG_LAST + 1;
2293 targetm.calls.function_arg_advance (&args_so_far, passed_mode,
2296 next_arg = TREE_CHAIN (cur_arg);
2299 if (DECL_NAME (cur_arg))
2300 arg_name = IDENTIFIER_POINTER (DECL_NAME (cur_arg));
2306 /* Split parallel insn into a sequence of insns. */
2308 next_arg_reg = targetm.calls.function_arg (&args_so_far, VOIDmode,
2309 void_type_node, true);
2310 if (next_arg_reg != 0 && GET_CODE (next_arg_reg) == PARALLEL)
2312 rtvec adjust = XVEC (next_arg_reg, 0);
2313 int num = GET_NUM_ELEM (adjust);
2315 for (i = 0; i < num; i++)
2317 rtx pattern = RTVEC_ELT (adjust, i);
2318 emit_insn (pattern);
2322 fsiz = compute_frame_size (get_frame_size ());
2324 /* If this function is a varargs function, store any registers that
2325 would normally hold arguments ($5 - $10) on the stack. */
2326 if (((TYPE_ARG_TYPES (fntype) != 0
2327 && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
2330 && ((arg_name[0] == '_'
2331 && strcmp (arg_name, "__builtin_va_alist") == 0)
2332 || (arg_name[0] == 'v'
2333 && strcmp (arg_name, "va_alist") == 0)))))
2335 int offset = (regno - GP_ARG_FIRST + 1) * UNITS_PER_WORD;
2336 rtx ptr = stack_pointer_rtx;
2338 /* If we are doing svr4-abi, sp has already been decremented by fsiz. */
2339 for (; regno <= GP_ARG_LAST; regno++)
2342 ptr = gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (offset));
2343 emit_move_insn (gen_rtx_MEM (SImode, ptr),
2344 gen_rtx_REG (SImode, regno));
2346 offset += GET_MODE_SIZE (SImode);
2353 rtx fsiz_rtx = GEN_INT (fsiz);
2356 insn = emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx,
2359 RTX_FRAME_RELATED_P (insn) = 1;
2361 /* Handle SUB_RETURN_ADDR_REGNUM specially at first. */
2362 if (!current_function_is_leaf || interrupt_handler)
2364 mem_rtx = gen_rtx_MEM (SImode,
2365 gen_rtx_PLUS (Pmode, stack_pointer_rtx,
2368 if (interrupt_handler)
2369 /* Do not optimize in flow analysis. */
2370 MEM_VOLATILE_P (mem_rtx) = 1;
2372 reg_rtx = gen_rtx_REG (SImode, MB_ABI_SUB_RETURN_ADDR_REGNUM);
2373 insn = emit_move_insn (mem_rtx, reg_rtx);
2374 RTX_FRAME_RELATED_P (insn) = 1;
2377 /* _save_ registers for prologue. */
2378 save_restore_insns (1);
2380 if (frame_pointer_needed)
2384 insn = emit_insn (gen_movsi (hard_frame_pointer_rtx,
2385 stack_pointer_rtx));
2388 RTX_FRAME_RELATED_P (insn) = 1;
2392 if (flag_pic == 2 && df_regs_ever_live_p (MB_ABI_PIC_ADDR_REGNUM))
2395 SET_REGNO (pic_offset_table_rtx, MB_ABI_PIC_ADDR_REGNUM);
2396 insn = emit_insn (gen_set_got (pic_offset_table_rtx)); /* setting GOT. */
2399 /* If we are profiling, make sure no instructions are scheduled before
2400 the call to mcount. */
2403 emit_insn (gen_blockage ());
2406 /* Do necessary cleanup after a function to restore stack, frame, and regs. */
2408 #define RA_MASK ((long) 0x80000000) /* 1 << 31 */
2409 #define PIC_OFFSET_TABLE_MASK (1 << (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST))
2412 microblaze_function_epilogue (FILE * file ATTRIBUTE_UNUSED,
2413 HOST_WIDE_INT size ATTRIBUTE_UNUSED)
2417 /* Get the function name the same way that toplev.c does before calling
2418 assemble_start_function. This is needed so that the name used here
2419 exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */
2420 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
2422 if (!flag_inhibit_size_directive)
2424 fputs ("\t.end\t", file);
2425 if (interrupt_handler)
2426 fputs ("_interrupt_handler", file);
2428 assemble_name (file, fnname);
2432 /* Reset state info for each function. */
2433 current_frame_info = zero_frame_info;
2435 /* Restore the output file if optimizing the GP (optimizing the GP causes
2436 the text to be diverted to a tempfile, so that data decls come before
2437 references to the data). */
2440 /* Expand the epilogue into a bunch of separate insns. */
2443 microblaze_expand_epilogue (void)
2445 HOST_WIDE_INT fsiz = current_frame_info.total_size;
2446 rtx fsiz_rtx = GEN_INT (fsiz);
2450 /* In case of interrupt handlers use addki instead of addi for changing the
2451 stack pointer value. */
2453 if (microblaze_can_use_return_insn ())
2455 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode,
2457 MB_ABI_SUB_RETURN_ADDR_REGNUM)));
2463 /* Restore SUB_RETURN_ADDR_REGNUM at first. This is to prevent the
2464 sequence of load-followed by a use (in rtsd) in every prologue. Saves
2465 a load-use stall cycle :) This is also important to handle alloca.
2466 (See comments for if (frame_pointer_needed) below. */
2468 if (!current_function_is_leaf || interrupt_handler)
2471 gen_rtx_MEM (SImode,
2472 gen_rtx_PLUS (Pmode, stack_pointer_rtx, const0_rtx));
2473 if (interrupt_handler)
2474 /* Do not optimize in flow analysis. */
2475 MEM_VOLATILE_P (mem_rtx) = 1;
2476 reg_rtx = gen_rtx_REG (SImode, MB_ABI_SUB_RETURN_ADDR_REGNUM);
2477 emit_move_insn (reg_rtx, mem_rtx);
2480 /* It is important that this is done after we restore the return address
2481 register (above). When alloca is used, we want to restore the
2482 sub-routine return address only from the current stack top and not
2483 from the frame pointer (which we restore below). (frame_pointer + 0)
2484 might have been over-written since alloca allocates memory on the
2486 if (frame_pointer_needed)
2487 emit_insn (gen_movsi (stack_pointer_rtx, hard_frame_pointer_rtx));
2489 /* _restore_ registers for epilogue. */
2490 save_restore_insns (0);
2491 emit_insn (gen_blockage ());
2492 emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, fsiz_rtx));
2495 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode, GP_REG_FIRST +
2496 MB_ABI_SUB_RETURN_ADDR_REGNUM)));
2500 /* Return nonzero if this function is known to have a null epilogue.
2501 This allows the optimizer to omit jumps to jumps if no stack
2505 microblaze_can_use_return_insn (void)
2507 if (!reload_completed)
2510 if (df_regs_ever_live_p (MB_ABI_SUB_RETURN_ADDR_REGNUM) || profile_flag)
2513 if (current_frame_info.initialized)
2514 return current_frame_info.total_size == 0;
2516 return compute_frame_size (get_frame_size ()) == 0;
2519 /* Implement TARGET_SECONDARY_RELOAD. */
2521 static enum reg_class
2522 microblaze_secondary_reload (bool in_p ATTRIBUTE_UNUSED, rtx x ATTRIBUTE_UNUSED,
2523 enum reg_class rclass, enum machine_mode mode ATTRIBUTE_UNUSED,
2524 secondary_reload_info *sri ATTRIBUTE_UNUSED)
2526 if (rclass == ST_REGS)
2533 microblaze_globalize_label (FILE * stream, const char *name)
2535 fputs ("\t.globl\t", stream);
2536 if (interrupt_handler && strcmp (name, INTERRUPT_HANDLER_NAME))
2538 fputs (INTERRUPT_HANDLER_NAME, stream);
2539 fputs ("\n\t.globl\t", stream);
2541 assemble_name (stream, name);
2542 fputs ("\n", stream);
2545 /* Returns true if decl should be placed into a "small data" section. */
2547 microblaze_elf_in_small_data_p (const_tree decl)
2549 if (!TARGET_XLGPOPT)
2552 /* We want to merge strings, so we never consider them small data. */
2553 if (TREE_CODE (decl) == STRING_CST)
2556 /* Functions are never in the small data area. */
2557 if (TREE_CODE (decl) == FUNCTION_DECL)
2560 if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl))
2562 const char *section = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
2563 if (strcmp (section, ".sdata") == 0
2564 || strcmp (section, ".sdata2") == 0
2565 || strcmp (section, ".sbss") == 0
2566 || strcmp (section, ".sbss2") == 0)
2570 HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (decl));
2572 return (size > 0 && size <= microblaze_section_threshold);
2577 microblaze_select_section (tree decl, int reloc, unsigned HOST_WIDE_INT align)
2579 switch (categorize_decl_for_section (decl, reloc))
2581 case SECCAT_RODATA_MERGE_STR:
2582 case SECCAT_RODATA_MERGE_STR_INIT:
2583 /* MB binutils have various issues with mergeable string sections and
2584 relaxation/relocation. Currently, turning mergeable sections
2585 into regular readonly sections. */
2587 return readonly_data_section;
2589 return default_elf_select_section (decl, reloc, align);
2594 Encode info about sections into the RTL based on a symbol's declaration.
2595 The default definition of this hook, default_encode_section_info in
2596 `varasm.c', sets a number of commonly-useful bits in SYMBOL_REF_FLAGS. */
2599 microblaze_encode_section_info (tree decl, rtx rtl, int first)
2601 default_encode_section_info (decl, rtl, first);
2605 expand_pic_symbol_ref (enum machine_mode mode ATTRIBUTE_UNUSED, rtx op)
2608 result = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op), UNSPEC_GOTOFF);
2609 result = gen_rtx_CONST (Pmode, result);
2610 result = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, result);
2611 result = gen_const_mem (Pmode, result);
2616 microblaze_expand_move (enum machine_mode mode, rtx operands[])
2618 /* If operands[1] is a constant address invalid for pic, then we need to
2619 handle it just like LEGITIMIZE_ADDRESS does. */
2622 if (GET_CODE (operands[0]) == MEM)
2624 rtx addr = XEXP (operands[0], 0);
2625 if (GET_CODE (addr) == SYMBOL_REF)
2627 if (reload_in_progress)
2628 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
2630 rtx ptr_reg, result;
2632 addr = expand_pic_symbol_ref (mode, addr);
2633 ptr_reg = gen_reg_rtx (Pmode);
2634 emit_move_insn (ptr_reg, addr);
2635 result = gen_rtx_MEM (mode, ptr_reg);
2636 operands[0] = result;
2639 if (GET_CODE (operands[1]) == SYMBOL_REF
2640 || GET_CODE (operands[1]) == LABEL_REF)
2643 if (reload_in_progress)
2644 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
2645 result = expand_pic_symbol_ref (mode, operands[1]);
2646 if (GET_CODE (operands[0]) != REG)
2648 rtx ptr_reg = gen_reg_rtx (Pmode);
2649 emit_move_insn (ptr_reg, result);
2650 emit_move_insn (operands[0], ptr_reg);
2654 emit_move_insn (operands[0], result);
2658 else if (GET_CODE (operands[1]) == MEM &&
2659 GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF)
2663 if (reload_in_progress)
2664 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
2665 result = expand_pic_symbol_ref (mode, XEXP (operands[1], 0));
2667 ptr_reg = gen_reg_rtx (Pmode);
2669 emit_move_insn (ptr_reg, result);
2670 result = gen_rtx_MEM (mode, ptr_reg);
2671 emit_move_insn (operands[0], result);
2674 else if (pic_address_needs_scratch (operands[1]))
2676 rtx temp = force_reg (SImode, XEXP (XEXP (operands[1], 0), 0));
2677 rtx temp2 = XEXP (XEXP (operands[1], 0), 1);
2679 if (reload_in_progress)
2680 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
2681 emit_move_insn (operands[0], gen_rtx_PLUS (SImode, temp, temp2));
2686 if ((reload_in_progress | reload_completed) == 0
2687 && !register_operand (operands[0], SImode)
2688 && !register_operand (operands[1], SImode)
2689 && (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 0))
2691 rtx temp = force_reg (SImode, operands[1]);
2692 emit_move_insn (operands[0], temp);
2698 /* Expand shift operations. */
2700 microblaze_expand_shift (rtx operands[])
2702 gcc_assert ((GET_CODE (operands[2]) == CONST_INT)
2703 || (GET_CODE (operands[2]) == REG)
2704 || (GET_CODE (operands[2]) == SUBREG));
2706 /* Shift by one -- generate pattern. */
2707 if ((GET_CODE (operands[2]) == CONST_INT) && (INTVAL (operands[2]) == 1))
2710 /* Have barrel shifter and shift > 1: use it. */
2711 if (TARGET_BARREL_SHIFT)
2714 gcc_assert ((GET_CODE (operands[0]) == REG)
2715 || (GET_CODE (operands[0]) == SUBREG)
2716 || (GET_CODE (operands[1]) == REG)
2717 || (GET_CODE (operands[1]) == SUBREG));
2719 /* Shift by zero -- copy regs if necessary. */
2720 if ((GET_CODE (operands[2]) == CONST_INT) && (INTVAL (operands[2]) == 0))
2722 if (REGNO (operands[0]) != REGNO (operands[1]))
2723 emit_insn (gen_movsi (operands[0], operands[1]));
2730 /* Return an RTX indicating where the return address to the
2731 calling function can be found. */
2733 microblaze_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
2738 return gen_rtx_PLUS (Pmode,
2739 get_hard_reg_initial_val (Pmode,
2740 MB_ABI_SUB_RETURN_ADDR_REGNUM),
2744 /* Put string into .sdata2 if below threashold. */
2746 microblaze_asm_output_ident (FILE *file ATTRIBUTE_UNUSED, const char *string)
2748 int size = strlen (string) + 1;
2749 if (size <= microblaze_section_threshold)
2750 switch_to_section (sdata2_section);
2752 switch_to_section (readonly_data_section);
2753 assemble_string (string, size);
2757 microblaze_elf_asm_init_sections (void)
2760 = get_unnamed_section (SECTION_WRITE, output_section_asm_op,
2761 SDATA2_SECTION_ASM_OP);
2764 /* Generate assembler code for constant parts of a trampoline. */
2767 microblaze_asm_trampoline_template (FILE *f)
2769 fprintf (f, "\t.word\t0x03e00821\t\t# move $1,$31\n");
2770 fprintf (f, "\t.word\t0x04110001\t\t# bgezal $0,.+8\n");
2771 fprintf (f, "\t.word\t0x00000000\t\t# nop\n");
2772 fprintf (f, "\t.word\t0x8fe30014\t\t# lw $3,20($31)\n");
2773 fprintf (f, "\t.word\t0x8fe20018\t\t# lw $2,24($31)\n");
2774 fprintf (f, "\t.word\t0x0060c821\t\t# move $25,$3 (abicalls)\n");
2775 fprintf (f, "\t.word\t0x00600008\t\t# jr $3\n");
2776 fprintf (f, "\t.word\t0x0020f821\t\t# move $31,$1\n");
2777 /* fprintf (f, "\t.word\t0x00000000\t\t# <function address>\n"); */
2778 /* fprintf (f, "\t.word\t0x00000000\t\t# <static chain value>\n"); */
2781 /* Implement TARGET_TRAMPOLINE_INIT. */
2784 microblaze_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
2786 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
2789 emit_block_move (m_tramp, assemble_trampoline_template (),
2790 GEN_INT (8*UNITS_PER_WORD), BLOCK_OP_NORMAL);
2792 mem = adjust_address (m_tramp, SImode, 8);
2793 emit_move_insn (mem, chain_value);
2794 mem = adjust_address (m_tramp, SImode, 12);
2795 emit_move_insn (mem, fnaddr);
2798 /* Emit instruction to perform compare.
2799 cmp is (compare_op op0 op1). */
2801 microblaze_emit_compare (enum machine_mode mode, rtx cmp, enum rtx_code *cmp_code)
2803 rtx cmp_op0 = XEXP (cmp, 0);
2804 rtx cmp_op1 = XEXP (cmp, 1);
2805 rtx comp_reg = gen_reg_rtx (SImode);
2806 enum rtx_code code = *cmp_code;
2808 gcc_assert ((GET_CODE (cmp_op0) == REG) || (GET_CODE (cmp_op0) == SUBREG));
2810 /* If comparing against zero, just test source reg. */
2811 if (cmp_op1 == const0_rtx)
2814 if (code == EQ || code == NE)
2816 if (TARGET_PATTERN_COMPARE && GET_CODE(cmp_op1) == REG)
2819 emit_insn (gen_seq_internal_pat (comp_reg, cmp_op0, cmp_op1));
2822 emit_insn (gen_sne_internal_pat (comp_reg, cmp_op0, cmp_op1));
2827 /* Use xor for equal/not-equal comparison. */
2828 emit_insn (gen_xorsi3 (comp_reg, cmp_op0, cmp_op1));
2830 else if (code == GT || code == GTU || code == LE || code == LEU)
2832 /* MicroBlaze compare is not symmetrical. */
2833 /* Swap argument order. */
2834 cmp_op1 = force_reg (mode, cmp_op1);
2835 if (code == GT || code == LE)
2836 emit_insn (gen_signed_compare (comp_reg, cmp_op0, cmp_op1));
2838 emit_insn (gen_unsigned_compare (comp_reg, cmp_op0, cmp_op1));
2839 /* Translate test condition. */
2840 *cmp_code = swap_condition (code);
2842 else /* if (code == GE || code == GEU || code == LT || code == LTU) */
2844 cmp_op1 = force_reg (mode, cmp_op1);
2845 if (code == GE || code == LT)
2846 emit_insn (gen_signed_compare (comp_reg, cmp_op1, cmp_op0));
2848 emit_insn (gen_unsigned_compare (comp_reg, cmp_op1, cmp_op0));
2854 /* Generate conditional branch -- first, generate test condition,
2855 second, generate correct branch instruction. */
2858 microblaze_expand_conditional_branch (enum machine_mode mode, rtx operands[])
2860 enum rtx_code code = GET_CODE (operands[0]);
2864 comp = microblaze_emit_compare (mode, operands[0], &code);
2865 condition = gen_rtx_fmt_ee (signed_condition (code), SImode, comp, const0_rtx);
2866 emit_jump_insn (gen_condjump (condition, operands[3]));
2870 microblaze_expand_conditional_branch_sf (rtx operands[])
2873 rtx cmp_op0 = XEXP (operands[0], 0);
2874 rtx cmp_op1 = XEXP (operands[0], 1);
2875 rtx comp_reg = gen_reg_rtx (SImode);
2877 emit_insn (gen_cstoresf4 (comp_reg, operands[0], cmp_op0, cmp_op1));
2878 condition = gen_rtx_NE (SImode, comp_reg, const0_rtx);
2879 emit_jump_insn (gen_condjump (condition, operands[3]));
2882 /* Implement TARGET_FRAME_POINTER_REQUIRED. */
2885 microblaze_frame_pointer_required (void)
2887 /* If the function contains dynamic stack allocations, we need to
2888 use the frame pointer to access the static parts of the frame. */
2889 if (cfun->calls_alloca)
2895 microblaze_expand_divide (rtx operands[])
2897 /* Table lookup software divides. Works for all (nr/dr) where (0 <= nr,dr <= 15). */
2899 rtx regt1 = gen_reg_rtx (SImode);
2900 rtx reg18 = gen_rtx_REG (SImode, R_TMP);
2901 rtx regqi = gen_reg_rtx (QImode);
2902 rtx div_label = gen_label_rtx ();
2903 rtx div_end_label = gen_label_rtx ();
2904 rtx div_table_rtx = gen_rtx_SYMBOL_REF (QImode,"_divsi3_table");
2907 rtx jump, cjump, insn;
2909 insn = emit_insn (gen_iorsi3 (regt1, operands[1], operands[2]));
2910 cjump = emit_jump_insn_after (gen_cbranchsi4 (
2911 gen_rtx_GTU (SImode, regt1, GEN_INT (15)),
2912 regt1, GEN_INT (15), div_label), insn);
2913 LABEL_NUSES (div_label) = 1;
2914 JUMP_LABEL (cjump) = div_label;
2915 emit_insn (gen_rtx_CLOBBER (SImode, reg18));
2917 emit_insn (gen_ashlsi3_bshift (regt1, operands[1], GEN_INT(4)));
2918 emit_insn (gen_addsi3 (regt1, regt1, operands[2]));
2919 mem_rtx = gen_rtx_MEM (QImode,
2920 gen_rtx_PLUS (Pmode, regt1, div_table_rtx));
2922 insn = emit_insn (gen_movqi (regqi, mem_rtx));
2923 insn = emit_insn (gen_movsi (operands[0], gen_rtx_SUBREG (SImode, regqi, 0)));
2924 jump = emit_jump_insn_after (gen_jump (div_end_label), insn);
2925 JUMP_LABEL (jump) = div_end_label;
2926 LABEL_NUSES (div_end_label) = 1;
2929 emit_label (div_label);
2930 ret = emit_library_call_value (gen_rtx_SYMBOL_REF (Pmode, "__divsi3"),
2931 operands[0], LCT_NORMAL,
2932 GET_MODE (operands[0]), 2, operands[1],
2933 GET_MODE (operands[1]), operands[2],
2934 GET_MODE (operands[2]));
2935 if (ret != operands[0])
2936 emit_move_insn (operands[0], ret);
2938 emit_label (div_end_label);
2939 emit_insn (gen_blockage ());
2942 /* Implement TARGET_FUNCTION_VALUE. */
2944 microblaze_function_value (const_tree valtype,
2945 const_tree func ATTRIBUTE_UNUSED,
2946 bool outgoing ATTRIBUTE_UNUSED)
2948 return LIBCALL_VALUE (TYPE_MODE (valtype));
2951 /* Implement TARGET_SCHED_ADJUST_COST. */
2953 microblaze_adjust_cost (rtx insn ATTRIBUTE_UNUSED, rtx link,
2954 rtx dep ATTRIBUTE_UNUSED, int cost)
2956 if (REG_NOTE_KIND (link) == REG_DEP_OUTPUT)
2958 if (REG_NOTE_KIND (link) != 0)
2963 #undef TARGET_ENCODE_SECTION_INFO
2964 #define TARGET_ENCODE_SECTION_INFO microblaze_encode_section_info
2966 #undef TARGET_ASM_GLOBALIZE_LABEL
2967 #define TARGET_ASM_GLOBALIZE_LABEL microblaze_globalize_label
2969 #undef TARGET_ASM_FUNCTION_PROLOGUE
2970 #define TARGET_ASM_FUNCTION_PROLOGUE microblaze_function_prologue
2972 #undef TARGET_ASM_FUNCTION_EPILOGUE
2973 #define TARGET_ASM_FUNCTION_EPILOGUE microblaze_function_epilogue
2975 #undef TARGET_RTX_COSTS
2976 #define TARGET_RTX_COSTS microblaze_rtx_costs
2978 #undef TARGET_ADDRESS_COST
2979 #define TARGET_ADDRESS_COST microblaze_address_cost
2981 #undef TARGET_ATTRIBUTE_TABLE
2982 #define TARGET_ATTRIBUTE_TABLE microblaze_attribute_table
2984 #undef TARGET_IN_SMALL_DATA_P
2985 #define TARGET_IN_SMALL_DATA_P microblaze_elf_in_small_data_p
2987 #undef TARGET_ASM_SELECT_SECTION
2988 #define TARGET_ASM_SELECT_SECTION microblaze_select_section
2990 #undef TARGET_HAVE_SRODATA_SECTION
2991 #define TARGET_HAVE_SRODATA_SECTION true
2993 #undef TARGET_ASM_FUNCTION_END_PROLOGUE
2994 #define TARGET_ASM_FUNCTION_END_PROLOGUE \
2995 microblaze_function_end_prologue
2997 #undef TARGET_HANDLE_OPTION
2998 #define TARGET_HANDLE_OPTION microblaze_handle_option
3000 #undef TARGET_DEFAULT_TARGET_FLAGS
3001 #define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
3003 #undef TARGET_ARG_PARTIAL_BYTES
3004 #define TARGET_ARG_PARTIAL_BYTES function_arg_partial_bytes
3006 #undef TARGET_FUNCTION_ARG
3007 #define TARGET_FUNCTION_ARG microblaze_function_arg
3009 #undef TARGET_FUNCTION_ARG_ADVANCE
3010 #define TARGET_FUNCTION_ARG_ADVANCE microblaze_function_arg_advance
3012 #undef TARGET_CAN_ELIMINATE
3013 #define TARGET_CAN_ELIMINATE microblaze_can_eliminate
3015 #undef TARGET_LEGITIMIZE_ADDRESS
3016 #define TARGET_LEGITIMIZE_ADDRESS microblaze_legitimize_address
3018 #undef TARGET_LEGITIMATE_ADDRESS_P
3019 #define TARGET_LEGITIMATE_ADDRESS_P microblaze_legitimate_address_p
3021 #undef TARGET_FRAME_POINTER_REQUIRED
3022 #define TARGET_FRAME_POINTER_REQUIRED microblaze_frame_pointer_required
3024 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
3025 #define TARGET_ASM_TRAMPOLINE_TEMPLATE microblaze_asm_trampoline_template
3027 #undef TARGET_TRAMPOLINE_INIT
3028 #define TARGET_TRAMPOLINE_INIT microblaze_trampoline_init
3030 #undef TARGET_PROMOTE_FUNCTION_MODE
3031 #define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
3033 #undef TARGET_FUNCTION_VALUE
3034 #define TARGET_FUNCTION_VALUE microblaze_function_value
3036 #undef TARGET_SECONDARY_RELOAD
3037 #define TARGET_SECONDARY_RELOAD microblaze_secondary_reload
3039 #undef TARGET_SCHED_ADJUST_COST
3040 #define TARGET_SCHED_ADJUST_COST microblaze_adjust_cost
3042 #undef TARGET_ASM_INIT_SECTIONS
3043 #define TARGET_ASM_INIT_SECTIONS microblaze_elf_asm_init_sections
3045 #undef TARGET_OPTION_OVERRIDE
3046 #define TARGET_OPTION_OVERRIDE microblaze_option_override
3048 #undef TARGET_OPTION_OPTIMIZATION_TABLE
3049 #define TARGET_OPTION_OPTIMIZATION_TABLE microblaze_option_optimization_table
3051 #undef TARGET_EXCEPT_UNWIND_INFO
3052 #define TARGET_EXCEPT_UNWIND_INFO sjlj_except_unwind_info
3054 struct gcc_target targetm = TARGET_INITIALIZER;
3056 #include "gt-microblaze.h"