1 /* score7.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 score7_sdata_max;
62 static char score7_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 score7_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 score7_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 score7_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)) <= SCORE7_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 score7_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 score7_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 score7_frame_info *
168 score7_cached_frame (void)
170 static struct score7_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 score7_frame_info *
177 score7_compute_frame_size (HOST_WIDE_INT size)
180 struct score7_frame_info *f = score7_cached_frame ();
182 memset (f, 0, sizeof (struct score7_frame_info));
185 f->var_size = SCORE7_STACK_ALIGN (size);
186 f->args_size = current_function_outgoing_args_size;
187 f->cprestore_size = flag_pic ? UNITS_PER_WORD : 0;
188 if (f->var_size == 0 && current_function_is_leaf)
189 f->args_size = f->cprestore_size = 0;
191 if (f->args_size == 0 && current_function_calls_alloca)
192 f->args_size = UNITS_PER_WORD;
194 f->total_size = f->var_size + f->args_size + f->cprestore_size;
195 for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
197 if (score7_save_reg_p (regno))
199 f->gp_reg_size += GET_MODE_SIZE (SImode);
200 f->mask |= 1 << (regno - GP_REG_FIRST);
204 if (current_function_calls_eh_return)
209 regno = EH_RETURN_DATA_REGNO (i);
210 if (regno == INVALID_REGNUM)
212 f->gp_reg_size += GET_MODE_SIZE (SImode);
213 f->mask |= 1 << (regno - GP_REG_FIRST);
217 f->total_size += f->gp_reg_size;
218 f->num_gp = f->gp_reg_size / UNITS_PER_WORD;
222 HOST_WIDE_INT offset;
223 offset = (f->args_size + f->cprestore_size + f->var_size
224 + f->gp_reg_size - GET_MODE_SIZE (SImode));
225 f->gp_sp_offset = offset;
233 /* Return true if X is a valid base register for the given mode.
234 Allow only hard registers if STRICT. */
236 score7_valid_base_register_p (rtx x, int strict)
238 if (!strict && GET_CODE (x) == SUBREG)
241 return (GET_CODE (x) == REG
242 && score7_regno_mode_ok_for_base_p (REGNO (x), strict));
245 /* Return true if X is a valid address for machine mode MODE. If it is,
246 fill in INFO appropriately. STRICT is true if we should only accept
247 hard base registers. */
249 score7_classify_address (struct score7_address_info *info,
250 enum machine_mode mode, rtx x, int strict)
252 info->code = GET_CODE (x);
258 info->type = SCORE7_ADD_REG;
260 info->offset = const0_rtx;
261 return score7_valid_base_register_p (info->reg, strict);
263 info->type = SCORE7_ADD_REG;
264 info->reg = XEXP (x, 0);
265 info->offset = XEXP (x, 1);
266 return (score7_valid_base_register_p (info->reg, strict)
267 && GET_CODE (info->offset) == CONST_INT
268 && IMM_IN_RANGE (INTVAL (info->offset), 15, 1));
273 if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (SImode))
275 info->type = SCORE7_ADD_REG;
276 info->reg = XEXP (x, 0);
277 info->offset = GEN_INT (GET_MODE_SIZE (mode));
278 return score7_valid_base_register_p (info->reg, strict);
280 info->type = SCORE7_ADD_CONST_INT;
281 return IMM_IN_RANGE (INTVAL (x), 15, 1);
285 info->type = SCORE7_ADD_SYMBOLIC;
286 return (score7_symbolic_constant_p (x, &info->symbol_type)
287 && (info->symbol_type == SYMBOL_GENERAL
288 || info->symbol_type == SYMBOL_SMALL_DATA));
295 score7_return_in_memory (tree type, tree fndecl ATTRIBUTE_UNUSED)
297 return ((TYPE_MODE (type) == BLKmode)
298 || (int_size_in_bytes (type) > 2 * UNITS_PER_WORD)
299 || (int_size_in_bytes (type) == -1));
302 /* Return a legitimate address for REG + OFFSET. */
304 score7_add_offset (rtx reg, HOST_WIDE_INT offset)
306 if (!IMM_IN_RANGE (offset, 15, 1))
308 reg = expand_simple_binop (GET_MODE (reg), PLUS,
309 gen_int_mode (offset & 0xffffc000,
311 reg, NULL, 0, OPTAB_WIDEN);
315 return plus_constant (reg, offset);
318 /* Implement TARGET_ASM_OUTPUT_MI_THUNK. Generate rtl rather than asm text
319 in order to avoid duplicating too much logic from elsewhere. */
321 score7_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
322 HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
325 rtx this, temp1, insn, fnaddr;
327 /* Pretend to be a post-reload pass while generating rtl. */
328 reload_completed = 1;
330 /* Mark the end of the (empty) prologue. */
331 emit_note (NOTE_INSN_PROLOGUE_END);
333 /* We need two temporary registers in some cases. */
334 temp1 = gen_rtx_REG (Pmode, 8);
336 /* Find out which register contains the "this" pointer. */
337 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
338 this = gen_rtx_REG (Pmode, ARG_REG_FIRST + 1);
340 this = gen_rtx_REG (Pmode, ARG_REG_FIRST);
342 /* Add DELTA to THIS. */
345 rtx offset = GEN_INT (delta);
346 if (!CONST_OK_FOR_LETTER_P (delta, 'L'))
348 emit_move_insn (temp1, offset);
351 emit_insn (gen_add3_insn (this, this, offset));
354 /* If needed, add *(*THIS + VCALL_OFFSET) to THIS. */
355 if (vcall_offset != 0)
359 /* Set TEMP1 to *THIS. */
360 emit_move_insn (temp1, gen_rtx_MEM (Pmode, this));
362 /* Set ADDR to a legitimate address for *THIS + VCALL_OFFSET. */
363 addr = score7_add_offset (temp1, vcall_offset);
365 /* Load the offset and add it to THIS. */
366 emit_move_insn (temp1, gen_rtx_MEM (Pmode, addr));
367 emit_insn (gen_add3_insn (this, this, temp1));
370 /* Jump to the target function. */
371 fnaddr = XEXP (DECL_RTL (function), 0);
372 insn = emit_call_insn (gen_sibcall_internal_score7 (fnaddr, const0_rtx));
373 SIBLING_CALL_P (insn) = 1;
375 /* Run just enough of rest_of_compilation. This sequence was
376 "borrowed" from alpha.c. */
378 insn_locators_alloc ();
379 split_all_insns_noflow ();
380 shorten_branches (insn);
381 final_start_function (insn, file, 1);
382 final (insn, file, 1);
383 final_end_function ();
385 /* Clean up the vars set above. Note that final_end_function resets
386 the global pointer for us. */
387 reload_completed = 0;
390 /* Copy VALUE to a register and return that register. If new psuedos
391 are allowed, copy it into a new register, otherwise use DEST. */
393 score7_force_temporary (rtx dest, rtx value)
395 if (can_create_pseudo_p ())
396 return force_reg (Pmode, value);
399 emit_move_insn (copy_rtx (dest), value);
404 /* Return a LO_SUM expression for ADDR. TEMP is as for score_force_temporary
405 and is used to load the high part into a register. */
407 score7_split_symbol (rtx temp, rtx addr)
409 rtx high = score7_force_temporary (temp,
410 gen_rtx_HIGH (Pmode, copy_rtx (addr)));
411 return gen_rtx_LO_SUM (Pmode, high, addr);
414 /* This function is used to implement LEGITIMIZE_ADDRESS. If *XLOC can
415 be legitimized in a way that the generic machinery might not expect,
416 put the new address in *XLOC and return true. */
418 score7_legitimize_address (rtx *xloc)
420 enum score_symbol_type symbol_type;
422 if (score7_symbolic_constant_p (*xloc, &symbol_type)
423 && symbol_type == SYMBOL_GENERAL)
425 *xloc = score7_split_symbol (0, *xloc);
429 if (GET_CODE (*xloc) == PLUS
430 && GET_CODE (XEXP (*xloc, 1)) == CONST_INT)
432 rtx reg = XEXP (*xloc, 0);
433 if (!score7_valid_base_register_p (reg, 0))
434 reg = copy_to_mode_reg (Pmode, reg);
435 *xloc = score7_add_offset (reg, INTVAL (XEXP (*xloc, 1)));
441 /* Fill INFO with information about a single argument. CUM is the
442 cumulative state for earlier arguments. MODE is the mode of this
443 argument and TYPE is its type (if known). NAMED is true if this
444 is a named (fixed) argument rather than a variable one. */
446 score7_classify_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
447 tree type, int named, struct score7_arg_info *info)
450 unsigned int num_words, max_regs;
453 if (GET_MODE_CLASS (mode) == MODE_INT
454 || GET_MODE_CLASS (mode) == MODE_FLOAT)
455 even_reg_p = (GET_MODE_SIZE (mode) > UNITS_PER_WORD);
457 if (type != NULL_TREE && TYPE_ALIGN (type) > BITS_PER_WORD && named)
460 if (TARGET_MUST_PASS_IN_STACK (mode, type))
461 info->reg_offset = ARG_REG_NUM;
464 info->reg_offset = cum->num_gprs;
466 info->reg_offset += info->reg_offset & 1;
470 info->num_bytes = int_size_in_bytes (type);
472 info->num_bytes = GET_MODE_SIZE (mode);
474 num_words = (info->num_bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
475 max_regs = ARG_REG_NUM - info->reg_offset;
477 /* Partition the argument between registers and stack. */
478 info->reg_words = MIN (num_words, max_regs);
479 info->stack_words = num_words - info->reg_words;
481 /* The alignment applied to registers is also applied to stack arguments. */
482 if (info->stack_words)
484 info->stack_offset = cum->stack_words;
486 info->stack_offset += info->stack_offset & 1;
490 /* Set up the stack and frame (if desired) for the function. */
492 score7_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
495 struct score7_frame_info *f = score7_cached_frame ();
496 HOST_WIDE_INT tsize = f->total_size;
498 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
499 if (!flag_inhibit_size_directive)
501 fputs ("\t.ent\t", file);
502 assemble_name (file, fnname);
505 assemble_name (file, fnname);
508 if (!flag_inhibit_size_directive)
511 "\t.frame\t%s," HOST_WIDE_INT_PRINT_DEC ",%s, %d\t\t"
512 "# vars= " HOST_WIDE_INT_PRINT_DEC ", regs= %d"
513 ", args= " HOST_WIDE_INT_PRINT_DEC
514 ", gp= " HOST_WIDE_INT_PRINT_DEC "\n",
515 (reg_names[(frame_pointer_needed)
516 ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM]),
518 reg_names[RA_REGNUM],
519 current_function_is_leaf ? 1 : 0,
525 fprintf(file, "\t.mask\t0x%08x," HOST_WIDE_INT_PRINT_DEC "\n",
527 (f->gp_sp_offset - f->total_size));
531 /* Do any necessary cleanup after a function to restore stack, frame,
534 score7_function_epilogue (FILE *file,
535 HOST_WIDE_INT size ATTRIBUTE_UNUSED)
537 if (!flag_inhibit_size_directive)
540 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
541 fputs ("\t.end\t", file);
542 assemble_name (file, fnname);
547 /* Returns true if X contains a SYMBOL_REF. */
549 score7_symbolic_expression_p (rtx x)
551 if (GET_CODE (x) == SYMBOL_REF)
554 if (GET_CODE (x) == CONST)
555 return score7_symbolic_expression_p (XEXP (x, 0));
558 return score7_symbolic_expression_p (XEXP (x, 0));
560 if (ARITHMETIC_P (x))
561 return (score7_symbolic_expression_p (XEXP (x, 0))
562 || score7_symbolic_expression_p (XEXP (x, 1)));
567 /* Choose the section to use for the constant rtx expression X that has
570 score7_select_rtx_section (enum machine_mode mode, rtx x,
571 unsigned HOST_WIDE_INT align)
573 if (GET_MODE_SIZE (mode) <= SCORE7_SDATA_MAX)
574 return get_named_section (0, ".sdata", 0);
575 else if (flag_pic && score7_symbolic_expression_p (x))
576 return get_named_section (0, ".data.rel.ro", 3);
578 return mergeable_constant_section (mode, align, 0);
581 /* Implement TARGET_IN_SMALL_DATA_P. */
583 score7_in_small_data_p (tree decl)
587 if (TREE_CODE (decl) == STRING_CST
588 || TREE_CODE (decl) == FUNCTION_DECL)
591 if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl) != 0)
594 name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
595 if (strcmp (name, ".sdata") != 0
596 && strcmp (name, ".sbss") != 0)
598 if (!DECL_EXTERNAL (decl))
601 size = int_size_in_bytes (TREE_TYPE (decl));
602 return (size > 0 && size <= SCORE7_SDATA_MAX);
605 /* Implement TARGET_ASM_FILE_START. */
607 score7_asm_file_start (void)
609 default_file_start ();
610 fprintf (asm_out_file, ASM_COMMENT_START
611 "GCC for S+core %s \n", SCORE_GCC_VERSION);
614 fprintf (asm_out_file, "\t.set pic\n");
617 /* Implement TARGET_ASM_FILE_END. When using assembler macros, emit
618 .externs for any small-data variables that turned out to be external. */
620 score7_asm_file_end (void)
623 struct extern_list *p;
626 fputs ("\n", asm_out_file);
627 for (p = extern_head; p != 0; p = p->next)
629 name_tree = get_identifier (p->name);
630 if (!TREE_ASM_WRITTEN (name_tree)
631 && TREE_SYMBOL_REFERENCED (name_tree))
633 TREE_ASM_WRITTEN (name_tree) = 1;
634 fputs ("\t.extern\t", asm_out_file);
635 assemble_name (asm_out_file, p->name);
636 fprintf (asm_out_file, ", %d\n", p->size);
642 /* Implement OVERRIDE_OPTIONS macro. */
644 score7_override_options (void)
648 score7_sdata_max = g_switch_set ? g_switch_value : SCORE7_DEFAULT_SDATA_MAX;
651 score7_sdata_max = 0;
652 if (g_switch_set && (g_switch_value != 0))
653 warning (0, "-fPIC and -G are incompatible");
656 score_char_to_class['d'] = G32_REGS;
657 score_char_to_class['e'] = G16_REGS;
658 score_char_to_class['t'] = T32_REGS;
660 score_char_to_class['h'] = HI_REG;
661 score_char_to_class['l'] = LO_REG;
662 score_char_to_class['x'] = CE_REGS;
664 score_char_to_class['q'] = CN_REG;
665 score_char_to_class['y'] = LC_REG;
666 score_char_to_class['z'] = SC_REG;
667 score_char_to_class['a'] = SP_REGS;
669 score_char_to_class['c'] = CR_REGS;
672 /* Implement REGNO_REG_CLASS macro. */
674 score7_reg_class (int regno)
677 gcc_assert (regno >= 0 && regno < FIRST_PSEUDO_REGISTER);
679 if (regno == FRAME_POINTER_REGNUM
680 || regno == ARG_POINTER_REGNUM)
683 for (c = 0; c < N_REG_CLASSES; c++)
684 if (TEST_HARD_REG_BIT (reg_class_contents[c], regno))
690 /* Implement PREFERRED_RELOAD_CLASS macro. */
692 score7_preferred_reload_class (rtx x ATTRIBUTE_UNUSED, enum reg_class class)
694 if (reg_class_subset_p (G16_REGS, class))
696 if (reg_class_subset_p (G32_REGS, class))
701 /* Implement SECONDARY_INPUT_RELOAD_CLASS
702 and SECONDARY_OUTPUT_RELOAD_CLASS macro. */
704 score7_secondary_reload_class (enum reg_class class,
705 enum machine_mode mode ATTRIBUTE_UNUSED,
709 if (GET_CODE (x) == REG || GET_CODE(x) == SUBREG)
710 regno = true_regnum (x);
712 if (!GR_REG_CLASS_P (class))
713 return GP_REG_P (regno) ? NO_REGS : G32_REGS;
717 /* Implement CONST_OK_FOR_LETTER_P macro. */
726 score7_const_ok_for_letter_p (HOST_WIDE_INT value, char c)
730 case 'I': return ((value & 0xffff) == 0);
731 case 'J': return IMM_IN_RANGE (value, 5, 0);
732 case 'K': return IMM_IN_RANGE (value, 16, 0);
733 case 'L': return IMM_IN_RANGE (value, 16, 1);
734 case 'M': return IMM_IN_RANGE (value, 14, 0);
735 case 'N': return IMM_IN_RANGE (value, 14, 1);
740 /* Implement EXTRA_CONSTRAINT macro. */
743 score7_extra_constraint (rtx op, char c)
748 return GET_CODE (op) == SYMBOL_REF;
754 /* Return truth value on whether or not a given hard register
755 can support a given mode. */
757 score7_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
759 int size = GET_MODE_SIZE (mode);
760 enum mode_class class = GET_MODE_CLASS (mode);
762 if (class == MODE_CC)
763 return regno == CC_REGNUM;
764 else if (regno == FRAME_POINTER_REGNUM
765 || regno == ARG_POINTER_REGNUM)
766 return class == MODE_INT;
767 else if (GP_REG_P (regno))
768 /* ((regno <= (GP_REG_LAST- HARD_REGNO_NREGS (dummy, mode)) + 1) */
769 return !(regno & 1) || (size <= UNITS_PER_WORD);
770 else if (CE_REG_P (regno))
771 return (class == MODE_INT
772 && ((size <= UNITS_PER_WORD)
773 || (regno == CE_REG_FIRST && size == 2 * UNITS_PER_WORD)));
775 return (class == MODE_INT) && (size <= UNITS_PER_WORD);
778 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
779 pointer or argument pointer. TO is either the stack pointer or
780 hard frame pointer. */
782 score7_initial_elimination_offset (int from,
783 int to ATTRIBUTE_UNUSED)
785 struct score7_frame_info *f = score7_compute_frame_size (get_frame_size ());
788 case ARG_POINTER_REGNUM:
789 return f->total_size;
790 case FRAME_POINTER_REGNUM:
797 /* Implement FUNCTION_ARG_ADVANCE macro. */
799 score7_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
800 tree type, int named)
802 struct score7_arg_info info;
803 score7_classify_arg (cum, mode, type, named, &info);
804 cum->num_gprs = info.reg_offset + info.reg_words;
805 if (info.stack_words > 0)
806 cum->stack_words = info.stack_offset + info.stack_words;
810 /* Implement TARGET_ARG_PARTIAL_BYTES macro. */
812 score7_arg_partial_bytes (CUMULATIVE_ARGS *cum,
813 enum machine_mode mode, tree type, bool named)
815 struct score7_arg_info info;
816 score7_classify_arg (cum, mode, type, named, &info);
817 return info.stack_words > 0 ? info.reg_words * UNITS_PER_WORD : 0;
820 /* Implement FUNCTION_ARG macro. */
822 score7_function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
823 tree type, int named)
825 struct score7_arg_info info;
827 if (mode == VOIDmode || !named)
830 score7_classify_arg (cum, mode, type, named, &info);
832 if (info.reg_offset == ARG_REG_NUM)
835 if (!info.stack_words)
836 return gen_rtx_REG (mode, ARG_REG_FIRST + info.reg_offset);
839 rtx ret = gen_rtx_PARALLEL (mode, rtvec_alloc (info.reg_words));
840 unsigned int i, part_offset = 0;
841 for (i = 0; i < info.reg_words; i++)
844 reg = gen_rtx_REG (SImode, ARG_REG_FIRST + info.reg_offset + i);
845 XVECEXP (ret, 0, i) = gen_rtx_EXPR_LIST (SImode, reg,
846 GEN_INT (part_offset));
847 part_offset += UNITS_PER_WORD;
853 /* Implement FUNCTION_VALUE and LIBCALL_VALUE. For normal calls,
854 VALTYPE is the return type and MODE is VOIDmode. For libcalls,
855 VALTYPE is null and MODE is the mode of the return value. */
857 score7_function_value (tree valtype, tree func ATTRIBUTE_UNUSED,
858 enum machine_mode mode)
863 mode = TYPE_MODE (valtype);
864 unsignedp = TYPE_UNSIGNED (valtype);
865 mode = promote_mode (valtype, mode, &unsignedp, 1);
867 return gen_rtx_REG (mode, RT_REGNUM);
870 /* Implement INITIALIZE_TRAMPOLINE macro. */
872 score7_initialize_trampoline (rtx ADDR, rtx FUNC, rtx CHAIN)
874 #define FFCACHE "_flush_cache"
875 #define CODE_SIZE (TRAMPOLINE_INSNS * UNITS_PER_WORD)
879 pfunc = plus_constant (ADDR, CODE_SIZE);
880 pchain = plus_constant (ADDR, CODE_SIZE + GET_MODE_SIZE (SImode));
882 emit_move_insn (gen_rtx_MEM (SImode, pfunc), FUNC);
883 emit_move_insn (gen_rtx_MEM (SImode, pchain), CHAIN);
884 emit_library_call (gen_rtx_SYMBOL_REF (Pmode, FFCACHE),
887 GEN_INT (TRAMPOLINE_SIZE), SImode);
892 /* This function is used to implement REG_MODE_OK_FOR_BASE_P macro. */
894 score7_regno_mode_ok_for_base_p (int regno, int strict)
896 if (regno >= FIRST_PSEUDO_REGISTER)
900 regno = reg_renumber[regno];
902 if (regno == ARG_POINTER_REGNUM
903 || regno == FRAME_POINTER_REGNUM)
905 return GP_REG_P (regno);
908 /* Implement GO_IF_LEGITIMATE_ADDRESS macro. */
910 score7_address_p (enum machine_mode mode, rtx x, int strict)
912 struct score7_address_info addr;
914 return score7_classify_address (&addr, mode, x, strict);
917 /* Return a number assessing the cost of moving a register in class
920 score7_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
921 enum reg_class from, enum reg_class to)
923 if (GR_REG_CLASS_P (from))
925 if (GR_REG_CLASS_P (to))
927 else if (SP_REG_CLASS_P (to))
929 else if (CP_REG_CLASS_P (to))
931 else if (CE_REG_CLASS_P (to))
934 if (GR_REG_CLASS_P (to))
936 if (GR_REG_CLASS_P (from))
938 else if (SP_REG_CLASS_P (from))
940 else if (CP_REG_CLASS_P (from))
942 else if (CE_REG_CLASS_P (from))
948 /* Return the number of instructions needed to load a symbol of the
949 given type into a register. */
951 score7_symbol_insns (enum score_symbol_type type)
958 case SYMBOL_SMALL_DATA:
965 /* Return the number of instructions needed to load or store a value
966 of mode MODE at X. Return 0 if X isn't valid for MODE. */
968 score7_address_insns (rtx x, enum machine_mode mode)
970 struct score7_address_info addr;
976 factor = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
978 if (score7_classify_address (&addr, mode, x, false))
982 case SCORE7_ADD_CONST_INT:
985 case SCORE7_ADD_SYMBOLIC:
986 return factor * score7_symbol_insns (addr.symbol_type);
991 /* Implement TARGET_RTX_COSTS macro. */
993 score7_rtx_costs (rtx x, int code, int outer_code, int *total)
995 enum machine_mode mode = GET_MODE (x);
1000 if (outer_code == SET)
1002 if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
1003 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L'))
1004 *total = COSTS_N_INSNS (1);
1006 *total = COSTS_N_INSNS (2);
1008 else if (outer_code == PLUS || outer_code == MINUS)
1010 if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'N'))
1012 else if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
1013 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L'))
1016 *total = COSTS_N_INSNS (2);
1018 else if (outer_code == AND || outer_code == IOR)
1020 if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'M'))
1022 else if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
1023 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'K'))
1026 *total = COSTS_N_INSNS (2);
1038 *total = COSTS_N_INSNS (2);
1043 /* If the address is legitimate, return the number of
1044 instructions it needs, otherwise use the default handling. */
1045 int n = score7_address_insns (XEXP (x, 0), GET_MODE (x));
1048 *total = COSTS_N_INSNS (n + 1);
1055 *total = COSTS_N_INSNS (6);
1059 *total = COSTS_N_INSNS (1);
1067 *total = COSTS_N_INSNS (2);
1077 *total = COSTS_N_INSNS ((GET_CODE (XEXP (x, 1)) == CONST_INT)
1084 *total = COSTS_N_INSNS (4);
1091 *total = COSTS_N_INSNS (4);
1094 *total = COSTS_N_INSNS (1);
1100 *total = COSTS_N_INSNS (4);
1106 *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (12);
1113 *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (33);
1118 switch (GET_MODE (XEXP (x, 0)))
1122 if (GET_CODE (XEXP (x, 0)) == MEM)
1124 *total = COSTS_N_INSNS (2);
1126 if (!TARGET_LITTLE_ENDIAN &&
1127 side_effects_p (XEXP (XEXP (x, 0), 0)))
1131 *total = COSTS_N_INSNS (1);
1135 *total = COSTS_N_INSNS (1);
1145 /* Implement TARGET_ADDRESS_COST macro. */
1147 score7_address_cost (rtx addr)
1149 return score7_address_insns (addr, SImode);
1152 /* Implement ASM_OUTPUT_EXTERNAL macro. */
1154 score7_output_external (FILE *file ATTRIBUTE_UNUSED,
1155 tree decl, const char *name)
1157 register struct extern_list *p;
1159 if (score7_in_small_data_p (decl))
1161 p = (struct extern_list *) ggc_alloc (sizeof (struct extern_list));
1162 p->next = extern_head;
1164 p->size = int_size_in_bytes (TREE_TYPE (decl));
1170 /* Implement RETURN_ADDR_RTX. Note, we do not support moving
1171 back to a previous frame. */
1173 score7_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
1177 return get_hard_reg_initial_val (Pmode, RA_REGNUM);
1180 /* Implement PRINT_OPERAND macro. */
1181 /* Score-specific operand codes:
1182 '[' print .set nor1 directive
1183 ']' print .set r1 directive
1184 'U' print hi part of a CONST_INT rtx
1187 'D' print SFmode const double
1188 'S' selectively print "!" if operand is 15bit instruction accessible
1189 'V' print "v!" if operand is 15bit instruction accessible, or "lfh!"
1190 'L' low part of DImode reg operand
1191 'H' high part of DImode reg operand
1192 'C' print part of opcode for a branch condition. */
1194 score7_print_operand (FILE *file, rtx op, int c)
1196 enum rtx_code code = -1;
1197 if (!PRINT_OPERAND_PUNCT_VALID_P (c))
1198 code = GET_CODE (op);
1202 fprintf (file, ".set r1\n");
1206 fprintf (file, "\n\t.set nor1");
1210 gcc_assert (code == CONST_INT);
1211 fprintf (file, HOST_WIDE_INT_PRINT_HEX,
1212 (INTVAL (op) >> 16) & 0xffff);
1216 if (GET_CODE (op) == CONST_DOUBLE)
1218 rtx temp = gen_lowpart (SImode, op);
1219 gcc_assert (GET_MODE (op) == SFmode);
1220 fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (temp) & 0xffffffff);
1223 output_addr_const (file, op);
1227 gcc_assert (code == REG);
1228 if (G16_REG_P (REGNO (op)))
1229 fprintf (file, "!");
1233 gcc_assert (code == REG);
1234 fprintf (file, G16_REG_P (REGNO (op)) ? "v!" : "lfh!");
1238 enum machine_mode mode = GET_MODE (XEXP (op, 0));
1242 case EQ: fputs ("eq", file); break;
1243 case NE: fputs ("ne", file); break;
1244 case GT: fputs ("gt", file); break;
1245 case GE: fputs (mode != CCmode ? "pl" : "ge", file); break;
1246 case LT: fputs (mode != CCmode ? "mi" : "lt", file); break;
1247 case LE: fputs ("le", file); break;
1248 case GTU: fputs ("gtu", file); break;
1249 case GEU: fputs ("cs", file); break;
1250 case LTU: fputs ("cc", file); break;
1251 case LEU: fputs ("leu", file); break;
1253 output_operand_lossage ("invalid operand for code: '%c'", code);
1258 unsigned HOST_WIDE_INT i;
1259 unsigned HOST_WIDE_INT pow2mask = 1;
1260 unsigned HOST_WIDE_INT val;
1263 for (i = 0; i < 32; i++)
1265 if (val == pow2mask)
1269 gcc_assert (i < 32);
1270 fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
1274 unsigned HOST_WIDE_INT i;
1275 unsigned HOST_WIDE_INT pow2mask = 1;
1276 unsigned HOST_WIDE_INT val;
1279 for (i = 0; i < 32; i++)
1281 if (val == pow2mask)
1285 gcc_assert (i < 32);
1286 fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
1288 else if (code == REG)
1290 int regnum = REGNO (op);
1291 if ((c == 'H' && !WORDS_BIG_ENDIAN)
1292 || (c == 'L' && WORDS_BIG_ENDIAN))
1294 fprintf (file, "%s", reg_names[regnum]);
1301 score7_print_operand_address (file, op);
1304 output_addr_const (file, op);
1309 /* Implement PRINT_OPERAND_ADDRESS macro. */
1311 score7_print_operand_address (FILE *file, rtx x)
1313 struct score7_address_info addr;
1314 enum rtx_code code = GET_CODE (x);
1315 enum machine_mode mode = GET_MODE (x);
1320 if (score7_classify_address (&addr, mode, x, true))
1324 case SCORE7_ADD_REG:
1329 fprintf (file, "[%s,-%ld]+", reg_names[REGNO (addr.reg)],
1330 INTVAL (addr.offset));
1333 fprintf (file, "[%s]+,-%ld", reg_names[REGNO (addr.reg)],
1334 INTVAL (addr.offset));
1337 fprintf (file, "[%s, %ld]+", reg_names[REGNO (addr.reg)],
1338 INTVAL (addr.offset));
1341 fprintf (file, "[%s]+, %ld", reg_names[REGNO (addr.reg)],
1342 INTVAL (addr.offset));
1345 if (INTVAL(addr.offset) == 0)
1346 fprintf(file, "[%s]", reg_names[REGNO (addr.reg)]);
1348 fprintf(file, "[%s, %ld]", reg_names[REGNO (addr.reg)],
1349 INTVAL(addr.offset));
1354 case SCORE7_ADD_CONST_INT:
1355 case SCORE7_ADD_SYMBOLIC:
1356 output_addr_const (file, x);
1360 print_rtl (stderr, x);
1364 /* Implement SELECT_CC_MODE macro. */
1366 score7_select_cc_mode (enum rtx_code op, rtx x, rtx y)
1368 if ((op == EQ || op == NE || op == LT || op == GE)
1370 && GET_MODE (x) == SImode)
1372 switch (GET_CODE (x))
1390 return (op == LT || op == GE) ? CC_Nmode : CCmode;
1397 if ((op == EQ || op == NE)
1398 && (GET_CODE (y) == NEG)
1399 && register_operand (XEXP (y, 0), SImode)
1400 && register_operand (x, SImode))
1408 /* Generate the prologue instructions for entry into a S+core function. */
1410 score7_prologue (void)
1412 #define EMIT_PL(_rtx) RTX_FRAME_RELATED_P (_rtx) = 1
1414 struct score7_frame_info *f = score7_compute_frame_size (get_frame_size ());
1418 size = f->total_size - f->gp_reg_size;
1421 emit_insn (gen_cpload_score7 ());
1423 for (regno = (int) GP_REG_LAST; regno >= (int) GP_REG_FIRST; regno--)
1425 if (BITSET_P (f->mask, regno - GP_REG_FIRST))
1427 rtx mem = gen_rtx_MEM (SImode,
1428 gen_rtx_PRE_DEC (SImode, stack_pointer_rtx));
1429 rtx reg = gen_rtx_REG (SImode, regno);
1430 if (!current_function_calls_eh_return)
1431 MEM_READONLY_P (mem) = 1;
1432 EMIT_PL (emit_insn (gen_pushsi_score7 (mem, reg)));
1440 if (CONST_OK_FOR_LETTER_P (-size, 'L'))
1441 EMIT_PL (emit_insn (gen_add3_insn (stack_pointer_rtx,
1446 EMIT_PL (emit_move_insn (gen_rtx_REG (Pmode, SCORE7_PROLOGUE_TEMP_REGNUM),
1449 (gen_sub3_insn (stack_pointer_rtx,
1452 SCORE7_PROLOGUE_TEMP_REGNUM))));
1454 insn = get_last_insn ();
1456 alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR,
1457 gen_rtx_SET (VOIDmode, stack_pointer_rtx,
1458 plus_constant (stack_pointer_rtx,
1463 if (frame_pointer_needed)
1464 EMIT_PL (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx));
1466 if (flag_pic && f->cprestore_size)
1468 if (frame_pointer_needed)
1469 emit_insn (gen_cprestore_use_fp_score7 (GEN_INT (size - f->cprestore_size)));
1471 emit_insn (gen_cprestore_use_sp_score7 (GEN_INT (size - f->cprestore_size)));
1477 /* Generate the epilogue instructions in a S+core function. */
1479 score7_epilogue (int sibcall_p)
1481 struct score7_frame_info *f = score7_compute_frame_size (get_frame_size ());
1486 size = f->total_size - f->gp_reg_size;
1488 if (!frame_pointer_needed)
1489 base = stack_pointer_rtx;
1491 base = hard_frame_pointer_rtx;
1495 if (CONST_OK_FOR_LETTER_P (size, 'L'))
1496 emit_insn (gen_add3_insn (base, base, GEN_INT (size)));
1499 emit_move_insn (gen_rtx_REG (Pmode, SCORE7_EPILOGUE_TEMP_REGNUM),
1501 emit_insn (gen_add3_insn (base, base,
1503 SCORE7_EPILOGUE_TEMP_REGNUM)));
1507 if (base != stack_pointer_rtx)
1508 emit_move_insn (stack_pointer_rtx, base);
1510 if (current_function_calls_eh_return)
1511 emit_insn (gen_add3_insn (stack_pointer_rtx,
1513 EH_RETURN_STACKADJ_RTX));
1515 for (regno = (int) GP_REG_FIRST; regno <= (int) GP_REG_LAST; regno++)
1517 if (BITSET_P (f->mask, regno - GP_REG_FIRST))
1519 rtx mem = gen_rtx_MEM (SImode,
1520 gen_rtx_POST_INC (SImode, stack_pointer_rtx));
1521 rtx reg = gen_rtx_REG (SImode, regno);
1523 if (!current_function_calls_eh_return)
1524 MEM_READONLY_P (mem) = 1;
1526 emit_insn (gen_popsi_score7 (reg, mem));
1531 emit_jump_insn (gen_return_internal_score7 (gen_rtx_REG (Pmode, RA_REGNUM)));
1535 score7_gen_cmp (enum machine_mode mode)
1537 emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (mode, CC_REGNUM),
1538 gen_rtx_COMPARE (mode, cmp_op0, cmp_op1)));
1541 /* Return true if X is a symbolic constant that can be calculated in
1542 the same way as a bare symbol. If it is, store the type of the
1543 symbol in *SYMBOL_TYPE. */
1545 score7_symbolic_constant_p (rtx x, enum score_symbol_type *symbol_type)
1547 HOST_WIDE_INT offset;
1549 score7_split_const (x, &x, &offset);
1550 if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF)
1551 *symbol_type = score7_classify_symbol (x);
1558 /* if offset > 15bit, must reload */
1559 if (!IMM_IN_RANGE (offset, 15, 1))
1562 switch (*symbol_type)
1564 case SYMBOL_GENERAL:
1566 case SYMBOL_SMALL_DATA:
1567 return score7_offset_within_object_p (x, offset);
1573 score7_movsicc (rtx *ops)
1575 enum machine_mode mode;
1577 mode = score7_select_cc_mode (GET_CODE (ops[1]), ops[2], ops[3]);
1578 emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (mode, CC_REGNUM),
1579 gen_rtx_COMPARE (mode, cmp_op0, cmp_op1)));
1582 /* Call and sibcall pattern all need call this function. */
1584 score7_call (rtx *ops, bool sib)
1586 rtx addr = XEXP (ops[0], 0);
1587 if (!call_insn_operand (addr, VOIDmode))
1590 addr = gen_reg_rtx (Pmode);
1591 gen_move_insn (addr, oaddr);
1595 emit_call_insn (gen_sibcall_internal_score7 (addr, ops[1]));
1597 emit_call_insn (gen_call_internal_score7 (addr, ops[1]));
1600 /* Call value and sibcall value pattern all need call this function. */
1602 score7_call_value (rtx *ops, bool sib)
1604 rtx result = ops[0];
1605 rtx addr = XEXP (ops[1], 0);
1608 if (!call_insn_operand (addr, VOIDmode))
1611 addr = gen_reg_rtx (Pmode);
1612 gen_move_insn (addr, oaddr);
1616 emit_call_insn (gen_sibcall_value_internal_score7 (result, addr, arg));
1618 emit_call_insn (gen_call_value_internal_score7 (result, addr, arg));
1623 score7_movdi (rtx *ops)
1627 rtx dst0 = score7_subw (dst, 0);
1628 rtx dst1 = score7_subw (dst, 1);
1629 rtx src0 = score7_subw (src, 0);
1630 rtx src1 = score7_subw (src, 1);
1632 if (GET_CODE (dst0) == REG && reg_overlap_mentioned_p (dst0, src))
1634 emit_move_insn (dst1, src1);
1635 emit_move_insn (dst0, src0);
1639 emit_move_insn (dst0, src0);
1640 emit_move_insn (dst1, src1);
1645 score7_zero_extract_andi (rtx *ops)
1647 if (INTVAL (ops[1]) == 1 && const_uimm5 (ops[2], SImode))
1648 emit_insn (gen_zero_extract_bittst_score7 (ops[0], ops[2]));
1651 unsigned HOST_WIDE_INT mask;
1652 mask = (0xffffffffU & ((1U << INTVAL (ops[1])) - 1U));
1653 mask = mask << INTVAL (ops[2]);
1654 emit_insn (gen_andsi3_cmp_score7 (ops[3], ops[0],
1655 gen_int_mode (mask, SImode)));
1659 /* Check addr could be present as PRE/POST mode. */
1661 score7_pindex_mem (rtx addr)
1663 if (GET_CODE (addr) == MEM)
1665 switch (GET_CODE (XEXP (addr, 0)))
1679 /* Output asm code for ld/sw insn. */
1681 score7_pr_addr_post (rtx *ops, int idata, int iaddr, char *ip, enum score_mem_unit unit)
1683 struct score7_address_info ai;
1685 gcc_assert (GET_CODE (ops[idata]) == REG);
1686 gcc_assert (score7_classify_address (&ai, SImode, XEXP (ops[iaddr], 0), true));
1688 if (!score7_pindex_mem (ops[iaddr])
1689 && ai.type == SCORE7_ADD_REG
1690 && GET_CODE (ai.offset) == CONST_INT
1691 && G16_REG_P (REGNO (ops[idata]))
1692 && G16_REG_P (REGNO (ai.reg)))
1694 if (INTVAL (ai.offset) == 0)
1696 ops[iaddr] = ai.reg;
1697 return snprintf (ip, INS_BUF_SZ,
1698 "!\t%%%d, [%%%d]", idata, iaddr);
1700 if (REGNO (ai.reg) == HARD_FRAME_POINTER_REGNUM)
1702 HOST_WIDE_INT offset = INTVAL (ai.offset);
1703 if (SCORE_ALIGN_UNIT (offset, unit)
1704 && CONST_OK_FOR_LETTER_P (offset >> unit, 'J'))
1706 ops[iaddr] = ai.offset;
1707 return snprintf (ip, INS_BUF_SZ,
1708 "p!\t%%%d, %%c%d", idata, iaddr);
1712 return snprintf (ip, INS_BUF_SZ, "\t%%%d, %%a%d", idata, iaddr);
1715 /* Output asm insn for load. */
1717 score7_linsn (rtx *ops, enum score_mem_unit unit, bool sign)
1719 const char *pre_ins[] =
1720 {"lbu", "lhu", "lw", "??", "lb", "lh", "lw", "??"};
1723 strcpy (score7_ins, pre_ins[(sign ? 4 : 0) + unit]);
1724 ip = score7_ins + strlen (score7_ins);
1726 if ((!sign && unit != SCORE_HWORD)
1727 || (sign && unit != SCORE_BYTE))
1728 score7_pr_addr_post (ops, 0, 1, ip, unit);
1730 snprintf (ip, INS_BUF_SZ, "\t%%0, %%a1");
1735 /* Output asm insn for store. */
1737 score7_sinsn (rtx *ops, enum score_mem_unit unit)
1739 const char *pre_ins[] = {"sb", "sh", "sw"};
1742 strcpy (score7_ins, pre_ins[unit]);
1743 ip = score7_ins + strlen (score7_ins);
1744 score7_pr_addr_post (ops, 1, 0, ip, unit);
1748 /* Output asm insn for load immediate. */
1750 score7_limm (rtx *ops)
1754 gcc_assert (GET_CODE (ops[0]) == REG);
1755 gcc_assert (GET_CODE (ops[1]) == CONST_INT);
1757 v = INTVAL (ops[1]);
1758 if (G16_REG_P (REGNO (ops[0])) && IMM_IN_RANGE (v, 8, 0))
1759 return "ldiu!\t%0, %c1";
1760 else if (IMM_IN_RANGE (v, 16, 1))
1761 return "ldi\t%0, %c1";
1762 else if ((v & 0xffff) == 0)
1763 return "ldis\t%0, %U1";
1765 return "li\t%0, %c1";
1768 /* Output asm insn for move. */
1770 score7_move (rtx *ops)
1772 gcc_assert (GET_CODE (ops[0]) == REG);
1773 gcc_assert (GET_CODE (ops[1]) == REG);
1775 if (G16_REG_P (REGNO (ops[0])))
1777 if (G16_REG_P (REGNO (ops[1])))
1778 return "mv!\t%0, %1";
1780 return "mlfh!\t%0, %1";
1782 else if (G16_REG_P (REGNO (ops[1])))
1783 return "mhfl!\t%0, %1";
1785 return "mv\t%0, %1";
1788 /* Generate add insn. */
1790 score7_select_add_imm (rtx *ops, bool set_cc)
1792 HOST_WIDE_INT v = INTVAL (ops[2]);
1794 gcc_assert (GET_CODE (ops[2]) == CONST_INT);
1795 gcc_assert (REGNO (ops[0]) == REGNO (ops[1]));
1797 if (set_cc && G16_REG_P (REGNO (ops[0])))
1799 if (v > 0 && IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT) v, 0, 15))
1801 ops[2] = GEN_INT (ffs (v) - 1);
1802 return "addei!\t%0, %c2";
1805 if (v < 0 && IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT) (-v), 0, 15))
1807 ops[2] = GEN_INT (ffs (-v) - 1);
1808 return "subei!\t%0, %c2";
1813 return "addi.c\t%0, %c2";
1815 return "addi\t%0, %c2";
1818 /* Output arith insn. */
1820 score7_select (rtx *ops, const char *inst_pre,
1821 bool commu, const char *letter, bool set_cc)
1823 gcc_assert (GET_CODE (ops[0]) == REG);
1824 gcc_assert (GET_CODE (ops[1]) == REG);
1826 if (set_cc && G16_REG_P (REGNO (ops[0]))
1827 && (GET_CODE (ops[2]) == REG ? G16_REG_P (REGNO (ops[2])) : 1)
1828 && REGNO (ops[0]) == REGNO (ops[1]))
1830 snprintf (score7_ins, INS_BUF_SZ, "%s!\t%%0, %%%s2", inst_pre, letter);
1834 if (commu && set_cc && G16_REG_P (REGNO (ops[0]))
1835 && G16_REG_P (REGNO (ops[1]))
1836 && REGNO (ops[0]) == REGNO (ops[2]))
1838 gcc_assert (GET_CODE (ops[2]) == REG);
1839 snprintf (score7_ins, INS_BUF_SZ, "%s!\t%%0, %%%s1", inst_pre, letter);
1844 snprintf (score7_ins, INS_BUF_SZ, "%s.c\t%%0, %%1, %%%s2", inst_pre, letter);
1846 snprintf (score7_ins, INS_BUF_SZ, "%s\t%%0, %%1, %%%s2", inst_pre, letter);