OSDN Git Service

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