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