OSDN Git Service

* config/score/crti.asm: add pic support.
[pf3gnuchains/gcc-fork.git] / gcc / config / score / score.c
1 /* Output routines for Sunplus S+CORE processor
2    Copyright (C) 2005 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 2, 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 COPYING.  If not, write to
19    the Free Software Foundation, 51 Franklin Street, Fifth Floor,
20    Boston, MA 02110-1301, USA.  */
21
22 #include "config.h"
23 #include "system.h"
24 #include "coretypes.h"
25 #include "tm.h"
26 #include <signal.h>
27 #include "rtl.h"
28 #include "regs.h"
29 #include "hard-reg-set.h"
30 #include "real.h"
31 #include "insn-config.h"
32 #include "conditions.h"
33 #include "insn-attr.h"
34 #include "recog.h"
35 #include "toplev.h"
36 #include "output.h"
37 #include "tree.h"
38 #include "function.h"
39 #include "expr.h"
40 #include "optabs.h"
41 #include "flags.h"
42 #include "reload.h"
43 #include "tm_p.h"
44 #include "ggc.h"
45 #include "gstab.h"
46 #include "hashtab.h"
47 #include "debug.h"
48 #include "target.h"
49 #include "target-def.h"
50 #include "integrate.h"
51 #include "langhooks.h"
52 #include "cfglayout.h"
53 #include "score-mdaux.h"
54
55 #define GR_REG_CLASS_P(C)        ((C) == G16_REGS || (C) == G32_REGS)
56 #define SP_REG_CLASS_P(C) \
57   ((C) == CN_REG || (C) == LC_REG || (C) == SC_REG || (C) == SP_REGS)
58 #define CP_REG_CLASS_P(C) \
59   ((C) == CP1_REGS || (C) == CP2_REGS || (C) == CP3_REGS || (C) == CPA_REGS)
60 #define CE_REG_CLASS_P(C) \
61   ((C) == HI_REG || (C) == LO_REG || (C) == CE_REGS)
62
63 static int score_arg_partial_bytes (const CUMULATIVE_ARGS *,
64                                     enum machine_mode, tree, int);
65
66 static int score_symbol_insns (enum score_symbol_type);
67
68 static int score_address_insns (rtx, enum machine_mode);
69
70 static bool score_rtx_costs (rtx, int, int, int *);
71
72 #undef  TARGET_ASM_FILE_START
73 #define TARGET_ASM_FILE_START           th_asm_file_start
74
75 #undef  TARGET_ASM_FILE_END
76 #define TARGET_ASM_FILE_END             th_asm_file_end
77
78 #undef  TARGET_ASM_FUNCTION_PROLOGUE
79 #define TARGET_ASM_FUNCTION_PROLOGUE    th_function_prologue
80
81 #undef  TARGET_ASM_FUNCTION_EPILOGUE
82 #define TARGET_ASM_FUNCTION_EPILOGUE    th_function_epilogue
83
84 #undef  TARGET_SCHED_ISSUE_RATE
85 #define TARGET_SCHED_ISSUE_RATE         th_issue_rate
86
87 #undef TARGET_ASM_SELECT_RTX_SECTION
88 #define TARGET_ASM_SELECT_RTX_SECTION   th_select_rtx_section
89
90 #undef  TARGET_IN_SMALL_DATA_P
91 #define TARGET_IN_SMALL_DATA_P          th_in_small_data_p
92
93 #undef  TARGET_FUNCTION_OK_FOR_SIBCALL
94 #define TARGET_FUNCTION_OK_FOR_SIBCALL  th_function_ok_for_sibcall
95
96 #undef TARGET_STRICT_ARGUMENT_NAMING
97 #define TARGET_STRICT_ARGUMENT_NAMING   th_strict_argument_naming
98
99 #undef TARGET_ASM_OUTPUT_MI_THUNK
100 #define TARGET_ASM_OUTPUT_MI_THUNK      th_output_mi_thunk
101
102 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
103 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK  hook_bool_tree_hwi_hwi_tree_true
104
105 #undef TARGET_PROMOTE_FUNCTION_ARGS
106 #define TARGET_PROMOTE_FUNCTION_ARGS    hook_bool_tree_true
107
108 #undef TARGET_PROMOTE_FUNCTION_RETURN
109 #define TARGET_PROMOTE_FUNCTION_RETURN  hook_bool_tree_true
110
111 #undef TARGET_PROMOTE_PROTOTYPES
112 #define TARGET_PROMOTE_PROTOTYPES       hook_bool_tree_true
113
114 #undef TARGET_MUST_PASS_IN_STACK
115 #define TARGET_MUST_PASS_IN_STACK       must_pass_in_stack_var_size
116
117 #undef TARGET_ARG_PARTIAL_BYTES
118 #define TARGET_ARG_PARTIAL_BYTES        score_arg_partial_bytes
119
120 #undef TARGET_PASS_BY_REFERENCE
121 #define TARGET_PASS_BY_REFERENCE        score_pass_by_reference
122
123 #undef TARGET_RETURN_IN_MEMORY
124 #define TARGET_RETURN_IN_MEMORY         score_return_in_memory
125
126 #undef TARGET_RTX_COSTS
127 #define TARGET_RTX_COSTS                score_rtx_costs
128
129 /* Implement TARGET_RETURN_IN_MEMORY.  In S+core,
130    small structures are returned in a register.
131    Objects with varying size must still be returned in memory.  */
132 static bool
133 score_return_in_memory (tree type, tree fndecl ATTRIBUTE_UNUSED)
134 {
135   return ((TYPE_MODE (type) == BLKmode)
136           || (int_size_in_bytes (type) > 2 * UNITS_PER_WORD)
137           || (int_size_in_bytes (type) == -1));
138 }
139
140 /* Return nonzero when an argument must be passed by reference.  */
141 static bool
142 score_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
143                          enum machine_mode mode, tree type,
144                          bool named ATTRIBUTE_UNUSED)
145 {
146   /* If we have a variable-sized parameter, we have no choice.  */
147   return targetm.calls.must_pass_in_stack (mode, type);
148 }
149
150 /* Return a legitimate address for REG + OFFSET.  */
151 static rtx
152 score_add_offset (rtx temp, rtx reg, HOST_WIDE_INT offset)
153 {
154   if (!CONST_OK_FOR_LETTER_P (offset, 'O'))
155     {
156       reg = expand_simple_binop (GET_MODE (reg), PLUS,
157                                  gen_int_mode (offset & 0xffffc000,
158                                                GET_MODE (reg)),
159                                  reg, NULL, 0, OPTAB_WIDEN);
160       offset &= 0x3fff;
161     }
162
163   return plus_constant (reg, offset);
164 }
165
166 /* Implement TARGET_ASM_OUTPUT_MI_THUNK.  Generate rtl rather than asm text
167    in order to avoid duplicating too much logic from elsewhere.  */
168 static void
169 th_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
170                     HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
171                     tree function)
172 {
173   rtx this, temp1, temp2, insn, fnaddr;
174
175   /* Pretend to be a post-reload pass while generating rtl.  */
176   no_new_pseudos = 1;
177   reload_completed = 1;
178   reset_block_changes ();
179
180   /* We need two temporary registers in some cases.  */
181   temp1 = gen_rtx_REG (Pmode, 8);
182   temp2 = gen_rtx_REG (Pmode, 9);
183
184   /* Find out which register contains the "this" pointer.  */
185   if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
186     this = gen_rtx_REG (Pmode, ARG_REG_FIRST + 1);
187   else
188     this = gen_rtx_REG (Pmode, ARG_REG_FIRST);
189
190   /* Add DELTA to THIS.  */
191   if (delta != 0)
192     {
193       rtx offset = GEN_INT (delta);
194       if (!CONST_OK_FOR_LETTER_P (delta, 'L'))
195         {
196           emit_move_insn (temp1, offset);
197           offset = temp1;
198         }
199       emit_insn (gen_add3_insn (this, this, offset));
200     }
201
202   /* If needed, add *(*THIS + VCALL_OFFSET) to THIS.  */
203   if (vcall_offset != 0)
204     {
205       rtx addr;
206
207       /* Set TEMP1 to *THIS.  */
208       emit_move_insn (temp1, gen_rtx_MEM (Pmode, this));
209
210       /* Set ADDR to a legitimate address for *THIS + VCALL_OFFSET.  */
211       addr = score_add_offset (temp2, temp1, vcall_offset);
212
213       /* Load the offset and add it to THIS.  */
214       emit_move_insn (temp1, gen_rtx_MEM (Pmode, addr));
215       emit_insn (gen_add3_insn (this, this, temp1));
216     }
217
218   /* Jump to the target function.  */
219   fnaddr = XEXP (DECL_RTL (function), 0);
220   insn = emit_call_insn (gen_sibcall_internal (fnaddr, const0_rtx));
221   SIBLING_CALL_P (insn) = 1;
222
223   /* Run just enough of rest_of_compilation.  This sequence was
224      "borrowed" from alpha.c.  */
225   insn = get_insns ();
226   insn_locators_initialize ();
227   split_all_insns_noflow ();
228   shorten_branches (insn);
229   final_start_function (insn, file, 1);
230   final (insn, file, 1);
231   final_end_function ();
232
233   /* Clean up the vars set above.  Note that final_end_function resets
234      the global pointer for us.  */
235   reload_completed = 0;
236   no_new_pseudos = 0;
237 }
238
239 /* Implement TARGET_STRICT_ARGUMENT_NAMING.  */
240 static bool
241 th_strict_argument_naming (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED)
242 {
243   return true;
244 }
245
246 /* Implement TARGET_FUNCTION_OK_FOR_SIBCALL.  */
247 static bool
248 th_function_ok_for_sibcall (ATTRIBUTE_UNUSED tree decl,
249                             ATTRIBUTE_UNUSED tree exp)
250 {
251   return true;
252 }
253
254 struct score_arg_info
255 {
256   /* The argument's size, in bytes.  */
257   unsigned int num_bytes;
258
259   /* The number of words passed in registers, rounded up.  */
260   unsigned int reg_words;
261
262   /* The offset of the first register from GP_ARG_FIRST or FP_ARG_FIRST,
263      or ARG_REG_NUM if the argument is passed entirely on the stack.  */
264   unsigned int reg_offset;
265
266   /* The number of words that must be passed on the stack, rounded up.  */
267   unsigned int stack_words;
268
269   /* The offset from the start of the stack overflow area of the argument's
270      first stack word.  Only meaningful when STACK_WORDS is nonzero.  */
271   unsigned int stack_offset;
272 };
273
274 /* Fill INFO with information about a single argument.  CUM is the
275    cumulative state for earlier arguments.  MODE is the mode of this
276    argument and TYPE is its type (if known).  NAMED is true if this
277    is a named (fixed) argument rather than a variable one.  */
278 static void
279 classify_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
280               tree type, int named, struct score_arg_info *info)
281 {
282   int even_reg_p;
283   unsigned int num_words, max_regs;
284
285   even_reg_p = 0;
286   if (GET_MODE_CLASS (mode) == MODE_INT
287       || GET_MODE_CLASS (mode) == MODE_FLOAT)
288     even_reg_p = (GET_MODE_SIZE (mode) > UNITS_PER_WORD);
289   else
290     if (type != NULL_TREE && TYPE_ALIGN (type) > BITS_PER_WORD && named)
291       even_reg_p = 1;
292
293   if (TARGET_MUST_PASS_IN_STACK (mode, type))
294     info->reg_offset = ARG_REG_NUM;
295   else
296     {
297       info->reg_offset = cum->num_gprs;
298       if (even_reg_p)
299         info->reg_offset += info->reg_offset & 1;
300     }
301
302   if (mode == BLKmode)
303     info->num_bytes = int_size_in_bytes (type);
304   else
305     info->num_bytes = GET_MODE_SIZE (mode);
306
307   num_words = (info->num_bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
308   max_regs = ARG_REG_NUM - info->reg_offset;
309
310   /* Partition the argument between registers and stack.  */
311   info->reg_words = MIN (num_words, max_regs);
312   info->stack_words = num_words - info->reg_words;
313
314   /* The alignment applied to registers is also applied to stack arguments.  */
315   if (info->stack_words)
316     {
317       info->stack_offset = cum->stack_words;
318       if (even_reg_p)
319         info->stack_offset += info->stack_offset & 1;
320     }
321 }
322
323 /* Set up the stack and frame (if desired) for the function.  */
324 static void
325 th_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
326 {
327   const char *fnname;
328   struct score_frame_info *f = mda_cached_frame ();
329   HOST_WIDE_INT tsize = f->total_size;
330
331   fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
332   if (!flag_inhibit_size_directive)
333     {
334       fputs ("\t.ent\t", file);
335       assemble_name (file, fnname);
336       fputs ("\n", file);
337     }
338   assemble_name (file, fnname);
339   fputs (":\n", file);
340
341   if (!flag_inhibit_size_directive)
342     {
343       fprintf (file,
344                "\t.frame\t%s," HOST_WIDE_INT_PRINT_DEC ",%s, %d\t\t"
345                "# vars= " HOST_WIDE_INT_PRINT_DEC ", regs= %d"
346                ", args= " HOST_WIDE_INT_PRINT_DEC
347                ", gp= " HOST_WIDE_INT_PRINT_DEC "\n",
348                (reg_names[(frame_pointer_needed)
349                 ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM]),
350                tsize,
351                reg_names[RA_REGNUM],
352                current_function_is_leaf ? 1 : 0,
353                f->var_size,
354                f->num_gp,
355                f->args_size,
356                f->cprestore_size);
357
358       fprintf(file, "\t.mask\t0x%08x," HOST_WIDE_INT_PRINT_DEC "\n",
359               f->mask,
360               (f->gp_sp_offset - f->total_size));
361     }
362 }
363
364 /* Do any necessary cleanup after a function to restore stack, frame,
365    and regs.  */
366 static void
367 th_function_epilogue (FILE *file,
368                       HOST_WIDE_INT size ATTRIBUTE_UNUSED)
369 {
370   if (!flag_inhibit_size_directive)
371     {
372       const char *fnname;
373       fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
374       fputs ("\t.end\t", file);
375       assemble_name (file, fnname);
376       fputs ("\n", file);
377     }
378 }
379
380 /* Implement TARGET_SCHED_ISSUE_RATE.  */
381 static int
382 th_issue_rate (void)
383 {
384   return 1;
385 }
386
387 /* Returns true if X contains a SYMBOL_REF.  */
388 static bool
389 symbolic_expression_p (rtx x)
390 {
391   if (GET_CODE (x) == SYMBOL_REF)
392     return true;
393
394   if (GET_CODE (x) == CONST)
395     return symbolic_expression_p (XEXP (x, 0));
396
397   if (UNARY_P (x))
398     return symbolic_expression_p (XEXP (x, 0));
399
400   if (ARITHMETIC_P (x))
401     return (symbolic_expression_p (XEXP (x, 0))
402             || symbolic_expression_p (XEXP (x, 1)));
403
404   return false;
405 }
406
407 /* Choose the section to use for the constant rtx expression X that has
408    mode MODE.  */
409 static section *
410 th_select_rtx_section (enum machine_mode mode, rtx x,
411                        unsigned HOST_WIDE_INT align)
412 {
413   if (GET_MODE_SIZE (mode) <= SCORE_SDATA_MAX)
414     return get_named_section (0, ".sdata", 0);
415   else if (flag_pic && symbolic_expression_p (x))
416     return get_named_section (0, ".data.rel.ro", 3);
417   else
418     return mergeable_constant_section (mode, align, 0);
419 }
420
421 /* Implement TARGET_IN_SMALL_DATA_P.  */
422 static bool
423 th_in_small_data_p (tree decl)
424 {
425   HOST_WIDE_INT size;
426
427   if (TREE_CODE (decl) == STRING_CST
428       || TREE_CODE (decl) == FUNCTION_DECL)
429     return false;
430
431   if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl) != 0)
432     {
433       const char *name;
434       name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
435       if (strcmp (name, ".sdata") != 0
436           && strcmp (name, ".sbss") != 0)
437         return true;
438       if (!DECL_EXTERNAL (decl))
439         return false;
440     }
441   size = int_size_in_bytes (TREE_TYPE (decl));
442   return (size > 0 && size <= SCORE_SDATA_MAX);
443 }
444
445 /* Implement TARGET_ASM_FILE_START.  */
446 static void
447 th_asm_file_start (void)
448 {
449   default_file_start ();
450   fprintf (asm_out_file, ASM_COMMENT_START
451            "GCC for S+core %s \n", SCORE_GCC_VERSION);
452
453   if (flag_pic)
454     fprintf (asm_out_file, "\t.set pic\n");
455 }
456
457 /* Implement TARGET_ASM_FILE_END.  When using assembler macros, emit
458    .externs for any small-data variables that turned out to be external.  */
459 struct extern_list *extern_head = 0;
460
461 static void
462 th_asm_file_end (void)
463 {
464   tree name_tree;
465   struct extern_list *p;
466   if (extern_head)
467     {
468       fputs ("\n", asm_out_file);
469       for (p = extern_head; p != 0; p = p->next)
470         {
471           name_tree = get_identifier (p->name);
472           if (!TREE_ASM_WRITTEN (name_tree)
473               && TREE_SYMBOL_REFERENCED (name_tree))
474             {
475               TREE_ASM_WRITTEN (name_tree) = 1;
476               fputs ("\t.extern\t", asm_out_file);
477               assemble_name (asm_out_file, p->name);
478               fprintf (asm_out_file, ", %d\n", p->size);
479             }
480         }
481     }
482 }
483
484 static unsigned int sdata_max;
485
486 int
487 score_sdata_max (void)
488 {
489   return sdata_max;
490 }
491
492 /* default 0 = NO_REGS  */
493 enum reg_class score_char_to_class[256];
494
495 /* Implement OVERRIDE_OPTIONS macro.  */
496 void
497 score_override_options (void)
498 {
499   if (!flag_pic)
500     sdata_max = g_switch_set ? g_switch_value : DEFAULT_SDATA_MAX;
501   else
502     {
503       sdata_max = 0;
504       if (g_switch_set)
505         warning (0, "-fPIC and -G are incompatible");
506     }
507
508   score_char_to_class['d'] = G32_REGS;
509   score_char_to_class['e'] = G16_REGS;
510   score_char_to_class['t'] = T32_REGS;
511
512   score_char_to_class['h'] = HI_REG;
513   score_char_to_class['l'] = LO_REG;
514   score_char_to_class['x'] = CE_REGS;
515
516   score_char_to_class['q'] = CN_REG;
517   score_char_to_class['y'] = LC_REG;
518   score_char_to_class['z'] = SC_REG;
519   score_char_to_class['a'] = SP_REGS;
520
521   score_char_to_class['c'] = CR_REGS;
522
523   score_char_to_class['b'] = CP1_REGS;
524   score_char_to_class['f'] = CP2_REGS;
525   score_char_to_class['i'] = CP3_REGS;
526   score_char_to_class['j'] = CPA_REGS;
527 }
528
529 /* Implement REGNO_REG_CLASS macro.  */
530 int
531 score_reg_class (int regno)
532 {
533   int c;
534   gcc_assert (regno >= 0 && regno < FIRST_PSEUDO_REGISTER);
535
536   if (regno == FRAME_POINTER_REGNUM
537       || regno == ARG_POINTER_REGNUM)
538     return ALL_REGS;
539
540   for (c = 0 ; c < N_REG_CLASSES ; c++)
541     if (TEST_HARD_REG_BIT (reg_class_contents[c], regno))
542       return c;
543
544   return NO_REGS;
545 }
546
547 /* Implement PREFERRED_RELOAD_CLASS macro.  */
548 enum reg_class
549 score_preferred_reload_class (rtx x ATTRIBUTE_UNUSED, enum reg_class class)
550 {
551   if (reg_class_subset_p (G32_REGS, class))
552     class = G32_REGS;
553   if (reg_class_subset_p (G16_REGS, class))
554     class = G16_REGS;
555   return class;
556 }
557
558 /* Implement SECONDARY_INPUT_RELOAD_CLASS
559    and SECONDARY_OUTPUT_RELOAD_CLASS macro.  */
560 enum reg_class
561 score_secondary_reload_class (enum reg_class class,
562                               enum machine_mode mode ATTRIBUTE_UNUSED,
563                               rtx x)
564 {
565   int regno = -1;
566   if (GET_CODE (x) == REG || GET_CODE(x) == SUBREG)
567     regno = true_regnum (x);
568
569   if (!GR_REG_CLASS_P (class))
570     return GP_REG_P (regno) ? NO_REGS : G32_REGS;
571   return NO_REGS;
572 }
573
574 /* Implement CONST_OK_FOR_LETTER_P macro.  */
575 /* imm constraints
576    I        IMM8        (i15-2-form)
577    J        IMM5        (i15_1-form)
578    K        IMM16       (i-form)
579    L        IMM16s      (i-form)
580    M        IMM14       (ri-form)
581    N        IMM14s      (ri-form)
582    O        IMM15s      (ri-form)
583    P        IMM12s      (rix-form) / IMM10s(cop-form) << 2  */
584 int
585 score_const_ok_for_letter_p (int value, char c)
586 {
587   switch (c)
588     {
589     case 'I': return IMM_IN_RANGE (value, 8, 0);
590     case 'J': return IMM_IN_RANGE (value, 5, 0);
591     case 'K': return IMM_IN_RANGE (value, 16, 0);
592     case 'L': return IMM_IN_RANGE (value, 16, 1);
593     case 'M': return IMM_IN_RANGE (value, 14, 0);
594     case 'N': return IMM_IN_RANGE (value, 14, 1);
595     case 'O': return IMM_IN_RANGE (value, 15, 1);
596     case 'P': return IMM_IN_RANGE (value, 12, 1);
597     default : return 0;
598     }
599 }
600
601 /* Implement EXTRA_CONSTRAINT macro.  */
602 /* Q        const_hi    imm
603    Z        symbol_ref  */
604 int
605 score_extra_constraint (rtx op, char c)
606 {
607   switch (c)
608     {
609     case 'Q':
610       return (GET_CODE (op) == CONST_INT && (INTVAL (op) & 0xffff) == 0);
611     case 'Z':
612       return GET_CODE (op) == SYMBOL_REF;
613     default:
614       gcc_unreachable ();
615     }
616 }
617
618 /* Return truth value on whether or not a given hard register
619    can support a given mode.  */
620 int
621 score_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
622 {
623   int size = GET_MODE_SIZE (mode);
624   enum mode_class class = GET_MODE_CLASS (mode);
625
626   if (class == MODE_CC)
627     return regno == CC_REGNUM;
628   else if (regno == FRAME_POINTER_REGNUM
629            || regno == ARG_POINTER_REGNUM)
630     return class == MODE_INT;
631   else if (GP_REG_P (regno))
632     /* ((regno <= (GP_REG_LAST- HARD_REGNO_NREGS (dummy, mode)) + 1)  */
633     return !(regno & 1) || (size <= UNITS_PER_WORD);
634   else if (CE_REG_P (regno))
635     return (class == MODE_INT
636             && ((size <= UNITS_PER_WORD)
637                 || (regno == CE_REG_FIRST && size == 2 * UNITS_PER_WORD)));
638   else
639     return (class == MODE_INT) && (size <= UNITS_PER_WORD);
640 }
641
642 /* Implement INITIAL_ELIMINATION_OFFSET.  FROM is either the frame
643    pointer or argument pointer.  TO is either the stack pointer or
644    hard frame pointer.  */
645 HOST_WIDE_INT
646 score_initial_elimination_offset (int from,
647                                   int to ATTRIBUTE_UNUSED)
648 {
649   struct score_frame_info *f = mda_compute_frame_size (get_frame_size ());
650   switch (from)
651     {
652     case ARG_POINTER_REGNUM:
653       return f->total_size;
654     case FRAME_POINTER_REGNUM:
655       return 0;
656     default:
657       gcc_unreachable ();
658     }
659 }
660
661 /* Argument support functions.  */
662
663 /* Initialize CUMULATIVE_ARGS for a function.  */
664 void
665 score_init_cumulative_args (CUMULATIVE_ARGS *cum,
666                             tree fntype ATTRIBUTE_UNUSED,
667                             rtx libname ATTRIBUTE_UNUSED)
668 {
669   memset (cum, 0, sizeof (CUMULATIVE_ARGS));
670 }
671
672 /* Implement FUNCTION_ARG_ADVANCE macro.  */
673 void
674 score_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
675                             tree type, int named)
676 {
677   struct score_arg_info info;
678   classify_arg (cum, mode, type, named, &info);
679   cum->num_gprs = info.reg_offset + info.reg_words;
680   if (info.stack_words > 0)
681     cum->stack_words = info.stack_offset + info.stack_words;
682   cum->arg_number++;
683 }
684
685 /* Implement TARGET_ARG_PARTIAL_BYTES macro.  */
686 static int
687 score_arg_partial_bytes (const CUMULATIVE_ARGS *cum,
688                          enum machine_mode mode, tree type, int named)
689 {
690   struct score_arg_info info;
691   classify_arg (cum, mode, type, named, &info);
692   return info.stack_words > 0 ? info.reg_words * UNITS_PER_WORD : 0;
693 }
694
695 /* Implement FUNCTION_ARG macro.  */
696 rtx
697 score_function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
698                     tree type, int named)
699 {
700   struct score_arg_info info;
701
702   if (mode == VOIDmode || !named)
703     return 0;
704
705   classify_arg (cum, mode, type, named, &info);
706
707   if (info.reg_offset == ARG_REG_NUM)
708     return 0;
709
710   if (!info.stack_words)
711     return gen_rtx_REG (mode, ARG_REG_FIRST + info.reg_offset);
712   else
713     {
714       rtx ret = gen_rtx_PARALLEL (mode, rtvec_alloc (info.reg_words));
715       unsigned int i, part_offset = 0;
716       for (i = 0; i < info.reg_words; i++)
717         {
718           rtx reg;
719           reg = gen_rtx_REG (SImode, ARG_REG_FIRST + info.reg_offset + i);
720           XVECEXP (ret, 0, i) = gen_rtx_EXPR_LIST (SImode, reg,
721                                                    GEN_INT (part_offset));
722           part_offset += UNITS_PER_WORD;
723         }
724       return ret;
725     }
726 }
727
728 /* Implement FUNCTION_VALUE and LIBCALL_VALUE.  For normal calls,
729    VALTYPE is the return type and MODE is VOIDmode.  For libcalls,
730    VALTYPE is null and MODE is the mode of the return value.  */
731 rtx
732 score_function_value (tree valtype, tree func ATTRIBUTE_UNUSED,
733                       enum machine_mode mode)
734 {
735   if (valtype)
736     {
737       int unsignedp;
738       mode = TYPE_MODE (valtype);
739       unsignedp = TYPE_UNSIGNED (valtype);
740       mode = promote_mode (valtype, mode, &unsignedp, 1);
741     }
742   return gen_rtx_REG (mode, RT_REGNUM);
743 }
744
745 /* Implement INITIALIZE_TRAMPOLINE macro.  */
746 void
747 score_initialize_trampoline (rtx ADDR, rtx FUNC, rtx CHAIN)
748 {
749 #define FFCACHE          "_flush_cache"
750 #define CODE_SIZE        (TRAMPOLINE_INSNS * UNITS_PER_WORD)
751
752   unsigned int tramp[TRAMPOLINE_INSNS] = {
753     0x8103bc56,                         /* mv      r8, r3          */
754     0x9000bc05,                         /* bl      0x0x8           */
755     0xc1238000 | (CODE_SIZE - 8),       /* lw      r9, &func       */
756     0xc0038000
757     | (STATIC_CHAIN_REGNUM << 21)
758     | (CODE_SIZE - 4),                  /* lw  static chain reg, &chain */
759     0x8068bc56,                         /* mv      r3, r8          */
760     0x8009bc08,                         /* br      r9              */
761     0x0,
762     0x0,
763     };
764   rtx pfunc, pchain;
765   int i;
766
767   for (i = 0; i < TRAMPOLINE_INSNS; i++)
768     emit_move_insn (gen_rtx_MEM (ptr_mode, plus_constant (ADDR, i << 2)),
769                     GEN_INT (tramp[i]));
770
771   pfunc = plus_constant (ADDR, CODE_SIZE);
772   pchain = plus_constant (ADDR, CODE_SIZE + GET_MODE_SIZE (ptr_mode));
773
774   emit_move_insn (gen_rtx_MEM (ptr_mode, pfunc), FUNC);
775   emit_move_insn (gen_rtx_MEM (ptr_mode, pchain), CHAIN);
776   emit_library_call (gen_rtx_SYMBOL_REF (Pmode, FFCACHE),
777                      0, VOIDmode, 2,
778                      ADDR, Pmode,
779                      GEN_INT (TRAMPOLINE_SIZE), SImode);
780 #undef FFCACHE
781 #undef CODE_SIZE
782 }
783
784 /* This function is used to implement REG_MODE_OK_FOR_BASE_P macro.  */
785 int
786 score_regno_mode_ok_for_base_p (int regno, int strict)
787 {
788   if (regno >= FIRST_PSEUDO_REGISTER)
789     {
790       if (!strict)
791         return 1;
792       regno = reg_renumber[regno];
793     }
794   if (regno == ARG_POINTER_REGNUM
795       || regno == FRAME_POINTER_REGNUM)
796     return 1;
797   return GP_REG_P (regno);
798 }
799
800 /* Implement GO_IF_LEGITIMATE_ADDRESS macro.  */
801 int
802 score_address_p (enum machine_mode mode, rtx x, int strict)
803 {
804   struct score_address_info addr;
805
806   return mda_classify_address (&addr, mode, x, strict);
807 }
808
809 /* Copy VALUE to a register and return that register.  If new psuedos
810    are allowed, copy it into a new register, otherwise use DEST.  */
811 static rtx
812 score_force_temporary (rtx dest, rtx value)
813 {
814   if (!no_new_pseudos)
815     return force_reg (Pmode, value);
816   else
817     {
818       emit_move_insn (copy_rtx (dest), value);
819       return dest;
820     }
821 }
822
823 /* Return a LO_SUM expression for ADDR.  TEMP is as for score_force_temporary
824    and is used to load the high part into a register.  */
825 static rtx
826 score_split_symbol (rtx temp, rtx addr)
827 {
828   rtx high = score_force_temporary (temp,
829                                     gen_rtx_HIGH (Pmode, copy_rtx (addr)));
830   return gen_rtx_LO_SUM (Pmode, high, addr);
831 }
832
833 /* This function is used to implement LEGITIMIZE_ADDRESS.  If *XLOC can
834    be legitimized in a way that the generic machinery might not expect,
835    put the new address in *XLOC and return true.  */
836 int
837 score_legitimize_address (rtx *xloc)
838 {
839   enum score_symbol_type symbol_type;
840
841   if (mda_symbolic_constant_p (*xloc, &symbol_type)
842       && symbol_type == SYMBOL_GENERAL)
843     {
844       *xloc = score_split_symbol (0, *xloc);
845       return 1;
846     }
847
848   if (GET_CODE (*xloc) == PLUS
849       && GET_CODE (XEXP (*xloc, 1)) == CONST_INT)
850     {
851       rtx reg = XEXP (*xloc, 0);
852       if (!mda_valid_base_register_p (reg, 0))
853         reg = copy_to_mode_reg (Pmode, reg);
854       *xloc = score_add_offset (NULL, reg, INTVAL (XEXP (*xloc, 1)));
855       return 1;
856     }
857   return 0;
858 }
859
860 /* Return a number assessing the cost of moving a register in class
861    FROM to class TO. */
862 int
863 score_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
864                           enum reg_class from, enum reg_class to)
865 {
866   if (GR_REG_CLASS_P (from))
867     {
868       if (GR_REG_CLASS_P (to))
869         return 2;
870       else if (SP_REG_CLASS_P (to))
871         return 4;
872       else if (CP_REG_CLASS_P (to))
873         return 5;
874       else if (CE_REG_CLASS_P (to))
875         return 6;
876     }
877   if (GR_REG_CLASS_P (to))
878     {
879       if (GR_REG_CLASS_P (from))
880         return 2;
881       else if (SP_REG_CLASS_P (from))
882         return 4;
883       else if (CP_REG_CLASS_P (from))
884         return 5;
885       else if (CE_REG_CLASS_P (from))
886         return 6;
887     }
888   return 12;
889 }
890
891 /* Return the number of instructions needed to load a symbol of the
892    given type into a register.  */
893 static int
894 score_symbol_insns (enum score_symbol_type type)
895 {
896   switch (type)
897     {
898     case SYMBOL_GENERAL:
899       return 2;
900
901     case SYMBOL_SMALL_DATA:
902       return 1;
903     }
904
905   gcc_unreachable ();
906 }
907
908 /* Return the number of instructions needed to load or store a value
909    of mode MODE at X.  Return 0 if X isn't valid for MODE.  */
910 static int
911 score_address_insns (rtx x, enum machine_mode mode)
912 {
913   struct score_address_info addr;
914   int factor;
915
916   if (mode == BLKmode)
917     /* BLKmode is used for single unaligned loads and stores.  */
918     factor = 1;
919   else
920     /* Each word of a multi-word value will be accessed individually.  */
921     factor = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
922
923   if (mda_classify_address (&addr, mode, x, false))
924     switch (addr.type)
925       {
926       case ADD_REG:
927       case ADD_CONST_INT:
928         return factor;
929
930       case ADD_SYMBOLIC:
931         return factor * score_symbol_insns (addr.symbol_type);
932       }
933   return 0;
934 }
935
936 /* Implement TARGET_RTX_COSTS macro.  */
937 static bool
938 score_rtx_costs (rtx x, int code, int outer_code, int *total)
939 {
940   enum machine_mode mode = GET_MODE (x);
941
942   switch (code)
943     {
944     case CONST_INT:
945       /* These can be used anywhere. */
946       *total = 0;
947       return true;
948
949       /* Otherwise fall through to the handling below because
950          we'll need to construct the constant.  */
951     case CONST:
952     case SYMBOL_REF:
953     case LABEL_REF:
954     case CONST_DOUBLE:
955       *total = COSTS_N_INSNS (1);
956       return true;
957
958     case MEM:
959       {
960         /* If the address is legitimate, return the number of
961            instructions it needs, otherwise use the default handling.  */
962         int n = score_address_insns (XEXP (x, 0), GET_MODE (x));
963         if (n > 0)
964           {
965             *total = COSTS_N_INSNS (n + 1);
966             return true;
967           }
968         return false;
969       }
970
971     case FFS:
972       *total = COSTS_N_INSNS (6);
973       return true;
974
975     case NOT:
976       *total = COSTS_N_INSNS (1);
977       return true;
978
979     case AND:
980     case IOR:
981     case XOR:
982       if (mode == DImode)
983         {
984           *total = COSTS_N_INSNS (2);
985           return true;
986         }
987       return false;
988
989     case ASHIFT:
990     case ASHIFTRT:
991     case LSHIFTRT:
992       if (mode == DImode)
993         {
994           *total = COSTS_N_INSNS ((GET_CODE (XEXP (x, 1)) == CONST_INT)
995                                   ? 4 : 12);
996           return true;
997         }
998       return false;
999
1000     case ABS:
1001       *total = COSTS_N_INSNS (4);
1002       return true;
1003
1004     case PLUS:
1005     case MINUS:
1006       if (mode == DImode)
1007         {
1008           *total = COSTS_N_INSNS (4);
1009           return true;
1010         }
1011       return false;
1012
1013     case NEG:
1014       if (mode == DImode)
1015         {
1016           *total = COSTS_N_INSNS (4);
1017           return true;
1018         }
1019       return false;
1020
1021     case MULT:
1022       *total = COSTS_N_INSNS (12);
1023       return true;
1024
1025     case DIV:
1026     case MOD:
1027     case UDIV:
1028     case UMOD:
1029       *total = COSTS_N_INSNS (33);
1030       return true;
1031
1032     case SIGN_EXTEND:
1033       *total = COSTS_N_INSNS (2);
1034       return true;
1035
1036     case ZERO_EXTEND:
1037       *total = COSTS_N_INSNS (1);
1038       return true;
1039
1040     default:
1041       return false;
1042     }
1043 }
1044
1045 /* Implement ASM_OUTPUT_EXTERNAL macro.  */
1046 int
1047 score_output_external (FILE *file ATTRIBUTE_UNUSED,
1048                        tree decl, const char *name)
1049 {
1050   register struct extern_list *p;
1051
1052   if (th_in_small_data_p (decl))
1053     {
1054       p = (struct extern_list *) ggc_alloc (sizeof (struct extern_list));
1055       p->next = extern_head;
1056       p->name = name;
1057       p->size = int_size_in_bytes (TREE_TYPE (decl));
1058       extern_head = p;
1059     }
1060   return 0;
1061 }
1062
1063 /* Output format asm string.  */
1064 void
1065 score_declare_object (FILE *stream, const char *name,
1066                       const char *directive, const char *fmt, ...)
1067 {
1068   va_list ap;
1069   fputs (directive, stream);
1070   assemble_name (stream, name);
1071   va_start (ap, fmt);
1072   vfprintf (stream, fmt, ap);
1073   va_end (ap);
1074 }
1075
1076 /* Implement RETURN_ADDR_RTX.  Note, we do not support moving
1077    back to a previous frame.  */
1078 rtx
1079 score_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
1080 {
1081   if (count != 0)
1082     return const0_rtx;
1083   return get_hard_reg_initial_val (Pmode, RA_REGNUM);
1084 }
1085
1086 /* Implement PRINT_OPERAND macro.  */
1087 /* Score-specific operand codes:
1088    '['        print .set nor1 directive
1089    ']'        print .set r1        directive
1090
1091    'U'        print hi part of a CONST_INT rtx
1092    'D'        print first part of const double
1093    'S'        selectively print '!' if operand is 15bit instruction accessible
1094    'V'        print "v!" if operand is 15bit instruction accessible, or
1095    "lfh!"
1096
1097    'L'        low  part of DImode reg operand
1098    'H'        high part of DImode reg operand
1099
1100    'C'  print part of opcode for a branch condition.  */
1101 void
1102 score_print_operand (FILE *file, rtx op, int c)
1103 {
1104   enum rtx_code code = -1;
1105   if (!PRINT_OPERAND_PUNCT_VALID_P (c))
1106     code = GET_CODE (op);
1107
1108   if (c == '[')
1109     {
1110       fprintf (file, ".set r1\n");
1111     }
1112   else if (c == ']')
1113     {
1114       fprintf (file, "\n\t.set nor1");
1115     }
1116   else if (c == 'U')
1117     {
1118       gcc_assert (code == CONST_INT);
1119       fprintf (file, HOST_WIDE_INT_PRINT_HEX,
1120                (unsigned HOST_WIDE_INT) INTVAL (op) >> 16);
1121     }
1122   else if (c == 'D')
1123     {
1124       if (GET_CODE (op) == CONST_DOUBLE)
1125         fprintf (file, HOST_WIDE_INT_PRINT_HEX,
1126                  TARGET_LITTLE_ENDIAN
1127                  ? CONST_DOUBLE_LOW (op) : CONST_DOUBLE_HIGH (op));
1128       else
1129         output_addr_const (file, op);
1130     }
1131   else if (c == 'S')
1132     {
1133       gcc_assert (code == REG);
1134       if (G16_REG_P (REGNO (op)))
1135         fprintf (file, "!");
1136     }
1137   else if (c == 'V')
1138     {
1139       gcc_assert (code == REG);
1140       fprintf (file, G16_REG_P (REGNO (op)) ? "v!" : "lfh!");
1141     }
1142   else if (code == REG)
1143     {
1144       int regnum = REGNO (op);
1145       if ((c == 'H' && !WORDS_BIG_ENDIAN)
1146           || (c == 'L' && WORDS_BIG_ENDIAN))
1147         regnum ++;
1148       fprintf (file, "%s", reg_names[regnum]);
1149     }
1150   else if (c == 'C')
1151     {
1152       switch (code)
1153         {
1154         case EQ: fputs ("eq", file); break;
1155         case NE: fputs ("ne", file); break;
1156         case GT: fputs ("gt", file); break;
1157         case GE: fputs ("ge", file); break;
1158         case LT: fputs ("lt", file); break;
1159         case LE: fputs ("le", file); break;
1160         case GTU: fputs ("gtu", file); break;
1161         case GEU: fputs ("cs", file); break;
1162         case LTU: fputs ("cc", file); break;
1163         case LEU: fputs ("leu", file); break;
1164         default:
1165           output_operand_lossage ("invalid operand for code: '%c'", code);
1166         }
1167     }
1168   else
1169     {
1170       switch (code)
1171         {
1172         case MEM:
1173           score_print_operand_address (file, op);
1174           break;
1175         default:
1176           output_addr_const (file, op);
1177         }
1178     }
1179 }
1180
1181 /* Implement PRINT_OPERAND_ADDRESS macro.  */
1182 void
1183 score_print_operand_address (FILE *file, rtx x)
1184 {
1185   struct score_address_info addr;
1186   enum rtx_code code = GET_CODE (x);
1187   enum machine_mode mode = GET_MODE (x);
1188
1189   if (code == MEM)
1190     x = XEXP (x, 0);
1191
1192   if (mda_classify_address (&addr, mode, x, true))
1193     {
1194       switch (addr.type)
1195         {
1196         case ADD_REG:
1197           {
1198             switch (addr.code)
1199               {
1200               case PRE_DEC:
1201                 fprintf (file, "[%s,-%ld]+", reg_names[REGNO (addr.reg)],
1202                          INTVAL (addr.offset));
1203                 break;
1204               case POST_DEC:
1205                 fprintf (file, "[%s]+,-%ld", reg_names[REGNO (addr.reg)],
1206                          INTVAL (addr.offset));
1207                 break;
1208               case PRE_INC:
1209                 fprintf (file, "[%s, %ld]+", reg_names[REGNO (addr.reg)],
1210                          INTVAL (addr.offset));
1211                 break;
1212               case POST_INC:
1213                 fprintf (file, "[%s]+, %ld", reg_names[REGNO (addr.reg)],
1214                          INTVAL (addr.offset));
1215                 break;
1216               default:
1217                 fprintf (file, "[%s,%ld]", reg_names[REGNO (addr.reg)],
1218                          INTVAL (addr.offset));
1219                 break;
1220               }
1221           }
1222           return;
1223         case ADD_CONST_INT:
1224         case ADD_SYMBOLIC:
1225           output_addr_const (file, x);
1226           return;
1227         }
1228     }
1229   print_rtl (stderr, x);
1230   gcc_unreachable ();
1231 }
1232
1233 struct gcc_target targetm = TARGET_INITIALIZER;