OSDN Git Service

PR target/42113
[pf3gnuchains/gcc-fork.git] / gcc / config / score / score7.c
1 /* score7.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 "score7.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 score7_sdata_max;
60 static char score7_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 score7_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 score7_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 score7_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)) <= SCORE7_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 score7_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 score7_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 score7_frame_info *
166 score7_cached_frame (void)
167 {
168   static struct score7_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 score7_frame_info *
175 score7_compute_frame_size (HOST_WIDE_INT size)
176 {
177   unsigned int regno;
178   struct score7_frame_info *f = score7_cached_frame ();
179
180   memset (f, 0, sizeof (struct score7_frame_info));
181   f->gp_reg_size = 0;
182   f->mask = 0;
183   f->var_size = SCORE7_STACK_ALIGN (size);
184   f->args_size = crtl->outgoing_args_size;
185   f->cprestore_size = flag_pic ? UNITS_PER_WORD : 0;
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 (score7_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 score7_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           && score7_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 score7_classify_address (struct score7_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 = SCORE7_ADD_REG;
257       info->reg = x;
258       info->offset = const0_rtx;
259       return score7_valid_base_register_p (info->reg, strict);
260     case PLUS:
261       info->type = SCORE7_ADD_REG;
262       info->reg = XEXP (x, 0);
263       info->offset = XEXP (x, 1);
264       return (score7_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 = SCORE7_ADD_REG;
274       info->reg = XEXP (x, 0);
275       info->offset = GEN_INT (GET_MODE_SIZE (mode));
276       return score7_valid_base_register_p (info->reg, strict);
277     case CONST_INT:
278       info->type = SCORE7_ADD_CONST_INT;
279       return IMM_IN_RANGE (INTVAL (x), 15, 1);
280     case CONST:
281     case LABEL_REF:
282     case SYMBOL_REF:
283       info->type = SCORE7_ADD_SYMBOLIC;
284       return (score7_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 score7_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 score7_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 score7_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 = score7_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_score7 (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 score7_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 score7_split_symbol (rtx temp, rtx addr)
406 {
407   rtx high = score7_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 score7_legitimize_address (rtx x)
417 {
418   enum score_symbol_type symbol_type;
419
420   if (score7_symbolic_constant_p (x, &symbol_type)
421       && symbol_type == SYMBOL_GENERAL)
422     return score7_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 (!score7_valid_base_register_p (reg, 0))
429         reg = copy_to_mode_reg (Pmode, reg);
430       return score7_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 score7_classify_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
442                      tree type, int named, struct score7_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 score7_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
488 {
489   const char *fnname;
490   struct score7_frame_info *f = score7_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 score7_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 score7_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 score7_symbolic_expression_p (XEXP (x, 0));
551
552   if (UNARY_P (x))
553     return score7_symbolic_expression_p (XEXP (x, 0));
554
555   if (ARITHMETIC_P (x))
556     return (score7_symbolic_expression_p (XEXP (x, 0))
557             || score7_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 score7_select_rtx_section (enum machine_mode mode, rtx x,
566                            unsigned HOST_WIDE_INT align)
567 {
568   if (GET_MODE_SIZE (mode) <= SCORE7_SDATA_MAX)
569     return get_named_section (0, ".sdata", 0);
570   else if (flag_pic && score7_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 score7_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 <= SCORE7_SDATA_MAX);
598 }
599
600 /* Implement TARGET_ASM_FILE_START.  */
601 void
602 score7_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 score7_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 score7_override_options (void)
640 {
641   flag_pic = false;
642   if (!flag_pic)
643     score7_sdata_max = g_switch_set ? g_switch_value : SCORE7_DEFAULT_SDATA_MAX;
644   else
645     {
646       score7_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 score7_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 score7_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 score7_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 int
721 score7_const_ok_for_letter_p (HOST_WIDE_INT value, char c)
722 {
723   switch (c)
724     {
725     case 'I': return ((value & 0xffff) == 0);
726     case 'J': return IMM_IN_RANGE (value, 5, 0);
727     case 'K': return IMM_IN_RANGE (value, 16, 0);
728     case 'L': return IMM_IN_RANGE (value, 16, 1);
729     case 'M': return IMM_IN_RANGE (value, 14, 0);
730     case 'N': return IMM_IN_RANGE (value, 14, 1);
731     default : return 0;
732     }
733 }
734
735 /* Implement EXTRA_CONSTRAINT macro.  */
736 /* Z        symbol_ref  */
737 int
738 score7_extra_constraint (rtx op, char c)
739 {
740   switch (c)
741     {
742     case 'Z':
743       return GET_CODE (op) == SYMBOL_REF;
744     default:
745       gcc_unreachable ();
746     }
747 }
748
749 /* Return truth value on whether or not a given hard register
750    can support a given mode.  */
751 int
752 score7_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
753 {
754   int size = GET_MODE_SIZE (mode);
755   enum mode_class mclass = GET_MODE_CLASS (mode);
756
757   if (mclass == MODE_CC)
758     return regno == CC_REGNUM;
759   else if (regno == FRAME_POINTER_REGNUM
760            || regno == ARG_POINTER_REGNUM)
761     return mclass == MODE_INT;
762   else if (GP_REG_P (regno))
763     /* ((regno <= (GP_REG_LAST- HARD_REGNO_NREGS (dummy, mode)) + 1)  */
764     return !(regno & 1) || (size <= UNITS_PER_WORD);
765   else if (CE_REG_P (regno))
766     return (mclass == MODE_INT
767             && ((size <= UNITS_PER_WORD)
768                 || (regno == CE_REG_FIRST && size == 2 * UNITS_PER_WORD)));
769   else
770     return (mclass == MODE_INT) && (size <= UNITS_PER_WORD);
771 }
772
773 /* Implement INITIAL_ELIMINATION_OFFSET.  FROM is either the frame
774    pointer or argument pointer.  TO is either the stack pointer or
775    hard frame pointer.  */
776 HOST_WIDE_INT
777 score7_initial_elimination_offset (int from,
778                                    int to ATTRIBUTE_UNUSED)
779 {
780   struct score7_frame_info *f = score7_compute_frame_size (get_frame_size ());
781   switch (from)
782     {
783     case ARG_POINTER_REGNUM:
784       return f->total_size;
785     case FRAME_POINTER_REGNUM:
786       return 0;
787     default:
788       gcc_unreachable ();
789     }
790 }
791
792 /* Implement FUNCTION_ARG_ADVANCE macro.  */
793 void
794 score7_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
795                              tree type, int named)
796 {
797   struct score7_arg_info info;
798   score7_classify_arg (cum, mode, type, named, &info);
799   cum->num_gprs = info.reg_offset + info.reg_words;
800   if (info.stack_words > 0)
801     cum->stack_words = info.stack_offset + info.stack_words;
802   cum->arg_number++;
803 }
804
805 /* Implement TARGET_ARG_PARTIAL_BYTES macro.  */
806 int
807 score7_arg_partial_bytes (CUMULATIVE_ARGS *cum,
808                           enum machine_mode mode, tree type, bool named)
809 {
810   struct score7_arg_info info;
811   score7_classify_arg (cum, mode, type, named, &info);
812   return info.stack_words > 0 ? info.reg_words * UNITS_PER_WORD : 0;
813 }
814
815 /* Implement FUNCTION_ARG macro.  */
816 rtx
817 score7_function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
818                      tree type, int named)
819 {
820   struct score7_arg_info info;
821
822   if (mode == VOIDmode || !named)
823     return 0;
824
825   score7_classify_arg (cum, mode, type, named, &info);
826
827   if (info.reg_offset == ARG_REG_NUM)
828     return 0;
829
830   if (!info.stack_words)
831     return gen_rtx_REG (mode, ARG_REG_FIRST + info.reg_offset);
832   else
833     {
834       rtx ret = gen_rtx_PARALLEL (mode, rtvec_alloc (info.reg_words));
835       unsigned int i, part_offset = 0;
836       for (i = 0; i < info.reg_words; i++)
837         {
838           rtx reg;
839           reg = gen_rtx_REG (SImode, ARG_REG_FIRST + info.reg_offset + i);
840           XVECEXP (ret, 0, i) = gen_rtx_EXPR_LIST (SImode, reg,
841                                                    GEN_INT (part_offset));
842           part_offset += UNITS_PER_WORD;
843         }
844       return ret;
845     }
846 }
847
848 /* Implement FUNCTION_VALUE and LIBCALL_VALUE.  For normal calls,
849    VALTYPE is the return type and MODE is VOIDmode.  For libcalls,
850    VALTYPE is null and MODE is the mode of the return value.  */
851 rtx
852 score7_function_value (tree valtype, tree func, enum machine_mode mode)
853 {
854   if (valtype)
855     {
856       int unsignedp;
857       mode = TYPE_MODE (valtype);
858       unsignedp = TYPE_UNSIGNED (valtype);
859       mode = promote_function_mode (valtype, mode, &unsignedp, func, 1);
860     }
861   return gen_rtx_REG (mode, RT_REGNUM);
862 }
863
864 /* Implement TARGET_ASM_TRAMPOLINE_TEMPLATE.  */
865
866 void
867 score7_asm_trampoline_template (FILE *f)
868 {
869   fprintf (f, "\t.set r1\n");
870   fprintf (f, "\tmv r31, r3\n");
871   fprintf (f, "\tbl nextinsn\n");
872   fprintf (f, "nextinsn:\n");
873   fprintf (f, "\tlw r1, [r3, 6*4-8]\n");
874   fprintf (f, "\tlw r23, [r3, 6*4-4]\n");
875   fprintf (f, "\tmv r3, r31\n");
876   fprintf (f, "\tbr! r1\n");
877   fprintf (f, "\tnop!\n");
878   fprintf (f, "\t.set nor1\n");
879 }
880
881 /* Implement TARGET_TRAMPOLINE_INIT.  */
882 void
883 score7_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
884 {
885 #define FFCACHE          "_flush_cache"
886 #define CODE_SIZE        (TRAMPOLINE_INSNS * UNITS_PER_WORD)
887
888   rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
889   rtx addr = XEXP (m_tramp, 0);
890   rtx mem;
891
892   emit_block_move (m_tramp, assemble_trampoline_template (),
893                    GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
894
895   mem = adjust_address (m_tramp, SImode, CODE_SIZE);
896   emit_move_insn (mem, fnaddr);
897   mem = adjust_address (m_tramp, SImode, CODE_SIZE + GET_MODE_SIZE (SImode));
898   emit_move_insn (mem, chain_value);
899
900   emit_library_call (gen_rtx_SYMBOL_REF (Pmode, FFCACHE),
901                      0, VOIDmode, 2,
902                      addr, Pmode,
903                      GEN_INT (TRAMPOLINE_SIZE), SImode);
904 #undef FFCACHE
905 #undef CODE_SIZE
906 }
907
908 /* This function is used to implement REG_MODE_OK_FOR_BASE_P macro.  */
909 int
910 score7_regno_mode_ok_for_base_p (int regno, int strict)
911 {
912   if (regno >= FIRST_PSEUDO_REGISTER)
913     {
914       if (!strict)
915         return 1;
916       regno = reg_renumber[regno];
917     }
918   if (regno == ARG_POINTER_REGNUM
919       || regno == FRAME_POINTER_REGNUM)
920     return 1;
921   return GP_REG_P (regno);
922 }
923
924 /* Implement TARGET_LEGITIMATE_ADDRESS_P macro.  */
925 bool
926 score7_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
927 {
928   struct score7_address_info addr;
929
930   return score7_classify_address (&addr, mode, x, strict);
931 }
932
933 /* Return a number assessing the cost of moving a register in class
934    FROM to class TO. */
935 int
936 score7_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
937                            enum reg_class from, enum reg_class to)
938 {
939   if (GR_REG_CLASS_P (from))
940     {
941       if (GR_REG_CLASS_P (to))
942         return 2;
943       else if (SP_REG_CLASS_P (to))
944         return 4;
945       else if (CP_REG_CLASS_P (to))
946         return 5;
947       else if (CE_REG_CLASS_P (to))
948         return 6;
949     }
950   if (GR_REG_CLASS_P (to))
951     {
952       if (GR_REG_CLASS_P (from))
953         return 2;
954       else if (SP_REG_CLASS_P (from))
955         return 4;
956       else if (CP_REG_CLASS_P (from))
957         return 5;
958       else if (CE_REG_CLASS_P (from))
959         return 6;
960     }
961   return 12;
962 }
963
964 /* Return the number of instructions needed to load a symbol of the
965    given type into a register.  */
966 static int
967 score7_symbol_insns (enum score_symbol_type type)
968 {
969   switch (type)
970     {
971     case SYMBOL_GENERAL:
972       return 2;
973
974     case SYMBOL_SMALL_DATA:
975       return 1;
976     }
977
978   gcc_unreachable ();
979 }
980
981 /* Return the number of instructions needed to load or store a value
982    of mode MODE at X.  Return 0 if X isn't valid for MODE.  */
983 static int
984 score7_address_insns (rtx x, enum machine_mode mode)
985 {
986   struct score7_address_info addr;
987   int factor;
988
989   if (mode == BLKmode)
990     factor = 1;
991   else
992     factor = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
993
994   if (score7_classify_address (&addr, mode, x, false))
995     switch (addr.type)
996       {
997       case SCORE7_ADD_REG:
998       case SCORE7_ADD_CONST_INT:
999         return factor;
1000
1001       case SCORE7_ADD_SYMBOLIC:
1002         return factor * score7_symbol_insns (addr.symbol_type);
1003       }
1004   return 0;
1005 }
1006
1007 /* Implement TARGET_RTX_COSTS macro.  */
1008 bool
1009 score7_rtx_costs (rtx x, int code, int outer_code, int *total,
1010                   bool speed ATTRIBUTE_UNUSED)
1011 {
1012   enum machine_mode mode = GET_MODE (x);
1013
1014   switch (code)
1015     {
1016     case CONST_INT:
1017       if (outer_code == SET)
1018         {
1019           if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
1020               || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L'))
1021             *total = COSTS_N_INSNS (1);
1022           else
1023             *total = COSTS_N_INSNS (2);
1024         }
1025       else if (outer_code == PLUS || outer_code == MINUS)
1026         {
1027           if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'N'))
1028             *total = 0;
1029           else if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
1030                    || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L'))
1031             *total = 1;
1032           else
1033             *total = COSTS_N_INSNS (2);
1034         }
1035       else if (outer_code == AND || outer_code == IOR)
1036         {
1037           if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'M'))
1038             *total = 0;
1039           else if (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
1040                    || CONST_OK_FOR_LETTER_P (INTVAL (x), 'K'))
1041             *total = 1;
1042           else
1043             *total = COSTS_N_INSNS (2);
1044         }
1045       else
1046         {
1047           *total = 0;
1048         }
1049       return true;
1050
1051     case CONST:
1052     case SYMBOL_REF:
1053     case LABEL_REF:
1054     case CONST_DOUBLE:
1055       *total = COSTS_N_INSNS (2);
1056       return true;
1057
1058     case MEM:
1059       {
1060         /* If the address is legitimate, return the number of
1061            instructions it needs, otherwise use the default handling.  */
1062         int n = score7_address_insns (XEXP (x, 0), GET_MODE (x));
1063         if (n > 0)
1064           {
1065             *total = COSTS_N_INSNS (n + 1);
1066             return true;
1067           }
1068         return false;
1069       }
1070
1071     case FFS:
1072       *total = COSTS_N_INSNS (6);
1073       return true;
1074
1075     case NOT:
1076       *total = COSTS_N_INSNS (1);
1077       return true;
1078
1079     case AND:
1080     case IOR:
1081     case XOR:
1082       if (mode == DImode)
1083         {
1084           *total = COSTS_N_INSNS (2);
1085           return true;
1086         }
1087       return false;
1088
1089     case ASHIFT:
1090     case ASHIFTRT:
1091     case LSHIFTRT:
1092       if (mode == DImode)
1093         {
1094           *total = COSTS_N_INSNS ((GET_CODE (XEXP (x, 1)) == CONST_INT)
1095                                   ? 4 : 12);
1096           return true;
1097         }
1098       return false;
1099
1100     case ABS:
1101       *total = COSTS_N_INSNS (4);
1102       return true;
1103
1104     case PLUS:
1105     case MINUS:
1106       if (mode == DImode)
1107         {
1108           *total = COSTS_N_INSNS (4);
1109           return true;
1110         }
1111       *total = COSTS_N_INSNS (1);
1112       return true;
1113
1114     case NEG:
1115       if (mode == DImode)
1116         {
1117           *total = COSTS_N_INSNS (4);
1118           return true;
1119         }
1120       return false;
1121
1122     case MULT:
1123       *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (12);
1124       return true;
1125
1126     case DIV:
1127     case MOD:
1128     case UDIV:
1129     case UMOD:
1130       *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (33);
1131       return true;
1132
1133     case SIGN_EXTEND:
1134     case ZERO_EXTEND:
1135       switch (GET_MODE (XEXP (x, 0)))
1136         {
1137         case QImode:
1138         case HImode:
1139           if (GET_CODE (XEXP (x, 0)) == MEM)
1140             {
1141               *total = COSTS_N_INSNS (2);
1142
1143               if (!TARGET_LITTLE_ENDIAN &&
1144                   side_effects_p (XEXP (XEXP (x, 0), 0)))
1145                 *total = 100;
1146             }
1147           else
1148             *total = COSTS_N_INSNS (1);
1149           break;
1150
1151         default:
1152           *total = COSTS_N_INSNS (1);
1153           break;
1154         }
1155       return true;
1156
1157     default:
1158       return false;
1159     }
1160 }
1161
1162 /* Implement TARGET_ADDRESS_COST macro.  */
1163 int
1164 score7_address_cost (rtx addr)
1165 {
1166   return score7_address_insns (addr, SImode);
1167 }
1168
1169 /* Implement ASM_OUTPUT_EXTERNAL macro.  */
1170 int
1171 score7_output_external (FILE *file ATTRIBUTE_UNUSED,
1172                         tree decl, const char *name)
1173 {
1174   register struct extern_list *p;
1175
1176   if (score7_in_small_data_p (decl))
1177     {
1178       p = (struct extern_list *) ggc_alloc (sizeof (struct extern_list));
1179       p->next = extern_head;
1180       p->name = name;
1181       p->size = int_size_in_bytes (TREE_TYPE (decl));
1182       extern_head = p;
1183     }
1184   return 0;
1185 }
1186
1187 /* Implement RETURN_ADDR_RTX.  Note, we do not support moving
1188    back to a previous frame.  */
1189 rtx
1190 score7_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
1191 {
1192   if (count != 0)
1193     return const0_rtx;
1194   return get_hard_reg_initial_val (Pmode, RA_REGNUM);
1195 }
1196
1197 /* Implement PRINT_OPERAND macro.  */
1198 /* Score-specific operand codes:
1199    '['        print .set nor1 directive
1200    ']'        print .set r1 directive
1201    'U'        print hi part of a CONST_INT rtx
1202    'E'        print log2(v)
1203    'F'        print log2(~v)
1204    'D'        print SFmode const double
1205    'S'        selectively print "!" if operand is 15bit instruction accessible
1206    'V'        print "v!" if operand is 15bit instruction accessible, or "lfh!"
1207    'L'        low  part of DImode reg operand
1208    'H'        high part of DImode reg operand
1209    'C'        print part of opcode for a branch condition.  */
1210 void
1211 score7_print_operand (FILE *file, rtx op, int c)
1212 {
1213   enum rtx_code code = -1;
1214   if (!PRINT_OPERAND_PUNCT_VALID_P (c))
1215     code = GET_CODE (op);
1216
1217   if (c == '[')
1218     {
1219       fprintf (file, ".set r1\n");
1220     }
1221   else if (c == ']')
1222     {
1223       fprintf (file, "\n\t.set nor1");
1224     }
1225   else if (c == 'U')
1226     {
1227       gcc_assert (code == CONST_INT);
1228       fprintf (file, HOST_WIDE_INT_PRINT_HEX,
1229                (INTVAL (op) >> 16) & 0xffff);
1230     }
1231   else if (c == 'D')
1232     {
1233       if (GET_CODE (op) == CONST_DOUBLE)
1234         {
1235           rtx temp = gen_lowpart (SImode, op);
1236           gcc_assert (GET_MODE (op) == SFmode);
1237           fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (temp) & 0xffffffff);
1238         }
1239       else
1240         output_addr_const (file, op);
1241     }
1242   else if (c == 'S')
1243     {
1244       gcc_assert (code == REG);
1245       if (G16_REG_P (REGNO (op)))
1246         fprintf (file, "!");
1247     }
1248   else if (c == 'V')
1249     {
1250       gcc_assert (code == REG);
1251       fprintf (file, G16_REG_P (REGNO (op)) ? "v!" : "lfh!");
1252     }
1253   else if (c == 'C')
1254     {
1255       enum machine_mode mode = GET_MODE (XEXP (op, 0));
1256
1257       switch (code)
1258         {
1259         case EQ: fputs ("eq", file); break;
1260         case NE: fputs ("ne", file); break;
1261         case GT: fputs ("gt", file); break;
1262         case GE: fputs (mode != CCmode ? "pl" : "ge", file); break;
1263         case LT: fputs (mode != CCmode ? "mi" : "lt", file); break;
1264         case LE: fputs ("le", file); break;
1265         case GTU: fputs ("gtu", file); break;
1266         case GEU: fputs ("cs", file); break;
1267         case LTU: fputs ("cc", file); break;
1268         case LEU: fputs ("leu", file); break;
1269         default:
1270           output_operand_lossage ("invalid operand for code: '%c'", code);
1271         }
1272     }
1273   else if (c == 'E')
1274     {
1275       unsigned HOST_WIDE_INT i;
1276       unsigned HOST_WIDE_INT pow2mask = 1;
1277       unsigned HOST_WIDE_INT val;
1278
1279       val = INTVAL (op);
1280       for (i = 0; i < 32; i++)
1281         {
1282           if (val == pow2mask)
1283             break;
1284           pow2mask <<= 1;
1285         }
1286       gcc_assert (i < 32);
1287       fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
1288     }
1289   else if (c == 'F')
1290     {
1291       unsigned HOST_WIDE_INT i;
1292       unsigned HOST_WIDE_INT pow2mask = 1;
1293       unsigned HOST_WIDE_INT val;
1294
1295       val = ~INTVAL (op);
1296       for (i = 0; i < 32; i++)
1297         {
1298           if (val == pow2mask)
1299             break;
1300           pow2mask <<= 1;
1301         }
1302       gcc_assert (i < 32);
1303       fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
1304     }
1305   else if (code == REG)
1306     {
1307       int regnum = REGNO (op);
1308       if ((c == 'H' && !WORDS_BIG_ENDIAN)
1309           || (c == 'L' && WORDS_BIG_ENDIAN))
1310         regnum ++;
1311       fprintf (file, "%s", reg_names[regnum]);
1312     }
1313   else
1314     {
1315       switch (code)
1316         {
1317         case MEM:
1318           score7_print_operand_address (file, op);
1319           break;
1320         default:
1321           output_addr_const (file, op);
1322         }
1323     }
1324 }
1325
1326 /* Implement PRINT_OPERAND_ADDRESS macro.  */
1327 void
1328 score7_print_operand_address (FILE *file, rtx x)
1329 {
1330   struct score7_address_info addr;
1331   enum rtx_code code = GET_CODE (x);
1332   enum machine_mode mode = GET_MODE (x);
1333
1334   if (code == MEM)
1335     x = XEXP (x, 0);
1336
1337   if (score7_classify_address (&addr, mode, x, true))
1338     {
1339       switch (addr.type)
1340         {
1341         case SCORE7_ADD_REG:
1342           {
1343             switch (addr.code)
1344               {
1345               case PRE_DEC:
1346                 fprintf (file, "[%s,-%ld]+", reg_names[REGNO (addr.reg)],
1347                          INTVAL (addr.offset));
1348                 break;
1349               case POST_DEC:
1350                 fprintf (file, "[%s]+,-%ld", reg_names[REGNO (addr.reg)],
1351                          INTVAL (addr.offset));
1352                 break;
1353               case PRE_INC:
1354                 fprintf (file, "[%s, %ld]+", reg_names[REGNO (addr.reg)],
1355                          INTVAL (addr.offset));
1356                 break;
1357               case POST_INC:
1358                 fprintf (file, "[%s]+, %ld", reg_names[REGNO (addr.reg)],
1359                          INTVAL (addr.offset));
1360                 break;
1361               default:
1362                 if (INTVAL(addr.offset) == 0)
1363                   fprintf(file, "[%s]", reg_names[REGNO (addr.reg)]);
1364                 else
1365                   fprintf(file, "[%s, %ld]", reg_names[REGNO (addr.reg)],
1366                           INTVAL(addr.offset));
1367                 break;
1368               }
1369           }
1370           return;
1371         case SCORE7_ADD_CONST_INT:
1372         case SCORE7_ADD_SYMBOLIC:
1373           output_addr_const (file, x);
1374           return;
1375         }
1376     }
1377   print_rtl (stderr, x);
1378   gcc_unreachable ();
1379 }
1380
1381 /* Implement SELECT_CC_MODE macro.  */
1382 enum machine_mode
1383 score7_select_cc_mode (enum rtx_code op, rtx x, rtx y)
1384 {
1385   if ((op == EQ || op == NE || op == LT || op == GE)
1386       && y == const0_rtx
1387       && GET_MODE (x) == SImode)
1388     {
1389       switch (GET_CODE (x))
1390         {
1391         case PLUS:
1392         case MINUS:
1393         case NEG:
1394         case AND:
1395         case IOR:
1396         case XOR:
1397         case NOT:
1398         case ASHIFT:
1399         case LSHIFTRT:
1400         case ASHIFTRT:
1401           return CC_NZmode;
1402
1403         case SIGN_EXTEND:
1404         case ZERO_EXTEND:
1405         case ROTATE:
1406         case ROTATERT:
1407           return (op == LT || op == GE) ? CC_Nmode : CCmode;
1408
1409         default:
1410           return CCmode;
1411         }
1412     }
1413
1414   if ((op == EQ || op == NE)
1415       && (GET_CODE (y) == NEG)
1416       && register_operand (XEXP (y, 0), SImode)
1417       && register_operand (x, SImode))
1418     {
1419       return CC_NZmode;
1420     }
1421
1422   return CCmode;
1423 }
1424
1425 /* Generate the prologue instructions for entry into a S+core function.  */
1426 void
1427 score7_prologue (void)
1428 {
1429 #define EMIT_PL(_rtx)        RTX_FRAME_RELATED_P (_rtx) = 1
1430
1431   struct score7_frame_info *f = score7_compute_frame_size (get_frame_size ());
1432   HOST_WIDE_INT size;
1433   int regno;
1434
1435   size = f->total_size - f->gp_reg_size;
1436
1437   if (flag_pic)
1438     emit_insn (gen_cpload_score7 ());
1439
1440   for (regno = (int) GP_REG_LAST; regno >= (int) GP_REG_FIRST; regno--)
1441     {
1442       if (BITSET_P (f->mask, regno - GP_REG_FIRST))
1443         {
1444           rtx mem = gen_rtx_MEM (SImode,
1445                                  gen_rtx_PRE_DEC (SImode, stack_pointer_rtx));
1446           rtx reg = gen_rtx_REG (SImode, regno);
1447           if (!crtl->calls_eh_return)
1448             MEM_READONLY_P (mem) = 1;
1449           EMIT_PL (emit_insn (gen_pushsi_score7 (mem, reg)));
1450         }
1451     }
1452
1453   if (size > 0)
1454     {
1455       rtx insn;
1456
1457       if (CONST_OK_FOR_LETTER_P (-size, 'L'))
1458         EMIT_PL (emit_insn (gen_add3_insn (stack_pointer_rtx,
1459                                            stack_pointer_rtx,
1460                                            GEN_INT (-size))));
1461       else
1462         {
1463           EMIT_PL (emit_move_insn (gen_rtx_REG (Pmode, SCORE7_PROLOGUE_TEMP_REGNUM),
1464                                    GEN_INT (size)));
1465           EMIT_PL (emit_insn
1466                    (gen_sub3_insn (stack_pointer_rtx,
1467                                    stack_pointer_rtx,
1468                                    gen_rtx_REG (Pmode,
1469                                                 SCORE7_PROLOGUE_TEMP_REGNUM))));
1470         }
1471       insn = get_last_insn ();
1472       REG_NOTES (insn) =
1473         alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR,
1474                          gen_rtx_SET (VOIDmode, stack_pointer_rtx,
1475                                       plus_constant (stack_pointer_rtx,
1476                                                      -size)),
1477                                       REG_NOTES (insn));
1478     }
1479
1480   if (frame_pointer_needed)
1481     EMIT_PL (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx));
1482
1483   if (flag_pic && f->cprestore_size)
1484     {
1485       if (frame_pointer_needed)
1486         emit_insn (gen_cprestore_use_fp_score7 (GEN_INT (size - f->cprestore_size)));
1487       else
1488         emit_insn (gen_cprestore_use_sp_score7 (GEN_INT (size - f->cprestore_size)));
1489     }
1490
1491 #undef EMIT_PL
1492 }
1493
1494 /* Generate the epilogue instructions in a S+core function.  */
1495 void
1496 score7_epilogue (int sibcall_p)
1497 {
1498   struct score7_frame_info *f = score7_compute_frame_size (get_frame_size ());
1499   HOST_WIDE_INT size;
1500   int regno;
1501   rtx base;
1502
1503   size = f->total_size - f->gp_reg_size;
1504
1505   if (!frame_pointer_needed)
1506     base = stack_pointer_rtx;
1507   else
1508     base = hard_frame_pointer_rtx;
1509
1510   if (size)
1511     {
1512       if (CONST_OK_FOR_LETTER_P (size, 'L'))
1513         emit_insn (gen_add3_insn (base, base, GEN_INT (size)));
1514       else
1515         {
1516           emit_move_insn (gen_rtx_REG (Pmode, SCORE7_EPILOGUE_TEMP_REGNUM),
1517                           GEN_INT (size));
1518           emit_insn (gen_add3_insn (base, base,
1519                                     gen_rtx_REG (Pmode,
1520                                                  SCORE7_EPILOGUE_TEMP_REGNUM)));
1521         }
1522     }
1523
1524   if (base != stack_pointer_rtx)
1525     emit_move_insn (stack_pointer_rtx, base);
1526
1527   if (crtl->calls_eh_return)
1528     emit_insn (gen_add3_insn (stack_pointer_rtx,
1529                               stack_pointer_rtx,
1530                               EH_RETURN_STACKADJ_RTX));
1531
1532   for (regno = (int) GP_REG_FIRST; regno <= (int) GP_REG_LAST; regno++)
1533     {
1534       if (BITSET_P (f->mask, regno - GP_REG_FIRST))
1535         {
1536           rtx mem = gen_rtx_MEM (SImode,
1537                                  gen_rtx_POST_INC (SImode, stack_pointer_rtx));
1538           rtx reg = gen_rtx_REG (SImode, regno);
1539
1540           if (!crtl->calls_eh_return)
1541             MEM_READONLY_P (mem) = 1;
1542
1543           emit_insn (gen_popsi_score7 (reg, mem));
1544         }
1545     }
1546
1547   if (!sibcall_p)
1548     emit_jump_insn (gen_return_internal_score7 (gen_rtx_REG (Pmode, RA_REGNUM)));
1549 }
1550
1551 /* Return true if X is a symbolic constant that can be calculated in
1552    the same way as a bare symbol.  If it is, store the type of the
1553    symbol in *SYMBOL_TYPE.  */
1554 int
1555 score7_symbolic_constant_p (rtx x, enum score_symbol_type *symbol_type)
1556 {
1557   HOST_WIDE_INT offset;
1558
1559   score7_split_const (x, &x, &offset);
1560   if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF)
1561     *symbol_type = score7_classify_symbol (x);
1562   else
1563     return 0;
1564
1565   if (offset == 0)
1566     return 1;
1567
1568   /* if offset > 15bit, must reload  */
1569   if (!IMM_IN_RANGE (offset, 15, 1))
1570     return 0;
1571
1572   switch (*symbol_type)
1573     {
1574     case SYMBOL_GENERAL:
1575       return 1;
1576     case SYMBOL_SMALL_DATA:
1577       return score7_offset_within_object_p (x, offset);
1578     }
1579   gcc_unreachable ();
1580 }
1581
1582 void
1583 score7_movsicc (rtx *ops)
1584 {
1585   enum machine_mode mode;
1586
1587   mode = score7_select_cc_mode (GET_CODE (ops[1]), ops[2], ops[3]);
1588   emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (mode, CC_REGNUM),
1589                           gen_rtx_COMPARE (mode, XEXP (ops[1], 0),
1590                                            XEXP (ops[1], 1))));
1591 }
1592
1593 /* Call and sibcall pattern all need call this function.  */
1594 void
1595 score7_call (rtx *ops, bool sib)
1596 {
1597   rtx addr = XEXP (ops[0], 0);
1598   if (!call_insn_operand (addr, VOIDmode))
1599     {
1600       rtx oaddr = addr;
1601       addr = gen_reg_rtx (Pmode);
1602       gen_move_insn (addr, oaddr);
1603     }
1604
1605   if (sib)
1606     emit_call_insn (gen_sibcall_internal_score7 (addr, ops[1]));
1607   else
1608     emit_call_insn (gen_call_internal_score7 (addr, ops[1]));
1609 }
1610
1611 /* Call value and sibcall value pattern all need call this function.  */
1612 void
1613 score7_call_value (rtx *ops, bool sib)
1614 {
1615   rtx result = ops[0];
1616   rtx addr = XEXP (ops[1], 0);
1617   rtx arg = ops[2];
1618
1619   if (!call_insn_operand (addr, VOIDmode))
1620     {
1621       rtx oaddr = addr;
1622       addr = gen_reg_rtx (Pmode);
1623       gen_move_insn (addr, oaddr);
1624     }
1625
1626   if (sib)
1627     emit_call_insn (gen_sibcall_value_internal_score7 (result, addr, arg));
1628   else
1629     emit_call_insn (gen_call_value_internal_score7 (result, addr, arg));
1630 }
1631
1632 /* Machine Split  */
1633 void
1634 score7_movdi (rtx *ops)
1635 {
1636   rtx dst = ops[0];
1637   rtx src = ops[1];
1638   rtx dst0 = score7_subw (dst, 0);
1639   rtx dst1 = score7_subw (dst, 1);
1640   rtx src0 = score7_subw (src, 0);
1641   rtx src1 = score7_subw (src, 1);
1642
1643   if (GET_CODE (dst0) == REG && reg_overlap_mentioned_p (dst0, src))
1644     {
1645       emit_move_insn (dst1, src1);
1646       emit_move_insn (dst0, src0);
1647     }
1648   else
1649     {
1650       emit_move_insn (dst0, src0);
1651       emit_move_insn (dst1, src1);
1652     }
1653 }
1654
1655 void
1656 score7_zero_extract_andi (rtx *ops)
1657 {
1658   if (INTVAL (ops[1]) == 1 && const_uimm5 (ops[2], SImode))
1659     emit_insn (gen_zero_extract_bittst_score7 (ops[0], ops[2]));
1660   else
1661     {
1662       unsigned HOST_WIDE_INT mask;
1663       mask = (0xffffffffU & ((1U << INTVAL (ops[1])) - 1U));
1664       mask = mask << INTVAL (ops[2]);
1665       emit_insn (gen_andsi3_cmp_score7 (ops[3], ops[0],
1666                                  gen_int_mode (mask, SImode)));
1667     }
1668 }
1669
1670 /* Check addr could be present as PRE/POST mode.  */
1671 static bool
1672 score7_pindex_mem (rtx addr)
1673 {
1674   if (GET_CODE (addr) == MEM)
1675     {
1676       switch (GET_CODE (XEXP (addr, 0)))
1677         {
1678         case PRE_DEC:
1679         case POST_DEC:
1680         case PRE_INC:
1681         case POST_INC:
1682           return true;
1683         default:
1684           break;
1685         }
1686     }
1687   return false;
1688 }
1689
1690 /* Output asm code for ld/sw insn.  */
1691 static int
1692 score7_pr_addr_post (rtx *ops, int idata, int iaddr, char *ip, enum score_mem_unit unit)
1693 {
1694   struct score7_address_info ai;
1695
1696   gcc_assert (GET_CODE (ops[idata]) == REG);
1697   gcc_assert (score7_classify_address (&ai, SImode, XEXP (ops[iaddr], 0), true));
1698
1699   if (!score7_pindex_mem (ops[iaddr])
1700       && ai.type == SCORE7_ADD_REG
1701       && GET_CODE (ai.offset) == CONST_INT
1702       && G16_REG_P (REGNO (ops[idata]))
1703       && G16_REG_P (REGNO (ai.reg)))
1704     {
1705       if (INTVAL (ai.offset) == 0)
1706         {
1707           ops[iaddr] = ai.reg;
1708           return snprintf (ip, INS_BUF_SZ,
1709                            "!\t%%%d, [%%%d]", idata, iaddr);
1710         }
1711       if (REGNO (ai.reg) == HARD_FRAME_POINTER_REGNUM)
1712         {
1713           HOST_WIDE_INT offset = INTVAL (ai.offset);
1714           if (SCORE_ALIGN_UNIT (offset, unit)
1715               && CONST_OK_FOR_LETTER_P (offset >> unit, 'J'))
1716             {
1717               ops[iaddr] = ai.offset;
1718               return snprintf (ip, INS_BUF_SZ,
1719                                "p!\t%%%d, %%c%d", idata, iaddr);
1720             }
1721         }
1722     }
1723   return snprintf (ip, INS_BUF_SZ, "\t%%%d, %%a%d", idata, iaddr);
1724 }
1725
1726 /* Output asm insn for load.  */
1727 const char *
1728 score7_linsn (rtx *ops, enum score_mem_unit unit, bool sign)
1729 {
1730   const char *pre_ins[] =
1731     {"lbu", "lhu", "lw", "??", "lb", "lh", "lw", "??"};
1732   char *ip;
1733
1734   strcpy (score7_ins, pre_ins[(sign ? 4 : 0) + unit]);
1735   ip = score7_ins + strlen (score7_ins);
1736
1737   if ((!sign && unit != SCORE_HWORD)
1738       || (sign && unit != SCORE_BYTE))
1739     score7_pr_addr_post (ops, 0, 1, ip, unit);
1740   else
1741     snprintf (ip, INS_BUF_SZ, "\t%%0, %%a1");
1742
1743   return score7_ins;
1744 }
1745
1746 /* Output asm insn for store.  */
1747 const char *
1748 score7_sinsn (rtx *ops, enum score_mem_unit unit)
1749 {
1750   const char *pre_ins[] = {"sb", "sh", "sw"};
1751   char *ip;
1752
1753   strcpy (score7_ins, pre_ins[unit]);
1754   ip = score7_ins + strlen (score7_ins);
1755   score7_pr_addr_post (ops, 1, 0, ip, unit);
1756   return score7_ins;
1757 }
1758
1759 /* Output asm insn for load immediate.  */
1760 const char *
1761 score7_limm (rtx *ops)
1762 {
1763   HOST_WIDE_INT v;
1764
1765   gcc_assert (GET_CODE (ops[0]) == REG);
1766   gcc_assert (GET_CODE (ops[1]) == CONST_INT);
1767
1768   v = INTVAL (ops[1]);
1769   if (G16_REG_P (REGNO (ops[0])) && IMM_IN_RANGE (v, 8, 0))
1770     return "ldiu!\t%0, %c1";
1771   else if (IMM_IN_RANGE (v, 16, 1))
1772     return "ldi\t%0, %c1";
1773   else if ((v & 0xffff) == 0)
1774     return "ldis\t%0, %U1";
1775   else
1776     return "li\t%0, %c1";
1777 }
1778
1779 /* Output asm insn for move.  */
1780 const char *
1781 score7_move (rtx *ops)
1782 {
1783   gcc_assert (GET_CODE (ops[0]) == REG);
1784   gcc_assert (GET_CODE (ops[1]) == REG);
1785
1786   if (G16_REG_P (REGNO (ops[0])))
1787     {
1788       if (G16_REG_P (REGNO (ops[1])))
1789         return "mv!\t%0, %1";
1790       else
1791         return "mlfh!\t%0, %1";
1792     }
1793   else if (G16_REG_P (REGNO (ops[1])))
1794     return "mhfl!\t%0, %1";
1795   else
1796     return "mv\t%0, %1";
1797 }
1798
1799 /* Generate add insn.  */
1800 const char *
1801 score7_select_add_imm (rtx *ops, bool set_cc)
1802 {
1803   HOST_WIDE_INT v = INTVAL (ops[2]);
1804
1805   gcc_assert (GET_CODE (ops[2]) == CONST_INT);
1806   gcc_assert (REGNO (ops[0]) == REGNO (ops[1]));
1807
1808   if (set_cc && G16_REG_P (REGNO (ops[0])))
1809     {
1810       if (v > 0 && IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT) v, 0, 15))
1811         {
1812           ops[2] = GEN_INT (ffs (v) - 1);
1813           return "addei!\t%0, %c2";
1814         }
1815
1816       if (v < 0 && IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT) (-v), 0, 15))
1817         {
1818           ops[2] = GEN_INT (ffs (-v) - 1);
1819           return "subei!\t%0, %c2";
1820         }
1821     }
1822
1823   if (set_cc)
1824     return "addi.c\t%0, %c2";
1825   else
1826     return "addi\t%0, %c2";
1827 }
1828
1829 /* Output arith insn.  */
1830 const char *
1831 score7_select (rtx *ops, const char *inst_pre,
1832                bool commu, const char *letter, bool set_cc)
1833 {
1834   gcc_assert (GET_CODE (ops[0]) == REG);
1835   gcc_assert (GET_CODE (ops[1]) == REG);
1836
1837   if (set_cc && G16_REG_P (REGNO (ops[0]))
1838       && (GET_CODE (ops[2]) == REG ? G16_REG_P (REGNO (ops[2])) : 1)
1839       && REGNO (ops[0]) == REGNO (ops[1]))
1840     {
1841       snprintf (score7_ins, INS_BUF_SZ, "%s!\t%%0, %%%s2", inst_pre, letter);
1842       return score7_ins;
1843     }
1844
1845   if (commu && set_cc && G16_REG_P (REGNO (ops[0]))
1846       && G16_REG_P (REGNO (ops[1]))
1847       && REGNO (ops[0]) == REGNO (ops[2]))
1848     {
1849       gcc_assert (GET_CODE (ops[2]) == REG);
1850       snprintf (score7_ins, INS_BUF_SZ, "%s!\t%%0, %%%s1", inst_pre, letter);
1851       return score7_ins;
1852     }
1853
1854   if (set_cc)
1855     snprintf (score7_ins, INS_BUF_SZ, "%s.c\t%%0, %%1, %%%s2", inst_pre, letter);
1856   else
1857     snprintf (score7_ins, INS_BUF_SZ, "%s\t%%0, %%1, %%%s2", inst_pre, letter);
1858   return score7_ins;
1859 }
1860