1 /* Output routines for Sunplus S+CORE processor
2 Copyright (C) 2005-2014 Free Software Foundation, Inc.
3 Contributed by Sunnorth.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published
9 by the Free Software Foundation; either version 3, or (at your
10 option) any later version.
12 GCC is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
15 License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
23 #include "coretypes.h"
27 #include "hard-reg-set.h"
28 #include "insn-config.h"
29 #include "conditions.h"
30 #include "insn-attr.h"
32 #include "diagnostic-core.h"
35 #include "stringpool.h"
38 #include "stor-layout.h"
50 #include "target-def.h"
51 #include "langhooks.h"
56 #define SCORE_SDATA_MAX score_sdata_max
57 #define SCORE_STACK_ALIGN(LOC) (((LOC) + 3) & ~3)
58 #define SCORE_PROLOGUE_TEMP_REGNUM (GP_REG_FIRST + 8)
59 #define SCORE_EPILOGUE_TEMP_REGNUM (GP_REG_FIRST + 8)
60 #define SCORE_DEFAULT_SDATA_MAX 8
62 #define BITSET_P(VALUE, BIT) (((VALUE) & (1L << (BIT))) != 0)
63 #define INS_BUF_SZ 128
65 enum score_address_type
72 struct score_frame_info
74 HOST_WIDE_INT total_size
; /* bytes that the entire frame takes up */
75 HOST_WIDE_INT var_size
; /* bytes that variables take up */
76 HOST_WIDE_INT args_size
; /* bytes that outgoing arguments take up */
77 HOST_WIDE_INT gp_reg_size
; /* bytes needed to store gp regs */
78 HOST_WIDE_INT gp_sp_offset
; /* offset from new sp to store gp registers */
79 HOST_WIDE_INT cprestore_size
; /* # bytes that the .cprestore slot takes up */
80 unsigned int mask
; /* mask of saved gp registers */
81 int num_gp
; /* number of gp registers saved */
86 unsigned int num_bytes
; /* The argument's size in bytes */
87 unsigned int reg_words
; /* The number of words passed in registers */
88 unsigned int reg_offset
; /* The offset of the first register from */
89 /* GP_ARG_FIRST or FP_ARG_FIRST etc */
90 unsigned int stack_words
; /* The number of words that must be passed */
92 unsigned int stack_offset
; /* The offset from the start of the stack */
97 struct score_address_info
99 enum score_address_type type
;
103 enum score_symbol_type symbol_type
;
107 static int score_sdata_max
;
108 static char score_ins
[INS_BUF_SZ
+ 8];
110 struct extern_list
*extern_head
= 0;
112 #undef TARGET_ASM_FILE_START
113 #define TARGET_ASM_FILE_START score_asm_file_start
115 #undef TARGET_ASM_FILE_END
116 #define TARGET_ASM_FILE_END score_asm_file_end
118 #undef TARGET_ASM_FUNCTION_PROLOGUE
119 #define TARGET_ASM_FUNCTION_PROLOGUE score_function_prologue
121 #undef TARGET_ASM_FUNCTION_EPILOGUE
122 #define TARGET_ASM_FUNCTION_EPILOGUE score_function_epilogue
124 #undef TARGET_OPTION_OVERRIDE
125 #define TARGET_OPTION_OVERRIDE score_option_override
127 #undef TARGET_SCHED_ISSUE_RATE
128 #define TARGET_SCHED_ISSUE_RATE score_issue_rate
130 #undef TARGET_ASM_SELECT_RTX_SECTION
131 #define TARGET_ASM_SELECT_RTX_SECTION score_select_rtx_section
133 #undef TARGET_IN_SMALL_DATA_P
134 #define TARGET_IN_SMALL_DATA_P score_in_small_data_p
136 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
137 #define TARGET_FUNCTION_OK_FOR_SIBCALL score_function_ok_for_sibcall
139 #undef TARGET_STRICT_ARGUMENT_NAMING
140 #define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true
142 #undef TARGET_ASM_OUTPUT_MI_THUNK
143 #define TARGET_ASM_OUTPUT_MI_THUNK score_output_mi_thunk
145 #undef TARGET_PROMOTE_FUNCTION_MODE
146 #define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
148 #undef TARGET_PROMOTE_PROTOTYPES
149 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
151 #undef TARGET_MUST_PASS_IN_STACK
152 #define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size
154 #undef TARGET_ARG_PARTIAL_BYTES
155 #define TARGET_ARG_PARTIAL_BYTES score_arg_partial_bytes
157 #undef TARGET_FUNCTION_ARG
158 #define TARGET_FUNCTION_ARG score_function_arg
160 #undef TARGET_FUNCTION_ARG_ADVANCE
161 #define TARGET_FUNCTION_ARG_ADVANCE score_function_arg_advance
163 #undef TARGET_PASS_BY_REFERENCE
164 #define TARGET_PASS_BY_REFERENCE score_pass_by_reference
166 #undef TARGET_RETURN_IN_MEMORY
167 #define TARGET_RETURN_IN_MEMORY score_return_in_memory
169 #undef TARGET_RTX_COSTS
170 #define TARGET_RTX_COSTS score_rtx_costs
172 #undef TARGET_ADDRESS_COST
173 #define TARGET_ADDRESS_COST score_address_cost
175 #undef TARGET_LEGITIMATE_ADDRESS_P
176 #define TARGET_LEGITIMATE_ADDRESS_P score_legitimate_address_p
178 #undef TARGET_CAN_ELIMINATE
179 #define TARGET_CAN_ELIMINATE score_can_eliminate
181 #undef TARGET_CONDITIONAL_REGISTER_USAGE
182 #define TARGET_CONDITIONAL_REGISTER_USAGE score_conditional_register_usage
184 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
185 #define TARGET_ASM_TRAMPOLINE_TEMPLATE score_asm_trampoline_template
186 #undef TARGET_TRAMPOLINE_INIT
187 #define TARGET_TRAMPOLINE_INIT score_trampoline_init
189 #undef TARGET_REGISTER_MOVE_COST
190 #define TARGET_REGISTER_MOVE_COST score_register_move_cost
192 /* Return true if SYMBOL is a SYMBOL_REF and OFFSET + SYMBOL points
193 to the same object as SYMBOL. */
195 score_offset_within_object_p (rtx symbol
, HOST_WIDE_INT offset
)
197 if (GET_CODE (symbol
) != SYMBOL_REF
)
200 if (CONSTANT_POOL_ADDRESS_P (symbol
)
202 && offset
< (int)GET_MODE_SIZE (get_pool_mode (symbol
)))
205 if (SYMBOL_REF_DECL (symbol
) != 0
207 && offset
< int_size_in_bytes (TREE_TYPE (SYMBOL_REF_DECL (symbol
))))
213 /* Split X into a base and a constant offset, storing them in *BASE
214 and *OFFSET respectively. */
216 score_split_const (rtx x
, rtx
*base
, HOST_WIDE_INT
*offset
)
220 if (GET_CODE (x
) == CONST
)
223 if (GET_CODE (x
) == PLUS
&& GET_CODE (XEXP (x
, 1)) == CONST_INT
)
225 *offset
+= INTVAL (XEXP (x
, 1));
232 /* Classify symbol X, which must be a SYMBOL_REF or a LABEL_REF. */
233 static enum score_symbol_type
234 score_classify_symbol (rtx x
)
236 if (GET_CODE (x
) == LABEL_REF
)
237 return SYMBOL_GENERAL
;
239 gcc_assert (GET_CODE (x
) == SYMBOL_REF
);
241 if (CONSTANT_POOL_ADDRESS_P (x
))
243 if (GET_MODE_SIZE (get_pool_mode (x
)) <= SCORE_SDATA_MAX
)
244 return SYMBOL_SMALL_DATA
;
245 return SYMBOL_GENERAL
;
247 if (SYMBOL_REF_SMALL_P (x
))
248 return SYMBOL_SMALL_DATA
;
249 return SYMBOL_GENERAL
;
252 /* Return true if the current function must save REGNO. */
254 score_save_reg_p (unsigned int regno
)
256 /* Check call-saved registers. */
257 if (df_regs_ever_live_p (regno
) && !call_used_regs
[regno
])
260 /* We need to save the old frame pointer before setting up a new one. */
261 if (regno
== HARD_FRAME_POINTER_REGNUM
&& frame_pointer_needed
)
264 /* We need to save the incoming return address if it is ever clobbered
265 within the function. */
266 if (regno
== RA_REGNUM
&& df_regs_ever_live_p (regno
))
272 /* Return one word of double-word value OP, taking into account the fixed
273 endianness of certain registers. HIGH_P is true to select the high part,
274 false to select the low part. */
276 score_subw (rtx op
, int high_p
)
279 enum machine_mode mode
= GET_MODE (op
);
281 if (mode
== VOIDmode
)
284 byte
= (TARGET_LITTLE_ENDIAN
? high_p
: !high_p
) ? UNITS_PER_WORD
: 0;
286 if (GET_CODE (op
) == REG
&& REGNO (op
) == HI_REGNUM
)
287 return gen_rtx_REG (SImode
, high_p
? HI_REGNUM
: LO_REGNUM
);
289 if (GET_CODE (op
) == MEM
)
290 return adjust_address (op
, SImode
, byte
);
292 return simplify_gen_subreg (SImode
, op
, mode
, byte
);
295 static struct score_frame_info
*
296 score_cached_frame (void)
298 static struct score_frame_info _frame_info
;
302 /* Return the bytes needed to compute the frame pointer from the current
303 stack pointer. SIZE is the size (in bytes) of the local variables. */
304 static struct score_frame_info
*
305 score_compute_frame_size (HOST_WIDE_INT size
)
308 struct score_frame_info
*f
= score_cached_frame ();
310 memset (f
, 0, sizeof (struct score_frame_info
));
313 f
->var_size
= SCORE_STACK_ALIGN (size
);
314 f
->args_size
= crtl
->outgoing_args_size
;
315 f
->cprestore_size
= flag_pic
? UNITS_PER_WORD
: 0;
316 if (f
->var_size
== 0 && crtl
->is_leaf
)
317 f
->args_size
= f
->cprestore_size
= 0;
319 if (f
->args_size
== 0 && cfun
->calls_alloca
)
320 f
->args_size
= UNITS_PER_WORD
;
322 f
->total_size
= f
->var_size
+ f
->args_size
+ f
->cprestore_size
;
323 for (regno
= GP_REG_FIRST
; regno
<= GP_REG_LAST
; regno
++)
325 if (score_save_reg_p (regno
))
327 f
->gp_reg_size
+= GET_MODE_SIZE (SImode
);
328 f
->mask
|= 1 << (regno
- GP_REG_FIRST
);
332 if (crtl
->calls_eh_return
)
337 regno
= EH_RETURN_DATA_REGNO (i
);
338 if (regno
== INVALID_REGNUM
)
340 f
->gp_reg_size
+= GET_MODE_SIZE (SImode
);
341 f
->mask
|= 1 << (regno
- GP_REG_FIRST
);
345 f
->total_size
+= f
->gp_reg_size
;
346 f
->num_gp
= f
->gp_reg_size
/ UNITS_PER_WORD
;
350 HOST_WIDE_INT offset
;
351 offset
= (f
->args_size
+ f
->cprestore_size
+ f
->var_size
352 + f
->gp_reg_size
- GET_MODE_SIZE (SImode
));
353 f
->gp_sp_offset
= offset
;
361 /* Return true if X is a valid base register for the given mode.
362 Allow only hard registers if STRICT. */
364 score_valid_base_register_p (rtx x
, int strict
)
366 if (!strict
&& GET_CODE (x
) == SUBREG
)
369 return (GET_CODE (x
) == REG
370 && score_regno_mode_ok_for_base_p (REGNO (x
), strict
));
373 /* Return true if X is a valid address for machine mode MODE. If it is,
374 fill in INFO appropriately. STRICT is true if we should only accept
375 hard base registers. */
377 score_classify_address (struct score_address_info
*info
,
378 enum machine_mode mode
, rtx x
, int strict
)
380 info
->code
= GET_CODE (x
);
386 info
->type
= SCORE_ADD_REG
;
388 info
->offset
= const0_rtx
;
389 return score_valid_base_register_p (info
->reg
, strict
);
391 info
->type
= SCORE_ADD_REG
;
392 info
->reg
= XEXP (x
, 0);
393 info
->offset
= XEXP (x
, 1);
394 return (score_valid_base_register_p (info
->reg
, strict
)
395 && GET_CODE (info
->offset
) == CONST_INT
396 && IMM_IN_RANGE (INTVAL (info
->offset
), 15, 1));
401 if (GET_MODE_SIZE (mode
) > GET_MODE_SIZE (SImode
))
403 info
->type
= SCORE_ADD_REG
;
404 info
->reg
= XEXP (x
, 0);
405 info
->offset
= GEN_INT (GET_MODE_SIZE (mode
));
406 return score_valid_base_register_p (info
->reg
, strict
);
408 info
->type
= SCORE_ADD_CONST_INT
;
409 return IMM_IN_RANGE (INTVAL (x
), 15, 1);
413 info
->type
= SCORE_ADD_SYMBOLIC
;
414 return (score_symbolic_constant_p (x
, &info
->symbol_type
)
415 && (info
->symbol_type
== SYMBOL_GENERAL
416 || info
->symbol_type
== SYMBOL_SMALL_DATA
));
422 /* Implement TARGET_RETURN_IN_MEMORY. In S+core,
423 small structures are returned in a register.
424 Objects with varying size must still be returned in memory. */
426 score_return_in_memory (const_tree type
, const_tree fndecl ATTRIBUTE_UNUSED
)
428 return ((TYPE_MODE (type
) == BLKmode
)
429 || (int_size_in_bytes (type
) > 2 * UNITS_PER_WORD
)
430 || (int_size_in_bytes (type
) == -1));
433 /* Return a legitimate address for REG + OFFSET. */
435 score_add_offset (rtx reg
, HOST_WIDE_INT offset
)
437 if (!IMM_IN_RANGE (offset
, 15, 1))
439 reg
= expand_simple_binop (GET_MODE (reg
), PLUS
,
440 gen_int_mode (offset
& 0xffffc000,
442 reg
, NULL
, 0, OPTAB_WIDEN
);
446 return plus_constant (GET_MODE (reg
), reg
, offset
);
449 /* Implement TARGET_ASM_OUTPUT_MI_THUNK. Generate rtl rather than asm text
450 in order to avoid duplicating too much logic from elsewhere. */
452 score_output_mi_thunk (FILE *file
, tree thunk_fndecl ATTRIBUTE_UNUSED
,
453 HOST_WIDE_INT delta
, HOST_WIDE_INT vcall_offset
,
456 rtx this_rtx
, temp1
, fnaddr
;
459 /* Pretend to be a post-reload pass while generating rtl. */
460 reload_completed
= 1;
462 /* Mark the end of the (empty) prologue. */
463 emit_note (NOTE_INSN_PROLOGUE_END
);
465 /* We need two temporary registers in some cases. */
466 temp1
= gen_rtx_REG (Pmode
, 8);
468 /* Find out which register contains the "this" pointer. */
469 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function
)), function
))
470 this_rtx
= gen_rtx_REG (Pmode
, ARG_REG_FIRST
+ 1);
472 this_rtx
= gen_rtx_REG (Pmode
, ARG_REG_FIRST
);
474 /* Add DELTA to THIS_RTX. */
477 rtx offset
= GEN_INT (delta
);
478 if (!(delta
>= -32768 && delta
<= 32767))
480 emit_move_insn (temp1
, offset
);
483 emit_insn (gen_add3_insn (this_rtx
, this_rtx
, offset
));
486 /* If needed, add *(*THIS_RTX + VCALL_OFFSET) to THIS_RTX. */
487 if (vcall_offset
!= 0)
491 /* Set TEMP1 to *THIS_RTX. */
492 emit_move_insn (temp1
, gen_rtx_MEM (Pmode
, this_rtx
));
494 /* Set ADDR to a legitimate address for *THIS_RTX + VCALL_OFFSET. */
495 addr
= score_add_offset (temp1
, vcall_offset
);
497 /* Load the offset and add it to THIS_RTX. */
498 emit_move_insn (temp1
, gen_rtx_MEM (Pmode
, addr
));
499 emit_insn (gen_add3_insn (this_rtx
, this_rtx
, temp1
));
502 /* Jump to the target function. */
503 fnaddr
= XEXP (DECL_RTL (function
), 0);
504 insn
= emit_call_insn (gen_sibcall_internal_score7 (fnaddr
, const0_rtx
));
505 SIBLING_CALL_P (insn
) = 1;
507 /* Run just enough of rest_of_compilation. This sequence was
508 "borrowed" from alpha.c. */
510 split_all_insns_noflow ();
511 shorten_branches (insn
);
512 final_start_function (insn
, file
, 1);
513 final (insn
, file
, 1);
514 final_end_function ();
516 /* Clean up the vars set above. Note that final_end_function resets
517 the global pointer for us. */
518 reload_completed
= 0;
521 /* Fill INFO with information about a single argument. CUM is the
522 cumulative state for earlier arguments. MODE is the mode of this
523 argument and TYPE is its type (if known). NAMED is true if this
524 is a named (fixed) argument rather than a variable one. */
526 score_classify_arg (const CUMULATIVE_ARGS
*cum
, enum machine_mode mode
,
527 const_tree type
, bool named
, struct score_arg_info
*info
)
530 unsigned int num_words
, max_regs
;
533 if (GET_MODE_CLASS (mode
) == MODE_INT
534 || GET_MODE_CLASS (mode
) == MODE_FLOAT
)
535 even_reg_p
= (GET_MODE_SIZE (mode
) > UNITS_PER_WORD
);
537 if (type
!= NULL_TREE
&& TYPE_ALIGN (type
) > BITS_PER_WORD
&& named
)
540 if (TARGET_MUST_PASS_IN_STACK (mode
, type
))
541 info
->reg_offset
= ARG_REG_NUM
;
544 info
->reg_offset
= cum
->num_gprs
;
546 info
->reg_offset
+= info
->reg_offset
& 1;
550 info
->num_bytes
= int_size_in_bytes (type
);
552 info
->num_bytes
= GET_MODE_SIZE (mode
);
554 num_words
= (info
->num_bytes
+ UNITS_PER_WORD
- 1) / UNITS_PER_WORD
;
555 max_regs
= ARG_REG_NUM
- info
->reg_offset
;
557 /* Partition the argument between registers and stack. */
558 info
->reg_words
= MIN (num_words
, max_regs
);
559 info
->stack_words
= num_words
- info
->reg_words
;
561 /* The alignment applied to registers is also applied to stack arguments. */
562 if (info
->stack_words
)
564 info
->stack_offset
= cum
->stack_words
;
566 info
->stack_offset
+= info
->stack_offset
& 1;
570 /* Set up the stack and frame (if desired) for the function. */
572 score_function_prologue (FILE *file
, HOST_WIDE_INT size ATTRIBUTE_UNUSED
)
575 struct score_frame_info
*f
= score_cached_frame ();
576 HOST_WIDE_INT tsize
= f
->total_size
;
578 fnname
= XSTR (XEXP (DECL_RTL (current_function_decl
), 0), 0);
579 if (!flag_inhibit_size_directive
)
581 fputs ("\t.ent\t", file
);
582 assemble_name (file
, fnname
);
585 assemble_name (file
, fnname
);
588 if (!flag_inhibit_size_directive
)
591 "\t.frame\t%s," HOST_WIDE_INT_PRINT_DEC
",%s, %d\t\t"
592 "# vars= " HOST_WIDE_INT_PRINT_DEC
", regs= %d"
593 ", args= " HOST_WIDE_INT_PRINT_DEC
594 ", gp= " HOST_WIDE_INT_PRINT_DEC
"\n",
595 (reg_names
[(frame_pointer_needed
)
596 ? HARD_FRAME_POINTER_REGNUM
: STACK_POINTER_REGNUM
]),
598 reg_names
[RA_REGNUM
],
599 crtl
->is_leaf
? 1 : 0,
605 fprintf(file
, "\t.mask\t0x%08x," HOST_WIDE_INT_PRINT_DEC
"\n",
607 (f
->gp_sp_offset
- f
->total_size
));
611 /* Do any necessary cleanup after a function to restore stack, frame,
614 score_function_epilogue (FILE *file
, HOST_WIDE_INT size ATTRIBUTE_UNUSED
)
616 if (!flag_inhibit_size_directive
)
619 fnname
= XSTR (XEXP (DECL_RTL (current_function_decl
), 0), 0);
620 fputs ("\t.end\t", file
);
621 assemble_name (file
, fnname
);
626 /* Returns true if X contains a SYMBOL_REF. */
628 score_symbolic_expression_p (rtx x
)
630 if (GET_CODE (x
) == SYMBOL_REF
)
633 if (GET_CODE (x
) == CONST
)
634 return score_symbolic_expression_p (XEXP (x
, 0));
637 return score_symbolic_expression_p (XEXP (x
, 0));
639 if (ARITHMETIC_P (x
))
640 return (score_symbolic_expression_p (XEXP (x
, 0))
641 || score_symbolic_expression_p (XEXP (x
, 1)));
646 /* Choose the section to use for the constant rtx expression X that has
649 score_select_rtx_section (enum machine_mode mode
, rtx x
, unsigned HOST_WIDE_INT align
)
651 if (GET_MODE_SIZE (mode
) <= SCORE_SDATA_MAX
)
652 return get_named_section (0, ".sdata", 0);
653 else if (flag_pic
&& score_symbolic_expression_p (x
))
654 return get_named_section (0, ".data.rel.ro", 3);
656 return mergeable_constant_section (mode
, align
, 0);
659 /* Implement TARGET_IN_SMALL_DATA_P. */
661 score_in_small_data_p (const_tree decl
)
665 if (TREE_CODE (decl
) == STRING_CST
666 || TREE_CODE (decl
) == FUNCTION_DECL
)
669 if (TREE_CODE (decl
) == VAR_DECL
&& DECL_SECTION_NAME (decl
) != 0)
672 name
= DECL_SECTION_NAME (decl
);
673 if (strcmp (name
, ".sdata") != 0
674 && strcmp (name
, ".sbss") != 0)
676 if (!DECL_EXTERNAL (decl
))
679 size
= int_size_in_bytes (TREE_TYPE (decl
));
680 return (size
> 0 && size
<= SCORE_SDATA_MAX
);
683 /* Implement TARGET_ASM_FILE_START. */
685 score_asm_file_start (void)
687 default_file_start ();
688 fprintf (asm_out_file
, ASM_COMMENT_START
689 "GCC for S+core %s \n", SCORE_GCC_VERSION
);
692 fprintf (asm_out_file
, "\t.set pic\n");
695 /* Implement TARGET_ASM_FILE_END. When using assembler macros, emit
696 .externs for any small-data variables that turned out to be external. */
698 score_asm_file_end (void)
701 struct extern_list
*p
;
704 fputs ("\n", asm_out_file
);
705 for (p
= extern_head
; p
!= 0; p
= p
->next
)
707 name_tree
= get_identifier (p
->name
);
708 if (!TREE_ASM_WRITTEN (name_tree
)
709 && TREE_SYMBOL_REFERENCED (name_tree
))
711 TREE_ASM_WRITTEN (name_tree
) = 1;
712 fputs ("\t.extern\t", asm_out_file
);
713 assemble_name (asm_out_file
, p
->name
);
714 fprintf (asm_out_file
, ", %d\n", p
->size
);
720 /* Implement TARGET_OPTION_OVERRIDE hook. */
722 score_option_override (void)
725 score_sdata_max
= SCORE_DEFAULT_SDATA_MAX
;
729 /* Implement REGNO_REG_CLASS macro. */
731 score_reg_class (int regno
)
734 gcc_assert (regno
>= 0 && regno
< FIRST_PSEUDO_REGISTER
);
736 if (regno
== FRAME_POINTER_REGNUM
737 || regno
== ARG_POINTER_REGNUM
)
740 for (c
= 0; c
< N_REG_CLASSES
; c
++)
741 if (TEST_HARD_REG_BIT (reg_class_contents
[c
], regno
))
747 /* Implement PREFERRED_RELOAD_CLASS macro. */
749 score_preferred_reload_class (rtx x ATTRIBUTE_UNUSED
, enum reg_class rclass
)
751 if (reg_class_subset_p (G16_REGS
, rclass
))
753 if (reg_class_subset_p (G32_REGS
, rclass
))
758 /* Implement SECONDARY_INPUT_RELOAD_CLASS
759 and SECONDARY_OUTPUT_RELOAD_CLASS macro. */
761 score_secondary_reload_class (enum reg_class rclass
,
762 enum machine_mode mode ATTRIBUTE_UNUSED
,
766 if (GET_CODE (x
) == REG
|| GET_CODE(x
) == SUBREG
)
767 regno
= true_regnum (x
);
769 if (!GR_REG_CLASS_P (rclass
))
770 return GP_REG_P (regno
) ? NO_REGS
: G32_REGS
;
775 /* Return truth value on whether or not a given hard register
776 can support a given mode. */
778 score_hard_regno_mode_ok (unsigned int regno
, enum machine_mode mode
)
780 int size
= GET_MODE_SIZE (mode
);
781 enum mode_class mclass
= GET_MODE_CLASS (mode
);
783 if (mclass
== MODE_CC
)
784 return regno
== CC_REGNUM
;
785 else if (regno
== FRAME_POINTER_REGNUM
786 || regno
== ARG_POINTER_REGNUM
)
787 return mclass
== MODE_INT
;
788 else if (GP_REG_P (regno
))
789 /* ((regno <= (GP_REG_LAST- HARD_REGNO_NREGS (dummy, mode)) + 1) */
790 return !(regno
& 1) || (size
<= UNITS_PER_WORD
);
791 else if (CE_REG_P (regno
))
792 return (mclass
== MODE_INT
793 && ((size
<= UNITS_PER_WORD
)
794 || (regno
== CE_REG_FIRST
&& size
== 2 * UNITS_PER_WORD
)));
796 return (mclass
== MODE_INT
) && (size
<= UNITS_PER_WORD
);
799 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
800 pointer or argument pointer. TO is either the stack pointer or
801 hard frame pointer. */
803 score_initial_elimination_offset (int from
,
804 int to ATTRIBUTE_UNUSED
)
806 struct score_frame_info
*f
= score_compute_frame_size (get_frame_size ());
809 case ARG_POINTER_REGNUM
:
810 return f
->total_size
;
811 case FRAME_POINTER_REGNUM
:
818 /* Implement TARGET_FUNCTION_ARG_ADVANCE hook. */
820 score_function_arg_advance (cumulative_args_t cum_args
, enum machine_mode mode
,
821 const_tree type
, bool named
)
823 struct score_arg_info info
;
824 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_args
);
825 score_classify_arg (cum
, mode
, type
, named
, &info
);
826 cum
->num_gprs
= info
.reg_offset
+ info
.reg_words
;
827 if (info
.stack_words
> 0)
828 cum
->stack_words
= info
.stack_offset
+ info
.stack_words
;
832 /* Implement TARGET_ARG_PARTIAL_BYTES macro. */
834 score_arg_partial_bytes (cumulative_args_t cum_args
,
835 enum machine_mode mode
, tree type
, bool named
)
837 struct score_arg_info info
;
838 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_args
);
839 score_classify_arg (cum
, mode
, type
, named
, &info
);
840 return info
.stack_words
> 0 ? info
.reg_words
* UNITS_PER_WORD
: 0;
843 /* Implement TARGET_FUNCTION_ARG hook. */
845 score_function_arg (cumulative_args_t cum_args
, enum machine_mode mode
,
846 const_tree type
, bool named
)
848 struct score_arg_info info
;
849 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_args
);
851 if (mode
== VOIDmode
|| !named
)
854 score_classify_arg (cum
, mode
, type
, named
, &info
);
856 if (info
.reg_offset
== ARG_REG_NUM
)
859 if (!info
.stack_words
)
860 return gen_rtx_REG (mode
, ARG_REG_FIRST
+ info
.reg_offset
);
863 rtx ret
= gen_rtx_PARALLEL (mode
, rtvec_alloc (info
.reg_words
));
864 unsigned int i
, part_offset
= 0;
865 for (i
= 0; i
< info
.reg_words
; i
++)
868 reg
= gen_rtx_REG (SImode
, ARG_REG_FIRST
+ info
.reg_offset
+ i
);
869 XVECEXP (ret
, 0, i
) = gen_rtx_EXPR_LIST (SImode
, reg
,
870 GEN_INT (part_offset
));
871 part_offset
+= UNITS_PER_WORD
;
877 /* Implement FUNCTION_VALUE and LIBCALL_VALUE. For normal calls,
878 VALTYPE is the return type and MODE is VOIDmode. For libcalls,
879 VALTYPE is null and MODE is the mode of the return value. */
881 score_function_value (const_tree valtype
, const_tree func
, enum machine_mode mode
)
886 mode
= TYPE_MODE (valtype
);
887 unsignedp
= TYPE_UNSIGNED (valtype
);
888 mode
= promote_function_mode (valtype
, mode
, &unsignedp
, func
, 1);
890 return gen_rtx_REG (mode
, RT_REGNUM
);
893 /* Implement TARGET_ASM_TRAMPOLINE_TEMPLATE. */
896 score_asm_trampoline_template (FILE *f
)
898 fprintf (f
, "\t.set r1\n");
899 fprintf (f
, "\tmv r31, r3\n");
900 fprintf (f
, "\tbl nextinsn\n");
901 fprintf (f
, "nextinsn:\n");
902 fprintf (f
, "\tlw r1, [r3, 6*4-8]\n");
903 fprintf (f
, "\tlw r23, [r3, 6*4-4]\n");
904 fprintf (f
, "\tmv r3, r31\n");
905 fprintf (f
, "\tbr! r1\n");
906 fprintf (f
, "\tnop!\n");
907 fprintf (f
, "\t.set nor1\n");
910 /* Implement TARGET_TRAMPOLINE_INIT. */
912 score_trampoline_init (rtx m_tramp
, tree fndecl
, rtx chain_value
)
914 #define CODE_SIZE (TRAMPOLINE_INSNS * UNITS_PER_WORD)
916 rtx fnaddr
= XEXP (DECL_RTL (fndecl
), 0);
919 emit_block_move (m_tramp
, assemble_trampoline_template (),
920 GEN_INT (TRAMPOLINE_SIZE
), BLOCK_OP_NORMAL
);
922 mem
= adjust_address (m_tramp
, SImode
, CODE_SIZE
);
923 emit_move_insn (mem
, fnaddr
);
924 mem
= adjust_address (m_tramp
, SImode
, CODE_SIZE
+ GET_MODE_SIZE (SImode
));
925 emit_move_insn (mem
, chain_value
);
930 /* This function is used to implement REG_MODE_OK_FOR_BASE_P macro. */
932 score_regno_mode_ok_for_base_p (int regno
, int strict
)
934 if (regno
>= FIRST_PSEUDO_REGISTER
)
938 regno
= reg_renumber
[regno
];
940 if (regno
== ARG_POINTER_REGNUM
941 || regno
== FRAME_POINTER_REGNUM
)
943 return GP_REG_P (regno
);
946 /* Implement TARGET_LEGITIMATE_ADDRESS_P macro. */
948 score_legitimate_address_p (enum machine_mode mode
, rtx x
, bool strict
)
950 struct score_address_info addr
;
952 return score_classify_address (&addr
, mode
, x
, strict
);
955 /* Implement TARGET_REGISTER_MOVE_COST.
957 Return a number assessing the cost of moving a register in class
960 score_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED
,
961 reg_class_t from
, reg_class_t to
)
963 if (GR_REG_CLASS_P (from
))
965 if (GR_REG_CLASS_P (to
))
967 else if (SP_REG_CLASS_P (to
))
969 else if (CP_REG_CLASS_P (to
))
971 else if (CE_REG_CLASS_P (to
))
974 if (GR_REG_CLASS_P (to
))
976 if (GR_REG_CLASS_P (from
))
978 else if (SP_REG_CLASS_P (from
))
980 else if (CP_REG_CLASS_P (from
))
982 else if (CE_REG_CLASS_P (from
))
988 /* Return the number of instructions needed to load a symbol of the
989 given type into a register. */
991 score_symbol_insns (enum score_symbol_type type
)
998 case SYMBOL_SMALL_DATA
:
1005 /* Return the number of instructions needed to load or store a value
1006 of mode MODE at X. Return 0 if X isn't valid for MODE. */
1008 score_address_insns (rtx x
, enum machine_mode mode
)
1010 struct score_address_info addr
;
1013 if (mode
== BLKmode
)
1016 factor
= (GET_MODE_SIZE (mode
) + UNITS_PER_WORD
- 1) / UNITS_PER_WORD
;
1018 if (score_classify_address (&addr
, mode
, x
, false))
1022 case SCORE_ADD_CONST_INT
:
1025 case SCORE_ADD_SYMBOLIC
:
1026 return factor
* score_symbol_insns (addr
.symbol_type
);
1031 /* Implement TARGET_RTX_COSTS macro. */
1033 score_rtx_costs (rtx x
, int code
, int outer_code
, int opno ATTRIBUTE_UNUSED
,
1034 int *total
, bool speed ATTRIBUTE_UNUSED
)
1036 enum machine_mode mode
= GET_MODE (x
);
1041 if (outer_code
== SET
)
1043 if (((INTVAL (x
) & 0xffff) == 0)
1044 || (INTVAL (x
) >= -32768 && INTVAL (x
) <= 32767))
1045 *total
= COSTS_N_INSNS (1);
1047 *total
= COSTS_N_INSNS (2);
1049 else if (outer_code
== PLUS
|| outer_code
== MINUS
)
1051 if (INTVAL (x
) >= -8192 && INTVAL (x
) <= 8191)
1053 else if (((INTVAL (x
) & 0xffff) == 0)
1054 || (INTVAL (x
) >= -32768 && INTVAL (x
) <= 32767))
1057 *total
= COSTS_N_INSNS (2);
1059 else if (outer_code
== AND
|| outer_code
== IOR
)
1061 if (INTVAL (x
) >= 0 && INTVAL (x
) <= 16383)
1063 else if (((INTVAL (x
) & 0xffff) == 0)
1064 || (INTVAL (x
) >= 0 && INTVAL (x
) <= 65535))
1067 *total
= COSTS_N_INSNS (2);
1079 *total
= COSTS_N_INSNS (2);
1084 /* If the address is legitimate, return the number of
1085 instructions it needs, otherwise use the default handling. */
1086 int n
= score_address_insns (XEXP (x
, 0), GET_MODE (x
));
1089 *total
= COSTS_N_INSNS (n
+ 1);
1096 *total
= COSTS_N_INSNS (6);
1100 *total
= COSTS_N_INSNS (1);
1108 *total
= COSTS_N_INSNS (2);
1118 *total
= COSTS_N_INSNS ((GET_CODE (XEXP (x
, 1)) == CONST_INT
)
1125 *total
= COSTS_N_INSNS (4);
1132 *total
= COSTS_N_INSNS (4);
1135 *total
= COSTS_N_INSNS (1);
1141 *total
= COSTS_N_INSNS (4);
1147 *total
= optimize_size
? COSTS_N_INSNS (2) : COSTS_N_INSNS (12);
1154 *total
= optimize_size
? COSTS_N_INSNS (2) : COSTS_N_INSNS (33);
1159 switch (GET_MODE (XEXP (x
, 0)))
1163 if (GET_CODE (XEXP (x
, 0)) == MEM
)
1165 *total
= COSTS_N_INSNS (2);
1167 if (!TARGET_LITTLE_ENDIAN
&&
1168 side_effects_p (XEXP (XEXP (x
, 0), 0)))
1172 *total
= COSTS_N_INSNS (1);
1176 *total
= COSTS_N_INSNS (1);
1186 /* Implement TARGET_ADDRESS_COST macro. */
1188 score_address_cost (rtx addr
, enum machine_mode mode ATTRIBUTE_UNUSED
,
1189 addr_space_t as ATTRIBUTE_UNUSED
,
1190 bool speed ATTRIBUTE_UNUSED
)
1192 return score_address_insns (addr
, SImode
);
1195 /* Implement ASM_OUTPUT_EXTERNAL macro. */
1197 score_output_external (FILE *file ATTRIBUTE_UNUSED
,
1198 tree decl
, const char *name
)
1200 register struct extern_list
*p
;
1202 if (score_in_small_data_p (decl
))
1204 p
= ggc_alloc
<extern_list
> ();
1205 p
->next
= extern_head
;
1207 p
->size
= int_size_in_bytes (TREE_TYPE (decl
));
1213 /* Implement RETURN_ADDR_RTX. Note, we do not support moving
1214 back to a previous frame. */
1216 score_return_addr (int count
, rtx frame ATTRIBUTE_UNUSED
)
1220 return get_hard_reg_initial_val (Pmode
, RA_REGNUM
);
1223 /* Implement PRINT_OPERAND macro. */
1224 /* Score-specific operand codes:
1225 '[' print .set nor1 directive
1226 ']' print .set r1 directive
1227 'U' print hi part of a CONST_INT rtx
1230 'D' print SFmode const double
1231 'S' selectively print "!" if operand is 15bit instruction accessible
1232 'V' print "v!" if operand is 15bit instruction accessible, or "lfh!"
1233 'L' low part of DImode reg operand
1234 'H' high part of DImode reg operand
1235 'C' print part of opcode for a branch condition. */
1237 score_print_operand (FILE *file
, rtx op
, int c
)
1239 enum rtx_code code
= UNKNOWN
;
1240 if (!PRINT_OPERAND_PUNCT_VALID_P (c
))
1241 code
= GET_CODE (op
);
1245 fprintf (file
, ".set r1\n");
1249 fprintf (file
, "\n\t.set nor1");
1253 gcc_assert (code
== CONST_INT
);
1254 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
,
1255 (INTVAL (op
) >> 16) & 0xffff);
1259 if (GET_CODE (op
) == CONST_DOUBLE
)
1261 rtx temp
= gen_lowpart (SImode
, op
);
1262 gcc_assert (GET_MODE (op
) == SFmode
);
1263 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, INTVAL (temp
) & 0xffffffff);
1266 output_addr_const (file
, op
);
1270 gcc_assert (code
== REG
);
1271 if (G16_REG_P (REGNO (op
)))
1272 fprintf (file
, "!");
1276 gcc_assert (code
== REG
);
1277 fprintf (file
, G16_REG_P (REGNO (op
)) ? "v!" : "lfh!");
1281 enum machine_mode mode
= GET_MODE (XEXP (op
, 0));
1285 case EQ
: fputs ("eq", file
); break;
1286 case NE
: fputs ("ne", file
); break;
1287 case GT
: fputs ("gt", file
); break;
1288 case GE
: fputs (mode
!= CCmode
? "pl" : "ge", file
); break;
1289 case LT
: fputs (mode
!= CCmode
? "mi" : "lt", file
); break;
1290 case LE
: fputs ("le", file
); break;
1291 case GTU
: fputs ("gtu", file
); break;
1292 case GEU
: fputs ("cs", file
); break;
1293 case LTU
: fputs ("cc", file
); break;
1294 case LEU
: fputs ("leu", file
); break;
1296 output_operand_lossage ("invalid operand for code: '%c'", code
);
1301 unsigned HOST_WIDE_INT i
;
1302 unsigned HOST_WIDE_INT pow2mask
= 1;
1303 unsigned HOST_WIDE_INT val
;
1306 for (i
= 0; i
< 32; i
++)
1308 if (val
== pow2mask
)
1312 gcc_assert (i
< 32);
1313 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, i
);
1317 unsigned HOST_WIDE_INT i
;
1318 unsigned HOST_WIDE_INT pow2mask
= 1;
1319 unsigned HOST_WIDE_INT val
;
1322 for (i
= 0; i
< 32; i
++)
1324 if (val
== pow2mask
)
1328 gcc_assert (i
< 32);
1329 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, i
);
1331 else if (code
== REG
)
1333 int regnum
= REGNO (op
);
1334 if ((c
== 'H' && !WORDS_BIG_ENDIAN
)
1335 || (c
== 'L' && WORDS_BIG_ENDIAN
))
1337 fprintf (file
, "%s", reg_names
[regnum
]);
1344 score_print_operand_address (file
, op
);
1347 output_addr_const (file
, op
);
1352 /* Implement PRINT_OPERAND_ADDRESS macro. */
1354 score_print_operand_address (FILE *file
, rtx x
)
1356 struct score_address_info addr
;
1357 enum rtx_code code
= GET_CODE (x
);
1358 enum machine_mode mode
= GET_MODE (x
);
1363 if (score_classify_address (&addr
, mode
, x
, true))
1372 fprintf (file
, "[%s,-%ld]+", reg_names
[REGNO (addr
.reg
)],
1373 INTVAL (addr
.offset
));
1376 fprintf (file
, "[%s]+,-%ld", reg_names
[REGNO (addr
.reg
)],
1377 INTVAL (addr
.offset
));
1380 fprintf (file
, "[%s, %ld]+", reg_names
[REGNO (addr
.reg
)],
1381 INTVAL (addr
.offset
));
1384 fprintf (file
, "[%s]+, %ld", reg_names
[REGNO (addr
.reg
)],
1385 INTVAL (addr
.offset
));
1388 if (INTVAL(addr
.offset
) == 0)
1389 fprintf(file
, "[%s]", reg_names
[REGNO (addr
.reg
)]);
1391 fprintf(file
, "[%s, %ld]", reg_names
[REGNO (addr
.reg
)],
1392 INTVAL(addr
.offset
));
1397 case SCORE_ADD_CONST_INT
:
1398 case SCORE_ADD_SYMBOLIC
:
1399 output_addr_const (file
, x
);
1403 print_rtl (stderr
, x
);
1407 /* Implement SELECT_CC_MODE macro. */
1409 score_select_cc_mode (enum rtx_code op
, rtx x
, rtx y
)
1411 if ((op
== EQ
|| op
== NE
|| op
== LT
|| op
== GE
)
1413 && GET_MODE (x
) == SImode
)
1415 switch (GET_CODE (x
))
1433 return (op
== LT
|| op
== GE
) ? CC_Nmode
: CCmode
;
1440 if ((op
== EQ
|| op
== NE
)
1441 && (GET_CODE (y
) == NEG
)
1442 && register_operand (XEXP (y
, 0), SImode
)
1443 && register_operand (x
, SImode
))
1451 /* Generate the prologue instructions for entry into a S+core function. */
1453 score_prologue (void)
1455 #define EMIT_PL(_rtx) RTX_FRAME_RELATED_P (_rtx) = 1
1457 struct score_frame_info
*f
= score_compute_frame_size (get_frame_size ());
1461 size
= f
->total_size
- f
->gp_reg_size
;
1464 emit_insn (gen_cpload_score7 ());
1466 for (regno
= (int) GP_REG_LAST
; regno
>= (int) GP_REG_FIRST
; regno
--)
1468 if (BITSET_P (f
->mask
, regno
- GP_REG_FIRST
))
1470 rtx mem
= gen_rtx_MEM (SImode
,
1471 gen_rtx_PRE_DEC (SImode
, stack_pointer_rtx
));
1472 rtx reg
= gen_rtx_REG (SImode
, regno
);
1473 if (!crtl
->calls_eh_return
)
1474 MEM_READONLY_P (mem
) = 1;
1475 EMIT_PL (emit_insn (gen_pushsi_score7 (mem
, reg
)));
1483 if (size
>= -32768 && size
<= 32767)
1484 EMIT_PL (emit_insn (gen_add3_insn (stack_pointer_rtx
,
1489 EMIT_PL (emit_move_insn (gen_rtx_REG (Pmode
, SCORE_PROLOGUE_TEMP_REGNUM
),
1492 (gen_sub3_insn (stack_pointer_rtx
,
1495 SCORE_PROLOGUE_TEMP_REGNUM
))));
1497 insn
= get_last_insn ();
1499 alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR
,
1500 gen_rtx_SET (VOIDmode
, stack_pointer_rtx
,
1501 plus_constant (Pmode
, stack_pointer_rtx
,
1506 if (frame_pointer_needed
)
1507 EMIT_PL (emit_move_insn (hard_frame_pointer_rtx
, stack_pointer_rtx
));
1509 if (flag_pic
&& f
->cprestore_size
)
1511 if (frame_pointer_needed
)
1512 emit_insn (gen_cprestore_use_fp_score7 (GEN_INT (size
- f
->cprestore_size
)));
1514 emit_insn (gen_cprestore_use_sp_score7 (GEN_INT (size
- f
->cprestore_size
)));
1520 /* Generate the epilogue instructions in a S+core function. */
1522 score_epilogue (int sibcall_p
)
1524 struct score_frame_info
*f
= score_compute_frame_size (get_frame_size ());
1529 size
= f
->total_size
- f
->gp_reg_size
;
1531 if (!frame_pointer_needed
)
1532 base
= stack_pointer_rtx
;
1534 base
= hard_frame_pointer_rtx
;
1538 if (size
>= -32768 && size
<= 32767)
1539 emit_insn (gen_add3_insn (base
, base
, GEN_INT (size
)));
1542 emit_move_insn (gen_rtx_REG (Pmode
, SCORE_EPILOGUE_TEMP_REGNUM
),
1544 emit_insn (gen_add3_insn (base
, base
,
1546 SCORE_EPILOGUE_TEMP_REGNUM
)));
1550 if (base
!= stack_pointer_rtx
)
1551 emit_move_insn (stack_pointer_rtx
, base
);
1553 if (crtl
->calls_eh_return
)
1554 emit_insn (gen_add3_insn (stack_pointer_rtx
,
1556 EH_RETURN_STACKADJ_RTX
));
1558 for (regno
= (int) GP_REG_FIRST
; regno
<= (int) GP_REG_LAST
; regno
++)
1560 if (BITSET_P (f
->mask
, regno
- GP_REG_FIRST
))
1562 rtx mem
= gen_rtx_MEM (SImode
,
1563 gen_rtx_POST_INC (SImode
, stack_pointer_rtx
));
1564 rtx reg
= gen_rtx_REG (SImode
, regno
);
1566 if (!crtl
->calls_eh_return
)
1567 MEM_READONLY_P (mem
) = 1;
1569 emit_insn (gen_popsi_score7 (reg
, mem
));
1574 emit_jump_insn (gen_return_internal_score7 (gen_rtx_REG (Pmode
, RA_REGNUM
)));
1577 /* Return true if X is a symbolic constant that can be calculated in
1578 the same way as a bare symbol. If it is, store the type of the
1579 symbol in *SYMBOL_TYPE. */
1581 score_symbolic_constant_p (rtx x
, enum score_symbol_type
*symbol_type
)
1583 HOST_WIDE_INT offset
;
1585 score_split_const (x
, &x
, &offset
);
1586 if (GET_CODE (x
) == SYMBOL_REF
|| GET_CODE (x
) == LABEL_REF
)
1587 *symbol_type
= score_classify_symbol (x
);
1594 /* if offset > 15bit, must reload */
1595 if (!IMM_IN_RANGE (offset
, 15, 1))
1598 switch (*symbol_type
)
1600 case SYMBOL_GENERAL
:
1602 case SYMBOL_SMALL_DATA
:
1603 return score_offset_within_object_p (x
, offset
);
1609 score_movsicc (rtx
*ops
)
1611 enum machine_mode mode
;
1613 mode
= score_select_cc_mode (GET_CODE (ops
[1]), ops
[2], ops
[3]);
1614 emit_insn (gen_rtx_SET (VOIDmode
, gen_rtx_REG (mode
, CC_REGNUM
),
1615 gen_rtx_COMPARE (mode
, XEXP (ops
[1], 0),
1616 XEXP (ops
[1], 1))));
1619 /* Call and sibcall pattern all need call this function. */
1621 score_call (rtx
*ops
, bool sib
)
1623 rtx addr
= XEXP (ops
[0], 0);
1624 if (!call_insn_operand (addr
, VOIDmode
))
1627 addr
= gen_reg_rtx (Pmode
);
1628 gen_move_insn (addr
, oaddr
);
1632 emit_call_insn (gen_sibcall_internal_score7 (addr
, ops
[1]));
1634 emit_call_insn (gen_call_internal_score7 (addr
, ops
[1]));
1637 /* Call value and sibcall value pattern all need call this function. */
1639 score_call_value (rtx
*ops
, bool sib
)
1641 rtx result
= ops
[0];
1642 rtx addr
= XEXP (ops
[1], 0);
1645 if (!call_insn_operand (addr
, VOIDmode
))
1648 addr
= gen_reg_rtx (Pmode
);
1649 gen_move_insn (addr
, oaddr
);
1653 emit_call_insn (gen_sibcall_value_internal_score7 (result
, addr
, arg
));
1655 emit_call_insn (gen_call_value_internal_score7 (result
, addr
, arg
));
1660 score_movdi (rtx
*ops
)
1664 rtx dst0
= score_subw (dst
, 0);
1665 rtx dst1
= score_subw (dst
, 1);
1666 rtx src0
= score_subw (src
, 0);
1667 rtx src1
= score_subw (src
, 1);
1669 if (GET_CODE (dst0
) == REG
&& reg_overlap_mentioned_p (dst0
, src
))
1671 emit_move_insn (dst1
, src1
);
1672 emit_move_insn (dst0
, src0
);
1676 emit_move_insn (dst0
, src0
);
1677 emit_move_insn (dst1
, src1
);
1682 score_zero_extract_andi (rtx
*ops
)
1684 if (INTVAL (ops
[1]) == 1 && const_uimm5 (ops
[2], SImode
))
1685 emit_insn (gen_zero_extract_bittst_score7 (ops
[0], ops
[2]));
1688 unsigned HOST_WIDE_INT mask
;
1689 mask
= (0xffffffffU
& ((1U << INTVAL (ops
[1])) - 1U));
1690 mask
= mask
<< INTVAL (ops
[2]);
1691 emit_insn (gen_andsi3_cmp_score7 (ops
[3], ops
[0],
1692 gen_int_mode (mask
, SImode
)));
1696 /* Check addr could be present as PRE/POST mode. */
1698 score_pindex_mem (rtx addr
)
1700 if (GET_CODE (addr
) == MEM
)
1702 switch (GET_CODE (XEXP (addr
, 0)))
1716 /* Output asm code for ld/sw insn. */
1718 score_pr_addr_post (rtx
*ops
, int idata
, int iaddr
, char *ip
, enum score_mem_unit unit
)
1720 struct score_address_info ai
;
1722 gcc_assert (GET_CODE (ops
[idata
]) == REG
);
1723 gcc_assert (score_classify_address (&ai
, SImode
, XEXP (ops
[iaddr
], 0), true));
1725 if (!score_pindex_mem (ops
[iaddr
])
1726 && ai
.type
== SCORE_ADD_REG
1727 && GET_CODE (ai
.offset
) == CONST_INT
1728 && G16_REG_P (REGNO (ops
[idata
]))
1729 && G16_REG_P (REGNO (ai
.reg
)))
1731 if (INTVAL (ai
.offset
) == 0)
1733 ops
[iaddr
] = ai
.reg
;
1734 return snprintf (ip
, INS_BUF_SZ
,
1735 "!\t%%%d, [%%%d]", idata
, iaddr
);
1737 if (REGNO (ai
.reg
) == HARD_FRAME_POINTER_REGNUM
)
1739 HOST_WIDE_INT offset
= INTVAL (ai
.offset
);
1740 if (SCORE_ALIGN_UNIT (offset
, unit
)
1741 && (((offset
>> unit
) >= 0) && ((offset
>> unit
) <= 31)))
1743 ops
[iaddr
] = ai
.offset
;
1744 return snprintf (ip
, INS_BUF_SZ
,
1745 "p!\t%%%d, %%c%d", idata
, iaddr
);
1749 return snprintf (ip
, INS_BUF_SZ
, "\t%%%d, %%a%d", idata
, iaddr
);
1752 /* Output asm insn for load. */
1754 score_linsn (rtx
*ops
, enum score_mem_unit unit
, bool sign
)
1756 const char *pre_ins
[] =
1757 {"lbu", "lhu", "lw", "??", "lb", "lh", "lw", "??"};
1760 strcpy (score_ins
, pre_ins
[(sign
? 4 : 0) + unit
]);
1761 ip
= score_ins
+ strlen (score_ins
);
1763 if ((!sign
&& unit
!= SCORE_HWORD
)
1764 || (sign
&& unit
!= SCORE_BYTE
))
1765 score_pr_addr_post (ops
, 0, 1, ip
, unit
);
1767 snprintf (ip
, INS_BUF_SZ
, "\t%%0, %%a1");
1772 /* Output asm insn for store. */
1774 score_sinsn (rtx
*ops
, enum score_mem_unit unit
)
1776 const char *pre_ins
[] = {"sb", "sh", "sw"};
1779 strcpy (score_ins
, pre_ins
[unit
]);
1780 ip
= score_ins
+ strlen (score_ins
);
1781 score_pr_addr_post (ops
, 1, 0, ip
, unit
);
1785 /* Output asm insn for load immediate. */
1787 score_limm (rtx
*ops
)
1791 gcc_assert (GET_CODE (ops
[0]) == REG
);
1792 gcc_assert (GET_CODE (ops
[1]) == CONST_INT
);
1794 v
= INTVAL (ops
[1]);
1795 if (G16_REG_P (REGNO (ops
[0])) && IMM_IN_RANGE (v
, 8, 0))
1796 return "ldiu!\t%0, %c1";
1797 else if (IMM_IN_RANGE (v
, 16, 1))
1798 return "ldi\t%0, %c1";
1799 else if ((v
& 0xffff) == 0)
1800 return "ldis\t%0, %U1";
1802 return "li\t%0, %c1";
1805 /* Output asm insn for move. */
1807 score_move (rtx
*ops
)
1809 gcc_assert (GET_CODE (ops
[0]) == REG
);
1810 gcc_assert (GET_CODE (ops
[1]) == REG
);
1812 if (G16_REG_P (REGNO (ops
[0])))
1814 if (G16_REG_P (REGNO (ops
[1])))
1815 return "mv!\t%0, %1";
1817 return "mlfh!\t%0, %1";
1819 else if (G16_REG_P (REGNO (ops
[1])))
1820 return "mhfl!\t%0, %1";
1822 return "mv\t%0, %1";
1825 /* Generate add insn. */
1827 score_select_add_imm (rtx
*ops
, bool set_cc
)
1829 HOST_WIDE_INT v
= INTVAL (ops
[2]);
1831 gcc_assert (GET_CODE (ops
[2]) == CONST_INT
);
1832 gcc_assert (REGNO (ops
[0]) == REGNO (ops
[1]));
1834 if (set_cc
&& G16_REG_P (REGNO (ops
[0])))
1836 if (v
> 0 && IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT
) v
, 0, 15))
1838 ops
[2] = GEN_INT (ffs (v
) - 1);
1839 return "addei!\t%0, %c2";
1842 if (v
< 0 && IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT
) (-v
), 0, 15))
1844 ops
[2] = GEN_INT (ffs (-v
) - 1);
1845 return "subei!\t%0, %c2";
1850 return "addi.c\t%0, %c2";
1852 return "addi\t%0, %c2";
1855 /* Output arith insn. */
1857 score_select (rtx
*ops
, const char *inst_pre
,
1858 bool commu
, const char *letter
, bool set_cc
)
1860 gcc_assert (GET_CODE (ops
[0]) == REG
);
1861 gcc_assert (GET_CODE (ops
[1]) == REG
);
1863 if (set_cc
&& G16_REG_P (REGNO (ops
[0]))
1864 && (GET_CODE (ops
[2]) == REG
? G16_REG_P (REGNO (ops
[2])) : 1)
1865 && REGNO (ops
[0]) == REGNO (ops
[1]))
1867 snprintf (score_ins
, INS_BUF_SZ
, "%s!\t%%0, %%%s2", inst_pre
, letter
);
1871 if (commu
&& set_cc
&& G16_REG_P (REGNO (ops
[0]))
1872 && G16_REG_P (REGNO (ops
[1]))
1873 && REGNO (ops
[0]) == REGNO (ops
[2]))
1875 gcc_assert (GET_CODE (ops
[2]) == REG
);
1876 snprintf (score_ins
, INS_BUF_SZ
, "%s!\t%%0, %%%s1", inst_pre
, letter
);
1881 snprintf (score_ins
, INS_BUF_SZ
, "%s.c\t%%0, %%1, %%%s2", inst_pre
, letter
);
1883 snprintf (score_ins
, INS_BUF_SZ
, "%s\t%%0, %%1, %%%s2", inst_pre
, letter
);
1887 /* Return nonzero when an argument must be passed by reference. */
1889 score_pass_by_reference (cumulative_args_t cum ATTRIBUTE_UNUSED
,
1890 enum machine_mode mode
, const_tree type
,
1891 bool named ATTRIBUTE_UNUSED
)
1893 /* If we have a variable-sized parameter, we have no choice. */
1894 return targetm
.calls
.must_pass_in_stack (mode
, type
);
1897 /* Implement TARGET_FUNCTION_OK_FOR_SIBCALL. */
1899 score_function_ok_for_sibcall (ATTRIBUTE_UNUSED tree decl
,
1900 ATTRIBUTE_UNUSED tree exp
)
1905 /* Implement TARGET_SCHED_ISSUE_RATE. */
1907 score_issue_rate (void)
1912 /* We can always eliminate to the hard frame pointer. We can eliminate
1913 to the stack pointer unless a frame pointer is needed. */
1916 score_can_eliminate (const int from ATTRIBUTE_UNUSED
, const int to
)
1918 return (to
== HARD_FRAME_POINTER_REGNUM
1919 || (to
== STACK_POINTER_REGNUM
&& !frame_pointer_needed
));
1922 /* Argument support functions. */
1924 /* Initialize CUMULATIVE_ARGS for a function. */
1926 score_init_cumulative_args (CUMULATIVE_ARGS
*cum
,
1927 tree fntype ATTRIBUTE_UNUSED
,
1928 rtx libname ATTRIBUTE_UNUSED
)
1930 memset (cum
, 0, sizeof (CUMULATIVE_ARGS
));
1934 score_conditional_register_usage (void)
1937 fixed_regs
[PIC_OFFSET_TABLE_REGNUM
] =
1938 call_used_regs
[PIC_OFFSET_TABLE_REGNUM
] = 0;
1941 struct gcc_target targetm
= TARGET_INITIALIZER
;