1 /* score7.c for Sunplus S+CORE processor
2 Copyright (C) 2005, 2007, 2008 Free Software Foundation, Inc.
3 Contributed by Sunnorth
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published
9 by the Free Software Foundation; either version 3, or (at your
10 option) any later version.
12 GCC is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
15 License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
23 #include "coretypes.h"
27 #include "hard-reg-set.h"
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 score7_sdata_max
;
63 static char score7_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 score7_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 score7_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 score7_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
)) <= SCORE7_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 score7_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 score7_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 score7_frame_info
*
169 score7_cached_frame (void)
171 static struct score7_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 score7_frame_info
*
178 score7_compute_frame_size (HOST_WIDE_INT size
)
181 struct score7_frame_info
*f
= score7_cached_frame ();
183 memset (f
, 0, sizeof (struct score7_frame_info
));
186 f
->var_size
= SCORE7_STACK_ALIGN (size
);
187 f
->args_size
= crtl
->outgoing_args_size
;
188 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 (score7_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 score7_valid_base_register_p (rtx x
, int strict
)
239 if (!strict
&& GET_CODE (x
) == SUBREG
)
242 return (GET_CODE (x
) == REG
243 && score7_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 score7_classify_address (struct score7_address_info
*info
,
251 enum machine_mode mode
, rtx x
, int strict
)
253 info
->code
= GET_CODE (x
);
259 info
->type
= SCORE7_ADD_REG
;
261 info
->offset
= const0_rtx
;
262 return score7_valid_base_register_p (info
->reg
, strict
);
264 info
->type
= SCORE7_ADD_REG
;
265 info
->reg
= XEXP (x
, 0);
266 info
->offset
= XEXP (x
, 1);
267 return (score7_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
= SCORE7_ADD_REG
;
277 info
->reg
= XEXP (x
, 0);
278 info
->offset
= GEN_INT (GET_MODE_SIZE (mode
));
279 return score7_valid_base_register_p (info
->reg
, strict
);
281 info
->type
= SCORE7_ADD_CONST_INT
;
282 return IMM_IN_RANGE (INTVAL (x
), 15, 1);
286 info
->type
= SCORE7_ADD_SYMBOLIC
;
287 return (score7_symbolic_constant_p (x
, &info
->symbol_type
)
288 && (info
->symbol_type
== SYMBOL_GENERAL
289 || info
->symbol_type
== SYMBOL_SMALL_DATA
));
296 score7_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 score7_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 score7_output_mi_thunk (FILE *file
, tree thunk_fndecl ATTRIBUTE_UNUSED
,
323 HOST_WIDE_INT delta
, HOST_WIDE_INT vcall_offset
,
326 rtx this_rtx
, 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_rtx
= gen_rtx_REG (Pmode
, ARG_REG_FIRST
+ 1);
341 this_rtx
= gen_rtx_REG (Pmode
, ARG_REG_FIRST
);
343 /* Add DELTA to THIS_RTX. */
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_rtx
, this_rtx
, offset
));
355 /* If needed, add *(*THIS_RTX + VCALL_OFFSET) to THIS_RTX. */
356 if (vcall_offset
!= 0)
360 /* Set TEMP1 to *THIS_RTX. */
361 emit_move_insn (temp1
, gen_rtx_MEM (Pmode
, this_rtx
));
363 /* Set ADDR to a legitimate address for *THIS_RTX + VCALL_OFFSET. */
364 addr
= score7_add_offset (temp1
, vcall_offset
);
366 /* Load the offset and add it to THIS_RTX. */
367 emit_move_insn (temp1
, gen_rtx_MEM (Pmode
, addr
));
368 emit_insn (gen_add3_insn (this_rtx
, this_rtx
, temp1
));
371 /* Jump to the target function. */
372 fnaddr
= XEXP (DECL_RTL (function
), 0);
373 insn
= emit_call_insn (gen_sibcall_internal_score7 (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 score7_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 score7_split_symbol (rtx temp
, rtx addr
)
411 rtx high
= score7_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 X can
417 be legitimized in a way that the generic machinery might not expect,
418 return the new address. */
420 score7_legitimize_address (rtx x
)
422 enum score_symbol_type symbol_type
;
424 if (score7_symbolic_constant_p (x
, &symbol_type
)
425 && symbol_type
== SYMBOL_GENERAL
)
426 return score7_split_symbol (0, x
);
428 if (GET_CODE (x
) == PLUS
429 && GET_CODE (XEXP (x
, 1)) == CONST_INT
)
431 rtx reg
= XEXP (x
, 0);
432 if (!score7_valid_base_register_p (reg
, 0))
433 reg
= copy_to_mode_reg (Pmode
, reg
);
434 return score7_add_offset (reg
, INTVAL (XEXP (x
, 1)));
440 /* Fill INFO with information about a single argument. CUM is the
441 cumulative state for earlier arguments. MODE is the mode of this
442 argument and TYPE is its type (if known). NAMED is true if this
443 is a named (fixed) argument rather than a variable one. */
445 score7_classify_arg (const CUMULATIVE_ARGS
*cum
, enum machine_mode mode
,
446 tree type
, int named
, struct score7_arg_info
*info
)
449 unsigned int num_words
, max_regs
;
452 if (GET_MODE_CLASS (mode
) == MODE_INT
453 || GET_MODE_CLASS (mode
) == MODE_FLOAT
)
454 even_reg_p
= (GET_MODE_SIZE (mode
) > UNITS_PER_WORD
);
456 if (type
!= NULL_TREE
&& TYPE_ALIGN (type
) > BITS_PER_WORD
&& named
)
459 if (TARGET_MUST_PASS_IN_STACK (mode
, type
))
460 info
->reg_offset
= ARG_REG_NUM
;
463 info
->reg_offset
= cum
->num_gprs
;
465 info
->reg_offset
+= info
->reg_offset
& 1;
469 info
->num_bytes
= int_size_in_bytes (type
);
471 info
->num_bytes
= GET_MODE_SIZE (mode
);
473 num_words
= (info
->num_bytes
+ UNITS_PER_WORD
- 1) / UNITS_PER_WORD
;
474 max_regs
= ARG_REG_NUM
- info
->reg_offset
;
476 /* Partition the argument between registers and stack. */
477 info
->reg_words
= MIN (num_words
, max_regs
);
478 info
->stack_words
= num_words
- info
->reg_words
;
480 /* The alignment applied to registers is also applied to stack arguments. */
481 if (info
->stack_words
)
483 info
->stack_offset
= cum
->stack_words
;
485 info
->stack_offset
+= info
->stack_offset
& 1;
489 /* Set up the stack and frame (if desired) for the function. */
491 score7_function_prologue (FILE *file
, HOST_WIDE_INT size ATTRIBUTE_UNUSED
)
494 struct score7_frame_info
*f
= score7_cached_frame ();
495 HOST_WIDE_INT tsize
= f
->total_size
;
497 fnname
= XSTR (XEXP (DECL_RTL (current_function_decl
), 0), 0);
498 if (!flag_inhibit_size_directive
)
500 fputs ("\t.ent\t", file
);
501 assemble_name (file
, fnname
);
504 assemble_name (file
, fnname
);
507 if (!flag_inhibit_size_directive
)
510 "\t.frame\t%s," HOST_WIDE_INT_PRINT_DEC
",%s, %d\t\t"
511 "# vars= " HOST_WIDE_INT_PRINT_DEC
", regs= %d"
512 ", args= " HOST_WIDE_INT_PRINT_DEC
513 ", gp= " HOST_WIDE_INT_PRINT_DEC
"\n",
514 (reg_names
[(frame_pointer_needed
)
515 ? HARD_FRAME_POINTER_REGNUM
: STACK_POINTER_REGNUM
]),
517 reg_names
[RA_REGNUM
],
518 current_function_is_leaf
? 1 : 0,
524 fprintf(file
, "\t.mask\t0x%08x," HOST_WIDE_INT_PRINT_DEC
"\n",
526 (f
->gp_sp_offset
- f
->total_size
));
530 /* Do any necessary cleanup after a function to restore stack, frame,
533 score7_function_epilogue (FILE *file
,
534 HOST_WIDE_INT size ATTRIBUTE_UNUSED
)
536 if (!flag_inhibit_size_directive
)
539 fnname
= XSTR (XEXP (DECL_RTL (current_function_decl
), 0), 0);
540 fputs ("\t.end\t", file
);
541 assemble_name (file
, fnname
);
546 /* Returns true if X contains a SYMBOL_REF. */
548 score7_symbolic_expression_p (rtx x
)
550 if (GET_CODE (x
) == SYMBOL_REF
)
553 if (GET_CODE (x
) == CONST
)
554 return score7_symbolic_expression_p (XEXP (x
, 0));
557 return score7_symbolic_expression_p (XEXP (x
, 0));
559 if (ARITHMETIC_P (x
))
560 return (score7_symbolic_expression_p (XEXP (x
, 0))
561 || score7_symbolic_expression_p (XEXP (x
, 1)));
566 /* Choose the section to use for the constant rtx expression X that has
569 score7_select_rtx_section (enum machine_mode mode
, rtx x
,
570 unsigned HOST_WIDE_INT align
)
572 if (GET_MODE_SIZE (mode
) <= SCORE7_SDATA_MAX
)
573 return get_named_section (0, ".sdata", 0);
574 else if (flag_pic
&& score7_symbolic_expression_p (x
))
575 return get_named_section (0, ".data.rel.ro", 3);
577 return mergeable_constant_section (mode
, align
, 0);
580 /* Implement TARGET_IN_SMALL_DATA_P. */
582 score7_in_small_data_p (tree decl
)
586 if (TREE_CODE (decl
) == STRING_CST
587 || TREE_CODE (decl
) == FUNCTION_DECL
)
590 if (TREE_CODE (decl
) == VAR_DECL
&& DECL_SECTION_NAME (decl
) != 0)
593 name
= TREE_STRING_POINTER (DECL_SECTION_NAME (decl
));
594 if (strcmp (name
, ".sdata") != 0
595 && strcmp (name
, ".sbss") != 0)
597 if (!DECL_EXTERNAL (decl
))
600 size
= int_size_in_bytes (TREE_TYPE (decl
));
601 return (size
> 0 && size
<= SCORE7_SDATA_MAX
);
604 /* Implement TARGET_ASM_FILE_START. */
606 score7_asm_file_start (void)
608 default_file_start ();
609 fprintf (asm_out_file
, ASM_COMMENT_START
610 "GCC for S+core %s \n", SCORE_GCC_VERSION
);
613 fprintf (asm_out_file
, "\t.set pic\n");
616 /* Implement TARGET_ASM_FILE_END. When using assembler macros, emit
617 .externs for any small-data variables that turned out to be external. */
619 score7_asm_file_end (void)
622 struct extern_list
*p
;
625 fputs ("\n", asm_out_file
);
626 for (p
= extern_head
; p
!= 0; p
= p
->next
)
628 name_tree
= get_identifier (p
->name
);
629 if (!TREE_ASM_WRITTEN (name_tree
)
630 && TREE_SYMBOL_REFERENCED (name_tree
))
632 TREE_ASM_WRITTEN (name_tree
) = 1;
633 fputs ("\t.extern\t", asm_out_file
);
634 assemble_name (asm_out_file
, p
->name
);
635 fprintf (asm_out_file
, ", %d\n", p
->size
);
641 /* Implement OVERRIDE_OPTIONS macro. */
643 score7_override_options (void)
647 score7_sdata_max
= g_switch_set
? g_switch_value
: SCORE7_DEFAULT_SDATA_MAX
;
650 score7_sdata_max
= 0;
651 if (g_switch_set
&& (g_switch_value
!= 0))
652 warning (0, "-fPIC and -G are incompatible");
655 score_char_to_class
['d'] = G32_REGS
;
656 score_char_to_class
['e'] = G16_REGS
;
657 score_char_to_class
['t'] = T32_REGS
;
659 score_char_to_class
['h'] = HI_REG
;
660 score_char_to_class
['l'] = LO_REG
;
661 score_char_to_class
['x'] = CE_REGS
;
663 score_char_to_class
['q'] = CN_REG
;
664 score_char_to_class
['y'] = LC_REG
;
665 score_char_to_class
['z'] = SC_REG
;
666 score_char_to_class
['a'] = SP_REGS
;
668 score_char_to_class
['c'] = CR_REGS
;
671 /* Implement REGNO_REG_CLASS macro. */
673 score7_reg_class (int regno
)
676 gcc_assert (regno
>= 0 && regno
< FIRST_PSEUDO_REGISTER
);
678 if (regno
== FRAME_POINTER_REGNUM
679 || regno
== ARG_POINTER_REGNUM
)
682 for (c
= 0; c
< N_REG_CLASSES
; c
++)
683 if (TEST_HARD_REG_BIT (reg_class_contents
[c
], regno
))
689 /* Implement PREFERRED_RELOAD_CLASS macro. */
691 score7_preferred_reload_class (rtx x ATTRIBUTE_UNUSED
, enum reg_class rclass
)
693 if (reg_class_subset_p (G16_REGS
, rclass
))
695 if (reg_class_subset_p (G32_REGS
, rclass
))
700 /* Implement SECONDARY_INPUT_RELOAD_CLASS
701 and SECONDARY_OUTPUT_RELOAD_CLASS macro. */
703 score7_secondary_reload_class (enum reg_class rclass
,
704 enum machine_mode mode ATTRIBUTE_UNUSED
,
708 if (GET_CODE (x
) == REG
|| GET_CODE(x
) == SUBREG
)
709 regno
= true_regnum (x
);
711 if (!GR_REG_CLASS_P (rclass
))
712 return GP_REG_P (regno
) ? NO_REGS
: G32_REGS
;
716 /* Implement CONST_OK_FOR_LETTER_P macro. */
725 score7_const_ok_for_letter_p (HOST_WIDE_INT value
, char c
)
729 case 'I': return ((value
& 0xffff) == 0);
730 case 'J': return IMM_IN_RANGE (value
, 5, 0);
731 case 'K': return IMM_IN_RANGE (value
, 16, 0);
732 case 'L': return IMM_IN_RANGE (value
, 16, 1);
733 case 'M': return IMM_IN_RANGE (value
, 14, 0);
734 case 'N': return IMM_IN_RANGE (value
, 14, 1);
739 /* Implement EXTRA_CONSTRAINT macro. */
742 score7_extra_constraint (rtx op
, char c
)
747 return GET_CODE (op
) == SYMBOL_REF
;
753 /* Return truth value on whether or not a given hard register
754 can support a given mode. */
756 score7_hard_regno_mode_ok (unsigned int regno
, enum machine_mode mode
)
758 int size
= GET_MODE_SIZE (mode
);
759 enum mode_class mclass
= GET_MODE_CLASS (mode
);
761 if (mclass
== MODE_CC
)
762 return regno
== CC_REGNUM
;
763 else if (regno
== FRAME_POINTER_REGNUM
764 || regno
== ARG_POINTER_REGNUM
)
765 return mclass
== MODE_INT
;
766 else if (GP_REG_P (regno
))
767 /* ((regno <= (GP_REG_LAST- HARD_REGNO_NREGS (dummy, mode)) + 1) */
768 return !(regno
& 1) || (size
<= UNITS_PER_WORD
);
769 else if (CE_REG_P (regno
))
770 return (mclass
== MODE_INT
771 && ((size
<= UNITS_PER_WORD
)
772 || (regno
== CE_REG_FIRST
&& size
== 2 * UNITS_PER_WORD
)));
774 return (mclass
== MODE_INT
) && (size
<= UNITS_PER_WORD
);
777 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
778 pointer or argument pointer. TO is either the stack pointer or
779 hard frame pointer. */
781 score7_initial_elimination_offset (int from
,
782 int to ATTRIBUTE_UNUSED
)
784 struct score7_frame_info
*f
= score7_compute_frame_size (get_frame_size ());
787 case ARG_POINTER_REGNUM
:
788 return f
->total_size
;
789 case FRAME_POINTER_REGNUM
:
796 /* Implement FUNCTION_ARG_ADVANCE macro. */
798 score7_function_arg_advance (CUMULATIVE_ARGS
*cum
, enum machine_mode mode
,
799 tree type
, int named
)
801 struct score7_arg_info info
;
802 score7_classify_arg (cum
, mode
, type
, named
, &info
);
803 cum
->num_gprs
= info
.reg_offset
+ info
.reg_words
;
804 if (info
.stack_words
> 0)
805 cum
->stack_words
= info
.stack_offset
+ info
.stack_words
;
809 /* Implement TARGET_ARG_PARTIAL_BYTES macro. */
811 score7_arg_partial_bytes (CUMULATIVE_ARGS
*cum
,
812 enum machine_mode mode
, tree type
, bool named
)
814 struct score7_arg_info info
;
815 score7_classify_arg (cum
, mode
, type
, named
, &info
);
816 return info
.stack_words
> 0 ? info
.reg_words
* UNITS_PER_WORD
: 0;
819 /* Implement FUNCTION_ARG macro. */
821 score7_function_arg (const CUMULATIVE_ARGS
*cum
, enum machine_mode mode
,
822 tree type
, int named
)
824 struct score7_arg_info info
;
826 if (mode
== VOIDmode
|| !named
)
829 score7_classify_arg (cum
, mode
, type
, named
, &info
);
831 if (info
.reg_offset
== ARG_REG_NUM
)
834 if (!info
.stack_words
)
835 return gen_rtx_REG (mode
, ARG_REG_FIRST
+ info
.reg_offset
);
838 rtx ret
= gen_rtx_PARALLEL (mode
, rtvec_alloc (info
.reg_words
));
839 unsigned int i
, part_offset
= 0;
840 for (i
= 0; i
< info
.reg_words
; i
++)
843 reg
= gen_rtx_REG (SImode
, ARG_REG_FIRST
+ info
.reg_offset
+ i
);
844 XVECEXP (ret
, 0, i
) = gen_rtx_EXPR_LIST (SImode
, reg
,
845 GEN_INT (part_offset
));
846 part_offset
+= UNITS_PER_WORD
;
852 /* Implement FUNCTION_VALUE and LIBCALL_VALUE. For normal calls,
853 VALTYPE is the return type and MODE is VOIDmode. For libcalls,
854 VALTYPE is null and MODE is the mode of the return value. */
856 score7_function_value (tree valtype
, tree func ATTRIBUTE_UNUSED
,
857 enum machine_mode mode
)
862 mode
= TYPE_MODE (valtype
);
863 unsignedp
= TYPE_UNSIGNED (valtype
);
864 mode
= promote_mode (valtype
, mode
, &unsignedp
, 1);
866 return gen_rtx_REG (mode
, RT_REGNUM
);
869 /* Implement INITIALIZE_TRAMPOLINE macro. */
871 score7_initialize_trampoline (rtx ADDR
, rtx FUNC
, rtx CHAIN
)
873 #define FFCACHE "_flush_cache"
874 #define CODE_SIZE (TRAMPOLINE_INSNS * UNITS_PER_WORD)
878 pfunc
= plus_constant (ADDR
, CODE_SIZE
);
879 pchain
= plus_constant (ADDR
, CODE_SIZE
+ GET_MODE_SIZE (SImode
));
881 emit_move_insn (gen_rtx_MEM (SImode
, pfunc
), FUNC
);
882 emit_move_insn (gen_rtx_MEM (SImode
, pchain
), CHAIN
);
883 emit_library_call (gen_rtx_SYMBOL_REF (Pmode
, FFCACHE
),
886 GEN_INT (TRAMPOLINE_SIZE
), SImode
);
891 /* This function is used to implement REG_MODE_OK_FOR_BASE_P macro. */
893 score7_regno_mode_ok_for_base_p (int regno
, int strict
)
895 if (regno
>= FIRST_PSEUDO_REGISTER
)
899 regno
= reg_renumber
[regno
];
901 if (regno
== ARG_POINTER_REGNUM
902 || regno
== FRAME_POINTER_REGNUM
)
904 return GP_REG_P (regno
);
907 /* Implement GO_IF_LEGITIMATE_ADDRESS macro. */
909 score7_address_p (enum machine_mode mode
, rtx x
, int strict
)
911 struct score7_address_info addr
;
913 return score7_classify_address (&addr
, mode
, x
, strict
);
916 /* Return a number assessing the cost of moving a register in class
919 score7_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED
,
920 enum reg_class from
, enum reg_class to
)
922 if (GR_REG_CLASS_P (from
))
924 if (GR_REG_CLASS_P (to
))
926 else if (SP_REG_CLASS_P (to
))
928 else if (CP_REG_CLASS_P (to
))
930 else if (CE_REG_CLASS_P (to
))
933 if (GR_REG_CLASS_P (to
))
935 if (GR_REG_CLASS_P (from
))
937 else if (SP_REG_CLASS_P (from
))
939 else if (CP_REG_CLASS_P (from
))
941 else if (CE_REG_CLASS_P (from
))
947 /* Return the number of instructions needed to load a symbol of the
948 given type into a register. */
950 score7_symbol_insns (enum score_symbol_type type
)
957 case SYMBOL_SMALL_DATA
:
964 /* Return the number of instructions needed to load or store a value
965 of mode MODE at X. Return 0 if X isn't valid for MODE. */
967 score7_address_insns (rtx x
, enum machine_mode mode
)
969 struct score7_address_info addr
;
975 factor
= (GET_MODE_SIZE (mode
) + UNITS_PER_WORD
- 1) / UNITS_PER_WORD
;
977 if (score7_classify_address (&addr
, mode
, x
, false))
981 case SCORE7_ADD_CONST_INT
:
984 case SCORE7_ADD_SYMBOLIC
:
985 return factor
* score7_symbol_insns (addr
.symbol_type
);
990 /* Implement TARGET_RTX_COSTS macro. */
992 score7_rtx_costs (rtx x
, int code
, int outer_code
, int *total
,
993 bool speed ATTRIBUTE_UNUSED
)
995 enum machine_mode mode
= GET_MODE (x
);
1000 if (outer_code
== SET
)
1002 if (CONST_OK_FOR_LETTER_P (INTVAL (x
), 'I')
1003 || CONST_OK_FOR_LETTER_P (INTVAL (x
), 'L'))
1004 *total
= COSTS_N_INSNS (1);
1006 *total
= COSTS_N_INSNS (2);
1008 else if (outer_code
== PLUS
|| outer_code
== MINUS
)
1010 if (CONST_OK_FOR_LETTER_P (INTVAL (x
), 'N'))
1012 else if (CONST_OK_FOR_LETTER_P (INTVAL (x
), 'I')
1013 || CONST_OK_FOR_LETTER_P (INTVAL (x
), 'L'))
1016 *total
= COSTS_N_INSNS (2);
1018 else if (outer_code
== AND
|| outer_code
== IOR
)
1020 if (CONST_OK_FOR_LETTER_P (INTVAL (x
), 'M'))
1022 else if (CONST_OK_FOR_LETTER_P (INTVAL (x
), 'I')
1023 || CONST_OK_FOR_LETTER_P (INTVAL (x
), 'K'))
1026 *total
= COSTS_N_INSNS (2);
1038 *total
= COSTS_N_INSNS (2);
1043 /* If the address is legitimate, return the number of
1044 instructions it needs, otherwise use the default handling. */
1045 int n
= score7_address_insns (XEXP (x
, 0), GET_MODE (x
));
1048 *total
= COSTS_N_INSNS (n
+ 1);
1055 *total
= COSTS_N_INSNS (6);
1059 *total
= COSTS_N_INSNS (1);
1067 *total
= COSTS_N_INSNS (2);
1077 *total
= COSTS_N_INSNS ((GET_CODE (XEXP (x
, 1)) == CONST_INT
)
1084 *total
= COSTS_N_INSNS (4);
1091 *total
= COSTS_N_INSNS (4);
1094 *total
= COSTS_N_INSNS (1);
1100 *total
= COSTS_N_INSNS (4);
1106 *total
= optimize_size
? COSTS_N_INSNS (2) : COSTS_N_INSNS (12);
1113 *total
= optimize_size
? COSTS_N_INSNS (2) : COSTS_N_INSNS (33);
1118 switch (GET_MODE (XEXP (x
, 0)))
1122 if (GET_CODE (XEXP (x
, 0)) == MEM
)
1124 *total
= COSTS_N_INSNS (2);
1126 if (!TARGET_LITTLE_ENDIAN
&&
1127 side_effects_p (XEXP (XEXP (x
, 0), 0)))
1131 *total
= COSTS_N_INSNS (1);
1135 *total
= COSTS_N_INSNS (1);
1145 /* Implement TARGET_ADDRESS_COST macro. */
1147 score7_address_cost (rtx addr
)
1149 return score7_address_insns (addr
, SImode
);
1152 /* Implement ASM_OUTPUT_EXTERNAL macro. */
1154 score7_output_external (FILE *file ATTRIBUTE_UNUSED
,
1155 tree decl
, const char *name
)
1157 register struct extern_list
*p
;
1159 if (score7_in_small_data_p (decl
))
1161 p
= (struct extern_list
*) ggc_alloc (sizeof (struct extern_list
));
1162 p
->next
= extern_head
;
1164 p
->size
= int_size_in_bytes (TREE_TYPE (decl
));
1170 /* Implement RETURN_ADDR_RTX. Note, we do not support moving
1171 back to a previous frame. */
1173 score7_return_addr (int count
, rtx frame ATTRIBUTE_UNUSED
)
1177 return get_hard_reg_initial_val (Pmode
, RA_REGNUM
);
1180 /* Implement PRINT_OPERAND macro. */
1181 /* Score-specific operand codes:
1182 '[' print .set nor1 directive
1183 ']' print .set r1 directive
1184 'U' print hi part of a CONST_INT rtx
1187 'D' print SFmode const double
1188 'S' selectively print "!" if operand is 15bit instruction accessible
1189 'V' print "v!" if operand is 15bit instruction accessible, or "lfh!"
1190 'L' low part of DImode reg operand
1191 'H' high part of DImode reg operand
1192 'C' print part of opcode for a branch condition. */
1194 score7_print_operand (FILE *file
, rtx op
, int c
)
1196 enum rtx_code code
= -1;
1197 if (!PRINT_OPERAND_PUNCT_VALID_P (c
))
1198 code
= GET_CODE (op
);
1202 fprintf (file
, ".set r1\n");
1206 fprintf (file
, "\n\t.set nor1");
1210 gcc_assert (code
== CONST_INT
);
1211 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
,
1212 (INTVAL (op
) >> 16) & 0xffff);
1216 if (GET_CODE (op
) == CONST_DOUBLE
)
1218 rtx temp
= gen_lowpart (SImode
, op
);
1219 gcc_assert (GET_MODE (op
) == SFmode
);
1220 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, INTVAL (temp
) & 0xffffffff);
1223 output_addr_const (file
, op
);
1227 gcc_assert (code
== REG
);
1228 if (G16_REG_P (REGNO (op
)))
1229 fprintf (file
, "!");
1233 gcc_assert (code
== REG
);
1234 fprintf (file
, G16_REG_P (REGNO (op
)) ? "v!" : "lfh!");
1238 enum machine_mode mode
= GET_MODE (XEXP (op
, 0));
1242 case EQ
: fputs ("eq", file
); break;
1243 case NE
: fputs ("ne", file
); break;
1244 case GT
: fputs ("gt", file
); break;
1245 case GE
: fputs (mode
!= CCmode
? "pl" : "ge", file
); break;
1246 case LT
: fputs (mode
!= CCmode
? "mi" : "lt", file
); break;
1247 case LE
: fputs ("le", file
); break;
1248 case GTU
: fputs ("gtu", file
); break;
1249 case GEU
: fputs ("cs", file
); break;
1250 case LTU
: fputs ("cc", file
); break;
1251 case LEU
: fputs ("leu", file
); break;
1253 output_operand_lossage ("invalid operand for code: '%c'", code
);
1258 unsigned HOST_WIDE_INT i
;
1259 unsigned HOST_WIDE_INT pow2mask
= 1;
1260 unsigned HOST_WIDE_INT val
;
1263 for (i
= 0; i
< 32; i
++)
1265 if (val
== pow2mask
)
1269 gcc_assert (i
< 32);
1270 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, i
);
1274 unsigned HOST_WIDE_INT i
;
1275 unsigned HOST_WIDE_INT pow2mask
= 1;
1276 unsigned HOST_WIDE_INT val
;
1279 for (i
= 0; i
< 32; i
++)
1281 if (val
== pow2mask
)
1285 gcc_assert (i
< 32);
1286 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, i
);
1288 else if (code
== REG
)
1290 int regnum
= REGNO (op
);
1291 if ((c
== 'H' && !WORDS_BIG_ENDIAN
)
1292 || (c
== 'L' && WORDS_BIG_ENDIAN
))
1294 fprintf (file
, "%s", reg_names
[regnum
]);
1301 score7_print_operand_address (file
, op
);
1304 output_addr_const (file
, op
);
1309 /* Implement PRINT_OPERAND_ADDRESS macro. */
1311 score7_print_operand_address (FILE *file
, rtx x
)
1313 struct score7_address_info addr
;
1314 enum rtx_code code
= GET_CODE (x
);
1315 enum machine_mode mode
= GET_MODE (x
);
1320 if (score7_classify_address (&addr
, mode
, x
, true))
1324 case SCORE7_ADD_REG
:
1329 fprintf (file
, "[%s,-%ld]+", reg_names
[REGNO (addr
.reg
)],
1330 INTVAL (addr
.offset
));
1333 fprintf (file
, "[%s]+,-%ld", reg_names
[REGNO (addr
.reg
)],
1334 INTVAL (addr
.offset
));
1337 fprintf (file
, "[%s, %ld]+", reg_names
[REGNO (addr
.reg
)],
1338 INTVAL (addr
.offset
));
1341 fprintf (file
, "[%s]+, %ld", reg_names
[REGNO (addr
.reg
)],
1342 INTVAL (addr
.offset
));
1345 if (INTVAL(addr
.offset
) == 0)
1346 fprintf(file
, "[%s]", reg_names
[REGNO (addr
.reg
)]);
1348 fprintf(file
, "[%s, %ld]", reg_names
[REGNO (addr
.reg
)],
1349 INTVAL(addr
.offset
));
1354 case SCORE7_ADD_CONST_INT
:
1355 case SCORE7_ADD_SYMBOLIC
:
1356 output_addr_const (file
, x
);
1360 print_rtl (stderr
, x
);
1364 /* Implement SELECT_CC_MODE macro. */
1366 score7_select_cc_mode (enum rtx_code op
, rtx x
, rtx y
)
1368 if ((op
== EQ
|| op
== NE
|| op
== LT
|| op
== GE
)
1370 && GET_MODE (x
) == SImode
)
1372 switch (GET_CODE (x
))
1390 return (op
== LT
|| op
== GE
) ? CC_Nmode
: CCmode
;
1397 if ((op
== EQ
|| op
== NE
)
1398 && (GET_CODE (y
) == NEG
)
1399 && register_operand (XEXP (y
, 0), SImode
)
1400 && register_operand (x
, SImode
))
1408 /* Generate the prologue instructions for entry into a S+core function. */
1410 score7_prologue (void)
1412 #define EMIT_PL(_rtx) RTX_FRAME_RELATED_P (_rtx) = 1
1414 struct score7_frame_info
*f
= score7_compute_frame_size (get_frame_size ());
1418 size
= f
->total_size
- f
->gp_reg_size
;
1421 emit_insn (gen_cpload_score7 ());
1423 for (regno
= (int) GP_REG_LAST
; regno
>= (int) GP_REG_FIRST
; regno
--)
1425 if (BITSET_P (f
->mask
, regno
- GP_REG_FIRST
))
1427 rtx mem
= gen_rtx_MEM (SImode
,
1428 gen_rtx_PRE_DEC (SImode
, stack_pointer_rtx
));
1429 rtx reg
= gen_rtx_REG (SImode
, regno
);
1430 if (!crtl
->calls_eh_return
)
1431 MEM_READONLY_P (mem
) = 1;
1432 EMIT_PL (emit_insn (gen_pushsi_score7 (mem
, reg
)));
1440 if (CONST_OK_FOR_LETTER_P (-size
, 'L'))
1441 EMIT_PL (emit_insn (gen_add3_insn (stack_pointer_rtx
,
1446 EMIT_PL (emit_move_insn (gen_rtx_REG (Pmode
, SCORE7_PROLOGUE_TEMP_REGNUM
),
1449 (gen_sub3_insn (stack_pointer_rtx
,
1452 SCORE7_PROLOGUE_TEMP_REGNUM
))));
1454 insn
= get_last_insn ();
1456 alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR
,
1457 gen_rtx_SET (VOIDmode
, stack_pointer_rtx
,
1458 plus_constant (stack_pointer_rtx
,
1463 if (frame_pointer_needed
)
1464 EMIT_PL (emit_move_insn (hard_frame_pointer_rtx
, stack_pointer_rtx
));
1466 if (flag_pic
&& f
->cprestore_size
)
1468 if (frame_pointer_needed
)
1469 emit_insn (gen_cprestore_use_fp_score7 (GEN_INT (size
- f
->cprestore_size
)));
1471 emit_insn (gen_cprestore_use_sp_score7 (GEN_INT (size
- f
->cprestore_size
)));
1477 /* Generate the epilogue instructions in a S+core function. */
1479 score7_epilogue (int sibcall_p
)
1481 struct score7_frame_info
*f
= score7_compute_frame_size (get_frame_size ());
1486 size
= f
->total_size
- f
->gp_reg_size
;
1488 if (!frame_pointer_needed
)
1489 base
= stack_pointer_rtx
;
1491 base
= hard_frame_pointer_rtx
;
1495 if (CONST_OK_FOR_LETTER_P (size
, 'L'))
1496 emit_insn (gen_add3_insn (base
, base
, GEN_INT (size
)));
1499 emit_move_insn (gen_rtx_REG (Pmode
, SCORE7_EPILOGUE_TEMP_REGNUM
),
1501 emit_insn (gen_add3_insn (base
, base
,
1503 SCORE7_EPILOGUE_TEMP_REGNUM
)));
1507 if (base
!= stack_pointer_rtx
)
1508 emit_move_insn (stack_pointer_rtx
, base
);
1510 if (crtl
->calls_eh_return
)
1511 emit_insn (gen_add3_insn (stack_pointer_rtx
,
1513 EH_RETURN_STACKADJ_RTX
));
1515 for (regno
= (int) GP_REG_FIRST
; regno
<= (int) GP_REG_LAST
; regno
++)
1517 if (BITSET_P (f
->mask
, regno
- GP_REG_FIRST
))
1519 rtx mem
= gen_rtx_MEM (SImode
,
1520 gen_rtx_POST_INC (SImode
, stack_pointer_rtx
));
1521 rtx reg
= gen_rtx_REG (SImode
, regno
);
1523 if (!crtl
->calls_eh_return
)
1524 MEM_READONLY_P (mem
) = 1;
1526 emit_insn (gen_popsi_score7 (reg
, mem
));
1531 emit_jump_insn (gen_return_internal_score7 (gen_rtx_REG (Pmode
, RA_REGNUM
)));
1535 score7_gen_cmp (enum machine_mode mode
)
1537 emit_insn (gen_rtx_SET (VOIDmode
, gen_rtx_REG (mode
, CC_REGNUM
),
1538 gen_rtx_COMPARE (mode
, cmp_op0
, cmp_op1
)));
1541 /* Return true if X is a symbolic constant that can be calculated in
1542 the same way as a bare symbol. If it is, store the type of the
1543 symbol in *SYMBOL_TYPE. */
1545 score7_symbolic_constant_p (rtx x
, enum score_symbol_type
*symbol_type
)
1547 HOST_WIDE_INT offset
;
1549 score7_split_const (x
, &x
, &offset
);
1550 if (GET_CODE (x
) == SYMBOL_REF
|| GET_CODE (x
) == LABEL_REF
)
1551 *symbol_type
= score7_classify_symbol (x
);
1558 /* if offset > 15bit, must reload */
1559 if (!IMM_IN_RANGE (offset
, 15, 1))
1562 switch (*symbol_type
)
1564 case SYMBOL_GENERAL
:
1566 case SYMBOL_SMALL_DATA
:
1567 return score7_offset_within_object_p (x
, offset
);
1573 score7_movsicc (rtx
*ops
)
1575 enum machine_mode mode
;
1577 mode
= score7_select_cc_mode (GET_CODE (ops
[1]), ops
[2], ops
[3]);
1578 emit_insn (gen_rtx_SET (VOIDmode
, gen_rtx_REG (mode
, CC_REGNUM
),
1579 gen_rtx_COMPARE (mode
, cmp_op0
, cmp_op1
)));
1582 /* Call and sibcall pattern all need call this function. */
1584 score7_call (rtx
*ops
, bool sib
)
1586 rtx addr
= XEXP (ops
[0], 0);
1587 if (!call_insn_operand (addr
, VOIDmode
))
1590 addr
= gen_reg_rtx (Pmode
);
1591 gen_move_insn (addr
, oaddr
);
1595 emit_call_insn (gen_sibcall_internal_score7 (addr
, ops
[1]));
1597 emit_call_insn (gen_call_internal_score7 (addr
, ops
[1]));
1600 /* Call value and sibcall value pattern all need call this function. */
1602 score7_call_value (rtx
*ops
, bool sib
)
1604 rtx result
= ops
[0];
1605 rtx addr
= XEXP (ops
[1], 0);
1608 if (!call_insn_operand (addr
, VOIDmode
))
1611 addr
= gen_reg_rtx (Pmode
);
1612 gen_move_insn (addr
, oaddr
);
1616 emit_call_insn (gen_sibcall_value_internal_score7 (result
, addr
, arg
));
1618 emit_call_insn (gen_call_value_internal_score7 (result
, addr
, arg
));
1623 score7_movdi (rtx
*ops
)
1627 rtx dst0
= score7_subw (dst
, 0);
1628 rtx dst1
= score7_subw (dst
, 1);
1629 rtx src0
= score7_subw (src
, 0);
1630 rtx src1
= score7_subw (src
, 1);
1632 if (GET_CODE (dst0
) == REG
&& reg_overlap_mentioned_p (dst0
, src
))
1634 emit_move_insn (dst1
, src1
);
1635 emit_move_insn (dst0
, src0
);
1639 emit_move_insn (dst0
, src0
);
1640 emit_move_insn (dst1
, src1
);
1645 score7_zero_extract_andi (rtx
*ops
)
1647 if (INTVAL (ops
[1]) == 1 && const_uimm5 (ops
[2], SImode
))
1648 emit_insn (gen_zero_extract_bittst_score7 (ops
[0], ops
[2]));
1651 unsigned HOST_WIDE_INT mask
;
1652 mask
= (0xffffffffU
& ((1U << INTVAL (ops
[1])) - 1U));
1653 mask
= mask
<< INTVAL (ops
[2]);
1654 emit_insn (gen_andsi3_cmp_score7 (ops
[3], ops
[0],
1655 gen_int_mode (mask
, SImode
)));
1659 /* Check addr could be present as PRE/POST mode. */
1661 score7_pindex_mem (rtx addr
)
1663 if (GET_CODE (addr
) == MEM
)
1665 switch (GET_CODE (XEXP (addr
, 0)))
1679 /* Output asm code for ld/sw insn. */
1681 score7_pr_addr_post (rtx
*ops
, int idata
, int iaddr
, char *ip
, enum score_mem_unit unit
)
1683 struct score7_address_info ai
;
1685 gcc_assert (GET_CODE (ops
[idata
]) == REG
);
1686 gcc_assert (score7_classify_address (&ai
, SImode
, XEXP (ops
[iaddr
], 0), true));
1688 if (!score7_pindex_mem (ops
[iaddr
])
1689 && ai
.type
== SCORE7_ADD_REG
1690 && GET_CODE (ai
.offset
) == CONST_INT
1691 && G16_REG_P (REGNO (ops
[idata
]))
1692 && G16_REG_P (REGNO (ai
.reg
)))
1694 if (INTVAL (ai
.offset
) == 0)
1696 ops
[iaddr
] = ai
.reg
;
1697 return snprintf (ip
, INS_BUF_SZ
,
1698 "!\t%%%d, [%%%d]", idata
, iaddr
);
1700 if (REGNO (ai
.reg
) == HARD_FRAME_POINTER_REGNUM
)
1702 HOST_WIDE_INT offset
= INTVAL (ai
.offset
);
1703 if (SCORE_ALIGN_UNIT (offset
, unit
)
1704 && CONST_OK_FOR_LETTER_P (offset
>> unit
, 'J'))
1706 ops
[iaddr
] = ai
.offset
;
1707 return snprintf (ip
, INS_BUF_SZ
,
1708 "p!\t%%%d, %%c%d", idata
, iaddr
);
1712 return snprintf (ip
, INS_BUF_SZ
, "\t%%%d, %%a%d", idata
, iaddr
);
1715 /* Output asm insn for load. */
1717 score7_linsn (rtx
*ops
, enum score_mem_unit unit
, bool sign
)
1719 const char *pre_ins
[] =
1720 {"lbu", "lhu", "lw", "??", "lb", "lh", "lw", "??"};
1723 strcpy (score7_ins
, pre_ins
[(sign
? 4 : 0) + unit
]);
1724 ip
= score7_ins
+ strlen (score7_ins
);
1726 if ((!sign
&& unit
!= SCORE_HWORD
)
1727 || (sign
&& unit
!= SCORE_BYTE
))
1728 score7_pr_addr_post (ops
, 0, 1, ip
, unit
);
1730 snprintf (ip
, INS_BUF_SZ
, "\t%%0, %%a1");
1735 /* Output asm insn for store. */
1737 score7_sinsn (rtx
*ops
, enum score_mem_unit unit
)
1739 const char *pre_ins
[] = {"sb", "sh", "sw"};
1742 strcpy (score7_ins
, pre_ins
[unit
]);
1743 ip
= score7_ins
+ strlen (score7_ins
);
1744 score7_pr_addr_post (ops
, 1, 0, ip
, unit
);
1748 /* Output asm insn for load immediate. */
1750 score7_limm (rtx
*ops
)
1754 gcc_assert (GET_CODE (ops
[0]) == REG
);
1755 gcc_assert (GET_CODE (ops
[1]) == CONST_INT
);
1757 v
= INTVAL (ops
[1]);
1758 if (G16_REG_P (REGNO (ops
[0])) && IMM_IN_RANGE (v
, 8, 0))
1759 return "ldiu!\t%0, %c1";
1760 else if (IMM_IN_RANGE (v
, 16, 1))
1761 return "ldi\t%0, %c1";
1762 else if ((v
& 0xffff) == 0)
1763 return "ldis\t%0, %U1";
1765 return "li\t%0, %c1";
1768 /* Output asm insn for move. */
1770 score7_move (rtx
*ops
)
1772 gcc_assert (GET_CODE (ops
[0]) == REG
);
1773 gcc_assert (GET_CODE (ops
[1]) == REG
);
1775 if (G16_REG_P (REGNO (ops
[0])))
1777 if (G16_REG_P (REGNO (ops
[1])))
1778 return "mv!\t%0, %1";
1780 return "mlfh!\t%0, %1";
1782 else if (G16_REG_P (REGNO (ops
[1])))
1783 return "mhfl!\t%0, %1";
1785 return "mv\t%0, %1";
1788 /* Generate add insn. */
1790 score7_select_add_imm (rtx
*ops
, bool set_cc
)
1792 HOST_WIDE_INT v
= INTVAL (ops
[2]);
1794 gcc_assert (GET_CODE (ops
[2]) == CONST_INT
);
1795 gcc_assert (REGNO (ops
[0]) == REGNO (ops
[1]));
1797 if (set_cc
&& G16_REG_P (REGNO (ops
[0])))
1799 if (v
> 0 && IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT
) v
, 0, 15))
1801 ops
[2] = GEN_INT (ffs (v
) - 1);
1802 return "addei!\t%0, %c2";
1805 if (v
< 0 && IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT
) (-v
), 0, 15))
1807 ops
[2] = GEN_INT (ffs (-v
) - 1);
1808 return "subei!\t%0, %c2";
1813 return "addi.c\t%0, %c2";
1815 return "addi\t%0, %c2";
1818 /* Output arith insn. */
1820 score7_select (rtx
*ops
, const char *inst_pre
,
1821 bool commu
, const char *letter
, bool set_cc
)
1823 gcc_assert (GET_CODE (ops
[0]) == REG
);
1824 gcc_assert (GET_CODE (ops
[1]) == REG
);
1826 if (set_cc
&& G16_REG_P (REGNO (ops
[0]))
1827 && (GET_CODE (ops
[2]) == REG
? G16_REG_P (REGNO (ops
[2])) : 1)
1828 && REGNO (ops
[0]) == REGNO (ops
[1]))
1830 snprintf (score7_ins
, INS_BUF_SZ
, "%s!\t%%0, %%%s2", inst_pre
, letter
);
1834 if (commu
&& set_cc
&& G16_REG_P (REGNO (ops
[0]))
1835 && G16_REG_P (REGNO (ops
[1]))
1836 && REGNO (ops
[0]) == REGNO (ops
[2]))
1838 gcc_assert (GET_CODE (ops
[2]) == REG
);
1839 snprintf (score7_ins
, INS_BUF_SZ
, "%s!\t%%0, %%%s1", inst_pre
, letter
);
1844 snprintf (score7_ins
, INS_BUF_SZ
, "%s.c\t%%0, %%1, %%%s2", inst_pre
, letter
);
1846 snprintf (score7_ins
, INS_BUF_SZ
, "%s\t%%0, %%1, %%%s2", inst_pre
, letter
);