Merge from mainline (167278:168000).
[official-gcc/graphite-test-results.git] / gcc / config / score / score3.c
blob5403adf1a44b1f15189082bd0f1a3e59f8d2cb3c
1 /* score3.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 "output.h"
34 #include "tree.h"
35 #include "function.h"
36 #include "expr.h"
37 #include "optabs.h"
38 #include "flags.h"
39 #include "reload.h"
40 #include "tm_p.h"
41 #include "ggc.h"
42 #include "gstab.h"
43 #include "hashtab.h"
44 #include "debug.h"
45 #include "target.h"
46 #include "target-def.h"
47 #include "integrate.h"
48 #include "langhooks.h"
49 #include "cfglayout.h"
50 #include "score3.h"
51 #include "df.h"
53 #define BITSET_P(VALUE, BIT) (((VALUE) & (1L << (BIT))) != 0)
54 #define INS_BUF_SZ 128
56 extern enum reg_class score_char_to_class[256];
58 static int score3_sdata_max;
59 static char score3_ins[INS_BUF_SZ + 8];
61 /* Return true if SYMBOL is a SYMBOL_REF and OFFSET + SYMBOL points
62 to the same object as SYMBOL. */
63 static int
64 score3_offset_within_object_p (rtx symbol, HOST_WIDE_INT offset)
66 if (GET_CODE (symbol) != SYMBOL_REF)
67 return 0;
69 if (CONSTANT_POOL_ADDRESS_P (symbol)
70 && offset >= 0
71 && offset < (int)GET_MODE_SIZE (get_pool_mode (symbol)))
72 return 1;
74 if (SYMBOL_REF_DECL (symbol) != 0
75 && offset >= 0
76 && offset < int_size_in_bytes (TREE_TYPE (SYMBOL_REF_DECL (symbol))))
77 return 1;
79 return 0;
82 /* Split X into a base and a constant offset, storing them in *BASE
83 and *OFFSET respectively. */
84 static void
85 score3_split_const (rtx x, rtx *base, HOST_WIDE_INT *offset)
87 *offset = 0;
89 if (GET_CODE (x) == CONST)
90 x = XEXP (x, 0);
92 if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
94 *offset += INTVAL (XEXP (x, 1));
95 x = XEXP (x, 0);
98 *base = x;
101 /* Classify symbol X, which must be a SYMBOL_REF or a LABEL_REF. */
102 static enum score_symbol_type
103 score3_classify_symbol (rtx x)
105 if (GET_CODE (x) == LABEL_REF)
106 return SYMBOL_GENERAL;
108 gcc_assert (GET_CODE (x) == SYMBOL_REF);
110 if (CONSTANT_POOL_ADDRESS_P (x))
112 if (GET_MODE_SIZE (get_pool_mode (x)) <= SCORE3_SDATA_MAX)
113 return SYMBOL_SMALL_DATA;
114 return SYMBOL_GENERAL;
116 if (SYMBOL_REF_SMALL_P (x))
117 return SYMBOL_SMALL_DATA;
118 return SYMBOL_GENERAL;
121 /* Return true if the current function must save REGNO. */
122 static int
123 score3_save_reg_p (unsigned int regno)
125 /* Check call-saved registers. */
126 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
127 return 1;
129 /* We need to save the old frame pointer before setting up a new one. */
130 if (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed)
131 return 1;
133 /* We need to save the incoming return address if it is ever clobbered
134 within the function. */
135 if (regno == RA_REGNUM && df_regs_ever_live_p (regno))
136 return 1;
138 return 0;
141 /* Return one word of double-word value OP, taking into account the fixed
142 endianness of certain registers. HIGH_P is true to select the high part,
143 false to select the low part. */
144 static rtx
145 score3_subw (rtx op, int high_p)
147 unsigned int byte;
148 enum machine_mode mode = GET_MODE (op);
150 if (mode == VOIDmode)
151 mode = DImode;
153 byte = (TARGET_LITTLE_ENDIAN ? high_p : !high_p) ? UNITS_PER_WORD : 0;
155 if (GET_CODE (op) == REG && REGNO (op) == HI_REGNUM)
156 return gen_rtx_REG (SImode, high_p ? HI_REGNUM : LO_REGNUM);
158 if (GET_CODE (op) == MEM)
159 return adjust_address (op, SImode, byte);
161 return simplify_gen_subreg (SImode, op, mode, byte);
164 static struct score3_frame_info *
165 score3_cached_frame (void)
167 static struct score3_frame_info _frame_info;
168 return &_frame_info;
171 /* Return the bytes needed to compute the frame pointer from the current
172 stack pointer. SIZE is the size (in bytes) of the local variables. */
173 static struct score3_frame_info *
174 score3_compute_frame_size (HOST_WIDE_INT size)
176 unsigned int regno;
177 struct score3_frame_info *f = score3_cached_frame ();
179 memset (f, 0, sizeof (struct score3_frame_info));
180 f->gp_reg_size = 0;
181 f->mask = 0;
182 f->var_size = SCORE3_STACK_ALIGN (size);
183 f->args_size = crtl->outgoing_args_size;
184 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 (score3_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 score3_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 && score3_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 score3_classify_address (struct score3_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 = SCORE3_ADD_REG;
257 info->reg = x;
258 info->offset = const0_rtx;
259 return score3_valid_base_register_p (info->reg, strict);
260 case PLUS:
261 info->type = SCORE3_ADD_REG;
262 info->reg = XEXP (x, 0);
263 info->offset = XEXP (x, 1);
264 return (score3_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 = SCORE3_ADD_REG;
274 info->reg = XEXP (x, 0);
275 info->offset = GEN_INT (GET_MODE_SIZE (mode));
276 return score3_valid_base_register_p (info->reg, strict);
277 case CONST_INT:
278 info->type = SCORE3_ADD_CONST_INT;
279 return 1;
280 case CONST:
281 case LABEL_REF:
282 case SYMBOL_REF:
283 info->type = SCORE3_ADD_SYMBOLIC;
284 return (score3_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 score3_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 score3_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 score3_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 = score3_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_score3 (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 score3_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 score3_split_symbol (rtx temp, rtx addr)
407 rtx high = score3_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 score3_legitimize_address (rtx x)
418 enum score_symbol_type symbol_type;
420 if (score3_symbolic_constant_p (x, &symbol_type)
421 && symbol_type == SYMBOL_GENERAL)
422 return score3_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 (!score3_valid_base_register_p (reg, 0))
429 reg = copy_to_mode_reg (Pmode, reg);
430 return score3_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 score3_classify_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
442 const_tree type, bool named, struct score3_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 score3_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
489 const char *fnname;
490 struct score3_frame_info *f = score3_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 score3_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 score3_symbolic_expression_p (rtx x)
546 if (GET_CODE (x) == SYMBOL_REF)
547 return true;
549 if (GET_CODE (x) == CONST)
550 return score3_symbolic_expression_p (XEXP (x, 0));
552 if (UNARY_P (x))
553 return score3_symbolic_expression_p (XEXP (x, 0));
555 if (ARITHMETIC_P (x))
556 return (score3_symbolic_expression_p (XEXP (x, 0))
557 || score3_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 score3_select_rtx_section (enum machine_mode mode, rtx x,
566 unsigned HOST_WIDE_INT align)
568 if (GET_MODE_SIZE (mode) <= SCORE3_SDATA_MAX)
569 return get_named_section (0, ".sdata", 0);
570 else if (flag_pic && score3_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 score3_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 <= SCORE3_SDATA_MAX);
600 /* Implement TARGET_ASM_FILE_START. */
601 void
602 score3_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 score3_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 score3_option_override (void)
641 flag_pic = false;
642 if (!flag_pic)
643 score3_sdata_max = (global_options_set.x_g_switch_value
644 ? g_switch_value
645 : SCORE3_DEFAULT_SDATA_MAX);
646 else
648 score3_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 score3_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 score3_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 score3_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
722 O simm14
723 P simm5
724 Q uimm32 */
726 score3_const_ok_for_letter_p (HOST_WIDE_INT value, char c)
728 switch (c)
730 case 'I': return ((value & 0xffff) == 0);
731 case 'J': return IMM_IN_RANGE (value, 5, 0);
732 case 'K': return IMM_IN_RANGE (value, 16, 0);
733 case 'L': return IMM_IN_RANGE (value, 16, 1);
734 case 'M': return IMM_IN_RANGE (value, 14, 0);
735 case 'N': return IMM_IN_RANGE (value, 14, 1);
736 case 'O': return IMM_IN_RANGE (value, 5, 1);
737 case 'P': return IMM_IN_RANGE (value, 6, 1);
738 case 'Q': return score_extra_constraint (GEN_INT(value), c);
739 default : return 0;
743 /* Implement EXTRA_CONSTRAINT macro. */
745 Q uimm32
746 Z symbol_ref */
748 score3_extra_constraint (rtx op, char c)
750 switch (c)
752 case 'Q': return IMM_IN_RANGE (INTVAL(op), 32, 0);
753 case 'Z':
754 return GET_CODE (op) == SYMBOL_REF;
755 default:
756 gcc_unreachable ();
760 /* Return truth value on whether or not a given hard register
761 can support a given mode. */
763 score3_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
765 int size = GET_MODE_SIZE (mode);
766 enum mode_class mclass = GET_MODE_CLASS (mode);
768 if (mclass == MODE_CC)
769 return regno == CC_REGNUM;
770 else if (regno == FRAME_POINTER_REGNUM
771 || regno == ARG_POINTER_REGNUM)
772 return mclass == MODE_INT;
773 else if (GP_REG_P (regno))
774 return !(regno & 1) || (size <= UNITS_PER_WORD);
775 else if (CE_REG_P (regno))
776 return (mclass == MODE_INT
777 && ((size <= UNITS_PER_WORD)
778 || (regno == CE_REG_FIRST && size == 2 * UNITS_PER_WORD)));
779 else
780 return (mclass == MODE_INT) && (size <= UNITS_PER_WORD);
783 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
784 pointer or argument pointer. TO is either the stack pointer or
785 hard frame pointer. */
786 HOST_WIDE_INT
787 score3_initial_elimination_offset (int from,
788 int to ATTRIBUTE_UNUSED)
790 struct score3_frame_info *f = score3_compute_frame_size (get_frame_size ());
791 switch (from)
793 case ARG_POINTER_REGNUM:
794 return f->total_size;
795 case FRAME_POINTER_REGNUM:
796 return 0;
797 default:
798 gcc_unreachable ();
802 /* Implement TARGET_FUNCTION_ARG_ADVANCE hook. */
803 void
804 score3_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
805 const_tree type, bool named)
807 struct score3_arg_info info;
808 score3_classify_arg (cum, mode, type, named, &info);
809 cum->num_gprs = info.reg_offset + info.reg_words;
810 if (info.stack_words > 0)
811 cum->stack_words = info.stack_offset + info.stack_words;
812 cum->arg_number++;
815 /* Implement TARGET_ARG_PARTIAL_BYTES macro. */
817 score3_arg_partial_bytes (CUMULATIVE_ARGS *cum,
818 enum machine_mode mode, tree type, bool named)
820 struct score3_arg_info info;
821 score3_classify_arg (cum, mode, type, named, &info);
822 return info.stack_words > 0 ? info.reg_words * UNITS_PER_WORD : 0;
825 /* Implement TARGET_FUNCTION_ARG hook. */
827 score3_function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
828 const_tree type, bool named)
830 struct score3_arg_info info;
832 if (mode == VOIDmode || !named)
833 return 0;
835 score3_classify_arg (cum, mode, type, named, &info);
837 if (info.reg_offset == ARG_REG_NUM)
838 return 0;
840 if (!info.stack_words)
841 return gen_rtx_REG (mode, ARG_REG_FIRST + info.reg_offset);
842 else
844 rtx ret = gen_rtx_PARALLEL (mode, rtvec_alloc (info.reg_words));
845 unsigned int i, part_offset = 0;
846 for (i = 0; i < info.reg_words; i++)
848 rtx reg;
849 reg = gen_rtx_REG (SImode, ARG_REG_FIRST + info.reg_offset + i);
850 XVECEXP (ret, 0, i) = gen_rtx_EXPR_LIST (SImode, reg,
851 GEN_INT (part_offset));
852 part_offset += UNITS_PER_WORD;
854 return ret;
858 /* Implement FUNCTION_VALUE and LIBCALL_VALUE. For normal calls,
859 VALTYPE is the return type and MODE is VOIDmode. For libcalls,
860 VALTYPE is null and MODE is the mode of the return value. */
862 score3_function_value (const_tree valtype, const_tree func,
863 enum machine_mode mode)
865 if (valtype)
867 int unsignedp;
868 mode = TYPE_MODE (valtype);
869 unsignedp = TYPE_UNSIGNED (valtype);
870 mode = promote_function_mode (valtype, mode, &unsignedp, func, 1);
872 return gen_rtx_REG (mode, RT_REGNUM);
875 /* Implement TARGET_ASM_TRAMPOLINE_TEMPLATE. */
877 void
878 score3_asm_trampoline_template (FILE *f)
880 fprintf (f, "\t.set r1\n");
881 fprintf (f, "\tmv! r31, r3\n");
882 fprintf (f, "\tnop!\n");
883 fprintf (f, "\tbl nextinsn\n");
884 fprintf (f, "nextinsn:\n");
885 fprintf (f, "\tlw! r1, [r3, 6*4-8]\n");
886 fprintf (f, "\tnop!\n");
887 fprintf (f, "\tlw r23, [r3, 6*4-4]\n");
888 fprintf (f, "\tmv! r3, r31\n");
889 fprintf (f, "\tnop!\n");
890 fprintf (f, "\tbr! r1\n");
891 fprintf (f, "\tnop!\n");
892 fprintf (f, "\t.set nor1\n");
895 /* Implement TARGET_TRAMPOLINE_INIT. */
896 void
897 score3_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
899 #define FFCACHE "_flush_cache"
900 #define CODE_SIZE (TRAMPOLINE_INSNS * UNITS_PER_WORD)
902 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
903 rtx addr = XEXP (m_tramp, 0);
904 rtx mem;
906 emit_block_move (m_tramp, assemble_trampoline_template (),
907 GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
909 mem = adjust_address (m_tramp, SImode, CODE_SIZE);
910 emit_move_insn (mem, fnaddr);
911 mem = adjust_address (m_tramp, SImode, CODE_SIZE + GET_MODE_SIZE (SImode));
912 emit_move_insn (mem, chain_value);
914 emit_library_call (gen_rtx_SYMBOL_REF (Pmode, FFCACHE),
915 LCT_NORMAL, VOIDmode, 2,
916 addr, Pmode,
917 GEN_INT (TRAMPOLINE_SIZE), SImode);
918 #undef FFCACHE
919 #undef CODE_SIZE
922 /* This function is used to implement REG_MODE_OK_FOR_BASE_P macro. */
924 score3_regno_mode_ok_for_base_p (int regno, int strict)
926 if (regno >= FIRST_PSEUDO_REGISTER)
928 if (!strict)
929 return 1;
930 regno = reg_renumber[regno];
932 if (regno == ARG_POINTER_REGNUM
933 || regno == FRAME_POINTER_REGNUM)
934 return 1;
935 return GP_REG_P (regno);
938 /* Implement TARGET_LEGITIMATE_ADDRESS_P macro. */
939 bool
940 score3_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
942 struct score3_address_info addr;
944 return score3_classify_address (&addr, mode, x, strict);
947 /* Return a number assessing the cost of moving a register in class
948 FROM to class TO. */
950 score3_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
951 enum reg_class from, enum reg_class to)
953 if (GR_REG_CLASS_P (from))
955 if (GR_REG_CLASS_P (to))
956 return 2;
957 else if (SP_REG_CLASS_P (to))
958 return 4;
959 else if (CP_REG_CLASS_P (to))
960 return 5;
961 else if (CE_REG_CLASS_P (to))
962 return 6;
964 if (GR_REG_CLASS_P (to))
966 if (GR_REG_CLASS_P (from))
967 return 2;
968 else if (SP_REG_CLASS_P (from))
969 return 4;
970 else if (CP_REG_CLASS_P (from))
971 return 5;
972 else if (CE_REG_CLASS_P (from))
973 return 6;
975 return 12;
978 /* Return the number of instructions needed to load a symbol of the
979 given type into a register. */
980 static int
981 score3_symbol_insns (enum score_symbol_type type)
983 switch (type)
985 case SYMBOL_GENERAL:
986 return 2;
988 case SYMBOL_SMALL_DATA:
989 return 1;
992 gcc_unreachable ();
995 /* Return the number of instructions needed to load or store a value
996 of mode MODE at X. Return 0 if X isn't valid for MODE. */
997 static int
998 score3_address_insns (rtx x, enum machine_mode mode)
1000 struct score3_address_info addr;
1001 int factor;
1003 if (mode == BLKmode)
1004 factor = 1;
1005 else
1006 factor = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
1008 if (score3_classify_address (&addr, mode, x, false))
1009 switch (addr.type)
1011 case SCORE3_ADD_REG:
1012 case SCORE3_ADD_CONST_INT:
1013 return factor;
1015 case SCORE3_ADD_SYMBOLIC:
1016 return factor * score3_symbol_insns (addr.symbol_type);
1018 return 0;
1021 /* Implement TARGET_RTX_COSTS macro. */
1022 bool
1023 score3_rtx_costs (rtx x, int code, int outer_code, int *total,
1024 bool speed ATTRIBUTE_UNUSED)
1026 enum machine_mode mode = GET_MODE (x);
1028 switch (code)
1030 case CONST_INT:
1031 if (outer_code == SET)
1033 if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
1034 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L'))
1035 *total = COSTS_N_INSNS (1);
1036 else
1037 *total = COSTS_N_INSNS (2);
1039 else if (outer_code == PLUS || outer_code == MINUS)
1041 if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'N'))
1042 *total = 0;
1043 else if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
1044 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L'))
1045 *total = 1;
1046 else
1047 *total = COSTS_N_INSNS (2);
1049 else if (outer_code == AND || outer_code == IOR)
1051 if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'M'))
1052 *total = 0;
1053 else if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
1054 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'K'))
1055 *total = 1;
1056 else
1057 *total = COSTS_N_INSNS (2);
1059 else
1061 *total = 0;
1063 return true;
1065 case CONST:
1066 case SYMBOL_REF:
1067 case LABEL_REF:
1068 case CONST_DOUBLE:
1069 *total = COSTS_N_INSNS (2);
1070 return true;
1072 case MEM:
1074 /* If the address is legitimate, return the number of
1075 instructions it needs, otherwise use the default handling. */
1076 int n = score3_address_insns (XEXP (x, 0), GET_MODE (x));
1077 if (n > 0)
1079 *total = COSTS_N_INSNS (n + 1);
1080 return true;
1082 return false;
1085 case FFS:
1086 *total = COSTS_N_INSNS (6);
1087 return true;
1089 case NOT:
1090 *total = COSTS_N_INSNS (1);
1091 return true;
1093 case AND:
1094 case IOR:
1095 case XOR:
1096 if (mode == DImode)
1098 *total = COSTS_N_INSNS (2);
1099 return true;
1101 return false;
1103 case ASHIFT:
1104 case ASHIFTRT:
1105 case LSHIFTRT:
1106 if (mode == DImode)
1108 *total = COSTS_N_INSNS ((GET_CODE (XEXP (x, 1)) == CONST_INT)
1109 ? 4 : 12);
1110 return true;
1112 return false;
1114 case ABS:
1115 *total = COSTS_N_INSNS (4);
1116 return true;
1118 case PLUS:
1119 case MINUS:
1120 if (mode == DImode)
1122 *total = COSTS_N_INSNS (4);
1123 return true;
1125 *total = COSTS_N_INSNS (1);
1126 return true;
1128 case NEG:
1129 if (mode == DImode)
1131 *total = COSTS_N_INSNS (4);
1132 return true;
1134 return false;
1136 case MULT:
1137 *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (12);
1138 return true;
1140 case DIV:
1141 case MOD:
1142 case UDIV:
1143 case UMOD:
1144 *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (33);
1145 return true;
1147 case SIGN_EXTEND:
1148 case ZERO_EXTEND:
1149 switch (GET_MODE (XEXP (x, 0)))
1151 case QImode:
1152 case HImode:
1153 if (GET_CODE (XEXP (x, 0)) == MEM)
1155 *total = COSTS_N_INSNS (2);
1157 if (!TARGET_LITTLE_ENDIAN &&
1158 side_effects_p (XEXP (XEXP (x, 0), 0)))
1159 *total = 100;
1161 else
1162 *total = COSTS_N_INSNS (1);
1163 break;
1165 default:
1166 *total = COSTS_N_INSNS (1);
1167 break;
1169 return true;
1171 default:
1172 return false;
1176 /* Implement TARGET_ADDRESS_COST macro. */
1178 score3_address_cost (rtx addr)
1180 return score3_address_insns (addr, SImode);
1183 /* Implement ASM_OUTPUT_EXTERNAL macro. */
1185 score3_output_external (FILE *file ATTRIBUTE_UNUSED,
1186 tree decl, const char *name)
1188 register struct extern_list *p;
1190 if (score3_in_small_data_p (decl))
1192 p = ggc_alloc_extern_list ();
1193 p->next = extern_head;
1194 p->name = name;
1195 p->size = int_size_in_bytes (TREE_TYPE (decl));
1196 extern_head = p;
1198 return 0;
1201 /* Implement RETURN_ADDR_RTX. Note, we do not support moving
1202 back to a previous frame. */
1204 score3_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
1206 if (count != 0)
1207 return const0_rtx;
1208 return get_hard_reg_initial_val (Pmode, RA_REGNUM);
1211 /* Implement PRINT_OPERAND macro. */
1212 /* Score-specific operand codes:
1213 '[' print .set nor1 directive
1214 ']' print .set r1 directive
1215 'U' print hi part of a CONST_INT rtx
1216 'E' print log2(v)
1217 'F' print log2(~v)
1218 'D' print SFmode const double
1219 'S' selectively print "!" if operand is 15bit instruction accessible
1220 'V' print "v!" if operand is 15bit instruction accessible, or "lfh!"
1221 'L' low part of DImode reg operand
1222 'H' high part of DImode reg operand
1223 'C' print part of opcode for a branch condition. */
1224 void
1225 score3_print_operand (FILE *file, rtx op, int c)
1227 enum rtx_code code = UNKNOWN;
1228 if (!PRINT_OPERAND_PUNCT_VALID_P (c))
1229 code = GET_CODE (op);
1231 if (c == '[')
1233 fprintf (file, ".set r1\n");
1235 else if (c == ']')
1237 fprintf (file, "\n\t.set nor1");
1239 else if (c == 'U')
1241 gcc_assert (code == CONST_INT);
1242 fprintf (file, HOST_WIDE_INT_PRINT_HEX,
1243 (INTVAL (op) >> 16) & 0xffff);
1245 else if (c == 'D')
1247 if (GET_CODE (op) == CONST_DOUBLE)
1249 rtx temp = gen_lowpart (SImode, op);
1250 gcc_assert (GET_MODE (op) == SFmode);
1251 fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (temp) & 0xffffffff);
1253 else
1254 output_addr_const (file, op);
1256 else if (c == 'S')
1258 gcc_assert (code == REG);
1259 if (G16_REG_P (REGNO (op)))
1260 fprintf (file, "!");
1262 else if (c == 'V')
1264 gcc_assert (code == REG);
1265 fprintf (file, G16_REG_P (REGNO (op)) ? "v!" : "lfh!");
1267 else if (c == 'C')
1269 enum machine_mode mode = GET_MODE (XEXP (op, 0));
1271 switch (code)
1273 case EQ: fputs ("eq!", file); break;
1274 case NE: fputs ("ne!", file); break;
1275 case GT: fputs ("gt!", file); break;
1276 case GE: fputs (mode != CCmode ? "pl" : "ge", file); break;
1277 case LT: fputs (mode != CCmode ? "mi" : "lt", file); break;
1278 case LE: fputs ("le!", file); break;
1279 case GTU: fputs ("gtu!", file); break;
1280 case GEU: fputs ("cs", file); break;
1281 case LTU: fputs ("cc", file); break;
1282 case LEU: fputs ("leu!", file); break;
1283 default:
1284 output_operand_lossage ("invalid operand for code: '%c'", code);
1287 else if (c == 'G') /* Seperate from b<cond>, use for mv<cond>. */
1289 enum machine_mode mode = GET_MODE (XEXP (op, 0));
1291 switch (code)
1293 case EQ: fputs ("eq", file); break;
1294 case NE: fputs ("ne", file); break;
1295 case GT: fputs ("gt", file); break;
1296 case GE: fputs (mode != CCmode ? "pl" : "ge", file); break;
1297 case LT: fputs (mode != CCmode ? "mi" : "lt", file); break;
1298 case LE: fputs ("le", file); break;
1299 case GTU: fputs ("gtu", file); break;
1300 case GEU: fputs ("cs", file); break;
1301 case LTU: fputs ("cc", file); break;
1302 case LEU: fputs ("leu", file); break;
1303 default:
1304 output_operand_lossage ("invalid operand for code: '%c'", code);
1307 else if (c == 'E')
1309 unsigned HOST_WIDE_INT i;
1310 unsigned HOST_WIDE_INT pow2mask = 1;
1311 unsigned HOST_WIDE_INT val;
1313 val = INTVAL (op);
1314 for (i = 0; i < 32; i++)
1316 if (val == pow2mask)
1317 break;
1318 pow2mask <<= 1;
1320 gcc_assert (i < 32);
1321 fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
1323 else if (c == 'F')
1325 unsigned HOST_WIDE_INT i;
1326 unsigned HOST_WIDE_INT pow2mask = 1;
1327 unsigned HOST_WIDE_INT val;
1329 val = ~INTVAL (op);
1330 for (i = 0; i < 32; i++)
1332 if (val == pow2mask)
1333 break;
1334 pow2mask <<= 1;
1336 gcc_assert (i < 32);
1337 fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
1339 else if (code == REG)
1341 int regnum = REGNO (op);
1342 if ((c == 'H' && !WORDS_BIG_ENDIAN)
1343 || (c == 'L' && WORDS_BIG_ENDIAN))
1344 regnum ++;
1345 fprintf (file, "%s", reg_names[regnum]);
1347 else
1349 switch (code)
1351 case MEM:
1352 score3_print_operand_address (file, op);
1353 break;
1354 default:
1355 output_addr_const (file, op);
1360 /* Implement PRINT_OPERAND_ADDRESS macro. */
1361 void
1362 score3_print_operand_address (FILE *file, rtx x)
1364 struct score3_address_info addr;
1365 enum rtx_code code = GET_CODE (x);
1366 enum machine_mode mode = GET_MODE (x);
1368 if (code == MEM)
1369 x = XEXP (x, 0);
1371 if (score3_classify_address (&addr, mode, x, true))
1373 switch (addr.type)
1375 case SCORE3_ADD_REG:
1377 switch (addr.code)
1379 case PRE_DEC:
1380 fprintf (file, "[%s,-%ld]+", reg_names[REGNO (addr.reg)],
1381 INTVAL (addr.offset));
1382 break;
1383 case POST_DEC:
1384 fprintf (file, "[%s]+,-%ld", reg_names[REGNO (addr.reg)],
1385 INTVAL (addr.offset));
1386 break;
1387 case PRE_INC:
1388 fprintf (file, "[%s, %ld]+", reg_names[REGNO (addr.reg)],
1389 INTVAL (addr.offset));
1390 break;
1391 case POST_INC:
1392 fprintf (file, "[%s]+, %ld", reg_names[REGNO (addr.reg)],
1393 INTVAL (addr.offset));
1394 break;
1395 default:
1396 if (INTVAL(addr.offset) == 0)
1397 fprintf(file, "[%s]", reg_names[REGNO (addr.reg)]);
1398 else
1399 fprintf(file, "[%s, %ld]", reg_names[REGNO (addr.reg)],
1400 INTVAL(addr.offset));
1401 break;
1404 return;
1405 case SCORE3_ADD_CONST_INT:
1406 case SCORE3_ADD_SYMBOLIC:
1407 output_addr_const (file, x);
1408 return;
1411 print_rtl (stderr, x);
1412 gcc_unreachable ();
1415 /* Implement SELECT_CC_MODE macro. */
1416 enum machine_mode
1417 score3_select_cc_mode (enum rtx_code op, rtx x, rtx y)
1419 if ((op == EQ || op == NE || op == LT || op == GE)
1420 && y == const0_rtx
1421 && GET_MODE (x) == SImode)
1423 switch (GET_CODE (x))
1425 case PLUS:
1426 case MINUS:
1427 case NEG:
1428 case AND:
1429 case IOR:
1430 case XOR:
1431 case NOT:
1432 case ASHIFT:
1433 case LSHIFTRT:
1434 case ASHIFTRT:
1435 return CC_NZmode;
1437 case SIGN_EXTEND:
1438 case ZERO_EXTEND:
1439 case ROTATE:
1440 case ROTATERT:
1441 return (op == LT || op == GE) ? CC_Nmode : CCmode;
1443 default:
1444 return CCmode;
1448 if ((op == EQ || op == NE)
1449 && (GET_CODE (y) == NEG)
1450 && register_operand (XEXP (y, 0), SImode)
1451 && register_operand (x, SImode))
1453 return CC_NZmode;
1456 return CCmode;
1459 #define EMIT_PL(_rtx) RTX_FRAME_RELATED_P (_rtx) = 1
1460 /* return 0, no more bit set in mask. */
1461 static int rpush_first (int mask, int sb, int *rd)
1463 int i, cnt = 1;
1465 if ((mask & (1 << sb)) == 0)
1466 return 0;
1468 *rd = sb;
1470 for (i = sb-1; i >= 0; i--)
1472 if (mask & (1 << i))
1474 cnt ++;
1475 continue;
1478 *rd = i+1;
1479 break;;
1482 return cnt;
1485 static void
1486 rpush (int rd, int cnt)
1488 rtx mem = gen_rtx_MEM (SImode, gen_rtx_PRE_DEC (SImode, stack_pointer_rtx));
1489 rtx reg = gen_rtx_REG (SImode, rd);
1491 if (!crtl->calls_eh_return)
1492 MEM_READONLY_P (mem) = 1;
1494 if (cnt == 1)
1495 EMIT_PL (emit_insn (gen_pushsi_score3 (mem, reg)));
1496 else
1498 int i;
1499 rtx insn = gen_store_multiple (gen_rtx_MEM (SImode, stack_pointer_rtx),
1500 gen_rtx_REG (SImode, rd),
1501 GEN_INT (cnt));
1503 rtx pat = PATTERN (insn);
1505 for (i = 0; i < XVECLEN (pat, 0); i++)
1506 if (GET_CODE (XVECEXP (pat, 0, i)) == SET)
1507 RTX_FRAME_RELATED_P (XVECEXP (pat, 0, i)) = 1;
1509 EMIT_PL (emit_insn (insn));
1513 /* Generate the prologue instructions for entry into a S+core function. */
1514 void
1515 score3_prologue (void)
1517 struct score3_frame_info *f = score3_compute_frame_size (get_frame_size ());
1518 HOST_WIDE_INT size;
1519 int regno;
1521 size = f->total_size - f->gp_reg_size;
1523 if (flag_pic)
1524 emit_insn (gen_cpload_score3 ());
1527 int cnt, rd;
1529 for (regno = (int) GP_REG_LAST; regno >= (int) GP_REG_FIRST; regno--)
1531 cnt = rpush_first (f->mask, regno, &rd);
1532 if (cnt != 0)
1534 rpush (rd, cnt);
1535 regno = regno - cnt;
1540 if (size > 0)
1542 rtx insn;
1544 if (CONST_OK_FOR_LETTER_P (-size, 'L'))
1545 EMIT_PL (emit_insn (gen_add3_insn (stack_pointer_rtx,
1546 stack_pointer_rtx,
1547 GEN_INT (-size))));
1548 else
1550 EMIT_PL (emit_move_insn (gen_rtx_REG (Pmode, SCORE3_PROLOGUE_TEMP_REGNUM),
1551 GEN_INT (size)));
1552 EMIT_PL (emit_insn
1553 (gen_sub3_insn (stack_pointer_rtx,
1554 stack_pointer_rtx,
1555 gen_rtx_REG (Pmode,
1556 SCORE3_PROLOGUE_TEMP_REGNUM))));
1558 insn = get_last_insn ();
1559 REG_NOTES (insn) =
1560 alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR,
1561 gen_rtx_SET (VOIDmode, stack_pointer_rtx,
1562 plus_constant (stack_pointer_rtx,
1563 -size)),
1564 REG_NOTES (insn));
1567 if (frame_pointer_needed)
1568 EMIT_PL (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx));
1570 if (flag_pic && f->cprestore_size)
1572 if (frame_pointer_needed)
1573 emit_insn (gen_cprestore_use_fp_score3 (GEN_INT (size - f->cprestore_size)));
1574 else
1575 emit_insn (gen_cprestore_use_sp_score3 (GEN_INT (size - f->cprestore_size)));
1579 /* return 0, no more bit set in mask. */
1580 static int
1581 rpop_first (int mask, int sb, int *rd)
1583 int i, cnt = 1;
1585 if ((mask & (1 << sb)) == 0)
1586 return 0;
1588 *rd = sb;
1590 for (i = sb+1; i < 32; i++)
1591 if (mask & (1 << i))
1592 cnt++;
1593 else
1594 break;;
1596 return cnt;
1599 static void
1600 rpop (int rd, int cnt)
1602 rtx mem = gen_rtx_MEM (SImode, gen_rtx_POST_INC (SImode, stack_pointer_rtx));
1603 rtx reg = gen_rtx_REG (SImode, rd);
1605 if (!crtl->calls_eh_return)
1606 MEM_READONLY_P (mem) = 1;
1608 if (cnt == 1)
1609 emit_insn (gen_popsi_score3 (reg, mem));
1610 else
1611 emit_insn (gen_load_multiple (reg,
1612 gen_rtx_MEM (SImode, stack_pointer_rtx),
1613 GEN_INT (cnt)));
1616 /* Generate the epilogue instructions in a S+core function. */
1617 void
1618 score3_epilogue (int sibcall_p)
1620 struct score3_frame_info *f = score3_compute_frame_size (get_frame_size ());
1621 HOST_WIDE_INT size;
1622 int regno;
1623 rtx base;
1625 size = f->total_size - f->gp_reg_size;
1627 if (!frame_pointer_needed)
1628 base = stack_pointer_rtx;
1629 else
1630 base = hard_frame_pointer_rtx;
1632 if (size)
1634 if (CONST_OK_FOR_LETTER_P (size, 'L'))
1635 emit_insn (gen_add3_insn (base, base, GEN_INT (size)));
1636 else
1638 emit_move_insn (gen_rtx_REG (Pmode, SCORE3_EPILOGUE_TEMP_REGNUM),
1639 GEN_INT (size));
1640 emit_insn (gen_add3_insn (base, base,
1641 gen_rtx_REG (Pmode,
1642 SCORE3_EPILOGUE_TEMP_REGNUM)));
1646 if (base != stack_pointer_rtx)
1647 emit_move_insn (stack_pointer_rtx, base);
1649 if (crtl->calls_eh_return)
1650 emit_insn (gen_add3_insn (stack_pointer_rtx,
1651 stack_pointer_rtx,
1652 EH_RETURN_STACKADJ_RTX));
1655 int cnt, rd;
1657 for (regno = (int) GP_REG_FIRST; regno <= (int) GP_REG_LAST; regno++)
1659 cnt = rpop_first (f->mask, regno, &rd);
1660 if (cnt != 0)
1662 rpop (rd, cnt);
1663 regno = regno + cnt;
1668 if (!sibcall_p)
1669 emit_jump_insn (gen_return_internal_score3 (gen_rtx_REG (Pmode, RA_REGNUM)));
1672 /* Return true if X is a symbolic constant that can be calculated in
1673 the same way as a bare symbol. If it is, store the type of the
1674 symbol in *SYMBOL_TYPE. */
1676 score3_symbolic_constant_p (rtx x, enum score_symbol_type *symbol_type)
1678 HOST_WIDE_INT offset;
1680 score3_split_const (x, &x, &offset);
1681 if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF)
1682 *symbol_type = score3_classify_symbol (x);
1683 else
1684 return 0;
1686 if (offset == 0)
1687 return 1;
1689 /* if offset > 15bit, must reload */
1690 if (!IMM_IN_RANGE (offset, 15, 1))
1691 return 0;
1693 switch (*symbol_type)
1695 case SYMBOL_GENERAL:
1696 return 1;
1697 case SYMBOL_SMALL_DATA:
1698 return score3_offset_within_object_p (x, offset);
1700 gcc_unreachable ();
1703 void
1704 score3_movsicc (rtx *ops)
1706 enum machine_mode mode;
1708 mode = score3_select_cc_mode (GET_CODE (ops[1]), ops[2], ops[3]);
1709 emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (mode, CC_REGNUM),
1710 gen_rtx_COMPARE (mode, XEXP (ops[1], 0),
1711 XEXP (ops[1], 1))));
1714 /* Call and sibcall pattern all need call this function. */
1715 void
1716 score3_call (rtx *ops, bool sib)
1718 rtx addr = XEXP (ops[0], 0);
1719 if (!call_insn_operand (addr, VOIDmode))
1721 rtx oaddr = addr;
1722 addr = gen_reg_rtx (Pmode);
1723 gen_move_insn (addr, oaddr);
1726 if (sib)
1727 emit_call_insn (gen_sibcall_internal_score3 (addr, ops[1]));
1728 else
1729 emit_call_insn (gen_call_internal_score3 (addr, ops[1]));
1732 /* Call value and sibcall value pattern all need call this function. */
1733 void
1734 score3_call_value (rtx *ops, bool sib)
1736 rtx result = ops[0];
1737 rtx addr = XEXP (ops[1], 0);
1738 rtx arg = ops[2];
1740 if (!call_insn_operand (addr, VOIDmode))
1742 rtx oaddr = addr;
1743 addr = gen_reg_rtx (Pmode);
1744 gen_move_insn (addr, oaddr);
1747 if (sib)
1748 emit_call_insn (gen_sibcall_value_internal_score3 (result, addr, arg));
1749 else
1750 emit_call_insn (gen_call_value_internal_score3 (result, addr, arg));
1753 /* Machine Split */
1754 void
1755 score3_movdi (rtx *ops)
1757 rtx dst = ops[0];
1758 rtx src = ops[1];
1759 rtx dst0 = score3_subw (dst, 0);
1760 rtx dst1 = score3_subw (dst, 1);
1761 rtx src0 = score3_subw (src, 0);
1762 rtx src1 = score3_subw (src, 1);
1764 if (GET_CODE (dst0) == REG && reg_overlap_mentioned_p (dst0, src))
1766 emit_move_insn (dst1, src1);
1767 emit_move_insn (dst0, src0);
1769 else
1771 emit_move_insn (dst0, src0);
1772 emit_move_insn (dst1, src1);
1776 void
1777 score3_zero_extract_andi (rtx *ops)
1779 if (INTVAL (ops[1]) == 1 && const_uimm5 (ops[2], SImode))
1780 emit_insn (gen_zero_extract_bittst_score3 (ops[0], ops[2]));
1781 else
1783 unsigned HOST_WIDE_INT mask;
1784 mask = (0xffffffffU & ((1U << INTVAL (ops[1])) - 1U));
1785 mask = mask << INTVAL (ops[2]);
1786 emit_insn (gen_andsi3_cmp_score3 (ops[3], ops[0],
1787 gen_int_mode (mask, SImode)));
1791 const char *
1792 score3_rpush (rtx *ops)
1794 snprintf (score3_ins, INS_BUF_SZ, "rpush!\t%%1, %d", XVECLEN (ops[0], 0));
1795 return score3_ins;
1798 const char *
1799 score3_rpop (rtx *ops)
1801 snprintf (score3_ins, INS_BUF_SZ, "rpop!\t%%1, %d", XVECLEN (ops[0], 0));
1802 return score3_ins;
1805 /* Output asm code for ld/sw insn. */
1806 static int
1807 score3_pr_addr_post (rtx *ops, int idata, int iaddr, char *ip,
1808 enum score_mem_unit unit ATTRIBUTE_UNUSED)
1810 struct score3_address_info ai;
1812 gcc_assert (GET_CODE (ops[idata]) == REG);
1813 gcc_assert (score3_classify_address (&ai, SImode, XEXP (ops[iaddr], 0), true));
1815 if (ai.type == SCORE3_ADD_REG
1816 && ai.code == REG
1817 && GET_CODE (ai.offset) == CONST_INT
1818 && G16_REG_P (REGNO (ops[idata]))
1819 && G8_REG_P (REGNO (ai.reg))
1820 && ((INTVAL (ai.offset) & 3) == 0)
1821 && (IMM_IN_RANGE (INTVAL (ai.offset), 7, 0)))
1823 ops[iaddr] = ai.reg;
1824 return snprintf (ip, INS_BUF_SZ, "!\t%%%d, [%%%d, "
1825 HOST_WIDE_INT_PRINT_DEC "]",
1826 idata, iaddr, INTVAL (ai.offset));
1829 if (ai.type == SCORE3_ADD_SYMBOLIC)
1830 return snprintf (ip, INS_BUF_SZ, "48\t%%%d, %%a%d", idata, iaddr);
1832 return snprintf (ip, INS_BUF_SZ, "\t%%%d, %%a%d", idata, iaddr);
1835 /* Output asm insn for load. */
1836 const char *
1837 score3_linsn (rtx *ops, enum score_mem_unit unit, bool sign)
1839 const char *pre_ins[] =
1840 {"lbu", "lhu", "lw", "??", "lb", "lh", "lw", "??"};
1841 char *ip;
1843 strcpy (score3_ins, pre_ins[(sign ? 4 : 0) + unit]);
1844 ip = score3_ins + strlen (score3_ins);
1846 if (unit == SCORE_WORD)
1847 score3_pr_addr_post (ops, 0, 1, ip, unit);
1848 else
1849 snprintf (ip, INS_BUF_SZ, "\t%%0, %%a1");
1851 return score3_ins;
1854 /* Output asm insn for store. */
1855 const char *
1856 score3_sinsn (rtx *ops, enum score_mem_unit unit)
1858 const char *pre_ins[] = {"sb", "sh", "sw"};
1859 char *ip;
1861 strcpy (score3_ins, pre_ins[unit]);
1862 ip = score3_ins + strlen (score3_ins);
1864 if (unit == SCORE_WORD)
1865 score3_pr_addr_post (ops, 1, 0, ip, unit);
1866 else
1867 snprintf (ip, INS_BUF_SZ, "\t%%1, %%a0");
1869 return score3_ins;
1872 /* Output asm insn for load immediate. */
1873 const char *
1874 score3_limm (rtx *ops)
1876 HOST_WIDE_INT v;
1878 gcc_assert (GET_CODE (ops[0]) == REG);
1879 gcc_assert (GET_CODE (ops[1]) == CONST_INT);
1881 v = INTVAL (ops[1]);
1882 if (G16_REG_P (REGNO (ops[0])) && IMM_IN_RANGE (v, 5, 0))
1883 return "ldiu!\t%0, %c1";
1884 else if (IMM_IN_RANGE (v, 16, 1))
1885 return "ldi\t%0, %c1";
1886 else if ((v & 0xffff) == 0)
1887 return "ldis\t%0, %U1";
1888 else
1889 return "li\t%0, %c1";
1892 /* Output asm insn for move. */
1893 const char *
1894 score3_move (rtx *ops)
1896 gcc_assert (GET_CODE (ops[0]) == REG);
1897 gcc_assert (GET_CODE (ops[1]) == REG);
1899 return "mv!\t%0, %1";
1902 /* Generate add insn. */
1903 const char *
1904 score3_select_add_imm (rtx *ops, bool set_cc)
1906 HOST_WIDE_INT v = INTVAL (ops[2]);
1908 gcc_assert (GET_CODE (ops[2]) == CONST_INT);
1909 gcc_assert (REGNO (ops[0]) == REGNO (ops[1]));
1911 if (set_cc)
1912 return "addi.c\t%0, %c2";
1913 else
1914 if (IMM_IN_RANGE (v, 6, 1) && G16_REG_P (REGNO (ops[0])))
1915 return "addi!\t%0, %c2";
1916 else
1917 return "addi\t%0, %c2";
1920 /* Output arith insn. */
1921 const char *
1922 score3_select (rtx *ops, const char *inst_pre, bool commu ATTRIBUTE_UNUSED,
1923 const char *letter, bool set_cc)
1925 gcc_assert (GET_CODE (ops[0]) == REG);
1926 gcc_assert (GET_CODE (ops[1]) == REG);
1928 if (set_cc)
1929 snprintf (score3_ins, INS_BUF_SZ, "%s.c\t%%0, %%1, %%%s2", inst_pre, letter);
1930 else
1931 snprintf (score3_ins, INS_BUF_SZ, "%s\t%%0, %%1, %%%s2", inst_pre, letter);
1932 return score3_ins;
1935 /* Output a Score3 casesi instruction. */
1936 const char *
1937 score3_output_casesi (rtx *operands)
1939 rtx diff_vec = PATTERN (next_real_insn (operands[2]));
1940 gcc_assert (GET_CODE (diff_vec) == ADDR_DIFF_VEC);
1942 output_asm_insn ("cmpi.c\t%0, %1", operands);
1943 output_asm_insn ("bgtu\t%3", operands);
1944 switch (GET_MODE(diff_vec))
1946 case QImode:
1947 output_asm_insn ("ldi48\t%4, %2", operands);
1948 output_asm_insn ("ltbb\t%4, [%4, %0]\n%2_tbb:", operands);
1949 return "brr!\t%4";
1950 case HImode:
1951 output_asm_insn ("ldi48\t%4, %2", operands);
1952 output_asm_insn ("ltbh\t%4, [%4, %0]\n%2_tbb:", operands);
1953 return "brr!\t%4";
1954 case SImode:
1955 output_asm_insn ("ldi48\t%4, %2", operands);
1956 output_asm_insn ("ltbw\t%4, [%4, %0]", operands);
1957 return "br!\t%4";
1958 default:
1959 gcc_unreachable ();