1 /* Subroutines used for code generation on Xilinx MicroBlaze.
2 Copyright (C) 2009-2018 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/>. */
22 #define IN_TARGET_CODE 1
26 #include "coretypes.h"
31 #include "stringpool.h"
41 #include "diagnostic-core.h"
43 #include "stor-layout.h"
52 #include "insn-addr.h"
55 /* This file should be included last. */
56 #include "target-def.h"
58 #define MICROBLAZE_VERSION_COMPARE(VA,VB) strcasecmp (VA, VB)
60 /* Classifies an address.
67 A natural register or a register + const_int offset address.
68 The register satisfies microblaze_valid_base_register_p and the
69 offset is a const_arith_operand.
73 A natural register offset by the index contained in an index register. The base
74 register satisfies microblaze_valid_base_register_p and the index register
75 satisfies microblaze_valid_index_register_p
79 A signed 16/32-bit constant address.
83 A constant symbolic address or a (register + symbol). */
85 enum microblaze_address_type
102 enum microblaze_symbol_type
108 /* TLS Address Type. */
117 /* Classification of a MicroBlaze address. */
118 struct microblaze_address_info
120 enum microblaze_address_type type
;
121 rtx regA
; /* Contains valid values on ADDRESS_REG, ADDRESS_REG_INDEX,
123 rtx regB
; /* Contains valid values on ADDRESS_REG_INDEX. */
124 rtx offset
; /* Contains valid values on ADDRESS_CONST_INT and ADDRESS_REG. */
125 rtx symbol
; /* Contains valid values on ADDRESS_SYMBOLIC. */
126 enum microblaze_symbol_type symbol_type
;
127 enum tls_reloc tls_type
;
130 /* Structure to be filled in by compute_frame_size with register
131 save masks, and offsets for the current function. */
133 struct GTY(()) microblaze_frame_info
{
134 long total_size
; /* # bytes that the entire frame takes up. */
135 long var_size
; /* # bytes that variables take up. */
136 long args_size
; /* # bytes that outgoing arguments take up. */
137 int link_debug_size
; /* # bytes for the link reg and back pointer. */
138 int gp_reg_size
; /* # bytes needed to store gp regs. */
139 long gp_offset
; /* offset from new sp to store gp registers. */
140 long mask
; /* mask of saved gp registers. */
141 int initialized
; /* != 0 if frame size already calculated. */
142 int num_gp
; /* number of gp registers saved. */
143 long insns_len
; /* length of insns. */
144 int alloc_stack
; /* Flag to indicate if the current function
145 must not create stack space. (As an optimization). */
148 /* Global variables for machine-dependent things. */
150 /* Toggle which pipleline interface to use. */
151 static GTY(()) int microblaze_sched_use_dfa
= 0;
153 /* Threshold for data being put into the small data/bss area, instead
154 of the normal data area (references to the small data/bss area take
155 1 instruction, and use the global pointer, references to the normal
156 data area takes 2 instructions). */
157 int microblaze_section_threshold
= -1;
159 /* Prevent scheduling potentially exception causing instructions in
160 delay slots. -mcpu=v3.00.a or v4.00.a turns this on. */
161 int microblaze_no_unsafe_delay
;
163 /* Set to one if the targeted core has the CLZ insn. */
164 int microblaze_has_clz
= 0;
166 /* Which CPU pipeline do we use. We haven't really standardized on a CPU
167 version having only a particular type of pipeline. There can still be
168 options on the CPU to scale pipeline features up or down. :(
169 Bad Presentation (??), so we let the MD file rely on the value of
170 this variable instead Making PIPE_5 the default. It should be backward
171 optimal with PIPE_3 MicroBlazes. */
172 enum pipeline_type microblaze_pipe
= MICROBLAZE_PIPE_5
;
174 /* High and low marks for floating point values which we will accept
175 as legitimate constants for TARGET_LEGITIMATE_CONSTANT_P. These are
176 initialized in override_options. */
177 REAL_VALUE_TYPE dfhigh
, dflow
, sfhigh
, sflow
;
179 /* Array giving truth value on whether or not a given hard register
180 can support a given mode. */
181 static char microblaze_hard_regno_mode_ok_p
[(int)MAX_MACHINE_MODE
]
182 [FIRST_PSEUDO_REGISTER
];
184 /* Current frame information calculated by compute_frame_size. */
185 struct microblaze_frame_info current_frame_info
;
187 /* Zero structure to initialize current_frame_info. */
188 struct microblaze_frame_info zero_frame_info
;
190 /* List of all MICROBLAZE punctuation characters used by print_operand. */
191 char microblaze_print_operand_punct
[256];
193 /* Map GCC register number to debugger register number. */
194 int microblaze_dbx_regno
[FIRST_PSEUDO_REGISTER
];
196 /* Map hard register number to register class. */
197 enum reg_class microblaze_regno_to_class
[] =
199 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
200 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
201 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
202 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
203 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
204 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
205 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
206 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
207 ST_REGS
, GR_REGS
, GR_REGS
, GR_REGS
210 /* MicroBlaze specific machine attributes.
211 interrupt_handler - Interrupt handler attribute to add interrupt prologue
212 and epilogue and use appropriate interrupt return.
213 save_volatiles - Similar to interrupt handler, but use normal return. */
214 int interrupt_handler
;
219 const struct attribute_spec microblaze_attribute_table
[] = {
220 /* name min_len, max_len, decl_req, type_req, fn_type_req,
221 affects_type_identity, handler, exclude */
222 {"interrupt_handler", 0, 0, true, false, false, false, NULL
, NULL
},
223 {"break_handler", 0, 0, true, false, false, false, NULL
, NULL
},
224 {"fast_interrupt", 0, 0, true, false, false, false, NULL
, NULL
},
225 {"save_volatiles", 0, 0, true, false, false, false, NULL
, NULL
},
226 { NULL
, 0, 0, false, false, false, false, NULL
, NULL
}
229 static int microblaze_interrupt_function_p (tree
);
231 static void microblaze_elf_asm_constructor (rtx
, int) ATTRIBUTE_UNUSED
;
232 static void microblaze_elf_asm_destructor (rtx
, int) ATTRIBUTE_UNUSED
;
234 section
*sdata2_section
;
237 #undef TARGET_HAVE_TLS
238 #define TARGET_HAVE_TLS true
241 /* Return truth value if a CONST_DOUBLE is ok to be a legitimate constant. */
243 microblaze_const_double_ok (rtx op
, machine_mode mode
)
247 if (GET_CODE (op
) != CONST_DOUBLE
)
250 if (GET_MODE (op
) == VOIDmode
)
253 if (mode
!= SFmode
&& mode
!= DFmode
)
256 if (op
== CONST0_RTX (mode
))
259 d
= *CONST_DOUBLE_REAL_VALUE (op
);
261 if (REAL_VALUE_ISNAN (d
))
264 if (REAL_VALUE_NEGATIVE (d
))
265 d
= real_value_negate (&d
);
269 if (real_less (&d
, &dfhigh
) && real_less (&dflow
, &d
))
274 if (real_less (&d
, &sfhigh
) && real_less (&sflow
, &d
))
281 /* Return truth value if a memory operand fits in a single instruction
282 (ie, register + small offset) or (register + register). */
285 simple_memory_operand (rtx op
, machine_mode mode ATTRIBUTE_UNUSED
)
287 rtx addr
, plus0
, plus1
;
289 /* Eliminate non-memory operations. */
290 if (GET_CODE (op
) != MEM
)
293 /* dword operations really put out 2 instructions, so eliminate them. */
294 /* ??? This isn't strictly correct. It is OK to accept multiword modes
295 here, since the length attributes are being set correctly, but only
296 if the address is offsettable. */
297 if (GET_MODE_SIZE (GET_MODE (op
)) > UNITS_PER_WORD
)
301 /* Decode the address now. */
303 switch (GET_CODE (addr
))
310 plus0
= XEXP (addr
, 0);
311 plus1
= XEXP (addr
, 1);
313 if (GET_CODE (plus0
) != REG
)
316 if (GET_CODE (plus0
) == REG
&& GET_CODE (plus1
) == CONST_INT
317 && SMALL_INT (plus1
))
321 else if (GET_CODE (plus1
) == REG
&& GET_CODE (plus0
) == CONST_INT
)
325 else if (GET_CODE (plus0
) == REG
&& GET_CODE (plus1
) == REG
)
342 /* Return nonzero for a memory address that can be used to load or store
346 double_memory_operand (rtx op
, machine_mode mode
)
350 if (GET_CODE (op
) != MEM
|| !memory_operand (op
, mode
))
352 /* During reload, we accept a pseudo register if it has an
353 appropriate memory address. If we don't do this, we will
354 wind up reloading into a register, and then reloading that
355 register from memory, when we could just reload directly from
357 if (reload_in_progress
358 && GET_CODE (op
) == REG
359 && REGNO (op
) >= FIRST_PSEUDO_REGISTER
360 && reg_renumber
[REGNO (op
)] < 0
361 && reg_equiv_mem (REGNO (op
)) != 0
362 && double_memory_operand (reg_equiv_mem (REGNO (op
)), mode
))
367 /* Make sure that 4 added to the address is a valid memory address.
368 This essentially just checks for overflow in an added constant. */
372 if (CONSTANT_ADDRESS_P (addr
))
375 return memory_address_p ((GET_MODE_CLASS (mode
) == MODE_INT
376 ? E_SImode
: E_SFmode
),
377 plus_constant (Pmode
, addr
, 4));
380 /* Implement REG_OK_FOR_BASE_P -and- REG_OK_FOR_INDEX_P. */
382 microblaze_regno_ok_for_base_p (int regno
, int strict
)
384 if (regno
>= FIRST_PSEUDO_REGISTER
)
388 regno
= reg_renumber
[regno
];
391 /* These fake registers will be eliminated to either the stack or
392 hard frame pointer, both of which are usually valid base registers.
393 Reload deals with the cases where the eliminated form isn't valid. */
394 if (regno
== ARG_POINTER_REGNUM
|| regno
== FRAME_POINTER_REGNUM
)
397 return GP_REG_P (regno
);
400 /* Return true if X is a valid base register for the given mode.
401 Allow only hard registers if STRICT. */
404 microblaze_valid_base_register_p (rtx x
,
405 machine_mode mode ATTRIBUTE_UNUSED
,
408 if (!strict
&& GET_CODE (x
) == SUBREG
)
411 return (GET_CODE (x
) == REG
412 && microblaze_regno_ok_for_base_p (REGNO (x
), strict
));
415 /* Build the SYMBOL_REF for __tls_get_addr. */
417 static GTY(()) rtx tls_get_addr_libfunc
;
420 get_tls_get_addr (void)
422 if (!tls_get_addr_libfunc
)
423 tls_get_addr_libfunc
= init_one_libfunc ("__tls_get_addr");
424 return tls_get_addr_libfunc
;
427 /* Return TRUE if X is a thread-local symbol. */
429 microblaze_tls_symbol_p (rtx x
)
431 if (!TARGET_HAVE_TLS
)
434 if (GET_CODE (x
) != SYMBOL_REF
)
437 return SYMBOL_REF_TLS_MODEL (x
) != 0;
440 /* Return TRUE if X contains any TLS symbol references. */
443 microblaze_tls_referenced_p (rtx x
)
445 if (!TARGET_HAVE_TLS
)
447 subrtx_iterator::array_type array
;
448 FOR_EACH_SUBRTX (iter
, array
, x
, ALL
)
451 if (GET_CODE (x
) == SYMBOL_REF
&& SYMBOL_REF_TLS_MODEL (x
) != 0)
453 /* Don't recurse into UNSPEC_TLS looking for TLS symbols; these are
454 TLS offsets, not real symbol references. */
455 if (GET_CODE (x
) == UNSPEC
&& XINT (x
, 1) == UNSPEC_TLS
)
456 iter
.skip_subrtxes ();
462 microblaze_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED
, rtx x
)
464 return microblaze_tls_referenced_p(x
);
467 /* Return TRUE if X references a SYMBOL_REF. */
469 symbol_mentioned_p (rtx x
)
474 if (GET_CODE (x
) == SYMBOL_REF
)
477 /* UNSPEC entries for a symbol include the SYMBOL_REF, but they
478 are constant offsets, not symbols. */
479 if (GET_CODE (x
) == UNSPEC
)
482 fmt
= GET_RTX_FORMAT (GET_CODE (x
));
484 for (i
= GET_RTX_LENGTH (GET_CODE (x
)) - 1; i
>= 0; i
--)
490 for (j
= XVECLEN (x
, i
) - 1; j
>= 0; j
--)
491 if (symbol_mentioned_p (XVECEXP (x
, i
, j
)))
494 else if (fmt
[i
] == 'e' && symbol_mentioned_p (XEXP (x
, i
)))
501 /* Return TRUE if X references a LABEL_REF. */
503 label_mentioned_p (rtx x
)
508 if (GET_CODE (x
) == LABEL_REF
)
511 /* UNSPEC entries for a symbol include a LABEL_REF for the referencing
512 instruction, but they are constant offsets, not symbols. */
513 if (GET_CODE (x
) == UNSPEC
)
516 fmt
= GET_RTX_FORMAT (GET_CODE (x
));
517 for (i
= GET_RTX_LENGTH (GET_CODE (x
)) - 1; i
>= 0; i
--)
523 for (j
= XVECLEN (x
, i
) - 1; j
>= 0; j
--)
524 if (label_mentioned_p (XVECEXP (x
, i
, j
)))
527 else if (fmt
[i
] == 'e' && label_mentioned_p (XEXP (x
, i
)))
535 tls_mentioned_p (rtx x
)
537 switch (GET_CODE (x
))
540 return tls_mentioned_p (XEXP (x
, 0));
543 if (XINT (x
, 1) == UNSPEC_TLS
)
553 load_tls_operand (rtx x
, rtx reg
)
558 reg
= gen_reg_rtx (Pmode
);
560 tmp
= gen_rtx_CONST (Pmode
, x
);
562 emit_insn (gen_rtx_SET (reg
,
563 gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
, tmp
)));
569 microblaze_call_tls_get_addr (rtx x
, rtx reg
, rtx
*valuep
, int reloc
)
574 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
578 tls_entry
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (2, x
, GEN_INT (reloc
)),
581 reg
= load_tls_operand (tls_entry
, reg
);
583 *valuep
= emit_library_call_value (get_tls_get_addr (), NULL_RTX
,
584 LCT_PURE
, /* LCT_CONST? */
587 insns
= get_insns ();
594 microblaze_legitimize_tls_address(rtx x
, rtx reg
)
596 rtx dest
, ret
, eqv
, addend
;
598 enum tls_model model
;
599 model
= SYMBOL_REF_TLS_MODEL (x
);
603 case TLS_MODEL_LOCAL_DYNAMIC
:
604 case TLS_MODEL_GLOBAL_DYNAMIC
:
605 case TLS_MODEL_INITIAL_EXEC
:
606 insns
= microblaze_call_tls_get_addr (x
, reg
, &ret
, TLS_GD
);
607 dest
= gen_reg_rtx (Pmode
);
608 emit_libcall_block (insns
, dest
, ret
, x
);
611 case TLS_MODEL_LOCAL_EXEC
:
612 insns
= microblaze_call_tls_get_addr (x
, reg
, &ret
, TLS_LDM
);
614 /* Attach a unique REG_EQUIV, to allow the RTL optimizers to
615 share the LDM result with other LD model accesses. */
616 eqv
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, const1_rtx
), UNSPEC_TLS
);
617 dest
= gen_reg_rtx (Pmode
);
618 emit_libcall_block (insns
, dest
, ret
, eqv
);
620 /* Load the addend. */
621 addend
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (2, x
, GEN_INT (TLS_DTPREL
)),
623 addend
= force_reg (SImode
, gen_rtx_CONST (SImode
, addend
));
624 dest
= gen_rtx_PLUS (Pmode
, dest
, addend
);
634 microblaze_classify_unspec (struct microblaze_address_info
*info
, rtx x
)
636 info
->symbol_type
= SYMBOL_TYPE_GENERAL
;
637 info
->symbol
= XVECEXP (x
, 0, 0);
639 if (XINT (x
, 1) == UNSPEC_GOTOFF
)
641 info
->regA
= gen_rtx_REG (SImode
, PIC_OFFSET_TABLE_REGNUM
);
642 info
->type
= ADDRESS_GOTOFF
;
644 else if (XINT (x
, 1) == UNSPEC_PLT
)
646 info
->type
= ADDRESS_PLT
;
648 else if (XINT (x
, 1) == UNSPEC_TLS
)
650 info
->type
= ADDRESS_TLS
;
651 info
->tls_type
= tls_reloc (INTVAL (XVECEXP (x
, 0, 1)));
661 /* Return true if X is a valid index register for the given mode.
662 Allow only hard registers if STRICT. */
665 microblaze_valid_index_register_p (rtx x
,
666 machine_mode mode ATTRIBUTE_UNUSED
,
669 if (!strict
&& GET_CODE (x
) == SUBREG
)
672 return (GET_CODE (x
) == REG
673 /* A base register is good enough to be an index register on MicroBlaze. */
674 && microblaze_regno_ok_for_base_p (REGNO (x
), strict
));
677 /* Get the base register for accessing a value from the memory or
678 Symbol ref. Used for MicroBlaze Small Data Area Pointer Optimization. */
685 if (!flag_pic
|| microblaze_tls_symbol_p(x
))
686 base_reg
= MB_ABI_BASE_REGNUM
;
688 base_reg
= MB_ABI_PIC_ADDR_REGNUM
;
691 && GET_CODE (x
) == SYMBOL_REF
692 && SYMBOL_REF_SMALL_P (x
) && (decl
= SYMBOL_REF_DECL (x
)) != NULL
)
694 if (TREE_READONLY (decl
))
695 base_reg
= MB_ABI_GPRO_REGNUM
;
697 base_reg
= MB_ABI_GPRW_REGNUM
;
703 /* Return true if X is a valid address for machine mode MODE. If it is,
704 fill in INFO appropriately. STRICT is true if we should only accept
707 type regA regB offset symbol
709 ADDRESS_INVALID NULL NULL NULL NULL
711 ADDRESS_REG %0 NULL const_0 / NULL
713 ADDRESS_REG_INDEX %0 %1 NULL NULL
715 ADDRESS_SYMBOLIC r0 / NULL NULL symbol
718 ADDRESS_CONST_INT r0 NULL const NULL
720 For modes spanning multiple registers (DFmode in 32-bit GPRs,
721 DImode, TImode), indexed addressing cannot be used because
722 adjacent memory cells are accessed by adding word-sized offsets
723 during assembly output. */
726 microblaze_classify_address (struct microblaze_address_info
*info
, rtx x
,
727 machine_mode mode
, int strict
)
732 info
->type
= ADDRESS_INVALID
;
737 info
->symbol_type
= SYMBOL_TYPE_INVALID
;
739 switch (GET_CODE (x
))
744 info
->type
= ADDRESS_REG
;
746 info
->offset
= const0_rtx
;
747 return microblaze_valid_base_register_p (info
->regA
, mode
, strict
);
751 xplus0
= XEXP (x
, 0);
752 xplus1
= XEXP (x
, 1);
754 if (microblaze_valid_base_register_p (xplus0
, mode
, strict
))
756 info
->type
= ADDRESS_REG
;
759 if (GET_CODE (xplus1
) == CONST_INT
)
761 info
->offset
= xplus1
;
764 else if (GET_CODE (xplus1
) == UNSPEC
)
766 /* Need offsettable address. */
767 if (GET_MODE_SIZE (mode
) > UNITS_PER_WORD
)
770 return microblaze_classify_unspec (info
, xplus1
);
772 else if ((GET_CODE (xplus1
) == SYMBOL_REF
||
773 GET_CODE (xplus1
) == LABEL_REF
))
775 if (flag_pic
== 2 || microblaze_tls_symbol_p(xplus1
))
777 info
->type
= ADDRESS_SYMBOLIC
;
778 info
->symbol
= xplus1
;
779 info
->symbol_type
= SYMBOL_TYPE_GENERAL
;
782 else if (GET_CODE (xplus1
) == CONST
)
784 rtx xconst0
= XEXP(xplus1
, 0);
787 if (GET_CODE (xconst0
) == UNSPEC
)
789 /* Need offsettable address. */
790 if (GET_MODE_SIZE (mode
) > UNITS_PER_WORD
)
792 return microblaze_classify_unspec(info
, xconst0
);
795 /* for (plus x const_int) just look at x. */
796 if (GET_CODE (xconst0
) == PLUS
797 && GET_CODE (XEXP (xconst0
, 1)) == CONST_INT
798 && SMALL_INT (XEXP (xconst0
, 1)))
800 /* This is ok as info->symbol is set to xplus1 the full
801 const-expression below. */
802 xconst0
= XEXP (xconst0
, 0);
805 if (GET_CODE (xconst0
) == SYMBOL_REF
806 || GET_CODE (xconst0
) == LABEL_REF
)
808 if (flag_pic
== 2 || microblaze_tls_symbol_p(xconst0
))
811 info
->type
= ADDRESS_SYMBOLIC
;
812 info
->symbol
= xplus1
;
813 info
->symbol_type
= SYMBOL_TYPE_GENERAL
;
817 /* Not base + symbol || base + UNSPEC. */
821 else if (GET_CODE (xplus1
) == REG
822 && microblaze_valid_index_register_p (xplus1
, mode
,
824 && (GET_MODE_SIZE (mode
) <= UNITS_PER_WORD
))
826 /* Restrict larger than word-width modes from using an index register. */
827 info
->type
= ADDRESS_REG_INDEX
;
836 info
->regA
= gen_raw_REG (mode
, 0);
837 info
->type
= ADDRESS_CONST_INT
;
845 info
->type
= ADDRESS_SYMBOLIC
;
846 info
->symbol_type
= SYMBOL_TYPE_GENERAL
;
848 info
->regA
= gen_raw_REG (mode
, get_base_reg (x
));
850 if (GET_CODE (x
) == CONST
)
852 if (GET_CODE (XEXP (x
, 0)) == UNSPEC
)
854 info
->regA
= gen_raw_REG (mode
,
855 get_base_reg (XVECEXP (XEXP (x
,0), 0, 0)));
856 return microblaze_classify_unspec (info
, XEXP (x
, 0));
858 return !(flag_pic
&& pic_address_needs_scratch (x
));
863 else if (microblaze_tls_symbol_p(x
))
871 if (reload_in_progress
)
872 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
873 return microblaze_classify_unspec (info
, x
);
883 /* This function is used to implement GO_IF_LEGITIMATE_ADDRESS. It
884 returns a nonzero value if X is a legitimate address for a memory
885 operand of the indicated MODE. STRICT is nonzero if this function
886 is called during reload. */
889 microblaze_legitimate_address_p (machine_mode mode
, rtx x
, bool strict
)
891 struct microblaze_address_info addr
;
893 return microblaze_classify_address (&addr
, x
, mode
, strict
);
897 microblaze_valid_pic_const (rtx x
)
899 switch (GET_CODE (x
))
911 microblaze_legitimate_pic_operand (rtx x
)
913 if (flag_pic
== 2 && (symbol_mentioned_p(x
) || label_mentioned_p(x
)))
916 if (microblaze_tls_referenced_p(x
))
922 /* Try machine-dependent ways of modifying an illegitimate address
923 to be legitimate. If we find one, return the new, valid address.
924 This is used from only one place: `memory_address' in explow.c.
926 OLDX is the address as it was before break_out_memory_refs was
927 called. In some cases it is useful to look at this to decide what
930 It is always safe for this function to do nothing. It exists to
931 recognize opportunities to optimize the output.
933 For the MicroBlaze, transform:
935 memory(X + <large int>)
939 Y = <large int> & ~0x7fff;
941 memory (Z + (<large int> & 0x7fff));
943 This is for CSE to find several similar references, and only use one Z.
945 When PIC, convert addresses of the form memory (symbol+large int) to
946 memory (reg+large int). */
949 microblaze_legitimize_address (rtx x
, rtx oldx ATTRIBUTE_UNUSED
,
950 machine_mode mode ATTRIBUTE_UNUSED
)
952 register rtx xinsn
= x
, result
;
954 if (GET_CODE (xinsn
) == CONST
955 && flag_pic
&& pic_address_needs_scratch (xinsn
))
957 rtx ptr_reg
= gen_reg_rtx (Pmode
);
958 rtx constant
= XEXP (XEXP (xinsn
, 0), 1);
960 emit_move_insn (ptr_reg
, XEXP (XEXP (xinsn
, 0), 0));
962 result
= gen_rtx_PLUS (Pmode
, ptr_reg
, constant
);
963 if (SMALL_INT (constant
))
965 /* Otherwise we fall through so the code below will fix the
970 if (GET_CODE (xinsn
) == PLUS
)
972 register rtx xplus0
= XEXP (xinsn
, 0);
973 register rtx xplus1
= XEXP (xinsn
, 1);
974 register enum rtx_code code0
= GET_CODE (xplus0
);
975 register enum rtx_code code1
= GET_CODE (xplus1
);
977 if (code0
!= REG
&& code1
== REG
)
979 xplus0
= XEXP (xinsn
, 1);
980 xplus1
= XEXP (xinsn
, 0);
981 code0
= GET_CODE (xplus0
);
982 code1
= GET_CODE (xplus1
);
985 if (code0
== REG
&& REG_OK_FOR_BASE_P (xplus0
)
986 && code1
== CONST_INT
&& !SMALL_INT (xplus1
))
988 rtx int_reg
= gen_reg_rtx (Pmode
);
989 rtx ptr_reg
= gen_reg_rtx (Pmode
);
991 emit_move_insn (int_reg
, GEN_INT (INTVAL (xplus1
) & ~0x7fff));
993 emit_insn (gen_rtx_SET (ptr_reg
,
994 gen_rtx_PLUS (Pmode
, xplus0
, int_reg
)));
996 result
= gen_rtx_PLUS (Pmode
, ptr_reg
,
997 GEN_INT (INTVAL (xplus1
) & 0x7fff));
1001 if (code0
== REG
&& REG_OK_FOR_BASE_P (xplus0
))
1003 if (reload_in_progress
)
1004 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
1007 xplus1
= XEXP (xplus1
, 0);
1008 code1
= GET_CODE (xplus1
);
1010 if (code1
== SYMBOL_REF
)
1012 if (microblaze_tls_symbol_p(xplus1
))
1015 reg
= gen_reg_rtx (Pmode
);
1017 tls_ref
= microblaze_legitimize_tls_address (xplus1
,
1019 emit_move_insn (reg
, tls_ref
);
1021 result
= gen_rtx_PLUS (Pmode
, xplus0
, reg
);
1025 else if (flag_pic
== 2)
1028 reg
= gen_reg_rtx (Pmode
);
1030 pic_ref
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, xplus1
),
1032 pic_ref
= gen_rtx_CONST (Pmode
, pic_ref
);
1033 pic_ref
= gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
, pic_ref
);
1034 pic_ref
= gen_const_mem (Pmode
, pic_ref
);
1035 emit_move_insn (reg
, pic_ref
);
1036 result
= gen_rtx_PLUS (Pmode
, xplus0
, reg
);
1043 if (GET_CODE (xinsn
) == SYMBOL_REF
)
1046 if (microblaze_tls_symbol_p(xinsn
))
1048 reg
= microblaze_legitimize_tls_address (xinsn
, NULL_RTX
);
1054 if (reload_in_progress
)
1055 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
1057 pic_ref
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, xinsn
), UNSPEC_GOTOFF
);
1058 pic_ref
= gen_rtx_CONST (Pmode
, pic_ref
);
1059 pic_ref
= gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
, pic_ref
);
1060 pic_ref
= gen_const_mem (Pmode
, pic_ref
);
1071 #define MAX_MOVE_REGS 8
1072 #define MAX_MOVE_BYTES (MAX_MOVE_REGS * UNITS_PER_WORD)
1074 /* Emit straight-line code to move LENGTH bytes from SRC to DEST.
1075 Assume that the areas do not overlap. */
1078 microblaze_block_move_straight (rtx dest
, rtx src
, HOST_WIDE_INT length
)
1080 HOST_WIDE_INT offset
, delta
;
1081 unsigned HOST_WIDE_INT bits
;
1086 bits
= BITS_PER_WORD
;
1087 mode
= int_mode_for_size (bits
, 0).require ();
1088 delta
= bits
/ BITS_PER_UNIT
;
1090 /* Allocate a buffer for the temporary registers. */
1091 regs
= XALLOCAVEC (rtx
, length
/ delta
);
1093 /* Load as many BITS-sized chunks as possible. Use a normal load if
1094 the source has enough alignment, otherwise use left/right pairs. */
1095 for (offset
= 0, i
= 0; offset
+ delta
<= length
; offset
+= delta
, i
++)
1097 regs
[i
] = gen_reg_rtx (mode
);
1098 emit_move_insn (regs
[i
], adjust_address (src
, mode
, offset
));
1101 /* Copy the chunks to the destination. */
1102 for (offset
= 0, i
= 0; offset
+ delta
<= length
; offset
+= delta
, i
++)
1103 emit_move_insn (adjust_address (dest
, mode
, offset
), regs
[i
]);
1105 /* Mop up any left-over bytes. */
1106 if (offset
< length
)
1108 src
= adjust_address (src
, BLKmode
, offset
);
1109 dest
= adjust_address (dest
, BLKmode
, offset
);
1110 move_by_pieces (dest
, src
, length
- offset
,
1111 MIN (MEM_ALIGN (src
), MEM_ALIGN (dest
)), 0);
1115 /* Helper function for doing a loop-based block operation on memory
1116 reference MEM. Each iteration of the loop will operate on LENGTH
1119 Create a new base register for use within the loop and point it to
1120 the start of MEM. Create a new memory reference that uses this
1121 register. Store them in *LOOP_REG and *LOOP_MEM respectively. */
1124 microblaze_adjust_block_mem (rtx mem
, HOST_WIDE_INT length
,
1125 rtx
* loop_reg
, rtx
* loop_mem
)
1127 *loop_reg
= copy_addr_to_reg (XEXP (mem
, 0));
1129 /* Although the new mem does not refer to a known location,
1130 it does keep up to LENGTH bytes of alignment. */
1131 *loop_mem
= change_address (mem
, BLKmode
, *loop_reg
);
1132 set_mem_align (*loop_mem
,
1133 MIN ((HOST_WIDE_INT
) MEM_ALIGN (mem
),
1134 length
* BITS_PER_UNIT
));
1138 /* Move LENGTH bytes from SRC to DEST using a loop that moves MAX_MOVE_BYTES
1139 per iteration. LENGTH must be at least MAX_MOVE_BYTES. Assume that the
1140 memory regions do not overlap. */
1143 microblaze_block_move_loop (rtx dest
, rtx src
, HOST_WIDE_INT length
)
1145 rtx_code_label
*label
;
1146 rtx src_reg
, dest_reg
, final_src
;
1147 HOST_WIDE_INT leftover
;
1149 leftover
= length
% MAX_MOVE_BYTES
;
1152 /* Create registers and memory references for use within the loop. */
1153 microblaze_adjust_block_mem (src
, MAX_MOVE_BYTES
, &src_reg
, &src
);
1154 microblaze_adjust_block_mem (dest
, MAX_MOVE_BYTES
, &dest_reg
, &dest
);
1156 /* Calculate the value that SRC_REG should have after the last iteration
1158 final_src
= expand_simple_binop (Pmode
, PLUS
, src_reg
, GEN_INT (length
),
1161 /* Emit the start of the loop. */
1162 label
= gen_label_rtx ();
1165 /* Emit the loop body. */
1166 microblaze_block_move_straight (dest
, src
, MAX_MOVE_BYTES
);
1168 /* Move on to the next block. */
1169 emit_move_insn (src_reg
, plus_constant (Pmode
, src_reg
, MAX_MOVE_BYTES
));
1170 emit_move_insn (dest_reg
, plus_constant (Pmode
, dest_reg
, MAX_MOVE_BYTES
));
1172 /* Emit the test & branch. */
1173 emit_insn (gen_cbranchsi4 (gen_rtx_NE (SImode
, src_reg
, final_src
),
1174 src_reg
, final_src
, label
));
1176 /* Mop up any left-over bytes. */
1178 microblaze_block_move_straight (dest
, src
, leftover
);
1181 /* Expand a movmemsi instruction. */
1184 microblaze_expand_block_move (rtx dest
, rtx src
, rtx length
, rtx align_rtx
)
1187 if (GET_CODE (length
) == CONST_INT
)
1189 HOST_WIDE_INT bytes
= INTVAL (length
);
1190 int align
= INTVAL (align_rtx
);
1192 if (align
> UNITS_PER_WORD
)
1194 align
= UNITS_PER_WORD
; /* We can't do any better. */
1196 else if (align
< UNITS_PER_WORD
)
1198 if (INTVAL (length
) <= MAX_MOVE_BYTES
)
1200 move_by_pieces (dest
, src
, bytes
, align
, 0);
1207 if (INTVAL (length
) <= 2 * MAX_MOVE_BYTES
)
1209 microblaze_block_move_straight (dest
, src
, INTVAL (length
));
1214 microblaze_block_move_loop (dest
, src
, INTVAL (length
));
1222 microblaze_rtx_costs (rtx x
, machine_mode mode
, int outer_code ATTRIBUTE_UNUSED
,
1223 int opno ATTRIBUTE_UNUSED
, int *total
,
1224 bool speed ATTRIBUTE_UNUSED
)
1226 int code
= GET_CODE (x
);
1232 int num_words
= (GET_MODE_SIZE (mode
) > UNITS_PER_WORD
) ? 2 : 1;
1233 if (simple_memory_operand (x
, mode
))
1234 *total
= COSTS_N_INSNS (2 * num_words
);
1236 *total
= COSTS_N_INSNS (2 * (2 * num_words
));
1244 *total
= COSTS_N_INSNS (2);
1247 *total
= COSTS_N_INSNS (1);
1256 *total
= COSTS_N_INSNS (2);
1259 *total
= COSTS_N_INSNS (1);
1267 if (TARGET_BARREL_SHIFT
)
1269 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v5.00.a")
1271 *total
= COSTS_N_INSNS (1);
1273 *total
= COSTS_N_INSNS (2);
1275 else if (!TARGET_SOFT_MUL
)
1276 *total
= COSTS_N_INSNS (1);
1277 else if (GET_CODE (XEXP (x
, 1)) == CONST_INT
)
1279 /* Add 1 to make shift slightly more expensive than add. */
1280 *total
= COSTS_N_INSNS (INTVAL (XEXP (x
, 1))) + 1;
1281 /* Reduce shift costs for special circumstances. */
1282 if (optimize_size
&& INTVAL (XEXP (x
, 1)) > 5)
1284 if (!optimize_size
&& INTVAL (XEXP (x
, 1)) > 17)
1288 /* Double the worst cost of shifts when there is no barrel shifter and
1289 the shift amount is in a reg. */
1290 *total
= COSTS_N_INSNS (32 * 4);
1296 if (mode
== SFmode
|| mode
== DFmode
)
1298 if (TARGET_HARD_FLOAT
)
1299 *total
= COSTS_N_INSNS (6);
1302 else if (mode
== DImode
)
1304 *total
= COSTS_N_INSNS (4);
1309 *total
= COSTS_N_INSNS (1);
1318 *total
= COSTS_N_INSNS (4);
1326 if (TARGET_HARD_FLOAT
)
1327 *total
= COSTS_N_INSNS (6);
1329 else if (!TARGET_SOFT_MUL
)
1331 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v5.00.a")
1333 *total
= COSTS_N_INSNS (1);
1335 *total
= COSTS_N_INSNS (3);
1338 *total
= COSTS_N_INSNS (10);
1346 if (TARGET_HARD_FLOAT
)
1347 *total
= COSTS_N_INSNS (23);
1353 *total
= COSTS_N_INSNS (1);
1358 *total
= COSTS_N_INSNS (1);
1366 /* Return the number of instructions needed to load or store a value
1367 of mode MODE at X. Return 0 if X isn't valid for MODE. */
1370 microblaze_address_insns (rtx x
, machine_mode mode
)
1372 struct microblaze_address_info addr
;
1374 if (microblaze_classify_address (&addr
, x
, mode
, false))
1379 if (SMALL_INT (addr
.offset
))
1383 case ADDRESS_CONST_INT
:
1388 case ADDRESS_REG_INDEX
:
1390 case ADDRESS_SYMBOLIC
:
1391 case ADDRESS_GOTOFF
:
1394 switch (addr
.tls_type
)
1412 /* Provide the costs of an addressing mode that contains ADDR.
1413 If ADDR is not a valid address, its cost is irrelevant. */
1415 microblaze_address_cost (rtx addr
, machine_mode mode ATTRIBUTE_UNUSED
,
1416 addr_space_t as ATTRIBUTE_UNUSED
,
1417 bool speed ATTRIBUTE_UNUSED
)
1419 return COSTS_N_INSNS (microblaze_address_insns (addr
, GET_MODE (addr
)));
1422 /* Return nonzero if X is an address which needs a temporary register when
1423 reloaded while generating PIC code. */
1426 pic_address_needs_scratch (rtx x
)
1428 if (GET_CODE (x
) == CONST
&& GET_CODE (XEXP (x
,0)) == PLUS
)
1432 p0
= XEXP (XEXP (x
, 0), 0);
1433 p1
= XEXP (XEXP (x
, 0), 1);
1435 if ((GET_CODE (p0
) == SYMBOL_REF
|| GET_CODE (p0
) == LABEL_REF
)
1436 && (GET_CODE (p1
) == CONST_INT
)
1437 && (flag_pic
== 2 || microblaze_tls_symbol_p (p0
) || !SMALL_INT (p1
)))
1443 /* Argument support functions. */
1444 /* Initialize CUMULATIVE_ARGS for a function. */
1447 init_cumulative_args (CUMULATIVE_ARGS
* cum
, tree fntype
,
1448 rtx libname ATTRIBUTE_UNUSED
)
1450 static CUMULATIVE_ARGS zero_cum
;
1451 tree param
, next_param
;
1455 /* Determine if this function has variable arguments. This is
1456 indicated by the last argument being 'void_type_mode' if there
1457 are no variable arguments. The standard MicroBlaze calling sequence
1458 passes all arguments in the general purpose registers in this case. */
1460 for (param
= fntype
? TYPE_ARG_TYPES (fntype
) : 0;
1461 param
!= 0; param
= next_param
)
1463 next_param
= TREE_CHAIN (param
);
1464 if (next_param
== 0 && TREE_VALUE (param
) != void_type_node
)
1465 cum
->gp_reg_found
= 1;
1469 /* Advance the argument to the next argument position. */
1472 microblaze_function_arg_advance (cumulative_args_t cum_v
,
1474 const_tree type
, bool named ATTRIBUTE_UNUSED
)
1476 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
1485 gcc_assert (GET_MODE_CLASS (mode
) == MODE_COMPLEX_INT
1486 || GET_MODE_CLASS (mode
) == MODE_COMPLEX_FLOAT
);
1488 cum
->gp_reg_found
= 1;
1489 cum
->arg_words
+= ((GET_MODE_SIZE (mode
) + UNITS_PER_WORD
- 1)
1494 cum
->gp_reg_found
= 1;
1495 cum
->arg_words
+= ((int_size_in_bytes (type
) + UNITS_PER_WORD
- 1)
1501 if (!cum
->gp_reg_found
&& cum
->arg_number
<= 2)
1502 cum
->fp_code
+= 1 << ((cum
->arg_number
- 1) * 2);
1506 cum
->arg_words
+= 2;
1507 if (!cum
->gp_reg_found
&& cum
->arg_number
<= 2)
1508 cum
->fp_code
+= 2 << ((cum
->arg_number
- 1) * 2);
1512 cum
->gp_reg_found
= 1;
1513 cum
->arg_words
+= 2;
1520 cum
->gp_reg_found
= 1;
1526 /* Return an RTL expression containing the register for the given mode,
1527 or 0 if the argument is to be passed on the stack. */
1530 microblaze_function_arg (cumulative_args_t cum_v
, machine_mode mode
,
1531 const_tree type ATTRIBUTE_UNUSED
,
1532 bool named ATTRIBUTE_UNUSED
)
1534 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
1538 int *arg_words
= &cum
->arg_words
;
1540 cum
->last_arg_fp
= 0;
1551 regbase
= GP_ARG_FIRST
;
1554 gcc_assert (GET_MODE_CLASS (mode
) == MODE_COMPLEX_INT
1555 || GET_MODE_CLASS (mode
) == MODE_COMPLEX_FLOAT
);
1558 regbase
= GP_ARG_FIRST
;
1562 if (*arg_words
>= MAX_ARGS_IN_REGISTERS
)
1566 gcc_assert (regbase
!= -1);
1568 ret
= gen_rtx_REG (mode
, regbase
+ *arg_words
);
1571 if (mode
== VOIDmode
)
1573 if (cum
->num_adjusts
> 0)
1574 ret
= gen_rtx_PARALLEL ((machine_mode
) cum
->fp_code
,
1575 gen_rtvec_v (cum
->num_adjusts
, cum
->adjust
));
1581 /* Return number of bytes of argument to put in registers. */
1583 function_arg_partial_bytes (cumulative_args_t cum_v
, machine_mode mode
,
1584 tree type
, bool named ATTRIBUTE_UNUSED
)
1586 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
1588 if ((mode
== BLKmode
1589 || GET_MODE_CLASS (mode
) != MODE_COMPLEX_INT
1590 || GET_MODE_CLASS (mode
) != MODE_COMPLEX_FLOAT
)
1591 && cum
->arg_words
< MAX_ARGS_IN_REGISTERS
)
1594 if (mode
== BLKmode
)
1595 words
= ((int_size_in_bytes (type
) + UNITS_PER_WORD
- 1)
1598 words
= (GET_MODE_SIZE (mode
) + UNITS_PER_WORD
- 1) / UNITS_PER_WORD
;
1600 if (words
+ cum
->arg_words
<= MAX_ARGS_IN_REGISTERS
)
1601 return 0; /* structure fits in registers */
1603 return (MAX_ARGS_IN_REGISTERS
- cum
->arg_words
) * UNITS_PER_WORD
;
1606 else if (mode
== DImode
&& cum
->arg_words
== MAX_ARGS_IN_REGISTERS
- 1)
1607 return UNITS_PER_WORD
;
1612 /* Convert a version number of the form "vX.YY.Z" to an integer encoding
1613 for easier range comparison. */
1615 microblaze_version_to_int (const char *version
)
1618 const char *tmpl
= "vXX.YY.Z";
1627 { /* Looking for major */
1634 if (!(*p
>= '0' && *p
<= '9'))
1636 iver
+= (int) (*p
- '0');
1641 { /* Looking for minor */
1642 if (!(*p
>= '0' && *p
<= '9'))
1644 iver
+= (int) (*p
- '0');
1648 { /* Looking for compat */
1649 if (!(*p
>= 'a' && *p
<= 'z'))
1652 iver
+= (int) (*p
- 'a');
1672 microblaze_option_override (void)
1674 register int i
, start
;
1676 register machine_mode mode
;
1679 microblaze_section_threshold
= (global_options_set
.x_g_switch_value
1681 : MICROBLAZE_DEFAULT_GVALUE
);
1685 /* Make sure it's 2, we only support one kind of PIC. */
1687 if (!TARGET_SUPPORTS_PIC
)
1689 error ("-fPIC/-fpic not supported for this target");
1690 /* Clear it to avoid further errors. */
1695 /* Check the MicroBlaze CPU version for any special action to be done. */
1696 if (microblaze_select_cpu
== NULL
)
1697 microblaze_select_cpu
= MICROBLAZE_DEFAULT_CPU
;
1698 ver
= microblaze_version_to_int (microblaze_select_cpu
);
1701 error ("%qs is an invalid argument to -mcpu=", microblaze_select_cpu
);
1704 ver
= MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v3.00.a");
1707 /* No hardware exceptions in earlier versions. So no worries. */
1709 microblaze_select_flags
&= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY
);
1711 microblaze_no_unsafe_delay
= 0;
1712 microblaze_pipe
= MICROBLAZE_PIPE_3
;
1715 || (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v4.00.b")
1719 microblaze_select_flags
|= (MICROBLAZE_MASK_NO_UNSAFE_DELAY
);
1721 microblaze_no_unsafe_delay
= 1;
1722 microblaze_pipe
= MICROBLAZE_PIPE_3
;
1726 /* We agree to use 5 pipe-stage model even on area optimized 3
1727 pipe-stage variants. */
1729 microblaze_select_flags
&= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY
);
1731 microblaze_no_unsafe_delay
= 0;
1732 microblaze_pipe
= MICROBLAZE_PIPE_5
;
1733 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v5.00.a") == 0
1734 || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
,
1736 || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
,
1739 /* Pattern compares are to be turned on by default only when
1740 compiling for MB v5.00.'z'. */
1741 target_flags
|= MASK_PATTERN_COMPARE
;
1745 ver
= MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v6.00.a");
1748 if (TARGET_MULTIPLY_HIGH
)
1750 "-mxl-multiply-high can be used only with -mcpu=v6.00.a or greater");
1753 ver
= MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v8.10.a");
1754 microblaze_has_clz
= 1;
1757 /* MicroBlaze prior to 8.10.a didn't have clz. */
1758 microblaze_has_clz
= 0;
1761 /* TARGET_REORDER defaults to 2 if -mxl-reorder not specified. */
1762 ver
= MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v8.30.a");
1765 if (TARGET_REORDER
== 1)
1766 warning (0, "-mxl-reorder can be used only with -mcpu=v8.30.a or greater");
1769 else if ((ver
== 0) && !TARGET_PATTERN_COMPARE
)
1771 if (TARGET_REORDER
== 1)
1772 warning (0, "-mxl-reorder requires -mxl-pattern-compare for -mcpu=v8.30.a");
1776 if (TARGET_MULTIPLY_HIGH
&& TARGET_SOFT_MUL
)
1777 error ("-mxl-multiply-high requires -mno-xl-soft-mul");
1779 /* Always use DFA scheduler. */
1780 microblaze_sched_use_dfa
= 1;
1783 microblaze_abicalls
= MICROBLAZE_ABICALLS_NO
;
1786 /* Initialize the high, low values for legit floating point constants. */
1787 real_maxval (&dfhigh
, 0, DFmode
);
1788 real_maxval (&dflow
, 1, DFmode
);
1789 real_maxval (&sfhigh
, 0, SFmode
);
1790 real_maxval (&sflow
, 1, SFmode
);
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;
1797 microblaze_print_operand_punct
['@'] = 1;
1798 microblaze_print_operand_punct
['.'] = 1;
1799 microblaze_print_operand_punct
['('] = 1;
1800 microblaze_print_operand_punct
[')'] = 1;
1801 microblaze_print_operand_punct
['['] = 1;
1802 microblaze_print_operand_punct
[']'] = 1;
1803 microblaze_print_operand_punct
['<'] = 1;
1804 microblaze_print_operand_punct
['>'] = 1;
1805 microblaze_print_operand_punct
['{'] = 1;
1806 microblaze_print_operand_punct
['}'] = 1;
1807 microblaze_print_operand_punct
['^'] = 1;
1808 microblaze_print_operand_punct
['$'] = 1;
1809 microblaze_print_operand_punct
['+'] = 1;
1811 /* Set up array to map GCC register number to debug register number.
1812 Ignore the special purpose register numbers. */
1814 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
1815 microblaze_dbx_regno
[i
] = -1;
1817 start
= GP_DBX_FIRST
- GP_REG_FIRST
;
1818 for (i
= GP_REG_FIRST
; i
<= GP_REG_LAST
; i
++)
1819 microblaze_dbx_regno
[i
] = i
+ start
;
1821 /* Set up array giving whether a given register can hold a given mode. */
1823 for (mode
= VOIDmode
;
1824 mode
!= MAX_MACHINE_MODE
; mode
= (machine_mode
) ((int) mode
+ 1))
1826 register int size
= GET_MODE_SIZE (mode
);
1828 for (regno
= 0; regno
< FIRST_PSEUDO_REGISTER
; regno
++)
1834 ok
= (ST_REG_P (regno
) || GP_REG_P (regno
));
1836 else if (GP_REG_P (regno
))
1837 ok
= ((regno
& 1) == 0 || size
<= UNITS_PER_WORD
);
1841 microblaze_hard_regno_mode_ok_p
[(int) mode
][regno
] = ok
;
1846 /* Implement TARGET_HARD_REGNO_MODE_OK. In 32 bit mode, require that
1847 DImode and DFmode be in even registers. For DImode, this makes some
1848 of the insns easier to write, since you don't have to worry about a
1849 DImode value in registers 3 & 4, producing a result in 4 & 5.
1851 To make the code simpler, the hook now just references an
1852 array built in override_options. */
1855 microblaze_hard_regno_mode_ok (unsigned int regno
, machine_mode mode
)
1857 return microblaze_hard_regno_mode_ok_p
[mode
][regno
];
1860 /* Implement TARGET_MODES_TIEABLE_P. */
1863 microblaze_modes_tieable_p (machine_mode mode1
, machine_mode mode2
)
1865 return ((GET_MODE_CLASS (mode1
) == MODE_FLOAT
1866 || GET_MODE_CLASS (mode1
) == MODE_COMPLEX_FLOAT
)
1867 == (GET_MODE_CLASS (mode2
) == MODE_FLOAT
1868 || GET_MODE_CLASS (mode2
) == MODE_COMPLEX_FLOAT
));
1871 /* Return true if FUNC is an interrupt function as specified
1872 by the "interrupt_handler" attribute. */
1875 microblaze_interrupt_function_p (tree func
)
1879 if (TREE_CODE (func
) != FUNCTION_DECL
)
1882 a
= lookup_attribute ("interrupt_handler", DECL_ATTRIBUTES (func
));
1883 return a
!= NULL_TREE
;
1887 microblaze_fast_interrupt_function_p (tree func
)
1891 if (TREE_CODE (func
) != FUNCTION_DECL
)
1894 a
= lookup_attribute ("fast_interrupt", DECL_ATTRIBUTES (func
));
1895 return a
!= NULL_TREE
;
1898 microblaze_break_function_p (tree func
)
1903 if (TREE_CODE (func
) != FUNCTION_DECL
)
1906 a
= lookup_attribute ("break_handler", DECL_ATTRIBUTES (func
));
1907 return a
!= NULL_TREE
;
1909 /* Return true if FUNC is an interrupt function which uses
1910 normal return, indicated by the "save_volatiles" attribute. */
1913 microblaze_save_volatiles (tree func
)
1917 if (TREE_CODE (func
) != FUNCTION_DECL
)
1920 a
= lookup_attribute ("save_volatiles", DECL_ATTRIBUTES (func
));
1921 return a
!= NULL_TREE
;
1924 /* Return whether function is tagged with 'interrupt_handler'
1925 or 'fast_interrupt' attribute. Return true if function
1926 should use return from interrupt rather than normal
1929 microblaze_is_interrupt_variant (void)
1931 return (interrupt_handler
|| fast_interrupt
);
1934 microblaze_is_break_handler (void)
1936 return break_handler
;
1939 /* Determine of register must be saved/restored in call. */
1941 microblaze_must_save_register (int regno
)
1943 if (pic_offset_table_rtx
&&
1944 (regno
== MB_ABI_PIC_ADDR_REGNUM
) && df_regs_ever_live_p (regno
))
1947 if (df_regs_ever_live_p (regno
) && !call_used_regs
[regno
])
1950 if (frame_pointer_needed
&& (regno
== HARD_FRAME_POINTER_REGNUM
))
1953 if (crtl
->calls_eh_return
1954 && regno
== MB_ABI_SUB_RETURN_ADDR_REGNUM
)
1959 if (regno
== MB_ABI_SUB_RETURN_ADDR_REGNUM
)
1961 if ((microblaze_is_interrupt_variant () || save_volatiles
) &&
1962 (regno
>= 3 && regno
<= 12))
1966 if (microblaze_is_interrupt_variant ())
1968 if (df_regs_ever_live_p (regno
)
1969 || regno
== MB_ABI_MSR_SAVE_REG
1970 || (interrupt_handler
1971 && (regno
== MB_ABI_ASM_TEMP_REGNUM
1972 || regno
== MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM
)))
1978 if (df_regs_ever_live_p (regno
)
1979 || regno
== MB_ABI_ASM_TEMP_REGNUM
1980 || regno
== MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM
)
1984 if (crtl
->calls_eh_return
1985 && (regno
== EH_RETURN_DATA_REGNO (0)
1986 || regno
== EH_RETURN_DATA_REGNO (1)))
1992 /* Return the bytes needed to compute the frame pointer from the current
1995 MicroBlaze stack frames look like:
1999 Before call After call
2000 +-----------------------+ +-----------------------+
2002 mem. | local variables, | | local variables, |
2003 | callee saved and | | callee saved and |
2005 +-----------------------+ +-----------------------+
2006 | arguments for called | | arguments for called |
2007 | subroutines | | subroutines |
2008 | (optional) | | (optional) |
2009 +-----------------------+ +-----------------------+
2010 | Link register | | Link register |
2012 +-----------------------+ +-----------------------+
2014 | local variables, |
2015 | callee saved and |
2017 +-----------------------+
2018 | MSR (optional if, |
2019 | interrupt handler) |
2020 +-----------------------+
2022 | alloca allocations |
2024 +-----------------------+
2026 | arguments for called |
2030 +-----------------------+
2033 memory +-----------------------+
2037 static HOST_WIDE_INT
2038 compute_frame_size (HOST_WIDE_INT size
)
2041 HOST_WIDE_INT total_size
; /* # bytes that the entire frame takes up. */
2042 HOST_WIDE_INT var_size
; /* # bytes that local variables take up. */
2043 HOST_WIDE_INT args_size
; /* # bytes that outgoing arguments take up. */
2044 int link_debug_size
; /* # bytes for link register. */
2045 HOST_WIDE_INT gp_reg_size
; /* # bytes needed to store calle-saved gp regs. */
2046 long mask
; /* mask of saved gp registers. */
2049 microblaze_interrupt_function_p (current_function_decl
);
2051 microblaze_break_function_p (current_function_decl
);
2054 microblaze_fast_interrupt_function_p (current_function_decl
);
2055 save_volatiles
= microblaze_save_volatiles (current_function_decl
);
2057 interrupt_handler
= break_handler
;
2062 args_size
= crtl
->outgoing_args_size
;
2064 if ((args_size
== 0) && cfun
->calls_alloca
)
2065 args_size
= NUM_OF_ARGS
* UNITS_PER_WORD
;
2067 total_size
= var_size
+ args_size
;
2070 /* force setting GOT. */
2071 df_set_regs_ever_live (MB_ABI_PIC_ADDR_REGNUM
, true);
2073 /* Calculate space needed for gp registers. */
2074 for (regno
= GP_REG_FIRST
; regno
<= GP_REG_LAST
; regno
++)
2076 if (microblaze_must_save_register (regno
))
2079 if (regno
!= MB_ABI_SUB_RETURN_ADDR_REGNUM
)
2080 /* Don't account for link register. It is accounted specially below. */
2081 gp_reg_size
+= GET_MODE_SIZE (SImode
);
2083 mask
|= (1L << (regno
- GP_REG_FIRST
));
2087 total_size
+= gp_reg_size
;
2089 /* Add 4 bytes for MSR. */
2090 if (microblaze_is_interrupt_variant ())
2093 /* No space to be allocated for link register in leaf functions with no other
2094 stack requirements. */
2095 if (total_size
== 0 && crtl
->is_leaf
)
2096 link_debug_size
= 0;
2098 link_debug_size
= UNITS_PER_WORD
;
2100 total_size
+= link_debug_size
;
2102 /* Save other computed information. */
2103 current_frame_info
.total_size
= total_size
;
2104 current_frame_info
.var_size
= var_size
;
2105 current_frame_info
.args_size
= args_size
;
2106 current_frame_info
.gp_reg_size
= gp_reg_size
;
2107 current_frame_info
.mask
= mask
;
2108 current_frame_info
.initialized
= reload_completed
;
2109 current_frame_info
.num_gp
= gp_reg_size
/ UNITS_PER_WORD
;
2110 current_frame_info
.link_debug_size
= link_debug_size
;
2113 /* Offset from which to callee-save GP regs. */
2114 current_frame_info
.gp_offset
= (total_size
- gp_reg_size
);
2116 current_frame_info
.gp_offset
= 0;
2118 /* Ok, we're done. */
2122 /* Make sure that we're not trying to eliminate to the wrong hard frame
2126 microblaze_can_eliminate (const int from
, const int to
)
2128 return ((from
== RETURN_ADDRESS_POINTER_REGNUM
&& !leaf_function_p())
2129 || (to
== MB_ABI_SUB_RETURN_ADDR_REGNUM
&& leaf_function_p())
2130 || (from
!= RETURN_ADDRESS_POINTER_REGNUM
2131 && (to
== HARD_FRAME_POINTER_REGNUM
2132 || (to
== STACK_POINTER_REGNUM
&& !frame_pointer_needed
))));
2135 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
2136 pointer or argument pointer or the return address pointer. TO is either
2137 the stack pointer or hard frame pointer. */
2140 microblaze_initial_elimination_offset (int from
, int to
)
2142 HOST_WIDE_INT offset
;
2146 case FRAME_POINTER_REGNUM
:
2149 case ARG_POINTER_REGNUM
:
2150 if (to
== STACK_POINTER_REGNUM
|| to
== HARD_FRAME_POINTER_REGNUM
)
2151 offset
= compute_frame_size (get_frame_size ());
2155 case RETURN_ADDRESS_POINTER_REGNUM
:
2159 offset
= current_frame_info
.gp_offset
+
2160 ((UNITS_PER_WORD
- (POINTER_SIZE
/ BITS_PER_UNIT
)));
2168 /* Print operands using format code.
2170 The MicroBlaze specific codes are:
2172 'X' X is CONST_INT, prints 32 bits in hexadecimal format = "0x%08x",
2173 'x' X is CONST_INT, prints 16 bits in hexadecimal format = "0x%04x",
2174 'F' op is CONST_DOUBLE, print 32 bits in hex,
2175 'd' output integer constant in decimal,
2176 'z' if the operand is 0, use $0 instead of normal operand.
2177 'D' print second register of double-word register operand.
2178 'L' print low-order register of double-word register operand.
2179 'M' print high-order register of double-word register operand.
2180 'C' print part of opcode for a branch condition.
2181 'N' print part of opcode for a branch condition, inverted.
2182 'S' X is CODE_LABEL, print with prefix of "LS" (for embedded switch).
2183 'B' print 'z' for EQ, 'n' for NE
2184 'b' print 'n' for EQ, 'z' for NE
2185 'T' print 'f' for EQ, 't' for NE
2186 't' print 't' for EQ, 'f' for NE
2187 'm' Print 1<<operand.
2188 'i' Print 'i' if MEM operand has immediate value
2189 'y' Print 'y' if MEM operand is single register
2190 'o' Print operand address+4
2191 '?' Print 'd' if we use a branch with delay slot instead of normal branch.
2192 'h' Print high word of const_double (int or float) value as hex
2193 'j' Print low word of const_double (int or float) value as hex
2194 's' Print -1 if operand is negative, 0 if positive (sign extend)
2195 '@' Print the name of the temporary register (rMB_ABI_ASM_TEMP_REGNUM).
2196 '#' Print nop if the delay slot of a branch is not filled.
2200 print_operand (FILE * file
, rtx op
, int letter
)
2202 register enum rtx_code code
;
2204 if (PRINT_OPERAND_PUNCT_VALID_P (letter
))
2209 /* Conditionally add a 'd' to indicate filled delay slot. */
2210 if (final_sequence
!= NULL
)
2215 /* Conditionally add a nop in unfilled delay slot. */
2216 if (final_sequence
== NULL
)
2217 fputs ("nop\t\t# Unfilled delay slot\n", file
);
2221 fputs (reg_names
[GP_REG_FIRST
+ MB_ABI_ASM_TEMP_REGNUM
], file
);
2225 output_operand_lossage ("unknown punctuation '%c'", letter
);
2234 output_operand_lossage ("null pointer");
2238 code
= GET_CODE (op
);
2240 if (code
== SIGN_EXTEND
)
2241 op
= XEXP (op
, 0), code
= GET_CODE (op
);
2269 fatal_insn ("PRINT_OPERAND, invalid insn for %%C", op
);
2272 else if (letter
== 'N')
2298 fatal_insn ("PRINT_OPERAND, invalid insn for %%N", op
);
2301 else if (letter
== 'S')
2305 ASM_GENERATE_INTERNAL_LABEL (buffer
, "LS", CODE_LABEL_NUMBER (op
));
2306 assemble_name (file
, buffer
);
2309 /* Print 'i' for memory operands which have immediate values. */
2310 else if (letter
== 'i')
2314 struct microblaze_address_info info
;
2316 if (!microblaze_classify_address
2317 (&info
, XEXP (op
, 0), GET_MODE (op
), 1))
2318 fatal_insn ("insn contains an invalid address !", op
);
2323 case ADDRESS_CONST_INT
:
2324 case ADDRESS_SYMBOLIC
:
2325 case ADDRESS_GOTOFF
:
2329 case ADDRESS_REG_INDEX
:
2331 case ADDRESS_INVALID
:
2333 fatal_insn ("invalid address", op
);
2338 else if (code
== REG
|| code
== SUBREG
)
2340 register int regnum
;
2343 regnum
= REGNO (op
);
2345 regnum
= true_regnum (op
);
2347 if ((letter
== 'M' && !WORDS_BIG_ENDIAN
)
2348 || (letter
== 'L' && WORDS_BIG_ENDIAN
) || letter
== 'D')
2351 fprintf (file
, "%s", reg_names
[regnum
]);
2354 else if (code
== MEM
)
2357 rtx op4
= adjust_address (op
, GET_MODE (op
), 4);
2358 output_address (GET_MODE (op
), XEXP (op4
, 0));
2360 else if (letter
== 'y')
2362 rtx mem_reg
= XEXP (op
, 0);
2363 if (GET_CODE (mem_reg
) == REG
)
2365 register int regnum
= REGNO (mem_reg
);
2366 fprintf (file
, "%s", reg_names
[regnum
]);
2370 output_address (GET_MODE (op
), XEXP (op
, 0));
2372 else if (letter
== 'h' || letter
== 'j')
2375 if (code
== CONST_DOUBLE
)
2377 if (GET_MODE (op
) == DFmode
)
2378 REAL_VALUE_TO_TARGET_DOUBLE (*CONST_DOUBLE_REAL_VALUE (op
), val
);
2381 val
[0] = CONST_DOUBLE_HIGH (op
);
2382 val
[1] = CONST_DOUBLE_LOW (op
);
2385 else if (code
== CONST_INT
)
2387 val
[0] = (INTVAL (op
) & 0xffffffff00000000LL
) >> 32;
2388 val
[1] = INTVAL (op
) & 0x00000000ffffffffLL
;
2389 if (val
[0] == 0 && val
[1] < 0)
2393 fprintf (file
, "0x%8.8lx", (letter
== 'h') ? val
[0] : val
[1]);
2395 else if (code
== CONST_DOUBLE
)
2399 unsigned long value_long
;
2400 REAL_VALUE_TO_TARGET_SINGLE (*CONST_DOUBLE_REAL_VALUE (op
),
2402 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, value_long
);
2407 real_to_decimal (s
, CONST_DOUBLE_REAL_VALUE (op
), sizeof (s
), 0, 1);
2412 else if (code
== UNSPEC
)
2414 print_operand_address (file
, op
);
2417 else if (letter
== 'x' && GET_CODE (op
) == CONST_INT
)
2418 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, 0xffff & INTVAL (op
));
2420 else if (letter
== 'X' && GET_CODE (op
) == CONST_INT
)
2421 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, INTVAL (op
));
2423 else if (letter
== 'd' && GET_CODE (op
) == CONST_INT
)
2424 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, (INTVAL (op
)));
2426 else if (letter
== 'z' && GET_CODE (op
) == CONST_INT
&& INTVAL (op
) == 0)
2427 fputs (reg_names
[GP_REG_FIRST
], file
);
2429 else if (letter
== 's' && GET_CODE (op
) == CONST_INT
)
2430 if (INTVAL (op
) < 0)
2435 else if (letter
== 'd' || letter
== 'x' || letter
== 'X' || letter
== 's')
2436 output_operand_lossage ("letter %c was found & insn was not CONST_INT", letter
);
2438 else if (letter
== 'B')
2439 fputs (code
== EQ
? "z" : "n", file
);
2440 else if (letter
== 'b')
2441 fputs (code
== EQ
? "n" : "z", file
);
2442 else if (letter
== 'T')
2443 fputs (code
== EQ
? "f" : "t", file
);
2444 else if (letter
== 't')
2445 fputs (code
== EQ
? "t" : "f", file
);
2447 else if (code
== CONST
2448 && ((GET_CODE (XEXP (op
, 0)) == REG
)
2449 || (GET_CODE (XEXP (op
, 0)) == UNSPEC
)))
2451 print_operand (file
, XEXP (op
, 0), letter
);
2453 else if (code
== CONST
2454 && (GET_CODE (XEXP (op
, 0)) == PLUS
)
2455 && (GET_CODE (XEXP (XEXP (op
, 0), 0)) == REG
)
2456 && (GET_CODE (XEXP (XEXP (op
, 0), 1)) == CONST
))
2458 print_operand_address (file
, XEXP (op
, 0));
2460 else if (letter
== 'm')
2461 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, (1L << INTVAL (op
)));
2463 output_addr_const (file
, op
);
2466 /* A C compound statement to output to stdio stream STREAM the
2467 assembler syntax for an instruction operand that is a memory
2468 reference whose address is ADDR. ADDR is an RTL expression.
2470 Possible address classifications and output formats are,
2472 ADDRESS_REG "%0, r0"
2474 ADDRESS_REG with non-zero "%0, <addr_const>"
2477 ADDRESS_REG_INDEX "rA, RB"
2478 (if rA is r0, rA and rB are swapped)
2480 ADDRESS_CONST_INT "r0, <addr_const>"
2482 ADDRESS_SYMBOLIC "rBase, <addr_const>"
2483 (rBase is a base register suitable for the
2488 print_operand_address (FILE * file
, rtx addr
)
2490 struct microblaze_address_info info
;
2491 enum microblaze_address_type type
;
2492 if (!microblaze_classify_address (&info
, addr
, GET_MODE (addr
), 1))
2493 fatal_insn ("insn contains an invalid address !", addr
);
2499 fprintf (file
, "%s,", reg_names
[REGNO (info
.regA
)]);
2500 output_addr_const (file
, info
.offset
);
2502 case ADDRESS_REG_INDEX
:
2503 if (REGNO (info
.regA
) == 0)
2504 /* Make rB == r0 instead of rA == r0. This helps reduce read port
2506 fprintf (file
, "%s,%s", reg_names
[REGNO (info
.regB
)],
2507 reg_names
[REGNO (info
.regA
)]);
2508 else if (REGNO (info
.regB
) != 0)
2509 /* This is a silly swap to help Dhrystone. */
2510 fprintf (file
, "%s,%s", reg_names
[REGNO (info
.regB
)],
2511 reg_names
[REGNO (info
.regA
)]);
2513 case ADDRESS_CONST_INT
:
2514 fprintf (file
, "%s,", reg_names
[REGNO (info
.regA
)]);
2515 output_addr_const (file
, info
.offset
);
2517 case ADDRESS_SYMBOLIC
:
2518 case ADDRESS_GOTOFF
:
2522 fprintf (file
, "%s,", reg_names
[REGNO (info
.regA
)]);
2523 output_addr_const (file
, info
.symbol
);
2524 if (type
== ADDRESS_GOTOFF
)
2526 fputs ("@GOT", file
);
2528 else if (type
== ADDRESS_PLT
)
2530 fputs ("@PLT", file
);
2532 else if (type
== ADDRESS_TLS
)
2534 switch (info
.tls_type
)
2537 fputs ("@TLSGD", file
);
2540 fputs ("@TLSLDM", file
);
2543 fputs ("@TLSDTPREL", file
);
2551 case ADDRESS_INVALID
:
2552 fatal_insn ("invalid address", addr
);
2557 /* Emit either a label, .comm, or .lcomm directive, and mark that the symbol
2558 is used, so that we don't emit an .extern for it in
2559 microblaze_asm_file_end. */
2562 microblaze_declare_object (FILE * stream
, const char *name
,
2563 const char *section
, const char *fmt
, int size
)
2566 fputs (section
, stream
);
2567 assemble_name (stream
, name
);
2568 fprintf (stream
, fmt
, size
);
2571 /* Common code to emit the insns (or to write the instructions to a file)
2572 to save/restore registers.
2574 Other parts of the code assume that MICROBLAZE_TEMP1_REGNUM (aka large_reg)
2575 is not modified within save_restore_insns. */
2577 #define BITSET_P(VALUE,BIT) (((VALUE) & (1L << (BIT))) != 0)
2579 /* Save or restore instructions based on whether this is the prologue or
2580 epilogue. prologue is 1 for the prologue. */
2582 save_restore_insns (int prologue
)
2584 rtx base_reg_rtx
, reg_rtx
, mem_rtx
, /* msr_rtx, */ isr_reg_rtx
=
2586 rtx isr_msr_rtx
= 0, insn
;
2587 long mask
= current_frame_info
.mask
;
2588 HOST_WIDE_INT gp_offset
;
2591 if (frame_pointer_needed
2592 && !BITSET_P (mask
, HARD_FRAME_POINTER_REGNUM
- GP_REG_FIRST
))
2598 /* Save registers starting from high to low. The debuggers prefer at least
2599 the return register be stored at func+4, and also it allows us not to
2600 need a nop in the epilog if at least one register is reloaded in
2601 addition to return address. */
2603 /* Pick which pointer to use as a base register. For small frames, just
2604 use the stack pointer. Otherwise, use a temporary register. Save 2
2605 cycles if the save area is near the end of a large frame, by reusing
2606 the constant created in the prologue/epilogue to adjust the stack
2609 gp_offset
= current_frame_info
.gp_offset
;
2611 gcc_assert (gp_offset
> 0);
2613 base_reg_rtx
= stack_pointer_rtx
;
2615 /* For interrupt_handlers, need to save/restore the MSR. */
2616 if (microblaze_is_interrupt_variant ())
2618 isr_mem_rtx
= gen_rtx_MEM (SImode
,
2619 gen_rtx_PLUS (Pmode
, base_reg_rtx
,
2620 GEN_INT (current_frame_info
.
2624 /* Do not optimize in flow analysis. */
2625 MEM_VOLATILE_P (isr_mem_rtx
) = 1;
2626 isr_reg_rtx
= gen_rtx_REG (SImode
, MB_ABI_MSR_SAVE_REG
);
2627 isr_msr_rtx
= gen_rtx_REG (SImode
, ST_REG
);
2630 if (microblaze_is_interrupt_variant () && !prologue
)
2632 emit_move_insn (isr_reg_rtx
, isr_mem_rtx
);
2633 emit_move_insn (isr_msr_rtx
, isr_reg_rtx
);
2634 /* Do not optimize in flow analysis. */
2635 emit_insn (gen_rtx_USE (SImode
, isr_reg_rtx
));
2636 emit_insn (gen_rtx_USE (SImode
, isr_msr_rtx
));
2639 for (regno
= GP_REG_FIRST
; regno
<= GP_REG_LAST
; regno
++)
2641 if (BITSET_P (mask
, regno
- GP_REG_FIRST
))
2643 if (regno
== MB_ABI_SUB_RETURN_ADDR_REGNUM
)
2644 /* Don't handle here. Already handled as the first register. */
2647 reg_rtx
= gen_rtx_REG (SImode
, regno
);
2648 insn
= gen_rtx_PLUS (Pmode
, base_reg_rtx
, GEN_INT (gp_offset
));
2649 mem_rtx
= gen_rtx_MEM (SImode
, insn
);
2650 if (microblaze_is_interrupt_variant () || save_volatiles
)
2651 /* Do not optimize in flow analysis. */
2652 MEM_VOLATILE_P (mem_rtx
) = 1;
2656 insn
= emit_move_insn (mem_rtx
, reg_rtx
);
2657 RTX_FRAME_RELATED_P (insn
) = 1;
2661 insn
= emit_move_insn (reg_rtx
, mem_rtx
);
2664 gp_offset
+= GET_MODE_SIZE (SImode
);
2668 if (microblaze_is_interrupt_variant () && prologue
)
2670 emit_move_insn (isr_reg_rtx
, isr_msr_rtx
);
2671 emit_move_insn (isr_mem_rtx
, isr_reg_rtx
);
2673 /* Do not optimize in flow analysis. */
2674 emit_insn (gen_rtx_USE (SImode
, isr_reg_rtx
));
2675 emit_insn (gen_rtx_USE (SImode
, isr_msr_rtx
));
2678 /* Done saving and restoring */
2682 /* Set up the stack and frame (if desired) for the function. */
2684 microblaze_function_prologue (FILE * file
)
2687 long fsiz
= current_frame_info
.total_size
;
2689 /* Get the function name the same way that toplev.c does before calling
2690 assemble_start_function. This is needed so that the name used here
2691 exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */
2692 fnname
= XSTR (XEXP (DECL_RTL (current_function_decl
), 0), 0);
2693 if (!flag_inhibit_size_directive
)
2695 fputs ("\t.ent\t", file
);
2696 if (interrupt_handler
&& strcmp (INTERRUPT_HANDLER_NAME
, fnname
))
2697 fputs ("_interrupt_handler", file
);
2698 else if (break_handler
&& strcmp (BREAK_HANDLER_NAME
, fnname
))
2699 fputs ("_break_handler", file
);
2700 else if (fast_interrupt
&& strcmp (FAST_INTERRUPT_NAME
, fnname
))
2701 fputs ("_fast_interrupt", file
);
2703 assemble_name (file
, fnname
);
2705 if (!microblaze_is_interrupt_variant ())
2706 ASM_OUTPUT_TYPE_DIRECTIVE (file
, fnname
, "function");
2709 assemble_name (file
, fnname
);
2710 fputs (":\n", file
);
2712 if (interrupt_handler
&& strcmp (INTERRUPT_HANDLER_NAME
, fnname
))
2713 fputs ("_interrupt_handler:\n", file
);
2714 if (break_handler
&& strcmp (BREAK_HANDLER_NAME
, fnname
))
2715 fputs ("_break_handler:\n", file
);
2716 if (!flag_inhibit_size_directive
)
2718 /* .frame FRAMEREG, FRAMESIZE, RETREG. */
2720 "\t.frame\t%s,%ld,%s\t\t# vars= %ld, regs= %d, args= %d\n",
2721 (reg_names
[(frame_pointer_needed
)
2722 ? HARD_FRAME_POINTER_REGNUM
:
2723 STACK_POINTER_REGNUM
]), fsiz
,
2724 reg_names
[MB_ABI_SUB_RETURN_ADDR_REGNUM
+ GP_REG_FIRST
],
2725 current_frame_info
.var_size
, current_frame_info
.num_gp
,
2726 (int) crtl
->outgoing_args_size
);
2727 fprintf (file
, "\t.mask\t0x%08lx\n", current_frame_info
.mask
);
2731 /* Output extra assembler code at the end of a prologue. */
2733 microblaze_function_end_prologue (FILE * file
)
2735 if (TARGET_STACK_CHECK
)
2737 fprintf (file
, "\t# Stack Check Stub -- Start.\n\t");
2738 fprintf (file
, "ori\tr18,r0,_stack_end\n\t");
2739 fprintf (file
, "cmpu\tr18,r1,r18\n\t");
2740 fprintf (file
, "bgei\tr18,_stack_overflow_exit\n\t");
2741 fprintf (file
, "# Stack Check Stub -- End.\n");
2746 microblaze_elf_asm_cdtor (rtx symbol
, int priority
, bool is_ctor
)
2750 if (priority
!= DEFAULT_INIT_PRIORITY
)
2753 sprintf (buf
, "%s.%.5u",
2754 is_ctor
? ".ctors" : ".dtors",
2755 MAX_INIT_PRIORITY
- priority
);
2756 s
= get_section (buf
, SECTION_WRITE
, NULL_TREE
);
2763 switch_to_section (s
);
2764 assemble_align (POINTER_SIZE
);
2765 fputs ("\t.word\t", asm_out_file
);
2766 output_addr_const (asm_out_file
, symbol
);
2767 fputs ("\n", asm_out_file
);
2770 /* Add a function to the list of static constructors. */
2773 microblaze_elf_asm_constructor (rtx symbol
, int priority
)
2775 microblaze_elf_asm_cdtor (symbol
, priority
, /*is_ctor=*/true);
2778 /* Add a function to the list of static destructors. */
2781 microblaze_elf_asm_destructor (rtx symbol
, int priority
)
2783 microblaze_elf_asm_cdtor (symbol
, priority
, /*is_ctor=*/false);
2786 /* Expand the prologue into a bunch of separate insns. */
2789 microblaze_expand_prologue (void)
2793 const char *arg_name
= 0;
2794 tree fndecl
= current_function_decl
;
2795 tree fntype
= TREE_TYPE (fndecl
);
2796 tree fnargs
= DECL_ARGUMENTS (fndecl
);
2801 CUMULATIVE_ARGS args_so_far_v
;
2802 cumulative_args_t args_so_far
;
2803 rtx mem_rtx
, reg_rtx
;
2805 /* If struct value address is treated as the first argument, make it so. */
2806 if (aggregate_value_p (DECL_RESULT (fndecl
), fntype
)
2807 && !cfun
->returns_pcc_struct
)
2809 tree type
= build_pointer_type (fntype
);
2810 tree function_result_decl
= build_decl (BUILTINS_LOCATION
, PARM_DECL
,
2813 DECL_ARG_TYPE (function_result_decl
) = type
;
2814 TREE_CHAIN (function_result_decl
) = fnargs
;
2815 fnargs
= function_result_decl
;
2818 /* Determine the last argument, and get its name. */
2820 INIT_CUMULATIVE_ARGS (args_so_far_v
, fntype
, NULL_RTX
, 0, 0);
2821 args_so_far
= pack_cumulative_args (&args_so_far_v
);
2822 regno
= GP_ARG_FIRST
;
2824 for (cur_arg
= fnargs
; cur_arg
!= 0; cur_arg
= next_arg
)
2826 tree passed_type
= DECL_ARG_TYPE (cur_arg
);
2827 machine_mode passed_mode
= TYPE_MODE (passed_type
);
2830 if (TREE_ADDRESSABLE (passed_type
))
2832 passed_type
= build_pointer_type (passed_type
);
2833 passed_mode
= Pmode
;
2836 entry_parm
= targetm
.calls
.function_arg (args_so_far
, passed_mode
,
2843 /* passed in a register, so will get homed automatically. */
2844 if (GET_MODE (entry_parm
) == BLKmode
)
2845 words
= (int_size_in_bytes (passed_type
) + 3) / 4;
2847 words
= (GET_MODE_SIZE (GET_MODE (entry_parm
)) + 3) / 4;
2849 regno
= REGNO (entry_parm
) + words
- 1;
2853 regno
= GP_ARG_LAST
+ 1;
2857 targetm
.calls
.function_arg_advance (args_so_far
, passed_mode
,
2860 next_arg
= TREE_CHAIN (cur_arg
);
2863 if (DECL_NAME (cur_arg
))
2864 arg_name
= IDENTIFIER_POINTER (DECL_NAME (cur_arg
));
2870 /* Split parallel insn into a sequence of insns. */
2872 next_arg_reg
= targetm
.calls
.function_arg (args_so_far
, VOIDmode
,
2873 void_type_node
, true);
2874 if (next_arg_reg
!= 0 && GET_CODE (next_arg_reg
) == PARALLEL
)
2876 rtvec adjust
= XVEC (next_arg_reg
, 0);
2877 int num
= GET_NUM_ELEM (adjust
);
2879 for (i
= 0; i
< num
; i
++)
2881 rtx pattern
= RTVEC_ELT (adjust
, i
);
2882 emit_insn (pattern
);
2886 fsiz
= compute_frame_size (get_frame_size ());
2888 if (flag_stack_usage_info
)
2889 current_function_static_stack_size
= fsiz
;
2892 /* If this function is a varargs function, store any registers that
2893 would normally hold arguments ($5 - $10) on the stack. */
2894 if (((TYPE_ARG_TYPES (fntype
) != 0
2895 && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype
)))
2898 && ((arg_name
[0] == '_'
2899 && strcmp (arg_name
, "__builtin_va_alist") == 0)
2900 || (arg_name
[0] == 'v'
2901 && strcmp (arg_name
, "va_alist") == 0)))))
2903 int offset
= (regno
- GP_ARG_FIRST
+ 1) * UNITS_PER_WORD
;
2904 rtx ptr
= stack_pointer_rtx
;
2906 /* If we are doing svr4-abi, sp has already been decremented by fsiz. */
2907 for (; regno
<= GP_ARG_LAST
; regno
++)
2910 ptr
= gen_rtx_PLUS (Pmode
, stack_pointer_rtx
, GEN_INT (offset
));
2911 emit_move_insn (gen_rtx_MEM (SImode
, ptr
),
2912 gen_rtx_REG (SImode
, regno
));
2914 offset
+= GET_MODE_SIZE (SImode
);
2921 rtx fsiz_rtx
= GEN_INT (fsiz
);
2923 rtx_insn
*insn
= NULL
;
2924 insn
= emit_insn (gen_subsi3 (stack_pointer_rtx
, stack_pointer_rtx
,
2927 RTX_FRAME_RELATED_P (insn
) = 1;
2929 /* Handle SUB_RETURN_ADDR_REGNUM specially at first. */
2930 if (!crtl
->is_leaf
|| interrupt_handler
)
2932 mem_rtx
= gen_rtx_MEM (SImode
,
2933 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
2936 if (interrupt_handler
)
2937 /* Do not optimize in flow analysis. */
2938 MEM_VOLATILE_P (mem_rtx
) = 1;
2940 reg_rtx
= gen_rtx_REG (SImode
, MB_ABI_SUB_RETURN_ADDR_REGNUM
);
2941 insn
= emit_move_insn (mem_rtx
, reg_rtx
);
2942 RTX_FRAME_RELATED_P (insn
) = 1;
2945 /* _save_ registers for prologue. */
2946 save_restore_insns (1);
2948 if (frame_pointer_needed
)
2952 insn
= emit_insn (gen_movsi (hard_frame_pointer_rtx
,
2953 stack_pointer_rtx
));
2956 RTX_FRAME_RELATED_P (insn
) = 1;
2960 if ((flag_pic
== 2 || TLS_NEEDS_GOT
)
2961 && df_regs_ever_live_p (MB_ABI_PIC_ADDR_REGNUM
))
2963 SET_REGNO (pic_offset_table_rtx
, MB_ABI_PIC_ADDR_REGNUM
);
2964 emit_insn (gen_set_got (pic_offset_table_rtx
)); /* setting GOT. */
2967 /* If we are profiling, make sure no instructions are scheduled before
2968 the call to mcount. */
2971 emit_insn (gen_blockage ());
2974 /* Do necessary cleanup after a function to restore stack, frame, and regs. */
2976 #define RA_MASK ((long) 0x80000000) /* 1 << 31 */
2977 #define PIC_OFFSET_TABLE_MASK (1 << (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST))
2980 microblaze_function_epilogue (FILE *file
)
2984 /* Get the function name the same way that toplev.c does before calling
2985 assemble_start_function. This is needed so that the name used here
2986 exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */
2987 fnname
= XSTR (XEXP (DECL_RTL (current_function_decl
), 0), 0);
2989 if (!flag_inhibit_size_directive
)
2991 fputs ("\t.end\t", file
);
2992 if (interrupt_handler
&& !break_handler
)
2993 fputs ("_interrupt_handler", file
);
2994 else if (break_handler
)
2995 fputs ("_break_handler", file
);
2997 assemble_name (file
, fnname
);
3001 /* Reset state info for each function. */
3002 current_frame_info
= zero_frame_info
;
3004 /* Restore the output file if optimizing the GP (optimizing the GP causes
3005 the text to be diverted to a tempfile, so that data decls come before
3006 references to the data). */
3009 /* Expand the epilogue into a bunch of separate insns. */
3012 microblaze_expand_epilogue (void)
3014 HOST_WIDE_INT fsiz
= current_frame_info
.total_size
;
3015 rtx fsiz_rtx
= GEN_INT (fsiz
);
3019 /* In case of interrupt handlers use addki instead of addi for changing the
3020 stack pointer value. */
3022 if (microblaze_can_use_return_insn ())
3024 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode
,
3026 MB_ABI_SUB_RETURN_ADDR_REGNUM
)));
3032 /* Restore SUB_RETURN_ADDR_REGNUM at first. This is to prevent the
3033 sequence of load-followed by a use (in rtsd) in every prologue. Saves
3034 a load-use stall cycle :) This is also important to handle alloca.
3035 (See comments for if (frame_pointer_needed) below. */
3037 if (!crtl
->is_leaf
|| interrupt_handler
)
3040 gen_rtx_MEM (SImode
,
3041 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
, const0_rtx
));
3042 if (interrupt_handler
)
3043 /* Do not optimize in flow analysis. */
3044 MEM_VOLATILE_P (mem_rtx
) = 1;
3045 reg_rtx
= gen_rtx_REG (SImode
, MB_ABI_SUB_RETURN_ADDR_REGNUM
);
3046 emit_move_insn (reg_rtx
, mem_rtx
);
3049 /* It is important that this is done after we restore the return address
3050 register (above). When alloca is used, we want to restore the
3051 sub-routine return address only from the current stack top and not
3052 from the frame pointer (which we restore below). (frame_pointer + 0)
3053 might have been over-written since alloca allocates memory on the
3055 if (frame_pointer_needed
)
3056 emit_insn (gen_movsi (stack_pointer_rtx
, hard_frame_pointer_rtx
));
3058 /* _restore_ registers for epilogue. */
3059 save_restore_insns (0);
3060 emit_insn (gen_blockage ());
3061 emit_insn (gen_addsi3 (stack_pointer_rtx
, stack_pointer_rtx
, fsiz_rtx
));
3064 if (crtl
->calls_eh_return
)
3065 emit_insn (gen_addsi3 (stack_pointer_rtx
,
3067 gen_raw_REG (SImode
,
3068 MB_EH_STACKADJ_REGNUM
)));
3070 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode
, GP_REG_FIRST
+
3071 MB_ABI_SUB_RETURN_ADDR_REGNUM
)));
3075 /* Return nonzero if this function is known to have a null epilogue.
3076 This allows the optimizer to omit jumps to jumps if no stack
3080 microblaze_can_use_return_insn (void)
3082 if (!reload_completed
)
3085 if (df_regs_ever_live_p (MB_ABI_SUB_RETURN_ADDR_REGNUM
) || profile_flag
)
3088 if (current_frame_info
.initialized
)
3089 return current_frame_info
.total_size
== 0;
3091 return compute_frame_size (get_frame_size ()) == 0;
3094 /* Implement TARGET_SECONDARY_RELOAD. */
3097 microblaze_secondary_reload (bool in_p ATTRIBUTE_UNUSED
, rtx x ATTRIBUTE_UNUSED
,
3098 reg_class_t rclass
, machine_mode mode ATTRIBUTE_UNUSED
,
3099 secondary_reload_info
*sri ATTRIBUTE_UNUSED
)
3101 if (rclass
== ST_REGS
)
3108 microblaze_globalize_label (FILE * stream
, const char *name
)
3110 fputs ("\t.globl\t", stream
);
3111 if (microblaze_is_interrupt_variant ())
3113 if (interrupt_handler
&& strcmp (name
, INTERRUPT_HANDLER_NAME
))
3114 fputs (INTERRUPT_HANDLER_NAME
, stream
);
3115 else if (break_handler
&& strcmp (name
, BREAK_HANDLER_NAME
))
3116 fputs (BREAK_HANDLER_NAME
, stream
);
3117 else if (fast_interrupt
&& strcmp (name
, FAST_INTERRUPT_NAME
))
3118 fputs (FAST_INTERRUPT_NAME
, stream
);
3119 fputs ("\n\t.globl\t", stream
);
3121 assemble_name (stream
, name
);
3122 fputs ("\n", stream
);
3125 /* Returns true if decl should be placed into a "small data" section. */
3127 microblaze_elf_in_small_data_p (const_tree decl
)
3131 if (!TARGET_XLGPOPT
)
3134 /* We want to merge strings, so we never consider them small data. */
3135 if (TREE_CODE (decl
) == STRING_CST
)
3138 /* Functions are never in the small data area. */
3139 if (TREE_CODE (decl
) == FUNCTION_DECL
)
3142 if (TREE_CODE (decl
) == VAR_DECL
&& DECL_SECTION_NAME (decl
))
3144 const char *section
= DECL_SECTION_NAME (decl
);
3145 if (strcmp (section
, ".sdata") == 0
3146 || strcmp (section
, ".sdata2") == 0
3147 || strcmp (section
, ".sbss") == 0
3148 || strcmp (section
, ".sbss2") == 0)
3152 size
= int_size_in_bytes (TREE_TYPE (decl
));
3154 return (size
> 0 && size
<= microblaze_section_threshold
);
3159 microblaze_select_section (tree decl
, int reloc
, unsigned HOST_WIDE_INT align
)
3161 switch (categorize_decl_for_section (decl
, reloc
))
3163 case SECCAT_RODATA_MERGE_STR
:
3164 case SECCAT_RODATA_MERGE_STR_INIT
:
3165 /* MB binutils have various issues with mergeable string sections and
3166 relaxation/relocation. Currently, turning mergeable sections
3167 into regular readonly sections. */
3169 return readonly_data_section
;
3171 return default_elf_select_section (decl
, reloc
, align
);
3176 Encode info about sections into the RTL based on a symbol's declaration.
3177 The default definition of this hook, default_encode_section_info in
3178 `varasm.c', sets a number of commonly-useful bits in SYMBOL_REF_FLAGS. */
3181 microblaze_encode_section_info (tree decl
, rtx rtl
, int first
)
3183 default_encode_section_info (decl
, rtl
, first
);
3187 expand_pic_symbol_ref (machine_mode mode ATTRIBUTE_UNUSED
, rtx op
)
3190 result
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, op
), UNSPEC_GOTOFF
);
3191 result
= gen_rtx_CONST (Pmode
, result
);
3192 result
= gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
, result
);
3193 result
= gen_const_mem (Pmode
, result
);
3198 microblaze_asm_output_mi_thunk (FILE *file
, tree thunk_fndecl ATTRIBUTE_UNUSED
,
3199 HOST_WIDE_INT delta
, HOST_WIDE_INT vcall_offset
,
3202 rtx this_rtx
, funexp
;
3205 reload_completed
= 1;
3206 epilogue_completed
= 1;
3208 /* Mark the end of the (empty) prologue. */
3209 emit_note (NOTE_INSN_PROLOGUE_END
);
3211 /* Find the "this" pointer. If the function returns a structure,
3212 the structure return pointer is in MB_ABI_FIRST_ARG_REGNUM. */
3213 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function
)), function
))
3214 this_rtx
= gen_rtx_REG (Pmode
, (MB_ABI_FIRST_ARG_REGNUM
+ 1));
3216 this_rtx
= gen_rtx_REG (Pmode
, MB_ABI_FIRST_ARG_REGNUM
);
3218 /* Apply the constant offset, if required. */
3220 emit_insn (gen_addsi3 (this_rtx
, this_rtx
, GEN_INT (delta
)));
3222 /* Apply the offset from the vtable, if required. */
3225 rtx vcall_offset_rtx
= GEN_INT (vcall_offset
);
3226 rtx temp1
= gen_rtx_REG (Pmode
, MB_ABI_TEMP1_REGNUM
);
3228 emit_move_insn (temp1
, gen_rtx_MEM (Pmode
, this_rtx
));
3230 rtx loc
= gen_rtx_PLUS (Pmode
, temp1
, vcall_offset_rtx
);
3231 emit_move_insn (temp1
, gen_rtx_MEM (Pmode
, loc
));
3233 emit_insn (gen_addsi3 (this_rtx
, this_rtx
, temp1
));
3236 /* Generate a tail call to the target function. */
3237 if (!TREE_USED (function
))
3239 assemble_external (function
);
3240 TREE_USED (function
) = 1;
3243 funexp
= XEXP (DECL_RTL (function
), 0);
3244 rtx temp2
= gen_rtx_REG (Pmode
, MB_ABI_TEMP2_REGNUM
);
3247 emit_move_insn (temp2
, expand_pic_symbol_ref (Pmode
, funexp
));
3249 emit_move_insn (temp2
, funexp
);
3251 emit_insn (gen_indirect_jump (temp2
));
3253 /* Run just enough of rest_of_compilation. This sequence was
3254 "borrowed" from rs6000.c. */
3255 insn
= get_insns ();
3256 shorten_branches (insn
);
3257 final_start_function (insn
, file
, 1);
3258 final (insn
, file
, 1);
3259 final_end_function ();
3261 reload_completed
= 0;
3262 epilogue_completed
= 0;
3266 microblaze_expand_move (machine_mode mode
, rtx operands
[])
3273 if (!register_operand (op0
, SImode
)
3274 && !register_operand (op1
, SImode
)
3275 && (GET_CODE (op1
) != CONST_INT
|| INTVAL (op1
) != 0))
3277 rtx temp
= force_reg (SImode
, op1
);
3278 emit_move_insn (op0
, temp
);
3281 /* If operands[1] is a constant address invalid for pic, then we need to
3282 handle it just like LEGITIMIZE_ADDRESS does. */
3283 if (GET_CODE (op1
) == SYMBOL_REF
|| GET_CODE (op1
) == LABEL_REF
)
3286 if (microblaze_tls_symbol_p(op1
))
3288 result
= microblaze_legitimize_tls_address (op1
, NULL_RTX
);
3289 emit_move_insn (op0
, result
);
3294 if (reload_in_progress
)
3295 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
3296 result
= expand_pic_symbol_ref (mode
, op1
);
3297 emit_move_insn (op0
, result
);
3301 /* Handle Case of (const (plus symbol const_int)). */
3302 if (GET_CODE (op1
) == CONST
&& GET_CODE (XEXP (op1
,0)) == PLUS
)
3306 p0
= XEXP (XEXP (op1
, 0), 0);
3307 p1
= XEXP (XEXP (op1
, 0), 1);
3309 if ((GET_CODE (p1
) == CONST_INT
)
3310 && ((GET_CODE (p0
) == UNSPEC
)
3311 || ((GET_CODE (p0
) == SYMBOL_REF
|| GET_CODE (p0
) == LABEL_REF
)
3312 && (flag_pic
== 2 || microblaze_tls_symbol_p (p0
)
3313 || !SMALL_INT (p1
)))))
3315 rtx temp
= force_reg (SImode
, p0
);
3318 if (flag_pic
&& reload_in_progress
)
3319 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
3320 emit_move_insn (op0
, gen_rtx_PLUS (SImode
, temp
, temp2
));
3327 /* Expand shift operations. */
3329 microblaze_expand_shift (rtx operands
[])
3331 gcc_assert ((GET_CODE (operands
[2]) == CONST_INT
)
3332 || (GET_CODE (operands
[2]) == REG
)
3333 || (GET_CODE (operands
[2]) == SUBREG
));
3335 /* Shift by one -- generate pattern. */
3336 if ((GET_CODE (operands
[2]) == CONST_INT
) && (INTVAL (operands
[2]) == 1))
3339 /* Have barrel shifter and shift > 1: use it. */
3340 if (TARGET_BARREL_SHIFT
)
3343 gcc_assert ((GET_CODE (operands
[0]) == REG
)
3344 || (GET_CODE (operands
[0]) == SUBREG
)
3345 || (GET_CODE (operands
[1]) == REG
)
3346 || (GET_CODE (operands
[1]) == SUBREG
));
3348 /* Shift by zero -- copy regs if necessary. */
3349 if (operands
[2] == const0_rtx
3350 && !rtx_equal_p (operands
[0], operands
[1]))
3352 emit_insn (gen_movsi (operands
[0], operands
[1]));
3359 /* Return an RTX indicating where the return address to the
3360 calling function can be found. */
3362 microblaze_return_addr (int count
, rtx frame ATTRIBUTE_UNUSED
)
3367 return get_hard_reg_initial_val (Pmode
,
3368 MB_ABI_SUB_RETURN_ADDR_REGNUM
);
3372 microblaze_eh_return (rtx op0
)
3374 emit_insn (gen_movsi (gen_rtx_MEM (Pmode
, stack_pointer_rtx
), op0
));
3377 /* Queue an .ident string in the queue of top-level asm statements.
3378 If the string size is below the threshold, put it into .sdata2.
3379 If the front-end is done, we must be being called from toplev.c.
3380 In that case, do nothing. */
3382 microblaze_asm_output_ident (const char *string
)
3384 const char *section_asm_op
;
3388 if (symtab
->state
!= PARSING
)
3391 size
= strlen (string
) + 1;
3392 if (size
<= microblaze_section_threshold
)
3393 section_asm_op
= SDATA2_SECTION_ASM_OP
;
3395 section_asm_op
= READONLY_DATA_SECTION_ASM_OP
;
3397 buf
= ACONCAT (("\t.pushsection", section_asm_op
,
3398 "\n\t.ascii \"", string
, "\\0\"\n",
3399 "\t.popsection\n", NULL
));
3400 symtab
->finalize_toplevel_asm (build_string (strlen (buf
), buf
));
3404 microblaze_elf_asm_init_sections (void)
3407 = get_unnamed_section (SECTION_WRITE
, output_section_asm_op
,
3408 SDATA2_SECTION_ASM_OP
);
3411 /* Generate assembler code for constant parts of a trampoline. */
3414 microblaze_asm_trampoline_template (FILE *f
)
3416 fprintf (f
, "\tmfs r18, rpc\n");
3417 fprintf (f
, "\tlwi r3, r18, 16\n");
3418 fprintf (f
, "\tlwi r18, r18, 20\n");
3419 fprintf (f
, "\tbra r18\n");
3420 /* fprintf (f, "\t.word\t0x00000000\t\t# <function address>\n"); */
3421 /* fprintf (f, "\t.word\t0x00000000\t\t# <static chain value>\n"); */
3424 /* Implement TARGET_TRAMPOLINE_INIT. */
3427 microblaze_trampoline_init (rtx m_tramp
, tree fndecl
, rtx chain_value
)
3429 rtx fnaddr
= XEXP (DECL_RTL (fndecl
), 0);
3432 emit_block_move (m_tramp
, assemble_trampoline_template (),
3433 GEN_INT (6*UNITS_PER_WORD
), BLOCK_OP_NORMAL
);
3435 mem
= adjust_address (m_tramp
, SImode
, 16);
3436 emit_move_insn (mem
, chain_value
);
3437 mem
= adjust_address (m_tramp
, SImode
, 20);
3438 emit_move_insn (mem
, fnaddr
);
3441 /* Generate conditional branch -- first, generate test condition,
3442 second, generate correct branch instruction. */
3445 microblaze_expand_conditional_branch (machine_mode mode
, rtx operands
[])
3447 enum rtx_code code
= GET_CODE (operands
[0]);
3448 rtx cmp_op0
= operands
[1];
3449 rtx cmp_op1
= operands
[2];
3450 rtx label1
= operands
[3];
3451 rtx comp_reg
= gen_reg_rtx (SImode
);
3454 gcc_assert ((GET_CODE (cmp_op0
) == REG
) || (GET_CODE (cmp_op0
) == SUBREG
));
3456 /* If comparing against zero, just test source reg. */
3457 if (cmp_op1
== const0_rtx
)
3460 condition
= gen_rtx_fmt_ee (signed_condition (code
), SImode
, comp_reg
, const0_rtx
);
3461 emit_jump_insn (gen_condjump (condition
, label1
));
3464 else if (code
== EQ
|| code
== NE
)
3466 /* Use xor for equal/not-equal comparison. */
3467 emit_insn (gen_xorsi3 (comp_reg
, cmp_op0
, cmp_op1
));
3468 condition
= gen_rtx_fmt_ee (signed_condition (code
), SImode
, comp_reg
, const0_rtx
);
3469 emit_jump_insn (gen_condjump (condition
, label1
));
3473 /* Generate compare and branch in single instruction. */
3474 cmp_op1
= force_reg (mode
, cmp_op1
);
3475 condition
= gen_rtx_fmt_ee (code
, mode
, cmp_op0
, cmp_op1
);
3476 emit_jump_insn (gen_branch_compare(condition
, cmp_op0
, cmp_op1
, label1
));
3481 microblaze_expand_conditional_branch_reg (machine_mode mode
, rtx operands
[])
3483 enum rtx_code code
= GET_CODE (operands
[0]);
3484 rtx cmp_op0
= operands
[1];
3485 rtx cmp_op1
= operands
[2];
3486 rtx label1
= operands
[3];
3487 rtx comp_reg
= gen_reg_rtx (SImode
);
3490 gcc_assert ((GET_CODE (cmp_op0
) == REG
)
3491 || (GET_CODE (cmp_op0
) == SUBREG
));
3493 /* If comparing against zero, just test source reg. */
3494 if (cmp_op1
== const0_rtx
)
3497 condition
= gen_rtx_fmt_ee (signed_condition (code
),
3498 SImode
, comp_reg
, const0_rtx
);
3499 emit_jump_insn (gen_condjump (condition
, label1
));
3501 else if (code
== EQ
)
3503 emit_insn (gen_seq_internal_pat (comp_reg
,
3505 condition
= gen_rtx_EQ (SImode
, comp_reg
, const0_rtx
);
3506 emit_jump_insn (gen_condjump (condition
, label1
));
3508 else if (code
== NE
)
3510 emit_insn (gen_sne_internal_pat (comp_reg
, cmp_op0
,
3512 condition
= gen_rtx_NE (SImode
, comp_reg
, const0_rtx
);
3513 emit_jump_insn (gen_condjump (condition
, label1
));
3517 /* Generate compare and branch in single instruction. */
3518 cmp_op1
= force_reg (mode
, cmp_op1
);
3519 condition
= gen_rtx_fmt_ee (code
, mode
, cmp_op0
, cmp_op1
);
3520 emit_jump_insn (gen_branch_compare (condition
, cmp_op0
,
3526 microblaze_expand_conditional_branch_sf (rtx operands
[])
3529 rtx cmp_op0
= XEXP (operands
[0], 0);
3530 rtx cmp_op1
= XEXP (operands
[0], 1);
3531 rtx comp_reg
= gen_reg_rtx (SImode
);
3533 emit_insn (gen_cstoresf4 (comp_reg
, operands
[0], cmp_op0
, cmp_op1
));
3534 condition
= gen_rtx_NE (SImode
, comp_reg
, const0_rtx
);
3535 emit_jump_insn (gen_condjump (condition
, operands
[3]));
3538 /* Implement TARGET_FRAME_POINTER_REQUIRED. */
3541 microblaze_frame_pointer_required (void)
3543 /* If the function contains dynamic stack allocations, we need to
3544 use the frame pointer to access the static parts of the frame. */
3545 if (cfun
->calls_alloca
)
3551 microblaze_expand_divide (rtx operands
[])
3553 /* Table lookup software divides. Works for all (nr/dr) where (0 <= nr,dr <= 15). */
3555 rtx regt1
= gen_reg_rtx (SImode
);
3556 rtx reg18
= gen_rtx_REG (SImode
, R_TMP
);
3557 rtx regqi
= gen_reg_rtx (QImode
);
3558 rtx_code_label
*div_label
= gen_label_rtx ();
3559 rtx_code_label
*div_end_label
= gen_label_rtx ();
3560 rtx div_table_rtx
= gen_rtx_SYMBOL_REF (QImode
,"_divsi3_table");
3563 rtx_insn
*jump
, *cjump
, *insn
;
3565 insn
= emit_insn (gen_iorsi3 (regt1
, operands
[1], operands
[2]));
3566 cjump
= emit_jump_insn_after (gen_cbranchsi4 (
3567 gen_rtx_GTU (SImode
, regt1
, GEN_INT (15)),
3568 regt1
, GEN_INT (15), div_label
), insn
);
3569 LABEL_NUSES (div_label
) = 1;
3570 JUMP_LABEL (cjump
) = div_label
;
3571 emit_insn (gen_rtx_CLOBBER (SImode
, reg18
));
3573 emit_insn (gen_ashlsi3_bshift (regt1
, operands
[1], GEN_INT(4)));
3574 emit_insn (gen_addsi3 (regt1
, regt1
, operands
[2]));
3575 mem_rtx
= gen_rtx_MEM (QImode
,
3576 gen_rtx_PLUS (Pmode
, regt1
, div_table_rtx
));
3578 insn
= emit_insn (gen_movqi (regqi
, mem_rtx
));
3579 insn
= emit_insn (gen_movsi (operands
[0], gen_rtx_SUBREG (SImode
, regqi
, 0)));
3580 jump
= emit_jump_insn_after (gen_jump (div_end_label
), insn
);
3581 JUMP_LABEL (jump
) = div_end_label
;
3582 LABEL_NUSES (div_end_label
) = 1;
3585 emit_label (div_label
);
3586 ret
= emit_library_call_value (gen_rtx_SYMBOL_REF (Pmode
, "__divsi3"),
3587 operands
[0], LCT_NORMAL
,
3588 GET_MODE (operands
[0]),
3589 operands
[1], GET_MODE (operands
[1]),
3590 operands
[2], GET_MODE (operands
[2]));
3591 if (ret
!= operands
[0])
3592 emit_move_insn (operands
[0], ret
);
3594 emit_label (div_end_label
);
3595 emit_insn (gen_blockage ());
3598 /* Implement TARGET_FUNCTION_VALUE. */
3600 microblaze_function_value (const_tree valtype
,
3601 const_tree func ATTRIBUTE_UNUSED
,
3602 bool outgoing ATTRIBUTE_UNUSED
)
3604 return LIBCALL_VALUE (TYPE_MODE (valtype
));
3607 /* Implement TARGET_SCHED_ADJUST_COST. */
3609 microblaze_adjust_cost (rtx_insn
*, int dep_type
, rtx_insn
*, int cost
,
3612 if (dep_type
== REG_DEP_OUTPUT
|| dep_type
== 0)
3617 /* Implement TARGET_LEGITIMATE_CONSTANT_P.
3619 At present, GAS doesn't understand li.[sd], so don't allow it
3620 to be generated at present. */
3622 microblaze_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED
, rtx x
)
3625 if (microblaze_cannot_force_const_mem(mode
, x
))
3628 if (GET_CODE (x
) == CONST_DOUBLE
)
3630 return microblaze_const_double_ok (x
, GET_MODE (x
));
3633 /* Handle Case of (const (plus unspec const_int)). */
3634 if (GET_CODE (x
) == CONST
&& GET_CODE (XEXP (x
,0)) == PLUS
)
3638 p0
= XEXP (XEXP (x
, 0), 0);
3639 p1
= XEXP (XEXP (x
, 0), 1);
3641 if (GET_CODE(p1
) == CONST_INT
)
3643 /* Const offset from UNSPEC is not supported. */
3644 if ((GET_CODE (p0
) == UNSPEC
))
3647 if ((GET_CODE (p0
) == SYMBOL_REF
|| GET_CODE (p0
) == LABEL_REF
)
3648 && (microblaze_tls_symbol_p (p0
) || !SMALL_INT (p1
)))
3657 get_branch_target (rtx branch
)
3659 if (CALL_P (branch
))
3663 call
= XVECEXP (PATTERN (branch
), 0, 0);
3664 if (GET_CODE (call
) == SET
)
3665 call
= SET_SRC (call
);
3666 if (GET_CODE (call
) != CALL
)
3668 return XEXP (XEXP (call
, 0), 0);
3674 /* Heuristics to identify where to insert at the
3675 fall through path of the caller function. If there
3676 is a call after the caller branch delay slot then
3677 we dont generate the instruction prefetch instruction.
3679 Scan up to 32 instructions after the call and checks
3680 for the JUMP and call instruction . If there is a call
3681 or JUMP instruction in the range of 32 instruction "wic"
3682 instruction wont be generated. Otherwise insert the "wic"
3683 instruction in the fall through of the call instruction
3684 four instruction after the call. before_4 is used for
3685 the position to insert "wic" instructions. before_16 is
3686 used to check for call and JUMP instruction for first
3690 insert_wic_for_ilb_runout (rtx_insn
*first
)
3693 rtx_insn
*before_4
= 0;
3694 rtx_insn
*before_16
= 0;
3695 int addr_offset
= 0;
3697 int wic_addr0
= 128 * 4;
3699 int first_addr
= INSN_ADDRESSES (INSN_UID (first
));
3701 for (insn
= first
; insn
; insn
= NEXT_INSN (insn
))
3704 addr_offset
= INSN_ADDRESSES (INSN_UID (insn
)) - first_addr
;
3705 length
= get_attr_length (insn
);
3706 if (before_4
== 0 && addr_offset
+ length
>= 4 * 4)
3711 if (before_16
== 0 && addr_offset
+ length
>= 14 * 4)
3713 if (CALL_P (insn
) || tablejump_p (insn
, 0, 0))
3715 if (addr_offset
+ length
>= 32 * 4)
3717 gcc_assert (before_4
&& before_16
);
3718 if (wic_addr0
> 4 * 4)
3721 emit_insn_before (gen_iprefetch
3722 (gen_int_mode (addr_offset
, SImode
)),
3724 recog_memoized (insn
);
3725 INSN_LOCATION (insn
) = INSN_LOCATION (before_4
);
3726 INSN_ADDRESSES_NEW (insn
, INSN_ADDRESSES (INSN_UID (before_4
)));
3733 /* Insert instruction prefetch instruction at the fall
3734 through path of the function call. */
3741 basic_block bb
, prev
= 0;
3742 rtx branch_target
= 0;
3744 shorten_branches (get_insns ());
3746 for (i
= 0; i
< n_basic_blocks_for_fn (cfun
) - 1; i
++)
3750 bool simple_loop
= false;
3752 bb
= BASIC_BLOCK_FOR_FN (cfun
, i
);
3757 if ((prev
!= 0) && (prev
!= bb
))
3762 FOR_EACH_EDGE (e
, ei
, bb
->preds
)
3770 for (insn
= BB_END (bb
); insn
; insn
= PREV_INSN (insn
))
3772 if (INSN_P (insn
) && !simple_loop
3775 if ((branch_target
= get_branch_target (insn
)))
3776 insert_wic_for_ilb_runout (
3777 next_active_insn (next_active_insn (insn
)));
3779 if (insn
== BB_HEAD (bb
))
3785 /* The reorg function defined through the macro
3786 TARGET_MACHINE_DEPENDENT_REORG. */
3789 microblaze_machine_dependent_reorg (void)
3791 if (TARGET_PREFETCH
)
3793 compute_bb_for_insn ();
3794 loop_optimizer_init (AVOID_CFG_MODIFICATIONS
);
3795 shorten_branches (get_insns ());
3797 loop_optimizer_finalize ();
3798 free_bb_for_insn ();
3803 /* Implement TARGET_CONSTANT_ALIGNMENT. */
3805 static HOST_WIDE_INT
3806 microblaze_constant_alignment (const_tree exp
, HOST_WIDE_INT align
)
3808 if (TREE_CODE (exp
) == STRING_CST
|| TREE_CODE (exp
) == CONSTRUCTOR
)
3809 return MAX (align
, BITS_PER_WORD
);
3813 /* Implement TARGET_STARTING_FRAME_OFFSET. */
3815 static HOST_WIDE_INT
3816 microblaze_starting_frame_offset (void)
3818 return (crtl
->outgoing_args_size
+ FIRST_PARM_OFFSET(FNDECL
));
3821 #undef TARGET_ENCODE_SECTION_INFO
3822 #define TARGET_ENCODE_SECTION_INFO microblaze_encode_section_info
3824 #undef TARGET_ASM_GLOBALIZE_LABEL
3825 #define TARGET_ASM_GLOBALIZE_LABEL microblaze_globalize_label
3827 #undef TARGET_ASM_FUNCTION_PROLOGUE
3828 #define TARGET_ASM_FUNCTION_PROLOGUE microblaze_function_prologue
3830 #undef TARGET_ASM_FUNCTION_EPILOGUE
3831 #define TARGET_ASM_FUNCTION_EPILOGUE microblaze_function_epilogue
3833 #undef TARGET_RTX_COSTS
3834 #define TARGET_RTX_COSTS microblaze_rtx_costs
3836 #undef TARGET_CANNOT_FORCE_CONST_MEM
3837 #define TARGET_CANNOT_FORCE_CONST_MEM microblaze_cannot_force_const_mem
3839 #undef TARGET_ADDRESS_COST
3840 #define TARGET_ADDRESS_COST microblaze_address_cost
3842 #undef TARGET_ATTRIBUTE_TABLE
3843 #define TARGET_ATTRIBUTE_TABLE microblaze_attribute_table
3845 #undef TARGET_IN_SMALL_DATA_P
3846 #define TARGET_IN_SMALL_DATA_P microblaze_elf_in_small_data_p
3848 #undef TARGET_ASM_SELECT_SECTION
3849 #define TARGET_ASM_SELECT_SECTION microblaze_select_section
3851 #undef TARGET_HAVE_SRODATA_SECTION
3852 #define TARGET_HAVE_SRODATA_SECTION true
3854 #undef TARGET_ASM_FUNCTION_END_PROLOGUE
3855 #define TARGET_ASM_FUNCTION_END_PROLOGUE \
3856 microblaze_function_end_prologue
3858 #undef TARGET_ARG_PARTIAL_BYTES
3859 #define TARGET_ARG_PARTIAL_BYTES function_arg_partial_bytes
3861 #undef TARGET_FUNCTION_ARG
3862 #define TARGET_FUNCTION_ARG microblaze_function_arg
3864 #undef TARGET_FUNCTION_ARG_ADVANCE
3865 #define TARGET_FUNCTION_ARG_ADVANCE microblaze_function_arg_advance
3867 #undef TARGET_CAN_ELIMINATE
3868 #define TARGET_CAN_ELIMINATE microblaze_can_eliminate
3870 #undef TARGET_LEGITIMIZE_ADDRESS
3871 #define TARGET_LEGITIMIZE_ADDRESS microblaze_legitimize_address
3873 #undef TARGET_LEGITIMATE_ADDRESS_P
3874 #define TARGET_LEGITIMATE_ADDRESS_P microblaze_legitimate_address_p
3877 #define TARGET_LRA_P hook_bool_void_false
3879 #undef TARGET_FRAME_POINTER_REQUIRED
3880 #define TARGET_FRAME_POINTER_REQUIRED microblaze_frame_pointer_required
3882 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
3883 #define TARGET_ASM_TRAMPOLINE_TEMPLATE microblaze_asm_trampoline_template
3885 #undef TARGET_TRAMPOLINE_INIT
3886 #define TARGET_TRAMPOLINE_INIT microblaze_trampoline_init
3888 #undef TARGET_PROMOTE_FUNCTION_MODE
3889 #define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
3891 #undef TARGET_FUNCTION_VALUE
3892 #define TARGET_FUNCTION_VALUE microblaze_function_value
3894 #undef TARGET_SECONDARY_RELOAD
3895 #define TARGET_SECONDARY_RELOAD microblaze_secondary_reload
3897 #undef TARGET_ASM_OUTPUT_MI_THUNK
3898 #define TARGET_ASM_OUTPUT_MI_THUNK microblaze_asm_output_mi_thunk
3900 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
3901 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true
3903 #undef TARGET_SCHED_ADJUST_COST
3904 #define TARGET_SCHED_ADJUST_COST microblaze_adjust_cost
3906 #undef TARGET_ASM_INIT_SECTIONS
3907 #define TARGET_ASM_INIT_SECTIONS microblaze_elf_asm_init_sections
3909 #undef TARGET_OPTION_OVERRIDE
3910 #define TARGET_OPTION_OVERRIDE microblaze_option_override
3912 #undef TARGET_LEGITIMATE_CONSTANT_P
3913 #define TARGET_LEGITIMATE_CONSTANT_P microblaze_legitimate_constant_p
3915 #undef TARGET_MACHINE_DEPENDENT_REORG
3916 #define TARGET_MACHINE_DEPENDENT_REORG microblaze_machine_dependent_reorg
3918 #undef TARGET_HARD_REGNO_MODE_OK
3919 #define TARGET_HARD_REGNO_MODE_OK microblaze_hard_regno_mode_ok
3921 #undef TARGET_MODES_TIEABLE_P
3922 #define TARGET_MODES_TIEABLE_P microblaze_modes_tieable_p
3924 #undef TARGET_CONSTANT_ALIGNMENT
3925 #define TARGET_CONSTANT_ALIGNMENT microblaze_constant_alignment
3927 #undef TARGET_STARTING_FRAME_OFFSET
3928 #define TARGET_STARTING_FRAME_OFFSET microblaze_starting_frame_offset
3930 struct gcc_target targetm
= TARGET_INITIALIZER
;
3932 #include "gt-microblaze.h"