1 /* Subroutines used for code generation on Xilinx MicroBlaze.
2 Copyright (C) 2009-2014 Free Software Foundation, Inc.
4 Contributed by Michael Eager <eager@eagercon.com>.
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published
10 by the Free Software Foundation; either version 3, or (at your
11 option) any later version.
13 GCC is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16 License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. */
24 #include "coretypes.h"
28 #include "hard-reg-set.h"
30 #include "insn-config.h"
31 #include "conditions.h"
32 #include "insn-flags.h"
33 #include "insn-attr.h"
37 #include "stor-layout.h"
47 #include "target-def.h"
52 #include "diagnostic-core.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
, enum 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 REAL_VALUE_FROM_CONST_DOUBLE (d
, op
);
264 if (REAL_VALUE_ISNAN (d
))
267 if (REAL_VALUE_NEGATIVE (d
))
268 d
= real_value_negate (&d
);
272 if (REAL_VALUES_LESS (d
, dfhigh
) && REAL_VALUES_LESS (dflow
, d
))
277 if (REAL_VALUES_LESS (d
, sfhigh
) && REAL_VALUES_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
, enum 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
, enum 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
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 enum 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;
444 microblaze_tls_operand_p_1 (rtx
*x
, void *data ATTRIBUTE_UNUSED
)
446 if (GET_CODE (*x
) == SYMBOL_REF
)
447 return SYMBOL_REF_TLS_MODEL (*x
) != 0;
449 /* Don't recurse into UNSPEC_TLS looking for TLS symbols; these are
450 TLS offsets, not real symbol references. */
451 if (GET_CODE (*x
) == UNSPEC
&& XINT (*x
, 1) == UNSPEC_TLS
)
457 /* Return TRUE if X contains any TLS symbol references. */
460 microblaze_tls_referenced_p (rtx x
)
462 if (!TARGET_HAVE_TLS
)
465 return for_each_rtx (&x
, microblaze_tls_operand_p_1
, NULL
);
469 microblaze_cannot_force_const_mem (enum machine_mode mode ATTRIBUTE_UNUSED
, rtx x
)
471 return microblaze_tls_referenced_p(x
);
474 /* Return TRUE if X references a SYMBOL_REF. */
476 symbol_mentioned_p (rtx x
)
481 if (GET_CODE (x
) == SYMBOL_REF
)
484 /* UNSPEC entries for a symbol include the SYMBOL_REF, but they
485 are constant offsets, not symbols. */
486 if (GET_CODE (x
) == UNSPEC
)
489 fmt
= GET_RTX_FORMAT (GET_CODE (x
));
491 for (i
= GET_RTX_LENGTH (GET_CODE (x
)) - 1; i
>= 0; i
--)
497 for (j
= XVECLEN (x
, i
) - 1; j
>= 0; j
--)
498 if (symbol_mentioned_p (XVECEXP (x
, i
, j
)))
501 else if (fmt
[i
] == 'e' && symbol_mentioned_p (XEXP (x
, i
)))
508 /* Return TRUE if X references a LABEL_REF. */
510 label_mentioned_p (rtx x
)
515 if (GET_CODE (x
) == LABEL_REF
)
518 /* UNSPEC entries for a symbol include a LABEL_REF for the referencing
519 instruction, but they are constant offsets, not symbols. */
520 if (GET_CODE (x
) == UNSPEC
)
523 fmt
= GET_RTX_FORMAT (GET_CODE (x
));
524 for (i
= GET_RTX_LENGTH (GET_CODE (x
)) - 1; i
>= 0; i
--)
530 for (j
= XVECLEN (x
, i
) - 1; j
>= 0; j
--)
531 if (label_mentioned_p (XVECEXP (x
, i
, j
)))
534 else if (fmt
[i
] == 'e' && label_mentioned_p (XEXP (x
, i
)))
542 tls_mentioned_p (rtx x
)
544 switch (GET_CODE (x
))
547 return tls_mentioned_p (XEXP (x
, 0));
550 if (XINT (x
, 1) == UNSPEC_TLS
)
559 load_tls_operand (rtx x
, rtx reg
)
564 reg
= gen_reg_rtx (Pmode
);
566 tmp
= gen_rtx_CONST (Pmode
, x
);
568 emit_insn (gen_rtx_SET (VOIDmode
, reg
,
569 gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
, tmp
)));
575 microblaze_call_tls_get_addr (rtx x
, rtx reg
, rtx
*valuep
, int reloc
)
580 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
584 tls_entry
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (2, x
, GEN_INT (reloc
)),
587 reg
= load_tls_operand (tls_entry
, reg
);
589 *valuep
= emit_library_call_value (get_tls_get_addr (), NULL_RTX
,
590 LCT_PURE
, /* LCT_CONST? */
591 Pmode
, 1, reg
, Pmode
);
593 insns
= get_insns ();
600 microblaze_legitimize_tls_address(rtx x
, rtx reg
)
602 rtx dest
, ret
, eqv
, addend
;
604 enum tls_model model
;
605 model
= SYMBOL_REF_TLS_MODEL (x
);
609 case TLS_MODEL_LOCAL_DYNAMIC
:
610 case TLS_MODEL_GLOBAL_DYNAMIC
:
611 case TLS_MODEL_INITIAL_EXEC
:
612 insns
= microblaze_call_tls_get_addr (x
, reg
, &ret
, TLS_GD
);
613 dest
= gen_reg_rtx (Pmode
);
614 emit_libcall_block (insns
, dest
, ret
, x
);
617 case TLS_MODEL_LOCAL_EXEC
:
618 insns
= microblaze_call_tls_get_addr (x
, reg
, &ret
, TLS_LDM
);
620 /* Attach a unique REG_EQUIV, to allow the RTL optimizers to
621 share the LDM result with other LD model accesses. */
622 eqv
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, const1_rtx
), UNSPEC_TLS
);
623 dest
= gen_reg_rtx (Pmode
);
624 emit_libcall_block (insns
, dest
, ret
, eqv
);
626 /* Load the addend. */
627 addend
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (2, x
, GEN_INT (TLS_DTPREL
)),
629 addend
= force_reg (SImode
, gen_rtx_CONST (SImode
, addend
));
630 dest
= gen_rtx_PLUS (Pmode
, dest
, addend
);
640 microblaze_classify_unspec (struct microblaze_address_info
*info
, rtx x
)
642 info
->symbol_type
= SYMBOL_TYPE_GENERAL
;
643 info
->symbol
= XVECEXP (x
, 0, 0);
645 if (XINT (x
, 1) == UNSPEC_GOTOFF
)
647 info
->regA
= gen_rtx_REG (SImode
, PIC_OFFSET_TABLE_REGNUM
);
648 info
->type
= ADDRESS_GOTOFF
;
650 else if (XINT (x
, 1) == UNSPEC_PLT
)
652 info
->type
= ADDRESS_PLT
;
654 else if (XINT (x
, 1) == UNSPEC_TLS
)
656 info
->type
= ADDRESS_TLS
;
657 info
->tls_type
= tls_reloc
INTVAL(XVECEXP(x
, 0, 1));
667 /* Return true if X is a valid index register for the given mode.
668 Allow only hard registers if STRICT. */
671 microblaze_valid_index_register_p (rtx x
,
672 enum machine_mode mode ATTRIBUTE_UNUSED
,
675 if (!strict
&& GET_CODE (x
) == SUBREG
)
678 return (GET_CODE (x
) == REG
679 /* A base register is good enough to be an index register on MicroBlaze. */
680 && microblaze_regno_ok_for_base_p (REGNO (x
), strict
));
683 /* Get the base register for accessing a value from the memory or
684 Symbol ref. Used for MicroBlaze Small Data Area Pointer Optimization. */
691 if (!flag_pic
|| microblaze_tls_symbol_p(x
))
692 base_reg
= MB_ABI_BASE_REGNUM
;
694 base_reg
= MB_ABI_PIC_ADDR_REGNUM
;
697 && GET_CODE (x
) == SYMBOL_REF
698 && SYMBOL_REF_SMALL_P (x
) && (decl
= SYMBOL_REF_DECL (x
)) != NULL
)
700 if (TREE_READONLY (decl
))
701 base_reg
= MB_ABI_GPRO_REGNUM
;
703 base_reg
= MB_ABI_GPRW_REGNUM
;
709 /* Return true if X is a valid address for machine mode MODE. If it is,
710 fill in INFO appropriately. STRICT is true if we should only accept
713 type regA regB offset symbol
715 ADDRESS_INVALID NULL NULL NULL NULL
717 ADDRESS_REG %0 NULL const_0 / NULL
719 ADDRESS_REG_INDEX %0 %1 NULL NULL
721 ADDRESS_SYMBOLIC r0 / NULL NULL symbol
724 ADDRESS_CONST_INT r0 NULL const NULL
726 For modes spanning multiple registers (DFmode in 32-bit GPRs,
727 DImode, TImode), indexed addressing cannot be used because
728 adjacent memory cells are accessed by adding word-sized offsets
729 during assembly output. */
732 microblaze_classify_address (struct microblaze_address_info
*info
, rtx x
,
733 enum machine_mode mode
, int strict
)
738 info
->type
= ADDRESS_INVALID
;
743 info
->symbol_type
= SYMBOL_TYPE_INVALID
;
745 switch (GET_CODE (x
))
750 info
->type
= ADDRESS_REG
;
752 info
->offset
= const0_rtx
;
753 return microblaze_valid_base_register_p (info
->regA
, mode
, strict
);
757 xplus0
= XEXP (x
, 0);
758 xplus1
= XEXP (x
, 1);
760 if (microblaze_valid_base_register_p (xplus0
, mode
, strict
))
762 info
->type
= ADDRESS_REG
;
765 if (GET_CODE (xplus1
) == CONST_INT
)
767 info
->offset
= xplus1
;
770 else if (GET_CODE (xplus1
) == UNSPEC
)
772 /* Need offsettable address. */
773 if (GET_MODE_SIZE (mode
) > UNITS_PER_WORD
)
776 return microblaze_classify_unspec (info
, xplus1
);
778 else if ((GET_CODE (xplus1
) == SYMBOL_REF
||
779 GET_CODE (xplus1
) == LABEL_REF
))
781 if (flag_pic
== 2 || microblaze_tls_symbol_p(xplus1
))
783 info
->type
= ADDRESS_SYMBOLIC
;
784 info
->symbol
= xplus1
;
785 info
->symbol_type
= SYMBOL_TYPE_GENERAL
;
788 else if (GET_CODE (xplus1
) == CONST
)
790 rtx xconst0
= XEXP(xplus1
, 0);
793 if (GET_CODE (xconst0
) == UNSPEC
)
795 /* Need offsettable address. */
796 if (GET_MODE_SIZE (mode
) > UNITS_PER_WORD
)
798 return microblaze_classify_unspec(info
, xconst0
);
801 /* for (plus x const_int) just look at x. */
802 if (GET_CODE (xconst0
) == PLUS
803 && GET_CODE (XEXP (xconst0
, 1)) == CONST_INT
804 && SMALL_INT (XEXP (xconst0
, 1)))
806 /* This is ok as info->symbol is set to xplus1 the full
807 const-expression below. */
808 xconst0
= XEXP (xconst0
, 0);
811 if (GET_CODE (xconst0
) == SYMBOL_REF
812 || GET_CODE (xconst0
) == LABEL_REF
)
814 if (flag_pic
== 2 || microblaze_tls_symbol_p(xconst0
))
817 info
->type
= ADDRESS_SYMBOLIC
;
818 info
->symbol
= xplus1
;
819 info
->symbol_type
= SYMBOL_TYPE_GENERAL
;
823 /* Not base + symbol || base + UNSPEC. */
827 else if (GET_CODE (xplus1
) == REG
828 && microblaze_valid_index_register_p (xplus1
, mode
,
830 && (GET_MODE_SIZE (mode
) <= UNITS_PER_WORD
))
832 /* Restrict larger than word-width modes from using an index register. */
833 info
->type
= ADDRESS_REG_INDEX
;
842 info
->regA
= gen_rtx_raw_REG (mode
, 0);
843 info
->type
= ADDRESS_CONST_INT
;
851 info
->type
= ADDRESS_SYMBOLIC
;
852 info
->symbol_type
= SYMBOL_TYPE_GENERAL
;
854 info
->regA
= gen_rtx_raw_REG (mode
, get_base_reg (x
));
856 if (GET_CODE (x
) == CONST
)
858 if (GET_CODE (XEXP (x
, 0)) == UNSPEC
)
860 info
->regA
= gen_rtx_raw_REG (mode
,
861 get_base_reg (XVECEXP (XEXP (x
,0), 0, 0)));
862 return microblaze_classify_unspec (info
, XEXP (x
, 0));
864 return !(flag_pic
&& pic_address_needs_scratch (x
));
869 else if (microblaze_tls_symbol_p(x
))
877 if (reload_in_progress
)
878 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
879 return microblaze_classify_unspec (info
, x
);
889 /* This function is used to implement GO_IF_LEGITIMATE_ADDRESS. It
890 returns a nonzero value if X is a legitimate address for a memory
891 operand of the indicated MODE. STRICT is nonzero if this function
892 is called during reload. */
895 microblaze_legitimate_address_p (enum machine_mode mode
, rtx x
, bool strict
)
897 struct microblaze_address_info addr
;
899 return microblaze_classify_address (&addr
, x
, mode
, strict
);
903 microblaze_valid_pic_const (rtx x
)
905 switch (GET_CODE (x
))
917 microblaze_legitimate_pic_operand (rtx x
)
919 if (flag_pic
== 2 && (symbol_mentioned_p(x
) || label_mentioned_p(x
)))
922 if (microblaze_tls_referenced_p(x
))
928 /* Try machine-dependent ways of modifying an illegitimate address
929 to be legitimate. If we find one, return the new, valid address.
930 This is used from only one place: `memory_address' in explow.c.
932 OLDX is the address as it was before break_out_memory_refs was
933 called. In some cases it is useful to look at this to decide what
936 It is always safe for this function to do nothing. It exists to
937 recognize opportunities to optimize the output.
939 For the MicroBlaze, transform:
941 memory(X + <large int>)
945 Y = <large int> & ~0x7fff;
947 memory (Z + (<large int> & 0x7fff));
949 This is for CSE to find several similar references, and only use one Z.
951 When PIC, convert addresses of the form memory (symbol+large int) to
952 memory (reg+large int). */
955 microblaze_legitimize_address (rtx x
, rtx oldx ATTRIBUTE_UNUSED
,
956 enum machine_mode mode ATTRIBUTE_UNUSED
)
958 register rtx xinsn
= x
, result
;
960 if (GET_CODE (xinsn
) == CONST
961 && flag_pic
&& pic_address_needs_scratch (xinsn
))
963 rtx ptr_reg
= gen_reg_rtx (Pmode
);
964 rtx constant
= XEXP (XEXP (xinsn
, 0), 1);
966 emit_move_insn (ptr_reg
, XEXP (XEXP (xinsn
, 0), 0));
968 result
= gen_rtx_PLUS (Pmode
, ptr_reg
, constant
);
969 if (SMALL_INT (constant
))
971 /* Otherwise we fall through so the code below will fix the
976 if (GET_CODE (xinsn
) == PLUS
)
978 register rtx xplus0
= XEXP (xinsn
, 0);
979 register rtx xplus1
= XEXP (xinsn
, 1);
980 register enum rtx_code code0
= GET_CODE (xplus0
);
981 register enum rtx_code code1
= GET_CODE (xplus1
);
983 if (code0
!= REG
&& code1
== REG
)
985 xplus0
= XEXP (xinsn
, 1);
986 xplus1
= XEXP (xinsn
, 0);
987 code0
= GET_CODE (xplus0
);
988 code1
= GET_CODE (xplus1
);
991 if (code0
== REG
&& REG_OK_FOR_BASE_P (xplus0
)
992 && code1
== CONST_INT
&& !SMALL_INT (xplus1
))
994 rtx int_reg
= gen_reg_rtx (Pmode
);
995 rtx ptr_reg
= gen_reg_rtx (Pmode
);
997 emit_move_insn (int_reg
, GEN_INT (INTVAL (xplus1
) & ~0x7fff));
999 emit_insn (gen_rtx_SET (VOIDmode
,
1001 gen_rtx_PLUS (Pmode
, xplus0
, int_reg
)));
1003 result
= gen_rtx_PLUS (Pmode
, ptr_reg
,
1004 GEN_INT (INTVAL (xplus1
) & 0x7fff));
1008 if (code0
== REG
&& REG_OK_FOR_BASE_P (xplus0
))
1010 if (reload_in_progress
)
1011 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
1014 xplus1
= XEXP (xplus1
, 0);
1015 code1
= GET_CODE (xplus1
);
1017 if (code1
== SYMBOL_REF
)
1019 if (microblaze_tls_symbol_p(xplus1
))
1022 reg
= gen_reg_rtx (Pmode
);
1024 tls_ref
= microblaze_legitimize_tls_address (xplus1
,
1026 emit_move_insn (reg
, tls_ref
);
1028 result
= gen_rtx_PLUS (Pmode
, xplus0
, reg
);
1032 else if (flag_pic
== 2)
1035 reg
= gen_reg_rtx (Pmode
);
1037 pic_ref
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, xplus1
),
1039 pic_ref
= gen_rtx_CONST (Pmode
, pic_ref
);
1040 pic_ref
= gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
, pic_ref
);
1041 pic_ref
= gen_const_mem (Pmode
, pic_ref
);
1042 emit_move_insn (reg
, pic_ref
);
1043 result
= gen_rtx_PLUS (Pmode
, xplus0
, reg
);
1050 if (GET_CODE (xinsn
) == SYMBOL_REF
)
1053 if (microblaze_tls_symbol_p(xinsn
))
1055 reg
= microblaze_legitimize_tls_address (xinsn
, NULL_RTX
);
1061 if (reload_in_progress
)
1062 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
1064 pic_ref
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, xinsn
), UNSPEC_GOTOFF
);
1065 pic_ref
= gen_rtx_CONST (Pmode
, pic_ref
);
1066 pic_ref
= gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
, pic_ref
);
1067 pic_ref
= gen_const_mem (Pmode
, pic_ref
);
1078 #define MAX_MOVE_REGS 8
1079 #define MAX_MOVE_BYTES (MAX_MOVE_REGS * UNITS_PER_WORD)
1081 /* Emit straight-line code to move LENGTH bytes from SRC to DEST.
1082 Assume that the areas do not overlap. */
1085 microblaze_block_move_straight (rtx dest
, rtx src
, HOST_WIDE_INT length
)
1087 HOST_WIDE_INT offset
, delta
;
1088 unsigned HOST_WIDE_INT bits
;
1090 enum machine_mode mode
;
1093 bits
= BITS_PER_WORD
;
1094 mode
= mode_for_size (bits
, MODE_INT
, 0);
1095 delta
= bits
/ BITS_PER_UNIT
;
1097 /* Allocate a buffer for the temporary registers. */
1098 regs
= XALLOCAVEC (rtx
, length
/ delta
);
1100 /* Load as many BITS-sized chunks as possible. Use a normal load if
1101 the source has enough alignment, otherwise use left/right pairs. */
1102 for (offset
= 0, i
= 0; offset
+ delta
<= length
; offset
+= delta
, i
++)
1104 regs
[i
] = gen_reg_rtx (mode
);
1105 emit_move_insn (regs
[i
], adjust_address (src
, mode
, offset
));
1108 /* Copy the chunks to the destination. */
1109 for (offset
= 0, i
= 0; offset
+ delta
<= length
; offset
+= delta
, i
++)
1110 emit_move_insn (adjust_address (dest
, mode
, offset
), regs
[i
]);
1112 /* Mop up any left-over bytes. */
1113 if (offset
< length
)
1115 src
= adjust_address (src
, BLKmode
, offset
);
1116 dest
= adjust_address (dest
, BLKmode
, offset
);
1117 move_by_pieces (dest
, src
, length
- offset
,
1118 MIN (MEM_ALIGN (src
), MEM_ALIGN (dest
)), 0);
1122 /* Helper function for doing a loop-based block operation on memory
1123 reference MEM. Each iteration of the loop will operate on LENGTH
1126 Create a new base register for use within the loop and point it to
1127 the start of MEM. Create a new memory reference that uses this
1128 register. Store them in *LOOP_REG and *LOOP_MEM respectively. */
1131 microblaze_adjust_block_mem (rtx mem
, HOST_WIDE_INT length
,
1132 rtx
* loop_reg
, rtx
* loop_mem
)
1134 *loop_reg
= copy_addr_to_reg (XEXP (mem
, 0));
1136 /* Although the new mem does not refer to a known location,
1137 it does keep up to LENGTH bytes of alignment. */
1138 *loop_mem
= change_address (mem
, BLKmode
, *loop_reg
);
1139 set_mem_align (*loop_mem
,
1140 MIN ((HOST_WIDE_INT
) MEM_ALIGN (mem
),
1141 length
* BITS_PER_UNIT
));
1145 /* Move LENGTH bytes from SRC to DEST using a loop that moves MAX_MOVE_BYTES
1146 per iteration. LENGTH must be at least MAX_MOVE_BYTES. Assume that the
1147 memory regions do not overlap. */
1150 microblaze_block_move_loop (rtx dest
, rtx src
, HOST_WIDE_INT length
)
1152 rtx_code_label
*label
;
1153 rtx src_reg
, dest_reg
, final_src
;
1154 HOST_WIDE_INT leftover
;
1156 leftover
= length
% MAX_MOVE_BYTES
;
1159 /* Create registers and memory references for use within the loop. */
1160 microblaze_adjust_block_mem (src
, MAX_MOVE_BYTES
, &src_reg
, &src
);
1161 microblaze_adjust_block_mem (dest
, MAX_MOVE_BYTES
, &dest_reg
, &dest
);
1163 /* Calculate the value that SRC_REG should have after the last iteration
1165 final_src
= expand_simple_binop (Pmode
, PLUS
, src_reg
, GEN_INT (length
),
1168 /* Emit the start of the loop. */
1169 label
= gen_label_rtx ();
1172 /* Emit the loop body. */
1173 microblaze_block_move_straight (dest
, src
, MAX_MOVE_BYTES
);
1175 /* Move on to the next block. */
1176 emit_move_insn (src_reg
, plus_constant (Pmode
, src_reg
, MAX_MOVE_BYTES
));
1177 emit_move_insn (dest_reg
, plus_constant (Pmode
, dest_reg
, MAX_MOVE_BYTES
));
1179 /* Emit the test & branch. */
1180 emit_insn (gen_cbranchsi4 (gen_rtx_NE (SImode
, src_reg
, final_src
),
1181 src_reg
, final_src
, label
));
1183 /* Mop up any left-over bytes. */
1185 microblaze_block_move_straight (dest
, src
, leftover
);
1188 /* Expand a movmemsi instruction. */
1191 microblaze_expand_block_move (rtx dest
, rtx src
, rtx length
, rtx align_rtx
)
1194 if (GET_CODE (length
) == CONST_INT
)
1196 HOST_WIDE_INT bytes
= INTVAL (length
);
1197 int align
= INTVAL (align_rtx
);
1199 if (align
> UNITS_PER_WORD
)
1201 align
= UNITS_PER_WORD
; /* We can't do any better. */
1203 else if (align
< UNITS_PER_WORD
)
1205 if (INTVAL (length
) <= MAX_MOVE_BYTES
)
1207 move_by_pieces (dest
, src
, bytes
, align
, 0);
1214 if (INTVAL (length
) <= 2 * MAX_MOVE_BYTES
)
1216 microblaze_block_move_straight (dest
, src
, INTVAL (length
));
1221 microblaze_block_move_loop (dest
, src
, INTVAL (length
));
1229 microblaze_rtx_costs (rtx x
, int code
, int outer_code ATTRIBUTE_UNUSED
,
1230 int opno ATTRIBUTE_UNUSED
, int *total
,
1231 bool speed ATTRIBUTE_UNUSED
)
1233 enum machine_mode mode
= GET_MODE (x
);
1239 int num_words
= (GET_MODE_SIZE (mode
) > UNITS_PER_WORD
) ? 2 : 1;
1240 if (simple_memory_operand (x
, mode
))
1241 *total
= COSTS_N_INSNS (2 * num_words
);
1243 *total
= COSTS_N_INSNS (2 * (2 * num_words
));
1251 *total
= COSTS_N_INSNS (2);
1254 *total
= COSTS_N_INSNS (1);
1263 *total
= COSTS_N_INSNS (2);
1266 *total
= COSTS_N_INSNS (1);
1274 if (TARGET_BARREL_SHIFT
)
1276 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v5.00.a")
1278 *total
= COSTS_N_INSNS (1);
1280 *total
= COSTS_N_INSNS (2);
1282 else if (!TARGET_SOFT_MUL
)
1283 *total
= COSTS_N_INSNS (1);
1284 else if (GET_CODE (XEXP (x
, 1)) == CONST_INT
)
1286 /* Add 1 to make shift slightly more expensive than add. */
1287 *total
= COSTS_N_INSNS (INTVAL (XEXP (x
, 1))) + 1;
1288 /* Reduce shift costs for special circumstances. */
1289 if (optimize_size
&& INTVAL (XEXP (x
, 1)) > 5)
1291 if (!optimize_size
&& INTVAL (XEXP (x
, 1)) > 17)
1295 /* Double the worst cost of shifts when there is no barrel shifter and
1296 the shift amount is in a reg. */
1297 *total
= COSTS_N_INSNS (32 * 4);
1303 if (mode
== SFmode
|| mode
== DFmode
)
1305 if (TARGET_HARD_FLOAT
)
1306 *total
= COSTS_N_INSNS (6);
1309 else if (mode
== DImode
)
1311 *total
= COSTS_N_INSNS (4);
1316 *total
= COSTS_N_INSNS (1);
1325 *total
= COSTS_N_INSNS (4);
1333 if (TARGET_HARD_FLOAT
)
1334 *total
= COSTS_N_INSNS (6);
1336 else if (!TARGET_SOFT_MUL
)
1338 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v5.00.a")
1340 *total
= COSTS_N_INSNS (1);
1342 *total
= COSTS_N_INSNS (3);
1345 *total
= COSTS_N_INSNS (10);
1353 if (TARGET_HARD_FLOAT
)
1354 *total
= COSTS_N_INSNS (23);
1360 *total
= COSTS_N_INSNS (1);
1365 *total
= COSTS_N_INSNS (1);
1373 /* Return the number of instructions needed to load or store a value
1374 of mode MODE at X. Return 0 if X isn't valid for MODE. */
1377 microblaze_address_insns (rtx x
, enum machine_mode mode
)
1379 struct microblaze_address_info addr
;
1381 if (microblaze_classify_address (&addr
, x
, mode
, false))
1386 if (SMALL_INT (addr
.offset
))
1390 case ADDRESS_CONST_INT
:
1395 case ADDRESS_REG_INDEX
:
1397 case ADDRESS_SYMBOLIC
:
1398 case ADDRESS_GOTOFF
:
1401 switch (addr
.tls_type
)
1419 /* Provide the costs of an addressing mode that contains ADDR.
1420 If ADDR is not a valid address, its cost is irrelevant. */
1422 microblaze_address_cost (rtx addr
, enum machine_mode mode ATTRIBUTE_UNUSED
,
1423 addr_space_t as ATTRIBUTE_UNUSED
,
1424 bool speed ATTRIBUTE_UNUSED
)
1426 return COSTS_N_INSNS (microblaze_address_insns (addr
, GET_MODE (addr
)));
1429 /* Return nonzero if X is an address which needs a temporary register when
1430 reloaded while generating PIC code. */
1433 pic_address_needs_scratch (rtx x
)
1435 if (GET_CODE (x
) == CONST
&& GET_CODE (XEXP (x
,0)) == PLUS
)
1439 p0
= XEXP (XEXP (x
, 0), 0);
1440 p1
= XEXP (XEXP (x
, 0), 1);
1442 if ((GET_CODE (p0
) == SYMBOL_REF
|| GET_CODE (p0
) == LABEL_REF
)
1443 && (GET_CODE (p1
) == CONST_INT
)
1444 && (flag_pic
== 2 || microblaze_tls_symbol_p (p0
) || !SMALL_INT (p1
)))
1450 /* Argument support functions. */
1451 /* Initialize CUMULATIVE_ARGS for a function. */
1454 init_cumulative_args (CUMULATIVE_ARGS
* cum
, tree fntype
,
1455 rtx libname ATTRIBUTE_UNUSED
)
1457 static CUMULATIVE_ARGS zero_cum
;
1458 tree param
, next_param
;
1462 /* Determine if this function has variable arguments. This is
1463 indicated by the last argument being 'void_type_mode' if there
1464 are no variable arguments. The standard MicroBlaze calling sequence
1465 passes all arguments in the general purpose registers in this case. */
1467 for (param
= fntype
? TYPE_ARG_TYPES (fntype
) : 0;
1468 param
!= 0; param
= next_param
)
1470 next_param
= TREE_CHAIN (param
);
1471 if (next_param
== 0 && TREE_VALUE (param
) != void_type_node
)
1472 cum
->gp_reg_found
= 1;
1476 /* Advance the argument to the next argument position. */
1479 microblaze_function_arg_advance (cumulative_args_t cum_v
,
1480 enum machine_mode mode
,
1481 const_tree type
, bool named ATTRIBUTE_UNUSED
)
1483 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
1492 gcc_assert (GET_MODE_CLASS (mode
) == MODE_COMPLEX_INT
1493 || GET_MODE_CLASS (mode
) == MODE_COMPLEX_FLOAT
);
1495 cum
->gp_reg_found
= 1;
1496 cum
->arg_words
+= ((GET_MODE_SIZE (mode
) + UNITS_PER_WORD
- 1)
1501 cum
->gp_reg_found
= 1;
1502 cum
->arg_words
+= ((int_size_in_bytes (type
) + UNITS_PER_WORD
- 1)
1508 if (!cum
->gp_reg_found
&& cum
->arg_number
<= 2)
1509 cum
->fp_code
+= 1 << ((cum
->arg_number
- 1) * 2);
1513 cum
->arg_words
+= 2;
1514 if (!cum
->gp_reg_found
&& cum
->arg_number
<= 2)
1515 cum
->fp_code
+= 2 << ((cum
->arg_number
- 1) * 2);
1519 cum
->gp_reg_found
= 1;
1520 cum
->arg_words
+= 2;
1527 cum
->gp_reg_found
= 1;
1533 /* Return an RTL expression containing the register for the given mode,
1534 or 0 if the argument is to be passed on the stack. */
1537 microblaze_function_arg (cumulative_args_t cum_v
, enum machine_mode mode
,
1538 const_tree type ATTRIBUTE_UNUSED
,
1539 bool named ATTRIBUTE_UNUSED
)
1541 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
1545 int *arg_words
= &cum
->arg_words
;
1547 cum
->last_arg_fp
= 0;
1558 regbase
= GP_ARG_FIRST
;
1561 gcc_assert (GET_MODE_CLASS (mode
) == MODE_COMPLEX_INT
1562 || GET_MODE_CLASS (mode
) == MODE_COMPLEX_FLOAT
);
1563 /* Drops through. */
1565 regbase
= GP_ARG_FIRST
;
1569 if (*arg_words
>= MAX_ARGS_IN_REGISTERS
)
1573 gcc_assert (regbase
!= -1);
1575 ret
= gen_rtx_REG (mode
, regbase
+ *arg_words
);
1578 if (mode
== VOIDmode
)
1580 if (cum
->num_adjusts
> 0)
1581 ret
= gen_rtx_PARALLEL ((enum machine_mode
) cum
->fp_code
,
1582 gen_rtvec_v (cum
->num_adjusts
, cum
->adjust
));
1588 /* Return number of bytes of argument to put in registers. */
1590 function_arg_partial_bytes (cumulative_args_t cum_v
, enum machine_mode mode
,
1591 tree type
, bool named ATTRIBUTE_UNUSED
)
1593 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
1595 if ((mode
== BLKmode
1596 || GET_MODE_CLASS (mode
) != MODE_COMPLEX_INT
1597 || GET_MODE_CLASS (mode
) != MODE_COMPLEX_FLOAT
)
1598 && cum
->arg_words
< MAX_ARGS_IN_REGISTERS
)
1601 if (mode
== BLKmode
)
1602 words
= ((int_size_in_bytes (type
) + UNITS_PER_WORD
- 1)
1605 words
= (GET_MODE_SIZE (mode
) + UNITS_PER_WORD
- 1) / UNITS_PER_WORD
;
1607 if (words
+ cum
->arg_words
<= MAX_ARGS_IN_REGISTERS
)
1608 return 0; /* structure fits in registers */
1610 return (MAX_ARGS_IN_REGISTERS
- cum
->arg_words
) * UNITS_PER_WORD
;
1613 else if (mode
== DImode
&& cum
->arg_words
== MAX_ARGS_IN_REGISTERS
- 1)
1614 return UNITS_PER_WORD
;
1619 /* Convert a version number of the form "vX.YY.Z" to an integer encoding
1620 for easier range comparison. */
1622 microblaze_version_to_int (const char *version
)
1625 const char *tmpl
= "vXX.YY.Z";
1634 { /* Looking for major */
1641 if (!(*p
>= '0' && *p
<= '9'))
1643 iver
+= (int) (*p
- '0');
1648 { /* Looking for minor */
1649 if (!(*p
>= '0' && *p
<= '9'))
1651 iver
+= (int) (*p
- '0');
1655 { /* Looking for compat */
1656 if (!(*p
>= 'a' && *p
<= 'z'))
1659 iver
+= (int) (*p
- 'a');
1679 microblaze_option_override (void)
1681 register int i
, start
;
1683 register enum machine_mode mode
;
1686 microblaze_section_threshold
= (global_options_set
.x_g_switch_value
1688 : MICROBLAZE_DEFAULT_GVALUE
);
1692 /* Make sure it's 2, we only support one kind of PIC. */
1694 if (!TARGET_SUPPORTS_PIC
)
1696 error ("-fPIC/-fpic not supported for this target");
1697 /* Clear it to avoid further errors. */
1702 /* Check the MicroBlaze CPU version for any special action to be done. */
1703 if (microblaze_select_cpu
== NULL
)
1704 microblaze_select_cpu
= MICROBLAZE_DEFAULT_CPU
;
1705 ver
= microblaze_version_to_int (microblaze_select_cpu
);
1708 error ("%qs is an invalid argument to -mcpu=", microblaze_select_cpu
);
1711 ver
= MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v3.00.a");
1714 /* No hardware exceptions in earlier versions. So no worries. */
1716 microblaze_select_flags
&= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY
);
1718 microblaze_no_unsafe_delay
= 0;
1719 microblaze_pipe
= MICROBLAZE_PIPE_3
;
1722 || (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v4.00.b")
1726 microblaze_select_flags
|= (MICROBLAZE_MASK_NO_UNSAFE_DELAY
);
1728 microblaze_no_unsafe_delay
= 1;
1729 microblaze_pipe
= MICROBLAZE_PIPE_3
;
1733 /* We agree to use 5 pipe-stage model even on area optimized 3
1734 pipe-stage variants. */
1736 microblaze_select_flags
&= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY
);
1738 microblaze_no_unsafe_delay
= 0;
1739 microblaze_pipe
= MICROBLAZE_PIPE_5
;
1740 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v5.00.a") == 0
1741 || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
,
1743 || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
,
1746 /* Pattern compares are to be turned on by default only when
1747 compiling for MB v5.00.'z'. */
1748 target_flags
|= MASK_PATTERN_COMPARE
;
1752 ver
= MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v6.00.a");
1755 if (TARGET_MULTIPLY_HIGH
)
1757 "-mxl-multiply-high can be used only with -mcpu=v6.00.a or greater");
1760 ver
= MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v8.10.a");
1761 microblaze_has_clz
= 1;
1764 /* MicroBlaze prior to 8.10.a didn't have clz. */
1765 microblaze_has_clz
= 0;
1768 /* TARGET_REORDER defaults to 2 if -mxl-reorder not specified. */
1769 ver
= MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v8.30.a");
1772 if (TARGET_REORDER
== 1)
1773 warning (0, "-mxl-reorder can be used only with -mcpu=v8.30.a or greater");
1776 else if ((ver
== 0) && !TARGET_PATTERN_COMPARE
)
1778 if (TARGET_REORDER
== 1)
1779 warning (0, "-mxl-reorder requires -mxl-pattern-compare for -mcpu=v8.30.a");
1783 if (TARGET_MULTIPLY_HIGH
&& TARGET_SOFT_MUL
)
1784 error ("-mxl-multiply-high requires -mno-xl-soft-mul");
1786 /* Always use DFA scheduler. */
1787 microblaze_sched_use_dfa
= 1;
1790 microblaze_abicalls
= MICROBLAZE_ABICALLS_NO
;
1793 /* Initialize the high, low values for legit floating point constants. */
1794 real_maxval (&dfhigh
, 0, DFmode
);
1795 real_maxval (&dflow
, 1, DFmode
);
1796 real_maxval (&sfhigh
, 0, SFmode
);
1797 real_maxval (&sflow
, 1, SFmode
);
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;
1813 microblaze_print_operand_punct
['}'] = 1;
1814 microblaze_print_operand_punct
['^'] = 1;
1815 microblaze_print_operand_punct
['$'] = 1;
1816 microblaze_print_operand_punct
['+'] = 1;
1818 /* Set up array to map GCC register number to debug register number.
1819 Ignore the special purpose register numbers. */
1821 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
1822 microblaze_dbx_regno
[i
] = -1;
1824 start
= GP_DBX_FIRST
- GP_REG_FIRST
;
1825 for (i
= GP_REG_FIRST
; i
<= GP_REG_LAST
; i
++)
1826 microblaze_dbx_regno
[i
] = i
+ start
;
1828 /* Set up array giving whether a given register can hold a given mode. */
1830 for (mode
= VOIDmode
;
1831 mode
!= MAX_MACHINE_MODE
; mode
= (enum machine_mode
) ((int) mode
+ 1))
1833 register int size
= GET_MODE_SIZE (mode
);
1835 for (regno
= 0; regno
< FIRST_PSEUDO_REGISTER
; regno
++)
1841 ok
= (ST_REG_P (regno
) || GP_REG_P (regno
));
1843 else if (GP_REG_P (regno
))
1844 ok
= ((regno
& 1) == 0 || size
<= UNITS_PER_WORD
);
1848 microblaze_hard_regno_mode_ok
[(int) mode
][regno
] = ok
;
1853 /* Return true if FUNC is an interrupt function as specified
1854 by the "interrupt_handler" attribute. */
1857 microblaze_interrupt_function_p (tree func
)
1861 if (TREE_CODE (func
) != FUNCTION_DECL
)
1864 a
= lookup_attribute ("interrupt_handler", DECL_ATTRIBUTES (func
));
1865 return a
!= NULL_TREE
;
1869 microblaze_fast_interrupt_function_p (tree func
)
1873 if (TREE_CODE (func
) != FUNCTION_DECL
)
1876 a
= lookup_attribute ("fast_interrupt", DECL_ATTRIBUTES (func
));
1877 return a
!= NULL_TREE
;
1880 microblaze_break_function_p (tree func
)
1885 if (TREE_CODE (func
) != FUNCTION_DECL
)
1888 a
= lookup_attribute ("break_handler", DECL_ATTRIBUTES (func
));
1889 return a
!= NULL_TREE
;
1891 /* Return true if FUNC is an interrupt function which uses
1892 normal return, indicated by the "save_volatiles" attribute. */
1895 microblaze_save_volatiles (tree func
)
1899 if (TREE_CODE (func
) != FUNCTION_DECL
)
1902 a
= lookup_attribute ("save_volatiles", DECL_ATTRIBUTES (func
));
1903 return a
!= NULL_TREE
;
1906 /* Return whether function is tagged with 'interrupt_handler'
1907 or 'fast_interrupt' attribute. Return true if function
1908 should use return from interrupt rather than normal
1911 microblaze_is_interrupt_variant (void)
1913 return (interrupt_handler
|| fast_interrupt
);
1916 microblaze_is_break_handler (void)
1918 return break_handler
;
1921 /* Determine of register must be saved/restored in call. */
1923 microblaze_must_save_register (int regno
)
1925 if (pic_offset_table_rtx
&&
1926 (regno
== MB_ABI_PIC_ADDR_REGNUM
) && df_regs_ever_live_p (regno
))
1929 if (df_regs_ever_live_p (regno
) && !call_used_regs
[regno
])
1932 if (frame_pointer_needed
&& (regno
== HARD_FRAME_POINTER_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
)
1965 /* Return the bytes needed to compute the frame pointer from the current
1968 MicroBlaze stack frames look like:
1972 Before call After call
1973 +-----------------------+ +-----------------------+
1975 mem. | local variables, | | local variables, |
1976 | callee saved and | | callee saved and |
1978 +-----------------------+ +-----------------------+
1979 | arguments for called | | arguments for called |
1980 | subroutines | | subroutines |
1981 | (optional) | | (optional) |
1982 +-----------------------+ +-----------------------+
1983 | Link register | | Link register |
1985 +-----------------------+ +-----------------------+
1987 | local variables, |
1988 | callee saved and |
1990 +-----------------------+
1991 | MSR (optional if, |
1992 | interrupt handler) |
1993 +-----------------------+
1995 | alloca allocations |
1997 +-----------------------+
1999 | arguments for called |
2003 +-----------------------+
2006 memory +-----------------------+
2010 static HOST_WIDE_INT
2011 compute_frame_size (HOST_WIDE_INT size
)
2014 HOST_WIDE_INT total_size
; /* # bytes that the entire frame takes up. */
2015 HOST_WIDE_INT var_size
; /* # bytes that local variables take up. */
2016 HOST_WIDE_INT args_size
; /* # bytes that outgoing arguments take up. */
2017 int link_debug_size
; /* # bytes for link register. */
2018 HOST_WIDE_INT gp_reg_size
; /* # bytes needed to store calle-saved gp regs. */
2019 long mask
; /* mask of saved gp registers. */
2022 microblaze_interrupt_function_p (current_function_decl
);
2024 microblaze_break_function_p (current_function_decl
);
2027 microblaze_fast_interrupt_function_p (current_function_decl
);
2028 save_volatiles
= microblaze_save_volatiles (current_function_decl
);
2030 interrupt_handler
= break_handler
;
2035 args_size
= crtl
->outgoing_args_size
;
2037 if ((args_size
== 0) && cfun
->calls_alloca
)
2038 args_size
= NUM_OF_ARGS
* UNITS_PER_WORD
;
2040 total_size
= var_size
+ args_size
;
2043 /* force setting GOT. */
2044 df_set_regs_ever_live (MB_ABI_PIC_ADDR_REGNUM
, true);
2046 /* Calculate space needed for gp registers. */
2047 for (regno
= GP_REG_FIRST
; regno
<= GP_REG_LAST
; regno
++)
2049 if (microblaze_must_save_register (regno
))
2052 if (regno
!= MB_ABI_SUB_RETURN_ADDR_REGNUM
)
2053 /* Don't account for link register. It is accounted specially below. */
2054 gp_reg_size
+= GET_MODE_SIZE (SImode
);
2056 mask
|= (1L << (regno
- GP_REG_FIRST
));
2060 total_size
+= gp_reg_size
;
2062 /* Add 4 bytes for MSR. */
2063 if (microblaze_is_interrupt_variant ())
2066 /* No space to be allocated for link register in leaf functions with no other
2067 stack requirements. */
2068 if (total_size
== 0 && crtl
->is_leaf
)
2069 link_debug_size
= 0;
2071 link_debug_size
= UNITS_PER_WORD
;
2073 total_size
+= link_debug_size
;
2075 /* Save other computed information. */
2076 current_frame_info
.total_size
= total_size
;
2077 current_frame_info
.var_size
= var_size
;
2078 current_frame_info
.args_size
= args_size
;
2079 current_frame_info
.gp_reg_size
= gp_reg_size
;
2080 current_frame_info
.mask
= mask
;
2081 current_frame_info
.initialized
= reload_completed
;
2082 current_frame_info
.num_gp
= gp_reg_size
/ UNITS_PER_WORD
;
2083 current_frame_info
.link_debug_size
= link_debug_size
;
2086 /* Offset from which to callee-save GP regs. */
2087 current_frame_info
.gp_offset
= (total_size
- gp_reg_size
);
2089 current_frame_info
.gp_offset
= 0;
2091 /* Ok, we're done. */
2095 /* Make sure that we're not trying to eliminate to the wrong hard frame
2099 microblaze_can_eliminate (const int from
, const int to
)
2101 return ((from
== RETURN_ADDRESS_POINTER_REGNUM
&& !leaf_function_p())
2102 || (to
== MB_ABI_SUB_RETURN_ADDR_REGNUM
&& leaf_function_p())
2103 || (from
!= RETURN_ADDRESS_POINTER_REGNUM
2104 && (to
== HARD_FRAME_POINTER_REGNUM
2105 || (to
== STACK_POINTER_REGNUM
&& !frame_pointer_needed
))));
2108 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
2109 pointer or argument pointer or the return address pointer. TO is either
2110 the stack pointer or hard frame pointer. */
2113 microblaze_initial_elimination_offset (int from
, int to
)
2115 HOST_WIDE_INT offset
;
2119 case FRAME_POINTER_REGNUM
:
2122 case ARG_POINTER_REGNUM
:
2123 if (to
== STACK_POINTER_REGNUM
|| to
== HARD_FRAME_POINTER_REGNUM
)
2124 offset
= compute_frame_size (get_frame_size ());
2128 case RETURN_ADDRESS_POINTER_REGNUM
:
2132 offset
= current_frame_info
.gp_offset
+
2133 ((UNITS_PER_WORD
- (POINTER_SIZE
/ BITS_PER_UNIT
)));
2141 /* Print operands using format code.
2143 The MicroBlaze specific codes are:
2145 'X' X is CONST_INT, prints 32 bits in hexadecimal format = "0x%08x",
2146 'x' X is CONST_INT, prints 16 bits in hexadecimal format = "0x%04x",
2147 'F' op is CONST_DOUBLE, print 32 bits in hex,
2148 'd' output integer constant in decimal,
2149 'z' if the operand is 0, use $0 instead of normal operand.
2150 'D' print second register of double-word register operand.
2151 'L' print low-order register of double-word register operand.
2152 'M' print high-order register of double-word register operand.
2153 'C' print part of opcode for a branch condition.
2154 'N' print part of opcode for a branch condition, inverted.
2155 'S' X is CODE_LABEL, print with prefix of "LS" (for embedded switch).
2156 'B' print 'z' for EQ, 'n' for NE
2157 'b' print 'n' for EQ, 'z' for NE
2158 'T' print 'f' for EQ, 't' for NE
2159 't' print 't' for EQ, 'f' for NE
2160 'm' Print 1<<operand.
2161 'i' Print 'i' if MEM operand has immediate value
2162 'y' Print 'y' if MEM operand is single register
2163 'o' Print operand address+4
2164 '?' Print 'd' if we use a branch with delay slot instead of normal branch.
2165 'h' Print high word of const_double (int or float) value as hex
2166 'j' Print low word of const_double (int or float) value as hex
2167 's' Print -1 if operand is negative, 0 if positive (sign extend)
2168 '@' Print the name of the temporary register (rMB_ABI_ASM_TEMP_REGNUM).
2169 '#' Print nop if the delay slot of a branch is not filled.
2173 print_operand (FILE * file
, rtx op
, int letter
)
2175 register enum rtx_code code
;
2177 if (PRINT_OPERAND_PUNCT_VALID_P (letter
))
2182 /* Conditionally add a 'd' to indicate filled delay slot. */
2183 if (final_sequence
!= NULL
)
2188 /* Conditionally add a nop in unfilled delay slot. */
2189 if (final_sequence
== NULL
)
2190 fputs ("nop\t\t# Unfilled delay slot\n", file
);
2194 fputs (reg_names
[GP_REG_FIRST
+ MB_ABI_ASM_TEMP_REGNUM
], file
);
2198 output_operand_lossage ("unknown punctuation '%c'", letter
);
2207 output_operand_lossage ("null pointer");
2211 code
= GET_CODE (op
);
2213 if (code
== SIGN_EXTEND
)
2214 op
= XEXP (op
, 0), code
= GET_CODE (op
);
2242 fatal_insn ("PRINT_OPERAND, invalid insn for %%C", op
);
2245 else if (letter
== 'N')
2271 fatal_insn ("PRINT_OPERAND, invalid insn for %%N", op
);
2274 else if (letter
== 'S')
2278 ASM_GENERATE_INTERNAL_LABEL (buffer
, "LS", CODE_LABEL_NUMBER (op
));
2279 assemble_name (file
, buffer
);
2282 /* Print 'i' for memory operands which have immediate values. */
2283 else if (letter
== 'i')
2287 struct microblaze_address_info info
;
2289 if (!microblaze_classify_address
2290 (&info
, XEXP (op
, 0), GET_MODE (op
), 1))
2291 fatal_insn ("insn contains an invalid address !", op
);
2296 case ADDRESS_CONST_INT
:
2297 case ADDRESS_SYMBOLIC
:
2298 case ADDRESS_GOTOFF
:
2302 case ADDRESS_REG_INDEX
:
2304 case ADDRESS_INVALID
:
2306 fatal_insn ("invalid address", op
);
2311 else if (code
== REG
|| code
== SUBREG
)
2313 register int regnum
;
2316 regnum
= REGNO (op
);
2318 regnum
= true_regnum (op
);
2320 if ((letter
== 'M' && !WORDS_BIG_ENDIAN
)
2321 || (letter
== 'L' && WORDS_BIG_ENDIAN
) || letter
== 'D')
2324 fprintf (file
, "%s", reg_names
[regnum
]);
2327 else if (code
== MEM
)
2330 rtx op4
= adjust_address (op
, GET_MODE (op
), 4);
2331 output_address (XEXP (op4
, 0));
2333 else if (letter
== 'y')
2335 rtx mem_reg
= XEXP (op
, 0);
2336 if (GET_CODE (mem_reg
) == REG
)
2338 register int regnum
= REGNO (mem_reg
);
2339 fprintf (file
, "%s", reg_names
[regnum
]);
2343 output_address (XEXP (op
, 0));
2345 else if (letter
== 'h' || letter
== 'j')
2348 if (code
== CONST_DOUBLE
)
2350 if (GET_MODE (op
) == DFmode
)
2352 REAL_VALUE_TYPE value
;
2353 REAL_VALUE_FROM_CONST_DOUBLE (value
, op
);
2354 REAL_VALUE_TO_TARGET_DOUBLE (value
, val
);
2358 val
[0] = CONST_DOUBLE_HIGH (op
);
2359 val
[1] = CONST_DOUBLE_LOW (op
);
2362 else if (code
== CONST_INT
)
2364 val
[0] = (INTVAL (op
) & 0xffffffff00000000LL
) >> 32;
2365 val
[1] = INTVAL (op
) & 0x00000000ffffffffLL
;
2366 if (val
[0] == 0 && val
[1] < 0)
2370 fprintf (file
, "0x%8.8lx", (letter
== 'h') ? val
[0] : val
[1]);
2372 else if (code
== CONST_DOUBLE
)
2376 unsigned long value_long
;
2377 REAL_VALUE_TYPE value
;
2378 REAL_VALUE_FROM_CONST_DOUBLE (value
, op
);
2379 REAL_VALUE_TO_TARGET_SINGLE (value
, value_long
);
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
, HOST_WIDE_INT size ATTRIBUTE_UNUSED
)
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 enum 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 ATTRIBUTE_UNUSED
,
2959 HOST_WIDE_INT size ATTRIBUTE_UNUSED
)
2963 /* Get the function name the same way that toplev.c does before calling
2964 assemble_start_function. This is needed so that the name used here
2965 exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */
2966 fnname
= XSTR (XEXP (DECL_RTL (current_function_decl
), 0), 0);
2968 if (!flag_inhibit_size_directive
)
2970 fputs ("\t.end\t", file
);
2971 if (interrupt_handler
&& !break_handler
)
2972 fputs ("_interrupt_handler", file
);
2973 else if (break_handler
)
2974 fputs ("_break_handler", file
);
2976 assemble_name (file
, fnname
);
2980 /* Reset state info for each function. */
2981 current_frame_info
= zero_frame_info
;
2983 /* Restore the output file if optimizing the GP (optimizing the GP causes
2984 the text to be diverted to a tempfile, so that data decls come before
2985 references to the data). */
2988 /* Expand the epilogue into a bunch of separate insns. */
2991 microblaze_expand_epilogue (void)
2993 HOST_WIDE_INT fsiz
= current_frame_info
.total_size
;
2994 rtx fsiz_rtx
= GEN_INT (fsiz
);
2998 /* In case of interrupt handlers use addki instead of addi for changing the
2999 stack pointer value. */
3001 if (microblaze_can_use_return_insn ())
3003 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode
,
3005 MB_ABI_SUB_RETURN_ADDR_REGNUM
)));
3011 /* Restore SUB_RETURN_ADDR_REGNUM at first. This is to prevent the
3012 sequence of load-followed by a use (in rtsd) in every prologue. Saves
3013 a load-use stall cycle :) This is also important to handle alloca.
3014 (See comments for if (frame_pointer_needed) below. */
3016 if (!crtl
->is_leaf
|| interrupt_handler
)
3019 gen_rtx_MEM (SImode
,
3020 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
, const0_rtx
));
3021 if (interrupt_handler
)
3022 /* Do not optimize in flow analysis. */
3023 MEM_VOLATILE_P (mem_rtx
) = 1;
3024 reg_rtx
= gen_rtx_REG (SImode
, MB_ABI_SUB_RETURN_ADDR_REGNUM
);
3025 emit_move_insn (reg_rtx
, mem_rtx
);
3028 /* It is important that this is done after we restore the return address
3029 register (above). When alloca is used, we want to restore the
3030 sub-routine return address only from the current stack top and not
3031 from the frame pointer (which we restore below). (frame_pointer + 0)
3032 might have been over-written since alloca allocates memory on the
3034 if (frame_pointer_needed
)
3035 emit_insn (gen_movsi (stack_pointer_rtx
, hard_frame_pointer_rtx
));
3037 /* _restore_ registers for epilogue. */
3038 save_restore_insns (0);
3039 emit_insn (gen_blockage ());
3040 emit_insn (gen_addsi3 (stack_pointer_rtx
, stack_pointer_rtx
, fsiz_rtx
));
3043 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode
, GP_REG_FIRST
+
3044 MB_ABI_SUB_RETURN_ADDR_REGNUM
)));
3048 /* Return nonzero if this function is known to have a null epilogue.
3049 This allows the optimizer to omit jumps to jumps if no stack
3053 microblaze_can_use_return_insn (void)
3055 if (!reload_completed
)
3058 if (df_regs_ever_live_p (MB_ABI_SUB_RETURN_ADDR_REGNUM
) || profile_flag
)
3061 if (current_frame_info
.initialized
)
3062 return current_frame_info
.total_size
== 0;
3064 return compute_frame_size (get_frame_size ()) == 0;
3067 /* Implement TARGET_SECONDARY_RELOAD. */
3070 microblaze_secondary_reload (bool in_p ATTRIBUTE_UNUSED
, rtx x ATTRIBUTE_UNUSED
,
3071 reg_class_t rclass
, enum machine_mode mode ATTRIBUTE_UNUSED
,
3072 secondary_reload_info
*sri ATTRIBUTE_UNUSED
)
3074 if (rclass
== ST_REGS
)
3081 microblaze_globalize_label (FILE * stream
, const char *name
)
3083 fputs ("\t.globl\t", stream
);
3084 if (microblaze_is_interrupt_variant ())
3086 if (interrupt_handler
&& strcmp (name
, INTERRUPT_HANDLER_NAME
))
3087 fputs (INTERRUPT_HANDLER_NAME
, stream
);
3088 else if (break_handler
&& strcmp (name
, BREAK_HANDLER_NAME
))
3089 fputs (BREAK_HANDLER_NAME
, stream
);
3090 else if (fast_interrupt
&& strcmp (name
, FAST_INTERRUPT_NAME
))
3091 fputs (FAST_INTERRUPT_NAME
, stream
);
3092 fputs ("\n\t.globl\t", stream
);
3094 assemble_name (stream
, name
);
3095 fputs ("\n", stream
);
3098 /* Returns true if decl should be placed into a "small data" section. */
3100 microblaze_elf_in_small_data_p (const_tree decl
)
3104 if (!TARGET_XLGPOPT
)
3107 /* We want to merge strings, so we never consider them small data. */
3108 if (TREE_CODE (decl
) == STRING_CST
)
3111 /* Functions are never in the small data area. */
3112 if (TREE_CODE (decl
) == FUNCTION_DECL
)
3115 if (TREE_CODE (decl
) == VAR_DECL
&& DECL_SECTION_NAME (decl
))
3117 const char *section
= DECL_SECTION_NAME (decl
);
3118 if (strcmp (section
, ".sdata") == 0
3119 || strcmp (section
, ".sdata2") == 0
3120 || strcmp (section
, ".sbss") == 0
3121 || strcmp (section
, ".sbss2") == 0)
3125 size
= int_size_in_bytes (TREE_TYPE (decl
));
3127 return (size
> 0 && size
<= microblaze_section_threshold
);
3132 microblaze_select_section (tree decl
, int reloc
, unsigned HOST_WIDE_INT align
)
3134 switch (categorize_decl_for_section (decl
, reloc
))
3136 case SECCAT_RODATA_MERGE_STR
:
3137 case SECCAT_RODATA_MERGE_STR_INIT
:
3138 /* MB binutils have various issues with mergeable string sections and
3139 relaxation/relocation. Currently, turning mergeable sections
3140 into regular readonly sections. */
3142 return readonly_data_section
;
3144 return default_elf_select_section (decl
, reloc
, align
);
3149 Encode info about sections into the RTL based on a symbol's declaration.
3150 The default definition of this hook, default_encode_section_info in
3151 `varasm.c', sets a number of commonly-useful bits in SYMBOL_REF_FLAGS. */
3154 microblaze_encode_section_info (tree decl
, rtx rtl
, int first
)
3156 default_encode_section_info (decl
, rtl
, first
);
3160 expand_pic_symbol_ref (enum machine_mode mode ATTRIBUTE_UNUSED
, rtx op
)
3163 result
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, op
), UNSPEC_GOTOFF
);
3164 result
= gen_rtx_CONST (Pmode
, result
);
3165 result
= gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
, result
);
3166 result
= gen_const_mem (Pmode
, result
);
3171 microblaze_asm_output_mi_thunk (FILE *file
, tree thunk_fndecl ATTRIBUTE_UNUSED
,
3172 HOST_WIDE_INT delta
, HOST_WIDE_INT vcall_offset
,
3175 rtx this_rtx
, funexp
;
3178 reload_completed
= 1;
3179 epilogue_completed
= 1;
3181 /* Mark the end of the (empty) prologue. */
3182 emit_note (NOTE_INSN_PROLOGUE_END
);
3184 /* Find the "this" pointer. If the function returns a structure,
3185 the structure return pointer is in MB_ABI_FIRST_ARG_REGNUM. */
3186 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function
)), function
))
3187 this_rtx
= gen_rtx_REG (Pmode
, (MB_ABI_FIRST_ARG_REGNUM
+ 1));
3189 this_rtx
= gen_rtx_REG (Pmode
, MB_ABI_FIRST_ARG_REGNUM
);
3191 /* Apply the constant offset, if required. */
3193 emit_insn (gen_addsi3 (this_rtx
, this_rtx
, GEN_INT (delta
)));
3195 /* Apply the offset from the vtable, if required. */
3198 rtx vcall_offset_rtx
= GEN_INT (vcall_offset
);
3199 rtx temp1
= gen_rtx_REG (Pmode
, MB_ABI_TEMP1_REGNUM
);
3201 emit_move_insn (temp1
, gen_rtx_MEM (Pmode
, this_rtx
));
3203 rtx loc
= gen_rtx_PLUS (Pmode
, temp1
, vcall_offset_rtx
);
3204 emit_move_insn (temp1
, gen_rtx_MEM (Pmode
, loc
));
3206 emit_insn (gen_addsi3 (this_rtx
, this_rtx
, temp1
));
3209 /* Generate a tail call to the target function. */
3210 if (!TREE_USED (function
))
3212 assemble_external (function
);
3213 TREE_USED (function
) = 1;
3216 funexp
= XEXP (DECL_RTL (function
), 0);
3217 rtx temp2
= gen_rtx_REG (Pmode
, MB_ABI_TEMP2_REGNUM
);
3220 emit_move_insn (temp2
, expand_pic_symbol_ref (Pmode
, funexp
));
3222 emit_move_insn (temp2
, funexp
);
3224 emit_insn (gen_indirect_jump (temp2
));
3226 /* Run just enough of rest_of_compilation. This sequence was
3227 "borrowed" from rs6000.c. */
3228 insn
= get_insns ();
3229 shorten_branches (insn
);
3230 final_start_function (insn
, file
, 1);
3231 final (insn
, file
, 1);
3232 final_end_function ();
3234 reload_completed
= 0;
3235 epilogue_completed
= 0;
3239 microblaze_expand_move (enum machine_mode mode
, rtx operands
[])
3246 if (!register_operand (op0
, SImode
)
3247 && !register_operand (op1
, SImode
)
3248 && (GET_CODE (op1
) != CONST_INT
|| INTVAL (op1
) != 0))
3250 rtx temp
= force_reg (SImode
, op1
);
3251 emit_move_insn (op0
, temp
);
3254 /* If operands[1] is a constant address invalid for pic, then we need to
3255 handle it just like LEGITIMIZE_ADDRESS does. */
3256 if (GET_CODE (op1
) == SYMBOL_REF
|| GET_CODE (op1
) == LABEL_REF
)
3259 if (microblaze_tls_symbol_p(op1
))
3261 result
= microblaze_legitimize_tls_address (op1
, NULL_RTX
);
3262 emit_move_insn (op0
, result
);
3267 if (reload_in_progress
)
3268 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
3269 result
= expand_pic_symbol_ref (mode
, op1
);
3270 emit_move_insn (op0
, result
);
3274 /* Handle Case of (const (plus symbol const_int)). */
3275 if (GET_CODE (op1
) == CONST
&& GET_CODE (XEXP (op1
,0)) == PLUS
)
3279 p0
= XEXP (XEXP (op1
, 0), 0);
3280 p1
= XEXP (XEXP (op1
, 0), 1);
3282 if ((GET_CODE (p1
) == CONST_INT
)
3283 && ((GET_CODE (p0
) == UNSPEC
)
3284 || ((GET_CODE (p0
) == SYMBOL_REF
|| GET_CODE (p0
) == LABEL_REF
)
3285 && (flag_pic
== 2 || microblaze_tls_symbol_p (p0
)
3286 || !SMALL_INT (p1
)))))
3288 rtx temp
= force_reg (SImode
, p0
);
3291 if (flag_pic
&& reload_in_progress
)
3292 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
3293 emit_move_insn (op0
, gen_rtx_PLUS (SImode
, temp
, temp2
));
3300 /* Expand shift operations. */
3302 microblaze_expand_shift (rtx operands
[])
3304 gcc_assert ((GET_CODE (operands
[2]) == CONST_INT
)
3305 || (GET_CODE (operands
[2]) == REG
)
3306 || (GET_CODE (operands
[2]) == SUBREG
));
3308 /* Shift by one -- generate pattern. */
3309 if ((GET_CODE (operands
[2]) == CONST_INT
) && (INTVAL (operands
[2]) == 1))
3312 /* Have barrel shifter and shift > 1: use it. */
3313 if (TARGET_BARREL_SHIFT
)
3316 gcc_assert ((GET_CODE (operands
[0]) == REG
)
3317 || (GET_CODE (operands
[0]) == SUBREG
)
3318 || (GET_CODE (operands
[1]) == REG
)
3319 || (GET_CODE (operands
[1]) == SUBREG
));
3321 /* Shift by zero -- copy regs if necessary. */
3322 if ((GET_CODE (operands
[2]) == CONST_INT
) && (INTVAL (operands
[2]) == 0))
3324 if (REGNO (operands
[0]) != REGNO (operands
[1]))
3325 emit_insn (gen_movsi (operands
[0], operands
[1]));
3332 /* Return an RTX indicating where the return address to the
3333 calling function can be found. */
3335 microblaze_return_addr (int count
, rtx frame ATTRIBUTE_UNUSED
)
3340 return gen_rtx_PLUS (Pmode
,
3341 get_hard_reg_initial_val (Pmode
,
3342 MB_ABI_SUB_RETURN_ADDR_REGNUM
),
3346 /* Queue an .ident string in the queue of top-level asm statements.
3347 If the string size is below the threshold, put it into .sdata2.
3348 If the front-end is done, we must be being called from toplev.c.
3349 In that case, do nothing. */
3351 microblaze_asm_output_ident (const char *string
)
3353 const char *section_asm_op
;
3357 if (symtab
->state
!= PARSING
)
3360 size
= strlen (string
) + 1;
3361 if (size
<= microblaze_section_threshold
)
3362 section_asm_op
= SDATA2_SECTION_ASM_OP
;
3364 section_asm_op
= READONLY_DATA_SECTION_ASM_OP
;
3366 buf
= ACONCAT ((section_asm_op
, "\n\t.ascii \"", string
, "\\0\"\n", NULL
));
3367 symtab
->finalize_toplevel_asm (build_string (strlen (buf
), buf
));
3371 microblaze_elf_asm_init_sections (void)
3374 = get_unnamed_section (SECTION_WRITE
, output_section_asm_op
,
3375 SDATA2_SECTION_ASM_OP
);
3378 /* Generate assembler code for constant parts of a trampoline. */
3381 microblaze_asm_trampoline_template (FILE *f
)
3383 fprintf (f
, "\tmfs r18, rpc\n");
3384 fprintf (f
, "\tlwi r3, r18, 16\n");
3385 fprintf (f
, "\tlwi r18, r18, 20\n");
3386 fprintf (f
, "\tbra r18\n");
3387 /* fprintf (f, "\t.word\t0x00000000\t\t# <function address>\n"); */
3388 /* fprintf (f, "\t.word\t0x00000000\t\t# <static chain value>\n"); */
3391 /* Implement TARGET_TRAMPOLINE_INIT. */
3394 microblaze_trampoline_init (rtx m_tramp
, tree fndecl
, rtx chain_value
)
3396 rtx fnaddr
= XEXP (DECL_RTL (fndecl
), 0);
3399 emit_block_move (m_tramp
, assemble_trampoline_template (),
3400 GEN_INT (6*UNITS_PER_WORD
), BLOCK_OP_NORMAL
);
3402 mem
= adjust_address (m_tramp
, SImode
, 16);
3403 emit_move_insn (mem
, chain_value
);
3404 mem
= adjust_address (m_tramp
, SImode
, 20);
3405 emit_move_insn (mem
, fnaddr
);
3408 /* Generate conditional branch -- first, generate test condition,
3409 second, generate correct branch instruction. */
3412 microblaze_expand_conditional_branch (enum machine_mode mode
, rtx operands
[])
3414 enum rtx_code code
= GET_CODE (operands
[0]);
3415 rtx cmp_op0
= operands
[1];
3416 rtx cmp_op1
= operands
[2];
3417 rtx label1
= operands
[3];
3418 rtx comp_reg
= gen_reg_rtx (SImode
);
3421 gcc_assert ((GET_CODE (cmp_op0
) == REG
) || (GET_CODE (cmp_op0
) == SUBREG
));
3423 /* If comparing against zero, just test source reg. */
3424 if (cmp_op1
== const0_rtx
)
3427 condition
= gen_rtx_fmt_ee (signed_condition (code
), SImode
, comp_reg
, const0_rtx
);
3428 emit_jump_insn (gen_condjump (condition
, label1
));
3431 else if (code
== EQ
|| code
== NE
)
3433 /* Use xor for equal/not-equal comparison. */
3434 emit_insn (gen_xorsi3 (comp_reg
, cmp_op0
, cmp_op1
));
3435 condition
= gen_rtx_fmt_ee (signed_condition (code
), SImode
, comp_reg
, const0_rtx
);
3436 emit_jump_insn (gen_condjump (condition
, label1
));
3440 /* Generate compare and branch in single instruction. */
3441 cmp_op1
= force_reg (mode
, cmp_op1
);
3442 condition
= gen_rtx_fmt_ee (code
, mode
, cmp_op0
, cmp_op1
);
3443 emit_jump_insn (gen_branch_compare(condition
, cmp_op0
, cmp_op1
, label1
));
3449 microblaze_expand_conditional_branch_sf (rtx operands
[])
3452 rtx cmp_op0
= XEXP (operands
[0], 0);
3453 rtx cmp_op1
= XEXP (operands
[0], 1);
3454 rtx comp_reg
= gen_reg_rtx (SImode
);
3456 emit_insn (gen_cstoresf4 (comp_reg
, operands
[0], cmp_op0
, cmp_op1
));
3457 condition
= gen_rtx_NE (SImode
, comp_reg
, const0_rtx
);
3458 emit_jump_insn (gen_condjump (condition
, operands
[3]));
3461 /* Implement TARGET_FRAME_POINTER_REQUIRED. */
3464 microblaze_frame_pointer_required (void)
3466 /* If the function contains dynamic stack allocations, we need to
3467 use the frame pointer to access the static parts of the frame. */
3468 if (cfun
->calls_alloca
)
3474 microblaze_expand_divide (rtx operands
[])
3476 /* Table lookup software divides. Works for all (nr/dr) where (0 <= nr,dr <= 15). */
3478 rtx regt1
= gen_reg_rtx (SImode
);
3479 rtx reg18
= gen_rtx_REG (SImode
, R_TMP
);
3480 rtx regqi
= gen_reg_rtx (QImode
);
3481 rtx_code_label
*div_label
= gen_label_rtx ();
3482 rtx_code_label
*div_end_label
= gen_label_rtx ();
3483 rtx div_table_rtx
= gen_rtx_SYMBOL_REF (QImode
,"_divsi3_table");
3486 rtx_insn
*jump
, *cjump
, *insn
;
3488 insn
= emit_insn (gen_iorsi3 (regt1
, operands
[1], operands
[2]));
3489 cjump
= emit_jump_insn_after (gen_cbranchsi4 (
3490 gen_rtx_GTU (SImode
, regt1
, GEN_INT (15)),
3491 regt1
, GEN_INT (15), div_label
), insn
);
3492 LABEL_NUSES (div_label
) = 1;
3493 JUMP_LABEL (cjump
) = div_label
;
3494 emit_insn (gen_rtx_CLOBBER (SImode
, reg18
));
3496 emit_insn (gen_ashlsi3_bshift (regt1
, operands
[1], GEN_INT(4)));
3497 emit_insn (gen_addsi3 (regt1
, regt1
, operands
[2]));
3498 mem_rtx
= gen_rtx_MEM (QImode
,
3499 gen_rtx_PLUS (Pmode
, regt1
, div_table_rtx
));
3501 insn
= emit_insn (gen_movqi (regqi
, mem_rtx
));
3502 insn
= emit_insn (gen_movsi (operands
[0], gen_rtx_SUBREG (SImode
, regqi
, 0)));
3503 jump
= emit_jump_insn_after (gen_jump (div_end_label
), insn
);
3504 JUMP_LABEL (jump
) = div_end_label
;
3505 LABEL_NUSES (div_end_label
) = 1;
3508 emit_label (div_label
);
3509 ret
= emit_library_call_value (gen_rtx_SYMBOL_REF (Pmode
, "__divsi3"),
3510 operands
[0], LCT_NORMAL
,
3511 GET_MODE (operands
[0]), 2, operands
[1],
3512 GET_MODE (operands
[1]), operands
[2],
3513 GET_MODE (operands
[2]));
3514 if (ret
!= operands
[0])
3515 emit_move_insn (operands
[0], ret
);
3517 emit_label (div_end_label
);
3518 emit_insn (gen_blockage ());
3521 /* Implement TARGET_FUNCTION_VALUE. */
3523 microblaze_function_value (const_tree valtype
,
3524 const_tree func ATTRIBUTE_UNUSED
,
3525 bool outgoing ATTRIBUTE_UNUSED
)
3527 return LIBCALL_VALUE (TYPE_MODE (valtype
));
3530 /* Implement TARGET_SCHED_ADJUST_COST. */
3532 microblaze_adjust_cost (rtx_insn
*insn ATTRIBUTE_UNUSED
, rtx link
,
3533 rtx_insn
*dep ATTRIBUTE_UNUSED
, int cost
)
3535 if (REG_NOTE_KIND (link
) == REG_DEP_OUTPUT
)
3537 if (REG_NOTE_KIND (link
) != 0)
3542 /* Implement TARGET_LEGITIMATE_CONSTANT_P.
3544 At present, GAS doesn't understand li.[sd], so don't allow it
3545 to be generated at present. */
3547 microblaze_legitimate_constant_p (enum machine_mode mode ATTRIBUTE_UNUSED
, rtx x
)
3550 if (microblaze_cannot_force_const_mem(mode
, x
))
3553 if (GET_CODE (x
) == CONST_DOUBLE
)
3555 return microblaze_const_double_ok (x
, GET_MODE (x
));
3558 /* Handle Case of (const (plus unspec const_int)). */
3559 if (GET_CODE (x
) == CONST
&& GET_CODE (XEXP (x
,0)) == PLUS
)
3563 p0
= XEXP (XEXP (x
, 0), 0);
3564 p1
= XEXP (XEXP (x
, 0), 1);
3566 if (GET_CODE(p1
) == CONST_INT
)
3568 /* Const offset from UNSPEC is not supported. */
3569 if ((GET_CODE (p0
) == UNSPEC
))
3572 if ((GET_CODE (p0
) == SYMBOL_REF
|| GET_CODE (p0
) == LABEL_REF
)
3573 && (microblaze_tls_symbol_p (p0
) || !SMALL_INT (p1
)))
3582 #undef TARGET_ENCODE_SECTION_INFO
3583 #define TARGET_ENCODE_SECTION_INFO microblaze_encode_section_info
3585 #undef TARGET_ASM_GLOBALIZE_LABEL
3586 #define TARGET_ASM_GLOBALIZE_LABEL microblaze_globalize_label
3588 #undef TARGET_ASM_FUNCTION_PROLOGUE
3589 #define TARGET_ASM_FUNCTION_PROLOGUE microblaze_function_prologue
3591 #undef TARGET_ASM_FUNCTION_EPILOGUE
3592 #define TARGET_ASM_FUNCTION_EPILOGUE microblaze_function_epilogue
3594 #undef TARGET_RTX_COSTS
3595 #define TARGET_RTX_COSTS microblaze_rtx_costs
3597 #undef TARGET_CANNOT_FORCE_CONST_MEM
3598 #define TARGET_CANNOT_FORCE_CONST_MEM microblaze_cannot_force_const_mem
3600 #undef TARGET_ADDRESS_COST
3601 #define TARGET_ADDRESS_COST microblaze_address_cost
3603 #undef TARGET_ATTRIBUTE_TABLE
3604 #define TARGET_ATTRIBUTE_TABLE microblaze_attribute_table
3606 #undef TARGET_IN_SMALL_DATA_P
3607 #define TARGET_IN_SMALL_DATA_P microblaze_elf_in_small_data_p
3609 #undef TARGET_ASM_SELECT_SECTION
3610 #define TARGET_ASM_SELECT_SECTION microblaze_select_section
3612 #undef TARGET_HAVE_SRODATA_SECTION
3613 #define TARGET_HAVE_SRODATA_SECTION true
3615 #undef TARGET_ASM_FUNCTION_END_PROLOGUE
3616 #define TARGET_ASM_FUNCTION_END_PROLOGUE \
3617 microblaze_function_end_prologue
3619 #undef TARGET_ARG_PARTIAL_BYTES
3620 #define TARGET_ARG_PARTIAL_BYTES function_arg_partial_bytes
3622 #undef TARGET_FUNCTION_ARG
3623 #define TARGET_FUNCTION_ARG microblaze_function_arg
3625 #undef TARGET_FUNCTION_ARG_ADVANCE
3626 #define TARGET_FUNCTION_ARG_ADVANCE microblaze_function_arg_advance
3628 #undef TARGET_CAN_ELIMINATE
3629 #define TARGET_CAN_ELIMINATE microblaze_can_eliminate
3631 #undef TARGET_LEGITIMIZE_ADDRESS
3632 #define TARGET_LEGITIMIZE_ADDRESS microblaze_legitimize_address
3634 #undef TARGET_LEGITIMATE_ADDRESS_P
3635 #define TARGET_LEGITIMATE_ADDRESS_P microblaze_legitimate_address_p
3637 #undef TARGET_FRAME_POINTER_REQUIRED
3638 #define TARGET_FRAME_POINTER_REQUIRED microblaze_frame_pointer_required
3640 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
3641 #define TARGET_ASM_TRAMPOLINE_TEMPLATE microblaze_asm_trampoline_template
3643 #undef TARGET_TRAMPOLINE_INIT
3644 #define TARGET_TRAMPOLINE_INIT microblaze_trampoline_init
3646 #undef TARGET_PROMOTE_FUNCTION_MODE
3647 #define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
3649 #undef TARGET_FUNCTION_VALUE
3650 #define TARGET_FUNCTION_VALUE microblaze_function_value
3652 #undef TARGET_SECONDARY_RELOAD
3653 #define TARGET_SECONDARY_RELOAD microblaze_secondary_reload
3655 #undef TARGET_ASM_OUTPUT_MI_THUNK
3656 #define TARGET_ASM_OUTPUT_MI_THUNK microblaze_asm_output_mi_thunk
3658 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
3659 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true
3661 #undef TARGET_SCHED_ADJUST_COST
3662 #define TARGET_SCHED_ADJUST_COST microblaze_adjust_cost
3664 #undef TARGET_ASM_INIT_SECTIONS
3665 #define TARGET_ASM_INIT_SECTIONS microblaze_elf_asm_init_sections
3667 #undef TARGET_OPTION_OVERRIDE
3668 #define TARGET_OPTION_OVERRIDE microblaze_option_override
3670 #undef TARGET_LEGITIMATE_CONSTANT_P
3671 #define TARGET_LEGITIMATE_CONSTANT_P microblaze_legitimate_constant_p
3673 struct gcc_target targetm
= TARGET_INITIALIZER
;
3675 #include "gt-microblaze.h"