1 /* Subroutines used for code generation on Xilinx MicroBlaze.
2 Copyright (C) 2009-2017 Free Software Foundation, Inc.
4 Contributed by Michael Eager <eager@eagercon.com>.
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published
10 by the Free Software Foundation; either version 3, or (at your
11 option) any later version.
13 GCC is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16 License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. */
24 #include "coretypes.h"
29 #include "stringpool.h"
39 #include "diagnostic-core.h"
41 #include "stor-layout.h"
50 #include "insn-addr.h"
53 /* This file should be included last. */
54 #include "target-def.h"
56 #define MICROBLAZE_VERSION_COMPARE(VA,VB) strcasecmp (VA, VB)
58 /* Classifies an address.
65 A natural register or a register + const_int offset address.
66 The register satisfies microblaze_valid_base_register_p and the
67 offset is a const_arith_operand.
71 A natural register offset by the index contained in an index register. The base
72 register satisfies microblaze_valid_base_register_p and the index register
73 satisfies microblaze_valid_index_register_p
77 A signed 16/32-bit constant address.
81 A constant symbolic address or a (register + symbol). */
83 enum microblaze_address_type
100 enum microblaze_symbol_type
106 /* TLS Address Type. */
115 /* Classification of a MicroBlaze address. */
116 struct microblaze_address_info
118 enum microblaze_address_type type
;
119 rtx regA
; /* Contains valid values on ADDRESS_REG, ADDRESS_REG_INDEX,
121 rtx regB
; /* Contains valid values on ADDRESS_REG_INDEX. */
122 rtx offset
; /* Contains valid values on ADDRESS_CONST_INT and ADDRESS_REG. */
123 rtx symbol
; /* Contains valid values on ADDRESS_SYMBOLIC. */
124 enum microblaze_symbol_type symbol_type
;
125 enum tls_reloc tls_type
;
128 /* Structure to be filled in by compute_frame_size with register
129 save masks, and offsets for the current function. */
131 struct GTY(()) microblaze_frame_info
{
132 long total_size
; /* # bytes that the entire frame takes up. */
133 long var_size
; /* # bytes that variables take up. */
134 long args_size
; /* # bytes that outgoing arguments take up. */
135 int link_debug_size
; /* # bytes for the link reg and back pointer. */
136 int gp_reg_size
; /* # bytes needed to store gp regs. */
137 long gp_offset
; /* offset from new sp to store gp registers. */
138 long mask
; /* mask of saved gp registers. */
139 int initialized
; /* != 0 if frame size already calculated. */
140 int num_gp
; /* number of gp registers saved. */
141 long insns_len
; /* length of insns. */
142 int alloc_stack
; /* Flag to indicate if the current function
143 must not create stack space. (As an optimization). */
146 /* Global variables for machine-dependent things. */
148 /* Toggle which pipleline interface to use. */
149 static GTY(()) int microblaze_sched_use_dfa
= 0;
151 /* Threshold for data being put into the small data/bss area, instead
152 of the normal data area (references to the small data/bss area take
153 1 instruction, and use the global pointer, references to the normal
154 data area takes 2 instructions). */
155 int microblaze_section_threshold
= -1;
157 /* Prevent scheduling potentially exception causing instructions in
158 delay slots. -mcpu=v3.00.a or v4.00.a turns this on. */
159 int microblaze_no_unsafe_delay
;
161 /* Set to one if the targeted core has the CLZ insn. */
162 int microblaze_has_clz
= 0;
164 /* Which CPU pipeline do we use. We haven't really standardized on a CPU
165 version having only a particular type of pipeline. There can still be
166 options on the CPU to scale pipeline features up or down. :(
167 Bad Presentation (??), so we let the MD file rely on the value of
168 this variable instead Making PIPE_5 the default. It should be backward
169 optimal with PIPE_3 MicroBlazes. */
170 enum pipeline_type microblaze_pipe
= MICROBLAZE_PIPE_5
;
172 /* High and low marks for floating point values which we will accept
173 as legitimate constants for TARGET_LEGITIMATE_CONSTANT_P. These are
174 initialized in override_options. */
175 REAL_VALUE_TYPE dfhigh
, dflow
, sfhigh
, sflow
;
177 /* Array giving truth value on whether or not a given hard register
178 can support a given mode. */
179 char microblaze_hard_regno_mode_ok
[(int)MAX_MACHINE_MODE
]
180 [FIRST_PSEUDO_REGISTER
];
182 /* Current frame information calculated by compute_frame_size. */
183 struct microblaze_frame_info current_frame_info
;
185 /* Zero structure to initialize current_frame_info. */
186 struct microblaze_frame_info zero_frame_info
;
188 /* List of all MICROBLAZE punctuation characters used by print_operand. */
189 char microblaze_print_operand_punct
[256];
191 /* Map GCC register number to debugger register number. */
192 int microblaze_dbx_regno
[FIRST_PSEUDO_REGISTER
];
194 /* Map hard register number to register class. */
195 enum reg_class microblaze_regno_to_class
[] =
197 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
198 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
199 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
200 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
201 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
202 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
203 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
204 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
205 ST_REGS
, GR_REGS
, GR_REGS
, GR_REGS
208 /* MicroBlaze specific machine attributes.
209 interrupt_handler - Interrupt handler attribute to add interrupt prologue
210 and epilogue and use appropriate interrupt return.
211 save_volatiles - Similar to interrupt handler, but use normal return. */
212 int interrupt_handler
;
217 const struct attribute_spec microblaze_attribute_table
[] = {
218 /* name min_len, max_len, decl_req, type_req, fn_type, req_handler,
219 affects_type_identity */
220 {"interrupt_handler", 0, 0, true, false, false, NULL
,
222 {"break_handler", 0, 0, true, false, false, NULL
,
224 {"fast_interrupt", 0, 0, true, false, false, NULL
,
226 {"save_volatiles" , 0, 0, true, false, false, NULL
,
228 { NULL
, 0, 0, false, false, false, NULL
,
232 static int microblaze_interrupt_function_p (tree
);
234 static void microblaze_elf_asm_constructor (rtx
, int) ATTRIBUTE_UNUSED
;
235 static void microblaze_elf_asm_destructor (rtx
, int) ATTRIBUTE_UNUSED
;
237 section
*sdata2_section
;
240 #undef TARGET_HAVE_TLS
241 #define TARGET_HAVE_TLS true
244 /* Return truth value if a CONST_DOUBLE is ok to be a legitimate constant. */
246 microblaze_const_double_ok (rtx op
, machine_mode mode
)
250 if (GET_CODE (op
) != CONST_DOUBLE
)
253 if (GET_MODE (op
) == VOIDmode
)
256 if (mode
!= SFmode
&& mode
!= DFmode
)
259 if (op
== CONST0_RTX (mode
))
262 d
= *CONST_DOUBLE_REAL_VALUE (op
);
264 if (REAL_VALUE_ISNAN (d
))
267 if (REAL_VALUE_NEGATIVE (d
))
268 d
= real_value_negate (&d
);
272 if (real_less (&d
, &dfhigh
) && real_less (&dflow
, &d
))
277 if (real_less (&d
, &sfhigh
) && real_less (&sflow
, &d
))
284 /* Return truth value if a memory operand fits in a single instruction
285 (ie, register + small offset) or (register + register). */
288 simple_memory_operand (rtx op
, machine_mode mode ATTRIBUTE_UNUSED
)
290 rtx addr
, plus0
, plus1
;
292 /* Eliminate non-memory operations. */
293 if (GET_CODE (op
) != MEM
)
296 /* dword operations really put out 2 instructions, so eliminate them. */
297 /* ??? This isn't strictly correct. It is OK to accept multiword modes
298 here, since the length attributes are being set correctly, but only
299 if the address is offsettable. */
300 if (GET_MODE_SIZE (GET_MODE (op
)) > UNITS_PER_WORD
)
304 /* Decode the address now. */
306 switch (GET_CODE (addr
))
313 plus0
= XEXP (addr
, 0);
314 plus1
= XEXP (addr
, 1);
316 if (GET_CODE (plus0
) != REG
)
319 if (GET_CODE (plus0
) == REG
&& GET_CODE (plus1
) == CONST_INT
320 && SMALL_INT (plus1
))
324 else if (GET_CODE (plus1
) == REG
&& GET_CODE (plus0
) == CONST_INT
)
328 else if (GET_CODE (plus0
) == REG
&& GET_CODE (plus1
) == REG
)
345 /* Return nonzero for a memory address that can be used to load or store
349 double_memory_operand (rtx op
, machine_mode mode
)
353 if (GET_CODE (op
) != MEM
|| !memory_operand (op
, mode
))
355 /* During reload, we accept a pseudo register if it has an
356 appropriate memory address. If we don't do this, we will
357 wind up reloading into a register, and then reloading that
358 register from memory, when we could just reload directly from
360 if (reload_in_progress
361 && GET_CODE (op
) == REG
362 && REGNO (op
) >= FIRST_PSEUDO_REGISTER
363 && reg_renumber
[REGNO (op
)] < 0
364 && reg_equiv_mem (REGNO (op
)) != 0
365 && double_memory_operand (reg_equiv_mem (REGNO (op
)), mode
))
370 /* Make sure that 4 added to the address is a valid memory address.
371 This essentially just checks for overflow in an added constant. */
375 if (CONSTANT_ADDRESS_P (addr
))
378 return memory_address_p ((GET_MODE_CLASS (mode
) == MODE_INT
379 ? E_SImode
: E_SFmode
),
380 plus_constant (Pmode
, addr
, 4));
383 /* Implement REG_OK_FOR_BASE_P -and- REG_OK_FOR_INDEX_P. */
385 microblaze_regno_ok_for_base_p (int regno
, int strict
)
387 if (regno
>= FIRST_PSEUDO_REGISTER
)
391 regno
= reg_renumber
[regno
];
394 /* These fake registers will be eliminated to either the stack or
395 hard frame pointer, both of which are usually valid base registers.
396 Reload deals with the cases where the eliminated form isn't valid. */
397 if (regno
== ARG_POINTER_REGNUM
|| regno
== FRAME_POINTER_REGNUM
)
400 return GP_REG_P (regno
);
403 /* Return true if X is a valid base register for the given mode.
404 Allow only hard registers if STRICT. */
407 microblaze_valid_base_register_p (rtx x
,
408 machine_mode mode ATTRIBUTE_UNUSED
,
411 if (!strict
&& GET_CODE (x
) == SUBREG
)
414 return (GET_CODE (x
) == REG
415 && microblaze_regno_ok_for_base_p (REGNO (x
), strict
));
418 /* Build the SYMBOL_REF for __tls_get_addr. */
420 static GTY(()) rtx tls_get_addr_libfunc
;
423 get_tls_get_addr (void)
425 if (!tls_get_addr_libfunc
)
426 tls_get_addr_libfunc
= init_one_libfunc ("__tls_get_addr");
427 return tls_get_addr_libfunc
;
430 /* Return TRUE if X is a thread-local symbol. */
432 microblaze_tls_symbol_p (rtx x
)
434 if (!TARGET_HAVE_TLS
)
437 if (GET_CODE (x
) != SYMBOL_REF
)
440 return SYMBOL_REF_TLS_MODEL (x
) != 0;
443 /* Return TRUE if X contains any TLS symbol references. */
446 microblaze_tls_referenced_p (rtx x
)
448 if (!TARGET_HAVE_TLS
)
450 subrtx_iterator::array_type array
;
451 FOR_EACH_SUBRTX (iter
, array
, x
, ALL
)
454 if (GET_CODE (x
) == SYMBOL_REF
&& SYMBOL_REF_TLS_MODEL (x
) != 0)
456 /* Don't recurse into UNSPEC_TLS looking for TLS symbols; these are
457 TLS offsets, not real symbol references. */
458 if (GET_CODE (x
) == UNSPEC
&& XINT (x
, 1) == UNSPEC_TLS
)
459 iter
.skip_subrtxes ();
465 microblaze_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED
, rtx x
)
467 return microblaze_tls_referenced_p(x
);
470 /* Return TRUE if X references a SYMBOL_REF. */
472 symbol_mentioned_p (rtx x
)
477 if (GET_CODE (x
) == SYMBOL_REF
)
480 /* UNSPEC entries for a symbol include the SYMBOL_REF, but they
481 are constant offsets, not symbols. */
482 if (GET_CODE (x
) == UNSPEC
)
485 fmt
= GET_RTX_FORMAT (GET_CODE (x
));
487 for (i
= GET_RTX_LENGTH (GET_CODE (x
)) - 1; i
>= 0; i
--)
493 for (j
= XVECLEN (x
, i
) - 1; j
>= 0; j
--)
494 if (symbol_mentioned_p (XVECEXP (x
, i
, j
)))
497 else if (fmt
[i
] == 'e' && symbol_mentioned_p (XEXP (x
, i
)))
504 /* Return TRUE if X references a LABEL_REF. */
506 label_mentioned_p (rtx x
)
511 if (GET_CODE (x
) == LABEL_REF
)
514 /* UNSPEC entries for a symbol include a LABEL_REF for the referencing
515 instruction, but they are constant offsets, not symbols. */
516 if (GET_CODE (x
) == UNSPEC
)
519 fmt
= GET_RTX_FORMAT (GET_CODE (x
));
520 for (i
= GET_RTX_LENGTH (GET_CODE (x
)) - 1; i
>= 0; i
--)
526 for (j
= XVECLEN (x
, i
) - 1; j
>= 0; j
--)
527 if (label_mentioned_p (XVECEXP (x
, i
, j
)))
530 else if (fmt
[i
] == 'e' && label_mentioned_p (XEXP (x
, i
)))
538 tls_mentioned_p (rtx x
)
540 switch (GET_CODE (x
))
543 return tls_mentioned_p (XEXP (x
, 0));
546 if (XINT (x
, 1) == UNSPEC_TLS
)
556 load_tls_operand (rtx x
, rtx reg
)
561 reg
= gen_reg_rtx (Pmode
);
563 tmp
= gen_rtx_CONST (Pmode
, x
);
565 emit_insn (gen_rtx_SET (reg
,
566 gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
, tmp
)));
572 microblaze_call_tls_get_addr (rtx x
, rtx reg
, rtx
*valuep
, int reloc
)
577 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
581 tls_entry
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (2, x
, GEN_INT (reloc
)),
584 reg
= load_tls_operand (tls_entry
, reg
);
586 *valuep
= emit_library_call_value (get_tls_get_addr (), NULL_RTX
,
587 LCT_PURE
, /* LCT_CONST? */
590 insns
= get_insns ();
597 microblaze_legitimize_tls_address(rtx x
, rtx reg
)
599 rtx dest
, ret
, eqv
, addend
;
601 enum tls_model model
;
602 model
= SYMBOL_REF_TLS_MODEL (x
);
606 case TLS_MODEL_LOCAL_DYNAMIC
:
607 case TLS_MODEL_GLOBAL_DYNAMIC
:
608 case TLS_MODEL_INITIAL_EXEC
:
609 insns
= microblaze_call_tls_get_addr (x
, reg
, &ret
, TLS_GD
);
610 dest
= gen_reg_rtx (Pmode
);
611 emit_libcall_block (insns
, dest
, ret
, x
);
614 case TLS_MODEL_LOCAL_EXEC
:
615 insns
= microblaze_call_tls_get_addr (x
, reg
, &ret
, TLS_LDM
);
617 /* Attach a unique REG_EQUIV, to allow the RTL optimizers to
618 share the LDM result with other LD model accesses. */
619 eqv
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, const1_rtx
), UNSPEC_TLS
);
620 dest
= gen_reg_rtx (Pmode
);
621 emit_libcall_block (insns
, dest
, ret
, eqv
);
623 /* Load the addend. */
624 addend
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (2, x
, GEN_INT (TLS_DTPREL
)),
626 addend
= force_reg (SImode
, gen_rtx_CONST (SImode
, addend
));
627 dest
= gen_rtx_PLUS (Pmode
, dest
, addend
);
637 microblaze_classify_unspec (struct microblaze_address_info
*info
, rtx x
)
639 info
->symbol_type
= SYMBOL_TYPE_GENERAL
;
640 info
->symbol
= XVECEXP (x
, 0, 0);
642 if (XINT (x
, 1) == UNSPEC_GOTOFF
)
644 info
->regA
= gen_rtx_REG (SImode
, PIC_OFFSET_TABLE_REGNUM
);
645 info
->type
= ADDRESS_GOTOFF
;
647 else if (XINT (x
, 1) == UNSPEC_PLT
)
649 info
->type
= ADDRESS_PLT
;
651 else if (XINT (x
, 1) == UNSPEC_TLS
)
653 info
->type
= ADDRESS_TLS
;
654 info
->tls_type
= tls_reloc (INTVAL (XVECEXP (x
, 0, 1)));
664 /* Return true if X is a valid index register for the given mode.
665 Allow only hard registers if STRICT. */
668 microblaze_valid_index_register_p (rtx x
,
669 machine_mode mode ATTRIBUTE_UNUSED
,
672 if (!strict
&& GET_CODE (x
) == SUBREG
)
675 return (GET_CODE (x
) == REG
676 /* A base register is good enough to be an index register on MicroBlaze. */
677 && microblaze_regno_ok_for_base_p (REGNO (x
), strict
));
680 /* Get the base register for accessing a value from the memory or
681 Symbol ref. Used for MicroBlaze Small Data Area Pointer Optimization. */
688 if (!flag_pic
|| microblaze_tls_symbol_p(x
))
689 base_reg
= MB_ABI_BASE_REGNUM
;
691 base_reg
= MB_ABI_PIC_ADDR_REGNUM
;
694 && GET_CODE (x
) == SYMBOL_REF
695 && SYMBOL_REF_SMALL_P (x
) && (decl
= SYMBOL_REF_DECL (x
)) != NULL
)
697 if (TREE_READONLY (decl
))
698 base_reg
= MB_ABI_GPRO_REGNUM
;
700 base_reg
= MB_ABI_GPRW_REGNUM
;
706 /* Return true if X is a valid address for machine mode MODE. If it is,
707 fill in INFO appropriately. STRICT is true if we should only accept
710 type regA regB offset symbol
712 ADDRESS_INVALID NULL NULL NULL NULL
714 ADDRESS_REG %0 NULL const_0 / NULL
716 ADDRESS_REG_INDEX %0 %1 NULL NULL
718 ADDRESS_SYMBOLIC r0 / NULL NULL symbol
721 ADDRESS_CONST_INT r0 NULL const NULL
723 For modes spanning multiple registers (DFmode in 32-bit GPRs,
724 DImode, TImode), indexed addressing cannot be used because
725 adjacent memory cells are accessed by adding word-sized offsets
726 during assembly output. */
729 microblaze_classify_address (struct microblaze_address_info
*info
, rtx x
,
730 machine_mode mode
, int strict
)
735 info
->type
= ADDRESS_INVALID
;
740 info
->symbol_type
= SYMBOL_TYPE_INVALID
;
742 switch (GET_CODE (x
))
747 info
->type
= ADDRESS_REG
;
749 info
->offset
= const0_rtx
;
750 return microblaze_valid_base_register_p (info
->regA
, mode
, strict
);
754 xplus0
= XEXP (x
, 0);
755 xplus1
= XEXP (x
, 1);
757 if (microblaze_valid_base_register_p (xplus0
, mode
, strict
))
759 info
->type
= ADDRESS_REG
;
762 if (GET_CODE (xplus1
) == CONST_INT
)
764 info
->offset
= xplus1
;
767 else if (GET_CODE (xplus1
) == UNSPEC
)
769 /* Need offsettable address. */
770 if (GET_MODE_SIZE (mode
) > UNITS_PER_WORD
)
773 return microblaze_classify_unspec (info
, xplus1
);
775 else if ((GET_CODE (xplus1
) == SYMBOL_REF
||
776 GET_CODE (xplus1
) == LABEL_REF
))
778 if (flag_pic
== 2 || microblaze_tls_symbol_p(xplus1
))
780 info
->type
= ADDRESS_SYMBOLIC
;
781 info
->symbol
= xplus1
;
782 info
->symbol_type
= SYMBOL_TYPE_GENERAL
;
785 else if (GET_CODE (xplus1
) == CONST
)
787 rtx xconst0
= XEXP(xplus1
, 0);
790 if (GET_CODE (xconst0
) == UNSPEC
)
792 /* Need offsettable address. */
793 if (GET_MODE_SIZE (mode
) > UNITS_PER_WORD
)
795 return microblaze_classify_unspec(info
, xconst0
);
798 /* for (plus x const_int) just look at x. */
799 if (GET_CODE (xconst0
) == PLUS
800 && GET_CODE (XEXP (xconst0
, 1)) == CONST_INT
801 && SMALL_INT (XEXP (xconst0
, 1)))
803 /* This is ok as info->symbol is set to xplus1 the full
804 const-expression below. */
805 xconst0
= XEXP (xconst0
, 0);
808 if (GET_CODE (xconst0
) == SYMBOL_REF
809 || GET_CODE (xconst0
) == LABEL_REF
)
811 if (flag_pic
== 2 || microblaze_tls_symbol_p(xconst0
))
814 info
->type
= ADDRESS_SYMBOLIC
;
815 info
->symbol
= xplus1
;
816 info
->symbol_type
= SYMBOL_TYPE_GENERAL
;
820 /* Not base + symbol || base + UNSPEC. */
824 else if (GET_CODE (xplus1
) == REG
825 && microblaze_valid_index_register_p (xplus1
, mode
,
827 && (GET_MODE_SIZE (mode
) <= UNITS_PER_WORD
))
829 /* Restrict larger than word-width modes from using an index register. */
830 info
->type
= ADDRESS_REG_INDEX
;
839 info
->regA
= gen_raw_REG (mode
, 0);
840 info
->type
= ADDRESS_CONST_INT
;
848 info
->type
= ADDRESS_SYMBOLIC
;
849 info
->symbol_type
= SYMBOL_TYPE_GENERAL
;
851 info
->regA
= gen_raw_REG (mode
, get_base_reg (x
));
853 if (GET_CODE (x
) == CONST
)
855 if (GET_CODE (XEXP (x
, 0)) == UNSPEC
)
857 info
->regA
= gen_raw_REG (mode
,
858 get_base_reg (XVECEXP (XEXP (x
,0), 0, 0)));
859 return microblaze_classify_unspec (info
, XEXP (x
, 0));
861 return !(flag_pic
&& pic_address_needs_scratch (x
));
866 else if (microblaze_tls_symbol_p(x
))
874 if (reload_in_progress
)
875 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
876 return microblaze_classify_unspec (info
, x
);
886 /* This function is used to implement GO_IF_LEGITIMATE_ADDRESS. It
887 returns a nonzero value if X is a legitimate address for a memory
888 operand of the indicated MODE. STRICT is nonzero if this function
889 is called during reload. */
892 microblaze_legitimate_address_p (machine_mode mode
, rtx x
, bool strict
)
894 struct microblaze_address_info addr
;
896 return microblaze_classify_address (&addr
, x
, mode
, strict
);
900 microblaze_valid_pic_const (rtx x
)
902 switch (GET_CODE (x
))
914 microblaze_legitimate_pic_operand (rtx x
)
916 if (flag_pic
== 2 && (symbol_mentioned_p(x
) || label_mentioned_p(x
)))
919 if (microblaze_tls_referenced_p(x
))
925 /* Try machine-dependent ways of modifying an illegitimate address
926 to be legitimate. If we find one, return the new, valid address.
927 This is used from only one place: `memory_address' in explow.c.
929 OLDX is the address as it was before break_out_memory_refs was
930 called. In some cases it is useful to look at this to decide what
933 It is always safe for this function to do nothing. It exists to
934 recognize opportunities to optimize the output.
936 For the MicroBlaze, transform:
938 memory(X + <large int>)
942 Y = <large int> & ~0x7fff;
944 memory (Z + (<large int> & 0x7fff));
946 This is for CSE to find several similar references, and only use one Z.
948 When PIC, convert addresses of the form memory (symbol+large int) to
949 memory (reg+large int). */
952 microblaze_legitimize_address (rtx x
, rtx oldx ATTRIBUTE_UNUSED
,
953 machine_mode mode ATTRIBUTE_UNUSED
)
955 register rtx xinsn
= x
, result
;
957 if (GET_CODE (xinsn
) == CONST
958 && flag_pic
&& pic_address_needs_scratch (xinsn
))
960 rtx ptr_reg
= gen_reg_rtx (Pmode
);
961 rtx constant
= XEXP (XEXP (xinsn
, 0), 1);
963 emit_move_insn (ptr_reg
, XEXP (XEXP (xinsn
, 0), 0));
965 result
= gen_rtx_PLUS (Pmode
, ptr_reg
, constant
);
966 if (SMALL_INT (constant
))
968 /* Otherwise we fall through so the code below will fix the
973 if (GET_CODE (xinsn
) == PLUS
)
975 register rtx xplus0
= XEXP (xinsn
, 0);
976 register rtx xplus1
= XEXP (xinsn
, 1);
977 register enum rtx_code code0
= GET_CODE (xplus0
);
978 register enum rtx_code code1
= GET_CODE (xplus1
);
980 if (code0
!= REG
&& code1
== REG
)
982 xplus0
= XEXP (xinsn
, 1);
983 xplus1
= XEXP (xinsn
, 0);
984 code0
= GET_CODE (xplus0
);
985 code1
= GET_CODE (xplus1
);
988 if (code0
== REG
&& REG_OK_FOR_BASE_P (xplus0
)
989 && code1
== CONST_INT
&& !SMALL_INT (xplus1
))
991 rtx int_reg
= gen_reg_rtx (Pmode
);
992 rtx ptr_reg
= gen_reg_rtx (Pmode
);
994 emit_move_insn (int_reg
, GEN_INT (INTVAL (xplus1
) & ~0x7fff));
996 emit_insn (gen_rtx_SET (ptr_reg
,
997 gen_rtx_PLUS (Pmode
, xplus0
, int_reg
)));
999 result
= gen_rtx_PLUS (Pmode
, ptr_reg
,
1000 GEN_INT (INTVAL (xplus1
) & 0x7fff));
1004 if (code0
== REG
&& REG_OK_FOR_BASE_P (xplus0
))
1006 if (reload_in_progress
)
1007 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
1010 xplus1
= XEXP (xplus1
, 0);
1011 code1
= GET_CODE (xplus1
);
1013 if (code1
== SYMBOL_REF
)
1015 if (microblaze_tls_symbol_p(xplus1
))
1018 reg
= gen_reg_rtx (Pmode
);
1020 tls_ref
= microblaze_legitimize_tls_address (xplus1
,
1022 emit_move_insn (reg
, tls_ref
);
1024 result
= gen_rtx_PLUS (Pmode
, xplus0
, reg
);
1028 else if (flag_pic
== 2)
1031 reg
= gen_reg_rtx (Pmode
);
1033 pic_ref
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, xplus1
),
1035 pic_ref
= gen_rtx_CONST (Pmode
, pic_ref
);
1036 pic_ref
= gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
, pic_ref
);
1037 pic_ref
= gen_const_mem (Pmode
, pic_ref
);
1038 emit_move_insn (reg
, pic_ref
);
1039 result
= gen_rtx_PLUS (Pmode
, xplus0
, reg
);
1046 if (GET_CODE (xinsn
) == SYMBOL_REF
)
1049 if (microblaze_tls_symbol_p(xinsn
))
1051 reg
= microblaze_legitimize_tls_address (xinsn
, NULL_RTX
);
1057 if (reload_in_progress
)
1058 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
1060 pic_ref
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, xinsn
), UNSPEC_GOTOFF
);
1061 pic_ref
= gen_rtx_CONST (Pmode
, pic_ref
);
1062 pic_ref
= gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
, pic_ref
);
1063 pic_ref
= gen_const_mem (Pmode
, pic_ref
);
1074 #define MAX_MOVE_REGS 8
1075 #define MAX_MOVE_BYTES (MAX_MOVE_REGS * UNITS_PER_WORD)
1077 /* Emit straight-line code to move LENGTH bytes from SRC to DEST.
1078 Assume that the areas do not overlap. */
1081 microblaze_block_move_straight (rtx dest
, rtx src
, HOST_WIDE_INT length
)
1083 HOST_WIDE_INT offset
, delta
;
1084 unsigned HOST_WIDE_INT bits
;
1089 bits
= BITS_PER_WORD
;
1090 mode
= mode_for_size (bits
, MODE_INT
, 0);
1091 delta
= bits
/ BITS_PER_UNIT
;
1093 /* Allocate a buffer for the temporary registers. */
1094 regs
= XALLOCAVEC (rtx
, length
/ delta
);
1096 /* Load as many BITS-sized chunks as possible. Use a normal load if
1097 the source has enough alignment, otherwise use left/right pairs. */
1098 for (offset
= 0, i
= 0; offset
+ delta
<= length
; offset
+= delta
, i
++)
1100 regs
[i
] = gen_reg_rtx (mode
);
1101 emit_move_insn (regs
[i
], adjust_address (src
, mode
, offset
));
1104 /* Copy the chunks to the destination. */
1105 for (offset
= 0, i
= 0; offset
+ delta
<= length
; offset
+= delta
, i
++)
1106 emit_move_insn (adjust_address (dest
, mode
, offset
), regs
[i
]);
1108 /* Mop up any left-over bytes. */
1109 if (offset
< length
)
1111 src
= adjust_address (src
, BLKmode
, offset
);
1112 dest
= adjust_address (dest
, BLKmode
, offset
);
1113 move_by_pieces (dest
, src
, length
- offset
,
1114 MIN (MEM_ALIGN (src
), MEM_ALIGN (dest
)), 0);
1118 /* Helper function for doing a loop-based block operation on memory
1119 reference MEM. Each iteration of the loop will operate on LENGTH
1122 Create a new base register for use within the loop and point it to
1123 the start of MEM. Create a new memory reference that uses this
1124 register. Store them in *LOOP_REG and *LOOP_MEM respectively. */
1127 microblaze_adjust_block_mem (rtx mem
, HOST_WIDE_INT length
,
1128 rtx
* loop_reg
, rtx
* loop_mem
)
1130 *loop_reg
= copy_addr_to_reg (XEXP (mem
, 0));
1132 /* Although the new mem does not refer to a known location,
1133 it does keep up to LENGTH bytes of alignment. */
1134 *loop_mem
= change_address (mem
, BLKmode
, *loop_reg
);
1135 set_mem_align (*loop_mem
,
1136 MIN ((HOST_WIDE_INT
) MEM_ALIGN (mem
),
1137 length
* BITS_PER_UNIT
));
1141 /* Move LENGTH bytes from SRC to DEST using a loop that moves MAX_MOVE_BYTES
1142 per iteration. LENGTH must be at least MAX_MOVE_BYTES. Assume that the
1143 memory regions do not overlap. */
1146 microblaze_block_move_loop (rtx dest
, rtx src
, HOST_WIDE_INT length
)
1148 rtx_code_label
*label
;
1149 rtx src_reg
, dest_reg
, final_src
;
1150 HOST_WIDE_INT leftover
;
1152 leftover
= length
% MAX_MOVE_BYTES
;
1155 /* Create registers and memory references for use within the loop. */
1156 microblaze_adjust_block_mem (src
, MAX_MOVE_BYTES
, &src_reg
, &src
);
1157 microblaze_adjust_block_mem (dest
, MAX_MOVE_BYTES
, &dest_reg
, &dest
);
1159 /* Calculate the value that SRC_REG should have after the last iteration
1161 final_src
= expand_simple_binop (Pmode
, PLUS
, src_reg
, GEN_INT (length
),
1164 /* Emit the start of the loop. */
1165 label
= gen_label_rtx ();
1168 /* Emit the loop body. */
1169 microblaze_block_move_straight (dest
, src
, MAX_MOVE_BYTES
);
1171 /* Move on to the next block. */
1172 emit_move_insn (src_reg
, plus_constant (Pmode
, src_reg
, MAX_MOVE_BYTES
));
1173 emit_move_insn (dest_reg
, plus_constant (Pmode
, dest_reg
, MAX_MOVE_BYTES
));
1175 /* Emit the test & branch. */
1176 emit_insn (gen_cbranchsi4 (gen_rtx_NE (SImode
, src_reg
, final_src
),
1177 src_reg
, final_src
, label
));
1179 /* Mop up any left-over bytes. */
1181 microblaze_block_move_straight (dest
, src
, leftover
);
1184 /* Expand a movmemsi instruction. */
1187 microblaze_expand_block_move (rtx dest
, rtx src
, rtx length
, rtx align_rtx
)
1190 if (GET_CODE (length
) == CONST_INT
)
1192 HOST_WIDE_INT bytes
= INTVAL (length
);
1193 int align
= INTVAL (align_rtx
);
1195 if (align
> UNITS_PER_WORD
)
1197 align
= UNITS_PER_WORD
; /* We can't do any better. */
1199 else if (align
< UNITS_PER_WORD
)
1201 if (INTVAL (length
) <= MAX_MOVE_BYTES
)
1203 move_by_pieces (dest
, src
, bytes
, align
, 0);
1210 if (INTVAL (length
) <= 2 * MAX_MOVE_BYTES
)
1212 microblaze_block_move_straight (dest
, src
, INTVAL (length
));
1217 microblaze_block_move_loop (dest
, src
, INTVAL (length
));
1225 microblaze_rtx_costs (rtx x
, machine_mode mode
, int outer_code ATTRIBUTE_UNUSED
,
1226 int opno ATTRIBUTE_UNUSED
, int *total
,
1227 bool speed ATTRIBUTE_UNUSED
)
1229 int code
= GET_CODE (x
);
1235 int num_words
= (GET_MODE_SIZE (mode
) > UNITS_PER_WORD
) ? 2 : 1;
1236 if (simple_memory_operand (x
, mode
))
1237 *total
= COSTS_N_INSNS (2 * num_words
);
1239 *total
= COSTS_N_INSNS (2 * (2 * num_words
));
1247 *total
= COSTS_N_INSNS (2);
1250 *total
= COSTS_N_INSNS (1);
1259 *total
= COSTS_N_INSNS (2);
1262 *total
= COSTS_N_INSNS (1);
1270 if (TARGET_BARREL_SHIFT
)
1272 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v5.00.a")
1274 *total
= COSTS_N_INSNS (1);
1276 *total
= COSTS_N_INSNS (2);
1278 else if (!TARGET_SOFT_MUL
)
1279 *total
= COSTS_N_INSNS (1);
1280 else if (GET_CODE (XEXP (x
, 1)) == CONST_INT
)
1282 /* Add 1 to make shift slightly more expensive than add. */
1283 *total
= COSTS_N_INSNS (INTVAL (XEXP (x
, 1))) + 1;
1284 /* Reduce shift costs for special circumstances. */
1285 if (optimize_size
&& INTVAL (XEXP (x
, 1)) > 5)
1287 if (!optimize_size
&& INTVAL (XEXP (x
, 1)) > 17)
1291 /* Double the worst cost of shifts when there is no barrel shifter and
1292 the shift amount is in a reg. */
1293 *total
= COSTS_N_INSNS (32 * 4);
1299 if (mode
== SFmode
|| mode
== DFmode
)
1301 if (TARGET_HARD_FLOAT
)
1302 *total
= COSTS_N_INSNS (6);
1305 else if (mode
== DImode
)
1307 *total
= COSTS_N_INSNS (4);
1312 *total
= COSTS_N_INSNS (1);
1321 *total
= COSTS_N_INSNS (4);
1329 if (TARGET_HARD_FLOAT
)
1330 *total
= COSTS_N_INSNS (6);
1332 else if (!TARGET_SOFT_MUL
)
1334 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v5.00.a")
1336 *total
= COSTS_N_INSNS (1);
1338 *total
= COSTS_N_INSNS (3);
1341 *total
= COSTS_N_INSNS (10);
1349 if (TARGET_HARD_FLOAT
)
1350 *total
= COSTS_N_INSNS (23);
1356 *total
= COSTS_N_INSNS (1);
1361 *total
= COSTS_N_INSNS (1);
1369 /* Return the number of instructions needed to load or store a value
1370 of mode MODE at X. Return 0 if X isn't valid for MODE. */
1373 microblaze_address_insns (rtx x
, machine_mode mode
)
1375 struct microblaze_address_info addr
;
1377 if (microblaze_classify_address (&addr
, x
, mode
, false))
1382 if (SMALL_INT (addr
.offset
))
1386 case ADDRESS_CONST_INT
:
1391 case ADDRESS_REG_INDEX
:
1393 case ADDRESS_SYMBOLIC
:
1394 case ADDRESS_GOTOFF
:
1397 switch (addr
.tls_type
)
1415 /* Provide the costs of an addressing mode that contains ADDR.
1416 If ADDR is not a valid address, its cost is irrelevant. */
1418 microblaze_address_cost (rtx addr
, machine_mode mode ATTRIBUTE_UNUSED
,
1419 addr_space_t as ATTRIBUTE_UNUSED
,
1420 bool speed ATTRIBUTE_UNUSED
)
1422 return COSTS_N_INSNS (microblaze_address_insns (addr
, GET_MODE (addr
)));
1425 /* Return nonzero if X is an address which needs a temporary register when
1426 reloaded while generating PIC code. */
1429 pic_address_needs_scratch (rtx x
)
1431 if (GET_CODE (x
) == CONST
&& GET_CODE (XEXP (x
,0)) == PLUS
)
1435 p0
= XEXP (XEXP (x
, 0), 0);
1436 p1
= XEXP (XEXP (x
, 0), 1);
1438 if ((GET_CODE (p0
) == SYMBOL_REF
|| GET_CODE (p0
) == LABEL_REF
)
1439 && (GET_CODE (p1
) == CONST_INT
)
1440 && (flag_pic
== 2 || microblaze_tls_symbol_p (p0
) || !SMALL_INT (p1
)))
1446 /* Argument support functions. */
1447 /* Initialize CUMULATIVE_ARGS for a function. */
1450 init_cumulative_args (CUMULATIVE_ARGS
* cum
, tree fntype
,
1451 rtx libname ATTRIBUTE_UNUSED
)
1453 static CUMULATIVE_ARGS zero_cum
;
1454 tree param
, next_param
;
1458 /* Determine if this function has variable arguments. This is
1459 indicated by the last argument being 'void_type_mode' if there
1460 are no variable arguments. The standard MicroBlaze calling sequence
1461 passes all arguments in the general purpose registers in this case. */
1463 for (param
= fntype
? TYPE_ARG_TYPES (fntype
) : 0;
1464 param
!= 0; param
= next_param
)
1466 next_param
= TREE_CHAIN (param
);
1467 if (next_param
== 0 && TREE_VALUE (param
) != void_type_node
)
1468 cum
->gp_reg_found
= 1;
1472 /* Advance the argument to the next argument position. */
1475 microblaze_function_arg_advance (cumulative_args_t cum_v
,
1477 const_tree type
, bool named ATTRIBUTE_UNUSED
)
1479 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
1488 gcc_assert (GET_MODE_CLASS (mode
) == MODE_COMPLEX_INT
1489 || GET_MODE_CLASS (mode
) == MODE_COMPLEX_FLOAT
);
1491 cum
->gp_reg_found
= 1;
1492 cum
->arg_words
+= ((GET_MODE_SIZE (mode
) + UNITS_PER_WORD
- 1)
1497 cum
->gp_reg_found
= 1;
1498 cum
->arg_words
+= ((int_size_in_bytes (type
) + UNITS_PER_WORD
- 1)
1504 if (!cum
->gp_reg_found
&& cum
->arg_number
<= 2)
1505 cum
->fp_code
+= 1 << ((cum
->arg_number
- 1) * 2);
1509 cum
->arg_words
+= 2;
1510 if (!cum
->gp_reg_found
&& cum
->arg_number
<= 2)
1511 cum
->fp_code
+= 2 << ((cum
->arg_number
- 1) * 2);
1515 cum
->gp_reg_found
= 1;
1516 cum
->arg_words
+= 2;
1523 cum
->gp_reg_found
= 1;
1529 /* Return an RTL expression containing the register for the given mode,
1530 or 0 if the argument is to be passed on the stack. */
1533 microblaze_function_arg (cumulative_args_t cum_v
, machine_mode mode
,
1534 const_tree type ATTRIBUTE_UNUSED
,
1535 bool named ATTRIBUTE_UNUSED
)
1537 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
1541 int *arg_words
= &cum
->arg_words
;
1543 cum
->last_arg_fp
= 0;
1554 regbase
= GP_ARG_FIRST
;
1557 gcc_assert (GET_MODE_CLASS (mode
) == MODE_COMPLEX_INT
1558 || GET_MODE_CLASS (mode
) == MODE_COMPLEX_FLOAT
);
1561 regbase
= GP_ARG_FIRST
;
1565 if (*arg_words
>= MAX_ARGS_IN_REGISTERS
)
1569 gcc_assert (regbase
!= -1);
1571 ret
= gen_rtx_REG (mode
, regbase
+ *arg_words
);
1574 if (mode
== VOIDmode
)
1576 if (cum
->num_adjusts
> 0)
1577 ret
= gen_rtx_PARALLEL ((machine_mode
) cum
->fp_code
,
1578 gen_rtvec_v (cum
->num_adjusts
, cum
->adjust
));
1584 /* Return number of bytes of argument to put in registers. */
1586 function_arg_partial_bytes (cumulative_args_t cum_v
, machine_mode mode
,
1587 tree type
, bool named ATTRIBUTE_UNUSED
)
1589 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
1591 if ((mode
== BLKmode
1592 || GET_MODE_CLASS (mode
) != MODE_COMPLEX_INT
1593 || GET_MODE_CLASS (mode
) != MODE_COMPLEX_FLOAT
)
1594 && cum
->arg_words
< MAX_ARGS_IN_REGISTERS
)
1597 if (mode
== BLKmode
)
1598 words
= ((int_size_in_bytes (type
) + UNITS_PER_WORD
- 1)
1601 words
= (GET_MODE_SIZE (mode
) + UNITS_PER_WORD
- 1) / UNITS_PER_WORD
;
1603 if (words
+ cum
->arg_words
<= MAX_ARGS_IN_REGISTERS
)
1604 return 0; /* structure fits in registers */
1606 return (MAX_ARGS_IN_REGISTERS
- cum
->arg_words
) * UNITS_PER_WORD
;
1609 else if (mode
== DImode
&& cum
->arg_words
== MAX_ARGS_IN_REGISTERS
- 1)
1610 return UNITS_PER_WORD
;
1615 /* Convert a version number of the form "vX.YY.Z" to an integer encoding
1616 for easier range comparison. */
1618 microblaze_version_to_int (const char *version
)
1621 const char *tmpl
= "vXX.YY.Z";
1630 { /* Looking for major */
1637 if (!(*p
>= '0' && *p
<= '9'))
1639 iver
+= (int) (*p
- '0');
1644 { /* Looking for minor */
1645 if (!(*p
>= '0' && *p
<= '9'))
1647 iver
+= (int) (*p
- '0');
1651 { /* Looking for compat */
1652 if (!(*p
>= 'a' && *p
<= 'z'))
1655 iver
+= (int) (*p
- 'a');
1675 microblaze_option_override (void)
1677 register int i
, start
;
1679 register machine_mode mode
;
1682 microblaze_section_threshold
= (global_options_set
.x_g_switch_value
1684 : MICROBLAZE_DEFAULT_GVALUE
);
1688 /* Make sure it's 2, we only support one kind of PIC. */
1690 if (!TARGET_SUPPORTS_PIC
)
1692 error ("-fPIC/-fpic not supported for this target");
1693 /* Clear it to avoid further errors. */
1698 /* Check the MicroBlaze CPU version for any special action to be done. */
1699 if (microblaze_select_cpu
== NULL
)
1700 microblaze_select_cpu
= MICROBLAZE_DEFAULT_CPU
;
1701 ver
= microblaze_version_to_int (microblaze_select_cpu
);
1704 error ("%qs is an invalid argument to -mcpu=", microblaze_select_cpu
);
1707 ver
= MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v3.00.a");
1710 /* No hardware exceptions in earlier versions. So no worries. */
1712 microblaze_select_flags
&= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY
);
1714 microblaze_no_unsafe_delay
= 0;
1715 microblaze_pipe
= MICROBLAZE_PIPE_3
;
1718 || (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v4.00.b")
1722 microblaze_select_flags
|= (MICROBLAZE_MASK_NO_UNSAFE_DELAY
);
1724 microblaze_no_unsafe_delay
= 1;
1725 microblaze_pipe
= MICROBLAZE_PIPE_3
;
1729 /* We agree to use 5 pipe-stage model even on area optimized 3
1730 pipe-stage variants. */
1732 microblaze_select_flags
&= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY
);
1734 microblaze_no_unsafe_delay
= 0;
1735 microblaze_pipe
= MICROBLAZE_PIPE_5
;
1736 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v5.00.a") == 0
1737 || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
,
1739 || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
,
1742 /* Pattern compares are to be turned on by default only when
1743 compiling for MB v5.00.'z'. */
1744 target_flags
|= MASK_PATTERN_COMPARE
;
1748 ver
= MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v6.00.a");
1751 if (TARGET_MULTIPLY_HIGH
)
1753 "-mxl-multiply-high can be used only with -mcpu=v6.00.a or greater");
1756 ver
= MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v8.10.a");
1757 microblaze_has_clz
= 1;
1760 /* MicroBlaze prior to 8.10.a didn't have clz. */
1761 microblaze_has_clz
= 0;
1764 /* TARGET_REORDER defaults to 2 if -mxl-reorder not specified. */
1765 ver
= MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v8.30.a");
1768 if (TARGET_REORDER
== 1)
1769 warning (0, "-mxl-reorder can be used only with -mcpu=v8.30.a or greater");
1772 else if ((ver
== 0) && !TARGET_PATTERN_COMPARE
)
1774 if (TARGET_REORDER
== 1)
1775 warning (0, "-mxl-reorder requires -mxl-pattern-compare for -mcpu=v8.30.a");
1779 if (TARGET_MULTIPLY_HIGH
&& TARGET_SOFT_MUL
)
1780 error ("-mxl-multiply-high requires -mno-xl-soft-mul");
1782 /* Always use DFA scheduler. */
1783 microblaze_sched_use_dfa
= 1;
1786 microblaze_abicalls
= MICROBLAZE_ABICALLS_NO
;
1789 /* Initialize the high, low values for legit floating point constants. */
1790 real_maxval (&dfhigh
, 0, DFmode
);
1791 real_maxval (&dflow
, 1, DFmode
);
1792 real_maxval (&sfhigh
, 0, SFmode
);
1793 real_maxval (&sflow
, 1, SFmode
);
1795 microblaze_print_operand_punct
['?'] = 1;
1796 microblaze_print_operand_punct
['#'] = 1;
1797 microblaze_print_operand_punct
['&'] = 1;
1798 microblaze_print_operand_punct
['!'] = 1;
1799 microblaze_print_operand_punct
['*'] = 1;
1800 microblaze_print_operand_punct
['@'] = 1;
1801 microblaze_print_operand_punct
['.'] = 1;
1802 microblaze_print_operand_punct
['('] = 1;
1803 microblaze_print_operand_punct
[')'] = 1;
1804 microblaze_print_operand_punct
['['] = 1;
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;
1814 /* Set up array to map GCC register number to debug register number.
1815 Ignore the special purpose register numbers. */
1817 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
1818 microblaze_dbx_regno
[i
] = -1;
1820 start
= GP_DBX_FIRST
- GP_REG_FIRST
;
1821 for (i
= GP_REG_FIRST
; i
<= GP_REG_LAST
; i
++)
1822 microblaze_dbx_regno
[i
] = i
+ start
;
1824 /* Set up array giving whether a given register can hold a given mode. */
1826 for (mode
= VOIDmode
;
1827 mode
!= MAX_MACHINE_MODE
; mode
= (machine_mode
) ((int) mode
+ 1))
1829 register int size
= GET_MODE_SIZE (mode
);
1831 for (regno
= 0; regno
< FIRST_PSEUDO_REGISTER
; regno
++)
1837 ok
= (ST_REG_P (regno
) || GP_REG_P (regno
));
1839 else if (GP_REG_P (regno
))
1840 ok
= ((regno
& 1) == 0 || size
<= UNITS_PER_WORD
);
1844 microblaze_hard_regno_mode_ok
[(int) mode
][regno
] = ok
;
1849 /* Return true if FUNC is an interrupt function as specified
1850 by the "interrupt_handler" attribute. */
1853 microblaze_interrupt_function_p (tree func
)
1857 if (TREE_CODE (func
) != FUNCTION_DECL
)
1860 a
= lookup_attribute ("interrupt_handler", DECL_ATTRIBUTES (func
));
1861 return a
!= NULL_TREE
;
1865 microblaze_fast_interrupt_function_p (tree func
)
1869 if (TREE_CODE (func
) != FUNCTION_DECL
)
1872 a
= lookup_attribute ("fast_interrupt", DECL_ATTRIBUTES (func
));
1873 return a
!= NULL_TREE
;
1876 microblaze_break_function_p (tree func
)
1881 if (TREE_CODE (func
) != FUNCTION_DECL
)
1884 a
= lookup_attribute ("break_handler", DECL_ATTRIBUTES (func
));
1885 return a
!= NULL_TREE
;
1887 /* Return true if FUNC is an interrupt function which uses
1888 normal return, indicated by the "save_volatiles" attribute. */
1891 microblaze_save_volatiles (tree func
)
1895 if (TREE_CODE (func
) != FUNCTION_DECL
)
1898 a
= lookup_attribute ("save_volatiles", DECL_ATTRIBUTES (func
));
1899 return a
!= NULL_TREE
;
1902 /* Return whether function is tagged with 'interrupt_handler'
1903 or 'fast_interrupt' attribute. Return true if function
1904 should use return from interrupt rather than normal
1907 microblaze_is_interrupt_variant (void)
1909 return (interrupt_handler
|| fast_interrupt
);
1912 microblaze_is_break_handler (void)
1914 return break_handler
;
1917 /* Determine of register must be saved/restored in call. */
1919 microblaze_must_save_register (int regno
)
1921 if (pic_offset_table_rtx
&&
1922 (regno
== MB_ABI_PIC_ADDR_REGNUM
) && df_regs_ever_live_p (regno
))
1925 if (df_regs_ever_live_p (regno
) && !call_used_regs
[regno
])
1928 if (frame_pointer_needed
&& (regno
== HARD_FRAME_POINTER_REGNUM
))
1931 if (crtl
->calls_eh_return
1932 && regno
== MB_ABI_SUB_RETURN_ADDR_REGNUM
)
1937 if (regno
== MB_ABI_SUB_RETURN_ADDR_REGNUM
)
1939 if ((microblaze_is_interrupt_variant () || save_volatiles
) &&
1940 (regno
>= 3 && regno
<= 12))
1944 if (microblaze_is_interrupt_variant ())
1946 if (df_regs_ever_live_p (regno
)
1947 || regno
== MB_ABI_MSR_SAVE_REG
1948 || (interrupt_handler
1949 && (regno
== MB_ABI_ASM_TEMP_REGNUM
1950 || regno
== MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM
)))
1956 if (df_regs_ever_live_p (regno
)
1957 || regno
== MB_ABI_ASM_TEMP_REGNUM
1958 || regno
== MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM
)
1962 if (crtl
->calls_eh_return
1963 && (regno
== EH_RETURN_DATA_REGNO (0)
1964 || regno
== EH_RETURN_DATA_REGNO (1)))
1970 /* Return the bytes needed to compute the frame pointer from the current
1973 MicroBlaze stack frames look like:
1977 Before call After call
1978 +-----------------------+ +-----------------------+
1980 mem. | local variables, | | local variables, |
1981 | callee saved and | | callee saved and |
1983 +-----------------------+ +-----------------------+
1984 | arguments for called | | arguments for called |
1985 | subroutines | | subroutines |
1986 | (optional) | | (optional) |
1987 +-----------------------+ +-----------------------+
1988 | Link register | | Link register |
1990 +-----------------------+ +-----------------------+
1992 | local variables, |
1993 | callee saved and |
1995 +-----------------------+
1996 | MSR (optional if, |
1997 | interrupt handler) |
1998 +-----------------------+
2000 | alloca allocations |
2002 +-----------------------+
2004 | arguments for called |
2008 +-----------------------+
2011 memory +-----------------------+
2015 static HOST_WIDE_INT
2016 compute_frame_size (HOST_WIDE_INT size
)
2019 HOST_WIDE_INT total_size
; /* # bytes that the entire frame takes up. */
2020 HOST_WIDE_INT var_size
; /* # bytes that local variables take up. */
2021 HOST_WIDE_INT args_size
; /* # bytes that outgoing arguments take up. */
2022 int link_debug_size
; /* # bytes for link register. */
2023 HOST_WIDE_INT gp_reg_size
; /* # bytes needed to store calle-saved gp regs. */
2024 long mask
; /* mask of saved gp registers. */
2027 microblaze_interrupt_function_p (current_function_decl
);
2029 microblaze_break_function_p (current_function_decl
);
2032 microblaze_fast_interrupt_function_p (current_function_decl
);
2033 save_volatiles
= microblaze_save_volatiles (current_function_decl
);
2035 interrupt_handler
= break_handler
;
2040 args_size
= crtl
->outgoing_args_size
;
2042 if ((args_size
== 0) && cfun
->calls_alloca
)
2043 args_size
= NUM_OF_ARGS
* UNITS_PER_WORD
;
2045 total_size
= var_size
+ args_size
;
2048 /* force setting GOT. */
2049 df_set_regs_ever_live (MB_ABI_PIC_ADDR_REGNUM
, true);
2051 /* Calculate space needed for gp registers. */
2052 for (regno
= GP_REG_FIRST
; regno
<= GP_REG_LAST
; regno
++)
2054 if (microblaze_must_save_register (regno
))
2057 if (regno
!= MB_ABI_SUB_RETURN_ADDR_REGNUM
)
2058 /* Don't account for link register. It is accounted specially below. */
2059 gp_reg_size
+= GET_MODE_SIZE (SImode
);
2061 mask
|= (1L << (regno
- GP_REG_FIRST
));
2065 total_size
+= gp_reg_size
;
2067 /* Add 4 bytes for MSR. */
2068 if (microblaze_is_interrupt_variant ())
2071 /* No space to be allocated for link register in leaf functions with no other
2072 stack requirements. */
2073 if (total_size
== 0 && crtl
->is_leaf
)
2074 link_debug_size
= 0;
2076 link_debug_size
= UNITS_PER_WORD
;
2078 total_size
+= link_debug_size
;
2080 /* Save other computed information. */
2081 current_frame_info
.total_size
= total_size
;
2082 current_frame_info
.var_size
= var_size
;
2083 current_frame_info
.args_size
= args_size
;
2084 current_frame_info
.gp_reg_size
= gp_reg_size
;
2085 current_frame_info
.mask
= mask
;
2086 current_frame_info
.initialized
= reload_completed
;
2087 current_frame_info
.num_gp
= gp_reg_size
/ UNITS_PER_WORD
;
2088 current_frame_info
.link_debug_size
= link_debug_size
;
2091 /* Offset from which to callee-save GP regs. */
2092 current_frame_info
.gp_offset
= (total_size
- gp_reg_size
);
2094 current_frame_info
.gp_offset
= 0;
2096 /* Ok, we're done. */
2100 /* Make sure that we're not trying to eliminate to the wrong hard frame
2104 microblaze_can_eliminate (const int from
, const int to
)
2106 return ((from
== RETURN_ADDRESS_POINTER_REGNUM
&& !leaf_function_p())
2107 || (to
== MB_ABI_SUB_RETURN_ADDR_REGNUM
&& leaf_function_p())
2108 || (from
!= RETURN_ADDRESS_POINTER_REGNUM
2109 && (to
== HARD_FRAME_POINTER_REGNUM
2110 || (to
== STACK_POINTER_REGNUM
&& !frame_pointer_needed
))));
2113 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
2114 pointer or argument pointer or the return address pointer. TO is either
2115 the stack pointer or hard frame pointer. */
2118 microblaze_initial_elimination_offset (int from
, int to
)
2120 HOST_WIDE_INT offset
;
2124 case FRAME_POINTER_REGNUM
:
2127 case ARG_POINTER_REGNUM
:
2128 if (to
== STACK_POINTER_REGNUM
|| to
== HARD_FRAME_POINTER_REGNUM
)
2129 offset
= compute_frame_size (get_frame_size ());
2133 case RETURN_ADDRESS_POINTER_REGNUM
:
2137 offset
= current_frame_info
.gp_offset
+
2138 ((UNITS_PER_WORD
- (POINTER_SIZE
/ BITS_PER_UNIT
)));
2146 /* Print operands using format code.
2148 The MicroBlaze specific codes are:
2150 'X' X is CONST_INT, prints 32 bits in hexadecimal format = "0x%08x",
2151 'x' X is CONST_INT, prints 16 bits in hexadecimal format = "0x%04x",
2152 'F' op is CONST_DOUBLE, print 32 bits in hex,
2153 'd' output integer constant in decimal,
2154 'z' if the operand is 0, use $0 instead of normal operand.
2155 'D' print second register of double-word register operand.
2156 'L' print low-order register of double-word register operand.
2157 'M' print high-order register of double-word register operand.
2158 'C' print part of opcode for a branch condition.
2159 'N' print part of opcode for a branch condition, inverted.
2160 'S' X is CODE_LABEL, print with prefix of "LS" (for embedded switch).
2161 'B' print 'z' for EQ, 'n' for NE
2162 'b' print 'n' for EQ, 'z' for NE
2163 'T' print 'f' for EQ, 't' for NE
2164 't' print 't' for EQ, 'f' for NE
2165 'm' Print 1<<operand.
2166 'i' Print 'i' if MEM operand has immediate value
2167 'y' Print 'y' if MEM operand is single register
2168 'o' Print operand address+4
2169 '?' Print 'd' if we use a branch with delay slot instead of normal branch.
2170 'h' Print high word of const_double (int or float) value as hex
2171 'j' Print low word of const_double (int or float) value as hex
2172 's' Print -1 if operand is negative, 0 if positive (sign extend)
2173 '@' Print the name of the temporary register (rMB_ABI_ASM_TEMP_REGNUM).
2174 '#' Print nop if the delay slot of a branch is not filled.
2178 print_operand (FILE * file
, rtx op
, int letter
)
2180 register enum rtx_code code
;
2182 if (PRINT_OPERAND_PUNCT_VALID_P (letter
))
2187 /* Conditionally add a 'd' to indicate filled delay slot. */
2188 if (final_sequence
!= NULL
)
2193 /* Conditionally add a nop in unfilled delay slot. */
2194 if (final_sequence
== NULL
)
2195 fputs ("nop\t\t# Unfilled delay slot\n", file
);
2199 fputs (reg_names
[GP_REG_FIRST
+ MB_ABI_ASM_TEMP_REGNUM
], file
);
2203 output_operand_lossage ("unknown punctuation '%c'", letter
);
2212 output_operand_lossage ("null pointer");
2216 code
= GET_CODE (op
);
2218 if (code
== SIGN_EXTEND
)
2219 op
= XEXP (op
, 0), code
= GET_CODE (op
);
2247 fatal_insn ("PRINT_OPERAND, invalid insn for %%C", op
);
2250 else if (letter
== 'N')
2276 fatal_insn ("PRINT_OPERAND, invalid insn for %%N", op
);
2279 else if (letter
== 'S')
2283 ASM_GENERATE_INTERNAL_LABEL (buffer
, "LS", CODE_LABEL_NUMBER (op
));
2284 assemble_name (file
, buffer
);
2287 /* Print 'i' for memory operands which have immediate values. */
2288 else if (letter
== 'i')
2292 struct microblaze_address_info info
;
2294 if (!microblaze_classify_address
2295 (&info
, XEXP (op
, 0), GET_MODE (op
), 1))
2296 fatal_insn ("insn contains an invalid address !", op
);
2301 case ADDRESS_CONST_INT
:
2302 case ADDRESS_SYMBOLIC
:
2303 case ADDRESS_GOTOFF
:
2307 case ADDRESS_REG_INDEX
:
2309 case ADDRESS_INVALID
:
2311 fatal_insn ("invalid address", op
);
2316 else if (code
== REG
|| code
== SUBREG
)
2318 register int regnum
;
2321 regnum
= REGNO (op
);
2323 regnum
= true_regnum (op
);
2325 if ((letter
== 'M' && !WORDS_BIG_ENDIAN
)
2326 || (letter
== 'L' && WORDS_BIG_ENDIAN
) || letter
== 'D')
2329 fprintf (file
, "%s", reg_names
[regnum
]);
2332 else if (code
== MEM
)
2335 rtx op4
= adjust_address (op
, GET_MODE (op
), 4);
2336 output_address (GET_MODE (op
), XEXP (op4
, 0));
2338 else if (letter
== 'y')
2340 rtx mem_reg
= XEXP (op
, 0);
2341 if (GET_CODE (mem_reg
) == REG
)
2343 register int regnum
= REGNO (mem_reg
);
2344 fprintf (file
, "%s", reg_names
[regnum
]);
2348 output_address (GET_MODE (op
), XEXP (op
, 0));
2350 else if (letter
== 'h' || letter
== 'j')
2353 if (code
== CONST_DOUBLE
)
2355 if (GET_MODE (op
) == DFmode
)
2356 REAL_VALUE_TO_TARGET_DOUBLE (*CONST_DOUBLE_REAL_VALUE (op
), val
);
2359 val
[0] = CONST_DOUBLE_HIGH (op
);
2360 val
[1] = CONST_DOUBLE_LOW (op
);
2363 else if (code
== CONST_INT
)
2365 val
[0] = (INTVAL (op
) & 0xffffffff00000000LL
) >> 32;
2366 val
[1] = INTVAL (op
) & 0x00000000ffffffffLL
;
2367 if (val
[0] == 0 && val
[1] < 0)
2371 fprintf (file
, "0x%8.8lx", (letter
== 'h') ? val
[0] : val
[1]);
2373 else if (code
== CONST_DOUBLE
)
2377 unsigned long value_long
;
2378 REAL_VALUE_TO_TARGET_SINGLE (*CONST_DOUBLE_REAL_VALUE (op
),
2380 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, value_long
);
2385 real_to_decimal (s
, CONST_DOUBLE_REAL_VALUE (op
), sizeof (s
), 0, 1);
2390 else if (code
== UNSPEC
)
2392 print_operand_address (file
, op
);
2395 else if (letter
== 'x' && GET_CODE (op
) == CONST_INT
)
2396 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, 0xffff & INTVAL (op
));
2398 else if (letter
== 'X' && GET_CODE (op
) == CONST_INT
)
2399 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, INTVAL (op
));
2401 else if (letter
== 'd' && GET_CODE (op
) == CONST_INT
)
2402 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, (INTVAL (op
)));
2404 else if (letter
== 'z' && GET_CODE (op
) == CONST_INT
&& INTVAL (op
) == 0)
2405 fputs (reg_names
[GP_REG_FIRST
], file
);
2407 else if (letter
== 's' && GET_CODE (op
) == CONST_INT
)
2408 if (INTVAL (op
) < 0)
2413 else if (letter
== 'd' || letter
== 'x' || letter
== 'X' || letter
== 's')
2414 output_operand_lossage ("letter %c was found & insn was not CONST_INT", letter
);
2416 else if (letter
== 'B')
2417 fputs (code
== EQ
? "z" : "n", file
);
2418 else if (letter
== 'b')
2419 fputs (code
== EQ
? "n" : "z", file
);
2420 else if (letter
== 'T')
2421 fputs (code
== EQ
? "f" : "t", file
);
2422 else if (letter
== 't')
2423 fputs (code
== EQ
? "t" : "f", file
);
2425 else if (code
== CONST
2426 && ((GET_CODE (XEXP (op
, 0)) == REG
)
2427 || (GET_CODE (XEXP (op
, 0)) == UNSPEC
)))
2429 print_operand (file
, XEXP (op
, 0), letter
);
2431 else if (code
== CONST
2432 && (GET_CODE (XEXP (op
, 0)) == PLUS
)
2433 && (GET_CODE (XEXP (XEXP (op
, 0), 0)) == REG
)
2434 && (GET_CODE (XEXP (XEXP (op
, 0), 1)) == CONST
))
2436 print_operand_address (file
, XEXP (op
, 0));
2438 else if (letter
== 'm')
2439 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, (1L << INTVAL (op
)));
2441 output_addr_const (file
, op
);
2444 /* A C compound statement to output to stdio stream STREAM the
2445 assembler syntax for an instruction operand that is a memory
2446 reference whose address is ADDR. ADDR is an RTL expression.
2448 Possible address classifications and output formats are,
2450 ADDRESS_REG "%0, r0"
2452 ADDRESS_REG with non-zero "%0, <addr_const>"
2455 ADDRESS_REG_INDEX "rA, RB"
2456 (if rA is r0, rA and rB are swapped)
2458 ADDRESS_CONST_INT "r0, <addr_const>"
2460 ADDRESS_SYMBOLIC "rBase, <addr_const>"
2461 (rBase is a base register suitable for the
2466 print_operand_address (FILE * file
, rtx addr
)
2468 struct microblaze_address_info info
;
2469 enum microblaze_address_type type
;
2470 if (!microblaze_classify_address (&info
, addr
, GET_MODE (addr
), 1))
2471 fatal_insn ("insn contains an invalid address !", addr
);
2477 fprintf (file
, "%s,", reg_names
[REGNO (info
.regA
)]);
2478 output_addr_const (file
, info
.offset
);
2480 case ADDRESS_REG_INDEX
:
2481 if (REGNO (info
.regA
) == 0)
2482 /* Make rB == r0 instead of rA == r0. This helps reduce read port
2484 fprintf (file
, "%s,%s", reg_names
[REGNO (info
.regB
)],
2485 reg_names
[REGNO (info
.regA
)]);
2486 else if (REGNO (info
.regB
) != 0)
2487 /* This is a silly swap to help Dhrystone. */
2488 fprintf (file
, "%s,%s", reg_names
[REGNO (info
.regB
)],
2489 reg_names
[REGNO (info
.regA
)]);
2491 case ADDRESS_CONST_INT
:
2492 fprintf (file
, "%s,", reg_names
[REGNO (info
.regA
)]);
2493 output_addr_const (file
, info
.offset
);
2495 case ADDRESS_SYMBOLIC
:
2496 case ADDRESS_GOTOFF
:
2500 fprintf (file
, "%s,", reg_names
[REGNO (info
.regA
)]);
2501 output_addr_const (file
, info
.symbol
);
2502 if (type
== ADDRESS_GOTOFF
)
2504 fputs ("@GOT", file
);
2506 else if (type
== ADDRESS_PLT
)
2508 fputs ("@PLT", file
);
2510 else if (type
== ADDRESS_TLS
)
2512 switch (info
.tls_type
)
2515 fputs ("@TLSGD", file
);
2518 fputs ("@TLSLDM", file
);
2521 fputs ("@TLSDTPREL", file
);
2529 case ADDRESS_INVALID
:
2530 fatal_insn ("invalid address", addr
);
2535 /* Emit either a label, .comm, or .lcomm directive, and mark that the symbol
2536 is used, so that we don't emit an .extern for it in
2537 microblaze_asm_file_end. */
2540 microblaze_declare_object (FILE * stream
, const char *name
,
2541 const char *section
, const char *fmt
, int size
)
2544 fputs (section
, stream
);
2545 assemble_name (stream
, name
);
2546 fprintf (stream
, fmt
, size
);
2549 /* Common code to emit the insns (or to write the instructions to a file)
2550 to save/restore registers.
2552 Other parts of the code assume that MICROBLAZE_TEMP1_REGNUM (aka large_reg)
2553 is not modified within save_restore_insns. */
2555 #define BITSET_P(VALUE,BIT) (((VALUE) & (1L << (BIT))) != 0)
2557 /* Save or restore instructions based on whether this is the prologue or
2558 epilogue. prologue is 1 for the prologue. */
2560 save_restore_insns (int prologue
)
2562 rtx base_reg_rtx
, reg_rtx
, mem_rtx
, /* msr_rtx, */ isr_reg_rtx
=
2564 rtx isr_msr_rtx
= 0, insn
;
2565 long mask
= current_frame_info
.mask
;
2566 HOST_WIDE_INT gp_offset
;
2569 if (frame_pointer_needed
2570 && !BITSET_P (mask
, HARD_FRAME_POINTER_REGNUM
- GP_REG_FIRST
))
2576 /* Save registers starting from high to low. The debuggers prefer at least
2577 the return register be stored at func+4, and also it allows us not to
2578 need a nop in the epilog if at least one register is reloaded in
2579 addition to return address. */
2581 /* Pick which pointer to use as a base register. For small frames, just
2582 use the stack pointer. Otherwise, use a temporary register. Save 2
2583 cycles if the save area is near the end of a large frame, by reusing
2584 the constant created in the prologue/epilogue to adjust the stack
2587 gp_offset
= current_frame_info
.gp_offset
;
2589 gcc_assert (gp_offset
> 0);
2591 base_reg_rtx
= stack_pointer_rtx
;
2593 /* For interrupt_handlers, need to save/restore the MSR. */
2594 if (microblaze_is_interrupt_variant ())
2596 isr_mem_rtx
= gen_rtx_MEM (SImode
,
2597 gen_rtx_PLUS (Pmode
, base_reg_rtx
,
2598 GEN_INT (current_frame_info
.
2602 /* Do not optimize in flow analysis. */
2603 MEM_VOLATILE_P (isr_mem_rtx
) = 1;
2604 isr_reg_rtx
= gen_rtx_REG (SImode
, MB_ABI_MSR_SAVE_REG
);
2605 isr_msr_rtx
= gen_rtx_REG (SImode
, ST_REG
);
2608 if (microblaze_is_interrupt_variant () && !prologue
)
2610 emit_move_insn (isr_reg_rtx
, isr_mem_rtx
);
2611 emit_move_insn (isr_msr_rtx
, isr_reg_rtx
);
2612 /* Do not optimize in flow analysis. */
2613 emit_insn (gen_rtx_USE (SImode
, isr_reg_rtx
));
2614 emit_insn (gen_rtx_USE (SImode
, isr_msr_rtx
));
2617 for (regno
= GP_REG_FIRST
; regno
<= GP_REG_LAST
; regno
++)
2619 if (BITSET_P (mask
, regno
- GP_REG_FIRST
))
2621 if (regno
== MB_ABI_SUB_RETURN_ADDR_REGNUM
)
2622 /* Don't handle here. Already handled as the first register. */
2625 reg_rtx
= gen_rtx_REG (SImode
, regno
);
2626 insn
= gen_rtx_PLUS (Pmode
, base_reg_rtx
, GEN_INT (gp_offset
));
2627 mem_rtx
= gen_rtx_MEM (SImode
, insn
);
2628 if (microblaze_is_interrupt_variant () || save_volatiles
)
2629 /* Do not optimize in flow analysis. */
2630 MEM_VOLATILE_P (mem_rtx
) = 1;
2634 insn
= emit_move_insn (mem_rtx
, reg_rtx
);
2635 RTX_FRAME_RELATED_P (insn
) = 1;
2639 insn
= emit_move_insn (reg_rtx
, mem_rtx
);
2642 gp_offset
+= GET_MODE_SIZE (SImode
);
2646 if (microblaze_is_interrupt_variant () && prologue
)
2648 emit_move_insn (isr_reg_rtx
, isr_msr_rtx
);
2649 emit_move_insn (isr_mem_rtx
, isr_reg_rtx
);
2651 /* Do not optimize in flow analysis. */
2652 emit_insn (gen_rtx_USE (SImode
, isr_reg_rtx
));
2653 emit_insn (gen_rtx_USE (SImode
, isr_msr_rtx
));
2656 /* Done saving and restoring */
2660 /* Set up the stack and frame (if desired) for the function. */
2662 microblaze_function_prologue (FILE * file
)
2665 long fsiz
= current_frame_info
.total_size
;
2667 /* Get the function name the same way that toplev.c does before calling
2668 assemble_start_function. This is needed so that the name used here
2669 exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */
2670 fnname
= XSTR (XEXP (DECL_RTL (current_function_decl
), 0), 0);
2671 if (!flag_inhibit_size_directive
)
2673 fputs ("\t.ent\t", file
);
2674 if (interrupt_handler
&& strcmp (INTERRUPT_HANDLER_NAME
, fnname
))
2675 fputs ("_interrupt_handler", file
);
2676 else if (break_handler
&& strcmp (BREAK_HANDLER_NAME
, fnname
))
2677 fputs ("_break_handler", file
);
2678 else if (fast_interrupt
&& strcmp (FAST_INTERRUPT_NAME
, fnname
))
2679 fputs ("_fast_interrupt", file
);
2681 assemble_name (file
, fnname
);
2683 if (!microblaze_is_interrupt_variant ())
2684 ASM_OUTPUT_TYPE_DIRECTIVE (file
, fnname
, "function");
2687 assemble_name (file
, fnname
);
2688 fputs (":\n", file
);
2690 if (interrupt_handler
&& strcmp (INTERRUPT_HANDLER_NAME
, fnname
))
2691 fputs ("_interrupt_handler:\n", file
);
2692 if (break_handler
&& strcmp (BREAK_HANDLER_NAME
, fnname
))
2693 fputs ("_break_handler:\n", file
);
2694 if (!flag_inhibit_size_directive
)
2696 /* .frame FRAMEREG, FRAMESIZE, RETREG. */
2698 "\t.frame\t%s,%ld,%s\t\t# vars= %ld, regs= %d, args= %d\n",
2699 (reg_names
[(frame_pointer_needed
)
2700 ? HARD_FRAME_POINTER_REGNUM
:
2701 STACK_POINTER_REGNUM
]), fsiz
,
2702 reg_names
[MB_ABI_SUB_RETURN_ADDR_REGNUM
+ GP_REG_FIRST
],
2703 current_frame_info
.var_size
, current_frame_info
.num_gp
,
2704 crtl
->outgoing_args_size
);
2705 fprintf (file
, "\t.mask\t0x%08lx\n", current_frame_info
.mask
);
2709 /* Output extra assembler code at the end of a prologue. */
2711 microblaze_function_end_prologue (FILE * file
)
2713 if (TARGET_STACK_CHECK
)
2715 fprintf (file
, "\t# Stack Check Stub -- Start.\n\t");
2716 fprintf (file
, "ori\tr18,r0,_stack_end\n\t");
2717 fprintf (file
, "cmpu\tr18,r1,r18\n\t");
2718 fprintf (file
, "bgei\tr18,_stack_overflow_exit\n\t");
2719 fprintf (file
, "# Stack Check Stub -- End.\n");
2724 microblaze_elf_asm_cdtor (rtx symbol
, int priority
, bool is_ctor
)
2728 if (priority
!= DEFAULT_INIT_PRIORITY
)
2731 sprintf (buf
, "%s.%.5u",
2732 is_ctor
? ".ctors" : ".dtors",
2733 MAX_INIT_PRIORITY
- priority
);
2734 s
= get_section (buf
, SECTION_WRITE
, NULL_TREE
);
2741 switch_to_section (s
);
2742 assemble_align (POINTER_SIZE
);
2743 fputs ("\t.word\t", asm_out_file
);
2744 output_addr_const (asm_out_file
, symbol
);
2745 fputs ("\n", asm_out_file
);
2748 /* Add a function to the list of static constructors. */
2751 microblaze_elf_asm_constructor (rtx symbol
, int priority
)
2753 microblaze_elf_asm_cdtor (symbol
, priority
, /*is_ctor=*/true);
2756 /* Add a function to the list of static destructors. */
2759 microblaze_elf_asm_destructor (rtx symbol
, int priority
)
2761 microblaze_elf_asm_cdtor (symbol
, priority
, /*is_ctor=*/false);
2764 /* Expand the prologue into a bunch of separate insns. */
2767 microblaze_expand_prologue (void)
2771 const char *arg_name
= 0;
2772 tree fndecl
= current_function_decl
;
2773 tree fntype
= TREE_TYPE (fndecl
);
2774 tree fnargs
= DECL_ARGUMENTS (fndecl
);
2779 CUMULATIVE_ARGS args_so_far_v
;
2780 cumulative_args_t args_so_far
;
2781 rtx mem_rtx
, reg_rtx
;
2783 /* If struct value address is treated as the first argument, make it so. */
2784 if (aggregate_value_p (DECL_RESULT (fndecl
), fntype
)
2785 && !cfun
->returns_pcc_struct
)
2787 tree type
= build_pointer_type (fntype
);
2788 tree function_result_decl
= build_decl (BUILTINS_LOCATION
, PARM_DECL
,
2791 DECL_ARG_TYPE (function_result_decl
) = type
;
2792 TREE_CHAIN (function_result_decl
) = fnargs
;
2793 fnargs
= function_result_decl
;
2796 /* Determine the last argument, and get its name. */
2798 INIT_CUMULATIVE_ARGS (args_so_far_v
, fntype
, NULL_RTX
, 0, 0);
2799 args_so_far
= pack_cumulative_args (&args_so_far_v
);
2800 regno
= GP_ARG_FIRST
;
2802 for (cur_arg
= fnargs
; cur_arg
!= 0; cur_arg
= next_arg
)
2804 tree passed_type
= DECL_ARG_TYPE (cur_arg
);
2805 machine_mode passed_mode
= TYPE_MODE (passed_type
);
2808 if (TREE_ADDRESSABLE (passed_type
))
2810 passed_type
= build_pointer_type (passed_type
);
2811 passed_mode
= Pmode
;
2814 entry_parm
= targetm
.calls
.function_arg (args_so_far
, passed_mode
,
2821 /* passed in a register, so will get homed automatically. */
2822 if (GET_MODE (entry_parm
) == BLKmode
)
2823 words
= (int_size_in_bytes (passed_type
) + 3) / 4;
2825 words
= (GET_MODE_SIZE (GET_MODE (entry_parm
)) + 3) / 4;
2827 regno
= REGNO (entry_parm
) + words
- 1;
2831 regno
= GP_ARG_LAST
+ 1;
2835 targetm
.calls
.function_arg_advance (args_so_far
, passed_mode
,
2838 next_arg
= TREE_CHAIN (cur_arg
);
2841 if (DECL_NAME (cur_arg
))
2842 arg_name
= IDENTIFIER_POINTER (DECL_NAME (cur_arg
));
2848 /* Split parallel insn into a sequence of insns. */
2850 next_arg_reg
= targetm
.calls
.function_arg (args_so_far
, VOIDmode
,
2851 void_type_node
, true);
2852 if (next_arg_reg
!= 0 && GET_CODE (next_arg_reg
) == PARALLEL
)
2854 rtvec adjust
= XVEC (next_arg_reg
, 0);
2855 int num
= GET_NUM_ELEM (adjust
);
2857 for (i
= 0; i
< num
; i
++)
2859 rtx pattern
= RTVEC_ELT (adjust
, i
);
2860 emit_insn (pattern
);
2864 fsiz
= compute_frame_size (get_frame_size ());
2866 if (flag_stack_usage_info
)
2867 current_function_static_stack_size
= fsiz
;
2870 /* If this function is a varargs function, store any registers that
2871 would normally hold arguments ($5 - $10) on the stack. */
2872 if (((TYPE_ARG_TYPES (fntype
) != 0
2873 && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype
)))
2876 && ((arg_name
[0] == '_'
2877 && strcmp (arg_name
, "__builtin_va_alist") == 0)
2878 || (arg_name
[0] == 'v'
2879 && strcmp (arg_name
, "va_alist") == 0)))))
2881 int offset
= (regno
- GP_ARG_FIRST
+ 1) * UNITS_PER_WORD
;
2882 rtx ptr
= stack_pointer_rtx
;
2884 /* If we are doing svr4-abi, sp has already been decremented by fsiz. */
2885 for (; regno
<= GP_ARG_LAST
; regno
++)
2888 ptr
= gen_rtx_PLUS (Pmode
, stack_pointer_rtx
, GEN_INT (offset
));
2889 emit_move_insn (gen_rtx_MEM (SImode
, ptr
),
2890 gen_rtx_REG (SImode
, regno
));
2892 offset
+= GET_MODE_SIZE (SImode
);
2899 rtx fsiz_rtx
= GEN_INT (fsiz
);
2901 rtx_insn
*insn
= NULL
;
2902 insn
= emit_insn (gen_subsi3 (stack_pointer_rtx
, stack_pointer_rtx
,
2905 RTX_FRAME_RELATED_P (insn
) = 1;
2907 /* Handle SUB_RETURN_ADDR_REGNUM specially at first. */
2908 if (!crtl
->is_leaf
|| interrupt_handler
)
2910 mem_rtx
= gen_rtx_MEM (SImode
,
2911 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
2914 if (interrupt_handler
)
2915 /* Do not optimize in flow analysis. */
2916 MEM_VOLATILE_P (mem_rtx
) = 1;
2918 reg_rtx
= gen_rtx_REG (SImode
, MB_ABI_SUB_RETURN_ADDR_REGNUM
);
2919 insn
= emit_move_insn (mem_rtx
, reg_rtx
);
2920 RTX_FRAME_RELATED_P (insn
) = 1;
2923 /* _save_ registers for prologue. */
2924 save_restore_insns (1);
2926 if (frame_pointer_needed
)
2930 insn
= emit_insn (gen_movsi (hard_frame_pointer_rtx
,
2931 stack_pointer_rtx
));
2934 RTX_FRAME_RELATED_P (insn
) = 1;
2938 if ((flag_pic
== 2 || TLS_NEEDS_GOT
)
2939 && df_regs_ever_live_p (MB_ABI_PIC_ADDR_REGNUM
))
2941 SET_REGNO (pic_offset_table_rtx
, MB_ABI_PIC_ADDR_REGNUM
);
2942 emit_insn (gen_set_got (pic_offset_table_rtx
)); /* setting GOT. */
2945 /* If we are profiling, make sure no instructions are scheduled before
2946 the call to mcount. */
2949 emit_insn (gen_blockage ());
2952 /* Do necessary cleanup after a function to restore stack, frame, and regs. */
2954 #define RA_MASK ((long) 0x80000000) /* 1 << 31 */
2955 #define PIC_OFFSET_TABLE_MASK (1 << (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST))
2958 microblaze_function_epilogue (FILE *file
)
2962 /* Get the function name the same way that toplev.c does before calling
2963 assemble_start_function. This is needed so that the name used here
2964 exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */
2965 fnname
= XSTR (XEXP (DECL_RTL (current_function_decl
), 0), 0);
2967 if (!flag_inhibit_size_directive
)
2969 fputs ("\t.end\t", file
);
2970 if (interrupt_handler
&& !break_handler
)
2971 fputs ("_interrupt_handler", file
);
2972 else if (break_handler
)
2973 fputs ("_break_handler", file
);
2975 assemble_name (file
, fnname
);
2979 /* Reset state info for each function. */
2980 current_frame_info
= zero_frame_info
;
2982 /* Restore the output file if optimizing the GP (optimizing the GP causes
2983 the text to be diverted to a tempfile, so that data decls come before
2984 references to the data). */
2987 /* Expand the epilogue into a bunch of separate insns. */
2990 microblaze_expand_epilogue (void)
2992 HOST_WIDE_INT fsiz
= current_frame_info
.total_size
;
2993 rtx fsiz_rtx
= GEN_INT (fsiz
);
2997 /* In case of interrupt handlers use addki instead of addi for changing the
2998 stack pointer value. */
3000 if (microblaze_can_use_return_insn ())
3002 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode
,
3004 MB_ABI_SUB_RETURN_ADDR_REGNUM
)));
3010 /* Restore SUB_RETURN_ADDR_REGNUM at first. This is to prevent the
3011 sequence of load-followed by a use (in rtsd) in every prologue. Saves
3012 a load-use stall cycle :) This is also important to handle alloca.
3013 (See comments for if (frame_pointer_needed) below. */
3015 if (!crtl
->is_leaf
|| interrupt_handler
)
3018 gen_rtx_MEM (SImode
,
3019 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
, const0_rtx
));
3020 if (interrupt_handler
)
3021 /* Do not optimize in flow analysis. */
3022 MEM_VOLATILE_P (mem_rtx
) = 1;
3023 reg_rtx
= gen_rtx_REG (SImode
, MB_ABI_SUB_RETURN_ADDR_REGNUM
);
3024 emit_move_insn (reg_rtx
, mem_rtx
);
3027 /* It is important that this is done after we restore the return address
3028 register (above). When alloca is used, we want to restore the
3029 sub-routine return address only from the current stack top and not
3030 from the frame pointer (which we restore below). (frame_pointer + 0)
3031 might have been over-written since alloca allocates memory on the
3033 if (frame_pointer_needed
)
3034 emit_insn (gen_movsi (stack_pointer_rtx
, hard_frame_pointer_rtx
));
3036 /* _restore_ registers for epilogue. */
3037 save_restore_insns (0);
3038 emit_insn (gen_blockage ());
3039 emit_insn (gen_addsi3 (stack_pointer_rtx
, stack_pointer_rtx
, fsiz_rtx
));
3042 if (crtl
->calls_eh_return
)
3043 emit_insn (gen_addsi3 (stack_pointer_rtx
,
3045 gen_raw_REG (SImode
,
3046 MB_EH_STACKADJ_REGNUM
)));
3048 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode
, GP_REG_FIRST
+
3049 MB_ABI_SUB_RETURN_ADDR_REGNUM
)));
3053 /* Return nonzero if this function is known to have a null epilogue.
3054 This allows the optimizer to omit jumps to jumps if no stack
3058 microblaze_can_use_return_insn (void)
3060 if (!reload_completed
)
3063 if (df_regs_ever_live_p (MB_ABI_SUB_RETURN_ADDR_REGNUM
) || profile_flag
)
3066 if (current_frame_info
.initialized
)
3067 return current_frame_info
.total_size
== 0;
3069 return compute_frame_size (get_frame_size ()) == 0;
3072 /* Implement TARGET_SECONDARY_RELOAD. */
3075 microblaze_secondary_reload (bool in_p ATTRIBUTE_UNUSED
, rtx x ATTRIBUTE_UNUSED
,
3076 reg_class_t rclass
, machine_mode mode ATTRIBUTE_UNUSED
,
3077 secondary_reload_info
*sri ATTRIBUTE_UNUSED
)
3079 if (rclass
== ST_REGS
)
3086 microblaze_globalize_label (FILE * stream
, const char *name
)
3088 fputs ("\t.globl\t", stream
);
3089 if (microblaze_is_interrupt_variant ())
3091 if (interrupt_handler
&& strcmp (name
, INTERRUPT_HANDLER_NAME
))
3092 fputs (INTERRUPT_HANDLER_NAME
, stream
);
3093 else if (break_handler
&& strcmp (name
, BREAK_HANDLER_NAME
))
3094 fputs (BREAK_HANDLER_NAME
, stream
);
3095 else if (fast_interrupt
&& strcmp (name
, FAST_INTERRUPT_NAME
))
3096 fputs (FAST_INTERRUPT_NAME
, stream
);
3097 fputs ("\n\t.globl\t", stream
);
3099 assemble_name (stream
, name
);
3100 fputs ("\n", stream
);
3103 /* Returns true if decl should be placed into a "small data" section. */
3105 microblaze_elf_in_small_data_p (const_tree decl
)
3109 if (!TARGET_XLGPOPT
)
3112 /* We want to merge strings, so we never consider them small data. */
3113 if (TREE_CODE (decl
) == STRING_CST
)
3116 /* Functions are never in the small data area. */
3117 if (TREE_CODE (decl
) == FUNCTION_DECL
)
3120 if (TREE_CODE (decl
) == VAR_DECL
&& DECL_SECTION_NAME (decl
))
3122 const char *section
= DECL_SECTION_NAME (decl
);
3123 if (strcmp (section
, ".sdata") == 0
3124 || strcmp (section
, ".sdata2") == 0
3125 || strcmp (section
, ".sbss") == 0
3126 || strcmp (section
, ".sbss2") == 0)
3130 size
= int_size_in_bytes (TREE_TYPE (decl
));
3132 return (size
> 0 && size
<= microblaze_section_threshold
);
3137 microblaze_select_section (tree decl
, int reloc
, unsigned HOST_WIDE_INT align
)
3139 switch (categorize_decl_for_section (decl
, reloc
))
3141 case SECCAT_RODATA_MERGE_STR
:
3142 case SECCAT_RODATA_MERGE_STR_INIT
:
3143 /* MB binutils have various issues with mergeable string sections and
3144 relaxation/relocation. Currently, turning mergeable sections
3145 into regular readonly sections. */
3147 return readonly_data_section
;
3149 return default_elf_select_section (decl
, reloc
, align
);
3154 Encode info about sections into the RTL based on a symbol's declaration.
3155 The default definition of this hook, default_encode_section_info in
3156 `varasm.c', sets a number of commonly-useful bits in SYMBOL_REF_FLAGS. */
3159 microblaze_encode_section_info (tree decl
, rtx rtl
, int first
)
3161 default_encode_section_info (decl
, rtl
, first
);
3165 expand_pic_symbol_ref (machine_mode mode ATTRIBUTE_UNUSED
, rtx op
)
3168 result
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, op
), UNSPEC_GOTOFF
);
3169 result
= gen_rtx_CONST (Pmode
, result
);
3170 result
= gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
, result
);
3171 result
= gen_const_mem (Pmode
, result
);
3176 microblaze_asm_output_mi_thunk (FILE *file
, tree thunk_fndecl ATTRIBUTE_UNUSED
,
3177 HOST_WIDE_INT delta
, HOST_WIDE_INT vcall_offset
,
3180 rtx this_rtx
, funexp
;
3183 reload_completed
= 1;
3184 epilogue_completed
= 1;
3186 /* Mark the end of the (empty) prologue. */
3187 emit_note (NOTE_INSN_PROLOGUE_END
);
3189 /* Find the "this" pointer. If the function returns a structure,
3190 the structure return pointer is in MB_ABI_FIRST_ARG_REGNUM. */
3191 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function
)), function
))
3192 this_rtx
= gen_rtx_REG (Pmode
, (MB_ABI_FIRST_ARG_REGNUM
+ 1));
3194 this_rtx
= gen_rtx_REG (Pmode
, MB_ABI_FIRST_ARG_REGNUM
);
3196 /* Apply the constant offset, if required. */
3198 emit_insn (gen_addsi3 (this_rtx
, this_rtx
, GEN_INT (delta
)));
3200 /* Apply the offset from the vtable, if required. */
3203 rtx vcall_offset_rtx
= GEN_INT (vcall_offset
);
3204 rtx temp1
= gen_rtx_REG (Pmode
, MB_ABI_TEMP1_REGNUM
);
3206 emit_move_insn (temp1
, gen_rtx_MEM (Pmode
, this_rtx
));
3208 rtx loc
= gen_rtx_PLUS (Pmode
, temp1
, vcall_offset_rtx
);
3209 emit_move_insn (temp1
, gen_rtx_MEM (Pmode
, loc
));
3211 emit_insn (gen_addsi3 (this_rtx
, this_rtx
, temp1
));
3214 /* Generate a tail call to the target function. */
3215 if (!TREE_USED (function
))
3217 assemble_external (function
);
3218 TREE_USED (function
) = 1;
3221 funexp
= XEXP (DECL_RTL (function
), 0);
3222 rtx temp2
= gen_rtx_REG (Pmode
, MB_ABI_TEMP2_REGNUM
);
3225 emit_move_insn (temp2
, expand_pic_symbol_ref (Pmode
, funexp
));
3227 emit_move_insn (temp2
, funexp
);
3229 emit_insn (gen_indirect_jump (temp2
));
3231 /* Run just enough of rest_of_compilation. This sequence was
3232 "borrowed" from rs6000.c. */
3233 insn
= get_insns ();
3234 shorten_branches (insn
);
3235 final_start_function (insn
, file
, 1);
3236 final (insn
, file
, 1);
3237 final_end_function ();
3239 reload_completed
= 0;
3240 epilogue_completed
= 0;
3244 microblaze_expand_move (machine_mode mode
, rtx operands
[])
3251 if (!register_operand (op0
, SImode
)
3252 && !register_operand (op1
, SImode
)
3253 && (GET_CODE (op1
) != CONST_INT
|| INTVAL (op1
) != 0))
3255 rtx temp
= force_reg (SImode
, op1
);
3256 emit_move_insn (op0
, temp
);
3259 /* If operands[1] is a constant address invalid for pic, then we need to
3260 handle it just like LEGITIMIZE_ADDRESS does. */
3261 if (GET_CODE (op1
) == SYMBOL_REF
|| GET_CODE (op1
) == LABEL_REF
)
3264 if (microblaze_tls_symbol_p(op1
))
3266 result
= microblaze_legitimize_tls_address (op1
, NULL_RTX
);
3267 emit_move_insn (op0
, result
);
3272 if (reload_in_progress
)
3273 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
3274 result
= expand_pic_symbol_ref (mode
, op1
);
3275 emit_move_insn (op0
, result
);
3279 /* Handle Case of (const (plus symbol const_int)). */
3280 if (GET_CODE (op1
) == CONST
&& GET_CODE (XEXP (op1
,0)) == PLUS
)
3284 p0
= XEXP (XEXP (op1
, 0), 0);
3285 p1
= XEXP (XEXP (op1
, 0), 1);
3287 if ((GET_CODE (p1
) == CONST_INT
)
3288 && ((GET_CODE (p0
) == UNSPEC
)
3289 || ((GET_CODE (p0
) == SYMBOL_REF
|| GET_CODE (p0
) == LABEL_REF
)
3290 && (flag_pic
== 2 || microblaze_tls_symbol_p (p0
)
3291 || !SMALL_INT (p1
)))))
3293 rtx temp
= force_reg (SImode
, p0
);
3296 if (flag_pic
&& reload_in_progress
)
3297 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
3298 emit_move_insn (op0
, gen_rtx_PLUS (SImode
, temp
, temp2
));
3305 /* Expand shift operations. */
3307 microblaze_expand_shift (rtx operands
[])
3309 gcc_assert ((GET_CODE (operands
[2]) == CONST_INT
)
3310 || (GET_CODE (operands
[2]) == REG
)
3311 || (GET_CODE (operands
[2]) == SUBREG
));
3313 /* Shift by one -- generate pattern. */
3314 if ((GET_CODE (operands
[2]) == CONST_INT
) && (INTVAL (operands
[2]) == 1))
3317 /* Have barrel shifter and shift > 1: use it. */
3318 if (TARGET_BARREL_SHIFT
)
3321 gcc_assert ((GET_CODE (operands
[0]) == REG
)
3322 || (GET_CODE (operands
[0]) == SUBREG
)
3323 || (GET_CODE (operands
[1]) == REG
)
3324 || (GET_CODE (operands
[1]) == SUBREG
));
3326 /* Shift by zero -- copy regs if necessary. */
3327 if (operands
[2] == const0_rtx
3328 && !rtx_equal_p (operands
[0], operands
[1]))
3330 emit_insn (gen_movsi (operands
[0], operands
[1]));
3337 /* Return an RTX indicating where the return address to the
3338 calling function can be found. */
3340 microblaze_return_addr (int count
, rtx frame ATTRIBUTE_UNUSED
)
3345 return get_hard_reg_initial_val (Pmode
,
3346 MB_ABI_SUB_RETURN_ADDR_REGNUM
);
3350 microblaze_eh_return (rtx op0
)
3352 emit_insn (gen_movsi (gen_rtx_MEM (Pmode
, stack_pointer_rtx
), op0
));
3355 /* Queue an .ident string in the queue of top-level asm statements.
3356 If the string size is below the threshold, put it into .sdata2.
3357 If the front-end is done, we must be being called from toplev.c.
3358 In that case, do nothing. */
3360 microblaze_asm_output_ident (const char *string
)
3362 const char *section_asm_op
;
3366 if (symtab
->state
!= PARSING
)
3369 size
= strlen (string
) + 1;
3370 if (size
<= microblaze_section_threshold
)
3371 section_asm_op
= SDATA2_SECTION_ASM_OP
;
3373 section_asm_op
= READONLY_DATA_SECTION_ASM_OP
;
3375 buf
= ACONCAT ((section_asm_op
, "\n\t.ascii \"", string
, "\\0\"\n", NULL
));
3376 symtab
->finalize_toplevel_asm (build_string (strlen (buf
), buf
));
3380 microblaze_elf_asm_init_sections (void)
3383 = get_unnamed_section (SECTION_WRITE
, output_section_asm_op
,
3384 SDATA2_SECTION_ASM_OP
);
3387 /* Generate assembler code for constant parts of a trampoline. */
3390 microblaze_asm_trampoline_template (FILE *f
)
3392 fprintf (f
, "\tmfs r18, rpc\n");
3393 fprintf (f
, "\tlwi r3, r18, 16\n");
3394 fprintf (f
, "\tlwi r18, r18, 20\n");
3395 fprintf (f
, "\tbra r18\n");
3396 /* fprintf (f, "\t.word\t0x00000000\t\t# <function address>\n"); */
3397 /* fprintf (f, "\t.word\t0x00000000\t\t# <static chain value>\n"); */
3400 /* Implement TARGET_TRAMPOLINE_INIT. */
3403 microblaze_trampoline_init (rtx m_tramp
, tree fndecl
, rtx chain_value
)
3405 rtx fnaddr
= XEXP (DECL_RTL (fndecl
), 0);
3408 emit_block_move (m_tramp
, assemble_trampoline_template (),
3409 GEN_INT (6*UNITS_PER_WORD
), BLOCK_OP_NORMAL
);
3411 mem
= adjust_address (m_tramp
, SImode
, 16);
3412 emit_move_insn (mem
, chain_value
);
3413 mem
= adjust_address (m_tramp
, SImode
, 20);
3414 emit_move_insn (mem
, fnaddr
);
3417 /* Generate conditional branch -- first, generate test condition,
3418 second, generate correct branch instruction. */
3421 microblaze_expand_conditional_branch (machine_mode mode
, rtx operands
[])
3423 enum rtx_code code
= GET_CODE (operands
[0]);
3424 rtx cmp_op0
= operands
[1];
3425 rtx cmp_op1
= operands
[2];
3426 rtx label1
= operands
[3];
3427 rtx comp_reg
= gen_reg_rtx (SImode
);
3430 gcc_assert ((GET_CODE (cmp_op0
) == REG
) || (GET_CODE (cmp_op0
) == SUBREG
));
3432 /* If comparing against zero, just test source reg. */
3433 if (cmp_op1
== const0_rtx
)
3436 condition
= gen_rtx_fmt_ee (signed_condition (code
), SImode
, comp_reg
, const0_rtx
);
3437 emit_jump_insn (gen_condjump (condition
, label1
));
3440 else if (code
== EQ
|| code
== NE
)
3442 /* Use xor for equal/not-equal comparison. */
3443 emit_insn (gen_xorsi3 (comp_reg
, cmp_op0
, cmp_op1
));
3444 condition
= gen_rtx_fmt_ee (signed_condition (code
), SImode
, comp_reg
, const0_rtx
);
3445 emit_jump_insn (gen_condjump (condition
, label1
));
3449 /* Generate compare and branch in single instruction. */
3450 cmp_op1
= force_reg (mode
, cmp_op1
);
3451 condition
= gen_rtx_fmt_ee (code
, mode
, cmp_op0
, cmp_op1
);
3452 emit_jump_insn (gen_branch_compare(condition
, cmp_op0
, cmp_op1
, label1
));
3457 microblaze_expand_conditional_branch_reg (machine_mode mode
, rtx operands
[])
3459 enum rtx_code code
= GET_CODE (operands
[0]);
3460 rtx cmp_op0
= operands
[1];
3461 rtx cmp_op1
= operands
[2];
3462 rtx label1
= operands
[3];
3463 rtx comp_reg
= gen_reg_rtx (SImode
);
3466 gcc_assert ((GET_CODE (cmp_op0
) == REG
)
3467 || (GET_CODE (cmp_op0
) == SUBREG
));
3469 /* If comparing against zero, just test source reg. */
3470 if (cmp_op1
== const0_rtx
)
3473 condition
= gen_rtx_fmt_ee (signed_condition (code
),
3474 SImode
, comp_reg
, const0_rtx
);
3475 emit_jump_insn (gen_condjump (condition
, label1
));
3477 else if (code
== EQ
)
3479 emit_insn (gen_seq_internal_pat (comp_reg
,
3481 condition
= gen_rtx_EQ (SImode
, comp_reg
, const0_rtx
);
3482 emit_jump_insn (gen_condjump (condition
, label1
));
3484 else if (code
== NE
)
3486 emit_insn (gen_sne_internal_pat (comp_reg
, cmp_op0
,
3488 condition
= gen_rtx_NE (SImode
, comp_reg
, const0_rtx
);
3489 emit_jump_insn (gen_condjump (condition
, label1
));
3493 /* Generate compare and branch in single instruction. */
3494 cmp_op1
= force_reg (mode
, cmp_op1
);
3495 condition
= gen_rtx_fmt_ee (code
, mode
, cmp_op0
, cmp_op1
);
3496 emit_jump_insn (gen_branch_compare (condition
, cmp_op0
,
3502 microblaze_expand_conditional_branch_sf (rtx operands
[])
3505 rtx cmp_op0
= XEXP (operands
[0], 0);
3506 rtx cmp_op1
= XEXP (operands
[0], 1);
3507 rtx comp_reg
= gen_reg_rtx (SImode
);
3509 emit_insn (gen_cstoresf4 (comp_reg
, operands
[0], cmp_op0
, cmp_op1
));
3510 condition
= gen_rtx_NE (SImode
, comp_reg
, const0_rtx
);
3511 emit_jump_insn (gen_condjump (condition
, operands
[3]));
3514 /* Implement TARGET_FRAME_POINTER_REQUIRED. */
3517 microblaze_frame_pointer_required (void)
3519 /* If the function contains dynamic stack allocations, we need to
3520 use the frame pointer to access the static parts of the frame. */
3521 if (cfun
->calls_alloca
)
3527 microblaze_expand_divide (rtx operands
[])
3529 /* Table lookup software divides. Works for all (nr/dr) where (0 <= nr,dr <= 15). */
3531 rtx regt1
= gen_reg_rtx (SImode
);
3532 rtx reg18
= gen_rtx_REG (SImode
, R_TMP
);
3533 rtx regqi
= gen_reg_rtx (QImode
);
3534 rtx_code_label
*div_label
= gen_label_rtx ();
3535 rtx_code_label
*div_end_label
= gen_label_rtx ();
3536 rtx div_table_rtx
= gen_rtx_SYMBOL_REF (QImode
,"_divsi3_table");
3539 rtx_insn
*jump
, *cjump
, *insn
;
3541 insn
= emit_insn (gen_iorsi3 (regt1
, operands
[1], operands
[2]));
3542 cjump
= emit_jump_insn_after (gen_cbranchsi4 (
3543 gen_rtx_GTU (SImode
, regt1
, GEN_INT (15)),
3544 regt1
, GEN_INT (15), div_label
), insn
);
3545 LABEL_NUSES (div_label
) = 1;
3546 JUMP_LABEL (cjump
) = div_label
;
3547 emit_insn (gen_rtx_CLOBBER (SImode
, reg18
));
3549 emit_insn (gen_ashlsi3_bshift (regt1
, operands
[1], GEN_INT(4)));
3550 emit_insn (gen_addsi3 (regt1
, regt1
, operands
[2]));
3551 mem_rtx
= gen_rtx_MEM (QImode
,
3552 gen_rtx_PLUS (Pmode
, regt1
, div_table_rtx
));
3554 insn
= emit_insn (gen_movqi (regqi
, mem_rtx
));
3555 insn
= emit_insn (gen_movsi (operands
[0], gen_rtx_SUBREG (SImode
, regqi
, 0)));
3556 jump
= emit_jump_insn_after (gen_jump (div_end_label
), insn
);
3557 JUMP_LABEL (jump
) = div_end_label
;
3558 LABEL_NUSES (div_end_label
) = 1;
3561 emit_label (div_label
);
3562 ret
= emit_library_call_value (gen_rtx_SYMBOL_REF (Pmode
, "__divsi3"),
3563 operands
[0], LCT_NORMAL
,
3564 GET_MODE (operands
[0]),
3565 operands
[1], GET_MODE (operands
[1]),
3566 operands
[2], GET_MODE (operands
[2]));
3567 if (ret
!= operands
[0])
3568 emit_move_insn (operands
[0], ret
);
3570 emit_label (div_end_label
);
3571 emit_insn (gen_blockage ());
3574 /* Implement TARGET_FUNCTION_VALUE. */
3576 microblaze_function_value (const_tree valtype
,
3577 const_tree func ATTRIBUTE_UNUSED
,
3578 bool outgoing ATTRIBUTE_UNUSED
)
3580 return LIBCALL_VALUE (TYPE_MODE (valtype
));
3583 /* Implement TARGET_SCHED_ADJUST_COST. */
3585 microblaze_adjust_cost (rtx_insn
*, int dep_type
, rtx_insn
*, int cost
,
3588 if (dep_type
== REG_DEP_OUTPUT
|| dep_type
== 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 get_branch_target (rtx branch
)
3635 if (CALL_P (branch
))
3639 call
= XVECEXP (PATTERN (branch
), 0, 0);
3640 if (GET_CODE (call
) == SET
)
3641 call
= SET_SRC (call
);
3642 if (GET_CODE (call
) != CALL
)
3644 return XEXP (XEXP (call
, 0), 0);
3650 /* Heuristics to identify where to insert at the
3651 fall through path of the caller function. If there
3652 is a call after the caller branch delay slot then
3653 we dont generate the instruction prefetch instruction.
3655 Scan up to 32 instructions after the call and checks
3656 for the JUMP and call instruction . If there is a call
3657 or JUMP instruction in the range of 32 instruction "wic"
3658 instruction wont be generated. Otherwise insert the "wic"
3659 instruction in the fall through of the call instruction
3660 four instruction after the call. before_4 is used for
3661 the position to insert "wic" instructions. before_16 is
3662 used to check for call and JUMP instruction for first
3666 insert_wic_for_ilb_runout (rtx_insn
*first
)
3669 rtx_insn
*before_4
= 0;
3670 rtx_insn
*before_16
= 0;
3671 int addr_offset
= 0;
3673 int wic_addr0
= 128 * 4;
3675 int first_addr
= INSN_ADDRESSES (INSN_UID (first
));
3677 for (insn
= first
; insn
; insn
= NEXT_INSN (insn
))
3680 addr_offset
= INSN_ADDRESSES (INSN_UID (insn
)) - first_addr
;
3681 length
= get_attr_length (insn
);
3682 if (before_4
== 0 && addr_offset
+ length
>= 4 * 4)
3687 if (before_16
== 0 && addr_offset
+ length
>= 14 * 4)
3689 if (CALL_P (insn
) || tablejump_p (insn
, 0, 0))
3691 if (addr_offset
+ length
>= 32 * 4)
3693 gcc_assert (before_4
&& before_16
);
3694 if (wic_addr0
> 4 * 4)
3697 emit_insn_before (gen_iprefetch
3698 (gen_int_mode (addr_offset
, SImode
)),
3700 recog_memoized (insn
);
3701 INSN_LOCATION (insn
) = INSN_LOCATION (before_4
);
3702 INSN_ADDRESSES_NEW (insn
, INSN_ADDRESSES (INSN_UID (before_4
)));
3709 /* Insert instruction prefetch instruction at the fall
3710 through path of the function call. */
3717 basic_block bb
, prev
= 0;
3718 rtx branch_target
= 0;
3720 shorten_branches (get_insns ());
3722 for (i
= 0; i
< n_basic_blocks_for_fn (cfun
) - 1; i
++)
3726 bool simple_loop
= false;
3728 bb
= BASIC_BLOCK_FOR_FN (cfun
, i
);
3733 if ((prev
!= 0) && (prev
!= bb
))
3738 FOR_EACH_EDGE (e
, ei
, bb
->preds
)
3746 for (insn
= BB_END (bb
); insn
; insn
= PREV_INSN (insn
))
3748 if (INSN_P (insn
) && !simple_loop
3751 if ((branch_target
= get_branch_target (insn
)))
3752 insert_wic_for_ilb_runout (
3753 next_active_insn (next_active_insn (insn
)));
3755 if (insn
== BB_HEAD (bb
))
3761 /* The reorg function defined through the macro
3762 TARGET_MACHINE_DEPENDENT_REORG. */
3765 microblaze_machine_dependent_reorg (void)
3767 if (TARGET_PREFETCH
)
3769 compute_bb_for_insn ();
3770 loop_optimizer_init (AVOID_CFG_MODIFICATIONS
);
3771 shorten_branches (get_insns ());
3773 loop_optimizer_finalize ();
3774 free_bb_for_insn ();
3779 #undef TARGET_ENCODE_SECTION_INFO
3780 #define TARGET_ENCODE_SECTION_INFO microblaze_encode_section_info
3782 #undef TARGET_ASM_GLOBALIZE_LABEL
3783 #define TARGET_ASM_GLOBALIZE_LABEL microblaze_globalize_label
3785 #undef TARGET_ASM_FUNCTION_PROLOGUE
3786 #define TARGET_ASM_FUNCTION_PROLOGUE microblaze_function_prologue
3788 #undef TARGET_ASM_FUNCTION_EPILOGUE
3789 #define TARGET_ASM_FUNCTION_EPILOGUE microblaze_function_epilogue
3791 #undef TARGET_RTX_COSTS
3792 #define TARGET_RTX_COSTS microblaze_rtx_costs
3794 #undef TARGET_CANNOT_FORCE_CONST_MEM
3795 #define TARGET_CANNOT_FORCE_CONST_MEM microblaze_cannot_force_const_mem
3797 #undef TARGET_ADDRESS_COST
3798 #define TARGET_ADDRESS_COST microblaze_address_cost
3800 #undef TARGET_ATTRIBUTE_TABLE
3801 #define TARGET_ATTRIBUTE_TABLE microblaze_attribute_table
3803 #undef TARGET_IN_SMALL_DATA_P
3804 #define TARGET_IN_SMALL_DATA_P microblaze_elf_in_small_data_p
3806 #undef TARGET_ASM_SELECT_SECTION
3807 #define TARGET_ASM_SELECT_SECTION microblaze_select_section
3809 #undef TARGET_HAVE_SRODATA_SECTION
3810 #define TARGET_HAVE_SRODATA_SECTION true
3812 #undef TARGET_ASM_FUNCTION_END_PROLOGUE
3813 #define TARGET_ASM_FUNCTION_END_PROLOGUE \
3814 microblaze_function_end_prologue
3816 #undef TARGET_ARG_PARTIAL_BYTES
3817 #define TARGET_ARG_PARTIAL_BYTES function_arg_partial_bytes
3819 #undef TARGET_FUNCTION_ARG
3820 #define TARGET_FUNCTION_ARG microblaze_function_arg
3822 #undef TARGET_FUNCTION_ARG_ADVANCE
3823 #define TARGET_FUNCTION_ARG_ADVANCE microblaze_function_arg_advance
3825 #undef TARGET_CAN_ELIMINATE
3826 #define TARGET_CAN_ELIMINATE microblaze_can_eliminate
3828 #undef TARGET_LEGITIMIZE_ADDRESS
3829 #define TARGET_LEGITIMIZE_ADDRESS microblaze_legitimize_address
3831 #undef TARGET_LEGITIMATE_ADDRESS_P
3832 #define TARGET_LEGITIMATE_ADDRESS_P microblaze_legitimate_address_p
3835 #define TARGET_LRA_P hook_bool_void_false
3837 #undef TARGET_FRAME_POINTER_REQUIRED
3838 #define TARGET_FRAME_POINTER_REQUIRED microblaze_frame_pointer_required
3840 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
3841 #define TARGET_ASM_TRAMPOLINE_TEMPLATE microblaze_asm_trampoline_template
3843 #undef TARGET_TRAMPOLINE_INIT
3844 #define TARGET_TRAMPOLINE_INIT microblaze_trampoline_init
3846 #undef TARGET_PROMOTE_FUNCTION_MODE
3847 #define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
3849 #undef TARGET_FUNCTION_VALUE
3850 #define TARGET_FUNCTION_VALUE microblaze_function_value
3852 #undef TARGET_SECONDARY_RELOAD
3853 #define TARGET_SECONDARY_RELOAD microblaze_secondary_reload
3855 #undef TARGET_ASM_OUTPUT_MI_THUNK
3856 #define TARGET_ASM_OUTPUT_MI_THUNK microblaze_asm_output_mi_thunk
3858 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
3859 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true
3861 #undef TARGET_SCHED_ADJUST_COST
3862 #define TARGET_SCHED_ADJUST_COST microblaze_adjust_cost
3864 #undef TARGET_ASM_INIT_SECTIONS
3865 #define TARGET_ASM_INIT_SECTIONS microblaze_elf_asm_init_sections
3867 #undef TARGET_OPTION_OVERRIDE
3868 #define TARGET_OPTION_OVERRIDE microblaze_option_override
3870 #undef TARGET_LEGITIMATE_CONSTANT_P
3871 #define TARGET_LEGITIMATE_CONSTANT_P microblaze_legitimate_constant_p
3873 #undef TARGET_MACHINE_DEPENDENT_REORG
3874 #define TARGET_MACHINE_DEPENDENT_REORG microblaze_machine_dependent_reorg
3876 struct gcc_target targetm
= TARGET_INITIALIZER
;
3878 #include "gt-microblaze.h"