Rebase.
[official-gcc.git] / gcc / config / score / score.c
blobd65684c45e49a64f0dbeb88c3d33da2f286dca2b
1 /* Output routines for Sunplus S+CORE processor
2 Copyright (C) 2005-2014 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/>. */
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "tm.h"
25 #include "rtl.h"
26 #include "regs.h"
27 #include "hard-reg-set.h"
28 #include "insn-config.h"
29 #include "conditions.h"
30 #include "insn-attr.h"
31 #include "recog.h"
32 #include "diagnostic-core.h"
33 #include "output.h"
34 #include "tree.h"
35 #include "stringpool.h"
36 #include "calls.h"
37 #include "varasm.h"
38 #include "stor-layout.h"
39 #include "function.h"
40 #include "expr.h"
41 #include "optabs.h"
42 #include "flags.h"
43 #include "reload.h"
44 #include "tm_p.h"
45 #include "ggc.h"
46 #include "gstab.h"
47 #include "hashtab.h"
48 #include "debug.h"
49 #include "target.h"
50 #include "target-def.h"
51 #include "langhooks.h"
52 #include "df.h"
53 #include "opts.h"
54 #include "builtins.h"
56 #define SCORE_SDATA_MAX score_sdata_max
57 #define SCORE_STACK_ALIGN(LOC) (((LOC) + 3) & ~3)
58 #define SCORE_PROLOGUE_TEMP_REGNUM (GP_REG_FIRST + 8)
59 #define SCORE_EPILOGUE_TEMP_REGNUM (GP_REG_FIRST + 8)
60 #define SCORE_DEFAULT_SDATA_MAX 8
62 #define BITSET_P(VALUE, BIT) (((VALUE) & (1L << (BIT))) != 0)
63 #define INS_BUF_SZ 128
65 enum score_address_type
67 SCORE_ADD_REG,
68 SCORE_ADD_CONST_INT,
69 SCORE_ADD_SYMBOLIC
72 struct score_frame_info
74 HOST_WIDE_INT total_size; /* bytes that the entire frame takes up */
75 HOST_WIDE_INT var_size; /* bytes that variables take up */
76 HOST_WIDE_INT args_size; /* bytes that outgoing arguments take up */
77 HOST_WIDE_INT gp_reg_size; /* bytes needed to store gp regs */
78 HOST_WIDE_INT gp_sp_offset; /* offset from new sp to store gp registers */
79 HOST_WIDE_INT cprestore_size; /* # bytes that the .cprestore slot takes up */
80 unsigned int mask; /* mask of saved gp registers */
81 int num_gp; /* number of gp registers saved */
84 struct score_arg_info
86 unsigned int num_bytes; /* The argument's size in bytes */
87 unsigned int reg_words; /* The number of words passed in registers */
88 unsigned int reg_offset; /* The offset of the first register from */
89 /* GP_ARG_FIRST or FP_ARG_FIRST etc */
90 unsigned int stack_words; /* The number of words that must be passed */
91 /* on the stack */
92 unsigned int stack_offset; /* The offset from the start of the stack */
93 /* overflow area */
96 #ifdef RTX_CODE
97 struct score_address_info
99 enum score_address_type type;
100 rtx reg;
101 rtx offset;
102 enum rtx_code code;
103 enum score_symbol_type symbol_type;
105 #endif
107 static int score_sdata_max;
108 static char score_ins[INS_BUF_SZ + 8];
110 struct extern_list *extern_head = 0;
112 #undef TARGET_ASM_FILE_START
113 #define TARGET_ASM_FILE_START score_asm_file_start
115 #undef TARGET_ASM_FILE_END
116 #define TARGET_ASM_FILE_END score_asm_file_end
118 #undef TARGET_ASM_FUNCTION_PROLOGUE
119 #define TARGET_ASM_FUNCTION_PROLOGUE score_function_prologue
121 #undef TARGET_ASM_FUNCTION_EPILOGUE
122 #define TARGET_ASM_FUNCTION_EPILOGUE score_function_epilogue
124 #undef TARGET_OPTION_OVERRIDE
125 #define TARGET_OPTION_OVERRIDE score_option_override
127 #undef TARGET_SCHED_ISSUE_RATE
128 #define TARGET_SCHED_ISSUE_RATE score_issue_rate
130 #undef TARGET_ASM_SELECT_RTX_SECTION
131 #define TARGET_ASM_SELECT_RTX_SECTION score_select_rtx_section
133 #undef TARGET_IN_SMALL_DATA_P
134 #define TARGET_IN_SMALL_DATA_P score_in_small_data_p
136 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
137 #define TARGET_FUNCTION_OK_FOR_SIBCALL score_function_ok_for_sibcall
139 #undef TARGET_STRICT_ARGUMENT_NAMING
140 #define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true
142 #undef TARGET_ASM_OUTPUT_MI_THUNK
143 #define TARGET_ASM_OUTPUT_MI_THUNK score_output_mi_thunk
145 #undef TARGET_PROMOTE_FUNCTION_MODE
146 #define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
148 #undef TARGET_PROMOTE_PROTOTYPES
149 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
151 #undef TARGET_MUST_PASS_IN_STACK
152 #define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size
154 #undef TARGET_ARG_PARTIAL_BYTES
155 #define TARGET_ARG_PARTIAL_BYTES score_arg_partial_bytes
157 #undef TARGET_FUNCTION_ARG
158 #define TARGET_FUNCTION_ARG score_function_arg
160 #undef TARGET_FUNCTION_ARG_ADVANCE
161 #define TARGET_FUNCTION_ARG_ADVANCE score_function_arg_advance
163 #undef TARGET_PASS_BY_REFERENCE
164 #define TARGET_PASS_BY_REFERENCE score_pass_by_reference
166 #undef TARGET_RETURN_IN_MEMORY
167 #define TARGET_RETURN_IN_MEMORY score_return_in_memory
169 #undef TARGET_RTX_COSTS
170 #define TARGET_RTX_COSTS score_rtx_costs
172 #undef TARGET_ADDRESS_COST
173 #define TARGET_ADDRESS_COST score_address_cost
175 #undef TARGET_LEGITIMATE_ADDRESS_P
176 #define TARGET_LEGITIMATE_ADDRESS_P score_legitimate_address_p
178 #undef TARGET_CAN_ELIMINATE
179 #define TARGET_CAN_ELIMINATE score_can_eliminate
181 #undef TARGET_CONDITIONAL_REGISTER_USAGE
182 #define TARGET_CONDITIONAL_REGISTER_USAGE score_conditional_register_usage
184 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
185 #define TARGET_ASM_TRAMPOLINE_TEMPLATE score_asm_trampoline_template
186 #undef TARGET_TRAMPOLINE_INIT
187 #define TARGET_TRAMPOLINE_INIT score_trampoline_init
189 #undef TARGET_REGISTER_MOVE_COST
190 #define TARGET_REGISTER_MOVE_COST score_register_move_cost
192 /* Return true if SYMBOL is a SYMBOL_REF and OFFSET + SYMBOL points
193 to the same object as SYMBOL. */
194 static int
195 score_offset_within_object_p (rtx symbol, HOST_WIDE_INT offset)
197 if (GET_CODE (symbol) != SYMBOL_REF)
198 return 0;
200 if (CONSTANT_POOL_ADDRESS_P (symbol)
201 && offset >= 0
202 && offset < (int)GET_MODE_SIZE (get_pool_mode (symbol)))
203 return 1;
205 if (SYMBOL_REF_DECL (symbol) != 0
206 && offset >= 0
207 && offset < int_size_in_bytes (TREE_TYPE (SYMBOL_REF_DECL (symbol))))
208 return 1;
210 return 0;
213 /* Split X into a base and a constant offset, storing them in *BASE
214 and *OFFSET respectively. */
215 static void
216 score_split_const (rtx x, rtx *base, HOST_WIDE_INT *offset)
218 *offset = 0;
220 if (GET_CODE (x) == CONST)
221 x = XEXP (x, 0);
223 if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
225 *offset += INTVAL (XEXP (x, 1));
226 x = XEXP (x, 0);
229 *base = x;
232 /* Classify symbol X, which must be a SYMBOL_REF or a LABEL_REF. */
233 static enum score_symbol_type
234 score_classify_symbol (rtx x)
236 if (GET_CODE (x) == LABEL_REF)
237 return SYMBOL_GENERAL;
239 gcc_assert (GET_CODE (x) == SYMBOL_REF);
241 if (CONSTANT_POOL_ADDRESS_P (x))
243 if (GET_MODE_SIZE (get_pool_mode (x)) <= SCORE_SDATA_MAX)
244 return SYMBOL_SMALL_DATA;
245 return SYMBOL_GENERAL;
247 if (SYMBOL_REF_SMALL_P (x))
248 return SYMBOL_SMALL_DATA;
249 return SYMBOL_GENERAL;
252 /* Return true if the current function must save REGNO. */
253 static int
254 score_save_reg_p (unsigned int regno)
256 /* Check call-saved registers. */
257 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
258 return 1;
260 /* We need to save the old frame pointer before setting up a new one. */
261 if (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed)
262 return 1;
264 /* We need to save the incoming return address if it is ever clobbered
265 within the function. */
266 if (regno == RA_REGNUM && df_regs_ever_live_p (regno))
267 return 1;
269 return 0;
272 /* Return one word of double-word value OP, taking into account the fixed
273 endianness of certain registers. HIGH_P is true to select the high part,
274 false to select the low part. */
275 static rtx
276 score_subw (rtx op, int high_p)
278 unsigned int byte;
279 enum machine_mode mode = GET_MODE (op);
281 if (mode == VOIDmode)
282 mode = DImode;
284 byte = (TARGET_LITTLE_ENDIAN ? high_p : !high_p) ? UNITS_PER_WORD : 0;
286 if (GET_CODE (op) == REG && REGNO (op) == HI_REGNUM)
287 return gen_rtx_REG (SImode, high_p ? HI_REGNUM : LO_REGNUM);
289 if (GET_CODE (op) == MEM)
290 return adjust_address (op, SImode, byte);
292 return simplify_gen_subreg (SImode, op, mode, byte);
295 static struct score_frame_info *
296 score_cached_frame (void)
298 static struct score_frame_info _frame_info;
299 return &_frame_info;
302 /* Return the bytes needed to compute the frame pointer from the current
303 stack pointer. SIZE is the size (in bytes) of the local variables. */
304 static struct score_frame_info *
305 score_compute_frame_size (HOST_WIDE_INT size)
307 unsigned int regno;
308 struct score_frame_info *f = score_cached_frame ();
310 memset (f, 0, sizeof (struct score_frame_info));
311 f->gp_reg_size = 0;
312 f->mask = 0;
313 f->var_size = SCORE_STACK_ALIGN (size);
314 f->args_size = crtl->outgoing_args_size;
315 f->cprestore_size = flag_pic ? UNITS_PER_WORD : 0;
316 if (f->var_size == 0 && crtl->is_leaf)
317 f->args_size = f->cprestore_size = 0;
319 if (f->args_size == 0 && cfun->calls_alloca)
320 f->args_size = UNITS_PER_WORD;
322 f->total_size = f->var_size + f->args_size + f->cprestore_size;
323 for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
325 if (score_save_reg_p (regno))
327 f->gp_reg_size += GET_MODE_SIZE (SImode);
328 f->mask |= 1 << (regno - GP_REG_FIRST);
332 if (crtl->calls_eh_return)
334 unsigned int i;
335 for (i = 0;; ++i)
337 regno = EH_RETURN_DATA_REGNO (i);
338 if (regno == INVALID_REGNUM)
339 break;
340 f->gp_reg_size += GET_MODE_SIZE (SImode);
341 f->mask |= 1 << (regno - GP_REG_FIRST);
345 f->total_size += f->gp_reg_size;
346 f->num_gp = f->gp_reg_size / UNITS_PER_WORD;
348 if (f->mask)
350 HOST_WIDE_INT offset;
351 offset = (f->args_size + f->cprestore_size + f->var_size
352 + f->gp_reg_size - GET_MODE_SIZE (SImode));
353 f->gp_sp_offset = offset;
355 else
356 f->gp_sp_offset = 0;
358 return f;
361 /* Return true if X is a valid base register for the given mode.
362 Allow only hard registers if STRICT. */
363 static int
364 score_valid_base_register_p (rtx x, int strict)
366 if (!strict && GET_CODE (x) == SUBREG)
367 x = SUBREG_REG (x);
369 return (GET_CODE (x) == REG
370 && score_regno_mode_ok_for_base_p (REGNO (x), strict));
373 /* Return true if X is a valid address for machine mode MODE. If it is,
374 fill in INFO appropriately. STRICT is true if we should only accept
375 hard base registers. */
376 static int
377 score_classify_address (struct score_address_info *info,
378 enum machine_mode mode, rtx x, int strict)
380 info->code = GET_CODE (x);
382 switch (info->code)
384 case REG:
385 case SUBREG:
386 info->type = SCORE_ADD_REG;
387 info->reg = x;
388 info->offset = const0_rtx;
389 return score_valid_base_register_p (info->reg, strict);
390 case PLUS:
391 info->type = SCORE_ADD_REG;
392 info->reg = XEXP (x, 0);
393 info->offset = XEXP (x, 1);
394 return (score_valid_base_register_p (info->reg, strict)
395 && GET_CODE (info->offset) == CONST_INT
396 && IMM_IN_RANGE (INTVAL (info->offset), 15, 1));
397 case PRE_DEC:
398 case POST_DEC:
399 case PRE_INC:
400 case POST_INC:
401 if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (SImode))
402 return false;
403 info->type = SCORE_ADD_REG;
404 info->reg = XEXP (x, 0);
405 info->offset = GEN_INT (GET_MODE_SIZE (mode));
406 return score_valid_base_register_p (info->reg, strict);
407 case CONST_INT:
408 info->type = SCORE_ADD_CONST_INT;
409 return IMM_IN_RANGE (INTVAL (x), 15, 1);
410 case CONST:
411 case LABEL_REF:
412 case SYMBOL_REF:
413 info->type = SCORE_ADD_SYMBOLIC;
414 return (score_symbolic_constant_p (x, &info->symbol_type)
415 && (info->symbol_type == SYMBOL_GENERAL
416 || info->symbol_type == SYMBOL_SMALL_DATA));
417 default:
418 return 0;
422 /* Implement TARGET_RETURN_IN_MEMORY. In S+core,
423 small structures are returned in a register.
424 Objects with varying size must still be returned in memory. */
425 static bool
426 score_return_in_memory (const_tree type, const_tree fndecl ATTRIBUTE_UNUSED)
428 return ((TYPE_MODE (type) == BLKmode)
429 || (int_size_in_bytes (type) > 2 * UNITS_PER_WORD)
430 || (int_size_in_bytes (type) == -1));
433 /* Return a legitimate address for REG + OFFSET. */
434 static rtx
435 score_add_offset (rtx reg, HOST_WIDE_INT offset)
437 if (!IMM_IN_RANGE (offset, 15, 1))
439 reg = expand_simple_binop (GET_MODE (reg), PLUS,
440 gen_int_mode (offset & 0xffffc000,
441 GET_MODE (reg)),
442 reg, NULL, 0, OPTAB_WIDEN);
443 offset &= 0x3fff;
446 return plus_constant (GET_MODE (reg), reg, offset);
449 /* Implement TARGET_ASM_OUTPUT_MI_THUNK. Generate rtl rather than asm text
450 in order to avoid duplicating too much logic from elsewhere. */
451 static void
452 score_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
453 HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
454 tree function)
456 rtx this_rtx, temp1, insn, fnaddr;
458 /* Pretend to be a post-reload pass while generating rtl. */
459 reload_completed = 1;
461 /* Mark the end of the (empty) prologue. */
462 emit_note (NOTE_INSN_PROLOGUE_END);
464 /* We need two temporary registers in some cases. */
465 temp1 = gen_rtx_REG (Pmode, 8);
467 /* Find out which register contains the "this" pointer. */
468 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
469 this_rtx = gen_rtx_REG (Pmode, ARG_REG_FIRST + 1);
470 else
471 this_rtx = gen_rtx_REG (Pmode, ARG_REG_FIRST);
473 /* Add DELTA to THIS_RTX. */
474 if (delta != 0)
476 rtx offset = GEN_INT (delta);
477 if (!(delta >= -32768 && delta <= 32767))
479 emit_move_insn (temp1, offset);
480 offset = temp1;
482 emit_insn (gen_add3_insn (this_rtx, this_rtx, offset));
485 /* If needed, add *(*THIS_RTX + VCALL_OFFSET) to THIS_RTX. */
486 if (vcall_offset != 0)
488 rtx addr;
490 /* Set TEMP1 to *THIS_RTX. */
491 emit_move_insn (temp1, gen_rtx_MEM (Pmode, this_rtx));
493 /* Set ADDR to a legitimate address for *THIS_RTX + VCALL_OFFSET. */
494 addr = score_add_offset (temp1, vcall_offset);
496 /* Load the offset and add it to THIS_RTX. */
497 emit_move_insn (temp1, gen_rtx_MEM (Pmode, addr));
498 emit_insn (gen_add3_insn (this_rtx, this_rtx, temp1));
501 /* Jump to the target function. */
502 fnaddr = XEXP (DECL_RTL (function), 0);
503 insn = emit_call_insn (gen_sibcall_internal_score7 (fnaddr, const0_rtx));
504 SIBLING_CALL_P (insn) = 1;
506 /* Run just enough of rest_of_compilation. This sequence was
507 "borrowed" from alpha.c. */
508 insn = get_insns ();
509 split_all_insns_noflow ();
510 shorten_branches (insn);
511 final_start_function (insn, file, 1);
512 final (insn, file, 1);
513 final_end_function ();
515 /* Clean up the vars set above. Note that final_end_function resets
516 the global pointer for us. */
517 reload_completed = 0;
520 /* Fill INFO with information about a single argument. CUM is the
521 cumulative state for earlier arguments. MODE is the mode of this
522 argument and TYPE is its type (if known). NAMED is true if this
523 is a named (fixed) argument rather than a variable one. */
524 static void
525 score_classify_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
526 const_tree type, bool named, struct score_arg_info *info)
528 int even_reg_p;
529 unsigned int num_words, max_regs;
531 even_reg_p = 0;
532 if (GET_MODE_CLASS (mode) == MODE_INT
533 || GET_MODE_CLASS (mode) == MODE_FLOAT)
534 even_reg_p = (GET_MODE_SIZE (mode) > UNITS_PER_WORD);
535 else
536 if (type != NULL_TREE && TYPE_ALIGN (type) > BITS_PER_WORD && named)
537 even_reg_p = 1;
539 if (TARGET_MUST_PASS_IN_STACK (mode, type))
540 info->reg_offset = ARG_REG_NUM;
541 else
543 info->reg_offset = cum->num_gprs;
544 if (even_reg_p)
545 info->reg_offset += info->reg_offset & 1;
548 if (mode == BLKmode)
549 info->num_bytes = int_size_in_bytes (type);
550 else
551 info->num_bytes = GET_MODE_SIZE (mode);
553 num_words = (info->num_bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
554 max_regs = ARG_REG_NUM - info->reg_offset;
556 /* Partition the argument between registers and stack. */
557 info->reg_words = MIN (num_words, max_regs);
558 info->stack_words = num_words - info->reg_words;
560 /* The alignment applied to registers is also applied to stack arguments. */
561 if (info->stack_words)
563 info->stack_offset = cum->stack_words;
564 if (even_reg_p)
565 info->stack_offset += info->stack_offset & 1;
569 /* Set up the stack and frame (if desired) for the function. */
570 static void
571 score_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
573 const char *fnname;
574 struct score_frame_info *f = score_cached_frame ();
575 HOST_WIDE_INT tsize = f->total_size;
577 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
578 if (!flag_inhibit_size_directive)
580 fputs ("\t.ent\t", file);
581 assemble_name (file, fnname);
582 fputs ("\n", file);
584 assemble_name (file, fnname);
585 fputs (":\n", file);
587 if (!flag_inhibit_size_directive)
589 fprintf (file,
590 "\t.frame\t%s," HOST_WIDE_INT_PRINT_DEC ",%s, %d\t\t"
591 "# vars= " HOST_WIDE_INT_PRINT_DEC ", regs= %d"
592 ", args= " HOST_WIDE_INT_PRINT_DEC
593 ", gp= " HOST_WIDE_INT_PRINT_DEC "\n",
594 (reg_names[(frame_pointer_needed)
595 ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM]),
596 tsize,
597 reg_names[RA_REGNUM],
598 crtl->is_leaf ? 1 : 0,
599 f->var_size,
600 f->num_gp,
601 f->args_size,
602 f->cprestore_size);
604 fprintf(file, "\t.mask\t0x%08x," HOST_WIDE_INT_PRINT_DEC "\n",
605 f->mask,
606 (f->gp_sp_offset - f->total_size));
610 /* Do any necessary cleanup after a function to restore stack, frame,
611 and regs. */
612 static void
613 score_function_epilogue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
615 if (!flag_inhibit_size_directive)
617 const char *fnname;
618 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
619 fputs ("\t.end\t", file);
620 assemble_name (file, fnname);
621 fputs ("\n", file);
625 /* Returns true if X contains a SYMBOL_REF. */
626 static bool
627 score_symbolic_expression_p (rtx x)
629 if (GET_CODE (x) == SYMBOL_REF)
630 return true;
632 if (GET_CODE (x) == CONST)
633 return score_symbolic_expression_p (XEXP (x, 0));
635 if (UNARY_P (x))
636 return score_symbolic_expression_p (XEXP (x, 0));
638 if (ARITHMETIC_P (x))
639 return (score_symbolic_expression_p (XEXP (x, 0))
640 || score_symbolic_expression_p (XEXP (x, 1)));
642 return false;
645 /* Choose the section to use for the constant rtx expression X that has
646 mode MODE. */
647 static section *
648 score_select_rtx_section (enum machine_mode mode, rtx x, unsigned HOST_WIDE_INT align)
650 if (GET_MODE_SIZE (mode) <= SCORE_SDATA_MAX)
651 return get_named_section (0, ".sdata", 0);
652 else if (flag_pic && score_symbolic_expression_p (x))
653 return get_named_section (0, ".data.rel.ro", 3);
654 else
655 return mergeable_constant_section (mode, align, 0);
658 /* Implement TARGET_IN_SMALL_DATA_P. */
659 static bool
660 score_in_small_data_p (const_tree decl)
662 HOST_WIDE_INT size;
664 if (TREE_CODE (decl) == STRING_CST
665 || TREE_CODE (decl) == FUNCTION_DECL)
666 return false;
668 if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl) != 0)
670 const char *name;
671 name = DECL_SECTION_NAME (decl);
672 if (strcmp (name, ".sdata") != 0
673 && strcmp (name, ".sbss") != 0)
674 return true;
675 if (!DECL_EXTERNAL (decl))
676 return false;
678 size = int_size_in_bytes (TREE_TYPE (decl));
679 return (size > 0 && size <= SCORE_SDATA_MAX);
682 /* Implement TARGET_ASM_FILE_START. */
683 static void
684 score_asm_file_start (void)
686 default_file_start ();
687 fprintf (asm_out_file, ASM_COMMENT_START
688 "GCC for S+core %s \n", SCORE_GCC_VERSION);
690 if (flag_pic)
691 fprintf (asm_out_file, "\t.set pic\n");
694 /* Implement TARGET_ASM_FILE_END. When using assembler macros, emit
695 .externs for any small-data variables that turned out to be external. */
696 static void
697 score_asm_file_end (void)
699 tree name_tree;
700 struct extern_list *p;
701 if (extern_head)
703 fputs ("\n", asm_out_file);
704 for (p = extern_head; p != 0; p = p->next)
706 name_tree = get_identifier (p->name);
707 if (!TREE_ASM_WRITTEN (name_tree)
708 && TREE_SYMBOL_REFERENCED (name_tree))
710 TREE_ASM_WRITTEN (name_tree) = 1;
711 fputs ("\t.extern\t", asm_out_file);
712 assemble_name (asm_out_file, p->name);
713 fprintf (asm_out_file, ", %d\n", p->size);
719 /* Implement TARGET_OPTION_OVERRIDE hook. */
720 static void
721 score_option_override (void)
723 flag_pic = false;
724 score_sdata_max = SCORE_DEFAULT_SDATA_MAX;
728 /* Implement REGNO_REG_CLASS macro. */
730 score_reg_class (int regno)
732 int c;
733 gcc_assert (regno >= 0 && regno < FIRST_PSEUDO_REGISTER);
735 if (regno == FRAME_POINTER_REGNUM
736 || regno == ARG_POINTER_REGNUM)
737 return ALL_REGS;
739 for (c = 0; c < N_REG_CLASSES; c++)
740 if (TEST_HARD_REG_BIT (reg_class_contents[c], regno))
741 return c;
743 return NO_REGS;
746 /* Implement PREFERRED_RELOAD_CLASS macro. */
747 enum reg_class
748 score_preferred_reload_class (rtx x ATTRIBUTE_UNUSED, enum reg_class rclass)
750 if (reg_class_subset_p (G16_REGS, rclass))
751 return G16_REGS;
752 if (reg_class_subset_p (G32_REGS, rclass))
753 return G32_REGS;
754 return rclass;
757 /* Implement SECONDARY_INPUT_RELOAD_CLASS
758 and SECONDARY_OUTPUT_RELOAD_CLASS macro. */
759 enum reg_class
760 score_secondary_reload_class (enum reg_class rclass,
761 enum machine_mode mode ATTRIBUTE_UNUSED,
762 rtx x)
764 int regno = -1;
765 if (GET_CODE (x) == REG || GET_CODE(x) == SUBREG)
766 regno = true_regnum (x);
768 if (!GR_REG_CLASS_P (rclass))
769 return GP_REG_P (regno) ? NO_REGS : G32_REGS;
770 return NO_REGS;
774 /* Return truth value on whether or not a given hard register
775 can support a given mode. */
777 score_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
779 int size = GET_MODE_SIZE (mode);
780 enum mode_class mclass = GET_MODE_CLASS (mode);
782 if (mclass == MODE_CC)
783 return regno == CC_REGNUM;
784 else if (regno == FRAME_POINTER_REGNUM
785 || regno == ARG_POINTER_REGNUM)
786 return mclass == MODE_INT;
787 else if (GP_REG_P (regno))
788 /* ((regno <= (GP_REG_LAST- HARD_REGNO_NREGS (dummy, mode)) + 1) */
789 return !(regno & 1) || (size <= UNITS_PER_WORD);
790 else if (CE_REG_P (regno))
791 return (mclass == MODE_INT
792 && ((size <= UNITS_PER_WORD)
793 || (regno == CE_REG_FIRST && size == 2 * UNITS_PER_WORD)));
794 else
795 return (mclass == MODE_INT) && (size <= UNITS_PER_WORD);
798 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
799 pointer or argument pointer. TO is either the stack pointer or
800 hard frame pointer. */
801 HOST_WIDE_INT
802 score_initial_elimination_offset (int from,
803 int to ATTRIBUTE_UNUSED)
805 struct score_frame_info *f = score_compute_frame_size (get_frame_size ());
806 switch (from)
808 case ARG_POINTER_REGNUM:
809 return f->total_size;
810 case FRAME_POINTER_REGNUM:
811 return 0;
812 default:
813 gcc_unreachable ();
817 /* Implement TARGET_FUNCTION_ARG_ADVANCE hook. */
818 static void
819 score_function_arg_advance (cumulative_args_t cum_args, enum machine_mode mode,
820 const_tree type, bool named)
822 struct score_arg_info info;
823 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_args);
824 score_classify_arg (cum, mode, type, named, &info);
825 cum->num_gprs = info.reg_offset + info.reg_words;
826 if (info.stack_words > 0)
827 cum->stack_words = info.stack_offset + info.stack_words;
828 cum->arg_number++;
831 /* Implement TARGET_ARG_PARTIAL_BYTES macro. */
833 score_arg_partial_bytes (cumulative_args_t cum_args,
834 enum machine_mode mode, tree type, bool named)
836 struct score_arg_info info;
837 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_args);
838 score_classify_arg (cum, mode, type, named, &info);
839 return info.stack_words > 0 ? info.reg_words * UNITS_PER_WORD : 0;
842 /* Implement TARGET_FUNCTION_ARG hook. */
843 static rtx
844 score_function_arg (cumulative_args_t cum_args, enum machine_mode mode,
845 const_tree type, bool named)
847 struct score_arg_info info;
848 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_args);
850 if (mode == VOIDmode || !named)
851 return 0;
853 score_classify_arg (cum, mode, type, named, &info);
855 if (info.reg_offset == ARG_REG_NUM)
856 return 0;
858 if (!info.stack_words)
859 return gen_rtx_REG (mode, ARG_REG_FIRST + info.reg_offset);
860 else
862 rtx ret = gen_rtx_PARALLEL (mode, rtvec_alloc (info.reg_words));
863 unsigned int i, part_offset = 0;
864 for (i = 0; i < info.reg_words; i++)
866 rtx reg;
867 reg = gen_rtx_REG (SImode, ARG_REG_FIRST + info.reg_offset + i);
868 XVECEXP (ret, 0, i) = gen_rtx_EXPR_LIST (SImode, reg,
869 GEN_INT (part_offset));
870 part_offset += UNITS_PER_WORD;
872 return ret;
876 /* Implement FUNCTION_VALUE and LIBCALL_VALUE. For normal calls,
877 VALTYPE is the return type and MODE is VOIDmode. For libcalls,
878 VALTYPE is null and MODE is the mode of the return value. */
880 score_function_value (const_tree valtype, const_tree func, enum machine_mode mode)
882 if (valtype)
884 int unsignedp;
885 mode = TYPE_MODE (valtype);
886 unsignedp = TYPE_UNSIGNED (valtype);
887 mode = promote_function_mode (valtype, mode, &unsignedp, func, 1);
889 return gen_rtx_REG (mode, RT_REGNUM);
892 /* Implement TARGET_ASM_TRAMPOLINE_TEMPLATE. */
894 static void
895 score_asm_trampoline_template (FILE *f)
897 fprintf (f, "\t.set r1\n");
898 fprintf (f, "\tmv r31, r3\n");
899 fprintf (f, "\tbl nextinsn\n");
900 fprintf (f, "nextinsn:\n");
901 fprintf (f, "\tlw r1, [r3, 6*4-8]\n");
902 fprintf (f, "\tlw r23, [r3, 6*4-4]\n");
903 fprintf (f, "\tmv r3, r31\n");
904 fprintf (f, "\tbr! r1\n");
905 fprintf (f, "\tnop!\n");
906 fprintf (f, "\t.set nor1\n");
909 /* Implement TARGET_TRAMPOLINE_INIT. */
910 static void
911 score_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
913 #define CODE_SIZE (TRAMPOLINE_INSNS * UNITS_PER_WORD)
915 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
916 rtx mem;
918 emit_block_move (m_tramp, assemble_trampoline_template (),
919 GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
921 mem = adjust_address (m_tramp, SImode, CODE_SIZE);
922 emit_move_insn (mem, fnaddr);
923 mem = adjust_address (m_tramp, SImode, CODE_SIZE + GET_MODE_SIZE (SImode));
924 emit_move_insn (mem, chain_value);
926 #undef CODE_SIZE
929 /* This function is used to implement REG_MODE_OK_FOR_BASE_P macro. */
931 score_regno_mode_ok_for_base_p (int regno, int strict)
933 if (regno >= FIRST_PSEUDO_REGISTER)
935 if (!strict)
936 return 1;
937 regno = reg_renumber[regno];
939 if (regno == ARG_POINTER_REGNUM
940 || regno == FRAME_POINTER_REGNUM)
941 return 1;
942 return GP_REG_P (regno);
945 /* Implement TARGET_LEGITIMATE_ADDRESS_P macro. */
946 static bool
947 score_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
949 struct score_address_info addr;
951 return score_classify_address (&addr, mode, x, strict);
954 /* Implement TARGET_REGISTER_MOVE_COST.
956 Return a number assessing the cost of moving a register in class
957 FROM to class TO. */
958 static int
959 score_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
960 reg_class_t from, reg_class_t to)
962 if (GR_REG_CLASS_P (from))
964 if (GR_REG_CLASS_P (to))
965 return 2;
966 else if (SP_REG_CLASS_P (to))
967 return 4;
968 else if (CP_REG_CLASS_P (to))
969 return 5;
970 else if (CE_REG_CLASS_P (to))
971 return 6;
973 if (GR_REG_CLASS_P (to))
975 if (GR_REG_CLASS_P (from))
976 return 2;
977 else if (SP_REG_CLASS_P (from))
978 return 4;
979 else if (CP_REG_CLASS_P (from))
980 return 5;
981 else if (CE_REG_CLASS_P (from))
982 return 6;
984 return 12;
987 /* Return the number of instructions needed to load a symbol of the
988 given type into a register. */
989 static int
990 score_symbol_insns (enum score_symbol_type type)
992 switch (type)
994 case SYMBOL_GENERAL:
995 return 2;
997 case SYMBOL_SMALL_DATA:
998 return 1;
1001 gcc_unreachable ();
1004 /* Return the number of instructions needed to load or store a value
1005 of mode MODE at X. Return 0 if X isn't valid for MODE. */
1006 static int
1007 score_address_insns (rtx x, enum machine_mode mode)
1009 struct score_address_info addr;
1010 int factor;
1012 if (mode == BLKmode)
1013 factor = 1;
1014 else
1015 factor = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
1017 if (score_classify_address (&addr, mode, x, false))
1018 switch (addr.type)
1020 case SCORE_ADD_REG:
1021 case SCORE_ADD_CONST_INT:
1022 return factor;
1024 case SCORE_ADD_SYMBOLIC:
1025 return factor * score_symbol_insns (addr.symbol_type);
1027 return 0;
1030 /* Implement TARGET_RTX_COSTS macro. */
1031 bool
1032 score_rtx_costs (rtx x, int code, int outer_code, int opno ATTRIBUTE_UNUSED,
1033 int *total, bool speed ATTRIBUTE_UNUSED)
1035 enum machine_mode mode = GET_MODE (x);
1037 switch (code)
1039 case CONST_INT:
1040 if (outer_code == SET)
1042 if (((INTVAL (x) & 0xffff) == 0)
1043 || (INTVAL (x) >= -32768 && INTVAL (x) <= 32767))
1044 *total = COSTS_N_INSNS (1);
1045 else
1046 *total = COSTS_N_INSNS (2);
1048 else if (outer_code == PLUS || outer_code == MINUS)
1050 if (INTVAL (x) >= -8192 && INTVAL (x) <= 8191)
1051 *total = 0;
1052 else if (((INTVAL (x) & 0xffff) == 0)
1053 || (INTVAL (x) >= -32768 && INTVAL (x) <= 32767))
1054 *total = 1;
1055 else
1056 *total = COSTS_N_INSNS (2);
1058 else if (outer_code == AND || outer_code == IOR)
1060 if (INTVAL (x) >= 0 && INTVAL (x) <= 16383)
1061 *total = 0;
1062 else if (((INTVAL (x) & 0xffff) == 0)
1063 || (INTVAL (x) >= 0 && INTVAL (x) <= 65535))
1064 *total = 1;
1065 else
1066 *total = COSTS_N_INSNS (2);
1068 else
1070 *total = 0;
1072 return true;
1074 case CONST:
1075 case SYMBOL_REF:
1076 case LABEL_REF:
1077 case CONST_DOUBLE:
1078 *total = COSTS_N_INSNS (2);
1079 return true;
1081 case MEM:
1083 /* If the address is legitimate, return the number of
1084 instructions it needs, otherwise use the default handling. */
1085 int n = score_address_insns (XEXP (x, 0), GET_MODE (x));
1086 if (n > 0)
1088 *total = COSTS_N_INSNS (n + 1);
1089 return true;
1091 return false;
1094 case FFS:
1095 *total = COSTS_N_INSNS (6);
1096 return true;
1098 case NOT:
1099 *total = COSTS_N_INSNS (1);
1100 return true;
1102 case AND:
1103 case IOR:
1104 case XOR:
1105 if (mode == DImode)
1107 *total = COSTS_N_INSNS (2);
1108 return true;
1110 return false;
1112 case ASHIFT:
1113 case ASHIFTRT:
1114 case LSHIFTRT:
1115 if (mode == DImode)
1117 *total = COSTS_N_INSNS ((GET_CODE (XEXP (x, 1)) == CONST_INT)
1118 ? 4 : 12);
1119 return true;
1121 return false;
1123 case ABS:
1124 *total = COSTS_N_INSNS (4);
1125 return true;
1127 case PLUS:
1128 case MINUS:
1129 if (mode == DImode)
1131 *total = COSTS_N_INSNS (4);
1132 return true;
1134 *total = COSTS_N_INSNS (1);
1135 return true;
1137 case NEG:
1138 if (mode == DImode)
1140 *total = COSTS_N_INSNS (4);
1141 return true;
1143 return false;
1145 case MULT:
1146 *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (12);
1147 return true;
1149 case DIV:
1150 case MOD:
1151 case UDIV:
1152 case UMOD:
1153 *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (33);
1154 return true;
1156 case SIGN_EXTEND:
1157 case ZERO_EXTEND:
1158 switch (GET_MODE (XEXP (x, 0)))
1160 case QImode:
1161 case HImode:
1162 if (GET_CODE (XEXP (x, 0)) == MEM)
1164 *total = COSTS_N_INSNS (2);
1166 if (!TARGET_LITTLE_ENDIAN &&
1167 side_effects_p (XEXP (XEXP (x, 0), 0)))
1168 *total = 100;
1170 else
1171 *total = COSTS_N_INSNS (1);
1172 break;
1174 default:
1175 *total = COSTS_N_INSNS (1);
1176 break;
1178 return true;
1180 default:
1181 return false;
1185 /* Implement TARGET_ADDRESS_COST macro. */
1187 score_address_cost (rtx addr, enum machine_mode mode ATTRIBUTE_UNUSED,
1188 addr_space_t as ATTRIBUTE_UNUSED,
1189 bool speed ATTRIBUTE_UNUSED)
1191 return score_address_insns (addr, SImode);
1194 /* Implement ASM_OUTPUT_EXTERNAL macro. */
1196 score_output_external (FILE *file ATTRIBUTE_UNUSED,
1197 tree decl, const char *name)
1199 register struct extern_list *p;
1201 if (score_in_small_data_p (decl))
1203 p = ggc_alloc<extern_list> ();
1204 p->next = extern_head;
1205 p->name = name;
1206 p->size = int_size_in_bytes (TREE_TYPE (decl));
1207 extern_head = p;
1209 return 0;
1212 /* Implement RETURN_ADDR_RTX. Note, we do not support moving
1213 back to a previous frame. */
1215 score_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
1217 if (count != 0)
1218 return const0_rtx;
1219 return get_hard_reg_initial_val (Pmode, RA_REGNUM);
1222 /* Implement PRINT_OPERAND macro. */
1223 /* Score-specific operand codes:
1224 '[' print .set nor1 directive
1225 ']' print .set r1 directive
1226 'U' print hi part of a CONST_INT rtx
1227 'E' print log2(v)
1228 'F' print log2(~v)
1229 'D' print SFmode const double
1230 'S' selectively print "!" if operand is 15bit instruction accessible
1231 'V' print "v!" if operand is 15bit instruction accessible, or "lfh!"
1232 'L' low part of DImode reg operand
1233 'H' high part of DImode reg operand
1234 'C' print part of opcode for a branch condition. */
1235 void
1236 score_print_operand (FILE *file, rtx op, int c)
1238 enum rtx_code code = UNKNOWN;
1239 if (!PRINT_OPERAND_PUNCT_VALID_P (c))
1240 code = GET_CODE (op);
1242 if (c == '[')
1244 fprintf (file, ".set r1\n");
1246 else if (c == ']')
1248 fprintf (file, "\n\t.set nor1");
1250 else if (c == 'U')
1252 gcc_assert (code == CONST_INT);
1253 fprintf (file, HOST_WIDE_INT_PRINT_HEX,
1254 (INTVAL (op) >> 16) & 0xffff);
1256 else if (c == 'D')
1258 if (GET_CODE (op) == CONST_DOUBLE)
1260 rtx temp = gen_lowpart (SImode, op);
1261 gcc_assert (GET_MODE (op) == SFmode);
1262 fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (temp) & 0xffffffff);
1264 else
1265 output_addr_const (file, op);
1267 else if (c == 'S')
1269 gcc_assert (code == REG);
1270 if (G16_REG_P (REGNO (op)))
1271 fprintf (file, "!");
1273 else if (c == 'V')
1275 gcc_assert (code == REG);
1276 fprintf (file, G16_REG_P (REGNO (op)) ? "v!" : "lfh!");
1278 else if (c == 'C')
1280 enum machine_mode mode = GET_MODE (XEXP (op, 0));
1282 switch (code)
1284 case EQ: fputs ("eq", file); break;
1285 case NE: fputs ("ne", file); break;
1286 case GT: fputs ("gt", file); break;
1287 case GE: fputs (mode != CCmode ? "pl" : "ge", file); break;
1288 case LT: fputs (mode != CCmode ? "mi" : "lt", file); break;
1289 case LE: fputs ("le", file); break;
1290 case GTU: fputs ("gtu", file); break;
1291 case GEU: fputs ("cs", file); break;
1292 case LTU: fputs ("cc", file); break;
1293 case LEU: fputs ("leu", file); break;
1294 default:
1295 output_operand_lossage ("invalid operand for code: '%c'", code);
1298 else if (c == 'E')
1300 unsigned HOST_WIDE_INT i;
1301 unsigned HOST_WIDE_INT pow2mask = 1;
1302 unsigned HOST_WIDE_INT val;
1304 val = INTVAL (op);
1305 for (i = 0; i < 32; i++)
1307 if (val == pow2mask)
1308 break;
1309 pow2mask <<= 1;
1311 gcc_assert (i < 32);
1312 fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
1314 else if (c == 'F')
1316 unsigned HOST_WIDE_INT i;
1317 unsigned HOST_WIDE_INT pow2mask = 1;
1318 unsigned HOST_WIDE_INT val;
1320 val = ~INTVAL (op);
1321 for (i = 0; i < 32; i++)
1323 if (val == pow2mask)
1324 break;
1325 pow2mask <<= 1;
1327 gcc_assert (i < 32);
1328 fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
1330 else if (code == REG)
1332 int regnum = REGNO (op);
1333 if ((c == 'H' && !WORDS_BIG_ENDIAN)
1334 || (c == 'L' && WORDS_BIG_ENDIAN))
1335 regnum ++;
1336 fprintf (file, "%s", reg_names[regnum]);
1338 else
1340 switch (code)
1342 case MEM:
1343 score_print_operand_address (file, op);
1344 break;
1345 default:
1346 output_addr_const (file, op);
1351 /* Implement PRINT_OPERAND_ADDRESS macro. */
1352 void
1353 score_print_operand_address (FILE *file, rtx x)
1355 struct score_address_info addr;
1356 enum rtx_code code = GET_CODE (x);
1357 enum machine_mode mode = GET_MODE (x);
1359 if (code == MEM)
1360 x = XEXP (x, 0);
1362 if (score_classify_address (&addr, mode, x, true))
1364 switch (addr.type)
1366 case SCORE_ADD_REG:
1368 switch (addr.code)
1370 case PRE_DEC:
1371 fprintf (file, "[%s,-%ld]+", reg_names[REGNO (addr.reg)],
1372 INTVAL (addr.offset));
1373 break;
1374 case POST_DEC:
1375 fprintf (file, "[%s]+,-%ld", reg_names[REGNO (addr.reg)],
1376 INTVAL (addr.offset));
1377 break;
1378 case PRE_INC:
1379 fprintf (file, "[%s, %ld]+", reg_names[REGNO (addr.reg)],
1380 INTVAL (addr.offset));
1381 break;
1382 case POST_INC:
1383 fprintf (file, "[%s]+, %ld", reg_names[REGNO (addr.reg)],
1384 INTVAL (addr.offset));
1385 break;
1386 default:
1387 if (INTVAL(addr.offset) == 0)
1388 fprintf(file, "[%s]", reg_names[REGNO (addr.reg)]);
1389 else
1390 fprintf(file, "[%s, %ld]", reg_names[REGNO (addr.reg)],
1391 INTVAL(addr.offset));
1392 break;
1395 return;
1396 case SCORE_ADD_CONST_INT:
1397 case SCORE_ADD_SYMBOLIC:
1398 output_addr_const (file, x);
1399 return;
1402 print_rtl (stderr, x);
1403 gcc_unreachable ();
1406 /* Implement SELECT_CC_MODE macro. */
1407 enum machine_mode
1408 score_select_cc_mode (enum rtx_code op, rtx x, rtx y)
1410 if ((op == EQ || op == NE || op == LT || op == GE)
1411 && y == const0_rtx
1412 && GET_MODE (x) == SImode)
1414 switch (GET_CODE (x))
1416 case PLUS:
1417 case MINUS:
1418 case NEG:
1419 case AND:
1420 case IOR:
1421 case XOR:
1422 case NOT:
1423 case ASHIFT:
1424 case LSHIFTRT:
1425 case ASHIFTRT:
1426 return CC_NZmode;
1428 case SIGN_EXTEND:
1429 case ZERO_EXTEND:
1430 case ROTATE:
1431 case ROTATERT:
1432 return (op == LT || op == GE) ? CC_Nmode : CCmode;
1434 default:
1435 return CCmode;
1439 if ((op == EQ || op == NE)
1440 && (GET_CODE (y) == NEG)
1441 && register_operand (XEXP (y, 0), SImode)
1442 && register_operand (x, SImode))
1444 return CC_NZmode;
1447 return CCmode;
1450 /* Generate the prologue instructions for entry into a S+core function. */
1451 void
1452 score_prologue (void)
1454 #define EMIT_PL(_rtx) RTX_FRAME_RELATED_P (_rtx) = 1
1456 struct score_frame_info *f = score_compute_frame_size (get_frame_size ());
1457 HOST_WIDE_INT size;
1458 int regno;
1460 size = f->total_size - f->gp_reg_size;
1462 if (flag_pic)
1463 emit_insn (gen_cpload_score7 ());
1465 for (regno = (int) GP_REG_LAST; regno >= (int) GP_REG_FIRST; regno--)
1467 if (BITSET_P (f->mask, regno - GP_REG_FIRST))
1469 rtx mem = gen_rtx_MEM (SImode,
1470 gen_rtx_PRE_DEC (SImode, stack_pointer_rtx));
1471 rtx reg = gen_rtx_REG (SImode, regno);
1472 if (!crtl->calls_eh_return)
1473 MEM_READONLY_P (mem) = 1;
1474 EMIT_PL (emit_insn (gen_pushsi_score7 (mem, reg)));
1478 if (size > 0)
1480 rtx insn;
1482 if (size >= -32768 && size <= 32767)
1483 EMIT_PL (emit_insn (gen_add3_insn (stack_pointer_rtx,
1484 stack_pointer_rtx,
1485 GEN_INT (-size))));
1486 else
1488 EMIT_PL (emit_move_insn (gen_rtx_REG (Pmode, SCORE_PROLOGUE_TEMP_REGNUM),
1489 GEN_INT (size)));
1490 EMIT_PL (emit_insn
1491 (gen_sub3_insn (stack_pointer_rtx,
1492 stack_pointer_rtx,
1493 gen_rtx_REG (Pmode,
1494 SCORE_PROLOGUE_TEMP_REGNUM))));
1496 insn = get_last_insn ();
1497 REG_NOTES (insn) =
1498 alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR,
1499 gen_rtx_SET (VOIDmode, stack_pointer_rtx,
1500 plus_constant (Pmode, stack_pointer_rtx,
1501 -size)),
1502 REG_NOTES (insn));
1505 if (frame_pointer_needed)
1506 EMIT_PL (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx));
1508 if (flag_pic && f->cprestore_size)
1510 if (frame_pointer_needed)
1511 emit_insn (gen_cprestore_use_fp_score7 (GEN_INT (size - f->cprestore_size)));
1512 else
1513 emit_insn (gen_cprestore_use_sp_score7 (GEN_INT (size - f->cprestore_size)));
1516 #undef EMIT_PL
1519 /* Generate the epilogue instructions in a S+core function. */
1520 void
1521 score_epilogue (int sibcall_p)
1523 struct score_frame_info *f = score_compute_frame_size (get_frame_size ());
1524 HOST_WIDE_INT size;
1525 int regno;
1526 rtx base;
1528 size = f->total_size - f->gp_reg_size;
1530 if (!frame_pointer_needed)
1531 base = stack_pointer_rtx;
1532 else
1533 base = hard_frame_pointer_rtx;
1535 if (size)
1537 if (size >= -32768 && size <= 32767)
1538 emit_insn (gen_add3_insn (base, base, GEN_INT (size)));
1539 else
1541 emit_move_insn (gen_rtx_REG (Pmode, SCORE_EPILOGUE_TEMP_REGNUM),
1542 GEN_INT (size));
1543 emit_insn (gen_add3_insn (base, base,
1544 gen_rtx_REG (Pmode,
1545 SCORE_EPILOGUE_TEMP_REGNUM)));
1549 if (base != stack_pointer_rtx)
1550 emit_move_insn (stack_pointer_rtx, base);
1552 if (crtl->calls_eh_return)
1553 emit_insn (gen_add3_insn (stack_pointer_rtx,
1554 stack_pointer_rtx,
1555 EH_RETURN_STACKADJ_RTX));
1557 for (regno = (int) GP_REG_FIRST; regno <= (int) GP_REG_LAST; regno++)
1559 if (BITSET_P (f->mask, regno - GP_REG_FIRST))
1561 rtx mem = gen_rtx_MEM (SImode,
1562 gen_rtx_POST_INC (SImode, stack_pointer_rtx));
1563 rtx reg = gen_rtx_REG (SImode, regno);
1565 if (!crtl->calls_eh_return)
1566 MEM_READONLY_P (mem) = 1;
1568 emit_insn (gen_popsi_score7 (reg, mem));
1572 if (!sibcall_p)
1573 emit_jump_insn (gen_return_internal_score7 (gen_rtx_REG (Pmode, RA_REGNUM)));
1576 /* Return true if X is a symbolic constant that can be calculated in
1577 the same way as a bare symbol. If it is, store the type of the
1578 symbol in *SYMBOL_TYPE. */
1580 score_symbolic_constant_p (rtx x, enum score_symbol_type *symbol_type)
1582 HOST_WIDE_INT offset;
1584 score_split_const (x, &x, &offset);
1585 if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF)
1586 *symbol_type = score_classify_symbol (x);
1587 else
1588 return 0;
1590 if (offset == 0)
1591 return 1;
1593 /* if offset > 15bit, must reload */
1594 if (!IMM_IN_RANGE (offset, 15, 1))
1595 return 0;
1597 switch (*symbol_type)
1599 case SYMBOL_GENERAL:
1600 return 1;
1601 case SYMBOL_SMALL_DATA:
1602 return score_offset_within_object_p (x, offset);
1604 gcc_unreachable ();
1607 void
1608 score_movsicc (rtx *ops)
1610 enum machine_mode mode;
1612 mode = score_select_cc_mode (GET_CODE (ops[1]), ops[2], ops[3]);
1613 emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (mode, CC_REGNUM),
1614 gen_rtx_COMPARE (mode, XEXP (ops[1], 0),
1615 XEXP (ops[1], 1))));
1618 /* Call and sibcall pattern all need call this function. */
1619 void
1620 score_call (rtx *ops, bool sib)
1622 rtx addr = XEXP (ops[0], 0);
1623 if (!call_insn_operand (addr, VOIDmode))
1625 rtx oaddr = addr;
1626 addr = gen_reg_rtx (Pmode);
1627 gen_move_insn (addr, oaddr);
1630 if (sib)
1631 emit_call_insn (gen_sibcall_internal_score7 (addr, ops[1]));
1632 else
1633 emit_call_insn (gen_call_internal_score7 (addr, ops[1]));
1636 /* Call value and sibcall value pattern all need call this function. */
1637 void
1638 score_call_value (rtx *ops, bool sib)
1640 rtx result = ops[0];
1641 rtx addr = XEXP (ops[1], 0);
1642 rtx arg = ops[2];
1644 if (!call_insn_operand (addr, VOIDmode))
1646 rtx oaddr = addr;
1647 addr = gen_reg_rtx (Pmode);
1648 gen_move_insn (addr, oaddr);
1651 if (sib)
1652 emit_call_insn (gen_sibcall_value_internal_score7 (result, addr, arg));
1653 else
1654 emit_call_insn (gen_call_value_internal_score7 (result, addr, arg));
1657 /* Machine Split */
1658 void
1659 score_movdi (rtx *ops)
1661 rtx dst = ops[0];
1662 rtx src = ops[1];
1663 rtx dst0 = score_subw (dst, 0);
1664 rtx dst1 = score_subw (dst, 1);
1665 rtx src0 = score_subw (src, 0);
1666 rtx src1 = score_subw (src, 1);
1668 if (GET_CODE (dst0) == REG && reg_overlap_mentioned_p (dst0, src))
1670 emit_move_insn (dst1, src1);
1671 emit_move_insn (dst0, src0);
1673 else
1675 emit_move_insn (dst0, src0);
1676 emit_move_insn (dst1, src1);
1680 void
1681 score_zero_extract_andi (rtx *ops)
1683 if (INTVAL (ops[1]) == 1 && const_uimm5 (ops[2], SImode))
1684 emit_insn (gen_zero_extract_bittst_score7 (ops[0], ops[2]));
1685 else
1687 unsigned HOST_WIDE_INT mask;
1688 mask = (0xffffffffU & ((1U << INTVAL (ops[1])) - 1U));
1689 mask = mask << INTVAL (ops[2]);
1690 emit_insn (gen_andsi3_cmp_score7 (ops[3], ops[0],
1691 gen_int_mode (mask, SImode)));
1695 /* Check addr could be present as PRE/POST mode. */
1696 static bool
1697 score_pindex_mem (rtx addr)
1699 if (GET_CODE (addr) == MEM)
1701 switch (GET_CODE (XEXP (addr, 0)))
1703 case PRE_DEC:
1704 case POST_DEC:
1705 case PRE_INC:
1706 case POST_INC:
1707 return true;
1708 default:
1709 break;
1712 return false;
1715 /* Output asm code for ld/sw insn. */
1716 static int
1717 score_pr_addr_post (rtx *ops, int idata, int iaddr, char *ip, enum score_mem_unit unit)
1719 struct score_address_info ai;
1721 gcc_assert (GET_CODE (ops[idata]) == REG);
1722 gcc_assert (score_classify_address (&ai, SImode, XEXP (ops[iaddr], 0), true));
1724 if (!score_pindex_mem (ops[iaddr])
1725 && ai.type == SCORE_ADD_REG
1726 && GET_CODE (ai.offset) == CONST_INT
1727 && G16_REG_P (REGNO (ops[idata]))
1728 && G16_REG_P (REGNO (ai.reg)))
1730 if (INTVAL (ai.offset) == 0)
1732 ops[iaddr] = ai.reg;
1733 return snprintf (ip, INS_BUF_SZ,
1734 "!\t%%%d, [%%%d]", idata, iaddr);
1736 if (REGNO (ai.reg) == HARD_FRAME_POINTER_REGNUM)
1738 HOST_WIDE_INT offset = INTVAL (ai.offset);
1739 if (SCORE_ALIGN_UNIT (offset, unit)
1740 && (((offset >> unit) >= 0) && ((offset >> unit) <= 31)))
1742 ops[iaddr] = ai.offset;
1743 return snprintf (ip, INS_BUF_SZ,
1744 "p!\t%%%d, %%c%d", idata, iaddr);
1748 return snprintf (ip, INS_BUF_SZ, "\t%%%d, %%a%d", idata, iaddr);
1751 /* Output asm insn for load. */
1752 const char *
1753 score_linsn (rtx *ops, enum score_mem_unit unit, bool sign)
1755 const char *pre_ins[] =
1756 {"lbu", "lhu", "lw", "??", "lb", "lh", "lw", "??"};
1757 char *ip;
1759 strcpy (score_ins, pre_ins[(sign ? 4 : 0) + unit]);
1760 ip = score_ins + strlen (score_ins);
1762 if ((!sign && unit != SCORE_HWORD)
1763 || (sign && unit != SCORE_BYTE))
1764 score_pr_addr_post (ops, 0, 1, ip, unit);
1765 else
1766 snprintf (ip, INS_BUF_SZ, "\t%%0, %%a1");
1768 return score_ins;
1771 /* Output asm insn for store. */
1772 const char *
1773 score_sinsn (rtx *ops, enum score_mem_unit unit)
1775 const char *pre_ins[] = {"sb", "sh", "sw"};
1776 char *ip;
1778 strcpy (score_ins, pre_ins[unit]);
1779 ip = score_ins + strlen (score_ins);
1780 score_pr_addr_post (ops, 1, 0, ip, unit);
1781 return score_ins;
1784 /* Output asm insn for load immediate. */
1785 const char *
1786 score_limm (rtx *ops)
1788 HOST_WIDE_INT v;
1790 gcc_assert (GET_CODE (ops[0]) == REG);
1791 gcc_assert (GET_CODE (ops[1]) == CONST_INT);
1793 v = INTVAL (ops[1]);
1794 if (G16_REG_P (REGNO (ops[0])) && IMM_IN_RANGE (v, 8, 0))
1795 return "ldiu!\t%0, %c1";
1796 else if (IMM_IN_RANGE (v, 16, 1))
1797 return "ldi\t%0, %c1";
1798 else if ((v & 0xffff) == 0)
1799 return "ldis\t%0, %U1";
1800 else
1801 return "li\t%0, %c1";
1804 /* Output asm insn for move. */
1805 const char *
1806 score_move (rtx *ops)
1808 gcc_assert (GET_CODE (ops[0]) == REG);
1809 gcc_assert (GET_CODE (ops[1]) == REG);
1811 if (G16_REG_P (REGNO (ops[0])))
1813 if (G16_REG_P (REGNO (ops[1])))
1814 return "mv!\t%0, %1";
1815 else
1816 return "mlfh!\t%0, %1";
1818 else if (G16_REG_P (REGNO (ops[1])))
1819 return "mhfl!\t%0, %1";
1820 else
1821 return "mv\t%0, %1";
1824 /* Generate add insn. */
1825 const char *
1826 score_select_add_imm (rtx *ops, bool set_cc)
1828 HOST_WIDE_INT v = INTVAL (ops[2]);
1830 gcc_assert (GET_CODE (ops[2]) == CONST_INT);
1831 gcc_assert (REGNO (ops[0]) == REGNO (ops[1]));
1833 if (set_cc && G16_REG_P (REGNO (ops[0])))
1835 if (v > 0 && IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT) v, 0, 15))
1837 ops[2] = GEN_INT (ffs (v) - 1);
1838 return "addei!\t%0, %c2";
1841 if (v < 0 && IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT) (-v), 0, 15))
1843 ops[2] = GEN_INT (ffs (-v) - 1);
1844 return "subei!\t%0, %c2";
1848 if (set_cc)
1849 return "addi.c\t%0, %c2";
1850 else
1851 return "addi\t%0, %c2";
1854 /* Output arith insn. */
1855 const char *
1856 score_select (rtx *ops, const char *inst_pre,
1857 bool commu, const char *letter, bool set_cc)
1859 gcc_assert (GET_CODE (ops[0]) == REG);
1860 gcc_assert (GET_CODE (ops[1]) == REG);
1862 if (set_cc && G16_REG_P (REGNO (ops[0]))
1863 && (GET_CODE (ops[2]) == REG ? G16_REG_P (REGNO (ops[2])) : 1)
1864 && REGNO (ops[0]) == REGNO (ops[1]))
1866 snprintf (score_ins, INS_BUF_SZ, "%s!\t%%0, %%%s2", inst_pre, letter);
1867 return score_ins;
1870 if (commu && set_cc && G16_REG_P (REGNO (ops[0]))
1871 && G16_REG_P (REGNO (ops[1]))
1872 && REGNO (ops[0]) == REGNO (ops[2]))
1874 gcc_assert (GET_CODE (ops[2]) == REG);
1875 snprintf (score_ins, INS_BUF_SZ, "%s!\t%%0, %%%s1", inst_pre, letter);
1876 return score_ins;
1879 if (set_cc)
1880 snprintf (score_ins, INS_BUF_SZ, "%s.c\t%%0, %%1, %%%s2", inst_pre, letter);
1881 else
1882 snprintf (score_ins, INS_BUF_SZ, "%s\t%%0, %%1, %%%s2", inst_pre, letter);
1883 return score_ins;
1886 /* Return nonzero when an argument must be passed by reference. */
1887 static bool
1888 score_pass_by_reference (cumulative_args_t cum ATTRIBUTE_UNUSED,
1889 enum machine_mode mode, const_tree type,
1890 bool named ATTRIBUTE_UNUSED)
1892 /* If we have a variable-sized parameter, we have no choice. */
1893 return targetm.calls.must_pass_in_stack (mode, type);
1896 /* Implement TARGET_FUNCTION_OK_FOR_SIBCALL. */
1897 static bool
1898 score_function_ok_for_sibcall (ATTRIBUTE_UNUSED tree decl,
1899 ATTRIBUTE_UNUSED tree exp)
1901 return true;
1904 /* Implement TARGET_SCHED_ISSUE_RATE. */
1905 static int
1906 score_issue_rate (void)
1908 return 1;
1911 /* We can always eliminate to the hard frame pointer. We can eliminate
1912 to the stack pointer unless a frame pointer is needed. */
1914 static bool
1915 score_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to)
1917 return (to == HARD_FRAME_POINTER_REGNUM
1918 || (to == STACK_POINTER_REGNUM && !frame_pointer_needed));
1921 /* Argument support functions. */
1923 /* Initialize CUMULATIVE_ARGS for a function. */
1924 void
1925 score_init_cumulative_args (CUMULATIVE_ARGS *cum,
1926 tree fntype ATTRIBUTE_UNUSED,
1927 rtx libname ATTRIBUTE_UNUSED)
1929 memset (cum, 0, sizeof (CUMULATIVE_ARGS));
1932 static void
1933 score_conditional_register_usage (void)
1935 if (!flag_pic)
1936 fixed_regs[PIC_OFFSET_TABLE_REGNUM] =
1937 call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 0;
1940 struct gcc_target targetm = TARGET_INITIALIZER;