Merge from mainline (165734:167278).
[official-gcc/graphite-test-results.git] / gcc / config / score / score3.c
blob3634e4bca3ff647a114648fe23eb1a7a12223490
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 "toplev.h"
34 #include "output.h"
35 #include "tree.h"
36 #include "function.h"
37 #include "expr.h"
38 #include "optabs.h"
39 #include "flags.h"
40 #include "reload.h"
41 #include "tm_p.h"
42 #include "ggc.h"
43 #include "gstab.h"
44 #include "hashtab.h"
45 #include "debug.h"
46 #include "target.h"
47 #include "target-def.h"
48 #include "integrate.h"
49 #include "langhooks.h"
50 #include "cfglayout.h"
51 #include "score3.h"
52 #include "df.h"
54 #define BITSET_P(VALUE, BIT) (((VALUE) & (1L << (BIT))) != 0)
55 #define INS_BUF_SZ 128
57 extern enum reg_class score_char_to_class[256];
59 static int score3_sdata_max;
60 static char score3_ins[INS_BUF_SZ + 8];
62 /* Return true if SYMBOL is a SYMBOL_REF and OFFSET + SYMBOL points
63 to the same object as SYMBOL. */
64 static int
65 score3_offset_within_object_p (rtx symbol, HOST_WIDE_INT offset)
67 if (GET_CODE (symbol) != SYMBOL_REF)
68 return 0;
70 if (CONSTANT_POOL_ADDRESS_P (symbol)
71 && offset >= 0
72 && offset < (int)GET_MODE_SIZE (get_pool_mode (symbol)))
73 return 1;
75 if (SYMBOL_REF_DECL (symbol) != 0
76 && offset >= 0
77 && offset < int_size_in_bytes (TREE_TYPE (SYMBOL_REF_DECL (symbol))))
78 return 1;
80 return 0;
83 /* Split X into a base and a constant offset, storing them in *BASE
84 and *OFFSET respectively. */
85 static void
86 score3_split_const (rtx x, rtx *base, HOST_WIDE_INT *offset)
88 *offset = 0;
90 if (GET_CODE (x) == CONST)
91 x = XEXP (x, 0);
93 if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
95 *offset += INTVAL (XEXP (x, 1));
96 x = XEXP (x, 0);
99 *base = x;
102 /* Classify symbol X, which must be a SYMBOL_REF or a LABEL_REF. */
103 static enum score_symbol_type
104 score3_classify_symbol (rtx x)
106 if (GET_CODE (x) == LABEL_REF)
107 return SYMBOL_GENERAL;
109 gcc_assert (GET_CODE (x) == SYMBOL_REF);
111 if (CONSTANT_POOL_ADDRESS_P (x))
113 if (GET_MODE_SIZE (get_pool_mode (x)) <= SCORE3_SDATA_MAX)
114 return SYMBOL_SMALL_DATA;
115 return SYMBOL_GENERAL;
117 if (SYMBOL_REF_SMALL_P (x))
118 return SYMBOL_SMALL_DATA;
119 return SYMBOL_GENERAL;
122 /* Return true if the current function must save REGNO. */
123 static int
124 score3_save_reg_p (unsigned int regno)
126 /* Check call-saved registers. */
127 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
128 return 1;
130 /* We need to save the old frame pointer before setting up a new one. */
131 if (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed)
132 return 1;
134 /* We need to save the incoming return address if it is ever clobbered
135 within the function. */
136 if (regno == RA_REGNUM && df_regs_ever_live_p (regno))
137 return 1;
139 return 0;
142 /* Return one word of double-word value OP, taking into account the fixed
143 endianness of certain registers. HIGH_P is true to select the high part,
144 false to select the low part. */
145 static rtx
146 score3_subw (rtx op, int high_p)
148 unsigned int byte;
149 enum machine_mode mode = GET_MODE (op);
151 if (mode == VOIDmode)
152 mode = DImode;
154 byte = (TARGET_LITTLE_ENDIAN ? high_p : !high_p) ? UNITS_PER_WORD : 0;
156 if (GET_CODE (op) == REG && REGNO (op) == HI_REGNUM)
157 return gen_rtx_REG (SImode, high_p ? HI_REGNUM : LO_REGNUM);
159 if (GET_CODE (op) == MEM)
160 return adjust_address (op, SImode, byte);
162 return simplify_gen_subreg (SImode, op, mode, byte);
165 static struct score3_frame_info *
166 score3_cached_frame (void)
168 static struct score3_frame_info _frame_info;
169 return &_frame_info;
172 /* Return the bytes needed to compute the frame pointer from the current
173 stack pointer. SIZE is the size (in bytes) of the local variables. */
174 static struct score3_frame_info *
175 score3_compute_frame_size (HOST_WIDE_INT size)
177 unsigned int regno;
178 struct score3_frame_info *f = score3_cached_frame ();
180 memset (f, 0, sizeof (struct score3_frame_info));
181 f->gp_reg_size = 0;
182 f->mask = 0;
183 f->var_size = SCORE3_STACK_ALIGN (size);
184 f->args_size = crtl->outgoing_args_size;
185 f->cprestore_size = flag_pic ? UNITS_PER_WORD : 0;
187 if (f->var_size == 0 && current_function_is_leaf)
188 f->args_size = f->cprestore_size = 0;
190 if (f->args_size == 0 && cfun->calls_alloca)
191 f->args_size = UNITS_PER_WORD;
193 f->total_size = f->var_size + f->args_size + f->cprestore_size;
194 for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
196 if (score3_save_reg_p (regno))
198 f->gp_reg_size += GET_MODE_SIZE (SImode);
199 f->mask |= 1 << (regno - GP_REG_FIRST);
203 if (crtl->calls_eh_return)
205 unsigned int i;
206 for (i = 0;; ++i)
208 regno = EH_RETURN_DATA_REGNO (i);
209 if (regno == INVALID_REGNUM)
210 break;
211 f->gp_reg_size += GET_MODE_SIZE (SImode);
212 f->mask |= 1 << (regno - GP_REG_FIRST);
216 f->total_size += f->gp_reg_size;
217 f->num_gp = f->gp_reg_size / UNITS_PER_WORD;
219 if (f->mask)
221 HOST_WIDE_INT offset;
222 offset = (f->args_size + f->cprestore_size + f->var_size
223 + f->gp_reg_size - GET_MODE_SIZE (SImode));
224 f->gp_sp_offset = offset;
226 else
227 f->gp_sp_offset = 0;
229 return f;
232 /* Return true if X is a valid base register for the given mode.
233 Allow only hard registers if STRICT. */
234 static int
235 score3_valid_base_register_p (rtx x, int strict)
237 if (!strict && GET_CODE (x) == SUBREG)
238 x = SUBREG_REG (x);
240 return (GET_CODE (x) == REG
241 && score3_regno_mode_ok_for_base_p (REGNO (x), strict));
244 /* Return true if X is a valid address for machine mode MODE. If it is,
245 fill in INFO appropriately. STRICT is true if we should only accept
246 hard base registers. */
247 static int
248 score3_classify_address (struct score3_address_info *info,
249 enum machine_mode mode, rtx x, int strict)
251 info->code = GET_CODE (x);
253 switch (info->code)
255 case REG:
256 case SUBREG:
257 info->type = SCORE3_ADD_REG;
258 info->reg = x;
259 info->offset = const0_rtx;
260 return score3_valid_base_register_p (info->reg, strict);
261 case PLUS:
262 info->type = SCORE3_ADD_REG;
263 info->reg = XEXP (x, 0);
264 info->offset = XEXP (x, 1);
265 return (score3_valid_base_register_p (info->reg, strict)
266 && GET_CODE (info->offset) == CONST_INT
267 && IMM_IN_RANGE (INTVAL (info->offset), 15, 1));
268 case PRE_DEC:
269 case POST_DEC:
270 case PRE_INC:
271 case POST_INC:
272 if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (SImode))
273 return false;
274 info->type = SCORE3_ADD_REG;
275 info->reg = XEXP (x, 0);
276 info->offset = GEN_INT (GET_MODE_SIZE (mode));
277 return score3_valid_base_register_p (info->reg, strict);
278 case CONST_INT:
279 info->type = SCORE3_ADD_CONST_INT;
280 return 1;
281 case CONST:
282 case LABEL_REF:
283 case SYMBOL_REF:
284 info->type = SCORE3_ADD_SYMBOLIC;
285 return (score3_symbolic_constant_p (x, &info->symbol_type)
286 && (info->symbol_type == SYMBOL_GENERAL
287 || info->symbol_type == SYMBOL_SMALL_DATA));
288 default:
289 return 0;
293 bool
294 score3_return_in_memory (const_tree type, const_tree fndecl ATTRIBUTE_UNUSED)
296 return ((TYPE_MODE (type) == BLKmode)
297 || (int_size_in_bytes (type) > 2 * UNITS_PER_WORD)
298 || (int_size_in_bytes (type) == -1));
301 /* Return a legitimate address for REG + OFFSET. */
302 static rtx
303 score3_add_offset (rtx reg, HOST_WIDE_INT offset)
305 if (!IMM_IN_RANGE (offset, 15, 1))
307 reg = expand_simple_binop (GET_MODE (reg), PLUS,
308 gen_int_mode (offset & 0xffffc000,
309 GET_MODE (reg)),
310 reg, NULL, 0, OPTAB_WIDEN);
311 offset &= 0x3fff;
314 return plus_constant (reg, offset);
317 /* Implement TARGET_ASM_OUTPUT_MI_THUNK. Generate rtl rather than asm text
318 in order to avoid duplicating too much logic from elsewhere. */
319 void
320 score3_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
321 HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
322 tree function)
324 rtx this_rtx, temp1, insn, fnaddr;
326 /* Pretend to be a post-reload pass while generating rtl. */
327 reload_completed = 1;
329 /* Mark the end of the (empty) prologue. */
330 emit_note (NOTE_INSN_PROLOGUE_END);
332 /* We need two temporary registers in some cases. */
333 temp1 = gen_rtx_REG (Pmode, 8);
335 /* Find out which register contains the "this" pointer. */
336 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
337 this_rtx = gen_rtx_REG (Pmode, ARG_REG_FIRST + 1);
338 else
339 this_rtx = gen_rtx_REG (Pmode, ARG_REG_FIRST);
341 /* Add DELTA to THIS_RTX. */
342 if (delta != 0)
344 rtx offset = GEN_INT (delta);
345 if (!CONST_OK_FOR_LETTER_P (delta, 'L'))
347 emit_move_insn (temp1, offset);
348 offset = temp1;
350 emit_insn (gen_add3_insn (this_rtx, this_rtx, offset));
353 /* If needed, add *(*THIS_RTX + VCALL_OFFSET) to THIS_RTX. */
354 if (vcall_offset != 0)
356 rtx addr;
358 /* Set TEMP1 to *THIS_RTX. */
359 emit_move_insn (temp1, gen_rtx_MEM (Pmode, this_rtx));
361 /* Set ADDR to a legitimate address for *THIS_RTX + VCALL_OFFSET. */
362 addr = score3_add_offset (temp1, vcall_offset);
364 /* Load the offset and add it to THIS_RTX. */
365 emit_move_insn (temp1, gen_rtx_MEM (Pmode, addr));
366 emit_insn (gen_add3_insn (this_rtx, this_rtx, temp1));
369 /* Jump to the target function. */
370 fnaddr = XEXP (DECL_RTL (function), 0);
371 insn = emit_call_insn (gen_sibcall_internal_score3 (fnaddr, const0_rtx));
372 SIBLING_CALL_P (insn) = 1;
374 /* Run just enough of rest_of_compilation. This sequence was
375 "borrowed" from alpha.c. */
376 insn = get_insns ();
377 insn_locators_alloc ();
378 split_all_insns_noflow ();
379 shorten_branches (insn);
380 final_start_function (insn, file, 1);
381 final (insn, file, 1);
382 final_end_function ();
384 /* Clean up the vars set above. Note that final_end_function resets
385 the global pointer for us. */
386 reload_completed = 0;
389 /* Copy VALUE to a register and return that register. If new psuedos
390 are allowed, copy it into a new register, otherwise use DEST. */
391 static rtx
392 score3_force_temporary (rtx dest, rtx value)
394 if (can_create_pseudo_p ())
395 return force_reg (Pmode, value);
396 else
398 emit_move_insn (copy_rtx (dest), value);
399 return dest;
403 /* Return a LO_SUM expression for ADDR. TEMP is as for score_force_temporary
404 and is used to load the high part into a register. */
405 static rtx
406 score3_split_symbol (rtx temp, rtx addr)
408 rtx high = score3_force_temporary (temp,
409 gen_rtx_HIGH (Pmode, copy_rtx (addr)));
410 return gen_rtx_LO_SUM (Pmode, high, addr);
413 /* This function is used to implement LEGITIMIZE_ADDRESS. If X can
414 be legitimized in a way that the generic machinery might not expect,
415 return the new address. */
417 score3_legitimize_address (rtx x)
419 enum score_symbol_type symbol_type;
421 if (score3_symbolic_constant_p (x, &symbol_type)
422 && symbol_type == SYMBOL_GENERAL)
423 return score3_split_symbol (0, x);
425 if (GET_CODE (x) == PLUS
426 && GET_CODE (XEXP (x, 1)) == CONST_INT)
428 rtx reg = XEXP (x, 0);
429 if (!score3_valid_base_register_p (reg, 0))
430 reg = copy_to_mode_reg (Pmode, reg);
431 return score3_add_offset (reg, INTVAL (XEXP (x, 1)));
434 return x;
437 /* Fill INFO with information about a single argument. CUM is the
438 cumulative state for earlier arguments. MODE is the mode of this
439 argument and TYPE is its type (if known). NAMED is true if this
440 is a named (fixed) argument rather than a variable one. */
441 static void
442 score3_classify_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
443 const_tree type, bool named, struct score3_arg_info *info)
445 int even_reg_p;
446 unsigned int num_words, max_regs;
448 even_reg_p = 0;
449 if (GET_MODE_CLASS (mode) == MODE_INT
450 || GET_MODE_CLASS (mode) == MODE_FLOAT)
451 even_reg_p = (GET_MODE_SIZE (mode) > UNITS_PER_WORD);
452 else
453 if (type != NULL_TREE && TYPE_ALIGN (type) > BITS_PER_WORD && named)
454 even_reg_p = 1;
456 if (TARGET_MUST_PASS_IN_STACK (mode, type))
457 info->reg_offset = ARG_REG_NUM;
458 else
460 info->reg_offset = cum->num_gprs;
461 if (even_reg_p)
462 info->reg_offset += info->reg_offset & 1;
465 if (mode == BLKmode)
466 info->num_bytes = int_size_in_bytes (type);
467 else
468 info->num_bytes = GET_MODE_SIZE (mode);
470 num_words = (info->num_bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
471 max_regs = ARG_REG_NUM - info->reg_offset;
473 /* Partition the argument between registers and stack. */
474 info->reg_words = MIN (num_words, max_regs);
475 info->stack_words = num_words - info->reg_words;
477 /* The alignment applied to registers is also applied to stack arguments. */
478 if (info->stack_words)
480 info->stack_offset = cum->stack_words;
481 if (even_reg_p)
482 info->stack_offset += info->stack_offset & 1;
486 /* Set up the stack and frame (if desired) for the function. */
487 void
488 score3_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
490 const char *fnname;
491 struct score3_frame_info *f = score3_cached_frame ();
492 HOST_WIDE_INT tsize = f->total_size;
494 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
495 if (!flag_inhibit_size_directive)
497 fputs ("\t.ent\t", file);
498 assemble_name (file, fnname);
499 fputs ("\n", file);
501 assemble_name (file, fnname);
502 fputs (":\n", file);
504 if (!flag_inhibit_size_directive)
506 fprintf (file,
507 "\t.frame\t%s," HOST_WIDE_INT_PRINT_DEC ",%s, %d\t\t"
508 "# vars= " HOST_WIDE_INT_PRINT_DEC ", regs= %d"
509 ", args= " HOST_WIDE_INT_PRINT_DEC
510 ", gp= " HOST_WIDE_INT_PRINT_DEC "\n",
511 (reg_names[(frame_pointer_needed)
512 ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM]),
513 tsize,
514 reg_names[RA_REGNUM],
515 current_function_is_leaf ? 1 : 0,
516 f->var_size,
517 f->num_gp,
518 f->args_size,
519 f->cprestore_size);
521 fprintf(file, "\t.mask\t0x%08x," HOST_WIDE_INT_PRINT_DEC "\n",
522 f->mask,
523 (f->gp_sp_offset - f->total_size));
527 /* Do any necessary cleanup after a function to restore stack, frame,
528 and regs. */
529 void
530 score3_function_epilogue (FILE *file,
531 HOST_WIDE_INT size ATTRIBUTE_UNUSED)
533 if (!flag_inhibit_size_directive)
535 const char *fnname;
536 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
537 fputs ("\t.end\t", file);
538 assemble_name (file, fnname);
539 fputs ("\n", file);
543 /* Returns true if X contains a SYMBOL_REF. */
544 static bool
545 score3_symbolic_expression_p (rtx x)
547 if (GET_CODE (x) == SYMBOL_REF)
548 return true;
550 if (GET_CODE (x) == CONST)
551 return score3_symbolic_expression_p (XEXP (x, 0));
553 if (UNARY_P (x))
554 return score3_symbolic_expression_p (XEXP (x, 0));
556 if (ARITHMETIC_P (x))
557 return (score3_symbolic_expression_p (XEXP (x, 0))
558 || score3_symbolic_expression_p (XEXP (x, 1)));
560 return false;
563 /* Choose the section to use for the constant rtx expression X that has
564 mode MODE. */
565 section *
566 score3_select_rtx_section (enum machine_mode mode, rtx x,
567 unsigned HOST_WIDE_INT align)
569 if (GET_MODE_SIZE (mode) <= SCORE3_SDATA_MAX)
570 return get_named_section (0, ".sdata", 0);
571 else if (flag_pic && score3_symbolic_expression_p (x))
572 return get_named_section (0, ".data.rel.ro", 3);
573 else
574 return mergeable_constant_section (mode, align, 0);
577 /* Implement TARGET_IN_SMALL_DATA_P. */
578 bool
579 score3_in_small_data_p (const_tree decl)
581 HOST_WIDE_INT size;
583 if (TREE_CODE (decl) == STRING_CST
584 || TREE_CODE (decl) == FUNCTION_DECL)
585 return false;
587 if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl) != 0)
589 const char *name;
590 name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
591 if (strcmp (name, ".sdata") != 0
592 && strcmp (name, ".sbss") != 0)
593 return true;
594 if (!DECL_EXTERNAL (decl))
595 return false;
597 size = int_size_in_bytes (TREE_TYPE (decl));
598 return (size > 0 && size <= SCORE3_SDATA_MAX);
601 /* Implement TARGET_ASM_FILE_START. */
602 void
603 score3_asm_file_start (void)
605 default_file_start ();
606 fprintf (asm_out_file, ASM_COMMENT_START
607 "GCC for S+core %s \n", SCORE_GCC_VERSION);
609 if (flag_pic)
610 fprintf (asm_out_file, "\t.set pic\n");
613 /* Implement TARGET_ASM_FILE_END. When using assembler macros, emit
614 .externs for any small-data variables that turned out to be external. */
615 void
616 score3_asm_file_end (void)
618 tree name_tree;
619 struct extern_list *p;
620 if (extern_head)
622 fputs ("\n", asm_out_file);
623 for (p = extern_head; p != 0; p = p->next)
625 name_tree = get_identifier (p->name);
626 if (!TREE_ASM_WRITTEN (name_tree)
627 && TREE_SYMBOL_REFERENCED (name_tree))
629 TREE_ASM_WRITTEN (name_tree) = 1;
630 fputs ("\t.extern\t", asm_out_file);
631 assemble_name (asm_out_file, p->name);
632 fprintf (asm_out_file, ", %d\n", p->size);
638 /* Implement TARGET_OPTION_OVERRIDE hook. */
639 void
640 score3_option_override (void)
642 flag_pic = false;
643 if (!flag_pic)
644 score3_sdata_max = (global_options_set.x_g_switch_value
645 ? g_switch_value
646 : SCORE3_DEFAULT_SDATA_MAX);
647 else
649 score3_sdata_max = 0;
650 if (global_options_set.x_g_switch_value && (g_switch_value != 0))
651 warning (0, "-fPIC and -G are incompatible");
654 score_char_to_class['d'] = G32_REGS;
655 score_char_to_class['e'] = G16_REGS;
656 score_char_to_class['t'] = T32_REGS;
658 score_char_to_class['h'] = HI_REG;
659 score_char_to_class['l'] = LO_REG;
660 score_char_to_class['x'] = CE_REGS;
662 score_char_to_class['q'] = CN_REG;
663 score_char_to_class['y'] = LC_REG;
664 score_char_to_class['z'] = SC_REG;
665 score_char_to_class['a'] = SP_REGS;
667 score_char_to_class['c'] = CR_REGS;
670 /* Implement REGNO_REG_CLASS macro. */
672 score3_reg_class (int regno)
674 int c;
675 gcc_assert (regno >= 0 && regno < FIRST_PSEUDO_REGISTER);
677 if (regno == FRAME_POINTER_REGNUM
678 || regno == ARG_POINTER_REGNUM)
679 return ALL_REGS;
681 for (c = 0; c < N_REG_CLASSES; c++)
682 if (TEST_HARD_REG_BIT (reg_class_contents[c], regno))
683 return c;
685 return NO_REGS;
688 /* Implement PREFERRED_RELOAD_CLASS macro. */
689 enum reg_class
690 score3_preferred_reload_class (rtx x ATTRIBUTE_UNUSED, enum reg_class rclass)
692 if (reg_class_subset_p (G16_REGS, rclass))
693 return G16_REGS;
694 if (reg_class_subset_p (G32_REGS, rclass))
695 return G32_REGS;
696 return rclass;
699 /* Implement SECONDARY_INPUT_RELOAD_CLASS
700 and SECONDARY_OUTPUT_RELOAD_CLASS macro. */
701 enum reg_class
702 score3_secondary_reload_class (enum reg_class rclass,
703 enum machine_mode mode ATTRIBUTE_UNUSED,
704 rtx x)
706 int regno = -1;
707 if (GET_CODE (x) == REG || GET_CODE(x) == SUBREG)
708 regno = true_regnum (x);
710 if (!GR_REG_CLASS_P (rclass))
711 return GP_REG_P (regno) ? NO_REGS : G32_REGS;
712 return NO_REGS;
715 /* Implement CONST_OK_FOR_LETTER_P macro. */
716 /* imm constraints
717 I imm16 << 16
718 J uimm5
719 K uimm16
720 L simm16
721 M uimm14
722 N simm14
723 O simm14
724 P simm5
725 Q uimm32 */
727 score3_const_ok_for_letter_p (HOST_WIDE_INT value, char c)
729 switch (c)
731 case 'I': return ((value & 0xffff) == 0);
732 case 'J': return IMM_IN_RANGE (value, 5, 0);
733 case 'K': return IMM_IN_RANGE (value, 16, 0);
734 case 'L': return IMM_IN_RANGE (value, 16, 1);
735 case 'M': return IMM_IN_RANGE (value, 14, 0);
736 case 'N': return IMM_IN_RANGE (value, 14, 1);
737 case 'O': return IMM_IN_RANGE (value, 5, 1);
738 case 'P': return IMM_IN_RANGE (value, 6, 1);
739 case 'Q': return score_extra_constraint (GEN_INT(value), c);
740 default : return 0;
744 /* Implement EXTRA_CONSTRAINT macro. */
746 Q uimm32
747 Z symbol_ref */
749 score3_extra_constraint (rtx op, char c)
751 switch (c)
753 case 'Q': return IMM_IN_RANGE (INTVAL(op), 32, 0);
754 case 'Z':
755 return GET_CODE (op) == SYMBOL_REF;
756 default:
757 gcc_unreachable ();
761 /* Return truth value on whether or not a given hard register
762 can support a given mode. */
764 score3_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
766 int size = GET_MODE_SIZE (mode);
767 enum mode_class mclass = GET_MODE_CLASS (mode);
769 if (mclass == MODE_CC)
770 return regno == CC_REGNUM;
771 else if (regno == FRAME_POINTER_REGNUM
772 || regno == ARG_POINTER_REGNUM)
773 return mclass == MODE_INT;
774 else if (GP_REG_P (regno))
775 return !(regno & 1) || (size <= UNITS_PER_WORD);
776 else if (CE_REG_P (regno))
777 return (mclass == MODE_INT
778 && ((size <= UNITS_PER_WORD)
779 || (regno == CE_REG_FIRST && size == 2 * UNITS_PER_WORD)));
780 else
781 return (mclass == MODE_INT) && (size <= UNITS_PER_WORD);
784 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
785 pointer or argument pointer. TO is either the stack pointer or
786 hard frame pointer. */
787 HOST_WIDE_INT
788 score3_initial_elimination_offset (int from,
789 int to ATTRIBUTE_UNUSED)
791 struct score3_frame_info *f = score3_compute_frame_size (get_frame_size ());
792 switch (from)
794 case ARG_POINTER_REGNUM:
795 return f->total_size;
796 case FRAME_POINTER_REGNUM:
797 return 0;
798 default:
799 gcc_unreachable ();
803 /* Implement TARGET_FUNCTION_ARG_ADVANCE hook. */
804 void
805 score3_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
806 const_tree type, bool named)
808 struct score3_arg_info info;
809 score3_classify_arg (cum, mode, type, named, &info);
810 cum->num_gprs = info.reg_offset + info.reg_words;
811 if (info.stack_words > 0)
812 cum->stack_words = info.stack_offset + info.stack_words;
813 cum->arg_number++;
816 /* Implement TARGET_ARG_PARTIAL_BYTES macro. */
818 score3_arg_partial_bytes (CUMULATIVE_ARGS *cum,
819 enum machine_mode mode, tree type, bool named)
821 struct score3_arg_info info;
822 score3_classify_arg (cum, mode, type, named, &info);
823 return info.stack_words > 0 ? info.reg_words * UNITS_PER_WORD : 0;
826 /* Implement TARGET_FUNCTION_ARG hook. */
828 score3_function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
829 const_tree type, bool named)
831 struct score3_arg_info info;
833 if (mode == VOIDmode || !named)
834 return 0;
836 score3_classify_arg (cum, mode, type, named, &info);
838 if (info.reg_offset == ARG_REG_NUM)
839 return 0;
841 if (!info.stack_words)
842 return gen_rtx_REG (mode, ARG_REG_FIRST + info.reg_offset);
843 else
845 rtx ret = gen_rtx_PARALLEL (mode, rtvec_alloc (info.reg_words));
846 unsigned int i, part_offset = 0;
847 for (i = 0; i < info.reg_words; i++)
849 rtx reg;
850 reg = gen_rtx_REG (SImode, ARG_REG_FIRST + info.reg_offset + i);
851 XVECEXP (ret, 0, i) = gen_rtx_EXPR_LIST (SImode, reg,
852 GEN_INT (part_offset));
853 part_offset += UNITS_PER_WORD;
855 return ret;
859 /* Implement FUNCTION_VALUE and LIBCALL_VALUE. For normal calls,
860 VALTYPE is the return type and MODE is VOIDmode. For libcalls,
861 VALTYPE is null and MODE is the mode of the return value. */
863 score3_function_value (const_tree valtype, const_tree func,
864 enum machine_mode mode)
866 if (valtype)
868 int unsignedp;
869 mode = TYPE_MODE (valtype);
870 unsignedp = TYPE_UNSIGNED (valtype);
871 mode = promote_function_mode (valtype, mode, &unsignedp, func, 1);
873 return gen_rtx_REG (mode, RT_REGNUM);
876 /* Implement TARGET_ASM_TRAMPOLINE_TEMPLATE. */
878 void
879 score3_asm_trampoline_template (FILE *f)
881 fprintf (f, "\t.set r1\n");
882 fprintf (f, "\tmv! r31, r3\n");
883 fprintf (f, "\tnop!\n");
884 fprintf (f, "\tbl nextinsn\n");
885 fprintf (f, "nextinsn:\n");
886 fprintf (f, "\tlw! r1, [r3, 6*4-8]\n");
887 fprintf (f, "\tnop!\n");
888 fprintf (f, "\tlw r23, [r3, 6*4-4]\n");
889 fprintf (f, "\tmv! r3, r31\n");
890 fprintf (f, "\tnop!\n");
891 fprintf (f, "\tbr! r1\n");
892 fprintf (f, "\tnop!\n");
893 fprintf (f, "\t.set nor1\n");
896 /* Implement TARGET_TRAMPOLINE_INIT. */
897 void
898 score3_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
900 #define FFCACHE "_flush_cache"
901 #define CODE_SIZE (TRAMPOLINE_INSNS * UNITS_PER_WORD)
903 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
904 rtx addr = XEXP (m_tramp, 0);
905 rtx mem;
907 emit_block_move (m_tramp, assemble_trampoline_template (),
908 GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
910 mem = adjust_address (m_tramp, SImode, CODE_SIZE);
911 emit_move_insn (mem, fnaddr);
912 mem = adjust_address (m_tramp, SImode, CODE_SIZE + GET_MODE_SIZE (SImode));
913 emit_move_insn (mem, chain_value);
915 emit_library_call (gen_rtx_SYMBOL_REF (Pmode, FFCACHE),
916 LCT_NORMAL, VOIDmode, 2,
917 addr, Pmode,
918 GEN_INT (TRAMPOLINE_SIZE), SImode);
919 #undef FFCACHE
920 #undef CODE_SIZE
923 /* This function is used to implement REG_MODE_OK_FOR_BASE_P macro. */
925 score3_regno_mode_ok_for_base_p (int regno, int strict)
927 if (regno >= FIRST_PSEUDO_REGISTER)
929 if (!strict)
930 return 1;
931 regno = reg_renumber[regno];
933 if (regno == ARG_POINTER_REGNUM
934 || regno == FRAME_POINTER_REGNUM)
935 return 1;
936 return GP_REG_P (regno);
939 /* Implement TARGET_LEGITIMATE_ADDRESS_P macro. */
940 bool
941 score3_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
943 struct score3_address_info addr;
945 return score3_classify_address (&addr, mode, x, strict);
948 /* Return a number assessing the cost of moving a register in class
949 FROM to class TO. */
951 score3_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
952 enum reg_class from, enum reg_class to)
954 if (GR_REG_CLASS_P (from))
956 if (GR_REG_CLASS_P (to))
957 return 2;
958 else if (SP_REG_CLASS_P (to))
959 return 4;
960 else if (CP_REG_CLASS_P (to))
961 return 5;
962 else if (CE_REG_CLASS_P (to))
963 return 6;
965 if (GR_REG_CLASS_P (to))
967 if (GR_REG_CLASS_P (from))
968 return 2;
969 else if (SP_REG_CLASS_P (from))
970 return 4;
971 else if (CP_REG_CLASS_P (from))
972 return 5;
973 else if (CE_REG_CLASS_P (from))
974 return 6;
976 return 12;
979 /* Return the number of instructions needed to load a symbol of the
980 given type into a register. */
981 static int
982 score3_symbol_insns (enum score_symbol_type type)
984 switch (type)
986 case SYMBOL_GENERAL:
987 return 2;
989 case SYMBOL_SMALL_DATA:
990 return 1;
993 gcc_unreachable ();
996 /* Return the number of instructions needed to load or store a value
997 of mode MODE at X. Return 0 if X isn't valid for MODE. */
998 static int
999 score3_address_insns (rtx x, enum machine_mode mode)
1001 struct score3_address_info addr;
1002 int factor;
1004 if (mode == BLKmode)
1005 factor = 1;
1006 else
1007 factor = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
1009 if (score3_classify_address (&addr, mode, x, false))
1010 switch (addr.type)
1012 case SCORE3_ADD_REG:
1013 case SCORE3_ADD_CONST_INT:
1014 return factor;
1016 case SCORE3_ADD_SYMBOLIC:
1017 return factor * score3_symbol_insns (addr.symbol_type);
1019 return 0;
1022 /* Implement TARGET_RTX_COSTS macro. */
1023 bool
1024 score3_rtx_costs (rtx x, int code, int outer_code, int *total,
1025 bool speed ATTRIBUTE_UNUSED)
1027 enum machine_mode mode = GET_MODE (x);
1029 switch (code)
1031 case CONST_INT:
1032 if (outer_code == SET)
1034 if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
1035 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L'))
1036 *total = COSTS_N_INSNS (1);
1037 else
1038 *total = COSTS_N_INSNS (2);
1040 else if (outer_code == PLUS || outer_code == MINUS)
1042 if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'N'))
1043 *total = 0;
1044 else if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
1045 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L'))
1046 *total = 1;
1047 else
1048 *total = COSTS_N_INSNS (2);
1050 else if (outer_code == AND || outer_code == IOR)
1052 if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'M'))
1053 *total = 0;
1054 else if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
1055 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'K'))
1056 *total = 1;
1057 else
1058 *total = COSTS_N_INSNS (2);
1060 else
1062 *total = 0;
1064 return true;
1066 case CONST:
1067 case SYMBOL_REF:
1068 case LABEL_REF:
1069 case CONST_DOUBLE:
1070 *total = COSTS_N_INSNS (2);
1071 return true;
1073 case MEM:
1075 /* If the address is legitimate, return the number of
1076 instructions it needs, otherwise use the default handling. */
1077 int n = score3_address_insns (XEXP (x, 0), GET_MODE (x));
1078 if (n > 0)
1080 *total = COSTS_N_INSNS (n + 1);
1081 return true;
1083 return false;
1086 case FFS:
1087 *total = COSTS_N_INSNS (6);
1088 return true;
1090 case NOT:
1091 *total = COSTS_N_INSNS (1);
1092 return true;
1094 case AND:
1095 case IOR:
1096 case XOR:
1097 if (mode == DImode)
1099 *total = COSTS_N_INSNS (2);
1100 return true;
1102 return false;
1104 case ASHIFT:
1105 case ASHIFTRT:
1106 case LSHIFTRT:
1107 if (mode == DImode)
1109 *total = COSTS_N_INSNS ((GET_CODE (XEXP (x, 1)) == CONST_INT)
1110 ? 4 : 12);
1111 return true;
1113 return false;
1115 case ABS:
1116 *total = COSTS_N_INSNS (4);
1117 return true;
1119 case PLUS:
1120 case MINUS:
1121 if (mode == DImode)
1123 *total = COSTS_N_INSNS (4);
1124 return true;
1126 *total = COSTS_N_INSNS (1);
1127 return true;
1129 case NEG:
1130 if (mode == DImode)
1132 *total = COSTS_N_INSNS (4);
1133 return true;
1135 return false;
1137 case MULT:
1138 *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (12);
1139 return true;
1141 case DIV:
1142 case MOD:
1143 case UDIV:
1144 case UMOD:
1145 *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (33);
1146 return true;
1148 case SIGN_EXTEND:
1149 case ZERO_EXTEND:
1150 switch (GET_MODE (XEXP (x, 0)))
1152 case QImode:
1153 case HImode:
1154 if (GET_CODE (XEXP (x, 0)) == MEM)
1156 *total = COSTS_N_INSNS (2);
1158 if (!TARGET_LITTLE_ENDIAN &&
1159 side_effects_p (XEXP (XEXP (x, 0), 0)))
1160 *total = 100;
1162 else
1163 *total = COSTS_N_INSNS (1);
1164 break;
1166 default:
1167 *total = COSTS_N_INSNS (1);
1168 break;
1170 return true;
1172 default:
1173 return false;
1177 /* Implement TARGET_ADDRESS_COST macro. */
1179 score3_address_cost (rtx addr)
1181 return score3_address_insns (addr, SImode);
1184 /* Implement ASM_OUTPUT_EXTERNAL macro. */
1186 score3_output_external (FILE *file ATTRIBUTE_UNUSED,
1187 tree decl, const char *name)
1189 register struct extern_list *p;
1191 if (score3_in_small_data_p (decl))
1193 p = ggc_alloc_extern_list ();
1194 p->next = extern_head;
1195 p->name = name;
1196 p->size = int_size_in_bytes (TREE_TYPE (decl));
1197 extern_head = p;
1199 return 0;
1202 /* Implement RETURN_ADDR_RTX. Note, we do not support moving
1203 back to a previous frame. */
1205 score3_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
1207 if (count != 0)
1208 return const0_rtx;
1209 return get_hard_reg_initial_val (Pmode, RA_REGNUM);
1212 /* Implement PRINT_OPERAND macro. */
1213 /* Score-specific operand codes:
1214 '[' print .set nor1 directive
1215 ']' print .set r1 directive
1216 'U' print hi part of a CONST_INT rtx
1217 'E' print log2(v)
1218 'F' print log2(~v)
1219 'D' print SFmode const double
1220 'S' selectively print "!" if operand is 15bit instruction accessible
1221 'V' print "v!" if operand is 15bit instruction accessible, or "lfh!"
1222 'L' low part of DImode reg operand
1223 'H' high part of DImode reg operand
1224 'C' print part of opcode for a branch condition. */
1225 void
1226 score3_print_operand (FILE *file, rtx op, int c)
1228 enum rtx_code code = UNKNOWN;
1229 if (!PRINT_OPERAND_PUNCT_VALID_P (c))
1230 code = GET_CODE (op);
1232 if (c == '[')
1234 fprintf (file, ".set r1\n");
1236 else if (c == ']')
1238 fprintf (file, "\n\t.set nor1");
1240 else if (c == 'U')
1242 gcc_assert (code == CONST_INT);
1243 fprintf (file, HOST_WIDE_INT_PRINT_HEX,
1244 (INTVAL (op) >> 16) & 0xffff);
1246 else if (c == 'D')
1248 if (GET_CODE (op) == CONST_DOUBLE)
1250 rtx temp = gen_lowpart (SImode, op);
1251 gcc_assert (GET_MODE (op) == SFmode);
1252 fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (temp) & 0xffffffff);
1254 else
1255 output_addr_const (file, op);
1257 else if (c == 'S')
1259 gcc_assert (code == REG);
1260 if (G16_REG_P (REGNO (op)))
1261 fprintf (file, "!");
1263 else if (c == 'V')
1265 gcc_assert (code == REG);
1266 fprintf (file, G16_REG_P (REGNO (op)) ? "v!" : "lfh!");
1268 else if (c == 'C')
1270 enum machine_mode mode = GET_MODE (XEXP (op, 0));
1272 switch (code)
1274 case EQ: fputs ("eq!", file); break;
1275 case NE: fputs ("ne!", file); break;
1276 case GT: fputs ("gt!", file); break;
1277 case GE: fputs (mode != CCmode ? "pl" : "ge", file); break;
1278 case LT: fputs (mode != CCmode ? "mi" : "lt", file); break;
1279 case LE: fputs ("le!", file); break;
1280 case GTU: fputs ("gtu!", file); break;
1281 case GEU: fputs ("cs", file); break;
1282 case LTU: fputs ("cc", file); break;
1283 case LEU: fputs ("leu!", file); break;
1284 default:
1285 output_operand_lossage ("invalid operand for code: '%c'", code);
1288 else if (c == 'G') /* Seperate from b<cond>, use for mv<cond>. */
1290 enum machine_mode mode = GET_MODE (XEXP (op, 0));
1292 switch (code)
1294 case EQ: fputs ("eq", file); break;
1295 case NE: fputs ("ne", file); break;
1296 case GT: fputs ("gt", file); break;
1297 case GE: fputs (mode != CCmode ? "pl" : "ge", file); break;
1298 case LT: fputs (mode != CCmode ? "mi" : "lt", file); break;
1299 case LE: fputs ("le", file); break;
1300 case GTU: fputs ("gtu", file); break;
1301 case GEU: fputs ("cs", file); break;
1302 case LTU: fputs ("cc", file); break;
1303 case LEU: fputs ("leu", file); break;
1304 default:
1305 output_operand_lossage ("invalid operand for code: '%c'", code);
1308 else if (c == 'E')
1310 unsigned HOST_WIDE_INT i;
1311 unsigned HOST_WIDE_INT pow2mask = 1;
1312 unsigned HOST_WIDE_INT val;
1314 val = INTVAL (op);
1315 for (i = 0; i < 32; i++)
1317 if (val == pow2mask)
1318 break;
1319 pow2mask <<= 1;
1321 gcc_assert (i < 32);
1322 fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
1324 else if (c == 'F')
1326 unsigned HOST_WIDE_INT i;
1327 unsigned HOST_WIDE_INT pow2mask = 1;
1328 unsigned HOST_WIDE_INT val;
1330 val = ~INTVAL (op);
1331 for (i = 0; i < 32; i++)
1333 if (val == pow2mask)
1334 break;
1335 pow2mask <<= 1;
1337 gcc_assert (i < 32);
1338 fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
1340 else if (code == REG)
1342 int regnum = REGNO (op);
1343 if ((c == 'H' && !WORDS_BIG_ENDIAN)
1344 || (c == 'L' && WORDS_BIG_ENDIAN))
1345 regnum ++;
1346 fprintf (file, "%s", reg_names[regnum]);
1348 else
1350 switch (code)
1352 case MEM:
1353 score3_print_operand_address (file, op);
1354 break;
1355 default:
1356 output_addr_const (file, op);
1361 /* Implement PRINT_OPERAND_ADDRESS macro. */
1362 void
1363 score3_print_operand_address (FILE *file, rtx x)
1365 struct score3_address_info addr;
1366 enum rtx_code code = GET_CODE (x);
1367 enum machine_mode mode = GET_MODE (x);
1369 if (code == MEM)
1370 x = XEXP (x, 0);
1372 if (score3_classify_address (&addr, mode, x, true))
1374 switch (addr.type)
1376 case SCORE3_ADD_REG:
1378 switch (addr.code)
1380 case PRE_DEC:
1381 fprintf (file, "[%s,-%ld]+", reg_names[REGNO (addr.reg)],
1382 INTVAL (addr.offset));
1383 break;
1384 case POST_DEC:
1385 fprintf (file, "[%s]+,-%ld", reg_names[REGNO (addr.reg)],
1386 INTVAL (addr.offset));
1387 break;
1388 case PRE_INC:
1389 fprintf (file, "[%s, %ld]+", reg_names[REGNO (addr.reg)],
1390 INTVAL (addr.offset));
1391 break;
1392 case POST_INC:
1393 fprintf (file, "[%s]+, %ld", reg_names[REGNO (addr.reg)],
1394 INTVAL (addr.offset));
1395 break;
1396 default:
1397 if (INTVAL(addr.offset) == 0)
1398 fprintf(file, "[%s]", reg_names[REGNO (addr.reg)]);
1399 else
1400 fprintf(file, "[%s, %ld]", reg_names[REGNO (addr.reg)],
1401 INTVAL(addr.offset));
1402 break;
1405 return;
1406 case SCORE3_ADD_CONST_INT:
1407 case SCORE3_ADD_SYMBOLIC:
1408 output_addr_const (file, x);
1409 return;
1412 print_rtl (stderr, x);
1413 gcc_unreachable ();
1416 /* Implement SELECT_CC_MODE macro. */
1417 enum machine_mode
1418 score3_select_cc_mode (enum rtx_code op, rtx x, rtx y)
1420 if ((op == EQ || op == NE || op == LT || op == GE)
1421 && y == const0_rtx
1422 && GET_MODE (x) == SImode)
1424 switch (GET_CODE (x))
1426 case PLUS:
1427 case MINUS:
1428 case NEG:
1429 case AND:
1430 case IOR:
1431 case XOR:
1432 case NOT:
1433 case ASHIFT:
1434 case LSHIFTRT:
1435 case ASHIFTRT:
1436 return CC_NZmode;
1438 case SIGN_EXTEND:
1439 case ZERO_EXTEND:
1440 case ROTATE:
1441 case ROTATERT:
1442 return (op == LT || op == GE) ? CC_Nmode : CCmode;
1444 default:
1445 return CCmode;
1449 if ((op == EQ || op == NE)
1450 && (GET_CODE (y) == NEG)
1451 && register_operand (XEXP (y, 0), SImode)
1452 && register_operand (x, SImode))
1454 return CC_NZmode;
1457 return CCmode;
1460 #define EMIT_PL(_rtx) RTX_FRAME_RELATED_P (_rtx) = 1
1461 /* return 0, no more bit set in mask. */
1462 static int rpush_first (int mask, int sb, int *rd)
1464 int i, cnt = 1;
1466 if ((mask & (1 << sb)) == 0)
1467 return 0;
1469 *rd = sb;
1471 for (i = sb-1; i >= 0; i--)
1473 if (mask & (1 << i))
1475 cnt ++;
1476 continue;
1479 *rd = i+1;
1480 break;;
1483 return cnt;
1486 static void
1487 rpush (int rd, int cnt)
1489 rtx mem = gen_rtx_MEM (SImode, gen_rtx_PRE_DEC (SImode, stack_pointer_rtx));
1490 rtx reg = gen_rtx_REG (SImode, rd);
1492 if (!crtl->calls_eh_return)
1493 MEM_READONLY_P (mem) = 1;
1495 if (cnt == 1)
1496 EMIT_PL (emit_insn (gen_pushsi_score3 (mem, reg)));
1497 else
1499 int i;
1500 rtx insn = gen_store_multiple (gen_rtx_MEM (SImode, stack_pointer_rtx),
1501 gen_rtx_REG (SImode, rd),
1502 GEN_INT (cnt));
1504 rtx pat = PATTERN (insn);
1506 for (i = 0; i < XVECLEN (pat, 0); i++)
1507 if (GET_CODE (XVECEXP (pat, 0, i)) == SET)
1508 RTX_FRAME_RELATED_P (XVECEXP (pat, 0, i)) = 1;
1510 EMIT_PL (emit_insn (insn));
1514 /* Generate the prologue instructions for entry into a S+core function. */
1515 void
1516 score3_prologue (void)
1518 struct score3_frame_info *f = score3_compute_frame_size (get_frame_size ());
1519 HOST_WIDE_INT size;
1520 int regno;
1522 size = f->total_size - f->gp_reg_size;
1524 if (flag_pic)
1525 emit_insn (gen_cpload_score3 ());
1528 int cnt, rd;
1530 for (regno = (int) GP_REG_LAST; regno >= (int) GP_REG_FIRST; regno--)
1532 cnt = rpush_first (f->mask, regno, &rd);
1533 if (cnt != 0)
1535 rpush (rd, cnt);
1536 regno = regno - cnt;
1541 if (size > 0)
1543 rtx insn;
1545 if (CONST_OK_FOR_LETTER_P (-size, 'L'))
1546 EMIT_PL (emit_insn (gen_add3_insn (stack_pointer_rtx,
1547 stack_pointer_rtx,
1548 GEN_INT (-size))));
1549 else
1551 EMIT_PL (emit_move_insn (gen_rtx_REG (Pmode, SCORE3_PROLOGUE_TEMP_REGNUM),
1552 GEN_INT (size)));
1553 EMIT_PL (emit_insn
1554 (gen_sub3_insn (stack_pointer_rtx,
1555 stack_pointer_rtx,
1556 gen_rtx_REG (Pmode,
1557 SCORE3_PROLOGUE_TEMP_REGNUM))));
1559 insn = get_last_insn ();
1560 REG_NOTES (insn) =
1561 alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR,
1562 gen_rtx_SET (VOIDmode, stack_pointer_rtx,
1563 plus_constant (stack_pointer_rtx,
1564 -size)),
1565 REG_NOTES (insn));
1568 if (frame_pointer_needed)
1569 EMIT_PL (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx));
1571 if (flag_pic && f->cprestore_size)
1573 if (frame_pointer_needed)
1574 emit_insn (gen_cprestore_use_fp_score3 (GEN_INT (size - f->cprestore_size)));
1575 else
1576 emit_insn (gen_cprestore_use_sp_score3 (GEN_INT (size - f->cprestore_size)));
1580 /* return 0, no more bit set in mask. */
1581 static int
1582 rpop_first (int mask, int sb, int *rd)
1584 int i, cnt = 1;
1586 if ((mask & (1 << sb)) == 0)
1587 return 0;
1589 *rd = sb;
1591 for (i = sb+1; i < 32; i++)
1592 if (mask & (1 << i))
1593 cnt++;
1594 else
1595 break;;
1597 return cnt;
1600 static void
1601 rpop (int rd, int cnt)
1603 rtx mem = gen_rtx_MEM (SImode, gen_rtx_POST_INC (SImode, stack_pointer_rtx));
1604 rtx reg = gen_rtx_REG (SImode, rd);
1606 if (!crtl->calls_eh_return)
1607 MEM_READONLY_P (mem) = 1;
1609 if (cnt == 1)
1610 emit_insn (gen_popsi_score3 (reg, mem));
1611 else
1612 emit_insn (gen_load_multiple (reg,
1613 gen_rtx_MEM (SImode, stack_pointer_rtx),
1614 GEN_INT (cnt)));
1617 /* Generate the epilogue instructions in a S+core function. */
1618 void
1619 score3_epilogue (int sibcall_p)
1621 struct score3_frame_info *f = score3_compute_frame_size (get_frame_size ());
1622 HOST_WIDE_INT size;
1623 int regno;
1624 rtx base;
1626 size = f->total_size - f->gp_reg_size;
1628 if (!frame_pointer_needed)
1629 base = stack_pointer_rtx;
1630 else
1631 base = hard_frame_pointer_rtx;
1633 if (size)
1635 if (CONST_OK_FOR_LETTER_P (size, 'L'))
1636 emit_insn (gen_add3_insn (base, base, GEN_INT (size)));
1637 else
1639 emit_move_insn (gen_rtx_REG (Pmode, SCORE3_EPILOGUE_TEMP_REGNUM),
1640 GEN_INT (size));
1641 emit_insn (gen_add3_insn (base, base,
1642 gen_rtx_REG (Pmode,
1643 SCORE3_EPILOGUE_TEMP_REGNUM)));
1647 if (base != stack_pointer_rtx)
1648 emit_move_insn (stack_pointer_rtx, base);
1650 if (crtl->calls_eh_return)
1651 emit_insn (gen_add3_insn (stack_pointer_rtx,
1652 stack_pointer_rtx,
1653 EH_RETURN_STACKADJ_RTX));
1656 int cnt, rd;
1658 for (regno = (int) GP_REG_FIRST; regno <= (int) GP_REG_LAST; regno++)
1660 cnt = rpop_first (f->mask, regno, &rd);
1661 if (cnt != 0)
1663 rpop (rd, cnt);
1664 regno = regno + cnt;
1669 if (!sibcall_p)
1670 emit_jump_insn (gen_return_internal_score3 (gen_rtx_REG (Pmode, RA_REGNUM)));
1673 /* Return true if X is a symbolic constant that can be calculated in
1674 the same way as a bare symbol. If it is, store the type of the
1675 symbol in *SYMBOL_TYPE. */
1677 score3_symbolic_constant_p (rtx x, enum score_symbol_type *symbol_type)
1679 HOST_WIDE_INT offset;
1681 score3_split_const (x, &x, &offset);
1682 if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF)
1683 *symbol_type = score3_classify_symbol (x);
1684 else
1685 return 0;
1687 if (offset == 0)
1688 return 1;
1690 /* if offset > 15bit, must reload */
1691 if (!IMM_IN_RANGE (offset, 15, 1))
1692 return 0;
1694 switch (*symbol_type)
1696 case SYMBOL_GENERAL:
1697 return 1;
1698 case SYMBOL_SMALL_DATA:
1699 return score3_offset_within_object_p (x, offset);
1701 gcc_unreachable ();
1704 void
1705 score3_movsicc (rtx *ops)
1707 enum machine_mode mode;
1709 mode = score3_select_cc_mode (GET_CODE (ops[1]), ops[2], ops[3]);
1710 emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (mode, CC_REGNUM),
1711 gen_rtx_COMPARE (mode, XEXP (ops[1], 0),
1712 XEXP (ops[1], 1))));
1715 /* Call and sibcall pattern all need call this function. */
1716 void
1717 score3_call (rtx *ops, bool sib)
1719 rtx addr = XEXP (ops[0], 0);
1720 if (!call_insn_operand (addr, VOIDmode))
1722 rtx oaddr = addr;
1723 addr = gen_reg_rtx (Pmode);
1724 gen_move_insn (addr, oaddr);
1727 if (sib)
1728 emit_call_insn (gen_sibcall_internal_score3 (addr, ops[1]));
1729 else
1730 emit_call_insn (gen_call_internal_score3 (addr, ops[1]));
1733 /* Call value and sibcall value pattern all need call this function. */
1734 void
1735 score3_call_value (rtx *ops, bool sib)
1737 rtx result = ops[0];
1738 rtx addr = XEXP (ops[1], 0);
1739 rtx arg = ops[2];
1741 if (!call_insn_operand (addr, VOIDmode))
1743 rtx oaddr = addr;
1744 addr = gen_reg_rtx (Pmode);
1745 gen_move_insn (addr, oaddr);
1748 if (sib)
1749 emit_call_insn (gen_sibcall_value_internal_score3 (result, addr, arg));
1750 else
1751 emit_call_insn (gen_call_value_internal_score3 (result, addr, arg));
1754 /* Machine Split */
1755 void
1756 score3_movdi (rtx *ops)
1758 rtx dst = ops[0];
1759 rtx src = ops[1];
1760 rtx dst0 = score3_subw (dst, 0);
1761 rtx dst1 = score3_subw (dst, 1);
1762 rtx src0 = score3_subw (src, 0);
1763 rtx src1 = score3_subw (src, 1);
1765 if (GET_CODE (dst0) == REG && reg_overlap_mentioned_p (dst0, src))
1767 emit_move_insn (dst1, src1);
1768 emit_move_insn (dst0, src0);
1770 else
1772 emit_move_insn (dst0, src0);
1773 emit_move_insn (dst1, src1);
1777 void
1778 score3_zero_extract_andi (rtx *ops)
1780 if (INTVAL (ops[1]) == 1 && const_uimm5 (ops[2], SImode))
1781 emit_insn (gen_zero_extract_bittst_score3 (ops[0], ops[2]));
1782 else
1784 unsigned HOST_WIDE_INT mask;
1785 mask = (0xffffffffU & ((1U << INTVAL (ops[1])) - 1U));
1786 mask = mask << INTVAL (ops[2]);
1787 emit_insn (gen_andsi3_cmp_score3 (ops[3], ops[0],
1788 gen_int_mode (mask, SImode)));
1792 const char *
1793 score3_rpush (rtx *ops)
1795 snprintf (score3_ins, INS_BUF_SZ, "rpush!\t%%1, %d", XVECLEN (ops[0], 0));
1796 return score3_ins;
1799 const char *
1800 score3_rpop (rtx *ops)
1802 snprintf (score3_ins, INS_BUF_SZ, "rpop!\t%%1, %d", XVECLEN (ops[0], 0));
1803 return score3_ins;
1806 /* Output asm code for ld/sw insn. */
1807 static int
1808 score3_pr_addr_post (rtx *ops, int idata, int iaddr, char *ip,
1809 enum score_mem_unit unit ATTRIBUTE_UNUSED)
1811 struct score3_address_info ai;
1813 gcc_assert (GET_CODE (ops[idata]) == REG);
1814 gcc_assert (score3_classify_address (&ai, SImode, XEXP (ops[iaddr], 0), true));
1816 if (ai.type == SCORE3_ADD_REG
1817 && ai.code == REG
1818 && GET_CODE (ai.offset) == CONST_INT
1819 && G16_REG_P (REGNO (ops[idata]))
1820 && G8_REG_P (REGNO (ai.reg))
1821 && ((INTVAL (ai.offset) & 3) == 0)
1822 && (IMM_IN_RANGE (INTVAL (ai.offset), 7, 0)))
1824 ops[iaddr] = ai.reg;
1825 return snprintf (ip, INS_BUF_SZ, "!\t%%%d, [%%%d, "
1826 HOST_WIDE_INT_PRINT_DEC "]",
1827 idata, iaddr, INTVAL (ai.offset));
1830 if (ai.type == SCORE3_ADD_SYMBOLIC)
1831 return snprintf (ip, INS_BUF_SZ, "48\t%%%d, %%a%d", idata, iaddr);
1833 return snprintf (ip, INS_BUF_SZ, "\t%%%d, %%a%d", idata, iaddr);
1836 /* Output asm insn for load. */
1837 const char *
1838 score3_linsn (rtx *ops, enum score_mem_unit unit, bool sign)
1840 const char *pre_ins[] =
1841 {"lbu", "lhu", "lw", "??", "lb", "lh", "lw", "??"};
1842 char *ip;
1844 strcpy (score3_ins, pre_ins[(sign ? 4 : 0) + unit]);
1845 ip = score3_ins + strlen (score3_ins);
1847 if (unit == SCORE_WORD)
1848 score3_pr_addr_post (ops, 0, 1, ip, unit);
1849 else
1850 snprintf (ip, INS_BUF_SZ, "\t%%0, %%a1");
1852 return score3_ins;
1855 /* Output asm insn for store. */
1856 const char *
1857 score3_sinsn (rtx *ops, enum score_mem_unit unit)
1859 const char *pre_ins[] = {"sb", "sh", "sw"};
1860 char *ip;
1862 strcpy (score3_ins, pre_ins[unit]);
1863 ip = score3_ins + strlen (score3_ins);
1865 if (unit == SCORE_WORD)
1866 score3_pr_addr_post (ops, 1, 0, ip, unit);
1867 else
1868 snprintf (ip, INS_BUF_SZ, "\t%%1, %%a0");
1870 return score3_ins;
1873 /* Output asm insn for load immediate. */
1874 const char *
1875 score3_limm (rtx *ops)
1877 HOST_WIDE_INT v;
1879 gcc_assert (GET_CODE (ops[0]) == REG);
1880 gcc_assert (GET_CODE (ops[1]) == CONST_INT);
1882 v = INTVAL (ops[1]);
1883 if (G16_REG_P (REGNO (ops[0])) && IMM_IN_RANGE (v, 5, 0))
1884 return "ldiu!\t%0, %c1";
1885 else if (IMM_IN_RANGE (v, 16, 1))
1886 return "ldi\t%0, %c1";
1887 else if ((v & 0xffff) == 0)
1888 return "ldis\t%0, %U1";
1889 else
1890 return "li\t%0, %c1";
1893 /* Output asm insn for move. */
1894 const char *
1895 score3_move (rtx *ops)
1897 gcc_assert (GET_CODE (ops[0]) == REG);
1898 gcc_assert (GET_CODE (ops[1]) == REG);
1900 return "mv!\t%0, %1";
1903 /* Generate add insn. */
1904 const char *
1905 score3_select_add_imm (rtx *ops, bool set_cc)
1907 HOST_WIDE_INT v = INTVAL (ops[2]);
1909 gcc_assert (GET_CODE (ops[2]) == CONST_INT);
1910 gcc_assert (REGNO (ops[0]) == REGNO (ops[1]));
1912 if (set_cc)
1913 return "addi.c\t%0, %c2";
1914 else
1915 if (IMM_IN_RANGE (v, 6, 1) && G16_REG_P (REGNO (ops[0])))
1916 return "addi!\t%0, %c2";
1917 else
1918 return "addi\t%0, %c2";
1921 /* Output arith insn. */
1922 const char *
1923 score3_select (rtx *ops, const char *inst_pre, bool commu ATTRIBUTE_UNUSED,
1924 const char *letter, bool set_cc)
1926 gcc_assert (GET_CODE (ops[0]) == REG);
1927 gcc_assert (GET_CODE (ops[1]) == REG);
1929 if (set_cc)
1930 snprintf (score3_ins, INS_BUF_SZ, "%s.c\t%%0, %%1, %%%s2", inst_pre, letter);
1931 else
1932 snprintf (score3_ins, INS_BUF_SZ, "%s\t%%0, %%1, %%%s2", inst_pre, letter);
1933 return score3_ins;
1936 /* Output a Score3 casesi instruction. */
1937 const char *
1938 score3_output_casesi (rtx *operands)
1940 rtx diff_vec = PATTERN (next_real_insn (operands[2]));
1941 gcc_assert (GET_CODE (diff_vec) == ADDR_DIFF_VEC);
1943 output_asm_insn ("cmpi.c\t%0, %1", operands);
1944 output_asm_insn ("bgtu\t%3", operands);
1945 switch (GET_MODE(diff_vec))
1947 case QImode:
1948 output_asm_insn ("ldi48\t%4, %2", operands);
1949 output_asm_insn ("ltbb\t%4, [%4, %0]\n%2_tbb:", operands);
1950 return "brr!\t%4";
1951 case HImode:
1952 output_asm_insn ("ldi48\t%4, %2", operands);
1953 output_asm_insn ("ltbh\t%4, [%4, %0]\n%2_tbb:", operands);
1954 return "brr!\t%4";
1955 case SImode:
1956 output_asm_insn ("ldi48\t%4, %2", operands);
1957 output_asm_insn ("ltbw\t%4, [%4, %0]", operands);
1958 return "br!\t%4";
1959 default:
1960 gcc_unreachable ();