2009-05-14 Paolo Bonzini <bonzini@gnu.org>
[official-gcc.git] / gcc / config / score / score7.c
blobc18d03b2675056e473c523d85a6eff310181d55c
1 /* score7.c for Sunplus S+CORE processor
2 Copyright (C) 2005, 2007, 2008 Free Software Foundation, Inc.
3 Contributed by Sunnorth
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published
9 by the Free Software Foundation; either version 3, or (at your
10 option) any later version.
12 GCC is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
15 License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
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 "real.h"
29 #include "insn-config.h"
30 #include "conditions.h"
31 #include "insn-attr.h"
32 #include "recog.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 (tree type, tree fndecl ATTRIBUTE_UNUSED)
295 return ((TYPE_MODE (type) == BLKmode)
296 || (int_size_in_bytes (type) > 2 * UNITS_PER_WORD)
297 || (int_size_in_bytes (type) == -1));
300 /* Return a legitimate address for REG + OFFSET. */
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 ();
382 free_after_compilation (cfun);
384 /* Clean up the vars set above. Note that final_end_function resets
385 the global pointer for us. */
386 reload_completed = 0;
389 /* Copy VALUE to a register and return that register. If new psuedos
390 are allowed, copy it into a new register, otherwise use DEST. */
391 static rtx
392 score7_force_temporary (rtx dest, rtx value)
394 if (can_create_pseudo_p ())
395 return force_reg (Pmode, value);
396 else
398 emit_move_insn (copy_rtx (dest), value);
399 return dest;
403 /* Return a LO_SUM expression for ADDR. TEMP is as for score_force_temporary
404 and is used to load the high part into a register. */
405 static rtx
406 score7_split_symbol (rtx temp, rtx addr)
408 rtx high = score7_force_temporary (temp,
409 gen_rtx_HIGH (Pmode, copy_rtx (addr)));
410 return gen_rtx_LO_SUM (Pmode, high, addr);
413 /* This function is used to implement LEGITIMIZE_ADDRESS. If X can
414 be legitimized in a way that the generic machinery might not expect,
415 return the new address. */
417 score7_legitimize_address (rtx x)
419 enum score_symbol_type symbol_type;
421 if (score7_symbolic_constant_p (x, &symbol_type)
422 && symbol_type == SYMBOL_GENERAL)
423 return score7_split_symbol (0, x);
425 if (GET_CODE (x) == PLUS
426 && GET_CODE (XEXP (x, 1)) == CONST_INT)
428 rtx reg = XEXP (x, 0);
429 if (!score7_valid_base_register_p (reg, 0))
430 reg = copy_to_mode_reg (Pmode, reg);
431 return score7_add_offset (reg, INTVAL (XEXP (x, 1)));
434 return x;
437 /* Fill INFO with information about a single argument. CUM is the
438 cumulative state for earlier arguments. MODE is the mode of this
439 argument and TYPE is its type (if known). NAMED is true if this
440 is a named (fixed) argument rather than a variable one. */
441 static void
442 score7_classify_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
443 tree type, int named, struct score7_arg_info *info)
445 int even_reg_p;
446 unsigned int num_words, max_regs;
448 even_reg_p = 0;
449 if (GET_MODE_CLASS (mode) == MODE_INT
450 || GET_MODE_CLASS (mode) == MODE_FLOAT)
451 even_reg_p = (GET_MODE_SIZE (mode) > UNITS_PER_WORD);
452 else
453 if (type != NULL_TREE && TYPE_ALIGN (type) > BITS_PER_WORD && named)
454 even_reg_p = 1;
456 if (TARGET_MUST_PASS_IN_STACK (mode, type))
457 info->reg_offset = ARG_REG_NUM;
458 else
460 info->reg_offset = cum->num_gprs;
461 if (even_reg_p)
462 info->reg_offset += info->reg_offset & 1;
465 if (mode == BLKmode)
466 info->num_bytes = int_size_in_bytes (type);
467 else
468 info->num_bytes = GET_MODE_SIZE (mode);
470 num_words = (info->num_bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
471 max_regs = ARG_REG_NUM - info->reg_offset;
473 /* Partition the argument between registers and stack. */
474 info->reg_words = MIN (num_words, max_regs);
475 info->stack_words = num_words - info->reg_words;
477 /* The alignment applied to registers is also applied to stack arguments. */
478 if (info->stack_words)
480 info->stack_offset = cum->stack_words;
481 if (even_reg_p)
482 info->stack_offset += info->stack_offset & 1;
486 /* Set up the stack and frame (if desired) for the function. */
487 void
488 score7_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
490 const char *fnname;
491 struct score7_frame_info *f = score7_cached_frame ();
492 HOST_WIDE_INT tsize = f->total_size;
494 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
495 if (!flag_inhibit_size_directive)
497 fputs ("\t.ent\t", file);
498 assemble_name (file, fnname);
499 fputs ("\n", file);
501 assemble_name (file, fnname);
502 fputs (":\n", file);
504 if (!flag_inhibit_size_directive)
506 fprintf (file,
507 "\t.frame\t%s," HOST_WIDE_INT_PRINT_DEC ",%s, %d\t\t"
508 "# vars= " HOST_WIDE_INT_PRINT_DEC ", regs= %d"
509 ", args= " HOST_WIDE_INT_PRINT_DEC
510 ", gp= " HOST_WIDE_INT_PRINT_DEC "\n",
511 (reg_names[(frame_pointer_needed)
512 ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM]),
513 tsize,
514 reg_names[RA_REGNUM],
515 current_function_is_leaf ? 1 : 0,
516 f->var_size,
517 f->num_gp,
518 f->args_size,
519 f->cprestore_size);
521 fprintf(file, "\t.mask\t0x%08x," HOST_WIDE_INT_PRINT_DEC "\n",
522 f->mask,
523 (f->gp_sp_offset - f->total_size));
527 /* Do any necessary cleanup after a function to restore stack, frame,
528 and regs. */
529 void
530 score7_function_epilogue (FILE *file,
531 HOST_WIDE_INT size ATTRIBUTE_UNUSED)
533 if (!flag_inhibit_size_directive)
535 const char *fnname;
536 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
537 fputs ("\t.end\t", file);
538 assemble_name (file, fnname);
539 fputs ("\n", file);
543 /* Returns true if X contains a SYMBOL_REF. */
544 static bool
545 score7_symbolic_expression_p (rtx x)
547 if (GET_CODE (x) == SYMBOL_REF)
548 return true;
550 if (GET_CODE (x) == CONST)
551 return score7_symbolic_expression_p (XEXP (x, 0));
553 if (UNARY_P (x))
554 return score7_symbolic_expression_p (XEXP (x, 0));
556 if (ARITHMETIC_P (x))
557 return (score7_symbolic_expression_p (XEXP (x, 0))
558 || score7_symbolic_expression_p (XEXP (x, 1)));
560 return false;
563 /* Choose the section to use for the constant rtx expression X that has
564 mode MODE. */
565 section *
566 score7_select_rtx_section (enum machine_mode mode, rtx x,
567 unsigned HOST_WIDE_INT align)
569 if (GET_MODE_SIZE (mode) <= SCORE7_SDATA_MAX)
570 return get_named_section (0, ".sdata", 0);
571 else if (flag_pic && score7_symbolic_expression_p (x))
572 return get_named_section (0, ".data.rel.ro", 3);
573 else
574 return mergeable_constant_section (mode, align, 0);
577 /* Implement TARGET_IN_SMALL_DATA_P. */
578 bool
579 score7_in_small_data_p (tree decl)
581 HOST_WIDE_INT size;
583 if (TREE_CODE (decl) == STRING_CST
584 || TREE_CODE (decl) == FUNCTION_DECL)
585 return false;
587 if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl) != 0)
589 const char *name;
590 name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
591 if (strcmp (name, ".sdata") != 0
592 && strcmp (name, ".sbss") != 0)
593 return true;
594 if (!DECL_EXTERNAL (decl))
595 return false;
597 size = int_size_in_bytes (TREE_TYPE (decl));
598 return (size > 0 && size <= SCORE7_SDATA_MAX);
601 /* Implement TARGET_ASM_FILE_START. */
602 void
603 score7_asm_file_start (void)
605 default_file_start ();
606 fprintf (asm_out_file, ASM_COMMENT_START
607 "GCC for S+core %s \n", SCORE_GCC_VERSION);
609 if (flag_pic)
610 fprintf (asm_out_file, "\t.set pic\n");
613 /* Implement TARGET_ASM_FILE_END. When using assembler macros, emit
614 .externs for any small-data variables that turned out to be external. */
615 void
616 score7_asm_file_end (void)
618 tree name_tree;
619 struct extern_list *p;
620 if (extern_head)
622 fputs ("\n", asm_out_file);
623 for (p = extern_head; p != 0; p = p->next)
625 name_tree = get_identifier (p->name);
626 if (!TREE_ASM_WRITTEN (name_tree)
627 && TREE_SYMBOL_REFERENCED (name_tree))
629 TREE_ASM_WRITTEN (name_tree) = 1;
630 fputs ("\t.extern\t", asm_out_file);
631 assemble_name (asm_out_file, p->name);
632 fprintf (asm_out_file, ", %d\n", p->size);
638 /* Implement OVERRIDE_OPTIONS macro. */
639 void
640 score7_override_options (void)
642 flag_pic = false;
643 if (!flag_pic)
644 score7_sdata_max = g_switch_set ? g_switch_value : SCORE7_DEFAULT_SDATA_MAX;
645 else
647 score7_sdata_max = 0;
648 if (g_switch_set && (g_switch_value != 0))
649 warning (0, "-fPIC and -G are incompatible");
652 score_char_to_class['d'] = G32_REGS;
653 score_char_to_class['e'] = G16_REGS;
654 score_char_to_class['t'] = T32_REGS;
656 score_char_to_class['h'] = HI_REG;
657 score_char_to_class['l'] = LO_REG;
658 score_char_to_class['x'] = CE_REGS;
660 score_char_to_class['q'] = CN_REG;
661 score_char_to_class['y'] = LC_REG;
662 score_char_to_class['z'] = SC_REG;
663 score_char_to_class['a'] = SP_REGS;
665 score_char_to_class['c'] = CR_REGS;
668 /* Implement REGNO_REG_CLASS macro. */
670 score7_reg_class (int regno)
672 int c;
673 gcc_assert (regno >= 0 && regno < FIRST_PSEUDO_REGISTER);
675 if (regno == FRAME_POINTER_REGNUM
676 || regno == ARG_POINTER_REGNUM)
677 return ALL_REGS;
679 for (c = 0; c < N_REG_CLASSES; c++)
680 if (TEST_HARD_REG_BIT (reg_class_contents[c], regno))
681 return c;
683 return NO_REGS;
686 /* Implement PREFERRED_RELOAD_CLASS macro. */
687 enum reg_class
688 score7_preferred_reload_class (rtx x ATTRIBUTE_UNUSED, enum reg_class rclass)
690 if (reg_class_subset_p (G16_REGS, rclass))
691 return G16_REGS;
692 if (reg_class_subset_p (G32_REGS, rclass))
693 return G32_REGS;
694 return rclass;
697 /* Implement SECONDARY_INPUT_RELOAD_CLASS
698 and SECONDARY_OUTPUT_RELOAD_CLASS macro. */
699 enum reg_class
700 score7_secondary_reload_class (enum reg_class rclass,
701 enum machine_mode mode ATTRIBUTE_UNUSED,
702 rtx x)
704 int regno = -1;
705 if (GET_CODE (x) == REG || GET_CODE(x) == SUBREG)
706 regno = true_regnum (x);
708 if (!GR_REG_CLASS_P (rclass))
709 return GP_REG_P (regno) ? NO_REGS : G32_REGS;
710 return NO_REGS;
713 /* Implement CONST_OK_FOR_LETTER_P macro. */
714 /* imm constraints
715 I imm16 << 16
716 J uimm5
717 K uimm16
718 L simm16
719 M uimm14
720 N simm14 */
722 score7_const_ok_for_letter_p (HOST_WIDE_INT value, char c)
724 switch (c)
726 case 'I': return ((value & 0xffff) == 0);
727 case 'J': return IMM_IN_RANGE (value, 5, 0);
728 case 'K': return IMM_IN_RANGE (value, 16, 0);
729 case 'L': return IMM_IN_RANGE (value, 16, 1);
730 case 'M': return IMM_IN_RANGE (value, 14, 0);
731 case 'N': return IMM_IN_RANGE (value, 14, 1);
732 default : return 0;
736 /* Implement EXTRA_CONSTRAINT macro. */
737 /* Z symbol_ref */
739 score7_extra_constraint (rtx op, char c)
741 switch (c)
743 case 'Z':
744 return GET_CODE (op) == SYMBOL_REF;
745 default:
746 gcc_unreachable ();
750 /* Return truth value on whether or not a given hard register
751 can support a given mode. */
753 score7_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
755 int size = GET_MODE_SIZE (mode);
756 enum mode_class mclass = GET_MODE_CLASS (mode);
758 if (mclass == MODE_CC)
759 return regno == CC_REGNUM;
760 else if (regno == FRAME_POINTER_REGNUM
761 || regno == ARG_POINTER_REGNUM)
762 return mclass == MODE_INT;
763 else if (GP_REG_P (regno))
764 /* ((regno <= (GP_REG_LAST- HARD_REGNO_NREGS (dummy, mode)) + 1) */
765 return !(regno & 1) || (size <= UNITS_PER_WORD);
766 else if (CE_REG_P (regno))
767 return (mclass == MODE_INT
768 && ((size <= UNITS_PER_WORD)
769 || (regno == CE_REG_FIRST && size == 2 * UNITS_PER_WORD)));
770 else
771 return (mclass == MODE_INT) && (size <= UNITS_PER_WORD);
774 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
775 pointer or argument pointer. TO is either the stack pointer or
776 hard frame pointer. */
777 HOST_WIDE_INT
778 score7_initial_elimination_offset (int from,
779 int to ATTRIBUTE_UNUSED)
781 struct score7_frame_info *f = score7_compute_frame_size (get_frame_size ());
782 switch (from)
784 case ARG_POINTER_REGNUM:
785 return f->total_size;
786 case FRAME_POINTER_REGNUM:
787 return 0;
788 default:
789 gcc_unreachable ();
793 /* Implement FUNCTION_ARG_ADVANCE macro. */
794 void
795 score7_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
796 tree type, int named)
798 struct score7_arg_info info;
799 score7_classify_arg (cum, mode, type, named, &info);
800 cum->num_gprs = info.reg_offset + info.reg_words;
801 if (info.stack_words > 0)
802 cum->stack_words = info.stack_offset + info.stack_words;
803 cum->arg_number++;
806 /* Implement TARGET_ARG_PARTIAL_BYTES macro. */
808 score7_arg_partial_bytes (CUMULATIVE_ARGS *cum,
809 enum machine_mode mode, tree type, bool named)
811 struct score7_arg_info info;
812 score7_classify_arg (cum, mode, type, named, &info);
813 return info.stack_words > 0 ? info.reg_words * UNITS_PER_WORD : 0;
816 /* Implement FUNCTION_ARG macro. */
818 score7_function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
819 tree type, int named)
821 struct score7_arg_info info;
823 if (mode == VOIDmode || !named)
824 return 0;
826 score7_classify_arg (cum, mode, type, named, &info);
828 if (info.reg_offset == ARG_REG_NUM)
829 return 0;
831 if (!info.stack_words)
832 return gen_rtx_REG (mode, ARG_REG_FIRST + info.reg_offset);
833 else
835 rtx ret = gen_rtx_PARALLEL (mode, rtvec_alloc (info.reg_words));
836 unsigned int i, part_offset = 0;
837 for (i = 0; i < info.reg_words; i++)
839 rtx reg;
840 reg = gen_rtx_REG (SImode, ARG_REG_FIRST + info.reg_offset + i);
841 XVECEXP (ret, 0, i) = gen_rtx_EXPR_LIST (SImode, reg,
842 GEN_INT (part_offset));
843 part_offset += UNITS_PER_WORD;
845 return ret;
849 /* Implement FUNCTION_VALUE and LIBCALL_VALUE. For normal calls,
850 VALTYPE is the return type and MODE is VOIDmode. For libcalls,
851 VALTYPE is null and MODE is the mode of the return value. */
853 score7_function_value (tree valtype, tree func ATTRIBUTE_UNUSED,
854 enum machine_mode mode)
856 if (valtype)
858 int unsignedp;
859 mode = TYPE_MODE (valtype);
860 unsignedp = TYPE_UNSIGNED (valtype);
861 mode = promote_mode (valtype, mode, &unsignedp, 1);
863 return gen_rtx_REG (mode, RT_REGNUM);
866 /* Implement INITIALIZE_TRAMPOLINE macro. */
867 void
868 score7_initialize_trampoline (rtx ADDR, rtx FUNC, rtx CHAIN)
870 #define FFCACHE "_flush_cache"
871 #define CODE_SIZE (TRAMPOLINE_INSNS * UNITS_PER_WORD)
873 rtx pfunc, pchain;
875 pfunc = plus_constant (ADDR, CODE_SIZE);
876 pchain = plus_constant (ADDR, CODE_SIZE + GET_MODE_SIZE (SImode));
878 emit_move_insn (gen_rtx_MEM (SImode, pfunc), FUNC);
879 emit_move_insn (gen_rtx_MEM (SImode, pchain), CHAIN);
880 emit_library_call (gen_rtx_SYMBOL_REF (Pmode, FFCACHE),
881 0, VOIDmode, 2,
882 ADDR, Pmode,
883 GEN_INT (TRAMPOLINE_SIZE), SImode);
884 #undef FFCACHE
885 #undef CODE_SIZE
888 /* This function is used to implement REG_MODE_OK_FOR_BASE_P macro. */
890 score7_regno_mode_ok_for_base_p (int regno, int strict)
892 if (regno >= FIRST_PSEUDO_REGISTER)
894 if (!strict)
895 return 1;
896 regno = reg_renumber[regno];
898 if (regno == ARG_POINTER_REGNUM
899 || regno == FRAME_POINTER_REGNUM)
900 return 1;
901 return GP_REG_P (regno);
904 /* Implement GO_IF_LEGITIMATE_ADDRESS macro. */
905 bool
906 score7_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
908 struct score7_address_info addr;
910 return score7_classify_address (&addr, mode, x, strict);
913 /* Return a number assessing the cost of moving a register in class
914 FROM to class TO. */
916 score7_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
917 enum reg_class from, enum reg_class to)
919 if (GR_REG_CLASS_P (from))
921 if (GR_REG_CLASS_P (to))
922 return 2;
923 else if (SP_REG_CLASS_P (to))
924 return 4;
925 else if (CP_REG_CLASS_P (to))
926 return 5;
927 else if (CE_REG_CLASS_P (to))
928 return 6;
930 if (GR_REG_CLASS_P (to))
932 if (GR_REG_CLASS_P (from))
933 return 2;
934 else if (SP_REG_CLASS_P (from))
935 return 4;
936 else if (CP_REG_CLASS_P (from))
937 return 5;
938 else if (CE_REG_CLASS_P (from))
939 return 6;
941 return 12;
944 /* Return the number of instructions needed to load a symbol of the
945 given type into a register. */
946 static int
947 score7_symbol_insns (enum score_symbol_type type)
949 switch (type)
951 case SYMBOL_GENERAL:
952 return 2;
954 case SYMBOL_SMALL_DATA:
955 return 1;
958 gcc_unreachable ();
961 /* Return the number of instructions needed to load or store a value
962 of mode MODE at X. Return 0 if X isn't valid for MODE. */
963 static int
964 score7_address_insns (rtx x, enum machine_mode mode)
966 struct score7_address_info addr;
967 int factor;
969 if (mode == BLKmode)
970 factor = 1;
971 else
972 factor = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
974 if (score7_classify_address (&addr, mode, x, false))
975 switch (addr.type)
977 case SCORE7_ADD_REG:
978 case SCORE7_ADD_CONST_INT:
979 return factor;
981 case SCORE7_ADD_SYMBOLIC:
982 return factor * score7_symbol_insns (addr.symbol_type);
984 return 0;
987 /* Implement TARGET_RTX_COSTS macro. */
988 bool
989 score7_rtx_costs (rtx x, int code, int outer_code, int *total,
990 bool speed ATTRIBUTE_UNUSED)
992 enum machine_mode mode = GET_MODE (x);
994 switch (code)
996 case CONST_INT:
997 if (outer_code == SET)
999 if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
1000 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L'))
1001 *total = COSTS_N_INSNS (1);
1002 else
1003 *total = COSTS_N_INSNS (2);
1005 else if (outer_code == PLUS || outer_code == MINUS)
1007 if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'N'))
1008 *total = 0;
1009 else if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
1010 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L'))
1011 *total = 1;
1012 else
1013 *total = COSTS_N_INSNS (2);
1015 else if (outer_code == AND || outer_code == IOR)
1017 if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'M'))
1018 *total = 0;
1019 else if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
1020 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'K'))
1021 *total = 1;
1022 else
1023 *total = COSTS_N_INSNS (2);
1025 else
1027 *total = 0;
1029 return true;
1031 case CONST:
1032 case SYMBOL_REF:
1033 case LABEL_REF:
1034 case CONST_DOUBLE:
1035 *total = COSTS_N_INSNS (2);
1036 return true;
1038 case MEM:
1040 /* If the address is legitimate, return the number of
1041 instructions it needs, otherwise use the default handling. */
1042 int n = score7_address_insns (XEXP (x, 0), GET_MODE (x));
1043 if (n > 0)
1045 *total = COSTS_N_INSNS (n + 1);
1046 return true;
1048 return false;
1051 case FFS:
1052 *total = COSTS_N_INSNS (6);
1053 return true;
1055 case NOT:
1056 *total = COSTS_N_INSNS (1);
1057 return true;
1059 case AND:
1060 case IOR:
1061 case XOR:
1062 if (mode == DImode)
1064 *total = COSTS_N_INSNS (2);
1065 return true;
1067 return false;
1069 case ASHIFT:
1070 case ASHIFTRT:
1071 case LSHIFTRT:
1072 if (mode == DImode)
1074 *total = COSTS_N_INSNS ((GET_CODE (XEXP (x, 1)) == CONST_INT)
1075 ? 4 : 12);
1076 return true;
1078 return false;
1080 case ABS:
1081 *total = COSTS_N_INSNS (4);
1082 return true;
1084 case PLUS:
1085 case MINUS:
1086 if (mode == DImode)
1088 *total = COSTS_N_INSNS (4);
1089 return true;
1091 *total = COSTS_N_INSNS (1);
1092 return true;
1094 case NEG:
1095 if (mode == DImode)
1097 *total = COSTS_N_INSNS (4);
1098 return true;
1100 return false;
1102 case MULT:
1103 *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (12);
1104 return true;
1106 case DIV:
1107 case MOD:
1108 case UDIV:
1109 case UMOD:
1110 *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (33);
1111 return true;
1113 case SIGN_EXTEND:
1114 case ZERO_EXTEND:
1115 switch (GET_MODE (XEXP (x, 0)))
1117 case QImode:
1118 case HImode:
1119 if (GET_CODE (XEXP (x, 0)) == MEM)
1121 *total = COSTS_N_INSNS (2);
1123 if (!TARGET_LITTLE_ENDIAN &&
1124 side_effects_p (XEXP (XEXP (x, 0), 0)))
1125 *total = 100;
1127 else
1128 *total = COSTS_N_INSNS (1);
1129 break;
1131 default:
1132 *total = COSTS_N_INSNS (1);
1133 break;
1135 return true;
1137 default:
1138 return false;
1142 /* Implement TARGET_ADDRESS_COST macro. */
1144 score7_address_cost (rtx addr)
1146 return score7_address_insns (addr, SImode);
1149 /* Implement ASM_OUTPUT_EXTERNAL macro. */
1151 score7_output_external (FILE *file ATTRIBUTE_UNUSED,
1152 tree decl, const char *name)
1154 register struct extern_list *p;
1156 if (score7_in_small_data_p (decl))
1158 p = (struct extern_list *) ggc_alloc (sizeof (struct extern_list));
1159 p->next = extern_head;
1160 p->name = name;
1161 p->size = int_size_in_bytes (TREE_TYPE (decl));
1162 extern_head = p;
1164 return 0;
1167 /* Implement RETURN_ADDR_RTX. Note, we do not support moving
1168 back to a previous frame. */
1170 score7_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
1172 if (count != 0)
1173 return const0_rtx;
1174 return get_hard_reg_initial_val (Pmode, RA_REGNUM);
1177 /* Implement PRINT_OPERAND macro. */
1178 /* Score-specific operand codes:
1179 '[' print .set nor1 directive
1180 ']' print .set r1 directive
1181 'U' print hi part of a CONST_INT rtx
1182 'E' print log2(v)
1183 'F' print log2(~v)
1184 'D' print SFmode const double
1185 'S' selectively print "!" if operand is 15bit instruction accessible
1186 'V' print "v!" if operand is 15bit instruction accessible, or "lfh!"
1187 'L' low part of DImode reg operand
1188 'H' high part of DImode reg operand
1189 'C' print part of opcode for a branch condition. */
1190 void
1191 score7_print_operand (FILE *file, rtx op, int c)
1193 enum rtx_code code = -1;
1194 if (!PRINT_OPERAND_PUNCT_VALID_P (c))
1195 code = GET_CODE (op);
1197 if (c == '[')
1199 fprintf (file, ".set r1\n");
1201 else if (c == ']')
1203 fprintf (file, "\n\t.set nor1");
1205 else if (c == 'U')
1207 gcc_assert (code == CONST_INT);
1208 fprintf (file, HOST_WIDE_INT_PRINT_HEX,
1209 (INTVAL (op) >> 16) & 0xffff);
1211 else if (c == 'D')
1213 if (GET_CODE (op) == CONST_DOUBLE)
1215 rtx temp = gen_lowpart (SImode, op);
1216 gcc_assert (GET_MODE (op) == SFmode);
1217 fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (temp) & 0xffffffff);
1219 else
1220 output_addr_const (file, op);
1222 else if (c == 'S')
1224 gcc_assert (code == REG);
1225 if (G16_REG_P (REGNO (op)))
1226 fprintf (file, "!");
1228 else if (c == 'V')
1230 gcc_assert (code == REG);
1231 fprintf (file, G16_REG_P (REGNO (op)) ? "v!" : "lfh!");
1233 else if (c == 'C')
1235 enum machine_mode mode = GET_MODE (XEXP (op, 0));
1237 switch (code)
1239 case EQ: fputs ("eq", file); break;
1240 case NE: fputs ("ne", file); break;
1241 case GT: fputs ("gt", file); break;
1242 case GE: fputs (mode != CCmode ? "pl" : "ge", file); break;
1243 case LT: fputs (mode != CCmode ? "mi" : "lt", file); break;
1244 case LE: fputs ("le", file); break;
1245 case GTU: fputs ("gtu", file); break;
1246 case GEU: fputs ("cs", file); break;
1247 case LTU: fputs ("cc", file); break;
1248 case LEU: fputs ("leu", file); break;
1249 default:
1250 output_operand_lossage ("invalid operand for code: '%c'", code);
1253 else if (c == 'E')
1255 unsigned HOST_WIDE_INT i;
1256 unsigned HOST_WIDE_INT pow2mask = 1;
1257 unsigned HOST_WIDE_INT val;
1259 val = INTVAL (op);
1260 for (i = 0; i < 32; i++)
1262 if (val == pow2mask)
1263 break;
1264 pow2mask <<= 1;
1266 gcc_assert (i < 32);
1267 fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
1269 else if (c == 'F')
1271 unsigned HOST_WIDE_INT i;
1272 unsigned HOST_WIDE_INT pow2mask = 1;
1273 unsigned HOST_WIDE_INT val;
1275 val = ~INTVAL (op);
1276 for (i = 0; i < 32; i++)
1278 if (val == pow2mask)
1279 break;
1280 pow2mask <<= 1;
1282 gcc_assert (i < 32);
1283 fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
1285 else if (code == REG)
1287 int regnum = REGNO (op);
1288 if ((c == 'H' && !WORDS_BIG_ENDIAN)
1289 || (c == 'L' && WORDS_BIG_ENDIAN))
1290 regnum ++;
1291 fprintf (file, "%s", reg_names[regnum]);
1293 else
1295 switch (code)
1297 case MEM:
1298 score7_print_operand_address (file, op);
1299 break;
1300 default:
1301 output_addr_const (file, op);
1306 /* Implement PRINT_OPERAND_ADDRESS macro. */
1307 void
1308 score7_print_operand_address (FILE *file, rtx x)
1310 struct score7_address_info addr;
1311 enum rtx_code code = GET_CODE (x);
1312 enum machine_mode mode = GET_MODE (x);
1314 if (code == MEM)
1315 x = XEXP (x, 0);
1317 if (score7_classify_address (&addr, mode, x, true))
1319 switch (addr.type)
1321 case SCORE7_ADD_REG:
1323 switch (addr.code)
1325 case PRE_DEC:
1326 fprintf (file, "[%s,-%ld]+", reg_names[REGNO (addr.reg)],
1327 INTVAL (addr.offset));
1328 break;
1329 case POST_DEC:
1330 fprintf (file, "[%s]+,-%ld", reg_names[REGNO (addr.reg)],
1331 INTVAL (addr.offset));
1332 break;
1333 case PRE_INC:
1334 fprintf (file, "[%s, %ld]+", reg_names[REGNO (addr.reg)],
1335 INTVAL (addr.offset));
1336 break;
1337 case POST_INC:
1338 fprintf (file, "[%s]+, %ld", reg_names[REGNO (addr.reg)],
1339 INTVAL (addr.offset));
1340 break;
1341 default:
1342 if (INTVAL(addr.offset) == 0)
1343 fprintf(file, "[%s]", reg_names[REGNO (addr.reg)]);
1344 else
1345 fprintf(file, "[%s, %ld]", reg_names[REGNO (addr.reg)],
1346 INTVAL(addr.offset));
1347 break;
1350 return;
1351 case SCORE7_ADD_CONST_INT:
1352 case SCORE7_ADD_SYMBOLIC:
1353 output_addr_const (file, x);
1354 return;
1357 print_rtl (stderr, x);
1358 gcc_unreachable ();
1361 /* Implement SELECT_CC_MODE macro. */
1362 enum machine_mode
1363 score7_select_cc_mode (enum rtx_code op, rtx x, rtx y)
1365 if ((op == EQ || op == NE || op == LT || op == GE)
1366 && y == const0_rtx
1367 && GET_MODE (x) == SImode)
1369 switch (GET_CODE (x))
1371 case PLUS:
1372 case MINUS:
1373 case NEG:
1374 case AND:
1375 case IOR:
1376 case XOR:
1377 case NOT:
1378 case ASHIFT:
1379 case LSHIFTRT:
1380 case ASHIFTRT:
1381 return CC_NZmode;
1383 case SIGN_EXTEND:
1384 case ZERO_EXTEND:
1385 case ROTATE:
1386 case ROTATERT:
1387 return (op == LT || op == GE) ? CC_Nmode : CCmode;
1389 default:
1390 return CCmode;
1394 if ((op == EQ || op == NE)
1395 && (GET_CODE (y) == NEG)
1396 && register_operand (XEXP (y, 0), SImode)
1397 && register_operand (x, SImode))
1399 return CC_NZmode;
1402 return CCmode;
1405 /* Generate the prologue instructions for entry into a S+core function. */
1406 void
1407 score7_prologue (void)
1409 #define EMIT_PL(_rtx) RTX_FRAME_RELATED_P (_rtx) = 1
1411 struct score7_frame_info *f = score7_compute_frame_size (get_frame_size ());
1412 HOST_WIDE_INT size;
1413 int regno;
1415 size = f->total_size - f->gp_reg_size;
1417 if (flag_pic)
1418 emit_insn (gen_cpload_score7 ());
1420 for (regno = (int) GP_REG_LAST; regno >= (int) GP_REG_FIRST; regno--)
1422 if (BITSET_P (f->mask, regno - GP_REG_FIRST))
1424 rtx mem = gen_rtx_MEM (SImode,
1425 gen_rtx_PRE_DEC (SImode, stack_pointer_rtx));
1426 rtx reg = gen_rtx_REG (SImode, regno);
1427 if (!crtl->calls_eh_return)
1428 MEM_READONLY_P (mem) = 1;
1429 EMIT_PL (emit_insn (gen_pushsi_score7 (mem, reg)));
1433 if (size > 0)
1435 rtx insn;
1437 if (CONST_OK_FOR_LETTER_P (-size, 'L'))
1438 EMIT_PL (emit_insn (gen_add3_insn (stack_pointer_rtx,
1439 stack_pointer_rtx,
1440 GEN_INT (-size))));
1441 else
1443 EMIT_PL (emit_move_insn (gen_rtx_REG (Pmode, SCORE7_PROLOGUE_TEMP_REGNUM),
1444 GEN_INT (size)));
1445 EMIT_PL (emit_insn
1446 (gen_sub3_insn (stack_pointer_rtx,
1447 stack_pointer_rtx,
1448 gen_rtx_REG (Pmode,
1449 SCORE7_PROLOGUE_TEMP_REGNUM))));
1451 insn = get_last_insn ();
1452 REG_NOTES (insn) =
1453 alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR,
1454 gen_rtx_SET (VOIDmode, stack_pointer_rtx,
1455 plus_constant (stack_pointer_rtx,
1456 -size)),
1457 REG_NOTES (insn));
1460 if (frame_pointer_needed)
1461 EMIT_PL (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx));
1463 if (flag_pic && f->cprestore_size)
1465 if (frame_pointer_needed)
1466 emit_insn (gen_cprestore_use_fp_score7 (GEN_INT (size - f->cprestore_size)));
1467 else
1468 emit_insn (gen_cprestore_use_sp_score7 (GEN_INT (size - f->cprestore_size)));
1471 #undef EMIT_PL
1474 /* Generate the epilogue instructions in a S+core function. */
1475 void
1476 score7_epilogue (int sibcall_p)
1478 struct score7_frame_info *f = score7_compute_frame_size (get_frame_size ());
1479 HOST_WIDE_INT size;
1480 int regno;
1481 rtx base;
1483 size = f->total_size - f->gp_reg_size;
1485 if (!frame_pointer_needed)
1486 base = stack_pointer_rtx;
1487 else
1488 base = hard_frame_pointer_rtx;
1490 if (size)
1492 if (CONST_OK_FOR_LETTER_P (size, 'L'))
1493 emit_insn (gen_add3_insn (base, base, GEN_INT (size)));
1494 else
1496 emit_move_insn (gen_rtx_REG (Pmode, SCORE7_EPILOGUE_TEMP_REGNUM),
1497 GEN_INT (size));
1498 emit_insn (gen_add3_insn (base, base,
1499 gen_rtx_REG (Pmode,
1500 SCORE7_EPILOGUE_TEMP_REGNUM)));
1504 if (base != stack_pointer_rtx)
1505 emit_move_insn (stack_pointer_rtx, base);
1507 if (crtl->calls_eh_return)
1508 emit_insn (gen_add3_insn (stack_pointer_rtx,
1509 stack_pointer_rtx,
1510 EH_RETURN_STACKADJ_RTX));
1512 for (regno = (int) GP_REG_FIRST; regno <= (int) GP_REG_LAST; regno++)
1514 if (BITSET_P (f->mask, regno - GP_REG_FIRST))
1516 rtx mem = gen_rtx_MEM (SImode,
1517 gen_rtx_POST_INC (SImode, stack_pointer_rtx));
1518 rtx reg = gen_rtx_REG (SImode, regno);
1520 if (!crtl->calls_eh_return)
1521 MEM_READONLY_P (mem) = 1;
1523 emit_insn (gen_popsi_score7 (reg, mem));
1527 if (!sibcall_p)
1528 emit_jump_insn (gen_return_internal_score7 (gen_rtx_REG (Pmode, RA_REGNUM)));
1531 /* Return true if X is a symbolic constant that can be calculated in
1532 the same way as a bare symbol. If it is, store the type of the
1533 symbol in *SYMBOL_TYPE. */
1535 score7_symbolic_constant_p (rtx x, enum score_symbol_type *symbol_type)
1537 HOST_WIDE_INT offset;
1539 score7_split_const (x, &x, &offset);
1540 if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF)
1541 *symbol_type = score7_classify_symbol (x);
1542 else
1543 return 0;
1545 if (offset == 0)
1546 return 1;
1548 /* if offset > 15bit, must reload */
1549 if (!IMM_IN_RANGE (offset, 15, 1))
1550 return 0;
1552 switch (*symbol_type)
1554 case SYMBOL_GENERAL:
1555 return 1;
1556 case SYMBOL_SMALL_DATA:
1557 return score7_offset_within_object_p (x, offset);
1559 gcc_unreachable ();
1562 void
1563 score7_movsicc (rtx *ops)
1565 enum machine_mode mode;
1567 mode = score7_select_cc_mode (GET_CODE (ops[1]), ops[2], ops[3]);
1568 emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (mode, CC_REGNUM),
1569 gen_rtx_COMPARE (mode, XEXP (ops[1], 0),
1570 XEXP (ops[1], 1))));
1573 /* Call and sibcall pattern all need call this function. */
1574 void
1575 score7_call (rtx *ops, bool sib)
1577 rtx addr = XEXP (ops[0], 0);
1578 if (!call_insn_operand (addr, VOIDmode))
1580 rtx oaddr = addr;
1581 addr = gen_reg_rtx (Pmode);
1582 gen_move_insn (addr, oaddr);
1585 if (sib)
1586 emit_call_insn (gen_sibcall_internal_score7 (addr, ops[1]));
1587 else
1588 emit_call_insn (gen_call_internal_score7 (addr, ops[1]));
1591 /* Call value and sibcall value pattern all need call this function. */
1592 void
1593 score7_call_value (rtx *ops, bool sib)
1595 rtx result = ops[0];
1596 rtx addr = XEXP (ops[1], 0);
1597 rtx arg = ops[2];
1599 if (!call_insn_operand (addr, VOIDmode))
1601 rtx oaddr = addr;
1602 addr = gen_reg_rtx (Pmode);
1603 gen_move_insn (addr, oaddr);
1606 if (sib)
1607 emit_call_insn (gen_sibcall_value_internal_score7 (result, addr, arg));
1608 else
1609 emit_call_insn (gen_call_value_internal_score7 (result, addr, arg));
1612 /* Machine Split */
1613 void
1614 score7_movdi (rtx *ops)
1616 rtx dst = ops[0];
1617 rtx src = ops[1];
1618 rtx dst0 = score7_subw (dst, 0);
1619 rtx dst1 = score7_subw (dst, 1);
1620 rtx src0 = score7_subw (src, 0);
1621 rtx src1 = score7_subw (src, 1);
1623 if (GET_CODE (dst0) == REG && reg_overlap_mentioned_p (dst0, src))
1625 emit_move_insn (dst1, src1);
1626 emit_move_insn (dst0, src0);
1628 else
1630 emit_move_insn (dst0, src0);
1631 emit_move_insn (dst1, src1);
1635 void
1636 score7_zero_extract_andi (rtx *ops)
1638 if (INTVAL (ops[1]) == 1 && const_uimm5 (ops[2], SImode))
1639 emit_insn (gen_zero_extract_bittst_score7 (ops[0], ops[2]));
1640 else
1642 unsigned HOST_WIDE_INT mask;
1643 mask = (0xffffffffU & ((1U << INTVAL (ops[1])) - 1U));
1644 mask = mask << INTVAL (ops[2]);
1645 emit_insn (gen_andsi3_cmp_score7 (ops[3], ops[0],
1646 gen_int_mode (mask, SImode)));
1650 /* Check addr could be present as PRE/POST mode. */
1651 static bool
1652 score7_pindex_mem (rtx addr)
1654 if (GET_CODE (addr) == MEM)
1656 switch (GET_CODE (XEXP (addr, 0)))
1658 case PRE_DEC:
1659 case POST_DEC:
1660 case PRE_INC:
1661 case POST_INC:
1662 return true;
1663 default:
1664 break;
1667 return false;
1670 /* Output asm code for ld/sw insn. */
1671 static int
1672 score7_pr_addr_post (rtx *ops, int idata, int iaddr, char *ip, enum score_mem_unit unit)
1674 struct score7_address_info ai;
1676 gcc_assert (GET_CODE (ops[idata]) == REG);
1677 gcc_assert (score7_classify_address (&ai, SImode, XEXP (ops[iaddr], 0), true));
1679 if (!score7_pindex_mem (ops[iaddr])
1680 && ai.type == SCORE7_ADD_REG
1681 && GET_CODE (ai.offset) == CONST_INT
1682 && G16_REG_P (REGNO (ops[idata]))
1683 && G16_REG_P (REGNO (ai.reg)))
1685 if (INTVAL (ai.offset) == 0)
1687 ops[iaddr] = ai.reg;
1688 return snprintf (ip, INS_BUF_SZ,
1689 "!\t%%%d, [%%%d]", idata, iaddr);
1691 if (REGNO (ai.reg) == HARD_FRAME_POINTER_REGNUM)
1693 HOST_WIDE_INT offset = INTVAL (ai.offset);
1694 if (SCORE_ALIGN_UNIT (offset, unit)
1695 && CONST_OK_FOR_LETTER_P (offset >> unit, 'J'))
1697 ops[iaddr] = ai.offset;
1698 return snprintf (ip, INS_BUF_SZ,
1699 "p!\t%%%d, %%c%d", idata, iaddr);
1703 return snprintf (ip, INS_BUF_SZ, "\t%%%d, %%a%d", idata, iaddr);
1706 /* Output asm insn for load. */
1707 const char *
1708 score7_linsn (rtx *ops, enum score_mem_unit unit, bool sign)
1710 const char *pre_ins[] =
1711 {"lbu", "lhu", "lw", "??", "lb", "lh", "lw", "??"};
1712 char *ip;
1714 strcpy (score7_ins, pre_ins[(sign ? 4 : 0) + unit]);
1715 ip = score7_ins + strlen (score7_ins);
1717 if ((!sign && unit != SCORE_HWORD)
1718 || (sign && unit != SCORE_BYTE))
1719 score7_pr_addr_post (ops, 0, 1, ip, unit);
1720 else
1721 snprintf (ip, INS_BUF_SZ, "\t%%0, %%a1");
1723 return score7_ins;
1726 /* Output asm insn for store. */
1727 const char *
1728 score7_sinsn (rtx *ops, enum score_mem_unit unit)
1730 const char *pre_ins[] = {"sb", "sh", "sw"};
1731 char *ip;
1733 strcpy (score7_ins, pre_ins[unit]);
1734 ip = score7_ins + strlen (score7_ins);
1735 score7_pr_addr_post (ops, 1, 0, ip, unit);
1736 return score7_ins;
1739 /* Output asm insn for load immediate. */
1740 const char *
1741 score7_limm (rtx *ops)
1743 HOST_WIDE_INT v;
1745 gcc_assert (GET_CODE (ops[0]) == REG);
1746 gcc_assert (GET_CODE (ops[1]) == CONST_INT);
1748 v = INTVAL (ops[1]);
1749 if (G16_REG_P (REGNO (ops[0])) && IMM_IN_RANGE (v, 8, 0))
1750 return "ldiu!\t%0, %c1";
1751 else if (IMM_IN_RANGE (v, 16, 1))
1752 return "ldi\t%0, %c1";
1753 else if ((v & 0xffff) == 0)
1754 return "ldis\t%0, %U1";
1755 else
1756 return "li\t%0, %c1";
1759 /* Output asm insn for move. */
1760 const char *
1761 score7_move (rtx *ops)
1763 gcc_assert (GET_CODE (ops[0]) == REG);
1764 gcc_assert (GET_CODE (ops[1]) == REG);
1766 if (G16_REG_P (REGNO (ops[0])))
1768 if (G16_REG_P (REGNO (ops[1])))
1769 return "mv!\t%0, %1";
1770 else
1771 return "mlfh!\t%0, %1";
1773 else if (G16_REG_P (REGNO (ops[1])))
1774 return "mhfl!\t%0, %1";
1775 else
1776 return "mv\t%0, %1";
1779 /* Generate add insn. */
1780 const char *
1781 score7_select_add_imm (rtx *ops, bool set_cc)
1783 HOST_WIDE_INT v = INTVAL (ops[2]);
1785 gcc_assert (GET_CODE (ops[2]) == CONST_INT);
1786 gcc_assert (REGNO (ops[0]) == REGNO (ops[1]));
1788 if (set_cc && G16_REG_P (REGNO (ops[0])))
1790 if (v > 0 && IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT) v, 0, 15))
1792 ops[2] = GEN_INT (ffs (v) - 1);
1793 return "addei!\t%0, %c2";
1796 if (v < 0 && IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT) (-v), 0, 15))
1798 ops[2] = GEN_INT (ffs (-v) - 1);
1799 return "subei!\t%0, %c2";
1803 if (set_cc)
1804 return "addi.c\t%0, %c2";
1805 else
1806 return "addi\t%0, %c2";
1809 /* Output arith insn. */
1810 const char *
1811 score7_select (rtx *ops, const char *inst_pre,
1812 bool commu, const char *letter, bool set_cc)
1814 gcc_assert (GET_CODE (ops[0]) == REG);
1815 gcc_assert (GET_CODE (ops[1]) == REG);
1817 if (set_cc && G16_REG_P (REGNO (ops[0]))
1818 && (GET_CODE (ops[2]) == REG ? G16_REG_P (REGNO (ops[2])) : 1)
1819 && REGNO (ops[0]) == REGNO (ops[1]))
1821 snprintf (score7_ins, INS_BUF_SZ, "%s!\t%%0, %%%s2", inst_pre, letter);
1822 return score7_ins;
1825 if (commu && set_cc && G16_REG_P (REGNO (ops[0]))
1826 && G16_REG_P (REGNO (ops[1]))
1827 && REGNO (ops[0]) == REGNO (ops[2]))
1829 gcc_assert (GET_CODE (ops[2]) == REG);
1830 snprintf (score7_ins, INS_BUF_SZ, "%s!\t%%0, %%%s1", inst_pre, letter);
1831 return score7_ins;
1834 if (set_cc)
1835 snprintf (score7_ins, INS_BUF_SZ, "%s.c\t%%0, %%1, %%%s2", inst_pre, letter);
1836 else
1837 snprintf (score7_ins, INS_BUF_SZ, "%s\t%%0, %%1, %%%s2", inst_pre, letter);
1838 return score7_ins;