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