1 /* score3.c for Sunplus S+CORE processor
2 Copyright (C) 2005, 2007 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"
53 #define BITSET_P(VALUE, BIT) (((VALUE) & (1L << (BIT))) != 0)
54 #define INS_BUF_SZ 128
56 /* Define the information needed to generate branch insns. This is
57 stored from the compare operation. */
58 extern rtx cmp_op0
, cmp_op1
;
59 extern enum reg_class score_char_to_class
[256];
61 static int score3_sdata_max
;
62 static char score3_ins
[INS_BUF_SZ
+ 8];
64 /* Return true if SYMBOL is a SYMBOL_REF and OFFSET + SYMBOL points
65 to the same object as SYMBOL. */
67 score3_offset_within_object_p (rtx symbol
, HOST_WIDE_INT offset
)
69 if (GET_CODE (symbol
) != SYMBOL_REF
)
72 if (CONSTANT_POOL_ADDRESS_P (symbol
)
74 && offset
< (int)GET_MODE_SIZE (get_pool_mode (symbol
)))
77 if (SYMBOL_REF_DECL (symbol
) != 0
79 && offset
< int_size_in_bytes (TREE_TYPE (SYMBOL_REF_DECL (symbol
))))
85 /* Split X into a base and a constant offset, storing them in *BASE
86 and *OFFSET respectively. */
88 score3_split_const (rtx x
, rtx
*base
, HOST_WIDE_INT
*offset
)
92 if (GET_CODE (x
) == CONST
)
95 if (GET_CODE (x
) == PLUS
&& GET_CODE (XEXP (x
, 1)) == CONST_INT
)
97 *offset
+= INTVAL (XEXP (x
, 1));
104 /* Classify symbol X, which must be a SYMBOL_REF or a LABEL_REF. */
105 static enum score_symbol_type
106 score3_classify_symbol (rtx x
)
108 if (GET_CODE (x
) == LABEL_REF
)
109 return SYMBOL_GENERAL
;
111 gcc_assert (GET_CODE (x
) == SYMBOL_REF
);
113 if (CONSTANT_POOL_ADDRESS_P (x
))
115 if (GET_MODE_SIZE (get_pool_mode (x
)) <= SCORE3_SDATA_MAX
)
116 return SYMBOL_SMALL_DATA
;
117 return SYMBOL_GENERAL
;
119 if (SYMBOL_REF_SMALL_P (x
))
120 return SYMBOL_SMALL_DATA
;
121 return SYMBOL_GENERAL
;
124 /* Return true if the current function must save REGNO. */
126 score3_save_reg_p (unsigned int regno
)
128 /* Check call-saved registers. */
129 if (df_regs_ever_live_p (regno
) && !call_used_regs
[regno
])
132 /* We need to save the old frame pointer before setting up a new one. */
133 if (regno
== HARD_FRAME_POINTER_REGNUM
&& frame_pointer_needed
)
136 /* We need to save the incoming return address if it is ever clobbered
137 within the function. */
138 if (regno
== RA_REGNUM
&& df_regs_ever_live_p (regno
))
144 /* Return one word of double-word value OP, taking into account the fixed
145 endianness of certain registers. HIGH_P is true to select the high part,
146 false to select the low part. */
148 score3_subw (rtx op
, int high_p
)
151 enum machine_mode mode
= GET_MODE (op
);
153 if (mode
== VOIDmode
)
156 byte
= (TARGET_LITTLE_ENDIAN
? high_p
: !high_p
) ? UNITS_PER_WORD
: 0;
158 if (GET_CODE (op
) == REG
&& REGNO (op
) == HI_REGNUM
)
159 return gen_rtx_REG (SImode
, high_p
? HI_REGNUM
: LO_REGNUM
);
161 if (GET_CODE (op
) == MEM
)
162 return adjust_address (op
, SImode
, byte
);
164 return simplify_gen_subreg (SImode
, op
, mode
, byte
);
167 static struct score3_frame_info
*
168 score3_cached_frame (void)
170 static struct score3_frame_info _frame_info
;
174 /* Return the bytes needed to compute the frame pointer from the current
175 stack pointer. SIZE is the size (in bytes) of the local variables. */
176 static struct score3_frame_info
*
177 score3_compute_frame_size (HOST_WIDE_INT size
)
180 struct score3_frame_info
*f
= score3_cached_frame ();
182 memset (f
, 0, sizeof (struct score3_frame_info
));
185 f
->var_size
= SCORE3_STACK_ALIGN (size
);
186 f
->args_size
= crtl
->outgoing_args_size
;
187 f
->cprestore_size
= flag_pic
? UNITS_PER_WORD
: 0;
189 if (f
->var_size
== 0 && current_function_is_leaf
)
190 f
->args_size
= f
->cprestore_size
= 0;
192 if (f
->args_size
== 0 && cfun
->calls_alloca
)
193 f
->args_size
= UNITS_PER_WORD
;
195 f
->total_size
= f
->var_size
+ f
->args_size
+ f
->cprestore_size
;
196 for (regno
= GP_REG_FIRST
; regno
<= GP_REG_LAST
; regno
++)
198 if (score3_save_reg_p (regno
))
200 f
->gp_reg_size
+= GET_MODE_SIZE (SImode
);
201 f
->mask
|= 1 << (regno
- GP_REG_FIRST
);
205 if (crtl
->calls_eh_return
)
210 regno
= EH_RETURN_DATA_REGNO (i
);
211 if (regno
== INVALID_REGNUM
)
213 f
->gp_reg_size
+= GET_MODE_SIZE (SImode
);
214 f
->mask
|= 1 << (regno
- GP_REG_FIRST
);
218 f
->total_size
+= f
->gp_reg_size
;
219 f
->num_gp
= f
->gp_reg_size
/ UNITS_PER_WORD
;
223 HOST_WIDE_INT offset
;
224 offset
= (f
->args_size
+ f
->cprestore_size
+ f
->var_size
225 + f
->gp_reg_size
- GET_MODE_SIZE (SImode
));
226 f
->gp_sp_offset
= offset
;
234 /* Return true if X is a valid base register for the given mode.
235 Allow only hard registers if STRICT. */
237 score3_valid_base_register_p (rtx x
, int strict
)
239 if (!strict
&& GET_CODE (x
) == SUBREG
)
242 return (GET_CODE (x
) == REG
243 && score3_regno_mode_ok_for_base_p (REGNO (x
), strict
));
246 /* Return true if X is a valid address for machine mode MODE. If it is,
247 fill in INFO appropriately. STRICT is true if we should only accept
248 hard base registers. */
250 score3_classify_address (struct score3_address_info
*info
,
251 enum machine_mode mode
, rtx x
, int strict
)
253 info
->code
= GET_CODE (x
);
259 info
->type
= SCORE3_ADD_REG
;
261 info
->offset
= const0_rtx
;
262 return score3_valid_base_register_p (info
->reg
, strict
);
264 info
->type
= SCORE3_ADD_REG
;
265 info
->reg
= XEXP (x
, 0);
266 info
->offset
= XEXP (x
, 1);
267 return (score3_valid_base_register_p (info
->reg
, strict
)
268 && GET_CODE (info
->offset
) == CONST_INT
269 && IMM_IN_RANGE (INTVAL (info
->offset
), 15, 1));
274 if (GET_MODE_SIZE (mode
) > GET_MODE_SIZE (SImode
))
276 info
->type
= SCORE3_ADD_REG
;
277 info
->reg
= XEXP (x
, 0);
278 info
->offset
= GEN_INT (GET_MODE_SIZE (mode
));
279 return score3_valid_base_register_p (info
->reg
, strict
);
281 info
->type
= SCORE3_ADD_CONST_INT
;
286 info
->type
= SCORE3_ADD_SYMBOLIC
;
287 return (score3_symbolic_constant_p (x
, &info
->symbol_type
)
288 && (info
->symbol_type
== SYMBOL_GENERAL
289 || info
->symbol_type
== SYMBOL_SMALL_DATA
));
296 score3_return_in_memory (tree type
, tree fndecl ATTRIBUTE_UNUSED
)
298 return ((TYPE_MODE (type
) == BLKmode
)
299 || (int_size_in_bytes (type
) > 2 * UNITS_PER_WORD
)
300 || (int_size_in_bytes (type
) == -1));
303 /* Return a legitimate address for REG + OFFSET. */
305 score3_add_offset (rtx reg
, HOST_WIDE_INT offset
)
307 if (!IMM_IN_RANGE (offset
, 15, 1))
309 reg
= expand_simple_binop (GET_MODE (reg
), PLUS
,
310 gen_int_mode (offset
& 0xffffc000,
312 reg
, NULL
, 0, OPTAB_WIDEN
);
316 return plus_constant (reg
, offset
);
319 /* Implement TARGET_ASM_OUTPUT_MI_THUNK. Generate rtl rather than asm text
320 in order to avoid duplicating too much logic from elsewhere. */
322 score3_output_mi_thunk (FILE *file
, tree thunk_fndecl ATTRIBUTE_UNUSED
,
323 HOST_WIDE_INT delta
, HOST_WIDE_INT vcall_offset
,
326 rtx
this, temp1
, insn
, fnaddr
;
328 /* Pretend to be a post-reload pass while generating rtl. */
329 reload_completed
= 1;
331 /* Mark the end of the (empty) prologue. */
332 emit_note (NOTE_INSN_PROLOGUE_END
);
334 /* We need two temporary registers in some cases. */
335 temp1
= gen_rtx_REG (Pmode
, 8);
337 /* Find out which register contains the "this" pointer. */
338 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function
)), function
))
339 this = gen_rtx_REG (Pmode
, ARG_REG_FIRST
+ 1);
341 this = gen_rtx_REG (Pmode
, ARG_REG_FIRST
);
343 /* Add DELTA to THIS. */
346 rtx offset
= GEN_INT (delta
);
347 if (!CONST_OK_FOR_LETTER_P (delta
, 'L'))
349 emit_move_insn (temp1
, offset
);
352 emit_insn (gen_add3_insn (this, this, offset
));
355 /* If needed, add *(*THIS + VCALL_OFFSET) to THIS. */
356 if (vcall_offset
!= 0)
360 /* Set TEMP1 to *THIS. */
361 emit_move_insn (temp1
, gen_rtx_MEM (Pmode
, this));
363 /* Set ADDR to a legitimate address for *THIS + VCALL_OFFSET. */
364 addr
= score3_add_offset (temp1
, vcall_offset
);
366 /* Load the offset and add it to THIS. */
367 emit_move_insn (temp1
, gen_rtx_MEM (Pmode
, addr
));
368 emit_insn (gen_add3_insn (this, this, temp1
));
371 /* Jump to the target function. */
372 fnaddr
= XEXP (DECL_RTL (function
), 0);
373 insn
= emit_call_insn (gen_sibcall_internal_score3 (fnaddr
, const0_rtx
));
374 SIBLING_CALL_P (insn
) = 1;
376 /* Run just enough of rest_of_compilation. This sequence was
377 "borrowed" from alpha.c. */
379 insn_locators_alloc ();
380 split_all_insns_noflow ();
381 shorten_branches (insn
);
382 final_start_function (insn
, file
, 1);
383 final (insn
, file
, 1);
384 final_end_function ();
385 free_after_compilation (cfun
);
387 /* Clean up the vars set above. Note that final_end_function resets
388 the global pointer for us. */
389 reload_completed
= 0;
392 /* Copy VALUE to a register and return that register. If new psuedos
393 are allowed, copy it into a new register, otherwise use DEST. */
395 score3_force_temporary (rtx dest
, rtx value
)
397 if (can_create_pseudo_p ())
398 return force_reg (Pmode
, value
);
401 emit_move_insn (copy_rtx (dest
), value
);
406 /* Return a LO_SUM expression for ADDR. TEMP is as for score_force_temporary
407 and is used to load the high part into a register. */
409 score3_split_symbol (rtx temp
, rtx addr
)
411 rtx high
= score3_force_temporary (temp
,
412 gen_rtx_HIGH (Pmode
, copy_rtx (addr
)));
413 return gen_rtx_LO_SUM (Pmode
, high
, addr
);
416 /* This function is used to implement LEGITIMIZE_ADDRESS. If *XLOC can
417 be legitimized in a way that the generic machinery might not expect,
418 put the new address in *XLOC and return true. */
420 score3_legitimize_address (rtx
*xloc
)
422 enum score_symbol_type symbol_type
;
424 if (score3_symbolic_constant_p (*xloc
, &symbol_type
)
425 && symbol_type
== SYMBOL_GENERAL
)
427 *xloc
= score3_split_symbol (0, *xloc
);
431 if (GET_CODE (*xloc
) == PLUS
432 && GET_CODE (XEXP (*xloc
, 1)) == CONST_INT
)
434 rtx reg
= XEXP (*xloc
, 0);
435 if (!score3_valid_base_register_p (reg
, 0))
436 reg
= copy_to_mode_reg (Pmode
, reg
);
437 *xloc
= score3_add_offset (reg
, INTVAL (XEXP (*xloc
, 1)));
443 /* Fill INFO with information about a single argument. CUM is the
444 cumulative state for earlier arguments. MODE is the mode of this
445 argument and TYPE is its type (if known). NAMED is true if this
446 is a named (fixed) argument rather than a variable one. */
448 score3_classify_arg (const CUMULATIVE_ARGS
*cum
, enum machine_mode mode
,
449 tree type
, int named
, struct score3_arg_info
*info
)
452 unsigned int num_words
, max_regs
;
455 if (GET_MODE_CLASS (mode
) == MODE_INT
456 || GET_MODE_CLASS (mode
) == MODE_FLOAT
)
457 even_reg_p
= (GET_MODE_SIZE (mode
) > UNITS_PER_WORD
);
459 if (type
!= NULL_TREE
&& TYPE_ALIGN (type
) > BITS_PER_WORD
&& named
)
462 if (TARGET_MUST_PASS_IN_STACK (mode
, type
))
463 info
->reg_offset
= ARG_REG_NUM
;
466 info
->reg_offset
= cum
->num_gprs
;
468 info
->reg_offset
+= info
->reg_offset
& 1;
472 info
->num_bytes
= int_size_in_bytes (type
);
474 info
->num_bytes
= GET_MODE_SIZE (mode
);
476 num_words
= (info
->num_bytes
+ UNITS_PER_WORD
- 1) / UNITS_PER_WORD
;
477 max_regs
= ARG_REG_NUM
- info
->reg_offset
;
479 /* Partition the argument between registers and stack. */
480 info
->reg_words
= MIN (num_words
, max_regs
);
481 info
->stack_words
= num_words
- info
->reg_words
;
483 /* The alignment applied to registers is also applied to stack arguments. */
484 if (info
->stack_words
)
486 info
->stack_offset
= cum
->stack_words
;
488 info
->stack_offset
+= info
->stack_offset
& 1;
492 /* Set up the stack and frame (if desired) for the function. */
494 score3_function_prologue (FILE *file
, HOST_WIDE_INT size ATTRIBUTE_UNUSED
)
497 struct score3_frame_info
*f
= score3_cached_frame ();
498 HOST_WIDE_INT tsize
= f
->total_size
;
500 fnname
= XSTR (XEXP (DECL_RTL (current_function_decl
), 0), 0);
501 if (!flag_inhibit_size_directive
)
503 fputs ("\t.ent\t", file
);
504 assemble_name (file
, fnname
);
507 assemble_name (file
, fnname
);
510 if (!flag_inhibit_size_directive
)
513 "\t.frame\t%s," HOST_WIDE_INT_PRINT_DEC
",%s, %d\t\t"
514 "# vars= " HOST_WIDE_INT_PRINT_DEC
", regs= %d"
515 ", args= " HOST_WIDE_INT_PRINT_DEC
516 ", gp= " HOST_WIDE_INT_PRINT_DEC
"\n",
517 (reg_names
[(frame_pointer_needed
)
518 ? HARD_FRAME_POINTER_REGNUM
: STACK_POINTER_REGNUM
]),
520 reg_names
[RA_REGNUM
],
521 current_function_is_leaf
? 1 : 0,
527 fprintf(file
, "\t.mask\t0x%08x," HOST_WIDE_INT_PRINT_DEC
"\n",
529 (f
->gp_sp_offset
- f
->total_size
));
533 /* Do any necessary cleanup after a function to restore stack, frame,
536 score3_function_epilogue (FILE *file
,
537 HOST_WIDE_INT size ATTRIBUTE_UNUSED
)
539 if (!flag_inhibit_size_directive
)
542 fnname
= XSTR (XEXP (DECL_RTL (current_function_decl
), 0), 0);
543 fputs ("\t.end\t", file
);
544 assemble_name (file
, fnname
);
549 /* Returns true if X contains a SYMBOL_REF. */
551 score3_symbolic_expression_p (rtx x
)
553 if (GET_CODE (x
) == SYMBOL_REF
)
556 if (GET_CODE (x
) == CONST
)
557 return score3_symbolic_expression_p (XEXP (x
, 0));
560 return score3_symbolic_expression_p (XEXP (x
, 0));
562 if (ARITHMETIC_P (x
))
563 return (score3_symbolic_expression_p (XEXP (x
, 0))
564 || score3_symbolic_expression_p (XEXP (x
, 1)));
569 /* Choose the section to use for the constant rtx expression X that has
572 score3_select_rtx_section (enum machine_mode mode
, rtx x
,
573 unsigned HOST_WIDE_INT align
)
575 if (GET_MODE_SIZE (mode
) <= SCORE3_SDATA_MAX
)
576 return get_named_section (0, ".sdata", 0);
577 else if (flag_pic
&& score3_symbolic_expression_p (x
))
578 return get_named_section (0, ".data.rel.ro", 3);
580 return mergeable_constant_section (mode
, align
, 0);
583 /* Implement TARGET_IN_SMALL_DATA_P. */
585 score3_in_small_data_p (tree decl
)
589 if (TREE_CODE (decl
) == STRING_CST
590 || TREE_CODE (decl
) == FUNCTION_DECL
)
593 if (TREE_CODE (decl
) == VAR_DECL
&& DECL_SECTION_NAME (decl
) != 0)
596 name
= TREE_STRING_POINTER (DECL_SECTION_NAME (decl
));
597 if (strcmp (name
, ".sdata") != 0
598 && strcmp (name
, ".sbss") != 0)
600 if (!DECL_EXTERNAL (decl
))
603 size
= int_size_in_bytes (TREE_TYPE (decl
));
604 return (size
> 0 && size
<= SCORE3_SDATA_MAX
);
607 /* Implement TARGET_ASM_FILE_START. */
609 score3_asm_file_start (void)
611 default_file_start ();
612 fprintf (asm_out_file
, ASM_COMMENT_START
613 "GCC for S+core %s \n", SCORE_GCC_VERSION
);
616 fprintf (asm_out_file
, "\t.set pic\n");
619 /* Implement TARGET_ASM_FILE_END. When using assembler macros, emit
620 .externs for any small-data variables that turned out to be external. */
622 score3_asm_file_end (void)
625 struct extern_list
*p
;
628 fputs ("\n", asm_out_file
);
629 for (p
= extern_head
; p
!= 0; p
= p
->next
)
631 name_tree
= get_identifier (p
->name
);
632 if (!TREE_ASM_WRITTEN (name_tree
)
633 && TREE_SYMBOL_REFERENCED (name_tree
))
635 TREE_ASM_WRITTEN (name_tree
) = 1;
636 fputs ("\t.extern\t", asm_out_file
);
637 assemble_name (asm_out_file
, p
->name
);
638 fprintf (asm_out_file
, ", %d\n", p
->size
);
644 /* Implement OVERRIDE_OPTIONS macro. */
646 score3_override_options (void)
650 score3_sdata_max
= g_switch_set
? g_switch_value
: SCORE3_DEFAULT_SDATA_MAX
;
653 score3_sdata_max
= 0;
654 if (g_switch_set
&& (g_switch_value
!= 0))
655 warning (0, "-fPIC and -G are incompatible");
658 score_char_to_class
['d'] = G32_REGS
;
659 score_char_to_class
['e'] = G16_REGS
;
660 score_char_to_class
['t'] = T32_REGS
;
662 score_char_to_class
['h'] = HI_REG
;
663 score_char_to_class
['l'] = LO_REG
;
664 score_char_to_class
['x'] = CE_REGS
;
666 score_char_to_class
['q'] = CN_REG
;
667 score_char_to_class
['y'] = LC_REG
;
668 score_char_to_class
['z'] = SC_REG
;
669 score_char_to_class
['a'] = SP_REGS
;
671 score_char_to_class
['c'] = CR_REGS
;
674 /* Implement REGNO_REG_CLASS macro. */
676 score3_reg_class (int regno
)
679 gcc_assert (regno
>= 0 && regno
< FIRST_PSEUDO_REGISTER
);
681 if (regno
== FRAME_POINTER_REGNUM
682 || regno
== ARG_POINTER_REGNUM
)
685 for (c
= 0; c
< N_REG_CLASSES
; c
++)
686 if (TEST_HARD_REG_BIT (reg_class_contents
[c
], regno
))
692 /* Implement PREFERRED_RELOAD_CLASS macro. */
694 score3_preferred_reload_class (rtx x ATTRIBUTE_UNUSED
, enum reg_class
class)
696 if (reg_class_subset_p (G16_REGS
, class))
698 if (reg_class_subset_p (G32_REGS
, class))
703 /* Implement SECONDARY_INPUT_RELOAD_CLASS
704 and SECONDARY_OUTPUT_RELOAD_CLASS macro. */
706 score3_secondary_reload_class (enum reg_class
class,
707 enum machine_mode mode ATTRIBUTE_UNUSED
,
711 if (GET_CODE (x
) == REG
|| GET_CODE(x
) == SUBREG
)
712 regno
= true_regnum (x
);
714 if (!GR_REG_CLASS_P (class))
715 return GP_REG_P (regno
) ? NO_REGS
: G32_REGS
;
719 /* Implement CONST_OK_FOR_LETTER_P macro. */
731 score3_const_ok_for_letter_p (HOST_WIDE_INT value
, char c
)
735 case 'I': return ((value
& 0xffff) == 0);
736 case 'J': return IMM_IN_RANGE (value
, 5, 0);
737 case 'K': return IMM_IN_RANGE (value
, 16, 0);
738 case 'L': return IMM_IN_RANGE (value
, 16, 1);
739 case 'M': return IMM_IN_RANGE (value
, 14, 0);
740 case 'N': return IMM_IN_RANGE (value
, 14, 1);
741 case 'O': return IMM_IN_RANGE (value
, 5, 1);
742 case 'P': return IMM_IN_RANGE (value
, 6, 1);
743 case 'Q': return score_extra_constraint (GEN_INT(value
), c
);
748 /* Implement EXTRA_CONSTRAINT macro. */
753 score3_extra_constraint (rtx op
, char c
)
757 case 'Q': return IMM_IN_RANGE (INTVAL(op
), 32, 0);
759 return GET_CODE (op
) == SYMBOL_REF
;
765 /* Return truth value on whether or not a given hard register
766 can support a given mode. */
768 score3_hard_regno_mode_ok (unsigned int regno
, enum machine_mode mode
)
770 int size
= GET_MODE_SIZE (mode
);
771 enum mode_class
class = GET_MODE_CLASS (mode
);
773 if (class == MODE_CC
)
774 return regno
== CC_REGNUM
;
775 else if (regno
== FRAME_POINTER_REGNUM
776 || regno
== ARG_POINTER_REGNUM
)
777 return class == MODE_INT
;
778 else if (GP_REG_P (regno
))
779 return !(regno
& 1) || (size
<= UNITS_PER_WORD
);
780 else if (CE_REG_P (regno
))
781 return (class == MODE_INT
782 && ((size
<= UNITS_PER_WORD
)
783 || (regno
== CE_REG_FIRST
&& size
== 2 * UNITS_PER_WORD
)));
785 return (class == MODE_INT
) && (size
<= UNITS_PER_WORD
);
788 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
789 pointer or argument pointer. TO is either the stack pointer or
790 hard frame pointer. */
792 score3_initial_elimination_offset (int from
,
793 int to ATTRIBUTE_UNUSED
)
795 struct score3_frame_info
*f
= score3_compute_frame_size (get_frame_size ());
798 case ARG_POINTER_REGNUM
:
799 return f
->total_size
;
800 case FRAME_POINTER_REGNUM
:
807 /* Implement FUNCTION_ARG_ADVANCE macro. */
809 score3_function_arg_advance (CUMULATIVE_ARGS
*cum
, enum machine_mode mode
,
810 tree type
, int named
)
812 struct score3_arg_info info
;
813 score3_classify_arg (cum
, mode
, type
, named
, &info
);
814 cum
->num_gprs
= info
.reg_offset
+ info
.reg_words
;
815 if (info
.stack_words
> 0)
816 cum
->stack_words
= info
.stack_offset
+ info
.stack_words
;
820 /* Implement TARGET_ARG_PARTIAL_BYTES macro. */
822 score3_arg_partial_bytes (CUMULATIVE_ARGS
*cum
,
823 enum machine_mode mode
, tree type
, bool named
)
825 struct score3_arg_info info
;
826 score3_classify_arg (cum
, mode
, type
, named
, &info
);
827 return info
.stack_words
> 0 ? info
.reg_words
* UNITS_PER_WORD
: 0;
830 /* Implement FUNCTION_ARG macro. */
832 score3_function_arg (const CUMULATIVE_ARGS
*cum
, enum machine_mode mode
,
833 tree type
, int named
)
835 struct score3_arg_info info
;
837 if (mode
== VOIDmode
|| !named
)
840 score3_classify_arg (cum
, mode
, type
, named
, &info
);
842 if (info
.reg_offset
== ARG_REG_NUM
)
845 if (!info
.stack_words
)
846 return gen_rtx_REG (mode
, ARG_REG_FIRST
+ info
.reg_offset
);
849 rtx ret
= gen_rtx_PARALLEL (mode
, rtvec_alloc (info
.reg_words
));
850 unsigned int i
, part_offset
= 0;
851 for (i
= 0; i
< info
.reg_words
; i
++)
854 reg
= gen_rtx_REG (SImode
, ARG_REG_FIRST
+ info
.reg_offset
+ i
);
855 XVECEXP (ret
, 0, i
) = gen_rtx_EXPR_LIST (SImode
, reg
,
856 GEN_INT (part_offset
));
857 part_offset
+= UNITS_PER_WORD
;
863 /* Implement FUNCTION_VALUE and LIBCALL_VALUE. For normal calls,
864 VALTYPE is the return type and MODE is VOIDmode. For libcalls,
865 VALTYPE is null and MODE is the mode of the return value. */
867 score3_function_value (tree valtype
, tree func ATTRIBUTE_UNUSED
,
868 enum machine_mode mode
)
873 mode
= TYPE_MODE (valtype
);
874 unsignedp
= TYPE_UNSIGNED (valtype
);
875 mode
= promote_mode (valtype
, mode
, &unsignedp
, 1);
877 return gen_rtx_REG (mode
, RT_REGNUM
);
880 /* Implement INITIALIZE_TRAMPOLINE macro. */
882 score3_initialize_trampoline (rtx ADDR
, rtx FUNC
, rtx CHAIN
)
884 #define FFCACHE "_flush_cache"
885 #define CODE_SIZE (TRAMPOLINE_INSNS * UNITS_PER_WORD)
889 pfunc
= plus_constant (ADDR
, CODE_SIZE
);
890 pchain
= plus_constant (ADDR
, CODE_SIZE
+ GET_MODE_SIZE (SImode
));
892 emit_move_insn (gen_rtx_MEM (SImode
, pfunc
), FUNC
);
893 emit_move_insn (gen_rtx_MEM (SImode
, pchain
), CHAIN
);
894 emit_library_call (gen_rtx_SYMBOL_REF (Pmode
, FFCACHE
),
897 GEN_INT (TRAMPOLINE_SIZE
), SImode
);
902 /* This function is used to implement REG_MODE_OK_FOR_BASE_P macro. */
904 score3_regno_mode_ok_for_base_p (int regno
, int strict
)
906 if (regno
>= FIRST_PSEUDO_REGISTER
)
910 regno
= reg_renumber
[regno
];
912 if (regno
== ARG_POINTER_REGNUM
913 || regno
== FRAME_POINTER_REGNUM
)
915 return GP_REG_P (regno
);
918 /* Implement GO_IF_LEGITIMATE_ADDRESS macro. */
920 score3_address_p (enum machine_mode mode
, rtx x
, int strict
)
922 struct score3_address_info addr
;
924 return score3_classify_address (&addr
, mode
, x
, strict
);
927 /* Return a number assessing the cost of moving a register in class
930 score3_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED
,
931 enum reg_class from
, enum reg_class to
)
933 if (GR_REG_CLASS_P (from
))
935 if (GR_REG_CLASS_P (to
))
937 else if (SP_REG_CLASS_P (to
))
939 else if (CP_REG_CLASS_P (to
))
941 else if (CE_REG_CLASS_P (to
))
944 if (GR_REG_CLASS_P (to
))
946 if (GR_REG_CLASS_P (from
))
948 else if (SP_REG_CLASS_P (from
))
950 else if (CP_REG_CLASS_P (from
))
952 else if (CE_REG_CLASS_P (from
))
958 /* Return the number of instructions needed to load a symbol of the
959 given type into a register. */
961 score3_symbol_insns (enum score_symbol_type type
)
968 case SYMBOL_SMALL_DATA
:
975 /* Return the number of instructions needed to load or store a value
976 of mode MODE at X. Return 0 if X isn't valid for MODE. */
978 score3_address_insns (rtx x
, enum machine_mode mode
)
980 struct score3_address_info addr
;
986 factor
= (GET_MODE_SIZE (mode
) + UNITS_PER_WORD
- 1) / UNITS_PER_WORD
;
988 if (score3_classify_address (&addr
, mode
, x
, false))
992 case SCORE3_ADD_CONST_INT
:
995 case SCORE3_ADD_SYMBOLIC
:
996 return factor
* score3_symbol_insns (addr
.symbol_type
);
1001 /* Implement TARGET_RTX_COSTS macro. */
1003 score3_rtx_costs (rtx x
, int code
, int outer_code
, int *total
)
1005 enum machine_mode mode
= GET_MODE (x
);
1010 if (outer_code
== SET
)
1012 if (CONST_OK_FOR_LETTER_P (INTVAL (x
), 'I')
1013 || CONST_OK_FOR_LETTER_P (INTVAL (x
), 'L'))
1014 *total
= COSTS_N_INSNS (1);
1016 *total
= COSTS_N_INSNS (2);
1018 else if (outer_code
== PLUS
|| outer_code
== MINUS
)
1020 if (CONST_OK_FOR_LETTER_P (INTVAL (x
), 'N'))
1022 else if (CONST_OK_FOR_LETTER_P (INTVAL (x
), 'I')
1023 || CONST_OK_FOR_LETTER_P (INTVAL (x
), 'L'))
1026 *total
= COSTS_N_INSNS (2);
1028 else if (outer_code
== AND
|| outer_code
== IOR
)
1030 if (CONST_OK_FOR_LETTER_P (INTVAL (x
), 'M'))
1032 else if (CONST_OK_FOR_LETTER_P (INTVAL (x
), 'I')
1033 || CONST_OK_FOR_LETTER_P (INTVAL (x
), 'K'))
1036 *total
= COSTS_N_INSNS (2);
1048 *total
= COSTS_N_INSNS (2);
1053 /* If the address is legitimate, return the number of
1054 instructions it needs, otherwise use the default handling. */
1055 int n
= score3_address_insns (XEXP (x
, 0), GET_MODE (x
));
1058 *total
= COSTS_N_INSNS (n
+ 1);
1065 *total
= COSTS_N_INSNS (6);
1069 *total
= COSTS_N_INSNS (1);
1077 *total
= COSTS_N_INSNS (2);
1087 *total
= COSTS_N_INSNS ((GET_CODE (XEXP (x
, 1)) == CONST_INT
)
1094 *total
= COSTS_N_INSNS (4);
1101 *total
= COSTS_N_INSNS (4);
1104 *total
= COSTS_N_INSNS (1);
1110 *total
= COSTS_N_INSNS (4);
1116 *total
= optimize_size
? COSTS_N_INSNS (2) : COSTS_N_INSNS (12);
1123 *total
= optimize_size
? COSTS_N_INSNS (2) : COSTS_N_INSNS (33);
1128 switch (GET_MODE (XEXP (x
, 0)))
1132 if (GET_CODE (XEXP (x
, 0)) == MEM
)
1134 *total
= COSTS_N_INSNS (2);
1136 if (!TARGET_LITTLE_ENDIAN
&&
1137 side_effects_p (XEXP (XEXP (x
, 0), 0)))
1141 *total
= COSTS_N_INSNS (1);
1145 *total
= COSTS_N_INSNS (1);
1155 /* Implement TARGET_ADDRESS_COST macro. */
1157 score3_address_cost (rtx addr
)
1159 return score3_address_insns (addr
, SImode
);
1162 /* Implement ASM_OUTPUT_EXTERNAL macro. */
1164 score3_output_external (FILE *file ATTRIBUTE_UNUSED
,
1165 tree decl
, const char *name
)
1167 register struct extern_list
*p
;
1169 if (score3_in_small_data_p (decl
))
1171 p
= (struct extern_list
*) ggc_alloc (sizeof (struct extern_list
));
1172 p
->next
= extern_head
;
1174 p
->size
= int_size_in_bytes (TREE_TYPE (decl
));
1180 /* Implement RETURN_ADDR_RTX. Note, we do not support moving
1181 back to a previous frame. */
1183 score3_return_addr (int count
, rtx frame ATTRIBUTE_UNUSED
)
1187 return get_hard_reg_initial_val (Pmode
, RA_REGNUM
);
1190 /* Implement PRINT_OPERAND macro. */
1191 /* Score-specific operand codes:
1192 '[' print .set nor1 directive
1193 ']' print .set r1 directive
1194 'U' print hi part of a CONST_INT rtx
1197 'D' print SFmode const double
1198 'S' selectively print "!" if operand is 15bit instruction accessible
1199 'V' print "v!" if operand is 15bit instruction accessible, or "lfh!"
1200 'L' low part of DImode reg operand
1201 'H' high part of DImode reg operand
1202 'C' print part of opcode for a branch condition. */
1204 score3_print_operand (FILE *file
, rtx op
, int c
)
1206 enum rtx_code code
= -1;
1207 if (!PRINT_OPERAND_PUNCT_VALID_P (c
))
1208 code
= GET_CODE (op
);
1212 fprintf (file
, ".set r1\n");
1216 fprintf (file
, "\n\t.set nor1");
1220 gcc_assert (code
== CONST_INT
);
1221 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
,
1222 (INTVAL (op
) >> 16) & 0xffff);
1226 if (GET_CODE (op
) == CONST_DOUBLE
)
1228 rtx temp
= gen_lowpart (SImode
, op
);
1229 gcc_assert (GET_MODE (op
) == SFmode
);
1230 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, INTVAL (temp
) & 0xffffffff);
1233 output_addr_const (file
, op
);
1237 gcc_assert (code
== REG
);
1238 if (G16_REG_P (REGNO (op
)))
1239 fprintf (file
, "!");
1243 gcc_assert (code
== REG
);
1244 fprintf (file
, G16_REG_P (REGNO (op
)) ? "v!" : "lfh!");
1248 enum machine_mode mode
= GET_MODE (XEXP (op
, 0));
1252 case EQ
: fputs ("eq!", file
); break;
1253 case NE
: fputs ("ne!", file
); break;
1254 case GT
: fputs ("gt!", file
); break;
1255 case GE
: fputs (mode
!= CCmode
? "pl" : "ge", file
); break;
1256 case LT
: fputs (mode
!= CCmode
? "mi" : "lt", file
); break;
1257 case LE
: fputs ("le!", file
); break;
1258 case GTU
: fputs ("gtu!", file
); break;
1259 case GEU
: fputs ("cs", file
); break;
1260 case LTU
: fputs ("cc", file
); break;
1261 case LEU
: fputs ("leu!", file
); break;
1263 output_operand_lossage ("invalid operand for code: '%c'", code
);
1266 else if (c
== 'G') /* Seperate from b<cond>, use for mv<cond>. */
1268 enum machine_mode mode
= GET_MODE (XEXP (op
, 0));
1272 case EQ
: fputs ("eq", file
); break;
1273 case NE
: fputs ("ne", file
); break;
1274 case GT
: fputs ("gt", file
); break;
1275 case GE
: fputs (mode
!= CCmode
? "pl" : "ge", file
); break;
1276 case LT
: fputs (mode
!= CCmode
? "mi" : "lt", file
); break;
1277 case LE
: fputs ("le", file
); break;
1278 case GTU
: fputs ("gtu", file
); break;
1279 case GEU
: fputs ("cs", file
); break;
1280 case LTU
: fputs ("cc", file
); break;
1281 case LEU
: fputs ("leu", file
); break;
1283 output_operand_lossage ("invalid operand for code: '%c'", code
);
1288 unsigned HOST_WIDE_INT i
;
1289 unsigned HOST_WIDE_INT pow2mask
= 1;
1290 unsigned HOST_WIDE_INT val
;
1293 for (i
= 0; i
< 32; i
++)
1295 if (val
== pow2mask
)
1299 gcc_assert (i
< 32);
1300 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, i
);
1304 unsigned HOST_WIDE_INT i
;
1305 unsigned HOST_WIDE_INT pow2mask
= 1;
1306 unsigned HOST_WIDE_INT val
;
1309 for (i
= 0; i
< 32; i
++)
1311 if (val
== pow2mask
)
1315 gcc_assert (i
< 32);
1316 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, i
);
1318 else if (code
== REG
)
1320 int regnum
= REGNO (op
);
1321 if ((c
== 'H' && !WORDS_BIG_ENDIAN
)
1322 || (c
== 'L' && WORDS_BIG_ENDIAN
))
1324 fprintf (file
, "%s", reg_names
[regnum
]);
1331 score3_print_operand_address (file
, op
);
1334 output_addr_const (file
, op
);
1339 /* Implement PRINT_OPERAND_ADDRESS macro. */
1341 score3_print_operand_address (FILE *file
, rtx x
)
1343 struct score3_address_info addr
;
1344 enum rtx_code code
= GET_CODE (x
);
1345 enum machine_mode mode
= GET_MODE (x
);
1350 if (score3_classify_address (&addr
, mode
, x
, true))
1354 case SCORE3_ADD_REG
:
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 fprintf (file
, "[%s]+, %ld", reg_names
[REGNO (addr
.reg
)],
1372 INTVAL (addr
.offset
));
1375 if (INTVAL(addr
.offset
) == 0)
1376 fprintf(file
, "[%s]", reg_names
[REGNO (addr
.reg
)]);
1378 fprintf(file
, "[%s, %ld]", reg_names
[REGNO (addr
.reg
)],
1379 INTVAL(addr
.offset
));
1384 case SCORE3_ADD_CONST_INT
:
1385 case SCORE3_ADD_SYMBOLIC
:
1386 output_addr_const (file
, x
);
1390 print_rtl (stderr
, x
);
1394 /* Implement SELECT_CC_MODE macro. */
1396 score3_select_cc_mode (enum rtx_code op
, rtx x
, rtx y
)
1398 if ((op
== EQ
|| op
== NE
|| op
== LT
|| op
== GE
)
1400 && GET_MODE (x
) == SImode
)
1402 switch (GET_CODE (x
))
1420 return (op
== LT
|| op
== GE
) ? CC_Nmode
: CCmode
;
1427 if ((op
== EQ
|| op
== NE
)
1428 && (GET_CODE (y
) == NEG
)
1429 && register_operand (XEXP (y
, 0), SImode
)
1430 && register_operand (x
, SImode
))
1438 #define EMIT_PL(_rtx) RTX_FRAME_RELATED_P (_rtx) = 1
1439 /* return 0, no more bit set in mask. */
1440 static int rpush_first (int mask
, int sb
, int *rd
)
1444 if ((mask
& (1 << sb
)) == 0)
1449 for (i
= sb
-1; i
>= 0; i
--)
1451 if (mask
& (1 << i
))
1465 rpush (int rd
, int cnt
)
1467 rtx mem
= gen_rtx_MEM (SImode
, gen_rtx_PRE_DEC (SImode
, stack_pointer_rtx
));
1468 rtx reg
= gen_rtx_REG (SImode
, rd
);
1470 if (!crtl
->calls_eh_return
)
1471 MEM_READONLY_P (mem
) = 1;
1474 EMIT_PL (emit_insn (gen_pushsi_score3 (mem
, reg
)));
1478 rtx insn
= gen_store_multiple (gen_rtx_MEM (SImode
, stack_pointer_rtx
),
1479 gen_rtx_REG (SImode
, rd
),
1482 rtx pat
= PATTERN (insn
);
1484 for (i
= 0; i
< XVECLEN (pat
, 0); i
++)
1485 if (GET_CODE (XVECEXP (pat
, 0, i
)) == SET
)
1486 RTX_FRAME_RELATED_P (XVECEXP (pat
, 0, i
)) = 1;
1488 EMIT_PL (emit_insn (insn
));
1492 /* Generate the prologue instructions for entry into a S+core function. */
1494 score3_prologue (void)
1496 struct score3_frame_info
*f
= score3_compute_frame_size (get_frame_size ());
1500 size
= f
->total_size
- f
->gp_reg_size
;
1503 emit_insn (gen_cpload_score3 ());
1508 for (regno
= (int) GP_REG_LAST
; regno
>= (int) GP_REG_FIRST
; regno
--)
1510 cnt
= rpush_first (f
->mask
, regno
, &rd
);
1514 regno
= regno
- cnt
;
1523 if (CONST_OK_FOR_LETTER_P (-size
, 'L'))
1524 EMIT_PL (emit_insn (gen_add3_insn (stack_pointer_rtx
,
1529 EMIT_PL (emit_move_insn (gen_rtx_REG (Pmode
, SCORE3_PROLOGUE_TEMP_REGNUM
),
1532 (gen_sub3_insn (stack_pointer_rtx
,
1535 SCORE3_PROLOGUE_TEMP_REGNUM
))));
1537 insn
= get_last_insn ();
1539 alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR
,
1540 gen_rtx_SET (VOIDmode
, stack_pointer_rtx
,
1541 plus_constant (stack_pointer_rtx
,
1546 if (frame_pointer_needed
)
1547 EMIT_PL (emit_move_insn (hard_frame_pointer_rtx
, stack_pointer_rtx
));
1549 if (flag_pic
&& f
->cprestore_size
)
1551 if (frame_pointer_needed
)
1552 emit_insn (gen_cprestore_use_fp_score3 (GEN_INT (size
- f
->cprestore_size
)));
1554 emit_insn (gen_cprestore_use_sp_score3 (GEN_INT (size
- f
->cprestore_size
)));
1558 /* return 0, no more bit set in mask. */
1560 rpop_first (int mask
, int sb
, int *rd
)
1564 if ((mask
& (1 << sb
)) == 0)
1569 for (i
= sb
+1; i
< 32; i
++)
1570 if (mask
& (1 << i
))
1579 rpop (int rd
, int cnt
)
1581 rtx mem
= gen_rtx_MEM (SImode
, gen_rtx_POST_INC (SImode
, stack_pointer_rtx
));
1582 rtx reg
= gen_rtx_REG (SImode
, rd
);
1584 if (!crtl
->calls_eh_return
)
1585 MEM_READONLY_P (mem
) = 1;
1588 emit_insn (gen_popsi_score3 (reg
, mem
));
1590 emit_insn (gen_load_multiple (reg
,
1591 gen_rtx_MEM (SImode
, stack_pointer_rtx
),
1595 /* Generate the epilogue instructions in a S+core function. */
1597 score3_epilogue (int sibcall_p
)
1599 struct score3_frame_info
*f
= score3_compute_frame_size (get_frame_size ());
1604 size
= f
->total_size
- f
->gp_reg_size
;
1606 if (!frame_pointer_needed
)
1607 base
= stack_pointer_rtx
;
1609 base
= hard_frame_pointer_rtx
;
1613 if (CONST_OK_FOR_LETTER_P (size
, 'L'))
1614 emit_insn (gen_add3_insn (base
, base
, GEN_INT (size
)));
1617 emit_move_insn (gen_rtx_REG (Pmode
, SCORE3_EPILOGUE_TEMP_REGNUM
),
1619 emit_insn (gen_add3_insn (base
, base
,
1621 SCORE3_EPILOGUE_TEMP_REGNUM
)));
1625 if (base
!= stack_pointer_rtx
)
1626 emit_move_insn (stack_pointer_rtx
, base
);
1628 if (crtl
->calls_eh_return
)
1629 emit_insn (gen_add3_insn (stack_pointer_rtx
,
1631 EH_RETURN_STACKADJ_RTX
));
1636 for (regno
= (int) GP_REG_FIRST
; regno
<= (int) GP_REG_LAST
; regno
++)
1638 cnt
= rpop_first (f
->mask
, regno
, &rd
);
1642 regno
= regno
+ cnt
;
1648 emit_jump_insn (gen_return_internal_score3 (gen_rtx_REG (Pmode
, RA_REGNUM
)));
1652 score3_gen_cmp (enum machine_mode mode
)
1654 emit_insn (gen_rtx_SET (VOIDmode
, gen_rtx_REG (mode
, CC_REGNUM
),
1655 gen_rtx_COMPARE (mode
, cmp_op0
, cmp_op1
)));
1658 /* Return true if X is a symbolic constant that can be calculated in
1659 the same way as a bare symbol. If it is, store the type of the
1660 symbol in *SYMBOL_TYPE. */
1662 score3_symbolic_constant_p (rtx x
, enum score_symbol_type
*symbol_type
)
1664 HOST_WIDE_INT offset
;
1666 score3_split_const (x
, &x
, &offset
);
1667 if (GET_CODE (x
) == SYMBOL_REF
|| GET_CODE (x
) == LABEL_REF
)
1668 *symbol_type
= score3_classify_symbol (x
);
1675 /* if offset > 15bit, must reload */
1676 if (!IMM_IN_RANGE (offset
, 15, 1))
1679 switch (*symbol_type
)
1681 case SYMBOL_GENERAL
:
1683 case SYMBOL_SMALL_DATA
:
1684 return score3_offset_within_object_p (x
, offset
);
1690 score3_movsicc (rtx
*ops
)
1692 enum machine_mode mode
;
1694 mode
= score3_select_cc_mode (GET_CODE (ops
[1]), ops
[2], ops
[3]);
1695 emit_insn (gen_rtx_SET (VOIDmode
, gen_rtx_REG (mode
, CC_REGNUM
),
1696 gen_rtx_COMPARE (mode
, cmp_op0
, cmp_op1
)));
1699 /* Call and sibcall pattern all need call this function. */
1701 score3_call (rtx
*ops
, bool sib
)
1703 rtx addr
= XEXP (ops
[0], 0);
1704 if (!call_insn_operand (addr
, VOIDmode
))
1707 addr
= gen_reg_rtx (Pmode
);
1708 gen_move_insn (addr
, oaddr
);
1712 emit_call_insn (gen_sibcall_internal_score3 (addr
, ops
[1]));
1714 emit_call_insn (gen_call_internal_score3 (addr
, ops
[1]));
1717 /* Call value and sibcall value pattern all need call this function. */
1719 score3_call_value (rtx
*ops
, bool sib
)
1721 rtx result
= ops
[0];
1722 rtx addr
= XEXP (ops
[1], 0);
1725 if (!call_insn_operand (addr
, VOIDmode
))
1728 addr
= gen_reg_rtx (Pmode
);
1729 gen_move_insn (addr
, oaddr
);
1733 emit_call_insn (gen_sibcall_value_internal_score3 (result
, addr
, arg
));
1735 emit_call_insn (gen_call_value_internal_score3 (result
, addr
, arg
));
1740 score3_movdi (rtx
*ops
)
1744 rtx dst0
= score3_subw (dst
, 0);
1745 rtx dst1
= score3_subw (dst
, 1);
1746 rtx src0
= score3_subw (src
, 0);
1747 rtx src1
= score3_subw (src
, 1);
1749 if (GET_CODE (dst0
) == REG
&& reg_overlap_mentioned_p (dst0
, src
))
1751 emit_move_insn (dst1
, src1
);
1752 emit_move_insn (dst0
, src0
);
1756 emit_move_insn (dst0
, src0
);
1757 emit_move_insn (dst1
, src1
);
1762 score3_zero_extract_andi (rtx
*ops
)
1764 if (INTVAL (ops
[1]) == 1 && const_uimm5 (ops
[2], SImode
))
1765 emit_insn (gen_zero_extract_bittst_score3 (ops
[0], ops
[2]));
1768 unsigned HOST_WIDE_INT mask
;
1769 mask
= (0xffffffffU
& ((1U << INTVAL (ops
[1])) - 1U));
1770 mask
= mask
<< INTVAL (ops
[2]);
1771 emit_insn (gen_andsi3_cmp_score3 (ops
[3], ops
[0],
1772 gen_int_mode (mask
, SImode
)));
1777 score3_rpush (rtx
*ops
)
1779 snprintf (score3_ins
, INS_BUF_SZ
, "rpush!\t%%1, %d", XVECLEN (ops
[0], 0));
1784 score3_rpop (rtx
*ops
)
1786 snprintf (score3_ins
, INS_BUF_SZ
, "rpop!\t%%1, %d", XVECLEN (ops
[0], 0));
1790 /* Output asm code for ld/sw insn. */
1792 score3_pr_addr_post (rtx
*ops
, int idata
, int iaddr
, char *ip
,
1793 enum score_mem_unit unit ATTRIBUTE_UNUSED
)
1795 struct score3_address_info ai
;
1797 gcc_assert (GET_CODE (ops
[idata
]) == REG
);
1798 gcc_assert (score3_classify_address (&ai
, SImode
, XEXP (ops
[iaddr
], 0), true));
1800 if (ai
.type
== SCORE3_ADD_REG
1802 && GET_CODE (ai
.offset
) == CONST_INT
1803 && G16_REG_P (REGNO (ops
[idata
]))
1804 && G8_REG_P (REGNO (ai
.reg
))
1805 && ((INTVAL (ai
.offset
) & 3) == 0)
1806 && (IMM_IN_RANGE (INTVAL (ai
.offset
), 7, 0)))
1808 ops
[iaddr
] = ai
.reg
;
1809 return snprintf (ip
, INS_BUF_SZ
, "!\t%%%d, [%%%d, "
1810 HOST_WIDE_INT_PRINT_DEC
"]",
1811 idata
, iaddr
, INTVAL (ai
.offset
));
1814 if (ai
.type
== SCORE3_ADD_SYMBOLIC
)
1815 return snprintf (ip
, INS_BUF_SZ
, "48\t%%%d, %%a%d", idata
, iaddr
);
1817 return snprintf (ip
, INS_BUF_SZ
, "\t%%%d, %%a%d", idata
, iaddr
);
1820 /* Output asm insn for load. */
1822 score3_linsn (rtx
*ops
, enum score_mem_unit unit
, bool sign
)
1824 const char *pre_ins
[] =
1825 {"lbu", "lhu", "lw", "??", "lb", "lh", "lw", "??"};
1828 strcpy (score3_ins
, pre_ins
[(sign
? 4 : 0) + unit
]);
1829 ip
= score3_ins
+ strlen (score3_ins
);
1831 if (unit
== SCORE_WORD
)
1832 score3_pr_addr_post (ops
, 0, 1, ip
, unit
);
1834 snprintf (ip
, INS_BUF_SZ
, "\t%%0, %%a1");
1839 /* Output asm insn for store. */
1841 score3_sinsn (rtx
*ops
, enum score_mem_unit unit
)
1843 const char *pre_ins
[] = {"sb", "sh", "sw"};
1846 strcpy (score3_ins
, pre_ins
[unit
]);
1847 ip
= score3_ins
+ strlen (score3_ins
);
1849 if (unit
== SCORE_WORD
)
1850 score3_pr_addr_post (ops
, 1, 0, ip
, unit
);
1852 snprintf (ip
, INS_BUF_SZ
, "\t%%1, %%a0");
1857 /* Output asm insn for load immediate. */
1859 score3_limm (rtx
*ops
)
1863 gcc_assert (GET_CODE (ops
[0]) == REG
);
1864 gcc_assert (GET_CODE (ops
[1]) == CONST_INT
);
1866 v
= INTVAL (ops
[1]);
1867 if (G16_REG_P (REGNO (ops
[0])) && IMM_IN_RANGE (v
, 5, 0))
1868 return "ldiu!\t%0, %c1";
1869 else if (IMM_IN_RANGE (v
, 16, 1))
1870 return "ldi\t%0, %c1";
1871 else if ((v
& 0xffff) == 0)
1872 return "ldis\t%0, %U1";
1874 return "li\t%0, %c1";
1877 /* Output asm insn for move. */
1879 score3_move (rtx
*ops
)
1881 gcc_assert (GET_CODE (ops
[0]) == REG
);
1882 gcc_assert (GET_CODE (ops
[1]) == REG
);
1884 return "mv!\t%0, %1";
1887 /* Generate add insn. */
1889 score3_select_add_imm (rtx
*ops
, bool set_cc
)
1891 HOST_WIDE_INT v
= INTVAL (ops
[2]);
1893 gcc_assert (GET_CODE (ops
[2]) == CONST_INT
);
1894 gcc_assert (REGNO (ops
[0]) == REGNO (ops
[1]));
1897 return "addi.c\t%0, %c2";
1899 if (IMM_IN_RANGE (v
, 6, 1) && G16_REG_P (REGNO (ops
[0])))
1900 return "addi!\t%0, %c2";
1902 return "addi\t%0, %c2";
1905 /* Output arith insn. */
1907 score3_select (rtx
*ops
, const char *inst_pre
, bool commu ATTRIBUTE_UNUSED
,
1908 const char *letter
, bool set_cc
)
1910 gcc_assert (GET_CODE (ops
[0]) == REG
);
1911 gcc_assert (GET_CODE (ops
[1]) == REG
);
1914 snprintf (score3_ins
, INS_BUF_SZ
, "%s.c\t%%0, %%1, %%%s2", inst_pre
, letter
);
1916 snprintf (score3_ins
, INS_BUF_SZ
, "%s\t%%0, %%1, %%%s2", inst_pre
, letter
);
1920 /* Output a Score3 casesi instruction. */
1922 score3_output_casesi (rtx
*operands
)
1924 rtx diff_vec
= PATTERN (next_real_insn (operands
[2]));
1925 gcc_assert (GET_CODE (diff_vec
) == ADDR_DIFF_VEC
);
1927 output_asm_insn ("cmpi.c\t%0, %1", operands
);
1928 output_asm_insn ("bgtu\t%3", operands
);
1929 switch (GET_MODE(diff_vec
))
1932 output_asm_insn ("ldi48\t%4, %2", operands
);
1933 output_asm_insn ("ltbb\t%4, [%4, %0]\n%2_tbb:", operands
);
1936 output_asm_insn ("ldi48\t%4, %2", operands
);
1937 output_asm_insn ("ltbh\t%4, [%4, %0]\n%2_tbb:", operands
);
1940 output_asm_insn ("ldi48\t%4, %2", operands
);
1941 output_asm_insn ("ltbw\t%4, [%4, %0]", operands
);