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 *cum,
64 enum machine_mode mode,
65 tree type, int named);
67 #undef TARGET_ASM_FILE_START
68 #define TARGET_ASM_FILE_START th_asm_file_start
70 #undef TARGET_ASM_FILE_END
71 #define TARGET_ASM_FILE_END th_asm_file_end
73 #undef TARGET_ASM_FUNCTION_PROLOGUE
74 #define TARGET_ASM_FUNCTION_PROLOGUE th_function_prologue
76 #undef TARGET_ASM_FUNCTION_EPILOGUE
77 #define TARGET_ASM_FUNCTION_EPILOGUE th_function_epilogue
79 #undef TARGET_SCHED_ISSUE_RATE
80 #define TARGET_SCHED_ISSUE_RATE th_issue_rate
82 #undef TARGET_ASM_SELECT_RTX_SECTION
83 #define TARGET_ASM_SELECT_RTX_SECTION th_select_rtx_section
85 #undef TARGET_IN_SMALL_DATA_P
86 #define TARGET_IN_SMALL_DATA_P th_in_small_data_p
88 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
89 #define TARGET_FUNCTION_OK_FOR_SIBCALL th_function_ok_for_sibcall
91 #undef TARGET_STRICT_ARGUMENT_NAMING
92 #define TARGET_STRICT_ARGUMENT_NAMING th_strict_argument_naming
94 #undef TARGET_ASM_OUTPUT_MI_THUNK
95 #define TARGET_ASM_OUTPUT_MI_THUNK th_output_mi_thunk
97 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
98 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_tree_hwi_hwi_tree_true
100 #undef TARGET_PROMOTE_FUNCTION_ARGS
101 #define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true
103 #undef TARGET_PROMOTE_FUNCTION_RETURN
104 #define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true
106 #undef TARGET_PROMOTE_PROTOTYPES
107 #define TARGET_PROMOTE_PROTOTYPES hook_bool_tree_true
109 #undef TARGET_MUST_PASS_IN_STACK
110 #define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size
112 #undef TARGET_ARG_PARTIAL_BYTES
113 #define TARGET_ARG_PARTIAL_BYTES score_arg_partial_bytes
115 #undef TARGET_PASS_BY_REFERENCE
116 #define TARGET_PASS_BY_REFERENCE score_pass_by_reference
118 #undef TARGET_RETURN_IN_MEMORY
119 #define TARGET_RETURN_IN_MEMORY score_return_in_memory
121 /* Implement TARGET_RETURN_IN_MEMORY. In S+core,
122 small structures are returned in a register.
123 Objects with varying size must still be returned in memory. */
125 score_return_in_memory (tree type, tree fndecl ATTRIBUTE_UNUSED)
127 return ((TYPE_MODE (type) == BLKmode)
128 || (int_size_in_bytes (type) > 2 * UNITS_PER_WORD)
129 || (int_size_in_bytes (type) == -1));
132 /* Return nonzero when an argument must be passed by reference. */
134 score_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
135 enum machine_mode mode, tree type,
136 bool named ATTRIBUTE_UNUSED)
138 /* If we have a variable-sized parameter, we have no choice. */
139 return targetm.calls.must_pass_in_stack (mode, type);
142 /* Return a legitimate address for REG + OFFSET. */
144 score_add_offset (rtx temp, rtx reg, HOST_WIDE_INT offset)
146 if (!CONST_OK_FOR_LETTER_P (offset, 'O'))
148 reg = expand_simple_binop (GET_MODE (reg), PLUS,
149 gen_int_mode (offset & 0xffffc000,
151 reg, NULL, 0, OPTAB_WIDEN);
155 return plus_constant (reg, offset);
158 /* Implement TARGET_ASM_OUTPUT_MI_THUNK. Generate rtl rather than asm text
159 in order to avoid duplicating too much logic from elsewhere. */
161 th_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
162 HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
165 rtx this, temp1, temp2, insn, fnaddr;
167 /* Pretend to be a post-reload pass while generating rtl. */
169 reload_completed = 1;
170 reset_block_changes ();
172 /* We need two temporary registers in some cases. */
173 temp1 = gen_rtx_REG (Pmode, 8);
174 temp2 = gen_rtx_REG (Pmode, 9);
176 /* Find out which register contains the "this" pointer. */
177 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
178 this = gen_rtx_REG (Pmode, ARG_REG_FIRST + 1);
180 this = gen_rtx_REG (Pmode, ARG_REG_FIRST);
182 /* Add DELTA to THIS. */
185 rtx offset = GEN_INT (delta);
186 if (!CONST_OK_FOR_LETTER_P (delta, 'L'))
188 emit_move_insn (temp1, offset);
191 emit_insn (gen_add3_insn (this, this, offset));
194 /* If needed, add *(*THIS + VCALL_OFFSET) to THIS. */
195 if (vcall_offset != 0)
199 /* Set TEMP1 to *THIS. */
200 emit_move_insn (temp1, gen_rtx_MEM (Pmode, this));
202 /* Set ADDR to a legitimate address for *THIS + VCALL_OFFSET. */
203 addr = score_add_offset (temp2, temp1, vcall_offset);
205 /* Load the offset and add it to THIS. */
206 emit_move_insn (temp1, gen_rtx_MEM (Pmode, addr));
207 emit_insn (gen_add3_insn (this, this, temp1));
210 /* Jump to the target function. */
211 fnaddr = XEXP (DECL_RTL (function), 0);
212 insn = emit_call_insn (gen_sibcall_internal (fnaddr, const0_rtx));
213 SIBLING_CALL_P (insn) = 1;
215 /* Run just enough of rest_of_compilation. This sequence was
216 "borrowed" from alpha.c. */
218 insn_locators_initialize ();
219 split_all_insns_noflow ();
220 shorten_branches (insn);
221 final_start_function (insn, file, 1);
222 final (insn, file, 1);
223 final_end_function ();
225 /* Clean up the vars set above. Note that final_end_function resets
226 the global pointer for us. */
227 reload_completed = 0;
231 /* Implement TARGET_STRICT_ARGUMENT_NAMING. */
233 th_strict_argument_naming (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED)
238 /* Implement TARGET_FUNCTION_OK_FOR_SIBCALL. */
240 th_function_ok_for_sibcall (ATTRIBUTE_UNUSED tree decl,
241 ATTRIBUTE_UNUSED tree exp)
246 struct score_arg_info
248 /* The argument's size, in bytes. */
249 unsigned int num_bytes;
251 /* The number of words passed in registers, rounded up. */
252 unsigned int reg_words;
254 /* The offset of the first register from GP_ARG_FIRST or FP_ARG_FIRST,
255 or ARG_REG_NUM if the argument is passed entirely on the stack. */
256 unsigned int reg_offset;
258 /* The number of words that must be passed on the stack, rounded up. */
259 unsigned int stack_words;
261 /* The offset from the start of the stack overflow area of the argument's
262 first stack word. Only meaningful when STACK_WORDS is nonzero. */
263 unsigned int stack_offset;
266 /* Fill INFO with information about a single argument. CUM is the
267 cumulative state for earlier arguments. MODE is the mode of this
268 argument and TYPE is its type (if known). NAMED is true if this
269 is a named (fixed) argument rather than a variable one. */
271 classify_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
272 tree type, int named, struct score_arg_info *info)
275 unsigned int num_words, max_regs;
278 if (GET_MODE_CLASS (mode) == MODE_INT
279 || GET_MODE_CLASS (mode) == MODE_FLOAT)
280 even_reg_p = (GET_MODE_SIZE (mode) > UNITS_PER_WORD);
282 if (type != NULL_TREE && TYPE_ALIGN (type) > BITS_PER_WORD && named)
285 if (TARGET_MUST_PASS_IN_STACK (mode, type))
286 info->reg_offset = ARG_REG_NUM;
289 info->reg_offset = cum->num_gprs;
291 info->reg_offset += info->reg_offset & 1;
295 info->num_bytes = int_size_in_bytes (type);
297 info->num_bytes = GET_MODE_SIZE (mode);
299 num_words = (info->num_bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
300 max_regs = ARG_REG_NUM - info->reg_offset;
302 /* Partition the argument between registers and stack. */
303 info->reg_words = MIN (num_words, max_regs);
304 info->stack_words = num_words - info->reg_words;
306 /* The alignment applied to registers is also applied to stack arguments. */
307 if (info->stack_words)
309 info->stack_offset = cum->stack_words;
311 info->stack_offset += info->stack_offset & 1;
315 /* Set up the stack and frame (if desired) for the function. */
317 th_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
320 struct score_frame_info *f = mda_cached_frame ();
321 HOST_WIDE_INT tsize = f->total_size;
323 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
324 if (!flag_inhibit_size_directive)
326 fputs ("\t.ent\t", file);
327 assemble_name (file, fnname);
330 assemble_name (file, fnname);
333 if (!flag_inhibit_size_directive)
336 "\t.frame\t%s," HOST_WIDE_INT_PRINT_DEC ",%s, %d\t\t"
337 "# vars= " HOST_WIDE_INT_PRINT_DEC ", regs= %d"
338 ", args= " HOST_WIDE_INT_PRINT_DEC
339 ", gp= " HOST_WIDE_INT_PRINT_DEC "\n",
340 (reg_names[(frame_pointer_needed)
341 ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM]),
343 reg_names[RA_REGNUM],
344 current_function_is_leaf ? 1 : 0,
350 fprintf(file, "\t.mask\t0x%08x," HOST_WIDE_INT_PRINT_DEC "\n",
352 (f->gp_sp_offset - f->total_size));
356 /* Do any necessary cleanup after a function to restore stack, frame,
359 th_function_epilogue (FILE *file,
360 HOST_WIDE_INT size ATTRIBUTE_UNUSED)
362 if (!flag_inhibit_size_directive)
365 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
366 fputs ("\t.end\t", file);
367 assemble_name (file, fnname);
372 /* Implement TARGET_SCHED_ISSUE_RATE. */
379 /* Returns true if X contains a SYMBOL_REF. */
381 symbolic_expression_p (rtx x)
383 if (GET_CODE (x) == SYMBOL_REF)
386 if (GET_CODE (x) == CONST)
387 return symbolic_expression_p (XEXP (x, 0));
390 return symbolic_expression_p (XEXP (x, 0));
392 if (ARITHMETIC_P (x))
393 return (symbolic_expression_p (XEXP (x, 0))
394 || symbolic_expression_p (XEXP (x, 1)));
399 /* Choose the section to use for the constant rtx expression X that has
402 th_select_rtx_section (enum machine_mode mode, rtx x,
403 unsigned HOST_WIDE_INT align)
405 if (GET_MODE_SIZE (mode) <= SCORE_SDATA_MAX)
406 return get_named_section (0, ".sdata", 0);
407 else if (flag_pic && symbolic_expression_p (x))
408 return get_named_section (0, ".data.rel.ro", 3);
410 return mergeable_constant_section (mode, align, 0);
413 /* Implement TARGET_IN_SMALL_DATA_P. */
415 th_in_small_data_p (tree decl)
419 if (TREE_CODE (decl) == STRING_CST
420 || TREE_CODE (decl) == FUNCTION_DECL)
423 if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl) != 0)
426 name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
427 if (strcmp (name, ".sdata") != 0
428 && strcmp (name, ".sbss") != 0)
430 if (!DECL_EXTERNAL (decl))
433 size = int_size_in_bytes (TREE_TYPE (decl));
434 return (size > 0 && size <= SCORE_SDATA_MAX);
437 /* Implement TARGET_ASM_FILE_START. */
439 th_asm_file_start (void)
441 default_file_start ();
442 fprintf (asm_out_file, ASM_COMMENT_START
443 "GCC for S+core %s \n", SCORE_GCC_VERSION);
446 fprintf (asm_out_file, "\t.set pic\n");
449 /* Implement TARGET_ASM_FILE_END. When using assembler macros, emit
450 .externs for any small-data variables that turned out to be external. */
451 struct extern_list *extern_head = 0;
454 th_asm_file_end (void)
457 struct extern_list *p;
460 fputs ("\n", asm_out_file);
461 for (p = extern_head; p != 0; p = p->next)
463 name_tree = get_identifier (p->name);
464 if (!TREE_ASM_WRITTEN (name_tree)
465 && TREE_SYMBOL_REFERENCED (name_tree))
467 TREE_ASM_WRITTEN (name_tree) = 1;
468 fputs ("\t.extern\t", asm_out_file);
469 assemble_name (asm_out_file, p->name);
470 fprintf (asm_out_file, ", %d\n", p->size);
476 static unsigned int sdata_max;
479 score_sdata_max (void)
484 /* default 0 = NO_REGS */
485 enum reg_class score_char_to_class[256];
487 /* Implement OVERRIDE_OPTIONS macro. */
489 score_override_options (void)
492 sdata_max = g_switch_set ? g_switch_value : DEFAULT_SDATA_MAX;
497 warning (0, "-fPIC and -G are incompatible");
500 score_char_to_class['d'] = G32_REGS;
501 score_char_to_class['e'] = G16_REGS;
502 score_char_to_class['t'] = T32_REGS;
504 score_char_to_class['h'] = HI_REG;
505 score_char_to_class['l'] = LO_REG;
506 score_char_to_class['x'] = CE_REGS;
508 score_char_to_class['q'] = CN_REG;
509 score_char_to_class['y'] = LC_REG;
510 score_char_to_class['z'] = SC_REG;
511 score_char_to_class['a'] = SP_REGS;
513 score_char_to_class['c'] = CR_REGS;
515 score_char_to_class['b'] = CP1_REGS;
516 score_char_to_class['f'] = CP2_REGS;
517 score_char_to_class['i'] = CP3_REGS;
518 score_char_to_class['j'] = CPA_REGS;
521 /* Implement REGNO_REG_CLASS macro. */
523 score_reg_class (int regno)
526 gcc_assert (regno >= 0 && regno < FIRST_PSEUDO_REGISTER);
528 if (regno == FRAME_POINTER_REGNUM
529 || regno == ARG_POINTER_REGNUM)
532 for (c = 0 ; c < N_REG_CLASSES ; c++)
533 if (TEST_HARD_REG_BIT (reg_class_contents[c], regno))
539 /* Implement PREFERRED_RELOAD_CLASS macro. */
541 score_preferred_reload_class (rtx x ATTRIBUTE_UNUSED, enum reg_class class)
543 if (reg_class_subset_p (G32_REGS, class))
545 if (reg_class_subset_p (G16_REGS, class))
550 /* Implement SECONDARY_INPUT_RELOAD_CLASS
551 and SECONDARY_OUTPUT_RELOAD_CLASS macro. */
553 score_secondary_reload_class (enum reg_class class,
554 enum machine_mode mode ATTRIBUTE_UNUSED,
558 if (GET_CODE (x) == REG || GET_CODE(x) == SUBREG)
559 regno = true_regnum (x);
561 if (!GR_REG_CLASS_P (class))
562 return GP_REG_P (regno) ? NO_REGS : G32_REGS;
566 /* Implement CONST_OK_FOR_LETTER_P macro. */
575 P IMM12s (rix-form) / IMM10s(cop-form) << 2 */
577 score_const_ok_for_letter_p (int value, char c)
581 case 'I': return IMM_IN_RANGE (value, 8, 0);
582 case 'J': return IMM_IN_RANGE (value, 5, 0);
583 case 'K': return IMM_IN_RANGE (value, 16, 0);
584 case 'L': return IMM_IN_RANGE (value, 16, 1);
585 case 'M': return IMM_IN_RANGE (value, 14, 0);
586 case 'N': return IMM_IN_RANGE (value, 14, 1);
587 case 'O': return IMM_IN_RANGE (value, 15, 1);
588 case 'P': return IMM_IN_RANGE (value, 12, 1);
593 /* Implement EXTRA_CONSTRAINT macro. */
597 score_extra_constraint (rtx op, char c)
602 return (GET_CODE (op) == CONST_INT && (INTVAL (op) & 0xffff) == 0);
604 return GET_CODE (op) == SYMBOL_REF;
610 /* Return truth value on whether or not a given hard register
611 can support a given mode. */
613 score_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
615 int size = GET_MODE_SIZE (mode);
616 enum mode_class class = GET_MODE_CLASS (mode);
618 if (class == MODE_CC)
619 return regno == CC_REGNUM;
620 else if (regno == FRAME_POINTER_REGNUM
621 || regno == ARG_POINTER_REGNUM)
622 return class == MODE_INT;
623 else if (GP_REG_P (regno))
624 /* ((regno <= (GP_REG_LAST- HARD_REGNO_NREGS (dummy, mode)) + 1) */
625 return !(regno & 1) || (size <= UNITS_PER_WORD);
626 else if (CE_REG_P (regno))
627 return (class == MODE_INT
628 && ((size <= UNITS_PER_WORD)
629 || (regno == CE_REG_FIRST && size == 2 * UNITS_PER_WORD)));
631 return (class == MODE_INT) && (size <= UNITS_PER_WORD);
634 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
635 pointer or argument pointer. TO is either the stack pointer or
636 hard frame pointer. */
638 score_initial_elimination_offset (int from,
639 int to ATTRIBUTE_UNUSED)
641 struct score_frame_info *f = mda_compute_frame_size (get_frame_size ());
644 case ARG_POINTER_REGNUM:
645 return f->total_size;
646 case FRAME_POINTER_REGNUM:
653 /* Argument support functions. */
655 /* Initialize CUMULATIVE_ARGS for a function. */
657 score_init_cumulative_args (CUMULATIVE_ARGS *cum,
658 tree fntype ATTRIBUTE_UNUSED,
659 rtx libname ATTRIBUTE_UNUSED)
661 memset (cum, 0, sizeof (CUMULATIVE_ARGS));
664 /* Implement FUNCTION_ARG_ADVANCE macro. */
666 score_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
667 tree type, int named)
669 struct score_arg_info info;
670 classify_arg (cum, mode, type, named, &info);
671 cum->num_gprs = info.reg_offset + info.reg_words;
672 if (info.stack_words > 0)
673 cum->stack_words = info.stack_offset + info.stack_words;
677 /* Implement TARGET_ARG_PARTIAL_BYTES macro. */
679 score_arg_partial_bytes (const CUMULATIVE_ARGS *cum,
680 enum machine_mode mode, tree type, int named)
682 struct score_arg_info info;
683 classify_arg (cum, mode, type, named, &info);
684 return info.stack_words > 0 ? info.reg_words * UNITS_PER_WORD : 0;
687 /* Implement FUNCTION_ARG macro. */
689 score_function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
690 tree type, int named)
692 struct score_arg_info info;
694 if (mode == VOIDmode || !named)
697 classify_arg (cum, mode, type, named, &info);
699 if (info.reg_offset == ARG_REG_NUM)
702 if (!info.stack_words)
703 return gen_rtx_REG (mode, ARG_REG_FIRST + info.reg_offset);
706 rtx ret = gen_rtx_PARALLEL (mode, rtvec_alloc (info.reg_words));
707 unsigned int i, part_offset = 0;
708 for (i = 0; i < info.reg_words; i++)
711 reg = gen_rtx_REG (SImode, ARG_REG_FIRST + info.reg_offset + i);
712 XVECEXP (ret, 0, i) = gen_rtx_EXPR_LIST (SImode, reg,
713 GEN_INT (part_offset));
714 part_offset += UNITS_PER_WORD;
720 /* Implement FUNCTION_VALUE and LIBCALL_VALUE. For normal calls,
721 VALTYPE is the return type and MODE is VOIDmode. For libcalls,
722 VALTYPE is null and MODE is the mode of the return value. */
724 score_function_value (tree valtype, tree func ATTRIBUTE_UNUSED,
725 enum machine_mode mode)
730 mode = TYPE_MODE (valtype);
731 unsignedp = TYPE_UNSIGNED (valtype);
732 mode = promote_mode (valtype, mode, &unsignedp, 1);
734 return gen_rtx_REG (mode, RT_REGNUM);
737 /* Implement INITIALIZE_TRAMPOLINE macro. */
739 score_initialize_trampoline (rtx ADDR, rtx FUNC, rtx CHAIN)
741 #define FFCACHE "_flush_cache"
742 #define CODE_SIZE (TRAMPOLINE_INSNS * UNITS_PER_WORD)
744 unsigned int tramp[TRAMPOLINE_INSNS] = {
745 0x8103bc56, /* mv r8, r3 */
746 0x9000bc05, /* bl 0x0x8 */
747 0xc1238000 | (CODE_SIZE - 8), /* lw r9, &func */
749 | (STATIC_CHAIN_REGNUM << 21)
750 | (CODE_SIZE - 4), /* lw static chain reg, &chain */
751 0x8068bc56, /* mv r3, r8 */
752 0x8009bc08, /* br r9 */
759 for (i = 0; i < TRAMPOLINE_INSNS; i++)
760 emit_move_insn (gen_rtx_MEM (ptr_mode, plus_constant (ADDR, i << 2)),
763 pfunc = plus_constant (ADDR, CODE_SIZE);
764 pchain = plus_constant (ADDR, CODE_SIZE + GET_MODE_SIZE (ptr_mode));
766 emit_move_insn (gen_rtx_MEM (ptr_mode, pfunc), FUNC);
767 emit_move_insn (gen_rtx_MEM (ptr_mode, pchain), CHAIN);
768 emit_library_call (gen_rtx_SYMBOL_REF (Pmode, FFCACHE),
771 GEN_INT (TRAMPOLINE_SIZE), SImode);
776 /* This function is used to implement REG_MODE_OK_FOR_BASE_P macro. */
778 score_regno_mode_ok_for_base_p (int regno, int strict)
780 if (regno >= FIRST_PSEUDO_REGISTER)
784 regno = reg_renumber[regno];
786 if (regno == ARG_POINTER_REGNUM
787 || regno == FRAME_POINTER_REGNUM)
789 return GP_REG_P (regno);
792 /* Implement GO_IF_LEGITIMATE_ADDRESS macro. */
794 score_address_p (enum machine_mode mode, rtx x, int strict)
796 struct score_address_info addr;
798 return mda_classify_address (&addr, mode, x, strict);
801 /* Copy VALUE to a register and return that register. If new psuedos
802 are allowed, copy it into a new register, otherwise use DEST. */
804 score_force_temporary (rtx dest, rtx value)
807 return force_reg (Pmode, value);
810 emit_move_insn (copy_rtx (dest), value);
815 /* Return a LO_SUM expression for ADDR. TEMP is as for score_force_temporary
816 and is used to load the high part into a register. */
818 score_split_symbol (rtx temp, rtx addr)
820 rtx high = score_force_temporary (temp,
821 gen_rtx_HIGH (Pmode, copy_rtx (addr)));
822 return gen_rtx_LO_SUM (Pmode, high, addr);
825 /* This function is used to implement LEGITIMIZE_ADDRESS. If *XLOC can
826 be legitimized in a way that the generic machinery might not expect,
827 put the new address in *XLOC and return true. */
829 score_legitimize_address (rtx *xloc)
831 enum score_symbol_type symbol_type;
833 if (mda_symbolic_constant_p (*xloc, &symbol_type)
834 && symbol_type == SYMBOL_GENERAL)
836 *xloc = score_split_symbol (0, *xloc);
840 if (GET_CODE (*xloc) == PLUS
841 && GET_CODE (XEXP (*xloc, 1)) == CONST_INT)
843 rtx reg = XEXP (*xloc, 0);
844 if (!mda_valid_base_register_p (reg, 0))
845 reg = copy_to_mode_reg (Pmode, reg);
846 *xloc = score_add_offset (NULL, reg, INTVAL (XEXP (*xloc, 1)));
852 /* Return a number assessing the cost of moving a register in class
855 score_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
856 enum reg_class from, enum reg_class to)
858 if (GR_REG_CLASS_P (from))
860 if (GR_REG_CLASS_P (to))
862 else if (SP_REG_CLASS_P (to))
864 else if (CP_REG_CLASS_P (to))
866 else if (CE_REG_CLASS_P (to))
869 if (GR_REG_CLASS_P (to))
871 if (GR_REG_CLASS_P (from))
873 else if (SP_REG_CLASS_P (from))
875 else if (CP_REG_CLASS_P (from))
877 else if (CE_REG_CLASS_P (from))
883 /* Implement ASM_OUTPUT_EXTERNAL macro. */
885 score_output_external (FILE *file ATTRIBUTE_UNUSED,
886 tree decl, const char *name)
888 register struct extern_list *p;
890 if (th_in_small_data_p (decl))
892 p = (struct extern_list *) ggc_alloc (sizeof (struct extern_list));
893 p->next = extern_head;
895 p->size = int_size_in_bytes (TREE_TYPE (decl));
901 /* Output format asm string. */
903 score_declare_object (FILE *stream, const char *name,
904 const char *directive, const char *fmt, ...)
907 fputs (directive, stream);
908 assemble_name (stream, name);
910 vfprintf (stream, fmt, ap);
914 /* Implement RETURN_ADDR_RTX. Note, we do not support moving
915 back to a previous frame. */
917 score_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
921 return get_hard_reg_initial_val (Pmode, RA_REGNUM);
924 /* Implement PRINT_OPERAND macro. */
925 /* Score-specific operand codes:
926 '[' print .set nor1 directive
927 ']' print .set r1 directive
929 'U' print hi part of a CONST_INT rtx
930 'D' print first part of const double
931 'S' selectively print '!' if operand is 15bit instruction accessible
932 'V' print "v!" if operand is 15bit instruction accessible, or
935 'L' low part of DImode reg operand
936 'H' high part of DImode reg operand
938 'C' print part of opcode for a branch condition. */
940 score_print_operand (FILE *file, rtx op, int c)
942 enum rtx_code code = -1;
943 if (!PRINT_OPERAND_PUNCT_VALID_P (c))
944 code = GET_CODE (op);
948 fprintf (file, ".set r1\n");
952 fprintf (file, "\n\t.set nor1");
956 gcc_assert (code == CONST_INT);
957 fprintf (file, HOST_WIDE_INT_PRINT_HEX,
958 (unsigned HOST_WIDE_INT) INTVAL (op) >> 16);
962 if (GET_CODE (op) == CONST_DOUBLE)
963 fprintf (file, HOST_WIDE_INT_PRINT_HEX,
965 ? CONST_DOUBLE_LOW (op) : CONST_DOUBLE_HIGH (op));
967 output_addr_const (file, op);
971 gcc_assert (code == REG);
972 if (G16_REG_P (REGNO (op)))
977 gcc_assert (code == REG);
978 fprintf (file, G16_REG_P (REGNO (op)) ? "v!" : "lfh!");
980 else if (code == REG)
982 int regnum = REGNO (op);
983 if ((c == 'H' && !WORDS_BIG_ENDIAN)
984 || (c == 'L' && WORDS_BIG_ENDIAN))
986 fprintf (file, "%s", reg_names[regnum]);
992 case EQ: fputs ("eq", file); break;
993 case NE: fputs ("ne", file); break;
994 case GT: fputs ("gt", file); break;
995 case GE: fputs ("ge", file); break;
996 case LT: fputs ("lt", file); break;
997 case LE: fputs ("le", file); break;
998 case GTU: fputs ("gtu", file); break;
999 case GEU: fputs ("cs", file); break;
1000 case LTU: fputs ("cc", file); break;
1001 case LEU: fputs ("leu", file); break;
1003 output_operand_lossage ("invalid operand for code: '%c'", code);
1011 score_print_operand_address (file, op);
1014 output_addr_const (file, op);
1019 /* Implement PRINT_OPERAND_ADDRESS macro. */
1021 score_print_operand_address (FILE *file, rtx x)
1023 struct score_address_info addr;
1024 enum rtx_code code = GET_CODE (x);
1025 enum machine_mode mode = GET_MODE (x);
1030 if (mda_classify_address (&addr, mode, x, true))
1039 fprintf (file, "[%s,-%ld]+", reg_names[REGNO (addr.reg)],
1040 INTVAL (addr.offset));
1043 fprintf (file, "[%s]+,-%ld", reg_names[REGNO (addr.reg)],
1044 INTVAL (addr.offset));
1047 fprintf (file, "[%s, %ld]+", reg_names[REGNO (addr.reg)],
1048 INTVAL (addr.offset));
1051 fprintf (file, "[%s]+, %ld", reg_names[REGNO (addr.reg)],
1052 INTVAL (addr.offset));
1055 fprintf (file, "[%s,%ld]", reg_names[REGNO (addr.reg)],
1056 INTVAL (addr.offset));
1063 output_addr_const (file, x);
1067 print_rtl (stderr, x);
1071 struct gcc_target targetm = TARGET_INITIALIZER;