1 /* Subroutines used for code generation on Xilinx MicroBlaze.
2 Copyright (C) 2009-2022 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"
56 /* This file should be included last. */
57 #include "target-def.h"
59 #define MICROBLAZE_VERSION_COMPARE(VA,VB) strcasecmp (VA, VB)
61 /* Classifies an address.
68 A natural register or a register + const_int offset address.
69 The register satisfies microblaze_valid_base_register_p and the
70 offset is a const_arith_operand.
74 A natural register offset by the index contained in an index register. The base
75 register satisfies microblaze_valid_base_register_p and the index register
76 satisfies microblaze_valid_index_register_p
80 A signed 16/32-bit constant address.
84 A constant symbolic address or a (register + symbol). */
86 enum microblaze_address_type
96 ADDRESS_SYMBOLIC_TXT_REL
104 enum microblaze_symbol_type
110 /* TLS Address Type. */
119 /* Classification of a MicroBlaze address. */
120 struct microblaze_address_info
122 enum microblaze_address_type type
;
123 rtx regA
; /* Contains valid values on ADDRESS_REG, ADDRESS_REG_INDEX,
125 rtx regB
; /* Contains valid values on ADDRESS_REG_INDEX. */
126 rtx offset
; /* Contains valid values on ADDRESS_CONST_INT and ADDRESS_REG. */
127 rtx symbol
; /* Contains valid values on ADDRESS_SYMBOLIC. */
128 enum microblaze_symbol_type symbol_type
;
129 enum tls_reloc tls_type
;
132 /* Structure to be filled in by compute_frame_size with register
133 save masks, and offsets for the current function. */
135 struct GTY(()) microblaze_frame_info
{
136 long total_size
; /* # bytes that the entire frame takes up. */
137 long var_size
; /* # bytes that variables take up. */
138 long args_size
; /* # bytes that outgoing arguments take up. */
139 int link_debug_size
; /* # bytes for the link reg and back pointer. */
140 int gp_reg_size
; /* # bytes needed to store gp regs. */
141 long gp_offset
; /* offset from new sp to store gp registers. */
142 long mask
; /* mask of saved gp registers. */
143 int initialized
; /* != 0 if frame size already calculated. */
144 int num_gp
; /* number of gp registers saved. */
145 long insns_len
; /* length of insns. */
146 int alloc_stack
; /* Flag to indicate if the current function
147 must not create stack space. (As an optimization). */
150 /* Global variables for machine-dependent things. */
152 /* Toggle which pipleline interface to use. */
153 static GTY(()) int microblaze_sched_use_dfa
= 0;
155 /* Threshold for data being put into the small data/bss area, instead
156 of the normal data area (references to the small data/bss area take
157 1 instruction, and use the global pointer, references to the normal
158 data area takes 2 instructions). */
159 int microblaze_section_threshold
= -1;
161 /* Prevent scheduling potentially exception causing instructions in
162 delay slots. -mcpu=v3.00.a or v4.00.a turns this on. */
163 int microblaze_no_unsafe_delay
;
165 /* Set to one if the targeted core has the CLZ insn. */
166 int microblaze_has_clz
= 0;
168 /* Which CPU pipeline do we use. We haven't really standardized on a CPU
169 version having only a particular type of pipeline. There can still be
170 options on the CPU to scale pipeline features up or down. :(
171 Bad Presentation (??), so we let the MD file rely on the value of
172 this variable instead Making PIPE_5 the default. It should be backward
173 optimal with PIPE_3 MicroBlazes. */
174 enum pipeline_type microblaze_pipe
= MICROBLAZE_PIPE_5
;
176 /* High and low marks for floating point values which we will accept
177 as legitimate constants for TARGET_LEGITIMATE_CONSTANT_P. These are
178 initialized in override_options. */
179 REAL_VALUE_TYPE dfhigh
, dflow
, sfhigh
, sflow
;
181 /* Array giving truth value on whether or not a given hard register
182 can support a given mode. */
183 static char microblaze_hard_regno_mode_ok_p
[(int)MAX_MACHINE_MODE
]
184 [FIRST_PSEUDO_REGISTER
];
186 /* Current frame information calculated by compute_frame_size. */
187 struct microblaze_frame_info current_frame_info
;
189 /* Zero structure to initialize current_frame_info. */
190 struct microblaze_frame_info zero_frame_info
;
192 /* List of all MICROBLAZE punctuation characters used by print_operand. */
193 char microblaze_print_operand_punct
[256];
195 /* Map GCC register number to debugger register number. */
196 int microblaze_dbx_regno
[FIRST_PSEUDO_REGISTER
];
198 /* Map hard register number to register class. */
199 enum reg_class microblaze_regno_to_class
[] =
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 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
208 GR_REGS
, GR_REGS
, GR_REGS
, GR_REGS
,
209 ST_REGS
, GR_REGS
, GR_REGS
, GR_REGS
212 /* MicroBlaze specific machine attributes.
213 interrupt_handler - Interrupt handler attribute to add interrupt prologue
214 and epilogue and use appropriate interrupt return.
215 save_volatiles - Similar to interrupt handler, but use normal return. */
216 int interrupt_handler
;
221 const struct attribute_spec microblaze_attribute_table
[] = {
222 /* name min_len, max_len, decl_req, type_req, fn_type_req,
223 affects_type_identity, handler, exclude */
224 {"interrupt_handler", 0, 0, true, false, false, false, NULL
, NULL
},
225 {"break_handler", 0, 0, true, false, false, false, NULL
, NULL
},
226 {"fast_interrupt", 0, 0, true, false, false, false, NULL
, NULL
},
227 {"save_volatiles", 0, 0, true, false, false, false, NULL
, NULL
},
228 { NULL
, 0, 0, false, false, false, false, NULL
, NULL
}
231 static int microblaze_interrupt_function_p (tree
);
233 static void microblaze_elf_asm_constructor (rtx
, int) ATTRIBUTE_UNUSED
;
234 static void microblaze_elf_asm_destructor (rtx
, int) ATTRIBUTE_UNUSED
;
236 section
*sdata2_section
;
239 #undef TARGET_HAVE_TLS
240 #define TARGET_HAVE_TLS true
243 /* Return truth value if a CONST_DOUBLE is ok to be a legitimate constant. */
245 microblaze_const_double_ok (rtx op
, machine_mode mode
)
249 if (GET_CODE (op
) != CONST_DOUBLE
)
252 if (GET_MODE (op
) == VOIDmode
)
255 if (mode
!= SFmode
&& mode
!= DFmode
)
258 if (op
== CONST0_RTX (mode
))
261 d
= *CONST_DOUBLE_REAL_VALUE (op
);
263 if (REAL_VALUE_ISNAN (d
))
266 if (REAL_VALUE_NEGATIVE (d
))
267 d
= real_value_negate (&d
);
271 if (real_less (&d
, &dfhigh
) && real_less (&dflow
, &d
))
276 if (real_less (&d
, &sfhigh
) && real_less (&sflow
, &d
))
283 /* Return truth value if a memory operand fits in a single instruction
284 (ie, register + small offset) or (register + register). */
287 simple_memory_operand (rtx op
, machine_mode mode ATTRIBUTE_UNUSED
)
289 rtx addr
, plus0
, plus1
;
291 /* Eliminate non-memory operations. */
292 if (GET_CODE (op
) != MEM
)
295 /* dword operations really put out 2 instructions, so eliminate them. */
296 /* ??? This isn't strictly correct. It is OK to accept multiword modes
297 here, since the length attributes are being set correctly, but only
298 if the address is offsettable. */
299 if (GET_MODE_SIZE (GET_MODE (op
)) > UNITS_PER_WORD
)
303 /* Decode the address now. */
305 switch (GET_CODE (addr
))
312 plus0
= XEXP (addr
, 0);
313 plus1
= XEXP (addr
, 1);
315 if (GET_CODE (plus0
) != REG
)
318 if (GET_CODE (plus0
) == REG
&& GET_CODE (plus1
) == CONST_INT
319 && SMALL_INT (plus1
))
323 else if (GET_CODE (plus1
) == REG
&& GET_CODE (plus0
) == CONST_INT
)
327 else if (GET_CODE (plus0
) == REG
&& GET_CODE (plus1
) == REG
)
344 /* Return nonzero for a memory address that can be used to load or store
348 double_memory_operand (rtx op
, machine_mode mode
)
352 if (GET_CODE (op
) != MEM
|| !memory_operand (op
, mode
))
354 /* During reload, we accept a pseudo register if it has an
355 appropriate memory address. If we don't do this, we will
356 wind up reloading into a register, and then reloading that
357 register from memory, when we could just reload directly from
359 if (reload_in_progress
360 && GET_CODE (op
) == REG
361 && REGNO (op
) >= FIRST_PSEUDO_REGISTER
362 && reg_renumber
[REGNO (op
)] < 0
363 && reg_equiv_mem (REGNO (op
)) != 0
364 && double_memory_operand (reg_equiv_mem (REGNO (op
)), mode
))
369 /* Make sure that 4 added to the address is a valid memory address.
370 This essentially just checks for overflow in an added constant. */
374 if (CONSTANT_ADDRESS_P (addr
))
377 return memory_address_p ((GET_MODE_CLASS (mode
) == MODE_INT
378 ? E_SImode
: E_SFmode
),
379 plus_constant (Pmode
, addr
, 4));
382 /* Implement REG_OK_FOR_BASE_P -and- REG_OK_FOR_INDEX_P. */
384 microblaze_regno_ok_for_base_p (int regno
, int strict
)
386 if (regno
>= FIRST_PSEUDO_REGISTER
)
390 regno
= reg_renumber
[regno
];
393 /* These fake registers will be eliminated to either the stack or
394 hard frame pointer, both of which are usually valid base registers.
395 Reload deals with the cases where the eliminated form isn't valid. */
396 if (regno
== ARG_POINTER_REGNUM
|| regno
== FRAME_POINTER_REGNUM
)
399 return GP_REG_P (regno
);
402 /* Return true if X is a valid base register for the given mode.
403 Allow only hard registers if STRICT. */
406 microblaze_valid_base_register_p (rtx x
,
407 machine_mode mode ATTRIBUTE_UNUSED
,
410 if (!strict
&& GET_CODE (x
) == SUBREG
)
413 return (GET_CODE (x
) == REG
414 && microblaze_regno_ok_for_base_p (REGNO (x
), strict
));
417 /* Build the SYMBOL_REF for __tls_get_addr. */
419 static GTY(()) rtx tls_get_addr_libfunc
;
422 get_tls_get_addr (void)
424 if (!tls_get_addr_libfunc
)
425 tls_get_addr_libfunc
= init_one_libfunc ("__tls_get_addr");
426 return tls_get_addr_libfunc
;
429 /* Return TRUE if X is a thread-local symbol. */
431 microblaze_tls_symbol_p (rtx x
)
433 if (!TARGET_HAVE_TLS
)
436 if (GET_CODE (x
) != SYMBOL_REF
)
439 return SYMBOL_REF_TLS_MODEL (x
) != 0;
442 /* Return TRUE if X contains any TLS symbol references. */
445 microblaze_tls_referenced_p (rtx x
)
447 if (!TARGET_HAVE_TLS
)
449 subrtx_iterator::array_type array
;
450 FOR_EACH_SUBRTX (iter
, array
, x
, ALL
)
453 if (GET_CODE (x
) == SYMBOL_REF
&& SYMBOL_REF_TLS_MODEL (x
) != 0)
455 /* Don't recurse into UNSPEC_TLS looking for TLS symbols; these are
456 TLS offsets, not real symbol references. */
457 if (GET_CODE (x
) == UNSPEC
&& XINT (x
, 1) == UNSPEC_TLS
)
458 iter
.skip_subrtxes ();
464 microblaze_cannot_force_const_mem (machine_mode mode ATTRIBUTE_UNUSED
, rtx x
)
466 return microblaze_tls_referenced_p(x
);
469 /* Return TRUE if X references a SYMBOL_REF. */
471 symbol_mentioned_p (rtx x
)
476 if (GET_CODE (x
) == SYMBOL_REF
)
479 /* UNSPEC entries for a symbol include the SYMBOL_REF, but they
480 are constant offsets, not symbols. */
481 if (GET_CODE (x
) == UNSPEC
)
484 fmt
= GET_RTX_FORMAT (GET_CODE (x
));
486 for (i
= GET_RTX_LENGTH (GET_CODE (x
)) - 1; i
>= 0; i
--)
492 for (j
= XVECLEN (x
, i
) - 1; j
>= 0; j
--)
493 if (symbol_mentioned_p (XVECEXP (x
, i
, j
)))
496 else if (fmt
[i
] == 'e' && symbol_mentioned_p (XEXP (x
, i
)))
503 /* Return TRUE if X references a LABEL_REF. */
505 label_mentioned_p (rtx x
)
510 if (GET_CODE (x
) == LABEL_REF
)
513 /* UNSPEC entries for a symbol include a LABEL_REF for the referencing
514 instruction, but they are constant offsets, not symbols. */
515 if (GET_CODE (x
) == UNSPEC
)
518 fmt
= GET_RTX_FORMAT (GET_CODE (x
));
519 for (i
= GET_RTX_LENGTH (GET_CODE (x
)) - 1; i
>= 0; i
--)
525 for (j
= XVECLEN (x
, i
) - 1; j
>= 0; j
--)
526 if (label_mentioned_p (XVECEXP (x
, i
, j
)))
529 else if (fmt
[i
] == 'e' && label_mentioned_p (XEXP (x
, i
)))
537 tls_mentioned_p (rtx x
)
539 switch (GET_CODE (x
))
542 return tls_mentioned_p (XEXP (x
, 0));
545 if (XINT (x
, 1) == UNSPEC_TLS
)
555 load_tls_operand (rtx x
, rtx reg
)
560 reg
= gen_reg_rtx (Pmode
);
562 tmp
= gen_rtx_CONST (Pmode
, x
);
564 emit_insn (gen_rtx_SET (reg
,
565 gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
, tmp
)));
571 microblaze_call_tls_get_addr (rtx x
, rtx reg
, rtx
*valuep
, int reloc
)
576 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
580 tls_entry
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (2, x
, GEN_INT (reloc
)),
583 reg
= load_tls_operand (tls_entry
, reg
);
585 *valuep
= emit_library_call_value (get_tls_get_addr (), NULL_RTX
,
586 LCT_PURE
, /* LCT_CONST? */
589 insns
= get_insns ();
596 microblaze_legitimize_tls_address(rtx x
, rtx reg
)
598 rtx dest
, ret
, eqv
, addend
;
600 enum tls_model model
;
601 model
= SYMBOL_REF_TLS_MODEL (x
);
605 case TLS_MODEL_LOCAL_DYNAMIC
:
606 case TLS_MODEL_GLOBAL_DYNAMIC
:
607 case TLS_MODEL_INITIAL_EXEC
:
608 insns
= microblaze_call_tls_get_addr (x
, reg
, &ret
, TLS_GD
);
609 dest
= gen_reg_rtx (Pmode
);
610 emit_libcall_block (insns
, dest
, ret
, x
);
613 case TLS_MODEL_LOCAL_EXEC
:
614 insns
= microblaze_call_tls_get_addr (x
, reg
, &ret
, TLS_LDM
);
616 /* Attach a unique REG_EQUIV, to allow the RTL optimizers to
617 share the LDM result with other LD model accesses. */
618 eqv
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, const1_rtx
), UNSPEC_TLS
);
619 dest
= gen_reg_rtx (Pmode
);
620 emit_libcall_block (insns
, dest
, ret
, eqv
);
622 /* Load the addend. */
623 addend
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (2, x
, GEN_INT (TLS_DTPREL
)),
625 addend
= force_reg (SImode
, gen_rtx_CONST (SImode
, addend
));
626 dest
= gen_rtx_PLUS (Pmode
, dest
, addend
);
636 microblaze_classify_unspec (struct microblaze_address_info
*info
, rtx x
)
638 info
->symbol_type
= SYMBOL_TYPE_GENERAL
;
639 info
->symbol
= XVECEXP (x
, 0, 0);
641 if (XINT (x
, 1) == UNSPEC_GOTOFF
)
643 info
->regA
= gen_rtx_REG (SImode
, PIC_OFFSET_TABLE_REGNUM
);
644 info
->type
= ADDRESS_GOTOFF
;
646 else if (XINT (x
, 1) == UNSPEC_PLT
)
648 info
->type
= ADDRESS_PLT
;
650 else if (XINT (x
, 1) == UNSPEC_TLS
)
652 info
->type
= ADDRESS_TLS
;
653 info
->tls_type
= tls_reloc (INTVAL (XVECEXP (x
, 0, 1)));
655 else if (XINT (x
, 1) == UNSPEC_TEXT
)
657 info
->type
= ADDRESS_SYMBOLIC_TXT_REL
;
667 /* Return true if X is a valid index register for the given mode.
668 Allow only hard registers if STRICT. */
671 microblaze_valid_index_register_p (rtx x
,
672 machine_mode mode ATTRIBUTE_UNUSED
,
675 if (!strict
&& GET_CODE (x
) == SUBREG
)
678 return (GET_CODE (x
) == REG
679 /* A base register is good enough to be an index register on MicroBlaze. */
680 && microblaze_regno_ok_for_base_p (REGNO (x
), strict
));
683 /* Get the base register for accessing a value from the memory or
684 Symbol ref. Used for MicroBlaze Small Data Area Pointer Optimization. */
691 if (!flag_pic
|| microblaze_tls_symbol_p(x
))
692 base_reg
= MB_ABI_BASE_REGNUM
;
694 base_reg
= MB_ABI_PIC_ADDR_REGNUM
;
697 && GET_CODE (x
) == SYMBOL_REF
698 && SYMBOL_REF_SMALL_P (x
) && (decl
= SYMBOL_REF_DECL (x
)) != NULL
)
700 if (TREE_READONLY (decl
))
701 base_reg
= MB_ABI_GPRO_REGNUM
;
703 base_reg
= MB_ABI_GPRW_REGNUM
;
709 /* Return true if X is a valid address for machine mode MODE. If it is,
710 fill in INFO appropriately.
711 STRICT > 0 if we should only accept hard base registers.
712 STRICT = 2 if the operand address is being printed thus
713 function has been called by print_operand_address.
715 type regA regB offset symbol
717 ADDRESS_INVALID NULL NULL NULL NULL
719 ADDRESS_REG %0 NULL const_0 / NULL
721 ADDRESS_REG_INDEX %0 %1 NULL NULL
723 ADDRESS_SYMBOLIC r0 / NULL NULL symbol
726 ADDRESS_CONST_INT r0 NULL const NULL
728 For modes spanning multiple registers (DFmode in 32-bit GPRs,
729 DImode, TImode), indexed addressing cannot be used because
730 adjacent memory cells are accessed by adding word-sized offsets
731 during assembly output. */
734 microblaze_classify_address (struct microblaze_address_info
*info
, rtx x
,
735 machine_mode mode
, int strict
)
741 info
->type
= ADDRESS_INVALID
;
746 info
->symbol_type
= SYMBOL_TYPE_INVALID
;
749 switch (GET_CODE (x
))
754 info
->type
= ADDRESS_REG
;
756 info
->offset
= const0_rtx
;
757 return microblaze_valid_base_register_p (info
->regA
, mode
, strict
);
761 xplus0
= XEXP (x
, 0);
762 xplus1
= XEXP (x
, 1);
764 if (microblaze_valid_base_register_p (xplus0
, mode
, strict
))
766 info
->type
= ADDRESS_REG
;
769 if (GET_CODE (xplus1
) == CONST_INT
)
771 info
->offset
= xplus1
;
774 else if (GET_CODE (xplus1
) == UNSPEC
)
776 /* Need offsettable address. */
777 if (GET_MODE_SIZE (mode
) > UNITS_PER_WORD
)
780 return microblaze_classify_unspec (info
, xplus1
);
782 else if ((GET_CODE (xplus1
) == SYMBOL_REF
||
783 GET_CODE (xplus1
) == LABEL_REF
))
785 if (flag_pic
== 2 || microblaze_tls_symbol_p(xplus1
))
787 info
->type
= ADDRESS_SYMBOLIC
;
788 info
->symbol
= xplus1
;
789 info
->symbol_type
= SYMBOL_TYPE_GENERAL
;
792 else if (GET_CODE (xplus1
) == CONST
)
794 rtx xconst0
= XEXP(xplus1
, 0);
797 if (GET_CODE (xconst0
) == UNSPEC
)
799 /* Need offsettable address. */
800 if (GET_MODE_SIZE (mode
) > UNITS_PER_WORD
)
802 return microblaze_classify_unspec(info
, xconst0
);
805 /* for (plus x const_int) just look at x. */
806 if (GET_CODE (xconst0
) == PLUS
807 && GET_CODE (XEXP (xconst0
, 1)) == CONST_INT
808 && (SMALL_INT (XEXP (xconst0
, 1))
809 || GET_CODE (XEXP (xconst0
, 0)) == UNSPEC
))
811 /* Hold CONST_INT Value in offset in case of
812 UNSPEC + CONST_INT. */
813 offset
= XEXP (xconst0
, 1);
815 /* This is ok as info->symbol is set to xplus1 the full
816 const-expression below. */
817 xconst0
= XEXP (xconst0
, 0);
820 if (GET_CODE (xconst0
) == SYMBOL_REF
821 || GET_CODE (xconst0
) == LABEL_REF
)
823 if (flag_pic
== 2 || microblaze_tls_symbol_p(xconst0
))
826 info
->type
= ADDRESS_SYMBOLIC
;
827 info
->symbol
= xplus1
;
828 info
->symbol_type
= SYMBOL_TYPE_GENERAL
;
832 if (GET_CODE (xconst0
) == UNSPEC
&& TARGET_PIC_DATA_TEXT_REL
)
834 if (GET_MODE_SIZE (mode
) > UNITS_PER_WORD
)
837 info
->offset
= offset
;
838 return microblaze_classify_unspec (info
, xconst0
);
841 /* Not base + symbol || base + UNSPEC. */
845 else if (GET_CODE (xplus1
) == REG
846 && microblaze_valid_index_register_p (xplus1
, mode
,
848 && (GET_MODE_SIZE (mode
) <= UNITS_PER_WORD
))
850 /* Restrict larger than word-width modes from using an index register. */
851 info
->type
= ADDRESS_REG_INDEX
;
860 info
->regA
= gen_raw_REG (mode
, 0);
861 info
->type
= ADDRESS_CONST_INT
;
869 info
->type
= ADDRESS_SYMBOLIC
;
870 info
->symbol_type
= SYMBOL_TYPE_GENERAL
;
872 info
->regA
= gen_raw_REG (mode
, get_base_reg (x
));
874 if (GET_CODE (x
) == CONST
)
876 if (GET_CODE (XEXP (x
, 0)) == UNSPEC
)
878 info
->regA
= gen_raw_REG (mode
,
879 get_base_reg (XVECEXP (XEXP (x
,0), 0, 0)));
880 return microblaze_classify_unspec (info
, XEXP (x
, 0));
882 return !(flag_pic
&& pic_address_needs_scratch (x
));
885 /* Avoid error in print_operand_address in case UNSPEC
886 is removed from SYMBOL or LABEL REFS during optimization. */
887 if ((GET_CODE (x
) == SYMBOL_REF
|| GET_CODE (x
) == LABEL_REF
)
888 && flag_pic
&& TARGET_PIC_DATA_TEXT_REL
&& strict
== 2)
890 info
->type
= ADDRESS_SYMBOLIC_TXT_REL
;
896 else if (microblaze_tls_symbol_p(x
))
904 if (reload_in_progress
)
905 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
906 return microblaze_classify_unspec (info
, x
);
916 /* This function is used to implement GO_IF_LEGITIMATE_ADDRESS. It
917 returns a nonzero value if X is a legitimate address for a memory
918 operand of the indicated MODE. STRICT is nonzero if this function
919 is called during reload. */
922 microblaze_legitimate_address_p (machine_mode mode
, rtx x
, bool strict
)
924 struct microblaze_address_info addr
;
926 return microblaze_classify_address (&addr
, x
, mode
, strict
);
930 microblaze_constant_address_p (rtx x
)
932 return ((GET_CODE (x
) == LABEL_REF
) || (GET_CODE (x
) == SYMBOL_REF
)
933 || GET_CODE (x
) == CONST_INT
934 || (GET_CODE (x
) == CONST
935 && ! (flag_pic
&& pic_address_needs_scratch (x
))));
939 microblaze_valid_pic_const (rtx x
)
941 switch (GET_CODE (x
))
953 microblaze_legitimate_pic_operand (rtx x
)
955 if (flag_pic
== 2 && (symbol_mentioned_p (x
) || label_mentioned_p (x
))
956 && !(TARGET_PIC_DATA_TEXT_REL
&& call_insn_operand (x
,VOIDmode
)))
959 if (microblaze_tls_referenced_p(x
))
965 /* Try machine-dependent ways of modifying an illegitimate address
966 to be legitimate. If we find one, return the new, valid address.
967 This is used from only one place: `memory_address' in explow.cc.
969 OLDX is the address as it was before break_out_memory_refs was
970 called. In some cases it is useful to look at this to decide what
973 It is always safe for this function to do nothing. It exists to
974 recognize opportunities to optimize the output.
976 For the MicroBlaze, transform:
978 memory(X + <large int>)
982 Y = <large int> & ~0x7fff;
984 memory (Z + (<large int> & 0x7fff));
986 This is for CSE to find several similar references, and only use one Z.
988 When PIC, convert addresses of the form memory (symbol+large int) to
989 memory (reg+large int). */
992 microblaze_legitimize_address (rtx x
, rtx oldx ATTRIBUTE_UNUSED
,
993 machine_mode mode ATTRIBUTE_UNUSED
)
995 rtx xinsn
= x
, result
;
997 if (GET_CODE (xinsn
) == CONST
998 && flag_pic
&& pic_address_needs_scratch (xinsn
))
1000 rtx ptr_reg
= gen_reg_rtx (Pmode
);
1001 rtx constant
= XEXP (XEXP (xinsn
, 0), 1);
1003 emit_move_insn (ptr_reg
, XEXP (XEXP (xinsn
, 0), 0));
1005 result
= gen_rtx_PLUS (Pmode
, ptr_reg
, constant
);
1006 if (SMALL_INT (constant
))
1008 /* Otherwise we fall through so the code below will fix the
1013 if (GET_CODE (xinsn
) == PLUS
)
1015 rtx xplus0
= XEXP (xinsn
, 0);
1016 rtx xplus1
= XEXP (xinsn
, 1);
1017 enum rtx_code code0
= GET_CODE (xplus0
);
1018 enum rtx_code code1
= GET_CODE (xplus1
);
1020 if (code0
!= REG
&& code1
== REG
)
1022 xplus0
= XEXP (xinsn
, 1);
1023 xplus1
= XEXP (xinsn
, 0);
1024 code0
= GET_CODE (xplus0
);
1025 code1
= GET_CODE (xplus1
);
1028 if (code0
== REG
&& REG_OK_FOR_BASE_P (xplus0
)
1029 && code1
== CONST_INT
&& !SMALL_INT (xplus1
))
1031 rtx int_reg
= gen_reg_rtx (Pmode
);
1032 rtx ptr_reg
= gen_reg_rtx (Pmode
);
1034 emit_move_insn (int_reg
, GEN_INT (INTVAL (xplus1
) & ~0x7fff));
1036 emit_insn (gen_rtx_SET (ptr_reg
,
1037 gen_rtx_PLUS (Pmode
, xplus0
, int_reg
)));
1039 result
= gen_rtx_PLUS (Pmode
, ptr_reg
,
1040 GEN_INT (INTVAL (xplus1
) & 0x7fff));
1044 if (code0
== REG
&& REG_OK_FOR_BASE_P (xplus0
))
1046 if (reload_in_progress
)
1047 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
1050 xplus1
= XEXP (xplus1
, 0);
1051 code1
= GET_CODE (xplus1
);
1053 if (code1
== SYMBOL_REF
)
1055 if (microblaze_tls_symbol_p(xplus1
))
1058 reg
= gen_reg_rtx (Pmode
);
1060 tls_ref
= microblaze_legitimize_tls_address (xplus1
,
1062 emit_move_insn (reg
, tls_ref
);
1064 result
= gen_rtx_PLUS (Pmode
, xplus0
, reg
);
1068 else if (flag_pic
== 2)
1070 if (!TARGET_PIC_DATA_TEXT_REL
)
1073 reg
= gen_reg_rtx (Pmode
);
1075 pic_ref
= gen_rtx_UNSPEC (Pmode
,
1076 gen_rtvec (1, xplus1
),
1078 pic_ref
= gen_rtx_CONST (Pmode
, pic_ref
);
1079 pic_ref
= gen_rtx_PLUS (Pmode
,
1080 pic_offset_table_rtx
, pic_ref
);
1081 pic_ref
= gen_const_mem (Pmode
, pic_ref
);
1082 emit_move_insn (reg
, pic_ref
);
1083 result
= gen_rtx_PLUS (Pmode
, xplus0
, reg
);
1089 reg
= gen_reg_rtx (Pmode
);
1090 pic_ref
= gen_rtx_UNSPEC (Pmode
,
1091 gen_rtvec (1, xplus1
),
1093 pic_ref
= gen_rtx_CONST (Pmode
, pic_ref
);
1094 emit_insn (gen_addsi3 (reg
,
1095 pic_offset_table_rtx
, xplus0
));
1096 result
= gen_rtx_PLUS (Pmode
, reg
, pic_ref
);
1104 if (GET_CODE (xinsn
) == SYMBOL_REF
)
1107 if (microblaze_tls_symbol_p(xinsn
))
1109 reg
= microblaze_legitimize_tls_address (xinsn
, NULL_RTX
);
1111 else if (flag_pic
== 2)
1113 if (reload_in_progress
)
1114 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
1116 if (!TARGET_PIC_DATA_TEXT_REL
)
1120 pic_ref
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, xinsn
), UNSPEC_GOTOFF
);
1121 pic_ref
= gen_rtx_CONST (Pmode
, pic_ref
);
1122 pic_ref
= gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
, pic_ref
);
1123 pic_ref
= gen_const_mem (Pmode
, pic_ref
);
1130 pic_ref
= gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, xinsn
), UNSPEC_TEXT
);
1131 pic_ref
= gen_rtx_CONST (Pmode
, pic_ref
);
1132 pic_ref
= gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
, pic_ref
);
1144 #define MAX_MOVE_REGS 8
1145 #define MAX_MOVE_BYTES (MAX_MOVE_REGS * UNITS_PER_WORD)
1147 /* Emit straight-line code to move LENGTH bytes from SRC to DEST.
1148 Assume that the areas do not overlap. */
1151 microblaze_block_move_straight (rtx dest
, rtx src
, HOST_WIDE_INT length
)
1153 HOST_WIDE_INT offset
, delta
;
1154 unsigned HOST_WIDE_INT bits
;
1159 bits
= BITS_PER_WORD
;
1160 mode
= int_mode_for_size (bits
, 0).require ();
1161 delta
= bits
/ BITS_PER_UNIT
;
1163 /* Allocate a buffer for the temporary registers. */
1164 regs
= XALLOCAVEC (rtx
, length
/ delta
);
1166 /* Load as many BITS-sized chunks as possible. Use a normal load if
1167 the source has enough alignment, otherwise use left/right pairs. */
1168 for (offset
= 0, i
= 0; offset
+ delta
<= length
; offset
+= delta
, i
++)
1170 regs
[i
] = gen_reg_rtx (mode
);
1171 emit_move_insn (regs
[i
], adjust_address (src
, mode
, offset
));
1174 /* Copy the chunks to the destination. */
1175 for (offset
= 0, i
= 0; offset
+ delta
<= length
; offset
+= delta
, i
++)
1176 emit_move_insn (adjust_address (dest
, mode
, offset
), regs
[i
]);
1178 /* Mop up any left-over bytes. */
1179 if (offset
< length
)
1181 src
= adjust_address (src
, BLKmode
, offset
);
1182 dest
= adjust_address (dest
, BLKmode
, offset
);
1183 move_by_pieces (dest
, src
, length
- offset
,
1184 MIN (MEM_ALIGN (src
), MEM_ALIGN (dest
)), RETURN_BEGIN
);
1188 /* Helper function for doing a loop-based block operation on memory
1189 reference MEM. Each iteration of the loop will operate on LENGTH
1192 Create a new base register for use within the loop and point it to
1193 the start of MEM. Create a new memory reference that uses this
1194 register. Store them in *LOOP_REG and *LOOP_MEM respectively. */
1197 microblaze_adjust_block_mem (rtx mem
, HOST_WIDE_INT length
,
1198 rtx
* loop_reg
, rtx
* loop_mem
)
1200 *loop_reg
= copy_addr_to_reg (XEXP (mem
, 0));
1202 /* Although the new mem does not refer to a known location,
1203 it does keep up to LENGTH bytes of alignment. */
1204 *loop_mem
= change_address (mem
, BLKmode
, *loop_reg
);
1205 set_mem_align (*loop_mem
,
1206 MIN ((HOST_WIDE_INT
) MEM_ALIGN (mem
),
1207 length
* BITS_PER_UNIT
));
1211 /* Move LENGTH bytes from SRC to DEST using a loop that moves MAX_MOVE_BYTES
1212 per iteration. LENGTH must be at least MAX_MOVE_BYTES. Assume that the
1213 memory regions do not overlap. */
1216 microblaze_block_move_loop (rtx dest
, rtx src
, HOST_WIDE_INT length
)
1218 rtx_code_label
*label
;
1219 rtx src_reg
, dest_reg
, final_src
;
1220 HOST_WIDE_INT leftover
;
1222 leftover
= length
% MAX_MOVE_BYTES
;
1225 /* Create registers and memory references for use within the loop. */
1226 microblaze_adjust_block_mem (src
, MAX_MOVE_BYTES
, &src_reg
, &src
);
1227 microblaze_adjust_block_mem (dest
, MAX_MOVE_BYTES
, &dest_reg
, &dest
);
1229 /* Calculate the value that SRC_REG should have after the last iteration
1231 final_src
= expand_simple_binop (Pmode
, PLUS
, src_reg
, GEN_INT (length
),
1234 /* Emit the start of the loop. */
1235 label
= gen_label_rtx ();
1238 /* Emit the loop body. */
1239 microblaze_block_move_straight (dest
, src
, MAX_MOVE_BYTES
);
1241 /* Move on to the next block. */
1242 emit_move_insn (src_reg
, plus_constant (Pmode
, src_reg
, MAX_MOVE_BYTES
));
1243 emit_move_insn (dest_reg
, plus_constant (Pmode
, dest_reg
, MAX_MOVE_BYTES
));
1245 /* Emit the test & branch. */
1246 emit_insn (gen_cbranchsi4 (gen_rtx_NE (SImode
, src_reg
, final_src
),
1247 src_reg
, final_src
, label
));
1249 /* Mop up any left-over bytes. */
1251 microblaze_block_move_straight (dest
, src
, leftover
);
1254 /* Expand a cpymemsi instruction. */
1257 microblaze_expand_block_move (rtx dest
, rtx src
, rtx length
, rtx align_rtx
)
1260 if (GET_CODE (length
) == CONST_INT
)
1262 unsigned HOST_WIDE_INT bytes
= UINTVAL (length
);
1263 unsigned int align
= UINTVAL (align_rtx
);
1265 if (align
> UNITS_PER_WORD
)
1267 align
= UNITS_PER_WORD
; /* We can't do any better. */
1269 else if (align
< UNITS_PER_WORD
)
1271 if (UINTVAL (length
) <= MAX_MOVE_BYTES
)
1273 move_by_pieces (dest
, src
, bytes
, align
, RETURN_BEGIN
);
1280 if (UINTVAL (length
) <= 2 * MAX_MOVE_BYTES
)
1282 microblaze_block_move_straight (dest
, src
, UINTVAL (length
));
1287 microblaze_block_move_loop (dest
, src
, UINTVAL (length
));
1295 microblaze_rtx_costs (rtx x
, machine_mode mode
, int outer_code ATTRIBUTE_UNUSED
,
1296 int opno ATTRIBUTE_UNUSED
, int *total
,
1297 bool speed ATTRIBUTE_UNUSED
)
1299 int code
= GET_CODE (x
);
1305 int num_words
= (GET_MODE_SIZE (mode
) > UNITS_PER_WORD
) ? 2 : 1;
1306 if (simple_memory_operand (x
, mode
))
1307 *total
= COSTS_N_INSNS (2 * num_words
);
1309 *total
= COSTS_N_INSNS (2 * (2 * num_words
));
1317 *total
= COSTS_N_INSNS (2);
1320 *total
= COSTS_N_INSNS (1);
1329 *total
= COSTS_N_INSNS (2);
1332 *total
= COSTS_N_INSNS (1);
1340 if (TARGET_BARREL_SHIFT
)
1342 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v5.00.a")
1344 *total
= COSTS_N_INSNS (1);
1346 *total
= COSTS_N_INSNS (2);
1348 else if (!TARGET_SOFT_MUL
)
1349 *total
= COSTS_N_INSNS (1);
1350 else if (GET_CODE (XEXP (x
, 1)) == CONST_INT
)
1352 /* Add 1 to make shift slightly more expensive than add. */
1353 *total
= COSTS_N_INSNS (INTVAL (XEXP (x
, 1))) + 1;
1354 /* Reduce shift costs for special circumstances. */
1355 if (optimize_size
&& INTVAL (XEXP (x
, 1)) > 5)
1357 if (!optimize_size
&& INTVAL (XEXP (x
, 1)) > 17)
1361 /* Double the worst cost of shifts when there is no barrel shifter and
1362 the shift amount is in a reg. */
1363 *total
= COSTS_N_INSNS (32 * 4);
1369 if (mode
== SFmode
|| mode
== DFmode
)
1371 if (TARGET_HARD_FLOAT
)
1372 *total
= COSTS_N_INSNS (6);
1375 else if (mode
== DImode
)
1377 *total
= COSTS_N_INSNS (4);
1382 *total
= COSTS_N_INSNS (1);
1391 *total
= COSTS_N_INSNS (4);
1399 if (TARGET_HARD_FLOAT
)
1400 *total
= COSTS_N_INSNS (6);
1402 else if (!TARGET_SOFT_MUL
)
1404 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v5.00.a")
1406 *total
= COSTS_N_INSNS (1);
1408 *total
= COSTS_N_INSNS (3);
1411 *total
= COSTS_N_INSNS (10);
1419 if (TARGET_HARD_FLOAT
)
1420 *total
= COSTS_N_INSNS (23);
1426 *total
= COSTS_N_INSNS (1);
1431 *total
= COSTS_N_INSNS (1);
1439 /* Return the number of instructions needed to load or store a value
1440 of mode MODE at X. Return 0 if X isn't valid for MODE. */
1443 microblaze_address_insns (rtx x
, machine_mode mode
)
1445 struct microblaze_address_info addr
;
1447 if (microblaze_classify_address (&addr
, x
, mode
, false))
1452 if (SMALL_INT (addr
.offset
))
1456 case ADDRESS_CONST_INT
:
1461 case ADDRESS_REG_INDEX
:
1463 case ADDRESS_SYMBOLIC
:
1464 case ADDRESS_SYMBOLIC_TXT_REL
:
1465 case ADDRESS_GOTOFF
:
1468 switch (addr
.tls_type
)
1486 /* Provide the costs of an addressing mode that contains ADDR.
1487 If ADDR is not a valid address, its cost is irrelevant. */
1489 microblaze_address_cost (rtx addr
, machine_mode mode ATTRIBUTE_UNUSED
,
1490 addr_space_t as ATTRIBUTE_UNUSED
,
1491 bool speed ATTRIBUTE_UNUSED
)
1493 return COSTS_N_INSNS (microblaze_address_insns (addr
, GET_MODE (addr
)));
1496 /* Return nonzero if X is an address which needs a temporary register when
1497 reloaded while generating PIC code. */
1500 pic_address_needs_scratch (rtx x
)
1502 if (GET_CODE (x
) == CONST
&& GET_CODE (XEXP (x
,0)) == PLUS
)
1506 p0
= XEXP (XEXP (x
, 0), 0);
1507 p1
= XEXP (XEXP (x
, 0), 1);
1509 if ((GET_CODE (p0
) == SYMBOL_REF
|| GET_CODE (p0
) == LABEL_REF
)
1510 && (GET_CODE (p1
) == CONST_INT
)
1511 && (flag_pic
== 2 || microblaze_tls_symbol_p (p0
) || !SMALL_INT (p1
)))
1517 /* Argument support functions. */
1518 /* Initialize CUMULATIVE_ARGS for a function. */
1521 init_cumulative_args (CUMULATIVE_ARGS
* cum
, tree fntype
,
1522 rtx libname ATTRIBUTE_UNUSED
)
1524 static CUMULATIVE_ARGS zero_cum
;
1525 tree param
, next_param
;
1529 /* Determine if this function has variable arguments. This is
1530 indicated by the last argument being 'void_type_mode' if there
1531 are no variable arguments. The standard MicroBlaze calling sequence
1532 passes all arguments in the general purpose registers in this case. */
1534 for (param
= fntype
? TYPE_ARG_TYPES (fntype
) : 0;
1535 param
!= 0; param
= next_param
)
1537 next_param
= TREE_CHAIN (param
);
1538 if (next_param
== 0 && TREE_VALUE (param
) != void_type_node
)
1539 cum
->gp_reg_found
= 1;
1543 /* Advance the argument to the next argument position. */
1546 microblaze_function_arg_advance (cumulative_args_t cum_v
,
1547 const function_arg_info
&arg
)
1549 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
1558 gcc_assert (GET_MODE_CLASS (arg
.mode
) == MODE_COMPLEX_INT
1559 || GET_MODE_CLASS (arg
.mode
) == MODE_COMPLEX_FLOAT
);
1561 cum
->gp_reg_found
= 1;
1562 cum
->arg_words
+= ((GET_MODE_SIZE (arg
.mode
) + UNITS_PER_WORD
- 1)
1567 cum
->gp_reg_found
= 1;
1568 cum
->arg_words
+= ((int_size_in_bytes (arg
.type
) + UNITS_PER_WORD
- 1)
1574 if (!cum
->gp_reg_found
&& cum
->arg_number
<= 2)
1575 cum
->fp_code
+= 1 << ((cum
->arg_number
- 1) * 2);
1579 cum
->arg_words
+= 2;
1580 if (!cum
->gp_reg_found
&& cum
->arg_number
<= 2)
1581 cum
->fp_code
+= 2 << ((cum
->arg_number
- 1) * 2);
1585 cum
->gp_reg_found
= 1;
1586 cum
->arg_words
+= 2;
1593 cum
->gp_reg_found
= 1;
1599 /* Return an RTL expression containing the register for the given argument
1600 or 0 if the argument is to be passed on the stack. */
1603 microblaze_function_arg (cumulative_args_t cum_v
, const function_arg_info
&arg
)
1605 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
1609 int *arg_words
= &cum
->arg_words
;
1611 cum
->last_arg_fp
= 0;
1622 regbase
= GP_ARG_FIRST
;
1625 gcc_assert (GET_MODE_CLASS (arg
.mode
) == MODE_COMPLEX_INT
1626 || GET_MODE_CLASS (arg
.mode
) == MODE_COMPLEX_FLOAT
);
1629 regbase
= GP_ARG_FIRST
;
1633 if (*arg_words
>= MAX_ARGS_IN_REGISTERS
)
1637 gcc_assert (regbase
!= -1);
1639 ret
= gen_rtx_REG (arg
.mode
, regbase
+ *arg_words
);
1642 if (arg
.end_marker_p ())
1644 if (cum
->num_adjusts
> 0)
1645 ret
= gen_rtx_PARALLEL ((machine_mode
) cum
->fp_code
,
1646 gen_rtvec_v (cum
->num_adjusts
, cum
->adjust
));
1652 /* Return number of bytes of argument to put in registers. */
1654 function_arg_partial_bytes (cumulative_args_t cum_v
,
1655 const function_arg_info
&arg
)
1657 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
1659 if ((arg
.mode
== BLKmode
1660 || GET_MODE_CLASS (arg
.mode
) != MODE_COMPLEX_INT
1661 || GET_MODE_CLASS (arg
.mode
) != MODE_COMPLEX_FLOAT
)
1662 && cum
->arg_words
< MAX_ARGS_IN_REGISTERS
)
1664 int words
= ((arg
.promoted_size_in_bytes () + UNITS_PER_WORD
- 1)
1666 if (words
+ cum
->arg_words
<= MAX_ARGS_IN_REGISTERS
)
1667 return 0; /* structure fits in registers */
1669 return (MAX_ARGS_IN_REGISTERS
- cum
->arg_words
) * UNITS_PER_WORD
;
1672 else if (arg
.mode
== DImode
&& cum
->arg_words
== MAX_ARGS_IN_REGISTERS
- 1)
1673 return UNITS_PER_WORD
;
1678 /* Convert a version number of the form "vX.YY.Z" to an integer encoding
1679 for easier range comparison. */
1681 microblaze_version_to_int (const char *version
)
1684 const char *tmpl
= "vXX.YY.Z";
1693 { /* Looking for major */
1700 if (!(*p
>= '0' && *p
<= '9'))
1702 iver
+= (int) (*p
- '0');
1707 { /* Looking for minor */
1708 if (!(*p
>= '0' && *p
<= '9'))
1710 iver
+= (int) (*p
- '0');
1714 { /* Looking for compat */
1715 if (!(*p
>= 'a' && *p
<= 'z'))
1718 iver
+= (int) (*p
- 'a');
1738 microblaze_option_override (void)
1745 microblaze_section_threshold
= (OPTION_SET_P (g_switch_value
)
1747 : MICROBLAZE_DEFAULT_GVALUE
);
1751 /* Make sure it's 2, we only support one kind of PIC. */
1753 if (!TARGET_SUPPORTS_PIC
)
1755 error ("%<-fPIC%>/%<-fpic%> not supported for this target");
1756 /* Clear it to avoid further errors. */
1761 /* Check the MicroBlaze CPU version for any special action to be done. */
1762 if (microblaze_select_cpu
== NULL
)
1763 microblaze_select_cpu
= MICROBLAZE_DEFAULT_CPU
;
1764 ver
= microblaze_version_to_int (microblaze_select_cpu
);
1767 error ("%qs is an invalid argument to %<-mcpu=%>", microblaze_select_cpu
);
1770 ver
= MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v3.00.a");
1773 /* No hardware exceptions in earlier versions. So no worries. */
1775 microblaze_select_flags
&= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY
);
1777 microblaze_no_unsafe_delay
= 0;
1778 microblaze_pipe
= MICROBLAZE_PIPE_3
;
1781 || (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v4.00.b")
1785 microblaze_select_flags
|= (MICROBLAZE_MASK_NO_UNSAFE_DELAY
);
1787 microblaze_no_unsafe_delay
= 1;
1788 microblaze_pipe
= MICROBLAZE_PIPE_3
;
1792 /* We agree to use 5 pipe-stage model even on area optimized 3
1793 pipe-stage variants. */
1795 microblaze_select_flags
&= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY
);
1797 microblaze_no_unsafe_delay
= 0;
1798 microblaze_pipe
= MICROBLAZE_PIPE_5
;
1799 if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v5.00.a") == 0
1800 || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
,
1802 || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
,
1805 /* Pattern compares are to be turned on by default only when
1806 compiling for MB v5.00.'z'. */
1807 target_flags
|= MASK_PATTERN_COMPARE
;
1811 ver
= MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v6.00.a");
1814 if (TARGET_MULTIPLY_HIGH
)
1816 "%<-mxl-multiply-high%> can be used only with "
1817 "%<-mcpu=v6.00.a%> or greater");
1820 ver
= MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v8.10.a");
1821 microblaze_has_clz
= 1;
1824 /* MicroBlaze prior to 8.10.a didn't have clz. */
1825 microblaze_has_clz
= 0;
1828 /* TARGET_REORDER defaults to 2 if -mxl-reorder not specified. */
1829 ver
= MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu
, "v8.30.a");
1832 if (TARGET_REORDER
== 1)
1833 warning (0, "%<-mxl-reorder%> can be used only with "
1834 "%<-mcpu=v8.30.a%> or greater");
1837 else if ((ver
== 0) && !TARGET_PATTERN_COMPARE
)
1839 if (TARGET_REORDER
== 1)
1840 warning (0, "%<-mxl-reorder%> requires %<-mxl-pattern-compare%> for "
1841 "%<-mcpu=v8.30.a%>");
1845 if (TARGET_MULTIPLY_HIGH
&& TARGET_SOFT_MUL
)
1846 error ("%<-mxl-multiply-high%> requires %<-mno-xl-soft-mul%>");
1848 /* Always use DFA scheduler. */
1849 microblaze_sched_use_dfa
= 1;
1852 microblaze_abicalls
= MICROBLAZE_ABICALLS_NO
;
1855 /* Initialize the high, low values for legit floating point constants. */
1856 real_maxval (&dfhigh
, 0, DFmode
);
1857 real_maxval (&dflow
, 1, DFmode
);
1858 real_maxval (&sfhigh
, 0, SFmode
);
1859 real_maxval (&sflow
, 1, SFmode
);
1861 microblaze_print_operand_punct
['?'] = 1;
1862 microblaze_print_operand_punct
['#'] = 1;
1863 microblaze_print_operand_punct
['&'] = 1;
1864 microblaze_print_operand_punct
['!'] = 1;
1865 microblaze_print_operand_punct
['*'] = 1;
1866 microblaze_print_operand_punct
['@'] = 1;
1867 microblaze_print_operand_punct
['.'] = 1;
1868 microblaze_print_operand_punct
['('] = 1;
1869 microblaze_print_operand_punct
[')'] = 1;
1870 microblaze_print_operand_punct
['['] = 1;
1871 microblaze_print_operand_punct
[']'] = 1;
1872 microblaze_print_operand_punct
['<'] = 1;
1873 microblaze_print_operand_punct
['>'] = 1;
1874 microblaze_print_operand_punct
['{'] = 1;
1875 microblaze_print_operand_punct
['}'] = 1;
1876 microblaze_print_operand_punct
['^'] = 1;
1877 microblaze_print_operand_punct
['$'] = 1;
1878 microblaze_print_operand_punct
['+'] = 1;
1880 /* Set up array to map GCC register number to debug register number.
1881 Ignore the special purpose register numbers. */
1883 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
1884 microblaze_dbx_regno
[i
] = -1;
1886 start
= GP_DBX_FIRST
- GP_REG_FIRST
;
1887 for (i
= GP_REG_FIRST
; i
<= GP_REG_LAST
; i
++)
1888 microblaze_dbx_regno
[i
] = i
+ start
;
1890 /* Set up array giving whether a given register can hold a given mode. */
1892 for (mode
= VOIDmode
;
1893 mode
!= MAX_MACHINE_MODE
; mode
= (machine_mode
) ((int) mode
+ 1))
1895 int size
= GET_MODE_SIZE (mode
);
1897 for (regno
= 0; regno
< FIRST_PSEUDO_REGISTER
; regno
++)
1903 ok
= (ST_REG_P (regno
) || GP_REG_P (regno
));
1905 else if (GP_REG_P (regno
))
1906 ok
= ((regno
& 1) == 0 || size
<= UNITS_PER_WORD
);
1910 microblaze_hard_regno_mode_ok_p
[(int) mode
][regno
] = ok
;
1915 /* Implement TARGET_HARD_REGNO_MODE_OK. In 32 bit mode, require that
1916 DImode and DFmode be in even registers. For DImode, this makes some
1917 of the insns easier to write, since you don't have to worry about a
1918 DImode value in registers 3 & 4, producing a result in 4 & 5.
1920 To make the code simpler, the hook now just references an
1921 array built in override_options. */
1924 microblaze_hard_regno_mode_ok (unsigned int regno
, machine_mode mode
)
1926 return microblaze_hard_regno_mode_ok_p
[mode
][regno
];
1929 /* Implement TARGET_MODES_TIEABLE_P. */
1932 microblaze_modes_tieable_p (machine_mode mode1
, machine_mode mode2
)
1934 return ((GET_MODE_CLASS (mode1
) == MODE_FLOAT
1935 || GET_MODE_CLASS (mode1
) == MODE_COMPLEX_FLOAT
)
1936 == (GET_MODE_CLASS (mode2
) == MODE_FLOAT
1937 || GET_MODE_CLASS (mode2
) == MODE_COMPLEX_FLOAT
));
1940 /* Return true if FUNC is an interrupt function as specified
1941 by the "interrupt_handler" attribute. */
1944 microblaze_interrupt_function_p (tree func
)
1948 if (TREE_CODE (func
) != FUNCTION_DECL
)
1951 a
= lookup_attribute ("interrupt_handler", DECL_ATTRIBUTES (func
));
1952 return a
!= NULL_TREE
;
1956 microblaze_fast_interrupt_function_p (tree func
)
1960 if (TREE_CODE (func
) != FUNCTION_DECL
)
1963 a
= lookup_attribute ("fast_interrupt", DECL_ATTRIBUTES (func
));
1964 return a
!= NULL_TREE
;
1967 microblaze_break_function_p (tree func
)
1972 if (TREE_CODE (func
) != FUNCTION_DECL
)
1975 a
= lookup_attribute ("break_handler", DECL_ATTRIBUTES (func
));
1976 return a
!= NULL_TREE
;
1978 /* Return true if FUNC is an interrupt function which uses
1979 normal return, indicated by the "save_volatiles" attribute. */
1982 microblaze_save_volatiles (tree func
)
1986 if (TREE_CODE (func
) != FUNCTION_DECL
)
1989 a
= lookup_attribute ("save_volatiles", DECL_ATTRIBUTES (func
));
1990 return a
!= NULL_TREE
;
1993 /* Return whether function is tagged with 'interrupt_handler'
1994 or 'fast_interrupt' attribute. Return true if function
1995 should use return from interrupt rather than normal
1998 microblaze_is_interrupt_variant (void)
2000 return (interrupt_handler
|| fast_interrupt
);
2003 microblaze_is_break_handler (void)
2005 return break_handler
;
2008 /* Determine of register must be saved/restored in call. */
2010 microblaze_must_save_register (int regno
)
2012 if (pic_offset_table_rtx
&&
2013 (regno
== MB_ABI_PIC_ADDR_REGNUM
) && df_regs_ever_live_p (regno
))
2016 if (df_regs_ever_live_p (regno
) && !call_used_or_fixed_reg_p (regno
))
2019 if (frame_pointer_needed
&& (regno
== HARD_FRAME_POINTER_REGNUM
))
2022 if (crtl
->calls_eh_return
2023 && regno
== MB_ABI_SUB_RETURN_ADDR_REGNUM
)
2028 if (regno
== MB_ABI_SUB_RETURN_ADDR_REGNUM
)
2030 if ((microblaze_is_interrupt_variant () || save_volatiles
) &&
2031 (regno
>= 3 && regno
<= 12))
2035 if (microblaze_is_interrupt_variant ())
2037 if (df_regs_ever_live_p (regno
)
2038 || regno
== MB_ABI_MSR_SAVE_REG
2039 || ((interrupt_handler
|| fast_interrupt
)
2040 && (regno
== MB_ABI_ASM_TEMP_REGNUM
2041 || regno
== MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM
)))
2047 if (df_regs_ever_live_p (regno
)
2048 || regno
== MB_ABI_ASM_TEMP_REGNUM
2049 || regno
== MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM
)
2053 if (crtl
->calls_eh_return
2054 && (regno
== EH_RETURN_DATA_REGNO (0)
2055 || regno
== EH_RETURN_DATA_REGNO (1)))
2061 /* Return the bytes needed to compute the frame pointer from the current
2064 MicroBlaze stack frames look like:
2068 Before call After call
2069 +-----------------------+ +-----------------------+
2071 mem. | local variables, | | local variables, |
2072 | callee saved and | | callee saved and |
2074 +-----------------------+ +-----------------------+
2075 | arguments for called | | arguments for called |
2076 | subroutines | | subroutines |
2077 | (optional) | | (optional) |
2078 +-----------------------+ +-----------------------+
2079 | Link register | | Link register |
2081 +-----------------------+ +-----------------------+
2083 | local variables, |
2084 | callee saved and |
2086 +-----------------------+
2087 | MSR (optional if, |
2088 | interrupt handler) |
2089 +-----------------------+
2091 | alloca allocations |
2093 +-----------------------+
2095 | arguments for called |
2099 +-----------------------+
2102 memory +-----------------------+
2106 static HOST_WIDE_INT
2107 compute_frame_size (HOST_WIDE_INT size
)
2110 HOST_WIDE_INT total_size
; /* # bytes that the entire frame takes up. */
2111 HOST_WIDE_INT var_size
; /* # bytes that local variables take up. */
2112 HOST_WIDE_INT args_size
; /* # bytes that outgoing arguments take up. */
2113 int link_debug_size
; /* # bytes for link register. */
2114 HOST_WIDE_INT gp_reg_size
; /* # bytes needed to store calle-saved gp regs. */
2115 long mask
; /* mask of saved gp registers. */
2118 microblaze_interrupt_function_p (current_function_decl
);
2120 microblaze_break_function_p (current_function_decl
);
2123 microblaze_fast_interrupt_function_p (current_function_decl
);
2124 save_volatiles
= microblaze_save_volatiles (current_function_decl
);
2126 interrupt_handler
= break_handler
;
2131 args_size
= crtl
->outgoing_args_size
;
2133 if ((args_size
== 0) && cfun
->calls_alloca
)
2134 args_size
= NUM_OF_ARGS
* UNITS_PER_WORD
;
2136 total_size
= var_size
+ args_size
;
2138 if (flag_pic
== 2 && !TARGET_PIC_DATA_TEXT_REL
)
2139 /* force setting GOT. */
2140 df_set_regs_ever_live (MB_ABI_PIC_ADDR_REGNUM
, true);
2142 /* Calculate space needed for gp registers. */
2143 for (regno
= GP_REG_FIRST
; regno
<= GP_REG_LAST
; regno
++)
2145 if (microblaze_must_save_register (regno
))
2148 if (regno
!= MB_ABI_SUB_RETURN_ADDR_REGNUM
)
2149 /* Don't account for link register. It is accounted specially below. */
2150 gp_reg_size
+= GET_MODE_SIZE (SImode
);
2152 mask
|= (1L << (regno
- GP_REG_FIRST
));
2156 total_size
+= gp_reg_size
;
2158 /* Add 4 bytes for MSR. */
2159 if (microblaze_is_interrupt_variant ())
2162 /* No space to be allocated for link register in leaf functions with no other
2163 stack requirements. */
2164 if (total_size
== 0 && crtl
->is_leaf
)
2165 link_debug_size
= 0;
2167 link_debug_size
= UNITS_PER_WORD
;
2169 total_size
+= link_debug_size
;
2171 /* Save other computed information. */
2172 current_frame_info
.total_size
= total_size
;
2173 current_frame_info
.var_size
= var_size
;
2174 current_frame_info
.args_size
= args_size
;
2175 current_frame_info
.gp_reg_size
= gp_reg_size
;
2176 current_frame_info
.mask
= mask
;
2177 current_frame_info
.initialized
= reload_completed
;
2178 current_frame_info
.num_gp
= gp_reg_size
/ UNITS_PER_WORD
;
2179 current_frame_info
.link_debug_size
= link_debug_size
;
2182 /* Offset from which to callee-save GP regs. */
2183 current_frame_info
.gp_offset
= (total_size
- gp_reg_size
);
2185 current_frame_info
.gp_offset
= 0;
2187 /* Ok, we're done. */
2191 /* Make sure that we're not trying to eliminate to the wrong hard frame
2195 microblaze_can_eliminate (const int from
, const int to
)
2197 return ((from
== RETURN_ADDRESS_POINTER_REGNUM
&& !leaf_function_p())
2198 || (to
== MB_ABI_SUB_RETURN_ADDR_REGNUM
&& leaf_function_p())
2199 || (from
!= RETURN_ADDRESS_POINTER_REGNUM
2200 && (to
== HARD_FRAME_POINTER_REGNUM
2201 || (to
== STACK_POINTER_REGNUM
&& !frame_pointer_needed
))));
2204 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
2205 pointer or argument pointer or the return address pointer. TO is either
2206 the stack pointer or hard frame pointer. */
2209 microblaze_initial_elimination_offset (int from
, int to
)
2211 HOST_WIDE_INT offset
;
2215 case FRAME_POINTER_REGNUM
:
2218 case ARG_POINTER_REGNUM
:
2219 if (to
== STACK_POINTER_REGNUM
|| to
== HARD_FRAME_POINTER_REGNUM
)
2220 offset
= compute_frame_size (get_frame_size ());
2224 case RETURN_ADDRESS_POINTER_REGNUM
:
2228 offset
= current_frame_info
.gp_offset
+
2229 ((UNITS_PER_WORD
- (POINTER_SIZE
/ BITS_PER_UNIT
)));
2237 /* Print operands using format code.
2239 The MicroBlaze specific codes are:
2241 'X' X is CONST_INT, prints 32 bits in hexadecimal format = "0x%08x",
2242 'x' X is CONST_INT, prints 16 bits in hexadecimal format = "0x%04x",
2243 'F' op is CONST_DOUBLE, print 32 bits in hex,
2244 'd' output integer constant in decimal,
2245 'z' if the operand is 0, use $0 instead of normal operand.
2246 'D' print second register of double-word register operand.
2247 'L' print low-order register of double-word register operand.
2248 'M' print high-order register of double-word register operand.
2249 'C' print part of opcode for a branch condition.
2250 'N' print part of opcode for a branch condition, inverted.
2251 'S' X is CODE_LABEL, print with prefix of "LS" (for embedded switch).
2252 'B' print 'z' for EQ, 'n' for NE
2253 'b' print 'n' for EQ, 'z' for NE
2254 'T' print 'f' for EQ, 't' for NE
2255 't' print 't' for EQ, 'f' for NE
2256 'm' Print 1<<operand.
2257 'i' Print 'i' if MEM operand has immediate value
2258 'y' Print 'y' if MEM operand is single register
2259 'o' Print operand address+4
2260 '?' Print 'd' if we use a branch with delay slot instead of normal branch.
2261 'h' Print high word of const_double (int or float) value as hex
2262 'j' Print low word of const_double (int or float) value as hex
2263 's' Print -1 if operand is negative, 0 if positive (sign extend)
2264 '@' Print the name of the temporary register (rMB_ABI_ASM_TEMP_REGNUM).
2265 '#' Print nop if the delay slot of a branch is not filled.
2269 print_operand (FILE * file
, rtx op
, int letter
)
2273 if (PRINT_OPERAND_PUNCT_VALID_P (letter
))
2278 /* Conditionally add a 'd' to indicate filled delay slot. */
2279 if (final_sequence
!= NULL
)
2284 /* Conditionally add a nop in unfilled delay slot. */
2285 if (final_sequence
== NULL
)
2286 fputs ("nop\t\t# Unfilled delay slot\n", file
);
2290 fputs (reg_names
[GP_REG_FIRST
+ MB_ABI_ASM_TEMP_REGNUM
], file
);
2294 output_operand_lossage ("unknown punctuation '%c'", letter
);
2303 output_operand_lossage ("null pointer");
2307 code
= GET_CODE (op
);
2309 if (code
== SIGN_EXTEND
)
2310 op
= XEXP (op
, 0), code
= GET_CODE (op
);
2338 fatal_insn ("PRINT_OPERAND, invalid insn for %%C", op
);
2341 else if (letter
== 'N')
2367 fatal_insn ("PRINT_OPERAND, invalid insn for %%N", op
);
2370 else if (letter
== 'S')
2374 ASM_GENERATE_INTERNAL_LABEL (buffer
, "LS", CODE_LABEL_NUMBER (op
));
2375 assemble_name (file
, buffer
);
2378 /* Print 'i' for memory operands which have immediate values. */
2379 else if (letter
== 'i')
2383 struct microblaze_address_info info
;
2385 if (!microblaze_classify_address
2386 (&info
, XEXP (op
, 0), GET_MODE (op
), 1))
2387 fatal_insn ("insn contains an invalid address !", op
);
2392 case ADDRESS_CONST_INT
:
2393 case ADDRESS_SYMBOLIC
:
2394 case ADDRESS_SYMBOLIC_TXT_REL
:
2395 case ADDRESS_GOTOFF
:
2399 case ADDRESS_REG_INDEX
:
2401 case ADDRESS_INVALID
:
2403 fatal_insn ("invalid address", op
);
2408 else if (code
== REG
|| code
== SUBREG
)
2413 regnum
= REGNO (op
);
2415 regnum
= true_regnum (op
);
2417 if ((letter
== 'M' && !WORDS_BIG_ENDIAN
)
2418 || (letter
== 'L' && WORDS_BIG_ENDIAN
) || letter
== 'D')
2421 fprintf (file
, "%s", reg_names
[regnum
]);
2424 else if (code
== MEM
)
2427 rtx op4
= adjust_address (op
, GET_MODE (op
), 4);
2428 output_address (GET_MODE (op
), XEXP (op4
, 0));
2430 else if (letter
== 'y')
2432 rtx mem_reg
= XEXP (op
, 0);
2433 if (GET_CODE (mem_reg
) == REG
)
2435 int regnum
= REGNO (mem_reg
);
2436 fprintf (file
, "%s", reg_names
[regnum
]);
2440 output_address (GET_MODE (op
), XEXP (op
, 0));
2442 else if (letter
== 'h' || letter
== 'j')
2445 if (code
== CONST_DOUBLE
)
2447 if (GET_MODE (op
) == DFmode
)
2448 REAL_VALUE_TO_TARGET_DOUBLE (*CONST_DOUBLE_REAL_VALUE (op
), val
);
2451 val
[0] = CONST_DOUBLE_HIGH (op
);
2452 val
[1] = CONST_DOUBLE_LOW (op
);
2455 else if (code
== CONST_INT
)
2457 val
[0] = (INTVAL (op
) & 0xffffffff00000000LL
) >> 32;
2458 val
[1] = INTVAL (op
) & 0x00000000ffffffffLL
;
2459 if (val
[0] == 0 && val
[1] < 0)
2463 fprintf (file
, "0x%8.8lx", (letter
== 'h') ? val
[0] : val
[1]);
2465 else if (code
== CONST_DOUBLE
)
2469 unsigned long value_long
;
2470 REAL_VALUE_TO_TARGET_SINGLE (*CONST_DOUBLE_REAL_VALUE (op
),
2472 fprintf (file
, "0x%lx", value_long
);
2477 real_to_decimal (s
, CONST_DOUBLE_REAL_VALUE (op
), sizeof (s
), 0, 1);
2482 else if (code
== UNSPEC
)
2484 print_operand_address (file
, op
);
2487 else if (letter
== 'x' && GET_CODE (op
) == CONST_INT
)
2488 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, 0xffff & INTVAL (op
));
2490 else if (letter
== 'X' && GET_CODE (op
) == CONST_INT
)
2491 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, INTVAL (op
));
2493 else if (letter
== 'd' && GET_CODE (op
) == CONST_INT
)
2494 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, (INTVAL (op
)));
2496 else if (letter
== 'z' && GET_CODE (op
) == CONST_INT
&& INTVAL (op
) == 0)
2497 fputs (reg_names
[GP_REG_FIRST
], file
);
2499 else if (letter
== 's' && GET_CODE (op
) == CONST_INT
)
2500 if (INTVAL (op
) < 0)
2505 else if (letter
== 'd' || letter
== 'x' || letter
== 'X' || letter
== 's')
2506 output_operand_lossage ("letter %c was found & insn was not CONST_INT", letter
);
2508 else if (letter
== 'B')
2509 fputs (code
== EQ
? "z" : "n", file
);
2510 else if (letter
== 'b')
2511 fputs (code
== EQ
? "n" : "z", file
);
2512 else if (letter
== 'T')
2513 fputs (code
== EQ
? "f" : "t", file
);
2514 else if (letter
== 't')
2515 fputs (code
== EQ
? "t" : "f", file
);
2517 else if (code
== CONST
2518 && ((GET_CODE (XEXP (op
, 0)) == REG
)
2519 || (GET_CODE (XEXP (op
, 0)) == UNSPEC
)))
2521 print_operand (file
, XEXP (op
, 0), letter
);
2523 else if (code
== CONST
2524 && (GET_CODE (XEXP (op
, 0)) == PLUS
)
2525 && (GET_CODE (XEXP (XEXP (op
, 0), 0)) == REG
)
2526 && (GET_CODE (XEXP (XEXP (op
, 0), 1)) == CONST
))
2528 print_operand_address (file
, XEXP (op
, 0));
2530 else if (letter
== 'm')
2531 fprintf (file
, "%ld", (1L << INTVAL (op
)));
2533 output_addr_const (file
, op
);
2536 /* A C compound statement to output to stdio stream STREAM the
2537 assembler syntax for an instruction operand that is a memory
2538 reference whose address is ADDR. ADDR is an RTL expression.
2540 Possible address classifications and output formats are,
2542 ADDRESS_REG "%0, r0"
2544 ADDRESS_REG with non-zero "%0, <addr_const>"
2547 ADDRESS_REG_INDEX "rA, RB"
2548 (if rA is r0, rA and rB are swapped)
2550 ADDRESS_CONST_INT "r0, <addr_const>"
2552 ADDRESS_SYMBOLIC "rBase, <addr_const>"
2553 (rBase is a base register suitable for the
2558 print_operand_address (FILE * file
, rtx addr
)
2560 struct microblaze_address_info info
;
2561 enum microblaze_address_type type
;
2562 if (!microblaze_classify_address (&info
, addr
, GET_MODE (addr
), 2))
2563 fatal_insn ("insn contains an invalid address !", addr
);
2569 fprintf (file
, "%s,", reg_names
[REGNO (info
.regA
)]);
2570 output_addr_const (file
, info
.offset
);
2572 case ADDRESS_REG_INDEX
:
2573 if (REGNO (info
.regA
) == 0)
2574 /* Make rB == r0 instead of rA == r0. This helps reduce read port
2576 fprintf (file
, "%s,%s", reg_names
[REGNO (info
.regB
)],
2577 reg_names
[REGNO (info
.regA
)]);
2578 else if (REGNO (info
.regB
) != 0)
2579 /* This is a silly swap to help Dhrystone. */
2580 fprintf (file
, "%s,%s", reg_names
[REGNO (info
.regB
)],
2581 reg_names
[REGNO (info
.regA
)]);
2583 case ADDRESS_CONST_INT
:
2584 fprintf (file
, "%s,", reg_names
[REGNO (info
.regA
)]);
2585 output_addr_const (file
, info
.offset
);
2587 case ADDRESS_SYMBOLIC
:
2588 case ADDRESS_SYMBOLIC_TXT_REL
:
2589 case ADDRESS_GOTOFF
:
2593 fprintf (file
, "%s,", reg_names
[REGNO (info
.regA
)]);
2594 output_addr_const (file
, info
.symbol
);
2595 if (type
== ADDRESS_GOTOFF
)
2597 fputs ("@GOT", file
);
2599 else if (type
== ADDRESS_PLT
)
2601 fputs ("@PLT", file
);
2603 else if (type
== ADDRESS_SYMBOLIC_TXT_REL
)
2605 if (info
.offset
!= NULL
&& CONST_INT_P (info
.offset
)
2606 && INTVAL (info
.offset
) > 0)
2608 fprintf (file
, "+");
2609 output_addr_const (file
, info
.offset
);
2611 fputs ("@TXTREL", file
);
2613 else if (type
== ADDRESS_TLS
)
2615 switch (info
.tls_type
)
2618 fputs ("@TLSGD", file
);
2621 fputs ("@TLSLDM", file
);
2624 fputs ("@TLSDTPREL", file
);
2632 case ADDRESS_INVALID
:
2633 fatal_insn ("invalid address", addr
);
2638 /* Emit either a label, .comm, or .lcomm directive, and mark that the symbol
2639 is used, so that we don't emit an .extern for it in
2640 microblaze_asm_file_end. */
2643 microblaze_declare_object (FILE * stream
, const char *name
,
2644 const char *section
, const char *fmt
, int size
)
2647 fputs (section
, stream
);
2648 assemble_name (stream
, name
);
2649 fprintf (stream
, fmt
, size
);
2652 /* Common code to emit the insns (or to write the instructions to a file)
2653 to save/restore registers.
2655 Other parts of the code assume that MICROBLAZE_TEMP1_REGNUM (aka large_reg)
2656 is not modified within save_restore_insns. */
2658 #define BITSET_P(VALUE,BIT) (((VALUE) & (1L << (BIT))) != 0)
2660 /* Save or restore instructions based on whether this is the prologue or
2661 epilogue. prologue is 1 for the prologue. */
2663 save_restore_insns (int prologue
)
2665 rtx base_reg_rtx
, reg_rtx
, mem_rtx
, /* msr_rtx, */ isr_reg_rtx
=
2667 rtx isr_msr_rtx
= 0, insn
;
2668 long mask
= current_frame_info
.mask
;
2669 HOST_WIDE_INT gp_offset
;
2672 if (frame_pointer_needed
2673 && !BITSET_P (mask
, HARD_FRAME_POINTER_REGNUM
- GP_REG_FIRST
))
2679 /* Save registers starting from high to low. The debuggers prefer at least
2680 the return register be stored at func+4, and also it allows us not to
2681 need a nop in the epilog if at least one register is reloaded in
2682 addition to return address. */
2684 /* Pick which pointer to use as a base register. For small frames, just
2685 use the stack pointer. Otherwise, use a temporary register. Save 2
2686 cycles if the save area is near the end of a large frame, by reusing
2687 the constant created in the prologue/epilogue to adjust the stack
2690 gp_offset
= current_frame_info
.gp_offset
;
2692 gcc_assert (gp_offset
> 0);
2694 base_reg_rtx
= stack_pointer_rtx
;
2696 /* For interrupt_handlers, need to save/restore the MSR. */
2697 if (microblaze_is_interrupt_variant ())
2699 isr_mem_rtx
= gen_rtx_MEM (SImode
,
2700 gen_rtx_PLUS (Pmode
, base_reg_rtx
,
2701 GEN_INT (current_frame_info
.
2705 /* Do not optimize in flow analysis. */
2706 MEM_VOLATILE_P (isr_mem_rtx
) = 1;
2707 isr_reg_rtx
= gen_rtx_REG (SImode
, MB_ABI_MSR_SAVE_REG
);
2708 isr_msr_rtx
= gen_rtx_REG (SImode
, ST_REG
);
2711 if (microblaze_is_interrupt_variant () && !prologue
)
2713 emit_move_insn (isr_reg_rtx
, isr_mem_rtx
);
2714 emit_move_insn (isr_msr_rtx
, isr_reg_rtx
);
2715 /* Do not optimize in flow analysis. */
2716 emit_insn (gen_rtx_USE (SImode
, isr_reg_rtx
));
2717 emit_insn (gen_rtx_USE (SImode
, isr_msr_rtx
));
2720 for (regno
= GP_REG_FIRST
; regno
<= GP_REG_LAST
; regno
++)
2722 if (BITSET_P (mask
, regno
- GP_REG_FIRST
))
2724 if (regno
== MB_ABI_SUB_RETURN_ADDR_REGNUM
)
2725 /* Don't handle here. Already handled as the first register. */
2728 reg_rtx
= gen_rtx_REG (SImode
, regno
);
2729 insn
= gen_rtx_PLUS (Pmode
, base_reg_rtx
, GEN_INT (gp_offset
));
2730 mem_rtx
= gen_rtx_MEM (SImode
, insn
);
2731 if (microblaze_is_interrupt_variant () || save_volatiles
)
2732 /* Do not optimize in flow analysis. */
2733 MEM_VOLATILE_P (mem_rtx
) = 1;
2737 insn
= emit_move_insn (mem_rtx
, reg_rtx
);
2738 RTX_FRAME_RELATED_P (insn
) = 1;
2742 insn
= emit_move_insn (reg_rtx
, mem_rtx
);
2745 gp_offset
+= GET_MODE_SIZE (SImode
);
2749 if (microblaze_is_interrupt_variant () && prologue
)
2751 emit_move_insn (isr_reg_rtx
, isr_msr_rtx
);
2752 emit_move_insn (isr_mem_rtx
, isr_reg_rtx
);
2754 /* Do not optimize in flow analysis. */
2755 emit_insn (gen_rtx_USE (SImode
, isr_reg_rtx
));
2756 emit_insn (gen_rtx_USE (SImode
, isr_msr_rtx
));
2759 /* Done saving and restoring */
2763 /* Set up the stack and frame (if desired) for the function. */
2765 microblaze_function_prologue (FILE * file
)
2768 long fsiz
= current_frame_info
.total_size
;
2770 /* Get the function name the same way that toplev.cc does before calling
2771 assemble_start_function. This is needed so that the name used here
2772 exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */
2773 fnname
= XSTR (XEXP (DECL_RTL (current_function_decl
), 0), 0);
2774 if (!flag_inhibit_size_directive
)
2776 fputs ("\t.ent\t", file
);
2777 if (interrupt_handler
&& strcmp (INTERRUPT_HANDLER_NAME
, fnname
))
2778 fputs ("_interrupt_handler", file
);
2779 else if (break_handler
&& strcmp (BREAK_HANDLER_NAME
, fnname
))
2780 fputs ("_break_handler", file
);
2781 else if (fast_interrupt
&& strcmp (FAST_INTERRUPT_NAME
, fnname
))
2782 fputs ("_fast_interrupt", file
);
2784 assemble_name (file
, fnname
);
2786 if (!microblaze_is_interrupt_variant ())
2787 ASM_OUTPUT_TYPE_DIRECTIVE (file
, fnname
, "function");
2790 assemble_name (file
, fnname
);
2791 fputs (":\n", file
);
2793 if (interrupt_handler
&& strcmp (INTERRUPT_HANDLER_NAME
, fnname
))
2794 fputs ("_interrupt_handler:\n", file
);
2795 if (break_handler
&& strcmp (BREAK_HANDLER_NAME
, fnname
))
2796 fputs ("_break_handler:\n", file
);
2797 if (!flag_inhibit_size_directive
)
2799 /* .frame FRAMEREG, FRAMESIZE, RETREG. */
2801 "\t.frame\t%s,%ld,%s\t\t# vars= %ld, regs= %d, args= %d\n",
2802 (reg_names
[(frame_pointer_needed
)
2803 ? HARD_FRAME_POINTER_REGNUM
:
2804 STACK_POINTER_REGNUM
]), fsiz
,
2805 reg_names
[MB_ABI_SUB_RETURN_ADDR_REGNUM
+ GP_REG_FIRST
],
2806 current_frame_info
.var_size
, current_frame_info
.num_gp
,
2807 (int) crtl
->outgoing_args_size
);
2808 fprintf (file
, "\t.mask\t0x%08lx\n", current_frame_info
.mask
);
2812 /* Output extra assembler code at the end of a prologue. */
2814 microblaze_function_end_prologue (FILE * file
)
2816 if (TARGET_STACK_CHECK
)
2818 fprintf (file
, "\t# Stack Check Stub -- Start.\n\t");
2819 fprintf (file
, "ori\tr18,r0,_stack_end\n\t");
2820 fprintf (file
, "cmpu\tr18,r1,r18\n\t");
2821 fprintf (file
, "bgei\tr18,_stack_overflow_exit\n\t");
2822 fprintf (file
, "# Stack Check Stub -- End.\n");
2827 microblaze_elf_asm_cdtor (rtx symbol
, int priority
, bool is_ctor
)
2831 if (priority
!= DEFAULT_INIT_PRIORITY
)
2834 sprintf (buf
, "%s.%.5u",
2835 is_ctor
? ".ctors" : ".dtors",
2836 MAX_INIT_PRIORITY
- priority
);
2837 s
= get_section (buf
, SECTION_WRITE
, NULL_TREE
);
2844 switch_to_section (s
);
2845 assemble_align (POINTER_SIZE
);
2846 fputs ("\t.word\t", asm_out_file
);
2847 output_addr_const (asm_out_file
, symbol
);
2848 fputs ("\n", asm_out_file
);
2851 /* Add a function to the list of static constructors. */
2854 microblaze_elf_asm_constructor (rtx symbol
, int priority
)
2856 microblaze_elf_asm_cdtor (symbol
, priority
, /*is_ctor=*/true);
2859 /* Add a function to the list of static destructors. */
2862 microblaze_elf_asm_destructor (rtx symbol
, int priority
)
2864 microblaze_elf_asm_cdtor (symbol
, priority
, /*is_ctor=*/false);
2867 /* Expand the prologue into a bunch of separate insns. */
2870 microblaze_expand_prologue (void)
2874 const char *arg_name
= 0;
2875 tree fndecl
= current_function_decl
;
2876 tree fntype
= TREE_TYPE (fndecl
);
2877 tree fnargs
= DECL_ARGUMENTS (fndecl
);
2882 CUMULATIVE_ARGS args_so_far_v
;
2883 cumulative_args_t args_so_far
;
2884 rtx mem_rtx
, reg_rtx
;
2886 /* If struct value address is treated as the first argument, make it so. */
2887 if (aggregate_value_p (DECL_RESULT (fndecl
), fntype
)
2888 && !cfun
->returns_pcc_struct
)
2890 tree type
= build_pointer_type (fntype
);
2891 tree function_result_decl
= build_decl (BUILTINS_LOCATION
, PARM_DECL
,
2894 DECL_ARG_TYPE (function_result_decl
) = type
;
2895 TREE_CHAIN (function_result_decl
) = fnargs
;
2896 fnargs
= function_result_decl
;
2899 /* Determine the last argument, and get its name. */
2901 INIT_CUMULATIVE_ARGS (args_so_far_v
, fntype
, NULL_RTX
, 0, 0);
2902 args_so_far
= pack_cumulative_args (&args_so_far_v
);
2903 regno
= GP_ARG_FIRST
;
2905 for (cur_arg
= fnargs
; cur_arg
!= 0; cur_arg
= next_arg
)
2907 tree passed_type
= DECL_ARG_TYPE (cur_arg
);
2908 machine_mode passed_mode
= TYPE_MODE (passed_type
);
2911 if (TREE_ADDRESSABLE (passed_type
))
2913 passed_type
= build_pointer_type (passed_type
);
2914 passed_mode
= Pmode
;
2917 function_arg_info
arg (passed_type
, passed_mode
, /*named=*/true);
2918 entry_parm
= targetm
.calls
.function_arg (args_so_far
, arg
);
2924 /* passed in a register, so will get homed automatically. */
2925 if (GET_MODE (entry_parm
) == BLKmode
)
2926 words
= (int_size_in_bytes (passed_type
) + 3) / 4;
2928 words
= (GET_MODE_SIZE (GET_MODE (entry_parm
)) + 3) / 4;
2930 regno
= REGNO (entry_parm
) + words
- 1;
2934 regno
= GP_ARG_LAST
+ 1;
2938 targetm
.calls
.function_arg_advance (args_so_far
, arg
);
2940 next_arg
= TREE_CHAIN (cur_arg
);
2943 if (DECL_NAME (cur_arg
))
2944 arg_name
= IDENTIFIER_POINTER (DECL_NAME (cur_arg
));
2950 /* Split parallel insn into a sequence of insns. */
2952 next_arg_reg
= targetm
.calls
.function_arg (args_so_far
,
2953 function_arg_info::end_marker ());
2954 if (next_arg_reg
!= 0 && GET_CODE (next_arg_reg
) == PARALLEL
)
2956 rtvec adjust
= XVEC (next_arg_reg
, 0);
2957 int num
= GET_NUM_ELEM (adjust
);
2959 for (i
= 0; i
< num
; i
++)
2961 rtx pattern
= RTVEC_ELT (adjust
, i
);
2962 emit_insn (pattern
);
2966 fsiz
= compute_frame_size (get_frame_size ());
2968 if (flag_stack_usage_info
)
2969 current_function_static_stack_size
= fsiz
;
2971 /* If this function is a varargs function, store any registers that
2972 would normally hold arguments ($5 - $10) on the stack. */
2973 if (((TYPE_ARG_TYPES (fntype
) != 0
2974 && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype
)))
2977 && ((arg_name
[0] == '_'
2978 && strcmp (arg_name
, "__builtin_va_alist") == 0)
2979 || (arg_name
[0] == 'v'
2980 && strcmp (arg_name
, "va_alist") == 0)))))
2982 int offset
= (regno
- GP_ARG_FIRST
+ 1) * UNITS_PER_WORD
;
2983 rtx ptr
= stack_pointer_rtx
;
2985 /* If we are doing svr4-abi, sp has already been decremented by fsiz. */
2986 for (; regno
<= GP_ARG_LAST
; regno
++)
2989 ptr
= gen_rtx_PLUS (Pmode
, stack_pointer_rtx
, GEN_INT (offset
));
2990 emit_move_insn (gen_rtx_MEM (SImode
, ptr
),
2991 gen_rtx_REG (SImode
, regno
));
2993 offset
+= GET_MODE_SIZE (SImode
);
2999 rtx fsiz_rtx
= GEN_INT (fsiz
);
3001 rtx_insn
*insn
= NULL
;
3002 insn
= emit_insn (gen_subsi3 (stack_pointer_rtx
, stack_pointer_rtx
,
3005 RTX_FRAME_RELATED_P (insn
) = 1;
3007 /* Handle SUB_RETURN_ADDR_REGNUM specially at first. */
3008 if (!crtl
->is_leaf
|| interrupt_handler
)
3010 mem_rtx
= gen_rtx_MEM (SImode
,
3011 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
,
3014 if (interrupt_handler
)
3015 /* Do not optimize in flow analysis. */
3016 MEM_VOLATILE_P (mem_rtx
) = 1;
3018 reg_rtx
= gen_rtx_REG (SImode
, MB_ABI_SUB_RETURN_ADDR_REGNUM
);
3019 insn
= emit_move_insn (mem_rtx
, reg_rtx
);
3020 RTX_FRAME_RELATED_P (insn
) = 1;
3023 /* _save_ registers for prologue. */
3024 save_restore_insns (1);
3026 if (frame_pointer_needed
)
3030 insn
= emit_insn (gen_movsi (hard_frame_pointer_rtx
,
3031 stack_pointer_rtx
));
3034 RTX_FRAME_RELATED_P (insn
) = 1;
3038 if ((flag_pic
== 2 || TLS_NEEDS_GOT
)
3039 && df_regs_ever_live_p (MB_ABI_PIC_ADDR_REGNUM
))
3041 if ((flag_pic
== 2 && !TARGET_PIC_DATA_TEXT_REL
) || TLS_NEEDS_GOT
)
3043 SET_REGNO (pic_offset_table_rtx
, MB_ABI_PIC_ADDR_REGNUM
);
3045 emit_insn (gen_set_got (pic_offset_table_rtx
));
3049 SET_REGNO (pic_offset_table_rtx
, MB_ABI_PIC_ADDR_REGNUM
);
3050 /* setting start of text. */
3051 emit_insn (gen_set_text (pic_offset_table_rtx
));
3055 /* If we are profiling, make sure no instructions are scheduled before
3056 the call to mcount. */
3059 emit_insn (gen_blockage ());
3062 /* Do necessary cleanup after a function to restore stack, frame, and regs. */
3064 #define RA_MASK ((long) 0x80000000) /* 1 << 31 */
3065 #define PIC_OFFSET_TABLE_MASK (1 << (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST))
3068 microblaze_function_epilogue (FILE *file
)
3072 /* Get the function name the same way that toplev.cc does before calling
3073 assemble_start_function. This is needed so that the name used here
3074 exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */
3075 fnname
= XSTR (XEXP (DECL_RTL (current_function_decl
), 0), 0);
3077 if (!flag_inhibit_size_directive
)
3079 fputs ("\t.end\t", file
);
3080 if (interrupt_handler
&& !break_handler
)
3081 fputs ("_interrupt_handler", file
);
3082 else if (break_handler
)
3083 fputs ("_break_handler", file
);
3085 assemble_name (file
, fnname
);
3089 /* Reset state info for each function. */
3090 current_frame_info
= zero_frame_info
;
3092 /* Restore the output file if optimizing the GP (optimizing the GP causes
3093 the text to be diverted to a tempfile, so that data decls come before
3094 references to the data). */
3097 /* Expand the epilogue into a bunch of separate insns. */
3100 microblaze_expand_epilogue (void)
3102 HOST_WIDE_INT fsiz
= current_frame_info
.total_size
;
3103 rtx fsiz_rtx
= GEN_INT (fsiz
);
3107 /* In case of interrupt handlers use addki instead of addi for changing the
3108 stack pointer value. */
3110 if (microblaze_can_use_return_insn ())
3112 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode
,
3114 MB_ABI_SUB_RETURN_ADDR_REGNUM
)));
3120 /* Restore SUB_RETURN_ADDR_REGNUM at first. This is to prevent the
3121 sequence of load-followed by a use (in rtsd) in every prologue. Saves
3122 a load-use stall cycle :) This is also important to handle alloca.
3123 (See comments for if (frame_pointer_needed) below. */
3125 if (!crtl
->is_leaf
|| interrupt_handler
)
3128 gen_rtx_MEM (SImode
,
3129 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
, const0_rtx
));
3130 if (interrupt_handler
)
3131 /* Do not optimize in flow analysis. */
3132 MEM_VOLATILE_P (mem_rtx
) = 1;
3133 reg_rtx
= gen_rtx_REG (SImode
, MB_ABI_SUB_RETURN_ADDR_REGNUM
);
3134 emit_move_insn (reg_rtx
, mem_rtx
);
3137 /* It is important that this is done after we restore the return address
3138 register (above). When alloca is used, we want to restore the
3139 sub-routine return address only from the current stack top and not
3140 from the frame pointer (which we restore below). (frame_pointer + 0)
3141 might have been over-written since alloca allocates memory on the
3143 if (frame_pointer_needed
)
3144 emit_insn (gen_movsi (stack_pointer_rtx
, hard_frame_pointer_rtx
));
3146 /* _restore_ registers for epilogue. */
3147 save_restore_insns (0);
3148 emit_insn (gen_blockage ());
3149 emit_insn (gen_addsi3 (stack_pointer_rtx
, stack_pointer_rtx
, fsiz_rtx
));
3152 if (crtl
->calls_eh_return
)
3153 emit_insn (gen_addsi3 (stack_pointer_rtx
,
3155 gen_raw_REG (SImode
,
3156 MB_EH_STACKADJ_REGNUM
)));
3158 emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode
, GP_REG_FIRST
+
3159 MB_ABI_SUB_RETURN_ADDR_REGNUM
)));
3163 /* Return nonzero if this function is known to have a null epilogue.
3164 This allows the optimizer to omit jumps to jumps if no stack
3168 microblaze_can_use_return_insn (void)
3170 if (!reload_completed
)
3173 if (df_regs_ever_live_p (MB_ABI_SUB_RETURN_ADDR_REGNUM
) || profile_flag
)
3176 if (current_frame_info
.initialized
)
3177 return current_frame_info
.total_size
== 0;
3179 return compute_frame_size (get_frame_size ()) == 0;
3182 /* Implement TARGET_SECONDARY_RELOAD. */
3185 microblaze_secondary_reload (bool in_p ATTRIBUTE_UNUSED
, rtx x ATTRIBUTE_UNUSED
,
3186 reg_class_t rclass
, machine_mode mode ATTRIBUTE_UNUSED
,
3187 secondary_reload_info
*sri ATTRIBUTE_UNUSED
)
3189 if (rclass
== ST_REGS
)
3196 microblaze_globalize_label (FILE * stream
, const char *name
)
3198 fputs ("\t.globl\t", stream
);
3199 if (microblaze_is_interrupt_variant ())
3201 if (interrupt_handler
&& strcmp (name
, INTERRUPT_HANDLER_NAME
))
3202 fputs (INTERRUPT_HANDLER_NAME
, stream
);
3203 else if (break_handler
&& strcmp (name
, BREAK_HANDLER_NAME
))
3204 fputs (BREAK_HANDLER_NAME
, stream
);
3205 else if (fast_interrupt
&& strcmp (name
, FAST_INTERRUPT_NAME
))
3206 fputs (FAST_INTERRUPT_NAME
, stream
);
3207 fputs ("\n\t.globl\t", stream
);
3209 assemble_name (stream
, name
);
3210 fputs ("\n", stream
);
3213 /* Returns true if decl should be placed into a "small data" section. */
3215 microblaze_elf_in_small_data_p (const_tree decl
)
3219 if (!TARGET_XLGPOPT
)
3222 /* We want to merge strings, so we never consider them small data. */
3223 if (TREE_CODE (decl
) == STRING_CST
)
3226 /* Functions are never in the small data area. */
3227 if (TREE_CODE (decl
) == FUNCTION_DECL
)
3230 if (TREE_CODE (decl
) == VAR_DECL
&& DECL_SECTION_NAME (decl
))
3232 const char *section
= DECL_SECTION_NAME (decl
);
3233 if (strcmp (section
, ".sdata") == 0
3234 || strcmp (section
, ".sdata2") == 0
3235 || strcmp (section
, ".sbss") == 0
3236 || strcmp (section
, ".sbss2") == 0)
3240 size
= int_size_in_bytes (TREE_TYPE (decl
));
3242 return (size
> 0 && size
<= microblaze_section_threshold
);
3245 /* We need to disable address diff vectors in
3246 case of pic data text relative mode. */
3249 microblaze_gen_pic_addr_dif_vec (void)
3251 return (flag_pic
&& !TARGET_PIC_DATA_TEXT_REL
);
3255 microblaze_select_section (tree decl
, int reloc
, unsigned HOST_WIDE_INT align
)
3257 switch (categorize_decl_for_section (decl
, reloc
))
3259 case SECCAT_RODATA_MERGE_STR
:
3260 case SECCAT_RODATA_MERGE_STR_INIT
:
3261 /* MB binutils have various issues with mergeable string sections and
3262 relaxation/relocation. Currently, turning mergeable sections
3263 into regular readonly sections. */
3265 return readonly_data_section
;
3267 return default_elf_select_section (decl
, reloc
, align
);
3272 Encode info about sections into the RTL based on a symbol's declaration.
3273 The default definition of this hook, default_encode_section_info in
3274 `varasm.cc', sets a number of commonly-useful bits in SYMBOL_REF_FLAGS. */
3277 microblaze_encode_section_info (tree decl
, rtx rtl
, int first
)
3279 default_encode_section_info (decl
, rtl
, first
);
3283 expand_pic_symbol_ref (machine_mode mode ATTRIBUTE_UNUSED
, rtx op
)
3286 bool isFunc
= (GET_CODE (op
) == SYMBOL_REF
3287 && (SYMBOL_REF_FLAGS (op
) & SYMBOL_FLAG_FUNCTION
));
3288 result
= (!TARGET_PIC_DATA_TEXT_REL
)
3289 ? gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, op
), UNSPEC_GOTOFF
)
3290 : gen_rtx_UNSPEC (Pmode
, gen_rtvec (1, op
), UNSPEC_TEXT
);
3291 result
= gen_rtx_CONST (Pmode
, result
);
3292 result
= (TARGET_PIC_DATA_TEXT_REL
&& isFunc
)
3293 ? gen_rtx_PLUS (Pmode
, gen_raw_REG (Pmode
,
3294 get_base_reg (op
)), result
)
3295 : gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
, result
);
3296 result
= (!TARGET_PIC_DATA_TEXT_REL
)
3297 ? gen_const_mem (Pmode
, result
) : result
;
3303 microblaze_asm_output_mi_thunk (FILE *file
, tree thunk_fndecl ATTRIBUTE_UNUSED
,
3304 HOST_WIDE_INT delta
, HOST_WIDE_INT vcall_offset
,
3307 const char *fnname
= IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (thunk_fndecl
));
3308 rtx this_rtx
, funexp
;
3311 reload_completed
= 1;
3312 epilogue_completed
= 1;
3314 /* Mark the end of the (empty) prologue. */
3315 emit_note (NOTE_INSN_PROLOGUE_END
);
3317 /* Find the "this" pointer. If the function returns a structure,
3318 the structure return pointer is in MB_ABI_FIRST_ARG_REGNUM. */
3319 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function
)), function
))
3320 this_rtx
= gen_rtx_REG (Pmode
, (MB_ABI_FIRST_ARG_REGNUM
+ 1));
3322 this_rtx
= gen_rtx_REG (Pmode
, MB_ABI_FIRST_ARG_REGNUM
);
3324 /* Apply the constant offset, if required. */
3326 emit_insn (gen_addsi3 (this_rtx
, this_rtx
, GEN_INT (delta
)));
3328 /* Apply the offset from the vtable, if required. */
3331 rtx vcall_offset_rtx
= GEN_INT (vcall_offset
);
3332 rtx temp1
= gen_rtx_REG (Pmode
, MB_ABI_TEMP1_REGNUM
);
3334 emit_move_insn (temp1
, gen_rtx_MEM (Pmode
, this_rtx
));
3336 rtx loc
= gen_rtx_PLUS (Pmode
, temp1
, vcall_offset_rtx
);
3337 emit_move_insn (temp1
, gen_rtx_MEM (Pmode
, loc
));
3339 emit_insn (gen_addsi3 (this_rtx
, this_rtx
, temp1
));
3342 /* Generate a tail call to the target function. */
3343 if (!TREE_USED (function
))
3345 assemble_external (function
);
3346 TREE_USED (function
) = 1;
3349 funexp
= XEXP (DECL_RTL (function
), 0);
3350 rtx temp2
= gen_rtx_REG (Pmode
, MB_ABI_TEMP2_REGNUM
);
3353 emit_move_insn (temp2
, expand_pic_symbol_ref (Pmode
, funexp
));
3355 emit_move_insn (temp2
, funexp
);
3357 emit_insn (gen_indirect_jump (temp2
));
3359 /* Run just enough of rest_of_compilation. This sequence was
3360 "borrowed" from rs6000.cc. */
3361 insn
= get_insns ();
3362 shorten_branches (insn
);
3363 assemble_start_function (thunk_fndecl
, fnname
);
3364 final_start_function (insn
, file
, 1);
3365 final (insn
, file
, 1);
3366 final_end_function ();
3367 assemble_end_function (thunk_fndecl
, fnname
);
3369 reload_completed
= 0;
3370 epilogue_completed
= 0;
3374 microblaze_expand_move (machine_mode mode
, rtx operands
[])
3381 if (!register_operand (op0
, SImode
)
3382 && !register_operand (op1
, SImode
)
3383 && (GET_CODE (op1
) != CONST_INT
|| INTVAL (op1
) != 0))
3385 rtx temp
= force_reg (SImode
, op1
);
3386 emit_move_insn (op0
, temp
);
3389 /* If operands[1] is a constant address invalid for pic, then we need to
3390 handle it just like LEGITIMIZE_ADDRESS does. */
3391 if (GET_CODE (op1
) == SYMBOL_REF
|| GET_CODE (op1
) == LABEL_REF
)
3394 if (microblaze_tls_symbol_p(op1
))
3396 result
= microblaze_legitimize_tls_address (op1
, NULL_RTX
);
3397 emit_move_insn (op0
, result
);
3402 if (reload_in_progress
)
3403 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
3404 result
= expand_pic_symbol_ref (mode
, op1
);
3406 if (TARGET_PIC_DATA_TEXT_REL
&& GET_CODE (op0
) == REG
3407 && REGNO (op0
) >= FIRST_PSEUDO_REGISTER
)
3408 result
= force_reg (SImode
, result
);
3410 emit_move_insn (op0
, result
);
3414 if (GET_CODE (op1
) == PLUS
&& GET_CODE (XEXP (op1
,1)) == CONST
)
3416 rtx p0
, p1
, result
, temp
;
3418 p0
= XEXP (XEXP (op1
,1), 0);
3420 if (GET_CODE (p0
) == PLUS
)
3426 if (GET_CODE (p0
) == UNSPEC
&& GET_CODE (p1
) == CONST_INT
3427 && flag_pic
&& TARGET_PIC_DATA_TEXT_REL
)
3429 result
= gen_rtx_CONST (Pmode
, p0
);
3430 result
= gen_rtx_PLUS (Pmode
, pic_offset_table_rtx
, result
);
3431 temp
= force_reg (SImode
, result
);
3432 emit_move_insn (op0
, gen_rtx_PLUS (SImode
, temp
, p1
));
3436 /* Handle Case of (const (plus symbol const_int)). */
3437 if (GET_CODE (op1
) == CONST
&& GET_CODE (XEXP (op1
,0)) == PLUS
)
3441 p0
= XEXP (XEXP (op1
, 0), 0);
3442 p1
= XEXP (XEXP (op1
, 0), 1);
3444 if ((GET_CODE (p1
) == CONST_INT
)
3445 && ((GET_CODE (p0
) == UNSPEC
)
3446 || ((GET_CODE (p0
) == SYMBOL_REF
|| GET_CODE (p0
) == LABEL_REF
)
3447 && (flag_pic
== 2 || microblaze_tls_symbol_p (p0
)
3448 || !SMALL_INT (p1
)))))
3450 rtx temp
= force_reg (SImode
, p0
);
3453 if (flag_pic
&& reload_in_progress
)
3454 df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM
, true);
3455 emit_move_insn (op0
, gen_rtx_PLUS (SImode
, temp
, temp2
));
3462 /* Expand shift operations. */
3464 microblaze_expand_shift (rtx operands
[])
3466 gcc_assert ((GET_CODE (operands
[2]) == CONST_INT
)
3467 || (GET_CODE (operands
[2]) == REG
)
3468 || (GET_CODE (operands
[2]) == SUBREG
));
3470 /* Shift by one -- generate pattern. */
3471 if ((GET_CODE (operands
[2]) == CONST_INT
) && (INTVAL (operands
[2]) == 1))
3474 /* Have barrel shifter and shift > 1: use it. */
3475 if (TARGET_BARREL_SHIFT
)
3478 gcc_assert ((GET_CODE (operands
[0]) == REG
)
3479 || (GET_CODE (operands
[0]) == SUBREG
)
3480 || (GET_CODE (operands
[1]) == REG
)
3481 || (GET_CODE (operands
[1]) == SUBREG
));
3483 /* Shift by zero -- copy regs if necessary. */
3484 if (operands
[2] == const0_rtx
3485 && !rtx_equal_p (operands
[0], operands
[1]))
3487 emit_insn (gen_movsi (operands
[0], operands
[1]));
3494 /* Return an RTX indicating where the return address to the
3495 calling function can be found. */
3497 microblaze_return_addr (int count
, rtx frame ATTRIBUTE_UNUSED
)
3502 return get_hard_reg_initial_val (Pmode
,
3503 MB_ABI_SUB_RETURN_ADDR_REGNUM
);
3507 microblaze_eh_return (rtx op0
)
3509 emit_insn (gen_movsi (gen_rtx_MEM (Pmode
, stack_pointer_rtx
), op0
));
3512 /* Queue an .ident string in the queue of top-level asm statements.
3513 If the string size is below the threshold, put it into .sdata2.
3514 If the front-end is done, we must be being called from toplev.cc.
3515 In that case, do nothing. */
3517 microblaze_asm_output_ident (const char *string
)
3519 const char *section_asm_op
;
3523 if (symtab
->state
!= PARSING
)
3526 size
= strlen (string
) + 1;
3527 if (size
<= microblaze_section_threshold
)
3528 section_asm_op
= SDATA2_SECTION_ASM_OP
;
3530 section_asm_op
= READONLY_DATA_SECTION_ASM_OP
;
3532 buf
= ACONCAT (("\t.pushsection", section_asm_op
,
3533 "\n\t.ascii \"", string
, "\\0\"\n",
3534 "\t.popsection\n", NULL
));
3535 symtab
->finalize_toplevel_asm (build_string (strlen (buf
), buf
));
3539 microblaze_elf_asm_init_sections (void)
3542 = get_unnamed_section (SECTION_WRITE
, output_section_asm_op
,
3543 SDATA2_SECTION_ASM_OP
);
3546 /* Generate assembler code for constant parts of a trampoline. */
3549 microblaze_asm_trampoline_template (FILE *f
)
3551 fprintf (f
, "\tmfs r18, rpc\n");
3552 fprintf (f
, "\tlwi r3, r18, 16\n");
3553 fprintf (f
, "\tlwi r18, r18, 20\n");
3554 fprintf (f
, "\tbra r18\n");
3555 /* fprintf (f, "\t.word\t0x00000000\t\t# <function address>\n"); */
3556 /* fprintf (f, "\t.word\t0x00000000\t\t# <static chain value>\n"); */
3559 /* Implement TARGET_TRAMPOLINE_INIT. */
3562 microblaze_trampoline_init (rtx m_tramp
, tree fndecl
, rtx chain_value
)
3564 rtx fnaddr
= XEXP (DECL_RTL (fndecl
), 0);
3567 emit_block_move (m_tramp
, assemble_trampoline_template (),
3568 GEN_INT (6*UNITS_PER_WORD
), BLOCK_OP_NORMAL
);
3570 mem
= adjust_address (m_tramp
, SImode
, 16);
3571 emit_move_insn (mem
, chain_value
);
3572 mem
= adjust_address (m_tramp
, SImode
, 20);
3573 emit_move_insn (mem
, fnaddr
);
3576 /* Generate conditional branch -- first, generate test condition,
3577 second, generate correct branch instruction. */
3580 microblaze_expand_conditional_branch (machine_mode mode
, rtx operands
[])
3582 enum rtx_code code
= GET_CODE (operands
[0]);
3583 rtx cmp_op0
= operands
[1];
3584 rtx cmp_op1
= operands
[2];
3585 rtx label1
= operands
[3];
3586 rtx comp_reg
= gen_reg_rtx (SImode
);
3589 gcc_assert ((GET_CODE (cmp_op0
) == REG
) || (GET_CODE (cmp_op0
) == SUBREG
));
3591 /* If comparing against zero, just test source reg. */
3592 if (cmp_op1
== const0_rtx
)
3595 condition
= gen_rtx_fmt_ee (signed_condition (code
), SImode
, comp_reg
, const0_rtx
);
3596 emit_jump_insn (gen_condjump (condition
, label1
));
3599 else if (code
== EQ
|| code
== NE
)
3601 /* Use xor for equal/not-equal comparison. */
3602 emit_insn (gen_xorsi3 (comp_reg
, cmp_op0
, cmp_op1
));
3603 condition
= gen_rtx_fmt_ee (signed_condition (code
), SImode
, comp_reg
, const0_rtx
);
3604 emit_jump_insn (gen_condjump (condition
, label1
));
3608 /* Generate compare and branch in single instruction. */
3609 cmp_op1
= force_reg (mode
, cmp_op1
);
3610 condition
= gen_rtx_fmt_ee (code
, mode
, cmp_op0
, cmp_op1
);
3611 emit_jump_insn (gen_branch_compare(condition
, cmp_op0
, cmp_op1
, label1
));
3616 microblaze_expand_conditional_branch_reg (machine_mode mode
, rtx operands
[])
3618 enum rtx_code code
= GET_CODE (operands
[0]);
3619 rtx cmp_op0
= operands
[1];
3620 rtx cmp_op1
= operands
[2];
3621 rtx label1
= operands
[3];
3622 rtx comp_reg
= gen_reg_rtx (SImode
);
3625 gcc_assert ((GET_CODE (cmp_op0
) == REG
)
3626 || (GET_CODE (cmp_op0
) == SUBREG
));
3628 /* If comparing against zero, just test source reg. */
3629 if (cmp_op1
== const0_rtx
)
3632 condition
= gen_rtx_fmt_ee (signed_condition (code
),
3633 SImode
, comp_reg
, const0_rtx
);
3634 emit_jump_insn (gen_condjump (condition
, label1
));
3636 else if (code
== EQ
)
3638 emit_insn (gen_seq_internal_pat (comp_reg
,
3640 condition
= gen_rtx_EQ (SImode
, comp_reg
, const0_rtx
);
3641 emit_jump_insn (gen_condjump (condition
, label1
));
3643 else if (code
== NE
)
3645 emit_insn (gen_sne_internal_pat (comp_reg
, cmp_op0
,
3647 condition
= gen_rtx_NE (SImode
, comp_reg
, const0_rtx
);
3648 emit_jump_insn (gen_condjump (condition
, label1
));
3652 /* Generate compare and branch in single instruction. */
3653 cmp_op1
= force_reg (mode
, cmp_op1
);
3654 condition
= gen_rtx_fmt_ee (code
, mode
, cmp_op0
, cmp_op1
);
3655 emit_jump_insn (gen_branch_compare (condition
, cmp_op0
,
3661 microblaze_expand_conditional_branch_sf (rtx operands
[])
3664 rtx cmp_op0
= XEXP (operands
[0], 0);
3665 rtx cmp_op1
= XEXP (operands
[0], 1);
3666 rtx comp_reg
= gen_reg_rtx (SImode
);
3668 emit_insn (gen_cstoresf4 (comp_reg
, operands
[0], cmp_op0
, cmp_op1
));
3669 condition
= gen_rtx_NE (SImode
, comp_reg
, const0_rtx
);
3670 emit_jump_insn (gen_condjump (condition
, operands
[3]));
3673 /* Implement TARGET_FRAME_POINTER_REQUIRED. */
3676 microblaze_frame_pointer_required (void)
3678 /* If the function contains dynamic stack allocations, we need to
3679 use the frame pointer to access the static parts of the frame. */
3680 if (cfun
->calls_alloca
)
3686 microblaze_expand_divide (rtx operands
[])
3688 /* Table lookup software divides. Works for all (nr/dr) where (0 <= nr,dr <= 15). */
3690 rtx regt1
= gen_reg_rtx (SImode
);
3691 rtx reg18
= gen_rtx_REG (SImode
, R_TMP
);
3692 rtx regqi
= gen_reg_rtx (QImode
);
3693 rtx_code_label
*div_label
= gen_label_rtx ();
3694 rtx_code_label
*div_end_label
= gen_label_rtx ();
3695 rtx div_table_rtx
= gen_rtx_SYMBOL_REF (QImode
,"_divsi3_table");
3698 rtx_insn
*jump
, *cjump
, *insn
;
3700 insn
= emit_insn (gen_iorsi3 (regt1
, operands
[1], operands
[2]));
3701 cjump
= emit_jump_insn_after (gen_cbranchsi4 (
3702 gen_rtx_GTU (SImode
, regt1
, GEN_INT (15)),
3703 regt1
, GEN_INT (15), div_label
), insn
);
3704 LABEL_NUSES (div_label
) = 1;
3705 JUMP_LABEL (cjump
) = div_label
;
3706 emit_insn (gen_rtx_CLOBBER (SImode
, reg18
));
3708 emit_insn (gen_ashlsi3_bshift (regt1
, operands
[1], GEN_INT(4)));
3709 emit_insn (gen_addsi3 (regt1
, regt1
, operands
[2]));
3710 mem_rtx
= gen_rtx_MEM (QImode
,
3711 gen_rtx_PLUS (Pmode
, regt1
, div_table_rtx
));
3713 insn
= emit_insn (gen_movqi (regqi
, mem_rtx
));
3714 insn
= emit_insn (gen_movsi (operands
[0], gen_rtx_SUBREG (SImode
, regqi
, 0)));
3715 jump
= emit_jump_insn_after (gen_jump (div_end_label
), insn
);
3716 JUMP_LABEL (jump
) = div_end_label
;
3717 LABEL_NUSES (div_end_label
) = 1;
3720 emit_label (div_label
);
3721 ret
= emit_library_call_value (gen_rtx_SYMBOL_REF (Pmode
, "__divsi3"),
3722 operands
[0], LCT_NORMAL
,
3723 GET_MODE (operands
[0]),
3724 operands
[1], GET_MODE (operands
[1]),
3725 operands
[2], GET_MODE (operands
[2]));
3726 if (ret
!= operands
[0])
3727 emit_move_insn (operands
[0], ret
);
3729 emit_label (div_end_label
);
3730 emit_insn (gen_blockage ());
3733 /* Implement TARGET_FUNCTION_VALUE. */
3735 microblaze_function_value (const_tree valtype
,
3736 const_tree func ATTRIBUTE_UNUSED
,
3737 bool outgoing ATTRIBUTE_UNUSED
)
3739 return LIBCALL_VALUE (TYPE_MODE (valtype
));
3742 /* Implement TARGET_SCHED_ADJUST_COST. */
3744 microblaze_adjust_cost (rtx_insn
*, int dep_type
, rtx_insn
*, int cost
,
3747 if (dep_type
== REG_DEP_OUTPUT
|| dep_type
== 0)
3752 /* Implement TARGET_LEGITIMATE_CONSTANT_P.
3754 At present, GAS doesn't understand li.[sd], so don't allow it
3755 to be generated at present. */
3757 microblaze_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED
, rtx x
)
3760 if (microblaze_cannot_force_const_mem(mode
, x
))
3763 if (GET_CODE (x
) == CONST_DOUBLE
)
3765 return microblaze_const_double_ok (x
, GET_MODE (x
));
3768 /* Handle Case of (const (plus unspec const_int)). */
3769 if (GET_CODE (x
) == CONST
&& GET_CODE (XEXP (x
,0)) == PLUS
)
3773 p0
= XEXP (XEXP (x
, 0), 0);
3774 p1
= XEXP (XEXP (x
, 0), 1);
3776 if (GET_CODE(p1
) == CONST_INT
)
3778 /* Const offset from UNSPEC is not supported. */
3779 if ((GET_CODE (p0
) == UNSPEC
))
3782 if ((GET_CODE (p0
) == SYMBOL_REF
|| GET_CODE (p0
) == LABEL_REF
)
3783 && (microblaze_tls_symbol_p (p0
) || !SMALL_INT (p1
)))
3792 get_branch_target (rtx branch
)
3794 if (CALL_P (branch
))
3798 call
= XVECEXP (PATTERN (branch
), 0, 0);
3799 if (GET_CODE (call
) == SET
)
3800 call
= SET_SRC (call
);
3801 if (GET_CODE (call
) != CALL
)
3803 return XEXP (XEXP (call
, 0), 0);
3809 /* Heuristics to identify where to insert at the
3810 fall through path of the caller function. If there
3811 is a call after the caller branch delay slot then
3812 we dont generate the instruction prefetch instruction.
3814 Scan up to 32 instructions after the call and checks
3815 for the JUMP and call instruction . If there is a call
3816 or JUMP instruction in the range of 32 instruction "wic"
3817 instruction wont be generated. Otherwise insert the "wic"
3818 instruction in the fall through of the call instruction
3819 four instruction after the call. before_4 is used for
3820 the position to insert "wic" instructions. before_16 is
3821 used to check for call and JUMP instruction for first
3825 insert_wic_for_ilb_runout (rtx_insn
*first
)
3828 rtx_insn
*before_4
= 0;
3829 rtx_insn
*before_16
= 0;
3830 int addr_offset
= 0;
3832 int wic_addr0
= 128 * 4;
3834 int first_addr
= INSN_ADDRESSES (INSN_UID (first
));
3836 for (insn
= first
; insn
; insn
= NEXT_INSN (insn
))
3839 addr_offset
= INSN_ADDRESSES (INSN_UID (insn
)) - first_addr
;
3840 length
= get_attr_length (insn
);
3841 if (before_4
== 0 && addr_offset
+ length
>= 4 * 4)
3846 if (before_16
== 0 && addr_offset
+ length
>= 14 * 4)
3848 if (CALL_P (insn
) || tablejump_p (insn
, 0, 0))
3850 if (addr_offset
+ length
>= 32 * 4)
3852 gcc_assert (before_4
&& before_16
);
3853 if (wic_addr0
> 4 * 4)
3856 emit_insn_before (gen_iprefetch
3857 (gen_int_mode (addr_offset
, SImode
)),
3859 recog_memoized (insn
);
3860 INSN_LOCATION (insn
) = INSN_LOCATION (before_4
);
3861 INSN_ADDRESSES_NEW (insn
, INSN_ADDRESSES (INSN_UID (before_4
)));
3868 /* Insert instruction prefetch instruction at the fall
3869 through path of the function call. */
3876 basic_block bb
, prev
= 0;
3877 rtx branch_target
= 0;
3879 shorten_branches (get_insns ());
3881 for (i
= 0; i
< n_basic_blocks_for_fn (cfun
) - 1; i
++)
3885 bool simple_loop
= false;
3887 bb
= BASIC_BLOCK_FOR_FN (cfun
, i
);
3892 if ((prev
!= 0) && (prev
!= bb
))
3897 FOR_EACH_EDGE (e
, ei
, bb
->preds
)
3905 for (insn
= BB_END (bb
); insn
; insn
= PREV_INSN (insn
))
3907 if (INSN_P (insn
) && !simple_loop
3910 if ((branch_target
= get_branch_target (insn
)))
3911 insert_wic_for_ilb_runout (
3912 next_active_insn (next_active_insn (insn
)));
3914 if (insn
== BB_HEAD (bb
))
3920 /* The reorg function defined through the macro
3921 TARGET_MACHINE_DEPENDENT_REORG. */
3924 microblaze_machine_dependent_reorg (void)
3926 if (TARGET_PREFETCH
)
3928 compute_bb_for_insn ();
3929 loop_optimizer_init (AVOID_CFG_MODIFICATIONS
);
3930 shorten_branches (get_insns ());
3932 loop_optimizer_finalize ();
3933 free_bb_for_insn ();
3938 /* Implement TARGET_CONSTANT_ALIGNMENT. */
3940 static HOST_WIDE_INT
3941 microblaze_constant_alignment (const_tree exp
, HOST_WIDE_INT align
)
3943 if (TREE_CODE (exp
) == STRING_CST
|| TREE_CODE (exp
) == CONSTRUCTOR
)
3944 return MAX (align
, BITS_PER_WORD
);
3948 /* Implement TARGET_STARTING_FRAME_OFFSET. */
3950 static HOST_WIDE_INT
3951 microblaze_starting_frame_offset (void)
3953 return (crtl
->outgoing_args_size
+ FIRST_PARM_OFFSET(FNDECL
));
3956 #undef TARGET_ENCODE_SECTION_INFO
3957 #define TARGET_ENCODE_SECTION_INFO microblaze_encode_section_info
3959 #undef TARGET_ASM_GLOBALIZE_LABEL
3960 #define TARGET_ASM_GLOBALIZE_LABEL microblaze_globalize_label
3962 #undef TARGET_ASM_FUNCTION_PROLOGUE
3963 #define TARGET_ASM_FUNCTION_PROLOGUE microblaze_function_prologue
3965 #undef TARGET_ASM_FUNCTION_EPILOGUE
3966 #define TARGET_ASM_FUNCTION_EPILOGUE microblaze_function_epilogue
3968 #undef TARGET_RTX_COSTS
3969 #define TARGET_RTX_COSTS microblaze_rtx_costs
3971 #undef TARGET_CANNOT_FORCE_CONST_MEM
3972 #define TARGET_CANNOT_FORCE_CONST_MEM microblaze_cannot_force_const_mem
3974 #undef TARGET_ADDRESS_COST
3975 #define TARGET_ADDRESS_COST microblaze_address_cost
3977 #undef TARGET_ATTRIBUTE_TABLE
3978 #define TARGET_ATTRIBUTE_TABLE microblaze_attribute_table
3980 #undef TARGET_IN_SMALL_DATA_P
3981 #define TARGET_IN_SMALL_DATA_P microblaze_elf_in_small_data_p
3983 #undef TARGET_ASM_SELECT_SECTION
3984 #define TARGET_ASM_SELECT_SECTION microblaze_select_section
3986 #undef TARGET_HAVE_SRODATA_SECTION
3987 #define TARGET_HAVE_SRODATA_SECTION true
3989 #undef TARGET_ASM_FUNCTION_END_PROLOGUE
3990 #define TARGET_ASM_FUNCTION_END_PROLOGUE \
3991 microblaze_function_end_prologue
3993 #undef TARGET_ARG_PARTIAL_BYTES
3994 #define TARGET_ARG_PARTIAL_BYTES function_arg_partial_bytes
3996 #undef TARGET_FUNCTION_ARG
3997 #define TARGET_FUNCTION_ARG microblaze_function_arg
3999 #undef TARGET_FUNCTION_ARG_ADVANCE
4000 #define TARGET_FUNCTION_ARG_ADVANCE microblaze_function_arg_advance
4002 #undef TARGET_CAN_ELIMINATE
4003 #define TARGET_CAN_ELIMINATE microblaze_can_eliminate
4005 #undef TARGET_LEGITIMIZE_ADDRESS
4006 #define TARGET_LEGITIMIZE_ADDRESS microblaze_legitimize_address
4008 #undef TARGET_LEGITIMATE_ADDRESS_P
4009 #define TARGET_LEGITIMATE_ADDRESS_P microblaze_legitimate_address_p
4012 #define TARGET_LRA_P hook_bool_void_false
4014 #undef TARGET_FRAME_POINTER_REQUIRED
4015 #define TARGET_FRAME_POINTER_REQUIRED microblaze_frame_pointer_required
4017 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
4018 #define TARGET_ASM_TRAMPOLINE_TEMPLATE microblaze_asm_trampoline_template
4020 #undef TARGET_TRAMPOLINE_INIT
4021 #define TARGET_TRAMPOLINE_INIT microblaze_trampoline_init
4023 #undef TARGET_PROMOTE_FUNCTION_MODE
4024 #define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
4026 #undef TARGET_FUNCTION_VALUE
4027 #define TARGET_FUNCTION_VALUE microblaze_function_value
4029 #undef TARGET_SECONDARY_RELOAD
4030 #define TARGET_SECONDARY_RELOAD microblaze_secondary_reload
4032 #undef TARGET_ASM_OUTPUT_MI_THUNK
4033 #define TARGET_ASM_OUTPUT_MI_THUNK microblaze_asm_output_mi_thunk
4035 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
4036 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true
4038 #undef TARGET_SCHED_ADJUST_COST
4039 #define TARGET_SCHED_ADJUST_COST microblaze_adjust_cost
4041 #undef TARGET_ASM_INIT_SECTIONS
4042 #define TARGET_ASM_INIT_SECTIONS microblaze_elf_asm_init_sections
4044 #undef TARGET_OPTION_OVERRIDE
4045 #define TARGET_OPTION_OVERRIDE microblaze_option_override
4047 #undef TARGET_LEGITIMATE_CONSTANT_P
4048 #define TARGET_LEGITIMATE_CONSTANT_P microblaze_legitimate_constant_p
4050 #undef TARGET_ASM_GENERATE_PIC_ADDR_DIFF_VEC
4051 #define TARGET_ASM_GENERATE_PIC_ADDR_DIFF_VEC microblaze_gen_pic_addr_dif_vec
4053 #undef TARGET_MACHINE_DEPENDENT_REORG
4054 #define TARGET_MACHINE_DEPENDENT_REORG microblaze_machine_dependent_reorg
4056 #undef TARGET_HARD_REGNO_MODE_OK
4057 #define TARGET_HARD_REGNO_MODE_OK microblaze_hard_regno_mode_ok
4059 #undef TARGET_MODES_TIEABLE_P
4060 #define TARGET_MODES_TIEABLE_P microblaze_modes_tieable_p
4062 #undef TARGET_CONSTANT_ALIGNMENT
4063 #define TARGET_CONSTANT_ALIGNMENT microblaze_constant_alignment
4065 #undef TARGET_STARTING_FRAME_OFFSET
4066 #define TARGET_STARTING_FRAME_OFFSET microblaze_starting_frame_offset
4068 struct gcc_target targetm
= TARGET_INITIALIZER
;
4070 #include "gt-microblaze.h"