1 /* score7.c for Sunplus S+CORE processor
2 Copyright (C) 2005, 2007, 2008 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"
54 #define BITSET_P(VALUE, BIT) (((VALUE) & (1L << (BIT))) != 0)
55 #define INS_BUF_SZ 128
57 /* Define the information needed to generate branch insns. This is
58 stored from the compare operation. */
59 extern rtx cmp_op0, cmp_op1;
60 extern enum reg_class score_char_to_class[256];
62 static int score7_sdata_max;
63 static char score7_ins[INS_BUF_SZ + 8];
65 /* Return true if SYMBOL is a SYMBOL_REF and OFFSET + SYMBOL points
66 to the same object as SYMBOL. */
68 score7_offset_within_object_p (rtx symbol, HOST_WIDE_INT offset)
70 if (GET_CODE (symbol) != SYMBOL_REF)
73 if (CONSTANT_POOL_ADDRESS_P (symbol)
75 && offset < (int)GET_MODE_SIZE (get_pool_mode (symbol)))
78 if (SYMBOL_REF_DECL (symbol) != 0
80 && offset < int_size_in_bytes (TREE_TYPE (SYMBOL_REF_DECL (symbol))))
86 /* Split X into a base and a constant offset, storing them in *BASE
87 and *OFFSET respectively. */
89 score7_split_const (rtx x, rtx *base, HOST_WIDE_INT *offset)
93 if (GET_CODE (x) == CONST)
96 if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
98 *offset += INTVAL (XEXP (x, 1));
105 /* Classify symbol X, which must be a SYMBOL_REF or a LABEL_REF. */
106 static enum score_symbol_type
107 score7_classify_symbol (rtx x)
109 if (GET_CODE (x) == LABEL_REF)
110 return SYMBOL_GENERAL;
112 gcc_assert (GET_CODE (x) == SYMBOL_REF);
114 if (CONSTANT_POOL_ADDRESS_P (x))
116 if (GET_MODE_SIZE (get_pool_mode (x)) <= SCORE7_SDATA_MAX)
117 return SYMBOL_SMALL_DATA;
118 return SYMBOL_GENERAL;
120 if (SYMBOL_REF_SMALL_P (x))
121 return SYMBOL_SMALL_DATA;
122 return SYMBOL_GENERAL;
125 /* Return true if the current function must save REGNO. */
127 score7_save_reg_p (unsigned int regno)
129 /* Check call-saved registers. */
130 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
133 /* We need to save the old frame pointer before setting up a new one. */
134 if (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed)
137 /* We need to save the incoming return address if it is ever clobbered
138 within the function. */
139 if (regno == RA_REGNUM && df_regs_ever_live_p (regno))
145 /* Return one word of double-word value OP, taking into account the fixed
146 endianness of certain registers. HIGH_P is true to select the high part,
147 false to select the low part. */
149 score7_subw (rtx op, int high_p)
152 enum machine_mode mode = GET_MODE (op);
154 if (mode == VOIDmode)
157 byte = (TARGET_LITTLE_ENDIAN ? high_p : !high_p) ? UNITS_PER_WORD : 0;
159 if (GET_CODE (op) == REG && REGNO (op) == HI_REGNUM)
160 return gen_rtx_REG (SImode, high_p ? HI_REGNUM : LO_REGNUM);
162 if (GET_CODE (op) == MEM)
163 return adjust_address (op, SImode, byte);
165 return simplify_gen_subreg (SImode, op, mode, byte);
168 static struct score7_frame_info *
169 score7_cached_frame (void)
171 static struct score7_frame_info _frame_info;
175 /* Return the bytes needed to compute the frame pointer from the current
176 stack pointer. SIZE is the size (in bytes) of the local variables. */
177 static struct score7_frame_info *
178 score7_compute_frame_size (HOST_WIDE_INT size)
181 struct score7_frame_info *f = score7_cached_frame ();
183 memset (f, 0, sizeof (struct score7_frame_info));
186 f->var_size = SCORE7_STACK_ALIGN (size);
187 f->args_size = crtl->outgoing_args_size;
188 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 && cfun->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 (score7_save_reg_p (regno))
200 f->gp_reg_size += GET_MODE_SIZE (SImode);
201 f->mask |= 1 << (regno - GP_REG_FIRST);
205 if (crtl->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 score7_valid_base_register_p (rtx x, int strict)
239 if (!strict && GET_CODE (x) == SUBREG)
242 return (GET_CODE (x) == REG
243 && score7_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 score7_classify_address (struct score7_address_info *info,
251 enum machine_mode mode, rtx x, int strict)
253 info->code = GET_CODE (x);
259 info->type = SCORE7_ADD_REG;
261 info->offset = const0_rtx;
262 return score7_valid_base_register_p (info->reg, strict);
264 info->type = SCORE7_ADD_REG;
265 info->reg = XEXP (x, 0);
266 info->offset = XEXP (x, 1);
267 return (score7_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 = SCORE7_ADD_REG;
277 info->reg = XEXP (x, 0);
278 info->offset = GEN_INT (GET_MODE_SIZE (mode));
279 return score7_valid_base_register_p (info->reg, strict);
281 info->type = SCORE7_ADD_CONST_INT;
282 return IMM_IN_RANGE (INTVAL (x), 15, 1);
286 info->type = SCORE7_ADD_SYMBOLIC;
287 return (score7_symbolic_constant_p (x, &info->symbol_type)
288 && (info->symbol_type == SYMBOL_GENERAL
289 || info->symbol_type == SYMBOL_SMALL_DATA));
296 score7_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 score7_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 score7_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
323 HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
326 rtx this_rtx, 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_rtx = gen_rtx_REG (Pmode, ARG_REG_FIRST + 1);
341 this_rtx = gen_rtx_REG (Pmode, ARG_REG_FIRST);
343 /* Add DELTA to THIS_RTX. */
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_rtx, this_rtx, offset));
355 /* If needed, add *(*THIS_RTX + VCALL_OFFSET) to THIS_RTX. */
356 if (vcall_offset != 0)
360 /* Set TEMP1 to *THIS_RTX. */
361 emit_move_insn (temp1, gen_rtx_MEM (Pmode, this_rtx));
363 /* Set ADDR to a legitimate address for *THIS_RTX + VCALL_OFFSET. */
364 addr = score7_add_offset (temp1, vcall_offset);
366 /* Load the offset and add it to THIS_RTX. */
367 emit_move_insn (temp1, gen_rtx_MEM (Pmode, addr));
368 emit_insn (gen_add3_insn (this_rtx, this_rtx, temp1));
371 /* Jump to the target function. */
372 fnaddr = XEXP (DECL_RTL (function), 0);
373 insn = emit_call_insn (gen_sibcall_internal_score7 (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 ();
385 free_after_compilation (cfun);
387 /* Clean up the vars set above. Note that final_end_function resets
388 the global pointer for us. */
389 reload_completed = 0;
392 /* Copy VALUE to a register and return that register. If new psuedos
393 are allowed, copy it into a new register, otherwise use DEST. */
395 score7_force_temporary (rtx dest, rtx value)
397 if (can_create_pseudo_p ())
398 return force_reg (Pmode, value);
401 emit_move_insn (copy_rtx (dest), value);
406 /* Return a LO_SUM expression for ADDR. TEMP is as for score_force_temporary
407 and is used to load the high part into a register. */
409 score7_split_symbol (rtx temp, rtx addr)
411 rtx high = score7_force_temporary (temp,
412 gen_rtx_HIGH (Pmode, copy_rtx (addr)));
413 return gen_rtx_LO_SUM (Pmode, high, addr);
416 /* This function is used to implement LEGITIMIZE_ADDRESS. If *XLOC can
417 be legitimized in a way that the generic machinery might not expect,
418 put the new address in *XLOC and return true. */
420 score7_legitimize_address (rtx *xloc)
422 enum score_symbol_type symbol_type;
424 if (score7_symbolic_constant_p (*xloc, &symbol_type)
425 && symbol_type == SYMBOL_GENERAL)
427 *xloc = score7_split_symbol (0, *xloc);
431 if (GET_CODE (*xloc) == PLUS
432 && GET_CODE (XEXP (*xloc, 1)) == CONST_INT)
434 rtx reg = XEXP (*xloc, 0);
435 if (!score7_valid_base_register_p (reg, 0))
436 reg = copy_to_mode_reg (Pmode, reg);
437 *xloc = score7_add_offset (reg, INTVAL (XEXP (*xloc, 1)));
443 /* Fill INFO with information about a single argument. CUM is the
444 cumulative state for earlier arguments. MODE is the mode of this
445 argument and TYPE is its type (if known). NAMED is true if this
446 is a named (fixed) argument rather than a variable one. */
448 score7_classify_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
449 tree type, int named, struct score7_arg_info *info)
452 unsigned int num_words, max_regs;
455 if (GET_MODE_CLASS (mode) == MODE_INT
456 || GET_MODE_CLASS (mode) == MODE_FLOAT)
457 even_reg_p = (GET_MODE_SIZE (mode) > UNITS_PER_WORD);
459 if (type != NULL_TREE && TYPE_ALIGN (type) > BITS_PER_WORD && named)
462 if (TARGET_MUST_PASS_IN_STACK (mode, type))
463 info->reg_offset = ARG_REG_NUM;
466 info->reg_offset = cum->num_gprs;
468 info->reg_offset += info->reg_offset & 1;
472 info->num_bytes = int_size_in_bytes (type);
474 info->num_bytes = GET_MODE_SIZE (mode);
476 num_words = (info->num_bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
477 max_regs = ARG_REG_NUM - info->reg_offset;
479 /* Partition the argument between registers and stack. */
480 info->reg_words = MIN (num_words, max_regs);
481 info->stack_words = num_words - info->reg_words;
483 /* The alignment applied to registers is also applied to stack arguments. */
484 if (info->stack_words)
486 info->stack_offset = cum->stack_words;
488 info->stack_offset += info->stack_offset & 1;
492 /* Set up the stack and frame (if desired) for the function. */
494 score7_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
497 struct score7_frame_info *f = score7_cached_frame ();
498 HOST_WIDE_INT tsize = f->total_size;
500 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
501 if (!flag_inhibit_size_directive)
503 fputs ("\t.ent\t", file);
504 assemble_name (file, fnname);
507 assemble_name (file, fnname);
510 if (!flag_inhibit_size_directive)
513 "\t.frame\t%s," HOST_WIDE_INT_PRINT_DEC ",%s, %d\t\t"
514 "# vars= " HOST_WIDE_INT_PRINT_DEC ", regs= %d"
515 ", args= " HOST_WIDE_INT_PRINT_DEC
516 ", gp= " HOST_WIDE_INT_PRINT_DEC "\n",
517 (reg_names[(frame_pointer_needed)
518 ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM]),
520 reg_names[RA_REGNUM],
521 current_function_is_leaf ? 1 : 0,
527 fprintf(file, "\t.mask\t0x%08x," HOST_WIDE_INT_PRINT_DEC "\n",
529 (f->gp_sp_offset - f->total_size));
533 /* Do any necessary cleanup after a function to restore stack, frame,
536 score7_function_epilogue (FILE *file,
537 HOST_WIDE_INT size ATTRIBUTE_UNUSED)
539 if (!flag_inhibit_size_directive)
542 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
543 fputs ("\t.end\t", file);
544 assemble_name (file, fnname);
549 /* Returns true if X contains a SYMBOL_REF. */
551 score7_symbolic_expression_p (rtx x)
553 if (GET_CODE (x) == SYMBOL_REF)
556 if (GET_CODE (x) == CONST)
557 return score7_symbolic_expression_p (XEXP (x, 0));
560 return score7_symbolic_expression_p (XEXP (x, 0));
562 if (ARITHMETIC_P (x))
563 return (score7_symbolic_expression_p (XEXP (x, 0))
564 || score7_symbolic_expression_p (XEXP (x, 1)));
569 /* Choose the section to use for the constant rtx expression X that has
572 score7_select_rtx_section (enum machine_mode mode, rtx x,
573 unsigned HOST_WIDE_INT align)
575 if (GET_MODE_SIZE (mode) <= SCORE7_SDATA_MAX)
576 return get_named_section (0, ".sdata", 0);
577 else if (flag_pic && score7_symbolic_expression_p (x))
578 return get_named_section (0, ".data.rel.ro", 3);
580 return mergeable_constant_section (mode, align, 0);
583 /* Implement TARGET_IN_SMALL_DATA_P. */
585 score7_in_small_data_p (tree decl)
589 if (TREE_CODE (decl) == STRING_CST
590 || TREE_CODE (decl) == FUNCTION_DECL)
593 if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl) != 0)
596 name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
597 if (strcmp (name, ".sdata") != 0
598 && strcmp (name, ".sbss") != 0)
600 if (!DECL_EXTERNAL (decl))
603 size = int_size_in_bytes (TREE_TYPE (decl));
604 return (size > 0 && size <= SCORE7_SDATA_MAX);
607 /* Implement TARGET_ASM_FILE_START. */
609 score7_asm_file_start (void)
611 default_file_start ();
612 fprintf (asm_out_file, ASM_COMMENT_START
613 "GCC for S+core %s \n", SCORE_GCC_VERSION);
616 fprintf (asm_out_file, "\t.set pic\n");
619 /* Implement TARGET_ASM_FILE_END. When using assembler macros, emit
620 .externs for any small-data variables that turned out to be external. */
622 score7_asm_file_end (void)
625 struct extern_list *p;
628 fputs ("\n", asm_out_file);
629 for (p = extern_head; p != 0; p = p->next)
631 name_tree = get_identifier (p->name);
632 if (!TREE_ASM_WRITTEN (name_tree)
633 && TREE_SYMBOL_REFERENCED (name_tree))
635 TREE_ASM_WRITTEN (name_tree) = 1;
636 fputs ("\t.extern\t", asm_out_file);
637 assemble_name (asm_out_file, p->name);
638 fprintf (asm_out_file, ", %d\n", p->size);
644 /* Implement OVERRIDE_OPTIONS macro. */
646 score7_override_options (void)
650 score7_sdata_max = g_switch_set ? g_switch_value : SCORE7_DEFAULT_SDATA_MAX;
653 score7_sdata_max = 0;
654 if (g_switch_set && (g_switch_value != 0))
655 warning (0, "-fPIC and -G are incompatible");
658 score_char_to_class['d'] = G32_REGS;
659 score_char_to_class['e'] = G16_REGS;
660 score_char_to_class['t'] = T32_REGS;
662 score_char_to_class['h'] = HI_REG;
663 score_char_to_class['l'] = LO_REG;
664 score_char_to_class['x'] = CE_REGS;
666 score_char_to_class['q'] = CN_REG;
667 score_char_to_class['y'] = LC_REG;
668 score_char_to_class['z'] = SC_REG;
669 score_char_to_class['a'] = SP_REGS;
671 score_char_to_class['c'] = CR_REGS;
674 /* Implement REGNO_REG_CLASS macro. */
676 score7_reg_class (int regno)
679 gcc_assert (regno >= 0 && regno < FIRST_PSEUDO_REGISTER);
681 if (regno == FRAME_POINTER_REGNUM
682 || regno == ARG_POINTER_REGNUM)
685 for (c = 0; c < N_REG_CLASSES; c++)
686 if (TEST_HARD_REG_BIT (reg_class_contents[c], regno))
692 /* Implement PREFERRED_RELOAD_CLASS macro. */
694 score7_preferred_reload_class (rtx x ATTRIBUTE_UNUSED, enum reg_class rclass)
696 if (reg_class_subset_p (G16_REGS, rclass))
698 if (reg_class_subset_p (G32_REGS, rclass))
703 /* Implement SECONDARY_INPUT_RELOAD_CLASS
704 and SECONDARY_OUTPUT_RELOAD_CLASS macro. */
706 score7_secondary_reload_class (enum reg_class rclass,
707 enum machine_mode mode ATTRIBUTE_UNUSED,
711 if (GET_CODE (x) == REG || GET_CODE(x) == SUBREG)
712 regno = true_regnum (x);
714 if (!GR_REG_CLASS_P (rclass))
715 return GP_REG_P (regno) ? NO_REGS : G32_REGS;
719 /* Implement CONST_OK_FOR_LETTER_P macro. */
728 score7_const_ok_for_letter_p (HOST_WIDE_INT value, char c)
732 case 'I': return ((value & 0xffff) == 0);
733 case 'J': return IMM_IN_RANGE (value, 5, 0);
734 case 'K': return IMM_IN_RANGE (value, 16, 0);
735 case 'L': return IMM_IN_RANGE (value, 16, 1);
736 case 'M': return IMM_IN_RANGE (value, 14, 0);
737 case 'N': return IMM_IN_RANGE (value, 14, 1);
742 /* Implement EXTRA_CONSTRAINT macro. */
745 score7_extra_constraint (rtx op, char c)
750 return GET_CODE (op) == SYMBOL_REF;
756 /* Return truth value on whether or not a given hard register
757 can support a given mode. */
759 score7_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
761 int size = GET_MODE_SIZE (mode);
762 enum mode_class mclass = GET_MODE_CLASS (mode);
764 if (mclass == MODE_CC)
765 return regno == CC_REGNUM;
766 else if (regno == FRAME_POINTER_REGNUM
767 || regno == ARG_POINTER_REGNUM)
768 return mclass == MODE_INT;
769 else if (GP_REG_P (regno))
770 /* ((regno <= (GP_REG_LAST- HARD_REGNO_NREGS (dummy, mode)) + 1) */
771 return !(regno & 1) || (size <= UNITS_PER_WORD);
772 else if (CE_REG_P (regno))
773 return (mclass == MODE_INT
774 && ((size <= UNITS_PER_WORD)
775 || (regno == CE_REG_FIRST && size == 2 * UNITS_PER_WORD)));
777 return (mclass == MODE_INT) && (size <= UNITS_PER_WORD);
780 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
781 pointer or argument pointer. TO is either the stack pointer or
782 hard frame pointer. */
784 score7_initial_elimination_offset (int from,
785 int to ATTRIBUTE_UNUSED)
787 struct score7_frame_info *f = score7_compute_frame_size (get_frame_size ());
790 case ARG_POINTER_REGNUM:
791 return f->total_size;
792 case FRAME_POINTER_REGNUM:
799 /* Implement FUNCTION_ARG_ADVANCE macro. */
801 score7_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
802 tree type, int named)
804 struct score7_arg_info info;
805 score7_classify_arg (cum, mode, type, named, &info);
806 cum->num_gprs = info.reg_offset + info.reg_words;
807 if (info.stack_words > 0)
808 cum->stack_words = info.stack_offset + info.stack_words;
812 /* Implement TARGET_ARG_PARTIAL_BYTES macro. */
814 score7_arg_partial_bytes (CUMULATIVE_ARGS *cum,
815 enum machine_mode mode, tree type, bool named)
817 struct score7_arg_info info;
818 score7_classify_arg (cum, mode, type, named, &info);
819 return info.stack_words > 0 ? info.reg_words * UNITS_PER_WORD : 0;
822 /* Implement FUNCTION_ARG macro. */
824 score7_function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
825 tree type, int named)
827 struct score7_arg_info info;
829 if (mode == VOIDmode || !named)
832 score7_classify_arg (cum, mode, type, named, &info);
834 if (info.reg_offset == ARG_REG_NUM)
837 if (!info.stack_words)
838 return gen_rtx_REG (mode, ARG_REG_FIRST + info.reg_offset);
841 rtx ret = gen_rtx_PARALLEL (mode, rtvec_alloc (info.reg_words));
842 unsigned int i, part_offset = 0;
843 for (i = 0; i < info.reg_words; i++)
846 reg = gen_rtx_REG (SImode, ARG_REG_FIRST + info.reg_offset + i);
847 XVECEXP (ret, 0, i) = gen_rtx_EXPR_LIST (SImode, reg,
848 GEN_INT (part_offset));
849 part_offset += UNITS_PER_WORD;
855 /* Implement FUNCTION_VALUE and LIBCALL_VALUE. For normal calls,
856 VALTYPE is the return type and MODE is VOIDmode. For libcalls,
857 VALTYPE is null and MODE is the mode of the return value. */
859 score7_function_value (tree valtype, tree func ATTRIBUTE_UNUSED,
860 enum machine_mode mode)
865 mode = TYPE_MODE (valtype);
866 unsignedp = TYPE_UNSIGNED (valtype);
867 mode = promote_mode (valtype, mode, &unsignedp, 1);
869 return gen_rtx_REG (mode, RT_REGNUM);
872 /* Implement INITIALIZE_TRAMPOLINE macro. */
874 score7_initialize_trampoline (rtx ADDR, rtx FUNC, rtx CHAIN)
876 #define FFCACHE "_flush_cache"
877 #define CODE_SIZE (TRAMPOLINE_INSNS * UNITS_PER_WORD)
881 pfunc = plus_constant (ADDR, CODE_SIZE);
882 pchain = plus_constant (ADDR, CODE_SIZE + GET_MODE_SIZE (SImode));
884 emit_move_insn (gen_rtx_MEM (SImode, pfunc), FUNC);
885 emit_move_insn (gen_rtx_MEM (SImode, pchain), CHAIN);
886 emit_library_call (gen_rtx_SYMBOL_REF (Pmode, FFCACHE),
889 GEN_INT (TRAMPOLINE_SIZE), SImode);
894 /* This function is used to implement REG_MODE_OK_FOR_BASE_P macro. */
896 score7_regno_mode_ok_for_base_p (int regno, int strict)
898 if (regno >= FIRST_PSEUDO_REGISTER)
902 regno = reg_renumber[regno];
904 if (regno == ARG_POINTER_REGNUM
905 || regno == FRAME_POINTER_REGNUM)
907 return GP_REG_P (regno);
910 /* Implement GO_IF_LEGITIMATE_ADDRESS macro. */
912 score7_address_p (enum machine_mode mode, rtx x, int strict)
914 struct score7_address_info addr;
916 return score7_classify_address (&addr, mode, x, strict);
919 /* Return a number assessing the cost of moving a register in class
922 score7_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
923 enum reg_class from, enum reg_class to)
925 if (GR_REG_CLASS_P (from))
927 if (GR_REG_CLASS_P (to))
929 else if (SP_REG_CLASS_P (to))
931 else if (CP_REG_CLASS_P (to))
933 else if (CE_REG_CLASS_P (to))
936 if (GR_REG_CLASS_P (to))
938 if (GR_REG_CLASS_P (from))
940 else if (SP_REG_CLASS_P (from))
942 else if (CP_REG_CLASS_P (from))
944 else if (CE_REG_CLASS_P (from))
950 /* Return the number of instructions needed to load a symbol of the
951 given type into a register. */
953 score7_symbol_insns (enum score_symbol_type type)
960 case SYMBOL_SMALL_DATA:
967 /* Return the number of instructions needed to load or store a value
968 of mode MODE at X. Return 0 if X isn't valid for MODE. */
970 score7_address_insns (rtx x, enum machine_mode mode)
972 struct score7_address_info addr;
978 factor = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
980 if (score7_classify_address (&addr, mode, x, false))
984 case SCORE7_ADD_CONST_INT:
987 case SCORE7_ADD_SYMBOLIC:
988 return factor * score7_symbol_insns (addr.symbol_type);
993 /* Implement TARGET_RTX_COSTS macro. */
995 score7_rtx_costs (rtx x, int code, int outer_code, int *total,
996 bool speed ATTRIBUTE_UNUSED)
998 enum machine_mode mode = GET_MODE (x);
1003 if (outer_code == SET)
1005 if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
1006 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L'))
1007 *total = COSTS_N_INSNS (1);
1009 *total = COSTS_N_INSNS (2);
1011 else if (outer_code == PLUS || outer_code == MINUS)
1013 if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'N'))
1015 else if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
1016 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L'))
1019 *total = COSTS_N_INSNS (2);
1021 else if (outer_code == AND || outer_code == IOR)
1023 if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'M'))
1025 else if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
1026 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'K'))
1029 *total = COSTS_N_INSNS (2);
1041 *total = COSTS_N_INSNS (2);
1046 /* If the address is legitimate, return the number of
1047 instructions it needs, otherwise use the default handling. */
1048 int n = score7_address_insns (XEXP (x, 0), GET_MODE (x));
1051 *total = COSTS_N_INSNS (n + 1);
1058 *total = COSTS_N_INSNS (6);
1062 *total = COSTS_N_INSNS (1);
1070 *total = COSTS_N_INSNS (2);
1080 *total = COSTS_N_INSNS ((GET_CODE (XEXP (x, 1)) == CONST_INT)
1087 *total = COSTS_N_INSNS (4);
1094 *total = COSTS_N_INSNS (4);
1097 *total = COSTS_N_INSNS (1);
1103 *total = COSTS_N_INSNS (4);
1109 *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (12);
1116 *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (33);
1121 switch (GET_MODE (XEXP (x, 0)))
1125 if (GET_CODE (XEXP (x, 0)) == MEM)
1127 *total = COSTS_N_INSNS (2);
1129 if (!TARGET_LITTLE_ENDIAN &&
1130 side_effects_p (XEXP (XEXP (x, 0), 0)))
1134 *total = COSTS_N_INSNS (1);
1138 *total = COSTS_N_INSNS (1);
1148 /* Implement TARGET_ADDRESS_COST macro. */
1150 score7_address_cost (rtx addr)
1152 return score7_address_insns (addr, SImode);
1155 /* Implement ASM_OUTPUT_EXTERNAL macro. */
1157 score7_output_external (FILE *file ATTRIBUTE_UNUSED,
1158 tree decl, const char *name)
1160 register struct extern_list *p;
1162 if (score7_in_small_data_p (decl))
1164 p = (struct extern_list *) ggc_alloc (sizeof (struct extern_list));
1165 p->next = extern_head;
1167 p->size = int_size_in_bytes (TREE_TYPE (decl));
1173 /* Implement RETURN_ADDR_RTX. Note, we do not support moving
1174 back to a previous frame. */
1176 score7_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
1180 return get_hard_reg_initial_val (Pmode, RA_REGNUM);
1183 /* Implement PRINT_OPERAND macro. */
1184 /* Score-specific operand codes:
1185 '[' print .set nor1 directive
1186 ']' print .set r1 directive
1187 'U' print hi part of a CONST_INT rtx
1190 'D' print SFmode const double
1191 'S' selectively print "!" if operand is 15bit instruction accessible
1192 'V' print "v!" if operand is 15bit instruction accessible, or "lfh!"
1193 'L' low part of DImode reg operand
1194 'H' high part of DImode reg operand
1195 'C' print part of opcode for a branch condition. */
1197 score7_print_operand (FILE *file, rtx op, int c)
1199 enum rtx_code code = -1;
1200 if (!PRINT_OPERAND_PUNCT_VALID_P (c))
1201 code = GET_CODE (op);
1205 fprintf (file, ".set r1\n");
1209 fprintf (file, "\n\t.set nor1");
1213 gcc_assert (code == CONST_INT);
1214 fprintf (file, HOST_WIDE_INT_PRINT_HEX,
1215 (INTVAL (op) >> 16) & 0xffff);
1219 if (GET_CODE (op) == CONST_DOUBLE)
1221 rtx temp = gen_lowpart (SImode, op);
1222 gcc_assert (GET_MODE (op) == SFmode);
1223 fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (temp) & 0xffffffff);
1226 output_addr_const (file, op);
1230 gcc_assert (code == REG);
1231 if (G16_REG_P (REGNO (op)))
1232 fprintf (file, "!");
1236 gcc_assert (code == REG);
1237 fprintf (file, G16_REG_P (REGNO (op)) ? "v!" : "lfh!");
1241 enum machine_mode mode = GET_MODE (XEXP (op, 0));
1245 case EQ: fputs ("eq", file); break;
1246 case NE: fputs ("ne", file); break;
1247 case GT: fputs ("gt", file); break;
1248 case GE: fputs (mode != CCmode ? "pl" : "ge", file); break;
1249 case LT: fputs (mode != CCmode ? "mi" : "lt", file); break;
1250 case LE: fputs ("le", file); break;
1251 case GTU: fputs ("gtu", file); break;
1252 case GEU: fputs ("cs", file); break;
1253 case LTU: fputs ("cc", file); break;
1254 case LEU: fputs ("leu", file); break;
1256 output_operand_lossage ("invalid operand for code: '%c'", code);
1261 unsigned HOST_WIDE_INT i;
1262 unsigned HOST_WIDE_INT pow2mask = 1;
1263 unsigned HOST_WIDE_INT val;
1266 for (i = 0; i < 32; i++)
1268 if (val == pow2mask)
1272 gcc_assert (i < 32);
1273 fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
1277 unsigned HOST_WIDE_INT i;
1278 unsigned HOST_WIDE_INT pow2mask = 1;
1279 unsigned HOST_WIDE_INT val;
1282 for (i = 0; i < 32; i++)
1284 if (val == pow2mask)
1288 gcc_assert (i < 32);
1289 fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
1291 else if (code == REG)
1293 int regnum = REGNO (op);
1294 if ((c == 'H' && !WORDS_BIG_ENDIAN)
1295 || (c == 'L' && WORDS_BIG_ENDIAN))
1297 fprintf (file, "%s", reg_names[regnum]);
1304 score7_print_operand_address (file, op);
1307 output_addr_const (file, op);
1312 /* Implement PRINT_OPERAND_ADDRESS macro. */
1314 score7_print_operand_address (FILE *file, rtx x)
1316 struct score7_address_info addr;
1317 enum rtx_code code = GET_CODE (x);
1318 enum machine_mode mode = GET_MODE (x);
1323 if (score7_classify_address (&addr, mode, x, true))
1327 case SCORE7_ADD_REG:
1332 fprintf (file, "[%s,-%ld]+", reg_names[REGNO (addr.reg)],
1333 INTVAL (addr.offset));
1336 fprintf (file, "[%s]+,-%ld", reg_names[REGNO (addr.reg)],
1337 INTVAL (addr.offset));
1340 fprintf (file, "[%s, %ld]+", reg_names[REGNO (addr.reg)],
1341 INTVAL (addr.offset));
1344 fprintf (file, "[%s]+, %ld", reg_names[REGNO (addr.reg)],
1345 INTVAL (addr.offset));
1348 if (INTVAL(addr.offset) == 0)
1349 fprintf(file, "[%s]", reg_names[REGNO (addr.reg)]);
1351 fprintf(file, "[%s, %ld]", reg_names[REGNO (addr.reg)],
1352 INTVAL(addr.offset));
1357 case SCORE7_ADD_CONST_INT:
1358 case SCORE7_ADD_SYMBOLIC:
1359 output_addr_const (file, x);
1363 print_rtl (stderr, x);
1367 /* Implement SELECT_CC_MODE macro. */
1369 score7_select_cc_mode (enum rtx_code op, rtx x, rtx y)
1371 if ((op == EQ || op == NE || op == LT || op == GE)
1373 && GET_MODE (x) == SImode)
1375 switch (GET_CODE (x))
1393 return (op == LT || op == GE) ? CC_Nmode : CCmode;
1400 if ((op == EQ || op == NE)
1401 && (GET_CODE (y) == NEG)
1402 && register_operand (XEXP (y, 0), SImode)
1403 && register_operand (x, SImode))
1411 /* Generate the prologue instructions for entry into a S+core function. */
1413 score7_prologue (void)
1415 #define EMIT_PL(_rtx) RTX_FRAME_RELATED_P (_rtx) = 1
1417 struct score7_frame_info *f = score7_compute_frame_size (get_frame_size ());
1421 size = f->total_size - f->gp_reg_size;
1424 emit_insn (gen_cpload_score7 ());
1426 for (regno = (int) GP_REG_LAST; regno >= (int) GP_REG_FIRST; regno--)
1428 if (BITSET_P (f->mask, regno - GP_REG_FIRST))
1430 rtx mem = gen_rtx_MEM (SImode,
1431 gen_rtx_PRE_DEC (SImode, stack_pointer_rtx));
1432 rtx reg = gen_rtx_REG (SImode, regno);
1433 if (!crtl->calls_eh_return)
1434 MEM_READONLY_P (mem) = 1;
1435 EMIT_PL (emit_insn (gen_pushsi_score7 (mem, reg)));
1443 if (CONST_OK_FOR_LETTER_P (-size, 'L'))
1444 EMIT_PL (emit_insn (gen_add3_insn (stack_pointer_rtx,
1449 EMIT_PL (emit_move_insn (gen_rtx_REG (Pmode, SCORE7_PROLOGUE_TEMP_REGNUM),
1452 (gen_sub3_insn (stack_pointer_rtx,
1455 SCORE7_PROLOGUE_TEMP_REGNUM))));
1457 insn = get_last_insn ();
1459 alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR,
1460 gen_rtx_SET (VOIDmode, stack_pointer_rtx,
1461 plus_constant (stack_pointer_rtx,
1466 if (frame_pointer_needed)
1467 EMIT_PL (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx));
1469 if (flag_pic && f->cprestore_size)
1471 if (frame_pointer_needed)
1472 emit_insn (gen_cprestore_use_fp_score7 (GEN_INT (size - f->cprestore_size)));
1474 emit_insn (gen_cprestore_use_sp_score7 (GEN_INT (size - f->cprestore_size)));
1480 /* Generate the epilogue instructions in a S+core function. */
1482 score7_epilogue (int sibcall_p)
1484 struct score7_frame_info *f = score7_compute_frame_size (get_frame_size ());
1489 size = f->total_size - f->gp_reg_size;
1491 if (!frame_pointer_needed)
1492 base = stack_pointer_rtx;
1494 base = hard_frame_pointer_rtx;
1498 if (CONST_OK_FOR_LETTER_P (size, 'L'))
1499 emit_insn (gen_add3_insn (base, base, GEN_INT (size)));
1502 emit_move_insn (gen_rtx_REG (Pmode, SCORE7_EPILOGUE_TEMP_REGNUM),
1504 emit_insn (gen_add3_insn (base, base,
1506 SCORE7_EPILOGUE_TEMP_REGNUM)));
1510 if (base != stack_pointer_rtx)
1511 emit_move_insn (stack_pointer_rtx, base);
1513 if (crtl->calls_eh_return)
1514 emit_insn (gen_add3_insn (stack_pointer_rtx,
1516 EH_RETURN_STACKADJ_RTX));
1518 for (regno = (int) GP_REG_FIRST; regno <= (int) GP_REG_LAST; regno++)
1520 if (BITSET_P (f->mask, regno - GP_REG_FIRST))
1522 rtx mem = gen_rtx_MEM (SImode,
1523 gen_rtx_POST_INC (SImode, stack_pointer_rtx));
1524 rtx reg = gen_rtx_REG (SImode, regno);
1526 if (!crtl->calls_eh_return)
1527 MEM_READONLY_P (mem) = 1;
1529 emit_insn (gen_popsi_score7 (reg, mem));
1534 emit_jump_insn (gen_return_internal_score7 (gen_rtx_REG (Pmode, RA_REGNUM)));
1538 score7_gen_cmp (enum machine_mode mode)
1540 emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (mode, CC_REGNUM),
1541 gen_rtx_COMPARE (mode, cmp_op0, cmp_op1)));
1544 /* Return true if X is a symbolic constant that can be calculated in
1545 the same way as a bare symbol. If it is, store the type of the
1546 symbol in *SYMBOL_TYPE. */
1548 score7_symbolic_constant_p (rtx x, enum score_symbol_type *symbol_type)
1550 HOST_WIDE_INT offset;
1552 score7_split_const (x, &x, &offset);
1553 if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF)
1554 *symbol_type = score7_classify_symbol (x);
1561 /* if offset > 15bit, must reload */
1562 if (!IMM_IN_RANGE (offset, 15, 1))
1565 switch (*symbol_type)
1567 case SYMBOL_GENERAL:
1569 case SYMBOL_SMALL_DATA:
1570 return score7_offset_within_object_p (x, offset);
1576 score7_movsicc (rtx *ops)
1578 enum machine_mode mode;
1580 mode = score7_select_cc_mode (GET_CODE (ops[1]), ops[2], ops[3]);
1581 emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (mode, CC_REGNUM),
1582 gen_rtx_COMPARE (mode, cmp_op0, cmp_op1)));
1585 /* Call and sibcall pattern all need call this function. */
1587 score7_call (rtx *ops, bool sib)
1589 rtx addr = XEXP (ops[0], 0);
1590 if (!call_insn_operand (addr, VOIDmode))
1593 addr = gen_reg_rtx (Pmode);
1594 gen_move_insn (addr, oaddr);
1598 emit_call_insn (gen_sibcall_internal_score7 (addr, ops[1]));
1600 emit_call_insn (gen_call_internal_score7 (addr, ops[1]));
1603 /* Call value and sibcall value pattern all need call this function. */
1605 score7_call_value (rtx *ops, bool sib)
1607 rtx result = ops[0];
1608 rtx addr = XEXP (ops[1], 0);
1611 if (!call_insn_operand (addr, VOIDmode))
1614 addr = gen_reg_rtx (Pmode);
1615 gen_move_insn (addr, oaddr);
1619 emit_call_insn (gen_sibcall_value_internal_score7 (result, addr, arg));
1621 emit_call_insn (gen_call_value_internal_score7 (result, addr, arg));
1626 score7_movdi (rtx *ops)
1630 rtx dst0 = score7_subw (dst, 0);
1631 rtx dst1 = score7_subw (dst, 1);
1632 rtx src0 = score7_subw (src, 0);
1633 rtx src1 = score7_subw (src, 1);
1635 if (GET_CODE (dst0) == REG && reg_overlap_mentioned_p (dst0, src))
1637 emit_move_insn (dst1, src1);
1638 emit_move_insn (dst0, src0);
1642 emit_move_insn (dst0, src0);
1643 emit_move_insn (dst1, src1);
1648 score7_zero_extract_andi (rtx *ops)
1650 if (INTVAL (ops[1]) == 1 && const_uimm5 (ops[2], SImode))
1651 emit_insn (gen_zero_extract_bittst_score7 (ops[0], ops[2]));
1654 unsigned HOST_WIDE_INT mask;
1655 mask = (0xffffffffU & ((1U << INTVAL (ops[1])) - 1U));
1656 mask = mask << INTVAL (ops[2]);
1657 emit_insn (gen_andsi3_cmp_score7 (ops[3], ops[0],
1658 gen_int_mode (mask, SImode)));
1662 /* Check addr could be present as PRE/POST mode. */
1664 score7_pindex_mem (rtx addr)
1666 if (GET_CODE (addr) == MEM)
1668 switch (GET_CODE (XEXP (addr, 0)))
1682 /* Output asm code for ld/sw insn. */
1684 score7_pr_addr_post (rtx *ops, int idata, int iaddr, char *ip, enum score_mem_unit unit)
1686 struct score7_address_info ai;
1688 gcc_assert (GET_CODE (ops[idata]) == REG);
1689 gcc_assert (score7_classify_address (&ai, SImode, XEXP (ops[iaddr], 0), true));
1691 if (!score7_pindex_mem (ops[iaddr])
1692 && ai.type == SCORE7_ADD_REG
1693 && GET_CODE (ai.offset) == CONST_INT
1694 && G16_REG_P (REGNO (ops[idata]))
1695 && G16_REG_P (REGNO (ai.reg)))
1697 if (INTVAL (ai.offset) == 0)
1699 ops[iaddr] = ai.reg;
1700 return snprintf (ip, INS_BUF_SZ,
1701 "!\t%%%d, [%%%d]", idata, iaddr);
1703 if (REGNO (ai.reg) == HARD_FRAME_POINTER_REGNUM)
1705 HOST_WIDE_INT offset = INTVAL (ai.offset);
1706 if (SCORE_ALIGN_UNIT (offset, unit)
1707 && CONST_OK_FOR_LETTER_P (offset >> unit, 'J'))
1709 ops[iaddr] = ai.offset;
1710 return snprintf (ip, INS_BUF_SZ,
1711 "p!\t%%%d, %%c%d", idata, iaddr);
1715 return snprintf (ip, INS_BUF_SZ, "\t%%%d, %%a%d", idata, iaddr);
1718 /* Output asm insn for load. */
1720 score7_linsn (rtx *ops, enum score_mem_unit unit, bool sign)
1722 const char *pre_ins[] =
1723 {"lbu", "lhu", "lw", "??", "lb", "lh", "lw", "??"};
1726 strcpy (score7_ins, pre_ins[(sign ? 4 : 0) + unit]);
1727 ip = score7_ins + strlen (score7_ins);
1729 if ((!sign && unit != SCORE_HWORD)
1730 || (sign && unit != SCORE_BYTE))
1731 score7_pr_addr_post (ops, 0, 1, ip, unit);
1733 snprintf (ip, INS_BUF_SZ, "\t%%0, %%a1");
1738 /* Output asm insn for store. */
1740 score7_sinsn (rtx *ops, enum score_mem_unit unit)
1742 const char *pre_ins[] = {"sb", "sh", "sw"};
1745 strcpy (score7_ins, pre_ins[unit]);
1746 ip = score7_ins + strlen (score7_ins);
1747 score7_pr_addr_post (ops, 1, 0, ip, unit);
1751 /* Output asm insn for load immediate. */
1753 score7_limm (rtx *ops)
1757 gcc_assert (GET_CODE (ops[0]) == REG);
1758 gcc_assert (GET_CODE (ops[1]) == CONST_INT);
1760 v = INTVAL (ops[1]);
1761 if (G16_REG_P (REGNO (ops[0])) && IMM_IN_RANGE (v, 8, 0))
1762 return "ldiu!\t%0, %c1";
1763 else if (IMM_IN_RANGE (v, 16, 1))
1764 return "ldi\t%0, %c1";
1765 else if ((v & 0xffff) == 0)
1766 return "ldis\t%0, %U1";
1768 return "li\t%0, %c1";
1771 /* Output asm insn for move. */
1773 score7_move (rtx *ops)
1775 gcc_assert (GET_CODE (ops[0]) == REG);
1776 gcc_assert (GET_CODE (ops[1]) == REG);
1778 if (G16_REG_P (REGNO (ops[0])))
1780 if (G16_REG_P (REGNO (ops[1])))
1781 return "mv!\t%0, %1";
1783 return "mlfh!\t%0, %1";
1785 else if (G16_REG_P (REGNO (ops[1])))
1786 return "mhfl!\t%0, %1";
1788 return "mv\t%0, %1";
1791 /* Generate add insn. */
1793 score7_select_add_imm (rtx *ops, bool set_cc)
1795 HOST_WIDE_INT v = INTVAL (ops[2]);
1797 gcc_assert (GET_CODE (ops[2]) == CONST_INT);
1798 gcc_assert (REGNO (ops[0]) == REGNO (ops[1]));
1800 if (set_cc && G16_REG_P (REGNO (ops[0])))
1802 if (v > 0 && IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT) v, 0, 15))
1804 ops[2] = GEN_INT (ffs (v) - 1);
1805 return "addei!\t%0, %c2";
1808 if (v < 0 && IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT) (-v), 0, 15))
1810 ops[2] = GEN_INT (ffs (-v) - 1);
1811 return "subei!\t%0, %c2";
1816 return "addi.c\t%0, %c2";
1818 return "addi\t%0, %c2";
1821 /* Output arith insn. */
1823 score7_select (rtx *ops, const char *inst_pre,
1824 bool commu, const char *letter, bool set_cc)
1826 gcc_assert (GET_CODE (ops[0]) == REG);
1827 gcc_assert (GET_CODE (ops[1]) == REG);
1829 if (set_cc && G16_REG_P (REGNO (ops[0]))
1830 && (GET_CODE (ops[2]) == REG ? G16_REG_P (REGNO (ops[2])) : 1)
1831 && REGNO (ops[0]) == REGNO (ops[1]))
1833 snprintf (score7_ins, INS_BUF_SZ, "%s!\t%%0, %%%s2", inst_pre, letter);
1837 if (commu && set_cc && G16_REG_P (REGNO (ops[0]))
1838 && G16_REG_P (REGNO (ops[1]))
1839 && REGNO (ops[0]) == REGNO (ops[2]))
1841 gcc_assert (GET_CODE (ops[2]) == REG);
1842 snprintf (score7_ins, INS_BUF_SZ, "%s!\t%%0, %%%s1", inst_pre, letter);
1847 snprintf (score7_ins, INS_BUF_SZ, "%s.c\t%%0, %%1, %%%s2", inst_pre, letter);
1849 snprintf (score7_ins, INS_BUF_SZ, "%s\t%%0, %%1, %%%s2", inst_pre, letter);