Merged trunk at revision 161680 into branch.
[official-gcc.git] / gcc / config / score / score3.c
blob3e20f16dc33de478cb149ab3c06667708ff9e7fb
1 /* score3.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 "insn-config.h"
29 #include "conditions.h"
30 #include "insn-attr.h"
31 #include "recog.h"
32 #include "toplev.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 (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 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 tree type, int 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 (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 OVERRIDE_OPTIONS macro. */
638 void
639 score3_override_options (void)
641 flag_pic = false;
642 if (!flag_pic)
643 score3_sdata_max = g_switch_set ? g_switch_value : SCORE3_DEFAULT_SDATA_MAX;
644 else
646 score3_sdata_max = 0;
647 if (g_switch_set && (g_switch_value != 0))
648 warning (0, "-fPIC and -G are incompatible");
651 score_char_to_class['d'] = G32_REGS;
652 score_char_to_class['e'] = G16_REGS;
653 score_char_to_class['t'] = T32_REGS;
655 score_char_to_class['h'] = HI_REG;
656 score_char_to_class['l'] = LO_REG;
657 score_char_to_class['x'] = CE_REGS;
659 score_char_to_class['q'] = CN_REG;
660 score_char_to_class['y'] = LC_REG;
661 score_char_to_class['z'] = SC_REG;
662 score_char_to_class['a'] = SP_REGS;
664 score_char_to_class['c'] = CR_REGS;
667 /* Implement REGNO_REG_CLASS macro. */
669 score3_reg_class (int regno)
671 int c;
672 gcc_assert (regno >= 0 && regno < FIRST_PSEUDO_REGISTER);
674 if (regno == FRAME_POINTER_REGNUM
675 || regno == ARG_POINTER_REGNUM)
676 return ALL_REGS;
678 for (c = 0; c < N_REG_CLASSES; c++)
679 if (TEST_HARD_REG_BIT (reg_class_contents[c], regno))
680 return c;
682 return NO_REGS;
685 /* Implement PREFERRED_RELOAD_CLASS macro. */
686 enum reg_class
687 score3_preferred_reload_class (rtx x ATTRIBUTE_UNUSED, enum reg_class rclass)
689 if (reg_class_subset_p (G16_REGS, rclass))
690 return G16_REGS;
691 if (reg_class_subset_p (G32_REGS, rclass))
692 return G32_REGS;
693 return rclass;
696 /* Implement SECONDARY_INPUT_RELOAD_CLASS
697 and SECONDARY_OUTPUT_RELOAD_CLASS macro. */
698 enum reg_class
699 score3_secondary_reload_class (enum reg_class rclass,
700 enum machine_mode mode ATTRIBUTE_UNUSED,
701 rtx x)
703 int regno = -1;
704 if (GET_CODE (x) == REG || GET_CODE(x) == SUBREG)
705 regno = true_regnum (x);
707 if (!GR_REG_CLASS_P (rclass))
708 return GP_REG_P (regno) ? NO_REGS : G32_REGS;
709 return NO_REGS;
712 /* Implement CONST_OK_FOR_LETTER_P macro. */
713 /* imm constraints
714 I imm16 << 16
715 J uimm5
716 K uimm16
717 L simm16
718 M uimm14
719 N simm14
720 O simm14
721 P simm5
722 Q uimm32 */
724 score3_const_ok_for_letter_p (HOST_WIDE_INT value, char c)
726 switch (c)
728 case 'I': return ((value & 0xffff) == 0);
729 case 'J': return IMM_IN_RANGE (value, 5, 0);
730 case 'K': return IMM_IN_RANGE (value, 16, 0);
731 case 'L': return IMM_IN_RANGE (value, 16, 1);
732 case 'M': return IMM_IN_RANGE (value, 14, 0);
733 case 'N': return IMM_IN_RANGE (value, 14, 1);
734 case 'O': return IMM_IN_RANGE (value, 5, 1);
735 case 'P': return IMM_IN_RANGE (value, 6, 1);
736 case 'Q': return score_extra_constraint (GEN_INT(value), c);
737 default : return 0;
741 /* Implement EXTRA_CONSTRAINT macro. */
743 Q uimm32
744 Z symbol_ref */
746 score3_extra_constraint (rtx op, char c)
748 switch (c)
750 case 'Q': return IMM_IN_RANGE (INTVAL(op), 32, 0);
751 case 'Z':
752 return GET_CODE (op) == SYMBOL_REF;
753 default:
754 gcc_unreachable ();
758 /* Return truth value on whether or not a given hard register
759 can support a given mode. */
761 score3_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
763 int size = GET_MODE_SIZE (mode);
764 enum mode_class mclass = GET_MODE_CLASS (mode);
766 if (mclass == MODE_CC)
767 return regno == CC_REGNUM;
768 else if (regno == FRAME_POINTER_REGNUM
769 || regno == ARG_POINTER_REGNUM)
770 return mclass == MODE_INT;
771 else if (GP_REG_P (regno))
772 return !(regno & 1) || (size <= UNITS_PER_WORD);
773 else if (CE_REG_P (regno))
774 return (mclass == MODE_INT
775 && ((size <= UNITS_PER_WORD)
776 || (regno == CE_REG_FIRST && size == 2 * UNITS_PER_WORD)));
777 else
778 return (mclass == MODE_INT) && (size <= UNITS_PER_WORD);
781 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
782 pointer or argument pointer. TO is either the stack pointer or
783 hard frame pointer. */
784 HOST_WIDE_INT
785 score3_initial_elimination_offset (int from,
786 int to ATTRIBUTE_UNUSED)
788 struct score3_frame_info *f = score3_compute_frame_size (get_frame_size ());
789 switch (from)
791 case ARG_POINTER_REGNUM:
792 return f->total_size;
793 case FRAME_POINTER_REGNUM:
794 return 0;
795 default:
796 gcc_unreachable ();
800 /* Implement FUNCTION_ARG_ADVANCE macro. */
801 void
802 score3_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
803 tree type, int named)
805 struct score3_arg_info info;
806 score3_classify_arg (cum, mode, type, named, &info);
807 cum->num_gprs = info.reg_offset + info.reg_words;
808 if (info.stack_words > 0)
809 cum->stack_words = info.stack_offset + info.stack_words;
810 cum->arg_number++;
813 /* Implement TARGET_ARG_PARTIAL_BYTES macro. */
815 score3_arg_partial_bytes (CUMULATIVE_ARGS *cum,
816 enum machine_mode mode, tree type, bool named)
818 struct score3_arg_info info;
819 score3_classify_arg (cum, mode, type, named, &info);
820 return info.stack_words > 0 ? info.reg_words * UNITS_PER_WORD : 0;
823 /* Implement FUNCTION_ARG macro. */
825 score3_function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
826 tree type, int named)
828 struct score3_arg_info info;
830 if (mode == VOIDmode || !named)
831 return 0;
833 score3_classify_arg (cum, mode, type, named, &info);
835 if (info.reg_offset == ARG_REG_NUM)
836 return 0;
838 if (!info.stack_words)
839 return gen_rtx_REG (mode, ARG_REG_FIRST + info.reg_offset);
840 else
842 rtx ret = gen_rtx_PARALLEL (mode, rtvec_alloc (info.reg_words));
843 unsigned int i, part_offset = 0;
844 for (i = 0; i < info.reg_words; i++)
846 rtx reg;
847 reg = gen_rtx_REG (SImode, ARG_REG_FIRST + info.reg_offset + i);
848 XVECEXP (ret, 0, i) = gen_rtx_EXPR_LIST (SImode, reg,
849 GEN_INT (part_offset));
850 part_offset += UNITS_PER_WORD;
852 return ret;
856 /* Implement FUNCTION_VALUE and LIBCALL_VALUE. For normal calls,
857 VALTYPE is the return type and MODE is VOIDmode. For libcalls,
858 VALTYPE is null and MODE is the mode of the return value. */
860 score3_function_value (tree valtype, tree func, enum machine_mode mode)
862 if (valtype)
864 int unsignedp;
865 mode = TYPE_MODE (valtype);
866 unsignedp = TYPE_UNSIGNED (valtype);
867 mode = promote_function_mode (valtype, mode, &unsignedp, func, 1);
869 return gen_rtx_REG (mode, RT_REGNUM);
872 /* Implement TARGET_ASM_TRAMPOLINE_TEMPLATE. */
874 void
875 score3_asm_trampoline_template (FILE *f)
877 fprintf (f, "\t.set r1\n");
878 fprintf (f, "\tmv! r31, r3\n");
879 fprintf (f, "\tnop!\n");
880 fprintf (f, "\tbl nextinsn\n");
881 fprintf (f, "nextinsn:\n");
882 fprintf (f, "\tlw! r1, [r3, 6*4-8]\n");
883 fprintf (f, "\tnop!\n");
884 fprintf (f, "\tlw r23, [r3, 6*4-4]\n");
885 fprintf (f, "\tmv! r3, r31\n");
886 fprintf (f, "\tnop!\n");
887 fprintf (f, "\tbr! r1\n");
888 fprintf (f, "\tnop!\n");
889 fprintf (f, "\t.set nor1\n");
892 /* Implement TARGET_TRAMPOLINE_INIT. */
893 void
894 score3_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
896 #define FFCACHE "_flush_cache"
897 #define CODE_SIZE (TRAMPOLINE_INSNS * UNITS_PER_WORD)
899 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
900 rtx addr = XEXP (m_tramp, 0);
901 rtx mem;
903 emit_block_move (m_tramp, assemble_trampoline_template (),
904 GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
906 mem = adjust_address (m_tramp, SImode, CODE_SIZE);
907 emit_move_insn (mem, fnaddr);
908 mem = adjust_address (m_tramp, SImode, CODE_SIZE + GET_MODE_SIZE (SImode));
909 emit_move_insn (mem, chain_value);
911 emit_library_call (gen_rtx_SYMBOL_REF (Pmode, FFCACHE),
912 0, VOIDmode, 2,
913 addr, Pmode,
914 GEN_INT (TRAMPOLINE_SIZE), SImode);
915 #undef FFCACHE
916 #undef CODE_SIZE
919 /* This function is used to implement REG_MODE_OK_FOR_BASE_P macro. */
921 score3_regno_mode_ok_for_base_p (int regno, int strict)
923 if (regno >= FIRST_PSEUDO_REGISTER)
925 if (!strict)
926 return 1;
927 regno = reg_renumber[regno];
929 if (regno == ARG_POINTER_REGNUM
930 || regno == FRAME_POINTER_REGNUM)
931 return 1;
932 return GP_REG_P (regno);
935 /* Implement TARGET_LEGITIMATE_ADDRESS_P macro. */
936 bool
937 score3_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
939 struct score3_address_info addr;
941 return score3_classify_address (&addr, mode, x, strict);
944 /* Return a number assessing the cost of moving a register in class
945 FROM to class TO. */
947 score3_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
948 enum reg_class from, enum reg_class to)
950 if (GR_REG_CLASS_P (from))
952 if (GR_REG_CLASS_P (to))
953 return 2;
954 else if (SP_REG_CLASS_P (to))
955 return 4;
956 else if (CP_REG_CLASS_P (to))
957 return 5;
958 else if (CE_REG_CLASS_P (to))
959 return 6;
961 if (GR_REG_CLASS_P (to))
963 if (GR_REG_CLASS_P (from))
964 return 2;
965 else if (SP_REG_CLASS_P (from))
966 return 4;
967 else if (CP_REG_CLASS_P (from))
968 return 5;
969 else if (CE_REG_CLASS_P (from))
970 return 6;
972 return 12;
975 /* Return the number of instructions needed to load a symbol of the
976 given type into a register. */
977 static int
978 score3_symbol_insns (enum score_symbol_type type)
980 switch (type)
982 case SYMBOL_GENERAL:
983 return 2;
985 case SYMBOL_SMALL_DATA:
986 return 1;
989 gcc_unreachable ();
992 /* Return the number of instructions needed to load or store a value
993 of mode MODE at X. Return 0 if X isn't valid for MODE. */
994 static int
995 score3_address_insns (rtx x, enum machine_mode mode)
997 struct score3_address_info addr;
998 int factor;
1000 if (mode == BLKmode)
1001 factor = 1;
1002 else
1003 factor = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
1005 if (score3_classify_address (&addr, mode, x, false))
1006 switch (addr.type)
1008 case SCORE3_ADD_REG:
1009 case SCORE3_ADD_CONST_INT:
1010 return factor;
1012 case SCORE3_ADD_SYMBOLIC:
1013 return factor * score3_symbol_insns (addr.symbol_type);
1015 return 0;
1018 /* Implement TARGET_RTX_COSTS macro. */
1019 bool
1020 score3_rtx_costs (rtx x, int code, int outer_code, int *total,
1021 bool speed ATTRIBUTE_UNUSED)
1023 enum machine_mode mode = GET_MODE (x);
1025 switch (code)
1027 case CONST_INT:
1028 if (outer_code == SET)
1030 if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
1031 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L'))
1032 *total = COSTS_N_INSNS (1);
1033 else
1034 *total = COSTS_N_INSNS (2);
1036 else if (outer_code == PLUS || outer_code == MINUS)
1038 if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'N'))
1039 *total = 0;
1040 else if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
1041 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L'))
1042 *total = 1;
1043 else
1044 *total = COSTS_N_INSNS (2);
1046 else if (outer_code == AND || outer_code == IOR)
1048 if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'M'))
1049 *total = 0;
1050 else if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
1051 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'K'))
1052 *total = 1;
1053 else
1054 *total = COSTS_N_INSNS (2);
1056 else
1058 *total = 0;
1060 return true;
1062 case CONST:
1063 case SYMBOL_REF:
1064 case LABEL_REF:
1065 case CONST_DOUBLE:
1066 *total = COSTS_N_INSNS (2);
1067 return true;
1069 case MEM:
1071 /* If the address is legitimate, return the number of
1072 instructions it needs, otherwise use the default handling. */
1073 int n = score3_address_insns (XEXP (x, 0), GET_MODE (x));
1074 if (n > 0)
1076 *total = COSTS_N_INSNS (n + 1);
1077 return true;
1079 return false;
1082 case FFS:
1083 *total = COSTS_N_INSNS (6);
1084 return true;
1086 case NOT:
1087 *total = COSTS_N_INSNS (1);
1088 return true;
1090 case AND:
1091 case IOR:
1092 case XOR:
1093 if (mode == DImode)
1095 *total = COSTS_N_INSNS (2);
1096 return true;
1098 return false;
1100 case ASHIFT:
1101 case ASHIFTRT:
1102 case LSHIFTRT:
1103 if (mode == DImode)
1105 *total = COSTS_N_INSNS ((GET_CODE (XEXP (x, 1)) == CONST_INT)
1106 ? 4 : 12);
1107 return true;
1109 return false;
1111 case ABS:
1112 *total = COSTS_N_INSNS (4);
1113 return true;
1115 case PLUS:
1116 case MINUS:
1117 if (mode == DImode)
1119 *total = COSTS_N_INSNS (4);
1120 return true;
1122 *total = COSTS_N_INSNS (1);
1123 return true;
1125 case NEG:
1126 if (mode == DImode)
1128 *total = COSTS_N_INSNS (4);
1129 return true;
1131 return false;
1133 case MULT:
1134 *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (12);
1135 return true;
1137 case DIV:
1138 case MOD:
1139 case UDIV:
1140 case UMOD:
1141 *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (33);
1142 return true;
1144 case SIGN_EXTEND:
1145 case ZERO_EXTEND:
1146 switch (GET_MODE (XEXP (x, 0)))
1148 case QImode:
1149 case HImode:
1150 if (GET_CODE (XEXP (x, 0)) == MEM)
1152 *total = COSTS_N_INSNS (2);
1154 if (!TARGET_LITTLE_ENDIAN &&
1155 side_effects_p (XEXP (XEXP (x, 0), 0)))
1156 *total = 100;
1158 else
1159 *total = COSTS_N_INSNS (1);
1160 break;
1162 default:
1163 *total = COSTS_N_INSNS (1);
1164 break;
1166 return true;
1168 default:
1169 return false;
1173 /* Implement TARGET_ADDRESS_COST macro. */
1175 score3_address_cost (rtx addr)
1177 return score3_address_insns (addr, SImode);
1180 /* Implement ASM_OUTPUT_EXTERNAL macro. */
1182 score3_output_external (FILE *file ATTRIBUTE_UNUSED,
1183 tree decl, const char *name)
1185 register struct extern_list *p;
1187 if (score3_in_small_data_p (decl))
1189 p = ggc_alloc_extern_list ();
1190 p->next = extern_head;
1191 p->name = name;
1192 p->size = int_size_in_bytes (TREE_TYPE (decl));
1193 extern_head = p;
1195 return 0;
1198 /* Implement RETURN_ADDR_RTX. Note, we do not support moving
1199 back to a previous frame. */
1201 score3_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
1203 if (count != 0)
1204 return const0_rtx;
1205 return get_hard_reg_initial_val (Pmode, RA_REGNUM);
1208 /* Implement PRINT_OPERAND macro. */
1209 /* Score-specific operand codes:
1210 '[' print .set nor1 directive
1211 ']' print .set r1 directive
1212 'U' print hi part of a CONST_INT rtx
1213 'E' print log2(v)
1214 'F' print log2(~v)
1215 'D' print SFmode const double
1216 'S' selectively print "!" if operand is 15bit instruction accessible
1217 'V' print "v!" if operand is 15bit instruction accessible, or "lfh!"
1218 'L' low part of DImode reg operand
1219 'H' high part of DImode reg operand
1220 'C' print part of opcode for a branch condition. */
1221 void
1222 score3_print_operand (FILE *file, rtx op, int c)
1224 enum rtx_code code = -1;
1225 if (!PRINT_OPERAND_PUNCT_VALID_P (c))
1226 code = GET_CODE (op);
1228 if (c == '[')
1230 fprintf (file, ".set r1\n");
1232 else if (c == ']')
1234 fprintf (file, "\n\t.set nor1");
1236 else if (c == 'U')
1238 gcc_assert (code == CONST_INT);
1239 fprintf (file, HOST_WIDE_INT_PRINT_HEX,
1240 (INTVAL (op) >> 16) & 0xffff);
1242 else if (c == 'D')
1244 if (GET_CODE (op) == CONST_DOUBLE)
1246 rtx temp = gen_lowpart (SImode, op);
1247 gcc_assert (GET_MODE (op) == SFmode);
1248 fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (temp) & 0xffffffff);
1250 else
1251 output_addr_const (file, op);
1253 else if (c == 'S')
1255 gcc_assert (code == REG);
1256 if (G16_REG_P (REGNO (op)))
1257 fprintf (file, "!");
1259 else if (c == 'V')
1261 gcc_assert (code == REG);
1262 fprintf (file, G16_REG_P (REGNO (op)) ? "v!" : "lfh!");
1264 else if (c == 'C')
1266 enum machine_mode mode = GET_MODE (XEXP (op, 0));
1268 switch (code)
1270 case EQ: fputs ("eq!", file); break;
1271 case NE: fputs ("ne!", file); break;
1272 case GT: fputs ("gt!", file); break;
1273 case GE: fputs (mode != CCmode ? "pl" : "ge", file); break;
1274 case LT: fputs (mode != CCmode ? "mi" : "lt", file); break;
1275 case LE: fputs ("le!", file); break;
1276 case GTU: fputs ("gtu!", file); break;
1277 case GEU: fputs ("cs", file); break;
1278 case LTU: fputs ("cc", file); break;
1279 case LEU: fputs ("leu!", file); break;
1280 default:
1281 output_operand_lossage ("invalid operand for code: '%c'", code);
1284 else if (c == 'G') /* Seperate from b<cond>, use for mv<cond>. */
1286 enum machine_mode mode = GET_MODE (XEXP (op, 0));
1288 switch (code)
1290 case EQ: fputs ("eq", file); break;
1291 case NE: fputs ("ne", file); break;
1292 case GT: fputs ("gt", file); break;
1293 case GE: fputs (mode != CCmode ? "pl" : "ge", file); break;
1294 case LT: fputs (mode != CCmode ? "mi" : "lt", file); break;
1295 case LE: fputs ("le", file); break;
1296 case GTU: fputs ("gtu", file); break;
1297 case GEU: fputs ("cs", file); break;
1298 case LTU: fputs ("cc", file); break;
1299 case LEU: fputs ("leu", file); break;
1300 default:
1301 output_operand_lossage ("invalid operand for code: '%c'", code);
1304 else if (c == 'E')
1306 unsigned HOST_WIDE_INT i;
1307 unsigned HOST_WIDE_INT pow2mask = 1;
1308 unsigned HOST_WIDE_INT val;
1310 val = INTVAL (op);
1311 for (i = 0; i < 32; i++)
1313 if (val == pow2mask)
1314 break;
1315 pow2mask <<= 1;
1317 gcc_assert (i < 32);
1318 fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
1320 else if (c == 'F')
1322 unsigned HOST_WIDE_INT i;
1323 unsigned HOST_WIDE_INT pow2mask = 1;
1324 unsigned HOST_WIDE_INT val;
1326 val = ~INTVAL (op);
1327 for (i = 0; i < 32; i++)
1329 if (val == pow2mask)
1330 break;
1331 pow2mask <<= 1;
1333 gcc_assert (i < 32);
1334 fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
1336 else if (code == REG)
1338 int regnum = REGNO (op);
1339 if ((c == 'H' && !WORDS_BIG_ENDIAN)
1340 || (c == 'L' && WORDS_BIG_ENDIAN))
1341 regnum ++;
1342 fprintf (file, "%s", reg_names[regnum]);
1344 else
1346 switch (code)
1348 case MEM:
1349 score3_print_operand_address (file, op);
1350 break;
1351 default:
1352 output_addr_const (file, op);
1357 /* Implement PRINT_OPERAND_ADDRESS macro. */
1358 void
1359 score3_print_operand_address (FILE *file, rtx x)
1361 struct score3_address_info addr;
1362 enum rtx_code code = GET_CODE (x);
1363 enum machine_mode mode = GET_MODE (x);
1365 if (code == MEM)
1366 x = XEXP (x, 0);
1368 if (score3_classify_address (&addr, mode, x, true))
1370 switch (addr.type)
1372 case SCORE3_ADD_REG:
1374 switch (addr.code)
1376 case PRE_DEC:
1377 fprintf (file, "[%s,-%ld]+", reg_names[REGNO (addr.reg)],
1378 INTVAL (addr.offset));
1379 break;
1380 case POST_DEC:
1381 fprintf (file, "[%s]+,-%ld", reg_names[REGNO (addr.reg)],
1382 INTVAL (addr.offset));
1383 break;
1384 case PRE_INC:
1385 fprintf (file, "[%s, %ld]+", reg_names[REGNO (addr.reg)],
1386 INTVAL (addr.offset));
1387 break;
1388 case POST_INC:
1389 fprintf (file, "[%s]+, %ld", reg_names[REGNO (addr.reg)],
1390 INTVAL (addr.offset));
1391 break;
1392 default:
1393 if (INTVAL(addr.offset) == 0)
1394 fprintf(file, "[%s]", reg_names[REGNO (addr.reg)]);
1395 else
1396 fprintf(file, "[%s, %ld]", reg_names[REGNO (addr.reg)],
1397 INTVAL(addr.offset));
1398 break;
1401 return;
1402 case SCORE3_ADD_CONST_INT:
1403 case SCORE3_ADD_SYMBOLIC:
1404 output_addr_const (file, x);
1405 return;
1408 print_rtl (stderr, x);
1409 gcc_unreachable ();
1412 /* Implement SELECT_CC_MODE macro. */
1413 enum machine_mode
1414 score3_select_cc_mode (enum rtx_code op, rtx x, rtx y)
1416 if ((op == EQ || op == NE || op == LT || op == GE)
1417 && y == const0_rtx
1418 && GET_MODE (x) == SImode)
1420 switch (GET_CODE (x))
1422 case PLUS:
1423 case MINUS:
1424 case NEG:
1425 case AND:
1426 case IOR:
1427 case XOR:
1428 case NOT:
1429 case ASHIFT:
1430 case LSHIFTRT:
1431 case ASHIFTRT:
1432 return CC_NZmode;
1434 case SIGN_EXTEND:
1435 case ZERO_EXTEND:
1436 case ROTATE:
1437 case ROTATERT:
1438 return (op == LT || op == GE) ? CC_Nmode : CCmode;
1440 default:
1441 return CCmode;
1445 if ((op == EQ || op == NE)
1446 && (GET_CODE (y) == NEG)
1447 && register_operand (XEXP (y, 0), SImode)
1448 && register_operand (x, SImode))
1450 return CC_NZmode;
1453 return CCmode;
1456 #define EMIT_PL(_rtx) RTX_FRAME_RELATED_P (_rtx) = 1
1457 /* return 0, no more bit set in mask. */
1458 static int rpush_first (int mask, int sb, int *rd)
1460 int i, cnt = 1;
1462 if ((mask & (1 << sb)) == 0)
1463 return 0;
1465 *rd = sb;
1467 for (i = sb-1; i >= 0; i--)
1469 if (mask & (1 << i))
1471 cnt ++;
1472 continue;
1475 *rd = i+1;
1476 break;;
1479 return cnt;
1482 static void
1483 rpush (int rd, int cnt)
1485 rtx mem = gen_rtx_MEM (SImode, gen_rtx_PRE_DEC (SImode, stack_pointer_rtx));
1486 rtx reg = gen_rtx_REG (SImode, rd);
1488 if (!crtl->calls_eh_return)
1489 MEM_READONLY_P (mem) = 1;
1491 if (cnt == 1)
1492 EMIT_PL (emit_insn (gen_pushsi_score3 (mem, reg)));
1493 else
1495 int i;
1496 rtx insn = gen_store_multiple (gen_rtx_MEM (SImode, stack_pointer_rtx),
1497 gen_rtx_REG (SImode, rd),
1498 GEN_INT (cnt));
1500 rtx pat = PATTERN (insn);
1502 for (i = 0; i < XVECLEN (pat, 0); i++)
1503 if (GET_CODE (XVECEXP (pat, 0, i)) == SET)
1504 RTX_FRAME_RELATED_P (XVECEXP (pat, 0, i)) = 1;
1506 EMIT_PL (emit_insn (insn));
1510 /* Generate the prologue instructions for entry into a S+core function. */
1511 void
1512 score3_prologue (void)
1514 struct score3_frame_info *f = score3_compute_frame_size (get_frame_size ());
1515 HOST_WIDE_INT size;
1516 int regno;
1518 size = f->total_size - f->gp_reg_size;
1520 if (flag_pic)
1521 emit_insn (gen_cpload_score3 ());
1524 int cnt, rd;
1526 for (regno = (int) GP_REG_LAST; regno >= (int) GP_REG_FIRST; regno--)
1528 cnt = rpush_first (f->mask, regno, &rd);
1529 if (cnt != 0)
1531 rpush (rd, cnt);
1532 regno = regno - cnt;
1537 if (size > 0)
1539 rtx insn;
1541 if (CONST_OK_FOR_LETTER_P (-size, 'L'))
1542 EMIT_PL (emit_insn (gen_add3_insn (stack_pointer_rtx,
1543 stack_pointer_rtx,
1544 GEN_INT (-size))));
1545 else
1547 EMIT_PL (emit_move_insn (gen_rtx_REG (Pmode, SCORE3_PROLOGUE_TEMP_REGNUM),
1548 GEN_INT (size)));
1549 EMIT_PL (emit_insn
1550 (gen_sub3_insn (stack_pointer_rtx,
1551 stack_pointer_rtx,
1552 gen_rtx_REG (Pmode,
1553 SCORE3_PROLOGUE_TEMP_REGNUM))));
1555 insn = get_last_insn ();
1556 REG_NOTES (insn) =
1557 alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR,
1558 gen_rtx_SET (VOIDmode, stack_pointer_rtx,
1559 plus_constant (stack_pointer_rtx,
1560 -size)),
1561 REG_NOTES (insn));
1564 if (frame_pointer_needed)
1565 EMIT_PL (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx));
1567 if (flag_pic && f->cprestore_size)
1569 if (frame_pointer_needed)
1570 emit_insn (gen_cprestore_use_fp_score3 (GEN_INT (size - f->cprestore_size)));
1571 else
1572 emit_insn (gen_cprestore_use_sp_score3 (GEN_INT (size - f->cprestore_size)));
1576 /* return 0, no more bit set in mask. */
1577 static int
1578 rpop_first (int mask, int sb, int *rd)
1580 int i, cnt = 1;
1582 if ((mask & (1 << sb)) == 0)
1583 return 0;
1585 *rd = sb;
1587 for (i = sb+1; i < 32; i++)
1588 if (mask & (1 << i))
1589 cnt++;
1590 else
1591 break;;
1593 return cnt;
1596 static void
1597 rpop (int rd, int cnt)
1599 rtx mem = gen_rtx_MEM (SImode, gen_rtx_POST_INC (SImode, stack_pointer_rtx));
1600 rtx reg = gen_rtx_REG (SImode, rd);
1602 if (!crtl->calls_eh_return)
1603 MEM_READONLY_P (mem) = 1;
1605 if (cnt == 1)
1606 emit_insn (gen_popsi_score3 (reg, mem));
1607 else
1608 emit_insn (gen_load_multiple (reg,
1609 gen_rtx_MEM (SImode, stack_pointer_rtx),
1610 GEN_INT (cnt)));
1613 /* Generate the epilogue instructions in a S+core function. */
1614 void
1615 score3_epilogue (int sibcall_p)
1617 struct score3_frame_info *f = score3_compute_frame_size (get_frame_size ());
1618 HOST_WIDE_INT size;
1619 int regno;
1620 rtx base;
1622 size = f->total_size - f->gp_reg_size;
1624 if (!frame_pointer_needed)
1625 base = stack_pointer_rtx;
1626 else
1627 base = hard_frame_pointer_rtx;
1629 if (size)
1631 if (CONST_OK_FOR_LETTER_P (size, 'L'))
1632 emit_insn (gen_add3_insn (base, base, GEN_INT (size)));
1633 else
1635 emit_move_insn (gen_rtx_REG (Pmode, SCORE3_EPILOGUE_TEMP_REGNUM),
1636 GEN_INT (size));
1637 emit_insn (gen_add3_insn (base, base,
1638 gen_rtx_REG (Pmode,
1639 SCORE3_EPILOGUE_TEMP_REGNUM)));
1643 if (base != stack_pointer_rtx)
1644 emit_move_insn (stack_pointer_rtx, base);
1646 if (crtl->calls_eh_return)
1647 emit_insn (gen_add3_insn (stack_pointer_rtx,
1648 stack_pointer_rtx,
1649 EH_RETURN_STACKADJ_RTX));
1652 int cnt, rd;
1654 for (regno = (int) GP_REG_FIRST; regno <= (int) GP_REG_LAST; regno++)
1656 cnt = rpop_first (f->mask, regno, &rd);
1657 if (cnt != 0)
1659 rpop (rd, cnt);
1660 regno = regno + cnt;
1665 if (!sibcall_p)
1666 emit_jump_insn (gen_return_internal_score3 (gen_rtx_REG (Pmode, RA_REGNUM)));
1669 /* Return true if X is a symbolic constant that can be calculated in
1670 the same way as a bare symbol. If it is, store the type of the
1671 symbol in *SYMBOL_TYPE. */
1673 score3_symbolic_constant_p (rtx x, enum score_symbol_type *symbol_type)
1675 HOST_WIDE_INT offset;
1677 score3_split_const (x, &x, &offset);
1678 if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF)
1679 *symbol_type = score3_classify_symbol (x);
1680 else
1681 return 0;
1683 if (offset == 0)
1684 return 1;
1686 /* if offset > 15bit, must reload */
1687 if (!IMM_IN_RANGE (offset, 15, 1))
1688 return 0;
1690 switch (*symbol_type)
1692 case SYMBOL_GENERAL:
1693 return 1;
1694 case SYMBOL_SMALL_DATA:
1695 return score3_offset_within_object_p (x, offset);
1697 gcc_unreachable ();
1700 void
1701 score3_movsicc (rtx *ops)
1703 enum machine_mode mode;
1705 mode = score3_select_cc_mode (GET_CODE (ops[1]), ops[2], ops[3]);
1706 emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (mode, CC_REGNUM),
1707 gen_rtx_COMPARE (mode, XEXP (ops[1], 0),
1708 XEXP (ops[1], 1))));
1711 /* Call and sibcall pattern all need call this function. */
1712 void
1713 score3_call (rtx *ops, bool sib)
1715 rtx addr = XEXP (ops[0], 0);
1716 if (!call_insn_operand (addr, VOIDmode))
1718 rtx oaddr = addr;
1719 addr = gen_reg_rtx (Pmode);
1720 gen_move_insn (addr, oaddr);
1723 if (sib)
1724 emit_call_insn (gen_sibcall_internal_score3 (addr, ops[1]));
1725 else
1726 emit_call_insn (gen_call_internal_score3 (addr, ops[1]));
1729 /* Call value and sibcall value pattern all need call this function. */
1730 void
1731 score3_call_value (rtx *ops, bool sib)
1733 rtx result = ops[0];
1734 rtx addr = XEXP (ops[1], 0);
1735 rtx arg = ops[2];
1737 if (!call_insn_operand (addr, VOIDmode))
1739 rtx oaddr = addr;
1740 addr = gen_reg_rtx (Pmode);
1741 gen_move_insn (addr, oaddr);
1744 if (sib)
1745 emit_call_insn (gen_sibcall_value_internal_score3 (result, addr, arg));
1746 else
1747 emit_call_insn (gen_call_value_internal_score3 (result, addr, arg));
1750 /* Machine Split */
1751 void
1752 score3_movdi (rtx *ops)
1754 rtx dst = ops[0];
1755 rtx src = ops[1];
1756 rtx dst0 = score3_subw (dst, 0);
1757 rtx dst1 = score3_subw (dst, 1);
1758 rtx src0 = score3_subw (src, 0);
1759 rtx src1 = score3_subw (src, 1);
1761 if (GET_CODE (dst0) == REG && reg_overlap_mentioned_p (dst0, src))
1763 emit_move_insn (dst1, src1);
1764 emit_move_insn (dst0, src0);
1766 else
1768 emit_move_insn (dst0, src0);
1769 emit_move_insn (dst1, src1);
1773 void
1774 score3_zero_extract_andi (rtx *ops)
1776 if (INTVAL (ops[1]) == 1 && const_uimm5 (ops[2], SImode))
1777 emit_insn (gen_zero_extract_bittst_score3 (ops[0], ops[2]));
1778 else
1780 unsigned HOST_WIDE_INT mask;
1781 mask = (0xffffffffU & ((1U << INTVAL (ops[1])) - 1U));
1782 mask = mask << INTVAL (ops[2]);
1783 emit_insn (gen_andsi3_cmp_score3 (ops[3], ops[0],
1784 gen_int_mode (mask, SImode)));
1788 const char *
1789 score3_rpush (rtx *ops)
1791 snprintf (score3_ins, INS_BUF_SZ, "rpush!\t%%1, %d", XVECLEN (ops[0], 0));
1792 return score3_ins;
1795 const char *
1796 score3_rpop (rtx *ops)
1798 snprintf (score3_ins, INS_BUF_SZ, "rpop!\t%%1, %d", XVECLEN (ops[0], 0));
1799 return score3_ins;
1802 /* Output asm code for ld/sw insn. */
1803 static int
1804 score3_pr_addr_post (rtx *ops, int idata, int iaddr, char *ip,
1805 enum score_mem_unit unit ATTRIBUTE_UNUSED)
1807 struct score3_address_info ai;
1809 gcc_assert (GET_CODE (ops[idata]) == REG);
1810 gcc_assert (score3_classify_address (&ai, SImode, XEXP (ops[iaddr], 0), true));
1812 if (ai.type == SCORE3_ADD_REG
1813 && ai.code == REG
1814 && GET_CODE (ai.offset) == CONST_INT
1815 && G16_REG_P (REGNO (ops[idata]))
1816 && G8_REG_P (REGNO (ai.reg))
1817 && ((INTVAL (ai.offset) & 3) == 0)
1818 && (IMM_IN_RANGE (INTVAL (ai.offset), 7, 0)))
1820 ops[iaddr] = ai.reg;
1821 return snprintf (ip, INS_BUF_SZ, "!\t%%%d, [%%%d, "
1822 HOST_WIDE_INT_PRINT_DEC "]",
1823 idata, iaddr, INTVAL (ai.offset));
1826 if (ai.type == SCORE3_ADD_SYMBOLIC)
1827 return snprintf (ip, INS_BUF_SZ, "48\t%%%d, %%a%d", idata, iaddr);
1829 return snprintf (ip, INS_BUF_SZ, "\t%%%d, %%a%d", idata, iaddr);
1832 /* Output asm insn for load. */
1833 const char *
1834 score3_linsn (rtx *ops, enum score_mem_unit unit, bool sign)
1836 const char *pre_ins[] =
1837 {"lbu", "lhu", "lw", "??", "lb", "lh", "lw", "??"};
1838 char *ip;
1840 strcpy (score3_ins, pre_ins[(sign ? 4 : 0) + unit]);
1841 ip = score3_ins + strlen (score3_ins);
1843 if (unit == SCORE_WORD)
1844 score3_pr_addr_post (ops, 0, 1, ip, unit);
1845 else
1846 snprintf (ip, INS_BUF_SZ, "\t%%0, %%a1");
1848 return score3_ins;
1851 /* Output asm insn for store. */
1852 const char *
1853 score3_sinsn (rtx *ops, enum score_mem_unit unit)
1855 const char *pre_ins[] = {"sb", "sh", "sw"};
1856 char *ip;
1858 strcpy (score3_ins, pre_ins[unit]);
1859 ip = score3_ins + strlen (score3_ins);
1861 if (unit == SCORE_WORD)
1862 score3_pr_addr_post (ops, 1, 0, ip, unit);
1863 else
1864 snprintf (ip, INS_BUF_SZ, "\t%%1, %%a0");
1866 return score3_ins;
1869 /* Output asm insn for load immediate. */
1870 const char *
1871 score3_limm (rtx *ops)
1873 HOST_WIDE_INT v;
1875 gcc_assert (GET_CODE (ops[0]) == REG);
1876 gcc_assert (GET_CODE (ops[1]) == CONST_INT);
1878 v = INTVAL (ops[1]);
1879 if (G16_REG_P (REGNO (ops[0])) && IMM_IN_RANGE (v, 5, 0))
1880 return "ldiu!\t%0, %c1";
1881 else if (IMM_IN_RANGE (v, 16, 1))
1882 return "ldi\t%0, %c1";
1883 else if ((v & 0xffff) == 0)
1884 return "ldis\t%0, %U1";
1885 else
1886 return "li\t%0, %c1";
1889 /* Output asm insn for move. */
1890 const char *
1891 score3_move (rtx *ops)
1893 gcc_assert (GET_CODE (ops[0]) == REG);
1894 gcc_assert (GET_CODE (ops[1]) == REG);
1896 return "mv!\t%0, %1";
1899 /* Generate add insn. */
1900 const char *
1901 score3_select_add_imm (rtx *ops, bool set_cc)
1903 HOST_WIDE_INT v = INTVAL (ops[2]);
1905 gcc_assert (GET_CODE (ops[2]) == CONST_INT);
1906 gcc_assert (REGNO (ops[0]) == REGNO (ops[1]));
1908 if (set_cc)
1909 return "addi.c\t%0, %c2";
1910 else
1911 if (IMM_IN_RANGE (v, 6, 1) && G16_REG_P (REGNO (ops[0])))
1912 return "addi!\t%0, %c2";
1913 else
1914 return "addi\t%0, %c2";
1917 /* Output arith insn. */
1918 const char *
1919 score3_select (rtx *ops, const char *inst_pre, bool commu ATTRIBUTE_UNUSED,
1920 const char *letter, bool set_cc)
1922 gcc_assert (GET_CODE (ops[0]) == REG);
1923 gcc_assert (GET_CODE (ops[1]) == REG);
1925 if (set_cc)
1926 snprintf (score3_ins, INS_BUF_SZ, "%s.c\t%%0, %%1, %%%s2", inst_pre, letter);
1927 else
1928 snprintf (score3_ins, INS_BUF_SZ, "%s\t%%0, %%1, %%%s2", inst_pre, letter);
1929 return score3_ins;
1932 /* Output a Score3 casesi instruction. */
1933 const char *
1934 score3_output_casesi (rtx *operands)
1936 rtx diff_vec = PATTERN (next_real_insn (operands[2]));
1937 gcc_assert (GET_CODE (diff_vec) == ADDR_DIFF_VEC);
1939 output_asm_insn ("cmpi.c\t%0, %1", operands);
1940 output_asm_insn ("bgtu\t%3", operands);
1941 switch (GET_MODE(diff_vec))
1943 case QImode:
1944 output_asm_insn ("ldi48\t%4, %2", operands);
1945 output_asm_insn ("ltbb\t%4, [%4, %0]\n%2_tbb:", operands);
1946 return "brr!\t%4";
1947 case HImode:
1948 output_asm_insn ("ldi48\t%4, %2", operands);
1949 output_asm_insn ("ltbh\t%4, [%4, %0]\n%2_tbb:", operands);
1950 return "brr!\t%4";
1951 case SImode:
1952 output_asm_insn ("ldi48\t%4, %2", operands);
1953 output_asm_insn ("ltbw\t%4, [%4, %0]", operands);
1954 return "br!\t%4";
1955 default:
1956 gcc_unreachable ();