1 /* Subroutines used for code generation on Xilinx MicroBlaze.
2 Copyright (C) 2009-2013 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"
44 #include "target-def.h"
49 #include "diagnostic-core.h"
52 #define MICROBLAZE_VERSION_COMPARE(VA,VB) strcasecmp (VA, VB)
54 /* Classifies an address.
61 A natural register or a register + const_int offset address.
62 The register satisfies microblaze_valid_base_register_p and the
63 offset is a const_arith_operand.
67 A natural register offset by the index contained in an index register. The base
68 register satisfies microblaze_valid_base_register_p and the index register
69 satisfies microblaze_valid_index_register_p
73 A signed 16/32-bit constant address.
77 A constant symbolic address or a (register + symbol). */
79 enum microblaze_address_type
96 enum microblaze_symbol_type
102 /* TLS Address Type. */
111 /* Classification of a MicroBlaze address. */
112 struct microblaze_address_info
114 enum microblaze_address_type type
;
115 rtx regA
; /* Contains valid values on ADDRESS_REG, ADDRESS_REG_INDEX,
117 rtx regB
; /* Contains valid values on ADDRESS_REG_INDEX. */
118 rtx offset
; /* Contains valid values on ADDRESS_CONST_INT and ADDRESS_REG. */
119 rtx symbol
; /* Contains valid values on ADDRESS_SYMBOLIC. */
120 enum microblaze_symbol_type symbol_type
;
121 enum tls_reloc tls_type
;
124 /* Structure to be filled in by compute_frame_size with register
125 save masks, and offsets for the current function. */
127 struct GTY(()) microblaze_frame_info
{
128 long total_size
; /* # bytes that the entire frame takes up. */
129 long var_size
; /* # bytes that variables take up. */
130 long args_size
; /* # bytes that outgoing arguments take up. */
131 int link_debug_size
; /* # bytes for the link reg and back pointer. */
132 int gp_reg_size
; /* # bytes needed to store gp regs. */
133 long gp_offset
; /* offset from new sp to store gp registers. */
134 long mask
; /* mask of saved gp registers. */
135 int initialized
; /* != 0 if frame size already calculated. */
136 int num_gp
; /* number of gp registers saved. */
137 long insns_len
; /* length of insns. */
138 int alloc_stack
; /* Flag to indicate if the current function
139 must not create stack space. (As an optimization). */
142 /* Global variables for machine-dependent things. */
144 /* Toggle which pipleline interface to use. */
145 static GTY(()) int microblaze_sched_use_dfa
= 0;
147 /* Threshold for data being put into the small data/bss area, instead
148 of the normal data area (references to the small data/bss area take
149 1 instruction, and use the global pointer, references to the normal
150 data area takes 2 instructions). */
151 int microblaze_section_threshold
= -1;
153 /* Prevent scheduling potentially exception causing instructions in
154 delay slots. -mcpu=v3.00.a or v4.00.a turns this on. */
155 int microblaze_no_unsafe_delay
;
157 /* Set to one if the targeted core has the CLZ insn. */
158 int microblaze_has_clz
= 0;
160 /* Which CPU pipeline do we use. We haven't really standardized on a CPU
161 version having only a particular type of pipeline. There can still be
162 options on the CPU to scale pipeline features up or down. :(
163 Bad Presentation (??), so we let the MD file rely on the value of
164 this variable instead Making PIPE_5 the default. It should be backward
165 optimal with PIPE_3 MicroBlazes. */
166 enum pipeline_type microblaze_pipe
= MICROBLAZE_PIPE_5
;
168 /* High and low marks for floating point values which we will accept
169 as legitimate constants for TARGET_LEGITIMATE_CONSTANT_P. These are
170 initialized in override_options. */
171 REAL_VALUE_TYPE dfhigh
, dflow
, sfhigh
, sflow
;
173 /* Array giving truth value on whether or not a given hard register
174 can support a given mode. */
175 char microblaze_hard_regno_mode_ok
[(int)MAX_MACHINE_MODE
]
176 [FIRST_PSEUDO_REGISTER
];
178 /* Current frame information calculated by compute_frame_size. */
179 struct microblaze_frame_info current_frame_info
;
181 /* Zero structure to initialize current_frame_info. */
182 struct microblaze_frame_info zero_frame_info
;
184 /* List of all MICROBLAZE punctuation characters used by print_operand. */
185 char microblaze_print_operand_punct
[256];
187 /* Map GCC register number to debugger register number. */
188 int microblaze_dbx_regno
[FIRST_PSEUDO_REGISTER
];
190 /* Map hard register number to register class. */
191 enum reg_class microblaze_regno_to_class
[] =
193 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
194 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
195 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
196 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
197 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
198 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
199 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
200 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
201 ST_REGS
, GR_REGS
, GR_REGS
, GR_REGS
204 /* MicroBlaze specific machine attributes.
205 interrupt_handler - Interrupt handler attribute to add interrupt prologue
206 and epilogue and use appropriate interrupt return.
207 save_volatiles - Similar to interrupt handler, but use normal return. */
208 int interrupt_handler
;
212 const struct attribute_spec microblaze_attribute_table
[] = {
213 /* name min_len, max_len, decl_req, type_req, fn_type, req_handler,
214 affects_type_identity */
215 {"interrupt_handler", 0, 0, true, false, false, NULL
,
217 {"fast_interrupt", 0, 0, true, false, false, NULL
,
219 {"save_volatiles" , 0, 0, true, false, false, NULL
,
221 { NULL
, 0, 0, false, false, false, NULL
,
225 static int microblaze_interrupt_function_p (tree
);
227 section
*sdata2_section
;
230 #undef TARGET_HAVE_TLS
231 #define TARGET_HAVE_TLS true
234 /* Return truth value if a CONST_DOUBLE is ok to be a legitimate constant. */
236 microblaze_const_double_ok (rtx op
, enum machine_mode mode
)
240 if (GET_CODE (op
) != CONST_DOUBLE
)
243 if (GET_MODE (op
) == VOIDmode
)
246 if (mode
!= SFmode
&& mode
!= DFmode
)
249 if (op
== CONST0_RTX (mode
))
252 REAL_VALUE_FROM_CONST_DOUBLE (d
, op
);
254 if (REAL_VALUE_ISNAN (d
))
257 if (REAL_VALUE_NEGATIVE (d
))
258 d
= real_value_negate (&d
);
262 if (REAL_VALUES_LESS (d
, dfhigh
) && REAL_VALUES_LESS (dflow
, d
))
267 if (REAL_VALUES_LESS (d
, sfhigh
) && REAL_VALUES_LESS (sflow
, d
))
274 /* Return truth value if a memory operand fits in a single instruction
275 (ie, register + small offset) or (register + register). */
278 simple_memory_operand (rtx op
, enum machine_mode mode ATTRIBUTE_UNUSED
)
280 rtx addr
, plus0
, plus1
;
282 /* Eliminate non-memory operations. */
283 if (GET_CODE (op
) != MEM
)
286 /* dword operations really put out 2 instructions, so eliminate them. */
287 /* ??? This isn't strictly correct. It is OK to accept multiword modes
288 here, since the length attributes are being set correctly, but only
289 if the address is offsettable. */
290 if (GET_MODE_SIZE (GET_MODE (op
)) > UNITS_PER_WORD
)
294 /* Decode the address now. */
296 switch (GET_CODE (addr
))
303 plus0
= XEXP (addr
, 0);
304 plus1
= XEXP (addr
, 1);
306 if (GET_CODE (plus0
) != REG
)
309 if (GET_CODE (plus0
) == REG
&& GET_CODE (plus1
) == CONST_INT
310 && SMALL_INT (plus1
))
314 else if (GET_CODE (plus1
) == REG
&& GET_CODE (plus0
) == CONST_INT
)
318 else if (GET_CODE (plus0
) == REG
&& GET_CODE (plus1
) == REG
)
335 /* Return nonzero for a memory address that can be used to load or store
339 double_memory_operand (rtx op
, enum machine_mode mode
)
343 if (GET_CODE (op
) != MEM
|| !memory_operand (op
, mode
))
345 /* During reload, we accept a pseudo register if it has an
346 appropriate memory address. If we don't do this, we will
347 wind up reloading into a register, and then reloading that
348 register from memory, when we could just reload directly from
350 if (reload_in_progress
351 && GET_CODE (op
) == REG
352 && REGNO (op
) >= FIRST_PSEUDO_REGISTER
353 && reg_renumber
[REGNO (op
)] < 0
354 && reg_equiv_mem (REGNO (op
)) != 0
355 && double_memory_operand (reg_equiv_mem (REGNO (op
)), mode
))
360 /* Make sure that 4 added to the address is a valid memory address.
361 This essentially just checks for overflow in an added constant. */
365 if (CONSTANT_ADDRESS_P (addr
))
368 return memory_address_p ((GET_MODE_CLASS (mode
) == MODE_INT
370 plus_constant (Pmode
, addr
, 4));
373 /* Implement REG_OK_FOR_BASE_P -and- REG_OK_FOR_INDEX_P. */
375 microblaze_regno_ok_for_base_p (int regno
, int strict
)
377 if (regno
>= FIRST_PSEUDO_REGISTER
)
381 regno
= reg_renumber
[regno
];
384 /* These fake registers will be eliminated to either the stack or
385 hard frame pointer, both of which are usually valid base registers.
386 Reload deals with the cases where the eliminated form isn't valid. */
387 if (regno
== ARG_POINTER_REGNUM
|| regno
== FRAME_POINTER_REGNUM
)
390 return GP_REG_P (regno
);
393 /* Return true if X is a valid base register for the given mode.
394 Allow only hard registers if STRICT. */
397 microblaze_valid_base_register_p (rtx x
,
398 enum machine_mode mode ATTRIBUTE_UNUSED
,
401 if (!strict
&& GET_CODE (x
) == SUBREG
)
404 return (GET_CODE (x
) == REG
405 && microblaze_regno_ok_for_base_p (REGNO (x
), strict
));
408 /* Build the SYMBOL_REF for __tls_get_addr. */
410 static GTY(()) rtx tls_get_addr_libfunc
;
413 get_tls_get_addr (void)
415 if (!tls_get_addr_libfunc
)
416 tls_get_addr_libfunc
= init_one_libfunc ("__tls_get_addr");
417 return tls_get_addr_libfunc
;
420 /* Return TRUE if X is a thread-local symbol. */
422 microblaze_tls_symbol_p (rtx x
)
424 if (!TARGET_HAVE_TLS
)
427 if (GET_CODE (x
) != SYMBOL_REF
)
430 return SYMBOL_REF_TLS_MODEL (x
) != 0;
434 microblaze_tls_operand_p_1 (rtx
*x
, void *data ATTRIBUTE_UNUSED
)
436 if (GET_CODE (*x
) == SYMBOL_REF
)
437 return SYMBOL_REF_TLS_MODEL (*x
) != 0;
439 /* Don't recurse into UNSPEC_TLS looking for TLS symbols; these are
440 TLS offsets, not real symbol references. */
441 if (GET_CODE (*x
) == UNSPEC
&& XINT (*x
, 1) == UNSPEC_TLS
)
447 /* Return TRUE if X contains any TLS symbol references. */
450 microblaze_tls_referenced_p (rtx x
)
452 if (!TARGET_HAVE_TLS
)
455 return for_each_rtx (&x
, microblaze_tls_operand_p_1
, NULL
);
459 microblaze_cannot_force_const_mem (enum machine_mode mode ATTRIBUTE_UNUSED
, rtx x
)
461 return microblaze_tls_referenced_p(x
);
464 /* Return TRUE if X references a SYMBOL_REF. */
466 symbol_mentioned_p (rtx x
)
471 if (GET_CODE (x
) == SYMBOL_REF
)
474 /* UNSPEC entries for a symbol include the SYMBOL_REF, but they
475 are constant offsets, not symbols. */
476 if (GET_CODE (x
) == UNSPEC
)
479 fmt
= GET_RTX_FORMAT (GET_CODE (x
));
481 for (i
= GET_RTX_LENGTH (GET_CODE (x
)) - 1; i
>= 0; i
--)
487 for (j
= XVECLEN (x
, i
) - 1; j
>= 0; j
--)
488 if (symbol_mentioned_p (XVECEXP (x
, i
, j
)))
491 else if (fmt
[i
] == 'e' && symbol_mentioned_p (XEXP (x
, i
)))
498 /* Return TRUE if X references a LABEL_REF. */
500 label_mentioned_p (rtx x
)
505 if (GET_CODE (x
) == LABEL_REF
)
508 /* UNSPEC entries for a symbol include a LABEL_REF for the referencing
509 instruction, but they are constant offsets, not symbols. */
510 if (GET_CODE (x
) == UNSPEC
)
513 fmt
= GET_RTX_FORMAT (GET_CODE (x
));
514 for (i
= GET_RTX_LENGTH (GET_CODE (x
)) - 1; i
>= 0; i
--)
520 for (j
= XVECLEN (x
, i
) - 1; j
>= 0; j
--)
521 if (label_mentioned_p (XVECEXP (x
, i
, j
)))
524 else if (fmt
[i
] == 'e' && label_mentioned_p (XEXP (x
, i
)))
532 tls_mentioned_p (rtx x
)
534 switch (GET_CODE (x
))
537 return tls_mentioned_p (XEXP (x
, 0));
540 if (XINT (x
, 1) == UNSPEC_TLS
)
549 load_tls_operand (rtx x
, rtx reg
)
554 reg
= gen_reg_rtx (Pmode
);
556 tmp
= gen_rtx_CONST (Pmode
, x
);
558 emit_insn (gen_rtx_SET (VOIDmode
, reg
,
559 gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
, tmp
)));
565 microblaze_call_tls_get_addr (rtx x
, rtx reg
, rtx
*valuep
, int reloc
)
567 rtx insns
, tls_entry
;
569 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
573 tls_entry
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (2, x
, GEN_INT (reloc
)),
576 reg
= load_tls_operand (tls_entry
, reg
);
578 *valuep
= emit_library_call_value (get_tls_get_addr (), NULL_RTX
,
579 LCT_PURE
, /* LCT_CONST? */
580 Pmode
, 1, reg
, Pmode
);
582 insns
= get_insns ();
589 microblaze_legitimize_tls_address(rtx x
, rtx reg
)
591 rtx dest
, insns
, ret
, eqv
, addend
;
592 enum tls_model model
;
593 model
= SYMBOL_REF_TLS_MODEL (x
);
597 case TLS_MODEL_LOCAL_DYNAMIC
:
598 case TLS_MODEL_GLOBAL_DYNAMIC
:
599 case TLS_MODEL_INITIAL_EXEC
:
600 insns
= microblaze_call_tls_get_addr (x
, reg
, &ret
, TLS_GD
);
601 dest
= gen_reg_rtx (Pmode
);
602 emit_libcall_block (insns
, dest
, ret
, x
);
605 case TLS_MODEL_LOCAL_EXEC
:
606 insns
= microblaze_call_tls_get_addr (x
, reg
, &ret
, TLS_LDM
);
608 /* Attach a unique REG_EQUIV, to allow the RTL optimizers to
609 share the LDM result with other LD model accesses. */
610 eqv
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, const1_rtx
), UNSPEC_TLS
);
611 dest
= gen_reg_rtx (Pmode
);
612 emit_libcall_block (insns
, dest
, ret
, eqv
);
614 /* Load the addend. */
615 addend
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (2, x
, GEN_INT (TLS_DTPREL
)),
617 addend
= force_reg (SImode
, gen_rtx_CONST (SImode
, addend
));
618 dest
= gen_rtx_PLUS (Pmode
, dest
, addend
);
628 microblaze_classify_unspec (struct microblaze_address_info
*info
, rtx x
)
630 info
->symbol_type
= SYMBOL_TYPE_GENERAL
;
631 info
->symbol
= XVECEXP (x
, 0, 0);
633 if (XINT (x
, 1) == UNSPEC_GOTOFF
)
635 info
->regA
= gen_rtx_REG (SImode
, PIC_OFFSET_TABLE_REGNUM
);
636 info
->type
= ADDRESS_GOTOFF
;
638 else if (XINT (x
, 1) == UNSPEC_PLT
)
640 info
->type
= ADDRESS_PLT
;
642 else if (XINT (x
, 1) == UNSPEC_TLS
)
644 info
->type
= ADDRESS_TLS
;
645 info
->tls_type
= tls_reloc
INTVAL(XVECEXP(x
, 0, 1));
655 /* Return true if X is a valid index register for the given mode.
656 Allow only hard registers if STRICT. */
659 microblaze_valid_index_register_p (rtx x
,
660 enum machine_mode mode ATTRIBUTE_UNUSED
,
663 if (!strict
&& GET_CODE (x
) == SUBREG
)
666 return (GET_CODE (x
) == REG
667 /* A base register is good enough to be an index register on MicroBlaze. */
668 && microblaze_regno_ok_for_base_p (REGNO (x
), strict
));
671 /* Get the base register for accessing a value from the memory or
672 Symbol ref. Used for MicroBlaze Small Data Area Pointer Optimization. */
679 if (!flag_pic
|| microblaze_tls_symbol_p(x
))
680 base_reg
= MB_ABI_BASE_REGNUM
;
682 base_reg
= MB_ABI_PIC_ADDR_REGNUM
;
685 && GET_CODE (x
) == SYMBOL_REF
686 && SYMBOL_REF_SMALL_P (x
) && (decl
= SYMBOL_REF_DECL (x
)) != NULL
)
688 if (TREE_READONLY (decl
))
689 base_reg
= MB_ABI_GPRO_REGNUM
;
691 base_reg
= MB_ABI_GPRW_REGNUM
;
697 /* Return true if X is a valid address for machine mode MODE. If it is,
698 fill in INFO appropriately. STRICT is true if we should only accept
701 type regA regB offset symbol
703 ADDRESS_INVALID NULL NULL NULL NULL
705 ADDRESS_REG %0 NULL const_0 / NULL
707 ADDRESS_REG_INDEX %0 %1 NULL NULL
709 ADDRESS_SYMBOLIC r0 / NULL NULL symbol
712 ADDRESS_CONST_INT r0 NULL const NULL
714 For modes spanning multiple registers (DFmode in 32-bit GPRs,
715 DImode, TImode), indexed addressing cannot be used because
716 adjacent memory cells are accessed by adding word-sized offsets
717 during assembly output. */
720 microblaze_classify_address (struct microblaze_address_info
*info
, rtx x
,
721 enum machine_mode mode
, int strict
)
726 info
->type
= ADDRESS_INVALID
;
731 info
->symbol_type
= SYMBOL_TYPE_INVALID
;
733 switch (GET_CODE (x
))
738 info
->type
= ADDRESS_REG
;
740 info
->offset
= const0_rtx
;
741 return microblaze_valid_base_register_p (info
->regA
, mode
, strict
);
745 xplus0
= XEXP (x
, 0);
746 xplus1
= XEXP (x
, 1);
748 if (microblaze_valid_base_register_p (xplus0
, mode
, strict
))
750 info
->type
= ADDRESS_REG
;
753 if (GET_CODE (xplus1
) == CONST_INT
)
755 info
->offset
= xplus1
;
758 else if (GET_CODE (xplus1
) == UNSPEC
)
760 /* Need offsettable address. */
761 if (GET_MODE_SIZE (mode
) > UNITS_PER_WORD
)
764 return microblaze_classify_unspec (info
, xplus1
);
766 else if ((GET_CODE (xplus1
) == SYMBOL_REF
||
767 GET_CODE (xplus1
) == LABEL_REF
))
769 if (flag_pic
== 2 || microblaze_tls_symbol_p(xplus1
))
771 info
->type
= ADDRESS_SYMBOLIC
;
772 info
->symbol
= xplus1
;
773 info
->symbol_type
= SYMBOL_TYPE_GENERAL
;
776 else if (GET_CODE (xplus1
) == CONST
)
778 rtx xconst0
= XEXP(xplus1
, 0);
781 if (GET_CODE (xconst0
) == UNSPEC
)
783 /* Need offsettable address. */
784 if (GET_MODE_SIZE (mode
) > UNITS_PER_WORD
)
786 return microblaze_classify_unspec(info
, xconst0
);
789 /* for (plus x const_int) just look at x. */
790 if (GET_CODE (xconst0
) == PLUS
791 && GET_CODE (XEXP (xconst0
, 1)) == CONST_INT
792 && SMALL_INT (XEXP (xconst0
, 1)))
794 /* This is ok as info->symbol is set to xplus1 the full
795 const-expression below. */
796 xconst0
= XEXP (xconst0
, 0);
799 if (GET_CODE (xconst0
) == SYMBOL_REF
800 || GET_CODE (xconst0
) == LABEL_REF
)
802 if (flag_pic
== 2 || microblaze_tls_symbol_p(xconst0
))
805 info
->type
= ADDRESS_SYMBOLIC
;
806 info
->symbol
= xplus1
;
807 info
->symbol_type
= SYMBOL_TYPE_GENERAL
;
811 /* Not base + symbol || base + UNSPEC. */
815 else if (GET_CODE (xplus1
) == REG
816 && microblaze_valid_index_register_p (xplus1
, mode
,
818 && (GET_MODE_SIZE (mode
) <= UNITS_PER_WORD
))
820 /* Restrict larger than word-width modes from using an index register. */
821 info
->type
= ADDRESS_REG_INDEX
;
830 info
->regA
= gen_rtx_raw_REG (mode
, 0);
831 info
->type
= ADDRESS_CONST_INT
;
839 info
->type
= ADDRESS_SYMBOLIC
;
840 info
->symbol_type
= SYMBOL_TYPE_GENERAL
;
842 info
->regA
= gen_rtx_raw_REG (mode
, get_base_reg (x
));
844 if (GET_CODE (x
) == CONST
)
846 if (GET_CODE (XEXP (x
, 0)) == UNSPEC
)
848 info
->regA
= gen_rtx_raw_REG (mode
,
849 get_base_reg (XVECEXP (XEXP (x
,0), 0, 0)));
850 return microblaze_classify_unspec (info
, XEXP (x
, 0));
852 return !(flag_pic
&& pic_address_needs_scratch (x
));
857 else if (microblaze_tls_symbol_p(x
))
865 if (reload_in_progress
)
866 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
867 return microblaze_classify_unspec (info
, x
);
877 /* This function is used to implement GO_IF_LEGITIMATE_ADDRESS. It
878 returns a nonzero value if X is a legitimate address for a memory
879 operand of the indicated MODE. STRICT is nonzero if this function
880 is called during reload. */
883 microblaze_legitimate_address_p (enum machine_mode mode
, rtx x
, bool strict
)
885 struct microblaze_address_info addr
;
887 return microblaze_classify_address (&addr
, x
, mode
, strict
);
891 microblaze_valid_pic_const (rtx x
)
893 switch (GET_CODE (x
))
905 microblaze_legitimate_pic_operand (rtx x
)
907 if (flag_pic
== 2 && (symbol_mentioned_p(x
) || label_mentioned_p(x
)))
910 if (microblaze_tls_referenced_p(x
))
916 /* Try machine-dependent ways of modifying an illegitimate address
917 to be legitimate. If we find one, return the new, valid address.
918 This is used from only one place: `memory_address' in explow.c.
920 OLDX is the address as it was before break_out_memory_refs was
921 called. In some cases it is useful to look at this to decide what
924 It is always safe for this function to do nothing. It exists to
925 recognize opportunities to optimize the output.
927 For the MicroBlaze, transform:
929 memory(X + <large int>)
933 Y = <large int> & ~0x7fff;
935 memory (Z + (<large int> & 0x7fff));
937 This is for CSE to find several similar references, and only use one Z.
939 When PIC, convert addresses of the form memory (symbol+large int) to
940 memory (reg+large int). */
943 microblaze_legitimize_address (rtx x
, rtx oldx ATTRIBUTE_UNUSED
,
944 enum machine_mode mode ATTRIBUTE_UNUSED
)
946 register rtx xinsn
= x
, result
;
948 if (GET_CODE (xinsn
) == CONST
949 && flag_pic
&& pic_address_needs_scratch (xinsn
))
951 rtx ptr_reg
= gen_reg_rtx (Pmode
);
952 rtx constant
= XEXP (XEXP (xinsn
, 0), 1);
954 emit_move_insn (ptr_reg
, XEXP (XEXP (xinsn
, 0), 0));
956 result
= gen_rtx_PLUS (Pmode
, ptr_reg
, constant
);
957 if (SMALL_INT (constant
))
959 /* Otherwise we fall through so the code below will fix the
964 if (GET_CODE (xinsn
) == PLUS
)
966 register rtx xplus0
= XEXP (xinsn
, 0);
967 register rtx xplus1
= XEXP (xinsn
, 1);
968 register enum rtx_code code0
= GET_CODE (xplus0
);
969 register enum rtx_code code1
= GET_CODE (xplus1
);
971 if (code0
!= REG
&& code1
== REG
)
973 xplus0
= XEXP (xinsn
, 1);
974 xplus1
= XEXP (xinsn
, 0);
975 code0
= GET_CODE (xplus0
);
976 code1
= GET_CODE (xplus1
);
979 if (code0
== REG
&& REG_OK_FOR_BASE_P (xplus0
)
980 && code1
== CONST_INT
&& !SMALL_INT (xplus1
))
982 rtx int_reg
= gen_reg_rtx (Pmode
);
983 rtx ptr_reg
= gen_reg_rtx (Pmode
);
985 emit_move_insn (int_reg
, GEN_INT (INTVAL (xplus1
) & ~0x7fff));
987 emit_insn (gen_rtx_SET (VOIDmode
,
989 gen_rtx_PLUS (Pmode
, xplus0
, int_reg
)));
991 result
= gen_rtx_PLUS (Pmode
, ptr_reg
,
992 GEN_INT (INTVAL (xplus1
) & 0x7fff));
996 if (code0
== REG
&& REG_OK_FOR_BASE_P (xplus0
))
998 if (reload_in_progress
)
999 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
1002 xplus1
= XEXP (xplus1
, 0);
1003 code1
= GET_CODE (xplus1
);
1005 if (code1
== SYMBOL_REF
)
1007 if (microblaze_tls_symbol_p(xplus1
))
1010 reg
= gen_reg_rtx (Pmode
);
1012 tls_ref
= microblaze_legitimize_tls_address (xplus1
,
1014 emit_move_insn (reg
, tls_ref
);
1016 result
= gen_rtx_PLUS (Pmode
, xplus0
, reg
);
1020 else if (flag_pic
== 2)
1023 reg
= gen_reg_rtx (Pmode
);
1025 pic_ref
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, xplus1
),
1027 pic_ref
= gen_rtx_CONST (Pmode
, pic_ref
);
1028 pic_ref
= gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
, pic_ref
);
1029 pic_ref
= gen_const_mem (Pmode
, pic_ref
);
1030 emit_move_insn (reg
, pic_ref
);
1031 result
= gen_rtx_PLUS (Pmode
, xplus0
, reg
);
1038 if (GET_CODE (xinsn
) == SYMBOL_REF
)
1041 if (microblaze_tls_symbol_p(xinsn
))
1043 reg
= microblaze_legitimize_tls_address (xinsn
, NULL_RTX
);
1049 if (reload_in_progress
)
1050 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
1052 pic_ref
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, xinsn
), UNSPEC_GOTOFF
);
1053 pic_ref
= gen_rtx_CONST (Pmode
, pic_ref
);
1054 pic_ref
= gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
, pic_ref
);
1055 pic_ref
= gen_const_mem (Pmode
, pic_ref
);
1066 #define MAX_MOVE_REGS 8
1067 #define MAX_MOVE_BYTES (MAX_MOVE_REGS * UNITS_PER_WORD)
1069 /* Emit straight-line code to move LENGTH bytes from SRC to DEST.
1070 Assume that the areas do not overlap. */
1073 microblaze_block_move_straight (rtx dest
, rtx src
, HOST_WIDE_INT length
)
1075 HOST_WIDE_INT offset
, delta
;
1076 unsigned HOST_WIDE_INT bits
;
1078 enum machine_mode mode
;
1081 bits
= BITS_PER_WORD
;
1082 mode
= mode_for_size (bits
, MODE_INT
, 0);
1083 delta
= bits
/ BITS_PER_UNIT
;
1085 /* Allocate a buffer for the temporary registers. */
1086 regs
= XALLOCAVEC (rtx
, length
/ delta
);
1088 /* Load as many BITS-sized chunks as possible. Use a normal load if
1089 the source has enough alignment, otherwise use left/right pairs. */
1090 for (offset
= 0, i
= 0; offset
+ delta
<= length
; offset
+= delta
, i
++)
1092 regs
[i
] = gen_reg_rtx (mode
);
1093 emit_move_insn (regs
[i
], adjust_address (src
, mode
, offset
));
1096 /* Copy the chunks to the destination. */
1097 for (offset
= 0, i
= 0; offset
+ delta
<= length
; offset
+= delta
, i
++)
1098 emit_move_insn (adjust_address (dest
, mode
, offset
), regs
[i
]);
1100 /* Mop up any left-over bytes. */
1101 if (offset
< length
)
1103 src
= adjust_address (src
, BLKmode
, offset
);
1104 dest
= adjust_address (dest
, BLKmode
, offset
);
1105 move_by_pieces (dest
, src
, length
- offset
,
1106 MIN (MEM_ALIGN (src
), MEM_ALIGN (dest
)), 0);
1110 /* Helper function for doing a loop-based block operation on memory
1111 reference MEM. Each iteration of the loop will operate on LENGTH
1114 Create a new base register for use within the loop and point it to
1115 the start of MEM. Create a new memory reference that uses this
1116 register. Store them in *LOOP_REG and *LOOP_MEM respectively. */
1119 microblaze_adjust_block_mem (rtx mem
, HOST_WIDE_INT length
,
1120 rtx
* loop_reg
, rtx
* loop_mem
)
1122 *loop_reg
= copy_addr_to_reg (XEXP (mem
, 0));
1124 /* Although the new mem does not refer to a known location,
1125 it does keep up to LENGTH bytes of alignment. */
1126 *loop_mem
= change_address (mem
, BLKmode
, *loop_reg
);
1127 set_mem_align (*loop_mem
,
1128 MIN ((HOST_WIDE_INT
) MEM_ALIGN (mem
),
1129 length
* BITS_PER_UNIT
));
1133 /* Move LENGTH bytes from SRC to DEST using a loop that moves MAX_MOVE_BYTES
1134 per iteration. LENGTH must be at least MAX_MOVE_BYTES. Assume that the
1135 memory regions do not overlap. */
1138 microblaze_block_move_loop (rtx dest
, rtx src
, HOST_WIDE_INT length
)
1140 rtx label
, src_reg
, dest_reg
, final_src
;
1141 HOST_WIDE_INT leftover
;
1143 leftover
= length
% MAX_MOVE_BYTES
;
1146 /* Create registers and memory references for use within the loop. */
1147 microblaze_adjust_block_mem (src
, MAX_MOVE_BYTES
, &src_reg
, &src
);
1148 microblaze_adjust_block_mem (dest
, MAX_MOVE_BYTES
, &dest_reg
, &dest
);
1150 /* Calculate the value that SRC_REG should have after the last iteration
1152 final_src
= expand_simple_binop (Pmode
, PLUS
, src_reg
, GEN_INT (length
),
1155 /* Emit the start of the loop. */
1156 label
= gen_label_rtx ();
1159 /* Emit the loop body. */
1160 microblaze_block_move_straight (dest
, src
, MAX_MOVE_BYTES
);
1162 /* Move on to the next block. */
1163 emit_move_insn (src_reg
, plus_constant (Pmode
, src_reg
, MAX_MOVE_BYTES
));
1164 emit_move_insn (dest_reg
, plus_constant (Pmode
, dest_reg
, MAX_MOVE_BYTES
));
1166 /* Emit the test & branch. */
1167 emit_insn (gen_cbranchsi4 (gen_rtx_NE (SImode
, src_reg
, final_src
),
1168 src_reg
, final_src
, label
));
1170 /* Mop up any left-over bytes. */
1172 microblaze_block_move_straight (dest
, src
, leftover
);
1175 /* Expand a movmemsi instruction. */
1178 microblaze_expand_block_move (rtx dest
, rtx src
, rtx length
, rtx align_rtx
)
1181 if (GET_CODE (length
) == CONST_INT
)
1183 HOST_WIDE_INT bytes
= INTVAL (length
);
1184 int align
= INTVAL (align_rtx
);
1186 if (align
> UNITS_PER_WORD
)
1188 align
= UNITS_PER_WORD
; /* We can't do any better. */
1190 else if (align
< UNITS_PER_WORD
)
1192 if (INTVAL (length
) <= MAX_MOVE_BYTES
)
1194 move_by_pieces (dest
, src
, bytes
, align
, 0);
1201 if (INTVAL (length
) <= 2 * MAX_MOVE_BYTES
)
1203 microblaze_block_move_straight (dest
, src
, INTVAL (length
));
1208 microblaze_block_move_loop (dest
, src
, INTVAL (length
));
1216 microblaze_rtx_costs (rtx x
, int code
, int outer_code ATTRIBUTE_UNUSED
,
1217 int opno ATTRIBUTE_UNUSED
, int *total
,
1218 bool speed ATTRIBUTE_UNUSED
)
1220 enum machine_mode mode
= GET_MODE (x
);
1226 int num_words
= (GET_MODE_SIZE (mode
) > UNITS_PER_WORD
) ? 2 : 1;
1227 if (simple_memory_operand (x
, mode
))
1228 *total
= COSTS_N_INSNS (2 * num_words
);
1230 *total
= COSTS_N_INSNS (2 * (2 * num_words
));
1238 *total
= COSTS_N_INSNS (2);
1241 *total
= COSTS_N_INSNS (1);
1250 *total
= COSTS_N_INSNS (2);
1253 *total
= COSTS_N_INSNS (1);
1261 if (TARGET_BARREL_SHIFT
)
1263 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v5.00.a")
1265 *total
= COSTS_N_INSNS (1);
1267 *total
= COSTS_N_INSNS (2);
1269 else if (!TARGET_SOFT_MUL
)
1270 *total
= COSTS_N_INSNS (1);
1271 else if (GET_CODE (XEXP (x
, 1)) == CONST_INT
)
1273 /* Add 1 to make shift slightly more expensive than add. */
1274 *total
= COSTS_N_INSNS (INTVAL (XEXP (x
, 1))) + 1;
1275 /* Reduce shift costs for special circumstances. */
1276 if (optimize_size
&& INTVAL (XEXP (x
, 1)) > 5)
1278 if (!optimize_size
&& INTVAL (XEXP (x
, 1)) > 17)
1282 /* Double the worst cost of shifts when there is no barrel shifter and
1283 the shift amount is in a reg. */
1284 *total
= COSTS_N_INSNS (32 * 4);
1290 if (mode
== SFmode
|| mode
== DFmode
)
1292 if (TARGET_HARD_FLOAT
)
1293 *total
= COSTS_N_INSNS (6);
1296 else if (mode
== DImode
)
1298 *total
= COSTS_N_INSNS (4);
1303 *total
= COSTS_N_INSNS (1);
1312 *total
= COSTS_N_INSNS (4);
1320 if (TARGET_HARD_FLOAT
)
1321 *total
= COSTS_N_INSNS (6);
1323 else if (!TARGET_SOFT_MUL
)
1325 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v5.00.a")
1327 *total
= COSTS_N_INSNS (1);
1329 *total
= COSTS_N_INSNS (3);
1332 *total
= COSTS_N_INSNS (10);
1340 if (TARGET_HARD_FLOAT
)
1341 *total
= COSTS_N_INSNS (23);
1347 *total
= COSTS_N_INSNS (1);
1352 *total
= COSTS_N_INSNS (1);
1360 /* Return the number of instructions needed to load or store a value
1361 of mode MODE at X. Return 0 if X isn't valid for MODE. */
1364 microblaze_address_insns (rtx x
, enum machine_mode mode
)
1366 struct microblaze_address_info addr
;
1368 if (microblaze_classify_address (&addr
, x
, mode
, false))
1373 if (SMALL_INT (addr
.offset
))
1377 case ADDRESS_CONST_INT
:
1382 case ADDRESS_REG_INDEX
:
1384 case ADDRESS_SYMBOLIC
:
1385 case ADDRESS_GOTOFF
:
1388 switch (addr
.tls_type
)
1406 /* Provide the costs of an addressing mode that contains ADDR.
1407 If ADDR is not a valid address, its cost is irrelevant. */
1409 microblaze_address_cost (rtx addr
, enum machine_mode mode ATTRIBUTE_UNUSED
,
1410 addr_space_t as ATTRIBUTE_UNUSED
,
1411 bool speed ATTRIBUTE_UNUSED
)
1413 return COSTS_N_INSNS (microblaze_address_insns (addr
, GET_MODE (addr
)));
1416 /* Return nonzero if X is an address which needs a temporary register when
1417 reloaded while generating PIC code. */
1420 pic_address_needs_scratch (rtx x
)
1422 if (GET_CODE (x
) == CONST
&& GET_CODE (XEXP (x
,0)) == PLUS
)
1426 p0
= XEXP (XEXP (x
, 0), 0);
1427 p1
= XEXP (XEXP (x
, 0), 1);
1429 if ((GET_CODE (p0
) == SYMBOL_REF
|| GET_CODE (p0
) == LABEL_REF
)
1430 && (GET_CODE (p1
) == CONST_INT
)
1431 && (flag_pic
== 2 || microblaze_tls_symbol_p (p0
) || !SMALL_INT (p1
)))
1437 /* Argument support functions. */
1438 /* Initialize CUMULATIVE_ARGS for a function. */
1441 init_cumulative_args (CUMULATIVE_ARGS
* cum
, tree fntype
,
1442 rtx libname ATTRIBUTE_UNUSED
)
1444 static CUMULATIVE_ARGS zero_cum
;
1445 tree param
, next_param
;
1449 /* Determine if this function has variable arguments. This is
1450 indicated by the last argument being 'void_type_mode' if there
1451 are no variable arguments. The standard MicroBlaze calling sequence
1452 passes all arguments in the general purpose registers in this case. */
1454 for (param
= fntype
? TYPE_ARG_TYPES (fntype
) : 0;
1455 param
!= 0; param
= next_param
)
1457 next_param
= TREE_CHAIN (param
);
1458 if (next_param
== 0 && TREE_VALUE (param
) != void_type_node
)
1459 cum
->gp_reg_found
= 1;
1463 /* Advance the argument to the next argument position. */
1466 microblaze_function_arg_advance (cumulative_args_t cum_v
,
1467 enum machine_mode mode
,
1468 const_tree type
, bool named ATTRIBUTE_UNUSED
)
1470 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
1479 gcc_assert (GET_MODE_CLASS (mode
) == MODE_COMPLEX_INT
1480 || GET_MODE_CLASS (mode
) == MODE_COMPLEX_FLOAT
);
1482 cum
->gp_reg_found
= 1;
1483 cum
->arg_words
+= ((GET_MODE_SIZE (mode
) + UNITS_PER_WORD
- 1)
1488 cum
->gp_reg_found
= 1;
1489 cum
->arg_words
+= ((int_size_in_bytes (type
) + UNITS_PER_WORD
- 1)
1495 if (!cum
->gp_reg_found
&& cum
->arg_number
<= 2)
1496 cum
->fp_code
+= 1 << ((cum
->arg_number
- 1) * 2);
1500 cum
->arg_words
+= 2;
1501 if (!cum
->gp_reg_found
&& cum
->arg_number
<= 2)
1502 cum
->fp_code
+= 2 << ((cum
->arg_number
- 1) * 2);
1506 cum
->gp_reg_found
= 1;
1507 cum
->arg_words
+= 2;
1514 cum
->gp_reg_found
= 1;
1520 /* Return an RTL expression containing the register for the given mode,
1521 or 0 if the argument is to be passed on the stack. */
1524 microblaze_function_arg (cumulative_args_t cum_v
, enum machine_mode mode
,
1525 const_tree type ATTRIBUTE_UNUSED
,
1526 bool named ATTRIBUTE_UNUSED
)
1528 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
1532 int *arg_words
= &cum
->arg_words
;
1534 cum
->last_arg_fp
= 0;
1545 regbase
= GP_ARG_FIRST
;
1548 gcc_assert (GET_MODE_CLASS (mode
) == MODE_COMPLEX_INT
1549 || GET_MODE_CLASS (mode
) == MODE_COMPLEX_FLOAT
);
1550 /* Drops through. */
1552 regbase
= GP_ARG_FIRST
;
1556 if (*arg_words
>= MAX_ARGS_IN_REGISTERS
)
1560 gcc_assert (regbase
!= -1);
1562 ret
= gen_rtx_REG (mode
, regbase
+ *arg_words
);
1565 if (mode
== VOIDmode
)
1567 if (cum
->num_adjusts
> 0)
1568 ret
= gen_rtx_PARALLEL ((enum machine_mode
) cum
->fp_code
,
1569 gen_rtvec_v (cum
->num_adjusts
, cum
->adjust
));
1575 /* Return number of bytes of argument to put in registers. */
1577 function_arg_partial_bytes (cumulative_args_t cum_v
, enum machine_mode mode
,
1578 tree type
, bool named ATTRIBUTE_UNUSED
)
1580 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
1582 if ((mode
== BLKmode
1583 || GET_MODE_CLASS (mode
) != MODE_COMPLEX_INT
1584 || GET_MODE_CLASS (mode
) != MODE_COMPLEX_FLOAT
)
1585 && cum
->arg_words
< MAX_ARGS_IN_REGISTERS
)
1588 if (mode
== BLKmode
)
1589 words
= ((int_size_in_bytes (type
) + UNITS_PER_WORD
- 1)
1592 words
= (GET_MODE_SIZE (mode
) + UNITS_PER_WORD
- 1) / UNITS_PER_WORD
;
1594 if (words
+ cum
->arg_words
<= MAX_ARGS_IN_REGISTERS
)
1595 return 0; /* structure fits in registers */
1597 return (MAX_ARGS_IN_REGISTERS
- cum
->arg_words
) * UNITS_PER_WORD
;
1600 else if (mode
== DImode
&& cum
->arg_words
== MAX_ARGS_IN_REGISTERS
- 1)
1601 return UNITS_PER_WORD
;
1606 /* Convert a version number of the form "vX.YY.Z" to an integer encoding
1607 for easier range comparison. */
1609 microblaze_version_to_int (const char *version
)
1612 const char *tmpl
= "vX.YY.Z";
1621 { /* Looking for major */
1622 if (!(*p
>= '0' && *p
<= '9'))
1624 iver
+= (int) (*p
- '0');
1628 { /* Looking for minor */
1629 if (!(*p
>= '0' && *p
<= '9'))
1631 iver
+= (int) (*p
- '0');
1635 { /* Looking for compat */
1636 if (!(*p
>= 'a' && *p
<= 'z'))
1639 iver
+= (int) (*p
- 'a');
1659 microblaze_option_override (void)
1661 register int i
, start
;
1663 register enum machine_mode mode
;
1666 microblaze_section_threshold
= (global_options_set
.x_g_switch_value
1668 : MICROBLAZE_DEFAULT_GVALUE
);
1672 /* Make sure it's 2, we only support one kind of PIC. */
1674 if (!TARGET_SUPPORTS_PIC
)
1676 error ("-fPIC/-fpic not supported for this target");
1677 /* Clear it to avoid further errors. */
1682 /* Check the MicroBlaze CPU version for any special action to be done. */
1683 if (microblaze_select_cpu
== NULL
)
1684 microblaze_select_cpu
= MICROBLAZE_DEFAULT_CPU
;
1685 ver
= microblaze_version_to_int (microblaze_select_cpu
);
1688 error ("%qs is an invalid argument to -mcpu=", microblaze_select_cpu
);
1691 ver
= MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v3.00.a");
1694 /* No hardware exceptions in earlier versions. So no worries. */
1696 microblaze_select_flags
&= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY
);
1698 microblaze_no_unsafe_delay
= 0;
1699 microblaze_pipe
= MICROBLAZE_PIPE_3
;
1702 || (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v4.00.b")
1706 microblaze_select_flags
|= (MICROBLAZE_MASK_NO_UNSAFE_DELAY
);
1708 microblaze_no_unsafe_delay
= 1;
1709 microblaze_pipe
= MICROBLAZE_PIPE_3
;
1713 /* We agree to use 5 pipe-stage model even on area optimized 3
1714 pipe-stage variants. */
1716 microblaze_select_flags
&= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY
);
1718 microblaze_no_unsafe_delay
= 0;
1719 microblaze_pipe
= MICROBLAZE_PIPE_5
;
1720 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v5.00.a") == 0
1721 || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
,
1723 || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
,
1726 /* Pattern compares are to be turned on by default only when
1727 compiling for MB v5.00.'z'. */
1728 target_flags
|= MASK_PATTERN_COMPARE
;
1732 ver
= MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v6.00.a");
1735 if (TARGET_MULTIPLY_HIGH
)
1737 "-mxl-multiply-high can be used only with -mcpu=v6.00.a or greater");
1740 ver
= MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v8.10.a");
1741 microblaze_has_clz
= 1;
1744 /* MicroBlaze prior to 8.10.a didn't have clz. */
1745 microblaze_has_clz
= 0;
1748 /* TARGET_REORDER defaults to 2 if -mxl-reorder not specified. */
1749 ver
= MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v8.30.a");
1752 if (TARGET_REORDER
== 1)
1753 warning (0, "-mxl-reorder can be used only with -mcpu=v8.30.a or greater");
1756 else if ((ver
== 0) && !TARGET_PATTERN_COMPARE
)
1758 if (TARGET_REORDER
== 1)
1759 warning (0, "-mxl-reorder requires -mxl-pattern-compare for -mcpu=v8.30.a");
1763 if (TARGET_MULTIPLY_HIGH
&& TARGET_SOFT_MUL
)
1764 error ("-mxl-multiply-high requires -mno-xl-soft-mul");
1766 /* Always use DFA scheduler. */
1767 microblaze_sched_use_dfa
= 1;
1770 microblaze_abicalls
= MICROBLAZE_ABICALLS_NO
;
1773 /* Initialize the high, low values for legit floating point constants. */
1774 real_maxval (&dfhigh
, 0, DFmode
);
1775 real_maxval (&dflow
, 1, DFmode
);
1776 real_maxval (&sfhigh
, 0, SFmode
);
1777 real_maxval (&sflow
, 1, SFmode
);
1779 microblaze_print_operand_punct
['?'] = 1;
1780 microblaze_print_operand_punct
['#'] = 1;
1781 microblaze_print_operand_punct
['&'] = 1;
1782 microblaze_print_operand_punct
['!'] = 1;
1783 microblaze_print_operand_punct
['*'] = 1;
1784 microblaze_print_operand_punct
['@'] = 1;
1785 microblaze_print_operand_punct
['.'] = 1;
1786 microblaze_print_operand_punct
['('] = 1;
1787 microblaze_print_operand_punct
[')'] = 1;
1788 microblaze_print_operand_punct
['['] = 1;
1789 microblaze_print_operand_punct
[']'] = 1;
1790 microblaze_print_operand_punct
['<'] = 1;
1791 microblaze_print_operand_punct
['>'] = 1;
1792 microblaze_print_operand_punct
['{'] = 1;
1793 microblaze_print_operand_punct
['}'] = 1;
1794 microblaze_print_operand_punct
['^'] = 1;
1795 microblaze_print_operand_punct
['$'] = 1;
1796 microblaze_print_operand_punct
['+'] = 1;
1798 /* Set up array to map GCC register number to debug register number.
1799 Ignore the special purpose register numbers. */
1801 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
1802 microblaze_dbx_regno
[i
] = -1;
1804 start
= GP_DBX_FIRST
- GP_REG_FIRST
;
1805 for (i
= GP_REG_FIRST
; i
<= GP_REG_LAST
; i
++)
1806 microblaze_dbx_regno
[i
] = i
+ start
;
1808 /* Set up array giving whether a given register can hold a given mode. */
1810 for (mode
= VOIDmode
;
1811 mode
!= MAX_MACHINE_MODE
; mode
= (enum machine_mode
) ((int) mode
+ 1))
1813 register int size
= GET_MODE_SIZE (mode
);
1815 for (regno
= 0; regno
< FIRST_PSEUDO_REGISTER
; regno
++)
1821 ok
= (ST_REG_P (regno
) || GP_REG_P (regno
));
1823 else if (GP_REG_P (regno
))
1824 ok
= ((regno
& 1) == 0 || size
<= UNITS_PER_WORD
);
1828 microblaze_hard_regno_mode_ok
[(int) mode
][regno
] = ok
;
1833 /* Return true if FUNC is an interrupt function as specified
1834 by the "interrupt_handler" attribute. */
1837 microblaze_interrupt_function_p (tree func
)
1841 if (TREE_CODE (func
) != FUNCTION_DECL
)
1844 a
= lookup_attribute ("interrupt_handler", DECL_ATTRIBUTES (func
));
1845 return a
!= NULL_TREE
;
1849 microblaze_fast_interrupt_function_p (tree func
)
1853 if (TREE_CODE (func
) != FUNCTION_DECL
)
1856 a
= lookup_attribute ("fast_interrupt", DECL_ATTRIBUTES (func
));
1857 return a
!= NULL_TREE
;
1860 /* Return true if FUNC is an interrupt function which uses
1861 normal return, indicated by the "save_volatiles" attribute. */
1864 microblaze_save_volatiles (tree func
)
1868 if (TREE_CODE (func
) != FUNCTION_DECL
)
1871 a
= lookup_attribute ("save_volatiles", DECL_ATTRIBUTES (func
));
1872 return a
!= NULL_TREE
;
1875 /* Return whether function is tagged with 'interrupt_handler'
1876 or 'fast_interrupt' attribute. Return true if function
1877 should use return from interrupt rather than normal
1880 microblaze_is_interrupt_variant (void)
1882 return (interrupt_handler
|| fast_interrupt
);
1885 /* Determine of register must be saved/restored in call. */
1887 microblaze_must_save_register (int regno
)
1889 if (pic_offset_table_rtx
&&
1890 (regno
== MB_ABI_PIC_ADDR_REGNUM
) && df_regs_ever_live_p (regno
))
1893 if (df_regs_ever_live_p (regno
) && !call_used_regs
[regno
])
1896 if (frame_pointer_needed
&& (regno
== HARD_FRAME_POINTER_REGNUM
))
1901 if (regno
== MB_ABI_SUB_RETURN_ADDR_REGNUM
)
1903 if ((microblaze_is_interrupt_variant () || save_volatiles
) &&
1904 (regno
>= 3 && regno
<= 12))
1908 if (microblaze_is_interrupt_variant ())
1910 if (df_regs_ever_live_p (regno
)
1911 || regno
== MB_ABI_MSR_SAVE_REG
1912 || (interrupt_handler
1913 && (regno
== MB_ABI_ASM_TEMP_REGNUM
1914 || regno
== MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM
)))
1920 if (df_regs_ever_live_p (regno
)
1921 || regno
== MB_ABI_ASM_TEMP_REGNUM
1922 || regno
== MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM
)
1929 /* Return the bytes needed to compute the frame pointer from the current
1932 MicroBlaze stack frames look like:
1936 Before call After call
1937 +-----------------------+ +-----------------------+
1939 mem. | local variables, | | local variables, |
1940 | callee saved and | | callee saved and |
1942 +-----------------------+ +-----------------------+
1943 | arguments for called | | arguments for called |
1944 | subroutines | | subroutines |
1945 | (optional) | | (optional) |
1946 +-----------------------+ +-----------------------+
1947 | Link register | | Link register |
1949 +-----------------------+ +-----------------------+
1951 | local variables, |
1952 | callee saved and |
1954 +-----------------------+
1955 | MSR (optional if, |
1956 | interrupt handler) |
1957 +-----------------------+
1959 | alloca allocations |
1961 +-----------------------+
1963 | arguments for called |
1967 +-----------------------+
1970 memory +-----------------------+
1974 static HOST_WIDE_INT
1975 compute_frame_size (HOST_WIDE_INT size
)
1978 HOST_WIDE_INT total_size
; /* # bytes that the entire frame takes up. */
1979 HOST_WIDE_INT var_size
; /* # bytes that local variables take up. */
1980 HOST_WIDE_INT args_size
; /* # bytes that outgoing arguments take up. */
1981 int link_debug_size
; /* # bytes for link register. */
1982 HOST_WIDE_INT gp_reg_size
; /* # bytes needed to store calle-saved gp regs. */
1983 long mask
; /* mask of saved gp registers. */
1986 microblaze_interrupt_function_p (current_function_decl
);
1988 microblaze_fast_interrupt_function_p (current_function_decl
);
1989 save_volatiles
= microblaze_save_volatiles (current_function_decl
);
1994 args_size
= crtl
->outgoing_args_size
;
1996 if ((args_size
== 0) && cfun
->calls_alloca
)
1997 args_size
= NUM_OF_ARGS
* UNITS_PER_WORD
;
1999 total_size
= var_size
+ args_size
;
2002 /* force setting GOT. */
2003 df_set_regs_ever_live (MB_ABI_PIC_ADDR_REGNUM
, true);
2005 /* Calculate space needed for gp registers. */
2006 for (regno
= GP_REG_FIRST
; regno
<= GP_REG_LAST
; regno
++)
2008 if (microblaze_must_save_register (regno
))
2011 if (regno
!= MB_ABI_SUB_RETURN_ADDR_REGNUM
)
2012 /* Don't account for link register. It is accounted specially below. */
2013 gp_reg_size
+= GET_MODE_SIZE (SImode
);
2015 mask
|= (1L << (regno
- GP_REG_FIRST
));
2019 total_size
+= gp_reg_size
;
2021 /* Add 4 bytes for MSR. */
2022 if (microblaze_is_interrupt_variant ())
2025 /* No space to be allocated for link register in leaf functions with no other
2026 stack requirements. */
2027 if (total_size
== 0 && crtl
->is_leaf
)
2028 link_debug_size
= 0;
2030 link_debug_size
= UNITS_PER_WORD
;
2032 total_size
+= link_debug_size
;
2034 /* Save other computed information. */
2035 current_frame_info
.total_size
= total_size
;
2036 current_frame_info
.var_size
= var_size
;
2037 current_frame_info
.args_size
= args_size
;
2038 current_frame_info
.gp_reg_size
= gp_reg_size
;
2039 current_frame_info
.mask
= mask
;
2040 current_frame_info
.initialized
= reload_completed
;
2041 current_frame_info
.num_gp
= gp_reg_size
/ UNITS_PER_WORD
;
2042 current_frame_info
.link_debug_size
= link_debug_size
;
2045 /* Offset from which to callee-save GP regs. */
2046 current_frame_info
.gp_offset
= (total_size
- gp_reg_size
);
2048 current_frame_info
.gp_offset
= 0;
2050 /* Ok, we're done. */
2054 /* Make sure that we're not trying to eliminate to the wrong hard frame
2058 microblaze_can_eliminate (const int from
, const int to
)
2060 return ((from
== RETURN_ADDRESS_POINTER_REGNUM
&& !leaf_function_p())
2061 || (to
== MB_ABI_SUB_RETURN_ADDR_REGNUM
&& leaf_function_p())
2062 || (from
!= RETURN_ADDRESS_POINTER_REGNUM
2063 && (to
== HARD_FRAME_POINTER_REGNUM
2064 || (to
== STACK_POINTER_REGNUM
&& !frame_pointer_needed
))));
2067 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
2068 pointer or argument pointer or the return address pointer. TO is either
2069 the stack pointer or hard frame pointer. */
2072 microblaze_initial_elimination_offset (int from
, int to
)
2074 HOST_WIDE_INT offset
;
2078 case FRAME_POINTER_REGNUM
:
2081 case ARG_POINTER_REGNUM
:
2082 if (to
== STACK_POINTER_REGNUM
|| to
== HARD_FRAME_POINTER_REGNUM
)
2083 offset
= compute_frame_size (get_frame_size ());
2087 case RETURN_ADDRESS_POINTER_REGNUM
:
2091 offset
= current_frame_info
.gp_offset
+
2092 ((UNITS_PER_WORD
- (POINTER_SIZE
/ BITS_PER_UNIT
)));
2100 /* Print operands using format code.
2102 The MicroBlaze specific codes are:
2104 'X' X is CONST_INT, prints 32 bits in hexadecimal format = "0x%08x",
2105 'x' X is CONST_INT, prints 16 bits in hexadecimal format = "0x%04x",
2106 'F' op is CONST_DOUBLE, print 32 bits in hex,
2107 'd' output integer constant in decimal,
2108 'z' if the operand is 0, use $0 instead of normal operand.
2109 'D' print second register of double-word register operand.
2110 'L' print low-order register of double-word register operand.
2111 'M' print high-order register of double-word register operand.
2112 'C' print part of opcode for a branch condition.
2113 'N' print part of opcode for a branch condition, inverted.
2114 'S' X is CODE_LABEL, print with prefix of "LS" (for embedded switch).
2115 'B' print 'z' for EQ, 'n' for NE
2116 'b' print 'n' for EQ, 'z' for NE
2117 'T' print 'f' for EQ, 't' for NE
2118 't' print 't' for EQ, 'f' for NE
2119 'm' Print 1<<operand.
2120 'i' Print 'i' if MEM operand has immediate value
2121 'o' Print operand address+4
2122 '?' Print 'd' if we use a branch with delay slot instead of normal branch.
2123 'h' Print high word of const_double (int or float) value as hex
2124 'j' Print low word of const_double (int or float) value as hex
2125 's' Print -1 if operand is negative, 0 if positive (sign extend)
2126 '@' Print the name of the temporary register (rMB_ABI_ASM_TEMP_REGNUM).
2127 '#' Print nop if the delay slot of a branch is not filled.
2131 print_operand (FILE * file
, rtx op
, int letter
)
2133 register enum rtx_code code
;
2135 if (PRINT_OPERAND_PUNCT_VALID_P (letter
))
2140 /* Conditionally add a 'd' to indicate filled delay slot. */
2141 if (final_sequence
!= NULL
)
2146 /* Conditionally add a nop in unfilled delay slot. */
2147 if (final_sequence
== NULL
)
2148 fputs ("nop\t\t# Unfilled delay slot\n", file
);
2152 fputs (reg_names
[GP_REG_FIRST
+ MB_ABI_ASM_TEMP_REGNUM
], file
);
2156 output_operand_lossage ("unknown punctuation '%c'", letter
);
2165 output_operand_lossage ("null pointer");
2169 code
= GET_CODE (op
);
2171 if (code
== SIGN_EXTEND
)
2172 op
= XEXP (op
, 0), code
= GET_CODE (op
);
2200 fatal_insn ("PRINT_OPERAND, invalid insn for %%C", op
);
2203 else if (letter
== 'N')
2229 fatal_insn ("PRINT_OPERAND, invalid insn for %%N", op
);
2232 else if (letter
== 'S')
2236 ASM_GENERATE_INTERNAL_LABEL (buffer
, "LS", CODE_LABEL_NUMBER (op
));
2237 assemble_name (file
, buffer
);
2240 /* Print 'i' for memory operands which have immediate values. */
2241 else if (letter
== 'i')
2245 struct microblaze_address_info info
;
2247 if (!microblaze_classify_address
2248 (&info
, XEXP (op
, 0), GET_MODE (op
), 1))
2249 fatal_insn ("insn contains an invalid address !", op
);
2254 case ADDRESS_CONST_INT
:
2255 case ADDRESS_SYMBOLIC
:
2256 case ADDRESS_GOTOFF
:
2260 case ADDRESS_REG_INDEX
:
2262 case ADDRESS_INVALID
:
2264 fatal_insn ("invalid address", op
);
2269 else if (code
== REG
|| code
== SUBREG
)
2271 register int regnum
;
2274 regnum
= REGNO (op
);
2276 regnum
= true_regnum (op
);
2278 if ((letter
== 'M' && !WORDS_BIG_ENDIAN
)
2279 || (letter
== 'L' && WORDS_BIG_ENDIAN
) || letter
== 'D')
2282 fprintf (file
, "%s", reg_names
[regnum
]);
2285 else if (code
== MEM
)
2288 rtx op4
= adjust_address (op
, GET_MODE (op
), 4);
2289 output_address (XEXP (op4
, 0));
2292 output_address (XEXP (op
, 0));
2294 else if (letter
== 'h' || letter
== 'j')
2297 if (code
== CONST_DOUBLE
)
2299 if (GET_MODE (op
) == DFmode
)
2301 REAL_VALUE_TYPE value
;
2302 REAL_VALUE_FROM_CONST_DOUBLE (value
, op
);
2303 REAL_VALUE_TO_TARGET_DOUBLE (value
, val
);
2307 val
[0] = CONST_DOUBLE_HIGH (op
);
2308 val
[1] = CONST_DOUBLE_LOW (op
);
2311 else if (code
== CONST_INT
)
2313 val
[0] = (INTVAL (op
) & 0xffffffff00000000LL
) >> 32;
2314 val
[1] = INTVAL (op
) & 0x00000000ffffffffLL
;
2315 if (val
[0] == 0 && val
[1] < 0)
2319 fprintf (file
, "0x%8.8lx", (letter
== 'h') ? val
[0] : val
[1]);
2321 else if (code
== CONST_DOUBLE
)
2325 unsigned long value_long
;
2326 REAL_VALUE_TYPE value
;
2327 REAL_VALUE_FROM_CONST_DOUBLE (value
, op
);
2328 REAL_VALUE_TO_TARGET_SINGLE (value
, value_long
);
2329 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, value_long
);
2334 real_to_decimal (s
, CONST_DOUBLE_REAL_VALUE (op
), sizeof (s
), 0, 1);
2339 else if (code
== UNSPEC
)
2341 print_operand_address (file
, op
);
2344 else if (letter
== 'x' && GET_CODE (op
) == CONST_INT
)
2345 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, 0xffff & INTVAL (op
));
2347 else if (letter
== 'X' && GET_CODE (op
) == CONST_INT
)
2348 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, INTVAL (op
));
2350 else if (letter
== 'd' && GET_CODE (op
) == CONST_INT
)
2351 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, (INTVAL (op
)));
2353 else if (letter
== 'z' && GET_CODE (op
) == CONST_INT
&& INTVAL (op
) == 0)
2354 fputs (reg_names
[GP_REG_FIRST
], file
);
2356 else if (letter
== 's' && GET_CODE (op
) == CONST_INT
)
2357 if (INTVAL (op
) < 0)
2362 else if (letter
== 'd' || letter
== 'x' || letter
== 'X' || letter
== 's')
2363 output_operand_lossage ("letter %c was found & insn was not CONST_INT", letter
);
2365 else if (letter
== 'B')
2366 fputs (code
== EQ
? "z" : "n", file
);
2367 else if (letter
== 'b')
2368 fputs (code
== EQ
? "n" : "z", file
);
2369 else if (letter
== 'T')
2370 fputs (code
== EQ
? "f" : "t", file
);
2371 else if (letter
== 't')
2372 fputs (code
== EQ
? "t" : "f", file
);
2374 else if (code
== CONST
2375 && ((GET_CODE (XEXP (op
, 0)) == REG
)
2376 || (GET_CODE (XEXP (op
, 0)) == UNSPEC
)))
2378 print_operand (file
, XEXP (op
, 0), letter
);
2380 else if (code
== CONST
2381 && (GET_CODE (XEXP (op
, 0)) == PLUS
)
2382 && (GET_CODE (XEXP (XEXP (op
, 0), 0)) == REG
)
2383 && (GET_CODE (XEXP (XEXP (op
, 0), 1)) == CONST
))
2385 print_operand_address (file
, XEXP (op
, 0));
2387 else if (letter
== 'm')
2388 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, (1L << INTVAL (op
)));
2390 output_addr_const (file
, op
);
2393 /* A C compound statement to output to stdio stream STREAM the
2394 assembler syntax for an instruction operand that is a memory
2395 reference whose address is ADDR. ADDR is an RTL expression.
2397 Possible address classifications and output formats are,
2399 ADDRESS_REG "%0, r0"
2401 ADDRESS_REG with non-zero "%0, <addr_const>"
2404 ADDRESS_REG_INDEX "rA, RB"
2405 (if rA is r0, rA and rB are swapped)
2407 ADDRESS_CONST_INT "r0, <addr_const>"
2409 ADDRESS_SYMBOLIC "rBase, <addr_const>"
2410 (rBase is a base register suitable for the
2415 print_operand_address (FILE * file
, rtx addr
)
2417 struct microblaze_address_info info
;
2418 enum microblaze_address_type type
;
2419 if (!microblaze_classify_address (&info
, addr
, GET_MODE (addr
), 1))
2420 fatal_insn ("insn contains an invalid address !", addr
);
2426 fprintf (file
, "%s,", reg_names
[REGNO (info
.regA
)]);
2427 output_addr_const (file
, info
.offset
);
2429 case ADDRESS_REG_INDEX
:
2430 if (REGNO (info
.regA
) == 0)
2431 /* Make rB == r0 instead of rA == r0. This helps reduce read port
2433 fprintf (file
, "%s,%s", reg_names
[REGNO (info
.regB
)],
2434 reg_names
[REGNO (info
.regA
)]);
2435 else if (REGNO (info
.regB
) != 0)
2436 /* This is a silly swap to help Dhrystone. */
2437 fprintf (file
, "%s,%s", reg_names
[REGNO (info
.regB
)],
2438 reg_names
[REGNO (info
.regA
)]);
2440 case ADDRESS_CONST_INT
:
2441 fprintf (file
, "%s,", reg_names
[REGNO (info
.regA
)]);
2442 output_addr_const (file
, info
.offset
);
2444 case ADDRESS_SYMBOLIC
:
2445 case ADDRESS_GOTOFF
:
2449 fprintf (file
, "%s,", reg_names
[REGNO (info
.regA
)]);
2450 output_addr_const (file
, info
.symbol
);
2451 if (type
== ADDRESS_GOTOFF
)
2453 fputs ("@GOT", file
);
2455 else if (type
== ADDRESS_PLT
)
2457 fputs ("@PLT", file
);
2459 else if (type
== ADDRESS_TLS
)
2461 switch (info
.tls_type
)
2464 fputs ("@TLSGD", file
);
2467 fputs ("@TLSLDM", file
);
2470 fputs ("@TLSDTPREL", file
);
2478 case ADDRESS_INVALID
:
2479 fatal_insn ("invalid address", addr
);
2484 /* Emit either a label, .comm, or .lcomm directive, and mark that the symbol
2485 is used, so that we don't emit an .extern for it in
2486 microblaze_asm_file_end. */
2489 microblaze_declare_object (FILE * stream
, const char *name
,
2490 const char *section
, const char *fmt
, int size
)
2493 fputs (section
, stream
);
2494 assemble_name (stream
, name
);
2495 fprintf (stream
, fmt
, size
);
2498 /* Common code to emit the insns (or to write the instructions to a file)
2499 to save/restore registers.
2501 Other parts of the code assume that MICROBLAZE_TEMP1_REGNUM (aka large_reg)
2502 is not modified within save_restore_insns. */
2504 #define BITSET_P(VALUE,BIT) (((VALUE) & (1L << (BIT))) != 0)
2506 /* Save or restore instructions based on whether this is the prologue or
2507 epilogue. prologue is 1 for the prologue. */
2509 save_restore_insns (int prologue
)
2511 rtx base_reg_rtx
, reg_rtx
, mem_rtx
, /* msr_rtx, */ isr_reg_rtx
=
2513 rtx isr_msr_rtx
= 0, insn
;
2514 long mask
= current_frame_info
.mask
;
2515 HOST_WIDE_INT gp_offset
;
2518 if (frame_pointer_needed
2519 && !BITSET_P (mask
, HARD_FRAME_POINTER_REGNUM
- GP_REG_FIRST
))
2525 /* Save registers starting from high to low. The debuggers prefer at least
2526 the return register be stored at func+4, and also it allows us not to
2527 need a nop in the epilog if at least one register is reloaded in
2528 addition to return address. */
2530 /* Pick which pointer to use as a base register. For small frames, just
2531 use the stack pointer. Otherwise, use a temporary register. Save 2
2532 cycles if the save area is near the end of a large frame, by reusing
2533 the constant created in the prologue/epilogue to adjust the stack
2536 gp_offset
= current_frame_info
.gp_offset
;
2538 gcc_assert (gp_offset
> 0);
2540 base_reg_rtx
= stack_pointer_rtx
;
2542 /* For interrupt_handlers, need to save/restore the MSR. */
2543 if (microblaze_is_interrupt_variant ())
2545 isr_mem_rtx
= gen_rtx_MEM (SImode
,
2546 gen_rtx_PLUS (Pmode
, base_reg_rtx
,
2547 GEN_INT (current_frame_info
.
2551 /* Do not optimize in flow analysis. */
2552 MEM_VOLATILE_P (isr_mem_rtx
) = 1;
2553 isr_reg_rtx
= gen_rtx_REG (SImode
, MB_ABI_MSR_SAVE_REG
);
2554 isr_msr_rtx
= gen_rtx_REG (SImode
, ST_REG
);
2557 if (microblaze_is_interrupt_variant () && !prologue
)
2559 emit_move_insn (isr_reg_rtx
, isr_mem_rtx
);
2560 emit_move_insn (isr_msr_rtx
, isr_reg_rtx
);
2561 /* Do not optimize in flow analysis. */
2562 emit_insn (gen_rtx_USE (SImode
, isr_reg_rtx
));
2563 emit_insn (gen_rtx_USE (SImode
, isr_msr_rtx
));
2566 for (regno
= GP_REG_FIRST
; regno
<= GP_REG_LAST
; regno
++)
2568 if (BITSET_P (mask
, regno
- GP_REG_FIRST
))
2570 if (regno
== MB_ABI_SUB_RETURN_ADDR_REGNUM
)
2571 /* Don't handle here. Already handled as the first register. */
2574 reg_rtx
= gen_rtx_REG (SImode
, regno
);
2575 insn
= gen_rtx_PLUS (Pmode
, base_reg_rtx
, GEN_INT (gp_offset
));
2576 mem_rtx
= gen_rtx_MEM (SImode
, insn
);
2577 if (microblaze_is_interrupt_variant () || save_volatiles
)
2578 /* Do not optimize in flow analysis. */
2579 MEM_VOLATILE_P (mem_rtx
) = 1;
2583 insn
= emit_move_insn (mem_rtx
, reg_rtx
);
2584 RTX_FRAME_RELATED_P (insn
) = 1;
2588 insn
= emit_move_insn (reg_rtx
, mem_rtx
);
2591 gp_offset
+= GET_MODE_SIZE (SImode
);
2595 if (microblaze_is_interrupt_variant () && prologue
)
2597 emit_move_insn (isr_reg_rtx
, isr_msr_rtx
);
2598 emit_move_insn (isr_mem_rtx
, isr_reg_rtx
);
2600 /* Do not optimize in flow analysis. */
2601 emit_insn (gen_rtx_USE (SImode
, isr_reg_rtx
));
2602 emit_insn (gen_rtx_USE (SImode
, isr_msr_rtx
));
2605 /* Done saving and restoring */
2609 /* Set up the stack and frame (if desired) for the function. */
2611 microblaze_function_prologue (FILE * file
, HOST_WIDE_INT size ATTRIBUTE_UNUSED
)
2614 long fsiz
= current_frame_info
.total_size
;
2616 /* Get the function name the same way that toplev.c does before calling
2617 assemble_start_function. This is needed so that the name used here
2618 exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */
2619 fnname
= XSTR (XEXP (DECL_RTL (current_function_decl
), 0), 0);
2620 if (!flag_inhibit_size_directive
)
2622 fputs ("\t.ent\t", file
);
2623 if (interrupt_handler
&& strcmp (INTERRUPT_HANDLER_NAME
, fnname
))
2624 fputs ("_interrupt_handler", file
);
2625 else if (fast_interrupt
&& strcmp (FAST_INTERRUPT_NAME
, fnname
))
2626 fputs ("_fast_interrupt", file
);
2628 assemble_name (file
, fnname
);
2630 if (!microblaze_is_interrupt_variant ())
2631 ASM_OUTPUT_TYPE_DIRECTIVE (file
, fnname
, "function");
2634 assemble_name (file
, fnname
);
2635 fputs (":\n", file
);
2637 if (interrupt_handler
&& strcmp (INTERRUPT_HANDLER_NAME
, fnname
))
2638 fputs ("_interrupt_handler:\n", file
);
2640 if (!flag_inhibit_size_directive
)
2642 /* .frame FRAMEREG, FRAMESIZE, RETREG. */
2644 "\t.frame\t%s,%ld,%s\t\t# vars= %ld, regs= %d, args= %d\n",
2645 (reg_names
[(frame_pointer_needed
)
2646 ? HARD_FRAME_POINTER_REGNUM
:
2647 STACK_POINTER_REGNUM
]), fsiz
,
2648 reg_names
[MB_ABI_SUB_RETURN_ADDR_REGNUM
+ GP_REG_FIRST
],
2649 current_frame_info
.var_size
, current_frame_info
.num_gp
,
2650 crtl
->outgoing_args_size
);
2651 fprintf (file
, "\t.mask\t0x%08lx\n", current_frame_info
.mask
);
2655 /* Output extra assembler code at the end of a prologue. */
2657 microblaze_function_end_prologue (FILE * file
)
2659 if (TARGET_STACK_CHECK
)
2661 fprintf (file
, "\t# Stack Check Stub -- Start.\n\t");
2662 fprintf (file
, "ori\tr18,r0,_stack_end\n\t");
2663 fprintf (file
, "cmpu\tr18,r1,r18\n\t");
2664 fprintf (file
, "bgei\tr18,_stack_overflow_exit\n\t");
2665 fprintf (file
, "# Stack Check Stub -- End.\n");
2669 /* Expand the prologue into a bunch of separate insns. */
2672 microblaze_expand_prologue (void)
2676 const char *arg_name
= 0;
2677 tree fndecl
= current_function_decl
;
2678 tree fntype
= TREE_TYPE (fndecl
);
2679 tree fnargs
= DECL_ARGUMENTS (fndecl
);
2684 CUMULATIVE_ARGS args_so_far_v
;
2685 cumulative_args_t args_so_far
;
2686 rtx mem_rtx
, reg_rtx
;
2688 /* If struct value address is treated as the first argument, make it so. */
2689 if (aggregate_value_p (DECL_RESULT (fndecl
), fntype
)
2690 && !cfun
->returns_pcc_struct
)
2692 tree type
= build_pointer_type (fntype
);
2693 tree function_result_decl
= build_decl (BUILTINS_LOCATION
, PARM_DECL
,
2696 DECL_ARG_TYPE (function_result_decl
) = type
;
2697 TREE_CHAIN (function_result_decl
) = fnargs
;
2698 fnargs
= function_result_decl
;
2701 /* Determine the last argument, and get its name. */
2703 INIT_CUMULATIVE_ARGS (args_so_far_v
, fntype
, NULL_RTX
, 0, 0);
2704 args_so_far
= pack_cumulative_args (&args_so_far_v
);
2705 regno
= GP_ARG_FIRST
;
2707 for (cur_arg
= fnargs
; cur_arg
!= 0; cur_arg
= next_arg
)
2709 tree passed_type
= DECL_ARG_TYPE (cur_arg
);
2710 enum machine_mode passed_mode
= TYPE_MODE (passed_type
);
2713 if (TREE_ADDRESSABLE (passed_type
))
2715 passed_type
= build_pointer_type (passed_type
);
2716 passed_mode
= Pmode
;
2719 entry_parm
= targetm
.calls
.function_arg (args_so_far
, passed_mode
,
2726 /* passed in a register, so will get homed automatically. */
2727 if (GET_MODE (entry_parm
) == BLKmode
)
2728 words
= (int_size_in_bytes (passed_type
) + 3) / 4;
2730 words
= (GET_MODE_SIZE (GET_MODE (entry_parm
)) + 3) / 4;
2732 regno
= REGNO (entry_parm
) + words
- 1;
2736 regno
= GP_ARG_LAST
+ 1;
2740 targetm
.calls
.function_arg_advance (args_so_far
, passed_mode
,
2743 next_arg
= TREE_CHAIN (cur_arg
);
2746 if (DECL_NAME (cur_arg
))
2747 arg_name
= IDENTIFIER_POINTER (DECL_NAME (cur_arg
));
2753 /* Split parallel insn into a sequence of insns. */
2755 next_arg_reg
= targetm
.calls
.function_arg (args_so_far
, VOIDmode
,
2756 void_type_node
, true);
2757 if (next_arg_reg
!= 0 && GET_CODE (next_arg_reg
) == PARALLEL
)
2759 rtvec adjust
= XVEC (next_arg_reg
, 0);
2760 int num
= GET_NUM_ELEM (adjust
);
2762 for (i
= 0; i
< num
; i
++)
2764 rtx pattern
= RTVEC_ELT (adjust
, i
);
2765 emit_insn (pattern
);
2769 fsiz
= compute_frame_size (get_frame_size ());
2771 if (flag_stack_usage
)
2772 current_function_static_stack_size
= fsiz
;
2774 /* If this function is a varargs function, store any registers that
2775 would normally hold arguments ($5 - $10) on the stack. */
2776 if (((TYPE_ARG_TYPES (fntype
) != 0
2777 && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype
)))
2780 && ((arg_name
[0] == '_'
2781 && strcmp (arg_name
, "__builtin_va_alist") == 0)
2782 || (arg_name
[0] == 'v'
2783 && strcmp (arg_name
, "va_alist") == 0)))))
2785 int offset
= (regno
- GP_ARG_FIRST
+ 1) * UNITS_PER_WORD
;
2786 rtx ptr
= stack_pointer_rtx
;
2788 /* If we are doing svr4-abi, sp has already been decremented by fsiz. */
2789 for (; regno
<= GP_ARG_LAST
; regno
++)
2792 ptr
= gen_rtx_PLUS (Pmode
, stack_pointer_rtx
, GEN_INT (offset
));
2793 emit_move_insn (gen_rtx_MEM (SImode
, ptr
),
2794 gen_rtx_REG (SImode
, regno
));
2796 offset
+= GET_MODE_SIZE (SImode
);
2803 rtx fsiz_rtx
= GEN_INT (fsiz
);
2806 insn
= emit_insn (gen_subsi3 (stack_pointer_rtx
, stack_pointer_rtx
,
2809 RTX_FRAME_RELATED_P (insn
) = 1;
2811 /* Handle SUB_RETURN_ADDR_REGNUM specially at first. */
2812 if (!crtl
->is_leaf
|| interrupt_handler
)
2814 mem_rtx
= gen_rtx_MEM (SImode
,
2815 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
2818 if (interrupt_handler
)
2819 /* Do not optimize in flow analysis. */
2820 MEM_VOLATILE_P (mem_rtx
) = 1;
2822 reg_rtx
= gen_rtx_REG (SImode
, MB_ABI_SUB_RETURN_ADDR_REGNUM
);
2823 insn
= emit_move_insn (mem_rtx
, reg_rtx
);
2824 RTX_FRAME_RELATED_P (insn
) = 1;
2827 /* _save_ registers for prologue. */
2828 save_restore_insns (1);
2830 if (frame_pointer_needed
)
2834 insn
= emit_insn (gen_movsi (hard_frame_pointer_rtx
,
2835 stack_pointer_rtx
));
2838 RTX_FRAME_RELATED_P (insn
) = 1;
2842 if ((flag_pic
== 2 || TLS_NEEDS_GOT
)
2843 && df_regs_ever_live_p (MB_ABI_PIC_ADDR_REGNUM
))
2845 SET_REGNO (pic_offset_table_rtx
, MB_ABI_PIC_ADDR_REGNUM
);
2846 emit_insn (gen_set_got (pic_offset_table_rtx
)); /* setting GOT. */
2849 /* If we are profiling, make sure no instructions are scheduled before
2850 the call to mcount. */
2853 emit_insn (gen_blockage ());
2856 /* Do necessary cleanup after a function to restore stack, frame, and regs. */
2858 #define RA_MASK ((long) 0x80000000) /* 1 << 31 */
2859 #define PIC_OFFSET_TABLE_MASK (1 << (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST))
2862 microblaze_function_epilogue (FILE * file ATTRIBUTE_UNUSED
,
2863 HOST_WIDE_INT size ATTRIBUTE_UNUSED
)
2867 /* Get the function name the same way that toplev.c does before calling
2868 assemble_start_function. This is needed so that the name used here
2869 exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */
2870 fnname
= XSTR (XEXP (DECL_RTL (current_function_decl
), 0), 0);
2872 if (!flag_inhibit_size_directive
)
2874 fputs ("\t.end\t", file
);
2875 if (interrupt_handler
)
2876 fputs ("_interrupt_handler", file
);
2878 assemble_name (file
, fnname
);
2882 /* Reset state info for each function. */
2883 current_frame_info
= zero_frame_info
;
2885 /* Restore the output file if optimizing the GP (optimizing the GP causes
2886 the text to be diverted to a tempfile, so that data decls come before
2887 references to the data). */
2890 /* Expand the epilogue into a bunch of separate insns. */
2893 microblaze_expand_epilogue (void)
2895 HOST_WIDE_INT fsiz
= current_frame_info
.total_size
;
2896 rtx fsiz_rtx
= GEN_INT (fsiz
);
2900 /* In case of interrupt handlers use addki instead of addi for changing the
2901 stack pointer value. */
2903 if (microblaze_can_use_return_insn ())
2905 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode
,
2907 MB_ABI_SUB_RETURN_ADDR_REGNUM
)));
2913 /* Restore SUB_RETURN_ADDR_REGNUM at first. This is to prevent the
2914 sequence of load-followed by a use (in rtsd) in every prologue. Saves
2915 a load-use stall cycle :) This is also important to handle alloca.
2916 (See comments for if (frame_pointer_needed) below. */
2918 if (!crtl
->is_leaf
|| interrupt_handler
)
2921 gen_rtx_MEM (SImode
,
2922 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
, const0_rtx
));
2923 if (interrupt_handler
)
2924 /* Do not optimize in flow analysis. */
2925 MEM_VOLATILE_P (mem_rtx
) = 1;
2926 reg_rtx
= gen_rtx_REG (SImode
, MB_ABI_SUB_RETURN_ADDR_REGNUM
);
2927 emit_move_insn (reg_rtx
, mem_rtx
);
2930 /* It is important that this is done after we restore the return address
2931 register (above). When alloca is used, we want to restore the
2932 sub-routine return address only from the current stack top and not
2933 from the frame pointer (which we restore below). (frame_pointer + 0)
2934 might have been over-written since alloca allocates memory on the
2936 if (frame_pointer_needed
)
2937 emit_insn (gen_movsi (stack_pointer_rtx
, hard_frame_pointer_rtx
));
2939 /* _restore_ registers for epilogue. */
2940 save_restore_insns (0);
2941 emit_insn (gen_blockage ());
2942 emit_insn (gen_addsi3 (stack_pointer_rtx
, stack_pointer_rtx
, fsiz_rtx
));
2945 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode
, GP_REG_FIRST
+
2946 MB_ABI_SUB_RETURN_ADDR_REGNUM
)));
2950 /* Return nonzero if this function is known to have a null epilogue.
2951 This allows the optimizer to omit jumps to jumps if no stack
2955 microblaze_can_use_return_insn (void)
2957 if (!reload_completed
)
2960 if (df_regs_ever_live_p (MB_ABI_SUB_RETURN_ADDR_REGNUM
) || profile_flag
)
2963 if (current_frame_info
.initialized
)
2964 return current_frame_info
.total_size
== 0;
2966 return compute_frame_size (get_frame_size ()) == 0;
2969 /* Implement TARGET_SECONDARY_RELOAD. */
2972 microblaze_secondary_reload (bool in_p ATTRIBUTE_UNUSED
, rtx x ATTRIBUTE_UNUSED
,
2973 reg_class_t rclass
, enum machine_mode mode ATTRIBUTE_UNUSED
,
2974 secondary_reload_info
*sri ATTRIBUTE_UNUSED
)
2976 if (rclass
== ST_REGS
)
2983 microblaze_globalize_label (FILE * stream
, const char *name
)
2985 fputs ("\t.globl\t", stream
);
2986 if (microblaze_is_interrupt_variant ())
2988 if (interrupt_handler
&& strcmp (name
, INTERRUPT_HANDLER_NAME
))
2989 fputs (INTERRUPT_HANDLER_NAME
, stream
);
2990 else if (fast_interrupt
&& strcmp (name
, FAST_INTERRUPT_NAME
))
2991 fputs (FAST_INTERRUPT_NAME
, stream
);
2992 fputs ("\n\t.globl\t", stream
);
2994 assemble_name (stream
, name
);
2995 fputs ("\n", stream
);
2998 /* Returns true if decl should be placed into a "small data" section. */
3000 microblaze_elf_in_small_data_p (const_tree decl
)
3004 if (!TARGET_XLGPOPT
)
3007 /* We want to merge strings, so we never consider them small data. */
3008 if (TREE_CODE (decl
) == STRING_CST
)
3011 /* Functions are never in the small data area. */
3012 if (TREE_CODE (decl
) == FUNCTION_DECL
)
3015 if (TREE_CODE (decl
) == VAR_DECL
&& DECL_SECTION_NAME (decl
))
3017 const char *section
= TREE_STRING_POINTER (DECL_SECTION_NAME (decl
));
3018 if (strcmp (section
, ".sdata") == 0
3019 || strcmp (section
, ".sdata2") == 0
3020 || strcmp (section
, ".sbss") == 0
3021 || strcmp (section
, ".sbss2") == 0)
3025 size
= int_size_in_bytes (TREE_TYPE (decl
));
3027 return (size
> 0 && size
<= microblaze_section_threshold
);
3032 microblaze_select_section (tree decl
, int reloc
, unsigned HOST_WIDE_INT align
)
3034 switch (categorize_decl_for_section (decl
, reloc
))
3036 case SECCAT_RODATA_MERGE_STR
:
3037 case SECCAT_RODATA_MERGE_STR_INIT
:
3038 /* MB binutils have various issues with mergeable string sections and
3039 relaxation/relocation. Currently, turning mergeable sections
3040 into regular readonly sections. */
3042 return readonly_data_section
;
3044 return default_elf_select_section (decl
, reloc
, align
);
3049 Encode info about sections into the RTL based on a symbol's declaration.
3050 The default definition of this hook, default_encode_section_info in
3051 `varasm.c', sets a number of commonly-useful bits in SYMBOL_REF_FLAGS. */
3054 microblaze_encode_section_info (tree decl
, rtx rtl
, int first
)
3056 default_encode_section_info (decl
, rtl
, first
);
3060 expand_pic_symbol_ref (enum machine_mode mode ATTRIBUTE_UNUSED
, rtx op
)
3063 result
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, op
), UNSPEC_GOTOFF
);
3064 result
= gen_rtx_CONST (Pmode
, result
);
3065 result
= gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
, result
);
3066 result
= gen_const_mem (Pmode
, result
);
3071 microblaze_expand_move (enum machine_mode mode
, rtx operands
[])
3078 if (!register_operand (op0
, SImode
)
3079 && !register_operand (op1
, SImode
)
3080 && (GET_CODE (op1
) != CONST_INT
|| INTVAL (op1
) != 0))
3082 rtx temp
= force_reg (SImode
, op1
);
3083 emit_move_insn (op0
, temp
);
3086 /* If operands[1] is a constant address invalid for pic, then we need to
3087 handle it just like LEGITIMIZE_ADDRESS does. */
3088 if (GET_CODE (op1
) == SYMBOL_REF
|| GET_CODE (op1
) == LABEL_REF
)
3091 if (microblaze_tls_symbol_p(op1
))
3093 result
= microblaze_legitimize_tls_address (op1
, NULL_RTX
);
3094 emit_move_insn (op0
, result
);
3099 if (reload_in_progress
)
3100 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
3101 result
= expand_pic_symbol_ref (mode
, op1
);
3102 emit_move_insn (op0
, result
);
3106 /* Handle Case of (const (plus symbol const_int)). */
3107 if (GET_CODE (op1
) == CONST
&& GET_CODE (XEXP (op1
,0)) == PLUS
)
3111 p0
= XEXP (XEXP (op1
, 0), 0);
3112 p1
= XEXP (XEXP (op1
, 0), 1);
3114 if ((GET_CODE (p1
) == CONST_INT
)
3115 && ((GET_CODE (p0
) == UNSPEC
)
3116 || ((GET_CODE (p0
) == SYMBOL_REF
|| GET_CODE (p0
) == LABEL_REF
)
3117 && (flag_pic
== 2 || microblaze_tls_symbol_p (p0
)
3118 || !SMALL_INT (p1
)))))
3120 rtx temp
= force_reg (SImode
, p0
);
3123 if (flag_pic
&& reload_in_progress
)
3124 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
3125 emit_move_insn (op0
, gen_rtx_PLUS (SImode
, temp
, temp2
));
3132 /* Expand shift operations. */
3134 microblaze_expand_shift (rtx operands
[])
3136 gcc_assert ((GET_CODE (operands
[2]) == CONST_INT
)
3137 || (GET_CODE (operands
[2]) == REG
)
3138 || (GET_CODE (operands
[2]) == SUBREG
));
3140 /* Shift by one -- generate pattern. */
3141 if ((GET_CODE (operands
[2]) == CONST_INT
) && (INTVAL (operands
[2]) == 1))
3144 /* Have barrel shifter and shift > 1: use it. */
3145 if (TARGET_BARREL_SHIFT
)
3148 gcc_assert ((GET_CODE (operands
[0]) == REG
)
3149 || (GET_CODE (operands
[0]) == SUBREG
)
3150 || (GET_CODE (operands
[1]) == REG
)
3151 || (GET_CODE (operands
[1]) == SUBREG
));
3153 /* Shift by zero -- copy regs if necessary. */
3154 if ((GET_CODE (operands
[2]) == CONST_INT
) && (INTVAL (operands
[2]) == 0))
3156 if (REGNO (operands
[0]) != REGNO (operands
[1]))
3157 emit_insn (gen_movsi (operands
[0], operands
[1]));
3164 /* Return an RTX indicating where the return address to the
3165 calling function can be found. */
3167 microblaze_return_addr (int count
, rtx frame ATTRIBUTE_UNUSED
)
3172 return gen_rtx_PLUS (Pmode
,
3173 get_hard_reg_initial_val (Pmode
,
3174 MB_ABI_SUB_RETURN_ADDR_REGNUM
),
3178 /* Queue an .ident string in the queue of top-level asm statements.
3179 If the string size is below the threshold, put it into .sdata2.
3180 If the front-end is done, we must be being called from toplev.c.
3181 In that case, do nothing. */
3183 microblaze_asm_output_ident (const char *string
)
3185 const char *section_asm_op
;
3189 if (cgraph_state
!= CGRAPH_STATE_PARSING
)
3192 size
= strlen (string
) + 1;
3193 if (size
<= microblaze_section_threshold
)
3194 section_asm_op
= SDATA2_SECTION_ASM_OP
;
3196 section_asm_op
= READONLY_DATA_SECTION_ASM_OP
;
3198 buf
= ACONCAT ((section_asm_op
, "\n\t.ascii \"", string
, "\\0\"\n", NULL
));
3199 add_asm_node (build_string (strlen (buf
), buf
));
3203 microblaze_elf_asm_init_sections (void)
3206 = get_unnamed_section (SECTION_WRITE
, output_section_asm_op
,
3207 SDATA2_SECTION_ASM_OP
);
3210 /* Generate assembler code for constant parts of a trampoline. */
3213 microblaze_asm_trampoline_template (FILE *f
)
3215 fprintf (f
, "\tmfs r18, rpc\n");
3216 fprintf (f
, "\tlwi r3, r18, 16\n");
3217 fprintf (f
, "\tlwi r18, r18, 20\n");
3218 fprintf (f
, "\tbra r18\n");
3219 /* fprintf (f, "\t.word\t0x00000000\t\t# <function address>\n"); */
3220 /* fprintf (f, "\t.word\t0x00000000\t\t# <static chain value>\n"); */
3223 /* Implement TARGET_TRAMPOLINE_INIT. */
3226 microblaze_trampoline_init (rtx m_tramp
, tree fndecl
, rtx chain_value
)
3228 rtx fnaddr
= XEXP (DECL_RTL (fndecl
), 0);
3231 emit_block_move (m_tramp
, assemble_trampoline_template (),
3232 GEN_INT (6*UNITS_PER_WORD
), BLOCK_OP_NORMAL
);
3234 mem
= adjust_address (m_tramp
, SImode
, 16);
3235 emit_move_insn (mem
, chain_value
);
3236 mem
= adjust_address (m_tramp
, SImode
, 20);
3237 emit_move_insn (mem
, fnaddr
);
3240 /* Emit instruction to perform compare.
3241 cmp is (compare_op op0 op1). */
3243 microblaze_emit_compare (enum machine_mode mode
, rtx cmp
, enum rtx_code
*cmp_code
)
3245 rtx cmp_op0
= XEXP (cmp
, 0);
3246 rtx cmp_op1
= XEXP (cmp
, 1);
3247 rtx comp_reg
= gen_reg_rtx (SImode
);
3248 enum rtx_code code
= *cmp_code
;
3250 gcc_assert ((GET_CODE (cmp_op0
) == REG
) || (GET_CODE (cmp_op0
) == SUBREG
));
3252 /* If comparing against zero, just test source reg. */
3253 if (cmp_op1
== const0_rtx
)
3256 if (code
== EQ
|| code
== NE
)
3258 /* Use xor for equal/not-equal comparison. */
3259 emit_insn (gen_xorsi3 (comp_reg
, cmp_op0
, cmp_op1
));
3261 else if (code
== GT
|| code
== GTU
|| code
== LE
|| code
== LEU
)
3263 /* MicroBlaze compare is not symmetrical. */
3264 /* Swap argument order. */
3265 cmp_op1
= force_reg (mode
, cmp_op1
);
3266 if (code
== GT
|| code
== LE
)
3267 emit_insn (gen_signed_compare (comp_reg
, cmp_op0
, cmp_op1
));
3269 emit_insn (gen_unsigned_compare (comp_reg
, cmp_op0
, cmp_op1
));
3270 /* Translate test condition. */
3271 *cmp_code
= swap_condition (code
);
3273 else /* if (code == GE || code == GEU || code == LT || code == LTU) */
3275 cmp_op1
= force_reg (mode
, cmp_op1
);
3276 if (code
== GE
|| code
== LT
)
3277 emit_insn (gen_signed_compare (comp_reg
, cmp_op1
, cmp_op0
));
3279 emit_insn (gen_unsigned_compare (comp_reg
, cmp_op1
, cmp_op0
));
3285 /* Generate conditional branch -- first, generate test condition,
3286 second, generate correct branch instruction. */
3289 microblaze_expand_conditional_branch (enum machine_mode mode
, rtx operands
[])
3291 enum rtx_code code
= GET_CODE (operands
[0]);
3295 comp
= microblaze_emit_compare (mode
, operands
[0], &code
);
3296 condition
= gen_rtx_fmt_ee (signed_condition (code
), SImode
, comp
, const0_rtx
);
3297 emit_jump_insn (gen_condjump (condition
, operands
[3]));
3301 microblaze_expand_conditional_branch_sf (rtx operands
[])
3304 rtx cmp_op0
= XEXP (operands
[0], 0);
3305 rtx cmp_op1
= XEXP (operands
[0], 1);
3306 rtx comp_reg
= gen_reg_rtx (SImode
);
3308 emit_insn (gen_cstoresf4 (comp_reg
, operands
[0], cmp_op0
, cmp_op1
));
3309 condition
= gen_rtx_NE (SImode
, comp_reg
, const0_rtx
);
3310 emit_jump_insn (gen_condjump (condition
, operands
[3]));
3313 /* Implement TARGET_FRAME_POINTER_REQUIRED. */
3316 microblaze_frame_pointer_required (void)
3318 /* If the function contains dynamic stack allocations, we need to
3319 use the frame pointer to access the static parts of the frame. */
3320 if (cfun
->calls_alloca
)
3326 microblaze_expand_divide (rtx operands
[])
3328 /* Table lookup software divides. Works for all (nr/dr) where (0 <= nr,dr <= 15). */
3330 rtx regt1
= gen_reg_rtx (SImode
);
3331 rtx reg18
= gen_rtx_REG (SImode
, R_TMP
);
3332 rtx regqi
= gen_reg_rtx (QImode
);
3333 rtx div_label
= gen_label_rtx ();
3334 rtx div_end_label
= gen_label_rtx ();
3335 rtx div_table_rtx
= gen_rtx_SYMBOL_REF (QImode
,"_divsi3_table");
3338 rtx jump
, cjump
, insn
;
3340 insn
= emit_insn (gen_iorsi3 (regt1
, operands
[1], operands
[2]));
3341 cjump
= emit_jump_insn_after (gen_cbranchsi4 (
3342 gen_rtx_GTU (SImode
, regt1
, GEN_INT (15)),
3343 regt1
, GEN_INT (15), div_label
), insn
);
3344 LABEL_NUSES (div_label
) = 1;
3345 JUMP_LABEL (cjump
) = div_label
;
3346 emit_insn (gen_rtx_CLOBBER (SImode
, reg18
));
3348 emit_insn (gen_ashlsi3_bshift (regt1
, operands
[1], GEN_INT(4)));
3349 emit_insn (gen_addsi3 (regt1
, regt1
, operands
[2]));
3350 mem_rtx
= gen_rtx_MEM (QImode
,
3351 gen_rtx_PLUS (Pmode
, regt1
, div_table_rtx
));
3353 insn
= emit_insn (gen_movqi (regqi
, mem_rtx
));
3354 insn
= emit_insn (gen_movsi (operands
[0], gen_rtx_SUBREG (SImode
, regqi
, 0)));
3355 jump
= emit_jump_insn_after (gen_jump (div_end_label
), insn
);
3356 JUMP_LABEL (jump
) = div_end_label
;
3357 LABEL_NUSES (div_end_label
) = 1;
3360 emit_label (div_label
);
3361 ret
= emit_library_call_value (gen_rtx_SYMBOL_REF (Pmode
, "__divsi3"),
3362 operands
[0], LCT_NORMAL
,
3363 GET_MODE (operands
[0]), 2, operands
[1],
3364 GET_MODE (operands
[1]), operands
[2],
3365 GET_MODE (operands
[2]));
3366 if (ret
!= operands
[0])
3367 emit_move_insn (operands
[0], ret
);
3369 emit_label (div_end_label
);
3370 emit_insn (gen_blockage ());
3373 /* Implement TARGET_FUNCTION_VALUE. */
3375 microblaze_function_value (const_tree valtype
,
3376 const_tree func ATTRIBUTE_UNUSED
,
3377 bool outgoing ATTRIBUTE_UNUSED
)
3379 return LIBCALL_VALUE (TYPE_MODE (valtype
));
3382 /* Implement TARGET_SCHED_ADJUST_COST. */
3384 microblaze_adjust_cost (rtx insn ATTRIBUTE_UNUSED
, rtx link
,
3385 rtx dep ATTRIBUTE_UNUSED
, int cost
)
3387 if (REG_NOTE_KIND (link
) == REG_DEP_OUTPUT
)
3389 if (REG_NOTE_KIND (link
) != 0)
3394 /* Implement TARGET_LEGITIMATE_CONSTANT_P.
3396 At present, GAS doesn't understand li.[sd], so don't allow it
3397 to be generated at present. */
3399 microblaze_legitimate_constant_p (enum machine_mode mode ATTRIBUTE_UNUSED
, rtx x
)
3402 if (microblaze_cannot_force_const_mem(mode
, x
))
3405 if (GET_CODE (x
) == CONST_DOUBLE
)
3407 return microblaze_const_double_ok (x
, GET_MODE (x
));
3410 /* Handle Case of (const (plus unspec const_int)). */
3411 if (GET_CODE (x
) == CONST
&& GET_CODE (XEXP (x
,0)) == PLUS
)
3415 p0
= XEXP (XEXP (x
, 0), 0);
3416 p1
= XEXP (XEXP (x
, 0), 1);
3418 if (GET_CODE(p1
) == CONST_INT
)
3420 /* Const offset from UNSPEC is not supported. */
3421 if ((GET_CODE (p0
) == UNSPEC
))
3424 if ((GET_CODE (p0
) == SYMBOL_REF
|| GET_CODE (p0
) == LABEL_REF
)
3425 && (microblaze_tls_symbol_p (p0
) || !SMALL_INT (p1
)))
3434 #undef TARGET_ENCODE_SECTION_INFO
3435 #define TARGET_ENCODE_SECTION_INFO microblaze_encode_section_info
3437 #undef TARGET_ASM_GLOBALIZE_LABEL
3438 #define TARGET_ASM_GLOBALIZE_LABEL microblaze_globalize_label
3440 #undef TARGET_ASM_FUNCTION_PROLOGUE
3441 #define TARGET_ASM_FUNCTION_PROLOGUE microblaze_function_prologue
3443 #undef TARGET_ASM_FUNCTION_EPILOGUE
3444 #define TARGET_ASM_FUNCTION_EPILOGUE microblaze_function_epilogue
3446 #undef TARGET_RTX_COSTS
3447 #define TARGET_RTX_COSTS microblaze_rtx_costs
3449 #undef TARGET_CANNOT_FORCE_CONST_MEM
3450 #define TARGET_CANNOT_FORCE_CONST_MEM microblaze_cannot_force_const_mem
3452 #undef TARGET_ADDRESS_COST
3453 #define TARGET_ADDRESS_COST microblaze_address_cost
3455 #undef TARGET_ATTRIBUTE_TABLE
3456 #define TARGET_ATTRIBUTE_TABLE microblaze_attribute_table
3458 #undef TARGET_IN_SMALL_DATA_P
3459 #define TARGET_IN_SMALL_DATA_P microblaze_elf_in_small_data_p
3461 #undef TARGET_ASM_SELECT_SECTION
3462 #define TARGET_ASM_SELECT_SECTION microblaze_select_section
3464 #undef TARGET_HAVE_SRODATA_SECTION
3465 #define TARGET_HAVE_SRODATA_SECTION true
3467 #undef TARGET_ASM_FUNCTION_END_PROLOGUE
3468 #define TARGET_ASM_FUNCTION_END_PROLOGUE \
3469 microblaze_function_end_prologue
3471 #undef TARGET_ARG_PARTIAL_BYTES
3472 #define TARGET_ARG_PARTIAL_BYTES function_arg_partial_bytes
3474 #undef TARGET_FUNCTION_ARG
3475 #define TARGET_FUNCTION_ARG microblaze_function_arg
3477 #undef TARGET_FUNCTION_ARG_ADVANCE
3478 #define TARGET_FUNCTION_ARG_ADVANCE microblaze_function_arg_advance
3480 #undef TARGET_CAN_ELIMINATE
3481 #define TARGET_CAN_ELIMINATE microblaze_can_eliminate
3483 #undef TARGET_LEGITIMIZE_ADDRESS
3484 #define TARGET_LEGITIMIZE_ADDRESS microblaze_legitimize_address
3486 #undef TARGET_LEGITIMATE_ADDRESS_P
3487 #define TARGET_LEGITIMATE_ADDRESS_P microblaze_legitimate_address_p
3489 #undef TARGET_FRAME_POINTER_REQUIRED
3490 #define TARGET_FRAME_POINTER_REQUIRED microblaze_frame_pointer_required
3492 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
3493 #define TARGET_ASM_TRAMPOLINE_TEMPLATE microblaze_asm_trampoline_template
3495 #undef TARGET_TRAMPOLINE_INIT
3496 #define TARGET_TRAMPOLINE_INIT microblaze_trampoline_init
3498 #undef TARGET_PROMOTE_FUNCTION_MODE
3499 #define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
3501 #undef TARGET_FUNCTION_VALUE
3502 #define TARGET_FUNCTION_VALUE microblaze_function_value
3504 #undef TARGET_SECONDARY_RELOAD
3505 #define TARGET_SECONDARY_RELOAD microblaze_secondary_reload
3507 #undef TARGET_SCHED_ADJUST_COST
3508 #define TARGET_SCHED_ADJUST_COST microblaze_adjust_cost
3510 #undef TARGET_ASM_INIT_SECTIONS
3511 #define TARGET_ASM_INIT_SECTIONS microblaze_elf_asm_init_sections
3513 #undef TARGET_OPTION_OVERRIDE
3514 #define TARGET_OPTION_OVERRIDE microblaze_option_override
3516 #undef TARGET_LEGITIMATE_CONSTANT_P
3517 #define TARGET_LEGITIMATE_CONSTANT_P microblaze_legitimate_constant_p
3519 struct gcc_target targetm
= TARGET_INITIALIZER
;
3521 #include "gt-microblaze.h"