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"
28 #include "insn-config.h"
29 #include "conditions.h"
30 #include "insn-attr.h"
46 #include "target-def.h"
47 #include "integrate.h"
48 #include "langhooks.h"
49 #include "cfglayout.h"
53 #define BITSET_P(VALUE, BIT) (((VALUE) & (1L << (BIT))) != 0)
54 #define INS_BUF_SZ 128
56 extern enum reg_class score_char_to_class[256];
58 static int score7_sdata_max;
59 static char score7_ins[INS_BUF_SZ + 8];
61 /* Return true if SYMBOL is a SYMBOL_REF and OFFSET + SYMBOL points
62 to the same object as SYMBOL. */
64 score7_offset_within_object_p (rtx symbol, HOST_WIDE_INT offset)
66 if (GET_CODE (symbol) != SYMBOL_REF)
69 if (CONSTANT_POOL_ADDRESS_P (symbol)
71 && offset < (int)GET_MODE_SIZE (get_pool_mode (symbol)))
74 if (SYMBOL_REF_DECL (symbol) != 0
76 && offset < int_size_in_bytes (TREE_TYPE (SYMBOL_REF_DECL (symbol))))
82 /* Split X into a base and a constant offset, storing them in *BASE
83 and *OFFSET respectively. */
85 score7_split_const (rtx x, rtx *base, HOST_WIDE_INT *offset)
89 if (GET_CODE (x) == CONST)
92 if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
94 *offset += INTVAL (XEXP (x, 1));
101 /* Classify symbol X, which must be a SYMBOL_REF or a LABEL_REF. */
102 static enum score_symbol_type
103 score7_classify_symbol (rtx x)
105 if (GET_CODE (x) == LABEL_REF)
106 return SYMBOL_GENERAL;
108 gcc_assert (GET_CODE (x) == SYMBOL_REF);
110 if (CONSTANT_POOL_ADDRESS_P (x))
112 if (GET_MODE_SIZE (get_pool_mode (x)) <= SCORE7_SDATA_MAX)
113 return SYMBOL_SMALL_DATA;
114 return SYMBOL_GENERAL;
116 if (SYMBOL_REF_SMALL_P (x))
117 return SYMBOL_SMALL_DATA;
118 return SYMBOL_GENERAL;
121 /* Return true if the current function must save REGNO. */
123 score7_save_reg_p (unsigned int regno)
125 /* Check call-saved registers. */
126 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
129 /* We need to save the old frame pointer before setting up a new one. */
130 if (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed)
133 /* We need to save the incoming return address if it is ever clobbered
134 within the function. */
135 if (regno == RA_REGNUM && df_regs_ever_live_p (regno))
141 /* Return one word of double-word value OP, taking into account the fixed
142 endianness of certain registers. HIGH_P is true to select the high part,
143 false to select the low part. */
145 score7_subw (rtx op, int high_p)
148 enum machine_mode mode = GET_MODE (op);
150 if (mode == VOIDmode)
153 byte = (TARGET_LITTLE_ENDIAN ? high_p : !high_p) ? UNITS_PER_WORD : 0;
155 if (GET_CODE (op) == REG && REGNO (op) == HI_REGNUM)
156 return gen_rtx_REG (SImode, high_p ? HI_REGNUM : LO_REGNUM);
158 if (GET_CODE (op) == MEM)
159 return adjust_address (op, SImode, byte);
161 return simplify_gen_subreg (SImode, op, mode, byte);
164 static struct score7_frame_info *
165 score7_cached_frame (void)
167 static struct score7_frame_info _frame_info;
171 /* Return the bytes needed to compute the frame pointer from the current
172 stack pointer. SIZE is the size (in bytes) of the local variables. */
173 static struct score7_frame_info *
174 score7_compute_frame_size (HOST_WIDE_INT size)
177 struct score7_frame_info *f = score7_cached_frame ();
179 memset (f, 0, sizeof (struct score7_frame_info));
182 f->var_size = SCORE7_STACK_ALIGN (size);
183 f->args_size = crtl->outgoing_args_size;
184 f->cprestore_size = flag_pic ? UNITS_PER_WORD : 0;
185 if (f->var_size == 0 && current_function_is_leaf)
186 f->args_size = f->cprestore_size = 0;
188 if (f->args_size == 0 && cfun->calls_alloca)
189 f->args_size = UNITS_PER_WORD;
191 f->total_size = f->var_size + f->args_size + f->cprestore_size;
192 for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
194 if (score7_save_reg_p (regno))
196 f->gp_reg_size += GET_MODE_SIZE (SImode);
197 f->mask |= 1 << (regno - GP_REG_FIRST);
201 if (crtl->calls_eh_return)
206 regno = EH_RETURN_DATA_REGNO (i);
207 if (regno == INVALID_REGNUM)
209 f->gp_reg_size += GET_MODE_SIZE (SImode);
210 f->mask |= 1 << (regno - GP_REG_FIRST);
214 f->total_size += f->gp_reg_size;
215 f->num_gp = f->gp_reg_size / UNITS_PER_WORD;
219 HOST_WIDE_INT offset;
220 offset = (f->args_size + f->cprestore_size + f->var_size
221 + f->gp_reg_size - GET_MODE_SIZE (SImode));
222 f->gp_sp_offset = offset;
230 /* Return true if X is a valid base register for the given mode.
231 Allow only hard registers if STRICT. */
233 score7_valid_base_register_p (rtx x, int strict)
235 if (!strict && GET_CODE (x) == SUBREG)
238 return (GET_CODE (x) == REG
239 && score7_regno_mode_ok_for_base_p (REGNO (x), strict));
242 /* Return true if X is a valid address for machine mode MODE. If it is,
243 fill in INFO appropriately. STRICT is true if we should only accept
244 hard base registers. */
246 score7_classify_address (struct score7_address_info *info,
247 enum machine_mode mode, rtx x, int strict)
249 info->code = GET_CODE (x);
255 info->type = SCORE7_ADD_REG;
257 info->offset = const0_rtx;
258 return score7_valid_base_register_p (info->reg, strict);
260 info->type = SCORE7_ADD_REG;
261 info->reg = XEXP (x, 0);
262 info->offset = XEXP (x, 1);
263 return (score7_valid_base_register_p (info->reg, strict)
264 && GET_CODE (info->offset) == CONST_INT
265 && IMM_IN_RANGE (INTVAL (info->offset), 15, 1));
270 if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (SImode))
272 info->type = SCORE7_ADD_REG;
273 info->reg = XEXP (x, 0);
274 info->offset = GEN_INT (GET_MODE_SIZE (mode));
275 return score7_valid_base_register_p (info->reg, strict);
277 info->type = SCORE7_ADD_CONST_INT;
278 return IMM_IN_RANGE (INTVAL (x), 15, 1);
282 info->type = SCORE7_ADD_SYMBOLIC;
283 return (score7_symbolic_constant_p (x, &info->symbol_type)
284 && (info->symbol_type == SYMBOL_GENERAL
285 || info->symbol_type == SYMBOL_SMALL_DATA));
292 score7_return_in_memory (tree type, tree fndecl ATTRIBUTE_UNUSED)
294 return ((TYPE_MODE (type) == BLKmode)
295 || (int_size_in_bytes (type) > 2 * UNITS_PER_WORD)
296 || (int_size_in_bytes (type) == -1));
299 /* Return a legitimate address for REG + OFFSET. */
301 score7_add_offset (rtx reg, HOST_WIDE_INT offset)
303 if (!IMM_IN_RANGE (offset, 15, 1))
305 reg = expand_simple_binop (GET_MODE (reg), PLUS,
306 gen_int_mode (offset & 0xffffc000,
308 reg, NULL, 0, OPTAB_WIDEN);
312 return plus_constant (reg, offset);
315 /* Implement TARGET_ASM_OUTPUT_MI_THUNK. Generate rtl rather than asm text
316 in order to avoid duplicating too much logic from elsewhere. */
318 score7_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
319 HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
322 rtx this_rtx, temp1, insn, fnaddr;
324 /* Pretend to be a post-reload pass while generating rtl. */
325 reload_completed = 1;
327 /* Mark the end of the (empty) prologue. */
328 emit_note (NOTE_INSN_PROLOGUE_END);
330 /* We need two temporary registers in some cases. */
331 temp1 = gen_rtx_REG (Pmode, 8);
333 /* Find out which register contains the "this" pointer. */
334 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
335 this_rtx = gen_rtx_REG (Pmode, ARG_REG_FIRST + 1);
337 this_rtx = gen_rtx_REG (Pmode, ARG_REG_FIRST);
339 /* Add DELTA to THIS_RTX. */
342 rtx offset = GEN_INT (delta);
343 if (!CONST_OK_FOR_LETTER_P (delta, 'L'))
345 emit_move_insn (temp1, offset);
348 emit_insn (gen_add3_insn (this_rtx, this_rtx, offset));
351 /* If needed, add *(*THIS_RTX + VCALL_OFFSET) to THIS_RTX. */
352 if (vcall_offset != 0)
356 /* Set TEMP1 to *THIS_RTX. */
357 emit_move_insn (temp1, gen_rtx_MEM (Pmode, this_rtx));
359 /* Set ADDR to a legitimate address for *THIS_RTX + VCALL_OFFSET. */
360 addr = score7_add_offset (temp1, vcall_offset);
362 /* Load the offset and add it to THIS_RTX. */
363 emit_move_insn (temp1, gen_rtx_MEM (Pmode, addr));
364 emit_insn (gen_add3_insn (this_rtx, this_rtx, temp1));
367 /* Jump to the target function. */
368 fnaddr = XEXP (DECL_RTL (function), 0);
369 insn = emit_call_insn (gen_sibcall_internal_score7 (fnaddr, const0_rtx));
370 SIBLING_CALL_P (insn) = 1;
372 /* Run just enough of rest_of_compilation. This sequence was
373 "borrowed" from alpha.c. */
375 insn_locators_alloc ();
376 split_all_insns_noflow ();
377 shorten_branches (insn);
378 final_start_function (insn, file, 1);
379 final (insn, file, 1);
380 final_end_function ();
382 /* Clean up the vars set above. Note that final_end_function resets
383 the global pointer for us. */
384 reload_completed = 0;
387 /* Copy VALUE to a register and return that register. If new psuedos
388 are allowed, copy it into a new register, otherwise use DEST. */
390 score7_force_temporary (rtx dest, rtx value)
392 if (can_create_pseudo_p ())
393 return force_reg (Pmode, value);
396 emit_move_insn (copy_rtx (dest), value);
401 /* Return a LO_SUM expression for ADDR. TEMP is as for score_force_temporary
402 and is used to load the high part into a register. */
404 score7_split_symbol (rtx temp, rtx addr)
406 rtx high = score7_force_temporary (temp,
407 gen_rtx_HIGH (Pmode, copy_rtx (addr)));
408 return gen_rtx_LO_SUM (Pmode, high, addr);
411 /* This function is used to implement LEGITIMIZE_ADDRESS. If X can
412 be legitimized in a way that the generic machinery might not expect,
413 return the new address. */
415 score7_legitimize_address (rtx x)
417 enum score_symbol_type symbol_type;
419 if (score7_symbolic_constant_p (x, &symbol_type)
420 && symbol_type == SYMBOL_GENERAL)
421 return score7_split_symbol (0, x);
423 if (GET_CODE (x) == PLUS
424 && GET_CODE (XEXP (x, 1)) == CONST_INT)
426 rtx reg = XEXP (x, 0);
427 if (!score7_valid_base_register_p (reg, 0))
428 reg = copy_to_mode_reg (Pmode, reg);
429 return score7_add_offset (reg, INTVAL (XEXP (x, 1)));
435 /* Fill INFO with information about a single argument. CUM is the
436 cumulative state for earlier arguments. MODE is the mode of this
437 argument and TYPE is its type (if known). NAMED is true if this
438 is a named (fixed) argument rather than a variable one. */
440 score7_classify_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
441 tree type, int named, struct score7_arg_info *info)
444 unsigned int num_words, max_regs;
447 if (GET_MODE_CLASS (mode) == MODE_INT
448 || GET_MODE_CLASS (mode) == MODE_FLOAT)
449 even_reg_p = (GET_MODE_SIZE (mode) > UNITS_PER_WORD);
451 if (type != NULL_TREE && TYPE_ALIGN (type) > BITS_PER_WORD && named)
454 if (TARGET_MUST_PASS_IN_STACK (mode, type))
455 info->reg_offset = ARG_REG_NUM;
458 info->reg_offset = cum->num_gprs;
460 info->reg_offset += info->reg_offset & 1;
464 info->num_bytes = int_size_in_bytes (type);
466 info->num_bytes = GET_MODE_SIZE (mode);
468 num_words = (info->num_bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
469 max_regs = ARG_REG_NUM - info->reg_offset;
471 /* Partition the argument between registers and stack. */
472 info->reg_words = MIN (num_words, max_regs);
473 info->stack_words = num_words - info->reg_words;
475 /* The alignment applied to registers is also applied to stack arguments. */
476 if (info->stack_words)
478 info->stack_offset = cum->stack_words;
480 info->stack_offset += info->stack_offset & 1;
484 /* Set up the stack and frame (if desired) for the function. */
486 score7_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
489 struct score7_frame_info *f = score7_cached_frame ();
490 HOST_WIDE_INT tsize = f->total_size;
492 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
493 if (!flag_inhibit_size_directive)
495 fputs ("\t.ent\t", file);
496 assemble_name (file, fnname);
499 assemble_name (file, fnname);
502 if (!flag_inhibit_size_directive)
505 "\t.frame\t%s," HOST_WIDE_INT_PRINT_DEC ",%s, %d\t\t"
506 "# vars= " HOST_WIDE_INT_PRINT_DEC ", regs= %d"
507 ", args= " HOST_WIDE_INT_PRINT_DEC
508 ", gp= " HOST_WIDE_INT_PRINT_DEC "\n",
509 (reg_names[(frame_pointer_needed)
510 ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM]),
512 reg_names[RA_REGNUM],
513 current_function_is_leaf ? 1 : 0,
519 fprintf(file, "\t.mask\t0x%08x," HOST_WIDE_INT_PRINT_DEC "\n",
521 (f->gp_sp_offset - f->total_size));
525 /* Do any necessary cleanup after a function to restore stack, frame,
528 score7_function_epilogue (FILE *file,
529 HOST_WIDE_INT size ATTRIBUTE_UNUSED)
531 if (!flag_inhibit_size_directive)
534 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
535 fputs ("\t.end\t", file);
536 assemble_name (file, fnname);
541 /* Returns true if X contains a SYMBOL_REF. */
543 score7_symbolic_expression_p (rtx x)
545 if (GET_CODE (x) == SYMBOL_REF)
548 if (GET_CODE (x) == CONST)
549 return score7_symbolic_expression_p (XEXP (x, 0));
552 return score7_symbolic_expression_p (XEXP (x, 0));
554 if (ARITHMETIC_P (x))
555 return (score7_symbolic_expression_p (XEXP (x, 0))
556 || score7_symbolic_expression_p (XEXP (x, 1)));
561 /* Choose the section to use for the constant rtx expression X that has
564 score7_select_rtx_section (enum machine_mode mode, rtx x,
565 unsigned HOST_WIDE_INT align)
567 if (GET_MODE_SIZE (mode) <= SCORE7_SDATA_MAX)
568 return get_named_section (0, ".sdata", 0);
569 else if (flag_pic && score7_symbolic_expression_p (x))
570 return get_named_section (0, ".data.rel.ro", 3);
572 return mergeable_constant_section (mode, align, 0);
575 /* Implement TARGET_IN_SMALL_DATA_P. */
577 score7_in_small_data_p (tree decl)
581 if (TREE_CODE (decl) == STRING_CST
582 || TREE_CODE (decl) == FUNCTION_DECL)
585 if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl) != 0)
588 name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
589 if (strcmp (name, ".sdata") != 0
590 && strcmp (name, ".sbss") != 0)
592 if (!DECL_EXTERNAL (decl))
595 size = int_size_in_bytes (TREE_TYPE (decl));
596 return (size > 0 && size <= SCORE7_SDATA_MAX);
599 /* Implement TARGET_ASM_FILE_START. */
601 score7_asm_file_start (void)
603 default_file_start ();
604 fprintf (asm_out_file, ASM_COMMENT_START
605 "GCC for S+core %s \n", SCORE_GCC_VERSION);
608 fprintf (asm_out_file, "\t.set pic\n");
611 /* Implement TARGET_ASM_FILE_END. When using assembler macros, emit
612 .externs for any small-data variables that turned out to be external. */
614 score7_asm_file_end (void)
617 struct extern_list *p;
620 fputs ("\n", asm_out_file);
621 for (p = extern_head; p != 0; p = p->next)
623 name_tree = get_identifier (p->name);
624 if (!TREE_ASM_WRITTEN (name_tree)
625 && TREE_SYMBOL_REFERENCED (name_tree))
627 TREE_ASM_WRITTEN (name_tree) = 1;
628 fputs ("\t.extern\t", asm_out_file);
629 assemble_name (asm_out_file, p->name);
630 fprintf (asm_out_file, ", %d\n", p->size);
636 /* Implement OVERRIDE_OPTIONS macro. */
638 score7_override_options (void)
642 score7_sdata_max = g_switch_set ? g_switch_value : SCORE7_DEFAULT_SDATA_MAX;
645 score7_sdata_max = 0;
646 if (g_switch_set && (g_switch_value != 0))
647 warning (0, "-fPIC and -G are incompatible");
650 score_char_to_class['d'] = G32_REGS;
651 score_char_to_class['e'] = G16_REGS;
652 score_char_to_class['t'] = T32_REGS;
654 score_char_to_class['h'] = HI_REG;
655 score_char_to_class['l'] = LO_REG;
656 score_char_to_class['x'] = CE_REGS;
658 score_char_to_class['q'] = CN_REG;
659 score_char_to_class['y'] = LC_REG;
660 score_char_to_class['z'] = SC_REG;
661 score_char_to_class['a'] = SP_REGS;
663 score_char_to_class['c'] = CR_REGS;
666 /* Implement REGNO_REG_CLASS macro. */
668 score7_reg_class (int regno)
671 gcc_assert (regno >= 0 && regno < FIRST_PSEUDO_REGISTER);
673 if (regno == FRAME_POINTER_REGNUM
674 || regno == ARG_POINTER_REGNUM)
677 for (c = 0; c < N_REG_CLASSES; c++)
678 if (TEST_HARD_REG_BIT (reg_class_contents[c], regno))
684 /* Implement PREFERRED_RELOAD_CLASS macro. */
686 score7_preferred_reload_class (rtx x ATTRIBUTE_UNUSED, enum reg_class rclass)
688 if (reg_class_subset_p (G16_REGS, rclass))
690 if (reg_class_subset_p (G32_REGS, rclass))
695 /* Implement SECONDARY_INPUT_RELOAD_CLASS
696 and SECONDARY_OUTPUT_RELOAD_CLASS macro. */
698 score7_secondary_reload_class (enum reg_class rclass,
699 enum machine_mode mode ATTRIBUTE_UNUSED,
703 if (GET_CODE (x) == REG || GET_CODE(x) == SUBREG)
704 regno = true_regnum (x);
706 if (!GR_REG_CLASS_P (rclass))
707 return GP_REG_P (regno) ? NO_REGS : G32_REGS;
711 /* Implement CONST_OK_FOR_LETTER_P macro. */
720 score7_const_ok_for_letter_p (HOST_WIDE_INT value, char c)
724 case 'I': return ((value & 0xffff) == 0);
725 case 'J': return IMM_IN_RANGE (value, 5, 0);
726 case 'K': return IMM_IN_RANGE (value, 16, 0);
727 case 'L': return IMM_IN_RANGE (value, 16, 1);
728 case 'M': return IMM_IN_RANGE (value, 14, 0);
729 case 'N': return IMM_IN_RANGE (value, 14, 1);
734 /* Implement EXTRA_CONSTRAINT macro. */
737 score7_extra_constraint (rtx op, char c)
742 return GET_CODE (op) == SYMBOL_REF;
748 /* Return truth value on whether or not a given hard register
749 can support a given mode. */
751 score7_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
753 int size = GET_MODE_SIZE (mode);
754 enum mode_class mclass = GET_MODE_CLASS (mode);
756 if (mclass == MODE_CC)
757 return regno == CC_REGNUM;
758 else if (regno == FRAME_POINTER_REGNUM
759 || regno == ARG_POINTER_REGNUM)
760 return mclass == MODE_INT;
761 else if (GP_REG_P (regno))
762 /* ((regno <= (GP_REG_LAST- HARD_REGNO_NREGS (dummy, mode)) + 1) */
763 return !(regno & 1) || (size <= UNITS_PER_WORD);
764 else if (CE_REG_P (regno))
765 return (mclass == MODE_INT
766 && ((size <= UNITS_PER_WORD)
767 || (regno == CE_REG_FIRST && size == 2 * UNITS_PER_WORD)));
769 return (mclass == MODE_INT) && (size <= UNITS_PER_WORD);
772 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
773 pointer or argument pointer. TO is either the stack pointer or
774 hard frame pointer. */
776 score7_initial_elimination_offset (int from,
777 int to ATTRIBUTE_UNUSED)
779 struct score7_frame_info *f = score7_compute_frame_size (get_frame_size ());
782 case ARG_POINTER_REGNUM:
783 return f->total_size;
784 case FRAME_POINTER_REGNUM:
791 /* Implement FUNCTION_ARG_ADVANCE macro. */
793 score7_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
794 tree type, int named)
796 struct score7_arg_info info;
797 score7_classify_arg (cum, mode, type, named, &info);
798 cum->num_gprs = info.reg_offset + info.reg_words;
799 if (info.stack_words > 0)
800 cum->stack_words = info.stack_offset + info.stack_words;
804 /* Implement TARGET_ARG_PARTIAL_BYTES macro. */
806 score7_arg_partial_bytes (CUMULATIVE_ARGS *cum,
807 enum machine_mode mode, tree type, bool named)
809 struct score7_arg_info info;
810 score7_classify_arg (cum, mode, type, named, &info);
811 return info.stack_words > 0 ? info.reg_words * UNITS_PER_WORD : 0;
814 /* Implement FUNCTION_ARG macro. */
816 score7_function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
817 tree type, int named)
819 struct score7_arg_info info;
821 if (mode == VOIDmode || !named)
824 score7_classify_arg (cum, mode, type, named, &info);
826 if (info.reg_offset == ARG_REG_NUM)
829 if (!info.stack_words)
830 return gen_rtx_REG (mode, ARG_REG_FIRST + info.reg_offset);
833 rtx ret = gen_rtx_PARALLEL (mode, rtvec_alloc (info.reg_words));
834 unsigned int i, part_offset = 0;
835 for (i = 0; i < info.reg_words; i++)
838 reg = gen_rtx_REG (SImode, ARG_REG_FIRST + info.reg_offset + i);
839 XVECEXP (ret, 0, i) = gen_rtx_EXPR_LIST (SImode, reg,
840 GEN_INT (part_offset));
841 part_offset += UNITS_PER_WORD;
847 /* Implement FUNCTION_VALUE and LIBCALL_VALUE. For normal calls,
848 VALTYPE is the return type and MODE is VOIDmode. For libcalls,
849 VALTYPE is null and MODE is the mode of the return value. */
851 score7_function_value (tree valtype, tree func, enum machine_mode mode)
856 mode = TYPE_MODE (valtype);
857 unsignedp = TYPE_UNSIGNED (valtype);
858 mode = promote_function_mode (valtype, mode, &unsignedp, func, 1);
860 return gen_rtx_REG (mode, RT_REGNUM);
863 /* Implement TARGET_ASM_TRAMPOLINE_TEMPLATE. */
866 score7_asm_trampoline_template (FILE *f)
868 fprintf (f, "\t.set r1\n");
869 fprintf (f, "\tmv r31, r3\n");
870 fprintf (f, "\tbl nextinsn\n");
871 fprintf (f, "nextinsn:\n");
872 fprintf (f, "\tlw r1, [r3, 6*4-8]\n");
873 fprintf (f, "\tlw r23, [r3, 6*4-4]\n");
874 fprintf (f, "\tmv r3, r31\n");
875 fprintf (f, "\tbr! r1\n");
876 fprintf (f, "\tnop!\n");
877 fprintf (f, "\t.set nor1\n");
880 /* Implement TARGET_TRAMPOLINE_INIT. */
882 score7_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
884 #define FFCACHE "_flush_cache"
885 #define CODE_SIZE (TRAMPOLINE_INSNS * UNITS_PER_WORD)
887 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
888 rtx addr = XEXP (m_tramp, 0);
891 emit_block_move (m_tramp, assemble_trampoline_template (),
892 GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
894 mem = adjust_address (m_tramp, SImode, CODE_SIZE);
895 emit_move_insn (mem, fnaddr);
896 mem = adjust_address (m_tramp, SImode, CODE_SIZE + GET_MODE_SIZE (SImode));
897 emit_move_insn (mem, chain_value);
899 emit_library_call (gen_rtx_SYMBOL_REF (Pmode, FFCACHE),
902 GEN_INT (TRAMPOLINE_SIZE), SImode);
907 /* This function is used to implement REG_MODE_OK_FOR_BASE_P macro. */
909 score7_regno_mode_ok_for_base_p (int regno, int strict)
911 if (regno >= FIRST_PSEUDO_REGISTER)
915 regno = reg_renumber[regno];
917 if (regno == ARG_POINTER_REGNUM
918 || regno == FRAME_POINTER_REGNUM)
920 return GP_REG_P (regno);
923 /* Implement TARGET_LEGITIMATE_ADDRESS_P macro. */
925 score7_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
927 struct score7_address_info addr;
929 return score7_classify_address (&addr, mode, x, strict);
932 /* Return a number assessing the cost of moving a register in class
935 score7_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
936 enum reg_class from, enum reg_class to)
938 if (GR_REG_CLASS_P (from))
940 if (GR_REG_CLASS_P (to))
942 else if (SP_REG_CLASS_P (to))
944 else if (CP_REG_CLASS_P (to))
946 else if (CE_REG_CLASS_P (to))
949 if (GR_REG_CLASS_P (to))
951 if (GR_REG_CLASS_P (from))
953 else if (SP_REG_CLASS_P (from))
955 else if (CP_REG_CLASS_P (from))
957 else if (CE_REG_CLASS_P (from))
963 /* Return the number of instructions needed to load a symbol of the
964 given type into a register. */
966 score7_symbol_insns (enum score_symbol_type type)
973 case SYMBOL_SMALL_DATA:
980 /* Return the number of instructions needed to load or store a value
981 of mode MODE at X. Return 0 if X isn't valid for MODE. */
983 score7_address_insns (rtx x, enum machine_mode mode)
985 struct score7_address_info addr;
991 factor = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
993 if (score7_classify_address (&addr, mode, x, false))
997 case SCORE7_ADD_CONST_INT:
1000 case SCORE7_ADD_SYMBOLIC:
1001 return factor * score7_symbol_insns (addr.symbol_type);
1006 /* Implement TARGET_RTX_COSTS macro. */
1008 score7_rtx_costs (rtx x, int code, int outer_code, int *total,
1009 bool speed ATTRIBUTE_UNUSED)
1011 enum machine_mode mode = GET_MODE (x);
1016 if (outer_code == SET)
1018 if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
1019 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L'))
1020 *total = COSTS_N_INSNS (1);
1022 *total = COSTS_N_INSNS (2);
1024 else if (outer_code == PLUS || outer_code == MINUS)
1026 if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'N'))
1028 else if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
1029 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L'))
1032 *total = COSTS_N_INSNS (2);
1034 else if (outer_code == AND || outer_code == IOR)
1036 if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'M'))
1038 else if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
1039 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'K'))
1042 *total = COSTS_N_INSNS (2);
1054 *total = COSTS_N_INSNS (2);
1059 /* If the address is legitimate, return the number of
1060 instructions it needs, otherwise use the default handling. */
1061 int n = score7_address_insns (XEXP (x, 0), GET_MODE (x));
1064 *total = COSTS_N_INSNS (n + 1);
1071 *total = COSTS_N_INSNS (6);
1075 *total = COSTS_N_INSNS (1);
1083 *total = COSTS_N_INSNS (2);
1093 *total = COSTS_N_INSNS ((GET_CODE (XEXP (x, 1)) == CONST_INT)
1100 *total = COSTS_N_INSNS (4);
1107 *total = COSTS_N_INSNS (4);
1110 *total = COSTS_N_INSNS (1);
1116 *total = COSTS_N_INSNS (4);
1122 *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (12);
1129 *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (33);
1134 switch (GET_MODE (XEXP (x, 0)))
1138 if (GET_CODE (XEXP (x, 0)) == MEM)
1140 *total = COSTS_N_INSNS (2);
1142 if (!TARGET_LITTLE_ENDIAN &&
1143 side_effects_p (XEXP (XEXP (x, 0), 0)))
1147 *total = COSTS_N_INSNS (1);
1151 *total = COSTS_N_INSNS (1);
1161 /* Implement TARGET_ADDRESS_COST macro. */
1163 score7_address_cost (rtx addr)
1165 return score7_address_insns (addr, SImode);
1168 /* Implement ASM_OUTPUT_EXTERNAL macro. */
1170 score7_output_external (FILE *file ATTRIBUTE_UNUSED,
1171 tree decl, const char *name)
1173 register struct extern_list *p;
1175 if (score7_in_small_data_p (decl))
1177 p = (struct extern_list *) ggc_alloc (sizeof (struct extern_list));
1178 p->next = extern_head;
1180 p->size = int_size_in_bytes (TREE_TYPE (decl));
1186 /* Implement RETURN_ADDR_RTX. Note, we do not support moving
1187 back to a previous frame. */
1189 score7_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
1193 return get_hard_reg_initial_val (Pmode, RA_REGNUM);
1196 /* Implement PRINT_OPERAND macro. */
1197 /* Score-specific operand codes:
1198 '[' print .set nor1 directive
1199 ']' print .set r1 directive
1200 'U' print hi part of a CONST_INT rtx
1203 'D' print SFmode const double
1204 'S' selectively print "!" if operand is 15bit instruction accessible
1205 'V' print "v!" if operand is 15bit instruction accessible, or "lfh!"
1206 'L' low part of DImode reg operand
1207 'H' high part of DImode reg operand
1208 'C' print part of opcode for a branch condition. */
1210 score7_print_operand (FILE *file, rtx op, int c)
1212 enum rtx_code code = -1;
1213 if (!PRINT_OPERAND_PUNCT_VALID_P (c))
1214 code = GET_CODE (op);
1218 fprintf (file, ".set r1\n");
1222 fprintf (file, "\n\t.set nor1");
1226 gcc_assert (code == CONST_INT);
1227 fprintf (file, HOST_WIDE_INT_PRINT_HEX,
1228 (INTVAL (op) >> 16) & 0xffff);
1232 if (GET_CODE (op) == CONST_DOUBLE)
1234 rtx temp = gen_lowpart (SImode, op);
1235 gcc_assert (GET_MODE (op) == SFmode);
1236 fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (temp) & 0xffffffff);
1239 output_addr_const (file, op);
1243 gcc_assert (code == REG);
1244 if (G16_REG_P (REGNO (op)))
1245 fprintf (file, "!");
1249 gcc_assert (code == REG);
1250 fprintf (file, G16_REG_P (REGNO (op)) ? "v!" : "lfh!");
1254 enum machine_mode mode = GET_MODE (XEXP (op, 0));
1258 case EQ: fputs ("eq", file); break;
1259 case NE: fputs ("ne", file); break;
1260 case GT: fputs ("gt", file); break;
1261 case GE: fputs (mode != CCmode ? "pl" : "ge", file); break;
1262 case LT: fputs (mode != CCmode ? "mi" : "lt", file); break;
1263 case LE: fputs ("le", file); break;
1264 case GTU: fputs ("gtu", file); break;
1265 case GEU: fputs ("cs", file); break;
1266 case LTU: fputs ("cc", file); break;
1267 case LEU: fputs ("leu", file); break;
1269 output_operand_lossage ("invalid operand for code: '%c'", code);
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);
1290 unsigned HOST_WIDE_INT i;
1291 unsigned HOST_WIDE_INT pow2mask = 1;
1292 unsigned HOST_WIDE_INT val;
1295 for (i = 0; i < 32; i++)
1297 if (val == pow2mask)
1301 gcc_assert (i < 32);
1302 fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
1304 else if (code == REG)
1306 int regnum = REGNO (op);
1307 if ((c == 'H' && !WORDS_BIG_ENDIAN)
1308 || (c == 'L' && WORDS_BIG_ENDIAN))
1310 fprintf (file, "%s", reg_names[regnum]);
1317 score7_print_operand_address (file, op);
1320 output_addr_const (file, op);
1325 /* Implement PRINT_OPERAND_ADDRESS macro. */
1327 score7_print_operand_address (FILE *file, rtx x)
1329 struct score7_address_info addr;
1330 enum rtx_code code = GET_CODE (x);
1331 enum machine_mode mode = GET_MODE (x);
1336 if (score7_classify_address (&addr, mode, x, true))
1340 case SCORE7_ADD_REG:
1345 fprintf (file, "[%s,-%ld]+", reg_names[REGNO (addr.reg)],
1346 INTVAL (addr.offset));
1349 fprintf (file, "[%s]+,-%ld", reg_names[REGNO (addr.reg)],
1350 INTVAL (addr.offset));
1353 fprintf (file, "[%s, %ld]+", reg_names[REGNO (addr.reg)],
1354 INTVAL (addr.offset));
1357 fprintf (file, "[%s]+, %ld", reg_names[REGNO (addr.reg)],
1358 INTVAL (addr.offset));
1361 if (INTVAL(addr.offset) == 0)
1362 fprintf(file, "[%s]", reg_names[REGNO (addr.reg)]);
1364 fprintf(file, "[%s, %ld]", reg_names[REGNO (addr.reg)],
1365 INTVAL(addr.offset));
1370 case SCORE7_ADD_CONST_INT:
1371 case SCORE7_ADD_SYMBOLIC:
1372 output_addr_const (file, x);
1376 print_rtl (stderr, x);
1380 /* Implement SELECT_CC_MODE macro. */
1382 score7_select_cc_mode (enum rtx_code op, rtx x, rtx y)
1384 if ((op == EQ || op == NE || op == LT || op == GE)
1386 && GET_MODE (x) == SImode)
1388 switch (GET_CODE (x))
1406 return (op == LT || op == GE) ? CC_Nmode : CCmode;
1413 if ((op == EQ || op == NE)
1414 && (GET_CODE (y) == NEG)
1415 && register_operand (XEXP (y, 0), SImode)
1416 && register_operand (x, SImode))
1424 /* Generate the prologue instructions for entry into a S+core function. */
1426 score7_prologue (void)
1428 #define EMIT_PL(_rtx) RTX_FRAME_RELATED_P (_rtx) = 1
1430 struct score7_frame_info *f = score7_compute_frame_size (get_frame_size ());
1434 size = f->total_size - f->gp_reg_size;
1437 emit_insn (gen_cpload_score7 ());
1439 for (regno = (int) GP_REG_LAST; regno >= (int) GP_REG_FIRST; regno--)
1441 if (BITSET_P (f->mask, regno - GP_REG_FIRST))
1443 rtx mem = gen_rtx_MEM (SImode,
1444 gen_rtx_PRE_DEC (SImode, stack_pointer_rtx));
1445 rtx reg = gen_rtx_REG (SImode, regno);
1446 if (!crtl->calls_eh_return)
1447 MEM_READONLY_P (mem) = 1;
1448 EMIT_PL (emit_insn (gen_pushsi_score7 (mem, reg)));
1456 if (CONST_OK_FOR_LETTER_P (-size, 'L'))
1457 EMIT_PL (emit_insn (gen_add3_insn (stack_pointer_rtx,
1462 EMIT_PL (emit_move_insn (gen_rtx_REG (Pmode, SCORE7_PROLOGUE_TEMP_REGNUM),
1465 (gen_sub3_insn (stack_pointer_rtx,
1468 SCORE7_PROLOGUE_TEMP_REGNUM))));
1470 insn = get_last_insn ();
1472 alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR,
1473 gen_rtx_SET (VOIDmode, stack_pointer_rtx,
1474 plus_constant (stack_pointer_rtx,
1479 if (frame_pointer_needed)
1480 EMIT_PL (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx));
1482 if (flag_pic && f->cprestore_size)
1484 if (frame_pointer_needed)
1485 emit_insn (gen_cprestore_use_fp_score7 (GEN_INT (size - f->cprestore_size)));
1487 emit_insn (gen_cprestore_use_sp_score7 (GEN_INT (size - f->cprestore_size)));
1493 /* Generate the epilogue instructions in a S+core function. */
1495 score7_epilogue (int sibcall_p)
1497 struct score7_frame_info *f = score7_compute_frame_size (get_frame_size ());
1502 size = f->total_size - f->gp_reg_size;
1504 if (!frame_pointer_needed)
1505 base = stack_pointer_rtx;
1507 base = hard_frame_pointer_rtx;
1511 if (CONST_OK_FOR_LETTER_P (size, 'L'))
1512 emit_insn (gen_add3_insn (base, base, GEN_INT (size)));
1515 emit_move_insn (gen_rtx_REG (Pmode, SCORE7_EPILOGUE_TEMP_REGNUM),
1517 emit_insn (gen_add3_insn (base, base,
1519 SCORE7_EPILOGUE_TEMP_REGNUM)));
1523 if (base != stack_pointer_rtx)
1524 emit_move_insn (stack_pointer_rtx, base);
1526 if (crtl->calls_eh_return)
1527 emit_insn (gen_add3_insn (stack_pointer_rtx,
1529 EH_RETURN_STACKADJ_RTX));
1531 for (regno = (int) GP_REG_FIRST; regno <= (int) GP_REG_LAST; regno++)
1533 if (BITSET_P (f->mask, regno - GP_REG_FIRST))
1535 rtx mem = gen_rtx_MEM (SImode,
1536 gen_rtx_POST_INC (SImode, stack_pointer_rtx));
1537 rtx reg = gen_rtx_REG (SImode, regno);
1539 if (!crtl->calls_eh_return)
1540 MEM_READONLY_P (mem) = 1;
1542 emit_insn (gen_popsi_score7 (reg, mem));
1547 emit_jump_insn (gen_return_internal_score7 (gen_rtx_REG (Pmode, RA_REGNUM)));
1550 /* Return true if X is a symbolic constant that can be calculated in
1551 the same way as a bare symbol. If it is, store the type of the
1552 symbol in *SYMBOL_TYPE. */
1554 score7_symbolic_constant_p (rtx x, enum score_symbol_type *symbol_type)
1556 HOST_WIDE_INT offset;
1558 score7_split_const (x, &x, &offset);
1559 if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF)
1560 *symbol_type = score7_classify_symbol (x);
1567 /* if offset > 15bit, must reload */
1568 if (!IMM_IN_RANGE (offset, 15, 1))
1571 switch (*symbol_type)
1573 case SYMBOL_GENERAL:
1575 case SYMBOL_SMALL_DATA:
1576 return score7_offset_within_object_p (x, offset);
1582 score7_movsicc (rtx *ops)
1584 enum machine_mode mode;
1586 mode = score7_select_cc_mode (GET_CODE (ops[1]), ops[2], ops[3]);
1587 emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (mode, CC_REGNUM),
1588 gen_rtx_COMPARE (mode, XEXP (ops[1], 0),
1589 XEXP (ops[1], 1))));
1592 /* Call and sibcall pattern all need call this function. */
1594 score7_call (rtx *ops, bool sib)
1596 rtx addr = XEXP (ops[0], 0);
1597 if (!call_insn_operand (addr, VOIDmode))
1600 addr = gen_reg_rtx (Pmode);
1601 gen_move_insn (addr, oaddr);
1605 emit_call_insn (gen_sibcall_internal_score7 (addr, ops[1]));
1607 emit_call_insn (gen_call_internal_score7 (addr, ops[1]));
1610 /* Call value and sibcall value pattern all need call this function. */
1612 score7_call_value (rtx *ops, bool sib)
1614 rtx result = ops[0];
1615 rtx addr = XEXP (ops[1], 0);
1618 if (!call_insn_operand (addr, VOIDmode))
1621 addr = gen_reg_rtx (Pmode);
1622 gen_move_insn (addr, oaddr);
1626 emit_call_insn (gen_sibcall_value_internal_score7 (result, addr, arg));
1628 emit_call_insn (gen_call_value_internal_score7 (result, addr, arg));
1633 score7_movdi (rtx *ops)
1637 rtx dst0 = score7_subw (dst, 0);
1638 rtx dst1 = score7_subw (dst, 1);
1639 rtx src0 = score7_subw (src, 0);
1640 rtx src1 = score7_subw (src, 1);
1642 if (GET_CODE (dst0) == REG && reg_overlap_mentioned_p (dst0, src))
1644 emit_move_insn (dst1, src1);
1645 emit_move_insn (dst0, src0);
1649 emit_move_insn (dst0, src0);
1650 emit_move_insn (dst1, src1);
1655 score7_zero_extract_andi (rtx *ops)
1657 if (INTVAL (ops[1]) == 1 && const_uimm5 (ops[2], SImode))
1658 emit_insn (gen_zero_extract_bittst_score7 (ops[0], ops[2]));
1661 unsigned HOST_WIDE_INT mask;
1662 mask = (0xffffffffU & ((1U << INTVAL (ops[1])) - 1U));
1663 mask = mask << INTVAL (ops[2]);
1664 emit_insn (gen_andsi3_cmp_score7 (ops[3], ops[0],
1665 gen_int_mode (mask, SImode)));
1669 /* Check addr could be present as PRE/POST mode. */
1671 score7_pindex_mem (rtx addr)
1673 if (GET_CODE (addr) == MEM)
1675 switch (GET_CODE (XEXP (addr, 0)))
1689 /* Output asm code for ld/sw insn. */
1691 score7_pr_addr_post (rtx *ops, int idata, int iaddr, char *ip, enum score_mem_unit unit)
1693 struct score7_address_info ai;
1695 gcc_assert (GET_CODE (ops[idata]) == REG);
1696 gcc_assert (score7_classify_address (&ai, SImode, XEXP (ops[iaddr], 0), true));
1698 if (!score7_pindex_mem (ops[iaddr])
1699 && ai.type == SCORE7_ADD_REG
1700 && GET_CODE (ai.offset) == CONST_INT
1701 && G16_REG_P (REGNO (ops[idata]))
1702 && G16_REG_P (REGNO (ai.reg)))
1704 if (INTVAL (ai.offset) == 0)
1706 ops[iaddr] = ai.reg;
1707 return snprintf (ip, INS_BUF_SZ,
1708 "!\t%%%d, [%%%d]", idata, iaddr);
1710 if (REGNO (ai.reg) == HARD_FRAME_POINTER_REGNUM)
1712 HOST_WIDE_INT offset = INTVAL (ai.offset);
1713 if (SCORE_ALIGN_UNIT (offset, unit)
1714 && CONST_OK_FOR_LETTER_P (offset >> unit, 'J'))
1716 ops[iaddr] = ai.offset;
1717 return snprintf (ip, INS_BUF_SZ,
1718 "p!\t%%%d, %%c%d", idata, iaddr);
1722 return snprintf (ip, INS_BUF_SZ, "\t%%%d, %%a%d", idata, iaddr);
1725 /* Output asm insn for load. */
1727 score7_linsn (rtx *ops, enum score_mem_unit unit, bool sign)
1729 const char *pre_ins[] =
1730 {"lbu", "lhu", "lw", "??", "lb", "lh", "lw", "??"};
1733 strcpy (score7_ins, pre_ins[(sign ? 4 : 0) + unit]);
1734 ip = score7_ins + strlen (score7_ins);
1736 if ((!sign && unit != SCORE_HWORD)
1737 || (sign && unit != SCORE_BYTE))
1738 score7_pr_addr_post (ops, 0, 1, ip, unit);
1740 snprintf (ip, INS_BUF_SZ, "\t%%0, %%a1");
1745 /* Output asm insn for store. */
1747 score7_sinsn (rtx *ops, enum score_mem_unit unit)
1749 const char *pre_ins[] = {"sb", "sh", "sw"};
1752 strcpy (score7_ins, pre_ins[unit]);
1753 ip = score7_ins + strlen (score7_ins);
1754 score7_pr_addr_post (ops, 1, 0, ip, unit);
1758 /* Output asm insn for load immediate. */
1760 score7_limm (rtx *ops)
1764 gcc_assert (GET_CODE (ops[0]) == REG);
1765 gcc_assert (GET_CODE (ops[1]) == CONST_INT);
1767 v = INTVAL (ops[1]);
1768 if (G16_REG_P (REGNO (ops[0])) && IMM_IN_RANGE (v, 8, 0))
1769 return "ldiu!\t%0, %c1";
1770 else if (IMM_IN_RANGE (v, 16, 1))
1771 return "ldi\t%0, %c1";
1772 else if ((v & 0xffff) == 0)
1773 return "ldis\t%0, %U1";
1775 return "li\t%0, %c1";
1778 /* Output asm insn for move. */
1780 score7_move (rtx *ops)
1782 gcc_assert (GET_CODE (ops[0]) == REG);
1783 gcc_assert (GET_CODE (ops[1]) == REG);
1785 if (G16_REG_P (REGNO (ops[0])))
1787 if (G16_REG_P (REGNO (ops[1])))
1788 return "mv!\t%0, %1";
1790 return "mlfh!\t%0, %1";
1792 else if (G16_REG_P (REGNO (ops[1])))
1793 return "mhfl!\t%0, %1";
1795 return "mv\t%0, %1";
1798 /* Generate add insn. */
1800 score7_select_add_imm (rtx *ops, bool set_cc)
1802 HOST_WIDE_INT v = INTVAL (ops[2]);
1804 gcc_assert (GET_CODE (ops[2]) == CONST_INT);
1805 gcc_assert (REGNO (ops[0]) == REGNO (ops[1]));
1807 if (set_cc && G16_REG_P (REGNO (ops[0])))
1809 if (v > 0 && IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT) v, 0, 15))
1811 ops[2] = GEN_INT (ffs (v) - 1);
1812 return "addei!\t%0, %c2";
1815 if (v < 0 && IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT) (-v), 0, 15))
1817 ops[2] = GEN_INT (ffs (-v) - 1);
1818 return "subei!\t%0, %c2";
1823 return "addi.c\t%0, %c2";
1825 return "addi\t%0, %c2";
1828 /* Output arith insn. */
1830 score7_select (rtx *ops, const char *inst_pre,
1831 bool commu, const char *letter, bool set_cc)
1833 gcc_assert (GET_CODE (ops[0]) == REG);
1834 gcc_assert (GET_CODE (ops[1]) == REG);
1836 if (set_cc && G16_REG_P (REGNO (ops[0]))
1837 && (GET_CODE (ops[2]) == REG ? G16_REG_P (REGNO (ops[2])) : 1)
1838 && REGNO (ops[0]) == REGNO (ops[1]))
1840 snprintf (score7_ins, INS_BUF_SZ, "%s!\t%%0, %%%s2", inst_pre, letter);
1844 if (commu && set_cc && G16_REG_P (REGNO (ops[0]))
1845 && G16_REG_P (REGNO (ops[1]))
1846 && REGNO (ops[0]) == REGNO (ops[2]))
1848 gcc_assert (GET_CODE (ops[2]) == REG);
1849 snprintf (score7_ins, INS_BUF_SZ, "%s!\t%%0, %%%s1", inst_pre, letter);
1854 snprintf (score7_ins, INS_BUF_SZ, "%s.c\t%%0, %%1, %%%s2", inst_pre, letter);
1856 snprintf (score7_ins, INS_BUF_SZ, "%s\t%%0, %%1, %%%s2", inst_pre, letter);