2008-05-30 Vladimir Makarov <vmakarov@redhat.com>
[official-gcc.git] / gcc / config / score / score3.c
blob3114bcd1c55c82297c05177a94baf9bc5be6e2c6
1 /* score3.c for Sunplus S+CORE processor
2 Copyright (C) 2005, 2007 Free Software Foundation, Inc.
3 Contributed by Sunnorth
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published
9 by the Free Software Foundation; either version 3, or (at your
10 option) any later version.
12 GCC is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
15 License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "tm.h"
25 #include "rtl.h"
26 #include "regs.h"
27 #include "hard-reg-set.h"
28 #include "real.h"
29 #include "insn-config.h"
30 #include "conditions.h"
31 #include "insn-attr.h"
32 #include "recog.h"
33 #include "toplev.h"
34 #include "output.h"
35 #include "tree.h"
36 #include "function.h"
37 #include "expr.h"
38 #include "optabs.h"
39 #include "flags.h"
40 #include "reload.h"
41 #include "tm_p.h"
42 #include "ggc.h"
43 #include "gstab.h"
44 #include "hashtab.h"
45 #include "debug.h"
46 #include "target.h"
47 #include "target-def.h"
48 #include "integrate.h"
49 #include "langhooks.h"
50 #include "cfglayout.h"
51 #include "score3.h"
53 #define BITSET_P(VALUE, BIT) (((VALUE) & (1L << (BIT))) != 0)
54 #define INS_BUF_SZ 128
56 /* Define the information needed to generate branch insns. This is
57 stored from the compare operation. */
58 extern rtx cmp_op0, cmp_op1;
59 extern enum reg_class score_char_to_class[256];
61 static int score3_sdata_max;
62 static char score3_ins[INS_BUF_SZ + 8];
64 /* Return true if SYMBOL is a SYMBOL_REF and OFFSET + SYMBOL points
65 to the same object as SYMBOL. */
66 static int
67 score3_offset_within_object_p (rtx symbol, HOST_WIDE_INT offset)
69 if (GET_CODE (symbol) != SYMBOL_REF)
70 return 0;
72 if (CONSTANT_POOL_ADDRESS_P (symbol)
73 && offset >= 0
74 && offset < (int)GET_MODE_SIZE (get_pool_mode (symbol)))
75 return 1;
77 if (SYMBOL_REF_DECL (symbol) != 0
78 && offset >= 0
79 && offset < int_size_in_bytes (TREE_TYPE (SYMBOL_REF_DECL (symbol))))
80 return 1;
82 return 0;
85 /* Split X into a base and a constant offset, storing them in *BASE
86 and *OFFSET respectively. */
87 static void
88 score3_split_const (rtx x, rtx *base, HOST_WIDE_INT *offset)
90 *offset = 0;
92 if (GET_CODE (x) == CONST)
93 x = XEXP (x, 0);
95 if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
97 *offset += INTVAL (XEXP (x, 1));
98 x = XEXP (x, 0);
101 *base = x;
104 /* Classify symbol X, which must be a SYMBOL_REF or a LABEL_REF. */
105 static enum score_symbol_type
106 score3_classify_symbol (rtx x)
108 if (GET_CODE (x) == LABEL_REF)
109 return SYMBOL_GENERAL;
111 gcc_assert (GET_CODE (x) == SYMBOL_REF);
113 if (CONSTANT_POOL_ADDRESS_P (x))
115 if (GET_MODE_SIZE (get_pool_mode (x)) <= SCORE3_SDATA_MAX)
116 return SYMBOL_SMALL_DATA;
117 return SYMBOL_GENERAL;
119 if (SYMBOL_REF_SMALL_P (x))
120 return SYMBOL_SMALL_DATA;
121 return SYMBOL_GENERAL;
124 /* Return true if the current function must save REGNO. */
125 static int
126 score3_save_reg_p (unsigned int regno)
128 /* Check call-saved registers. */
129 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
130 return 1;
132 /* We need to save the old frame pointer before setting up a new one. */
133 if (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed)
134 return 1;
136 /* We need to save the incoming return address if it is ever clobbered
137 within the function. */
138 if (regno == RA_REGNUM && df_regs_ever_live_p (regno))
139 return 1;
141 return 0;
144 /* Return one word of double-word value OP, taking into account the fixed
145 endianness of certain registers. HIGH_P is true to select the high part,
146 false to select the low part. */
147 static rtx
148 score3_subw (rtx op, int high_p)
150 unsigned int byte;
151 enum machine_mode mode = GET_MODE (op);
153 if (mode == VOIDmode)
154 mode = DImode;
156 byte = (TARGET_LITTLE_ENDIAN ? high_p : !high_p) ? UNITS_PER_WORD : 0;
158 if (GET_CODE (op) == REG && REGNO (op) == HI_REGNUM)
159 return gen_rtx_REG (SImode, high_p ? HI_REGNUM : LO_REGNUM);
161 if (GET_CODE (op) == MEM)
162 return adjust_address (op, SImode, byte);
164 return simplify_gen_subreg (SImode, op, mode, byte);
167 static struct score3_frame_info *
168 score3_cached_frame (void)
170 static struct score3_frame_info _frame_info;
171 return &_frame_info;
174 /* Return the bytes needed to compute the frame pointer from the current
175 stack pointer. SIZE is the size (in bytes) of the local variables. */
176 static struct score3_frame_info *
177 score3_compute_frame_size (HOST_WIDE_INT size)
179 unsigned int regno;
180 struct score3_frame_info *f = score3_cached_frame ();
182 memset (f, 0, sizeof (struct score3_frame_info));
183 f->gp_reg_size = 0;
184 f->mask = 0;
185 f->var_size = SCORE3_STACK_ALIGN (size);
186 f->args_size = crtl->outgoing_args_size;
187 f->cprestore_size = flag_pic ? UNITS_PER_WORD : 0;
189 if (f->var_size == 0 && current_function_is_leaf)
190 f->args_size = f->cprestore_size = 0;
192 if (f->args_size == 0 && cfun->calls_alloca)
193 f->args_size = UNITS_PER_WORD;
195 f->total_size = f->var_size + f->args_size + f->cprestore_size;
196 for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
198 if (score3_save_reg_p (regno))
200 f->gp_reg_size += GET_MODE_SIZE (SImode);
201 f->mask |= 1 << (regno - GP_REG_FIRST);
205 if (crtl->calls_eh_return)
207 unsigned int i;
208 for (i = 0;; ++i)
210 regno = EH_RETURN_DATA_REGNO (i);
211 if (regno == INVALID_REGNUM)
212 break;
213 f->gp_reg_size += GET_MODE_SIZE (SImode);
214 f->mask |= 1 << (regno - GP_REG_FIRST);
218 f->total_size += f->gp_reg_size;
219 f->num_gp = f->gp_reg_size / UNITS_PER_WORD;
221 if (f->mask)
223 HOST_WIDE_INT offset;
224 offset = (f->args_size + f->cprestore_size + f->var_size
225 + f->gp_reg_size - GET_MODE_SIZE (SImode));
226 f->gp_sp_offset = offset;
228 else
229 f->gp_sp_offset = 0;
231 return f;
234 /* Return true if X is a valid base register for the given mode.
235 Allow only hard registers if STRICT. */
236 static int
237 score3_valid_base_register_p (rtx x, int strict)
239 if (!strict && GET_CODE (x) == SUBREG)
240 x = SUBREG_REG (x);
242 return (GET_CODE (x) == REG
243 && score3_regno_mode_ok_for_base_p (REGNO (x), strict));
246 /* Return true if X is a valid address for machine mode MODE. If it is,
247 fill in INFO appropriately. STRICT is true if we should only accept
248 hard base registers. */
249 static int
250 score3_classify_address (struct score3_address_info *info,
251 enum machine_mode mode, rtx x, int strict)
253 info->code = GET_CODE (x);
255 switch (info->code)
257 case REG:
258 case SUBREG:
259 info->type = SCORE3_ADD_REG;
260 info->reg = x;
261 info->offset = const0_rtx;
262 return score3_valid_base_register_p (info->reg, strict);
263 case PLUS:
264 info->type = SCORE3_ADD_REG;
265 info->reg = XEXP (x, 0);
266 info->offset = XEXP (x, 1);
267 return (score3_valid_base_register_p (info->reg, strict)
268 && GET_CODE (info->offset) == CONST_INT
269 && IMM_IN_RANGE (INTVAL (info->offset), 15, 1));
270 case PRE_DEC:
271 case POST_DEC:
272 case PRE_INC:
273 case POST_INC:
274 if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (SImode))
275 return false;
276 info->type = SCORE3_ADD_REG;
277 info->reg = XEXP (x, 0);
278 info->offset = GEN_INT (GET_MODE_SIZE (mode));
279 return score3_valid_base_register_p (info->reg, strict);
280 case CONST_INT:
281 info->type = SCORE3_ADD_CONST_INT;
282 return 1;
283 case CONST:
284 case LABEL_REF:
285 case SYMBOL_REF:
286 info->type = SCORE3_ADD_SYMBOLIC;
287 return (score3_symbolic_constant_p (x, &info->symbol_type)
288 && (info->symbol_type == SYMBOL_GENERAL
289 || info->symbol_type == SYMBOL_SMALL_DATA));
290 default:
291 return 0;
295 bool
296 score3_return_in_memory (tree type, tree fndecl ATTRIBUTE_UNUSED)
298 return ((TYPE_MODE (type) == BLKmode)
299 || (int_size_in_bytes (type) > 2 * UNITS_PER_WORD)
300 || (int_size_in_bytes (type) == -1));
303 /* Return a legitimate address for REG + OFFSET. */
304 static rtx
305 score3_add_offset (rtx reg, HOST_WIDE_INT offset)
307 if (!IMM_IN_RANGE (offset, 15, 1))
309 reg = expand_simple_binop (GET_MODE (reg), PLUS,
310 gen_int_mode (offset & 0xffffc000,
311 GET_MODE (reg)),
312 reg, NULL, 0, OPTAB_WIDEN);
313 offset &= 0x3fff;
316 return plus_constant (reg, offset);
319 /* Implement TARGET_ASM_OUTPUT_MI_THUNK. Generate rtl rather than asm text
320 in order to avoid duplicating too much logic from elsewhere. */
321 void
322 score3_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
323 HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
324 tree function)
326 rtx this, temp1, insn, fnaddr;
328 /* Pretend to be a post-reload pass while generating rtl. */
329 reload_completed = 1;
331 /* Mark the end of the (empty) prologue. */
332 emit_note (NOTE_INSN_PROLOGUE_END);
334 /* We need two temporary registers in some cases. */
335 temp1 = gen_rtx_REG (Pmode, 8);
337 /* Find out which register contains the "this" pointer. */
338 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
339 this = gen_rtx_REG (Pmode, ARG_REG_FIRST + 1);
340 else
341 this = gen_rtx_REG (Pmode, ARG_REG_FIRST);
343 /* Add DELTA to THIS. */
344 if (delta != 0)
346 rtx offset = GEN_INT (delta);
347 if (!CONST_OK_FOR_LETTER_P (delta, 'L'))
349 emit_move_insn (temp1, offset);
350 offset = temp1;
352 emit_insn (gen_add3_insn (this, this, offset));
355 /* If needed, add *(*THIS + VCALL_OFFSET) to THIS. */
356 if (vcall_offset != 0)
358 rtx addr;
360 /* Set TEMP1 to *THIS. */
361 emit_move_insn (temp1, gen_rtx_MEM (Pmode, this));
363 /* Set ADDR to a legitimate address for *THIS + VCALL_OFFSET. */
364 addr = score3_add_offset (temp1, vcall_offset);
366 /* Load the offset and add it to THIS. */
367 emit_move_insn (temp1, gen_rtx_MEM (Pmode, addr));
368 emit_insn (gen_add3_insn (this, this, temp1));
371 /* Jump to the target function. */
372 fnaddr = XEXP (DECL_RTL (function), 0);
373 insn = emit_call_insn (gen_sibcall_internal_score3 (fnaddr, const0_rtx));
374 SIBLING_CALL_P (insn) = 1;
376 /* Run just enough of rest_of_compilation. This sequence was
377 "borrowed" from alpha.c. */
378 insn = get_insns ();
379 insn_locators_alloc ();
380 split_all_insns_noflow ();
381 shorten_branches (insn);
382 final_start_function (insn, file, 1);
383 final (insn, file, 1);
384 final_end_function ();
385 free_after_compilation (cfun);
387 /* Clean up the vars set above. Note that final_end_function resets
388 the global pointer for us. */
389 reload_completed = 0;
392 /* Copy VALUE to a register and return that register. If new psuedos
393 are allowed, copy it into a new register, otherwise use DEST. */
394 static rtx
395 score3_force_temporary (rtx dest, rtx value)
397 if (can_create_pseudo_p ())
398 return force_reg (Pmode, value);
399 else
401 emit_move_insn (copy_rtx (dest), value);
402 return dest;
406 /* Return a LO_SUM expression for ADDR. TEMP is as for score_force_temporary
407 and is used to load the high part into a register. */
408 static rtx
409 score3_split_symbol (rtx temp, rtx addr)
411 rtx high = score3_force_temporary (temp,
412 gen_rtx_HIGH (Pmode, copy_rtx (addr)));
413 return gen_rtx_LO_SUM (Pmode, high, addr);
416 /* This function is used to implement LEGITIMIZE_ADDRESS. If *XLOC can
417 be legitimized in a way that the generic machinery might not expect,
418 put the new address in *XLOC and return true. */
420 score3_legitimize_address (rtx *xloc)
422 enum score_symbol_type symbol_type;
424 if (score3_symbolic_constant_p (*xloc, &symbol_type)
425 && symbol_type == SYMBOL_GENERAL)
427 *xloc = score3_split_symbol (0, *xloc);
428 return 1;
431 if (GET_CODE (*xloc) == PLUS
432 && GET_CODE (XEXP (*xloc, 1)) == CONST_INT)
434 rtx reg = XEXP (*xloc, 0);
435 if (!score3_valid_base_register_p (reg, 0))
436 reg = copy_to_mode_reg (Pmode, reg);
437 *xloc = score3_add_offset (reg, INTVAL (XEXP (*xloc, 1)));
438 return 1;
440 return 0;
443 /* Fill INFO with information about a single argument. CUM is the
444 cumulative state for earlier arguments. MODE is the mode of this
445 argument and TYPE is its type (if known). NAMED is true if this
446 is a named (fixed) argument rather than a variable one. */
447 static void
448 score3_classify_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
449 tree type, int named, struct score3_arg_info *info)
451 int even_reg_p;
452 unsigned int num_words, max_regs;
454 even_reg_p = 0;
455 if (GET_MODE_CLASS (mode) == MODE_INT
456 || GET_MODE_CLASS (mode) == MODE_FLOAT)
457 even_reg_p = (GET_MODE_SIZE (mode) > UNITS_PER_WORD);
458 else
459 if (type != NULL_TREE && TYPE_ALIGN (type) > BITS_PER_WORD && named)
460 even_reg_p = 1;
462 if (TARGET_MUST_PASS_IN_STACK (mode, type))
463 info->reg_offset = ARG_REG_NUM;
464 else
466 info->reg_offset = cum->num_gprs;
467 if (even_reg_p)
468 info->reg_offset += info->reg_offset & 1;
471 if (mode == BLKmode)
472 info->num_bytes = int_size_in_bytes (type);
473 else
474 info->num_bytes = GET_MODE_SIZE (mode);
476 num_words = (info->num_bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
477 max_regs = ARG_REG_NUM - info->reg_offset;
479 /* Partition the argument between registers and stack. */
480 info->reg_words = MIN (num_words, max_regs);
481 info->stack_words = num_words - info->reg_words;
483 /* The alignment applied to registers is also applied to stack arguments. */
484 if (info->stack_words)
486 info->stack_offset = cum->stack_words;
487 if (even_reg_p)
488 info->stack_offset += info->stack_offset & 1;
492 /* Set up the stack and frame (if desired) for the function. */
493 void
494 score3_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
496 const char *fnname;
497 struct score3_frame_info *f = score3_cached_frame ();
498 HOST_WIDE_INT tsize = f->total_size;
500 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
501 if (!flag_inhibit_size_directive)
503 fputs ("\t.ent\t", file);
504 assemble_name (file, fnname);
505 fputs ("\n", file);
507 assemble_name (file, fnname);
508 fputs (":\n", file);
510 if (!flag_inhibit_size_directive)
512 fprintf (file,
513 "\t.frame\t%s," HOST_WIDE_INT_PRINT_DEC ",%s, %d\t\t"
514 "# vars= " HOST_WIDE_INT_PRINT_DEC ", regs= %d"
515 ", args= " HOST_WIDE_INT_PRINT_DEC
516 ", gp= " HOST_WIDE_INT_PRINT_DEC "\n",
517 (reg_names[(frame_pointer_needed)
518 ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM]),
519 tsize,
520 reg_names[RA_REGNUM],
521 current_function_is_leaf ? 1 : 0,
522 f->var_size,
523 f->num_gp,
524 f->args_size,
525 f->cprestore_size);
527 fprintf(file, "\t.mask\t0x%08x," HOST_WIDE_INT_PRINT_DEC "\n",
528 f->mask,
529 (f->gp_sp_offset - f->total_size));
533 /* Do any necessary cleanup after a function to restore stack, frame,
534 and regs. */
535 void
536 score3_function_epilogue (FILE *file,
537 HOST_WIDE_INT size ATTRIBUTE_UNUSED)
539 if (!flag_inhibit_size_directive)
541 const char *fnname;
542 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
543 fputs ("\t.end\t", file);
544 assemble_name (file, fnname);
545 fputs ("\n", file);
549 /* Returns true if X contains a SYMBOL_REF. */
550 static bool
551 score3_symbolic_expression_p (rtx x)
553 if (GET_CODE (x) == SYMBOL_REF)
554 return true;
556 if (GET_CODE (x) == CONST)
557 return score3_symbolic_expression_p (XEXP (x, 0));
559 if (UNARY_P (x))
560 return score3_symbolic_expression_p (XEXP (x, 0));
562 if (ARITHMETIC_P (x))
563 return (score3_symbolic_expression_p (XEXP (x, 0))
564 || score3_symbolic_expression_p (XEXP (x, 1)));
566 return false;
569 /* Choose the section to use for the constant rtx expression X that has
570 mode MODE. */
571 section *
572 score3_select_rtx_section (enum machine_mode mode, rtx x,
573 unsigned HOST_WIDE_INT align)
575 if (GET_MODE_SIZE (mode) <= SCORE3_SDATA_MAX)
576 return get_named_section (0, ".sdata", 0);
577 else if (flag_pic && score3_symbolic_expression_p (x))
578 return get_named_section (0, ".data.rel.ro", 3);
579 else
580 return mergeable_constant_section (mode, align, 0);
583 /* Implement TARGET_IN_SMALL_DATA_P. */
584 bool
585 score3_in_small_data_p (tree decl)
587 HOST_WIDE_INT size;
589 if (TREE_CODE (decl) == STRING_CST
590 || TREE_CODE (decl) == FUNCTION_DECL)
591 return false;
593 if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl) != 0)
595 const char *name;
596 name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
597 if (strcmp (name, ".sdata") != 0
598 && strcmp (name, ".sbss") != 0)
599 return true;
600 if (!DECL_EXTERNAL (decl))
601 return false;
603 size = int_size_in_bytes (TREE_TYPE (decl));
604 return (size > 0 && size <= SCORE3_SDATA_MAX);
607 /* Implement TARGET_ASM_FILE_START. */
608 void
609 score3_asm_file_start (void)
611 default_file_start ();
612 fprintf (asm_out_file, ASM_COMMENT_START
613 "GCC for S+core %s \n", SCORE_GCC_VERSION);
615 if (flag_pic)
616 fprintf (asm_out_file, "\t.set pic\n");
619 /* Implement TARGET_ASM_FILE_END. When using assembler macros, emit
620 .externs for any small-data variables that turned out to be external. */
621 void
622 score3_asm_file_end (void)
624 tree name_tree;
625 struct extern_list *p;
626 if (extern_head)
628 fputs ("\n", asm_out_file);
629 for (p = extern_head; p != 0; p = p->next)
631 name_tree = get_identifier (p->name);
632 if (!TREE_ASM_WRITTEN (name_tree)
633 && TREE_SYMBOL_REFERENCED (name_tree))
635 TREE_ASM_WRITTEN (name_tree) = 1;
636 fputs ("\t.extern\t", asm_out_file);
637 assemble_name (asm_out_file, p->name);
638 fprintf (asm_out_file, ", %d\n", p->size);
644 /* Implement OVERRIDE_OPTIONS macro. */
645 void
646 score3_override_options (void)
648 flag_pic = false;
649 if (!flag_pic)
650 score3_sdata_max = g_switch_set ? g_switch_value : SCORE3_DEFAULT_SDATA_MAX;
651 else
653 score3_sdata_max = 0;
654 if (g_switch_set && (g_switch_value != 0))
655 warning (0, "-fPIC and -G are incompatible");
658 score_char_to_class['d'] = G32_REGS;
659 score_char_to_class['e'] = G16_REGS;
660 score_char_to_class['t'] = T32_REGS;
662 score_char_to_class['h'] = HI_REG;
663 score_char_to_class['l'] = LO_REG;
664 score_char_to_class['x'] = CE_REGS;
666 score_char_to_class['q'] = CN_REG;
667 score_char_to_class['y'] = LC_REG;
668 score_char_to_class['z'] = SC_REG;
669 score_char_to_class['a'] = SP_REGS;
671 score_char_to_class['c'] = CR_REGS;
674 /* Implement REGNO_REG_CLASS macro. */
676 score3_reg_class (int regno)
678 int c;
679 gcc_assert (regno >= 0 && regno < FIRST_PSEUDO_REGISTER);
681 if (regno == FRAME_POINTER_REGNUM
682 || regno == ARG_POINTER_REGNUM)
683 return ALL_REGS;
685 for (c = 0; c < N_REG_CLASSES; c++)
686 if (TEST_HARD_REG_BIT (reg_class_contents[c], regno))
687 return c;
689 return NO_REGS;
692 /* Implement PREFERRED_RELOAD_CLASS macro. */
693 enum reg_class
694 score3_preferred_reload_class (rtx x ATTRIBUTE_UNUSED, enum reg_class class)
696 if (reg_class_subset_p (G16_REGS, class))
697 return G16_REGS;
698 if (reg_class_subset_p (G32_REGS, class))
699 return G32_REGS;
700 return class;
703 /* Implement SECONDARY_INPUT_RELOAD_CLASS
704 and SECONDARY_OUTPUT_RELOAD_CLASS macro. */
705 enum reg_class
706 score3_secondary_reload_class (enum reg_class class,
707 enum machine_mode mode ATTRIBUTE_UNUSED,
708 rtx x)
710 int regno = -1;
711 if (GET_CODE (x) == REG || GET_CODE(x) == SUBREG)
712 regno = true_regnum (x);
714 if (!GR_REG_CLASS_P (class))
715 return GP_REG_P (regno) ? NO_REGS : G32_REGS;
716 return NO_REGS;
719 /* Implement CONST_OK_FOR_LETTER_P macro. */
720 /* imm constraints
721 I imm16 << 16
722 J uimm5
723 K uimm16
724 L simm16
725 M uimm14
726 N simm14
727 O simm14
728 P simm5
729 Q uimm32 */
731 score3_const_ok_for_letter_p (HOST_WIDE_INT value, char c)
733 switch (c)
735 case 'I': return ((value & 0xffff) == 0);
736 case 'J': return IMM_IN_RANGE (value, 5, 0);
737 case 'K': return IMM_IN_RANGE (value, 16, 0);
738 case 'L': return IMM_IN_RANGE (value, 16, 1);
739 case 'M': return IMM_IN_RANGE (value, 14, 0);
740 case 'N': return IMM_IN_RANGE (value, 14, 1);
741 case 'O': return IMM_IN_RANGE (value, 5, 1);
742 case 'P': return IMM_IN_RANGE (value, 6, 1);
743 case 'Q': return score_extra_constraint (GEN_INT(value), c);
744 default : return 0;
748 /* Implement EXTRA_CONSTRAINT macro. */
750 Q uimm32
751 Z symbol_ref */
753 score3_extra_constraint (rtx op, char c)
755 switch (c)
757 case 'Q': return IMM_IN_RANGE (INTVAL(op), 32, 0);
758 case 'Z':
759 return GET_CODE (op) == SYMBOL_REF;
760 default:
761 gcc_unreachable ();
765 /* Return truth value on whether or not a given hard register
766 can support a given mode. */
768 score3_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
770 int size = GET_MODE_SIZE (mode);
771 enum mode_class class = GET_MODE_CLASS (mode);
773 if (class == MODE_CC)
774 return regno == CC_REGNUM;
775 else if (regno == FRAME_POINTER_REGNUM
776 || regno == ARG_POINTER_REGNUM)
777 return class == MODE_INT;
778 else if (GP_REG_P (regno))
779 return !(regno & 1) || (size <= UNITS_PER_WORD);
780 else if (CE_REG_P (regno))
781 return (class == MODE_INT
782 && ((size <= UNITS_PER_WORD)
783 || (regno == CE_REG_FIRST && size == 2 * UNITS_PER_WORD)));
784 else
785 return (class == MODE_INT) && (size <= UNITS_PER_WORD);
788 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
789 pointer or argument pointer. TO is either the stack pointer or
790 hard frame pointer. */
791 HOST_WIDE_INT
792 score3_initial_elimination_offset (int from,
793 int to ATTRIBUTE_UNUSED)
795 struct score3_frame_info *f = score3_compute_frame_size (get_frame_size ());
796 switch (from)
798 case ARG_POINTER_REGNUM:
799 return f->total_size;
800 case FRAME_POINTER_REGNUM:
801 return 0;
802 default:
803 gcc_unreachable ();
807 /* Implement FUNCTION_ARG_ADVANCE macro. */
808 void
809 score3_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
810 tree type, int named)
812 struct score3_arg_info info;
813 score3_classify_arg (cum, mode, type, named, &info);
814 cum->num_gprs = info.reg_offset + info.reg_words;
815 if (info.stack_words > 0)
816 cum->stack_words = info.stack_offset + info.stack_words;
817 cum->arg_number++;
820 /* Implement TARGET_ARG_PARTIAL_BYTES macro. */
822 score3_arg_partial_bytes (CUMULATIVE_ARGS *cum,
823 enum machine_mode mode, tree type, bool named)
825 struct score3_arg_info info;
826 score3_classify_arg (cum, mode, type, named, &info);
827 return info.stack_words > 0 ? info.reg_words * UNITS_PER_WORD : 0;
830 /* Implement FUNCTION_ARG macro. */
832 score3_function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
833 tree type, int named)
835 struct score3_arg_info info;
837 if (mode == VOIDmode || !named)
838 return 0;
840 score3_classify_arg (cum, mode, type, named, &info);
842 if (info.reg_offset == ARG_REG_NUM)
843 return 0;
845 if (!info.stack_words)
846 return gen_rtx_REG (mode, ARG_REG_FIRST + info.reg_offset);
847 else
849 rtx ret = gen_rtx_PARALLEL (mode, rtvec_alloc (info.reg_words));
850 unsigned int i, part_offset = 0;
851 for (i = 0; i < info.reg_words; i++)
853 rtx reg;
854 reg = gen_rtx_REG (SImode, ARG_REG_FIRST + info.reg_offset + i);
855 XVECEXP (ret, 0, i) = gen_rtx_EXPR_LIST (SImode, reg,
856 GEN_INT (part_offset));
857 part_offset += UNITS_PER_WORD;
859 return ret;
863 /* Implement FUNCTION_VALUE and LIBCALL_VALUE. For normal calls,
864 VALTYPE is the return type and MODE is VOIDmode. For libcalls,
865 VALTYPE is null and MODE is the mode of the return value. */
867 score3_function_value (tree valtype, tree func ATTRIBUTE_UNUSED,
868 enum machine_mode mode)
870 if (valtype)
872 int unsignedp;
873 mode = TYPE_MODE (valtype);
874 unsignedp = TYPE_UNSIGNED (valtype);
875 mode = promote_mode (valtype, mode, &unsignedp, 1);
877 return gen_rtx_REG (mode, RT_REGNUM);
880 /* Implement INITIALIZE_TRAMPOLINE macro. */
881 void
882 score3_initialize_trampoline (rtx ADDR, rtx FUNC, rtx CHAIN)
884 #define FFCACHE "_flush_cache"
885 #define CODE_SIZE (TRAMPOLINE_INSNS * UNITS_PER_WORD)
887 rtx pfunc, pchain;
889 pfunc = plus_constant (ADDR, CODE_SIZE);
890 pchain = plus_constant (ADDR, CODE_SIZE + GET_MODE_SIZE (SImode));
892 emit_move_insn (gen_rtx_MEM (SImode, pfunc), FUNC);
893 emit_move_insn (gen_rtx_MEM (SImode, pchain), CHAIN);
894 emit_library_call (gen_rtx_SYMBOL_REF (Pmode, FFCACHE),
895 0, VOIDmode, 2,
896 ADDR, Pmode,
897 GEN_INT (TRAMPOLINE_SIZE), SImode);
898 #undef FFCACHE
899 #undef CODE_SIZE
902 /* This function is used to implement REG_MODE_OK_FOR_BASE_P macro. */
904 score3_regno_mode_ok_for_base_p (int regno, int strict)
906 if (regno >= FIRST_PSEUDO_REGISTER)
908 if (!strict)
909 return 1;
910 regno = reg_renumber[regno];
912 if (regno == ARG_POINTER_REGNUM
913 || regno == FRAME_POINTER_REGNUM)
914 return 1;
915 return GP_REG_P (regno);
918 /* Implement GO_IF_LEGITIMATE_ADDRESS macro. */
920 score3_address_p (enum machine_mode mode, rtx x, int strict)
922 struct score3_address_info addr;
924 return score3_classify_address (&addr, mode, x, strict);
927 /* Return a number assessing the cost of moving a register in class
928 FROM to class TO. */
930 score3_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
931 enum reg_class from, enum reg_class to)
933 if (GR_REG_CLASS_P (from))
935 if (GR_REG_CLASS_P (to))
936 return 2;
937 else if (SP_REG_CLASS_P (to))
938 return 4;
939 else if (CP_REG_CLASS_P (to))
940 return 5;
941 else if (CE_REG_CLASS_P (to))
942 return 6;
944 if (GR_REG_CLASS_P (to))
946 if (GR_REG_CLASS_P (from))
947 return 2;
948 else if (SP_REG_CLASS_P (from))
949 return 4;
950 else if (CP_REG_CLASS_P (from))
951 return 5;
952 else if (CE_REG_CLASS_P (from))
953 return 6;
955 return 12;
958 /* Return the number of instructions needed to load a symbol of the
959 given type into a register. */
960 static int
961 score3_symbol_insns (enum score_symbol_type type)
963 switch (type)
965 case SYMBOL_GENERAL:
966 return 2;
968 case SYMBOL_SMALL_DATA:
969 return 1;
972 gcc_unreachable ();
975 /* Return the number of instructions needed to load or store a value
976 of mode MODE at X. Return 0 if X isn't valid for MODE. */
977 static int
978 score3_address_insns (rtx x, enum machine_mode mode)
980 struct score3_address_info addr;
981 int factor;
983 if (mode == BLKmode)
984 factor = 1;
985 else
986 factor = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
988 if (score3_classify_address (&addr, mode, x, false))
989 switch (addr.type)
991 case SCORE3_ADD_REG:
992 case SCORE3_ADD_CONST_INT:
993 return factor;
995 case SCORE3_ADD_SYMBOLIC:
996 return factor * score3_symbol_insns (addr.symbol_type);
998 return 0;
1001 /* Implement TARGET_RTX_COSTS macro. */
1002 bool
1003 score3_rtx_costs (rtx x, int code, int outer_code, int *total)
1005 enum machine_mode mode = GET_MODE (x);
1007 switch (code)
1009 case CONST_INT:
1010 if (outer_code == SET)
1012 if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
1013 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L'))
1014 *total = COSTS_N_INSNS (1);
1015 else
1016 *total = COSTS_N_INSNS (2);
1018 else if (outer_code == PLUS || outer_code == MINUS)
1020 if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'N'))
1021 *total = 0;
1022 else if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
1023 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L'))
1024 *total = 1;
1025 else
1026 *total = COSTS_N_INSNS (2);
1028 else if (outer_code == AND || outer_code == IOR)
1030 if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'M'))
1031 *total = 0;
1032 else if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
1033 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'K'))
1034 *total = 1;
1035 else
1036 *total = COSTS_N_INSNS (2);
1038 else
1040 *total = 0;
1042 return true;
1044 case CONST:
1045 case SYMBOL_REF:
1046 case LABEL_REF:
1047 case CONST_DOUBLE:
1048 *total = COSTS_N_INSNS (2);
1049 return true;
1051 case MEM:
1053 /* If the address is legitimate, return the number of
1054 instructions it needs, otherwise use the default handling. */
1055 int n = score3_address_insns (XEXP (x, 0), GET_MODE (x));
1056 if (n > 0)
1058 *total = COSTS_N_INSNS (n + 1);
1059 return true;
1061 return false;
1064 case FFS:
1065 *total = COSTS_N_INSNS (6);
1066 return true;
1068 case NOT:
1069 *total = COSTS_N_INSNS (1);
1070 return true;
1072 case AND:
1073 case IOR:
1074 case XOR:
1075 if (mode == DImode)
1077 *total = COSTS_N_INSNS (2);
1078 return true;
1080 return false;
1082 case ASHIFT:
1083 case ASHIFTRT:
1084 case LSHIFTRT:
1085 if (mode == DImode)
1087 *total = COSTS_N_INSNS ((GET_CODE (XEXP (x, 1)) == CONST_INT)
1088 ? 4 : 12);
1089 return true;
1091 return false;
1093 case ABS:
1094 *total = COSTS_N_INSNS (4);
1095 return true;
1097 case PLUS:
1098 case MINUS:
1099 if (mode == DImode)
1101 *total = COSTS_N_INSNS (4);
1102 return true;
1104 *total = COSTS_N_INSNS (1);
1105 return true;
1107 case NEG:
1108 if (mode == DImode)
1110 *total = COSTS_N_INSNS (4);
1111 return true;
1113 return false;
1115 case MULT:
1116 *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (12);
1117 return true;
1119 case DIV:
1120 case MOD:
1121 case UDIV:
1122 case UMOD:
1123 *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (33);
1124 return true;
1126 case SIGN_EXTEND:
1127 case ZERO_EXTEND:
1128 switch (GET_MODE (XEXP (x, 0)))
1130 case QImode:
1131 case HImode:
1132 if (GET_CODE (XEXP (x, 0)) == MEM)
1134 *total = COSTS_N_INSNS (2);
1136 if (!TARGET_LITTLE_ENDIAN &&
1137 side_effects_p (XEXP (XEXP (x, 0), 0)))
1138 *total = 100;
1140 else
1141 *total = COSTS_N_INSNS (1);
1142 break;
1144 default:
1145 *total = COSTS_N_INSNS (1);
1146 break;
1148 return true;
1150 default:
1151 return false;
1155 /* Implement TARGET_ADDRESS_COST macro. */
1157 score3_address_cost (rtx addr)
1159 return score3_address_insns (addr, SImode);
1162 /* Implement ASM_OUTPUT_EXTERNAL macro. */
1164 score3_output_external (FILE *file ATTRIBUTE_UNUSED,
1165 tree decl, const char *name)
1167 register struct extern_list *p;
1169 if (score3_in_small_data_p (decl))
1171 p = (struct extern_list *) ggc_alloc (sizeof (struct extern_list));
1172 p->next = extern_head;
1173 p->name = name;
1174 p->size = int_size_in_bytes (TREE_TYPE (decl));
1175 extern_head = p;
1177 return 0;
1180 /* Implement RETURN_ADDR_RTX. Note, we do not support moving
1181 back to a previous frame. */
1183 score3_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
1185 if (count != 0)
1186 return const0_rtx;
1187 return get_hard_reg_initial_val (Pmode, RA_REGNUM);
1190 /* Implement PRINT_OPERAND macro. */
1191 /* Score-specific operand codes:
1192 '[' print .set nor1 directive
1193 ']' print .set r1 directive
1194 'U' print hi part of a CONST_INT rtx
1195 'E' print log2(v)
1196 'F' print log2(~v)
1197 'D' print SFmode const double
1198 'S' selectively print "!" if operand is 15bit instruction accessible
1199 'V' print "v!" if operand is 15bit instruction accessible, or "lfh!"
1200 'L' low part of DImode reg operand
1201 'H' high part of DImode reg operand
1202 'C' print part of opcode for a branch condition. */
1203 void
1204 score3_print_operand (FILE *file, rtx op, int c)
1206 enum rtx_code code = -1;
1207 if (!PRINT_OPERAND_PUNCT_VALID_P (c))
1208 code = GET_CODE (op);
1210 if (c == '[')
1212 fprintf (file, ".set r1\n");
1214 else if (c == ']')
1216 fprintf (file, "\n\t.set nor1");
1218 else if (c == 'U')
1220 gcc_assert (code == CONST_INT);
1221 fprintf (file, HOST_WIDE_INT_PRINT_HEX,
1222 (INTVAL (op) >> 16) & 0xffff);
1224 else if (c == 'D')
1226 if (GET_CODE (op) == CONST_DOUBLE)
1228 rtx temp = gen_lowpart (SImode, op);
1229 gcc_assert (GET_MODE (op) == SFmode);
1230 fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (temp) & 0xffffffff);
1232 else
1233 output_addr_const (file, op);
1235 else if (c == 'S')
1237 gcc_assert (code == REG);
1238 if (G16_REG_P (REGNO (op)))
1239 fprintf (file, "!");
1241 else if (c == 'V')
1243 gcc_assert (code == REG);
1244 fprintf (file, G16_REG_P (REGNO (op)) ? "v!" : "lfh!");
1246 else if (c == 'C')
1248 enum machine_mode mode = GET_MODE (XEXP (op, 0));
1250 switch (code)
1252 case EQ: fputs ("eq!", file); break;
1253 case NE: fputs ("ne!", file); break;
1254 case GT: fputs ("gt!", file); break;
1255 case GE: fputs (mode != CCmode ? "pl" : "ge", file); break;
1256 case LT: fputs (mode != CCmode ? "mi" : "lt", file); break;
1257 case LE: fputs ("le!", file); break;
1258 case GTU: fputs ("gtu!", file); break;
1259 case GEU: fputs ("cs", file); break;
1260 case LTU: fputs ("cc", file); break;
1261 case LEU: fputs ("leu!", file); break;
1262 default:
1263 output_operand_lossage ("invalid operand for code: '%c'", code);
1266 else if (c == 'G') /* Seperate from b<cond>, use for mv<cond>. */
1268 enum machine_mode mode = GET_MODE (XEXP (op, 0));
1270 switch (code)
1272 case EQ: fputs ("eq", file); break;
1273 case NE: fputs ("ne", file); break;
1274 case GT: fputs ("gt", file); break;
1275 case GE: fputs (mode != CCmode ? "pl" : "ge", file); break;
1276 case LT: fputs (mode != CCmode ? "mi" : "lt", file); break;
1277 case LE: fputs ("le", file); break;
1278 case GTU: fputs ("gtu", file); break;
1279 case GEU: fputs ("cs", file); break;
1280 case LTU: fputs ("cc", file); break;
1281 case LEU: fputs ("leu", file); break;
1282 default:
1283 output_operand_lossage ("invalid operand for code: '%c'", code);
1286 else if (c == 'E')
1288 unsigned HOST_WIDE_INT i;
1289 unsigned HOST_WIDE_INT pow2mask = 1;
1290 unsigned HOST_WIDE_INT val;
1292 val = INTVAL (op);
1293 for (i = 0; i < 32; i++)
1295 if (val == pow2mask)
1296 break;
1297 pow2mask <<= 1;
1299 gcc_assert (i < 32);
1300 fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
1302 else if (c == 'F')
1304 unsigned HOST_WIDE_INT i;
1305 unsigned HOST_WIDE_INT pow2mask = 1;
1306 unsigned HOST_WIDE_INT val;
1308 val = ~INTVAL (op);
1309 for (i = 0; i < 32; i++)
1311 if (val == pow2mask)
1312 break;
1313 pow2mask <<= 1;
1315 gcc_assert (i < 32);
1316 fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
1318 else if (code == REG)
1320 int regnum = REGNO (op);
1321 if ((c == 'H' && !WORDS_BIG_ENDIAN)
1322 || (c == 'L' && WORDS_BIG_ENDIAN))
1323 regnum ++;
1324 fprintf (file, "%s", reg_names[regnum]);
1326 else
1328 switch (code)
1330 case MEM:
1331 score3_print_operand_address (file, op);
1332 break;
1333 default:
1334 output_addr_const (file, op);
1339 /* Implement PRINT_OPERAND_ADDRESS macro. */
1340 void
1341 score3_print_operand_address (FILE *file, rtx x)
1343 struct score3_address_info addr;
1344 enum rtx_code code = GET_CODE (x);
1345 enum machine_mode mode = GET_MODE (x);
1347 if (code == MEM)
1348 x = XEXP (x, 0);
1350 if (score3_classify_address (&addr, mode, x, true))
1352 switch (addr.type)
1354 case SCORE3_ADD_REG:
1356 switch (addr.code)
1358 case PRE_DEC:
1359 fprintf (file, "[%s,-%ld]+", reg_names[REGNO (addr.reg)],
1360 INTVAL (addr.offset));
1361 break;
1362 case POST_DEC:
1363 fprintf (file, "[%s]+,-%ld", reg_names[REGNO (addr.reg)],
1364 INTVAL (addr.offset));
1365 break;
1366 case PRE_INC:
1367 fprintf (file, "[%s, %ld]+", reg_names[REGNO (addr.reg)],
1368 INTVAL (addr.offset));
1369 break;
1370 case POST_INC:
1371 fprintf (file, "[%s]+, %ld", reg_names[REGNO (addr.reg)],
1372 INTVAL (addr.offset));
1373 break;
1374 default:
1375 if (INTVAL(addr.offset) == 0)
1376 fprintf(file, "[%s]", reg_names[REGNO (addr.reg)]);
1377 else
1378 fprintf(file, "[%s, %ld]", reg_names[REGNO (addr.reg)],
1379 INTVAL(addr.offset));
1380 break;
1383 return;
1384 case SCORE3_ADD_CONST_INT:
1385 case SCORE3_ADD_SYMBOLIC:
1386 output_addr_const (file, x);
1387 return;
1390 print_rtl (stderr, x);
1391 gcc_unreachable ();
1394 /* Implement SELECT_CC_MODE macro. */
1395 enum machine_mode
1396 score3_select_cc_mode (enum rtx_code op, rtx x, rtx y)
1398 if ((op == EQ || op == NE || op == LT || op == GE)
1399 && y == const0_rtx
1400 && GET_MODE (x) == SImode)
1402 switch (GET_CODE (x))
1404 case PLUS:
1405 case MINUS:
1406 case NEG:
1407 case AND:
1408 case IOR:
1409 case XOR:
1410 case NOT:
1411 case ASHIFT:
1412 case LSHIFTRT:
1413 case ASHIFTRT:
1414 return CC_NZmode;
1416 case SIGN_EXTEND:
1417 case ZERO_EXTEND:
1418 case ROTATE:
1419 case ROTATERT:
1420 return (op == LT || op == GE) ? CC_Nmode : CCmode;
1422 default:
1423 return CCmode;
1427 if ((op == EQ || op == NE)
1428 && (GET_CODE (y) == NEG)
1429 && register_operand (XEXP (y, 0), SImode)
1430 && register_operand (x, SImode))
1432 return CC_NZmode;
1435 return CCmode;
1438 #define EMIT_PL(_rtx) RTX_FRAME_RELATED_P (_rtx) = 1
1439 /* return 0, no more bit set in mask. */
1440 static int rpush_first (int mask, int sb, int *rd)
1442 int i, cnt = 1;
1444 if ((mask & (1 << sb)) == 0)
1445 return 0;
1447 *rd = sb;
1449 for (i = sb-1; i >= 0; i--)
1451 if (mask & (1 << i))
1453 cnt ++;
1454 continue;
1457 *rd = i+1;
1458 break;;
1461 return cnt;
1464 static void
1465 rpush (int rd, int cnt)
1467 rtx mem = gen_rtx_MEM (SImode, gen_rtx_PRE_DEC (SImode, stack_pointer_rtx));
1468 rtx reg = gen_rtx_REG (SImode, rd);
1470 if (!crtl->calls_eh_return)
1471 MEM_READONLY_P (mem) = 1;
1473 if (cnt == 1)
1474 EMIT_PL (emit_insn (gen_pushsi_score3 (mem, reg)));
1475 else
1477 int i;
1478 rtx insn = gen_store_multiple (gen_rtx_MEM (SImode, stack_pointer_rtx),
1479 gen_rtx_REG (SImode, rd),
1480 GEN_INT (cnt));
1482 rtx pat = PATTERN (insn);
1484 for (i = 0; i < XVECLEN (pat, 0); i++)
1485 if (GET_CODE (XVECEXP (pat, 0, i)) == SET)
1486 RTX_FRAME_RELATED_P (XVECEXP (pat, 0, i)) = 1;
1488 EMIT_PL (emit_insn (insn));
1492 /* Generate the prologue instructions for entry into a S+core function. */
1493 void
1494 score3_prologue (void)
1496 struct score3_frame_info *f = score3_compute_frame_size (get_frame_size ());
1497 HOST_WIDE_INT size;
1498 int regno;
1500 size = f->total_size - f->gp_reg_size;
1502 if (flag_pic)
1503 emit_insn (gen_cpload_score3 ());
1506 int cnt, rd;
1508 for (regno = (int) GP_REG_LAST; regno >= (int) GP_REG_FIRST; regno--)
1510 cnt = rpush_first (f->mask, regno, &rd);
1511 if (cnt != 0)
1513 rpush (rd, cnt);
1514 regno = regno - cnt;
1519 if (size > 0)
1521 rtx insn;
1523 if (CONST_OK_FOR_LETTER_P (-size, 'L'))
1524 EMIT_PL (emit_insn (gen_add3_insn (stack_pointer_rtx,
1525 stack_pointer_rtx,
1526 GEN_INT (-size))));
1527 else
1529 EMIT_PL (emit_move_insn (gen_rtx_REG (Pmode, SCORE3_PROLOGUE_TEMP_REGNUM),
1530 GEN_INT (size)));
1531 EMIT_PL (emit_insn
1532 (gen_sub3_insn (stack_pointer_rtx,
1533 stack_pointer_rtx,
1534 gen_rtx_REG (Pmode,
1535 SCORE3_PROLOGUE_TEMP_REGNUM))));
1537 insn = get_last_insn ();
1538 REG_NOTES (insn) =
1539 alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR,
1540 gen_rtx_SET (VOIDmode, stack_pointer_rtx,
1541 plus_constant (stack_pointer_rtx,
1542 -size)),
1543 REG_NOTES (insn));
1546 if (frame_pointer_needed)
1547 EMIT_PL (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx));
1549 if (flag_pic && f->cprestore_size)
1551 if (frame_pointer_needed)
1552 emit_insn (gen_cprestore_use_fp_score3 (GEN_INT (size - f->cprestore_size)));
1553 else
1554 emit_insn (gen_cprestore_use_sp_score3 (GEN_INT (size - f->cprestore_size)));
1558 /* return 0, no more bit set in mask. */
1559 static int
1560 rpop_first (int mask, int sb, int *rd)
1562 int i, cnt = 1;
1564 if ((mask & (1 << sb)) == 0)
1565 return 0;
1567 *rd = sb;
1569 for (i = sb+1; i < 32; i++)
1570 if (mask & (1 << i))
1571 cnt++;
1572 else
1573 break;;
1575 return cnt;
1578 static void
1579 rpop (int rd, int cnt)
1581 rtx mem = gen_rtx_MEM (SImode, gen_rtx_POST_INC (SImode, stack_pointer_rtx));
1582 rtx reg = gen_rtx_REG (SImode, rd);
1584 if (!crtl->calls_eh_return)
1585 MEM_READONLY_P (mem) = 1;
1587 if (cnt == 1)
1588 emit_insn (gen_popsi_score3 (reg, mem));
1589 else
1590 emit_insn (gen_load_multiple (reg,
1591 gen_rtx_MEM (SImode, stack_pointer_rtx),
1592 GEN_INT (cnt)));
1595 /* Generate the epilogue instructions in a S+core function. */
1596 void
1597 score3_epilogue (int sibcall_p)
1599 struct score3_frame_info *f = score3_compute_frame_size (get_frame_size ());
1600 HOST_WIDE_INT size;
1601 int regno;
1602 rtx base;
1604 size = f->total_size - f->gp_reg_size;
1606 if (!frame_pointer_needed)
1607 base = stack_pointer_rtx;
1608 else
1609 base = hard_frame_pointer_rtx;
1611 if (size)
1613 if (CONST_OK_FOR_LETTER_P (size, 'L'))
1614 emit_insn (gen_add3_insn (base, base, GEN_INT (size)));
1615 else
1617 emit_move_insn (gen_rtx_REG (Pmode, SCORE3_EPILOGUE_TEMP_REGNUM),
1618 GEN_INT (size));
1619 emit_insn (gen_add3_insn (base, base,
1620 gen_rtx_REG (Pmode,
1621 SCORE3_EPILOGUE_TEMP_REGNUM)));
1625 if (base != stack_pointer_rtx)
1626 emit_move_insn (stack_pointer_rtx, base);
1628 if (crtl->calls_eh_return)
1629 emit_insn (gen_add3_insn (stack_pointer_rtx,
1630 stack_pointer_rtx,
1631 EH_RETURN_STACKADJ_RTX));
1634 int cnt, rd;
1636 for (regno = (int) GP_REG_FIRST; regno <= (int) GP_REG_LAST; regno++)
1638 cnt = rpop_first (f->mask, regno, &rd);
1639 if (cnt != 0)
1641 rpop (rd, cnt);
1642 regno = regno + cnt;
1647 if (!sibcall_p)
1648 emit_jump_insn (gen_return_internal_score3 (gen_rtx_REG (Pmode, RA_REGNUM)));
1651 void
1652 score3_gen_cmp (enum machine_mode mode)
1654 emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (mode, CC_REGNUM),
1655 gen_rtx_COMPARE (mode, cmp_op0, cmp_op1)));
1658 /* Return true if X is a symbolic constant that can be calculated in
1659 the same way as a bare symbol. If it is, store the type of the
1660 symbol in *SYMBOL_TYPE. */
1662 score3_symbolic_constant_p (rtx x, enum score_symbol_type *symbol_type)
1664 HOST_WIDE_INT offset;
1666 score3_split_const (x, &x, &offset);
1667 if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF)
1668 *symbol_type = score3_classify_symbol (x);
1669 else
1670 return 0;
1672 if (offset == 0)
1673 return 1;
1675 /* if offset > 15bit, must reload */
1676 if (!IMM_IN_RANGE (offset, 15, 1))
1677 return 0;
1679 switch (*symbol_type)
1681 case SYMBOL_GENERAL:
1682 return 1;
1683 case SYMBOL_SMALL_DATA:
1684 return score3_offset_within_object_p (x, offset);
1686 gcc_unreachable ();
1689 void
1690 score3_movsicc (rtx *ops)
1692 enum machine_mode mode;
1694 mode = score3_select_cc_mode (GET_CODE (ops[1]), ops[2], ops[3]);
1695 emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (mode, CC_REGNUM),
1696 gen_rtx_COMPARE (mode, cmp_op0, cmp_op1)));
1699 /* Call and sibcall pattern all need call this function. */
1700 void
1701 score3_call (rtx *ops, bool sib)
1703 rtx addr = XEXP (ops[0], 0);
1704 if (!call_insn_operand (addr, VOIDmode))
1706 rtx oaddr = addr;
1707 addr = gen_reg_rtx (Pmode);
1708 gen_move_insn (addr, oaddr);
1711 if (sib)
1712 emit_call_insn (gen_sibcall_internal_score3 (addr, ops[1]));
1713 else
1714 emit_call_insn (gen_call_internal_score3 (addr, ops[1]));
1717 /* Call value and sibcall value pattern all need call this function. */
1718 void
1719 score3_call_value (rtx *ops, bool sib)
1721 rtx result = ops[0];
1722 rtx addr = XEXP (ops[1], 0);
1723 rtx arg = ops[2];
1725 if (!call_insn_operand (addr, VOIDmode))
1727 rtx oaddr = addr;
1728 addr = gen_reg_rtx (Pmode);
1729 gen_move_insn (addr, oaddr);
1732 if (sib)
1733 emit_call_insn (gen_sibcall_value_internal_score3 (result, addr, arg));
1734 else
1735 emit_call_insn (gen_call_value_internal_score3 (result, addr, arg));
1738 /* Machine Split */
1739 void
1740 score3_movdi (rtx *ops)
1742 rtx dst = ops[0];
1743 rtx src = ops[1];
1744 rtx dst0 = score3_subw (dst, 0);
1745 rtx dst1 = score3_subw (dst, 1);
1746 rtx src0 = score3_subw (src, 0);
1747 rtx src1 = score3_subw (src, 1);
1749 if (GET_CODE (dst0) == REG && reg_overlap_mentioned_p (dst0, src))
1751 emit_move_insn (dst1, src1);
1752 emit_move_insn (dst0, src0);
1754 else
1756 emit_move_insn (dst0, src0);
1757 emit_move_insn (dst1, src1);
1761 void
1762 score3_zero_extract_andi (rtx *ops)
1764 if (INTVAL (ops[1]) == 1 && const_uimm5 (ops[2], SImode))
1765 emit_insn (gen_zero_extract_bittst_score3 (ops[0], ops[2]));
1766 else
1768 unsigned HOST_WIDE_INT mask;
1769 mask = (0xffffffffU & ((1U << INTVAL (ops[1])) - 1U));
1770 mask = mask << INTVAL (ops[2]);
1771 emit_insn (gen_andsi3_cmp_score3 (ops[3], ops[0],
1772 gen_int_mode (mask, SImode)));
1776 const char *
1777 score3_rpush (rtx *ops)
1779 snprintf (score3_ins, INS_BUF_SZ, "rpush!\t%%1, %d", XVECLEN (ops[0], 0));
1780 return score3_ins;
1783 const char *
1784 score3_rpop (rtx *ops)
1786 snprintf (score3_ins, INS_BUF_SZ, "rpop!\t%%1, %d", XVECLEN (ops[0], 0));
1787 return score3_ins;
1790 /* Output asm code for ld/sw insn. */
1791 static int
1792 score3_pr_addr_post (rtx *ops, int idata, int iaddr, char *ip,
1793 enum score_mem_unit unit ATTRIBUTE_UNUSED)
1795 struct score3_address_info ai;
1797 gcc_assert (GET_CODE (ops[idata]) == REG);
1798 gcc_assert (score3_classify_address (&ai, SImode, XEXP (ops[iaddr], 0), true));
1800 if (ai.type == SCORE3_ADD_REG
1801 && ai.code == REG
1802 && GET_CODE (ai.offset) == CONST_INT
1803 && G16_REG_P (REGNO (ops[idata]))
1804 && G8_REG_P (REGNO (ai.reg))
1805 && ((INTVAL (ai.offset) & 3) == 0)
1806 && (IMM_IN_RANGE (INTVAL (ai.offset), 7, 0)))
1808 ops[iaddr] = ai.reg;
1809 return snprintf (ip, INS_BUF_SZ, "!\t%%%d, [%%%d, "
1810 HOST_WIDE_INT_PRINT_DEC "]",
1811 idata, iaddr, INTVAL (ai.offset));
1814 if (ai.type == SCORE3_ADD_SYMBOLIC)
1815 return snprintf (ip, INS_BUF_SZ, "48\t%%%d, %%a%d", idata, iaddr);
1817 return snprintf (ip, INS_BUF_SZ, "\t%%%d, %%a%d", idata, iaddr);
1820 /* Output asm insn for load. */
1821 const char *
1822 score3_linsn (rtx *ops, enum score_mem_unit unit, bool sign)
1824 const char *pre_ins[] =
1825 {"lbu", "lhu", "lw", "??", "lb", "lh", "lw", "??"};
1826 char *ip;
1828 strcpy (score3_ins, pre_ins[(sign ? 4 : 0) + unit]);
1829 ip = score3_ins + strlen (score3_ins);
1831 if (unit == SCORE_WORD)
1832 score3_pr_addr_post (ops, 0, 1, ip, unit);
1833 else
1834 snprintf (ip, INS_BUF_SZ, "\t%%0, %%a1");
1836 return score3_ins;
1839 /* Output asm insn for store. */
1840 const char *
1841 score3_sinsn (rtx *ops, enum score_mem_unit unit)
1843 const char *pre_ins[] = {"sb", "sh", "sw"};
1844 char *ip;
1846 strcpy (score3_ins, pre_ins[unit]);
1847 ip = score3_ins + strlen (score3_ins);
1849 if (unit == SCORE_WORD)
1850 score3_pr_addr_post (ops, 1, 0, ip, unit);
1851 else
1852 snprintf (ip, INS_BUF_SZ, "\t%%1, %%a0");
1854 return score3_ins;
1857 /* Output asm insn for load immediate. */
1858 const char *
1859 score3_limm (rtx *ops)
1861 HOST_WIDE_INT v;
1863 gcc_assert (GET_CODE (ops[0]) == REG);
1864 gcc_assert (GET_CODE (ops[1]) == CONST_INT);
1866 v = INTVAL (ops[1]);
1867 if (G16_REG_P (REGNO (ops[0])) && IMM_IN_RANGE (v, 5, 0))
1868 return "ldiu!\t%0, %c1";
1869 else if (IMM_IN_RANGE (v, 16, 1))
1870 return "ldi\t%0, %c1";
1871 else if ((v & 0xffff) == 0)
1872 return "ldis\t%0, %U1";
1873 else
1874 return "li\t%0, %c1";
1877 /* Output asm insn for move. */
1878 const char *
1879 score3_move (rtx *ops)
1881 gcc_assert (GET_CODE (ops[0]) == REG);
1882 gcc_assert (GET_CODE (ops[1]) == REG);
1884 return "mv!\t%0, %1";
1887 /* Generate add insn. */
1888 const char *
1889 score3_select_add_imm (rtx *ops, bool set_cc)
1891 HOST_WIDE_INT v = INTVAL (ops[2]);
1893 gcc_assert (GET_CODE (ops[2]) == CONST_INT);
1894 gcc_assert (REGNO (ops[0]) == REGNO (ops[1]));
1896 if (set_cc)
1897 return "addi.c\t%0, %c2";
1898 else
1899 if (IMM_IN_RANGE (v, 6, 1) && G16_REG_P (REGNO (ops[0])))
1900 return "addi!\t%0, %c2";
1901 else
1902 return "addi\t%0, %c2";
1905 /* Output arith insn. */
1906 const char *
1907 score3_select (rtx *ops, const char *inst_pre, bool commu ATTRIBUTE_UNUSED,
1908 const char *letter, bool set_cc)
1910 gcc_assert (GET_CODE (ops[0]) == REG);
1911 gcc_assert (GET_CODE (ops[1]) == REG);
1913 if (set_cc)
1914 snprintf (score3_ins, INS_BUF_SZ, "%s.c\t%%0, %%1, %%%s2", inst_pre, letter);
1915 else
1916 snprintf (score3_ins, INS_BUF_SZ, "%s\t%%0, %%1, %%%s2", inst_pre, letter);
1917 return score3_ins;
1920 /* Output a Score3 casesi instruction. */
1921 const char *
1922 score3_output_casesi (rtx *operands)
1924 rtx diff_vec = PATTERN (next_real_insn (operands[2]));
1925 gcc_assert (GET_CODE (diff_vec) == ADDR_DIFF_VEC);
1927 output_asm_insn ("cmpi.c\t%0, %1", operands);
1928 output_asm_insn ("bgtu\t%3", operands);
1929 switch (GET_MODE(diff_vec))
1931 case QImode:
1932 output_asm_insn ("ldi48\t%4, %2", operands);
1933 output_asm_insn ("ltbb\t%4, [%4, %0]\n%2_tbb:", operands);
1934 return "brr!\t%4";
1935 case HImode:
1936 output_asm_insn ("ldi48\t%4, %2", operands);
1937 output_asm_insn ("ltbh\t%4, [%4, %0]\n%2_tbb:", operands);
1938 return "brr!\t%4";
1939 case SImode:
1940 output_asm_insn ("ldi48\t%4, %2", operands);
1941 output_asm_insn ("ltbw\t%4, [%4, %0]", operands);
1942 return "br!\t%4";
1943 default:
1944 gcc_unreachable ();