1 /* Subroutines used for code generation on Xilinx MicroBlaze.
2 Copyright (C) 2009-2024 Free Software Foundation, Inc.
4 Contributed by Michael Eager <eager@eagercon.com>.
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published
10 by the Free Software Foundation; either version 3, or (at your
11 option) any later version.
13 GCC is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16 License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. */
22 #define IN_TARGET_CODE 1
26 #include "coretypes.h"
31 #include "stringpool.h"
41 #include "diagnostic-core.h"
43 #include "stor-layout.h"
52 #include "insn-addr.h"
56 /* This file should be included last. */
57 #include "target-def.h"
59 #define MICROBLAZE_VERSION_COMPARE(VA,VB) strverscmp (VA, VB)
61 /* Classifies an address.
68 A natural register or a register + const_int offset address.
69 The register satisfies microblaze_valid_base_register_p and the
70 offset is a const_arith_operand.
74 A natural register offset by the index contained in an index register. The base
75 register satisfies microblaze_valid_base_register_p and the index register
76 satisfies microblaze_valid_index_register_p
80 A signed 16/32-bit constant address.
84 A constant symbolic address or a (register + symbol). */
86 enum microblaze_address_type
96 ADDRESS_SYMBOLIC_TXT_REL
104 enum microblaze_symbol_type
110 /* TLS Address Type. */
119 /* Classification of a MicroBlaze address. */
120 struct microblaze_address_info
122 enum microblaze_address_type type
;
123 rtx regA
; /* Contains valid values on ADDRESS_REG, ADDRESS_REG_INDEX,
125 rtx regB
; /* Contains valid values on ADDRESS_REG_INDEX. */
126 rtx offset
; /* Contains valid values on ADDRESS_CONST_INT and ADDRESS_REG. */
127 rtx symbol
; /* Contains valid values on ADDRESS_SYMBOLIC. */
128 enum microblaze_symbol_type symbol_type
;
129 enum tls_reloc tls_type
;
132 /* Structure to be filled in by compute_frame_size with register
133 save masks, and offsets for the current function. */
135 struct GTY(()) microblaze_frame_info
{
136 long total_size
; /* # bytes that the entire frame takes up. */
137 long var_size
; /* # bytes that variables take up. */
138 long args_size
; /* # bytes that outgoing arguments take up. */
139 int link_debug_size
; /* # bytes for the link reg and back pointer. */
140 int gp_reg_size
; /* # bytes needed to store gp regs. */
141 long gp_offset
; /* offset from new sp to store gp registers. */
142 long mask
; /* mask of saved gp registers. */
143 int initialized
; /* != 0 if frame size already calculated. */
144 int num_gp
; /* number of gp registers saved. */
145 long insns_len
; /* length of insns. */
146 int alloc_stack
; /* Flag to indicate if the current function
147 must not create stack space. (As an optimization). */
150 /* Global variables for machine-dependent things. */
152 /* Toggle which pipleline interface to use. */
153 static GTY(()) int microblaze_sched_use_dfa
= 0;
155 /* Threshold for data being put into the small data/bss area, instead
156 of the normal data area (references to the small data/bss area take
157 1 instruction, and use the global pointer, references to the normal
158 data area takes 2 instructions). */
159 int microblaze_section_threshold
= -1;
161 /* Prevent scheduling potentially exception causing instructions in
162 delay slots. -mcpu=v3.00.a or v4.00.a turns this on. */
163 int microblaze_no_unsafe_delay
;
165 /* Set to one if the targeted core has the CLZ insn. */
166 int microblaze_has_clz
= 0;
168 /* Which CPU pipeline do we use. We haven't really standardized on a CPU
169 version having only a particular type of pipeline. There can still be
170 options on the CPU to scale pipeline features up or down. :(
171 Bad Presentation (??), so we let the MD file rely on the value of
172 this variable instead Making PIPE_5 the default. It should be backward
173 optimal with PIPE_3 MicroBlazes. */
174 enum pipeline_type microblaze_pipe
= MICROBLAZE_PIPE_5
;
176 /* High and low marks for floating point values which we will accept
177 as legitimate constants for TARGET_LEGITIMATE_CONSTANT_P. These are
178 initialized in override_options. */
179 REAL_VALUE_TYPE dfhigh
, dflow
, sfhigh
, sflow
;
181 /* Array giving truth value on whether or not a given hard register
182 can support a given mode. */
183 static char microblaze_hard_regno_mode_ok_p
[(int)MAX_MACHINE_MODE
]
184 [FIRST_PSEUDO_REGISTER
];
186 /* Current frame information calculated by compute_frame_size. */
187 struct microblaze_frame_info current_frame_info
;
189 /* Zero structure to initialize current_frame_info. */
190 struct microblaze_frame_info zero_frame_info
;
192 /* List of all MICROBLAZE punctuation characters used by print_operand. */
193 char microblaze_print_operand_punct
[256];
195 /* Map GCC register number to debugger register number. */
196 int microblaze_debugger_regno
[FIRST_PSEUDO_REGISTER
];
198 /* Map hard register number to register class. */
199 enum reg_class microblaze_regno_to_class
[] =
201 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
202 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
203 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
204 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
205 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
206 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
207 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
208 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
209 ST_REGS
, GR_REGS
, GR_REGS
, GR_REGS
212 /* MicroBlaze specific machine attributes.
213 interrupt_handler - Interrupt handler attribute to add interrupt prologue
214 and epilogue and use appropriate interrupt return.
215 save_volatiles - Similar to interrupt handler, but use normal return. */
216 int interrupt_handler
;
221 TARGET_GNU_ATTRIBUTES (microblaze_attribute_table
, {
222 /* name min_len, max_len, decl_req, type_req, fn_type_req,
223 affects_type_identity, handler, exclude */
224 {"interrupt_handler", 0, 0, true, false, false, false, NULL
, NULL
},
225 {"break_handler", 0, 0, true, false, false, false, NULL
, NULL
},
226 {"fast_interrupt", 0, 0, true, false, false, false, NULL
, NULL
},
227 {"save_volatiles", 0, 0, true, false, false, false, NULL
, NULL
}
230 static int microblaze_interrupt_function_p (tree
);
232 static void microblaze_elf_asm_constructor (rtx
, int) ATTRIBUTE_UNUSED
;
233 static void microblaze_elf_asm_destructor (rtx
, int) ATTRIBUTE_UNUSED
;
235 section
*sdata2_section
;
238 #undef TARGET_HAVE_TLS
239 #define TARGET_HAVE_TLS true
242 /* Return truth value if a CONST_DOUBLE is ok to be a legitimate constant. */
244 microblaze_const_double_ok (rtx op
, machine_mode mode
)
248 if (GET_CODE (op
) != CONST_DOUBLE
)
251 if (GET_MODE (op
) == VOIDmode
)
254 if (mode
!= SFmode
&& mode
!= DFmode
)
257 if (op
== CONST0_RTX (mode
))
260 d
= *CONST_DOUBLE_REAL_VALUE (op
);
262 if (REAL_VALUE_ISNAN (d
))
265 if (REAL_VALUE_NEGATIVE (d
))
266 d
= real_value_negate (&d
);
270 if (real_less (&d
, &dfhigh
) && real_less (&dflow
, &d
))
275 if (real_less (&d
, &sfhigh
) && real_less (&sflow
, &d
))
282 /* Return truth value if a memory operand fits in a single instruction
283 (ie, register + small offset) or (register + register). */
286 simple_memory_operand (rtx op
, machine_mode mode ATTRIBUTE_UNUSED
)
288 rtx addr
, plus0
, plus1
;
290 /* Eliminate non-memory operations. */
291 if (GET_CODE (op
) != MEM
)
294 /* dword operations really put out 2 instructions, so eliminate them. */
295 /* ??? This isn't strictly correct. It is OK to accept multiword modes
296 here, since the length attributes are being set correctly, but only
297 if the address is offsettable. */
298 if (GET_MODE_SIZE (GET_MODE (op
)) > UNITS_PER_WORD
)
302 /* Decode the address now. */
304 switch (GET_CODE (addr
))
311 plus0
= XEXP (addr
, 0);
312 plus1
= XEXP (addr
, 1);
314 if (GET_CODE (plus0
) != REG
)
317 if (GET_CODE (plus0
) == REG
&& GET_CODE (plus1
) == CONST_INT
318 && SMALL_INT (plus1
))
322 else if (GET_CODE (plus1
) == REG
&& GET_CODE (plus0
) == CONST_INT
)
326 else if (GET_CODE (plus0
) == REG
&& GET_CODE (plus1
) == REG
)
343 /* Return nonzero for a memory address that can be used to load or store
347 double_memory_operand (rtx op
, machine_mode mode
)
351 if (GET_CODE (op
) != MEM
|| !memory_operand (op
, mode
))
353 /* During reload, we accept a pseudo register if it has an
354 appropriate memory address. If we don't do this, we will
355 wind up reloading into a register, and then reloading that
356 register from memory, when we could just reload directly from
358 if (reload_in_progress
359 && GET_CODE (op
) == REG
360 && REGNO (op
) >= FIRST_PSEUDO_REGISTER
361 && reg_renumber
[REGNO (op
)] < 0
362 && reg_equiv_mem (REGNO (op
)) != 0
363 && double_memory_operand (reg_equiv_mem (REGNO (op
)), mode
))
368 /* Make sure that 4 added to the address is a valid memory address.
369 This essentially just checks for overflow in an added constant. */
373 if (CONSTANT_ADDRESS_P (addr
))
376 return memory_address_p ((GET_MODE_CLASS (mode
) == MODE_INT
377 ? E_SImode
: E_SFmode
),
378 plus_constant (Pmode
, addr
, 4));
381 /* Implement REG_OK_FOR_BASE_P -and- REG_OK_FOR_INDEX_P. */
383 microblaze_regno_ok_for_base_p (int regno
, int strict
)
385 if (regno
>= FIRST_PSEUDO_REGISTER
)
389 regno
= reg_renumber
[regno
];
392 /* These fake registers will be eliminated to either the stack or
393 hard frame pointer, both of which are usually valid base registers.
394 Reload deals with the cases where the eliminated form isn't valid. */
395 if (regno
== ARG_POINTER_REGNUM
|| regno
== FRAME_POINTER_REGNUM
)
398 return GP_REG_P (regno
);
401 /* Return true if X is a valid base register for the given mode.
402 Allow only hard registers if STRICT. */
405 microblaze_valid_base_register_p (rtx x
,
406 machine_mode mode ATTRIBUTE_UNUSED
,
409 if (!strict
&& GET_CODE (x
) == SUBREG
)
412 return (GET_CODE (x
) == REG
413 && microblaze_regno_ok_for_base_p (REGNO (x
), strict
));
416 /* Build the SYMBOL_REF for __tls_get_addr. */
418 static GTY(()) rtx tls_get_addr_libfunc
;
421 get_tls_get_addr (void)
423 if (!tls_get_addr_libfunc
)
424 tls_get_addr_libfunc
= init_one_libfunc ("__tls_get_addr");
425 return tls_get_addr_libfunc
;
428 /* Return TRUE if X is a thread-local symbol. */
430 microblaze_tls_symbol_p (rtx x
)
432 if (!TARGET_HAVE_TLS
)
435 if (GET_CODE (x
) != SYMBOL_REF
)
438 return SYMBOL_REF_TLS_MODEL (x
) != 0;
441 /* Return TRUE if X contains any TLS symbol references. */
444 microblaze_tls_referenced_p (rtx x
)
446 if (!TARGET_HAVE_TLS
)
448 subrtx_iterator::array_type array
;
449 FOR_EACH_SUBRTX (iter
, array
, x
, ALL
)
452 if (GET_CODE (x
) == SYMBOL_REF
&& SYMBOL_REF_TLS_MODEL (x
) != 0)
454 /* Don't recurse into UNSPEC_TLS looking for TLS symbols; these are
455 TLS offsets, not real symbol references. */
456 if (GET_CODE (x
) == UNSPEC
&& XINT (x
, 1) == UNSPEC_TLS
)
457 iter
.skip_subrtxes ();
463 microblaze_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED
, rtx x
)
465 return microblaze_tls_referenced_p(x
);
468 /* Return TRUE if X references a SYMBOL_REF. */
470 symbol_mentioned_p (rtx x
)
475 if (GET_CODE (x
) == SYMBOL_REF
)
478 /* UNSPEC entries for a symbol include the SYMBOL_REF, but they
479 are constant offsets, not symbols. */
480 if (GET_CODE (x
) == UNSPEC
)
483 fmt
= GET_RTX_FORMAT (GET_CODE (x
));
485 for (i
= GET_RTX_LENGTH (GET_CODE (x
)) - 1; i
>= 0; i
--)
491 for (j
= XVECLEN (x
, i
) - 1; j
>= 0; j
--)
492 if (symbol_mentioned_p (XVECEXP (x
, i
, j
)))
495 else if (fmt
[i
] == 'e' && symbol_mentioned_p (XEXP (x
, i
)))
502 /* Return TRUE if X references a LABEL_REF. */
504 label_mentioned_p (rtx x
)
509 if (GET_CODE (x
) == LABEL_REF
)
512 /* UNSPEC entries for a symbol include a LABEL_REF for the referencing
513 instruction, but they are constant offsets, not symbols. */
514 if (GET_CODE (x
) == UNSPEC
)
517 fmt
= GET_RTX_FORMAT (GET_CODE (x
));
518 for (i
= GET_RTX_LENGTH (GET_CODE (x
)) - 1; i
>= 0; i
--)
524 for (j
= XVECLEN (x
, i
) - 1; j
>= 0; j
--)
525 if (label_mentioned_p (XVECEXP (x
, i
, j
)))
528 else if (fmt
[i
] == 'e' && label_mentioned_p (XEXP (x
, i
)))
536 tls_mentioned_p (rtx x
)
538 switch (GET_CODE (x
))
541 return tls_mentioned_p (XEXP (x
, 0));
544 if (XINT (x
, 1) == UNSPEC_TLS
)
554 load_tls_operand (rtx x
, rtx reg
)
559 reg
= gen_reg_rtx (Pmode
);
561 tmp
= gen_rtx_CONST (Pmode
, x
);
563 emit_insn (gen_rtx_SET (reg
,
564 gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
, tmp
)));
570 microblaze_call_tls_get_addr (rtx x
, rtx reg
, rtx
*valuep
, int reloc
)
575 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
579 tls_entry
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (2, x
, GEN_INT (reloc
)),
582 reg
= load_tls_operand (tls_entry
, reg
);
584 *valuep
= emit_library_call_value (get_tls_get_addr (), NULL_RTX
,
585 LCT_PURE
, /* LCT_CONST? */
588 insns
= get_insns ();
595 microblaze_legitimize_tls_address(rtx x
, rtx reg
)
597 rtx dest
, ret
, eqv
, addend
;
599 enum tls_model model
;
600 model
= SYMBOL_REF_TLS_MODEL (x
);
604 case TLS_MODEL_LOCAL_DYNAMIC
:
605 case TLS_MODEL_GLOBAL_DYNAMIC
:
606 case TLS_MODEL_INITIAL_EXEC
:
607 insns
= microblaze_call_tls_get_addr (x
, reg
, &ret
, TLS_GD
);
608 dest
= gen_reg_rtx (Pmode
);
609 emit_libcall_block (insns
, dest
, ret
, x
);
612 case TLS_MODEL_LOCAL_EXEC
:
613 insns
= microblaze_call_tls_get_addr (x
, reg
, &ret
, TLS_LDM
);
615 /* Attach a unique REG_EQUIV, to allow the RTL optimizers to
616 share the LDM result with other LD model accesses. */
617 eqv
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, const1_rtx
), UNSPEC_TLS
);
618 dest
= gen_reg_rtx (Pmode
);
619 emit_libcall_block (insns
, dest
, ret
, eqv
);
621 /* Load the addend. */
622 addend
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (2, x
, GEN_INT (TLS_DTPREL
)),
624 addend
= force_reg (SImode
, gen_rtx_CONST (SImode
, addend
));
625 dest
= gen_rtx_PLUS (Pmode
, dest
, addend
);
635 microblaze_classify_unspec (struct microblaze_address_info
*info
, rtx x
)
637 info
->symbol_type
= SYMBOL_TYPE_GENERAL
;
638 info
->symbol
= XVECEXP (x
, 0, 0);
640 if (XINT (x
, 1) == UNSPEC_GOTOFF
)
642 info
->regA
= gen_rtx_REG (SImode
, PIC_OFFSET_TABLE_REGNUM
);
643 info
->type
= ADDRESS_GOTOFF
;
645 else if (XINT (x
, 1) == UNSPEC_PLT
)
647 info
->type
= ADDRESS_PLT
;
649 else if (XINT (x
, 1) == UNSPEC_TLS
)
651 info
->type
= ADDRESS_TLS
;
652 info
->tls_type
= tls_reloc (INTVAL (XVECEXP (x
, 0, 1)));
654 else if (XINT (x
, 1) == UNSPEC_TEXT
)
656 info
->type
= ADDRESS_SYMBOLIC_TXT_REL
;
666 /* Return true if X is a valid index register for the given mode.
667 Allow only hard registers if STRICT. */
670 microblaze_valid_index_register_p (rtx x
,
671 machine_mode mode ATTRIBUTE_UNUSED
,
674 if (!strict
&& GET_CODE (x
) == SUBREG
)
677 return (GET_CODE (x
) == REG
678 /* A base register is good enough to be an index register on MicroBlaze. */
679 && microblaze_regno_ok_for_base_p (REGNO (x
), strict
));
682 /* Get the base register for accessing a value from the memory or
683 Symbol ref. Used for MicroBlaze Small Data Area Pointer Optimization. */
690 if (!flag_pic
|| microblaze_tls_symbol_p(x
))
691 base_reg
= MB_ABI_BASE_REGNUM
;
693 base_reg
= MB_ABI_PIC_ADDR_REGNUM
;
696 && GET_CODE (x
) == SYMBOL_REF
697 && SYMBOL_REF_SMALL_P (x
) && (decl
= SYMBOL_REF_DECL (x
)) != NULL
)
699 if (TREE_READONLY (decl
))
700 base_reg
= MB_ABI_GPRO_REGNUM
;
702 base_reg
= MB_ABI_GPRW_REGNUM
;
708 /* Return true if X is a valid address for machine mode MODE. If it is,
709 fill in INFO appropriately.
710 STRICT > 0 if we should only accept hard base registers.
711 STRICT = 2 if the operand address is being printed thus
712 function has been called by print_operand_address.
714 type regA regB offset symbol
716 ADDRESS_INVALID NULL NULL NULL NULL
718 ADDRESS_REG %0 NULL const_0 / NULL
720 ADDRESS_REG_INDEX %0 %1 NULL NULL
722 ADDRESS_SYMBOLIC r0 / NULL NULL symbol
725 ADDRESS_CONST_INT r0 NULL const NULL
727 For modes spanning multiple registers (DFmode in 32-bit GPRs,
728 DImode, TImode), indexed addressing cannot be used because
729 adjacent memory cells are accessed by adding word-sized offsets
730 during assembly output. */
733 microblaze_classify_address (struct microblaze_address_info
*info
, rtx x
,
734 machine_mode mode
, int strict
)
740 info
->type
= ADDRESS_INVALID
;
745 info
->symbol_type
= SYMBOL_TYPE_INVALID
;
748 switch (GET_CODE (x
))
753 info
->type
= ADDRESS_REG
;
755 info
->offset
= const0_rtx
;
756 return microblaze_valid_base_register_p (info
->regA
, mode
, strict
);
760 xplus0
= XEXP (x
, 0);
761 xplus1
= XEXP (x
, 1);
763 if (microblaze_valid_base_register_p (xplus0
, mode
, strict
))
765 info
->type
= ADDRESS_REG
;
768 if (GET_CODE (xplus1
) == CONST_INT
)
770 info
->offset
= xplus1
;
773 else if (GET_CODE (xplus1
) == UNSPEC
)
775 /* Need offsettable address. */
776 if (GET_MODE_SIZE (mode
) > UNITS_PER_WORD
)
779 return microblaze_classify_unspec (info
, xplus1
);
781 else if ((GET_CODE (xplus1
) == SYMBOL_REF
||
782 GET_CODE (xplus1
) == LABEL_REF
))
784 if (flag_pic
== 2 || microblaze_tls_symbol_p(xplus1
))
786 info
->type
= ADDRESS_SYMBOLIC
;
787 info
->symbol
= xplus1
;
788 info
->symbol_type
= SYMBOL_TYPE_GENERAL
;
791 else if (GET_CODE (xplus1
) == CONST
)
793 rtx xconst0
= XEXP(xplus1
, 0);
796 if (GET_CODE (xconst0
) == UNSPEC
)
798 /* Need offsettable address. */
799 if (GET_MODE_SIZE (mode
) > UNITS_PER_WORD
)
801 return microblaze_classify_unspec(info
, xconst0
);
804 /* for (plus x const_int) just look at x. */
805 if (GET_CODE (xconst0
) == PLUS
806 && GET_CODE (XEXP (xconst0
, 1)) == CONST_INT
807 && (SMALL_INT (XEXP (xconst0
, 1))
808 || GET_CODE (XEXP (xconst0
, 0)) == UNSPEC
))
810 /* Hold CONST_INT Value in offset in case of
811 UNSPEC + CONST_INT. */
812 offset
= XEXP (xconst0
, 1);
814 /* This is ok as info->symbol is set to xplus1 the full
815 const-expression below. */
816 xconst0
= XEXP (xconst0
, 0);
819 if (GET_CODE (xconst0
) == SYMBOL_REF
820 || GET_CODE (xconst0
) == LABEL_REF
)
822 if (flag_pic
== 2 || microblaze_tls_symbol_p(xconst0
))
825 info
->type
= ADDRESS_SYMBOLIC
;
826 info
->symbol
= xplus1
;
827 info
->symbol_type
= SYMBOL_TYPE_GENERAL
;
831 if (GET_CODE (xconst0
) == UNSPEC
&& TARGET_PIC_DATA_TEXT_REL
)
833 if (GET_MODE_SIZE (mode
) > UNITS_PER_WORD
)
836 info
->offset
= offset
;
837 return microblaze_classify_unspec (info
, xconst0
);
840 /* Not base + symbol || base + UNSPEC. */
844 else if (GET_CODE (xplus1
) == REG
845 && microblaze_valid_index_register_p (xplus1
, mode
,
847 && (GET_MODE_SIZE (mode
) <= UNITS_PER_WORD
))
849 /* Restrict larger than word-width modes from using an index register. */
850 info
->type
= ADDRESS_REG_INDEX
;
859 info
->regA
= gen_raw_REG (mode
, 0);
860 info
->type
= ADDRESS_CONST_INT
;
868 info
->type
= ADDRESS_SYMBOLIC
;
869 info
->symbol_type
= SYMBOL_TYPE_GENERAL
;
871 info
->regA
= gen_raw_REG (mode
, get_base_reg (x
));
873 if (GET_CODE (x
) == CONST
)
875 if (GET_CODE (XEXP (x
, 0)) == UNSPEC
)
877 info
->regA
= gen_raw_REG (mode
,
878 get_base_reg (XVECEXP (XEXP (x
,0), 0, 0)));
879 return microblaze_classify_unspec (info
, XEXP (x
, 0));
881 return !(flag_pic
&& pic_address_needs_scratch (x
));
884 /* Avoid error in print_operand_address in case UNSPEC
885 is removed from SYMBOL or LABEL REFS during optimization. */
886 if ((GET_CODE (x
) == SYMBOL_REF
|| GET_CODE (x
) == LABEL_REF
)
887 && flag_pic
&& TARGET_PIC_DATA_TEXT_REL
&& strict
== 2)
889 info
->type
= ADDRESS_SYMBOLIC_TXT_REL
;
895 else if (microblaze_tls_symbol_p(x
))
903 if (reload_in_progress
)
904 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
905 return microblaze_classify_unspec (info
, x
);
915 /* This function is used to implement GO_IF_LEGITIMATE_ADDRESS. It
916 returns a nonzero value if X is a legitimate address for a memory
917 operand of the indicated MODE. STRICT is nonzero if this function
918 is called during reload. */
921 microblaze_legitimate_address_p (machine_mode mode
, rtx x
, bool strict
,
924 struct microblaze_address_info addr
;
926 return microblaze_classify_address (&addr
, x
, mode
, strict
);
930 microblaze_constant_address_p (rtx x
)
932 return ((GET_CODE (x
) == LABEL_REF
) || (GET_CODE (x
) == SYMBOL_REF
)
933 || GET_CODE (x
) == CONST_INT
934 || (GET_CODE (x
) == CONST
935 && ! (flag_pic
&& pic_address_needs_scratch (x
))));
939 microblaze_valid_pic_const (rtx x
)
941 switch (GET_CODE (x
))
953 microblaze_legitimate_pic_operand (rtx x
)
955 if (flag_pic
== 2 && (symbol_mentioned_p (x
) || label_mentioned_p (x
))
956 && !(TARGET_PIC_DATA_TEXT_REL
&& call_insn_operand (x
,VOIDmode
)))
959 if (microblaze_tls_referenced_p(x
))
965 /* Try machine-dependent ways of modifying an illegitimate address
966 to be legitimate. If we find one, return the new, valid address.
967 This is used from only one place: `memory_address' in explow.cc.
969 OLDX is the address as it was before break_out_memory_refs was
970 called. In some cases it is useful to look at this to decide what
973 It is always safe for this function to do nothing. It exists to
974 recognize opportunities to optimize the output.
976 For the MicroBlaze, transform:
978 memory(X + <large int>)
982 Y = <large int> & ~0x7fff;
984 memory (Z + (<large int> & 0x7fff));
986 This is for CSE to find several similar references, and only use one Z.
988 When PIC, convert addresses of the form memory (symbol+large int) to
989 memory (reg+large int). */
992 microblaze_legitimize_address (rtx x
, rtx oldx ATTRIBUTE_UNUSED
,
993 machine_mode mode ATTRIBUTE_UNUSED
)
995 rtx xinsn
= x
, result
;
997 if (GET_CODE (xinsn
) == CONST
998 && flag_pic
&& pic_address_needs_scratch (xinsn
))
1000 rtx ptr_reg
= gen_reg_rtx (Pmode
);
1001 rtx constant
= XEXP (XEXP (xinsn
, 0), 1);
1003 emit_move_insn (ptr_reg
, XEXP (XEXP (xinsn
, 0), 0));
1005 result
= gen_rtx_PLUS (Pmode
, ptr_reg
, constant
);
1006 if (SMALL_INT (constant
))
1008 /* Otherwise we fall through so the code below will fix the
1013 if (GET_CODE (xinsn
) == PLUS
)
1015 rtx xplus0
= XEXP (xinsn
, 0);
1016 rtx xplus1
= XEXP (xinsn
, 1);
1017 enum rtx_code code0
= GET_CODE (xplus0
);
1018 enum rtx_code code1
= GET_CODE (xplus1
);
1020 if (code0
!= REG
&& code1
== REG
)
1022 xplus0
= XEXP (xinsn
, 1);
1023 xplus1
= XEXP (xinsn
, 0);
1024 code0
= GET_CODE (xplus0
);
1025 code1
= GET_CODE (xplus1
);
1028 if (code0
== REG
&& REG_OK_FOR_BASE_P (xplus0
)
1029 && code1
== CONST_INT
&& !SMALL_INT (xplus1
))
1031 rtx int_reg
= gen_reg_rtx (Pmode
);
1032 rtx ptr_reg
= gen_reg_rtx (Pmode
);
1034 emit_move_insn (int_reg
, GEN_INT (INTVAL (xplus1
) & ~0x7fff));
1036 emit_insn (gen_rtx_SET (ptr_reg
,
1037 gen_rtx_PLUS (Pmode
, xplus0
, int_reg
)));
1039 result
= gen_rtx_PLUS (Pmode
, ptr_reg
,
1040 GEN_INT (INTVAL (xplus1
) & 0x7fff));
1044 if (code0
== REG
&& REG_OK_FOR_BASE_P (xplus0
))
1046 if (reload_in_progress
)
1047 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
1050 xplus1
= XEXP (xplus1
, 0);
1051 code1
= GET_CODE (xplus1
);
1053 if (code1
== SYMBOL_REF
)
1055 if (microblaze_tls_symbol_p(xplus1
))
1058 reg
= gen_reg_rtx (Pmode
);
1060 tls_ref
= microblaze_legitimize_tls_address (xplus1
,
1062 emit_move_insn (reg
, tls_ref
);
1064 result
= gen_rtx_PLUS (Pmode
, xplus0
, reg
);
1068 else if (flag_pic
== 2)
1070 if (!TARGET_PIC_DATA_TEXT_REL
)
1073 reg
= gen_reg_rtx (Pmode
);
1075 pic_ref
= gen_rtx_UNSPEC (Pmode
,
1076 gen_rtvec (1, xplus1
),
1078 pic_ref
= gen_rtx_CONST (Pmode
, pic_ref
);
1079 pic_ref
= gen_rtx_PLUS (Pmode
,
1080 pic_offset_table_rtx
, pic_ref
);
1081 pic_ref
= gen_const_mem (Pmode
, pic_ref
);
1082 emit_move_insn (reg
, pic_ref
);
1083 result
= gen_rtx_PLUS (Pmode
, xplus0
, reg
);
1089 reg
= gen_reg_rtx (Pmode
);
1090 pic_ref
= gen_rtx_UNSPEC (Pmode
,
1091 gen_rtvec (1, xplus1
),
1093 pic_ref
= gen_rtx_CONST (Pmode
, pic_ref
);
1094 emit_insn (gen_addsi3 (reg
,
1095 pic_offset_table_rtx
, xplus0
));
1096 result
= gen_rtx_PLUS (Pmode
, reg
, pic_ref
);
1104 if (GET_CODE (xinsn
) == SYMBOL_REF
)
1107 if (microblaze_tls_symbol_p(xinsn
))
1109 reg
= microblaze_legitimize_tls_address (xinsn
, NULL_RTX
);
1111 else if (flag_pic
== 2)
1113 if (reload_in_progress
)
1114 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
1116 if (!TARGET_PIC_DATA_TEXT_REL
)
1120 pic_ref
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, xinsn
), UNSPEC_GOTOFF
);
1121 pic_ref
= gen_rtx_CONST (Pmode
, pic_ref
);
1122 pic_ref
= gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
, pic_ref
);
1123 pic_ref
= gen_const_mem (Pmode
, pic_ref
);
1130 pic_ref
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, xinsn
), UNSPEC_TEXT
);
1131 pic_ref
= gen_rtx_CONST (Pmode
, pic_ref
);
1132 pic_ref
= gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
, pic_ref
);
1138 /* This should never happen. */
1149 #define MAX_MOVE_REGS 8
1150 #define MAX_MOVE_BYTES (MAX_MOVE_REGS * UNITS_PER_WORD)
1152 /* Emit straight-line code to move LENGTH bytes from SRC to DEST.
1153 Assume that the areas do not overlap. */
1156 microblaze_block_move_straight (rtx dest
, rtx src
, HOST_WIDE_INT length
)
1158 HOST_WIDE_INT offset
, delta
;
1159 unsigned HOST_WIDE_INT bits
;
1164 bits
= BITS_PER_WORD
;
1165 mode
= int_mode_for_size (bits
, 0).require ();
1166 delta
= bits
/ BITS_PER_UNIT
;
1168 /* Allocate a buffer for the temporary registers. */
1169 regs
= XALLOCAVEC (rtx
, length
/ delta
);
1171 /* Load as many BITS-sized chunks as possible. Use a normal load if
1172 the source has enough alignment, otherwise use left/right pairs. */
1173 for (offset
= 0, i
= 0; offset
+ delta
<= length
; offset
+= delta
, i
++)
1175 regs
[i
] = gen_reg_rtx (mode
);
1176 emit_move_insn (regs
[i
], adjust_address (src
, mode
, offset
));
1179 /* Copy the chunks to the destination. */
1180 for (offset
= 0, i
= 0; offset
+ delta
<= length
; offset
+= delta
, i
++)
1181 emit_move_insn (adjust_address (dest
, mode
, offset
), regs
[i
]);
1183 /* Mop up any left-over bytes. */
1184 if (offset
< length
)
1186 src
= adjust_address (src
, BLKmode
, offset
);
1187 dest
= adjust_address (dest
, BLKmode
, offset
);
1188 move_by_pieces (dest
, src
, length
- offset
,
1189 MIN (MEM_ALIGN (src
), MEM_ALIGN (dest
)), RETURN_BEGIN
);
1193 /* Helper function for doing a loop-based block operation on memory
1194 reference MEM. Each iteration of the loop will operate on LENGTH
1197 Create a new base register for use within the loop and point it to
1198 the start of MEM. Create a new memory reference that uses this
1199 register. Store them in *LOOP_REG and *LOOP_MEM respectively. */
1202 microblaze_adjust_block_mem (rtx mem
, HOST_WIDE_INT length
,
1203 rtx
* loop_reg
, rtx
* loop_mem
)
1205 *loop_reg
= copy_addr_to_reg (XEXP (mem
, 0));
1207 /* Although the new mem does not refer to a known location,
1208 it does keep up to LENGTH bytes of alignment. */
1209 *loop_mem
= change_address (mem
, BLKmode
, *loop_reg
);
1210 set_mem_align (*loop_mem
,
1211 MIN ((HOST_WIDE_INT
) MEM_ALIGN (mem
),
1212 length
* BITS_PER_UNIT
));
1216 /* Move LENGTH bytes from SRC to DEST using a loop that moves MAX_MOVE_BYTES
1217 per iteration. LENGTH must be at least MAX_MOVE_BYTES. Assume that the
1218 memory regions do not overlap. */
1221 microblaze_block_move_loop (rtx dest
, rtx src
, HOST_WIDE_INT length
)
1223 rtx_code_label
*label
;
1224 rtx src_reg
, dest_reg
, final_src
;
1225 HOST_WIDE_INT leftover
;
1227 leftover
= length
% MAX_MOVE_BYTES
;
1230 /* Create registers and memory references for use within the loop. */
1231 microblaze_adjust_block_mem (src
, MAX_MOVE_BYTES
, &src_reg
, &src
);
1232 microblaze_adjust_block_mem (dest
, MAX_MOVE_BYTES
, &dest_reg
, &dest
);
1234 /* Calculate the value that SRC_REG should have after the last iteration
1236 final_src
= expand_simple_binop (Pmode
, PLUS
, src_reg
, GEN_INT (length
),
1239 /* Emit the start of the loop. */
1240 label
= gen_label_rtx ();
1243 /* Emit the loop body. */
1244 microblaze_block_move_straight (dest
, src
, MAX_MOVE_BYTES
);
1246 /* Move on to the next block. */
1247 emit_move_insn (src_reg
, plus_constant (Pmode
, src_reg
, MAX_MOVE_BYTES
));
1248 emit_move_insn (dest_reg
, plus_constant (Pmode
, dest_reg
, MAX_MOVE_BYTES
));
1250 /* Emit the test & branch. */
1251 emit_insn (gen_cbranchsi4 (gen_rtx_NE (SImode
, src_reg
, final_src
),
1252 src_reg
, final_src
, label
));
1254 /* Mop up any left-over bytes. */
1256 microblaze_block_move_straight (dest
, src
, leftover
);
1259 /* Expand a cpymemsi instruction. */
1262 microblaze_expand_block_move (rtx dest
, rtx src
, rtx length
, rtx align_rtx
)
1265 if (GET_CODE (length
) == CONST_INT
)
1267 unsigned HOST_WIDE_INT bytes
= UINTVAL (length
);
1268 unsigned int align
= UINTVAL (align_rtx
);
1270 if (align
> UNITS_PER_WORD
)
1272 align
= UNITS_PER_WORD
; /* We can't do any better. */
1274 else if (align
< UNITS_PER_WORD
)
1276 if (UINTVAL (length
) <= MAX_MOVE_BYTES
)
1278 move_by_pieces (dest
, src
, bytes
, align
, RETURN_BEGIN
);
1285 if (UINTVAL (length
) <= 2 * MAX_MOVE_BYTES
)
1287 microblaze_block_move_straight (dest
, src
, UINTVAL (length
));
1292 microblaze_block_move_loop (dest
, src
, UINTVAL (length
));
1300 microblaze_rtx_costs (rtx x
, machine_mode mode
, int outer_code ATTRIBUTE_UNUSED
,
1301 int opno ATTRIBUTE_UNUSED
, int *total
,
1302 bool speed ATTRIBUTE_UNUSED
)
1304 int code
= GET_CODE (x
);
1310 int num_words
= (GET_MODE_SIZE (mode
) > UNITS_PER_WORD
) ? 2 : 1;
1311 if (simple_memory_operand (x
, mode
))
1312 *total
= COSTS_N_INSNS (2 * num_words
);
1314 *total
= COSTS_N_INSNS (2 * (2 * num_words
));
1322 *total
= COSTS_N_INSNS (2);
1325 *total
= COSTS_N_INSNS (1);
1334 *total
= COSTS_N_INSNS (2);
1337 *total
= COSTS_N_INSNS (1);
1345 if (TARGET_BARREL_SHIFT
)
1347 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v5.00.a")
1349 *total
= COSTS_N_INSNS (1);
1351 *total
= COSTS_N_INSNS (2);
1353 else if (!TARGET_SOFT_MUL
)
1354 *total
= COSTS_N_INSNS (1);
1355 else if (GET_CODE (XEXP (x
, 1)) == CONST_INT
)
1357 /* Add 1 to make shift slightly more expensive than add. */
1358 *total
= COSTS_N_INSNS (INTVAL (XEXP (x
, 1))) + 1;
1359 /* Reduce shift costs for special circumstances. */
1360 if (optimize_size
&& INTVAL (XEXP (x
, 1)) > 5)
1362 if (!optimize_size
&& INTVAL (XEXP (x
, 1)) > 17)
1366 /* Double the worst cost of shifts when there is no barrel shifter and
1367 the shift amount is in a reg. */
1368 *total
= COSTS_N_INSNS (32 * 4);
1374 if (mode
== SFmode
|| mode
== DFmode
)
1376 if (TARGET_HARD_FLOAT
)
1377 *total
= COSTS_N_INSNS (6);
1380 else if (mode
== DImode
)
1382 *total
= COSTS_N_INSNS (4);
1387 *total
= COSTS_N_INSNS (1);
1396 *total
= COSTS_N_INSNS (4);
1404 if (TARGET_HARD_FLOAT
)
1405 *total
= COSTS_N_INSNS (6);
1407 else if (!TARGET_SOFT_MUL
)
1409 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v5.00.a")
1411 *total
= COSTS_N_INSNS (1);
1413 *total
= COSTS_N_INSNS (3);
1416 *total
= COSTS_N_INSNS (10);
1424 if (TARGET_HARD_FLOAT
)
1425 *total
= COSTS_N_INSNS (23);
1431 *total
= COSTS_N_INSNS (1);
1436 *total
= COSTS_N_INSNS (1);
1444 /* Return the number of instructions needed to load or store a value
1445 of mode MODE at X. Return 0 if X isn't valid for MODE. */
1448 microblaze_address_insns (rtx x
, machine_mode mode
)
1450 struct microblaze_address_info addr
;
1452 if (microblaze_classify_address (&addr
, x
, mode
, false))
1457 if (SMALL_INT (addr
.offset
))
1461 case ADDRESS_CONST_INT
:
1466 case ADDRESS_REG_INDEX
:
1468 case ADDRESS_SYMBOLIC
:
1469 case ADDRESS_SYMBOLIC_TXT_REL
:
1470 case ADDRESS_GOTOFF
:
1473 switch (addr
.tls_type
)
1491 /* Provide the costs of an addressing mode that contains ADDR.
1492 If ADDR is not a valid address, its cost is irrelevant. */
1494 microblaze_address_cost (rtx addr
, machine_mode mode ATTRIBUTE_UNUSED
,
1495 addr_space_t as ATTRIBUTE_UNUSED
,
1496 bool speed ATTRIBUTE_UNUSED
)
1498 return COSTS_N_INSNS (microblaze_address_insns (addr
, GET_MODE (addr
)));
1501 /* Return nonzero if X is an address which needs a temporary register when
1502 reloaded while generating PIC code. */
1505 pic_address_needs_scratch (rtx x
)
1507 if (GET_CODE (x
) == CONST
&& GET_CODE (XEXP (x
,0)) == PLUS
)
1511 p0
= XEXP (XEXP (x
, 0), 0);
1512 p1
= XEXP (XEXP (x
, 0), 1);
1514 if ((GET_CODE (p0
) == SYMBOL_REF
|| GET_CODE (p0
) == LABEL_REF
)
1515 && (GET_CODE (p1
) == CONST_INT
)
1516 && (flag_pic
== 2 || microblaze_tls_symbol_p (p0
) || !SMALL_INT (p1
)))
1522 /* Argument support functions. */
1523 /* Initialize CUMULATIVE_ARGS for a function. */
1526 init_cumulative_args (CUMULATIVE_ARGS
* cum
, tree fntype
,
1527 rtx libname ATTRIBUTE_UNUSED
)
1529 static CUMULATIVE_ARGS zero_cum
;
1530 tree param
, next_param
;
1534 /* Determine if this function has variable arguments. This is
1535 indicated by the last argument being 'void_type_mode' if there
1536 are no variable arguments. The standard MicroBlaze calling sequence
1537 passes all arguments in the general purpose registers in this case. */
1539 for (param
= fntype
? TYPE_ARG_TYPES (fntype
) : 0;
1540 param
!= 0; param
= next_param
)
1542 next_param
= TREE_CHAIN (param
);
1543 if (next_param
== 0 && TREE_VALUE (param
) != void_type_node
)
1544 cum
->gp_reg_found
= 1;
1548 /* Advance the argument to the next argument position. */
1551 microblaze_function_arg_advance (cumulative_args_t cum_v
,
1552 const function_arg_info
&arg
)
1554 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
1563 gcc_assert (GET_MODE_CLASS (arg
.mode
) == MODE_COMPLEX_INT
1564 || GET_MODE_CLASS (arg
.mode
) == MODE_COMPLEX_FLOAT
);
1566 cum
->gp_reg_found
= 1;
1567 cum
->arg_words
+= ((GET_MODE_SIZE (arg
.mode
) + UNITS_PER_WORD
- 1)
1572 cum
->gp_reg_found
= 1;
1573 cum
->arg_words
+= ((int_size_in_bytes (arg
.type
) + UNITS_PER_WORD
- 1)
1579 if (!cum
->gp_reg_found
&& cum
->arg_number
<= 2)
1580 cum
->fp_code
+= 1 << ((cum
->arg_number
- 1) * 2);
1584 cum
->arg_words
+= 2;
1585 if (!cum
->gp_reg_found
&& cum
->arg_number
<= 2)
1586 cum
->fp_code
+= 2 << ((cum
->arg_number
- 1) * 2);
1590 cum
->gp_reg_found
= 1;
1591 cum
->arg_words
+= 2;
1598 cum
->gp_reg_found
= 1;
1604 /* Return an RTL expression containing the register for the given argument
1605 or 0 if the argument is to be passed on the stack. */
1608 microblaze_function_arg (cumulative_args_t cum_v
, const function_arg_info
&arg
)
1610 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
1614 int *arg_words
= &cum
->arg_words
;
1616 cum
->last_arg_fp
= 0;
1627 regbase
= GP_ARG_FIRST
;
1630 gcc_assert (GET_MODE_CLASS (arg
.mode
) == MODE_COMPLEX_INT
1631 || GET_MODE_CLASS (arg
.mode
) == MODE_COMPLEX_FLOAT
);
1634 regbase
= GP_ARG_FIRST
;
1638 if (*arg_words
>= MAX_ARGS_IN_REGISTERS
)
1642 gcc_assert (regbase
!= -1);
1644 ret
= gen_rtx_REG (arg
.mode
, regbase
+ *arg_words
);
1647 if (arg
.end_marker_p ())
1649 if (cum
->num_adjusts
> 0)
1650 ret
= gen_rtx_PARALLEL ((machine_mode
) cum
->fp_code
,
1651 gen_rtvec_v (cum
->num_adjusts
, cum
->adjust
));
1657 /* Return number of bytes of argument to put in registers. */
1659 function_arg_partial_bytes (cumulative_args_t cum_v
,
1660 const function_arg_info
&arg
)
1662 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
1664 if ((arg
.mode
== BLKmode
1665 || GET_MODE_CLASS (arg
.mode
) != MODE_COMPLEX_INT
1666 || GET_MODE_CLASS (arg
.mode
) != MODE_COMPLEX_FLOAT
)
1667 && cum
->arg_words
< MAX_ARGS_IN_REGISTERS
)
1669 int words
= ((arg
.promoted_size_in_bytes () + UNITS_PER_WORD
- 1)
1671 if (words
+ cum
->arg_words
<= MAX_ARGS_IN_REGISTERS
)
1672 return 0; /* structure fits in registers */
1674 return (MAX_ARGS_IN_REGISTERS
- cum
->arg_words
) * UNITS_PER_WORD
;
1677 else if (arg
.mode
== DImode
&& cum
->arg_words
== MAX_ARGS_IN_REGISTERS
- 1)
1678 return UNITS_PER_WORD
;
1683 /* Convert a version number of the form "vX.YY.Z" to an integer encoding
1684 for easier range comparison. */
1686 microblaze_version_to_int (const char *version
)
1689 const char *tmpl
= "vXX.YY.Z";
1698 { /* Looking for major */
1705 if (!(*p
>= '0' && *p
<= '9'))
1707 iver
+= (int) (*p
- '0');
1712 { /* Looking for minor */
1713 if (!(*p
>= '0' && *p
<= '9'))
1715 iver
+= (int) (*p
- '0');
1719 { /* Looking for compat */
1720 if (!(*p
>= 'a' && *p
<= 'z'))
1723 iver
+= (int) (*p
- 'a');
1743 microblaze_option_override (void)
1750 microblaze_section_threshold
= (OPTION_SET_P (g_switch_value
)
1752 : MICROBLAZE_DEFAULT_GVALUE
);
1756 /* Make sure it's 2, we only support one kind of PIC. */
1758 if (!TARGET_SUPPORTS_PIC
)
1760 error ("%<-fPIC%>/%<-fpic%> not supported for this target");
1761 /* Clear it to avoid further errors. */
1766 /* Check the MicroBlaze CPU version for any special action to be done. */
1767 if (microblaze_select_cpu
== NULL
)
1768 microblaze_select_cpu
= MICROBLAZE_DEFAULT_CPU
;
1769 ver
= microblaze_version_to_int (microblaze_select_cpu
);
1772 error ("%qs is an invalid argument to %<-mcpu=%>", microblaze_select_cpu
);
1775 ver
= MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v3.00.a");
1778 /* No hardware exceptions in earlier versions. So no worries. */
1780 microblaze_select_flags
&= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY
);
1782 microblaze_no_unsafe_delay
= 0;
1783 microblaze_pipe
= MICROBLAZE_PIPE_3
;
1786 || (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v4.00.b")
1790 microblaze_select_flags
|= (MICROBLAZE_MASK_NO_UNSAFE_DELAY
);
1792 microblaze_no_unsafe_delay
= 1;
1793 microblaze_pipe
= MICROBLAZE_PIPE_3
;
1797 /* We agree to use 5 pipe-stage model even on area optimized 3
1798 pipe-stage variants. */
1800 microblaze_select_flags
&= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY
);
1802 microblaze_no_unsafe_delay
= 0;
1803 microblaze_pipe
= MICROBLAZE_PIPE_5
;
1804 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v5.00.a") == 0
1805 || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
,
1807 || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
,
1810 /* Pattern compares are to be turned on by default only when
1811 compiling for MB v5.00.'z'. */
1812 target_flags
|= MASK_PATTERN_COMPARE
;
1816 ver
= MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v6.00.a");
1819 if (TARGET_MULTIPLY_HIGH
)
1821 "%<-mxl-multiply-high%> can be used only with "
1822 "%<-mcpu=v6.00.a%> or greater");
1825 ver
= MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v8.10.a");
1826 microblaze_has_clz
= 1;
1829 /* MicroBlaze prior to 8.10.a didn't have clz. */
1830 microblaze_has_clz
= 0;
1833 /* TARGET_REORDER defaults to 2 if -mxl-reorder not specified. */
1834 ver
= MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v8.30.a");
1837 if (TARGET_REORDER
== 1)
1838 warning (0, "%<-mxl-reorder%> can be used only with "
1839 "%<-mcpu=v8.30.a%> or greater");
1842 else if ((ver
== 0) && !TARGET_PATTERN_COMPARE
)
1844 if (TARGET_REORDER
== 1)
1845 warning (0, "%<-mxl-reorder%> requires %<-mxl-pattern-compare%> for "
1846 "%<-mcpu=v8.30.a%>");
1850 if (TARGET_MULTIPLY_HIGH
&& TARGET_SOFT_MUL
)
1851 error ("%<-mxl-multiply-high%> requires %<-mno-xl-soft-mul%>");
1853 /* Always use DFA scheduler. */
1854 microblaze_sched_use_dfa
= 1;
1857 microblaze_abicalls
= MICROBLAZE_ABICALLS_NO
;
1860 /* Initialize the high, low values for legit floating point constants. */
1861 real_maxval (&dfhigh
, 0, DFmode
);
1862 real_maxval (&dflow
, 1, DFmode
);
1863 real_maxval (&sfhigh
, 0, SFmode
);
1864 real_maxval (&sflow
, 1, SFmode
);
1866 microblaze_print_operand_punct
['?'] = 1;
1867 microblaze_print_operand_punct
['#'] = 1;
1868 microblaze_print_operand_punct
['&'] = 1;
1869 microblaze_print_operand_punct
['!'] = 1;
1870 microblaze_print_operand_punct
['*'] = 1;
1871 microblaze_print_operand_punct
['@'] = 1;
1872 microblaze_print_operand_punct
['.'] = 1;
1873 microblaze_print_operand_punct
['('] = 1;
1874 microblaze_print_operand_punct
[')'] = 1;
1875 microblaze_print_operand_punct
['['] = 1;
1876 microblaze_print_operand_punct
[']'] = 1;
1877 microblaze_print_operand_punct
['<'] = 1;
1878 microblaze_print_operand_punct
['>'] = 1;
1879 microblaze_print_operand_punct
['{'] = 1;
1880 microblaze_print_operand_punct
['}'] = 1;
1881 microblaze_print_operand_punct
['^'] = 1;
1882 microblaze_print_operand_punct
['$'] = 1;
1883 microblaze_print_operand_punct
['+'] = 1;
1885 /* Set up array to map GCC register number to debug register number.
1886 Ignore the special purpose register numbers. */
1888 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
1889 microblaze_debugger_regno
[i
] = -1;
1891 start
= GP_DEBUGGER_FIRST
- GP_REG_FIRST
;
1892 for (i
= GP_REG_FIRST
; i
<= GP_REG_LAST
; i
++)
1893 microblaze_debugger_regno
[i
] = i
+ start
;
1895 /* Set up array giving whether a given register can hold a given mode. */
1897 for (mode
= VOIDmode
;
1898 mode
!= MAX_MACHINE_MODE
; mode
= (machine_mode
) ((int) mode
+ 1))
1900 int size
= GET_MODE_SIZE (mode
);
1902 for (regno
= 0; regno
< FIRST_PSEUDO_REGISTER
; regno
++)
1908 ok
= (ST_REG_P (regno
) || GP_REG_P (regno
));
1910 else if (GP_REG_P (regno
))
1911 ok
= ((regno
& 1) == 0 || size
<= UNITS_PER_WORD
);
1915 microblaze_hard_regno_mode_ok_p
[(int) mode
][regno
] = ok
;
1920 /* Implement TARGET_HARD_REGNO_MODE_OK. In 32 bit mode, require that
1921 DImode and DFmode be in even registers. For DImode, this makes some
1922 of the insns easier to write, since you don't have to worry about a
1923 DImode value in registers 3 & 4, producing a result in 4 & 5.
1925 To make the code simpler, the hook now just references an
1926 array built in override_options. */
1929 microblaze_hard_regno_mode_ok (unsigned int regno
, machine_mode mode
)
1931 return microblaze_hard_regno_mode_ok_p
[mode
][regno
];
1934 /* Implement TARGET_MODES_TIEABLE_P. */
1937 microblaze_modes_tieable_p (machine_mode mode1
, machine_mode mode2
)
1939 return ((GET_MODE_CLASS (mode1
) == MODE_FLOAT
1940 || GET_MODE_CLASS (mode1
) == MODE_COMPLEX_FLOAT
)
1941 == (GET_MODE_CLASS (mode2
) == MODE_FLOAT
1942 || GET_MODE_CLASS (mode2
) == MODE_COMPLEX_FLOAT
));
1945 /* Return true if FUNC is an interrupt function as specified
1946 by the "interrupt_handler" attribute. */
1949 microblaze_interrupt_function_p (tree func
)
1953 if (TREE_CODE (func
) != FUNCTION_DECL
)
1956 a
= lookup_attribute ("interrupt_handler", DECL_ATTRIBUTES (func
));
1957 return a
!= NULL_TREE
;
1961 microblaze_fast_interrupt_function_p (tree func
)
1965 if (TREE_CODE (func
) != FUNCTION_DECL
)
1968 a
= lookup_attribute ("fast_interrupt", DECL_ATTRIBUTES (func
));
1969 return a
!= NULL_TREE
;
1972 microblaze_break_function_p (tree func
)
1977 if (TREE_CODE (func
) != FUNCTION_DECL
)
1980 a
= lookup_attribute ("break_handler", DECL_ATTRIBUTES (func
));
1981 return a
!= NULL_TREE
;
1983 /* Return true if FUNC is an interrupt function which uses
1984 normal return, indicated by the "save_volatiles" attribute. */
1987 microblaze_save_volatiles (tree func
)
1991 if (TREE_CODE (func
) != FUNCTION_DECL
)
1994 a
= lookup_attribute ("save_volatiles", DECL_ATTRIBUTES (func
));
1995 return a
!= NULL_TREE
;
1998 /* Return whether function is tagged with 'interrupt_handler'
1999 or 'fast_interrupt' attribute. Return true if function
2000 should use return from interrupt rather than normal
2003 microblaze_is_interrupt_variant (void)
2005 return (interrupt_handler
|| fast_interrupt
);
2008 microblaze_is_break_handler (void)
2010 return break_handler
;
2013 /* Determine of register must be saved/restored in call. */
2015 microblaze_must_save_register (int regno
)
2017 if (pic_offset_table_rtx
&&
2018 (regno
== MB_ABI_PIC_ADDR_REGNUM
) && df_regs_ever_live_p (regno
))
2021 if (df_regs_ever_live_p (regno
) && !call_used_or_fixed_reg_p (regno
))
2024 if (frame_pointer_needed
&& (regno
== HARD_FRAME_POINTER_REGNUM
))
2027 if (crtl
->calls_eh_return
2028 && regno
== MB_ABI_SUB_RETURN_ADDR_REGNUM
)
2033 if (regno
== MB_ABI_SUB_RETURN_ADDR_REGNUM
)
2035 if ((microblaze_is_interrupt_variant () || save_volatiles
) &&
2036 (regno
>= 3 && regno
<= 12))
2040 if (microblaze_is_interrupt_variant ())
2042 if (df_regs_ever_live_p (regno
)
2043 || regno
== MB_ABI_MSR_SAVE_REG
2044 || ((interrupt_handler
|| fast_interrupt
)
2045 && (regno
== MB_ABI_ASM_TEMP_REGNUM
2046 || regno
== MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM
)))
2052 if (df_regs_ever_live_p (regno
)
2053 || regno
== MB_ABI_ASM_TEMP_REGNUM
2054 || regno
== MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM
)
2058 if (crtl
->calls_eh_return
2059 && (regno
== EH_RETURN_DATA_REGNO (0)
2060 || regno
== EH_RETURN_DATA_REGNO (1)))
2066 /* Return the bytes needed to compute the frame pointer from the current
2069 MicroBlaze stack frames look like:
2073 Before call After call
2074 +-----------------------+ +-----------------------+
2076 mem. | local variables, | | local variables, |
2077 | callee saved and | | callee saved and |
2079 +-----------------------+ +-----------------------+
2080 | arguments for called | | arguments for called |
2081 | subroutines | | subroutines |
2082 | (optional) | | (optional) |
2083 +-----------------------+ +-----------------------+
2084 | Link register | | Link register |
2086 +-----------------------+ +-----------------------+
2088 | local variables, |
2089 | callee saved and |
2091 +-----------------------+
2092 | MSR (optional if, |
2093 | interrupt handler) |
2094 +-----------------------+
2096 | alloca allocations |
2098 +-----------------------+
2100 | arguments for called |
2104 +-----------------------+
2107 memory +-----------------------+
2111 static HOST_WIDE_INT
2112 compute_frame_size (HOST_WIDE_INT size
)
2115 HOST_WIDE_INT total_size
; /* # bytes that the entire frame takes up. */
2116 HOST_WIDE_INT var_size
; /* # bytes that local variables take up. */
2117 HOST_WIDE_INT args_size
; /* # bytes that outgoing arguments take up. */
2118 int link_debug_size
; /* # bytes for link register. */
2119 HOST_WIDE_INT gp_reg_size
; /* # bytes needed to store calle-saved gp regs. */
2120 long mask
; /* mask of saved gp registers. */
2123 microblaze_interrupt_function_p (current_function_decl
);
2125 microblaze_break_function_p (current_function_decl
);
2128 microblaze_fast_interrupt_function_p (current_function_decl
);
2129 save_volatiles
= microblaze_save_volatiles (current_function_decl
);
2131 interrupt_handler
= break_handler
;
2136 args_size
= crtl
->outgoing_args_size
;
2138 if ((args_size
== 0) && cfun
->calls_alloca
)
2139 args_size
= NUM_OF_ARGS
* UNITS_PER_WORD
;
2141 total_size
= var_size
+ args_size
;
2143 if (flag_pic
== 2 && !TARGET_PIC_DATA_TEXT_REL
)
2144 /* force setting GOT. */
2145 df_set_regs_ever_live (MB_ABI_PIC_ADDR_REGNUM
, true);
2147 /* Calculate space needed for gp registers. */
2148 for (regno
= GP_REG_FIRST
; regno
<= GP_REG_LAST
; regno
++)
2150 if (microblaze_must_save_register (regno
))
2153 if (regno
!= MB_ABI_SUB_RETURN_ADDR_REGNUM
)
2154 /* Don't account for link register. It is accounted specially below. */
2155 gp_reg_size
+= GET_MODE_SIZE (SImode
);
2157 mask
|= (1L << (regno
- GP_REG_FIRST
));
2161 total_size
+= gp_reg_size
;
2163 /* Add 4 bytes for MSR. */
2164 if (microblaze_is_interrupt_variant ())
2167 /* No space to be allocated for link register in leaf functions with no other
2168 stack requirements. */
2169 if (total_size
== 0 && crtl
->is_leaf
)
2170 link_debug_size
= 0;
2172 link_debug_size
= UNITS_PER_WORD
;
2174 total_size
+= link_debug_size
;
2176 /* Save other computed information. */
2177 current_frame_info
.total_size
= total_size
;
2178 current_frame_info
.var_size
= var_size
;
2179 current_frame_info
.args_size
= args_size
;
2180 current_frame_info
.gp_reg_size
= gp_reg_size
;
2181 current_frame_info
.mask
= mask
;
2182 current_frame_info
.initialized
= reload_completed
;
2183 current_frame_info
.num_gp
= gp_reg_size
/ UNITS_PER_WORD
;
2184 current_frame_info
.link_debug_size
= link_debug_size
;
2187 /* Offset from which to callee-save GP regs. */
2188 current_frame_info
.gp_offset
= (total_size
- gp_reg_size
);
2190 current_frame_info
.gp_offset
= 0;
2192 /* Ok, we're done. */
2196 /* Make sure that we're not trying to eliminate to the wrong hard frame
2200 microblaze_can_eliminate (const int from
, const int to
)
2202 return ((from
== RETURN_ADDRESS_POINTER_REGNUM
&& !leaf_function_p())
2203 || (to
== MB_ABI_SUB_RETURN_ADDR_REGNUM
&& leaf_function_p())
2204 || (from
!= RETURN_ADDRESS_POINTER_REGNUM
2205 && (to
== HARD_FRAME_POINTER_REGNUM
2206 || (to
== STACK_POINTER_REGNUM
&& !frame_pointer_needed
))));
2209 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
2210 pointer or argument pointer or the return address pointer. TO is either
2211 the stack pointer or hard frame pointer. */
2214 microblaze_initial_elimination_offset (int from
, int to
)
2216 HOST_WIDE_INT offset
;
2220 case FRAME_POINTER_REGNUM
:
2223 case ARG_POINTER_REGNUM
:
2224 if (to
== STACK_POINTER_REGNUM
|| to
== HARD_FRAME_POINTER_REGNUM
)
2225 offset
= compute_frame_size (get_frame_size ());
2229 case RETURN_ADDRESS_POINTER_REGNUM
:
2233 offset
= current_frame_info
.gp_offset
+
2234 ((UNITS_PER_WORD
- (POINTER_SIZE
/ BITS_PER_UNIT
)));
2242 /* Print operands using format code.
2244 The MicroBlaze specific codes are:
2246 'X' X is CONST_INT, prints 32 bits in hexadecimal format = "0x%08x",
2247 'x' X is CONST_INT, prints 16 bits in hexadecimal format = "0x%04x",
2248 'F' op is CONST_DOUBLE, print 32 bits in hex,
2249 'd' output integer constant in decimal,
2250 'z' if the operand is 0, use $0 instead of normal operand.
2251 'D' print second register of double-word register operand.
2252 'L' print low-order register of double-word register operand.
2253 'M' print high-order register of double-word register operand.
2254 'C' print part of opcode for a branch condition.
2255 'N' print part of opcode for a branch condition, inverted.
2256 'S' X is CODE_LABEL, print with prefix of "LS" (for embedded switch).
2257 'B' print 'z' for EQ, 'n' for NE
2258 'b' print 'n' for EQ, 'z' for NE
2259 'T' print 'f' for EQ, 't' for NE
2260 't' print 't' for EQ, 'f' for NE
2261 'm' Print 1<<operand.
2262 'i' Print 'i' if MEM operand has immediate value
2263 'y' Print 'y' if MEM operand is single register
2264 'o' Print operand address+4
2265 '?' Print 'd' if we use a branch with delay slot instead of normal branch.
2266 'h' Print high word of const_double (int or float) value as hex
2267 'j' Print low word of const_double (int or float) value as hex
2268 's' Print -1 if operand is negative, 0 if positive (sign extend)
2269 '@' Print the name of the temporary register (rMB_ABI_ASM_TEMP_REGNUM).
2270 '#' Print nop if the delay slot of a branch is not filled.
2274 print_operand (FILE * file
, rtx op
, int letter
)
2278 if (PRINT_OPERAND_PUNCT_VALID_P (letter
))
2283 /* Conditionally add a 'd' to indicate filled delay slot. */
2284 if (final_sequence
!= NULL
)
2289 /* Conditionally add a nop in unfilled delay slot. */
2290 if (final_sequence
== NULL
)
2291 fputs ("nop\t\t# Unfilled delay slot\n", file
);
2295 fputs (reg_names
[GP_REG_FIRST
+ MB_ABI_ASM_TEMP_REGNUM
], file
);
2299 output_operand_lossage ("unknown punctuation '%c'", letter
);
2308 output_operand_lossage ("null pointer");
2312 code
= GET_CODE (op
);
2314 if (code
== SIGN_EXTEND
)
2315 op
= XEXP (op
, 0), code
= GET_CODE (op
);
2343 fatal_insn ("PRINT_OPERAND, invalid insn for %%C", op
);
2346 else if (letter
== 'N')
2372 fatal_insn ("PRINT_OPERAND, invalid insn for %%N", op
);
2375 else if (letter
== 'S')
2379 ASM_GENERATE_INTERNAL_LABEL (buffer
, "LS", CODE_LABEL_NUMBER (op
));
2380 assemble_name (file
, buffer
);
2383 /* Print 'i' for memory operands which have immediate values. */
2384 else if (letter
== 'i')
2388 struct microblaze_address_info info
;
2390 if (!microblaze_classify_address
2391 (&info
, XEXP (op
, 0), GET_MODE (op
), 1))
2392 fatal_insn ("insn contains an invalid address !", op
);
2397 case ADDRESS_CONST_INT
:
2398 case ADDRESS_SYMBOLIC
:
2399 case ADDRESS_SYMBOLIC_TXT_REL
:
2400 case ADDRESS_GOTOFF
:
2404 case ADDRESS_REG_INDEX
:
2406 case ADDRESS_INVALID
:
2408 fatal_insn ("invalid address", op
);
2413 else if (code
== REG
|| code
== SUBREG
)
2418 regnum
= REGNO (op
);
2420 regnum
= true_regnum (op
);
2422 if ((letter
== 'M' && !WORDS_BIG_ENDIAN
)
2423 || (letter
== 'L' && WORDS_BIG_ENDIAN
) || letter
== 'D')
2426 fprintf (file
, "%s", reg_names
[regnum
]);
2429 else if (code
== MEM
)
2432 rtx op4
= adjust_address (op
, GET_MODE (op
), 4);
2433 output_address (GET_MODE (op
), XEXP (op4
, 0));
2435 else if (letter
== 'y')
2437 rtx mem_reg
= XEXP (op
, 0);
2438 if (GET_CODE (mem_reg
) == REG
)
2440 int regnum
= REGNO (mem_reg
);
2441 fprintf (file
, "%s", reg_names
[regnum
]);
2445 output_address (GET_MODE (op
), XEXP (op
, 0));
2447 else if (letter
== 'h' || letter
== 'j')
2450 if (code
== CONST_DOUBLE
)
2452 if (GET_MODE (op
) == DFmode
)
2453 REAL_VALUE_TO_TARGET_DOUBLE (*CONST_DOUBLE_REAL_VALUE (op
), val
);
2456 val
[0] = CONST_DOUBLE_HIGH (op
);
2457 val
[1] = CONST_DOUBLE_LOW (op
);
2460 else if (code
== CONST_INT
)
2462 val
[0] = (INTVAL (op
) & 0xffffffff00000000LL
) >> 32;
2463 val
[1] = INTVAL (op
) & 0x00000000ffffffffLL
;
2464 if (val
[0] == 0 && val
[1] < 0)
2468 fprintf (file
, "0x%8.8lx", (letter
== 'h') ? val
[0] : val
[1]);
2470 else if (code
== CONST_DOUBLE
)
2474 unsigned long value_long
;
2475 REAL_VALUE_TO_TARGET_SINGLE (*CONST_DOUBLE_REAL_VALUE (op
),
2477 fprintf (file
, "0x%lx", value_long
);
2482 real_to_decimal (s
, CONST_DOUBLE_REAL_VALUE (op
), sizeof (s
), 0, 1);
2487 else if (code
== UNSPEC
)
2489 print_operand_address (file
, op
);
2492 else if (letter
== 'x' && GET_CODE (op
) == CONST_INT
)
2493 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, 0xffff & INTVAL (op
));
2495 else if (letter
== 'X' && GET_CODE (op
) == CONST_INT
)
2496 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, INTVAL (op
));
2498 else if (letter
== 'd' && GET_CODE (op
) == CONST_INT
)
2499 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, (INTVAL (op
)));
2501 else if (letter
== 'z' && GET_CODE (op
) == CONST_INT
&& INTVAL (op
) == 0)
2502 fputs (reg_names
[GP_REG_FIRST
], file
);
2504 else if (letter
== 's' && GET_CODE (op
) == CONST_INT
)
2505 if (INTVAL (op
) < 0)
2510 else if (letter
== 'd' || letter
== 'x' || letter
== 'X' || letter
== 's')
2511 output_operand_lossage ("letter %c was found & insn was not CONST_INT", letter
);
2513 else if (letter
== 'B')
2514 fputs (code
== EQ
? "z" : "n", file
);
2515 else if (letter
== 'b')
2516 fputs (code
== EQ
? "n" : "z", file
);
2517 else if (letter
== 'T')
2518 fputs (code
== EQ
? "f" : "t", file
);
2519 else if (letter
== 't')
2520 fputs (code
== EQ
? "t" : "f", file
);
2522 else if (code
== CONST
2523 && ((GET_CODE (XEXP (op
, 0)) == REG
)
2524 || (GET_CODE (XEXP (op
, 0)) == UNSPEC
)))
2526 print_operand (file
, XEXP (op
, 0), letter
);
2528 else if (code
== CONST
2529 && (GET_CODE (XEXP (op
, 0)) == PLUS
)
2530 && (GET_CODE (XEXP (XEXP (op
, 0), 0)) == REG
)
2531 && (GET_CODE (XEXP (XEXP (op
, 0), 1)) == CONST
))
2533 print_operand_address (file
, XEXP (op
, 0));
2535 else if (letter
== 'm')
2536 fprintf (file
, "%ld", (1L << INTVAL (op
)));
2538 output_addr_const (file
, op
);
2541 /* A C compound statement to output to stdio stream STREAM the
2542 assembler syntax for an instruction operand that is a memory
2543 reference whose address is ADDR. ADDR is an RTL expression.
2545 Possible address classifications and output formats are,
2547 ADDRESS_REG "%0, r0"
2549 ADDRESS_REG with non-zero "%0, <addr_const>"
2552 ADDRESS_REG_INDEX "rA, RB"
2553 (if rA is r0, rA and rB are swapped)
2555 ADDRESS_CONST_INT "r0, <addr_const>"
2557 ADDRESS_SYMBOLIC "rBase, <addr_const>"
2558 (rBase is a base register suitable for the
2563 print_operand_address (FILE * file
, rtx addr
)
2565 struct microblaze_address_info info
;
2566 enum microblaze_address_type type
;
2567 if (!microblaze_classify_address (&info
, addr
, GET_MODE (addr
), 2))
2568 fatal_insn ("insn contains an invalid address !", addr
);
2574 fprintf (file
, "%s,", reg_names
[REGNO (info
.regA
)]);
2575 output_addr_const (file
, info
.offset
);
2577 case ADDRESS_REG_INDEX
:
2578 if (REGNO (info
.regA
) == 0)
2579 /* Make rB == r0 instead of rA == r0. This helps reduce read port
2581 fprintf (file
, "%s,%s", reg_names
[REGNO (info
.regB
)],
2582 reg_names
[REGNO (info
.regA
)]);
2583 else if (REGNO (info
.regB
) != 0)
2584 /* This is a silly swap to help Dhrystone. */
2585 fprintf (file
, "%s,%s", reg_names
[REGNO (info
.regB
)],
2586 reg_names
[REGNO (info
.regA
)]);
2588 case ADDRESS_CONST_INT
:
2589 fprintf (file
, "%s,", reg_names
[REGNO (info
.regA
)]);
2590 output_addr_const (file
, info
.offset
);
2592 case ADDRESS_SYMBOLIC
:
2593 case ADDRESS_SYMBOLIC_TXT_REL
:
2594 case ADDRESS_GOTOFF
:
2598 fprintf (file
, "%s,", reg_names
[REGNO (info
.regA
)]);
2599 output_addr_const (file
, info
.symbol
);
2600 if (type
== ADDRESS_GOTOFF
)
2602 fputs ("@GOT", file
);
2604 else if (type
== ADDRESS_PLT
)
2606 fputs ("@PLT", file
);
2608 else if (type
== ADDRESS_SYMBOLIC_TXT_REL
)
2610 if (info
.offset
!= NULL
&& CONST_INT_P (info
.offset
)
2611 && INTVAL (info
.offset
) > 0)
2613 fprintf (file
, "+");
2614 output_addr_const (file
, info
.offset
);
2616 fputs ("@TXTREL", file
);
2618 else if (type
== ADDRESS_TLS
)
2620 switch (info
.tls_type
)
2623 fputs ("@TLSGD", file
);
2626 fputs ("@TLSLDM", file
);
2629 fputs ("@TLSDTPREL", file
);
2637 case ADDRESS_INVALID
:
2638 fatal_insn ("invalid address", addr
);
2643 /* Emit either a label, .comm, or .lcomm directive, and mark that the symbol
2644 is used, so that we don't emit an .extern for it in
2645 microblaze_asm_file_end. */
2648 microblaze_declare_object (FILE * stream
, const char *name
,
2649 const char *section
, const char *fmt
, int size
)
2652 fputs (section
, stream
);
2653 assemble_name (stream
, name
);
2654 fprintf (stream
, fmt
, size
);
2657 /* Common code to emit the insns (or to write the instructions to a file)
2658 to save/restore registers.
2660 Other parts of the code assume that MICROBLAZE_TEMP1_REGNUM (aka large_reg)
2661 is not modified within save_restore_insns. */
2663 #define BITSET_P(VALUE,BIT) (((VALUE) & (1L << (BIT))) != 0)
2665 /* Save or restore instructions based on whether this is the prologue or
2666 epilogue. prologue is 1 for the prologue. */
2668 save_restore_insns (int prologue
)
2670 rtx base_reg_rtx
, reg_rtx
, mem_rtx
, /* msr_rtx, */ isr_reg_rtx
=
2672 rtx isr_msr_rtx
= 0, insn
;
2673 long mask
= current_frame_info
.mask
;
2674 HOST_WIDE_INT gp_offset
;
2677 if (frame_pointer_needed
2678 && !BITSET_P (mask
, HARD_FRAME_POINTER_REGNUM
- GP_REG_FIRST
))
2684 /* Save registers starting from high to low. The debuggers prefer at least
2685 the return register be stored at func+4, and also it allows us not to
2686 need a nop in the epilog if at least one register is reloaded in
2687 addition to return address. */
2689 /* Pick which pointer to use as a base register. For small frames, just
2690 use the stack pointer. Otherwise, use a temporary register. Save 2
2691 cycles if the save area is near the end of a large frame, by reusing
2692 the constant created in the prologue/epilogue to adjust the stack
2695 gp_offset
= current_frame_info
.gp_offset
;
2697 gcc_assert (gp_offset
> 0);
2699 base_reg_rtx
= stack_pointer_rtx
;
2701 /* For interrupt_handlers, need to save/restore the MSR. */
2702 if (microblaze_is_interrupt_variant ())
2704 isr_mem_rtx
= gen_rtx_MEM (SImode
,
2705 gen_rtx_PLUS (Pmode
, base_reg_rtx
,
2706 GEN_INT (current_frame_info
.
2710 /* Do not optimize in flow analysis. */
2711 MEM_VOLATILE_P (isr_mem_rtx
) = 1;
2712 isr_reg_rtx
= gen_rtx_REG (SImode
, MB_ABI_MSR_SAVE_REG
);
2713 isr_msr_rtx
= gen_rtx_REG (SImode
, ST_REG
);
2716 if (microblaze_is_interrupt_variant () && !prologue
)
2718 emit_move_insn (isr_reg_rtx
, isr_mem_rtx
);
2719 emit_move_insn (isr_msr_rtx
, isr_reg_rtx
);
2720 /* Do not optimize in flow analysis. */
2721 emit_insn (gen_rtx_USE (SImode
, isr_reg_rtx
));
2722 emit_insn (gen_rtx_USE (SImode
, isr_msr_rtx
));
2725 for (regno
= GP_REG_FIRST
; regno
<= GP_REG_LAST
; regno
++)
2727 if (BITSET_P (mask
, regno
- GP_REG_FIRST
))
2729 if (regno
== MB_ABI_SUB_RETURN_ADDR_REGNUM
)
2730 /* Don't handle here. Already handled as the first register. */
2733 reg_rtx
= gen_rtx_REG (SImode
, regno
);
2734 insn
= gen_rtx_PLUS (Pmode
, base_reg_rtx
, GEN_INT (gp_offset
));
2735 mem_rtx
= gen_rtx_MEM (SImode
, insn
);
2736 if (microblaze_is_interrupt_variant () || save_volatiles
)
2737 /* Do not optimize in flow analysis. */
2738 MEM_VOLATILE_P (mem_rtx
) = 1;
2742 insn
= emit_move_insn (mem_rtx
, reg_rtx
);
2743 RTX_FRAME_RELATED_P (insn
) = 1;
2747 insn
= emit_move_insn (reg_rtx
, mem_rtx
);
2750 gp_offset
+= GET_MODE_SIZE (SImode
);
2754 if (microblaze_is_interrupt_variant () && prologue
)
2756 emit_move_insn (isr_reg_rtx
, isr_msr_rtx
);
2757 emit_move_insn (isr_mem_rtx
, isr_reg_rtx
);
2759 /* Do not optimize in flow analysis. */
2760 emit_insn (gen_rtx_USE (SImode
, isr_reg_rtx
));
2761 emit_insn (gen_rtx_USE (SImode
, isr_msr_rtx
));
2764 /* Done saving and restoring */
2768 /* Set up the stack and frame (if desired) for the function. */
2770 microblaze_function_prologue (FILE * file
)
2773 long fsiz
= current_frame_info
.total_size
;
2775 /* Get the function name the same way that toplev.cc does before calling
2776 assemble_start_function. This is needed so that the name used here
2777 exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */
2778 fnname
= XSTR (XEXP (DECL_RTL (current_function_decl
), 0), 0);
2779 if (!flag_inhibit_size_directive
)
2781 fputs ("\t.ent\t", file
);
2782 if (interrupt_handler
&& strcmp (INTERRUPT_HANDLER_NAME
, fnname
))
2783 fputs ("_interrupt_handler", file
);
2784 else if (break_handler
&& strcmp (BREAK_HANDLER_NAME
, fnname
))
2785 fputs ("_break_handler", file
);
2786 else if (fast_interrupt
&& strcmp (FAST_INTERRUPT_NAME
, fnname
))
2787 fputs ("_fast_interrupt", file
);
2789 assemble_name (file
, fnname
);
2791 if (!microblaze_is_interrupt_variant ())
2792 ASM_OUTPUT_TYPE_DIRECTIVE (file
, fnname
, "function");
2795 ASM_OUTPUT_FUNCTION_LABEL (file
, fnname
, current_function_decl
);
2797 if (interrupt_handler
&& strcmp (INTERRUPT_HANDLER_NAME
, fnname
))
2798 fputs ("_interrupt_handler:\n", file
);
2799 if (break_handler
&& strcmp (BREAK_HANDLER_NAME
, fnname
))
2800 fputs ("_break_handler:\n", file
);
2801 if (!flag_inhibit_size_directive
)
2803 /* .frame FRAMEREG, FRAMESIZE, RETREG. */
2805 "\t.frame\t%s,%ld,%s\t\t# vars= %ld, regs= %d, args= %d\n",
2806 (reg_names
[(frame_pointer_needed
)
2807 ? HARD_FRAME_POINTER_REGNUM
:
2808 STACK_POINTER_REGNUM
]), fsiz
,
2809 reg_names
[MB_ABI_SUB_RETURN_ADDR_REGNUM
+ GP_REG_FIRST
],
2810 current_frame_info
.var_size
, current_frame_info
.num_gp
,
2811 (int) crtl
->outgoing_args_size
);
2812 fprintf (file
, "\t.mask\t0x%08lx\n", current_frame_info
.mask
);
2816 /* Output extra assembler code at the end of a prologue. */
2818 microblaze_function_end_prologue (FILE * file
)
2820 if (TARGET_STACK_CHECK
)
2822 fprintf (file
, "\t# Stack Check Stub -- Start.\n\t");
2823 fprintf (file
, "ori\tr18,r0,_stack_end\n\t");
2824 fprintf (file
, "cmpu\tr18,r1,r18\n\t");
2825 fprintf (file
, "bgei\tr18,_stack_overflow_exit\n\t");
2826 fprintf (file
, "# Stack Check Stub -- End.\n");
2831 microblaze_elf_asm_cdtor (rtx symbol
, int priority
, bool is_ctor
)
2835 if (priority
!= DEFAULT_INIT_PRIORITY
)
2838 sprintf (buf
, "%s.%.5u",
2839 is_ctor
? ".ctors" : ".dtors",
2840 MAX_INIT_PRIORITY
- priority
);
2841 s
= get_section (buf
, SECTION_WRITE
, NULL_TREE
);
2848 switch_to_section (s
);
2849 assemble_align (POINTER_SIZE
);
2850 fputs ("\t.word\t", asm_out_file
);
2851 output_addr_const (asm_out_file
, symbol
);
2852 fputs ("\n", asm_out_file
);
2855 /* Add a function to the list of static constructors. */
2858 microblaze_elf_asm_constructor (rtx symbol
, int priority
)
2860 microblaze_elf_asm_cdtor (symbol
, priority
, /*is_ctor=*/true);
2863 /* Add a function to the list of static destructors. */
2866 microblaze_elf_asm_destructor (rtx symbol
, int priority
)
2868 microblaze_elf_asm_cdtor (symbol
, priority
, /*is_ctor=*/false);
2871 /* Expand the prologue into a bunch of separate insns. */
2874 microblaze_expand_prologue (void)
2878 const char *arg_name
= 0;
2879 tree fndecl
= current_function_decl
;
2880 tree fntype
= TREE_TYPE (fndecl
);
2881 tree fnargs
= DECL_ARGUMENTS (fndecl
);
2886 CUMULATIVE_ARGS args_so_far_v
;
2887 cumulative_args_t args_so_far
;
2888 rtx mem_rtx
, reg_rtx
;
2890 /* If struct value address is treated as the first argument, make it so. */
2891 if (aggregate_value_p (DECL_RESULT (fndecl
), fntype
)
2892 && !cfun
->returns_pcc_struct
)
2894 tree type
= build_pointer_type (fntype
);
2895 tree function_result_decl
= build_decl (BUILTINS_LOCATION
, PARM_DECL
,
2898 DECL_ARG_TYPE (function_result_decl
) = type
;
2899 TREE_CHAIN (function_result_decl
) = fnargs
;
2900 fnargs
= function_result_decl
;
2903 /* Determine the last argument, and get its name. */
2905 INIT_CUMULATIVE_ARGS (args_so_far_v
, fntype
, NULL_RTX
, 0, 0);
2906 args_so_far
= pack_cumulative_args (&args_so_far_v
);
2907 regno
= GP_ARG_FIRST
;
2909 for (cur_arg
= fnargs
; cur_arg
!= 0; cur_arg
= next_arg
)
2911 tree passed_type
= DECL_ARG_TYPE (cur_arg
);
2912 machine_mode passed_mode
= TYPE_MODE (passed_type
);
2915 if (TREE_ADDRESSABLE (passed_type
))
2917 passed_type
= build_pointer_type (passed_type
);
2918 passed_mode
= Pmode
;
2921 function_arg_info
arg (passed_type
, passed_mode
, /*named=*/true);
2922 entry_parm
= targetm
.calls
.function_arg (args_so_far
, arg
);
2928 /* passed in a register, so will get homed automatically. */
2929 if (GET_MODE (entry_parm
) == BLKmode
)
2930 words
= (int_size_in_bytes (passed_type
) + 3) / 4;
2932 words
= (GET_MODE_SIZE (GET_MODE (entry_parm
)) + 3) / 4;
2934 regno
= REGNO (entry_parm
) + words
- 1;
2938 regno
= GP_ARG_LAST
+ 1;
2942 targetm
.calls
.function_arg_advance (args_so_far
, arg
);
2944 next_arg
= TREE_CHAIN (cur_arg
);
2947 if (DECL_NAME (cur_arg
))
2948 arg_name
= IDENTIFIER_POINTER (DECL_NAME (cur_arg
));
2954 /* Split parallel insn into a sequence of insns. */
2956 next_arg_reg
= targetm
.calls
.function_arg (args_so_far
,
2957 function_arg_info::end_marker ());
2958 if (next_arg_reg
!= 0 && GET_CODE (next_arg_reg
) == PARALLEL
)
2960 rtvec adjust
= XVEC (next_arg_reg
, 0);
2961 int num
= GET_NUM_ELEM (adjust
);
2963 for (i
= 0; i
< num
; i
++)
2965 rtx pattern
= RTVEC_ELT (adjust
, i
);
2966 emit_insn (pattern
);
2970 fsiz
= compute_frame_size (get_frame_size ());
2972 if (flag_stack_usage_info
)
2973 current_function_static_stack_size
= fsiz
;
2975 /* If this function is a varargs function, store any registers that
2976 would normally hold arguments ($5 - $10) on the stack. */
2977 if (((TYPE_ARG_TYPES (fntype
) != 0
2978 && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype
)))
2981 && ((arg_name
[0] == '_'
2982 && strcmp (arg_name
, "__builtin_va_alist") == 0)
2983 || (arg_name
[0] == 'v'
2984 && strcmp (arg_name
, "va_alist") == 0)))))
2986 int offset
= (regno
- GP_ARG_FIRST
+ 1) * UNITS_PER_WORD
;
2987 rtx ptr
= stack_pointer_rtx
;
2989 /* If we are doing svr4-abi, sp has already been decremented by fsiz. */
2990 for (; regno
<= GP_ARG_LAST
; regno
++)
2993 ptr
= gen_rtx_PLUS (Pmode
, stack_pointer_rtx
, GEN_INT (offset
));
2994 emit_move_insn (gen_rtx_MEM (SImode
, ptr
),
2995 gen_rtx_REG (SImode
, regno
));
2997 offset
+= GET_MODE_SIZE (SImode
);
3003 rtx fsiz_rtx
= GEN_INT (fsiz
);
3005 rtx_insn
*insn
= NULL
;
3006 insn
= emit_insn (gen_subsi3 (stack_pointer_rtx
, stack_pointer_rtx
,
3009 RTX_FRAME_RELATED_P (insn
) = 1;
3011 /* Handle SUB_RETURN_ADDR_REGNUM specially at first. */
3012 if (!crtl
->is_leaf
|| interrupt_handler
)
3014 mem_rtx
= gen_rtx_MEM (SImode
,
3015 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
3018 if (interrupt_handler
)
3019 /* Do not optimize in flow analysis. */
3020 MEM_VOLATILE_P (mem_rtx
) = 1;
3022 reg_rtx
= gen_rtx_REG (SImode
, MB_ABI_SUB_RETURN_ADDR_REGNUM
);
3023 insn
= emit_move_insn (mem_rtx
, reg_rtx
);
3024 RTX_FRAME_RELATED_P (insn
) = 1;
3027 /* _save_ registers for prologue. */
3028 save_restore_insns (1);
3030 if (frame_pointer_needed
)
3034 insn
= emit_insn (gen_movsi (hard_frame_pointer_rtx
,
3035 stack_pointer_rtx
));
3038 RTX_FRAME_RELATED_P (insn
) = 1;
3042 if ((flag_pic
== 2 || TLS_NEEDS_GOT
)
3043 && df_regs_ever_live_p (MB_ABI_PIC_ADDR_REGNUM
))
3045 if ((flag_pic
== 2 && !TARGET_PIC_DATA_TEXT_REL
) || TLS_NEEDS_GOT
)
3047 SET_REGNO (pic_offset_table_rtx
, MB_ABI_PIC_ADDR_REGNUM
);
3049 emit_insn (gen_set_got (pic_offset_table_rtx
));
3053 SET_REGNO (pic_offset_table_rtx
, MB_ABI_PIC_ADDR_REGNUM
);
3054 /* setting start of text. */
3055 emit_insn (gen_set_text (pic_offset_table_rtx
));
3059 /* If we are profiling, make sure no instructions are scheduled before
3060 the call to mcount. */
3063 emit_insn (gen_blockage ());
3066 /* Do necessary cleanup after a function to restore stack, frame, and regs. */
3068 #define RA_MASK ((long) 0x80000000) /* 1 << 31 */
3069 #define PIC_OFFSET_TABLE_MASK (1 << (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST))
3072 microblaze_function_epilogue (FILE *file
)
3076 /* Get the function name the same way that toplev.cc does before calling
3077 assemble_start_function. This is needed so that the name used here
3078 exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */
3079 fnname
= XSTR (XEXP (DECL_RTL (current_function_decl
), 0), 0);
3081 if (!flag_inhibit_size_directive
)
3083 fputs ("\t.end\t", file
);
3084 if (interrupt_handler
&& !break_handler
)
3085 fputs ("_interrupt_handler", file
);
3086 else if (break_handler
)
3087 fputs ("_break_handler", file
);
3089 assemble_name (file
, fnname
);
3093 /* Reset state info for each function. */
3094 current_frame_info
= zero_frame_info
;
3096 /* Restore the output file if optimizing the GP (optimizing the GP causes
3097 the text to be diverted to a tempfile, so that data decls come before
3098 references to the data). */
3101 /* Expand the epilogue into a bunch of separate insns. */
3104 microblaze_expand_epilogue (void)
3106 HOST_WIDE_INT fsiz
= current_frame_info
.total_size
;
3107 rtx fsiz_rtx
= GEN_INT (fsiz
);
3111 /* In case of interrupt handlers use addki instead of addi for changing the
3112 stack pointer value. */
3114 if (microblaze_can_use_return_insn ())
3116 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode
,
3118 MB_ABI_SUB_RETURN_ADDR_REGNUM
)));
3124 /* Restore SUB_RETURN_ADDR_REGNUM at first. This is to prevent the
3125 sequence of load-followed by a use (in rtsd) in every prologue. Saves
3126 a load-use stall cycle :) This is also important to handle alloca.
3127 (See comments for if (frame_pointer_needed) below. */
3129 if (!crtl
->is_leaf
|| interrupt_handler
)
3132 gen_rtx_MEM (SImode
,
3133 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
, const0_rtx
));
3134 if (interrupt_handler
)
3135 /* Do not optimize in flow analysis. */
3136 MEM_VOLATILE_P (mem_rtx
) = 1;
3137 reg_rtx
= gen_rtx_REG (SImode
, MB_ABI_SUB_RETURN_ADDR_REGNUM
);
3138 emit_move_insn (reg_rtx
, mem_rtx
);
3141 /* It is important that this is done after we restore the return address
3142 register (above). When alloca is used, we want to restore the
3143 sub-routine return address only from the current stack top and not
3144 from the frame pointer (which we restore below). (frame_pointer + 0)
3145 might have been over-written since alloca allocates memory on the
3147 if (frame_pointer_needed
)
3148 emit_insn (gen_movsi (stack_pointer_rtx
, hard_frame_pointer_rtx
));
3150 /* _restore_ registers for epilogue. */
3151 save_restore_insns (0);
3152 emit_insn (gen_blockage ());
3153 emit_insn (gen_addsi3 (stack_pointer_rtx
, stack_pointer_rtx
, fsiz_rtx
));
3156 if (crtl
->calls_eh_return
)
3157 emit_insn (gen_addsi3 (stack_pointer_rtx
,
3159 gen_raw_REG (SImode
,
3160 MB_EH_STACKADJ_REGNUM
)));
3162 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode
, GP_REG_FIRST
+
3163 MB_ABI_SUB_RETURN_ADDR_REGNUM
)));
3167 /* Return nonzero if this function is known to have a null epilogue.
3168 This allows the optimizer to omit jumps to jumps if no stack
3172 microblaze_can_use_return_insn (void)
3174 if (!reload_completed
)
3177 if (df_regs_ever_live_p (MB_ABI_SUB_RETURN_ADDR_REGNUM
) || profile_flag
)
3180 if (current_frame_info
.initialized
)
3181 return current_frame_info
.total_size
== 0;
3183 return compute_frame_size (get_frame_size ()) == 0;
3186 /* Implement TARGET_SECONDARY_RELOAD. */
3189 microblaze_secondary_reload (bool in_p ATTRIBUTE_UNUSED
, rtx x ATTRIBUTE_UNUSED
,
3190 reg_class_t rclass
, machine_mode mode ATTRIBUTE_UNUSED
,
3191 secondary_reload_info
*sri ATTRIBUTE_UNUSED
)
3193 if (rclass
== ST_REGS
)
3200 microblaze_globalize_label (FILE * stream
, const char *name
)
3202 fputs ("\t.globl\t", stream
);
3203 if (microblaze_is_interrupt_variant ())
3205 if (interrupt_handler
&& strcmp (name
, INTERRUPT_HANDLER_NAME
))
3206 fputs (INTERRUPT_HANDLER_NAME
, stream
);
3207 else if (break_handler
&& strcmp (name
, BREAK_HANDLER_NAME
))
3208 fputs (BREAK_HANDLER_NAME
, stream
);
3209 else if (fast_interrupt
&& strcmp (name
, FAST_INTERRUPT_NAME
))
3210 fputs (FAST_INTERRUPT_NAME
, stream
);
3211 fputs ("\n\t.globl\t", stream
);
3213 assemble_name (stream
, name
);
3214 fputs ("\n", stream
);
3217 /* Returns true if decl should be placed into a "small data" section. */
3219 microblaze_elf_in_small_data_p (const_tree decl
)
3223 if (!TARGET_XLGPOPT
)
3226 /* We want to merge strings, so we never consider them small data. */
3227 if (TREE_CODE (decl
) == STRING_CST
)
3230 /* Functions are never in the small data area. */
3231 if (TREE_CODE (decl
) == FUNCTION_DECL
)
3234 if (VAR_P (decl
) && DECL_SECTION_NAME (decl
))
3236 const char *section
= DECL_SECTION_NAME (decl
);
3237 if (strcmp (section
, ".sdata") == 0
3238 || strcmp (section
, ".sdata2") == 0
3239 || strcmp (section
, ".sbss") == 0
3240 || strcmp (section
, ".sbss2") == 0)
3244 size
= int_size_in_bytes (TREE_TYPE (decl
));
3246 return (size
> 0 && size
<= microblaze_section_threshold
);
3249 /* We need to disable address diff vectors in
3250 case of pic data text relative mode. */
3253 microblaze_gen_pic_addr_dif_vec (void)
3255 return (flag_pic
&& !TARGET_PIC_DATA_TEXT_REL
);
3259 microblaze_select_section (tree decl
, int reloc
, unsigned HOST_WIDE_INT align
)
3261 switch (categorize_decl_for_section (decl
, reloc
))
3263 case SECCAT_RODATA_MERGE_STR
:
3264 case SECCAT_RODATA_MERGE_STR_INIT
:
3265 /* MB binutils have various issues with mergeable string sections and
3266 relaxation/relocation. Currently, turning mergeable sections
3267 into regular readonly sections. */
3269 return readonly_data_section
;
3271 return default_elf_select_section (decl
, reloc
, align
);
3276 Encode info about sections into the RTL based on a symbol's declaration.
3277 The default definition of this hook, default_encode_section_info in
3278 `varasm.cc', sets a number of commonly-useful bits in SYMBOL_REF_FLAGS. */
3281 microblaze_encode_section_info (tree decl
, rtx rtl
, int first
)
3283 default_encode_section_info (decl
, rtl
, first
);
3287 expand_pic_symbol_ref (machine_mode mode ATTRIBUTE_UNUSED
, rtx op
)
3290 bool isFunc
= (GET_CODE (op
) == SYMBOL_REF
3291 && (SYMBOL_REF_FLAGS (op
) & SYMBOL_FLAG_FUNCTION
));
3292 result
= (!TARGET_PIC_DATA_TEXT_REL
)
3293 ? gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, op
), UNSPEC_GOTOFF
)
3294 : gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, op
), UNSPEC_TEXT
);
3295 result
= gen_rtx_CONST (Pmode
, result
);
3296 result
= (TARGET_PIC_DATA_TEXT_REL
&& isFunc
)
3297 ? gen_rtx_PLUS (Pmode
, gen_raw_REG (Pmode
,
3298 get_base_reg (op
)), result
)
3299 : gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
, result
);
3300 result
= (!TARGET_PIC_DATA_TEXT_REL
)
3301 ? gen_const_mem (Pmode
, result
) : result
;
3307 microblaze_asm_output_mi_thunk (FILE *file
, tree thunk_fndecl ATTRIBUTE_UNUSED
,
3308 HOST_WIDE_INT delta
, HOST_WIDE_INT vcall_offset
,
3311 const char *fnname
= IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (thunk_fndecl
));
3312 rtx this_rtx
, funexp
;
3315 reload_completed
= 1;
3316 epilogue_completed
= 1;
3318 /* Mark the end of the (empty) prologue. */
3319 emit_note (NOTE_INSN_PROLOGUE_END
);
3321 /* Find the "this" pointer. If the function returns a structure,
3322 the structure return pointer is in MB_ABI_FIRST_ARG_REGNUM. */
3323 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function
)), function
))
3324 this_rtx
= gen_rtx_REG (Pmode
, (MB_ABI_FIRST_ARG_REGNUM
+ 1));
3326 this_rtx
= gen_rtx_REG (Pmode
, MB_ABI_FIRST_ARG_REGNUM
);
3328 /* Apply the constant offset, if required. */
3330 emit_insn (gen_addsi3 (this_rtx
, this_rtx
, GEN_INT (delta
)));
3332 /* Apply the offset from the vtable, if required. */
3335 rtx vcall_offset_rtx
= GEN_INT (vcall_offset
);
3336 rtx temp1
= gen_rtx_REG (Pmode
, MB_ABI_TEMP1_REGNUM
);
3338 emit_move_insn (temp1
, gen_rtx_MEM (Pmode
, this_rtx
));
3340 rtx loc
= gen_rtx_PLUS (Pmode
, temp1
, vcall_offset_rtx
);
3341 emit_move_insn (temp1
, gen_rtx_MEM (Pmode
, loc
));
3343 emit_insn (gen_addsi3 (this_rtx
, this_rtx
, temp1
));
3346 /* Generate a tail call to the target function. */
3347 if (!TREE_USED (function
))
3349 assemble_external (function
);
3350 TREE_USED (function
) = 1;
3353 funexp
= XEXP (DECL_RTL (function
), 0);
3354 rtx temp2
= gen_rtx_REG (Pmode
, MB_ABI_TEMP2_REGNUM
);
3357 emit_move_insn (temp2
, expand_pic_symbol_ref (Pmode
, funexp
));
3359 emit_move_insn (temp2
, funexp
);
3361 emit_insn (gen_indirect_jump (temp2
));
3363 /* Run just enough of rest_of_compilation. This sequence was
3364 "borrowed" from rs6000.cc. */
3365 insn
= get_insns ();
3366 shorten_branches (insn
);
3367 assemble_start_function (thunk_fndecl
, fnname
);
3368 final_start_function (insn
, file
, 1);
3369 final (insn
, file
, 1);
3370 final_end_function ();
3371 assemble_end_function (thunk_fndecl
, fnname
);
3373 reload_completed
= 0;
3374 epilogue_completed
= 0;
3378 microblaze_expand_move (machine_mode mode
, rtx operands
[])
3385 if (!register_operand (op0
, SImode
)
3386 && !register_operand (op1
, SImode
)
3387 && (GET_CODE (op1
) != CONST_INT
|| INTVAL (op1
) != 0))
3389 rtx temp
= force_reg (SImode
, op1
);
3390 emit_move_insn (op0
, temp
);
3393 /* If operands[1] is a constant address invalid for pic, then we need to
3394 handle it just like LEGITIMIZE_ADDRESS does. */
3395 if (GET_CODE (op1
) == SYMBOL_REF
|| GET_CODE (op1
) == LABEL_REF
)
3398 if (microblaze_tls_symbol_p(op1
))
3400 result
= microblaze_legitimize_tls_address (op1
, NULL_RTX
);
3401 emit_move_insn (op0
, result
);
3406 if (reload_in_progress
)
3407 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
3408 result
= expand_pic_symbol_ref (mode
, op1
);
3410 if (TARGET_PIC_DATA_TEXT_REL
&& GET_CODE (op0
) == REG
3411 && REGNO (op0
) >= FIRST_PSEUDO_REGISTER
)
3412 result
= force_reg (SImode
, result
);
3414 emit_move_insn (op0
, result
);
3418 if (GET_CODE (op1
) == PLUS
&& GET_CODE (XEXP (op1
,1)) == CONST
)
3420 rtx p0
, p1
= NULL
, result
, temp
;
3422 p0
= XEXP (XEXP (op1
,1), 0);
3424 if (GET_CODE (p0
) == PLUS
)
3430 /* This should never happen. */
3434 if (GET_CODE (p0
) == UNSPEC
&& GET_CODE (p1
) == CONST_INT
3435 && flag_pic
&& TARGET_PIC_DATA_TEXT_REL
)
3437 result
= gen_rtx_CONST (Pmode
, p0
);
3438 result
= gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
, result
);
3439 temp
= force_reg (SImode
, result
);
3440 emit_move_insn (op0
, gen_rtx_PLUS (SImode
, temp
, p1
));
3444 /* Handle Case of (const (plus symbol const_int)). */
3445 if (GET_CODE (op1
) == CONST
&& GET_CODE (XEXP (op1
,0)) == PLUS
)
3449 p0
= XEXP (XEXP (op1
, 0), 0);
3450 p1
= XEXP (XEXP (op1
, 0), 1);
3452 if ((GET_CODE (p1
) == CONST_INT
)
3453 && ((GET_CODE (p0
) == UNSPEC
)
3454 || ((GET_CODE (p0
) == SYMBOL_REF
|| GET_CODE (p0
) == LABEL_REF
)
3455 && (flag_pic
== 2 || microblaze_tls_symbol_p (p0
)
3456 || !SMALL_INT (p1
)))))
3458 rtx temp
= force_reg (SImode
, p0
);
3461 if (flag_pic
&& reload_in_progress
)
3462 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
3463 emit_move_insn (op0
, gen_rtx_PLUS (SImode
, temp
, temp2
));
3470 /* Expand shift operations. */
3472 microblaze_expand_shift (rtx operands
[])
3474 gcc_assert ((GET_CODE (operands
[2]) == CONST_INT
)
3475 || (GET_CODE (operands
[2]) == REG
)
3476 || (GET_CODE (operands
[2]) == SUBREG
));
3478 /* Shift by one -- generate pattern. */
3479 if ((GET_CODE (operands
[2]) == CONST_INT
) && (INTVAL (operands
[2]) == 1))
3482 /* Have barrel shifter and shift > 1: use it. */
3483 if (TARGET_BARREL_SHIFT
)
3486 gcc_assert ((GET_CODE (operands
[0]) == REG
)
3487 || (GET_CODE (operands
[0]) == SUBREG
)
3488 || (GET_CODE (operands
[1]) == REG
)
3489 || (GET_CODE (operands
[1]) == SUBREG
));
3491 /* Shift by zero -- copy regs if necessary. */
3492 if (operands
[2] == const0_rtx
3493 && !rtx_equal_p (operands
[0], operands
[1]))
3495 emit_insn (gen_movsi (operands
[0], operands
[1]));
3502 /* Return an RTX indicating where the return address to the
3503 calling function can be found. */
3505 microblaze_return_addr (int count
, rtx frame ATTRIBUTE_UNUSED
)
3510 return get_hard_reg_initial_val (Pmode
,
3511 MB_ABI_SUB_RETURN_ADDR_REGNUM
);
3515 microblaze_eh_return (rtx op0
)
3517 emit_insn (gen_movsi (gen_rtx_MEM (Pmode
, stack_pointer_rtx
), op0
));
3520 /* Queue an .ident string in the queue of top-level asm statements.
3521 If the string size is below the threshold, put it into .sdata2.
3522 If the front-end is done, we must be being called from toplev.cc.
3523 In that case, do nothing. */
3525 microblaze_asm_output_ident (const char *string
)
3527 const char *section_asm_op
;
3531 if (symtab
->state
!= PARSING
)
3534 size
= strlen (string
) + 1;
3535 if (size
<= microblaze_section_threshold
)
3536 section_asm_op
= SDATA2_SECTION_ASM_OP
;
3538 section_asm_op
= READONLY_DATA_SECTION_ASM_OP
;
3540 buf
= ACONCAT (("\t.pushsection", section_asm_op
,
3541 "\n\t.ascii \"", string
, "\\0\"\n",
3542 "\t.popsection\n", NULL
));
3543 symtab
->finalize_toplevel_asm (build_string (strlen (buf
), buf
));
3547 microblaze_elf_asm_init_sections (void)
3550 = get_unnamed_section (SECTION_WRITE
, output_section_asm_op
,
3551 SDATA2_SECTION_ASM_OP
);
3554 /* Generate assembler code for constant parts of a trampoline. */
3557 microblaze_asm_trampoline_template (FILE *f
)
3559 fprintf (f
, "\tmfs r18, rpc\n");
3560 fprintf (f
, "\tlwi r3, r18, 16\n");
3561 fprintf (f
, "\tlwi r18, r18, 20\n");
3562 fprintf (f
, "\tbra r18\n");
3563 /* fprintf (f, "\t.word\t0x00000000\t\t# <function address>\n"); */
3564 /* fprintf (f, "\t.word\t0x00000000\t\t# <static chain value>\n"); */
3567 /* Implement TARGET_TRAMPOLINE_INIT. */
3570 microblaze_trampoline_init (rtx m_tramp
, tree fndecl
, rtx chain_value
)
3572 rtx fnaddr
= XEXP (DECL_RTL (fndecl
), 0);
3575 emit_block_move (m_tramp
, assemble_trampoline_template (),
3576 GEN_INT (6*UNITS_PER_WORD
), BLOCK_OP_NORMAL
);
3578 mem
= adjust_address (m_tramp
, SImode
, 16);
3579 emit_move_insn (mem
, chain_value
);
3580 mem
= adjust_address (m_tramp
, SImode
, 20);
3581 emit_move_insn (mem
, fnaddr
);
3584 /* Generate conditional branch -- first, generate test condition,
3585 second, generate correct branch instruction. */
3588 microblaze_expand_conditional_branch (machine_mode mode
, rtx operands
[])
3590 enum rtx_code code
= GET_CODE (operands
[0]);
3591 rtx cmp_op0
= operands
[1];
3592 rtx cmp_op1
= operands
[2];
3593 rtx label1
= operands
[3];
3594 rtx comp_reg
= gen_reg_rtx (SImode
);
3597 gcc_assert ((GET_CODE (cmp_op0
) == REG
) || (GET_CODE (cmp_op0
) == SUBREG
));
3599 /* If comparing against zero, just test source reg. */
3600 if (cmp_op1
== const0_rtx
)
3603 condition
= gen_rtx_fmt_ee (signed_condition (code
), SImode
, comp_reg
, const0_rtx
);
3604 emit_jump_insn (gen_condjump (condition
, label1
));
3607 else if (code
== EQ
|| code
== NE
)
3609 /* Use xor for equal/not-equal comparison. */
3610 emit_insn (gen_xorsi3 (comp_reg
, cmp_op0
, cmp_op1
));
3611 condition
= gen_rtx_fmt_ee (signed_condition (code
), SImode
, comp_reg
, const0_rtx
);
3612 emit_jump_insn (gen_condjump (condition
, label1
));
3616 /* Generate compare and branch in single instruction. */
3617 cmp_op1
= force_reg (mode
, cmp_op1
);
3618 condition
= gen_rtx_fmt_ee (code
, mode
, cmp_op0
, cmp_op1
);
3619 emit_jump_insn (gen_branch_compare(condition
, cmp_op0
, cmp_op1
, label1
));
3624 microblaze_expand_conditional_branch_reg (machine_mode mode
, rtx operands
[])
3626 enum rtx_code code
= GET_CODE (operands
[0]);
3627 rtx cmp_op0
= operands
[1];
3628 rtx cmp_op1
= operands
[2];
3629 rtx label1
= operands
[3];
3630 rtx comp_reg
= gen_reg_rtx (SImode
);
3633 gcc_assert ((GET_CODE (cmp_op0
) == REG
)
3634 || (GET_CODE (cmp_op0
) == SUBREG
));
3636 /* If comparing against zero, just test source reg. */
3637 if (cmp_op1
== const0_rtx
)
3640 condition
= gen_rtx_fmt_ee (signed_condition (code
),
3641 SImode
, comp_reg
, const0_rtx
);
3642 emit_jump_insn (gen_condjump (condition
, label1
));
3644 else if (code
== EQ
)
3646 emit_insn (gen_seq_internal_pat (comp_reg
,
3648 condition
= gen_rtx_EQ (SImode
, comp_reg
, const0_rtx
);
3649 emit_jump_insn (gen_condjump (condition
, label1
));
3651 else if (code
== NE
)
3653 emit_insn (gen_sne_internal_pat (comp_reg
, cmp_op0
,
3655 condition
= gen_rtx_NE (SImode
, comp_reg
, const0_rtx
);
3656 emit_jump_insn (gen_condjump (condition
, label1
));
3660 /* Generate compare and branch in single instruction. */
3661 cmp_op1
= force_reg (mode
, cmp_op1
);
3662 condition
= gen_rtx_fmt_ee (code
, mode
, cmp_op0
, cmp_op1
);
3663 emit_jump_insn (gen_branch_compare (condition
, cmp_op0
,
3669 microblaze_expand_conditional_branch_sf (rtx operands
[])
3672 rtx cmp_op0
= XEXP (operands
[0], 0);
3673 rtx cmp_op1
= XEXP (operands
[0], 1);
3674 rtx comp_reg
= gen_reg_rtx (SImode
);
3676 emit_insn (gen_cstoresf4 (comp_reg
, operands
[0], cmp_op0
, cmp_op1
));
3677 condition
= gen_rtx_NE (SImode
, comp_reg
, const0_rtx
);
3678 emit_jump_insn (gen_condjump (condition
, operands
[3]));
3681 /* Implement TARGET_FRAME_POINTER_REQUIRED. */
3684 microblaze_frame_pointer_required (void)
3686 /* If the function contains dynamic stack allocations, we need to
3687 use the frame pointer to access the static parts of the frame. */
3688 if (cfun
->calls_alloca
)
3694 microblaze_expand_divide (rtx operands
[])
3696 /* Table lookup software divides. Works for all (nr/dr) where (0 <= nr,dr <= 15). */
3698 rtx regt1
= gen_reg_rtx (SImode
);
3699 rtx reg18
= gen_rtx_REG (SImode
, R_TMP
);
3700 rtx regqi
= gen_reg_rtx (QImode
);
3701 rtx_code_label
*div_label
= gen_label_rtx ();
3702 rtx_code_label
*div_end_label
= gen_label_rtx ();
3703 rtx div_table_rtx
= gen_rtx_SYMBOL_REF (QImode
,"_divsi3_table");
3706 rtx_insn
*jump
, *cjump
, *insn
;
3708 insn
= emit_insn (gen_iorsi3 (regt1
, operands
[1], operands
[2]));
3709 cjump
= emit_jump_insn_after (gen_cbranchsi4 (
3710 gen_rtx_GTU (SImode
, regt1
, GEN_INT (15)),
3711 regt1
, GEN_INT (15), div_label
), insn
);
3712 LABEL_NUSES (div_label
) = 1;
3713 JUMP_LABEL (cjump
) = div_label
;
3714 emit_insn (gen_rtx_CLOBBER (SImode
, reg18
));
3716 emit_insn (gen_ashlsi3_bshift (regt1
, operands
[1], GEN_INT(4)));
3717 emit_insn (gen_addsi3 (regt1
, regt1
, operands
[2]));
3718 mem_rtx
= gen_rtx_MEM (QImode
,
3719 gen_rtx_PLUS (Pmode
, regt1
, div_table_rtx
));
3721 insn
= emit_insn (gen_movqi (regqi
, mem_rtx
));
3722 insn
= emit_insn (gen_movsi (operands
[0], gen_rtx_SUBREG (SImode
, regqi
, 0)));
3723 jump
= emit_jump_insn_after (gen_jump (div_end_label
), insn
);
3724 JUMP_LABEL (jump
) = div_end_label
;
3725 LABEL_NUSES (div_end_label
) = 1;
3728 emit_label (div_label
);
3729 ret
= emit_library_call_value (gen_rtx_SYMBOL_REF (Pmode
, "__divsi3"),
3730 operands
[0], LCT_NORMAL
,
3731 GET_MODE (operands
[0]),
3732 operands
[1], GET_MODE (operands
[1]),
3733 operands
[2], GET_MODE (operands
[2]));
3734 if (ret
!= operands
[0])
3735 emit_move_insn (operands
[0], ret
);
3737 emit_label (div_end_label
);
3738 emit_insn (gen_blockage ());
3741 /* Implement TARGET_FUNCTION_VALUE. */
3743 microblaze_function_value (const_tree valtype
,
3744 const_tree func ATTRIBUTE_UNUSED
,
3745 bool outgoing ATTRIBUTE_UNUSED
)
3747 return LIBCALL_VALUE (TYPE_MODE (valtype
));
3750 /* Implement TARGET_SCHED_ADJUST_COST. */
3752 microblaze_adjust_cost (rtx_insn
*, int dep_type
, rtx_insn
*, int cost
,
3755 if (dep_type
== REG_DEP_OUTPUT
|| dep_type
== 0)
3760 /* Implement TARGET_LEGITIMATE_CONSTANT_P.
3762 At present, GAS doesn't understand li.[sd], so don't allow it
3763 to be generated at present. */
3765 microblaze_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED
, rtx x
)
3768 if (microblaze_cannot_force_const_mem(mode
, x
))
3771 if (GET_CODE (x
) == CONST_DOUBLE
)
3773 return microblaze_const_double_ok (x
, GET_MODE (x
));
3776 /* Handle Case of (const (plus unspec const_int)). */
3777 if (GET_CODE (x
) == CONST
&& GET_CODE (XEXP (x
,0)) == PLUS
)
3781 p0
= XEXP (XEXP (x
, 0), 0);
3782 p1
= XEXP (XEXP (x
, 0), 1);
3784 if (GET_CODE(p1
) == CONST_INT
)
3786 /* Const offset from UNSPEC is not supported. */
3787 if ((GET_CODE (p0
) == UNSPEC
))
3790 if ((GET_CODE (p0
) == SYMBOL_REF
|| GET_CODE (p0
) == LABEL_REF
)
3791 && (microblaze_tls_symbol_p (p0
) || !SMALL_INT (p1
)))
3800 get_branch_target (rtx branch
)
3802 if (CALL_P (branch
))
3806 call
= XVECEXP (PATTERN (branch
), 0, 0);
3807 if (GET_CODE (call
) == SET
)
3808 call
= SET_SRC (call
);
3809 if (GET_CODE (call
) != CALL
)
3811 return XEXP (XEXP (call
, 0), 0);
3817 /* Heuristics to identify where to insert at the
3818 fall through path of the caller function. If there
3819 is a call after the caller branch delay slot then
3820 we dont generate the instruction prefetch instruction.
3822 Scan up to 32 instructions after the call and checks
3823 for the JUMP and call instruction . If there is a call
3824 or JUMP instruction in the range of 32 instruction "wic"
3825 instruction wont be generated. Otherwise insert the "wic"
3826 instruction in the fall through of the call instruction
3827 four instruction after the call. before_4 is used for
3828 the position to insert "wic" instructions. before_16 is
3829 used to check for call and JUMP instruction for first
3833 insert_wic_for_ilb_runout (rtx_insn
*first
)
3836 rtx_insn
*before_4
= 0;
3837 rtx_insn
*before_16
= 0;
3838 int addr_offset
= 0;
3840 int wic_addr0
= 128 * 4;
3842 int first_addr
= INSN_ADDRESSES (INSN_UID (first
));
3844 for (insn
= first
; insn
; insn
= NEXT_INSN (insn
))
3847 addr_offset
= INSN_ADDRESSES (INSN_UID (insn
)) - first_addr
;
3848 length
= get_attr_length (insn
);
3849 if (before_4
== 0 && addr_offset
+ length
>= 4 * 4)
3854 if (before_16
== 0 && addr_offset
+ length
>= 14 * 4)
3856 if (CALL_P (insn
) || tablejump_p (insn
, 0, 0))
3858 if (addr_offset
+ length
>= 32 * 4)
3860 gcc_assert (before_4
&& before_16
);
3861 if (wic_addr0
> 4 * 4)
3864 emit_insn_before (gen_iprefetch
3865 (gen_int_mode (addr_offset
, SImode
)),
3867 recog_memoized (insn
);
3868 INSN_LOCATION (insn
) = INSN_LOCATION (before_4
);
3869 INSN_ADDRESSES_NEW (insn
, INSN_ADDRESSES (INSN_UID (before_4
)));
3876 /* Insert instruction prefetch instruction at the fall
3877 through path of the function call. */
3884 basic_block bb
, prev
= 0;
3885 rtx branch_target
= 0;
3887 shorten_branches (get_insns ());
3889 for (i
= 0; i
< n_basic_blocks_for_fn (cfun
) - 1; i
++)
3893 bool simple_loop
= false;
3895 bb
= BASIC_BLOCK_FOR_FN (cfun
, i
);
3900 if ((prev
!= 0) && (prev
!= bb
))
3905 FOR_EACH_EDGE (e
, ei
, bb
->preds
)
3913 for (insn
= BB_END (bb
); insn
; insn
= PREV_INSN (insn
))
3915 if (INSN_P (insn
) && !simple_loop
3918 if ((branch_target
= get_branch_target (insn
)))
3919 insert_wic_for_ilb_runout (
3920 next_active_insn (next_active_insn (insn
)));
3922 if (insn
== BB_HEAD (bb
))
3928 /* The reorg function defined through the macro
3929 TARGET_MACHINE_DEPENDENT_REORG. */
3932 microblaze_machine_dependent_reorg (void)
3934 if (TARGET_PREFETCH
)
3936 compute_bb_for_insn ();
3937 loop_optimizer_init (AVOID_CFG_MODIFICATIONS
);
3938 shorten_branches (get_insns ());
3940 loop_optimizer_finalize ();
3941 free_bb_for_insn ();
3946 /* Implement TARGET_CONSTANT_ALIGNMENT. */
3948 static HOST_WIDE_INT
3949 microblaze_constant_alignment (const_tree exp
, HOST_WIDE_INT align
)
3951 if (TREE_CODE (exp
) == STRING_CST
|| TREE_CODE (exp
) == CONSTRUCTOR
)
3952 return MAX (align
, BITS_PER_WORD
);
3956 /* Implement TARGET_STARTING_FRAME_OFFSET. */
3958 static HOST_WIDE_INT
3959 microblaze_starting_frame_offset (void)
3961 return (crtl
->outgoing_args_size
+ FIRST_PARM_OFFSET(FNDECL
));
3964 #undef TARGET_ENCODE_SECTION_INFO
3965 #define TARGET_ENCODE_SECTION_INFO microblaze_encode_section_info
3967 #undef TARGET_ASM_GLOBALIZE_LABEL
3968 #define TARGET_ASM_GLOBALIZE_LABEL microblaze_globalize_label
3970 #undef TARGET_ASM_FUNCTION_PROLOGUE
3971 #define TARGET_ASM_FUNCTION_PROLOGUE microblaze_function_prologue
3973 #undef TARGET_ASM_FUNCTION_EPILOGUE
3974 #define TARGET_ASM_FUNCTION_EPILOGUE microblaze_function_epilogue
3976 #undef TARGET_RTX_COSTS
3977 #define TARGET_RTX_COSTS microblaze_rtx_costs
3979 #undef TARGET_CANNOT_FORCE_CONST_MEM
3980 #define TARGET_CANNOT_FORCE_CONST_MEM microblaze_cannot_force_const_mem
3982 #undef TARGET_ADDRESS_COST
3983 #define TARGET_ADDRESS_COST microblaze_address_cost
3985 #undef TARGET_ATTRIBUTE_TABLE
3986 #define TARGET_ATTRIBUTE_TABLE microblaze_attribute_table
3988 #undef TARGET_IN_SMALL_DATA_P
3989 #define TARGET_IN_SMALL_DATA_P microblaze_elf_in_small_data_p
3991 #undef TARGET_ASM_SELECT_SECTION
3992 #define TARGET_ASM_SELECT_SECTION microblaze_select_section
3994 #undef TARGET_HAVE_SRODATA_SECTION
3995 #define TARGET_HAVE_SRODATA_SECTION true
3997 #undef TARGET_ASM_FUNCTION_END_PROLOGUE
3998 #define TARGET_ASM_FUNCTION_END_PROLOGUE \
3999 microblaze_function_end_prologue
4001 #undef TARGET_ARG_PARTIAL_BYTES
4002 #define TARGET_ARG_PARTIAL_BYTES function_arg_partial_bytes
4004 #undef TARGET_FUNCTION_ARG
4005 #define TARGET_FUNCTION_ARG microblaze_function_arg
4007 #undef TARGET_FUNCTION_ARG_ADVANCE
4008 #define TARGET_FUNCTION_ARG_ADVANCE microblaze_function_arg_advance
4010 #undef TARGET_CAN_ELIMINATE
4011 #define TARGET_CAN_ELIMINATE microblaze_can_eliminate
4013 #undef TARGET_LEGITIMIZE_ADDRESS
4014 #define TARGET_LEGITIMIZE_ADDRESS microblaze_legitimize_address
4016 #undef TARGET_LEGITIMATE_ADDRESS_P
4017 #define TARGET_LEGITIMATE_ADDRESS_P microblaze_legitimate_address_p
4019 #undef TARGET_FRAME_POINTER_REQUIRED
4020 #define TARGET_FRAME_POINTER_REQUIRED microblaze_frame_pointer_required
4022 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
4023 #define TARGET_ASM_TRAMPOLINE_TEMPLATE microblaze_asm_trampoline_template
4025 #undef TARGET_TRAMPOLINE_INIT
4026 #define TARGET_TRAMPOLINE_INIT microblaze_trampoline_init
4028 #undef TARGET_PROMOTE_FUNCTION_MODE
4029 #define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
4031 #undef TARGET_FUNCTION_VALUE
4032 #define TARGET_FUNCTION_VALUE microblaze_function_value
4034 #undef TARGET_SECONDARY_RELOAD
4035 #define TARGET_SECONDARY_RELOAD microblaze_secondary_reload
4037 #undef TARGET_ASM_OUTPUT_MI_THUNK
4038 #define TARGET_ASM_OUTPUT_MI_THUNK microblaze_asm_output_mi_thunk
4040 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
4041 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true
4043 #undef TARGET_SCHED_ADJUST_COST
4044 #define TARGET_SCHED_ADJUST_COST microblaze_adjust_cost
4046 #undef TARGET_ASM_INIT_SECTIONS
4047 #define TARGET_ASM_INIT_SECTIONS microblaze_elf_asm_init_sections
4049 #undef TARGET_OPTION_OVERRIDE
4050 #define TARGET_OPTION_OVERRIDE microblaze_option_override
4052 #undef TARGET_LEGITIMATE_CONSTANT_P
4053 #define TARGET_LEGITIMATE_CONSTANT_P microblaze_legitimate_constant_p
4055 #undef TARGET_ASM_GENERATE_PIC_ADDR_DIFF_VEC
4056 #define TARGET_ASM_GENERATE_PIC_ADDR_DIFF_VEC microblaze_gen_pic_addr_dif_vec
4058 #undef TARGET_MACHINE_DEPENDENT_REORG
4059 #define TARGET_MACHINE_DEPENDENT_REORG microblaze_machine_dependent_reorg
4061 #undef TARGET_HARD_REGNO_MODE_OK
4062 #define TARGET_HARD_REGNO_MODE_OK microblaze_hard_regno_mode_ok
4064 #undef TARGET_MODES_TIEABLE_P
4065 #define TARGET_MODES_TIEABLE_P microblaze_modes_tieable_p
4067 #undef TARGET_CONSTANT_ALIGNMENT
4068 #define TARGET_CONSTANT_ALIGNMENT microblaze_constant_alignment
4070 #undef TARGET_STARTING_FRAME_OFFSET
4071 #define TARGET_STARTING_FRAME_OFFSET microblaze_starting_frame_offset
4073 struct gcc_target targetm
= TARGET_INITIALIZER
;
4075 #include "gt-microblaze.h"