1 /* Output routines for Sunplus S+CORE processor
2 Copyright (C) 2005 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 2, 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 COPYING. If not, write to
19 the Free Software Foundation, 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA. */
24 #include "coretypes.h"
29 #include "hard-reg-set.h"
31 #include "insn-config.h"
32 #include "conditions.h"
33 #include "insn-attr.h"
49 #include "target-def.h"
50 #include "integrate.h"
51 #include "langhooks.h"
52 #include "cfglayout.h"
53 #include "score-mdaux.h"
55 #define GR_REG_CLASS_P(C) ((C) == G16_REGS || (C) == G32_REGS)
56 #define SP_REG_CLASS_P(C) \
57 ((C) == CN_REG || (C) == LC_REG || (C) == SC_REG || (C) == SP_REGS)
58 #define CP_REG_CLASS_P(C) \
59 ((C) == CP1_REGS || (C) == CP2_REGS || (C) == CP3_REGS || (C) == CPA_REGS)
60 #define CE_REG_CLASS_P(C) \
61 ((C) == HI_REG || (C) == LO_REG || (C) == CE_REGS)
63 static int score_arg_partial_bytes (const CUMULATIVE_ARGS *,
64 enum machine_mode, tree, int);
66 static int score_symbol_insns (enum score_symbol_type);
68 static int score_address_insns (rtx, enum machine_mode);
70 static bool score_rtx_costs (rtx, int, int, int *);
72 #undef TARGET_ASM_FILE_START
73 #define TARGET_ASM_FILE_START th_asm_file_start
75 #undef TARGET_ASM_FILE_END
76 #define TARGET_ASM_FILE_END th_asm_file_end
78 #undef TARGET_ASM_FUNCTION_PROLOGUE
79 #define TARGET_ASM_FUNCTION_PROLOGUE th_function_prologue
81 #undef TARGET_ASM_FUNCTION_EPILOGUE
82 #define TARGET_ASM_FUNCTION_EPILOGUE th_function_epilogue
84 #undef TARGET_SCHED_ISSUE_RATE
85 #define TARGET_SCHED_ISSUE_RATE th_issue_rate
87 #undef TARGET_ASM_SELECT_RTX_SECTION
88 #define TARGET_ASM_SELECT_RTX_SECTION th_select_rtx_section
90 #undef TARGET_IN_SMALL_DATA_P
91 #define TARGET_IN_SMALL_DATA_P th_in_small_data_p
93 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
94 #define TARGET_FUNCTION_OK_FOR_SIBCALL th_function_ok_for_sibcall
96 #undef TARGET_STRICT_ARGUMENT_NAMING
97 #define TARGET_STRICT_ARGUMENT_NAMING th_strict_argument_naming
99 #undef TARGET_ASM_OUTPUT_MI_THUNK
100 #define TARGET_ASM_OUTPUT_MI_THUNK th_output_mi_thunk
102 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
103 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_tree_hwi_hwi_tree_true
105 #undef TARGET_PROMOTE_FUNCTION_ARGS
106 #define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true
108 #undef TARGET_PROMOTE_FUNCTION_RETURN
109 #define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true
111 #undef TARGET_PROMOTE_PROTOTYPES
112 #define TARGET_PROMOTE_PROTOTYPES hook_bool_tree_true
114 #undef TARGET_MUST_PASS_IN_STACK
115 #define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size
117 #undef TARGET_ARG_PARTIAL_BYTES
118 #define TARGET_ARG_PARTIAL_BYTES score_arg_partial_bytes
120 #undef TARGET_PASS_BY_REFERENCE
121 #define TARGET_PASS_BY_REFERENCE score_pass_by_reference
123 #undef TARGET_RETURN_IN_MEMORY
124 #define TARGET_RETURN_IN_MEMORY score_return_in_memory
126 #undef TARGET_RTX_COSTS
127 #define TARGET_RTX_COSTS score_rtx_costs
129 /* Implement TARGET_RETURN_IN_MEMORY. In S+core,
130 small structures are returned in a register.
131 Objects with varying size must still be returned in memory. */
133 score_return_in_memory (tree type, tree fndecl ATTRIBUTE_UNUSED)
135 return ((TYPE_MODE (type) == BLKmode)
136 || (int_size_in_bytes (type) > 2 * UNITS_PER_WORD)
137 || (int_size_in_bytes (type) == -1));
140 /* Return nonzero when an argument must be passed by reference. */
142 score_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
143 enum machine_mode mode, tree type,
144 bool named ATTRIBUTE_UNUSED)
146 /* If we have a variable-sized parameter, we have no choice. */
147 return targetm.calls.must_pass_in_stack (mode, type);
150 /* Return a legitimate address for REG + OFFSET. */
152 score_add_offset (rtx temp, rtx reg, HOST_WIDE_INT offset)
154 if (!CONST_OK_FOR_LETTER_P (offset, 'O'))
156 reg = expand_simple_binop (GET_MODE (reg), PLUS,
157 gen_int_mode (offset & 0xffffc000,
159 reg, NULL, 0, OPTAB_WIDEN);
163 return plus_constant (reg, offset);
166 /* Implement TARGET_ASM_OUTPUT_MI_THUNK. Generate rtl rather than asm text
167 in order to avoid duplicating too much logic from elsewhere. */
169 th_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
170 HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
173 rtx this, temp1, temp2, insn, fnaddr;
175 /* Pretend to be a post-reload pass while generating rtl. */
177 reload_completed = 1;
178 reset_block_changes ();
180 /* We need two temporary registers in some cases. */
181 temp1 = gen_rtx_REG (Pmode, 8);
182 temp2 = gen_rtx_REG (Pmode, 9);
184 /* Find out which register contains the "this" pointer. */
185 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
186 this = gen_rtx_REG (Pmode, ARG_REG_FIRST + 1);
188 this = gen_rtx_REG (Pmode, ARG_REG_FIRST);
190 /* Add DELTA to THIS. */
193 rtx offset = GEN_INT (delta);
194 if (!CONST_OK_FOR_LETTER_P (delta, 'L'))
196 emit_move_insn (temp1, offset);
199 emit_insn (gen_add3_insn (this, this, offset));
202 /* If needed, add *(*THIS + VCALL_OFFSET) to THIS. */
203 if (vcall_offset != 0)
207 /* Set TEMP1 to *THIS. */
208 emit_move_insn (temp1, gen_rtx_MEM (Pmode, this));
210 /* Set ADDR to a legitimate address for *THIS + VCALL_OFFSET. */
211 addr = score_add_offset (temp2, temp1, vcall_offset);
213 /* Load the offset and add it to THIS. */
214 emit_move_insn (temp1, gen_rtx_MEM (Pmode, addr));
215 emit_insn (gen_add3_insn (this, this, temp1));
218 /* Jump to the target function. */
219 fnaddr = XEXP (DECL_RTL (function), 0);
220 insn = emit_call_insn (gen_sibcall_internal (fnaddr, const0_rtx));
221 SIBLING_CALL_P (insn) = 1;
223 /* Run just enough of rest_of_compilation. This sequence was
224 "borrowed" from alpha.c. */
226 insn_locators_initialize ();
227 split_all_insns_noflow ();
228 shorten_branches (insn);
229 final_start_function (insn, file, 1);
230 final (insn, file, 1);
231 final_end_function ();
233 /* Clean up the vars set above. Note that final_end_function resets
234 the global pointer for us. */
235 reload_completed = 0;
239 /* Implement TARGET_STRICT_ARGUMENT_NAMING. */
241 th_strict_argument_naming (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED)
246 /* Implement TARGET_FUNCTION_OK_FOR_SIBCALL. */
248 th_function_ok_for_sibcall (ATTRIBUTE_UNUSED tree decl,
249 ATTRIBUTE_UNUSED tree exp)
254 struct score_arg_info
256 /* The argument's size, in bytes. */
257 unsigned int num_bytes;
259 /* The number of words passed in registers, rounded up. */
260 unsigned int reg_words;
262 /* The offset of the first register from GP_ARG_FIRST or FP_ARG_FIRST,
263 or ARG_REG_NUM if the argument is passed entirely on the stack. */
264 unsigned int reg_offset;
266 /* The number of words that must be passed on the stack, rounded up. */
267 unsigned int stack_words;
269 /* The offset from the start of the stack overflow area of the argument's
270 first stack word. Only meaningful when STACK_WORDS is nonzero. */
271 unsigned int stack_offset;
274 /* Fill INFO with information about a single argument. CUM is the
275 cumulative state for earlier arguments. MODE is the mode of this
276 argument and TYPE is its type (if known). NAMED is true if this
277 is a named (fixed) argument rather than a variable one. */
279 classify_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
280 tree type, int named, struct score_arg_info *info)
283 unsigned int num_words, max_regs;
286 if (GET_MODE_CLASS (mode) == MODE_INT
287 || GET_MODE_CLASS (mode) == MODE_FLOAT)
288 even_reg_p = (GET_MODE_SIZE (mode) > UNITS_PER_WORD);
290 if (type != NULL_TREE && TYPE_ALIGN (type) > BITS_PER_WORD && named)
293 if (TARGET_MUST_PASS_IN_STACK (mode, type))
294 info->reg_offset = ARG_REG_NUM;
297 info->reg_offset = cum->num_gprs;
299 info->reg_offset += info->reg_offset & 1;
303 info->num_bytes = int_size_in_bytes (type);
305 info->num_bytes = GET_MODE_SIZE (mode);
307 num_words = (info->num_bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
308 max_regs = ARG_REG_NUM - info->reg_offset;
310 /* Partition the argument between registers and stack. */
311 info->reg_words = MIN (num_words, max_regs);
312 info->stack_words = num_words - info->reg_words;
314 /* The alignment applied to registers is also applied to stack arguments. */
315 if (info->stack_words)
317 info->stack_offset = cum->stack_words;
319 info->stack_offset += info->stack_offset & 1;
323 /* Set up the stack and frame (if desired) for the function. */
325 th_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
328 struct score_frame_info *f = mda_cached_frame ();
329 HOST_WIDE_INT tsize = f->total_size;
331 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
332 if (!flag_inhibit_size_directive)
334 fputs ("\t.ent\t", file);
335 assemble_name (file, fnname);
338 assemble_name (file, fnname);
341 if (!flag_inhibit_size_directive)
344 "\t.frame\t%s," HOST_WIDE_INT_PRINT_DEC ",%s, %d\t\t"
345 "# vars= " HOST_WIDE_INT_PRINT_DEC ", regs= %d"
346 ", args= " HOST_WIDE_INT_PRINT_DEC
347 ", gp= " HOST_WIDE_INT_PRINT_DEC "\n",
348 (reg_names[(frame_pointer_needed)
349 ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM]),
351 reg_names[RA_REGNUM],
352 current_function_is_leaf ? 1 : 0,
358 fprintf(file, "\t.mask\t0x%08x," HOST_WIDE_INT_PRINT_DEC "\n",
360 (f->gp_sp_offset - f->total_size));
364 /* Do any necessary cleanup after a function to restore stack, frame,
367 th_function_epilogue (FILE *file,
368 HOST_WIDE_INT size ATTRIBUTE_UNUSED)
370 if (!flag_inhibit_size_directive)
373 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
374 fputs ("\t.end\t", file);
375 assemble_name (file, fnname);
380 /* Implement TARGET_SCHED_ISSUE_RATE. */
387 /* Returns true if X contains a SYMBOL_REF. */
389 symbolic_expression_p (rtx x)
391 if (GET_CODE (x) == SYMBOL_REF)
394 if (GET_CODE (x) == CONST)
395 return symbolic_expression_p (XEXP (x, 0));
398 return symbolic_expression_p (XEXP (x, 0));
400 if (ARITHMETIC_P (x))
401 return (symbolic_expression_p (XEXP (x, 0))
402 || symbolic_expression_p (XEXP (x, 1)));
407 /* Choose the section to use for the constant rtx expression X that has
410 th_select_rtx_section (enum machine_mode mode, rtx x,
411 unsigned HOST_WIDE_INT align)
413 if (GET_MODE_SIZE (mode) <= SCORE_SDATA_MAX)
414 return get_named_section (0, ".sdata", 0);
415 else if (flag_pic && symbolic_expression_p (x))
416 return get_named_section (0, ".data.rel.ro", 3);
418 return mergeable_constant_section (mode, align, 0);
421 /* Implement TARGET_IN_SMALL_DATA_P. */
423 th_in_small_data_p (tree decl)
427 if (TREE_CODE (decl) == STRING_CST
428 || TREE_CODE (decl) == FUNCTION_DECL)
431 if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl) != 0)
434 name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
435 if (strcmp (name, ".sdata") != 0
436 && strcmp (name, ".sbss") != 0)
438 if (!DECL_EXTERNAL (decl))
441 size = int_size_in_bytes (TREE_TYPE (decl));
442 return (size > 0 && size <= SCORE_SDATA_MAX);
445 /* Implement TARGET_ASM_FILE_START. */
447 th_asm_file_start (void)
449 default_file_start ();
450 fprintf (asm_out_file, ASM_COMMENT_START
451 "GCC for S+core %s \n", SCORE_GCC_VERSION);
454 fprintf (asm_out_file, "\t.set pic\n");
457 /* Implement TARGET_ASM_FILE_END. When using assembler macros, emit
458 .externs for any small-data variables that turned out to be external. */
459 struct extern_list *extern_head = 0;
462 th_asm_file_end (void)
465 struct extern_list *p;
468 fputs ("\n", asm_out_file);
469 for (p = extern_head; p != 0; p = p->next)
471 name_tree = get_identifier (p->name);
472 if (!TREE_ASM_WRITTEN (name_tree)
473 && TREE_SYMBOL_REFERENCED (name_tree))
475 TREE_ASM_WRITTEN (name_tree) = 1;
476 fputs ("\t.extern\t", asm_out_file);
477 assemble_name (asm_out_file, p->name);
478 fprintf (asm_out_file, ", %d\n", p->size);
484 static unsigned int sdata_max;
487 score_sdata_max (void)
492 /* default 0 = NO_REGS */
493 enum reg_class score_char_to_class[256];
495 /* Implement OVERRIDE_OPTIONS macro. */
497 score_override_options (void)
500 sdata_max = g_switch_set ? g_switch_value : DEFAULT_SDATA_MAX;
505 warning (0, "-fPIC and -G are incompatible");
508 score_char_to_class['d'] = G32_REGS;
509 score_char_to_class['e'] = G16_REGS;
510 score_char_to_class['t'] = T32_REGS;
512 score_char_to_class['h'] = HI_REG;
513 score_char_to_class['l'] = LO_REG;
514 score_char_to_class['x'] = CE_REGS;
516 score_char_to_class['q'] = CN_REG;
517 score_char_to_class['y'] = LC_REG;
518 score_char_to_class['z'] = SC_REG;
519 score_char_to_class['a'] = SP_REGS;
521 score_char_to_class['c'] = CR_REGS;
523 score_char_to_class['b'] = CP1_REGS;
524 score_char_to_class['f'] = CP2_REGS;
525 score_char_to_class['i'] = CP3_REGS;
526 score_char_to_class['j'] = CPA_REGS;
529 /* Implement REGNO_REG_CLASS macro. */
531 score_reg_class (int regno)
534 gcc_assert (regno >= 0 && regno < FIRST_PSEUDO_REGISTER);
536 if (regno == FRAME_POINTER_REGNUM
537 || regno == ARG_POINTER_REGNUM)
540 for (c = 0 ; c < N_REG_CLASSES ; c++)
541 if (TEST_HARD_REG_BIT (reg_class_contents[c], regno))
547 /* Implement PREFERRED_RELOAD_CLASS macro. */
549 score_preferred_reload_class (rtx x ATTRIBUTE_UNUSED, enum reg_class class)
551 if (reg_class_subset_p (G32_REGS, class))
553 if (reg_class_subset_p (G16_REGS, class))
558 /* Implement SECONDARY_INPUT_RELOAD_CLASS
559 and SECONDARY_OUTPUT_RELOAD_CLASS macro. */
561 score_secondary_reload_class (enum reg_class class,
562 enum machine_mode mode ATTRIBUTE_UNUSED,
566 if (GET_CODE (x) == REG || GET_CODE(x) == SUBREG)
567 regno = true_regnum (x);
569 if (!GR_REG_CLASS_P (class))
570 return GP_REG_P (regno) ? NO_REGS : G32_REGS;
574 /* Implement CONST_OK_FOR_LETTER_P macro. */
583 P IMM12s (rix-form) / IMM10s(cop-form) << 2 */
585 score_const_ok_for_letter_p (int value, char c)
589 case 'I': return IMM_IN_RANGE (value, 8, 0);
590 case 'J': return IMM_IN_RANGE (value, 5, 0);
591 case 'K': return IMM_IN_RANGE (value, 16, 0);
592 case 'L': return IMM_IN_RANGE (value, 16, 1);
593 case 'M': return IMM_IN_RANGE (value, 14, 0);
594 case 'N': return IMM_IN_RANGE (value, 14, 1);
595 case 'O': return IMM_IN_RANGE (value, 15, 1);
596 case 'P': return IMM_IN_RANGE (value, 12, 1);
601 /* Implement EXTRA_CONSTRAINT macro. */
605 score_extra_constraint (rtx op, char c)
610 return (GET_CODE (op) == CONST_INT && (INTVAL (op) & 0xffff) == 0);
612 return GET_CODE (op) == SYMBOL_REF;
618 /* Return truth value on whether or not a given hard register
619 can support a given mode. */
621 score_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
623 int size = GET_MODE_SIZE (mode);
624 enum mode_class class = GET_MODE_CLASS (mode);
626 if (class == MODE_CC)
627 return regno == CC_REGNUM;
628 else if (regno == FRAME_POINTER_REGNUM
629 || regno == ARG_POINTER_REGNUM)
630 return class == MODE_INT;
631 else if (GP_REG_P (regno))
632 /* ((regno <= (GP_REG_LAST- HARD_REGNO_NREGS (dummy, mode)) + 1) */
633 return !(regno & 1) || (size <= UNITS_PER_WORD);
634 else if (CE_REG_P (regno))
635 return (class == MODE_INT
636 && ((size <= UNITS_PER_WORD)
637 || (regno == CE_REG_FIRST && size == 2 * UNITS_PER_WORD)));
639 return (class == MODE_INT) && (size <= UNITS_PER_WORD);
642 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
643 pointer or argument pointer. TO is either the stack pointer or
644 hard frame pointer. */
646 score_initial_elimination_offset (int from,
647 int to ATTRIBUTE_UNUSED)
649 struct score_frame_info *f = mda_compute_frame_size (get_frame_size ());
652 case ARG_POINTER_REGNUM:
653 return f->total_size;
654 case FRAME_POINTER_REGNUM:
661 /* Argument support functions. */
663 /* Initialize CUMULATIVE_ARGS for a function. */
665 score_init_cumulative_args (CUMULATIVE_ARGS *cum,
666 tree fntype ATTRIBUTE_UNUSED,
667 rtx libname ATTRIBUTE_UNUSED)
669 memset (cum, 0, sizeof (CUMULATIVE_ARGS));
672 /* Implement FUNCTION_ARG_ADVANCE macro. */
674 score_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
675 tree type, int named)
677 struct score_arg_info info;
678 classify_arg (cum, mode, type, named, &info);
679 cum->num_gprs = info.reg_offset + info.reg_words;
680 if (info.stack_words > 0)
681 cum->stack_words = info.stack_offset + info.stack_words;
685 /* Implement TARGET_ARG_PARTIAL_BYTES macro. */
687 score_arg_partial_bytes (const CUMULATIVE_ARGS *cum,
688 enum machine_mode mode, tree type, int named)
690 struct score_arg_info info;
691 classify_arg (cum, mode, type, named, &info);
692 return info.stack_words > 0 ? info.reg_words * UNITS_PER_WORD : 0;
695 /* Implement FUNCTION_ARG macro. */
697 score_function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
698 tree type, int named)
700 struct score_arg_info info;
702 if (mode == VOIDmode || !named)
705 classify_arg (cum, mode, type, named, &info);
707 if (info.reg_offset == ARG_REG_NUM)
710 if (!info.stack_words)
711 return gen_rtx_REG (mode, ARG_REG_FIRST + info.reg_offset);
714 rtx ret = gen_rtx_PARALLEL (mode, rtvec_alloc (info.reg_words));
715 unsigned int i, part_offset = 0;
716 for (i = 0; i < info.reg_words; i++)
719 reg = gen_rtx_REG (SImode, ARG_REG_FIRST + info.reg_offset + i);
720 XVECEXP (ret, 0, i) = gen_rtx_EXPR_LIST (SImode, reg,
721 GEN_INT (part_offset));
722 part_offset += UNITS_PER_WORD;
728 /* Implement FUNCTION_VALUE and LIBCALL_VALUE. For normal calls,
729 VALTYPE is the return type and MODE is VOIDmode. For libcalls,
730 VALTYPE is null and MODE is the mode of the return value. */
732 score_function_value (tree valtype, tree func ATTRIBUTE_UNUSED,
733 enum machine_mode mode)
738 mode = TYPE_MODE (valtype);
739 unsignedp = TYPE_UNSIGNED (valtype);
740 mode = promote_mode (valtype, mode, &unsignedp, 1);
742 return gen_rtx_REG (mode, RT_REGNUM);
745 /* Implement INITIALIZE_TRAMPOLINE macro. */
747 score_initialize_trampoline (rtx ADDR, rtx FUNC, rtx CHAIN)
749 #define FFCACHE "_flush_cache"
750 #define CODE_SIZE (TRAMPOLINE_INSNS * UNITS_PER_WORD)
752 unsigned int tramp[TRAMPOLINE_INSNS] = {
753 0x8103bc56, /* mv r8, r3 */
754 0x9000bc05, /* bl 0x0x8 */
755 0xc1238000 | (CODE_SIZE - 8), /* lw r9, &func */
757 | (STATIC_CHAIN_REGNUM << 21)
758 | (CODE_SIZE - 4), /* lw static chain reg, &chain */
759 0x8068bc56, /* mv r3, r8 */
760 0x8009bc08, /* br r9 */
767 for (i = 0; i < TRAMPOLINE_INSNS; i++)
768 emit_move_insn (gen_rtx_MEM (ptr_mode, plus_constant (ADDR, i << 2)),
771 pfunc = plus_constant (ADDR, CODE_SIZE);
772 pchain = plus_constant (ADDR, CODE_SIZE + GET_MODE_SIZE (ptr_mode));
774 emit_move_insn (gen_rtx_MEM (ptr_mode, pfunc), FUNC);
775 emit_move_insn (gen_rtx_MEM (ptr_mode, pchain), CHAIN);
776 emit_library_call (gen_rtx_SYMBOL_REF (Pmode, FFCACHE),
779 GEN_INT (TRAMPOLINE_SIZE), SImode);
784 /* This function is used to implement REG_MODE_OK_FOR_BASE_P macro. */
786 score_regno_mode_ok_for_base_p (int regno, int strict)
788 if (regno >= FIRST_PSEUDO_REGISTER)
792 regno = reg_renumber[regno];
794 if (regno == ARG_POINTER_REGNUM
795 || regno == FRAME_POINTER_REGNUM)
797 return GP_REG_P (regno);
800 /* Implement GO_IF_LEGITIMATE_ADDRESS macro. */
802 score_address_p (enum machine_mode mode, rtx x, int strict)
804 struct score_address_info addr;
806 return mda_classify_address (&addr, mode, x, strict);
809 /* Copy VALUE to a register and return that register. If new psuedos
810 are allowed, copy it into a new register, otherwise use DEST. */
812 score_force_temporary (rtx dest, rtx value)
815 return force_reg (Pmode, value);
818 emit_move_insn (copy_rtx (dest), value);
823 /* Return a LO_SUM expression for ADDR. TEMP is as for score_force_temporary
824 and is used to load the high part into a register. */
826 score_split_symbol (rtx temp, rtx addr)
828 rtx high = score_force_temporary (temp,
829 gen_rtx_HIGH (Pmode, copy_rtx (addr)));
830 return gen_rtx_LO_SUM (Pmode, high, addr);
833 /* This function is used to implement LEGITIMIZE_ADDRESS. If *XLOC can
834 be legitimized in a way that the generic machinery might not expect,
835 put the new address in *XLOC and return true. */
837 score_legitimize_address (rtx *xloc)
839 enum score_symbol_type symbol_type;
841 if (mda_symbolic_constant_p (*xloc, &symbol_type)
842 && symbol_type == SYMBOL_GENERAL)
844 *xloc = score_split_symbol (0, *xloc);
848 if (GET_CODE (*xloc) == PLUS
849 && GET_CODE (XEXP (*xloc, 1)) == CONST_INT)
851 rtx reg = XEXP (*xloc, 0);
852 if (!mda_valid_base_register_p (reg, 0))
853 reg = copy_to_mode_reg (Pmode, reg);
854 *xloc = score_add_offset (NULL, reg, INTVAL (XEXP (*xloc, 1)));
860 /* Return a number assessing the cost of moving a register in class
863 score_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
864 enum reg_class from, enum reg_class to)
866 if (GR_REG_CLASS_P (from))
868 if (GR_REG_CLASS_P (to))
870 else if (SP_REG_CLASS_P (to))
872 else if (CP_REG_CLASS_P (to))
874 else if (CE_REG_CLASS_P (to))
877 if (GR_REG_CLASS_P (to))
879 if (GR_REG_CLASS_P (from))
881 else if (SP_REG_CLASS_P (from))
883 else if (CP_REG_CLASS_P (from))
885 else if (CE_REG_CLASS_P (from))
891 /* Return the number of instructions needed to load a symbol of the
892 given type into a register. */
894 score_symbol_insns (enum score_symbol_type type)
901 case SYMBOL_SMALL_DATA:
908 /* Return the number of instructions needed to load or store a value
909 of mode MODE at X. Return 0 if X isn't valid for MODE. */
911 score_address_insns (rtx x, enum machine_mode mode)
913 struct score_address_info addr;
917 /* BLKmode is used for single unaligned loads and stores. */
920 /* Each word of a multi-word value will be accessed individually. */
921 factor = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
923 if (mda_classify_address (&addr, mode, x, false))
931 return factor * score_symbol_insns (addr.symbol_type);
936 /* Implement TARGET_RTX_COSTS macro. */
938 score_rtx_costs (rtx x, int code, int outer_code, int *total)
940 enum machine_mode mode = GET_MODE (x);
945 /* These can be used anywhere. */
949 /* Otherwise fall through to the handling below because
950 we'll need to construct the constant. */
955 *total = COSTS_N_INSNS (1);
960 /* If the address is legitimate, return the number of
961 instructions it needs, otherwise use the default handling. */
962 int n = score_address_insns (XEXP (x, 0), GET_MODE (x));
965 *total = COSTS_N_INSNS (n + 1);
972 *total = COSTS_N_INSNS (6);
976 *total = COSTS_N_INSNS (1);
984 *total = COSTS_N_INSNS (2);
994 *total = COSTS_N_INSNS ((GET_CODE (XEXP (x, 1)) == CONST_INT)
1001 *total = COSTS_N_INSNS (4);
1008 *total = COSTS_N_INSNS (4);
1016 *total = COSTS_N_INSNS (4);
1022 *total = COSTS_N_INSNS (12);
1029 *total = COSTS_N_INSNS (33);
1033 *total = COSTS_N_INSNS (2);
1037 *total = COSTS_N_INSNS (1);
1045 /* Implement ASM_OUTPUT_EXTERNAL macro. */
1047 score_output_external (FILE *file ATTRIBUTE_UNUSED,
1048 tree decl, const char *name)
1050 register struct extern_list *p;
1052 if (th_in_small_data_p (decl))
1054 p = (struct extern_list *) ggc_alloc (sizeof (struct extern_list));
1055 p->next = extern_head;
1057 p->size = int_size_in_bytes (TREE_TYPE (decl));
1063 /* Output format asm string. */
1065 score_declare_object (FILE *stream, const char *name,
1066 const char *directive, const char *fmt, ...)
1069 fputs (directive, stream);
1070 assemble_name (stream, name);
1072 vfprintf (stream, fmt, ap);
1076 /* Implement RETURN_ADDR_RTX. Note, we do not support moving
1077 back to a previous frame. */
1079 score_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
1083 return get_hard_reg_initial_val (Pmode, RA_REGNUM);
1086 /* Implement PRINT_OPERAND macro. */
1087 /* Score-specific operand codes:
1088 '[' print .set nor1 directive
1089 ']' print .set r1 directive
1091 'U' print hi part of a CONST_INT rtx
1092 'D' print first part of const double
1093 'S' selectively print '!' if operand is 15bit instruction accessible
1094 'V' print "v!" if operand is 15bit instruction accessible, or
1097 'L' low part of DImode reg operand
1098 'H' high part of DImode reg operand
1100 'C' print part of opcode for a branch condition. */
1102 score_print_operand (FILE *file, rtx op, int c)
1104 enum rtx_code code = -1;
1105 if (!PRINT_OPERAND_PUNCT_VALID_P (c))
1106 code = GET_CODE (op);
1110 fprintf (file, ".set r1\n");
1114 fprintf (file, "\n\t.set nor1");
1118 gcc_assert (code == CONST_INT);
1119 fprintf (file, HOST_WIDE_INT_PRINT_HEX,
1120 (unsigned HOST_WIDE_INT) INTVAL (op) >> 16);
1124 if (GET_CODE (op) == CONST_DOUBLE)
1125 fprintf (file, HOST_WIDE_INT_PRINT_HEX,
1126 TARGET_LITTLE_ENDIAN
1127 ? CONST_DOUBLE_LOW (op) : CONST_DOUBLE_HIGH (op));
1129 output_addr_const (file, op);
1133 gcc_assert (code == REG);
1134 if (G16_REG_P (REGNO (op)))
1135 fprintf (file, "!");
1139 gcc_assert (code == REG);
1140 fprintf (file, G16_REG_P (REGNO (op)) ? "v!" : "lfh!");
1142 else if (code == REG)
1144 int regnum = REGNO (op);
1145 if ((c == 'H' && !WORDS_BIG_ENDIAN)
1146 || (c == 'L' && WORDS_BIG_ENDIAN))
1148 fprintf (file, "%s", reg_names[regnum]);
1154 case EQ: fputs ("eq", file); break;
1155 case NE: fputs ("ne", file); break;
1156 case GT: fputs ("gt", file); break;
1157 case GE: fputs ("ge", file); break;
1158 case LT: fputs ("lt", file); break;
1159 case LE: fputs ("le", file); break;
1160 case GTU: fputs ("gtu", file); break;
1161 case GEU: fputs ("cs", file); break;
1162 case LTU: fputs ("cc", file); break;
1163 case LEU: fputs ("leu", file); break;
1165 output_operand_lossage ("invalid operand for code: '%c'", code);
1173 score_print_operand_address (file, op);
1176 output_addr_const (file, op);
1181 /* Implement PRINT_OPERAND_ADDRESS macro. */
1183 score_print_operand_address (FILE *file, rtx x)
1185 struct score_address_info addr;
1186 enum rtx_code code = GET_CODE (x);
1187 enum machine_mode mode = GET_MODE (x);
1192 if (mda_classify_address (&addr, mode, x, true))
1201 fprintf (file, "[%s,-%ld]+", reg_names[REGNO (addr.reg)],
1202 INTVAL (addr.offset));
1205 fprintf (file, "[%s]+,-%ld", reg_names[REGNO (addr.reg)],
1206 INTVAL (addr.offset));
1209 fprintf (file, "[%s, %ld]+", reg_names[REGNO (addr.reg)],
1210 INTVAL (addr.offset));
1213 fprintf (file, "[%s]+, %ld", reg_names[REGNO (addr.reg)],
1214 INTVAL (addr.offset));
1217 fprintf (file, "[%s,%ld]", reg_names[REGNO (addr.reg)],
1218 INTVAL (addr.offset));
1225 output_addr_const (file, x);
1229 print_rtl (stderr, x);
1233 struct gcc_target targetm = TARGET_INITIALIZER;