]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/config/score/score.c
Fix dupplicate declaration of ggc_realloc in gencondmd
[thirdparty/gcc.git] / gcc / config / score / score.c
1 /* Output routines for Sunplus S+CORE processor
2 Copyright (C) 2005-2014 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 "rtl.h"
26 #include "regs.h"
27 #include "hard-reg-set.h"
28 #include "insn-config.h"
29 #include "conditions.h"
30 #include "insn-attr.h"
31 #include "recog.h"
32 #include "diagnostic-core.h"
33 #include "output.h"
34 #include "tree.h"
35 #include "stringpool.h"
36 #include "calls.h"
37 #include "varasm.h"
38 #include "stor-layout.h"
39 #include "function.h"
40 #include "expr.h"
41 #include "optabs.h"
42 #include "flags.h"
43 #include "reload.h"
44 #include "tm_p.h"
45 #include "ggc.h"
46 #include "gstab.h"
47 #include "hashtab.h"
48 #include "debug.h"
49 #include "target.h"
50 #include "target-def.h"
51 #include "langhooks.h"
52 #include "df.h"
53 #include "opts.h"
54 #include "builtins.h"
55
56 #define SCORE_SDATA_MAX score_sdata_max
57 #define SCORE_STACK_ALIGN(LOC) (((LOC) + 3) & ~3)
58 #define SCORE_PROLOGUE_TEMP_REGNUM (GP_REG_FIRST + 8)
59 #define SCORE_EPILOGUE_TEMP_REGNUM (GP_REG_FIRST + 8)
60 #define SCORE_DEFAULT_SDATA_MAX 8
61
62 #define BITSET_P(VALUE, BIT) (((VALUE) & (1L << (BIT))) != 0)
63 #define INS_BUF_SZ 128
64
65 enum score_address_type
66 {
67 SCORE_ADD_REG,
68 SCORE_ADD_CONST_INT,
69 SCORE_ADD_SYMBOLIC
70 };
71
72 struct score_frame_info
73 {
74 HOST_WIDE_INT total_size; /* bytes that the entire frame takes up */
75 HOST_WIDE_INT var_size; /* bytes that variables take up */
76 HOST_WIDE_INT args_size; /* bytes that outgoing arguments take up */
77 HOST_WIDE_INT gp_reg_size; /* bytes needed to store gp regs */
78 HOST_WIDE_INT gp_sp_offset; /* offset from new sp to store gp registers */
79 HOST_WIDE_INT cprestore_size; /* # bytes that the .cprestore slot takes up */
80 unsigned int mask; /* mask of saved gp registers */
81 int num_gp; /* number of gp registers saved */
82 };
83
84 struct score_arg_info
85 {
86 unsigned int num_bytes; /* The argument's size in bytes */
87 unsigned int reg_words; /* The number of words passed in registers */
88 unsigned int reg_offset; /* The offset of the first register from */
89 /* GP_ARG_FIRST or FP_ARG_FIRST etc */
90 unsigned int stack_words; /* The number of words that must be passed */
91 /* on the stack */
92 unsigned int stack_offset; /* The offset from the start of the stack */
93 /* overflow area */
94 };
95
96 #ifdef RTX_CODE
97 struct score_address_info
98 {
99 enum score_address_type type;
100 rtx reg;
101 rtx offset;
102 enum rtx_code code;
103 enum score_symbol_type symbol_type;
104 };
105 #endif
106
107 static int score_sdata_max;
108 static char score_ins[INS_BUF_SZ + 8];
109
110 struct extern_list *extern_head = 0;
111
112 #undef TARGET_ASM_FILE_START
113 #define TARGET_ASM_FILE_START score_asm_file_start
114
115 #undef TARGET_ASM_FILE_END
116 #define TARGET_ASM_FILE_END score_asm_file_end
117
118 #undef TARGET_ASM_FUNCTION_PROLOGUE
119 #define TARGET_ASM_FUNCTION_PROLOGUE score_function_prologue
120
121 #undef TARGET_ASM_FUNCTION_EPILOGUE
122 #define TARGET_ASM_FUNCTION_EPILOGUE score_function_epilogue
123
124 #undef TARGET_OPTION_OVERRIDE
125 #define TARGET_OPTION_OVERRIDE score_option_override
126
127 #undef TARGET_SCHED_ISSUE_RATE
128 #define TARGET_SCHED_ISSUE_RATE score_issue_rate
129
130 #undef TARGET_ASM_SELECT_RTX_SECTION
131 #define TARGET_ASM_SELECT_RTX_SECTION score_select_rtx_section
132
133 #undef TARGET_IN_SMALL_DATA_P
134 #define TARGET_IN_SMALL_DATA_P score_in_small_data_p
135
136 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
137 #define TARGET_FUNCTION_OK_FOR_SIBCALL score_function_ok_for_sibcall
138
139 #undef TARGET_STRICT_ARGUMENT_NAMING
140 #define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true
141
142 #undef TARGET_ASM_OUTPUT_MI_THUNK
143 #define TARGET_ASM_OUTPUT_MI_THUNK score_output_mi_thunk
144
145 #undef TARGET_PROMOTE_FUNCTION_MODE
146 #define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
147
148 #undef TARGET_PROMOTE_PROTOTYPES
149 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
150
151 #undef TARGET_MUST_PASS_IN_STACK
152 #define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size
153
154 #undef TARGET_ARG_PARTIAL_BYTES
155 #define TARGET_ARG_PARTIAL_BYTES score_arg_partial_bytes
156
157 #undef TARGET_FUNCTION_ARG
158 #define TARGET_FUNCTION_ARG score_function_arg
159
160 #undef TARGET_FUNCTION_ARG_ADVANCE
161 #define TARGET_FUNCTION_ARG_ADVANCE score_function_arg_advance
162
163 #undef TARGET_PASS_BY_REFERENCE
164 #define TARGET_PASS_BY_REFERENCE score_pass_by_reference
165
166 #undef TARGET_RETURN_IN_MEMORY
167 #define TARGET_RETURN_IN_MEMORY score_return_in_memory
168
169 #undef TARGET_RTX_COSTS
170 #define TARGET_RTX_COSTS score_rtx_costs
171
172 #undef TARGET_ADDRESS_COST
173 #define TARGET_ADDRESS_COST score_address_cost
174
175 #undef TARGET_LEGITIMATE_ADDRESS_P
176 #define TARGET_LEGITIMATE_ADDRESS_P score_legitimate_address_p
177
178 #undef TARGET_CAN_ELIMINATE
179 #define TARGET_CAN_ELIMINATE score_can_eliminate
180
181 #undef TARGET_CONDITIONAL_REGISTER_USAGE
182 #define TARGET_CONDITIONAL_REGISTER_USAGE score_conditional_register_usage
183
184 #undef TARGET_ASM_TRAMPOLINE_TEMPLATE
185 #define TARGET_ASM_TRAMPOLINE_TEMPLATE score_asm_trampoline_template
186 #undef TARGET_TRAMPOLINE_INIT
187 #define TARGET_TRAMPOLINE_INIT score_trampoline_init
188
189 #undef TARGET_REGISTER_MOVE_COST
190 #define TARGET_REGISTER_MOVE_COST score_register_move_cost
191
192 /* Return true if SYMBOL is a SYMBOL_REF and OFFSET + SYMBOL points
193 to the same object as SYMBOL. */
194 static int
195 score_offset_within_object_p (rtx symbol, HOST_WIDE_INT offset)
196 {
197 if (GET_CODE (symbol) != SYMBOL_REF)
198 return 0;
199
200 if (CONSTANT_POOL_ADDRESS_P (symbol)
201 && offset >= 0
202 && offset < (int)GET_MODE_SIZE (get_pool_mode (symbol)))
203 return 1;
204
205 if (SYMBOL_REF_DECL (symbol) != 0
206 && offset >= 0
207 && offset < int_size_in_bytes (TREE_TYPE (SYMBOL_REF_DECL (symbol))))
208 return 1;
209
210 return 0;
211 }
212
213 /* Split X into a base and a constant offset, storing them in *BASE
214 and *OFFSET respectively. */
215 static void
216 score_split_const (rtx x, rtx *base, HOST_WIDE_INT *offset)
217 {
218 *offset = 0;
219
220 if (GET_CODE (x) == CONST)
221 x = XEXP (x, 0);
222
223 if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
224 {
225 *offset += INTVAL (XEXP (x, 1));
226 x = XEXP (x, 0);
227 }
228
229 *base = x;
230 }
231
232 /* Classify symbol X, which must be a SYMBOL_REF or a LABEL_REF. */
233 static enum score_symbol_type
234 score_classify_symbol (rtx x)
235 {
236 if (GET_CODE (x) == LABEL_REF)
237 return SYMBOL_GENERAL;
238
239 gcc_assert (GET_CODE (x) == SYMBOL_REF);
240
241 if (CONSTANT_POOL_ADDRESS_P (x))
242 {
243 if (GET_MODE_SIZE (get_pool_mode (x)) <= SCORE_SDATA_MAX)
244 return SYMBOL_SMALL_DATA;
245 return SYMBOL_GENERAL;
246 }
247 if (SYMBOL_REF_SMALL_P (x))
248 return SYMBOL_SMALL_DATA;
249 return SYMBOL_GENERAL;
250 }
251
252 /* Return true if the current function must save REGNO. */
253 static int
254 score_save_reg_p (unsigned int regno)
255 {
256 /* Check call-saved registers. */
257 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
258 return 1;
259
260 /* We need to save the old frame pointer before setting up a new one. */
261 if (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed)
262 return 1;
263
264 /* We need to save the incoming return address if it is ever clobbered
265 within the function. */
266 if (regno == RA_REGNUM && df_regs_ever_live_p (regno))
267 return 1;
268
269 return 0;
270 }
271
272 /* Return one word of double-word value OP, taking into account the fixed
273 endianness of certain registers. HIGH_P is true to select the high part,
274 false to select the low part. */
275 static rtx
276 score_subw (rtx op, int high_p)
277 {
278 unsigned int byte;
279 enum machine_mode mode = GET_MODE (op);
280
281 if (mode == VOIDmode)
282 mode = DImode;
283
284 byte = (TARGET_LITTLE_ENDIAN ? high_p : !high_p) ? UNITS_PER_WORD : 0;
285
286 if (GET_CODE (op) == REG && REGNO (op) == HI_REGNUM)
287 return gen_rtx_REG (SImode, high_p ? HI_REGNUM : LO_REGNUM);
288
289 if (GET_CODE (op) == MEM)
290 return adjust_address (op, SImode, byte);
291
292 return simplify_gen_subreg (SImode, op, mode, byte);
293 }
294
295 static struct score_frame_info *
296 score_cached_frame (void)
297 {
298 static struct score_frame_info _frame_info;
299 return &_frame_info;
300 }
301
302 /* Return the bytes needed to compute the frame pointer from the current
303 stack pointer. SIZE is the size (in bytes) of the local variables. */
304 static struct score_frame_info *
305 score_compute_frame_size (HOST_WIDE_INT size)
306 {
307 unsigned int regno;
308 struct score_frame_info *f = score_cached_frame ();
309
310 memset (f, 0, sizeof (struct score_frame_info));
311 f->gp_reg_size = 0;
312 f->mask = 0;
313 f->var_size = SCORE_STACK_ALIGN (size);
314 f->args_size = crtl->outgoing_args_size;
315 f->cprestore_size = flag_pic ? UNITS_PER_WORD : 0;
316 if (f->var_size == 0 && crtl->is_leaf)
317 f->args_size = f->cprestore_size = 0;
318
319 if (f->args_size == 0 && cfun->calls_alloca)
320 f->args_size = UNITS_PER_WORD;
321
322 f->total_size = f->var_size + f->args_size + f->cprestore_size;
323 for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
324 {
325 if (score_save_reg_p (regno))
326 {
327 f->gp_reg_size += GET_MODE_SIZE (SImode);
328 f->mask |= 1 << (regno - GP_REG_FIRST);
329 }
330 }
331
332 if (crtl->calls_eh_return)
333 {
334 unsigned int i;
335 for (i = 0;; ++i)
336 {
337 regno = EH_RETURN_DATA_REGNO (i);
338 if (regno == INVALID_REGNUM)
339 break;
340 f->gp_reg_size += GET_MODE_SIZE (SImode);
341 f->mask |= 1 << (regno - GP_REG_FIRST);
342 }
343 }
344
345 f->total_size += f->gp_reg_size;
346 f->num_gp = f->gp_reg_size / UNITS_PER_WORD;
347
348 if (f->mask)
349 {
350 HOST_WIDE_INT offset;
351 offset = (f->args_size + f->cprestore_size + f->var_size
352 + f->gp_reg_size - GET_MODE_SIZE (SImode));
353 f->gp_sp_offset = offset;
354 }
355 else
356 f->gp_sp_offset = 0;
357
358 return f;
359 }
360
361 /* Return true if X is a valid base register for the given mode.
362 Allow only hard registers if STRICT. */
363 static int
364 score_valid_base_register_p (rtx x, int strict)
365 {
366 if (!strict && GET_CODE (x) == SUBREG)
367 x = SUBREG_REG (x);
368
369 return (GET_CODE (x) == REG
370 && score_regno_mode_ok_for_base_p (REGNO (x), strict));
371 }
372
373 /* Return true if X is a valid address for machine mode MODE. If it is,
374 fill in INFO appropriately. STRICT is true if we should only accept
375 hard base registers. */
376 static int
377 score_classify_address (struct score_address_info *info,
378 enum machine_mode mode, rtx x, int strict)
379 {
380 info->code = GET_CODE (x);
381
382 switch (info->code)
383 {
384 case REG:
385 case SUBREG:
386 info->type = SCORE_ADD_REG;
387 info->reg = x;
388 info->offset = const0_rtx;
389 return score_valid_base_register_p (info->reg, strict);
390 case PLUS:
391 info->type = SCORE_ADD_REG;
392 info->reg = XEXP (x, 0);
393 info->offset = XEXP (x, 1);
394 return (score_valid_base_register_p (info->reg, strict)
395 && GET_CODE (info->offset) == CONST_INT
396 && IMM_IN_RANGE (INTVAL (info->offset), 15, 1));
397 case PRE_DEC:
398 case POST_DEC:
399 case PRE_INC:
400 case POST_INC:
401 if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (SImode))
402 return false;
403 info->type = SCORE_ADD_REG;
404 info->reg = XEXP (x, 0);
405 info->offset = GEN_INT (GET_MODE_SIZE (mode));
406 return score_valid_base_register_p (info->reg, strict);
407 case CONST_INT:
408 info->type = SCORE_ADD_CONST_INT;
409 return IMM_IN_RANGE (INTVAL (x), 15, 1);
410 case CONST:
411 case LABEL_REF:
412 case SYMBOL_REF:
413 info->type = SCORE_ADD_SYMBOLIC;
414 return (score_symbolic_constant_p (x, &info->symbol_type)
415 && (info->symbol_type == SYMBOL_GENERAL
416 || info->symbol_type == SYMBOL_SMALL_DATA));
417 default:
418 return 0;
419 }
420 }
421
422 /* Implement TARGET_RETURN_IN_MEMORY. In S+core,
423 small structures are returned in a register.
424 Objects with varying size must still be returned in memory. */
425 static bool
426 score_return_in_memory (const_tree type, const_tree fndecl ATTRIBUTE_UNUSED)
427 {
428 return ((TYPE_MODE (type) == BLKmode)
429 || (int_size_in_bytes (type) > 2 * UNITS_PER_WORD)
430 || (int_size_in_bytes (type) == -1));
431 }
432
433 /* Return a legitimate address for REG + OFFSET. */
434 static rtx
435 score_add_offset (rtx reg, HOST_WIDE_INT offset)
436 {
437 if (!IMM_IN_RANGE (offset, 15, 1))
438 {
439 reg = expand_simple_binop (GET_MODE (reg), PLUS,
440 gen_int_mode (offset & 0xffffc000,
441 GET_MODE (reg)),
442 reg, NULL, 0, OPTAB_WIDEN);
443 offset &= 0x3fff;
444 }
445
446 return plus_constant (GET_MODE (reg), reg, offset);
447 }
448
449 /* Implement TARGET_ASM_OUTPUT_MI_THUNK. Generate rtl rather than asm text
450 in order to avoid duplicating too much logic from elsewhere. */
451 static void
452 score_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
453 HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
454 tree function)
455 {
456 rtx this_rtx, temp1, fnaddr;
457 rtx_insn *insn;
458
459 /* Pretend to be a post-reload pass while generating rtl. */
460 reload_completed = 1;
461
462 /* Mark the end of the (empty) prologue. */
463 emit_note (NOTE_INSN_PROLOGUE_END);
464
465 /* We need two temporary registers in some cases. */
466 temp1 = gen_rtx_REG (Pmode, 8);
467
468 /* Find out which register contains the "this" pointer. */
469 if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
470 this_rtx = gen_rtx_REG (Pmode, ARG_REG_FIRST + 1);
471 else
472 this_rtx = gen_rtx_REG (Pmode, ARG_REG_FIRST);
473
474 /* Add DELTA to THIS_RTX. */
475 if (delta != 0)
476 {
477 rtx offset = GEN_INT (delta);
478 if (!(delta >= -32768 && delta <= 32767))
479 {
480 emit_move_insn (temp1, offset);
481 offset = temp1;
482 }
483 emit_insn (gen_add3_insn (this_rtx, this_rtx, offset));
484 }
485
486 /* If needed, add *(*THIS_RTX + VCALL_OFFSET) to THIS_RTX. */
487 if (vcall_offset != 0)
488 {
489 rtx addr;
490
491 /* Set TEMP1 to *THIS_RTX. */
492 emit_move_insn (temp1, gen_rtx_MEM (Pmode, this_rtx));
493
494 /* Set ADDR to a legitimate address for *THIS_RTX + VCALL_OFFSET. */
495 addr = score_add_offset (temp1, vcall_offset);
496
497 /* Load the offset and add it to THIS_RTX. */
498 emit_move_insn (temp1, gen_rtx_MEM (Pmode, addr));
499 emit_insn (gen_add3_insn (this_rtx, this_rtx, temp1));
500 }
501
502 /* Jump to the target function. */
503 fnaddr = XEXP (DECL_RTL (function), 0);
504 insn = emit_call_insn (gen_sibcall_internal_score7 (fnaddr, const0_rtx));
505 SIBLING_CALL_P (insn) = 1;
506
507 /* Run just enough of rest_of_compilation. This sequence was
508 "borrowed" from alpha.c. */
509 insn = get_insns ();
510 split_all_insns_noflow ();
511 shorten_branches (insn);
512 final_start_function (insn, file, 1);
513 final (insn, file, 1);
514 final_end_function ();
515
516 /* Clean up the vars set above. Note that final_end_function resets
517 the global pointer for us. */
518 reload_completed = 0;
519 }
520
521 /* Fill INFO with information about a single argument. CUM is the
522 cumulative state for earlier arguments. MODE is the mode of this
523 argument and TYPE is its type (if known). NAMED is true if this
524 is a named (fixed) argument rather than a variable one. */
525 static void
526 score_classify_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
527 const_tree type, bool named, struct score_arg_info *info)
528 {
529 int even_reg_p;
530 unsigned int num_words, max_regs;
531
532 even_reg_p = 0;
533 if (GET_MODE_CLASS (mode) == MODE_INT
534 || GET_MODE_CLASS (mode) == MODE_FLOAT)
535 even_reg_p = (GET_MODE_SIZE (mode) > UNITS_PER_WORD);
536 else
537 if (type != NULL_TREE && TYPE_ALIGN (type) > BITS_PER_WORD && named)
538 even_reg_p = 1;
539
540 if (TARGET_MUST_PASS_IN_STACK (mode, type))
541 info->reg_offset = ARG_REG_NUM;
542 else
543 {
544 info->reg_offset = cum->num_gprs;
545 if (even_reg_p)
546 info->reg_offset += info->reg_offset & 1;
547 }
548
549 if (mode == BLKmode)
550 info->num_bytes = int_size_in_bytes (type);
551 else
552 info->num_bytes = GET_MODE_SIZE (mode);
553
554 num_words = (info->num_bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
555 max_regs = ARG_REG_NUM - info->reg_offset;
556
557 /* Partition the argument between registers and stack. */
558 info->reg_words = MIN (num_words, max_regs);
559 info->stack_words = num_words - info->reg_words;
560
561 /* The alignment applied to registers is also applied to stack arguments. */
562 if (info->stack_words)
563 {
564 info->stack_offset = cum->stack_words;
565 if (even_reg_p)
566 info->stack_offset += info->stack_offset & 1;
567 }
568 }
569
570 /* Set up the stack and frame (if desired) for the function. */
571 static void
572 score_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
573 {
574 const char *fnname;
575 struct score_frame_info *f = score_cached_frame ();
576 HOST_WIDE_INT tsize = f->total_size;
577
578 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
579 if (!flag_inhibit_size_directive)
580 {
581 fputs ("\t.ent\t", file);
582 assemble_name (file, fnname);
583 fputs ("\n", file);
584 }
585 assemble_name (file, fnname);
586 fputs (":\n", file);
587
588 if (!flag_inhibit_size_directive)
589 {
590 fprintf (file,
591 "\t.frame\t%s," HOST_WIDE_INT_PRINT_DEC ",%s, %d\t\t"
592 "# vars= " HOST_WIDE_INT_PRINT_DEC ", regs= %d"
593 ", args= " HOST_WIDE_INT_PRINT_DEC
594 ", gp= " HOST_WIDE_INT_PRINT_DEC "\n",
595 (reg_names[(frame_pointer_needed)
596 ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM]),
597 tsize,
598 reg_names[RA_REGNUM],
599 crtl->is_leaf ? 1 : 0,
600 f->var_size,
601 f->num_gp,
602 f->args_size,
603 f->cprestore_size);
604
605 fprintf(file, "\t.mask\t0x%08x," HOST_WIDE_INT_PRINT_DEC "\n",
606 f->mask,
607 (f->gp_sp_offset - f->total_size));
608 }
609 }
610
611 /* Do any necessary cleanup after a function to restore stack, frame,
612 and regs. */
613 static void
614 score_function_epilogue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
615 {
616 if (!flag_inhibit_size_directive)
617 {
618 const char *fnname;
619 fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
620 fputs ("\t.end\t", file);
621 assemble_name (file, fnname);
622 fputs ("\n", file);
623 }
624 }
625
626 /* Returns true if X contains a SYMBOL_REF. */
627 static bool
628 score_symbolic_expression_p (rtx x)
629 {
630 if (GET_CODE (x) == SYMBOL_REF)
631 return true;
632
633 if (GET_CODE (x) == CONST)
634 return score_symbolic_expression_p (XEXP (x, 0));
635
636 if (UNARY_P (x))
637 return score_symbolic_expression_p (XEXP (x, 0));
638
639 if (ARITHMETIC_P (x))
640 return (score_symbolic_expression_p (XEXP (x, 0))
641 || score_symbolic_expression_p (XEXP (x, 1)));
642
643 return false;
644 }
645
646 /* Choose the section to use for the constant rtx expression X that has
647 mode MODE. */
648 static section *
649 score_select_rtx_section (enum machine_mode mode, rtx x, unsigned HOST_WIDE_INT align)
650 {
651 if (GET_MODE_SIZE (mode) <= SCORE_SDATA_MAX)
652 return get_named_section (0, ".sdata", 0);
653 else if (flag_pic && score_symbolic_expression_p (x))
654 return get_named_section (0, ".data.rel.ro", 3);
655 else
656 return mergeable_constant_section (mode, align, 0);
657 }
658
659 /* Implement TARGET_IN_SMALL_DATA_P. */
660 static bool
661 score_in_small_data_p (const_tree decl)
662 {
663 HOST_WIDE_INT size;
664
665 if (TREE_CODE (decl) == STRING_CST
666 || TREE_CODE (decl) == FUNCTION_DECL)
667 return false;
668
669 if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl) != 0)
670 {
671 const char *name;
672 name = DECL_SECTION_NAME (decl);
673 if (strcmp (name, ".sdata") != 0
674 && strcmp (name, ".sbss") != 0)
675 return true;
676 if (!DECL_EXTERNAL (decl))
677 return false;
678 }
679 size = int_size_in_bytes (TREE_TYPE (decl));
680 return (size > 0 && size <= SCORE_SDATA_MAX);
681 }
682
683 /* Implement TARGET_ASM_FILE_START. */
684 static void
685 score_asm_file_start (void)
686 {
687 default_file_start ();
688 fprintf (asm_out_file, ASM_COMMENT_START
689 "GCC for S+core %s \n", SCORE_GCC_VERSION);
690
691 if (flag_pic)
692 fprintf (asm_out_file, "\t.set pic\n");
693 }
694
695 /* Implement TARGET_ASM_FILE_END. When using assembler macros, emit
696 .externs for any small-data variables that turned out to be external. */
697 static void
698 score_asm_file_end (void)
699 {
700 tree name_tree;
701 struct extern_list *p;
702 if (extern_head)
703 {
704 fputs ("\n", asm_out_file);
705 for (p = extern_head; p != 0; p = p->next)
706 {
707 name_tree = get_identifier (p->name);
708 if (!TREE_ASM_WRITTEN (name_tree)
709 && TREE_SYMBOL_REFERENCED (name_tree))
710 {
711 TREE_ASM_WRITTEN (name_tree) = 1;
712 fputs ("\t.extern\t", asm_out_file);
713 assemble_name (asm_out_file, p->name);
714 fprintf (asm_out_file, ", %d\n", p->size);
715 }
716 }
717 }
718 }
719
720 /* Implement TARGET_OPTION_OVERRIDE hook. */
721 static void
722 score_option_override (void)
723 {
724 flag_pic = false;
725 score_sdata_max = SCORE_DEFAULT_SDATA_MAX;
726
727 }
728
729 /* Implement REGNO_REG_CLASS macro. */
730 int
731 score_reg_class (int regno)
732 {
733 int c;
734 gcc_assert (regno >= 0 && regno < FIRST_PSEUDO_REGISTER);
735
736 if (regno == FRAME_POINTER_REGNUM
737 || regno == ARG_POINTER_REGNUM)
738 return ALL_REGS;
739
740 for (c = 0; c < N_REG_CLASSES; c++)
741 if (TEST_HARD_REG_BIT (reg_class_contents[c], regno))
742 return c;
743
744 return NO_REGS;
745 }
746
747 /* Implement PREFERRED_RELOAD_CLASS macro. */
748 enum reg_class
749 score_preferred_reload_class (rtx x ATTRIBUTE_UNUSED, enum reg_class rclass)
750 {
751 if (reg_class_subset_p (G16_REGS, rclass))
752 return G16_REGS;
753 if (reg_class_subset_p (G32_REGS, rclass))
754 return G32_REGS;
755 return rclass;
756 }
757
758 /* Implement SECONDARY_INPUT_RELOAD_CLASS
759 and SECONDARY_OUTPUT_RELOAD_CLASS macro. */
760 enum reg_class
761 score_secondary_reload_class (enum reg_class rclass,
762 enum machine_mode mode ATTRIBUTE_UNUSED,
763 rtx x)
764 {
765 int regno = -1;
766 if (GET_CODE (x) == REG || GET_CODE(x) == SUBREG)
767 regno = true_regnum (x);
768
769 if (!GR_REG_CLASS_P (rclass))
770 return GP_REG_P (regno) ? NO_REGS : G32_REGS;
771 return NO_REGS;
772 }
773
774
775 /* Return truth value on whether or not a given hard register
776 can support a given mode. */
777 int
778 score_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
779 {
780 int size = GET_MODE_SIZE (mode);
781 enum mode_class mclass = GET_MODE_CLASS (mode);
782
783 if (mclass == MODE_CC)
784 return regno == CC_REGNUM;
785 else if (regno == FRAME_POINTER_REGNUM
786 || regno == ARG_POINTER_REGNUM)
787 return mclass == MODE_INT;
788 else if (GP_REG_P (regno))
789 /* ((regno <= (GP_REG_LAST- HARD_REGNO_NREGS (dummy, mode)) + 1) */
790 return !(regno & 1) || (size <= UNITS_PER_WORD);
791 else if (CE_REG_P (regno))
792 return (mclass == MODE_INT
793 && ((size <= UNITS_PER_WORD)
794 || (regno == CE_REG_FIRST && size == 2 * UNITS_PER_WORD)));
795 else
796 return (mclass == MODE_INT) && (size <= UNITS_PER_WORD);
797 }
798
799 /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
800 pointer or argument pointer. TO is either the stack pointer or
801 hard frame pointer. */
802 HOST_WIDE_INT
803 score_initial_elimination_offset (int from,
804 int to ATTRIBUTE_UNUSED)
805 {
806 struct score_frame_info *f = score_compute_frame_size (get_frame_size ());
807 switch (from)
808 {
809 case ARG_POINTER_REGNUM:
810 return f->total_size;
811 case FRAME_POINTER_REGNUM:
812 return 0;
813 default:
814 gcc_unreachable ();
815 }
816 }
817
818 /* Implement TARGET_FUNCTION_ARG_ADVANCE hook. */
819 static void
820 score_function_arg_advance (cumulative_args_t cum_args, enum machine_mode mode,
821 const_tree type, bool named)
822 {
823 struct score_arg_info info;
824 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_args);
825 score_classify_arg (cum, mode, type, named, &info);
826 cum->num_gprs = info.reg_offset + info.reg_words;
827 if (info.stack_words > 0)
828 cum->stack_words = info.stack_offset + info.stack_words;
829 cum->arg_number++;
830 }
831
832 /* Implement TARGET_ARG_PARTIAL_BYTES macro. */
833 int
834 score_arg_partial_bytes (cumulative_args_t cum_args,
835 enum machine_mode mode, tree type, bool named)
836 {
837 struct score_arg_info info;
838 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_args);
839 score_classify_arg (cum, mode, type, named, &info);
840 return info.stack_words > 0 ? info.reg_words * UNITS_PER_WORD : 0;
841 }
842
843 /* Implement TARGET_FUNCTION_ARG hook. */
844 static rtx
845 score_function_arg (cumulative_args_t cum_args, enum machine_mode mode,
846 const_tree type, bool named)
847 {
848 struct score_arg_info info;
849 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_args);
850
851 if (mode == VOIDmode || !named)
852 return 0;
853
854 score_classify_arg (cum, mode, type, named, &info);
855
856 if (info.reg_offset == ARG_REG_NUM)
857 return 0;
858
859 if (!info.stack_words)
860 return gen_rtx_REG (mode, ARG_REG_FIRST + info.reg_offset);
861 else
862 {
863 rtx ret = gen_rtx_PARALLEL (mode, rtvec_alloc (info.reg_words));
864 unsigned int i, part_offset = 0;
865 for (i = 0; i < info.reg_words; i++)
866 {
867 rtx reg;
868 reg = gen_rtx_REG (SImode, ARG_REG_FIRST + info.reg_offset + i);
869 XVECEXP (ret, 0, i) = gen_rtx_EXPR_LIST (SImode, reg,
870 GEN_INT (part_offset));
871 part_offset += UNITS_PER_WORD;
872 }
873 return ret;
874 }
875 }
876
877 /* Implement FUNCTION_VALUE and LIBCALL_VALUE. For normal calls,
878 VALTYPE is the return type and MODE is VOIDmode. For libcalls,
879 VALTYPE is null and MODE is the mode of the return value. */
880 rtx
881 score_function_value (const_tree valtype, const_tree func, enum machine_mode mode)
882 {
883 if (valtype)
884 {
885 int unsignedp;
886 mode = TYPE_MODE (valtype);
887 unsignedp = TYPE_UNSIGNED (valtype);
888 mode = promote_function_mode (valtype, mode, &unsignedp, func, 1);
889 }
890 return gen_rtx_REG (mode, RT_REGNUM);
891 }
892
893 /* Implement TARGET_ASM_TRAMPOLINE_TEMPLATE. */
894
895 static void
896 score_asm_trampoline_template (FILE *f)
897 {
898 fprintf (f, "\t.set r1\n");
899 fprintf (f, "\tmv r31, r3\n");
900 fprintf (f, "\tbl nextinsn\n");
901 fprintf (f, "nextinsn:\n");
902 fprintf (f, "\tlw r1, [r3, 6*4-8]\n");
903 fprintf (f, "\tlw r23, [r3, 6*4-4]\n");
904 fprintf (f, "\tmv r3, r31\n");
905 fprintf (f, "\tbr! r1\n");
906 fprintf (f, "\tnop!\n");
907 fprintf (f, "\t.set nor1\n");
908 }
909
910 /* Implement TARGET_TRAMPOLINE_INIT. */
911 static void
912 score_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
913 {
914 #define CODE_SIZE (TRAMPOLINE_INSNS * UNITS_PER_WORD)
915
916 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
917 rtx mem;
918
919 emit_block_move (m_tramp, assemble_trampoline_template (),
920 GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
921
922 mem = adjust_address (m_tramp, SImode, CODE_SIZE);
923 emit_move_insn (mem, fnaddr);
924 mem = adjust_address (m_tramp, SImode, CODE_SIZE + GET_MODE_SIZE (SImode));
925 emit_move_insn (mem, chain_value);
926
927 #undef CODE_SIZE
928 }
929
930 /* This function is used to implement REG_MODE_OK_FOR_BASE_P macro. */
931 int
932 score_regno_mode_ok_for_base_p (int regno, int strict)
933 {
934 if (regno >= FIRST_PSEUDO_REGISTER)
935 {
936 if (!strict)
937 return 1;
938 regno = reg_renumber[regno];
939 }
940 if (regno == ARG_POINTER_REGNUM
941 || regno == FRAME_POINTER_REGNUM)
942 return 1;
943 return GP_REG_P (regno);
944 }
945
946 /* Implement TARGET_LEGITIMATE_ADDRESS_P macro. */
947 static bool
948 score_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
949 {
950 struct score_address_info addr;
951
952 return score_classify_address (&addr, mode, x, strict);
953 }
954
955 /* Implement TARGET_REGISTER_MOVE_COST.
956
957 Return a number assessing the cost of moving a register in class
958 FROM to class TO. */
959 static int
960 score_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
961 reg_class_t from, reg_class_t to)
962 {
963 if (GR_REG_CLASS_P (from))
964 {
965 if (GR_REG_CLASS_P (to))
966 return 2;
967 else if (SP_REG_CLASS_P (to))
968 return 4;
969 else if (CP_REG_CLASS_P (to))
970 return 5;
971 else if (CE_REG_CLASS_P (to))
972 return 6;
973 }
974 if (GR_REG_CLASS_P (to))
975 {
976 if (GR_REG_CLASS_P (from))
977 return 2;
978 else if (SP_REG_CLASS_P (from))
979 return 4;
980 else if (CP_REG_CLASS_P (from))
981 return 5;
982 else if (CE_REG_CLASS_P (from))
983 return 6;
984 }
985 return 12;
986 }
987
988 /* Return the number of instructions needed to load a symbol of the
989 given type into a register. */
990 static int
991 score_symbol_insns (enum score_symbol_type type)
992 {
993 switch (type)
994 {
995 case SYMBOL_GENERAL:
996 return 2;
997
998 case SYMBOL_SMALL_DATA:
999 return 1;
1000 }
1001
1002 gcc_unreachable ();
1003 }
1004
1005 /* Return the number of instructions needed to load or store a value
1006 of mode MODE at X. Return 0 if X isn't valid for MODE. */
1007 static int
1008 score_address_insns (rtx x, enum machine_mode mode)
1009 {
1010 struct score_address_info addr;
1011 int factor;
1012
1013 if (mode == BLKmode)
1014 factor = 1;
1015 else
1016 factor = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
1017
1018 if (score_classify_address (&addr, mode, x, false))
1019 switch (addr.type)
1020 {
1021 case SCORE_ADD_REG:
1022 case SCORE_ADD_CONST_INT:
1023 return factor;
1024
1025 case SCORE_ADD_SYMBOLIC:
1026 return factor * score_symbol_insns (addr.symbol_type);
1027 }
1028 return 0;
1029 }
1030
1031 /* Implement TARGET_RTX_COSTS macro. */
1032 bool
1033 score_rtx_costs (rtx x, int code, int outer_code, int opno ATTRIBUTE_UNUSED,
1034 int *total, bool speed ATTRIBUTE_UNUSED)
1035 {
1036 enum machine_mode mode = GET_MODE (x);
1037
1038 switch (code)
1039 {
1040 case CONST_INT:
1041 if (outer_code == SET)
1042 {
1043 if (((INTVAL (x) & 0xffff) == 0)
1044 || (INTVAL (x) >= -32768 && INTVAL (x) <= 32767))
1045 *total = COSTS_N_INSNS (1);
1046 else
1047 *total = COSTS_N_INSNS (2);
1048 }
1049 else if (outer_code == PLUS || outer_code == MINUS)
1050 {
1051 if (INTVAL (x) >= -8192 && INTVAL (x) <= 8191)
1052 *total = 0;
1053 else if (((INTVAL (x) & 0xffff) == 0)
1054 || (INTVAL (x) >= -32768 && INTVAL (x) <= 32767))
1055 *total = 1;
1056 else
1057 *total = COSTS_N_INSNS (2);
1058 }
1059 else if (outer_code == AND || outer_code == IOR)
1060 {
1061 if (INTVAL (x) >= 0 && INTVAL (x) <= 16383)
1062 *total = 0;
1063 else if (((INTVAL (x) & 0xffff) == 0)
1064 || (INTVAL (x) >= 0 && INTVAL (x) <= 65535))
1065 *total = 1;
1066 else
1067 *total = COSTS_N_INSNS (2);
1068 }
1069 else
1070 {
1071 *total = 0;
1072 }
1073 return true;
1074
1075 case CONST:
1076 case SYMBOL_REF:
1077 case LABEL_REF:
1078 case CONST_DOUBLE:
1079 *total = COSTS_N_INSNS (2);
1080 return true;
1081
1082 case MEM:
1083 {
1084 /* If the address is legitimate, return the number of
1085 instructions it needs, otherwise use the default handling. */
1086 int n = score_address_insns (XEXP (x, 0), GET_MODE (x));
1087 if (n > 0)
1088 {
1089 *total = COSTS_N_INSNS (n + 1);
1090 return true;
1091 }
1092 return false;
1093 }
1094
1095 case FFS:
1096 *total = COSTS_N_INSNS (6);
1097 return true;
1098
1099 case NOT:
1100 *total = COSTS_N_INSNS (1);
1101 return true;
1102
1103 case AND:
1104 case IOR:
1105 case XOR:
1106 if (mode == DImode)
1107 {
1108 *total = COSTS_N_INSNS (2);
1109 return true;
1110 }
1111 return false;
1112
1113 case ASHIFT:
1114 case ASHIFTRT:
1115 case LSHIFTRT:
1116 if (mode == DImode)
1117 {
1118 *total = COSTS_N_INSNS ((GET_CODE (XEXP (x, 1)) == CONST_INT)
1119 ? 4 : 12);
1120 return true;
1121 }
1122 return false;
1123
1124 case ABS:
1125 *total = COSTS_N_INSNS (4);
1126 return true;
1127
1128 case PLUS:
1129 case MINUS:
1130 if (mode == DImode)
1131 {
1132 *total = COSTS_N_INSNS (4);
1133 return true;
1134 }
1135 *total = COSTS_N_INSNS (1);
1136 return true;
1137
1138 case NEG:
1139 if (mode == DImode)
1140 {
1141 *total = COSTS_N_INSNS (4);
1142 return true;
1143 }
1144 return false;
1145
1146 case MULT:
1147 *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (12);
1148 return true;
1149
1150 case DIV:
1151 case MOD:
1152 case UDIV:
1153 case UMOD:
1154 *total = optimize_size ? COSTS_N_INSNS (2) : COSTS_N_INSNS (33);
1155 return true;
1156
1157 case SIGN_EXTEND:
1158 case ZERO_EXTEND:
1159 switch (GET_MODE (XEXP (x, 0)))
1160 {
1161 case QImode:
1162 case HImode:
1163 if (GET_CODE (XEXP (x, 0)) == MEM)
1164 {
1165 *total = COSTS_N_INSNS (2);
1166
1167 if (!TARGET_LITTLE_ENDIAN &&
1168 side_effects_p (XEXP (XEXP (x, 0), 0)))
1169 *total = 100;
1170 }
1171 else
1172 *total = COSTS_N_INSNS (1);
1173 break;
1174
1175 default:
1176 *total = COSTS_N_INSNS (1);
1177 break;
1178 }
1179 return true;
1180
1181 default:
1182 return false;
1183 }
1184 }
1185
1186 /* Implement TARGET_ADDRESS_COST macro. */
1187 int
1188 score_address_cost (rtx addr, enum machine_mode mode ATTRIBUTE_UNUSED,
1189 addr_space_t as ATTRIBUTE_UNUSED,
1190 bool speed ATTRIBUTE_UNUSED)
1191 {
1192 return score_address_insns (addr, SImode);
1193 }
1194
1195 /* Implement ASM_OUTPUT_EXTERNAL macro. */
1196 int
1197 score_output_external (FILE *file ATTRIBUTE_UNUSED,
1198 tree decl, const char *name)
1199 {
1200 register struct extern_list *p;
1201
1202 if (score_in_small_data_p (decl))
1203 {
1204 p = ggc_alloc<extern_list> ();
1205 p->next = extern_head;
1206 p->name = name;
1207 p->size = int_size_in_bytes (TREE_TYPE (decl));
1208 extern_head = p;
1209 }
1210 return 0;
1211 }
1212
1213 /* Implement RETURN_ADDR_RTX. Note, we do not support moving
1214 back to a previous frame. */
1215 rtx
1216 score_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
1217 {
1218 if (count != 0)
1219 return const0_rtx;
1220 return get_hard_reg_initial_val (Pmode, RA_REGNUM);
1221 }
1222
1223 /* Implement PRINT_OPERAND macro. */
1224 /* Score-specific operand codes:
1225 '[' print .set nor1 directive
1226 ']' print .set r1 directive
1227 'U' print hi part of a CONST_INT rtx
1228 'E' print log2(v)
1229 'F' print log2(~v)
1230 'D' print SFmode const double
1231 'S' selectively print "!" if operand is 15bit instruction accessible
1232 'V' print "v!" if operand is 15bit instruction accessible, or "lfh!"
1233 'L' low part of DImode reg operand
1234 'H' high part of DImode reg operand
1235 'C' print part of opcode for a branch condition. */
1236 void
1237 score_print_operand (FILE *file, rtx op, int c)
1238 {
1239 enum rtx_code code = UNKNOWN;
1240 if (!PRINT_OPERAND_PUNCT_VALID_P (c))
1241 code = GET_CODE (op);
1242
1243 if (c == '[')
1244 {
1245 fprintf (file, ".set r1\n");
1246 }
1247 else if (c == ']')
1248 {
1249 fprintf (file, "\n\t.set nor1");
1250 }
1251 else if (c == 'U')
1252 {
1253 gcc_assert (code == CONST_INT);
1254 fprintf (file, HOST_WIDE_INT_PRINT_HEX,
1255 (INTVAL (op) >> 16) & 0xffff);
1256 }
1257 else if (c == 'D')
1258 {
1259 if (GET_CODE (op) == CONST_DOUBLE)
1260 {
1261 rtx temp = gen_lowpart (SImode, op);
1262 gcc_assert (GET_MODE (op) == SFmode);
1263 fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (temp) & 0xffffffff);
1264 }
1265 else
1266 output_addr_const (file, op);
1267 }
1268 else if (c == 'S')
1269 {
1270 gcc_assert (code == REG);
1271 if (G16_REG_P (REGNO (op)))
1272 fprintf (file, "!");
1273 }
1274 else if (c == 'V')
1275 {
1276 gcc_assert (code == REG);
1277 fprintf (file, G16_REG_P (REGNO (op)) ? "v!" : "lfh!");
1278 }
1279 else if (c == 'C')
1280 {
1281 enum machine_mode mode = GET_MODE (XEXP (op, 0));
1282
1283 switch (code)
1284 {
1285 case EQ: fputs ("eq", file); break;
1286 case NE: fputs ("ne", file); break;
1287 case GT: fputs ("gt", file); break;
1288 case GE: fputs (mode != CCmode ? "pl" : "ge", file); break;
1289 case LT: fputs (mode != CCmode ? "mi" : "lt", file); break;
1290 case LE: fputs ("le", file); break;
1291 case GTU: fputs ("gtu", file); break;
1292 case GEU: fputs ("cs", file); break;
1293 case LTU: fputs ("cc", file); break;
1294 case LEU: fputs ("leu", file); break;
1295 default:
1296 output_operand_lossage ("invalid operand for code: '%c'", code);
1297 }
1298 }
1299 else if (c == 'E')
1300 {
1301 unsigned HOST_WIDE_INT i;
1302 unsigned HOST_WIDE_INT pow2mask = 1;
1303 unsigned HOST_WIDE_INT val;
1304
1305 val = INTVAL (op);
1306 for (i = 0; i < 32; i++)
1307 {
1308 if (val == pow2mask)
1309 break;
1310 pow2mask <<= 1;
1311 }
1312 gcc_assert (i < 32);
1313 fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
1314 }
1315 else if (c == 'F')
1316 {
1317 unsigned HOST_WIDE_INT i;
1318 unsigned HOST_WIDE_INT pow2mask = 1;
1319 unsigned HOST_WIDE_INT val;
1320
1321 val = ~INTVAL (op);
1322 for (i = 0; i < 32; i++)
1323 {
1324 if (val == pow2mask)
1325 break;
1326 pow2mask <<= 1;
1327 }
1328 gcc_assert (i < 32);
1329 fprintf (file, HOST_WIDE_INT_PRINT_HEX, i);
1330 }
1331 else if (code == REG)
1332 {
1333 int regnum = REGNO (op);
1334 if ((c == 'H' && !WORDS_BIG_ENDIAN)
1335 || (c == 'L' && WORDS_BIG_ENDIAN))
1336 regnum ++;
1337 fprintf (file, "%s", reg_names[regnum]);
1338 }
1339 else
1340 {
1341 switch (code)
1342 {
1343 case MEM:
1344 score_print_operand_address (file, op);
1345 break;
1346 default:
1347 output_addr_const (file, op);
1348 }
1349 }
1350 }
1351
1352 /* Implement PRINT_OPERAND_ADDRESS macro. */
1353 void
1354 score_print_operand_address (FILE *file, rtx x)
1355 {
1356 struct score_address_info addr;
1357 enum rtx_code code = GET_CODE (x);
1358 enum machine_mode mode = GET_MODE (x);
1359
1360 if (code == MEM)
1361 x = XEXP (x, 0);
1362
1363 if (score_classify_address (&addr, mode, x, true))
1364 {
1365 switch (addr.type)
1366 {
1367 case SCORE_ADD_REG:
1368 {
1369 switch (addr.code)
1370 {
1371 case PRE_DEC:
1372 fprintf (file, "[%s,-%ld]+", reg_names[REGNO (addr.reg)],
1373 INTVAL (addr.offset));
1374 break;
1375 case POST_DEC:
1376 fprintf (file, "[%s]+,-%ld", reg_names[REGNO (addr.reg)],
1377 INTVAL (addr.offset));
1378 break;
1379 case PRE_INC:
1380 fprintf (file, "[%s, %ld]+", reg_names[REGNO (addr.reg)],
1381 INTVAL (addr.offset));
1382 break;
1383 case POST_INC:
1384 fprintf (file, "[%s]+, %ld", reg_names[REGNO (addr.reg)],
1385 INTVAL (addr.offset));
1386 break;
1387 default:
1388 if (INTVAL(addr.offset) == 0)
1389 fprintf(file, "[%s]", reg_names[REGNO (addr.reg)]);
1390 else
1391 fprintf(file, "[%s, %ld]", reg_names[REGNO (addr.reg)],
1392 INTVAL(addr.offset));
1393 break;
1394 }
1395 }
1396 return;
1397 case SCORE_ADD_CONST_INT:
1398 case SCORE_ADD_SYMBOLIC:
1399 output_addr_const (file, x);
1400 return;
1401 }
1402 }
1403 print_rtl (stderr, x);
1404 gcc_unreachable ();
1405 }
1406
1407 /* Implement SELECT_CC_MODE macro. */
1408 enum machine_mode
1409 score_select_cc_mode (enum rtx_code op, rtx x, rtx y)
1410 {
1411 if ((op == EQ || op == NE || op == LT || op == GE)
1412 && y == const0_rtx
1413 && GET_MODE (x) == SImode)
1414 {
1415 switch (GET_CODE (x))
1416 {
1417 case PLUS:
1418 case MINUS:
1419 case NEG:
1420 case AND:
1421 case IOR:
1422 case XOR:
1423 case NOT:
1424 case ASHIFT:
1425 case LSHIFTRT:
1426 case ASHIFTRT:
1427 return CC_NZmode;
1428
1429 case SIGN_EXTEND:
1430 case ZERO_EXTEND:
1431 case ROTATE:
1432 case ROTATERT:
1433 return (op == LT || op == GE) ? CC_Nmode : CCmode;
1434
1435 default:
1436 return CCmode;
1437 }
1438 }
1439
1440 if ((op == EQ || op == NE)
1441 && (GET_CODE (y) == NEG)
1442 && register_operand (XEXP (y, 0), SImode)
1443 && register_operand (x, SImode))
1444 {
1445 return CC_NZmode;
1446 }
1447
1448 return CCmode;
1449 }
1450
1451 /* Generate the prologue instructions for entry into a S+core function. */
1452 void
1453 score_prologue (void)
1454 {
1455 #define EMIT_PL(_rtx) RTX_FRAME_RELATED_P (_rtx) = 1
1456
1457 struct score_frame_info *f = score_compute_frame_size (get_frame_size ());
1458 HOST_WIDE_INT size;
1459 int regno;
1460
1461 size = f->total_size - f->gp_reg_size;
1462
1463 if (flag_pic)
1464 emit_insn (gen_cpload_score7 ());
1465
1466 for (regno = (int) GP_REG_LAST; regno >= (int) GP_REG_FIRST; regno--)
1467 {
1468 if (BITSET_P (f->mask, regno - GP_REG_FIRST))
1469 {
1470 rtx mem = gen_rtx_MEM (SImode,
1471 gen_rtx_PRE_DEC (SImode, stack_pointer_rtx));
1472 rtx reg = gen_rtx_REG (SImode, regno);
1473 if (!crtl->calls_eh_return)
1474 MEM_READONLY_P (mem) = 1;
1475 EMIT_PL (emit_insn (gen_pushsi_score7 (mem, reg)));
1476 }
1477 }
1478
1479 if (size > 0)
1480 {
1481 rtx_insn *insn;
1482
1483 if (size >= -32768 && size <= 32767)
1484 EMIT_PL (emit_insn (gen_add3_insn (stack_pointer_rtx,
1485 stack_pointer_rtx,
1486 GEN_INT (-size))));
1487 else
1488 {
1489 EMIT_PL (emit_move_insn (gen_rtx_REG (Pmode, SCORE_PROLOGUE_TEMP_REGNUM),
1490 GEN_INT (size)));
1491 EMIT_PL (emit_insn
1492 (gen_sub3_insn (stack_pointer_rtx,
1493 stack_pointer_rtx,
1494 gen_rtx_REG (Pmode,
1495 SCORE_PROLOGUE_TEMP_REGNUM))));
1496 }
1497 insn = get_last_insn ();
1498 REG_NOTES (insn) =
1499 alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR,
1500 gen_rtx_SET (VOIDmode, stack_pointer_rtx,
1501 plus_constant (Pmode, stack_pointer_rtx,
1502 -size)),
1503 REG_NOTES (insn));
1504 }
1505
1506 if (frame_pointer_needed)
1507 EMIT_PL (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx));
1508
1509 if (flag_pic && f->cprestore_size)
1510 {
1511 if (frame_pointer_needed)
1512 emit_insn (gen_cprestore_use_fp_score7 (GEN_INT (size - f->cprestore_size)));
1513 else
1514 emit_insn (gen_cprestore_use_sp_score7 (GEN_INT (size - f->cprestore_size)));
1515 }
1516
1517 #undef EMIT_PL
1518 }
1519
1520 /* Generate the epilogue instructions in a S+core function. */
1521 void
1522 score_epilogue (int sibcall_p)
1523 {
1524 struct score_frame_info *f = score_compute_frame_size (get_frame_size ());
1525 HOST_WIDE_INT size;
1526 int regno;
1527 rtx base;
1528
1529 size = f->total_size - f->gp_reg_size;
1530
1531 if (!frame_pointer_needed)
1532 base = stack_pointer_rtx;
1533 else
1534 base = hard_frame_pointer_rtx;
1535
1536 if (size)
1537 {
1538 if (size >= -32768 && size <= 32767)
1539 emit_insn (gen_add3_insn (base, base, GEN_INT (size)));
1540 else
1541 {
1542 emit_move_insn (gen_rtx_REG (Pmode, SCORE_EPILOGUE_TEMP_REGNUM),
1543 GEN_INT (size));
1544 emit_insn (gen_add3_insn (base, base,
1545 gen_rtx_REG (Pmode,
1546 SCORE_EPILOGUE_TEMP_REGNUM)));
1547 }
1548 }
1549
1550 if (base != stack_pointer_rtx)
1551 emit_move_insn (stack_pointer_rtx, base);
1552
1553 if (crtl->calls_eh_return)
1554 emit_insn (gen_add3_insn (stack_pointer_rtx,
1555 stack_pointer_rtx,
1556 EH_RETURN_STACKADJ_RTX));
1557
1558 for (regno = (int) GP_REG_FIRST; regno <= (int) GP_REG_LAST; regno++)
1559 {
1560 if (BITSET_P (f->mask, regno - GP_REG_FIRST))
1561 {
1562 rtx mem = gen_rtx_MEM (SImode,
1563 gen_rtx_POST_INC (SImode, stack_pointer_rtx));
1564 rtx reg = gen_rtx_REG (SImode, regno);
1565
1566 if (!crtl->calls_eh_return)
1567 MEM_READONLY_P (mem) = 1;
1568
1569 emit_insn (gen_popsi_score7 (reg, mem));
1570 }
1571 }
1572
1573 if (!sibcall_p)
1574 emit_jump_insn (gen_return_internal_score7 (gen_rtx_REG (Pmode, RA_REGNUM)));
1575 }
1576
1577 /* Return true if X is a symbolic constant that can be calculated in
1578 the same way as a bare symbol. If it is, store the type of the
1579 symbol in *SYMBOL_TYPE. */
1580 int
1581 score_symbolic_constant_p (rtx x, enum score_symbol_type *symbol_type)
1582 {
1583 HOST_WIDE_INT offset;
1584
1585 score_split_const (x, &x, &offset);
1586 if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF)
1587 *symbol_type = score_classify_symbol (x);
1588 else
1589 return 0;
1590
1591 if (offset == 0)
1592 return 1;
1593
1594 /* if offset > 15bit, must reload */
1595 if (!IMM_IN_RANGE (offset, 15, 1))
1596 return 0;
1597
1598 switch (*symbol_type)
1599 {
1600 case SYMBOL_GENERAL:
1601 return 1;
1602 case SYMBOL_SMALL_DATA:
1603 return score_offset_within_object_p (x, offset);
1604 }
1605 gcc_unreachable ();
1606 }
1607
1608 void
1609 score_movsicc (rtx *ops)
1610 {
1611 enum machine_mode mode;
1612
1613 mode = score_select_cc_mode (GET_CODE (ops[1]), ops[2], ops[3]);
1614 emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_REG (mode, CC_REGNUM),
1615 gen_rtx_COMPARE (mode, XEXP (ops[1], 0),
1616 XEXP (ops[1], 1))));
1617 }
1618
1619 /* Call and sibcall pattern all need call this function. */
1620 void
1621 score_call (rtx *ops, bool sib)
1622 {
1623 rtx addr = XEXP (ops[0], 0);
1624 if (!call_insn_operand (addr, VOIDmode))
1625 {
1626 rtx oaddr = addr;
1627 addr = gen_reg_rtx (Pmode);
1628 gen_move_insn (addr, oaddr);
1629 }
1630
1631 if (sib)
1632 emit_call_insn (gen_sibcall_internal_score7 (addr, ops[1]));
1633 else
1634 emit_call_insn (gen_call_internal_score7 (addr, ops[1]));
1635 }
1636
1637 /* Call value and sibcall value pattern all need call this function. */
1638 void
1639 score_call_value (rtx *ops, bool sib)
1640 {
1641 rtx result = ops[0];
1642 rtx addr = XEXP (ops[1], 0);
1643 rtx arg = ops[2];
1644
1645 if (!call_insn_operand (addr, VOIDmode))
1646 {
1647 rtx oaddr = addr;
1648 addr = gen_reg_rtx (Pmode);
1649 gen_move_insn (addr, oaddr);
1650 }
1651
1652 if (sib)
1653 emit_call_insn (gen_sibcall_value_internal_score7 (result, addr, arg));
1654 else
1655 emit_call_insn (gen_call_value_internal_score7 (result, addr, arg));
1656 }
1657
1658 /* Machine Split */
1659 void
1660 score_movdi (rtx *ops)
1661 {
1662 rtx dst = ops[0];
1663 rtx src = ops[1];
1664 rtx dst0 = score_subw (dst, 0);
1665 rtx dst1 = score_subw (dst, 1);
1666 rtx src0 = score_subw (src, 0);
1667 rtx src1 = score_subw (src, 1);
1668
1669 if (GET_CODE (dst0) == REG && reg_overlap_mentioned_p (dst0, src))
1670 {
1671 emit_move_insn (dst1, src1);
1672 emit_move_insn (dst0, src0);
1673 }
1674 else
1675 {
1676 emit_move_insn (dst0, src0);
1677 emit_move_insn (dst1, src1);
1678 }
1679 }
1680
1681 void
1682 score_zero_extract_andi (rtx *ops)
1683 {
1684 if (INTVAL (ops[1]) == 1 && const_uimm5 (ops[2], SImode))
1685 emit_insn (gen_zero_extract_bittst_score7 (ops[0], ops[2]));
1686 else
1687 {
1688 unsigned HOST_WIDE_INT mask;
1689 mask = (0xffffffffU & ((1U << INTVAL (ops[1])) - 1U));
1690 mask = mask << INTVAL (ops[2]);
1691 emit_insn (gen_andsi3_cmp_score7 (ops[3], ops[0],
1692 gen_int_mode (mask, SImode)));
1693 }
1694 }
1695
1696 /* Check addr could be present as PRE/POST mode. */
1697 static bool
1698 score_pindex_mem (rtx addr)
1699 {
1700 if (GET_CODE (addr) == MEM)
1701 {
1702 switch (GET_CODE (XEXP (addr, 0)))
1703 {
1704 case PRE_DEC:
1705 case POST_DEC:
1706 case PRE_INC:
1707 case POST_INC:
1708 return true;
1709 default:
1710 break;
1711 }
1712 }
1713 return false;
1714 }
1715
1716 /* Output asm code for ld/sw insn. */
1717 static int
1718 score_pr_addr_post (rtx *ops, int idata, int iaddr, char *ip, enum score_mem_unit unit)
1719 {
1720 struct score_address_info ai;
1721
1722 gcc_assert (GET_CODE (ops[idata]) == REG);
1723 gcc_assert (score_classify_address (&ai, SImode, XEXP (ops[iaddr], 0), true));
1724
1725 if (!score_pindex_mem (ops[iaddr])
1726 && ai.type == SCORE_ADD_REG
1727 && GET_CODE (ai.offset) == CONST_INT
1728 && G16_REG_P (REGNO (ops[idata]))
1729 && G16_REG_P (REGNO (ai.reg)))
1730 {
1731 if (INTVAL (ai.offset) == 0)
1732 {
1733 ops[iaddr] = ai.reg;
1734 return snprintf (ip, INS_BUF_SZ,
1735 "!\t%%%d, [%%%d]", idata, iaddr);
1736 }
1737 if (REGNO (ai.reg) == HARD_FRAME_POINTER_REGNUM)
1738 {
1739 HOST_WIDE_INT offset = INTVAL (ai.offset);
1740 if (SCORE_ALIGN_UNIT (offset, unit)
1741 && (((offset >> unit) >= 0) && ((offset >> unit) <= 31)))
1742 {
1743 ops[iaddr] = ai.offset;
1744 return snprintf (ip, INS_BUF_SZ,
1745 "p!\t%%%d, %%c%d", idata, iaddr);
1746 }
1747 }
1748 }
1749 return snprintf (ip, INS_BUF_SZ, "\t%%%d, %%a%d", idata, iaddr);
1750 }
1751
1752 /* Output asm insn for load. */
1753 const char *
1754 score_linsn (rtx *ops, enum score_mem_unit unit, bool sign)
1755 {
1756 const char *pre_ins[] =
1757 {"lbu", "lhu", "lw", "??", "lb", "lh", "lw", "??"};
1758 char *ip;
1759
1760 strcpy (score_ins, pre_ins[(sign ? 4 : 0) + unit]);
1761 ip = score_ins + strlen (score_ins);
1762
1763 if ((!sign && unit != SCORE_HWORD)
1764 || (sign && unit != SCORE_BYTE))
1765 score_pr_addr_post (ops, 0, 1, ip, unit);
1766 else
1767 snprintf (ip, INS_BUF_SZ, "\t%%0, %%a1");
1768
1769 return score_ins;
1770 }
1771
1772 /* Output asm insn for store. */
1773 const char *
1774 score_sinsn (rtx *ops, enum score_mem_unit unit)
1775 {
1776 const char *pre_ins[] = {"sb", "sh", "sw"};
1777 char *ip;
1778
1779 strcpy (score_ins, pre_ins[unit]);
1780 ip = score_ins + strlen (score_ins);
1781 score_pr_addr_post (ops, 1, 0, ip, unit);
1782 return score_ins;
1783 }
1784
1785 /* Output asm insn for load immediate. */
1786 const char *
1787 score_limm (rtx *ops)
1788 {
1789 HOST_WIDE_INT v;
1790
1791 gcc_assert (GET_CODE (ops[0]) == REG);
1792 gcc_assert (GET_CODE (ops[1]) == CONST_INT);
1793
1794 v = INTVAL (ops[1]);
1795 if (G16_REG_P (REGNO (ops[0])) && IMM_IN_RANGE (v, 8, 0))
1796 return "ldiu!\t%0, %c1";
1797 else if (IMM_IN_RANGE (v, 16, 1))
1798 return "ldi\t%0, %c1";
1799 else if ((v & 0xffff) == 0)
1800 return "ldis\t%0, %U1";
1801 else
1802 return "li\t%0, %c1";
1803 }
1804
1805 /* Output asm insn for move. */
1806 const char *
1807 score_move (rtx *ops)
1808 {
1809 gcc_assert (GET_CODE (ops[0]) == REG);
1810 gcc_assert (GET_CODE (ops[1]) == REG);
1811
1812 if (G16_REG_P (REGNO (ops[0])))
1813 {
1814 if (G16_REG_P (REGNO (ops[1])))
1815 return "mv!\t%0, %1";
1816 else
1817 return "mlfh!\t%0, %1";
1818 }
1819 else if (G16_REG_P (REGNO (ops[1])))
1820 return "mhfl!\t%0, %1";
1821 else
1822 return "mv\t%0, %1";
1823 }
1824
1825 /* Generate add insn. */
1826 const char *
1827 score_select_add_imm (rtx *ops, bool set_cc)
1828 {
1829 HOST_WIDE_INT v = INTVAL (ops[2]);
1830
1831 gcc_assert (GET_CODE (ops[2]) == CONST_INT);
1832 gcc_assert (REGNO (ops[0]) == REGNO (ops[1]));
1833
1834 if (set_cc && G16_REG_P (REGNO (ops[0])))
1835 {
1836 if (v > 0 && IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT) v, 0, 15))
1837 {
1838 ops[2] = GEN_INT (ffs (v) - 1);
1839 return "addei!\t%0, %c2";
1840 }
1841
1842 if (v < 0 && IMM_IS_POW_OF_2 ((unsigned HOST_WIDE_INT) (-v), 0, 15))
1843 {
1844 ops[2] = GEN_INT (ffs (-v) - 1);
1845 return "subei!\t%0, %c2";
1846 }
1847 }
1848
1849 if (set_cc)
1850 return "addi.c\t%0, %c2";
1851 else
1852 return "addi\t%0, %c2";
1853 }
1854
1855 /* Output arith insn. */
1856 const char *
1857 score_select (rtx *ops, const char *inst_pre,
1858 bool commu, const char *letter, bool set_cc)
1859 {
1860 gcc_assert (GET_CODE (ops[0]) == REG);
1861 gcc_assert (GET_CODE (ops[1]) == REG);
1862
1863 if (set_cc && G16_REG_P (REGNO (ops[0]))
1864 && (GET_CODE (ops[2]) == REG ? G16_REG_P (REGNO (ops[2])) : 1)
1865 && REGNO (ops[0]) == REGNO (ops[1]))
1866 {
1867 snprintf (score_ins, INS_BUF_SZ, "%s!\t%%0, %%%s2", inst_pre, letter);
1868 return score_ins;
1869 }
1870
1871 if (commu && set_cc && G16_REG_P (REGNO (ops[0]))
1872 && G16_REG_P (REGNO (ops[1]))
1873 && REGNO (ops[0]) == REGNO (ops[2]))
1874 {
1875 gcc_assert (GET_CODE (ops[2]) == REG);
1876 snprintf (score_ins, INS_BUF_SZ, "%s!\t%%0, %%%s1", inst_pre, letter);
1877 return score_ins;
1878 }
1879
1880 if (set_cc)
1881 snprintf (score_ins, INS_BUF_SZ, "%s.c\t%%0, %%1, %%%s2", inst_pre, letter);
1882 else
1883 snprintf (score_ins, INS_BUF_SZ, "%s\t%%0, %%1, %%%s2", inst_pre, letter);
1884 return score_ins;
1885 }
1886
1887 /* Return nonzero when an argument must be passed by reference. */
1888 static bool
1889 score_pass_by_reference (cumulative_args_t cum ATTRIBUTE_UNUSED,
1890 enum machine_mode mode, const_tree type,
1891 bool named ATTRIBUTE_UNUSED)
1892 {
1893 /* If we have a variable-sized parameter, we have no choice. */
1894 return targetm.calls.must_pass_in_stack (mode, type);
1895 }
1896
1897 /* Implement TARGET_FUNCTION_OK_FOR_SIBCALL. */
1898 static bool
1899 score_function_ok_for_sibcall (ATTRIBUTE_UNUSED tree decl,
1900 ATTRIBUTE_UNUSED tree exp)
1901 {
1902 return true;
1903 }
1904
1905 /* Implement TARGET_SCHED_ISSUE_RATE. */
1906 static int
1907 score_issue_rate (void)
1908 {
1909 return 1;
1910 }
1911
1912 /* We can always eliminate to the hard frame pointer. We can eliminate
1913 to the stack pointer unless a frame pointer is needed. */
1914
1915 static bool
1916 score_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to)
1917 {
1918 return (to == HARD_FRAME_POINTER_REGNUM
1919 || (to == STACK_POINTER_REGNUM && !frame_pointer_needed));
1920 }
1921
1922 /* Argument support functions. */
1923
1924 /* Initialize CUMULATIVE_ARGS for a function. */
1925 void
1926 score_init_cumulative_args (CUMULATIVE_ARGS *cum,
1927 tree fntype ATTRIBUTE_UNUSED,
1928 rtx libname ATTRIBUTE_UNUSED)
1929 {
1930 memset (cum, 0, sizeof (CUMULATIVE_ARGS));
1931 }
1932
1933 static void
1934 score_conditional_register_usage (void)
1935 {
1936 if (!flag_pic)
1937 fixed_regs[PIC_OFFSET_TABLE_REGNUM] =
1938 call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 0;
1939 }
1940
1941 struct gcc_target targetm = TARGET_INITIALIZER;