1 /* Subroutines used for code generation on Xilinx MicroBlaze.
2 Copyright (C) 2009-2013 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"
28 #include "hard-reg-set.h"
30 #include "insn-config.h"
31 #include "conditions.h"
32 #include "insn-flags.h"
33 #include "insn-attr.h"
44 #include "target-def.h"
49 #include "diagnostic-core.h"
52 #define MICROBLAZE_VERSION_COMPARE(VA,VB) strcasecmp (VA, VB)
54 /* Classifies an address.
61 A natural register or a register + const_int offset address.
62 The register satisfies microblaze_valid_base_register_p and the
63 offset is a const_arith_operand.
67 A natural register offset by the index contained in an index register. The base
68 register satisfies microblaze_valid_base_register_p and the index register
69 satisfies microblaze_valid_index_register_p
73 A signed 16/32-bit constant address.
77 A constant symbolic address or a (register + symbol). */
79 enum microblaze_address_type
95 enum microblaze_symbol_type
101 /* Classification of a MicroBlaze address. */
102 struct microblaze_address_info
104 enum microblaze_address_type type
;
105 rtx regA
; /* Contains valid values on ADDRESS_REG, ADDRESS_REG_INDEX,
107 rtx regB
; /* Contains valid values on ADDRESS_REG_INDEX. */
108 rtx offset
; /* Contains valid values on ADDRESS_CONST_INT and ADDRESS_REG. */
109 rtx symbol
; /* Contains valid values on ADDRESS_SYMBOLIC. */
110 enum microblaze_symbol_type symbol_type
;
113 /* Structure to be filled in by compute_frame_size with register
114 save masks, and offsets for the current function. */
116 struct GTY(()) microblaze_frame_info
{
117 long total_size
; /* # bytes that the entire frame takes up. */
118 long var_size
; /* # bytes that variables take up. */
119 long args_size
; /* # bytes that outgoing arguments take up. */
120 int link_debug_size
; /* # bytes for the link reg and back pointer. */
121 int gp_reg_size
; /* # bytes needed to store gp regs. */
122 long gp_offset
; /* offset from new sp to store gp registers. */
123 long mask
; /* mask of saved gp registers. */
124 int initialized
; /* != 0 if frame size already calculated. */
125 int num_gp
; /* number of gp registers saved. */
126 long insns_len
; /* length of insns. */
127 int alloc_stack
; /* Flag to indicate if the current function
128 must not create stack space. (As an optimization). */
131 /* Global variables for machine-dependent things. */
133 /* Toggle which pipleline interface to use. */
134 static GTY(()) int microblaze_sched_use_dfa
= 0;
136 /* Threshold for data being put into the small data/bss area, instead
137 of the normal data area (references to the small data/bss area take
138 1 instruction, and use the global pointer, references to the normal
139 data area takes 2 instructions). */
140 int microblaze_section_threshold
= -1;
142 /* Prevent scheduling potentially exception causing instructions in
143 delay slots. -mcpu=v3.00.a or v4.00.a turns this on. */
144 int microblaze_no_unsafe_delay
;
146 /* Set to one if the targeted core has the CLZ insn. */
147 int microblaze_has_clz
= 0;
149 /* Which CPU pipeline do we use. We haven't really standardized on a CPU
150 version having only a particular type of pipeline. There can still be
151 options on the CPU to scale pipeline features up or down. :(
152 Bad Presentation (??), so we let the MD file rely on the value of
153 this variable instead Making PIPE_5 the default. It should be backward
154 optimal with PIPE_3 MicroBlazes. */
155 enum pipeline_type microblaze_pipe
= MICROBLAZE_PIPE_5
;
157 /* High and low marks for floating point values which we will accept
158 as legitimate constants for TARGET_LEGITIMATE_CONSTANT_P. These are
159 initialized in override_options. */
160 REAL_VALUE_TYPE dfhigh
, dflow
, sfhigh
, sflow
;
162 /* Array giving truth value on whether or not a given hard register
163 can support a given mode. */
164 char microblaze_hard_regno_mode_ok
[(int)MAX_MACHINE_MODE
]
165 [FIRST_PSEUDO_REGISTER
];
167 /* Current frame information calculated by compute_frame_size. */
168 struct microblaze_frame_info current_frame_info
;
170 /* Zero structure to initialize current_frame_info. */
171 struct microblaze_frame_info zero_frame_info
;
173 /* List of all MICROBLAZE punctuation characters used by print_operand. */
174 char microblaze_print_operand_punct
[256];
176 /* Map GCC register number to debugger register number. */
177 int microblaze_dbx_regno
[FIRST_PSEUDO_REGISTER
];
179 /* Map hard register number to register class. */
180 enum reg_class microblaze_regno_to_class
[] =
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 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
190 ST_REGS
, GR_REGS
, GR_REGS
, GR_REGS
193 /* MicroBlaze specific machine attributes.
194 interrupt_handler - Interrupt handler attribute to add interrupt prologue
195 and epilogue and use appropriate interrupt return.
196 save_volatiles - Similar to interrupt handler, but use normal return. */
197 int interrupt_handler
;
201 const struct attribute_spec microblaze_attribute_table
[] = {
202 /* name min_len, max_len, decl_req, type_req, fn_type, req_handler,
203 affects_type_identity */
204 {"interrupt_handler", 0, 0, true, false, false, NULL
,
206 {"fast_interrupt", 0, 0, true, false, false, NULL
,
208 {"save_volatiles" , 0, 0, true, false, false, NULL
,
210 { NULL
, 0, 0, false, false, false, NULL
,
214 static int microblaze_interrupt_function_p (tree
);
216 section
*sdata2_section
;
218 /* Return truth value if a CONST_DOUBLE is ok to be a legitimate constant. */
220 microblaze_const_double_ok (rtx op
, enum machine_mode mode
)
224 if (GET_CODE (op
) != CONST_DOUBLE
)
227 if (GET_MODE (op
) == VOIDmode
)
230 if (mode
!= SFmode
&& mode
!= DFmode
)
233 if (op
== CONST0_RTX (mode
))
236 REAL_VALUE_FROM_CONST_DOUBLE (d
, op
);
238 if (REAL_VALUE_ISNAN (d
))
241 if (REAL_VALUE_NEGATIVE (d
))
242 d
= real_value_negate (&d
);
246 if (REAL_VALUES_LESS (d
, dfhigh
) && REAL_VALUES_LESS (dflow
, d
))
251 if (REAL_VALUES_LESS (d
, sfhigh
) && REAL_VALUES_LESS (sflow
, d
))
258 /* Return truth value if a memory operand fits in a single instruction
259 (ie, register + small offset) or (register + register). */
262 simple_memory_operand (rtx op
, enum machine_mode mode ATTRIBUTE_UNUSED
)
264 rtx addr
, plus0
, plus1
;
266 /* Eliminate non-memory operations. */
267 if (GET_CODE (op
) != MEM
)
270 /* dword operations really put out 2 instructions, so eliminate them. */
271 /* ??? This isn't strictly correct. It is OK to accept multiword modes
272 here, since the length attributes are being set correctly, but only
273 if the address is offsettable. */
274 if (GET_MODE_SIZE (GET_MODE (op
)) > UNITS_PER_WORD
)
278 /* Decode the address now. */
280 switch (GET_CODE (addr
))
287 plus0
= XEXP (addr
, 0);
288 plus1
= XEXP (addr
, 1);
290 if (GET_CODE (plus0
) == REG
&& GET_CODE (plus1
) == CONST_INT
291 && SMALL_INT (plus1
))
295 else if (GET_CODE (plus1
) == REG
&& GET_CODE (plus0
) == CONST_INT
)
299 else if (GET_CODE (plus0
) == REG
&& GET_CODE (plus1
) == REG
)
316 /* Return nonzero for a memory address that can be used to load or store
320 double_memory_operand (rtx op
, enum machine_mode mode
)
324 if (GET_CODE (op
) != MEM
|| !memory_operand (op
, mode
))
326 /* During reload, we accept a pseudo register if it has an
327 appropriate memory address. If we don't do this, we will
328 wind up reloading into a register, and then reloading that
329 register from memory, when we could just reload directly from
331 if (reload_in_progress
332 && GET_CODE (op
) == REG
333 && REGNO (op
) >= FIRST_PSEUDO_REGISTER
334 && reg_renumber
[REGNO (op
)] < 0
335 && reg_equiv_mem (REGNO (op
)) != 0
336 && double_memory_operand (reg_equiv_mem (REGNO (op
)), mode
))
341 /* Make sure that 4 added to the address is a valid memory address.
342 This essentially just checks for overflow in an added constant. */
346 if (CONSTANT_ADDRESS_P (addr
))
349 return memory_address_p ((GET_MODE_CLASS (mode
) == MODE_INT
351 plus_constant (Pmode
, addr
, 4));
354 /* Implement REG_OK_FOR_BASE_P -and- REG_OK_FOR_INDEX_P. */
356 microblaze_regno_ok_for_base_p (int regno
, int strict
)
358 if (regno
>= FIRST_PSEUDO_REGISTER
)
362 regno
= reg_renumber
[regno
];
365 /* These fake registers will be eliminated to either the stack or
366 hard frame pointer, both of which are usually valid base registers.
367 Reload deals with the cases where the eliminated form isn't valid. */
368 if (regno
== ARG_POINTER_REGNUM
|| regno
== FRAME_POINTER_REGNUM
)
371 return GP_REG_P (regno
);
374 /* Return true if X is a valid base register for the given mode.
375 Allow only hard registers if STRICT. */
378 microblaze_valid_base_register_p (rtx x
,
379 enum machine_mode mode ATTRIBUTE_UNUSED
,
382 if (!strict
&& GET_CODE (x
) == SUBREG
)
385 return (GET_CODE (x
) == REG
386 && microblaze_regno_ok_for_base_p (REGNO (x
), strict
));
390 microblaze_classify_unspec (struct microblaze_address_info
*info
, rtx x
)
392 info
->symbol_type
= SYMBOL_TYPE_GENERAL
;
393 info
->symbol
= XVECEXP (x
, 0, 0);
395 if (XINT (x
, 1) == UNSPEC_GOTOFF
)
397 info
->regA
= gen_rtx_REG (SImode
, PIC_OFFSET_TABLE_REGNUM
);
398 info
->type
= ADDRESS_GOTOFF
;
400 else if (XINT (x
, 1) == UNSPEC_PLT
)
402 info
->type
= ADDRESS_PLT
;
412 /* Return true if X is a valid index register for the given mode.
413 Allow only hard registers if STRICT. */
416 microblaze_valid_index_register_p (rtx x
,
417 enum machine_mode mode ATTRIBUTE_UNUSED
,
420 if (!strict
&& GET_CODE (x
) == SUBREG
)
423 return (GET_CODE (x
) == REG
424 /* A base register is good enough to be an index register on MicroBlaze. */
425 && microblaze_regno_ok_for_base_p (REGNO (x
), strict
));
428 /* Get the base register for accessing a value from the memory or
429 Symbol ref. Used for MicroBlaze Small Data Area Pointer Optimization. */
434 int base_reg
= (flag_pic
? MB_ABI_PIC_ADDR_REGNUM
: MB_ABI_BASE_REGNUM
);
437 && GET_CODE (x
) == SYMBOL_REF
438 && SYMBOL_REF_SMALL_P (x
) && (decl
= SYMBOL_REF_DECL (x
)) != NULL
)
440 if (TREE_READONLY (decl
))
441 base_reg
= MB_ABI_GPRO_REGNUM
;
443 base_reg
= MB_ABI_GPRW_REGNUM
;
449 /* Return true if X is a valid address for machine mode MODE. If it is,
450 fill in INFO appropriately. STRICT is true if we should only accept
453 type regA regB offset symbol
455 ADDRESS_INVALID NULL NULL NULL NULL
457 ADDRESS_REG %0 NULL const_0 / NULL
459 ADDRESS_REG_INDEX %0 %1 NULL NULL
461 ADDRESS_SYMBOLIC r0 / NULL NULL symbol
464 ADDRESS_CONST_INT r0 NULL const NULL
466 For modes spanning multiple registers (DFmode in 32-bit GPRs,
467 DImode, TImode), indexed addressing cannot be used because
468 adjacent memory cells are accessed by adding word-sized offsets
469 during assembly output. */
472 microblaze_classify_address (struct microblaze_address_info
*info
, rtx x
,
473 enum machine_mode mode
, int strict
)
478 info
->type
= ADDRESS_INVALID
;
483 info
->symbol_type
= SYMBOL_TYPE_INVALID
;
485 switch (GET_CODE (x
))
490 info
->type
= ADDRESS_REG
;
492 info
->offset
= const0_rtx
;
493 return microblaze_valid_base_register_p (info
->regA
, mode
, strict
);
497 xplus0
= XEXP (x
, 0);
498 xplus1
= XEXP (x
, 1);
500 if (microblaze_valid_base_register_p (xplus0
, mode
, strict
))
502 info
->type
= ADDRESS_REG
;
505 if (GET_CODE (xplus1
) == CONST_INT
)
507 info
->offset
= xplus1
;
510 else if (GET_CODE (xplus1
) == UNSPEC
)
512 return microblaze_classify_unspec (info
, xplus1
);
514 else if ((GET_CODE (xplus1
) == SYMBOL_REF
||
515 GET_CODE (xplus1
) == LABEL_REF
) && flag_pic
== 2)
519 else if (GET_CODE (xplus1
) == SYMBOL_REF
||
520 GET_CODE (xplus1
) == LABEL_REF
||
521 GET_CODE (xplus1
) == CONST
)
523 if (GET_CODE (XEXP (xplus1
, 0)) == UNSPEC
)
524 return microblaze_classify_unspec (info
, XEXP (xplus1
, 0));
525 else if (flag_pic
== 2)
529 info
->type
= ADDRESS_SYMBOLIC
;
530 info
->symbol
= xplus1
;
531 info
->symbol_type
= SYMBOL_TYPE_GENERAL
;
534 else if (GET_CODE (xplus1
) == REG
535 && microblaze_valid_index_register_p (xplus1
, mode
,
537 && (GET_MODE_SIZE (mode
) <= UNITS_PER_WORD
))
539 /* Restrict larger than word-width modes from using an index register. */
540 info
->type
= ADDRESS_REG_INDEX
;
549 info
->regA
= gen_rtx_raw_REG (mode
, 0);
550 info
->type
= ADDRESS_CONST_INT
;
558 info
->type
= ADDRESS_SYMBOLIC
;
559 info
->symbol_type
= SYMBOL_TYPE_GENERAL
;
561 info
->regA
= gen_rtx_raw_REG (mode
, get_base_reg (x
));
563 if (GET_CODE (x
) == CONST
)
565 return !(flag_pic
&& pic_address_needs_scratch (x
));
567 else if (flag_pic
== 2)
577 if (reload_in_progress
)
578 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
579 return microblaze_classify_unspec (info
, x
);
589 /* This function is used to implement GO_IF_LEGITIMATE_ADDRESS. It
590 returns a nonzero value if X is a legitimate address for a memory
591 operand of the indicated MODE. STRICT is nonzero if this function
592 is called during reload. */
595 microblaze_legitimate_address_p (enum machine_mode mode
, rtx x
, bool strict
)
597 struct microblaze_address_info addr
;
599 return microblaze_classify_address (&addr
, x
, mode
, strict
);
603 microblaze_valid_pic_const (rtx x
)
605 switch (GET_CODE (x
))
617 microblaze_legitimate_pic_operand (rtx x
)
619 struct microblaze_address_info addr
;
621 if (pic_address_needs_scratch (x
))
623 if (!microblaze_valid_pic_const(x
))
629 /* Try machine-dependent ways of modifying an illegitimate address
630 to be legitimate. If we find one, return the new, valid address.
631 This is used from only one place: `memory_address' in explow.c.
633 OLDX is the address as it was before break_out_memory_refs was
634 called. In some cases it is useful to look at this to decide what
637 It is always safe for this function to do nothing. It exists to
638 recognize opportunities to optimize the output.
640 For the MicroBlaze, transform:
642 memory(X + <large int>)
646 Y = <large int> & ~0x7fff;
648 memory (Z + (<large int> & 0x7fff));
650 This is for CSE to find several similar references, and only use one Z.
652 When PIC, convert addresses of the form memory (symbol+large int) to
653 memory (reg+large int). */
656 microblaze_legitimize_address (rtx x
, rtx oldx ATTRIBUTE_UNUSED
,
657 enum machine_mode mode ATTRIBUTE_UNUSED
)
659 register rtx xinsn
= x
, result
;
661 if (GET_CODE (xinsn
) == CONST
662 && flag_pic
&& pic_address_needs_scratch (xinsn
))
664 rtx ptr_reg
= gen_reg_rtx (Pmode
);
665 rtx constant
= XEXP (XEXP (xinsn
, 0), 1);
667 emit_move_insn (ptr_reg
, XEXP (XEXP (xinsn
, 0), 0));
669 result
= gen_rtx_PLUS (Pmode
, ptr_reg
, constant
);
670 if (SMALL_INT (constant
))
672 /* Otherwise we fall through so the code below will fix the
677 if (GET_CODE (xinsn
) == PLUS
)
679 register rtx xplus0
= XEXP (xinsn
, 0);
680 register rtx xplus1
= XEXP (xinsn
, 1);
681 register enum rtx_code code0
= GET_CODE (xplus0
);
682 register enum rtx_code code1
= GET_CODE (xplus1
);
684 if (code0
!= REG
&& code1
== REG
)
686 xplus0
= XEXP (xinsn
, 1);
687 xplus1
= XEXP (xinsn
, 0);
688 code0
= GET_CODE (xplus0
);
689 code1
= GET_CODE (xplus1
);
692 if (code0
== REG
&& REG_OK_FOR_BASE_P (xplus0
)
693 && code1
== CONST_INT
&& !SMALL_INT (xplus1
))
695 rtx int_reg
= gen_reg_rtx (Pmode
);
696 rtx ptr_reg
= gen_reg_rtx (Pmode
);
698 emit_move_insn (int_reg
, GEN_INT (INTVAL (xplus1
) & ~0x7fff));
700 emit_insn (gen_rtx_SET (VOIDmode
,
702 gen_rtx_PLUS (Pmode
, xplus0
, int_reg
)));
704 result
= gen_rtx_PLUS (Pmode
, ptr_reg
,
705 GEN_INT (INTVAL (xplus1
) & 0x7fff));
709 if (code0
== REG
&& REG_OK_FOR_BASE_P (xplus0
) && flag_pic
== 2)
711 if (reload_in_progress
)
712 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
715 xplus1
= XEXP (xplus1
, 0);
716 code1
= GET_CODE (xplus1
);
718 if (code1
== SYMBOL_REF
)
721 gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, xplus1
), UNSPEC_GOTOFF
);
722 result
= gen_rtx_CONST (Pmode
, result
);
723 result
= gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
, result
);
724 result
= gen_const_mem (Pmode
, result
);
725 result
= gen_rtx_PLUS (Pmode
, xplus0
, result
);
731 if (GET_CODE (xinsn
) == SYMBOL_REF
)
733 if (reload_in_progress
)
734 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
735 result
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, xinsn
), UNSPEC_GOTOFF
);
736 result
= gen_rtx_CONST (Pmode
, result
);
737 result
= gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
, result
);
738 result
= gen_const_mem (Pmode
, result
);
747 #define MAX_MOVE_REGS 8
748 #define MAX_MOVE_BYTES (MAX_MOVE_REGS * UNITS_PER_WORD)
750 /* Emit straight-line code to move LENGTH bytes from SRC to DEST.
751 Assume that the areas do not overlap. */
754 microblaze_block_move_straight (rtx dest
, rtx src
, HOST_WIDE_INT length
)
756 HOST_WIDE_INT offset
, delta
;
757 unsigned HOST_WIDE_INT bits
;
759 enum machine_mode mode
;
762 bits
= BITS_PER_WORD
;
763 mode
= mode_for_size (bits
, MODE_INT
, 0);
764 delta
= bits
/ BITS_PER_UNIT
;
766 /* Allocate a buffer for the temporary registers. */
767 regs
= XALLOCAVEC (rtx
, length
/ delta
);
769 /* Load as many BITS-sized chunks as possible. Use a normal load if
770 the source has enough alignment, otherwise use left/right pairs. */
771 for (offset
= 0, i
= 0; offset
+ delta
<= length
; offset
+= delta
, i
++)
773 regs
[i
] = gen_reg_rtx (mode
);
774 emit_move_insn (regs
[i
], adjust_address (src
, mode
, offset
));
777 /* Copy the chunks to the destination. */
778 for (offset
= 0, i
= 0; offset
+ delta
<= length
; offset
+= delta
, i
++)
779 emit_move_insn (adjust_address (dest
, mode
, offset
), regs
[i
]);
781 /* Mop up any left-over bytes. */
784 src
= adjust_address (src
, BLKmode
, offset
);
785 dest
= adjust_address (dest
, BLKmode
, offset
);
786 move_by_pieces (dest
, src
, length
- offset
,
787 MIN (MEM_ALIGN (src
), MEM_ALIGN (dest
)), 0);
791 /* Helper function for doing a loop-based block operation on memory
792 reference MEM. Each iteration of the loop will operate on LENGTH
795 Create a new base register for use within the loop and point it to
796 the start of MEM. Create a new memory reference that uses this
797 register. Store them in *LOOP_REG and *LOOP_MEM respectively. */
800 microblaze_adjust_block_mem (rtx mem
, HOST_WIDE_INT length
,
801 rtx
* loop_reg
, rtx
* loop_mem
)
803 *loop_reg
= copy_addr_to_reg (XEXP (mem
, 0));
805 /* Although the new mem does not refer to a known location,
806 it does keep up to LENGTH bytes of alignment. */
807 *loop_mem
= change_address (mem
, BLKmode
, *loop_reg
);
808 set_mem_align (*loop_mem
,
809 MIN ((HOST_WIDE_INT
) MEM_ALIGN (mem
),
810 length
* BITS_PER_UNIT
));
814 /* Move LENGTH bytes from SRC to DEST using a loop that moves MAX_MOVE_BYTES
815 per iteration. LENGTH must be at least MAX_MOVE_BYTES. Assume that the
816 memory regions do not overlap. */
819 microblaze_block_move_loop (rtx dest
, rtx src
, HOST_WIDE_INT length
)
821 rtx label
, src_reg
, dest_reg
, final_src
;
822 HOST_WIDE_INT leftover
;
824 leftover
= length
% MAX_MOVE_BYTES
;
827 /* Create registers and memory references for use within the loop. */
828 microblaze_adjust_block_mem (src
, MAX_MOVE_BYTES
, &src_reg
, &src
);
829 microblaze_adjust_block_mem (dest
, MAX_MOVE_BYTES
, &dest_reg
, &dest
);
831 /* Calculate the value that SRC_REG should have after the last iteration
833 final_src
= expand_simple_binop (Pmode
, PLUS
, src_reg
, GEN_INT (length
),
836 /* Emit the start of the loop. */
837 label
= gen_label_rtx ();
840 /* Emit the loop body. */
841 microblaze_block_move_straight (dest
, src
, MAX_MOVE_BYTES
);
843 /* Move on to the next block. */
844 emit_move_insn (src_reg
, plus_constant (Pmode
, src_reg
, MAX_MOVE_BYTES
));
845 emit_move_insn (dest_reg
, plus_constant (Pmode
, dest_reg
, MAX_MOVE_BYTES
));
847 /* Emit the test & branch. */
848 emit_insn (gen_cbranchsi4 (gen_rtx_NE (SImode
, src_reg
, final_src
),
849 src_reg
, final_src
, label
));
851 /* Mop up any left-over bytes. */
853 microblaze_block_move_straight (dest
, src
, leftover
);
856 /* Expand a movmemsi instruction. */
859 microblaze_expand_block_move (rtx dest
, rtx src
, rtx length
, rtx align_rtx
)
862 if (GET_CODE (length
) == CONST_INT
)
864 HOST_WIDE_INT bytes
= INTVAL (length
);
865 int align
= INTVAL (align_rtx
);
867 if (align
> UNITS_PER_WORD
)
869 align
= UNITS_PER_WORD
; /* We can't do any better. */
871 else if (align
< UNITS_PER_WORD
)
873 if (INTVAL (length
) <= MAX_MOVE_BYTES
)
875 move_by_pieces (dest
, src
, bytes
, align
, 0);
882 if (INTVAL (length
) <= 2 * MAX_MOVE_BYTES
)
884 microblaze_block_move_straight (dest
, src
, INTVAL (length
));
889 microblaze_block_move_loop (dest
, src
, INTVAL (length
));
897 microblaze_rtx_costs (rtx x
, int code
, int outer_code ATTRIBUTE_UNUSED
,
898 int opno ATTRIBUTE_UNUSED
, int *total
,
899 bool speed ATTRIBUTE_UNUSED
)
901 enum machine_mode mode
= GET_MODE (x
);
907 int num_words
= (GET_MODE_SIZE (mode
) > UNITS_PER_WORD
) ? 2 : 1;
908 if (simple_memory_operand (x
, mode
))
909 *total
= COSTS_N_INSNS (2 * num_words
);
911 *total
= COSTS_N_INSNS (2 * (2 * num_words
));
919 *total
= COSTS_N_INSNS (2);
922 *total
= COSTS_N_INSNS (1);
931 *total
= COSTS_N_INSNS (2);
934 *total
= COSTS_N_INSNS (1);
942 if (TARGET_BARREL_SHIFT
)
944 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v5.00.a")
946 *total
= COSTS_N_INSNS (1);
948 *total
= COSTS_N_INSNS (2);
950 else if (!TARGET_SOFT_MUL
)
951 *total
= COSTS_N_INSNS (1);
952 else if (GET_CODE (XEXP (x
, 1)) == CONST_INT
)
954 /* Add 1 to make shift slightly more expensive than add. */
955 *total
= COSTS_N_INSNS (INTVAL (XEXP (x
, 1))) + 1;
956 /* Reduce shift costs for special circumstances. */
957 if (optimize_size
&& INTVAL (XEXP (x
, 1)) > 5)
959 if (!optimize_size
&& INTVAL (XEXP (x
, 1)) > 17)
963 /* Double the worst cost of shifts when there is no barrel shifter and
964 the shift amount is in a reg. */
965 *total
= COSTS_N_INSNS (32 * 4);
971 if (mode
== SFmode
|| mode
== DFmode
)
973 if (TARGET_HARD_FLOAT
)
974 *total
= COSTS_N_INSNS (6);
977 else if (mode
== DImode
)
979 *total
= COSTS_N_INSNS (4);
984 *total
= COSTS_N_INSNS (1);
993 *total
= COSTS_N_INSNS (4);
1001 if (TARGET_HARD_FLOAT
)
1002 *total
= COSTS_N_INSNS (6);
1004 else if (!TARGET_SOFT_MUL
)
1006 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v5.00.a")
1008 *total
= COSTS_N_INSNS (1);
1010 *total
= COSTS_N_INSNS (3);
1013 *total
= COSTS_N_INSNS (10);
1021 if (TARGET_HARD_FLOAT
)
1022 *total
= COSTS_N_INSNS (23);
1028 *total
= COSTS_N_INSNS (1);
1033 *total
= COSTS_N_INSNS (1);
1041 /* Return the number of instructions needed to load or store a value
1042 of mode MODE at X. Return 0 if X isn't valid for MODE. */
1045 microblaze_address_insns (rtx x
, enum machine_mode mode
)
1047 struct microblaze_address_info addr
;
1049 if (microblaze_classify_address (&addr
, x
, mode
, false))
1054 if (SMALL_INT (addr
.offset
))
1058 case ADDRESS_CONST_INT
:
1063 case ADDRESS_REG_INDEX
:
1064 case ADDRESS_SYMBOLIC
:
1066 case ADDRESS_GOTOFF
:
1075 /* Provide the costs of an addressing mode that contains ADDR.
1076 If ADDR is not a valid address, its cost is irrelevant. */
1078 microblaze_address_cost (rtx addr
, enum machine_mode mode ATTRIBUTE_UNUSED
,
1079 addr_space_t as ATTRIBUTE_UNUSED
,
1080 bool speed ATTRIBUTE_UNUSED
)
1082 return COSTS_N_INSNS (microblaze_address_insns (addr
, GET_MODE (addr
)));
1085 /* Return nonzero if X is an address which needs a temporary register when
1086 reloaded while generating PIC code. */
1089 pic_address_needs_scratch (rtx x
)
1091 /* An address which is a symbolic plus a non SMALL_INT needs a temp reg. */
1092 if (GET_CODE (x
) == CONST
&& GET_CODE (XEXP (x
, 0)) == PLUS
1093 && GET_CODE (XEXP (XEXP (x
, 0), 0)) == SYMBOL_REF
1094 && GET_CODE (XEXP (XEXP (x
, 0), 1)) == CONST_INT
1095 && (flag_pic
== 2 || !SMALL_INT (XEXP (XEXP (x
, 0), 1))))
1101 /* Argument support functions. */
1102 /* Initialize CUMULATIVE_ARGS for a function. */
1105 init_cumulative_args (CUMULATIVE_ARGS
* cum
, tree fntype
,
1106 rtx libname ATTRIBUTE_UNUSED
)
1108 static CUMULATIVE_ARGS zero_cum
;
1109 tree param
, next_param
;
1113 /* Determine if this function has variable arguments. This is
1114 indicated by the last argument being 'void_type_mode' if there
1115 are no variable arguments. The standard MicroBlaze calling sequence
1116 passes all arguments in the general purpose registers in this case. */
1118 for (param
= fntype
? TYPE_ARG_TYPES (fntype
) : 0;
1119 param
!= 0; param
= next_param
)
1121 next_param
= TREE_CHAIN (param
);
1122 if (next_param
== 0 && TREE_VALUE (param
) != void_type_node
)
1123 cum
->gp_reg_found
= 1;
1127 /* Advance the argument to the next argument position. */
1130 microblaze_function_arg_advance (cumulative_args_t cum_v
,
1131 enum machine_mode mode
,
1132 const_tree type
, bool named ATTRIBUTE_UNUSED
)
1134 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
1143 gcc_assert (GET_MODE_CLASS (mode
) == MODE_COMPLEX_INT
1144 || GET_MODE_CLASS (mode
) == MODE_COMPLEX_FLOAT
);
1146 cum
->gp_reg_found
= 1;
1147 cum
->arg_words
+= ((GET_MODE_SIZE (mode
) + UNITS_PER_WORD
- 1)
1152 cum
->gp_reg_found
= 1;
1153 cum
->arg_words
+= ((int_size_in_bytes (type
) + UNITS_PER_WORD
- 1)
1159 if (!cum
->gp_reg_found
&& cum
->arg_number
<= 2)
1160 cum
->fp_code
+= 1 << ((cum
->arg_number
- 1) * 2);
1164 cum
->arg_words
+= 2;
1165 if (!cum
->gp_reg_found
&& cum
->arg_number
<= 2)
1166 cum
->fp_code
+= 2 << ((cum
->arg_number
- 1) * 2);
1170 cum
->gp_reg_found
= 1;
1171 cum
->arg_words
+= 2;
1178 cum
->gp_reg_found
= 1;
1184 /* Return an RTL expression containing the register for the given mode,
1185 or 0 if the argument is to be passed on the stack. */
1188 microblaze_function_arg (cumulative_args_t cum_v
, enum machine_mode mode
,
1189 const_tree type ATTRIBUTE_UNUSED
,
1190 bool named ATTRIBUTE_UNUSED
)
1192 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
1196 int *arg_words
= &cum
->arg_words
;
1198 cum
->last_arg_fp
= 0;
1209 regbase
= GP_ARG_FIRST
;
1212 gcc_assert (GET_MODE_CLASS (mode
) == MODE_COMPLEX_INT
1213 || GET_MODE_CLASS (mode
) == MODE_COMPLEX_FLOAT
);
1214 /* Drops through. */
1216 regbase
= GP_ARG_FIRST
;
1220 if (*arg_words
>= MAX_ARGS_IN_REGISTERS
)
1224 gcc_assert (regbase
!= -1);
1226 ret
= gen_rtx_REG (mode
, regbase
+ *arg_words
);
1229 if (mode
== VOIDmode
)
1231 if (cum
->num_adjusts
> 0)
1232 ret
= gen_rtx_PARALLEL ((enum machine_mode
) cum
->fp_code
,
1233 gen_rtvec_v (cum
->num_adjusts
, cum
->adjust
));
1239 /* Return number of bytes of argument to put in registers. */
1241 function_arg_partial_bytes (cumulative_args_t cum_v
, enum machine_mode mode
,
1242 tree type
, bool named ATTRIBUTE_UNUSED
)
1244 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
1246 if ((mode
== BLKmode
1247 || GET_MODE_CLASS (mode
) != MODE_COMPLEX_INT
1248 || GET_MODE_CLASS (mode
) != MODE_COMPLEX_FLOAT
)
1249 && cum
->arg_words
< MAX_ARGS_IN_REGISTERS
)
1252 if (mode
== BLKmode
)
1253 words
= ((int_size_in_bytes (type
) + UNITS_PER_WORD
- 1)
1256 words
= (GET_MODE_SIZE (mode
) + UNITS_PER_WORD
- 1) / UNITS_PER_WORD
;
1258 if (words
+ cum
->arg_words
<= MAX_ARGS_IN_REGISTERS
)
1259 return 0; /* structure fits in registers */
1261 return (MAX_ARGS_IN_REGISTERS
- cum
->arg_words
) * UNITS_PER_WORD
;
1264 else if (mode
== DImode
&& cum
->arg_words
== MAX_ARGS_IN_REGISTERS
- 1)
1265 return UNITS_PER_WORD
;
1270 /* Convert a version number of the form "vX.YY.Z" to an integer encoding
1271 for easier range comparison. */
1273 microblaze_version_to_int (const char *version
)
1276 const char *tmpl
= "vX.YY.Z";
1285 { /* Looking for major */
1286 if (!(*p
>= '0' && *p
<= '9'))
1288 iver
+= (int) (*p
- '0');
1292 { /* Looking for minor */
1293 if (!(*p
>= '0' && *p
<= '9'))
1295 iver
+= (int) (*p
- '0');
1299 { /* Looking for compat */
1300 if (!(*p
>= 'a' && *p
<= 'z'))
1303 iver
+= (int) (*p
- 'a');
1323 microblaze_option_override (void)
1325 register int i
, start
;
1327 register enum machine_mode mode
;
1330 microblaze_section_threshold
= (global_options_set
.x_g_switch_value
1332 : MICROBLAZE_DEFAULT_GVALUE
);
1336 /* Make sure it's 2, we only support one kind of PIC. */
1338 if (!TARGET_SUPPORTS_PIC
)
1340 error ("-fPIC/-fpic not supported for this target");
1341 /* Clear it to avoid further errors. */
1346 /* Check the MicroBlaze CPU version for any special action to be done. */
1347 if (microblaze_select_cpu
== NULL
)
1348 microblaze_select_cpu
= MICROBLAZE_DEFAULT_CPU
;
1349 ver
= microblaze_version_to_int (microblaze_select_cpu
);
1352 error ("%qs is an invalid argument to -mcpu=", microblaze_select_cpu
);
1355 ver
= MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v3.00.a");
1358 /* No hardware exceptions in earlier versions. So no worries. */
1360 microblaze_select_flags
&= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY
);
1362 microblaze_no_unsafe_delay
= 0;
1363 microblaze_pipe
= MICROBLAZE_PIPE_3
;
1366 || (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v4.00.b")
1370 microblaze_select_flags
|= (MICROBLAZE_MASK_NO_UNSAFE_DELAY
);
1372 microblaze_no_unsafe_delay
= 1;
1373 microblaze_pipe
= MICROBLAZE_PIPE_3
;
1377 /* We agree to use 5 pipe-stage model even on area optimized 3
1378 pipe-stage variants. */
1380 microblaze_select_flags
&= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY
);
1382 microblaze_no_unsafe_delay
= 0;
1383 microblaze_pipe
= MICROBLAZE_PIPE_5
;
1384 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v5.00.a") == 0
1385 || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
,
1387 || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
,
1390 /* Pattern compares are to be turned on by default only when
1391 compiling for MB v5.00.'z'. */
1392 target_flags
|= MASK_PATTERN_COMPARE
;
1396 ver
= MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v6.00.a");
1399 if (TARGET_MULTIPLY_HIGH
)
1401 "-mxl-multiply-high can be used only with -mcpu=v6.00.a or greater");
1404 ver
= MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v8.10.a");
1405 microblaze_has_clz
= 1;
1408 /* MicroBlaze prior to 8.10.a didn't have clz. */
1409 microblaze_has_clz
= 0;
1412 /* TARGET_REORDER defaults to 2 if -mxl-reorder not specified. */
1413 ver
= MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v8.30.a");
1416 if (TARGET_REORDER
== 1)
1417 warning (0, "-mxl-reorder can be used only with -mcpu=v8.30.a or greater");
1420 else if ((ver
== 0) && !TARGET_PATTERN_COMPARE
)
1422 if (TARGET_REORDER
== 1)
1423 warning (0, "-mxl-reorder requires -mxl-pattern-compare for -mcpu=v8.30.a");
1427 if (TARGET_MULTIPLY_HIGH
&& TARGET_SOFT_MUL
)
1428 error ("-mxl-multiply-high requires -mno-xl-soft-mul");
1430 /* Always use DFA scheduler. */
1431 microblaze_sched_use_dfa
= 1;
1434 microblaze_abicalls
= MICROBLAZE_ABICALLS_NO
;
1437 /* Initialize the high, low values for legit floating point constants. */
1438 real_maxval (&dfhigh
, 0, DFmode
);
1439 real_maxval (&dflow
, 1, DFmode
);
1440 real_maxval (&sfhigh
, 0, SFmode
);
1441 real_maxval (&sflow
, 1, SFmode
);
1443 microblaze_print_operand_punct
['?'] = 1;
1444 microblaze_print_operand_punct
['#'] = 1;
1445 microblaze_print_operand_punct
['&'] = 1;
1446 microblaze_print_operand_punct
['!'] = 1;
1447 microblaze_print_operand_punct
['*'] = 1;
1448 microblaze_print_operand_punct
['@'] = 1;
1449 microblaze_print_operand_punct
['.'] = 1;
1450 microblaze_print_operand_punct
['('] = 1;
1451 microblaze_print_operand_punct
[')'] = 1;
1452 microblaze_print_operand_punct
['['] = 1;
1453 microblaze_print_operand_punct
[']'] = 1;
1454 microblaze_print_operand_punct
['<'] = 1;
1455 microblaze_print_operand_punct
['>'] = 1;
1456 microblaze_print_operand_punct
['{'] = 1;
1457 microblaze_print_operand_punct
['}'] = 1;
1458 microblaze_print_operand_punct
['^'] = 1;
1459 microblaze_print_operand_punct
['$'] = 1;
1460 microblaze_print_operand_punct
['+'] = 1;
1462 /* Set up array to map GCC register number to debug register number.
1463 Ignore the special purpose register numbers. */
1465 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
1466 microblaze_dbx_regno
[i
] = -1;
1468 start
= GP_DBX_FIRST
- GP_REG_FIRST
;
1469 for (i
= GP_REG_FIRST
; i
<= GP_REG_LAST
; i
++)
1470 microblaze_dbx_regno
[i
] = i
+ start
;
1472 /* Set up array giving whether a given register can hold a given mode. */
1474 for (mode
= VOIDmode
;
1475 mode
!= MAX_MACHINE_MODE
; mode
= (enum machine_mode
) ((int) mode
+ 1))
1477 register int size
= GET_MODE_SIZE (mode
);
1479 for (regno
= 0; regno
< FIRST_PSEUDO_REGISTER
; regno
++)
1485 ok
= (ST_REG_P (regno
) || GP_REG_P (regno
));
1487 else if (GP_REG_P (regno
))
1488 ok
= ((regno
& 1) == 0 || size
<= UNITS_PER_WORD
);
1492 microblaze_hard_regno_mode_ok
[(int) mode
][regno
] = ok
;
1497 /* Return true if FUNC is an interrupt function as specified
1498 by the "interrupt_handler" attribute. */
1501 microblaze_interrupt_function_p (tree func
)
1505 if (TREE_CODE (func
) != FUNCTION_DECL
)
1508 a
= lookup_attribute ("interrupt_handler", DECL_ATTRIBUTES (func
));
1509 return a
!= NULL_TREE
;
1513 microblaze_fast_interrupt_function_p (tree func
)
1517 if (TREE_CODE (func
) != FUNCTION_DECL
)
1520 a
= lookup_attribute ("fast_interrupt", DECL_ATTRIBUTES (func
));
1521 return a
!= NULL_TREE
;
1524 /* Return true if FUNC is an interrupt function which uses
1525 normal return, indicated by the "save_volatiles" attribute. */
1528 microblaze_save_volatiles (tree func
)
1532 if (TREE_CODE (func
) != FUNCTION_DECL
)
1535 a
= lookup_attribute ("save_volatiles", DECL_ATTRIBUTES (func
));
1536 return a
!= NULL_TREE
;
1539 /* Return whether function is tagged with 'interrupt_handler'
1540 or 'fast_interrupt' attribute. Return true if function
1541 should use return from interrupt rather than normal
1544 microblaze_is_interrupt_variant (void)
1546 return (interrupt_handler
|| fast_interrupt
);
1549 /* Determine of register must be saved/restored in call. */
1551 microblaze_must_save_register (int regno
)
1553 if (pic_offset_table_rtx
&&
1554 (regno
== MB_ABI_PIC_ADDR_REGNUM
) && df_regs_ever_live_p (regno
))
1557 if (df_regs_ever_live_p (regno
) && !call_used_regs
[regno
])
1560 if (frame_pointer_needed
&& (regno
== HARD_FRAME_POINTER_REGNUM
))
1565 if (regno
== MB_ABI_SUB_RETURN_ADDR_REGNUM
)
1567 if ((microblaze_is_interrupt_variant () || save_volatiles
) &&
1568 (regno
>= 3 && regno
<= 12))
1572 if (microblaze_is_interrupt_variant ())
1574 if (df_regs_ever_live_p (regno
)
1575 || regno
== MB_ABI_MSR_SAVE_REG
1576 || (interrupt_handler
1577 && (regno
== MB_ABI_ASM_TEMP_REGNUM
1578 || regno
== MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM
)))
1584 if (df_regs_ever_live_p (regno
)
1585 || regno
== MB_ABI_ASM_TEMP_REGNUM
1586 || regno
== MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM
)
1593 /* Return the bytes needed to compute the frame pointer from the current
1596 MicroBlaze stack frames look like:
1600 Before call After call
1601 +-----------------------+ +-----------------------+
1603 mem. | local variables, | | local variables, |
1604 | callee saved and | | callee saved and |
1606 +-----------------------+ +-----------------------+
1607 | arguments for called | | arguments for called |
1608 | subroutines | | subroutines |
1609 | (optional) | | (optional) |
1610 +-----------------------+ +-----------------------+
1611 | Link register | | Link register |
1613 +-----------------------+ +-----------------------+
1615 | local variables, |
1616 | callee saved and |
1618 +-----------------------+
1619 | MSR (optional if, |
1620 | interrupt handler) |
1621 +-----------------------+
1623 | alloca allocations |
1625 +-----------------------+
1627 | arguments for called |
1631 +-----------------------+
1634 memory +-----------------------+
1638 static HOST_WIDE_INT
1639 compute_frame_size (HOST_WIDE_INT size
)
1642 HOST_WIDE_INT total_size
; /* # bytes that the entire frame takes up. */
1643 HOST_WIDE_INT var_size
; /* # bytes that local variables take up. */
1644 HOST_WIDE_INT args_size
; /* # bytes that outgoing arguments take up. */
1645 int link_debug_size
; /* # bytes for link register. */
1646 HOST_WIDE_INT gp_reg_size
; /* # bytes needed to store calle-saved gp regs. */
1647 long mask
; /* mask of saved gp registers. */
1650 microblaze_interrupt_function_p (current_function_decl
);
1652 microblaze_fast_interrupt_function_p (current_function_decl
);
1653 save_volatiles
= microblaze_save_volatiles (current_function_decl
);
1658 args_size
= crtl
->outgoing_args_size
;
1660 if ((args_size
== 0) && cfun
->calls_alloca
)
1661 args_size
= NUM_OF_ARGS
* UNITS_PER_WORD
;
1663 total_size
= var_size
+ args_size
;
1666 /* force setting GOT. */
1667 df_set_regs_ever_live (MB_ABI_PIC_ADDR_REGNUM
, true);
1669 /* Calculate space needed for gp registers. */
1670 for (regno
= GP_REG_FIRST
; regno
<= GP_REG_LAST
; regno
++)
1672 if (microblaze_must_save_register (regno
))
1675 if (regno
!= MB_ABI_SUB_RETURN_ADDR_REGNUM
)
1676 /* Don't account for link register. It is accounted specially below. */
1677 gp_reg_size
+= GET_MODE_SIZE (SImode
);
1679 mask
|= (1L << (regno
- GP_REG_FIRST
));
1683 total_size
+= gp_reg_size
;
1685 /* Add 4 bytes for MSR. */
1686 if (microblaze_is_interrupt_variant ())
1689 /* No space to be allocated for link register in leaf functions with no other
1690 stack requirements. */
1691 if (total_size
== 0 && crtl
->is_leaf
)
1692 link_debug_size
= 0;
1694 link_debug_size
= UNITS_PER_WORD
;
1696 total_size
+= link_debug_size
;
1698 /* Save other computed information. */
1699 current_frame_info
.total_size
= total_size
;
1700 current_frame_info
.var_size
= var_size
;
1701 current_frame_info
.args_size
= args_size
;
1702 current_frame_info
.gp_reg_size
= gp_reg_size
;
1703 current_frame_info
.mask
= mask
;
1704 current_frame_info
.initialized
= reload_completed
;
1705 current_frame_info
.num_gp
= gp_reg_size
/ UNITS_PER_WORD
;
1706 current_frame_info
.link_debug_size
= link_debug_size
;
1709 /* Offset from which to callee-save GP regs. */
1710 current_frame_info
.gp_offset
= (total_size
- gp_reg_size
);
1712 current_frame_info
.gp_offset
= 0;
1714 /* Ok, we're done. */
1718 /* Make sure that we're not trying to eliminate to the wrong hard frame
1722 microblaze_can_eliminate (const int from
, const int to
)
1724 return ((from
== RETURN_ADDRESS_POINTER_REGNUM
&& !leaf_function_p())
1725 || (to
== MB_ABI_SUB_RETURN_ADDR_REGNUM
&& leaf_function_p())
1726 || (from
!= RETURN_ADDRESS_POINTER_REGNUM
1727 && (to
== HARD_FRAME_POINTER_REGNUM
1728 || (to
== STACK_POINTER_REGNUM
&& !frame_pointer_needed
))));
1731 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
1732 pointer or argument pointer or the return address pointer. TO is either
1733 the stack pointer or hard frame pointer. */
1736 microblaze_initial_elimination_offset (int from
, int to
)
1738 HOST_WIDE_INT offset
;
1742 case FRAME_POINTER_REGNUM
:
1745 case ARG_POINTER_REGNUM
:
1746 if (to
== STACK_POINTER_REGNUM
|| to
== HARD_FRAME_POINTER_REGNUM
)
1747 offset
= compute_frame_size (get_frame_size ());
1751 case RETURN_ADDRESS_POINTER_REGNUM
:
1755 offset
= current_frame_info
.gp_offset
+
1756 ((UNITS_PER_WORD
- (POINTER_SIZE
/ BITS_PER_UNIT
)));
1764 /* Print operands using format code.
1766 The MicroBlaze specific codes are:
1768 'X' X is CONST_INT, prints 32 bits in hexadecimal format = "0x%08x",
1769 'x' X is CONST_INT, prints 16 bits in hexadecimal format = "0x%04x",
1770 'F' op is CONST_DOUBLE, print 32 bits in hex,
1771 'd' output integer constant in decimal,
1772 'z' if the operand is 0, use $0 instead of normal operand.
1773 'D' print second register of double-word register operand.
1774 'L' print low-order register of double-word register operand.
1775 'M' print high-order register of double-word register operand.
1776 'C' print part of opcode for a branch condition.
1777 'N' print part of opcode for a branch condition, inverted.
1778 'S' X is CODE_LABEL, print with prefix of "LS" (for embedded switch).
1779 'B' print 'z' for EQ, 'n' for NE
1780 'b' print 'n' for EQ, 'z' for NE
1781 'T' print 'f' for EQ, 't' for NE
1782 't' print 't' for EQ, 'f' for NE
1783 'm' Print 1<<operand.
1784 'i' Print 'i' if MEM operand has immediate value
1785 'o' Print operand address+4
1786 '?' Print 'd' if we use a branch with delay slot instead of normal branch.
1787 'h' Print high word of const_double (int or float) value as hex
1788 'j' Print low word of const_double (int or float) value as hex
1789 's' Print -1 if operand is negative, 0 if positive (sign extend)
1790 '@' Print the name of the temporary register (rMB_ABI_ASM_TEMP_REGNUM).
1791 '#' Print nop if the delay slot of a branch is not filled.
1795 print_operand (FILE * file
, rtx op
, int letter
)
1797 register enum rtx_code code
;
1799 if (PRINT_OPERAND_PUNCT_VALID_P (letter
))
1804 /* Conditionally add a 'd' to indicate filled delay slot. */
1805 if (final_sequence
!= NULL
)
1810 /* Conditionally add a nop in unfilled delay slot. */
1811 if (final_sequence
== NULL
)
1812 fputs ("nop\t\t# Unfilled delay slot\n", file
);
1816 fputs (reg_names
[GP_REG_FIRST
+ MB_ABI_ASM_TEMP_REGNUM
], file
);
1820 output_operand_lossage ("unknown punctuation '%c'", letter
);
1829 output_operand_lossage ("null pointer");
1833 code
= GET_CODE (op
);
1835 if (code
== SIGN_EXTEND
)
1836 op
= XEXP (op
, 0), code
= GET_CODE (op
);
1864 fatal_insn ("PRINT_OPERAND, invalid insn for %%C", op
);
1867 else if (letter
== 'N')
1893 fatal_insn ("PRINT_OPERAND, invalid insn for %%N", op
);
1896 else if (letter
== 'S')
1900 ASM_GENERATE_INTERNAL_LABEL (buffer
, "LS", CODE_LABEL_NUMBER (op
));
1901 assemble_name (file
, buffer
);
1904 /* Print 'i' for memory operands which have immediate values. */
1905 else if (letter
== 'i')
1909 struct microblaze_address_info info
;
1911 if (!microblaze_classify_address
1912 (&info
, XEXP (op
, 0), GET_MODE (op
), 1))
1913 fatal_insn ("insn contains an invalid address !", op
);
1918 case ADDRESS_CONST_INT
:
1919 case ADDRESS_SYMBOLIC
:
1920 case ADDRESS_GOTOFF
:
1923 case ADDRESS_REG_INDEX
:
1925 case ADDRESS_INVALID
:
1927 fatal_insn ("invalid address", op
);
1932 else if (code
== REG
|| code
== SUBREG
)
1934 register int regnum
;
1937 regnum
= REGNO (op
);
1939 regnum
= true_regnum (op
);
1941 if ((letter
== 'M' && !WORDS_BIG_ENDIAN
)
1942 || (letter
== 'L' && WORDS_BIG_ENDIAN
) || letter
== 'D')
1945 fprintf (file
, "%s", reg_names
[regnum
]);
1948 else if (code
== MEM
)
1951 rtx op4
= adjust_address (op
, GET_MODE (op
), 4);
1952 output_address (XEXP (op4
, 0));
1955 output_address (XEXP (op
, 0));
1957 else if (letter
== 'h' || letter
== 'j')
1960 if (code
== CONST_DOUBLE
)
1962 if (GET_MODE (op
) == DFmode
)
1964 REAL_VALUE_TYPE value
;
1965 REAL_VALUE_FROM_CONST_DOUBLE (value
, op
);
1966 REAL_VALUE_TO_TARGET_DOUBLE (value
, val
);
1970 val
[0] = CONST_DOUBLE_HIGH (op
);
1971 val
[1] = CONST_DOUBLE_LOW (op
);
1974 else if (code
== CONST_INT
)
1976 val
[0] = (INTVAL (op
) & 0xffffffff00000000LL
) >> 32;
1977 val
[1] = INTVAL (op
) & 0x00000000ffffffffLL
;
1978 if (val
[0] == 0 && val
[1] < 0)
1982 fprintf (file
, "0x%8.8lx", (letter
== 'h') ? val
[0] : val
[1]);
1984 else if (code
== CONST_DOUBLE
)
1988 unsigned long value_long
;
1989 REAL_VALUE_TYPE value
;
1990 REAL_VALUE_FROM_CONST_DOUBLE (value
, op
);
1991 REAL_VALUE_TO_TARGET_SINGLE (value
, value_long
);
1992 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, value_long
);
1997 real_to_decimal (s
, CONST_DOUBLE_REAL_VALUE (op
), sizeof (s
), 0, 1);
2002 else if (code
== UNSPEC
)
2004 print_operand_address (file
, op
);
2007 else if (letter
== 'x' && GET_CODE (op
) == CONST_INT
)
2008 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, 0xffff & INTVAL (op
));
2010 else if (letter
== 'X' && GET_CODE (op
) == CONST_INT
)
2011 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, INTVAL (op
));
2013 else if (letter
== 'd' && GET_CODE (op
) == CONST_INT
)
2014 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, (INTVAL (op
)));
2016 else if (letter
== 'z' && GET_CODE (op
) == CONST_INT
&& INTVAL (op
) == 0)
2017 fputs (reg_names
[GP_REG_FIRST
], file
);
2019 else if (letter
== 's' && GET_CODE (op
) == CONST_INT
)
2020 if (INTVAL (op
) < 0)
2025 else if (letter
== 'd' || letter
== 'x' || letter
== 'X' || letter
== 's')
2026 output_operand_lossage ("letter %c was found & insn was not CONST_INT", letter
);
2028 else if (letter
== 'B')
2029 fputs (code
== EQ
? "z" : "n", file
);
2030 else if (letter
== 'b')
2031 fputs (code
== EQ
? "n" : "z", file
);
2032 else if (letter
== 'T')
2033 fputs (code
== EQ
? "f" : "t", file
);
2034 else if (letter
== 't')
2035 fputs (code
== EQ
? "t" : "f", file
);
2037 else if (code
== CONST
&& GET_CODE (XEXP (op
, 0)) == REG
)
2039 print_operand (file
, XEXP (op
, 0), letter
);
2041 else if (letter
== 'm')
2042 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, (1L << INTVAL (op
)));
2044 output_addr_const (file
, op
);
2047 /* A C compound statement to output to stdio stream STREAM the
2048 assembler syntax for an instruction operand that is a memory
2049 reference whose address is ADDR. ADDR is an RTL expression.
2051 Possible address classifications and output formats are,
2053 ADDRESS_REG "%0, r0"
2055 ADDRESS_REG with non-zero "%0, <addr_const>"
2058 ADDRESS_REG_INDEX "rA, RB"
2059 (if rA is r0, rA and rB are swapped)
2061 ADDRESS_CONST_INT "r0, <addr_const>"
2063 ADDRESS_SYMBOLIC "rBase, <addr_const>"
2064 (rBase is a base register suitable for the
2069 print_operand_address (FILE * file
, rtx addr
)
2071 struct microblaze_address_info info
;
2072 enum microblaze_address_type type
;
2073 if (!microblaze_classify_address (&info
, addr
, GET_MODE (addr
), 1))
2074 fatal_insn ("insn contains an invalid address !", addr
);
2080 fprintf (file
, "%s,", reg_names
[REGNO (info
.regA
)]);
2081 output_addr_const (file
, info
.offset
);
2083 case ADDRESS_REG_INDEX
:
2084 if (REGNO (info
.regA
) == 0)
2085 /* Make rB == r0 instead of rA == r0. This helps reduce read port
2087 fprintf (file
, "%s,%s", reg_names
[REGNO (info
.regB
)],
2088 reg_names
[REGNO (info
.regA
)]);
2089 else if (REGNO (info
.regB
) != 0)
2090 /* This is a silly swap to help Dhrystone. */
2091 fprintf (file
, "%s,%s", reg_names
[REGNO (info
.regB
)],
2092 reg_names
[REGNO (info
.regA
)]);
2094 case ADDRESS_CONST_INT
:
2095 fprintf (file
, "%s,", reg_names
[REGNO (info
.regA
)]);
2096 output_addr_const (file
, info
.offset
);
2098 case ADDRESS_SYMBOLIC
:
2099 case ADDRESS_GOTOFF
:
2102 fprintf (file
, "%s,", reg_names
[REGNO (info
.regA
)]);
2103 output_addr_const (file
, info
.symbol
);
2104 if (type
== ADDRESS_GOTOFF
)
2106 fputs ("@GOT", file
);
2108 else if (type
== ADDRESS_PLT
)
2110 fputs ("@PLT", file
);
2113 case ADDRESS_INVALID
:
2114 fatal_insn ("invalid address", addr
);
2119 /* Emit either a label, .comm, or .lcomm directive, and mark that the symbol
2120 is used, so that we don't emit an .extern for it in
2121 microblaze_asm_file_end. */
2124 microblaze_declare_object (FILE * stream
, const char *name
,
2125 const char *section
, const char *fmt
, int size
)
2128 fputs (section
, stream
);
2129 assemble_name (stream
, name
);
2130 fprintf (stream
, fmt
, size
);
2133 /* Common code to emit the insns (or to write the instructions to a file)
2134 to save/restore registers.
2136 Other parts of the code assume that MICROBLAZE_TEMP1_REGNUM (aka large_reg)
2137 is not modified within save_restore_insns. */
2139 #define BITSET_P(VALUE,BIT) (((VALUE) & (1L << (BIT))) != 0)
2141 /* Save or restore instructions based on whether this is the prologue or
2142 epilogue. prologue is 1 for the prologue. */
2144 save_restore_insns (int prologue
)
2146 rtx base_reg_rtx
, reg_rtx
, mem_rtx
, /* msr_rtx, */ isr_reg_rtx
=
2148 rtx isr_msr_rtx
= 0, insn
;
2149 long mask
= current_frame_info
.mask
;
2150 HOST_WIDE_INT gp_offset
;
2153 if (frame_pointer_needed
2154 && !BITSET_P (mask
, HARD_FRAME_POINTER_REGNUM
- GP_REG_FIRST
))
2160 /* Save registers starting from high to low. The debuggers prefer at least
2161 the return register be stored at func+4, and also it allows us not to
2162 need a nop in the epilog if at least one register is reloaded in
2163 addition to return address. */
2165 /* Pick which pointer to use as a base register. For small frames, just
2166 use the stack pointer. Otherwise, use a temporary register. Save 2
2167 cycles if the save area is near the end of a large frame, by reusing
2168 the constant created in the prologue/epilogue to adjust the stack
2171 gp_offset
= current_frame_info
.gp_offset
;
2173 gcc_assert (gp_offset
> 0);
2175 base_reg_rtx
= stack_pointer_rtx
;
2177 /* For interrupt_handlers, need to save/restore the MSR. */
2178 if (microblaze_is_interrupt_variant ())
2180 isr_mem_rtx
= gen_rtx_MEM (SImode
,
2181 gen_rtx_PLUS (Pmode
, base_reg_rtx
,
2182 GEN_INT (current_frame_info
.
2186 /* Do not optimize in flow analysis. */
2187 MEM_VOLATILE_P (isr_mem_rtx
) = 1;
2188 isr_reg_rtx
= gen_rtx_REG (SImode
, MB_ABI_MSR_SAVE_REG
);
2189 isr_msr_rtx
= gen_rtx_REG (SImode
, ST_REG
);
2192 if (microblaze_is_interrupt_variant () && !prologue
)
2194 emit_move_insn (isr_reg_rtx
, isr_mem_rtx
);
2195 emit_move_insn (isr_msr_rtx
, isr_reg_rtx
);
2196 /* Do not optimize in flow analysis. */
2197 emit_insn (gen_rtx_USE (SImode
, isr_reg_rtx
));
2198 emit_insn (gen_rtx_USE (SImode
, isr_msr_rtx
));
2201 for (regno
= GP_REG_FIRST
; regno
<= GP_REG_LAST
; regno
++)
2203 if (BITSET_P (mask
, regno
- GP_REG_FIRST
))
2205 if (regno
== MB_ABI_SUB_RETURN_ADDR_REGNUM
)
2206 /* Don't handle here. Already handled as the first register. */
2209 reg_rtx
= gen_rtx_REG (SImode
, regno
);
2210 insn
= gen_rtx_PLUS (Pmode
, base_reg_rtx
, GEN_INT (gp_offset
));
2211 mem_rtx
= gen_rtx_MEM (SImode
, insn
);
2212 if (microblaze_is_interrupt_variant () || save_volatiles
)
2213 /* Do not optimize in flow analysis. */
2214 MEM_VOLATILE_P (mem_rtx
) = 1;
2218 insn
= emit_move_insn (mem_rtx
, reg_rtx
);
2219 RTX_FRAME_RELATED_P (insn
) = 1;
2223 insn
= emit_move_insn (reg_rtx
, mem_rtx
);
2226 gp_offset
+= GET_MODE_SIZE (SImode
);
2230 if (microblaze_is_interrupt_variant () && prologue
)
2232 emit_move_insn (isr_reg_rtx
, isr_msr_rtx
);
2233 emit_move_insn (isr_mem_rtx
, isr_reg_rtx
);
2235 /* Do not optimize in flow analysis. */
2236 emit_insn (gen_rtx_USE (SImode
, isr_reg_rtx
));
2237 emit_insn (gen_rtx_USE (SImode
, isr_msr_rtx
));
2240 /* Done saving and restoring */
2244 /* Set up the stack and frame (if desired) for the function. */
2246 microblaze_function_prologue (FILE * file
, HOST_WIDE_INT size ATTRIBUTE_UNUSED
)
2249 long fsiz
= current_frame_info
.total_size
;
2251 /* Get the function name the same way that toplev.c does before calling
2252 assemble_start_function. This is needed so that the name used here
2253 exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */
2254 fnname
= XSTR (XEXP (DECL_RTL (current_function_decl
), 0), 0);
2255 if (!flag_inhibit_size_directive
)
2257 fputs ("\t.ent\t", file
);
2258 if (interrupt_handler
&& strcmp (INTERRUPT_HANDLER_NAME
, fnname
))
2259 fputs ("_interrupt_handler", file
);
2260 else if (fast_interrupt
&& strcmp (FAST_INTERRUPT_NAME
, fnname
))
2261 fputs ("_fast_interrupt", file
);
2263 assemble_name (file
, fnname
);
2265 if (!microblaze_is_interrupt_variant ())
2266 ASM_OUTPUT_TYPE_DIRECTIVE (file
, fnname
, "function");
2269 assemble_name (file
, fnname
);
2270 fputs (":\n", file
);
2272 if (interrupt_handler
&& strcmp (INTERRUPT_HANDLER_NAME
, fnname
))
2273 fputs ("_interrupt_handler:\n", file
);
2275 if (!flag_inhibit_size_directive
)
2277 /* .frame FRAMEREG, FRAMESIZE, RETREG. */
2279 "\t.frame\t%s,%ld,%s\t\t# vars= %ld, regs= %d, args= %d\n",
2280 (reg_names
[(frame_pointer_needed
)
2281 ? HARD_FRAME_POINTER_REGNUM
:
2282 STACK_POINTER_REGNUM
]), fsiz
,
2283 reg_names
[MB_ABI_SUB_RETURN_ADDR_REGNUM
+ GP_REG_FIRST
],
2284 current_frame_info
.var_size
, current_frame_info
.num_gp
,
2285 crtl
->outgoing_args_size
);
2286 fprintf (file
, "\t.mask\t0x%08lx\n", current_frame_info
.mask
);
2290 /* Output extra assembler code at the end of a prologue. */
2292 microblaze_function_end_prologue (FILE * file
)
2294 if (TARGET_STACK_CHECK
)
2296 fprintf (file
, "\t# Stack Check Stub -- Start.\n\t");
2297 fprintf (file
, "ori\tr18,r0,_stack_end\n\t");
2298 fprintf (file
, "cmpu\tr18,r1,r18\n\t");
2299 fprintf (file
, "bgei\tr18,_stack_overflow_exit\n\t");
2300 fprintf (file
, "# Stack Check Stub -- End.\n");
2304 /* Expand the prologue into a bunch of separate insns. */
2307 microblaze_expand_prologue (void)
2311 const char *arg_name
= 0;
2312 tree fndecl
= current_function_decl
;
2313 tree fntype
= TREE_TYPE (fndecl
);
2314 tree fnargs
= DECL_ARGUMENTS (fndecl
);
2319 CUMULATIVE_ARGS args_so_far_v
;
2320 cumulative_args_t args_so_far
;
2321 rtx mem_rtx
, reg_rtx
;
2323 /* If struct value address is treated as the first argument, make it so. */
2324 if (aggregate_value_p (DECL_RESULT (fndecl
), fntype
)
2325 && !cfun
->returns_pcc_struct
)
2327 tree type
= build_pointer_type (fntype
);
2328 tree function_result_decl
= build_decl (BUILTINS_LOCATION
, PARM_DECL
,
2331 DECL_ARG_TYPE (function_result_decl
) = type
;
2332 TREE_CHAIN (function_result_decl
) = fnargs
;
2333 fnargs
= function_result_decl
;
2336 /* Determine the last argument, and get its name. */
2338 INIT_CUMULATIVE_ARGS (args_so_far_v
, fntype
, NULL_RTX
, 0, 0);
2339 args_so_far
= pack_cumulative_args (&args_so_far_v
);
2340 regno
= GP_ARG_FIRST
;
2342 for (cur_arg
= fnargs
; cur_arg
!= 0; cur_arg
= next_arg
)
2344 tree passed_type
= DECL_ARG_TYPE (cur_arg
);
2345 enum machine_mode passed_mode
= TYPE_MODE (passed_type
);
2348 if (TREE_ADDRESSABLE (passed_type
))
2350 passed_type
= build_pointer_type (passed_type
);
2351 passed_mode
= Pmode
;
2354 entry_parm
= targetm
.calls
.function_arg (args_so_far
, passed_mode
,
2361 /* passed in a register, so will get homed automatically. */
2362 if (GET_MODE (entry_parm
) == BLKmode
)
2363 words
= (int_size_in_bytes (passed_type
) + 3) / 4;
2365 words
= (GET_MODE_SIZE (GET_MODE (entry_parm
)) + 3) / 4;
2367 regno
= REGNO (entry_parm
) + words
- 1;
2371 regno
= GP_ARG_LAST
+ 1;
2375 targetm
.calls
.function_arg_advance (args_so_far
, passed_mode
,
2378 next_arg
= TREE_CHAIN (cur_arg
);
2381 if (DECL_NAME (cur_arg
))
2382 arg_name
= IDENTIFIER_POINTER (DECL_NAME (cur_arg
));
2388 /* Split parallel insn into a sequence of insns. */
2390 next_arg_reg
= targetm
.calls
.function_arg (args_so_far
, VOIDmode
,
2391 void_type_node
, true);
2392 if (next_arg_reg
!= 0 && GET_CODE (next_arg_reg
) == PARALLEL
)
2394 rtvec adjust
= XVEC (next_arg_reg
, 0);
2395 int num
= GET_NUM_ELEM (adjust
);
2397 for (i
= 0; i
< num
; i
++)
2399 rtx pattern
= RTVEC_ELT (adjust
, i
);
2400 emit_insn (pattern
);
2404 fsiz
= compute_frame_size (get_frame_size ());
2406 /* If this function is a varargs function, store any registers that
2407 would normally hold arguments ($5 - $10) on the stack. */
2408 if (((TYPE_ARG_TYPES (fntype
) != 0
2409 && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype
)))
2412 && ((arg_name
[0] == '_'
2413 && strcmp (arg_name
, "__builtin_va_alist") == 0)
2414 || (arg_name
[0] == 'v'
2415 && strcmp (arg_name
, "va_alist") == 0)))))
2417 int offset
= (regno
- GP_ARG_FIRST
+ 1) * UNITS_PER_WORD
;
2418 rtx ptr
= stack_pointer_rtx
;
2420 /* If we are doing svr4-abi, sp has already been decremented by fsiz. */
2421 for (; regno
<= GP_ARG_LAST
; regno
++)
2424 ptr
= gen_rtx_PLUS (Pmode
, stack_pointer_rtx
, GEN_INT (offset
));
2425 emit_move_insn (gen_rtx_MEM (SImode
, ptr
),
2426 gen_rtx_REG (SImode
, regno
));
2428 offset
+= GET_MODE_SIZE (SImode
);
2435 rtx fsiz_rtx
= GEN_INT (fsiz
);
2438 insn
= emit_insn (gen_subsi3 (stack_pointer_rtx
, stack_pointer_rtx
,
2441 RTX_FRAME_RELATED_P (insn
) = 1;
2443 /* Handle SUB_RETURN_ADDR_REGNUM specially at first. */
2444 if (!crtl
->is_leaf
|| interrupt_handler
)
2446 mem_rtx
= gen_rtx_MEM (SImode
,
2447 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
2450 if (interrupt_handler
)
2451 /* Do not optimize in flow analysis. */
2452 MEM_VOLATILE_P (mem_rtx
) = 1;
2454 reg_rtx
= gen_rtx_REG (SImode
, MB_ABI_SUB_RETURN_ADDR_REGNUM
);
2455 insn
= emit_move_insn (mem_rtx
, reg_rtx
);
2456 RTX_FRAME_RELATED_P (insn
) = 1;
2459 /* _save_ registers for prologue. */
2460 save_restore_insns (1);
2462 if (frame_pointer_needed
)
2466 insn
= emit_insn (gen_movsi (hard_frame_pointer_rtx
,
2467 stack_pointer_rtx
));
2470 RTX_FRAME_RELATED_P (insn
) = 1;
2474 if (flag_pic
== 2 && df_regs_ever_live_p (MB_ABI_PIC_ADDR_REGNUM
))
2476 SET_REGNO (pic_offset_table_rtx
, MB_ABI_PIC_ADDR_REGNUM
);
2477 emit_insn (gen_set_got (pic_offset_table_rtx
)); /* setting GOT. */
2480 /* If we are profiling, make sure no instructions are scheduled before
2481 the call to mcount. */
2484 emit_insn (gen_blockage ());
2487 /* Do necessary cleanup after a function to restore stack, frame, and regs. */
2489 #define RA_MASK ((long) 0x80000000) /* 1 << 31 */
2490 #define PIC_OFFSET_TABLE_MASK (1 << (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST))
2493 microblaze_function_epilogue (FILE * file ATTRIBUTE_UNUSED
,
2494 HOST_WIDE_INT size ATTRIBUTE_UNUSED
)
2498 /* Get the function name the same way that toplev.c does before calling
2499 assemble_start_function. This is needed so that the name used here
2500 exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */
2501 fnname
= XSTR (XEXP (DECL_RTL (current_function_decl
), 0), 0);
2503 if (!flag_inhibit_size_directive
)
2505 fputs ("\t.end\t", file
);
2506 if (interrupt_handler
)
2507 fputs ("_interrupt_handler", file
);
2509 assemble_name (file
, fnname
);
2513 /* Reset state info for each function. */
2514 current_frame_info
= zero_frame_info
;
2516 /* Restore the output file if optimizing the GP (optimizing the GP causes
2517 the text to be diverted to a tempfile, so that data decls come before
2518 references to the data). */
2521 /* Expand the epilogue into a bunch of separate insns. */
2524 microblaze_expand_epilogue (void)
2526 HOST_WIDE_INT fsiz
= current_frame_info
.total_size
;
2527 rtx fsiz_rtx
= GEN_INT (fsiz
);
2531 /* In case of interrupt handlers use addki instead of addi for changing the
2532 stack pointer value. */
2534 if (microblaze_can_use_return_insn ())
2536 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode
,
2538 MB_ABI_SUB_RETURN_ADDR_REGNUM
)));
2544 /* Restore SUB_RETURN_ADDR_REGNUM at first. This is to prevent the
2545 sequence of load-followed by a use (in rtsd) in every prologue. Saves
2546 a load-use stall cycle :) This is also important to handle alloca.
2547 (See comments for if (frame_pointer_needed) below. */
2549 if (!crtl
->is_leaf
|| interrupt_handler
)
2552 gen_rtx_MEM (SImode
,
2553 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
, const0_rtx
));
2554 if (interrupt_handler
)
2555 /* Do not optimize in flow analysis. */
2556 MEM_VOLATILE_P (mem_rtx
) = 1;
2557 reg_rtx
= gen_rtx_REG (SImode
, MB_ABI_SUB_RETURN_ADDR_REGNUM
);
2558 emit_move_insn (reg_rtx
, mem_rtx
);
2561 /* It is important that this is done after we restore the return address
2562 register (above). When alloca is used, we want to restore the
2563 sub-routine return address only from the current stack top and not
2564 from the frame pointer (which we restore below). (frame_pointer + 0)
2565 might have been over-written since alloca allocates memory on the
2567 if (frame_pointer_needed
)
2568 emit_insn (gen_movsi (stack_pointer_rtx
, hard_frame_pointer_rtx
));
2570 /* _restore_ registers for epilogue. */
2571 save_restore_insns (0);
2572 emit_insn (gen_blockage ());
2573 emit_insn (gen_addsi3 (stack_pointer_rtx
, stack_pointer_rtx
, fsiz_rtx
));
2576 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode
, GP_REG_FIRST
+
2577 MB_ABI_SUB_RETURN_ADDR_REGNUM
)));
2581 /* Return nonzero if this function is known to have a null epilogue.
2582 This allows the optimizer to omit jumps to jumps if no stack
2586 microblaze_can_use_return_insn (void)
2588 if (!reload_completed
)
2591 if (df_regs_ever_live_p (MB_ABI_SUB_RETURN_ADDR_REGNUM
) || profile_flag
)
2594 if (current_frame_info
.initialized
)
2595 return current_frame_info
.total_size
== 0;
2597 return compute_frame_size (get_frame_size ()) == 0;
2600 /* Implement TARGET_SECONDARY_RELOAD. */
2603 microblaze_secondary_reload (bool in_p ATTRIBUTE_UNUSED
, rtx x ATTRIBUTE_UNUSED
,
2604 reg_class_t rclass
, enum machine_mode mode ATTRIBUTE_UNUSED
,
2605 secondary_reload_info
*sri ATTRIBUTE_UNUSED
)
2607 if (rclass
== ST_REGS
)
2614 microblaze_globalize_label (FILE * stream
, const char *name
)
2616 fputs ("\t.globl\t", stream
);
2617 if (microblaze_is_interrupt_variant ())
2619 if (interrupt_handler
&& strcmp (name
, INTERRUPT_HANDLER_NAME
))
2620 fputs (INTERRUPT_HANDLER_NAME
, stream
);
2621 else if (fast_interrupt
&& strcmp (name
, FAST_INTERRUPT_NAME
))
2622 fputs (FAST_INTERRUPT_NAME
, stream
);
2623 fputs ("\n\t.globl\t", stream
);
2625 assemble_name (stream
, name
);
2626 fputs ("\n", stream
);
2629 /* Returns true if decl should be placed into a "small data" section. */
2631 microblaze_elf_in_small_data_p (const_tree decl
)
2635 if (!TARGET_XLGPOPT
)
2638 /* We want to merge strings, so we never consider them small data. */
2639 if (TREE_CODE (decl
) == STRING_CST
)
2642 /* Functions are never in the small data area. */
2643 if (TREE_CODE (decl
) == FUNCTION_DECL
)
2646 if (TREE_CODE (decl
) == VAR_DECL
&& DECL_SECTION_NAME (decl
))
2648 const char *section
= TREE_STRING_POINTER (DECL_SECTION_NAME (decl
));
2649 if (strcmp (section
, ".sdata") == 0
2650 || strcmp (section
, ".sdata2") == 0
2651 || strcmp (section
, ".sbss") == 0
2652 || strcmp (section
, ".sbss2") == 0)
2656 size
= int_size_in_bytes (TREE_TYPE (decl
));
2658 return (size
> 0 && size
<= microblaze_section_threshold
);
2663 microblaze_select_section (tree decl
, int reloc
, unsigned HOST_WIDE_INT align
)
2665 switch (categorize_decl_for_section (decl
, reloc
))
2667 case SECCAT_RODATA_MERGE_STR
:
2668 case SECCAT_RODATA_MERGE_STR_INIT
:
2669 /* MB binutils have various issues with mergeable string sections and
2670 relaxation/relocation. Currently, turning mergeable sections
2671 into regular readonly sections. */
2673 return readonly_data_section
;
2675 return default_elf_select_section (decl
, reloc
, align
);
2680 Encode info about sections into the RTL based on a symbol's declaration.
2681 The default definition of this hook, default_encode_section_info in
2682 `varasm.c', sets a number of commonly-useful bits in SYMBOL_REF_FLAGS. */
2685 microblaze_encode_section_info (tree decl
, rtx rtl
, int first
)
2687 default_encode_section_info (decl
, rtl
, first
);
2691 expand_pic_symbol_ref (enum machine_mode mode ATTRIBUTE_UNUSED
, rtx op
)
2694 result
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, op
), UNSPEC_GOTOFF
);
2695 result
= gen_rtx_CONST (Pmode
, result
);
2696 result
= gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
, result
);
2697 result
= gen_const_mem (Pmode
, result
);
2702 microblaze_expand_move (enum machine_mode mode
, rtx operands
[])
2704 /* If operands[1] is a constant address invalid for pic, then we need to
2705 handle it just like LEGITIMIZE_ADDRESS does. */
2708 if (GET_CODE (operands
[0]) == MEM
)
2710 rtx addr
= XEXP (operands
[0], 0);
2711 if (GET_CODE (addr
) == SYMBOL_REF
)
2713 rtx ptr_reg
, result
;
2715 if (reload_in_progress
)
2716 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
2718 addr
= expand_pic_symbol_ref (mode
, addr
);
2719 ptr_reg
= gen_reg_rtx (Pmode
);
2720 emit_move_insn (ptr_reg
, addr
);
2721 result
= gen_rtx_MEM (mode
, ptr_reg
);
2722 operands
[0] = result
;
2725 if (GET_CODE (operands
[1]) == SYMBOL_REF
2726 || GET_CODE (operands
[1]) == LABEL_REF
)
2729 if (reload_in_progress
)
2730 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
2731 result
= expand_pic_symbol_ref (mode
, operands
[1]);
2732 if (GET_CODE (operands
[0]) != REG
)
2734 rtx ptr_reg
= gen_reg_rtx (Pmode
);
2735 emit_move_insn (ptr_reg
, result
);
2736 emit_move_insn (operands
[0], ptr_reg
);
2740 emit_move_insn (operands
[0], result
);
2744 else if (GET_CODE (operands
[1]) == MEM
&&
2745 GET_CODE (XEXP (operands
[1], 0)) == SYMBOL_REF
)
2749 if (reload_in_progress
)
2750 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
2751 result
= expand_pic_symbol_ref (mode
, XEXP (operands
[1], 0));
2753 ptr_reg
= gen_reg_rtx (Pmode
);
2755 emit_move_insn (ptr_reg
, result
);
2756 result
= gen_rtx_MEM (mode
, ptr_reg
);
2757 emit_move_insn (operands
[0], result
);
2760 else if (pic_address_needs_scratch (operands
[1]))
2762 rtx temp
= force_reg (SImode
, XEXP (XEXP (operands
[1], 0), 0));
2763 rtx temp2
= XEXP (XEXP (operands
[1], 0), 1);
2765 if (reload_in_progress
)
2766 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
2767 emit_move_insn (operands
[0], gen_rtx_PLUS (SImode
, temp
, temp2
));
2772 if ((reload_in_progress
| reload_completed
) == 0
2773 && !register_operand (operands
[0], SImode
)
2774 && !register_operand (operands
[1], SImode
)
2775 && (GET_CODE (operands
[1]) != CONST_INT
|| INTVAL (operands
[1]) != 0))
2777 rtx temp
= force_reg (SImode
, operands
[1]);
2778 emit_move_insn (operands
[0], temp
);
2784 /* Expand shift operations. */
2786 microblaze_expand_shift (rtx operands
[])
2788 gcc_assert ((GET_CODE (operands
[2]) == CONST_INT
)
2789 || (GET_CODE (operands
[2]) == REG
)
2790 || (GET_CODE (operands
[2]) == SUBREG
));
2792 /* Shift by one -- generate pattern. */
2793 if ((GET_CODE (operands
[2]) == CONST_INT
) && (INTVAL (operands
[2]) == 1))
2796 /* Have barrel shifter and shift > 1: use it. */
2797 if (TARGET_BARREL_SHIFT
)
2800 gcc_assert ((GET_CODE (operands
[0]) == REG
)
2801 || (GET_CODE (operands
[0]) == SUBREG
)
2802 || (GET_CODE (operands
[1]) == REG
)
2803 || (GET_CODE (operands
[1]) == SUBREG
));
2805 /* Shift by zero -- copy regs if necessary. */
2806 if ((GET_CODE (operands
[2]) == CONST_INT
) && (INTVAL (operands
[2]) == 0))
2808 if (REGNO (operands
[0]) != REGNO (operands
[1]))
2809 emit_insn (gen_movsi (operands
[0], operands
[1]));
2816 /* Return an RTX indicating where the return address to the
2817 calling function can be found. */
2819 microblaze_return_addr (int count
, rtx frame ATTRIBUTE_UNUSED
)
2824 return gen_rtx_PLUS (Pmode
,
2825 get_hard_reg_initial_val (Pmode
,
2826 MB_ABI_SUB_RETURN_ADDR_REGNUM
),
2830 /* Queue an .ident string in the queue of top-level asm statements.
2831 If the string size is below the threshold, put it into .sdata2.
2832 If the front-end is done, we must be being called from toplev.c.
2833 In that case, do nothing. */
2835 microblaze_asm_output_ident (const char *string
)
2837 const char *section_asm_op
;
2841 if (cgraph_state
!= CGRAPH_STATE_PARSING
)
2844 size
= strlen (string
) + 1;
2845 if (size
<= microblaze_section_threshold
)
2846 section_asm_op
= SDATA2_SECTION_ASM_OP
;
2848 section_asm_op
= READONLY_DATA_SECTION_ASM_OP
;
2850 buf
= ACONCAT ((section_asm_op
, "\n\t.ascii \"", string
, "\\0\"\n", NULL
));
2851 add_asm_node (build_string (strlen (buf
), buf
));
2855 microblaze_elf_asm_init_sections (void)
2858 = get_unnamed_section (SECTION_WRITE
, output_section_asm_op
,
2859 SDATA2_SECTION_ASM_OP
);
2862 /* Generate assembler code for constant parts of a trampoline. */
2865 microblaze_asm_trampoline_template (FILE *f
)
2867 fprintf (f
, "\tmfs r18, rpc\n");
2868 fprintf (f
, "\tlwi r3, r18, 16\n");
2869 fprintf (f
, "\tlwi r18, r18, 20\n");
2870 fprintf (f
, "\tbra r18\n");
2871 /* fprintf (f, "\t.word\t0x00000000\t\t# <function address>\n"); */
2872 /* fprintf (f, "\t.word\t0x00000000\t\t# <static chain value>\n"); */
2875 /* Implement TARGET_TRAMPOLINE_INIT. */
2878 microblaze_trampoline_init (rtx m_tramp
, tree fndecl
, rtx chain_value
)
2880 rtx fnaddr
= XEXP (DECL_RTL (fndecl
), 0);
2883 emit_block_move (m_tramp
, assemble_trampoline_template (),
2884 GEN_INT (6*UNITS_PER_WORD
), BLOCK_OP_NORMAL
);
2886 mem
= adjust_address (m_tramp
, SImode
, 16);
2887 emit_move_insn (mem
, chain_value
);
2888 mem
= adjust_address (m_tramp
, SImode
, 20);
2889 emit_move_insn (mem
, fnaddr
);
2892 /* Emit instruction to perform compare.
2893 cmp is (compare_op op0 op1). */
2895 microblaze_emit_compare (enum machine_mode mode
, rtx cmp
, enum rtx_code
*cmp_code
)
2897 rtx cmp_op0
= XEXP (cmp
, 0);
2898 rtx cmp_op1
= XEXP (cmp
, 1);
2899 rtx comp_reg
= gen_reg_rtx (SImode
);
2900 enum rtx_code code
= *cmp_code
;
2902 gcc_assert ((GET_CODE (cmp_op0
) == REG
) || (GET_CODE (cmp_op0
) == SUBREG
));
2904 /* If comparing against zero, just test source reg. */
2905 if (cmp_op1
== const0_rtx
)
2908 if (code
== EQ
|| code
== NE
)
2910 /* Use xor for equal/not-equal comparison. */
2911 emit_insn (gen_xorsi3 (comp_reg
, cmp_op0
, cmp_op1
));
2913 else if (code
== GT
|| code
== GTU
|| code
== LE
|| code
== LEU
)
2915 /* MicroBlaze compare is not symmetrical. */
2916 /* Swap argument order. */
2917 cmp_op1
= force_reg (mode
, cmp_op1
);
2918 if (code
== GT
|| code
== LE
)
2919 emit_insn (gen_signed_compare (comp_reg
, cmp_op0
, cmp_op1
));
2921 emit_insn (gen_unsigned_compare (comp_reg
, cmp_op0
, cmp_op1
));
2922 /* Translate test condition. */
2923 *cmp_code
= swap_condition (code
);
2925 else /* if (code == GE || code == GEU || code == LT || code == LTU) */
2927 cmp_op1
= force_reg (mode
, cmp_op1
);
2928 if (code
== GE
|| code
== LT
)
2929 emit_insn (gen_signed_compare (comp_reg
, cmp_op1
, cmp_op0
));
2931 emit_insn (gen_unsigned_compare (comp_reg
, cmp_op1
, cmp_op0
));
2937 /* Generate conditional branch -- first, generate test condition,
2938 second, generate correct branch instruction. */
2941 microblaze_expand_conditional_branch (enum machine_mode mode
, rtx operands
[])
2943 enum rtx_code code
= GET_CODE (operands
[0]);
2947 comp
= microblaze_emit_compare (mode
, operands
[0], &code
);
2948 condition
= gen_rtx_fmt_ee (signed_condition (code
), SImode
, comp
, const0_rtx
);
2949 emit_jump_insn (gen_condjump (condition
, operands
[3]));
2953 microblaze_expand_conditional_branch_sf (rtx operands
[])
2956 rtx cmp_op0
= XEXP (operands
[0], 0);
2957 rtx cmp_op1
= XEXP (operands
[0], 1);
2958 rtx comp_reg
= gen_reg_rtx (SImode
);
2960 emit_insn (gen_cstoresf4 (comp_reg
, operands
[0], cmp_op0
, cmp_op1
));
2961 condition
= gen_rtx_NE (SImode
, comp_reg
, const0_rtx
);
2962 emit_jump_insn (gen_condjump (condition
, operands
[3]));
2965 /* Implement TARGET_FRAME_POINTER_REQUIRED. */
2968 microblaze_frame_pointer_required (void)
2970 /* If the function contains dynamic stack allocations, we need to
2971 use the frame pointer to access the static parts of the frame. */
2972 if (cfun
->calls_alloca
)
2978 microblaze_expand_divide (rtx operands
[])
2980 /* Table lookup software divides. Works for all (nr/dr) where (0 <= nr,dr <= 15). */
2982 rtx regt1
= gen_reg_rtx (SImode
);
2983 rtx reg18
= gen_rtx_REG (SImode
, R_TMP
);
2984 rtx regqi
= gen_reg_rtx (QImode
);
2985 rtx div_label
= gen_label_rtx ();
2986 rtx div_end_label
= gen_label_rtx ();
2987 rtx div_table_rtx
= gen_rtx_SYMBOL_REF (QImode
,"_divsi3_table");
2990 rtx jump
, cjump
, insn
;
2992 insn
= emit_insn (gen_iorsi3 (regt1
, operands
[1], operands
[2]));
2993 cjump
= emit_jump_insn_after (gen_cbranchsi4 (
2994 gen_rtx_GTU (SImode
, regt1
, GEN_INT (15)),
2995 regt1
, GEN_INT (15), div_label
), insn
);
2996 LABEL_NUSES (div_label
) = 1;
2997 JUMP_LABEL (cjump
) = div_label
;
2998 emit_insn (gen_rtx_CLOBBER (SImode
, reg18
));
3000 emit_insn (gen_ashlsi3_bshift (regt1
, operands
[1], GEN_INT(4)));
3001 emit_insn (gen_addsi3 (regt1
, regt1
, operands
[2]));
3002 mem_rtx
= gen_rtx_MEM (QImode
,
3003 gen_rtx_PLUS (Pmode
, regt1
, div_table_rtx
));
3005 insn
= emit_insn (gen_movqi (regqi
, mem_rtx
));
3006 insn
= emit_insn (gen_movsi (operands
[0], gen_rtx_SUBREG (SImode
, regqi
, 0)));
3007 jump
= emit_jump_insn_after (gen_jump (div_end_label
), insn
);
3008 JUMP_LABEL (jump
) = div_end_label
;
3009 LABEL_NUSES (div_end_label
) = 1;
3012 emit_label (div_label
);
3013 ret
= emit_library_call_value (gen_rtx_SYMBOL_REF (Pmode
, "__divsi3"),
3014 operands
[0], LCT_NORMAL
,
3015 GET_MODE (operands
[0]), 2, operands
[1],
3016 GET_MODE (operands
[1]), operands
[2],
3017 GET_MODE (operands
[2]));
3018 if (ret
!= operands
[0])
3019 emit_move_insn (operands
[0], ret
);
3021 emit_label (div_end_label
);
3022 emit_insn (gen_blockage ());
3025 /* Implement TARGET_FUNCTION_VALUE. */
3027 microblaze_function_value (const_tree valtype
,
3028 const_tree func ATTRIBUTE_UNUSED
,
3029 bool outgoing ATTRIBUTE_UNUSED
)
3031 return LIBCALL_VALUE (TYPE_MODE (valtype
));
3034 /* Implement TARGET_SCHED_ADJUST_COST. */
3036 microblaze_adjust_cost (rtx insn ATTRIBUTE_UNUSED
, rtx link
,
3037 rtx dep ATTRIBUTE_UNUSED
, int cost
)
3039 if (REG_NOTE_KIND (link
) == REG_DEP_OUTPUT
)
3041 if (REG_NOTE_KIND (link
) != 0)
3046 /* Implement TARGET_LEGITIMATE_CONSTANT_P.
3048 At present, GAS doesn't understand li.[sd], so don't allow it
3049 to be generated at present. */
3051 microblaze_legitimate_constant_p (enum machine_mode mode
, rtx x
)
3053 return GET_CODE (x
) != CONST_DOUBLE
|| microblaze_const_double_ok (x
, mode
);
3056 #undef TARGET_ENCODE_SECTION_INFO
3057 #define TARGET_ENCODE_SECTION_INFO microblaze_encode_section_info
3059 #undef TARGET_ASM_GLOBALIZE_LABEL
3060 #define TARGET_ASM_GLOBALIZE_LABEL microblaze_globalize_label
3062 #undef TARGET_ASM_FUNCTION_PROLOGUE
3063 #define TARGET_ASM_FUNCTION_PROLOGUE microblaze_function_prologue
3065 #undef TARGET_ASM_FUNCTION_EPILOGUE
3066 #define TARGET_ASM_FUNCTION_EPILOGUE microblaze_function_epilogue
3068 #undef TARGET_RTX_COSTS
3069 #define TARGET_RTX_COSTS microblaze_rtx_costs
3071 #undef TARGET_ADDRESS_COST
3072 #define TARGET_ADDRESS_COST microblaze_address_cost
3074 #undef TARGET_ATTRIBUTE_TABLE
3075 #define TARGET_ATTRIBUTE_TABLE microblaze_attribute_table
3077 #undef TARGET_IN_SMALL_DATA_P
3078 #define TARGET_IN_SMALL_DATA_P microblaze_elf_in_small_data_p
3080 #undef TARGET_ASM_SELECT_SECTION
3081 #define TARGET_ASM_SELECT_SECTION microblaze_select_section
3083 #undef TARGET_HAVE_SRODATA_SECTION
3084 #define TARGET_HAVE_SRODATA_SECTION true
3086 #undef TARGET_ASM_FUNCTION_END_PROLOGUE
3087 #define TARGET_ASM_FUNCTION_END_PROLOGUE \
3088 microblaze_function_end_prologue
3090 #undef TARGET_ARG_PARTIAL_BYTES
3091 #define TARGET_ARG_PARTIAL_BYTES function_arg_partial_bytes
3093 #undef TARGET_FUNCTION_ARG
3094 #define TARGET_FUNCTION_ARG microblaze_function_arg
3096 #undef TARGET_FUNCTION_ARG_ADVANCE
3097 #define TARGET_FUNCTION_ARG_ADVANCE microblaze_function_arg_advance
3099 #undef TARGET_CAN_ELIMINATE
3100 #define TARGET_CAN_ELIMINATE microblaze_can_eliminate
3102 #undef TARGET_LEGITIMIZE_ADDRESS
3103 #define TARGET_LEGITIMIZE_ADDRESS microblaze_legitimize_address
3105 #undef TARGET_LEGITIMATE_ADDRESS_P
3106 #define TARGET_LEGITIMATE_ADDRESS_P microblaze_legitimate_address_p
3108 #undef TARGET_FRAME_POINTER_REQUIRED
3109 #define TARGET_FRAME_POINTER_REQUIRED microblaze_frame_pointer_required
3111 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
3112 #define TARGET_ASM_TRAMPOLINE_TEMPLATE microblaze_asm_trampoline_template
3114 #undef TARGET_TRAMPOLINE_INIT
3115 #define TARGET_TRAMPOLINE_INIT microblaze_trampoline_init
3117 #undef TARGET_PROMOTE_FUNCTION_MODE
3118 #define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
3120 #undef TARGET_FUNCTION_VALUE
3121 #define TARGET_FUNCTION_VALUE microblaze_function_value
3123 #undef TARGET_SECONDARY_RELOAD
3124 #define TARGET_SECONDARY_RELOAD microblaze_secondary_reload
3126 #undef TARGET_SCHED_ADJUST_COST
3127 #define TARGET_SCHED_ADJUST_COST microblaze_adjust_cost
3129 #undef TARGET_ASM_INIT_SECTIONS
3130 #define TARGET_ASM_INIT_SECTIONS microblaze_elf_asm_init_sections
3132 #undef TARGET_OPTION_OVERRIDE
3133 #define TARGET_OPTION_OVERRIDE microblaze_option_override
3135 #undef TARGET_LEGITIMATE_CONSTANT_P
3136 #define TARGET_LEGITIMATE_CONSTANT_P microblaze_legitimate_constant_p
3138 struct gcc_target targetm
= TARGET_INITIALIZER
;
3140 #include "gt-microblaze.h"