1 /* Subroutines used for code generation on Xilinx MicroBlaze.
2 Copyright (C) 2009-2015 Free Software Foundation, Inc.
4 Contributed by Michael Eager <eager@eagercon.com>.
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published
10 by the Free Software Foundation; either version 3, or (at your
11 option) any later version.
13 GCC is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16 License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. */
24 #include "coretypes.h"
28 #include "hard-reg-set.h"
30 #include "insn-config.h"
31 #include "conditions.h"
32 #include "insn-flags.h"
33 #include "insn-attr.h"
38 #include "double-int.h"
46 #include "stor-layout.h"
51 #include "statistics.h"
52 #include "fixed-value.h"
63 #include "target-def.h"
66 #include "dominance.h"
72 #include "cfgcleanup.h"
74 #include "basic-block.h"
76 #include "insn-codes.h"
78 #include "diagnostic-core.h"
81 #include "plugin-api.h"
87 #define MICROBLAZE_VERSION_COMPARE(VA,VB) strcasecmp (VA, VB)
89 /* Classifies an address.
96 A natural register or a register + const_int offset address.
97 The register satisfies microblaze_valid_base_register_p and the
98 offset is a const_arith_operand.
102 A natural register offset by the index contained in an index register. The base
103 register satisfies microblaze_valid_base_register_p and the index register
104 satisfies microblaze_valid_index_register_p
108 A signed 16/32-bit constant address.
112 A constant symbolic address or a (register + symbol). */
114 enum microblaze_address_type
126 /* Classifies symbols
131 enum microblaze_symbol_type
137 /* TLS Address Type. */
146 /* Classification of a MicroBlaze address. */
147 struct microblaze_address_info
149 enum microblaze_address_type type
;
150 rtx regA
; /* Contains valid values on ADDRESS_REG, ADDRESS_REG_INDEX,
152 rtx regB
; /* Contains valid values on ADDRESS_REG_INDEX. */
153 rtx offset
; /* Contains valid values on ADDRESS_CONST_INT and ADDRESS_REG. */
154 rtx symbol
; /* Contains valid values on ADDRESS_SYMBOLIC. */
155 enum microblaze_symbol_type symbol_type
;
156 enum tls_reloc tls_type
;
159 /* Structure to be filled in by compute_frame_size with register
160 save masks, and offsets for the current function. */
162 struct GTY(()) microblaze_frame_info
{
163 long total_size
; /* # bytes that the entire frame takes up. */
164 long var_size
; /* # bytes that variables take up. */
165 long args_size
; /* # bytes that outgoing arguments take up. */
166 int link_debug_size
; /* # bytes for the link reg and back pointer. */
167 int gp_reg_size
; /* # bytes needed to store gp regs. */
168 long gp_offset
; /* offset from new sp to store gp registers. */
169 long mask
; /* mask of saved gp registers. */
170 int initialized
; /* != 0 if frame size already calculated. */
171 int num_gp
; /* number of gp registers saved. */
172 long insns_len
; /* length of insns. */
173 int alloc_stack
; /* Flag to indicate if the current function
174 must not create stack space. (As an optimization). */
177 /* Global variables for machine-dependent things. */
179 /* Toggle which pipleline interface to use. */
180 static GTY(()) int microblaze_sched_use_dfa
= 0;
182 /* Threshold for data being put into the small data/bss area, instead
183 of the normal data area (references to the small data/bss area take
184 1 instruction, and use the global pointer, references to the normal
185 data area takes 2 instructions). */
186 int microblaze_section_threshold
= -1;
188 /* Prevent scheduling potentially exception causing instructions in
189 delay slots. -mcpu=v3.00.a or v4.00.a turns this on. */
190 int microblaze_no_unsafe_delay
;
192 /* Set to one if the targeted core has the CLZ insn. */
193 int microblaze_has_clz
= 0;
195 /* Which CPU pipeline do we use. We haven't really standardized on a CPU
196 version having only a particular type of pipeline. There can still be
197 options on the CPU to scale pipeline features up or down. :(
198 Bad Presentation (??), so we let the MD file rely on the value of
199 this variable instead Making PIPE_5 the default. It should be backward
200 optimal with PIPE_3 MicroBlazes. */
201 enum pipeline_type microblaze_pipe
= MICROBLAZE_PIPE_5
;
203 /* High and low marks for floating point values which we will accept
204 as legitimate constants for TARGET_LEGITIMATE_CONSTANT_P. These are
205 initialized in override_options. */
206 REAL_VALUE_TYPE dfhigh
, dflow
, sfhigh
, sflow
;
208 /* Array giving truth value on whether or not a given hard register
209 can support a given mode. */
210 char microblaze_hard_regno_mode_ok
[(int)MAX_MACHINE_MODE
]
211 [FIRST_PSEUDO_REGISTER
];
213 /* Current frame information calculated by compute_frame_size. */
214 struct microblaze_frame_info current_frame_info
;
216 /* Zero structure to initialize current_frame_info. */
217 struct microblaze_frame_info zero_frame_info
;
219 /* List of all MICROBLAZE punctuation characters used by print_operand. */
220 char microblaze_print_operand_punct
[256];
222 /* Map GCC register number to debugger register number. */
223 int microblaze_dbx_regno
[FIRST_PSEUDO_REGISTER
];
225 /* Map hard register number to register class. */
226 enum reg_class microblaze_regno_to_class
[] =
228 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
229 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
230 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
231 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
232 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
233 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
234 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
235 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
236 ST_REGS
, GR_REGS
, GR_REGS
, GR_REGS
239 /* MicroBlaze specific machine attributes.
240 interrupt_handler - Interrupt handler attribute to add interrupt prologue
241 and epilogue and use appropriate interrupt return.
242 save_volatiles - Similar to interrupt handler, but use normal return. */
243 int interrupt_handler
;
248 const struct attribute_spec microblaze_attribute_table
[] = {
249 /* name min_len, max_len, decl_req, type_req, fn_type, req_handler,
250 affects_type_identity */
251 {"interrupt_handler", 0, 0, true, false, false, NULL
,
253 {"break_handler", 0, 0, true, false, false, NULL
,
255 {"fast_interrupt", 0, 0, true, false, false, NULL
,
257 {"save_volatiles" , 0, 0, true, false, false, NULL
,
259 { NULL
, 0, 0, false, false, false, NULL
,
263 static int microblaze_interrupt_function_p (tree
);
265 static void microblaze_elf_asm_constructor (rtx
, int) ATTRIBUTE_UNUSED
;
266 static void microblaze_elf_asm_destructor (rtx
, int) ATTRIBUTE_UNUSED
;
268 section
*sdata2_section
;
271 #undef TARGET_HAVE_TLS
272 #define TARGET_HAVE_TLS true
275 /* Return truth value if a CONST_DOUBLE is ok to be a legitimate constant. */
277 microblaze_const_double_ok (rtx op
, machine_mode mode
)
281 if (GET_CODE (op
) != CONST_DOUBLE
)
284 if (GET_MODE (op
) == VOIDmode
)
287 if (mode
!= SFmode
&& mode
!= DFmode
)
290 if (op
== CONST0_RTX (mode
))
293 REAL_VALUE_FROM_CONST_DOUBLE (d
, op
);
295 if (REAL_VALUE_ISNAN (d
))
298 if (REAL_VALUE_NEGATIVE (d
))
299 d
= real_value_negate (&d
);
303 if (REAL_VALUES_LESS (d
, dfhigh
) && REAL_VALUES_LESS (dflow
, d
))
308 if (REAL_VALUES_LESS (d
, sfhigh
) && REAL_VALUES_LESS (sflow
, d
))
315 /* Return truth value if a memory operand fits in a single instruction
316 (ie, register + small offset) or (register + register). */
319 simple_memory_operand (rtx op
, machine_mode mode ATTRIBUTE_UNUSED
)
321 rtx addr
, plus0
, plus1
;
323 /* Eliminate non-memory operations. */
324 if (GET_CODE (op
) != MEM
)
327 /* dword operations really put out 2 instructions, so eliminate them. */
328 /* ??? This isn't strictly correct. It is OK to accept multiword modes
329 here, since the length attributes are being set correctly, but only
330 if the address is offsettable. */
331 if (GET_MODE_SIZE (GET_MODE (op
)) > UNITS_PER_WORD
)
335 /* Decode the address now. */
337 switch (GET_CODE (addr
))
344 plus0
= XEXP (addr
, 0);
345 plus1
= XEXP (addr
, 1);
347 if (GET_CODE (plus0
) != REG
)
350 if (GET_CODE (plus0
) == REG
&& GET_CODE (plus1
) == CONST_INT
351 && SMALL_INT (plus1
))
355 else if (GET_CODE (plus1
) == REG
&& GET_CODE (plus0
) == CONST_INT
)
359 else if (GET_CODE (plus0
) == REG
&& GET_CODE (plus1
) == REG
)
376 /* Return nonzero for a memory address that can be used to load or store
380 double_memory_operand (rtx op
, machine_mode mode
)
384 if (GET_CODE (op
) != MEM
|| !memory_operand (op
, mode
))
386 /* During reload, we accept a pseudo register if it has an
387 appropriate memory address. If we don't do this, we will
388 wind up reloading into a register, and then reloading that
389 register from memory, when we could just reload directly from
391 if (reload_in_progress
392 && GET_CODE (op
) == REG
393 && REGNO (op
) >= FIRST_PSEUDO_REGISTER
394 && reg_renumber
[REGNO (op
)] < 0
395 && reg_equiv_mem (REGNO (op
)) != 0
396 && double_memory_operand (reg_equiv_mem (REGNO (op
)), mode
))
401 /* Make sure that 4 added to the address is a valid memory address.
402 This essentially just checks for overflow in an added constant. */
406 if (CONSTANT_ADDRESS_P (addr
))
409 return memory_address_p ((GET_MODE_CLASS (mode
) == MODE_INT
411 plus_constant (Pmode
, addr
, 4));
414 /* Implement REG_OK_FOR_BASE_P -and- REG_OK_FOR_INDEX_P. */
416 microblaze_regno_ok_for_base_p (int regno
, int strict
)
418 if (regno
>= FIRST_PSEUDO_REGISTER
)
422 regno
= reg_renumber
[regno
];
425 /* These fake registers will be eliminated to either the stack or
426 hard frame pointer, both of which are usually valid base registers.
427 Reload deals with the cases where the eliminated form isn't valid. */
428 if (regno
== ARG_POINTER_REGNUM
|| regno
== FRAME_POINTER_REGNUM
)
431 return GP_REG_P (regno
);
434 /* Return true if X is a valid base register for the given mode.
435 Allow only hard registers if STRICT. */
438 microblaze_valid_base_register_p (rtx x
,
439 machine_mode mode ATTRIBUTE_UNUSED
,
442 if (!strict
&& GET_CODE (x
) == SUBREG
)
445 return (GET_CODE (x
) == REG
446 && microblaze_regno_ok_for_base_p (REGNO (x
), strict
));
449 /* Build the SYMBOL_REF for __tls_get_addr. */
451 static GTY(()) rtx tls_get_addr_libfunc
;
454 get_tls_get_addr (void)
456 if (!tls_get_addr_libfunc
)
457 tls_get_addr_libfunc
= init_one_libfunc ("__tls_get_addr");
458 return tls_get_addr_libfunc
;
461 /* Return TRUE if X is a thread-local symbol. */
463 microblaze_tls_symbol_p (rtx x
)
465 if (!TARGET_HAVE_TLS
)
468 if (GET_CODE (x
) != SYMBOL_REF
)
471 return SYMBOL_REF_TLS_MODEL (x
) != 0;
474 /* Return TRUE if X contains any TLS symbol references. */
477 microblaze_tls_referenced_p (rtx x
)
479 if (!TARGET_HAVE_TLS
)
481 subrtx_iterator::array_type array
;
482 FOR_EACH_SUBRTX (iter
, array
, x
, ALL
)
485 if (GET_CODE (x
) == SYMBOL_REF
&& SYMBOL_REF_TLS_MODEL (x
) != 0)
487 /* Don't recurse into UNSPEC_TLS looking for TLS symbols; these are
488 TLS offsets, not real symbol references. */
489 if (GET_CODE (x
) == UNSPEC
&& XINT (x
, 1) == UNSPEC_TLS
)
490 iter
.skip_subrtxes ();
496 microblaze_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED
, rtx x
)
498 return microblaze_tls_referenced_p(x
);
501 /* Return TRUE if X references a SYMBOL_REF. */
503 symbol_mentioned_p (rtx x
)
508 if (GET_CODE (x
) == SYMBOL_REF
)
511 /* UNSPEC entries for a symbol include the SYMBOL_REF, but they
512 are constant offsets, not symbols. */
513 if (GET_CODE (x
) == UNSPEC
)
516 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 (symbol_mentioned_p (XVECEXP (x
, i
, j
)))
528 else if (fmt
[i
] == 'e' && symbol_mentioned_p (XEXP (x
, i
)))
535 /* Return TRUE if X references a LABEL_REF. */
537 label_mentioned_p (rtx x
)
542 if (GET_CODE (x
) == LABEL_REF
)
545 /* UNSPEC entries for a symbol include a LABEL_REF for the referencing
546 instruction, but they are constant offsets, not symbols. */
547 if (GET_CODE (x
) == UNSPEC
)
550 fmt
= GET_RTX_FORMAT (GET_CODE (x
));
551 for (i
= GET_RTX_LENGTH (GET_CODE (x
)) - 1; i
>= 0; i
--)
557 for (j
= XVECLEN (x
, i
) - 1; j
>= 0; j
--)
558 if (label_mentioned_p (XVECEXP (x
, i
, j
)))
561 else if (fmt
[i
] == 'e' && label_mentioned_p (XEXP (x
, i
)))
569 tls_mentioned_p (rtx x
)
571 switch (GET_CODE (x
))
574 return tls_mentioned_p (XEXP (x
, 0));
577 if (XINT (x
, 1) == UNSPEC_TLS
)
586 load_tls_operand (rtx x
, rtx reg
)
591 reg
= gen_reg_rtx (Pmode
);
593 tmp
= gen_rtx_CONST (Pmode
, x
);
595 emit_insn (gen_rtx_SET (reg
,
596 gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
, tmp
)));
602 microblaze_call_tls_get_addr (rtx x
, rtx reg
, rtx
*valuep
, int reloc
)
607 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
611 tls_entry
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (2, x
, GEN_INT (reloc
)),
614 reg
= load_tls_operand (tls_entry
, reg
);
616 *valuep
= emit_library_call_value (get_tls_get_addr (), NULL_RTX
,
617 LCT_PURE
, /* LCT_CONST? */
618 Pmode
, 1, reg
, Pmode
);
620 insns
= get_insns ();
627 microblaze_legitimize_tls_address(rtx x
, rtx reg
)
629 rtx dest
, ret
, eqv
, addend
;
631 enum tls_model model
;
632 model
= SYMBOL_REF_TLS_MODEL (x
);
636 case TLS_MODEL_LOCAL_DYNAMIC
:
637 case TLS_MODEL_GLOBAL_DYNAMIC
:
638 case TLS_MODEL_INITIAL_EXEC
:
639 insns
= microblaze_call_tls_get_addr (x
, reg
, &ret
, TLS_GD
);
640 dest
= gen_reg_rtx (Pmode
);
641 emit_libcall_block (insns
, dest
, ret
, x
);
644 case TLS_MODEL_LOCAL_EXEC
:
645 insns
= microblaze_call_tls_get_addr (x
, reg
, &ret
, TLS_LDM
);
647 /* Attach a unique REG_EQUIV, to allow the RTL optimizers to
648 share the LDM result with other LD model accesses. */
649 eqv
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, const1_rtx
), UNSPEC_TLS
);
650 dest
= gen_reg_rtx (Pmode
);
651 emit_libcall_block (insns
, dest
, ret
, eqv
);
653 /* Load the addend. */
654 addend
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (2, x
, GEN_INT (TLS_DTPREL
)),
656 addend
= force_reg (SImode
, gen_rtx_CONST (SImode
, addend
));
657 dest
= gen_rtx_PLUS (Pmode
, dest
, addend
);
667 microblaze_classify_unspec (struct microblaze_address_info
*info
, rtx x
)
669 info
->symbol_type
= SYMBOL_TYPE_GENERAL
;
670 info
->symbol
= XVECEXP (x
, 0, 0);
672 if (XINT (x
, 1) == UNSPEC_GOTOFF
)
674 info
->regA
= gen_rtx_REG (SImode
, PIC_OFFSET_TABLE_REGNUM
);
675 info
->type
= ADDRESS_GOTOFF
;
677 else if (XINT (x
, 1) == UNSPEC_PLT
)
679 info
->type
= ADDRESS_PLT
;
681 else if (XINT (x
, 1) == UNSPEC_TLS
)
683 info
->type
= ADDRESS_TLS
;
684 info
->tls_type
= tls_reloc
INTVAL(XVECEXP(x
, 0, 1));
694 /* Return true if X is a valid index register for the given mode.
695 Allow only hard registers if STRICT. */
698 microblaze_valid_index_register_p (rtx x
,
699 machine_mode mode ATTRIBUTE_UNUSED
,
702 if (!strict
&& GET_CODE (x
) == SUBREG
)
705 return (GET_CODE (x
) == REG
706 /* A base register is good enough to be an index register on MicroBlaze. */
707 && microblaze_regno_ok_for_base_p (REGNO (x
), strict
));
710 /* Get the base register for accessing a value from the memory or
711 Symbol ref. Used for MicroBlaze Small Data Area Pointer Optimization. */
718 if (!flag_pic
|| microblaze_tls_symbol_p(x
))
719 base_reg
= MB_ABI_BASE_REGNUM
;
721 base_reg
= MB_ABI_PIC_ADDR_REGNUM
;
724 && GET_CODE (x
) == SYMBOL_REF
725 && SYMBOL_REF_SMALL_P (x
) && (decl
= SYMBOL_REF_DECL (x
)) != NULL
)
727 if (TREE_READONLY (decl
))
728 base_reg
= MB_ABI_GPRO_REGNUM
;
730 base_reg
= MB_ABI_GPRW_REGNUM
;
736 /* Return true if X is a valid address for machine mode MODE. If it is,
737 fill in INFO appropriately. STRICT is true if we should only accept
740 type regA regB offset symbol
742 ADDRESS_INVALID NULL NULL NULL NULL
744 ADDRESS_REG %0 NULL const_0 / NULL
746 ADDRESS_REG_INDEX %0 %1 NULL NULL
748 ADDRESS_SYMBOLIC r0 / NULL NULL symbol
751 ADDRESS_CONST_INT r0 NULL const NULL
753 For modes spanning multiple registers (DFmode in 32-bit GPRs,
754 DImode, TImode), indexed addressing cannot be used because
755 adjacent memory cells are accessed by adding word-sized offsets
756 during assembly output. */
759 microblaze_classify_address (struct microblaze_address_info
*info
, rtx x
,
760 machine_mode mode
, int strict
)
765 info
->type
= ADDRESS_INVALID
;
770 info
->symbol_type
= SYMBOL_TYPE_INVALID
;
772 switch (GET_CODE (x
))
777 info
->type
= ADDRESS_REG
;
779 info
->offset
= const0_rtx
;
780 return microblaze_valid_base_register_p (info
->regA
, mode
, strict
);
784 xplus0
= XEXP (x
, 0);
785 xplus1
= XEXP (x
, 1);
787 if (microblaze_valid_base_register_p (xplus0
, mode
, strict
))
789 info
->type
= ADDRESS_REG
;
792 if (GET_CODE (xplus1
) == CONST_INT
)
794 info
->offset
= xplus1
;
797 else if (GET_CODE (xplus1
) == UNSPEC
)
799 /* Need offsettable address. */
800 if (GET_MODE_SIZE (mode
) > UNITS_PER_WORD
)
803 return microblaze_classify_unspec (info
, xplus1
);
805 else if ((GET_CODE (xplus1
) == SYMBOL_REF
||
806 GET_CODE (xplus1
) == LABEL_REF
))
808 if (flag_pic
== 2 || microblaze_tls_symbol_p(xplus1
))
810 info
->type
= ADDRESS_SYMBOLIC
;
811 info
->symbol
= xplus1
;
812 info
->symbol_type
= SYMBOL_TYPE_GENERAL
;
815 else if (GET_CODE (xplus1
) == CONST
)
817 rtx xconst0
= XEXP(xplus1
, 0);
820 if (GET_CODE (xconst0
) == UNSPEC
)
822 /* Need offsettable address. */
823 if (GET_MODE_SIZE (mode
) > UNITS_PER_WORD
)
825 return microblaze_classify_unspec(info
, xconst0
);
828 /* for (plus x const_int) just look at x. */
829 if (GET_CODE (xconst0
) == PLUS
830 && GET_CODE (XEXP (xconst0
, 1)) == CONST_INT
831 && SMALL_INT (XEXP (xconst0
, 1)))
833 /* This is ok as info->symbol is set to xplus1 the full
834 const-expression below. */
835 xconst0
= XEXP (xconst0
, 0);
838 if (GET_CODE (xconst0
) == SYMBOL_REF
839 || GET_CODE (xconst0
) == LABEL_REF
)
841 if (flag_pic
== 2 || microblaze_tls_symbol_p(xconst0
))
844 info
->type
= ADDRESS_SYMBOLIC
;
845 info
->symbol
= xplus1
;
846 info
->symbol_type
= SYMBOL_TYPE_GENERAL
;
850 /* Not base + symbol || base + UNSPEC. */
854 else if (GET_CODE (xplus1
) == REG
855 && microblaze_valid_index_register_p (xplus1
, mode
,
857 && (GET_MODE_SIZE (mode
) <= UNITS_PER_WORD
))
859 /* Restrict larger than word-width modes from using an index register. */
860 info
->type
= ADDRESS_REG_INDEX
;
869 info
->regA
= gen_rtx_raw_REG (mode
, 0);
870 info
->type
= ADDRESS_CONST_INT
;
878 info
->type
= ADDRESS_SYMBOLIC
;
879 info
->symbol_type
= SYMBOL_TYPE_GENERAL
;
881 info
->regA
= gen_rtx_raw_REG (mode
, get_base_reg (x
));
883 if (GET_CODE (x
) == CONST
)
885 if (GET_CODE (XEXP (x
, 0)) == UNSPEC
)
887 info
->regA
= gen_rtx_raw_REG (mode
,
888 get_base_reg (XVECEXP (XEXP (x
,0), 0, 0)));
889 return microblaze_classify_unspec (info
, XEXP (x
, 0));
891 return !(flag_pic
&& pic_address_needs_scratch (x
));
896 else if (microblaze_tls_symbol_p(x
))
904 if (reload_in_progress
)
905 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
906 return microblaze_classify_unspec (info
, x
);
916 /* This function is used to implement GO_IF_LEGITIMATE_ADDRESS. It
917 returns a nonzero value if X is a legitimate address for a memory
918 operand of the indicated MODE. STRICT is nonzero if this function
919 is called during reload. */
922 microblaze_legitimate_address_p (machine_mode mode
, rtx x
, bool strict
)
924 struct microblaze_address_info addr
;
926 return microblaze_classify_address (&addr
, x
, mode
, strict
);
930 microblaze_valid_pic_const (rtx x
)
932 switch (GET_CODE (x
))
944 microblaze_legitimate_pic_operand (rtx x
)
946 if (flag_pic
== 2 && (symbol_mentioned_p(x
) || label_mentioned_p(x
)))
949 if (microblaze_tls_referenced_p(x
))
955 /* Try machine-dependent ways of modifying an illegitimate address
956 to be legitimate. If we find one, return the new, valid address.
957 This is used from only one place: `memory_address' in explow.c.
959 OLDX is the address as it was before break_out_memory_refs was
960 called. In some cases it is useful to look at this to decide what
963 It is always safe for this function to do nothing. It exists to
964 recognize opportunities to optimize the output.
966 For the MicroBlaze, transform:
968 memory(X + <large int>)
972 Y = <large int> & ~0x7fff;
974 memory (Z + (<large int> & 0x7fff));
976 This is for CSE to find several similar references, and only use one Z.
978 When PIC, convert addresses of the form memory (symbol+large int) to
979 memory (reg+large int). */
982 microblaze_legitimize_address (rtx x
, rtx oldx ATTRIBUTE_UNUSED
,
983 machine_mode mode ATTRIBUTE_UNUSED
)
985 register rtx xinsn
= x
, result
;
987 if (GET_CODE (xinsn
) == CONST
988 && flag_pic
&& pic_address_needs_scratch (xinsn
))
990 rtx ptr_reg
= gen_reg_rtx (Pmode
);
991 rtx constant
= XEXP (XEXP (xinsn
, 0), 1);
993 emit_move_insn (ptr_reg
, XEXP (XEXP (xinsn
, 0), 0));
995 result
= gen_rtx_PLUS (Pmode
, ptr_reg
, constant
);
996 if (SMALL_INT (constant
))
998 /* Otherwise we fall through so the code below will fix the
1003 if (GET_CODE (xinsn
) == PLUS
)
1005 register rtx xplus0
= XEXP (xinsn
, 0);
1006 register rtx xplus1
= XEXP (xinsn
, 1);
1007 register enum rtx_code code0
= GET_CODE (xplus0
);
1008 register enum rtx_code code1
= GET_CODE (xplus1
);
1010 if (code0
!= REG
&& code1
== REG
)
1012 xplus0
= XEXP (xinsn
, 1);
1013 xplus1
= XEXP (xinsn
, 0);
1014 code0
= GET_CODE (xplus0
);
1015 code1
= GET_CODE (xplus1
);
1018 if (code0
== REG
&& REG_OK_FOR_BASE_P (xplus0
)
1019 && code1
== CONST_INT
&& !SMALL_INT (xplus1
))
1021 rtx int_reg
= gen_reg_rtx (Pmode
);
1022 rtx ptr_reg
= gen_reg_rtx (Pmode
);
1024 emit_move_insn (int_reg
, GEN_INT (INTVAL (xplus1
) & ~0x7fff));
1026 emit_insn (gen_rtx_SET (ptr_reg
,
1027 gen_rtx_PLUS (Pmode
, xplus0
, int_reg
)));
1029 result
= gen_rtx_PLUS (Pmode
, ptr_reg
,
1030 GEN_INT (INTVAL (xplus1
) & 0x7fff));
1034 if (code0
== REG
&& REG_OK_FOR_BASE_P (xplus0
))
1036 if (reload_in_progress
)
1037 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
1040 xplus1
= XEXP (xplus1
, 0);
1041 code1
= GET_CODE (xplus1
);
1043 if (code1
== SYMBOL_REF
)
1045 if (microblaze_tls_symbol_p(xplus1
))
1048 reg
= gen_reg_rtx (Pmode
);
1050 tls_ref
= microblaze_legitimize_tls_address (xplus1
,
1052 emit_move_insn (reg
, tls_ref
);
1054 result
= gen_rtx_PLUS (Pmode
, xplus0
, reg
);
1058 else if (flag_pic
== 2)
1061 reg
= gen_reg_rtx (Pmode
);
1063 pic_ref
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, xplus1
),
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
);
1068 emit_move_insn (reg
, pic_ref
);
1069 result
= gen_rtx_PLUS (Pmode
, xplus0
, reg
);
1076 if (GET_CODE (xinsn
) == SYMBOL_REF
)
1079 if (microblaze_tls_symbol_p(xinsn
))
1081 reg
= microblaze_legitimize_tls_address (xinsn
, NULL_RTX
);
1087 if (reload_in_progress
)
1088 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
1090 pic_ref
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, xinsn
), UNSPEC_GOTOFF
);
1091 pic_ref
= gen_rtx_CONST (Pmode
, pic_ref
);
1092 pic_ref
= gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
, pic_ref
);
1093 pic_ref
= gen_const_mem (Pmode
, pic_ref
);
1104 #define MAX_MOVE_REGS 8
1105 #define MAX_MOVE_BYTES (MAX_MOVE_REGS * UNITS_PER_WORD)
1107 /* Emit straight-line code to move LENGTH bytes from SRC to DEST.
1108 Assume that the areas do not overlap. */
1111 microblaze_block_move_straight (rtx dest
, rtx src
, HOST_WIDE_INT length
)
1113 HOST_WIDE_INT offset
, delta
;
1114 unsigned HOST_WIDE_INT bits
;
1119 bits
= BITS_PER_WORD
;
1120 mode
= mode_for_size (bits
, MODE_INT
, 0);
1121 delta
= bits
/ BITS_PER_UNIT
;
1123 /* Allocate a buffer for the temporary registers. */
1124 regs
= XALLOCAVEC (rtx
, length
/ delta
);
1126 /* Load as many BITS-sized chunks as possible. Use a normal load if
1127 the source has enough alignment, otherwise use left/right pairs. */
1128 for (offset
= 0, i
= 0; offset
+ delta
<= length
; offset
+= delta
, i
++)
1130 regs
[i
] = gen_reg_rtx (mode
);
1131 emit_move_insn (regs
[i
], adjust_address (src
, mode
, offset
));
1134 /* Copy the chunks to the destination. */
1135 for (offset
= 0, i
= 0; offset
+ delta
<= length
; offset
+= delta
, i
++)
1136 emit_move_insn (adjust_address (dest
, mode
, offset
), regs
[i
]);
1138 /* Mop up any left-over bytes. */
1139 if (offset
< length
)
1141 src
= adjust_address (src
, BLKmode
, offset
);
1142 dest
= adjust_address (dest
, BLKmode
, offset
);
1143 move_by_pieces (dest
, src
, length
- offset
,
1144 MIN (MEM_ALIGN (src
), MEM_ALIGN (dest
)), 0);
1148 /* Helper function for doing a loop-based block operation on memory
1149 reference MEM. Each iteration of the loop will operate on LENGTH
1152 Create a new base register for use within the loop and point it to
1153 the start of MEM. Create a new memory reference that uses this
1154 register. Store them in *LOOP_REG and *LOOP_MEM respectively. */
1157 microblaze_adjust_block_mem (rtx mem
, HOST_WIDE_INT length
,
1158 rtx
* loop_reg
, rtx
* loop_mem
)
1160 *loop_reg
= copy_addr_to_reg (XEXP (mem
, 0));
1162 /* Although the new mem does not refer to a known location,
1163 it does keep up to LENGTH bytes of alignment. */
1164 *loop_mem
= change_address (mem
, BLKmode
, *loop_reg
);
1165 set_mem_align (*loop_mem
,
1166 MIN ((HOST_WIDE_INT
) MEM_ALIGN (mem
),
1167 length
* BITS_PER_UNIT
));
1171 /* Move LENGTH bytes from SRC to DEST using a loop that moves MAX_MOVE_BYTES
1172 per iteration. LENGTH must be at least MAX_MOVE_BYTES. Assume that the
1173 memory regions do not overlap. */
1176 microblaze_block_move_loop (rtx dest
, rtx src
, HOST_WIDE_INT length
)
1178 rtx_code_label
*label
;
1179 rtx src_reg
, dest_reg
, final_src
;
1180 HOST_WIDE_INT leftover
;
1182 leftover
= length
% MAX_MOVE_BYTES
;
1185 /* Create registers and memory references for use within the loop. */
1186 microblaze_adjust_block_mem (src
, MAX_MOVE_BYTES
, &src_reg
, &src
);
1187 microblaze_adjust_block_mem (dest
, MAX_MOVE_BYTES
, &dest_reg
, &dest
);
1189 /* Calculate the value that SRC_REG should have after the last iteration
1191 final_src
= expand_simple_binop (Pmode
, PLUS
, src_reg
, GEN_INT (length
),
1194 /* Emit the start of the loop. */
1195 label
= gen_label_rtx ();
1198 /* Emit the loop body. */
1199 microblaze_block_move_straight (dest
, src
, MAX_MOVE_BYTES
);
1201 /* Move on to the next block. */
1202 emit_move_insn (src_reg
, plus_constant (Pmode
, src_reg
, MAX_MOVE_BYTES
));
1203 emit_move_insn (dest_reg
, plus_constant (Pmode
, dest_reg
, MAX_MOVE_BYTES
));
1205 /* Emit the test & branch. */
1206 emit_insn (gen_cbranchsi4 (gen_rtx_NE (SImode
, src_reg
, final_src
),
1207 src_reg
, final_src
, label
));
1209 /* Mop up any left-over bytes. */
1211 microblaze_block_move_straight (dest
, src
, leftover
);
1214 /* Expand a movmemsi instruction. */
1217 microblaze_expand_block_move (rtx dest
, rtx src
, rtx length
, rtx align_rtx
)
1220 if (GET_CODE (length
) == CONST_INT
)
1222 HOST_WIDE_INT bytes
= INTVAL (length
);
1223 int align
= INTVAL (align_rtx
);
1225 if (align
> UNITS_PER_WORD
)
1227 align
= UNITS_PER_WORD
; /* We can't do any better. */
1229 else if (align
< UNITS_PER_WORD
)
1231 if (INTVAL (length
) <= MAX_MOVE_BYTES
)
1233 move_by_pieces (dest
, src
, bytes
, align
, 0);
1240 if (INTVAL (length
) <= 2 * MAX_MOVE_BYTES
)
1242 microblaze_block_move_straight (dest
, src
, INTVAL (length
));
1247 microblaze_block_move_loop (dest
, src
, INTVAL (length
));
1255 microblaze_rtx_costs (rtx x
, int code
, int outer_code ATTRIBUTE_UNUSED
,
1256 int opno ATTRIBUTE_UNUSED
, int *total
,
1257 bool speed ATTRIBUTE_UNUSED
)
1259 machine_mode mode
= GET_MODE (x
);
1265 int num_words
= (GET_MODE_SIZE (mode
) > UNITS_PER_WORD
) ? 2 : 1;
1266 if (simple_memory_operand (x
, mode
))
1267 *total
= COSTS_N_INSNS (2 * num_words
);
1269 *total
= COSTS_N_INSNS (2 * (2 * num_words
));
1277 *total
= COSTS_N_INSNS (2);
1280 *total
= COSTS_N_INSNS (1);
1289 *total
= COSTS_N_INSNS (2);
1292 *total
= COSTS_N_INSNS (1);
1300 if (TARGET_BARREL_SHIFT
)
1302 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v5.00.a")
1304 *total
= COSTS_N_INSNS (1);
1306 *total
= COSTS_N_INSNS (2);
1308 else if (!TARGET_SOFT_MUL
)
1309 *total
= COSTS_N_INSNS (1);
1310 else if (GET_CODE (XEXP (x
, 1)) == CONST_INT
)
1312 /* Add 1 to make shift slightly more expensive than add. */
1313 *total
= COSTS_N_INSNS (INTVAL (XEXP (x
, 1))) + 1;
1314 /* Reduce shift costs for special circumstances. */
1315 if (optimize_size
&& INTVAL (XEXP (x
, 1)) > 5)
1317 if (!optimize_size
&& INTVAL (XEXP (x
, 1)) > 17)
1321 /* Double the worst cost of shifts when there is no barrel shifter and
1322 the shift amount is in a reg. */
1323 *total
= COSTS_N_INSNS (32 * 4);
1329 if (mode
== SFmode
|| mode
== DFmode
)
1331 if (TARGET_HARD_FLOAT
)
1332 *total
= COSTS_N_INSNS (6);
1335 else if (mode
== DImode
)
1337 *total
= COSTS_N_INSNS (4);
1342 *total
= COSTS_N_INSNS (1);
1351 *total
= COSTS_N_INSNS (4);
1359 if (TARGET_HARD_FLOAT
)
1360 *total
= COSTS_N_INSNS (6);
1362 else if (!TARGET_SOFT_MUL
)
1364 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v5.00.a")
1366 *total
= COSTS_N_INSNS (1);
1368 *total
= COSTS_N_INSNS (3);
1371 *total
= COSTS_N_INSNS (10);
1379 if (TARGET_HARD_FLOAT
)
1380 *total
= COSTS_N_INSNS (23);
1386 *total
= COSTS_N_INSNS (1);
1391 *total
= COSTS_N_INSNS (1);
1399 /* Return the number of instructions needed to load or store a value
1400 of mode MODE at X. Return 0 if X isn't valid for MODE. */
1403 microblaze_address_insns (rtx x
, machine_mode mode
)
1405 struct microblaze_address_info addr
;
1407 if (microblaze_classify_address (&addr
, x
, mode
, false))
1412 if (SMALL_INT (addr
.offset
))
1416 case ADDRESS_CONST_INT
:
1421 case ADDRESS_REG_INDEX
:
1423 case ADDRESS_SYMBOLIC
:
1424 case ADDRESS_GOTOFF
:
1427 switch (addr
.tls_type
)
1445 /* Provide the costs of an addressing mode that contains ADDR.
1446 If ADDR is not a valid address, its cost is irrelevant. */
1448 microblaze_address_cost (rtx addr
, machine_mode mode ATTRIBUTE_UNUSED
,
1449 addr_space_t as ATTRIBUTE_UNUSED
,
1450 bool speed ATTRIBUTE_UNUSED
)
1452 return COSTS_N_INSNS (microblaze_address_insns (addr
, GET_MODE (addr
)));
1455 /* Return nonzero if X is an address which needs a temporary register when
1456 reloaded while generating PIC code. */
1459 pic_address_needs_scratch (rtx x
)
1461 if (GET_CODE (x
) == CONST
&& GET_CODE (XEXP (x
,0)) == PLUS
)
1465 p0
= XEXP (XEXP (x
, 0), 0);
1466 p1
= XEXP (XEXP (x
, 0), 1);
1468 if ((GET_CODE (p0
) == SYMBOL_REF
|| GET_CODE (p0
) == LABEL_REF
)
1469 && (GET_CODE (p1
) == CONST_INT
)
1470 && (flag_pic
== 2 || microblaze_tls_symbol_p (p0
) || !SMALL_INT (p1
)))
1476 /* Argument support functions. */
1477 /* Initialize CUMULATIVE_ARGS for a function. */
1480 init_cumulative_args (CUMULATIVE_ARGS
* cum
, tree fntype
,
1481 rtx libname ATTRIBUTE_UNUSED
)
1483 static CUMULATIVE_ARGS zero_cum
;
1484 tree param
, next_param
;
1488 /* Determine if this function has variable arguments. This is
1489 indicated by the last argument being 'void_type_mode' if there
1490 are no variable arguments. The standard MicroBlaze calling sequence
1491 passes all arguments in the general purpose registers in this case. */
1493 for (param
= fntype
? TYPE_ARG_TYPES (fntype
) : 0;
1494 param
!= 0; param
= next_param
)
1496 next_param
= TREE_CHAIN (param
);
1497 if (next_param
== 0 && TREE_VALUE (param
) != void_type_node
)
1498 cum
->gp_reg_found
= 1;
1502 /* Advance the argument to the next argument position. */
1505 microblaze_function_arg_advance (cumulative_args_t cum_v
,
1507 const_tree type
, bool named ATTRIBUTE_UNUSED
)
1509 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
1518 gcc_assert (GET_MODE_CLASS (mode
) == MODE_COMPLEX_INT
1519 || GET_MODE_CLASS (mode
) == MODE_COMPLEX_FLOAT
);
1521 cum
->gp_reg_found
= 1;
1522 cum
->arg_words
+= ((GET_MODE_SIZE (mode
) + UNITS_PER_WORD
- 1)
1527 cum
->gp_reg_found
= 1;
1528 cum
->arg_words
+= ((int_size_in_bytes (type
) + UNITS_PER_WORD
- 1)
1534 if (!cum
->gp_reg_found
&& cum
->arg_number
<= 2)
1535 cum
->fp_code
+= 1 << ((cum
->arg_number
- 1) * 2);
1539 cum
->arg_words
+= 2;
1540 if (!cum
->gp_reg_found
&& cum
->arg_number
<= 2)
1541 cum
->fp_code
+= 2 << ((cum
->arg_number
- 1) * 2);
1545 cum
->gp_reg_found
= 1;
1546 cum
->arg_words
+= 2;
1553 cum
->gp_reg_found
= 1;
1559 /* Return an RTL expression containing the register for the given mode,
1560 or 0 if the argument is to be passed on the stack. */
1563 microblaze_function_arg (cumulative_args_t cum_v
, machine_mode mode
,
1564 const_tree type ATTRIBUTE_UNUSED
,
1565 bool named ATTRIBUTE_UNUSED
)
1567 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
1571 int *arg_words
= &cum
->arg_words
;
1573 cum
->last_arg_fp
= 0;
1584 regbase
= GP_ARG_FIRST
;
1587 gcc_assert (GET_MODE_CLASS (mode
) == MODE_COMPLEX_INT
1588 || GET_MODE_CLASS (mode
) == MODE_COMPLEX_FLOAT
);
1589 /* Drops through. */
1591 regbase
= GP_ARG_FIRST
;
1595 if (*arg_words
>= MAX_ARGS_IN_REGISTERS
)
1599 gcc_assert (regbase
!= -1);
1601 ret
= gen_rtx_REG (mode
, regbase
+ *arg_words
);
1604 if (mode
== VOIDmode
)
1606 if (cum
->num_adjusts
> 0)
1607 ret
= gen_rtx_PARALLEL ((machine_mode
) cum
->fp_code
,
1608 gen_rtvec_v (cum
->num_adjusts
, cum
->adjust
));
1614 /* Return number of bytes of argument to put in registers. */
1616 function_arg_partial_bytes (cumulative_args_t cum_v
, machine_mode mode
,
1617 tree type
, bool named ATTRIBUTE_UNUSED
)
1619 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
1621 if ((mode
== BLKmode
1622 || GET_MODE_CLASS (mode
) != MODE_COMPLEX_INT
1623 || GET_MODE_CLASS (mode
) != MODE_COMPLEX_FLOAT
)
1624 && cum
->arg_words
< MAX_ARGS_IN_REGISTERS
)
1627 if (mode
== BLKmode
)
1628 words
= ((int_size_in_bytes (type
) + UNITS_PER_WORD
- 1)
1631 words
= (GET_MODE_SIZE (mode
) + UNITS_PER_WORD
- 1) / UNITS_PER_WORD
;
1633 if (words
+ cum
->arg_words
<= MAX_ARGS_IN_REGISTERS
)
1634 return 0; /* structure fits in registers */
1636 return (MAX_ARGS_IN_REGISTERS
- cum
->arg_words
) * UNITS_PER_WORD
;
1639 else if (mode
== DImode
&& cum
->arg_words
== MAX_ARGS_IN_REGISTERS
- 1)
1640 return UNITS_PER_WORD
;
1645 /* Convert a version number of the form "vX.YY.Z" to an integer encoding
1646 for easier range comparison. */
1648 microblaze_version_to_int (const char *version
)
1651 const char *tmpl
= "vXX.YY.Z";
1660 { /* Looking for major */
1667 if (!(*p
>= '0' && *p
<= '9'))
1669 iver
+= (int) (*p
- '0');
1674 { /* Looking for minor */
1675 if (!(*p
>= '0' && *p
<= '9'))
1677 iver
+= (int) (*p
- '0');
1681 { /* Looking for compat */
1682 if (!(*p
>= 'a' && *p
<= 'z'))
1685 iver
+= (int) (*p
- 'a');
1705 microblaze_option_override (void)
1707 register int i
, start
;
1709 register machine_mode mode
;
1712 microblaze_section_threshold
= (global_options_set
.x_g_switch_value
1714 : MICROBLAZE_DEFAULT_GVALUE
);
1718 /* Make sure it's 2, we only support one kind of PIC. */
1720 if (!TARGET_SUPPORTS_PIC
)
1722 error ("-fPIC/-fpic not supported for this target");
1723 /* Clear it to avoid further errors. */
1728 /* Check the MicroBlaze CPU version for any special action to be done. */
1729 if (microblaze_select_cpu
== NULL
)
1730 microblaze_select_cpu
= MICROBLAZE_DEFAULT_CPU
;
1731 ver
= microblaze_version_to_int (microblaze_select_cpu
);
1734 error ("%qs is an invalid argument to -mcpu=", microblaze_select_cpu
);
1737 ver
= MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v3.00.a");
1740 /* No hardware exceptions in earlier versions. So no worries. */
1742 microblaze_select_flags
&= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY
);
1744 microblaze_no_unsafe_delay
= 0;
1745 microblaze_pipe
= MICROBLAZE_PIPE_3
;
1748 || (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v4.00.b")
1752 microblaze_select_flags
|= (MICROBLAZE_MASK_NO_UNSAFE_DELAY
);
1754 microblaze_no_unsafe_delay
= 1;
1755 microblaze_pipe
= MICROBLAZE_PIPE_3
;
1759 /* We agree to use 5 pipe-stage model even on area optimized 3
1760 pipe-stage variants. */
1762 microblaze_select_flags
&= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY
);
1764 microblaze_no_unsafe_delay
= 0;
1765 microblaze_pipe
= MICROBLAZE_PIPE_5
;
1766 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v5.00.a") == 0
1767 || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
,
1769 || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
,
1772 /* Pattern compares are to be turned on by default only when
1773 compiling for MB v5.00.'z'. */
1774 target_flags
|= MASK_PATTERN_COMPARE
;
1778 ver
= MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v6.00.a");
1781 if (TARGET_MULTIPLY_HIGH
)
1783 "-mxl-multiply-high can be used only with -mcpu=v6.00.a or greater");
1786 ver
= MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v8.10.a");
1787 microblaze_has_clz
= 1;
1790 /* MicroBlaze prior to 8.10.a didn't have clz. */
1791 microblaze_has_clz
= 0;
1794 /* TARGET_REORDER defaults to 2 if -mxl-reorder not specified. */
1795 ver
= MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v8.30.a");
1798 if (TARGET_REORDER
== 1)
1799 warning (0, "-mxl-reorder can be used only with -mcpu=v8.30.a or greater");
1802 else if ((ver
== 0) && !TARGET_PATTERN_COMPARE
)
1804 if (TARGET_REORDER
== 1)
1805 warning (0, "-mxl-reorder requires -mxl-pattern-compare for -mcpu=v8.30.a");
1809 if (TARGET_MULTIPLY_HIGH
&& TARGET_SOFT_MUL
)
1810 error ("-mxl-multiply-high requires -mno-xl-soft-mul");
1812 /* Always use DFA scheduler. */
1813 microblaze_sched_use_dfa
= 1;
1816 microblaze_abicalls
= MICROBLAZE_ABICALLS_NO
;
1819 /* Initialize the high, low values for legit floating point constants. */
1820 real_maxval (&dfhigh
, 0, DFmode
);
1821 real_maxval (&dflow
, 1, DFmode
);
1822 real_maxval (&sfhigh
, 0, SFmode
);
1823 real_maxval (&sflow
, 1, SFmode
);
1825 microblaze_print_operand_punct
['?'] = 1;
1826 microblaze_print_operand_punct
['#'] = 1;
1827 microblaze_print_operand_punct
['&'] = 1;
1828 microblaze_print_operand_punct
['!'] = 1;
1829 microblaze_print_operand_punct
['*'] = 1;
1830 microblaze_print_operand_punct
['@'] = 1;
1831 microblaze_print_operand_punct
['.'] = 1;
1832 microblaze_print_operand_punct
['('] = 1;
1833 microblaze_print_operand_punct
[')'] = 1;
1834 microblaze_print_operand_punct
['['] = 1;
1835 microblaze_print_operand_punct
[']'] = 1;
1836 microblaze_print_operand_punct
['<'] = 1;
1837 microblaze_print_operand_punct
['>'] = 1;
1838 microblaze_print_operand_punct
['{'] = 1;
1839 microblaze_print_operand_punct
['}'] = 1;
1840 microblaze_print_operand_punct
['^'] = 1;
1841 microblaze_print_operand_punct
['$'] = 1;
1842 microblaze_print_operand_punct
['+'] = 1;
1844 /* Set up array to map GCC register number to debug register number.
1845 Ignore the special purpose register numbers. */
1847 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
1848 microblaze_dbx_regno
[i
] = -1;
1850 start
= GP_DBX_FIRST
- GP_REG_FIRST
;
1851 for (i
= GP_REG_FIRST
; i
<= GP_REG_LAST
; i
++)
1852 microblaze_dbx_regno
[i
] = i
+ start
;
1854 /* Set up array giving whether a given register can hold a given mode. */
1856 for (mode
= VOIDmode
;
1857 mode
!= MAX_MACHINE_MODE
; mode
= (machine_mode
) ((int) mode
+ 1))
1859 register int size
= GET_MODE_SIZE (mode
);
1861 for (regno
= 0; regno
< FIRST_PSEUDO_REGISTER
; regno
++)
1867 ok
= (ST_REG_P (regno
) || GP_REG_P (regno
));
1869 else if (GP_REG_P (regno
))
1870 ok
= ((regno
& 1) == 0 || size
<= UNITS_PER_WORD
);
1874 microblaze_hard_regno_mode_ok
[(int) mode
][regno
] = ok
;
1879 /* Return true if FUNC is an interrupt function as specified
1880 by the "interrupt_handler" attribute. */
1883 microblaze_interrupt_function_p (tree func
)
1887 if (TREE_CODE (func
) != FUNCTION_DECL
)
1890 a
= lookup_attribute ("interrupt_handler", DECL_ATTRIBUTES (func
));
1891 return a
!= NULL_TREE
;
1895 microblaze_fast_interrupt_function_p (tree func
)
1899 if (TREE_CODE (func
) != FUNCTION_DECL
)
1902 a
= lookup_attribute ("fast_interrupt", DECL_ATTRIBUTES (func
));
1903 return a
!= NULL_TREE
;
1906 microblaze_break_function_p (tree func
)
1911 if (TREE_CODE (func
) != FUNCTION_DECL
)
1914 a
= lookup_attribute ("break_handler", DECL_ATTRIBUTES (func
));
1915 return a
!= NULL_TREE
;
1917 /* Return true if FUNC is an interrupt function which uses
1918 normal return, indicated by the "save_volatiles" attribute. */
1921 microblaze_save_volatiles (tree func
)
1925 if (TREE_CODE (func
) != FUNCTION_DECL
)
1928 a
= lookup_attribute ("save_volatiles", DECL_ATTRIBUTES (func
));
1929 return a
!= NULL_TREE
;
1932 /* Return whether function is tagged with 'interrupt_handler'
1933 or 'fast_interrupt' attribute. Return true if function
1934 should use return from interrupt rather than normal
1937 microblaze_is_interrupt_variant (void)
1939 return (interrupt_handler
|| fast_interrupt
);
1942 microblaze_is_break_handler (void)
1944 return break_handler
;
1947 /* Determine of register must be saved/restored in call. */
1949 microblaze_must_save_register (int regno
)
1951 if (pic_offset_table_rtx
&&
1952 (regno
== MB_ABI_PIC_ADDR_REGNUM
) && df_regs_ever_live_p (regno
))
1955 if (df_regs_ever_live_p (regno
) && !call_used_regs
[regno
])
1958 if (frame_pointer_needed
&& (regno
== HARD_FRAME_POINTER_REGNUM
))
1963 if (regno
== MB_ABI_SUB_RETURN_ADDR_REGNUM
)
1965 if ((microblaze_is_interrupt_variant () || save_volatiles
) &&
1966 (regno
>= 3 && regno
<= 12))
1970 if (microblaze_is_interrupt_variant ())
1972 if (df_regs_ever_live_p (regno
)
1973 || regno
== MB_ABI_MSR_SAVE_REG
1974 || (interrupt_handler
1975 && (regno
== MB_ABI_ASM_TEMP_REGNUM
1976 || regno
== MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM
)))
1982 if (df_regs_ever_live_p (regno
)
1983 || regno
== MB_ABI_ASM_TEMP_REGNUM
1984 || regno
== MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM
)
1991 /* Return the bytes needed to compute the frame pointer from the current
1994 MicroBlaze stack frames look like:
1998 Before call After call
1999 +-----------------------+ +-----------------------+
2001 mem. | local variables, | | local variables, |
2002 | callee saved and | | callee saved and |
2004 +-----------------------+ +-----------------------+
2005 | arguments for called | | arguments for called |
2006 | subroutines | | subroutines |
2007 | (optional) | | (optional) |
2008 +-----------------------+ +-----------------------+
2009 | Link register | | Link register |
2011 +-----------------------+ +-----------------------+
2013 | local variables, |
2014 | callee saved and |
2016 +-----------------------+
2017 | MSR (optional if, |
2018 | interrupt handler) |
2019 +-----------------------+
2021 | alloca allocations |
2023 +-----------------------+
2025 | arguments for called |
2029 +-----------------------+
2032 memory +-----------------------+
2036 static HOST_WIDE_INT
2037 compute_frame_size (HOST_WIDE_INT size
)
2040 HOST_WIDE_INT total_size
; /* # bytes that the entire frame takes up. */
2041 HOST_WIDE_INT var_size
; /* # bytes that local variables take up. */
2042 HOST_WIDE_INT args_size
; /* # bytes that outgoing arguments take up. */
2043 int link_debug_size
; /* # bytes for link register. */
2044 HOST_WIDE_INT gp_reg_size
; /* # bytes needed to store calle-saved gp regs. */
2045 long mask
; /* mask of saved gp registers. */
2048 microblaze_interrupt_function_p (current_function_decl
);
2050 microblaze_break_function_p (current_function_decl
);
2053 microblaze_fast_interrupt_function_p (current_function_decl
);
2054 save_volatiles
= microblaze_save_volatiles (current_function_decl
);
2056 interrupt_handler
= break_handler
;
2061 args_size
= crtl
->outgoing_args_size
;
2063 if ((args_size
== 0) && cfun
->calls_alloca
)
2064 args_size
= NUM_OF_ARGS
* UNITS_PER_WORD
;
2066 total_size
= var_size
+ args_size
;
2069 /* force setting GOT. */
2070 df_set_regs_ever_live (MB_ABI_PIC_ADDR_REGNUM
, true);
2072 /* Calculate space needed for gp registers. */
2073 for (regno
= GP_REG_FIRST
; regno
<= GP_REG_LAST
; regno
++)
2075 if (microblaze_must_save_register (regno
))
2078 if (regno
!= MB_ABI_SUB_RETURN_ADDR_REGNUM
)
2079 /* Don't account for link register. It is accounted specially below. */
2080 gp_reg_size
+= GET_MODE_SIZE (SImode
);
2082 mask
|= (1L << (regno
- GP_REG_FIRST
));
2086 total_size
+= gp_reg_size
;
2088 /* Add 4 bytes for MSR. */
2089 if (microblaze_is_interrupt_variant ())
2092 /* No space to be allocated for link register in leaf functions with no other
2093 stack requirements. */
2094 if (total_size
== 0 && crtl
->is_leaf
)
2095 link_debug_size
= 0;
2097 link_debug_size
= UNITS_PER_WORD
;
2099 total_size
+= link_debug_size
;
2101 /* Save other computed information. */
2102 current_frame_info
.total_size
= total_size
;
2103 current_frame_info
.var_size
= var_size
;
2104 current_frame_info
.args_size
= args_size
;
2105 current_frame_info
.gp_reg_size
= gp_reg_size
;
2106 current_frame_info
.mask
= mask
;
2107 current_frame_info
.initialized
= reload_completed
;
2108 current_frame_info
.num_gp
= gp_reg_size
/ UNITS_PER_WORD
;
2109 current_frame_info
.link_debug_size
= link_debug_size
;
2112 /* Offset from which to callee-save GP regs. */
2113 current_frame_info
.gp_offset
= (total_size
- gp_reg_size
);
2115 current_frame_info
.gp_offset
= 0;
2117 /* Ok, we're done. */
2121 /* Make sure that we're not trying to eliminate to the wrong hard frame
2125 microblaze_can_eliminate (const int from
, const int to
)
2127 return ((from
== RETURN_ADDRESS_POINTER_REGNUM
&& !leaf_function_p())
2128 || (to
== MB_ABI_SUB_RETURN_ADDR_REGNUM
&& leaf_function_p())
2129 || (from
!= RETURN_ADDRESS_POINTER_REGNUM
2130 && (to
== HARD_FRAME_POINTER_REGNUM
2131 || (to
== STACK_POINTER_REGNUM
&& !frame_pointer_needed
))));
2134 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
2135 pointer or argument pointer or the return address pointer. TO is either
2136 the stack pointer or hard frame pointer. */
2139 microblaze_initial_elimination_offset (int from
, int to
)
2141 HOST_WIDE_INT offset
;
2145 case FRAME_POINTER_REGNUM
:
2148 case ARG_POINTER_REGNUM
:
2149 if (to
== STACK_POINTER_REGNUM
|| to
== HARD_FRAME_POINTER_REGNUM
)
2150 offset
= compute_frame_size (get_frame_size ());
2154 case RETURN_ADDRESS_POINTER_REGNUM
:
2158 offset
= current_frame_info
.gp_offset
+
2159 ((UNITS_PER_WORD
- (POINTER_SIZE
/ BITS_PER_UNIT
)));
2167 /* Print operands using format code.
2169 The MicroBlaze specific codes are:
2171 'X' X is CONST_INT, prints 32 bits in hexadecimal format = "0x%08x",
2172 'x' X is CONST_INT, prints 16 bits in hexadecimal format = "0x%04x",
2173 'F' op is CONST_DOUBLE, print 32 bits in hex,
2174 'd' output integer constant in decimal,
2175 'z' if the operand is 0, use $0 instead of normal operand.
2176 'D' print second register of double-word register operand.
2177 'L' print low-order register of double-word register operand.
2178 'M' print high-order register of double-word register operand.
2179 'C' print part of opcode for a branch condition.
2180 'N' print part of opcode for a branch condition, inverted.
2181 'S' X is CODE_LABEL, print with prefix of "LS" (for embedded switch).
2182 'B' print 'z' for EQ, 'n' for NE
2183 'b' print 'n' for EQ, 'z' for NE
2184 'T' print 'f' for EQ, 't' for NE
2185 't' print 't' for EQ, 'f' for NE
2186 'm' Print 1<<operand.
2187 'i' Print 'i' if MEM operand has immediate value
2188 'y' Print 'y' if MEM operand is single register
2189 'o' Print operand address+4
2190 '?' Print 'd' if we use a branch with delay slot instead of normal branch.
2191 'h' Print high word of const_double (int or float) value as hex
2192 'j' Print low word of const_double (int or float) value as hex
2193 's' Print -1 if operand is negative, 0 if positive (sign extend)
2194 '@' Print the name of the temporary register (rMB_ABI_ASM_TEMP_REGNUM).
2195 '#' Print nop if the delay slot of a branch is not filled.
2199 print_operand (FILE * file
, rtx op
, int letter
)
2201 register enum rtx_code code
;
2203 if (PRINT_OPERAND_PUNCT_VALID_P (letter
))
2208 /* Conditionally add a 'd' to indicate filled delay slot. */
2209 if (final_sequence
!= NULL
)
2214 /* Conditionally add a nop in unfilled delay slot. */
2215 if (final_sequence
== NULL
)
2216 fputs ("nop\t\t# Unfilled delay slot\n", file
);
2220 fputs (reg_names
[GP_REG_FIRST
+ MB_ABI_ASM_TEMP_REGNUM
], file
);
2224 output_operand_lossage ("unknown punctuation '%c'", letter
);
2233 output_operand_lossage ("null pointer");
2237 code
= GET_CODE (op
);
2239 if (code
== SIGN_EXTEND
)
2240 op
= XEXP (op
, 0), code
= GET_CODE (op
);
2268 fatal_insn ("PRINT_OPERAND, invalid insn for %%C", op
);
2271 else if (letter
== 'N')
2297 fatal_insn ("PRINT_OPERAND, invalid insn for %%N", op
);
2300 else if (letter
== 'S')
2304 ASM_GENERATE_INTERNAL_LABEL (buffer
, "LS", CODE_LABEL_NUMBER (op
));
2305 assemble_name (file
, buffer
);
2308 /* Print 'i' for memory operands which have immediate values. */
2309 else if (letter
== 'i')
2313 struct microblaze_address_info info
;
2315 if (!microblaze_classify_address
2316 (&info
, XEXP (op
, 0), GET_MODE (op
), 1))
2317 fatal_insn ("insn contains an invalid address !", op
);
2322 case ADDRESS_CONST_INT
:
2323 case ADDRESS_SYMBOLIC
:
2324 case ADDRESS_GOTOFF
:
2328 case ADDRESS_REG_INDEX
:
2330 case ADDRESS_INVALID
:
2332 fatal_insn ("invalid address", op
);
2337 else if (code
== REG
|| code
== SUBREG
)
2339 register int regnum
;
2342 regnum
= REGNO (op
);
2344 regnum
= true_regnum (op
);
2346 if ((letter
== 'M' && !WORDS_BIG_ENDIAN
)
2347 || (letter
== 'L' && WORDS_BIG_ENDIAN
) || letter
== 'D')
2350 fprintf (file
, "%s", reg_names
[regnum
]);
2353 else if (code
== MEM
)
2356 rtx op4
= adjust_address (op
, GET_MODE (op
), 4);
2357 output_address (XEXP (op4
, 0));
2359 else if (letter
== 'y')
2361 rtx mem_reg
= XEXP (op
, 0);
2362 if (GET_CODE (mem_reg
) == REG
)
2364 register int regnum
= REGNO (mem_reg
);
2365 fprintf (file
, "%s", reg_names
[regnum
]);
2369 output_address (XEXP (op
, 0));
2371 else if (letter
== 'h' || letter
== 'j')
2374 if (code
== CONST_DOUBLE
)
2376 if (GET_MODE (op
) == DFmode
)
2378 REAL_VALUE_TYPE value
;
2379 REAL_VALUE_FROM_CONST_DOUBLE (value
, op
);
2380 REAL_VALUE_TO_TARGET_DOUBLE (value
, val
);
2384 val
[0] = CONST_DOUBLE_HIGH (op
);
2385 val
[1] = CONST_DOUBLE_LOW (op
);
2388 else if (code
== CONST_INT
)
2390 val
[0] = (INTVAL (op
) & 0xffffffff00000000LL
) >> 32;
2391 val
[1] = INTVAL (op
) & 0x00000000ffffffffLL
;
2392 if (val
[0] == 0 && val
[1] < 0)
2396 fprintf (file
, "0x%8.8lx", (letter
== 'h') ? val
[0] : val
[1]);
2398 else if (code
== CONST_DOUBLE
)
2402 unsigned long value_long
;
2403 REAL_VALUE_TYPE value
;
2404 REAL_VALUE_FROM_CONST_DOUBLE (value
, op
);
2405 REAL_VALUE_TO_TARGET_SINGLE (value
, value_long
);
2406 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, value_long
);
2411 real_to_decimal (s
, CONST_DOUBLE_REAL_VALUE (op
), sizeof (s
), 0, 1);
2416 else if (code
== UNSPEC
)
2418 print_operand_address (file
, op
);
2421 else if (letter
== 'x' && GET_CODE (op
) == CONST_INT
)
2422 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, 0xffff & INTVAL (op
));
2424 else if (letter
== 'X' && GET_CODE (op
) == CONST_INT
)
2425 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, INTVAL (op
));
2427 else if (letter
== 'd' && GET_CODE (op
) == CONST_INT
)
2428 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, (INTVAL (op
)));
2430 else if (letter
== 'z' && GET_CODE (op
) == CONST_INT
&& INTVAL (op
) == 0)
2431 fputs (reg_names
[GP_REG_FIRST
], file
);
2433 else if (letter
== 's' && GET_CODE (op
) == CONST_INT
)
2434 if (INTVAL (op
) < 0)
2439 else if (letter
== 'd' || letter
== 'x' || letter
== 'X' || letter
== 's')
2440 output_operand_lossage ("letter %c was found & insn was not CONST_INT", letter
);
2442 else if (letter
== 'B')
2443 fputs (code
== EQ
? "z" : "n", file
);
2444 else if (letter
== 'b')
2445 fputs (code
== EQ
? "n" : "z", file
);
2446 else if (letter
== 'T')
2447 fputs (code
== EQ
? "f" : "t", file
);
2448 else if (letter
== 't')
2449 fputs (code
== EQ
? "t" : "f", file
);
2451 else if (code
== CONST
2452 && ((GET_CODE (XEXP (op
, 0)) == REG
)
2453 || (GET_CODE (XEXP (op
, 0)) == UNSPEC
)))
2455 print_operand (file
, XEXP (op
, 0), letter
);
2457 else if (code
== CONST
2458 && (GET_CODE (XEXP (op
, 0)) == PLUS
)
2459 && (GET_CODE (XEXP (XEXP (op
, 0), 0)) == REG
)
2460 && (GET_CODE (XEXP (XEXP (op
, 0), 1)) == CONST
))
2462 print_operand_address (file
, XEXP (op
, 0));
2464 else if (letter
== 'm')
2465 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, (1L << INTVAL (op
)));
2467 output_addr_const (file
, op
);
2470 /* A C compound statement to output to stdio stream STREAM the
2471 assembler syntax for an instruction operand that is a memory
2472 reference whose address is ADDR. ADDR is an RTL expression.
2474 Possible address classifications and output formats are,
2476 ADDRESS_REG "%0, r0"
2478 ADDRESS_REG with non-zero "%0, <addr_const>"
2481 ADDRESS_REG_INDEX "rA, RB"
2482 (if rA is r0, rA and rB are swapped)
2484 ADDRESS_CONST_INT "r0, <addr_const>"
2486 ADDRESS_SYMBOLIC "rBase, <addr_const>"
2487 (rBase is a base register suitable for the
2492 print_operand_address (FILE * file
, rtx addr
)
2494 struct microblaze_address_info info
;
2495 enum microblaze_address_type type
;
2496 if (!microblaze_classify_address (&info
, addr
, GET_MODE (addr
), 1))
2497 fatal_insn ("insn contains an invalid address !", addr
);
2503 fprintf (file
, "%s,", reg_names
[REGNO (info
.regA
)]);
2504 output_addr_const (file
, info
.offset
);
2506 case ADDRESS_REG_INDEX
:
2507 if (REGNO (info
.regA
) == 0)
2508 /* Make rB == r0 instead of rA == r0. This helps reduce read port
2510 fprintf (file
, "%s,%s", reg_names
[REGNO (info
.regB
)],
2511 reg_names
[REGNO (info
.regA
)]);
2512 else if (REGNO (info
.regB
) != 0)
2513 /* This is a silly swap to help Dhrystone. */
2514 fprintf (file
, "%s,%s", reg_names
[REGNO (info
.regB
)],
2515 reg_names
[REGNO (info
.regA
)]);
2517 case ADDRESS_CONST_INT
:
2518 fprintf (file
, "%s,", reg_names
[REGNO (info
.regA
)]);
2519 output_addr_const (file
, info
.offset
);
2521 case ADDRESS_SYMBOLIC
:
2522 case ADDRESS_GOTOFF
:
2526 fprintf (file
, "%s,", reg_names
[REGNO (info
.regA
)]);
2527 output_addr_const (file
, info
.symbol
);
2528 if (type
== ADDRESS_GOTOFF
)
2530 fputs ("@GOT", file
);
2532 else if (type
== ADDRESS_PLT
)
2534 fputs ("@PLT", file
);
2536 else if (type
== ADDRESS_TLS
)
2538 switch (info
.tls_type
)
2541 fputs ("@TLSGD", file
);
2544 fputs ("@TLSLDM", file
);
2547 fputs ("@TLSDTPREL", file
);
2555 case ADDRESS_INVALID
:
2556 fatal_insn ("invalid address", addr
);
2561 /* Emit either a label, .comm, or .lcomm directive, and mark that the symbol
2562 is used, so that we don't emit an .extern for it in
2563 microblaze_asm_file_end. */
2566 microblaze_declare_object (FILE * stream
, const char *name
,
2567 const char *section
, const char *fmt
, int size
)
2570 fputs (section
, stream
);
2571 assemble_name (stream
, name
);
2572 fprintf (stream
, fmt
, size
);
2575 /* Common code to emit the insns (or to write the instructions to a file)
2576 to save/restore registers.
2578 Other parts of the code assume that MICROBLAZE_TEMP1_REGNUM (aka large_reg)
2579 is not modified within save_restore_insns. */
2581 #define BITSET_P(VALUE,BIT) (((VALUE) & (1L << (BIT))) != 0)
2583 /* Save or restore instructions based on whether this is the prologue or
2584 epilogue. prologue is 1 for the prologue. */
2586 save_restore_insns (int prologue
)
2588 rtx base_reg_rtx
, reg_rtx
, mem_rtx
, /* msr_rtx, */ isr_reg_rtx
=
2590 rtx isr_msr_rtx
= 0, insn
;
2591 long mask
= current_frame_info
.mask
;
2592 HOST_WIDE_INT gp_offset
;
2595 if (frame_pointer_needed
2596 && !BITSET_P (mask
, HARD_FRAME_POINTER_REGNUM
- GP_REG_FIRST
))
2602 /* Save registers starting from high to low. The debuggers prefer at least
2603 the return register be stored at func+4, and also it allows us not to
2604 need a nop in the epilog if at least one register is reloaded in
2605 addition to return address. */
2607 /* Pick which pointer to use as a base register. For small frames, just
2608 use the stack pointer. Otherwise, use a temporary register. Save 2
2609 cycles if the save area is near the end of a large frame, by reusing
2610 the constant created in the prologue/epilogue to adjust the stack
2613 gp_offset
= current_frame_info
.gp_offset
;
2615 gcc_assert (gp_offset
> 0);
2617 base_reg_rtx
= stack_pointer_rtx
;
2619 /* For interrupt_handlers, need to save/restore the MSR. */
2620 if (microblaze_is_interrupt_variant ())
2622 isr_mem_rtx
= gen_rtx_MEM (SImode
,
2623 gen_rtx_PLUS (Pmode
, base_reg_rtx
,
2624 GEN_INT (current_frame_info
.
2628 /* Do not optimize in flow analysis. */
2629 MEM_VOLATILE_P (isr_mem_rtx
) = 1;
2630 isr_reg_rtx
= gen_rtx_REG (SImode
, MB_ABI_MSR_SAVE_REG
);
2631 isr_msr_rtx
= gen_rtx_REG (SImode
, ST_REG
);
2634 if (microblaze_is_interrupt_variant () && !prologue
)
2636 emit_move_insn (isr_reg_rtx
, isr_mem_rtx
);
2637 emit_move_insn (isr_msr_rtx
, isr_reg_rtx
);
2638 /* Do not optimize in flow analysis. */
2639 emit_insn (gen_rtx_USE (SImode
, isr_reg_rtx
));
2640 emit_insn (gen_rtx_USE (SImode
, isr_msr_rtx
));
2643 for (regno
= GP_REG_FIRST
; regno
<= GP_REG_LAST
; regno
++)
2645 if (BITSET_P (mask
, regno
- GP_REG_FIRST
))
2647 if (regno
== MB_ABI_SUB_RETURN_ADDR_REGNUM
)
2648 /* Don't handle here. Already handled as the first register. */
2651 reg_rtx
= gen_rtx_REG (SImode
, regno
);
2652 insn
= gen_rtx_PLUS (Pmode
, base_reg_rtx
, GEN_INT (gp_offset
));
2653 mem_rtx
= gen_rtx_MEM (SImode
, insn
);
2654 if (microblaze_is_interrupt_variant () || save_volatiles
)
2655 /* Do not optimize in flow analysis. */
2656 MEM_VOLATILE_P (mem_rtx
) = 1;
2660 insn
= emit_move_insn (mem_rtx
, reg_rtx
);
2661 RTX_FRAME_RELATED_P (insn
) = 1;
2665 insn
= emit_move_insn (reg_rtx
, mem_rtx
);
2668 gp_offset
+= GET_MODE_SIZE (SImode
);
2672 if (microblaze_is_interrupt_variant () && prologue
)
2674 emit_move_insn (isr_reg_rtx
, isr_msr_rtx
);
2675 emit_move_insn (isr_mem_rtx
, isr_reg_rtx
);
2677 /* Do not optimize in flow analysis. */
2678 emit_insn (gen_rtx_USE (SImode
, isr_reg_rtx
));
2679 emit_insn (gen_rtx_USE (SImode
, isr_msr_rtx
));
2682 /* Done saving and restoring */
2686 /* Set up the stack and frame (if desired) for the function. */
2688 microblaze_function_prologue (FILE * file
, HOST_WIDE_INT size ATTRIBUTE_UNUSED
)
2691 long fsiz
= current_frame_info
.total_size
;
2693 /* Get the function name the same way that toplev.c does before calling
2694 assemble_start_function. This is needed so that the name used here
2695 exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */
2696 fnname
= XSTR (XEXP (DECL_RTL (current_function_decl
), 0), 0);
2697 if (!flag_inhibit_size_directive
)
2699 fputs ("\t.ent\t", file
);
2700 if (interrupt_handler
&& strcmp (INTERRUPT_HANDLER_NAME
, fnname
))
2701 fputs ("_interrupt_handler", file
);
2702 else if (break_handler
&& strcmp (BREAK_HANDLER_NAME
, fnname
))
2703 fputs ("_break_handler", file
);
2704 else if (fast_interrupt
&& strcmp (FAST_INTERRUPT_NAME
, fnname
))
2705 fputs ("_fast_interrupt", file
);
2707 assemble_name (file
, fnname
);
2709 if (!microblaze_is_interrupt_variant ())
2710 ASM_OUTPUT_TYPE_DIRECTIVE (file
, fnname
, "function");
2713 assemble_name (file
, fnname
);
2714 fputs (":\n", file
);
2716 if (interrupt_handler
&& strcmp (INTERRUPT_HANDLER_NAME
, fnname
))
2717 fputs ("_interrupt_handler:\n", file
);
2718 if (break_handler
&& strcmp (BREAK_HANDLER_NAME
, fnname
))
2719 fputs ("_break_handler:\n", file
);
2720 if (!flag_inhibit_size_directive
)
2722 /* .frame FRAMEREG, FRAMESIZE, RETREG. */
2724 "\t.frame\t%s,%ld,%s\t\t# vars= %ld, regs= %d, args= %d\n",
2725 (reg_names
[(frame_pointer_needed
)
2726 ? HARD_FRAME_POINTER_REGNUM
:
2727 STACK_POINTER_REGNUM
]), fsiz
,
2728 reg_names
[MB_ABI_SUB_RETURN_ADDR_REGNUM
+ GP_REG_FIRST
],
2729 current_frame_info
.var_size
, current_frame_info
.num_gp
,
2730 crtl
->outgoing_args_size
);
2731 fprintf (file
, "\t.mask\t0x%08lx\n", current_frame_info
.mask
);
2735 /* Output extra assembler code at the end of a prologue. */
2737 microblaze_function_end_prologue (FILE * file
)
2739 if (TARGET_STACK_CHECK
)
2741 fprintf (file
, "\t# Stack Check Stub -- Start.\n\t");
2742 fprintf (file
, "ori\tr18,r0,_stack_end\n\t");
2743 fprintf (file
, "cmpu\tr18,r1,r18\n\t");
2744 fprintf (file
, "bgei\tr18,_stack_overflow_exit\n\t");
2745 fprintf (file
, "# Stack Check Stub -- End.\n");
2750 microblaze_elf_asm_cdtor (rtx symbol
, int priority
, bool is_ctor
)
2754 if (priority
!= DEFAULT_INIT_PRIORITY
)
2757 sprintf (buf
, "%s.%.5u",
2758 is_ctor
? ".ctors" : ".dtors",
2759 MAX_INIT_PRIORITY
- priority
);
2760 s
= get_section (buf
, SECTION_WRITE
, NULL_TREE
);
2767 switch_to_section (s
);
2768 assemble_align (POINTER_SIZE
);
2769 fputs ("\t.word\t", asm_out_file
);
2770 output_addr_const (asm_out_file
, symbol
);
2771 fputs ("\n", asm_out_file
);
2774 /* Add a function to the list of static constructors. */
2777 microblaze_elf_asm_constructor (rtx symbol
, int priority
)
2779 microblaze_elf_asm_cdtor (symbol
, priority
, /*is_ctor=*/true);
2782 /* Add a function to the list of static destructors. */
2785 microblaze_elf_asm_destructor (rtx symbol
, int priority
)
2787 microblaze_elf_asm_cdtor (symbol
, priority
, /*is_ctor=*/false);
2790 /* Expand the prologue into a bunch of separate insns. */
2793 microblaze_expand_prologue (void)
2797 const char *arg_name
= 0;
2798 tree fndecl
= current_function_decl
;
2799 tree fntype
= TREE_TYPE (fndecl
);
2800 tree fnargs
= DECL_ARGUMENTS (fndecl
);
2805 CUMULATIVE_ARGS args_so_far_v
;
2806 cumulative_args_t args_so_far
;
2807 rtx mem_rtx
, reg_rtx
;
2809 /* If struct value address is treated as the first argument, make it so. */
2810 if (aggregate_value_p (DECL_RESULT (fndecl
), fntype
)
2811 && !cfun
->returns_pcc_struct
)
2813 tree type
= build_pointer_type (fntype
);
2814 tree function_result_decl
= build_decl (BUILTINS_LOCATION
, PARM_DECL
,
2817 DECL_ARG_TYPE (function_result_decl
) = type
;
2818 TREE_CHAIN (function_result_decl
) = fnargs
;
2819 fnargs
= function_result_decl
;
2822 /* Determine the last argument, and get its name. */
2824 INIT_CUMULATIVE_ARGS (args_so_far_v
, fntype
, NULL_RTX
, 0, 0);
2825 args_so_far
= pack_cumulative_args (&args_so_far_v
);
2826 regno
= GP_ARG_FIRST
;
2828 for (cur_arg
= fnargs
; cur_arg
!= 0; cur_arg
= next_arg
)
2830 tree passed_type
= DECL_ARG_TYPE (cur_arg
);
2831 machine_mode passed_mode
= TYPE_MODE (passed_type
);
2834 if (TREE_ADDRESSABLE (passed_type
))
2836 passed_type
= build_pointer_type (passed_type
);
2837 passed_mode
= Pmode
;
2840 entry_parm
= targetm
.calls
.function_arg (args_so_far
, passed_mode
,
2847 /* passed in a register, so will get homed automatically. */
2848 if (GET_MODE (entry_parm
) == BLKmode
)
2849 words
= (int_size_in_bytes (passed_type
) + 3) / 4;
2851 words
= (GET_MODE_SIZE (GET_MODE (entry_parm
)) + 3) / 4;
2853 regno
= REGNO (entry_parm
) + words
- 1;
2857 regno
= GP_ARG_LAST
+ 1;
2861 targetm
.calls
.function_arg_advance (args_so_far
, passed_mode
,
2864 next_arg
= TREE_CHAIN (cur_arg
);
2867 if (DECL_NAME (cur_arg
))
2868 arg_name
= IDENTIFIER_POINTER (DECL_NAME (cur_arg
));
2874 /* Split parallel insn into a sequence of insns. */
2876 next_arg_reg
= targetm
.calls
.function_arg (args_so_far
, VOIDmode
,
2877 void_type_node
, true);
2878 if (next_arg_reg
!= 0 && GET_CODE (next_arg_reg
) == PARALLEL
)
2880 rtvec adjust
= XVEC (next_arg_reg
, 0);
2881 int num
= GET_NUM_ELEM (adjust
);
2883 for (i
= 0; i
< num
; i
++)
2885 rtx pattern
= RTVEC_ELT (adjust
, i
);
2886 emit_insn (pattern
);
2890 fsiz
= compute_frame_size (get_frame_size ());
2892 if (flag_stack_usage_info
)
2893 current_function_static_stack_size
= fsiz
;
2896 /* If this function is a varargs function, store any registers that
2897 would normally hold arguments ($5 - $10) on the stack. */
2898 if (((TYPE_ARG_TYPES (fntype
) != 0
2899 && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype
)))
2902 && ((arg_name
[0] == '_'
2903 && strcmp (arg_name
, "__builtin_va_alist") == 0)
2904 || (arg_name
[0] == 'v'
2905 && strcmp (arg_name
, "va_alist") == 0)))))
2907 int offset
= (regno
- GP_ARG_FIRST
+ 1) * UNITS_PER_WORD
;
2908 rtx ptr
= stack_pointer_rtx
;
2910 /* If we are doing svr4-abi, sp has already been decremented by fsiz. */
2911 for (; regno
<= GP_ARG_LAST
; regno
++)
2914 ptr
= gen_rtx_PLUS (Pmode
, stack_pointer_rtx
, GEN_INT (offset
));
2915 emit_move_insn (gen_rtx_MEM (SImode
, ptr
),
2916 gen_rtx_REG (SImode
, regno
));
2918 offset
+= GET_MODE_SIZE (SImode
);
2925 rtx fsiz_rtx
= GEN_INT (fsiz
);
2927 rtx_insn
*insn
= NULL
;
2928 insn
= emit_insn (gen_subsi3 (stack_pointer_rtx
, stack_pointer_rtx
,
2931 RTX_FRAME_RELATED_P (insn
) = 1;
2933 /* Handle SUB_RETURN_ADDR_REGNUM specially at first. */
2934 if (!crtl
->is_leaf
|| interrupt_handler
)
2936 mem_rtx
= gen_rtx_MEM (SImode
,
2937 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
2940 if (interrupt_handler
)
2941 /* Do not optimize in flow analysis. */
2942 MEM_VOLATILE_P (mem_rtx
) = 1;
2944 reg_rtx
= gen_rtx_REG (SImode
, MB_ABI_SUB_RETURN_ADDR_REGNUM
);
2945 insn
= emit_move_insn (mem_rtx
, reg_rtx
);
2946 RTX_FRAME_RELATED_P (insn
) = 1;
2949 /* _save_ registers for prologue. */
2950 save_restore_insns (1);
2952 if (frame_pointer_needed
)
2956 insn
= emit_insn (gen_movsi (hard_frame_pointer_rtx
,
2957 stack_pointer_rtx
));
2960 RTX_FRAME_RELATED_P (insn
) = 1;
2964 if ((flag_pic
== 2 || TLS_NEEDS_GOT
)
2965 && df_regs_ever_live_p (MB_ABI_PIC_ADDR_REGNUM
))
2967 SET_REGNO (pic_offset_table_rtx
, MB_ABI_PIC_ADDR_REGNUM
);
2968 emit_insn (gen_set_got (pic_offset_table_rtx
)); /* setting GOT. */
2971 /* If we are profiling, make sure no instructions are scheduled before
2972 the call to mcount. */
2975 emit_insn (gen_blockage ());
2978 /* Do necessary cleanup after a function to restore stack, frame, and regs. */
2980 #define RA_MASK ((long) 0x80000000) /* 1 << 31 */
2981 #define PIC_OFFSET_TABLE_MASK (1 << (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST))
2984 microblaze_function_epilogue (FILE * file ATTRIBUTE_UNUSED
,
2985 HOST_WIDE_INT size ATTRIBUTE_UNUSED
)
2989 /* Get the function name the same way that toplev.c does before calling
2990 assemble_start_function. This is needed so that the name used here
2991 exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */
2992 fnname
= XSTR (XEXP (DECL_RTL (current_function_decl
), 0), 0);
2994 if (!flag_inhibit_size_directive
)
2996 fputs ("\t.end\t", file
);
2997 if (interrupt_handler
&& !break_handler
)
2998 fputs ("_interrupt_handler", file
);
2999 else if (break_handler
)
3000 fputs ("_break_handler", file
);
3002 assemble_name (file
, fnname
);
3006 /* Reset state info for each function. */
3007 current_frame_info
= zero_frame_info
;
3009 /* Restore the output file if optimizing the GP (optimizing the GP causes
3010 the text to be diverted to a tempfile, so that data decls come before
3011 references to the data). */
3014 /* Expand the epilogue into a bunch of separate insns. */
3017 microblaze_expand_epilogue (void)
3019 HOST_WIDE_INT fsiz
= current_frame_info
.total_size
;
3020 rtx fsiz_rtx
= GEN_INT (fsiz
);
3024 /* In case of interrupt handlers use addki instead of addi for changing the
3025 stack pointer value. */
3027 if (microblaze_can_use_return_insn ())
3029 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode
,
3031 MB_ABI_SUB_RETURN_ADDR_REGNUM
)));
3037 /* Restore SUB_RETURN_ADDR_REGNUM at first. This is to prevent the
3038 sequence of load-followed by a use (in rtsd) in every prologue. Saves
3039 a load-use stall cycle :) This is also important to handle alloca.
3040 (See comments for if (frame_pointer_needed) below. */
3042 if (!crtl
->is_leaf
|| interrupt_handler
)
3045 gen_rtx_MEM (SImode
,
3046 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
, const0_rtx
));
3047 if (interrupt_handler
)
3048 /* Do not optimize in flow analysis. */
3049 MEM_VOLATILE_P (mem_rtx
) = 1;
3050 reg_rtx
= gen_rtx_REG (SImode
, MB_ABI_SUB_RETURN_ADDR_REGNUM
);
3051 emit_move_insn (reg_rtx
, mem_rtx
);
3054 /* It is important that this is done after we restore the return address
3055 register (above). When alloca is used, we want to restore the
3056 sub-routine return address only from the current stack top and not
3057 from the frame pointer (which we restore below). (frame_pointer + 0)
3058 might have been over-written since alloca allocates memory on the
3060 if (frame_pointer_needed
)
3061 emit_insn (gen_movsi (stack_pointer_rtx
, hard_frame_pointer_rtx
));
3063 /* _restore_ registers for epilogue. */
3064 save_restore_insns (0);
3065 emit_insn (gen_blockage ());
3066 emit_insn (gen_addsi3 (stack_pointer_rtx
, stack_pointer_rtx
, fsiz_rtx
));
3069 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode
, GP_REG_FIRST
+
3070 MB_ABI_SUB_RETURN_ADDR_REGNUM
)));
3074 /* Return nonzero if this function is known to have a null epilogue.
3075 This allows the optimizer to omit jumps to jumps if no stack
3079 microblaze_can_use_return_insn (void)
3081 if (!reload_completed
)
3084 if (df_regs_ever_live_p (MB_ABI_SUB_RETURN_ADDR_REGNUM
) || profile_flag
)
3087 if (current_frame_info
.initialized
)
3088 return current_frame_info
.total_size
== 0;
3090 return compute_frame_size (get_frame_size ()) == 0;
3093 /* Implement TARGET_SECONDARY_RELOAD. */
3096 microblaze_secondary_reload (bool in_p ATTRIBUTE_UNUSED
, rtx x ATTRIBUTE_UNUSED
,
3097 reg_class_t rclass
, machine_mode mode ATTRIBUTE_UNUSED
,
3098 secondary_reload_info
*sri ATTRIBUTE_UNUSED
)
3100 if (rclass
== ST_REGS
)
3107 microblaze_globalize_label (FILE * stream
, const char *name
)
3109 fputs ("\t.globl\t", stream
);
3110 if (microblaze_is_interrupt_variant ())
3112 if (interrupt_handler
&& strcmp (name
, INTERRUPT_HANDLER_NAME
))
3113 fputs (INTERRUPT_HANDLER_NAME
, stream
);
3114 else if (break_handler
&& strcmp (name
, BREAK_HANDLER_NAME
))
3115 fputs (BREAK_HANDLER_NAME
, stream
);
3116 else if (fast_interrupt
&& strcmp (name
, FAST_INTERRUPT_NAME
))
3117 fputs (FAST_INTERRUPT_NAME
, stream
);
3118 fputs ("\n\t.globl\t", stream
);
3120 assemble_name (stream
, name
);
3121 fputs ("\n", stream
);
3124 /* Returns true if decl should be placed into a "small data" section. */
3126 microblaze_elf_in_small_data_p (const_tree decl
)
3130 if (!TARGET_XLGPOPT
)
3133 /* We want to merge strings, so we never consider them small data. */
3134 if (TREE_CODE (decl
) == STRING_CST
)
3137 /* Functions are never in the small data area. */
3138 if (TREE_CODE (decl
) == FUNCTION_DECL
)
3141 if (TREE_CODE (decl
) == VAR_DECL
&& DECL_SECTION_NAME (decl
))
3143 const char *section
= DECL_SECTION_NAME (decl
);
3144 if (strcmp (section
, ".sdata") == 0
3145 || strcmp (section
, ".sdata2") == 0
3146 || strcmp (section
, ".sbss") == 0
3147 || strcmp (section
, ".sbss2") == 0)
3151 size
= int_size_in_bytes (TREE_TYPE (decl
));
3153 return (size
> 0 && size
<= microblaze_section_threshold
);
3158 microblaze_select_section (tree decl
, int reloc
, unsigned HOST_WIDE_INT align
)
3160 switch (categorize_decl_for_section (decl
, reloc
))
3162 case SECCAT_RODATA_MERGE_STR
:
3163 case SECCAT_RODATA_MERGE_STR_INIT
:
3164 /* MB binutils have various issues with mergeable string sections and
3165 relaxation/relocation. Currently, turning mergeable sections
3166 into regular readonly sections. */
3168 return readonly_data_section
;
3170 return default_elf_select_section (decl
, reloc
, align
);
3175 Encode info about sections into the RTL based on a symbol's declaration.
3176 The default definition of this hook, default_encode_section_info in
3177 `varasm.c', sets a number of commonly-useful bits in SYMBOL_REF_FLAGS. */
3180 microblaze_encode_section_info (tree decl
, rtx rtl
, int first
)
3182 default_encode_section_info (decl
, rtl
, first
);
3186 expand_pic_symbol_ref (machine_mode mode ATTRIBUTE_UNUSED
, rtx op
)
3189 result
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, op
), UNSPEC_GOTOFF
);
3190 result
= gen_rtx_CONST (Pmode
, result
);
3191 result
= gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
, result
);
3192 result
= gen_const_mem (Pmode
, result
);
3197 microblaze_asm_output_mi_thunk (FILE *file
, tree thunk_fndecl ATTRIBUTE_UNUSED
,
3198 HOST_WIDE_INT delta
, HOST_WIDE_INT vcall_offset
,
3201 rtx this_rtx
, funexp
;
3204 reload_completed
= 1;
3205 epilogue_completed
= 1;
3207 /* Mark the end of the (empty) prologue. */
3208 emit_note (NOTE_INSN_PROLOGUE_END
);
3210 /* Find the "this" pointer. If the function returns a structure,
3211 the structure return pointer is in MB_ABI_FIRST_ARG_REGNUM. */
3212 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function
)), function
))
3213 this_rtx
= gen_rtx_REG (Pmode
, (MB_ABI_FIRST_ARG_REGNUM
+ 1));
3215 this_rtx
= gen_rtx_REG (Pmode
, MB_ABI_FIRST_ARG_REGNUM
);
3217 /* Apply the constant offset, if required. */
3219 emit_insn (gen_addsi3 (this_rtx
, this_rtx
, GEN_INT (delta
)));
3221 /* Apply the offset from the vtable, if required. */
3224 rtx vcall_offset_rtx
= GEN_INT (vcall_offset
);
3225 rtx temp1
= gen_rtx_REG (Pmode
, MB_ABI_TEMP1_REGNUM
);
3227 emit_move_insn (temp1
, gen_rtx_MEM (Pmode
, this_rtx
));
3229 rtx loc
= gen_rtx_PLUS (Pmode
, temp1
, vcall_offset_rtx
);
3230 emit_move_insn (temp1
, gen_rtx_MEM (Pmode
, loc
));
3232 emit_insn (gen_addsi3 (this_rtx
, this_rtx
, temp1
));
3235 /* Generate a tail call to the target function. */
3236 if (!TREE_USED (function
))
3238 assemble_external (function
);
3239 TREE_USED (function
) = 1;
3242 funexp
= XEXP (DECL_RTL (function
), 0);
3243 rtx temp2
= gen_rtx_REG (Pmode
, MB_ABI_TEMP2_REGNUM
);
3246 emit_move_insn (temp2
, expand_pic_symbol_ref (Pmode
, funexp
));
3248 emit_move_insn (temp2
, funexp
);
3250 emit_insn (gen_indirect_jump (temp2
));
3252 /* Run just enough of rest_of_compilation. This sequence was
3253 "borrowed" from rs6000.c. */
3254 insn
= get_insns ();
3255 shorten_branches (insn
);
3256 final_start_function (insn
, file
, 1);
3257 final (insn
, file
, 1);
3258 final_end_function ();
3260 reload_completed
= 0;
3261 epilogue_completed
= 0;
3265 microblaze_expand_move (machine_mode mode
, rtx operands
[])
3272 if (!register_operand (op0
, SImode
)
3273 && !register_operand (op1
, SImode
)
3274 && (GET_CODE (op1
) != CONST_INT
|| INTVAL (op1
) != 0))
3276 rtx temp
= force_reg (SImode
, op1
);
3277 emit_move_insn (op0
, temp
);
3280 /* If operands[1] is a constant address invalid for pic, then we need to
3281 handle it just like LEGITIMIZE_ADDRESS does. */
3282 if (GET_CODE (op1
) == SYMBOL_REF
|| GET_CODE (op1
) == LABEL_REF
)
3285 if (microblaze_tls_symbol_p(op1
))
3287 result
= microblaze_legitimize_tls_address (op1
, NULL_RTX
);
3288 emit_move_insn (op0
, result
);
3293 if (reload_in_progress
)
3294 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
3295 result
= expand_pic_symbol_ref (mode
, op1
);
3296 emit_move_insn (op0
, result
);
3300 /* Handle Case of (const (plus symbol const_int)). */
3301 if (GET_CODE (op1
) == CONST
&& GET_CODE (XEXP (op1
,0)) == PLUS
)
3305 p0
= XEXP (XEXP (op1
, 0), 0);
3306 p1
= XEXP (XEXP (op1
, 0), 1);
3308 if ((GET_CODE (p1
) == CONST_INT
)
3309 && ((GET_CODE (p0
) == UNSPEC
)
3310 || ((GET_CODE (p0
) == SYMBOL_REF
|| GET_CODE (p0
) == LABEL_REF
)
3311 && (flag_pic
== 2 || microblaze_tls_symbol_p (p0
)
3312 || !SMALL_INT (p1
)))))
3314 rtx temp
= force_reg (SImode
, p0
);
3317 if (flag_pic
&& reload_in_progress
)
3318 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
3319 emit_move_insn (op0
, gen_rtx_PLUS (SImode
, temp
, temp2
));
3326 /* Expand shift operations. */
3328 microblaze_expand_shift (rtx operands
[])
3330 gcc_assert ((GET_CODE (operands
[2]) == CONST_INT
)
3331 || (GET_CODE (operands
[2]) == REG
)
3332 || (GET_CODE (operands
[2]) == SUBREG
));
3334 /* Shift by one -- generate pattern. */
3335 if ((GET_CODE (operands
[2]) == CONST_INT
) && (INTVAL (operands
[2]) == 1))
3338 /* Have barrel shifter and shift > 1: use it. */
3339 if (TARGET_BARREL_SHIFT
)
3342 gcc_assert ((GET_CODE (operands
[0]) == REG
)
3343 || (GET_CODE (operands
[0]) == SUBREG
)
3344 || (GET_CODE (operands
[1]) == REG
)
3345 || (GET_CODE (operands
[1]) == SUBREG
));
3347 /* Shift by zero -- copy regs if necessary. */
3348 if ((GET_CODE (operands
[2]) == CONST_INT
) && (INTVAL (operands
[2]) == 0))
3350 if (REGNO (operands
[0]) != REGNO (operands
[1]))
3351 emit_insn (gen_movsi (operands
[0], operands
[1]));
3358 /* Return an RTX indicating where the return address to the
3359 calling function can be found. */
3361 microblaze_return_addr (int count
, rtx frame ATTRIBUTE_UNUSED
)
3366 return gen_rtx_PLUS (Pmode
,
3367 get_hard_reg_initial_val (Pmode
,
3368 MB_ABI_SUB_RETURN_ADDR_REGNUM
),
3372 /* Queue an .ident string in the queue of top-level asm statements.
3373 If the string size is below the threshold, put it into .sdata2.
3374 If the front-end is done, we must be being called from toplev.c.
3375 In that case, do nothing. */
3377 microblaze_asm_output_ident (const char *string
)
3379 const char *section_asm_op
;
3383 if (symtab
->state
!= PARSING
)
3386 size
= strlen (string
) + 1;
3387 if (size
<= microblaze_section_threshold
)
3388 section_asm_op
= SDATA2_SECTION_ASM_OP
;
3390 section_asm_op
= READONLY_DATA_SECTION_ASM_OP
;
3392 buf
= ACONCAT ((section_asm_op
, "\n\t.ascii \"", string
, "\\0\"\n", NULL
));
3393 symtab
->finalize_toplevel_asm (build_string (strlen (buf
), buf
));
3397 microblaze_elf_asm_init_sections (void)
3400 = get_unnamed_section (SECTION_WRITE
, output_section_asm_op
,
3401 SDATA2_SECTION_ASM_OP
);
3404 /* Generate assembler code for constant parts of a trampoline. */
3407 microblaze_asm_trampoline_template (FILE *f
)
3409 fprintf (f
, "\tmfs r18, rpc\n");
3410 fprintf (f
, "\tlwi r3, r18, 16\n");
3411 fprintf (f
, "\tlwi r18, r18, 20\n");
3412 fprintf (f
, "\tbra r18\n");
3413 /* fprintf (f, "\t.word\t0x00000000\t\t# <function address>\n"); */
3414 /* fprintf (f, "\t.word\t0x00000000\t\t# <static chain value>\n"); */
3417 /* Implement TARGET_TRAMPOLINE_INIT. */
3420 microblaze_trampoline_init (rtx m_tramp
, tree fndecl
, rtx chain_value
)
3422 rtx fnaddr
= XEXP (DECL_RTL (fndecl
), 0);
3425 emit_block_move (m_tramp
, assemble_trampoline_template (),
3426 GEN_INT (6*UNITS_PER_WORD
), BLOCK_OP_NORMAL
);
3428 mem
= adjust_address (m_tramp
, SImode
, 16);
3429 emit_move_insn (mem
, chain_value
);
3430 mem
= adjust_address (m_tramp
, SImode
, 20);
3431 emit_move_insn (mem
, fnaddr
);
3434 /* Generate conditional branch -- first, generate test condition,
3435 second, generate correct branch instruction. */
3438 microblaze_expand_conditional_branch (machine_mode mode
, rtx operands
[])
3440 enum rtx_code code
= GET_CODE (operands
[0]);
3441 rtx cmp_op0
= operands
[1];
3442 rtx cmp_op1
= operands
[2];
3443 rtx label1
= operands
[3];
3444 rtx comp_reg
= gen_reg_rtx (SImode
);
3447 gcc_assert ((GET_CODE (cmp_op0
) == REG
) || (GET_CODE (cmp_op0
) == SUBREG
));
3449 /* If comparing against zero, just test source reg. */
3450 if (cmp_op1
== const0_rtx
)
3453 condition
= gen_rtx_fmt_ee (signed_condition (code
), SImode
, comp_reg
, const0_rtx
);
3454 emit_jump_insn (gen_condjump (condition
, label1
));
3457 else if (code
== EQ
|| code
== NE
)
3459 /* Use xor for equal/not-equal comparison. */
3460 emit_insn (gen_xorsi3 (comp_reg
, cmp_op0
, cmp_op1
));
3461 condition
= gen_rtx_fmt_ee (signed_condition (code
), SImode
, comp_reg
, const0_rtx
);
3462 emit_jump_insn (gen_condjump (condition
, label1
));
3466 /* Generate compare and branch in single instruction. */
3467 cmp_op1
= force_reg (mode
, cmp_op1
);
3468 condition
= gen_rtx_fmt_ee (code
, mode
, cmp_op0
, cmp_op1
);
3469 emit_jump_insn (gen_branch_compare(condition
, cmp_op0
, cmp_op1
, label1
));
3474 microblaze_expand_conditional_branch_reg (enum machine_mode mode
,
3477 enum rtx_code code
= GET_CODE (operands
[0]);
3478 rtx cmp_op0
= operands
[1];
3479 rtx cmp_op1
= operands
[2];
3480 rtx label1
= operands
[3];
3481 rtx comp_reg
= gen_reg_rtx (SImode
);
3484 gcc_assert ((GET_CODE (cmp_op0
) == REG
)
3485 || (GET_CODE (cmp_op0
) == SUBREG
));
3487 /* If comparing against zero, just test source reg. */
3488 if (cmp_op1
== const0_rtx
)
3491 condition
= gen_rtx_fmt_ee (signed_condition (code
),
3492 SImode
, comp_reg
, const0_rtx
);
3493 emit_jump_insn (gen_condjump (condition
, label1
));
3495 else if (code
== EQ
)
3497 emit_insn (gen_seq_internal_pat (comp_reg
,
3499 condition
= gen_rtx_EQ (SImode
, comp_reg
, const0_rtx
);
3500 emit_jump_insn (gen_condjump (condition
, label1
));
3502 else if (code
== NE
)
3504 emit_insn (gen_sne_internal_pat (comp_reg
, cmp_op0
,
3506 condition
= gen_rtx_NE (SImode
, comp_reg
, const0_rtx
);
3507 emit_jump_insn (gen_condjump (condition
, label1
));
3511 /* Generate compare and branch in single instruction. */
3512 cmp_op1
= force_reg (mode
, cmp_op1
);
3513 condition
= gen_rtx_fmt_ee (code
, mode
, cmp_op0
, cmp_op1
);
3514 emit_jump_insn (gen_branch_compare (condition
, cmp_op0
,
3520 microblaze_expand_conditional_branch_sf (rtx operands
[])
3523 rtx cmp_op0
= XEXP (operands
[0], 0);
3524 rtx cmp_op1
= XEXP (operands
[0], 1);
3525 rtx comp_reg
= gen_reg_rtx (SImode
);
3527 emit_insn (gen_cstoresf4 (comp_reg
, operands
[0], cmp_op0
, cmp_op1
));
3528 condition
= gen_rtx_NE (SImode
, comp_reg
, const0_rtx
);
3529 emit_jump_insn (gen_condjump (condition
, operands
[3]));
3532 /* Implement TARGET_FRAME_POINTER_REQUIRED. */
3535 microblaze_frame_pointer_required (void)
3537 /* If the function contains dynamic stack allocations, we need to
3538 use the frame pointer to access the static parts of the frame. */
3539 if (cfun
->calls_alloca
)
3545 microblaze_expand_divide (rtx operands
[])
3547 /* Table lookup software divides. Works for all (nr/dr) where (0 <= nr,dr <= 15). */
3549 rtx regt1
= gen_reg_rtx (SImode
);
3550 rtx reg18
= gen_rtx_REG (SImode
, R_TMP
);
3551 rtx regqi
= gen_reg_rtx (QImode
);
3552 rtx_code_label
*div_label
= gen_label_rtx ();
3553 rtx_code_label
*div_end_label
= gen_label_rtx ();
3554 rtx div_table_rtx
= gen_rtx_SYMBOL_REF (QImode
,"_divsi3_table");
3557 rtx_insn
*jump
, *cjump
, *insn
;
3559 insn
= emit_insn (gen_iorsi3 (regt1
, operands
[1], operands
[2]));
3560 cjump
= emit_jump_insn_after (gen_cbranchsi4 (
3561 gen_rtx_GTU (SImode
, regt1
, GEN_INT (15)),
3562 regt1
, GEN_INT (15), div_label
), insn
);
3563 LABEL_NUSES (div_label
) = 1;
3564 JUMP_LABEL (cjump
) = div_label
;
3565 emit_insn (gen_rtx_CLOBBER (SImode
, reg18
));
3567 emit_insn (gen_ashlsi3_bshift (regt1
, operands
[1], GEN_INT(4)));
3568 emit_insn (gen_addsi3 (regt1
, regt1
, operands
[2]));
3569 mem_rtx
= gen_rtx_MEM (QImode
,
3570 gen_rtx_PLUS (Pmode
, regt1
, div_table_rtx
));
3572 insn
= emit_insn (gen_movqi (regqi
, mem_rtx
));
3573 insn
= emit_insn (gen_movsi (operands
[0], gen_rtx_SUBREG (SImode
, regqi
, 0)));
3574 jump
= emit_jump_insn_after (gen_jump (div_end_label
), insn
);
3575 JUMP_LABEL (jump
) = div_end_label
;
3576 LABEL_NUSES (div_end_label
) = 1;
3579 emit_label (div_label
);
3580 ret
= emit_library_call_value (gen_rtx_SYMBOL_REF (Pmode
, "__divsi3"),
3581 operands
[0], LCT_NORMAL
,
3582 GET_MODE (operands
[0]), 2, operands
[1],
3583 GET_MODE (operands
[1]), operands
[2],
3584 GET_MODE (operands
[2]));
3585 if (ret
!= operands
[0])
3586 emit_move_insn (operands
[0], ret
);
3588 emit_label (div_end_label
);
3589 emit_insn (gen_blockage ());
3592 /* Implement TARGET_FUNCTION_VALUE. */
3594 microblaze_function_value (const_tree valtype
,
3595 const_tree func ATTRIBUTE_UNUSED
,
3596 bool outgoing ATTRIBUTE_UNUSED
)
3598 return LIBCALL_VALUE (TYPE_MODE (valtype
));
3601 /* Implement TARGET_SCHED_ADJUST_COST. */
3603 microblaze_adjust_cost (rtx_insn
*insn ATTRIBUTE_UNUSED
, rtx link
,
3604 rtx_insn
*dep ATTRIBUTE_UNUSED
, int cost
)
3606 if (REG_NOTE_KIND (link
) == REG_DEP_OUTPUT
)
3608 if (REG_NOTE_KIND (link
) != 0)
3613 /* Implement TARGET_LEGITIMATE_CONSTANT_P.
3615 At present, GAS doesn't understand li.[sd], so don't allow it
3616 to be generated at present. */
3618 microblaze_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED
, rtx x
)
3621 if (microblaze_cannot_force_const_mem(mode
, x
))
3624 if (GET_CODE (x
) == CONST_DOUBLE
)
3626 return microblaze_const_double_ok (x
, GET_MODE (x
));
3629 /* Handle Case of (const (plus unspec const_int)). */
3630 if (GET_CODE (x
) == CONST
&& GET_CODE (XEXP (x
,0)) == PLUS
)
3634 p0
= XEXP (XEXP (x
, 0), 0);
3635 p1
= XEXP (XEXP (x
, 0), 1);
3637 if (GET_CODE(p1
) == CONST_INT
)
3639 /* Const offset from UNSPEC is not supported. */
3640 if ((GET_CODE (p0
) == UNSPEC
))
3643 if ((GET_CODE (p0
) == SYMBOL_REF
|| GET_CODE (p0
) == LABEL_REF
)
3644 && (microblaze_tls_symbol_p (p0
) || !SMALL_INT (p1
)))
3653 #undef TARGET_ENCODE_SECTION_INFO
3654 #define TARGET_ENCODE_SECTION_INFO microblaze_encode_section_info
3656 #undef TARGET_ASM_GLOBALIZE_LABEL
3657 #define TARGET_ASM_GLOBALIZE_LABEL microblaze_globalize_label
3659 #undef TARGET_ASM_FUNCTION_PROLOGUE
3660 #define TARGET_ASM_FUNCTION_PROLOGUE microblaze_function_prologue
3662 #undef TARGET_ASM_FUNCTION_EPILOGUE
3663 #define TARGET_ASM_FUNCTION_EPILOGUE microblaze_function_epilogue
3665 #undef TARGET_RTX_COSTS
3666 #define TARGET_RTX_COSTS microblaze_rtx_costs
3668 #undef TARGET_CANNOT_FORCE_CONST_MEM
3669 #define TARGET_CANNOT_FORCE_CONST_MEM microblaze_cannot_force_const_mem
3671 #undef TARGET_ADDRESS_COST
3672 #define TARGET_ADDRESS_COST microblaze_address_cost
3674 #undef TARGET_ATTRIBUTE_TABLE
3675 #define TARGET_ATTRIBUTE_TABLE microblaze_attribute_table
3677 #undef TARGET_IN_SMALL_DATA_P
3678 #define TARGET_IN_SMALL_DATA_P microblaze_elf_in_small_data_p
3680 #undef TARGET_ASM_SELECT_SECTION
3681 #define TARGET_ASM_SELECT_SECTION microblaze_select_section
3683 #undef TARGET_HAVE_SRODATA_SECTION
3684 #define TARGET_HAVE_SRODATA_SECTION true
3686 #undef TARGET_ASM_FUNCTION_END_PROLOGUE
3687 #define TARGET_ASM_FUNCTION_END_PROLOGUE \
3688 microblaze_function_end_prologue
3690 #undef TARGET_ARG_PARTIAL_BYTES
3691 #define TARGET_ARG_PARTIAL_BYTES function_arg_partial_bytes
3693 #undef TARGET_FUNCTION_ARG
3694 #define TARGET_FUNCTION_ARG microblaze_function_arg
3696 #undef TARGET_FUNCTION_ARG_ADVANCE
3697 #define TARGET_FUNCTION_ARG_ADVANCE microblaze_function_arg_advance
3699 #undef TARGET_CAN_ELIMINATE
3700 #define TARGET_CAN_ELIMINATE microblaze_can_eliminate
3702 #undef TARGET_LEGITIMIZE_ADDRESS
3703 #define TARGET_LEGITIMIZE_ADDRESS microblaze_legitimize_address
3705 #undef TARGET_LEGITIMATE_ADDRESS_P
3706 #define TARGET_LEGITIMATE_ADDRESS_P microblaze_legitimate_address_p
3708 #undef TARGET_FRAME_POINTER_REQUIRED
3709 #define TARGET_FRAME_POINTER_REQUIRED microblaze_frame_pointer_required
3711 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
3712 #define TARGET_ASM_TRAMPOLINE_TEMPLATE microblaze_asm_trampoline_template
3714 #undef TARGET_TRAMPOLINE_INIT
3715 #define TARGET_TRAMPOLINE_INIT microblaze_trampoline_init
3717 #undef TARGET_PROMOTE_FUNCTION_MODE
3718 #define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
3720 #undef TARGET_FUNCTION_VALUE
3721 #define TARGET_FUNCTION_VALUE microblaze_function_value
3723 #undef TARGET_SECONDARY_RELOAD
3724 #define TARGET_SECONDARY_RELOAD microblaze_secondary_reload
3726 #undef TARGET_ASM_OUTPUT_MI_THUNK
3727 #define TARGET_ASM_OUTPUT_MI_THUNK microblaze_asm_output_mi_thunk
3729 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
3730 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true
3732 #undef TARGET_SCHED_ADJUST_COST
3733 #define TARGET_SCHED_ADJUST_COST microblaze_adjust_cost
3735 #undef TARGET_ASM_INIT_SECTIONS
3736 #define TARGET_ASM_INIT_SECTIONS microblaze_elf_asm_init_sections
3738 #undef TARGET_OPTION_OVERRIDE
3739 #define TARGET_OPTION_OVERRIDE microblaze_option_override
3741 #undef TARGET_LEGITIMATE_CONSTANT_P
3742 #define TARGET_LEGITIMATE_CONSTANT_P microblaze_legitimate_constant_p
3744 struct gcc_target targetm
= TARGET_INITIALIZER
;
3746 #include "gt-microblaze.h"