OSDN Git Service

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