1 /* Subroutines used for code generation on Xilinx MicroBlaze.
2 Copyright (C) 2009-2015 Free Software Foundation, Inc.
4 Contributed by Michael Eager <eager@eagercon.com>.
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published
10 by the Free Software Foundation; either version 3, or (at your
11 option) any later version.
13 GCC is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16 License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. */
24 #include "coretypes.h"
28 #include "hard-reg-set.h"
30 #include "insn-config.h"
31 #include "conditions.h"
32 #include "insn-flags.h"
33 #include "insn-attr.h"
38 #include "double-int.h"
46 #include "stor-layout.h"
56 #include "target-def.h"
59 #include "dominance.h"
65 #include "cfgcleanup.h"
67 #include "basic-block.h"
69 #include "insn-codes.h"
71 #include "diagnostic-core.h"
74 #include "plugin-api.h"
80 #define MICROBLAZE_VERSION_COMPARE(VA,VB) strcasecmp (VA, VB)
82 /* Classifies an address.
89 A natural register or a register + const_int offset address.
90 The register satisfies microblaze_valid_base_register_p and the
91 offset is a const_arith_operand.
95 A natural register offset by the index contained in an index register. The base
96 register satisfies microblaze_valid_base_register_p and the index register
97 satisfies microblaze_valid_index_register_p
101 A signed 16/32-bit constant address.
105 A constant symbolic address or a (register + symbol). */
107 enum microblaze_address_type
119 /* Classifies symbols
124 enum microblaze_symbol_type
130 /* TLS Address Type. */
139 /* Classification of a MicroBlaze address. */
140 struct microblaze_address_info
142 enum microblaze_address_type type
;
143 rtx regA
; /* Contains valid values on ADDRESS_REG, ADDRESS_REG_INDEX,
145 rtx regB
; /* Contains valid values on ADDRESS_REG_INDEX. */
146 rtx offset
; /* Contains valid values on ADDRESS_CONST_INT and ADDRESS_REG. */
147 rtx symbol
; /* Contains valid values on ADDRESS_SYMBOLIC. */
148 enum microblaze_symbol_type symbol_type
;
149 enum tls_reloc tls_type
;
152 /* Structure to be filled in by compute_frame_size with register
153 save masks, and offsets for the current function. */
155 struct GTY(()) microblaze_frame_info
{
156 long total_size
; /* # bytes that the entire frame takes up. */
157 long var_size
; /* # bytes that variables take up. */
158 long args_size
; /* # bytes that outgoing arguments take up. */
159 int link_debug_size
; /* # bytes for the link reg and back pointer. */
160 int gp_reg_size
; /* # bytes needed to store gp regs. */
161 long gp_offset
; /* offset from new sp to store gp registers. */
162 long mask
; /* mask of saved gp registers. */
163 int initialized
; /* != 0 if frame size already calculated. */
164 int num_gp
; /* number of gp registers saved. */
165 long insns_len
; /* length of insns. */
166 int alloc_stack
; /* Flag to indicate if the current function
167 must not create stack space. (As an optimization). */
170 /* Global variables for machine-dependent things. */
172 /* Toggle which pipleline interface to use. */
173 static GTY(()) int microblaze_sched_use_dfa
= 0;
175 /* Threshold for data being put into the small data/bss area, instead
176 of the normal data area (references to the small data/bss area take
177 1 instruction, and use the global pointer, references to the normal
178 data area takes 2 instructions). */
179 int microblaze_section_threshold
= -1;
181 /* Prevent scheduling potentially exception causing instructions in
182 delay slots. -mcpu=v3.00.a or v4.00.a turns this on. */
183 int microblaze_no_unsafe_delay
;
185 /* Set to one if the targeted core has the CLZ insn. */
186 int microblaze_has_clz
= 0;
188 /* Which CPU pipeline do we use. We haven't really standardized on a CPU
189 version having only a particular type of pipeline. There can still be
190 options on the CPU to scale pipeline features up or down. :(
191 Bad Presentation (??), so we let the MD file rely on the value of
192 this variable instead Making PIPE_5 the default. It should be backward
193 optimal with PIPE_3 MicroBlazes. */
194 enum pipeline_type microblaze_pipe
= MICROBLAZE_PIPE_5
;
196 /* High and low marks for floating point values which we will accept
197 as legitimate constants for TARGET_LEGITIMATE_CONSTANT_P. These are
198 initialized in override_options. */
199 REAL_VALUE_TYPE dfhigh
, dflow
, sfhigh
, sflow
;
201 /* Array giving truth value on whether or not a given hard register
202 can support a given mode. */
203 char microblaze_hard_regno_mode_ok
[(int)MAX_MACHINE_MODE
]
204 [FIRST_PSEUDO_REGISTER
];
206 /* Current frame information calculated by compute_frame_size. */
207 struct microblaze_frame_info current_frame_info
;
209 /* Zero structure to initialize current_frame_info. */
210 struct microblaze_frame_info zero_frame_info
;
212 /* List of all MICROBLAZE punctuation characters used by print_operand. */
213 char microblaze_print_operand_punct
[256];
215 /* Map GCC register number to debugger register number. */
216 int microblaze_dbx_regno
[FIRST_PSEUDO_REGISTER
];
218 /* Map hard register number to register class. */
219 enum reg_class microblaze_regno_to_class
[] =
221 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
222 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
223 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
224 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
225 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
226 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
227 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
228 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
229 ST_REGS
, GR_REGS
, GR_REGS
, GR_REGS
232 /* MicroBlaze specific machine attributes.
233 interrupt_handler - Interrupt handler attribute to add interrupt prologue
234 and epilogue and use appropriate interrupt return.
235 save_volatiles - Similar to interrupt handler, but use normal return. */
236 int interrupt_handler
;
241 const struct attribute_spec microblaze_attribute_table
[] = {
242 /* name min_len, max_len, decl_req, type_req, fn_type, req_handler,
243 affects_type_identity */
244 {"interrupt_handler", 0, 0, true, false, false, NULL
,
246 {"break_handler", 0, 0, true, false, false, NULL
,
248 {"fast_interrupt", 0, 0, true, false, false, NULL
,
250 {"save_volatiles" , 0, 0, true, false, false, NULL
,
252 { NULL
, 0, 0, false, false, false, NULL
,
256 static int microblaze_interrupt_function_p (tree
);
258 static void microblaze_elf_asm_constructor (rtx
, int) ATTRIBUTE_UNUSED
;
259 static void microblaze_elf_asm_destructor (rtx
, int) ATTRIBUTE_UNUSED
;
261 section
*sdata2_section
;
264 #undef TARGET_HAVE_TLS
265 #define TARGET_HAVE_TLS true
268 /* Return truth value if a CONST_DOUBLE is ok to be a legitimate constant. */
270 microblaze_const_double_ok (rtx op
, machine_mode mode
)
274 if (GET_CODE (op
) != CONST_DOUBLE
)
277 if (GET_MODE (op
) == VOIDmode
)
280 if (mode
!= SFmode
&& mode
!= DFmode
)
283 if (op
== CONST0_RTX (mode
))
286 REAL_VALUE_FROM_CONST_DOUBLE (d
, op
);
288 if (REAL_VALUE_ISNAN (d
))
291 if (REAL_VALUE_NEGATIVE (d
))
292 d
= real_value_negate (&d
);
296 if (REAL_VALUES_LESS (d
, dfhigh
) && REAL_VALUES_LESS (dflow
, d
))
301 if (REAL_VALUES_LESS (d
, sfhigh
) && REAL_VALUES_LESS (sflow
, d
))
308 /* Return truth value if a memory operand fits in a single instruction
309 (ie, register + small offset) or (register + register). */
312 simple_memory_operand (rtx op
, machine_mode mode ATTRIBUTE_UNUSED
)
314 rtx addr
, plus0
, plus1
;
316 /* Eliminate non-memory operations. */
317 if (GET_CODE (op
) != MEM
)
320 /* dword operations really put out 2 instructions, so eliminate them. */
321 /* ??? This isn't strictly correct. It is OK to accept multiword modes
322 here, since the length attributes are being set correctly, but only
323 if the address is offsettable. */
324 if (GET_MODE_SIZE (GET_MODE (op
)) > UNITS_PER_WORD
)
328 /* Decode the address now. */
330 switch (GET_CODE (addr
))
337 plus0
= XEXP (addr
, 0);
338 plus1
= XEXP (addr
, 1);
340 if (GET_CODE (plus0
) != REG
)
343 if (GET_CODE (plus0
) == REG
&& GET_CODE (plus1
) == CONST_INT
344 && SMALL_INT (plus1
))
348 else if (GET_CODE (plus1
) == REG
&& GET_CODE (plus0
) == CONST_INT
)
352 else if (GET_CODE (plus0
) == REG
&& GET_CODE (plus1
) == REG
)
369 /* Return nonzero for a memory address that can be used to load or store
373 double_memory_operand (rtx op
, machine_mode mode
)
377 if (GET_CODE (op
) != MEM
|| !memory_operand (op
, mode
))
379 /* During reload, we accept a pseudo register if it has an
380 appropriate memory address. If we don't do this, we will
381 wind up reloading into a register, and then reloading that
382 register from memory, when we could just reload directly from
384 if (reload_in_progress
385 && GET_CODE (op
) == REG
386 && REGNO (op
) >= FIRST_PSEUDO_REGISTER
387 && reg_renumber
[REGNO (op
)] < 0
388 && reg_equiv_mem (REGNO (op
)) != 0
389 && double_memory_operand (reg_equiv_mem (REGNO (op
)), mode
))
394 /* Make sure that 4 added to the address is a valid memory address.
395 This essentially just checks for overflow in an added constant. */
399 if (CONSTANT_ADDRESS_P (addr
))
402 return memory_address_p ((GET_MODE_CLASS (mode
) == MODE_INT
404 plus_constant (Pmode
, addr
, 4));
407 /* Implement REG_OK_FOR_BASE_P -and- REG_OK_FOR_INDEX_P. */
409 microblaze_regno_ok_for_base_p (int regno
, int strict
)
411 if (regno
>= FIRST_PSEUDO_REGISTER
)
415 regno
= reg_renumber
[regno
];
418 /* These fake registers will be eliminated to either the stack or
419 hard frame pointer, both of which are usually valid base registers.
420 Reload deals with the cases where the eliminated form isn't valid. */
421 if (regno
== ARG_POINTER_REGNUM
|| regno
== FRAME_POINTER_REGNUM
)
424 return GP_REG_P (regno
);
427 /* Return true if X is a valid base register for the given mode.
428 Allow only hard registers if STRICT. */
431 microblaze_valid_base_register_p (rtx x
,
432 machine_mode mode ATTRIBUTE_UNUSED
,
435 if (!strict
&& GET_CODE (x
) == SUBREG
)
438 return (GET_CODE (x
) == REG
439 && microblaze_regno_ok_for_base_p (REGNO (x
), strict
));
442 /* Build the SYMBOL_REF for __tls_get_addr. */
444 static GTY(()) rtx tls_get_addr_libfunc
;
447 get_tls_get_addr (void)
449 if (!tls_get_addr_libfunc
)
450 tls_get_addr_libfunc
= init_one_libfunc ("__tls_get_addr");
451 return tls_get_addr_libfunc
;
454 /* Return TRUE if X is a thread-local symbol. */
456 microblaze_tls_symbol_p (rtx x
)
458 if (!TARGET_HAVE_TLS
)
461 if (GET_CODE (x
) != SYMBOL_REF
)
464 return SYMBOL_REF_TLS_MODEL (x
) != 0;
467 /* Return TRUE if X contains any TLS symbol references. */
470 microblaze_tls_referenced_p (rtx x
)
472 if (!TARGET_HAVE_TLS
)
474 subrtx_iterator::array_type array
;
475 FOR_EACH_SUBRTX (iter
, array
, x
, ALL
)
478 if (GET_CODE (x
) == SYMBOL_REF
&& SYMBOL_REF_TLS_MODEL (x
) != 0)
480 /* Don't recurse into UNSPEC_TLS looking for TLS symbols; these are
481 TLS offsets, not real symbol references. */
482 if (GET_CODE (x
) == UNSPEC
&& XINT (x
, 1) == UNSPEC_TLS
)
483 iter
.skip_subrtxes ();
489 microblaze_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED
, rtx x
)
491 return microblaze_tls_referenced_p(x
);
494 /* Return TRUE if X references a SYMBOL_REF. */
496 symbol_mentioned_p (rtx x
)
501 if (GET_CODE (x
) == SYMBOL_REF
)
504 /* UNSPEC entries for a symbol include the SYMBOL_REF, but they
505 are constant offsets, not symbols. */
506 if (GET_CODE (x
) == UNSPEC
)
509 fmt
= GET_RTX_FORMAT (GET_CODE (x
));
511 for (i
= GET_RTX_LENGTH (GET_CODE (x
)) - 1; i
>= 0; i
--)
517 for (j
= XVECLEN (x
, i
) - 1; j
>= 0; j
--)
518 if (symbol_mentioned_p (XVECEXP (x
, i
, j
)))
521 else if (fmt
[i
] == 'e' && symbol_mentioned_p (XEXP (x
, i
)))
528 /* Return TRUE if X references a LABEL_REF. */
530 label_mentioned_p (rtx x
)
535 if (GET_CODE (x
) == LABEL_REF
)
538 /* UNSPEC entries for a symbol include a LABEL_REF for the referencing
539 instruction, but they are constant offsets, not symbols. */
540 if (GET_CODE (x
) == UNSPEC
)
543 fmt
= GET_RTX_FORMAT (GET_CODE (x
));
544 for (i
= GET_RTX_LENGTH (GET_CODE (x
)) - 1; i
>= 0; i
--)
550 for (j
= XVECLEN (x
, i
) - 1; j
>= 0; j
--)
551 if (label_mentioned_p (XVECEXP (x
, i
, j
)))
554 else if (fmt
[i
] == 'e' && label_mentioned_p (XEXP (x
, i
)))
562 tls_mentioned_p (rtx x
)
564 switch (GET_CODE (x
))
567 return tls_mentioned_p (XEXP (x
, 0));
570 if (XINT (x
, 1) == UNSPEC_TLS
)
579 load_tls_operand (rtx x
, rtx reg
)
584 reg
= gen_reg_rtx (Pmode
);
586 tmp
= gen_rtx_CONST (Pmode
, x
);
588 emit_insn (gen_rtx_SET (VOIDmode
, reg
,
589 gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
, tmp
)));
595 microblaze_call_tls_get_addr (rtx x
, rtx reg
, rtx
*valuep
, int reloc
)
600 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
604 tls_entry
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (2, x
, GEN_INT (reloc
)),
607 reg
= load_tls_operand (tls_entry
, reg
);
609 *valuep
= emit_library_call_value (get_tls_get_addr (), NULL_RTX
,
610 LCT_PURE
, /* LCT_CONST? */
611 Pmode
, 1, reg
, Pmode
);
613 insns
= get_insns ();
620 microblaze_legitimize_tls_address(rtx x
, rtx reg
)
622 rtx dest
, ret
, eqv
, addend
;
624 enum tls_model model
;
625 model
= SYMBOL_REF_TLS_MODEL (x
);
629 case TLS_MODEL_LOCAL_DYNAMIC
:
630 case TLS_MODEL_GLOBAL_DYNAMIC
:
631 case TLS_MODEL_INITIAL_EXEC
:
632 insns
= microblaze_call_tls_get_addr (x
, reg
, &ret
, TLS_GD
);
633 dest
= gen_reg_rtx (Pmode
);
634 emit_libcall_block (insns
, dest
, ret
, x
);
637 case TLS_MODEL_LOCAL_EXEC
:
638 insns
= microblaze_call_tls_get_addr (x
, reg
, &ret
, TLS_LDM
);
640 /* Attach a unique REG_EQUIV, to allow the RTL optimizers to
641 share the LDM result with other LD model accesses. */
642 eqv
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, const1_rtx
), UNSPEC_TLS
);
643 dest
= gen_reg_rtx (Pmode
);
644 emit_libcall_block (insns
, dest
, ret
, eqv
);
646 /* Load the addend. */
647 addend
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (2, x
, GEN_INT (TLS_DTPREL
)),
649 addend
= force_reg (SImode
, gen_rtx_CONST (SImode
, addend
));
650 dest
= gen_rtx_PLUS (Pmode
, dest
, addend
);
660 microblaze_classify_unspec (struct microblaze_address_info
*info
, rtx x
)
662 info
->symbol_type
= SYMBOL_TYPE_GENERAL
;
663 info
->symbol
= XVECEXP (x
, 0, 0);
665 if (XINT (x
, 1) == UNSPEC_GOTOFF
)
667 info
->regA
= gen_rtx_REG (SImode
, PIC_OFFSET_TABLE_REGNUM
);
668 info
->type
= ADDRESS_GOTOFF
;
670 else if (XINT (x
, 1) == UNSPEC_PLT
)
672 info
->type
= ADDRESS_PLT
;
674 else if (XINT (x
, 1) == UNSPEC_TLS
)
676 info
->type
= ADDRESS_TLS
;
677 info
->tls_type
= tls_reloc
INTVAL(XVECEXP(x
, 0, 1));
687 /* Return true if X is a valid index register for the given mode.
688 Allow only hard registers if STRICT. */
691 microblaze_valid_index_register_p (rtx x
,
692 machine_mode mode ATTRIBUTE_UNUSED
,
695 if (!strict
&& GET_CODE (x
) == SUBREG
)
698 return (GET_CODE (x
) == REG
699 /* A base register is good enough to be an index register on MicroBlaze. */
700 && microblaze_regno_ok_for_base_p (REGNO (x
), strict
));
703 /* Get the base register for accessing a value from the memory or
704 Symbol ref. Used for MicroBlaze Small Data Area Pointer Optimization. */
711 if (!flag_pic
|| microblaze_tls_symbol_p(x
))
712 base_reg
= MB_ABI_BASE_REGNUM
;
714 base_reg
= MB_ABI_PIC_ADDR_REGNUM
;
717 && GET_CODE (x
) == SYMBOL_REF
718 && SYMBOL_REF_SMALL_P (x
) && (decl
= SYMBOL_REF_DECL (x
)) != NULL
)
720 if (TREE_READONLY (decl
))
721 base_reg
= MB_ABI_GPRO_REGNUM
;
723 base_reg
= MB_ABI_GPRW_REGNUM
;
729 /* Return true if X is a valid address for machine mode MODE. If it is,
730 fill in INFO appropriately. STRICT is true if we should only accept
733 type regA regB offset symbol
735 ADDRESS_INVALID NULL NULL NULL NULL
737 ADDRESS_REG %0 NULL const_0 / NULL
739 ADDRESS_REG_INDEX %0 %1 NULL NULL
741 ADDRESS_SYMBOLIC r0 / NULL NULL symbol
744 ADDRESS_CONST_INT r0 NULL const NULL
746 For modes spanning multiple registers (DFmode in 32-bit GPRs,
747 DImode, TImode), indexed addressing cannot be used because
748 adjacent memory cells are accessed by adding word-sized offsets
749 during assembly output. */
752 microblaze_classify_address (struct microblaze_address_info
*info
, rtx x
,
753 machine_mode mode
, int strict
)
758 info
->type
= ADDRESS_INVALID
;
763 info
->symbol_type
= SYMBOL_TYPE_INVALID
;
765 switch (GET_CODE (x
))
770 info
->type
= ADDRESS_REG
;
772 info
->offset
= const0_rtx
;
773 return microblaze_valid_base_register_p (info
->regA
, mode
, strict
);
777 xplus0
= XEXP (x
, 0);
778 xplus1
= XEXP (x
, 1);
780 if (microblaze_valid_base_register_p (xplus0
, mode
, strict
))
782 info
->type
= ADDRESS_REG
;
785 if (GET_CODE (xplus1
) == CONST_INT
)
787 info
->offset
= xplus1
;
790 else if (GET_CODE (xplus1
) == UNSPEC
)
792 /* Need offsettable address. */
793 if (GET_MODE_SIZE (mode
) > UNITS_PER_WORD
)
796 return microblaze_classify_unspec (info
, xplus1
);
798 else if ((GET_CODE (xplus1
) == SYMBOL_REF
||
799 GET_CODE (xplus1
) == LABEL_REF
))
801 if (flag_pic
== 2 || microblaze_tls_symbol_p(xplus1
))
803 info
->type
= ADDRESS_SYMBOLIC
;
804 info
->symbol
= xplus1
;
805 info
->symbol_type
= SYMBOL_TYPE_GENERAL
;
808 else if (GET_CODE (xplus1
) == CONST
)
810 rtx xconst0
= XEXP(xplus1
, 0);
813 if (GET_CODE (xconst0
) == UNSPEC
)
815 /* Need offsettable address. */
816 if (GET_MODE_SIZE (mode
) > UNITS_PER_WORD
)
818 return microblaze_classify_unspec(info
, xconst0
);
821 /* for (plus x const_int) just look at x. */
822 if (GET_CODE (xconst0
) == PLUS
823 && GET_CODE (XEXP (xconst0
, 1)) == CONST_INT
824 && SMALL_INT (XEXP (xconst0
, 1)))
826 /* This is ok as info->symbol is set to xplus1 the full
827 const-expression below. */
828 xconst0
= XEXP (xconst0
, 0);
831 if (GET_CODE (xconst0
) == SYMBOL_REF
832 || GET_CODE (xconst0
) == LABEL_REF
)
834 if (flag_pic
== 2 || microblaze_tls_symbol_p(xconst0
))
837 info
->type
= ADDRESS_SYMBOLIC
;
838 info
->symbol
= xplus1
;
839 info
->symbol_type
= SYMBOL_TYPE_GENERAL
;
843 /* Not base + symbol || base + UNSPEC. */
847 else if (GET_CODE (xplus1
) == REG
848 && microblaze_valid_index_register_p (xplus1
, mode
,
850 && (GET_MODE_SIZE (mode
) <= UNITS_PER_WORD
))
852 /* Restrict larger than word-width modes from using an index register. */
853 info
->type
= ADDRESS_REG_INDEX
;
862 info
->regA
= gen_rtx_raw_REG (mode
, 0);
863 info
->type
= ADDRESS_CONST_INT
;
871 info
->type
= ADDRESS_SYMBOLIC
;
872 info
->symbol_type
= SYMBOL_TYPE_GENERAL
;
874 info
->regA
= gen_rtx_raw_REG (mode
, get_base_reg (x
));
876 if (GET_CODE (x
) == CONST
)
878 if (GET_CODE (XEXP (x
, 0)) == UNSPEC
)
880 info
->regA
= gen_rtx_raw_REG (mode
,
881 get_base_reg (XVECEXP (XEXP (x
,0), 0, 0)));
882 return microblaze_classify_unspec (info
, XEXP (x
, 0));
884 return !(flag_pic
&& pic_address_needs_scratch (x
));
889 else if (microblaze_tls_symbol_p(x
))
897 if (reload_in_progress
)
898 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
899 return microblaze_classify_unspec (info
, x
);
909 /* This function is used to implement GO_IF_LEGITIMATE_ADDRESS. It
910 returns a nonzero value if X is a legitimate address for a memory
911 operand of the indicated MODE. STRICT is nonzero if this function
912 is called during reload. */
915 microblaze_legitimate_address_p (machine_mode mode
, rtx x
, bool strict
)
917 struct microblaze_address_info addr
;
919 return microblaze_classify_address (&addr
, x
, mode
, strict
);
923 microblaze_valid_pic_const (rtx x
)
925 switch (GET_CODE (x
))
937 microblaze_legitimate_pic_operand (rtx x
)
939 if (flag_pic
== 2 && (symbol_mentioned_p(x
) || label_mentioned_p(x
)))
942 if (microblaze_tls_referenced_p(x
))
948 /* Try machine-dependent ways of modifying an illegitimate address
949 to be legitimate. If we find one, return the new, valid address.
950 This is used from only one place: `memory_address' in explow.c.
952 OLDX is the address as it was before break_out_memory_refs was
953 called. In some cases it is useful to look at this to decide what
956 It is always safe for this function to do nothing. It exists to
957 recognize opportunities to optimize the output.
959 For the MicroBlaze, transform:
961 memory(X + <large int>)
965 Y = <large int> & ~0x7fff;
967 memory (Z + (<large int> & 0x7fff));
969 This is for CSE to find several similar references, and only use one Z.
971 When PIC, convert addresses of the form memory (symbol+large int) to
972 memory (reg+large int). */
975 microblaze_legitimize_address (rtx x
, rtx oldx ATTRIBUTE_UNUSED
,
976 machine_mode mode ATTRIBUTE_UNUSED
)
978 register rtx xinsn
= x
, result
;
980 if (GET_CODE (xinsn
) == CONST
981 && flag_pic
&& pic_address_needs_scratch (xinsn
))
983 rtx ptr_reg
= gen_reg_rtx (Pmode
);
984 rtx constant
= XEXP (XEXP (xinsn
, 0), 1);
986 emit_move_insn (ptr_reg
, XEXP (XEXP (xinsn
, 0), 0));
988 result
= gen_rtx_PLUS (Pmode
, ptr_reg
, constant
);
989 if (SMALL_INT (constant
))
991 /* Otherwise we fall through so the code below will fix the
996 if (GET_CODE (xinsn
) == PLUS
)
998 register rtx xplus0
= XEXP (xinsn
, 0);
999 register rtx xplus1
= XEXP (xinsn
, 1);
1000 register enum rtx_code code0
= GET_CODE (xplus0
);
1001 register enum rtx_code code1
= GET_CODE (xplus1
);
1003 if (code0
!= REG
&& code1
== REG
)
1005 xplus0
= XEXP (xinsn
, 1);
1006 xplus1
= XEXP (xinsn
, 0);
1007 code0
= GET_CODE (xplus0
);
1008 code1
= GET_CODE (xplus1
);
1011 if (code0
== REG
&& REG_OK_FOR_BASE_P (xplus0
)
1012 && code1
== CONST_INT
&& !SMALL_INT (xplus1
))
1014 rtx int_reg
= gen_reg_rtx (Pmode
);
1015 rtx ptr_reg
= gen_reg_rtx (Pmode
);
1017 emit_move_insn (int_reg
, GEN_INT (INTVAL (xplus1
) & ~0x7fff));
1019 emit_insn (gen_rtx_SET (VOIDmode
,
1021 gen_rtx_PLUS (Pmode
, xplus0
, int_reg
)));
1023 result
= gen_rtx_PLUS (Pmode
, ptr_reg
,
1024 GEN_INT (INTVAL (xplus1
) & 0x7fff));
1028 if (code0
== REG
&& REG_OK_FOR_BASE_P (xplus0
))
1030 if (reload_in_progress
)
1031 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
1034 xplus1
= XEXP (xplus1
, 0);
1035 code1
= GET_CODE (xplus1
);
1037 if (code1
== SYMBOL_REF
)
1039 if (microblaze_tls_symbol_p(xplus1
))
1042 reg
= gen_reg_rtx (Pmode
);
1044 tls_ref
= microblaze_legitimize_tls_address (xplus1
,
1046 emit_move_insn (reg
, tls_ref
);
1048 result
= gen_rtx_PLUS (Pmode
, xplus0
, reg
);
1052 else if (flag_pic
== 2)
1055 reg
= gen_reg_rtx (Pmode
);
1057 pic_ref
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, xplus1
),
1059 pic_ref
= gen_rtx_CONST (Pmode
, pic_ref
);
1060 pic_ref
= gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
, pic_ref
);
1061 pic_ref
= gen_const_mem (Pmode
, pic_ref
);
1062 emit_move_insn (reg
, pic_ref
);
1063 result
= gen_rtx_PLUS (Pmode
, xplus0
, reg
);
1070 if (GET_CODE (xinsn
) == SYMBOL_REF
)
1073 if (microblaze_tls_symbol_p(xinsn
))
1075 reg
= microblaze_legitimize_tls_address (xinsn
, NULL_RTX
);
1081 if (reload_in_progress
)
1082 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
1084 pic_ref
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, xinsn
), UNSPEC_GOTOFF
);
1085 pic_ref
= gen_rtx_CONST (Pmode
, pic_ref
);
1086 pic_ref
= gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
, pic_ref
);
1087 pic_ref
= gen_const_mem (Pmode
, pic_ref
);
1098 #define MAX_MOVE_REGS 8
1099 #define MAX_MOVE_BYTES (MAX_MOVE_REGS * UNITS_PER_WORD)
1101 /* Emit straight-line code to move LENGTH bytes from SRC to DEST.
1102 Assume that the areas do not overlap. */
1105 microblaze_block_move_straight (rtx dest
, rtx src
, HOST_WIDE_INT length
)
1107 HOST_WIDE_INT offset
, delta
;
1108 unsigned HOST_WIDE_INT bits
;
1113 bits
= BITS_PER_WORD
;
1114 mode
= mode_for_size (bits
, MODE_INT
, 0);
1115 delta
= bits
/ BITS_PER_UNIT
;
1117 /* Allocate a buffer for the temporary registers. */
1118 regs
= XALLOCAVEC (rtx
, length
/ delta
);
1120 /* Load as many BITS-sized chunks as possible. Use a normal load if
1121 the source has enough alignment, otherwise use left/right pairs. */
1122 for (offset
= 0, i
= 0; offset
+ delta
<= length
; offset
+= delta
, i
++)
1124 regs
[i
] = gen_reg_rtx (mode
);
1125 emit_move_insn (regs
[i
], adjust_address (src
, mode
, offset
));
1128 /* Copy the chunks to the destination. */
1129 for (offset
= 0, i
= 0; offset
+ delta
<= length
; offset
+= delta
, i
++)
1130 emit_move_insn (adjust_address (dest
, mode
, offset
), regs
[i
]);
1132 /* Mop up any left-over bytes. */
1133 if (offset
< length
)
1135 src
= adjust_address (src
, BLKmode
, offset
);
1136 dest
= adjust_address (dest
, BLKmode
, offset
);
1137 move_by_pieces (dest
, src
, length
- offset
,
1138 MIN (MEM_ALIGN (src
), MEM_ALIGN (dest
)), 0);
1142 /* Helper function for doing a loop-based block operation on memory
1143 reference MEM. Each iteration of the loop will operate on LENGTH
1146 Create a new base register for use within the loop and point it to
1147 the start of MEM. Create a new memory reference that uses this
1148 register. Store them in *LOOP_REG and *LOOP_MEM respectively. */
1151 microblaze_adjust_block_mem (rtx mem
, HOST_WIDE_INT length
,
1152 rtx
* loop_reg
, rtx
* loop_mem
)
1154 *loop_reg
= copy_addr_to_reg (XEXP (mem
, 0));
1156 /* Although the new mem does not refer to a known location,
1157 it does keep up to LENGTH bytes of alignment. */
1158 *loop_mem
= change_address (mem
, BLKmode
, *loop_reg
);
1159 set_mem_align (*loop_mem
,
1160 MIN ((HOST_WIDE_INT
) MEM_ALIGN (mem
),
1161 length
* BITS_PER_UNIT
));
1165 /* Move LENGTH bytes from SRC to DEST using a loop that moves MAX_MOVE_BYTES
1166 per iteration. LENGTH must be at least MAX_MOVE_BYTES. Assume that the
1167 memory regions do not overlap. */
1170 microblaze_block_move_loop (rtx dest
, rtx src
, HOST_WIDE_INT length
)
1172 rtx_code_label
*label
;
1173 rtx src_reg
, dest_reg
, final_src
;
1174 HOST_WIDE_INT leftover
;
1176 leftover
= length
% MAX_MOVE_BYTES
;
1179 /* Create registers and memory references for use within the loop. */
1180 microblaze_adjust_block_mem (src
, MAX_MOVE_BYTES
, &src_reg
, &src
);
1181 microblaze_adjust_block_mem (dest
, MAX_MOVE_BYTES
, &dest_reg
, &dest
);
1183 /* Calculate the value that SRC_REG should have after the last iteration
1185 final_src
= expand_simple_binop (Pmode
, PLUS
, src_reg
, GEN_INT (length
),
1188 /* Emit the start of the loop. */
1189 label
= gen_label_rtx ();
1192 /* Emit the loop body. */
1193 microblaze_block_move_straight (dest
, src
, MAX_MOVE_BYTES
);
1195 /* Move on to the next block. */
1196 emit_move_insn (src_reg
, plus_constant (Pmode
, src_reg
, MAX_MOVE_BYTES
));
1197 emit_move_insn (dest_reg
, plus_constant (Pmode
, dest_reg
, MAX_MOVE_BYTES
));
1199 /* Emit the test & branch. */
1200 emit_insn (gen_cbranchsi4 (gen_rtx_NE (SImode
, src_reg
, final_src
),
1201 src_reg
, final_src
, label
));
1203 /* Mop up any left-over bytes. */
1205 microblaze_block_move_straight (dest
, src
, leftover
);
1208 /* Expand a movmemsi instruction. */
1211 microblaze_expand_block_move (rtx dest
, rtx src
, rtx length
, rtx align_rtx
)
1214 if (GET_CODE (length
) == CONST_INT
)
1216 HOST_WIDE_INT bytes
= INTVAL (length
);
1217 int align
= INTVAL (align_rtx
);
1219 if (align
> UNITS_PER_WORD
)
1221 align
= UNITS_PER_WORD
; /* We can't do any better. */
1223 else if (align
< UNITS_PER_WORD
)
1225 if (INTVAL (length
) <= MAX_MOVE_BYTES
)
1227 move_by_pieces (dest
, src
, bytes
, align
, 0);
1234 if (INTVAL (length
) <= 2 * MAX_MOVE_BYTES
)
1236 microblaze_block_move_straight (dest
, src
, INTVAL (length
));
1241 microblaze_block_move_loop (dest
, src
, INTVAL (length
));
1249 microblaze_rtx_costs (rtx x
, int code
, int outer_code ATTRIBUTE_UNUSED
,
1250 int opno ATTRIBUTE_UNUSED
, int *total
,
1251 bool speed ATTRIBUTE_UNUSED
)
1253 machine_mode mode
= GET_MODE (x
);
1259 int num_words
= (GET_MODE_SIZE (mode
) > UNITS_PER_WORD
) ? 2 : 1;
1260 if (simple_memory_operand (x
, mode
))
1261 *total
= COSTS_N_INSNS (2 * num_words
);
1263 *total
= COSTS_N_INSNS (2 * (2 * num_words
));
1271 *total
= COSTS_N_INSNS (2);
1274 *total
= COSTS_N_INSNS (1);
1283 *total
= COSTS_N_INSNS (2);
1286 *total
= COSTS_N_INSNS (1);
1294 if (TARGET_BARREL_SHIFT
)
1296 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v5.00.a")
1298 *total
= COSTS_N_INSNS (1);
1300 *total
= COSTS_N_INSNS (2);
1302 else if (!TARGET_SOFT_MUL
)
1303 *total
= COSTS_N_INSNS (1);
1304 else if (GET_CODE (XEXP (x
, 1)) == CONST_INT
)
1306 /* Add 1 to make shift slightly more expensive than add. */
1307 *total
= COSTS_N_INSNS (INTVAL (XEXP (x
, 1))) + 1;
1308 /* Reduce shift costs for special circumstances. */
1309 if (optimize_size
&& INTVAL (XEXP (x
, 1)) > 5)
1311 if (!optimize_size
&& INTVAL (XEXP (x
, 1)) > 17)
1315 /* Double the worst cost of shifts when there is no barrel shifter and
1316 the shift amount is in a reg. */
1317 *total
= COSTS_N_INSNS (32 * 4);
1323 if (mode
== SFmode
|| mode
== DFmode
)
1325 if (TARGET_HARD_FLOAT
)
1326 *total
= COSTS_N_INSNS (6);
1329 else if (mode
== DImode
)
1331 *total
= COSTS_N_INSNS (4);
1336 *total
= COSTS_N_INSNS (1);
1345 *total
= COSTS_N_INSNS (4);
1353 if (TARGET_HARD_FLOAT
)
1354 *total
= COSTS_N_INSNS (6);
1356 else if (!TARGET_SOFT_MUL
)
1358 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v5.00.a")
1360 *total
= COSTS_N_INSNS (1);
1362 *total
= COSTS_N_INSNS (3);
1365 *total
= COSTS_N_INSNS (10);
1373 if (TARGET_HARD_FLOAT
)
1374 *total
= COSTS_N_INSNS (23);
1380 *total
= COSTS_N_INSNS (1);
1385 *total
= COSTS_N_INSNS (1);
1393 /* Return the number of instructions needed to load or store a value
1394 of mode MODE at X. Return 0 if X isn't valid for MODE. */
1397 microblaze_address_insns (rtx x
, machine_mode mode
)
1399 struct microblaze_address_info addr
;
1401 if (microblaze_classify_address (&addr
, x
, mode
, false))
1406 if (SMALL_INT (addr
.offset
))
1410 case ADDRESS_CONST_INT
:
1415 case ADDRESS_REG_INDEX
:
1417 case ADDRESS_SYMBOLIC
:
1418 case ADDRESS_GOTOFF
:
1421 switch (addr
.tls_type
)
1439 /* Provide the costs of an addressing mode that contains ADDR.
1440 If ADDR is not a valid address, its cost is irrelevant. */
1442 microblaze_address_cost (rtx addr
, machine_mode mode ATTRIBUTE_UNUSED
,
1443 addr_space_t as ATTRIBUTE_UNUSED
,
1444 bool speed ATTRIBUTE_UNUSED
)
1446 return COSTS_N_INSNS (microblaze_address_insns (addr
, GET_MODE (addr
)));
1449 /* Return nonzero if X is an address which needs a temporary register when
1450 reloaded while generating PIC code. */
1453 pic_address_needs_scratch (rtx x
)
1455 if (GET_CODE (x
) == CONST
&& GET_CODE (XEXP (x
,0)) == PLUS
)
1459 p0
= XEXP (XEXP (x
, 0), 0);
1460 p1
= XEXP (XEXP (x
, 0), 1);
1462 if ((GET_CODE (p0
) == SYMBOL_REF
|| GET_CODE (p0
) == LABEL_REF
)
1463 && (GET_CODE (p1
) == CONST_INT
)
1464 && (flag_pic
== 2 || microblaze_tls_symbol_p (p0
) || !SMALL_INT (p1
)))
1470 /* Argument support functions. */
1471 /* Initialize CUMULATIVE_ARGS for a function. */
1474 init_cumulative_args (CUMULATIVE_ARGS
* cum
, tree fntype
,
1475 rtx libname ATTRIBUTE_UNUSED
)
1477 static CUMULATIVE_ARGS zero_cum
;
1478 tree param
, next_param
;
1482 /* Determine if this function has variable arguments. This is
1483 indicated by the last argument being 'void_type_mode' if there
1484 are no variable arguments. The standard MicroBlaze calling sequence
1485 passes all arguments in the general purpose registers in this case. */
1487 for (param
= fntype
? TYPE_ARG_TYPES (fntype
) : 0;
1488 param
!= 0; param
= next_param
)
1490 next_param
= TREE_CHAIN (param
);
1491 if (next_param
== 0 && TREE_VALUE (param
) != void_type_node
)
1492 cum
->gp_reg_found
= 1;
1496 /* Advance the argument to the next argument position. */
1499 microblaze_function_arg_advance (cumulative_args_t cum_v
,
1501 const_tree type
, bool named ATTRIBUTE_UNUSED
)
1503 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
1512 gcc_assert (GET_MODE_CLASS (mode
) == MODE_COMPLEX_INT
1513 || GET_MODE_CLASS (mode
) == MODE_COMPLEX_FLOAT
);
1515 cum
->gp_reg_found
= 1;
1516 cum
->arg_words
+= ((GET_MODE_SIZE (mode
) + UNITS_PER_WORD
- 1)
1521 cum
->gp_reg_found
= 1;
1522 cum
->arg_words
+= ((int_size_in_bytes (type
) + UNITS_PER_WORD
- 1)
1528 if (!cum
->gp_reg_found
&& cum
->arg_number
<= 2)
1529 cum
->fp_code
+= 1 << ((cum
->arg_number
- 1) * 2);
1533 cum
->arg_words
+= 2;
1534 if (!cum
->gp_reg_found
&& cum
->arg_number
<= 2)
1535 cum
->fp_code
+= 2 << ((cum
->arg_number
- 1) * 2);
1539 cum
->gp_reg_found
= 1;
1540 cum
->arg_words
+= 2;
1547 cum
->gp_reg_found
= 1;
1553 /* Return an RTL expression containing the register for the given mode,
1554 or 0 if the argument is to be passed on the stack. */
1557 microblaze_function_arg (cumulative_args_t cum_v
, machine_mode mode
,
1558 const_tree type ATTRIBUTE_UNUSED
,
1559 bool named ATTRIBUTE_UNUSED
)
1561 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
1565 int *arg_words
= &cum
->arg_words
;
1567 cum
->last_arg_fp
= 0;
1578 regbase
= GP_ARG_FIRST
;
1581 gcc_assert (GET_MODE_CLASS (mode
) == MODE_COMPLEX_INT
1582 || GET_MODE_CLASS (mode
) == MODE_COMPLEX_FLOAT
);
1583 /* Drops through. */
1585 regbase
= GP_ARG_FIRST
;
1589 if (*arg_words
>= MAX_ARGS_IN_REGISTERS
)
1593 gcc_assert (regbase
!= -1);
1595 ret
= gen_rtx_REG (mode
, regbase
+ *arg_words
);
1598 if (mode
== VOIDmode
)
1600 if (cum
->num_adjusts
> 0)
1601 ret
= gen_rtx_PARALLEL ((machine_mode
) cum
->fp_code
,
1602 gen_rtvec_v (cum
->num_adjusts
, cum
->adjust
));
1608 /* Return number of bytes of argument to put in registers. */
1610 function_arg_partial_bytes (cumulative_args_t cum_v
, machine_mode mode
,
1611 tree type
, bool named ATTRIBUTE_UNUSED
)
1613 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
1615 if ((mode
== BLKmode
1616 || GET_MODE_CLASS (mode
) != MODE_COMPLEX_INT
1617 || GET_MODE_CLASS (mode
) != MODE_COMPLEX_FLOAT
)
1618 && cum
->arg_words
< MAX_ARGS_IN_REGISTERS
)
1621 if (mode
== BLKmode
)
1622 words
= ((int_size_in_bytes (type
) + UNITS_PER_WORD
- 1)
1625 words
= (GET_MODE_SIZE (mode
) + UNITS_PER_WORD
- 1) / UNITS_PER_WORD
;
1627 if (words
+ cum
->arg_words
<= MAX_ARGS_IN_REGISTERS
)
1628 return 0; /* structure fits in registers */
1630 return (MAX_ARGS_IN_REGISTERS
- cum
->arg_words
) * UNITS_PER_WORD
;
1633 else if (mode
== DImode
&& cum
->arg_words
== MAX_ARGS_IN_REGISTERS
- 1)
1634 return UNITS_PER_WORD
;
1639 /* Convert a version number of the form "vX.YY.Z" to an integer encoding
1640 for easier range comparison. */
1642 microblaze_version_to_int (const char *version
)
1645 const char *tmpl
= "vXX.YY.Z";
1654 { /* Looking for major */
1661 if (!(*p
>= '0' && *p
<= '9'))
1663 iver
+= (int) (*p
- '0');
1668 { /* Looking for minor */
1669 if (!(*p
>= '0' && *p
<= '9'))
1671 iver
+= (int) (*p
- '0');
1675 { /* Looking for compat */
1676 if (!(*p
>= 'a' && *p
<= 'z'))
1679 iver
+= (int) (*p
- 'a');
1699 microblaze_option_override (void)
1701 register int i
, start
;
1703 register machine_mode mode
;
1706 microblaze_section_threshold
= (global_options_set
.x_g_switch_value
1708 : MICROBLAZE_DEFAULT_GVALUE
);
1712 /* Make sure it's 2, we only support one kind of PIC. */
1714 if (!TARGET_SUPPORTS_PIC
)
1716 error ("-fPIC/-fpic not supported for this target");
1717 /* Clear it to avoid further errors. */
1722 /* Check the MicroBlaze CPU version for any special action to be done. */
1723 if (microblaze_select_cpu
== NULL
)
1724 microblaze_select_cpu
= MICROBLAZE_DEFAULT_CPU
;
1725 ver
= microblaze_version_to_int (microblaze_select_cpu
);
1728 error ("%qs is an invalid argument to -mcpu=", microblaze_select_cpu
);
1731 ver
= MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v3.00.a");
1734 /* No hardware exceptions in earlier versions. So no worries. */
1736 microblaze_select_flags
&= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY
);
1738 microblaze_no_unsafe_delay
= 0;
1739 microblaze_pipe
= MICROBLAZE_PIPE_3
;
1742 || (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v4.00.b")
1746 microblaze_select_flags
|= (MICROBLAZE_MASK_NO_UNSAFE_DELAY
);
1748 microblaze_no_unsafe_delay
= 1;
1749 microblaze_pipe
= MICROBLAZE_PIPE_3
;
1753 /* We agree to use 5 pipe-stage model even on area optimized 3
1754 pipe-stage variants. */
1756 microblaze_select_flags
&= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY
);
1758 microblaze_no_unsafe_delay
= 0;
1759 microblaze_pipe
= MICROBLAZE_PIPE_5
;
1760 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v5.00.a") == 0
1761 || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
,
1763 || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
,
1766 /* Pattern compares are to be turned on by default only when
1767 compiling for MB v5.00.'z'. */
1768 target_flags
|= MASK_PATTERN_COMPARE
;
1772 ver
= MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v6.00.a");
1775 if (TARGET_MULTIPLY_HIGH
)
1777 "-mxl-multiply-high can be used only with -mcpu=v6.00.a or greater");
1780 ver
= MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v8.10.a");
1781 microblaze_has_clz
= 1;
1784 /* MicroBlaze prior to 8.10.a didn't have clz. */
1785 microblaze_has_clz
= 0;
1788 /* TARGET_REORDER defaults to 2 if -mxl-reorder not specified. */
1789 ver
= MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v8.30.a");
1792 if (TARGET_REORDER
== 1)
1793 warning (0, "-mxl-reorder can be used only with -mcpu=v8.30.a or greater");
1796 else if ((ver
== 0) && !TARGET_PATTERN_COMPARE
)
1798 if (TARGET_REORDER
== 1)
1799 warning (0, "-mxl-reorder requires -mxl-pattern-compare for -mcpu=v8.30.a");
1803 if (TARGET_MULTIPLY_HIGH
&& TARGET_SOFT_MUL
)
1804 error ("-mxl-multiply-high requires -mno-xl-soft-mul");
1806 /* Always use DFA scheduler. */
1807 microblaze_sched_use_dfa
= 1;
1810 microblaze_abicalls
= MICROBLAZE_ABICALLS_NO
;
1813 /* Initialize the high, low values for legit floating point constants. */
1814 real_maxval (&dfhigh
, 0, DFmode
);
1815 real_maxval (&dflow
, 1, DFmode
);
1816 real_maxval (&sfhigh
, 0, SFmode
);
1817 real_maxval (&sflow
, 1, SFmode
);
1819 microblaze_print_operand_punct
['?'] = 1;
1820 microblaze_print_operand_punct
['#'] = 1;
1821 microblaze_print_operand_punct
['&'] = 1;
1822 microblaze_print_operand_punct
['!'] = 1;
1823 microblaze_print_operand_punct
['*'] = 1;
1824 microblaze_print_operand_punct
['@'] = 1;
1825 microblaze_print_operand_punct
['.'] = 1;
1826 microblaze_print_operand_punct
['('] = 1;
1827 microblaze_print_operand_punct
[')'] = 1;
1828 microblaze_print_operand_punct
['['] = 1;
1829 microblaze_print_operand_punct
[']'] = 1;
1830 microblaze_print_operand_punct
['<'] = 1;
1831 microblaze_print_operand_punct
['>'] = 1;
1832 microblaze_print_operand_punct
['{'] = 1;
1833 microblaze_print_operand_punct
['}'] = 1;
1834 microblaze_print_operand_punct
['^'] = 1;
1835 microblaze_print_operand_punct
['$'] = 1;
1836 microblaze_print_operand_punct
['+'] = 1;
1838 /* Set up array to map GCC register number to debug register number.
1839 Ignore the special purpose register numbers. */
1841 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
1842 microblaze_dbx_regno
[i
] = -1;
1844 start
= GP_DBX_FIRST
- GP_REG_FIRST
;
1845 for (i
= GP_REG_FIRST
; i
<= GP_REG_LAST
; i
++)
1846 microblaze_dbx_regno
[i
] = i
+ start
;
1848 /* Set up array giving whether a given register can hold a given mode. */
1850 for (mode
= VOIDmode
;
1851 mode
!= MAX_MACHINE_MODE
; mode
= (machine_mode
) ((int) mode
+ 1))
1853 register int size
= GET_MODE_SIZE (mode
);
1855 for (regno
= 0; regno
< FIRST_PSEUDO_REGISTER
; regno
++)
1861 ok
= (ST_REG_P (regno
) || GP_REG_P (regno
));
1863 else if (GP_REG_P (regno
))
1864 ok
= ((regno
& 1) == 0 || size
<= UNITS_PER_WORD
);
1868 microblaze_hard_regno_mode_ok
[(int) mode
][regno
] = ok
;
1873 /* Return true if FUNC is an interrupt function as specified
1874 by the "interrupt_handler" attribute. */
1877 microblaze_interrupt_function_p (tree func
)
1881 if (TREE_CODE (func
) != FUNCTION_DECL
)
1884 a
= lookup_attribute ("interrupt_handler", DECL_ATTRIBUTES (func
));
1885 return a
!= NULL_TREE
;
1889 microblaze_fast_interrupt_function_p (tree func
)
1893 if (TREE_CODE (func
) != FUNCTION_DECL
)
1896 a
= lookup_attribute ("fast_interrupt", DECL_ATTRIBUTES (func
));
1897 return a
!= NULL_TREE
;
1900 microblaze_break_function_p (tree func
)
1905 if (TREE_CODE (func
) != FUNCTION_DECL
)
1908 a
= lookup_attribute ("break_handler", DECL_ATTRIBUTES (func
));
1909 return a
!= NULL_TREE
;
1911 /* Return true if FUNC is an interrupt function which uses
1912 normal return, indicated by the "save_volatiles" attribute. */
1915 microblaze_save_volatiles (tree func
)
1919 if (TREE_CODE (func
) != FUNCTION_DECL
)
1922 a
= lookup_attribute ("save_volatiles", DECL_ATTRIBUTES (func
));
1923 return a
!= NULL_TREE
;
1926 /* Return whether function is tagged with 'interrupt_handler'
1927 or 'fast_interrupt' attribute. Return true if function
1928 should use return from interrupt rather than normal
1931 microblaze_is_interrupt_variant (void)
1933 return (interrupt_handler
|| fast_interrupt
);
1936 microblaze_is_break_handler (void)
1938 return break_handler
;
1941 /* Determine of register must be saved/restored in call. */
1943 microblaze_must_save_register (int regno
)
1945 if (pic_offset_table_rtx
&&
1946 (regno
== MB_ABI_PIC_ADDR_REGNUM
) && df_regs_ever_live_p (regno
))
1949 if (df_regs_ever_live_p (regno
) && !call_used_regs
[regno
])
1952 if (frame_pointer_needed
&& (regno
== HARD_FRAME_POINTER_REGNUM
))
1957 if (regno
== MB_ABI_SUB_RETURN_ADDR_REGNUM
)
1959 if ((microblaze_is_interrupt_variant () || save_volatiles
) &&
1960 (regno
>= 3 && regno
<= 12))
1964 if (microblaze_is_interrupt_variant ())
1966 if (df_regs_ever_live_p (regno
)
1967 || regno
== MB_ABI_MSR_SAVE_REG
1968 || (interrupt_handler
1969 && (regno
== MB_ABI_ASM_TEMP_REGNUM
1970 || regno
== MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM
)))
1976 if (df_regs_ever_live_p (regno
)
1977 || regno
== MB_ABI_ASM_TEMP_REGNUM
1978 || regno
== MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM
)
1985 /* Return the bytes needed to compute the frame pointer from the current
1988 MicroBlaze stack frames look like:
1992 Before call After call
1993 +-----------------------+ +-----------------------+
1995 mem. | local variables, | | local variables, |
1996 | callee saved and | | callee saved and |
1998 +-----------------------+ +-----------------------+
1999 | arguments for called | | arguments for called |
2000 | subroutines | | subroutines |
2001 | (optional) | | (optional) |
2002 +-----------------------+ +-----------------------+
2003 | Link register | | Link register |
2005 +-----------------------+ +-----------------------+
2007 | local variables, |
2008 | callee saved and |
2010 +-----------------------+
2011 | MSR (optional if, |
2012 | interrupt handler) |
2013 +-----------------------+
2015 | alloca allocations |
2017 +-----------------------+
2019 | arguments for called |
2023 +-----------------------+
2026 memory +-----------------------+
2030 static HOST_WIDE_INT
2031 compute_frame_size (HOST_WIDE_INT size
)
2034 HOST_WIDE_INT total_size
; /* # bytes that the entire frame takes up. */
2035 HOST_WIDE_INT var_size
; /* # bytes that local variables take up. */
2036 HOST_WIDE_INT args_size
; /* # bytes that outgoing arguments take up. */
2037 int link_debug_size
; /* # bytes for link register. */
2038 HOST_WIDE_INT gp_reg_size
; /* # bytes needed to store calle-saved gp regs. */
2039 long mask
; /* mask of saved gp registers. */
2042 microblaze_interrupt_function_p (current_function_decl
);
2044 microblaze_break_function_p (current_function_decl
);
2047 microblaze_fast_interrupt_function_p (current_function_decl
);
2048 save_volatiles
= microblaze_save_volatiles (current_function_decl
);
2050 interrupt_handler
= break_handler
;
2055 args_size
= crtl
->outgoing_args_size
;
2057 if ((args_size
== 0) && cfun
->calls_alloca
)
2058 args_size
= NUM_OF_ARGS
* UNITS_PER_WORD
;
2060 total_size
= var_size
+ args_size
;
2063 /* force setting GOT. */
2064 df_set_regs_ever_live (MB_ABI_PIC_ADDR_REGNUM
, true);
2066 /* Calculate space needed for gp registers. */
2067 for (regno
= GP_REG_FIRST
; regno
<= GP_REG_LAST
; regno
++)
2069 if (microblaze_must_save_register (regno
))
2072 if (regno
!= MB_ABI_SUB_RETURN_ADDR_REGNUM
)
2073 /* Don't account for link register. It is accounted specially below. */
2074 gp_reg_size
+= GET_MODE_SIZE (SImode
);
2076 mask
|= (1L << (regno
- GP_REG_FIRST
));
2080 total_size
+= gp_reg_size
;
2082 /* Add 4 bytes for MSR. */
2083 if (microblaze_is_interrupt_variant ())
2086 /* No space to be allocated for link register in leaf functions with no other
2087 stack requirements. */
2088 if (total_size
== 0 && crtl
->is_leaf
)
2089 link_debug_size
= 0;
2091 link_debug_size
= UNITS_PER_WORD
;
2093 total_size
+= link_debug_size
;
2095 /* Save other computed information. */
2096 current_frame_info
.total_size
= total_size
;
2097 current_frame_info
.var_size
= var_size
;
2098 current_frame_info
.args_size
= args_size
;
2099 current_frame_info
.gp_reg_size
= gp_reg_size
;
2100 current_frame_info
.mask
= mask
;
2101 current_frame_info
.initialized
= reload_completed
;
2102 current_frame_info
.num_gp
= gp_reg_size
/ UNITS_PER_WORD
;
2103 current_frame_info
.link_debug_size
= link_debug_size
;
2106 /* Offset from which to callee-save GP regs. */
2107 current_frame_info
.gp_offset
= (total_size
- gp_reg_size
);
2109 current_frame_info
.gp_offset
= 0;
2111 /* Ok, we're done. */
2115 /* Make sure that we're not trying to eliminate to the wrong hard frame
2119 microblaze_can_eliminate (const int from
, const int to
)
2121 return ((from
== RETURN_ADDRESS_POINTER_REGNUM
&& !leaf_function_p())
2122 || (to
== MB_ABI_SUB_RETURN_ADDR_REGNUM
&& leaf_function_p())
2123 || (from
!= RETURN_ADDRESS_POINTER_REGNUM
2124 && (to
== HARD_FRAME_POINTER_REGNUM
2125 || (to
== STACK_POINTER_REGNUM
&& !frame_pointer_needed
))));
2128 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
2129 pointer or argument pointer or the return address pointer. TO is either
2130 the stack pointer or hard frame pointer. */
2133 microblaze_initial_elimination_offset (int from
, int to
)
2135 HOST_WIDE_INT offset
;
2139 case FRAME_POINTER_REGNUM
:
2142 case ARG_POINTER_REGNUM
:
2143 if (to
== STACK_POINTER_REGNUM
|| to
== HARD_FRAME_POINTER_REGNUM
)
2144 offset
= compute_frame_size (get_frame_size ());
2148 case RETURN_ADDRESS_POINTER_REGNUM
:
2152 offset
= current_frame_info
.gp_offset
+
2153 ((UNITS_PER_WORD
- (POINTER_SIZE
/ BITS_PER_UNIT
)));
2161 /* Print operands using format code.
2163 The MicroBlaze specific codes are:
2165 'X' X is CONST_INT, prints 32 bits in hexadecimal format = "0x%08x",
2166 'x' X is CONST_INT, prints 16 bits in hexadecimal format = "0x%04x",
2167 'F' op is CONST_DOUBLE, print 32 bits in hex,
2168 'd' output integer constant in decimal,
2169 'z' if the operand is 0, use $0 instead of normal operand.
2170 'D' print second register of double-word register operand.
2171 'L' print low-order register of double-word register operand.
2172 'M' print high-order register of double-word register operand.
2173 'C' print part of opcode for a branch condition.
2174 'N' print part of opcode for a branch condition, inverted.
2175 'S' X is CODE_LABEL, print with prefix of "LS" (for embedded switch).
2176 'B' print 'z' for EQ, 'n' for NE
2177 'b' print 'n' for EQ, 'z' for NE
2178 'T' print 'f' for EQ, 't' for NE
2179 't' print 't' for EQ, 'f' for NE
2180 'm' Print 1<<operand.
2181 'i' Print 'i' if MEM operand has immediate value
2182 'y' Print 'y' if MEM operand is single register
2183 'o' Print operand address+4
2184 '?' Print 'd' if we use a branch with delay slot instead of normal branch.
2185 'h' Print high word of const_double (int or float) value as hex
2186 'j' Print low word of const_double (int or float) value as hex
2187 's' Print -1 if operand is negative, 0 if positive (sign extend)
2188 '@' Print the name of the temporary register (rMB_ABI_ASM_TEMP_REGNUM).
2189 '#' Print nop if the delay slot of a branch is not filled.
2193 print_operand (FILE * file
, rtx op
, int letter
)
2195 register enum rtx_code code
;
2197 if (PRINT_OPERAND_PUNCT_VALID_P (letter
))
2202 /* Conditionally add a 'd' to indicate filled delay slot. */
2203 if (final_sequence
!= NULL
)
2208 /* Conditionally add a nop in unfilled delay slot. */
2209 if (final_sequence
== NULL
)
2210 fputs ("nop\t\t# Unfilled delay slot\n", file
);
2214 fputs (reg_names
[GP_REG_FIRST
+ MB_ABI_ASM_TEMP_REGNUM
], file
);
2218 output_operand_lossage ("unknown punctuation '%c'", letter
);
2227 output_operand_lossage ("null pointer");
2231 code
= GET_CODE (op
);
2233 if (code
== SIGN_EXTEND
)
2234 op
= XEXP (op
, 0), code
= GET_CODE (op
);
2262 fatal_insn ("PRINT_OPERAND, invalid insn for %%C", op
);
2265 else if (letter
== 'N')
2291 fatal_insn ("PRINT_OPERAND, invalid insn for %%N", op
);
2294 else if (letter
== 'S')
2298 ASM_GENERATE_INTERNAL_LABEL (buffer
, "LS", CODE_LABEL_NUMBER (op
));
2299 assemble_name (file
, buffer
);
2302 /* Print 'i' for memory operands which have immediate values. */
2303 else if (letter
== 'i')
2307 struct microblaze_address_info info
;
2309 if (!microblaze_classify_address
2310 (&info
, XEXP (op
, 0), GET_MODE (op
), 1))
2311 fatal_insn ("insn contains an invalid address !", op
);
2316 case ADDRESS_CONST_INT
:
2317 case ADDRESS_SYMBOLIC
:
2318 case ADDRESS_GOTOFF
:
2322 case ADDRESS_REG_INDEX
:
2324 case ADDRESS_INVALID
:
2326 fatal_insn ("invalid address", op
);
2331 else if (code
== REG
|| code
== SUBREG
)
2333 register int regnum
;
2336 regnum
= REGNO (op
);
2338 regnum
= true_regnum (op
);
2340 if ((letter
== 'M' && !WORDS_BIG_ENDIAN
)
2341 || (letter
== 'L' && WORDS_BIG_ENDIAN
) || letter
== 'D')
2344 fprintf (file
, "%s", reg_names
[regnum
]);
2347 else if (code
== MEM
)
2350 rtx op4
= adjust_address (op
, GET_MODE (op
), 4);
2351 output_address (XEXP (op4
, 0));
2353 else if (letter
== 'y')
2355 rtx mem_reg
= XEXP (op
, 0);
2356 if (GET_CODE (mem_reg
) == REG
)
2358 register int regnum
= REGNO (mem_reg
);
2359 fprintf (file
, "%s", reg_names
[regnum
]);
2363 output_address (XEXP (op
, 0));
2365 else if (letter
== 'h' || letter
== 'j')
2368 if (code
== CONST_DOUBLE
)
2370 if (GET_MODE (op
) == DFmode
)
2372 REAL_VALUE_TYPE value
;
2373 REAL_VALUE_FROM_CONST_DOUBLE (value
, op
);
2374 REAL_VALUE_TO_TARGET_DOUBLE (value
, val
);
2378 val
[0] = CONST_DOUBLE_HIGH (op
);
2379 val
[1] = CONST_DOUBLE_LOW (op
);
2382 else if (code
== CONST_INT
)
2384 val
[0] = (INTVAL (op
) & 0xffffffff00000000LL
) >> 32;
2385 val
[1] = INTVAL (op
) & 0x00000000ffffffffLL
;
2386 if (val
[0] == 0 && val
[1] < 0)
2390 fprintf (file
, "0x%8.8lx", (letter
== 'h') ? val
[0] : val
[1]);
2392 else if (code
== CONST_DOUBLE
)
2396 unsigned long value_long
;
2397 REAL_VALUE_TYPE value
;
2398 REAL_VALUE_FROM_CONST_DOUBLE (value
, op
);
2399 REAL_VALUE_TO_TARGET_SINGLE (value
, value_long
);
2400 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, value_long
);
2405 real_to_decimal (s
, CONST_DOUBLE_REAL_VALUE (op
), sizeof (s
), 0, 1);
2410 else if (code
== UNSPEC
)
2412 print_operand_address (file
, op
);
2415 else if (letter
== 'x' && GET_CODE (op
) == CONST_INT
)
2416 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, 0xffff & INTVAL (op
));
2418 else if (letter
== 'X' && GET_CODE (op
) == CONST_INT
)
2419 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, INTVAL (op
));
2421 else if (letter
== 'd' && GET_CODE (op
) == CONST_INT
)
2422 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, (INTVAL (op
)));
2424 else if (letter
== 'z' && GET_CODE (op
) == CONST_INT
&& INTVAL (op
) == 0)
2425 fputs (reg_names
[GP_REG_FIRST
], file
);
2427 else if (letter
== 's' && GET_CODE (op
) == CONST_INT
)
2428 if (INTVAL (op
) < 0)
2433 else if (letter
== 'd' || letter
== 'x' || letter
== 'X' || letter
== 's')
2434 output_operand_lossage ("letter %c was found & insn was not CONST_INT", letter
);
2436 else if (letter
== 'B')
2437 fputs (code
== EQ
? "z" : "n", file
);
2438 else if (letter
== 'b')
2439 fputs (code
== EQ
? "n" : "z", file
);
2440 else if (letter
== 'T')
2441 fputs (code
== EQ
? "f" : "t", file
);
2442 else if (letter
== 't')
2443 fputs (code
== EQ
? "t" : "f", file
);
2445 else if (code
== CONST
2446 && ((GET_CODE (XEXP (op
, 0)) == REG
)
2447 || (GET_CODE (XEXP (op
, 0)) == UNSPEC
)))
2449 print_operand (file
, XEXP (op
, 0), letter
);
2451 else if (code
== CONST
2452 && (GET_CODE (XEXP (op
, 0)) == PLUS
)
2453 && (GET_CODE (XEXP (XEXP (op
, 0), 0)) == REG
)
2454 && (GET_CODE (XEXP (XEXP (op
, 0), 1)) == CONST
))
2456 print_operand_address (file
, XEXP (op
, 0));
2458 else if (letter
== 'm')
2459 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, (1L << INTVAL (op
)));
2461 output_addr_const (file
, op
);
2464 /* A C compound statement to output to stdio stream STREAM the
2465 assembler syntax for an instruction operand that is a memory
2466 reference whose address is ADDR. ADDR is an RTL expression.
2468 Possible address classifications and output formats are,
2470 ADDRESS_REG "%0, r0"
2472 ADDRESS_REG with non-zero "%0, <addr_const>"
2475 ADDRESS_REG_INDEX "rA, RB"
2476 (if rA is r0, rA and rB are swapped)
2478 ADDRESS_CONST_INT "r0, <addr_const>"
2480 ADDRESS_SYMBOLIC "rBase, <addr_const>"
2481 (rBase is a base register suitable for the
2486 print_operand_address (FILE * file
, rtx addr
)
2488 struct microblaze_address_info info
;
2489 enum microblaze_address_type type
;
2490 if (!microblaze_classify_address (&info
, addr
, GET_MODE (addr
), 1))
2491 fatal_insn ("insn contains an invalid address !", addr
);
2497 fprintf (file
, "%s,", reg_names
[REGNO (info
.regA
)]);
2498 output_addr_const (file
, info
.offset
);
2500 case ADDRESS_REG_INDEX
:
2501 if (REGNO (info
.regA
) == 0)
2502 /* Make rB == r0 instead of rA == r0. This helps reduce read port
2504 fprintf (file
, "%s,%s", reg_names
[REGNO (info
.regB
)],
2505 reg_names
[REGNO (info
.regA
)]);
2506 else if (REGNO (info
.regB
) != 0)
2507 /* This is a silly swap to help Dhrystone. */
2508 fprintf (file
, "%s,%s", reg_names
[REGNO (info
.regB
)],
2509 reg_names
[REGNO (info
.regA
)]);
2511 case ADDRESS_CONST_INT
:
2512 fprintf (file
, "%s,", reg_names
[REGNO (info
.regA
)]);
2513 output_addr_const (file
, info
.offset
);
2515 case ADDRESS_SYMBOLIC
:
2516 case ADDRESS_GOTOFF
:
2520 fprintf (file
, "%s,", reg_names
[REGNO (info
.regA
)]);
2521 output_addr_const (file
, info
.symbol
);
2522 if (type
== ADDRESS_GOTOFF
)
2524 fputs ("@GOT", file
);
2526 else if (type
== ADDRESS_PLT
)
2528 fputs ("@PLT", file
);
2530 else if (type
== ADDRESS_TLS
)
2532 switch (info
.tls_type
)
2535 fputs ("@TLSGD", file
);
2538 fputs ("@TLSLDM", file
);
2541 fputs ("@TLSDTPREL", file
);
2549 case ADDRESS_INVALID
:
2550 fatal_insn ("invalid address", addr
);
2555 /* Emit either a label, .comm, or .lcomm directive, and mark that the symbol
2556 is used, so that we don't emit an .extern for it in
2557 microblaze_asm_file_end. */
2560 microblaze_declare_object (FILE * stream
, const char *name
,
2561 const char *section
, const char *fmt
, int size
)
2564 fputs (section
, stream
);
2565 assemble_name (stream
, name
);
2566 fprintf (stream
, fmt
, size
);
2569 /* Common code to emit the insns (or to write the instructions to a file)
2570 to save/restore registers.
2572 Other parts of the code assume that MICROBLAZE_TEMP1_REGNUM (aka large_reg)
2573 is not modified within save_restore_insns. */
2575 #define BITSET_P(VALUE,BIT) (((VALUE) & (1L << (BIT))) != 0)
2577 /* Save or restore instructions based on whether this is the prologue or
2578 epilogue. prologue is 1 for the prologue. */
2580 save_restore_insns (int prologue
)
2582 rtx base_reg_rtx
, reg_rtx
, mem_rtx
, /* msr_rtx, */ isr_reg_rtx
=
2584 rtx isr_msr_rtx
= 0, insn
;
2585 long mask
= current_frame_info
.mask
;
2586 HOST_WIDE_INT gp_offset
;
2589 if (frame_pointer_needed
2590 && !BITSET_P (mask
, HARD_FRAME_POINTER_REGNUM
- GP_REG_FIRST
))
2596 /* Save registers starting from high to low. The debuggers prefer at least
2597 the return register be stored at func+4, and also it allows us not to
2598 need a nop in the epilog if at least one register is reloaded in
2599 addition to return address. */
2601 /* Pick which pointer to use as a base register. For small frames, just
2602 use the stack pointer. Otherwise, use a temporary register. Save 2
2603 cycles if the save area is near the end of a large frame, by reusing
2604 the constant created in the prologue/epilogue to adjust the stack
2607 gp_offset
= current_frame_info
.gp_offset
;
2609 gcc_assert (gp_offset
> 0);
2611 base_reg_rtx
= stack_pointer_rtx
;
2613 /* For interrupt_handlers, need to save/restore the MSR. */
2614 if (microblaze_is_interrupt_variant ())
2616 isr_mem_rtx
= gen_rtx_MEM (SImode
,
2617 gen_rtx_PLUS (Pmode
, base_reg_rtx
,
2618 GEN_INT (current_frame_info
.
2622 /* Do not optimize in flow analysis. */
2623 MEM_VOLATILE_P (isr_mem_rtx
) = 1;
2624 isr_reg_rtx
= gen_rtx_REG (SImode
, MB_ABI_MSR_SAVE_REG
);
2625 isr_msr_rtx
= gen_rtx_REG (SImode
, ST_REG
);
2628 if (microblaze_is_interrupt_variant () && !prologue
)
2630 emit_move_insn (isr_reg_rtx
, isr_mem_rtx
);
2631 emit_move_insn (isr_msr_rtx
, isr_reg_rtx
);
2632 /* Do not optimize in flow analysis. */
2633 emit_insn (gen_rtx_USE (SImode
, isr_reg_rtx
));
2634 emit_insn (gen_rtx_USE (SImode
, isr_msr_rtx
));
2637 for (regno
= GP_REG_FIRST
; regno
<= GP_REG_LAST
; regno
++)
2639 if (BITSET_P (mask
, regno
- GP_REG_FIRST
))
2641 if (regno
== MB_ABI_SUB_RETURN_ADDR_REGNUM
)
2642 /* Don't handle here. Already handled as the first register. */
2645 reg_rtx
= gen_rtx_REG (SImode
, regno
);
2646 insn
= gen_rtx_PLUS (Pmode
, base_reg_rtx
, GEN_INT (gp_offset
));
2647 mem_rtx
= gen_rtx_MEM (SImode
, insn
);
2648 if (microblaze_is_interrupt_variant () || save_volatiles
)
2649 /* Do not optimize in flow analysis. */
2650 MEM_VOLATILE_P (mem_rtx
) = 1;
2654 insn
= emit_move_insn (mem_rtx
, reg_rtx
);
2655 RTX_FRAME_RELATED_P (insn
) = 1;
2659 insn
= emit_move_insn (reg_rtx
, mem_rtx
);
2662 gp_offset
+= GET_MODE_SIZE (SImode
);
2666 if (microblaze_is_interrupt_variant () && prologue
)
2668 emit_move_insn (isr_reg_rtx
, isr_msr_rtx
);
2669 emit_move_insn (isr_mem_rtx
, isr_reg_rtx
);
2671 /* Do not optimize in flow analysis. */
2672 emit_insn (gen_rtx_USE (SImode
, isr_reg_rtx
));
2673 emit_insn (gen_rtx_USE (SImode
, isr_msr_rtx
));
2676 /* Done saving and restoring */
2680 /* Set up the stack and frame (if desired) for the function. */
2682 microblaze_function_prologue (FILE * file
, HOST_WIDE_INT size ATTRIBUTE_UNUSED
)
2685 long fsiz
= current_frame_info
.total_size
;
2687 /* Get the function name the same way that toplev.c does before calling
2688 assemble_start_function. This is needed so that the name used here
2689 exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */
2690 fnname
= XSTR (XEXP (DECL_RTL (current_function_decl
), 0), 0);
2691 if (!flag_inhibit_size_directive
)
2693 fputs ("\t.ent\t", file
);
2694 if (interrupt_handler
&& strcmp (INTERRUPT_HANDLER_NAME
, fnname
))
2695 fputs ("_interrupt_handler", file
);
2696 else if (break_handler
&& strcmp (BREAK_HANDLER_NAME
, fnname
))
2697 fputs ("_break_handler", file
);
2698 else if (fast_interrupt
&& strcmp (FAST_INTERRUPT_NAME
, fnname
))
2699 fputs ("_fast_interrupt", file
);
2701 assemble_name (file
, fnname
);
2703 if (!microblaze_is_interrupt_variant ())
2704 ASM_OUTPUT_TYPE_DIRECTIVE (file
, fnname
, "function");
2707 assemble_name (file
, fnname
);
2708 fputs (":\n", file
);
2710 if (interrupt_handler
&& strcmp (INTERRUPT_HANDLER_NAME
, fnname
))
2711 fputs ("_interrupt_handler:\n", file
);
2712 if (break_handler
&& strcmp (BREAK_HANDLER_NAME
, fnname
))
2713 fputs ("_break_handler:\n", file
);
2714 if (!flag_inhibit_size_directive
)
2716 /* .frame FRAMEREG, FRAMESIZE, RETREG. */
2718 "\t.frame\t%s,%ld,%s\t\t# vars= %ld, regs= %d, args= %d\n",
2719 (reg_names
[(frame_pointer_needed
)
2720 ? HARD_FRAME_POINTER_REGNUM
:
2721 STACK_POINTER_REGNUM
]), fsiz
,
2722 reg_names
[MB_ABI_SUB_RETURN_ADDR_REGNUM
+ GP_REG_FIRST
],
2723 current_frame_info
.var_size
, current_frame_info
.num_gp
,
2724 crtl
->outgoing_args_size
);
2725 fprintf (file
, "\t.mask\t0x%08lx\n", current_frame_info
.mask
);
2729 /* Output extra assembler code at the end of a prologue. */
2731 microblaze_function_end_prologue (FILE * file
)
2733 if (TARGET_STACK_CHECK
)
2735 fprintf (file
, "\t# Stack Check Stub -- Start.\n\t");
2736 fprintf (file
, "ori\tr18,r0,_stack_end\n\t");
2737 fprintf (file
, "cmpu\tr18,r1,r18\n\t");
2738 fprintf (file
, "bgei\tr18,_stack_overflow_exit\n\t");
2739 fprintf (file
, "# Stack Check Stub -- End.\n");
2744 microblaze_elf_asm_cdtor (rtx symbol
, int priority
, bool is_ctor
)
2748 if (priority
!= DEFAULT_INIT_PRIORITY
)
2751 sprintf (buf
, "%s.%.5u",
2752 is_ctor
? ".ctors" : ".dtors",
2753 MAX_INIT_PRIORITY
- priority
);
2754 s
= get_section (buf
, SECTION_WRITE
, NULL_TREE
);
2761 switch_to_section (s
);
2762 assemble_align (POINTER_SIZE
);
2763 fputs ("\t.word\t", asm_out_file
);
2764 output_addr_const (asm_out_file
, symbol
);
2765 fputs ("\n", asm_out_file
);
2768 /* Add a function to the list of static constructors. */
2771 microblaze_elf_asm_constructor (rtx symbol
, int priority
)
2773 microblaze_elf_asm_cdtor (symbol
, priority
, /*is_ctor=*/true);
2776 /* Add a function to the list of static destructors. */
2779 microblaze_elf_asm_destructor (rtx symbol
, int priority
)
2781 microblaze_elf_asm_cdtor (symbol
, priority
, /*is_ctor=*/false);
2784 /* Expand the prologue into a bunch of separate insns. */
2787 microblaze_expand_prologue (void)
2791 const char *arg_name
= 0;
2792 tree fndecl
= current_function_decl
;
2793 tree fntype
= TREE_TYPE (fndecl
);
2794 tree fnargs
= DECL_ARGUMENTS (fndecl
);
2799 CUMULATIVE_ARGS args_so_far_v
;
2800 cumulative_args_t args_so_far
;
2801 rtx mem_rtx
, reg_rtx
;
2803 /* If struct value address is treated as the first argument, make it so. */
2804 if (aggregate_value_p (DECL_RESULT (fndecl
), fntype
)
2805 && !cfun
->returns_pcc_struct
)
2807 tree type
= build_pointer_type (fntype
);
2808 tree function_result_decl
= build_decl (BUILTINS_LOCATION
, PARM_DECL
,
2811 DECL_ARG_TYPE (function_result_decl
) = type
;
2812 TREE_CHAIN (function_result_decl
) = fnargs
;
2813 fnargs
= function_result_decl
;
2816 /* Determine the last argument, and get its name. */
2818 INIT_CUMULATIVE_ARGS (args_so_far_v
, fntype
, NULL_RTX
, 0, 0);
2819 args_so_far
= pack_cumulative_args (&args_so_far_v
);
2820 regno
= GP_ARG_FIRST
;
2822 for (cur_arg
= fnargs
; cur_arg
!= 0; cur_arg
= next_arg
)
2824 tree passed_type
= DECL_ARG_TYPE (cur_arg
);
2825 machine_mode passed_mode
= TYPE_MODE (passed_type
);
2828 if (TREE_ADDRESSABLE (passed_type
))
2830 passed_type
= build_pointer_type (passed_type
);
2831 passed_mode
= Pmode
;
2834 entry_parm
= targetm
.calls
.function_arg (args_so_far
, passed_mode
,
2841 /* passed in a register, so will get homed automatically. */
2842 if (GET_MODE (entry_parm
) == BLKmode
)
2843 words
= (int_size_in_bytes (passed_type
) + 3) / 4;
2845 words
= (GET_MODE_SIZE (GET_MODE (entry_parm
)) + 3) / 4;
2847 regno
= REGNO (entry_parm
) + words
- 1;
2851 regno
= GP_ARG_LAST
+ 1;
2855 targetm
.calls
.function_arg_advance (args_so_far
, passed_mode
,
2858 next_arg
= TREE_CHAIN (cur_arg
);
2861 if (DECL_NAME (cur_arg
))
2862 arg_name
= IDENTIFIER_POINTER (DECL_NAME (cur_arg
));
2868 /* Split parallel insn into a sequence of insns. */
2870 next_arg_reg
= targetm
.calls
.function_arg (args_so_far
, VOIDmode
,
2871 void_type_node
, true);
2872 if (next_arg_reg
!= 0 && GET_CODE (next_arg_reg
) == PARALLEL
)
2874 rtvec adjust
= XVEC (next_arg_reg
, 0);
2875 int num
= GET_NUM_ELEM (adjust
);
2877 for (i
= 0; i
< num
; i
++)
2879 rtx pattern
= RTVEC_ELT (adjust
, i
);
2880 emit_insn (pattern
);
2884 fsiz
= compute_frame_size (get_frame_size ());
2886 if (flag_stack_usage_info
)
2887 current_function_static_stack_size
= fsiz
;
2890 /* If this function is a varargs function, store any registers that
2891 would normally hold arguments ($5 - $10) on the stack. */
2892 if (((TYPE_ARG_TYPES (fntype
) != 0
2893 && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype
)))
2896 && ((arg_name
[0] == '_'
2897 && strcmp (arg_name
, "__builtin_va_alist") == 0)
2898 || (arg_name
[0] == 'v'
2899 && strcmp (arg_name
, "va_alist") == 0)))))
2901 int offset
= (regno
- GP_ARG_FIRST
+ 1) * UNITS_PER_WORD
;
2902 rtx ptr
= stack_pointer_rtx
;
2904 /* If we are doing svr4-abi, sp has already been decremented by fsiz. */
2905 for (; regno
<= GP_ARG_LAST
; regno
++)
2908 ptr
= gen_rtx_PLUS (Pmode
, stack_pointer_rtx
, GEN_INT (offset
));
2909 emit_move_insn (gen_rtx_MEM (SImode
, ptr
),
2910 gen_rtx_REG (SImode
, regno
));
2912 offset
+= GET_MODE_SIZE (SImode
);
2919 rtx fsiz_rtx
= GEN_INT (fsiz
);
2921 rtx_insn
*insn
= NULL
;
2922 insn
= emit_insn (gen_subsi3 (stack_pointer_rtx
, stack_pointer_rtx
,
2925 RTX_FRAME_RELATED_P (insn
) = 1;
2927 /* Handle SUB_RETURN_ADDR_REGNUM specially at first. */
2928 if (!crtl
->is_leaf
|| interrupt_handler
)
2930 mem_rtx
= gen_rtx_MEM (SImode
,
2931 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
2934 if (interrupt_handler
)
2935 /* Do not optimize in flow analysis. */
2936 MEM_VOLATILE_P (mem_rtx
) = 1;
2938 reg_rtx
= gen_rtx_REG (SImode
, MB_ABI_SUB_RETURN_ADDR_REGNUM
);
2939 insn
= emit_move_insn (mem_rtx
, reg_rtx
);
2940 RTX_FRAME_RELATED_P (insn
) = 1;
2943 /* _save_ registers for prologue. */
2944 save_restore_insns (1);
2946 if (frame_pointer_needed
)
2950 insn
= emit_insn (gen_movsi (hard_frame_pointer_rtx
,
2951 stack_pointer_rtx
));
2954 RTX_FRAME_RELATED_P (insn
) = 1;
2958 if ((flag_pic
== 2 || TLS_NEEDS_GOT
)
2959 && df_regs_ever_live_p (MB_ABI_PIC_ADDR_REGNUM
))
2961 SET_REGNO (pic_offset_table_rtx
, MB_ABI_PIC_ADDR_REGNUM
);
2962 emit_insn (gen_set_got (pic_offset_table_rtx
)); /* setting GOT. */
2965 /* If we are profiling, make sure no instructions are scheduled before
2966 the call to mcount. */
2969 emit_insn (gen_blockage ());
2972 /* Do necessary cleanup after a function to restore stack, frame, and regs. */
2974 #define RA_MASK ((long) 0x80000000) /* 1 << 31 */
2975 #define PIC_OFFSET_TABLE_MASK (1 << (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST))
2978 microblaze_function_epilogue (FILE * file ATTRIBUTE_UNUSED
,
2979 HOST_WIDE_INT size ATTRIBUTE_UNUSED
)
2983 /* Get the function name the same way that toplev.c does before calling
2984 assemble_start_function. This is needed so that the name used here
2985 exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */
2986 fnname
= XSTR (XEXP (DECL_RTL (current_function_decl
), 0), 0);
2988 if (!flag_inhibit_size_directive
)
2990 fputs ("\t.end\t", file
);
2991 if (interrupt_handler
&& !break_handler
)
2992 fputs ("_interrupt_handler", file
);
2993 else if (break_handler
)
2994 fputs ("_break_handler", file
);
2996 assemble_name (file
, fnname
);
3000 /* Reset state info for each function. */
3001 current_frame_info
= zero_frame_info
;
3003 /* Restore the output file if optimizing the GP (optimizing the GP causes
3004 the text to be diverted to a tempfile, so that data decls come before
3005 references to the data). */
3008 /* Expand the epilogue into a bunch of separate insns. */
3011 microblaze_expand_epilogue (void)
3013 HOST_WIDE_INT fsiz
= current_frame_info
.total_size
;
3014 rtx fsiz_rtx
= GEN_INT (fsiz
);
3018 /* In case of interrupt handlers use addki instead of addi for changing the
3019 stack pointer value. */
3021 if (microblaze_can_use_return_insn ())
3023 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode
,
3025 MB_ABI_SUB_RETURN_ADDR_REGNUM
)));
3031 /* Restore SUB_RETURN_ADDR_REGNUM at first. This is to prevent the
3032 sequence of load-followed by a use (in rtsd) in every prologue. Saves
3033 a load-use stall cycle :) This is also important to handle alloca.
3034 (See comments for if (frame_pointer_needed) below. */
3036 if (!crtl
->is_leaf
|| interrupt_handler
)
3039 gen_rtx_MEM (SImode
,
3040 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
, const0_rtx
));
3041 if (interrupt_handler
)
3042 /* Do not optimize in flow analysis. */
3043 MEM_VOLATILE_P (mem_rtx
) = 1;
3044 reg_rtx
= gen_rtx_REG (SImode
, MB_ABI_SUB_RETURN_ADDR_REGNUM
);
3045 emit_move_insn (reg_rtx
, mem_rtx
);
3048 /* It is important that this is done after we restore the return address
3049 register (above). When alloca is used, we want to restore the
3050 sub-routine return address only from the current stack top and not
3051 from the frame pointer (which we restore below). (frame_pointer + 0)
3052 might have been over-written since alloca allocates memory on the
3054 if (frame_pointer_needed
)
3055 emit_insn (gen_movsi (stack_pointer_rtx
, hard_frame_pointer_rtx
));
3057 /* _restore_ registers for epilogue. */
3058 save_restore_insns (0);
3059 emit_insn (gen_blockage ());
3060 emit_insn (gen_addsi3 (stack_pointer_rtx
, stack_pointer_rtx
, fsiz_rtx
));
3063 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode
, GP_REG_FIRST
+
3064 MB_ABI_SUB_RETURN_ADDR_REGNUM
)));
3068 /* Return nonzero if this function is known to have a null epilogue.
3069 This allows the optimizer to omit jumps to jumps if no stack
3073 microblaze_can_use_return_insn (void)
3075 if (!reload_completed
)
3078 if (df_regs_ever_live_p (MB_ABI_SUB_RETURN_ADDR_REGNUM
) || profile_flag
)
3081 if (current_frame_info
.initialized
)
3082 return current_frame_info
.total_size
== 0;
3084 return compute_frame_size (get_frame_size ()) == 0;
3087 /* Implement TARGET_SECONDARY_RELOAD. */
3090 microblaze_secondary_reload (bool in_p ATTRIBUTE_UNUSED
, rtx x ATTRIBUTE_UNUSED
,
3091 reg_class_t rclass
, machine_mode mode ATTRIBUTE_UNUSED
,
3092 secondary_reload_info
*sri ATTRIBUTE_UNUSED
)
3094 if (rclass
== ST_REGS
)
3101 microblaze_globalize_label (FILE * stream
, const char *name
)
3103 fputs ("\t.globl\t", stream
);
3104 if (microblaze_is_interrupt_variant ())
3106 if (interrupt_handler
&& strcmp (name
, INTERRUPT_HANDLER_NAME
))
3107 fputs (INTERRUPT_HANDLER_NAME
, stream
);
3108 else if (break_handler
&& strcmp (name
, BREAK_HANDLER_NAME
))
3109 fputs (BREAK_HANDLER_NAME
, stream
);
3110 else if (fast_interrupt
&& strcmp (name
, FAST_INTERRUPT_NAME
))
3111 fputs (FAST_INTERRUPT_NAME
, stream
);
3112 fputs ("\n\t.globl\t", stream
);
3114 assemble_name (stream
, name
);
3115 fputs ("\n", stream
);
3118 /* Returns true if decl should be placed into a "small data" section. */
3120 microblaze_elf_in_small_data_p (const_tree decl
)
3124 if (!TARGET_XLGPOPT
)
3127 /* We want to merge strings, so we never consider them small data. */
3128 if (TREE_CODE (decl
) == STRING_CST
)
3131 /* Functions are never in the small data area. */
3132 if (TREE_CODE (decl
) == FUNCTION_DECL
)
3135 if (TREE_CODE (decl
) == VAR_DECL
&& DECL_SECTION_NAME (decl
))
3137 const char *section
= DECL_SECTION_NAME (decl
);
3138 if (strcmp (section
, ".sdata") == 0
3139 || strcmp (section
, ".sdata2") == 0
3140 || strcmp (section
, ".sbss") == 0
3141 || strcmp (section
, ".sbss2") == 0)
3145 size
= int_size_in_bytes (TREE_TYPE (decl
));
3147 return (size
> 0 && size
<= microblaze_section_threshold
);
3152 microblaze_select_section (tree decl
, int reloc
, unsigned HOST_WIDE_INT align
)
3154 switch (categorize_decl_for_section (decl
, reloc
))
3156 case SECCAT_RODATA_MERGE_STR
:
3157 case SECCAT_RODATA_MERGE_STR_INIT
:
3158 /* MB binutils have various issues with mergeable string sections and
3159 relaxation/relocation. Currently, turning mergeable sections
3160 into regular readonly sections. */
3162 return readonly_data_section
;
3164 return default_elf_select_section (decl
, reloc
, align
);
3169 Encode info about sections into the RTL based on a symbol's declaration.
3170 The default definition of this hook, default_encode_section_info in
3171 `varasm.c', sets a number of commonly-useful bits in SYMBOL_REF_FLAGS. */
3174 microblaze_encode_section_info (tree decl
, rtx rtl
, int first
)
3176 default_encode_section_info (decl
, rtl
, first
);
3180 expand_pic_symbol_ref (machine_mode mode ATTRIBUTE_UNUSED
, rtx op
)
3183 result
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, op
), UNSPEC_GOTOFF
);
3184 result
= gen_rtx_CONST (Pmode
, result
);
3185 result
= gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
, result
);
3186 result
= gen_const_mem (Pmode
, result
);
3191 microblaze_asm_output_mi_thunk (FILE *file
, tree thunk_fndecl ATTRIBUTE_UNUSED
,
3192 HOST_WIDE_INT delta
, HOST_WIDE_INT vcall_offset
,
3195 rtx this_rtx
, funexp
;
3198 reload_completed
= 1;
3199 epilogue_completed
= 1;
3201 /* Mark the end of the (empty) prologue. */
3202 emit_note (NOTE_INSN_PROLOGUE_END
);
3204 /* Find the "this" pointer. If the function returns a structure,
3205 the structure return pointer is in MB_ABI_FIRST_ARG_REGNUM. */
3206 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function
)), function
))
3207 this_rtx
= gen_rtx_REG (Pmode
, (MB_ABI_FIRST_ARG_REGNUM
+ 1));
3209 this_rtx
= gen_rtx_REG (Pmode
, MB_ABI_FIRST_ARG_REGNUM
);
3211 /* Apply the constant offset, if required. */
3213 emit_insn (gen_addsi3 (this_rtx
, this_rtx
, GEN_INT (delta
)));
3215 /* Apply the offset from the vtable, if required. */
3218 rtx vcall_offset_rtx
= GEN_INT (vcall_offset
);
3219 rtx temp1
= gen_rtx_REG (Pmode
, MB_ABI_TEMP1_REGNUM
);
3221 emit_move_insn (temp1
, gen_rtx_MEM (Pmode
, this_rtx
));
3223 rtx loc
= gen_rtx_PLUS (Pmode
, temp1
, vcall_offset_rtx
);
3224 emit_move_insn (temp1
, gen_rtx_MEM (Pmode
, loc
));
3226 emit_insn (gen_addsi3 (this_rtx
, this_rtx
, temp1
));
3229 /* Generate a tail call to the target function. */
3230 if (!TREE_USED (function
))
3232 assemble_external (function
);
3233 TREE_USED (function
) = 1;
3236 funexp
= XEXP (DECL_RTL (function
), 0);
3237 rtx temp2
= gen_rtx_REG (Pmode
, MB_ABI_TEMP2_REGNUM
);
3240 emit_move_insn (temp2
, expand_pic_symbol_ref (Pmode
, funexp
));
3242 emit_move_insn (temp2
, funexp
);
3244 emit_insn (gen_indirect_jump (temp2
));
3246 /* Run just enough of rest_of_compilation. This sequence was
3247 "borrowed" from rs6000.c. */
3248 insn
= get_insns ();
3249 shorten_branches (insn
);
3250 final_start_function (insn
, file
, 1);
3251 final (insn
, file
, 1);
3252 final_end_function ();
3254 reload_completed
= 0;
3255 epilogue_completed
= 0;
3259 microblaze_expand_move (machine_mode mode
, rtx operands
[])
3266 if (!register_operand (op0
, SImode
)
3267 && !register_operand (op1
, SImode
)
3268 && (GET_CODE (op1
) != CONST_INT
|| INTVAL (op1
) != 0))
3270 rtx temp
= force_reg (SImode
, op1
);
3271 emit_move_insn (op0
, temp
);
3274 /* If operands[1] is a constant address invalid for pic, then we need to
3275 handle it just like LEGITIMIZE_ADDRESS does. */
3276 if (GET_CODE (op1
) == SYMBOL_REF
|| GET_CODE (op1
) == LABEL_REF
)
3279 if (microblaze_tls_symbol_p(op1
))
3281 result
= microblaze_legitimize_tls_address (op1
, NULL_RTX
);
3282 emit_move_insn (op0
, result
);
3287 if (reload_in_progress
)
3288 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
3289 result
= expand_pic_symbol_ref (mode
, op1
);
3290 emit_move_insn (op0
, result
);
3294 /* Handle Case of (const (plus symbol const_int)). */
3295 if (GET_CODE (op1
) == CONST
&& GET_CODE (XEXP (op1
,0)) == PLUS
)
3299 p0
= XEXP (XEXP (op1
, 0), 0);
3300 p1
= XEXP (XEXP (op1
, 0), 1);
3302 if ((GET_CODE (p1
) == CONST_INT
)
3303 && ((GET_CODE (p0
) == UNSPEC
)
3304 || ((GET_CODE (p0
) == SYMBOL_REF
|| GET_CODE (p0
) == LABEL_REF
)
3305 && (flag_pic
== 2 || microblaze_tls_symbol_p (p0
)
3306 || !SMALL_INT (p1
)))))
3308 rtx temp
= force_reg (SImode
, p0
);
3311 if (flag_pic
&& reload_in_progress
)
3312 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
3313 emit_move_insn (op0
, gen_rtx_PLUS (SImode
, temp
, temp2
));
3320 /* Expand shift operations. */
3322 microblaze_expand_shift (rtx operands
[])
3324 gcc_assert ((GET_CODE (operands
[2]) == CONST_INT
)
3325 || (GET_CODE (operands
[2]) == REG
)
3326 || (GET_CODE (operands
[2]) == SUBREG
));
3328 /* Shift by one -- generate pattern. */
3329 if ((GET_CODE (operands
[2]) == CONST_INT
) && (INTVAL (operands
[2]) == 1))
3332 /* Have barrel shifter and shift > 1: use it. */
3333 if (TARGET_BARREL_SHIFT
)
3336 gcc_assert ((GET_CODE (operands
[0]) == REG
)
3337 || (GET_CODE (operands
[0]) == SUBREG
)
3338 || (GET_CODE (operands
[1]) == REG
)
3339 || (GET_CODE (operands
[1]) == SUBREG
));
3341 /* Shift by zero -- copy regs if necessary. */
3342 if ((GET_CODE (operands
[2]) == CONST_INT
) && (INTVAL (operands
[2]) == 0))
3344 if (REGNO (operands
[0]) != REGNO (operands
[1]))
3345 emit_insn (gen_movsi (operands
[0], operands
[1]));
3352 /* Return an RTX indicating where the return address to the
3353 calling function can be found. */
3355 microblaze_return_addr (int count
, rtx frame ATTRIBUTE_UNUSED
)
3360 return gen_rtx_PLUS (Pmode
,
3361 get_hard_reg_initial_val (Pmode
,
3362 MB_ABI_SUB_RETURN_ADDR_REGNUM
),
3366 /* Queue an .ident string in the queue of top-level asm statements.
3367 If the string size is below the threshold, put it into .sdata2.
3368 If the front-end is done, we must be being called from toplev.c.
3369 In that case, do nothing. */
3371 microblaze_asm_output_ident (const char *string
)
3373 const char *section_asm_op
;
3377 if (symtab
->state
!= PARSING
)
3380 size
= strlen (string
) + 1;
3381 if (size
<= microblaze_section_threshold
)
3382 section_asm_op
= SDATA2_SECTION_ASM_OP
;
3384 section_asm_op
= READONLY_DATA_SECTION_ASM_OP
;
3386 buf
= ACONCAT ((section_asm_op
, "\n\t.ascii \"", string
, "\\0\"\n", NULL
));
3387 symtab
->finalize_toplevel_asm (build_string (strlen (buf
), buf
));
3391 microblaze_elf_asm_init_sections (void)
3394 = get_unnamed_section (SECTION_WRITE
, output_section_asm_op
,
3395 SDATA2_SECTION_ASM_OP
);
3398 /* Generate assembler code for constant parts of a trampoline. */
3401 microblaze_asm_trampoline_template (FILE *f
)
3403 fprintf (f
, "\tmfs r18, rpc\n");
3404 fprintf (f
, "\tlwi r3, r18, 16\n");
3405 fprintf (f
, "\tlwi r18, r18, 20\n");
3406 fprintf (f
, "\tbra r18\n");
3407 /* fprintf (f, "\t.word\t0x00000000\t\t# <function address>\n"); */
3408 /* fprintf (f, "\t.word\t0x00000000\t\t# <static chain value>\n"); */
3411 /* Implement TARGET_TRAMPOLINE_INIT. */
3414 microblaze_trampoline_init (rtx m_tramp
, tree fndecl
, rtx chain_value
)
3416 rtx fnaddr
= XEXP (DECL_RTL (fndecl
), 0);
3419 emit_block_move (m_tramp
, assemble_trampoline_template (),
3420 GEN_INT (6*UNITS_PER_WORD
), BLOCK_OP_NORMAL
);
3422 mem
= adjust_address (m_tramp
, SImode
, 16);
3423 emit_move_insn (mem
, chain_value
);
3424 mem
= adjust_address (m_tramp
, SImode
, 20);
3425 emit_move_insn (mem
, fnaddr
);
3428 /* Generate conditional branch -- first, generate test condition,
3429 second, generate correct branch instruction. */
3432 microblaze_expand_conditional_branch (machine_mode mode
, rtx operands
[])
3434 enum rtx_code code
= GET_CODE (operands
[0]);
3435 rtx cmp_op0
= operands
[1];
3436 rtx cmp_op1
= operands
[2];
3437 rtx label1
= operands
[3];
3438 rtx comp_reg
= gen_reg_rtx (SImode
);
3441 gcc_assert ((GET_CODE (cmp_op0
) == REG
) || (GET_CODE (cmp_op0
) == SUBREG
));
3443 /* If comparing against zero, just test source reg. */
3444 if (cmp_op1
== const0_rtx
)
3447 condition
= gen_rtx_fmt_ee (signed_condition (code
), SImode
, comp_reg
, const0_rtx
);
3448 emit_jump_insn (gen_condjump (condition
, label1
));
3451 else if (code
== EQ
|| code
== NE
)
3453 /* Use xor for equal/not-equal comparison. */
3454 emit_insn (gen_xorsi3 (comp_reg
, cmp_op0
, cmp_op1
));
3455 condition
= gen_rtx_fmt_ee (signed_condition (code
), SImode
, comp_reg
, const0_rtx
);
3456 emit_jump_insn (gen_condjump (condition
, label1
));
3460 /* Generate compare and branch in single instruction. */
3461 cmp_op1
= force_reg (mode
, cmp_op1
);
3462 condition
= gen_rtx_fmt_ee (code
, mode
, cmp_op0
, cmp_op1
);
3463 emit_jump_insn (gen_branch_compare(condition
, cmp_op0
, cmp_op1
, label1
));
3469 microblaze_expand_conditional_branch_sf (rtx operands
[])
3472 rtx cmp_op0
= XEXP (operands
[0], 0);
3473 rtx cmp_op1
= XEXP (operands
[0], 1);
3474 rtx comp_reg
= gen_reg_rtx (SImode
);
3476 emit_insn (gen_cstoresf4 (comp_reg
, operands
[0], cmp_op0
, cmp_op1
));
3477 condition
= gen_rtx_NE (SImode
, comp_reg
, const0_rtx
);
3478 emit_jump_insn (gen_condjump (condition
, operands
[3]));
3481 /* Implement TARGET_FRAME_POINTER_REQUIRED. */
3484 microblaze_frame_pointer_required (void)
3486 /* If the function contains dynamic stack allocations, we need to
3487 use the frame pointer to access the static parts of the frame. */
3488 if (cfun
->calls_alloca
)
3494 microblaze_expand_divide (rtx operands
[])
3496 /* Table lookup software divides. Works for all (nr/dr) where (0 <= nr,dr <= 15). */
3498 rtx regt1
= gen_reg_rtx (SImode
);
3499 rtx reg18
= gen_rtx_REG (SImode
, R_TMP
);
3500 rtx regqi
= gen_reg_rtx (QImode
);
3501 rtx_code_label
*div_label
= gen_label_rtx ();
3502 rtx_code_label
*div_end_label
= gen_label_rtx ();
3503 rtx div_table_rtx
= gen_rtx_SYMBOL_REF (QImode
,"_divsi3_table");
3506 rtx_insn
*jump
, *cjump
, *insn
;
3508 insn
= emit_insn (gen_iorsi3 (regt1
, operands
[1], operands
[2]));
3509 cjump
= emit_jump_insn_after (gen_cbranchsi4 (
3510 gen_rtx_GTU (SImode
, regt1
, GEN_INT (15)),
3511 regt1
, GEN_INT (15), div_label
), insn
);
3512 LABEL_NUSES (div_label
) = 1;
3513 JUMP_LABEL (cjump
) = div_label
;
3514 emit_insn (gen_rtx_CLOBBER (SImode
, reg18
));
3516 emit_insn (gen_ashlsi3_bshift (regt1
, operands
[1], GEN_INT(4)));
3517 emit_insn (gen_addsi3 (regt1
, regt1
, operands
[2]));
3518 mem_rtx
= gen_rtx_MEM (QImode
,
3519 gen_rtx_PLUS (Pmode
, regt1
, div_table_rtx
));
3521 insn
= emit_insn (gen_movqi (regqi
, mem_rtx
));
3522 insn
= emit_insn (gen_movsi (operands
[0], gen_rtx_SUBREG (SImode
, regqi
, 0)));
3523 jump
= emit_jump_insn_after (gen_jump (div_end_label
), insn
);
3524 JUMP_LABEL (jump
) = div_end_label
;
3525 LABEL_NUSES (div_end_label
) = 1;
3528 emit_label (div_label
);
3529 ret
= emit_library_call_value (gen_rtx_SYMBOL_REF (Pmode
, "__divsi3"),
3530 operands
[0], LCT_NORMAL
,
3531 GET_MODE (operands
[0]), 2, operands
[1],
3532 GET_MODE (operands
[1]), operands
[2],
3533 GET_MODE (operands
[2]));
3534 if (ret
!= operands
[0])
3535 emit_move_insn (operands
[0], ret
);
3537 emit_label (div_end_label
);
3538 emit_insn (gen_blockage ());
3541 /* Implement TARGET_FUNCTION_VALUE. */
3543 microblaze_function_value (const_tree valtype
,
3544 const_tree func ATTRIBUTE_UNUSED
,
3545 bool outgoing ATTRIBUTE_UNUSED
)
3547 return LIBCALL_VALUE (TYPE_MODE (valtype
));
3550 /* Implement TARGET_SCHED_ADJUST_COST. */
3552 microblaze_adjust_cost (rtx_insn
*insn ATTRIBUTE_UNUSED
, rtx link
,
3553 rtx_insn
*dep ATTRIBUTE_UNUSED
, int cost
)
3555 if (REG_NOTE_KIND (link
) == REG_DEP_OUTPUT
)
3557 if (REG_NOTE_KIND (link
) != 0)
3562 /* Implement TARGET_LEGITIMATE_CONSTANT_P.
3564 At present, GAS doesn't understand li.[sd], so don't allow it
3565 to be generated at present. */
3567 microblaze_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED
, rtx x
)
3570 if (microblaze_cannot_force_const_mem(mode
, x
))
3573 if (GET_CODE (x
) == CONST_DOUBLE
)
3575 return microblaze_const_double_ok (x
, GET_MODE (x
));
3578 /* Handle Case of (const (plus unspec const_int)). */
3579 if (GET_CODE (x
) == CONST
&& GET_CODE (XEXP (x
,0)) == PLUS
)
3583 p0
= XEXP (XEXP (x
, 0), 0);
3584 p1
= XEXP (XEXP (x
, 0), 1);
3586 if (GET_CODE(p1
) == CONST_INT
)
3588 /* Const offset from UNSPEC is not supported. */
3589 if ((GET_CODE (p0
) == UNSPEC
))
3592 if ((GET_CODE (p0
) == SYMBOL_REF
|| GET_CODE (p0
) == LABEL_REF
)
3593 && (microblaze_tls_symbol_p (p0
) || !SMALL_INT (p1
)))
3602 #undef TARGET_ENCODE_SECTION_INFO
3603 #define TARGET_ENCODE_SECTION_INFO microblaze_encode_section_info
3605 #undef TARGET_ASM_GLOBALIZE_LABEL
3606 #define TARGET_ASM_GLOBALIZE_LABEL microblaze_globalize_label
3608 #undef TARGET_ASM_FUNCTION_PROLOGUE
3609 #define TARGET_ASM_FUNCTION_PROLOGUE microblaze_function_prologue
3611 #undef TARGET_ASM_FUNCTION_EPILOGUE
3612 #define TARGET_ASM_FUNCTION_EPILOGUE microblaze_function_epilogue
3614 #undef TARGET_RTX_COSTS
3615 #define TARGET_RTX_COSTS microblaze_rtx_costs
3617 #undef TARGET_CANNOT_FORCE_CONST_MEM
3618 #define TARGET_CANNOT_FORCE_CONST_MEM microblaze_cannot_force_const_mem
3620 #undef TARGET_ADDRESS_COST
3621 #define TARGET_ADDRESS_COST microblaze_address_cost
3623 #undef TARGET_ATTRIBUTE_TABLE
3624 #define TARGET_ATTRIBUTE_TABLE microblaze_attribute_table
3626 #undef TARGET_IN_SMALL_DATA_P
3627 #define TARGET_IN_SMALL_DATA_P microblaze_elf_in_small_data_p
3629 #undef TARGET_ASM_SELECT_SECTION
3630 #define TARGET_ASM_SELECT_SECTION microblaze_select_section
3632 #undef TARGET_HAVE_SRODATA_SECTION
3633 #define TARGET_HAVE_SRODATA_SECTION true
3635 #undef TARGET_ASM_FUNCTION_END_PROLOGUE
3636 #define TARGET_ASM_FUNCTION_END_PROLOGUE \
3637 microblaze_function_end_prologue
3639 #undef TARGET_ARG_PARTIAL_BYTES
3640 #define TARGET_ARG_PARTIAL_BYTES function_arg_partial_bytes
3642 #undef TARGET_FUNCTION_ARG
3643 #define TARGET_FUNCTION_ARG microblaze_function_arg
3645 #undef TARGET_FUNCTION_ARG_ADVANCE
3646 #define TARGET_FUNCTION_ARG_ADVANCE microblaze_function_arg_advance
3648 #undef TARGET_CAN_ELIMINATE
3649 #define TARGET_CAN_ELIMINATE microblaze_can_eliminate
3651 #undef TARGET_LEGITIMIZE_ADDRESS
3652 #define TARGET_LEGITIMIZE_ADDRESS microblaze_legitimize_address
3654 #undef TARGET_LEGITIMATE_ADDRESS_P
3655 #define TARGET_LEGITIMATE_ADDRESS_P microblaze_legitimate_address_p
3657 #undef TARGET_FRAME_POINTER_REQUIRED
3658 #define TARGET_FRAME_POINTER_REQUIRED microblaze_frame_pointer_required
3660 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
3661 #define TARGET_ASM_TRAMPOLINE_TEMPLATE microblaze_asm_trampoline_template
3663 #undef TARGET_TRAMPOLINE_INIT
3664 #define TARGET_TRAMPOLINE_INIT microblaze_trampoline_init
3666 #undef TARGET_PROMOTE_FUNCTION_MODE
3667 #define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
3669 #undef TARGET_FUNCTION_VALUE
3670 #define TARGET_FUNCTION_VALUE microblaze_function_value
3672 #undef TARGET_SECONDARY_RELOAD
3673 #define TARGET_SECONDARY_RELOAD microblaze_secondary_reload
3675 #undef TARGET_ASM_OUTPUT_MI_THUNK
3676 #define TARGET_ASM_OUTPUT_MI_THUNK microblaze_asm_output_mi_thunk
3678 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
3679 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true
3681 #undef TARGET_SCHED_ADJUST_COST
3682 #define TARGET_SCHED_ADJUST_COST microblaze_adjust_cost
3684 #undef TARGET_ASM_INIT_SECTIONS
3685 #define TARGET_ASM_INIT_SECTIONS microblaze_elf_asm_init_sections
3687 #undef TARGET_OPTION_OVERRIDE
3688 #define TARGET_OPTION_OVERRIDE microblaze_option_override
3690 #undef TARGET_LEGITIMATE_CONSTANT_P
3691 #define TARGET_LEGITIMATE_CONSTANT_P microblaze_legitimate_constant_p
3693 struct gcc_target targetm
= TARGET_INITIALIZER
;
3695 #include "gt-microblaze.h"