OSDN Git Service

2008-04-03 Jan Hubicka <jh@suse.cz>
[pf3gnuchains/gcc-fork.git] / gcc / config / score / score3.c
1 /* score3.c for Sunplus S+CORE processor
2    Copyright (C) 2005, 2007 Free Software Foundation, Inc.
3    Contributed by Sunnorth
4
5    This file is part of GCC.
6
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.
11
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.
16
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/>.  */
20
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"
52
53 #define BITSET_P(VALUE, BIT)      (((VALUE) & (1L << (BIT))) != 0)
54 #define INS_BUF_SZ                128
55
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];
60
61 static int score3_sdata_max;
62 static char score3_ins[INS_BUF_SZ + 8];
63
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)
68 {
69   if (GET_CODE (symbol) != SYMBOL_REF)
70     return 0;
71
72   if (CONSTANT_POOL_ADDRESS_P (symbol)
73       && offset >= 0
74       && offset < (int)GET_MODE_SIZE (get_pool_mode (symbol)))
75     return 1;
76
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;
81
82   return 0;
83 }
84
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)
89 {
90   *offset = 0;
91
92   if (GET_CODE (x) == CONST)
93     x = XEXP (x, 0);
94
95   if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
96     {
97       *offset += INTVAL (XEXP (x, 1));
98       x = XEXP (x, 0);
99     }
100
101   *base = x;
102 }
103
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)
107 {
108   if (GET_CODE (x) == LABEL_REF)
109     return SYMBOL_GENERAL;
110
111   gcc_assert (GET_CODE (x) == SYMBOL_REF);
112
113   if (CONSTANT_POOL_ADDRESS_P (x))
114     {
115       if (GET_MODE_SIZE (get_pool_mode (x)) <= SCORE3_SDATA_MAX)
116         return SYMBOL_SMALL_DATA;
117       return SYMBOL_GENERAL;
118     }
119   if (SYMBOL_REF_SMALL_P (x))
120     return SYMBOL_SMALL_DATA;
121   return SYMBOL_GENERAL;
122 }
123
124 /* Return true if the current function must save REGNO.  */
125 static int
126 score3_save_reg_p (unsigned int regno)
127 {
128   /* Check call-saved registers.  */
129   if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
130     return 1;
131
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;
135
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;
140
141   return 0;
142 }
143
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)
149 {
150   unsigned int byte;
151   enum machine_mode mode = GET_MODE (op);
152
153   if (mode == VOIDmode)
154     mode = DImode;
155
156   byte = (TARGET_LITTLE_ENDIAN ? high_p : !high_p) ? UNITS_PER_WORD : 0;
157
158   if (GET_CODE (op) == REG && REGNO (op) == HI_REGNUM)
159     return gen_rtx_REG (SImode, high_p ? HI_REGNUM : LO_REGNUM);
160
161   if (GET_CODE (op) == MEM)
162     return adjust_address (op, SImode, byte);
163
164   return simplify_gen_subreg (SImode, op, mode, byte);
165 }
166
167 static struct score3_frame_info *
168 score3_cached_frame (void)
169 {
170   static struct score3_frame_info _frame_info;
171   return &_frame_info;
172 }
173
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)
178 {
179   unsigned int regno;
180   struct score3_frame_info *f = score3_cached_frame ();
181
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 = current_function_outgoing_args_size;
187   f->cprestore_size = flag_pic ? UNITS_PER_WORD : 0;
188
189   if (f->var_size == 0 && current_function_is_leaf)
190     f->args_size = f->cprestore_size = 0;
191
192   if (f->args_size == 0 && current_function_calls_alloca)
193     f->args_size = UNITS_PER_WORD;
194
195   f->total_size = f->var_size + f->args_size + f->cprestore_size;
196   for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
197     {
198       if (score3_save_reg_p (regno))
199         {
200           f->gp_reg_size += GET_MODE_SIZE (SImode);
201           f->mask |= 1 << (regno - GP_REG_FIRST);
202         }
203     }
204
205   if (current_function_calls_eh_return)
206     {
207       unsigned int i;
208       for (i = 0;; ++i)
209         {
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);
215         }
216     }
217
218   f->total_size += f->gp_reg_size;
219   f->num_gp = f->gp_reg_size / UNITS_PER_WORD;
220
221   if (f->mask)
222     {
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;
227     }
228   else
229     f->gp_sp_offset = 0;
230
231   return f;
232 }
233
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)
238 {
239   if (!strict && GET_CODE (x) == SUBREG)
240     x = SUBREG_REG (x);
241
242   return (GET_CODE (x) == REG
243           && score3_regno_mode_ok_for_base_p (REGNO (x), strict));
244 }
245
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)
252 {
253   info->code = GET_CODE (x);
254
255   switch (info->code)
256     {
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;
292     }
293 }
294
295 bool
296 score3_return_in_memory (tree type, tree fndecl ATTRIBUTE_UNUSED)
297 {
298     return ((TYPE_MODE (type) == BLKmode)
299             || (int_size_in_bytes (type) > 2 * UNITS_PER_WORD)
300             || (int_size_in_bytes (type) == -1));
301 }
302
303 /* Return a legitimate address for REG + OFFSET.  */
304 static rtx
305 score3_add_offset (rtx reg, HOST_WIDE_INT offset)
306 {
307   if (!IMM_IN_RANGE (offset, 15, 1))
308     {
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;
314     }
315
316   return plus_constant (reg, offset);
317 }
318
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)
325 {
326   rtx this, temp1, insn, fnaddr;
327
328   /* Pretend to be a post-reload pass while generating rtl.  */
329   reload_completed = 1;
330
331   /* Mark the end of the (empty) prologue.  */
332   emit_note (NOTE_INSN_PROLOGUE_END);
333
334   /* We need two temporary registers in some cases.  */
335   temp1 = gen_rtx_REG (Pmode, 8);
336
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);
342
343   /* Add DELTA to THIS.  */
344   if (delta != 0)
345     {
346       rtx offset = GEN_INT (delta);
347       if (!CONST_OK_FOR_LETTER_P (delta, 'L'))
348         {
349           emit_move_insn (temp1, offset);
350           offset = temp1;
351         }
352       emit_insn (gen_add3_insn (this, this, offset));
353     }
354
355   /* If needed, add *(*THIS + VCALL_OFFSET) to THIS.  */
356   if (vcall_offset != 0)
357     {
358       rtx addr;
359
360       /* Set TEMP1 to *THIS.  */
361       emit_move_insn (temp1, gen_rtx_MEM (Pmode, this));
362
363       /* Set ADDR to a legitimate address for *THIS + VCALL_OFFSET.  */
364       addr = score3_add_offset (temp1, vcall_offset);
365
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));
369     }
370
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;
375
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);
386
387   /* Clean up the vars set above.  Note that final_end_function resets
388      the global pointer for us.  */
389   reload_completed = 0;
390 }
391
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)
396 {
397   if (can_create_pseudo_p ())
398     return force_reg (Pmode, value);
399   else
400     {
401       emit_move_insn (copy_rtx (dest), value);
402       return dest;
403     }
404 }
405
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)
410 {
411   rtx high = score3_force_temporary (temp,
412                                      gen_rtx_HIGH (Pmode, copy_rtx (addr)));
413   return gen_rtx_LO_SUM (Pmode, high, addr);
414 }
415
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.  */
419 int
420 score3_legitimize_address (rtx *xloc)
421 {
422   enum score_symbol_type symbol_type;
423
424   if (score3_symbolic_constant_p (*xloc, &symbol_type)
425       && symbol_type == SYMBOL_GENERAL)
426     {
427       *xloc = score3_split_symbol (0, *xloc);
428       return 1;
429     }
430
431   if (GET_CODE (*xloc) == PLUS
432       && GET_CODE (XEXP (*xloc, 1)) == CONST_INT)
433     {
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;
439     }
440   return 0;
441 }
442
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)
450 {
451   int even_reg_p;
452   unsigned int num_words, max_regs;
453
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;
461
462   if (TARGET_MUST_PASS_IN_STACK (mode, type))
463     info->reg_offset = ARG_REG_NUM;
464   else
465     {
466       info->reg_offset = cum->num_gprs;
467       if (even_reg_p)
468         info->reg_offset += info->reg_offset & 1;
469     }
470
471   if (mode == BLKmode)
472     info->num_bytes = int_size_in_bytes (type);
473   else
474     info->num_bytes = GET_MODE_SIZE (mode);
475
476   num_words = (info->num_bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
477   max_regs = ARG_REG_NUM - info->reg_offset;
478
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;
482
483   /* The alignment applied to registers is also applied to stack arguments.  */
484   if (info->stack_words)
485     {
486       info->stack_offset = cum->stack_words;
487       if (even_reg_p)
488         info->stack_offset += info->stack_offset & 1;
489     }
490 }
491
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)
495 {
496   const char *fnname;
497   struct score3_frame_info *f = score3_cached_frame ();
498   HOST_WIDE_INT tsize = f->total_size;
499
500   fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
501   if (!flag_inhibit_size_directive)
502     {
503       fputs ("\t.ent\t", file);
504       assemble_name (file, fnname);
505       fputs ("\n", file);
506     }
507   assemble_name (file, fnname);
508   fputs (":\n", file);
509
510   if (!flag_inhibit_size_directive)
511     {
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);
526
527       fprintf(file, "\t.mask\t0x%08x," HOST_WIDE_INT_PRINT_DEC "\n",
528               f->mask,
529               (f->gp_sp_offset - f->total_size));
530     }
531 }
532
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)
538 {
539   if (!flag_inhibit_size_directive)
540     {
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);
546     }
547 }
548
549 /* Returns true if X contains a SYMBOL_REF.  */
550 static bool
551 score3_symbolic_expression_p (rtx x)
552 {
553   if (GET_CODE (x) == SYMBOL_REF)
554     return true;
555
556   if (GET_CODE (x) == CONST)
557     return score3_symbolic_expression_p (XEXP (x, 0));
558
559   if (UNARY_P (x))
560     return score3_symbolic_expression_p (XEXP (x, 0));
561
562   if (ARITHMETIC_P (x))
563     return (score3_symbolic_expression_p (XEXP (x, 0))
564             || score3_symbolic_expression_p (XEXP (x, 1)));
565
566   return false;
567 }
568
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)
574 {
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);
581 }
582
583 /* Implement TARGET_IN_SMALL_DATA_P.  */
584 bool
585 score3_in_small_data_p (tree decl)
586 {
587   HOST_WIDE_INT size;
588
589   if (TREE_CODE (decl) == STRING_CST
590       || TREE_CODE (decl) == FUNCTION_DECL)
591     return false;
592
593   if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl) != 0)
594     {
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;
602     }
603   size = int_size_in_bytes (TREE_TYPE (decl));
604   return (size > 0 && size <= SCORE3_SDATA_MAX);
605 }
606
607 /* Implement TARGET_ASM_FILE_START.  */
608 void
609 score3_asm_file_start (void)
610 {
611   default_file_start ();
612   fprintf (asm_out_file, ASM_COMMENT_START
613            "GCC for S+core %s \n", SCORE_GCC_VERSION);
614
615   if (flag_pic)
616     fprintf (asm_out_file, "\t.set pic\n");
617 }
618
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)
623 {
624   tree name_tree;
625   struct extern_list *p;
626   if (extern_head)
627     {
628       fputs ("\n", asm_out_file);
629       for (p = extern_head; p != 0; p = p->next)
630         {
631           name_tree = get_identifier (p->name);
632           if (!TREE_ASM_WRITTEN (name_tree)
633               && TREE_SYMBOL_REFERENCED (name_tree))
634             {
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);
639             }
640         }
641     }
642 }
643
644 /* Implement OVERRIDE_OPTIONS macro.  */
645 void
646 score3_override_options (void)
647 {
648   flag_pic = false;
649   if (!flag_pic)
650     score3_sdata_max = g_switch_set ? g_switch_value : SCORE3_DEFAULT_SDATA_MAX;
651   else
652     {
653       score3_sdata_max = 0;
654       if (g_switch_set && (g_switch_value != 0))
655         warning (0, "-fPIC and -G are incompatible");
656     }
657
658   score_char_to_class['d'] = G32_REGS;
659   score_char_to_class['e'] = G16_REGS;
660   score_char_to_class['t'] = T32_REGS;
661
662   score_char_to_class['h'] = HI_REG;
663   score_char_to_class['l'] = LO_REG;
664   score_char_to_class['x'] = CE_REGS;
665
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;
670
671   score_char_to_class['c'] = CR_REGS;
672 }
673
674 /* Implement REGNO_REG_CLASS macro.  */
675 int
676 score3_reg_class (int regno)
677 {
678   int c;
679   gcc_assert (regno >= 0 && regno < FIRST_PSEUDO_REGISTER);
680
681   if (regno == FRAME_POINTER_REGNUM
682       || regno == ARG_POINTER_REGNUM)
683     return ALL_REGS;
684
685   for (c = 0; c < N_REG_CLASSES; c++)
686     if (TEST_HARD_REG_BIT (reg_class_contents[c], regno))
687       return c;
688
689   return NO_REGS;
690 }
691
692 /* Implement PREFERRED_RELOAD_CLASS macro.  */
693 enum reg_class
694 score3_preferred_reload_class (rtx x ATTRIBUTE_UNUSED, enum reg_class class)
695 {
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;
701 }
702
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)
709 {
710   int regno = -1;
711   if (GET_CODE (x) == REG || GET_CODE(x) == SUBREG)
712     regno = true_regnum (x);
713
714   if (!GR_REG_CLASS_P (class))
715     return GP_REG_P (regno) ? NO_REGS : G32_REGS;
716   return NO_REGS;
717 }
718
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  */
730 int
731 score3_const_ok_for_letter_p (HOST_WIDE_INT value, char c)
732 {
733   switch (c)
734     {
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;
745     }
746 }
747
748 /* Implement EXTRA_CONSTRAINT macro.  */
749 /*
750    Q        uimm32
751    Z        symbol_ref  */
752 int
753 score3_extra_constraint (rtx op, char c)
754 {
755   switch (c)
756     {
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 ();
762     }
763 }
764
765 /* Return truth value on whether or not a given hard register
766    can support a given mode.  */
767 int
768 score3_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
769 {
770   int size = GET_MODE_SIZE (mode);
771   enum mode_class class = GET_MODE_CLASS (mode);
772
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);
786 }
787
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)
794 {
795   struct score3_frame_info *f = score3_compute_frame_size (get_frame_size ());
796   switch (from)
797     {
798     case ARG_POINTER_REGNUM:
799       return f->total_size;
800     case FRAME_POINTER_REGNUM:
801       return 0;
802     default:
803       gcc_unreachable ();
804     }
805 }
806
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)
811 {
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++;
818 }
819
820 /* Implement TARGET_ARG_PARTIAL_BYTES macro.  */
821 int
822 score3_arg_partial_bytes (CUMULATIVE_ARGS *cum,
823                           enum machine_mode mode, tree type, bool named)
824 {
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;
828 }
829
830 /* Implement FUNCTION_ARG macro.  */
831 rtx
832 score3_function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
833                      tree type, int named)
834 {
835   struct score3_arg_info info;
836
837   if (mode == VOIDmode || !named)
838     return 0;
839
840   score3_classify_arg (cum, mode, type, named, &info);
841
842   if (info.reg_offset == ARG_REG_NUM)
843     return 0;
844
845   if (!info.stack_words)
846     return gen_rtx_REG (mode, ARG_REG_FIRST + info.reg_offset);
847   else
848     {
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++)
852         {
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;
858         }
859       return ret;
860     }
861 }
862
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.  */
866 rtx
867 score3_function_value (tree valtype, tree func ATTRIBUTE_UNUSED,
868                        enum machine_mode mode)
869 {
870   if (valtype)
871     {
872       int unsignedp;
873       mode = TYPE_MODE (valtype);
874       unsignedp = TYPE_UNSIGNED (valtype);
875       mode = promote_mode (valtype, mode, &unsignedp, 1);
876     }
877   return gen_rtx_REG (mode, RT_REGNUM);
878 }
879
880 /* Implement INITIALIZE_TRAMPOLINE macro.  */
881 void
882 score3_initialize_trampoline (rtx ADDR, rtx FUNC, rtx CHAIN)
883 {
884 #define FFCACHE          "_flush_cache"
885 #define CODE_SIZE        (TRAMPOLINE_INSNS * UNITS_PER_WORD)
886
887   rtx pfunc, pchain;
888
889   pfunc = plus_constant (ADDR, CODE_SIZE);
890   pchain = plus_constant (ADDR, CODE_SIZE + GET_MODE_SIZE (SImode));
891
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
900 }
901
902 /* This function is used to implement REG_MODE_OK_FOR_BASE_P macro.  */
903 int
904 score3_regno_mode_ok_for_base_p (int regno, int strict)
905 {
906   if (regno >= FIRST_PSEUDO_REGISTER)
907     {
908       if (!strict)
909         return 1;
910       regno = reg_renumber[regno];
911     }
912   if (regno == ARG_POINTER_REGNUM
913       || regno == FRAME_POINTER_REGNUM)
914     return 1;
915   return GP_REG_P (regno);
916 }
917
918 /* Implement GO_IF_LEGITIMATE_ADDRESS macro.  */
919 int
920 score3_address_p (enum machine_mode mode, rtx x, int strict)
921 {
922   struct score3_address_info addr;
923
924   return score3_classify_address (&addr, mode, x, strict);
925 }
926
927 /* Return a number assessing the cost of moving a register in class
928    FROM to class TO. */
929 int
930 score3_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
931                            enum reg_class from, enum reg_class to)
932 {
933   if (GR_REG_CLASS_P (from))
934     {
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;
943     }
944   if (GR_REG_CLASS_P (to))
945     {
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;
954     }
955   return 12;
956 }
957
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)
962 {
963   switch (type)
964     {
965     case SYMBOL_GENERAL:
966       return 2;
967
968     case SYMBOL_SMALL_DATA:
969       return 1;
970     }
971
972   gcc_unreachable ();
973 }
974
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)
979 {
980   struct score3_address_info addr;
981   int factor;
982
983   if (mode == BLKmode)
984     factor = 1;
985   else
986     factor = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
987
988   if (score3_classify_address (&addr, mode, x, false))
989     switch (addr.type)
990       {
991       case SCORE3_ADD_REG:
992       case SCORE3_ADD_CONST_INT:
993         return factor;
994
995       case SCORE3_ADD_SYMBOLIC:
996         return factor * score3_symbol_insns (addr.symbol_type);
997       }
998   return 0;
999 }
1000
1001 /* Implement TARGET_RTX_COSTS macro.  */
1002 bool
1003 score3_rtx_costs (rtx x, int code, int outer_code, int *total)
1004 {
1005   enum machine_mode mode = GET_MODE (x);
1006
1007   switch (code)
1008     {
1009     case CONST_INT:
1010       if (outer_code == SET)
1011         {
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);
1017         }
1018       else if (outer_code == PLUS || outer_code == MINUS)
1019         {
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);
1027         }
1028       else if (outer_code == AND || outer_code == IOR)
1029         {
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);
1037         }
1038       else
1039         {
1040           *total = 0;
1041         }
1042       return true;
1043
1044     case CONST:
1045     case SYMBOL_REF:
1046     case LABEL_REF:
1047     case CONST_DOUBLE:
1048       *total = COSTS_N_INSNS (2);
1049       return true;
1050
1051     case MEM:
1052       {
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)
1057           {
1058             *total = COSTS_N_INSNS (n + 1);
1059             return true;
1060           }
1061         return false;
1062       }
1063
1064     case FFS:
1065       *total = COSTS_N_INSNS (6);
1066       return true;
1067
1068     case NOT:
1069       *total = COSTS_N_INSNS (1);
1070       return true;
1071
1072     case AND:
1073     case IOR:
1074     case XOR:
1075       if (mode == DImode)
1076         {
1077           *total = COSTS_N_INSNS (2);
1078           return true;
1079         }
1080       return false;
1081
1082     case ASHIFT:
1083     case ASHIFTRT:
1084     case LSHIFTRT:
1085       if (mode == DImode)
1086         {
1087           *total = COSTS_N_INSNS ((GET_CODE (XEXP (x, 1)) == CONST_INT)
1088                                   ? 4 : 12);
1089           return true;
1090         }
1091       return false;
1092
1093     case ABS:
1094       *total = COSTS_N_INSNS (4);
1095       return true;
1096
1097     case PLUS:
1098     case MINUS:
1099       if (mode == DImode)
1100         {
1101           *total = COSTS_N_INSNS (4);
1102           return true;
1103         }
1104       *total = COSTS_N_INSNS (1);
1105       return true;
1106
1107     case NEG:
1108       if (mode == DImode)
1109         {
1110           *total = COSTS_N_INSNS (4);
1111           return true;
1112         }
1113       return false;
1114
1115     case MULT:
1116       *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (12);
1117       return true;
1118
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;
1125
1126     case SIGN_EXTEND:
1127     case ZERO_EXTEND:
1128       switch (GET_MODE (XEXP (x, 0)))
1129         {
1130         case QImode:
1131         case HImode:
1132           if (GET_CODE (XEXP (x, 0)) == MEM)
1133             {
1134               *total = COSTS_N_INSNS (2);
1135
1136               if (!TARGET_LITTLE_ENDIAN &&
1137                   side_effects_p (XEXP (XEXP (x, 0), 0)))
1138                 *total = 100;
1139             }
1140           else
1141             *total = COSTS_N_INSNS (1);
1142           break;
1143
1144         default:
1145           *total = COSTS_N_INSNS (1);
1146           break;
1147         }
1148       return true;
1149
1150     default:
1151       return false;
1152     }
1153 }
1154
1155 /* Implement TARGET_ADDRESS_COST macro.  */
1156 int
1157 score3_address_cost (rtx addr)
1158 {
1159   return score3_address_insns (addr, SImode);
1160 }
1161
1162 /* Implement ASM_OUTPUT_EXTERNAL macro.  */
1163 int
1164 score3_output_external (FILE *file ATTRIBUTE_UNUSED,
1165                         tree decl, const char *name)
1166 {
1167   register struct extern_list *p;
1168
1169   if (score3_in_small_data_p (decl))
1170     {
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;
1176     }
1177   return 0;
1178 }
1179
1180 /* Implement RETURN_ADDR_RTX.  Note, we do not support moving
1181    back to a previous frame.  */
1182 rtx
1183 score3_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
1184 {
1185   if (count != 0)
1186     return const0_rtx;
1187   return get_hard_reg_initial_val (Pmode, RA_REGNUM);
1188 }
1189
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)
1205 {
1206   enum rtx_code code = -1;
1207   if (!PRINT_OPERAND_PUNCT_VALID_P (c))
1208     code = GET_CODE (op);
1209
1210   if (c == '[')
1211     {
1212       fprintf (file, ".set r1\n");
1213     }
1214   else if (c == ']')
1215     {
1216       fprintf (file, "\n\t.set nor1");
1217     }
1218   else if (c == 'U')
1219     {
1220       gcc_assert (code == CONST_INT);
1221       fprintf (file, HOST_WIDE_INT_PRINT_HEX,
1222                (INTVAL (op) >> 16) & 0xffff);
1223     }
1224   else if (c == 'D')
1225     {
1226       if (GET_CODE (op) == CONST_DOUBLE)
1227         {
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);
1231         }
1232       else
1233         output_addr_const (file, op);
1234     }
1235   else if (c == 'S')
1236     {
1237       gcc_assert (code == REG);
1238       if (G16_REG_P (REGNO (op)))
1239         fprintf (file, "!");
1240     }
1241   else if (c == 'V')
1242     {
1243       gcc_assert (code == REG);
1244       fprintf (file, G16_REG_P (REGNO (op)) ? "v!" : "lfh!");
1245     }
1246   else if (c == 'C')
1247     {
1248       enum machine_mode mode = GET_MODE (XEXP (op, 0));
1249
1250       switch (code)
1251         {
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);
1264         }
1265     }
1266   else if (c == 'G')  /* Seperate from b<cond>, use for mv<cond>.  */
1267     {
1268       enum machine_mode mode = GET_MODE (XEXP (op, 0));
1269
1270       switch (code)
1271         {
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);
1284         }
1285     }
1286   else if (c == 'E')
1287     {
1288       unsigned HOST_WIDE_INT i;
1289       unsigned HOST_WIDE_INT pow2mask = 1;
1290       unsigned HOST_WIDE_INT val;
1291
1292       val = INTVAL (op);
1293       for (i = 0; i < 32; i++)
1294         {
1295           if (val == pow2mask)
1296             break;
1297           pow2mask <<= 1;
1298         }
1299       gcc_assert (i < 32);
1300       fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
1301     }
1302   else if (c == 'F')
1303     {
1304       unsigned HOST_WIDE_INT i;
1305       unsigned HOST_WIDE_INT pow2mask = 1;
1306       unsigned HOST_WIDE_INT val;
1307
1308       val = ~INTVAL (op);
1309       for (i = 0; i < 32; i++)
1310         {
1311           if (val == pow2mask)
1312             break;
1313           pow2mask <<= 1;
1314         }
1315       gcc_assert (i < 32);
1316       fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
1317     }
1318   else if (code == REG)
1319     {
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]);
1325     }
1326   else
1327     {
1328       switch (code)
1329         {
1330         case MEM:
1331           score3_print_operand_address (file, op);
1332           break;
1333         default:
1334           output_addr_const (file, op);
1335         }
1336     }
1337 }
1338
1339 /* Implement PRINT_OPERAND_ADDRESS macro.  */
1340 void
1341 score3_print_operand_address (FILE *file, rtx x)
1342 {
1343   struct score3_address_info addr;
1344   enum rtx_code code = GET_CODE (x);
1345   enum machine_mode mode = GET_MODE (x);
1346
1347   if (code == MEM)
1348     x = XEXP (x, 0);
1349
1350   if (score3_classify_address (&addr, mode, x, true))
1351     {
1352       switch (addr.type)
1353         {
1354         case SCORE3_ADD_REG:
1355           {
1356             switch (addr.code)
1357               {
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;
1381               }
1382           }
1383           return;
1384         case SCORE3_ADD_CONST_INT:
1385         case SCORE3_ADD_SYMBOLIC:
1386           output_addr_const (file, x);
1387           return;
1388         }
1389     }
1390   print_rtl (stderr, x);
1391   gcc_unreachable ();
1392 }
1393
1394 /* Implement SELECT_CC_MODE macro.  */
1395 enum machine_mode
1396 score3_select_cc_mode (enum rtx_code op, rtx x, rtx y)
1397 {
1398   if ((op == EQ || op == NE || op == LT || op == GE)
1399       && y == const0_rtx
1400       && GET_MODE (x) == SImode)
1401     {
1402       switch (GET_CODE (x))
1403         {
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;
1415
1416         case SIGN_EXTEND:
1417         case ZERO_EXTEND:
1418         case ROTATE:
1419         case ROTATERT:
1420           return (op == LT || op == GE) ? CC_Nmode : CCmode;
1421
1422         default:
1423           return CCmode;
1424         }
1425     }
1426
1427   if ((op == EQ || op == NE)
1428       && (GET_CODE (y) == NEG)
1429       && register_operand (XEXP (y, 0), SImode)
1430       && register_operand (x, SImode))
1431     {
1432       return CC_NZmode;
1433     }
1434
1435   return CCmode;
1436 }
1437
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)
1441 {
1442   int i, cnt = 1;
1443
1444   if ((mask & (1 << sb)) == 0)
1445     return 0;
1446
1447   *rd = sb;
1448
1449   for (i = sb-1; i >= 0; i--)
1450     {
1451       if (mask & (1 << i))
1452         {
1453           cnt ++;
1454           continue;
1455         }
1456
1457       *rd = i+1;
1458       break;;
1459     }
1460
1461   return cnt;
1462 }
1463
1464 static void
1465 rpush (int rd, int cnt)
1466 {
1467   rtx mem = gen_rtx_MEM (SImode, gen_rtx_PRE_DEC (SImode, stack_pointer_rtx));
1468   rtx reg = gen_rtx_REG (SImode, rd);
1469
1470   if (!current_function_calls_eh_return)
1471     MEM_READONLY_P (mem) = 1;
1472
1473   if (cnt == 1)
1474     EMIT_PL (emit_insn (gen_pushsi_score3 (mem, reg)));
1475   else
1476     {
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));
1481
1482       rtx pat = PATTERN (insn);
1483
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;
1487
1488       EMIT_PL (emit_insn (insn));
1489     }
1490 }
1491
1492 /* Generate the prologue instructions for entry into a S+core function.  */
1493 void
1494 score3_prologue (void)
1495 {
1496   struct score3_frame_info *f = score3_compute_frame_size (get_frame_size ());
1497   HOST_WIDE_INT size;
1498   int regno;
1499
1500   size = f->total_size - f->gp_reg_size;
1501
1502   if (flag_pic)
1503     emit_insn (gen_cpload_score3 ());
1504
1505   {
1506     int cnt, rd;
1507
1508     for (regno = (int) GP_REG_LAST; regno >= (int) GP_REG_FIRST; regno--)
1509       {
1510         cnt = rpush_first (f->mask, regno, &rd);
1511         if (cnt != 0)
1512           {
1513             rpush (rd, cnt);
1514             regno = regno - cnt;
1515           }
1516       }
1517   }
1518
1519   if (size > 0)
1520     {
1521       rtx insn;
1522
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
1528         {
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))));
1536         }
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));
1544     }
1545
1546   if (frame_pointer_needed)
1547     EMIT_PL (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx));
1548
1549   if (flag_pic && f->cprestore_size)
1550     {
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)));
1555     }
1556 }
1557
1558 /* return 0, no more bit set in mask.  */
1559 static int
1560 rpop_first (int mask, int sb, int *rd)
1561 {
1562   int i, cnt = 1;
1563
1564   if ((mask & (1 << sb)) == 0)
1565     return 0;
1566
1567   *rd = sb;
1568
1569   for (i = sb+1; i < 32; i++)
1570     if (mask & (1 << i))
1571       cnt++;
1572     else
1573       break;;
1574
1575   return cnt;
1576 }
1577
1578 static void
1579 rpop (int rd, int cnt)
1580 {
1581   rtx mem = gen_rtx_MEM (SImode, gen_rtx_POST_INC (SImode, stack_pointer_rtx));
1582   rtx reg = gen_rtx_REG (SImode, rd);
1583
1584   if (!current_function_calls_eh_return)
1585     MEM_READONLY_P (mem) = 1;
1586
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)));
1593 }
1594
1595 /* Generate the epilogue instructions in a S+core function.  */
1596 void
1597 score3_epilogue (int sibcall_p)
1598 {
1599   struct score3_frame_info *f = score3_compute_frame_size (get_frame_size ());
1600   HOST_WIDE_INT size;
1601   int regno;
1602   rtx base;
1603
1604   size = f->total_size - f->gp_reg_size;
1605
1606   if (!frame_pointer_needed)
1607     base = stack_pointer_rtx;
1608   else
1609     base = hard_frame_pointer_rtx;
1610
1611   if (size)
1612     {
1613       if (CONST_OK_FOR_LETTER_P (size, 'L'))
1614         emit_insn (gen_add3_insn (base, base, GEN_INT (size)));
1615       else
1616         {
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)));
1622         }
1623     }
1624
1625   if (base != stack_pointer_rtx)
1626     emit_move_insn (stack_pointer_rtx, base);
1627
1628   if (current_function_calls_eh_return)
1629     emit_insn (gen_add3_insn (stack_pointer_rtx,
1630                               stack_pointer_rtx,
1631                               EH_RETURN_STACKADJ_RTX));
1632
1633   {
1634     int cnt, rd;
1635
1636     for (regno = (int) GP_REG_FIRST; regno <= (int) GP_REG_LAST; regno++)
1637       {
1638         cnt = rpop_first (f->mask, regno, &rd);
1639         if (cnt != 0)
1640           {
1641             rpop (rd, cnt);
1642             regno = regno + cnt;
1643           }
1644       }
1645   }
1646
1647   if (!sibcall_p)
1648     emit_jump_insn (gen_return_internal_score3 (gen_rtx_REG (Pmode, RA_REGNUM)));
1649 }
1650
1651 void
1652 score3_gen_cmp (enum machine_mode mode)
1653 {
1654   emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (mode, CC_REGNUM),
1655                           gen_rtx_COMPARE (mode, cmp_op0, cmp_op1)));
1656 }
1657
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.  */
1661 int
1662 score3_symbolic_constant_p (rtx x, enum score_symbol_type *symbol_type)
1663 {
1664   HOST_WIDE_INT offset;
1665
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;
1671
1672   if (offset == 0)
1673     return 1;
1674
1675   /* if offset > 15bit, must reload  */
1676   if (!IMM_IN_RANGE (offset, 15, 1))
1677     return 0;
1678
1679   switch (*symbol_type)
1680     {
1681     case SYMBOL_GENERAL:
1682       return 1;
1683     case SYMBOL_SMALL_DATA:
1684       return score3_offset_within_object_p (x, offset);
1685     }
1686   gcc_unreachable ();
1687 }
1688
1689 void
1690 score3_movsicc (rtx *ops)
1691 {
1692   enum machine_mode mode;
1693
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)));
1697 }
1698
1699 /* Call and sibcall pattern all need call this function.  */
1700 void
1701 score3_call (rtx *ops, bool sib)
1702 {
1703   rtx addr = XEXP (ops[0], 0);
1704   if (!call_insn_operand (addr, VOIDmode))
1705     {
1706       rtx oaddr = addr;
1707       addr = gen_reg_rtx (Pmode);
1708       gen_move_insn (addr, oaddr);
1709     }
1710
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]));
1715 }
1716
1717 /* Call value and sibcall value pattern all need call this function.  */
1718 void
1719 score3_call_value (rtx *ops, bool sib)
1720 {
1721   rtx result = ops[0];
1722   rtx addr = XEXP (ops[1], 0);
1723   rtx arg = ops[2];
1724
1725   if (!call_insn_operand (addr, VOIDmode))
1726     {
1727       rtx oaddr = addr;
1728       addr = gen_reg_rtx (Pmode);
1729       gen_move_insn (addr, oaddr);
1730     }
1731
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));
1736 }
1737
1738 /* Machine Split  */
1739 void
1740 score3_movdi (rtx *ops)
1741 {
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);
1748
1749   if (GET_CODE (dst0) == REG && reg_overlap_mentioned_p (dst0, src))
1750     {
1751       emit_move_insn (dst1, src1);
1752       emit_move_insn (dst0, src0);
1753     }
1754   else
1755     {
1756       emit_move_insn (dst0, src0);
1757       emit_move_insn (dst1, src1);
1758     }
1759 }
1760
1761 void
1762 score3_zero_extract_andi (rtx *ops)
1763 {
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
1767     {
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)));
1773     }
1774 }
1775
1776 const char *
1777 score3_rpush (rtx *ops)
1778 {
1779   snprintf (score3_ins, INS_BUF_SZ, "rpush!\t%%1, %d", XVECLEN (ops[0], 0));
1780   return score3_ins;
1781 }
1782
1783 const char *
1784 score3_rpop (rtx *ops)
1785 {
1786   snprintf (score3_ins, INS_BUF_SZ, "rpop!\t%%1, %d", XVECLEN (ops[0], 0));
1787   return score3_ins;
1788 }
1789
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)
1794 {
1795   struct score3_address_info ai;
1796
1797   gcc_assert (GET_CODE (ops[idata]) == REG);
1798   gcc_assert (score3_classify_address (&ai, SImode, XEXP (ops[iaddr], 0), true));
1799
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)))
1807     {
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));
1812     }
1813
1814   if (ai.type == SCORE3_ADD_SYMBOLIC)
1815     return snprintf (ip, INS_BUF_SZ, "48\t%%%d, %%a%d", idata, iaddr);
1816
1817   return snprintf (ip, INS_BUF_SZ, "\t%%%d, %%a%d", idata, iaddr);
1818 }
1819
1820 /* Output asm insn for load.  */
1821 const char *
1822 score3_linsn (rtx *ops, enum score_mem_unit unit, bool sign)
1823 {
1824   const char *pre_ins[] =
1825     {"lbu", "lhu", "lw", "??", "lb", "lh", "lw", "??"};
1826   char *ip;
1827
1828   strcpy (score3_ins, pre_ins[(sign ? 4 : 0) + unit]);
1829   ip = score3_ins + strlen (score3_ins);
1830
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");
1835
1836   return score3_ins;
1837 }
1838
1839 /* Output asm insn for store.  */
1840 const char *
1841 score3_sinsn (rtx *ops, enum score_mem_unit unit)
1842 {
1843   const char *pre_ins[] = {"sb", "sh", "sw"};
1844   char *ip;
1845
1846   strcpy (score3_ins, pre_ins[unit]);
1847   ip = score3_ins + strlen (score3_ins);
1848
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");
1853
1854   return score3_ins;
1855 }
1856
1857 /* Output asm insn for load immediate.  */
1858 const char *
1859 score3_limm (rtx *ops)
1860 {
1861   HOST_WIDE_INT v;
1862
1863   gcc_assert (GET_CODE (ops[0]) == REG);
1864   gcc_assert (GET_CODE (ops[1]) == CONST_INT);
1865
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";
1875 }
1876
1877 /* Output asm insn for move.  */
1878 const char *
1879 score3_move (rtx *ops)
1880 {
1881   gcc_assert (GET_CODE (ops[0]) == REG);
1882   gcc_assert (GET_CODE (ops[1]) == REG);
1883
1884   return "mv!\t%0, %1";
1885 }
1886
1887 /* Generate add insn.  */
1888 const char *
1889 score3_select_add_imm (rtx *ops, bool set_cc)
1890 {
1891   HOST_WIDE_INT v = INTVAL (ops[2]);
1892
1893   gcc_assert (GET_CODE (ops[2]) == CONST_INT);
1894   gcc_assert (REGNO (ops[0]) == REGNO (ops[1]));
1895
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";
1903 }
1904
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)
1909 {
1910   gcc_assert (GET_CODE (ops[0]) == REG);
1911   gcc_assert (GET_CODE (ops[1]) == REG);
1912
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;
1918 }
1919
1920 /* Output a Score3 casesi instruction.  */
1921 const char *
1922 score3_output_casesi (rtx *operands)
1923 {
1924   rtx diff_vec = PATTERN (next_real_insn (operands[2]));
1925   gcc_assert (GET_CODE (diff_vec) == ADDR_DIFF_VEC);
1926
1927   output_asm_insn ("cmpi.c\t%0, %1", operands);
1928   output_asm_insn ("bgtu\t%3", operands);
1929   switch (GET_MODE(diff_vec))
1930     {
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 ();
1945     }
1946 }