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
, insn
, fnaddr
;
458 /* Pretend to be a post-reload pass while generating rtl. */
459 reload_completed
= 1;
461 /* Mark the end of the (empty) prologue. */
462 emit_note (NOTE_INSN_PROLOGUE_END
);
464 /* We need two temporary registers in some cases. */
465 temp1
= gen_rtx_REG (Pmode
, 8);
467 /* Find out which register contains the "this" pointer. */
468 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function
)), function
))
469 this_rtx
= gen_rtx_REG (Pmode
, ARG_REG_FIRST
+ 1);
471 this_rtx
= gen_rtx_REG (Pmode
, ARG_REG_FIRST
);
473 /* Add DELTA to THIS_RTX. */
476 rtx offset
= GEN_INT (delta
);
477 if (!(delta
>= -32768 && delta
<= 32767))
479 emit_move_insn (temp1
, offset
);
482 emit_insn (gen_add3_insn (this_rtx
, this_rtx
, offset
));
485 /* If needed, add *(*THIS_RTX + VCALL_OFFSET) to THIS_RTX. */
486 if (vcall_offset
!= 0)
490 /* Set TEMP1 to *THIS_RTX. */
491 emit_move_insn (temp1
, gen_rtx_MEM (Pmode
, this_rtx
));
493 /* Set ADDR to a legitimate address for *THIS_RTX + VCALL_OFFSET. */
494 addr
= score_add_offset (temp1
, vcall_offset
);
496 /* Load the offset and add it to THIS_RTX. */
497 emit_move_insn (temp1
, gen_rtx_MEM (Pmode
, addr
));
498 emit_insn (gen_add3_insn (this_rtx
, this_rtx
, temp1
));
501 /* Jump to the target function. */
502 fnaddr
= XEXP (DECL_RTL (function
), 0);
503 insn
= emit_call_insn (gen_sibcall_internal_score7 (fnaddr
, const0_rtx
));
504 SIBLING_CALL_P (insn
) = 1;
506 /* Run just enough of rest_of_compilation. This sequence was
507 "borrowed" from alpha.c. */
509 split_all_insns_noflow ();
510 shorten_branches (insn
);
511 final_start_function (insn
, file
, 1);
512 final (insn
, file
, 1);
513 final_end_function ();
515 /* Clean up the vars set above. Note that final_end_function resets
516 the global pointer for us. */
517 reload_completed
= 0;
520 /* Fill INFO with information about a single argument. CUM is the
521 cumulative state for earlier arguments. MODE is the mode of this
522 argument and TYPE is its type (if known). NAMED is true if this
523 is a named (fixed) argument rather than a variable one. */
525 score_classify_arg (const CUMULATIVE_ARGS
*cum
, enum machine_mode mode
,
526 const_tree type
, bool named
, struct score_arg_info
*info
)
529 unsigned int num_words
, max_regs
;
532 if (GET_MODE_CLASS (mode
) == MODE_INT
533 || GET_MODE_CLASS (mode
) == MODE_FLOAT
)
534 even_reg_p
= (GET_MODE_SIZE (mode
) > UNITS_PER_WORD
);
536 if (type
!= NULL_TREE
&& TYPE_ALIGN (type
) > BITS_PER_WORD
&& named
)
539 if (TARGET_MUST_PASS_IN_STACK (mode
, type
))
540 info
->reg_offset
= ARG_REG_NUM
;
543 info
->reg_offset
= cum
->num_gprs
;
545 info
->reg_offset
+= info
->reg_offset
& 1;
549 info
->num_bytes
= int_size_in_bytes (type
);
551 info
->num_bytes
= GET_MODE_SIZE (mode
);
553 num_words
= (info
->num_bytes
+ UNITS_PER_WORD
- 1) / UNITS_PER_WORD
;
554 max_regs
= ARG_REG_NUM
- info
->reg_offset
;
556 /* Partition the argument between registers and stack. */
557 info
->reg_words
= MIN (num_words
, max_regs
);
558 info
->stack_words
= num_words
- info
->reg_words
;
560 /* The alignment applied to registers is also applied to stack arguments. */
561 if (info
->stack_words
)
563 info
->stack_offset
= cum
->stack_words
;
565 info
->stack_offset
+= info
->stack_offset
& 1;
569 /* Set up the stack and frame (if desired) for the function. */
571 score_function_prologue (FILE *file
, HOST_WIDE_INT size ATTRIBUTE_UNUSED
)
574 struct score_frame_info
*f
= score_cached_frame ();
575 HOST_WIDE_INT tsize
= f
->total_size
;
577 fnname
= XSTR (XEXP (DECL_RTL (current_function_decl
), 0), 0);
578 if (!flag_inhibit_size_directive
)
580 fputs ("\t.ent\t", file
);
581 assemble_name (file
, fnname
);
584 assemble_name (file
, fnname
);
587 if (!flag_inhibit_size_directive
)
590 "\t.frame\t%s," HOST_WIDE_INT_PRINT_DEC
",%s, %d\t\t"
591 "# vars= " HOST_WIDE_INT_PRINT_DEC
", regs= %d"
592 ", args= " HOST_WIDE_INT_PRINT_DEC
593 ", gp= " HOST_WIDE_INT_PRINT_DEC
"\n",
594 (reg_names
[(frame_pointer_needed
)
595 ? HARD_FRAME_POINTER_REGNUM
: STACK_POINTER_REGNUM
]),
597 reg_names
[RA_REGNUM
],
598 crtl
->is_leaf
? 1 : 0,
604 fprintf(file
, "\t.mask\t0x%08x," HOST_WIDE_INT_PRINT_DEC
"\n",
606 (f
->gp_sp_offset
- f
->total_size
));
610 /* Do any necessary cleanup after a function to restore stack, frame,
613 score_function_epilogue (FILE *file
, HOST_WIDE_INT size ATTRIBUTE_UNUSED
)
615 if (!flag_inhibit_size_directive
)
618 fnname
= XSTR (XEXP (DECL_RTL (current_function_decl
), 0), 0);
619 fputs ("\t.end\t", file
);
620 assemble_name (file
, fnname
);
625 /* Returns true if X contains a SYMBOL_REF. */
627 score_symbolic_expression_p (rtx x
)
629 if (GET_CODE (x
) == SYMBOL_REF
)
632 if (GET_CODE (x
) == CONST
)
633 return score_symbolic_expression_p (XEXP (x
, 0));
636 return score_symbolic_expression_p (XEXP (x
, 0));
638 if (ARITHMETIC_P (x
))
639 return (score_symbolic_expression_p (XEXP (x
, 0))
640 || score_symbolic_expression_p (XEXP (x
, 1)));
645 /* Choose the section to use for the constant rtx expression X that has
648 score_select_rtx_section (enum machine_mode mode
, rtx x
, unsigned HOST_WIDE_INT align
)
650 if (GET_MODE_SIZE (mode
) <= SCORE_SDATA_MAX
)
651 return get_named_section (0, ".sdata", 0);
652 else if (flag_pic
&& score_symbolic_expression_p (x
))
653 return get_named_section (0, ".data.rel.ro", 3);
655 return mergeable_constant_section (mode
, align
, 0);
658 /* Implement TARGET_IN_SMALL_DATA_P. */
660 score_in_small_data_p (const_tree decl
)
664 if (TREE_CODE (decl
) == STRING_CST
665 || TREE_CODE (decl
) == FUNCTION_DECL
)
668 if (TREE_CODE (decl
) == VAR_DECL
&& DECL_SECTION_NAME (decl
) != 0)
671 name
= DECL_SECTION_NAME (decl
);
672 if (strcmp (name
, ".sdata") != 0
673 && strcmp (name
, ".sbss") != 0)
675 if (!DECL_EXTERNAL (decl
))
678 size
= int_size_in_bytes (TREE_TYPE (decl
));
679 return (size
> 0 && size
<= SCORE_SDATA_MAX
);
682 /* Implement TARGET_ASM_FILE_START. */
684 score_asm_file_start (void)
686 default_file_start ();
687 fprintf (asm_out_file
, ASM_COMMENT_START
688 "GCC for S+core %s \n", SCORE_GCC_VERSION
);
691 fprintf (asm_out_file
, "\t.set pic\n");
694 /* Implement TARGET_ASM_FILE_END. When using assembler macros, emit
695 .externs for any small-data variables that turned out to be external. */
697 score_asm_file_end (void)
700 struct extern_list
*p
;
703 fputs ("\n", asm_out_file
);
704 for (p
= extern_head
; p
!= 0; p
= p
->next
)
706 name_tree
= get_identifier (p
->name
);
707 if (!TREE_ASM_WRITTEN (name_tree
)
708 && TREE_SYMBOL_REFERENCED (name_tree
))
710 TREE_ASM_WRITTEN (name_tree
) = 1;
711 fputs ("\t.extern\t", asm_out_file
);
712 assemble_name (asm_out_file
, p
->name
);
713 fprintf (asm_out_file
, ", %d\n", p
->size
);
719 /* Implement TARGET_OPTION_OVERRIDE hook. */
721 score_option_override (void)
724 score_sdata_max
= SCORE_DEFAULT_SDATA_MAX
;
728 /* Implement REGNO_REG_CLASS macro. */
730 score_reg_class (int regno
)
733 gcc_assert (regno
>= 0 && regno
< FIRST_PSEUDO_REGISTER
);
735 if (regno
== FRAME_POINTER_REGNUM
736 || regno
== ARG_POINTER_REGNUM
)
739 for (c
= 0; c
< N_REG_CLASSES
; c
++)
740 if (TEST_HARD_REG_BIT (reg_class_contents
[c
], regno
))
746 /* Implement PREFERRED_RELOAD_CLASS macro. */
748 score_preferred_reload_class (rtx x ATTRIBUTE_UNUSED
, enum reg_class rclass
)
750 if (reg_class_subset_p (G16_REGS
, rclass
))
752 if (reg_class_subset_p (G32_REGS
, rclass
))
757 /* Implement SECONDARY_INPUT_RELOAD_CLASS
758 and SECONDARY_OUTPUT_RELOAD_CLASS macro. */
760 score_secondary_reload_class (enum reg_class rclass
,
761 enum machine_mode mode ATTRIBUTE_UNUSED
,
765 if (GET_CODE (x
) == REG
|| GET_CODE(x
) == SUBREG
)
766 regno
= true_regnum (x
);
768 if (!GR_REG_CLASS_P (rclass
))
769 return GP_REG_P (regno
) ? NO_REGS
: G32_REGS
;
774 /* Return truth value on whether or not a given hard register
775 can support a given mode. */
777 score_hard_regno_mode_ok (unsigned int regno
, enum machine_mode mode
)
779 int size
= GET_MODE_SIZE (mode
);
780 enum mode_class mclass
= GET_MODE_CLASS (mode
);
782 if (mclass
== MODE_CC
)
783 return regno
== CC_REGNUM
;
784 else if (regno
== FRAME_POINTER_REGNUM
785 || regno
== ARG_POINTER_REGNUM
)
786 return mclass
== MODE_INT
;
787 else if (GP_REG_P (regno
))
788 /* ((regno <= (GP_REG_LAST- HARD_REGNO_NREGS (dummy, mode)) + 1) */
789 return !(regno
& 1) || (size
<= UNITS_PER_WORD
);
790 else if (CE_REG_P (regno
))
791 return (mclass
== MODE_INT
792 && ((size
<= UNITS_PER_WORD
)
793 || (regno
== CE_REG_FIRST
&& size
== 2 * UNITS_PER_WORD
)));
795 return (mclass
== MODE_INT
) && (size
<= UNITS_PER_WORD
);
798 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
799 pointer or argument pointer. TO is either the stack pointer or
800 hard frame pointer. */
802 score_initial_elimination_offset (int from
,
803 int to ATTRIBUTE_UNUSED
)
805 struct score_frame_info
*f
= score_compute_frame_size (get_frame_size ());
808 case ARG_POINTER_REGNUM
:
809 return f
->total_size
;
810 case FRAME_POINTER_REGNUM
:
817 /* Implement TARGET_FUNCTION_ARG_ADVANCE hook. */
819 score_function_arg_advance (cumulative_args_t cum_args
, enum machine_mode mode
,
820 const_tree type
, bool named
)
822 struct score_arg_info info
;
823 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_args
);
824 score_classify_arg (cum
, mode
, type
, named
, &info
);
825 cum
->num_gprs
= info
.reg_offset
+ info
.reg_words
;
826 if (info
.stack_words
> 0)
827 cum
->stack_words
= info
.stack_offset
+ info
.stack_words
;
831 /* Implement TARGET_ARG_PARTIAL_BYTES macro. */
833 score_arg_partial_bytes (cumulative_args_t cum_args
,
834 enum machine_mode mode
, tree type
, bool named
)
836 struct score_arg_info info
;
837 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_args
);
838 score_classify_arg (cum
, mode
, type
, named
, &info
);
839 return info
.stack_words
> 0 ? info
.reg_words
* UNITS_PER_WORD
: 0;
842 /* Implement TARGET_FUNCTION_ARG hook. */
844 score_function_arg (cumulative_args_t cum_args
, enum machine_mode mode
,
845 const_tree type
, bool named
)
847 struct score_arg_info info
;
848 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_args
);
850 if (mode
== VOIDmode
|| !named
)
853 score_classify_arg (cum
, mode
, type
, named
, &info
);
855 if (info
.reg_offset
== ARG_REG_NUM
)
858 if (!info
.stack_words
)
859 return gen_rtx_REG (mode
, ARG_REG_FIRST
+ info
.reg_offset
);
862 rtx ret
= gen_rtx_PARALLEL (mode
, rtvec_alloc (info
.reg_words
));
863 unsigned int i
, part_offset
= 0;
864 for (i
= 0; i
< info
.reg_words
; i
++)
867 reg
= gen_rtx_REG (SImode
, ARG_REG_FIRST
+ info
.reg_offset
+ i
);
868 XVECEXP (ret
, 0, i
) = gen_rtx_EXPR_LIST (SImode
, reg
,
869 GEN_INT (part_offset
));
870 part_offset
+= UNITS_PER_WORD
;
876 /* Implement FUNCTION_VALUE and LIBCALL_VALUE. For normal calls,
877 VALTYPE is the return type and MODE is VOIDmode. For libcalls,
878 VALTYPE is null and MODE is the mode of the return value. */
880 score_function_value (const_tree valtype
, const_tree func
, enum machine_mode mode
)
885 mode
= TYPE_MODE (valtype
);
886 unsignedp
= TYPE_UNSIGNED (valtype
);
887 mode
= promote_function_mode (valtype
, mode
, &unsignedp
, func
, 1);
889 return gen_rtx_REG (mode
, RT_REGNUM
);
892 /* Implement TARGET_ASM_TRAMPOLINE_TEMPLATE. */
895 score_asm_trampoline_template (FILE *f
)
897 fprintf (f
, "\t.set r1\n");
898 fprintf (f
, "\tmv r31, r3\n");
899 fprintf (f
, "\tbl nextinsn\n");
900 fprintf (f
, "nextinsn:\n");
901 fprintf (f
, "\tlw r1, [r3, 6*4-8]\n");
902 fprintf (f
, "\tlw r23, [r3, 6*4-4]\n");
903 fprintf (f
, "\tmv r3, r31\n");
904 fprintf (f
, "\tbr! r1\n");
905 fprintf (f
, "\tnop!\n");
906 fprintf (f
, "\t.set nor1\n");
909 /* Implement TARGET_TRAMPOLINE_INIT. */
911 score_trampoline_init (rtx m_tramp
, tree fndecl
, rtx chain_value
)
913 #define CODE_SIZE (TRAMPOLINE_INSNS * UNITS_PER_WORD)
915 rtx fnaddr
= XEXP (DECL_RTL (fndecl
), 0);
918 emit_block_move (m_tramp
, assemble_trampoline_template (),
919 GEN_INT (TRAMPOLINE_SIZE
), BLOCK_OP_NORMAL
);
921 mem
= adjust_address (m_tramp
, SImode
, CODE_SIZE
);
922 emit_move_insn (mem
, fnaddr
);
923 mem
= adjust_address (m_tramp
, SImode
, CODE_SIZE
+ GET_MODE_SIZE (SImode
));
924 emit_move_insn (mem
, chain_value
);
929 /* This function is used to implement REG_MODE_OK_FOR_BASE_P macro. */
931 score_regno_mode_ok_for_base_p (int regno
, int strict
)
933 if (regno
>= FIRST_PSEUDO_REGISTER
)
937 regno
= reg_renumber
[regno
];
939 if (regno
== ARG_POINTER_REGNUM
940 || regno
== FRAME_POINTER_REGNUM
)
942 return GP_REG_P (regno
);
945 /* Implement TARGET_LEGITIMATE_ADDRESS_P macro. */
947 score_legitimate_address_p (enum machine_mode mode
, rtx x
, bool strict
)
949 struct score_address_info addr
;
951 return score_classify_address (&addr
, mode
, x
, strict
);
954 /* Implement TARGET_REGISTER_MOVE_COST.
956 Return a number assessing the cost of moving a register in class
959 score_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED
,
960 reg_class_t from
, reg_class_t to
)
962 if (GR_REG_CLASS_P (from
))
964 if (GR_REG_CLASS_P (to
))
966 else if (SP_REG_CLASS_P (to
))
968 else if (CP_REG_CLASS_P (to
))
970 else if (CE_REG_CLASS_P (to
))
973 if (GR_REG_CLASS_P (to
))
975 if (GR_REG_CLASS_P (from
))
977 else if (SP_REG_CLASS_P (from
))
979 else if (CP_REG_CLASS_P (from
))
981 else if (CE_REG_CLASS_P (from
))
987 /* Return the number of instructions needed to load a symbol of the
988 given type into a register. */
990 score_symbol_insns (enum score_symbol_type type
)
997 case SYMBOL_SMALL_DATA
:
1004 /* Return the number of instructions needed to load or store a value
1005 of mode MODE at X. Return 0 if X isn't valid for MODE. */
1007 score_address_insns (rtx x
, enum machine_mode mode
)
1009 struct score_address_info addr
;
1012 if (mode
== BLKmode
)
1015 factor
= (GET_MODE_SIZE (mode
) + UNITS_PER_WORD
- 1) / UNITS_PER_WORD
;
1017 if (score_classify_address (&addr
, mode
, x
, false))
1021 case SCORE_ADD_CONST_INT
:
1024 case SCORE_ADD_SYMBOLIC
:
1025 return factor
* score_symbol_insns (addr
.symbol_type
);
1030 /* Implement TARGET_RTX_COSTS macro. */
1032 score_rtx_costs (rtx x
, int code
, int outer_code
, int opno ATTRIBUTE_UNUSED
,
1033 int *total
, bool speed ATTRIBUTE_UNUSED
)
1035 enum machine_mode mode
= GET_MODE (x
);
1040 if (outer_code
== SET
)
1042 if (((INTVAL (x
) & 0xffff) == 0)
1043 || (INTVAL (x
) >= -32768 && INTVAL (x
) <= 32767))
1044 *total
= COSTS_N_INSNS (1);
1046 *total
= COSTS_N_INSNS (2);
1048 else if (outer_code
== PLUS
|| outer_code
== MINUS
)
1050 if (INTVAL (x
) >= -8192 && INTVAL (x
) <= 8191)
1052 else if (((INTVAL (x
) & 0xffff) == 0)
1053 || (INTVAL (x
) >= -32768 && INTVAL (x
) <= 32767))
1056 *total
= COSTS_N_INSNS (2);
1058 else if (outer_code
== AND
|| outer_code
== IOR
)
1060 if (INTVAL (x
) >= 0 && INTVAL (x
) <= 16383)
1062 else if (((INTVAL (x
) & 0xffff) == 0)
1063 || (INTVAL (x
) >= 0 && INTVAL (x
) <= 65535))
1066 *total
= COSTS_N_INSNS (2);
1078 *total
= COSTS_N_INSNS (2);
1083 /* If the address is legitimate, return the number of
1084 instructions it needs, otherwise use the default handling. */
1085 int n
= score_address_insns (XEXP (x
, 0), GET_MODE (x
));
1088 *total
= COSTS_N_INSNS (n
+ 1);
1095 *total
= COSTS_N_INSNS (6);
1099 *total
= COSTS_N_INSNS (1);
1107 *total
= COSTS_N_INSNS (2);
1117 *total
= COSTS_N_INSNS ((GET_CODE (XEXP (x
, 1)) == CONST_INT
)
1124 *total
= COSTS_N_INSNS (4);
1131 *total
= COSTS_N_INSNS (4);
1134 *total
= COSTS_N_INSNS (1);
1140 *total
= COSTS_N_INSNS (4);
1146 *total
= optimize_size
? COSTS_N_INSNS (2) : COSTS_N_INSNS (12);
1153 *total
= optimize_size
? COSTS_N_INSNS (2) : COSTS_N_INSNS (33);
1158 switch (GET_MODE (XEXP (x
, 0)))
1162 if (GET_CODE (XEXP (x
, 0)) == MEM
)
1164 *total
= COSTS_N_INSNS (2);
1166 if (!TARGET_LITTLE_ENDIAN
&&
1167 side_effects_p (XEXP (XEXP (x
, 0), 0)))
1171 *total
= COSTS_N_INSNS (1);
1175 *total
= COSTS_N_INSNS (1);
1185 /* Implement TARGET_ADDRESS_COST macro. */
1187 score_address_cost (rtx addr
, enum machine_mode mode ATTRIBUTE_UNUSED
,
1188 addr_space_t as ATTRIBUTE_UNUSED
,
1189 bool speed ATTRIBUTE_UNUSED
)
1191 return score_address_insns (addr
, SImode
);
1194 /* Implement ASM_OUTPUT_EXTERNAL macro. */
1196 score_output_external (FILE *file ATTRIBUTE_UNUSED
,
1197 tree decl
, const char *name
)
1199 register struct extern_list
*p
;
1201 if (score_in_small_data_p (decl
))
1203 p
= ggc_alloc
<extern_list
> ();
1204 p
->next
= extern_head
;
1206 p
->size
= int_size_in_bytes (TREE_TYPE (decl
));
1212 /* Implement RETURN_ADDR_RTX. Note, we do not support moving
1213 back to a previous frame. */
1215 score_return_addr (int count
, rtx frame ATTRIBUTE_UNUSED
)
1219 return get_hard_reg_initial_val (Pmode
, RA_REGNUM
);
1222 /* Implement PRINT_OPERAND macro. */
1223 /* Score-specific operand codes:
1224 '[' print .set nor1 directive
1225 ']' print .set r1 directive
1226 'U' print hi part of a CONST_INT rtx
1229 'D' print SFmode const double
1230 'S' selectively print "!" if operand is 15bit instruction accessible
1231 'V' print "v!" if operand is 15bit instruction accessible, or "lfh!"
1232 'L' low part of DImode reg operand
1233 'H' high part of DImode reg operand
1234 'C' print part of opcode for a branch condition. */
1236 score_print_operand (FILE *file
, rtx op
, int c
)
1238 enum rtx_code code
= UNKNOWN
;
1239 if (!PRINT_OPERAND_PUNCT_VALID_P (c
))
1240 code
= GET_CODE (op
);
1244 fprintf (file
, ".set r1\n");
1248 fprintf (file
, "\n\t.set nor1");
1252 gcc_assert (code
== CONST_INT
);
1253 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
,
1254 (INTVAL (op
) >> 16) & 0xffff);
1258 if (GET_CODE (op
) == CONST_DOUBLE
)
1260 rtx temp
= gen_lowpart (SImode
, op
);
1261 gcc_assert (GET_MODE (op
) == SFmode
);
1262 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, INTVAL (temp
) & 0xffffffff);
1265 output_addr_const (file
, op
);
1269 gcc_assert (code
== REG
);
1270 if (G16_REG_P (REGNO (op
)))
1271 fprintf (file
, "!");
1275 gcc_assert (code
== REG
);
1276 fprintf (file
, G16_REG_P (REGNO (op
)) ? "v!" : "lfh!");
1280 enum machine_mode mode
= GET_MODE (XEXP (op
, 0));
1284 case EQ
: fputs ("eq", file
); break;
1285 case NE
: fputs ("ne", file
); break;
1286 case GT
: fputs ("gt", file
); break;
1287 case GE
: fputs (mode
!= CCmode
? "pl" : "ge", file
); break;
1288 case LT
: fputs (mode
!= CCmode
? "mi" : "lt", file
); break;
1289 case LE
: fputs ("le", file
); break;
1290 case GTU
: fputs ("gtu", file
); break;
1291 case GEU
: fputs ("cs", file
); break;
1292 case LTU
: fputs ("cc", file
); break;
1293 case LEU
: fputs ("leu", file
); break;
1295 output_operand_lossage ("invalid operand for code: '%c'", code
);
1300 unsigned HOST_WIDE_INT i
;
1301 unsigned HOST_WIDE_INT pow2mask
= 1;
1302 unsigned HOST_WIDE_INT val
;
1305 for (i
= 0; i
< 32; i
++)
1307 if (val
== pow2mask
)
1311 gcc_assert (i
< 32);
1312 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, i
);
1316 unsigned HOST_WIDE_INT i
;
1317 unsigned HOST_WIDE_INT pow2mask
= 1;
1318 unsigned HOST_WIDE_INT val
;
1321 for (i
= 0; i
< 32; i
++)
1323 if (val
== pow2mask
)
1327 gcc_assert (i
< 32);
1328 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, i
);
1330 else if (code
== REG
)
1332 int regnum
= REGNO (op
);
1333 if ((c
== 'H' && !WORDS_BIG_ENDIAN
)
1334 || (c
== 'L' && WORDS_BIG_ENDIAN
))
1336 fprintf (file
, "%s", reg_names
[regnum
]);
1343 score_print_operand_address (file
, op
);
1346 output_addr_const (file
, op
);
1351 /* Implement PRINT_OPERAND_ADDRESS macro. */
1353 score_print_operand_address (FILE *file
, rtx x
)
1355 struct score_address_info addr
;
1356 enum rtx_code code
= GET_CODE (x
);
1357 enum machine_mode mode
= GET_MODE (x
);
1362 if (score_classify_address (&addr
, mode
, x
, true))
1371 fprintf (file
, "[%s,-%ld]+", reg_names
[REGNO (addr
.reg
)],
1372 INTVAL (addr
.offset
));
1375 fprintf (file
, "[%s]+,-%ld", reg_names
[REGNO (addr
.reg
)],
1376 INTVAL (addr
.offset
));
1379 fprintf (file
, "[%s, %ld]+", reg_names
[REGNO (addr
.reg
)],
1380 INTVAL (addr
.offset
));
1383 fprintf (file
, "[%s]+, %ld", reg_names
[REGNO (addr
.reg
)],
1384 INTVAL (addr
.offset
));
1387 if (INTVAL(addr
.offset
) == 0)
1388 fprintf(file
, "[%s]", reg_names
[REGNO (addr
.reg
)]);
1390 fprintf(file
, "[%s, %ld]", reg_names
[REGNO (addr
.reg
)],
1391 INTVAL(addr
.offset
));
1396 case SCORE_ADD_CONST_INT
:
1397 case SCORE_ADD_SYMBOLIC
:
1398 output_addr_const (file
, x
);
1402 print_rtl (stderr
, x
);
1406 /* Implement SELECT_CC_MODE macro. */
1408 score_select_cc_mode (enum rtx_code op
, rtx x
, rtx y
)
1410 if ((op
== EQ
|| op
== NE
|| op
== LT
|| op
== GE
)
1412 && GET_MODE (x
) == SImode
)
1414 switch (GET_CODE (x
))
1432 return (op
== LT
|| op
== GE
) ? CC_Nmode
: CCmode
;
1439 if ((op
== EQ
|| op
== NE
)
1440 && (GET_CODE (y
) == NEG
)
1441 && register_operand (XEXP (y
, 0), SImode
)
1442 && register_operand (x
, SImode
))
1450 /* Generate the prologue instructions for entry into a S+core function. */
1452 score_prologue (void)
1454 #define EMIT_PL(_rtx) RTX_FRAME_RELATED_P (_rtx) = 1
1456 struct score_frame_info
*f
= score_compute_frame_size (get_frame_size ());
1460 size
= f
->total_size
- f
->gp_reg_size
;
1463 emit_insn (gen_cpload_score7 ());
1465 for (regno
= (int) GP_REG_LAST
; regno
>= (int) GP_REG_FIRST
; regno
--)
1467 if (BITSET_P (f
->mask
, regno
- GP_REG_FIRST
))
1469 rtx mem
= gen_rtx_MEM (SImode
,
1470 gen_rtx_PRE_DEC (SImode
, stack_pointer_rtx
));
1471 rtx reg
= gen_rtx_REG (SImode
, regno
);
1472 if (!crtl
->calls_eh_return
)
1473 MEM_READONLY_P (mem
) = 1;
1474 EMIT_PL (emit_insn (gen_pushsi_score7 (mem
, reg
)));
1482 if (size
>= -32768 && size
<= 32767)
1483 EMIT_PL (emit_insn (gen_add3_insn (stack_pointer_rtx
,
1488 EMIT_PL (emit_move_insn (gen_rtx_REG (Pmode
, SCORE_PROLOGUE_TEMP_REGNUM
),
1491 (gen_sub3_insn (stack_pointer_rtx
,
1494 SCORE_PROLOGUE_TEMP_REGNUM
))));
1496 insn
= get_last_insn ();
1498 alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR
,
1499 gen_rtx_SET (VOIDmode
, stack_pointer_rtx
,
1500 plus_constant (Pmode
, stack_pointer_rtx
,
1505 if (frame_pointer_needed
)
1506 EMIT_PL (emit_move_insn (hard_frame_pointer_rtx
, stack_pointer_rtx
));
1508 if (flag_pic
&& f
->cprestore_size
)
1510 if (frame_pointer_needed
)
1511 emit_insn (gen_cprestore_use_fp_score7 (GEN_INT (size
- f
->cprestore_size
)));
1513 emit_insn (gen_cprestore_use_sp_score7 (GEN_INT (size
- f
->cprestore_size
)));
1519 /* Generate the epilogue instructions in a S+core function. */
1521 score_epilogue (int sibcall_p
)
1523 struct score_frame_info
*f
= score_compute_frame_size (get_frame_size ());
1528 size
= f
->total_size
- f
->gp_reg_size
;
1530 if (!frame_pointer_needed
)
1531 base
= stack_pointer_rtx
;
1533 base
= hard_frame_pointer_rtx
;
1537 if (size
>= -32768 && size
<= 32767)
1538 emit_insn (gen_add3_insn (base
, base
, GEN_INT (size
)));
1541 emit_move_insn (gen_rtx_REG (Pmode
, SCORE_EPILOGUE_TEMP_REGNUM
),
1543 emit_insn (gen_add3_insn (base
, base
,
1545 SCORE_EPILOGUE_TEMP_REGNUM
)));
1549 if (base
!= stack_pointer_rtx
)
1550 emit_move_insn (stack_pointer_rtx
, base
);
1552 if (crtl
->calls_eh_return
)
1553 emit_insn (gen_add3_insn (stack_pointer_rtx
,
1555 EH_RETURN_STACKADJ_RTX
));
1557 for (regno
= (int) GP_REG_FIRST
; regno
<= (int) GP_REG_LAST
; regno
++)
1559 if (BITSET_P (f
->mask
, regno
- GP_REG_FIRST
))
1561 rtx mem
= gen_rtx_MEM (SImode
,
1562 gen_rtx_POST_INC (SImode
, stack_pointer_rtx
));
1563 rtx reg
= gen_rtx_REG (SImode
, regno
);
1565 if (!crtl
->calls_eh_return
)
1566 MEM_READONLY_P (mem
) = 1;
1568 emit_insn (gen_popsi_score7 (reg
, mem
));
1573 emit_jump_insn (gen_return_internal_score7 (gen_rtx_REG (Pmode
, RA_REGNUM
)));
1576 /* Return true if X is a symbolic constant that can be calculated in
1577 the same way as a bare symbol. If it is, store the type of the
1578 symbol in *SYMBOL_TYPE. */
1580 score_symbolic_constant_p (rtx x
, enum score_symbol_type
*symbol_type
)
1582 HOST_WIDE_INT offset
;
1584 score_split_const (x
, &x
, &offset
);
1585 if (GET_CODE (x
) == SYMBOL_REF
|| GET_CODE (x
) == LABEL_REF
)
1586 *symbol_type
= score_classify_symbol (x
);
1593 /* if offset > 15bit, must reload */
1594 if (!IMM_IN_RANGE (offset
, 15, 1))
1597 switch (*symbol_type
)
1599 case SYMBOL_GENERAL
:
1601 case SYMBOL_SMALL_DATA
:
1602 return score_offset_within_object_p (x
, offset
);
1608 score_movsicc (rtx
*ops
)
1610 enum machine_mode mode
;
1612 mode
= score_select_cc_mode (GET_CODE (ops
[1]), ops
[2], ops
[3]);
1613 emit_insn (gen_rtx_SET (VOIDmode
, gen_rtx_REG (mode
, CC_REGNUM
),
1614 gen_rtx_COMPARE (mode
, XEXP (ops
[1], 0),
1615 XEXP (ops
[1], 1))));
1618 /* Call and sibcall pattern all need call this function. */
1620 score_call (rtx
*ops
, bool sib
)
1622 rtx addr
= XEXP (ops
[0], 0);
1623 if (!call_insn_operand (addr
, VOIDmode
))
1626 addr
= gen_reg_rtx (Pmode
);
1627 gen_move_insn (addr
, oaddr
);
1631 emit_call_insn (gen_sibcall_internal_score7 (addr
, ops
[1]));
1633 emit_call_insn (gen_call_internal_score7 (addr
, ops
[1]));
1636 /* Call value and sibcall value pattern all need call this function. */
1638 score_call_value (rtx
*ops
, bool sib
)
1640 rtx result
= ops
[0];
1641 rtx addr
= XEXP (ops
[1], 0);
1644 if (!call_insn_operand (addr
, VOIDmode
))
1647 addr
= gen_reg_rtx (Pmode
);
1648 gen_move_insn (addr
, oaddr
);
1652 emit_call_insn (gen_sibcall_value_internal_score7 (result
, addr
, arg
));
1654 emit_call_insn (gen_call_value_internal_score7 (result
, addr
, arg
));
1659 score_movdi (rtx
*ops
)
1663 rtx dst0
= score_subw (dst
, 0);
1664 rtx dst1
= score_subw (dst
, 1);
1665 rtx src0
= score_subw (src
, 0);
1666 rtx src1
= score_subw (src
, 1);
1668 if (GET_CODE (dst0
) == REG
&& reg_overlap_mentioned_p (dst0
, src
))
1670 emit_move_insn (dst1
, src1
);
1671 emit_move_insn (dst0
, src0
);
1675 emit_move_insn (dst0
, src0
);
1676 emit_move_insn (dst1
, src1
);
1681 score_zero_extract_andi (rtx
*ops
)
1683 if (INTVAL (ops
[1]) == 1 && const_uimm5 (ops
[2], SImode
))
1684 emit_insn (gen_zero_extract_bittst_score7 (ops
[0], ops
[2]));
1687 unsigned HOST_WIDE_INT mask
;
1688 mask
= (0xffffffffU
& ((1U << INTVAL (ops
[1])) - 1U));
1689 mask
= mask
<< INTVAL (ops
[2]);
1690 emit_insn (gen_andsi3_cmp_score7 (ops
[3], ops
[0],
1691 gen_int_mode (mask
, SImode
)));
1695 /* Check addr could be present as PRE/POST mode. */
1697 score_pindex_mem (rtx addr
)
1699 if (GET_CODE (addr
) == MEM
)
1701 switch (GET_CODE (XEXP (addr
, 0)))
1715 /* Output asm code for ld/sw insn. */
1717 score_pr_addr_post (rtx
*ops
, int idata
, int iaddr
, char *ip
, enum score_mem_unit unit
)
1719 struct score_address_info ai
;
1721 gcc_assert (GET_CODE (ops
[idata
]) == REG
);
1722 gcc_assert (score_classify_address (&ai
, SImode
, XEXP (ops
[iaddr
], 0), true));
1724 if (!score_pindex_mem (ops
[iaddr
])
1725 && ai
.type
== SCORE_ADD_REG
1726 && GET_CODE (ai
.offset
) == CONST_INT
1727 && G16_REG_P (REGNO (ops
[idata
]))
1728 && G16_REG_P (REGNO (ai
.reg
)))
1730 if (INTVAL (ai
.offset
) == 0)
1732 ops
[iaddr
] = ai
.reg
;
1733 return snprintf (ip
, INS_BUF_SZ
,
1734 "!\t%%%d, [%%%d]", idata
, iaddr
);
1736 if (REGNO (ai
.reg
) == HARD_FRAME_POINTER_REGNUM
)
1738 HOST_WIDE_INT offset
= INTVAL (ai
.offset
);
1739 if (SCORE_ALIGN_UNIT (offset
, unit
)
1740 && (((offset
>> unit
) >= 0) && ((offset
>> unit
) <= 31)))
1742 ops
[iaddr
] = ai
.offset
;
1743 return snprintf (ip
, INS_BUF_SZ
,
1744 "p!\t%%%d, %%c%d", idata
, iaddr
);
1748 return snprintf (ip
, INS_BUF_SZ
, "\t%%%d, %%a%d", idata
, iaddr
);
1751 /* Output asm insn for load. */
1753 score_linsn (rtx
*ops
, enum score_mem_unit unit
, bool sign
)
1755 const char *pre_ins
[] =
1756 {"lbu", "lhu", "lw", "??", "lb", "lh", "lw", "??"};
1759 strcpy (score_ins
, pre_ins
[(sign
? 4 : 0) + unit
]);
1760 ip
= score_ins
+ strlen (score_ins
);
1762 if ((!sign
&& unit
!= SCORE_HWORD
)
1763 || (sign
&& unit
!= SCORE_BYTE
))
1764 score_pr_addr_post (ops
, 0, 1, ip
, unit
);
1766 snprintf (ip
, INS_BUF_SZ
, "\t%%0, %%a1");
1771 /* Output asm insn for store. */
1773 score_sinsn (rtx
*ops
, enum score_mem_unit unit
)
1775 const char *pre_ins
[] = {"sb", "sh", "sw"};
1778 strcpy (score_ins
, pre_ins
[unit
]);
1779 ip
= score_ins
+ strlen (score_ins
);
1780 score_pr_addr_post (ops
, 1, 0, ip
, unit
);
1784 /* Output asm insn for load immediate. */
1786 score_limm (rtx
*ops
)
1790 gcc_assert (GET_CODE (ops
[0]) == REG
);
1791 gcc_assert (GET_CODE (ops
[1]) == CONST_INT
);
1793 v
= INTVAL (ops
[1]);
1794 if (G16_REG_P (REGNO (ops
[0])) && IMM_IN_RANGE (v
, 8, 0))
1795 return "ldiu!\t%0, %c1";
1796 else if (IMM_IN_RANGE (v
, 16, 1))
1797 return "ldi\t%0, %c1";
1798 else if ((v
& 0xffff) == 0)
1799 return "ldis\t%0, %U1";
1801 return "li\t%0, %c1";
1804 /* Output asm insn for move. */
1806 score_move (rtx
*ops
)
1808 gcc_assert (GET_CODE (ops
[0]) == REG
);
1809 gcc_assert (GET_CODE (ops
[1]) == REG
);
1811 if (G16_REG_P (REGNO (ops
[0])))
1813 if (G16_REG_P (REGNO (ops
[1])))
1814 return "mv!\t%0, %1";
1816 return "mlfh!\t%0, %1";
1818 else if (G16_REG_P (REGNO (ops
[1])))
1819 return "mhfl!\t%0, %1";
1821 return "mv\t%0, %1";
1824 /* Generate add insn. */
1826 score_select_add_imm (rtx
*ops
, bool set_cc
)
1828 HOST_WIDE_INT v
= INTVAL (ops
[2]);
1830 gcc_assert (GET_CODE (ops
[2]) == CONST_INT
);
1831 gcc_assert (REGNO (ops
[0]) == REGNO (ops
[1]));
1833 if (set_cc
&& G16_REG_P (REGNO (ops
[0])))
1835 if (v
> 0 && IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT
) v
, 0, 15))
1837 ops
[2] = GEN_INT (ffs (v
) - 1);
1838 return "addei!\t%0, %c2";
1841 if (v
< 0 && IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT
) (-v
), 0, 15))
1843 ops
[2] = GEN_INT (ffs (-v
) - 1);
1844 return "subei!\t%0, %c2";
1849 return "addi.c\t%0, %c2";
1851 return "addi\t%0, %c2";
1854 /* Output arith insn. */
1856 score_select (rtx
*ops
, const char *inst_pre
,
1857 bool commu
, const char *letter
, bool set_cc
)
1859 gcc_assert (GET_CODE (ops
[0]) == REG
);
1860 gcc_assert (GET_CODE (ops
[1]) == REG
);
1862 if (set_cc
&& G16_REG_P (REGNO (ops
[0]))
1863 && (GET_CODE (ops
[2]) == REG
? G16_REG_P (REGNO (ops
[2])) : 1)
1864 && REGNO (ops
[0]) == REGNO (ops
[1]))
1866 snprintf (score_ins
, INS_BUF_SZ
, "%s!\t%%0, %%%s2", inst_pre
, letter
);
1870 if (commu
&& set_cc
&& G16_REG_P (REGNO (ops
[0]))
1871 && G16_REG_P (REGNO (ops
[1]))
1872 && REGNO (ops
[0]) == REGNO (ops
[2]))
1874 gcc_assert (GET_CODE (ops
[2]) == REG
);
1875 snprintf (score_ins
, INS_BUF_SZ
, "%s!\t%%0, %%%s1", inst_pre
, letter
);
1880 snprintf (score_ins
, INS_BUF_SZ
, "%s.c\t%%0, %%1, %%%s2", inst_pre
, letter
);
1882 snprintf (score_ins
, INS_BUF_SZ
, "%s\t%%0, %%1, %%%s2", inst_pre
, letter
);
1886 /* Return nonzero when an argument must be passed by reference. */
1888 score_pass_by_reference (cumulative_args_t cum ATTRIBUTE_UNUSED
,
1889 enum machine_mode mode
, const_tree type
,
1890 bool named ATTRIBUTE_UNUSED
)
1892 /* If we have a variable-sized parameter, we have no choice. */
1893 return targetm
.calls
.must_pass_in_stack (mode
, type
);
1896 /* Implement TARGET_FUNCTION_OK_FOR_SIBCALL. */
1898 score_function_ok_for_sibcall (ATTRIBUTE_UNUSED tree decl
,
1899 ATTRIBUTE_UNUSED tree exp
)
1904 /* Implement TARGET_SCHED_ISSUE_RATE. */
1906 score_issue_rate (void)
1911 /* We can always eliminate to the hard frame pointer. We can eliminate
1912 to the stack pointer unless a frame pointer is needed. */
1915 score_can_eliminate (const int from ATTRIBUTE_UNUSED
, const int to
)
1917 return (to
== HARD_FRAME_POINTER_REGNUM
1918 || (to
== STACK_POINTER_REGNUM
&& !frame_pointer_needed
));
1921 /* Argument support functions. */
1923 /* Initialize CUMULATIVE_ARGS for a function. */
1925 score_init_cumulative_args (CUMULATIVE_ARGS
*cum
,
1926 tree fntype ATTRIBUTE_UNUSED
,
1927 rtx libname ATTRIBUTE_UNUSED
)
1929 memset (cum
, 0, sizeof (CUMULATIVE_ARGS
));
1933 score_conditional_register_usage (void)
1936 fixed_regs
[PIC_OFFSET_TABLE_REGNUM
] =
1937 call_used_regs
[PIC_OFFSET_TABLE_REGNUM
] = 0;
1940 struct gcc_target targetm
= TARGET_INITIALIZER
;