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"
37 #include "diagnostic-core.h"
39 #include "stor-layout.h"
48 #include "insn-addr.h"
51 /* This file should be included last. */
52 #include "target-def.h"
54 #define MICROBLAZE_VERSION_COMPARE(VA,VB) strcasecmp (VA, VB)
56 /* Classifies an address.
63 A natural register or a register + const_int offset address.
64 The register satisfies microblaze_valid_base_register_p and the
65 offset is a const_arith_operand.
69 A natural register offset by the index contained in an index register. The base
70 register satisfies microblaze_valid_base_register_p and the index register
71 satisfies microblaze_valid_index_register_p
75 A signed 16/32-bit constant address.
79 A constant symbolic address or a (register + symbol). */
81 enum microblaze_address_type
98 enum microblaze_symbol_type
104 /* TLS Address Type. */
113 /* Classification of a MicroBlaze address. */
114 struct microblaze_address_info
116 enum microblaze_address_type type
;
117 rtx regA
; /* Contains valid values on ADDRESS_REG, ADDRESS_REG_INDEX,
119 rtx regB
; /* Contains valid values on ADDRESS_REG_INDEX. */
120 rtx offset
; /* Contains valid values on ADDRESS_CONST_INT and ADDRESS_REG. */
121 rtx symbol
; /* Contains valid values on ADDRESS_SYMBOLIC. */
122 enum microblaze_symbol_type symbol_type
;
123 enum tls_reloc tls_type
;
126 /* Structure to be filled in by compute_frame_size with register
127 save masks, and offsets for the current function. */
129 struct GTY(()) microblaze_frame_info
{
130 long total_size
; /* # bytes that the entire frame takes up. */
131 long var_size
; /* # bytes that variables take up. */
132 long args_size
; /* # bytes that outgoing arguments take up. */
133 int link_debug_size
; /* # bytes for the link reg and back pointer. */
134 int gp_reg_size
; /* # bytes needed to store gp regs. */
135 long gp_offset
; /* offset from new sp to store gp registers. */
136 long mask
; /* mask of saved gp registers. */
137 int initialized
; /* != 0 if frame size already calculated. */
138 int num_gp
; /* number of gp registers saved. */
139 long insns_len
; /* length of insns. */
140 int alloc_stack
; /* Flag to indicate if the current function
141 must not create stack space. (As an optimization). */
144 /* Global variables for machine-dependent things. */
146 /* Toggle which pipleline interface to use. */
147 static GTY(()) int microblaze_sched_use_dfa
= 0;
149 /* Threshold for data being put into the small data/bss area, instead
150 of the normal data area (references to the small data/bss area take
151 1 instruction, and use the global pointer, references to the normal
152 data area takes 2 instructions). */
153 int microblaze_section_threshold
= -1;
155 /* Prevent scheduling potentially exception causing instructions in
156 delay slots. -mcpu=v3.00.a or v4.00.a turns this on. */
157 int microblaze_no_unsafe_delay
;
159 /* Set to one if the targeted core has the CLZ insn. */
160 int microblaze_has_clz
= 0;
162 /* Which CPU pipeline do we use. We haven't really standardized on a CPU
163 version having only a particular type of pipeline. There can still be
164 options on the CPU to scale pipeline features up or down. :(
165 Bad Presentation (??), so we let the MD file rely on the value of
166 this variable instead Making PIPE_5 the default. It should be backward
167 optimal with PIPE_3 MicroBlazes. */
168 enum pipeline_type microblaze_pipe
= MICROBLAZE_PIPE_5
;
170 /* High and low marks for floating point values which we will accept
171 as legitimate constants for TARGET_LEGITIMATE_CONSTANT_P. These are
172 initialized in override_options. */
173 REAL_VALUE_TYPE dfhigh
, dflow
, sfhigh
, sflow
;
175 /* Array giving truth value on whether or not a given hard register
176 can support a given mode. */
177 char microblaze_hard_regno_mode_ok
[(int)MAX_MACHINE_MODE
]
178 [FIRST_PSEUDO_REGISTER
];
180 /* Current frame information calculated by compute_frame_size. */
181 struct microblaze_frame_info current_frame_info
;
183 /* Zero structure to initialize current_frame_info. */
184 struct microblaze_frame_info zero_frame_info
;
186 /* List of all MICROBLAZE punctuation characters used by print_operand. */
187 char microblaze_print_operand_punct
[256];
189 /* Map GCC register number to debugger register number. */
190 int microblaze_dbx_regno
[FIRST_PSEUDO_REGISTER
];
192 /* Map hard register number to register class. */
193 enum reg_class microblaze_regno_to_class
[] =
195 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
196 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
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 ST_REGS
, GR_REGS
, GR_REGS
, GR_REGS
206 /* MicroBlaze specific machine attributes.
207 interrupt_handler - Interrupt handler attribute to add interrupt prologue
208 and epilogue and use appropriate interrupt return.
209 save_volatiles - Similar to interrupt handler, but use normal return. */
210 int interrupt_handler
;
215 const struct attribute_spec microblaze_attribute_table
[] = {
216 /* name min_len, max_len, decl_req, type_req, fn_type, req_handler,
217 affects_type_identity */
218 {"interrupt_handler", 0, 0, true, false, false, NULL
,
220 {"break_handler", 0, 0, true, false, false, NULL
,
222 {"fast_interrupt", 0, 0, true, false, false, NULL
,
224 {"save_volatiles" , 0, 0, true, false, false, NULL
,
226 { NULL
, 0, 0, false, false, false, NULL
,
230 static int microblaze_interrupt_function_p (tree
);
232 static void microblaze_elf_asm_constructor (rtx
, int) ATTRIBUTE_UNUSED
;
233 static void microblaze_elf_asm_destructor (rtx
, int) ATTRIBUTE_UNUSED
;
235 section
*sdata2_section
;
238 #undef TARGET_HAVE_TLS
239 #define TARGET_HAVE_TLS true
242 /* Return truth value if a CONST_DOUBLE is ok to be a legitimate constant. */
244 microblaze_const_double_ok (rtx op
, machine_mode mode
)
248 if (GET_CODE (op
) != CONST_DOUBLE
)
251 if (GET_MODE (op
) == VOIDmode
)
254 if (mode
!= SFmode
&& mode
!= DFmode
)
257 if (op
== CONST0_RTX (mode
))
260 d
= *CONST_DOUBLE_REAL_VALUE (op
);
262 if (REAL_VALUE_ISNAN (d
))
265 if (REAL_VALUE_NEGATIVE (d
))
266 d
= real_value_negate (&d
);
270 if (real_less (&d
, &dfhigh
) && real_less (&dflow
, &d
))
275 if (real_less (&d
, &sfhigh
) && real_less (&sflow
, &d
))
282 /* Return truth value if a memory operand fits in a single instruction
283 (ie, register + small offset) or (register + register). */
286 simple_memory_operand (rtx op
, machine_mode mode ATTRIBUTE_UNUSED
)
288 rtx addr
, plus0
, plus1
;
290 /* Eliminate non-memory operations. */
291 if (GET_CODE (op
) != MEM
)
294 /* dword operations really put out 2 instructions, so eliminate them. */
295 /* ??? This isn't strictly correct. It is OK to accept multiword modes
296 here, since the length attributes are being set correctly, but only
297 if the address is offsettable. */
298 if (GET_MODE_SIZE (GET_MODE (op
)) > UNITS_PER_WORD
)
302 /* Decode the address now. */
304 switch (GET_CODE (addr
))
311 plus0
= XEXP (addr
, 0);
312 plus1
= XEXP (addr
, 1);
314 if (GET_CODE (plus0
) != REG
)
317 if (GET_CODE (plus0
) == REG
&& GET_CODE (plus1
) == CONST_INT
318 && SMALL_INT (plus1
))
322 else if (GET_CODE (plus1
) == REG
&& GET_CODE (plus0
) == CONST_INT
)
326 else if (GET_CODE (plus0
) == REG
&& GET_CODE (plus1
) == REG
)
343 /* Return nonzero for a memory address that can be used to load or store
347 double_memory_operand (rtx op
, machine_mode mode
)
351 if (GET_CODE (op
) != MEM
|| !memory_operand (op
, mode
))
353 /* During reload, we accept a pseudo register if it has an
354 appropriate memory address. If we don't do this, we will
355 wind up reloading into a register, and then reloading that
356 register from memory, when we could just reload directly from
358 if (reload_in_progress
359 && GET_CODE (op
) == REG
360 && REGNO (op
) >= FIRST_PSEUDO_REGISTER
361 && reg_renumber
[REGNO (op
)] < 0
362 && reg_equiv_mem (REGNO (op
)) != 0
363 && double_memory_operand (reg_equiv_mem (REGNO (op
)), mode
))
368 /* Make sure that 4 added to the address is a valid memory address.
369 This essentially just checks for overflow in an added constant. */
373 if (CONSTANT_ADDRESS_P (addr
))
376 return memory_address_p ((GET_MODE_CLASS (mode
) == MODE_INT
378 plus_constant (Pmode
, addr
, 4));
381 /* Implement REG_OK_FOR_BASE_P -and- REG_OK_FOR_INDEX_P. */
383 microblaze_regno_ok_for_base_p (int regno
, int strict
)
385 if (regno
>= FIRST_PSEUDO_REGISTER
)
389 regno
= reg_renumber
[regno
];
392 /* These fake registers will be eliminated to either the stack or
393 hard frame pointer, both of which are usually valid base registers.
394 Reload deals with the cases where the eliminated form isn't valid. */
395 if (regno
== ARG_POINTER_REGNUM
|| regno
== FRAME_POINTER_REGNUM
)
398 return GP_REG_P (regno
);
401 /* Return true if X is a valid base register for the given mode.
402 Allow only hard registers if STRICT. */
405 microblaze_valid_base_register_p (rtx x
,
406 machine_mode mode ATTRIBUTE_UNUSED
,
409 if (!strict
&& GET_CODE (x
) == SUBREG
)
412 return (GET_CODE (x
) == REG
413 && microblaze_regno_ok_for_base_p (REGNO (x
), strict
));
416 /* Build the SYMBOL_REF for __tls_get_addr. */
418 static GTY(()) rtx tls_get_addr_libfunc
;
421 get_tls_get_addr (void)
423 if (!tls_get_addr_libfunc
)
424 tls_get_addr_libfunc
= init_one_libfunc ("__tls_get_addr");
425 return tls_get_addr_libfunc
;
428 /* Return TRUE if X is a thread-local symbol. */
430 microblaze_tls_symbol_p (rtx x
)
432 if (!TARGET_HAVE_TLS
)
435 if (GET_CODE (x
) != SYMBOL_REF
)
438 return SYMBOL_REF_TLS_MODEL (x
) != 0;
441 /* Return TRUE if X contains any TLS symbol references. */
444 microblaze_tls_referenced_p (rtx x
)
446 if (!TARGET_HAVE_TLS
)
448 subrtx_iterator::array_type array
;
449 FOR_EACH_SUBRTX (iter
, array
, x
, ALL
)
452 if (GET_CODE (x
) == SYMBOL_REF
&& SYMBOL_REF_TLS_MODEL (x
) != 0)
454 /* Don't recurse into UNSPEC_TLS looking for TLS symbols; these are
455 TLS offsets, not real symbol references. */
456 if (GET_CODE (x
) == UNSPEC
&& XINT (x
, 1) == UNSPEC_TLS
)
457 iter
.skip_subrtxes ();
463 microblaze_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED
, rtx x
)
465 return microblaze_tls_referenced_p(x
);
468 /* Return TRUE if X references a SYMBOL_REF. */
470 symbol_mentioned_p (rtx x
)
475 if (GET_CODE (x
) == SYMBOL_REF
)
478 /* UNSPEC entries for a symbol include the SYMBOL_REF, but they
479 are constant offsets, not symbols. */
480 if (GET_CODE (x
) == UNSPEC
)
483 fmt
= GET_RTX_FORMAT (GET_CODE (x
));
485 for (i
= GET_RTX_LENGTH (GET_CODE (x
)) - 1; i
>= 0; i
--)
491 for (j
= XVECLEN (x
, i
) - 1; j
>= 0; j
--)
492 if (symbol_mentioned_p (XVECEXP (x
, i
, j
)))
495 else if (fmt
[i
] == 'e' && symbol_mentioned_p (XEXP (x
, i
)))
502 /* Return TRUE if X references a LABEL_REF. */
504 label_mentioned_p (rtx x
)
509 if (GET_CODE (x
) == LABEL_REF
)
512 /* UNSPEC entries for a symbol include a LABEL_REF for the referencing
513 instruction, but they are constant offsets, not symbols. */
514 if (GET_CODE (x
) == UNSPEC
)
517 fmt
= GET_RTX_FORMAT (GET_CODE (x
));
518 for (i
= GET_RTX_LENGTH (GET_CODE (x
)) - 1; i
>= 0; i
--)
524 for (j
= XVECLEN (x
, i
) - 1; j
>= 0; j
--)
525 if (label_mentioned_p (XVECEXP (x
, i
, j
)))
528 else if (fmt
[i
] == 'e' && label_mentioned_p (XEXP (x
, i
)))
536 tls_mentioned_p (rtx x
)
538 switch (GET_CODE (x
))
541 return tls_mentioned_p (XEXP (x
, 0));
544 if (XINT (x
, 1) == UNSPEC_TLS
)
554 load_tls_operand (rtx x
, rtx reg
)
559 reg
= gen_reg_rtx (Pmode
);
561 tmp
= gen_rtx_CONST (Pmode
, x
);
563 emit_insn (gen_rtx_SET (reg
,
564 gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
, tmp
)));
570 microblaze_call_tls_get_addr (rtx x
, rtx reg
, rtx
*valuep
, int reloc
)
575 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
579 tls_entry
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (2, x
, GEN_INT (reloc
)),
582 reg
= load_tls_operand (tls_entry
, reg
);
584 *valuep
= emit_library_call_value (get_tls_get_addr (), NULL_RTX
,
585 LCT_PURE
, /* LCT_CONST? */
586 Pmode
, 1, reg
, Pmode
);
588 insns
= get_insns ();
595 microblaze_legitimize_tls_address(rtx x
, rtx reg
)
597 rtx dest
, ret
, eqv
, addend
;
599 enum tls_model model
;
600 model
= SYMBOL_REF_TLS_MODEL (x
);
604 case TLS_MODEL_LOCAL_DYNAMIC
:
605 case TLS_MODEL_GLOBAL_DYNAMIC
:
606 case TLS_MODEL_INITIAL_EXEC
:
607 insns
= microblaze_call_tls_get_addr (x
, reg
, &ret
, TLS_GD
);
608 dest
= gen_reg_rtx (Pmode
);
609 emit_libcall_block (insns
, dest
, ret
, x
);
612 case TLS_MODEL_LOCAL_EXEC
:
613 insns
= microblaze_call_tls_get_addr (x
, reg
, &ret
, TLS_LDM
);
615 /* Attach a unique REG_EQUIV, to allow the RTL optimizers to
616 share the LDM result with other LD model accesses. */
617 eqv
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, const1_rtx
), UNSPEC_TLS
);
618 dest
= gen_reg_rtx (Pmode
);
619 emit_libcall_block (insns
, dest
, ret
, eqv
);
621 /* Load the addend. */
622 addend
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (2, x
, GEN_INT (TLS_DTPREL
)),
624 addend
= force_reg (SImode
, gen_rtx_CONST (SImode
, addend
));
625 dest
= gen_rtx_PLUS (Pmode
, dest
, addend
);
635 microblaze_classify_unspec (struct microblaze_address_info
*info
, rtx x
)
637 info
->symbol_type
= SYMBOL_TYPE_GENERAL
;
638 info
->symbol
= XVECEXP (x
, 0, 0);
640 if (XINT (x
, 1) == UNSPEC_GOTOFF
)
642 info
->regA
= gen_rtx_REG (SImode
, PIC_OFFSET_TABLE_REGNUM
);
643 info
->type
= ADDRESS_GOTOFF
;
645 else if (XINT (x
, 1) == UNSPEC_PLT
)
647 info
->type
= ADDRESS_PLT
;
649 else if (XINT (x
, 1) == UNSPEC_TLS
)
651 info
->type
= ADDRESS_TLS
;
652 info
->tls_type
= tls_reloc (INTVAL (XVECEXP (x
, 0, 1)));
662 /* Return true if X is a valid index register for the given mode.
663 Allow only hard registers if STRICT. */
666 microblaze_valid_index_register_p (rtx x
,
667 machine_mode mode ATTRIBUTE_UNUSED
,
670 if (!strict
&& GET_CODE (x
) == SUBREG
)
673 return (GET_CODE (x
) == REG
674 /* A base register is good enough to be an index register on MicroBlaze. */
675 && microblaze_regno_ok_for_base_p (REGNO (x
), strict
));
678 /* Get the base register for accessing a value from the memory or
679 Symbol ref. Used for MicroBlaze Small Data Area Pointer Optimization. */
686 if (!flag_pic
|| microblaze_tls_symbol_p(x
))
687 base_reg
= MB_ABI_BASE_REGNUM
;
689 base_reg
= MB_ABI_PIC_ADDR_REGNUM
;
692 && GET_CODE (x
) == SYMBOL_REF
693 && SYMBOL_REF_SMALL_P (x
) && (decl
= SYMBOL_REF_DECL (x
)) != NULL
)
695 if (TREE_READONLY (decl
))
696 base_reg
= MB_ABI_GPRO_REGNUM
;
698 base_reg
= MB_ABI_GPRW_REGNUM
;
704 /* Return true if X is a valid address for machine mode MODE. If it is,
705 fill in INFO appropriately. STRICT is true if we should only accept
708 type regA regB offset symbol
710 ADDRESS_INVALID NULL NULL NULL NULL
712 ADDRESS_REG %0 NULL const_0 / NULL
714 ADDRESS_REG_INDEX %0 %1 NULL NULL
716 ADDRESS_SYMBOLIC r0 / NULL NULL symbol
719 ADDRESS_CONST_INT r0 NULL const NULL
721 For modes spanning multiple registers (DFmode in 32-bit GPRs,
722 DImode, TImode), indexed addressing cannot be used because
723 adjacent memory cells are accessed by adding word-sized offsets
724 during assembly output. */
727 microblaze_classify_address (struct microblaze_address_info
*info
, rtx x
,
728 machine_mode mode
, int strict
)
733 info
->type
= ADDRESS_INVALID
;
738 info
->symbol_type
= SYMBOL_TYPE_INVALID
;
740 switch (GET_CODE (x
))
745 info
->type
= ADDRESS_REG
;
747 info
->offset
= const0_rtx
;
748 return microblaze_valid_base_register_p (info
->regA
, mode
, strict
);
752 xplus0
= XEXP (x
, 0);
753 xplus1
= XEXP (x
, 1);
755 if (microblaze_valid_base_register_p (xplus0
, mode
, strict
))
757 info
->type
= ADDRESS_REG
;
760 if (GET_CODE (xplus1
) == CONST_INT
)
762 info
->offset
= xplus1
;
765 else if (GET_CODE (xplus1
) == UNSPEC
)
767 /* Need offsettable address. */
768 if (GET_MODE_SIZE (mode
) > UNITS_PER_WORD
)
771 return microblaze_classify_unspec (info
, xplus1
);
773 else if ((GET_CODE (xplus1
) == SYMBOL_REF
||
774 GET_CODE (xplus1
) == LABEL_REF
))
776 if (flag_pic
== 2 || microblaze_tls_symbol_p(xplus1
))
778 info
->type
= ADDRESS_SYMBOLIC
;
779 info
->symbol
= xplus1
;
780 info
->symbol_type
= SYMBOL_TYPE_GENERAL
;
783 else if (GET_CODE (xplus1
) == CONST
)
785 rtx xconst0
= XEXP(xplus1
, 0);
788 if (GET_CODE (xconst0
) == UNSPEC
)
790 /* Need offsettable address. */
791 if (GET_MODE_SIZE (mode
) > UNITS_PER_WORD
)
793 return microblaze_classify_unspec(info
, xconst0
);
796 /* for (plus x const_int) just look at x. */
797 if (GET_CODE (xconst0
) == PLUS
798 && GET_CODE (XEXP (xconst0
, 1)) == CONST_INT
799 && SMALL_INT (XEXP (xconst0
, 1)))
801 /* This is ok as info->symbol is set to xplus1 the full
802 const-expression below. */
803 xconst0
= XEXP (xconst0
, 0);
806 if (GET_CODE (xconst0
) == SYMBOL_REF
807 || GET_CODE (xconst0
) == LABEL_REF
)
809 if (flag_pic
== 2 || microblaze_tls_symbol_p(xconst0
))
812 info
->type
= ADDRESS_SYMBOLIC
;
813 info
->symbol
= xplus1
;
814 info
->symbol_type
= SYMBOL_TYPE_GENERAL
;
818 /* Not base + symbol || base + UNSPEC. */
822 else if (GET_CODE (xplus1
) == REG
823 && microblaze_valid_index_register_p (xplus1
, mode
,
825 && (GET_MODE_SIZE (mode
) <= UNITS_PER_WORD
))
827 /* Restrict larger than word-width modes from using an index register. */
828 info
->type
= ADDRESS_REG_INDEX
;
837 info
->regA
= gen_raw_REG (mode
, 0);
838 info
->type
= ADDRESS_CONST_INT
;
846 info
->type
= ADDRESS_SYMBOLIC
;
847 info
->symbol_type
= SYMBOL_TYPE_GENERAL
;
849 info
->regA
= gen_raw_REG (mode
, get_base_reg (x
));
851 if (GET_CODE (x
) == CONST
)
853 if (GET_CODE (XEXP (x
, 0)) == UNSPEC
)
855 info
->regA
= gen_raw_REG (mode
,
856 get_base_reg (XVECEXP (XEXP (x
,0), 0, 0)));
857 return microblaze_classify_unspec (info
, XEXP (x
, 0));
859 return !(flag_pic
&& pic_address_needs_scratch (x
));
864 else if (microblaze_tls_symbol_p(x
))
872 if (reload_in_progress
)
873 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
874 return microblaze_classify_unspec (info
, x
);
884 /* This function is used to implement GO_IF_LEGITIMATE_ADDRESS. It
885 returns a nonzero value if X is a legitimate address for a memory
886 operand of the indicated MODE. STRICT is nonzero if this function
887 is called during reload. */
890 microblaze_legitimate_address_p (machine_mode mode
, rtx x
, bool strict
)
892 struct microblaze_address_info addr
;
894 return microblaze_classify_address (&addr
, x
, mode
, strict
);
898 microblaze_valid_pic_const (rtx x
)
900 switch (GET_CODE (x
))
912 microblaze_legitimate_pic_operand (rtx x
)
914 if (flag_pic
== 2 && (symbol_mentioned_p(x
) || label_mentioned_p(x
)))
917 if (microblaze_tls_referenced_p(x
))
923 /* Try machine-dependent ways of modifying an illegitimate address
924 to be legitimate. If we find one, return the new, valid address.
925 This is used from only one place: `memory_address' in explow.c.
927 OLDX is the address as it was before break_out_memory_refs was
928 called. In some cases it is useful to look at this to decide what
931 It is always safe for this function to do nothing. It exists to
932 recognize opportunities to optimize the output.
934 For the MicroBlaze, transform:
936 memory(X + <large int>)
940 Y = <large int> & ~0x7fff;
942 memory (Z + (<large int> & 0x7fff));
944 This is for CSE to find several similar references, and only use one Z.
946 When PIC, convert addresses of the form memory (symbol+large int) to
947 memory (reg+large int). */
950 microblaze_legitimize_address (rtx x
, rtx oldx ATTRIBUTE_UNUSED
,
951 machine_mode mode ATTRIBUTE_UNUSED
)
953 register rtx xinsn
= x
, result
;
955 if (GET_CODE (xinsn
) == CONST
956 && flag_pic
&& pic_address_needs_scratch (xinsn
))
958 rtx ptr_reg
= gen_reg_rtx (Pmode
);
959 rtx constant
= XEXP (XEXP (xinsn
, 0), 1);
961 emit_move_insn (ptr_reg
, XEXP (XEXP (xinsn
, 0), 0));
963 result
= gen_rtx_PLUS (Pmode
, ptr_reg
, constant
);
964 if (SMALL_INT (constant
))
966 /* Otherwise we fall through so the code below will fix the
971 if (GET_CODE (xinsn
) == PLUS
)
973 register rtx xplus0
= XEXP (xinsn
, 0);
974 register rtx xplus1
= XEXP (xinsn
, 1);
975 register enum rtx_code code0
= GET_CODE (xplus0
);
976 register enum rtx_code code1
= GET_CODE (xplus1
);
978 if (code0
!= REG
&& code1
== REG
)
980 xplus0
= XEXP (xinsn
, 1);
981 xplus1
= XEXP (xinsn
, 0);
982 code0
= GET_CODE (xplus0
);
983 code1
= GET_CODE (xplus1
);
986 if (code0
== REG
&& REG_OK_FOR_BASE_P (xplus0
)
987 && code1
== CONST_INT
&& !SMALL_INT (xplus1
))
989 rtx int_reg
= gen_reg_rtx (Pmode
);
990 rtx ptr_reg
= gen_reg_rtx (Pmode
);
992 emit_move_insn (int_reg
, GEN_INT (INTVAL (xplus1
) & ~0x7fff));
994 emit_insn (gen_rtx_SET (ptr_reg
,
995 gen_rtx_PLUS (Pmode
, xplus0
, int_reg
)));
997 result
= gen_rtx_PLUS (Pmode
, ptr_reg
,
998 GEN_INT (INTVAL (xplus1
) & 0x7fff));
1002 if (code0
== REG
&& REG_OK_FOR_BASE_P (xplus0
))
1004 if (reload_in_progress
)
1005 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
1008 xplus1
= XEXP (xplus1
, 0);
1009 code1
= GET_CODE (xplus1
);
1011 if (code1
== SYMBOL_REF
)
1013 if (microblaze_tls_symbol_p(xplus1
))
1016 reg
= gen_reg_rtx (Pmode
);
1018 tls_ref
= microblaze_legitimize_tls_address (xplus1
,
1020 emit_move_insn (reg
, tls_ref
);
1022 result
= gen_rtx_PLUS (Pmode
, xplus0
, reg
);
1026 else if (flag_pic
== 2)
1029 reg
= gen_reg_rtx (Pmode
);
1031 pic_ref
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, xplus1
),
1033 pic_ref
= gen_rtx_CONST (Pmode
, pic_ref
);
1034 pic_ref
= gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
, pic_ref
);
1035 pic_ref
= gen_const_mem (Pmode
, pic_ref
);
1036 emit_move_insn (reg
, pic_ref
);
1037 result
= gen_rtx_PLUS (Pmode
, xplus0
, reg
);
1044 if (GET_CODE (xinsn
) == SYMBOL_REF
)
1047 if (microblaze_tls_symbol_p(xinsn
))
1049 reg
= microblaze_legitimize_tls_address (xinsn
, NULL_RTX
);
1055 if (reload_in_progress
)
1056 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
1058 pic_ref
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, xinsn
), UNSPEC_GOTOFF
);
1059 pic_ref
= gen_rtx_CONST (Pmode
, pic_ref
);
1060 pic_ref
= gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
, pic_ref
);
1061 pic_ref
= gen_const_mem (Pmode
, pic_ref
);
1072 #define MAX_MOVE_REGS 8
1073 #define MAX_MOVE_BYTES (MAX_MOVE_REGS * UNITS_PER_WORD)
1075 /* Emit straight-line code to move LENGTH bytes from SRC to DEST.
1076 Assume that the areas do not overlap. */
1079 microblaze_block_move_straight (rtx dest
, rtx src
, HOST_WIDE_INT length
)
1081 HOST_WIDE_INT offset
, delta
;
1082 unsigned HOST_WIDE_INT bits
;
1087 bits
= BITS_PER_WORD
;
1088 mode
= mode_for_size (bits
, MODE_INT
, 0);
1089 delta
= bits
/ BITS_PER_UNIT
;
1091 /* Allocate a buffer for the temporary registers. */
1092 regs
= XALLOCAVEC (rtx
, length
/ delta
);
1094 /* Load as many BITS-sized chunks as possible. Use a normal load if
1095 the source has enough alignment, otherwise use left/right pairs. */
1096 for (offset
= 0, i
= 0; offset
+ delta
<= length
; offset
+= delta
, i
++)
1098 regs
[i
] = gen_reg_rtx (mode
);
1099 emit_move_insn (regs
[i
], adjust_address (src
, mode
, offset
));
1102 /* Copy the chunks to the destination. */
1103 for (offset
= 0, i
= 0; offset
+ delta
<= length
; offset
+= delta
, i
++)
1104 emit_move_insn (adjust_address (dest
, mode
, offset
), regs
[i
]);
1106 /* Mop up any left-over bytes. */
1107 if (offset
< length
)
1109 src
= adjust_address (src
, BLKmode
, offset
);
1110 dest
= adjust_address (dest
, BLKmode
, offset
);
1111 move_by_pieces (dest
, src
, length
- offset
,
1112 MIN (MEM_ALIGN (src
), MEM_ALIGN (dest
)), 0);
1116 /* Helper function for doing a loop-based block operation on memory
1117 reference MEM. Each iteration of the loop will operate on LENGTH
1120 Create a new base register for use within the loop and point it to
1121 the start of MEM. Create a new memory reference that uses this
1122 register. Store them in *LOOP_REG and *LOOP_MEM respectively. */
1125 microblaze_adjust_block_mem (rtx mem
, HOST_WIDE_INT length
,
1126 rtx
* loop_reg
, rtx
* loop_mem
)
1128 *loop_reg
= copy_addr_to_reg (XEXP (mem
, 0));
1130 /* Although the new mem does not refer to a known location,
1131 it does keep up to LENGTH bytes of alignment. */
1132 *loop_mem
= change_address (mem
, BLKmode
, *loop_reg
);
1133 set_mem_align (*loop_mem
,
1134 MIN ((HOST_WIDE_INT
) MEM_ALIGN (mem
),
1135 length
* BITS_PER_UNIT
));
1139 /* Move LENGTH bytes from SRC to DEST using a loop that moves MAX_MOVE_BYTES
1140 per iteration. LENGTH must be at least MAX_MOVE_BYTES. Assume that the
1141 memory regions do not overlap. */
1144 microblaze_block_move_loop (rtx dest
, rtx src
, HOST_WIDE_INT length
)
1146 rtx_code_label
*label
;
1147 rtx src_reg
, dest_reg
, final_src
;
1148 HOST_WIDE_INT leftover
;
1150 leftover
= length
% MAX_MOVE_BYTES
;
1153 /* Create registers and memory references for use within the loop. */
1154 microblaze_adjust_block_mem (src
, MAX_MOVE_BYTES
, &src_reg
, &src
);
1155 microblaze_adjust_block_mem (dest
, MAX_MOVE_BYTES
, &dest_reg
, &dest
);
1157 /* Calculate the value that SRC_REG should have after the last iteration
1159 final_src
= expand_simple_binop (Pmode
, PLUS
, src_reg
, GEN_INT (length
),
1162 /* Emit the start of the loop. */
1163 label
= gen_label_rtx ();
1166 /* Emit the loop body. */
1167 microblaze_block_move_straight (dest
, src
, MAX_MOVE_BYTES
);
1169 /* Move on to the next block. */
1170 emit_move_insn (src_reg
, plus_constant (Pmode
, src_reg
, MAX_MOVE_BYTES
));
1171 emit_move_insn (dest_reg
, plus_constant (Pmode
, dest_reg
, MAX_MOVE_BYTES
));
1173 /* Emit the test & branch. */
1174 emit_insn (gen_cbranchsi4 (gen_rtx_NE (SImode
, src_reg
, final_src
),
1175 src_reg
, final_src
, label
));
1177 /* Mop up any left-over bytes. */
1179 microblaze_block_move_straight (dest
, src
, leftover
);
1182 /* Expand a movmemsi instruction. */
1185 microblaze_expand_block_move (rtx dest
, rtx src
, rtx length
, rtx align_rtx
)
1188 if (GET_CODE (length
) == CONST_INT
)
1190 HOST_WIDE_INT bytes
= INTVAL (length
);
1191 int align
= INTVAL (align_rtx
);
1193 if (align
> UNITS_PER_WORD
)
1195 align
= UNITS_PER_WORD
; /* We can't do any better. */
1197 else if (align
< UNITS_PER_WORD
)
1199 if (INTVAL (length
) <= MAX_MOVE_BYTES
)
1201 move_by_pieces (dest
, src
, bytes
, align
, 0);
1208 if (INTVAL (length
) <= 2 * MAX_MOVE_BYTES
)
1210 microblaze_block_move_straight (dest
, src
, INTVAL (length
));
1215 microblaze_block_move_loop (dest
, src
, INTVAL (length
));
1223 microblaze_rtx_costs (rtx x
, machine_mode mode
, int outer_code ATTRIBUTE_UNUSED
,
1224 int opno ATTRIBUTE_UNUSED
, int *total
,
1225 bool speed ATTRIBUTE_UNUSED
)
1227 int code
= GET_CODE (x
);
1233 int num_words
= (GET_MODE_SIZE (mode
) > UNITS_PER_WORD
) ? 2 : 1;
1234 if (simple_memory_operand (x
, mode
))
1235 *total
= COSTS_N_INSNS (2 * num_words
);
1237 *total
= COSTS_N_INSNS (2 * (2 * num_words
));
1245 *total
= COSTS_N_INSNS (2);
1248 *total
= COSTS_N_INSNS (1);
1257 *total
= COSTS_N_INSNS (2);
1260 *total
= COSTS_N_INSNS (1);
1268 if (TARGET_BARREL_SHIFT
)
1270 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v5.00.a")
1272 *total
= COSTS_N_INSNS (1);
1274 *total
= COSTS_N_INSNS (2);
1276 else if (!TARGET_SOFT_MUL
)
1277 *total
= COSTS_N_INSNS (1);
1278 else if (GET_CODE (XEXP (x
, 1)) == CONST_INT
)
1280 /* Add 1 to make shift slightly more expensive than add. */
1281 *total
= COSTS_N_INSNS (INTVAL (XEXP (x
, 1))) + 1;
1282 /* Reduce shift costs for special circumstances. */
1283 if (optimize_size
&& INTVAL (XEXP (x
, 1)) > 5)
1285 if (!optimize_size
&& INTVAL (XEXP (x
, 1)) > 17)
1289 /* Double the worst cost of shifts when there is no barrel shifter and
1290 the shift amount is in a reg. */
1291 *total
= COSTS_N_INSNS (32 * 4);
1297 if (mode
== SFmode
|| mode
== DFmode
)
1299 if (TARGET_HARD_FLOAT
)
1300 *total
= COSTS_N_INSNS (6);
1303 else if (mode
== DImode
)
1305 *total
= COSTS_N_INSNS (4);
1310 *total
= COSTS_N_INSNS (1);
1319 *total
= COSTS_N_INSNS (4);
1327 if (TARGET_HARD_FLOAT
)
1328 *total
= COSTS_N_INSNS (6);
1330 else if (!TARGET_SOFT_MUL
)
1332 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v5.00.a")
1334 *total
= COSTS_N_INSNS (1);
1336 *total
= COSTS_N_INSNS (3);
1339 *total
= COSTS_N_INSNS (10);
1347 if (TARGET_HARD_FLOAT
)
1348 *total
= COSTS_N_INSNS (23);
1354 *total
= COSTS_N_INSNS (1);
1359 *total
= COSTS_N_INSNS (1);
1367 /* Return the number of instructions needed to load or store a value
1368 of mode MODE at X. Return 0 if X isn't valid for MODE. */
1371 microblaze_address_insns (rtx x
, machine_mode mode
)
1373 struct microblaze_address_info addr
;
1375 if (microblaze_classify_address (&addr
, x
, mode
, false))
1380 if (SMALL_INT (addr
.offset
))
1384 case ADDRESS_CONST_INT
:
1389 case ADDRESS_REG_INDEX
:
1391 case ADDRESS_SYMBOLIC
:
1392 case ADDRESS_GOTOFF
:
1395 switch (addr
.tls_type
)
1413 /* Provide the costs of an addressing mode that contains ADDR.
1414 If ADDR is not a valid address, its cost is irrelevant. */
1416 microblaze_address_cost (rtx addr
, machine_mode mode ATTRIBUTE_UNUSED
,
1417 addr_space_t as ATTRIBUTE_UNUSED
,
1418 bool speed ATTRIBUTE_UNUSED
)
1420 return COSTS_N_INSNS (microblaze_address_insns (addr
, GET_MODE (addr
)));
1423 /* Return nonzero if X is an address which needs a temporary register when
1424 reloaded while generating PIC code. */
1427 pic_address_needs_scratch (rtx x
)
1429 if (GET_CODE (x
) == CONST
&& GET_CODE (XEXP (x
,0)) == PLUS
)
1433 p0
= XEXP (XEXP (x
, 0), 0);
1434 p1
= XEXP (XEXP (x
, 0), 1);
1436 if ((GET_CODE (p0
) == SYMBOL_REF
|| GET_CODE (p0
) == LABEL_REF
)
1437 && (GET_CODE (p1
) == CONST_INT
)
1438 && (flag_pic
== 2 || microblaze_tls_symbol_p (p0
) || !SMALL_INT (p1
)))
1444 /* Argument support functions. */
1445 /* Initialize CUMULATIVE_ARGS for a function. */
1448 init_cumulative_args (CUMULATIVE_ARGS
* cum
, tree fntype
,
1449 rtx libname ATTRIBUTE_UNUSED
)
1451 static CUMULATIVE_ARGS zero_cum
;
1452 tree param
, next_param
;
1456 /* Determine if this function has variable arguments. This is
1457 indicated by the last argument being 'void_type_mode' if there
1458 are no variable arguments. The standard MicroBlaze calling sequence
1459 passes all arguments in the general purpose registers in this case. */
1461 for (param
= fntype
? TYPE_ARG_TYPES (fntype
) : 0;
1462 param
!= 0; param
= next_param
)
1464 next_param
= TREE_CHAIN (param
);
1465 if (next_param
== 0 && TREE_VALUE (param
) != void_type_node
)
1466 cum
->gp_reg_found
= 1;
1470 /* Advance the argument to the next argument position. */
1473 microblaze_function_arg_advance (cumulative_args_t cum_v
,
1475 const_tree type
, bool named ATTRIBUTE_UNUSED
)
1477 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
1486 gcc_assert (GET_MODE_CLASS (mode
) == MODE_COMPLEX_INT
1487 || GET_MODE_CLASS (mode
) == MODE_COMPLEX_FLOAT
);
1489 cum
->gp_reg_found
= 1;
1490 cum
->arg_words
+= ((GET_MODE_SIZE (mode
) + UNITS_PER_WORD
- 1)
1495 cum
->gp_reg_found
= 1;
1496 cum
->arg_words
+= ((int_size_in_bytes (type
) + UNITS_PER_WORD
- 1)
1502 if (!cum
->gp_reg_found
&& cum
->arg_number
<= 2)
1503 cum
->fp_code
+= 1 << ((cum
->arg_number
- 1) * 2);
1507 cum
->arg_words
+= 2;
1508 if (!cum
->gp_reg_found
&& cum
->arg_number
<= 2)
1509 cum
->fp_code
+= 2 << ((cum
->arg_number
- 1) * 2);
1513 cum
->gp_reg_found
= 1;
1514 cum
->arg_words
+= 2;
1521 cum
->gp_reg_found
= 1;
1527 /* Return an RTL expression containing the register for the given mode,
1528 or 0 if the argument is to be passed on the stack. */
1531 microblaze_function_arg (cumulative_args_t cum_v
, machine_mode mode
,
1532 const_tree type ATTRIBUTE_UNUSED
,
1533 bool named ATTRIBUTE_UNUSED
)
1535 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
1539 int *arg_words
= &cum
->arg_words
;
1541 cum
->last_arg_fp
= 0;
1552 regbase
= GP_ARG_FIRST
;
1555 gcc_assert (GET_MODE_CLASS (mode
) == MODE_COMPLEX_INT
1556 || GET_MODE_CLASS (mode
) == MODE_COMPLEX_FLOAT
);
1559 regbase
= GP_ARG_FIRST
;
1563 if (*arg_words
>= MAX_ARGS_IN_REGISTERS
)
1567 gcc_assert (regbase
!= -1);
1569 ret
= gen_rtx_REG (mode
, regbase
+ *arg_words
);
1572 if (mode
== VOIDmode
)
1574 if (cum
->num_adjusts
> 0)
1575 ret
= gen_rtx_PARALLEL ((machine_mode
) cum
->fp_code
,
1576 gen_rtvec_v (cum
->num_adjusts
, cum
->adjust
));
1582 /* Return number of bytes of argument to put in registers. */
1584 function_arg_partial_bytes (cumulative_args_t cum_v
, machine_mode mode
,
1585 tree type
, bool named ATTRIBUTE_UNUSED
)
1587 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
1589 if ((mode
== BLKmode
1590 || GET_MODE_CLASS (mode
) != MODE_COMPLEX_INT
1591 || GET_MODE_CLASS (mode
) != MODE_COMPLEX_FLOAT
)
1592 && cum
->arg_words
< MAX_ARGS_IN_REGISTERS
)
1595 if (mode
== BLKmode
)
1596 words
= ((int_size_in_bytes (type
) + UNITS_PER_WORD
- 1)
1599 words
= (GET_MODE_SIZE (mode
) + UNITS_PER_WORD
- 1) / UNITS_PER_WORD
;
1601 if (words
+ cum
->arg_words
<= MAX_ARGS_IN_REGISTERS
)
1602 return 0; /* structure fits in registers */
1604 return (MAX_ARGS_IN_REGISTERS
- cum
->arg_words
) * UNITS_PER_WORD
;
1607 else if (mode
== DImode
&& cum
->arg_words
== MAX_ARGS_IN_REGISTERS
- 1)
1608 return UNITS_PER_WORD
;
1613 /* Convert a version number of the form "vX.YY.Z" to an integer encoding
1614 for easier range comparison. */
1616 microblaze_version_to_int (const char *version
)
1619 const char *tmpl
= "vXX.YY.Z";
1628 { /* Looking for major */
1635 if (!(*p
>= '0' && *p
<= '9'))
1637 iver
+= (int) (*p
- '0');
1642 { /* Looking for minor */
1643 if (!(*p
>= '0' && *p
<= '9'))
1645 iver
+= (int) (*p
- '0');
1649 { /* Looking for compat */
1650 if (!(*p
>= 'a' && *p
<= 'z'))
1653 iver
+= (int) (*p
- 'a');
1673 microblaze_option_override (void)
1675 register int i
, start
;
1677 register machine_mode mode
;
1680 microblaze_section_threshold
= (global_options_set
.x_g_switch_value
1682 : MICROBLAZE_DEFAULT_GVALUE
);
1686 /* Make sure it's 2, we only support one kind of PIC. */
1688 if (!TARGET_SUPPORTS_PIC
)
1690 error ("-fPIC/-fpic not supported for this target");
1691 /* Clear it to avoid further errors. */
1696 /* Check the MicroBlaze CPU version for any special action to be done. */
1697 if (microblaze_select_cpu
== NULL
)
1698 microblaze_select_cpu
= MICROBLAZE_DEFAULT_CPU
;
1699 ver
= microblaze_version_to_int (microblaze_select_cpu
);
1702 error ("%qs is an invalid argument to -mcpu=", microblaze_select_cpu
);
1705 ver
= MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v3.00.a");
1708 /* No hardware exceptions in earlier versions. So no worries. */
1710 microblaze_select_flags
&= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY
);
1712 microblaze_no_unsafe_delay
= 0;
1713 microblaze_pipe
= MICROBLAZE_PIPE_3
;
1716 || (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v4.00.b")
1720 microblaze_select_flags
|= (MICROBLAZE_MASK_NO_UNSAFE_DELAY
);
1722 microblaze_no_unsafe_delay
= 1;
1723 microblaze_pipe
= MICROBLAZE_PIPE_3
;
1727 /* We agree to use 5 pipe-stage model even on area optimized 3
1728 pipe-stage variants. */
1730 microblaze_select_flags
&= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY
);
1732 microblaze_no_unsafe_delay
= 0;
1733 microblaze_pipe
= MICROBLAZE_PIPE_5
;
1734 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v5.00.a") == 0
1735 || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
,
1737 || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
,
1740 /* Pattern compares are to be turned on by default only when
1741 compiling for MB v5.00.'z'. */
1742 target_flags
|= MASK_PATTERN_COMPARE
;
1746 ver
= MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v6.00.a");
1749 if (TARGET_MULTIPLY_HIGH
)
1751 "-mxl-multiply-high can be used only with -mcpu=v6.00.a or greater");
1754 ver
= MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v8.10.a");
1755 microblaze_has_clz
= 1;
1758 /* MicroBlaze prior to 8.10.a didn't have clz. */
1759 microblaze_has_clz
= 0;
1762 /* TARGET_REORDER defaults to 2 if -mxl-reorder not specified. */
1763 ver
= MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v8.30.a");
1766 if (TARGET_REORDER
== 1)
1767 warning (0, "-mxl-reorder can be used only with -mcpu=v8.30.a or greater");
1770 else if ((ver
== 0) && !TARGET_PATTERN_COMPARE
)
1772 if (TARGET_REORDER
== 1)
1773 warning (0, "-mxl-reorder requires -mxl-pattern-compare for -mcpu=v8.30.a");
1777 if (TARGET_MULTIPLY_HIGH
&& TARGET_SOFT_MUL
)
1778 error ("-mxl-multiply-high requires -mno-xl-soft-mul");
1780 /* Always use DFA scheduler. */
1781 microblaze_sched_use_dfa
= 1;
1784 microblaze_abicalls
= MICROBLAZE_ABICALLS_NO
;
1787 /* Initialize the high, low values for legit floating point constants. */
1788 real_maxval (&dfhigh
, 0, DFmode
);
1789 real_maxval (&dflow
, 1, DFmode
);
1790 real_maxval (&sfhigh
, 0, SFmode
);
1791 real_maxval (&sflow
, 1, SFmode
);
1793 microblaze_print_operand_punct
['?'] = 1;
1794 microblaze_print_operand_punct
['#'] = 1;
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;
1812 /* Set up array to map GCC register number to debug register number.
1813 Ignore the special purpose register numbers. */
1815 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
1816 microblaze_dbx_regno
[i
] = -1;
1818 start
= GP_DBX_FIRST
- GP_REG_FIRST
;
1819 for (i
= GP_REG_FIRST
; i
<= GP_REG_LAST
; i
++)
1820 microblaze_dbx_regno
[i
] = i
+ start
;
1822 /* Set up array giving whether a given register can hold a given mode. */
1824 for (mode
= VOIDmode
;
1825 mode
!= MAX_MACHINE_MODE
; mode
= (machine_mode
) ((int) mode
+ 1))
1827 register int size
= GET_MODE_SIZE (mode
);
1829 for (regno
= 0; regno
< FIRST_PSEUDO_REGISTER
; regno
++)
1835 ok
= (ST_REG_P (regno
) || GP_REG_P (regno
));
1837 else if (GP_REG_P (regno
))
1838 ok
= ((regno
& 1) == 0 || size
<= UNITS_PER_WORD
);
1842 microblaze_hard_regno_mode_ok
[(int) mode
][regno
] = ok
;
1847 /* Return true if FUNC is an interrupt function as specified
1848 by the "interrupt_handler" attribute. */
1851 microblaze_interrupt_function_p (tree func
)
1855 if (TREE_CODE (func
) != FUNCTION_DECL
)
1858 a
= lookup_attribute ("interrupt_handler", DECL_ATTRIBUTES (func
));
1859 return a
!= NULL_TREE
;
1863 microblaze_fast_interrupt_function_p (tree func
)
1867 if (TREE_CODE (func
) != FUNCTION_DECL
)
1870 a
= lookup_attribute ("fast_interrupt", DECL_ATTRIBUTES (func
));
1871 return a
!= NULL_TREE
;
1874 microblaze_break_function_p (tree func
)
1879 if (TREE_CODE (func
) != FUNCTION_DECL
)
1882 a
= lookup_attribute ("break_handler", DECL_ATTRIBUTES (func
));
1883 return a
!= NULL_TREE
;
1885 /* Return true if FUNC is an interrupt function which uses
1886 normal return, indicated by the "save_volatiles" attribute. */
1889 microblaze_save_volatiles (tree func
)
1893 if (TREE_CODE (func
) != FUNCTION_DECL
)
1896 a
= lookup_attribute ("save_volatiles", DECL_ATTRIBUTES (func
));
1897 return a
!= NULL_TREE
;
1900 /* Return whether function is tagged with 'interrupt_handler'
1901 or 'fast_interrupt' attribute. Return true if function
1902 should use return from interrupt rather than normal
1905 microblaze_is_interrupt_variant (void)
1907 return (interrupt_handler
|| fast_interrupt
);
1910 microblaze_is_break_handler (void)
1912 return break_handler
;
1915 /* Determine of register must be saved/restored in call. */
1917 microblaze_must_save_register (int regno
)
1919 if (pic_offset_table_rtx
&&
1920 (regno
== MB_ABI_PIC_ADDR_REGNUM
) && df_regs_ever_live_p (regno
))
1923 if (df_regs_ever_live_p (regno
) && !call_used_regs
[regno
])
1926 if (frame_pointer_needed
&& (regno
== HARD_FRAME_POINTER_REGNUM
))
1929 if (crtl
->calls_eh_return
1930 && regno
== MB_ABI_SUB_RETURN_ADDR_REGNUM
)
1935 if (regno
== MB_ABI_SUB_RETURN_ADDR_REGNUM
)
1937 if ((microblaze_is_interrupt_variant () || save_volatiles
) &&
1938 (regno
>= 3 && regno
<= 12))
1942 if (microblaze_is_interrupt_variant ())
1944 if (df_regs_ever_live_p (regno
)
1945 || regno
== MB_ABI_MSR_SAVE_REG
1946 || (interrupt_handler
1947 && (regno
== MB_ABI_ASM_TEMP_REGNUM
1948 || regno
== MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM
)))
1954 if (df_regs_ever_live_p (regno
)
1955 || regno
== MB_ABI_ASM_TEMP_REGNUM
1956 || regno
== MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM
)
1960 if (crtl
->calls_eh_return
1961 && (regno
== EH_RETURN_DATA_REGNO (0)
1962 || regno
== EH_RETURN_DATA_REGNO (1)))
1968 /* Return the bytes needed to compute the frame pointer from the current
1971 MicroBlaze stack frames look like:
1975 Before call After call
1976 +-----------------------+ +-----------------------+
1978 mem. | local variables, | | local variables, |
1979 | callee saved and | | callee saved and |
1981 +-----------------------+ +-----------------------+
1982 | arguments for called | | arguments for called |
1983 | subroutines | | subroutines |
1984 | (optional) | | (optional) |
1985 +-----------------------+ +-----------------------+
1986 | Link register | | Link register |
1988 +-----------------------+ +-----------------------+
1990 | local variables, |
1991 | callee saved and |
1993 +-----------------------+
1994 | MSR (optional if, |
1995 | interrupt handler) |
1996 +-----------------------+
1998 | alloca allocations |
2000 +-----------------------+
2002 | arguments for called |
2006 +-----------------------+
2009 memory +-----------------------+
2013 static HOST_WIDE_INT
2014 compute_frame_size (HOST_WIDE_INT size
)
2017 HOST_WIDE_INT total_size
; /* # bytes that the entire frame takes up. */
2018 HOST_WIDE_INT var_size
; /* # bytes that local variables take up. */
2019 HOST_WIDE_INT args_size
; /* # bytes that outgoing arguments take up. */
2020 int link_debug_size
; /* # bytes for link register. */
2021 HOST_WIDE_INT gp_reg_size
; /* # bytes needed to store calle-saved gp regs. */
2022 long mask
; /* mask of saved gp registers. */
2025 microblaze_interrupt_function_p (current_function_decl
);
2027 microblaze_break_function_p (current_function_decl
);
2030 microblaze_fast_interrupt_function_p (current_function_decl
);
2031 save_volatiles
= microblaze_save_volatiles (current_function_decl
);
2033 interrupt_handler
= break_handler
;
2038 args_size
= crtl
->outgoing_args_size
;
2040 if ((args_size
== 0) && cfun
->calls_alloca
)
2041 args_size
= NUM_OF_ARGS
* UNITS_PER_WORD
;
2043 total_size
= var_size
+ args_size
;
2046 /* force setting GOT. */
2047 df_set_regs_ever_live (MB_ABI_PIC_ADDR_REGNUM
, true);
2049 /* Calculate space needed for gp registers. */
2050 for (regno
= GP_REG_FIRST
; regno
<= GP_REG_LAST
; regno
++)
2052 if (microblaze_must_save_register (regno
))
2055 if (regno
!= MB_ABI_SUB_RETURN_ADDR_REGNUM
)
2056 /* Don't account for link register. It is accounted specially below. */
2057 gp_reg_size
+= GET_MODE_SIZE (SImode
);
2059 mask
|= (1L << (regno
- GP_REG_FIRST
));
2063 total_size
+= gp_reg_size
;
2065 /* Add 4 bytes for MSR. */
2066 if (microblaze_is_interrupt_variant ())
2069 /* No space to be allocated for link register in leaf functions with no other
2070 stack requirements. */
2071 if (total_size
== 0 && crtl
->is_leaf
)
2072 link_debug_size
= 0;
2074 link_debug_size
= UNITS_PER_WORD
;
2076 total_size
+= link_debug_size
;
2078 /* Save other computed information. */
2079 current_frame_info
.total_size
= total_size
;
2080 current_frame_info
.var_size
= var_size
;
2081 current_frame_info
.args_size
= args_size
;
2082 current_frame_info
.gp_reg_size
= gp_reg_size
;
2083 current_frame_info
.mask
= mask
;
2084 current_frame_info
.initialized
= reload_completed
;
2085 current_frame_info
.num_gp
= gp_reg_size
/ UNITS_PER_WORD
;
2086 current_frame_info
.link_debug_size
= link_debug_size
;
2089 /* Offset from which to callee-save GP regs. */
2090 current_frame_info
.gp_offset
= (total_size
- gp_reg_size
);
2092 current_frame_info
.gp_offset
= 0;
2094 /* Ok, we're done. */
2098 /* Make sure that we're not trying to eliminate to the wrong hard frame
2102 microblaze_can_eliminate (const int from
, const int to
)
2104 return ((from
== RETURN_ADDRESS_POINTER_REGNUM
&& !leaf_function_p())
2105 || (to
== MB_ABI_SUB_RETURN_ADDR_REGNUM
&& leaf_function_p())
2106 || (from
!= RETURN_ADDRESS_POINTER_REGNUM
2107 && (to
== HARD_FRAME_POINTER_REGNUM
2108 || (to
== STACK_POINTER_REGNUM
&& !frame_pointer_needed
))));
2111 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
2112 pointer or argument pointer or the return address pointer. TO is either
2113 the stack pointer or hard frame pointer. */
2116 microblaze_initial_elimination_offset (int from
, int to
)
2118 HOST_WIDE_INT offset
;
2122 case FRAME_POINTER_REGNUM
:
2125 case ARG_POINTER_REGNUM
:
2126 if (to
== STACK_POINTER_REGNUM
|| to
== HARD_FRAME_POINTER_REGNUM
)
2127 offset
= compute_frame_size (get_frame_size ());
2131 case RETURN_ADDRESS_POINTER_REGNUM
:
2135 offset
= current_frame_info
.gp_offset
+
2136 ((UNITS_PER_WORD
- (POINTER_SIZE
/ BITS_PER_UNIT
)));
2144 /* Print operands using format code.
2146 The MicroBlaze specific codes are:
2148 'X' X is CONST_INT, prints 32 bits in hexadecimal format = "0x%08x",
2149 'x' X is CONST_INT, prints 16 bits in hexadecimal format = "0x%04x",
2150 'F' op is CONST_DOUBLE, print 32 bits in hex,
2151 'd' output integer constant in decimal,
2152 'z' if the operand is 0, use $0 instead of normal operand.
2153 'D' print second register of double-word register operand.
2154 'L' print low-order register of double-word register operand.
2155 'M' print high-order register of double-word register operand.
2156 'C' print part of opcode for a branch condition.
2157 'N' print part of opcode for a branch condition, inverted.
2158 'S' X is CODE_LABEL, print with prefix of "LS" (for embedded switch).
2159 'B' print 'z' for EQ, 'n' for NE
2160 'b' print 'n' for EQ, 'z' for NE
2161 'T' print 'f' for EQ, 't' for NE
2162 't' print 't' for EQ, 'f' for NE
2163 'm' Print 1<<operand.
2164 'i' Print 'i' if MEM operand has immediate value
2165 'y' Print 'y' if MEM operand is single register
2166 'o' Print operand address+4
2167 '?' Print 'd' if we use a branch with delay slot instead of normal branch.
2168 'h' Print high word of const_double (int or float) value as hex
2169 'j' Print low word of const_double (int or float) value as hex
2170 's' Print -1 if operand is negative, 0 if positive (sign extend)
2171 '@' Print the name of the temporary register (rMB_ABI_ASM_TEMP_REGNUM).
2172 '#' Print nop if the delay slot of a branch is not filled.
2176 print_operand (FILE * file
, rtx op
, int letter
)
2178 register enum rtx_code code
;
2180 if (PRINT_OPERAND_PUNCT_VALID_P (letter
))
2185 /* Conditionally add a 'd' to indicate filled delay slot. */
2186 if (final_sequence
!= NULL
)
2191 /* Conditionally add a nop in unfilled delay slot. */
2192 if (final_sequence
== NULL
)
2193 fputs ("nop\t\t# Unfilled delay slot\n", file
);
2197 fputs (reg_names
[GP_REG_FIRST
+ MB_ABI_ASM_TEMP_REGNUM
], file
);
2201 output_operand_lossage ("unknown punctuation '%c'", letter
);
2210 output_operand_lossage ("null pointer");
2214 code
= GET_CODE (op
);
2216 if (code
== SIGN_EXTEND
)
2217 op
= XEXP (op
, 0), code
= GET_CODE (op
);
2245 fatal_insn ("PRINT_OPERAND, invalid insn for %%C", op
);
2248 else if (letter
== 'N')
2274 fatal_insn ("PRINT_OPERAND, invalid insn for %%N", op
);
2277 else if (letter
== 'S')
2281 ASM_GENERATE_INTERNAL_LABEL (buffer
, "LS", CODE_LABEL_NUMBER (op
));
2282 assemble_name (file
, buffer
);
2285 /* Print 'i' for memory operands which have immediate values. */
2286 else if (letter
== 'i')
2290 struct microblaze_address_info info
;
2292 if (!microblaze_classify_address
2293 (&info
, XEXP (op
, 0), GET_MODE (op
), 1))
2294 fatal_insn ("insn contains an invalid address !", op
);
2299 case ADDRESS_CONST_INT
:
2300 case ADDRESS_SYMBOLIC
:
2301 case ADDRESS_GOTOFF
:
2305 case ADDRESS_REG_INDEX
:
2307 case ADDRESS_INVALID
:
2309 fatal_insn ("invalid address", op
);
2314 else if (code
== REG
|| code
== SUBREG
)
2316 register int regnum
;
2319 regnum
= REGNO (op
);
2321 regnum
= true_regnum (op
);
2323 if ((letter
== 'M' && !WORDS_BIG_ENDIAN
)
2324 || (letter
== 'L' && WORDS_BIG_ENDIAN
) || letter
== 'D')
2327 fprintf (file
, "%s", reg_names
[regnum
]);
2330 else if (code
== MEM
)
2333 rtx op4
= adjust_address (op
, GET_MODE (op
), 4);
2334 output_address (GET_MODE (op
), XEXP (op4
, 0));
2336 else if (letter
== 'y')
2338 rtx mem_reg
= XEXP (op
, 0);
2339 if (GET_CODE (mem_reg
) == REG
)
2341 register int regnum
= REGNO (mem_reg
);
2342 fprintf (file
, "%s", reg_names
[regnum
]);
2346 output_address (GET_MODE (op
), XEXP (op
, 0));
2348 else if (letter
== 'h' || letter
== 'j')
2351 if (code
== CONST_DOUBLE
)
2353 if (GET_MODE (op
) == DFmode
)
2354 REAL_VALUE_TO_TARGET_DOUBLE (*CONST_DOUBLE_REAL_VALUE (op
), val
);
2357 val
[0] = CONST_DOUBLE_HIGH (op
);
2358 val
[1] = CONST_DOUBLE_LOW (op
);
2361 else if (code
== CONST_INT
)
2363 val
[0] = (INTVAL (op
) & 0xffffffff00000000LL
) >> 32;
2364 val
[1] = INTVAL (op
) & 0x00000000ffffffffLL
;
2365 if (val
[0] == 0 && val
[1] < 0)
2369 fprintf (file
, "0x%8.8lx", (letter
== 'h') ? val
[0] : val
[1]);
2371 else if (code
== CONST_DOUBLE
)
2375 unsigned long value_long
;
2376 REAL_VALUE_TO_TARGET_SINGLE (*CONST_DOUBLE_REAL_VALUE (op
),
2378 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, value_long
);
2383 real_to_decimal (s
, CONST_DOUBLE_REAL_VALUE (op
), sizeof (s
), 0, 1);
2388 else if (code
== UNSPEC
)
2390 print_operand_address (file
, op
);
2393 else if (letter
== 'x' && GET_CODE (op
) == CONST_INT
)
2394 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, 0xffff & INTVAL (op
));
2396 else if (letter
== 'X' && GET_CODE (op
) == CONST_INT
)
2397 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, INTVAL (op
));
2399 else if (letter
== 'd' && GET_CODE (op
) == CONST_INT
)
2400 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, (INTVAL (op
)));
2402 else if (letter
== 'z' && GET_CODE (op
) == CONST_INT
&& INTVAL (op
) == 0)
2403 fputs (reg_names
[GP_REG_FIRST
], file
);
2405 else if (letter
== 's' && GET_CODE (op
) == CONST_INT
)
2406 if (INTVAL (op
) < 0)
2411 else if (letter
== 'd' || letter
== 'x' || letter
== 'X' || letter
== 's')
2412 output_operand_lossage ("letter %c was found & insn was not CONST_INT", letter
);
2414 else if (letter
== 'B')
2415 fputs (code
== EQ
? "z" : "n", file
);
2416 else if (letter
== 'b')
2417 fputs (code
== EQ
? "n" : "z", file
);
2418 else if (letter
== 'T')
2419 fputs (code
== EQ
? "f" : "t", file
);
2420 else if (letter
== 't')
2421 fputs (code
== EQ
? "t" : "f", file
);
2423 else if (code
== CONST
2424 && ((GET_CODE (XEXP (op
, 0)) == REG
)
2425 || (GET_CODE (XEXP (op
, 0)) == UNSPEC
)))
2427 print_operand (file
, XEXP (op
, 0), letter
);
2429 else if (code
== CONST
2430 && (GET_CODE (XEXP (op
, 0)) == PLUS
)
2431 && (GET_CODE (XEXP (XEXP (op
, 0), 0)) == REG
)
2432 && (GET_CODE (XEXP (XEXP (op
, 0), 1)) == CONST
))
2434 print_operand_address (file
, XEXP (op
, 0));
2436 else if (letter
== 'm')
2437 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, (1L << INTVAL (op
)));
2439 output_addr_const (file
, op
);
2442 /* A C compound statement to output to stdio stream STREAM the
2443 assembler syntax for an instruction operand that is a memory
2444 reference whose address is ADDR. ADDR is an RTL expression.
2446 Possible address classifications and output formats are,
2448 ADDRESS_REG "%0, r0"
2450 ADDRESS_REG with non-zero "%0, <addr_const>"
2453 ADDRESS_REG_INDEX "rA, RB"
2454 (if rA is r0, rA and rB are swapped)
2456 ADDRESS_CONST_INT "r0, <addr_const>"
2458 ADDRESS_SYMBOLIC "rBase, <addr_const>"
2459 (rBase is a base register suitable for the
2464 print_operand_address (FILE * file
, rtx addr
)
2466 struct microblaze_address_info info
;
2467 enum microblaze_address_type type
;
2468 if (!microblaze_classify_address (&info
, addr
, GET_MODE (addr
), 1))
2469 fatal_insn ("insn contains an invalid address !", addr
);
2475 fprintf (file
, "%s,", reg_names
[REGNO (info
.regA
)]);
2476 output_addr_const (file
, info
.offset
);
2478 case ADDRESS_REG_INDEX
:
2479 if (REGNO (info
.regA
) == 0)
2480 /* Make rB == r0 instead of rA == r0. This helps reduce read port
2482 fprintf (file
, "%s,%s", reg_names
[REGNO (info
.regB
)],
2483 reg_names
[REGNO (info
.regA
)]);
2484 else if (REGNO (info
.regB
) != 0)
2485 /* This is a silly swap to help Dhrystone. */
2486 fprintf (file
, "%s,%s", reg_names
[REGNO (info
.regB
)],
2487 reg_names
[REGNO (info
.regA
)]);
2489 case ADDRESS_CONST_INT
:
2490 fprintf (file
, "%s,", reg_names
[REGNO (info
.regA
)]);
2491 output_addr_const (file
, info
.offset
);
2493 case ADDRESS_SYMBOLIC
:
2494 case ADDRESS_GOTOFF
:
2498 fprintf (file
, "%s,", reg_names
[REGNO (info
.regA
)]);
2499 output_addr_const (file
, info
.symbol
);
2500 if (type
== ADDRESS_GOTOFF
)
2502 fputs ("@GOT", file
);
2504 else if (type
== ADDRESS_PLT
)
2506 fputs ("@PLT", file
);
2508 else if (type
== ADDRESS_TLS
)
2510 switch (info
.tls_type
)
2513 fputs ("@TLSGD", file
);
2516 fputs ("@TLSLDM", file
);
2519 fputs ("@TLSDTPREL", file
);
2527 case ADDRESS_INVALID
:
2528 fatal_insn ("invalid address", addr
);
2533 /* Emit either a label, .comm, or .lcomm directive, and mark that the symbol
2534 is used, so that we don't emit an .extern for it in
2535 microblaze_asm_file_end. */
2538 microblaze_declare_object (FILE * stream
, const char *name
,
2539 const char *section
, const char *fmt
, int size
)
2542 fputs (section
, stream
);
2543 assemble_name (stream
, name
);
2544 fprintf (stream
, fmt
, size
);
2547 /* Common code to emit the insns (or to write the instructions to a file)
2548 to save/restore registers.
2550 Other parts of the code assume that MICROBLAZE_TEMP1_REGNUM (aka large_reg)
2551 is not modified within save_restore_insns. */
2553 #define BITSET_P(VALUE,BIT) (((VALUE) & (1L << (BIT))) != 0)
2555 /* Save or restore instructions based on whether this is the prologue or
2556 epilogue. prologue is 1 for the prologue. */
2558 save_restore_insns (int prologue
)
2560 rtx base_reg_rtx
, reg_rtx
, mem_rtx
, /* msr_rtx, */ isr_reg_rtx
=
2562 rtx isr_msr_rtx
= 0, insn
;
2563 long mask
= current_frame_info
.mask
;
2564 HOST_WIDE_INT gp_offset
;
2567 if (frame_pointer_needed
2568 && !BITSET_P (mask
, HARD_FRAME_POINTER_REGNUM
- GP_REG_FIRST
))
2574 /* Save registers starting from high to low. The debuggers prefer at least
2575 the return register be stored at func+4, and also it allows us not to
2576 need a nop in the epilog if at least one register is reloaded in
2577 addition to return address. */
2579 /* Pick which pointer to use as a base register. For small frames, just
2580 use the stack pointer. Otherwise, use a temporary register. Save 2
2581 cycles if the save area is near the end of a large frame, by reusing
2582 the constant created in the prologue/epilogue to adjust the stack
2585 gp_offset
= current_frame_info
.gp_offset
;
2587 gcc_assert (gp_offset
> 0);
2589 base_reg_rtx
= stack_pointer_rtx
;
2591 /* For interrupt_handlers, need to save/restore the MSR. */
2592 if (microblaze_is_interrupt_variant ())
2594 isr_mem_rtx
= gen_rtx_MEM (SImode
,
2595 gen_rtx_PLUS (Pmode
, base_reg_rtx
,
2596 GEN_INT (current_frame_info
.
2600 /* Do not optimize in flow analysis. */
2601 MEM_VOLATILE_P (isr_mem_rtx
) = 1;
2602 isr_reg_rtx
= gen_rtx_REG (SImode
, MB_ABI_MSR_SAVE_REG
);
2603 isr_msr_rtx
= gen_rtx_REG (SImode
, ST_REG
);
2606 if (microblaze_is_interrupt_variant () && !prologue
)
2608 emit_move_insn (isr_reg_rtx
, isr_mem_rtx
);
2609 emit_move_insn (isr_msr_rtx
, isr_reg_rtx
);
2610 /* Do not optimize in flow analysis. */
2611 emit_insn (gen_rtx_USE (SImode
, isr_reg_rtx
));
2612 emit_insn (gen_rtx_USE (SImode
, isr_msr_rtx
));
2615 for (regno
= GP_REG_FIRST
; regno
<= GP_REG_LAST
; regno
++)
2617 if (BITSET_P (mask
, regno
- GP_REG_FIRST
))
2619 if (regno
== MB_ABI_SUB_RETURN_ADDR_REGNUM
)
2620 /* Don't handle here. Already handled as the first register. */
2623 reg_rtx
= gen_rtx_REG (SImode
, regno
);
2624 insn
= gen_rtx_PLUS (Pmode
, base_reg_rtx
, GEN_INT (gp_offset
));
2625 mem_rtx
= gen_rtx_MEM (SImode
, insn
);
2626 if (microblaze_is_interrupt_variant () || save_volatiles
)
2627 /* Do not optimize in flow analysis. */
2628 MEM_VOLATILE_P (mem_rtx
) = 1;
2632 insn
= emit_move_insn (mem_rtx
, reg_rtx
);
2633 RTX_FRAME_RELATED_P (insn
) = 1;
2637 insn
= emit_move_insn (reg_rtx
, mem_rtx
);
2640 gp_offset
+= GET_MODE_SIZE (SImode
);
2644 if (microblaze_is_interrupt_variant () && prologue
)
2646 emit_move_insn (isr_reg_rtx
, isr_msr_rtx
);
2647 emit_move_insn (isr_mem_rtx
, isr_reg_rtx
);
2649 /* Do not optimize in flow analysis. */
2650 emit_insn (gen_rtx_USE (SImode
, isr_reg_rtx
));
2651 emit_insn (gen_rtx_USE (SImode
, isr_msr_rtx
));
2654 /* Done saving and restoring */
2658 /* Set up the stack and frame (if desired) for the function. */
2660 microblaze_function_prologue (FILE * file
, HOST_WIDE_INT size ATTRIBUTE_UNUSED
)
2663 long fsiz
= current_frame_info
.total_size
;
2665 /* Get the function name the same way that toplev.c does before calling
2666 assemble_start_function. This is needed so that the name used here
2667 exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */
2668 fnname
= XSTR (XEXP (DECL_RTL (current_function_decl
), 0), 0);
2669 if (!flag_inhibit_size_directive
)
2671 fputs ("\t.ent\t", file
);
2672 if (interrupt_handler
&& strcmp (INTERRUPT_HANDLER_NAME
, fnname
))
2673 fputs ("_interrupt_handler", file
);
2674 else if (break_handler
&& strcmp (BREAK_HANDLER_NAME
, fnname
))
2675 fputs ("_break_handler", file
);
2676 else if (fast_interrupt
&& strcmp (FAST_INTERRUPT_NAME
, fnname
))
2677 fputs ("_fast_interrupt", file
);
2679 assemble_name (file
, fnname
);
2681 if (!microblaze_is_interrupt_variant ())
2682 ASM_OUTPUT_TYPE_DIRECTIVE (file
, fnname
, "function");
2685 assemble_name (file
, fnname
);
2686 fputs (":\n", file
);
2688 if (interrupt_handler
&& strcmp (INTERRUPT_HANDLER_NAME
, fnname
))
2689 fputs ("_interrupt_handler:\n", file
);
2690 if (break_handler
&& strcmp (BREAK_HANDLER_NAME
, fnname
))
2691 fputs ("_break_handler:\n", file
);
2692 if (!flag_inhibit_size_directive
)
2694 /* .frame FRAMEREG, FRAMESIZE, RETREG. */
2696 "\t.frame\t%s,%ld,%s\t\t# vars= %ld, regs= %d, args= %d\n",
2697 (reg_names
[(frame_pointer_needed
)
2698 ? HARD_FRAME_POINTER_REGNUM
:
2699 STACK_POINTER_REGNUM
]), fsiz
,
2700 reg_names
[MB_ABI_SUB_RETURN_ADDR_REGNUM
+ GP_REG_FIRST
],
2701 current_frame_info
.var_size
, current_frame_info
.num_gp
,
2702 crtl
->outgoing_args_size
);
2703 fprintf (file
, "\t.mask\t0x%08lx\n", current_frame_info
.mask
);
2707 /* Output extra assembler code at the end of a prologue. */
2709 microblaze_function_end_prologue (FILE * file
)
2711 if (TARGET_STACK_CHECK
)
2713 fprintf (file
, "\t# Stack Check Stub -- Start.\n\t");
2714 fprintf (file
, "ori\tr18,r0,_stack_end\n\t");
2715 fprintf (file
, "cmpu\tr18,r1,r18\n\t");
2716 fprintf (file
, "bgei\tr18,_stack_overflow_exit\n\t");
2717 fprintf (file
, "# Stack Check Stub -- End.\n");
2722 microblaze_elf_asm_cdtor (rtx symbol
, int priority
, bool is_ctor
)
2726 if (priority
!= DEFAULT_INIT_PRIORITY
)
2729 sprintf (buf
, "%s.%.5u",
2730 is_ctor
? ".ctors" : ".dtors",
2731 MAX_INIT_PRIORITY
- priority
);
2732 s
= get_section (buf
, SECTION_WRITE
, NULL_TREE
);
2739 switch_to_section (s
);
2740 assemble_align (POINTER_SIZE
);
2741 fputs ("\t.word\t", asm_out_file
);
2742 output_addr_const (asm_out_file
, symbol
);
2743 fputs ("\n", asm_out_file
);
2746 /* Add a function to the list of static constructors. */
2749 microblaze_elf_asm_constructor (rtx symbol
, int priority
)
2751 microblaze_elf_asm_cdtor (symbol
, priority
, /*is_ctor=*/true);
2754 /* Add a function to the list of static destructors. */
2757 microblaze_elf_asm_destructor (rtx symbol
, int priority
)
2759 microblaze_elf_asm_cdtor (symbol
, priority
, /*is_ctor=*/false);
2762 /* Expand the prologue into a bunch of separate insns. */
2765 microblaze_expand_prologue (void)
2769 const char *arg_name
= 0;
2770 tree fndecl
= current_function_decl
;
2771 tree fntype
= TREE_TYPE (fndecl
);
2772 tree fnargs
= DECL_ARGUMENTS (fndecl
);
2777 CUMULATIVE_ARGS args_so_far_v
;
2778 cumulative_args_t args_so_far
;
2779 rtx mem_rtx
, reg_rtx
;
2781 /* If struct value address is treated as the first argument, make it so. */
2782 if (aggregate_value_p (DECL_RESULT (fndecl
), fntype
)
2783 && !cfun
->returns_pcc_struct
)
2785 tree type
= build_pointer_type (fntype
);
2786 tree function_result_decl
= build_decl (BUILTINS_LOCATION
, PARM_DECL
,
2789 DECL_ARG_TYPE (function_result_decl
) = type
;
2790 TREE_CHAIN (function_result_decl
) = fnargs
;
2791 fnargs
= function_result_decl
;
2794 /* Determine the last argument, and get its name. */
2796 INIT_CUMULATIVE_ARGS (args_so_far_v
, fntype
, NULL_RTX
, 0, 0);
2797 args_so_far
= pack_cumulative_args (&args_so_far_v
);
2798 regno
= GP_ARG_FIRST
;
2800 for (cur_arg
= fnargs
; cur_arg
!= 0; cur_arg
= next_arg
)
2802 tree passed_type
= DECL_ARG_TYPE (cur_arg
);
2803 machine_mode passed_mode
= TYPE_MODE (passed_type
);
2806 if (TREE_ADDRESSABLE (passed_type
))
2808 passed_type
= build_pointer_type (passed_type
);
2809 passed_mode
= Pmode
;
2812 entry_parm
= targetm
.calls
.function_arg (args_so_far
, passed_mode
,
2819 /* passed in a register, so will get homed automatically. */
2820 if (GET_MODE (entry_parm
) == BLKmode
)
2821 words
= (int_size_in_bytes (passed_type
) + 3) / 4;
2823 words
= (GET_MODE_SIZE (GET_MODE (entry_parm
)) + 3) / 4;
2825 regno
= REGNO (entry_parm
) + words
- 1;
2829 regno
= GP_ARG_LAST
+ 1;
2833 targetm
.calls
.function_arg_advance (args_so_far
, passed_mode
,
2836 next_arg
= TREE_CHAIN (cur_arg
);
2839 if (DECL_NAME (cur_arg
))
2840 arg_name
= IDENTIFIER_POINTER (DECL_NAME (cur_arg
));
2846 /* Split parallel insn into a sequence of insns. */
2848 next_arg_reg
= targetm
.calls
.function_arg (args_so_far
, VOIDmode
,
2849 void_type_node
, true);
2850 if (next_arg_reg
!= 0 && GET_CODE (next_arg_reg
) == PARALLEL
)
2852 rtvec adjust
= XVEC (next_arg_reg
, 0);
2853 int num
= GET_NUM_ELEM (adjust
);
2855 for (i
= 0; i
< num
; i
++)
2857 rtx pattern
= RTVEC_ELT (adjust
, i
);
2858 emit_insn (pattern
);
2862 fsiz
= compute_frame_size (get_frame_size ());
2864 if (flag_stack_usage_info
)
2865 current_function_static_stack_size
= fsiz
;
2868 /* If this function is a varargs function, store any registers that
2869 would normally hold arguments ($5 - $10) on the stack. */
2870 if (((TYPE_ARG_TYPES (fntype
) != 0
2871 && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype
)))
2874 && ((arg_name
[0] == '_'
2875 && strcmp (arg_name
, "__builtin_va_alist") == 0)
2876 || (arg_name
[0] == 'v'
2877 && strcmp (arg_name
, "va_alist") == 0)))))
2879 int offset
= (regno
- GP_ARG_FIRST
+ 1) * UNITS_PER_WORD
;
2880 rtx ptr
= stack_pointer_rtx
;
2882 /* If we are doing svr4-abi, sp has already been decremented by fsiz. */
2883 for (; regno
<= GP_ARG_LAST
; regno
++)
2886 ptr
= gen_rtx_PLUS (Pmode
, stack_pointer_rtx
, GEN_INT (offset
));
2887 emit_move_insn (gen_rtx_MEM (SImode
, ptr
),
2888 gen_rtx_REG (SImode
, regno
));
2890 offset
+= GET_MODE_SIZE (SImode
);
2897 rtx fsiz_rtx
= GEN_INT (fsiz
);
2899 rtx_insn
*insn
= NULL
;
2900 insn
= emit_insn (gen_subsi3 (stack_pointer_rtx
, stack_pointer_rtx
,
2903 RTX_FRAME_RELATED_P (insn
) = 1;
2905 /* Handle SUB_RETURN_ADDR_REGNUM specially at first. */
2906 if (!crtl
->is_leaf
|| interrupt_handler
)
2908 mem_rtx
= gen_rtx_MEM (SImode
,
2909 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
2912 if (interrupt_handler
)
2913 /* Do not optimize in flow analysis. */
2914 MEM_VOLATILE_P (mem_rtx
) = 1;
2916 reg_rtx
= gen_rtx_REG (SImode
, MB_ABI_SUB_RETURN_ADDR_REGNUM
);
2917 insn
= emit_move_insn (mem_rtx
, reg_rtx
);
2918 RTX_FRAME_RELATED_P (insn
) = 1;
2921 /* _save_ registers for prologue. */
2922 save_restore_insns (1);
2924 if (frame_pointer_needed
)
2928 insn
= emit_insn (gen_movsi (hard_frame_pointer_rtx
,
2929 stack_pointer_rtx
));
2932 RTX_FRAME_RELATED_P (insn
) = 1;
2936 if ((flag_pic
== 2 || TLS_NEEDS_GOT
)
2937 && df_regs_ever_live_p (MB_ABI_PIC_ADDR_REGNUM
))
2939 SET_REGNO (pic_offset_table_rtx
, MB_ABI_PIC_ADDR_REGNUM
);
2940 emit_insn (gen_set_got (pic_offset_table_rtx
)); /* setting GOT. */
2943 /* If we are profiling, make sure no instructions are scheduled before
2944 the call to mcount. */
2947 emit_insn (gen_blockage ());
2950 /* Do necessary cleanup after a function to restore stack, frame, and regs. */
2952 #define RA_MASK ((long) 0x80000000) /* 1 << 31 */
2953 #define PIC_OFFSET_TABLE_MASK (1 << (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST))
2956 microblaze_function_epilogue (FILE * file ATTRIBUTE_UNUSED
,
2957 HOST_WIDE_INT size ATTRIBUTE_UNUSED
)
2961 /* Get the function name the same way that toplev.c does before calling
2962 assemble_start_function. This is needed so that the name used here
2963 exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */
2964 fnname
= XSTR (XEXP (DECL_RTL (current_function_decl
), 0), 0);
2966 if (!flag_inhibit_size_directive
)
2968 fputs ("\t.end\t", file
);
2969 if (interrupt_handler
&& !break_handler
)
2970 fputs ("_interrupt_handler", file
);
2971 else if (break_handler
)
2972 fputs ("_break_handler", file
);
2974 assemble_name (file
, fnname
);
2978 /* Reset state info for each function. */
2979 current_frame_info
= zero_frame_info
;
2981 /* Restore the output file if optimizing the GP (optimizing the GP causes
2982 the text to be diverted to a tempfile, so that data decls come before
2983 references to the data). */
2986 /* Expand the epilogue into a bunch of separate insns. */
2989 microblaze_expand_epilogue (void)
2991 HOST_WIDE_INT fsiz
= current_frame_info
.total_size
;
2992 rtx fsiz_rtx
= GEN_INT (fsiz
);
2996 /* In case of interrupt handlers use addki instead of addi for changing the
2997 stack pointer value. */
2999 if (microblaze_can_use_return_insn ())
3001 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode
,
3003 MB_ABI_SUB_RETURN_ADDR_REGNUM
)));
3009 /* Restore SUB_RETURN_ADDR_REGNUM at first. This is to prevent the
3010 sequence of load-followed by a use (in rtsd) in every prologue. Saves
3011 a load-use stall cycle :) This is also important to handle alloca.
3012 (See comments for if (frame_pointer_needed) below. */
3014 if (!crtl
->is_leaf
|| interrupt_handler
)
3017 gen_rtx_MEM (SImode
,
3018 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
, const0_rtx
));
3019 if (interrupt_handler
)
3020 /* Do not optimize in flow analysis. */
3021 MEM_VOLATILE_P (mem_rtx
) = 1;
3022 reg_rtx
= gen_rtx_REG (SImode
, MB_ABI_SUB_RETURN_ADDR_REGNUM
);
3023 emit_move_insn (reg_rtx
, mem_rtx
);
3026 /* It is important that this is done after we restore the return address
3027 register (above). When alloca is used, we want to restore the
3028 sub-routine return address only from the current stack top and not
3029 from the frame pointer (which we restore below). (frame_pointer + 0)
3030 might have been over-written since alloca allocates memory on the
3032 if (frame_pointer_needed
)
3033 emit_insn (gen_movsi (stack_pointer_rtx
, hard_frame_pointer_rtx
));
3035 /* _restore_ registers for epilogue. */
3036 save_restore_insns (0);
3037 emit_insn (gen_blockage ());
3038 emit_insn (gen_addsi3 (stack_pointer_rtx
, stack_pointer_rtx
, fsiz_rtx
));
3041 if (crtl
->calls_eh_return
)
3042 emit_insn (gen_addsi3 (stack_pointer_rtx
,
3044 gen_raw_REG (SImode
,
3045 MB_EH_STACKADJ_REGNUM
)));
3047 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode
, GP_REG_FIRST
+
3048 MB_ABI_SUB_RETURN_ADDR_REGNUM
)));
3052 /* Return nonzero if this function is known to have a null epilogue.
3053 This allows the optimizer to omit jumps to jumps if no stack
3057 microblaze_can_use_return_insn (void)
3059 if (!reload_completed
)
3062 if (df_regs_ever_live_p (MB_ABI_SUB_RETURN_ADDR_REGNUM
) || profile_flag
)
3065 if (current_frame_info
.initialized
)
3066 return current_frame_info
.total_size
== 0;
3068 return compute_frame_size (get_frame_size ()) == 0;
3071 /* Implement TARGET_SECONDARY_RELOAD. */
3074 microblaze_secondary_reload (bool in_p ATTRIBUTE_UNUSED
, rtx x ATTRIBUTE_UNUSED
,
3075 reg_class_t rclass
, machine_mode mode ATTRIBUTE_UNUSED
,
3076 secondary_reload_info
*sri ATTRIBUTE_UNUSED
)
3078 if (rclass
== ST_REGS
)
3085 microblaze_globalize_label (FILE * stream
, const char *name
)
3087 fputs ("\t.globl\t", stream
);
3088 if (microblaze_is_interrupt_variant ())
3090 if (interrupt_handler
&& strcmp (name
, INTERRUPT_HANDLER_NAME
))
3091 fputs (INTERRUPT_HANDLER_NAME
, stream
);
3092 else if (break_handler
&& strcmp (name
, BREAK_HANDLER_NAME
))
3093 fputs (BREAK_HANDLER_NAME
, stream
);
3094 else if (fast_interrupt
&& strcmp (name
, FAST_INTERRUPT_NAME
))
3095 fputs (FAST_INTERRUPT_NAME
, stream
);
3096 fputs ("\n\t.globl\t", stream
);
3098 assemble_name (stream
, name
);
3099 fputs ("\n", stream
);
3102 /* Returns true if decl should be placed into a "small data" section. */
3104 microblaze_elf_in_small_data_p (const_tree decl
)
3108 if (!TARGET_XLGPOPT
)
3111 /* We want to merge strings, so we never consider them small data. */
3112 if (TREE_CODE (decl
) == STRING_CST
)
3115 /* Functions are never in the small data area. */
3116 if (TREE_CODE (decl
) == FUNCTION_DECL
)
3119 if (TREE_CODE (decl
) == VAR_DECL
&& DECL_SECTION_NAME (decl
))
3121 const char *section
= DECL_SECTION_NAME (decl
);
3122 if (strcmp (section
, ".sdata") == 0
3123 || strcmp (section
, ".sdata2") == 0
3124 || strcmp (section
, ".sbss") == 0
3125 || strcmp (section
, ".sbss2") == 0)
3129 size
= int_size_in_bytes (TREE_TYPE (decl
));
3131 return (size
> 0 && size
<= microblaze_section_threshold
);
3136 microblaze_select_section (tree decl
, int reloc
, unsigned HOST_WIDE_INT align
)
3138 switch (categorize_decl_for_section (decl
, reloc
))
3140 case SECCAT_RODATA_MERGE_STR
:
3141 case SECCAT_RODATA_MERGE_STR_INIT
:
3142 /* MB binutils have various issues with mergeable string sections and
3143 relaxation/relocation. Currently, turning mergeable sections
3144 into regular readonly sections. */
3146 return readonly_data_section
;
3148 return default_elf_select_section (decl
, reloc
, align
);
3153 Encode info about sections into the RTL based on a symbol's declaration.
3154 The default definition of this hook, default_encode_section_info in
3155 `varasm.c', sets a number of commonly-useful bits in SYMBOL_REF_FLAGS. */
3158 microblaze_encode_section_info (tree decl
, rtx rtl
, int first
)
3160 default_encode_section_info (decl
, rtl
, first
);
3164 expand_pic_symbol_ref (machine_mode mode ATTRIBUTE_UNUSED
, rtx op
)
3167 result
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, op
), UNSPEC_GOTOFF
);
3168 result
= gen_rtx_CONST (Pmode
, result
);
3169 result
= gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
, result
);
3170 result
= gen_const_mem (Pmode
, result
);
3175 microblaze_asm_output_mi_thunk (FILE *file
, tree thunk_fndecl ATTRIBUTE_UNUSED
,
3176 HOST_WIDE_INT delta
, HOST_WIDE_INT vcall_offset
,
3179 rtx this_rtx
, funexp
;
3182 reload_completed
= 1;
3183 epilogue_completed
= 1;
3185 /* Mark the end of the (empty) prologue. */
3186 emit_note (NOTE_INSN_PROLOGUE_END
);
3188 /* Find the "this" pointer. If the function returns a structure,
3189 the structure return pointer is in MB_ABI_FIRST_ARG_REGNUM. */
3190 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function
)), function
))
3191 this_rtx
= gen_rtx_REG (Pmode
, (MB_ABI_FIRST_ARG_REGNUM
+ 1));
3193 this_rtx
= gen_rtx_REG (Pmode
, MB_ABI_FIRST_ARG_REGNUM
);
3195 /* Apply the constant offset, if required. */
3197 emit_insn (gen_addsi3 (this_rtx
, this_rtx
, GEN_INT (delta
)));
3199 /* Apply the offset from the vtable, if required. */
3202 rtx vcall_offset_rtx
= GEN_INT (vcall_offset
);
3203 rtx temp1
= gen_rtx_REG (Pmode
, MB_ABI_TEMP1_REGNUM
);
3205 emit_move_insn (temp1
, gen_rtx_MEM (Pmode
, this_rtx
));
3207 rtx loc
= gen_rtx_PLUS (Pmode
, temp1
, vcall_offset_rtx
);
3208 emit_move_insn (temp1
, gen_rtx_MEM (Pmode
, loc
));
3210 emit_insn (gen_addsi3 (this_rtx
, this_rtx
, temp1
));
3213 /* Generate a tail call to the target function. */
3214 if (!TREE_USED (function
))
3216 assemble_external (function
);
3217 TREE_USED (function
) = 1;
3220 funexp
= XEXP (DECL_RTL (function
), 0);
3221 rtx temp2
= gen_rtx_REG (Pmode
, MB_ABI_TEMP2_REGNUM
);
3224 emit_move_insn (temp2
, expand_pic_symbol_ref (Pmode
, funexp
));
3226 emit_move_insn (temp2
, funexp
);
3228 emit_insn (gen_indirect_jump (temp2
));
3230 /* Run just enough of rest_of_compilation. This sequence was
3231 "borrowed" from rs6000.c. */
3232 insn
= get_insns ();
3233 shorten_branches (insn
);
3234 final_start_function (insn
, file
, 1);
3235 final (insn
, file
, 1);
3236 final_end_function ();
3238 reload_completed
= 0;
3239 epilogue_completed
= 0;
3243 microblaze_expand_move (machine_mode mode
, rtx operands
[])
3250 if (!register_operand (op0
, SImode
)
3251 && !register_operand (op1
, SImode
)
3252 && (GET_CODE (op1
) != CONST_INT
|| INTVAL (op1
) != 0))
3254 rtx temp
= force_reg (SImode
, op1
);
3255 emit_move_insn (op0
, temp
);
3258 /* If operands[1] is a constant address invalid for pic, then we need to
3259 handle it just like LEGITIMIZE_ADDRESS does. */
3260 if (GET_CODE (op1
) == SYMBOL_REF
|| GET_CODE (op1
) == LABEL_REF
)
3263 if (microblaze_tls_symbol_p(op1
))
3265 result
= microblaze_legitimize_tls_address (op1
, NULL_RTX
);
3266 emit_move_insn (op0
, result
);
3271 if (reload_in_progress
)
3272 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
3273 result
= expand_pic_symbol_ref (mode
, op1
);
3274 emit_move_insn (op0
, result
);
3278 /* Handle Case of (const (plus symbol const_int)). */
3279 if (GET_CODE (op1
) == CONST
&& GET_CODE (XEXP (op1
,0)) == PLUS
)
3283 p0
= XEXP (XEXP (op1
, 0), 0);
3284 p1
= XEXP (XEXP (op1
, 0), 1);
3286 if ((GET_CODE (p1
) == CONST_INT
)
3287 && ((GET_CODE (p0
) == UNSPEC
)
3288 || ((GET_CODE (p0
) == SYMBOL_REF
|| GET_CODE (p0
) == LABEL_REF
)
3289 && (flag_pic
== 2 || microblaze_tls_symbol_p (p0
)
3290 || !SMALL_INT (p1
)))))
3292 rtx temp
= force_reg (SImode
, p0
);
3295 if (flag_pic
&& reload_in_progress
)
3296 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
3297 emit_move_insn (op0
, gen_rtx_PLUS (SImode
, temp
, temp2
));
3304 /* Expand shift operations. */
3306 microblaze_expand_shift (rtx operands
[])
3308 gcc_assert ((GET_CODE (operands
[2]) == CONST_INT
)
3309 || (GET_CODE (operands
[2]) == REG
)
3310 || (GET_CODE (operands
[2]) == SUBREG
));
3312 /* Shift by one -- generate pattern. */
3313 if ((GET_CODE (operands
[2]) == CONST_INT
) && (INTVAL (operands
[2]) == 1))
3316 /* Have barrel shifter and shift > 1: use it. */
3317 if (TARGET_BARREL_SHIFT
)
3320 gcc_assert ((GET_CODE (operands
[0]) == REG
)
3321 || (GET_CODE (operands
[0]) == SUBREG
)
3322 || (GET_CODE (operands
[1]) == REG
)
3323 || (GET_CODE (operands
[1]) == SUBREG
));
3325 /* Shift by zero -- copy regs if necessary. */
3326 if (operands
[2] == const0_rtx
3327 && !rtx_equal_p (operands
[0], operands
[1]))
3329 emit_insn (gen_movsi (operands
[0], operands
[1]));
3336 /* Return an RTX indicating where the return address to the
3337 calling function can be found. */
3339 microblaze_return_addr (int count
, rtx frame ATTRIBUTE_UNUSED
)
3344 return get_hard_reg_initial_val (Pmode
,
3345 MB_ABI_SUB_RETURN_ADDR_REGNUM
);
3349 microblaze_eh_return (rtx op0
)
3351 emit_insn (gen_movsi (gen_rtx_MEM (Pmode
, stack_pointer_rtx
), op0
));
3354 /* Queue an .ident string in the queue of top-level asm statements.
3355 If the string size is below the threshold, put it into .sdata2.
3356 If the front-end is done, we must be being called from toplev.c.
3357 In that case, do nothing. */
3359 microblaze_asm_output_ident (const char *string
)
3361 const char *section_asm_op
;
3365 if (symtab
->state
!= PARSING
)
3368 size
= strlen (string
) + 1;
3369 if (size
<= microblaze_section_threshold
)
3370 section_asm_op
= SDATA2_SECTION_ASM_OP
;
3372 section_asm_op
= READONLY_DATA_SECTION_ASM_OP
;
3374 buf
= ACONCAT ((section_asm_op
, "\n\t.ascii \"", string
, "\\0\"\n", NULL
));
3375 symtab
->finalize_toplevel_asm (build_string (strlen (buf
), buf
));
3379 microblaze_elf_asm_init_sections (void)
3382 = get_unnamed_section (SECTION_WRITE
, output_section_asm_op
,
3383 SDATA2_SECTION_ASM_OP
);
3386 /* Generate assembler code for constant parts of a trampoline. */
3389 microblaze_asm_trampoline_template (FILE *f
)
3391 fprintf (f
, "\tmfs r18, rpc\n");
3392 fprintf (f
, "\tlwi r3, r18, 16\n");
3393 fprintf (f
, "\tlwi r18, r18, 20\n");
3394 fprintf (f
, "\tbra r18\n");
3395 /* fprintf (f, "\t.word\t0x00000000\t\t# <function address>\n"); */
3396 /* fprintf (f, "\t.word\t0x00000000\t\t# <static chain value>\n"); */
3399 /* Implement TARGET_TRAMPOLINE_INIT. */
3402 microblaze_trampoline_init (rtx m_tramp
, tree fndecl
, rtx chain_value
)
3404 rtx fnaddr
= XEXP (DECL_RTL (fndecl
), 0);
3407 emit_block_move (m_tramp
, assemble_trampoline_template (),
3408 GEN_INT (6*UNITS_PER_WORD
), BLOCK_OP_NORMAL
);
3410 mem
= adjust_address (m_tramp
, SImode
, 16);
3411 emit_move_insn (mem
, chain_value
);
3412 mem
= adjust_address (m_tramp
, SImode
, 20);
3413 emit_move_insn (mem
, fnaddr
);
3416 /* Generate conditional branch -- first, generate test condition,
3417 second, generate correct branch instruction. */
3420 microblaze_expand_conditional_branch (machine_mode mode
, rtx operands
[])
3422 enum rtx_code code
= GET_CODE (operands
[0]);
3423 rtx cmp_op0
= operands
[1];
3424 rtx cmp_op1
= operands
[2];
3425 rtx label1
= operands
[3];
3426 rtx comp_reg
= gen_reg_rtx (SImode
);
3429 gcc_assert ((GET_CODE (cmp_op0
) == REG
) || (GET_CODE (cmp_op0
) == SUBREG
));
3431 /* If comparing against zero, just test source reg. */
3432 if (cmp_op1
== const0_rtx
)
3435 condition
= gen_rtx_fmt_ee (signed_condition (code
), SImode
, comp_reg
, const0_rtx
);
3436 emit_jump_insn (gen_condjump (condition
, label1
));
3439 else if (code
== EQ
|| code
== NE
)
3441 /* Use xor for equal/not-equal comparison. */
3442 emit_insn (gen_xorsi3 (comp_reg
, cmp_op0
, cmp_op1
));
3443 condition
= gen_rtx_fmt_ee (signed_condition (code
), SImode
, comp_reg
, const0_rtx
);
3444 emit_jump_insn (gen_condjump (condition
, label1
));
3448 /* Generate compare and branch in single instruction. */
3449 cmp_op1
= force_reg (mode
, cmp_op1
);
3450 condition
= gen_rtx_fmt_ee (code
, mode
, cmp_op0
, cmp_op1
);
3451 emit_jump_insn (gen_branch_compare(condition
, cmp_op0
, cmp_op1
, label1
));
3456 microblaze_expand_conditional_branch_reg (machine_mode mode
, rtx operands
[])
3458 enum rtx_code code
= GET_CODE (operands
[0]);
3459 rtx cmp_op0
= operands
[1];
3460 rtx cmp_op1
= operands
[2];
3461 rtx label1
= operands
[3];
3462 rtx comp_reg
= gen_reg_rtx (SImode
);
3465 gcc_assert ((GET_CODE (cmp_op0
) == REG
)
3466 || (GET_CODE (cmp_op0
) == SUBREG
));
3468 /* If comparing against zero, just test source reg. */
3469 if (cmp_op1
== const0_rtx
)
3472 condition
= gen_rtx_fmt_ee (signed_condition (code
),
3473 SImode
, comp_reg
, const0_rtx
);
3474 emit_jump_insn (gen_condjump (condition
, label1
));
3476 else if (code
== EQ
)
3478 emit_insn (gen_seq_internal_pat (comp_reg
,
3480 condition
= gen_rtx_EQ (SImode
, comp_reg
, const0_rtx
);
3481 emit_jump_insn (gen_condjump (condition
, label1
));
3483 else if (code
== NE
)
3485 emit_insn (gen_sne_internal_pat (comp_reg
, cmp_op0
,
3487 condition
= gen_rtx_NE (SImode
, comp_reg
, const0_rtx
);
3488 emit_jump_insn (gen_condjump (condition
, label1
));
3492 /* Generate compare and branch in single instruction. */
3493 cmp_op1
= force_reg (mode
, cmp_op1
);
3494 condition
= gen_rtx_fmt_ee (code
, mode
, cmp_op0
, cmp_op1
);
3495 emit_jump_insn (gen_branch_compare (condition
, cmp_op0
,
3501 microblaze_expand_conditional_branch_sf (rtx operands
[])
3504 rtx cmp_op0
= XEXP (operands
[0], 0);
3505 rtx cmp_op1
= XEXP (operands
[0], 1);
3506 rtx comp_reg
= gen_reg_rtx (SImode
);
3508 emit_insn (gen_cstoresf4 (comp_reg
, operands
[0], cmp_op0
, cmp_op1
));
3509 condition
= gen_rtx_NE (SImode
, comp_reg
, const0_rtx
);
3510 emit_jump_insn (gen_condjump (condition
, operands
[3]));
3513 /* Implement TARGET_FRAME_POINTER_REQUIRED. */
3516 microblaze_frame_pointer_required (void)
3518 /* If the function contains dynamic stack allocations, we need to
3519 use the frame pointer to access the static parts of the frame. */
3520 if (cfun
->calls_alloca
)
3526 microblaze_expand_divide (rtx operands
[])
3528 /* Table lookup software divides. Works for all (nr/dr) where (0 <= nr,dr <= 15). */
3530 rtx regt1
= gen_reg_rtx (SImode
);
3531 rtx reg18
= gen_rtx_REG (SImode
, R_TMP
);
3532 rtx regqi
= gen_reg_rtx (QImode
);
3533 rtx_code_label
*div_label
= gen_label_rtx ();
3534 rtx_code_label
*div_end_label
= gen_label_rtx ();
3535 rtx div_table_rtx
= gen_rtx_SYMBOL_REF (QImode
,"_divsi3_table");
3538 rtx_insn
*jump
, *cjump
, *insn
;
3540 insn
= emit_insn (gen_iorsi3 (regt1
, operands
[1], operands
[2]));
3541 cjump
= emit_jump_insn_after (gen_cbranchsi4 (
3542 gen_rtx_GTU (SImode
, regt1
, GEN_INT (15)),
3543 regt1
, GEN_INT (15), div_label
), insn
);
3544 LABEL_NUSES (div_label
) = 1;
3545 JUMP_LABEL (cjump
) = div_label
;
3546 emit_insn (gen_rtx_CLOBBER (SImode
, reg18
));
3548 emit_insn (gen_ashlsi3_bshift (regt1
, operands
[1], GEN_INT(4)));
3549 emit_insn (gen_addsi3 (regt1
, regt1
, operands
[2]));
3550 mem_rtx
= gen_rtx_MEM (QImode
,
3551 gen_rtx_PLUS (Pmode
, regt1
, div_table_rtx
));
3553 insn
= emit_insn (gen_movqi (regqi
, mem_rtx
));
3554 insn
= emit_insn (gen_movsi (operands
[0], gen_rtx_SUBREG (SImode
, regqi
, 0)));
3555 jump
= emit_jump_insn_after (gen_jump (div_end_label
), insn
);
3556 JUMP_LABEL (jump
) = div_end_label
;
3557 LABEL_NUSES (div_end_label
) = 1;
3560 emit_label (div_label
);
3561 ret
= emit_library_call_value (gen_rtx_SYMBOL_REF (Pmode
, "__divsi3"),
3562 operands
[0], LCT_NORMAL
,
3563 GET_MODE (operands
[0]), 2, operands
[1],
3564 GET_MODE (operands
[1]), operands
[2],
3565 GET_MODE (operands
[2]));
3566 if (ret
!= operands
[0])
3567 emit_move_insn (operands
[0], ret
);
3569 emit_label (div_end_label
);
3570 emit_insn (gen_blockage ());
3573 /* Implement TARGET_FUNCTION_VALUE. */
3575 microblaze_function_value (const_tree valtype
,
3576 const_tree func ATTRIBUTE_UNUSED
,
3577 bool outgoing ATTRIBUTE_UNUSED
)
3579 return LIBCALL_VALUE (TYPE_MODE (valtype
));
3582 /* Implement TARGET_SCHED_ADJUST_COST. */
3584 microblaze_adjust_cost (rtx_insn
*, int dep_type
, rtx_insn
*, int cost
,
3587 if (dep_type
== REG_DEP_OUTPUT
|| dep_type
== 0)
3592 /* Implement TARGET_LEGITIMATE_CONSTANT_P.
3594 At present, GAS doesn't understand li.[sd], so don't allow it
3595 to be generated at present. */
3597 microblaze_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED
, rtx x
)
3600 if (microblaze_cannot_force_const_mem(mode
, x
))
3603 if (GET_CODE (x
) == CONST_DOUBLE
)
3605 return microblaze_const_double_ok (x
, GET_MODE (x
));
3608 /* Handle Case of (const (plus unspec const_int)). */
3609 if (GET_CODE (x
) == CONST
&& GET_CODE (XEXP (x
,0)) == PLUS
)
3613 p0
= XEXP (XEXP (x
, 0), 0);
3614 p1
= XEXP (XEXP (x
, 0), 1);
3616 if (GET_CODE(p1
) == CONST_INT
)
3618 /* Const offset from UNSPEC is not supported. */
3619 if ((GET_CODE (p0
) == UNSPEC
))
3622 if ((GET_CODE (p0
) == SYMBOL_REF
|| GET_CODE (p0
) == LABEL_REF
)
3623 && (microblaze_tls_symbol_p (p0
) || !SMALL_INT (p1
)))
3632 get_branch_target (rtx branch
)
3634 if (CALL_P (branch
))
3638 call
= XVECEXP (PATTERN (branch
), 0, 0);
3639 if (GET_CODE (call
) == SET
)
3640 call
= SET_SRC (call
);
3641 if (GET_CODE (call
) != CALL
)
3643 return XEXP (XEXP (call
, 0), 0);
3649 /* Heuristics to identify where to insert at the
3650 fall through path of the caller function. If there
3651 is a call after the caller branch delay slot then
3652 we dont generate the instruction prefetch instruction.
3654 Scan up to 32 instructions after the call and checks
3655 for the JUMP and call instruction . If there is a call
3656 or JUMP instruction in the range of 32 instruction "wic"
3657 instruction wont be generated. Otherwise insert the "wic"
3658 instruction in the fall through of the call instruction
3659 four instruction after the call. before_4 is used for
3660 the position to insert "wic" instructions. before_16 is
3661 used to check for call and JUMP instruction for first
3665 insert_wic_for_ilb_runout (rtx_insn
*first
)
3668 rtx_insn
*before_4
= 0;
3669 rtx_insn
*before_16
= 0;
3670 int addr_offset
= 0;
3672 int wic_addr0
= 128 * 4;
3674 int first_addr
= INSN_ADDRESSES (INSN_UID (first
));
3676 for (insn
= first
; insn
; insn
= NEXT_INSN (insn
))
3679 addr_offset
= INSN_ADDRESSES (INSN_UID (insn
)) - first_addr
;
3680 length
= get_attr_length (insn
);
3681 if (before_4
== 0 && addr_offset
+ length
>= 4 * 4)
3686 if (before_16
== 0 && addr_offset
+ length
>= 14 * 4)
3688 if (CALL_P (insn
) || tablejump_p (insn
, 0, 0))
3690 if (addr_offset
+ length
>= 32 * 4)
3692 gcc_assert (before_4
&& before_16
);
3693 if (wic_addr0
> 4 * 4)
3696 emit_insn_before (gen_iprefetch
3697 (gen_int_mode (addr_offset
, SImode
)),
3699 recog_memoized (insn
);
3700 INSN_LOCATION (insn
) = INSN_LOCATION (before_4
);
3701 INSN_ADDRESSES_NEW (insn
, INSN_ADDRESSES (INSN_UID (before_4
)));
3708 /* Insert instruction prefetch instruction at the fall
3709 through path of the function call. */
3716 basic_block bb
, prev
= 0;
3717 rtx branch_target
= 0;
3719 shorten_branches (get_insns ());
3721 for (i
= 0; i
< n_basic_blocks_for_fn (cfun
) - 1; i
++)
3725 bool simple_loop
= false;
3727 bb
= BASIC_BLOCK_FOR_FN (cfun
, i
);
3732 if ((prev
!= 0) && (prev
!= bb
))
3737 FOR_EACH_EDGE (e
, ei
, bb
->preds
)
3745 for (insn
= BB_END (bb
); insn
; insn
= PREV_INSN (insn
))
3747 if (INSN_P (insn
) && !simple_loop
3750 if ((branch_target
= get_branch_target (insn
)))
3751 insert_wic_for_ilb_runout (
3752 next_active_insn (next_active_insn (insn
)));
3754 if (insn
== BB_HEAD (bb
))
3760 /* The reorg function defined through the macro
3761 TARGET_MACHINE_DEPENDENT_REORG. */
3764 microblaze_machine_dependent_reorg (void)
3766 if (TARGET_PREFETCH
)
3768 compute_bb_for_insn ();
3769 loop_optimizer_init (AVOID_CFG_MODIFICATIONS
);
3770 shorten_branches (get_insns ());
3772 loop_optimizer_finalize ();
3773 free_bb_for_insn ();
3778 #undef TARGET_ENCODE_SECTION_INFO
3779 #define TARGET_ENCODE_SECTION_INFO microblaze_encode_section_info
3781 #undef TARGET_ASM_GLOBALIZE_LABEL
3782 #define TARGET_ASM_GLOBALIZE_LABEL microblaze_globalize_label
3784 #undef TARGET_ASM_FUNCTION_PROLOGUE
3785 #define TARGET_ASM_FUNCTION_PROLOGUE microblaze_function_prologue
3787 #undef TARGET_ASM_FUNCTION_EPILOGUE
3788 #define TARGET_ASM_FUNCTION_EPILOGUE microblaze_function_epilogue
3790 #undef TARGET_RTX_COSTS
3791 #define TARGET_RTX_COSTS microblaze_rtx_costs
3793 #undef TARGET_CANNOT_FORCE_CONST_MEM
3794 #define TARGET_CANNOT_FORCE_CONST_MEM microblaze_cannot_force_const_mem
3796 #undef TARGET_ADDRESS_COST
3797 #define TARGET_ADDRESS_COST microblaze_address_cost
3799 #undef TARGET_ATTRIBUTE_TABLE
3800 #define TARGET_ATTRIBUTE_TABLE microblaze_attribute_table
3802 #undef TARGET_IN_SMALL_DATA_P
3803 #define TARGET_IN_SMALL_DATA_P microblaze_elf_in_small_data_p
3805 #undef TARGET_ASM_SELECT_SECTION
3806 #define TARGET_ASM_SELECT_SECTION microblaze_select_section
3808 #undef TARGET_HAVE_SRODATA_SECTION
3809 #define TARGET_HAVE_SRODATA_SECTION true
3811 #undef TARGET_ASM_FUNCTION_END_PROLOGUE
3812 #define TARGET_ASM_FUNCTION_END_PROLOGUE \
3813 microblaze_function_end_prologue
3815 #undef TARGET_ARG_PARTIAL_BYTES
3816 #define TARGET_ARG_PARTIAL_BYTES function_arg_partial_bytes
3818 #undef TARGET_FUNCTION_ARG
3819 #define TARGET_FUNCTION_ARG microblaze_function_arg
3821 #undef TARGET_FUNCTION_ARG_ADVANCE
3822 #define TARGET_FUNCTION_ARG_ADVANCE microblaze_function_arg_advance
3824 #undef TARGET_CAN_ELIMINATE
3825 #define TARGET_CAN_ELIMINATE microblaze_can_eliminate
3827 #undef TARGET_LEGITIMIZE_ADDRESS
3828 #define TARGET_LEGITIMIZE_ADDRESS microblaze_legitimize_address
3830 #undef TARGET_LEGITIMATE_ADDRESS_P
3831 #define TARGET_LEGITIMATE_ADDRESS_P microblaze_legitimate_address_p
3834 #define TARGET_LRA_P hook_bool_void_false
3836 #undef TARGET_FRAME_POINTER_REQUIRED
3837 #define TARGET_FRAME_POINTER_REQUIRED microblaze_frame_pointer_required
3839 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
3840 #define TARGET_ASM_TRAMPOLINE_TEMPLATE microblaze_asm_trampoline_template
3842 #undef TARGET_TRAMPOLINE_INIT
3843 #define TARGET_TRAMPOLINE_INIT microblaze_trampoline_init
3845 #undef TARGET_PROMOTE_FUNCTION_MODE
3846 #define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
3848 #undef TARGET_FUNCTION_VALUE
3849 #define TARGET_FUNCTION_VALUE microblaze_function_value
3851 #undef TARGET_SECONDARY_RELOAD
3852 #define TARGET_SECONDARY_RELOAD microblaze_secondary_reload
3854 #undef TARGET_ASM_OUTPUT_MI_THUNK
3855 #define TARGET_ASM_OUTPUT_MI_THUNK microblaze_asm_output_mi_thunk
3857 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
3858 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true
3860 #undef TARGET_SCHED_ADJUST_COST
3861 #define TARGET_SCHED_ADJUST_COST microblaze_adjust_cost
3863 #undef TARGET_ASM_INIT_SECTIONS
3864 #define TARGET_ASM_INIT_SECTIONS microblaze_elf_asm_init_sections
3866 #undef TARGET_OPTION_OVERRIDE
3867 #define TARGET_OPTION_OVERRIDE microblaze_option_override
3869 #undef TARGET_LEGITIMATE_CONSTANT_P
3870 #define TARGET_LEGITIMATE_CONSTANT_P microblaze_legitimate_constant_p
3872 #undef TARGET_MACHINE_DEPENDENT_REORG
3873 #define TARGET_MACHINE_DEPENDENT_REORG microblaze_machine_dependent_reorg
3875 struct gcc_target targetm
= TARGET_INITIALIZER
;
3877 #include "gt-microblaze.h"