OSDN Git Service

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