1 /* Output routines for Sunplus S+CORE processor
2 Copyright (C) 2005-2013 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"
46 #include "target-def.h"
47 #include "langhooks.h"
51 #define SCORE_SDATA_MAX score_sdata_max
52 #define SCORE_STACK_ALIGN(LOC) (((LOC) + 3) & ~3)
53 #define SCORE_PROLOGUE_TEMP_REGNUM (GP_REG_FIRST + 8)
54 #define SCORE_EPILOGUE_TEMP_REGNUM (GP_REG_FIRST + 8)
55 #define SCORE_DEFAULT_SDATA_MAX 8
57 #define BITSET_P(VALUE, BIT) (((VALUE) & (1L << (BIT))) != 0)
58 #define INS_BUF_SZ 128
60 enum score_address_type
67 struct score_frame_info
69 HOST_WIDE_INT total_size; /* bytes that the entire frame takes up */
70 HOST_WIDE_INT var_size; /* bytes that variables take up */
71 HOST_WIDE_INT args_size; /* bytes that outgoing arguments take up */
72 HOST_WIDE_INT gp_reg_size; /* bytes needed to store gp regs */
73 HOST_WIDE_INT gp_sp_offset; /* offset from new sp to store gp registers */
74 HOST_WIDE_INT cprestore_size; /* # bytes that the .cprestore slot takes up */
75 unsigned int mask; /* mask of saved gp registers */
76 int num_gp; /* number of gp registers saved */
81 unsigned int num_bytes; /* The argument's size in bytes */
82 unsigned int reg_words; /* The number of words passed in registers */
83 unsigned int reg_offset; /* The offset of the first register from */
84 /* GP_ARG_FIRST or FP_ARG_FIRST etc */
85 unsigned int stack_words; /* The number of words that must be passed */
87 unsigned int stack_offset; /* The offset from the start of the stack */
92 struct score_address_info
94 enum score_address_type type;
98 enum score_symbol_type symbol_type;
102 static int score_sdata_max;
103 static char score_ins[INS_BUF_SZ + 8];
105 struct extern_list *extern_head = 0;
107 #undef TARGET_ASM_FILE_START
108 #define TARGET_ASM_FILE_START score_asm_file_start
110 #undef TARGET_ASM_FILE_END
111 #define TARGET_ASM_FILE_END score_asm_file_end
113 #undef TARGET_ASM_FUNCTION_PROLOGUE
114 #define TARGET_ASM_FUNCTION_PROLOGUE score_function_prologue
116 #undef TARGET_ASM_FUNCTION_EPILOGUE
117 #define TARGET_ASM_FUNCTION_EPILOGUE score_function_epilogue
119 #undef TARGET_OPTION_OVERRIDE
120 #define TARGET_OPTION_OVERRIDE score_option_override
122 #undef TARGET_SCHED_ISSUE_RATE
123 #define TARGET_SCHED_ISSUE_RATE score_issue_rate
125 #undef TARGET_ASM_SELECT_RTX_SECTION
126 #define TARGET_ASM_SELECT_RTX_SECTION score_select_rtx_section
128 #undef TARGET_IN_SMALL_DATA_P
129 #define TARGET_IN_SMALL_DATA_P score_in_small_data_p
131 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
132 #define TARGET_FUNCTION_OK_FOR_SIBCALL score_function_ok_for_sibcall
134 #undef TARGET_STRICT_ARGUMENT_NAMING
135 #define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true
137 #undef TARGET_ASM_OUTPUT_MI_THUNK
138 #define TARGET_ASM_OUTPUT_MI_THUNK score_output_mi_thunk
140 #undef TARGET_PROMOTE_FUNCTION_MODE
141 #define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
143 #undef TARGET_PROMOTE_PROTOTYPES
144 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
146 #undef TARGET_MUST_PASS_IN_STACK
147 #define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size
149 #undef TARGET_ARG_PARTIAL_BYTES
150 #define TARGET_ARG_PARTIAL_BYTES score_arg_partial_bytes
152 #undef TARGET_FUNCTION_ARG
153 #define TARGET_FUNCTION_ARG score_function_arg
155 #undef TARGET_FUNCTION_ARG_ADVANCE
156 #define TARGET_FUNCTION_ARG_ADVANCE score_function_arg_advance
158 #undef TARGET_PASS_BY_REFERENCE
159 #define TARGET_PASS_BY_REFERENCE score_pass_by_reference
161 #undef TARGET_RETURN_IN_MEMORY
162 #define TARGET_RETURN_IN_MEMORY score_return_in_memory
164 #undef TARGET_RTX_COSTS
165 #define TARGET_RTX_COSTS score_rtx_costs
167 #undef TARGET_ADDRESS_COST
168 #define TARGET_ADDRESS_COST score_address_cost
170 #undef TARGET_LEGITIMATE_ADDRESS_P
171 #define TARGET_LEGITIMATE_ADDRESS_P score_legitimate_address_p
173 #undef TARGET_CAN_ELIMINATE
174 #define TARGET_CAN_ELIMINATE score_can_eliminate
176 #undef TARGET_CONDITIONAL_REGISTER_USAGE
177 #define TARGET_CONDITIONAL_REGISTER_USAGE score_conditional_register_usage
179 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
180 #define TARGET_ASM_TRAMPOLINE_TEMPLATE score_asm_trampoline_template
181 #undef TARGET_TRAMPOLINE_INIT
182 #define TARGET_TRAMPOLINE_INIT score_trampoline_init
184 #undef TARGET_REGISTER_MOVE_COST
185 #define TARGET_REGISTER_MOVE_COST score_register_move_cost
187 /* Return true if SYMBOL is a SYMBOL_REF and OFFSET + SYMBOL points
188 to the same object as SYMBOL. */
190 score_offset_within_object_p (rtx symbol, HOST_WIDE_INT offset)
192 if (GET_CODE (symbol) != SYMBOL_REF)
195 if (CONSTANT_POOL_ADDRESS_P (symbol)
197 && offset < (int)GET_MODE_SIZE (get_pool_mode (symbol)))
200 if (SYMBOL_REF_DECL (symbol) != 0
202 && offset < int_size_in_bytes (TREE_TYPE (SYMBOL_REF_DECL (symbol))))
208 /* Split X into a base and a constant offset, storing them in *BASE
209 and *OFFSET respectively. */
211 score_split_const (rtx x, rtx *base, HOST_WIDE_INT *offset)
215 if (GET_CODE (x) == CONST)
218 if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
220 *offset += INTVAL (XEXP (x, 1));
227 /* Classify symbol X, which must be a SYMBOL_REF or a LABEL_REF. */
228 static enum score_symbol_type
229 score_classify_symbol (rtx x)
231 if (GET_CODE (x) == LABEL_REF)
232 return SYMBOL_GENERAL;
234 gcc_assert (GET_CODE (x) == SYMBOL_REF);
236 if (CONSTANT_POOL_ADDRESS_P (x))
238 if (GET_MODE_SIZE (get_pool_mode (x)) <= SCORE_SDATA_MAX)
239 return SYMBOL_SMALL_DATA;
240 return SYMBOL_GENERAL;
242 if (SYMBOL_REF_SMALL_P (x))
243 return SYMBOL_SMALL_DATA;
244 return SYMBOL_GENERAL;
247 /* Return true if the current function must save REGNO. */
249 score_save_reg_p (unsigned int regno)
251 /* Check call-saved registers. */
252 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
255 /* We need to save the old frame pointer before setting up a new one. */
256 if (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed)
259 /* We need to save the incoming return address if it is ever clobbered
260 within the function. */
261 if (regno == RA_REGNUM && df_regs_ever_live_p (regno))
267 /* Return one word of double-word value OP, taking into account the fixed
268 endianness of certain registers. HIGH_P is true to select the high part,
269 false to select the low part. */
271 score_subw (rtx op, int high_p)
274 enum machine_mode mode = GET_MODE (op);
276 if (mode == VOIDmode)
279 byte = (TARGET_LITTLE_ENDIAN ? high_p : !high_p) ? UNITS_PER_WORD : 0;
281 if (GET_CODE (op) == REG && REGNO (op) == HI_REGNUM)
282 return gen_rtx_REG (SImode, high_p ? HI_REGNUM : LO_REGNUM);
284 if (GET_CODE (op) == MEM)
285 return adjust_address (op, SImode, byte);
287 return simplify_gen_subreg (SImode, op, mode, byte);
290 static struct score_frame_info *
291 score_cached_frame (void)
293 static struct score_frame_info _frame_info;
297 /* Return the bytes needed to compute the frame pointer from the current
298 stack pointer. SIZE is the size (in bytes) of the local variables. */
299 static struct score_frame_info *
300 score_compute_frame_size (HOST_WIDE_INT size)
303 struct score_frame_info *f = score_cached_frame ();
305 memset (f, 0, sizeof (struct score_frame_info));
308 f->var_size = SCORE_STACK_ALIGN (size);
309 f->args_size = crtl->outgoing_args_size;
310 f->cprestore_size = flag_pic ? UNITS_PER_WORD : 0;
311 if (f->var_size == 0 && crtl->is_leaf)
312 f->args_size = f->cprestore_size = 0;
314 if (f->args_size == 0 && cfun->calls_alloca)
315 f->args_size = UNITS_PER_WORD;
317 f->total_size = f->var_size + f->args_size + f->cprestore_size;
318 for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
320 if (score_save_reg_p (regno))
322 f->gp_reg_size += GET_MODE_SIZE (SImode);
323 f->mask |= 1 << (regno - GP_REG_FIRST);
327 if (crtl->calls_eh_return)
332 regno = EH_RETURN_DATA_REGNO (i);
333 if (regno == INVALID_REGNUM)
335 f->gp_reg_size += GET_MODE_SIZE (SImode);
336 f->mask |= 1 << (regno - GP_REG_FIRST);
340 f->total_size += f->gp_reg_size;
341 f->num_gp = f->gp_reg_size / UNITS_PER_WORD;
345 HOST_WIDE_INT offset;
346 offset = (f->args_size + f->cprestore_size + f->var_size
347 + f->gp_reg_size - GET_MODE_SIZE (SImode));
348 f->gp_sp_offset = offset;
356 /* Return true if X is a valid base register for the given mode.
357 Allow only hard registers if STRICT. */
359 score_valid_base_register_p (rtx x, int strict)
361 if (!strict && GET_CODE (x) == SUBREG)
364 return (GET_CODE (x) == REG
365 && score_regno_mode_ok_for_base_p (REGNO (x), strict));
368 /* Return true if X is a valid address for machine mode MODE. If it is,
369 fill in INFO appropriately. STRICT is true if we should only accept
370 hard base registers. */
372 score_classify_address (struct score_address_info *info,
373 enum machine_mode mode, rtx x, int strict)
375 info->code = GET_CODE (x);
381 info->type = SCORE_ADD_REG;
383 info->offset = const0_rtx;
384 return score_valid_base_register_p (info->reg, strict);
386 info->type = SCORE_ADD_REG;
387 info->reg = XEXP (x, 0);
388 info->offset = XEXP (x, 1);
389 return (score_valid_base_register_p (info->reg, strict)
390 && GET_CODE (info->offset) == CONST_INT
391 && IMM_IN_RANGE (INTVAL (info->offset), 15, 1));
396 if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (SImode))
398 info->type = SCORE_ADD_REG;
399 info->reg = XEXP (x, 0);
400 info->offset = GEN_INT (GET_MODE_SIZE (mode));
401 return score_valid_base_register_p (info->reg, strict);
403 info->type = SCORE_ADD_CONST_INT;
404 return IMM_IN_RANGE (INTVAL (x), 15, 1);
408 info->type = SCORE_ADD_SYMBOLIC;
409 return (score_symbolic_constant_p (x, &info->symbol_type)
410 && (info->symbol_type == SYMBOL_GENERAL
411 || info->symbol_type == SYMBOL_SMALL_DATA));
417 /* Implement TARGET_RETURN_IN_MEMORY. In S+core,
418 small structures are returned in a register.
419 Objects with varying size must still be returned in memory. */
421 score_return_in_memory (const_tree type, const_tree fndecl ATTRIBUTE_UNUSED)
423 return ((TYPE_MODE (type) == BLKmode)
424 || (int_size_in_bytes (type) > 2 * UNITS_PER_WORD)
425 || (int_size_in_bytes (type) == -1));
428 /* Return a legitimate address for REG + OFFSET. */
430 score_add_offset (rtx reg, HOST_WIDE_INT offset)
432 if (!IMM_IN_RANGE (offset, 15, 1))
434 reg = expand_simple_binop (GET_MODE (reg), PLUS,
435 gen_int_mode (offset & 0xffffc000,
437 reg, NULL, 0, OPTAB_WIDEN);
441 return plus_constant (GET_MODE (reg), reg, offset);
444 /* Implement TARGET_ASM_OUTPUT_MI_THUNK. Generate rtl rather than asm text
445 in order to avoid duplicating too much logic from elsewhere. */
447 score_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
448 HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
451 rtx this_rtx, temp1, insn, fnaddr;
453 /* Pretend to be a post-reload pass while generating rtl. */
454 reload_completed = 1;
456 /* Mark the end of the (empty) prologue. */
457 emit_note (NOTE_INSN_PROLOGUE_END);
459 /* We need two temporary registers in some cases. */
460 temp1 = gen_rtx_REG (Pmode, 8);
462 /* Find out which register contains the "this" pointer. */
463 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
464 this_rtx = gen_rtx_REG (Pmode, ARG_REG_FIRST + 1);
466 this_rtx = gen_rtx_REG (Pmode, ARG_REG_FIRST);
468 /* Add DELTA to THIS_RTX. */
471 rtx offset = GEN_INT (delta);
472 if (!(delta >= -32768 && delta <= 32767))
474 emit_move_insn (temp1, offset);
477 emit_insn (gen_add3_insn (this_rtx, this_rtx, offset));
480 /* If needed, add *(*THIS_RTX + VCALL_OFFSET) to THIS_RTX. */
481 if (vcall_offset != 0)
485 /* Set TEMP1 to *THIS_RTX. */
486 emit_move_insn (temp1, gen_rtx_MEM (Pmode, this_rtx));
488 /* Set ADDR to a legitimate address for *THIS_RTX + VCALL_OFFSET. */
489 addr = score_add_offset (temp1, vcall_offset);
491 /* Load the offset and add it to THIS_RTX. */
492 emit_move_insn (temp1, gen_rtx_MEM (Pmode, addr));
493 emit_insn (gen_add3_insn (this_rtx, this_rtx, temp1));
496 /* Jump to the target function. */
497 fnaddr = XEXP (DECL_RTL (function), 0);
498 insn = emit_call_insn (gen_sibcall_internal_score7 (fnaddr, const0_rtx));
499 SIBLING_CALL_P (insn) = 1;
501 /* Run just enough of rest_of_compilation. This sequence was
502 "borrowed" from alpha.c. */
504 split_all_insns_noflow ();
505 shorten_branches (insn);
506 final_start_function (insn, file, 1);
507 final (insn, file, 1);
508 final_end_function ();
510 /* Clean up the vars set above. Note that final_end_function resets
511 the global pointer for us. */
512 reload_completed = 0;
515 /* Copy VALUE to a register and return that register. If new psuedos
516 are allowed, copy it into a new register, otherwise use DEST. */
518 score_force_temporary (rtx dest, rtx value)
520 if (can_create_pseudo_p ())
521 return force_reg (Pmode, value);
524 emit_move_insn (copy_rtx (dest), value);
529 /* Return a LO_SUM expression for ADDR. TEMP is as for score_force_temporary
530 and is used to load the high part into a register. */
532 score_split_symbol (rtx temp, rtx addr)
534 rtx high = score_force_temporary (temp,
535 gen_rtx_HIGH (Pmode, copy_rtx (addr)));
536 return gen_rtx_LO_SUM (Pmode, high, addr);
539 /* Fill INFO with information about a single argument. CUM is the
540 cumulative state for earlier arguments. MODE is the mode of this
541 argument and TYPE is its type (if known). NAMED is true if this
542 is a named (fixed) argument rather than a variable one. */
544 score_classify_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
545 const_tree type, bool named, struct score_arg_info *info)
548 unsigned int num_words, max_regs;
551 if (GET_MODE_CLASS (mode) == MODE_INT
552 || GET_MODE_CLASS (mode) == MODE_FLOAT)
553 even_reg_p = (GET_MODE_SIZE (mode) > UNITS_PER_WORD);
555 if (type != NULL_TREE && TYPE_ALIGN (type) > BITS_PER_WORD && named)
558 if (TARGET_MUST_PASS_IN_STACK (mode, type))
559 info->reg_offset = ARG_REG_NUM;
562 info->reg_offset = cum->num_gprs;
564 info->reg_offset += info->reg_offset & 1;
568 info->num_bytes = int_size_in_bytes (type);
570 info->num_bytes = GET_MODE_SIZE (mode);
572 num_words = (info->num_bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
573 max_regs = ARG_REG_NUM - info->reg_offset;
575 /* Partition the argument between registers and stack. */
576 info->reg_words = MIN (num_words, max_regs);
577 info->stack_words = num_words - info->reg_words;
579 /* The alignment applied to registers is also applied to stack arguments. */
580 if (info->stack_words)
582 info->stack_offset = cum->stack_words;
584 info->stack_offset += info->stack_offset & 1;
588 /* Set up the stack and frame (if desired) for the function. */
590 score_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
593 struct score_frame_info *f = score_cached_frame ();
594 HOST_WIDE_INT tsize = f->total_size;
596 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
597 if (!flag_inhibit_size_directive)
599 fputs ("\t.ent\t", file);
600 assemble_name (file, fnname);
603 assemble_name (file, fnname);
606 if (!flag_inhibit_size_directive)
609 "\t.frame\t%s," HOST_WIDE_INT_PRINT_DEC ",%s, %d\t\t"
610 "# vars= " HOST_WIDE_INT_PRINT_DEC ", regs= %d"
611 ", args= " HOST_WIDE_INT_PRINT_DEC
612 ", gp= " HOST_WIDE_INT_PRINT_DEC "\n",
613 (reg_names[(frame_pointer_needed)
614 ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM]),
616 reg_names[RA_REGNUM],
617 crtl->is_leaf ? 1 : 0,
623 fprintf(file, "\t.mask\t0x%08x," HOST_WIDE_INT_PRINT_DEC "\n",
625 (f->gp_sp_offset - f->total_size));
629 /* Do any necessary cleanup after a function to restore stack, frame,
632 score_function_epilogue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
634 if (!flag_inhibit_size_directive)
637 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
638 fputs ("\t.end\t", file);
639 assemble_name (file, fnname);
644 /* Returns true if X contains a SYMBOL_REF. */
646 score_symbolic_expression_p (rtx x)
648 if (GET_CODE (x) == SYMBOL_REF)
651 if (GET_CODE (x) == CONST)
652 return score_symbolic_expression_p (XEXP (x, 0));
655 return score_symbolic_expression_p (XEXP (x, 0));
657 if (ARITHMETIC_P (x))
658 return (score_symbolic_expression_p (XEXP (x, 0))
659 || score_symbolic_expression_p (XEXP (x, 1)));
664 /* Choose the section to use for the constant rtx expression X that has
667 score_select_rtx_section (enum machine_mode mode, rtx x, unsigned HOST_WIDE_INT align)
669 if (GET_MODE_SIZE (mode) <= SCORE_SDATA_MAX)
670 return get_named_section (0, ".sdata", 0);
671 else if (flag_pic && score_symbolic_expression_p (x))
672 return get_named_section (0, ".data.rel.ro", 3);
674 return mergeable_constant_section (mode, align, 0);
677 /* Implement TARGET_IN_SMALL_DATA_P. */
679 score_in_small_data_p (const_tree decl)
683 if (TREE_CODE (decl) == STRING_CST
684 || TREE_CODE (decl) == FUNCTION_DECL)
687 if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl) != 0)
690 name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
691 if (strcmp (name, ".sdata") != 0
692 && strcmp (name, ".sbss") != 0)
694 if (!DECL_EXTERNAL (decl))
697 size = int_size_in_bytes (TREE_TYPE (decl));
698 return (size > 0 && size <= SCORE_SDATA_MAX);
701 /* Implement TARGET_ASM_FILE_START. */
703 score_asm_file_start (void)
705 default_file_start ();
706 fprintf (asm_out_file, ASM_COMMENT_START
707 "GCC for S+core %s \n", SCORE_GCC_VERSION);
710 fprintf (asm_out_file, "\t.set pic\n");
713 /* Implement TARGET_ASM_FILE_END. When using assembler macros, emit
714 .externs for any small-data variables that turned out to be external. */
716 score_asm_file_end (void)
719 struct extern_list *p;
722 fputs ("\n", asm_out_file);
723 for (p = extern_head; p != 0; p = p->next)
725 name_tree = get_identifier (p->name);
726 if (!TREE_ASM_WRITTEN (name_tree)
727 && TREE_SYMBOL_REFERENCED (name_tree))
729 TREE_ASM_WRITTEN (name_tree) = 1;
730 fputs ("\t.extern\t", asm_out_file);
731 assemble_name (asm_out_file, p->name);
732 fprintf (asm_out_file, ", %d\n", p->size);
738 /* Implement TARGET_OPTION_OVERRIDE hook. */
740 score_option_override (void)
743 score_sdata_max = SCORE_DEFAULT_SDATA_MAX;
747 /* Implement REGNO_REG_CLASS macro. */
749 score_reg_class (int regno)
752 gcc_assert (regno >= 0 && regno < FIRST_PSEUDO_REGISTER);
754 if (regno == FRAME_POINTER_REGNUM
755 || regno == ARG_POINTER_REGNUM)
758 for (c = 0; c < N_REG_CLASSES; c++)
759 if (TEST_HARD_REG_BIT (reg_class_contents[c], regno))
765 /* Implement PREFERRED_RELOAD_CLASS macro. */
767 score_preferred_reload_class (rtx x ATTRIBUTE_UNUSED, enum reg_class rclass)
769 if (reg_class_subset_p (G16_REGS, rclass))
771 if (reg_class_subset_p (G32_REGS, rclass))
776 /* Implement SECONDARY_INPUT_RELOAD_CLASS
777 and SECONDARY_OUTPUT_RELOAD_CLASS macro. */
779 score_secondary_reload_class (enum reg_class rclass,
780 enum machine_mode mode ATTRIBUTE_UNUSED,
784 if (GET_CODE (x) == REG || GET_CODE(x) == SUBREG)
785 regno = true_regnum (x);
787 if (!GR_REG_CLASS_P (rclass))
788 return GP_REG_P (regno) ? NO_REGS : G32_REGS;
793 /* Return truth value on whether or not a given hard register
794 can support a given mode. */
796 score_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
798 int size = GET_MODE_SIZE (mode);
799 enum mode_class mclass = GET_MODE_CLASS (mode);
801 if (mclass == MODE_CC)
802 return regno == CC_REGNUM;
803 else if (regno == FRAME_POINTER_REGNUM
804 || regno == ARG_POINTER_REGNUM)
805 return mclass == MODE_INT;
806 else if (GP_REG_P (regno))
807 /* ((regno <= (GP_REG_LAST- HARD_REGNO_NREGS (dummy, mode)) + 1) */
808 return !(regno & 1) || (size <= UNITS_PER_WORD);
809 else if (CE_REG_P (regno))
810 return (mclass == MODE_INT
811 && ((size <= UNITS_PER_WORD)
812 || (regno == CE_REG_FIRST && size == 2 * UNITS_PER_WORD)));
814 return (mclass == MODE_INT) && (size <= UNITS_PER_WORD);
817 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
818 pointer or argument pointer. TO is either the stack pointer or
819 hard frame pointer. */
821 score_initial_elimination_offset (int from,
822 int to ATTRIBUTE_UNUSED)
824 struct score_frame_info *f = score_compute_frame_size (get_frame_size ());
827 case ARG_POINTER_REGNUM:
828 return f->total_size;
829 case FRAME_POINTER_REGNUM:
836 /* Implement TARGET_FUNCTION_ARG_ADVANCE hook. */
838 score_function_arg_advance (cumulative_args_t cum_args, enum machine_mode mode,
839 const_tree type, bool named)
841 struct score_arg_info info;
842 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_args);
843 score_classify_arg (cum, mode, type, named, &info);
844 cum->num_gprs = info.reg_offset + info.reg_words;
845 if (info.stack_words > 0)
846 cum->stack_words = info.stack_offset + info.stack_words;
850 /* Implement TARGET_ARG_PARTIAL_BYTES macro. */
852 score_arg_partial_bytes (cumulative_args_t cum_args,
853 enum machine_mode mode, tree type, bool named)
855 struct score_arg_info info;
856 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_args);
857 score_classify_arg (cum, mode, type, named, &info);
858 return info.stack_words > 0 ? info.reg_words * UNITS_PER_WORD : 0;
861 /* Implement TARGET_FUNCTION_ARG hook. */
863 score_function_arg (cumulative_args_t cum_args, enum machine_mode mode,
864 const_tree type, bool named)
866 struct score_arg_info info;
867 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_args);
869 if (mode == VOIDmode || !named)
872 score_classify_arg (cum, mode, type, named, &info);
874 if (info.reg_offset == ARG_REG_NUM)
877 if (!info.stack_words)
878 return gen_rtx_REG (mode, ARG_REG_FIRST + info.reg_offset);
881 rtx ret = gen_rtx_PARALLEL (mode, rtvec_alloc (info.reg_words));
882 unsigned int i, part_offset = 0;
883 for (i = 0; i < info.reg_words; i++)
886 reg = gen_rtx_REG (SImode, ARG_REG_FIRST + info.reg_offset + i);
887 XVECEXP (ret, 0, i) = gen_rtx_EXPR_LIST (SImode, reg,
888 GEN_INT (part_offset));
889 part_offset += UNITS_PER_WORD;
895 /* Implement FUNCTION_VALUE and LIBCALL_VALUE. For normal calls,
896 VALTYPE is the return type and MODE is VOIDmode. For libcalls,
897 VALTYPE is null and MODE is the mode of the return value. */
899 score_function_value (const_tree valtype, const_tree func, enum machine_mode mode)
904 mode = TYPE_MODE (valtype);
905 unsignedp = TYPE_UNSIGNED (valtype);
906 mode = promote_function_mode (valtype, mode, &unsignedp, func, 1);
908 return gen_rtx_REG (mode, RT_REGNUM);
911 /* Implement TARGET_ASM_TRAMPOLINE_TEMPLATE. */
914 score_asm_trampoline_template (FILE *f)
916 fprintf (f, "\t.set r1\n");
917 fprintf (f, "\tmv r31, r3\n");
918 fprintf (f, "\tbl nextinsn\n");
919 fprintf (f, "nextinsn:\n");
920 fprintf (f, "\tlw r1, [r3, 6*4-8]\n");
921 fprintf (f, "\tlw r23, [r3, 6*4-4]\n");
922 fprintf (f, "\tmv r3, r31\n");
923 fprintf (f, "\tbr! r1\n");
924 fprintf (f, "\tnop!\n");
925 fprintf (f, "\t.set nor1\n");
928 /* Implement TARGET_TRAMPOLINE_INIT. */
930 score_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
932 #define CODE_SIZE (TRAMPOLINE_INSNS * UNITS_PER_WORD)
934 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
937 emit_block_move (m_tramp, assemble_trampoline_template (),
938 GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
940 mem = adjust_address (m_tramp, SImode, CODE_SIZE);
941 emit_move_insn (mem, fnaddr);
942 mem = adjust_address (m_tramp, SImode, CODE_SIZE + GET_MODE_SIZE (SImode));
943 emit_move_insn (mem, chain_value);
948 /* This function is used to implement REG_MODE_OK_FOR_BASE_P macro. */
950 score_regno_mode_ok_for_base_p (int regno, int strict)
952 if (regno >= FIRST_PSEUDO_REGISTER)
956 regno = reg_renumber[regno];
958 if (regno == ARG_POINTER_REGNUM
959 || regno == FRAME_POINTER_REGNUM)
961 return GP_REG_P (regno);
964 /* Implement TARGET_LEGITIMATE_ADDRESS_P macro. */
966 score_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
968 struct score_address_info addr;
970 return score_classify_address (&addr, mode, x, strict);
973 /* Implement TARGET_REGISTER_MOVE_COST.
975 Return a number assessing the cost of moving a register in class
978 score_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
979 reg_class_t from, reg_class_t to)
981 if (GR_REG_CLASS_P (from))
983 if (GR_REG_CLASS_P (to))
985 else if (SP_REG_CLASS_P (to))
987 else if (CP_REG_CLASS_P (to))
989 else if (CE_REG_CLASS_P (to))
992 if (GR_REG_CLASS_P (to))
994 if (GR_REG_CLASS_P (from))
996 else if (SP_REG_CLASS_P (from))
998 else if (CP_REG_CLASS_P (from))
1000 else if (CE_REG_CLASS_P (from))
1006 /* Return the number of instructions needed to load a symbol of the
1007 given type into a register. */
1009 score_symbol_insns (enum score_symbol_type type)
1013 case SYMBOL_GENERAL:
1016 case SYMBOL_SMALL_DATA:
1023 /* Return the number of instructions needed to load or store a value
1024 of mode MODE at X. Return 0 if X isn't valid for MODE. */
1026 score_address_insns (rtx x, enum machine_mode mode)
1028 struct score_address_info addr;
1031 if (mode == BLKmode)
1034 factor = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
1036 if (score_classify_address (&addr, mode, x, false))
1040 case SCORE_ADD_CONST_INT:
1043 case SCORE_ADD_SYMBOLIC:
1044 return factor * score_symbol_insns (addr.symbol_type);
1049 /* Implement TARGET_RTX_COSTS macro. */
1051 score_rtx_costs (rtx x, int code, int outer_code, int opno ATTRIBUTE_UNUSED,
1052 int *total, bool speed ATTRIBUTE_UNUSED)
1054 enum machine_mode mode = GET_MODE (x);
1059 if (outer_code == SET)
1061 if (((INTVAL (x) & 0xffff) == 0)
1062 || (INTVAL (x) >= -32768 && INTVAL (x) <= 32767))
1063 *total = COSTS_N_INSNS (1);
1065 *total = COSTS_N_INSNS (2);
1067 else if (outer_code == PLUS || outer_code == MINUS)
1069 if (INTVAL (x) >= -8192 && INTVAL (x) <= 8191)
1071 else if (((INTVAL (x) & 0xffff) == 0)
1072 || (INTVAL (x) >= -32768 && INTVAL (x) <= 32767))
1075 *total = COSTS_N_INSNS (2);
1077 else if (outer_code == AND || outer_code == IOR)
1079 if (INTVAL (x) >= 0 && INTVAL (x) <= 16383)
1081 else if (((INTVAL (x) & 0xffff) == 0)
1082 || (INTVAL (x) >= 0 && INTVAL (x) <= 65535))
1085 *total = COSTS_N_INSNS (2);
1097 *total = COSTS_N_INSNS (2);
1102 /* If the address is legitimate, return the number of
1103 instructions it needs, otherwise use the default handling. */
1104 int n = score_address_insns (XEXP (x, 0), GET_MODE (x));
1107 *total = COSTS_N_INSNS (n + 1);
1114 *total = COSTS_N_INSNS (6);
1118 *total = COSTS_N_INSNS (1);
1126 *total = COSTS_N_INSNS (2);
1136 *total = COSTS_N_INSNS ((GET_CODE (XEXP (x, 1)) == CONST_INT)
1143 *total = COSTS_N_INSNS (4);
1150 *total = COSTS_N_INSNS (4);
1153 *total = COSTS_N_INSNS (1);
1159 *total = COSTS_N_INSNS (4);
1165 *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (12);
1172 *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (33);
1177 switch (GET_MODE (XEXP (x, 0)))
1181 if (GET_CODE (XEXP (x, 0)) == MEM)
1183 *total = COSTS_N_INSNS (2);
1185 if (!TARGET_LITTLE_ENDIAN &&
1186 side_effects_p (XEXP (XEXP (x, 0), 0)))
1190 *total = COSTS_N_INSNS (1);
1194 *total = COSTS_N_INSNS (1);
1204 /* Implement TARGET_ADDRESS_COST macro. */
1206 score_address_cost (rtx addr, enum machine_mode mode ATTRIBUTE_UNUSED,
1207 addr_space_t as ATTRIBUTE_UNUSED,
1208 bool speed ATTRIBUTE_UNUSED)
1210 return score_address_insns (addr, SImode);
1213 /* Implement ASM_OUTPUT_EXTERNAL macro. */
1215 score_output_external (FILE *file ATTRIBUTE_UNUSED,
1216 tree decl, const char *name)
1218 register struct extern_list *p;
1220 if (score_in_small_data_p (decl))
1222 p = ggc_alloc_extern_list ();
1223 p->next = extern_head;
1225 p->size = int_size_in_bytes (TREE_TYPE (decl));
1231 /* Implement RETURN_ADDR_RTX. Note, we do not support moving
1232 back to a previous frame. */
1234 score_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
1238 return get_hard_reg_initial_val (Pmode, RA_REGNUM);
1241 /* Implement PRINT_OPERAND macro. */
1242 /* Score-specific operand codes:
1243 '[' print .set nor1 directive
1244 ']' print .set r1 directive
1245 'U' print hi part of a CONST_INT rtx
1248 'D' print SFmode const double
1249 'S' selectively print "!" if operand is 15bit instruction accessible
1250 'V' print "v!" if operand is 15bit instruction accessible, or "lfh!"
1251 'L' low part of DImode reg operand
1252 'H' high part of DImode reg operand
1253 'C' print part of opcode for a branch condition. */
1255 score_print_operand (FILE *file, rtx op, int c)
1257 enum rtx_code code = UNKNOWN;
1258 if (!PRINT_OPERAND_PUNCT_VALID_P (c))
1259 code = GET_CODE (op);
1263 fprintf (file, ".set r1\n");
1267 fprintf (file, "\n\t.set nor1");
1271 gcc_assert (code == CONST_INT);
1272 fprintf (file, HOST_WIDE_INT_PRINT_HEX,
1273 (INTVAL (op) >> 16) & 0xffff);
1277 if (GET_CODE (op) == CONST_DOUBLE)
1279 rtx temp = gen_lowpart (SImode, op);
1280 gcc_assert (GET_MODE (op) == SFmode);
1281 fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (temp) & 0xffffffff);
1284 output_addr_const (file, op);
1288 gcc_assert (code == REG);
1289 if (G16_REG_P (REGNO (op)))
1290 fprintf (file, "!");
1294 gcc_assert (code == REG);
1295 fprintf (file, G16_REG_P (REGNO (op)) ? "v!" : "lfh!");
1299 enum machine_mode mode = GET_MODE (XEXP (op, 0));
1303 case EQ: fputs ("eq", file); break;
1304 case NE: fputs ("ne", file); break;
1305 case GT: fputs ("gt", file); break;
1306 case GE: fputs (mode != CCmode ? "pl" : "ge", file); break;
1307 case LT: fputs (mode != CCmode ? "mi" : "lt", file); break;
1308 case LE: fputs ("le", file); break;
1309 case GTU: fputs ("gtu", file); break;
1310 case GEU: fputs ("cs", file); break;
1311 case LTU: fputs ("cc", file); break;
1312 case LEU: fputs ("leu", file); break;
1314 output_operand_lossage ("invalid operand for code: '%c'", code);
1319 unsigned HOST_WIDE_INT i;
1320 unsigned HOST_WIDE_INT pow2mask = 1;
1321 unsigned HOST_WIDE_INT val;
1324 for (i = 0; i < 32; i++)
1326 if (val == pow2mask)
1330 gcc_assert (i < 32);
1331 fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
1335 unsigned HOST_WIDE_INT i;
1336 unsigned HOST_WIDE_INT pow2mask = 1;
1337 unsigned HOST_WIDE_INT val;
1340 for (i = 0; i < 32; i++)
1342 if (val == pow2mask)
1346 gcc_assert (i < 32);
1347 fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
1349 else if (code == REG)
1351 int regnum = REGNO (op);
1352 if ((c == 'H' && !WORDS_BIG_ENDIAN)
1353 || (c == 'L' && WORDS_BIG_ENDIAN))
1355 fprintf (file, "%s", reg_names[regnum]);
1362 score_print_operand_address (file, op);
1365 output_addr_const (file, op);
1370 /* Implement PRINT_OPERAND_ADDRESS macro. */
1372 score_print_operand_address (FILE *file, rtx x)
1374 struct score_address_info addr;
1375 enum rtx_code code = GET_CODE (x);
1376 enum machine_mode mode = GET_MODE (x);
1381 if (score_classify_address (&addr, mode, x, true))
1390 fprintf (file, "[%s,-%ld]+", reg_names[REGNO (addr.reg)],
1391 INTVAL (addr.offset));
1394 fprintf (file, "[%s]+,-%ld", reg_names[REGNO (addr.reg)],
1395 INTVAL (addr.offset));
1398 fprintf (file, "[%s, %ld]+", reg_names[REGNO (addr.reg)],
1399 INTVAL (addr.offset));
1402 fprintf (file, "[%s]+, %ld", reg_names[REGNO (addr.reg)],
1403 INTVAL (addr.offset));
1406 if (INTVAL(addr.offset) == 0)
1407 fprintf(file, "[%s]", reg_names[REGNO (addr.reg)]);
1409 fprintf(file, "[%s, %ld]", reg_names[REGNO (addr.reg)],
1410 INTVAL(addr.offset));
1415 case SCORE_ADD_CONST_INT:
1416 case SCORE_ADD_SYMBOLIC:
1417 output_addr_const (file, x);
1421 print_rtl (stderr, x);
1425 /* Implement SELECT_CC_MODE macro. */
1427 score_select_cc_mode (enum rtx_code op, rtx x, rtx y)
1429 if ((op == EQ || op == NE || op == LT || op == GE)
1431 && GET_MODE (x) == SImode)
1433 switch (GET_CODE (x))
1451 return (op == LT || op == GE) ? CC_Nmode : CCmode;
1458 if ((op == EQ || op == NE)
1459 && (GET_CODE (y) == NEG)
1460 && register_operand (XEXP (y, 0), SImode)
1461 && register_operand (x, SImode))
1469 /* Generate the prologue instructions for entry into a S+core function. */
1471 score_prologue (void)
1473 #define EMIT_PL(_rtx) RTX_FRAME_RELATED_P (_rtx) = 1
1475 struct score_frame_info *f = score_compute_frame_size (get_frame_size ());
1479 size = f->total_size - f->gp_reg_size;
1482 emit_insn (gen_cpload_score7 ());
1484 for (regno = (int) GP_REG_LAST; regno >= (int) GP_REG_FIRST; regno--)
1486 if (BITSET_P (f->mask, regno - GP_REG_FIRST))
1488 rtx mem = gen_rtx_MEM (SImode,
1489 gen_rtx_PRE_DEC (SImode, stack_pointer_rtx));
1490 rtx reg = gen_rtx_REG (SImode, regno);
1491 if (!crtl->calls_eh_return)
1492 MEM_READONLY_P (mem) = 1;
1493 EMIT_PL (emit_insn (gen_pushsi_score7 (mem, reg)));
1501 if (size >= -32768 && size <= 32767)
1502 EMIT_PL (emit_insn (gen_add3_insn (stack_pointer_rtx,
1507 EMIT_PL (emit_move_insn (gen_rtx_REG (Pmode, SCORE_PROLOGUE_TEMP_REGNUM),
1510 (gen_sub3_insn (stack_pointer_rtx,
1513 SCORE_PROLOGUE_TEMP_REGNUM))));
1515 insn = get_last_insn ();
1517 alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR,
1518 gen_rtx_SET (VOIDmode, stack_pointer_rtx,
1519 plus_constant (Pmode, stack_pointer_rtx,
1524 if (frame_pointer_needed)
1525 EMIT_PL (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx));
1527 if (flag_pic && f->cprestore_size)
1529 if (frame_pointer_needed)
1530 emit_insn (gen_cprestore_use_fp_score7 (GEN_INT (size - f->cprestore_size)));
1532 emit_insn (gen_cprestore_use_sp_score7 (GEN_INT (size - f->cprestore_size)));
1538 /* Generate the epilogue instructions in a S+core function. */
1540 score_epilogue (int sibcall_p)
1542 struct score_frame_info *f = score_compute_frame_size (get_frame_size ());
1547 size = f->total_size - f->gp_reg_size;
1549 if (!frame_pointer_needed)
1550 base = stack_pointer_rtx;
1552 base = hard_frame_pointer_rtx;
1556 if (size >= -32768 && size <= 32767)
1557 emit_insn (gen_add3_insn (base, base, GEN_INT (size)));
1560 emit_move_insn (gen_rtx_REG (Pmode, SCORE_EPILOGUE_TEMP_REGNUM),
1562 emit_insn (gen_add3_insn (base, base,
1564 SCORE_EPILOGUE_TEMP_REGNUM)));
1568 if (base != stack_pointer_rtx)
1569 emit_move_insn (stack_pointer_rtx, base);
1571 if (crtl->calls_eh_return)
1572 emit_insn (gen_add3_insn (stack_pointer_rtx,
1574 EH_RETURN_STACKADJ_RTX));
1576 for (regno = (int) GP_REG_FIRST; regno <= (int) GP_REG_LAST; regno++)
1578 if (BITSET_P (f->mask, regno - GP_REG_FIRST))
1580 rtx mem = gen_rtx_MEM (SImode,
1581 gen_rtx_POST_INC (SImode, stack_pointer_rtx));
1582 rtx reg = gen_rtx_REG (SImode, regno);
1584 if (!crtl->calls_eh_return)
1585 MEM_READONLY_P (mem) = 1;
1587 emit_insn (gen_popsi_score7 (reg, mem));
1592 emit_jump_insn (gen_return_internal_score7 (gen_rtx_REG (Pmode, RA_REGNUM)));
1595 /* Return true if X is a symbolic constant that can be calculated in
1596 the same way as a bare symbol. If it is, store the type of the
1597 symbol in *SYMBOL_TYPE. */
1599 score_symbolic_constant_p (rtx x, enum score_symbol_type *symbol_type)
1601 HOST_WIDE_INT offset;
1603 score_split_const (x, &x, &offset);
1604 if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF)
1605 *symbol_type = score_classify_symbol (x);
1612 /* if offset > 15bit, must reload */
1613 if (!IMM_IN_RANGE (offset, 15, 1))
1616 switch (*symbol_type)
1618 case SYMBOL_GENERAL:
1620 case SYMBOL_SMALL_DATA:
1621 return score_offset_within_object_p (x, offset);
1627 score_movsicc (rtx *ops)
1629 enum machine_mode mode;
1631 mode = score_select_cc_mode (GET_CODE (ops[1]), ops[2], ops[3]);
1632 emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (mode, CC_REGNUM),
1633 gen_rtx_COMPARE (mode, XEXP (ops[1], 0),
1634 XEXP (ops[1], 1))));
1637 /* Call and sibcall pattern all need call this function. */
1639 score_call (rtx *ops, bool sib)
1641 rtx addr = XEXP (ops[0], 0);
1642 if (!call_insn_operand (addr, VOIDmode))
1645 addr = gen_reg_rtx (Pmode);
1646 gen_move_insn (addr, oaddr);
1650 emit_call_insn (gen_sibcall_internal_score7 (addr, ops[1]));
1652 emit_call_insn (gen_call_internal_score7 (addr, ops[1]));
1655 /* Call value and sibcall value pattern all need call this function. */
1657 score_call_value (rtx *ops, bool sib)
1659 rtx result = ops[0];
1660 rtx addr = XEXP (ops[1], 0);
1663 if (!call_insn_operand (addr, VOIDmode))
1666 addr = gen_reg_rtx (Pmode);
1667 gen_move_insn (addr, oaddr);
1671 emit_call_insn (gen_sibcall_value_internal_score7 (result, addr, arg));
1673 emit_call_insn (gen_call_value_internal_score7 (result, addr, arg));
1678 score_movdi (rtx *ops)
1682 rtx dst0 = score_subw (dst, 0);
1683 rtx dst1 = score_subw (dst, 1);
1684 rtx src0 = score_subw (src, 0);
1685 rtx src1 = score_subw (src, 1);
1687 if (GET_CODE (dst0) == REG && reg_overlap_mentioned_p (dst0, src))
1689 emit_move_insn (dst1, src1);
1690 emit_move_insn (dst0, src0);
1694 emit_move_insn (dst0, src0);
1695 emit_move_insn (dst1, src1);
1700 score_zero_extract_andi (rtx *ops)
1702 if (INTVAL (ops[1]) == 1 && const_uimm5 (ops[2], SImode))
1703 emit_insn (gen_zero_extract_bittst_score7 (ops[0], ops[2]));
1706 unsigned HOST_WIDE_INT mask;
1707 mask = (0xffffffffU & ((1U << INTVAL (ops[1])) - 1U));
1708 mask = mask << INTVAL (ops[2]);
1709 emit_insn (gen_andsi3_cmp_score7 (ops[3], ops[0],
1710 gen_int_mode (mask, SImode)));
1714 /* Check addr could be present as PRE/POST mode. */
1716 score_pindex_mem (rtx addr)
1718 if (GET_CODE (addr) == MEM)
1720 switch (GET_CODE (XEXP (addr, 0)))
1734 /* Output asm code for ld/sw insn. */
1736 score_pr_addr_post (rtx *ops, int idata, int iaddr, char *ip, enum score_mem_unit unit)
1738 struct score_address_info ai;
1740 gcc_assert (GET_CODE (ops[idata]) == REG);
1741 gcc_assert (score_classify_address (&ai, SImode, XEXP (ops[iaddr], 0), true));
1743 if (!score_pindex_mem (ops[iaddr])
1744 && ai.type == SCORE_ADD_REG
1745 && GET_CODE (ai.offset) == CONST_INT
1746 && G16_REG_P (REGNO (ops[idata]))
1747 && G16_REG_P (REGNO (ai.reg)))
1749 if (INTVAL (ai.offset) == 0)
1751 ops[iaddr] = ai.reg;
1752 return snprintf (ip, INS_BUF_SZ,
1753 "!\t%%%d, [%%%d]", idata, iaddr);
1755 if (REGNO (ai.reg) == HARD_FRAME_POINTER_REGNUM)
1757 HOST_WIDE_INT offset = INTVAL (ai.offset);
1758 if (SCORE_ALIGN_UNIT (offset, unit)
1759 && (((offset >> unit) >= 0) && ((offset >> unit) <= 31)))
1761 ops[iaddr] = ai.offset;
1762 return snprintf (ip, INS_BUF_SZ,
1763 "p!\t%%%d, %%c%d", idata, iaddr);
1767 return snprintf (ip, INS_BUF_SZ, "\t%%%d, %%a%d", idata, iaddr);
1770 /* Output asm insn for load. */
1772 score_linsn (rtx *ops, enum score_mem_unit unit, bool sign)
1774 const char *pre_ins[] =
1775 {"lbu", "lhu", "lw", "??", "lb", "lh", "lw", "??"};
1778 strcpy (score_ins, pre_ins[(sign ? 4 : 0) + unit]);
1779 ip = score_ins + strlen (score_ins);
1781 if ((!sign && unit != SCORE_HWORD)
1782 || (sign && unit != SCORE_BYTE))
1783 score_pr_addr_post (ops, 0, 1, ip, unit);
1785 snprintf (ip, INS_BUF_SZ, "\t%%0, %%a1");
1790 /* Output asm insn for store. */
1792 score_sinsn (rtx *ops, enum score_mem_unit unit)
1794 const char *pre_ins[] = {"sb", "sh", "sw"};
1797 strcpy (score_ins, pre_ins[unit]);
1798 ip = score_ins + strlen (score_ins);
1799 score_pr_addr_post (ops, 1, 0, ip, unit);
1803 /* Output asm insn for load immediate. */
1805 score_limm (rtx *ops)
1809 gcc_assert (GET_CODE (ops[0]) == REG);
1810 gcc_assert (GET_CODE (ops[1]) == CONST_INT);
1812 v = INTVAL (ops[1]);
1813 if (G16_REG_P (REGNO (ops[0])) && IMM_IN_RANGE (v, 8, 0))
1814 return "ldiu!\t%0, %c1";
1815 else if (IMM_IN_RANGE (v, 16, 1))
1816 return "ldi\t%0, %c1";
1817 else if ((v & 0xffff) == 0)
1818 return "ldis\t%0, %U1";
1820 return "li\t%0, %c1";
1823 /* Output asm insn for move. */
1825 score_move (rtx *ops)
1827 gcc_assert (GET_CODE (ops[0]) == REG);
1828 gcc_assert (GET_CODE (ops[1]) == REG);
1830 if (G16_REG_P (REGNO (ops[0])))
1832 if (G16_REG_P (REGNO (ops[1])))
1833 return "mv!\t%0, %1";
1835 return "mlfh!\t%0, %1";
1837 else if (G16_REG_P (REGNO (ops[1])))
1838 return "mhfl!\t%0, %1";
1840 return "mv\t%0, %1";
1843 /* Generate add insn. */
1845 score_select_add_imm (rtx *ops, bool set_cc)
1847 HOST_WIDE_INT v = INTVAL (ops[2]);
1849 gcc_assert (GET_CODE (ops[2]) == CONST_INT);
1850 gcc_assert (REGNO (ops[0]) == REGNO (ops[1]));
1852 if (set_cc && G16_REG_P (REGNO (ops[0])))
1854 if (v > 0 && IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT) v, 0, 15))
1856 ops[2] = GEN_INT (ffs (v) - 1);
1857 return "addei!\t%0, %c2";
1860 if (v < 0 && IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT) (-v), 0, 15))
1862 ops[2] = GEN_INT (ffs (-v) - 1);
1863 return "subei!\t%0, %c2";
1868 return "addi.c\t%0, %c2";
1870 return "addi\t%0, %c2";
1873 /* Output arith insn. */
1875 score_select (rtx *ops, const char *inst_pre,
1876 bool commu, const char *letter, bool set_cc)
1878 gcc_assert (GET_CODE (ops[0]) == REG);
1879 gcc_assert (GET_CODE (ops[1]) == REG);
1881 if (set_cc && G16_REG_P (REGNO (ops[0]))
1882 && (GET_CODE (ops[2]) == REG ? G16_REG_P (REGNO (ops[2])) : 1)
1883 && REGNO (ops[0]) == REGNO (ops[1]))
1885 snprintf (score_ins, INS_BUF_SZ, "%s!\t%%0, %%%s2", inst_pre, letter);
1889 if (commu && set_cc && G16_REG_P (REGNO (ops[0]))
1890 && G16_REG_P (REGNO (ops[1]))
1891 && REGNO (ops[0]) == REGNO (ops[2]))
1893 gcc_assert (GET_CODE (ops[2]) == REG);
1894 snprintf (score_ins, INS_BUF_SZ, "%s!\t%%0, %%%s1", inst_pre, letter);
1899 snprintf (score_ins, INS_BUF_SZ, "%s.c\t%%0, %%1, %%%s2", inst_pre, letter);
1901 snprintf (score_ins, INS_BUF_SZ, "%s\t%%0, %%1, %%%s2", inst_pre, letter);
1905 /* Return nonzero when an argument must be passed by reference. */
1907 score_pass_by_reference (cumulative_args_t cum ATTRIBUTE_UNUSED,
1908 enum machine_mode mode, const_tree type,
1909 bool named ATTRIBUTE_UNUSED)
1911 /* If we have a variable-sized parameter, we have no choice. */
1912 return targetm.calls.must_pass_in_stack (mode, type);
1915 /* Implement TARGET_FUNCTION_OK_FOR_SIBCALL. */
1917 score_function_ok_for_sibcall (ATTRIBUTE_UNUSED tree decl,
1918 ATTRIBUTE_UNUSED tree exp)
1923 /* Implement TARGET_SCHED_ISSUE_RATE. */
1925 score_issue_rate (void)
1930 /* We can always eliminate to the hard frame pointer. We can eliminate
1931 to the stack pointer unless a frame pointer is needed. */
1934 score_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to)
1936 return (to == HARD_FRAME_POINTER_REGNUM
1937 || (to == STACK_POINTER_REGNUM && !frame_pointer_needed));
1940 /* Argument support functions. */
1942 /* Initialize CUMULATIVE_ARGS for a function. */
1944 score_init_cumulative_args (CUMULATIVE_ARGS *cum,
1945 tree fntype ATTRIBUTE_UNUSED,
1946 rtx libname ATTRIBUTE_UNUSED)
1948 memset (cum, 0, sizeof (CUMULATIVE_ARGS));
1952 score_conditional_register_usage (void)
1955 fixed_regs[PIC_OFFSET_TABLE_REGNUM] =
1956 call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 0;
1959 struct gcc_target targetm = TARGET_INITIALIZER;