1 /* score3.c for Sunplus S+CORE processor
2 Copyright (C) 2005, 2007, 2008, 2009, 2010 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"
32 #include "diagnostic-core.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 score3_sdata_max
;
59 static char score3_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 score3_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 score3_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 score3_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
)) <= SCORE3_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 score3_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 score3_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 score3_frame_info
*
165 score3_cached_frame (void)
167 static struct score3_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 score3_frame_info
*
174 score3_compute_frame_size (HOST_WIDE_INT size
)
177 struct score3_frame_info
*f
= score3_cached_frame ();
179 memset (f
, 0, sizeof (struct score3_frame_info
));
182 f
->var_size
= SCORE3_STACK_ALIGN (size
);
183 f
->args_size
= crtl
->outgoing_args_size
;
184 f
->cprestore_size
= flag_pic
? UNITS_PER_WORD
: 0;
186 if (f
->var_size
== 0 && current_function_is_leaf
)
187 f
->args_size
= f
->cprestore_size
= 0;
189 if (f
->args_size
== 0 && cfun
->calls_alloca
)
190 f
->args_size
= UNITS_PER_WORD
;
192 f
->total_size
= f
->var_size
+ f
->args_size
+ f
->cprestore_size
;
193 for (regno
= GP_REG_FIRST
; regno
<= GP_REG_LAST
; regno
++)
195 if (score3_save_reg_p (regno
))
197 f
->gp_reg_size
+= GET_MODE_SIZE (SImode
);
198 f
->mask
|= 1 << (regno
- GP_REG_FIRST
);
202 if (crtl
->calls_eh_return
)
207 regno
= EH_RETURN_DATA_REGNO (i
);
208 if (regno
== INVALID_REGNUM
)
210 f
->gp_reg_size
+= GET_MODE_SIZE (SImode
);
211 f
->mask
|= 1 << (regno
- GP_REG_FIRST
);
215 f
->total_size
+= f
->gp_reg_size
;
216 f
->num_gp
= f
->gp_reg_size
/ UNITS_PER_WORD
;
220 HOST_WIDE_INT offset
;
221 offset
= (f
->args_size
+ f
->cprestore_size
+ f
->var_size
222 + f
->gp_reg_size
- GET_MODE_SIZE (SImode
));
223 f
->gp_sp_offset
= offset
;
231 /* Return true if X is a valid base register for the given mode.
232 Allow only hard registers if STRICT. */
234 score3_valid_base_register_p (rtx x
, int strict
)
236 if (!strict
&& GET_CODE (x
) == SUBREG
)
239 return (GET_CODE (x
) == REG
240 && score3_regno_mode_ok_for_base_p (REGNO (x
), strict
));
243 /* Return true if X is a valid address for machine mode MODE. If it is,
244 fill in INFO appropriately. STRICT is true if we should only accept
245 hard base registers. */
247 score3_classify_address (struct score3_address_info
*info
,
248 enum machine_mode mode
, rtx x
, int strict
)
250 info
->code
= GET_CODE (x
);
256 info
->type
= SCORE3_ADD_REG
;
258 info
->offset
= const0_rtx
;
259 return score3_valid_base_register_p (info
->reg
, strict
);
261 info
->type
= SCORE3_ADD_REG
;
262 info
->reg
= XEXP (x
, 0);
263 info
->offset
= XEXP (x
, 1);
264 return (score3_valid_base_register_p (info
->reg
, strict
)
265 && GET_CODE (info
->offset
) == CONST_INT
266 && IMM_IN_RANGE (INTVAL (info
->offset
), 15, 1));
271 if (GET_MODE_SIZE (mode
) > GET_MODE_SIZE (SImode
))
273 info
->type
= SCORE3_ADD_REG
;
274 info
->reg
= XEXP (x
, 0);
275 info
->offset
= GEN_INT (GET_MODE_SIZE (mode
));
276 return score3_valid_base_register_p (info
->reg
, strict
);
278 info
->type
= SCORE3_ADD_CONST_INT
;
283 info
->type
= SCORE3_ADD_SYMBOLIC
;
284 return (score3_symbolic_constant_p (x
, &info
->symbol_type
)
285 && (info
->symbol_type
== SYMBOL_GENERAL
286 || info
->symbol_type
== SYMBOL_SMALL_DATA
));
293 score3_return_in_memory (const_tree type
, const_tree fndecl ATTRIBUTE_UNUSED
)
295 return ((TYPE_MODE (type
) == BLKmode
)
296 || (int_size_in_bytes (type
) > 2 * UNITS_PER_WORD
)
297 || (int_size_in_bytes (type
) == -1));
300 /* Return a legitimate address for REG + OFFSET. */
302 score3_add_offset (rtx reg
, HOST_WIDE_INT offset
)
304 if (!IMM_IN_RANGE (offset
, 15, 1))
306 reg
= expand_simple_binop (GET_MODE (reg
), PLUS
,
307 gen_int_mode (offset
& 0xffffc000,
309 reg
, NULL
, 0, OPTAB_WIDEN
);
313 return plus_constant (reg
, offset
);
316 /* Implement TARGET_ASM_OUTPUT_MI_THUNK. Generate rtl rather than asm text
317 in order to avoid duplicating too much logic from elsewhere. */
319 score3_output_mi_thunk (FILE *file
, tree thunk_fndecl ATTRIBUTE_UNUSED
,
320 HOST_WIDE_INT delta
, HOST_WIDE_INT vcall_offset
,
323 rtx this_rtx
, temp1
, insn
, fnaddr
;
325 /* Pretend to be a post-reload pass while generating rtl. */
326 reload_completed
= 1;
328 /* Mark the end of the (empty) prologue. */
329 emit_note (NOTE_INSN_PROLOGUE_END
);
331 /* We need two temporary registers in some cases. */
332 temp1
= gen_rtx_REG (Pmode
, 8);
334 /* Find out which register contains the "this" pointer. */
335 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function
)), function
))
336 this_rtx
= gen_rtx_REG (Pmode
, ARG_REG_FIRST
+ 1);
338 this_rtx
= gen_rtx_REG (Pmode
, ARG_REG_FIRST
);
340 /* Add DELTA to THIS_RTX. */
343 rtx offset
= GEN_INT (delta
);
344 if (!CONST_OK_FOR_LETTER_P (delta
, 'L'))
346 emit_move_insn (temp1
, offset
);
349 emit_insn (gen_add3_insn (this_rtx
, this_rtx
, offset
));
352 /* If needed, add *(*THIS_RTX + VCALL_OFFSET) to THIS_RTX. */
353 if (vcall_offset
!= 0)
357 /* Set TEMP1 to *THIS_RTX. */
358 emit_move_insn (temp1
, gen_rtx_MEM (Pmode
, this_rtx
));
360 /* Set ADDR to a legitimate address for *THIS_RTX + VCALL_OFFSET. */
361 addr
= score3_add_offset (temp1
, vcall_offset
);
363 /* Load the offset and add it to THIS_RTX. */
364 emit_move_insn (temp1
, gen_rtx_MEM (Pmode
, addr
));
365 emit_insn (gen_add3_insn (this_rtx
, this_rtx
, temp1
));
368 /* Jump to the target function. */
369 fnaddr
= XEXP (DECL_RTL (function
), 0);
370 insn
= emit_call_insn (gen_sibcall_internal_score3 (fnaddr
, const0_rtx
));
371 SIBLING_CALL_P (insn
) = 1;
373 /* Run just enough of rest_of_compilation. This sequence was
374 "borrowed" from alpha.c. */
376 insn_locators_alloc ();
377 split_all_insns_noflow ();
378 shorten_branches (insn
);
379 final_start_function (insn
, file
, 1);
380 final (insn
, file
, 1);
381 final_end_function ();
383 /* Clean up the vars set above. Note that final_end_function resets
384 the global pointer for us. */
385 reload_completed
= 0;
388 /* Copy VALUE to a register and return that register. If new psuedos
389 are allowed, copy it into a new register, otherwise use DEST. */
391 score3_force_temporary (rtx dest
, rtx value
)
393 if (can_create_pseudo_p ())
394 return force_reg (Pmode
, value
);
397 emit_move_insn (copy_rtx (dest
), value
);
402 /* Return a LO_SUM expression for ADDR. TEMP is as for score_force_temporary
403 and is used to load the high part into a register. */
405 score3_split_symbol (rtx temp
, rtx addr
)
407 rtx high
= score3_force_temporary (temp
,
408 gen_rtx_HIGH (Pmode
, copy_rtx (addr
)));
409 return gen_rtx_LO_SUM (Pmode
, high
, addr
);
412 /* This function is used to implement LEGITIMIZE_ADDRESS. If X can
413 be legitimized in a way that the generic machinery might not expect,
414 return the new address. */
416 score3_legitimize_address (rtx x
)
418 enum score_symbol_type symbol_type
;
420 if (score3_symbolic_constant_p (x
, &symbol_type
)
421 && symbol_type
== SYMBOL_GENERAL
)
422 return score3_split_symbol (0, x
);
424 if (GET_CODE (x
) == PLUS
425 && GET_CODE (XEXP (x
, 1)) == CONST_INT
)
427 rtx reg
= XEXP (x
, 0);
428 if (!score3_valid_base_register_p (reg
, 0))
429 reg
= copy_to_mode_reg (Pmode
, reg
);
430 return score3_add_offset (reg
, INTVAL (XEXP (x
, 1)));
436 /* Fill INFO with information about a single argument. CUM is the
437 cumulative state for earlier arguments. MODE is the mode of this
438 argument and TYPE is its type (if known). NAMED is true if this
439 is a named (fixed) argument rather than a variable one. */
441 score3_classify_arg (const CUMULATIVE_ARGS
*cum
, enum machine_mode mode
,
442 const_tree type
, bool named
, struct score3_arg_info
*info
)
445 unsigned int num_words
, max_regs
;
448 if (GET_MODE_CLASS (mode
) == MODE_INT
449 || GET_MODE_CLASS (mode
) == MODE_FLOAT
)
450 even_reg_p
= (GET_MODE_SIZE (mode
) > UNITS_PER_WORD
);
452 if (type
!= NULL_TREE
&& TYPE_ALIGN (type
) > BITS_PER_WORD
&& named
)
455 if (TARGET_MUST_PASS_IN_STACK (mode
, type
))
456 info
->reg_offset
= ARG_REG_NUM
;
459 info
->reg_offset
= cum
->num_gprs
;
461 info
->reg_offset
+= info
->reg_offset
& 1;
465 info
->num_bytes
= int_size_in_bytes (type
);
467 info
->num_bytes
= GET_MODE_SIZE (mode
);
469 num_words
= (info
->num_bytes
+ UNITS_PER_WORD
- 1) / UNITS_PER_WORD
;
470 max_regs
= ARG_REG_NUM
- info
->reg_offset
;
472 /* Partition the argument between registers and stack. */
473 info
->reg_words
= MIN (num_words
, max_regs
);
474 info
->stack_words
= num_words
- info
->reg_words
;
476 /* The alignment applied to registers is also applied to stack arguments. */
477 if (info
->stack_words
)
479 info
->stack_offset
= cum
->stack_words
;
481 info
->stack_offset
+= info
->stack_offset
& 1;
485 /* Set up the stack and frame (if desired) for the function. */
487 score3_function_prologue (FILE *file
, HOST_WIDE_INT size ATTRIBUTE_UNUSED
)
490 struct score3_frame_info
*f
= score3_cached_frame ();
491 HOST_WIDE_INT tsize
= f
->total_size
;
493 fnname
= XSTR (XEXP (DECL_RTL (current_function_decl
), 0), 0);
494 if (!flag_inhibit_size_directive
)
496 fputs ("\t.ent\t", file
);
497 assemble_name (file
, fnname
);
500 assemble_name (file
, fnname
);
503 if (!flag_inhibit_size_directive
)
506 "\t.frame\t%s," HOST_WIDE_INT_PRINT_DEC
",%s, %d\t\t"
507 "# vars= " HOST_WIDE_INT_PRINT_DEC
", regs= %d"
508 ", args= " HOST_WIDE_INT_PRINT_DEC
509 ", gp= " HOST_WIDE_INT_PRINT_DEC
"\n",
510 (reg_names
[(frame_pointer_needed
)
511 ? HARD_FRAME_POINTER_REGNUM
: STACK_POINTER_REGNUM
]),
513 reg_names
[RA_REGNUM
],
514 current_function_is_leaf
? 1 : 0,
520 fprintf(file
, "\t.mask\t0x%08x," HOST_WIDE_INT_PRINT_DEC
"\n",
522 (f
->gp_sp_offset
- f
->total_size
));
526 /* Do any necessary cleanup after a function to restore stack, frame,
529 score3_function_epilogue (FILE *file
,
530 HOST_WIDE_INT size ATTRIBUTE_UNUSED
)
532 if (!flag_inhibit_size_directive
)
535 fnname
= XSTR (XEXP (DECL_RTL (current_function_decl
), 0), 0);
536 fputs ("\t.end\t", file
);
537 assemble_name (file
, fnname
);
542 /* Returns true if X contains a SYMBOL_REF. */
544 score3_symbolic_expression_p (rtx x
)
546 if (GET_CODE (x
) == SYMBOL_REF
)
549 if (GET_CODE (x
) == CONST
)
550 return score3_symbolic_expression_p (XEXP (x
, 0));
553 return score3_symbolic_expression_p (XEXP (x
, 0));
555 if (ARITHMETIC_P (x
))
556 return (score3_symbolic_expression_p (XEXP (x
, 0))
557 || score3_symbolic_expression_p (XEXP (x
, 1)));
562 /* Choose the section to use for the constant rtx expression X that has
565 score3_select_rtx_section (enum machine_mode mode
, rtx x
,
566 unsigned HOST_WIDE_INT align
)
568 if (GET_MODE_SIZE (mode
) <= SCORE3_SDATA_MAX
)
569 return get_named_section (0, ".sdata", 0);
570 else if (flag_pic
&& score3_symbolic_expression_p (x
))
571 return get_named_section (0, ".data.rel.ro", 3);
573 return mergeable_constant_section (mode
, align
, 0);
576 /* Implement TARGET_IN_SMALL_DATA_P. */
578 score3_in_small_data_p (const_tree decl
)
582 if (TREE_CODE (decl
) == STRING_CST
583 || TREE_CODE (decl
) == FUNCTION_DECL
)
586 if (TREE_CODE (decl
) == VAR_DECL
&& DECL_SECTION_NAME (decl
) != 0)
589 name
= TREE_STRING_POINTER (DECL_SECTION_NAME (decl
));
590 if (strcmp (name
, ".sdata") != 0
591 && strcmp (name
, ".sbss") != 0)
593 if (!DECL_EXTERNAL (decl
))
596 size
= int_size_in_bytes (TREE_TYPE (decl
));
597 return (size
> 0 && size
<= SCORE3_SDATA_MAX
);
600 /* Implement TARGET_ASM_FILE_START. */
602 score3_asm_file_start (void)
604 default_file_start ();
605 fprintf (asm_out_file
, ASM_COMMENT_START
606 "GCC for S+core %s \n", SCORE_GCC_VERSION
);
609 fprintf (asm_out_file
, "\t.set pic\n");
612 /* Implement TARGET_ASM_FILE_END. When using assembler macros, emit
613 .externs for any small-data variables that turned out to be external. */
615 score3_asm_file_end (void)
618 struct extern_list
*p
;
621 fputs ("\n", asm_out_file
);
622 for (p
= extern_head
; p
!= 0; p
= p
->next
)
624 name_tree
= get_identifier (p
->name
);
625 if (!TREE_ASM_WRITTEN (name_tree
)
626 && TREE_SYMBOL_REFERENCED (name_tree
))
628 TREE_ASM_WRITTEN (name_tree
) = 1;
629 fputs ("\t.extern\t", asm_out_file
);
630 assemble_name (asm_out_file
, p
->name
);
631 fprintf (asm_out_file
, ", %d\n", p
->size
);
637 /* Implement TARGET_OPTION_OVERRIDE hook. */
639 score3_option_override (void)
643 score3_sdata_max
= (global_options_set
.x_g_switch_value
645 : SCORE3_DEFAULT_SDATA_MAX
);
648 score3_sdata_max
= 0;
649 if (global_options_set
.x_g_switch_value
&& (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 TARGET_FUNCTION_ARG_ADVANCE hook. */
804 score3_function_arg_advance (CUMULATIVE_ARGS
*cum
, enum machine_mode mode
,
805 const_tree type
, bool 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 TARGET_FUNCTION_ARG hook. */
827 score3_function_arg (const CUMULATIVE_ARGS
*cum
, enum machine_mode mode
,
828 const_tree type
, bool 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 (const_tree valtype
, const_tree func
,
863 enum machine_mode mode
)
868 mode
= TYPE_MODE (valtype
);
869 unsignedp
= TYPE_UNSIGNED (valtype
);
870 mode
= promote_function_mode (valtype
, mode
, &unsignedp
, func
, 1);
872 return gen_rtx_REG (mode
, RT_REGNUM
);
875 /* Implement TARGET_ASM_TRAMPOLINE_TEMPLATE. */
878 score3_asm_trampoline_template (FILE *f
)
880 fprintf (f
, "\t.set r1\n");
881 fprintf (f
, "\tmv! r31, r3\n");
882 fprintf (f
, "\tnop!\n");
883 fprintf (f
, "\tbl nextinsn\n");
884 fprintf (f
, "nextinsn:\n");
885 fprintf (f
, "\tlw! r1, [r3, 6*4-8]\n");
886 fprintf (f
, "\tnop!\n");
887 fprintf (f
, "\tlw r23, [r3, 6*4-4]\n");
888 fprintf (f
, "\tmv! r3, r31\n");
889 fprintf (f
, "\tnop!\n");
890 fprintf (f
, "\tbr! r1\n");
891 fprintf (f
, "\tnop!\n");
892 fprintf (f
, "\t.set nor1\n");
895 /* Implement TARGET_TRAMPOLINE_INIT. */
897 score3_trampoline_init (rtx m_tramp
, tree fndecl
, rtx chain_value
)
899 #define FFCACHE "_flush_cache"
900 #define CODE_SIZE (TRAMPOLINE_INSNS * UNITS_PER_WORD)
902 rtx fnaddr
= XEXP (DECL_RTL (fndecl
), 0);
903 rtx addr
= XEXP (m_tramp
, 0);
906 emit_block_move (m_tramp
, assemble_trampoline_template (),
907 GEN_INT (TRAMPOLINE_SIZE
), BLOCK_OP_NORMAL
);
909 mem
= adjust_address (m_tramp
, SImode
, CODE_SIZE
);
910 emit_move_insn (mem
, fnaddr
);
911 mem
= adjust_address (m_tramp
, SImode
, CODE_SIZE
+ GET_MODE_SIZE (SImode
));
912 emit_move_insn (mem
, chain_value
);
914 emit_library_call (gen_rtx_SYMBOL_REF (Pmode
, FFCACHE
),
915 LCT_NORMAL
, VOIDmode
, 2,
917 GEN_INT (TRAMPOLINE_SIZE
), SImode
);
922 /* This function is used to implement REG_MODE_OK_FOR_BASE_P macro. */
924 score3_regno_mode_ok_for_base_p (int regno
, int strict
)
926 if (regno
>= FIRST_PSEUDO_REGISTER
)
930 regno
= reg_renumber
[regno
];
932 if (regno
== ARG_POINTER_REGNUM
933 || regno
== FRAME_POINTER_REGNUM
)
935 return GP_REG_P (regno
);
938 /* Implement TARGET_LEGITIMATE_ADDRESS_P macro. */
940 score3_legitimate_address_p (enum machine_mode mode
, rtx x
, bool strict
)
942 struct score3_address_info addr
;
944 return score3_classify_address (&addr
, mode
, x
, strict
);
947 /* Return a number assessing the cost of moving a register in class
950 score3_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED
,
951 enum reg_class from
, enum reg_class to
)
953 if (GR_REG_CLASS_P (from
))
955 if (GR_REG_CLASS_P (to
))
957 else if (SP_REG_CLASS_P (to
))
959 else if (CP_REG_CLASS_P (to
))
961 else if (CE_REG_CLASS_P (to
))
964 if (GR_REG_CLASS_P (to
))
966 if (GR_REG_CLASS_P (from
))
968 else if (SP_REG_CLASS_P (from
))
970 else if (CP_REG_CLASS_P (from
))
972 else if (CE_REG_CLASS_P (from
))
978 /* Return the number of instructions needed to load a symbol of the
979 given type into a register. */
981 score3_symbol_insns (enum score_symbol_type type
)
988 case SYMBOL_SMALL_DATA
:
995 /* Return the number of instructions needed to load or store a value
996 of mode MODE at X. Return 0 if X isn't valid for MODE. */
998 score3_address_insns (rtx x
, enum machine_mode mode
)
1000 struct score3_address_info addr
;
1003 if (mode
== BLKmode
)
1006 factor
= (GET_MODE_SIZE (mode
) + UNITS_PER_WORD
- 1) / UNITS_PER_WORD
;
1008 if (score3_classify_address (&addr
, mode
, x
, false))
1011 case SCORE3_ADD_REG
:
1012 case SCORE3_ADD_CONST_INT
:
1015 case SCORE3_ADD_SYMBOLIC
:
1016 return factor
* score3_symbol_insns (addr
.symbol_type
);
1021 /* Implement TARGET_RTX_COSTS macro. */
1023 score3_rtx_costs (rtx x
, int code
, int outer_code
, int *total
,
1024 bool speed ATTRIBUTE_UNUSED
)
1026 enum machine_mode mode
= GET_MODE (x
);
1031 if (outer_code
== SET
)
1033 if (CONST_OK_FOR_LETTER_P (INTVAL (x
), 'I')
1034 || CONST_OK_FOR_LETTER_P (INTVAL (x
), 'L'))
1035 *total
= COSTS_N_INSNS (1);
1037 *total
= COSTS_N_INSNS (2);
1039 else if (outer_code
== PLUS
|| outer_code
== MINUS
)
1041 if (CONST_OK_FOR_LETTER_P (INTVAL (x
), 'N'))
1043 else if (CONST_OK_FOR_LETTER_P (INTVAL (x
), 'I')
1044 || CONST_OK_FOR_LETTER_P (INTVAL (x
), 'L'))
1047 *total
= COSTS_N_INSNS (2);
1049 else if (outer_code
== AND
|| outer_code
== IOR
)
1051 if (CONST_OK_FOR_LETTER_P (INTVAL (x
), 'M'))
1053 else if (CONST_OK_FOR_LETTER_P (INTVAL (x
), 'I')
1054 || CONST_OK_FOR_LETTER_P (INTVAL (x
), 'K'))
1057 *total
= COSTS_N_INSNS (2);
1069 *total
= COSTS_N_INSNS (2);
1074 /* If the address is legitimate, return the number of
1075 instructions it needs, otherwise use the default handling. */
1076 int n
= score3_address_insns (XEXP (x
, 0), GET_MODE (x
));
1079 *total
= COSTS_N_INSNS (n
+ 1);
1086 *total
= COSTS_N_INSNS (6);
1090 *total
= COSTS_N_INSNS (1);
1098 *total
= COSTS_N_INSNS (2);
1108 *total
= COSTS_N_INSNS ((GET_CODE (XEXP (x
, 1)) == CONST_INT
)
1115 *total
= COSTS_N_INSNS (4);
1122 *total
= COSTS_N_INSNS (4);
1125 *total
= COSTS_N_INSNS (1);
1131 *total
= COSTS_N_INSNS (4);
1137 *total
= optimize_size
? COSTS_N_INSNS (2) : COSTS_N_INSNS (12);
1144 *total
= optimize_size
? COSTS_N_INSNS (2) : COSTS_N_INSNS (33);
1149 switch (GET_MODE (XEXP (x
, 0)))
1153 if (GET_CODE (XEXP (x
, 0)) == MEM
)
1155 *total
= COSTS_N_INSNS (2);
1157 if (!TARGET_LITTLE_ENDIAN
&&
1158 side_effects_p (XEXP (XEXP (x
, 0), 0)))
1162 *total
= COSTS_N_INSNS (1);
1166 *total
= COSTS_N_INSNS (1);
1176 /* Implement TARGET_ADDRESS_COST macro. */
1178 score3_address_cost (rtx addr
)
1180 return score3_address_insns (addr
, SImode
);
1183 /* Implement ASM_OUTPUT_EXTERNAL macro. */
1185 score3_output_external (FILE *file ATTRIBUTE_UNUSED
,
1186 tree decl
, const char *name
)
1188 register struct extern_list
*p
;
1190 if (score3_in_small_data_p (decl
))
1192 p
= ggc_alloc_extern_list ();
1193 p
->next
= extern_head
;
1195 p
->size
= int_size_in_bytes (TREE_TYPE (decl
));
1201 /* Implement RETURN_ADDR_RTX. Note, we do not support moving
1202 back to a previous frame. */
1204 score3_return_addr (int count
, rtx frame ATTRIBUTE_UNUSED
)
1208 return get_hard_reg_initial_val (Pmode
, RA_REGNUM
);
1211 /* Implement PRINT_OPERAND macro. */
1212 /* Score-specific operand codes:
1213 '[' print .set nor1 directive
1214 ']' print .set r1 directive
1215 'U' print hi part of a CONST_INT rtx
1218 'D' print SFmode const double
1219 'S' selectively print "!" if operand is 15bit instruction accessible
1220 'V' print "v!" if operand is 15bit instruction accessible, or "lfh!"
1221 'L' low part of DImode reg operand
1222 'H' high part of DImode reg operand
1223 'C' print part of opcode for a branch condition. */
1225 score3_print_operand (FILE *file
, rtx op
, int c
)
1227 enum rtx_code code
= UNKNOWN
;
1228 if (!PRINT_OPERAND_PUNCT_VALID_P (c
))
1229 code
= GET_CODE (op
);
1233 fprintf (file
, ".set r1\n");
1237 fprintf (file
, "\n\t.set nor1");
1241 gcc_assert (code
== CONST_INT
);
1242 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
,
1243 (INTVAL (op
) >> 16) & 0xffff);
1247 if (GET_CODE (op
) == CONST_DOUBLE
)
1249 rtx temp
= gen_lowpart (SImode
, op
);
1250 gcc_assert (GET_MODE (op
) == SFmode
);
1251 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, INTVAL (temp
) & 0xffffffff);
1254 output_addr_const (file
, op
);
1258 gcc_assert (code
== REG
);
1259 if (G16_REG_P (REGNO (op
)))
1260 fprintf (file
, "!");
1264 gcc_assert (code
== REG
);
1265 fprintf (file
, G16_REG_P (REGNO (op
)) ? "v!" : "lfh!");
1269 enum machine_mode mode
= GET_MODE (XEXP (op
, 0));
1273 case EQ
: fputs ("eq!", file
); break;
1274 case NE
: fputs ("ne!", file
); break;
1275 case GT
: fputs ("gt!", file
); break;
1276 case GE
: fputs (mode
!= CCmode
? "pl" : "ge", file
); break;
1277 case LT
: fputs (mode
!= CCmode
? "mi" : "lt", file
); break;
1278 case LE
: fputs ("le!", file
); break;
1279 case GTU
: fputs ("gtu!", file
); break;
1280 case GEU
: fputs ("cs", file
); break;
1281 case LTU
: fputs ("cc", file
); break;
1282 case LEU
: fputs ("leu!", file
); break;
1284 output_operand_lossage ("invalid operand for code: '%c'", code
);
1287 else if (c
== 'G') /* Seperate from b<cond>, use for mv<cond>. */
1289 enum machine_mode mode
= GET_MODE (XEXP (op
, 0));
1293 case EQ
: fputs ("eq", file
); break;
1294 case NE
: fputs ("ne", file
); break;
1295 case GT
: fputs ("gt", file
); break;
1296 case GE
: fputs (mode
!= CCmode
? "pl" : "ge", file
); break;
1297 case LT
: fputs (mode
!= CCmode
? "mi" : "lt", file
); break;
1298 case LE
: fputs ("le", file
); break;
1299 case GTU
: fputs ("gtu", file
); break;
1300 case GEU
: fputs ("cs", file
); break;
1301 case LTU
: fputs ("cc", file
); break;
1302 case LEU
: fputs ("leu", file
); break;
1304 output_operand_lossage ("invalid operand for code: '%c'", code
);
1309 unsigned HOST_WIDE_INT i
;
1310 unsigned HOST_WIDE_INT pow2mask
= 1;
1311 unsigned HOST_WIDE_INT val
;
1314 for (i
= 0; i
< 32; i
++)
1316 if (val
== pow2mask
)
1320 gcc_assert (i
< 32);
1321 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, i
);
1325 unsigned HOST_WIDE_INT i
;
1326 unsigned HOST_WIDE_INT pow2mask
= 1;
1327 unsigned HOST_WIDE_INT val
;
1330 for (i
= 0; i
< 32; i
++)
1332 if (val
== pow2mask
)
1336 gcc_assert (i
< 32);
1337 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, i
);
1339 else if (code
== REG
)
1341 int regnum
= REGNO (op
);
1342 if ((c
== 'H' && !WORDS_BIG_ENDIAN
)
1343 || (c
== 'L' && WORDS_BIG_ENDIAN
))
1345 fprintf (file
, "%s", reg_names
[regnum
]);
1352 score3_print_operand_address (file
, op
);
1355 output_addr_const (file
, op
);
1360 /* Implement PRINT_OPERAND_ADDRESS macro. */
1362 score3_print_operand_address (FILE *file
, rtx x
)
1364 struct score3_address_info addr
;
1365 enum rtx_code code
= GET_CODE (x
);
1366 enum machine_mode mode
= GET_MODE (x
);
1371 if (score3_classify_address (&addr
, mode
, x
, true))
1375 case SCORE3_ADD_REG
:
1380 fprintf (file
, "[%s,-%ld]+", reg_names
[REGNO (addr
.reg
)],
1381 INTVAL (addr
.offset
));
1384 fprintf (file
, "[%s]+,-%ld", reg_names
[REGNO (addr
.reg
)],
1385 INTVAL (addr
.offset
));
1388 fprintf (file
, "[%s, %ld]+", reg_names
[REGNO (addr
.reg
)],
1389 INTVAL (addr
.offset
));
1392 fprintf (file
, "[%s]+, %ld", reg_names
[REGNO (addr
.reg
)],
1393 INTVAL (addr
.offset
));
1396 if (INTVAL(addr
.offset
) == 0)
1397 fprintf(file
, "[%s]", reg_names
[REGNO (addr
.reg
)]);
1399 fprintf(file
, "[%s, %ld]", reg_names
[REGNO (addr
.reg
)],
1400 INTVAL(addr
.offset
));
1405 case SCORE3_ADD_CONST_INT
:
1406 case SCORE3_ADD_SYMBOLIC
:
1407 output_addr_const (file
, x
);
1411 print_rtl (stderr
, x
);
1415 /* Implement SELECT_CC_MODE macro. */
1417 score3_select_cc_mode (enum rtx_code op
, rtx x
, rtx y
)
1419 if ((op
== EQ
|| op
== NE
|| op
== LT
|| op
== GE
)
1421 && GET_MODE (x
) == SImode
)
1423 switch (GET_CODE (x
))
1441 return (op
== LT
|| op
== GE
) ? CC_Nmode
: CCmode
;
1448 if ((op
== EQ
|| op
== NE
)
1449 && (GET_CODE (y
) == NEG
)
1450 && register_operand (XEXP (y
, 0), SImode
)
1451 && register_operand (x
, SImode
))
1459 #define EMIT_PL(_rtx) RTX_FRAME_RELATED_P (_rtx) = 1
1460 /* return 0, no more bit set in mask. */
1461 static int rpush_first (int mask
, int sb
, int *rd
)
1465 if ((mask
& (1 << sb
)) == 0)
1470 for (i
= sb
-1; i
>= 0; i
--)
1472 if (mask
& (1 << i
))
1486 rpush (int rd
, int cnt
)
1488 rtx mem
= gen_rtx_MEM (SImode
, gen_rtx_PRE_DEC (SImode
, stack_pointer_rtx
));
1489 rtx reg
= gen_rtx_REG (SImode
, rd
);
1491 if (!crtl
->calls_eh_return
)
1492 MEM_READONLY_P (mem
) = 1;
1495 EMIT_PL (emit_insn (gen_pushsi_score3 (mem
, reg
)));
1499 rtx insn
= gen_store_multiple (gen_rtx_MEM (SImode
, stack_pointer_rtx
),
1500 gen_rtx_REG (SImode
, rd
),
1503 rtx pat
= PATTERN (insn
);
1505 for (i
= 0; i
< XVECLEN (pat
, 0); i
++)
1506 if (GET_CODE (XVECEXP (pat
, 0, i
)) == SET
)
1507 RTX_FRAME_RELATED_P (XVECEXP (pat
, 0, i
)) = 1;
1509 EMIT_PL (emit_insn (insn
));
1513 /* Generate the prologue instructions for entry into a S+core function. */
1515 score3_prologue (void)
1517 struct score3_frame_info
*f
= score3_compute_frame_size (get_frame_size ());
1521 size
= f
->total_size
- f
->gp_reg_size
;
1524 emit_insn (gen_cpload_score3 ());
1529 for (regno
= (int) GP_REG_LAST
; regno
>= (int) GP_REG_FIRST
; regno
--)
1531 cnt
= rpush_first (f
->mask
, regno
, &rd
);
1535 regno
= regno
- cnt
;
1544 if (CONST_OK_FOR_LETTER_P (-size
, 'L'))
1545 EMIT_PL (emit_insn (gen_add3_insn (stack_pointer_rtx
,
1550 EMIT_PL (emit_move_insn (gen_rtx_REG (Pmode
, SCORE3_PROLOGUE_TEMP_REGNUM
),
1553 (gen_sub3_insn (stack_pointer_rtx
,
1556 SCORE3_PROLOGUE_TEMP_REGNUM
))));
1558 insn
= get_last_insn ();
1560 alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR
,
1561 gen_rtx_SET (VOIDmode
, stack_pointer_rtx
,
1562 plus_constant (stack_pointer_rtx
,
1567 if (frame_pointer_needed
)
1568 EMIT_PL (emit_move_insn (hard_frame_pointer_rtx
, stack_pointer_rtx
));
1570 if (flag_pic
&& f
->cprestore_size
)
1572 if (frame_pointer_needed
)
1573 emit_insn (gen_cprestore_use_fp_score3 (GEN_INT (size
- f
->cprestore_size
)));
1575 emit_insn (gen_cprestore_use_sp_score3 (GEN_INT (size
- f
->cprestore_size
)));
1579 /* return 0, no more bit set in mask. */
1581 rpop_first (int mask
, int sb
, int *rd
)
1585 if ((mask
& (1 << sb
)) == 0)
1590 for (i
= sb
+1; i
< 32; i
++)
1591 if (mask
& (1 << i
))
1600 rpop (int rd
, int cnt
)
1602 rtx mem
= gen_rtx_MEM (SImode
, gen_rtx_POST_INC (SImode
, stack_pointer_rtx
));
1603 rtx reg
= gen_rtx_REG (SImode
, rd
);
1605 if (!crtl
->calls_eh_return
)
1606 MEM_READONLY_P (mem
) = 1;
1609 emit_insn (gen_popsi_score3 (reg
, mem
));
1611 emit_insn (gen_load_multiple (reg
,
1612 gen_rtx_MEM (SImode
, stack_pointer_rtx
),
1616 /* Generate the epilogue instructions in a S+core function. */
1618 score3_epilogue (int sibcall_p
)
1620 struct score3_frame_info
*f
= score3_compute_frame_size (get_frame_size ());
1625 size
= f
->total_size
- f
->gp_reg_size
;
1627 if (!frame_pointer_needed
)
1628 base
= stack_pointer_rtx
;
1630 base
= hard_frame_pointer_rtx
;
1634 if (CONST_OK_FOR_LETTER_P (size
, 'L'))
1635 emit_insn (gen_add3_insn (base
, base
, GEN_INT (size
)));
1638 emit_move_insn (gen_rtx_REG (Pmode
, SCORE3_EPILOGUE_TEMP_REGNUM
),
1640 emit_insn (gen_add3_insn (base
, base
,
1642 SCORE3_EPILOGUE_TEMP_REGNUM
)));
1646 if (base
!= stack_pointer_rtx
)
1647 emit_move_insn (stack_pointer_rtx
, base
);
1649 if (crtl
->calls_eh_return
)
1650 emit_insn (gen_add3_insn (stack_pointer_rtx
,
1652 EH_RETURN_STACKADJ_RTX
));
1657 for (regno
= (int) GP_REG_FIRST
; regno
<= (int) GP_REG_LAST
; regno
++)
1659 cnt
= rpop_first (f
->mask
, regno
, &rd
);
1663 regno
= regno
+ cnt
;
1669 emit_jump_insn (gen_return_internal_score3 (gen_rtx_REG (Pmode
, RA_REGNUM
)));
1672 /* Return true if X is a symbolic constant that can be calculated in
1673 the same way as a bare symbol. If it is, store the type of the
1674 symbol in *SYMBOL_TYPE. */
1676 score3_symbolic_constant_p (rtx x
, enum score_symbol_type
*symbol_type
)
1678 HOST_WIDE_INT offset
;
1680 score3_split_const (x
, &x
, &offset
);
1681 if (GET_CODE (x
) == SYMBOL_REF
|| GET_CODE (x
) == LABEL_REF
)
1682 *symbol_type
= score3_classify_symbol (x
);
1689 /* if offset > 15bit, must reload */
1690 if (!IMM_IN_RANGE (offset
, 15, 1))
1693 switch (*symbol_type
)
1695 case SYMBOL_GENERAL
:
1697 case SYMBOL_SMALL_DATA
:
1698 return score3_offset_within_object_p (x
, offset
);
1704 score3_movsicc (rtx
*ops
)
1706 enum machine_mode mode
;
1708 mode
= score3_select_cc_mode (GET_CODE (ops
[1]), ops
[2], ops
[3]);
1709 emit_insn (gen_rtx_SET (VOIDmode
, gen_rtx_REG (mode
, CC_REGNUM
),
1710 gen_rtx_COMPARE (mode
, XEXP (ops
[1], 0),
1711 XEXP (ops
[1], 1))));
1714 /* Call and sibcall pattern all need call this function. */
1716 score3_call (rtx
*ops
, bool sib
)
1718 rtx addr
= XEXP (ops
[0], 0);
1719 if (!call_insn_operand (addr
, VOIDmode
))
1722 addr
= gen_reg_rtx (Pmode
);
1723 gen_move_insn (addr
, oaddr
);
1727 emit_call_insn (gen_sibcall_internal_score3 (addr
, ops
[1]));
1729 emit_call_insn (gen_call_internal_score3 (addr
, ops
[1]));
1732 /* Call value and sibcall value pattern all need call this function. */
1734 score3_call_value (rtx
*ops
, bool sib
)
1736 rtx result
= ops
[0];
1737 rtx addr
= XEXP (ops
[1], 0);
1740 if (!call_insn_operand (addr
, VOIDmode
))
1743 addr
= gen_reg_rtx (Pmode
);
1744 gen_move_insn (addr
, oaddr
);
1748 emit_call_insn (gen_sibcall_value_internal_score3 (result
, addr
, arg
));
1750 emit_call_insn (gen_call_value_internal_score3 (result
, addr
, arg
));
1755 score3_movdi (rtx
*ops
)
1759 rtx dst0
= score3_subw (dst
, 0);
1760 rtx dst1
= score3_subw (dst
, 1);
1761 rtx src0
= score3_subw (src
, 0);
1762 rtx src1
= score3_subw (src
, 1);
1764 if (GET_CODE (dst0
) == REG
&& reg_overlap_mentioned_p (dst0
, src
))
1766 emit_move_insn (dst1
, src1
);
1767 emit_move_insn (dst0
, src0
);
1771 emit_move_insn (dst0
, src0
);
1772 emit_move_insn (dst1
, src1
);
1777 score3_zero_extract_andi (rtx
*ops
)
1779 if (INTVAL (ops
[1]) == 1 && const_uimm5 (ops
[2], SImode
))
1780 emit_insn (gen_zero_extract_bittst_score3 (ops
[0], ops
[2]));
1783 unsigned HOST_WIDE_INT mask
;
1784 mask
= (0xffffffffU
& ((1U << INTVAL (ops
[1])) - 1U));
1785 mask
= mask
<< INTVAL (ops
[2]);
1786 emit_insn (gen_andsi3_cmp_score3 (ops
[3], ops
[0],
1787 gen_int_mode (mask
, SImode
)));
1792 score3_rpush (rtx
*ops
)
1794 snprintf (score3_ins
, INS_BUF_SZ
, "rpush!\t%%1, %d", XVECLEN (ops
[0], 0));
1799 score3_rpop (rtx
*ops
)
1801 snprintf (score3_ins
, INS_BUF_SZ
, "rpop!\t%%1, %d", XVECLEN (ops
[0], 0));
1805 /* Output asm code for ld/sw insn. */
1807 score3_pr_addr_post (rtx
*ops
, int idata
, int iaddr
, char *ip
,
1808 enum score_mem_unit unit ATTRIBUTE_UNUSED
)
1810 struct score3_address_info ai
;
1812 gcc_assert (GET_CODE (ops
[idata
]) == REG
);
1813 gcc_assert (score3_classify_address (&ai
, SImode
, XEXP (ops
[iaddr
], 0), true));
1815 if (ai
.type
== SCORE3_ADD_REG
1817 && GET_CODE (ai
.offset
) == CONST_INT
1818 && G16_REG_P (REGNO (ops
[idata
]))
1819 && G8_REG_P (REGNO (ai
.reg
))
1820 && ((INTVAL (ai
.offset
) & 3) == 0)
1821 && (IMM_IN_RANGE (INTVAL (ai
.offset
), 7, 0)))
1823 ops
[iaddr
] = ai
.reg
;
1824 return snprintf (ip
, INS_BUF_SZ
, "!\t%%%d, [%%%d, "
1825 HOST_WIDE_INT_PRINT_DEC
"]",
1826 idata
, iaddr
, INTVAL (ai
.offset
));
1829 if (ai
.type
== SCORE3_ADD_SYMBOLIC
)
1830 return snprintf (ip
, INS_BUF_SZ
, "48\t%%%d, %%a%d", idata
, iaddr
);
1832 return snprintf (ip
, INS_BUF_SZ
, "\t%%%d, %%a%d", idata
, iaddr
);
1835 /* Output asm insn for load. */
1837 score3_linsn (rtx
*ops
, enum score_mem_unit unit
, bool sign
)
1839 const char *pre_ins
[] =
1840 {"lbu", "lhu", "lw", "??", "lb", "lh", "lw", "??"};
1843 strcpy (score3_ins
, pre_ins
[(sign
? 4 : 0) + unit
]);
1844 ip
= score3_ins
+ strlen (score3_ins
);
1846 if (unit
== SCORE_WORD
)
1847 score3_pr_addr_post (ops
, 0, 1, ip
, unit
);
1849 snprintf (ip
, INS_BUF_SZ
, "\t%%0, %%a1");
1854 /* Output asm insn for store. */
1856 score3_sinsn (rtx
*ops
, enum score_mem_unit unit
)
1858 const char *pre_ins
[] = {"sb", "sh", "sw"};
1861 strcpy (score3_ins
, pre_ins
[unit
]);
1862 ip
= score3_ins
+ strlen (score3_ins
);
1864 if (unit
== SCORE_WORD
)
1865 score3_pr_addr_post (ops
, 1, 0, ip
, unit
);
1867 snprintf (ip
, INS_BUF_SZ
, "\t%%1, %%a0");
1872 /* Output asm insn for load immediate. */
1874 score3_limm (rtx
*ops
)
1878 gcc_assert (GET_CODE (ops
[0]) == REG
);
1879 gcc_assert (GET_CODE (ops
[1]) == CONST_INT
);
1881 v
= INTVAL (ops
[1]);
1882 if (G16_REG_P (REGNO (ops
[0])) && IMM_IN_RANGE (v
, 5, 0))
1883 return "ldiu!\t%0, %c1";
1884 else if (IMM_IN_RANGE (v
, 16, 1))
1885 return "ldi\t%0, %c1";
1886 else if ((v
& 0xffff) == 0)
1887 return "ldis\t%0, %U1";
1889 return "li\t%0, %c1";
1892 /* Output asm insn for move. */
1894 score3_move (rtx
*ops
)
1896 gcc_assert (GET_CODE (ops
[0]) == REG
);
1897 gcc_assert (GET_CODE (ops
[1]) == REG
);
1899 return "mv!\t%0, %1";
1902 /* Generate add insn. */
1904 score3_select_add_imm (rtx
*ops
, bool set_cc
)
1906 HOST_WIDE_INT v
= INTVAL (ops
[2]);
1908 gcc_assert (GET_CODE (ops
[2]) == CONST_INT
);
1909 gcc_assert (REGNO (ops
[0]) == REGNO (ops
[1]));
1912 return "addi.c\t%0, %c2";
1914 if (IMM_IN_RANGE (v
, 6, 1) && G16_REG_P (REGNO (ops
[0])))
1915 return "addi!\t%0, %c2";
1917 return "addi\t%0, %c2";
1920 /* Output arith insn. */
1922 score3_select (rtx
*ops
, const char *inst_pre
, bool commu ATTRIBUTE_UNUSED
,
1923 const char *letter
, bool set_cc
)
1925 gcc_assert (GET_CODE (ops
[0]) == REG
);
1926 gcc_assert (GET_CODE (ops
[1]) == REG
);
1929 snprintf (score3_ins
, INS_BUF_SZ
, "%s.c\t%%0, %%1, %%%s2", inst_pre
, letter
);
1931 snprintf (score3_ins
, INS_BUF_SZ
, "%s\t%%0, %%1, %%%s2", inst_pre
, letter
);
1935 /* Output a Score3 casesi instruction. */
1937 score3_output_casesi (rtx
*operands
)
1939 rtx diff_vec
= PATTERN (next_real_insn (operands
[2]));
1940 gcc_assert (GET_CODE (diff_vec
) == ADDR_DIFF_VEC
);
1942 output_asm_insn ("cmpi.c\t%0, %1", operands
);
1943 output_asm_insn ("bgtu\t%3", operands
);
1944 switch (GET_MODE(diff_vec
))
1947 output_asm_insn ("ldi48\t%4, %2", operands
);
1948 output_asm_insn ("ltbb\t%4, [%4, %0]\n%2_tbb:", operands
);
1951 output_asm_insn ("ldi48\t%4, %2", operands
);
1952 output_asm_insn ("ltbh\t%4, [%4, %0]\n%2_tbb:", operands
);
1955 output_asm_insn ("ldi48\t%4, %2", operands
);
1956 output_asm_insn ("ltbw\t%4, [%4, %0]", operands
);