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