1a3aee5412f9b0a28a389a01b1dfcd8c41c6cdfc
[gcc.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 (const CUMULATIVE_ARGS *,
63 enum machine_mode, tree, int);
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_tree_hwi_hwi_tree_true
105
106 #undef TARGET_PROMOTE_FUNCTION_ARGS
107 #define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true
108
109 #undef TARGET_PROMOTE_FUNCTION_RETURN
110 #define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true
111
112 #undef TARGET_PROMOTE_PROTOTYPES
113 #define TARGET_PROMOTE_PROTOTYPES hook_bool_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 (tree type, 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, 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, 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 (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 (const CUMULATIVE_ARGS *cum,
689 enum machine_mode mode, tree type, int 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 (tree valtype, 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;