1 /* score3.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 extern enum reg_class score_char_to_class[256];
59 static int score3_sdata_max;
60 static char score3_ins[INS_BUF_SZ + 8];
62 /* Return true if SYMBOL is a SYMBOL_REF and OFFSET + SYMBOL points
63 to the same object as SYMBOL. */
65 score3_offset_within_object_p (rtx symbol, HOST_WIDE_INT offset)
67 if (GET_CODE (symbol) != SYMBOL_REF)
70 if (CONSTANT_POOL_ADDRESS_P (symbol)
72 && offset < (int)GET_MODE_SIZE (get_pool_mode (symbol)))
75 if (SYMBOL_REF_DECL (symbol) != 0
77 && offset < int_size_in_bytes (TREE_TYPE (SYMBOL_REF_DECL (symbol))))
83 /* Split X into a base and a constant offset, storing them in *BASE
84 and *OFFSET respectively. */
86 score3_split_const (rtx x, rtx *base, HOST_WIDE_INT *offset)
90 if (GET_CODE (x) == CONST)
93 if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
95 *offset += INTVAL (XEXP (x, 1));
102 /* Classify symbol X, which must be a SYMBOL_REF or a LABEL_REF. */
103 static enum score_symbol_type
104 score3_classify_symbol (rtx x)
106 if (GET_CODE (x) == LABEL_REF)
107 return SYMBOL_GENERAL;
109 gcc_assert (GET_CODE (x) == SYMBOL_REF);
111 if (CONSTANT_POOL_ADDRESS_P (x))
113 if (GET_MODE_SIZE (get_pool_mode (x)) <= SCORE3_SDATA_MAX)
114 return SYMBOL_SMALL_DATA;
115 return SYMBOL_GENERAL;
117 if (SYMBOL_REF_SMALL_P (x))
118 return SYMBOL_SMALL_DATA;
119 return SYMBOL_GENERAL;
122 /* Return true if the current function must save REGNO. */
124 score3_save_reg_p (unsigned int regno)
126 /* Check call-saved registers. */
127 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
130 /* We need to save the old frame pointer before setting up a new one. */
131 if (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed)
134 /* We need to save the incoming return address if it is ever clobbered
135 within the function. */
136 if (regno == RA_REGNUM && df_regs_ever_live_p (regno))
142 /* Return one word of double-word value OP, taking into account the fixed
143 endianness of certain registers. HIGH_P is true to select the high part,
144 false to select the low part. */
146 score3_subw (rtx op, int high_p)
149 enum machine_mode mode = GET_MODE (op);
151 if (mode == VOIDmode)
154 byte = (TARGET_LITTLE_ENDIAN ? high_p : !high_p) ? UNITS_PER_WORD : 0;
156 if (GET_CODE (op) == REG && REGNO (op) == HI_REGNUM)
157 return gen_rtx_REG (SImode, high_p ? HI_REGNUM : LO_REGNUM);
159 if (GET_CODE (op) == MEM)
160 return adjust_address (op, SImode, byte);
162 return simplify_gen_subreg (SImode, op, mode, byte);
165 static struct score3_frame_info *
166 score3_cached_frame (void)
168 static struct score3_frame_info _frame_info;
172 /* Return the bytes needed to compute the frame pointer from the current
173 stack pointer. SIZE is the size (in bytes) of the local variables. */
174 static struct score3_frame_info *
175 score3_compute_frame_size (HOST_WIDE_INT size)
178 struct score3_frame_info *f = score3_cached_frame ();
180 memset (f, 0, sizeof (struct score3_frame_info));
183 f->var_size = SCORE3_STACK_ALIGN (size);
184 f->args_size = crtl->outgoing_args_size;
185 f->cprestore_size = flag_pic ? UNITS_PER_WORD : 0;
187 if (f->var_size == 0 && current_function_is_leaf)
188 f->args_size = f->cprestore_size = 0;
190 if (f->args_size == 0 && cfun->calls_alloca)
191 f->args_size = UNITS_PER_WORD;
193 f->total_size = f->var_size + f->args_size + f->cprestore_size;
194 for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
196 if (score3_save_reg_p (regno))
198 f->gp_reg_size += GET_MODE_SIZE (SImode);
199 f->mask |= 1 << (regno - GP_REG_FIRST);
203 if (crtl->calls_eh_return)
208 regno = EH_RETURN_DATA_REGNO (i);
209 if (regno == INVALID_REGNUM)
211 f->gp_reg_size += GET_MODE_SIZE (SImode);
212 f->mask |= 1 << (regno - GP_REG_FIRST);
216 f->total_size += f->gp_reg_size;
217 f->num_gp = f->gp_reg_size / UNITS_PER_WORD;
221 HOST_WIDE_INT offset;
222 offset = (f->args_size + f->cprestore_size + f->var_size
223 + f->gp_reg_size - GET_MODE_SIZE (SImode));
224 f->gp_sp_offset = offset;
232 /* Return true if X is a valid base register for the given mode.
233 Allow only hard registers if STRICT. */
235 score3_valid_base_register_p (rtx x, int strict)
237 if (!strict && GET_CODE (x) == SUBREG)
240 return (GET_CODE (x) == REG
241 && score3_regno_mode_ok_for_base_p (REGNO (x), strict));
244 /* Return true if X is a valid address for machine mode MODE. If it is,
245 fill in INFO appropriately. STRICT is true if we should only accept
246 hard base registers. */
248 score3_classify_address (struct score3_address_info *info,
249 enum machine_mode mode, rtx x, int strict)
251 info->code = GET_CODE (x);
257 info->type = SCORE3_ADD_REG;
259 info->offset = const0_rtx;
260 return score3_valid_base_register_p (info->reg, strict);
262 info->type = SCORE3_ADD_REG;
263 info->reg = XEXP (x, 0);
264 info->offset = XEXP (x, 1);
265 return (score3_valid_base_register_p (info->reg, strict)
266 && GET_CODE (info->offset) == CONST_INT
267 && IMM_IN_RANGE (INTVAL (info->offset), 15, 1));
272 if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (SImode))
274 info->type = SCORE3_ADD_REG;
275 info->reg = XEXP (x, 0);
276 info->offset = GEN_INT (GET_MODE_SIZE (mode));
277 return score3_valid_base_register_p (info->reg, strict);
279 info->type = SCORE3_ADD_CONST_INT;
284 info->type = SCORE3_ADD_SYMBOLIC;
285 return (score3_symbolic_constant_p (x, &info->symbol_type)
286 && (info->symbol_type == SYMBOL_GENERAL
287 || info->symbol_type == SYMBOL_SMALL_DATA));
294 score3_return_in_memory (tree type, tree fndecl ATTRIBUTE_UNUSED)
296 return ((TYPE_MODE (type) == BLKmode)
297 || (int_size_in_bytes (type) > 2 * UNITS_PER_WORD)
298 || (int_size_in_bytes (type) == -1));
301 /* Return a legitimate address for REG + OFFSET. */
303 score3_add_offset (rtx reg, HOST_WIDE_INT offset)
305 if (!IMM_IN_RANGE (offset, 15, 1))
307 reg = expand_simple_binop (GET_MODE (reg), PLUS,
308 gen_int_mode (offset & 0xffffc000,
310 reg, NULL, 0, OPTAB_WIDEN);
314 return plus_constant (reg, offset);
317 /* Implement TARGET_ASM_OUTPUT_MI_THUNK. Generate rtl rather than asm text
318 in order to avoid duplicating too much logic from elsewhere. */
320 score3_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
321 HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
324 rtx this_rtx, temp1, insn, fnaddr;
326 /* Pretend to be a post-reload pass while generating rtl. */
327 reload_completed = 1;
329 /* Mark the end of the (empty) prologue. */
330 emit_note (NOTE_INSN_PROLOGUE_END);
332 /* We need two temporary registers in some cases. */
333 temp1 = gen_rtx_REG (Pmode, 8);
335 /* Find out which register contains the "this" pointer. */
336 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
337 this_rtx = gen_rtx_REG (Pmode, ARG_REG_FIRST + 1);
339 this_rtx = gen_rtx_REG (Pmode, ARG_REG_FIRST);
341 /* Add DELTA to THIS_RTX. */
344 rtx offset = GEN_INT (delta);
345 if (!CONST_OK_FOR_LETTER_P (delta, 'L'))
347 emit_move_insn (temp1, offset);
350 emit_insn (gen_add3_insn (this_rtx, this_rtx, offset));
353 /* If needed, add *(*THIS_RTX + VCALL_OFFSET) to THIS_RTX. */
354 if (vcall_offset != 0)
358 /* Set TEMP1 to *THIS_RTX. */
359 emit_move_insn (temp1, gen_rtx_MEM (Pmode, this_rtx));
361 /* Set ADDR to a legitimate address for *THIS_RTX + VCALL_OFFSET. */
362 addr = score3_add_offset (temp1, vcall_offset);
364 /* Load the offset and add it to THIS_RTX. */
365 emit_move_insn (temp1, gen_rtx_MEM (Pmode, addr));
366 emit_insn (gen_add3_insn (this_rtx, this_rtx, temp1));
369 /* Jump to the target function. */
370 fnaddr = XEXP (DECL_RTL (function), 0);
371 insn = emit_call_insn (gen_sibcall_internal_score3 (fnaddr, const0_rtx));
372 SIBLING_CALL_P (insn) = 1;
374 /* Run just enough of rest_of_compilation. This sequence was
375 "borrowed" from alpha.c. */
377 insn_locators_alloc ();
378 split_all_insns_noflow ();
379 shorten_branches (insn);
380 final_start_function (insn, file, 1);
381 final (insn, file, 1);
382 final_end_function ();
383 free_after_compilation (cfun);
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 score3_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 score3_split_symbol (rtx temp, rtx addr)
409 rtx high = score3_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 X can
415 be legitimized in a way that the generic machinery might not expect,
416 return the new address. */
418 score3_legitimize_address (rtx x)
420 enum score_symbol_type symbol_type;
422 if (score3_symbolic_constant_p (x, &symbol_type)
423 && symbol_type == SYMBOL_GENERAL)
424 return score3_split_symbol (0, x);
426 if (GET_CODE (x) == PLUS
427 && GET_CODE (XEXP (x, 1)) == CONST_INT)
429 rtx reg = XEXP (x, 0);
430 if (!score3_valid_base_register_p (reg, 0))
431 reg = copy_to_mode_reg (Pmode, reg);
432 return score3_add_offset (reg, INTVAL (XEXP (x, 1)));
438 /* Fill INFO with information about a single argument. CUM is the
439 cumulative state for earlier arguments. MODE is the mode of this
440 argument and TYPE is its type (if known). NAMED is true if this
441 is a named (fixed) argument rather than a variable one. */
443 score3_classify_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
444 tree type, int named, struct score3_arg_info *info)
447 unsigned int num_words, max_regs;
450 if (GET_MODE_CLASS (mode) == MODE_INT
451 || GET_MODE_CLASS (mode) == MODE_FLOAT)
452 even_reg_p = (GET_MODE_SIZE (mode) > UNITS_PER_WORD);
454 if (type != NULL_TREE && TYPE_ALIGN (type) > BITS_PER_WORD && named)
457 if (TARGET_MUST_PASS_IN_STACK (mode, type))
458 info->reg_offset = ARG_REG_NUM;
461 info->reg_offset = cum->num_gprs;
463 info->reg_offset += info->reg_offset & 1;
467 info->num_bytes = int_size_in_bytes (type);
469 info->num_bytes = GET_MODE_SIZE (mode);
471 num_words = (info->num_bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
472 max_regs = ARG_REG_NUM - info->reg_offset;
474 /* Partition the argument between registers and stack. */
475 info->reg_words = MIN (num_words, max_regs);
476 info->stack_words = num_words - info->reg_words;
478 /* The alignment applied to registers is also applied to stack arguments. */
479 if (info->stack_words)
481 info->stack_offset = cum->stack_words;
483 info->stack_offset += info->stack_offset & 1;
487 /* Set up the stack and frame (if desired) for the function. */
489 score3_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
492 struct score3_frame_info *f = score3_cached_frame ();
493 HOST_WIDE_INT tsize = f->total_size;
495 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
496 if (!flag_inhibit_size_directive)
498 fputs ("\t.ent\t", file);
499 assemble_name (file, fnname);
502 assemble_name (file, fnname);
505 if (!flag_inhibit_size_directive)
508 "\t.frame\t%s," HOST_WIDE_INT_PRINT_DEC ",%s, %d\t\t"
509 "# vars= " HOST_WIDE_INT_PRINT_DEC ", regs= %d"
510 ", args= " HOST_WIDE_INT_PRINT_DEC
511 ", gp= " HOST_WIDE_INT_PRINT_DEC "\n",
512 (reg_names[(frame_pointer_needed)
513 ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM]),
515 reg_names[RA_REGNUM],
516 current_function_is_leaf ? 1 : 0,
522 fprintf(file, "\t.mask\t0x%08x," HOST_WIDE_INT_PRINT_DEC "\n",
524 (f->gp_sp_offset - f->total_size));
528 /* Do any necessary cleanup after a function to restore stack, frame,
531 score3_function_epilogue (FILE *file,
532 HOST_WIDE_INT size ATTRIBUTE_UNUSED)
534 if (!flag_inhibit_size_directive)
537 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
538 fputs ("\t.end\t", file);
539 assemble_name (file, fnname);
544 /* Returns true if X contains a SYMBOL_REF. */
546 score3_symbolic_expression_p (rtx x)
548 if (GET_CODE (x) == SYMBOL_REF)
551 if (GET_CODE (x) == CONST)
552 return score3_symbolic_expression_p (XEXP (x, 0));
555 return score3_symbolic_expression_p (XEXP (x, 0));
557 if (ARITHMETIC_P (x))
558 return (score3_symbolic_expression_p (XEXP (x, 0))
559 || score3_symbolic_expression_p (XEXP (x, 1)));
564 /* Choose the section to use for the constant rtx expression X that has
567 score3_select_rtx_section (enum machine_mode mode, rtx x,
568 unsigned HOST_WIDE_INT align)
570 if (GET_MODE_SIZE (mode) <= SCORE3_SDATA_MAX)
571 return get_named_section (0, ".sdata", 0);
572 else if (flag_pic && score3_symbolic_expression_p (x))
573 return get_named_section (0, ".data.rel.ro", 3);
575 return mergeable_constant_section (mode, align, 0);
578 /* Implement TARGET_IN_SMALL_DATA_P. */
580 score3_in_small_data_p (tree decl)
584 if (TREE_CODE (decl) == STRING_CST
585 || TREE_CODE (decl) == FUNCTION_DECL)
588 if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl) != 0)
591 name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
592 if (strcmp (name, ".sdata") != 0
593 && strcmp (name, ".sbss") != 0)
595 if (!DECL_EXTERNAL (decl))
598 size = int_size_in_bytes (TREE_TYPE (decl));
599 return (size > 0 && size <= SCORE3_SDATA_MAX);
602 /* Implement TARGET_ASM_FILE_START. */
604 score3_asm_file_start (void)
606 default_file_start ();
607 fprintf (asm_out_file, ASM_COMMENT_START
608 "GCC for S+core %s \n", SCORE_GCC_VERSION);
611 fprintf (asm_out_file, "\t.set pic\n");
614 /* Implement TARGET_ASM_FILE_END. When using assembler macros, emit
615 .externs for any small-data variables that turned out to be external. */
617 score3_asm_file_end (void)
620 struct extern_list *p;
623 fputs ("\n", asm_out_file);
624 for (p = extern_head; p != 0; p = p->next)
626 name_tree = get_identifier (p->name);
627 if (!TREE_ASM_WRITTEN (name_tree)
628 && TREE_SYMBOL_REFERENCED (name_tree))
630 TREE_ASM_WRITTEN (name_tree) = 1;
631 fputs ("\t.extern\t", asm_out_file);
632 assemble_name (asm_out_file, p->name);
633 fprintf (asm_out_file, ", %d\n", p->size);
639 /* Implement OVERRIDE_OPTIONS macro. */
641 score3_override_options (void)
645 score3_sdata_max = g_switch_set ? g_switch_value : SCORE3_DEFAULT_SDATA_MAX;
648 score3_sdata_max = 0;
649 if (g_switch_set && (g_switch_value != 0))
650 warning (0, "-fPIC and -G are incompatible");
653 score_char_to_class['d'] = G32_REGS;
654 score_char_to_class['e'] = G16_REGS;
655 score_char_to_class['t'] = T32_REGS;
657 score_char_to_class['h'] = HI_REG;
658 score_char_to_class['l'] = LO_REG;
659 score_char_to_class['x'] = CE_REGS;
661 score_char_to_class['q'] = CN_REG;
662 score_char_to_class['y'] = LC_REG;
663 score_char_to_class['z'] = SC_REG;
664 score_char_to_class['a'] = SP_REGS;
666 score_char_to_class['c'] = CR_REGS;
669 /* Implement REGNO_REG_CLASS macro. */
671 score3_reg_class (int regno)
674 gcc_assert (regno >= 0 && regno < FIRST_PSEUDO_REGISTER);
676 if (regno == FRAME_POINTER_REGNUM
677 || regno == ARG_POINTER_REGNUM)
680 for (c = 0; c < N_REG_CLASSES; c++)
681 if (TEST_HARD_REG_BIT (reg_class_contents[c], regno))
687 /* Implement PREFERRED_RELOAD_CLASS macro. */
689 score3_preferred_reload_class (rtx x ATTRIBUTE_UNUSED, enum reg_class rclass)
691 if (reg_class_subset_p (G16_REGS, rclass))
693 if (reg_class_subset_p (G32_REGS, rclass))
698 /* Implement SECONDARY_INPUT_RELOAD_CLASS
699 and SECONDARY_OUTPUT_RELOAD_CLASS macro. */
701 score3_secondary_reload_class (enum reg_class rclass,
702 enum machine_mode mode ATTRIBUTE_UNUSED,
706 if (GET_CODE (x) == REG || GET_CODE(x) == SUBREG)
707 regno = true_regnum (x);
709 if (!GR_REG_CLASS_P (rclass))
710 return GP_REG_P (regno) ? NO_REGS : G32_REGS;
714 /* Implement CONST_OK_FOR_LETTER_P macro. */
726 score3_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);
736 case 'O': return IMM_IN_RANGE (value, 5, 1);
737 case 'P': return IMM_IN_RANGE (value, 6, 1);
738 case 'Q': return score_extra_constraint (GEN_INT(value), c);
743 /* Implement EXTRA_CONSTRAINT macro. */
748 score3_extra_constraint (rtx op, char c)
752 case 'Q': return IMM_IN_RANGE (INTVAL(op), 32, 0);
754 return GET_CODE (op) == SYMBOL_REF;
760 /* Return truth value on whether or not a given hard register
761 can support a given mode. */
763 score3_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
765 int size = GET_MODE_SIZE (mode);
766 enum mode_class mclass = GET_MODE_CLASS (mode);
768 if (mclass == MODE_CC)
769 return regno == CC_REGNUM;
770 else if (regno == FRAME_POINTER_REGNUM
771 || regno == ARG_POINTER_REGNUM)
772 return mclass == MODE_INT;
773 else if (GP_REG_P (regno))
774 return !(regno & 1) || (size <= UNITS_PER_WORD);
775 else if (CE_REG_P (regno))
776 return (mclass == MODE_INT
777 && ((size <= UNITS_PER_WORD)
778 || (regno == CE_REG_FIRST && size == 2 * UNITS_PER_WORD)));
780 return (mclass == MODE_INT) && (size <= UNITS_PER_WORD);
783 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
784 pointer or argument pointer. TO is either the stack pointer or
785 hard frame pointer. */
787 score3_initial_elimination_offset (int from,
788 int to ATTRIBUTE_UNUSED)
790 struct score3_frame_info *f = score3_compute_frame_size (get_frame_size ());
793 case ARG_POINTER_REGNUM:
794 return f->total_size;
795 case FRAME_POINTER_REGNUM:
802 /* Implement FUNCTION_ARG_ADVANCE macro. */
804 score3_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
805 tree type, int named)
807 struct score3_arg_info info;
808 score3_classify_arg (cum, mode, type, named, &info);
809 cum->num_gprs = info.reg_offset + info.reg_words;
810 if (info.stack_words > 0)
811 cum->stack_words = info.stack_offset + info.stack_words;
815 /* Implement TARGET_ARG_PARTIAL_BYTES macro. */
817 score3_arg_partial_bytes (CUMULATIVE_ARGS *cum,
818 enum machine_mode mode, tree type, bool named)
820 struct score3_arg_info info;
821 score3_classify_arg (cum, mode, type, named, &info);
822 return info.stack_words > 0 ? info.reg_words * UNITS_PER_WORD : 0;
825 /* Implement FUNCTION_ARG macro. */
827 score3_function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
828 tree type, int named)
830 struct score3_arg_info info;
832 if (mode == VOIDmode || !named)
835 score3_classify_arg (cum, mode, type, named, &info);
837 if (info.reg_offset == ARG_REG_NUM)
840 if (!info.stack_words)
841 return gen_rtx_REG (mode, ARG_REG_FIRST + info.reg_offset);
844 rtx ret = gen_rtx_PARALLEL (mode, rtvec_alloc (info.reg_words));
845 unsigned int i, part_offset = 0;
846 for (i = 0; i < info.reg_words; i++)
849 reg = gen_rtx_REG (SImode, ARG_REG_FIRST + info.reg_offset + i);
850 XVECEXP (ret, 0, i) = gen_rtx_EXPR_LIST (SImode, reg,
851 GEN_INT (part_offset));
852 part_offset += UNITS_PER_WORD;
858 /* Implement FUNCTION_VALUE and LIBCALL_VALUE. For normal calls,
859 VALTYPE is the return type and MODE is VOIDmode. For libcalls,
860 VALTYPE is null and MODE is the mode of the return value. */
862 score3_function_value (tree valtype, tree func ATTRIBUTE_UNUSED,
863 enum machine_mode mode)
868 mode = TYPE_MODE (valtype);
869 unsignedp = TYPE_UNSIGNED (valtype);
870 mode = promote_mode (valtype, mode, &unsignedp, 1);
872 return gen_rtx_REG (mode, RT_REGNUM);
875 /* Implement INITIALIZE_TRAMPOLINE macro. */
877 score3_initialize_trampoline (rtx ADDR, rtx FUNC, rtx CHAIN)
879 #define FFCACHE "_flush_cache"
880 #define CODE_SIZE (TRAMPOLINE_INSNS * UNITS_PER_WORD)
884 pfunc = plus_constant (ADDR, CODE_SIZE);
885 pchain = plus_constant (ADDR, CODE_SIZE + GET_MODE_SIZE (SImode));
887 emit_move_insn (gen_rtx_MEM (SImode, pfunc), FUNC);
888 emit_move_insn (gen_rtx_MEM (SImode, pchain), CHAIN);
889 emit_library_call (gen_rtx_SYMBOL_REF (Pmode, FFCACHE),
892 GEN_INT (TRAMPOLINE_SIZE), SImode);
897 /* This function is used to implement REG_MODE_OK_FOR_BASE_P macro. */
899 score3_regno_mode_ok_for_base_p (int regno, int strict)
901 if (regno >= FIRST_PSEUDO_REGISTER)
905 regno = reg_renumber[regno];
907 if (regno == ARG_POINTER_REGNUM
908 || regno == FRAME_POINTER_REGNUM)
910 return GP_REG_P (regno);
913 /* Implement GO_IF_LEGITIMATE_ADDRESS macro. */
915 score3_address_p (enum machine_mode mode, rtx x, int strict)
917 struct score3_address_info addr;
919 return score3_classify_address (&addr, mode, x, strict);
922 /* Return a number assessing the cost of moving a register in class
925 score3_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
926 enum reg_class from, enum reg_class to)
928 if (GR_REG_CLASS_P (from))
930 if (GR_REG_CLASS_P (to))
932 else if (SP_REG_CLASS_P (to))
934 else if (CP_REG_CLASS_P (to))
936 else if (CE_REG_CLASS_P (to))
939 if (GR_REG_CLASS_P (to))
941 if (GR_REG_CLASS_P (from))
943 else if (SP_REG_CLASS_P (from))
945 else if (CP_REG_CLASS_P (from))
947 else if (CE_REG_CLASS_P (from))
953 /* Return the number of instructions needed to load a symbol of the
954 given type into a register. */
956 score3_symbol_insns (enum score_symbol_type type)
963 case SYMBOL_SMALL_DATA:
970 /* Return the number of instructions needed to load or store a value
971 of mode MODE at X. Return 0 if X isn't valid for MODE. */
973 score3_address_insns (rtx x, enum machine_mode mode)
975 struct score3_address_info addr;
981 factor = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
983 if (score3_classify_address (&addr, mode, x, false))
987 case SCORE3_ADD_CONST_INT:
990 case SCORE3_ADD_SYMBOLIC:
991 return factor * score3_symbol_insns (addr.symbol_type);
996 /* Implement TARGET_RTX_COSTS macro. */
998 score3_rtx_costs (rtx x, int code, int outer_code, int *total,
999 bool speed ATTRIBUTE_UNUSED)
1001 enum machine_mode mode = GET_MODE (x);
1006 if (outer_code == SET)
1008 if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
1009 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L'))
1010 *total = COSTS_N_INSNS (1);
1012 *total = COSTS_N_INSNS (2);
1014 else if (outer_code == PLUS || outer_code == MINUS)
1016 if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'N'))
1018 else if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
1019 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L'))
1022 *total = COSTS_N_INSNS (2);
1024 else if (outer_code == AND || outer_code == IOR)
1026 if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'M'))
1028 else if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
1029 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'K'))
1032 *total = COSTS_N_INSNS (2);
1044 *total = COSTS_N_INSNS (2);
1049 /* If the address is legitimate, return the number of
1050 instructions it needs, otherwise use the default handling. */
1051 int n = score3_address_insns (XEXP (x, 0), GET_MODE (x));
1054 *total = COSTS_N_INSNS (n + 1);
1061 *total = COSTS_N_INSNS (6);
1065 *total = COSTS_N_INSNS (1);
1073 *total = COSTS_N_INSNS (2);
1083 *total = COSTS_N_INSNS ((GET_CODE (XEXP (x, 1)) == CONST_INT)
1090 *total = COSTS_N_INSNS (4);
1097 *total = COSTS_N_INSNS (4);
1100 *total = COSTS_N_INSNS (1);
1106 *total = COSTS_N_INSNS (4);
1112 *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (12);
1119 *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (33);
1124 switch (GET_MODE (XEXP (x, 0)))
1128 if (GET_CODE (XEXP (x, 0)) == MEM)
1130 *total = COSTS_N_INSNS (2);
1132 if (!TARGET_LITTLE_ENDIAN &&
1133 side_effects_p (XEXP (XEXP (x, 0), 0)))
1137 *total = COSTS_N_INSNS (1);
1141 *total = COSTS_N_INSNS (1);
1151 /* Implement TARGET_ADDRESS_COST macro. */
1153 score3_address_cost (rtx addr)
1155 return score3_address_insns (addr, SImode);
1158 /* Implement ASM_OUTPUT_EXTERNAL macro. */
1160 score3_output_external (FILE *file ATTRIBUTE_UNUSED,
1161 tree decl, const char *name)
1163 register struct extern_list *p;
1165 if (score3_in_small_data_p (decl))
1167 p = (struct extern_list *) ggc_alloc (sizeof (struct extern_list));
1168 p->next = extern_head;
1170 p->size = int_size_in_bytes (TREE_TYPE (decl));
1176 /* Implement RETURN_ADDR_RTX. Note, we do not support moving
1177 back to a previous frame. */
1179 score3_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
1183 return get_hard_reg_initial_val (Pmode, RA_REGNUM);
1186 /* Implement PRINT_OPERAND macro. */
1187 /* Score-specific operand codes:
1188 '[' print .set nor1 directive
1189 ']' print .set r1 directive
1190 'U' print hi part of a CONST_INT rtx
1193 'D' print SFmode const double
1194 'S' selectively print "!" if operand is 15bit instruction accessible
1195 'V' print "v!" if operand is 15bit instruction accessible, or "lfh!"
1196 'L' low part of DImode reg operand
1197 'H' high part of DImode reg operand
1198 'C' print part of opcode for a branch condition. */
1200 score3_print_operand (FILE *file, rtx op, int c)
1202 enum rtx_code code = -1;
1203 if (!PRINT_OPERAND_PUNCT_VALID_P (c))
1204 code = GET_CODE (op);
1208 fprintf (file, ".set r1\n");
1212 fprintf (file, "\n\t.set nor1");
1216 gcc_assert (code == CONST_INT);
1217 fprintf (file, HOST_WIDE_INT_PRINT_HEX,
1218 (INTVAL (op) >> 16) & 0xffff);
1222 if (GET_CODE (op) == CONST_DOUBLE)
1224 rtx temp = gen_lowpart (SImode, op);
1225 gcc_assert (GET_MODE (op) == SFmode);
1226 fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (temp) & 0xffffffff);
1229 output_addr_const (file, op);
1233 gcc_assert (code == REG);
1234 if (G16_REG_P (REGNO (op)))
1235 fprintf (file, "!");
1239 gcc_assert (code == REG);
1240 fprintf (file, G16_REG_P (REGNO (op)) ? "v!" : "lfh!");
1244 enum machine_mode mode = GET_MODE (XEXP (op, 0));
1248 case EQ: fputs ("eq!", file); break;
1249 case NE: fputs ("ne!", file); break;
1250 case GT: fputs ("gt!", file); break;
1251 case GE: fputs (mode != CCmode ? "pl" : "ge", file); break;
1252 case LT: fputs (mode != CCmode ? "mi" : "lt", file); break;
1253 case LE: fputs ("le!", file); break;
1254 case GTU: fputs ("gtu!", file); break;
1255 case GEU: fputs ("cs", file); break;
1256 case LTU: fputs ("cc", file); break;
1257 case LEU: fputs ("leu!", file); break;
1259 output_operand_lossage ("invalid operand for code: '%c'", code);
1262 else if (c == 'G') /* Seperate from b<cond>, use for mv<cond>. */
1264 enum machine_mode mode = GET_MODE (XEXP (op, 0));
1268 case EQ: fputs ("eq", file); break;
1269 case NE: fputs ("ne", file); break;
1270 case GT: fputs ("gt", file); break;
1271 case GE: fputs (mode != CCmode ? "pl" : "ge", file); break;
1272 case LT: fputs (mode != CCmode ? "mi" : "lt", file); break;
1273 case LE: fputs ("le", file); break;
1274 case GTU: fputs ("gtu", file); break;
1275 case GEU: fputs ("cs", file); break;
1276 case LTU: fputs ("cc", file); break;
1277 case LEU: fputs ("leu", file); break;
1279 output_operand_lossage ("invalid operand for code: '%c'", code);
1284 unsigned HOST_WIDE_INT i;
1285 unsigned HOST_WIDE_INT pow2mask = 1;
1286 unsigned HOST_WIDE_INT val;
1289 for (i = 0; i < 32; i++)
1291 if (val == pow2mask)
1295 gcc_assert (i < 32);
1296 fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
1300 unsigned HOST_WIDE_INT i;
1301 unsigned HOST_WIDE_INT pow2mask = 1;
1302 unsigned HOST_WIDE_INT val;
1305 for (i = 0; i < 32; i++)
1307 if (val == pow2mask)
1311 gcc_assert (i < 32);
1312 fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
1314 else if (code == REG)
1316 int regnum = REGNO (op);
1317 if ((c == 'H' && !WORDS_BIG_ENDIAN)
1318 || (c == 'L' && WORDS_BIG_ENDIAN))
1320 fprintf (file, "%s", reg_names[regnum]);
1327 score3_print_operand_address (file, op);
1330 output_addr_const (file, op);
1335 /* Implement PRINT_OPERAND_ADDRESS macro. */
1337 score3_print_operand_address (FILE *file, rtx x)
1339 struct score3_address_info addr;
1340 enum rtx_code code = GET_CODE (x);
1341 enum machine_mode mode = GET_MODE (x);
1346 if (score3_classify_address (&addr, mode, x, true))
1350 case SCORE3_ADD_REG:
1355 fprintf (file, "[%s,-%ld]+", reg_names[REGNO (addr.reg)],
1356 INTVAL (addr.offset));
1359 fprintf (file, "[%s]+,-%ld", reg_names[REGNO (addr.reg)],
1360 INTVAL (addr.offset));
1363 fprintf (file, "[%s, %ld]+", reg_names[REGNO (addr.reg)],
1364 INTVAL (addr.offset));
1367 fprintf (file, "[%s]+, %ld", reg_names[REGNO (addr.reg)],
1368 INTVAL (addr.offset));
1371 if (INTVAL(addr.offset) == 0)
1372 fprintf(file, "[%s]", reg_names[REGNO (addr.reg)]);
1374 fprintf(file, "[%s, %ld]", reg_names[REGNO (addr.reg)],
1375 INTVAL(addr.offset));
1380 case SCORE3_ADD_CONST_INT:
1381 case SCORE3_ADD_SYMBOLIC:
1382 output_addr_const (file, x);
1386 print_rtl (stderr, x);
1390 /* Implement SELECT_CC_MODE macro. */
1392 score3_select_cc_mode (enum rtx_code op, rtx x, rtx y)
1394 if ((op == EQ || op == NE || op == LT || op == GE)
1396 && GET_MODE (x) == SImode)
1398 switch (GET_CODE (x))
1416 return (op == LT || op == GE) ? CC_Nmode : CCmode;
1423 if ((op == EQ || op == NE)
1424 && (GET_CODE (y) == NEG)
1425 && register_operand (XEXP (y, 0), SImode)
1426 && register_operand (x, SImode))
1434 #define EMIT_PL(_rtx) RTX_FRAME_RELATED_P (_rtx) = 1
1435 /* return 0, no more bit set in mask. */
1436 static int rpush_first (int mask, int sb, int *rd)
1440 if ((mask & (1 << sb)) == 0)
1445 for (i = sb-1; i >= 0; i--)
1447 if (mask & (1 << i))
1461 rpush (int rd, int cnt)
1463 rtx mem = gen_rtx_MEM (SImode, gen_rtx_PRE_DEC (SImode, stack_pointer_rtx));
1464 rtx reg = gen_rtx_REG (SImode, rd);
1466 if (!crtl->calls_eh_return)
1467 MEM_READONLY_P (mem) = 1;
1470 EMIT_PL (emit_insn (gen_pushsi_score3 (mem, reg)));
1474 rtx insn = gen_store_multiple (gen_rtx_MEM (SImode, stack_pointer_rtx),
1475 gen_rtx_REG (SImode, rd),
1478 rtx pat = PATTERN (insn);
1480 for (i = 0; i < XVECLEN (pat, 0); i++)
1481 if (GET_CODE (XVECEXP (pat, 0, i)) == SET)
1482 RTX_FRAME_RELATED_P (XVECEXP (pat, 0, i)) = 1;
1484 EMIT_PL (emit_insn (insn));
1488 /* Generate the prologue instructions for entry into a S+core function. */
1490 score3_prologue (void)
1492 struct score3_frame_info *f = score3_compute_frame_size (get_frame_size ());
1496 size = f->total_size - f->gp_reg_size;
1499 emit_insn (gen_cpload_score3 ());
1504 for (regno = (int) GP_REG_LAST; regno >= (int) GP_REG_FIRST; regno--)
1506 cnt = rpush_first (f->mask, regno, &rd);
1510 regno = regno - cnt;
1519 if (CONST_OK_FOR_LETTER_P (-size, 'L'))
1520 EMIT_PL (emit_insn (gen_add3_insn (stack_pointer_rtx,
1525 EMIT_PL (emit_move_insn (gen_rtx_REG (Pmode, SCORE3_PROLOGUE_TEMP_REGNUM),
1528 (gen_sub3_insn (stack_pointer_rtx,
1531 SCORE3_PROLOGUE_TEMP_REGNUM))));
1533 insn = get_last_insn ();
1535 alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR,
1536 gen_rtx_SET (VOIDmode, stack_pointer_rtx,
1537 plus_constant (stack_pointer_rtx,
1542 if (frame_pointer_needed)
1543 EMIT_PL (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx));
1545 if (flag_pic && f->cprestore_size)
1547 if (frame_pointer_needed)
1548 emit_insn (gen_cprestore_use_fp_score3 (GEN_INT (size - f->cprestore_size)));
1550 emit_insn (gen_cprestore_use_sp_score3 (GEN_INT (size - f->cprestore_size)));
1554 /* return 0, no more bit set in mask. */
1556 rpop_first (int mask, int sb, int *rd)
1560 if ((mask & (1 << sb)) == 0)
1565 for (i = sb+1; i < 32; i++)
1566 if (mask & (1 << i))
1575 rpop (int rd, int cnt)
1577 rtx mem = gen_rtx_MEM (SImode, gen_rtx_POST_INC (SImode, stack_pointer_rtx));
1578 rtx reg = gen_rtx_REG (SImode, rd);
1580 if (!crtl->calls_eh_return)
1581 MEM_READONLY_P (mem) = 1;
1584 emit_insn (gen_popsi_score3 (reg, mem));
1586 emit_insn (gen_load_multiple (reg,
1587 gen_rtx_MEM (SImode, stack_pointer_rtx),
1591 /* Generate the epilogue instructions in a S+core function. */
1593 score3_epilogue (int sibcall_p)
1595 struct score3_frame_info *f = score3_compute_frame_size (get_frame_size ());
1600 size = f->total_size - f->gp_reg_size;
1602 if (!frame_pointer_needed)
1603 base = stack_pointer_rtx;
1605 base = hard_frame_pointer_rtx;
1609 if (CONST_OK_FOR_LETTER_P (size, 'L'))
1610 emit_insn (gen_add3_insn (base, base, GEN_INT (size)));
1613 emit_move_insn (gen_rtx_REG (Pmode, SCORE3_EPILOGUE_TEMP_REGNUM),
1615 emit_insn (gen_add3_insn (base, base,
1617 SCORE3_EPILOGUE_TEMP_REGNUM)));
1621 if (base != stack_pointer_rtx)
1622 emit_move_insn (stack_pointer_rtx, base);
1624 if (crtl->calls_eh_return)
1625 emit_insn (gen_add3_insn (stack_pointer_rtx,
1627 EH_RETURN_STACKADJ_RTX));
1632 for (regno = (int) GP_REG_FIRST; regno <= (int) GP_REG_LAST; regno++)
1634 cnt = rpop_first (f->mask, regno, &rd);
1638 regno = regno + cnt;
1644 emit_jump_insn (gen_return_internal_score3 (gen_rtx_REG (Pmode, RA_REGNUM)));
1647 /* Return true if X is a symbolic constant that can be calculated in
1648 the same way as a bare symbol. If it is, store the type of the
1649 symbol in *SYMBOL_TYPE. */
1651 score3_symbolic_constant_p (rtx x, enum score_symbol_type *symbol_type)
1653 HOST_WIDE_INT offset;
1655 score3_split_const (x, &x, &offset);
1656 if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF)
1657 *symbol_type = score3_classify_symbol (x);
1664 /* if offset > 15bit, must reload */
1665 if (!IMM_IN_RANGE (offset, 15, 1))
1668 switch (*symbol_type)
1670 case SYMBOL_GENERAL:
1672 case SYMBOL_SMALL_DATA:
1673 return score3_offset_within_object_p (x, offset);
1679 score3_movsicc (rtx *ops)
1681 enum machine_mode mode;
1683 mode = score3_select_cc_mode (GET_CODE (ops[1]), ops[2], ops[3]);
1684 emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (mode, CC_REGNUM),
1685 gen_rtx_COMPARE (mode, XEXP (ops[1], 0),
1686 XEXP (ops[1], 1))));
1689 /* Call and sibcall pattern all need call this function. */
1691 score3_call (rtx *ops, bool sib)
1693 rtx addr = XEXP (ops[0], 0);
1694 if (!call_insn_operand (addr, VOIDmode))
1697 addr = gen_reg_rtx (Pmode);
1698 gen_move_insn (addr, oaddr);
1702 emit_call_insn (gen_sibcall_internal_score3 (addr, ops[1]));
1704 emit_call_insn (gen_call_internal_score3 (addr, ops[1]));
1707 /* Call value and sibcall value pattern all need call this function. */
1709 score3_call_value (rtx *ops, bool sib)
1711 rtx result = ops[0];
1712 rtx addr = XEXP (ops[1], 0);
1715 if (!call_insn_operand (addr, VOIDmode))
1718 addr = gen_reg_rtx (Pmode);
1719 gen_move_insn (addr, oaddr);
1723 emit_call_insn (gen_sibcall_value_internal_score3 (result, addr, arg));
1725 emit_call_insn (gen_call_value_internal_score3 (result, addr, arg));
1730 score3_movdi (rtx *ops)
1734 rtx dst0 = score3_subw (dst, 0);
1735 rtx dst1 = score3_subw (dst, 1);
1736 rtx src0 = score3_subw (src, 0);
1737 rtx src1 = score3_subw (src, 1);
1739 if (GET_CODE (dst0) == REG && reg_overlap_mentioned_p (dst0, src))
1741 emit_move_insn (dst1, src1);
1742 emit_move_insn (dst0, src0);
1746 emit_move_insn (dst0, src0);
1747 emit_move_insn (dst1, src1);
1752 score3_zero_extract_andi (rtx *ops)
1754 if (INTVAL (ops[1]) == 1 && const_uimm5 (ops[2], SImode))
1755 emit_insn (gen_zero_extract_bittst_score3 (ops[0], ops[2]));
1758 unsigned HOST_WIDE_INT mask;
1759 mask = (0xffffffffU & ((1U << INTVAL (ops[1])) - 1U));
1760 mask = mask << INTVAL (ops[2]);
1761 emit_insn (gen_andsi3_cmp_score3 (ops[3], ops[0],
1762 gen_int_mode (mask, SImode)));
1767 score3_rpush (rtx *ops)
1769 snprintf (score3_ins, INS_BUF_SZ, "rpush!\t%%1, %d", XVECLEN (ops[0], 0));
1774 score3_rpop (rtx *ops)
1776 snprintf (score3_ins, INS_BUF_SZ, "rpop!\t%%1, %d", XVECLEN (ops[0], 0));
1780 /* Output asm code for ld/sw insn. */
1782 score3_pr_addr_post (rtx *ops, int idata, int iaddr, char *ip,
1783 enum score_mem_unit unit ATTRIBUTE_UNUSED)
1785 struct score3_address_info ai;
1787 gcc_assert (GET_CODE (ops[idata]) == REG);
1788 gcc_assert (score3_classify_address (&ai, SImode, XEXP (ops[iaddr], 0), true));
1790 if (ai.type == SCORE3_ADD_REG
1792 && GET_CODE (ai.offset) == CONST_INT
1793 && G16_REG_P (REGNO (ops[idata]))
1794 && G8_REG_P (REGNO (ai.reg))
1795 && ((INTVAL (ai.offset) & 3) == 0)
1796 && (IMM_IN_RANGE (INTVAL (ai.offset), 7, 0)))
1798 ops[iaddr] = ai.reg;
1799 return snprintf (ip, INS_BUF_SZ, "!\t%%%d, [%%%d, "
1800 HOST_WIDE_INT_PRINT_DEC "]",
1801 idata, iaddr, INTVAL (ai.offset));
1804 if (ai.type == SCORE3_ADD_SYMBOLIC)
1805 return snprintf (ip, INS_BUF_SZ, "48\t%%%d, %%a%d", idata, iaddr);
1807 return snprintf (ip, INS_BUF_SZ, "\t%%%d, %%a%d", idata, iaddr);
1810 /* Output asm insn for load. */
1812 score3_linsn (rtx *ops, enum score_mem_unit unit, bool sign)
1814 const char *pre_ins[] =
1815 {"lbu", "lhu", "lw", "??", "lb", "lh", "lw", "??"};
1818 strcpy (score3_ins, pre_ins[(sign ? 4 : 0) + unit]);
1819 ip = score3_ins + strlen (score3_ins);
1821 if (unit == SCORE_WORD)
1822 score3_pr_addr_post (ops, 0, 1, ip, unit);
1824 snprintf (ip, INS_BUF_SZ, "\t%%0, %%a1");
1829 /* Output asm insn for store. */
1831 score3_sinsn (rtx *ops, enum score_mem_unit unit)
1833 const char *pre_ins[] = {"sb", "sh", "sw"};
1836 strcpy (score3_ins, pre_ins[unit]);
1837 ip = score3_ins + strlen (score3_ins);
1839 if (unit == SCORE_WORD)
1840 score3_pr_addr_post (ops, 1, 0, ip, unit);
1842 snprintf (ip, INS_BUF_SZ, "\t%%1, %%a0");
1847 /* Output asm insn for load immediate. */
1849 score3_limm (rtx *ops)
1853 gcc_assert (GET_CODE (ops[0]) == REG);
1854 gcc_assert (GET_CODE (ops[1]) == CONST_INT);
1856 v = INTVAL (ops[1]);
1857 if (G16_REG_P (REGNO (ops[0])) && IMM_IN_RANGE (v, 5, 0))
1858 return "ldiu!\t%0, %c1";
1859 else if (IMM_IN_RANGE (v, 16, 1))
1860 return "ldi\t%0, %c1";
1861 else if ((v & 0xffff) == 0)
1862 return "ldis\t%0, %U1";
1864 return "li\t%0, %c1";
1867 /* Output asm insn for move. */
1869 score3_move (rtx *ops)
1871 gcc_assert (GET_CODE (ops[0]) == REG);
1872 gcc_assert (GET_CODE (ops[1]) == REG);
1874 return "mv!\t%0, %1";
1877 /* Generate add insn. */
1879 score3_select_add_imm (rtx *ops, bool set_cc)
1881 HOST_WIDE_INT v = INTVAL (ops[2]);
1883 gcc_assert (GET_CODE (ops[2]) == CONST_INT);
1884 gcc_assert (REGNO (ops[0]) == REGNO (ops[1]));
1887 return "addi.c\t%0, %c2";
1889 if (IMM_IN_RANGE (v, 6, 1) && G16_REG_P (REGNO (ops[0])))
1890 return "addi!\t%0, %c2";
1892 return "addi\t%0, %c2";
1895 /* Output arith insn. */
1897 score3_select (rtx *ops, const char *inst_pre, bool commu ATTRIBUTE_UNUSED,
1898 const char *letter, bool set_cc)
1900 gcc_assert (GET_CODE (ops[0]) == REG);
1901 gcc_assert (GET_CODE (ops[1]) == REG);
1904 snprintf (score3_ins, INS_BUF_SZ, "%s.c\t%%0, %%1, %%%s2", inst_pre, letter);
1906 snprintf (score3_ins, INS_BUF_SZ, "%s\t%%0, %%1, %%%s2", inst_pre, letter);
1910 /* Output a Score3 casesi instruction. */
1912 score3_output_casesi (rtx *operands)
1914 rtx diff_vec = PATTERN (next_real_insn (operands[2]));
1915 gcc_assert (GET_CODE (diff_vec) == ADDR_DIFF_VEC);
1917 output_asm_insn ("cmpi.c\t%0, %1", operands);
1918 output_asm_insn ("bgtu\t%3", operands);
1919 switch (GET_MODE(diff_vec))
1922 output_asm_insn ("ldi48\t%4, %2", operands);
1923 output_asm_insn ("ltbb\t%4, [%4, %0]\n%2_tbb:", operands);
1926 output_asm_insn ("ldi48\t%4, %2", operands);
1927 output_asm_insn ("ltbh\t%4, [%4, %0]\n%2_tbb:", operands);
1930 output_asm_insn ("ldi48\t%4, %2", operands);
1931 output_asm_insn ("ltbw\t%4, [%4, %0]", operands);