OSDN Git Service

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