1 /* Output routines for Sunplus S+CORE processor
2 Copyright (C) 2005-2013 Free Software Foundation, Inc.
3 Contributed by Sunnorth.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published
9 by the Free Software Foundation; either version 3, or (at your
10 option) any later version.
12 GCC is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
15 License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
23 #include "coretypes.h"
27 #include "hard-reg-set.h"
28 #include "insn-config.h"
29 #include "conditions.h"
30 #include "insn-attr.h"
32 #include "diagnostic-core.h"
35 #include "stringpool.h"
38 #include "stor-layout.h"
50 #include "target-def.h"
51 #include "langhooks.h"
55 #define SCORE_SDATA_MAX score_sdata_max
56 #define SCORE_STACK_ALIGN(LOC) (((LOC) + 3) & ~3)
57 #define SCORE_PROLOGUE_TEMP_REGNUM (GP_REG_FIRST + 8)
58 #define SCORE_EPILOGUE_TEMP_REGNUM (GP_REG_FIRST + 8)
59 #define SCORE_DEFAULT_SDATA_MAX 8
61 #define BITSET_P(VALUE, BIT) (((VALUE) & (1L << (BIT))) != 0)
62 #define INS_BUF_SZ 128
64 enum score_address_type
71 struct score_frame_info
73 HOST_WIDE_INT total_size
; /* bytes that the entire frame takes up */
74 HOST_WIDE_INT var_size
; /* bytes that variables take up */
75 HOST_WIDE_INT args_size
; /* bytes that outgoing arguments take up */
76 HOST_WIDE_INT gp_reg_size
; /* bytes needed to store gp regs */
77 HOST_WIDE_INT gp_sp_offset
; /* offset from new sp to store gp registers */
78 HOST_WIDE_INT cprestore_size
; /* # bytes that the .cprestore slot takes up */
79 unsigned int mask
; /* mask of saved gp registers */
80 int num_gp
; /* number of gp registers saved */
85 unsigned int num_bytes
; /* The argument's size in bytes */
86 unsigned int reg_words
; /* The number of words passed in registers */
87 unsigned int reg_offset
; /* The offset of the first register from */
88 /* GP_ARG_FIRST or FP_ARG_FIRST etc */
89 unsigned int stack_words
; /* The number of words that must be passed */
91 unsigned int stack_offset
; /* The offset from the start of the stack */
96 struct score_address_info
98 enum score_address_type type
;
102 enum score_symbol_type symbol_type
;
106 static int score_sdata_max
;
107 static char score_ins
[INS_BUF_SZ
+ 8];
109 struct extern_list
*extern_head
= 0;
111 #undef TARGET_ASM_FILE_START
112 #define TARGET_ASM_FILE_START score_asm_file_start
114 #undef TARGET_ASM_FILE_END
115 #define TARGET_ASM_FILE_END score_asm_file_end
117 #undef TARGET_ASM_FUNCTION_PROLOGUE
118 #define TARGET_ASM_FUNCTION_PROLOGUE score_function_prologue
120 #undef TARGET_ASM_FUNCTION_EPILOGUE
121 #define TARGET_ASM_FUNCTION_EPILOGUE score_function_epilogue
123 #undef TARGET_OPTION_OVERRIDE
124 #define TARGET_OPTION_OVERRIDE score_option_override
126 #undef TARGET_SCHED_ISSUE_RATE
127 #define TARGET_SCHED_ISSUE_RATE score_issue_rate
129 #undef TARGET_ASM_SELECT_RTX_SECTION
130 #define TARGET_ASM_SELECT_RTX_SECTION score_select_rtx_section
132 #undef TARGET_IN_SMALL_DATA_P
133 #define TARGET_IN_SMALL_DATA_P score_in_small_data_p
135 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
136 #define TARGET_FUNCTION_OK_FOR_SIBCALL score_function_ok_for_sibcall
138 #undef TARGET_STRICT_ARGUMENT_NAMING
139 #define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true
141 #undef TARGET_ASM_OUTPUT_MI_THUNK
142 #define TARGET_ASM_OUTPUT_MI_THUNK score_output_mi_thunk
144 #undef TARGET_PROMOTE_FUNCTION_MODE
145 #define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
147 #undef TARGET_PROMOTE_PROTOTYPES
148 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
150 #undef TARGET_MUST_PASS_IN_STACK
151 #define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size
153 #undef TARGET_ARG_PARTIAL_BYTES
154 #define TARGET_ARG_PARTIAL_BYTES score_arg_partial_bytes
156 #undef TARGET_FUNCTION_ARG
157 #define TARGET_FUNCTION_ARG score_function_arg
159 #undef TARGET_FUNCTION_ARG_ADVANCE
160 #define TARGET_FUNCTION_ARG_ADVANCE score_function_arg_advance
162 #undef TARGET_PASS_BY_REFERENCE
163 #define TARGET_PASS_BY_REFERENCE score_pass_by_reference
165 #undef TARGET_RETURN_IN_MEMORY
166 #define TARGET_RETURN_IN_MEMORY score_return_in_memory
168 #undef TARGET_RTX_COSTS
169 #define TARGET_RTX_COSTS score_rtx_costs
171 #undef TARGET_ADDRESS_COST
172 #define TARGET_ADDRESS_COST score_address_cost
174 #undef TARGET_LEGITIMATE_ADDRESS_P
175 #define TARGET_LEGITIMATE_ADDRESS_P score_legitimate_address_p
177 #undef TARGET_CAN_ELIMINATE
178 #define TARGET_CAN_ELIMINATE score_can_eliminate
180 #undef TARGET_CONDITIONAL_REGISTER_USAGE
181 #define TARGET_CONDITIONAL_REGISTER_USAGE score_conditional_register_usage
183 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
184 #define TARGET_ASM_TRAMPOLINE_TEMPLATE score_asm_trampoline_template
185 #undef TARGET_TRAMPOLINE_INIT
186 #define TARGET_TRAMPOLINE_INIT score_trampoline_init
188 #undef TARGET_REGISTER_MOVE_COST
189 #define TARGET_REGISTER_MOVE_COST score_register_move_cost
191 /* Return true if SYMBOL is a SYMBOL_REF and OFFSET + SYMBOL points
192 to the same object as SYMBOL. */
194 score_offset_within_object_p (rtx symbol
, HOST_WIDE_INT offset
)
196 if (GET_CODE (symbol
) != SYMBOL_REF
)
199 if (CONSTANT_POOL_ADDRESS_P (symbol
)
201 && offset
< (int)GET_MODE_SIZE (get_pool_mode (symbol
)))
204 if (SYMBOL_REF_DECL (symbol
) != 0
206 && offset
< int_size_in_bytes (TREE_TYPE (SYMBOL_REF_DECL (symbol
))))
212 /* Split X into a base and a constant offset, storing them in *BASE
213 and *OFFSET respectively. */
215 score_split_const (rtx x
, rtx
*base
, HOST_WIDE_INT
*offset
)
219 if (GET_CODE (x
) == CONST
)
222 if (GET_CODE (x
) == PLUS
&& GET_CODE (XEXP (x
, 1)) == CONST_INT
)
224 *offset
+= INTVAL (XEXP (x
, 1));
231 /* Classify symbol X, which must be a SYMBOL_REF or a LABEL_REF. */
232 static enum score_symbol_type
233 score_classify_symbol (rtx x
)
235 if (GET_CODE (x
) == LABEL_REF
)
236 return SYMBOL_GENERAL
;
238 gcc_assert (GET_CODE (x
) == SYMBOL_REF
);
240 if (CONSTANT_POOL_ADDRESS_P (x
))
242 if (GET_MODE_SIZE (get_pool_mode (x
)) <= SCORE_SDATA_MAX
)
243 return SYMBOL_SMALL_DATA
;
244 return SYMBOL_GENERAL
;
246 if (SYMBOL_REF_SMALL_P (x
))
247 return SYMBOL_SMALL_DATA
;
248 return SYMBOL_GENERAL
;
251 /* Return true if the current function must save REGNO. */
253 score_save_reg_p (unsigned int regno
)
255 /* Check call-saved registers. */
256 if (df_regs_ever_live_p (regno
) && !call_used_regs
[regno
])
259 /* We need to save the old frame pointer before setting up a new one. */
260 if (regno
== HARD_FRAME_POINTER_REGNUM
&& frame_pointer_needed
)
263 /* We need to save the incoming return address if it is ever clobbered
264 within the function. */
265 if (regno
== RA_REGNUM
&& df_regs_ever_live_p (regno
))
271 /* Return one word of double-word value OP, taking into account the fixed
272 endianness of certain registers. HIGH_P is true to select the high part,
273 false to select the low part. */
275 score_subw (rtx op
, int high_p
)
278 enum machine_mode mode
= GET_MODE (op
);
280 if (mode
== VOIDmode
)
283 byte
= (TARGET_LITTLE_ENDIAN
? high_p
: !high_p
) ? UNITS_PER_WORD
: 0;
285 if (GET_CODE (op
) == REG
&& REGNO (op
) == HI_REGNUM
)
286 return gen_rtx_REG (SImode
, high_p
? HI_REGNUM
: LO_REGNUM
);
288 if (GET_CODE (op
) == MEM
)
289 return adjust_address (op
, SImode
, byte
);
291 return simplify_gen_subreg (SImode
, op
, mode
, byte
);
294 static struct score_frame_info
*
295 score_cached_frame (void)
297 static struct score_frame_info _frame_info
;
301 /* Return the bytes needed to compute the frame pointer from the current
302 stack pointer. SIZE is the size (in bytes) of the local variables. */
303 static struct score_frame_info
*
304 score_compute_frame_size (HOST_WIDE_INT size
)
307 struct score_frame_info
*f
= score_cached_frame ();
309 memset (f
, 0, sizeof (struct score_frame_info
));
312 f
->var_size
= SCORE_STACK_ALIGN (size
);
313 f
->args_size
= crtl
->outgoing_args_size
;
314 f
->cprestore_size
= flag_pic
? UNITS_PER_WORD
: 0;
315 if (f
->var_size
== 0 && crtl
->is_leaf
)
316 f
->args_size
= f
->cprestore_size
= 0;
318 if (f
->args_size
== 0 && cfun
->calls_alloca
)
319 f
->args_size
= UNITS_PER_WORD
;
321 f
->total_size
= f
->var_size
+ f
->args_size
+ f
->cprestore_size
;
322 for (regno
= GP_REG_FIRST
; regno
<= GP_REG_LAST
; regno
++)
324 if (score_save_reg_p (regno
))
326 f
->gp_reg_size
+= GET_MODE_SIZE (SImode
);
327 f
->mask
|= 1 << (regno
- GP_REG_FIRST
);
331 if (crtl
->calls_eh_return
)
336 regno
= EH_RETURN_DATA_REGNO (i
);
337 if (regno
== INVALID_REGNUM
)
339 f
->gp_reg_size
+= GET_MODE_SIZE (SImode
);
340 f
->mask
|= 1 << (regno
- GP_REG_FIRST
);
344 f
->total_size
+= f
->gp_reg_size
;
345 f
->num_gp
= f
->gp_reg_size
/ UNITS_PER_WORD
;
349 HOST_WIDE_INT offset
;
350 offset
= (f
->args_size
+ f
->cprestore_size
+ f
->var_size
351 + f
->gp_reg_size
- GET_MODE_SIZE (SImode
));
352 f
->gp_sp_offset
= offset
;
360 /* Return true if X is a valid base register for the given mode.
361 Allow only hard registers if STRICT. */
363 score_valid_base_register_p (rtx x
, int strict
)
365 if (!strict
&& GET_CODE (x
) == SUBREG
)
368 return (GET_CODE (x
) == REG
369 && score_regno_mode_ok_for_base_p (REGNO (x
), strict
));
372 /* Return true if X is a valid address for machine mode MODE. If it is,
373 fill in INFO appropriately. STRICT is true if we should only accept
374 hard base registers. */
376 score_classify_address (struct score_address_info
*info
,
377 enum machine_mode mode
, rtx x
, int strict
)
379 info
->code
= GET_CODE (x
);
385 info
->type
= SCORE_ADD_REG
;
387 info
->offset
= const0_rtx
;
388 return score_valid_base_register_p (info
->reg
, strict
);
390 info
->type
= SCORE_ADD_REG
;
391 info
->reg
= XEXP (x
, 0);
392 info
->offset
= XEXP (x
, 1);
393 return (score_valid_base_register_p (info
->reg
, strict
)
394 && GET_CODE (info
->offset
) == CONST_INT
395 && IMM_IN_RANGE (INTVAL (info
->offset
), 15, 1));
400 if (GET_MODE_SIZE (mode
) > GET_MODE_SIZE (SImode
))
402 info
->type
= SCORE_ADD_REG
;
403 info
->reg
= XEXP (x
, 0);
404 info
->offset
= GEN_INT (GET_MODE_SIZE (mode
));
405 return score_valid_base_register_p (info
->reg
, strict
);
407 info
->type
= SCORE_ADD_CONST_INT
;
408 return IMM_IN_RANGE (INTVAL (x
), 15, 1);
412 info
->type
= SCORE_ADD_SYMBOLIC
;
413 return (score_symbolic_constant_p (x
, &info
->symbol_type
)
414 && (info
->symbol_type
== SYMBOL_GENERAL
415 || info
->symbol_type
== SYMBOL_SMALL_DATA
));
421 /* Implement TARGET_RETURN_IN_MEMORY. In S+core,
422 small structures are returned in a register.
423 Objects with varying size must still be returned in memory. */
425 score_return_in_memory (const_tree type
, const_tree fndecl ATTRIBUTE_UNUSED
)
427 return ((TYPE_MODE (type
) == BLKmode
)
428 || (int_size_in_bytes (type
) > 2 * UNITS_PER_WORD
)
429 || (int_size_in_bytes (type
) == -1));
432 /* Return a legitimate address for REG + OFFSET. */
434 score_add_offset (rtx reg
, HOST_WIDE_INT offset
)
436 if (!IMM_IN_RANGE (offset
, 15, 1))
438 reg
= expand_simple_binop (GET_MODE (reg
), PLUS
,
439 gen_int_mode (offset
& 0xffffc000,
441 reg
, NULL
, 0, OPTAB_WIDEN
);
445 return plus_constant (GET_MODE (reg
), reg
, offset
);
448 /* Implement TARGET_ASM_OUTPUT_MI_THUNK. Generate rtl rather than asm text
449 in order to avoid duplicating too much logic from elsewhere. */
451 score_output_mi_thunk (FILE *file
, tree thunk_fndecl ATTRIBUTE_UNUSED
,
452 HOST_WIDE_INT delta
, HOST_WIDE_INT vcall_offset
,
455 rtx this_rtx
, temp1
, insn
, fnaddr
;
457 /* Pretend to be a post-reload pass while generating rtl. */
458 reload_completed
= 1;
460 /* Mark the end of the (empty) prologue. */
461 emit_note (NOTE_INSN_PROLOGUE_END
);
463 /* We need two temporary registers in some cases. */
464 temp1
= gen_rtx_REG (Pmode
, 8);
466 /* Find out which register contains the "this" pointer. */
467 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function
)), function
))
468 this_rtx
= gen_rtx_REG (Pmode
, ARG_REG_FIRST
+ 1);
470 this_rtx
= gen_rtx_REG (Pmode
, ARG_REG_FIRST
);
472 /* Add DELTA to THIS_RTX. */
475 rtx offset
= GEN_INT (delta
);
476 if (!(delta
>= -32768 && delta
<= 32767))
478 emit_move_insn (temp1
, offset
);
481 emit_insn (gen_add3_insn (this_rtx
, this_rtx
, offset
));
484 /* If needed, add *(*THIS_RTX + VCALL_OFFSET) to THIS_RTX. */
485 if (vcall_offset
!= 0)
489 /* Set TEMP1 to *THIS_RTX. */
490 emit_move_insn (temp1
, gen_rtx_MEM (Pmode
, this_rtx
));
492 /* Set ADDR to a legitimate address for *THIS_RTX + VCALL_OFFSET. */
493 addr
= score_add_offset (temp1
, vcall_offset
);
495 /* Load the offset and add it to THIS_RTX. */
496 emit_move_insn (temp1
, gen_rtx_MEM (Pmode
, addr
));
497 emit_insn (gen_add3_insn (this_rtx
, this_rtx
, temp1
));
500 /* Jump to the target function. */
501 fnaddr
= XEXP (DECL_RTL (function
), 0);
502 insn
= emit_call_insn (gen_sibcall_internal_score7 (fnaddr
, const0_rtx
));
503 SIBLING_CALL_P (insn
) = 1;
505 /* Run just enough of rest_of_compilation. This sequence was
506 "borrowed" from alpha.c. */
508 split_all_insns_noflow ();
509 shorten_branches (insn
);
510 final_start_function (insn
, file
, 1);
511 final (insn
, file
, 1);
512 final_end_function ();
514 /* Clean up the vars set above. Note that final_end_function resets
515 the global pointer for us. */
516 reload_completed
= 0;
519 /* Copy VALUE to a register and return that register. If new psuedos
520 are allowed, copy it into a new register, otherwise use DEST. */
522 score_force_temporary (rtx dest
, rtx value
)
524 if (can_create_pseudo_p ())
525 return force_reg (Pmode
, value
);
528 emit_move_insn (copy_rtx (dest
), value
);
533 /* Return a LO_SUM expression for ADDR. TEMP is as for score_force_temporary
534 and is used to load the high part into a register. */
536 score_split_symbol (rtx temp
, rtx addr
)
538 rtx high
= score_force_temporary (temp
,
539 gen_rtx_HIGH (Pmode
, copy_rtx (addr
)));
540 return gen_rtx_LO_SUM (Pmode
, high
, addr
);
543 /* Fill INFO with information about a single argument. CUM is the
544 cumulative state for earlier arguments. MODE is the mode of this
545 argument and TYPE is its type (if known). NAMED is true if this
546 is a named (fixed) argument rather than a variable one. */
548 score_classify_arg (const CUMULATIVE_ARGS
*cum
, enum machine_mode mode
,
549 const_tree type
, bool named
, struct score_arg_info
*info
)
552 unsigned int num_words
, max_regs
;
555 if (GET_MODE_CLASS (mode
) == MODE_INT
556 || GET_MODE_CLASS (mode
) == MODE_FLOAT
)
557 even_reg_p
= (GET_MODE_SIZE (mode
) > UNITS_PER_WORD
);
559 if (type
!= NULL_TREE
&& TYPE_ALIGN (type
) > BITS_PER_WORD
&& named
)
562 if (TARGET_MUST_PASS_IN_STACK (mode
, type
))
563 info
->reg_offset
= ARG_REG_NUM
;
566 info
->reg_offset
= cum
->num_gprs
;
568 info
->reg_offset
+= info
->reg_offset
& 1;
572 info
->num_bytes
= int_size_in_bytes (type
);
574 info
->num_bytes
= GET_MODE_SIZE (mode
);
576 num_words
= (info
->num_bytes
+ UNITS_PER_WORD
- 1) / UNITS_PER_WORD
;
577 max_regs
= ARG_REG_NUM
- info
->reg_offset
;
579 /* Partition the argument between registers and stack. */
580 info
->reg_words
= MIN (num_words
, max_regs
);
581 info
->stack_words
= num_words
- info
->reg_words
;
583 /* The alignment applied to registers is also applied to stack arguments. */
584 if (info
->stack_words
)
586 info
->stack_offset
= cum
->stack_words
;
588 info
->stack_offset
+= info
->stack_offset
& 1;
592 /* Set up the stack and frame (if desired) for the function. */
594 score_function_prologue (FILE *file
, HOST_WIDE_INT size ATTRIBUTE_UNUSED
)
597 struct score_frame_info
*f
= score_cached_frame ();
598 HOST_WIDE_INT tsize
= f
->total_size
;
600 fnname
= XSTR (XEXP (DECL_RTL (current_function_decl
), 0), 0);
601 if (!flag_inhibit_size_directive
)
603 fputs ("\t.ent\t", file
);
604 assemble_name (file
, fnname
);
607 assemble_name (file
, fnname
);
610 if (!flag_inhibit_size_directive
)
613 "\t.frame\t%s," HOST_WIDE_INT_PRINT_DEC
",%s, %d\t\t"
614 "# vars= " HOST_WIDE_INT_PRINT_DEC
", regs= %d"
615 ", args= " HOST_WIDE_INT_PRINT_DEC
616 ", gp= " HOST_WIDE_INT_PRINT_DEC
"\n",
617 (reg_names
[(frame_pointer_needed
)
618 ? HARD_FRAME_POINTER_REGNUM
: STACK_POINTER_REGNUM
]),
620 reg_names
[RA_REGNUM
],
621 crtl
->is_leaf
? 1 : 0,
627 fprintf(file
, "\t.mask\t0x%08x," HOST_WIDE_INT_PRINT_DEC
"\n",
629 (f
->gp_sp_offset
- f
->total_size
));
633 /* Do any necessary cleanup after a function to restore stack, frame,
636 score_function_epilogue (FILE *file
, HOST_WIDE_INT size ATTRIBUTE_UNUSED
)
638 if (!flag_inhibit_size_directive
)
641 fnname
= XSTR (XEXP (DECL_RTL (current_function_decl
), 0), 0);
642 fputs ("\t.end\t", file
);
643 assemble_name (file
, fnname
);
648 /* Returns true if X contains a SYMBOL_REF. */
650 score_symbolic_expression_p (rtx x
)
652 if (GET_CODE (x
) == SYMBOL_REF
)
655 if (GET_CODE (x
) == CONST
)
656 return score_symbolic_expression_p (XEXP (x
, 0));
659 return score_symbolic_expression_p (XEXP (x
, 0));
661 if (ARITHMETIC_P (x
))
662 return (score_symbolic_expression_p (XEXP (x
, 0))
663 || score_symbolic_expression_p (XEXP (x
, 1)));
668 /* Choose the section to use for the constant rtx expression X that has
671 score_select_rtx_section (enum machine_mode mode
, rtx x
, unsigned HOST_WIDE_INT align
)
673 if (GET_MODE_SIZE (mode
) <= SCORE_SDATA_MAX
)
674 return get_named_section (0, ".sdata", 0);
675 else if (flag_pic
&& score_symbolic_expression_p (x
))
676 return get_named_section (0, ".data.rel.ro", 3);
678 return mergeable_constant_section (mode
, align
, 0);
681 /* Implement TARGET_IN_SMALL_DATA_P. */
683 score_in_small_data_p (const_tree decl
)
687 if (TREE_CODE (decl
) == STRING_CST
688 || TREE_CODE (decl
) == FUNCTION_DECL
)
691 if (TREE_CODE (decl
) == VAR_DECL
&& DECL_SECTION_NAME (decl
) != 0)
694 name
= TREE_STRING_POINTER (DECL_SECTION_NAME (decl
));
695 if (strcmp (name
, ".sdata") != 0
696 && strcmp (name
, ".sbss") != 0)
698 if (!DECL_EXTERNAL (decl
))
701 size
= int_size_in_bytes (TREE_TYPE (decl
));
702 return (size
> 0 && size
<= SCORE_SDATA_MAX
);
705 /* Implement TARGET_ASM_FILE_START. */
707 score_asm_file_start (void)
709 default_file_start ();
710 fprintf (asm_out_file
, ASM_COMMENT_START
711 "GCC for S+core %s \n", SCORE_GCC_VERSION
);
714 fprintf (asm_out_file
, "\t.set pic\n");
717 /* Implement TARGET_ASM_FILE_END. When using assembler macros, emit
718 .externs for any small-data variables that turned out to be external. */
720 score_asm_file_end (void)
723 struct extern_list
*p
;
726 fputs ("\n", asm_out_file
);
727 for (p
= extern_head
; p
!= 0; p
= p
->next
)
729 name_tree
= get_identifier (p
->name
);
730 if (!TREE_ASM_WRITTEN (name_tree
)
731 && TREE_SYMBOL_REFERENCED (name_tree
))
733 TREE_ASM_WRITTEN (name_tree
) = 1;
734 fputs ("\t.extern\t", asm_out_file
);
735 assemble_name (asm_out_file
, p
->name
);
736 fprintf (asm_out_file
, ", %d\n", p
->size
);
742 /* Implement TARGET_OPTION_OVERRIDE hook. */
744 score_option_override (void)
747 score_sdata_max
= SCORE_DEFAULT_SDATA_MAX
;
751 /* Implement REGNO_REG_CLASS macro. */
753 score_reg_class (int regno
)
756 gcc_assert (regno
>= 0 && regno
< FIRST_PSEUDO_REGISTER
);
758 if (regno
== FRAME_POINTER_REGNUM
759 || regno
== ARG_POINTER_REGNUM
)
762 for (c
= 0; c
< N_REG_CLASSES
; c
++)
763 if (TEST_HARD_REG_BIT (reg_class_contents
[c
], regno
))
769 /* Implement PREFERRED_RELOAD_CLASS macro. */
771 score_preferred_reload_class (rtx x ATTRIBUTE_UNUSED
, enum reg_class rclass
)
773 if (reg_class_subset_p (G16_REGS
, rclass
))
775 if (reg_class_subset_p (G32_REGS
, rclass
))
780 /* Implement SECONDARY_INPUT_RELOAD_CLASS
781 and SECONDARY_OUTPUT_RELOAD_CLASS macro. */
783 score_secondary_reload_class (enum reg_class rclass
,
784 enum machine_mode mode ATTRIBUTE_UNUSED
,
788 if (GET_CODE (x
) == REG
|| GET_CODE(x
) == SUBREG
)
789 regno
= true_regnum (x
);
791 if (!GR_REG_CLASS_P (rclass
))
792 return GP_REG_P (regno
) ? NO_REGS
: G32_REGS
;
797 /* Return truth value on whether or not a given hard register
798 can support a given mode. */
800 score_hard_regno_mode_ok (unsigned int regno
, enum machine_mode mode
)
802 int size
= GET_MODE_SIZE (mode
);
803 enum mode_class mclass
= GET_MODE_CLASS (mode
);
805 if (mclass
== MODE_CC
)
806 return regno
== CC_REGNUM
;
807 else if (regno
== FRAME_POINTER_REGNUM
808 || regno
== ARG_POINTER_REGNUM
)
809 return mclass
== MODE_INT
;
810 else if (GP_REG_P (regno
))
811 /* ((regno <= (GP_REG_LAST- HARD_REGNO_NREGS (dummy, mode)) + 1) */
812 return !(regno
& 1) || (size
<= UNITS_PER_WORD
);
813 else if (CE_REG_P (regno
))
814 return (mclass
== MODE_INT
815 && ((size
<= UNITS_PER_WORD
)
816 || (regno
== CE_REG_FIRST
&& size
== 2 * UNITS_PER_WORD
)));
818 return (mclass
== MODE_INT
) && (size
<= UNITS_PER_WORD
);
821 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
822 pointer or argument pointer. TO is either the stack pointer or
823 hard frame pointer. */
825 score_initial_elimination_offset (int from
,
826 int to ATTRIBUTE_UNUSED
)
828 struct score_frame_info
*f
= score_compute_frame_size (get_frame_size ());
831 case ARG_POINTER_REGNUM
:
832 return f
->total_size
;
833 case FRAME_POINTER_REGNUM
:
840 /* Implement TARGET_FUNCTION_ARG_ADVANCE hook. */
842 score_function_arg_advance (cumulative_args_t cum_args
, enum machine_mode mode
,
843 const_tree type
, bool named
)
845 struct score_arg_info info
;
846 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_args
);
847 score_classify_arg (cum
, mode
, type
, named
, &info
);
848 cum
->num_gprs
= info
.reg_offset
+ info
.reg_words
;
849 if (info
.stack_words
> 0)
850 cum
->stack_words
= info
.stack_offset
+ info
.stack_words
;
854 /* Implement TARGET_ARG_PARTIAL_BYTES macro. */
856 score_arg_partial_bytes (cumulative_args_t cum_args
,
857 enum machine_mode mode
, tree type
, bool named
)
859 struct score_arg_info info
;
860 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_args
);
861 score_classify_arg (cum
, mode
, type
, named
, &info
);
862 return info
.stack_words
> 0 ? info
.reg_words
* UNITS_PER_WORD
: 0;
865 /* Implement TARGET_FUNCTION_ARG hook. */
867 score_function_arg (cumulative_args_t cum_args
, enum machine_mode mode
,
868 const_tree type
, bool named
)
870 struct score_arg_info info
;
871 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_args
);
873 if (mode
== VOIDmode
|| !named
)
876 score_classify_arg (cum
, mode
, type
, named
, &info
);
878 if (info
.reg_offset
== ARG_REG_NUM
)
881 if (!info
.stack_words
)
882 return gen_rtx_REG (mode
, ARG_REG_FIRST
+ info
.reg_offset
);
885 rtx ret
= gen_rtx_PARALLEL (mode
, rtvec_alloc (info
.reg_words
));
886 unsigned int i
, part_offset
= 0;
887 for (i
= 0; i
< info
.reg_words
; i
++)
890 reg
= gen_rtx_REG (SImode
, ARG_REG_FIRST
+ info
.reg_offset
+ i
);
891 XVECEXP (ret
, 0, i
) = gen_rtx_EXPR_LIST (SImode
, reg
,
892 GEN_INT (part_offset
));
893 part_offset
+= UNITS_PER_WORD
;
899 /* Implement FUNCTION_VALUE and LIBCALL_VALUE. For normal calls,
900 VALTYPE is the return type and MODE is VOIDmode. For libcalls,
901 VALTYPE is null and MODE is the mode of the return value. */
903 score_function_value (const_tree valtype
, const_tree func
, enum machine_mode mode
)
908 mode
= TYPE_MODE (valtype
);
909 unsignedp
= TYPE_UNSIGNED (valtype
);
910 mode
= promote_function_mode (valtype
, mode
, &unsignedp
, func
, 1);
912 return gen_rtx_REG (mode
, RT_REGNUM
);
915 /* Implement TARGET_ASM_TRAMPOLINE_TEMPLATE. */
918 score_asm_trampoline_template (FILE *f
)
920 fprintf (f
, "\t.set r1\n");
921 fprintf (f
, "\tmv r31, r3\n");
922 fprintf (f
, "\tbl nextinsn\n");
923 fprintf (f
, "nextinsn:\n");
924 fprintf (f
, "\tlw r1, [r3, 6*4-8]\n");
925 fprintf (f
, "\tlw r23, [r3, 6*4-4]\n");
926 fprintf (f
, "\tmv r3, r31\n");
927 fprintf (f
, "\tbr! r1\n");
928 fprintf (f
, "\tnop!\n");
929 fprintf (f
, "\t.set nor1\n");
932 /* Implement TARGET_TRAMPOLINE_INIT. */
934 score_trampoline_init (rtx m_tramp
, tree fndecl
, rtx chain_value
)
936 #define CODE_SIZE (TRAMPOLINE_INSNS * UNITS_PER_WORD)
938 rtx fnaddr
= XEXP (DECL_RTL (fndecl
), 0);
941 emit_block_move (m_tramp
, assemble_trampoline_template (),
942 GEN_INT (TRAMPOLINE_SIZE
), BLOCK_OP_NORMAL
);
944 mem
= adjust_address (m_tramp
, SImode
, CODE_SIZE
);
945 emit_move_insn (mem
, fnaddr
);
946 mem
= adjust_address (m_tramp
, SImode
, CODE_SIZE
+ GET_MODE_SIZE (SImode
));
947 emit_move_insn (mem
, chain_value
);
952 /* This function is used to implement REG_MODE_OK_FOR_BASE_P macro. */
954 score_regno_mode_ok_for_base_p (int regno
, int strict
)
956 if (regno
>= FIRST_PSEUDO_REGISTER
)
960 regno
= reg_renumber
[regno
];
962 if (regno
== ARG_POINTER_REGNUM
963 || regno
== FRAME_POINTER_REGNUM
)
965 return GP_REG_P (regno
);
968 /* Implement TARGET_LEGITIMATE_ADDRESS_P macro. */
970 score_legitimate_address_p (enum machine_mode mode
, rtx x
, bool strict
)
972 struct score_address_info addr
;
974 return score_classify_address (&addr
, mode
, x
, strict
);
977 /* Implement TARGET_REGISTER_MOVE_COST.
979 Return a number assessing the cost of moving a register in class
982 score_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED
,
983 reg_class_t from
, reg_class_t to
)
985 if (GR_REG_CLASS_P (from
))
987 if (GR_REG_CLASS_P (to
))
989 else if (SP_REG_CLASS_P (to
))
991 else if (CP_REG_CLASS_P (to
))
993 else if (CE_REG_CLASS_P (to
))
996 if (GR_REG_CLASS_P (to
))
998 if (GR_REG_CLASS_P (from
))
1000 else if (SP_REG_CLASS_P (from
))
1002 else if (CP_REG_CLASS_P (from
))
1004 else if (CE_REG_CLASS_P (from
))
1010 /* Return the number of instructions needed to load a symbol of the
1011 given type into a register. */
1013 score_symbol_insns (enum score_symbol_type type
)
1017 case SYMBOL_GENERAL
:
1020 case SYMBOL_SMALL_DATA
:
1027 /* Return the number of instructions needed to load or store a value
1028 of mode MODE at X. Return 0 if X isn't valid for MODE. */
1030 score_address_insns (rtx x
, enum machine_mode mode
)
1032 struct score_address_info addr
;
1035 if (mode
== BLKmode
)
1038 factor
= (GET_MODE_SIZE (mode
) + UNITS_PER_WORD
- 1) / UNITS_PER_WORD
;
1040 if (score_classify_address (&addr
, mode
, x
, false))
1044 case SCORE_ADD_CONST_INT
:
1047 case SCORE_ADD_SYMBOLIC
:
1048 return factor
* score_symbol_insns (addr
.symbol_type
);
1053 /* Implement TARGET_RTX_COSTS macro. */
1055 score_rtx_costs (rtx x
, int code
, int outer_code
, int opno ATTRIBUTE_UNUSED
,
1056 int *total
, bool speed ATTRIBUTE_UNUSED
)
1058 enum machine_mode mode
= GET_MODE (x
);
1063 if (outer_code
== SET
)
1065 if (((INTVAL (x
) & 0xffff) == 0)
1066 || (INTVAL (x
) >= -32768 && INTVAL (x
) <= 32767))
1067 *total
= COSTS_N_INSNS (1);
1069 *total
= COSTS_N_INSNS (2);
1071 else if (outer_code
== PLUS
|| outer_code
== MINUS
)
1073 if (INTVAL (x
) >= -8192 && INTVAL (x
) <= 8191)
1075 else if (((INTVAL (x
) & 0xffff) == 0)
1076 || (INTVAL (x
) >= -32768 && INTVAL (x
) <= 32767))
1079 *total
= COSTS_N_INSNS (2);
1081 else if (outer_code
== AND
|| outer_code
== IOR
)
1083 if (INTVAL (x
) >= 0 && INTVAL (x
) <= 16383)
1085 else if (((INTVAL (x
) & 0xffff) == 0)
1086 || (INTVAL (x
) >= 0 && INTVAL (x
) <= 65535))
1089 *total
= COSTS_N_INSNS (2);
1101 *total
= COSTS_N_INSNS (2);
1106 /* If the address is legitimate, return the number of
1107 instructions it needs, otherwise use the default handling. */
1108 int n
= score_address_insns (XEXP (x
, 0), GET_MODE (x
));
1111 *total
= COSTS_N_INSNS (n
+ 1);
1118 *total
= COSTS_N_INSNS (6);
1122 *total
= COSTS_N_INSNS (1);
1130 *total
= COSTS_N_INSNS (2);
1140 *total
= COSTS_N_INSNS ((GET_CODE (XEXP (x
, 1)) == CONST_INT
)
1147 *total
= COSTS_N_INSNS (4);
1154 *total
= COSTS_N_INSNS (4);
1157 *total
= COSTS_N_INSNS (1);
1163 *total
= COSTS_N_INSNS (4);
1169 *total
= optimize_size
? COSTS_N_INSNS (2) : COSTS_N_INSNS (12);
1176 *total
= optimize_size
? COSTS_N_INSNS (2) : COSTS_N_INSNS (33);
1181 switch (GET_MODE (XEXP (x
, 0)))
1185 if (GET_CODE (XEXP (x
, 0)) == MEM
)
1187 *total
= COSTS_N_INSNS (2);
1189 if (!TARGET_LITTLE_ENDIAN
&&
1190 side_effects_p (XEXP (XEXP (x
, 0), 0)))
1194 *total
= COSTS_N_INSNS (1);
1198 *total
= COSTS_N_INSNS (1);
1208 /* Implement TARGET_ADDRESS_COST macro. */
1210 score_address_cost (rtx addr
, enum machine_mode mode ATTRIBUTE_UNUSED
,
1211 addr_space_t as ATTRIBUTE_UNUSED
,
1212 bool speed ATTRIBUTE_UNUSED
)
1214 return score_address_insns (addr
, SImode
);
1217 /* Implement ASM_OUTPUT_EXTERNAL macro. */
1219 score_output_external (FILE *file ATTRIBUTE_UNUSED
,
1220 tree decl
, const char *name
)
1222 register struct extern_list
*p
;
1224 if (score_in_small_data_p (decl
))
1226 p
= ggc_alloc_extern_list ();
1227 p
->next
= extern_head
;
1229 p
->size
= int_size_in_bytes (TREE_TYPE (decl
));
1235 /* Implement RETURN_ADDR_RTX. Note, we do not support moving
1236 back to a previous frame. */
1238 score_return_addr (int count
, rtx frame ATTRIBUTE_UNUSED
)
1242 return get_hard_reg_initial_val (Pmode
, RA_REGNUM
);
1245 /* Implement PRINT_OPERAND macro. */
1246 /* Score-specific operand codes:
1247 '[' print .set nor1 directive
1248 ']' print .set r1 directive
1249 'U' print hi part of a CONST_INT rtx
1252 'D' print SFmode const double
1253 'S' selectively print "!" if operand is 15bit instruction accessible
1254 'V' print "v!" if operand is 15bit instruction accessible, or "lfh!"
1255 'L' low part of DImode reg operand
1256 'H' high part of DImode reg operand
1257 'C' print part of opcode for a branch condition. */
1259 score_print_operand (FILE *file
, rtx op
, int c
)
1261 enum rtx_code code
= UNKNOWN
;
1262 if (!PRINT_OPERAND_PUNCT_VALID_P (c
))
1263 code
= GET_CODE (op
);
1267 fprintf (file
, ".set r1\n");
1271 fprintf (file
, "\n\t.set nor1");
1275 gcc_assert (code
== CONST_INT
);
1276 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
,
1277 (INTVAL (op
) >> 16) & 0xffff);
1281 if (GET_CODE (op
) == CONST_DOUBLE
)
1283 rtx temp
= gen_lowpart (SImode
, op
);
1284 gcc_assert (GET_MODE (op
) == SFmode
);
1285 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, INTVAL (temp
) & 0xffffffff);
1288 output_addr_const (file
, op
);
1292 gcc_assert (code
== REG
);
1293 if (G16_REG_P (REGNO (op
)))
1294 fprintf (file
, "!");
1298 gcc_assert (code
== REG
);
1299 fprintf (file
, G16_REG_P (REGNO (op
)) ? "v!" : "lfh!");
1303 enum machine_mode mode
= GET_MODE (XEXP (op
, 0));
1307 case EQ
: fputs ("eq", file
); break;
1308 case NE
: fputs ("ne", file
); break;
1309 case GT
: fputs ("gt", file
); break;
1310 case GE
: fputs (mode
!= CCmode
? "pl" : "ge", file
); break;
1311 case LT
: fputs (mode
!= CCmode
? "mi" : "lt", file
); break;
1312 case LE
: fputs ("le", file
); break;
1313 case GTU
: fputs ("gtu", file
); break;
1314 case GEU
: fputs ("cs", file
); break;
1315 case LTU
: fputs ("cc", file
); break;
1316 case LEU
: fputs ("leu", file
); break;
1318 output_operand_lossage ("invalid operand for code: '%c'", code
);
1323 unsigned HOST_WIDE_INT i
;
1324 unsigned HOST_WIDE_INT pow2mask
= 1;
1325 unsigned HOST_WIDE_INT val
;
1328 for (i
= 0; i
< 32; i
++)
1330 if (val
== pow2mask
)
1334 gcc_assert (i
< 32);
1335 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, i
);
1339 unsigned HOST_WIDE_INT i
;
1340 unsigned HOST_WIDE_INT pow2mask
= 1;
1341 unsigned HOST_WIDE_INT val
;
1344 for (i
= 0; i
< 32; i
++)
1346 if (val
== pow2mask
)
1350 gcc_assert (i
< 32);
1351 fprintf (file
, HOST_WIDE_INT_PRINT_HEX
, i
);
1353 else if (code
== REG
)
1355 int regnum
= REGNO (op
);
1356 if ((c
== 'H' && !WORDS_BIG_ENDIAN
)
1357 || (c
== 'L' && WORDS_BIG_ENDIAN
))
1359 fprintf (file
, "%s", reg_names
[regnum
]);
1366 score_print_operand_address (file
, op
);
1369 output_addr_const (file
, op
);
1374 /* Implement PRINT_OPERAND_ADDRESS macro. */
1376 score_print_operand_address (FILE *file
, rtx x
)
1378 struct score_address_info addr
;
1379 enum rtx_code code
= GET_CODE (x
);
1380 enum machine_mode mode
= GET_MODE (x
);
1385 if (score_classify_address (&addr
, mode
, x
, true))
1394 fprintf (file
, "[%s,-%ld]+", reg_names
[REGNO (addr
.reg
)],
1395 INTVAL (addr
.offset
));
1398 fprintf (file
, "[%s]+,-%ld", reg_names
[REGNO (addr
.reg
)],
1399 INTVAL (addr
.offset
));
1402 fprintf (file
, "[%s, %ld]+", reg_names
[REGNO (addr
.reg
)],
1403 INTVAL (addr
.offset
));
1406 fprintf (file
, "[%s]+, %ld", reg_names
[REGNO (addr
.reg
)],
1407 INTVAL (addr
.offset
));
1410 if (INTVAL(addr
.offset
) == 0)
1411 fprintf(file
, "[%s]", reg_names
[REGNO (addr
.reg
)]);
1413 fprintf(file
, "[%s, %ld]", reg_names
[REGNO (addr
.reg
)],
1414 INTVAL(addr
.offset
));
1419 case SCORE_ADD_CONST_INT
:
1420 case SCORE_ADD_SYMBOLIC
:
1421 output_addr_const (file
, x
);
1425 print_rtl (stderr
, x
);
1429 /* Implement SELECT_CC_MODE macro. */
1431 score_select_cc_mode (enum rtx_code op
, rtx x
, rtx y
)
1433 if ((op
== EQ
|| op
== NE
|| op
== LT
|| op
== GE
)
1435 && GET_MODE (x
) == SImode
)
1437 switch (GET_CODE (x
))
1455 return (op
== LT
|| op
== GE
) ? CC_Nmode
: CCmode
;
1462 if ((op
== EQ
|| op
== NE
)
1463 && (GET_CODE (y
) == NEG
)
1464 && register_operand (XEXP (y
, 0), SImode
)
1465 && register_operand (x
, SImode
))
1473 /* Generate the prologue instructions for entry into a S+core function. */
1475 score_prologue (void)
1477 #define EMIT_PL(_rtx) RTX_FRAME_RELATED_P (_rtx) = 1
1479 struct score_frame_info
*f
= score_compute_frame_size (get_frame_size ());
1483 size
= f
->total_size
- f
->gp_reg_size
;
1486 emit_insn (gen_cpload_score7 ());
1488 for (regno
= (int) GP_REG_LAST
; regno
>= (int) GP_REG_FIRST
; regno
--)
1490 if (BITSET_P (f
->mask
, regno
- GP_REG_FIRST
))
1492 rtx mem
= gen_rtx_MEM (SImode
,
1493 gen_rtx_PRE_DEC (SImode
, stack_pointer_rtx
));
1494 rtx reg
= gen_rtx_REG (SImode
, regno
);
1495 if (!crtl
->calls_eh_return
)
1496 MEM_READONLY_P (mem
) = 1;
1497 EMIT_PL (emit_insn (gen_pushsi_score7 (mem
, reg
)));
1505 if (size
>= -32768 && size
<= 32767)
1506 EMIT_PL (emit_insn (gen_add3_insn (stack_pointer_rtx
,
1511 EMIT_PL (emit_move_insn (gen_rtx_REG (Pmode
, SCORE_PROLOGUE_TEMP_REGNUM
),
1514 (gen_sub3_insn (stack_pointer_rtx
,
1517 SCORE_PROLOGUE_TEMP_REGNUM
))));
1519 insn
= get_last_insn ();
1521 alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR
,
1522 gen_rtx_SET (VOIDmode
, stack_pointer_rtx
,
1523 plus_constant (Pmode
, stack_pointer_rtx
,
1528 if (frame_pointer_needed
)
1529 EMIT_PL (emit_move_insn (hard_frame_pointer_rtx
, stack_pointer_rtx
));
1531 if (flag_pic
&& f
->cprestore_size
)
1533 if (frame_pointer_needed
)
1534 emit_insn (gen_cprestore_use_fp_score7 (GEN_INT (size
- f
->cprestore_size
)));
1536 emit_insn (gen_cprestore_use_sp_score7 (GEN_INT (size
- f
->cprestore_size
)));
1542 /* Generate the epilogue instructions in a S+core function. */
1544 score_epilogue (int sibcall_p
)
1546 struct score_frame_info
*f
= score_compute_frame_size (get_frame_size ());
1551 size
= f
->total_size
- f
->gp_reg_size
;
1553 if (!frame_pointer_needed
)
1554 base
= stack_pointer_rtx
;
1556 base
= hard_frame_pointer_rtx
;
1560 if (size
>= -32768 && size
<= 32767)
1561 emit_insn (gen_add3_insn (base
, base
, GEN_INT (size
)));
1564 emit_move_insn (gen_rtx_REG (Pmode
, SCORE_EPILOGUE_TEMP_REGNUM
),
1566 emit_insn (gen_add3_insn (base
, base
,
1568 SCORE_EPILOGUE_TEMP_REGNUM
)));
1572 if (base
!= stack_pointer_rtx
)
1573 emit_move_insn (stack_pointer_rtx
, base
);
1575 if (crtl
->calls_eh_return
)
1576 emit_insn (gen_add3_insn (stack_pointer_rtx
,
1578 EH_RETURN_STACKADJ_RTX
));
1580 for (regno
= (int) GP_REG_FIRST
; regno
<= (int) GP_REG_LAST
; regno
++)
1582 if (BITSET_P (f
->mask
, regno
- GP_REG_FIRST
))
1584 rtx mem
= gen_rtx_MEM (SImode
,
1585 gen_rtx_POST_INC (SImode
, stack_pointer_rtx
));
1586 rtx reg
= gen_rtx_REG (SImode
, regno
);
1588 if (!crtl
->calls_eh_return
)
1589 MEM_READONLY_P (mem
) = 1;
1591 emit_insn (gen_popsi_score7 (reg
, mem
));
1596 emit_jump_insn (gen_return_internal_score7 (gen_rtx_REG (Pmode
, RA_REGNUM
)));
1599 /* Return true if X is a symbolic constant that can be calculated in
1600 the same way as a bare symbol. If it is, store the type of the
1601 symbol in *SYMBOL_TYPE. */
1603 score_symbolic_constant_p (rtx x
, enum score_symbol_type
*symbol_type
)
1605 HOST_WIDE_INT offset
;
1607 score_split_const (x
, &x
, &offset
);
1608 if (GET_CODE (x
) == SYMBOL_REF
|| GET_CODE (x
) == LABEL_REF
)
1609 *symbol_type
= score_classify_symbol (x
);
1616 /* if offset > 15bit, must reload */
1617 if (!IMM_IN_RANGE (offset
, 15, 1))
1620 switch (*symbol_type
)
1622 case SYMBOL_GENERAL
:
1624 case SYMBOL_SMALL_DATA
:
1625 return score_offset_within_object_p (x
, offset
);
1631 score_movsicc (rtx
*ops
)
1633 enum machine_mode mode
;
1635 mode
= score_select_cc_mode (GET_CODE (ops
[1]), ops
[2], ops
[3]);
1636 emit_insn (gen_rtx_SET (VOIDmode
, gen_rtx_REG (mode
, CC_REGNUM
),
1637 gen_rtx_COMPARE (mode
, XEXP (ops
[1], 0),
1638 XEXP (ops
[1], 1))));
1641 /* Call and sibcall pattern all need call this function. */
1643 score_call (rtx
*ops
, bool sib
)
1645 rtx addr
= XEXP (ops
[0], 0);
1646 if (!call_insn_operand (addr
, VOIDmode
))
1649 addr
= gen_reg_rtx (Pmode
);
1650 gen_move_insn (addr
, oaddr
);
1654 emit_call_insn (gen_sibcall_internal_score7 (addr
, ops
[1]));
1656 emit_call_insn (gen_call_internal_score7 (addr
, ops
[1]));
1659 /* Call value and sibcall value pattern all need call this function. */
1661 score_call_value (rtx
*ops
, bool sib
)
1663 rtx result
= ops
[0];
1664 rtx addr
= XEXP (ops
[1], 0);
1667 if (!call_insn_operand (addr
, VOIDmode
))
1670 addr
= gen_reg_rtx (Pmode
);
1671 gen_move_insn (addr
, oaddr
);
1675 emit_call_insn (gen_sibcall_value_internal_score7 (result
, addr
, arg
));
1677 emit_call_insn (gen_call_value_internal_score7 (result
, addr
, arg
));
1682 score_movdi (rtx
*ops
)
1686 rtx dst0
= score_subw (dst
, 0);
1687 rtx dst1
= score_subw (dst
, 1);
1688 rtx src0
= score_subw (src
, 0);
1689 rtx src1
= score_subw (src
, 1);
1691 if (GET_CODE (dst0
) == REG
&& reg_overlap_mentioned_p (dst0
, src
))
1693 emit_move_insn (dst1
, src1
);
1694 emit_move_insn (dst0
, src0
);
1698 emit_move_insn (dst0
, src0
);
1699 emit_move_insn (dst1
, src1
);
1704 score_zero_extract_andi (rtx
*ops
)
1706 if (INTVAL (ops
[1]) == 1 && const_uimm5 (ops
[2], SImode
))
1707 emit_insn (gen_zero_extract_bittst_score7 (ops
[0], ops
[2]));
1710 unsigned HOST_WIDE_INT mask
;
1711 mask
= (0xffffffffU
& ((1U << INTVAL (ops
[1])) - 1U));
1712 mask
= mask
<< INTVAL (ops
[2]);
1713 emit_insn (gen_andsi3_cmp_score7 (ops
[3], ops
[0],
1714 gen_int_mode (mask
, SImode
)));
1718 /* Check addr could be present as PRE/POST mode. */
1720 score_pindex_mem (rtx addr
)
1722 if (GET_CODE (addr
) == MEM
)
1724 switch (GET_CODE (XEXP (addr
, 0)))
1738 /* Output asm code for ld/sw insn. */
1740 score_pr_addr_post (rtx
*ops
, int idata
, int iaddr
, char *ip
, enum score_mem_unit unit
)
1742 struct score_address_info ai
;
1744 gcc_assert (GET_CODE (ops
[idata
]) == REG
);
1745 gcc_assert (score_classify_address (&ai
, SImode
, XEXP (ops
[iaddr
], 0), true));
1747 if (!score_pindex_mem (ops
[iaddr
])
1748 && ai
.type
== SCORE_ADD_REG
1749 && GET_CODE (ai
.offset
) == CONST_INT
1750 && G16_REG_P (REGNO (ops
[idata
]))
1751 && G16_REG_P (REGNO (ai
.reg
)))
1753 if (INTVAL (ai
.offset
) == 0)
1755 ops
[iaddr
] = ai
.reg
;
1756 return snprintf (ip
, INS_BUF_SZ
,
1757 "!\t%%%d, [%%%d]", idata
, iaddr
);
1759 if (REGNO (ai
.reg
) == HARD_FRAME_POINTER_REGNUM
)
1761 HOST_WIDE_INT offset
= INTVAL (ai
.offset
);
1762 if (SCORE_ALIGN_UNIT (offset
, unit
)
1763 && (((offset
>> unit
) >= 0) && ((offset
>> unit
) <= 31)))
1765 ops
[iaddr
] = ai
.offset
;
1766 return snprintf (ip
, INS_BUF_SZ
,
1767 "p!\t%%%d, %%c%d", idata
, iaddr
);
1771 return snprintf (ip
, INS_BUF_SZ
, "\t%%%d, %%a%d", idata
, iaddr
);
1774 /* Output asm insn for load. */
1776 score_linsn (rtx
*ops
, enum score_mem_unit unit
, bool sign
)
1778 const char *pre_ins
[] =
1779 {"lbu", "lhu", "lw", "??", "lb", "lh", "lw", "??"};
1782 strcpy (score_ins
, pre_ins
[(sign
? 4 : 0) + unit
]);
1783 ip
= score_ins
+ strlen (score_ins
);
1785 if ((!sign
&& unit
!= SCORE_HWORD
)
1786 || (sign
&& unit
!= SCORE_BYTE
))
1787 score_pr_addr_post (ops
, 0, 1, ip
, unit
);
1789 snprintf (ip
, INS_BUF_SZ
, "\t%%0, %%a1");
1794 /* Output asm insn for store. */
1796 score_sinsn (rtx
*ops
, enum score_mem_unit unit
)
1798 const char *pre_ins
[] = {"sb", "sh", "sw"};
1801 strcpy (score_ins
, pre_ins
[unit
]);
1802 ip
= score_ins
+ strlen (score_ins
);
1803 score_pr_addr_post (ops
, 1, 0, ip
, unit
);
1807 /* Output asm insn for load immediate. */
1809 score_limm (rtx
*ops
)
1813 gcc_assert (GET_CODE (ops
[0]) == REG
);
1814 gcc_assert (GET_CODE (ops
[1]) == CONST_INT
);
1816 v
= INTVAL (ops
[1]);
1817 if (G16_REG_P (REGNO (ops
[0])) && IMM_IN_RANGE (v
, 8, 0))
1818 return "ldiu!\t%0, %c1";
1819 else if (IMM_IN_RANGE (v
, 16, 1))
1820 return "ldi\t%0, %c1";
1821 else if ((v
& 0xffff) == 0)
1822 return "ldis\t%0, %U1";
1824 return "li\t%0, %c1";
1827 /* Output asm insn for move. */
1829 score_move (rtx
*ops
)
1831 gcc_assert (GET_CODE (ops
[0]) == REG
);
1832 gcc_assert (GET_CODE (ops
[1]) == REG
);
1834 if (G16_REG_P (REGNO (ops
[0])))
1836 if (G16_REG_P (REGNO (ops
[1])))
1837 return "mv!\t%0, %1";
1839 return "mlfh!\t%0, %1";
1841 else if (G16_REG_P (REGNO (ops
[1])))
1842 return "mhfl!\t%0, %1";
1844 return "mv\t%0, %1";
1847 /* Generate add insn. */
1849 score_select_add_imm (rtx
*ops
, bool set_cc
)
1851 HOST_WIDE_INT v
= INTVAL (ops
[2]);
1853 gcc_assert (GET_CODE (ops
[2]) == CONST_INT
);
1854 gcc_assert (REGNO (ops
[0]) == REGNO (ops
[1]));
1856 if (set_cc
&& G16_REG_P (REGNO (ops
[0])))
1858 if (v
> 0 && IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT
) v
, 0, 15))
1860 ops
[2] = GEN_INT (ffs (v
) - 1);
1861 return "addei!\t%0, %c2";
1864 if (v
< 0 && IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT
) (-v
), 0, 15))
1866 ops
[2] = GEN_INT (ffs (-v
) - 1);
1867 return "subei!\t%0, %c2";
1872 return "addi.c\t%0, %c2";
1874 return "addi\t%0, %c2";
1877 /* Output arith insn. */
1879 score_select (rtx
*ops
, const char *inst_pre
,
1880 bool commu
, const char *letter
, bool set_cc
)
1882 gcc_assert (GET_CODE (ops
[0]) == REG
);
1883 gcc_assert (GET_CODE (ops
[1]) == REG
);
1885 if (set_cc
&& G16_REG_P (REGNO (ops
[0]))
1886 && (GET_CODE (ops
[2]) == REG
? G16_REG_P (REGNO (ops
[2])) : 1)
1887 && REGNO (ops
[0]) == REGNO (ops
[1]))
1889 snprintf (score_ins
, INS_BUF_SZ
, "%s!\t%%0, %%%s2", inst_pre
, letter
);
1893 if (commu
&& set_cc
&& G16_REG_P (REGNO (ops
[0]))
1894 && G16_REG_P (REGNO (ops
[1]))
1895 && REGNO (ops
[0]) == REGNO (ops
[2]))
1897 gcc_assert (GET_CODE (ops
[2]) == REG
);
1898 snprintf (score_ins
, INS_BUF_SZ
, "%s!\t%%0, %%%s1", inst_pre
, letter
);
1903 snprintf (score_ins
, INS_BUF_SZ
, "%s.c\t%%0, %%1, %%%s2", inst_pre
, letter
);
1905 snprintf (score_ins
, INS_BUF_SZ
, "%s\t%%0, %%1, %%%s2", inst_pre
, letter
);
1909 /* Return nonzero when an argument must be passed by reference. */
1911 score_pass_by_reference (cumulative_args_t cum ATTRIBUTE_UNUSED
,
1912 enum machine_mode mode
, const_tree type
,
1913 bool named ATTRIBUTE_UNUSED
)
1915 /* If we have a variable-sized parameter, we have no choice. */
1916 return targetm
.calls
.must_pass_in_stack (mode
, type
);
1919 /* Implement TARGET_FUNCTION_OK_FOR_SIBCALL. */
1921 score_function_ok_for_sibcall (ATTRIBUTE_UNUSED tree decl
,
1922 ATTRIBUTE_UNUSED tree exp
)
1927 /* Implement TARGET_SCHED_ISSUE_RATE. */
1929 score_issue_rate (void)
1934 /* We can always eliminate to the hard frame pointer. We can eliminate
1935 to the stack pointer unless a frame pointer is needed. */
1938 score_can_eliminate (const int from ATTRIBUTE_UNUSED
, const int to
)
1940 return (to
== HARD_FRAME_POINTER_REGNUM
1941 || (to
== STACK_POINTER_REGNUM
&& !frame_pointer_needed
));
1944 /* Argument support functions. */
1946 /* Initialize CUMULATIVE_ARGS for a function. */
1948 score_init_cumulative_args (CUMULATIVE_ARGS
*cum
,
1949 tree fntype ATTRIBUTE_UNUSED
,
1950 rtx libname ATTRIBUTE_UNUSED
)
1952 memset (cum
, 0, sizeof (CUMULATIVE_ARGS
));
1956 score_conditional_register_usage (void)
1959 fixed_regs
[PIC_OFFSET_TABLE_REGNUM
] =
1960 call_used_regs
[PIC_OFFSET_TABLE_REGNUM
] = 0;
1963 struct gcc_target targetm
= TARGET_INITIALIZER
;