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 extern enum reg_class score_char_to_class
[256];
59 static int score7_sdata_max
;
60 static char score7_ins
[INS_BUF_SZ
+ 8];
62 /* Return true if SYMBOL is a SYMBOL_REF and OFFSET + SYMBOL points
63 to the same object as SYMBOL. */
65 score7_offset_within_object_p (rtx symbol
, HOST_WIDE_INT offset
)
67 if (GET_CODE (symbol
) != SYMBOL_REF
)
70 if (CONSTANT_POOL_ADDRESS_P (symbol
)
72 && offset
< (int)GET_MODE_SIZE (get_pool_mode (symbol
)))
75 if (SYMBOL_REF_DECL (symbol
) != 0
77 && offset
< int_size_in_bytes (TREE_TYPE (SYMBOL_REF_DECL (symbol
))))
83 /* Split X into a base and a constant offset, storing them in *BASE
84 and *OFFSET respectively. */
86 score7_split_const (rtx x
, rtx
*base
, HOST_WIDE_INT
*offset
)
90 if (GET_CODE (x
) == CONST
)
93 if (GET_CODE (x
) == PLUS
&& GET_CODE (XEXP (x
, 1)) == CONST_INT
)
95 *offset
+= INTVAL (XEXP (x
, 1));
102 /* Classify symbol X, which must be a SYMBOL_REF or a LABEL_REF. */
103 static enum score_symbol_type
104 score7_classify_symbol (rtx x
)
106 if (GET_CODE (x
) == LABEL_REF
)
107 return SYMBOL_GENERAL
;
109 gcc_assert (GET_CODE (x
) == SYMBOL_REF
);
111 if (CONSTANT_POOL_ADDRESS_P (x
))
113 if (GET_MODE_SIZE (get_pool_mode (x
)) <= SCORE7_SDATA_MAX
)
114 return SYMBOL_SMALL_DATA
;
115 return SYMBOL_GENERAL
;
117 if (SYMBOL_REF_SMALL_P (x
))
118 return SYMBOL_SMALL_DATA
;
119 return SYMBOL_GENERAL
;
122 /* Return true if the current function must save REGNO. */
124 score7_save_reg_p (unsigned int regno
)
126 /* Check call-saved registers. */
127 if (df_regs_ever_live_p (regno
) && !call_used_regs
[regno
])
130 /* We need to save the old frame pointer before setting up a new one. */
131 if (regno
== HARD_FRAME_POINTER_REGNUM
&& frame_pointer_needed
)
134 /* We need to save the incoming return address if it is ever clobbered
135 within the function. */
136 if (regno
== RA_REGNUM
&& df_regs_ever_live_p (regno
))
142 /* Return one word of double-word value OP, taking into account the fixed
143 endianness of certain registers. HIGH_P is true to select the high part,
144 false to select the low part. */
146 score7_subw (rtx op
, int high_p
)
149 enum machine_mode mode
= GET_MODE (op
);
151 if (mode
== VOIDmode
)
154 byte
= (TARGET_LITTLE_ENDIAN
? high_p
: !high_p
) ? UNITS_PER_WORD
: 0;
156 if (GET_CODE (op
) == REG
&& REGNO (op
) == HI_REGNUM
)
157 return gen_rtx_REG (SImode
, high_p
? HI_REGNUM
: LO_REGNUM
);
159 if (GET_CODE (op
) == MEM
)
160 return adjust_address (op
, SImode
, byte
);
162 return simplify_gen_subreg (SImode
, op
, mode
, byte
);
165 static struct score7_frame_info
*
166 score7_cached_frame (void)
168 static struct score7_frame_info _frame_info
;
172 /* Return the bytes needed to compute the frame pointer from the current
173 stack pointer. SIZE is the size (in bytes) of the local variables. */
174 static struct score7_frame_info
*
175 score7_compute_frame_size (HOST_WIDE_INT size
)
178 struct score7_frame_info
*f
= score7_cached_frame ();
180 memset (f
, 0, sizeof (struct score7_frame_info
));
183 f
->var_size
= SCORE7_STACK_ALIGN (size
);
184 f
->args_size
= crtl
->outgoing_args_size
;
185 f
->cprestore_size
= flag_pic
? UNITS_PER_WORD
: 0;
186 if (f
->var_size
== 0 && current_function_is_leaf
)
187 f
->args_size
= f
->cprestore_size
= 0;
189 if (f
->args_size
== 0 && cfun
->calls_alloca
)
190 f
->args_size
= UNITS_PER_WORD
;
192 f
->total_size
= f
->var_size
+ f
->args_size
+ f
->cprestore_size
;
193 for (regno
= GP_REG_FIRST
; regno
<= GP_REG_LAST
; regno
++)
195 if (score7_save_reg_p (regno
))
197 f
->gp_reg_size
+= GET_MODE_SIZE (SImode
);
198 f
->mask
|= 1 << (regno
- GP_REG_FIRST
);
202 if (crtl
->calls_eh_return
)
207 regno
= EH_RETURN_DATA_REGNO (i
);
208 if (regno
== INVALID_REGNUM
)
210 f
->gp_reg_size
+= GET_MODE_SIZE (SImode
);
211 f
->mask
|= 1 << (regno
- GP_REG_FIRST
);
215 f
->total_size
+= f
->gp_reg_size
;
216 f
->num_gp
= f
->gp_reg_size
/ UNITS_PER_WORD
;
220 HOST_WIDE_INT offset
;
221 offset
= (f
->args_size
+ f
->cprestore_size
+ f
->var_size
222 + f
->gp_reg_size
- GET_MODE_SIZE (SImode
));
223 f
->gp_sp_offset
= offset
;
231 /* Return true if X is a valid base register for the given mode.
232 Allow only hard registers if STRICT. */
234 score7_valid_base_register_p (rtx x
, int strict
)
236 if (!strict
&& GET_CODE (x
) == SUBREG
)
239 return (GET_CODE (x
) == REG
240 && score7_regno_mode_ok_for_base_p (REGNO (x
), strict
));
243 /* Return true if X is a valid address for machine mode MODE. If it is,
244 fill in INFO appropriately. STRICT is true if we should only accept
245 hard base registers. */
247 score7_classify_address (struct score7_address_info
*info
,
248 enum machine_mode mode
, rtx x
, int strict
)
250 info
->code
= GET_CODE (x
);
256 info
->type
= SCORE7_ADD_REG
;
258 info
->offset
= const0_rtx
;
259 return score7_valid_base_register_p (info
->reg
, strict
);
261 info
->type
= SCORE7_ADD_REG
;
262 info
->reg
= XEXP (x
, 0);
263 info
->offset
= XEXP (x
, 1);
264 return (score7_valid_base_register_p (info
->reg
, strict
)
265 && GET_CODE (info
->offset
) == CONST_INT
266 && IMM_IN_RANGE (INTVAL (info
->offset
), 15, 1));
271 if (GET_MODE_SIZE (mode
) > GET_MODE_SIZE (SImode
))
273 info
->type
= SCORE7_ADD_REG
;
274 info
->reg
= XEXP (x
, 0);
275 info
->offset
= GEN_INT (GET_MODE_SIZE (mode
));
276 return score7_valid_base_register_p (info
->reg
, strict
);
278 info
->type
= SCORE7_ADD_CONST_INT
;
279 return IMM_IN_RANGE (INTVAL (x
), 15, 1);
283 info
->type
= SCORE7_ADD_SYMBOLIC
;
284 return (score7_symbolic_constant_p (x
, &info
->symbol_type
)
285 && (info
->symbol_type
== SYMBOL_GENERAL
286 || info
->symbol_type
== SYMBOL_SMALL_DATA
));
293 score7_return_in_memory (tree type
, tree fndecl ATTRIBUTE_UNUSED
)
295 return ((TYPE_MODE (type
) == BLKmode
)
296 || (int_size_in_bytes (type
) > 2 * UNITS_PER_WORD
)
297 || (int_size_in_bytes (type
) == -1));
300 /* Return a legitimate address for REG + OFFSET. */
302 score7_add_offset (rtx reg
, HOST_WIDE_INT offset
)
304 if (!IMM_IN_RANGE (offset
, 15, 1))
306 reg
= expand_simple_binop (GET_MODE (reg
), PLUS
,
307 gen_int_mode (offset
& 0xffffc000,
309 reg
, NULL
, 0, OPTAB_WIDEN
);
313 return plus_constant (reg
, offset
);
316 /* Implement TARGET_ASM_OUTPUT_MI_THUNK. Generate rtl rather than asm text
317 in order to avoid duplicating too much logic from elsewhere. */
319 score7_output_mi_thunk (FILE *file
, tree thunk_fndecl ATTRIBUTE_UNUSED
,
320 HOST_WIDE_INT delta
, HOST_WIDE_INT vcall_offset
,
323 rtx this_rtx
, temp1
, insn
, fnaddr
;
325 /* Pretend to be a post-reload pass while generating rtl. */
326 reload_completed
= 1;
328 /* Mark the end of the (empty) prologue. */
329 emit_note (NOTE_INSN_PROLOGUE_END
);
331 /* We need two temporary registers in some cases. */
332 temp1
= gen_rtx_REG (Pmode
, 8);
334 /* Find out which register contains the "this" pointer. */
335 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function
)), function
))
336 this_rtx
= gen_rtx_REG (Pmode
, ARG_REG_FIRST
+ 1);
338 this_rtx
= gen_rtx_REG (Pmode
, ARG_REG_FIRST
);
340 /* Add DELTA to THIS_RTX. */
343 rtx offset
= GEN_INT (delta
);
344 if (!CONST_OK_FOR_LETTER_P (delta
, 'L'))
346 emit_move_insn (temp1
, offset
);
349 emit_insn (gen_add3_insn (this_rtx
, this_rtx
, offset
));
352 /* If needed, add *(*THIS_RTX + VCALL_OFFSET) to THIS_RTX. */
353 if (vcall_offset
!= 0)
357 /* Set TEMP1 to *THIS_RTX. */
358 emit_move_insn (temp1
, gen_rtx_MEM (Pmode
, this_rtx
));
360 /* Set ADDR to a legitimate address for *THIS_RTX + VCALL_OFFSET. */
361 addr
= score7_add_offset (temp1
, vcall_offset
);
363 /* Load the offset and add it to THIS_RTX. */
364 emit_move_insn (temp1
, gen_rtx_MEM (Pmode
, addr
));
365 emit_insn (gen_add3_insn (this_rtx
, this_rtx
, temp1
));
368 /* Jump to the target function. */
369 fnaddr
= XEXP (DECL_RTL (function
), 0);
370 insn
= emit_call_insn (gen_sibcall_internal_score7 (fnaddr
, const0_rtx
));
371 SIBLING_CALL_P (insn
) = 1;
373 /* Run just enough of rest_of_compilation. This sequence was
374 "borrowed" from alpha.c. */
376 insn_locators_alloc ();
377 split_all_insns_noflow ();
378 shorten_branches (insn
);
379 final_start_function (insn
, file
, 1);
380 final (insn
, file
, 1);
381 final_end_function ();
382 free_after_compilation (cfun
);
384 /* Clean up the vars set above. Note that final_end_function resets
385 the global pointer for us. */
386 reload_completed
= 0;
389 /* Copy VALUE to a register and return that register. If new psuedos
390 are allowed, copy it into a new register, otherwise use DEST. */
392 score7_force_temporary (rtx dest
, rtx value
)
394 if (can_create_pseudo_p ())
395 return force_reg (Pmode
, value
);
398 emit_move_insn (copy_rtx (dest
), value
);
403 /* Return a LO_SUM expression for ADDR. TEMP is as for score_force_temporary
404 and is used to load the high part into a register. */
406 score7_split_symbol (rtx temp
, rtx addr
)
408 rtx high
= score7_force_temporary (temp
,
409 gen_rtx_HIGH (Pmode
, copy_rtx (addr
)));
410 return gen_rtx_LO_SUM (Pmode
, high
, addr
);
413 /* This function is used to implement LEGITIMIZE_ADDRESS. If X can
414 be legitimized in a way that the generic machinery might not expect,
415 return the new address. */
417 score7_legitimize_address (rtx x
)
419 enum score_symbol_type symbol_type
;
421 if (score7_symbolic_constant_p (x
, &symbol_type
)
422 && symbol_type
== SYMBOL_GENERAL
)
423 return score7_split_symbol (0, x
);
425 if (GET_CODE (x
) == PLUS
426 && GET_CODE (XEXP (x
, 1)) == CONST_INT
)
428 rtx reg
= XEXP (x
, 0);
429 if (!score7_valid_base_register_p (reg
, 0))
430 reg
= copy_to_mode_reg (Pmode
, reg
);
431 return score7_add_offset (reg
, INTVAL (XEXP (x
, 1)));
437 /* Fill INFO with information about a single argument. CUM is the
438 cumulative state for earlier arguments. MODE is the mode of this
439 argument and TYPE is its type (if known). NAMED is true if this
440 is a named (fixed) argument rather than a variable one. */
442 score7_classify_arg (const CUMULATIVE_ARGS
*cum
, enum machine_mode mode
,
443 tree type
, int named
, struct score7_arg_info
*info
)
446 unsigned int num_words
, max_regs
;
449 if (GET_MODE_CLASS (mode
) == MODE_INT
450 || GET_MODE_CLASS (mode
) == MODE_FLOAT
)
451 even_reg_p
= (GET_MODE_SIZE (mode
) > UNITS_PER_WORD
);
453 if (type
!= NULL_TREE
&& TYPE_ALIGN (type
) > BITS_PER_WORD
&& named
)
456 if (TARGET_MUST_PASS_IN_STACK (mode
, type
))
457 info
->reg_offset
= ARG_REG_NUM
;
460 info
->reg_offset
= cum
->num_gprs
;
462 info
->reg_offset
+= info
->reg_offset
& 1;
466 info
->num_bytes
= int_size_in_bytes (type
);
468 info
->num_bytes
= GET_MODE_SIZE (mode
);
470 num_words
= (info
->num_bytes
+ UNITS_PER_WORD
- 1) / UNITS_PER_WORD
;
471 max_regs
= ARG_REG_NUM
- info
->reg_offset
;
473 /* Partition the argument between registers and stack. */
474 info
->reg_words
= MIN (num_words
, max_regs
);
475 info
->stack_words
= num_words
- info
->reg_words
;
477 /* The alignment applied to registers is also applied to stack arguments. */
478 if (info
->stack_words
)
480 info
->stack_offset
= cum
->stack_words
;
482 info
->stack_offset
+= info
->stack_offset
& 1;
486 /* Set up the stack and frame (if desired) for the function. */
488 score7_function_prologue (FILE *file
, HOST_WIDE_INT size ATTRIBUTE_UNUSED
)
491 struct score7_frame_info
*f
= score7_cached_frame ();
492 HOST_WIDE_INT tsize
= f
->total_size
;
494 fnname
= XSTR (XEXP (DECL_RTL (current_function_decl
), 0), 0);
495 if (!flag_inhibit_size_directive
)
497 fputs ("\t.ent\t", file
);
498 assemble_name (file
, fnname
);
501 assemble_name (file
, fnname
);
504 if (!flag_inhibit_size_directive
)
507 "\t.frame\t%s," HOST_WIDE_INT_PRINT_DEC
",%s, %d\t\t"
508 "# vars= " HOST_WIDE_INT_PRINT_DEC
", regs= %d"
509 ", args= " HOST_WIDE_INT_PRINT_DEC
510 ", gp= " HOST_WIDE_INT_PRINT_DEC
"\n",
511 (reg_names
[(frame_pointer_needed
)
512 ? HARD_FRAME_POINTER_REGNUM
: STACK_POINTER_REGNUM
]),
514 reg_names
[RA_REGNUM
],
515 current_function_is_leaf
? 1 : 0,
521 fprintf(file
, "\t.mask\t0x%08x," HOST_WIDE_INT_PRINT_DEC
"\n",
523 (f
->gp_sp_offset
- f
->total_size
));
527 /* Do any necessary cleanup after a function to restore stack, frame,
530 score7_function_epilogue (FILE *file
,
531 HOST_WIDE_INT size ATTRIBUTE_UNUSED
)
533 if (!flag_inhibit_size_directive
)
536 fnname
= XSTR (XEXP (DECL_RTL (current_function_decl
), 0), 0);
537 fputs ("\t.end\t", file
);
538 assemble_name (file
, fnname
);
543 /* Returns true if X contains a SYMBOL_REF. */
545 score7_symbolic_expression_p (rtx x
)
547 if (GET_CODE (x
) == SYMBOL_REF
)
550 if (GET_CODE (x
) == CONST
)
551 return score7_symbolic_expression_p (XEXP (x
, 0));
554 return score7_symbolic_expression_p (XEXP (x
, 0));
556 if (ARITHMETIC_P (x
))
557 return (score7_symbolic_expression_p (XEXP (x
, 0))
558 || score7_symbolic_expression_p (XEXP (x
, 1)));
563 /* Choose the section to use for the constant rtx expression X that has
566 score7_select_rtx_section (enum machine_mode mode
, rtx x
,
567 unsigned HOST_WIDE_INT align
)
569 if (GET_MODE_SIZE (mode
) <= SCORE7_SDATA_MAX
)
570 return get_named_section (0, ".sdata", 0);
571 else if (flag_pic
&& score7_symbolic_expression_p (x
))
572 return get_named_section (0, ".data.rel.ro", 3);
574 return mergeable_constant_section (mode
, align
, 0);
577 /* Implement TARGET_IN_SMALL_DATA_P. */
579 score7_in_small_data_p (tree decl
)
583 if (TREE_CODE (decl
) == STRING_CST
584 || TREE_CODE (decl
) == FUNCTION_DECL
)
587 if (TREE_CODE (decl
) == VAR_DECL
&& DECL_SECTION_NAME (decl
) != 0)
590 name
= TREE_STRING_POINTER (DECL_SECTION_NAME (decl
));
591 if (strcmp (name
, ".sdata") != 0
592 && strcmp (name
, ".sbss") != 0)
594 if (!DECL_EXTERNAL (decl
))
597 size
= int_size_in_bytes (TREE_TYPE (decl
));
598 return (size
> 0 && size
<= SCORE7_SDATA_MAX
);
601 /* Implement TARGET_ASM_FILE_START. */
603 score7_asm_file_start (void)
605 default_file_start ();
606 fprintf (asm_out_file
, ASM_COMMENT_START
607 "GCC for S+core %s \n", SCORE_GCC_VERSION
);
610 fprintf (asm_out_file
, "\t.set pic\n");
613 /* Implement TARGET_ASM_FILE_END. When using assembler macros, emit
614 .externs for any small-data variables that turned out to be external. */
616 score7_asm_file_end (void)
619 struct extern_list
*p
;
622 fputs ("\n", asm_out_file
);
623 for (p
= extern_head
; p
!= 0; p
= p
->next
)
625 name_tree
= get_identifier (p
->name
);
626 if (!TREE_ASM_WRITTEN (name_tree
)
627 && TREE_SYMBOL_REFERENCED (name_tree
))
629 TREE_ASM_WRITTEN (name_tree
) = 1;
630 fputs ("\t.extern\t", asm_out_file
);
631 assemble_name (asm_out_file
, p
->name
);
632 fprintf (asm_out_file
, ", %d\n", p
->size
);
638 /* Implement OVERRIDE_OPTIONS macro. */
640 score7_override_options (void)
644 score7_sdata_max
= g_switch_set
? g_switch_value
: SCORE7_DEFAULT_SDATA_MAX
;
647 score7_sdata_max
= 0;
648 if (g_switch_set
&& (g_switch_value
!= 0))
649 warning (0, "-fPIC and -G are incompatible");
652 score_char_to_class
['d'] = G32_REGS
;
653 score_char_to_class
['e'] = G16_REGS
;
654 score_char_to_class
['t'] = T32_REGS
;
656 score_char_to_class
['h'] = HI_REG
;
657 score_char_to_class
['l'] = LO_REG
;
658 score_char_to_class
['x'] = CE_REGS
;
660 score_char_to_class
['q'] = CN_REG
;
661 score_char_to_class
['y'] = LC_REG
;
662 score_char_to_class
['z'] = SC_REG
;
663 score_char_to_class
['a'] = SP_REGS
;
665 score_char_to_class
['c'] = CR_REGS
;
668 /* Implement REGNO_REG_CLASS macro. */
670 score7_reg_class (int regno
)
673 gcc_assert (regno
>= 0 && regno
< FIRST_PSEUDO_REGISTER
);
675 if (regno
== FRAME_POINTER_REGNUM
676 || regno
== ARG_POINTER_REGNUM
)
679 for (c
= 0; c
< N_REG_CLASSES
; c
++)
680 if (TEST_HARD_REG_BIT (reg_class_contents
[c
], regno
))
686 /* Implement PREFERRED_RELOAD_CLASS macro. */
688 score7_preferred_reload_class (rtx x ATTRIBUTE_UNUSED
, enum reg_class rclass
)
690 if (reg_class_subset_p (G16_REGS
, rclass
))
692 if (reg_class_subset_p (G32_REGS
, rclass
))
697 /* Implement SECONDARY_INPUT_RELOAD_CLASS
698 and SECONDARY_OUTPUT_RELOAD_CLASS macro. */
700 score7_secondary_reload_class (enum reg_class rclass
,
701 enum machine_mode mode ATTRIBUTE_UNUSED
,
705 if (GET_CODE (x
) == REG
|| GET_CODE(x
) == SUBREG
)
706 regno
= true_regnum (x
);
708 if (!GR_REG_CLASS_P (rclass
))
709 return GP_REG_P (regno
) ? NO_REGS
: G32_REGS
;
713 /* Implement CONST_OK_FOR_LETTER_P macro. */
722 score7_const_ok_for_letter_p (HOST_WIDE_INT value
, char c
)
726 case 'I': return ((value
& 0xffff) == 0);
727 case 'J': return IMM_IN_RANGE (value
, 5, 0);
728 case 'K': return IMM_IN_RANGE (value
, 16, 0);
729 case 'L': return IMM_IN_RANGE (value
, 16, 1);
730 case 'M': return IMM_IN_RANGE (value
, 14, 0);
731 case 'N': return IMM_IN_RANGE (value
, 14, 1);
736 /* Implement EXTRA_CONSTRAINT macro. */
739 score7_extra_constraint (rtx op
, char c
)
744 return GET_CODE (op
) == SYMBOL_REF
;
750 /* Return truth value on whether or not a given hard register
751 can support a given mode. */
753 score7_hard_regno_mode_ok (unsigned int regno
, enum machine_mode mode
)
755 int size
= GET_MODE_SIZE (mode
);
756 enum mode_class mclass
= GET_MODE_CLASS (mode
);
758 if (mclass
== MODE_CC
)
759 return regno
== CC_REGNUM
;
760 else if (regno
== FRAME_POINTER_REGNUM
761 || regno
== ARG_POINTER_REGNUM
)
762 return mclass
== MODE_INT
;
763 else if (GP_REG_P (regno
))
764 /* ((regno <= (GP_REG_LAST- HARD_REGNO_NREGS (dummy, mode)) + 1) */
765 return !(regno
& 1) || (size
<= UNITS_PER_WORD
);
766 else if (CE_REG_P (regno
))
767 return (mclass
== MODE_INT
768 && ((size
<= UNITS_PER_WORD
)
769 || (regno
== CE_REG_FIRST
&& size
== 2 * UNITS_PER_WORD
)));
771 return (mclass
== MODE_INT
) && (size
<= UNITS_PER_WORD
);
774 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
775 pointer or argument pointer. TO is either the stack pointer or
776 hard frame pointer. */
778 score7_initial_elimination_offset (int from
,
779 int to ATTRIBUTE_UNUSED
)
781 struct score7_frame_info
*f
= score7_compute_frame_size (get_frame_size ());
784 case ARG_POINTER_REGNUM
:
785 return f
->total_size
;
786 case FRAME_POINTER_REGNUM
:
793 /* Implement FUNCTION_ARG_ADVANCE macro. */
795 score7_function_arg_advance (CUMULATIVE_ARGS
*cum
, enum machine_mode mode
,
796 tree type
, int named
)
798 struct score7_arg_info info
;
799 score7_classify_arg (cum
, mode
, type
, named
, &info
);
800 cum
->num_gprs
= info
.reg_offset
+ info
.reg_words
;
801 if (info
.stack_words
> 0)
802 cum
->stack_words
= info
.stack_offset
+ info
.stack_words
;
806 /* Implement TARGET_ARG_PARTIAL_BYTES macro. */
808 score7_arg_partial_bytes (CUMULATIVE_ARGS
*cum
,
809 enum machine_mode mode
, tree type
, bool named
)
811 struct score7_arg_info info
;
812 score7_classify_arg (cum
, mode
, type
, named
, &info
);
813 return info
.stack_words
> 0 ? info
.reg_words
* UNITS_PER_WORD
: 0;
816 /* Implement FUNCTION_ARG macro. */
818 score7_function_arg (const CUMULATIVE_ARGS
*cum
, enum machine_mode mode
,
819 tree type
, int named
)
821 struct score7_arg_info info
;
823 if (mode
== VOIDmode
|| !named
)
826 score7_classify_arg (cum
, mode
, type
, named
, &info
);
828 if (info
.reg_offset
== ARG_REG_NUM
)
831 if (!info
.stack_words
)
832 return gen_rtx_REG (mode
, ARG_REG_FIRST
+ info
.reg_offset
);
835 rtx ret
= gen_rtx_PARALLEL (mode
, rtvec_alloc (info
.reg_words
));
836 unsigned int i
, part_offset
= 0;
837 for (i
= 0; i
< info
.reg_words
; i
++)
840 reg
= gen_rtx_REG (SImode
, ARG_REG_FIRST
+ info
.reg_offset
+ i
);
841 XVECEXP (ret
, 0, i
) = gen_rtx_EXPR_LIST (SImode
, reg
,
842 GEN_INT (part_offset
));
843 part_offset
+= UNITS_PER_WORD
;
849 /* Implement FUNCTION_VALUE and LIBCALL_VALUE. For normal calls,
850 VALTYPE is the return type and MODE is VOIDmode. For libcalls,
851 VALTYPE is null and MODE is the mode of the return value. */
853 score7_function_value (tree valtype
, tree func ATTRIBUTE_UNUSED
,
854 enum machine_mode mode
)
859 mode
= TYPE_MODE (valtype
);
860 unsignedp
= TYPE_UNSIGNED (valtype
);
861 mode
= promote_mode (valtype
, mode
, &unsignedp
, 1);
863 return gen_rtx_REG (mode
, RT_REGNUM
);
866 /* Implement INITIALIZE_TRAMPOLINE macro. */
868 score7_initialize_trampoline (rtx ADDR
, rtx FUNC
, rtx CHAIN
)
870 #define FFCACHE "_flush_cache"
871 #define CODE_SIZE (TRAMPOLINE_INSNS * UNITS_PER_WORD)
875 pfunc
= plus_constant (ADDR
, CODE_SIZE
);
876 pchain
= plus_constant (ADDR
, CODE_SIZE
+ GET_MODE_SIZE (SImode
));
878 emit_move_insn (gen_rtx_MEM (SImode
, pfunc
), FUNC
);
879 emit_move_insn (gen_rtx_MEM (SImode
, pchain
), CHAIN
);
880 emit_library_call (gen_rtx_SYMBOL_REF (Pmode
, FFCACHE
),
883 GEN_INT (TRAMPOLINE_SIZE
), SImode
);
888 /* This function is used to implement REG_MODE_OK_FOR_BASE_P macro. */
890 score7_regno_mode_ok_for_base_p (int regno
, int strict
)
892 if (regno
>= FIRST_PSEUDO_REGISTER
)
896 regno
= reg_renumber
[regno
];
898 if (regno
== ARG_POINTER_REGNUM
899 || regno
== FRAME_POINTER_REGNUM
)
901 return GP_REG_P (regno
);
904 /* Implement GO_IF_LEGITIMATE_ADDRESS macro. */
906 score7_legitimate_address_p (enum machine_mode mode
, rtx x
, bool strict
)
908 struct score7_address_info addr
;
910 return score7_classify_address (&addr
, mode
, x
, strict
);
913 /* Return a number assessing the cost of moving a register in class
916 score7_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED
,
917 enum reg_class from
, enum reg_class to
)
919 if (GR_REG_CLASS_P (from
))
921 if (GR_REG_CLASS_P (to
))
923 else if (SP_REG_CLASS_P (to
))
925 else if (CP_REG_CLASS_P (to
))
927 else if (CE_REG_CLASS_P (to
))
930 if (GR_REG_CLASS_P (to
))
932 if (GR_REG_CLASS_P (from
))
934 else if (SP_REG_CLASS_P (from
))
936 else if (CP_REG_CLASS_P (from
))
938 else if (CE_REG_CLASS_P (from
))
944 /* Return the number of instructions needed to load a symbol of the
945 given type into a register. */
947 score7_symbol_insns (enum score_symbol_type type
)
954 case SYMBOL_SMALL_DATA
:
961 /* Return the number of instructions needed to load or store a value
962 of mode MODE at X. Return 0 if X isn't valid for MODE. */
964 score7_address_insns (rtx x
, enum machine_mode mode
)
966 struct score7_address_info addr
;
972 factor
= (GET_MODE_SIZE (mode
) + UNITS_PER_WORD
- 1) / UNITS_PER_WORD
;
974 if (score7_classify_address (&addr
, mode
, x
, false))
978 case SCORE7_ADD_CONST_INT
:
981 case SCORE7_ADD_SYMBOLIC
:
982 return factor
* score7_symbol_insns (addr
.symbol_type
);
987 /* Implement TARGET_RTX_COSTS macro. */
989 score7_rtx_costs (rtx x
, int code
, int outer_code
, int *total
,
990 bool speed ATTRIBUTE_UNUSED
)
992 enum machine_mode mode
= GET_MODE (x
);
997 if (outer_code
== SET
)
999 if (CONST_OK_FOR_LETTER_P (INTVAL (x
), 'I')
1000 || CONST_OK_FOR_LETTER_P (INTVAL (x
), 'L'))
1001 *total
= COSTS_N_INSNS (1);
1003 *total
= COSTS_N_INSNS (2);
1005 else if (outer_code
== PLUS
|| outer_code
== MINUS
)
1007 if (CONST_OK_FOR_LETTER_P (INTVAL (x
), 'N'))
1009 else if (CONST_OK_FOR_LETTER_P (INTVAL (x
), 'I')
1010 || CONST_OK_FOR_LETTER_P (INTVAL (x
), 'L'))
1013 *total
= COSTS_N_INSNS (2);
1015 else if (outer_code
== AND
|| outer_code
== IOR
)
1017 if (CONST_OK_FOR_LETTER_P (INTVAL (x
), 'M'))
1019 else if (CONST_OK_FOR_LETTER_P (INTVAL (x
), 'I')
1020 || CONST_OK_FOR_LETTER_P (INTVAL (x
), 'K'))
1023 *total
= COSTS_N_INSNS (2);
1035 *total
= COSTS_N_INSNS (2);
1040 /* If the address is legitimate, return the number of
1041 instructions it needs, otherwise use the default handling. */
1042 int n
= score7_address_insns (XEXP (x
, 0), GET_MODE (x
));
1045 *total
= COSTS_N_INSNS (n
+ 1);
1052 *total
= COSTS_N_INSNS (6);
1056 *total
= COSTS_N_INSNS (1);
1064 *total
= COSTS_N_INSNS (2);
1074 *total
= COSTS_N_INSNS ((GET_CODE (XEXP (x
, 1)) == CONST_INT
)
1081 *total
= COSTS_N_INSNS (4);
1088 *total
= COSTS_N_INSNS (4);
1091 *total
= COSTS_N_INSNS (1);
1097 *total
= COSTS_N_INSNS (4);
1103 *total
= optimize_size
? COSTS_N_INSNS (2) : COSTS_N_INSNS (12);
1110 *total
= optimize_size
? COSTS_N_INSNS (2) : COSTS_N_INSNS (33);
1115 switch (GET_MODE (XEXP (x
, 0)))
1119 if (GET_CODE (XEXP (x
, 0)) == MEM
)
1121 *total
= COSTS_N_INSNS (2);
1123 if (!TARGET_LITTLE_ENDIAN
&&
1124 side_effects_p (XEXP (XEXP (x
, 0), 0)))
1128 *total
= COSTS_N_INSNS (1);
1132 *total
= COSTS_N_INSNS (1);
1142 /* Implement TARGET_ADDRESS_COST macro. */
1144 score7_address_cost (rtx addr
)
1146 return score7_address_insns (addr
, SImode
);
1149 /* Implement ASM_OUTPUT_EXTERNAL macro. */
1151 score7_output_external (FILE *file ATTRIBUTE_UNUSED
,
1152 tree decl
, const char *name
)
1154 register struct extern_list
*p
;
1156 if (score7_in_small_data_p (decl
))
1158 p
= (struct extern_list
*) ggc_alloc (sizeof (struct extern_list
));
1159 p
->next
= extern_head
;
1161 p
->size
= int_size_in_bytes (TREE_TYPE (decl
));
1167 /* Implement RETURN_ADDR_RTX. Note, we do not support moving
1168 back to a previous frame. */
1170 score7_return_addr (int count
, rtx frame ATTRIBUTE_UNUSED
)
1174 return get_hard_reg_initial_val (Pmode
, RA_REGNUM
);
1177 /* Implement PRINT_OPERAND macro. */
1178 /* Score-specific operand codes:
1179 '[' print .set nor1 directive
1180 ']' print .set r1 directive
1181 'U' print hi part of a CONST_INT rtx
1184 'D' print SFmode const double
1185 'S' selectively print "!" if operand is 15bit instruction accessible
1186 'V' print "v!" if operand is 15bit instruction accessible, or "lfh!"
1187 'L' low part of DImode reg operand
1188 'H' high part of DImode reg operand
1189 'C' print part of opcode for a branch condition. */
1191 score7_print_operand (FILE *file
, rtx op
, int c
)
1193 enum rtx_code code
= -1;
1194 if (!PRINT_OPERAND_PUNCT_VALID_P (c
))
1195 code
= GET_CODE (op
);
1199 fprintf (file
, ".set r1\n");
1203 fprintf (file
, "\n\t.set nor1");
1207 gcc_assert (code
== CONST_INT
);
1208 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
,
1209 (INTVAL (op
) >> 16) & 0xffff);
1213 if (GET_CODE (op
) == CONST_DOUBLE
)
1215 rtx temp
= gen_lowpart (SImode
, op
);
1216 gcc_assert (GET_MODE (op
) == SFmode
);
1217 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, INTVAL (temp
) & 0xffffffff);
1220 output_addr_const (file
, op
);
1224 gcc_assert (code
== REG
);
1225 if (G16_REG_P (REGNO (op
)))
1226 fprintf (file
, "!");
1230 gcc_assert (code
== REG
);
1231 fprintf (file
, G16_REG_P (REGNO (op
)) ? "v!" : "lfh!");
1235 enum machine_mode mode
= GET_MODE (XEXP (op
, 0));
1239 case EQ
: fputs ("eq", file
); break;
1240 case NE
: fputs ("ne", file
); break;
1241 case GT
: fputs ("gt", file
); break;
1242 case GE
: fputs (mode
!= CCmode
? "pl" : "ge", file
); break;
1243 case LT
: fputs (mode
!= CCmode
? "mi" : "lt", file
); break;
1244 case LE
: fputs ("le", file
); break;
1245 case GTU
: fputs ("gtu", file
); break;
1246 case GEU
: fputs ("cs", file
); break;
1247 case LTU
: fputs ("cc", file
); break;
1248 case LEU
: fputs ("leu", file
); break;
1250 output_operand_lossage ("invalid operand for code: '%c'", code
);
1255 unsigned HOST_WIDE_INT i
;
1256 unsigned HOST_WIDE_INT pow2mask
= 1;
1257 unsigned HOST_WIDE_INT val
;
1260 for (i
= 0; i
< 32; i
++)
1262 if (val
== pow2mask
)
1266 gcc_assert (i
< 32);
1267 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, i
);
1271 unsigned HOST_WIDE_INT i
;
1272 unsigned HOST_WIDE_INT pow2mask
= 1;
1273 unsigned HOST_WIDE_INT val
;
1276 for (i
= 0; i
< 32; i
++)
1278 if (val
== pow2mask
)
1282 gcc_assert (i
< 32);
1283 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, i
);
1285 else if (code
== REG
)
1287 int regnum
= REGNO (op
);
1288 if ((c
== 'H' && !WORDS_BIG_ENDIAN
)
1289 || (c
== 'L' && WORDS_BIG_ENDIAN
))
1291 fprintf (file
, "%s", reg_names
[regnum
]);
1298 score7_print_operand_address (file
, op
);
1301 output_addr_const (file
, op
);
1306 /* Implement PRINT_OPERAND_ADDRESS macro. */
1308 score7_print_operand_address (FILE *file
, rtx x
)
1310 struct score7_address_info addr
;
1311 enum rtx_code code
= GET_CODE (x
);
1312 enum machine_mode mode
= GET_MODE (x
);
1317 if (score7_classify_address (&addr
, mode
, x
, true))
1321 case SCORE7_ADD_REG
:
1326 fprintf (file
, "[%s,-%ld]+", reg_names
[REGNO (addr
.reg
)],
1327 INTVAL (addr
.offset
));
1330 fprintf (file
, "[%s]+,-%ld", reg_names
[REGNO (addr
.reg
)],
1331 INTVAL (addr
.offset
));
1334 fprintf (file
, "[%s, %ld]+", reg_names
[REGNO (addr
.reg
)],
1335 INTVAL (addr
.offset
));
1338 fprintf (file
, "[%s]+, %ld", reg_names
[REGNO (addr
.reg
)],
1339 INTVAL (addr
.offset
));
1342 if (INTVAL(addr
.offset
) == 0)
1343 fprintf(file
, "[%s]", reg_names
[REGNO (addr
.reg
)]);
1345 fprintf(file
, "[%s, %ld]", reg_names
[REGNO (addr
.reg
)],
1346 INTVAL(addr
.offset
));
1351 case SCORE7_ADD_CONST_INT
:
1352 case SCORE7_ADD_SYMBOLIC
:
1353 output_addr_const (file
, x
);
1357 print_rtl (stderr
, x
);
1361 /* Implement SELECT_CC_MODE macro. */
1363 score7_select_cc_mode (enum rtx_code op
, rtx x
, rtx y
)
1365 if ((op
== EQ
|| op
== NE
|| op
== LT
|| op
== GE
)
1367 && GET_MODE (x
) == SImode
)
1369 switch (GET_CODE (x
))
1387 return (op
== LT
|| op
== GE
) ? CC_Nmode
: CCmode
;
1394 if ((op
== EQ
|| op
== NE
)
1395 && (GET_CODE (y
) == NEG
)
1396 && register_operand (XEXP (y
, 0), SImode
)
1397 && register_operand (x
, SImode
))
1405 /* Generate the prologue instructions for entry into a S+core function. */
1407 score7_prologue (void)
1409 #define EMIT_PL(_rtx) RTX_FRAME_RELATED_P (_rtx) = 1
1411 struct score7_frame_info
*f
= score7_compute_frame_size (get_frame_size ());
1415 size
= f
->total_size
- f
->gp_reg_size
;
1418 emit_insn (gen_cpload_score7 ());
1420 for (regno
= (int) GP_REG_LAST
; regno
>= (int) GP_REG_FIRST
; regno
--)
1422 if (BITSET_P (f
->mask
, regno
- GP_REG_FIRST
))
1424 rtx mem
= gen_rtx_MEM (SImode
,
1425 gen_rtx_PRE_DEC (SImode
, stack_pointer_rtx
));
1426 rtx reg
= gen_rtx_REG (SImode
, regno
);
1427 if (!crtl
->calls_eh_return
)
1428 MEM_READONLY_P (mem
) = 1;
1429 EMIT_PL (emit_insn (gen_pushsi_score7 (mem
, reg
)));
1437 if (CONST_OK_FOR_LETTER_P (-size
, 'L'))
1438 EMIT_PL (emit_insn (gen_add3_insn (stack_pointer_rtx
,
1443 EMIT_PL (emit_move_insn (gen_rtx_REG (Pmode
, SCORE7_PROLOGUE_TEMP_REGNUM
),
1446 (gen_sub3_insn (stack_pointer_rtx
,
1449 SCORE7_PROLOGUE_TEMP_REGNUM
))));
1451 insn
= get_last_insn ();
1453 alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR
,
1454 gen_rtx_SET (VOIDmode
, stack_pointer_rtx
,
1455 plus_constant (stack_pointer_rtx
,
1460 if (frame_pointer_needed
)
1461 EMIT_PL (emit_move_insn (hard_frame_pointer_rtx
, stack_pointer_rtx
));
1463 if (flag_pic
&& f
->cprestore_size
)
1465 if (frame_pointer_needed
)
1466 emit_insn (gen_cprestore_use_fp_score7 (GEN_INT (size
- f
->cprestore_size
)));
1468 emit_insn (gen_cprestore_use_sp_score7 (GEN_INT (size
- f
->cprestore_size
)));
1474 /* Generate the epilogue instructions in a S+core function. */
1476 score7_epilogue (int sibcall_p
)
1478 struct score7_frame_info
*f
= score7_compute_frame_size (get_frame_size ());
1483 size
= f
->total_size
- f
->gp_reg_size
;
1485 if (!frame_pointer_needed
)
1486 base
= stack_pointer_rtx
;
1488 base
= hard_frame_pointer_rtx
;
1492 if (CONST_OK_FOR_LETTER_P (size
, 'L'))
1493 emit_insn (gen_add3_insn (base
, base
, GEN_INT (size
)));
1496 emit_move_insn (gen_rtx_REG (Pmode
, SCORE7_EPILOGUE_TEMP_REGNUM
),
1498 emit_insn (gen_add3_insn (base
, base
,
1500 SCORE7_EPILOGUE_TEMP_REGNUM
)));
1504 if (base
!= stack_pointer_rtx
)
1505 emit_move_insn (stack_pointer_rtx
, base
);
1507 if (crtl
->calls_eh_return
)
1508 emit_insn (gen_add3_insn (stack_pointer_rtx
,
1510 EH_RETURN_STACKADJ_RTX
));
1512 for (regno
= (int) GP_REG_FIRST
; regno
<= (int) GP_REG_LAST
; regno
++)
1514 if (BITSET_P (f
->mask
, regno
- GP_REG_FIRST
))
1516 rtx mem
= gen_rtx_MEM (SImode
,
1517 gen_rtx_POST_INC (SImode
, stack_pointer_rtx
));
1518 rtx reg
= gen_rtx_REG (SImode
, regno
);
1520 if (!crtl
->calls_eh_return
)
1521 MEM_READONLY_P (mem
) = 1;
1523 emit_insn (gen_popsi_score7 (reg
, mem
));
1528 emit_jump_insn (gen_return_internal_score7 (gen_rtx_REG (Pmode
, RA_REGNUM
)));
1531 /* Return true if X is a symbolic constant that can be calculated in
1532 the same way as a bare symbol. If it is, store the type of the
1533 symbol in *SYMBOL_TYPE. */
1535 score7_symbolic_constant_p (rtx x
, enum score_symbol_type
*symbol_type
)
1537 HOST_WIDE_INT offset
;
1539 score7_split_const (x
, &x
, &offset
);
1540 if (GET_CODE (x
) == SYMBOL_REF
|| GET_CODE (x
) == LABEL_REF
)
1541 *symbol_type
= score7_classify_symbol (x
);
1548 /* if offset > 15bit, must reload */
1549 if (!IMM_IN_RANGE (offset
, 15, 1))
1552 switch (*symbol_type
)
1554 case SYMBOL_GENERAL
:
1556 case SYMBOL_SMALL_DATA
:
1557 return score7_offset_within_object_p (x
, offset
);
1563 score7_movsicc (rtx
*ops
)
1565 enum machine_mode mode
;
1567 mode
= score7_select_cc_mode (GET_CODE (ops
[1]), ops
[2], ops
[3]);
1568 emit_insn (gen_rtx_SET (VOIDmode
, gen_rtx_REG (mode
, CC_REGNUM
),
1569 gen_rtx_COMPARE (mode
, XEXP (ops
[1], 0),
1570 XEXP (ops
[1], 1))));
1573 /* Call and sibcall pattern all need call this function. */
1575 score7_call (rtx
*ops
, bool sib
)
1577 rtx addr
= XEXP (ops
[0], 0);
1578 if (!call_insn_operand (addr
, VOIDmode
))
1581 addr
= gen_reg_rtx (Pmode
);
1582 gen_move_insn (addr
, oaddr
);
1586 emit_call_insn (gen_sibcall_internal_score7 (addr
, ops
[1]));
1588 emit_call_insn (gen_call_internal_score7 (addr
, ops
[1]));
1591 /* Call value and sibcall value pattern all need call this function. */
1593 score7_call_value (rtx
*ops
, bool sib
)
1595 rtx result
= ops
[0];
1596 rtx addr
= XEXP (ops
[1], 0);
1599 if (!call_insn_operand (addr
, VOIDmode
))
1602 addr
= gen_reg_rtx (Pmode
);
1603 gen_move_insn (addr
, oaddr
);
1607 emit_call_insn (gen_sibcall_value_internal_score7 (result
, addr
, arg
));
1609 emit_call_insn (gen_call_value_internal_score7 (result
, addr
, arg
));
1614 score7_movdi (rtx
*ops
)
1618 rtx dst0
= score7_subw (dst
, 0);
1619 rtx dst1
= score7_subw (dst
, 1);
1620 rtx src0
= score7_subw (src
, 0);
1621 rtx src1
= score7_subw (src
, 1);
1623 if (GET_CODE (dst0
) == REG
&& reg_overlap_mentioned_p (dst0
, src
))
1625 emit_move_insn (dst1
, src1
);
1626 emit_move_insn (dst0
, src0
);
1630 emit_move_insn (dst0
, src0
);
1631 emit_move_insn (dst1
, src1
);
1636 score7_zero_extract_andi (rtx
*ops
)
1638 if (INTVAL (ops
[1]) == 1 && const_uimm5 (ops
[2], SImode
))
1639 emit_insn (gen_zero_extract_bittst_score7 (ops
[0], ops
[2]));
1642 unsigned HOST_WIDE_INT mask
;
1643 mask
= (0xffffffffU
& ((1U << INTVAL (ops
[1])) - 1U));
1644 mask
= mask
<< INTVAL (ops
[2]);
1645 emit_insn (gen_andsi3_cmp_score7 (ops
[3], ops
[0],
1646 gen_int_mode (mask
, SImode
)));
1650 /* Check addr could be present as PRE/POST mode. */
1652 score7_pindex_mem (rtx addr
)
1654 if (GET_CODE (addr
) == MEM
)
1656 switch (GET_CODE (XEXP (addr
, 0)))
1670 /* Output asm code for ld/sw insn. */
1672 score7_pr_addr_post (rtx
*ops
, int idata
, int iaddr
, char *ip
, enum score_mem_unit unit
)
1674 struct score7_address_info ai
;
1676 gcc_assert (GET_CODE (ops
[idata
]) == REG
);
1677 gcc_assert (score7_classify_address (&ai
, SImode
, XEXP (ops
[iaddr
], 0), true));
1679 if (!score7_pindex_mem (ops
[iaddr
])
1680 && ai
.type
== SCORE7_ADD_REG
1681 && GET_CODE (ai
.offset
) == CONST_INT
1682 && G16_REG_P (REGNO (ops
[idata
]))
1683 && G16_REG_P (REGNO (ai
.reg
)))
1685 if (INTVAL (ai
.offset
) == 0)
1687 ops
[iaddr
] = ai
.reg
;
1688 return snprintf (ip
, INS_BUF_SZ
,
1689 "!\t%%%d, [%%%d]", idata
, iaddr
);
1691 if (REGNO (ai
.reg
) == HARD_FRAME_POINTER_REGNUM
)
1693 HOST_WIDE_INT offset
= INTVAL (ai
.offset
);
1694 if (SCORE_ALIGN_UNIT (offset
, unit
)
1695 && CONST_OK_FOR_LETTER_P (offset
>> unit
, 'J'))
1697 ops
[iaddr
] = ai
.offset
;
1698 return snprintf (ip
, INS_BUF_SZ
,
1699 "p!\t%%%d, %%c%d", idata
, iaddr
);
1703 return snprintf (ip
, INS_BUF_SZ
, "\t%%%d, %%a%d", idata
, iaddr
);
1706 /* Output asm insn for load. */
1708 score7_linsn (rtx
*ops
, enum score_mem_unit unit
, bool sign
)
1710 const char *pre_ins
[] =
1711 {"lbu", "lhu", "lw", "??", "lb", "lh", "lw", "??"};
1714 strcpy (score7_ins
, pre_ins
[(sign
? 4 : 0) + unit
]);
1715 ip
= score7_ins
+ strlen (score7_ins
);
1717 if ((!sign
&& unit
!= SCORE_HWORD
)
1718 || (sign
&& unit
!= SCORE_BYTE
))
1719 score7_pr_addr_post (ops
, 0, 1, ip
, unit
);
1721 snprintf (ip
, INS_BUF_SZ
, "\t%%0, %%a1");
1726 /* Output asm insn for store. */
1728 score7_sinsn (rtx
*ops
, enum score_mem_unit unit
)
1730 const char *pre_ins
[] = {"sb", "sh", "sw"};
1733 strcpy (score7_ins
, pre_ins
[unit
]);
1734 ip
= score7_ins
+ strlen (score7_ins
);
1735 score7_pr_addr_post (ops
, 1, 0, ip
, unit
);
1739 /* Output asm insn for load immediate. */
1741 score7_limm (rtx
*ops
)
1745 gcc_assert (GET_CODE (ops
[0]) == REG
);
1746 gcc_assert (GET_CODE (ops
[1]) == CONST_INT
);
1748 v
= INTVAL (ops
[1]);
1749 if (G16_REG_P (REGNO (ops
[0])) && IMM_IN_RANGE (v
, 8, 0))
1750 return "ldiu!\t%0, %c1";
1751 else if (IMM_IN_RANGE (v
, 16, 1))
1752 return "ldi\t%0, %c1";
1753 else if ((v
& 0xffff) == 0)
1754 return "ldis\t%0, %U1";
1756 return "li\t%0, %c1";
1759 /* Output asm insn for move. */
1761 score7_move (rtx
*ops
)
1763 gcc_assert (GET_CODE (ops
[0]) == REG
);
1764 gcc_assert (GET_CODE (ops
[1]) == REG
);
1766 if (G16_REG_P (REGNO (ops
[0])))
1768 if (G16_REG_P (REGNO (ops
[1])))
1769 return "mv!\t%0, %1";
1771 return "mlfh!\t%0, %1";
1773 else if (G16_REG_P (REGNO (ops
[1])))
1774 return "mhfl!\t%0, %1";
1776 return "mv\t%0, %1";
1779 /* Generate add insn. */
1781 score7_select_add_imm (rtx
*ops
, bool set_cc
)
1783 HOST_WIDE_INT v
= INTVAL (ops
[2]);
1785 gcc_assert (GET_CODE (ops
[2]) == CONST_INT
);
1786 gcc_assert (REGNO (ops
[0]) == REGNO (ops
[1]));
1788 if (set_cc
&& G16_REG_P (REGNO (ops
[0])))
1790 if (v
> 0 && IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT
) v
, 0, 15))
1792 ops
[2] = GEN_INT (ffs (v
) - 1);
1793 return "addei!\t%0, %c2";
1796 if (v
< 0 && IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT
) (-v
), 0, 15))
1798 ops
[2] = GEN_INT (ffs (-v
) - 1);
1799 return "subei!\t%0, %c2";
1804 return "addi.c\t%0, %c2";
1806 return "addi\t%0, %c2";
1809 /* Output arith insn. */
1811 score7_select (rtx
*ops
, const char *inst_pre
,
1812 bool commu
, const char *letter
, bool set_cc
)
1814 gcc_assert (GET_CODE (ops
[0]) == REG
);
1815 gcc_assert (GET_CODE (ops
[1]) == REG
);
1817 if (set_cc
&& G16_REG_P (REGNO (ops
[0]))
1818 && (GET_CODE (ops
[2]) == REG
? G16_REG_P (REGNO (ops
[2])) : 1)
1819 && REGNO (ops
[0]) == REGNO (ops
[1]))
1821 snprintf (score7_ins
, INS_BUF_SZ
, "%s!\t%%0, %%%s2", inst_pre
, letter
);
1825 if (commu
&& set_cc
&& G16_REG_P (REGNO (ops
[0]))
1826 && G16_REG_P (REGNO (ops
[1]))
1827 && REGNO (ops
[0]) == REGNO (ops
[2]))
1829 gcc_assert (GET_CODE (ops
[2]) == REG
);
1830 snprintf (score7_ins
, INS_BUF_SZ
, "%s!\t%%0, %%%s1", inst_pre
, letter
);
1835 snprintf (score7_ins
, INS_BUF_SZ
, "%s.c\t%%0, %%1, %%%s2", inst_pre
, letter
);
1837 snprintf (score7_ins
, INS_BUF_SZ
, "%s\t%%0, %%1, %%%s2", inst_pre
, letter
);