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 /* Define the information needed to generate branch insns. This is
58 stored from the compare operation. */
59 extern rtx cmp_op0
, cmp_op1
;
60 extern enum reg_class score_char_to_class
[256];
62 static int score3_sdata_max
;
63 static char score3_ins
[INS_BUF_SZ
+ 8];
65 /* Return true if SYMBOL is a SYMBOL_REF and OFFSET + SYMBOL points
66 to the same object as SYMBOL. */
68 score3_offset_within_object_p (rtx symbol
, HOST_WIDE_INT offset
)
70 if (GET_CODE (symbol
) != SYMBOL_REF
)
73 if (CONSTANT_POOL_ADDRESS_P (symbol
)
75 && offset
< (int)GET_MODE_SIZE (get_pool_mode (symbol
)))
78 if (SYMBOL_REF_DECL (symbol
) != 0
80 && offset
< int_size_in_bytes (TREE_TYPE (SYMBOL_REF_DECL (symbol
))))
86 /* Split X into a base and a constant offset, storing them in *BASE
87 and *OFFSET respectively. */
89 score3_split_const (rtx x
, rtx
*base
, HOST_WIDE_INT
*offset
)
93 if (GET_CODE (x
) == CONST
)
96 if (GET_CODE (x
) == PLUS
&& GET_CODE (XEXP (x
, 1)) == CONST_INT
)
98 *offset
+= INTVAL (XEXP (x
, 1));
105 /* Classify symbol X, which must be a SYMBOL_REF or a LABEL_REF. */
106 static enum score_symbol_type
107 score3_classify_symbol (rtx x
)
109 if (GET_CODE (x
) == LABEL_REF
)
110 return SYMBOL_GENERAL
;
112 gcc_assert (GET_CODE (x
) == SYMBOL_REF
);
114 if (CONSTANT_POOL_ADDRESS_P (x
))
116 if (GET_MODE_SIZE (get_pool_mode (x
)) <= SCORE3_SDATA_MAX
)
117 return SYMBOL_SMALL_DATA
;
118 return SYMBOL_GENERAL
;
120 if (SYMBOL_REF_SMALL_P (x
))
121 return SYMBOL_SMALL_DATA
;
122 return SYMBOL_GENERAL
;
125 /* Return true if the current function must save REGNO. */
127 score3_save_reg_p (unsigned int regno
)
129 /* Check call-saved registers. */
130 if (df_regs_ever_live_p (regno
) && !call_used_regs
[regno
])
133 /* We need to save the old frame pointer before setting up a new one. */
134 if (regno
== HARD_FRAME_POINTER_REGNUM
&& frame_pointer_needed
)
137 /* We need to save the incoming return address if it is ever clobbered
138 within the function. */
139 if (regno
== RA_REGNUM
&& df_regs_ever_live_p (regno
))
145 /* Return one word of double-word value OP, taking into account the fixed
146 endianness of certain registers. HIGH_P is true to select the high part,
147 false to select the low part. */
149 score3_subw (rtx op
, int high_p
)
152 enum machine_mode mode
= GET_MODE (op
);
154 if (mode
== VOIDmode
)
157 byte
= (TARGET_LITTLE_ENDIAN
? high_p
: !high_p
) ? UNITS_PER_WORD
: 0;
159 if (GET_CODE (op
) == REG
&& REGNO (op
) == HI_REGNUM
)
160 return gen_rtx_REG (SImode
, high_p
? HI_REGNUM
: LO_REGNUM
);
162 if (GET_CODE (op
) == MEM
)
163 return adjust_address (op
, SImode
, byte
);
165 return simplify_gen_subreg (SImode
, op
, mode
, byte
);
168 static struct score3_frame_info
*
169 score3_cached_frame (void)
171 static struct score3_frame_info _frame_info
;
175 /* Return the bytes needed to compute the frame pointer from the current
176 stack pointer. SIZE is the size (in bytes) of the local variables. */
177 static struct score3_frame_info
*
178 score3_compute_frame_size (HOST_WIDE_INT size
)
181 struct score3_frame_info
*f
= score3_cached_frame ();
183 memset (f
, 0, sizeof (struct score3_frame_info
));
186 f
->var_size
= SCORE3_STACK_ALIGN (size
);
187 f
->args_size
= crtl
->outgoing_args_size
;
188 f
->cprestore_size
= flag_pic
? UNITS_PER_WORD
: 0;
190 if (f
->var_size
== 0 && current_function_is_leaf
)
191 f
->args_size
= f
->cprestore_size
= 0;
193 if (f
->args_size
== 0 && cfun
->calls_alloca
)
194 f
->args_size
= UNITS_PER_WORD
;
196 f
->total_size
= f
->var_size
+ f
->args_size
+ f
->cprestore_size
;
197 for (regno
= GP_REG_FIRST
; regno
<= GP_REG_LAST
; regno
++)
199 if (score3_save_reg_p (regno
))
201 f
->gp_reg_size
+= GET_MODE_SIZE (SImode
);
202 f
->mask
|= 1 << (regno
- GP_REG_FIRST
);
206 if (crtl
->calls_eh_return
)
211 regno
= EH_RETURN_DATA_REGNO (i
);
212 if (regno
== INVALID_REGNUM
)
214 f
->gp_reg_size
+= GET_MODE_SIZE (SImode
);
215 f
->mask
|= 1 << (regno
- GP_REG_FIRST
);
219 f
->total_size
+= f
->gp_reg_size
;
220 f
->num_gp
= f
->gp_reg_size
/ UNITS_PER_WORD
;
224 HOST_WIDE_INT offset
;
225 offset
= (f
->args_size
+ f
->cprestore_size
+ f
->var_size
226 + f
->gp_reg_size
- GET_MODE_SIZE (SImode
));
227 f
->gp_sp_offset
= offset
;
235 /* Return true if X is a valid base register for the given mode.
236 Allow only hard registers if STRICT. */
238 score3_valid_base_register_p (rtx x
, int strict
)
240 if (!strict
&& GET_CODE (x
) == SUBREG
)
243 return (GET_CODE (x
) == REG
244 && score3_regno_mode_ok_for_base_p (REGNO (x
), strict
));
247 /* Return true if X is a valid address for machine mode MODE. If it is,
248 fill in INFO appropriately. STRICT is true if we should only accept
249 hard base registers. */
251 score3_classify_address (struct score3_address_info
*info
,
252 enum machine_mode mode
, rtx x
, int strict
)
254 info
->code
= GET_CODE (x
);
260 info
->type
= SCORE3_ADD_REG
;
262 info
->offset
= const0_rtx
;
263 return score3_valid_base_register_p (info
->reg
, strict
);
265 info
->type
= SCORE3_ADD_REG
;
266 info
->reg
= XEXP (x
, 0);
267 info
->offset
= XEXP (x
, 1);
268 return (score3_valid_base_register_p (info
->reg
, strict
)
269 && GET_CODE (info
->offset
) == CONST_INT
270 && IMM_IN_RANGE (INTVAL (info
->offset
), 15, 1));
275 if (GET_MODE_SIZE (mode
) > GET_MODE_SIZE (SImode
))
277 info
->type
= SCORE3_ADD_REG
;
278 info
->reg
= XEXP (x
, 0);
279 info
->offset
= GEN_INT (GET_MODE_SIZE (mode
));
280 return score3_valid_base_register_p (info
->reg
, strict
);
282 info
->type
= SCORE3_ADD_CONST_INT
;
287 info
->type
= SCORE3_ADD_SYMBOLIC
;
288 return (score3_symbolic_constant_p (x
, &info
->symbol_type
)
289 && (info
->symbol_type
== SYMBOL_GENERAL
290 || info
->symbol_type
== SYMBOL_SMALL_DATA
));
297 score3_return_in_memory (tree type
, tree fndecl ATTRIBUTE_UNUSED
)
299 return ((TYPE_MODE (type
) == BLKmode
)
300 || (int_size_in_bytes (type
) > 2 * UNITS_PER_WORD
)
301 || (int_size_in_bytes (type
) == -1));
304 /* Return a legitimate address for REG + OFFSET. */
306 score3_add_offset (rtx reg
, HOST_WIDE_INT offset
)
308 if (!IMM_IN_RANGE (offset
, 15, 1))
310 reg
= expand_simple_binop (GET_MODE (reg
), PLUS
,
311 gen_int_mode (offset
& 0xffffc000,
313 reg
, NULL
, 0, OPTAB_WIDEN
);
317 return plus_constant (reg
, offset
);
320 /* Implement TARGET_ASM_OUTPUT_MI_THUNK. Generate rtl rather than asm text
321 in order to avoid duplicating too much logic from elsewhere. */
323 score3_output_mi_thunk (FILE *file
, tree thunk_fndecl ATTRIBUTE_UNUSED
,
324 HOST_WIDE_INT delta
, HOST_WIDE_INT vcall_offset
,
327 rtx this_rtx
, temp1
, insn
, fnaddr
;
329 /* Pretend to be a post-reload pass while generating rtl. */
330 reload_completed
= 1;
332 /* Mark the end of the (empty) prologue. */
333 emit_note (NOTE_INSN_PROLOGUE_END
);
335 /* We need two temporary registers in some cases. */
336 temp1
= gen_rtx_REG (Pmode
, 8);
338 /* Find out which register contains the "this" pointer. */
339 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function
)), function
))
340 this_rtx
= gen_rtx_REG (Pmode
, ARG_REG_FIRST
+ 1);
342 this_rtx
= gen_rtx_REG (Pmode
, ARG_REG_FIRST
);
344 /* Add DELTA to THIS_RTX. */
347 rtx offset
= GEN_INT (delta
);
348 if (!CONST_OK_FOR_LETTER_P (delta
, 'L'))
350 emit_move_insn (temp1
, offset
);
353 emit_insn (gen_add3_insn (this_rtx
, this_rtx
, offset
));
356 /* If needed, add *(*THIS_RTX + VCALL_OFFSET) to THIS_RTX. */
357 if (vcall_offset
!= 0)
361 /* Set TEMP1 to *THIS_RTX. */
362 emit_move_insn (temp1
, gen_rtx_MEM (Pmode
, this_rtx
));
364 /* Set ADDR to a legitimate address for *THIS_RTX + VCALL_OFFSET. */
365 addr
= score3_add_offset (temp1
, vcall_offset
);
367 /* Load the offset and add it to THIS_RTX. */
368 emit_move_insn (temp1
, gen_rtx_MEM (Pmode
, addr
));
369 emit_insn (gen_add3_insn (this_rtx
, this_rtx
, temp1
));
372 /* Jump to the target function. */
373 fnaddr
= XEXP (DECL_RTL (function
), 0);
374 insn
= emit_call_insn (gen_sibcall_internal_score3 (fnaddr
, const0_rtx
));
375 SIBLING_CALL_P (insn
) = 1;
377 /* Run just enough of rest_of_compilation. This sequence was
378 "borrowed" from alpha.c. */
380 insn_locators_alloc ();
381 split_all_insns_noflow ();
382 shorten_branches (insn
);
383 final_start_function (insn
, file
, 1);
384 final (insn
, file
, 1);
385 final_end_function ();
386 free_after_compilation (cfun
);
388 /* Clean up the vars set above. Note that final_end_function resets
389 the global pointer for us. */
390 reload_completed
= 0;
393 /* Copy VALUE to a register and return that register. If new psuedos
394 are allowed, copy it into a new register, otherwise use DEST. */
396 score3_force_temporary (rtx dest
, rtx value
)
398 if (can_create_pseudo_p ())
399 return force_reg (Pmode
, value
);
402 emit_move_insn (copy_rtx (dest
), value
);
407 /* Return a LO_SUM expression for ADDR. TEMP is as for score_force_temporary
408 and is used to load the high part into a register. */
410 score3_split_symbol (rtx temp
, rtx addr
)
412 rtx high
= score3_force_temporary (temp
,
413 gen_rtx_HIGH (Pmode
, copy_rtx (addr
)));
414 return gen_rtx_LO_SUM (Pmode
, high
, addr
);
417 /* This function is used to implement LEGITIMIZE_ADDRESS. If *XLOC can
418 be legitimized in a way that the generic machinery might not expect,
419 put the new address in *XLOC and return true. */
421 score3_legitimize_address (rtx
*xloc
)
423 enum score_symbol_type symbol_type
;
425 if (score3_symbolic_constant_p (*xloc
, &symbol_type
)
426 && symbol_type
== SYMBOL_GENERAL
)
428 *xloc
= score3_split_symbol (0, *xloc
);
432 if (GET_CODE (*xloc
) == PLUS
433 && GET_CODE (XEXP (*xloc
, 1)) == CONST_INT
)
435 rtx reg
= XEXP (*xloc
, 0);
436 if (!score3_valid_base_register_p (reg
, 0))
437 reg
= copy_to_mode_reg (Pmode
, reg
);
438 *xloc
= score3_add_offset (reg
, INTVAL (XEXP (*xloc
, 1)));
444 /* Fill INFO with information about a single argument. CUM is the
445 cumulative state for earlier arguments. MODE is the mode of this
446 argument and TYPE is its type (if known). NAMED is true if this
447 is a named (fixed) argument rather than a variable one. */
449 score3_classify_arg (const CUMULATIVE_ARGS
*cum
, enum machine_mode mode
,
450 tree type
, int named
, struct score3_arg_info
*info
)
453 unsigned int num_words
, max_regs
;
456 if (GET_MODE_CLASS (mode
) == MODE_INT
457 || GET_MODE_CLASS (mode
) == MODE_FLOAT
)
458 even_reg_p
= (GET_MODE_SIZE (mode
) > UNITS_PER_WORD
);
460 if (type
!= NULL_TREE
&& TYPE_ALIGN (type
) > BITS_PER_WORD
&& named
)
463 if (TARGET_MUST_PASS_IN_STACK (mode
, type
))
464 info
->reg_offset
= ARG_REG_NUM
;
467 info
->reg_offset
= cum
->num_gprs
;
469 info
->reg_offset
+= info
->reg_offset
& 1;
473 info
->num_bytes
= int_size_in_bytes (type
);
475 info
->num_bytes
= GET_MODE_SIZE (mode
);
477 num_words
= (info
->num_bytes
+ UNITS_PER_WORD
- 1) / UNITS_PER_WORD
;
478 max_regs
= ARG_REG_NUM
- info
->reg_offset
;
480 /* Partition the argument between registers and stack. */
481 info
->reg_words
= MIN (num_words
, max_regs
);
482 info
->stack_words
= num_words
- info
->reg_words
;
484 /* The alignment applied to registers is also applied to stack arguments. */
485 if (info
->stack_words
)
487 info
->stack_offset
= cum
->stack_words
;
489 info
->stack_offset
+= info
->stack_offset
& 1;
493 /* Set up the stack and frame (if desired) for the function. */
495 score3_function_prologue (FILE *file
, HOST_WIDE_INT size ATTRIBUTE_UNUSED
)
498 struct score3_frame_info
*f
= score3_cached_frame ();
499 HOST_WIDE_INT tsize
= f
->total_size
;
501 fnname
= XSTR (XEXP (DECL_RTL (current_function_decl
), 0), 0);
502 if (!flag_inhibit_size_directive
)
504 fputs ("\t.ent\t", file
);
505 assemble_name (file
, fnname
);
508 assemble_name (file
, fnname
);
511 if (!flag_inhibit_size_directive
)
514 "\t.frame\t%s," HOST_WIDE_INT_PRINT_DEC
",%s, %d\t\t"
515 "# vars= " HOST_WIDE_INT_PRINT_DEC
", regs= %d"
516 ", args= " HOST_WIDE_INT_PRINT_DEC
517 ", gp= " HOST_WIDE_INT_PRINT_DEC
"\n",
518 (reg_names
[(frame_pointer_needed
)
519 ? HARD_FRAME_POINTER_REGNUM
: STACK_POINTER_REGNUM
]),
521 reg_names
[RA_REGNUM
],
522 current_function_is_leaf
? 1 : 0,
528 fprintf(file
, "\t.mask\t0x%08x," HOST_WIDE_INT_PRINT_DEC
"\n",
530 (f
->gp_sp_offset
- f
->total_size
));
534 /* Do any necessary cleanup after a function to restore stack, frame,
537 score3_function_epilogue (FILE *file
,
538 HOST_WIDE_INT size ATTRIBUTE_UNUSED
)
540 if (!flag_inhibit_size_directive
)
543 fnname
= XSTR (XEXP (DECL_RTL (current_function_decl
), 0), 0);
544 fputs ("\t.end\t", file
);
545 assemble_name (file
, fnname
);
550 /* Returns true if X contains a SYMBOL_REF. */
552 score3_symbolic_expression_p (rtx x
)
554 if (GET_CODE (x
) == SYMBOL_REF
)
557 if (GET_CODE (x
) == CONST
)
558 return score3_symbolic_expression_p (XEXP (x
, 0));
561 return score3_symbolic_expression_p (XEXP (x
, 0));
563 if (ARITHMETIC_P (x
))
564 return (score3_symbolic_expression_p (XEXP (x
, 0))
565 || score3_symbolic_expression_p (XEXP (x
, 1)));
570 /* Choose the section to use for the constant rtx expression X that has
573 score3_select_rtx_section (enum machine_mode mode
, rtx x
,
574 unsigned HOST_WIDE_INT align
)
576 if (GET_MODE_SIZE (mode
) <= SCORE3_SDATA_MAX
)
577 return get_named_section (0, ".sdata", 0);
578 else if (flag_pic
&& score3_symbolic_expression_p (x
))
579 return get_named_section (0, ".data.rel.ro", 3);
581 return mergeable_constant_section (mode
, align
, 0);
584 /* Implement TARGET_IN_SMALL_DATA_P. */
586 score3_in_small_data_p (tree decl
)
590 if (TREE_CODE (decl
) == STRING_CST
591 || TREE_CODE (decl
) == FUNCTION_DECL
)
594 if (TREE_CODE (decl
) == VAR_DECL
&& DECL_SECTION_NAME (decl
) != 0)
597 name
= TREE_STRING_POINTER (DECL_SECTION_NAME (decl
));
598 if (strcmp (name
, ".sdata") != 0
599 && strcmp (name
, ".sbss") != 0)
601 if (!DECL_EXTERNAL (decl
))
604 size
= int_size_in_bytes (TREE_TYPE (decl
));
605 return (size
> 0 && size
<= SCORE3_SDATA_MAX
);
608 /* Implement TARGET_ASM_FILE_START. */
610 score3_asm_file_start (void)
612 default_file_start ();
613 fprintf (asm_out_file
, ASM_COMMENT_START
614 "GCC for S+core %s \n", SCORE_GCC_VERSION
);
617 fprintf (asm_out_file
, "\t.set pic\n");
620 /* Implement TARGET_ASM_FILE_END. When using assembler macros, emit
621 .externs for any small-data variables that turned out to be external. */
623 score3_asm_file_end (void)
626 struct extern_list
*p
;
629 fputs ("\n", asm_out_file
);
630 for (p
= extern_head
; p
!= 0; p
= p
->next
)
632 name_tree
= get_identifier (p
->name
);
633 if (!TREE_ASM_WRITTEN (name_tree
)
634 && TREE_SYMBOL_REFERENCED (name_tree
))
636 TREE_ASM_WRITTEN (name_tree
) = 1;
637 fputs ("\t.extern\t", asm_out_file
);
638 assemble_name (asm_out_file
, p
->name
);
639 fprintf (asm_out_file
, ", %d\n", p
->size
);
645 /* Implement OVERRIDE_OPTIONS macro. */
647 score3_override_options (void)
651 score3_sdata_max
= g_switch_set
? g_switch_value
: SCORE3_DEFAULT_SDATA_MAX
;
654 score3_sdata_max
= 0;
655 if (g_switch_set
&& (g_switch_value
!= 0))
656 warning (0, "-fPIC and -G are incompatible");
659 score_char_to_class
['d'] = G32_REGS
;
660 score_char_to_class
['e'] = G16_REGS
;
661 score_char_to_class
['t'] = T32_REGS
;
663 score_char_to_class
['h'] = HI_REG
;
664 score_char_to_class
['l'] = LO_REG
;
665 score_char_to_class
['x'] = CE_REGS
;
667 score_char_to_class
['q'] = CN_REG
;
668 score_char_to_class
['y'] = LC_REG
;
669 score_char_to_class
['z'] = SC_REG
;
670 score_char_to_class
['a'] = SP_REGS
;
672 score_char_to_class
['c'] = CR_REGS
;
675 /* Implement REGNO_REG_CLASS macro. */
677 score3_reg_class (int regno
)
680 gcc_assert (regno
>= 0 && regno
< FIRST_PSEUDO_REGISTER
);
682 if (regno
== FRAME_POINTER_REGNUM
683 || regno
== ARG_POINTER_REGNUM
)
686 for (c
= 0; c
< N_REG_CLASSES
; c
++)
687 if (TEST_HARD_REG_BIT (reg_class_contents
[c
], regno
))
693 /* Implement PREFERRED_RELOAD_CLASS macro. */
695 score3_preferred_reload_class (rtx x ATTRIBUTE_UNUSED
, enum reg_class rclass
)
697 if (reg_class_subset_p (G16_REGS
, rclass
))
699 if (reg_class_subset_p (G32_REGS
, rclass
))
704 /* Implement SECONDARY_INPUT_RELOAD_CLASS
705 and SECONDARY_OUTPUT_RELOAD_CLASS macro. */
707 score3_secondary_reload_class (enum reg_class rclass
,
708 enum machine_mode mode ATTRIBUTE_UNUSED
,
712 if (GET_CODE (x
) == REG
|| GET_CODE(x
) == SUBREG
)
713 regno
= true_regnum (x
);
715 if (!GR_REG_CLASS_P (rclass
))
716 return GP_REG_P (regno
) ? NO_REGS
: G32_REGS
;
720 /* Implement CONST_OK_FOR_LETTER_P macro. */
732 score3_const_ok_for_letter_p (HOST_WIDE_INT value
, char c
)
736 case 'I': return ((value
& 0xffff) == 0);
737 case 'J': return IMM_IN_RANGE (value
, 5, 0);
738 case 'K': return IMM_IN_RANGE (value
, 16, 0);
739 case 'L': return IMM_IN_RANGE (value
, 16, 1);
740 case 'M': return IMM_IN_RANGE (value
, 14, 0);
741 case 'N': return IMM_IN_RANGE (value
, 14, 1);
742 case 'O': return IMM_IN_RANGE (value
, 5, 1);
743 case 'P': return IMM_IN_RANGE (value
, 6, 1);
744 case 'Q': return score_extra_constraint (GEN_INT(value
), c
);
749 /* Implement EXTRA_CONSTRAINT macro. */
754 score3_extra_constraint (rtx op
, char c
)
758 case 'Q': return IMM_IN_RANGE (INTVAL(op
), 32, 0);
760 return GET_CODE (op
) == SYMBOL_REF
;
766 /* Return truth value on whether or not a given hard register
767 can support a given mode. */
769 score3_hard_regno_mode_ok (unsigned int regno
, enum machine_mode mode
)
771 int size
= GET_MODE_SIZE (mode
);
772 enum mode_class mclass
= GET_MODE_CLASS (mode
);
774 if (mclass
== MODE_CC
)
775 return regno
== CC_REGNUM
;
776 else if (regno
== FRAME_POINTER_REGNUM
777 || regno
== ARG_POINTER_REGNUM
)
778 return mclass
== MODE_INT
;
779 else if (GP_REG_P (regno
))
780 return !(regno
& 1) || (size
<= UNITS_PER_WORD
);
781 else if (CE_REG_P (regno
))
782 return (mclass
== MODE_INT
783 && ((size
<= UNITS_PER_WORD
)
784 || (regno
== CE_REG_FIRST
&& size
== 2 * UNITS_PER_WORD
)));
786 return (mclass
== MODE_INT
) && (size
<= UNITS_PER_WORD
);
789 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
790 pointer or argument pointer. TO is either the stack pointer or
791 hard frame pointer. */
793 score3_initial_elimination_offset (int from
,
794 int to ATTRIBUTE_UNUSED
)
796 struct score3_frame_info
*f
= score3_compute_frame_size (get_frame_size ());
799 case ARG_POINTER_REGNUM
:
800 return f
->total_size
;
801 case FRAME_POINTER_REGNUM
:
808 /* Implement FUNCTION_ARG_ADVANCE macro. */
810 score3_function_arg_advance (CUMULATIVE_ARGS
*cum
, enum machine_mode mode
,
811 tree type
, int named
)
813 struct score3_arg_info info
;
814 score3_classify_arg (cum
, mode
, type
, named
, &info
);
815 cum
->num_gprs
= info
.reg_offset
+ info
.reg_words
;
816 if (info
.stack_words
> 0)
817 cum
->stack_words
= info
.stack_offset
+ info
.stack_words
;
821 /* Implement TARGET_ARG_PARTIAL_BYTES macro. */
823 score3_arg_partial_bytes (CUMULATIVE_ARGS
*cum
,
824 enum machine_mode mode
, tree type
, bool named
)
826 struct score3_arg_info info
;
827 score3_classify_arg (cum
, mode
, type
, named
, &info
);
828 return info
.stack_words
> 0 ? info
.reg_words
* UNITS_PER_WORD
: 0;
831 /* Implement FUNCTION_ARG macro. */
833 score3_function_arg (const CUMULATIVE_ARGS
*cum
, enum machine_mode mode
,
834 tree type
, int named
)
836 struct score3_arg_info info
;
838 if (mode
== VOIDmode
|| !named
)
841 score3_classify_arg (cum
, mode
, type
, named
, &info
);
843 if (info
.reg_offset
== ARG_REG_NUM
)
846 if (!info
.stack_words
)
847 return gen_rtx_REG (mode
, ARG_REG_FIRST
+ info
.reg_offset
);
850 rtx ret
= gen_rtx_PARALLEL (mode
, rtvec_alloc (info
.reg_words
));
851 unsigned int i
, part_offset
= 0;
852 for (i
= 0; i
< info
.reg_words
; i
++)
855 reg
= gen_rtx_REG (SImode
, ARG_REG_FIRST
+ info
.reg_offset
+ i
);
856 XVECEXP (ret
, 0, i
) = gen_rtx_EXPR_LIST (SImode
, reg
,
857 GEN_INT (part_offset
));
858 part_offset
+= UNITS_PER_WORD
;
864 /* Implement FUNCTION_VALUE and LIBCALL_VALUE. For normal calls,
865 VALTYPE is the return type and MODE is VOIDmode. For libcalls,
866 VALTYPE is null and MODE is the mode of the return value. */
868 score3_function_value (tree valtype
, tree func ATTRIBUTE_UNUSED
,
869 enum machine_mode mode
)
874 mode
= TYPE_MODE (valtype
);
875 unsignedp
= TYPE_UNSIGNED (valtype
);
876 mode
= promote_mode (valtype
, mode
, &unsignedp
, 1);
878 return gen_rtx_REG (mode
, RT_REGNUM
);
881 /* Implement INITIALIZE_TRAMPOLINE macro. */
883 score3_initialize_trampoline (rtx ADDR
, rtx FUNC
, rtx CHAIN
)
885 #define FFCACHE "_flush_cache"
886 #define CODE_SIZE (TRAMPOLINE_INSNS * UNITS_PER_WORD)
890 pfunc
= plus_constant (ADDR
, CODE_SIZE
);
891 pchain
= plus_constant (ADDR
, CODE_SIZE
+ GET_MODE_SIZE (SImode
));
893 emit_move_insn (gen_rtx_MEM (SImode
, pfunc
), FUNC
);
894 emit_move_insn (gen_rtx_MEM (SImode
, pchain
), CHAIN
);
895 emit_library_call (gen_rtx_SYMBOL_REF (Pmode
, FFCACHE
),
898 GEN_INT (TRAMPOLINE_SIZE
), SImode
);
903 /* This function is used to implement REG_MODE_OK_FOR_BASE_P macro. */
905 score3_regno_mode_ok_for_base_p (int regno
, int strict
)
907 if (regno
>= FIRST_PSEUDO_REGISTER
)
911 regno
= reg_renumber
[regno
];
913 if (regno
== ARG_POINTER_REGNUM
914 || regno
== FRAME_POINTER_REGNUM
)
916 return GP_REG_P (regno
);
919 /* Implement GO_IF_LEGITIMATE_ADDRESS macro. */
921 score3_address_p (enum machine_mode mode
, rtx x
, int strict
)
923 struct score3_address_info addr
;
925 return score3_classify_address (&addr
, mode
, x
, strict
);
928 /* Return a number assessing the cost of moving a register in class
931 score3_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED
,
932 enum reg_class from
, enum reg_class to
)
934 if (GR_REG_CLASS_P (from
))
936 if (GR_REG_CLASS_P (to
))
938 else if (SP_REG_CLASS_P (to
))
940 else if (CP_REG_CLASS_P (to
))
942 else if (CE_REG_CLASS_P (to
))
945 if (GR_REG_CLASS_P (to
))
947 if (GR_REG_CLASS_P (from
))
949 else if (SP_REG_CLASS_P (from
))
951 else if (CP_REG_CLASS_P (from
))
953 else if (CE_REG_CLASS_P (from
))
959 /* Return the number of instructions needed to load a symbol of the
960 given type into a register. */
962 score3_symbol_insns (enum score_symbol_type type
)
969 case SYMBOL_SMALL_DATA
:
976 /* Return the number of instructions needed to load or store a value
977 of mode MODE at X. Return 0 if X isn't valid for MODE. */
979 score3_address_insns (rtx x
, enum machine_mode mode
)
981 struct score3_address_info addr
;
987 factor
= (GET_MODE_SIZE (mode
) + UNITS_PER_WORD
- 1) / UNITS_PER_WORD
;
989 if (score3_classify_address (&addr
, mode
, x
, false))
993 case SCORE3_ADD_CONST_INT
:
996 case SCORE3_ADD_SYMBOLIC
:
997 return factor
* score3_symbol_insns (addr
.symbol_type
);
1002 /* Implement TARGET_RTX_COSTS macro. */
1004 score3_rtx_costs (rtx x
, int code
, int outer_code
, int *total
,
1005 bool speed ATTRIBUTE_UNUSED
)
1007 enum machine_mode mode
= GET_MODE (x
);
1012 if (outer_code
== SET
)
1014 if (CONST_OK_FOR_LETTER_P (INTVAL (x
), 'I')
1015 || CONST_OK_FOR_LETTER_P (INTVAL (x
), 'L'))
1016 *total
= COSTS_N_INSNS (1);
1018 *total
= COSTS_N_INSNS (2);
1020 else if (outer_code
== PLUS
|| outer_code
== MINUS
)
1022 if (CONST_OK_FOR_LETTER_P (INTVAL (x
), 'N'))
1024 else if (CONST_OK_FOR_LETTER_P (INTVAL (x
), 'I')
1025 || CONST_OK_FOR_LETTER_P (INTVAL (x
), 'L'))
1028 *total
= COSTS_N_INSNS (2);
1030 else if (outer_code
== AND
|| outer_code
== IOR
)
1032 if (CONST_OK_FOR_LETTER_P (INTVAL (x
), 'M'))
1034 else if (CONST_OK_FOR_LETTER_P (INTVAL (x
), 'I')
1035 || CONST_OK_FOR_LETTER_P (INTVAL (x
), 'K'))
1038 *total
= COSTS_N_INSNS (2);
1050 *total
= COSTS_N_INSNS (2);
1055 /* If the address is legitimate, return the number of
1056 instructions it needs, otherwise use the default handling. */
1057 int n
= score3_address_insns (XEXP (x
, 0), GET_MODE (x
));
1060 *total
= COSTS_N_INSNS (n
+ 1);
1067 *total
= COSTS_N_INSNS (6);
1071 *total
= COSTS_N_INSNS (1);
1079 *total
= COSTS_N_INSNS (2);
1089 *total
= COSTS_N_INSNS ((GET_CODE (XEXP (x
, 1)) == CONST_INT
)
1096 *total
= COSTS_N_INSNS (4);
1103 *total
= COSTS_N_INSNS (4);
1106 *total
= COSTS_N_INSNS (1);
1112 *total
= COSTS_N_INSNS (4);
1118 *total
= optimize_size
? COSTS_N_INSNS (2) : COSTS_N_INSNS (12);
1125 *total
= optimize_size
? COSTS_N_INSNS (2) : COSTS_N_INSNS (33);
1130 switch (GET_MODE (XEXP (x
, 0)))
1134 if (GET_CODE (XEXP (x
, 0)) == MEM
)
1136 *total
= COSTS_N_INSNS (2);
1138 if (!TARGET_LITTLE_ENDIAN
&&
1139 side_effects_p (XEXP (XEXP (x
, 0), 0)))
1143 *total
= COSTS_N_INSNS (1);
1147 *total
= COSTS_N_INSNS (1);
1157 /* Implement TARGET_ADDRESS_COST macro. */
1159 score3_address_cost (rtx addr
)
1161 return score3_address_insns (addr
, SImode
);
1164 /* Implement ASM_OUTPUT_EXTERNAL macro. */
1166 score3_output_external (FILE *file ATTRIBUTE_UNUSED
,
1167 tree decl
, const char *name
)
1169 register struct extern_list
*p
;
1171 if (score3_in_small_data_p (decl
))
1173 p
= (struct extern_list
*) ggc_alloc (sizeof (struct extern_list
));
1174 p
->next
= extern_head
;
1176 p
->size
= int_size_in_bytes (TREE_TYPE (decl
));
1182 /* Implement RETURN_ADDR_RTX. Note, we do not support moving
1183 back to a previous frame. */
1185 score3_return_addr (int count
, rtx frame ATTRIBUTE_UNUSED
)
1189 return get_hard_reg_initial_val (Pmode
, RA_REGNUM
);
1192 /* Implement PRINT_OPERAND macro. */
1193 /* Score-specific operand codes:
1194 '[' print .set nor1 directive
1195 ']' print .set r1 directive
1196 'U' print hi part of a CONST_INT rtx
1199 'D' print SFmode const double
1200 'S' selectively print "!" if operand is 15bit instruction accessible
1201 'V' print "v!" if operand is 15bit instruction accessible, or "lfh!"
1202 'L' low part of DImode reg operand
1203 'H' high part of DImode reg operand
1204 'C' print part of opcode for a branch condition. */
1206 score3_print_operand (FILE *file
, rtx op
, int c
)
1208 enum rtx_code code
= -1;
1209 if (!PRINT_OPERAND_PUNCT_VALID_P (c
))
1210 code
= GET_CODE (op
);
1214 fprintf (file
, ".set r1\n");
1218 fprintf (file
, "\n\t.set nor1");
1222 gcc_assert (code
== CONST_INT
);
1223 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
,
1224 (INTVAL (op
) >> 16) & 0xffff);
1228 if (GET_CODE (op
) == CONST_DOUBLE
)
1230 rtx temp
= gen_lowpart (SImode
, op
);
1231 gcc_assert (GET_MODE (op
) == SFmode
);
1232 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, INTVAL (temp
) & 0xffffffff);
1235 output_addr_const (file
, op
);
1239 gcc_assert (code
== REG
);
1240 if (G16_REG_P (REGNO (op
)))
1241 fprintf (file
, "!");
1245 gcc_assert (code
== REG
);
1246 fprintf (file
, G16_REG_P (REGNO (op
)) ? "v!" : "lfh!");
1250 enum machine_mode mode
= GET_MODE (XEXP (op
, 0));
1254 case EQ
: fputs ("eq!", file
); break;
1255 case NE
: fputs ("ne!", file
); break;
1256 case GT
: fputs ("gt!", file
); break;
1257 case GE
: fputs (mode
!= CCmode
? "pl" : "ge", file
); break;
1258 case LT
: fputs (mode
!= CCmode
? "mi" : "lt", file
); break;
1259 case LE
: fputs ("le!", file
); break;
1260 case GTU
: fputs ("gtu!", file
); break;
1261 case GEU
: fputs ("cs", file
); break;
1262 case LTU
: fputs ("cc", file
); break;
1263 case LEU
: fputs ("leu!", file
); break;
1265 output_operand_lossage ("invalid operand for code: '%c'", code
);
1268 else if (c
== 'G') /* Seperate from b<cond>, use for mv<cond>. */
1270 enum machine_mode mode
= GET_MODE (XEXP (op
, 0));
1274 case EQ
: fputs ("eq", file
); break;
1275 case NE
: fputs ("ne", file
); break;
1276 case GT
: fputs ("gt", file
); break;
1277 case GE
: fputs (mode
!= CCmode
? "pl" : "ge", file
); break;
1278 case LT
: fputs (mode
!= CCmode
? "mi" : "lt", file
); break;
1279 case LE
: fputs ("le", file
); break;
1280 case GTU
: fputs ("gtu", file
); break;
1281 case GEU
: fputs ("cs", file
); break;
1282 case LTU
: fputs ("cc", file
); break;
1283 case LEU
: fputs ("leu", file
); break;
1285 output_operand_lossage ("invalid operand for code: '%c'", code
);
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
);
1306 unsigned HOST_WIDE_INT i
;
1307 unsigned HOST_WIDE_INT pow2mask
= 1;
1308 unsigned HOST_WIDE_INT val
;
1311 for (i
= 0; i
< 32; i
++)
1313 if (val
== pow2mask
)
1317 gcc_assert (i
< 32);
1318 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, i
);
1320 else if (code
== REG
)
1322 int regnum
= REGNO (op
);
1323 if ((c
== 'H' && !WORDS_BIG_ENDIAN
)
1324 || (c
== 'L' && WORDS_BIG_ENDIAN
))
1326 fprintf (file
, "%s", reg_names
[regnum
]);
1333 score3_print_operand_address (file
, op
);
1336 output_addr_const (file
, op
);
1341 /* Implement PRINT_OPERAND_ADDRESS macro. */
1343 score3_print_operand_address (FILE *file
, rtx x
)
1345 struct score3_address_info addr
;
1346 enum rtx_code code
= GET_CODE (x
);
1347 enum machine_mode mode
= GET_MODE (x
);
1352 if (score3_classify_address (&addr
, mode
, x
, true))
1356 case SCORE3_ADD_REG
:
1361 fprintf (file
, "[%s,-%ld]+", reg_names
[REGNO (addr
.reg
)],
1362 INTVAL (addr
.offset
));
1365 fprintf (file
, "[%s]+,-%ld", reg_names
[REGNO (addr
.reg
)],
1366 INTVAL (addr
.offset
));
1369 fprintf (file
, "[%s, %ld]+", reg_names
[REGNO (addr
.reg
)],
1370 INTVAL (addr
.offset
));
1373 fprintf (file
, "[%s]+, %ld", reg_names
[REGNO (addr
.reg
)],
1374 INTVAL (addr
.offset
));
1377 if (INTVAL(addr
.offset
) == 0)
1378 fprintf(file
, "[%s]", reg_names
[REGNO (addr
.reg
)]);
1380 fprintf(file
, "[%s, %ld]", reg_names
[REGNO (addr
.reg
)],
1381 INTVAL(addr
.offset
));
1386 case SCORE3_ADD_CONST_INT
:
1387 case SCORE3_ADD_SYMBOLIC
:
1388 output_addr_const (file
, x
);
1392 print_rtl (stderr
, x
);
1396 /* Implement SELECT_CC_MODE macro. */
1398 score3_select_cc_mode (enum rtx_code op
, rtx x
, rtx y
)
1400 if ((op
== EQ
|| op
== NE
|| op
== LT
|| op
== GE
)
1402 && GET_MODE (x
) == SImode
)
1404 switch (GET_CODE (x
))
1422 return (op
== LT
|| op
== GE
) ? CC_Nmode
: CCmode
;
1429 if ((op
== EQ
|| op
== NE
)
1430 && (GET_CODE (y
) == NEG
)
1431 && register_operand (XEXP (y
, 0), SImode
)
1432 && register_operand (x
, SImode
))
1440 #define EMIT_PL(_rtx) RTX_FRAME_RELATED_P (_rtx) = 1
1441 /* return 0, no more bit set in mask. */
1442 static int rpush_first (int mask
, int sb
, int *rd
)
1446 if ((mask
& (1 << sb
)) == 0)
1451 for (i
= sb
-1; i
>= 0; i
--)
1453 if (mask
& (1 << i
))
1467 rpush (int rd
, int cnt
)
1469 rtx mem
= gen_rtx_MEM (SImode
, gen_rtx_PRE_DEC (SImode
, stack_pointer_rtx
));
1470 rtx reg
= gen_rtx_REG (SImode
, rd
);
1472 if (!crtl
->calls_eh_return
)
1473 MEM_READONLY_P (mem
) = 1;
1476 EMIT_PL (emit_insn (gen_pushsi_score3 (mem
, reg
)));
1480 rtx insn
= gen_store_multiple (gen_rtx_MEM (SImode
, stack_pointer_rtx
),
1481 gen_rtx_REG (SImode
, rd
),
1484 rtx pat
= PATTERN (insn
);
1486 for (i
= 0; i
< XVECLEN (pat
, 0); i
++)
1487 if (GET_CODE (XVECEXP (pat
, 0, i
)) == SET
)
1488 RTX_FRAME_RELATED_P (XVECEXP (pat
, 0, i
)) = 1;
1490 EMIT_PL (emit_insn (insn
));
1494 /* Generate the prologue instructions for entry into a S+core function. */
1496 score3_prologue (void)
1498 struct score3_frame_info
*f
= score3_compute_frame_size (get_frame_size ());
1502 size
= f
->total_size
- f
->gp_reg_size
;
1505 emit_insn (gen_cpload_score3 ());
1510 for (regno
= (int) GP_REG_LAST
; regno
>= (int) GP_REG_FIRST
; regno
--)
1512 cnt
= rpush_first (f
->mask
, regno
, &rd
);
1516 regno
= regno
- cnt
;
1525 if (CONST_OK_FOR_LETTER_P (-size
, 'L'))
1526 EMIT_PL (emit_insn (gen_add3_insn (stack_pointer_rtx
,
1531 EMIT_PL (emit_move_insn (gen_rtx_REG (Pmode
, SCORE3_PROLOGUE_TEMP_REGNUM
),
1534 (gen_sub3_insn (stack_pointer_rtx
,
1537 SCORE3_PROLOGUE_TEMP_REGNUM
))));
1539 insn
= get_last_insn ();
1541 alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR
,
1542 gen_rtx_SET (VOIDmode
, stack_pointer_rtx
,
1543 plus_constant (stack_pointer_rtx
,
1548 if (frame_pointer_needed
)
1549 EMIT_PL (emit_move_insn (hard_frame_pointer_rtx
, stack_pointer_rtx
));
1551 if (flag_pic
&& f
->cprestore_size
)
1553 if (frame_pointer_needed
)
1554 emit_insn (gen_cprestore_use_fp_score3 (GEN_INT (size
- f
->cprestore_size
)));
1556 emit_insn (gen_cprestore_use_sp_score3 (GEN_INT (size
- f
->cprestore_size
)));
1560 /* return 0, no more bit set in mask. */
1562 rpop_first (int mask
, int sb
, int *rd
)
1566 if ((mask
& (1 << sb
)) == 0)
1571 for (i
= sb
+1; i
< 32; i
++)
1572 if (mask
& (1 << i
))
1581 rpop (int rd
, int cnt
)
1583 rtx mem
= gen_rtx_MEM (SImode
, gen_rtx_POST_INC (SImode
, stack_pointer_rtx
));
1584 rtx reg
= gen_rtx_REG (SImode
, rd
);
1586 if (!crtl
->calls_eh_return
)
1587 MEM_READONLY_P (mem
) = 1;
1590 emit_insn (gen_popsi_score3 (reg
, mem
));
1592 emit_insn (gen_load_multiple (reg
,
1593 gen_rtx_MEM (SImode
, stack_pointer_rtx
),
1597 /* Generate the epilogue instructions in a S+core function. */
1599 score3_epilogue (int sibcall_p
)
1601 struct score3_frame_info
*f
= score3_compute_frame_size (get_frame_size ());
1606 size
= f
->total_size
- f
->gp_reg_size
;
1608 if (!frame_pointer_needed
)
1609 base
= stack_pointer_rtx
;
1611 base
= hard_frame_pointer_rtx
;
1615 if (CONST_OK_FOR_LETTER_P (size
, 'L'))
1616 emit_insn (gen_add3_insn (base
, base
, GEN_INT (size
)));
1619 emit_move_insn (gen_rtx_REG (Pmode
, SCORE3_EPILOGUE_TEMP_REGNUM
),
1621 emit_insn (gen_add3_insn (base
, base
,
1623 SCORE3_EPILOGUE_TEMP_REGNUM
)));
1627 if (base
!= stack_pointer_rtx
)
1628 emit_move_insn (stack_pointer_rtx
, base
);
1630 if (crtl
->calls_eh_return
)
1631 emit_insn (gen_add3_insn (stack_pointer_rtx
,
1633 EH_RETURN_STACKADJ_RTX
));
1638 for (regno
= (int) GP_REG_FIRST
; regno
<= (int) GP_REG_LAST
; regno
++)
1640 cnt
= rpop_first (f
->mask
, regno
, &rd
);
1644 regno
= regno
+ cnt
;
1650 emit_jump_insn (gen_return_internal_score3 (gen_rtx_REG (Pmode
, RA_REGNUM
)));
1654 score3_gen_cmp (enum machine_mode mode
)
1656 emit_insn (gen_rtx_SET (VOIDmode
, gen_rtx_REG (mode
, CC_REGNUM
),
1657 gen_rtx_COMPARE (mode
, cmp_op0
, cmp_op1
)));
1660 /* Return true if X is a symbolic constant that can be calculated in
1661 the same way as a bare symbol. If it is, store the type of the
1662 symbol in *SYMBOL_TYPE. */
1664 score3_symbolic_constant_p (rtx x
, enum score_symbol_type
*symbol_type
)
1666 HOST_WIDE_INT offset
;
1668 score3_split_const (x
, &x
, &offset
);
1669 if (GET_CODE (x
) == SYMBOL_REF
|| GET_CODE (x
) == LABEL_REF
)
1670 *symbol_type
= score3_classify_symbol (x
);
1677 /* if offset > 15bit, must reload */
1678 if (!IMM_IN_RANGE (offset
, 15, 1))
1681 switch (*symbol_type
)
1683 case SYMBOL_GENERAL
:
1685 case SYMBOL_SMALL_DATA
:
1686 return score3_offset_within_object_p (x
, offset
);
1692 score3_movsicc (rtx
*ops
)
1694 enum machine_mode mode
;
1696 mode
= score3_select_cc_mode (GET_CODE (ops
[1]), ops
[2], ops
[3]);
1697 emit_insn (gen_rtx_SET (VOIDmode
, gen_rtx_REG (mode
, CC_REGNUM
),
1698 gen_rtx_COMPARE (mode
, cmp_op0
, cmp_op1
)));
1701 /* Call and sibcall pattern all need call this function. */
1703 score3_call (rtx
*ops
, bool sib
)
1705 rtx addr
= XEXP (ops
[0], 0);
1706 if (!call_insn_operand (addr
, VOIDmode
))
1709 addr
= gen_reg_rtx (Pmode
);
1710 gen_move_insn (addr
, oaddr
);
1714 emit_call_insn (gen_sibcall_internal_score3 (addr
, ops
[1]));
1716 emit_call_insn (gen_call_internal_score3 (addr
, ops
[1]));
1719 /* Call value and sibcall value pattern all need call this function. */
1721 score3_call_value (rtx
*ops
, bool sib
)
1723 rtx result
= ops
[0];
1724 rtx addr
= XEXP (ops
[1], 0);
1727 if (!call_insn_operand (addr
, VOIDmode
))
1730 addr
= gen_reg_rtx (Pmode
);
1731 gen_move_insn (addr
, oaddr
);
1735 emit_call_insn (gen_sibcall_value_internal_score3 (result
, addr
, arg
));
1737 emit_call_insn (gen_call_value_internal_score3 (result
, addr
, arg
));
1742 score3_movdi (rtx
*ops
)
1746 rtx dst0
= score3_subw (dst
, 0);
1747 rtx dst1
= score3_subw (dst
, 1);
1748 rtx src0
= score3_subw (src
, 0);
1749 rtx src1
= score3_subw (src
, 1);
1751 if (GET_CODE (dst0
) == REG
&& reg_overlap_mentioned_p (dst0
, src
))
1753 emit_move_insn (dst1
, src1
);
1754 emit_move_insn (dst0
, src0
);
1758 emit_move_insn (dst0
, src0
);
1759 emit_move_insn (dst1
, src1
);
1764 score3_zero_extract_andi (rtx
*ops
)
1766 if (INTVAL (ops
[1]) == 1 && const_uimm5 (ops
[2], SImode
))
1767 emit_insn (gen_zero_extract_bittst_score3 (ops
[0], ops
[2]));
1770 unsigned HOST_WIDE_INT mask
;
1771 mask
= (0xffffffffU
& ((1U << INTVAL (ops
[1])) - 1U));
1772 mask
= mask
<< INTVAL (ops
[2]);
1773 emit_insn (gen_andsi3_cmp_score3 (ops
[3], ops
[0],
1774 gen_int_mode (mask
, SImode
)));
1779 score3_rpush (rtx
*ops
)
1781 snprintf (score3_ins
, INS_BUF_SZ
, "rpush!\t%%1, %d", XVECLEN (ops
[0], 0));
1786 score3_rpop (rtx
*ops
)
1788 snprintf (score3_ins
, INS_BUF_SZ
, "rpop!\t%%1, %d", XVECLEN (ops
[0], 0));
1792 /* Output asm code for ld/sw insn. */
1794 score3_pr_addr_post (rtx
*ops
, int idata
, int iaddr
, char *ip
,
1795 enum score_mem_unit unit ATTRIBUTE_UNUSED
)
1797 struct score3_address_info ai
;
1799 gcc_assert (GET_CODE (ops
[idata
]) == REG
);
1800 gcc_assert (score3_classify_address (&ai
, SImode
, XEXP (ops
[iaddr
], 0), true));
1802 if (ai
.type
== SCORE3_ADD_REG
1804 && GET_CODE (ai
.offset
) == CONST_INT
1805 && G16_REG_P (REGNO (ops
[idata
]))
1806 && G8_REG_P (REGNO (ai
.reg
))
1807 && ((INTVAL (ai
.offset
) & 3) == 0)
1808 && (IMM_IN_RANGE (INTVAL (ai
.offset
), 7, 0)))
1810 ops
[iaddr
] = ai
.reg
;
1811 return snprintf (ip
, INS_BUF_SZ
, "!\t%%%d, [%%%d, "
1812 HOST_WIDE_INT_PRINT_DEC
"]",
1813 idata
, iaddr
, INTVAL (ai
.offset
));
1816 if (ai
.type
== SCORE3_ADD_SYMBOLIC
)
1817 return snprintf (ip
, INS_BUF_SZ
, "48\t%%%d, %%a%d", idata
, iaddr
);
1819 return snprintf (ip
, INS_BUF_SZ
, "\t%%%d, %%a%d", idata
, iaddr
);
1822 /* Output asm insn for load. */
1824 score3_linsn (rtx
*ops
, enum score_mem_unit unit
, bool sign
)
1826 const char *pre_ins
[] =
1827 {"lbu", "lhu", "lw", "??", "lb", "lh", "lw", "??"};
1830 strcpy (score3_ins
, pre_ins
[(sign
? 4 : 0) + unit
]);
1831 ip
= score3_ins
+ strlen (score3_ins
);
1833 if (unit
== SCORE_WORD
)
1834 score3_pr_addr_post (ops
, 0, 1, ip
, unit
);
1836 snprintf (ip
, INS_BUF_SZ
, "\t%%0, %%a1");
1841 /* Output asm insn for store. */
1843 score3_sinsn (rtx
*ops
, enum score_mem_unit unit
)
1845 const char *pre_ins
[] = {"sb", "sh", "sw"};
1848 strcpy (score3_ins
, pre_ins
[unit
]);
1849 ip
= score3_ins
+ strlen (score3_ins
);
1851 if (unit
== SCORE_WORD
)
1852 score3_pr_addr_post (ops
, 1, 0, ip
, unit
);
1854 snprintf (ip
, INS_BUF_SZ
, "\t%%1, %%a0");
1859 /* Output asm insn for load immediate. */
1861 score3_limm (rtx
*ops
)
1865 gcc_assert (GET_CODE (ops
[0]) == REG
);
1866 gcc_assert (GET_CODE (ops
[1]) == CONST_INT
);
1868 v
= INTVAL (ops
[1]);
1869 if (G16_REG_P (REGNO (ops
[0])) && IMM_IN_RANGE (v
, 5, 0))
1870 return "ldiu!\t%0, %c1";
1871 else if (IMM_IN_RANGE (v
, 16, 1))
1872 return "ldi\t%0, %c1";
1873 else if ((v
& 0xffff) == 0)
1874 return "ldis\t%0, %U1";
1876 return "li\t%0, %c1";
1879 /* Output asm insn for move. */
1881 score3_move (rtx
*ops
)
1883 gcc_assert (GET_CODE (ops
[0]) == REG
);
1884 gcc_assert (GET_CODE (ops
[1]) == REG
);
1886 return "mv!\t%0, %1";
1889 /* Generate add insn. */
1891 score3_select_add_imm (rtx
*ops
, bool set_cc
)
1893 HOST_WIDE_INT v
= INTVAL (ops
[2]);
1895 gcc_assert (GET_CODE (ops
[2]) == CONST_INT
);
1896 gcc_assert (REGNO (ops
[0]) == REGNO (ops
[1]));
1899 return "addi.c\t%0, %c2";
1901 if (IMM_IN_RANGE (v
, 6, 1) && G16_REG_P (REGNO (ops
[0])))
1902 return "addi!\t%0, %c2";
1904 return "addi\t%0, %c2";
1907 /* Output arith insn. */
1909 score3_select (rtx
*ops
, const char *inst_pre
, bool commu ATTRIBUTE_UNUSED
,
1910 const char *letter
, bool set_cc
)
1912 gcc_assert (GET_CODE (ops
[0]) == REG
);
1913 gcc_assert (GET_CODE (ops
[1]) == REG
);
1916 snprintf (score3_ins
, INS_BUF_SZ
, "%s.c\t%%0, %%1, %%%s2", inst_pre
, letter
);
1918 snprintf (score3_ins
, INS_BUF_SZ
, "%s\t%%0, %%1, %%%s2", inst_pre
, letter
);
1922 /* Output a Score3 casesi instruction. */
1924 score3_output_casesi (rtx
*operands
)
1926 rtx diff_vec
= PATTERN (next_real_insn (operands
[2]));
1927 gcc_assert (GET_CODE (diff_vec
) == ADDR_DIFF_VEC
);
1929 output_asm_insn ("cmpi.c\t%0, %1", operands
);
1930 output_asm_insn ("bgtu\t%3", operands
);
1931 switch (GET_MODE(diff_vec
))
1934 output_asm_insn ("ldi48\t%4, %2", operands
);
1935 output_asm_insn ("ltbb\t%4, [%4, %0]\n%2_tbb:", operands
);
1938 output_asm_insn ("ldi48\t%4, %2", operands
);
1939 output_asm_insn ("ltbh\t%4, [%4, %0]\n%2_tbb:", operands
);
1942 output_asm_insn ("ldi48\t%4, %2", operands
);
1943 output_asm_insn ("ltbw\t%4, [%4, %0]", operands
);