OSDN Git Service

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