1 /* score3.c 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"
27 #include "hard-reg-set.h"
29 #include "insn-config.h"
30 #include "conditions.h"
31 #include "insn-attr.h"
47 #include "target-def.h"
48 #include "integrate.h"
49 #include "langhooks.h"
50 #include "cfglayout.h"
53 #define BITSET_P(VALUE, BIT) (((VALUE) & (1L << (BIT))) != 0)
54 #define INS_BUF_SZ 128
56 /* Define the information needed to generate branch insns. This is
57 stored from the compare operation. */
58 extern rtx cmp_op0, cmp_op1;
59 extern enum reg_class score_char_to_class[256];
61 static int score3_sdata_max;
62 static char score3_ins[INS_BUF_SZ + 8];
64 /* Return true if SYMBOL is a SYMBOL_REF and OFFSET + SYMBOL points
65 to the same object as SYMBOL. */
67 score3_offset_within_object_p (rtx symbol, HOST_WIDE_INT offset)
69 if (GET_CODE (symbol) != SYMBOL_REF)
72 if (CONSTANT_POOL_ADDRESS_P (symbol)
74 && offset < (int)GET_MODE_SIZE (get_pool_mode (symbol)))
77 if (SYMBOL_REF_DECL (symbol) != 0
79 && offset < int_size_in_bytes (TREE_TYPE (SYMBOL_REF_DECL (symbol))))
85 /* Split X into a base and a constant offset, storing them in *BASE
86 and *OFFSET respectively. */
88 score3_split_const (rtx x, rtx *base, HOST_WIDE_INT *offset)
92 if (GET_CODE (x) == CONST)
95 if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
97 *offset += INTVAL (XEXP (x, 1));
104 /* Classify symbol X, which must be a SYMBOL_REF or a LABEL_REF. */
105 static enum score_symbol_type
106 score3_classify_symbol (rtx x)
108 if (GET_CODE (x) == LABEL_REF)
109 return SYMBOL_GENERAL;
111 gcc_assert (GET_CODE (x) == SYMBOL_REF);
113 if (CONSTANT_POOL_ADDRESS_P (x))
115 if (GET_MODE_SIZE (get_pool_mode (x)) <= SCORE3_SDATA_MAX)
116 return SYMBOL_SMALL_DATA;
117 return SYMBOL_GENERAL;
119 if (SYMBOL_REF_SMALL_P (x))
120 return SYMBOL_SMALL_DATA;
121 return SYMBOL_GENERAL;
124 /* Return true if the current function must save REGNO. */
126 score3_save_reg_p (unsigned int regno)
128 /* Check call-saved registers. */
129 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
132 /* We need to save the old frame pointer before setting up a new one. */
133 if (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed)
136 /* We need to save the incoming return address if it is ever clobbered
137 within the function. */
138 if (regno == RA_REGNUM && df_regs_ever_live_p (regno))
144 /* Return one word of double-word value OP, taking into account the fixed
145 endianness of certain registers. HIGH_P is true to select the high part,
146 false to select the low part. */
148 score3_subw (rtx op, int high_p)
151 enum machine_mode mode = GET_MODE (op);
153 if (mode == VOIDmode)
156 byte = (TARGET_LITTLE_ENDIAN ? high_p : !high_p) ? UNITS_PER_WORD : 0;
158 if (GET_CODE (op) == REG && REGNO (op) == HI_REGNUM)
159 return gen_rtx_REG (SImode, high_p ? HI_REGNUM : LO_REGNUM);
161 if (GET_CODE (op) == MEM)
162 return adjust_address (op, SImode, byte);
164 return simplify_gen_subreg (SImode, op, mode, byte);
167 static struct score3_frame_info *
168 score3_cached_frame (void)
170 static struct score3_frame_info _frame_info;
174 /* Return the bytes needed to compute the frame pointer from the current
175 stack pointer. SIZE is the size (in bytes) of the local variables. */
176 static struct score3_frame_info *
177 score3_compute_frame_size (HOST_WIDE_INT size)
180 struct score3_frame_info *f = score3_cached_frame ();
182 memset (f, 0, sizeof (struct score3_frame_info));
185 f->var_size = SCORE3_STACK_ALIGN (size);
186 f->args_size = current_function_outgoing_args_size;
187 f->cprestore_size = flag_pic ? UNITS_PER_WORD : 0;
189 if (f->var_size == 0 && current_function_is_leaf)
190 f->args_size = f->cprestore_size = 0;
192 if (f->args_size == 0 && current_function_calls_alloca)
193 f->args_size = UNITS_PER_WORD;
195 f->total_size = f->var_size + f->args_size + f->cprestore_size;
196 for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
198 if (score3_save_reg_p (regno))
200 f->gp_reg_size += GET_MODE_SIZE (SImode);
201 f->mask |= 1 << (regno - GP_REG_FIRST);
205 if (current_function_calls_eh_return)
210 regno = EH_RETURN_DATA_REGNO (i);
211 if (regno == INVALID_REGNUM)
213 f->gp_reg_size += GET_MODE_SIZE (SImode);
214 f->mask |= 1 << (regno - GP_REG_FIRST);
218 f->total_size += f->gp_reg_size;
219 f->num_gp = f->gp_reg_size / UNITS_PER_WORD;
223 HOST_WIDE_INT offset;
224 offset = (f->args_size + f->cprestore_size + f->var_size
225 + f->gp_reg_size - GET_MODE_SIZE (SImode));
226 f->gp_sp_offset = offset;
234 /* Return true if X is a valid base register for the given mode.
235 Allow only hard registers if STRICT. */
237 score3_valid_base_register_p (rtx x, int strict)
239 if (!strict && GET_CODE (x) == SUBREG)
242 return (GET_CODE (x) == REG
243 && score3_regno_mode_ok_for_base_p (REGNO (x), strict));
246 /* Return true if X is a valid address for machine mode MODE. If it is,
247 fill in INFO appropriately. STRICT is true if we should only accept
248 hard base registers. */
250 score3_classify_address (struct score3_address_info *info,
251 enum machine_mode mode, rtx x, int strict)
253 info->code = GET_CODE (x);
259 info->type = SCORE3_ADD_REG;
261 info->offset = const0_rtx;
262 return score3_valid_base_register_p (info->reg, strict);
264 info->type = SCORE3_ADD_REG;
265 info->reg = XEXP (x, 0);
266 info->offset = XEXP (x, 1);
267 return (score3_valid_base_register_p (info->reg, strict)
268 && GET_CODE (info->offset) == CONST_INT
269 && IMM_IN_RANGE (INTVAL (info->offset), 15, 1));
274 if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (SImode))
276 info->type = SCORE3_ADD_REG;
277 info->reg = XEXP (x, 0);
278 info->offset = GEN_INT (GET_MODE_SIZE (mode));
279 return score3_valid_base_register_p (info->reg, strict);
281 info->type = SCORE3_ADD_CONST_INT;
286 info->type = SCORE3_ADD_SYMBOLIC;
287 return (score3_symbolic_constant_p (x, &info->symbol_type)
288 && (info->symbol_type == SYMBOL_GENERAL
289 || info->symbol_type == SYMBOL_SMALL_DATA));
296 score3_return_in_memory (tree type, tree fndecl ATTRIBUTE_UNUSED)
298 return ((TYPE_MODE (type) == BLKmode)
299 || (int_size_in_bytes (type) > 2 * UNITS_PER_WORD)
300 || (int_size_in_bytes (type) == -1));
303 /* Return a legitimate address for REG + OFFSET. */
305 score3_add_offset (rtx reg, HOST_WIDE_INT offset)
307 if (!IMM_IN_RANGE (offset, 15, 1))
309 reg = expand_simple_binop (GET_MODE (reg), PLUS,
310 gen_int_mode (offset & 0xffffc000,
312 reg, NULL, 0, OPTAB_WIDEN);
316 return plus_constant (reg, offset);
319 /* Implement TARGET_ASM_OUTPUT_MI_THUNK. Generate rtl rather than asm text
320 in order to avoid duplicating too much logic from elsewhere. */
322 score3_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
323 HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
326 rtx this, temp1, insn, fnaddr;
328 /* Pretend to be a post-reload pass while generating rtl. */
329 reload_completed = 1;
331 /* Mark the end of the (empty) prologue. */
332 emit_note (NOTE_INSN_PROLOGUE_END);
334 /* We need two temporary registers in some cases. */
335 temp1 = gen_rtx_REG (Pmode, 8);
337 /* Find out which register contains the "this" pointer. */
338 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
339 this = gen_rtx_REG (Pmode, ARG_REG_FIRST + 1);
341 this = gen_rtx_REG (Pmode, ARG_REG_FIRST);
343 /* Add DELTA to THIS. */
346 rtx offset = GEN_INT (delta);
347 if (!CONST_OK_FOR_LETTER_P (delta, 'L'))
349 emit_move_insn (temp1, offset);
352 emit_insn (gen_add3_insn (this, this, offset));
355 /* If needed, add *(*THIS + VCALL_OFFSET) to THIS. */
356 if (vcall_offset != 0)
360 /* Set TEMP1 to *THIS. */
361 emit_move_insn (temp1, gen_rtx_MEM (Pmode, this));
363 /* Set ADDR to a legitimate address for *THIS + VCALL_OFFSET. */
364 addr = score3_add_offset (temp1, vcall_offset);
366 /* Load the offset and add it to THIS. */
367 emit_move_insn (temp1, gen_rtx_MEM (Pmode, addr));
368 emit_insn (gen_add3_insn (this, this, temp1));
371 /* Jump to the target function. */
372 fnaddr = XEXP (DECL_RTL (function), 0);
373 insn = emit_call_insn (gen_sibcall_internal_score3 (fnaddr, const0_rtx));
374 SIBLING_CALL_P (insn) = 1;
376 /* Run just enough of rest_of_compilation. This sequence was
377 "borrowed" from alpha.c. */
379 insn_locators_alloc ();
380 split_all_insns_noflow ();
381 shorten_branches (insn);
382 final_start_function (insn, file, 1);
383 final (insn, file, 1);
384 final_end_function ();
386 /* Clean up the vars set above. Note that final_end_function resets
387 the global pointer for us. */
388 reload_completed = 0;
391 /* Copy VALUE to a register and return that register. If new psuedos
392 are allowed, copy it into a new register, otherwise use DEST. */
394 score3_force_temporary (rtx dest, rtx value)
396 if (can_create_pseudo_p ())
397 return force_reg (Pmode, value);
400 emit_move_insn (copy_rtx (dest), value);
405 /* Return a LO_SUM expression for ADDR. TEMP is as for score_force_temporary
406 and is used to load the high part into a register. */
408 score3_split_symbol (rtx temp, rtx addr)
410 rtx high = score3_force_temporary (temp,
411 gen_rtx_HIGH (Pmode, copy_rtx (addr)));
412 return gen_rtx_LO_SUM (Pmode, high, addr);
415 /* This function is used to implement LEGITIMIZE_ADDRESS. If *XLOC can
416 be legitimized in a way that the generic machinery might not expect,
417 put the new address in *XLOC and return true. */
419 score3_legitimize_address (rtx *xloc)
421 enum score_symbol_type symbol_type;
423 if (score3_symbolic_constant_p (*xloc, &symbol_type)
424 && symbol_type == SYMBOL_GENERAL)
426 *xloc = score3_split_symbol (0, *xloc);
430 if (GET_CODE (*xloc) == PLUS
431 && GET_CODE (XEXP (*xloc, 1)) == CONST_INT)
433 rtx reg = XEXP (*xloc, 0);
434 if (!score3_valid_base_register_p (reg, 0))
435 reg = copy_to_mode_reg (Pmode, reg);
436 *xloc = score3_add_offset (reg, INTVAL (XEXP (*xloc, 1)));
442 /* Fill INFO with information about a single argument. CUM is the
443 cumulative state for earlier arguments. MODE is the mode of this
444 argument and TYPE is its type (if known). NAMED is true if this
445 is a named (fixed) argument rather than a variable one. */
447 score3_classify_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
448 tree type, int named, struct score3_arg_info *info)
451 unsigned int num_words, max_regs;
454 if (GET_MODE_CLASS (mode) == MODE_INT
455 || GET_MODE_CLASS (mode) == MODE_FLOAT)
456 even_reg_p = (GET_MODE_SIZE (mode) > UNITS_PER_WORD);
458 if (type != NULL_TREE && TYPE_ALIGN (type) > BITS_PER_WORD && named)
461 if (TARGET_MUST_PASS_IN_STACK (mode, type))
462 info->reg_offset = ARG_REG_NUM;
465 info->reg_offset = cum->num_gprs;
467 info->reg_offset += info->reg_offset & 1;
471 info->num_bytes = int_size_in_bytes (type);
473 info->num_bytes = GET_MODE_SIZE (mode);
475 num_words = (info->num_bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
476 max_regs = ARG_REG_NUM - info->reg_offset;
478 /* Partition the argument between registers and stack. */
479 info->reg_words = MIN (num_words, max_regs);
480 info->stack_words = num_words - info->reg_words;
482 /* The alignment applied to registers is also applied to stack arguments. */
483 if (info->stack_words)
485 info->stack_offset = cum->stack_words;
487 info->stack_offset += info->stack_offset & 1;
491 /* Set up the stack and frame (if desired) for the function. */
493 score3_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
496 struct score3_frame_info *f = score3_cached_frame ();
497 HOST_WIDE_INT tsize = f->total_size;
499 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
500 if (!flag_inhibit_size_directive)
502 fputs ("\t.ent\t", file);
503 assemble_name (file, fnname);
506 assemble_name (file, fnname);
509 if (!flag_inhibit_size_directive)
512 "\t.frame\t%s," HOST_WIDE_INT_PRINT_DEC ",%s, %d\t\t"
513 "# vars= " HOST_WIDE_INT_PRINT_DEC ", regs= %d"
514 ", args= " HOST_WIDE_INT_PRINT_DEC
515 ", gp= " HOST_WIDE_INT_PRINT_DEC "\n",
516 (reg_names[(frame_pointer_needed)
517 ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM]),
519 reg_names[RA_REGNUM],
520 current_function_is_leaf ? 1 : 0,
526 fprintf(file, "\t.mask\t0x%08x," HOST_WIDE_INT_PRINT_DEC "\n",
528 (f->gp_sp_offset - f->total_size));
532 /* Do any necessary cleanup after a function to restore stack, frame,
535 score3_function_epilogue (FILE *file,
536 HOST_WIDE_INT size ATTRIBUTE_UNUSED)
538 if (!flag_inhibit_size_directive)
541 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
542 fputs ("\t.end\t", file);
543 assemble_name (file, fnname);
548 /* Returns true if X contains a SYMBOL_REF. */
550 score3_symbolic_expression_p (rtx x)
552 if (GET_CODE (x) == SYMBOL_REF)
555 if (GET_CODE (x) == CONST)
556 return score3_symbolic_expression_p (XEXP (x, 0));
559 return score3_symbolic_expression_p (XEXP (x, 0));
561 if (ARITHMETIC_P (x))
562 return (score3_symbolic_expression_p (XEXP (x, 0))
563 || score3_symbolic_expression_p (XEXP (x, 1)));
568 /* Choose the section to use for the constant rtx expression X that has
571 score3_select_rtx_section (enum machine_mode mode, rtx x,
572 unsigned HOST_WIDE_INT align)
574 if (GET_MODE_SIZE (mode) <= SCORE3_SDATA_MAX)
575 return get_named_section (0, ".sdata", 0);
576 else if (flag_pic && score3_symbolic_expression_p (x))
577 return get_named_section (0, ".data.rel.ro", 3);
579 return mergeable_constant_section (mode, align, 0);
582 /* Implement TARGET_IN_SMALL_DATA_P. */
584 score3_in_small_data_p (tree decl)
588 if (TREE_CODE (decl) == STRING_CST
589 || TREE_CODE (decl) == FUNCTION_DECL)
592 if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl) != 0)
595 name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
596 if (strcmp (name, ".sdata") != 0
597 && strcmp (name, ".sbss") != 0)
599 if (!DECL_EXTERNAL (decl))
602 size = int_size_in_bytes (TREE_TYPE (decl));
603 return (size > 0 && size <= SCORE3_SDATA_MAX);
606 /* Implement TARGET_ASM_FILE_START. */
608 score3_asm_file_start (void)
610 default_file_start ();
611 fprintf (asm_out_file, ASM_COMMENT_START
612 "GCC for S+core %s \n", SCORE_GCC_VERSION);
615 fprintf (asm_out_file, "\t.set pic\n");
618 /* Implement TARGET_ASM_FILE_END. When using assembler macros, emit
619 .externs for any small-data variables that turned out to be external. */
621 score3_asm_file_end (void)
624 struct extern_list *p;
627 fputs ("\n", asm_out_file);
628 for (p = extern_head; p != 0; p = p->next)
630 name_tree = get_identifier (p->name);
631 if (!TREE_ASM_WRITTEN (name_tree)
632 && TREE_SYMBOL_REFERENCED (name_tree))
634 TREE_ASM_WRITTEN (name_tree) = 1;
635 fputs ("\t.extern\t", asm_out_file);
636 assemble_name (asm_out_file, p->name);
637 fprintf (asm_out_file, ", %d\n", p->size);
643 /* Implement OVERRIDE_OPTIONS macro. */
645 score3_override_options (void)
649 score3_sdata_max = g_switch_set ? g_switch_value : SCORE3_DEFAULT_SDATA_MAX;
652 score3_sdata_max = 0;
653 if (g_switch_set && (g_switch_value != 0))
654 warning (0, "-fPIC and -G are incompatible");
657 score_char_to_class['d'] = G32_REGS;
658 score_char_to_class['e'] = G16_REGS;
659 score_char_to_class['t'] = T32_REGS;
661 score_char_to_class['h'] = HI_REG;
662 score_char_to_class['l'] = LO_REG;
663 score_char_to_class['x'] = CE_REGS;
665 score_char_to_class['q'] = CN_REG;
666 score_char_to_class['y'] = LC_REG;
667 score_char_to_class['z'] = SC_REG;
668 score_char_to_class['a'] = SP_REGS;
670 score_char_to_class['c'] = CR_REGS;
673 /* Implement REGNO_REG_CLASS macro. */
675 score3_reg_class (int regno)
678 gcc_assert (regno >= 0 && regno < FIRST_PSEUDO_REGISTER);
680 if (regno == FRAME_POINTER_REGNUM
681 || regno == ARG_POINTER_REGNUM)
684 for (c = 0; c < N_REG_CLASSES; c++)
685 if (TEST_HARD_REG_BIT (reg_class_contents[c], regno))
691 /* Implement PREFERRED_RELOAD_CLASS macro. */
693 score3_preferred_reload_class (rtx x ATTRIBUTE_UNUSED, enum reg_class class)
695 if (reg_class_subset_p (G16_REGS, class))
697 if (reg_class_subset_p (G32_REGS, class))
702 /* Implement SECONDARY_INPUT_RELOAD_CLASS
703 and SECONDARY_OUTPUT_RELOAD_CLASS macro. */
705 score3_secondary_reload_class (enum reg_class class,
706 enum machine_mode mode ATTRIBUTE_UNUSED,
710 if (GET_CODE (x) == REG || GET_CODE(x) == SUBREG)
711 regno = true_regnum (x);
713 if (!GR_REG_CLASS_P (class))
714 return GP_REG_P (regno) ? NO_REGS : G32_REGS;
718 /* Implement CONST_OK_FOR_LETTER_P macro. */
730 score3_const_ok_for_letter_p (HOST_WIDE_INT value, char c)
734 case 'I': return ((value & 0xffff) == 0);
735 case 'J': return IMM_IN_RANGE (value, 5, 0);
736 case 'K': return IMM_IN_RANGE (value, 16, 0);
737 case 'L': return IMM_IN_RANGE (value, 16, 1);
738 case 'M': return IMM_IN_RANGE (value, 14, 0);
739 case 'N': return IMM_IN_RANGE (value, 14, 1);
740 case 'O': return IMM_IN_RANGE (value, 5, 1);
741 case 'P': return IMM_IN_RANGE (value, 6, 1);
742 case 'Q': return score_extra_constraint (GEN_INT(value), c);
747 /* Implement EXTRA_CONSTRAINT macro. */
752 score3_extra_constraint (rtx op, char c)
756 case 'Q': return IMM_IN_RANGE (INTVAL(op), 32, 0);
758 return GET_CODE (op) == SYMBOL_REF;
764 /* Return truth value on whether or not a given hard register
765 can support a given mode. */
767 score3_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
769 int size = GET_MODE_SIZE (mode);
770 enum mode_class class = GET_MODE_CLASS (mode);
772 if (class == MODE_CC)
773 return regno == CC_REGNUM;
774 else if (regno == FRAME_POINTER_REGNUM
775 || regno == ARG_POINTER_REGNUM)
776 return class == MODE_INT;
777 else if (GP_REG_P (regno))
778 return !(regno & 1) || (size <= UNITS_PER_WORD);
779 else if (CE_REG_P (regno))
780 return (class == MODE_INT
781 && ((size <= UNITS_PER_WORD)
782 || (regno == CE_REG_FIRST && size == 2 * UNITS_PER_WORD)));
784 return (class == MODE_INT) && (size <= UNITS_PER_WORD);
787 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
788 pointer or argument pointer. TO is either the stack pointer or
789 hard frame pointer. */
791 score3_initial_elimination_offset (int from,
792 int to ATTRIBUTE_UNUSED)
794 struct score3_frame_info *f = score3_compute_frame_size (get_frame_size ());
797 case ARG_POINTER_REGNUM:
798 return f->total_size;
799 case FRAME_POINTER_REGNUM:
806 /* Implement FUNCTION_ARG_ADVANCE macro. */
808 score3_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
809 tree type, int named)
811 struct score3_arg_info info;
812 score3_classify_arg (cum, mode, type, named, &info);
813 cum->num_gprs = info.reg_offset + info.reg_words;
814 if (info.stack_words > 0)
815 cum->stack_words = info.stack_offset + info.stack_words;
819 /* Implement TARGET_ARG_PARTIAL_BYTES macro. */
821 score3_arg_partial_bytes (CUMULATIVE_ARGS *cum,
822 enum machine_mode mode, tree type, bool named)
824 struct score3_arg_info info;
825 score3_classify_arg (cum, mode, type, named, &info);
826 return info.stack_words > 0 ? info.reg_words * UNITS_PER_WORD : 0;
829 /* Implement FUNCTION_ARG macro. */
831 score3_function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
832 tree type, int named)
834 struct score3_arg_info info;
836 if (mode == VOIDmode || !named)
839 score3_classify_arg (cum, mode, type, named, &info);
841 if (info.reg_offset == ARG_REG_NUM)
844 if (!info.stack_words)
845 return gen_rtx_REG (mode, ARG_REG_FIRST + info.reg_offset);
848 rtx ret = gen_rtx_PARALLEL (mode, rtvec_alloc (info.reg_words));
849 unsigned int i, part_offset = 0;
850 for (i = 0; i < info.reg_words; i++)
853 reg = gen_rtx_REG (SImode, ARG_REG_FIRST + info.reg_offset + i);
854 XVECEXP (ret, 0, i) = gen_rtx_EXPR_LIST (SImode, reg,
855 GEN_INT (part_offset));
856 part_offset += UNITS_PER_WORD;
862 /* Implement FUNCTION_VALUE and LIBCALL_VALUE. For normal calls,
863 VALTYPE is the return type and MODE is VOIDmode. For libcalls,
864 VALTYPE is null and MODE is the mode of the return value. */
866 score3_function_value (tree valtype, tree func ATTRIBUTE_UNUSED,
867 enum machine_mode mode)
872 mode = TYPE_MODE (valtype);
873 unsignedp = TYPE_UNSIGNED (valtype);
874 mode = promote_mode (valtype, mode, &unsignedp, 1);
876 return gen_rtx_REG (mode, RT_REGNUM);
879 /* Implement INITIALIZE_TRAMPOLINE macro. */
881 score3_initialize_trampoline (rtx ADDR, rtx FUNC, rtx CHAIN)
883 #define FFCACHE "_flush_cache"
884 #define CODE_SIZE (TRAMPOLINE_INSNS * UNITS_PER_WORD)
888 pfunc = plus_constant (ADDR, CODE_SIZE);
889 pchain = plus_constant (ADDR, CODE_SIZE + GET_MODE_SIZE (SImode));
891 emit_move_insn (gen_rtx_MEM (SImode, pfunc), FUNC);
892 emit_move_insn (gen_rtx_MEM (SImode, pchain), CHAIN);
893 emit_library_call (gen_rtx_SYMBOL_REF (Pmode, FFCACHE),
896 GEN_INT (TRAMPOLINE_SIZE), SImode);
901 /* This function is used to implement REG_MODE_OK_FOR_BASE_P macro. */
903 score3_regno_mode_ok_for_base_p (int regno, int strict)
905 if (regno >= FIRST_PSEUDO_REGISTER)
909 regno = reg_renumber[regno];
911 if (regno == ARG_POINTER_REGNUM
912 || regno == FRAME_POINTER_REGNUM)
914 return GP_REG_P (regno);
917 /* Implement GO_IF_LEGITIMATE_ADDRESS macro. */
919 score3_address_p (enum machine_mode mode, rtx x, int strict)
921 struct score3_address_info addr;
923 return score3_classify_address (&addr, mode, x, strict);
926 /* Return a number assessing the cost of moving a register in class
929 score3_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
930 enum reg_class from, enum reg_class to)
932 if (GR_REG_CLASS_P (from))
934 if (GR_REG_CLASS_P (to))
936 else if (SP_REG_CLASS_P (to))
938 else if (CP_REG_CLASS_P (to))
940 else if (CE_REG_CLASS_P (to))
943 if (GR_REG_CLASS_P (to))
945 if (GR_REG_CLASS_P (from))
947 else if (SP_REG_CLASS_P (from))
949 else if (CP_REG_CLASS_P (from))
951 else if (CE_REG_CLASS_P (from))
957 /* Return the number of instructions needed to load a symbol of the
958 given type into a register. */
960 score3_symbol_insns (enum score_symbol_type type)
967 case SYMBOL_SMALL_DATA:
974 /* Return the number of instructions needed to load or store a value
975 of mode MODE at X. Return 0 if X isn't valid for MODE. */
977 score3_address_insns (rtx x, enum machine_mode mode)
979 struct score3_address_info addr;
985 factor = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
987 if (score3_classify_address (&addr, mode, x, false))
991 case SCORE3_ADD_CONST_INT:
994 case SCORE3_ADD_SYMBOLIC:
995 return factor * score3_symbol_insns (addr.symbol_type);
1000 /* Implement TARGET_RTX_COSTS macro. */
1002 score3_rtx_costs (rtx x, int code, int outer_code, int *total)
1004 enum machine_mode mode = GET_MODE (x);
1009 if (outer_code == SET)
1011 if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
1012 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L'))
1013 *total = COSTS_N_INSNS (1);
1015 *total = COSTS_N_INSNS (2);
1017 else if (outer_code == PLUS || outer_code == MINUS)
1019 if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'N'))
1021 else if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
1022 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L'))
1025 *total = COSTS_N_INSNS (2);
1027 else if (outer_code == AND || outer_code == IOR)
1029 if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'M'))
1031 else if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
1032 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'K'))
1035 *total = COSTS_N_INSNS (2);
1047 *total = COSTS_N_INSNS (2);
1052 /* If the address is legitimate, return the number of
1053 instructions it needs, otherwise use the default handling. */
1054 int n = score3_address_insns (XEXP (x, 0), GET_MODE (x));
1057 *total = COSTS_N_INSNS (n + 1);
1064 *total = COSTS_N_INSNS (6);
1068 *total = COSTS_N_INSNS (1);
1076 *total = COSTS_N_INSNS (2);
1086 *total = COSTS_N_INSNS ((GET_CODE (XEXP (x, 1)) == CONST_INT)
1093 *total = COSTS_N_INSNS (4);
1100 *total = COSTS_N_INSNS (4);
1103 *total = COSTS_N_INSNS (1);
1109 *total = COSTS_N_INSNS (4);
1115 *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (12);
1122 *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (33);
1127 switch (GET_MODE (XEXP (x, 0)))
1131 if (GET_CODE (XEXP (x, 0)) == MEM)
1133 *total = COSTS_N_INSNS (2);
1135 if (!TARGET_LITTLE_ENDIAN &&
1136 side_effects_p (XEXP (XEXP (x, 0), 0)))
1140 *total = COSTS_N_INSNS (1);
1144 *total = COSTS_N_INSNS (1);
1154 /* Implement TARGET_ADDRESS_COST macro. */
1156 score3_address_cost (rtx addr)
1158 return score3_address_insns (addr, SImode);
1161 /* Implement ASM_OUTPUT_EXTERNAL macro. */
1163 score3_output_external (FILE *file ATTRIBUTE_UNUSED,
1164 tree decl, const char *name)
1166 register struct extern_list *p;
1168 if (score3_in_small_data_p (decl))
1170 p = (struct extern_list *) ggc_alloc (sizeof (struct extern_list));
1171 p->next = extern_head;
1173 p->size = int_size_in_bytes (TREE_TYPE (decl));
1179 /* Implement RETURN_ADDR_RTX. Note, we do not support moving
1180 back to a previous frame. */
1182 score3_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
1186 return get_hard_reg_initial_val (Pmode, RA_REGNUM);
1189 /* Implement PRINT_OPERAND macro. */
1190 /* Score-specific operand codes:
1191 '[' print .set nor1 directive
1192 ']' print .set r1 directive
1193 'U' print hi part of a CONST_INT rtx
1196 'D' print SFmode const double
1197 'S' selectively print "!" if operand is 15bit instruction accessible
1198 'V' print "v!" if operand is 15bit instruction accessible, or "lfh!"
1199 'L' low part of DImode reg operand
1200 'H' high part of DImode reg operand
1201 'C' print part of opcode for a branch condition. */
1203 score3_print_operand (FILE *file, rtx op, int c)
1205 enum rtx_code code = -1;
1206 if (!PRINT_OPERAND_PUNCT_VALID_P (c))
1207 code = GET_CODE (op);
1211 fprintf (file, ".set r1\n");
1215 fprintf (file, "\n\t.set nor1");
1219 gcc_assert (code == CONST_INT);
1220 fprintf (file, HOST_WIDE_INT_PRINT_HEX,
1221 (INTVAL (op) >> 16) & 0xffff);
1225 if (GET_CODE (op) == CONST_DOUBLE)
1227 rtx temp = gen_lowpart (SImode, op);
1228 gcc_assert (GET_MODE (op) == SFmode);
1229 fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (temp) & 0xffffffff);
1232 output_addr_const (file, op);
1236 gcc_assert (code == REG);
1237 if (G16_REG_P (REGNO (op)))
1238 fprintf (file, "!");
1242 gcc_assert (code == REG);
1243 fprintf (file, G16_REG_P (REGNO (op)) ? "v!" : "lfh!");
1247 enum machine_mode mode = GET_MODE (XEXP (op, 0));
1251 case EQ: fputs ("eq!", file); break;
1252 case NE: fputs ("ne!", file); break;
1253 case GT: fputs ("gt!", file); break;
1254 case GE: fputs (mode != CCmode ? "pl" : "ge", file); break;
1255 case LT: fputs (mode != CCmode ? "mi" : "lt", file); break;
1256 case LE: fputs ("le!", file); break;
1257 case GTU: fputs ("gtu!", file); break;
1258 case GEU: fputs ("cs", file); break;
1259 case LTU: fputs ("cc", file); break;
1260 case LEU: fputs ("leu!", file); break;
1262 output_operand_lossage ("invalid operand for code: '%c'", code);
1265 else if (c == 'G') /* Seperate from b<cond>, use for mv<cond>. */
1267 enum machine_mode mode = GET_MODE (XEXP (op, 0));
1271 case EQ: fputs ("eq", file); break;
1272 case NE: fputs ("ne", file); break;
1273 case GT: fputs ("gt", file); break;
1274 case GE: fputs (mode != CCmode ? "pl" : "ge", file); break;
1275 case LT: fputs (mode != CCmode ? "mi" : "lt", file); break;
1276 case LE: fputs ("le", file); break;
1277 case GTU: fputs ("gtu", file); break;
1278 case GEU: fputs ("cs", file); break;
1279 case LTU: fputs ("cc", file); break;
1280 case LEU: fputs ("leu", file); break;
1282 output_operand_lossage ("invalid operand for code: '%c'", code);
1287 unsigned HOST_WIDE_INT i;
1288 unsigned HOST_WIDE_INT pow2mask = 1;
1289 unsigned HOST_WIDE_INT val;
1292 for (i = 0; i < 32; i++)
1294 if (val == pow2mask)
1298 gcc_assert (i < 32);
1299 fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
1303 unsigned HOST_WIDE_INT i;
1304 unsigned HOST_WIDE_INT pow2mask = 1;
1305 unsigned HOST_WIDE_INT val;
1308 for (i = 0; i < 32; i++)
1310 if (val == pow2mask)
1314 gcc_assert (i < 32);
1315 fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
1317 else if (code == REG)
1319 int regnum = REGNO (op);
1320 if ((c == 'H' && !WORDS_BIG_ENDIAN)
1321 || (c == 'L' && WORDS_BIG_ENDIAN))
1323 fprintf (file, "%s", reg_names[regnum]);
1330 score3_print_operand_address (file, op);
1333 output_addr_const (file, op);
1338 /* Implement PRINT_OPERAND_ADDRESS macro. */
1340 score3_print_operand_address (FILE *file, rtx x)
1342 struct score3_address_info addr;
1343 enum rtx_code code = GET_CODE (x);
1344 enum machine_mode mode = GET_MODE (x);
1349 if (score3_classify_address (&addr, mode, x, true))
1353 case SCORE3_ADD_REG:
1358 fprintf (file, "[%s,-%ld]+", reg_names[REGNO (addr.reg)],
1359 INTVAL (addr.offset));
1362 fprintf (file, "[%s]+,-%ld", reg_names[REGNO (addr.reg)],
1363 INTVAL (addr.offset));
1366 fprintf (file, "[%s, %ld]+", reg_names[REGNO (addr.reg)],
1367 INTVAL (addr.offset));
1370 fprintf (file, "[%s]+, %ld", reg_names[REGNO (addr.reg)],
1371 INTVAL (addr.offset));
1374 if (INTVAL(addr.offset) == 0)
1375 fprintf(file, "[%s]", reg_names[REGNO (addr.reg)]);
1377 fprintf(file, "[%s, %ld]", reg_names[REGNO (addr.reg)],
1378 INTVAL(addr.offset));
1383 case SCORE3_ADD_CONST_INT:
1384 case SCORE3_ADD_SYMBOLIC:
1385 output_addr_const (file, x);
1389 print_rtl (stderr, x);
1393 /* Implement SELECT_CC_MODE macro. */
1395 score3_select_cc_mode (enum rtx_code op, rtx x, rtx y)
1397 if ((op == EQ || op == NE || op == LT || op == GE)
1399 && GET_MODE (x) == SImode)
1401 switch (GET_CODE (x))
1419 return (op == LT || op == GE) ? CC_Nmode : CCmode;
1426 if ((op == EQ || op == NE)
1427 && (GET_CODE (y) == NEG)
1428 && register_operand (XEXP (y, 0), SImode)
1429 && register_operand (x, SImode))
1437 #define EMIT_PL(_rtx) RTX_FRAME_RELATED_P (_rtx) = 1
1438 /* return 0, no more bit set in mask. */
1439 static int rpush_first (int mask, int sb, int *rd)
1443 if ((mask & (1 << sb)) == 0)
1448 for (i = sb-1; i >= 0; i--)
1450 if (mask & (1 << i))
1464 rpush (int rd, int cnt)
1466 rtx mem = gen_rtx_MEM (SImode, gen_rtx_PRE_DEC (SImode, stack_pointer_rtx));
1467 rtx reg = gen_rtx_REG (SImode, rd);
1469 if (!current_function_calls_eh_return)
1470 MEM_READONLY_P (mem) = 1;
1473 EMIT_PL (emit_insn (gen_pushsi_score3 (mem, reg)));
1477 rtx insn = gen_store_multiple (gen_rtx_MEM (SImode, stack_pointer_rtx),
1478 gen_rtx_REG (SImode, rd),
1481 rtx pat = PATTERN (insn);
1483 for (i = 0; i < XVECLEN (pat, 0); i++)
1484 if (GET_CODE (XVECEXP (pat, 0, i)) == SET)
1485 RTX_FRAME_RELATED_P (XVECEXP (pat, 0, i)) = 1;
1487 EMIT_PL (emit_insn (insn));
1491 /* Generate the prologue instructions for entry into a S+core function. */
1493 score3_prologue (void)
1495 struct score3_frame_info *f = score3_compute_frame_size (get_frame_size ());
1499 size = f->total_size - f->gp_reg_size;
1502 emit_insn (gen_cpload_score3 ());
1507 for (regno = (int) GP_REG_LAST; regno >= (int) GP_REG_FIRST; regno--)
1509 cnt = rpush_first (f->mask, regno, &rd);
1513 regno = regno - cnt;
1522 if (CONST_OK_FOR_LETTER_P (-size, 'L'))
1523 EMIT_PL (emit_insn (gen_add3_insn (stack_pointer_rtx,
1528 EMIT_PL (emit_move_insn (gen_rtx_REG (Pmode, SCORE3_PROLOGUE_TEMP_REGNUM),
1531 (gen_sub3_insn (stack_pointer_rtx,
1534 SCORE3_PROLOGUE_TEMP_REGNUM))));
1536 insn = get_last_insn ();
1538 alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR,
1539 gen_rtx_SET (VOIDmode, stack_pointer_rtx,
1540 plus_constant (stack_pointer_rtx,
1545 if (frame_pointer_needed)
1546 EMIT_PL (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx));
1548 if (flag_pic && f->cprestore_size)
1550 if (frame_pointer_needed)
1551 emit_insn (gen_cprestore_use_fp_score3 (GEN_INT (size - f->cprestore_size)));
1553 emit_insn (gen_cprestore_use_sp_score3 (GEN_INT (size - f->cprestore_size)));
1557 /* return 0, no more bit set in mask. */
1559 rpop_first (int mask, int sb, int *rd)
1563 if ((mask & (1 << sb)) == 0)
1568 for (i = sb+1; i < 32; i++)
1569 if (mask & (1 << i))
1578 rpop (int rd, int cnt)
1580 rtx mem = gen_rtx_MEM (SImode, gen_rtx_POST_INC (SImode, stack_pointer_rtx));
1581 rtx reg = gen_rtx_REG (SImode, rd);
1583 if (!current_function_calls_eh_return)
1584 MEM_READONLY_P (mem) = 1;
1587 emit_insn (gen_popsi_score3 (reg, mem));
1589 emit_insn (gen_load_multiple (reg,
1590 gen_rtx_MEM (SImode, stack_pointer_rtx),
1594 /* Generate the epilogue instructions in a S+core function. */
1596 score3_epilogue (int sibcall_p)
1598 struct score3_frame_info *f = score3_compute_frame_size (get_frame_size ());
1603 size = f->total_size - f->gp_reg_size;
1605 if (!frame_pointer_needed)
1606 base = stack_pointer_rtx;
1608 base = hard_frame_pointer_rtx;
1612 if (CONST_OK_FOR_LETTER_P (size, 'L'))
1613 emit_insn (gen_add3_insn (base, base, GEN_INT (size)));
1616 emit_move_insn (gen_rtx_REG (Pmode, SCORE3_EPILOGUE_TEMP_REGNUM),
1618 emit_insn (gen_add3_insn (base, base,
1620 SCORE3_EPILOGUE_TEMP_REGNUM)));
1624 if (base != stack_pointer_rtx)
1625 emit_move_insn (stack_pointer_rtx, base);
1627 if (current_function_calls_eh_return)
1628 emit_insn (gen_add3_insn (stack_pointer_rtx,
1630 EH_RETURN_STACKADJ_RTX));
1635 for (regno = (int) GP_REG_FIRST; regno <= (int) GP_REG_LAST; regno++)
1637 cnt = rpop_first (f->mask, regno, &rd);
1641 regno = regno + cnt;
1647 emit_jump_insn (gen_return_internal_score3 (gen_rtx_REG (Pmode, RA_REGNUM)));
1651 score3_gen_cmp (enum machine_mode mode)
1653 emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (mode, CC_REGNUM),
1654 gen_rtx_COMPARE (mode, cmp_op0, cmp_op1)));
1657 /* Return true if X is a symbolic constant that can be calculated in
1658 the same way as a bare symbol. If it is, store the type of the
1659 symbol in *SYMBOL_TYPE. */
1661 score3_symbolic_constant_p (rtx x, enum score_symbol_type *symbol_type)
1663 HOST_WIDE_INT offset;
1665 score3_split_const (x, &x, &offset);
1666 if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF)
1667 *symbol_type = score3_classify_symbol (x);
1674 /* if offset > 15bit, must reload */
1675 if (!IMM_IN_RANGE (offset, 15, 1))
1678 switch (*symbol_type)
1680 case SYMBOL_GENERAL:
1682 case SYMBOL_SMALL_DATA:
1683 return score3_offset_within_object_p (x, offset);
1689 score3_movsicc (rtx *ops)
1691 enum machine_mode mode;
1693 mode = score3_select_cc_mode (GET_CODE (ops[1]), ops[2], ops[3]);
1694 emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (mode, CC_REGNUM),
1695 gen_rtx_COMPARE (mode, cmp_op0, cmp_op1)));
1698 /* Call and sibcall pattern all need call this function. */
1700 score3_call (rtx *ops, bool sib)
1702 rtx addr = XEXP (ops[0], 0);
1703 if (!call_insn_operand (addr, VOIDmode))
1706 addr = gen_reg_rtx (Pmode);
1707 gen_move_insn (addr, oaddr);
1711 emit_call_insn (gen_sibcall_internal_score3 (addr, ops[1]));
1713 emit_call_insn (gen_call_internal_score3 (addr, ops[1]));
1716 /* Call value and sibcall value pattern all need call this function. */
1718 score3_call_value (rtx *ops, bool sib)
1720 rtx result = ops[0];
1721 rtx addr = XEXP (ops[1], 0);
1724 if (!call_insn_operand (addr, VOIDmode))
1727 addr = gen_reg_rtx (Pmode);
1728 gen_move_insn (addr, oaddr);
1732 emit_call_insn (gen_sibcall_value_internal_score3 (result, addr, arg));
1734 emit_call_insn (gen_call_value_internal_score3 (result, addr, arg));
1739 score3_movdi (rtx *ops)
1743 rtx dst0 = score3_subw (dst, 0);
1744 rtx dst1 = score3_subw (dst, 1);
1745 rtx src0 = score3_subw (src, 0);
1746 rtx src1 = score3_subw (src, 1);
1748 if (GET_CODE (dst0) == REG && reg_overlap_mentioned_p (dst0, src))
1750 emit_move_insn (dst1, src1);
1751 emit_move_insn (dst0, src0);
1755 emit_move_insn (dst0, src0);
1756 emit_move_insn (dst1, src1);
1761 score3_zero_extract_andi (rtx *ops)
1763 if (INTVAL (ops[1]) == 1 && const_uimm5 (ops[2], SImode))
1764 emit_insn (gen_zero_extract_bittst_score3 (ops[0], ops[2]));
1767 unsigned HOST_WIDE_INT mask;
1768 mask = (0xffffffffU & ((1U << INTVAL (ops[1])) - 1U));
1769 mask = mask << INTVAL (ops[2]);
1770 emit_insn (gen_andsi3_cmp_score3 (ops[3], ops[0],
1771 gen_int_mode (mask, SImode)));
1776 score3_rpush (rtx *ops)
1778 snprintf (score3_ins, INS_BUF_SZ, "rpush!\t%%1, %d", XVECLEN (ops[0], 0));
1783 score3_rpop (rtx *ops)
1785 snprintf (score3_ins, INS_BUF_SZ, "rpop!\t%%1, %d", XVECLEN (ops[0], 0));
1789 /* Output asm code for ld/sw insn. */
1791 score3_pr_addr_post (rtx *ops, int idata, int iaddr, char *ip,
1792 enum score_mem_unit unit ATTRIBUTE_UNUSED)
1794 struct score3_address_info ai;
1796 gcc_assert (GET_CODE (ops[idata]) == REG);
1797 gcc_assert (score3_classify_address (&ai, SImode, XEXP (ops[iaddr], 0), true));
1799 if (ai.type == SCORE3_ADD_REG
1801 && GET_CODE (ai.offset) == CONST_INT
1802 && G16_REG_P (REGNO (ops[idata]))
1803 && G8_REG_P (REGNO (ai.reg))
1804 && ((INTVAL (ai.offset) & 3) == 0)
1805 && (IMM_IN_RANGE (INTVAL (ai.offset), 7, 0)))
1807 ops[iaddr] = ai.reg;
1808 return snprintf (ip, INS_BUF_SZ, "!\t%%%d, [%%%d, "
1809 HOST_WIDE_INT_PRINT_DEC "]",
1810 idata, iaddr, INTVAL (ai.offset));
1813 if (ai.type == SCORE3_ADD_SYMBOLIC)
1814 return snprintf (ip, INS_BUF_SZ, "48\t%%%d, %%a%d", idata, iaddr);
1816 return snprintf (ip, INS_BUF_SZ, "\t%%%d, %%a%d", idata, iaddr);
1819 /* Output asm insn for load. */
1821 score3_linsn (rtx *ops, enum score_mem_unit unit, bool sign)
1823 const char *pre_ins[] =
1824 {"lbu", "lhu", "lw", "??", "lb", "lh", "lw", "??"};
1827 strcpy (score3_ins, pre_ins[(sign ? 4 : 0) + unit]);
1828 ip = score3_ins + strlen (score3_ins);
1830 if (unit == SCORE_WORD)
1831 score3_pr_addr_post (ops, 0, 1, ip, unit);
1833 snprintf (ip, INS_BUF_SZ, "\t%%0, %%a1");
1838 /* Output asm insn for store. */
1840 score3_sinsn (rtx *ops, enum score_mem_unit unit)
1842 const char *pre_ins[] = {"sb", "sh", "sw"};
1845 strcpy (score3_ins, pre_ins[unit]);
1846 ip = score3_ins + strlen (score3_ins);
1848 if (unit == SCORE_WORD)
1849 score3_pr_addr_post (ops, 1, 0, ip, unit);
1851 snprintf (ip, INS_BUF_SZ, "\t%%1, %%a0");
1856 /* Output asm insn for load immediate. */
1858 score3_limm (rtx *ops)
1862 gcc_assert (GET_CODE (ops[0]) == REG);
1863 gcc_assert (GET_CODE (ops[1]) == CONST_INT);
1865 v = INTVAL (ops[1]);
1866 if (G16_REG_P (REGNO (ops[0])) && IMM_IN_RANGE (v, 5, 0))
1867 return "ldiu!\t%0, %c1";
1868 else if (IMM_IN_RANGE (v, 16, 1))
1869 return "ldi\t%0, %c1";
1870 else if ((v & 0xffff) == 0)
1871 return "ldis\t%0, %U1";
1873 return "li\t%0, %c1";
1876 /* Output asm insn for move. */
1878 score3_move (rtx *ops)
1880 gcc_assert (GET_CODE (ops[0]) == REG);
1881 gcc_assert (GET_CODE (ops[1]) == REG);
1883 return "mv!\t%0, %1";
1886 /* Generate add insn. */
1888 score3_select_add_imm (rtx *ops, bool set_cc)
1890 HOST_WIDE_INT v = INTVAL (ops[2]);
1892 gcc_assert (GET_CODE (ops[2]) == CONST_INT);
1893 gcc_assert (REGNO (ops[0]) == REGNO (ops[1]));
1896 return "addi.c\t%0, %c2";
1898 if (IMM_IN_RANGE (v, 6, 1) && G16_REG_P (REGNO (ops[0])))
1899 return "addi!\t%0, %c2";
1901 return "addi\t%0, %c2";
1904 /* Output arith insn. */
1906 score3_select (rtx *ops, const char *inst_pre, bool commu ATTRIBUTE_UNUSED,
1907 const char *letter, bool set_cc)
1909 gcc_assert (GET_CODE (ops[0]) == REG);
1910 gcc_assert (GET_CODE (ops[1]) == REG);
1913 snprintf (score3_ins, INS_BUF_SZ, "%s.c\t%%0, %%1, %%%s2", inst_pre, letter);
1915 snprintf (score3_ins, INS_BUF_SZ, "%s\t%%0, %%1, %%%s2", inst_pre, letter);
1919 /* Output a Score3 casesi instruction. */
1921 score3_output_casesi (rtx *operands)
1923 rtx diff_vec = PATTERN (next_real_insn (operands[2]));
1924 gcc_assert (GET_CODE (diff_vec) == ADDR_DIFF_VEC);
1926 output_asm_insn ("cmpi.c\t%0, %1", operands);
1927 output_asm_insn ("bgtu\t%3", operands);
1928 switch (GET_MODE(diff_vec))
1931 output_asm_insn ("ldi48\t%4, %2", operands);
1932 output_asm_insn ("ltbb\t%4, [%4, %0]\n%2_tbb:", operands);
1935 output_asm_insn ("ldi48\t%4, %2", operands);
1936 output_asm_insn ("ltbh\t%4, [%4, %0]\n%2_tbb:", operands);
1939 output_asm_insn ("ldi48\t%4, %2", operands);
1940 output_asm_insn ("ltbw\t%4, [%4, %0]", operands);