OSDN Git Service

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