OSDN Git Service

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