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