OSDN Git Service

f268cbaf2df2db0b19e4e9e98692a1f44ce7030e
[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
386   /* Clean up the vars set above.  Note that final_end_function resets
387      the global pointer for us.  */
388   reload_completed = 0;
389 }
390
391 /* Copy VALUE to a register and return that register.  If new psuedos
392    are allowed, copy it into a new register, otherwise use DEST.  */
393 static rtx
394 score3_force_temporary (rtx dest, rtx value)
395 {
396   if (can_create_pseudo_p ())
397     return force_reg (Pmode, value);
398   else
399     {
400       emit_move_insn (copy_rtx (dest), value);
401       return dest;
402     }
403 }
404
405 /* Return a LO_SUM expression for ADDR.  TEMP is as for score_force_temporary
406    and is used to load the high part into a register.  */
407 static rtx
408 score3_split_symbol (rtx temp, rtx addr)
409 {
410   rtx high = score3_force_temporary (temp,
411                                      gen_rtx_HIGH (Pmode, copy_rtx (addr)));
412   return gen_rtx_LO_SUM (Pmode, high, addr);
413 }
414
415 /* This function is used to implement LEGITIMIZE_ADDRESS.  If *XLOC can
416    be legitimized in a way that the generic machinery might not expect,
417    put the new address in *XLOC and return true.  */
418 int
419 score3_legitimize_address (rtx *xloc)
420 {
421   enum score_symbol_type symbol_type;
422
423   if (score3_symbolic_constant_p (*xloc, &symbol_type)
424       && symbol_type == SYMBOL_GENERAL)
425     {
426       *xloc = score3_split_symbol (0, *xloc);
427       return 1;
428     }
429
430   if (GET_CODE (*xloc) == PLUS
431       && GET_CODE (XEXP (*xloc, 1)) == CONST_INT)
432     {
433       rtx reg = XEXP (*xloc, 0);
434       if (!score3_valid_base_register_p (reg, 0))
435         reg = copy_to_mode_reg (Pmode, reg);
436       *xloc = score3_add_offset (reg, INTVAL (XEXP (*xloc, 1)));
437       return 1;
438     }
439   return 0;
440 }
441
442 /* Fill INFO with information about a single argument.  CUM is the
443    cumulative state for earlier arguments.  MODE is the mode of this
444    argument and TYPE is its type (if known).  NAMED is true if this
445    is a named (fixed) argument rather than a variable one.  */
446 static void
447 score3_classify_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
448                      tree type, int named, struct score3_arg_info *info)
449 {
450   int even_reg_p;
451   unsigned int num_words, max_regs;
452
453   even_reg_p = 0;
454   if (GET_MODE_CLASS (mode) == MODE_INT
455       || GET_MODE_CLASS (mode) == MODE_FLOAT)
456     even_reg_p = (GET_MODE_SIZE (mode) > UNITS_PER_WORD);
457   else
458     if (type != NULL_TREE && TYPE_ALIGN (type) > BITS_PER_WORD && named)
459       even_reg_p = 1;
460
461   if (TARGET_MUST_PASS_IN_STACK (mode, type))
462     info->reg_offset = ARG_REG_NUM;
463   else
464     {
465       info->reg_offset = cum->num_gprs;
466       if (even_reg_p)
467         info->reg_offset += info->reg_offset & 1;
468     }
469
470   if (mode == BLKmode)
471     info->num_bytes = int_size_in_bytes (type);
472   else
473     info->num_bytes = GET_MODE_SIZE (mode);
474
475   num_words = (info->num_bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
476   max_regs = ARG_REG_NUM - info->reg_offset;
477
478   /* Partition the argument between registers and stack.  */
479   info->reg_words = MIN (num_words, max_regs);
480   info->stack_words = num_words - info->reg_words;
481
482   /* The alignment applied to registers is also applied to stack arguments.  */
483   if (info->stack_words)
484     {
485       info->stack_offset = cum->stack_words;
486       if (even_reg_p)
487         info->stack_offset += info->stack_offset & 1;
488     }
489 }
490
491 /* Set up the stack and frame (if desired) for the function.  */
492 void
493 score3_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
494 {
495   const char *fnname;
496   struct score3_frame_info *f = score3_cached_frame ();
497   HOST_WIDE_INT tsize = f->total_size;
498
499   fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
500   if (!flag_inhibit_size_directive)
501     {
502       fputs ("\t.ent\t", file);
503       assemble_name (file, fnname);
504       fputs ("\n", file);
505     }
506   assemble_name (file, fnname);
507   fputs (":\n", file);
508
509   if (!flag_inhibit_size_directive)
510     {
511       fprintf (file,
512                "\t.frame\t%s," HOST_WIDE_INT_PRINT_DEC ",%s, %d\t\t"
513                "# vars= " HOST_WIDE_INT_PRINT_DEC ", regs= %d"
514                ", args= " HOST_WIDE_INT_PRINT_DEC
515                ", gp= " HOST_WIDE_INT_PRINT_DEC "\n",
516                (reg_names[(frame_pointer_needed)
517                 ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM]),
518                tsize,
519                reg_names[RA_REGNUM],
520                current_function_is_leaf ? 1 : 0,
521                f->var_size,
522                f->num_gp,
523                f->args_size,
524                f->cprestore_size);
525
526       fprintf(file, "\t.mask\t0x%08x," HOST_WIDE_INT_PRINT_DEC "\n",
527               f->mask,
528               (f->gp_sp_offset - f->total_size));
529     }
530 }
531
532 /* Do any necessary cleanup after a function to restore stack, frame,
533    and regs.  */
534 void
535 score3_function_epilogue (FILE *file,
536                           HOST_WIDE_INT size ATTRIBUTE_UNUSED)
537 {
538   if (!flag_inhibit_size_directive)
539     {
540       const char *fnname;
541       fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
542       fputs ("\t.end\t", file);
543       assemble_name (file, fnname);
544       fputs ("\n", file);
545     }
546 }
547
548 /* Returns true if X contains a SYMBOL_REF.  */
549 static bool
550 score3_symbolic_expression_p (rtx x)
551 {
552   if (GET_CODE (x) == SYMBOL_REF)
553     return true;
554
555   if (GET_CODE (x) == CONST)
556     return score3_symbolic_expression_p (XEXP (x, 0));
557
558   if (UNARY_P (x))
559     return score3_symbolic_expression_p (XEXP (x, 0));
560
561   if (ARITHMETIC_P (x))
562     return (score3_symbolic_expression_p (XEXP (x, 0))
563             || score3_symbolic_expression_p (XEXP (x, 1)));
564
565   return false;
566 }
567
568 /* Choose the section to use for the constant rtx expression X that has
569    mode MODE.  */
570 section *
571 score3_select_rtx_section (enum machine_mode mode, rtx x,
572                            unsigned HOST_WIDE_INT align)
573 {
574   if (GET_MODE_SIZE (mode) <= SCORE3_SDATA_MAX)
575     return get_named_section (0, ".sdata", 0);
576   else if (flag_pic && score3_symbolic_expression_p (x))
577     return get_named_section (0, ".data.rel.ro", 3);
578   else
579     return mergeable_constant_section (mode, align, 0);
580 }
581
582 /* Implement TARGET_IN_SMALL_DATA_P.  */
583 bool
584 score3_in_small_data_p (tree decl)
585 {
586   HOST_WIDE_INT size;
587
588   if (TREE_CODE (decl) == STRING_CST
589       || TREE_CODE (decl) == FUNCTION_DECL)
590     return false;
591
592   if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl) != 0)
593     {
594       const char *name;
595       name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
596       if (strcmp (name, ".sdata") != 0
597           && strcmp (name, ".sbss") != 0)
598         return true;
599       if (!DECL_EXTERNAL (decl))
600         return false;
601     }
602   size = int_size_in_bytes (TREE_TYPE (decl));
603   return (size > 0 && size <= SCORE3_SDATA_MAX);
604 }
605
606 /* Implement TARGET_ASM_FILE_START.  */
607 void
608 score3_asm_file_start (void)
609 {
610   default_file_start ();
611   fprintf (asm_out_file, ASM_COMMENT_START
612            "GCC for S+core %s \n", SCORE_GCC_VERSION);
613
614   if (flag_pic)
615     fprintf (asm_out_file, "\t.set pic\n");
616 }
617
618 /* Implement TARGET_ASM_FILE_END.  When using assembler macros, emit
619    .externs for any small-data variables that turned out to be external.  */
620 void
621 score3_asm_file_end (void)
622 {
623   tree name_tree;
624   struct extern_list *p;
625   if (extern_head)
626     {
627       fputs ("\n", asm_out_file);
628       for (p = extern_head; p != 0; p = p->next)
629         {
630           name_tree = get_identifier (p->name);
631           if (!TREE_ASM_WRITTEN (name_tree)
632               && TREE_SYMBOL_REFERENCED (name_tree))
633             {
634               TREE_ASM_WRITTEN (name_tree) = 1;
635               fputs ("\t.extern\t", asm_out_file);
636               assemble_name (asm_out_file, p->name);
637               fprintf (asm_out_file, ", %d\n", p->size);
638             }
639         }
640     }
641 }
642
643 /* Implement OVERRIDE_OPTIONS macro.  */
644 void
645 score3_override_options (void)
646 {
647   flag_pic = false;
648   if (!flag_pic)
649     score3_sdata_max = g_switch_set ? g_switch_value : SCORE3_DEFAULT_SDATA_MAX;
650   else
651     {
652       score3_sdata_max = 0;
653       if (g_switch_set && (g_switch_value != 0))
654         warning (0, "-fPIC and -G are incompatible");
655     }
656
657   score_char_to_class['d'] = G32_REGS;
658   score_char_to_class['e'] = G16_REGS;
659   score_char_to_class['t'] = T32_REGS;
660
661   score_char_to_class['h'] = HI_REG;
662   score_char_to_class['l'] = LO_REG;
663   score_char_to_class['x'] = CE_REGS;
664
665   score_char_to_class['q'] = CN_REG;
666   score_char_to_class['y'] = LC_REG;
667   score_char_to_class['z'] = SC_REG;
668   score_char_to_class['a'] = SP_REGS;
669
670   score_char_to_class['c'] = CR_REGS;
671 }
672
673 /* Implement REGNO_REG_CLASS macro.  */
674 int
675 score3_reg_class (int regno)
676 {
677   int c;
678   gcc_assert (regno >= 0 && regno < FIRST_PSEUDO_REGISTER);
679
680   if (regno == FRAME_POINTER_REGNUM
681       || regno == ARG_POINTER_REGNUM)
682     return ALL_REGS;
683
684   for (c = 0; c < N_REG_CLASSES; c++)
685     if (TEST_HARD_REG_BIT (reg_class_contents[c], regno))
686       return c;
687
688   return NO_REGS;
689 }
690
691 /* Implement PREFERRED_RELOAD_CLASS macro.  */
692 enum reg_class
693 score3_preferred_reload_class (rtx x ATTRIBUTE_UNUSED, enum reg_class class)
694 {
695   if (reg_class_subset_p (G16_REGS, class))
696     return G16_REGS;
697   if (reg_class_subset_p (G32_REGS, class))
698     return G32_REGS;
699   return class;
700 }
701
702 /* Implement SECONDARY_INPUT_RELOAD_CLASS
703    and SECONDARY_OUTPUT_RELOAD_CLASS macro.  */
704 enum reg_class
705 score3_secondary_reload_class (enum reg_class class,
706                                enum machine_mode mode ATTRIBUTE_UNUSED,
707                                rtx x)
708 {
709   int regno = -1;
710   if (GET_CODE (x) == REG || GET_CODE(x) == SUBREG)
711     regno = true_regnum (x);
712
713   if (!GR_REG_CLASS_P (class))
714     return GP_REG_P (regno) ? NO_REGS : G32_REGS;
715   return NO_REGS;
716 }
717
718 /* Implement CONST_OK_FOR_LETTER_P macro.  */
719 /* imm constraints
720    I        imm16 << 16
721    J        uimm5
722    K        uimm16
723    L        simm16
724    M        uimm14
725    N        simm14
726    O        simm14
727    P        simm5
728    Q        uimm32  */
729 int
730 score3_const_ok_for_letter_p (HOST_WIDE_INT value, char c)
731 {
732   switch (c)
733     {
734     case 'I': return ((value & 0xffff) == 0);
735     case 'J': return IMM_IN_RANGE (value, 5, 0);
736     case 'K': return IMM_IN_RANGE (value, 16, 0);
737     case 'L': return IMM_IN_RANGE (value, 16, 1);
738     case 'M': return IMM_IN_RANGE (value, 14, 0);
739     case 'N': return IMM_IN_RANGE (value, 14, 1);
740     case 'O': return IMM_IN_RANGE (value, 5, 1);
741     case 'P': return IMM_IN_RANGE (value, 6, 1);
742     case 'Q': return score_extra_constraint (GEN_INT(value), c);
743     default : return 0;
744     }
745 }
746
747 /* Implement EXTRA_CONSTRAINT macro.  */
748 /*
749    Q        uimm32
750    Z        symbol_ref  */
751 int
752 score3_extra_constraint (rtx op, char c)
753 {
754   switch (c)
755     {
756     case 'Q': return IMM_IN_RANGE (INTVAL(op), 32, 0);
757     case 'Z':
758       return GET_CODE (op) == SYMBOL_REF;
759     default:
760       gcc_unreachable ();
761     }
762 }
763
764 /* Return truth value on whether or not a given hard register
765    can support a given mode.  */
766 int
767 score3_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
768 {
769   int size = GET_MODE_SIZE (mode);
770   enum mode_class class = GET_MODE_CLASS (mode);
771
772   if (class == MODE_CC)
773     return regno == CC_REGNUM;
774   else if (regno == FRAME_POINTER_REGNUM
775            || regno == ARG_POINTER_REGNUM)
776     return class == MODE_INT;
777   else if (GP_REG_P (regno))
778     return !(regno & 1) || (size <= UNITS_PER_WORD);
779   else if (CE_REG_P (regno))
780     return (class == MODE_INT
781             && ((size <= UNITS_PER_WORD)
782                 || (regno == CE_REG_FIRST && size == 2 * UNITS_PER_WORD)));
783   else
784     return (class == MODE_INT) && (size <= UNITS_PER_WORD);
785 }
786
787 /* Implement INITIAL_ELIMINATION_OFFSET.  FROM is either the frame
788    pointer or argument pointer.  TO is either the stack pointer or
789    hard frame pointer.  */
790 HOST_WIDE_INT
791 score3_initial_elimination_offset (int from,
792                                    int to ATTRIBUTE_UNUSED)
793 {
794   struct score3_frame_info *f = score3_compute_frame_size (get_frame_size ());
795   switch (from)
796     {
797     case ARG_POINTER_REGNUM:
798       return f->total_size;
799     case FRAME_POINTER_REGNUM:
800       return 0;
801     default:
802       gcc_unreachable ();
803     }
804 }
805
806 /* Implement FUNCTION_ARG_ADVANCE macro.  */
807 void
808 score3_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
809                              tree type, int named)
810 {
811   struct score3_arg_info info;
812   score3_classify_arg (cum, mode, type, named, &info);
813   cum->num_gprs = info.reg_offset + info.reg_words;
814   if (info.stack_words > 0)
815     cum->stack_words = info.stack_offset + info.stack_words;
816   cum->arg_number++;
817 }
818
819 /* Implement TARGET_ARG_PARTIAL_BYTES macro.  */
820 int
821 score3_arg_partial_bytes (CUMULATIVE_ARGS *cum,
822                           enum machine_mode mode, tree type, bool named)
823 {
824   struct score3_arg_info info;
825   score3_classify_arg (cum, mode, type, named, &info);
826   return info.stack_words > 0 ? info.reg_words * UNITS_PER_WORD : 0;
827 }
828
829 /* Implement FUNCTION_ARG macro.  */
830 rtx
831 score3_function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
832                      tree type, int named)
833 {
834   struct score3_arg_info info;
835
836   if (mode == VOIDmode || !named)
837     return 0;
838
839   score3_classify_arg (cum, mode, type, named, &info);
840
841   if (info.reg_offset == ARG_REG_NUM)
842     return 0;
843
844   if (!info.stack_words)
845     return gen_rtx_REG (mode, ARG_REG_FIRST + info.reg_offset);
846   else
847     {
848       rtx ret = gen_rtx_PARALLEL (mode, rtvec_alloc (info.reg_words));
849       unsigned int i, part_offset = 0;
850       for (i = 0; i < info.reg_words; i++)
851         {
852           rtx reg;
853           reg = gen_rtx_REG (SImode, ARG_REG_FIRST + info.reg_offset + i);
854           XVECEXP (ret, 0, i) = gen_rtx_EXPR_LIST (SImode, reg,
855                                                    GEN_INT (part_offset));
856           part_offset += UNITS_PER_WORD;
857         }
858       return ret;
859     }
860 }
861
862 /* Implement FUNCTION_VALUE and LIBCALL_VALUE.  For normal calls,
863    VALTYPE is the return type and MODE is VOIDmode.  For libcalls,
864    VALTYPE is null and MODE is the mode of the return value.  */
865 rtx
866 score3_function_value (tree valtype, tree func ATTRIBUTE_UNUSED,
867                        enum machine_mode mode)
868 {
869   if (valtype)
870     {
871       int unsignedp;
872       mode = TYPE_MODE (valtype);
873       unsignedp = TYPE_UNSIGNED (valtype);
874       mode = promote_mode (valtype, mode, &unsignedp, 1);
875     }
876   return gen_rtx_REG (mode, RT_REGNUM);
877 }
878
879 /* Implement INITIALIZE_TRAMPOLINE macro.  */
880 void
881 score3_initialize_trampoline (rtx ADDR, rtx FUNC, rtx CHAIN)
882 {
883 #define FFCACHE          "_flush_cache"
884 #define CODE_SIZE        (TRAMPOLINE_INSNS * UNITS_PER_WORD)
885
886   rtx pfunc, pchain;
887
888   pfunc = plus_constant (ADDR, CODE_SIZE);
889   pchain = plus_constant (ADDR, CODE_SIZE + GET_MODE_SIZE (SImode));
890
891   emit_move_insn (gen_rtx_MEM (SImode, pfunc), FUNC);
892   emit_move_insn (gen_rtx_MEM (SImode, pchain), CHAIN);
893   emit_library_call (gen_rtx_SYMBOL_REF (Pmode, FFCACHE),
894                      0, VOIDmode, 2,
895                      ADDR, Pmode,
896                      GEN_INT (TRAMPOLINE_SIZE), SImode);
897 #undef FFCACHE
898 #undef CODE_SIZE
899 }
900
901 /* This function is used to implement REG_MODE_OK_FOR_BASE_P macro.  */
902 int
903 score3_regno_mode_ok_for_base_p (int regno, int strict)
904 {
905   if (regno >= FIRST_PSEUDO_REGISTER)
906     {
907       if (!strict)
908         return 1;
909       regno = reg_renumber[regno];
910     }
911   if (regno == ARG_POINTER_REGNUM
912       || regno == FRAME_POINTER_REGNUM)
913     return 1;
914   return GP_REG_P (regno);
915 }
916
917 /* Implement GO_IF_LEGITIMATE_ADDRESS macro.  */
918 int
919 score3_address_p (enum machine_mode mode, rtx x, int strict)
920 {
921   struct score3_address_info addr;
922
923   return score3_classify_address (&addr, mode, x, strict);
924 }
925
926 /* Return a number assessing the cost of moving a register in class
927    FROM to class TO. */
928 int
929 score3_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
930                            enum reg_class from, enum reg_class to)
931 {
932   if (GR_REG_CLASS_P (from))
933     {
934       if (GR_REG_CLASS_P (to))
935         return 2;
936       else if (SP_REG_CLASS_P (to))
937         return 4;
938       else if (CP_REG_CLASS_P (to))
939         return 5;
940       else if (CE_REG_CLASS_P (to))
941         return 6;
942     }
943   if (GR_REG_CLASS_P (to))
944     {
945       if (GR_REG_CLASS_P (from))
946         return 2;
947       else if (SP_REG_CLASS_P (from))
948         return 4;
949       else if (CP_REG_CLASS_P (from))
950         return 5;
951       else if (CE_REG_CLASS_P (from))
952         return 6;
953     }
954   return 12;
955 }
956
957 /* Return the number of instructions needed to load a symbol of the
958    given type into a register.  */
959 static int
960 score3_symbol_insns (enum score_symbol_type type)
961 {
962   switch (type)
963     {
964     case SYMBOL_GENERAL:
965       return 2;
966
967     case SYMBOL_SMALL_DATA:
968       return 1;
969     }
970
971   gcc_unreachable ();
972 }
973
974 /* Return the number of instructions needed to load or store a value
975    of mode MODE at X.  Return 0 if X isn't valid for MODE.  */
976 static int
977 score3_address_insns (rtx x, enum machine_mode mode)
978 {
979   struct score3_address_info addr;
980   int factor;
981
982   if (mode == BLKmode)
983     factor = 1;
984   else
985     factor = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
986
987   if (score3_classify_address (&addr, mode, x, false))
988     switch (addr.type)
989       {
990       case SCORE3_ADD_REG:
991       case SCORE3_ADD_CONST_INT:
992         return factor;
993
994       case SCORE3_ADD_SYMBOLIC:
995         return factor * score3_symbol_insns (addr.symbol_type);
996       }
997   return 0;
998 }
999
1000 /* Implement TARGET_RTX_COSTS macro.  */
1001 bool
1002 score3_rtx_costs (rtx x, int code, int outer_code, int *total)
1003 {
1004   enum machine_mode mode = GET_MODE (x);
1005
1006   switch (code)
1007     {
1008     case CONST_INT:
1009       if (outer_code == SET)
1010         {
1011           if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
1012               || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L'))
1013             *total = COSTS_N_INSNS (1);
1014           else
1015             *total = COSTS_N_INSNS (2);
1016         }
1017       else if (outer_code == PLUS || outer_code == MINUS)
1018         {
1019           if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'N'))
1020             *total = 0;
1021           else if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
1022                    || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L'))
1023             *total = 1;
1024           else
1025             *total = COSTS_N_INSNS (2);
1026         }
1027       else if (outer_code == AND || outer_code == IOR)
1028         {
1029           if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'M'))
1030             *total = 0;
1031           else if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
1032                    || CONST_OK_FOR_LETTER_P (INTVAL (x), 'K'))
1033             *total = 1;
1034           else
1035             *total = COSTS_N_INSNS (2);
1036         }
1037       else
1038         {
1039           *total = 0;
1040         }
1041       return true;
1042
1043     case CONST:
1044     case SYMBOL_REF:
1045     case LABEL_REF:
1046     case CONST_DOUBLE:
1047       *total = COSTS_N_INSNS (2);
1048       return true;
1049
1050     case MEM:
1051       {
1052         /* If the address is legitimate, return the number of
1053            instructions it needs, otherwise use the default handling.  */
1054         int n = score3_address_insns (XEXP (x, 0), GET_MODE (x));
1055         if (n > 0)
1056           {
1057             *total = COSTS_N_INSNS (n + 1);
1058             return true;
1059           }
1060         return false;
1061       }
1062
1063     case FFS:
1064       *total = COSTS_N_INSNS (6);
1065       return true;
1066
1067     case NOT:
1068       *total = COSTS_N_INSNS (1);
1069       return true;
1070
1071     case AND:
1072     case IOR:
1073     case XOR:
1074       if (mode == DImode)
1075         {
1076           *total = COSTS_N_INSNS (2);
1077           return true;
1078         }
1079       return false;
1080
1081     case ASHIFT:
1082     case ASHIFTRT:
1083     case LSHIFTRT:
1084       if (mode == DImode)
1085         {
1086           *total = COSTS_N_INSNS ((GET_CODE (XEXP (x, 1)) == CONST_INT)
1087                                   ? 4 : 12);
1088           return true;
1089         }
1090       return false;
1091
1092     case ABS:
1093       *total = COSTS_N_INSNS (4);
1094       return true;
1095
1096     case PLUS:
1097     case MINUS:
1098       if (mode == DImode)
1099         {
1100           *total = COSTS_N_INSNS (4);
1101           return true;
1102         }
1103       *total = COSTS_N_INSNS (1);
1104       return true;
1105
1106     case NEG:
1107       if (mode == DImode)
1108         {
1109           *total = COSTS_N_INSNS (4);
1110           return true;
1111         }
1112       return false;
1113
1114     case MULT:
1115       *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (12);
1116       return true;
1117
1118     case DIV:
1119     case MOD:
1120     case UDIV:
1121     case UMOD:
1122       *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (33);
1123       return true;
1124
1125     case SIGN_EXTEND:
1126     case ZERO_EXTEND:
1127       switch (GET_MODE (XEXP (x, 0)))
1128         {
1129         case QImode:
1130         case HImode:
1131           if (GET_CODE (XEXP (x, 0)) == MEM)
1132             {
1133               *total = COSTS_N_INSNS (2);
1134
1135               if (!TARGET_LITTLE_ENDIAN &&
1136                   side_effects_p (XEXP (XEXP (x, 0), 0)))
1137                 *total = 100;
1138             }
1139           else
1140             *total = COSTS_N_INSNS (1);
1141           break;
1142
1143         default:
1144           *total = COSTS_N_INSNS (1);
1145           break;
1146         }
1147       return true;
1148
1149     default:
1150       return false;
1151     }
1152 }
1153
1154 /* Implement TARGET_ADDRESS_COST macro.  */
1155 int
1156 score3_address_cost (rtx addr)
1157 {
1158   return score3_address_insns (addr, SImode);
1159 }
1160
1161 /* Implement ASM_OUTPUT_EXTERNAL macro.  */
1162 int
1163 score3_output_external (FILE *file ATTRIBUTE_UNUSED,
1164                         tree decl, const char *name)
1165 {
1166   register struct extern_list *p;
1167
1168   if (score3_in_small_data_p (decl))
1169     {
1170       p = (struct extern_list *) ggc_alloc (sizeof (struct extern_list));
1171       p->next = extern_head;
1172       p->name = name;
1173       p->size = int_size_in_bytes (TREE_TYPE (decl));
1174       extern_head = p;
1175     }
1176   return 0;
1177 }
1178
1179 /* Implement RETURN_ADDR_RTX.  Note, we do not support moving
1180    back to a previous frame.  */
1181 rtx
1182 score3_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
1183 {
1184   if (count != 0)
1185     return const0_rtx;
1186   return get_hard_reg_initial_val (Pmode, RA_REGNUM);
1187 }
1188
1189 /* Implement PRINT_OPERAND macro.  */
1190 /* Score-specific operand codes:
1191    '['        print .set nor1 directive
1192    ']'        print .set r1 directive
1193    'U'        print hi part of a CONST_INT rtx
1194    'E'        print log2(v)
1195    'F'        print log2(~v)
1196    'D'        print SFmode const double
1197    'S'        selectively print "!" if operand is 15bit instruction accessible
1198    'V'        print "v!" if operand is 15bit instruction accessible, or "lfh!"
1199    'L'        low  part of DImode reg operand
1200    'H'        high part of DImode reg operand
1201    'C'        print part of opcode for a branch condition.  */
1202 void
1203 score3_print_operand (FILE *file, rtx op, int c)
1204 {
1205   enum rtx_code code = -1;
1206   if (!PRINT_OPERAND_PUNCT_VALID_P (c))
1207     code = GET_CODE (op);
1208
1209   if (c == '[')
1210     {
1211       fprintf (file, ".set r1\n");
1212     }
1213   else if (c == ']')
1214     {
1215       fprintf (file, "\n\t.set nor1");
1216     }
1217   else if (c == 'U')
1218     {
1219       gcc_assert (code == CONST_INT);
1220       fprintf (file, HOST_WIDE_INT_PRINT_HEX,
1221                (INTVAL (op) >> 16) & 0xffff);
1222     }
1223   else if (c == 'D')
1224     {
1225       if (GET_CODE (op) == CONST_DOUBLE)
1226         {
1227           rtx temp = gen_lowpart (SImode, op);
1228           gcc_assert (GET_MODE (op) == SFmode);
1229           fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (temp) & 0xffffffff);
1230         }
1231       else
1232         output_addr_const (file, op);
1233     }
1234   else if (c == 'S')
1235     {
1236       gcc_assert (code == REG);
1237       if (G16_REG_P (REGNO (op)))
1238         fprintf (file, "!");
1239     }
1240   else if (c == 'V')
1241     {
1242       gcc_assert (code == REG);
1243       fprintf (file, G16_REG_P (REGNO (op)) ? "v!" : "lfh!");
1244     }
1245   else if (c == 'C')
1246     {
1247       enum machine_mode mode = GET_MODE (XEXP (op, 0));
1248
1249       switch (code)
1250         {
1251         case EQ: fputs ("eq!", file); break;
1252         case NE: fputs ("ne!", file); break;
1253         case GT: fputs ("gt!", file); break;
1254         case GE: fputs (mode != CCmode ? "pl" : "ge", file); break;
1255         case LT: fputs (mode != CCmode ? "mi" : "lt", file); break;
1256         case LE: fputs ("le!", file); break;
1257         case GTU: fputs ("gtu!", file); break;
1258         case GEU: fputs ("cs", file); break;
1259         case LTU: fputs ("cc", file); break;
1260         case LEU: fputs ("leu!", file); break;
1261         default:
1262           output_operand_lossage ("invalid operand for code: '%c'", code);
1263         }
1264     }
1265   else if (c == 'G')  /* Seperate from b<cond>, use for mv<cond>.  */
1266     {
1267       enum machine_mode mode = GET_MODE (XEXP (op, 0));
1268
1269       switch (code)
1270         {
1271         case EQ: fputs ("eq", file); break;
1272         case NE: fputs ("ne", file); break;
1273         case GT: fputs ("gt", file); break;
1274         case GE: fputs (mode != CCmode ? "pl" : "ge", file); break;
1275         case LT: fputs (mode != CCmode ? "mi" : "lt", file); break;
1276         case LE: fputs ("le", file); break;
1277         case GTU: fputs ("gtu", file); break;
1278         case GEU: fputs ("cs", file); break;
1279         case LTU: fputs ("cc", file); break;
1280         case LEU: fputs ("leu", file); break;
1281         default:
1282           output_operand_lossage ("invalid operand for code: '%c'", code);
1283         }
1284     }
1285   else if (c == 'E')
1286     {
1287       unsigned HOST_WIDE_INT i;
1288       unsigned HOST_WIDE_INT pow2mask = 1;
1289       unsigned HOST_WIDE_INT val;
1290
1291       val = INTVAL (op);
1292       for (i = 0; i < 32; i++)
1293         {
1294           if (val == pow2mask)
1295             break;
1296           pow2mask <<= 1;
1297         }
1298       gcc_assert (i < 32);
1299       fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
1300     }
1301   else if (c == 'F')
1302     {
1303       unsigned HOST_WIDE_INT i;
1304       unsigned HOST_WIDE_INT pow2mask = 1;
1305       unsigned HOST_WIDE_INT val;
1306
1307       val = ~INTVAL (op);
1308       for (i = 0; i < 32; i++)
1309         {
1310           if (val == pow2mask)
1311             break;
1312           pow2mask <<= 1;
1313         }
1314       gcc_assert (i < 32);
1315       fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
1316     }
1317   else if (code == REG)
1318     {
1319       int regnum = REGNO (op);
1320       if ((c == 'H' && !WORDS_BIG_ENDIAN)
1321           || (c == 'L' && WORDS_BIG_ENDIAN))
1322         regnum ++;
1323       fprintf (file, "%s", reg_names[regnum]);
1324     }
1325   else
1326     {
1327       switch (code)
1328         {
1329         case MEM:
1330           score3_print_operand_address (file, op);
1331           break;
1332         default:
1333           output_addr_const (file, op);
1334         }
1335     }
1336 }
1337
1338 /* Implement PRINT_OPERAND_ADDRESS macro.  */
1339 void
1340 score3_print_operand_address (FILE *file, rtx x)
1341 {
1342   struct score3_address_info addr;
1343   enum rtx_code code = GET_CODE (x);
1344   enum machine_mode mode = GET_MODE (x);
1345
1346   if (code == MEM)
1347     x = XEXP (x, 0);
1348
1349   if (score3_classify_address (&addr, mode, x, true))
1350     {
1351       switch (addr.type)
1352         {
1353         case SCORE3_ADD_REG:
1354           {
1355             switch (addr.code)
1356               {
1357               case PRE_DEC:
1358                 fprintf (file, "[%s,-%ld]+", reg_names[REGNO (addr.reg)],
1359                          INTVAL (addr.offset));
1360                 break;
1361               case POST_DEC:
1362                 fprintf (file, "[%s]+,-%ld", reg_names[REGNO (addr.reg)],
1363                          INTVAL (addr.offset));
1364                 break;
1365               case PRE_INC:
1366                 fprintf (file, "[%s, %ld]+", reg_names[REGNO (addr.reg)],
1367                          INTVAL (addr.offset));
1368                 break;
1369               case POST_INC:
1370                 fprintf (file, "[%s]+, %ld", reg_names[REGNO (addr.reg)],
1371                          INTVAL (addr.offset));
1372                 break;
1373               default:
1374                 if (INTVAL(addr.offset) == 0)
1375                   fprintf(file, "[%s]", reg_names[REGNO (addr.reg)]);
1376                 else
1377                   fprintf(file, "[%s, %ld]", reg_names[REGNO (addr.reg)],
1378                           INTVAL(addr.offset));
1379                 break;
1380               }
1381           }
1382           return;
1383         case SCORE3_ADD_CONST_INT:
1384         case SCORE3_ADD_SYMBOLIC:
1385           output_addr_const (file, x);
1386           return;
1387         }
1388     }
1389   print_rtl (stderr, x);
1390   gcc_unreachable ();
1391 }
1392
1393 /* Implement SELECT_CC_MODE macro.  */
1394 enum machine_mode
1395 score3_select_cc_mode (enum rtx_code op, rtx x, rtx y)
1396 {
1397   if ((op == EQ || op == NE || op == LT || op == GE)
1398       && y == const0_rtx
1399       && GET_MODE (x) == SImode)
1400     {
1401       switch (GET_CODE (x))
1402         {
1403         case PLUS:
1404         case MINUS:
1405         case NEG:
1406         case AND:
1407         case IOR:
1408         case XOR:
1409         case NOT:
1410         case ASHIFT:
1411         case LSHIFTRT:
1412         case ASHIFTRT:
1413           return CC_NZmode;
1414
1415         case SIGN_EXTEND:
1416         case ZERO_EXTEND:
1417         case ROTATE:
1418         case ROTATERT:
1419           return (op == LT || op == GE) ? CC_Nmode : CCmode;
1420
1421         default:
1422           return CCmode;
1423         }
1424     }
1425
1426   if ((op == EQ || op == NE)
1427       && (GET_CODE (y) == NEG)
1428       && register_operand (XEXP (y, 0), SImode)
1429       && register_operand (x, SImode))
1430     {
1431       return CC_NZmode;
1432     }
1433
1434   return CCmode;
1435 }
1436
1437 #define EMIT_PL(_rtx)        RTX_FRAME_RELATED_P (_rtx) = 1
1438 /* return 0, no more bit set in mask.  */
1439 static int rpush_first (int mask, int sb, int *rd)
1440 {
1441   int i, cnt = 1;
1442
1443   if ((mask & (1 << sb)) == 0)
1444     return 0;
1445
1446   *rd = sb;
1447
1448   for (i = sb-1; i >= 0; i--)
1449     {
1450       if (mask & (1 << i))
1451         {
1452           cnt ++;
1453           continue;
1454         }
1455
1456       *rd = i+1;
1457       break;;
1458     }
1459
1460   return cnt;
1461 }
1462
1463 static void
1464 rpush (int rd, int cnt)
1465 {
1466   rtx mem = gen_rtx_MEM (SImode, gen_rtx_PRE_DEC (SImode, stack_pointer_rtx));
1467   rtx reg = gen_rtx_REG (SImode, rd);
1468
1469   if (!current_function_calls_eh_return)
1470     MEM_READONLY_P (mem) = 1;
1471
1472   if (cnt == 1)
1473     EMIT_PL (emit_insn (gen_pushsi_score3 (mem, reg)));
1474   else
1475     {
1476       int i;
1477       rtx insn = gen_store_multiple (gen_rtx_MEM (SImode, stack_pointer_rtx),
1478                                      gen_rtx_REG (SImode, rd),
1479                                      GEN_INT (cnt));
1480
1481       rtx pat = PATTERN (insn);
1482
1483       for (i = 0; i < XVECLEN (pat, 0); i++)
1484         if (GET_CODE (XVECEXP (pat, 0, i)) == SET)
1485           RTX_FRAME_RELATED_P (XVECEXP (pat, 0, i)) = 1;
1486
1487       EMIT_PL (emit_insn (insn));
1488     }
1489 }
1490
1491 /* Generate the prologue instructions for entry into a S+core function.  */
1492 void
1493 score3_prologue (void)
1494 {
1495   struct score3_frame_info *f = score3_compute_frame_size (get_frame_size ());
1496   HOST_WIDE_INT size;
1497   int regno;
1498
1499   size = f->total_size - f->gp_reg_size;
1500
1501   if (flag_pic)
1502     emit_insn (gen_cpload_score3 ());
1503
1504   {
1505     int cnt, rd;
1506
1507     for (regno = (int) GP_REG_LAST; regno >= (int) GP_REG_FIRST; regno--)
1508       {
1509         cnt = rpush_first (f->mask, regno, &rd);
1510         if (cnt != 0)
1511           {
1512             rpush (rd, cnt);
1513             regno = regno - cnt;
1514           }
1515       }
1516   }
1517
1518   if (size > 0)
1519     {
1520       rtx insn;
1521
1522       if (CONST_OK_FOR_LETTER_P (-size, 'L'))
1523         EMIT_PL (emit_insn (gen_add3_insn (stack_pointer_rtx,
1524                                            stack_pointer_rtx,
1525                                            GEN_INT (-size))));
1526       else
1527         {
1528           EMIT_PL (emit_move_insn (gen_rtx_REG (Pmode, SCORE3_PROLOGUE_TEMP_REGNUM),
1529                                    GEN_INT (size)));
1530           EMIT_PL (emit_insn
1531                    (gen_sub3_insn (stack_pointer_rtx,
1532                                    stack_pointer_rtx,
1533                                    gen_rtx_REG (Pmode,
1534                                                 SCORE3_PROLOGUE_TEMP_REGNUM))));
1535         }
1536       insn = get_last_insn ();
1537       REG_NOTES (insn) =
1538         alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR,
1539                          gen_rtx_SET (VOIDmode, stack_pointer_rtx,
1540                                       plus_constant (stack_pointer_rtx,
1541                                                      -size)),
1542                                       REG_NOTES (insn));
1543     }
1544
1545   if (frame_pointer_needed)
1546     EMIT_PL (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx));
1547
1548   if (flag_pic && f->cprestore_size)
1549     {
1550       if (frame_pointer_needed)
1551         emit_insn (gen_cprestore_use_fp_score3 (GEN_INT (size - f->cprestore_size)));
1552       else
1553         emit_insn (gen_cprestore_use_sp_score3 (GEN_INT (size - f->cprestore_size)));
1554     }
1555 }
1556
1557 /* return 0, no more bit set in mask.  */
1558 static int
1559 rpop_first (int mask, int sb, int *rd)
1560 {
1561   int i, cnt = 1;
1562
1563   if ((mask & (1 << sb)) == 0)
1564     return 0;
1565
1566   *rd = sb;
1567
1568   for (i = sb+1; i < 32; i++)
1569     if (mask & (1 << i))
1570       cnt++;
1571     else
1572       break;;
1573
1574   return cnt;
1575 }
1576
1577 static void
1578 rpop (int rd, int cnt)
1579 {
1580   rtx mem = gen_rtx_MEM (SImode, gen_rtx_POST_INC (SImode, stack_pointer_rtx));
1581   rtx reg = gen_rtx_REG (SImode, rd);
1582
1583   if (!current_function_calls_eh_return)
1584     MEM_READONLY_P (mem) = 1;
1585
1586   if (cnt == 1)
1587     emit_insn (gen_popsi_score3 (reg, mem));
1588   else
1589     emit_insn (gen_load_multiple (reg,
1590                                   gen_rtx_MEM (SImode, stack_pointer_rtx),
1591                                   GEN_INT (cnt)));
1592 }
1593
1594 /* Generate the epilogue instructions in a S+core function.  */
1595 void
1596 score3_epilogue (int sibcall_p)
1597 {
1598   struct score3_frame_info *f = score3_compute_frame_size (get_frame_size ());
1599   HOST_WIDE_INT size;
1600   int regno;
1601   rtx base;
1602
1603   size = f->total_size - f->gp_reg_size;
1604
1605   if (!frame_pointer_needed)
1606     base = stack_pointer_rtx;
1607   else
1608     base = hard_frame_pointer_rtx;
1609
1610   if (size)
1611     {
1612       if (CONST_OK_FOR_LETTER_P (size, 'L'))
1613         emit_insn (gen_add3_insn (base, base, GEN_INT (size)));
1614       else
1615         {
1616           emit_move_insn (gen_rtx_REG (Pmode, SCORE3_EPILOGUE_TEMP_REGNUM),
1617                           GEN_INT (size));
1618           emit_insn (gen_add3_insn (base, base,
1619                                     gen_rtx_REG (Pmode,
1620                                                  SCORE3_EPILOGUE_TEMP_REGNUM)));
1621         }
1622     }
1623
1624   if (base != stack_pointer_rtx)
1625     emit_move_insn (stack_pointer_rtx, base);
1626
1627   if (current_function_calls_eh_return)
1628     emit_insn (gen_add3_insn (stack_pointer_rtx,
1629                               stack_pointer_rtx,
1630                               EH_RETURN_STACKADJ_RTX));
1631
1632   {
1633     int cnt, rd;
1634
1635     for (regno = (int) GP_REG_FIRST; regno <= (int) GP_REG_LAST; regno++)
1636       {
1637         cnt = rpop_first (f->mask, regno, &rd);
1638         if (cnt != 0)
1639           {
1640             rpop (rd, cnt);
1641             regno = regno + cnt;
1642           }
1643       }
1644   }
1645
1646   if (!sibcall_p)
1647     emit_jump_insn (gen_return_internal_score3 (gen_rtx_REG (Pmode, RA_REGNUM)));
1648 }
1649
1650 void
1651 score3_gen_cmp (enum machine_mode mode)
1652 {
1653   emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (mode, CC_REGNUM),
1654                           gen_rtx_COMPARE (mode, cmp_op0, cmp_op1)));
1655 }
1656
1657 /* Return true if X is a symbolic constant that can be calculated in
1658    the same way as a bare symbol.  If it is, store the type of the
1659    symbol in *SYMBOL_TYPE.  */
1660 int
1661 score3_symbolic_constant_p (rtx x, enum score_symbol_type *symbol_type)
1662 {
1663   HOST_WIDE_INT offset;
1664
1665   score3_split_const (x, &x, &offset);
1666   if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF)
1667     *symbol_type = score3_classify_symbol (x);
1668   else
1669     return 0;
1670
1671   if (offset == 0)
1672     return 1;
1673
1674   /* if offset > 15bit, must reload  */
1675   if (!IMM_IN_RANGE (offset, 15, 1))
1676     return 0;
1677
1678   switch (*symbol_type)
1679     {
1680     case SYMBOL_GENERAL:
1681       return 1;
1682     case SYMBOL_SMALL_DATA:
1683       return score3_offset_within_object_p (x, offset);
1684     }
1685   gcc_unreachable ();
1686 }
1687
1688 void
1689 score3_movsicc (rtx *ops)
1690 {
1691   enum machine_mode mode;
1692
1693   mode = score3_select_cc_mode (GET_CODE (ops[1]), ops[2], ops[3]);
1694   emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (mode, CC_REGNUM),
1695                           gen_rtx_COMPARE (mode, cmp_op0, cmp_op1)));
1696 }
1697
1698 /* Call and sibcall pattern all need call this function.  */
1699 void
1700 score3_call (rtx *ops, bool sib)
1701 {
1702   rtx addr = XEXP (ops[0], 0);
1703   if (!call_insn_operand (addr, VOIDmode))
1704     {
1705       rtx oaddr = addr;
1706       addr = gen_reg_rtx (Pmode);
1707       gen_move_insn (addr, oaddr);
1708     }
1709
1710   if (sib)
1711     emit_call_insn (gen_sibcall_internal_score3 (addr, ops[1]));
1712   else
1713     emit_call_insn (gen_call_internal_score3 (addr, ops[1]));
1714 }
1715
1716 /* Call value and sibcall value pattern all need call this function.  */
1717 void
1718 score3_call_value (rtx *ops, bool sib)
1719 {
1720   rtx result = ops[0];
1721   rtx addr = XEXP (ops[1], 0);
1722   rtx arg = ops[2];
1723
1724   if (!call_insn_operand (addr, VOIDmode))
1725     {
1726       rtx oaddr = addr;
1727       addr = gen_reg_rtx (Pmode);
1728       gen_move_insn (addr, oaddr);
1729     }
1730
1731   if (sib)
1732     emit_call_insn (gen_sibcall_value_internal_score3 (result, addr, arg));
1733   else
1734     emit_call_insn (gen_call_value_internal_score3 (result, addr, arg));
1735 }
1736
1737 /* Machine Split  */
1738 void
1739 score3_movdi (rtx *ops)
1740 {
1741   rtx dst = ops[0];
1742   rtx src = ops[1];
1743   rtx dst0 = score3_subw (dst, 0);
1744   rtx dst1 = score3_subw (dst, 1);
1745   rtx src0 = score3_subw (src, 0);
1746   rtx src1 = score3_subw (src, 1);
1747
1748   if (GET_CODE (dst0) == REG && reg_overlap_mentioned_p (dst0, src))
1749     {
1750       emit_move_insn (dst1, src1);
1751       emit_move_insn (dst0, src0);
1752     }
1753   else
1754     {
1755       emit_move_insn (dst0, src0);
1756       emit_move_insn (dst1, src1);
1757     }
1758 }
1759
1760 void
1761 score3_zero_extract_andi (rtx *ops)
1762 {
1763   if (INTVAL (ops[1]) == 1 && const_uimm5 (ops[2], SImode))
1764     emit_insn (gen_zero_extract_bittst_score3 (ops[0], ops[2]));
1765   else
1766     {
1767       unsigned HOST_WIDE_INT mask;
1768       mask = (0xffffffffU & ((1U << INTVAL (ops[1])) - 1U));
1769       mask = mask << INTVAL (ops[2]);
1770       emit_insn (gen_andsi3_cmp_score3 (ops[3], ops[0],
1771                                         gen_int_mode (mask, SImode)));
1772     }
1773 }
1774
1775 const char *
1776 score3_rpush (rtx *ops)
1777 {
1778   snprintf (score3_ins, INS_BUF_SZ, "rpush!\t%%1, %d", XVECLEN (ops[0], 0));
1779   return score3_ins;
1780 }
1781
1782 const char *
1783 score3_rpop (rtx *ops)
1784 {
1785   snprintf (score3_ins, INS_BUF_SZ, "rpop!\t%%1, %d", XVECLEN (ops[0], 0));
1786   return score3_ins;
1787 }
1788
1789 /* Output asm code for ld/sw insn.  */
1790 static int
1791 score3_pr_addr_post (rtx *ops, int idata, int iaddr, char *ip,
1792                      enum score_mem_unit unit ATTRIBUTE_UNUSED)
1793 {
1794   struct score3_address_info ai;
1795
1796   gcc_assert (GET_CODE (ops[idata]) == REG);
1797   gcc_assert (score3_classify_address (&ai, SImode, XEXP (ops[iaddr], 0), true));
1798
1799   if (ai.type == SCORE3_ADD_REG
1800       && ai.code == REG
1801       && GET_CODE (ai.offset) == CONST_INT
1802       && G16_REG_P (REGNO (ops[idata]))
1803       && G8_REG_P (REGNO (ai.reg))
1804       && ((INTVAL (ai.offset) & 3) == 0)
1805       && (IMM_IN_RANGE (INTVAL (ai.offset), 7, 0)))
1806     {
1807       ops[iaddr] = ai.reg;
1808       return snprintf (ip, INS_BUF_SZ, "!\t%%%d, [%%%d, "
1809                        HOST_WIDE_INT_PRINT_DEC "]",
1810                        idata, iaddr, INTVAL (ai.offset));
1811     }
1812
1813   if (ai.type == SCORE3_ADD_SYMBOLIC)
1814     return snprintf (ip, INS_BUF_SZ, "48\t%%%d, %%a%d", idata, iaddr);
1815
1816   return snprintf (ip, INS_BUF_SZ, "\t%%%d, %%a%d", idata, iaddr);
1817 }
1818
1819 /* Output asm insn for load.  */
1820 const char *
1821 score3_linsn (rtx *ops, enum score_mem_unit unit, bool sign)
1822 {
1823   const char *pre_ins[] =
1824     {"lbu", "lhu", "lw", "??", "lb", "lh", "lw", "??"};
1825   char *ip;
1826
1827   strcpy (score3_ins, pre_ins[(sign ? 4 : 0) + unit]);
1828   ip = score3_ins + strlen (score3_ins);
1829
1830   if (unit == SCORE_WORD)
1831     score3_pr_addr_post (ops, 0, 1, ip, unit);
1832   else
1833     snprintf (ip, INS_BUF_SZ, "\t%%0, %%a1");
1834
1835   return score3_ins;
1836 }
1837
1838 /* Output asm insn for store.  */
1839 const char *
1840 score3_sinsn (rtx *ops, enum score_mem_unit unit)
1841 {
1842   const char *pre_ins[] = {"sb", "sh", "sw"};
1843   char *ip;
1844
1845   strcpy (score3_ins, pre_ins[unit]);
1846   ip = score3_ins + strlen (score3_ins);
1847
1848   if (unit == SCORE_WORD)
1849     score3_pr_addr_post (ops, 1, 0, ip, unit);
1850   else
1851     snprintf (ip, INS_BUF_SZ, "\t%%1, %%a0");
1852
1853   return score3_ins;
1854 }
1855
1856 /* Output asm insn for load immediate.  */
1857 const char *
1858 score3_limm (rtx *ops)
1859 {
1860   HOST_WIDE_INT v;
1861
1862   gcc_assert (GET_CODE (ops[0]) == REG);
1863   gcc_assert (GET_CODE (ops[1]) == CONST_INT);
1864
1865   v = INTVAL (ops[1]);
1866   if (G16_REG_P (REGNO (ops[0])) && IMM_IN_RANGE (v, 5, 0))
1867     return "ldiu!\t%0, %c1";
1868   else if (IMM_IN_RANGE (v, 16, 1))
1869     return "ldi\t%0, %c1";
1870   else if ((v & 0xffff) == 0)
1871     return "ldis\t%0, %U1";
1872   else
1873     return "li\t%0, %c1";
1874 }
1875
1876 /* Output asm insn for move.  */
1877 const char *
1878 score3_move (rtx *ops)
1879 {
1880   gcc_assert (GET_CODE (ops[0]) == REG);
1881   gcc_assert (GET_CODE (ops[1]) == REG);
1882
1883   return "mv!\t%0, %1";
1884 }
1885
1886 /* Generate add insn.  */
1887 const char *
1888 score3_select_add_imm (rtx *ops, bool set_cc)
1889 {
1890   HOST_WIDE_INT v = INTVAL (ops[2]);
1891
1892   gcc_assert (GET_CODE (ops[2]) == CONST_INT);
1893   gcc_assert (REGNO (ops[0]) == REGNO (ops[1]));
1894
1895   if (set_cc)
1896     return "addi.c\t%0, %c2";
1897   else
1898     if (IMM_IN_RANGE (v, 6, 1) && G16_REG_P (REGNO (ops[0])))
1899       return "addi!\t%0, %c2";
1900     else
1901       return "addi\t%0, %c2";
1902 }
1903
1904 /* Output arith insn.  */
1905 const char *
1906 score3_select (rtx *ops, const char *inst_pre, bool commu ATTRIBUTE_UNUSED,
1907                const char *letter, bool set_cc)
1908 {
1909   gcc_assert (GET_CODE (ops[0]) == REG);
1910   gcc_assert (GET_CODE (ops[1]) == REG);
1911
1912   if (set_cc)
1913     snprintf (score3_ins, INS_BUF_SZ, "%s.c\t%%0, %%1, %%%s2", inst_pre, letter);
1914   else
1915     snprintf (score3_ins, INS_BUF_SZ, "%s\t%%0, %%1, %%%s2", inst_pre, letter);
1916   return score3_ins;
1917 }
1918
1919 /* Output a Score3 casesi instruction.  */
1920 const char *
1921 score3_output_casesi (rtx *operands)
1922 {
1923   rtx diff_vec = PATTERN (next_real_insn (operands[2]));
1924   gcc_assert (GET_CODE (diff_vec) == ADDR_DIFF_VEC);
1925
1926   output_asm_insn ("cmpi.c\t%0, %1", operands);
1927   output_asm_insn ("bgtu\t%3", operands);
1928   switch (GET_MODE(diff_vec))
1929     {
1930     case QImode:
1931       output_asm_insn ("ldi48\t%4, %2", operands);
1932       output_asm_insn ("ltbb\t%4, [%4, %0]\n%2_tbb:", operands);
1933       return "brr!\t%4";
1934     case HImode:
1935       output_asm_insn ("ldi48\t%4, %2", operands);
1936       output_asm_insn ("ltbh\t%4, [%4, %0]\n%2_tbb:", operands);
1937       return "brr!\t%4";
1938     case SImode:
1939       output_asm_insn ("ldi48\t%4, %2", operands);
1940       output_asm_insn ("ltbw\t%4, [%4, %0]", operands);
1941       return "br!\t%4";
1942     default:
1943       gcc_unreachable ();
1944     }
1945 }