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