1 /* Output routines for Sunplus S+CORE processor
2 Copyright (C) 2005, 2007 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"
28 #include "hard-reg-set.h"
30 #include "insn-config.h"
31 #include "conditions.h"
32 #include "insn-attr.h"
48 #include "target-def.h"
49 #include "integrate.h"
50 #include "langhooks.h"
51 #include "cfglayout.h"
52 #include "score-mdaux.h"
54 #define GR_REG_CLASS_P(C) ((C) == G16_REGS || (C) == G32_REGS)
55 #define SP_REG_CLASS_P(C) \
56 ((C) == CN_REG || (C) == LC_REG || (C) == SC_REG || (C) == SP_REGS)
57 #define CP_REG_CLASS_P(C) \
58 ((C) == CP1_REGS || (C) == CP2_REGS || (C) == CP3_REGS || (C) == CPA_REGS)
59 #define CE_REG_CLASS_P(C) \
60 ((C) == HI_REG || (C) == LO_REG || (C) == CE_REGS)
62 static int score_arg_partial_bytes (CUMULATIVE_ARGS *,
63 enum machine_mode, tree, bool);
65 static int score_symbol_insns (enum score_symbol_type);
67 static int score_address_insns (rtx, enum machine_mode);
69 static bool score_rtx_costs (rtx, enum rtx_code, enum rtx_code, int *);
71 static int score_address_cost (rtx);
73 #undef TARGET_ASM_FILE_START
74 #define TARGET_ASM_FILE_START th_asm_file_start
76 #undef TARGET_ASM_FILE_END
77 #define TARGET_ASM_FILE_END th_asm_file_end
79 #undef TARGET_ASM_FUNCTION_PROLOGUE
80 #define TARGET_ASM_FUNCTION_PROLOGUE th_function_prologue
82 #undef TARGET_ASM_FUNCTION_EPILOGUE
83 #define TARGET_ASM_FUNCTION_EPILOGUE th_function_epilogue
85 #undef TARGET_SCHED_ISSUE_RATE
86 #define TARGET_SCHED_ISSUE_RATE th_issue_rate
88 #undef TARGET_ASM_SELECT_RTX_SECTION
89 #define TARGET_ASM_SELECT_RTX_SECTION th_select_rtx_section
91 #undef TARGET_IN_SMALL_DATA_P
92 #define TARGET_IN_SMALL_DATA_P th_in_small_data_p
94 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
95 #define TARGET_FUNCTION_OK_FOR_SIBCALL th_function_ok_for_sibcall
97 #undef TARGET_STRICT_ARGUMENT_NAMING
98 #define TARGET_STRICT_ARGUMENT_NAMING th_strict_argument_naming
100 #undef TARGET_ASM_OUTPUT_MI_THUNK
101 #define TARGET_ASM_OUTPUT_MI_THUNK th_output_mi_thunk
103 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
104 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true
106 #undef TARGET_PROMOTE_FUNCTION_ARGS
107 #define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_const_tree_true
109 #undef TARGET_PROMOTE_FUNCTION_RETURN
110 #define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_const_tree_true
112 #undef TARGET_PROMOTE_PROTOTYPES
113 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
115 #undef TARGET_MUST_PASS_IN_STACK
116 #define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size
118 #undef TARGET_ARG_PARTIAL_BYTES
119 #define TARGET_ARG_PARTIAL_BYTES score_arg_partial_bytes
121 #undef TARGET_PASS_BY_REFERENCE
122 #define TARGET_PASS_BY_REFERENCE score_pass_by_reference
124 #undef TARGET_RETURN_IN_MEMORY
125 #define TARGET_RETURN_IN_MEMORY score_return_in_memory
127 #undef TARGET_RTX_COSTS
128 #define TARGET_RTX_COSTS score_rtx_costs
130 #undef TARGET_ADDRESS_COST
131 #define TARGET_ADDRESS_COST score_address_cost
133 #undef TARGET_DEFAULT_TARGET_FLAGS
134 #define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
136 /* Implement TARGET_RETURN_IN_MEMORY. In S+core,
137 small structures are returned in a register.
138 Objects with varying size must still be returned in memory. */
140 score_return_in_memory (const_tree type, const_tree fndecl ATTRIBUTE_UNUSED)
142 return ((TYPE_MODE (type) == BLKmode)
143 || (int_size_in_bytes (type) > 2 * UNITS_PER_WORD)
144 || (int_size_in_bytes (type) == -1));
147 /* Return nonzero when an argument must be passed by reference. */
149 score_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
150 enum machine_mode mode, const_tree type,
151 bool named ATTRIBUTE_UNUSED)
153 /* If we have a variable-sized parameter, we have no choice. */
154 return targetm.calls.must_pass_in_stack (mode, type);
157 /* Return a legitimate address for REG + OFFSET. */
159 score_add_offset (rtx temp ATTRIBUTE_UNUSED, rtx reg, HOST_WIDE_INT offset)
161 if (!IMM_IN_RANGE (offset, 15, 1))
163 reg = expand_simple_binop (GET_MODE (reg), PLUS,
164 gen_int_mode (offset & 0xffffc000,
166 reg, NULL, 0, OPTAB_WIDEN);
170 return plus_constant (reg, offset);
173 /* Implement TARGET_ASM_OUTPUT_MI_THUNK. Generate rtl rather than asm text
174 in order to avoid duplicating too much logic from elsewhere. */
176 th_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
177 HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
180 rtx this, temp1, temp2, insn, fnaddr;
182 /* Pretend to be a post-reload pass while generating rtl. */
183 reload_completed = 1;
185 /* Mark the end of the (empty) prologue. */
186 emit_note (NOTE_INSN_PROLOGUE_END);
188 /* We need two temporary registers in some cases. */
189 temp1 = gen_rtx_REG (Pmode, 8);
190 temp2 = gen_rtx_REG (Pmode, 9);
192 /* Find out which register contains the "this" pointer. */
193 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
194 this = gen_rtx_REG (Pmode, ARG_REG_FIRST + 1);
196 this = gen_rtx_REG (Pmode, ARG_REG_FIRST);
198 /* Add DELTA to THIS. */
201 rtx offset = GEN_INT (delta);
202 if (!CONST_OK_FOR_LETTER_P (delta, 'L'))
204 emit_move_insn (temp1, offset);
207 emit_insn (gen_add3_insn (this, this, offset));
210 /* If needed, add *(*THIS + VCALL_OFFSET) to THIS. */
211 if (vcall_offset != 0)
215 /* Set TEMP1 to *THIS. */
216 emit_move_insn (temp1, gen_rtx_MEM (Pmode, this));
218 /* Set ADDR to a legitimate address for *THIS + VCALL_OFFSET. */
219 addr = score_add_offset (temp2, temp1, vcall_offset);
221 /* Load the offset and add it to THIS. */
222 emit_move_insn (temp1, gen_rtx_MEM (Pmode, addr));
223 emit_insn (gen_add3_insn (this, this, temp1));
226 /* Jump to the target function. */
227 fnaddr = XEXP (DECL_RTL (function), 0);
228 insn = emit_call_insn (gen_sibcall_internal (fnaddr, const0_rtx));
229 SIBLING_CALL_P (insn) = 1;
231 /* Run just enough of rest_of_compilation. This sequence was
232 "borrowed" from alpha.c. */
234 insn_locators_alloc ();
235 split_all_insns_noflow ();
236 shorten_branches (insn);
237 final_start_function (insn, file, 1);
238 final (insn, file, 1);
239 final_end_function ();
241 /* Clean up the vars set above. Note that final_end_function resets
242 the global pointer for us. */
243 reload_completed = 0;
246 /* Implement TARGET_STRICT_ARGUMENT_NAMING. */
248 th_strict_argument_naming (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED)
253 /* Implement TARGET_FUNCTION_OK_FOR_SIBCALL. */
255 th_function_ok_for_sibcall (ATTRIBUTE_UNUSED tree decl,
256 ATTRIBUTE_UNUSED tree exp)
261 struct score_arg_info
263 /* The argument's size, in bytes. */
264 unsigned int num_bytes;
266 /* The number of words passed in registers, rounded up. */
267 unsigned int reg_words;
269 /* The offset of the first register from GP_ARG_FIRST or FP_ARG_FIRST,
270 or ARG_REG_NUM if the argument is passed entirely on the stack. */
271 unsigned int reg_offset;
273 /* The number of words that must be passed on the stack, rounded up. */
274 unsigned int stack_words;
276 /* The offset from the start of the stack overflow area of the argument's
277 first stack word. Only meaningful when STACK_WORDS is nonzero. */
278 unsigned int stack_offset;
281 /* Fill INFO with information about a single argument. CUM is the
282 cumulative state for earlier arguments. MODE is the mode of this
283 argument and TYPE is its type (if known). NAMED is true if this
284 is a named (fixed) argument rather than a variable one. */
286 classify_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
287 tree type, int named, struct score_arg_info *info)
290 unsigned int num_words, max_regs;
293 if (GET_MODE_CLASS (mode) == MODE_INT
294 || GET_MODE_CLASS (mode) == MODE_FLOAT)
295 even_reg_p = (GET_MODE_SIZE (mode) > UNITS_PER_WORD);
297 if (type != NULL_TREE && TYPE_ALIGN (type) > BITS_PER_WORD && named)
300 if (TARGET_MUST_PASS_IN_STACK (mode, type))
301 info->reg_offset = ARG_REG_NUM;
304 info->reg_offset = cum->num_gprs;
306 info->reg_offset += info->reg_offset & 1;
310 info->num_bytes = int_size_in_bytes (type);
312 info->num_bytes = GET_MODE_SIZE (mode);
314 num_words = (info->num_bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
315 max_regs = ARG_REG_NUM - info->reg_offset;
317 /* Partition the argument between registers and stack. */
318 info->reg_words = MIN (num_words, max_regs);
319 info->stack_words = num_words - info->reg_words;
321 /* The alignment applied to registers is also applied to stack arguments. */
322 if (info->stack_words)
324 info->stack_offset = cum->stack_words;
326 info->stack_offset += info->stack_offset & 1;
330 /* Set up the stack and frame (if desired) for the function. */
332 th_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
335 struct score_frame_info *f = mda_cached_frame ();
336 HOST_WIDE_INT tsize = f->total_size;
338 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
339 if (!flag_inhibit_size_directive)
341 fputs ("\t.ent\t", file);
342 assemble_name (file, fnname);
345 assemble_name (file, fnname);
348 if (!flag_inhibit_size_directive)
351 "\t.frame\t%s," HOST_WIDE_INT_PRINT_DEC ",%s, %d\t\t"
352 "# vars= " HOST_WIDE_INT_PRINT_DEC ", regs= %d"
353 ", args= " HOST_WIDE_INT_PRINT_DEC
354 ", gp= " HOST_WIDE_INT_PRINT_DEC "\n",
355 (reg_names[(frame_pointer_needed)
356 ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM]),
358 reg_names[RA_REGNUM],
359 current_function_is_leaf ? 1 : 0,
365 fprintf(file, "\t.mask\t0x%08x," HOST_WIDE_INT_PRINT_DEC "\n",
367 (f->gp_sp_offset - f->total_size));
371 /* Do any necessary cleanup after a function to restore stack, frame,
374 th_function_epilogue (FILE *file,
375 HOST_WIDE_INT size ATTRIBUTE_UNUSED)
377 if (!flag_inhibit_size_directive)
380 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
381 fputs ("\t.end\t", file);
382 assemble_name (file, fnname);
387 /* Implement TARGET_SCHED_ISSUE_RATE. */
394 /* Returns true if X contains a SYMBOL_REF. */
396 symbolic_expression_p (rtx x)
398 if (GET_CODE (x) == SYMBOL_REF)
401 if (GET_CODE (x) == CONST)
402 return symbolic_expression_p (XEXP (x, 0));
405 return symbolic_expression_p (XEXP (x, 0));
407 if (ARITHMETIC_P (x))
408 return (symbolic_expression_p (XEXP (x, 0))
409 || symbolic_expression_p (XEXP (x, 1)));
414 /* Choose the section to use for the constant rtx expression X that has
417 th_select_rtx_section (enum machine_mode mode, rtx x,
418 unsigned HOST_WIDE_INT align)
420 if (GET_MODE_SIZE (mode) <= SCORE_SDATA_MAX)
421 return get_named_section (0, ".sdata", 0);
422 else if (flag_pic && symbolic_expression_p (x))
423 return get_named_section (0, ".data.rel.ro", 3);
425 return mergeable_constant_section (mode, align, 0);
428 /* Implement TARGET_IN_SMALL_DATA_P. */
430 th_in_small_data_p (const_tree decl)
434 if (TREE_CODE (decl) == STRING_CST
435 || TREE_CODE (decl) == FUNCTION_DECL)
438 if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl) != 0)
441 name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
442 if (strcmp (name, ".sdata") != 0
443 && strcmp (name, ".sbss") != 0)
445 if (!DECL_EXTERNAL (decl))
448 size = int_size_in_bytes (TREE_TYPE (decl));
449 return (size > 0 && size <= SCORE_SDATA_MAX);
452 /* Implement TARGET_ASM_FILE_START. */
454 th_asm_file_start (void)
456 default_file_start ();
457 fprintf (asm_out_file, ASM_COMMENT_START
458 "GCC for S+core %s \n", SCORE_GCC_VERSION);
461 fprintf (asm_out_file, "\t.set pic\n");
464 /* Implement TARGET_ASM_FILE_END. When using assembler macros, emit
465 .externs for any small-data variables that turned out to be external. */
466 struct extern_list *extern_head = 0;
469 th_asm_file_end (void)
472 struct extern_list *p;
475 fputs ("\n", asm_out_file);
476 for (p = extern_head; p != 0; p = p->next)
478 name_tree = get_identifier (p->name);
479 if (!TREE_ASM_WRITTEN (name_tree)
480 && TREE_SYMBOL_REFERENCED (name_tree))
482 TREE_ASM_WRITTEN (name_tree) = 1;
483 fputs ("\t.extern\t", asm_out_file);
484 assemble_name (asm_out_file, p->name);
485 fprintf (asm_out_file, ", %d\n", p->size);
491 static unsigned int sdata_max;
494 score_sdata_max (void)
499 /* default 0 = NO_REGS */
500 enum reg_class score_char_to_class[256];
502 /* Implement OVERRIDE_OPTIONS macro. */
504 score_override_options (void)
508 sdata_max = g_switch_set ? g_switch_value : DEFAULT_SDATA_MAX;
512 if (g_switch_set && (g_switch_value != 0))
513 warning (0, "-fPIC and -G are incompatible");
516 score_char_to_class['d'] = G32_REGS;
517 score_char_to_class['e'] = G16_REGS;
518 score_char_to_class['t'] = T32_REGS;
520 score_char_to_class['h'] = HI_REG;
521 score_char_to_class['l'] = LO_REG;
522 score_char_to_class['x'] = CE_REGS;
524 score_char_to_class['q'] = CN_REG;
525 score_char_to_class['y'] = LC_REG;
526 score_char_to_class['z'] = SC_REG;
527 score_char_to_class['a'] = SP_REGS;
529 score_char_to_class['c'] = CR_REGS;
531 score_char_to_class['b'] = CP1_REGS;
532 score_char_to_class['f'] = CP2_REGS;
533 score_char_to_class['i'] = CP3_REGS;
534 score_char_to_class['j'] = CPA_REGS;
537 /* Implement REGNO_REG_CLASS macro. */
539 score_reg_class (int regno)
542 gcc_assert (regno >= 0 && regno < FIRST_PSEUDO_REGISTER);
544 if (regno == FRAME_POINTER_REGNUM
545 || regno == ARG_POINTER_REGNUM)
548 for (c = 0; c < N_REG_CLASSES; c++)
549 if (TEST_HARD_REG_BIT (reg_class_contents[c], regno))
555 /* Implement PREFERRED_RELOAD_CLASS macro. */
557 score_preferred_reload_class (rtx x ATTRIBUTE_UNUSED, enum reg_class class)
559 if (reg_class_subset_p (G16_REGS, class))
561 if (reg_class_subset_p (G32_REGS, class))
566 /* Implement SECONDARY_INPUT_RELOAD_CLASS
567 and SECONDARY_OUTPUT_RELOAD_CLASS macro. */
569 score_secondary_reload_class (enum reg_class class,
570 enum machine_mode mode ATTRIBUTE_UNUSED,
574 if (GET_CODE (x) == REG || GET_CODE(x) == SUBREG)
575 regno = true_regnum (x);
577 if (!GR_REG_CLASS_P (class))
578 return GP_REG_P (regno) ? NO_REGS : G32_REGS;
582 /* Implement CONST_OK_FOR_LETTER_P macro. */
591 score_const_ok_for_letter_p (HOST_WIDE_INT value, char c)
595 case 'I': return ((value & 0xffff) == 0);
596 case 'J': return IMM_IN_RANGE (value, 5, 0);
597 case 'K': return IMM_IN_RANGE (value, 16, 0);
598 case 'L': return IMM_IN_RANGE (value, 16, 1);
599 case 'M': return IMM_IN_RANGE (value, 14, 0);
600 case 'N': return IMM_IN_RANGE (value, 14, 1);
605 /* Implement EXTRA_CONSTRAINT macro. */
608 score_extra_constraint (rtx op, char c)
613 return GET_CODE (op) == SYMBOL_REF;
619 /* Return truth value on whether or not a given hard register
620 can support a given mode. */
622 score_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
624 int size = GET_MODE_SIZE (mode);
625 enum mode_class class = GET_MODE_CLASS (mode);
627 if (class == MODE_CC)
628 return regno == CC_REGNUM;
629 else if (regno == FRAME_POINTER_REGNUM
630 || regno == ARG_POINTER_REGNUM)
631 return class == MODE_INT;
632 else if (GP_REG_P (regno))
633 /* ((regno <= (GP_REG_LAST- HARD_REGNO_NREGS (dummy, mode)) + 1) */
634 return !(regno & 1) || (size <= UNITS_PER_WORD);
635 else if (CE_REG_P (regno))
636 return (class == MODE_INT
637 && ((size <= UNITS_PER_WORD)
638 || (regno == CE_REG_FIRST && size == 2 * UNITS_PER_WORD)));
640 return (class == MODE_INT) && (size <= UNITS_PER_WORD);
643 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
644 pointer or argument pointer. TO is either the stack pointer or
645 hard frame pointer. */
647 score_initial_elimination_offset (int from,
648 int to ATTRIBUTE_UNUSED)
650 struct score_frame_info *f = mda_compute_frame_size (get_frame_size ());
653 case ARG_POINTER_REGNUM:
654 return f->total_size;
655 case FRAME_POINTER_REGNUM:
662 /* Argument support functions. */
664 /* Initialize CUMULATIVE_ARGS for a function. */
666 score_init_cumulative_args (CUMULATIVE_ARGS *cum,
667 tree fntype ATTRIBUTE_UNUSED,
668 rtx libname ATTRIBUTE_UNUSED)
670 memset (cum, 0, sizeof (CUMULATIVE_ARGS));
673 /* Implement FUNCTION_ARG_ADVANCE macro. */
675 score_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
676 tree type, int named)
678 struct score_arg_info info;
679 classify_arg (cum, mode, type, named, &info);
680 cum->num_gprs = info.reg_offset + info.reg_words;
681 if (info.stack_words > 0)
682 cum->stack_words = info.stack_offset + info.stack_words;
686 /* Implement TARGET_ARG_PARTIAL_BYTES macro. */
688 score_arg_partial_bytes (CUMULATIVE_ARGS *cum,
689 enum machine_mode mode, tree type, bool named)
691 struct score_arg_info info;
692 classify_arg (cum, mode, type, named, &info);
693 return info.stack_words > 0 ? info.reg_words * UNITS_PER_WORD : 0;
696 /* Implement FUNCTION_ARG macro. */
698 score_function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
699 tree type, int named)
701 struct score_arg_info info;
703 if (mode == VOIDmode || !named)
706 classify_arg (cum, mode, type, named, &info);
708 if (info.reg_offset == ARG_REG_NUM)
711 if (!info.stack_words)
712 return gen_rtx_REG (mode, ARG_REG_FIRST + info.reg_offset);
715 rtx ret = gen_rtx_PARALLEL (mode, rtvec_alloc (info.reg_words));
716 unsigned int i, part_offset = 0;
717 for (i = 0; i < info.reg_words; i++)
720 reg = gen_rtx_REG (SImode, ARG_REG_FIRST + info.reg_offset + i);
721 XVECEXP (ret, 0, i) = gen_rtx_EXPR_LIST (SImode, reg,
722 GEN_INT (part_offset));
723 part_offset += UNITS_PER_WORD;
729 /* Implement FUNCTION_VALUE and LIBCALL_VALUE. For normal calls,
730 VALTYPE is the return type and MODE is VOIDmode. For libcalls,
731 VALTYPE is null and MODE is the mode of the return value. */
733 score_function_value (const_tree valtype, const_tree func ATTRIBUTE_UNUSED,
734 enum machine_mode mode)
739 mode = TYPE_MODE (valtype);
740 unsignedp = TYPE_UNSIGNED (valtype);
741 mode = promote_mode (valtype, mode, &unsignedp, 1);
743 return gen_rtx_REG (mode, RT_REGNUM);
746 /* Implement INITIALIZE_TRAMPOLINE macro. */
748 score_initialize_trampoline (rtx ADDR, rtx FUNC, rtx CHAIN)
750 #define FFCACHE "_flush_cache"
751 #define CODE_SIZE (TRAMPOLINE_INSNS * UNITS_PER_WORD)
755 pfunc = plus_constant (ADDR, CODE_SIZE);
756 pchain = plus_constant (ADDR, CODE_SIZE + GET_MODE_SIZE (SImode));
758 emit_move_insn (gen_rtx_MEM (SImode, pfunc), FUNC);
759 emit_move_insn (gen_rtx_MEM (SImode, pchain), CHAIN);
760 emit_library_call (gen_rtx_SYMBOL_REF (Pmode, FFCACHE),
763 GEN_INT (TRAMPOLINE_SIZE), SImode);
768 /* This function is used to implement REG_MODE_OK_FOR_BASE_P macro. */
770 score_regno_mode_ok_for_base_p (int regno, int strict)
772 if (regno >= FIRST_PSEUDO_REGISTER)
776 regno = reg_renumber[regno];
778 if (regno == ARG_POINTER_REGNUM
779 || regno == FRAME_POINTER_REGNUM)
781 return GP_REG_P (regno);
784 /* Implement GO_IF_LEGITIMATE_ADDRESS macro. */
786 score_address_p (enum machine_mode mode, rtx x, int strict)
788 struct score_address_info addr;
790 return mda_classify_address (&addr, mode, x, strict);
793 /* Copy VALUE to a register and return that register. If new psuedos
794 are allowed, copy it into a new register, otherwise use DEST. */
796 score_force_temporary (rtx dest, rtx value)
798 if (can_create_pseudo_p ())
799 return force_reg (Pmode, value);
802 emit_move_insn (copy_rtx (dest), value);
807 /* Return a LO_SUM expression for ADDR. TEMP is as for score_force_temporary
808 and is used to load the high part into a register. */
810 score_split_symbol (rtx temp, rtx addr)
812 rtx high = score_force_temporary (temp,
813 gen_rtx_HIGH (Pmode, copy_rtx (addr)));
814 return gen_rtx_LO_SUM (Pmode, high, addr);
817 /* This function is used to implement LEGITIMIZE_ADDRESS. If *XLOC can
818 be legitimized in a way that the generic machinery might not expect,
819 put the new address in *XLOC and return true. */
821 score_legitimize_address (rtx *xloc)
823 enum score_symbol_type symbol_type;
825 if (mda_symbolic_constant_p (*xloc, &symbol_type)
826 && symbol_type == SYMBOL_GENERAL)
828 *xloc = score_split_symbol (0, *xloc);
832 if (GET_CODE (*xloc) == PLUS
833 && GET_CODE (XEXP (*xloc, 1)) == CONST_INT)
835 rtx reg = XEXP (*xloc, 0);
836 if (!mda_valid_base_register_p (reg, 0))
837 reg = copy_to_mode_reg (Pmode, reg);
838 *xloc = score_add_offset (NULL, reg, INTVAL (XEXP (*xloc, 1)));
844 /* Return a number assessing the cost of moving a register in class
847 score_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
848 enum reg_class from, enum reg_class to)
850 if (GR_REG_CLASS_P (from))
852 if (GR_REG_CLASS_P (to))
854 else if (SP_REG_CLASS_P (to))
856 else if (CP_REG_CLASS_P (to))
858 else if (CE_REG_CLASS_P (to))
861 if (GR_REG_CLASS_P (to))
863 if (GR_REG_CLASS_P (from))
865 else if (SP_REG_CLASS_P (from))
867 else if (CP_REG_CLASS_P (from))
869 else if (CE_REG_CLASS_P (from))
875 /* Return the number of instructions needed to load a symbol of the
876 given type into a register. */
878 score_symbol_insns (enum score_symbol_type type)
885 case SYMBOL_SMALL_DATA:
892 /* Return the number of instructions needed to load or store a value
893 of mode MODE at X. Return 0 if X isn't valid for MODE. */
895 score_address_insns (rtx x, enum machine_mode mode)
897 struct score_address_info addr;
903 factor = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
905 if (mda_classify_address (&addr, mode, x, false))
913 return factor * score_symbol_insns (addr.symbol_type);
918 /* Implement TARGET_RTX_COSTS macro. */
920 score_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer_code,
923 enum machine_mode mode = GET_MODE (x);
928 if (outer_code == SET)
930 if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
931 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L'))
932 *total = COSTS_N_INSNS (1);
934 *total = COSTS_N_INSNS (2);
936 else if (outer_code == PLUS || outer_code == MINUS)
938 if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'N'))
940 else if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
941 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L'))
944 *total = COSTS_N_INSNS (2);
946 else if (outer_code == AND || outer_code == IOR)
948 if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'M'))
950 else if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
951 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'K'))
954 *total = COSTS_N_INSNS (2);
966 *total = COSTS_N_INSNS (2);
971 /* If the address is legitimate, return the number of
972 instructions it needs, otherwise use the default handling. */
973 int n = score_address_insns (XEXP (x, 0), GET_MODE (x));
976 *total = COSTS_N_INSNS (n + 1);
983 *total = COSTS_N_INSNS (6);
987 *total = COSTS_N_INSNS (1);
995 *total = COSTS_N_INSNS (2);
1005 *total = COSTS_N_INSNS ((GET_CODE (XEXP (x, 1)) == CONST_INT)
1012 *total = COSTS_N_INSNS (4);
1019 *total = COSTS_N_INSNS (4);
1022 *total = COSTS_N_INSNS (1);
1028 *total = COSTS_N_INSNS (4);
1034 *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (12);
1041 *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (33);
1046 switch (GET_MODE (XEXP (x, 0)))
1050 if (GET_CODE (XEXP (x, 0)) == MEM)
1052 *total = COSTS_N_INSNS (2);
1054 if (!TARGET_LITTLE_ENDIAN &&
1055 side_effects_p (XEXP (XEXP (x, 0), 0)))
1059 *total = COSTS_N_INSNS (1);
1063 *total = COSTS_N_INSNS (1);
1073 /* Implement TARGET_ADDRESS_COST macro. */
1075 score_address_cost (rtx addr)
1077 return score_address_insns (addr, SImode);
1080 /* Implement ASM_OUTPUT_EXTERNAL macro. */
1082 score_output_external (FILE *file ATTRIBUTE_UNUSED,
1083 tree decl, const char *name)
1085 register struct extern_list *p;
1087 if (th_in_small_data_p (decl))
1089 p = (struct extern_list *) ggc_alloc (sizeof (struct extern_list));
1090 p->next = extern_head;
1092 p->size = int_size_in_bytes (TREE_TYPE (decl));
1098 /* Output format asm string. */
1100 score_declare_object (FILE *stream, const char *name,
1101 const char *directive, const char *fmt, ...)
1104 fputs (directive, stream);
1105 assemble_name (stream, name);
1107 vfprintf (stream, fmt, ap);
1111 /* Implement RETURN_ADDR_RTX. Note, we do not support moving
1112 back to a previous frame. */
1114 score_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
1118 return get_hard_reg_initial_val (Pmode, RA_REGNUM);
1121 /* Implement PRINT_OPERAND macro. */
1122 /* Score-specific operand codes:
1123 '[' print .set nor1 directive
1124 ']' print .set r1 directive
1125 'U' print hi part of a CONST_INT rtx
1128 'D' print SFmode const double
1129 'S' selectively print "!" if operand is 15bit instruction accessible
1130 'V' print "v!" if operand is 15bit instruction accessible, or "lfh!"
1131 'L' low part of DImode reg operand
1132 'H' high part of DImode reg operand
1133 'C' print part of opcode for a branch condition. */
1135 score_print_operand (FILE *file, rtx op, int c)
1137 enum rtx_code code = -1;
1138 if (!PRINT_OPERAND_PUNCT_VALID_P (c))
1139 code = GET_CODE (op);
1143 fprintf (file, ".set r1\n");
1147 fprintf (file, "\n\t.set nor1");
1151 gcc_assert (code == CONST_INT);
1152 fprintf (file, HOST_WIDE_INT_PRINT_HEX,
1153 (INTVAL (op) >> 16) & 0xffff);
1157 if (GET_CODE (op) == CONST_DOUBLE)
1159 rtx temp = gen_lowpart (SImode, op);
1160 gcc_assert (GET_MODE (op) == SFmode);
1161 fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (temp) & 0xffffffff);
1164 output_addr_const (file, op);
1168 gcc_assert (code == REG);
1169 if (G16_REG_P (REGNO (op)))
1170 fprintf (file, "!");
1174 gcc_assert (code == REG);
1175 fprintf (file, G16_REG_P (REGNO (op)) ? "v!" : "lfh!");
1179 enum machine_mode mode = GET_MODE (XEXP (op, 0));
1183 case EQ: fputs ("eq", file); break;
1184 case NE: fputs ("ne", file); break;
1185 case GT: fputs ("gt", file); break;
1186 case GE: fputs (mode != CCmode ? "pl" : "ge", file); break;
1187 case LT: fputs (mode != CCmode ? "mi" : "lt", file); break;
1188 case LE: fputs ("le", file); break;
1189 case GTU: fputs ("gtu", file); break;
1190 case GEU: fputs ("cs", file); break;
1191 case LTU: fputs ("cc", file); break;
1192 case LEU: fputs ("leu", file); break;
1194 output_operand_lossage ("invalid operand for code: '%c'", code);
1199 unsigned HOST_WIDE_INT i;
1200 unsigned HOST_WIDE_INT pow2mask = 1;
1201 unsigned HOST_WIDE_INT val;
1204 for (i = 0; i < 32; i++)
1206 if (val == pow2mask)
1210 gcc_assert (i < 32);
1211 fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
1215 unsigned HOST_WIDE_INT i;
1216 unsigned HOST_WIDE_INT pow2mask = 1;
1217 unsigned HOST_WIDE_INT val;
1220 for (i = 0; i < 32; i++)
1222 if (val == pow2mask)
1226 gcc_assert (i < 32);
1227 fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
1229 else if (code == REG)
1231 int regnum = REGNO (op);
1232 if ((c == 'H' && !WORDS_BIG_ENDIAN)
1233 || (c == 'L' && WORDS_BIG_ENDIAN))
1235 fprintf (file, "%s", reg_names[regnum]);
1242 score_print_operand_address (file, op);
1245 output_addr_const (file, op);
1250 /* Implement PRINT_OPERAND_ADDRESS macro. */
1252 score_print_operand_address (FILE *file, rtx x)
1254 struct score_address_info addr;
1255 enum rtx_code code = GET_CODE (x);
1256 enum machine_mode mode = GET_MODE (x);
1261 if (mda_classify_address (&addr, mode, x, true))
1270 fprintf (file, "[%s,-%ld]+", reg_names[REGNO (addr.reg)],
1271 INTVAL (addr.offset));
1274 fprintf (file, "[%s]+,-%ld", reg_names[REGNO (addr.reg)],
1275 INTVAL (addr.offset));
1278 fprintf (file, "[%s, %ld]+", reg_names[REGNO (addr.reg)],
1279 INTVAL (addr.offset));
1282 fprintf (file, "[%s]+, %ld", reg_names[REGNO (addr.reg)],
1283 INTVAL (addr.offset));
1286 if (INTVAL(addr.offset) == 0)
1287 fprintf(file, "[%s]", reg_names[REGNO (addr.reg)]);
1289 fprintf(file, "[%s, %ld]", reg_names[REGNO (addr.reg)],
1290 INTVAL(addr.offset));
1297 output_addr_const (file, x);
1301 print_rtl (stderr, x);
1305 /* Implement SELECT_CC_MODE macro. */
1307 score_select_cc_mode (enum rtx_code op, rtx x, rtx y)
1309 if ((op == EQ || op == NE || op == LT || op == GE)
1311 && GET_MODE (x) == SImode)
1313 switch (GET_CODE (x))
1331 return (op == LT || op == GE) ? CC_Nmode : CCmode;
1338 if ((op == EQ || op == NE)
1339 && (GET_CODE (y) == NEG)
1340 && register_operand (XEXP (y, 0), SImode)
1341 && register_operand (x, SImode))
1349 struct gcc_target targetm = TARGET_INITIALIZER;