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"
31 #include "insn-config.h"
32 #include "conditions.h"
33 #include "insn-flags.h"
34 #include "insn-attr.h"
38 #include "stor-layout.h"
56 #include "cfgcleanup.h"
57 #include "insn-codes.h"
59 #include "diagnostic-core.h"
64 /* This file should be included last. */
65 #include "target-def.h"
67 #define MICROBLAZE_VERSION_COMPARE(VA,VB) strcasecmp (VA, VB)
69 /* Classifies an address.
76 A natural register or a register + const_int offset address.
77 The register satisfies microblaze_valid_base_register_p and the
78 offset is a const_arith_operand.
82 A natural register offset by the index contained in an index register. The base
83 register satisfies microblaze_valid_base_register_p and the index register
84 satisfies microblaze_valid_index_register_p
88 A signed 16/32-bit constant address.
92 A constant symbolic address or a (register + symbol). */
94 enum microblaze_address_type
106 /* Classifies symbols
111 enum microblaze_symbol_type
117 /* TLS Address Type. */
126 /* Classification of a MicroBlaze address. */
127 struct microblaze_address_info
129 enum microblaze_address_type type
;
130 rtx regA
; /* Contains valid values on ADDRESS_REG, ADDRESS_REG_INDEX,
132 rtx regB
; /* Contains valid values on ADDRESS_REG_INDEX. */
133 rtx offset
; /* Contains valid values on ADDRESS_CONST_INT and ADDRESS_REG. */
134 rtx symbol
; /* Contains valid values on ADDRESS_SYMBOLIC. */
135 enum microblaze_symbol_type symbol_type
;
136 enum tls_reloc tls_type
;
139 /* Structure to be filled in by compute_frame_size with register
140 save masks, and offsets for the current function. */
142 struct GTY(()) microblaze_frame_info
{
143 long total_size
; /* # bytes that the entire frame takes up. */
144 long var_size
; /* # bytes that variables take up. */
145 long args_size
; /* # bytes that outgoing arguments take up. */
146 int link_debug_size
; /* # bytes for the link reg and back pointer. */
147 int gp_reg_size
; /* # bytes needed to store gp regs. */
148 long gp_offset
; /* offset from new sp to store gp registers. */
149 long mask
; /* mask of saved gp registers. */
150 int initialized
; /* != 0 if frame size already calculated. */
151 int num_gp
; /* number of gp registers saved. */
152 long insns_len
; /* length of insns. */
153 int alloc_stack
; /* Flag to indicate if the current function
154 must not create stack space. (As an optimization). */
157 /* Global variables for machine-dependent things. */
159 /* Toggle which pipleline interface to use. */
160 static GTY(()) int microblaze_sched_use_dfa
= 0;
162 /* Threshold for data being put into the small data/bss area, instead
163 of the normal data area (references to the small data/bss area take
164 1 instruction, and use the global pointer, references to the normal
165 data area takes 2 instructions). */
166 int microblaze_section_threshold
= -1;
168 /* Prevent scheduling potentially exception causing instructions in
169 delay slots. -mcpu=v3.00.a or v4.00.a turns this on. */
170 int microblaze_no_unsafe_delay
;
172 /* Set to one if the targeted core has the CLZ insn. */
173 int microblaze_has_clz
= 0;
175 /* Which CPU pipeline do we use. We haven't really standardized on a CPU
176 version having only a particular type of pipeline. There can still be
177 options on the CPU to scale pipeline features up or down. :(
178 Bad Presentation (??), so we let the MD file rely on the value of
179 this variable instead Making PIPE_5 the default. It should be backward
180 optimal with PIPE_3 MicroBlazes. */
181 enum pipeline_type microblaze_pipe
= MICROBLAZE_PIPE_5
;
183 /* High and low marks for floating point values which we will accept
184 as legitimate constants for TARGET_LEGITIMATE_CONSTANT_P. These are
185 initialized in override_options. */
186 REAL_VALUE_TYPE dfhigh
, dflow
, sfhigh
, sflow
;
188 /* Array giving truth value on whether or not a given hard register
189 can support a given mode. */
190 char microblaze_hard_regno_mode_ok
[(int)MAX_MACHINE_MODE
]
191 [FIRST_PSEUDO_REGISTER
];
193 /* Current frame information calculated by compute_frame_size. */
194 struct microblaze_frame_info current_frame_info
;
196 /* Zero structure to initialize current_frame_info. */
197 struct microblaze_frame_info zero_frame_info
;
199 /* List of all MICROBLAZE punctuation characters used by print_operand. */
200 char microblaze_print_operand_punct
[256];
202 /* Map GCC register number to debugger register number. */
203 int microblaze_dbx_regno
[FIRST_PSEUDO_REGISTER
];
205 /* Map hard register number to register class. */
206 enum reg_class microblaze_regno_to_class
[] =
208 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
209 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
210 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
211 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
212 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
213 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
214 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
215 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
216 ST_REGS
, GR_REGS
, GR_REGS
, GR_REGS
219 /* MicroBlaze specific machine attributes.
220 interrupt_handler - Interrupt handler attribute to add interrupt prologue
221 and epilogue and use appropriate interrupt return.
222 save_volatiles - Similar to interrupt handler, but use normal return. */
223 int interrupt_handler
;
228 const struct attribute_spec microblaze_attribute_table
[] = {
229 /* name min_len, max_len, decl_req, type_req, fn_type, req_handler,
230 affects_type_identity */
231 {"interrupt_handler", 0, 0, true, false, false, NULL
,
233 {"break_handler", 0, 0, true, false, false, NULL
,
235 {"fast_interrupt", 0, 0, true, false, false, NULL
,
237 {"save_volatiles" , 0, 0, true, false, false, NULL
,
239 { NULL
, 0, 0, false, false, false, NULL
,
243 static int microblaze_interrupt_function_p (tree
);
245 static void microblaze_elf_asm_constructor (rtx
, int) ATTRIBUTE_UNUSED
;
246 static void microblaze_elf_asm_destructor (rtx
, int) ATTRIBUTE_UNUSED
;
248 section
*sdata2_section
;
251 #undef TARGET_HAVE_TLS
252 #define TARGET_HAVE_TLS true
255 /* Return truth value if a CONST_DOUBLE is ok to be a legitimate constant. */
257 microblaze_const_double_ok (rtx op
, machine_mode mode
)
261 if (GET_CODE (op
) != CONST_DOUBLE
)
264 if (GET_MODE (op
) == VOIDmode
)
267 if (mode
!= SFmode
&& mode
!= DFmode
)
270 if (op
== CONST0_RTX (mode
))
273 REAL_VALUE_FROM_CONST_DOUBLE (d
, op
);
275 if (REAL_VALUE_ISNAN (d
))
278 if (REAL_VALUE_NEGATIVE (d
))
279 d
= real_value_negate (&d
);
283 if (REAL_VALUES_LESS (d
, dfhigh
) && REAL_VALUES_LESS (dflow
, d
))
288 if (REAL_VALUES_LESS (d
, sfhigh
) && REAL_VALUES_LESS (sflow
, d
))
295 /* Return truth value if a memory operand fits in a single instruction
296 (ie, register + small offset) or (register + register). */
299 simple_memory_operand (rtx op
, machine_mode mode ATTRIBUTE_UNUSED
)
301 rtx addr
, plus0
, plus1
;
303 /* Eliminate non-memory operations. */
304 if (GET_CODE (op
) != MEM
)
307 /* dword operations really put out 2 instructions, so eliminate them. */
308 /* ??? This isn't strictly correct. It is OK to accept multiword modes
309 here, since the length attributes are being set correctly, but only
310 if the address is offsettable. */
311 if (GET_MODE_SIZE (GET_MODE (op
)) > UNITS_PER_WORD
)
315 /* Decode the address now. */
317 switch (GET_CODE (addr
))
324 plus0
= XEXP (addr
, 0);
325 plus1
= XEXP (addr
, 1);
327 if (GET_CODE (plus0
) != REG
)
330 if (GET_CODE (plus0
) == REG
&& GET_CODE (plus1
) == CONST_INT
331 && SMALL_INT (plus1
))
335 else if (GET_CODE (plus1
) == REG
&& GET_CODE (plus0
) == CONST_INT
)
339 else if (GET_CODE (plus0
) == REG
&& GET_CODE (plus1
) == REG
)
356 /* Return nonzero for a memory address that can be used to load or store
360 double_memory_operand (rtx op
, machine_mode mode
)
364 if (GET_CODE (op
) != MEM
|| !memory_operand (op
, mode
))
366 /* During reload, we accept a pseudo register if it has an
367 appropriate memory address. If we don't do this, we will
368 wind up reloading into a register, and then reloading that
369 register from memory, when we could just reload directly from
371 if (reload_in_progress
372 && GET_CODE (op
) == REG
373 && REGNO (op
) >= FIRST_PSEUDO_REGISTER
374 && reg_renumber
[REGNO (op
)] < 0
375 && reg_equiv_mem (REGNO (op
)) != 0
376 && double_memory_operand (reg_equiv_mem (REGNO (op
)), mode
))
381 /* Make sure that 4 added to the address is a valid memory address.
382 This essentially just checks for overflow in an added constant. */
386 if (CONSTANT_ADDRESS_P (addr
))
389 return memory_address_p ((GET_MODE_CLASS (mode
) == MODE_INT
391 plus_constant (Pmode
, addr
, 4));
394 /* Implement REG_OK_FOR_BASE_P -and- REG_OK_FOR_INDEX_P. */
396 microblaze_regno_ok_for_base_p (int regno
, int strict
)
398 if (regno
>= FIRST_PSEUDO_REGISTER
)
402 regno
= reg_renumber
[regno
];
405 /* These fake registers will be eliminated to either the stack or
406 hard frame pointer, both of which are usually valid base registers.
407 Reload deals with the cases where the eliminated form isn't valid. */
408 if (regno
== ARG_POINTER_REGNUM
|| regno
== FRAME_POINTER_REGNUM
)
411 return GP_REG_P (regno
);
414 /* Return true if X is a valid base register for the given mode.
415 Allow only hard registers if STRICT. */
418 microblaze_valid_base_register_p (rtx x
,
419 machine_mode mode ATTRIBUTE_UNUSED
,
422 if (!strict
&& GET_CODE (x
) == SUBREG
)
425 return (GET_CODE (x
) == REG
426 && microblaze_regno_ok_for_base_p (REGNO (x
), strict
));
429 /* Build the SYMBOL_REF for __tls_get_addr. */
431 static GTY(()) rtx tls_get_addr_libfunc
;
434 get_tls_get_addr (void)
436 if (!tls_get_addr_libfunc
)
437 tls_get_addr_libfunc
= init_one_libfunc ("__tls_get_addr");
438 return tls_get_addr_libfunc
;
441 /* Return TRUE if X is a thread-local symbol. */
443 microblaze_tls_symbol_p (rtx x
)
445 if (!TARGET_HAVE_TLS
)
448 if (GET_CODE (x
) != SYMBOL_REF
)
451 return SYMBOL_REF_TLS_MODEL (x
) != 0;
454 /* Return TRUE if X contains any TLS symbol references. */
457 microblaze_tls_referenced_p (rtx x
)
459 if (!TARGET_HAVE_TLS
)
461 subrtx_iterator::array_type array
;
462 FOR_EACH_SUBRTX (iter
, array
, x
, ALL
)
465 if (GET_CODE (x
) == SYMBOL_REF
&& SYMBOL_REF_TLS_MODEL (x
) != 0)
467 /* Don't recurse into UNSPEC_TLS looking for TLS symbols; these are
468 TLS offsets, not real symbol references. */
469 if (GET_CODE (x
) == UNSPEC
&& XINT (x
, 1) == UNSPEC_TLS
)
470 iter
.skip_subrtxes ();
476 microblaze_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED
, rtx x
)
478 return microblaze_tls_referenced_p(x
);
481 /* Return TRUE if X references a SYMBOL_REF. */
483 symbol_mentioned_p (rtx x
)
488 if (GET_CODE (x
) == SYMBOL_REF
)
491 /* UNSPEC entries for a symbol include the SYMBOL_REF, but they
492 are constant offsets, not symbols. */
493 if (GET_CODE (x
) == UNSPEC
)
496 fmt
= GET_RTX_FORMAT (GET_CODE (x
));
498 for (i
= GET_RTX_LENGTH (GET_CODE (x
)) - 1; i
>= 0; i
--)
504 for (j
= XVECLEN (x
, i
) - 1; j
>= 0; j
--)
505 if (symbol_mentioned_p (XVECEXP (x
, i
, j
)))
508 else if (fmt
[i
] == 'e' && symbol_mentioned_p (XEXP (x
, i
)))
515 /* Return TRUE if X references a LABEL_REF. */
517 label_mentioned_p (rtx x
)
522 if (GET_CODE (x
) == LABEL_REF
)
525 /* UNSPEC entries for a symbol include a LABEL_REF for the referencing
526 instruction, but they are constant offsets, not symbols. */
527 if (GET_CODE (x
) == UNSPEC
)
530 fmt
= GET_RTX_FORMAT (GET_CODE (x
));
531 for (i
= GET_RTX_LENGTH (GET_CODE (x
)) - 1; i
>= 0; i
--)
537 for (j
= XVECLEN (x
, i
) - 1; j
>= 0; j
--)
538 if (label_mentioned_p (XVECEXP (x
, i
, j
)))
541 else if (fmt
[i
] == 'e' && label_mentioned_p (XEXP (x
, i
)))
549 tls_mentioned_p (rtx x
)
551 switch (GET_CODE (x
))
554 return tls_mentioned_p (XEXP (x
, 0));
557 if (XINT (x
, 1) == UNSPEC_TLS
)
566 load_tls_operand (rtx x
, rtx reg
)
571 reg
= gen_reg_rtx (Pmode
);
573 tmp
= gen_rtx_CONST (Pmode
, x
);
575 emit_insn (gen_rtx_SET (reg
,
576 gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
, tmp
)));
582 microblaze_call_tls_get_addr (rtx x
, rtx reg
, rtx
*valuep
, int reloc
)
587 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
591 tls_entry
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (2, x
, GEN_INT (reloc
)),
594 reg
= load_tls_operand (tls_entry
, reg
);
596 *valuep
= emit_library_call_value (get_tls_get_addr (), NULL_RTX
,
597 LCT_PURE
, /* LCT_CONST? */
598 Pmode
, 1, reg
, Pmode
);
600 insns
= get_insns ();
607 microblaze_legitimize_tls_address(rtx x
, rtx reg
)
609 rtx dest
, ret
, eqv
, addend
;
611 enum tls_model model
;
612 model
= SYMBOL_REF_TLS_MODEL (x
);
616 case TLS_MODEL_LOCAL_DYNAMIC
:
617 case TLS_MODEL_GLOBAL_DYNAMIC
:
618 case TLS_MODEL_INITIAL_EXEC
:
619 insns
= microblaze_call_tls_get_addr (x
, reg
, &ret
, TLS_GD
);
620 dest
= gen_reg_rtx (Pmode
);
621 emit_libcall_block (insns
, dest
, ret
, x
);
624 case TLS_MODEL_LOCAL_EXEC
:
625 insns
= microblaze_call_tls_get_addr (x
, reg
, &ret
, TLS_LDM
);
627 /* Attach a unique REG_EQUIV, to allow the RTL optimizers to
628 share the LDM result with other LD model accesses. */
629 eqv
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, const1_rtx
), UNSPEC_TLS
);
630 dest
= gen_reg_rtx (Pmode
);
631 emit_libcall_block (insns
, dest
, ret
, eqv
);
633 /* Load the addend. */
634 addend
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (2, x
, GEN_INT (TLS_DTPREL
)),
636 addend
= force_reg (SImode
, gen_rtx_CONST (SImode
, addend
));
637 dest
= gen_rtx_PLUS (Pmode
, dest
, addend
);
647 microblaze_classify_unspec (struct microblaze_address_info
*info
, rtx x
)
649 info
->symbol_type
= SYMBOL_TYPE_GENERAL
;
650 info
->symbol
= XVECEXP (x
, 0, 0);
652 if (XINT (x
, 1) == UNSPEC_GOTOFF
)
654 info
->regA
= gen_rtx_REG (SImode
, PIC_OFFSET_TABLE_REGNUM
);
655 info
->type
= ADDRESS_GOTOFF
;
657 else if (XINT (x
, 1) == UNSPEC_PLT
)
659 info
->type
= ADDRESS_PLT
;
661 else if (XINT (x
, 1) == UNSPEC_TLS
)
663 info
->type
= ADDRESS_TLS
;
664 info
->tls_type
= tls_reloc (INTVAL (XVECEXP (x
, 0, 1)));
674 /* Return true if X is a valid index register for the given mode.
675 Allow only hard registers if STRICT. */
678 microblaze_valid_index_register_p (rtx x
,
679 machine_mode mode ATTRIBUTE_UNUSED
,
682 if (!strict
&& GET_CODE (x
) == SUBREG
)
685 return (GET_CODE (x
) == REG
686 /* A base register is good enough to be an index register on MicroBlaze. */
687 && microblaze_regno_ok_for_base_p (REGNO (x
), strict
));
690 /* Get the base register for accessing a value from the memory or
691 Symbol ref. Used for MicroBlaze Small Data Area Pointer Optimization. */
698 if (!flag_pic
|| microblaze_tls_symbol_p(x
))
699 base_reg
= MB_ABI_BASE_REGNUM
;
701 base_reg
= MB_ABI_PIC_ADDR_REGNUM
;
704 && GET_CODE (x
) == SYMBOL_REF
705 && SYMBOL_REF_SMALL_P (x
) && (decl
= SYMBOL_REF_DECL (x
)) != NULL
)
707 if (TREE_READONLY (decl
))
708 base_reg
= MB_ABI_GPRO_REGNUM
;
710 base_reg
= MB_ABI_GPRW_REGNUM
;
716 /* Return true if X is a valid address for machine mode MODE. If it is,
717 fill in INFO appropriately. STRICT is true if we should only accept
720 type regA regB offset symbol
722 ADDRESS_INVALID NULL NULL NULL NULL
724 ADDRESS_REG %0 NULL const_0 / NULL
726 ADDRESS_REG_INDEX %0 %1 NULL NULL
728 ADDRESS_SYMBOLIC r0 / NULL NULL symbol
731 ADDRESS_CONST_INT r0 NULL const NULL
733 For modes spanning multiple registers (DFmode in 32-bit GPRs,
734 DImode, TImode), indexed addressing cannot be used because
735 adjacent memory cells are accessed by adding word-sized offsets
736 during assembly output. */
739 microblaze_classify_address (struct microblaze_address_info
*info
, rtx x
,
740 machine_mode mode
, int strict
)
745 info
->type
= ADDRESS_INVALID
;
750 info
->symbol_type
= SYMBOL_TYPE_INVALID
;
752 switch (GET_CODE (x
))
757 info
->type
= ADDRESS_REG
;
759 info
->offset
= const0_rtx
;
760 return microblaze_valid_base_register_p (info
->regA
, mode
, strict
);
764 xplus0
= XEXP (x
, 0);
765 xplus1
= XEXP (x
, 1);
767 if (microblaze_valid_base_register_p (xplus0
, mode
, strict
))
769 info
->type
= ADDRESS_REG
;
772 if (GET_CODE (xplus1
) == CONST_INT
)
774 info
->offset
= xplus1
;
777 else if (GET_CODE (xplus1
) == UNSPEC
)
779 /* Need offsettable address. */
780 if (GET_MODE_SIZE (mode
) > UNITS_PER_WORD
)
783 return microblaze_classify_unspec (info
, xplus1
);
785 else if ((GET_CODE (xplus1
) == SYMBOL_REF
||
786 GET_CODE (xplus1
) == LABEL_REF
))
788 if (flag_pic
== 2 || microblaze_tls_symbol_p(xplus1
))
790 info
->type
= ADDRESS_SYMBOLIC
;
791 info
->symbol
= xplus1
;
792 info
->symbol_type
= SYMBOL_TYPE_GENERAL
;
795 else if (GET_CODE (xplus1
) == CONST
)
797 rtx xconst0
= XEXP(xplus1
, 0);
800 if (GET_CODE (xconst0
) == UNSPEC
)
802 /* Need offsettable address. */
803 if (GET_MODE_SIZE (mode
) > UNITS_PER_WORD
)
805 return microblaze_classify_unspec(info
, xconst0
);
808 /* for (plus x const_int) just look at x. */
809 if (GET_CODE (xconst0
) == PLUS
810 && GET_CODE (XEXP (xconst0
, 1)) == CONST_INT
811 && SMALL_INT (XEXP (xconst0
, 1)))
813 /* This is ok as info->symbol is set to xplus1 the full
814 const-expression below. */
815 xconst0
= XEXP (xconst0
, 0);
818 if (GET_CODE (xconst0
) == SYMBOL_REF
819 || GET_CODE (xconst0
) == LABEL_REF
)
821 if (flag_pic
== 2 || microblaze_tls_symbol_p(xconst0
))
824 info
->type
= ADDRESS_SYMBOLIC
;
825 info
->symbol
= xplus1
;
826 info
->symbol_type
= SYMBOL_TYPE_GENERAL
;
830 /* Not base + symbol || base + UNSPEC. */
834 else if (GET_CODE (xplus1
) == REG
835 && microblaze_valid_index_register_p (xplus1
, mode
,
837 && (GET_MODE_SIZE (mode
) <= UNITS_PER_WORD
))
839 /* Restrict larger than word-width modes from using an index register. */
840 info
->type
= ADDRESS_REG_INDEX
;
849 info
->regA
= gen_raw_REG (mode
, 0);
850 info
->type
= ADDRESS_CONST_INT
;
858 info
->type
= ADDRESS_SYMBOLIC
;
859 info
->symbol_type
= SYMBOL_TYPE_GENERAL
;
861 info
->regA
= gen_raw_REG (mode
, get_base_reg (x
));
863 if (GET_CODE (x
) == CONST
)
865 if (GET_CODE (XEXP (x
, 0)) == UNSPEC
)
867 info
->regA
= gen_raw_REG (mode
,
868 get_base_reg (XVECEXP (XEXP (x
,0), 0, 0)));
869 return microblaze_classify_unspec (info
, XEXP (x
, 0));
871 return !(flag_pic
&& pic_address_needs_scratch (x
));
876 else if (microblaze_tls_symbol_p(x
))
884 if (reload_in_progress
)
885 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
886 return microblaze_classify_unspec (info
, x
);
896 /* This function is used to implement GO_IF_LEGITIMATE_ADDRESS. It
897 returns a nonzero value if X is a legitimate address for a memory
898 operand of the indicated MODE. STRICT is nonzero if this function
899 is called during reload. */
902 microblaze_legitimate_address_p (machine_mode mode
, rtx x
, bool strict
)
904 struct microblaze_address_info addr
;
906 return microblaze_classify_address (&addr
, x
, mode
, strict
);
910 microblaze_valid_pic_const (rtx x
)
912 switch (GET_CODE (x
))
924 microblaze_legitimate_pic_operand (rtx x
)
926 if (flag_pic
== 2 && (symbol_mentioned_p(x
) || label_mentioned_p(x
)))
929 if (microblaze_tls_referenced_p(x
))
935 /* Try machine-dependent ways of modifying an illegitimate address
936 to be legitimate. If we find one, return the new, valid address.
937 This is used from only one place: `memory_address' in explow.c.
939 OLDX is the address as it was before break_out_memory_refs was
940 called. In some cases it is useful to look at this to decide what
943 It is always safe for this function to do nothing. It exists to
944 recognize opportunities to optimize the output.
946 For the MicroBlaze, transform:
948 memory(X + <large int>)
952 Y = <large int> & ~0x7fff;
954 memory (Z + (<large int> & 0x7fff));
956 This is for CSE to find several similar references, and only use one Z.
958 When PIC, convert addresses of the form memory (symbol+large int) to
959 memory (reg+large int). */
962 microblaze_legitimize_address (rtx x
, rtx oldx ATTRIBUTE_UNUSED
,
963 machine_mode mode ATTRIBUTE_UNUSED
)
965 register rtx xinsn
= x
, result
;
967 if (GET_CODE (xinsn
) == CONST
968 && flag_pic
&& pic_address_needs_scratch (xinsn
))
970 rtx ptr_reg
= gen_reg_rtx (Pmode
);
971 rtx constant
= XEXP (XEXP (xinsn
, 0), 1);
973 emit_move_insn (ptr_reg
, XEXP (XEXP (xinsn
, 0), 0));
975 result
= gen_rtx_PLUS (Pmode
, ptr_reg
, constant
);
976 if (SMALL_INT (constant
))
978 /* Otherwise we fall through so the code below will fix the
983 if (GET_CODE (xinsn
) == PLUS
)
985 register rtx xplus0
= XEXP (xinsn
, 0);
986 register rtx xplus1
= XEXP (xinsn
, 1);
987 register enum rtx_code code0
= GET_CODE (xplus0
);
988 register enum rtx_code code1
= GET_CODE (xplus1
);
990 if (code0
!= REG
&& code1
== REG
)
992 xplus0
= XEXP (xinsn
, 1);
993 xplus1
= XEXP (xinsn
, 0);
994 code0
= GET_CODE (xplus0
);
995 code1
= GET_CODE (xplus1
);
998 if (code0
== REG
&& REG_OK_FOR_BASE_P (xplus0
)
999 && code1
== CONST_INT
&& !SMALL_INT (xplus1
))
1001 rtx int_reg
= gen_reg_rtx (Pmode
);
1002 rtx ptr_reg
= gen_reg_rtx (Pmode
);
1004 emit_move_insn (int_reg
, GEN_INT (INTVAL (xplus1
) & ~0x7fff));
1006 emit_insn (gen_rtx_SET (ptr_reg
,
1007 gen_rtx_PLUS (Pmode
, xplus0
, int_reg
)));
1009 result
= gen_rtx_PLUS (Pmode
, ptr_reg
,
1010 GEN_INT (INTVAL (xplus1
) & 0x7fff));
1014 if (code0
== REG
&& REG_OK_FOR_BASE_P (xplus0
))
1016 if (reload_in_progress
)
1017 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
1020 xplus1
= XEXP (xplus1
, 0);
1021 code1
= GET_CODE (xplus1
);
1023 if (code1
== SYMBOL_REF
)
1025 if (microblaze_tls_symbol_p(xplus1
))
1028 reg
= gen_reg_rtx (Pmode
);
1030 tls_ref
= microblaze_legitimize_tls_address (xplus1
,
1032 emit_move_insn (reg
, tls_ref
);
1034 result
= gen_rtx_PLUS (Pmode
, xplus0
, reg
);
1038 else if (flag_pic
== 2)
1041 reg
= gen_reg_rtx (Pmode
);
1043 pic_ref
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, xplus1
),
1045 pic_ref
= gen_rtx_CONST (Pmode
, pic_ref
);
1046 pic_ref
= gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
, pic_ref
);
1047 pic_ref
= gen_const_mem (Pmode
, pic_ref
);
1048 emit_move_insn (reg
, pic_ref
);
1049 result
= gen_rtx_PLUS (Pmode
, xplus0
, reg
);
1056 if (GET_CODE (xinsn
) == SYMBOL_REF
)
1059 if (microblaze_tls_symbol_p(xinsn
))
1061 reg
= microblaze_legitimize_tls_address (xinsn
, NULL_RTX
);
1067 if (reload_in_progress
)
1068 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
1070 pic_ref
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, xinsn
), UNSPEC_GOTOFF
);
1071 pic_ref
= gen_rtx_CONST (Pmode
, pic_ref
);
1072 pic_ref
= gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
, pic_ref
);
1073 pic_ref
= gen_const_mem (Pmode
, pic_ref
);
1084 #define MAX_MOVE_REGS 8
1085 #define MAX_MOVE_BYTES (MAX_MOVE_REGS * UNITS_PER_WORD)
1087 /* Emit straight-line code to move LENGTH bytes from SRC to DEST.
1088 Assume that the areas do not overlap. */
1091 microblaze_block_move_straight (rtx dest
, rtx src
, HOST_WIDE_INT length
)
1093 HOST_WIDE_INT offset
, delta
;
1094 unsigned HOST_WIDE_INT bits
;
1099 bits
= BITS_PER_WORD
;
1100 mode
= mode_for_size (bits
, MODE_INT
, 0);
1101 delta
= bits
/ BITS_PER_UNIT
;
1103 /* Allocate a buffer for the temporary registers. */
1104 regs
= XALLOCAVEC (rtx
, length
/ delta
);
1106 /* Load as many BITS-sized chunks as possible. Use a normal load if
1107 the source has enough alignment, otherwise use left/right pairs. */
1108 for (offset
= 0, i
= 0; offset
+ delta
<= length
; offset
+= delta
, i
++)
1110 regs
[i
] = gen_reg_rtx (mode
);
1111 emit_move_insn (regs
[i
], adjust_address (src
, mode
, offset
));
1114 /* Copy the chunks to the destination. */
1115 for (offset
= 0, i
= 0; offset
+ delta
<= length
; offset
+= delta
, i
++)
1116 emit_move_insn (adjust_address (dest
, mode
, offset
), regs
[i
]);
1118 /* Mop up any left-over bytes. */
1119 if (offset
< length
)
1121 src
= adjust_address (src
, BLKmode
, offset
);
1122 dest
= adjust_address (dest
, BLKmode
, offset
);
1123 move_by_pieces (dest
, src
, length
- offset
,
1124 MIN (MEM_ALIGN (src
), MEM_ALIGN (dest
)), 0);
1128 /* Helper function for doing a loop-based block operation on memory
1129 reference MEM. Each iteration of the loop will operate on LENGTH
1132 Create a new base register for use within the loop and point it to
1133 the start of MEM. Create a new memory reference that uses this
1134 register. Store them in *LOOP_REG and *LOOP_MEM respectively. */
1137 microblaze_adjust_block_mem (rtx mem
, HOST_WIDE_INT length
,
1138 rtx
* loop_reg
, rtx
* loop_mem
)
1140 *loop_reg
= copy_addr_to_reg (XEXP (mem
, 0));
1142 /* Although the new mem does not refer to a known location,
1143 it does keep up to LENGTH bytes of alignment. */
1144 *loop_mem
= change_address (mem
, BLKmode
, *loop_reg
);
1145 set_mem_align (*loop_mem
,
1146 MIN ((HOST_WIDE_INT
) MEM_ALIGN (mem
),
1147 length
* BITS_PER_UNIT
));
1151 /* Move LENGTH bytes from SRC to DEST using a loop that moves MAX_MOVE_BYTES
1152 per iteration. LENGTH must be at least MAX_MOVE_BYTES. Assume that the
1153 memory regions do not overlap. */
1156 microblaze_block_move_loop (rtx dest
, rtx src
, HOST_WIDE_INT length
)
1158 rtx_code_label
*label
;
1159 rtx src_reg
, dest_reg
, final_src
;
1160 HOST_WIDE_INT leftover
;
1162 leftover
= length
% MAX_MOVE_BYTES
;
1165 /* Create registers and memory references for use within the loop. */
1166 microblaze_adjust_block_mem (src
, MAX_MOVE_BYTES
, &src_reg
, &src
);
1167 microblaze_adjust_block_mem (dest
, MAX_MOVE_BYTES
, &dest_reg
, &dest
);
1169 /* Calculate the value that SRC_REG should have after the last iteration
1171 final_src
= expand_simple_binop (Pmode
, PLUS
, src_reg
, GEN_INT (length
),
1174 /* Emit the start of the loop. */
1175 label
= gen_label_rtx ();
1178 /* Emit the loop body. */
1179 microblaze_block_move_straight (dest
, src
, MAX_MOVE_BYTES
);
1181 /* Move on to the next block. */
1182 emit_move_insn (src_reg
, plus_constant (Pmode
, src_reg
, MAX_MOVE_BYTES
));
1183 emit_move_insn (dest_reg
, plus_constant (Pmode
, dest_reg
, MAX_MOVE_BYTES
));
1185 /* Emit the test & branch. */
1186 emit_insn (gen_cbranchsi4 (gen_rtx_NE (SImode
, src_reg
, final_src
),
1187 src_reg
, final_src
, label
));
1189 /* Mop up any left-over bytes. */
1191 microblaze_block_move_straight (dest
, src
, leftover
);
1194 /* Expand a movmemsi instruction. */
1197 microblaze_expand_block_move (rtx dest
, rtx src
, rtx length
, rtx align_rtx
)
1200 if (GET_CODE (length
) == CONST_INT
)
1202 HOST_WIDE_INT bytes
= INTVAL (length
);
1203 int align
= INTVAL (align_rtx
);
1205 if (align
> UNITS_PER_WORD
)
1207 align
= UNITS_PER_WORD
; /* We can't do any better. */
1209 else if (align
< UNITS_PER_WORD
)
1211 if (INTVAL (length
) <= MAX_MOVE_BYTES
)
1213 move_by_pieces (dest
, src
, bytes
, align
, 0);
1220 if (INTVAL (length
) <= 2 * MAX_MOVE_BYTES
)
1222 microblaze_block_move_straight (dest
, src
, INTVAL (length
));
1227 microblaze_block_move_loop (dest
, src
, INTVAL (length
));
1235 microblaze_rtx_costs (rtx x
, machine_mode mode
, int outer_code ATTRIBUTE_UNUSED
,
1236 int opno ATTRIBUTE_UNUSED
, int *total
,
1237 bool speed ATTRIBUTE_UNUSED
)
1239 int code
= GET_CODE (x
);
1245 int num_words
= (GET_MODE_SIZE (mode
) > UNITS_PER_WORD
) ? 2 : 1;
1246 if (simple_memory_operand (x
, mode
))
1247 *total
= COSTS_N_INSNS (2 * num_words
);
1249 *total
= COSTS_N_INSNS (2 * (2 * num_words
));
1257 *total
= COSTS_N_INSNS (2);
1260 *total
= COSTS_N_INSNS (1);
1269 *total
= COSTS_N_INSNS (2);
1272 *total
= COSTS_N_INSNS (1);
1280 if (TARGET_BARREL_SHIFT
)
1282 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v5.00.a")
1284 *total
= COSTS_N_INSNS (1);
1286 *total
= COSTS_N_INSNS (2);
1288 else if (!TARGET_SOFT_MUL
)
1289 *total
= COSTS_N_INSNS (1);
1290 else if (GET_CODE (XEXP (x
, 1)) == CONST_INT
)
1292 /* Add 1 to make shift slightly more expensive than add. */
1293 *total
= COSTS_N_INSNS (INTVAL (XEXP (x
, 1))) + 1;
1294 /* Reduce shift costs for special circumstances. */
1295 if (optimize_size
&& INTVAL (XEXP (x
, 1)) > 5)
1297 if (!optimize_size
&& INTVAL (XEXP (x
, 1)) > 17)
1301 /* Double the worst cost of shifts when there is no barrel shifter and
1302 the shift amount is in a reg. */
1303 *total
= COSTS_N_INSNS (32 * 4);
1309 if (mode
== SFmode
|| mode
== DFmode
)
1311 if (TARGET_HARD_FLOAT
)
1312 *total
= COSTS_N_INSNS (6);
1315 else if (mode
== DImode
)
1317 *total
= COSTS_N_INSNS (4);
1322 *total
= COSTS_N_INSNS (1);
1331 *total
= COSTS_N_INSNS (4);
1339 if (TARGET_HARD_FLOAT
)
1340 *total
= COSTS_N_INSNS (6);
1342 else if (!TARGET_SOFT_MUL
)
1344 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v5.00.a")
1346 *total
= COSTS_N_INSNS (1);
1348 *total
= COSTS_N_INSNS (3);
1351 *total
= COSTS_N_INSNS (10);
1359 if (TARGET_HARD_FLOAT
)
1360 *total
= COSTS_N_INSNS (23);
1366 *total
= COSTS_N_INSNS (1);
1371 *total
= COSTS_N_INSNS (1);
1379 /* Return the number of instructions needed to load or store a value
1380 of mode MODE at X. Return 0 if X isn't valid for MODE. */
1383 microblaze_address_insns (rtx x
, machine_mode mode
)
1385 struct microblaze_address_info addr
;
1387 if (microblaze_classify_address (&addr
, x
, mode
, false))
1392 if (SMALL_INT (addr
.offset
))
1396 case ADDRESS_CONST_INT
:
1401 case ADDRESS_REG_INDEX
:
1403 case ADDRESS_SYMBOLIC
:
1404 case ADDRESS_GOTOFF
:
1407 switch (addr
.tls_type
)
1425 /* Provide the costs of an addressing mode that contains ADDR.
1426 If ADDR is not a valid address, its cost is irrelevant. */
1428 microblaze_address_cost (rtx addr
, machine_mode mode ATTRIBUTE_UNUSED
,
1429 addr_space_t as ATTRIBUTE_UNUSED
,
1430 bool speed ATTRIBUTE_UNUSED
)
1432 return COSTS_N_INSNS (microblaze_address_insns (addr
, GET_MODE (addr
)));
1435 /* Return nonzero if X is an address which needs a temporary register when
1436 reloaded while generating PIC code. */
1439 pic_address_needs_scratch (rtx x
)
1441 if (GET_CODE (x
) == CONST
&& GET_CODE (XEXP (x
,0)) == PLUS
)
1445 p0
= XEXP (XEXP (x
, 0), 0);
1446 p1
= XEXP (XEXP (x
, 0), 1);
1448 if ((GET_CODE (p0
) == SYMBOL_REF
|| GET_CODE (p0
) == LABEL_REF
)
1449 && (GET_CODE (p1
) == CONST_INT
)
1450 && (flag_pic
== 2 || microblaze_tls_symbol_p (p0
) || !SMALL_INT (p1
)))
1456 /* Argument support functions. */
1457 /* Initialize CUMULATIVE_ARGS for a function. */
1460 init_cumulative_args (CUMULATIVE_ARGS
* cum
, tree fntype
,
1461 rtx libname ATTRIBUTE_UNUSED
)
1463 static CUMULATIVE_ARGS zero_cum
;
1464 tree param
, next_param
;
1468 /* Determine if this function has variable arguments. This is
1469 indicated by the last argument being 'void_type_mode' if there
1470 are no variable arguments. The standard MicroBlaze calling sequence
1471 passes all arguments in the general purpose registers in this case. */
1473 for (param
= fntype
? TYPE_ARG_TYPES (fntype
) : 0;
1474 param
!= 0; param
= next_param
)
1476 next_param
= TREE_CHAIN (param
);
1477 if (next_param
== 0 && TREE_VALUE (param
) != void_type_node
)
1478 cum
->gp_reg_found
= 1;
1482 /* Advance the argument to the next argument position. */
1485 microblaze_function_arg_advance (cumulative_args_t cum_v
,
1487 const_tree type
, bool named ATTRIBUTE_UNUSED
)
1489 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
1498 gcc_assert (GET_MODE_CLASS (mode
) == MODE_COMPLEX_INT
1499 || GET_MODE_CLASS (mode
) == MODE_COMPLEX_FLOAT
);
1501 cum
->gp_reg_found
= 1;
1502 cum
->arg_words
+= ((GET_MODE_SIZE (mode
) + UNITS_PER_WORD
- 1)
1507 cum
->gp_reg_found
= 1;
1508 cum
->arg_words
+= ((int_size_in_bytes (type
) + UNITS_PER_WORD
- 1)
1514 if (!cum
->gp_reg_found
&& cum
->arg_number
<= 2)
1515 cum
->fp_code
+= 1 << ((cum
->arg_number
- 1) * 2);
1519 cum
->arg_words
+= 2;
1520 if (!cum
->gp_reg_found
&& cum
->arg_number
<= 2)
1521 cum
->fp_code
+= 2 << ((cum
->arg_number
- 1) * 2);
1525 cum
->gp_reg_found
= 1;
1526 cum
->arg_words
+= 2;
1533 cum
->gp_reg_found
= 1;
1539 /* Return an RTL expression containing the register for the given mode,
1540 or 0 if the argument is to be passed on the stack. */
1543 microblaze_function_arg (cumulative_args_t cum_v
, machine_mode mode
,
1544 const_tree type ATTRIBUTE_UNUSED
,
1545 bool named ATTRIBUTE_UNUSED
)
1547 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
1551 int *arg_words
= &cum
->arg_words
;
1553 cum
->last_arg_fp
= 0;
1564 regbase
= GP_ARG_FIRST
;
1567 gcc_assert (GET_MODE_CLASS (mode
) == MODE_COMPLEX_INT
1568 || GET_MODE_CLASS (mode
) == MODE_COMPLEX_FLOAT
);
1569 /* Drops through. */
1571 regbase
= GP_ARG_FIRST
;
1575 if (*arg_words
>= MAX_ARGS_IN_REGISTERS
)
1579 gcc_assert (regbase
!= -1);
1581 ret
= gen_rtx_REG (mode
, regbase
+ *arg_words
);
1584 if (mode
== VOIDmode
)
1586 if (cum
->num_adjusts
> 0)
1587 ret
= gen_rtx_PARALLEL ((machine_mode
) cum
->fp_code
,
1588 gen_rtvec_v (cum
->num_adjusts
, cum
->adjust
));
1594 /* Return number of bytes of argument to put in registers. */
1596 function_arg_partial_bytes (cumulative_args_t cum_v
, machine_mode mode
,
1597 tree type
, bool named ATTRIBUTE_UNUSED
)
1599 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
1601 if ((mode
== BLKmode
1602 || GET_MODE_CLASS (mode
) != MODE_COMPLEX_INT
1603 || GET_MODE_CLASS (mode
) != MODE_COMPLEX_FLOAT
)
1604 && cum
->arg_words
< MAX_ARGS_IN_REGISTERS
)
1607 if (mode
== BLKmode
)
1608 words
= ((int_size_in_bytes (type
) + UNITS_PER_WORD
- 1)
1611 words
= (GET_MODE_SIZE (mode
) + UNITS_PER_WORD
- 1) / UNITS_PER_WORD
;
1613 if (words
+ cum
->arg_words
<= MAX_ARGS_IN_REGISTERS
)
1614 return 0; /* structure fits in registers */
1616 return (MAX_ARGS_IN_REGISTERS
- cum
->arg_words
) * UNITS_PER_WORD
;
1619 else if (mode
== DImode
&& cum
->arg_words
== MAX_ARGS_IN_REGISTERS
- 1)
1620 return UNITS_PER_WORD
;
1625 /* Convert a version number of the form "vX.YY.Z" to an integer encoding
1626 for easier range comparison. */
1628 microblaze_version_to_int (const char *version
)
1631 const char *tmpl
= "vXX.YY.Z";
1640 { /* Looking for major */
1647 if (!(*p
>= '0' && *p
<= '9'))
1649 iver
+= (int) (*p
- '0');
1654 { /* Looking for minor */
1655 if (!(*p
>= '0' && *p
<= '9'))
1657 iver
+= (int) (*p
- '0');
1661 { /* Looking for compat */
1662 if (!(*p
>= 'a' && *p
<= 'z'))
1665 iver
+= (int) (*p
- 'a');
1685 microblaze_option_override (void)
1687 register int i
, start
;
1689 register machine_mode mode
;
1692 microblaze_section_threshold
= (global_options_set
.x_g_switch_value
1694 : MICROBLAZE_DEFAULT_GVALUE
);
1698 /* Make sure it's 2, we only support one kind of PIC. */
1700 if (!TARGET_SUPPORTS_PIC
)
1702 error ("-fPIC/-fpic not supported for this target");
1703 /* Clear it to avoid further errors. */
1708 /* Check the MicroBlaze CPU version for any special action to be done. */
1709 if (microblaze_select_cpu
== NULL
)
1710 microblaze_select_cpu
= MICROBLAZE_DEFAULT_CPU
;
1711 ver
= microblaze_version_to_int (microblaze_select_cpu
);
1714 error ("%qs is an invalid argument to -mcpu=", microblaze_select_cpu
);
1717 ver
= MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v3.00.a");
1720 /* No hardware exceptions in earlier versions. So no worries. */
1722 microblaze_select_flags
&= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY
);
1724 microblaze_no_unsafe_delay
= 0;
1725 microblaze_pipe
= MICROBLAZE_PIPE_3
;
1728 || (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v4.00.b")
1732 microblaze_select_flags
|= (MICROBLAZE_MASK_NO_UNSAFE_DELAY
);
1734 microblaze_no_unsafe_delay
= 1;
1735 microblaze_pipe
= MICROBLAZE_PIPE_3
;
1739 /* We agree to use 5 pipe-stage model even on area optimized 3
1740 pipe-stage variants. */
1742 microblaze_select_flags
&= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY
);
1744 microblaze_no_unsafe_delay
= 0;
1745 microblaze_pipe
= MICROBLAZE_PIPE_5
;
1746 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v5.00.a") == 0
1747 || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
,
1749 || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
,
1752 /* Pattern compares are to be turned on by default only when
1753 compiling for MB v5.00.'z'. */
1754 target_flags
|= MASK_PATTERN_COMPARE
;
1758 ver
= MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v6.00.a");
1761 if (TARGET_MULTIPLY_HIGH
)
1763 "-mxl-multiply-high can be used only with -mcpu=v6.00.a or greater");
1766 ver
= MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v8.10.a");
1767 microblaze_has_clz
= 1;
1770 /* MicroBlaze prior to 8.10.a didn't have clz. */
1771 microblaze_has_clz
= 0;
1774 /* TARGET_REORDER defaults to 2 if -mxl-reorder not specified. */
1775 ver
= MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v8.30.a");
1778 if (TARGET_REORDER
== 1)
1779 warning (0, "-mxl-reorder can be used only with -mcpu=v8.30.a or greater");
1782 else if ((ver
== 0) && !TARGET_PATTERN_COMPARE
)
1784 if (TARGET_REORDER
== 1)
1785 warning (0, "-mxl-reorder requires -mxl-pattern-compare for -mcpu=v8.30.a");
1789 if (TARGET_MULTIPLY_HIGH
&& TARGET_SOFT_MUL
)
1790 error ("-mxl-multiply-high requires -mno-xl-soft-mul");
1792 /* Always use DFA scheduler. */
1793 microblaze_sched_use_dfa
= 1;
1796 microblaze_abicalls
= MICROBLAZE_ABICALLS_NO
;
1799 /* Initialize the high, low values for legit floating point constants. */
1800 real_maxval (&dfhigh
, 0, DFmode
);
1801 real_maxval (&dflow
, 1, DFmode
);
1802 real_maxval (&sfhigh
, 0, SFmode
);
1803 real_maxval (&sflow
, 1, SFmode
);
1805 microblaze_print_operand_punct
['?'] = 1;
1806 microblaze_print_operand_punct
['#'] = 1;
1807 microblaze_print_operand_punct
['&'] = 1;
1808 microblaze_print_operand_punct
['!'] = 1;
1809 microblaze_print_operand_punct
['*'] = 1;
1810 microblaze_print_operand_punct
['@'] = 1;
1811 microblaze_print_operand_punct
['.'] = 1;
1812 microblaze_print_operand_punct
['('] = 1;
1813 microblaze_print_operand_punct
[')'] = 1;
1814 microblaze_print_operand_punct
['['] = 1;
1815 microblaze_print_operand_punct
[']'] = 1;
1816 microblaze_print_operand_punct
['<'] = 1;
1817 microblaze_print_operand_punct
['>'] = 1;
1818 microblaze_print_operand_punct
['{'] = 1;
1819 microblaze_print_operand_punct
['}'] = 1;
1820 microblaze_print_operand_punct
['^'] = 1;
1821 microblaze_print_operand_punct
['$'] = 1;
1822 microblaze_print_operand_punct
['+'] = 1;
1824 /* Set up array to map GCC register number to debug register number.
1825 Ignore the special purpose register numbers. */
1827 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
1828 microblaze_dbx_regno
[i
] = -1;
1830 start
= GP_DBX_FIRST
- GP_REG_FIRST
;
1831 for (i
= GP_REG_FIRST
; i
<= GP_REG_LAST
; i
++)
1832 microblaze_dbx_regno
[i
] = i
+ start
;
1834 /* Set up array giving whether a given register can hold a given mode. */
1836 for (mode
= VOIDmode
;
1837 mode
!= MAX_MACHINE_MODE
; mode
= (machine_mode
) ((int) mode
+ 1))
1839 register int size
= GET_MODE_SIZE (mode
);
1841 for (regno
= 0; regno
< FIRST_PSEUDO_REGISTER
; regno
++)
1847 ok
= (ST_REG_P (regno
) || GP_REG_P (regno
));
1849 else if (GP_REG_P (regno
))
1850 ok
= ((regno
& 1) == 0 || size
<= UNITS_PER_WORD
);
1854 microblaze_hard_regno_mode_ok
[(int) mode
][regno
] = ok
;
1859 /* Return true if FUNC is an interrupt function as specified
1860 by the "interrupt_handler" attribute. */
1863 microblaze_interrupt_function_p (tree func
)
1867 if (TREE_CODE (func
) != FUNCTION_DECL
)
1870 a
= lookup_attribute ("interrupt_handler", DECL_ATTRIBUTES (func
));
1871 return a
!= NULL_TREE
;
1875 microblaze_fast_interrupt_function_p (tree func
)
1879 if (TREE_CODE (func
) != FUNCTION_DECL
)
1882 a
= lookup_attribute ("fast_interrupt", DECL_ATTRIBUTES (func
));
1883 return a
!= NULL_TREE
;
1886 microblaze_break_function_p (tree func
)
1891 if (TREE_CODE (func
) != FUNCTION_DECL
)
1894 a
= lookup_attribute ("break_handler", DECL_ATTRIBUTES (func
));
1895 return a
!= NULL_TREE
;
1897 /* Return true if FUNC is an interrupt function which uses
1898 normal return, indicated by the "save_volatiles" attribute. */
1901 microblaze_save_volatiles (tree func
)
1905 if (TREE_CODE (func
) != FUNCTION_DECL
)
1908 a
= lookup_attribute ("save_volatiles", DECL_ATTRIBUTES (func
));
1909 return a
!= NULL_TREE
;
1912 /* Return whether function is tagged with 'interrupt_handler'
1913 or 'fast_interrupt' attribute. Return true if function
1914 should use return from interrupt rather than normal
1917 microblaze_is_interrupt_variant (void)
1919 return (interrupt_handler
|| fast_interrupt
);
1922 microblaze_is_break_handler (void)
1924 return break_handler
;
1927 /* Determine of register must be saved/restored in call. */
1929 microblaze_must_save_register (int regno
)
1931 if (pic_offset_table_rtx
&&
1932 (regno
== MB_ABI_PIC_ADDR_REGNUM
) && df_regs_ever_live_p (regno
))
1935 if (df_regs_ever_live_p (regno
) && !call_used_regs
[regno
])
1938 if (frame_pointer_needed
&& (regno
== HARD_FRAME_POINTER_REGNUM
))
1943 if (regno
== MB_ABI_SUB_RETURN_ADDR_REGNUM
)
1945 if ((microblaze_is_interrupt_variant () || save_volatiles
) &&
1946 (regno
>= 3 && regno
<= 12))
1950 if (microblaze_is_interrupt_variant ())
1952 if (df_regs_ever_live_p (regno
)
1953 || regno
== MB_ABI_MSR_SAVE_REG
1954 || (interrupt_handler
1955 && (regno
== MB_ABI_ASM_TEMP_REGNUM
1956 || regno
== MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM
)))
1962 if (df_regs_ever_live_p (regno
)
1963 || regno
== MB_ABI_ASM_TEMP_REGNUM
1964 || regno
== MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM
)
1971 /* Return the bytes needed to compute the frame pointer from the current
1974 MicroBlaze stack frames look like:
1978 Before call After call
1979 +-----------------------+ +-----------------------+
1981 mem. | local variables, | | local variables, |
1982 | callee saved and | | callee saved and |
1984 +-----------------------+ +-----------------------+
1985 | arguments for called | | arguments for called |
1986 | subroutines | | subroutines |
1987 | (optional) | | (optional) |
1988 +-----------------------+ +-----------------------+
1989 | Link register | | Link register |
1991 +-----------------------+ +-----------------------+
1993 | local variables, |
1994 | callee saved and |
1996 +-----------------------+
1997 | MSR (optional if, |
1998 | interrupt handler) |
1999 +-----------------------+
2001 | alloca allocations |
2003 +-----------------------+
2005 | arguments for called |
2009 +-----------------------+
2012 memory +-----------------------+
2016 static HOST_WIDE_INT
2017 compute_frame_size (HOST_WIDE_INT size
)
2020 HOST_WIDE_INT total_size
; /* # bytes that the entire frame takes up. */
2021 HOST_WIDE_INT var_size
; /* # bytes that local variables take up. */
2022 HOST_WIDE_INT args_size
; /* # bytes that outgoing arguments take up. */
2023 int link_debug_size
; /* # bytes for link register. */
2024 HOST_WIDE_INT gp_reg_size
; /* # bytes needed to store calle-saved gp regs. */
2025 long mask
; /* mask of saved gp registers. */
2028 microblaze_interrupt_function_p (current_function_decl
);
2030 microblaze_break_function_p (current_function_decl
);
2033 microblaze_fast_interrupt_function_p (current_function_decl
);
2034 save_volatiles
= microblaze_save_volatiles (current_function_decl
);
2036 interrupt_handler
= break_handler
;
2041 args_size
= crtl
->outgoing_args_size
;
2043 if ((args_size
== 0) && cfun
->calls_alloca
)
2044 args_size
= NUM_OF_ARGS
* UNITS_PER_WORD
;
2046 total_size
= var_size
+ args_size
;
2049 /* force setting GOT. */
2050 df_set_regs_ever_live (MB_ABI_PIC_ADDR_REGNUM
, true);
2052 /* Calculate space needed for gp registers. */
2053 for (regno
= GP_REG_FIRST
; regno
<= GP_REG_LAST
; regno
++)
2055 if (microblaze_must_save_register (regno
))
2058 if (regno
!= MB_ABI_SUB_RETURN_ADDR_REGNUM
)
2059 /* Don't account for link register. It is accounted specially below. */
2060 gp_reg_size
+= GET_MODE_SIZE (SImode
);
2062 mask
|= (1L << (regno
- GP_REG_FIRST
));
2066 total_size
+= gp_reg_size
;
2068 /* Add 4 bytes for MSR. */
2069 if (microblaze_is_interrupt_variant ())
2072 /* No space to be allocated for link register in leaf functions with no other
2073 stack requirements. */
2074 if (total_size
== 0 && crtl
->is_leaf
)
2075 link_debug_size
= 0;
2077 link_debug_size
= UNITS_PER_WORD
;
2079 total_size
+= link_debug_size
;
2081 /* Save other computed information. */
2082 current_frame_info
.total_size
= total_size
;
2083 current_frame_info
.var_size
= var_size
;
2084 current_frame_info
.args_size
= args_size
;
2085 current_frame_info
.gp_reg_size
= gp_reg_size
;
2086 current_frame_info
.mask
= mask
;
2087 current_frame_info
.initialized
= reload_completed
;
2088 current_frame_info
.num_gp
= gp_reg_size
/ UNITS_PER_WORD
;
2089 current_frame_info
.link_debug_size
= link_debug_size
;
2092 /* Offset from which to callee-save GP regs. */
2093 current_frame_info
.gp_offset
= (total_size
- gp_reg_size
);
2095 current_frame_info
.gp_offset
= 0;
2097 /* Ok, we're done. */
2101 /* Make sure that we're not trying to eliminate to the wrong hard frame
2105 microblaze_can_eliminate (const int from
, const int to
)
2107 return ((from
== RETURN_ADDRESS_POINTER_REGNUM
&& !leaf_function_p())
2108 || (to
== MB_ABI_SUB_RETURN_ADDR_REGNUM
&& leaf_function_p())
2109 || (from
!= RETURN_ADDRESS_POINTER_REGNUM
2110 && (to
== HARD_FRAME_POINTER_REGNUM
2111 || (to
== STACK_POINTER_REGNUM
&& !frame_pointer_needed
))));
2114 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
2115 pointer or argument pointer or the return address pointer. TO is either
2116 the stack pointer or hard frame pointer. */
2119 microblaze_initial_elimination_offset (int from
, int to
)
2121 HOST_WIDE_INT offset
;
2125 case FRAME_POINTER_REGNUM
:
2128 case ARG_POINTER_REGNUM
:
2129 if (to
== STACK_POINTER_REGNUM
|| to
== HARD_FRAME_POINTER_REGNUM
)
2130 offset
= compute_frame_size (get_frame_size ());
2134 case RETURN_ADDRESS_POINTER_REGNUM
:
2138 offset
= current_frame_info
.gp_offset
+
2139 ((UNITS_PER_WORD
- (POINTER_SIZE
/ BITS_PER_UNIT
)));
2147 /* Print operands using format code.
2149 The MicroBlaze specific codes are:
2151 'X' X is CONST_INT, prints 32 bits in hexadecimal format = "0x%08x",
2152 'x' X is CONST_INT, prints 16 bits in hexadecimal format = "0x%04x",
2153 'F' op is CONST_DOUBLE, print 32 bits in hex,
2154 'd' output integer constant in decimal,
2155 'z' if the operand is 0, use $0 instead of normal operand.
2156 'D' print second register of double-word register operand.
2157 'L' print low-order register of double-word register operand.
2158 'M' print high-order register of double-word register operand.
2159 'C' print part of opcode for a branch condition.
2160 'N' print part of opcode for a branch condition, inverted.
2161 'S' X is CODE_LABEL, print with prefix of "LS" (for embedded switch).
2162 'B' print 'z' for EQ, 'n' for NE
2163 'b' print 'n' for EQ, 'z' for NE
2164 'T' print 'f' for EQ, 't' for NE
2165 't' print 't' for EQ, 'f' for NE
2166 'm' Print 1<<operand.
2167 'i' Print 'i' if MEM operand has immediate value
2168 'y' Print 'y' if MEM operand is single register
2169 'o' Print operand address+4
2170 '?' Print 'd' if we use a branch with delay slot instead of normal branch.
2171 'h' Print high word of const_double (int or float) value as hex
2172 'j' Print low word of const_double (int or float) value as hex
2173 's' Print -1 if operand is negative, 0 if positive (sign extend)
2174 '@' Print the name of the temporary register (rMB_ABI_ASM_TEMP_REGNUM).
2175 '#' Print nop if the delay slot of a branch is not filled.
2179 print_operand (FILE * file
, rtx op
, int letter
)
2181 register enum rtx_code code
;
2183 if (PRINT_OPERAND_PUNCT_VALID_P (letter
))
2188 /* Conditionally add a 'd' to indicate filled delay slot. */
2189 if (final_sequence
!= NULL
)
2194 /* Conditionally add a nop in unfilled delay slot. */
2195 if (final_sequence
== NULL
)
2196 fputs ("nop\t\t# Unfilled delay slot\n", file
);
2200 fputs (reg_names
[GP_REG_FIRST
+ MB_ABI_ASM_TEMP_REGNUM
], file
);
2204 output_operand_lossage ("unknown punctuation '%c'", letter
);
2213 output_operand_lossage ("null pointer");
2217 code
= GET_CODE (op
);
2219 if (code
== SIGN_EXTEND
)
2220 op
= XEXP (op
, 0), code
= GET_CODE (op
);
2248 fatal_insn ("PRINT_OPERAND, invalid insn for %%C", op
);
2251 else if (letter
== 'N')
2277 fatal_insn ("PRINT_OPERAND, invalid insn for %%N", op
);
2280 else if (letter
== 'S')
2284 ASM_GENERATE_INTERNAL_LABEL (buffer
, "LS", CODE_LABEL_NUMBER (op
));
2285 assemble_name (file
, buffer
);
2288 /* Print 'i' for memory operands which have immediate values. */
2289 else if (letter
== 'i')
2293 struct microblaze_address_info info
;
2295 if (!microblaze_classify_address
2296 (&info
, XEXP (op
, 0), GET_MODE (op
), 1))
2297 fatal_insn ("insn contains an invalid address !", op
);
2302 case ADDRESS_CONST_INT
:
2303 case ADDRESS_SYMBOLIC
:
2304 case ADDRESS_GOTOFF
:
2308 case ADDRESS_REG_INDEX
:
2310 case ADDRESS_INVALID
:
2312 fatal_insn ("invalid address", op
);
2317 else if (code
== REG
|| code
== SUBREG
)
2319 register int regnum
;
2322 regnum
= REGNO (op
);
2324 regnum
= true_regnum (op
);
2326 if ((letter
== 'M' && !WORDS_BIG_ENDIAN
)
2327 || (letter
== 'L' && WORDS_BIG_ENDIAN
) || letter
== 'D')
2330 fprintf (file
, "%s", reg_names
[regnum
]);
2333 else if (code
== MEM
)
2336 rtx op4
= adjust_address (op
, GET_MODE (op
), 4);
2337 output_address (XEXP (op4
, 0));
2339 else if (letter
== 'y')
2341 rtx mem_reg
= XEXP (op
, 0);
2342 if (GET_CODE (mem_reg
) == REG
)
2344 register int regnum
= REGNO (mem_reg
);
2345 fprintf (file
, "%s", reg_names
[regnum
]);
2349 output_address (XEXP (op
, 0));
2351 else if (letter
== 'h' || letter
== 'j')
2354 if (code
== CONST_DOUBLE
)
2356 if (GET_MODE (op
) == DFmode
)
2358 REAL_VALUE_TYPE value
;
2359 REAL_VALUE_FROM_CONST_DOUBLE (value
, op
);
2360 REAL_VALUE_TO_TARGET_DOUBLE (value
, val
);
2364 val
[0] = CONST_DOUBLE_HIGH (op
);
2365 val
[1] = CONST_DOUBLE_LOW (op
);
2368 else if (code
== CONST_INT
)
2370 val
[0] = (INTVAL (op
) & 0xffffffff00000000LL
) >> 32;
2371 val
[1] = INTVAL (op
) & 0x00000000ffffffffLL
;
2372 if (val
[0] == 0 && val
[1] < 0)
2376 fprintf (file
, "0x%8.8lx", (letter
== 'h') ? val
[0] : val
[1]);
2378 else if (code
== CONST_DOUBLE
)
2382 unsigned long value_long
;
2383 REAL_VALUE_TYPE value
;
2384 REAL_VALUE_FROM_CONST_DOUBLE (value
, op
);
2385 REAL_VALUE_TO_TARGET_SINGLE (value
, value_long
);
2386 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, value_long
);
2391 real_to_decimal (s
, CONST_DOUBLE_REAL_VALUE (op
), sizeof (s
), 0, 1);
2396 else if (code
== UNSPEC
)
2398 print_operand_address (file
, op
);
2401 else if (letter
== 'x' && GET_CODE (op
) == CONST_INT
)
2402 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, 0xffff & INTVAL (op
));
2404 else if (letter
== 'X' && GET_CODE (op
) == CONST_INT
)
2405 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, INTVAL (op
));
2407 else if (letter
== 'd' && GET_CODE (op
) == CONST_INT
)
2408 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, (INTVAL (op
)));
2410 else if (letter
== 'z' && GET_CODE (op
) == CONST_INT
&& INTVAL (op
) == 0)
2411 fputs (reg_names
[GP_REG_FIRST
], file
);
2413 else if (letter
== 's' && GET_CODE (op
) == CONST_INT
)
2414 if (INTVAL (op
) < 0)
2419 else if (letter
== 'd' || letter
== 'x' || letter
== 'X' || letter
== 's')
2420 output_operand_lossage ("letter %c was found & insn was not CONST_INT", letter
);
2422 else if (letter
== 'B')
2423 fputs (code
== EQ
? "z" : "n", file
);
2424 else if (letter
== 'b')
2425 fputs (code
== EQ
? "n" : "z", file
);
2426 else if (letter
== 'T')
2427 fputs (code
== EQ
? "f" : "t", file
);
2428 else if (letter
== 't')
2429 fputs (code
== EQ
? "t" : "f", file
);
2431 else if (code
== CONST
2432 && ((GET_CODE (XEXP (op
, 0)) == REG
)
2433 || (GET_CODE (XEXP (op
, 0)) == UNSPEC
)))
2435 print_operand (file
, XEXP (op
, 0), letter
);
2437 else if (code
== CONST
2438 && (GET_CODE (XEXP (op
, 0)) == PLUS
)
2439 && (GET_CODE (XEXP (XEXP (op
, 0), 0)) == REG
)
2440 && (GET_CODE (XEXP (XEXP (op
, 0), 1)) == CONST
))
2442 print_operand_address (file
, XEXP (op
, 0));
2444 else if (letter
== 'm')
2445 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, (1L << INTVAL (op
)));
2447 output_addr_const (file
, op
);
2450 /* A C compound statement to output to stdio stream STREAM the
2451 assembler syntax for an instruction operand that is a memory
2452 reference whose address is ADDR. ADDR is an RTL expression.
2454 Possible address classifications and output formats are,
2456 ADDRESS_REG "%0, r0"
2458 ADDRESS_REG with non-zero "%0, <addr_const>"
2461 ADDRESS_REG_INDEX "rA, RB"
2462 (if rA is r0, rA and rB are swapped)
2464 ADDRESS_CONST_INT "r0, <addr_const>"
2466 ADDRESS_SYMBOLIC "rBase, <addr_const>"
2467 (rBase is a base register suitable for the
2472 print_operand_address (FILE * file
, rtx addr
)
2474 struct microblaze_address_info info
;
2475 enum microblaze_address_type type
;
2476 if (!microblaze_classify_address (&info
, addr
, GET_MODE (addr
), 1))
2477 fatal_insn ("insn contains an invalid address !", addr
);
2483 fprintf (file
, "%s,", reg_names
[REGNO (info
.regA
)]);
2484 output_addr_const (file
, info
.offset
);
2486 case ADDRESS_REG_INDEX
:
2487 if (REGNO (info
.regA
) == 0)
2488 /* Make rB == r0 instead of rA == r0. This helps reduce read port
2490 fprintf (file
, "%s,%s", reg_names
[REGNO (info
.regB
)],
2491 reg_names
[REGNO (info
.regA
)]);
2492 else if (REGNO (info
.regB
) != 0)
2493 /* This is a silly swap to help Dhrystone. */
2494 fprintf (file
, "%s,%s", reg_names
[REGNO (info
.regB
)],
2495 reg_names
[REGNO (info
.regA
)]);
2497 case ADDRESS_CONST_INT
:
2498 fprintf (file
, "%s,", reg_names
[REGNO (info
.regA
)]);
2499 output_addr_const (file
, info
.offset
);
2501 case ADDRESS_SYMBOLIC
:
2502 case ADDRESS_GOTOFF
:
2506 fprintf (file
, "%s,", reg_names
[REGNO (info
.regA
)]);
2507 output_addr_const (file
, info
.symbol
);
2508 if (type
== ADDRESS_GOTOFF
)
2510 fputs ("@GOT", file
);
2512 else if (type
== ADDRESS_PLT
)
2514 fputs ("@PLT", file
);
2516 else if (type
== ADDRESS_TLS
)
2518 switch (info
.tls_type
)
2521 fputs ("@TLSGD", file
);
2524 fputs ("@TLSLDM", file
);
2527 fputs ("@TLSDTPREL", file
);
2535 case ADDRESS_INVALID
:
2536 fatal_insn ("invalid address", addr
);
2541 /* Emit either a label, .comm, or .lcomm directive, and mark that the symbol
2542 is used, so that we don't emit an .extern for it in
2543 microblaze_asm_file_end. */
2546 microblaze_declare_object (FILE * stream
, const char *name
,
2547 const char *section
, const char *fmt
, int size
)
2550 fputs (section
, stream
);
2551 assemble_name (stream
, name
);
2552 fprintf (stream
, fmt
, size
);
2555 /* Common code to emit the insns (or to write the instructions to a file)
2556 to save/restore registers.
2558 Other parts of the code assume that MICROBLAZE_TEMP1_REGNUM (aka large_reg)
2559 is not modified within save_restore_insns. */
2561 #define BITSET_P(VALUE,BIT) (((VALUE) & (1L << (BIT))) != 0)
2563 /* Save or restore instructions based on whether this is the prologue or
2564 epilogue. prologue is 1 for the prologue. */
2566 save_restore_insns (int prologue
)
2568 rtx base_reg_rtx
, reg_rtx
, mem_rtx
, /* msr_rtx, */ isr_reg_rtx
=
2570 rtx isr_msr_rtx
= 0, insn
;
2571 long mask
= current_frame_info
.mask
;
2572 HOST_WIDE_INT gp_offset
;
2575 if (frame_pointer_needed
2576 && !BITSET_P (mask
, HARD_FRAME_POINTER_REGNUM
- GP_REG_FIRST
))
2582 /* Save registers starting from high to low. The debuggers prefer at least
2583 the return register be stored at func+4, and also it allows us not to
2584 need a nop in the epilog if at least one register is reloaded in
2585 addition to return address. */
2587 /* Pick which pointer to use as a base register. For small frames, just
2588 use the stack pointer. Otherwise, use a temporary register. Save 2
2589 cycles if the save area is near the end of a large frame, by reusing
2590 the constant created in the prologue/epilogue to adjust the stack
2593 gp_offset
= current_frame_info
.gp_offset
;
2595 gcc_assert (gp_offset
> 0);
2597 base_reg_rtx
= stack_pointer_rtx
;
2599 /* For interrupt_handlers, need to save/restore the MSR. */
2600 if (microblaze_is_interrupt_variant ())
2602 isr_mem_rtx
= gen_rtx_MEM (SImode
,
2603 gen_rtx_PLUS (Pmode
, base_reg_rtx
,
2604 GEN_INT (current_frame_info
.
2608 /* Do not optimize in flow analysis. */
2609 MEM_VOLATILE_P (isr_mem_rtx
) = 1;
2610 isr_reg_rtx
= gen_rtx_REG (SImode
, MB_ABI_MSR_SAVE_REG
);
2611 isr_msr_rtx
= gen_rtx_REG (SImode
, ST_REG
);
2614 if (microblaze_is_interrupt_variant () && !prologue
)
2616 emit_move_insn (isr_reg_rtx
, isr_mem_rtx
);
2617 emit_move_insn (isr_msr_rtx
, isr_reg_rtx
);
2618 /* Do not optimize in flow analysis. */
2619 emit_insn (gen_rtx_USE (SImode
, isr_reg_rtx
));
2620 emit_insn (gen_rtx_USE (SImode
, isr_msr_rtx
));
2623 for (regno
= GP_REG_FIRST
; regno
<= GP_REG_LAST
; regno
++)
2625 if (BITSET_P (mask
, regno
- GP_REG_FIRST
))
2627 if (regno
== MB_ABI_SUB_RETURN_ADDR_REGNUM
)
2628 /* Don't handle here. Already handled as the first register. */
2631 reg_rtx
= gen_rtx_REG (SImode
, regno
);
2632 insn
= gen_rtx_PLUS (Pmode
, base_reg_rtx
, GEN_INT (gp_offset
));
2633 mem_rtx
= gen_rtx_MEM (SImode
, insn
);
2634 if (microblaze_is_interrupt_variant () || save_volatiles
)
2635 /* Do not optimize in flow analysis. */
2636 MEM_VOLATILE_P (mem_rtx
) = 1;
2640 insn
= emit_move_insn (mem_rtx
, reg_rtx
);
2641 RTX_FRAME_RELATED_P (insn
) = 1;
2645 insn
= emit_move_insn (reg_rtx
, mem_rtx
);
2648 gp_offset
+= GET_MODE_SIZE (SImode
);
2652 if (microblaze_is_interrupt_variant () && prologue
)
2654 emit_move_insn (isr_reg_rtx
, isr_msr_rtx
);
2655 emit_move_insn (isr_mem_rtx
, isr_reg_rtx
);
2657 /* Do not optimize in flow analysis. */
2658 emit_insn (gen_rtx_USE (SImode
, isr_reg_rtx
));
2659 emit_insn (gen_rtx_USE (SImode
, isr_msr_rtx
));
2662 /* Done saving and restoring */
2666 /* Set up the stack and frame (if desired) for the function. */
2668 microblaze_function_prologue (FILE * file
, HOST_WIDE_INT size ATTRIBUTE_UNUSED
)
2671 long fsiz
= current_frame_info
.total_size
;
2673 /* Get the function name the same way that toplev.c does before calling
2674 assemble_start_function. This is needed so that the name used here
2675 exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */
2676 fnname
= XSTR (XEXP (DECL_RTL (current_function_decl
), 0), 0);
2677 if (!flag_inhibit_size_directive
)
2679 fputs ("\t.ent\t", file
);
2680 if (interrupt_handler
&& strcmp (INTERRUPT_HANDLER_NAME
, fnname
))
2681 fputs ("_interrupt_handler", file
);
2682 else if (break_handler
&& strcmp (BREAK_HANDLER_NAME
, fnname
))
2683 fputs ("_break_handler", file
);
2684 else if (fast_interrupt
&& strcmp (FAST_INTERRUPT_NAME
, fnname
))
2685 fputs ("_fast_interrupt", file
);
2687 assemble_name (file
, fnname
);
2689 if (!microblaze_is_interrupt_variant ())
2690 ASM_OUTPUT_TYPE_DIRECTIVE (file
, fnname
, "function");
2693 assemble_name (file
, fnname
);
2694 fputs (":\n", file
);
2696 if (interrupt_handler
&& strcmp (INTERRUPT_HANDLER_NAME
, fnname
))
2697 fputs ("_interrupt_handler:\n", file
);
2698 if (break_handler
&& strcmp (BREAK_HANDLER_NAME
, fnname
))
2699 fputs ("_break_handler:\n", file
);
2700 if (!flag_inhibit_size_directive
)
2702 /* .frame FRAMEREG, FRAMESIZE, RETREG. */
2704 "\t.frame\t%s,%ld,%s\t\t# vars= %ld, regs= %d, args= %d\n",
2705 (reg_names
[(frame_pointer_needed
)
2706 ? HARD_FRAME_POINTER_REGNUM
:
2707 STACK_POINTER_REGNUM
]), fsiz
,
2708 reg_names
[MB_ABI_SUB_RETURN_ADDR_REGNUM
+ GP_REG_FIRST
],
2709 current_frame_info
.var_size
, current_frame_info
.num_gp
,
2710 crtl
->outgoing_args_size
);
2711 fprintf (file
, "\t.mask\t0x%08lx\n", current_frame_info
.mask
);
2715 /* Output extra assembler code at the end of a prologue. */
2717 microblaze_function_end_prologue (FILE * file
)
2719 if (TARGET_STACK_CHECK
)
2721 fprintf (file
, "\t# Stack Check Stub -- Start.\n\t");
2722 fprintf (file
, "ori\tr18,r0,_stack_end\n\t");
2723 fprintf (file
, "cmpu\tr18,r1,r18\n\t");
2724 fprintf (file
, "bgei\tr18,_stack_overflow_exit\n\t");
2725 fprintf (file
, "# Stack Check Stub -- End.\n");
2730 microblaze_elf_asm_cdtor (rtx symbol
, int priority
, bool is_ctor
)
2734 if (priority
!= DEFAULT_INIT_PRIORITY
)
2737 sprintf (buf
, "%s.%.5u",
2738 is_ctor
? ".ctors" : ".dtors",
2739 MAX_INIT_PRIORITY
- priority
);
2740 s
= get_section (buf
, SECTION_WRITE
, NULL_TREE
);
2747 switch_to_section (s
);
2748 assemble_align (POINTER_SIZE
);
2749 fputs ("\t.word\t", asm_out_file
);
2750 output_addr_const (asm_out_file
, symbol
);
2751 fputs ("\n", asm_out_file
);
2754 /* Add a function to the list of static constructors. */
2757 microblaze_elf_asm_constructor (rtx symbol
, int priority
)
2759 microblaze_elf_asm_cdtor (symbol
, priority
, /*is_ctor=*/true);
2762 /* Add a function to the list of static destructors. */
2765 microblaze_elf_asm_destructor (rtx symbol
, int priority
)
2767 microblaze_elf_asm_cdtor (symbol
, priority
, /*is_ctor=*/false);
2770 /* Expand the prologue into a bunch of separate insns. */
2773 microblaze_expand_prologue (void)
2777 const char *arg_name
= 0;
2778 tree fndecl
= current_function_decl
;
2779 tree fntype
= TREE_TYPE (fndecl
);
2780 tree fnargs
= DECL_ARGUMENTS (fndecl
);
2785 CUMULATIVE_ARGS args_so_far_v
;
2786 cumulative_args_t args_so_far
;
2787 rtx mem_rtx
, reg_rtx
;
2789 /* If struct value address is treated as the first argument, make it so. */
2790 if (aggregate_value_p (DECL_RESULT (fndecl
), fntype
)
2791 && !cfun
->returns_pcc_struct
)
2793 tree type
= build_pointer_type (fntype
);
2794 tree function_result_decl
= build_decl (BUILTINS_LOCATION
, PARM_DECL
,
2797 DECL_ARG_TYPE (function_result_decl
) = type
;
2798 TREE_CHAIN (function_result_decl
) = fnargs
;
2799 fnargs
= function_result_decl
;
2802 /* Determine the last argument, and get its name. */
2804 INIT_CUMULATIVE_ARGS (args_so_far_v
, fntype
, NULL_RTX
, 0, 0);
2805 args_so_far
= pack_cumulative_args (&args_so_far_v
);
2806 regno
= GP_ARG_FIRST
;
2808 for (cur_arg
= fnargs
; cur_arg
!= 0; cur_arg
= next_arg
)
2810 tree passed_type
= DECL_ARG_TYPE (cur_arg
);
2811 machine_mode passed_mode
= TYPE_MODE (passed_type
);
2814 if (TREE_ADDRESSABLE (passed_type
))
2816 passed_type
= build_pointer_type (passed_type
);
2817 passed_mode
= Pmode
;
2820 entry_parm
= targetm
.calls
.function_arg (args_so_far
, passed_mode
,
2827 /* passed in a register, so will get homed automatically. */
2828 if (GET_MODE (entry_parm
) == BLKmode
)
2829 words
= (int_size_in_bytes (passed_type
) + 3) / 4;
2831 words
= (GET_MODE_SIZE (GET_MODE (entry_parm
)) + 3) / 4;
2833 regno
= REGNO (entry_parm
) + words
- 1;
2837 regno
= GP_ARG_LAST
+ 1;
2841 targetm
.calls
.function_arg_advance (args_so_far
, passed_mode
,
2844 next_arg
= TREE_CHAIN (cur_arg
);
2847 if (DECL_NAME (cur_arg
))
2848 arg_name
= IDENTIFIER_POINTER (DECL_NAME (cur_arg
));
2854 /* Split parallel insn into a sequence of insns. */
2856 next_arg_reg
= targetm
.calls
.function_arg (args_so_far
, VOIDmode
,
2857 void_type_node
, true);
2858 if (next_arg_reg
!= 0 && GET_CODE (next_arg_reg
) == PARALLEL
)
2860 rtvec adjust
= XVEC (next_arg_reg
, 0);
2861 int num
= GET_NUM_ELEM (adjust
);
2863 for (i
= 0; i
< num
; i
++)
2865 rtx pattern
= RTVEC_ELT (adjust
, i
);
2866 emit_insn (pattern
);
2870 fsiz
= compute_frame_size (get_frame_size ());
2872 if (flag_stack_usage_info
)
2873 current_function_static_stack_size
= fsiz
;
2876 /* If this function is a varargs function, store any registers that
2877 would normally hold arguments ($5 - $10) on the stack. */
2878 if (((TYPE_ARG_TYPES (fntype
) != 0
2879 && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype
)))
2882 && ((arg_name
[0] == '_'
2883 && strcmp (arg_name
, "__builtin_va_alist") == 0)
2884 || (arg_name
[0] == 'v'
2885 && strcmp (arg_name
, "va_alist") == 0)))))
2887 int offset
= (regno
- GP_ARG_FIRST
+ 1) * UNITS_PER_WORD
;
2888 rtx ptr
= stack_pointer_rtx
;
2890 /* If we are doing svr4-abi, sp has already been decremented by fsiz. */
2891 for (; regno
<= GP_ARG_LAST
; regno
++)
2894 ptr
= gen_rtx_PLUS (Pmode
, stack_pointer_rtx
, GEN_INT (offset
));
2895 emit_move_insn (gen_rtx_MEM (SImode
, ptr
),
2896 gen_rtx_REG (SImode
, regno
));
2898 offset
+= GET_MODE_SIZE (SImode
);
2905 rtx fsiz_rtx
= GEN_INT (fsiz
);
2907 rtx_insn
*insn
= NULL
;
2908 insn
= emit_insn (gen_subsi3 (stack_pointer_rtx
, stack_pointer_rtx
,
2911 RTX_FRAME_RELATED_P (insn
) = 1;
2913 /* Handle SUB_RETURN_ADDR_REGNUM specially at first. */
2914 if (!crtl
->is_leaf
|| interrupt_handler
)
2916 mem_rtx
= gen_rtx_MEM (SImode
,
2917 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
2920 if (interrupt_handler
)
2921 /* Do not optimize in flow analysis. */
2922 MEM_VOLATILE_P (mem_rtx
) = 1;
2924 reg_rtx
= gen_rtx_REG (SImode
, MB_ABI_SUB_RETURN_ADDR_REGNUM
);
2925 insn
= emit_move_insn (mem_rtx
, reg_rtx
);
2926 RTX_FRAME_RELATED_P (insn
) = 1;
2929 /* _save_ registers for prologue. */
2930 save_restore_insns (1);
2932 if (frame_pointer_needed
)
2936 insn
= emit_insn (gen_movsi (hard_frame_pointer_rtx
,
2937 stack_pointer_rtx
));
2940 RTX_FRAME_RELATED_P (insn
) = 1;
2944 if ((flag_pic
== 2 || TLS_NEEDS_GOT
)
2945 && df_regs_ever_live_p (MB_ABI_PIC_ADDR_REGNUM
))
2947 SET_REGNO (pic_offset_table_rtx
, MB_ABI_PIC_ADDR_REGNUM
);
2948 emit_insn (gen_set_got (pic_offset_table_rtx
)); /* setting GOT. */
2951 /* If we are profiling, make sure no instructions are scheduled before
2952 the call to mcount. */
2955 emit_insn (gen_blockage ());
2958 /* Do necessary cleanup after a function to restore stack, frame, and regs. */
2960 #define RA_MASK ((long) 0x80000000) /* 1 << 31 */
2961 #define PIC_OFFSET_TABLE_MASK (1 << (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST))
2964 microblaze_function_epilogue (FILE * file ATTRIBUTE_UNUSED
,
2965 HOST_WIDE_INT size ATTRIBUTE_UNUSED
)
2969 /* Get the function name the same way that toplev.c does before calling
2970 assemble_start_function. This is needed so that the name used here
2971 exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */
2972 fnname
= XSTR (XEXP (DECL_RTL (current_function_decl
), 0), 0);
2974 if (!flag_inhibit_size_directive
)
2976 fputs ("\t.end\t", file
);
2977 if (interrupt_handler
&& !break_handler
)
2978 fputs ("_interrupt_handler", file
);
2979 else if (break_handler
)
2980 fputs ("_break_handler", file
);
2982 assemble_name (file
, fnname
);
2986 /* Reset state info for each function. */
2987 current_frame_info
= zero_frame_info
;
2989 /* Restore the output file if optimizing the GP (optimizing the GP causes
2990 the text to be diverted to a tempfile, so that data decls come before
2991 references to the data). */
2994 /* Expand the epilogue into a bunch of separate insns. */
2997 microblaze_expand_epilogue (void)
2999 HOST_WIDE_INT fsiz
= current_frame_info
.total_size
;
3000 rtx fsiz_rtx
= GEN_INT (fsiz
);
3004 /* In case of interrupt handlers use addki instead of addi for changing the
3005 stack pointer value. */
3007 if (microblaze_can_use_return_insn ())
3009 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode
,
3011 MB_ABI_SUB_RETURN_ADDR_REGNUM
)));
3017 /* Restore SUB_RETURN_ADDR_REGNUM at first. This is to prevent the
3018 sequence of load-followed by a use (in rtsd) in every prologue. Saves
3019 a load-use stall cycle :) This is also important to handle alloca.
3020 (See comments for if (frame_pointer_needed) below. */
3022 if (!crtl
->is_leaf
|| interrupt_handler
)
3025 gen_rtx_MEM (SImode
,
3026 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
, const0_rtx
));
3027 if (interrupt_handler
)
3028 /* Do not optimize in flow analysis. */
3029 MEM_VOLATILE_P (mem_rtx
) = 1;
3030 reg_rtx
= gen_rtx_REG (SImode
, MB_ABI_SUB_RETURN_ADDR_REGNUM
);
3031 emit_move_insn (reg_rtx
, mem_rtx
);
3034 /* It is important that this is done after we restore the return address
3035 register (above). When alloca is used, we want to restore the
3036 sub-routine return address only from the current stack top and not
3037 from the frame pointer (which we restore below). (frame_pointer + 0)
3038 might have been over-written since alloca allocates memory on the
3040 if (frame_pointer_needed
)
3041 emit_insn (gen_movsi (stack_pointer_rtx
, hard_frame_pointer_rtx
));
3043 /* _restore_ registers for epilogue. */
3044 save_restore_insns (0);
3045 emit_insn (gen_blockage ());
3046 emit_insn (gen_addsi3 (stack_pointer_rtx
, stack_pointer_rtx
, fsiz_rtx
));
3049 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode
, GP_REG_FIRST
+
3050 MB_ABI_SUB_RETURN_ADDR_REGNUM
)));
3054 /* Return nonzero if this function is known to have a null epilogue.
3055 This allows the optimizer to omit jumps to jumps if no stack
3059 microblaze_can_use_return_insn (void)
3061 if (!reload_completed
)
3064 if (df_regs_ever_live_p (MB_ABI_SUB_RETURN_ADDR_REGNUM
) || profile_flag
)
3067 if (current_frame_info
.initialized
)
3068 return current_frame_info
.total_size
== 0;
3070 return compute_frame_size (get_frame_size ()) == 0;
3073 /* Implement TARGET_SECONDARY_RELOAD. */
3076 microblaze_secondary_reload (bool in_p ATTRIBUTE_UNUSED
, rtx x ATTRIBUTE_UNUSED
,
3077 reg_class_t rclass
, machine_mode mode ATTRIBUTE_UNUSED
,
3078 secondary_reload_info
*sri ATTRIBUTE_UNUSED
)
3080 if (rclass
== ST_REGS
)
3087 microblaze_globalize_label (FILE * stream
, const char *name
)
3089 fputs ("\t.globl\t", stream
);
3090 if (microblaze_is_interrupt_variant ())
3092 if (interrupt_handler
&& strcmp (name
, INTERRUPT_HANDLER_NAME
))
3093 fputs (INTERRUPT_HANDLER_NAME
, stream
);
3094 else if (break_handler
&& strcmp (name
, BREAK_HANDLER_NAME
))
3095 fputs (BREAK_HANDLER_NAME
, stream
);
3096 else if (fast_interrupt
&& strcmp (name
, FAST_INTERRUPT_NAME
))
3097 fputs (FAST_INTERRUPT_NAME
, stream
);
3098 fputs ("\n\t.globl\t", stream
);
3100 assemble_name (stream
, name
);
3101 fputs ("\n", stream
);
3104 /* Returns true if decl should be placed into a "small data" section. */
3106 microblaze_elf_in_small_data_p (const_tree decl
)
3110 if (!TARGET_XLGPOPT
)
3113 /* We want to merge strings, so we never consider them small data. */
3114 if (TREE_CODE (decl
) == STRING_CST
)
3117 /* Functions are never in the small data area. */
3118 if (TREE_CODE (decl
) == FUNCTION_DECL
)
3121 if (TREE_CODE (decl
) == VAR_DECL
&& DECL_SECTION_NAME (decl
))
3123 const char *section
= DECL_SECTION_NAME (decl
);
3124 if (strcmp (section
, ".sdata") == 0
3125 || strcmp (section
, ".sdata2") == 0
3126 || strcmp (section
, ".sbss") == 0
3127 || strcmp (section
, ".sbss2") == 0)
3131 size
= int_size_in_bytes (TREE_TYPE (decl
));
3133 return (size
> 0 && size
<= microblaze_section_threshold
);
3138 microblaze_select_section (tree decl
, int reloc
, unsigned HOST_WIDE_INT align
)
3140 switch (categorize_decl_for_section (decl
, reloc
))
3142 case SECCAT_RODATA_MERGE_STR
:
3143 case SECCAT_RODATA_MERGE_STR_INIT
:
3144 /* MB binutils have various issues with mergeable string sections and
3145 relaxation/relocation. Currently, turning mergeable sections
3146 into regular readonly sections. */
3148 return readonly_data_section
;
3150 return default_elf_select_section (decl
, reloc
, align
);
3155 Encode info about sections into the RTL based on a symbol's declaration.
3156 The default definition of this hook, default_encode_section_info in
3157 `varasm.c', sets a number of commonly-useful bits in SYMBOL_REF_FLAGS. */
3160 microblaze_encode_section_info (tree decl
, rtx rtl
, int first
)
3162 default_encode_section_info (decl
, rtl
, first
);
3166 expand_pic_symbol_ref (machine_mode mode ATTRIBUTE_UNUSED
, rtx op
)
3169 result
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, op
), UNSPEC_GOTOFF
);
3170 result
= gen_rtx_CONST (Pmode
, result
);
3171 result
= gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
, result
);
3172 result
= gen_const_mem (Pmode
, result
);
3177 microblaze_asm_output_mi_thunk (FILE *file
, tree thunk_fndecl ATTRIBUTE_UNUSED
,
3178 HOST_WIDE_INT delta
, HOST_WIDE_INT vcall_offset
,
3181 rtx this_rtx
, funexp
;
3184 reload_completed
= 1;
3185 epilogue_completed
= 1;
3187 /* Mark the end of the (empty) prologue. */
3188 emit_note (NOTE_INSN_PROLOGUE_END
);
3190 /* Find the "this" pointer. If the function returns a structure,
3191 the structure return pointer is in MB_ABI_FIRST_ARG_REGNUM. */
3192 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function
)), function
))
3193 this_rtx
= gen_rtx_REG (Pmode
, (MB_ABI_FIRST_ARG_REGNUM
+ 1));
3195 this_rtx
= gen_rtx_REG (Pmode
, MB_ABI_FIRST_ARG_REGNUM
);
3197 /* Apply the constant offset, if required. */
3199 emit_insn (gen_addsi3 (this_rtx
, this_rtx
, GEN_INT (delta
)));
3201 /* Apply the offset from the vtable, if required. */
3204 rtx vcall_offset_rtx
= GEN_INT (vcall_offset
);
3205 rtx temp1
= gen_rtx_REG (Pmode
, MB_ABI_TEMP1_REGNUM
);
3207 emit_move_insn (temp1
, gen_rtx_MEM (Pmode
, this_rtx
));
3209 rtx loc
= gen_rtx_PLUS (Pmode
, temp1
, vcall_offset_rtx
);
3210 emit_move_insn (temp1
, gen_rtx_MEM (Pmode
, loc
));
3212 emit_insn (gen_addsi3 (this_rtx
, this_rtx
, temp1
));
3215 /* Generate a tail call to the target function. */
3216 if (!TREE_USED (function
))
3218 assemble_external (function
);
3219 TREE_USED (function
) = 1;
3222 funexp
= XEXP (DECL_RTL (function
), 0);
3223 rtx temp2
= gen_rtx_REG (Pmode
, MB_ABI_TEMP2_REGNUM
);
3226 emit_move_insn (temp2
, expand_pic_symbol_ref (Pmode
, funexp
));
3228 emit_move_insn (temp2
, funexp
);
3230 emit_insn (gen_indirect_jump (temp2
));
3232 /* Run just enough of rest_of_compilation. This sequence was
3233 "borrowed" from rs6000.c. */
3234 insn
= get_insns ();
3235 shorten_branches (insn
);
3236 final_start_function (insn
, file
, 1);
3237 final (insn
, file
, 1);
3238 final_end_function ();
3240 reload_completed
= 0;
3241 epilogue_completed
= 0;
3245 microblaze_expand_move (machine_mode mode
, rtx operands
[])
3252 if (!register_operand (op0
, SImode
)
3253 && !register_operand (op1
, SImode
)
3254 && (GET_CODE (op1
) != CONST_INT
|| INTVAL (op1
) != 0))
3256 rtx temp
= force_reg (SImode
, op1
);
3257 emit_move_insn (op0
, temp
);
3260 /* If operands[1] is a constant address invalid for pic, then we need to
3261 handle it just like LEGITIMIZE_ADDRESS does. */
3262 if (GET_CODE (op1
) == SYMBOL_REF
|| GET_CODE (op1
) == LABEL_REF
)
3265 if (microblaze_tls_symbol_p(op1
))
3267 result
= microblaze_legitimize_tls_address (op1
, NULL_RTX
);
3268 emit_move_insn (op0
, result
);
3273 if (reload_in_progress
)
3274 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
3275 result
= expand_pic_symbol_ref (mode
, op1
);
3276 emit_move_insn (op0
, result
);
3280 /* Handle Case of (const (plus symbol const_int)). */
3281 if (GET_CODE (op1
) == CONST
&& GET_CODE (XEXP (op1
,0)) == PLUS
)
3285 p0
= XEXP (XEXP (op1
, 0), 0);
3286 p1
= XEXP (XEXP (op1
, 0), 1);
3288 if ((GET_CODE (p1
) == CONST_INT
)
3289 && ((GET_CODE (p0
) == UNSPEC
)
3290 || ((GET_CODE (p0
) == SYMBOL_REF
|| GET_CODE (p0
) == LABEL_REF
)
3291 && (flag_pic
== 2 || microblaze_tls_symbol_p (p0
)
3292 || !SMALL_INT (p1
)))))
3294 rtx temp
= force_reg (SImode
, p0
);
3297 if (flag_pic
&& reload_in_progress
)
3298 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
3299 emit_move_insn (op0
, gen_rtx_PLUS (SImode
, temp
, temp2
));
3306 /* Expand shift operations. */
3308 microblaze_expand_shift (rtx operands
[])
3310 gcc_assert ((GET_CODE (operands
[2]) == CONST_INT
)
3311 || (GET_CODE (operands
[2]) == REG
)
3312 || (GET_CODE (operands
[2]) == SUBREG
));
3314 /* Shift by one -- generate pattern. */
3315 if ((GET_CODE (operands
[2]) == CONST_INT
) && (INTVAL (operands
[2]) == 1))
3318 /* Have barrel shifter and shift > 1: use it. */
3319 if (TARGET_BARREL_SHIFT
)
3322 gcc_assert ((GET_CODE (operands
[0]) == REG
)
3323 || (GET_CODE (operands
[0]) == SUBREG
)
3324 || (GET_CODE (operands
[1]) == REG
)
3325 || (GET_CODE (operands
[1]) == SUBREG
));
3327 /* Shift by zero -- copy regs if necessary. */
3328 if ((GET_CODE (operands
[2]) == CONST_INT
) && (INTVAL (operands
[2]) == 0))
3330 if (REGNO (operands
[0]) != REGNO (operands
[1]))
3331 emit_insn (gen_movsi (operands
[0], operands
[1]));
3338 /* Return an RTX indicating where the return address to the
3339 calling function can be found. */
3341 microblaze_return_addr (int count
, rtx frame ATTRIBUTE_UNUSED
)
3346 return gen_rtx_PLUS (Pmode
,
3347 get_hard_reg_initial_val (Pmode
,
3348 MB_ABI_SUB_RETURN_ADDR_REGNUM
),
3352 /* Queue an .ident string in the queue of top-level asm statements.
3353 If the string size is below the threshold, put it into .sdata2.
3354 If the front-end is done, we must be being called from toplev.c.
3355 In that case, do nothing. */
3357 microblaze_asm_output_ident (const char *string
)
3359 const char *section_asm_op
;
3363 if (symtab
->state
!= PARSING
)
3366 size
= strlen (string
) + 1;
3367 if (size
<= microblaze_section_threshold
)
3368 section_asm_op
= SDATA2_SECTION_ASM_OP
;
3370 section_asm_op
= READONLY_DATA_SECTION_ASM_OP
;
3372 buf
= ACONCAT ((section_asm_op
, "\n\t.ascii \"", string
, "\\0\"\n", NULL
));
3373 symtab
->finalize_toplevel_asm (build_string (strlen (buf
), buf
));
3377 microblaze_elf_asm_init_sections (void)
3380 = get_unnamed_section (SECTION_WRITE
, output_section_asm_op
,
3381 SDATA2_SECTION_ASM_OP
);
3384 /* Generate assembler code for constant parts of a trampoline. */
3387 microblaze_asm_trampoline_template (FILE *f
)
3389 fprintf (f
, "\tmfs r18, rpc\n");
3390 fprintf (f
, "\tlwi r3, r18, 16\n");
3391 fprintf (f
, "\tlwi r18, r18, 20\n");
3392 fprintf (f
, "\tbra r18\n");
3393 /* fprintf (f, "\t.word\t0x00000000\t\t# <function address>\n"); */
3394 /* fprintf (f, "\t.word\t0x00000000\t\t# <static chain value>\n"); */
3397 /* Implement TARGET_TRAMPOLINE_INIT. */
3400 microblaze_trampoline_init (rtx m_tramp
, tree fndecl
, rtx chain_value
)
3402 rtx fnaddr
= XEXP (DECL_RTL (fndecl
), 0);
3405 emit_block_move (m_tramp
, assemble_trampoline_template (),
3406 GEN_INT (6*UNITS_PER_WORD
), BLOCK_OP_NORMAL
);
3408 mem
= adjust_address (m_tramp
, SImode
, 16);
3409 emit_move_insn (mem
, chain_value
);
3410 mem
= adjust_address (m_tramp
, SImode
, 20);
3411 emit_move_insn (mem
, fnaddr
);
3414 /* Generate conditional branch -- first, generate test condition,
3415 second, generate correct branch instruction. */
3418 microblaze_expand_conditional_branch (machine_mode mode
, rtx operands
[])
3420 enum rtx_code code
= GET_CODE (operands
[0]);
3421 rtx cmp_op0
= operands
[1];
3422 rtx cmp_op1
= operands
[2];
3423 rtx label1
= operands
[3];
3424 rtx comp_reg
= gen_reg_rtx (SImode
);
3427 gcc_assert ((GET_CODE (cmp_op0
) == REG
) || (GET_CODE (cmp_op0
) == SUBREG
));
3429 /* If comparing against zero, just test source reg. */
3430 if (cmp_op1
== const0_rtx
)
3433 condition
= gen_rtx_fmt_ee (signed_condition (code
), SImode
, comp_reg
, const0_rtx
);
3434 emit_jump_insn (gen_condjump (condition
, label1
));
3437 else if (code
== EQ
|| code
== NE
)
3439 /* Use xor for equal/not-equal comparison. */
3440 emit_insn (gen_xorsi3 (comp_reg
, cmp_op0
, cmp_op1
));
3441 condition
= gen_rtx_fmt_ee (signed_condition (code
), SImode
, comp_reg
, const0_rtx
);
3442 emit_jump_insn (gen_condjump (condition
, label1
));
3446 /* Generate compare and branch in single instruction. */
3447 cmp_op1
= force_reg (mode
, cmp_op1
);
3448 condition
= gen_rtx_fmt_ee (code
, mode
, cmp_op0
, cmp_op1
);
3449 emit_jump_insn (gen_branch_compare(condition
, cmp_op0
, cmp_op1
, label1
));
3454 microblaze_expand_conditional_branch_reg (enum machine_mode mode
,
3457 enum rtx_code code
= GET_CODE (operands
[0]);
3458 rtx cmp_op0
= operands
[1];
3459 rtx cmp_op1
= operands
[2];
3460 rtx label1
= operands
[3];
3461 rtx comp_reg
= gen_reg_rtx (SImode
);
3464 gcc_assert ((GET_CODE (cmp_op0
) == REG
)
3465 || (GET_CODE (cmp_op0
) == SUBREG
));
3467 /* If comparing against zero, just test source reg. */
3468 if (cmp_op1
== const0_rtx
)
3471 condition
= gen_rtx_fmt_ee (signed_condition (code
),
3472 SImode
, comp_reg
, const0_rtx
);
3473 emit_jump_insn (gen_condjump (condition
, label1
));
3475 else if (code
== EQ
)
3477 emit_insn (gen_seq_internal_pat (comp_reg
,
3479 condition
= gen_rtx_EQ (SImode
, comp_reg
, const0_rtx
);
3480 emit_jump_insn (gen_condjump (condition
, label1
));
3482 else if (code
== NE
)
3484 emit_insn (gen_sne_internal_pat (comp_reg
, cmp_op0
,
3486 condition
= gen_rtx_NE (SImode
, comp_reg
, const0_rtx
);
3487 emit_jump_insn (gen_condjump (condition
, label1
));
3491 /* Generate compare and branch in single instruction. */
3492 cmp_op1
= force_reg (mode
, cmp_op1
);
3493 condition
= gen_rtx_fmt_ee (code
, mode
, cmp_op0
, cmp_op1
);
3494 emit_jump_insn (gen_branch_compare (condition
, cmp_op0
,
3500 microblaze_expand_conditional_branch_sf (rtx operands
[])
3503 rtx cmp_op0
= XEXP (operands
[0], 0);
3504 rtx cmp_op1
= XEXP (operands
[0], 1);
3505 rtx comp_reg
= gen_reg_rtx (SImode
);
3507 emit_insn (gen_cstoresf4 (comp_reg
, operands
[0], cmp_op0
, cmp_op1
));
3508 condition
= gen_rtx_NE (SImode
, comp_reg
, const0_rtx
);
3509 emit_jump_insn (gen_condjump (condition
, operands
[3]));
3512 /* Implement TARGET_FRAME_POINTER_REQUIRED. */
3515 microblaze_frame_pointer_required (void)
3517 /* If the function contains dynamic stack allocations, we need to
3518 use the frame pointer to access the static parts of the frame. */
3519 if (cfun
->calls_alloca
)
3525 microblaze_expand_divide (rtx operands
[])
3527 /* Table lookup software divides. Works for all (nr/dr) where (0 <= nr,dr <= 15). */
3529 rtx regt1
= gen_reg_rtx (SImode
);
3530 rtx reg18
= gen_rtx_REG (SImode
, R_TMP
);
3531 rtx regqi
= gen_reg_rtx (QImode
);
3532 rtx_code_label
*div_label
= gen_label_rtx ();
3533 rtx_code_label
*div_end_label
= gen_label_rtx ();
3534 rtx div_table_rtx
= gen_rtx_SYMBOL_REF (QImode
,"_divsi3_table");
3537 rtx_insn
*jump
, *cjump
, *insn
;
3539 insn
= emit_insn (gen_iorsi3 (regt1
, operands
[1], operands
[2]));
3540 cjump
= emit_jump_insn_after (gen_cbranchsi4 (
3541 gen_rtx_GTU (SImode
, regt1
, GEN_INT (15)),
3542 regt1
, GEN_INT (15), div_label
), insn
);
3543 LABEL_NUSES (div_label
) = 1;
3544 JUMP_LABEL (cjump
) = div_label
;
3545 emit_insn (gen_rtx_CLOBBER (SImode
, reg18
));
3547 emit_insn (gen_ashlsi3_bshift (regt1
, operands
[1], GEN_INT(4)));
3548 emit_insn (gen_addsi3 (regt1
, regt1
, operands
[2]));
3549 mem_rtx
= gen_rtx_MEM (QImode
,
3550 gen_rtx_PLUS (Pmode
, regt1
, div_table_rtx
));
3552 insn
= emit_insn (gen_movqi (regqi
, mem_rtx
));
3553 insn
= emit_insn (gen_movsi (operands
[0], gen_rtx_SUBREG (SImode
, regqi
, 0)));
3554 jump
= emit_jump_insn_after (gen_jump (div_end_label
), insn
);
3555 JUMP_LABEL (jump
) = div_end_label
;
3556 LABEL_NUSES (div_end_label
) = 1;
3559 emit_label (div_label
);
3560 ret
= emit_library_call_value (gen_rtx_SYMBOL_REF (Pmode
, "__divsi3"),
3561 operands
[0], LCT_NORMAL
,
3562 GET_MODE (operands
[0]), 2, operands
[1],
3563 GET_MODE (operands
[1]), operands
[2],
3564 GET_MODE (operands
[2]));
3565 if (ret
!= operands
[0])
3566 emit_move_insn (operands
[0], ret
);
3568 emit_label (div_end_label
);
3569 emit_insn (gen_blockage ());
3572 /* Implement TARGET_FUNCTION_VALUE. */
3574 microblaze_function_value (const_tree valtype
,
3575 const_tree func ATTRIBUTE_UNUSED
,
3576 bool outgoing ATTRIBUTE_UNUSED
)
3578 return LIBCALL_VALUE (TYPE_MODE (valtype
));
3581 /* Implement TARGET_SCHED_ADJUST_COST. */
3583 microblaze_adjust_cost (rtx_insn
*insn ATTRIBUTE_UNUSED
, rtx link
,
3584 rtx_insn
*dep ATTRIBUTE_UNUSED
, int cost
)
3586 if (REG_NOTE_KIND (link
) == REG_DEP_OUTPUT
)
3588 if (REG_NOTE_KIND (link
) != 0)
3593 /* Implement TARGET_LEGITIMATE_CONSTANT_P.
3595 At present, GAS doesn't understand li.[sd], so don't allow it
3596 to be generated at present. */
3598 microblaze_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED
, rtx x
)
3601 if (microblaze_cannot_force_const_mem(mode
, x
))
3604 if (GET_CODE (x
) == CONST_DOUBLE
)
3606 return microblaze_const_double_ok (x
, GET_MODE (x
));
3609 /* Handle Case of (const (plus unspec const_int)). */
3610 if (GET_CODE (x
) == CONST
&& GET_CODE (XEXP (x
,0)) == PLUS
)
3614 p0
= XEXP (XEXP (x
, 0), 0);
3615 p1
= XEXP (XEXP (x
, 0), 1);
3617 if (GET_CODE(p1
) == CONST_INT
)
3619 /* Const offset from UNSPEC is not supported. */
3620 if ((GET_CODE (p0
) == UNSPEC
))
3623 if ((GET_CODE (p0
) == SYMBOL_REF
|| GET_CODE (p0
) == LABEL_REF
)
3624 && (microblaze_tls_symbol_p (p0
) || !SMALL_INT (p1
)))
3633 #undef TARGET_ENCODE_SECTION_INFO
3634 #define TARGET_ENCODE_SECTION_INFO microblaze_encode_section_info
3636 #undef TARGET_ASM_GLOBALIZE_LABEL
3637 #define TARGET_ASM_GLOBALIZE_LABEL microblaze_globalize_label
3639 #undef TARGET_ASM_FUNCTION_PROLOGUE
3640 #define TARGET_ASM_FUNCTION_PROLOGUE microblaze_function_prologue
3642 #undef TARGET_ASM_FUNCTION_EPILOGUE
3643 #define TARGET_ASM_FUNCTION_EPILOGUE microblaze_function_epilogue
3645 #undef TARGET_RTX_COSTS
3646 #define TARGET_RTX_COSTS microblaze_rtx_costs
3648 #undef TARGET_CANNOT_FORCE_CONST_MEM
3649 #define TARGET_CANNOT_FORCE_CONST_MEM microblaze_cannot_force_const_mem
3651 #undef TARGET_ADDRESS_COST
3652 #define TARGET_ADDRESS_COST microblaze_address_cost
3654 #undef TARGET_ATTRIBUTE_TABLE
3655 #define TARGET_ATTRIBUTE_TABLE microblaze_attribute_table
3657 #undef TARGET_IN_SMALL_DATA_P
3658 #define TARGET_IN_SMALL_DATA_P microblaze_elf_in_small_data_p
3660 #undef TARGET_ASM_SELECT_SECTION
3661 #define TARGET_ASM_SELECT_SECTION microblaze_select_section
3663 #undef TARGET_HAVE_SRODATA_SECTION
3664 #define TARGET_HAVE_SRODATA_SECTION true
3666 #undef TARGET_ASM_FUNCTION_END_PROLOGUE
3667 #define TARGET_ASM_FUNCTION_END_PROLOGUE \
3668 microblaze_function_end_prologue
3670 #undef TARGET_ARG_PARTIAL_BYTES
3671 #define TARGET_ARG_PARTIAL_BYTES function_arg_partial_bytes
3673 #undef TARGET_FUNCTION_ARG
3674 #define TARGET_FUNCTION_ARG microblaze_function_arg
3676 #undef TARGET_FUNCTION_ARG_ADVANCE
3677 #define TARGET_FUNCTION_ARG_ADVANCE microblaze_function_arg_advance
3679 #undef TARGET_CAN_ELIMINATE
3680 #define TARGET_CAN_ELIMINATE microblaze_can_eliminate
3682 #undef TARGET_LEGITIMIZE_ADDRESS
3683 #define TARGET_LEGITIMIZE_ADDRESS microblaze_legitimize_address
3685 #undef TARGET_LEGITIMATE_ADDRESS_P
3686 #define TARGET_LEGITIMATE_ADDRESS_P microblaze_legitimate_address_p
3688 #undef TARGET_FRAME_POINTER_REQUIRED
3689 #define TARGET_FRAME_POINTER_REQUIRED microblaze_frame_pointer_required
3691 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
3692 #define TARGET_ASM_TRAMPOLINE_TEMPLATE microblaze_asm_trampoline_template
3694 #undef TARGET_TRAMPOLINE_INIT
3695 #define TARGET_TRAMPOLINE_INIT microblaze_trampoline_init
3697 #undef TARGET_PROMOTE_FUNCTION_MODE
3698 #define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
3700 #undef TARGET_FUNCTION_VALUE
3701 #define TARGET_FUNCTION_VALUE microblaze_function_value
3703 #undef TARGET_SECONDARY_RELOAD
3704 #define TARGET_SECONDARY_RELOAD microblaze_secondary_reload
3706 #undef TARGET_ASM_OUTPUT_MI_THUNK
3707 #define TARGET_ASM_OUTPUT_MI_THUNK microblaze_asm_output_mi_thunk
3709 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
3710 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true
3712 #undef TARGET_SCHED_ADJUST_COST
3713 #define TARGET_SCHED_ADJUST_COST microblaze_adjust_cost
3715 #undef TARGET_ASM_INIT_SECTIONS
3716 #define TARGET_ASM_INIT_SECTIONS microblaze_elf_asm_init_sections
3718 #undef TARGET_OPTION_OVERRIDE
3719 #define TARGET_OPTION_OVERRIDE microblaze_option_override
3721 #undef TARGET_LEGITIMATE_CONSTANT_P
3722 #define TARGET_LEGITIMATE_CONSTANT_P microblaze_legitimate_constant_p
3724 struct gcc_target targetm
= TARGET_INITIALIZER
;
3726 #include "gt-microblaze.h"