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