Merge from mainline (165734:167278).
[official-gcc/graphite-test-results.git] / gcc / config / score / score7.c
blob90e8446838b0c93146227c24dfa7113093234b9d
1 /* score7.c for Sunplus S+CORE processor
2 Copyright (C) 2005, 2007, 2008, 2009, 2010 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 "toplev.h"
34 #include "output.h"
35 #include "tree.h"
36 #include "function.h"
37 #include "expr.h"
38 #include "optabs.h"
39 #include "flags.h"
40 #include "reload.h"
41 #include "tm_p.h"
42 #include "ggc.h"
43 #include "gstab.h"
44 #include "hashtab.h"
45 #include "debug.h"
46 #include "target.h"
47 #include "target-def.h"
48 #include "integrate.h"
49 #include "langhooks.h"
50 #include "cfglayout.h"
51 #include "score7.h"
52 #include "df.h"
54 #define BITSET_P(VALUE, BIT) (((VALUE) & (1L << (BIT))) != 0)
55 #define INS_BUF_SZ 128
57 extern enum reg_class score_char_to_class[256];
59 static int score7_sdata_max;
60 static char score7_ins[INS_BUF_SZ + 8];
62 /* Return true if SYMBOL is a SYMBOL_REF and OFFSET + SYMBOL points
63 to the same object as SYMBOL. */
64 static int
65 score7_offset_within_object_p (rtx symbol, HOST_WIDE_INT offset)
67 if (GET_CODE (symbol) != SYMBOL_REF)
68 return 0;
70 if (CONSTANT_POOL_ADDRESS_P (symbol)
71 && offset >= 0
72 && offset < (int)GET_MODE_SIZE (get_pool_mode (symbol)))
73 return 1;
75 if (SYMBOL_REF_DECL (symbol) != 0
76 && offset >= 0
77 && offset < int_size_in_bytes (TREE_TYPE (SYMBOL_REF_DECL (symbol))))
78 return 1;
80 return 0;
83 /* Split X into a base and a constant offset, storing them in *BASE
84 and *OFFSET respectively. */
85 static void
86 score7_split_const (rtx x, rtx *base, HOST_WIDE_INT *offset)
88 *offset = 0;
90 if (GET_CODE (x) == CONST)
91 x = XEXP (x, 0);
93 if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
95 *offset += INTVAL (XEXP (x, 1));
96 x = XEXP (x, 0);
99 *base = x;
102 /* Classify symbol X, which must be a SYMBOL_REF or a LABEL_REF. */
103 static enum score_symbol_type
104 score7_classify_symbol (rtx x)
106 if (GET_CODE (x) == LABEL_REF)
107 return SYMBOL_GENERAL;
109 gcc_assert (GET_CODE (x) == SYMBOL_REF);
111 if (CONSTANT_POOL_ADDRESS_P (x))
113 if (GET_MODE_SIZE (get_pool_mode (x)) <= SCORE7_SDATA_MAX)
114 return SYMBOL_SMALL_DATA;
115 return SYMBOL_GENERAL;
117 if (SYMBOL_REF_SMALL_P (x))
118 return SYMBOL_SMALL_DATA;
119 return SYMBOL_GENERAL;
122 /* Return true if the current function must save REGNO. */
123 static int
124 score7_save_reg_p (unsigned int regno)
126 /* Check call-saved registers. */
127 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
128 return 1;
130 /* We need to save the old frame pointer before setting up a new one. */
131 if (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed)
132 return 1;
134 /* We need to save the incoming return address if it is ever clobbered
135 within the function. */
136 if (regno == RA_REGNUM && df_regs_ever_live_p (regno))
137 return 1;
139 return 0;
142 /* Return one word of double-word value OP, taking into account the fixed
143 endianness of certain registers. HIGH_P is true to select the high part,
144 false to select the low part. */
145 static rtx
146 score7_subw (rtx op, int high_p)
148 unsigned int byte;
149 enum machine_mode mode = GET_MODE (op);
151 if (mode == VOIDmode)
152 mode = DImode;
154 byte = (TARGET_LITTLE_ENDIAN ? high_p : !high_p) ? UNITS_PER_WORD : 0;
156 if (GET_CODE (op) == REG && REGNO (op) == HI_REGNUM)
157 return gen_rtx_REG (SImode, high_p ? HI_REGNUM : LO_REGNUM);
159 if (GET_CODE (op) == MEM)
160 return adjust_address (op, SImode, byte);
162 return simplify_gen_subreg (SImode, op, mode, byte);
165 static struct score7_frame_info *
166 score7_cached_frame (void)
168 static struct score7_frame_info _frame_info;
169 return &_frame_info;
172 /* Return the bytes needed to compute the frame pointer from the current
173 stack pointer. SIZE is the size (in bytes) of the local variables. */
174 static struct score7_frame_info *
175 score7_compute_frame_size (HOST_WIDE_INT size)
177 unsigned int regno;
178 struct score7_frame_info *f = score7_cached_frame ();
180 memset (f, 0, sizeof (struct score7_frame_info));
181 f->gp_reg_size = 0;
182 f->mask = 0;
183 f->var_size = SCORE7_STACK_ALIGN (size);
184 f->args_size = crtl->outgoing_args_size;
185 f->cprestore_size = flag_pic ? UNITS_PER_WORD : 0;
186 if (f->var_size == 0 && current_function_is_leaf)
187 f->args_size = f->cprestore_size = 0;
189 if (f->args_size == 0 && cfun->calls_alloca)
190 f->args_size = UNITS_PER_WORD;
192 f->total_size = f->var_size + f->args_size + f->cprestore_size;
193 for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
195 if (score7_save_reg_p (regno))
197 f->gp_reg_size += GET_MODE_SIZE (SImode);
198 f->mask |= 1 << (regno - GP_REG_FIRST);
202 if (crtl->calls_eh_return)
204 unsigned int i;
205 for (i = 0;; ++i)
207 regno = EH_RETURN_DATA_REGNO (i);
208 if (regno == INVALID_REGNUM)
209 break;
210 f->gp_reg_size += GET_MODE_SIZE (SImode);
211 f->mask |= 1 << (regno - GP_REG_FIRST);
215 f->total_size += f->gp_reg_size;
216 f->num_gp = f->gp_reg_size / UNITS_PER_WORD;
218 if (f->mask)
220 HOST_WIDE_INT offset;
221 offset = (f->args_size + f->cprestore_size + f->var_size
222 + f->gp_reg_size - GET_MODE_SIZE (SImode));
223 f->gp_sp_offset = offset;
225 else
226 f->gp_sp_offset = 0;
228 return f;
231 /* Return true if X is a valid base register for the given mode.
232 Allow only hard registers if STRICT. */
233 static int
234 score7_valid_base_register_p (rtx x, int strict)
236 if (!strict && GET_CODE (x) == SUBREG)
237 x = SUBREG_REG (x);
239 return (GET_CODE (x) == REG
240 && score7_regno_mode_ok_for_base_p (REGNO (x), strict));
243 /* Return true if X is a valid address for machine mode MODE. If it is,
244 fill in INFO appropriately. STRICT is true if we should only accept
245 hard base registers. */
246 static int
247 score7_classify_address (struct score7_address_info *info,
248 enum machine_mode mode, rtx x, int strict)
250 info->code = GET_CODE (x);
252 switch (info->code)
254 case REG:
255 case SUBREG:
256 info->type = SCORE7_ADD_REG;
257 info->reg = x;
258 info->offset = const0_rtx;
259 return score7_valid_base_register_p (info->reg, strict);
260 case PLUS:
261 info->type = SCORE7_ADD_REG;
262 info->reg = XEXP (x, 0);
263 info->offset = XEXP (x, 1);
264 return (score7_valid_base_register_p (info->reg, strict)
265 && GET_CODE (info->offset) == CONST_INT
266 && IMM_IN_RANGE (INTVAL (info->offset), 15, 1));
267 case PRE_DEC:
268 case POST_DEC:
269 case PRE_INC:
270 case POST_INC:
271 if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (SImode))
272 return false;
273 info->type = SCORE7_ADD_REG;
274 info->reg = XEXP (x, 0);
275 info->offset = GEN_INT (GET_MODE_SIZE (mode));
276 return score7_valid_base_register_p (info->reg, strict);
277 case CONST_INT:
278 info->type = SCORE7_ADD_CONST_INT;
279 return IMM_IN_RANGE (INTVAL (x), 15, 1);
280 case CONST:
281 case LABEL_REF:
282 case SYMBOL_REF:
283 info->type = SCORE7_ADD_SYMBOLIC;
284 return (score7_symbolic_constant_p (x, &info->symbol_type)
285 && (info->symbol_type == SYMBOL_GENERAL
286 || info->symbol_type == SYMBOL_SMALL_DATA));
287 default:
288 return 0;
292 bool
293 score7_return_in_memory (const_tree type, const_tree fndecl ATTRIBUTE_UNUSED)
295 return ((TYPE_MODE (type) == BLKmode)
296 || (int_size_in_bytes (type) > 2 * UNITS_PER_WORD)
297 || (int_size_in_bytes (type) == -1));
300 /* Return a legitimate address for REG + OFFSET. */
301 static rtx
302 score7_add_offset (rtx reg, HOST_WIDE_INT offset)
304 if (!IMM_IN_RANGE (offset, 15, 1))
306 reg = expand_simple_binop (GET_MODE (reg), PLUS,
307 gen_int_mode (offset & 0xffffc000,
308 GET_MODE (reg)),
309 reg, NULL, 0, OPTAB_WIDEN);
310 offset &= 0x3fff;
313 return plus_constant (reg, offset);
316 /* Implement TARGET_ASM_OUTPUT_MI_THUNK. Generate rtl rather than asm text
317 in order to avoid duplicating too much logic from elsewhere. */
318 void
319 score7_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
320 HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
321 tree function)
323 rtx this_rtx, temp1, insn, fnaddr;
325 /* Pretend to be a post-reload pass while generating rtl. */
326 reload_completed = 1;
328 /* Mark the end of the (empty) prologue. */
329 emit_note (NOTE_INSN_PROLOGUE_END);
331 /* We need two temporary registers in some cases. */
332 temp1 = gen_rtx_REG (Pmode, 8);
334 /* Find out which register contains the "this" pointer. */
335 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
336 this_rtx = gen_rtx_REG (Pmode, ARG_REG_FIRST + 1);
337 else
338 this_rtx = gen_rtx_REG (Pmode, ARG_REG_FIRST);
340 /* Add DELTA to THIS_RTX. */
341 if (delta != 0)
343 rtx offset = GEN_INT (delta);
344 if (!CONST_OK_FOR_LETTER_P (delta, 'L'))
346 emit_move_insn (temp1, offset);
347 offset = temp1;
349 emit_insn (gen_add3_insn (this_rtx, this_rtx, offset));
352 /* If needed, add *(*THIS_RTX + VCALL_OFFSET) to THIS_RTX. */
353 if (vcall_offset != 0)
355 rtx addr;
357 /* Set TEMP1 to *THIS_RTX. */
358 emit_move_insn (temp1, gen_rtx_MEM (Pmode, this_rtx));
360 /* Set ADDR to a legitimate address for *THIS_RTX + VCALL_OFFSET. */
361 addr = score7_add_offset (temp1, vcall_offset);
363 /* Load the offset and add it to THIS_RTX. */
364 emit_move_insn (temp1, gen_rtx_MEM (Pmode, addr));
365 emit_insn (gen_add3_insn (this_rtx, this_rtx, temp1));
368 /* Jump to the target function. */
369 fnaddr = XEXP (DECL_RTL (function), 0);
370 insn = emit_call_insn (gen_sibcall_internal_score7 (fnaddr, const0_rtx));
371 SIBLING_CALL_P (insn) = 1;
373 /* Run just enough of rest_of_compilation. This sequence was
374 "borrowed" from alpha.c. */
375 insn = get_insns ();
376 insn_locators_alloc ();
377 split_all_insns_noflow ();
378 shorten_branches (insn);
379 final_start_function (insn, file, 1);
380 final (insn, file, 1);
381 final_end_function ();
383 /* Clean up the vars set above. Note that final_end_function resets
384 the global pointer for us. */
385 reload_completed = 0;
388 /* Copy VALUE to a register and return that register. If new psuedos
389 are allowed, copy it into a new register, otherwise use DEST. */
390 static rtx
391 score7_force_temporary (rtx dest, rtx value)
393 if (can_create_pseudo_p ())
394 return force_reg (Pmode, value);
395 else
397 emit_move_insn (copy_rtx (dest), value);
398 return dest;
402 /* Return a LO_SUM expression for ADDR. TEMP is as for score_force_temporary
403 and is used to load the high part into a register. */
404 static rtx
405 score7_split_symbol (rtx temp, rtx addr)
407 rtx high = score7_force_temporary (temp,
408 gen_rtx_HIGH (Pmode, copy_rtx (addr)));
409 return gen_rtx_LO_SUM (Pmode, high, addr);
412 /* This function is used to implement LEGITIMIZE_ADDRESS. If X can
413 be legitimized in a way that the generic machinery might not expect,
414 return the new address. */
416 score7_legitimize_address (rtx x)
418 enum score_symbol_type symbol_type;
420 if (score7_symbolic_constant_p (x, &symbol_type)
421 && symbol_type == SYMBOL_GENERAL)
422 return score7_split_symbol (0, x);
424 if (GET_CODE (x) == PLUS
425 && GET_CODE (XEXP (x, 1)) == CONST_INT)
427 rtx reg = XEXP (x, 0);
428 if (!score7_valid_base_register_p (reg, 0))
429 reg = copy_to_mode_reg (Pmode, reg);
430 return score7_add_offset (reg, INTVAL (XEXP (x, 1)));
433 return x;
436 /* Fill INFO with information about a single argument. CUM is the
437 cumulative state for earlier arguments. MODE is the mode of this
438 argument and TYPE is its type (if known). NAMED is true if this
439 is a named (fixed) argument rather than a variable one. */
440 static void
441 score7_classify_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
442 const_tree type, bool named, struct score7_arg_info *info)
444 int even_reg_p;
445 unsigned int num_words, max_regs;
447 even_reg_p = 0;
448 if (GET_MODE_CLASS (mode) == MODE_INT
449 || GET_MODE_CLASS (mode) == MODE_FLOAT)
450 even_reg_p = (GET_MODE_SIZE (mode) > UNITS_PER_WORD);
451 else
452 if (type != NULL_TREE && TYPE_ALIGN (type) > BITS_PER_WORD && named)
453 even_reg_p = 1;
455 if (TARGET_MUST_PASS_IN_STACK (mode, type))
456 info->reg_offset = ARG_REG_NUM;
457 else
459 info->reg_offset = cum->num_gprs;
460 if (even_reg_p)
461 info->reg_offset += info->reg_offset & 1;
464 if (mode == BLKmode)
465 info->num_bytes = int_size_in_bytes (type);
466 else
467 info->num_bytes = GET_MODE_SIZE (mode);
469 num_words = (info->num_bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
470 max_regs = ARG_REG_NUM - info->reg_offset;
472 /* Partition the argument between registers and stack. */
473 info->reg_words = MIN (num_words, max_regs);
474 info->stack_words = num_words - info->reg_words;
476 /* The alignment applied to registers is also applied to stack arguments. */
477 if (info->stack_words)
479 info->stack_offset = cum->stack_words;
480 if (even_reg_p)
481 info->stack_offset += info->stack_offset & 1;
485 /* Set up the stack and frame (if desired) for the function. */
486 void
487 score7_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
489 const char *fnname;
490 struct score7_frame_info *f = score7_cached_frame ();
491 HOST_WIDE_INT tsize = f->total_size;
493 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
494 if (!flag_inhibit_size_directive)
496 fputs ("\t.ent\t", file);
497 assemble_name (file, fnname);
498 fputs ("\n", file);
500 assemble_name (file, fnname);
501 fputs (":\n", file);
503 if (!flag_inhibit_size_directive)
505 fprintf (file,
506 "\t.frame\t%s," HOST_WIDE_INT_PRINT_DEC ",%s, %d\t\t"
507 "# vars= " HOST_WIDE_INT_PRINT_DEC ", regs= %d"
508 ", args= " HOST_WIDE_INT_PRINT_DEC
509 ", gp= " HOST_WIDE_INT_PRINT_DEC "\n",
510 (reg_names[(frame_pointer_needed)
511 ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM]),
512 tsize,
513 reg_names[RA_REGNUM],
514 current_function_is_leaf ? 1 : 0,
515 f->var_size,
516 f->num_gp,
517 f->args_size,
518 f->cprestore_size);
520 fprintf(file, "\t.mask\t0x%08x," HOST_WIDE_INT_PRINT_DEC "\n",
521 f->mask,
522 (f->gp_sp_offset - f->total_size));
526 /* Do any necessary cleanup after a function to restore stack, frame,
527 and regs. */
528 void
529 score7_function_epilogue (FILE *file,
530 HOST_WIDE_INT size ATTRIBUTE_UNUSED)
532 if (!flag_inhibit_size_directive)
534 const char *fnname;
535 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
536 fputs ("\t.end\t", file);
537 assemble_name (file, fnname);
538 fputs ("\n", file);
542 /* Returns true if X contains a SYMBOL_REF. */
543 static bool
544 score7_symbolic_expression_p (rtx x)
546 if (GET_CODE (x) == SYMBOL_REF)
547 return true;
549 if (GET_CODE (x) == CONST)
550 return score7_symbolic_expression_p (XEXP (x, 0));
552 if (UNARY_P (x))
553 return score7_symbolic_expression_p (XEXP (x, 0));
555 if (ARITHMETIC_P (x))
556 return (score7_symbolic_expression_p (XEXP (x, 0))
557 || score7_symbolic_expression_p (XEXP (x, 1)));
559 return false;
562 /* Choose the section to use for the constant rtx expression X that has
563 mode MODE. */
564 section *
565 score7_select_rtx_section (enum machine_mode mode, rtx x,
566 unsigned HOST_WIDE_INT align)
568 if (GET_MODE_SIZE (mode) <= SCORE7_SDATA_MAX)
569 return get_named_section (0, ".sdata", 0);
570 else if (flag_pic && score7_symbolic_expression_p (x))
571 return get_named_section (0, ".data.rel.ro", 3);
572 else
573 return mergeable_constant_section (mode, align, 0);
576 /* Implement TARGET_IN_SMALL_DATA_P. */
577 bool
578 score7_in_small_data_p (const_tree decl)
580 HOST_WIDE_INT size;
582 if (TREE_CODE (decl) == STRING_CST
583 || TREE_CODE (decl) == FUNCTION_DECL)
584 return false;
586 if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl) != 0)
588 const char *name;
589 name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
590 if (strcmp (name, ".sdata") != 0
591 && strcmp (name, ".sbss") != 0)
592 return true;
593 if (!DECL_EXTERNAL (decl))
594 return false;
596 size = int_size_in_bytes (TREE_TYPE (decl));
597 return (size > 0 && size <= SCORE7_SDATA_MAX);
600 /* Implement TARGET_ASM_FILE_START. */
601 void
602 score7_asm_file_start (void)
604 default_file_start ();
605 fprintf (asm_out_file, ASM_COMMENT_START
606 "GCC for S+core %s \n", SCORE_GCC_VERSION);
608 if (flag_pic)
609 fprintf (asm_out_file, "\t.set pic\n");
612 /* Implement TARGET_ASM_FILE_END. When using assembler macros, emit
613 .externs for any small-data variables that turned out to be external. */
614 void
615 score7_asm_file_end (void)
617 tree name_tree;
618 struct extern_list *p;
619 if (extern_head)
621 fputs ("\n", asm_out_file);
622 for (p = extern_head; p != 0; p = p->next)
624 name_tree = get_identifier (p->name);
625 if (!TREE_ASM_WRITTEN (name_tree)
626 && TREE_SYMBOL_REFERENCED (name_tree))
628 TREE_ASM_WRITTEN (name_tree) = 1;
629 fputs ("\t.extern\t", asm_out_file);
630 assemble_name (asm_out_file, p->name);
631 fprintf (asm_out_file, ", %d\n", p->size);
637 /* Implement TARGET_OPTION_OVERRIDE hook. */
638 void
639 score7_option_override (void)
641 flag_pic = false;
642 if (!flag_pic)
643 score7_sdata_max = (global_options_set.x_g_switch_value
644 ? g_switch_value
645 : SCORE7_DEFAULT_SDATA_MAX);
646 else
648 score7_sdata_max = 0;
649 if (global_options_set.x_g_switch_value && (g_switch_value != 0))
650 warning (0, "-fPIC and -G are incompatible");
653 score_char_to_class['d'] = G32_REGS;
654 score_char_to_class['e'] = G16_REGS;
655 score_char_to_class['t'] = T32_REGS;
657 score_char_to_class['h'] = HI_REG;
658 score_char_to_class['l'] = LO_REG;
659 score_char_to_class['x'] = CE_REGS;
661 score_char_to_class['q'] = CN_REG;
662 score_char_to_class['y'] = LC_REG;
663 score_char_to_class['z'] = SC_REG;
664 score_char_to_class['a'] = SP_REGS;
666 score_char_to_class['c'] = CR_REGS;
669 /* Implement REGNO_REG_CLASS macro. */
671 score7_reg_class (int regno)
673 int c;
674 gcc_assert (regno >= 0 && regno < FIRST_PSEUDO_REGISTER);
676 if (regno == FRAME_POINTER_REGNUM
677 || regno == ARG_POINTER_REGNUM)
678 return ALL_REGS;
680 for (c = 0; c < N_REG_CLASSES; c++)
681 if (TEST_HARD_REG_BIT (reg_class_contents[c], regno))
682 return c;
684 return NO_REGS;
687 /* Implement PREFERRED_RELOAD_CLASS macro. */
688 enum reg_class
689 score7_preferred_reload_class (rtx x ATTRIBUTE_UNUSED, enum reg_class rclass)
691 if (reg_class_subset_p (G16_REGS, rclass))
692 return G16_REGS;
693 if (reg_class_subset_p (G32_REGS, rclass))
694 return G32_REGS;
695 return rclass;
698 /* Implement SECONDARY_INPUT_RELOAD_CLASS
699 and SECONDARY_OUTPUT_RELOAD_CLASS macro. */
700 enum reg_class
701 score7_secondary_reload_class (enum reg_class rclass,
702 enum machine_mode mode ATTRIBUTE_UNUSED,
703 rtx x)
705 int regno = -1;
706 if (GET_CODE (x) == REG || GET_CODE(x) == SUBREG)
707 regno = true_regnum (x);
709 if (!GR_REG_CLASS_P (rclass))
710 return GP_REG_P (regno) ? NO_REGS : G32_REGS;
711 return NO_REGS;
714 /* Implement CONST_OK_FOR_LETTER_P macro. */
715 /* imm constraints
716 I imm16 << 16
717 J uimm5
718 K uimm16
719 L simm16
720 M uimm14
721 N simm14 */
723 score7_const_ok_for_letter_p (HOST_WIDE_INT value, char c)
725 switch (c)
727 case 'I': return ((value & 0xffff) == 0);
728 case 'J': return IMM_IN_RANGE (value, 5, 0);
729 case 'K': return IMM_IN_RANGE (value, 16, 0);
730 case 'L': return IMM_IN_RANGE (value, 16, 1);
731 case 'M': return IMM_IN_RANGE (value, 14, 0);
732 case 'N': return IMM_IN_RANGE (value, 14, 1);
733 default : return 0;
737 /* Implement EXTRA_CONSTRAINT macro. */
738 /* Z symbol_ref */
740 score7_extra_constraint (rtx op, char c)
742 switch (c)
744 case 'Z':
745 return GET_CODE (op) == SYMBOL_REF;
746 default:
747 gcc_unreachable ();
751 /* Return truth value on whether or not a given hard register
752 can support a given mode. */
754 score7_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
756 int size = GET_MODE_SIZE (mode);
757 enum mode_class mclass = GET_MODE_CLASS (mode);
759 if (mclass == MODE_CC)
760 return regno == CC_REGNUM;
761 else if (regno == FRAME_POINTER_REGNUM
762 || regno == ARG_POINTER_REGNUM)
763 return mclass == MODE_INT;
764 else if (GP_REG_P (regno))
765 /* ((regno <= (GP_REG_LAST- HARD_REGNO_NREGS (dummy, mode)) + 1) */
766 return !(regno & 1) || (size <= UNITS_PER_WORD);
767 else if (CE_REG_P (regno))
768 return (mclass == MODE_INT
769 && ((size <= UNITS_PER_WORD)
770 || (regno == CE_REG_FIRST && size == 2 * UNITS_PER_WORD)));
771 else
772 return (mclass == MODE_INT) && (size <= UNITS_PER_WORD);
775 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
776 pointer or argument pointer. TO is either the stack pointer or
777 hard frame pointer. */
778 HOST_WIDE_INT
779 score7_initial_elimination_offset (int from,
780 int to ATTRIBUTE_UNUSED)
782 struct score7_frame_info *f = score7_compute_frame_size (get_frame_size ());
783 switch (from)
785 case ARG_POINTER_REGNUM:
786 return f->total_size;
787 case FRAME_POINTER_REGNUM:
788 return 0;
789 default:
790 gcc_unreachable ();
794 /* Implement TARGET_FUNCTION_ARG_ADVANCE hook. */
795 void
796 score7_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
797 const_tree type, bool named)
799 struct score7_arg_info info;
800 score7_classify_arg (cum, mode, type, named, &info);
801 cum->num_gprs = info.reg_offset + info.reg_words;
802 if (info.stack_words > 0)
803 cum->stack_words = info.stack_offset + info.stack_words;
804 cum->arg_number++;
807 /* Implement TARGET_ARG_PARTIAL_BYTES macro. */
809 score7_arg_partial_bytes (CUMULATIVE_ARGS *cum,
810 enum machine_mode mode, tree type, bool named)
812 struct score7_arg_info info;
813 score7_classify_arg (cum, mode, type, named, &info);
814 return info.stack_words > 0 ? info.reg_words * UNITS_PER_WORD : 0;
817 /* Implement TARGET_FUNCTION_ARG hook. */
819 score7_function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
820 const_tree type, bool named)
822 struct score7_arg_info info;
824 if (mode == VOIDmode || !named)
825 return 0;
827 score7_classify_arg (cum, mode, type, named, &info);
829 if (info.reg_offset == ARG_REG_NUM)
830 return 0;
832 if (!info.stack_words)
833 return gen_rtx_REG (mode, ARG_REG_FIRST + info.reg_offset);
834 else
836 rtx ret = gen_rtx_PARALLEL (mode, rtvec_alloc (info.reg_words));
837 unsigned int i, part_offset = 0;
838 for (i = 0; i < info.reg_words; i++)
840 rtx reg;
841 reg = gen_rtx_REG (SImode, ARG_REG_FIRST + info.reg_offset + i);
842 XVECEXP (ret, 0, i) = gen_rtx_EXPR_LIST (SImode, reg,
843 GEN_INT (part_offset));
844 part_offset += UNITS_PER_WORD;
846 return ret;
850 /* Implement FUNCTION_VALUE and LIBCALL_VALUE. For normal calls,
851 VALTYPE is the return type and MODE is VOIDmode. For libcalls,
852 VALTYPE is null and MODE is the mode of the return value. */
854 score7_function_value (const_tree valtype, const_tree func,
855 enum machine_mode mode)
857 if (valtype)
859 int unsignedp;
860 mode = TYPE_MODE (valtype);
861 unsignedp = TYPE_UNSIGNED (valtype);
862 mode = promote_function_mode (valtype, mode, &unsignedp, func, 1);
864 return gen_rtx_REG (mode, RT_REGNUM);
867 /* Implement TARGET_ASM_TRAMPOLINE_TEMPLATE. */
869 void
870 score7_asm_trampoline_template (FILE *f)
872 fprintf (f, "\t.set r1\n");
873 fprintf (f, "\tmv r31, r3\n");
874 fprintf (f, "\tbl nextinsn\n");
875 fprintf (f, "nextinsn:\n");
876 fprintf (f, "\tlw r1, [r3, 6*4-8]\n");
877 fprintf (f, "\tlw r23, [r3, 6*4-4]\n");
878 fprintf (f, "\tmv r3, r31\n");
879 fprintf (f, "\tbr! r1\n");
880 fprintf (f, "\tnop!\n");
881 fprintf (f, "\t.set nor1\n");
884 /* Implement TARGET_TRAMPOLINE_INIT. */
885 void
886 score7_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
888 #define FFCACHE "_flush_cache"
889 #define CODE_SIZE (TRAMPOLINE_INSNS * UNITS_PER_WORD)
891 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
892 rtx addr = XEXP (m_tramp, 0);
893 rtx mem;
895 emit_block_move (m_tramp, assemble_trampoline_template (),
896 GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
898 mem = adjust_address (m_tramp, SImode, CODE_SIZE);
899 emit_move_insn (mem, fnaddr);
900 mem = adjust_address (m_tramp, SImode, CODE_SIZE + GET_MODE_SIZE (SImode));
901 emit_move_insn (mem, chain_value);
903 emit_library_call (gen_rtx_SYMBOL_REF (Pmode, FFCACHE),
904 LCT_NORMAL, VOIDmode, 2,
905 addr, Pmode,
906 GEN_INT (TRAMPOLINE_SIZE), SImode);
907 #undef FFCACHE
908 #undef CODE_SIZE
911 /* This function is used to implement REG_MODE_OK_FOR_BASE_P macro. */
913 score7_regno_mode_ok_for_base_p (int regno, int strict)
915 if (regno >= FIRST_PSEUDO_REGISTER)
917 if (!strict)
918 return 1;
919 regno = reg_renumber[regno];
921 if (regno == ARG_POINTER_REGNUM
922 || regno == FRAME_POINTER_REGNUM)
923 return 1;
924 return GP_REG_P (regno);
927 /* Implement TARGET_LEGITIMATE_ADDRESS_P macro. */
928 bool
929 score7_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
931 struct score7_address_info addr;
933 return score7_classify_address (&addr, mode, x, strict);
936 /* Return a number assessing the cost of moving a register in class
937 FROM to class TO. */
939 score7_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
940 enum reg_class from, enum reg_class to)
942 if (GR_REG_CLASS_P (from))
944 if (GR_REG_CLASS_P (to))
945 return 2;
946 else if (SP_REG_CLASS_P (to))
947 return 4;
948 else if (CP_REG_CLASS_P (to))
949 return 5;
950 else if (CE_REG_CLASS_P (to))
951 return 6;
953 if (GR_REG_CLASS_P (to))
955 if (GR_REG_CLASS_P (from))
956 return 2;
957 else if (SP_REG_CLASS_P (from))
958 return 4;
959 else if (CP_REG_CLASS_P (from))
960 return 5;
961 else if (CE_REG_CLASS_P (from))
962 return 6;
964 return 12;
967 /* Return the number of instructions needed to load a symbol of the
968 given type into a register. */
969 static int
970 score7_symbol_insns (enum score_symbol_type type)
972 switch (type)
974 case SYMBOL_GENERAL:
975 return 2;
977 case SYMBOL_SMALL_DATA:
978 return 1;
981 gcc_unreachable ();
984 /* Return the number of instructions needed to load or store a value
985 of mode MODE at X. Return 0 if X isn't valid for MODE. */
986 static int
987 score7_address_insns (rtx x, enum machine_mode mode)
989 struct score7_address_info addr;
990 int factor;
992 if (mode == BLKmode)
993 factor = 1;
994 else
995 factor = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
997 if (score7_classify_address (&addr, mode, x, false))
998 switch (addr.type)
1000 case SCORE7_ADD_REG:
1001 case SCORE7_ADD_CONST_INT:
1002 return factor;
1004 case SCORE7_ADD_SYMBOLIC:
1005 return factor * score7_symbol_insns (addr.symbol_type);
1007 return 0;
1010 /* Implement TARGET_RTX_COSTS macro. */
1011 bool
1012 score7_rtx_costs (rtx x, int code, int outer_code, int *total,
1013 bool speed ATTRIBUTE_UNUSED)
1015 enum machine_mode mode = GET_MODE (x);
1017 switch (code)
1019 case CONST_INT:
1020 if (outer_code == SET)
1022 if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
1023 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L'))
1024 *total = COSTS_N_INSNS (1);
1025 else
1026 *total = COSTS_N_INSNS (2);
1028 else if (outer_code == PLUS || outer_code == MINUS)
1030 if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'N'))
1031 *total = 0;
1032 else if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
1033 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L'))
1034 *total = 1;
1035 else
1036 *total = COSTS_N_INSNS (2);
1038 else if (outer_code == AND || outer_code == IOR)
1040 if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'M'))
1041 *total = 0;
1042 else if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
1043 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'K'))
1044 *total = 1;
1045 else
1046 *total = COSTS_N_INSNS (2);
1048 else
1050 *total = 0;
1052 return true;
1054 case CONST:
1055 case SYMBOL_REF:
1056 case LABEL_REF:
1057 case CONST_DOUBLE:
1058 *total = COSTS_N_INSNS (2);
1059 return true;
1061 case MEM:
1063 /* If the address is legitimate, return the number of
1064 instructions it needs, otherwise use the default handling. */
1065 int n = score7_address_insns (XEXP (x, 0), GET_MODE (x));
1066 if (n > 0)
1068 *total = COSTS_N_INSNS (n + 1);
1069 return true;
1071 return false;
1074 case FFS:
1075 *total = COSTS_N_INSNS (6);
1076 return true;
1078 case NOT:
1079 *total = COSTS_N_INSNS (1);
1080 return true;
1082 case AND:
1083 case IOR:
1084 case XOR:
1085 if (mode == DImode)
1087 *total = COSTS_N_INSNS (2);
1088 return true;
1090 return false;
1092 case ASHIFT:
1093 case ASHIFTRT:
1094 case LSHIFTRT:
1095 if (mode == DImode)
1097 *total = COSTS_N_INSNS ((GET_CODE (XEXP (x, 1)) == CONST_INT)
1098 ? 4 : 12);
1099 return true;
1101 return false;
1103 case ABS:
1104 *total = COSTS_N_INSNS (4);
1105 return true;
1107 case PLUS:
1108 case MINUS:
1109 if (mode == DImode)
1111 *total = COSTS_N_INSNS (4);
1112 return true;
1114 *total = COSTS_N_INSNS (1);
1115 return true;
1117 case NEG:
1118 if (mode == DImode)
1120 *total = COSTS_N_INSNS (4);
1121 return true;
1123 return false;
1125 case MULT:
1126 *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (12);
1127 return true;
1129 case DIV:
1130 case MOD:
1131 case UDIV:
1132 case UMOD:
1133 *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (33);
1134 return true;
1136 case SIGN_EXTEND:
1137 case ZERO_EXTEND:
1138 switch (GET_MODE (XEXP (x, 0)))
1140 case QImode:
1141 case HImode:
1142 if (GET_CODE (XEXP (x, 0)) == MEM)
1144 *total = COSTS_N_INSNS (2);
1146 if (!TARGET_LITTLE_ENDIAN &&
1147 side_effects_p (XEXP (XEXP (x, 0), 0)))
1148 *total = 100;
1150 else
1151 *total = COSTS_N_INSNS (1);
1152 break;
1154 default:
1155 *total = COSTS_N_INSNS (1);
1156 break;
1158 return true;
1160 default:
1161 return false;
1165 /* Implement TARGET_ADDRESS_COST macro. */
1167 score7_address_cost (rtx addr)
1169 return score7_address_insns (addr, SImode);
1172 /* Implement ASM_OUTPUT_EXTERNAL macro. */
1174 score7_output_external (FILE *file ATTRIBUTE_UNUSED,
1175 tree decl, const char *name)
1177 register struct extern_list *p;
1179 if (score7_in_small_data_p (decl))
1181 p = ggc_alloc_extern_list ();
1182 p->next = extern_head;
1183 p->name = name;
1184 p->size = int_size_in_bytes (TREE_TYPE (decl));
1185 extern_head = p;
1187 return 0;
1190 /* Implement RETURN_ADDR_RTX. Note, we do not support moving
1191 back to a previous frame. */
1193 score7_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
1195 if (count != 0)
1196 return const0_rtx;
1197 return get_hard_reg_initial_val (Pmode, RA_REGNUM);
1200 /* Implement PRINT_OPERAND macro. */
1201 /* Score-specific operand codes:
1202 '[' print .set nor1 directive
1203 ']' print .set r1 directive
1204 'U' print hi part of a CONST_INT rtx
1205 'E' print log2(v)
1206 'F' print log2(~v)
1207 'D' print SFmode const double
1208 'S' selectively print "!" if operand is 15bit instruction accessible
1209 'V' print "v!" if operand is 15bit instruction accessible, or "lfh!"
1210 'L' low part of DImode reg operand
1211 'H' high part of DImode reg operand
1212 'C' print part of opcode for a branch condition. */
1213 void
1214 score7_print_operand (FILE *file, rtx op, int c)
1216 enum rtx_code code = UNKNOWN;
1217 if (!PRINT_OPERAND_PUNCT_VALID_P (c))
1218 code = GET_CODE (op);
1220 if (c == '[')
1222 fprintf (file, ".set r1\n");
1224 else if (c == ']')
1226 fprintf (file, "\n\t.set nor1");
1228 else if (c == 'U')
1230 gcc_assert (code == CONST_INT);
1231 fprintf (file, HOST_WIDE_INT_PRINT_HEX,
1232 (INTVAL (op) >> 16) & 0xffff);
1234 else if (c == 'D')
1236 if (GET_CODE (op) == CONST_DOUBLE)
1238 rtx temp = gen_lowpart (SImode, op);
1239 gcc_assert (GET_MODE (op) == SFmode);
1240 fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (temp) & 0xffffffff);
1242 else
1243 output_addr_const (file, op);
1245 else if (c == 'S')
1247 gcc_assert (code == REG);
1248 if (G16_REG_P (REGNO (op)))
1249 fprintf (file, "!");
1251 else if (c == 'V')
1253 gcc_assert (code == REG);
1254 fprintf (file, G16_REG_P (REGNO (op)) ? "v!" : "lfh!");
1256 else if (c == 'C')
1258 enum machine_mode mode = GET_MODE (XEXP (op, 0));
1260 switch (code)
1262 case EQ: fputs ("eq", file); break;
1263 case NE: fputs ("ne", file); break;
1264 case GT: fputs ("gt", file); break;
1265 case GE: fputs (mode != CCmode ? "pl" : "ge", file); break;
1266 case LT: fputs (mode != CCmode ? "mi" : "lt", file); break;
1267 case LE: fputs ("le", file); break;
1268 case GTU: fputs ("gtu", file); break;
1269 case GEU: fputs ("cs", file); break;
1270 case LTU: fputs ("cc", file); break;
1271 case LEU: fputs ("leu", file); break;
1272 default:
1273 output_operand_lossage ("invalid operand for code: '%c'", code);
1276 else if (c == 'E')
1278 unsigned HOST_WIDE_INT i;
1279 unsigned HOST_WIDE_INT pow2mask = 1;
1280 unsigned HOST_WIDE_INT val;
1282 val = INTVAL (op);
1283 for (i = 0; i < 32; i++)
1285 if (val == pow2mask)
1286 break;
1287 pow2mask <<= 1;
1289 gcc_assert (i < 32);
1290 fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
1292 else if (c == 'F')
1294 unsigned HOST_WIDE_INT i;
1295 unsigned HOST_WIDE_INT pow2mask = 1;
1296 unsigned HOST_WIDE_INT val;
1298 val = ~INTVAL (op);
1299 for (i = 0; i < 32; i++)
1301 if (val == pow2mask)
1302 break;
1303 pow2mask <<= 1;
1305 gcc_assert (i < 32);
1306 fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
1308 else if (code == REG)
1310 int regnum = REGNO (op);
1311 if ((c == 'H' && !WORDS_BIG_ENDIAN)
1312 || (c == 'L' && WORDS_BIG_ENDIAN))
1313 regnum ++;
1314 fprintf (file, "%s", reg_names[regnum]);
1316 else
1318 switch (code)
1320 case MEM:
1321 score7_print_operand_address (file, op);
1322 break;
1323 default:
1324 output_addr_const (file, op);
1329 /* Implement PRINT_OPERAND_ADDRESS macro. */
1330 void
1331 score7_print_operand_address (FILE *file, rtx x)
1333 struct score7_address_info addr;
1334 enum rtx_code code = GET_CODE (x);
1335 enum machine_mode mode = GET_MODE (x);
1337 if (code == MEM)
1338 x = XEXP (x, 0);
1340 if (score7_classify_address (&addr, mode, x, true))
1342 switch (addr.type)
1344 case SCORE7_ADD_REG:
1346 switch (addr.code)
1348 case PRE_DEC:
1349 fprintf (file, "[%s,-%ld]+", reg_names[REGNO (addr.reg)],
1350 INTVAL (addr.offset));
1351 break;
1352 case POST_DEC:
1353 fprintf (file, "[%s]+,-%ld", reg_names[REGNO (addr.reg)],
1354 INTVAL (addr.offset));
1355 break;
1356 case PRE_INC:
1357 fprintf (file, "[%s, %ld]+", reg_names[REGNO (addr.reg)],
1358 INTVAL (addr.offset));
1359 break;
1360 case POST_INC:
1361 fprintf (file, "[%s]+, %ld", reg_names[REGNO (addr.reg)],
1362 INTVAL (addr.offset));
1363 break;
1364 default:
1365 if (INTVAL(addr.offset) == 0)
1366 fprintf(file, "[%s]", reg_names[REGNO (addr.reg)]);
1367 else
1368 fprintf(file, "[%s, %ld]", reg_names[REGNO (addr.reg)],
1369 INTVAL(addr.offset));
1370 break;
1373 return;
1374 case SCORE7_ADD_CONST_INT:
1375 case SCORE7_ADD_SYMBOLIC:
1376 output_addr_const (file, x);
1377 return;
1380 print_rtl (stderr, x);
1381 gcc_unreachable ();
1384 /* Implement SELECT_CC_MODE macro. */
1385 enum machine_mode
1386 score7_select_cc_mode (enum rtx_code op, rtx x, rtx y)
1388 if ((op == EQ || op == NE || op == LT || op == GE)
1389 && y == const0_rtx
1390 && GET_MODE (x) == SImode)
1392 switch (GET_CODE (x))
1394 case PLUS:
1395 case MINUS:
1396 case NEG:
1397 case AND:
1398 case IOR:
1399 case XOR:
1400 case NOT:
1401 case ASHIFT:
1402 case LSHIFTRT:
1403 case ASHIFTRT:
1404 return CC_NZmode;
1406 case SIGN_EXTEND:
1407 case ZERO_EXTEND:
1408 case ROTATE:
1409 case ROTATERT:
1410 return (op == LT || op == GE) ? CC_Nmode : CCmode;
1412 default:
1413 return CCmode;
1417 if ((op == EQ || op == NE)
1418 && (GET_CODE (y) == NEG)
1419 && register_operand (XEXP (y, 0), SImode)
1420 && register_operand (x, SImode))
1422 return CC_NZmode;
1425 return CCmode;
1428 /* Generate the prologue instructions for entry into a S+core function. */
1429 void
1430 score7_prologue (void)
1432 #define EMIT_PL(_rtx) RTX_FRAME_RELATED_P (_rtx) = 1
1434 struct score7_frame_info *f = score7_compute_frame_size (get_frame_size ());
1435 HOST_WIDE_INT size;
1436 int regno;
1438 size = f->total_size - f->gp_reg_size;
1440 if (flag_pic)
1441 emit_insn (gen_cpload_score7 ());
1443 for (regno = (int) GP_REG_LAST; regno >= (int) GP_REG_FIRST; regno--)
1445 if (BITSET_P (f->mask, regno - GP_REG_FIRST))
1447 rtx mem = gen_rtx_MEM (SImode,
1448 gen_rtx_PRE_DEC (SImode, stack_pointer_rtx));
1449 rtx reg = gen_rtx_REG (SImode, regno);
1450 if (!crtl->calls_eh_return)
1451 MEM_READONLY_P (mem) = 1;
1452 EMIT_PL (emit_insn (gen_pushsi_score7 (mem, reg)));
1456 if (size > 0)
1458 rtx insn;
1460 if (CONST_OK_FOR_LETTER_P (-size, 'L'))
1461 EMIT_PL (emit_insn (gen_add3_insn (stack_pointer_rtx,
1462 stack_pointer_rtx,
1463 GEN_INT (-size))));
1464 else
1466 EMIT_PL (emit_move_insn (gen_rtx_REG (Pmode, SCORE7_PROLOGUE_TEMP_REGNUM),
1467 GEN_INT (size)));
1468 EMIT_PL (emit_insn
1469 (gen_sub3_insn (stack_pointer_rtx,
1470 stack_pointer_rtx,
1471 gen_rtx_REG (Pmode,
1472 SCORE7_PROLOGUE_TEMP_REGNUM))));
1474 insn = get_last_insn ();
1475 REG_NOTES (insn) =
1476 alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR,
1477 gen_rtx_SET (VOIDmode, stack_pointer_rtx,
1478 plus_constant (stack_pointer_rtx,
1479 -size)),
1480 REG_NOTES (insn));
1483 if (frame_pointer_needed)
1484 EMIT_PL (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx));
1486 if (flag_pic && f->cprestore_size)
1488 if (frame_pointer_needed)
1489 emit_insn (gen_cprestore_use_fp_score7 (GEN_INT (size - f->cprestore_size)));
1490 else
1491 emit_insn (gen_cprestore_use_sp_score7 (GEN_INT (size - f->cprestore_size)));
1494 #undef EMIT_PL
1497 /* Generate the epilogue instructions in a S+core function. */
1498 void
1499 score7_epilogue (int sibcall_p)
1501 struct score7_frame_info *f = score7_compute_frame_size (get_frame_size ());
1502 HOST_WIDE_INT size;
1503 int regno;
1504 rtx base;
1506 size = f->total_size - f->gp_reg_size;
1508 if (!frame_pointer_needed)
1509 base = stack_pointer_rtx;
1510 else
1511 base = hard_frame_pointer_rtx;
1513 if (size)
1515 if (CONST_OK_FOR_LETTER_P (size, 'L'))
1516 emit_insn (gen_add3_insn (base, base, GEN_INT (size)));
1517 else
1519 emit_move_insn (gen_rtx_REG (Pmode, SCORE7_EPILOGUE_TEMP_REGNUM),
1520 GEN_INT (size));
1521 emit_insn (gen_add3_insn (base, base,
1522 gen_rtx_REG (Pmode,
1523 SCORE7_EPILOGUE_TEMP_REGNUM)));
1527 if (base != stack_pointer_rtx)
1528 emit_move_insn (stack_pointer_rtx, base);
1530 if (crtl->calls_eh_return)
1531 emit_insn (gen_add3_insn (stack_pointer_rtx,
1532 stack_pointer_rtx,
1533 EH_RETURN_STACKADJ_RTX));
1535 for (regno = (int) GP_REG_FIRST; regno <= (int) GP_REG_LAST; regno++)
1537 if (BITSET_P (f->mask, regno - GP_REG_FIRST))
1539 rtx mem = gen_rtx_MEM (SImode,
1540 gen_rtx_POST_INC (SImode, stack_pointer_rtx));
1541 rtx reg = gen_rtx_REG (SImode, regno);
1543 if (!crtl->calls_eh_return)
1544 MEM_READONLY_P (mem) = 1;
1546 emit_insn (gen_popsi_score7 (reg, mem));
1550 if (!sibcall_p)
1551 emit_jump_insn (gen_return_internal_score7 (gen_rtx_REG (Pmode, RA_REGNUM)));
1554 /* Return true if X is a symbolic constant that can be calculated in
1555 the same way as a bare symbol. If it is, store the type of the
1556 symbol in *SYMBOL_TYPE. */
1558 score7_symbolic_constant_p (rtx x, enum score_symbol_type *symbol_type)
1560 HOST_WIDE_INT offset;
1562 score7_split_const (x, &x, &offset);
1563 if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF)
1564 *symbol_type = score7_classify_symbol (x);
1565 else
1566 return 0;
1568 if (offset == 0)
1569 return 1;
1571 /* if offset > 15bit, must reload */
1572 if (!IMM_IN_RANGE (offset, 15, 1))
1573 return 0;
1575 switch (*symbol_type)
1577 case SYMBOL_GENERAL:
1578 return 1;
1579 case SYMBOL_SMALL_DATA:
1580 return score7_offset_within_object_p (x, offset);
1582 gcc_unreachable ();
1585 void
1586 score7_movsicc (rtx *ops)
1588 enum machine_mode mode;
1590 mode = score7_select_cc_mode (GET_CODE (ops[1]), ops[2], ops[3]);
1591 emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (mode, CC_REGNUM),
1592 gen_rtx_COMPARE (mode, XEXP (ops[1], 0),
1593 XEXP (ops[1], 1))));
1596 /* Call and sibcall pattern all need call this function. */
1597 void
1598 score7_call (rtx *ops, bool sib)
1600 rtx addr = XEXP (ops[0], 0);
1601 if (!call_insn_operand (addr, VOIDmode))
1603 rtx oaddr = addr;
1604 addr = gen_reg_rtx (Pmode);
1605 gen_move_insn (addr, oaddr);
1608 if (sib)
1609 emit_call_insn (gen_sibcall_internal_score7 (addr, ops[1]));
1610 else
1611 emit_call_insn (gen_call_internal_score7 (addr, ops[1]));
1614 /* Call value and sibcall value pattern all need call this function. */
1615 void
1616 score7_call_value (rtx *ops, bool sib)
1618 rtx result = ops[0];
1619 rtx addr = XEXP (ops[1], 0);
1620 rtx arg = ops[2];
1622 if (!call_insn_operand (addr, VOIDmode))
1624 rtx oaddr = addr;
1625 addr = gen_reg_rtx (Pmode);
1626 gen_move_insn (addr, oaddr);
1629 if (sib)
1630 emit_call_insn (gen_sibcall_value_internal_score7 (result, addr, arg));
1631 else
1632 emit_call_insn (gen_call_value_internal_score7 (result, addr, arg));
1635 /* Machine Split */
1636 void
1637 score7_movdi (rtx *ops)
1639 rtx dst = ops[0];
1640 rtx src = ops[1];
1641 rtx dst0 = score7_subw (dst, 0);
1642 rtx dst1 = score7_subw (dst, 1);
1643 rtx src0 = score7_subw (src, 0);
1644 rtx src1 = score7_subw (src, 1);
1646 if (GET_CODE (dst0) == REG && reg_overlap_mentioned_p (dst0, src))
1648 emit_move_insn (dst1, src1);
1649 emit_move_insn (dst0, src0);
1651 else
1653 emit_move_insn (dst0, src0);
1654 emit_move_insn (dst1, src1);
1658 void
1659 score7_zero_extract_andi (rtx *ops)
1661 if (INTVAL (ops[1]) == 1 && const_uimm5 (ops[2], SImode))
1662 emit_insn (gen_zero_extract_bittst_score7 (ops[0], ops[2]));
1663 else
1665 unsigned HOST_WIDE_INT mask;
1666 mask = (0xffffffffU & ((1U << INTVAL (ops[1])) - 1U));
1667 mask = mask << INTVAL (ops[2]);
1668 emit_insn (gen_andsi3_cmp_score7 (ops[3], ops[0],
1669 gen_int_mode (mask, SImode)));
1673 /* Check addr could be present as PRE/POST mode. */
1674 static bool
1675 score7_pindex_mem (rtx addr)
1677 if (GET_CODE (addr) == MEM)
1679 switch (GET_CODE (XEXP (addr, 0)))
1681 case PRE_DEC:
1682 case POST_DEC:
1683 case PRE_INC:
1684 case POST_INC:
1685 return true;
1686 default:
1687 break;
1690 return false;
1693 /* Output asm code for ld/sw insn. */
1694 static int
1695 score7_pr_addr_post (rtx *ops, int idata, int iaddr, char *ip, enum score_mem_unit unit)
1697 struct score7_address_info ai;
1699 gcc_assert (GET_CODE (ops[idata]) == REG);
1700 gcc_assert (score7_classify_address (&ai, SImode, XEXP (ops[iaddr], 0), true));
1702 if (!score7_pindex_mem (ops[iaddr])
1703 && ai.type == SCORE7_ADD_REG
1704 && GET_CODE (ai.offset) == CONST_INT
1705 && G16_REG_P (REGNO (ops[idata]))
1706 && G16_REG_P (REGNO (ai.reg)))
1708 if (INTVAL (ai.offset) == 0)
1710 ops[iaddr] = ai.reg;
1711 return snprintf (ip, INS_BUF_SZ,
1712 "!\t%%%d, [%%%d]", idata, iaddr);
1714 if (REGNO (ai.reg) == HARD_FRAME_POINTER_REGNUM)
1716 HOST_WIDE_INT offset = INTVAL (ai.offset);
1717 if (SCORE_ALIGN_UNIT (offset, unit)
1718 && CONST_OK_FOR_LETTER_P (offset >> unit, 'J'))
1720 ops[iaddr] = ai.offset;
1721 return snprintf (ip, INS_BUF_SZ,
1722 "p!\t%%%d, %%c%d", idata, iaddr);
1726 return snprintf (ip, INS_BUF_SZ, "\t%%%d, %%a%d", idata, iaddr);
1729 /* Output asm insn for load. */
1730 const char *
1731 score7_linsn (rtx *ops, enum score_mem_unit unit, bool sign)
1733 const char *pre_ins[] =
1734 {"lbu", "lhu", "lw", "??", "lb", "lh", "lw", "??"};
1735 char *ip;
1737 strcpy (score7_ins, pre_ins[(sign ? 4 : 0) + unit]);
1738 ip = score7_ins + strlen (score7_ins);
1740 if ((!sign && unit != SCORE_HWORD)
1741 || (sign && unit != SCORE_BYTE))
1742 score7_pr_addr_post (ops, 0, 1, ip, unit);
1743 else
1744 snprintf (ip, INS_BUF_SZ, "\t%%0, %%a1");
1746 return score7_ins;
1749 /* Output asm insn for store. */
1750 const char *
1751 score7_sinsn (rtx *ops, enum score_mem_unit unit)
1753 const char *pre_ins[] = {"sb", "sh", "sw"};
1754 char *ip;
1756 strcpy (score7_ins, pre_ins[unit]);
1757 ip = score7_ins + strlen (score7_ins);
1758 score7_pr_addr_post (ops, 1, 0, ip, unit);
1759 return score7_ins;
1762 /* Output asm insn for load immediate. */
1763 const char *
1764 score7_limm (rtx *ops)
1766 HOST_WIDE_INT v;
1768 gcc_assert (GET_CODE (ops[0]) == REG);
1769 gcc_assert (GET_CODE (ops[1]) == CONST_INT);
1771 v = INTVAL (ops[1]);
1772 if (G16_REG_P (REGNO (ops[0])) && IMM_IN_RANGE (v, 8, 0))
1773 return "ldiu!\t%0, %c1";
1774 else if (IMM_IN_RANGE (v, 16, 1))
1775 return "ldi\t%0, %c1";
1776 else if ((v & 0xffff) == 0)
1777 return "ldis\t%0, %U1";
1778 else
1779 return "li\t%0, %c1";
1782 /* Output asm insn for move. */
1783 const char *
1784 score7_move (rtx *ops)
1786 gcc_assert (GET_CODE (ops[0]) == REG);
1787 gcc_assert (GET_CODE (ops[1]) == REG);
1789 if (G16_REG_P (REGNO (ops[0])))
1791 if (G16_REG_P (REGNO (ops[1])))
1792 return "mv!\t%0, %1";
1793 else
1794 return "mlfh!\t%0, %1";
1796 else if (G16_REG_P (REGNO (ops[1])))
1797 return "mhfl!\t%0, %1";
1798 else
1799 return "mv\t%0, %1";
1802 /* Generate add insn. */
1803 const char *
1804 score7_select_add_imm (rtx *ops, bool set_cc)
1806 HOST_WIDE_INT v = INTVAL (ops[2]);
1808 gcc_assert (GET_CODE (ops[2]) == CONST_INT);
1809 gcc_assert (REGNO (ops[0]) == REGNO (ops[1]));
1811 if (set_cc && G16_REG_P (REGNO (ops[0])))
1813 if (v > 0 && IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT) v, 0, 15))
1815 ops[2] = GEN_INT (ffs (v) - 1);
1816 return "addei!\t%0, %c2";
1819 if (v < 0 && IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT) (-v), 0, 15))
1821 ops[2] = GEN_INT (ffs (-v) - 1);
1822 return "subei!\t%0, %c2";
1826 if (set_cc)
1827 return "addi.c\t%0, %c2";
1828 else
1829 return "addi\t%0, %c2";
1832 /* Output arith insn. */
1833 const char *
1834 score7_select (rtx *ops, const char *inst_pre,
1835 bool commu, const char *letter, bool set_cc)
1837 gcc_assert (GET_CODE (ops[0]) == REG);
1838 gcc_assert (GET_CODE (ops[1]) == REG);
1840 if (set_cc && G16_REG_P (REGNO (ops[0]))
1841 && (GET_CODE (ops[2]) == REG ? G16_REG_P (REGNO (ops[2])) : 1)
1842 && REGNO (ops[0]) == REGNO (ops[1]))
1844 snprintf (score7_ins, INS_BUF_SZ, "%s!\t%%0, %%%s2", inst_pre, letter);
1845 return score7_ins;
1848 if (commu && set_cc && G16_REG_P (REGNO (ops[0]))
1849 && G16_REG_P (REGNO (ops[1]))
1850 && REGNO (ops[0]) == REGNO (ops[2]))
1852 gcc_assert (GET_CODE (ops[2]) == REG);
1853 snprintf (score7_ins, INS_BUF_SZ, "%s!\t%%0, %%%s1", inst_pre, letter);
1854 return score7_ins;
1857 if (set_cc)
1858 snprintf (score7_ins, INS_BUF_SZ, "%s.c\t%%0, %%1, %%%s2", inst_pre, letter);
1859 else
1860 snprintf (score7_ins, INS_BUF_SZ, "%s\t%%0, %%1, %%%s2", inst_pre, letter);
1861 return score7_ins;